* * * "CUTS" DEVICE FILE * * * TO ASSEMBLE: * * 1) SELECT THE TAPE UNIT THIS ASSEMBLY WILL DRIVE. DO THIS * BY SETTING THE EQUATED SYMBOL 'UNIT' TO THE PROPER * VALUE. (SEE 'UNIT SELECTION' BELOW) * 2) MAKE SURE THAT THE LOAD ADDRESS (THE 'ORG') IS CORRECT. * (SEE 'LOAD ADDRESSES' BELOW) * 3) ASSEMBLE THIS SOURCE TO A BINARY FILE WITH IMAGE TYPE. * (FOR EXAMPLE: I. ; THIS IS THE ASSEMBLER DEFAULT) * 4) SCRUNCH THE BINARY FILE TO ONE IMAGE BLOCK WITH THE * COMMAND: EXTR ,S * WHERE IS THE NAME YOU JUST ASSEMBLED * THIS DRIVER TO. * 5) CHANGE THE FILES'S TYPE TO 'DEVICE' BY THE COMMAND: * RETYPE ,D * * THE DRIVER IS NOW READY FOR USE. USE IT AS YOU WOULD ANY * OTHER FILE. FOR EXAMPLE: * COPY TARGET,CTAPE1 (CTAPE1 IS DRIVER) * WOULD PUT THE FILE 'TARGET' ON CASSETTE TAPE. * * CAUTION: TO READ FROM OR WRITE TO THE DEVICE FILE ITSELF * (WITH READ, COPY, GET, ETC.) YOU MUST FIRST * CHANGE ITS TYPE TO OTHER THAN 'D', DO THE * OPERATION, AND THEN CHANGE THE TYPE BACK TO 'D'. * FOR EXAMPLE: * RETYPE CTAPE2,? * GET /1,CTAPE2 * RETYPE CTAPE2/1,D * RETYPE CTAPE2,D * IS THE PROPER SEQUENCE TO COPY A DEVICE FILE FROM * DISK UNIT 0 (THE CURRENT DEFAULT) TO DISK UNIT 1. * * * FILE FORMAT * * A PTDOS CASSETTE FILE TAKES THE FORM OF A SERIES OF DATA * BLOCKS FOLLOWED BY AN EOF BLOCK. A DATA BLOCK HAS A * HEADER (FORMAT BELOW) FOLLOWED BY 400H BYTES OF DATA. * AN EOF BLOCK HAS A HEADER WITH THE BYTE COUNT IN THE HEADER * BEING ZERO, AND NO DATA. THE LAST DATA BLOCK BEFORE THE EOF * BLOCK MAY HAVE LESS THAN 400H BYTES OF DATA. ALL HEADERS * ARE FOLLOWED BY A CRC BYTE AND THERE IS A CRC BYTE AFTER * EVERY 256 DATA BYTES. * * HEADER FORMAT: * * ENTRY LENGTH STANDARD VALUE * (ALL WRITES USE THESE VALUES) * NAME 5 BYTES "PTFIL" * 1 BYTE ALWAYS 0 * TYPE 1 BYTE 'D'+80H DATA, NOT EXECUTABLE * BLOCK SIZE 2 BYTES AMOUNT OF DATA (400H OR LESS) * BLOCK # 2 BYTES INCREMENTS THROUGH FILE (NOTE: THIS * IS THE LOAD ADDRESS IN SOLOS/CUTER) * XEQ ADDR 2 BYTES 0000 NOT USED * SPARES 3 BYTES 00 00 00 NOT USED * * * **************************************************************** * * * UNIT SELECTION * UNIT EQU 1 1 FOR UNIT ONE OR 2 FOR UNIT TWO * * COPY NPTDEFS DISK SYSTEM DEFINITIONS. * * * PORT ASSIGNMENTS * STAPT EQU 0FAH STATUS/CONTROL PORT GENERAL TDATA EQU 0FBH TAPE DATA PORT * * BIT ASSIGNMENT MASKS * TAPE1 EQU 80H FOR TURNING TAPE UNIT 1 ON TAPE2 EQU 40H " " " UNIT 2 " TFE EQU 8 TAPE FRAMING ERROR TOE EQU 16 TAPE OVERFLOW ERROR TDR EQU 64 TAPE DATA READY TTBE EQU 128 TAPE TRANSMITTER BUFFER EMPTY * * CR EQU 0DH ASCII CHARACTER CARRIAGE RETURN LF EQU 0AH ASCII CHARACTER LINE FEED * * * LOAD ADDRESSES * * THE DRIVER FOR UNIT 1 MUST LOAD AT A DIFFERENT LOCATION * FROM THE UNIT 2 DRIVER SO THAT BOTH MAY BE USED AT THE SAME * TIME. A GOOD PLACE TO LOAD THE DRIVERS (UNIT 1 AND 2) IS * ABOVE THE DEBUGGER (>6300H) AND LOWER THAN YOUR BUFFER * AREA. MAKE SURE AN EDITOR DOESN'T OVERWRITE A DRIVER * AS THE DRIVER AREA IS NOT PROTECTED. * * NOTE: THIS DRIVER IS 032BH BYTES LONG SO AT LEAST THAT MANY * BYTES MUST SEPARATE THE TWO LOAD ADDRESSES. * IF 2-UNIT ORG FOR UNIT 1 ORG 7000H ENDF * IF 1-UNIT ORG FOR UNIT 2 ORG 732BH ENDF * * * * DRIVER DISPATCH TABLE * DTRB DW READBLOCK DTRNB DW READBLOCK READ NEXT BLOCK; SAME AS READ BLOCK DTRLB DW 0 READ LAST BLOCK NOT SUPPORTED DTWBR DW WRITBLOCK WRITE BLOCK, READ NEXT (0 BYTES READ) DTWB DW WRITBLOCK DTREW DW REWIND TURNS ON TAPE UNIT AND ISSUES A REWIND MESSAGE DTEOF DW ENDFILE WRITE A HEADER WITH A 0000 BYTE COUNT. DTCLO DW CLOSE EOF IF NECESSARY. DTSEK DW SEEK SPACE PAST EOF. (NOTE: NON-STANDARD SEEK) DTCTL DW 0 NO CONTROL OPERATION DTBLK DW 1024 BLOCK SIZE DTITO DB 0 IMMEDIATE TRANSFER OPTION OFF. DTINI DW INIT INITIALIZE. * INIT RET . NO INITIALIZATION NECESSARY. * * **************************************************************** **************************************************************** * * * READ ROUTINES * * * **************************************************************** * * * SPACE FORWARD PAST EOF * * ON ENTRY: * HL = BUFFER ADDRESS (IGNORED) * DE = MAXIMUM BYTE COUNT (IGNORED) * A = USER B AT CALL (IGNORED) * 16-BIT VALUE UNDER RETURN ADDRESS ON STACK IS * SEEK ADDRESS (REMOVED) * * RETURN: * CALL+1 : ERROR : SEEK ADDRESS OUT OF RANGE (NOT USED) * CALL+2 : SUCCESS : HL = SIZE OF BLOCK LOADED (WILL BE 0) * DE = CURSOR POSITION IN BLOCK (0) * * SEEK POP H REMOVE RETURN ADDRESS FROM STACK POP D SO THAT THE SEEK ADDRESS MAY BE GOTTEN RID OF. PUSH H REPLACE RETURN ADDRESS. * LDA DIRTY CAN'T SEEK AFTER WRITE. ORA A JNZ NOREAD ERROR. LDA EOFLG EOFLG SET MEANS WE WROTE ALSO ORA A JNZ NOREAD AND IS ALSO A NO-NO. * MVI B,3 DELAY CALL TAPEON AFTER TURNING THE TAPE ON. IN TDATA CLEAR UART FLAGS. * * LOOP PAST NEXT EOF * SPAO1 CALL RHEAD READ NEXT HEADER JNZ SPAO1 IF ERROR, TRY AGAIN. LHLD HBLOCK LOOK FOR ZERO BLOCK MOV A,H ORA L JNZ SPAO1 DIDN'T FIND IT YET. * SPAOF CALL RSETHEAD RESET HEADER BUFFER TO CORRECT VALUES. LXI D,0 RETURN DISPLACEMENT OF 0. LXI H,0 RETURN ZERO IN HL TOO FOR BYTE COUNT. JMP CALL2 TURN TAPE OFF AND RETURN TO CALL+2. * * **************************************************************** * * * READ BLOCK * * ON ENTRY: * HL = BUFFER ADDRESS TO READ TO * DE = MAXIMUM READ BYTE COUNT * * RETURN: * CALL+1 : ERROR : EOF ENCOUNTERED * CALL+2 : SUCCESS : HL = NUMBER OF BYTES READ * READBLOCK LDA DIRTY CAN'T READ AFTER WRITING. ORA A JNZ NOREAD ERROR. LDA EOFLG CAN'T READ AFTER EOFING EITHER. ORA A JNZ NOREAD ERROR. * PUSH H SAVE BUFFER ADDRESS. PUSH D SAVE COUNT. MVI B,3 DELAY CALL TAPEON AFTER TURNING ON THE TAPE IN TDATA CLEAR THE UART FLAGS. * TLOD1 CALL RHEAD READ PAST HEADER. JNZ TLOD1 IF ERROR START OVER. * LHLD HBLOCK GET BLOCK SIZE FROM HEADER MOV A,H ORA L JZ EOFIT 0000 BLOCK...END OF FILE REACHED * * COMPARE MAXIMUM COUNT TO BLOCK SIZE * POP D GET BACK MAXIMUM COUNT MOV A,L BLOCK SIZE IS STILL IN HL. SUB E MOV A,H SBB D JNC BLKOK MAX COUNT IS LESS SO USE IT FOR TRANSFER COUNT XCHG . OTHERWISE USE HEADER COUNT. * * DE HAVE CORRECT COUNT FOR TRANSFER * BLKOK POP H GET BACK ADDRESS TO READ TO. PUSH D SAVE COUNT FOR # OF BYTES READ RETURNED IN HL. * LOLOOP MOV A,D TEST COUNT OF BYTES LEFT TO READ ORA E JNZ READ256 STILL SOMETHING LEFT TO READ. * CALL RSETHEAD RESET HEADER BUFFER TO CORRECT VALUES. POP H GET BACK # OF BYTES READ TO RETURN TO CALLER. JMP CALL2 TURN OFF TAPE AND RETURN TO CALL+2. * READ256 LXI B,-256 READ THIS MANY PRIOR TO CRC TEST XCHG . COUNT TO HL FOR DAD B A LITTLE MATH. DECREASE COUNT BY APPROPRIATE AMOUNT. LXI B,0 READ COUNT OF 256 (IN B). INIT CRC COUNT (IN C) TO 0. JC RDBLK THERES AT LEAST 256 BYTES LEFT TO READ MOV B,L L HAS # OF BYTES LEFT TO READ (L WAS UNCHANGED BY DAD) LXI H,0 TELL DE WE'RE DONE * RDBLK XCHG . COUNT BACK TO DE. ADDRESS BACK TO HL. * RTBYT CALL TAPIN GET A CHARACTER. MOV M,A STORE IT INX H BUMP MEMORY LOCATION CALL CRCCA UPDATE CRC COUNT. DCR B COUNT DOWN JNZ RTBYT STILL MORE IF NOT ZERO. * CALL CRCCK CHECK CRC. JZ LOLOOP TEST OK. JMP CRCERROR TEST RESULT NOT SO GOOD. * * EOFIT POP H CLEAR THE STACK OF THE COUNT POP H AND THE ADDRESS. CALL RSETHEAD RESET HEADER BUFFER TO CORRECT VALUES. LXI H,0 RETURN THE FACT THAT 0 BYTES WERE READ. JMP CALL1 TURN OFF TAPE AND RETURN TO CALL+1. * * **************************************************************** * * * READ SUBROUTINES * * * * READ THE HEADER * * FIND 10 NULLS IN A ROW * RHEAD MVI B,10 FIND 10 NULLS RHEA1 CALL STAT WAIT FOR A CHAR TO BE READY TO READ. IN TDATA IGNORE ERROR CONDITIONS ORA A ZERO? JNZ RHEAD DCR B JNZ RHEA1 LOOP UNTIL 10 IN A ROW * * WAIT FOR THE START CHARACTER (01) * STARTWAIT CALL TAPIN GET A CHAR ORA A STILL NULLS? JZ STARTWAIT CPI 1 START CHAR? JNZ RHEAD NOT 0 OR 1, NOT BEGINNING OF HEADER. SEARCH AGAIN. * * NOW GET THE HEADER * LXI H,THEAD POINT TO BUFFER LXI B,HLEN*256 LENGTH OF HEADER IN 'B',C=0 (CRC COUNT) * RHED1 CALL TAPIN GET A BYTE MOV M,A STORE IT INX H INCREMENT ADDRESS CALL CRCCA UPDATE CRC COUNT. DCR B WHOLE HEADER YET? JNZ RHED1 LOOP UNTIL DONE * CALL CRCCK CHECK CRC COUNT RET . CALLING ROUTINE WILL CHECK FLAGS. * * * * CHECK THE CRC COUNT * * READ THE NEXT BYTE FORM THE TAPE AND COMPARE IT * TO THE VALUE IN REGISTER C. THE FLAGS ARE SET ON * RETURN. * CRCCK CALL TAPIN GET CRC BYTE. XRA C COMPARE IT WITH CALCULATED VALUE. RET * * * * WAIT FOR DATA READY * STAT IN STAPT TEST STATUS PORT. ANI TDR DATA READY? RNZ A CHARACTER IS NOW WAITING TO BE READ. * CALL CONTST WHILE WAITING, CHECK FOR QUIT CHAR. JZ STAT CONSOLE IS IDLE. CALL CONIN GET A CHAR FROM THE CONSOLE. ANI 7FH ZAP PARITY AND CHECK FOR QUIT CHAR (NULL - CONTROL @) JNZ STAT IF NOT QUIT THEN IGNORE IT. * * ABORT THE READ * JMP QUIT * * * GET NEXT CHAR FROM THE TAPE * TAPIN CALL STAT WAIT FOR CHAR TO BE READY. * TREDY IN STAPT GET STATUS AGAIN. ANI TFE+TOE DATA ERROR? JNZ FRAMERROR IF FRAMING OR OVERRUN ERROR IN TDATA GET THE DATA. RET * * * * RESET HEADER IN BUFFER * RSETHEAD LXI H,GOODHEAD ADDRESS OF PROPER HEADER LXI D,THEAD STANDARD HEADER BUFFER. MVI B,HLEN LENGTH OF HEADER: NUMBER OF BYTES TO MOVE. * RSETLOOP MOV A,M GET A CHAR OF THE GOOD HEADER. STAX D PUT IT IN HEADER BUFFER. INX H MOVE TO NEXT POSITION IN HEADER. INX D DCR B SEE IF WE HAVE HIT END OF HEADER. JNZ RSETLOOP NOPE, SO LOOP BACK. * RET * * **************************************************************** **************************************************************** * * * WRITE ROUTINES * * * **************************************************************** * * * WRITE BLOCK * * ON ENTRY: * HL = ADDRESS OF DATA TO WRITE * DE = COUNT OF BYTES TO WRITE * * RETURN: * CALL+1 : ERROR : EOF ENCOUNTERED (NOT USED) * CALL+2 : SUCCESS : HL = NUMBER OF BYTES READ (0000) * WRITBLOCK MVI A,1 MAKE A FLAG AND STA DIRTY SAY WE HAVE WRITTEN. XRA A MAKE A ZERO STA EOFLG TO SAY WE NO LONGER HAVE JUST WRITTEN AN EOF. CALL SAVEBLOCK WRITE THE BLOCK. LXI H,0 NO BYTES WERE READ (FOR RETURN). JMP CALL2 TURN OFF TAPE AND RETURN TO CALL+2. * * **************************************************************** * * * END FILE ROUTINE * * ON ENTRY: * HL = ADDRESS OF BLOCK TO WRITE OUT * DE = BYTE COUNT TO WRITE OUT * * RETURN: * CALL+1 : SUCCESS * ENDFILE MOV A,D SEE IF WE SHOULD WRITE ANY DATA FIRST. ORA E JZ NOSAVE NO, COUNT IS ZERO. CALL SAVEBLOCK YEP. TRANSFER COUNT WAS NON-ZERO. JMP DOEOF * NOSAVE LDA DIRTY MUST HAVE WRITTEN BEFORE EOF. ORA A JZ NOEOF ERROR, ATTEMPT TO EOF BEFORE WRITE. * DOEOF CALL EOF WRITE THE EOF. JMP CALL1 TURN OFF TAPE AND RETURN TO CALL+1 * * **************************************************************** * * * CLOSE FILE ROUTINE * CLOSE LDA DIRTY SEE IF FILE LEFT UNENDED AFTER A WRITE. ORA A CNZ EOF YES, SO ENDFILE IT JMP CALL1 TURN OFF TAPE AND RETURN TO CALL+1. * * **************************************************************** * * * REWIND * * ON ENTRY: * HL = ADDRESS TO READ FIRST BLOCK TO (NOT USED) * DE = MAXIMUM READ BYTE COUNT (NOT USED) * * RETURN: * CALL+1 : SUCCESS : HL = BYTES READ (0000) * REWIND LDA DIRTY SEE IF FILE LEFT UNENDED AFTER A WRITE. ORA A CNZ EOF YES, SO FINISH IT OFF. XRA A CLEAR EOF FLAG (SINCE WILL WE BE AT THE BEGINNING) STA EOFLG STA DIRTY AND THE JUST WRITTEN FLAG (BEING SAFE). LXI H,0 RESET BLOCK COUNTER. SHLD HADDR * POWER MVI B,1 DELAY CALL TAPEON AFTER TURNING ON THE TAPE. * LXI H,RWMES TELL THEM TO REWIND THE APPROPRIATE UNIT. CALL MESG * * CALL CONIN SEE IF WE ARE DONE REWINDING. ANI 7FH ZAP PARITY AND CHECK FOR NULL (QUIT). JZ QUIT ABORT OPERATION. PUSH PSW SAVE INPUT CHAR. CALL CRLF LET HIM KNOW THAT WE GOT SOMETHING. POP PSW GET INPUT CHAR BACK. CPI 0DH DONE RERWINDING? JNZ POWER NOPE, START OVER. * LXI H,0 NO BYTES READ. JMP CALL1 TURN OFF TAPE AND RETURN TO CALL+1. * * RWMES EQU $ * IF 2-UNIT MESSAGE FOR UNIT 1. ASC "REWIND TAPE UNIT 1" ENDF * IF 1-UNIT MESSAGE FOR UNIT 2. ASC "REWIND TAPE UNIT 2" ENDF * ASC " (HIT RETURN WHEN REWOUND) " DB 0 * * **************************************************************** * * * WRITE SUBROUTINES * * * * WRITE A BLOCK * * ON ENTRY: * HL = DATA ADDRESS * DE = NUMBER OF BYTES TO WRITE * SAVEBLOCK PUSH D SAVE WRITE COUNT. PUSH H SAVE WRITE FROM ADDRESS. * LHLD HADDR INCREMENT BLOCK COUNT. INX H SHLD HADDR * * START THE TAPE MVI B,4 LONG DELAY CALL TAPEON * POP D GET LOAD ADDRESS BACK. POP H DITTO COUNT. SHLD HBLOCK STORE BLOCK SIZE PUSH D SAVE ADDRESS AGAIN. * MVI D,50 WRITE 50 ZER0S; MAKE HEADER EASY TO FIND. NULOP XRA A THE ZERO TO WRITE. CALL WRBYT WRITE THE ZERO. DCR D CHECK COUNT. JNZ NULOP NOT DONE YET. * MVI A,1 CALL WRBYT WRITE START BYTE * * WRITE THE HEADER * LXI H,THEAD POINTER TO HEADER. LXI B,HLEN*256 HEADER LENGTH INTO B; CLEAR C FOR CRC COUNT * WLOOP MOV A,M GET A CHAR OF THE HEADER CALL WRBYT AND WRITE IT TO THE TAPE. INX H MOVE TO NEXT BYTE OF HEADER. DCR B ARE WE DONE? JNZ WLOOP NOT YET. * MOV A,C WRITE THE CRC BYTE. CALL WRBYT * * LHLD HBLOCK GET BACK # OF BYTES TO WRITE. XCHG POP H GET WRITE FORM ADDRESS BACK. * * DE HAS BYTES LEFT TO WRITE; HL HAS ADDRESS OF REMAINING DATA * WRLOP MOV A,D ALL DONE WRITING? (COUNT 0) ORA E JZ WRDONE YES, DONE WRITING * LXI B,-256 WRITE 256 BYTES AT A TIME (FOR CRC). XCHG COUNT TO HL FOR SUBSEQUENT DAD DAD B SUBTRACT 256 FROM COUNT MVI B,0 JC WDBLK CARRY SET MEANS STILL MORE THAN 256 BYTES TO WRITE. MOV B,L < 256 LEFT. L HAS REMAINING COUNT (UNCHANGED BY DAD) LXI H,0 INDICATE NO MORE BYTES LEFT TO WRITE. * WDBLK XCHG COUNT BACK TO DE; ADDRESS BACK TO HL. MVI C,0 INITIALIZE CRC COUNT. * WDBL1 MOV A,M GET A CHAR OF DATA CALL WRBYT AND WRITE IT. INX H MORE TO NEXT BYTE. DCR B DONE WRITING? JNZ WDBL1 STILL MORE. * MOV A,C WRITE THE CRC BYTE. CALL WRBYT JMP WRLOP LOOP UNTIL ALL DATA IS WRITTEN. * * WRDONE MVI B,1 DELAY BEFORE STOPPING. CALL DELAY RET * * * WRITE ONE BYTE TO THE TAPE * WRBYT PUSH PSW SAVE THE DATA. * WRWAT IN STAPT CAN WE WRITE YET? ANI TTBE CHECK FOR BUFFER EMPTY. JZ WRWAT LOOP UNTIL IT IS. * POP PSW GET DATA BACK OUT TDATA AND WRITE IT. CALL CRCCA UPDATE CRC COUNT. RET * * * * WRITE AN EOF * EOF LXI D,0 WRITE A BLOCK SIZE OF 0. LXI H,0 WRITE ADDRESS (DOESN'T MATTER). CALL SAVEBLOCK WRITE HEADER. (NO DATA SINCE COUNT IS 0) XRA A INDICATE NO LONGER JUST WROTE STA DIRTY BY ZEROING THE DIRTY FLAG. INR A MAKE A SET FLAG STA EOFLG TO INDICATE WE JUST WROTE AN EOF. LXI H,0 RESET BLOCK COUNTER. SHLD HADDR RET . AND GO BACK * * **************************************************************** **************************************************************** * * * GENERAL SUBROUTINES * * * **************************************************************** * * * TURN THE TAPE UNIT ON * * B : DELAY COUNT * TAPEON EQU $ * IF 2-UNIT SELECT WHICH UNIT TO TURN ON MVI A,TAPE1 ENDF * IF 1-UNIT THE ALTERNATE. MVI A,TAPE2 ENDF * OUT STAPT OUTPUT APPROPRIATE MASK TO STATUS/CONTROL PORT. CALL DELAY DO THE DELAY SPECIFIED BY B. RET * * * * TURN THE TAPE OFF * TAPOFF XRA A MAKE A ZERO TO OUTPUT TO OUT STAPT STATUS/CONTROL PORT (SHUT OFF BOTH UNITS). RET * * * DELAY LOOP * * B : DELAY COUNT * DELAY LXI D,0 INNER LOOP COUNT. DLOOP DCX D COUNT FROM FFFF DOWN TO 0. MOV A,D ORA E JNZ DLOOP DCR B ARGUMENT IN B IS NUMBER OF TIMES THROUGH OUTER LOOP. JNZ DELAY RET * * * * UPDATE THE CRC COUNT * CRCCA SUB C TAKE THE DATA IN A AND USE IT FOR CRC CALCULATION MOV C,A WITH CURRENT CRC VALUE IN C. XRA C CMA SUB C MOV C,A RET * * * * PRINT MESSAGES TO THE CONSOLE * MESG MOV A,M GET A CHAR OF THE MESSAGE ORA A AND TEST FOR END OF MESSAGE (0). RZ . IF SO THEN DONE PRINTING. CALL CONOUT PRINT A CHAR OF THE MESSAGE. INX H MOVE TO NEXT CHAR OF MESSAGE. JMP MESG * CRLF MVI A,CR CALL CONOUT MVI A,LF CALL CONOUT RET * * * * RETURN TO CALLER * CALL2 XTHL . SAVE HL AND GET RETURN ADDRESS. INX H MOVE RETURN ADDRESS TO CALL+2. INX H INX H XTHL . PUT EVERYTHING BACK WHERE IT BELONGS. * CALL1 CALL TAPOFF MAKE SURE TAPE UNITS ARE SHUT OFF. RET . RETURN TO CALLER. * * **************************************************************** **************************************************************** * * * ERROR HANDLING * * * **************************************************************** * * CRCERROR LXI H,CRCMESG JMP ERROR CRCMESG ASC "CRC ERROR" DB 0 * * QUIT LXI H,QUITMESG JMP ERROR QUITMESG ASC "QUIT" DB 0 * * NOREAD LXI H,NOREMESG JMP ERROR NOREMESG ASC "CAN'T READ AFTER WRITE" DB 0 * * NOEOF LXI H,NEOFMESG JMP ERROR NEOFMESG ASC "CAN'T EOF BEFORE WRITE" DB 0 * * FRAMERROR LXI H,FRAMMESG JMP ERROR FRAMMESG ASC "FRAMING OR OVERRUN ERROR" DB 0 * * * ERROR CALL TAPOFF TURN OFF BOTH TAPE UNITS. CALL MESG PRINT ERROR MESSAGE POINTED TO BY HL. CALL CRLF FINISH MESSAGE WITH A CARRIAGE RETURN AND LINE FEED. CALL ERRL0 INITIATE ERROR HANDLING (LEVEL 0). DB ERDRI "DRIVER ERROR" * * **************************************************************** **************************************************************** * * STORAGE AREA * * EOFLG DB 0 INDICATES AN EOF WAS JUST WRITTEN IF NON-ZERO. DIRTY DB 0 INDICATES A WRITE WAS JUST PERFORMED IF NON-ZERO. * * TAPE HEADER BUFFER (INITIALIZED) * THEAD ASC "PTFIL" FILE NAME. DB 0 HTYPE DB 'D'+80H MAKE FILE TYPE "DATA" AND NONEXECUTABLE. HBLOCK DW 0 BLOCK SIZE. HADDR DW 0 BLOCK NUMBER (SOLOS/CUTER USES THIS AS LOAD ADDRESS) XEQAD DW 0 HSPR DW 0 SPARES DB 0 * HLEN EQU $-THEAD * * GOODHEAD ASC "PTFIL" THIS HEADER IS NEVER CHANGED. DB 0 DB 'D'+80H DW 0 BLOCK SIZE DW 0 BLOCK NUMBER DW 0 XEQ ADDR DW 0 SPARES DB 0 * * END *