Close

20230214b -- LCD revisited

A project log for ROM Disassembly - AlphaSmart Pro

Wherein I disassemble the ROM from a vintage typewriter-thing

ziggurat29ziggurat29 02/16/2023 at 13:440 Comments

The LCD analysis isn't strictly complete.  While I'm pretty sure I found the data lines (nybble mode, PD5-2), there are control lines as well.

While rummaging through the RAM stuff, I came across a routine:

F618             sub_F618:
F618 86 01           ldaa    #1
F61A BD F6 5E        jsr     sub_F65E
F61D 39              rts

 which then invokes:

F65E             sub_F65E:
F65E 15 5B 02        bclr    byte_5B 2
F661 16              tab
F662 BD F6 74        jsr     sendLCDbyteB_F674 ; send byte in B to LCD (w/ctrl as per 0x5b)
F665 14 5B 02        bset    byte_5B 2
F668 39              rts

before going off to the 'sendLCDbytesB' routine at F674 that I had already reversed.  There were some unknowns in that, namely the data location at 0x5B.

I know that the LCD command for "Clear Display and Set Cursor to loc 0" is 0x01, but being a command, it requires that the control lines OC1 and OC2 be set in a particular state.  As per doc, here's how they work:

OC2 OC1 function
  0   0 command
  0   1 display address
  1   0 data
  1   1 cursor address

The thing that's interesting here is that we are manipulating byte_5b, which is internal RAM, not a peripheral port.  Surely this cannot be memory-mapped.  However, revisiting sendLCDbyteB_F674, and the internal routine F68F, it became clear that loc 0x5b stores a virtual copy of those control bits, which then are transferred to harware when writing out the nybble.

F68F             sendLCDnybble_F68F:
F68F 4F              clra                    ; (an elaborate way of A = (0x5b) & 3.  Why? unknown.)
F690 13 5B 02 04     brclr   byte_5B 2 cont_F698 ; LCD control lines state in b1 = IOC2, b0 = IOC1
F694 8A 02           oraa    #2
F696 20 00           bra     *+2             ; delay 3 cy; 1.5 usec
F698             cont_F698:
F698 13 5B 01 04     brclr   byte_5B 1 cont_F6A0 ; LCD control lines state in b1 = IOC2, b0 = IOC1
F69C 8A 01           oraa    #1
F69E 20 00           bra     *+2             ; delay 3 cy; 1.5 usec
F6A0             cont_F6A0:
F6A0 58              aslb                    ; move up two bits to align lower nybble with PDb5-4
F6A1 58              aslb
F6A2 B7 80 00        staa    $8000           ; XXX mystery?
F6A5 96 08           ldaa    PORTD_8         ; PORTD:
F6A7 84 03           anda    #3              ; preserve lower two bits
F6A9 1B              aba                     ; merge on shifted B into nybble position (port D7,6 are not bonded, so who cares about those)
F6AA 97 08           staa    PORTD_8         ; write nybble out
F6AC 14 00 80        bset    PORTA_0 $80 ; 'Ç' ; flick PA7 high, low
F6AF 15 00 80        bclr    PORTA_0 $80 ; 'Ç'
F6B2 39              rts

So, the nybble to send is in B, it is shifted up to positions to get to Port D bits 5-2, and location 0x5b is translated into the two bits at Port D bits 1 and 0.  Those are merged together and written out to Port D.  PAb7 is then flicked high/low.  This almost certainly means that PAb7 is the LCD 'EX' line as per timing diagrams.

This also means that Port D is fully accounted for as for its pins (b7,6 are not available on this 40 pin DIP), unless they do double duty somehow.  It's interesting that Port D is configured for open-drain outputs, though in the photo you can clearly see a resistor pack next to where Port D is on the package, so those are doubtlessly pull-ups.

Knowing this, these actions at the start of lcdInit make now sense:

EC16             lcdInit_EC16:
EC16 15 5B 01        bclr    byte_5B 1       ; IOC1, 2 low for 'command'
EC19 15 5B 02        bclr    byte_5B 2
...

Studying other use cases and correlating with datasheet show that 0x5b bit 1 is IOC2 and bit 0 is IOC2, and that these eventually set PDb1,0.

Another mystery is starting to come to light.  The mystery of '8000h'.  I have seen several writes to this location of values 0, ffh, 4.  (Maybe there are others.)  Now that I am pretty sure RAM is at 0100-7fff, then what are these writes (and there is a similar one at C000)?  So, maybe memory mapped IO?  There is an apparently LCD related routine at EC45:

EC45             sub_EC45:
EC45 86 03           ldaa    #3
EC47 97 09           staa    DDRD_9          ; DDRD: b1, b0 output; others input
EC49 86 04           ldaa    #4
EC4B B7 80 00        staa    $8000
EC4E 14 00 80        bset    PORTA_0 $80     ; PORTA:  b7 high
EC51 96 08           ldaa    PORTD_8         ; PORTD: all data bits
EC53 15 00 80        bclr    PORTA_0 $80     ; PORTA:  b7 low
EC56 14 09 FF        bset    DDRD_9 $FF      ; DDRD:  all pins output
EC59 7F 80 00        clr     $8000
EC5C 15 08 3C        bclr    PORTD_8 $3C     ; PORTD:  b5,4,3,2 low
EC5F 39              rts

It's rarely used:  once in 'lcdInit_EC16' and twice in success in 'sendLCDbyteB_F674'.  In both cases immediately afterwards bit 5 is tested, and looping happens if it set until it goes low.  This bit happens to coincide with the 'BUSY' bit of the LCD status.  So I am concluding that sub_EC45 is 'readLCDnybble_EC45'.  I do not know 8000 for a fact, but being as it sets bit 2, and this is the only place that the LCD is read from, I am starting to suspect that 8000 is a latch, and bit 2 is wired to the LCD R/~W line (and maybe other things!).

So, on-chip port hardware is so far mapping out like this:

Port A:
b7  LCD EX
b6  (not bonded on DIP40)
b5  RAM Bank Select 1 (A16)
b4  (not bonded on DIP40)
b3  RAM Bank Select 0 (A15)
b2  ???
b1  ???
b0  ???

Port D:
b7  (not available with external memory)
b6  (not available with external memory)
b5  LCD data 7
b4  LCD data 6
b3  LCD data 5
b2  LCD data 4
b1  LCD OC2
b0  LCD OC1

Port B, C -- (used for external memory address/data bus)

There's still the possibility of multiple duty for these lines, but these applications at least I think I am pretty confident of.

A pending mystery is the emulated keyboard ports.  There are three lines on A unaccounted for, and maybe they're involved with that, but a peculiarity of Port A on this device is that bit 2,1,0 are hard configured in silicon as inputs only.  3 and 7 are bidirectional, but are here configured as outputs (and 5 is hard configured as output).  There almost surely needs to be some other output line for keyboard data, so there's more mysteries to solve there, eventually.

Update labels, comments, and propagate....

Discussions