I spent yesterday disassembling ROM 4 of the MCU2 board. I got to 100% code coverage of that one. That doesn't mean 100% understanding, it just means all the jigsaw puzzle pieces are now on the table.
It was interesting. There are a lot of table-dispatched functions.
Dispatch Magic
I found some code which seems to be in a spin-wait for something to come into 8000h.
7874 loc_7874:
7874 E1 pop hl ; discard the return address
7875 ED 73 CE FF ld (word_FFCE), sp ; XXX stores SP during some Cefucom ROM4 stuff
7879 loop_7879:
7879 CD B9 78 call sub_78B9 ; XXX some stuff with keys (as in buttons)
787C 2A C3 FF ld hl, (word_FFC3) ; XXX Cefu; a pointer into buffer @8000h
787F 11 00 80 ld de, unk_8000
7882 B7 or a
7883 ED 52 sbc hl, de
7885 28 F2 jr z, loop_7879 ; XXX nothing 'received'; spin
7887 21 00 00 ld hl, 0
788A 22 C5 FF ld (word_FFC5), hl
788D CD E3 78 call sub_78E3 ; XXX messes with DE, which will be a synthetic return address
7890 CD 7F 79 call sub_797F
7893 01 99 78 ld bc, sub_7899
7896 C5 push bc ; queue sub_7899 on the stack
7897 D5 push de ; queue the call sub_78E3 computed
7898 C9 ret ; (not really returning from here since we queued the above two)
And there is magicry at the end.
The code infers the availability of data by the difference between the start of buffer and end of buffer, so that end of buffer pointer must be atomically updated. Cross referencing word_FFC5 I find that is indeed happening:
7899 sub_7899:
7899 F3 di ; critical section around these pointer updates
789A 2A C5 FF ld hl, (word_FFC5) ; XXX Cefu; an OFFSET into buffer @8000 while building
... move block into position at 8000h and computes end in DE and other stuff
78B2 ED 53 C3 FF ld (word_FFC3), de ; XXX Cefu; an end pointer into buffer @8000h
78B6 FB ei ; end critical section
...
so word_FFC5 seems to be used while transferring the block, and when it is completed then word_FFC3 is atomically updated with the final value.
The magicry at the end depends on sub_78E3 leaving a return address in DE, which eventually gets pushed to the stack prior to the ret, effectively synthesizing 'jp (de)'.
78E3 ; XXX lookup dispatch info
78E3 sub_78E3:
78E3 21 00 80 ld hl, unk_8000
78E6 E5 push hl
78E7 7E ld a, (hl) ; get the code from buffer
78E8 ED 4B 1C 00 ld bc, (off_1B+1) ; XXX freaky as it is in the middle of a constant; val c7e0. bug?
78EC 21 0B 79 ld hl, dispatchByCode_790B ; XXX dispatch 29 entries/116 by: (code, C, addr)
78EF loop_78EF:
78EF ED A1 cpi
78F1 28 08 jr z, leave_78FB ; found it
78F3 E2 05 79 jp po, loc_7905 ; finished; but not found
78F6 23 inc hl ; (HL already +1, so we only need +3 to get to next)
78F7 23 inc hl
78F8 23 inc hl
78F9 18 F4 jr loop_78EF
78FB leave_78FB:
78FB 4E ld c, (hl)
78FC 06 00 ld b, 0
78FE 23 inc hl
78FF 5E ld e, (hl)
7900 23 inc hl
7901 56 ld d, (hl)
7902 E1 pop hl ; (which will be 8000h)
7903 23 inc hl
7904 C9 ret
7905 loc_7905:
7905 23 inc hl
7906 23 inc hl
7907 23 inc hl
7908 23 inc hl
7909 18 F0 jr leave_78FB
The sub_78E3 basically looks up the servicing address from the code that is at the start of the block, and returns an additional associated parameter in C. Here's the first entry:
The sub_78E3 basically looks up the servicing address from the code that is at the start of the block, and returns an additional associated parameter in C. Here's the first entry:
790B 21 dispatchByCode_790B:db 21h ; code to match @8000h
790C 05 db 5 ; XXX goes in C
790D A6 79 dw sub_79A6 ; XXX goes in DE (and becomes a call address)
...
That table has 29 entries.
"State"
Rummaging through the references to PIO A code, there were sections like this:
7E96 sub_7E96:
7E96 3E 02 ld a, 2
7E98 32 E4 FF ld (byte_FFE4), a
7E9B 3E 10 ld a, 10h
7E9D D3 E0 out (0E0h), a
7E9F 3A EA FF ld a, (byte_FFE8+2)
7EA2 D3 E2 out (0E2h), a ; PIO B data out
7EA4 C9 ret
Knowing that PIO A b2,1,0 are inputs, and that b5,4,3 are outputs, it occurred to me that those might be bitfields of a 3-bit number. One expressed from MCU2 to PCU, and one expressed from PCU to MCU2. I re-annotated that code throughout:
7E96 sub_7E96:
7E96 3E 02 ld a, 2 ; transition state 2
7E98 32 E4 FF ld (byte_FFE4), a ; XXX PIO A data related; dispatch index
7E9B 3E 10 ld a, 10h
7E9D D3 E0 out (0E0h), a ; PIO A set b5 low, b4 high, b3 low (send 2)
7E9F 3A EA FF ld a, (byte_FFE8+2)
7EA2 D3 E2 out (0E2h), a ; PIO B data out
7EA4 C9 ret
Things start to make a little more sense in that context. So in sum PIO Port A is structured this way:
PIO A:
b7 - /FS from VDG
b6 - x (unused)
b5 - \
b4 - +=> "MCU2 State (to ioboard)"
b3 - /
b2 - \
b1 - +=< "PCU State (to main board)"
b0 - /
Port B has no bit structure, and seems to be used for bulk data transport between the boards.
Because there is no 'strobe' between the boards to notify of state change, I am suspect that happens as a consequence of data being available on B.
Interboard Communications
Reviewing the ISR for Port B:
7E1C isrPIOb_7E1C:
7E1C FB ei ; allow nesting this interrupt
7E1D F5 push af
7E1E C5 push bc
7E1F D5 push de
7E20 E5 push hl
7E21 CD 2F 7E call sub_7E2F
7E24 3E 0A ld a, 10
7E26 32 E3 FF ld (byte_FFE3), a
7E29 E1 pop hl
7E2A D1 pop de
7E2B C1 pop bc
7E2C F1 pop af
7E2D ED 4D reti
There is a constant whacking of byte_FFE3 to the value of 10. Cross referencing that, it can be found in the ISR for Port A:
7F95 isrPIOaHelper_7F95:
7F95 F5 push af
7F96 E5 push hl
7F97 21 E3 FF ld hl, byte_FFE3
7F9A 35 dec (hl)
7F9B 20 1A jr nz, leave_7FB7
...
So Port B whacks it to 10 ever time a byte comes over, and Port A decrements it each time a systick comes in, doing different things based on whether is reaches zero or not. So I surmise this is a 'receive data timeout'. Since I know the systick is 60 Hz, this means a timeout of 167 ms.
I elided the code above, but the short story is that 'if it times out, the system is returned to state 0'. So state 0 seems to be the quiescent state.
I should also point out that in these state processing, that Port B is turned around several times. So in both systems it is configured in 'input mode' but during the operation is it changed to output as well.
So sub_7E2F is probably the 'stow a byte and maybe advance the state machine' function.
After I went though all the dispatch tables (there's something like 12 of them), I am now at 100% disassembly coverage of ROM4. I don't know what all these things do, but it's still a milestone because code and data are now separated, so cross referencing can happen. On the other hand, this state table design will possibly require my building of another document to keep track of the system.
I did take a peek at [Nigel]'s instruction trace. At this point it's not exciting news because it is simply stuck in the 'memory test failed' loop on the PCU board. He had configured the emulator for less than 32 KiB RAM and so it was failing there. Easily fixed, and he got to a prompt, but still not working. No big surprise, still so much more to do.
OK, with this understanding of PIO A and B, I'm going back to PCU board.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.