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
/
CPMUG025.ARK
/
FBIOS24.ASM
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
27KB
|
1,070 lines
; BASIC INPUT/OUTPUT OPERATING SYSTEM
; TARBELL ELECTRONICS
; 4-DRIVE VERSION OF 2-15-78
; (NOTE THAT CP/M VERSION 1.3 ONLY SUPPORTS 2 DRIVES,
; WHILE CP/M VERSION 1.4 WILL SUPPORT 4 DRIVES.)
;
; THIS MODULE CONTAINS ALL THE INPUT/OUTPUT
; ROUTINES FOR THE CP/M SYSTEM, INCLUDING
; THE DISK ROUTINES.
;
MSIZE EQU 24 ;MEMORY SIZE.
; THIS SECTION DEFINES THE I/O PORTS AND
; STATUS BITS. BY SETTING THE PROPER VALUES
; FOR THE EQU STATEMENTS, THE I/O MAY BE
; AUTOMATICALLY RECONFIGURED TO FIT MOST
; SITUATIONS. THE TRUE AND FALSE ONES
; CONTROL CONDITIONAL ASSEMBLIES OF DIFFERENT
; SECTIONS OF I/O ROUTINES TO FIT DIFFERENT
; INTERFACE REQUIREMENTS.
TRUE EQU 0FFFFH ;DEFINE VALUE OF TRUE.
FALSE EQU NOT TRUE ;DEFINE VALUE OF FALSE.
INTRP EQU FALSE ;TRUE IF INTERRUPTS ALLOWED.
STD EQU TRUE ;TRUE IF STANDARD I/O.
MSIO2 EQU FALSE ;TRUE IF MITS 2SIO.
ISIO2 EQU FALSE ;TRUE IF IMSAI SIO-2.
TUART EQU FALSE ;TRUE IF CROMEMCO TUART.
VDM EQU FALSE ;TRUE IF PROC TECH VDM.
SIO2 EQU MSIO2 OR ISIO2 OR TUART
OTHER EQU FALSE ;TRUE IF SOMETHING ELSE.
CSTAT EQU 0 ;CONSOLE STATUS PORT.
CCOM EQU 0 ;CONSOLE COMMAND PORT.
CDATA EQU 1 ;CONSOLE DATA PORT.
IF STD ;IF STANDARD I/O,
CKBR EQU 00000001B ;KEYBOARD READY BIT.
CPTR EQU 10000000B ;CONS OUTPUT RDY BIT.
ENDIF
IF MSIO2 ;IF MITS 2SIO,
CKBR EQU 00000001B ;KEYBOARD READY BIT.
CPTR EQU 00000010B ;PRINT READY BIT.
ENDIF
IF ISIO2 ;IF IMSAI SIO-2,
CKBR EQU 00000010B ;KEYBOARD READY BIT.
CPTR EQU 00000001B ;PRINT READY BIT.
ENDIF
IF TUART ;IF CROMEMCO TUART,
CKBR EQU 01000000B ;KEYBOARD READY BIT.
CPTR EQU 10000000B ;PRINT READY BIT.
ENDIF
IF OTHER ;IF SOMETHING ELSE,
CKBR EQU 00000010B ;KEYBOARD READY BIT.
CPTR EQU 10000000B ;PRINTER READY BIT.
ENDIF
CNULL EQU 1 ;CONSOLE NULL COUNT.
LSTAT EQU 2 ;LIST STATUS PORT.
LCOM EQU 2 ;LIST COMMAND PORT.
LDATA EQU 3 ;LIST DATA PORT.
LRBIT EQU CPTR ;LIST READY BIT.
LNULL EQU 2 ;LIST NULL COUNT.
DUAL EQU TRUE ;TRUE IF DUAL DRIVE.
FAST EQU TRUE ;TRUE IF FAST SEEK.
DISK EQU 0F8H ;DISK BASE ADDRESS.
DCOM EQU DISK ;DISK COMMAND PORT.
DSTAT EQU DISK ;DISK STATUS PORT.
TRACK EQU DISK+1 ;DISK TRACK PORT.
SECTP EQU DISK+2 ;DISK SECTOR PORT.
DDATA EQU DISK+3 ;DISK DATA PORT.
WAIT EQU DISK+4 ;DISK WAIT PORT.
DCONT EQU DISK+4 ;DISK CONTROL PORT.
RTCNT EQU 10 ;RETRY COUNT.
ORG MSIZE*1024-1536 ;FIRST ADDRESS.
CBASE EQU (MSIZE-17)*1024 ;BIAS FOR LARGER THAN 17K.
CPMB EQU CBASE+2900H ;START OF CPM.
BDOS EQU CBASE+3106H ;START OF BDOS.
CPML EQU $-CPMB ;LENGTH OF CPM SYSTEM-BIOS.
NSECTS EQU CPML/128 ;NUMBER OF SECTORS IN IT.
;
; I/O JUMP VECTOR
; THIS IS WHERE CPM CALLS WHENEVER IT NEEDS
; TO DO ANY INPUT/OUTPUT OPERATION.
; USER PROGRAMS MAY USE THESE ENTRY POINTS
; ALSO, BUT NOTE THAT THE LOCATION OF THIS
; VECTOR CHANGES WITH THE MEMORY SIZE.
;
JMP BOOT ;FROM COLD START LOADER.
WBOOTE: JMP WBOOT ;FROM WARM BOOT.
JMP CONST ;CHECK CONSOLE KB STATUS.
JMP CONIN ;READ CONSOLE CHARACTER.
JMP CONOT ;WRITE CONSOLE CHARACTER.
JMP LIST ;WRITE LISTING CHAR.
JMP PUNCH ;WRITE PUNCH CHAR.
JMP READER ;READ READER CHAR.
JMP HOME ;MOVE DISK TO TRACK ZERO.
JMP SELDSK ;SELECT DISK DRIVE.
JMP SETTRK ;SEEK TO TRACK IN REG A.
JMP SETSEC ;SET SECTOR NUMBER.
JMP SETDMA ;SET DISK STARTING ADR.
READN: JMP READ ;READ SELECTED SECTOR.
WRITEN: JMP WRITE ;WRITE SELECTED SECTOR.
; THESE ENTRY POINTS ADDED BY TARBELL ELECTRONICS.
JMP READN ;READ WITH NO HEAD LOAD.
JMP WRITEN ;WRITE WITH NO HEAD LOAD.
;
; BOOT
; THIS SECTION IS EXECUTED WHENEVER RESET AND RUN
; IS PUSHED, AFTER THE COLDSTART LOADER READS IN
; THE CPM SYSTEM.
;
BOOT: LXI SP,80H ;SET STACK POINTER.
IF INTRP ;IF INTERRUPTS ALLOWED,
EI ;ENABLE THEM HERE.
ENDIF
IF VDM ;IF PROC TECH VDM,
CALL CLR ;CLEAR VDM SCREEN.
ENDIF
IF STD ;IF STANDARD I/O,
NOP!NOP!NOP!NOP ;LEAVE SPACE FOR INIT.
NOP!NOP!NOP!NOP
NOP!NOP!NOP!NOP
NOP!NOP!NOP!NOP
ENDIF
IF MSIO2 ;IF MITS 2SIO,
MVI A,3 ;INITIALIZE 2SIO.
OUT CCOM
OUT LCOM
MVI A,11H
OUT CCOM
OUT LCOM
ENDIF
IF ISIO2 ;IF IMSAI SIO2,
MVI A,0AAH ;INITIALIZE SIO 2-2.
OUT CCOM
MVI A,40H
OUT CCOM
MVI A,0CEH
OUT CCOM
MVI A,37H
OUT CCOM
ENDIF
IF TUART ;IF CROMEMCO TUART,
MVI A,1 ;SET A = 1.
OUT 54H ;SELECT DEVICE A.
OUT 52H ;RESET DEVICE B.
LXI H,BAUDRS ;GET ADR OF BAUD RATE TABLE.
MVI A,11H ;OCTUPLE THE CLOCK.
IT1: OUT 02H ;& RESET CURRENT DEV.
MOV A,M ;GET BAUD RATE FROM TABLE.
OUT 0 ;SET BAUD RATE.
CALL CONIN ;READ KEYBOARD.
CALL CONIN ;READ KEYBOARD AGAIN.
CPI 0DH ;IF NOT CARRIAGE-RETURN,
MVI A,1 ;SLOW THE CLOCK.
JNZ IT1 ;UNTIL A CARRIAGE-RETURN.
ENDIF
LXI H,SMSG ;PRINT OPENING MESSAGE.
CALL PMSG
CALL CONIN ;READ # OF DISKS.
MOV C,A ;ECHO THE CHAR.
CALL CONOT
ANI 7 ;LOOK AT 3 LSB'S.
STA NODSKS ;SAVE IT.
XRA A ;SET DISK NUMBER = 0.
STA DISKNO
GOCPM: MVI A,0C3H ;PUT JMP TO WBOOT
STA 0 ;ADR AT ZERO.
LXI H,WBOOTE
SHLD 1
STA 5
LXI H,BDOS ;PUT JUMP TO BDOS
SHLD 6 ;AT ADR 5,6,7.
LXI H,80H ;SET DEFAULT DMA ADR.
SHLD DMAADD
LDA DISKNO ;GET DISK NUMBER TO
MOV C,A ;PASS TO CCP IN C.
JMP CPMB ;JUMP TO CCP.
IF TUART ;IF CROMEMCO TUART,
BAUDRS: DB 94H,0CEH,0A2H,92H,88H,84H,82H,1
ENDIF
;
; WARM-BOOT: READ ALL OF CPM BACK IN
; EXCEPT BIOS, THEN JUMP TO CCP.
;
WBOOT: LXI SP,80H ;SET STACK POINTER.
IF INTRP ;IF INTERRUPTS ALLOWED,
EI ;ALLOW THEM HERE.
ENDIF
LDA DISKNO ;SAVE DISK NUMBER.
STA TEMP
MVI C,0 ;SELECT DISK ZERO.
CALL SELDSK
CALL HOME ;MOVE TO TRACK ZERO.
JNZ RDERR ;IF ERROR, PRINT MESSAGE.
MVI D,NSECTS ;GET # SECTORS FOR CPM READ.
LXI B,2 ;TRACK (B)=0, SECTOR (C)=2.
LXI H,CPMB ;GET STARTING ADDRESS.
IF INTRP ;IF INTERRUPTS ALLOWED,
DI ;DISABLE THEM HERE.
ENDIF
RDBLK: MOV A,B ;GO TO TRACK IN B.
CALL SEEK
JNZ RDERR ;IF ERROR, PRINT MESSAGE.
MOV A,C ;READ STARTING AT SECTOR IN C.
CALL READ1
RBLK1 JNZ RDERR ;IF ERROR, PRINT MESSAGE.
DCR D ;DECREMENT SECTOR COUNT.
JZ ALDON ;ALL DONE WHEN ZERO.
INR C ;INCREMENT SECTOR NUMBER.
MOV A,C ;IF SECTOR NUMBER
CPI 27 ;IS NOT 27,
JC RBLK2 ;HOP OUT OF LOOP.
MVI C,1 ;OTHERWISE, RESET SECTOR=1
INR B ;INCREMENT TRACK NUMBER,
JMP RDBLK ;AND READ NEXT TRACK.
ALDON: LDA TEMP ;RESTORE DISK NUMBER.
IF INTRP ;IF INTERRUPTS ALLOWED,
EI ;ALLOW THEM AGAIN HERE.
ENDIF
STA DISKNO
JMP GOCPM ;GO BACK TO CPM.
;
RBLK2: CALL READ2 ;READ ANOTHER TRACK.
JMP RBLK1
;
RDERR: LXI H,BTMSG ;GET ADDRESS OF "BOOT ERROR".
CALL PMSG ;PRINT IT.
CALL CONIN ;READ A CHAR FROM CONSOLE.
JMP WBOOT ;DO A WARM BOOT.
;
; CHECK CONSOLE INPUT STATUS.
;
CONST: IN CSTAT ;READ CONSOLE STATUS.
ANI CKBR ;LOOK AT KB READY BIT.
MVI A,0 ;SET A=0 FOR RETURN.
IF STD ;IF STANDARD I/O,
RNZ ;NOT READY WHEN NOT 0.
ENDIF
IF SIO2 ;IF MITS OR IMSAI,
RZ ;NOT READY WHEN ZERO.
ENDIF
IF OTHER ;IF SOMETHING ELSE,
RNZ ;IT MIGHT BE THIS.
ENDIF
CMA ;IF READY A=FF.
RET ;RETURN FROM CONST.
;
; READ A CHARACTER FROM CONSOLE.
;
CONIN: IN CSTAT ;READ CONSOLE STATUS.
ANI CKBR ;IF NOT READY,
IF STD ;IF STANDARD I/O,
JNZ CONIN ;READY WHEN LOW.
ENDIF
IF SIO2 ;IF MITS OR IMSAI,
JZ CONIN ;READY WHEN HIGH.
ENDIF
IF OTHER ;IF SOMETHING ELSE,
JNZ CONIN ;IT MIGHT BE THIS.
ENDIF
IN CDATA ;READ A CHARACTER.
ANI 7FH ;MAKE MOST SIG. BIT = 0.
RET
;
; WRITE A CHARACTER TO THE CONSOLE DEVICE.
;
IF NOT VDM ;IF NOT PROC TECH VDM,
CONOT: MVI A,0DH ;IF IT'S A CR,
CMP C ;THEN HOP OUT
JZ CONUL ;TO NULL ROUTINE.
CONOT1: IN CSTAT ;READ CONSOLE STATUS.
ANI CPTR ;IF NOT READY,
ENDIF
IF STD AND NOT VDM ;IF STANDARD I/O,
JNZ CONOT1 ;READY WHEN LOW.
ENDIF
IF SIO2 ;IF MITS OR IMSAI,
JZ CONOT1 ;READY WHEN HIGH.
ENDIF
IF NOT VDM ;IF NOT PROC TECH VDM,
MOV A,C ;GET CHARACTER.
OUT CDATA ;PRINT IT.
RET ;RETURN.
CONUL: PUSH B ;SAVE B&C.
MVI B,CNULL ;GET NULL COUNT.
CONUL1: CALL CONOT1 ;PRINT CR.
MVI C,0 ;GET NULL CHAR.
DCR B ;DECREMENT COUNTER.
JNZ CONUL1 ;DO NEXT NULL.
POP B ;RESTORE B&C.
MOV A,C ;RESTORE A.
RET ;RETURN.
ENDIF
IF VDM ;IF PROC TECH VDM,
; VDM DRIVER FOR CBIOS.
; 9-24-77 VERSION
;
VDMB EQU 0CC00H
VDMP EQU 0CCH
VDMD EQU 0C8H
CONOT: MOV A,C ;PUT CHAR IN A.
SHLD HLSAV ;SAVE H&L.
LXI H,0 ;CLEAR H&L.
DAD SP ;HL=SP.
LXI SP,VSTACK ;SET STACK PTR.
PUSH H ;SAVE OLD SP.
PUSH D ;SAVE D&E.
PUSH B ;SAVE B&C.
PUSH PSW ;SAVE A&PSW.
CALL SCREEN ;WRITE ON SCREEN.
POP PSW ;RESTORE A&PSW.
POP B ;RESTORE B&C.
POP D ;RESTORE D&E.
POP H ;RESTORE H&L.
SPHL ;RESTORE SP.
LHLD HLSAV ;RESTORE H&L.
RET ;RETURN FROM CONOT.
;
;
SCREEN: MOV B,A ;GET CHARACTER.
MOV A,B
ANI 7FH ;NOT DELETE.
CPI 0DH ;IF IT'S CR,
JZ CHOT2 ;TAKE CARE OF IT.
CPI 20H ;CTL CHAR?
RC ;DON'T DISPLAY.
JMP CHOUT ;GO TO CHOUT.
;
; CLEAR SCREEN & INIT CURSOR.
;
CLR: LXI H,VDMB ;GET VDM MEM ADR.
MOV A,H ;FIGURE VDM MEM TOP.
ADI 4
CLR2: MVI M,' ' ;PUT SPACE IN MEMORY.
INX H ;INCREMENT POINTER.
CMP H ;AT TOP YET?
JNZ CLR2 ;KEEP GOING IF NOT.
XRA A ;SET A = 0.
STA BOSL ;BEG SCRN LINE = 0.
STA BOTL ;BEG TEXT LINE = 0.
STA CCP ;CURSOR PTR = 0.
CMA ;SET A = FF.
STA CURF ;SET CURSOR ON.
MVI A,15 ;SET CURSOR AT BOTTOM.
STA CLN
CALL VDMOT ;SET VDM UP.
RET ;RETURN FROM CLR.
;
; OUTPUT BOSL & BOTL TO VDM.
;
VDMOT: LDA BOSL ;INITIALIZE VDM.
RLC ;SHIFT LEFT 4.
RLC
RLC
RLC
LXI H,BOTL
ORA M
OUT VDMD ;OUT TO VDM PORT.
RET ;RETURN FROM VDMOT.
;
; STORE CHAR IN VDM MEMORY.
;
CHOUT: MOV C,A ;SAVE CHARACTER.
LDA CCP ;GET CURSOR PTR.
MOV B,A ;PUT IN B.
LDA CLN ;GET LINE NUMBER.
CALL CLNA ;CONVERT TO ADR.
MOV M,C ;PUT CHAR ON SCREEN.
LDA CCP ;ADVANCE CURSOR.
INR A
CPI 64 ;WRAP AROUND?
JNZ CHOT1
CHOT2: LDA CCP ;GET CURSOR POS.
MOV B,A
LDA CLN ;GET LINE NUMBER.
CALL CCUR ;CLEAR CURSOR.
CALL SCRL ;SCROLL UP.
SUB A ;CURSOR TO LEFT MARGIN.
CHOT1: STA CCP
MOV B,A
LDA CLN
JMP SCUR ;SET CURSOR ON/OFF.
;
;
SCRL: LXI H,BOTL ;SAVE BEG. TEXT LINE.
PUSH H
MOV A,M
INR M
SUB M
LXI B,0
CALL CLNA ;CONVERT LINE NO.
LXI B,2040H
SCRL2: MOV M,B ;CLEAR BOTTOM LINE.
INR L
DCR C
JNZ SCRL2
POP H
MOV A,M
ANI 0FH
MOV M,A
JMP VDMOT
;
; CONVERT LINE NUMBER IN REG A AND CHR
; POSITION IN REG B TO ADDRESS IN H&L.
;
CLNA: MOV L,A
LDA BOTL
ADD L
RRC
RRC
MOV L,A
ANI 3
ADI VDMP
MOV H,A
MOV A,L
ANI 0C0H
ADD B
MOV L,A
RET
;
;
SCUR: ANI 0FH
STA CLN
CALL CLNA
MOV A,B
STA CCP
LDA CURF
ORA A
MOV A,M
JZ CCUR2
ORI 80H
MOV M,A
RET
CCUR2: ANI 7FH
MOV M,A
RET
;
;
CCUR: CALL CLNA
MOV A,M
ANI 7FH
MOV M,A
RET
;
;
CLN: DS 1
CCP: DS 1
CURF: DS 1
BOSL: DS 1
BOTL: DS 1
HLSAV: DS 32
VSTACK: DS 1
ENDIF ;END OF VDM DRIVER.
;
; MOVE DISK TO TRACK ZERO.
;
HOME: MVI A,RTCNT ;GET RETRY COUNT.
HRETRY: STA ERCNT ;STORE IN ERROR CTR.
MVI A,0D0H ;CLEAR ANY PENDING COMMAND.
OUT DCOM
LDA DISKNO ;GET DISK NUMBER.
MOV E,A ;PUT IN D&E.
XRA A
MOV D,A
LXI H,TRTAB ;GET ADR OF TRK TABLE.
IF NOT DUAL ;IF NOT A DUAL DRIVE.
DAD D ;ADD DISK NUMBER.
ENDIF
MOV M,A ;PUT ZERO INTO TABLE.
HOME1: IN DSTAT ;READ DISK STATUS.
RRC ;LOOK AT LSB.
JC HOME1 ;WAIT FOR NOT BUSY.
IF FAST ;IF FAST SEEK,
LDA NODSKS ;GET NUMBER OF DISKS.
DCR A ;IF ONLY ONE DISK,
JZ HOME2 ;SKIP OVER NEXT PART.
LDA DISKNO ;GET DISK NUMBER.
RLC!RLC!RLC!RLC ;SHIFT LEFT 4 BITS.
ANI 10H ;LOOK AT BIT 4.
HOME2: CMA ;INVERT.
MOV E,A ;SAVE IT.
ANI 0B2H ;SET PERSCI
OUT DCONT ;RESTORE LINE.
HLOOP: IN DSTAT ;LOOK AT STATUS
ANI 4 ;BIT 2 (TRACK 0)
JZ HLOOP ;AND WAIT TILL 1.
MOV A,E ;RESTORE OLD BITS
ANI 0F2H ;IN LATCH AND CLEAR
OUT DCONT ;RESTORE LINE.
ENDIF
MVI A,2 ;10 MS STEP RATE.
OUT DCOM ;ISSUE HOME COMMAND.
IN WAIT ;WAIT FOR INTRQ.
ORA A ;SET FLAGS.
JM HERR ;ERROR IF DRQ.
IN DSTAT ;READ DISK STATUS.
MOV D,A ;SAVE IN REGISTER D.
ANI 4 ;LOOK AT BIT 2.
JZ HERR ;ERROR IF NOT TRK 0.
MOV A,D ;GET STATUS BACK.
ANI 91H ;MASK NON-ERROR BITS.
RZ ;RETURN IF NO ERROR.
HERR: LDA HECNT ;GET TOTAL ERROR COUNT.
INR A ;ADD ONE.
STA HECNT ;SAVE IT BACK.
LDA ERCNT ;GET THIS ERROR COUNT.
DCR A ;DECREMENT COUNT.
JNZ HRETRY ;TRY TO HOME AGAIN.
LXI H,HEMSG ;PRINT "HOME ".
MOV A,D ;MASK NON-ERROR BITS.
ANI 91H
MOV D,A
JMP ERMSG ;DO COMMON ERROR MSGS.
;
; SELECT DISK NUMBER ACCORDING TO REGISTER C.
;
SELDSK: MOV A,C ;GET NEW DISK NUMBER.
ANI 3 ;ONLY LOOK AT 2 LSB'S.
LXI H,DISKNO ;GET ADR OF OLD DISK NO.
CMP M ;NEW = OLD?
RZ ;IF SO, RETURN.
PUSH A ;SAVE DISK NUMBER.
LDA NODSKS ;GET NUMBER OF DISKS.
DCR A ;IF MORE THAN ONE DISK,
JNZ SELMOR ;TAKE CARE OF IT.
LXI H,MNTMSG ;GET ADR OF MOUNT MESSAGE.
CALL PMSG ;PRINT "MOUNT ".
POP A ;GET DISK NUMBER.
STA DISKNO ;UPDATE OLD WITH NEW.
ADI 'A' ;ADD ASCII FOR 'A'.
MOV C,A ;PUT INTO C.
CALL CONOT ;PRINT IT.
CALL CONIN ;READ A CARRIAGE RETURN.
XRA A ;SET A=0 FOR NO ERRO IND.
RET ;RETURN FROM SELDSK.
SELMOR: POP A ;MAKE STACK RIGHT.
MOV A,M ;GET OLD DISK NUMBER.
IF DUAL ;IF DUAL DRIVE,
ANI 0FEH ;CLEAR OUT BIT 0.
ENDIF
MOV E,A ;PUT OLD DISK NO. IN D&E.
MVI D,0
LXI H,TRTAB ;GET ADDRESS OF TRACK TABLE.
DAD D ;ADD DISK NO. TO ADDRESS.
IN TRACK ;READ 1771 TRACK REGISTER.
MOV M,A ;PUT INTO TABLE.
MOV A,C ;GET NEW DISK NUMBER.
IF DUAL ;IF A DUAL DRIVE,
ANI 0FEH ;CLEAR BIT 0.
ENDIF
MOV E,A ;PUT NEW DISK NO. IN D&E.
LXI H,TRTAB ;GET ADDRESS OF TRACK TABLE.
DAD D ;ADD DISK NO. TO ADDRESS.
MOV A,M ;GET NEW TRACK NUMBER.
OUT TRACK ;PUT INTO 1771 TRACK REG.
MOV A,C ;UPDATE OLD DISK NUMBER.
STA DISKNO
CMA ;BITS INVERTED INTO LATCH.
ADD A ;PUT BITS 1&2 AT 4&5.
ADD A
ADD A
ADD A
ORI 2 ;MAKE LATCH COMMAND.
DSK1: OUT DCONT ;SET THE LATCH WITH CODE.
XRA A ;SET A = 0.
RET ;RETURN FROM SELDSK.
;
; SET TRACK NUMBER TO WHATEVER IS IN REGISTER C.
; ALSO PERFORM MOVE TO THE CORRECT TRACK (SEEK).
;
SETTRK: MOV A,C ;GET NEW TRACK NUMBER.
STA TRK ;UPDATE OLD WITH NEW.
CALL SEEK ;MOVE TO NEW TRACK.
RET ;RETURN FROM SETTRK ROUTINE.
;
; SET DISK SECTOR NUMBER.
;
SETSEC: MOV A,C ;GET SECTOR NUMBER.
STA SECT ;PUT AT SECT # ADDRESS.
RET ;RETURN FROM SETSEC.
;
; SET DISK DMA ADDRESS.
;
SETDMA: MOV H,B ;MOVE B&C TO H&L.
MOV L,C
SHLD DMAADD ;PUT AT DMA ADR ADDRESS.
RET ;RETURN FROM SETDMA.
;
; READ A SECTOR WITHOUT LOADING HEAD FIRST.
;
READ2: OUT SECTP ;SET SECTOR NUMBER INTO 1771.
MVI A,88H ;GET CODE FOR READ W/O HLD.
JMP READE ;READ A SECTOR.
;
; READ THE SECTOR AT SECT, FROM THE PRESENT TRACK.
; USE STARTING ADDRESS AT DMAADD.
;
READ: MVI A,RTCNT ;GET RETRY COUNT.
RRETRY: STA ERCNT ;STORE IN ERROR CTR.
LHLD DMAADD ;GET STARTING ADR.
MVI A,0D0H ;CAUSE INTERRUPT.
OUT DCOM
XTHL ;SOME DELAY.
XTHL
IF INTRP ;IF INTERRUPTS ALLOWED,
DI ;DISABLE THEM HERE.
ENDIF
IN DSTAT ;READ STATUS.
ANI 20H ;LOOK AT HLD BIT.
LDA SECT ;GET SECTOR NUMBER.
READ1: OUT SECTP ;SET SECTOR INTO 1771.
MVI A,8CH ;READ WITH HEAD LOAD
JZ READE ;HEAD NOT LOADED.
MVI A,88H ;CODE FOR READ W/O HD LD.
READE: OUT DCOM ;SEND COMMAND TO 1771.
RLOOP: IN WAIT ;WAIT FOR DRQ OR INTRQ.
ORA A ;SET FLAGS.
JP RDDONE ;DONE IF INTRQ.
IN DDATA ;READ A DATA BYTE FROM DISK.
MOV M,A ;PUT BYTE INTO MEMORY.
INX H ;INCREMENT MEMORY POINTER.
JMP RLOOP ;KEEP READING.
RDDONE: IN DSTAT ;READ DISK STATUS.
IF INTRP ;IF INTERRUPTS ALLOWED,
EI ;ALLOW AGAIN HERE.
ENDIF
ANI 9DH ;LOOK AT ERROR BITS.
RZ ;RETURN IF NONE.
CHECK: CALL ERCHK ;CHECK FOR SEEK ERROR.
LXI H,RECNT ;GET RD ERR COUNT ADDR.
INR M ;ONE MORE ERROR.
LDA ERCNT ;GET ERROR COUNT.
DCR A ;DECREMENT COUNT.
JNZ RRETRY ;TRY TO READ AGAIN.
LXI H,RDMSG ;PRINT "READ ".
ERMSG: CALL PMSG ;PRINT ORIGIN MESSAGE.
ERMSG1:
IF NOT VDM ;IF NOT PROC TECH VDM,
MOV A,D ;GET ERROR BITS.
ANI 80H ;IF BIT 7 HIGH,
LXI H,NRMSG ;"NOT READY".
CNZ PMSG
MOV A,D ;GET ERROR BITS.
ANI 10H ;IF BIT 4 IS HIGH,
LXI H,RNMSG ;PRINT "RECORD NOT FOUND"
CNZ PMSG
MOV A,D ;GET ERROR BITS.
ANI 8H ;IF BIT 3 IS HIGH,
LXI H,CRCMSG ;PRINT "CRC ERROR".
CNZ PMSG
MOV A,D ;GET ERROR BITS.
ANI 4H ;IF BIT 2 IS HIGH,
LXI H,LDMSG ;PRINT "LOST DATA".
CNZ PMSG
MOV A,D ;GET ERROR BITS.
ANI 1 ;IF BIT 1 IS HIGH,
LXI H,BSYMSG ;PRINT "BUSY".
CNZ PMSG
ENDIF
PERMSG: LXI H,ERRMSG ;PRINT "ERROR."
CALL PMSG
MVI A,1 ;SET FOR PERM ERR MSG.
ORA A ;SET FLAGS.
RET
;
; ERCHK - CHECK FOR RECORD NOT FOUND ERROR.
;
ERCHK: MOV D,A ;SAVE ERROR BITS IN D.
ANI 10H ;IF RECORD NOT FOUND,
JNZ CHKSK ;DO A CHECK ON SEEK.
MOV A,D ;OTHERWISE RESTORE BITS
ORA A ;SET FLAGS,
RET ;AND RETURN.
;CHECK FOR SEEK TO CORRECT TRACK,
;AND CHANGE IF NECESSARY.
CHKSK: MVI A,0C4H ;SEND COMMAND TO 1771
OUT DCOM ;TO READ ADDRESS.
IN WAIT ;WAIT FOR DRQ OR INTRQ.
IN DDATA ;READ THE TRACK ADDRESS.
MOV B,A ;SAVE IN REGISTER B.
CHKS2: IN WAIT ;WAIT FOR INTRQ.
ORA A ;SET FLAGS.
JP CHKS3 ;DONE WITH READ ADR OP.
IN DDATA ;READ ANOTHER BYTE.
JMP CHKS2 ;DO IT AGAIN.
CHKS3: IN DSTAT ;READ DISK STATUS.
ORA A ;SET FLAGS.
JZ CHKS4 ;READ ADR OK IF 0.
CALL HOME ;OTHERWISE, HOME FIRST.
JMP CHKS5
CHKS4: MOV A,B ;UPDATE TRACK REGISTER.
OUT TRACK
CHKS5: LDA TRK ;GET REQUIRED TRACK NO.
CALL SEEK ;MOVE THE HEAD TO IT.
MOV A,D ;GET ERROR BITS.
ORA A ;SET FLAGS.
RET ;RETURN FROM ERCHK.
;
; WRITE THE SECTOR AT SECT, ON THE PRESENT TRACK.
; USE STARTING ADDRESS AT DMAADD.
;
WRITE: MVI A,RTCNT ;GET RETRY COUNT.
WRETRY: STA ERCNT ;STORE IN ERROR COUNTER.
LHLD DMAADD ;GET STARTING ADR.
MVI A,0D0H ;STATUS INTERUPT FOR 1771.
OUT DCOM ;COMMAND 1771.
XTHL ;WAIT FOR STATUS.
XTHL ;CHANGE IT BACK.
IF INTRP ;IF INTERRPUTS ALLOWED,
DI ;DISABLE THEM HERE.
ENDIF
IN DSTAT ;GET 1771 STATUS.
ANI 20H ;CHECK FOR HEAD LOAD.
LDA SECT ;GET SECTOR NUMBER.
WRITE1: OUT SECTP ;SET THE SECTOR INTO 1771.
MVI A,0ACH ;SET UP 1771 FOR WRITE.
JZ WRITE2 ;HEAD IS NOT LOADED.
MVI A,0A8H ;CODE FOR WRITE W/O HD LD.
WRITE2: OUT DCOM
WLOOP: IN WAIT ;WAIT FOR READY.
ORA A ;SET FLAGS.
JP WDONE ;HOP OUT WHEN DONE.
MOV A,M ;GET BYTE FROM MEM.
OUT DDATA ;WRITE ONTO DISK.
INX H ;INCREMENT MEM PTR.
JMP WLOOP ;KEEP WRITING.
WDONE: IN DSTAT ;READ DISK STATUS.
IF INTRP ;IF INTERRUPTS ALLOWED,
EI ;ENABLE AGAIN HERE.
ENDIF
ANI 0FDH ;LOOK AT THESE BITS.
PROCER: RZ ;RETURN IF NO ERR.
CALL ERCHK ;CHECK/CORRECT SEEK ERR.
LXI H,WECNT ;GET ADR OF WRITE ERR CTR.
INR M ;ONE MORE WRITE ERROR.
LDA ERCNT ;GET ERROR COUNT.
DCR A ;DECREMENT COUNT.
JNZ WRETRY ;TRY TO WRITE AGAIN.
WERR0: LXI H,WTMSG ;PRINT "WRITE ".
IF NOT VDM ;IF NOT PROC TECH VDM,
CALL PMSG
MOV A,D ;GET ERROR BITS.
ANI 40H ;LOOK AT BIT 6.
LXI H,WPMSG ;PRINT "PROTECT ".
CNZ PMSG
MOV A,D ;GET ERROR BITS.
ANI 20H ;LOOK AT BIT 5.
LXI H,WFMSG ;PRINT "FAULT ".
CNZ PMSG
JMP ERMSG1 ;DO COMMON MESSAGES.
ENDIF
IF VDM ;IF PROC TECH VDM,
JMP ERMSG
ENDIF
;
; MOVE THE HEAD TO THE TRACK IN REGISTER A.
;
SEEK: PUSH B ;SAVE B&C.
MOV B,A ;SAVE DESTINATION TRACK.
MVI A,RTCNT ;GET RETRY COUNT.
SRETRY: STA SERCNT ;STORE IN ERROR COUNTER.
IN TRACK ;READ PRESENT TRACK NO.
MOV C,A ;SAVE IN C.
MOV A,C ;DELAY.
CMP B ;SAME AS NEW TRACK NO.?
MOV A,B ;RESTORE A FROM B.
JNZ NOTHR ;JUMP IF NOT THERE.
THERE: POP B ;RESTORE B&C.
RET ;RETURN FROM SEEK.
NOTHR:
IF NOT FAST ;IF NOT FAST SEEK,
OUT DDATA ;TRACK TO DATA REGISTER.
BUSY: IN DSTAT ;READ DISK STATUS.
RRC ;LOOK AT BIT 0.
JC BUSY ;WAIT TILL NOT BUSY.
MVI A,12H ;SET FOR 10 MS STEP.
ORI 4 ;VERIFY ON LAST TRACK.
OUT DCOM ;ISSUE SEEK COMMAND.
IN WAIT ;WAIT FOR INTRQ.
IN DSTAT ;READ STATUS.
ANI 91H ;LOOK AT BITS.
JZ THERE ;OK IF ZERO.
ENDIF
IF FAST ;IF FAST SEEK,
MVI A,40H ;IF CARRY = 1,
JC SDIR ;STEP IN.
MVI A,60H ;OTHERWISE, OUT.
SDIR: OUT DCOM ;ISSUE STEP DIRECTION.
MVI A,20 ;DELAY LOOP COUNT.
DLOOP: DCR A ;DECREMENT COUNTER.
JNZ DLOOP
MOV A,C ;GET PRESENT TRACK.
SUB B ;FIGURE TRACKS TO STEP.
JP STEP ;IF NEGATIVE,
CMA ;FIGURE THE
INR A ;TWO'S COMPLEMENT.
STEP: MOV C,A ;GET DIFFERENCE.
MVI A,1 ;PERSCI STEP COMMAND.
STEP1: OUT DCONT ;STEP(PERSCI (E-14).
DCR C ;COUNT THE STEP.
JNZ STEP1 ;STEP UNTIL C = 0.
IN WAIT ;CLEAR 1771.
IN DSTAT
MOV A,B ;GET DEST. TRACK.
OUT TRACK ;UPDATE TRACK REG.
LDA DISKNO ;GET DISK NUMBER.
RLC!RLC!RLC!RLC ;SHIFT LEFT 4 BITS.
ANI 10H ;LOOK A BIT 4.
CMA ;INVERT.
MOV B,A ;SAVE IN B.
ANI 72H ;MAKE COMMAND TO
OUT DCONT ;SWITCH WAIT FOR
IN WAIT ;SEEK COMPLETE.
MOV A,B ;RESTORE ORIG. BITS.
ANI 0F2H ;SWITCH WAIT BACK.
OUT DCONT
XRA A ;MAKE GOOD RETURN.
POP B ;RMSTOREE B&C.
RET
ENDIF
IF NOT FAST ;IF NOT FAST SEEK,
PUSH H ;SAVE H&L.
LXI H,SECNT ;GET ADR OF SEEK ERR CTR.
INR M ;ONE MORE SEEK ERROR.
POP H ;RESTORE H&L.
LDA ERCN\ ;GET ERROR COUNT.
DCR A ;DECREMENT COUNT.
JNZ SRETRY ;RETRY SEK.
POP B ;RESTORE B&C.
LXI H,SKMSG ;PRINT "SEEK ".
IN DSTAT ;READ DISK STATUS.
ANI 91H ;LOOK AT ERROR BITS.
MOV D,A ;PUT IN REG D.
JMP ERMSG ;DO COMMON ERR MESSAGES.
ENDIF
;
; PRINT THE MESSAGE AT H&L UNTIL A ZERO.
;
PMSG: MOV A,M ;GET A CHARACTER.
ORA A ;IF IT'S ZERO,
RZ ;RETURN.
MOV C,A ;OTHERWISE,
CALL CONOT ;PRINT IT.
INX H ;INCREMENT H&L,
JMP PMSG ;AND GET ANOTHER.
;
; CBIOS MESSAGES
;
IF NOT VDM ;IF NOT PROC TECH VDM,
NRMSG: DB 'NOT READY ',0
RNMSG: DB 'RECORD NOT FOUND ',0
CRCMSG: DB 'CRC ',0
LDMSG: DB 'LOST DATA ',0
BSYMSG: DB 'BUSY ',0
WPMSG: DB 'PROTECT ',0
WFMSG: DB 'FAULT ',0
ENDIF
ERRMSG: DB 'ERROR.',0
RDMSG: DB 0DH,0AH,'READ ',0
WTMSG: DB 0DH,0AH,'WRITE ',0
BTMSG: DB 'BOOT ERROR',0
SKMSG: DB 0DH,0AH,'SEEK ',0
HEMSG: DB 0DH,0AH,'HOME ',0
MNTMSG: DB 0DH,0AH,'MOUNT ',0
SMSG: DB 0DH,0AH,'TARBELL '
DB MSIZE/10+'0',MSIZE MOD 10 + '0'
DB 'K CPM V1.4 OF 2-15-78'
DB 0DH,0AH
IF STD ;IF STANDARD I/O,
DB 'STANDARD '
ENDIF
IF MSIO2 ;IF MITS 2SIO,
DB '2SIO '
ENDIF
IF ISIO2 ;IF IMSAI SIO-2,
DB 'SIO-2 '
ENDIF
IF TUART ;IF TUART,
DB 'TUART '
ENDIF
IF VDM ;IF PROC TECH VDM,
DB 'VDM '
ENDIF
IF FAST ;IF FAST SEEK,
DB 'FAST SEEK '
ENDIF
IF DUAL ;IF DUAL DRIVE,
DB 'DUAL '
ENDIF
DB 'VERSION.'
DB 0DH,0AH,'HOW MANY DISKS? ',0
;
; WRITE A CHARACTER ON LISTING DEVICE.
;
LIST:
IF NOT VDM ;IF NOT PROC TECH VDM,
MVI A,0DH ;IF IT'S A CR,
CMP C ;THEN HOP OUT TO
JZ LINUL ;NULL ROUTINE.
ENDIF
LIST1: IN LSTAT ;READ LISTER STATUS.
ANI LRBIT ;LOOK AT READY BIT.
IF STD ;IF STANDARD I/O,
JNZ LIST1 ;READY WHEN LOW.
ENDIF
IF SIO2 ;IF MITS, IMSAI, CROM.,
JZ LIST1 ;READY WHEN HIGH.
ENDIF
IF OTHER ;IF ANYTHING ELSE,
JZ LIST1 ;READY WHEN HIGH.
ENDIF
MOV A,C ;GET DATA BYTE.
OUT LDATA ;PRINT IT.
RET ;RETURN FROM LIST.
IF NOT VDM ;IF NOT PROC TECH VDM,
LINUL: PUSH B ;SAVE B&C.
MVI B,LNULL ;GET NULL COUNT.
LINUL1: CALL LIST1 ;PRINT (CR FIRST).
MVI C,0 ;GET NULL CHAR.
DCR B ;DECREMENT COUNTER.
JNZ LINUL1 ;DO NEXT NULL.
POP B ;RESTORE B&C.
MOV A,C ;RESTORE A.
RET ;RETURN FROM LIST.
ENDIF
;
; NORMALLY USED TO PUNCH PAPER TAPE, BUT IS
; NICE FOR AN INFINITE BIT BUCKET TO CHECK FILES.
;
PUNCH:
IF NOT VDM ;IF NOT PROC TECH VDM,
NOP ;SPACE FOR YOUR ROUTINE.
NOP!NOP!NOP!NOP
NOP!NOP!NOP!NOP
NOP
ENDIF
RET ;RETURN FROM PUNCH.
;
; NORMALLY USED TO READ PAPER TAPE.
; SET UP TO READ FROM CONSOLE IN STANDARD SYSTEM.
;
READER:
IF NOT VDM ;IF NOT PROC TECH VDM,
CALL CONIN ;READ FROM CONSOLE.
NOP!NOP!NOP!NOP ;MORE SPACE FOR YOUR ROUTINE.
NOP!NOP!NOP!NOP
ENDIF
RET ;RETURN FROM READER.
;NOTE: AS THERE ARE ONLY NINE SECTORS
;AVAILABLE FOR CBIOS ON THE SECOND SYSTEM TRACK (1),
;THE LAST ADDRESS BEFORE THIS POINT SHOULD BE NO
;GREATER THAN THE CBIOS STARTING ADDRESS + 047F (HEX).
;THIS WILL NORMALLY BE XE7F (HEX).
;
; ERROR COUNTS. THESE LOCATIONS KEEP TRACK OF THE
; NUMBER OF ERRRS THAT OCCUR DURING READ, WRITE,
; OR SEEK OPERATIONS. THEY ARE INITIALIZED ONLY
; WHEN A COLD-START IS PERFORMED BY THE BOOOTSTRAP.
;
HECNT: DB 0 ;HOME ERROR COUNT.
RECNT: DB 0 ;READ ERROR COUNT.
WECNT: DB 0 ;WRITE ERROR COUNT.
SECNT: DB 0 ;SEEK ERROR COUNT.
;
; TRTAB - DISK TRACK TABLE - PRESENT POSITION OF
; HEADS FOR UP TO 4 DRIVES.
;
TRTAB: DS 4
;
NODSKS: DS 1 ;NUMBER OF DISKS.
ERCNT: DS 1 ;ERROR COUNT FOR RETRIES.
SERCNT: DS 1 ;SEEK RETRY COUNTER.
TEMP: DS 1 ;TEMPORARY STORAGE.
TRK: DS 1 ;CURRENTLY SELECTED TRACK.
SECT: DS 1 ;CURRENTLY SELECTED SECTOR.
DMAADD: DS 2 ;CURRENT READ/WRITE ADDRESS.
DISKNO: DS 1 ;CURRENT DISK NUMBER.
END