TRS-80 DOS – NEWDOS/80 v2.0 for the Model I – BOOT/SYS Disassembled

General:

This boot module is basically two main routine, and Cliff Ide treated them as such by use of the EXX register swap. One routine uses HL to point to the Floppy Disk Controller memory locations and DE to point to the track and sector being worked on. The other routine uses HL to point to a RAM buffer which contains the sector data. In fact, Cliff uses the PUSH command only 3 times in this entire boot routine!

Another thing done here, more out of necessity than anything else, is to use the Model I RAM location for the Floppy Disk Controller access. The Model I didn’t have ports so it couldn’t be any other way (thanks to Eric Dittman for pointing this out), but it remains that by doing it this way only 1 opcode is needed to test and manipulate the controller, instead of 2.

These two things are a HUGE time saver.


Disassembly:

 
ORG 4200H
4200
NOP
No Operation (Do Nothing).
4201
CP 11H
DOS slang for pointing out that the directory track is on track 11H (Decimal: 17).
4203
DI
Disable Interrupts.
4204
LD HL,37ECH
Let Register Pair HL equal 37ECH, which is the RAM location for the Floppy Disk Controller Status/Command Register and mirrors Port F0H.
4207
LD (HL),0FEH
Store the value 0FEH (Binary: 1111 1110) into the FDC. On its own, this would be an invalid command to send to the stock FDC. HOWEVER, as Blair Robbins has pointed out, this is a perfectly valid command to a Percom Doubler, and it sets the doubler to use the 1771 single density chip instead of the 1791 double density chip.
4209
LD (HL),0D0H
Store the value 0D0H (Binary: 1101 0000) into the memory location pointed to by Register Pair HL, which resets the Floppy Disk Controller and puts it into INTRQ mode for NOT READY to READY transition.
420B
INC HL
INCrement the value stored in Register Pair HL by 1 to now point to 37EDH, which is the memory location of the Floppy Disk Controller TRACK REGISTER (which would be Port F1H if they were using ports).
420C
LD (HL),00H
Store the value 00H into memory location 37EDH (aka Port F1H) to set to TRACK 0.
420E
INC HL
INCrement the value stored in Register Pair HL by 1 to now point to 37EEH, which is the memory location of the Floppy Disk Controller SECTOR REGISTER (which would be Port F2H if they were using ports).
420F
LD (HL),00H
Store the value 00H into memory location 37EEH (aka Port F2H) to set to SECTOR 0.
4211
LD DE,0005H
Let Register Pair DE equal 0005H in preparation of pointing to Track 0, Sector 5, which is the location of SYS0/SYS.
4214
EXX
EXchanges the 16-bit contents of BC, DE, and HL with BC’, DE’, and HL’. Note: AF is not handled via EXX.
4215
LD SP,41E0H
Move the Stack Pointer to 41E0H.
4218
LD HL,51FFH
Let Register Pair HL equal 51FFH as a sector buffer in RAM from 5200H-52FFH. It had to be set 1 lower because the common 4252H fetch routine increments Register L as its first instruction.
421B
GOSUB to 4252H to bump to the next byte of the RAM BUFFER and then fetch the byte into Register A.
421E
CP 20H
Compare the byte read from disk (held in Register A) against 20H. If the byte was GREATER THAN 20H the NC Flag would be set.
4220
LD B,A
Save the byte (held in Register A) in Register B.
4221
If the byte was GREATER THAN 20H then we know already that there is no DOS present, so JUMP to 424CH to display the “NO SYS” error message and freeze the system.
4223
LD D,A
If we didn’t jump away then we might still have a DOS! First, save the byte read into Register D.
4224
GOSUB to 4252H to bump to the next byte of the RAM BUFFER and then fetch the byte into Register A.
4227
LD C,A
Save the byte (held in Register A), which should be the number of bytes, in Register C.
4228
GOSUB to 4252H to bump to the next byte of the RAM BUFFER and then fetch the byte into Register A.
422B
LD E,A
Save the byte (held in Register A), which should be the MSB of the starting RAM location to load the code from DISK, in Register E.
422C
JUMP to 4240H, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.
422E
GOSUB to 4252H to bump to the next byte of the RAM BUFFER and then fetch the byte into Register A.
4231
LD D,A
Save the byte (held in Register A), which should be the MSB of the starting RAM location to load the code from DISK, in Register D.
4232
4233
DEC C
DEC C
DECrement the value stored in Register C by 2 since the address was 2 bytes.
4234
INC L
INCrement the BUFFER POINTER (held in HL) by 1.
4235
If the BUFFER POINTER has just rolled over, then GOSUB to 4255H to read another sector into the RAM BUFFER.
4238
LD A,(HL)
Fetch the value held in the BUFFER (pointed to by Register Pair HL) and store it into Register A.
4239
LD (DE),A
Store that value into the memory location pointed to by Register Pair DE (which is the location in RAM for that code to be placed as set in DE from disk).
423A
INC DE
INCrement the memory location pointed to by Register Pair DE (i.e., the memory location to put the bytes from diskette) by 1.
423B
DEC C
DECrement the remaining number of bytes to read counter (stored in Register C) by 1.
423C
If there are still bytes to read (meaning Register C did not yet hit 0), JUMP to 4234H.
423E
If we read all the bytes we needed to read (and C is now 0), JUMP to 421BH.

