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
/
CPMUG049.ARK
/
4FDCBIOS.Z80
< prev
next >
Wrap
Text File
|
1984-04-29
|
13KB
|
665 lines
LIST NOCOND,NOGEN
;
;
PERSCISW: EQU 0 ;ONE IF PERSCI DRIVE
LARGESW: EQU 0 OR PERSCISW ;ONE IF MAXI DRIVE
NUMDRIVES: EQU 2 ;ONE TO FOUR (MUST BE SAME TYPE)
BIGIOSW: EQU 1 ;ZERO IF NO LIST, NO PUNCH
;
BEGINADR: EQU 0E400H ;THIS IS THE START OF 64K CPM
;
ORG 1600H+BEGINADR
;
; CROMEMCO 4FDC I/O ASSIGNMENTS
;
CSTATPORT: EQU 00H ;3P + S, 4FDC, TU-UART, OR SCC
CDATAPORT: EQU 01H
IMODEPORT: EQU 02H ;(3P + S DOESNT HAVE THESE)
IMASKPORT: EQU 03H
PARLPORT: EQU 04H ;NOT USED
;
STATPORT: EQU 30H ;4FDC OR CCS 2422 BOARD
TRAKPORT: EQU 31H
SECTPORT: EQU 32H
DATAPORT: EQU 33H
FLAGPORT: EQU 34H
;
BANKPORT: EQU 40H ;MEMORY BANKING PORT
;
; 1771/179X EQUATES
;
HEADLOAD: EQU 08H
VERIFY: EQU 04H
;
IF BIGIOSW = 1
;
; OTHER DEFINITIONS (OPTIONAL)
;
BAUDRATE: EQU 01H ;110 BAUD FOR READER ?
RSTATPORT: EQU 20H
RBAUDPORT: EQU RSTATPORT ;TU-UART BOARD FOR PAPER TAPE
RDATAPORT: EQU RSTATPORT+1
PSTATPORT: EQU 20H
PBAUDPORT: EQU PSTATPORT ;PAPER TAPE PUNCH ALSO
PDATAPORT: EQU PSTATPORT+1
LSTATPORT: EQU 54H ;PARALLEL PRINTER POARD
LDATAPORT: EQU LSTATPORT
ENDIF
;
; CPM ENTRY POINTS
CPMB: EQU 00H+BEGINADR
BDOS: EQU 806H+BEGINADR
;
; JUMP VECTOR
JP CBOOT
EBOOT:
JP WBOOT
JP CONSTAT
JP CONIN
JP CONOUT
JP LIST
JP PUNCH
JP READER
JP HOME
JP SELDSK
JP SETTRK
JP SETSEC
JP SETDMA
JP READ
JP WRITE
JP LISTAT
JP SECTRAN
;
; CP/M 2.2 DISK CONTROL BLOCKS
;
DPBASE:
DW XLT0,0000
DW 0000,0000
DW DIRBUF,DPB0
DW CSV0,ALV0
;
IF NUMDRIVES > 1
DW XLT0,0000
DW 0000,0000
DW DIRBUF,DPB0
DW CSV1,ALV1
ENDIF
;
IF NUMDRIVES > 2
DW XLT0,0000
DW 0000,0000
DW DIRBUF,DPB0
DW CSV2,ALV2
ENDIF
;
IF NUMDRIVES > 3
DW XLT0,0000
DW 0000,0000
DW DIRBUF,DPB0
DW CSV3,ALV3
ENDIF
;
DPB0:
;
; disk parameter block, common to all disks
; this implements a "standard" CP/M directory
; with 64 entries, and 1K blocks.
;
DW 18+LARGESW*8 ;sectors per track
DB 3 ;block shift factor
DB 7 ;block mask
DB 0 ;null mask
DW 81+LARGESW*161 ;disk size-1
DW 63 ;directory max
DB 192 ;alloc 0
DB 0 ;alloc 1
DW 16 ;check size
DW 3-LARGESW ;track offset
;
XLT0:
;
; sector translate vector
;
IF LARGESW EQ 0
DB 1,6,11,16 ;sectors 1,2,3,4
DB 3,8,13,18 ;sectors 5,6,7,8
DB 5,10,15,2 ;sectors 9,10,11,12
DB 7,12,17,4 ;sectors 13,14,15,16
DB 9,14 ;sectors 17,18
ENDIF
;
;
IF LARGESW EQ 1
DB 1,7,13,19 ;sectors 1,2,3,4
DB 25,5,11,17 ;sectors 5,6,7,8
DB 23,3,9,15 ;sectors 9,10,11,12
DB 21,2,8,14 ;sectors 13,14,15,16
DB 20,26,6,12 ;sectors 17,18,19,20
DB 18,24,4,10 ;sectors 21,22,23,24
DB 16,22 ;sectors 25,26
ENDIF
;
;
SIGNON:
DEFB 13,10,10
DEFB '64'
DEFB 'k CP/M vers 2.2'
DEFB 13,10,0
;
SELDSK: ;
LD HL,0
LD A,C ;C CONTAINS REQUESTED DRIVE NO.
CP NUMDRIVES
RET NC ;IGNORE IF TOO HIGH
LD (CURRDRIVE),A
LD (DKNUMB),A
LD L,C ;L=disk number 0,1,2,3
ADD HL,HL ;*2
ADD HL,HL ;*4
ADD HL,HL ;*8
ADD HL,HL ;*16 (size of each header)
LD DE,DPBASE
ADD HL,DE ;HL=.dpbase(diskno*16)
RET
;
SECTRAN: ;TRANSLATE SECTOR IN C USING TABLE AT DE
LD B,0
EX DE,HL ;TABLE ADDR TO HL
ADD HL,BC ;GET ADDRESS
LD L,(HL) ;GET BYTE
LD H,0 ;ANSWER IN HL
RET
;
SETSEC:
LD A,C ;JUST SAVE SECTOR NUMBER
LD (DKSECT),A
RET
;
SETDMA:
LD (DKDMA),BC ;JUST SAVE I/O ADDRESS
RET
;
;
; ERROR CHECKING READ AND WRITE RTNS FOR
; CROMEMCO CBIOS
;
READ:
CALL CLEAR
RETRYREAD:
CALL READ4FDC ;READ SECTOR
RET Z ;SUCCESSFUL READ. RETURN
CALL ERROR ;INCREMENT RETRYCOUNT
JR NZ,RETRYREAD ;RETRY 20 TIMES
OR 01H ;CP/M CONVENTION FOR PERMANENT ERROR
RET
;
CLEAR:
XOR A
LD (TRKERCNT),A ;ZERO OUT TRACK ERROR COUNTER
LD (RETRYCOUNT),A ;ZERO OUT CRC ERROR COUNTER
RET
;
WRITE:
CALL CLEAR
RETRYWRITE:
CALL WRIT4FDC ;WRITE SECTOR
RET Z ;SUCCESSFUL WRITE. RETURN
CALL ERROR ;INCREMENT RETRYCOUNT
JR NZ,RETRYWRITE ;RETRY 20 TIMES
OR 01H ;CP/M CONVENTION FOR PERMANENT ERROR
RET
;
ERROR:
PUSH HL
AND 10H ;CHECK FOR NRF
JR NZ,TRACKERROR
LD HL,RETRYCOUNT
INC (HL) ;INCREMENT RETRYCOUNT
LD A,(HL)
POP HL
SUB 20 ;20 TRIES?
RET
;
TRACKERROR:
LD HL,TRKERCNT
INC (HL) ;INCREMENT NO OF TRACK ERRORS
LD A,(HL)
SUB 10D ;ALLOW ONLY 10 TRACK ERRORS
POP HL
RET Z ;IF >10, RETURN A FAILURE
PUSH BC
CALL HOME ;HOME THE HEAD
LD A,(DKTRACK)
LD C,A ;GET TRACK IN C
CALL SETTRK ;RESEEK TO CORRECT TRACK
POP BC
OR 0FFH ;RETRY
RET
;
; RESTORE THE DISK TO TRACK ZERO
;
HOME:
SUB A,A ;ZERO OUT TRACK COUNTER
LD (DKTRACK),A
CALL DISKSELECT ;NOW SELECT THE DISK
OUT FLAGPORT,A
LD A,02H+HEADLOAD+VERIFY ;USE SLOW STEPPING SPEED FOR ALL DISKS
OUT STATPORT,A
RSTI:
IN A,FLAGPORT ;NOW CHECK STATUS
RRA
JR NC,RSTI ;LOOP BACK UNTIL DONE
JP SEEKTEST
;
; HERE, ACTUALLY DO THE READ OPERATION
;
READ4FDC:
PUSH BC
PUSH HL ;FIRST, SAVE REGS
PUSH DE
LD E,88H ;READ COMMAND (VALID FOR 1771, 179X)
CALL INIT4FDC
RDI1:
IN A,FLAGPORT ;NOW CHECK FLAGS
RRA
JR C,RDI3 ;IF PREMATURELY DONE, STOP
INI
JR NZ,RDI1 ;READ ANOTHER BYTE INTO CORE UNTIL DONE
RDI2:
IN A,FLAGPORT ;CHECK FLAGS
RRA
JR NC,RDI2 ;LOOP UNTIL READY
RDI3:
IN A,STATPORT ;NOW CHECK STATUS
AND A,9CH
RDWREND:
EI
POP DE ;RESTORE REGS
POP HL
POP BC
RET
;
; ACTUALLY DO WRITE OPERATION
;
WRIT4FDC:
PUSH BC
PUSH HL ;SAVE REGS
PUSH DE
LD E,0A8H ;WRITE COMMAND (VALID FOR 1771, 179X)
CALL INIT4FDC
WRI1:
IN A,FLAGPORT ;CHECK FLAGS
RRA
JR C,WRI3 ;IF PREMATURELY DONE, STOP
OUTI
JR NZ,WRI1 ;WRITE DATA FROM MEMORY TIL DONE
WRI2:
IN A,FLAGPORT ;CHECK FLAGS
RRA
JR NC,WRI2 ;LOOP TIL DONE WITH WHOLE OPERATION
WRI3:
IN A,STATPORT ;NOW CHECK ERROR STATUS
AND A,0FCH
JR RDWREND
;
; SET THE TRACK, AND MOVE DISK ARM THERE
;
SETTRK:
LD A,C
LD (DKTRACK),A ;STORE THE TRACK NUMBER
SUB A,A
CALL DISKSELECT ;NOW SELECT THE DISK
OUT FLAGPORT,A
LD A,C
OUT DATAPORT,A ;TELL 1771 ABOUT TRACK WANTED
LD A,(DKSECT)
OUT SECTPORT,A ;TELL IT ABOUT SECTOR WANTED
PUSH HL
PUSH DE
LD HL,LOGINTAB ;NOW, SEE WHERE DISK ARM IS NOW
LD A,(DKNUMB)
LD E,A ;LOOK UP IN TABLE
LD D,0
ADD HL,DE ;GET BYTE
LD A,(HL)
OUT TRAKPORT,A ;TELL 1771 WHERE ARM IS NOW
LD A,(HL)
SUB A,C
POP DE ;NOW CAN RESTORE THE REGS
POP HL
RET Z ;IF ALREADY AT THAT TRACK, QUIT
LD A,12H-LARGESW*2+HEADLOAD+VERIFY
OUT STATPORT,A ;PERFORM THE SEEK THAT IS NEEDED
SKI:
IN A,FLAGPORT ;CHECK FLAGS
RRA
JR NC,SKI ;LOOP UNITL OPERATION DONE
SEEKTEST:
IN A,STATPORT ;NOW CHECK ERROR STATUS
AND A,98H
RET NZ ;ZERO IS ALL OK
PUSH DE
LD D,0 ;UPDATE TRACK TABLE
LD A,(DKNUMB)
LD E,A ;WITH NEW POSITION
IF PERSCISW = 1
CALL ADDSHIFT ;PERSCI DRIVES HAVE ONE ARM FOR
BIT 7,E ;TWO DISKS, SO MUST POST BOTH
LD E,1 ;ENTRIES IN TABLE
JR Z,ADD2SHFT
LD DE,-1 ;THIS WAS THE OTHER ONE
ADD2SHFT:
CALL ADDSHIFT ;DO THE CORRECTION AND GO
POP DE
RET
ENDIF
ADDSHIFT: ;IF NOT PERSCI, FALL THRU HERE
PUSH HL
LD HL,LOGINTAB ;GET CORRECT ADDRESS OF DISK
ADD HL,DE
LD A,(DKTRACK) ;AND GET CURRENT TRACK NUMBER
LD (HL),A
SUB A,A ;PUT IT IN
POP HL
IF PERSCISW = 0
POP DE ;AND MISC CLEANUP
ENDIF
RET
;
; INITIALIZE THE 4FDC, BY SELECTING THE DISK AND
; TURNING ON THE DISK MOTORS, AND INITIALIZE THE
; REGISTERS FOR THE I/O OPERATION
;
INIT4FDC:
LD A,80H ;FIRST, SELECT THE DISK
CALL DISKSELECT
LD HL,(DKDMA) ;INITIALIZE HL AND BC REGS FOR I/O
LD BC,8000H+DATAPORT ;80H IS 128 BYTE SECTORS
LD D,A ;SAVE THE A REG
DI ;DISABLE INTERRUPTS
LD A,(DKSECT)
OUT SECTPORT,A ;SET THE SECTOR WANTED
IN A,FLAGPORT
CPL ;SEE IF HEAD IS LOADED
AND A,20H
JR Z,IN0
LD A,04 ;THIS IS THE HEAD LOAD BIT
IN0:
ADD A,E ;ADD HEAD LOAD BIT TO COMMAND
LD E,A
LD A,D ;RESTORE THE A REG
OUT FLAGPORT,A
LD A,E
OUT STATPORT,A ;OUTPUT THE COMMAND
RET
;
; FIGURE OUT WHICH DISK TO SELECT AND PUT BIT THERE
;
DISKSELECT:
PUSH BC ;FIRST, SAVE THIS, ITS NEEDED
LD C,A
LD A,(DKNUMB) ;GET DISK NUMBER 0-3
LD B,A
INC B ;ADD ONE
SUB A,A
SCF ;SET A BIT IN TO BE SHIFTED
SHIFTBIT:
RLA ;NOW, ROTATE BITS OVER
DJNZ SHIFTBIT
LD B,A ;SAVE THE NEW VALUE
XOR A
OR A,20H+LARGESW*10H ;CONDITION 4FDC FOR MOTOR ON AND MAXI
OR A,B
OR A,C ;OR IN DRIVE SELECT AND COMMAND WANTED
POP BC
RET
;
; THIS TRAPS THE MISSING MEMORY ERROR, BECAUSE IF A
; MEMORY BOARD IS MISSING, THAT WILL GIVE FF'S, AND
; THE FF OP-CODE IS THE RST 38H, SO THAT TRAPS HERE
;
MERROR:
LD SP,80H
LD HL,ERRMSG ;PRINT OUT THE ERROR AND WARMSTART
CALL PRMSG
;
; GETS CONTROL ON A WARM START
;
WBOOT:
LD A,01H ;FIRST, RESTORE DEFAULT BANKING
OUT BANKPORT,A
;
LD SP,80H
LD A,(DKNUMB)
LD (CURRDRIVE),A ;STORE SELECTED DRIVE
;
STARTBOOT:
LD C,0
CALL SELDSK ;SELECT DRIVE A TO REBOOT
CALL HOME
LD HL,CPMB-128 ;WILL INCREMENT BY 128 LATER
LD (DKDMA),HL
LD BC,44*256+1 ;SECTOR COUNT, FIRST SECTOR-1
RDSEC:
LD A,C ;C IS SECTOR NUMBER
CP 18+LARGESW*8
JR Z,NXTTRK
LD DE,128 ;INCREMENT DMA ADDRESS
LD HL,(DKDMA)
ADD HL,DE
LD (DKDMA),HL ;STORE DMA ADDRESS
INC C ;INCREMENT SECTOR NUMBER
CALL SETSEC
CALL READ ;READ THE DATA
JR NZ,WBOOT ;ON READ FAILURE TRY AGAIN
DJNZ RDSEC
JR BOOT ;READ CCP AND BDOS;
NXTTRK:
LD A,(DKTRACK)
CP 2-LARGESW
JR Z,BOOT ;STOP AT TRACK 2
LD C,A
INC C ;SEEK NEXT TRACK IF NOT
CALL SETTRK
LD C,0
JR RDSEC
;
;
CBOOT: ;AFTER COLD BOOT
LD SP,80H ;INITIALIZE STACK FOR ROUTINE
LD HL,SIGNON
CALL PRMSG ;PRINT MESSAGE
BOOT: ;GETS CONTROL AFTER COLD OR WARM BOOT
DI
LD A,0C3H ;SET UP PARAMETERS ON PAGE 0
LD (0),A
LD HL,EBOOT
LD (1),HL
LD (7*8),A ;PRINT ERROR AND BACK TO BOOT
LD HL,MERROR ; (MAY BE DESTROYED BY DDT
LD (7*8+1),HL
LD (5),A
LD HL,BDOS
LD (6),HL
;
; CROMEMCO INITIALIZATION HERE (READER, LIST NOT NEEDED)
; NOTE .. THE CONSOLE TUART IS INITIALIZED BY RDOS
;
IF BIGIOSW = 1
LD A,BAUDRATE
OUT PBAUDPORT,A
ENDIF
LD A,80H ;RST 7
OUT IMASKPORT,A
LD A,0CH ;RST7 AND INTA
OUT IMODEPORT,A
;
LD BC,80H ;SET DEFAULT DMA ADDR
CALL SETDMA
;
LD A,(CURRDRIVE) ;RESELECT THE DRIVE THAT WAS ACTIVE
LD C,A ; BEFORE THE WARM START
EI
JP CPMB
;
;
ERRMSG:
DEFB 13,10,'?? ERROR ??',13,10,0
;
PRMSG: ;PRINT MESSAGE AT H,L UNTIL 0
LD A,(HL)
OR A ;ZERO?
RET Z
LD C,A ;GO PRINT CHAR
CALL CONOUT
INC HL ;GET NEXT CHAR
JR PRMSG
;
;
;HARDWARE UART CONSOLE ROUTINES
;
CONSTAT:
IN A,CSTATPORT ;CHECK CONSOLE STATUS
AND 40H
RET Z ;ZERO MEANS NO INPUT BYTE READY
LD A,0FFH
RET ;FF MEANS INPUT
;
CONIN:
CALL CONSTAT ;CHECK STATUS TIL GOT A BYTE
JR Z,CONIN
IN A,CDATAPORT ;READ THE BYTE AND KILL OFF 80H
AND 7FH
;
; THE FOLLOWING CODE REPLACES THE DEL KEY WITH A CTRL-U,
; SO THAT DEL MEANS LINE DELETE. USE BACKSPACE TO DELETE
; A SINGLE CHARACTER.
;
; CP 127 ; DEL
; RET NZ
; SUB 127-21 ; CTRL-U
RET
;
; CONSOLE OUTPUT ROUTINE
;
CONOUT:
IN A,CSTATPORT ;FIRST, LOOP UNITL TRANSMITTER BUFFER
AND 80H ;IS EMPTY
JR Z,CONOUT
LD A,C ;NOW, OUTPUT CHARACTER TO CONSOLE
OUT CDATAPORT,A
RET
;
; LIST STATUS CHECK FOR CP/M 2.2
;
LISTAT:
IF BIGIOSW = 1
IN A,LSTATPORT ;IF LIST TRANSMITTER IS BUSY,
CPL ;THEN RETURN WITH ZERO
AND 20H
RET Z
OR A,0FFH ;LIST TRANSMITTER BUFFER IS EMPTY
RET
ENDIF
;
LIST:
IF BIGIOSW = 1
CALL LISTAT ;CHECK IF PRINTER BUSY
JR Z,LIST
LD A,C ;NOW OUTPUT CHARACTER
SET 7,A
OUT LDATAPORT,A ;WITH HIGH STROBE
RES 7,A
OUT LDATAPORT,A ;NOW LOW STROBE
SET 7,A
OUT LDATAPORT,A ;NOW HIGH STROBE AGAIN
RET
ENDIF
;
PUNCH:
IF BIGIOSW = 1
IN A,PSTATPORT ;CHECK IF PUNCH BUFFER EMPTY
AND 80H
JR Z,PUNCH ;LOOP UNTIL READY
LD A,C
OUT PDATAPORT,A ;OUTPUT CHARACTER
RET
ENDIF
;
READER:
IF BIGIOSW = 1
IN A,RSTATPORT ;SEE IF READER BUFFER FULL
AND 40H
JR Z,READER ;LOOP UNTIL FULL
IN A,RDATAPORT ;AND READ IT
RET
ENDIF
;
IF BIGIOSW NE 1
XOR A,A ;DUMMY ROUTINE FOR LIST,PUNCH,READER
RET
ENDIF
;
DKNUMB: EQU 4 ;THIS IS WHERE THE DISK NUMBER IS
; ;KEPT IN NORMAL CP/M
CURRDRIVE:
DB 0 ;THE SAVE AREA FOR THE DEFAULT DRIVE
LOGINTAB:
DB 2-LARGESW,0,0,0 ;FOUR DRIVES MAX
DKSECT:
DB 0 ;SECTOR NUMBER
DKTRACK:
DB 0 ;TRACK NUMBER
DKDMA:
DW 0 ;DMA ADDRESS
TRKERCNT:
DB 0 ;NUMBER OF TRACK ERRORS
RETRYCOUNT:
DB 0 ;NUMBER OF READ ERRORS
;
; FROM HERE ON, THE AREAS ARE INITIALIZED BY CP/M AS NEEDED
;
DIRBUF:
DS 128 ;SAVE AREA FOR DISK DIRECTORY OPERATIONS
;
;
ALV0:
DS 32
;
IF NUMDRIVES > 1
ALV1:
DS 32
ENDIF
;
IF NUMDRIVES > 2
ALV2:
DS 32
ENDIF
;
IF NUMDRIVES > 3
ALV3:
DS 32
ENDIF
;
CSV0:
DS 16
;
IF NUMDRIVES > 1
CSV1:
DS 16
ENDIF
;
IF NUMDRIVES > 2
CSV2:
DS 16
ENDIF
;
IF NUMDRIVES > 3
CSV3:
DS 16
ENDIF
;
; THIS HAD BETTER BE WITHIN YOUR CORE SIZE
;
END