| boot_reloc: | 0000 | LXI H,0013 | HL=0013, mem copy source. |
| 0003 | LXI D,5C00 | DE=5C00, mem copy destination. | |
| 0006 | MVI C,FC | C=FC, mem copy size. | |
| 0008 | MOV A,M | Read from source. | |
| 0009 | STAX D | Write to destination. | |
| 000A | INX H | ||
| 000B | INX D | ||
| 000C | DCR C | ||
| 000D | JNZ 0008 | Loop back until all FCh bytes are done. | |
| 0010 | JMP 5C00 | Jump to 5C00, where the bootstrap now lives. |
| 5C00 | DI | Disable Interrupts. | |
| 5C01 | XRA A | Write 00h to port 22h (poss. Centronics Printer IO). | |
| 5C02 | OUT 22 | ||
| 5C04 | CMA | Write FFh to port 23h (poss. Centronics Printer IO). | |
| 5C05 | OUT 23 | ||
| 5C07 | MVI A,2C | Write 2Ch to port 22h (poss. Centronics Printer IO). | |
| 5C09 | OUT 22 | ||
| 5C0B | MVI A,03 | Reset the serial IO card. | |
| 5C0D | OUT 10 | ||
| 5C0F | IN FF | ?What is port FF is for? | |
| 5C11 | ANI 10 | ||
| 5C13 | RRC | ||
| 5C14 | RRC | ||
| 5C15 | ADI 10 | ||
| 5C17 | OUT 10 | Another serial IO status write. Effect unknown. |
| 5C19 | LXI SP,5D8A | SP=5D8A. Presumably a safe place. | |
| 5C1C | XRA A | Select disk 0 for IO. | |
| 5C1D | OUT 08 | ||
| 5C1F | IN 08 | Wait for bit 3 of port 8 to be 0. I don't yet know what we're waiting for here! | |
| 5C21 | ANI 08 | ||
| 5C23 | JNZ 5C1C | ||
| 5C26 | MVI A,04 | Load head to drive surface. | |
| 5C28 | OUT 09 | ||
| 5C2A | JMP 5C38 | Jump ahead to Track0Test. | |
| MoveHeadOut: | 5C2D | IN 08 | Wait for permission to move head. |
| 5C2F | ANI 02 | ||
| 5C31 | JNZ 5C2D | ||
| 5C34 | MVI A,02 | Move head out one track (ie towards track 0 on the rim). | |
| 5C36 | OUT 09 | ||
| Track0Test: | 5C38 | IN 08 | If we're not on track 0 then jump back to MoveHeadOut. |
| 5C3A | ANI 40 | ||
| 5C3C | JNZ 5C2D |
[Note that the mnemonics for this section are Z80 style. I have not got around to making them the less-familiar-to-me-and-frankly-inferior 8080 style.]
| 5C3F | LD DE,0000 | DE=0000, ie BASIC destination. | |
| 5C42 | LD B,08 | B=08h, ie # of first sector to read from track 0. | |
| 5C44 | JP NZ,0006 | What a slimy hack! This jump never occurs; it's a cheap way to avoid executing the next instruction (at 5C45) on the first pass, ie when reading track 0. | |
| ReadTrack: | 5C45 | LD B,00 | B=00h, # of first sector (pass 2). |
| 5C47 | LD A,10 | A=10h, max attempts to read a sector. | |
| 5C49 | PUSH AF | ||
| 5C4A | PUSH DE | ||
| 5C4B | PUSH BC | ||
| 5C4C | PUSH DE | ||
| 5C4D | LD DE,8086 | E=86h, ie bytes to read. D is ignored. | |
| 5C50 | LD HL,5CFC | ||
| WaitForSector: | 5C53 | IN A,(09) | Wait for the required sector (in B register) to spin past. |
| 5C55 | RRA | ||
| 5C56 | JP C,5C53 | ||
| 5C59 | AND 1F | ||
| 5C5B | CP B | ||
| 5C5C | JP NZ,5C53 | ||
| ReadSector: | 5C5F | IN A,(08) | Wait for a new byte to be readable. |
| 5C61 | OR A | ||
| 5C62 | JM M,5C5F | ||
| 5C65 | IN A,(0A) | Read the byte from the disk and write it to 5CFC+. | |
| 5C67 | LD (HL),A | ||
| 5C68 | INC HL | ||
| 5C69 | DEC E | If we've read the whole sector, then jump ahead to CopyPayload. | |
| 5C6A | JP Z,5C75 | ||
| 5C6D | DEC E | ||
| 5C6E | IN A,(0A) | Read another byte from the disk and write it to 5CFC+. | |
| 5C70 | LD (HL),A | ||
| 5C71 | INC HL | ||
| 5C72 | JP NZ,5C5F | Jump back until sector complete. | |
| CopyPayload: | 5C75 | POP HL | HL=BASIC destination. |
| 5C76 | LD DE,5CFF | DE=5CFF, sector payload source. | |
| 5C79 | LD BC,0080 | B=00 (checksum). C=80 (payload size). | |
| CopyLoop: | 5C7C | LD A,(DE) | Copy one byte of sector payload to BASIC destination. |
| 5C7D | LD (HL),A | ||
| 5C7E | CP (HL) | Check the mem copy worked. If it failed then jump to ErrBadMemory. | |
| 5C7F | JP NZ,5CDC | ||
| 5C82 | ADD A,B | Add the byte value to the checksum in B. | |
| 5C83 | LD B,A | ||
| 5C84 | INC DE | ||
| 5C85 | INC HL | ||
| 5C86 | DEC C | Loop until all 80h bytes of the payload have been copied. | |
| 5C87 | JP NZ,5C7C | ||
| CheckEOP: | 5C8A | LD A,(DE) | Check for the End of Payload (EOP) marker byte. |
| 5C8B | CP FF | ||
| 5C8D | JP NZ,5C93 | ||
| 5C90 | INC DE | ||
| 5C91 | LD A,(DE) | Compare the payload checksum from disk with what it should be (stored in B). | |
| 5C92 | CP B | ||
| 5C93 | POP BC | B= # of sector read. | |
| 5C94 | EX DE,HL | HL=payload source, DE=BASIC destination. | |
| 5C95 | JP NZ,5CD0 | If checksum bad, jump to SectorIsBad. | |
| 5C98 | POP AF | Clear up stack. AF is ignored. | |
| 5C99 | POP AF | ||
| 5C9A | LD HL,(5CFD) | HL=sector signature. | |
| 5C9D | PUSH DE | Preserve DE (BASIC destination). | |
| 5C9E | LD DE,5C00 | Compare sector signature to 5C00. | |
| 5CA1 | CALL 5CF6 | ||
| 5CA4 | POP DE | DE=BASIC destination. | |
| 5CA5 | JP C,5CD9 | If sector sig. > 5C00 then jump to ErrBadSig. | |
| 5CA8 | CALL 5CF6 | Compare sector signature to DE. | |
| 5CAB | JP NC,5CC9 | If sig. <= DE then jump ahead to RunBASIC | |
| 5CAE | INC B | ||
| 5CAF | INC B | Add 2 to sector #. | |
| 5CB0 | LD A,B | ||
| 5CB1 | CP 20 | Loop back to foobar until we've read the last sector for the current pass. | |
| 5CB3 | JP C,5C47 | ||
| 5CB6 | LD B,01 | B=1 (first sector # for second half of read). | |
| 5CB8 | JP Z,5C47 | Jump back to foobar for second read | |
| 5CBB | IN A,(08) | Wait for permission to move head. | |
| 5CBD | AND 02 | ||
| 5CBF | JP NZ,5CBB | ||
| 5CC2 | LD A,01 | Move head inwards onto the next track. | |
| 5CC4 | OUT (09),A | ||
| 5CC6 | JP 5C45 | Jump back to ReadTrack | |
| RunBASIC: | 5CC9 | LD A,80 | Deselect disk 0. |
| 5CCB | OUT (08),A | ||
| 5CCD | JP 0000 | Jump to BASIC!!! | |
| SectorIsBad: | 5CD0 | POP DE | |
| 5CD1 | POP AF | A=bad sectors tolerated | |
| 5CD2 | DEC A | Decrement allowed sector read attempts. | |
| 5CD3 | JP NZ,5C49 | If allowed, jump back to try to read the sector again. | |
| ErrBadSector: | 5CD6 | LD A,43 | Error code 43h. |
| 5CD8 | LD BC,4F3E | ||
| 5CDB | LD BC,4D3E | ||
| (Execution continues at DoError (5CDE) below.) | |||
| ErrBadSig: | 5CD9 | LD A,4F | Error code 4Fh. |
| 5CDB | LD BC,4D3E | ||
| (Execution continues at DoError (5CDE) below.) | |||
| ErrBadMemory: | 5CDC | LD A,4D | Error code 4Dh. |
| DoError: | 5CDE | EI | |
| 5CDF | LD (0000),A | Write error code to mem addr 0000. | |
| 5CE2 | LD (0001),HL | HL is presumably extra error info. | |
| 5CE5 | LD B,A | B=Error code. | |
| 5CE6 | LD A,80 | Deselect disk 0. | |
| 5CE8 | OUT (08),A | ||
| 5CEA | LD A,B | A=Error code. | |
| ErrorOut: | 5CEB | OUT (01),A | ?What is port 01h? |
| 5CED | OUT (11),A | ?What is port 11h? | |
| 5CEF | OUT (05),A | ?What is port 05h? | |
| 5CF1 | OUT (23),A | ?What is port 23h? | |
| 5CF3 | JP 5CEB | Infinite loop back to ErrorOut. | |
| CompareDEandHL: | 5CF6 | LD A,D | Simple helper function that compares DE and HL for equality. |
| 5CF7 | CP H | ||
| 5CF8 | RET NZ | ||
| 5CF9 | LD A,E | ||
| 5CFA | CP L | ||
| 5CFB | RET | ||