M100 TS-DOS ROM TPDD Protocol
From Bitchin100 DocGarden
Jump to navigationJump to search
TS-DOS Model 100/102 ROM TPDD Protocol routines
; =========================================================================================
; Flush the RX output buffer to the TPDD file
; =========================================================================================
46DDH LHLD FCCEH ; Get address of FD control
46E0H LXI B,0007H ; Load offset of write buffer length
46E3H DAD B ; Calculate address of write buffer length within FD control
46E4H MOV A,M ; Load the write buffer length
46E5H PUSH H ; Save pointer to write buffer length in FD control on stack
46E6H INX H ; Skip the LSB of the write buffer pointer
46E7H INX H ; Skip the MSB of the write buffer pointer
46E8H INX H ; Point to the actual data in the file write buffer
46E9H LXI D,FD04H ; DE points to the data area in RX buffer
46ECH MOV C,A ; Load buffer length into BC
46EDH MVI B,00H ; Make MSB of BC zero
46EFH PUSH PSW ; Save write buffer length to stack
46F0H CALL 4A05H ; Move BC bytes from M to (DE) with increment
46F3H POP PSW ; Retrieve write buffer length from stack
46F4H ANA A ; Test if write buffer is empty
46F5H CNZ 4095H ; Send TPDD Write File opcode using RX buffer with length in A if not empty
46F8H POP H ; Retrieve pointer to write buffer length in FD control from stack
46F9H MVI M,00H ; Set length of write buffer to zero - it is flushed
46FBH INX H ; Increment to address in FD control of write buffer
46FCH MOV D,H ; Save HL to DE for storage of new buffer pointer address
46FDH MOV E,L ; Save MSB of HL to DE
46FEH INX H ; Increment to MSB of address in FD conrol of write buffer
46FFH INX H ; Increment to actual write buffer address
4700H SHLX ; Save new write buffer pointer to FD control
4701H RET
; =========================================================================================
; Appears to be unused code
; =========================================================================================
4702H POP PSW
4703H RET
; =========================================================================================
; Display or print all disk files and free space
; =========================================================================================
4704H LXI H,F685H ; Keyboard buffer
4707H SHLD FCDBH ; Initialize pointer to File Length table
470AH CALL 4735H ; Clear #files displayed, init TPDD and send 1st file dir referene opode
470DH JNZ 486AH ; Communication Error
4710H XRA A ; Prepare to initialize "skip page" count to zero
4711H STA FCDAH ; Load the "skip page" count
4714H STA FCD4H ; Current Page of files being displayed
4717H DCR A ; Set A to 0xFF
4718H STA FCD7H ; Save as Page size to print (print 255 files per page)
471BH MVI A,01H ;
471DH STA F63AH ; ???
4720H CALL 4747H ; Get next page of files from server (NADSBox) with page size = 255
4723H JMP 4C23H ; Send CRLF to screen or printer
; =========================================================================================
; Display Disk free space on LCD at current position
; NOT CALLED!
; Old function - reporting of Free space was merged into the printing of the function
; key display routine.
; =========================================================================================
4726H CALL 4A10H ; Multiply TPDD free sectors len x 128 = free space
4729H CALL 4C3EH ; Print binary number in HL at current position
472CH LXI H,4AD1H ; Point to "0 Bytes free" text
472FH CALL 4A2CH ; Send buffer at M to screen
4732H JMP 4C23H ; Send CRLF to screen or printer
; =========================================================================================
; Clear #files displayed, init TPDD and send 1st file dir referene opode
; =========================================================================================
4735H XRA A ; Indicate zero files being displayed
4736H STA FCD6H ; Count of files on screen
4739H CALL 4943H ; Configure baud, test for NADSBox, get NADSBox dir
473CH LXI H,0146H ; Load code for "F" attribute and First File dir reference
473FH JMP 476FH ; Send Directory Reference opcode with HL=access mode
; =========================================================================================
; Get next page of files from server (NADSBox / TPDD)
; =========================================================================================
4742H MVI A,14H ; Maximum files that will fit on the display
4744H STA FCD7H ; Save for comparison of file count
4747H LDA FCCBH ; NADSBox / Desklink / TPDD2 flag
474AH ANA A ; Test if TPDD
474BH JNZ 4757H ; Skip 1st invocation of "Next file" if NADSBox or TPDD2??
474EH LXI H,02F6H ; Load access mode code for "Next entry" dir reference
4751H CALL 476FH ; Send Directory Reference opcode with HL=access mode
4754H JNZ 47F8H ; Check RX packet for Noraml Response & report errors
4757H LDA FD04H ; 1st filename byte
475AH ANA A ; Test if 1st filename byte is zero
475BH RZ ; Return if last file retrieved
475CH LDA FCDAH ; Load the "skip page" count
475FH ANA A ; Test if this is a "skip page"
4760H CZ 4781H ; Call routine to display file if not a skip page
4763H LXI H,FCD6H ; Count of files on screen
4766H INR M ; Increment #files displayed on LCD
4767H LDA FCD7H ; Load count of max files that will fit on LCD
476AH CMP M ; Compare with current file count
476BH JNZ 474EH ; Jump back to get next file from TPDD if not full
476EH RET
; =========================================================================================
; Send Directory Reference opcode with HL=access mode
; =========================================================================================
476FH SHLD FD00H ; Save file attrib and reference mode to TX buffer
4772H LXI H,1A00H ; Load code and length for Directory Reference opcode
4775H CALL 4822H ; Send TPDD Command/Len in HL
4778H CALL 47CCH ; Receive a packet
477BH LDA FD02H ; Storage for RX packet - response byte
477EH CPI 11H ; Test if response was 0x11 (valid Dir Ref response)
4780H RET
; =========================================================================================
; Print filename in RX buffer to LCD and save length info
; =========================================================================================
4781H MVI C,09H ; Prepare to draw 9 bytes of filename to LCD
4783H LXI H,FD04H ; Location of filename in RX packet
4786H CALL 48E5H ; Redraw C characters from buffer at HL using current video mode
4789H MVI A,20H ; Prepare to draw a trailing space
478BH RST 4 ; Send char in A to LCD
478CH LHLD FD1DH ; Get file size parameter from RX buffer
478FH MOV E,H ; Save file size LSB in E
4790H MOV D,L ; Save file size MSB in D
; =========================================================================================
; Store next file length to keyboard buffer
; =========================================================================================
4791H LHLD FCDBH ; Next storage location for file size info
4794H XCHG ; HL <--> DE
4795H SHLX ; Store file length at address of next file save
4796H XCHG ; HL <--> DE
4797H INX H ; Increment storage address of next file length
4798H INX H ; Increment again (2 byte length)
4799H SHLD FCDBH ; Save new address for lenght storage for next file
479CH RET
; =========================================================================================
; Receive an RX packet. This routine gets copied into RAM and executed from there while
; the Main ROM is selected. This allows the RX packet to be recieved without
; switching to and from the Main ROM to receive each individual byte. The jump
; addresses represent the RAM execution locations.
; =========================================================================================
479DH LXI H,FD02H ; Storage for RX packet
47A0H PUSH H ; Save start of packet address on stack
47A1H CALL FDB2H ; Get next byte from RX into HL
47A4H CALL FDB2H ; Get next byte from RX into HL
47A7H MOV C,A ; Move length byte into C
47A8H CALL FDB2H ; Get next byte from RX into HL
47ABH MOV B,C ; Move length byte to B
47ACH MOV A,C ; Move length byte to A for zero test
47ADH ANA A ; Test if length is zero
47AEH JZ FDA4H ; Skip reading payload if zero length
47B1H CALL FDB2H ; Get next byte from RX into HL
47B4H DCR C ; Decrement length byte
47B5H JNZ FD9DH ; Keep looping until all data received
47B8H POP H ; Restore start of RX packet address
47B9H INR B ; Add opcode byte to length for checksum
47BAH INR B ; Add length byte to length for checksum
47BBH XRA A ; Clear A for checksum calculation
47BCH SIM ; ?Clear Interrupts
47BDH ADD M ; Add next byte to checksum
47BEH INX H ; Increment RX data pointer
47BFH DCR B ; Decrement length counter
47C0H JNZ FDA9H ; Keep looping until all bytes added
47C3H CMA ; Compliment the checksum
47C4H CMP M ; Compare with received checksum
47C5H RET ; Branch if no match - Communication Error
; =========================================================================================
; Get next RX byte and store at HL, test for drive ready & print errors
; This routine (and the one above) get copied into RAM and then executed
; when the Main ROM is selected, so a direct call to the Main ROM address
; is allowed.
; =========================================================================================
47C6H CALL 6D7EH ; Get a character from RS232 receive queue
47C9H MOV M,A ; Save byte at HL
47CAH INX H ; Increment HL
47CBH RET
; =========================================================================================
; Copy the 2 Receive RX Packet routines above to RAM and execute
; =========================================================================================
47CCH LXI H,479DH ; Point to Receive RX Packet routine
47CFH LXI D,FD89H ; Point to target destination in RAM
47D2H LXI B,002FH ; Length of the routine
47D5H CALL 4A05H ; Move BC bytes from M to (DE) with increment
47D8H CALL 4862H ; Test if DSR is set - drive ready, error otherwise
47DBH CALL 4BDBH ; Call Main ROM's Set interrupt to 1DH routine.
47DEH RST 1 ; Switch to Main ROM and execute "Receive RX Pakcet" routine
47DFH DW FD89H ; Address of our RX routine we just copied to RAM
47E1H JNZ 486AH ; Communication Error if no /DSR
47E4H RET
; =========================================================================================
; Get next RX byte and store at HL, test for drive ready & print errors
; =========================================================================================
47E5H CALL 47EBH ; Test drive and get byte from RX
47E8H MOV M,A ; Save byte at HL
47E9H INX H ; Increment HL
47EAH RET
; =========================================================================================
; Test drive ready and get byte from RX, Report error if not ready
; =========================================================================================
47EBH CALL 4862H ; Test if DSR is set - Drive Ready
47EEH CALL 4BE7H ; Get a character from RS232 receive queue
47F1H JC 488DH ; Empty Error Text
47F4H JNZ 486AH ; Communication Error
47F7H RET
; =========================================================================================
; Check RX packet for Normal Response & report errors
; =========================================================================================
47F8H LDA FD02H ; Storage for RX packet
47FBH CPI 12H ; Test for normal return code
47FDH JNZ 486AH ; Communication Error
4800H LDA FD04H ; Location of error code in RX packet
4803H ANA A ; Test if error code is zero
4804H RZ ; Return if no error
4805H CPI 10H
4807H JZ 487EH ; File Exists Error
480AH CPI 50H
480CH JZ 486DH ; Write Protect Error
480FH CPI 60H
4811H JZ 4881H ; Disk Full Error
4814H JC 486AH ; Communication Error
4817H JZ 4873H ; Disk not in drive error
481AH CPI 80H
481CH JC 4873H ; Disk not in drive error
481FH JMP 4870H ; Drive Trouble Error
; =========================================================================================
; Send TPDD Command/Len in HL, H=len, L=Cmd. 0XED8A already has data
; =========================================================================================
4822H SHLD FCE6H ; Store TDD CMD/Len passed in HL
4825H LXI H,FCE6H ; Point to Command/Len storage location
4828H PUSH H ; Save Cmd/Len storage address to stack
4829H LDA FCCAH ; TPDD Bank Numbere
482CH ANA A ; Test if reading from side zero
482DH JZ 4837H ; Skip ahead if reading from side zero
4830H ANI 01H ; Mask off all but LSB (only side 1 allowed)
4832H RAR ; Move the "1" to C
4833H RAR ; Move the "1" to bit 7
4834H RAR ; Move the "1" to bit 6 (could just do MVI 0x40 !!)
4835H ORA M ; OR the 0x40 with Cmd to access Disk Bank 1
4836H MOV M,A ; Save the updated cmd value back at (HL)
4837H MOV A,M ; Get the command value / modified value
4838H INX H ; Point to length parameter passed in
4839H ADD M ; Add the length parameter (checksum)
483AH MOV B,A ; Store checksum in B
483BH MOV A,M ; Get the Length parameter
483CH PUSH PSW ; Save length on stack
483DH INX H ; Point to data (already loaded before invocation)
483EH ANA A ; Test if length is zero
483FH JZ 484BH ; Skip data checksum if length zero
4842H MOV C,A ; Save current count
4843H MOV A,B ; Get running checksum value
4844H ADD M ; Add this byte to checksum
4845H INX H ; Point to next data byte
4846H DCR C ; Decrement count
4847H JNZ 4844H ; Keep looping until count is zero
484AH MOV B,A ; Save updated checksum in B
484BH MOV A,B ; Get Checksum from B
484CH CMA ; Compliment the checksum (protocol thing)
484DH MOV D,A ; Save complimented checksum in D
484EH LXI B,5A5AH ; Load "ZZ" header signature into BC
4851H CALL 49DBH ; Send BC to the serial port using XON/XOFF
4854H POP B ; Get the length from stack into BC
4855H MOV C,B ; Move the length into C
4856H MVI B,00H ; Clear upper MSB of count
4858H INX B ; Add Opcode byte to the TX length
4859H INX B ; Add length byte to the TX length
485AH POP H ; Get address of TX packet from stack
485BH CALL 48D9H ; Send BC bytes to RS-232 from (HL) using XON/XOFF
485EH MOV A,D ; Get checksum byte for TX
; =========================================================================================
; Send A to RS-232 using XON/XOFF and check DSR when done
; =========================================================================================
485FH CALL 4BE3H ; Call Main ROM's Send A to RS-232 using XON/XOFF routine
; =========================================================================================
; Test if DSR is set - drive ready, error otherwise
; =========================================================================================
4862H IN BBH ; Get I/O port with /DSR bit
4864H ANI 20H ; Mask all but the /DSR bit
4866H RZ ; Return if /DSR is asserted (low = asserted)
; =========================================================================================
; Error jump table. Loads A with error number and prints
; =========================================================================================
4867H (3EH) MVI A,01H
DB 0x21 ; Filler - looks like "LXI H,XXXX"
486AH MVI A,02H ; Communication Error
DB 0x21
486DH MVI A,03H ; Write Protect Error
DB 0x21
4870H MVI A,04H ; Drive Trouble Error
DB 0x21
4873H MVI A,05H ; Disk not in drive Error
; =========================================================================================
; For any of the errors above, change the RAM/Disk mode back to RAM
; =========================================================================================
4875H LXI H,FCD9H ; RAM / Disk mode (0=RAM, 1=DISK)
4878H MVI M,00H ; Go back to RAM mode
DB 0x21 ; Filler - looks like "LXI H,XXXX"
487BH MVI A,06H ; Printer Not Ready Error
DB 0x21
487EH MVI A,07H ; File Exists Error
DB 0x21
4881H MVI A,08H ; Disk Full Error
DB 0x21
4884H MVI A,09H ; File Empty Error
DB 0x21
4887H MVI A,0AH ; Directory Full Error
DB 0x21
488AH MVI A,0BH ; Ram Full Error
DB 0x21
488DH MVI A,0CH ; ID Error (No text...runtime error only)
DB 0x21
4890H MVI A,0DH ; Bad File Name Error
; =========================================================================================
; Generate the error loaded in A above
; =========================================================================================
4892H LXI H,4B02H ; Pointer to error string table
4895H MOV C,A ; Save error number for loop counting
4896H DCR C ; Decrement error counter to test if string found
4897H JZ 48A4H ; String found in table
489AH MOV A,M ; Get next byte of error string
489BH INX H ; Inrcrement pointer
489CH CPI 00H ; Test if end of string
489EH JNZ 489AH ; Loop until end of string found
48A1H JMP 4896H ; Branch back to decrement string counter
; =========================================================================================
; Print error string at HL from error table
; =========================================================================================
48A4H LDA FCD2H ; Get the "Print error messages" flag
48A7H ANA A ; Test if printing allowed
48A8H JZ 48D0H ; Jump to generate system error if not allowed to print
48ABH MVI A,07H ; Print BELL to cause a beep
48ADH RST 4 ; Send A to the LCD
48AEH INX H ; Skip the error code
48AFH CALL 48F4H ; Print string at HL to col 1 on the bottom line
48B2H CALL 48C7H ; Display "Press any key" and wait for key
; =========================================================================================
; Perform Long jump
; =========================================================================================
48B5H LHLD FCCEH ; Stack pointer upon entry
48B8H SPHL ; Restore stack frame
48B9H LHLD FCD0H ; Get return vector after error
48BCH PUSH H ; Prepare to return to return vector
48BDH RET
; =========================================================================================
; Draw "Press any key" text with pre&post CR and wait for key press
; =========================================================================================
48BEH CALL 4C23H ; Send CRLF to screen or printer
48C1H CALL 48C7H ; Display "Press any key" and wait for key
48C4H JMP 4C23H ; Send CRLF to screen or printer
; =========================================================================================
; Draw "Press any key" text and wait for key press
; =========================================================================================
48C7H LXI H,4BBBH ; Point to "Press any key" text
48CAH CALL 4A2CH ; Send buffer at M to screen
48CDH JMP 4BEBH ; Wait for key from keyboard
; =========================================================================================
; Generate system error from code saved at (HL). This is called in liu of printing when
; the print/generate system error flag is set. The 1st byte of each error entry
; contains the system error number to generate.
; =========================================================================================
48D0H MOV E,M ; Get the error code
48D1H LHLD FCCEH ; Stack pointer upon entry
48D4H MVI M,00H ; Indicate all arguments (none) processed
48D6H JMP 4C37H ; Generate error in E
; =========================================================================================
; Send BC bytes to RS-232 from (HL) using XON/XOFF
; =========================================================================================
48D9H MOV A,M ; Get next byte from (HL)
48DAH CALL 485FH ; Send A to RS-232 using XON/XOFF
48DDH INX H ; Increment poiner
48DEH DCX B ; Decrement byte count
48DFH MOV A,C ; Get C for zero comparison
48E0H ORA B ; Or in MSB of count
48E1H JNZ 48D9H ; Jump to send next byte if not zero
48E4H RET
; =========================================================================================
; Draw C characters to LCD from buffer at HL using current video mode
; =========================================================================================
48E5H MOV A,M ; Get next byte from LCD buffer
48E6H CPI 20H ; Test if it is a space
48E8H JNC 48EDH ; Test if it's less than space, jump if not to redraw
48EBH MVI A,20H ; Draw a space for "illegal" values
48EDH RST 4 ; Draw byte with current regular/inverse video mode
48EEH INX H ; Increment to next byte in LCD buffer
48EFH DCR C ; Decrement the loop counter
48F0H JNZ 48E5H ; Branch if not done to process next character
48F3H RET ; Done
; =========================================================================================
; Print string at HL to col 1 on the bottom line
; =========================================================================================
48F4H PUSH H ; Save pointer to error text on stack
48F5H LXI H,0108H ; Position cursor on col 1 of row 16
48F8H SHLD F639H ; Cursor row (1-8)
48FBH CALL 4C2BH ; Erase from cursor to end of line
48FEH POP H ; Restore pointer to error text from stack
48FFH JMP 4A2CH ; Send buffer at M to screen
; =========================================================================================
; Copy filename at (HL) to current BASIC program
; =========================================================================================
4902H PUSH H ; Save pointer to filename on stack
4903H MVI A,20H ; Load A with code for SPACE
4905H LXI H,FC93H ; Filename of current BASIC program
4908H MVI B,08H ; Prepare to fill current BASIC program with 8 spaces
490AH CALL 4A34H ; Fill (HL) with B bytes of A
490DH POP H ; Retrieve filename pointer from stack
490EH LXI D,FC93H ; Filename of current BASIC program
4911H MVI B,06H ; Prepare to copy 6 bytes of filename before ext
4913H MOV A,M ; Get next byte of filename from source
4914H CPI 41H ; Compare byte with 'A' to test validity
4916H JC 4890H ; Bad Filename Error if invalid char
4919H MOV A,M ; Get next byte again
491AH CPI 2EH ; Compare with '.'
491CH JZ 492BH ; Branch if '.' to fill remaining with ' '
491FH ORA A ; Test for zero (NULL term)
4920H RZ ; Return if done copying filename (NULL term)
4921H STAX D ; Store next filename byte at (DE)
4922H INX H ; Increment source pointer
4923H INX D ; Increment dest pointer
4924H DCR B ; Decrement counter
4925H JNZ 4919H ; Keep looping until all bytes copied
4928H JMP 4933H ; Jump to copy 2 extension bytes
; =========================================================================================
; Fill remainder of filename at (DE) with spaces, B has count
; =========================================================================================
492BH MVI A,20H ; Load code for ' '
492DH STAX D ; Save next byte as ' '
492EH INX D ; Increment pointer
492FH DCR B ; Decrement count
4930H JNZ 492DH ; Keep looping until full
; =========================================================================================
; Copy 2 extention bytes from (HL) to (DE)
; =========================================================================================
4933H MVI B,02H ; Setup count = 2
4935H INX H ; Skip the '.' in the source name
4936H MOV A,M ; Load next extension byte from source
4937H ORA A ; Test for NULL termination
4938H RZ ; Return if NULL terminated
4939H STAX D ; Store in destination
493AH INX D ; Increment destination
493BH DCR B ; Decrement the counter
493CH JNZ 4935H ; Keep looping until done
493FH MVI A,00H ; Load NULL termination byte
4941H STAX D ; Add NULL termination to filename
4942H RET
; =========================================================================================
; Configure baud, test for NADSBox, get NADSBox dir
; =========================================================================================
4943H CALL 4A94H ; Configure baud (19200 for NADSBox/Desklink, 9600 otherwise)
4946H CALL 49A2H ; Send M1 and test for NADSBox/Desklink response
4949H CALL 47CCH ; Receive a packet
494CH CALL 47F8H ; Check RX packet for Normal Response & report errors
494FH LDA FCCBH ; NADSBo / Desklink / TPDD2 flag
4952H ANA A ; Test if server is NADSBox / Desklink
4953H RZ ; Return if not NADSBox / Desklink
4954H LXI H,0008H ; Load opcode 0x08 - FDC Emulation mode
4957H CALL 4822H ; Send TPDD Command/Len in HL
495AH CALL 47CCH ; Receive a packet - should be the current directory name
495DH LDA FD03H ; Load length byte from the RX payload area
4960H CPI 01H ; Test if length 1
4962H JZ 4977H ; Jump to send mystery opcodes if length = 1
4965H DCR A ; Subtract 1 from length (skip reserved 0x00 in filename)
4966H MOV C,A ; Save count in C
4967H MVI A,02H ; Prepare to indicate we have a NADSBox / Desklink directory name
4969H STA FCCBH ; NADSBox / Desklink flag = HAVE_NADS_DIR
496CH MVI B,00H ; Clear MSB of count
496EH LXI H,FD05H ; Point to filename in RX payload (skip 1st byte)
4971H LXI D,FCC0H ; Storage area for NADSBox directory
4974H JMP 4A05H ; Move BC bytes from M to (DE) with increment
; =========================================================================================
; Send mystery opcodes
; =========================================================================================
4977H LXI H,0023H ; Load mystery opcode 23
497AH CALL 4822H ; Send TPDD Command/Len in HL
497DH CALL 47CCH ; Receive a packet
4980H LXI H,4AE7H ; Point to mystery opcode 0x31
4983H CALL 498FH ; Send 9-byte protocol packet at HL
4986H LXI H,4AF0H ; Point to 2nd mystery opcode 0x31
4989H CALL 498FH ; Send 9-byte protocol packet at HL
498CH LXI H,4AF9H ; Point to 3rd mystery opcode 0x31
; =========================================================================================
; Send 9-byte protocol packet at HL
; =========================================================================================
498FH LXI B,0009H ; Load byte counter to send 9 bytes
4992H CALL 48D9H ; Send BC bytes at (HL) to RS-232 using XON/XOFF
4995H JMP 47CCH ; Receive a packet
; =========================================================================================
; Flush the RX queue & discard
; =========================================================================================
4998H CALL 4BDFH ; Check RS232 queue for pending characters
499BH RZ ; Return if RS232 queue is empty
499CH CALL 47EBH ; Test drive ready and get byte from RX.
499FH JMP 4998H ; Branch to get next byte from RX
; =========================================================================================
; Send M1 and test for NADSBox / Desklink response
; =========================================================================================
49A2H CALL 4862H ; Test if DSR set - drive ready
49A5H CALL 49CDH ; Send "M1",0x0D to TX and delay about 3ms
49A8H CALL 4998H ; Flush the RX queue & discard
49ABH CALL 419BH ; Send Opcode 0x08 - FDC emulation mode
49AEH CALL 49D3H ; Send 0x0D to RS-232 and Delay 3ms
49B1H CALL 4BDFH ; Check RS232 queue for pending characters
49B4H MVI A,00H ; NADSBox / Desklink / TPDD2 flag
49B6H JNZ 49BAH ; Skip setting NADSBox / Desklink flag if no response
49B9H INR A ; Indicate response from "M1" command = NADSBox / Desklink
49BAH STA FCCBH ; Store NADSBox / Desklink / TPDD2 flag
49BDH CALL 4998H ; Flush the RX queue & discard
49C0H CALL 49CDH ; Send "M1" to TX and delay about 3ms
49C3H CALL 4998H ; Flush the RX queue & discard
49C6H LXI H,0007H ; Load opcode for Drive Status
49C9H CALL 4822H ; Send TPDD Command/Len in HL
49CCH RET
; =========================================================================================
; Send "M1",0x0D to RS-232 and delay about 3ms
; =========================================================================================
49CDH LXI B,4D31H ; Load code for "M1"
49D0H CALL 49DBH ; Send BC to RS-232 using XON/XOFF
49D3H MVI A,0DH ; Load code for CR (0x0D)
49D5H CALL 485FH ; Send A to RS-232 using XON/XOFF
49D8H JMP 49E3H ; Delay routine - about 3ms
; =========================================================================================
; Send BC to RS-232 using XON/XOFF
; =========================================================================================
49DBH MOV A,B ; Get first byte to send
49DCH CALL 485FH ; Send A to RS-232 using XON/XOFF
49DFH MOV A,C ; Get 2nd byte to send
49E0H JMP 485FH ; Send A to RS-232 using XON/XOFF
; =========================================================================================
; Delay routine - about 72000 cycles = 28.9ms
; =========================================================================================
49E3H MVI H,14H ; 7 Cycles
49E5H MVI L,FFH ; 7 Cycles
49E7H DCR L ; 4 Cycles
49E8H JNZ 49E7H ; 10 Cycles to Jump back. 14 * 255 = 3570 cycles inner loop
49EBH DCR H ; 4 Cycles. But we save 3 cycles from the final JNZ, so 1 cycle
49ECH JNZ 49E5H ; 10 Cycles to jump back. (3570+1+7)*20+7 = 71567 cycles
49EFH RET ; 71567 * 403.877ns = 28.904ms
; =========================================================================================
; Wait for drive to be ready for 20480 counts of 28.9ms = 9.8 minutes???.
; Report error if no data received.
; =========================================================================================
49F0H LXI B,FF50H ; Get count of delay times to wait
49F3H CALL 49E3H ; Delay 28.9ms
49F6H CALL 4BDFH ; Check RS232 queue for pending characters
49F9H RNZ ; Return if data available
49FAH DCR B ; Decrement inner loop count
49FBH JNZ 49F3H ; Branch to delay and test again
49FEH DCR C ; Decrement outer loop count
49FFH JNZ 49F3H ; Branch to delay and test again
4A02H JMP 4867H ; No data received - Drive Not Ready error
; =========================================================================================
; Move BC bytes from M to (DE) with increment
; =========================================================================================
4A05H MOV A,M ; Get next byte from (HL)
4A06H STAX D ; Store next byte at (DE)
4A07H INX H ; Increment source pointer
4A08H INX D ; Increment destination poiner
4A09H DCX B ; Decrement loop control
4A0AH MOV A,B ; Prepare to test for zero
4A0BH ORA C ; OR in LSB to test for zero
4A0CH JNZ 4A05H ; Keep looping until done
4A0FH RET
; =========================================================================================
; Multiply TPDD free sectors len x 128 = free space. A '0' is added to LCD to convert this
; multiplication to x1280 (the TPDD sector size).
; =========================================================================================
4A10H LDA FD1FH ; Get number of free sectors reported from server (TPDD)
4A13H MOV L,A ; Move #free sectors into HL for multiply
4A14H MVI H,00H ; Clear MSB of HL
4A16H LXI D,0080H ; Prepare to multiply #sectors x 128
4A19H JMP 4C1FH ; Signed integer muliply (FAC1=HL*DE)
; =========================================================================================
; Compare (HL) with (DE), C bytes long
; =========================================================================================
4A1CH PUSH D ; Save pointer to 1st buffer
4A1DH PUSH H ; Save pointer to 2nd buffer
4A1EH LDAX D ; Load next byte from 1st buffer
4A1FH SUB M ; Compare with nex byte from 2nd buffer
4A20H JNZ 4A29H ; Jump to exit if no match
4A23H INX H ; Increment 2nd buffer pointer
4A24H INX D ; Increment 1st buffer pointer
4A25H DCR C ; Decrement length
4A26H JNZ 4A1EH ; Jump to compare next byte if not at end
4A29H POP H ; Restore pointer to 2nd buffer
4A2AH POP D ; Restore pointer to 1st buffer
4A2BH RET
; =========================================================================================
; Send buffer at M to screen
; =========================================================================================
4A2CH (7EH) MOV A,M ; Get next byte to send to LCD
4A2DH (A7H) ANA A ; Test for end of string
4A2EH (C8H) RZ ; Return if end of string (NULL terminated)
4A2FH (E7H) RST 4 ; Send character in A to screen/printer
4A30H (23H) INX H ; Increment to next byte
4A31H (C3H) JMP 4A2CH ; Branch to test next byte for zero and print
; =========================================================================================
; Fill (HL) with B bytes of A
; =========================================================================================
4A34H MOV M,A ; Load next byte at (HL) with A
4A35H INX H ; Increment pointer
4A36H DCR B ; Decrement counter
4A37H JNZ 4A34H ; Keep looping until B bytes copied
4A3AH RET
; =========================================================================================
; Initialize blank filename and attribute byte
; =========================================================================================
4A3BH MVI A,20H ; Prepare to fill TX packet with spaces
4A3DH MVI B,18H ; Fill TX buffer with 24 spaces
4A3FH LXI H,FCE8H ; Address of TX packet data
4A42H CALL 4A34H ; Fill (HL) with B bytes of A
4A45H MVI A,46H ; Load "F" TPDD file attribute flag
4A47H STA FD00H ; Store in TX packet data location
4A4AH RET
; =========================================================================================
; Get RAM directory address of selected file into HL
; =========================================================================================
4A4BH LHLD FCE4H ; LCD Buffer address of current file selection
4A4EH CALL 4902H ; Copy filename at (HL) to current BASIC program
; =========================================================================================
; Get RAM directory address of current BASIC program
; =========================================================================================
4A51H CALL 4C0FH ; Update system pointers
4A54H JMP 4BFBH ; Find catalog entry address of current BASIC program
; =========================================================================================
; Send Dir Reference for filename at (HL)
; =========================================================================================
4A57H PUSH H ; Save filename address on stack
4A58H CALL 4A3BH ; Initialize blank filename and attribute byte
4A5BH POP H ; Restore filename address
4A5CH LXI D,FCE8H ; Address of TX packet data
4A5FH LXI B,0006H ; Prepare to copy 6 bytes of TX data
4A62H CALL 4A05H ; Move BC bytes from M to (DE) with increment
4A65H MVI A,2EH ; Load code for '.'
4A67H STAX D ; Add '.' between name and extension
4A68H INX D ; Increment TX pkt address pointer
4A69H LXI B,0002H ; Prepare to copy extension from filename
4A6CH CALL 4A05H ; Move BC bytes from M to (DE) with increment
4A6FH CALL 4943H ; Configure baud, test for NADSBox, get NADSBox dir
; =========================================================================================
; Send Dir Reference opcode
; =========================================================================================
4A72H MVI A,00H ; Set dir reference type to "reference" for open
4A74H STA FD01H ; Save in dir reference location in TX buffer
4A77H LXI H,1A00H ; Load opcode for directory reference
4A7AH CALL 4822H ; Send TPDD Command/Len in HL
4A7DH CALL 47CCH ; Receive a packet
4A80H LDA FD1CH ; Load attribute byte
4A83H ANA A ; Test attribute byte for zero
4A84H RET
; =========================================================================================
; Save OS's baud rate string to storage area, A = "Print error messages" flag
; =========================================================================================
4A85H STA FCD2H ; Store "Print error messages" flag
4A88H LXI D,F9A8H ; Storage area for previous baud setting
4A8BH LXI H,F65BH ; RS232 parameter setting table
4A8EH LXI B,0005H ; Copy 7 bytes of parameter data
4A91H JMP 4A05H ; Move BC bytes from M to (DE) with increment
; =========================================================================================
; Configure baud, check for Desklink/NADSBox. Set to 9600 if not Desklink/NADSBox
; =========================================================================================
4A94H CALL 4BD7H ; Wait for TX empty and Reset UART to accept mode bits
4A97H LXI H,4ADEH ; Baud rate string for "98N1D"
4A9AH LXI D,F65BH ; RS232 parameter setting table
4A9DH LXI B,0005H ; Prepare to copy 5 bytes to Baud Parameter table
4AA0H CALL 4A05H ; Move BC bytes from M to (DE) with increment
4AA3H LXI H,F65BH ; Point to RS232 parameter setting table
4AA6H STC ; Indicate Baud rate is part of string
4AA7H CALL 4BD3H ; Set RS232 parameters from string at M
4AAAH CALL 4998H ; Flush the RX queue & discard
4AADH CALL 49A2H ; Send M1 and test for NADSBox / Desklink response
4AB0H CALL 49E3H ; Delay routine - about 3ms
4AB3H CALL 4BDFH ; Check RS232 queue for pending characters
4AB6H JNZ 4998H ; Jump to flush RX and keep 19200 if NADSBox / Desklink found
4AB9H CALL 4BD7H ; Wait for TX empty and Reset UART to accept mode bits
4ABCH LXI H,F65BH ; Baud rate string for "98N1D"
4ABFH DCR M ; Set baud rate to '8' = 9600 baud
4AC0H STC ; Indicate Baud rate is part of string
4AC1H JMP 4BD3H ; Set RS232 parameters from string at M - change to 9600 Baud
; =========================================================================================
; Restore original baud settings
; =========================================================================================
4AC4H LXI H,F9A8H ; Storage for OS's baud settings
4AC7H MOV A,M ; Get 1st byte of setting
4AC8H SUI 3AH ; Test if 1st byte is numeric
4ACAH JC 4BD3H ; Set RS232 parameters from string at M
4ACDH INX H ; Skip setting baud if 1st byte is "M"odem
4ACEH JMP 4BD3H ; Set RS232 parameters from string at M
; =========================================================================================
; Strings and table data
; =========================================================================================
4AD1H DB "0 Bytes free",0x00 ; Old Text - NOT USED in ROM version, only RAM version
4ADEH DB "98N1DNN", 0x00 ; Parameters for setting baud rate
4ADFH DB "8N1D",0x00
4AE4H DB 0x02,0x03,0x01 ; RST 7,30h open mode to TPDD Open mode mapping
4AE9H DB "ZZ1",0x04,0x01,0x00,0x84,0xFF,"F"
4AF0H DB "ZZ1",0x04,0x01,0x00,0x96,0x0F,0x24
4AF9H DB "ZZ1",0x04,0x01,0x00,0x94,0x0F,0x26
4B02H DB 0x12,"Drive Not Ready",0x00
DB 0x12,"Communication Error",0x00
DB 0x12,"Write Protect",0x00
DB 0x12,"Drive Trouble",0x00
DB 0x12,"Disk not in drive",0x00
DB 0x34,"Printer not ready",0x00
DB 0x05,"File Exists",0x00
DB 0x39,"Disk Full",0x00
DB 0x1A,"File Empty",0x00
DB 0x39,"Directory Full",0x00
DB 0x07,"Ram Full",0x00
DB 0x36,0x00
DB 0x37,"Bad File Name",0x00
4BBBH DB " Press any key.",0x00
; =========================================================================================
; RST 1 Vectors to Main ROM. At places in the code where a call is needed to the Main ROM,
; a RST 1 followed by a 2-byte address is issued. The routines will jump to one of
; the handler functions below to perform that RST 1 operation.
; =========================================================================================
4BCBH RST 1 ; Call main ROM at address in following 2 bytes
4BCCH DW 340AH
4BCEH RET
; =========================================================================================
; Call Main ROM's Evaluate expressino at M-1 routine
; =========================================================================================
4BCFH RST 1 ; Call main ROM at address in following 2 bytes
4BD0H DW 1113H
4BD2H RET
; =========================================================================================
; Call Main ROM's Set RS232 parameters from string at M routine
; =========================================================================================
4BD3H RST 1 ; Call main ROM at address in following 2 bytes
4BD4H DW 17E6H
4BD6H RET
; =========================================================================================
; Call Main ROM's Wait for TX empty and Reset UART routine
; =========================================================================================
4BD7H RST 1 ; Call main ROM at address in following 2 bytes
4BD8H DW 6ECBH
4BDAH RET
; =========================================================================================
; Call Main ROM's Set interrupt to 1DH routine.
; Seems like it would be easy enough to just do it in this ROM!
; =========================================================================================
4BDBH RST 1 ; Call main ROM at address in following 2 bytes
4BDCH DW 765CH
4BDEH RET
; =========================================================================================
; Call Main ROM's Check RS232 queue for pending characters routine
; =========================================================================================
4BDFH RST 1 ; Call main ROM at address in following 2 bytes
4BE0H DW 6D6DH
4BE2H RET
; =========================================================================================
; Call Main ROM's Send A to RS-232 using XON/XOFF routine
; =========================================================================================
4BE3H RST 1 ; Call main ROM at address in following 2 bytes
4BE4H DW 6E32H
4BE6H RET
; =========================================================================================
; Call Main ROM's Get a character from RS232 receive queue routine
; =========================================================================================
4BE7H RST 1 ; Call main ROM at address in following 2 bytes
4BE8H DW 6D7EH
4BEAH RET
; =========================================================================================
; Call Main ROM's Wait for key from keyboard routine
; =========================================================================================
4BEBH RST 1 ; Call main ROM at address in following 2 bytes
4BECH DW 12CBH
4BEEH RET
; =========================================================================================
; Call Main ROM's Scan keyboard for character (CTRL-BREAK ==> CTRL-C) routine
; =========================================================================================
4BEFH RST 1 ; Call main ROM at address in following 2 bytes
4BF0H DW 7242H
4BF2H RET
; =========================================================================================
; Call Main ROM's Power Down routine
; =========================================================================================
4BF3H RST 1 ; Call main ROM at address in following 2 bytes
4BF4H DW 13B5H
4BF6H RET
; =========================================================================================
; Call Main ROM's Renew automatic power-off counter routine
; =========================================================================================
4BF7H RST 1 ; Call main ROM at address in following 2 bytes
4BF8H DW 1BB1H
4BFAH RET
; =========================================================================================
; Call Main ROM's Find Catalog Entry Address of current BASIC program routine
; =========================================================================================
4BFBH RST 1 ; Call main ROM at address in following 2 bytes
4BFCH DW 20AFH
4BFEH RET
; =========================================================================================
; Call Main ROM's Kill .DO file routine
; =========================================================================================
4BFFH RST 1 ; Call main ROM at address in following 2 bytes
4C00H DW 1FBFH
4C02H RET
; =========================================================================================
; Call Main ROM's Kill .BA file routine
; =========================================================================================
4C03H RST 1 ; Call main ROM at address in following 2 bytes
4C04H DW 2017H
4C06H RET
; =========================================================================================
; Call Main ROM's Kill .CO file routine
; =========================================================================================
4C07H RST 1 ; Call main ROM at address in following 2 bytes
4C08H DW 1FD9H
4C0AH RET
; =========================================================================================
; Call Main ROM's Insert BC spaces at M routine
; =========================================================================================
4C0BH RST 1 ; Call main ROM at address in following 2 bytes
4C0CH DW 6B6DH
4C0EH RET
; =========================================================================================
; Call Main ROM's Update system pointers routine
; =========================================================================================
4C0FH RST 1 ; Call main ROM at address in following 2 bytes
4C10H DW 2146H
4C12H RET
; =========================================================================================
; Call Main ROM's Find BASIC end of program routine
; =========================================================================================
4C13H RST 1 ; Call main ROM at address in following 2 bytes
4C14H DW 05F4H
4C16H RET
; =========================================================================================
; Call Main Rom's Write new entry to catalog routine
; =========================================================================================
4C17H RST 1 ; Call main ROM at address in following 2 bytes
4C18H DW 2239H
4C1AH RET
; =========================================================================================
; Call Main ROM's Signed integer divide (FAC1=DE/HL) routine
; =========================================================================================
4C1BH RST 1 ; Call main ROM at address in following 2 bytes
4C1CH DW 377EH
4C1EH RET
; =========================================================================================
; Call Main ROM's Signed integer muliply (FAC1=HL*DE) routine
; =========================================================================================
4C1FH RST 1 ; Call main ROM at address in following 2 bytes
4C20H DW 3725H
4C22H RET
; =========================================================================================
; Call Main ROM's Send CRLF to LCD routine
; =========================================================================================
4C23H RST 1 ; Call main ROM at address in following 2 bytes
4C24H DW 4222H
4C26H RET
; =========================================================================================
; Call Main ROM's CLS statement routine
; =========================================================================================
4C27H RST 1 ; Call main ROM at address in following 2 bytes
4C28H DW 4231H
4C2AH RET
; =========================================================================================
; Call Main ROM's Erase from cursor to end of line routine
; =========================================================================================
4C2BH RST 1 ; Call main ROM at address in following 2 bytes
4C2CH DW 425DH
4C2EH RET
; =========================================================================================
; Call Main ROM's Start inverse character mode routine
; =========================================================================================
4C2FH RST 1 ; Call main ROM at address in following 2 bytes
4C30H DW 4269H
4C32H RET
; =========================================================================================
; Call Main ROM's Cancel inverse video routine
; =========================================================================================
4C33H RST 1 ; Call main ROM at address in following 2 bytes
4C34H DW 426EH
4C36H RET
; =========================================================================================
; Call Main ROM's Generate error in E routine
; =========================================================================================
4C37H LXI H,045DH ; Load address of Main ROM's Generate Error in E routine
4C3AH PUSH H ; Push routine to the stack
4C3BH JMP 00A6H ; Jump to Main ROM
; =========================================================================================
; Call Main ROM's Print binary number in HL at current position routine
; =========================================================================================
4C3EH RST 1 ; Call main ROM at address in following 2 bytes
4C3FH DW 39D4H
4C41H RET
; =========================================================================================
; Call Main ROM's Print A to printer, expanding tabs if necessary routine
; =========================================================================================
4C42H RST 1 ; Call main ROM at address in following 2 bytes
4C43H DW 4B55H
4C45H RET
; =========================================================================================
; Call Main ROM's Input and display (no "?") line and store routine
; =========================================================================================
4C46H RST 1 ; Call main ROM at address in following 2 bytes
4C47H DW 4644H
4C49H RET
; =========================================================================================
; Call Main ROM's Check keyboard queue for pending characters routine
; =========================================================================================
4C4AH RST 1 ; Call main ROM at address in following 2 bytes
4C4BH DW 13DBH
4C4DH RET
; =========================================================================================
; Call Main ROM's Move BC bytes from M to (DE) with decrement routine
; =========================================================================================
4C4EH RST 1 ; Call main ROM at address in following 2 bytes
4C4FH DW 6BE6H
4C51H RET
; =========================================================================================
; Call Main ROM's LCOPY statement routine
; =========================================================================================
4C52H RST 1 ; Call main ROM at address in following 2 bytes
4C53H DW 1E5EH
4C55H RET
; =========================================================================================
; Call Main ROM's Stop automatic scrolling routine
; =========================================================================================
4C56H RST 1 ; Call main ROM at address in following 2 bytes
4C57H DW 423FH
4C59H RET
; =========================================================================================
; Call Main ROM's Resume Automatic Scrolling routine
; =========================================================================================
4C5AH RST 1 ; Call main ROM at address in following 2 bytes
4C5BH DW 4244H
4C5DH RET
; =========================================================================================
; Call Main ROM's Get char at M and convert to uppercase routine
; =========================================================================================
4C5EH RST 1 ; Call main ROM at address in following 2 bytes
4C5FH DW 0FE8H
4C61H RET
; =========================================================================================
; Call Main ROM's Get file descriptor for file in A routine
; NOT CALLED
; =========================================================================================
4C62H RST 1 ; Call main ROM at address in following 2 bytes
4C63H DW 4C81H
4C65H RET
; =========================================================================================
; Call Main ROM's Update line addresses for current BASIC program routine
; =========================================================================================
4C66H RST 1 ; Call main ROM at address in following 2 bytes
4C67H DW 05F0H
4C69H RET
; =========================================================================================
; Call Main ROM's Copy CO header bytes (6) from (HL) to "active" CO Header storage area routine
; =========================================================================================
4C6AH RST 1 ; Call main ROM at address in following 2 bytes
4C6BH DW 253DH
4C6DH RET
; =========================================================================================
; Call Main ROM's print CO address, length and invocation address to LCD routine
; =========================================================================================
4C6EH RST 1 ; Call main ROM at address in following 2 bytes
4C6FH DW 25A4H
4C71H RET
; =========================================================================================
; Call Main ROM's Process SAVEM arguments for address, length and entry point routine
; =========================================================================================
4C72H RST 1 ; Call main ROM at address in following 2 bytes
4C73H DW 2346H
4C75H RET
Navigate to: