6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 3:24 pm

All times are UTC




Post new topic Reply to topic  [ 12 posts ] 
Author Message
PostPosted: Sun Jan 23, 2022 12:32 pm 
Offline
User avatar

Joined: Thu Oct 12, 2017 10:51 pm
Posts: 90
I've just dumped the ROM of a Vtech toy laptop, the Ordi Genius Kid. The machine itself has a variety of semi-educational games and a little dot-matrix LCD screen, with lots of sampled sound, speech, and polyphonic music. The ROM is a 2MB serial flash job.

After much work with cpu_rec I have discovered that the ROM seems to contain 6502 code! Sort of. Here's a fragment:

Code:
        .byte   $0C
        cmp     $6006,y
        lsr     $A8,x
        lda     #$F3
        sta     a:$4C
        lda     #$00
        sta     a:$4D
        jsr     L6602
        rts

        lda     $06D7
        cmp     #$01
        bcs     LE829
        asl     a
        tax
        jsr     LA872
        .byte   $80
        .byte   $03
        .byte   $7C
        .byte   $7F
        tay
        inc     $06D7
        rts

LE829:  lda     #$01
        .byte   $0C
        cmp     $6006,y
        sta     ($A8,x)
        lda     #$F4
        sta     a:$4C
        lda     #$00
        sta     a:$4D
        jsr     L6602
        rts

        lda     $06D7
        cmp     #$01
        bcs     LE854
        asl     a
        tax
        jsr     LA89D
        .byte   $80
        .byte   $03
        .byte   $7C
        tax
        tay
        inc     $06D7
        rts


It's probably one of the GeneralPlus 6502-based LCD controller parts, but the ones I've found datasheets for don't describe all those extended instructions. $0c looks like a prefix byte, maybe to do with overriding the current memory bank, but the strings starting with $80 could be anything. Has anyone seen anything like this? Running my own code on it would be fascinating, if completely pointless!


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 23, 2022 12:48 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
I haven't seen this before - I too would guess a SunPlus/GeneralPlus product but only as a guess.

That tax tay sequence shows, I think, that the $80 $03 are to be followed by a pair of bytes. That is, it's not a TAX but an $AA.

It would be interesting to try to figure out these special cases by understanding the whole thing.