4240H – Jump Point if the Byte was a 20H.

4240
LOOP back to 423BH, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.
4242
GOSUB to 4252H to bump to the next byte of the RAM BUFFER and then fetch the byte into Register A.
4245
LD D,A
Copy the byte just read (held in Register A), which should be the MSB of the entry point, into Register D so that DE now contains the entry point.
4246
LD A,(DE)
Fetch the value held in the memory location pointed to by Register Pair DE and store it into Register A.
4247
CP 0A5H
Compare the value held in Register A against A5H to see if SYS0/SYS is being read. If the byte matches and we are actually at SYS0/SYS, then the Z FLAG will be set.
4249
INC DE
INCrement the value stored in Register Pair DE by 1 to skip past the A5H.
424A
PUSH DE
Save the contents of Register Pair DE to the top of the stack.
424B
RET Z
If the Z FLAG (Zero) has been set, then we are at SYS0/SYS, so RETurn. If we did not find SYS0/SYS then …

424CH – Display the “NO SYS” Error Message.

424C
LD HL,42E5H
Let Register Pair HL equal 42E5H to as to point to the “NO SYS” message.
424F
JUMP to 42C3H to display the “NO SYS” message and then hang the system.

4252H – Fetch a byte from the RAM BUFFER.

4252
INC L
INCrement the BUFFER POINTER (held in HL) by 1.
4253
LD A,(HL)
Fetch the value held in the RAM Buffer (pointed to by Register Pair HL) and store it into Register A.
4254
RET NZ
If the NZ FLAG (Not Zero) has been set, RETurn to the caller.

4255H – Routine to read a whole sector into the RAM Buffer

