3000H - Copyright Stamp and Unused Bytes
The Diagnostic's first 21 bytes are not code. The CPU reaches the Diagnostic through two jumps in ROM A, which stays at 0000H-1FFFH: the reset entry 0000H-0004H (DI / XOR A / JP 3015H) and the NMI entry 0066H (JP 3039H). Nothing jumps to 3000H-3014H, so the copyright stamp and the five zero bytes after it are never executed.
3000-300F
DEFM "(c) 1989 M.A.D.",00H 28 63 29 20 31 39 38 39 20 4D 2E 41 2E 44 2E 00
The copyright stamp (c) 1989 M.A.D. and a 00H byte, 16 bytes at 3000H-300FH. No instruction reads them; the banner the Diagnostic shows comes from 30A0H.
3010-3014
DEFB 00H x 5 00 x 5
Five 00H bytes at 3010H-3014H, before the entry point 3015H that the JP 3015H at ROM A 0002H reaches after a reset. Nothing jumps to them or reads them.
3015H - Cold Start: Stack, Clock, NMI Mask and Drive Number
After a reset ROM A runs DI / XOR A / JP 3015H (0000H-0004H), so the Diagnostic starts here with interrupts disabled. It never executes an EI, so maskable interrupts stay off for the whole program; the only interrupt it uses is the NMI the floppy disk controller raises at the end of a sector read (3609H, 3629H).
3015
LD SP,4100H 31 00 41
Load the Stack Pointer with 4100H: the stack grows down from 40FFH in RAM, below the work cells at 42FCH-42FFH and the sector buffer at 4300H.
3018
LD A,50H 3E 50
Load Register A with 50H, the value for port ECH: bits 6 and 4 set, all other bits clear.
301A
OUT (ECH),A D3 EC
Write Register A (50H) to port ECH: the CPU clock goes to 4 MHz and the external I/O bus is enabled; video waits, the alternate character set and double width are off.
| Port ECH: 50H (01010000) | | Function Description |
| 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | | Bit 6 = 1: CPU clock 4 MHz Bit 5 = 0: video waits off Bit 4 = 1: external I/O bus enabled Bit 3 = 0: standard character set Bit 2 = 0: normal width characters Bit 1 = 0: cassette motor bit |
301C
IM 1 ED 56
Set the Z80 to interrupt mode 1 (IM 1), where a maskable interrupt would restart at 0038H. Interrupts are disabled and no EI follows anywhere in the Diagnostic.
301E
XOR A AF
Set Register A to 00H (XOR A), the value for the NMI mask port and for the drive number cell.
301F
OUT (E4H),A D3 E4
Write Register A (00H) to port E4H, the NMI mask: no NMI is enabled until the sector read at 3609H turns on the one for the end of a command.
| Port E4H (NMI Mask): 00H (00000000) | | Function Description |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | Bit 7 = 0: no NMI on INTRQ Bit 6 = 0: the second NMI source of the port off Bits 5-0: not used |
3021
LD (42FCH),A 32 FC 42
Store Register A (00H) at 42FCH, the drive number cell: drive 0. The disk test (3338H) changes it; the floppy boot (3426H) uses drive 0 from here.
3024
LD A,0FH 3E 0F
Load Register A with 0FH, the number of the last CRT controller register (R15); the loop at 302BH programs R15 down to R0.
3026
LD HL,3407H 21 07 34
Load Register Pair HL with 3407H, the last byte of the 16-byte CRT controller table 33F8H-3407H, which holds the value for R15.
3029
LD C,89H 0E 89
Load Register C with 89H, the CRT controller data port, the port the OUTD at 302DH writes to.
302BH - Program the CRT Controller for 64 x 16
The 16 bytes 33F8H-3407H are written to the CRT controller's registers R15 down to R0, so 33F8H holds R0 and 3407H holds R15. Port 88H selects the register, port 89H takes its value.
302B
OUT (88H),A D3 88
Write Register A (the register number, 0FH down to 00H) to port 88H, the CRT controller address port, selecting the register.
302D
OUTD ED AB
OUTD: write the byte at Register Pair HL to the port in Register C (89H), then DECrement Register Pair HL to the byte for the next lower register and DECrement Register B (Register B is not used as a count here).
302F
DEC A 3D
DECrement Register A to the next lower register number; it goes from 00H to FFH after R0, which sets the SIGN FLAG.
3030
If the P FLAG is set (Register A is 00H to 7FH, a register still to write), JUMP to 302BH; after R0 Register A is FFH and the loop ends.
3033
LD HL,3045H 21 45 30
Load Register Pair HL with 3045H, the address the screen clear at 3082H jumps to when it is done (it ends with JP (HL)).
3036
JUMP to 3082H to fill video RAM 3C00H-3FFFH with spaces; it comes back to 3045H through Register Pair HL.
3038
NOP 00
A 00H byte between the jump at 3036H and the NMI entry 3039H; the JR at 3036H passes it and nothing jumps to it.
3039H - NMI Entry
ROM A's NMI entry 0066H holds JP 3039H, so a non-maskable interrupt comes here. The only NMI the Diagnostic enables is the one for the end of a sector read (port E4H = 80H at 3609H); its handler is at 3629H.
3039
JUMP to 3629H, the handler for the NMI that ends a sector read: it drops the address the NMI pushed and goes on to check the controller's status.
303CH - Video RAM Failure: Show Static RAM Bad and Stop
Reached from 304BH when 3C00H does not read back the space the clear at 3082H wrote. Register Pair DE still holds 3C00H, so the message goes to the top left of the screen, and the CPU halts with interrupts disabled until the machine is reset.
303C
LD HL,3092H 21 92 30
Load Register Pair HL with 3092H, the text Static RAM Bad.
303F
LD BC,000EH 01 0E 00
Load Register Pair BC with 000EH (14), the length of the text Static RAM Bad.
3042
LDIR ED B0
Copy the 14 bytes at Register Pair HL (3092H) to Register Pair DE (3C00H, the top line of the screen), counting Register Pair BC down to 0000H.
3044
HALT 76
HALT: the CPU stops. Interrupts are disabled and no NMI is enabled, so only a reset restarts the machine.
3045H - Check Video RAM, Show the Menu
The screen has just been filled with spaces. One byte, 3C00H, is read back; if it is not a space the video RAM (static RAM) is reported bad. Otherwise the banner and the menu are copied to the top four lines of the screen.
3045
LD DE,3C00H 11 00 3C
Load Register Pair DE with 3C00H, the first byte of video RAM.
3048
LD A,(DE) 1A
Fetch the byte at Register Pair DE (3C00H) into Register A.
3049
CP 20H FE 20
Compare Register A (the byte read from 3C00H) against 20H, the space the clear at 3082H stored there.
304B
If the NZ FLAG is set (3C00H did not hold the space), JUMP to 303CH to show Static RAM Bad and halt.
304D
LD HL,30A0H 21 A0 30
Load Register Pair HL with 30A0H, the banner and menu text.
3050
LD BC,00E1H 01 E1 00
Load Register Pair BC with 00E1H (225), the length of the text at 30A0H-3180H: three full lines of 64 characters and 33 characters of the fourth.
3053
LDIR ED B0
Copy the 225 bytes at Register Pair HL (30A0H) to Register Pair DE (3C00H), counting Register Pair BC down to 0000H: the banner, the version and Select line, and the two lines that name the tests.
3055
LD D,B 50
Copy Register B (00H, the LDIR has counted Register Pair BC down to 0000H) into Register D.
3056
LD E,C 59
Copy Register C (00H) into Register E: Register Pair DE = 0000H, the screen offset the tests start at (345EH ORs 3CH into Register D, so 0000H is 3C00H).
3057H - Scan the Keyboard for a Test Key
Polls three rows of the keyboard matrix until one of the six keys is down. The rows read 1 for a key that is down. D, M and the screen clear: Register Pair HL is loaded with the test's address and 3082H clears the screen and jumps there. B, V, P and S jump straight to their test.
3057
LD A,(3801H) 3A 01 38
Fetch keyboard row 3801H (keys @ A B C D E F G, bits 0-7) into Register A.
305A
BIT 4,A CB 67
Test bit 4 of Register A, the D key: the Z FLAG is clear when D is down.
305C
LD HL,3322H 21 22 33
Load Register Pair HL with 3322H, the disk test, for the jump through 3082H. The flags of the BIT at 305AH are unchanged.
305F
If the NZ FLAG is set (D is down), JUMP to 3082H to clear the screen and go to the disk test at 3322H.
3061
BIT 2,A CB 57
Test bit 2 of Register A (row 3801H), the B key: the Z FLAG is clear when B is down.
3063
If the NZ FLAG is set (B is down), JUMP to 3426H, boot from floppy disk drive 0.
3066
LD A,(3804H) 3A 04 38
Fetch keyboard row 3804H (keys P Q R S T U V W, bits 0-7) into Register A.
3069
BIT 6,A CB 77
Test bit 6 of Register A, the V key: the Z FLAG is clear when V is down.
306B
If the NZ FLAG is set (V is down), JUMP to 3181H, the video test.
306E
BIT 0,A CB 47
Test bit 0 of Register A (row 3804H), the P key: the Z FLAG is clear when P is down.
3070
If the NZ FLAG is set (P is down), JUMP to 3408H, the printer test.
3073
BIT 3,A CB 5F
Test bit 3 of Register A (row 3804H), the S key: the Z FLAG is clear when S is down.
3075
If the NZ FLAG is set (S is down), JUMP to 365CH, boot from the RS-232 port.
3078
LD A,(3802H) 3A 02 38
Fetch keyboard row 3802H (keys H I J K L M N O, bits 0-7) into Register A.
307B
AND 20H E6 20
AND Register A with 20H, keeping bit 5, the M key: the Z FLAG is set when M is not down.
307D
If the Z FLAG is set (none of the six keys is down), JUMP back to 3057H and scan again.
307F
LD HL,31C8H 21 C8 31
Load Register Pair HL with 31C8H, the memory test; the code falls into 3082H, which clears the screen and jumps there.
3082H - Clear the Screen and Jump through HL
Fills the 1024 bytes of video RAM 3C00H-3FFFH with spaces, working in the alternate register set so that Register Pairs BC, DE and HL of the caller are kept, then jumps to the address in Register Pair HL. Callers: 3036H (HL = 3045H), 305FH (HL = 3322H) and the fall from 307FH (HL = 31C8H).
3082
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set (EXX): Register Pair HL (the address to go to) is kept in the alternate set while the clear runs.
3083
LD HL,3FFFH 21 FF 3F
Load Register Pair HL with 3FFFH, the last byte of video RAM; the fill runs downward from here.
3086
LD BC,03FFH 01 FF 03
Load Register Pair BC with 03FFH (1023), the bytes 3C00H-3FFEH that the LDDR fills after the first one.
3089
LD D,H 54
Copy Register H (3FH) into Register D, the high byte of the fill address 3FFFH.
308A
LD E,L 5D
Copy Register L (FFH) into Register E: Register Pair DE = 3FFFH, equal to Register Pair HL.
308B
LD (HL),20H 36 20
Store 20H (a space) at Register Pair HL (3FFFH), the byte the LDDR copies down the screen.
308D
DEC DE 1B
DECrement Register Pair DE to 3FFEH, one below Register Pair HL.
308E
LDDR ED B8
LDDR: copy the byte at Register Pair HL to Register Pair DE and DECrement both, counting Register Pair BC down to 0000H; each byte copied is the space stored the step before, so 3FFEH down to 3C00H become spaces.
3090
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set again (EXX): the caller's Register Pairs come back, Register Pair HL holding the address to go to.
3091
JP (HL) E9
JUMP to the address in Register Pair HL: 3045H after the power-up clear, 3322H for the disk test or 31C8H for the memory test.
3092H - Message Text: Static RAM Bad, Banner and Menu
Text the Diagnostic copies to the screen with LDIR, by count, with no end byte: Static RAM Bad (14 bytes, 303CH) and the 225 bytes of banner and menu (304DH), laid out as lines of 64 characters, so 30A0H, 30E0H, 3120H and 3160H start the first four lines of the screen (3C00H, 3C40H, 3C80H, 3CC0H).
3092-309F
DEFM "Static RAM Bad" 53 74 61 74 69 63 20 52 41 4D 20 42 61 64
Static RAM Bad, the 14 bytes 303CH copies to 3C00H when video RAM does not read back a space. No end byte follows; the copy is counted by Register Pair BC = 000EH.
30A0-30DF
DEFM "XDROM Diagnostics (c) 1989 M.A.D. Software. All rights reserved" 58 44 52 4F 4D 20 44 69 61 67 6E 6F 73 74 69 63 73 20 28 63 29 20 31 39 38 39 20 4D 2E 41 2E 44 2E 20 53 6F 66 74 77 61 72 65 2E 20 20 41 6C 6C 20 72 69 67 68 74 73 20 72 65 73 65 72 76 65 64
The first line of the screen (3C00H-3C3FH), 64 characters: the banner XDROM Diagnostics (c) 1989 M.A.D. Software. All rights reserved.
30E0-311F
DEFM "Version is 1(1) 1-Apr-89 Select:(M|D|V|B|P|S) RESET to exit." 56 65 72 73 69 6F 6E 20 69 73 20 20 31 28 31 29 20 20 31 2D 41 70 72 2D 38 39 20 20 20 53 65 6C 65 63 74 3A 28 4D 7C 44 7C 56 7C 42 7C 50 7C 53 29 20 52 45 53 45 54 20 74 6F 20 65 78 69 74 2E
The second line of the screen (3C40H-3C7FH), 64 characters: the version 1(1) of 1-Apr-89 and the prompt that names the six keys, M D V B P S, and RESET to leave the Diagnostic.
3120-315F
DEFM "M - Memory D - Disk V - Video B - Boot from Floppy Disk " 4D 20 2D 20 4D 65 6D 6F 72 79 20 20 20 44 20 2D 20 44 69 73 6B 20 20 20 56 20 2D 20 56 69 64 65 6F 20 20 20 42 20 2D 20 42 6F 6F 74 20 66 72 6F 6D 20 46 6C 6F 70 70 79 20 44 69 73 6B 20 20 20
The third line of the screen (3C80H-3CBFH), 64 characters: what the keys M, D, V and B do (memory test, disk test, video test, boot from floppy disk).
3160-3180
DEFM "P - Printer S - Boot from RS232" 50 20 2D 20 50 72 69 6E 74 65 72 20 20 20 53 20 2D 20 42 6F 6F 74 20 66 72 6F 6D 20 52 53 32 33 32
The fourth line of the screen (3CC0H-3CE0H), 33 characters, the last of the 225 bytes copied at 3053H: what the keys P and S do (printer test, boot from the RS-232 port).
3181H - Video Test (V)
Selected with V. For each character in the list at 31C1H-31C6H the test fills both pages of video RAM with it (33D0H) and waits for the space bar, then sets the display to 80 x 24 (port 84H bit 2 and the CRT controller values at 31B7H-31C0H) and waits again, then puts the CRT controller back to its 64 x 16 values (33E9H). After the last character it starts again with the first. The pointer into the list is kept in the alternate register set while the helpers run. RESET ends the test.
3181
LD HL,31C1H 21 C1 31
Load Register Pair HL with 31C1H, the first of the fill characters 31C1H-31C6H (the list ends with 00H at 31C7H).
3184
LD A,(HL) 7E
Fetch the fill character at Register Pair HL into Register A.
3185
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the 00H that ends the list.
3186
If the Z FLAG is set (the end of the list), JUMP back to 3181H to start again with the first character.
3188
INC HL 23
INCrement Register Pair HL to the next character of the list, for the next pass.
3189
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set (EXX): the list pointer in Register Pair HL is kept there while the fill, the key wait and the CRT controller routines use the other set.
318A
GOSUB to 33D0H to fill both 1024-byte pages of video RAM with the character in Register A; it leaves port 84H at 00H, the 64 x 16 display, page 0.
318D
GOSUB to 31A3H to wait until the space bar is let go and pressed again.
3190
LD A,04H 3E 04
Load Register A with 04H, the value for port 84H: bit 2 set (80 x 24 display), all other bits clear.
3192
OUT (84H),A D3 84
Write Register A (04H) to port 84H: the display goes to 80 x 24; bits 1-0 = 00 keep the memory map with the ROMs, the keyboard at 3800H and video RAM at 3C00H; normal (not reverse) video, page 0.
3194
LD HL,31C0H 21 C0 31
Load Register Pair HL with 31C0H, the last byte of the 80 x 24 CRT controller table 31B7H-31C0H (the value for R9).
3197
GOSUB to 33ECH to write the 10 bytes ending at Register Pair HL (31C0H) to the CRT controller registers R9 down to R0: 80 characters a line, 24 lines.
319A
GOSUB to 31A3H to wait until the space bar is let go and pressed again, with the screen in 80 x 24.
319D
GOSUB to 33E9H to write the 64 x 16 values 33F8H-3401H to the CRT controller registers R9 down to R0 again.
31A0
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set again (EXX): Register Pair HL is the list pointer once more, at the next fill character.
31A1
JUMP to 3184H to fetch the next fill character and run the next pass.
31A3H - Wait for the Space Bar
Used by the video test between its steps. It waits until the space bar (bit 7 of keyboard row 3840H) is up, waits a fixed delay of 2560 DJNZ steps, then waits until the space bar is down and returns. Uses Register Pairs BC and HL and Register A.
31A3
LD HL,3840H 21 40 38
Load Register Pair HL with 3840H, keyboard row 6 (ENTER CLEAR BREAK UP DOWN LEFT RIGHT SPACE, bits 0-7).
31A6
LD BC,000AH 01 0A 00
Load Register Pair BC with 000AH: Register B = 00H (256 steps for the DJNZ at 31ADH) and Register C = 0AH (10 rounds of it).
31A9
LD A,(HL) 7E
Fetch keyboard row 3840H at Register Pair HL into Register A; bit 7 is 1 while the space bar is down.
31AA
RLCA 07
Rotate Register A left (RLCA): bit 7, the space bar, goes into the CARRY FLAG.
31AB
If the CARRY FLAG is set (the space bar is still down), JUMP back to 31A6H to load the delay again and look again.
31AD
DECrement Register B and LOOP BACK to 31ADH until it is zero: 256 steps of delay.
31AF
DEC C 0D
DECrement Register C, the rounds of 256 steps left.
31B0
If the NZ FLAG is set (rounds are left), JUMP back to 31ADH for the next 256 steps: 2560 in all.
31B2
LD A,(HL) 7E
Fetch keyboard row 3840H at Register Pair HL into Register A, to see whether the space bar has been pressed.
31B3
RLCA 07
Rotate Register A left (RLCA): bit 7, the space bar, goes into the CARRY FLAG.
31B4
RET C D8
If the CARRY FLAG is set (the space bar is down), RETURN to the caller.
31B5
JUMP back to 31B2H and look at the space bar again until it is pressed.
31B7H - CRT Controller Values for 80 x 24
Ten values for the CRT controller registers R0-R9 that the video test writes with 33ECH (Register Pair HL = 31C0H, the routine writes R9 first and works down to R0 at 31B7H). The display has 80 characters a line and 24 lines of 10 scan lines. Data, not code.
31B7
DEFB 63H 63
R0, horizontal total: 63H (99), so a scan line takes 100 character times.
31B8
DEFB 50H 50
R1, horizontal displayed: 50H (80) characters on each line.
31B9
DEFB 55H 55
R2, horizontal sync position: 55H (85), the character time where the horizontal sync starts.
31BA
DEFB 0AH 0A
R3, sync width: 0AH (10) character times of horizontal sync.
31BB
DEFB 19H 19
R4, vertical total: 19H (25), so a frame takes 26 character rows.
31BC
DEFB 04H 04
R5, vertical total adjust: 04H, four more scan lines added to each frame.
31BD
DEFB 18H 18
R6, vertical displayed: 18H (24) character rows on the screen.
31BE
DEFB 18H 18
R7, vertical sync position: 18H (24), the character row where the vertical sync starts.
31BF
DEFB 00H 00
R8, interlace mode: 00H, a normal display that is not interlaced.
31C0
DEFB 09H 09
R9, maximum scan line address: 09H, so each character row has ten scan lines (0-9).
31C1H - Fill Characters of the Video Test
The characters the video test fills the screen with, in order, ending with 00H, which sends the test back to the first one (3186H). Data, not code.
31C1
DEFB 45H 45
45H, the letter E: the first character the video test fills both pages of the screen with.
31C2
DEFB 5FH 5F
5FH, the underline character: the second fill character of the video test.
31C3
DEFB 7CH 7C
7CH, the vertical bar character: the third fill character of the video test.
31C4
DEFB 2BH 2B
2BH, the plus sign: the fourth fill character of the video test.
31C5
DEFB BAH BA
BAH, a graphics character (codes 80H-BFH are the 2 x 3 block characters): the fifth fill character of the video test.
31C6
DEFB BFH BF
BFH, the graphics character with all six blocks lit: the sixth fill character, a solid screen.
31C7
DEFB 00H 00
00H, the end of the list: when 3184H fetches it the test goes back to the first character at 31C1H.
31C8H - Memory Test (M)
Selected with M; 3082H has cleared the screen and Register Pair DE is 0000H. All 64K of main RAM is tested, so the test keeps its stack (3FFEH), its pass counter (3C2FH) and its result block (3C30H-3C34H) in video RAM. Each pass tests the upper 32K (8000H-FFFFH) with the routine at 32B7H run from the ROM, then copies the routine to 8100H and runs the copy to test the lower 32K (0000H-7FFFH), which needs the ROMs switched out of the memory map. Passes repeat until an error is found; then the counts are shown and the CPU halts.
31C8
XOR A AF
Set Register A to 00H (XOR A), the starting value of the pass counter.
31C9
LD (3C2FH),A 32 2F 3C
Store Register A (00H) at 3C2FH, the pass counter. It is a byte of video RAM (line 0, column 47) and shows on the screen as a character.
31CC
LD SP,3FFEH 31 FE 3F
Load the Stack Pointer with 3FFEH: the stack is in video RAM, at the bottom right of the screen, since every byte of main RAM is about to be written.
31CF
LD HL,3261H 21 61 32
Load Register Pair HL with 3261H, the title 64K Memory Test Pass= (ends with 00H at 3277H).
31D2
GOSUB to 345EH to put the title at Register Pair DE (0000H, so at 3C00H-3C15H, the top line); Register Pair DE ends at 3C16H.
31D5H - One Pass: Count It, Test Both Halves
Adds one to the pass counter, shows it, tests 8000H-FFFFH from the ROM, then 0000H-7FFFH from the copy at 8100H. Index Register IX points at the five-byte result block that 32B7H clears and fills: +00H the number of wrong reads, +01H the number that were wrong again when read a second time, +02H-+03H the address of the last error (high byte first), +04H the data bits that were ever wrong.
31D5
LD HL,3C16H 21 16 3C
Load Register Pair HL with 3C16H, the screen position after Pass= on the top line, where 330CH writes the pass count.
31D8
LD BC,3C2FH 01 2F 3C
Load Register Pair BC with 3C2FH, the pass counter in video RAM.
31DB
LD A,(BC) 0A
Fetch the pass counter at Register Pair BC (3C2FH) into Register A.
31DC
INC A 3C
INCrement Register A, the number of this pass (01H for the first; after FFH it goes to 00H).
31DD
LD (BC),A 02
Store Register A (the pass number) at Register Pair BC (3C2FH).
31DE
GOSUB to 330CH to show Register A (the pass number) as two hexadecimal digits at Register Pair HL (3C16H-3C17H); it uses Register D.
31E1
LD IX,3C30H DD 21 30 3C
Load Index Register IX with 3C30H, the result block in video RAM (line 0, columns 48-52).
31E5
LD HL,8000H 21 00 80
Load Register Pair HL with 8000H, the first byte of the upper 32K of RAM that 32B7H tests now.
31E8
GOSUB to 32B7H, run from the ROM, to test the 32K from Register Pair HL (8000H-FFFFH); the results go to the block at Index Register IX (3C30H).
31EB
LD A,(IX+00H) DD 7E 00
Fetch the number of wrong reads, at Index Register IX+00H (3C30H), into Register A.
31EE
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set when the upper 32K had no error.
31EF
If the NZ FLAG is set (an error was found), JUMP to 3215H to show the counts and halt.
31F1
LD IX,FC30H DD 21 30 FC
Load Index Register IX with FC30H, the same result block as it is addressed while port 84H is 02H, with video RAM at F800H-FFFFH: 320FH reads the results back at 3C30H after the copy has set port 84H to 00H again.
31F5
LD DE,8100H 11 00 81
Load Register Pair DE with 8100H, where the routine is copied to, in the upper 32K that has just been tested.
31F8
LD BC,0059H 01 59 00
Load Register Pair BC with 0059H (89), the length of the routine 32B3H-330BH.
31FB
LD HL,32B3H 21 B3 32
Load Register Pair HL with 32B3H, the first byte of the routine to copy (the port 84H setting at 32B3H and the test from 32B7H).
31FE
LDIR ED B0
Copy the 89 bytes at Register Pair HL (32B3H-330BH) to Register Pair DE (8100H-8158H), counting Register Pair BC down to 0000H. The routine uses only relative jumps, so the copy runs as it is.
3200
LD H,B 60
Copy Register B (00H after the LDIR) into Register H.
3201
LD L,C 69
Copy Register C (00H) into Register L: Register Pair HL = 0000H, the first byte of the lower 32K that the copy tests.
3202
LD SP,FFFEH 31 FE FF
Load the Stack Pointer with FFFEH. The CALL at 3205H pushes 3208H at FFFCH-FFFDH while port 84H is still 00H, so in main RAM of the half already tested; the copy's own pushes, made after it sets port 84H to 02H, go to video RAM, which is at F800H-FFFFH in that map.
3205
CALL 8100H CD 00 81
GOSUB to 8100H, the copy: it sets port 84H to 02H (RAM at 0000H), tests 0000H-7FFFH, sets port 84H to 00H again and returns to 3208H through FFFCH in main RAM.
3208
LD SP,3FFEH 31 FE 3F
Load the Stack Pointer with 3FFEH again, the stack in video RAM.
320B
LD IX,3C30H DD 21 30 3C
Load Index Register IX with 3C30H, the result block at its address with port 84H at 00H.
320F
LD A,(IX+00H) DD 7E 00
Fetch the number of wrong reads of the lower 32K, at Index Register IX+00H (3C30H), into Register A.
3212
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set when the lower 32K had no error.
3213
If the Z FLAG is set (no error in this pass), JUMP to 31D5H for the next pass.
3215H - Show the Error Counts and Halt
Reached when a half of RAM had an error; Index Register IX points at the result block at 3C30H. Line 2 of the screen (3C80H) gets the labels and three values: the number of wrong reads after Intr Errors= (3C8CH), the number that were wrong again after Hard Errors= (3C9CH) and the address of the last error at 3CADH-3CB0H, after Last Error @ and one blank column. Line 4 (3D00H) gets Failing Rows: and the number (7 down to 0) of every data bit that was ever wrong, a digit at every second column. The CPU then halts.
3215
LD DE,3C80H 11 80 3C
Load Register Pair DE with 3C80H, the start of line 2 of the screen.
3218
LD HL,3278H 21 78 32
Load Register Pair HL with 3278H, the labels Intr Errors= Hard Errors= Last Error @ (44 characters, then 00H at 32A4H).
321B
GOSUB to 345EH to put the labels at Register Pair DE (3C80H-3CABH); Register Pair HL is left at the 00H at 32A4H.
321E
LD DE,3D00H 11 00 3D
Load Register Pair DE with 3D00H, the start of line 4 of the screen.
3221
INC HL 23
INCrement Register Pair HL past the 00H to 32A5H, the label Failing Rows:.
3222
GOSUB to 345EH to put Failing Rows: at Register Pair DE (3D00H); 3248H puts it there a second time.
3225
PUSH IX DD E5
Save Index Register IX (3C30H, the result block) to the stack.
3227
POP BC C1
Restore it into Register Pair BC: Register Pair BC = 3C30H, which the code walks through the block.
3228
LD HL,3C8CH 21 8C 3C
Load Register Pair HL with 3C8CH, the column after Intr Errors= on line 2.
322B
LD A,(BC) 0A
Fetch the byte at Register Pair BC (3C30H, the number of wrong reads) into Register A.
322C
INC BC 03
INCrement Register Pair BC to 3C31H, the number of errors that were wrong again.
322D
GOSUB to 330CH to show Register A as two hexadecimal digits at Register Pair HL (3C8CH-3C8DH).
3230
LD HL,3C9CH 21 9C 3C
Load Register Pair HL with 3C9CH, the column after Hard Errors= on line 2.
3233
LD A,(BC) 0A
Fetch the byte at Register Pair BC (3C31H, the errors that were wrong when read again) into Register A.
3234
INC BC 03
INCrement Register Pair BC to 3C32H, the high byte of the address of the last error.
3235
GOSUB to 330CH to show Register A as two hexadecimal digits at Register Pair HL (3C9CH-3C9DH).
3238
LD HL,3CADH 21 AD 3C
Load Register Pair HL with 3CADH, where the address of the last error is shown (columns 45-48 of line 2, one blank column after Last Error @).
323B
LD A,(BC) 0A
Fetch the byte at Register Pair BC (3C32H, the high byte of the address) into Register A.
323C
INC BC 03
INCrement Register Pair BC to 3C33H, the low byte of the address.
323D
GOSUB to 330CH to show Register A (the high byte) as two hexadecimal digits at Register Pair HL (3CADH-3CAEH).
3240
LD A,(BC) 0A
Fetch the byte at Register Pair BC (3C33H, the low byte of the address) into Register A.
3241
INC BC 03
INCrement Register Pair BC to 3C34H, the data bits that were ever wrong.
3242
GOSUB to 330CH to show Register A (the low byte) as two hexadecimal digits at Register Pair HL (3CAFH-3CB0H).
3245
LD HL,32A5H 21 A5 32
Load Register Pair HL with 32A5H, the label Failing Rows:.
3248
LD DE,3D00H 11 00 3D
Load Register Pair DE with 3D00H, the start of line 4 of the screen.
324B
GOSUB to 345EH to put Failing Rows: at Register Pair DE (3D00H-3D0CH); Register Pair DE ends at 3D0DH.
324E
LD A,(BC) 0A
Fetch the byte at Register Pair BC (3C34H) into Register A: a 1 for each data bit (bits 7-0) that read wrong at least once. Each bit is one RAM chip of the bank, the row the label names.
324F
LD B,08H 06 08
Load Register B with 08H, the eight data bits, tested from bit 7 down to bit 0.
3251
RLCA 07
Rotate Register A left (RLCA): the next data bit, from bit 7 down, goes into the CARRY FLAG.
3252
If the NC FLAG is set (this bit never read wrong), JUMP to 325CH to go to the next bit.
3254
EX AF,AF' 08
Exchange Register Pair AF with the alternate Register Pair AF': the rotated mask is kept in AF' while Register A builds the digit.
3255
LD A,B 78
Copy Register B (08H for bit 7 down to 01H for bit 0) into Register A.
3256
ADD A,2FH C6 2F
ADD 2FH to Register A: Register B = 08H gives 37H (the digit 7) and 01H gives 30H (the digit 0), the number of the failing bit.
3258
LD (DE),A 12
Store Register A (the digit of the failing bit) at Register Pair DE, on line 4 after Failing Rows:.
3259
EX AF,AF' 08
Exchange Register Pair AF with the alternate Register Pair AF' again: Register A is the rotated mask once more.
325A
INC DE 13
INCrement Register Pair DE to the next column.
325B
INC DE 13
INCrement Register Pair DE once more, leaving a blank column between the digits.
325C
DECrement Register B (the bits left) and LOOP BACK to 3251H while it is not zero.
325E
JUMP to 344FH (DI / HALT): the CPU stops with the counts on the screen until the machine is reset.
3261H - Memory Test Text
The text strings of the memory test, each ending with 00H for 345EH.
3261-3277
DEFM "64K Memory Test Pass=",00H 36 34 4B 20 4D 65 6D 6F 72 79 20 54 65 73 74 20 20 50 61 73 73 3D 00
The title of the memory test, 22 characters and 00H: 31CFH puts it at the top left of the screen, and the pass number is shown after Pass= at 3C16H.
3278-32A4
DEFM "Intr Errors= Hard Errors= Last Error @",00H 49 6E 74 72 20 45 72 72 6F 72 73 3D 20 20 20 20 48 61 72 64 20 45 72 72 6F 72 73 3D 20 20 20 20 4C 61 73 74 20 45 72 72 6F 72 20 40 00
The labels of line 2 of the error report, 44 characters and 00H: 3218H puts them at 3C80H-3CABH, and the values are written at 3C8CH, 3C9CH and 3CADH.
32A5-32B2
DEFM "Failing Rows:",00H 46 61 69 6C 69 6E 67 20 52 6F 77 73 3A 00
The label of line 4 of the error report, 13 characters and 00H, put at 3D00H by 3222H and again by 324BH, followed by the numbers of the failing data bits.
32B3H - Test 32K of RAM
The routine 31FEH copies to 8100H-8158H (89 bytes). The copy is entered at 8100H, the first two instructions, which switch the ROMs out (port 84H = 02H); the ROM itself enters it at 32B7H for the upper 32K. On entry Register Pair HL is the first byte of the 32K and Index Register IX the result block. For each of 255 rounds (Register B = FFH down to 01H) every byte of the 32K is written with a value that starts at the round number and goes up by one per byte, then the whole 32K is read back and compared. A wrong byte is recorded at 32EDH and the reading goes on. At the end port 84H is set back to 00H. All jumps in it are relative, so the copy runs at 8100H as it is: 32B7H is 8104H there, 32D6H is 8123H and 32EDH is 813AH.
32B3
LD A,02H 3E 02
Load Register A with 02H, the value for port 84H: bits 1-0 = 10, memory map 2. Run only in the copy, at 8100H; the ROM calls 32B7H.
32B5
OUT (84H),A D3 84
Write Register A (02H) to port 84H (in the copy, at 8102H): memory map 2, RAM from 0000H to F3FFH, the keyboard at F400H and video RAM at F800H-FFFFH, so 0000H-7FFFH can be tested and the result block is at FC30H.
32B7
PUSH IX DD E5
Save Index Register IX (the result block, 3C30H or FC30H) to the stack.
32B9
POP BC C1
Restore it into Register Pair BC: Register Pair BC = the first byte of the result block, for the clear.
32BA
LD D,05H 16 05
Load Register D with 05H, the five bytes of the result block, Index Register IX+00H to +04H.
32BC
XOR A AF
Set Register A to 00H (XOR A), the value the result block is cleared to.
32BD
LD (BC),A 02
Store Register A (00H) at Register Pair BC, the next byte of the result block.
32BE
INC BC 03
INCrement Register Pair BC to the next byte of the result block.
32BF
DEC D 15
DECrement Register D, the bytes of the result block left to clear.
32C0
If the NZ FLAG is set (bytes are left), JUMP back to 32BDH to clear the next one.
32C2
LD B,FFH 06 FF
Load Register B with FFH (255), the number of rounds; Register B also gives each round its first value.
32C4
PUSH BC C5
Save Register Pair BC (Register B = the rounds left, also the first value of this round) to the stack.
32C5
PUSH HL E5
Save Register Pair HL (the first byte of the 32K) to the stack.
32C6
LD D,B 50
Copy Register B (the round number) into Register D, the value written to the first byte; it goes up by one for each byte.
32C7
LD BC,8000H 01 00 80
Load Register Pair BC with 8000H (32768), the number of bytes written.
32CA
PUSH BC C5
Save Register Pair BC (8000H) to the stack, the count for the reading back.
32CB
LD (HL),D 72
Store Register D (the value of this byte) at Register Pair HL.
32CC
INC D 14
INCrement Register D, the value for the next byte (after FFH it goes to 00H).
32CD
INC HL 23
INCrement Register Pair HL to the next byte of the 32K.
32CE
DEC BC 0B
DECrement Register Pair BC, the bytes left to write.
32CF
LD A,B 78
Copy Register B (the high byte of the count) into Register A.
32D0
OR C B1
OR Register C (the low byte of the count) into Register A: the Z FLAG is set when Register Pair BC is 0000H.
32D1
If the NZ FLAG is set (bytes are left), JUMP back to 32CBH to write the next byte.
32D3
POP BC C1
Restore Register Pair BC from the stack: 8000H, the number of bytes to read back.
32D4
POP HL E1
Restore Register Pair HL from the stack: the first byte of the 32K. Register D has gone up 8000H times and is back at the round's first value.
32D5
PUSH HL E5
Save Register Pair HL (the first byte of the 32K) to the stack again, for the next round.
32D6
LD A,(HL) 7E
Fetch the byte at Register Pair HL into Register A.
32D7
CP D BA
Compare Register A (the byte read) against Register D (the value written there).
32D8
If the NZ FLAG is set (the byte is wrong), JUMP to 32EDH to record the error; it comes back to 32DAH.
32DA
DEC BC 0B
DECrement Register Pair BC, the bytes left to read.
32DB
INC HL 23
INCrement Register Pair HL to the next byte of the 32K.
32DC
INC D 14
INCrement Register D, the value written to the next byte.
32DD
LD A,B 78
Copy Register B (the high byte of the count) into Register A.
32DE
OR C B1
OR Register C (the low byte of the count) into Register A: the Z FLAG is set when Register Pair BC is 0000H.
32DF
If the NZ FLAG is set (bytes are left), JUMP back to 32D6H to read the next byte.
32E1
POP HL E1
Restore Register Pair HL from the stack: the first byte of the 32K.
32E2
POP BC C1
Restore Register Pair BC from the stack: Register B = the round number.
32E3
DECrement Register B and LOOP BACK to 32C4H for the next round while it is not zero (255 rounds, first values FFH down to 01H).
32E5
JUMP to 32E9H to set port 84H back and return.
32E7
POP HL E1
Restore Register Pair HL from the stack (the first byte of the 32K): the way out from 32F8H when 255 errors have been counted.
32E8
POP BC C1
Restore Register Pair BC from the stack (the round number), so the stack holds the return address again.
32E9
XOR A AF
Set Register A to 00H (XOR A), the value for port 84H.
32EA
OUT (84H),A D3 84
Write Register A (00H) to port 84H: memory map 0 again, with the ROMs at 0000H-37FFH, the keyboard at 3800H and video RAM at 3C00H; 64 x 16 display, page 0.
32EC
RET C9
RETURN to the caller: 31EBH from the ROM, 3208H from the copy, through the address the CALL at 3205H left at FFFCH in main RAM.
32EDH - Record a Wrong Byte
Register A is the byte read, Register D the value written, Register Pair HL its address and Index Register IX the result block. The bits that differ are added to +04H, the wrong reads are counted in +00H (the test stops when that would pass FFH), the byte is read again and counted in +01H if it is still wrong, and its address is stored in +02H-+03H.
32ED
XOR D AA
XOR Register D (the value written) into Register A (the value read): a 1 for each data bit that is wrong.
32EE
OR (IX+04H) DD B6 04
OR the bits wrong so far, at Index Register IX+04H, into Register A.
32F1
LD (IX+04H),A DD 77 04
Store Register A at Index Register IX+04H: every data bit that has read wrong at least once.
32F4
LD A,(IX+00H) DD 7E 00
Fetch the number of wrong reads, at Index Register IX+00H, into Register A.
32F7
INC A 3C
INCrement Register A: the Z FLAG is set when the count was already FFH.
32F8
If the Z FLAG is set (255 wrong reads counted), JUMP to 32E7H to end the test; the count stays at FFH.
32FA
LD (IX+00H),A DD 77 00
Store Register A (the count plus one) at Index Register IX+00H.
32FD
LD A,(HL) 7E
Fetch the byte at Register Pair HL into Register A again, to see whether it is still wrong.
32FE
CP D BA
Compare Register A (the byte read the second time) against Register D (the value written).
32FF
If the Z FLAG is set (it reads right this time), JUMP to 3304H; it counts only as a wrong read.
3301
INC (IX+01H) DD 34 01
INCrement the byte at Index Register IX+01H, the number of bytes that read wrong the second time too.
3304
LD (IX+03H),L DD 75 03
Store Register L (the low byte of the address) at Index Register IX+03H.
3307
LD (IX+02H),H DD 74 02
Store Register H (the high byte of the address) at Index Register IX+02H: +02H-+03H hold the address of the last error, high byte first.
330A
JUMP to 32DAH to go on reading the rest of the 32K (8127H in the copy).
330CH - Show a Byte as Two Hexadecimal Digits
Writes Register A as two hexadecimal digits (0-9, A-F) at Register Pair HL and HL + 1, high digit first, and returns with Register Pair HL past them. Register D is used to keep the byte. Used by the memory test (31DEH, 322DH-3242H) and the disk test (3375H, 337BH).
330C
LD D,A 57
Copy Register A (the byte to show) into Register D, to keep it for the low digit.
330D
GOSUB to 3313H to turn the high four bits of Register A into a digit and store it at Register Pair HL.
3310
LD A,D 7A
Copy Register D (the byte to show) into Register A again, for the low digit.
3311
JUMP to 3317H to turn the low four bits into a digit, store it and return to the caller.
3313
RRA 1F
Rotate Register A right through the CARRY FLAG (RRA), the first of four that bring the high four bits down to bits 3-0.
3314
RRA 1F
Rotate Register A right through the CARRY FLAG (RRA), the second of four.
3315
RRA 1F
Rotate Register A right through the CARRY FLAG (RRA), the third of four.
3316
RRA 1F
Rotate Register A right through the CARRY FLAG (RRA), the fourth: the high four bits are now bits 3-0 (the bits above them are cleared at 3317H).
3317
AND 0FH E6 0F
AND Register A with 0FH, keeping the four bits of one digit (00H-0FH).
3319
ADD A,90H C6 90
ADD 90H to Register A, the first step of the conversion to a character: 90H-99H for 0-9, 9AH-9FH for 0AH-0FH.
331B
DAA 27
Decimal adjust Register A (DAA): 0-9 give 90H-99H with the CARRY FLAG clear, 0AH-0FH give 00H-05H with the CARRY FLAG set.
331C
ADC A,40H CE 40
ADD 40H and the CARRY FLAG to Register A (ADC): 0-9 give D0H-D9H, 0AH-0FH give 41H-46H.
331E
DAA 27
Decimal adjust Register A (DAA): D0H-D9H become 30H-39H (the characters 0-9), 41H-46H stay (the letters A-F).
331F
LD (HL),A 77
Store Register A (the character of the digit) at Register Pair HL.
3320
INC HL 23
INCrement Register Pair HL to the next column of the screen.
3321
RET C9
RETURN: to 3310H after the high digit, to the caller of 330CH after the low digit.
3322H - Disk Test (D): Choose the Drive
Selected with D; 3082H has cleared the screen and Register Pair DE is 0000H. The labels Cylinder Sector Drive: go on the top line and the test waits for one of the keys 0-3, the drive to test. The drive is restored to track 0 (3453H); if that fails the error is shown and the CPU halts (3439H).
3322
LD HL,352DH 21 2D 35
Load Register Pair HL with 352DH, the labels Cylinder Sector Drive: (24 characters, then 00H at 3545H).
3325
GOSUB to 345EH to put the labels at Register Pair DE (0000H, so at 3C00H-3C17H); Register Pair DE ends at 3C18H, after Drive:.
3328
LD A,(3810H) 3A 10 38
Fetch keyboard row 3810H (keys 0 1 2 3 4 5 6 7, bits 0-7) into Register A.
332B
AND 0FH E6 0F
AND Register A with 0FH, keeping the keys 0-3: the Z FLAG is set when none of them is down.
332D
If the Z FLAG is set (no drive key is down), JUMP back to 3328H and read the row again.
332F
LD B,A 47
Copy Register A (the bits of the keys 0-3 that are down) into Register B.
3330
XOR A AF
Set Register A to 00H (XOR A), the drive number counted up; the XOR also clears the CARRY FLAG for the RR at 3331H.
3331
RR B CB 18
Rotate Register B right through the CARRY FLAG (RR B): the bit of the lowest key not yet looked at goes into the CARRY FLAG.
3333
If the CARRY FLAG is set (this key is down), JUMP to 3338H with its number in Register A; when several are down the lowest is taken.
3335
INC A 3C
INCrement Register A to the number of the next key.
3336
JUMP back to 3331H to look at the next key bit.
3338
LD (42FCH),A 32 FC 42
Store Register A (the drive number, 00H-03H) at 42FCH, the drive number cell that 3550H reads to select the drive.
333B
ADD A,30H C6 30
ADD 30H to Register A, the character 0-3 of the drive number.
333D
LD (DE),A 12
Store Register A (the character of the drive number) at Register Pair DE (3C18H), after Drive: on the top line.
333E
GOSUB to 3453H to select the drive and restore it to track 0; Register A returns the error code, with the Z FLAG set for none.
3341
If the NZ FLAG is set (the restore failed), JUMP to 3439H to clear the screen, show the message for the error code in Register A and halt.
3344H - Disk Test: Step the Head Across the Disk
Reads one sector at each track: tracks 0 up to 39, then 39 down to 1, then pairs that close in from the two ends (0 and 39, 1 and 38, up to 38 and 1), then starts again, until RESET. Register B is the track and Register C the sector, which goes up by one on every read (00H-11H, 18 sectors) whatever the track. Index Register IY is the screen line that shows the track and sector being read; it moves down a line only after an error, so the lines above it keep the errors found.
3344
LD IY,3C40H FD 21 40 3C
Load Index Register IY with 3C40H, line 1 of the screen, under the labels: the line for the track and sector being read.
3348
LD C,00H 0E 00
Load Register C with 00H, the first sector to read.
334A
LD B,00H 06 00
Load Register B with 00H, track 0, the first track of the pass that steps up across the disk.
334C
GOSUB to 3371H to read sector Register C of track Register B and show it; it adds one to Register C.
334F
INC B 04
INCrement Register B to the next track, one step further in from the outside of the disk.
3350
LD A,B 78
Copy Register B (the track just read) into Register A, to compare it with the end of the pass.
3351
CP 28H FE 28
Compare Register A against 28H (40), one past the last track tested, 39.
3353
If the NZ FLAG is set (Register B is still below 40), JUMP back to 334CH to read on the next track.
3355
DEC B 05
DECrement Register B to 27H (39), the last track, to step back down.
3356
GOSUB to 3371H to read sector Register C of track Register B (39 down to 1) and show it.
3359
DEC B 05
DECrement Register B to the track below, one step back toward track 0.
335A
If the NZ FLAG is set (Register B has not reached track 0), JUMP back to 3356H.
335C
LD HL,0027H 21 27 00
Load Register Pair HL with 0027H: Register H = 00H (the low track of the first pair) and Register L = 27H (39, its high track).
335F
LD B,H 44
Copy Register H (the low track of this pair) into Register B.
3360
PUSH HL E5
Save Register Pair HL (the pair of tracks) to the stack across the read.
3361
GOSUB to 3371H to read sector Register C of the low track Register B and show it.
3364
POP HL E1
Restore Register Pair HL (the pair of tracks) from the stack.
3365
LD B,L 45
Copy Register L (the high track of this pair) into Register B.
3366
PUSH HL E5
Save Register Pair HL (the pair of tracks) to the stack across the read.
3367
GOSUB to 3371H to read sector Register C of the high track Register B and show it: the head makes a long step each time.
336A
POP HL E1
Restore Register Pair HL (the pair of tracks) from the stack.
336B
INC H 24
INCrement Register H, the low track of the next pair.
336C
DEC L 2D
DECrement Register L, the high track of the next pair: the Z FLAG is set when it reaches 00H.
336D
If the NZ FLAG is set (Register L has not reached 0), JUMP back to 335FH for the next pair; the last pair is 38 and 1.
336F
JUMP to 334AH to start again at track 0; Register C goes on from the sector it has reached.
3371H - Disk Test: Read One Sector and Show It
Shows the track (Register B) in columns 0-1 and the sector (Register C) in columns 10-11 of the line at Index Register IY, under Cylinder and Sector, then reads that sector into 4300H. After an error the message for its code goes in column 16 of the line, the drive is restored to track 0 and the line moves down one, or, on line 14 (3F80H), the lines above are moved up one instead. Register C then goes to the next sector (00H after 11H). Register B is kept.
3371
PUSH IY FD E5
Save Index Register IY (the line for this read) to the stack.
3373
POP HL E1
Restore it into Register Pair HL: Register Pair HL = the first column of the line.
3374
LD A,B 78
Copy Register B (the track of this read) into Register A, the byte 330CH shows.
3375
GOSUB to 330CH to show Register A (the track) as two hexadecimal digits at Register Pair HL (columns 0-1 of the line); Register Pair HL ends at column 2.
3378
LD A,C 79
Copy Register C (the sector) into Register A.
3379
SET 3,L CB DD
Set bit 3 of Register L: the line starts at a multiple of 40H, so Register Pair HL goes from column 2 to column 10, under Sector.
337B
GOSUB to 330CH to show Register A (the sector) as two hexadecimal digits at Register Pair HL (columns 10-11 of the line).
337E
PUSH BC C5
Save Register Pair BC (Register B the track, Register C the sector) to the stack across the read.
337F
LD E,B 58
Copy Register B (the track) into Register E, the track the read routine seeks to.
3380
GOSUB to 3765H to read sector Register C of track Register E of the drive at 42FCH into the buffer at 4300H; Register A returns the error code, with the Z FLAG set for none.
3383
If the Z FLAG is set (the sector was read without error), JUMP to 33C6H to go to the next sector.
3385
LD HL,346AH 21 6A 34
Load Register Pair HL with 346AH, the table of the addresses of the error messages, two bytes for each error code.
3388
ADD A,A 87
ADD Register A (the error code, 00H-0BH) to itself: the offset of its entry in the table.
3389
LD D,00H 16 00
Load Register D with 00H, the high byte of the offset.
338B
LD E,A 5F
Copy Register A (the offset) into Register E: Register Pair DE = the offset of the entry.
338C
ADD HL,DE 19
ADD Register Pair DE (the offset) to Register Pair HL (346AH): Register Pair HL = the entry for the error code.
338D
LD A,(HL) 7E
Fetch the low byte of the message address at Register Pair HL into Register A.
338E
INC HL 23
INCrement Register Pair HL to the high byte of the entry.
338F
LD H,(HL) 66
Fetch the high byte of the message address at Register Pair HL into Register H.
3390
LD L,A 6F
Copy Register A (the low byte) into Register L: Register Pair HL = the address of the message.
3391
EX DE,HL EB
Exchange Register Pair DE with Register Pair HL: Register Pair DE = the address of the message.
3392
LD HL,0010H 21 10 00
Load Register Pair HL with 0010H, the column of the line where the message goes (16).
3395
PUSH IY FD E5
Save Index Register IY (the line of this read) to the stack.
3397
POP BC C1
Restore it into Register Pair BC: Register Pair BC = the first column of the line (the track and sector are on the stack).
3398
ADD HL,BC 09
ADD Register Pair BC (the line) to Register Pair HL (0010H): Register Pair HL = column 16 of the line.
3399
EX DE,HL EB
Exchange Register Pair DE with Register Pair HL: Register Pair HL = the address of the message, Register Pair DE = column 16 of the line.
339A
XOR A AF
Set Register A to 00H (XOR A); 345EH loads Register A from Register D before it uses it.
339B
GOSUB to 345EH to put the message at Register Pair HL on the screen at Register Pair DE (column 16 of the line).
339E
GOSUB to 3453H to restore the drive to track 0 after the error; the error code it returns is not looked at.
33A1
XOR A AF
Set Register A to 00H (XOR A), clearing the CARRY FLAG for the SBC at 33A8H.
33A2
LD HL,3F80H 21 80 3F
Load Register Pair HL with 3F80H, line 14 of the screen, the lowest line the status line is moved to.
33A5
PUSH IY FD E5
Save Index Register IY (the line of this read) to the stack.
33A7
POP DE D1
Restore it into Register Pair DE: Register Pair DE = the line of this read.
33A8
SBC HL,DE ED 52
Subtract Register Pair DE (the line) from Register Pair HL (3F80H) with the CARRY FLAG (clear): the Z FLAG is set when the line is line 14.
33AA
If the Z FLAG is set (the line is line 14), JUMP to 33B3H to move the lines up instead of moving down.
33AC
LD DE,0040H 11 40 00
Load Register Pair DE with 0040H (64), the length of a line of the screen.
33AF
ADD IY,DE FD 19
ADD Register Pair DE (0040H) to Index Register IY: the next read is shown on the line below, leaving the error on this one.
33B1
JUMP to 33C6H to go to the next sector, leaving the error on the line above.
33B3
LD HL,3C80H 21 80 3C
Load Register Pair HL with 3C80H, the start of line 2 of the screen, the first byte moved up.
33B6
LD DE,3C40H 11 40 3C
Load Register Pair DE with 3C40H, the start of line 1, where line 2 moves to.
33B9
LD BC,0341H 01 41 03
Load Register Pair BC with 0341H (833), the bytes 3C80H-3FC0H that are moved.
33BC
LDIR ED B0
Copy the 833 bytes at Register Pair HL (3C80H-3FC0H) to Register Pair DE (3C40H-3F80H), counting Register Pair BC down to 0000H: lines 2-14 move up to lines 1-13 and the first byte of line 15 goes to the start of line 14. Register Pair DE ends at 3F81H.
33BE
LD A,20H 3E 20
Load Register A with 20H, the space the code fills with.
33C0
LD C,3FH 0E 3F
Load Register C with 3FH (63): with Register B = 00H after the LDIR, Register Pair BC = 003FH, the bytes 33E2H copies after the first.
33C2
EX DE,HL EB
Exchange Register Pair DE with Register Pair HL: Register Pair HL = 3F81H, the first byte filled.
33C3
GOSUB to 33E2H to fill the 64 bytes 3F81H-3FC0H with the space in Register A: line 14 is blank but for its first byte, the first byte of line 15 (3FC0H) is blanked too, and IY stays on line 14 for the next read.
33C6
POP BC C1
Restore Register Pair BC from the stack: Register B the track, Register C the sector just read.
33C7
INC C 0C
INCrement Register C to the next sector, the one the next read of the test uses.
33C8
LD A,C 79
Copy Register C (the next sector) into Register A.
33C9
SUB 12H D6 12
SUBtract 12H (18), the number of sectors on a track, from Register A: the Z FLAG is set when Register C has gone past sector 11H (17).
33CB
RET NZ C0
If the NZ FLAG is set (Register C is a sector of the track), RETURN to the caller.
33CC
LD C,A 4F
Copy Register A (00H) into Register C: the next read is sector 0.
33CD
RET C9
RETURN to the caller with Register C = 00H, so the next read is sector 0 again.
33CEH - Fill Both Video Pages
Video RAM has two pages of 1024 bytes; port 84H bit 7 chooses the one the CPU sees at 3C00H-3FFFH. 33CEH fills both with spaces (the floppy boot 3426H, its error 343AH, the RS-232 boot 365EH and its error 36D5H); 33D0H fills both with the character in Register A (the video test, 318AH). Page 1 is filled first, then page 0, and port 84H is left at 00H: memory map 0, 64 x 16, page 0. 33E2H is the fill loop itself, also used by the disk test (33C3H). Uses Register Pairs AF', BC, DE and HL.
33CE
LD A,20H 3E 20
Load Register A with 20H, the space, the character both pages are filled with.
33D0
EX AF,AF' 08
Exchange Register Pair AF with the alternate Register Pair AF': the fill character is kept in AF' while Register A holds the values for port 84H.
33D1
LD A,80H 3E 80
Load Register A with 80H, the value for port 84H: bit 7 set (video page 1), memory map 0, 64 x 16.
33D3
GOSUB to 33D9H to select video page 1 with port 84H = 80H and fill it with the character in AF'.
33D6
EX AF,AF' 08
Exchange Register Pair AF with the alternate Register Pair AF': the fill character goes back to AF'.
33D7
LD A,00H 3E 00
Load Register A with 00H, the value for port 84H: video page 0, memory map 0, 64 x 16.
33D9
OUT (84H),A D3 84
Write Register A to port 84H: 80H selects video page 1 at 3C00H-3FFFH, 00H page 0.
33DB
EX AF,AF' 08
Exchange Register Pair AF with the alternate Register Pair AF': Register A is the fill character again.
33DC
LD HL,3C00H 21 00 3C
Load Register Pair HL with 3C00H, the first byte of the video page.
33DF
LD BC,03FFH 01 FF 03
Load Register Pair BC with 03FFH (1023), the bytes after the first one, up to 3FFFH.
33E2
LD (HL),A 77
Store Register A (the fill character) at Register Pair HL, the first byte of the area.
33E3
LD D,H 54
Copy Register H into Register D, the high byte of the first byte of the area.
33E4
LD E,L 5D
Copy Register L into Register E: Register Pair DE = Register Pair HL.
33E5
INC DE 13
INCrement Register Pair DE to the byte after Register Pair HL.
33E6
LDIR ED B0
Copy the byte at Register Pair HL to Register Pair DE and on upward, counting Register Pair BC down to 0000H: each byte copied is the one stored the step before, so the whole area gets the fill character.
33E8
RET C9
RETURN to the caller: to 33D6H after page 1, to the caller of 33CEH or 33D0H after page 0.
33E9H - Write the CRT Controller Registers R9 to R0
33E9H writes the 64 x 16 values 33F8H-3401H; 33ECH writes the ten bytes that end at Register Pair HL (the video test, 3197H, with HL = 31C0H for 80 x 24). The byte at Register Pair HL goes to R9, the one below it to R8, down to R0. Register B is changed by the OUTD.
33E9
LD HL,3401H 21 01 34
Load Register Pair HL with 3401H, the value for R9 in the 64 x 16 table 33F8H-3407H.
33EC
LD A,09H 3E 09
Load Register A with 09H, the number of register R9, the first written.
33EE
LD C,89H 0E 89
Load Register C with 89H, the CRT controller data port, the port the OUTD at 33F2H writes to.
33F0
OUT (88H),A D3 88
Write Register A (the register number) to port 88H, the CRT controller address port, selecting the register.
33F2
OUTD ED AB
OUTD: write the byte at Register Pair HL to the port in Register C (89H), then DECrement Register Pair HL to the value of the next lower register and DECrement Register B.
33F4
DEC A 3D
DECrement Register A to the next lower register number; after R0 it goes from 00H to FFH and the SIGN FLAG is set.
33F5
RET M F8
If the M FLAG is set (Register A is FFH, R0 has been written), RETURN to the caller.
33F6
JUMP back to 33F0H to write the next lower register.
33F8H - CRT Controller Values for 64 x 16
The values for registers R0-R15 of the CRT controller: 64 characters a line and 16 lines of 12 scan lines. The cold start writes all 16 (3024H-3030H, from 3407H down); 33E9H writes R0-R9 again after the video test's 80 x 24 step. Data, not code.
33F8
DEFB 4FH 4F
R0, horizontal total: 4FH (79), so a scan line takes 80 character times.
33F9
DEFB 40H 40
R1, horizontal displayed: 40H (64) characters on each line.
33FA
DEFB 44H 44
R2, horizontal sync position: 44H (68), the character time where the horizontal sync starts.
33FB
DEFB 08H 08
R3, sync width: 08H, eight character times of horizontal sync.
33FC
DEFB 15H 15
R4, vertical total: 15H (21), so a frame takes 22 character rows.
33FD
DEFB 00H 00
R5, vertical total adjust: 00H, no scan lines added to the frame.
33FE
DEFB 10H 10
R6, vertical displayed: 10H (16) character rows on the screen.
33FF
DEFB 12H 12
R7, vertical sync position: 12H (18), the character row where the vertical sync starts.
3400
DEFB 00H 00
R8, interlace mode: 00H, a normal display that is not interlaced.
3401
DEFB 0BH 0B
R9, maximum scan line address: 0BH (11), so each character row has twelve scan lines (0-11).
3402
DEFB 00H 00
R10, cursor start: 00H, scan line 0, written only by the cold start.
3403
DEFB 00H 00
R11, cursor end: 00H, scan line 0, written only by the cold start.
3404
DEFB 00H 00
R12, the high byte of the display start address: 00H, written only by the cold start.
3405
DEFB 00H 00
R13, the low byte of the display start address: 00H, so the display starts at the first byte of video RAM.
3406
DEFB 00H 00
R14, the high byte of the cursor address: 00H, written only by the cold start.
3407
DEFB 00H 00
R15, the low byte of the cursor address: 00H, the first value the cold start writes (Register Pair HL = 3407H at 3026H).
3408H - Printer Test (P)
Selected with P; the menu stays on the screen. Prints the characters 20H to 7FH and a carriage return, over and over, until RESET. Each character waits until the printer status port reports the printer ready.
3408
LD A,20H 3E 20
Load Register A with 20H, the space, the first character of the line printed.
340A
GOSUB to 3419H to wait for the printer and send it the character in Register A.
340D
INC A 3C
INCrement Register A to the next character code.
340E
CP 80H FE 80
Compare Register A against 80H, one past the last character printed, 7FH.
3410
If the CARRY FLAG is set (Register A is below 80H), JUMP back to 340AH to print it.
3412
LD A,0DH 3E 0D
Load Register A with 0DH, the carriage return that ends the printed line.
3414
GOSUB to 3419H to wait for the printer and send it the carriage return in Register A.
3417
JUMP back to 3408H to print the next line, starting again at the space.
3419H - Send a Character to the Printer
Waits until the printer status read from port F8H, bits 7-4, is 0011: not busy (bit 7 = 0), paper (bit 6 = 0), selected (bit 5 = 1) and no fault (bit 4 = 1). Then writes the character in Register A to port FAH, one of the ports F8H-FBH the printer latch answers to. Register A and the flags are kept on the stack while the status is read.
3419
PUSH AF F5
Save Register Pair AF (Register A holds the character to print) to the stack while Register A is used for the status.
341A
IN A,(F8H) DB F8
Read the printer status from port F8H into Register A: bit 7 busy, bit 6 out of paper, bit 5 selected, bit 4 no fault.
341C
AND F0H E6 F0
AND Register A with F0H, keeping the four status bits 7-4.
341E
CP 30H FE 30
Compare Register A against 30H, the status of a ready printer: selected and no fault, not busy and not out of paper.
3420
If the NZ FLAG is set (the printer is not ready), JUMP back to 341AH to read the status again.
3422
POP AF F1
Restore Register Pair AF from the stack: Register A is the character to print.
3423
OUT (FAH),A D3 FA
Write Register A (the character) to port FAH, the printer data latch (ports F8H-FBH), which prints it.
3425
RET C9
RETURN to the caller, with Register A still holding the character just sent.
3426H - Boot from Floppy Disk Drive 0 (B)
Selected with B. Both video pages are cleared, drive 0 is restored to track 0 and sector 1 of track 0 is read into 4300H-43FFH in double density; if it is read without error the Diagnostic jumps to 4300H and leaves the program it has loaded to run. The drive number at 42FCH is the 00H stored at 3021H: the menu is reached only through a reset, and the disk test, the only code that changes 42FCH, never returns to it.
3426
GOSUB to 33CEH to fill both video pages with spaces; port 84H is left at 00H.
3429
GOSUB to 3453H to select the drive at 42FCH (drive 0) and restore it to track 0; Register A returns the error code, with the Z FLAG set for none.
342C
If the NZ FLAG is set (the restore failed), JUMP to 3439H to show the message for the error code in Register A and halt.
342E
LD C,01H 0E 01
Load Register C with 01H, the sector to read, sector 1.
3430
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H: Register E = 00H, the track to read, track 0 (Register D is not used by the read).
3433
GOSUB to 3767H to read sector Register C of track Register E into 4300H; Register A returns the error code, with the Z FLAG set for none.
3436
JP Z,4300H CA 00 43
If the Z FLAG is set (the sector was read without error), JUMP to 4300H, the first byte of the sector just read: the boot code runs from there and the Diagnostic is done.
3439H - Show a Disk Error and Halt
Reached from the disk test (3341H) and the floppy boot (342CH, and after a failed read at 3436H) with the error code in Register A (00H-0BH). Both video pages are cleared, the message for the code (table 346AH) goes to the top left of the screen and the CPU halts. 344FH (DI / HALT) is also the end of the memory test (325EH).
3439
PUSH AF F5
Save Register Pair AF (Register A holds the error code) to the stack while the screen is cleared.
343A
GOSUB to 33CEH to fill both video pages with spaces; port 84H is left at 00H.
343D
POP AF F1
Restore Register Pair AF from the stack: Register A is the error code again.
343E
ADD A,A 87
ADD Register A (the error code) to itself: the offset of its entry in the table at 346AH, two bytes for each code.
343F
LD HL,346AH 21 6A 34
Load Register Pair HL with 346AH, the table of the addresses of the error messages.
3442
LD D,00H 16 00
Load Register D with 00H, the high byte of the offset.
3444
LD E,A 5F
Copy Register A (the offset) into Register E: Register Pair DE = the offset of the entry.
3445
ADD HL,DE 19
ADD Register Pair DE (the offset) to Register Pair HL (346AH): Register Pair HL = the entry for the error code.
3446
LD A,(HL) 7E
Fetch the low byte of the message address at Register Pair HL into Register A.
3447
INC HL 23
INCrement Register Pair HL to the high byte of the entry.
3448
LD H,(HL) 66
Fetch the high byte of the message address at Register Pair HL into Register H.
3449
LD L,A 6F
Copy Register A (the low byte) into Register L: Register Pair HL = the address of the message.
344A
XOR A AF
Set Register A to 00H (XOR A), the value for Register E.
344B
LD E,A 5F
Copy Register A (00H) into Register E: Register Pair DE = 0000H (Register D is 00H from 3442H), the top left of the screen.
344C
GOSUB to 345EH to put the message at Register Pair HL on the screen at Register Pair DE (0000H, so at 3C00H).
344F
DI F3
Disable maskable interrupts (DI); they are off already, as the Diagnostic never enables them.
3450
HALT 76
HALT: the CPU stops with the message on the screen. When the read ended at 361CH (drive not ready) port E4H is still 80H and a later NMI from the controller would go to 3629H; otherwise no NMI is enabled and only a reset restarts the machine.
3451
JUMP back to 3450H to halt again, should the CPU ever leave the HALT.
3453H - Select the Drive and Restore It to Track 0
Selects the drive whose number is at 42FCH and restores it to track 0 (3546H with Register B = 04H). The error code comes back in Register A (00H with the Z FLAG set when there is none) and is also stored at 42FFH, which nothing reads. Register C is written to the controller's sector register on the way (354DH). Callers: the disk test (333EH, 339EH) and the floppy boot (3429H).
3453
LD A,01H 3E 01
Load Register A with 01H, the value 3546H starts with; it DECrements it and jumps to 354AH whatever the result.
3455
LD B,04H 06 04
Load Register B with 04H, the operation for 3546H: below 05H, so it restores the drive to track 0.
3457
GOSUB to 3546H to select the drive at 42FCH and restore it; Register A returns the error code, with the Z FLAG set for none.
345A
LD (42FFH),A 32 FF 42
Store Register A (the error code) at 42FFH; no instruction of the Diagnostic reads 42FFH.
345D
RET C9
RETURN to the caller with the error code in Register A and the Z FLAG set when it is 00H.
345EH - Put a Text on the Screen
Copies the text at Register Pair HL, up to the 00H that ends it, to the screen at Register Pair DE. Register D is ORed with 3CH first, so the callers can give the screen offset 0000H-03FFH (or the screen address itself). Returns with Register Pair HL at the 00H and Register Pair DE after the last character. Uses Register A.
345E
LD A,D 7A
Copy Register D (the high byte of the screen offset) into Register A.
345F
OR 3CH F6 3C
OR Register A with 3CH: offsets 00H-03H for the high byte become 3CH-3FH, the high bytes of video RAM 3C00H-3FFFH.
3461
LD D,A 57
Copy Register A into Register D: Register Pair DE is now the address in video RAM.
3462
LD A,(HL) 7E
Fetch the next character of the text at Register Pair HL into Register A.
3463
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the 00H that ends the text.
3464
RET Z C8
If the Z FLAG is set (the end of the text), RETURN to the caller with Register Pair HL at the 00H.
3465
LD (DE),A 12
Store Register A (the character) at Register Pair DE, on the screen.
3466
INC HL 23
INCrement Register Pair HL to the next character of the text.
3467
INC DE 13
INCrement Register Pair DE to the next column of the screen.
3468
JUMP back to 3462H to copy the next character.
346AH - Error Message Table and Disk Texts
Twelve two-byte addresses, low byte first, one for each error code 00H-0BH that the disk routine 3546H returns; 3385H and 343EH double the code to find the entry. The error texts and the other texts of the disk and RS-232 tests follow, each ending with 00H for 345EH. The texts Drive Not Available (3503H) and the RS-232 texts at 3482H and 3491H are not in the table.
346A-346B
DEFW 34A0H A0 34
Error code 00H, no error: never looked up, since 3385H and 343EH are reached only with the NZ FLAG set. The entry points at Drive Not Ready (34A0H).
346C-346D
DEFW 34A0H A0 34
Error code 01H, which the disk routine 3546H never returns. The entry points at Drive Not Ready (34A0H).
346E-346F
DEFW 34A0H A0 34
Error code 02H, which the disk routine 3546H never returns. The entry points at Drive Not Ready (34A0H).
3470-3471
DEFW 34A0H A0 34
Error code 03H: the status showed not ready (bit 7) at the end of a restore, a seek or a read (35DDH), or the drive went not ready during the restore after showing only the index and track 0 bits (3581H). The entry points at Drive Not Ready (34A0H).
3472-3473
DEFW 34A0H A0 34
Error code 04H, which the disk routine 3546H never returns. The entry points at Drive Not Ready (34A0H).
3474-3475
DEFW 34A0H A0 34
Error code 05H: the drive went not ready during the restore before it showed any of the status bits 7, 4, 3, 2 or 1 (357BH). The entry points at Drive Not Ready (34A0H).
3476-3477
DEFW 34F3H F3 34
Error code 06H: the drive went not ready during the restore after it showed status bits other than index and track 0 (3583H). The entry points at Drive Door Open (34F3H).
3478-3479
DEFW 34B0H B0 34
Error code 07H: the controller reported a CRC error (status bit 3) after a restore, a seek or a read (35D7H). The entry points at Data CRC Error (34B0H).
347A-347B
DEFW 34BFH BF 34
Error code 08H: the controller reported a seek error (status bit 4) after the restore or a seek (35C7H). The entry points at Track Seek Error (34BFH).
347C-347D
DEFW 34A0H A0 34
Error code 09H, which the disk routine 3546H never returns. The entry points at Drive Not Ready (34A0H).
347E-347F
DEFW 34D0H D0 34
Error code 0AH: the controller reported lost data (status bit 2) after a read (35CBH). The entry points at Lost Data Error (34D0H).
3480-3481
DEFW 34E0H E0 34
Error code 0BH: the controller reported record not found (status bit 4) after a read (35D1H). The entry points at ID Not Found Error (34E0H).
3482-3490
DEFM "Host Not Ready",00H 48 6F 73 74 20 4E 6F 74 20 52 65 61 64 79 00
Shown at the top left of the screen by the RS-232 boot (3665H) while it waits for the host computer to be ready; it is not sent over the RS-232 port.
3491-349F
DEFM "Host Is Ready ",00H 48 6F 73 74 20 49 73 20 52 65 61 64 79 20 00
Shown at the top left over Host Not Ready by the RS-232 boot (3677H) when port E8H bit 5 shows the host ready; the space at its end covers the last letter of the longer text. It is not sent over the RS-232 port.
34A0-34AF
DEFM "Drive Not Ready",00H 44 72 69 76 65 20 4E 6F 74 20 52 65 61 64 79 00
The message for the error codes 00H-05H and 09H (table entries 346AH-3475H and 347CH): the drive is not ready.
34B0-34BE
DEFM "Data CRC Error",00H 44 61 74 61 20 43 52 43 20 45 72 72 6F 72 00
The message for error code 07H (table entry 3478H): the controller reported a CRC error.
34BF-34CF
DEFM "Track Seek Error",00H 54 72 61 63 6B 20 53 65 65 6B 20 45 72 72 6F 72 00
The message for error code 08H (table entry 347AH): the controller reported a seek error.
34D0-34DF
DEFM "Lost Data Error",00H 4C 6F 73 74 20 44 61 74 61 20 45 72 72 6F 72 00
The message for error code 0AH (table entry 347EH): the controller reported lost data during a read.
34E0-34F2
DEFM "ID Not Found Error",00H 49 44 20 4E 6F 74 20 46 6F 75 6E 64 20 45 72 72 6F 72 00
The message for error code 0BH (table entry 3480H): the controller did not find the sector (record not found).
34F3-3502
DEFM "Drive Door Open",00H 44 72 69 76 65 20 44 6F 6F 72 20 4F 70 65 6E 00
The message for error code 06H (table entry 3476H): the drive went not ready during the restore after it had shown other status bits.
3503-3516
DEFM "Drive Not Available",00H 44 72 69 76 65 20 4E 6F 74 20 41 76 61 69 6C 61 62 6C 65 00
A text that no instruction of the Diagnostic points at and no table entry names: it is never shown.
3517-3521
DEFM "Loading...",00H 4C 6F 61 64 69 6E 67 2E 2E 2E 00
Shown on line 9 at column 4 (0244H) and sent to the host by the RS-232 boot (36C5H) when the FFH that starts the load has arrived.
3522-352C
DEFM "Load Error",00H 4C 6F 61 64 20 45 72 72 6F 72 00
Shown on line 15 at column 4 (03C4H) and sent to the host by the RS-232 boot (36DBH) when a byte arrives with an error; a letter for the error follows it on the screen.
352D-3545
DEFM "Cylinder Sector Drive:",00H 43 79 6C 69 6E 64 65 72 20 20 53 65 63 74 6F 72 20 20 44 72 69 76 65 3A 00
The labels the disk test puts on the top line (3322H): the track is shown under Cylinder (columns 0-1), the sector under Sector (columns 10-11) and the drive number after Drive: (column 24).
3546H - Floppy Disk Routine: Select the Drive
The one routine of the Diagnostic that drives the WD1793 floppy disk controller (ports F0H-F3H) and the drive select latch (port F4H). Called with Register B = the operation (04H, restore the drive to track 0, from 3453H; 0CH, read a sector, from 3765H and 3767H), Register C = the sector, Register E = the track (read) and Register Pair HL = the buffer (read). It returns the error code in Register A (00H-0BH, see the table at 346AH) with the Z FLAG set when it is 00H. The drive number comes from 42FCH and is always selected in double density.
3546
DEC A 3D
DECrement Register A (01H from 3453H and 3765H, 00H from the floppy boot through 3767H): the Z FLAG may be set or not, but both ways lead to 354AH.
3547
If the Z FLAG is set, JUMP to 354AH, the next instruction: the jump changes nothing.
354A
GOSUB to 363AH to stop any command of the controller (Force Interrupt D0H) and wait 256 DJNZ steps.
354D
LD A,C 79
Copy Register C (the sector) into Register A.
354E
OUT (F2H),A D3 F2
Write Register A (the sector) to port F2H, the controller's sector register; the read at 35EDH takes it from there.
3550
LD A,(42FCH) 3A FC 42
Fetch the drive number (00H-03H) from 42FCH into Register A.
3553
LD C,01H 0E 01
Load Register C with 01H, the select bit of drive 0, shifted left once for each drive number.
3555
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set when the drive number is 00H; the OR also clears the CARRY FLAG for the RL at 3558H.
3556
If the Z FLAG is set (Register A has counted down to 00H), JUMP to 355DH with the select bit in Register C.
3558
RL C CB 11
Rotate Register C left through the CARRY FLAG (clear): the select bit moves to the next drive.
355A
DEC A 3D
DECrement Register A, the drive number counted down.
355B
JUMP back to 3556H to see whether the select bit is in place.
355D
LD A,C 79
Copy Register C (the select bit of the drive: 01H, 02H, 04H or 08H) into Register A.
355E
OR 80H F6 80
OR Register A with 80H, bit 7 of the drive select latch: double density.
3560
LD (42FDH),A 32 FD 42
Store Register A (the drive select value) at 42FDH, for the sector read (35E7H).
3563
OUT (F4H),A D3 F4
Write Register A to port F4H, the drive select latch: the drive is selected in double density, side 0.
| Port F4H: Drive Select and Options | | Function Description |
| D | W | P | S | d3 | d2 | d1 | d0 | | D (bit 7): 1 = double density (MFM), 0 = single density (FM) W (bit 6): 1 = wait states while the controller has no data ready P (bit 5): 1 = write precompensation S (bit 4): 0 = side 0, 1 = side 1 d3-d0: one bit per drive, 1 = selected |
3565
LD A,B 78
Copy Register B (the operation, 04H or 0CH) into Register A.
3566
CP 05H FE 05
Compare Register A against 05H: the CARRY FLAG is set for operations below 05H, the restore.
3568
If the NC FLAG is set (operation 05H or more, the read), JUMP to 3588H.
356AH - Restore the Drive to Track 0
Operation 04H. The controller steps the head out to track 0 and checks the track number there. 364AH returns early when the status shows not ready while the controller is still busy. When that status is exactly 81H (bit 5 ignored) the status read just before it, in Register C, chooses the code: 05H, 03H or 06H. Every other status, including an early return with more bits set, is turned into a code from 35C7H.
356A
LD A,0CH 3E 0C
Load Register A with 0CH, the Restore command: head loaded at the start, the track checked at the end, 6 ms steps.
| 1793 FDC Command: 0CH (00001100) | | Function Description |
| 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | | Command=Restore (bits 7-4 = 0000) h = 1: head load at the start V = 1: verify the track ID r1 r0 = 00: 6 ms stepping rate |
356C
GOSUB to 364AH to issue the Restore and wait until the controller is no longer busy or reports not ready; Register A returns the last status and Register C the one before it (00H when there was none).
356F
LD B,A 47
Copy Register A (the last status) into Register B, for the tests from 35C7H.
3570
AND DFH E6 DF
AND Register A with DFH, clearing bit 5 (head loaded), which does not matter here.
3572
CP 81H FE 81
Compare Register A against 81H: the Z FLAG is set only when the status is not ready (bit 7) and busy (bit 0) with no other bit set but head loaded, one form of the early return of 364AH.
| 1793 Status Bits the Diagnostic Tests | | Function Description |
| N | W | H | F | C | L | D | B | | N: 1 = not ready W: 1 = write protected H: 1 = head loaded (restore, seek) F: 1 = seek error (restore, seek), record not found (read) C: 1 = CRC error L: 1 = track 0 (restore, seek), lost data (read) D: 1 = index (restore, seek), data request (read) B: 1 = busy |
3574
If the NZ FLAG is set (any other status: the restore ended, or the drive went not ready while busy with another bit also set, such as 85H), JUMP to 35C7H to turn the status bits in Register B into an error code.
3576
LD A,C 79
Copy Register C (the status read before the drive went not ready, 00H if it was not ready at the first read) into Register A.
3577
AND 9EH E6 9E
AND Register A with 9EH, keeping bits 7, 4, 3, 2 and 1: not ready, seek error, CRC error, track 0 and index.
3579
LD D,05H 16 05
Load Register D with 05H, the error code when none of those bits was set.
357B
If the Z FLAG is set (none was set), JUMP to 3585H to return error code 05H (Drive Not Ready).
357D
LD D,03H 16 03
Load Register D with 03H, the error code when only the index and track 0 bits were set.
357F
CP 06H FE 06
Compare Register A against 06H, bits 2 (track 0) and 1 (index) and no other.
3581
If the Z FLAG is set (only track 0 and index), JUMP to 3585H to return error code 03H (Drive Not Ready).
3583
LD D,06H 16 06
Load Register D with 06H, the error code for any other bits (Drive Door Open), which falls into 3585H.
3585H - Return the Error Code
All the error exits of the disk routine come here with the code in Register D.
3585
LD A,D 7A
Copy Register D (the error code) into Register A.
3586
OR A B7
OR Register A with itself to set the flags: the code is never 00H here, so the Z FLAG is clear.
3587
RET C9
RETURN to the caller with the error code in Register A and the NZ FLAG set.
3588H - Operations of 05H and More
The read (0CH) goes on to 35AFH. The code from 358CH to 35AEH, for operation 32H, is never run: no caller passes 32H. It goes through drives 0-3 (select bits 01H-08H, single density) and restores, without a head load or a check, each drive whose status shows the head loaded.
3588
CP 32H FE 32
Compare Register A (the operation) against 32H; the callers pass only 04H and 0CH, so the Z FLAG is never set here.
358A
If the NZ FLAG is set (always: the operation is 0CH), JUMP to 35AFH to seek and read the sector.
358C
LD B,04H 06 04
Load Register B with 04H, the four drives this unused part goes through (never run).
358E
LD D,01H 16 01
Load Register D with 01H, the select bit of drive 0 for the unused part (never run).
3590
GOSUB to 363AH to stop any command of the controller and wait 256 DJNZ steps (never run).
3593
LD A,D 7A
Copy Register D (the select bit of the drive) into Register A (never run).
3594
OUT (F4H),A D3 F4
Write Register A to port F4H, selecting the drive in single density, side 0 (never run).
3596
RLCA 07
Rotate Register A left (RLCA): the select bit of the next drive (never run).
3597
LD D,A 57
Copy Register A (the select bit of the next drive) into Register D (never run).
3598
IN A,(F0H) DB F0
Read the controller status from port F0H into Register A (never run).
359A
AND 20H E6 20
AND Register A with 20H, keeping bit 5, head loaded: the Z FLAG is set when the head is not loaded (never run).
359C
If the Z FLAG is set (the head is not loaded), JUMP to 35ACH for the next drive (never run).
359E
XOR A AF
Set Register A to 00H (XOR A), the Restore command with no head load, no check and 6 ms steps (never run).
359F
OUT (F0H),A D3 F0
Write Register A (00H, Restore) to port F0H, the controller's command register (never run).
35A1
GOSUB to 3643H to wait 19 DJNZ steps before the controller's status is read (never run).
35A4
IN A,(F0H) DB F0
Read the controller status from port F0H into Register A (never run).
35A6
XOR 01H EE 01
XOR Register A with 01H, turning bit 0 (busy) around: bit 0 is now 1 when the controller is no longer busy (never run).
35A8
AND 05H E6 05
AND Register A with 05H, keeping bit 0 (no longer busy) and bit 2 (track 0) (never run).
35AA
If the Z FLAG is set (still busy and not at track 0), JUMP back to 35A4H to read the status again (never run).
35AC
DECrement Register B (the drives left) and LOOP BACK to 3590H while it is not zero (never run).
35AE
RET C9
RETURN to the caller once the four drives have been looked at (never run).
35AFH - Seek to the Track
The read needs the head on the track in Register E. If the controller's track register already holds it nothing is done; otherwise a Seek (with the track checked) is issued, and a not ready, seek error or CRC error status ends the routine with its error code.
35AF
IN A,(F1H) DB F1
Read the controller's track register from port F1H into Register A: the track the head is on.
35B1
CP E BB
Compare Register A (the track the head is on) against Register E (the track to read).
35B2
If the Z FLAG is set (the head is on that track), JUMP to 35C1H.
35B4
LD A,E 7B
Copy Register E (the track to read) into Register A.
35B5
OUT (F3H),A D3 F3
Write Register A (the track to read) to port F3H, the controller's data register: the track the Seek goes to.
35B7
LD A,1CH 3E 1C
Load Register A with 1CH, the Seek command: head loaded at the start, the track checked at the end, 6 ms steps.
| 1793 FDC Command: 1CH (00011100) | | Function Description |
| 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | | Command=Seek (bits 7-4 = 0001) h = 1: head load at the start V = 1: verify the track ID r1 r0 = 00: 6 ms stepping rate |
35B9
GOSUB to 364AH to issue the Seek and wait until the controller is no longer busy or reports not ready; Register A returns the status.
35BC
LD D,A 57
Copy Register A (the status of the Seek) into Register D.
35BD
AND 98H E6 98
AND Register A with 98H, keeping bits 7 (not ready), 4 (seek error) and 3 (CRC error).
35BF
If the NZ FLAG is set (one of them is set), JUMP to 35C6H to turn the status into an error code.
35C1
LD A,B 78
Copy Register B (the operation) into Register A.
35C2
CP 0CH FE 0C
Compare Register A against 0CH, the read; it is always 0CH here.
35C4
If the Z FLAG is set (the read), JUMP to 35E5H to read the sector.
35C6
LD B,D 42
Copy Register D (the status of the Seek) into Register B, for the bit tests that follow.
35C7H - Turn the Status into an Error Code
Entered at 35C7H after a restore or a seek (Register B = the status), and at 35CBH after a read. The bits are tested in turn and the first one set gives the code: lost data 0AH (read only), seek error or record not found 08H or 0BH, CRC error 07H, not ready 03H. When none is set the routine returns 00H with the Z FLAG set.
35C7
LD D,08H 16 08
Load Register D with 08H, the error code for status bit 4 after a restore or a seek: seek error (Track Seek Error).
35C9
JUMP to 35D3H to test bit 4, past the lost data test and the record not found code of the read.
35CB
LD D,0AH 16 0A
Load Register D with 0AH, the error code for status bit 2 after a read: lost data (Lost Data Error).
35CD
BIT 2,B CB 50
Test bit 2 of Register B (the status): lost data, the CPU did not take a byte in time.
35CF
If the NZ FLAG is set (lost data), JUMP to 3585H to return error code 0AH.
35D1
LD D,0BH 16 0B
Load Register D with 0BH, the error code for status bit 4 after a read: record not found (ID Not Found Error).
35D3
BIT 4,B CB 60
Test bit 4 of Register B (the status): seek error after a restore or a seek, record not found after a read.
35D5
If the NZ FLAG is set (bit 4 is set), JUMP to 3585H to return the code in Register D (08H or 0BH).
35D7
LD D,07H 16 07
Load Register D with 07H, the error code for status bit 3: CRC error (Data CRC Error).
35D9
BIT 3,B CB 58
Test bit 3 of Register B (the status): CRC error, in the track ID after a restore or a seek, in the ID or the data after a read.
35DB
If the NZ FLAG is set (CRC error), JUMP to 3585H to return error code 07H.
35DD
LD D,03H 16 03
Load Register D with 03H, the error code for status bit 7: not ready (Drive Not Ready).
35DF
BIT 7,B CB 78
Test bit 7 of Register B (the status): not ready.
35E1
If the NZ FLAG is set (not ready), JUMP to 3585H to return error code 03H.
35E3
XOR A AF
Set Register A to 00H (XOR A), error code 00H: no error. The XOR sets the Z FLAG.
35E4
RET C9
RETURN to the caller with Register A = 00H and the Z FLAG set.
35E5H - Read the Sector
Sectors 00H-11H are on side 0; a sector of 12H or more would be read from side 1 as sector minus 12H (the callers pass only 00H-11H). The Read Sector command is issued with the NMI on the end of a command enabled. The first byte is waited for by polling; from then on the latch's wait state bit holds the CPU at each IN until the controller has the next byte, so the INI loop at 3623H takes the 256 bytes as fast as they come and never ends by itself: the controller's interrupt request at the end of the sector raises the NMI, which goes through 0066H and 3039H to 3629H.
35E5
XOR A AF
Set Register A to 00H (XOR A), the value Register B is loaded with next.
35E6
LD B,A 47
Copy Register A (00H) into Register B, the value added to the sector at 35F9H.
35E7
LD A,(42FDH) 3A FD 42
Fetch the drive select value stored at 42FDH (the drive's select bit and bit 7, double density) into Register A.
35EA
LD D,A 57
Copy Register A (the drive select value) into Register D, for the writes to port F4H.
35EB
LD C,82H 0E 82
Load Register C with 82H, the Read Sector command for side 0, side compare on.
| 1793 FDC Command: 82H (10000010) | | Function Description |
| 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | | Command=Read Sector (bits 7-5 = 100) m = 0: one sector S = 0: side to compare (used only when C = 1) E = 0: no 15 ms delay C = 1: side compare on |
35ED
IN A,(F2H) DB F2
Read the controller's sector register from port F2H into Register A: the sector written at 354EH.
35EF
CP 12H FE 12
Compare Register A (the sector) against 12H (18), the number of sectors on one side.
35F1
If the CARRY FLAG is set (sector 00H-11H, side 0), JUMP to 35F9H.
35F3
SUB 12H D6 12
SUBtract 12H from Register A: the sector number on side 1.
35F5
SET 4,D CB E2
Set bit 4 of Register D, the side select bit of the drive select value: side 1.
35F7
SET 3,C CB D9
Set bit 3 of Register C: the Read Sector command becomes 8AH, which compares the side number 1.
35F9
ADD A,B 80
ADD Register B (00H) to Register A: the sector number is unchanged.
35FA
OUT (F2H),A D3 F2
Write Register A (the sector) to port F2H, the controller's sector register.
35FC
LD A,D 7A
Copy Register D (the drive select value, with the side bit) into Register A.
35FD
OUT (F4H),A D3 F4
Write Register A to port F4H, the drive select latch: the drive and the side are selected.
35FF
LD B,00H 06 00
Load Register B with 00H: the INI count, which goes 00H, FFH and down (it is not used to end the loop).
3601
LD E,H 5C
Copy Register H (the high byte of the buffer, 43H) into Register E, to work out at 3633H how many 256-byte pages came in.
3602
LD A,C 79
Copy Register C (the Read Sector command, 82H or 8AH) into Register A.
3603
LD C,F3H 0E F3
Load Register C with F3H, the controller's data register, the port the INI instructions read.
3605
OUT (F0H),A D3 F0
Write Register A (the Read Sector command) to port F0H, the controller's command register: the read starts.
3607
LD A,80H 3E 80
Load Register A with 80H, the value for the NMI mask: bit 7, an NMI at the end of a command.
3609
OUT (E4H),A D3 E4
Write Register A (80H) to port E4H: the controller's interrupt request at the end of the read now raises an NMI.
| Port E4H (NMI Mask): 80H (10000000) | | Function Description |
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | Bit 7 = 1: NMI on the controller's interrupt request (INTRQ), the end of a command Bit 6 = 0: the second NMI source of the port off Bits 5-0: not used |
360B
GOSUB to 3643H to wait 19 DJNZ steps before the controller's status is read.
360E
LD A,D 7A
Copy Register D (the drive select value) into Register A.
360F
OUT (F4H),A D3 F4
Write Register A to port F4H again: the drive select latch is written once more without the wait state bit.
3611H - Wait for the First Byte
Polls the status until the controller has the first byte (data request, bit 1) or the drive is not ready (bit 7).
3611
IN A,(F0H) DB F0
Read the controller status from port F0H into Register A.
3613
BIT 1,A CB 4F
Test bit 1 of Register A, data request: the Z FLAG is clear when the controller has a byte for the CPU.
3615
If the NZ FLAG is set (a byte is ready), JUMP to 361EH to take it.
3618
RLCA 07
Rotate Register A left (RLCA): bit 7, not ready, goes into the CARRY FLAG.
3619
If the NC FLAG is set (the drive is ready), JUMP back to 3611H and wait for the byte.
361C
JUMP to 362DH: the drive is not ready, so the status is read and turned into an error code (03H for not ready); on this way port E4H stays at 80H.
361E
INI ED A2
INI: read the first byte from the port in Register C (F3H) into the byte at Register Pair HL, INCrement Register Pair HL and DECrement Register B.
3620
LD A,D 7A
Copy Register D (the drive select value) into Register A.
3621
OR 40H F6 40
OR Register A with 40H, bit 6 of the drive select latch: wait states while the controller has no byte ready.
3623
OUT (F4H),A D3 F4
Write Register A to port F4H, the drive select latch with the wait state bit set: the next IN from the controller holds the CPU until the byte is there.
3625
INI ED A2
INI: read the next byte from the port in Register C (F3H) into the byte at Register Pair HL, INCrement Register Pair HL and DECrement Register B.
3627
JUMP back to 3623H for the next byte. The loop does not end by itself: the NMI at the end of the sector takes the CPU to 3629H.
3629H - NMI Handler: End of the Read
The NMI comes through ROM A 0066H (JP 3039H) and 3039H (JP 3629H) at the end of the command, with the address the CPU was at on the stack: in the INI loop after a full sector, or in the wait for the first byte (3611H-3621H) when the read ends without data, for instance with record not found. That address is dropped, the NMI mask is cleared, the status is read and the routine finishes with a RETN to its own next instruction, which ends the NMI for the CPU. The status is then turned into an error code at 35CBH.
3629
POP BC C1
Restore Register Pair BC from the stack: this drops the address the NMI pushed (in the INI loop 3623H-3627H, or in the wait at 3611H-3621H), which is not returned to.
362A
XOR A AF
Set Register A to 00H (XOR A), the value for the NMI mask.
362B
OUT (E4H),A D3 E4
Write Register A (00H) to port E4H, the NMI mask: no more NMI.
| Port E4H (NMI Mask): 00H (00000000) | | Function Description |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | Bit 7 = 0: no NMI on INTRQ Bit 6 = 0: the second NMI source of the port off Bits 5-0: not used |
362D
IN A,(F0H) DB F0
Read the controller status from port F0H into Register A: the status at the end of the read (reading it also clears the controller's interrupt request).
362F
LD B,A 47
Copy Register A (the status) into Register B, for the bit tests from 35CBH.
3630
GOSUB to 3638H, a RETN, which returns to 3633H and ends the NMI state of the CPU (interrupts stay disabled).
3633
LD A,H 7C
Copy Register H (the high byte of the buffer address after the last byte) into Register A.
3634
SUB E 93
SUBtract Register E (the high byte of the buffer address at the start, from 3601H) from Register A: the number of 256-byte pages read, 01H for a full sector.
3635
LD E,A 5F
Copy Register A (the pages read) into Register E; the Diagnostic does not look at it (the disk test loads Register E again at 338BH).
3636
JUMP to 35CBH to turn the status in Register B into an error code, testing lost data first.
3638
RETN ED 45
RETN: return to the address on the stack (3633H when called from 3630H) and copy the CPU's saved interrupt state back, ending the NMI.
363AH - Controller Helpers: Stop, Wait, Command
363AH stops any command of the controller (Force Interrupt D0H) and waits 256 DJNZ steps; 3643H waits 19 DJNZ steps; 364AH issues the command in Register A and waits until the controller is no longer busy or reports not ready. Register Pair BC is kept by the waits.
363A
LD A,D0H 3E D0
Load Register A with D0H, the Force Interrupt command with no condition: the command in progress ends and no interrupt request follows.
| 1793 FDC Command: D0H (11010000) | | Function Description |
| 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | | Command=Force Interrupt (bits 7-4 = 1101) I3-I0 = 0000: end the command without an interrupt |
363C
OUT (F0H),A D3 F0
Write Register A (D0H) to port F0H, the controller's command register.
363E
PUSH BC C5
Save Register Pair BC to the stack across the wait.
363F
LD B,00H 06 00
Load Register B with 00H, so the DJNZ at 3646H runs 256 times.
3641
JUMP to 3646H, the wait loop shared with the short wait at 3643H.
3643
PUSH BC C5
Save Register Pair BC to the stack across the wait.
3644
LD B,13H 06 13
Load Register B with 13H (19), the steps of the short wait.
3646
DECrement Register B and LOOP BACK to 3646H while it is not zero: the wait.
3648
POP BC C1
Restore Register Pair BC from the stack, as it was before the wait.
3649
RET C9
RETURN to the caller once the wait is over, with Register Pair BC as it was.
364A
OUT (F0H),A D3 F0
Write Register A (the command, Restore 0CH or Seek 1CH) to port F0H, the controller's command register.
364C
GOSUB to 3643H to wait 19 DJNZ steps before the controller's status is read.
364F
LD C,00H 0E 00
Load Register C with 00H, the status before the last one, kept while the controller is busy.
3651
IN A,(F0H) DB F0
Read the controller status from port F0H into Register A.
3653
BIT 0,A CB 47
Test bit 0 of Register A, busy: the Z FLAG is set when the command has ended.
3655
RET Z C8
If the Z FLAG is set (the command has ended), RETURN with the status in Register A.
3656
BIT 7,A CB 7F
Test bit 7 of Register A, not ready: the Z FLAG is clear when the drive is not ready.
3658
RET NZ C0
If the NZ FLAG is set (the drive is not ready while the command is still busy), RETURN with that status in Register A.
3659
LD C,A 4F
Copy Register A (this status) into Register C, the status before the next one.
365A
JUMP back to 3651H to read the status again until the command ends or the drive drops out.
365CH - Boot from the RS-232 Port (S): Wait for the Host
Selected with S. Both video pages are cleared, the UART is set up and Host Not Ready is shown until bit 5 of the RS-232 status port E8H reads 0, then Host Is Ready. The UART is set for 8 data bits, odd parity and 1 stop bit; the baud rate is found at 3680H.
365C
LD A,04H 3E 04
Load Register A with 04H; 33CEH loads Register A with 20H first thing, so the 04H is not used.
365E
GOSUB to 33CEH to fill both video pages with spaces; port 84H is left at 00H.
3661
LD A,64H 3E 64
Load Register A with 64H, the value for the UART control register: bits 6-5 = 11 (8 data bits), bit 4 = 0 (1 stop bit), bit 3 = 0 (parity on), bit 7 = 0 (odd parity), bit 2 = 1 (transmitter on, no break), bits 1-0 = 00 (RTS and DTR on). The retry after a load error comes back here (36EEH).
3663
OUT (EAH),A D3 EA
Write Register A (64H) to port EAH, the UART control register.
3665
LD HL,3482H 21 82 34
Load Register Pair HL with 3482H, the text Host Not Ready.
3668
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the top left of the screen for 345EH.
366B
GOSUB to 345EH to put Host Not Ready at Register Pair DE (3C00H).
366E
IN A,(E8H) DB E8
Read the RS-232 status from port E8H into Register A: bit 5 is the carrier detect line (pin 8 of the connector).
3670
AND 20H E6 20
AND Register A with 20H, keeping bit 5: the Z FLAG is set when it reads 0.
3672
If the NZ FLAG is set (bit 5 reads 1), JUMP back to 366EH and read the status again: the host is not ready.
3674
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the top left of the screen again.
3677
LD HL,3491H 21 91 34
Load Register Pair HL with 3491H, the text Host Is Ready followed by a space.
367A
GOSUB to 345EH to put Host Is Ready over Host Not Ready at Register Pair DE (3C00H).
367D
LD HL,42FEH 21 FE 42
Load Register Pair HL with 42FEH; nothing reads Register Pair HL before 36ABH loads it again, so the value is not used.
3680H - Find the Baud Rate
The host is to send the byte 55H over and over. The 16 rates of the baud rate port E9H are tried from FFH (19200 baud) down to 00H (50 baud), the same code in both halves of the byte; at each rate up to ten bytes are read, and a 55H then has to be followed by ten more 55H. When the rate is found, Found Baud Rate and a letter for it (A for 00H up to P for FFH) are shown on line 6. Bytes that arrive with an error count as bytes that are not 55H. There is no time limit: 36F1H waits for each byte.
3680
LD A,FFH 3E FF
Load Register A with FFH, the first baud rate code tried: 19200 baud.
3682
LD C,A 4F
Copy Register A (the baud rate code) into Register C, which keeps it.
3683
OUT (E9H),A D3 E9
Write Register A (the baud rate code) to port E9H, the baud rate generator.
3685
OUT (E8H),A D3 E8
Write Register A to port E8H; any write to port E8H resets the UART.
3687
LD B,0AH 06 0A
Load Register B with 0AH (10), the bytes read at this rate while looking for 55H.
3689
GOSUB to 36F1H to wait for a byte; Register A returns it, with the Z FLAG clear if it arrived with an error.
368C
If the NZ FLAG is set (the byte had an error), JUMP to 3692H; it counts as one of the ten.
368E
CP 55H FE 55
Compare Register A (the byte) against 55H, the byte the host sends.
3690
If the Z FLAG is set (55H arrived), JUMP to 369BH to check that ten more follow at this rate.
3692
DECrement Register B (the bytes left at this rate) and LOOP BACK to 3689H while it is not zero.
3694
LD A,C 79
Copy Register C (the baud rate code) into Register A.
3695
SUB 11H D6 11
SUBtract 11H from Register A: the code of the next lower rate (EEH after FFH, down to 00H).
3697
If the NC FLAG is set (Register A did not go below 00H), JUMP back to 3682H to try that rate.
3699
JUMP back to 3680H to start again at 19200 baud after 50 baud has been tried.
369B
LD B,0AH 06 0A
Load Register B with 0AH (10), the number of 55H bytes that have to follow.
369D
GOSUB to 36F1H to wait for a byte; Register A returns it, with the Z FLAG clear if it arrived with an error.
36A0
If the NZ FLAG is set (the byte had an error), JUMP back to 3680H to search again from 19200 baud.
36A2
CP 55H FE 55
Compare Register A (the byte just read) against 55H, the byte the host keeps sending.
36A4
If the NZ FLAG is set (it is not 55H), JUMP back to 3680H to search again from 19200 baud.
36A6
DECrement Register B (the 55H bytes still to come) and LOOP BACK to 369DH while it is not zero.
36A8
LD DE,0184H 11 84 01
Load Register Pair DE with 0184H, the screen offset of line 6, column 4.
36AB
LD HL,3710H 21 10 37
Load Register Pair HL with 3710H, the text Found Baud Rate followed by a space.
36AE
GOSUB to 36FDH to put Found Baud Rate at Register Pair DE (3D84H) and send it to the host; Register Pair DE ends at 3D94H, after the text.
36B1H - Load the Program and Run It
The letter of the rate goes after Found Baud Rate. Then bytes are read until an FFH arrives, Loading... is shown and sent, and the records that follow are loaded (3721H). When the transfer record has been read the program is run at its transfer address. A byte with an error at any point shows Load Error and a letter for the error, waits, and starts again at 3661H.
36B1
LD A,C 79
Copy Register C (the baud rate code, 00H-FFH in steps of 11H) into Register A.
36B2
AND 0FH E6 0F
AND Register A with 0FH, keeping the low half of the code: 00H-0FH.
36B4
ADD A,41H C6 41
ADD 41H to Register A: the letter A for 00H (50 baud) up to P for 0FH (19200 baud).
36B6
LD (DE),A 12
Store Register A (the letter of the rate) at Register Pair DE (3D94H), after Found Baud Rate on line 6.
36B7
IN A,(EBH) DB EB
Read the UART's receive register from port EBH into Register A; the byte is not used.
36B9
GOSUB to 36F1H to wait for a byte; Register A returns it, with the Z FLAG clear if it arrived with an error.
36BC
If the NZ FLAG is set (the byte had an error), JUMP to 36D1H to show Load Error.
36BE
CP FFH FE FF
Compare Register A (the byte) against FFH, the byte that starts the load.
36C0
If the NZ FLAG is set (it is not FFH), JUMP back to 36B9H for the next byte.
36C2
LD DE,0244H 11 44 02
Load Register Pair DE with 0244H, the screen offset of line 9, column 4.
36C5
LD HL,3517H 21 17 35
Load Register Pair HL with 3517H, the text Loading...
36C8
GOSUB to 36FDH to put Loading... at Register Pair DE (3E44H) and send it to the host.
36CB
GOSUB to 3721H to load the records; it returns with the Z FLAG set and the transfer address in Register Pair HL, or with the NZ FLAG set after a byte with an error.
36CE
If the NZ FLAG is set (a byte had an error), JUMP to 36D1H to show Load Error.
36D0
JP (HL) E9
JUMP to the address in Register Pair HL, the transfer address of the program just loaded: the Diagnostic is done.
36D1
RRCA 0F
Rotate Register A right (RRCA), the first of three: Register A holds the error bits 5-3 of the UART status (overrun, framing, parity).
36D2
RRCA 0F
Rotate Register A right (RRCA), the second of three.
36D3
RRCA 0F
Rotate Register A right (RRCA), the third: the error bits are now bits 2-0, 1 for parity, 2 for framing, 4 for overrun.
36D4
PUSH AF F5
Save Register Pair AF (Register A holds the error bits) to the stack while the screen is cleared.
36D5
GOSUB to 33CEH to fill both video pages with spaces; port 84H is left at 00H.
36D8
LD DE,03C4H 11 C4 03
Load Register Pair DE with 03C4H, the screen offset of line 15, column 4.
36DB
LD HL,3522H 21 22 35
Load Register Pair HL with 3522H, the text Load Error.
36DE
GOSUB to 36FDH to put Load Error at Register Pair DE (3FC4H) and send it to the host; Register Pair DE ends at 3FCEH.
36E1
POP AF F1
Restore Register Pair AF from the stack: Register A is the error bits, 01H-07H.
36E2
ADD A,41H C6 41
ADD 41H to Register A: B for a parity error, C for framing, E for overrun, and D, F, G or H when there were several.
36E4
INC DE 13
INCrement Register Pair DE to 3FCFH, leaving a blank column after Load Error.
36E5
LD (DE),A 12
Store Register A (the letter of the error) at Register Pair DE (3FCFH).
36E6
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H: Register B = 00H (256 DJNZ steps) and Register C = 00H (256 rounds of them).
36E9
DECrement Register B and LOOP BACK to 36E9H while it is not zero: 256 steps of the wait.
36EB
DEC C 0D
DECrement Register C, the rounds of 256 steps left (from 00H it goes to FFH).
36EC
If the NZ FLAG is set (rounds are left), JUMP back to 36E9H: 65536 steps in all.
36EE
JUMP to 3661H to set up the UART again and wait for the host; the screen is not cleared, Host Not Ready goes over the top line.
36F1H - RS-232 Helpers: Read a Byte, Send a Text
36F1H waits until the UART has a byte and returns it in Register A with the Z FLAG set, or, if it arrived with a parity, framing or overrun error, returns the error bits (status AND 38H) with the Z FLAG clear and leaves the byte unread. There is no time limit. 36FDH puts the text at Register Pair HL on the screen at Register Pair DE (345EH) and sends it to the host, each byte when the transmitter is empty, without the 00H that ends it.
36F1
IN A,(EAH) DB EA
Read the UART status from port EAH into Register A: bit 7 data ready, bits 5-3 overrun, framing and parity errors, bit 6 transmitter empty.
36F3
BIT 7,A CB 7F
Test bit 7 of Register A, data ready: the Z FLAG is set when no byte has arrived.
36F5
If the Z FLAG is set (no byte yet), JUMP back to 36F1H and read the status again.
36F7
AND 38H E6 38
AND Register A with 38H, keeping bits 5-3, the overrun, framing and parity errors: the Z FLAG is set when there is none.
36F9
RET NZ C0
If the NZ FLAG is set (the byte arrived with an error), RETURN with the error bits in Register A.
36FA
IN A,(EBH) DB EB
Read the byte from port EBH, the UART's receive register, into Register A; the Z FLAG is still set from 36F7H.
36FC
RET C9
RETURN to the caller with the byte in Register A and the Z FLAG set.
36FD
PUSH HL E5
Save Register Pair HL (the address of the text) to the stack.
36FE
GOSUB to 345EH to put the text at Register Pair HL on the screen at Register Pair DE.
3701
POP HL E1
Restore Register Pair HL from the stack: the address of the text again, for sending it.
3702
IN A,(EAH) DB EA
Read the UART status from port EAH into Register A.
3704
AND 40H E6 40
AND Register A with 40H, keeping bit 6, transmitter empty: the Z FLAG is set while the UART is still sending.
3706
If the Z FLAG is set (the transmitter is not empty), JUMP back to 3702H and wait.
3708
LD A,(HL) 7E
Fetch the next character of the text at Register Pair HL into Register A.
3709
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the 00H that ends the text.
370A
RET Z C8
If the Z FLAG is set (the end of the text), RETURN to the caller; the 00H is not sent.
370B
OUT (EBH),A D3 EB
Write Register A (the character) to port EBH, the UART's transmit register: it is sent to the host.
370D
INC HL 23
INCrement Register Pair HL to the next character of the text.
370E
JUMP back to 3702H to wait for the transmitter and send the next character.
3710H - RS-232 Text
The text 36ABH shows on line 6 and sends to the host when the baud rate has been found.
3710-3720
DEFM "Found Baud Rate ",00H 46 6F 75 6E 64 20 42 61 75 64 20 52 61 74 65 20 00
16 characters and 00H: shown at 3D84H and sent to the host; the letter of the rate goes after it at 3D94H.
3721H - Load the Records
The program comes as records: a type byte, a length byte, then the bytes. Type 01H is a load record: the length is 2 more than the number of data bytes (a length of 02H means 256), then the load address (low byte first) and the data, stored from that address up. Type 02H is the transfer record: a length byte that is not used and the transfer address (low byte first), after which the routine returns with the Z FLAG set and the address in Register Pair HL. Any other type is skipped: a length byte and that many bytes (00H means 256). A byte with an error ends the routine with the NZ FLAG set.
3721
LD E,FFH 1E FF
Load Register E with FFH; no instruction reads Register E afterwards, so the value is not used.
3723
GOSUB to 36F1H to wait for the type byte of the next record; Register A returns it.
3726
RET NZ C0
If the NZ FLAG is set (the byte had an error), RETURN with the error bits in Register A.
3727
DEC A 3D
DECrement Register A (the type): the Z FLAG is set for type 01H.
3728
If the Z FLAG is set (type 01H, a load record), JUMP to 373BH.
372A
DEC A 3D
DECrement Register A again: the Z FLAG is set for type 02H.
372B
If the NZ FLAG is set (neither 01H nor 02H), JUMP to 3750H to skip the record.
372D
GOSUB to 36F1H to wait for the length byte of the transfer record, which is not used.
3730
RET NZ C0
If the NZ FLAG is set (the byte had an error), RETURN with the error bits in Register A.
3731H - Read an Address into HL
Reads two bytes, low byte first, into Register Pair HL. Used for the transfer address (from 372DH) and for the load address of a load record (3742H). The second byte's error is not tested here; the RET returns with its flags.
3731
GOSUB to 36F1H to wait for the low byte of the address; Register A returns it.
3734
RET NZ C0
If the NZ FLAG is set (the byte had an error), RETURN with the error bits in Register A.
3735
LD L,A 6F
Copy Register A (the low byte of the address) into Register L.
3736
GOSUB to 36F1H to wait for the high byte of the address; Register A returns it.
3739
LD H,A 67
Copy Register A (the high byte of the address) into Register H: Register Pair HL = the address.
373A
RET C9
RETURN with the address in Register Pair HL and the flags of 36F1H: Z when the high byte arrived without error.
373BH - Load Record
Type 01H: the length byte, the load address and the data bytes, stored at the address and up.
373B
GOSUB to 36F1H to wait for the length byte of the load record; Register A returns it.
373E
RET NZ C0
If the NZ FLAG is set (the byte had an error), RETURN with the error bits in Register A.
373F
DEC A 3D
DECrement Register A (the length), the first of two: the two bytes of the load address are part of the length.
3740
DEC A 3D
DECrement Register A again: the number of data bytes (00H for a length of 02H, which the DJNZ counts as 256).
3741
LD B,A 47
Copy Register A (the number of data bytes) into Register B, the count for the DJNZ at 374CH.
3742
GOSUB to 3731H to read the load address into Register Pair HL.
3745
RET NZ C0
If the NZ FLAG is set (a byte had an error), RETURN with the error bits in Register A.
3746
GOSUB to 36F1H to wait for the next data byte; Register A returns it.
3749
RET NZ C0
If the NZ FLAG is set (the byte had an error), RETURN with the error bits in Register A.
374A
LD (HL),A 77
Store Register A (the data byte) at Register Pair HL, its place in memory.
374B
INC HL 23
INCrement Register Pair HL to the address of the next data byte.
374C
DECrement Register B (the data bytes left) and LOOP BACK to 3746H while it is not zero.
374E
JUMP back to 3723H to read the type byte of the next record.
3750H - Skip a Record
Any type other than 01H and 02H: the length byte, then that many bytes read and dropped. An error in the length byte is not tested; the error bits are then taken as the length.
3750
GOSUB to 36F1H to wait for the length byte of the record to skip; Register A returns it.
3753
LD B,A 47
Copy Register A (the length, 00H counting as 256) into Register B, the count for the DJNZ at 3758H.
3754
GOSUB to 36F1H to wait for the next byte of the record, which is dropped.
3757
RET NZ C0
If the NZ FLAG is set (the byte had an error), RETURN with the error bits in Register A.
3758
DECrement Register B (the bytes left to skip) and LOOP BACK to 3754H while it is not zero.
375A
JUMP back to 3723H to read the type byte of the next record.
375CH - Unused: Multiply by Adding
No instruction of the Diagnostic calls 375CH. It returns Register C times the count in Register A (the low byte of the product) in Register A, by adding Register C that many times; a count of 00H returns 00H at once.
375C
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set when the count is 00H (never run).
375D
RET Z C8
If the Z FLAG is set (the count is 00H), RETURN with Register A = 00H (never run).
375E
LD B,A 47
Copy Register A (the count) into Register B, the count for the DJNZ at 3761H (never run).
375F
XOR A AF
Set Register A to 00H (XOR A), the sum the additions start from (never run).
3760
ADD A,C 81
ADD Register C to Register A, one more time Register C (never run).
3761
DECrement Register B (the additions left) and LOOP BACK to 3760H while it is not zero (never run).
3763
RET C9
RETURN with Register A = Register C times the count, the low byte of the product (never run).
3764H - Read a Sector into 4300H
Three entries into the disk routine 3546H with Register Pair HL = 4300H, the buffer, and Register B = 0CH, the read: 3765H for the disk test (3380H) and 3767H for the floppy boot (3433H), both with Register C = the sector and Register E = the track. 3764H, which would take the sector from Register A, is not used.
3764
LD C,A 4F
Copy Register A into Register C, the sector to read; no instruction jumps to 3764H, so this entry is never used.
3765
LD A,01H 3E 01
Load Register A with 01H, the value 3546H DECrements without effect (the disk test's entry).
3767
LD HL,4300H 21 00 43
Load Register Pair HL with 4300H, the buffer the sector is read into, 4300H-43FFH (the floppy boot's entry).
376A
LD B,0CH 06 0C
Load Register B with 0CH, the operation for 3546H: read a sector.
376C
JUMP to 3546H to select the drive, seek to the track in Register E and read the sector in Register C into Register Pair HL; 3546H returns to the caller of 3765H or 3767H.
376FH - Unused Bytes to the End of the Diagnostic
The rest of the 2K, up to 37FFH, holds FFH, the value of EPROM bytes that were never programmed. Nothing jumps here or reads it.
376F-37FF
DEFB FFH x 145 FF x 145
The 145 bytes 376FH-37FFH are FFH, never programmed. They are not code and nothing reads them; the Diagnostic's last instruction is the JP 3546H at 376CH.