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
4200H
NOP
No Operation (Do Nothing).
4201H
FEH + 11H
DOS slang for: [FE] – Recognize this as a DOS disk and [11H] Directory track is on track 11H (Decimal: 17).
4203H
DI
Disable Interrupts.
4204H
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.
4207H
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.
4209H
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.
420BH
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).
420CH
LD (HL),00H
Store the value 00H into memory location 37EDH (aka Port F1H) to set to TRACK 0.
420EH
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).
420FH
LD (HL),00H
Store the value 00H into memory location 37EEH (aka Port F2H) to set to SECTOR 0.
4211H
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.
4214H
EXX
EXchanges the 16-bit contents of BC, DE, and HL with BC’, DE’, and HL’. Note: AF is not handled via EXX.
4215H
LD SP,41E0H
Move the Stack Pointer to 41E0H.
4218H
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.
421BH
GOSUB to 4252H to bump to the next byte of the RAM BUFFER and then fetch the byte into Register A.
421EH
CP 20H
Compare the byte read from disk (held in Register A) against 20H. If the byte was GREATER THAN 1FH the NC Flag would be set to signify an error.
4220H
LD B,A
Save the byte (held in Register A) in Register B which will act as a countdown for the DJNZ loop at 422CH.
4221H
If the byte was GREATER THAN 1FH 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.
4223H
LD D,A
If we didn’t jump away then we might still have a DOS! First, save the byte read into Register D.
4224H
GOSUB to 4252H to bump to the next byte of the RAM BUFFER and then fetch the byte into Register A.
4227H
LD C,A
Save the byte (held in Register A), which should be the number of bytes, in Register C.
4228H
GOSUB to 4252H to bump to the next byte of the RAM BUFFER and then fetch the byte into Register A.
422BH
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.
422CH
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.
422EH
GOSUB to 4252H to bump to the next byte of the RAM BUFFER and then fetch the byte into Register A.
4231H
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.
4233H
DEC C
DECrement the value stored in Register C by 2 since the address was 2 bytes.
4234H
INC L
INCrement the BUFFER POINTER (held in HL) by 1.
4235H
If the BUFFER POINTER has just rolled over, then GOSUB to 4255H to read another sector into the RAM BUFFER.
4238H
LD A,(HL)
Fetch the value held in the BUFFER (pointed to by Register Pair HL) and store it into Register A.
4239H
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).
423AH
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.
423BH
DEC C
DECrement the remaining number of bytes to read counter (stored in Register C) by 1.
423CH
If there are still bytes to read (meaning Register C did not yet hit 0), JUMP to 4234H.
423EH
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.

4240H
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.
4242H
GOSUB to 4252H to bump to the next byte of the RAM BUFFER and then fetch the byte into Register A.
4245H
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.
4246H
LD A,(DE)
Fetch the value held in the memory location pointed to by Register Pair DE and store it into Register A.
4247H
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.
4249H
INC DE
INCrement the value stored in Register Pair DE by 1 to skip past the A5H.
424AH
PUSH DE
Save the contents of Register Pair DE to the top of the stack.
424BH
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.

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

4252H – Fetch a byte from the RAM BUFFER.

4252H
INC L
INCrement the BUFFER POINTER (held in HL) by 1. On the very first run, this turns L to 00H which will permit a pass through at 4254H to load the first sector (and not RETurn).
4253H
LD A,(HL)
Fetch the value held in the RAM Buffer (pointed to by Register Pair HL) and store it into Register A.
4254H
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

4255H
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.
4256H
LD B,0AH
Let Register B equal 0AH (Decimal: 10) for a retry count of 10 times.
4258H
LD HL,37E1H
Let Register Pair HL equal 37E1H, which is the DISK DRIVE SELECT LATCH ADDRESS.
425BH
LD (HL),01H
Store the value 01H into the drive select latch, which sets to DRIVE :0.
425DH
PUSH DE
Save the contents of Register Pair DE (i.e., the track and sector) to the top of the stack.
425EH
PUSH BC
Save the contents of Register Pair BC (i.e., the retry count) to the top of the stack.
425FH
LD A,E
Copy the contents of Register E (i.e., the sector) into Register A.
4260H
SUB 0AH
SUBtract the value 0AH (Decimal: 10) from Register A. If Register A was greater than 10, the CARRY FLAG will trip.
4262H
If the Carry Flag is set, then the sector number is too high! JUMP to 4267H.
4264H
LD E,A
Copy the SUBTRACTED FROM 10 contents of Register A into Register E.
4265H
LD (HL),09H
Store the value 09H (Binary:0000 1001) into the drive select latch, which turns on all drive lights.
4267H
LD HL,37ECH
Let Register Pair HL equal 37ECH, which is the RAM location for the Floppy Disk Controller.
426AH
GOSUB to 42CEH to wait until the Floppy Disk Controller signals READY.
426DH
LD (37EEH),DE
Store the value held in Register Pair DE into the FLOPPY DRIVE CONTROLLER SECTOR SELECT Register (i.e., 37EEH).
4271H
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)
4273H
GOSUB to 42CEH to wait until the Floppy Disk Controller signals READY.
4276H
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).
4278H
LD DE,37EFH
Let Register Pair DE equal 37EFH (aka Port F3H) to point to the Floppy Disk Controller DATA Register.
427BH
LD BC,5100H
Let Register Pair BC equal 5100H to be a RAM BUFFER to hold the sector data.
427EH
GOSUB to 42D7H for a very short delay.
4281H
LD A,(HL)
Fetch the value from the Floppy Disk Controller Status Register and put the result into Register A.
4282H
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.
4284H
If the PARITY/OVERFLOW FLAG has been RESET, LOOP back to 4281H and keep polling.
4287H
LD A,(DE)
Fetch a byte from the Floppy Disk Controller Data Register and store it into Register A.
4288H
LD (BC),A
Store the byte (now held in Register A) into the RAM BUFFER (pointed to by Register Pair BC).
4289H
INC BC
INCrement the RAM BUFFER pointer (stored in Register Pair BC) by 1.
428AH
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).
428CH
If the index mark was found, JUMP to 4287H.
428FH
BIT 1,(HL)
Check for the index mark a second time … Z=Not Found, NZ=Found.
4291H
If the index mark was found, JUMP to 4287H.
4294H
BIT 1,(HL)
Check for the index mark a THIRD time … Z=Not Found, NZ=Found.
4296H
If the index mark was found, JUMP to 4287H.
4298H
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).
429AH
If the drive is BUSY, JUMP to 42A4H.
429CH
BIT 1,(HL)
Check for the index mark again … Z=Not Found, NZ=Found.
429EH
If the index mark was found, JUMP to 4287H.
42A0H
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).
42A2H
If drive is READY, JUMP to 428AH.
42A4H
LD A,(HL)
Fetch the status from the Floppy Drive Controller Status Register and store it into Register A.
42A5H
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.
42A7H
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.
42A8H
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.
42A9H
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.
42ABH
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.
42ADH
INC E
INCrement the sector number (stored in Register E) by 1.
42AEH
LD A,E
Copy the new sector number (held in Register E) into Register A.
42AFH
SUB 0AH
SUBtract the value 0AH (Decimal: 10) from Register A. If Register A was less than 10, the NZ FLAG will be set.
42B1H
If the NZ FLAG (Not Zero) has been set, JUMP to 42B6H to skip over incrementing the track.
42B3H
INC D
INCrement the track (stored in Register D) by 1.
42B4H
LD E,00H
Let Register E equal 00H to reset to Sector 0 on that new track.
42B6H
EXX
EXchanges the 16-bit contents of BC, DE, and HL with BC’, DE’, and HL’. Note: AF is not handled via EXX.
42B7H
LD A,(HL)
Fetch the value held in the RAM BUFFER pointed to by Register Pair HL and store it into Register A.
42B8H
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.

42B9H
GOSUB to 42D7H for a VERY short delay to wait for the Floppy Disk Controller to be ready.
42BCH
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
42BEH
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.
42C0H
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.

42C3H
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.
42C4H
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.
42C6H
If we are at the End-of-Message, LOOP back to 42C3H to freeze the system.
42C8H
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.
42C9H
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.
42CCH
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.

42CEH
GOSUB to 42D7H for a VERY short delay to wait for the Floppy Disk Controller to be ready.
42D1H
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).
42D3H
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.
42D5H
LD A,(HL)
Fetch the value held in the memory location pointed to by Register Pair HL and store it into Register A.
42D6H
RET
RETurn to the caller.

42D7H – Subroutine with a VERY short delay.

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

42DDH – MESSAGE STORAGE TABLE.

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