It would also be interesting to see a transcript of your cpu_rec session, I think. Especially in verbose mode. (A tool I haven't come across before.)

Have you seen py8dis? That might be helpful, in a modified form.


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 23, 2022 1:35 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
An enjoyable and engaging puzzle!

How confident are you that you've parsed the bytes correctly (in order to determine where the instruction boundaries lie)? I'm not challenging you; just pointing out that it would be easy to go awry, based on the fact that you have some unknown instructions. The length of such an instruction is also unknown, which means you can't reliably disassemble the bytes that follow it -- or at least that's my initial take on the situation.

Starting from the reset vector I'd say you *can* reliably disassemble, but only up to the point where the first unknown instruction occurs -- then everything after that forces you to rely on your assumptions. Let me know if I'm missing something.

Quote:
$0c looks like a prefix byte, maybe to do with overriding the current memory bank
I suppose it could be a prefix, but I have doubts about it overriding the current memory bank. Didn't you say the ROM was serial? That's a whole different addressing regimen, and it seems to me the need for banking would be absent.

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 23, 2022 3:55 pm 
Offline
User avatar

Joined: Thu Oct 12, 2017 10:51 pm
Posts: 90
All I know is that the disassembly produces sensible-looking code. You can see from the fragment I posted that it's divided fairly neatly into routines. I haven't figured out the load address yet --- I have found two different string tables which are consistent with themselves (tables of pointers pointing at strings) but not with each other, which suggests two different load addresses?

Regarding serial flash: some microcontrollers will map SPI serial flash to address space. It's slow, but if you run the flash at 100MHz and the CPU at 8MHz or so it's manageable and drastically reduces the footprint --- you only need four lines to the CPU instead of 25 or so, which simplifies the board design. I doubt this device is loading chunks of SPI flash into RAM as RAM is expensive, but I've met GeneralPlus 8051 controllers which appear to do exactly that, so I'm not ruling anything out yet.

Regarding cpu_rec: I actually used the binwalk plugin for this, as raw cpu_rec got rather confused, presumably by the large amounts of encoded audio in the ROM image. It said this. The block quoted above is from the beginning of the block at 0x2800.

Code:
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             None (size=0x2800, entropy=0.756435)
10240         0x2800          6502 (size=0x1800, entropy=0.815547)
16384         0x4000          None (size=0x8000, entropy=0.700533)
49152         0xC000          6502 (size=0x800, entropy=0.682909)
51200         0xC800          None (size=0x5800, entropy=0.494502)
73728         0x12000         6502 (size=0x800, entropy=0.752871)
75776         0x12800         None (size=0x1000, entropy=0.708310)
79872         0x13800         6502 (size=0x800, entropy=0.735430)
81920         0x14000         None (size=0x4800, entropy=0.302463)
100352        0x18800         6502 (size=0x2000, entropy=0.713948)
108544        0x1A800         None (size=0x18800, entropy=0.727674)
208896        0x33000         6502 (size=0x1000, entropy=0.675372)
212992        0x34000         None (size=0x5800, entropy=0.683224)
235520        0x39800         NDS32 (size=0x2000, entropy=0.580428)
243712        0x3B800         None (size=0x1000, entropy=0.685640)
247808        0x3C800         IA-64 (size=0x6000, entropy=0.581180)
272384        0x42800         None (size=0x1bc000, entropy=0.866990)
2091008       0x1FE800        6502 (size=0x800, entropy=0.755303)
2093056       0x1FF000        None (size=0x1000, entropy=0.806666)


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 23, 2022 4:39 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1949
Location: Sacramento, CA, USA
Maybe try running it through a 'c02 disassembler? It looks a lot like 65c02 machine language to me. The $80 $03 is BRA *+3, the $0C $D9 $06 $60 is TSB $06D9 : RTS, and the $7C $7F $A8 is JMP ($A87F,X) ... maybe ...

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 23, 2022 5:33 pm 
Offline
User avatar

Joined: Thu Oct 12, 2017 10:51 pm
Posts: 90
barrym95838 wrote:
Maybe try running it through a 'c02 disassembler? It looks a lot like 65c02 machine language to me. The $80 $03 is BRA *+3, the $0C $D9 $06 $60 is TSB $06D9 : RTS, and the $7C $7F $A8 is JMP ($A87F,X) ... maybe ...


facepalm

Yes, it definitely looks like a 65c02. Here's the disassembly (different disassembler, different base address). It looks like it makes sense; I fed it all to ghidra, managed to identify a load address, and it looks like this. There's a weird JSR/BRA/JMP(abs),X construct which looks like a subroutine call to a code offset in X. Maybe a system call handler of some kind?

Code:
            a850 0c d9 06        TSB        DAT_06d9
            a853 60              RTS
            a854 56 a8           LSR        0xa8,X
            a856 a9 f3           LDA        #0xf3
            a858 8d 4c 00        STA        switchD_a89a::Z40                                = ??
            a85b a9 00           LDA        #0x0
            a85d 8d 4d 00        STA        switchD_a89a::caseD_20                           = ??
            a860 20 02 66        JSR        switchD_a89a::caseD_48
            a863 60              RTS
            a864 ad d7 06        LDA        switchD_a89a::caseD_5a
            a867 c9 01           CMP        #0x1
            a869 b0 0e           BCS        LAB_a879
            a86b 0a              ASL        A
            a86c aa              TAX
            a86d 20 72 a8        JSR        SUB_a872
            a870 80 03           BRA        LAB_a875
                             SUB_a872                                        XREF[1]:     a86d(c) 
            a872 7c 7f a8        JMP        (LAB_a87f,X)
                             LAB_a875                                        XREF[1]:     a870(j) 
            a875 ee d7 06        INC        switchD_a89a::caseD_5a
            a878 60              RTS
                             LAB_a879                                        XREF[1]:     a869(j) 
            a879 a9 01           LDA        #0x1
            a87b 0c d9 06        TSB        DAT_06d9
            a87e 60              RTS



Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 23, 2022 7:08 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
Oh, nice!


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 23, 2022 7:18 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1949
Location: Sacramento, CA, USA
hjalfi wrote:
There's a weird JSR/BRA/JMP(abs),X construct which looks like a subroutine call to a code offset in X.
That's a work-around to cover the 65c02's lack of a JSR (abs,X) instruction. Old-school '02 coders typically utilize a different route entirely, but it's an effective kludge.

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 24, 2022 10:47 pm 
Offline
User avatar

Joined: Thu Oct 12, 2017 10:51 pm
Posts: 90
Quick update! I've discovered several interesting things.

(a) I've managed to positively identify the address of a few routines, based on references to tables. That JSR/BRA/JMP sequence is really handy, too, as the JSR $+2 is very easy to identify.
(b) I discovered that my ROM dump was missing bytes every so often, which was incredibly confusing. I repeated it until I got a consistent result and now it makes more sense.
(c) Hooking up a signal analyser and watching how the device accesses the SPI flash shows that it reads one byte at a time, following the execution path. When it hits a BEQ it reads one byte after the branch and then starts reading bytes from the address jumped to. This is excellent news, as it means that it's mapped the SPI flash into the 6502's address space and is making SPI reads for every memory access.
(d) The very first thing it does is to read the address 0xc951 from the flash. Then it starts execution of code at what I determined to be address 0xc951. This is in the flash at offset 0x14951. This suggests a simple mapping of flash offset to address. Lots of code starts happening in the ROM at 0x12000, which would correspond to 0xa000... and yup, that all works perfectly!

So I'm going to guess that this device has a SPI flash bridge (I've seen references to a SPI SRAM bridge in some GeneralPlus devices, and flash is the same protocol). That means that it's capable of memory mapping the 2MB SPI flash. It has to be banked. There's also going to be a mask ROM internal to the blob on the PCB, and that'll be banked somewhere else. The next obvious chunk of ROM is at 0x18000, which suggests a 24kB window. I can see subroutine calls to routines from 0x2000-0x7000ish so I reckon that's where the mask ROM window is. RAM is below that. I would actually have expected the ROM to be mapped up high where the exception vectors are, but whatever.

