Close

20230225a - Displaying the Current File

A project log for ROM Disassembly - AlphaSmart Pro

Wherein I disassemble the ROM from a vintage typewriter-thing

ziggurat29ziggurat29 02/26/2023 at 17:170 Comments

sub_F374 has caught my interest because it seems to be painting the LCD with the currently selected file's contents according to several state variables that I have not fully reverse-engineered.

The routine begins like this:

F374             sub_F374:
F374 BD F6 18        jsr     clearHomeLCD_F618 ; Clear LCD set cursor pos 0
F377 FE 01 20        ldx     word_120        ; XXX file related ???
F37A BD F3 D5        jsr     sub_F3D5
F37D DF 4E           stx     word_4E         ; scratch; /this/ keyboard scan column mask (rectus)
F37F FE 01 20        ldx     word_120        ; XXX file related ???
...

word_120 has been vexing for me for some time.  It's file-related and next to other file-related variables, but I haven't been able to make it out yet what it does.  Maybe this will be an opportunity to find out.

...
0120 ?? ??       word_120:       rmb 2      ; XXX file related ???
0122 ?? ??       curfileIns_122: rmb 2      ; XXX file related (current file insert ptr???) .0
0124 ?? ??       curfileEnd_124: rmb 2      ; XXX file related (current file ptr end char (one past last)???) .4
0126 ?? ??       curFileRgnLast_126:rmb 2   ; this file; file region end addr (inclusive)
0128 ?? ??       curFileRgnFirst_128:rmb 2  ; this file; file region start addr
012A ?? ?? ?? ??+aFileState_12A: rmb $30    ; XXX an array of 8 3-word file structures
...

These various file-related variables strike me as curious from a design perspective because they are essentially copies of stuff that is already in aFileState_12A and also in ROM in aFilePartitions_FB24, but just for the current file (as per thisFileNo_15D).  I'm not sure why this apparent redundancy is done, but maybe that will become clearer later.  (Or it may just be an oddity -- humans sometimes do inexplicable things.)

The sub_F3D5 is called early, just after loading X with the word_120 value, presumably as a parameter:

F3D5             sub_F3D5:
F3D5 DF 44           stx     word_44         ; XXX scratch
F3D7 86 28           ldaa    #40
F3D9 97 48           staa    byte_48         ; XXX counter; 100/40
F3DB 18 FE 01 24     ldy     curfileEnd_124  ; XXX file related (current file ptr end char (one past last)???) .4
F3DF 18 DF 42        sty     word_42
F3E2 BD EC 80        jsr     selectRAMpageForFile_EC80 ; select in the relevant RAM page based on file number (byte_15D)
F3E5             loop_F3E5:
F3E5 9C 42           cpx     word_42
F3E7 27 2A           beq     loc_F413
F3E9 A6 00           ldaa    0,x
F3EB 81 0D           cmpa    #$D
F3ED 27 1E           beq     loc_F40D
F3EF 7A 00 48        dec     byte_48         ; XXX counter; 100/40
F3F2 27 03           beq     loc_F3F7
F3F4 08              inx
F3F5 20 EE           bra     loop_F3E5
F3F7             loc_F3F7:
F3F7 BD F4 1A        jsr     sub_F41A
F3FA 29 11           bvs     loc_F40D
F3FC             loc_F3FC:
F3FC 09              dex
F3FD A6 00           ldaa    0,x
F3FF BD F4 1A        jsr     sub_F41A
F402 29 09           bvs     loc_F40D
F404 9C 44           cpx     word_44         ; XXX scratch
F406 26 F4           bne     loc_F3FC
F408 DE 44           ldx     word_44         ; XXX scratch
F40A C6 27           ldab    #$27 ; '''
F40C 3A              abx
F40D             loc_F40D:
F40D BD EC 79        jsr     selectRAMPage0_EC79 ; select 32 KiB RAM page 0
F410 08              inx
F411 0A              clv
F412 39              rts
F413             loc_F413:
F413 BD EC 79        jsr     selectRAMPage0_EC79 ; select 32 KiB RAM page 0
F416 DE 44           ldx     word_44         ; XXX scratch
F418 0B              sev
F419 39              rts

As annotated, the byte_48 location seemed to be a counter of sorts based upon cross-references and was loaded either with 100 or 40.  40 seems coincidental with the 40 columns of LCD.  I don't know what 100 is for.

But the loop "loop_F3E5" is particularly interesting since it seems to be whizzing through a file (starting at word_120) and looking for a carriage return (0x0d).  If found, it will go one past that character and clear the V bit (a common technique in this firmware to indicate 'success') and leave.

If it does not find in within the 40 chars, then it starts to look backwards (up to the point at word_120) for some sort of characterization provided by sub_F41A:

F41A             sub_F41A:
F41A 81 0D           cmpa    #$D
F41C 27 0E           beq     loc_F42C
F41E 81 09           cmpa    #9
F420 27 0A           beq     loc_F42C
F422 81 20           cmpa    #$20 ; ' '
F424 27 06           beq     loc_F42C
F426 81 2D           cmpa    #$2D ; '-'
F428 27 02           beq     loc_F42C
F42A 0A              clv
F42B 39              rts
F42C             loc_F42C:
F42C 0B              sev
F42D 39              rts

