Author Topic: EEVblog #1144 - Padauk Programmer Reverse Engineering  (Read 391568 times)

crossbound and 4 Guests are viewing this topic.

Offline js_12345678_55AA

  • Frequent Contributor
  • **
  • Posts: 337
  • Country: ht
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #50 on: November 16, 2018, 11:01:10 pm »
Found 2 more instructions which are not in manual:

LDSPTL   0x0006
LDSPTH  0x0007

They are fixed instructions with no arguments.

Speculation...
Looks like it is a syntax which uses L and H 
Since the stack pointer is mapped on IO 0x02 and does not have High or Low, the "SP" inside the name might me misleading

----
There are 2 more undocumented instructions which the IDE knows but refuses to compile. I tried many many different 1xx processors:

WORD data
...

LDTABL  data
LDTABH  data

Compiler always says: "The 'LDTABx' not be supported at PFS154" (for every 1xx processor I tried)

All other instructions from the list are already mapped.

One special exception is the "TRAP" instruction. The IDE just put's a "NOP" inside the binary. I assume this is used for the ICE only... so need to wait for my ICE to arrive ;D
Easy PDK programmer and more: https://free-pdk.github.io
 
The following users thanked this post: hidden

Offline js_12345678_55AA

  • Frequent Contributor
  • **
  • Posts: 337
  • Country: ht
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #51 on: November 16, 2018, 11:12:27 pm »
@ js_12345678_55AA: Could you post the modifications you made to deobfuscate the PDKs in the USB_Driver directory?

I updated the initial post (both source and windows binary)
Easy PDK programmer and more: https://free-pdk.github.io
 

Offline DocBen

  • Regular Contributor
  • *
  • Posts: 111
  • Country: de
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #52 on: November 17, 2018, 08:58:02 am »
Speaking of ICE
The USB_Driver/USB directory also seems to contain the firmware for the ICE (*.usb and *.hid files)
As far as I can tell this should be firmware for an Cypress EZ-USB FX2LP Chip CY7C68013A (8051 code) it is not obfuscated.

I assume that the ICE*PDK files are for GAL/PAL/FPGA device seen in the video of the ICE. (Cypress even markets the chip as an FPGA companion "Booting an FPGA from FX2LP" so probably an FPGA.

AN63620 - Configuring a Xilinx Spartan-3E FPGA Over USB Using EZ-USB FX2LP™:
"This  application  note  demonstrates  a  technique  for  dynamically  configuring  a  Xilinx  Spartan-3E  Field  Programmable  Gate Array  (FPGA)  over  USB  using  EZ-USB  FX2LP,  a  high-speed  USB  peripheral  controller.  After  the  FPGA  is  configured, FX2LP  can  act  as  a  high-speed  data  path  between  the  USB  host  and  the  FPGA.  This  capability of  FX2LP  enhances 
FPGA-based USB applications such as logical analyzers, oscilloscopes, image processing,
and high-speed data acquisition."

They are all wildly different from each other, which would make sense if they all are for differnt cores.
The file sizes are however all divisible by 64 -> Logic cells/blocks?




ICE_3.usb and WRITER_5.usb on the other hand are almost identical, so I assume thats for the same thing (as far as I understand thats the multicore ICE)

ICE5.fw would then be the obfuscated single core firmware for the ICE that Dave has. It seems that they still use a Cypress FX2 chip, so probably almost identical to ICE_3.usb.
Maybe that helps with deobfuscation.
« Last Edit: November 17, 2018, 09:42:47 am by DocBen »
 

Offline js_12345678_55AA

  • Frequent Contributor
  • **
  • Posts: 337
  • Country: ht
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #53 on: November 17, 2018, 10:55:58 am »

@ js_12345678_55AA:

Also: in the USB_Driver/USB directory there seems to be the firmware for the programmer (in obfuscated form):

P5SP_BOOT_UPDATER.fw
P5SP_G1.fw
P5SP_G2.fw
P5SP_TESTER.fw

from Dave's video the P5SP files could be for an STM32F072V8T6

You asked for it... here it is:

It's a command line utility called defw which requires 2 parameters: inputfile and outputfile.

Example: ./defw input.fw output.bin

Compilation with gcc -o defw defw.c

Or use the attached compiled executable for Windows.

Have fun,

JS  8)

P.S. works for all *.fw files and also the *.hid files in "USB_Driver/USB" directory. All other files (*.usb) there seem not to be obfuscated. For the PDK files use "depdk".

defw.c


#include <stdio.h>
#include <stdint.h>
#include <string.h>