4255
EXX
EXchanges the 16-bit contents of BC, DE, and HL with BC’, DE’, and HL’. Among other things, this puts DE back to point to a TRACK and SECTOR, and HL back to pointing to the Floppy Disk Controller DATA BYTE.Note: AF is not handled via EXX.
4256
LD B,0AH
Let Register B equal 0AH (Decimal: 10) for a retry count of 10 times.
4258
LD HL,37E1H
Let Register Pair HL equal 37E1H, which is the DISK DRIVE SELECT LATCH ADDRESS.
425B
LD (HL),01H
Store the value 01H into the drive select latch, which sets to DRIVE :0.
425D
PUSH DE
Save the contents of Register Pair DE (i.e., the track and sector) to the top of the stack.
425E
PUSH BC
Save the contents of Register Pair BC (i.e., the retry count) to the top of the stack.
425F
LD A,E
Copy the contents of Register E (i.e., the sector) into Register A.
4260
SUB 0AH
SUBtract the value 0AH (Decimal: 10) from Register A. If Register A was greater than 10, the CARRY FLAG will trip.
4262
If the Carry Flag is set, then the sector number is too high! JUMP to 4267H.
4264
LD E,A
Copy the SUBTRACTED FROM 10 contents of Register A into Register E.
4265
LD (HL),09H
Store the value 09H (Binary:0000 1001) into the drive select latch, which turns on all drive lights.
4267
LD HL,37ECH
Let Register Pair HL equal 37ECH, which is the RAM location for the Floppy Disk Controller.
426A
GOSUB to 42CEH to wait until the Floppy Disk Controller signals READY.
426D
LD (37EEH),DE
Store the value held in Register Pair DE into the FLOPPY DRIVE CONTROLLER SECTOR SELECT Register (i.e., 37EEH).
4271
LD (HL),1BH
Store the value 1BH (Binary:0001 1011) into the Floppy Drive Controller. This is the command to SEEK (0001), Load Head at Beginning (1), No Verify (0), 30ms Stepping Rate (11)
4273
GOSUB to 42CEH to wait until the Floppy Disk Controller signals READY.
4276
LD (HL),88H
Store the value 88H (Binary: 1000 1000) into the Floppy Drive Controller. This is the command to READ (100), Single Record (0), Compare for Side 1 (1), No 15ms Delay (0), Disable Side Compare (00).
4278
LD DE,37EFH
Let Register Pair DE equal 37EFH (aka Port F3H) to point to the Floppy Disk Controller DATA Register.
427B
LD BC,5100H
Let Register Pair BC equal 5100H to be a RAM BUFFER to hold the sector data.
427E
GOSUB to 42D7H for a very short delay.
4281
LD A,(HL)
Fetch the value from the Floppy Disk Controller Status Register and put the result into Register A.
4282
AND 83H
MASK the value of Register A against 83H (1000 0011). This has the effect of leaving only bits 7 (1=NOT READY), 1 (1=Index Found), and 0 (1=Busy/Command in Progress) active.
4284
If the PARITY/OVERFLOW FLAG has been RESET, LOOP back to 4281H and keep polling.
4287
LD A,(DE)
Fetch a byte from the Floppy Disk Controller Data Register and store it into Register A.
4288
LD (BC),A
Store the byte (now held in Register A) into the RAM BUFFER (pointed to by Register Pair BC).
4289
INC BC
INCrement the RAM BUFFER pointer (stored in Register Pair BC) by 1.
428A
BIT 1,(HL)
Test Bit Number 1 of the Floppy Disk Controller Status Register. Z FLAG will be set if that bit is 0 (meaning NO index mark), and NZ FLAG will be set if that bit is 1 (meaning, index mark found).
428C
If the index mark was found, JUMP to 4287H.
428F
BIT 1,(HL)
Check for the index mark a second time … Z=Not Found, NZ=Found.
4291
If the index mark was found, JUMP to 4287H.
4294
BIT 1,(HL)
Check for the index mark a THIRD time … Z=Not Found, NZ=Found.
4296
If the index mark was found, JUMP to 4287H.
4298
BIT 0,(HL)
So far, we have failed to find an index mark 3 times. Next, test Bit 0 of the Floppy Disk Controller Status Register. Z FLAG will be set if that bit is 0 (meaning NOT busy), and NZ FLAG will be set if that bit is 1 (meaning, BUSY).
429A
If the drive is BUSY, JUMP to 42A4H.
429C
BIT 1,(HL)
Check for the index mark again … Z=Not Found, NZ=Found.
429E
If the index mark was found, JUMP to 4287H.
42A0
BIT 7,(HL)
Test Bit Number 7 of the Floppy Disk Controller Status Register. Z FLAG will be set if that bit is 0 (READY), and NZ FLAG will be set if that bit is 1 (NOT READY).
42A2
If drive is READY, JUMP to 428AH.
42A4
LD A,(HL)
Fetch the status from the Floppy Drive Controller Status Register and store it into Register A.
42A5
LD (HL),0D0H
Store the value 0D0H (Binary: 1101 0000) into the Floppy Drive Controller Command Register, which resets the Floppy Disk Controller and puts it into INTRQ mode for NOT READY to READY transition.
42A7
POP BC
Put the value held at the top of the STACK (i.e., the retry count) into Register Pair BC, and then remove the entry from the stack.
42A8
POP DE
Put the value held at the top of the STACK (i.e., the track and sector) into Register Pair DE, and then remove the entry from the stack.
42A9
AND 0FCH
MASK the value of Register A (i.e., the status from the Floppy Disk Controller; read at 42A4H) against 0FCH (1111 1100). This has the effect of turning off bits 1 and 0. With that NZ will only be set if the following is true: The head is positioned to Track 0, there is a CRC error, there is a Seek error, the head is loaded, write protect is actived, or the drive is not ready.
42AB
If any of that stuff is true then that’s a bad thing … JUMP to 42B9H to wait for the Floppy Drive Controller to be ready, send a RESET to the FDC, and continue a countdown of retries; failing to DISK ERROR if the retry count expires.
42AD
INC E
INCrement the sector number (stored in Register E) by 1.
42AE
LD A,E
Copy the new sector number (held in Register E) into Register A.
42AF
SUB 0AH
SUBtract the value 0AH (Decimal: 10) from Register A. If Register A was less than 10, the NZ FLAG will be set.
42B1
If the NZ FLAG (Not Zero) has been set, JUMP to 42B6H to skip over incrementing the track.
42B3
INC D
INCrement the track (stored in Register D) by 1.
42B4
LD E,00H
Let Register E equal 00H to reset to Sector 0 on that new track.
42B6
EXX
EXchanges the 16-bit contents of BC, DE, and HL with BC’, DE’, and HL’. Note: AF is not handled via EXX.
42B7
LD A,(HL)
Fetch the value held in the RAM BUFFER pointed to by Register Pair HL and store it into Register A.
42B8
RET
RETurn to the caller.