Which is pretty clear to indicate 'tab, or cr, or space, or hyphen'.  In other words, traditional line breaking characters.

So sub_F3D5 seems to actually be 'find end of display line'.  It does it by first hunting for a CR within 40 chars, and if not found, search backwards for a line-breaking character, and if not found, just give up and break it at 40 characters.

So if one was to compose a document with the word: "pneumonoultramicroscopicsilicovolcanoconiosis" (a specific lung disease caused by inhaling quartz dust), or refer to Lake Chargoggagoggmanchauggauggagoggchaubunagungamaugg (in Michigan), then you'd have to suffer a hard break in the middle of the word.  But even if you don't suffer "hippopotomonstrosesquippedaliophobia" (fear of long words) you'll almost always still be OK with a 40-char line.  Though for the mid 90's I think they really should have tried to splurge for 80.  80 looks more like a typewritten page would be.  Though such a display would have been a tight fit in this unit.  On the other hand, you can't index an 80x4 display with one byte, so there would be a price to pay in code. 

Getting back to sub_F374, the logic is a loop over characters in the file, spewing them to the LCD, starting with the location word_120, until the logical end-of-line is found, then advancing to the next line and continue spewing.  This happens until 4 lines are filled, or until the end-of-file is reached.  So it seems that word_120 is 'file position at start of screen'.  Annotated, the function now looks like this:

F374             ; re-paint LCD for current file state
F374             displayCurFile_F374:
F374 BD F6 18        jsr     clearHomeLCD_F618 ; Clear LCD set cursor pos 0
F377 FE 01 20        ldx     curfileStartOfScreen_120 ; XXX file related (current file screen start ptr???) .2
F37A BD F3 D5        jsr     findNextLineStart_F3D5 ; find start of next display line considering breaking chars;  X =  cur file.2; V if no more lines; clear if next line start valid
F37D DF 4E           stx     scratchw_4E     ; save start of /next/ line
F37F FE 01 20        ldx     curfileStartOfScreen_120 ; XXX file related (current file screen start ptr???) .2
F382 86 01           ldaa    #1
F384 97 4C           staa    scratchby_4C    ; (used for tracking row)
F386             loopLine_F386:
F386 86 01           ldaa    #1
F388 97 60           staa    scratchby_60    ; (used for tracking col)
F38A             loopChar_F38A:
F38A BC 01 22        cpx     curfileIns_122  ; is this char at the insertion point? remember (row,col) for it
F38D 26 08           bne     cont_F397       ; nope; keep spewing chars
F38F 96 4C           ldaa    scratchby_4C    ; row
F391 97 6C           staa    lcdcpRow1_6C    ; 1-relative LCD cursor pos row
F393 96 60           ldaa    scratchby_60    ; col
F395 97 6B           staa    lcdcpCol1_6B    ; 1-relative LCD cursor pos col
F397             cont_F397:
F397 BC 01 24        cpx     curfileEnd_124  ; finished entire file? leave
F39A 27 2A           beq     showCapLockLeave_F3C6
F39C BD EC 80        jsr     selectRAMpageForFile_EC80 ; select in the relevant RAM page based on file number (byte_15D)
F39F A6 00           ldaa    0,x             ; get char in file
F3A1 BD EC 79        jsr     selectRAMPage0_EC79 ; select 32 KiB RAM page 0
F3A4 BD F6 2D        jsr     xlatShowChar_F62D ; put it on the LCD (cp will advance automatically)
F3A7 08              inx                     ; next char
F3A8 7C 00 60        inc     scratchby_60    ; next col
F3AB 9C 4E           cpx     scratchw_4E     ; is it now at the start of the next display line?
F3AD 26 DB           bne     loopChar_F38A   ; nope; keep spewing chars
F3AF 96 4C           ldaa    scratchby_4C    ; row
F3B1 81 04           cmpa    #4              ; was this the 4th (last) line? leave if so
F3B3 27 11           beq     showCapLockLeave_F3C6
F3B5 7C 00 4C        inc     scratchby_4C    ; next row
F3B8 3C              pshx                    ; save file ptr while we fiddle with things
F3B9 BD F4 2E        jsr     lcdSetCPatLineA ; set LCD cursor position at start of line A
F3BC DE 4E           ldx     scratchw_4E     ; get the last end-of-line and hunt for next end-of-line
F3BE BD F3 D5        jsr     findNextLineStart_F3D5 ; find start of next display line considering breaking chars;  X =  cur file.2; V if no more lines; clear if next line start valid
F3C1 DF 4E           stx     scratchw_4E     ; save the next end-of-line
F3C3 38              pulx                    ; restore file ptr while we continue on the next line
F3C4 20 C0           bra     loopLine_F386
F3C6             showCapLockLeave_F3C6:
F3C6 13 A1 01 0A     brclr   bCapsLock_A1 1 leave_F3D4 ; flag; CAPS lock in effect
F3CA C6 9F           ldab    #159            ; cursor at end of screen
F3CC BD F7 60        jsr     commonSetCursorPosB_F760 ; common set cursor position (abs pos in B)
F3CF C6 0F           ldab    #$F             ; solid block char
F3D1 BD F6 74        jsr     sendLCDbyteB_F674 ; send byte in B to LCD (w/ctrl as per 0x5b)
F3D4             leave_F3D4:
F3D4 39              rts

And that is how we do that! 

Discussions