4200H - Boot Entry: Stack, Screen and Controller Registers
When the computer is reset with a diskette in drive 0, the ROM selects drive 0, steps the head to track 0, reads sector 0 into 4200H-42FFH and jumps to 4200H (its 0674H-06C9H). Interrupts are off (the DI at 0000H) and stay off: nothing in this sector enables them. This first part sets the stack, clears the screen and puts the three addresses the controller code needs into the alternate register set, then reads track 0, sector 1.
4200
CP 00H FE 00
Compare Register A with 00H. Register A holds the last byte the ROM took from the controller's data register while reading this sector (its 06C4H); the flags are never tested. The instruction is there because of its first byte: FEH at 4200H is the length byte of the sector. Every sector MicroDOS writes starts with the count of the data bytes that follow it (the main file's sector write at 4BF6H writes the count held at 448FH as byte 0 of the sector), and the main file's CMD"M" (4841H, through 491BH) takes the first byte of its copy of this sector, 4594H, as that count: 254 data bytes, 4201H-42FEH. Its second byte, 00H at 4201H, is the first of those data bytes.
4202
LD SP,41FCH 31 FC 41
Load the Stack Pointer with 41FCH. The ROM left it at 407DH (its 0693H). The calls and pushes of this sector go below 41FCH: its own deepest use is 41F2H-41FBH (the return address of the read at 4212H or 4247H, the return of 424CH's call to 4275H, the return of the call to 42B9H at 4299H, Register Pair AF pushed at 42B9H and the return of its call to 42C7H). The ROM routines called at 01C9H, 0033H, 0060H and 002BH push more below. 41FCH-41FFH are not used.
4205
GOSUB to the ROM's clear screen routine at 01C9H: it sends 1CH (cursor to 3C00H, the top left corner, and 64 characters a line) and 1FH (clear to the end of the screen) through the display routine. The ROM set up the display's control block at 401DH from its 06D2H table before reading this sector, so the display routine works here.
4208
LD BC,4300H 01 00 43
Load Register Pair BC with 4300H, the start of the 256 byte sector buffer 4300H-43FFH. After the EXX at 4211H it is Register Pair BC', the pointer the read loop at 4263H stores each byte through.
420B
LD DE,37ECH 11 EC 37
Load Register Pair DE with 37ECH, the controller's command register (written) and status register (read). After the EXX at 4211H it is Register Pair DE', through which 425DH, 4267H, 42BFH, 42C0H and 42CDH read the status and write the commands.
420E
LD HL,37EFH 21 EF 37
Load Register Pair HL with 37EFH, the controller's data register. After the EXX at 4211H it is Register Pair HL', from which the read loop takes each byte of a sector (4262H).
4211
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: BC' = 4300H (buffer pointer), DE' = 37ECH (command and status) and HL' = 37EFH (data) for the whole boot. The main set is left free for the signature check, the copy and the texts; each routine below that works the controller through the alternate set starts and ends with EXX.
4212
GOSUB to 424CH to read the sector named by 42DDH (track, 00H) and 42DEH (sector, 01H): track 0, sector 1, the first sector of the MicroDOS main file, into the buffer 4300H-43FFH. 424CH comes back only when the read had no error; an error goes to DISK ERROR at 42A2H.
4215H - Check for MICRODOS on Track 0, Sector 1
The first sector of the main file carries the eight characters MICRODOS at bytes 4-11 (its byte 0 is the length byte FFH and bytes 1-3 are the JP 4727H that becomes 4400H-4402H of the main file). They are compared with the same eight characters in this sector; a diskette that does not have them gets NO MICRODOS.
4215
LD DE,42F1H 11 F1 42
Point Register Pair DE to 42F1H, the eight characters MICRODOS in this sector (they are also the end of the NO MICRODOS text that starts at 42ECH).
4218
LD HL,4304H 21 04 43
Point Register Pair HL to 4304H, byte 4 of the sector just read into the buffer: where the main file's MICRODOS (its 4403H-440AH) is when the first sector is in the buffer.
421B
LD B,08H 06 08
Load Register B with 08H, the number of characters to compare.
421D
LD A,(DE) 1A
Fetch the next character of MICRODOS in this sector (Register Pair DE, 42F1H-42F8H) into Register A.
421E
CP (HL) BE
Compare Register A with the byte at the same place in the buffer (Register Pair HL, 4304H-430BH).
421F
If they differ, track 0, sector 1 of the diskette in drive 0 is not MicroDOS's: JUMP to 42A7H to display NO MICRODOS.
4222
INC DE 13
Point Register Pair DE to the next character of MICRODOS in this sector.
4223
INC HL 23
Point Register Pair HL to the next byte of the buffer.
4224
Decrement Register B, the characters left to compare, and LOOP BACK to 421DH until all eight have matched. Register Pair HL then holds 430CH, the byte after MICRODOS in the buffer.
4226H - Display the Sign-On Text and Load the Main File
The text after MICRODOS in the first sector is displayed, then the data bytes of the first sector and of each sector after it are copied to 4400H upward. A sector whose length byte is FFH (255 data bytes) means more sectors follow; a sector with any other length is the last one, and the boot jumps to 4400H. On this diskette the main file is 19 sectors, track 0 sectors 1-9 and track 1 sectors 0-9, the last with the length 12H: 18 x 255 + 18 = 4608 bytes, 4400H-55FFH.
4226
GOSUB to 42D4H to display the text at Register Pair HL (430CH in the buffer, which becomes 440BH of the main file) up to its 00H byte: A SIMPLE, POWERFUL DOS, WRITTEN BY JAMES W. STUTSMAN and FOR PERCOM DATA COMPANY, each followed by 0DH (new line), and one more 0DH for a blank line. The screen was cleared at 4205H, so the text starts at the top left corner.
4229
LD DE,4400H 11 00 44
Point Register Pair DE to 4400H, where the main file goes: the data bytes of each sector are copied there one after the other.
422C
LD B,00H 06 00
Load Register B with 00H, the high byte of the count of bytes to copy (a sector holds at most 255 data bytes). The loop comes back here after each further sector is read.
422E
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, byte 0 of the sector in the buffer: its length byte.
4231
LD C,(HL) 4E
Load Register C with the length byte at 4300H (Register Pair HL): FFH for every sector of the main file but the last, 12H for the last one. Register Pair BC is now the number of data bytes to copy (00FFH or 0012H). A length byte of 00H would make Register Pair BC 0000H and the copy run for 65536 bytes; no sector of the main file has one.
4232
LD A,(HL) 7E
Load Register A with the same length byte from 4300H (Register Pair HL), for the test at 4236H.
4233
INC HL 23
Point Register Pair HL to 4301H, the first data byte of the sector.
4234
LDIR ED B0
Copy Register Pair BC bytes from the buffer (Register Pair HL, from 4301H) to the main file's place (Register Pair DE). Register Pair DE ends one byte past the last byte copied, where the next sector's data bytes go; Register Pair BC ends 0000H.
4236
INC A 3C
Increment Register A, the length byte: FFH becomes 00H and sets the Z flag; any other length leaves NZ.
4237
If the sector just copied was not a full one (its length byte was not FFH), the whole main file is in memory: JUMP to 4400H, its first instruction, JP 4727H. On this diskette that happens after track 1, sector 9 (length 12H), with Register Pair DE = 5600H, one past the last byte loaded, Register A = 13H and the Stack Pointer still at 41FCH. The main file's copy of this sector has the same jump at 45CBH.
423A
LD HL,42DEH 21 DE 42
Point Register Pair HL to 42DEH, the sector number of the sector to read next.
423D
LD A,09H 3E 09
Load Register A with 09H, the highest sector number of a track (sectors 0-9).
423F
INC (HL) 34
Add 1 to the sector number at 42DEH (Register Pair HL): the sector after the one just copied.
4240
CP (HL) BE
Compare 09H in Register A with the new sector number at 42DEH (Register Pair HL): the Carry flag is set when the sector number has passed 9.
4241
If the sector number is 9 or less, it is on the same track: JUMP to 4247H to read it.
4243
LD (HL),00H 36 00
Otherwise the track is finished: set the sector number at 42DEH (Register Pair HL) to 00H.
4245
DEC HL 2B
Point Register Pair HL to 42DDH, the track number.
4246
INC (HL) 34
Add 1 to the track number at 42DDH (Register Pair HL): the next sector is sector 0 of the next track.
4247
GOSUB to 424CH to read the sector named by 42DDH (track) and 42DEH (sector) into the buffer 4300H-43FFH: on this diskette track 0 sectors 2-9, then track 1 sectors 0-9.
424A
LOOP BACK to 422CH to copy the data bytes of the sector just read.
424CH - Read One Sector
Reads the sector of drive 0 named by 42DDH (track) and 42DEH (sector) into the buffer 4300H-43FFH, taking each byte from the data register when the controller shows DATA REQUEST. It returns only after a read without error, with the alternate set holding 4300H, 37ECH and 37EFH again; an error goes to DISK ERROR at 42A2H and does not return. The main file's copy of this sector has the same routine at 45E0H.
424C
GOSUB to 4275H to select drive 0 (waiting for it when it was not ready), seek the head to the track at 42DDH and put the sector number at 42DEH in the sector register. 4275H comes back only when the seek had no error.
424F
LD A,88H 3E 88
Load Register A with 88H, the Read Sector command.
| 1771 FDC Command: 88H (10001000) | | Function Description |
| 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | | Command=Read Sector (bits 7-5 = 100) m = 0: one sector b = 1: IBM sector length E = 0: no head load delay |
4251
GOSUB to 42B9H to wait until the controller is not busy, write the command in Register A (88H) to 37ECH and wait until the controller shows BUSY.
4254
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: BC = 4300H (the buffer pointer), DE = 37ECH (the status register), HL = 37EFH (the data register).
4255
JUMP to 425DH to read the status for the first byte.
4257
AND 81H E6 81
No byte was waiting. Keep bit 7 (NOT READY) and bit 0 (BUSY) of the status in Register A.
4259
XOR 01H EE 01
Flip bit 0 of Register A: the result is 00H only while the controller is busy and the drive is ready.
425B
If the controller has finished (BUSY is off) or the drive is not ready, the read is over: JUMP to 4267H to check its status.
425D
LD A,(DE) 1A
Fetch the controller's status from 37ECH (Register Pair DE) into Register A.
425E
BIT 1,A CB 4F
Test bit 1 of Register A, DATA REQUEST: 1 when a byte of the sector is waiting in the data register.
4260
If no byte is waiting, JUMP to 4257H to see whether the read is still running.
4262
LD A,(HL) 7E
Fetch the byte from the data register 37EFH (Register Pair HL) into Register A.
4263
LD (BC),A 02
Store Register A in the buffer at Register Pair BC (4300H for the first byte of the sector).
4264
INC BC 03
Point Register Pair BC to the next byte of the buffer.
4265
LOOP BACK to 425DH to wait for the next byte of the sector; Register Pair BC points where it goes.
4267
LD A,(DE) 1A
Fetch the status after the read from 37ECH (Register Pair DE) into Register A.
4268
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = 37ECH, DE = 37EFH.
4269
LD (HL),D0H 36 D0
Write D0H to the command register 37ECH (Register Pair HL): Force Interrupt, which ends any command that is still running.
| 1771 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, no interrupt |
426B
EX DE,HL EB
Exchange Register Pairs DE and HL back: DE = 37ECH, HL = 37EFH.
426C
AND 9CH E6 9C
Keep the error bits of the status in Register A: bit 7 NOT READY, bit 4 RECORD NOT FOUND, bit 3 CRC ERROR and bit 2 LOST DATA.
426E
If any of them is set, JUMP to 42A2H to display DISK ERROR. The return addresses stay on the stack; that path ends with a reset of the computer.
4270
LD BC,4300H 01 00 43
Set Register Pair BC back to 4300H, the start of the buffer, for the next read.
4273
EXX D9
Exchange back to the main register set; the alternate set keeps 4300H, 37ECH and 37EFH.
4274
RET C9
RETURN to the caller with the sector in 4300H-43FFH.
4275H - Select Drive 0 and Seek the Track
Selects drive 0. If the drive was not ready before the select (its motor was off), waits about one second for the motor to come up to speed. Then puts the track from 42DDH in the data register and the sector from 42DEH in the sector register and gives the Seek command with verify. Returns when the seek had no error; with an error it falls into DISK ERROR at 42A2H.
4275
LD A,(37ECH) 3A EC 37
Fetch the controller's status from 37ECH into Register A, before drive 0 is selected again.
4278
RLCA 07
Rotate Register A left: bit 7 of the status, NOT READY, goes into the Carry flag.
4279
LD A,01H 3E 01
Load Register A with 01H, the select bit of drive 0.
| Drive Select Latch: 01H (00000001) | | Function Description |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | | Bits 0-3: one bit per drive drive 0 selected |
427B
LD (37E1H),A 32 E1 37
Store Register A (01H) to the drive select latch at 37E1H: drive 0 is selected and its motor runs.
427E
If the drive was ready (NOT READY was 0, Carry clear), JUMP to 428BH to seek.
4280
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H, the longest count of the ROM's delay.
4283
GOSUB to the ROM's delay at 0060H: with Register Pair BC = 0000H it loops 65536 times, about 0.96 second, so the drive motor comes up to speed. It returns with Register Pair BC = 0000H.
4286
LD A,01H 3E 01
Load Register A with 01H, the select bit of drive 0.
4288
LD (37E1H),A 32 E1 37
Store Register A (01H) to the drive select latch at 37E1H once more, so drive 0 stays selected with its motor running.
428B
LD A,(42DDH) 3A DD 42
Fetch the track to read from 42DDH into Register A (00H for track 0, 01H for track 1).
428E
LD (37EFH),A 32 EF 37
Store Register A in the data register 37EFH: the Seek command takes the track to go to from there.
4291
LD A,(42DEH) 3A DE 42
Fetch the sector to read from 42DEH into Register A.
4294
LD (37EEH),A 32 EE 37
Store Register A in the sector register 37EEH, for the Read Sector command that follows the seek.
4297
LD A,17H 3E 17
Load Register A with 17H, the Seek command with verify.
| 1771 FDC Command: 17H (00010111) | | Function Description |
| 0 | 0 | 0 | 1 | 0 | 1 | 1 | 1 | | Command=Seek (bits 7-4 = 0001) h = 0: no head load delay V = 1: verify the track ID r1 r0 = 11: 40 ms stepping rate |
4299
GOSUB to 42B9H to wait until the controller is not busy, write the Seek command in Register A (17H) to 37ECH and wait until the controller shows BUSY.
429C
GOSUB to 42C7H to wait until the seek is finished (BUSY off). Register A comes back with the status from 37ECH.
429F
AND 98H E6 98
Keep the error bits of the status after a seek in Register A: bit 7 NOT READY, bit 4 SEEK ERROR (no ID field of the track was found when verifying) and bit 3 CRC ERROR (an ID field read when verifying was bad).
42A1
RET Z C8
If none of them is set, RETURN to 424FH: the head is on the track. Otherwise fall through into 42A2H to display DISK ERROR.
42A2H - Disk Error and No MicroDOS
The two ways the boot can fail. A read or seek error displays DISK ERROR; a diskette without MICRODOS in track 0, sector 1 displays NO MICRODOS. Either way the screen is cleared, the text is displayed on the second line, and a key press resets the computer, which boots from drive 0 again.
42A2
LD HL,42DFH 21 DF 42
Point Register Pair HL to 42DFH, the DISK ERROR text. A seek error falls through to here from 42A1H; a read error jumps here from 426EH.
42A5
JUMP to 42AAH to display the DISK ERROR text at Register Pair HL (42DFH).
42A7
LD HL,42ECH 21 EC 42
The check at 421FH jumps here. Point Register Pair HL to 42ECH, the NO MICRODOS text.
42AA
GOSUB to the ROM's clear screen routine at 01C9H: cursor to the top left corner in 64 characters a line, and clear the screen. Register Pair HL keeps the address of the text.
42AD
GOSUB to 42D4H to display the text at Register Pair HL. Both texts start with 17H (32 characters a line) and E8H (40 spaces, two screen positions each in that mode), so the message starts on the second line of the screen, eight characters in.
42B0
GOSUB to the ROM's keyboard scan at 002BH: Register A comes back with the character of a key just pressed, or 00H when no key is pressed.
42B3
OR A B7
Test Register A, the character from the keyboard.
42B4
If Register A is 00H (no key was pressed), LOOP BACK to 42B0H to scan the keyboard again.
42B6
JUMP to 0000H, the ROM's reset: it boots from drive 0 again, so another diskette can be tried. With BREAK held down there, the ROM starts BASIC without the disk instead (its 068BH-0690H).
42B9H - Give the Controller a Command
Entered with the command in Register A (88H Read Sector from 4251H, 17H Seek from 4299H). Waits until the controller is not busy, writes the command and waits until the controller shows BUSY, so that the next status read belongs to the new command. The main file's copy of this sector has the same routine at 464DH.
42B9
PUSH AF F5
Save Register Pair AF on the stack: Register A holds the command (88H or 17H), which the wait at 42C7H would change.
42BA
GOSUB to 42C7H to wait until the controller is not busy.
42BD
POP AF F1
Restore Register Pair AF from the stack: Register A holds the command again (88H or 17H).
42BE
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: DE = 37ECH.
42BF
LD (DE),A 12
Write the command in Register A to the command register 37ECH (Register Pair DE).
42C0
LD A,(DE) 1A
Fetch the status from 37ECH (Register Pair DE) into Register A.
42C1
BIT 0,A CB 47
Test bit 0 of Register A (the status from 37ECH): BUSY, 1 while the controller works on a command.
42C3
LOOP BACK to 42C0H until BUSY is on: the controller has started the command.
42C5
EXX D9
EXX: exchange back to the main register set; the alternate set keeps 4300H, 37ECH and 37EFH.
42C6
RET C9
RETURN to the caller: the controller has started the command that is in Register A.
42C7H - Wait While the Controller Is Busy
Reads the status until BUSY is off, selecting drive 0 again on every pass so that its motor keeps running for as long as the command lasts. Returns the last status in Register A. The main file's copy of this sector has the same routine at 465BH.
42C7
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: DE = 37ECH.
42C8
LD A,01H 3E 01
Load Register A with 01H, the select bit of drive 0.
42CA
LD (37E1H),A 32 E1 37
Store Register A (01H) to the drive select latch at 37E1H on every pass: drive 0 stays selected and its motor keeps running.
42CD
LD A,(DE) 1A
Fetch the status from 37ECH (Register Pair DE) into Register A.
42CE
BIT 0,A CB 47
Test bit 0 of Register A (the status from 37ECH): BUSY, 1 while the controller works on a command.
42D0
LOOP BACK to 42C8H while the controller is busy.
42D2
EXX D9
EXX: exchange back to the main register set (the alternate set keeps 4300H, 37ECH and 37EFH). Register A keeps the last status, with BUSY off.
42D3
RET C9
RETURN to the caller with the status in Register A.
42D4H - Display a Text
Displays the text at Register Pair HL through the ROM, one character at a time, up to the 00H byte that ends it. Used for the sign-on text from the first sector (4226H) and for the two error texts (42ADH). The main file's copy of this sector has the same routine at 4668H.
42D4
LD A,(HL) 7E
Fetch the next character of the text at Register Pair HL into Register A.
42D5
OR A B7
Test Register A, the character just fetched: 00H ends the text.
42D6
RET Z C8
If it is 00H, RETURN to the caller, with Register Pair HL pointing at the 00H.
42D7
GOSUB to the ROM's display routine at 0033H to display the character in Register A at the cursor. Control codes act: 0DH starts a new line, 17H sets 32 characters a line, C0H-FFH display (code - C0H) spaces. The routine keeps Register Pair HL and leaves Register Pair DE holding 401DH, the display's control block.
42DA
INC HL 23
Point Register Pair HL to the next character of the text.
42DB
LOOP BACK to 42D4H for the next character of the text at Register Pair HL.
42DDH - Data: Track and Sector Numbers and Texts
The two variables of the load and the texts of the boot. The bytes up to 42FEH are the 254 data bytes the length byte at 4200H counts; 42FFH is the last byte of the sector.
42DD
DEFB 00H 00
The track of the sector to read: 00H as the sector is written, so the first read is on track 0. 4246H adds 1 when the sector number passes 9 (01H for track 1); 428BH puts it in the data register for the seek.
42DE
DEFB 01H 01
The sector to read: 01H as the sector is written, so the first read is track 0, sector 1, the first sector of the main file. 423FH adds 1 after each sector is copied and 4243H sets it to 00H at the start of a new track; 4291H puts it in the sector register.
42DF-42EB
DEFM 17H,E8H,"DISK ERROR",00H 17 E8 44 49 53 4B 20 45 52 52 4F 52 00
The DISK ERROR text, displayed by 42ADH after a read or seek error: 17H (32 characters a line), E8H (40 spaces), DISK ERROR, and the 00H that ends it.
42EC-42F0
DEFM 17H,E8H,"NO " 17 E8 4E 4F 20
The start of the NO MICRODOS text, displayed by 42ADH when track 0, sector 1 does not have MICRODOS: 17H (32 characters a line), E8H (40 spaces) and NO followed by a space. It has no 00H; the text runs on into MICRODOS at 42F1H.
42F1-42F9
DEFM "MICRODOS",00H 4D 49 43 52 4F 44 4F 53 00
The eight characters MICRODOS that the check at 421DH compares with bytes 4-11 of the first sector (4304H-430BH), and at the same time the end of the NO MICRODOS text from 42ECH, ended by the 00H at 42F9H.
42FA-42FE
DEFM "$STEP" 24 53 54 45 50
Five bytes that no code reads, the last of the 254 data bytes. The main file's copy of this sector has the same five bytes at 468EH-4692H.
42FF
DEFB 48H 48
The last byte of the sector, H. It is not one of the 254 data bytes the length byte FEH at 4200H counts, and nothing reads it. The main file's copy of this sector has 4CH (L) at 4693H.