This means that it's wide open for exploiting! All I need to do is write code to the flash in the right place, and the mask ROM will happily run it. Of course, until I can identify a way to get data out there's not a lot I can do with that, but this machine has loads of GPIOs for running the keyboard.

The ROM is full of jump tables, which ghidra hates.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 24, 2022 11:54 pm 
Offline
User avatar

Joined: Thu Oct 12, 2017 10:51 pm
Posts: 90
...I've figured out why it's going to 0xc951 on startup --- there's a system call table at the bottom of the flash with addresses and memory banks in it, so system call 12 pages in bank 0x82 and jumps to 0xc951. That let me fabricate my own flash image which on startup jumps to 0xa000 and just spins in an infinite loop; the device actually runs this, at least until the watchdog timer kills it, and I can see it happen with the logic analyser. The screen seems to have startup up, too. Tomorrow's job is to write to video memory and see what comes out.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 25, 2022 2:57 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
Sounds like you're having fun! :)

Care to share a photo or two of this toy laptop?

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 25, 2022 11:13 am 
Offline
User avatar

Joined: Thu Oct 12, 2017 10:51 pm
Posts: 90
Currently it's in pieces and probably can't be reassembled again due to having had to solder a socket onto where the eight-pin flash chip was, but it's one of these:

Image

Yes, that's an ortho alphabetic keyboard. It's about as bad as you'd expect. Shockingly the dpad is surprisingly decent. I managed to damage the paper LCD ribbon cable so one column of pixels doesn't work any more, but it's not like this thing is worth anything. I think the English equivalent is the My Zone.

There are some similar toy laptops with full qwerty keyboards; I'll see if I can get my hands on one...


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC


Who is online

Users browsing this forum: Google [Bot] and 26 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: