Model I TRSDOS v2.3 SYS0/SYS Explained
This is a disassembly of TRSDOS v2.3’s SYS0/SYS file. SYS0/SYS resides from 4300-4D00H
TRSDOS does quite a bit of sector work by using a buffer and then writing out the buffer when done. The buffer is usually set up being pointed to by the IX register, as that is 1 of 2 registers upon which math can be done. In the case of the buffered sector:
- IX+00H = special DCB code area
- IX+01H = special codes. Lowest 3 bits are the permission flags. Bit 4 signals that the buffer has been updated / is available for use. Bit 5 forces a read on the next file access. Bit 6 signifies the need for a POSITION call. Bit 7 specifies physical or logical I/O.
- IX+02H = Reserved / Not Used
- IX+03H = the LSB of the DCB Sector Buffer Address
- IX+04H = the MSB of the DCB Sector Buffer Address
- IX+05H = the next record address -OR – current byte offset in sector buffer to the current record
- IX+06H = the drive number
- IX+07H = the DIRECTORY SECTOR OFFSET (i.e., directory sector number with the HIT Index) or the OVERFLOW pointer
- IX+08H = EOF offset held in the DCB
- IX+09H = record size in bytes
- IX+0AH = the LSB of the next sector number
- IX+0BH = the MSB of the next sector number
- IX+0CH = the LSB of the EOF sector held in the DCB -or- The number of records
- IX+0DH = the MSB of the EOF sector held in the DCB -or- The number of records
- IX+0EH = the track number of the lst GAP
- IX+0FH = Granule count
The reason the below starts at 400C is that the ROM itself fills 4000H, 4003H, 4006H, and 4009H with JUMPs, but puts RETs at 400C and 400F, and an EI at 4012H.
Local Storage Area
Interrupt task list
System Sector Buffer
Track History Table
Directory Track List Table
Unit Flags and Addresses
DEBUG related
-43BF
4398H – Routine to wait for Disk Controller to Become NOT Busy
43C0H – Storage Locations
Overlay Call Vectors
System Function Vectors
RST 38H
RST 38H
RST 38H
RST 38H
4473H – Routine Process Overlay Load Requests
4480H – System DCB – 32 Bytes
44A0H – System DCB – 16 Bytes
44B0H – Vector to Overlay to call SYS4/SYS to Load Error Messages
44B4H – Vector to Load DEBUG
44B8H – Enter Driver. This is called From LEVEL II ROM
44CFH – Vector to Send a Message to the Video Display
44DFH – Vector to SEND MESSAGE TO PRINTER
4500H – Interrupt Task List Address
The subroutine at 4560H executes the task (based on the interrupt processor) and 4040H holds the counter used to select the next task.
4518H – Interrupt Service Routine. This is entered for all maskable interrupts.
4538H – Call Interrupt Task Routine Associated With On List
4547H – Return Point for Interrupt Task Routines
454FH – This subroutine is jumped to with we have a BREAK to exit. We need to see if DEBUG is active and needs to be loaded or not.
4560H – Clock Interrupt Routine
Now we are going to locate the task address and execute the task
Load the address for the FIRST level of indirection into DE
Load the address for the SECOND level of indirection into DE
458E – Routine to replace the address for the first pointer in the INTERRUPT TABLE with the contents held in Register Pair DE
4593H – Vector to Remove an address from the Interrupt Task List
4596H – Vector to Add an address to the Interrupt Task List
459F
45A0
INC L
LD (HL),D
45A3 – This is default interrupt task list jump location
45AFH – Routine to maintain the clock. This routine gets called if CLOCK (ON)
45C3H – Continuing on the theme of incrementing periods if a lower period has overflowed (i.e., hours has flowed into an increased date)
Maximum value table for Periods
4600H – Select Drive Specified in C-Register
4634
OR L
Construct Unit Select Mask for Value in A-Register
463C
463D
RLCA
RLCA
Select Drive and Issue Seek if not on Track
4661H – Send the Command in Register A to the Floppy Disk Controller. The routine returns when the command is processed.
4665
4666
4667
4668
POP AF
NOP
NOP
NOP
4671H – Disk Driver. When this routine is called, A has the OPCODE for the controller, C has the drive unit, and DE has the track/sector
The operation is complete so check the status and test for errors
46C3
LD (4308H),A
If the rotating bits finally puts a “1” into the Carry, then we sent here from 46D6H
46DD – This is the read Subroutine used for Calling Disk Driver. Driver Returns to Caller of Read Subroutine
46E6 – This is the write subroutine used for Calling Disk Driver. Driver Returns to Caller of Write Subroutine
46EF – This is the write subroutine used for Calling Disk Driver. Driver Returns to Caller of Write Subroutine
46F3 – This is the read Subroutine used for Calling Disk Driver. Driver Returns to Caller of Read Subroutine
4700H – This is the POSITION Vector Routine – Position File to Specified Record Number
POSN positions a file to read or write a randomly selected logical record. Since it deals with logical records, the proper computation is clone to locate which physical record(s) contain the data. Following a POSN with a READ or WRITE will transfer the record to/from RAM.
Note that positioning to logical record zero sets the file to read the first logical record in the file. To position to end of file in order to add new records onto the end, use the record number ERN+ 1 (see page 2).
On Entry: DE=DCB (must have been opened previously), BC=Logical record number to position for, CALL 4442H
On Exit: Z=OK, A=TRSDOS error code
470E
LD L,C
4716
LD C,L
4723
LD (IX+0BH),B
4737H – This is the BACKSPACE Vector – Backspace Operation
473D
LD B,(IX+0BH)
doing physical or logical I/O
4756H – THIS IS THE REWIND ROUTINE- Jumped from the Vector – Use POSN Code to Position to Record 0
475FH – This is the SKIP TO EOF Vector – Skip to EOF
4765
LD B,(IX+0DH)
476D – Read Processing – This is where the READ VECTOR jumps to
If LRL>0, READ transfers the logical record whose number is in the DCB as NRN (see page 2) into the RAM area addressed as UREC for the length LRL as defined at open time. The record comes from the RAM BUFFER defined at open time. If TRSDOS must read a new physical record to satisfy the request, it will do so. “Spanned” logical records will be re-assembled as necessary. READ automatically increments NRN by one in the DCB after the transfer is completed. INIT/OPEN sets NRN=X’0000′ in order to read the first record with the first READ.
If LRL=0, READ transfers one physical record into the RAM BUFFER, which was defined at open time, from the disk file. Registers HL are ignored. READ increments NRN as above.
On Entry: HL=UREC if LRL is not zero. Unused if LRL=0, DE=DCB, CALL 44364
On Exit: Z=OK, A=TRSDOS error code.
477BH – This is the LOGICAL READ routine. It transfers a record from the sector buffer to the user’s record area, byte by byte. The subroutine at 47BBH returns the next byte from the sector buffer. If the buffer is exhaused, the next sector will be read.
478BH – This is the beginning of WRITE Processing – WRITE VECTOR JUMPS HERE.
If we are here, then we are doing LOGICAL I/O instead of PHYSICAL I/O. This routine will transfer a record from the user’s record area to the file sector buffer byte by byte. The subroutine at 47DAH stores the next byte in the sector buffer. If the buffer is full, it is written to disk.
47A8H – This is the VERIFY routine called from the Vectors
The only difference between VERF and WRITE is that VERF writes one physical record to disk and then reads it back into a special TRSDOS RAM area not defined bv the user. This special area and the original write buffer are then compared byte by byte to assure that tbe record was successfully written.
On Entry: HL=UREC if LRL is not zero. Unused if LR L= 0, DE=> DCB, CALL 443CH
On Exit: Z=OK, A=TRSDOS error code
47AEH – General Purpose Driver Entry —Called From Driver Entry at 44BB
If we are here, then we are doing a READ operation
If we are here, then we are doing a WRITE operation
This is the JUMP point if there was no error reading a new sector into the buffer.
This routine reads the next sector from the file into the buffer. It is called from a few places. This first part tests to see if there is protection that would otherwise stop us from doing the read.
This routine reads the next sector from the file into the buffer. It is called from a few places.
This routine continues the WRITE routine. It where the routine jumps when a PHYSICAL I/O is set.
This routine purges the sector buffer
This routine gets the address of the next record in the sector buffer pointed to by DE and computes the address for the next byte to be stored/fetched in current logical record
4892H – Save the Registers
48B3H – Restore Context After I/O Operation
48B9H – Test for EOF. This routine returns A with: 0=NOT EOF, 1C=EOF, 1D=Beyond EOF
48DCH – Locate the GAP for the Current Record Number
4900
LD L,E
We are here if the relative granule number is greater than the sum of the granules allocated.
If the difference is less than 256, compare it to the number of granules assigned to the current GAP because the relative granule may fall within the next GAP.
If we are here, then the elative granule is not in the current GAP so we need to search directory entries belonging to the file for a GAP containing the relative granule number being sought.
492E
LD L,C
Search the DCB for the GAP matching the number returned From 49B5H. When this routine finishes, HL will hold the track and granule count owning the relative granule. DE will hold the cumulative granule count addressable through this track.
4951
4952
INC HL
Move GAP’s in DCB down one entry
496AH – This routine converts the granule number and GAP into an absolute track/sector number
4979
RLCA
4995
4996
RLCA
RLCA
49A7
49A8
RLCA
ADD A,E
49B5H – Finds the GAP for Relative Granule number held in BC by searching the directory entries belonging to a file. If there are overflow entries, read them as well. On Entry: BC=Granule Number. On Exit: L=Track, H=Count of Granules assigned to the track, and DE=cumulative number of granules thru this GAP.
If we are here, the requested granule exists in the GAP range we just found
Jumped to by 49D0H if we had either an end of extents or overflow was found.
4A00H – Granule Assignment Routine.
On entry: BC = requested granule number (target granule), DE = Number of granules presently assigned, and HL = Address of file entry in directory sector.
4A13
LD C,L
The next bit of math is to isolate and then calculate the advanced starting position in the GAT
4A2B
DEC E
4A39
4A3A
RLCA
RLCA
INC E
This routine calls on SYS2/SYS to build an overlow entry.
This routine assigns the granule for a new GAP
This routine makes the initial GAP Byte 2 Assignment the granule for a new GAP
4AB1
OR C
4AC1H – READ the Directory Entry for Directory Sector in B
4AD6H – WRITE the Directory Entry for Directory Sector in B
4AF0H – READ the GAT sector for the drive pointed to by Register C
4B03H – WRITE the GAT sector for the drive pointed to by Register C
4B1EH – Prepare Registers for Directory I/O
Entry: B = the system sector number, C = disk drive number
Exit: DE = Track/Sector number, HL = Buffer Address for the file entry, AF = Non-Zero is sector out of range
4B35H – Routine to Call the Disk Driver
Entry: DE = Track/Sector number, HL = Buffer Address, C = Drive number
4B49
INC HL
4B55H – Routine to Return Directory Track Nwnber for Unit C
4B5DH – Build and execute an instruction to test the bit held in Register A for the quantity held in Register B
4B60
4B61
RLCA
RLCA
4B6AH – Compute the sector number for a record number held in DE with a record length held in A
The math is RECORD SIZE x RECORD NUMBER / 256.
4B84H – This routine performs MODULO division by shifting the most significant bit out of the dividend (held in HL) into Register A one bit at a time
Whenever Register A is greater than or equal to the modulus or is full, decrement it by the modulo value and bump the quotient.
Entry: HL = dividend, A = divisor
Exit: HL = quotient, A= remainder
4B97H – test for EOF in the sector buffer
4BA0H – Return with zero status. The 4312H vector points here.
4BA2H – RST 28 Processing. Load System Overlay. Entry: A holds the overlay request
4C06H – Vector to The LOAD FILE IN SYSTEM DCB Vector
4C16H – Load File From DCB Specified in DE Vector
4C29H – General Purpose File Loader
4C39H – System Loader
4C4FH – Skip to Next Control Byte
4C5AH – Get Transfer Address Into HL
4C67H – Load Data Into Memory
4C81H – Determine Cause of Storage Failure
4C8CH – Get the Next Byte of Load Data from the Sector Buffer
4CA3H – Re-initialize BC to 4D00 and fetch the first byte of data from the buffer
4CA9 – CLOCK Display Routine
4CB7 – Vector to DISPLAY CLOCK ON VIDEO Vector
4CD2 – Vector to DISPLAY DATE ON VIDEO
4CD9H – TRACE Display Routine
RRA
RRA
RRA