42B9H – Wait for the Floppy Drive Controller to be ready, Send a RESET to the FDC, and continue a countdown of retries; failing to DISK ERROR if the retry count expires.

42B9
GOSUB to 42D7H for a VERY short delay to wait for the Floppy Disk Controller to be ready.
42BC
LD (HL),0BH
Store the value 0BH (Binary: 0000 1011) into the Floppy Disk Controller Command Register, which sends the command:
  • 0000 = RESTORE
  • 1 = LOAD HEAD AT BEGINNING
  • 0 = NO VERIFY
  • 11 = 30ms STEPPING RATE
42BE
LOOP back to 4258H, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.
42C0
LD HL,42DDH
If we fall through then we have an error, so let Register Pair HL equal 42DDH to point to the message “DISK ERROR”.

42C3H – Display a Message (Pointed to by HL) and hang the system.

42C3
LD A,(HL)
Fetch the value held in the memory location pointed to by Register Pair HL (which should be pointing to a message) and store it into Register A.
42C4
CP 03H
Compare the value held in Register A against 03H, which is a standard End-of-Message delimeter. If Register A equals 03H/3, the Z FLAG is set; otherwise the NZ FLAG is set.
42C6
If we are at the End-of-Message, LOOP back to 42C3H to freeze the system.
42C8
INC HL
If we are NOT at the End-of-Message, INCrement the value stored in Register Pair HL by 1 to point to the next character in the message to display.
42C9
GOSUB to 0033H.
NOTE: 0033H is the Model III ROM character print routine; displays the character held in Register A at the current cursor position.
42CC
LOOP back to the top of this routine (i.e., 42C3H) to either keep displaying message letters or be in an endless loop.

42CEH – Wait until the Floppy Disk Controller signals READY.

42CE
GOSUB to 42D7H for a VERY short delay to wait for the Floppy Disk Controller to be ready.
42D1
BIT 0,(HL)
Test Bit Number 0 of the Floppy Disk Controller Status. Bit 0 is the BUSY bit. Z FLAG will be set if that bit is 0, and NZ FLAG will be set if the Floppy Disk Controller reported that a command is in progress (=1).
42D3
If a command is in progress (and the NZ FLAG has been set as a result), JUMP BACK one instruction to 42D1H and test again.
42D5
LD A,(HL)
Fetch the value held in the memory location pointed to by Register Pair HL and store it into Register A.
42D6
RET
RETurn to the caller.

42D7H – Subroutine with a VERY short delay.

42D7
LD A,06H
Let Register A equal 06H for a very short delay.
42D9
DEC A
DECrement the value stored in Register A by 1.
42DA
If the NZ FLAG (Not Zero) has been set, LOOP BACK to the prior instruction.
42DC
RET
RETurn to the caller.

42DDH – MESSAGE STORAGE TABLE.

42DD
DEFM …
1C + 1F + “ERROR” + 03H
42E5
DEFM …
1C + 1F + “NO SYS” + 03H
 
END 4200H
That’s it!