int main( int argc, const char * argv [] )
{
  if( 3 != argc ) {
    printf("usage: %s inputfile outputfile\n\n", argv[0]);
    return 0;
  }

  FILE* fin = fopen( argv[1], "rb");
  if( !fin ) { printf("Could not open %s for reading.\n", argv[1]); return -1; }

  FILE* fout = fopen( argv[2], "wb");
  if( !fin ) { printf("Could not open %s for writing.\n", argv[2]); return -1; }
 
  uint16_t data[0x10000];
  int lenwords = fread( data, sizeof(uint16_t), sizeof(data)/sizeof(uint16_t), fin );
  if( lenwords<=0 ) {
     printf("Could not read %s.\n", argv[1]); return -1;
  }

  for( uint32_t i=0; i<lenwords; i++ ) {
    data[ i ] ^= i;
    if( i & 1 ) data[ i ] ^= 0x55;
    else
    if( i & 2 ) data[ i ] ^= 0xAA23;
    else
    if( i & 4 ) data[ i ] ^= 0x3759;
    else
      data[ i ] ^= 0xAFCD;
    data[ i ] ^= (lenwords-i-1)<<3;
  }
   
  if( lenwords != fwrite( data, sizeof(uint16_t), lenwords, fout ) ) {
    printf("Error writing output file\n");
    return -1;
  }

  fclose(fin);
  fclose(fout);

  return 0;
}



... it is indeed STM32 firmware in there :-)


Edit: fixed forum formatting of data[ i ]
« Last Edit: November 17, 2018, 11:42:29 am by js_12345678_55AA »
Easy PDK programmer and more: https://free-pdk.github.io
 

Offline js_12345678_55AA

  • Frequent Contributor
  • **
  • Posts: 337
  • Country: ht
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #54 on: November 17, 2018, 11:07:18 am »
Hi,

seems youtuber "bigclivedotcom" spotted a PADAUK MCU containing device in the wild:



 :)
Easy PDK programmer and more: https://free-pdk.github.io
 

Offline DocBen

  • Regular Contributor
  • *
  • Posts: 111
  • Country: de
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #55 on: November 17, 2018, 11:24:16 am »
Hey thanks!

Whats interesting is that there is a "simple emulator" that isnt available anywhere:
5S-I-S0 2B

http://www.padauk.com.tw//upload/ICEmanual/5S-ICE_UM_EN_V002_20181105.pdf (page 15)

But: there is an dev board with Cypress FX2 Chip
https://de.aliexpress.com/wholesale?catId=0&SearchText=EZ-USB+FX2LP+CY7C68013A
for ~3.5 USD

If we can find out what FPGA they use  :popcorn:
 

Offline DocBen

  • Regular Contributor
  • *
  • Posts: 111
  • Country: de
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #56 on: November 17, 2018, 11:29:38 am »
small error:
data ^= ...
should read
 data square brackets i ^= ... (Forum doesnt let me post square brackets  :-//)
fixed locally and seems to work
 

Offline DocBen

  • Regular Contributor
  • *
  • Posts: 111
  • Country: de
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #57 on: November 17, 2018, 11:40:55 am »
and more voltages appear:
T:CN5/CN6
VPP_PWR != 11V
T:CN7
T:CN12/CN6/CN5
VPP_PWR != 0V
VDD_PWR != 7.8V
T:CN11
T:CN11/CN4/CN3
VDD_PWR != 0V
HVPP_IC != 11V
T:IC_PA5
T:Q32
VPP_IC != 0V
VDD_IC != 7.8V
T:IC_VDD
T:Q9
VDD_IC != 0V
`pGp
d!/H
VDD_PWR != 3V
 T:CN11
 

Offline DocBen

  • Regular Contributor
  • *
  • Posts: 111
  • Country: de
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #58 on: November 17, 2018, 12:28:03 pm »

seems youtuber "bigclivedotcom" spotted a PADAUK MCU containing device in the wild:


Too bad he doesnt desolder the chip to show the bottom so we can see the package markings.

Just FYI package markings on the chips I have:
PMS150C: YS17 RBAAADO 1839XA0
PMC232-S16A: FS20 FC62450 1737YAD
PFS154-S16: YP56 R2E9691 1609XBD
Bj8P509FNB (supposedly clone of elan 13-bit clone of microchip 12c509): BJY180338
 

Offline gdelazzari

  • Contributor
  • Posts: 15
  • Country: it
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #59 on: November 17, 2018, 02:34:14 pm »
I was thinking about creating a library (may be called "libpdk") which contains all the code one may need to create tools for these MCUs. The lib would contain stuff like the PDK decryption/encryption code, the instruction list with their opcode encoding/decoding rules, etc... then all the tools like disassembler, assembler, emulator, etc... can link to the same library. This would let us have only one codebase where the "important stuff" is so if we need to make changes and adjustments (like adding new instrs etc) we wouldn't have to change every single other tool. I'm starting to layout the instruction list in C++ in a way that can be used both to assemble, disassemble or emulate stuff. Is there a place for people interested in helping with the code to chat with the others so we somehow coordinate the work? Like a Slack or Discord channel or something
 

Offline DocBen

  • Regular Contributor
  • *
  • Posts: 111
  • Country: de
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #60 on: November 17, 2018, 03:00:49 pm »
IMHO it would be more useful to add the padauk controllers to already existing toolchains like radare
similarly to 8051 or 6502 or pic that are already there:

https://github.com/radare/radare2/tree/master/libr/asm/arch/8051
https://github.com/radare/radare2/tree/master/libr/asm/arch/6502
https://github.com/radare/radare2/tree/master/libr/asm/arch/avr
https://github.com/radare/radare2/tree/master/libr/asm/arch/pic

You can also add file formats like this:
https://github.com/radare/radare2/blob/master/libr/io/p/io_ihex.c

I think it would save you and others a lot of work, because most of the underlying work has already been done and tested.
Also radare has already got quite a few tools build in for analysis, disassembling and low level debugging as you can see here:

https://www.megabeets.net/reverse-engineering-a-gameboy-rom-with-radare2/

For compiling it might be interesting to add this architecture to sdcc.
« Last Edit: November 17, 2018, 04:07:42 pm by DocBen »
 

Offline js_12345678_55AA

  • Frequent Contributor
  • **
  • Posts: 337
  • Country: ht
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #61 on: November 17, 2018, 04:16:35 pm »
Too bad he doesnt desolder the chip to show the bottom so we can see the package markings.

You asked for it...  :)

Just stopped at ALDI and saw them having a similar LED Christmas lights offering for 2.99 EUR.

I bought and opened it (without powering it on, because "Don't turn it on, take it apart!" 8) ) ...

... and yes, PCB and MCU looks same as from bigclivedotcom's video.

But to my surprise it is having a 32kHz crystal so it can do much better than the more cost optimized version bigclivedotcom was testing.

Last picture shows the MCU from back side. I'm pretty sure it is a PMC154 (just the cheapest and the pinout for GND, VDD, crystal also matches).


JS
Easy PDK programmer and more: https://free-pdk.github.io
 
The following users thanked this post: thm_w, DocBen, rhodges

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #62 on: November 17, 2018, 04:17:17 pm »
(Forum doesnt let me post square brackets  :-//)

Look here: https://wiki.simplemachines.org/smf/Alphabetical_list_of_all_bulletin_board_codes

The ones that might work for that are pre or nobbc, me thinks.
The further a society drifts from truth, the more it will hate those who speak it.
 
The following users thanked this post: DocBen

Offline DocBen

  • Regular Contributor
  • *
  • Posts: 111
  • Country: de
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #63 on: November 17, 2018, 04:35:59 pm »

Last picture shows the MCU from back side. I'm pretty sure it is a PMC154 (just the cheapest and the pinout for GND, VDD, crystal also matches).


I dont think so. The chips I have have 3 lines of markings. This just has the one.
No Bojuxing Industry BJ8P509FNB either because thats more laser carved and the chip marking you have seems inkjetted.

All these chips are probably very interchangable anyhow. Or they just rewrite the code, after all these are throw away products

Maybe ALDI has the premium version for germans  :-DD thus the crystal for milisecond switching precision
(seriously the cheapest crystal I could find on lcsc costs more than the pms150c  :scared: utter madness)
« Last Edit: November 17, 2018, 04:59:31 pm by DocBen »
 

Offline DocBen

  • Regular Contributor
  • *
  • Posts: 111
  • Country: de
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #64 on: November 17, 2018, 10:17:42 pm »
This isnt complete but its a start.
If you would like to extend this, youre welcome
Its based on
https://github.com/limkokhole/radare2/wiki/Implementing-a-new-architecture
and by no means any good, but I think its not too hard to get it usable.

create a directory. put the two files in it. install radare2 if you havent already.
make
sudo make install

I also had to
cp /usr/lib/radare2/last/* ~/.config/radare2/plugins
otherwise the plugin isnt recognized

rasm2 -L should list it at the end
and then you can
rasm2 -a PADAUK -d 0x0069
to get:  neg a

padauk.c

Code: [Select]
/* Padauk disassembler plugin for radare */

#include <r_asm.h>
#include <r_lib.h>
#include <string.h>

static struct {
ut8 op1;
ut8 op2;
char *name;
} ops[] = {
{0x00, 0x00, "nopi"},
{0x00, 0x60, "addc a"},
{0x00, 0x61, "subc a"},
{0x00, 0x62, "izsn a"},
{0x00, 0x63, "dzsn a"},
{0x00, 0x64, "?"},
{0x00, 0x65, "?"},
{0x00, 0x66, "?"},
{0x00, 0x67, "pcadd a"},
{0x00, 0x68, "not a"},
{0x00, 0x69, "neg a"},
{0x00, 0x6a, "sr a"},
{0x00, 0x6b, "sl a"},
{0x00, 0x6c, "src a"},
{0x00, 0x6d, "slc a"},
{0x00, 0x6e, "swap a"},
{0x00, 0x6f, "?"},
{0x3f, 0xff, NULL}};

static int _PADAUKDisass (RAsm *a, RAsmOp *op, const ut8 *buf, int len) {
int i;
op->size = 2;
for (i=0; ops[i].name != NULL; i++) {
if (ops[i].op1 == buf[0]) {
if (ops[i].op2 == buf[1]) {
sprintf (op->buf_asm, "%s", ops[i].name);
break;
}
}
}
return op->size;
}

RAsmPlugin r_asm_plugin_padauk = {
        .name = "PADAUK",
        .arch = "PADAUK",
        .license = "LGPL3",
        .bits = 16,
        .desc = "Padauk disassembler",
        .disassemble = &_PADAUKDisass,
};

#ifndef CORELIB
struct r_lib_struct_t radare_plugin = {
        .type = R_LIB_TYPE_ASM,
        .data = &r_asm_plugin_padauk
};
#endif

Makefile

Code: [Select]
NAME=padauk
R2_PLUGIN_PATH=$(shell r2 -hh|grep LIBR_PLUGINS|awk '{print $$2}')
CFLAGS=-g -fPIC $(shell pkg-config --cflags r_asm)
LDFLAGS=-shared $(shell pkg-config --libs r_asm)
OBJS=$(NAME).o
SO_EXT=$(shell uname|grep -q Darwin && echo dylib || echo so)
LIB=$(NAME).$(SO_EXT)

all: $(LIB)

clean:
rm -f $(LIB) $(OBJS)

$(LIB): $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $(LIB)

install:
cp -f $(NAME).$(SO_EXT) $(R2_PLUGIN_PATH)

uninstall:
rm -f $(R2_PLUGIN_PATH)/$(NAME).$(SO_EXT)
« Last Edit: November 17, 2018, 10:31:22 pm by DocBen »
 

Offline DocBen

  • Regular Contributor
  • *
  • Posts: 111
  • Country: de
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #65 on: November 18, 2018, 12:27:02 pm »
This is a slightly improved version tested with radare 3.1 git.
The documentation for radare is shall we say "sparse" and every backend seems to have multiple layers of indirection and slightly different ways of going about it, especially for the assembler.
But once you found a way it works quite nicely. This is also not very complete and thus minimalistic because I dont know what the best way to de/encode the instructions is.
The table approach has the advantage of being inversible i.e the dissassembler is the inverse of the assembler, but its quite pointless to do it in this manor for instructions that take addresses etc.

Use the makefile from above.
make && sudo make install
and then you can do
rasm2 -a padauk -d 0x0073
to get "popaf" or
rasm2 -a padauk 'addc a'
to get "0x0060"
and you also get stuff like this
rasm2 -a padauk 'nop; ret; reti; addc a; sr a;'
rasm2 -a padauk -d 0x0000006000720073
for free

padauk.c
Code: [Select]
/* Padauk (dis)assembler plugin for radare 3.1 git - DocBen 2018 */

#include <r_asm.h>
#include <r_lib.h>
#include <string.h>

static struct {
ut16 op;
char *name;
} ops[] = {
{0x0000, "nop"},
{0x0060, "addc a"},
{0x0061, "subc a"},
{0x0062, "izsn a"},
{0x0063, "dzsn a"},
{0x0064, "?"},
{0x0065, "?"},
{0x0066, "?"},
{0x0067, "pcadd a"},
{0x0068, "not a"},
{0x0069, "neg a"},
{0x006c, "src a"},
{0x006d, "slc a"},
{0x006a, "sr a"},
{0x006b, "sl a"},
{0x006e, "swap a"},
{0x006f, "?"},
{0x0070, "wdreset"},
{0x0071, "?"},
{0x0072, "pushaf"},
{0x0073, "popaf"},
{0x0074, "?"},
{0x0075, "reset"},
{0x0076, "stopsys"},
{0x0077, "stopexe"},
{0x0078, "engint"},
{0x0079, "disgint"},
{0x007b, "reti"},
{0x007a, "ret"},
{0x007c, "mul"},
{0x007d, "?"},
{0x007e, "?"},
{0x007f, "?"},
{0x4000, NULL}};

int _PADAUKDisass (RAsm *a, RAsmOp *op, const ut8 *buf, int len) {
int i;
op->size = 2;
const char *buf_asm = "unknown";
for (i=0; ops[i].name != NULL; i++) {
if (ops[i].op == 0x100 * buf[0] + buf[1]) {
buf_asm = sdb_fmt ("%s", ops[i].name);
break;
}
}
r_strbuf_set (&op->buf_asm, buf_asm);
return op->size;
}

int _PADAUKAss (RAsm *a, RAsmOp *op, const char *buf) {
int i;
op->size = 2;
ut16 opbuf = 0x4000;
const char *buf_hex = "unknown";
for (i = 0; ops[i].name != NULL; i++) {
if (!strncmp(ops[i].name, buf, strlen(ops[i].name))) {
opbuf = ops[i].op;
buf_hex = sdb_fmt ("0x%.4X\n", opbuf);
break;
}
}
r_strbuf_set (&op->buf_hex, buf_hex);
return op->size;
}

RAsmPlugin r_asm_plugin_padauk = {
        .name = "padauk",
        .arch = "padauk",
        .license = "LGPL3",
        .bits = 16,
        .desc = "Padauk (dis)assembler",
        .disassemble = &_PADAUKDisass,
        .assemble = &_PADAUKAss,
};

#ifndef CORELIB
struct r_lib_struct_t radare_plugin = {
        .type = R_LIB_TYPE_ASM,
        .data = &r_asm_plugin_padauk
};
#endif
« Last Edit: November 18, 2018, 12:56:25 pm by DocBen »
 

Offline DocBen

  • Regular Contributor
  • *
  • Posts: 111
  • Country: de
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #66 on: November 18, 2018, 08:15:18 pm »
Playing further with radare I noticed that there are mostly disassembler backends but only a few assemblers.
I kind of like the idea of having something table driven that allows for a certain symmetry of assembler and disassembler.
Also looks more like a datasheet. Again not complete but recognizes the instructions given, if you want more instructions its literally copy and paste from the website somewhere above.

Don't know if I'll be able to finish this soon though. Just to give an idea that this could be generalized I did the same for pic12 and at least it looks good ;)

Code: [Select]
/* Padauk (dis)assembler plugin for radare 3.1 git - DocBen 2018
now looking more like a datasheet
*/

#include <r_asm.h>
#include <r_lib.h>
#include <string.h>

static struct {
char *op;
char *name;
ut8 args;
char *comment;
} ops[] = {
// memory mapped io i (6-bit)
// nth bit n (3-bit)
// memory address m (6 bit)
// memory address M (7 bit)
// immediate c (8 bit)
// address k (11 bit)
//"binary representation","mnemonic"(,"num parameters (could be inferred)"),"comment"
"0000.0000.0000.0000", "nop", 0, "does nothing (tm)",
"0000.0000.0110.0000", "addc a", 1, "A ← A + CF",
"0000.0000.11ii.iiii", "xor io,a", 2, "IO ← IO ^ A",
"0000.0001.10ii.iiii", "mov io,a", 2, "IO ← A",
"0000.0001.11ii.iiii", "mov a,io", 2, "A ← IO",
"0000.0010.cccc.cccc", "ret c", 1, "",
"0000.0011.1MMM.MMM0", "idxm M, a", 2, "[M] ← A (last bit of M set to 0, M must be word aligned, 2 cycles)",
"0000.0011.1MMM.MMM1", "idxm a, M", 2, "a ← [M] (last bit of M set to 1, M must be word aligned, 2 cycles)",
"0000.010n.nnii.iiii", "swapc io.n", 2, "",
"0000.0110.0MMM.MMMM", "comp a, M", 2, "",
"0010.000n.nnmm.mmmm", "t0sn m.n", 2, "",
"0011.0kkk.kkkk.kkkk", "goto k", 1, "goto address",
"0011.1kkk.kkkk.kkkk", "call k", 1, "call address",
"2222.2222.2222.2222", NULL, 0, "",
};


void bitstring(uint16_t val, char buffer[]) {
int size = 20;
buffer[--size] = 0;
while (size > 0) {
buffer[--size] = (val % 2 ? '1' : '0');
if ( size % 5 == 0 && size > 0) buffer[--size] = '.';
val = val >> 1;
}
}

int _PADAUKDisass (RAsm *a, RAsmOp *op, const ut8 *buf, int len) {
int i;
op->size = 2;
const char *buf_asm = "unknown";
char buf_bin[40];
bitstring(0x100 * buf[0] + buf[1], buf_bin);
for (i=0; ops[i].name != NULL ; i++) {
for (int j = 0; j < 20; j++) {
if (ops[i].op[j] != buf_bin[j]) {
if (ops[i].op[j] != '0' && ops[i].op[j] != '1') { // treat all letters as dont care
continue;
} else {
break;
}
}
if (j == 19) {
buf_asm = sdb_fmt ("%s = %s ; %s", buf_bin, ops[i].name, ops[i].comment);
r_strbuf_set (&op->buf_asm, buf_asm);
return op->size;
}
}
}
r_strbuf_set (&op->buf_asm, buf_asm);
return op->size;
}

int _PADAUKAss (RAsm *a, RAsmOp *op, const char *buf) {
int i;
op->size = 2;
ut16 opbuf = 0x4000;
const char *buf_hex = "unknown";
for (i = 0; ops[i].name != NULL; i++) {
if (!strncmp(ops[i].name, buf, strlen(ops[i].name))) {
//opbuf = ops[i].op;
buf_hex = sdb_fmt ("0x%.4X\n", opbuf);
break;
}
}
r_strbuf_set (&op->buf_hex, buf_hex);
return op->size;
}

RAsmPlugin r_asm_plugin_padauk = {
        .name = "padauk2",
        .arch = "padauk2",
        .license = "LGPL3",
        .bits = 16,
        .desc = "Padauk (dis)assembler",
        .disassemble = &_PADAUKDisass,
        .assemble = &_PADAUKAss,
};

#ifndef CORELIB
struct r_lib_struct_t radare_plugin = {
        .type = R_LIB_TYPE_ASM,
        .data = &r_asm_plugin_padauk
};
#endif

PIC12
Code: [Select]
static struct {
char *op;
char *name;
ut8 args;
char *comment;
} ops[] = {
// direction d (1 bit)
// tri-state register t (2 bit)
// nth bit b (3-bit)
// register bank (3 bit)
// register f (5 bit)
// immediate c (8 bit)
// address k (8 bit)
// address K (9 bit)
//"binary representation","mnemonic"(,"num parameters"), "comment"
"0000.0000.0000.0000", "nop", 0, "No operation (MOVW 0,W)",
"0000.0000.0000.0010", "option", 0, "Copy W to OPTION register",
"0000.0000.0000.0011", "sleep", 0, "Go into standby mode",
"0000.0000.0000.0100", "clrwdt", 0, "Restart watchdog timer",
"0000.0000.0000.01tt", "tris t", 0, "Copy W to tri-state register (f = 1, 2 or 3)",
"0000.0000.0001.0BBB", "movlb k", 1, "Set bank select register to k",
"0000.0000.0001.1110", "return", 0, "Return from subroutine, W unmodified",
"0000.0000.0001.1111", "retfie", 0, "Return from interrupt; return & enable interrupts",
"0000.0000.001f.ffff", "movwf f", 1, "dest ← W",
"0000.0000.01df.ffff", "clr f,d", 2, "dest ← 0, usually written CLRW or CLRF f",
"0000.0000.10df.ffff", "subwf f,d", 2, "dest ← f−W (dest ← f+~W+1)",
"0000.0000.11df.ffff", "decf f,d", 2, "dest ← f−1",
"0000.0001.00df.ffff", "iorwf f,d", 2, "dest ← f | W, logical inclusive or",
"0000.0001.01df.ffff", "andwf f,d", 2, "dest ← f & W, logical and",
"0000.0001.10df.ffff", "xorwf f,d", 2, "dest ← f ^ W, logical exclusive or",
"0000.0001.11df.ffff", "addwf f,d", 2, "dest ← f+W",
"0000.0010.00df.ffff", "movwf f,d", 2, "dest ← f",
"0000.0010.01df.ffff", "comf f,d", 2, "dest ← ~f, bitwise complement",
"0000.0010.10df.ffff", "incf f,d", 2, "dest ← f+1",
"0000.0010.11df.ffff", "decfsz f,d", 2, "dest ← f−1, then skip if zero",
"0000.0011.00df.ffff", "rrf f,d", 2, "dest ← CARRY<<7 | f>>1, rotate right through carry",
"0000.0011.01df.ffff", "rlf f,d", 2, "dest ← F<<1 | CARRY, rotate left through carry",
"0000.0011.10df.ffff", "swapf f,d", 2, "dest ← f<<4 | f>>4, swap nibbles",
"0000.0011.11df.ffff", "incfsz f,d", 2, "dest ← f+1, then skip if zero",
"0000.0100.bbbf.ffff", "bcf f,b", 2, "Clear bit b of f",
"0000.0101.bbbf.ffff", "bsf f,b", 2, "Set bit b of f",
"0000.0110.bbbf.ffff", "btfsc f,b", 2, "Skip if bit b of f is clear",
"0000.0111.bbbf.ffff", "btfss f,b", 2, "Skip if bit b of f is set",
"0000.1000.cccc.cccc", "retlw c", 2, "Set W ← k, then return from subroutine",
"0000.1001.kkkk.kkkk", "call k", 2, "Call subroutine, 8-bit address k",
"0000.101K.KKKK.KKKK", "goto k", 2, "Jump to 9-bit address k",
"0000.1100.cccc.cccc", "movlw c", 2, "W ← c",
"0000.1101.cccc.cccc", "iorlw c", 2, "W ← c | W, bitwise logical or",
"0000.1110.cccc.cccc", "andlw c", 2, "W ← c & W, bitwise and",
"0000.1111.cccc.cccc", "xorlw c", 2, "W ← c ^ W, bitwise exclusive or",
"2222.2222.2222.2222", NULL, 0, "",
};
 

Offline gdelazzari

  • Contributor
  • Posts: 15
  • Country: it
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #67 on: November 19, 2018, 10:11:11 am »
Nice job, would it be possible to make a github repo out of it?

Anyhow my idea for a "universal" instruction table was to have a list of objects like this, if this can somehow interest you:

opcode (16bit)
opcode_mask (16bit)
parameters (array)
[
  {
    type {IO/MEM/IMM/...}
    length (in bits)
    pos (bit n#)
  }
]

There are not a lot of instructions that have more than one parameter encoded, but there are still some, so having an array of parameters descriptions covers everything. Let's call the object above "instr_t". You could write functions to create an instr_t from an assembly line, from an opcode or whatever. Also you could write functions to convert it to an opcode, to an assembly line or to emulate the thing (or maybe the emulator is just a big switch on the opcode and you do everything manually, idk). The point is, this should cover everything and be pretty flexible and somewhat clean.

It may be faster than your current approach (which I like anyway, it is very readable IMHO) but by pattern matching like that may not be the most efficient thing, also you'll have to reconstruct the parameter values and other stuff which would be easier with a table like mine, at least that's what I anticipate.
 

Offline gdelazzari

  • Contributor
  • Posts: 15
  • Country: it
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #68 on: November 19, 2018, 10:20:31 am »
Also you may want the make install rule to install the plugin under the user plugins directory (on my Linux system it's ~/.local/share/radare2/plugins) which is a bit less invasive ;)
 

Offline david.given

  • Contributor
  • Posts: 27
  • Country: ch
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #69 on: November 19, 2018, 01:58:23 pm »
The architecture's engagingly minimal --- memory/memory architecture, one register! I actually have a self-hosting tiny compiler (<plug> http://cowlark.com/cowgol </plug>) which would map very nicely onto this thing. Sadly, it doesn't have enough RAM to run the compiler on itself...

If anyone comes up with a simulator which will run PDK files, I'd love to know about it!
 

Offline gdelazzari

  • Contributor
  • Posts: 15
  • Country: it
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #70 on: November 19, 2018, 02:37:44 pm »
Uhm, I just noticed the PMS150/PMS150C opcodes are different from the PMS154C ones, while still being 14-bit wide. Seems like there are multiple encodings for the same instructions.

For instance:

mov A, 0xAA       -> 0x17AA
mov <addr>, A    -> 0x05C.. something like that
pcadd a               -> 0x0017
wdreset                -> 0x0030

But they're not totally different, most of the time it's just one bit off. Also the PDK fill pattern is 0x1FFF instead of 0x3FFF.

This may need some investigation.

edit: actually no value goes beyond 0x1FFF, I should have noticed that before. Seems like they shaved one bit off and the opcodes are 13-bit (?) if that makes any sense.
« Last Edit: November 19, 2018, 02:42:39 pm by gdelazzari »
 

Offline FrankBuss

  • Supporter
  • ****
  • Posts: 2365
  • Country: de
    • Frank Buss
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #71 on: November 19, 2018, 03:11:50 pm »
If anyone comes up with a simulator which will run PDK files, I'd love to know about it!

Maybe it could be added as a target for QEMU. It has already all kinds of infrastructure functions to implement a new target without too much effort, and it is very fast, because it translates the code to native assembler code on the fly, like a JIT compiler. And it has already functions for timers, interrupts etc.
So Long, and Thanks for All the Fish
Electronics, hiking, retro-computing, electronic music etc.: https://www.youtube.com/c/FrankBussProgrammer
 

Offline spth

  • Regular Contributor
  • *
  • Posts: 163
  • Country: de
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #72 on: November 19, 2018, 03:27:18 pm »
If anyone comes up with a simulator which will run PDK files, I'd love to know about it!

I intend to get support for some Padauk devices into SDCC. For this, they'd need to be supported in the asxxxx fork that SDCC uses, the linker and the uCsim simulator. Support for the Single-Core devices will probably come first (as the lack of sp-relative addressing is a serious restriction for the multicore devices, requiring careful though on how to work around it).

Philipp
 

Offline spth

  • Regular Contributor
  • *
  • Posts: 163
  • Country: de
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #73 on: November 19, 2018, 03:35:43 pm »
Uhm, I just noticed the PMS150/PMS150C opcodes are different from the PMS154C ones, while still being 14-bit wide. Seems like there are multiple encodings for the same instructions.

For instance:

mov A, 0xAA       -> 0x17AA
mov <addr>, A    -> 0x05C.. something like that
pcadd a               -> 0x0017
wdreset                -> 0x0030

But they're not totally different, most of the time it's just one bit off. Also the PDK fill pattern is 0x1FFF instead of 0x3FFF.

This may need some investigation.

edit: actually no value goes beyond 0x1FFF, I should have noticed that before. Seems like they shaved one bit off and the opcodes are 13-bit (?) if that makes any sense.

There are 3 different instruction sets¹ (each with some minor variation such as possible presence of mul). I assumed them to be 14, 15 and 16 bits. But from what you found it seems that they are 13, 14 and 16 bits. The 13-bit instruction set would be used on devices that have up to 1 kiloword of program memory, the 14-bit instruction set for up to 2 kilowords of program memory. The 16-bit instruction set would then be for larger and multicore devices.

Philipp

¹ According to an email by Padauk.
 

Offline DDunfield

  • Regular Contributor
  • *
  • Posts: 173
  • Country: ca
Re: EEVblog #1144 - Padauk Programmer Reverse Engineering
« Reply #74 on: November 19, 2018, 04:49:12 pm »
Hi Guys,

Just found this thread. Seems like we've been duplicating some work.

I was planning to develop a PC based simulator to allow code to be quickly
tested and debugged, and also perhaps an STM32 based one which would allow
code to be tested "in circuit" with downloadability and decent debugging
capability. Would also like to eventually include device programming in
the STM32 but I've not looked really looked into it yet.

Here's what I've figured out about the instruction set:
I've added some notes and questions at the end, if anyone can help clarify
these points, please let me know.

The PMS/C150 uses a 13 bit opcode:

00000 101ppppp  MOV       A,io-addr
00000 100ppppp  MOV       io-addr,A
10111 dddddddd  MOV       A,imm-data
00111 11aaaaaa  MOV       A,ram-addr
00101 11aaaaaa  MOV       ram-addr,A
00000 110aaaa1  LDT16     ram-addr-even
00000 110aaaa0  STT16     ram-addr-even
00000 111aaaa1  IDXM      A,ram-addr-even
00000 111aaaa0  IDXM      ram-addr-even,A
01001 11aaaaaa  XCH       ram-addr
00000 00110010  PUSHAF
00000 00110011  POPAF
10000 dddddddd  ADD       A,imm-data
00110 00aaaaaa  ADD       A,ram-addr
00100 00aaaaaa  ADD       ram-addr,a
00000 00010000  ADDC      A
00110 10aaaaaa  ADDC      A,ram-addr
00100 10aaaaaa  ADDC      ram-addr,A
10001 dddddddd  SUB       A,imm-data
00110 01aaaaaa  SUB       A,ram-addr
00100 01aaaaaa  SUB       ram-addr,a
00000 00010001  SUBC      A
00110 11aaaaaa  SUBC      A,ram-addr
00100 11aaaaaa  SUBC      ram-addr,A
01001 00aaaaaa  INC       ram-addr
01001 01aaaaaa  DEC       ram-addr
01001 10aaaaaa  CLEAR     ram-addr
00000 00011010  SR        A
01010 10aaaaaa  SR        ram-addr
00000 00011100  SRC       A
01011 00aaaaaa  SRC       ram-addr
00000 00011011  SL        A
01010 11aaaaaa  SL        ram-addr
00000 00011101  SLC       A
01011 01aaaaaa  SLC       ram-addr
00000 00011110  SWAP      A
10100 dddddddd  AND       A,imm-data
00111 00aaaaaa  AND       A,ram-addr
00101 00aaaaaa  AND       ram-addr,A
10101 dddddddd  OR        A,imm-data
00111 01aaaaaa  OR        A,ram-addr
00101 01aaaaaa  OR        ram-addr,A
10110 dddddddd  XOR       A,imm-data
00111 10aaaaaa  XOR       A,ram-addr
00101 10aaaaaa  XOR       ram-addr,A
00000 011ppppp  XOR       io-addr,A
00000 00011000  NOT       A
01010 00aaaaaa  NOT       ram-addr
00000 00011001  NEG       A
01010 01aaaaaa  NEG       ram-addr
01110 bbbppppp  SET0      io-addr.bit
01111 bbbppppp  SET1      io-addr.bit
00011 bbb0aaaa  SET0      ram-addr.bit
00011 bbb1aaaa  SET1      ram-addr.bit
10010 dddddddd  CEQSN     A,imm-data
01011 10aaaaaa  CEQSN     A,ram-addr
01100 bbbppppp  T0SN      io-addr.bit
01101 bbbppppp  T1SN      io-addr.bit
00010 bbb0aaaa  T0SN      ram-addr.bit
00010 bbb1aaaa  T1SN      ram-addr.bit
00000 00010010  IZSN      A
00000 00010011  DZSN      A
01000 10aaaaaa  IZSN      ram-addr
01000 11aaaaaa  DZSN      ram-addr
110aa aaaaaaaa  GOTO      code-addr
111aa aaaaaaaa  CALL      code-addr
00001 dddddddd  RET       imm-data
00000 00111010  RET
00000 00111011  RETI
00000 00000000  NOP
00000 00010111  PCADD     A
00000 00111000  ENGINT
00000 00111001  DISGINT
00000 00110110  STOPSYS
00000 00110111  STOPEXE
00000 00110101  RESET
00000 00110000  WDRESET
00000 00000000  TRAP     // Assembler accepts, but same as NOP

General notes:
--------------
Full ram-addr range is 0x00-0x3B (60 bytes).

Instructions requiring ram-addr-even allow only 0x00-0x1E, lowest bit
is *NOT* encoded and is assumed to be zero.

Bit set/clear instructions on ram-addr allow only 0x00-0x0F.

Full io-addr range is 0x00-0x1F.


Instruction set notes:
----------------------
According to the data sheet, there are 4 flags: OV, Z, C, AC

Other than 'C' which can be accessed in the ADDC, SUBC, SRC and SLC
instructions, it is not clear what role the OV, Z and AC flags play.
There does not appear to be any instructions which access them.
The only conditionals are "compare ACC" and skip.

The only way I can see to access the other flags is via PUSHAF and then
reading them from memory (you would need to know exactly where SP points).

I'm wondering if this is "cut/paste" error and this processor does not
actually have OV, Z and AC (would make writing the simulator easier).

Perhaps someone with the actual part could write some test code using
arithmetic instructions and PUSHAF to test if these flags are actually
implemented on the PMS150?


The data sheet also says (page 18): (sic)
"The OTP program memory may contains the data, tables and interrupt entry."

I can see no capability in the instruction set to read data/tables from
program memory (other than immediate data).
Perhaps I have missed something?


The instruction set allows for a MAXIMUM of 64 bytes of RAM ... RAM
addresses are encoded in 6 bits. Yet, the indirect instruction IDXM uses
"pointer" values in memory which are two bytes in size. This makes no
sense to me as RAM is a very limited resource, and only one byte is needed
to address all of it. It also wastes instructions clearing the unused top
byte of the pointer - also a limited resource.

Perhaps "special" values in the upper byte allow indexed access to other
things, such as CODE memory or IO space ... but I can find no mention of
any such capability. Anyone know better?


PADAUK assembler notes:
-----------------------
HB@,LB@/HD@,LD@ can be used to access high/low byte of word data:
   MOV A,hb@word_symbol

HA@,LA@ can be used to get high/low symbol address as immediate-data:
   MOV A,ha@symbol

IO. can be used to specify an arbitrary IO address:
   MOV A,io.2

I've not found a prefix for force a RAM access. The only way I've found
to access ROM is by explicitly declaring symbols with "word" and "byte"
directives. Anyone know better?


Regards,
Dave

 
The following users thanked this post: oPossum


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf