home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
SIMTEL
/
CPMUG
/
CPMUG032.ARK
/
TBASICIO.ASM
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
19KB
|
707 lines
;
; TARBELL CASSETTE BASIC I/O SYSTEM
; LAST CHANGED 8-23-78
;
; THIS INPUT/OUTPUT SOURCE USES CONDITIONAL
; ASSEMBLIES TO ACTIVATE DIFFERENT PARTS OF
; THE CODE FOR DIFFERENT PURPOSES. NOTE THAT
; SEVERAL EQU'S BELOW ARE SET EITHER TO TRUE
; (-1) OR FALSE (0). THESE VALUES ARE THEN
; USED WITH THE PSUEDO-OPS "IF" AND "ENDIF"
; TO INHIBIT THE ASSEMBLY OF SECTIONS OF CODE.
; THIS IS A FEATURE OF THE CP/M ASSEMBLER.
;
TRUE EQU 0FFFFH ;FOR CONDITIONAL ASSEMBLIES.
FALSE EQU NOT TRUE
;
CPM EQU TRUE ;TRUE FOR CP/M DISK SYSTEMS.
DISK EQU TRUE ;TRUE FOR DISK VERSION.
STD EQU FALSE ;TRUE FOR STANDARD CONSOLE.
; PORTS FOR STANDARD I/O SYSTEM.
CONSP EQU 0 ;CONSOLE STATUS PORT.
CONDP EQU 1 ;CONSOLE DATA PORT.
CONIM EQU 01H ;CONSOLE INPUT MASK.
CONOM EQU 80H ;CONSOLE OUTPUT MASK.
LSTSP EQU 2 ;LISTER STATUS PORT.
LSTDP EQU 3 ;LISTER DATA PORT.
LSTOM EQU 080H ;LISTER OUTPUT MASK.
; PORTS FOR TARBELL CASSETTE I/O.
CASC EQU 6EH ;CASSETTE STATUS PORT.
CASD EQU 6FH ;CASSETTE DATA PORT.
; CP/M BIOS JUMP VECTOR OFFSETS.
CONST EQU 3 ;CONSOLE STATUS OFFSET.
CONIN EQU 6 ;CONSOLE INPUT OFFSET.
CONOT EQU 9 ;CONSOLE OUTPUT OFFSET.
LIST EQU 12 ;LIST OUTPUT OFFSET.
; CP/M COMMON LOCATIONS.
BDOS EQU 5 ;MAIN ENTRY POINT TO BDOS.
FCB EQU 5CH ;DEFAULT FILE CONTROL BLOCK.
TBUFF EQU 80H ;DEFAULT BUFFER LOCATION.
; ENTRY POINTS INTO TARBELL BASIC INTERPRETER.
BASIC EQU 0500H ;START OF TBASIC INTERPRETER.
CHANL EQU BASIC+3 ;ADR OF ADR OF CHANNEL TABLE.
TRMNL EQU BASIC+5 ;ADR OF ADR OF TERMINAL TABLE.
SSSS EQU BASIC+7 ;ADR OF ADR OF END OF MEMORY.
CNVRA EQU BASIC+9 ;ADR OF ADR OF NO. OF DIGITS.
FPRA6 EQU BASIC+11 ;ADR OF ADR OF USR ROUTINE.
MODES EQU BASIC+13 ;ADR OF ADR OF MODES TABLE.
FSRC EQU BASIC+15 ;ADR OF ADR OF START OF PROGRAM.
ESRC EQU BASIC+17 ;ADR OF ADR OF END OF PROGRAM.
;
;
ORG 100H ;NORMAL LOAD ADDRESS.
JMP INIT ;GO TO INITIALIZATION.
CONI: JMP CONINP ;CONSOLE INPUT ROUTINE.
CONO: JMP CONOUT ;CONSOLE OUTPUT ROUTINE.
SPAR: NOP!NOP!RET ;FOR SPARE I/O ROUTINE.
LSTO: JMP LSTOUT ;LISTING OUTPUT ROUTINE.
RDRI: NOP!NOP!RET ;FOR READER INPUT ROUTINE.
PUNO: NOP!NOP!RET ;FOR PUNCH OUTPUT ROUTINE.
DSKI: JMP DSKINP ;DISK INPUT ROUTINE.
DSKO: JMP DSKOUT ;DISK OUTPUT ROUTINE.
CASI: JMP CASINP ;CASSETTE INPUT ROUTINE.
CASO: JMP CASOUT ;CASSETTE OUTPUT ROUTINE.
USR: JMP USRSUB ;HOP TO USER SUBROUTINE.
;
INIT:
IF NOT CPM ;IF NOT CPM, LET BASIC
LXI H,1 ;FIGURE END OF MEMORY.
ENDIF
IF CPM AND NOT DISK ;IF NOT DISK VERSION,
LHLD 1 ;GET START OF BIOS.
ENDIF
IF CPM AND DISK ;IF DISK VERSION,
XRA A ;SET DISK I/O FLAG = 0.
STA DSKFLG
LHLD 6 ;GET START OF CP/M.
ENDIF
DCX H ;DECREMENT BELOW IT.
XCHG ;PUT IN D&E.
LHLD SSSS ;SET TOP OF MEMORY.
MOV M,E ;PUT TOP ADR
INX H ;AT SSSS.
MOV M,D
LHLD CNVRA ;GET ADR OF NO. OF DIGITIS.
MVI M,10 ;MAKE IT TEN.
LXI H,USR ;GET ADR OF USER SUBROUTINE.
XCHG ;PUT INTO D&E.
LHLD FPRA6 ;GET LINKING ADDRESS.
MOV M,E ;PUT ADR OF USER ROUTINE
INX H
MOV M,D ;AT FPRAA+6 IN BASIC.
LHLD CHANL ;GET ADR OF CHANNEL TABLE.
LXI D,JADR ;GET ADR OF JMP ADR TABLE.
MVI B,20 ;MOVE ADDRESS FROM THERE
CALL MOVE ;TO BASIC'S CHANNEL TABLE.
LXI D,IMODES ;GET ADR OF INITIAL MODES.
LHLD MODES ;GET ADR OF MODES TABLE.
MVI B,10 ;BYTE COUNT = 10.
CALL MOVE ;INITIALIZE THE MODES TABLE.
LHLD TRMNL ;GET ADR OF TERMINAL TABLE.
INX H!INX H!INX H ;H&L = H&L+3
MVI M,72 ;SET CONSOLE TERM WIDTH.
INX H!INX H ;H&L = H&L+2.
MVI M,7FH ;SET CONSOLE RUBOUT.
LXI D,10 ;SET D&E = 10.
DAD D ;H&L = H&L+10.
MVI M,72 ;SET LISTING WIDTH.
INX H ;GET LIST LOC #2.
MVI M,0 ;PUT ZERO IN IT.
INX H ;GET LIST LOC #3.
MVI M,0BH ;PUT 0B INTO IT.
JMP BASIC ;HOP INTO TARBELL BASIC.
;
; JADR - I/O JUMP ADDRESS TABLE, GETS MOVED
; INTO BASIC'S CHANNEL TABLE AT INITIALIZATION.
;
JADR: DW CONI ;CONSOLE INPUT ADDRESS.
DW CONO ;CONSOLE OUTPUT ADDRESS.
DW CASI ;CASSETTE INPUT ADDRESS.
DW CASO ;CASSETTE OUTPUT ADDRESS.
DW SPAR ;SPARE I/O ADDRESS.
DW LSTO ;LISTING OUTPUT ADDRESS.
DW RDRI ;READER INPUT ADDRESS.
DW PUNO ;PUNCH OUTPUT ADDRESS.
DW DSKI ;DISK INPUT ADDRESS.
DW DSKO ;DISK OUTPUT ADDRESS.
;
; MOVE - MOVE THE NUMBER OF BYTES SPECIFIED BY
; REGISTER B, FROM THE ADDRESS IN D&E TO THE
; ADDRESS IN H&L.
;
MOVE: LDAX D ;GET A BYTE.
MOV M,A ;PUT A BYTE.
INX H ;INCREMENT H&L.
INX D ;INCREMENT D&E.
DCR B ;DECREMENT COUNTER.
JNZ MOVE ;GO TILL COUNTER=0.
RET ;RETURN FROM MOVE.
;
; IMODES - INITIAL MODES TABLE FOR I/O DEVICES.
; THIS GETS TRANSFERRED FROM HERE TO BASIC'S
; MODES TABLE UPON INITIALIZATION. AFTER THAT,
; BASIC'S MODES TABLE MAY BE CHANGED FROM A
; RUNNING BASIC PROGRAM BY USING THE ASSIGN
; AND DROP STATEMENTS TO SET & RESET BITS.
;
;LOG. DEV. # 76543210 ;PHYSICAL DEVICE.
IMODES: DB 00000001B ;KEYBOARD INPUT.
DB 00000010B ;CONSOLE PRINTER.
IF NOT DISK ;IF NOT DISK VERSION.
DB 00010100B ;CASSETTE INPUT.
DB 00101000B ;CASSETTE OUTPUT.
ENDIF
IF DISK ;IF DISK VERSION,
DB 00000000B ;CASSETTE INPUT.
DB 00000000B ;CASSETTE OUTPUT.
ENDIF
DB 00000000B ;SPARE INPUT/OUTPUT.
DB 00000000B ;LISTING OUTPUT.
DB 00000000B ;READER INPUT.
DB 00000000B ;PUNCH OUTPUT.
IF DISK ;IF DISK VERSION,
DB 00010100B ;DISK INPUT.
DB 00101000B ;DISK OUTPUT.
ENDIF
IF NOT DISK ;IF NOT DISK VERSION,
DB 00000000B ;DISK INPUT.
DB 00000000B ;DISK OUTPUT.
ENDIF
;
; CONOUT - PRINT THE CHARACTER IN REGISTER A
; ONTO THE CONSOLE OUTPUT DEVICE, USUALLY A
; TELETYPEWRITER OR CRT TERMINAL. IF THE
; CHARACTER IS A CARRIAGE-RETURN, ADD A
; LINE-FEED. IF THE CHARACTER IS A RUBOUT,
; ECHO A BACKSPACE.
;
CONOUT: PUSH H ;SAVE H&L.
PUSH D ;SAVE D&E.
PUSH B ;SAVE B&C.
PUSH PSW ;SAVE A&PSW.
CPI 7FH ;IS IT RUBOUT?
JNZ ECHO ;IF NOT, ECHO.
MVI A,08H ;IF SO, GET BACKSPACE.
IF CPM ;IF CP/M I/O,
CALL IO ;PRINT CHARACTER IN A.
DB CONOT
MVI A,20H ;PRINT SPACE.
CALL IO
DB CONOT
MVI A,08H ;PRINT BACKSPACE.
ECHO: CALL IO
DB CONOT
ENDIF
IF STD ;IF STANDARD I/O,
CALL CONOTS ;PRINT CHARACTER IN A.
MVI A,20H ;PRINT SPACE.
CALL CONOTS
MVI A,08H ;PRINT BACKSPACE AGAIN.
ECHO: CALL CONOTS
ENDIF
POP PSW ;RESTORE A&PSW.
POP B ;RESTORE B&C.
POP D ;RESTORE D&E.
POP H ;RESTORE H&L.
RET ;RETURN FROM CONOUT.
IF STD ;IF STANDARD I/O,
CONOTS: PUSH PSW ;SAVE REGISTER A & STATUS.
CONOTL: IN CONSP ;READ CONSOLE STATUS.
ANI CONOM ;LOOK AT OUTPUT STATUS BIT.
JNZ CONOTL ;WAIT UNTIL READY.
POP PSW ;GET CHARACTER.
OUT CONDP ;PRINT IT.
RET ;RETURN FROM CONOT.
ENDIF
;
; CONINP - READ A BYTE FROM THE CONSOLE KEYBOARD INTO
; REGISTER A. IF THIS ROUTINE IS ENTERED WITH THE
; 8080 ZERO FLAG SET, IT IS A CHECK FOR CONTROL-C.
; IN THIS CASE, A CHECK IS MADE TO SEE IF A CONTROL-C
; KEY HAS BEEN PUSHED. IF IT HASN'T, A RETURN IS
; MADE WITH THE ZERO FLAG CLEARED. IF IT HAS, A
; RETURN IS MADE WITH THE ZERO FLAG SET.
;
CONINP: JZ CHKST ;IF ZERO, MUST BE STATUS CHECK.
IF CPM ;IF CP/M I/O,
CALL IO ;READ KEYBOARD.
DB CONIN
ENDIF
IF STD ;IF STANDARD I/O,
CALL CONINS ;READ KEYBOARD.
ENDIF
RET ;RETURN FROM CONINP.
CHKST: PUSH H ;SAVE H&L.
PUSH D ;SAVE D&E.
PUSH B ;SAVE B&C.
IF CPM ;IF CP/M I/O,
CALL IO ;CHECK KEYBOARD STATUS.
DB CONST
ENDIF
IF STD ;IF STANDARD I/O,
CALL CHKSTS ;CHECK KEYBOARD STATUS.
ENDIF
POP B ;RESTORE B&C.
POP D ;RESTORE D&E.
POP H ;RESTORE H&L.
CMA ;COMPLEMENT RESULT.
ORA A ;SET FLAGS.
RNZ ;RETURN IF NO KEY PUSH.
CHKST1:
IF CPM ;IF CP/M I/O,
CALL IO ;READ KEYBOARD.
DB CONIN
ENDIF
IF STD ;IF STANDARD I/O,
CALL CONINS ;READ KEYBOARD.
ENDIF
CPI 3 ;SET ZERO FLAG IF CTL-C.
RZ ;RETURN IF CTL-C.
CPI 13H ;IS IT A CTL-S?
JZ CHKST1 ;IF SO, READ KB AGAIN.
RET ;RETURN FROM CONINP.
IF STD ;IF STANDARD I/O,
;
; CONINS - STANDARD READ FROM KEYBOARD.
;
CONINS: IN CONSP ;READ CONSOLE STATUS.
ANI CONIM ;LOOK AT INPUT STATUS BIT.
JNZ CONINS ;LOOP UNTIL READY.
IN CONDP ;READ THE CHARCTER.
ANI 7FH ;STRIP PARITY BIT OFF.
RET ;RETURN FROM CONINS.
;
; CHKSTS - STANDARD CONSOLE STATUS ROUTINE.
;
CHKSTS: IN CONSP ;READ CONSOLE STATUS.
ANI CONIM ;LOOK AT KB READY BIT.
MVI A,0 ;SET A=0 FOR RETURN.
RNZ ;NOT READY WHEN NOT ZERO.
CMA ;IF READY, A=FF.
RET ;RETURN FROM CHKSTS.
ENDIF
IF CPM ;IF CP/M INPUT/OUTPUT,
;
; IO - PERFORM AN INPUT OR OUTPUT OPERATION USING
; CP/M'S BIOS (BASIC INPUT/OUTPUT SYSTEM). THE
; BYTE FOLLOWING THE CALL TO THIS ROUTINE IS AN
; OFFSET WHICH IS ADDED TO THE BIOS JUMP VECTOR
; ADDRESS TO DETERMINE THE CORRECT ENTRY POINT
; TO BIOS.
;
IO: XTHL ;GET ADDRESS OF OFFSET.
MOV E,M ;PUT OFFSET IN D&E.
MVI D,0
INX H ;MAKE RETURN ADDRESS RIGHT.
XTHL ;PUT BACK ONTO STACK.
LHLD 1 ;GET ADDRESS OF IO VECTOR.
DAD D ;ADD OFFSET.
MOV C,A ;OUTPUT GOES IN C.
PCHL ;JUMP TO IO ROUTINE.
ENDIF
;
; LSTOUT - PRINT THE CHARACTER IN REGISTER A ON THE
; LISTING DEVICE. IF IT'S A CARRIAGE-RETURN, ADD
; A LINE-FEED.
;
LSTOUT: PUSH PSW ;SAVE REG A AND PSW.
PUSH B ;SAVE B&C.
IF CPM ;IF CP/M I/O,
CALL IO ;PRINT CHARACTER.
DB LIST
ENDIF
IF STD ;IF STANDARD I/O,
CALL LSTOUS ;PRINT CHARACTER.
ENDIF
POP B ;RESTORE B&C.
POP PSW ;RESTORE REG A AND PSW.
RET ;RETURN FROM LSTOUT.
IF STD ;IF STANDARD I/O,
;
; LSTOUS - STANDARD LISTING DEVICE ROUTINE.
;
LSTOUS: PUSH PSW ;SAVE CHARACTER.
LSTOUL: IN LSTSP ;READ STATUS.
ANI LSTOM ;LOOK AT STATUS BIT.
JNZ LSTOUL ;WAIT TILL READY.
POP PSW ;GET CHARACTER BACK.
PUSH PSW ;BACK AGAIN.
CPI 7FH ;IS IT BACKSPACE?
JNZ LSTECH ;HOP IF NOT.
MVI A,'\' ;PRINT BACKSLASH INSTEAD.
LSTECH: OUT LSTDP ;PRINT CHARACTER.
POP PSW ;RECOVER ORIG. CHAR.
RET ;RETURN FROM LSTOUS.
ENDIF
;
; CASINP - READ A BYTE FROM CASSETTE RECORDER.
; BYTE RETURNS IN REGISTER A. IF THE CARRY
; FLAG IS SET UPON RETURN FROM THIS ROUTINE,
; A TAPE READ ERROR HAS OCCURED.
;
CASINP: RZ ;RETURN IF EITHER FLAG SET.
JNC CASINC ;IF CARRY,
ORA A ;CLEAR IT AND QUIT.
RET
CASINC: PUSH H ;SAVE H&L.
PUSH D ;SAVE D&E.
PUSH B ;SAVE B&C.
LDA CASIB ;GET BYTE COUNT.
ORA A ;IF IT'S NOT ZERO,
JNZ CASIM ;MOVE BYTE FROM BUFFER.
CALL CTRD ;READ FROM CASSETTE.
CASIR: JZ CASINE ;NO ERROR IF ZERO SET.
STC ;OTHERWISE, SET CARRY,
JMP CASIRT ;RETURN WITH ERROR.
CASINE: MOV A,B ;GET BYTE COUNT.
LXI H,IBUF ;INITIALIZE BUFFER POINTER.
SHLD CASIHL
CASIM: LHLD CASIHL ;LOAD BUFFER POINTER.
CASIL1: MOV C,M ;GET BYTE FROM BUFFER.
INX H ;INCREMENT POINTER.
SHLD CASIHL ;SAVE THE POINTER.
DCR A ;DECREMENT BYTE COUNT.
STA CASIB ;SAVE IT.
MOV A,C ;GET DATA BYTE.
ORA A ;CLEAR CARRY.
CASIRT: POP B ;RESTORE B&C.
POP D ;RESTORE D&E.
POP H ;RESTORE H&L.
RET
;
; CASOUT - OUTPUT ONE BYTE TO CASSETTE RECORDER.
; ON ENTRY, IF REG A=1, INITIALIZE.
; IF CARRY SET, END OF TRANSFER.
; DATA BYTE IS IN REGISTER A.
;
CASOUT: PUSH H ;SAVE ALL REGISTERS.
PUSH D
PUSH B
PUSH PSW
JZ CASOST ;IF Z=1, MUST BE START.
CASONS: LHLD CASOHL ;GET BUFFER POINTER.
LDA CASOB ;GET BYTE COUNT.
MOV B,A ;PUT INTO REG B.
POP PSW ;RESTORE REG A AND PSW.
PUSH PSW ;SAVE IT BACK.
JC CASOEN ;IF CARRY, MUST BE END.
CASOL1: MOV M,A ;PUT BYTE INTO BUFFER.
INX H ;INCREMENT POINTER.
SHLD CASOHL ;SAVE THE POINTER.
INR B ;INCREMENT BYTE COUNT.
MOV A,B ;SAVE NEW BYTE COUNT.
STA CASOB
CPI 128 ;128 BYTES YET?
JNZ REGRES ;RETURN IF NOT.
CASOEN: MOV A,B ;GET BYTE COUNT.
ORA A ;IF IT'S ZERO,
JZ REGRES ;RETURN.
LXI H,OBUF ;GET ADDRESS OF BUFFER.
CALL CTWT ;IF SO, WRITE BUFFER.
CASOST: LXI H,OBUF ;GET ADDRESS OF OUTPUT BUFFER.
SHLD CASOHL ;INITIALIZE POINTER WITH IT.
XRA A ;SET BYTE COUNT=0.
STA CASOB
REGRES: POP PSW ;RESTORE PSW&A.
POP B ;RESTORE B&C.
POP D ;RESTORE D&E.
POP H ;RESTORE H&L.
RET ;RETURN FROM REGRES.
;
; DSKINP - READ A BYTE FROM THE CURRENT DISK FILE.
; BYTE RETURNS IN REGISTER A. IF THE CARRY FLAG
; IS SET UPON RETURN FROM THIS ROUTINE, A DISK
; READ ERROR HAS OCCURED.
;
DSKINP:
IF DISK ;IF DISK VERSION,
RZ ;RETURN IF EITHER FLAG SET.
JNC DSKINC ;IF CARRY,
ORA A ;CLEAR IT AND QUIT.
RET
DSKINC: PUSH H ;SAVE H&L.
PUSH D ;SAVE D&E.
PUSH B ;SAVE B&C.
LXI H,DSKFLG ;GET ADR OF DISK FLAG.
XRA A ;SET A = ZERO.
CMP M ;IS DISK FLAG = 0?
JNZ DSKIRB ;HOP AROUND READ IF NOT.
MVI M,0FFH ; SET DISK FLAG = READ MODE.
CALL DSKRD ;READ FIRST BLOCK FROM DISK.
JC CASIRT ;RETURN IF CARRY (ERROR).
DSKIRB: LHLD DSKHL ;GET BUFFER POINTER.
MOV A,M ;GET BYTE FROM BUFFER.
INX H ;INCREMENT POINTER.
SHLD DSKHL ;SAVE IT.
LXI H,DSKCTR ;GET ADR OF BYTE COUNT.
ORA A ;CLEAR CARRY FLAG!!!!
INR M ;INCREMENT IT.
JP CASIRT ;RETURN IF NOT 128 YET.
PUSH A ;SAVE DATA BYTE ON STACK.
CALL DSKRD ;READ FROM DISK.
POP B ;GET DATA BYTE BACK FROM
MOV A,B ;STACK WITHOUT CHANGING PSW.
JMP CASIRT ;RESTORE REGISTERS & RETURN.
ENDIF
;
; DSKOUT - OUTPUT ONE BYTE TO CURRENT DISK FILE.
; ON ENTRY, IF REG A=1, INITIALIZE.
; IF CARRY SET, END OF TRANSFER.
; DATA BYTE IS IN REGISTER A.
;
DSKOUT:
IF DISK ;IF DISK VERSION,
RZ ;RETURN IF START FLAG.
RC ;RETURN IF END FLAG.
PUSH H ;SAVE ALL REGISTERS.
PUSH D
PUSH B
PUSH PSW
DSKPUT: LHLD DSKHL ;GET BUFFER POINTER.
MOV M,A ;PUT BYTE INTO BUFFER.
INX H ;INCREMENT POINTER.
SHLD DSKHL ;UPDATE POINTER.
MVI A,1 ;SET DISK WRITE MODE.
STA DSKFLG
LXI H,DSKCTR ;GET ADR OF BYTE COUNT.
INR M ;INCREMENT BYTE COUNT.
CM DSKWT ;IF 128, WRITE TO DISK.
JMP REGRES ;RESTORE & RETURN.
ENDIF
IF DISK ;IF DISK VERSION,
;
; USRSUB - THIS IS THE SUBROUTINE THAT GETS
; CALLED BY THE USR FUNCTION IN TARBELL BASIC.
; THE ARGUMENT OF THE FUNCTION COMES IN D&E.
; IF D&E = ZERO, IT MEANS TO CLOSE A FILE.
; IF D&E = ONE, IT MEANS TO OPEN CURRENT FILE.
; IF D&E FROM 128 TO 255, GOTO ZERO.
; IF D&E => 256, D&E CONTAINS THE ADDRESS OF A
; STRING WHICH IS THE NAME OF THE FILE TO OPEN.
;
USRSUB: MOV A,D ;CHECK TO SEE IF
ORA A ;IS D=0?
JNZ USRS2 ;IF NOT, MUST BE NAME.
MOV A,E ;IS E=0 TOO?
ORA A ;IF SO,
JZ DSKCL ;JUST CLOSE FILE.
JM 0 ;IF MSB = 1 GOTOT 0.
DCR A ;IF E WAS 1,
JZ DSKOP ;OPEN WITH PRESENT NAME.
USRS2: PUSH D ;SAVE D&E.
LXI D,BFCB ;GET ADR OF BLANK FCB.
LXI H,FCB ;GET ADR OF FCB.
MVI B,16 ;GET LENGTH OF AREA.
CALL MOVE ;SET FCB TO BLANK.
POP D ;RESTORE D&E.
LXI H,FCB+1 ;GET ADR OF FCB+1.
MVI C,11 ;MAXIMUM OF 11 CHARS.
USRS1: LDAX D ;GET CHAR FROM STRING.
ANI 7FH ;CLEAR MSB.
MOV M,A ;PUT INTO FCB.
INX H ;INCREMENT POINTERS.
LDAX D ;GET CHAR AGAIN.
INX D ;INCREMENT D&E.
DCR C ;DECREMENT COUNTER.
JZ DSKOP ;IF 11 CHARS, OPEN.
ORA A ;IS MSB SET?
JP USRS1 ;IF NOT MSB, GET ANOTHER.
;
; DSKOP - OPEN THE DISK FILE WHOSE NAME IS IN
; THE DEFAULT FILE CONTROL BLOCK.
;
DSKOP: LDA DSKFLG ;GET DISK MODE FLAG.
ORA A ;WAS FILE OPEN?
CNZ DSKCL ;CLOSE IF FILE OPEN.
CALL DSKRS ;RESET DISK PTR & CTR.
MVI C,15 ;OPEN FILE.
LXI D,FCB ;DEFAULT FCB ADR.
CALL BDOS ;DO IT.
INR A ;WAS FILE FOUND?
MVI A,0 ;SET NR = 0.
STA FCB+32
RNZ ;RETURN IF FILE FOUND.
MVI C,22 ;OTHERWISE MAKE FILE.
LXI D,FCB ;FILE CTL BLOCK ADR.
CALL BDOS ;DO IT.
MVI D,0 ;PUT A INTO D&E.
MOV E,A
INR A ;WAS THERE ROOM?
JNZ DSKOP ;OPEN IF SO.
RET ;RETURN IF NOT.
;
; BFCB - BLANK FILE CONTROL BLOCK.
;
BFCB: DB 0,' ',0,0,0,0
;
; DSKCL - CLOSE THE DISK FILE WHOSE NAME IS IN
; THE DEFAULT FILE CONTROL BLOCK.
;
DSKCL: LDA DSKFLG ;GET DISK FLAG.
INR A ;IF IT WAS = FF,
JZ DSKCLR ;MUST HAVE BEEN READING.
LHLD DSKHL ;GET DISK BUFFER PTR.
MVI M,1AH ;PUT IN END-OF-FILE.
CALL DSKWT ;WRITE LAST RECORD.
XRA A ;SET DISK MODE INACTIVE.
DSKCLR: STA DSKFLG
MVI C,16 ;CLOSE FILE CODE.
LXI D,FCB ;DEFAULT FCB ADR.
CALL BDOS ;CLOSE IT.
RET
;
; DSKRD - READ A SECTOR FROM THE CURRENT DISK
; FILE INTO MEMORY AT ADDRESS 0080H.
;
DSKRD: CALL DSKRS ;RESET POINTER & COUNTER.
MVI C,20 ;READ NEXT RECORD.
LXI D,FCB ;GET ADR OF FCB.
CALL BDOS
ORA A ;SET FLAGS.
RZ ;RETURN IF NO ERRORS.
STC ;SET CARRY IF ERROR.
RET ;RETURN FROM DSKRD.
;
; DSKWT - WRITE A SECTOR FROM THE BUFFER AT
; ADDRESS 0080H TO THE CURRENT DISK FILE.
; ALSO RESET DISK BUFFER POINTER & COUNTER.
;
DSKWT: MVI C,21 ;WRITE NEXT RECORD.
LXI D,FCB ;GET ADR OF FCB.
CALL BDOS
DSKRS: LXI H,TBUFF ;GET DISK BUFFER ADR.
SHLD DSKHL ;INITIALIZE POINTER.
XRA A ;SET BYTE COUNT = 0.
STA DSKCTR
RET
ENDIF
IF NOT DISK ;IF NOT DISK VERSION,
USRSUB: JMP 0 ;JUST HOP TO ZERO.
ENDIF
;
; CTWT - WRITE A BLOCK TO CASSETTE.
;
CTWT: LXI D,187*2 ;GET COUNT FOR 2 SECONDS.
DELAY: MVI A,3CH ;WRITE START BYTE.
CALL CASW
DCX D ;DECREMENT COUNT.
MOV A,D ;IF D&E ARE
ORA E ;NOT YET ZERO,
JNZ DELAY ;KEEP COUNTING DOWN.
MVI A,0E6H ;WRITE SYNC BYTE.
CALL CASW
MVI C,0 ;CLEAR CHECKSUM.
MVI A,90H ;WRITE TYPE BYTE.
CALL CASW
MOV A,B ;WRITE LENGTH BYTE.
CALL CASW
MOV A,B ;GET LENGTH BYTE.
ORA A ;IF IT'S ZERO,
RZ ;RETURN FROM CTWT.
CTLP: MOV A,M ;WRITE DATA BYTE.
CALL CASW
INX H ;INCREMENT POINTER.
DCR B ;DECREMENT COUNTER.
JNZ CTLP ;REPEAT.
MOV A,C ;WRITE CHECKSUM.
CASW: PUSH PSW ;SAVE DATA ON STACK.
CALP: IN CASC ;READ CASSETTE STATUS.
ANI 20H ;LOOK AT BIT 5.
JNZ CALP ;WAIT UNTIL READY.
POP PSW ;RECOVER DATA.
OUT CASD ;WRITE A BYTE.
ADD C ;ADD TO CHECKSUM.
MOV C,A
RET ;RETURN FROM CASW.
;
; CTRD - READ A RECORD FROM CASSETTE.
;
CTRD: LXI H,IBUF ;GET BUFFER ADDRESS.
CALL CASW ;DELAY TO ALLOW LAST
CALL CASW ;BYTE TO PASS THROUGH.
MVI E,0 ;SET CHECKSUM=0.
MVI A,10H ;SET BIT 4=1.
OUT CASC ;RESET RECEIVER.
CALL CASR ;READ TYPE BYTE.
CALL CASR ;READ LENGTH BYTE.
MOV B,A ;PUT LENGTH BYTE IN B.
RZ ;RETURN IF LENGTH 0.
MOV C,A ;PUT LENGTH IN C TOO.
CRLOP: CALL CASR ;READ DATA BYTE.
MOV M,A ;PUT INTO MEMORY.
INX H ;INCREMENT POINTER.
DCR C ;DECREMENT COUNTER.
JNZ CRLOP ;READ ANOTHER BYTE.
MOV C,E ;PUT CHECKSUM IN C.
CALL CASR ;READ CHECKSUM.
SUB C ;SUBTRACT FROM A.
RET ;RETURN FROM CRLOP.
;
CASR: IN CASC ;READ CASS. STATUS.
ANI 10H ;CHECK BIT 4.
JNZ CASR ;WAIT TILL READY.
IN CASD ;READ DATA.
PUSH PSW ;SAVE REG A.
ADD E ;ADD TO CHECKSUM.
MOV E,A
POP PSW ;RESTORE A.
ORA A ;SET FLAGS.
RET ;RETURN FROM CASR.
;
;
; THIS PART SHOULD BE IN RAM.
;
DSKFLG: DS 1 ;0=NONE, 1=WRITE, FF=READ.
DSKHL: DS 2 ;DISK BUFFER POINTER.
DSKCTR: DB 0 ;DISK BYTE COUNTER.
CASOHL: DS 2 ;OUTPUT BUFFER POINTER.
CASOB: DB 0 ;CASS. OUTPUT BYTE COUNT.
OBUF: DS 128 ;CASS. OUTPUT BUFFER.
CASIHL: DS 2 ;INPUT BUFFER POINTER.
CASIB: DB 0 ;INPUT BYTE COUNT.
IBUF: DS 128 ;INPUT BUFFER.
END