;start measurment
0x002b: 0x2f02 MOV A, 0x02
0x002c: 0x0182 MOV IO(0x02), A ;SP ;setup SP to memory @0x02
0x002d: 0x1304 CLEAR [0x04] ;zero memory @0x04
0x002e: 0x1305 CLEAR [0x05] ;zero memory @0x05
0x002f: 0x2f55 MOV A, 0x55
0x0030: 0x0b82 MOV [0x02], A ;store 0x55 in memory @0x02
0x0031: 0x2f00 MOV A, 0x00
0x0032: 0x0b83 MOV [0x03], A ;store 0x00 in memory @0x03
;16 bit loop (0x0055) times some operations
0x0033: 0x0006 LDSPTL ;load from memory where SP is pointing to A
0x0034: 0x0b04 XOR [0x04], A
0x0035: 0x0007 LDSPTH ;load from memory where SP is pointing to A
0x0036: 0x0805 ADD [0x05], A
0x0037: 0x1584 SL [0x04] ;rotate left 16 bit value
0x0038: 0x1685 SLC [0x05]
0x0039: 0x1004 ADDC [0x04]
0x003a: 0x1282 DECM [0x02] ;memory low byte -1
0x003b: 0x1083 SUBC [0x03] ;memory high byte -1 if carry set
0x003c: 0x1a40 T1SN IO(0x00).1 ;FLAG.CF ;test for carry (0x0000 -1 => carry set)
0x003d: 0x3033 GOTO 0x033 ;loop
00000 00000000 NOP
00000 00000000 TRAP // Assembler accepts, but same as NOP
00000 00000001
.. .. ??
00000 00001111
00000 00010000 ADDC A
00000 00010001 SUBC A
00000 00010010 IZSN A
00000 00010011 DZSN A
00000 00010100
.. .. ??
00000 00010110
00000 00010111 PCADD A
00000 00011000 NOT A
00000 00011001 NEG A
00000 00011010 SR A
00000 00011011 SL A
00000 00011100 SRC A
00000 00011101 SLC A
00000 00011110 SWAP A
00000 00011111
.. .. ??
00000 00101111
00000 00110000 WDRESET
00000 00110001 ?
00000 00110010 PUSHAF
00000 00110011 POPAF
00000 00110100 ?
00000 00110101 RESET
00000 00110110 STOPSYS
00000 00110111 STOPEXE
00000 00111000 ENGINT
00000 00111001 DISGINT
00000 00111010 RET
00000 00111011 RETI
00000 00111100
.. .. ??
00000 01011111
00000 011ppppp XOR io-addr,A
00000 100ppppp MOV io-addr,A
00000 101ppppp MOV A,io-addr
00000 110aaaa0 STT16 ram-addr-even
00000 110aaaa1 LDT16 ram-addr-even
00000 111aaaa0 IDXM ram-addr-even,A
00000 111aaaa1 IDXM A,ram-addr-even
00001 dddddddd RET imm-data
00010 bbb0aaaa T0SN ram-addr.bit
00010 bbb1aaaa T1SN ram-addr.bit
00011 bbb0aaaa SET0 ram-addr.bit
00011 bbb1aaaa SET1 ram-addr.bit
00100 00aaaaaa ADD ram-addr,a
00100 01aaaaaa SUB ram-addr,a
00100 10aaaaaa ADDC ram-addr,A
00100 11aaaaaa SUBC ram-addr,A
00101 00aaaaaa AND ram-addr,A
00101 01aaaaaa OR ram-addr,A
00101 10aaaaaa XOR ram-addr,A
00101 11aaaaaa MOV ram-addr,A
00110 00aaaaaa ADD A,ram-addr
00110 01aaaaaa SUB A,ram-addr
00110 10aaaaaa ADDC A,ram-addr
00110 11aaaaaa SUBC A,ram-addr
00111 00aaaaaa AND A,ram-addr
00111 01aaaaaa OR A,ram-addr
00111 10aaaaaa XOR A,ram-addr
00111 11aaaaaa MOV A,ram-addr
01000 00000000
.. .. ??
01000 01111111
01000 10aaaaaa IZSN ram-addr
01000 11aaaaaa DZSN ram-addr
01001 00aaaaaa INC ram-addr
01001 01aaaaaa DEC ram-addr
01001 10aaaaaa CLEAR ram-addr
01001 11aaaaaa XCH ram-addr
01010 00aaaaaa NOT ram-addr
01010 01aaaaaa NEG ram-addr
01010 10aaaaaa SR ram-addr
01010 11aaaaaa SL ram-addr
01011 00aaaaaa SRC ram-addr
01011 01aaaaaa SLC ram-addr
01011 10aaaaaa CEQSN A,ram-addr
01011 11000000
.. .. ??
01011 11111111
01100 bbbppppp T0SN io-addr.bit
01101 bbbppppp T1SN io-addr.bit
01110 bbbppppp SET0 io-addr.bit
01111 bbbppppp SET1 io-addr.bit
10000 dddddddd ADD A,imm-data
10001 dddddddd SUB A,imm-data
10010 dddddddd CEQSN A,imm-data
10011 00000000
.. .. ??
10011 11111111
10100 dddddddd AND A,imm-data
10101 dddddddd OR A,imm-data
10110 dddddddd XOR A,imm-data
10111 dddddddd MOV A,imm-data
110aa aaaaaaaa GOTO code-addr
111aa aaaaaaaa CALL code-addr
Nice job js_12345678_55AA, really interesting. Will take an in depth look.
At the moment I also got the 13-bit ISA implemented in my infrastructure so I can disassemble PMS150 (C) ROMs. I noticed an interesting thing (I still have to look at the disasm). The PMS150 (without the C) has an order of magnitude less init code compared to the PMS150C (which seems to have code that more or less does the same stuff the 154C is doing).
I'm attaching the two listings if someone wants to take a look and start figuring it out.
(to discriminate what's "my" code and PADAUK's code, in both ROMs I only have the main which is simply incrementing a byte in memory, you'll find the inc [0x...]; goto @0x... as the last two instructions in both listings, that are the only two things not part of the init code)
After checking the disassembly of the calibration again some things look suspicious:
;start measurment
0x002b: 0x2f02 MOV A, 0x02
0x002c: 0x0182 MOV IO(0x02), A ;SP ;setup SP to memory @0x02
0x002d: 0x1304 CLEAR [0x04] ;zero memory @0x04
0x002e: 0x1305 CLEAR [0x05] ;zero memory @0x05
0x002f: 0x2f55 MOV A, 0x55
0x0030: 0x0b82 MOV [0x02], A ;store 0x55 in memory @0x02
0x0031: 0x2f00 MOV A, 0x00
0x0032: 0x0b83 MOV [0x03], A ;store 0x00 in memory @0x03
;16 bit loop (0x0055) times some operations
0x0033: 0x0006 LDSPTL ;load from memory where SP is pointing to A
0x0034: 0x0b04 XOR [0x04], A
0x0035: 0x0007 LDSPTH ;load from memory where SP is pointing to A
0x0036: 0x0805 ADD [0x05], A
0x0037: 0x1584 SL [0x04] ;rotate left 16 bit value
0x0038: 0x1685 SLC [0x05]
0x0039: 0x1004 ADDC [0x04]
0x003a: 0x1282 DECM [0x02] ;memory low byte -1
0x003b: 0x1083 SUBC [0x03] ;memory high byte -1 if carry set
0x003c: 0x1a40 T1SN IO(0x00).1 ;FLAG.CF ;test for carry (0x0000 -1 => carry set)
0x003d: 0x3033 GOTO 0x033 ;loop
At the beginning the SP is setup to point to a new location. SP / stack is never used anywhere after this point in calibration program.
So the only use could be from the undocumented instructions LDSPTL and LDSPTH. Also SP points to the memory which is initialized
with static values.
This lets me think LDSPTL/LDSPTL stands for "LoaD from SP Table Low" / "LoaD from SP Table High":
LDSPTL => A = [SP]
LDSPTH => A = [SP+1]
Then the above loop would be again some "obfuscation" crypto from PADAUK (XOR 0x55 ... smells like the magic value they love, known from IDE obfuscation).
The result in this case is just 0x11E4 which is then sent out via bitbang to the WRITER to "verify"
The loop also serves the purpose to run for several cycles, so WRITER can measure the time it takes and use it for calibration.
JS
EDIT: The loop runs for exact 1040 cycles (including loop init)
SP / stack is never used anywhere after this point in calibration program.
So the only use could be from the undocumented instructions LDSPTL and LDSPTH.
Also SP points to the memory which is initialized with static values.
Could you also add the 13-bit instructions to the documentation on GitHub?
Also, js_12345678_55AA, I had a pull on the docs repo fixing some stuff that is still unfixed after your last commit (a couple of instr swapped IIRC), maybe you want to check that out.
Back in 2006 I was talking to a uC manufacturer in China about their 4 bit uC then costing $0,11 and lower with high volume we were discussing. It could replace $0,40 of logic on our boards so quite interesting with massproduction.
There were some bizar quirks in those things. They were manufactured for one single goal: cheap toys.
The manufacturing process was not as you expect from fabs these days with a result that in your firmware at boottime you had to test the ram since unknown bits would (not could) be dead and you had to make a map so not to use that byte in ram. Also upto 2% of the devices would have problems in the alu or other critical parts. I asked how I could know that the first code would run ok if the ram was not to be trusted. The answer was you could tell from the end product if it worked or not.
I couldnt believe this but had it b&w in an email.
They probably also sell 100% tested uCs that had no flaws but that was pricewise much less interesting.
#include "extern.h"
void<>FPPA0 (void)
{
.ADJUST_IC SYSCLK=IHRC/2 // SYSCLK=IHRC/2
while (1){}
}
...
00000008 MOV ---- A / 0x0008: 0x019b MOV IO(0x1B), A ;
...
00000033 NOP / 0x0033: 0x0006 LDSPTL
00000034 NOP / 0x0034: 0x0b04 XOR [0x04], A
00000035 NOP / 0x0035: 0x0007 LDSPTH
00000036 NOP / 0x0036: 0x0805 ADD [0x05], A
00000037 NOP / 0x0037: 0x1584 SL [0x04]
00000038 NOP / 0x0038: 0x1685 SLC [0x05]
00000039 NOP / 0x0039: 0x1004 ADDC [0x04]
0000003A NOP / 0x003a: 0x1282 DECM [0x02]
0000003B NOP / 0x003b: 0x1083 SUBC [0x03]
...
Hi,
I just got my ICE today... and when you connect it and start debugging you can bring up a disassembly window (no opcodes of course but good to verify our stuff).
Is there any way you could determine the type of fpga they are using?
EDIT:
USB enumeration shows this:
VID: 0x0797
PID: 0x7002
Device String: "LGS_DEV FX2-HID 0.01"
T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=03 Dev#= 9 Spd=480 MxCh= 0
D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1
P: Vendor=0797 ProdID=7002 Rev=80.01
S: Manufacturer=PADAUK
S: Product=LGS_DEV FX2-HID 0.01
C: #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=500mA
I: If#= 0 Alt= 0 #EPs= 2 Cls=03(HID ) Sub=00 Prot=00 Driver=usbhid
I got my ICE today as well. Here is a high resolution image:
The FPGA has no markings. It might be possible to capture the JTAG init sequence, if it doesn't store the configuration data inside the FPGA, because looks like there is no external configuration flash memory.
I got my ICE today as well. Here is a high resolution image:
The FPGA has no markings. It might be possible to capture the JTAG init sequence, if it doesn't store the configuration data inside the FPGA, because looks like there is no external configuration flash memory.
Does the FPGA have markings on the bottom? It doesnt look dremeled on the top to me.
I just ordered one of these PLCC remover from China. Will report back in 4 weeks when it arrives
Hi,
I just got my ICE today... and when you connect it and start debugging you can bring up a disassembly window (no opcodes of course but good to verify our stuff).
Is there any way you could determine the type of fpga they are using?
Could be a CPLD - plenty of PLC44 options showing on Digikey for that package. If there is 5V anywhere that would narrow it down a lot.
Hi,
>Hi, do you have any plans to upload your disassembler (and eventually assembler if you have one) to the GitHub organization?
Sure I will do (I just want to structure it a bit more, will take 1-2 days)
>I also have tools in a preliminary state working with the 13-bit and 14-bit ISAs, which unfortunately is duplicate work but I wanted to disasm some listings so I proceeded anyway in implementing them, but that was not a lot of work so it's not a problem for me to trash everything if we want to keep your infrastructure.
All of the code I did is also just for experimentation. Most likely it will be replaced by better implementations later. So no need to keep / stick to something from me right now.
>Also I think we should define a bit how we want to proceed with the assembler.
I did not start with an assembler implementation. Maybe this is something you/somebody else want to try?
I'm already busy reversing stuff and find out how things are connected.
Today my WRITER and SIMULATOR arrived. So now I can start to work with real hardware :-)
>Some stuff to be discussed may be:
>- syntax quirks (how to represent various kind of values/addresses), asm directives, macros, defines, includes, etc...
I did not really investigated on this. I just used a syntax which I thought was good enough for first tests.
Mainly I used the syntax PADAUK used in their manuals. Just to distinguish between RAM / ROM / IO we would need to invent something. Note: The "." syntax is mainly used to represent a special bit (8051 assembly). "[ ]" are used for normal memory access. "WORD PTR" is usually used for 16 bit address references, ... I think we should adapt already known schemes so it easier for others to understand
Creating a document defining the syntax of the assembler would be a good starting point.
I think during implementation of assembler some changes will be required. Since the disassembler is fairly easy to adapt I consider it to follow any syntax changes the assembler creator might need to do.
>- whether to deviate from PADAUK's ASM syntax and implement something of our own, or whether to implement their same syntax for compatibility; or even both at the same time (i.e. a flag to choose the syntax)
One syntax please :-). As close as possible to PADAUK syntax with just some extensions for direct memory/io access.
>- what binary format we want to use across the open source toolchain, i.e. just the raw ROM content on a .bin file, or keeping their PDK format for compatibility with their OTP Writer, or have our own format, or a mix of these three things, or whatever
I think we should use the PDK format. The creation for a "liberated" WRITER seems to be the most difficult part which most likely will take the longest time.
>- if it makes sense to keep the ISA description open enough so that it can be imported by someone that wants to implement for instance an SDCC backend or a radare2 plugin to disasm, etc... or just keep it simple and hard coded in the tools
The ISA is so small and simple, everyone can adapt and implement it for a disasm within a few hours. So I think there is no need to be generic here.
>Also, regarding an hypothetical PC simulator (not real time, maybe cycle accurate, or even not) for debugging only:
Why "hypothetical PC simulator"? I finished this task already
>- how that would be presented to the user, i.e.
>- a GUI? With what features? I/O interaction?
>- some kind of simulation you launch and outputs a waveform file in some standard format for inspection later (and that can also accept an input waveform file or some kind of description of what to do with the inputs - i.e. after 0.1s set PA.3 high etc...)
>- a command line tool like GDB where you can single step, inspect memory and regs, run, pause, etc...
>- a combination of some of the things above
>- ...
I was having a look at a 8051 emulator which uses ncurses ( [url]https://github.com/jarikomppa/emu8051[/url] ). This simulator I plan to repurpose for the front end.
>- we'll need our own init code if we want to create a full toolchain you can use from start to finish without touching PADAUK's tools, what should be done in that regard? Should we replicate PADAUK's code (eventually improving it) or do something else? Maybe have different init code options i.e. if you don't need precise clock speeds you can free up space by not having the calibration code, or you can chose to have it, you can have the ROM checksum or not, etc...
The init code is tied to the WRITER which I think we should stay compatible with (see comment above).
Usually this kind of things (init code) is implemented in include (.INC) files which the developer gets automatically in his project when he starts a new project (e.g. from a empty project template).
Then it up to the developer to modify / delete stuff from init code or use different/optimized implementations.
>- least important thing in this message but cool: a library of pre-made routines for stuff like SPI, UART, etc... could be made and optimized by the community. Like a collection of include files "spi.inc" "uart.inc" you can just bring in and use would be pretty cool
Personally I prefer simple sample projects with code snippets I can just cut and paste to my project. I don't like big libraries (like Arduino or STM32). Especially when every byte counts.
>The STM32 emulator you're working on is also vital in the toolchain I think, so keep that up. I started to play around with some methods of efficiently emulating the code on ARM Thumb by checking what assembly GCC generates for various approaches, and it seems like writing the time critical parts in assembly may be the easiest route... GCC insists on keeping the PC/ACC/ecc in RAM but having 12 general purpose registers I think the best thing is to assign the ACC, PC, SP, etc... to a couple of regs and avoid all the LDRs that just slow things down. Of course I may be wrong and there may be a way to write the C code in such a way that GCC does this by itself, but I still didn't find a way. I thought we could map every PADAUK's cycle to 8 cortex cycles with a CPU clock of 64MHz which sounds a reasonable choice given there's the ultracheap STM32F103C8T6 everywhere on eBay, Aliexpress, etc... that fits that frequency, staying in an 8 cycle frame might be viable if most of the stuff is in registers since most instructions take 1 cycle only. Did you make any progress regarding emulation on STM32?
After implementing the FLAG solver for AC and OV i recognized emulation will be quite complex.
Also keep in mind that you need to emulate the CLOCK, IO, PWM, INTERRUPTS, TIMER, WATCHDOG, ...
So I don't think a near real time emulation on STM32 will be possible.
But why not using FPGA? Simple ones are also very cheap. And one guy here in forum already said he would be able to create a FPGA version.
>Let me know what you think about my points and how we should proceed. If we can coordinate at least a bit the work that should be done (and how it should be done) I can start working on some tools.
Creating the assembler would be nice.
I really would love to have an assembler as soon as possible so I can automate tests for the simulator :-)
Does the FPGA have markings on the bottom? It doesnt look dremeled on the top to me.
// define pin names
Out0 BIT PB.0;
Out1 BIT PB.1;
Out2 BIT PB.2;
Out3 BIT PB.3;
Out4 BIT PB.4;
Out5 BIT PB.5;
Out6 BIT PB.6;
Out7 BIT PB.7;
// FPPA0 is started first
void FPPA0 (void)
{
.ADJUST_IC SYSCLK=IHRC/2, IHRC=16MHz, VDD=5V, Bandgap=On;
// set pins to output
$ Out0 High, Out;
$ Out1 High, Out;
$ Out2 High, Out;
$ Out3 High, Out;
$ Out4 High, Out;
$ Out5 High, Out;
$ Out6 High, Out;
$ Out7 High, Out;
// see datasheet "pmode": FPPA duty cycle, 1/8 for all 8 FPPAs
pmode 31;
// enable all FPPAs
fppen = 0xFF;
// generate test output
while (1) {
Out0 = 0;
.delay 1;
Out0 = 1;
.delay 1;
}
}
void FPPA1 (void)
{
// generate test output
while (1) {
Out1 = 0;
.delay 10;
Out1 = 1;
.delay 10;
}
}
void FPPA2 (void)
{
// generate test output
while (1) {
Out2 = 0;
.delay 100;
Out2 = 1;
.delay 100;
}
}
void FPPA3 (void)
{
// generate test output
while (1) {
Out3 = 0;
.delay 1000;
Out3 = 1;
.delay 1000;
}
}
void FPPA4 (void)
{
// generate test output
while (1) {
Out4 = 0;
.delay 10000;
Out4 = 1;
.delay 10000;
}
}
void FPPA5 (void)
{
// generate test output
while (1) {
Out5 = 0;
.delay 100000;
Out5 = 1;
.delay 100000;
}
}
void FPPA6 (void)
{
// generate test output
while (1) {
Out6 = 0;
.delay 1000000;
Out6 = 1;
.delay 1000000;
}
}
void FPPA7 (void)
{
// generate test output
while (1) {
Out7 = 0;
.delay 10000000;
Out7 = 1;
.delay 10000000;
}
}
/*
void Interrupt (void)
{
pushaf;
if (Intrq.T16)
{ // T16 Trig
// User can add code
Intrq.T16 = 0;
//...
}
popaf;
}
*/
PB0: 203 kHz
PB1: 44 kHz
PB2: 5 kHz
PB3: 508 Hz
PB4: 50.8 Hz
PB5: 5.08 Hz
PB6: 0.5 Hz
PB7: 0.05 Hz