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
/
CPMUG082.ARK
/
NBIOS56.ASM
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
56KB
|
2,199 lines
TITLE 'BIOS - NORTH STAR DD CP/M 2.2 OF 02/21/82'
; PAGE 44
;
; These routines copyright (c) 1980, 1981, 1982 by Steve Bogolub,
; 2338 S. Scoville Ave., Berwyn, IL 60402. Jade Double D (tm)
; disk handlers contributed to the public domain for use on Jade
; equipment by special permission of Jade Computer Products.
; This software may be used freely for non-commercial purposes
; only, and may not be sold.
;
; THIS BIOS CONTAINS ROUTINES TO SUPPORT THE
; FOLLOWING HARDWARE:
;
; DISK: NORTH STAR MDS-AD2 DOUBLE DENSITY 5.25"
; FLOPPY DISK UNITS 1 AND 2 AS CP/M DRIVES
; A: AND B:
;
; JADE DOUBLE D REV C 8" FLOPPY DISK UNITS
; 0 AND 1 AS CP/M DRIVES C: AND D:
;
; SERIAL I/O: HORIZON LEFT (LOW) SERIAL I/O PORT AS
; CP/M DEVICE CRT:
;
; QT IO+ BLOCK D (RIGHT) USART AS CP/M DEVICE
; UC1:, INIT'ED TO 19.2K BAUD RATE
;
; QT IO+ BLOCK C (LEFT) USART AS CP/M DEVICE
; TTY:, INIT'ED TO 300 BAUD RATE
;
; HORIZON RIGHT (HIGH) SERIAL I/O PORT AS
; CP/M DEVICE LPT:, WHICH IS SUPPORTED AS
; A MODEL 40 TELETYPE WITH THE SIMPLIFIED
; (HANDSHAKE) EIA INTERFACE, AND IS GENNED-IN
; AS THE LIST DEVICE.
;
; THE GENNED-IN CONSOLE IS DETERMINED BY SOLICITING
; A SPACE CODE (20H) FROM CRT:, TTY:, AND UC1:. IF
; NO SPACE CODE IS RECEIVED AFTER ABOUT EIGHT SECONDS
; (AT 4 MHZ), CRT: IS ASSUMED TO BE THE CONSOLE. IF
; A SPACE IS READ FROM ONE OF THE DEVICES, THAT DEVICE
; IS ASSUMED TO BE THE CONSOLE.
;
; LIST DEVICE UL1: PRINTS ON THE CURRENT CON: DEVICE.
; IF TTY: IS THE LIST DEVICE, DTR MUST BE HIGH, PROVIDING
; A SERIAL PRINTER PORT. BAT: IS NOT SUPPORTED, AND IS
; SET TO LPT: FOR OUTPUT AND CRT: FOR INPUT.
;
; SINCE THIS BIOS IS SO LARGE, MOVCPM SHOULD BE
; RUN FOR TWO LESS THAN THE DESIRED SYSTEM SIZE
; IN K, I.E. SPECIFY 30 FOR A 32K SYSTEM.
;
; *** IMPORTANT BOOTSTRAP INFO ***
;
; THIS BIOS IS INTENDED TO RUN IN THE LAST
; 3.5K OF MEMORY. THE LAST .5K IS SET ASIDE
; FOR A NORTH STAR SECTOR DEBLOCKING BUFFER.
; THE FIRST 3K IS GENNED-IN BIOS CODE, AND
; IS EXPECTED TO RESIDE ON TRACK 0 OF NORTH
; STAR DISK UNIT 1 (A:) IN SECTORS 5-9, AND
; 4. THE NORTH STAR BOOT PROM READS IN SECTOR
; 4 INTO CONSECUTIVE PAGES OF MEMORY, STARTING
; WITH THE PAGE NUMBER SPECIFIED BY THE FIRST
; BYTE OF SECTOR DATA, THEN JUMPS TO THAT
; ADDRESS + 10 (0AH). THIS BIOS IS SET UP TO
; USE THAT METHOD TO COLD BOOT ITSELF. CODE
; AT THAT ADDRESS READS THE LAST FIVE SECTORS
; OF TRACK ZERO INTO MEMORY AT ADDRESS "BIOS",
; THEN JUMPS TO THE BIOS COLD START ADDRESS.
; THE BIOS COLD BOOT EXPECTS THE JADE DOUBLE D
; CONTROL CODE ("NDCM") TO RESIDE ON SECTORS
; ONE AND TWO OF TRACK ZERO, AND LOADS THOSE
; SECTORS FROM THE DISK INTO THE JADE DD MEMORY,
; THEN RESETS AND STARTS UP THE JADE DD RESIDENT
; Z80. THE BIOS WARM BOOT EXPECTS THE CCP/BDOS
; CODE TO RESIDE ON TRACKS 0-9 OF TRACK ONE
; (IN OTHER WORDS, THE WHOLE TRACK), AND THE
; LAST SECTOR IS EXPECTED TO BE ON TRACK ZERO,
; SECTOR 3. TRACK ZERO, SECTOR ZERO IS RESERVED
; FOR LIFEBOAT-COMPATIBLE ID INFO AND FUTURE
; ADDITIONS. THE MODIFIED VERSION OF SYSGEN
; NAMED "NSGEN" IS SET UP TO TRANSFER CP/M TO
; AND FROM DISK IN THIS REQUIRED MANNER.
;
; WE USE THE Z80 INSTRUCTION "LD A,I" ON ENTRY
; TO THE DISK READ AND WRITE ROUTINES TO GET
; THE STATUS OF THE INTERRUPT FLIP/FLOP, SINCE
; WE MUST DISABLE INTERRUPTS WHILE THE NORTH
; STAR DISK READS OR WRITES ARE PERFORMED.
; USING THE Z80 STATUS, WE CAN RE-ENABLE
; INTERRUPTS AFTER WE LEAVE. THIS CHECK IS
; DONE BY THE ROUTINES "INTDI" AND "INDEN",
; AND CAN EASILY BE REMOVED IF WE EVER GO
; TO A NON-Z80 CPU (NEVER, I HOPE).
;
LDAI EQU 057EDH ;Z80 "LD A,I" BYTE-SWAPPED
; FOR "DW" USE
;
; DISK OPERATING SYSTEM ADDRESSES
;
NKSYS EQU 56 ;SYS SIZE IN K BYTES
KBYTE EQU 1024 ;1K BYTE SIZE
CPMSZ EQU NKSYS*KBYTE ;TOP SYSTEM ADDRESS
CPMBS EQU CPMSZ-(22*KBYTE);CP/M BIAS VALUE
CCP EQU CPMBS+3400H ;ADDRESS OF CCP
BDOS EQU CPMBS+3C00H ;ADDRESS OF BDOS
BIOS EQU CPMBS+4A00H ;ADDRESS OF BIOS
BIOSR EQU 1F80H-BIOS+400H ;DDT LOAD OFFSET
;(LEAVES ROOM FOR NDCM)
IOBYTE EQU 0003H ;IOBYTE ADDRESS
DEFDSK EQU 0004H ;DEFAULT DISK FOR CCP
SECSZ EQU 128 ;BYTES PER SECTOR
HSTSIZ EQU 512 ;BYTES PER N* SECTOR
NDRVS EQU 4 ;# DRIVES IN SYSTEM
;
; BDOS CONSTANTS ON ENTRY TO WRITE
;
WRALL EQU 0 ;WRITE TO ALLOCATED
WRDIR EQU 1 ;WRITE TO DIRECTORY
WRUAL EQU 2 ;WRITE TO UNALLOCATED
;
; NORTH STAR MEMORY MAPPED I/O ADDRESSES
;
NSROM EQU 0E800H ;COLD BOOT ROM ADDRESS
WDATA EQU 0E900H ;WRITE DATA. DATA IS
; LOW 8 ADRESS BITS.
CORDER EQU 0EA00H ;CONTROLLER ORDER
CCMND EQU 0EB00H ;CONTROLLER COMMAND
;
; DOUBLE D HARDWARE PARAMETERS
;
DPORT EQU 043H ;DOUBLE D PORT ADDRESS
DBASE EQU 0E000H ;DOUBLE D WINDOW MEM BASE ADDR
DSHLT EQU 001H ;STATUS PORT INDICATOR
;
; DOUBLE D HARDWARE COMMANDS
;
DCSIN EQU 001H ;SWITCH DD BANK 0 INTO SYS
DCMB0 EQU 001H ;SELECT DD BANK 0
DCMB1 EQU 003H ;SELECT DD BANK 1
DCSOT EQU 000H ;SWITCH DD MEM OUT OF SYS
DCINT EQU 002H ;ISSUE DD Z80A INTERRUPT
DCBGN EQU 080H ;RESET DD Z80A AND EXECUTE
;
; DISK CONTROLLER MODULE LINKAGE (DCM - VER 2.2)
;
; -- COMMAND BLOCK DEFINED
;
DDCBT EQU 0370H ;COMMAND BYTE (BANK 0)
DDDRV EQU 0371H ;DRIVE NUMBER (BANK 0)
DDTRK EQU 0372H ;TRACK NUMBER (BANK 0)
DDSEC EQU 0373H ;SECTOR NUMBER (BANK 0)
DDSTS EQU 0377H ;COMMAND STATUS (BANK 0)
DDBBF EQU 0000H ;1024 SECTOR BUFFER (BANK 1)
DDFBF EQU 0300H ;FORMAT BUFFER (BANK 1)
FMTSZ EQU 0100H ;FORMAT BUFF SIZE
DDDPB EQU 0020H ;ID SEC DPB (BANK 1)
DDDDF EQU DDDPB+0011H ;ID SEC FLAGS (BANK 1)
;
; -- DCM COMMANDS
;
DCLOG EQU 000H ;LOG ON DISKETTE
DCRDS EQU 001H ;READ SECTOR
DCWRS EQU 002H ;WRITE SECTOR
DCFMT EQU 003H ;FORMAT TRACK
DCIDL EQU 007H ;STAY IDLE
;
; CONSOLE DEFINITIONS
;
MOTHR EQU 000H ;HORIZON MOTHERBOARD BASE
CRT EQU MOTHR+2 ;HORIZON LEFT SERIAL BASE
;
QTIO EQU 0A0H ;QT IO+ BOARD BASE
QTCTRL EQU QTIO+03H ;QT CONTROL PORT
QTBAUD EQU QTIO+01H ;QT BAUD RATE PORT
TTY EQU QTIO+08H ;QT LEFT SERIAL BASE
UC1 EQU QTIO+0CH ;QT RIGHT SERIAL BASE
;
CR EQU 0DH ;ASCII CARRIAGE RETURN
LF EQU 0AH ;ASCII LINE FEED
SPACE EQU 20H ;ASCII SPACE
;
; PRINTER DEFINITIONS
;
LPD EQU MOTHR+4 ;DATA OUT
LPC EQU LPD+1 ;STATUS
LPIO EQU MOTHR+6 ;CHAIN CONTROL WORD
CHAIN EQU 10H ;CHAIN RUNNING BIT IN LPIO
FF EQU 0CH ;ASCII FORM FEED
;
;
; BIOS JUMP VECTOR TABLE
;
ORG BIOS ;START OF BIOS CODE
;
JMP NSROM ;COLD BOOT FROM ROM
JMP WARM ;RELOAD CCP/BDOS
;
; USE VECTORS FOR INTERNAL CALLS ON CONSOLE ROUTINES
; INSTEAD OF CALLING THE ROUTINES DIRECTLY SO THAT
; BIOS ERROR I/O CAN BE HANDLED BY "BYE" AND OTHER
; VECTOR-PATCHING PROGRAMS.
;
BCNSCK: JMP CNSCK ;GET CONSOLE STATUS
BCNSIN: JMP CNSIN ;CONSOLE INPUT
BCNSOT: JMP CNSOT ;CONSOLE OUTPUT
;
JMP LIST ;PRINTER OUTPUT
JMP PUNCH ;PUNCH OUTPUT
JMP READER ;READER INPUT
JMP HOME ;HOME SELECTED DRIVE
JMP SELDSK ;SELECT DISK DRIVE
JMP SETTRK ;SET TRACK NUMBER
JMP SETSEC ;SET SECTOR NUMBER
JMP SETDMA ;SET TRANSFER ADDRESS
JMP DISKRD ;PERFORM DISK READ
JMP DISKWR ;PERFORM DISK WRITE
JMP LISTST ;RETURN LIST STAT
JMP SECTRN ;TRANSLATE SECTOR
JMP FORMAT ;FORMAT A JADE DD TRACK
;
; INIT - COLD START ENTRY ** DIRECTORY BUFFER OVERLAY **
;
DIRBF EQU $ ;BUFFER BEGINNING
;
; SCRATCH RAM FOR BDOS OVERLAY
;
D0ALL EQU DIRBF+SECSZ ;OVERLAY ALLOCATE AND CHECK
D0CHK EQU D0ALL+23 ; BUFFERS HERE TOO
D1ALL EQU D0CHK+16
D1CHK EQU D1ALL+23
D2ALL EQU D1CHK+16 ;NOTE THAT THE JADE DISKS
D2CHK EQU D2ALL+39 ; (C: AND D:) MAY NEED
D3ALL EQU D2CHK+32 ; MUCH MORE ALLOC AND
D3CHK EQU D3ALL+39 ; CHECK SPACE THAN N*
;
ENDOV EQU D3CHK+32 ;END OF OVERLAY AREA
;
; THE INIT ROUTINE IS ACTUALLY A CONTINUATION OF THE
; COLD BOOT BEGUN DOWN AT "BOOT".
;
INIT: LXI SP,HSTBUF+HSTSIZ ;SET SP TO SCRATCH AREA
LXI H,CCP ;WHERE TO START CP/M
PUSH H
XRA A ;INIT HORIZON MOTHERBOARD
OUT MOTHR+6
STA COLDB ;BIOS NOW IN MEMORY
MVI A,0B1H ;INIT QT IO+ BOARD
OUT QTCTRL
MVI A,01FH ;INIT UC1: TO 19.2K BAUD
OUT QTBAUD
MVI A,005H ;INIT TTY: TO 300 BAUD
OUT QTBAUD
CALL DELAY ;DELAY FOR 8251'S
MVI A,0AEH ;INIT SERIAL PORTS
OUT CRT+1 ;OUTPUT DUMMY MODE TO INSURE
OUT TTY+1
OUT UC1+1
OUT LPC
CALL DELAY
MVI A,040H ; CMD EXPECTED, THEN OUTPUT
OUT CRT+1 ; RESET CMD
OUT TTY+1
OUT UC1+1
OUT LPC
CALL DELAY
MVI A,04EH ;MODE: 1 STOP BIT, 16X CLK,
OUT CRT+1 ; 8 DATA BITS, NO PARITY
OUT TTY+1
OUT UC1+1
OUT LPC
CALL DELAY
MVI A,037H ;CMD: RTS, ER, RXEN, DTR, TXEN
OUT CRT+1
OUT TTY+1
OUT UC1+1
CALL DELAY
CALL LGOOSE ;FINISH INIT OF MODEL 40
IN CRT ;FLUSH RECEIVER INPUTS
IN TTY
IN UC1
;
; WAIT APPROX 8 SECONDS FOR OPERATOR TO STRIKE
; THE SPACE BAR ON CRT:, UC1:, OR TTY: TO DETERMINE
; CONSOLE. IF NO SPACE RECEIVED, DEFAULT TO CRT:.
;
LXI H,0 ;SET UP WAIT
MVI B,2 ; FOR ABOUT 8 SECS
;
ICHK: CALL CRTCHK ;CHECK CRT:
JZ ICHK5 ;PASS IF NOTHING
IN CRT ; ELSE READ CHAR
ANI 07FH ;STRIP PARITY
CPI SPACE ;IS IT SPACE?
JNZ ICHK5 ;TOSS IF NOT
JMP ICHK20 ;IF SO, CON:=CRT:
;
ICHK5: CALL TTYCHK ;CHECK TTY:
JZ ICHK10
IN TTY
ANI 07FH
CPI SPACE
JNZ ICHK10
MVI A,00B ;CON:=TTY:
JMP ICHK25 ;GO SET IT
;
ICHK10: CALL UC1CHK ;CHECK UC1:
JZ ICHK15
IN UC1
ANI 07FH
CPI SPACE
JNZ ICHK15
MVI A,11B ;CON:=UC1:
JMP ICHK25 ;GO SET IT
;
ICHK15: DCX H ;COUNT DOWN
MOV A,H
ORA L
JNZ ICHK
DCR B
JNZ ICHK
;
ICHK20: MVI A,01B ;TIME UP, SET CON:=CRT:
;
ICHK25: ADI 80H ;DEFAULT LST:=LPT:
STA IOBYTE ;SET INITIAL I/O BYTE
LXI H,MSGSO ;SIGN-ON MSG ADDRESS
CALL MSGOT ;ISSUE MESSAGE
;
; MUST NOW LOAD UP THE JADE DOUBLE D CONTROL CODE
; OFF THE DISK AND START UP THE DOUBLE D.
;
MVI A,DCSIN ;REQUEST BANK ZERO
OUT DPORT
MVI A,1 ;CODE STARTS ON SEC 1
STA HSTSEC ;WE KNOW HSTTRK STILL 0
IN DPORT ;INPUT DD BOARD STATUS
ANI 0EH ;MASK FOR ADDRESS SWITCHES
RLC ;POSITION BITS
ORI DBASE SHR 8 ;OR IN BASE ADDRESS
MOV H,A ;FORM WINDOW ADDRESS IN HL
MVI L,0
SHLD DADDR ;SAVE ADDRESS FOR ALL JADE I/O
SHLD HSTADR ;SET NS I/O ADDR TO DD MEM
CALL WSETUP ;KICK MOTORS AND SEEK TRK
CALL WRMRD ;READ SECTOR AND CHECK ERR
MVI A,2 ;CODE EXTENDS INTO SEC 2
STA HSTSEC
LXI D,512
LHLD DADDR
DAD D
SHLD HSTADR
CALL WRMRD
MVI A,DCBGN ;NOW START UP DD Z80
OUT DPORT
;
JMP CPMLD ;GO PERFORM WARM BOOT FUNCS
;
; THIS DELAY SUBROUTINE IS USED TO HELP US OUT ON
; TIMING WHEN RESETTING THE 8251 CONSOLE SERIAL DEVICE.
;
DELAY: LXI B,600H
DEL5: DCX B
MOV A,B
ORA C
JNZ DEL5
RET
;
MSGSO: DB CR,LF,'North Star / '
DB 'Jade DD '
DB (NKSYS/10)+'0',(NKSYS MOD 10)+'0'
DB 'K CP/M 2.2 of 02/21/82',CR,LF+80H
;
IF ($-ENDOV) SHR 15
ORG ENDOV ;FILL OUT OVERLAY SIZE
ENDIF
;
; SELECT DRIVE - LOGON
;
SELDSK: LXI H,0 ;ERROR RETURN CODE
MOV A,C ;PUT DRIVE # IN A
CPI NDRVS ;CHECK IF LEGAL DRIVE
RNC ;NO CARRY IF ILLEGAL
STA SEKDSK ;STORE DRIVE NUMBER
MOV B,E ;SAVE LOGON REQ REG
MOV L,C ;L = DISK NUMBER
MVI H,0 ;ZERO H REG
DAD H ; *2
DAD H ; *4
DAD H ; *8
DAD H ; *16 (SIZE OF HEADER)
LXI D,D0DPH ;DRIVE 0 DPH
DAD D ;HL = DRIVE N DPH
SHLD DTPTR ;STORE DRIVE TBL PTR
;
; LOG-ON - SET DISK PARAMETER BLOCK
;
; -- CHECK IF LOG-ON REQUESTED
;
XRA A
STA LOGFLG ;ASSUME NO JADE LOGON
MOV A,B ;CHECK LOG REQUEST
ANI 001H ;LOG ON BIT TEST
JNZ NOLOG ;PASS IF NO REQUEST
CALL HFLUSH ;MAKE SURE HOST BUF
JNZ LOGERR ; AVAILABLE, OUT ON ERR
;
; SEE IF DISK IS JADE OR NORTH STAR.
;
LDA SEKDSK ;GET DISK #
CPI 2
JNC LOGJAD ;IF JADE, GO ELSEWHERE
;
; LOG ON NORTH STAR BY READING ID SECTOR, THEN DECIDE
; WHICH TABLE TO USE BASED ON SINGLE OR DOUBLE DENSITY.
; IF DOUBLE DENSITY, LOOK FOR LIFEBOAT 2.X FLAG BYTE
; AT OFFSET 05CH IN THE SECTOR, AND USE LIFEBOAT 2.X
; DPB IF THAT BYTE CONTAINS 0B0H. IF NOT, ASSUME OUR
; NORMAL LIFEBOAT 1.4-COMPATIBLE DPB FOR DOUBLE DENSITY.
;
STA HSTDSK ;GOING TO ACCESS THIS DISK
XRA A
STA HSTTRK ;TRACK ZERO
STA HSTSEC ;N* SECTOR ZERO
CALL INTDI ;INTERRUPTS OFF
CALL READHST ;READ THE SECTOR
CALL INTEN ;INTERRUPTS RESTORED
LDA ERFLAG ;CHECK FOR READ ERROR
ORA A
JNZ LOGERR ;LOG-ON ERROR IF SO
LDA NSDENS ;IF OK, GET DENSITY FLAG
LXI B,TRAN5S ;ASSUME SINGLE DENSITY,
LXI D,DPBNSS ; EVEN THO USUALLY WRONG
ORA A ;CHECK
JNZ LOGNSD ;GO ON IF RIGHT
LXI B,TRAN5D ;DOUBLE DENS, COMMON XLATE
LXI D,DPBNSD ; BUT ASSUME OUR 1.4 DPB
LDA HSTBUF+05CH ;GET LIFEBOAT FLAG BYTE
CPI 0B0H ;IS IT LIFEBOAT 2.X FLAG?
JNZ LOGNSD ;KEEP OUR DPB IF NOT
LXI D,DPBNSL ;GO TO LIFEBOAT 2.X IF NOT
;
LOGNSD: LHLD DTPTR ;LOAD DRIVE TBL PTR
MOV M,C ;SET TRANSLATE TABLE ADDR
INX H
MOV M,B
LXI B,9 ;PT TO DPB ADDR
DAD B
MOV M,E ;SET DPB ADDR
INX H
MOV M,D
JMP NOLOG ;GO COMPLETE LOGON NOW
;
; -- READ JADE IDENTITY SECTOR
;
LOGJAD: STA LOGFLG ;LOGGING ON JADE DISK
MVI A,DCSIN ;SWITCH DD INTO SYS
OUT DPORT ;ISSUE HARDWARE CMND
MVI A,DCLOG ;LOAD DCM LOG-ON CMND
CALL DSKEX ;PERFORM DISK OP
JZ LOGCK ;PASS IF OK
CALL DSKER ;ERROR, BAD LOG ON
;
LOGERR: LXI H,0
RET
;
; -- CHECK FOR JADE ID
;
LOGCK: MVI A,DCMB1 ;SELECT BANK 1
OUT DPORT ; BECAUSE BUFFER IS THERE
LHLD DADDR ;GET DD BUFFER ADDR IN HL
LXI D,JADEID ;DE PNTS TO BIOS ID
MVI B,IDSZE ;SET LABEL SIZE
LOGID: LDAX D ;GET LABEL CHARACTER
CMP M ;DOES ID SECTOR MATCH?
JNZ LG3740 ;ASSUME 3740 IF NOT
INX H ;ADVANCE PTRS
INX D
DCR B
JNZ LOGID ;GO BACK IF MORE TO MATCH
;
; -- DISKETTE CONTAINS ID
;
CALL TRNONE ;ASSUME DDENS
CALL DPBAD ;GET DPB ADDR IN DE
LXI B,DDDPB ;GET ID DPB ADDR IN HL
LHLD DADDR
DAD B
LXI B,DPBSZ ;DPB SIZE IN BYTES
CALL BLOCK ;MOVE INTO DPB
LXI B,DDDDF ;CALC ADDR OF ID FLAGS
LHLD DADDR
DAD B
MOV A,M ;GET ID FLAGS IN ACC
PUSH PSW ;SAVE FLAGS
ANI 0F0H ;STRIP LOW FLAGS
RAR ;MOVE SECTOR SHIFT BIT
RAR ; FLAG RIGHT
RAR
DCX D ;PT INTO DPB ADD-ON
STAX D ;SAVE SECTOR SHIFT
ORA A ;IS THERE A SHIFT?
CNZ TR1024 ;USE 1024 BYTES/SECTOR
; XLATE TABLE IF SO
POP PSW ;GET ORIG FLAGS AGAIN
ANI 04H ;TEST DATA DENSITY
CZ TR3740 ;IF ZERO USE 3740 TRN
;
; SET UP DEBLOCKING VARIABLES FROM DPB VALUES
;
NOLOG: CALL DPBAD ;GET DPB ADDR
XCHG ; IN HL
MOV A,M ;SET UP DEBLOCK
STA CPMSPT ; SECTORS PER TRACK
INX H ;GET TO GROUP MASK
INX H
INX H
MOV A,M ;GET IT
INR A ;CALC # BLOCKS/GROUP
STA UNAVAL ; AND SAVE THAT
LXI D,12
DAD D ;PT TO SECTOR SHIFT
MOV A,M ; BIT FLAG
ORA A ;HAVE WE GOT ONE?
JZ NOSHF ;PASS IF NOT
MVI B,0FFH ;INIT SHIFT COUNT
;
CALCSH: INR B ;COUNT UP A SHIFT
RAR ;SEE IF DONE
JNC CALCSH ;GO BACK IF NOT YET
MOV A,B ;SHIFT COUNT TO ACC
;
NOSHF: STA SECSHF ;STORE SHIFT COUNT
MOV A,M ;RELOAD BIT FLAG
DCR A ;FORM SECTOR MASK
STA SECMSK ; AND SET IT
LHLD DTPTR ;RELOAD PTR
LDA LOGFLG ;WAS JADE LOGGED ON?
ORA A ;FLAG NON-ZERO IF SO,
JNZ DSKOK ; GO HANDLE DCM MORE
RET ;IF NOT, DONE, RET ZERO
;
; -- ASSUME 3740 DISKETTE
;
LG3740: CALL TR3740 ;SET SECTOR TRANSLATE
CALL DPBAD ;SET REGISTER DE
LXI B,DPBSZ ;DPB SIZE IN BYTES
LXI H,DPB8 ;ADDRESS OF BLK IMAGE
CALL BLOCK ;MOVE INTO DPB
JMP NOLOG ;GO SET UP (CLEAR) THE
; DEBLOCK VARIABLES
;
; -- SET 3740 SECTOR TRANSLATION
;
TR3740: LXI D,TRAN8 ;SECTOR TRAN TBL ADDR
;
TRCOM: LHLD DTPTR ;ADDR DISK PARA HDER
MOV M,E
INX H
MOV M,D
RET
;
; -- SET 1024 BYTES/SECTOR TRANSLATION
;
TR1024: LXI D,TRN124 ;SECTOR TRAN TBL ADDR
JMP TRCOM ;GO SET IT
;
; -- SET NO SECTOR TRANSLATION
;
TRNONE: XRA A ;ZERO A REG
LHLD DTPTR
MOV M,A
INX H
MOV M,A
RET
;
; -- GET DRIVE PARA BLK ADDR
;
DPBAD: LHLD DTPTR ;ADDR DISK PARA HDED
LXI D,10 ;DPB TBL PNTR OFFSET
DAD D ;NOW AT DPB PNTR
MOV E,M ;LOAD INTO DE
INX H
MOV D,M
RET ;RETURN TO LOG USER
;
; HOME DRIVE
;
HOME: MVI C,0 ;SET TRACK TO ZERO TO HOME
LDA HSTWRT ;CHECK FOR PENDING WRITE
ORA A
JNZ SETTRK
STA HSTACT ;CLEAR HOST ACTIVE IF NOT
;
; SET TRACK
;
SETTRK: MOV A,C ;MOVE TRACK NUMBER
STA SEKTRK ; THEN SAVE IT
RET ;RETURN TO CALLER
;
; SET SECTOR
;
SETSEC: MOV A,C ;MOVE SECTOR NUMBER
STA SEKSEC ; THEN SAVE IT
RET ;RETURN TO CALLER
;
; SET TRANSFER ADDRESS
;
SETDMA: MOV H,B ;MOVE ADDR TO HL
MOV L,C
SHLD DMAADR ; THEN SAVE IT
RET ;RETURN TO CALLER
;
; SECTOR TRANSLATION
;
SECTRN: MOV A,E ;IS THERE A TABLE?
ORA D
JZ JTRAN ;JADE SPECIAL XLATE IF NOT
XCHG ;MAP OFF TABLE IF SO
DAD B
MOV L,M
MVI H,0
RET
;
JTRAN: MOV H,B ;JADE XLATE OFF BY ONE
MOV L,C ; SO FIX FOR CALLER
INX H
RET ; THEN DONE
;
; IOBYTE IS SUPPORTED FOR CONSOLE AND LIST DEVICE
;
; CONSOLE STATUS
;
CNSCK: CALL CONS ;GET HARDWARE STATUS
RZ ;IF NO CHAR READY, RETURN 0
MVI A,0FFH ; ELSE RETURN 0FFH
RET
;
CONS: LDA IOBYTE ;GET IOBYTE
CALL ROUTE ;DISPATCH TO STATUS ROUTINE
DW TTYCHK ;TTY:
DW CRTCHK ;CRT:
DW CRTCHK ;BAT: (RDR: NOT SUPPORTED)
DW UC1CHK ;UC1:
;
; CONSOLE INPUT
;
CNSIN: CALL CONS ;GET HARDWARE STATUS
JZ CNSIN ;WAIT FOR CHAR READY
CALL CONIN ; THEN GET CHAR
ANI 07FH ;STRIP PARITY
RET ; AND RETURN IN ACC
;
CONIN: LDA IOBYTE
CALL ROUTE ;DISPATCH TO INPUT ROUTINE
DW TTYIN ;TTY:
DW CRTIN ;CRT:
DW CRTIN ;BAT: NOT SUPPORTED, USE CRT:
DW UC1IN ;UC1:
;
; HXBOT DISPLAYS HEXIDECIMAL EQUIV OF ACC CONTENTS.
;
HXBOT: PUSH PSW ;SAVE CHAR
RRC ;SWAP NIBBLES
RRC
RRC
RRC
CALL HXNOT ;OUTPUT HIGH NIBBLE
POP PSW ; THEN LOW NIBBLE
HXNOT: ANI 0FH ;STRIP HIGH NIBBLE
ADI 90H ;CVT TO ASCII DECIMAL
DAA
ACI 40H
DAA
MOV C,A ;CHAR TO C
JMP BCNSOT ;THRU VECTOR TO CNSOT
;
; CONSOLE OUTPUT
;
CNSOT: LDA IOBYTE
CALL ROUTE ;DISPATCH TO OUTPUT ROUTINE
DW TTYOT ;TTY:
DW CRTOT ;CRT:
DW LPTOT ;BAT: NOT SUPPORTED, USE LPT:
DW UC1OT ;UC1:
;
; READER INPUT
;
READER: EQU CNSIN ;SAME AS CONSOLE INPUT
;
; PUNCH OUTPUT
;
PUNCH: EQU CNSOT ;SAME AS CONSOLE OUTPUT
;
; LIST STATUS
;
LISTST: XRA A ;SAY IT'S READY
DCR A
RET
;
; LIST OUTPUT
;
LIST: LDA IOBYTE
RLC ;ROTATE LST: BITS TO LOW
RLC ; BIT POSITIONS
CALL ROUTE ;DISPATCH TO LIST ROUTINE
DW TTYOTS ;TTY: WITH DTR FOR
; SERIAL PRINTERS
DW CRTOT ;CRT:
DW LPTOT ;LPT:
DW CNSOT ;UL1: USES CURRENT CON:
;
; THE ROUTING ROUTINE
;
ROUTE: RLC ;DOUBLE FOR WORD OFFSET
ANI 06H ;STRIP UNUSED BITS
XTHL ;GET DISPATCH TABLE ADDR
ADD L ;ADD OFFSET TO GET
MOV L,A ; TO CORRECT VECTOR
JNC ROUTE5
INR H
ROUTE5: MOV A,M ;PULL VECTOR
INX H
MOV H,M
MOV L,A
XTHL ;STACK VECTOR, RESTORE HL
RET ; THEN OFF TO ROUTINE
;
; HORIZON TTY: ROUTINES
;
TTYCHK: IN TTY+1 ;GET PORT STATUS
ANI 2 ;CHECK RECEIVER
RET ;RET NON-ZERO IF READY
;
TTYIN: IN TTY ;GET PORT DATA
RET
;
TTYOT: IN TTY+1 ;GET PORT STATUS
RRC ;XMIT BUFFER EMPTY?
JNC TTYOT ;IF NOT, WAIT TIL IS
;
; HERE FROM TTYOTS BELOW TO OUTPUT CHAR FROM C
;
TTYOTC: MOV A,C ; THEN OUTPUT CHAR FROM C
OUT TTY
RET
;
; SERIAL PRINTER ROUTINE. WAIT FOR DTR HIGH, XMIT
; BUFFER EMPTY, AND XMITTER READY BEFORE SENDING NEXT
; CHAR. THIS ROUTINE HAS BEEN TESTED WITH THE EPSON
; MX-80 WITH 2K SERIAL BUFFER, WHICH SHOULD BE
; TYPICAL OF SERIAL PRINTERS.
;
TTYOTS: IN TTY+1
ANI 85H
CPI 85H ;NEED ALL 3 BITS HIGH
JNZ TTYOTS
JMP TTYOTC ;NOW OUTPUT
;
; HORIZON CRT: ROUTINES. SAME AS TTY:, BUT DIFF PORT
;
CRTCHK: IN CRT+1 ;GET PORT STATUS
ANI 2 ;CHECK RECEIVER
RET ;RET NON-ZERO IF READY
;
CRTIN: IN CRT ;GET PORT DATA
RET
;
CRTOT: IN CRT+1 ;GET PORT STATUS
RRC ;XMIT BUFFER EMPTY?
JNC CRTOT ;IF NOT, WAIT TIL IS
MOV A,C ; THEN OUTPUT CHAR FROM C
OUT CRT
RET
;
; UC1 CONSOLE SERIAL ROUTINES
;
UC1CHK: IN UC1+1 ;GET PORT STATUS
ANI 02H ;CHECK RECEIVER
RET ;RET NON-ZERO IF READY
;
UC1IN: IN UC1 ;GET PORT DATA
RET
;
UC1OT: IN UC1+1 ;GET PORT STATUS
RRC ;XMIT BUFFER EMPTY?
JNC UC1OT ;IF NOT, WAIT TIL IS
MOV A,C ; THEN OUTPUT CHAR FROM C
OUT UC1
RET
;
; LIST CHAR OUT TO MODEL 40 LINE PRINTER
;
LPTOT: PUSH H ;SAVE HL
PUSH B ;SAVE CHAR TO OUTPUT
IN LPIO ;SEE IF M40 CHAIN RUNNING
ANI CHAIN
JZ LOUT7 ;SKIP RE-INIT IF SO
;
LOUT5: CALL LGOOSE ;GOOSE PRINTER
;
LOUT7: LXI H,0 ;LOAD UP FOR NICE LONG DELAY
MVI B,8
;
LOUT10: DCX H ;COUNT DOWN
MOV A,H ;SEE IF ZERO YET
ORA L
JNZ LOUT20 ;PASS IF NOT
DCR B ;COUNT OFF HIGHER BITS
JNZ LOUT20 ;PASS IF NOT ZERO YET
;
LOUT15: MVI A,'P' ;DISK P: NOT READY, FOR PRINTER
CALL PNTRDY ;REPORT, AND RETURN IF NO CTRL-C
JMP LOUT5 ;NOW GO RE-INIT THE PRINTER
;
LOUT20: IN LPIO ;CHECK FOR CHAIN NOT RUNNING
ANI CHAIN
JNZ LOUT10 ;COUNT DOWN TIMEOUT IF SO
IN LPC ;GET 8251 STATUS
ANI 85H ;STRIP OUT REQ NXT CHAR, XMIT
CPI 85H ; BUF RDY, AND XMIT EMPTY,
; THEN CHECK THEM
JNZ LOUT10 ;ALL 3 MUST BE UP TO SEND
;
; PRINTER NOW READY. OUTPUT CHAR.
;
POP B ;RESTORE CHAR TO C
MOV A,C ; AND GET IT TO ACC
ANI 7FH ;STRIP PARITY
OUT LPD ;OUTPUT THE CHAR
CPI FF ;WAS CHAR FORM FEED?
JNZ LOUT35 ;PASS IF NOT
MVI L,6 ;MUST FOLLOW WITH NULLS IF SO
;
LOUT30: IN LPC ;WAIT FOR BUFFER READY
RRC
JNC LOUT30
XRA A ; THEN OUTPUT NULL
OUT LPD
DCR L ; AND COUNT IT OFF
JNZ LOUT30 ;GO BACK IF MORE TO DO
;
LOUT35: MOV A,C ;RESTORE CHAR TO ACC
POP H ;RESTORE HL
RET ; AND RETURN
;
; TOGGLE DTR FOR PRINTER TO GOOSE IT INTO STARTING CHAIN UP
;
LGOOSE: MVI A,035H ;RAISE DTR
OUT LPC
CALL LWAIT ;DELAY
MVI A,037H ;NOW DROP DTR TO TOGGLE
OUT LPC
LWAIT: XRA A ;DELAY
LPIL: XTHL
XTHL
XTHL
XTHL
DCR A
JNZ LPIL
RET
;
; DEBLOCKING DISK WRITE
;
DISKWR: CALL INTDI ;MASK INTERRUPTS
CALL DSKWR ;DO THE WRITE
JMP INTEN ;GO RESTORE INTS
;
; DEBLOCKING DISK READ. NOTE THAT ON DEBLOCKING READ
; AND WRITE, THE CALLER SECTOR NUMBERS RANGE FROM 1-XX
; DECIMAL. THIS IS FOR COMPATIBILITY WITH 8" FORMATS
; THAT ARE 1-ORIGIN. WE ADJUST FOR THIS THROUGHOUT THE
; DEBLOCKING ROUTINES BY SUBTRACTING 1 FROM SEKSEC
; BEFORE WE USE IT. VARIABLES TO CONTROL DEBLOCKING
; ARE SET UP FOR US WHEN DISK IS SELECTED.
;
DISKRD: CALL INTDI ;DISABLE INTERRUPTS
CALL DSKRD ;DO THE I/O
;
INTEN: PUSH PSW ;SAVE DISK I/O ERROR CODE
LHLD ENTPSW ;GET ENTRY PSW TO TEST
PUSH H
POP PSW
JPO INTEN5 ;PASS IF INTS OFF WHEN ENTERED
EI ; ELSE RE-ENABLE INTS
;
INTEN5: POP PSW ;RESTORE DISK I/O ERROR CODE
RET ; THEN RETURN TO CALLER
;
INTDI: MVI A,7FH ;CHECK FOR RUNNING ON
INR A ; 8080 OR Z80
JPO NOTZ80 ;CAN'T GET INT STATE ON 8080
DW LDAI ;GET INT STATE INTO
PUSH PSW ; PARITY FLAG, THEN
POP H ; SAVE PSW IN MEMORY
SHLD ENTPSW
;
NOTZ80: DI ;ALLOW NO INTERRUPTS
RET ; DURING THE I/O XFER
;
DSKRD: LDA SECSHF ;SEE IF DEBLOCKING
ORA A
JZ JADERD ;MUST BE JADE IF NOT
LDA SEKDSK ;IF SO, SEE IF JADE ANYWAY
CPI 2
JC NOTJR ;PASS IF NOT, N* READ
LDA SEKTRK ;IF SO, IS TRACK 0 OR 1?
CPI 2
JC JADERD ;NORMAL SECTOR SIZE IF SO
;
NOTJR: MVI A,WRUAL
STA WRTYPE ;TREAT AS UNALLOC
STA READOP ;READ OPERATION
JMP ALLOC ;GO END UNALLOC SECTORS
; AND FORCE READ
;
DSKWR: LDA SECSHF ;SEE IF DEBLOCKING
ORA A
JZ JADEWR ;MUST BE JADE IF NOT
LDA SEKDSK ;IF SO, SEE IF JADE ANYWAY
CPI 2
JC NOTJW ;PASS IF NOT, N* WRITE
LDA SEKTRK ;IF SO, IS TRACK 0 OR 1?
CPI 2
JC JADEWR ;NORMAL SECTOR SIZE IF SO
;
NOTJW: XRA A
STA READOP ;NOT A READ OPERATION
MOV A,C ;WRITE TYPE IN C
STA WRTYPE
CPI WRUAL ;WRITE UNALLOCATED?
JNZ CHKUNA ;CHECK FOR UNALLOC
;
; WRITE TO UNALLOCATED, SET PARAMETERS
;
LDA UNAVAL ;NEXT UNALLOC RECS
STA UNACNT
LHLD SEKDSK ;PICK UP SEKDSK AND SEKTRK
SHLD UNADSK ;UNADSK=SEKDSK, UNATRK=SEKTRK
LDA SEKSEC
STA UNASEC ;UNASEC = SEKSEC
;
; CHECK FOR WRITE TO UNALLOCATED SECTOR
;
CHKUNA: LDA UNACNT ;ANY UNALLOC REMAIN?
ORA A
JZ ALLOC ;SKIP IF NOT
;
; MORE UNALLOCATED RECORDS REMAIN
;
DCR A ;UNACNT = UNACNT - 1
STA UNACNT
LDA SEKDSK ;SAME DISK?
LXI H,UNADSK
CMP M ;SEKDSK = UNADSK?
JNZ ALLOC ;SKIP IF NOT
;
; DISKS ARE THE SAME, CHECK TRACKS
;
LDA SEKTRK
LXI H,UNATRK
CMP M ;SEKTRK = UNATRK?
JNZ ALLOC ;SKIP IF NOT
;
; TRACKS ARE THE SAME, CHECK SECTORS
;
LDA SEKSEC
LXI H,UNASEC
CMP M ;SEKSEC = UNASEC?
JNZ ALLOC ;SKIP IF NOT
;
; MATCH, MOVE TO NEXT SECTOR FOR FUTURE REF
;
INR M ;UNASEC = UNASEC+1
LDA CPMSPT ;CHECK FOR END OF TRACK
CMP M
JNC NOOVF ;SKIP IF STILL ON TRACK
;
; OVERFLOW TO NEXT TRACK
;
MVI M,1 ;UNASEC = 1
LXI H,UNATRK
INR M ;UNATRK = UNATRK+1
;
; MATCH FOUND, MARK AS UNNECESSARY READ
;
NOOVF: XRA A
STA RSFLAG ;RSFLAG = 0
JMP RWOPER ;GO DO WRITE
;
; NOT AN UNALLOCATED RECORD, REQUIRES PRE-READ
;
ALLOC: XRA A
STA UNACNT ;UNACNT = 0
INR A
STA RSFLAG ;RSFLAG = 1
;
; COMMON CODE FOR READ AND WRITE FOLLOWS
;
RWOPER: XRA A
STA ERFLAG ;NO ERRORS (YET)
LDA SECSHF ;GET SECTOR SHIFT COUNT
MOV B,A ; IN COUNT REG
LDA SEKSEC ;COMPUTE HOST SECTOR
DCR A ;ADJUST FOR 1-ORIGIN
;
RWOPSH: ORA A ;CARRY = 0
RAR ;SHIFT RIGHT
DCR B ;COUNT OFF A SHIFT
JNZ RWOPSH ;LOOP IF MORE
STA SEKHST ;HOST SECTOR TO SEEK
;
; ACTIVE HOST SECTOR?
;
LXI H,HSTACT ;HOST ACTIVE FLAG
MOV A,M
MVI M,1 ;ALWAYS BECOMES 1
ORA A ;WAS IT ALREADY?
JZ FILHST ;FILL HOST IF NOT
;
; HOST BUFFER ACTIVE, SAME AS SEEK BUFFER?
;
LDA SEKDSK
LXI H,HSTDSK ;SAME DISK?
CMP M ;SEKDSK = HSTDSK?
JNZ NOMATCH
;
; SAME DISK, CHECK TRACK
;
LDA SEKTRK
LXI H,HSTTRK
CMP M ;SEKTRK = HSTTRK?
JNZ NOMATCH
;
; SAME DISK AND TRACK, CHECK SECTOR
;
LDA SEKHST
LXI H,HSTSEC
CMP M ;SEKHST = HSTSEC?
JZ MATCH ;SKIP IF MATCH
;
; MUST FLUSH HOST BUFFER FOR NEW SECTOR
;
NOMATCH: LDA HSTWRT ;HOST WRITTEN?
ORA A
CNZ WRITEHST ;CLEAR HOST BUFFER
LDA ERFLAG ;CHECK FOR ERROR
ORA A
RNZ ;RETURN ERROR IF SO
;
FILHST: LHLD SEKDSK ;MAY HAVE TO FILL HOST BUFFER
SHLD HSTDSK ;HSTDSK=SEKDSK,HSTTRK=SEKTRK
LDA SEKHST
STA HSTSEC
XRA A
STA HSTWRT ;NO PENDING WRITE
LDA RSFLAG ;NEED TO READ?
ORA A
JZ MATCH ;NO IF FLAG ZERO
LDA HSTDSK ;SEE WHICH DISK
CPI 2 ;IF C: OR D:, JADE
JNC NOTNSR ;BRANCH IF JADE
CALL READHST ;IF A: OR B:, READ N*
LDA ERFLAG ;CHECK FOR ERRORS
ORA A
RNZ ;NO MORE IF SO
CALL GNSDEN ;CHECK DENSITY
LXI H,NSDENS
CMP M ;IS DENSITY RIGHT?
JZ MATCH ;OK IF SO
LXI H,SDEMSG ;ERROR IF NOT
CALL DSKERR ;REPORT IT
MVI A,5
STA ERFLAG
RET ;RET NZ ACC TO CALLER
;
NOTNSR: CALL JHREAD ;READ JADE DISK
LDA ERFLAG ;READ ERROR?
ORA A
RNZ ;LEAVE BUF ALONE IF SO
;
; COPY DATA TO OR FROM BUFFER
;
MATCH: LDA SECMSK ;GET MASK
MOV H,A ; INTO TEMP REG
LDA SEKSEC ;MASK SECTOR BUFFER NUMBER
DCR A ;ADJUST FOR 1-ORIGIN
ANA H ;LEAST SIGNIF BITS
RAR ;GET VALUE SHIFTED
MOV H,A ; LEFT 7 IN HL
MVI A,0
RAR
MOV L,A
;
; HL CONTAINS RELATIVE HOST BUFFER ADDRESS
;
LXI D,HSTBUF ;ASSUME USING N* BUFFER
LDA HSTDSK ;CHECK DISK SELECTED
CPI 2
JC NJBUF ;RIGHT IF NOT JADE DISK
MVI A,DCMB1 ;USING JADE BUFFER,
OUT DPORT ; SWITCH BANK ONE IN
XCHG ;PUT OFFSET IN DE NOW
LHLD DADDR ;PT HL AT BUFFER
;
NJBUF: DAD D ;HL = HOST ADDRESS
XCHG ;NOW IN DE
LHLD DMAADR ;GET/PUT CP/M DATA
MVI C,SECSZ ;LENGTH OF MOVE
LDA READOP ;WHICH WAY?
ORA A
JNZ RWMOVE ;SKIP IF READ
;
; WRITE OPERATION, MARK AND SWITCH DIRECTION
;
INR A ;ACC KNOWN ZERO ABOVE
STA HSTWRT ;HSTWRT = 1
XCHG ;SOURCE/DEST SWAP
;
RWMOVE: LDAX D ;SOURCE CHARACTER
INX D
MOV M,A ;TO DEST
INX H
DCR C ;LOOP 128 TIMES
JNZ RWMOVE
LDA HSTDSK ;IS THIS JADE DISK?
CPI 2
CNC DSKOUT ;FIX MEM STATUS IF SO
;
; DATA HAS BEEN MOVED TO/FROM HOST BUFFER
;
LDA WRTYPE ;WRITE TYPE
CPI WRDIR ;TO DIRECTORY?
MVI A,0 ;NO ERROR AT THIS PT
RNZ ;RET IF NOT DIR WRITE
;
; CLEAR HOST BUFFER FOR DIRECTORY WRITE
;
CALL WRITEHST
LDA ERFLAG
RET
;
; WRITEHST PERFORMS THE PHYSICAL WRITE TO THE
; NORTH STAR DISK. ON ENTRY, DRIVE IS IN HSTDSK,
; TRACK IS IN HSTTRK, SECTOR IS IN HSTSEC. ON
; EXIT, ERROR FLAG IS IN ERFLAG (ZERO IF NONE).
;
; IT IS ASSUMED INTERRUPTS ARE DISABLED AT
; THIS POINT. IF NOT, I/O MAY BE DISRUPTED.
;
WRITEHST: ;WRITE HOST
XRA A ;BUFFER WILL BE CLEARED
STA HSTWRT
LDA HSTDSK ;SEE IF N* DISK SELECTED
CPI 2
JNC JHWRIT ;IF NOT, DO JADE WRITE
CALL GNSDEN ;GET DENSITY BASED ON ID
STA NSCNT ;SET WRITE BYTE COUNT
CALL SETUP ;SELECT DRIVE AND
; SEEK TO TRACK
LDA ERFLAG ;CHECK FOR ERRORS
ORA A
RNZ ;INDEX PULSE NOT FOUND IS FATAL
CALL POSEC ;POSITION TO SECTOR
JNZ SNFERR ;OUT ON ERROR
LDA CCMND+20H ;GET B-STATUS
ANI 02H ;IS DISK WRITE-PROTECTED?
MVI A,6 ;ASSUME SO, ERROR CODE 6
STA ERFLAG
JNZ WPERR ;WRITE ALWAYS FAILS IF SO
LHLD HSTADR ;GET ADDRESS TO WRITE FROM
MVI B,31 ;ASSUME DOUBLE DENSITY
MVI E,2
LDA NSCNT ;CHECK
MOV C,A ;SAVE COUNT FOR LATER
ORA A
JZ WRIT5 ;GO ON IF COUNTS RIGHT
MVI B,15 ;CORRECT FOR SINGLE DENS
DCR E
;
WRIT5: LDA CCMND+16H ;INITIATE SECTOR WRITE
;
WRIT10: LDA CCMND+15H ;KEEP MOTORS RUNNING, GET A-STAT
ANI 08H ;MUST LOOP UNTIL 96 USEC WINDOW
JNZ WRIT10 ; PAST, SO LOOP WHILE WI TRUE
;
; NOW WRITE THE 31 OR 15 BYTES OF LEADING ZEROES ON THE SECTOR
;
WRIT15: LDA WDATA+00H ;WRITE A BYTE OF ZEROES
NOP ;KILL TIME
MVI D,WDATA SHR 8 ;KILL TIME BY LOADING D FOR LATER
DCR B ;COUNT OFF A ZERO BYTE
JNZ WRIT15 ;DO THEM ALL
;
; FOLLOW WITH ONE OR TWO SYNCH BYTES
;
WRIT17: LDA WDATA+0FBH ;WRITE A SYNCH BYTE
DCR E ;CHECK FOR 2ND NEEDED
JNZ WRIT17 ;GO BACK IF SO
;
; NOW WRITE OUT 256 OR 512 BYTES. DO THIS TWO AT A
; TIME SO WE CAN USE A SINGLE PRECISION COUNTER. B IS
; ZERO FROM ABOVE TO INIT THE CRC BYTE.
;
WRIT20: MOV A,M ;GET NEXT BYTE TO OUTPUT
MOV E,A ; IN OUTPUT REG
XRA B ;ADD INTO CHECKSUM
RLC
MOV B,A ;LEAVE CHECKSUM IN B
LDAX D ;WRITE DATA BYTE TO DISK
INX H ;BOP BUF PTR
MOV A,M ;REPEAT FOR NEXT BYTE
MOV E,A
XRA B
RLC
MOV B,A
LDAX D
INX H
DCR C ;COUNT OFF LAST PAIR OF BYTES
JNZ WRIT20 ;GO BACK IF MORE TO WRITE
MOV E,B ;IF NOT, TIME TO WRITE CHECKSUM
INX B ;KILL TIME
LDAX D ; THEN WRITE THE BYTE
XRA A ;DONE, INDICATE NO ERROR
STA ERFLAG
RET ;RETURN TO CALLER
;
WPERR: LXI H,WPEMSG ;WRITE PROTECT ERROR
JMP DSKERR ;TELL OPERATOR ON WAY OUT
;
; GNSDEN IS CALLED BY N* I/O ROUTINES TO DETERMINE THE
; DENSITY OF THE CURRENT BLOCK BASED ON THE DENSITY OF
; THE ID BLOCK. THAT IS DETERMINED BY TAKING ADVANTAGE
; OF THE FACT THAT THE HOST DISK HAS NO TRANSLATE TABLE
; IF SINGLE DENSITY.
;
GNSDEN: LXI H,D0DPH ;ASSUME A:
LDA HSTDSK ;NOW CHECK
ORA A
JZ GNSDA ;GO ON IF SO
LXI H,D1DPH ;B: IF NOT
GNSDA: MOV A,M ;SEE IF GOT XLATE TABLE
INX H
ORA M ;IF NOT, SINGLE DENSITY
MVI A,80H ;ASSUME SINGLE
RZ ;DONE IF RIGHT
XRA A ;CORRECT IF DOUBLE DENSITY
RET
;
; DISK I/O ROUTINES FOR JADE DOUBLE D CONTROLLER
;
; JADE HOST WRITE FOR FLUSHING BIG SECTOR BUFFER.
; LIKE JADE HOST READ, THESE ROUTINES ARE CALLED BY
; SECTOR DEBLOCKING I/O ROUTINES TO HANDLE JADE DISKS
; WITH DATA SECTORS OF LARGER THAN 128 BYTES/SECTOR.
;
JHWRIT: MVI B,DCWRS ;WRITE OP
JMP JHOP
;
; JADE HOST READ FOR FILLING BIG SECTOR BUFFER
;
JHREAD: MVI B,DCRDS ;READ OP
;
JHOP: LDA HSTDSK ;SET UP DISK TO USE
SUI 2 ;OFFSET FOR 2ND CTRLR
STA BTDSK
LDA HSTTRK ;THIS TRACK
STA BTTRK
LDA HSTSEC ;THIS SECTOR
INR A ;ADJUST FOR 1-ORIGIN
STA BTSEC
MVI A,DCSIN ;SWITCH IN JADE MEM
OUT DPORT
MOV A,B ;SET READ OR WRITE
STA BTCMD
CALL DSKEXR ;DO THE OPERATION
JZ DSKOK ;IF OK, GO THERE
JMP DSKER ;IF ERROR, GO REPORT
;
; READ A JADE DISK SECTOR ROUTINE. LIKE JADE DISK
; WRITE, THIS ROUTINE IS CALLED TO DO A NORMAL, NON-
; DEBLOCKING SECTOR I/O TO A DISK WITH 128-BYTE SECTORS.
;
JADERD: CALL JFLUSH ;FLUSH JADE BUF MAYBE
RNZ ;OUT ON ERROR
MVI A,DCSIN ;SWITCH DD INTO SYS
OUT DPORT
MVI A,DCRDS ;READ SECTOR COMMAND
CALL DSKEX ;PERFORM OPERATION
JNZ DSKER ;ERROR EXIT
LHLD DMAADR ;LOAD USER BUF ADDRESS
XCHG
LHLD DADDR ;GET SECTOR BUF ADDR IN HL
LXI B,SECSZ ;LOAD SECTOR SIZE
MVI A,DCMB1 ;BUFFER IS IN BANK ONE
OUT DPORT
CALL BLOCK ;BLOCK MOVE ROUTINE
JMP DSKOK ;NORMAL RETURN
;
; WRITE A JADE DISK SECTOR
;
JADEWR: CALL JFLUSH ;FLUSH JADE BUF MAYBE
RNZ ;OUT ON ERROR
MVI A,DCMB1 ;SWITCH DD BANK ONE IN
OUT DPORT
LHLD DADDR ;LOAD BUFFER ADDR
XCHG ;GET IT IN DE
LHLD DMAADR ;LOAD USER BUF ADDRESS
LXI B,SECSZ ;LOAD SECTOR SIZE
CALL BLOCK ;BLOCK MOVE ROUTINE
MVI A,DCMB0 ;DSKEX NEEDS BANK 0
OUT DPORT ; SO SWITCH IT IN
MVI A,DCWRS ;LOAD WRITE SEC COMMAND
CALL DSKEX ;CALL DISK EXEC
JNZ DSKER ;IF ERROR, JUMP, ELSE
; FALL INTO DSKOK
;
; JADE DISK READ/WRITE/FORMAT EXITS
;
DSKOK: XRA A ;ZERO PSW
JMP DSKOUT
;
DSKER: PUSH PSW ;SAVE ERROR CODE
LXI H,JIOMSG ;PT TO LEADER
CALL MSGOT ;OUTPUT MESSAGE
POP PSW
CALL HXBOT ;FORMAT AND OUTPUT HEX CODE
LDA BTTRK ;IT HAPPENED ON THIS TRK
STA HSTTRK
LDA BTSEC ; AND THIS SECTOR
STA ERSEC
LDA BTDSK ; WITH THIS DISK
ADI 2 ;OFFSET FOR C:
CALL JAERR ;CALL COMMON CODE TO DO REST
;
FMTER: XRA A ;SIGNAL ERROR TO CALLER
DCR A ; WITH NON-ZERO STATUS
;
DSKOUT: PUSH PSW ;SAVE RETURN STATUS
PUSH H ; AND OTHER REGS
PUSH D
LHLD DADDR ;PT TO DD MEM
LXI D,DDCBT ;CALC DCM CMD BUF ADDR
DAD D
MVI A,DCMB0 ;CALL FOR BANK ZERO
OUT DPORT
MVI M,DCIDL ;MAKE SURE DCM STAYS IDLE
MVI A,DCSOT ;SWITCH OUT DD MEM
OUT DPORT
POP D ;RESTORE REGS NOW
POP H
POP PSW ;GET RETURN PSW
RET ;RET ZERO OR NON-ZERO
;
; JFLUSH IS CALLED BY NORMAL JADE SECTOR ROUTINES TO
; MAKE SURE THE JADE BUFFER IS NOT IN USE WHEN A
; NORMAL READ, WRITE, OR FORMAT OPERATION NEEDS
; THE BUFFER.
;
JFLUSH: XRA A ;NO ERROR YET
STA ERFLAG
LDA HSTDSK ;IF N* DISK,
CPI 2
JC NOJFL ; NOT USING OUR BUFFER
;
; COME HERE FROM SELDSK TO CLEAR ALL PENDING HOST WRITES
;
HFLUSH: LDA HSTWRT ;SEE IF BUFFER NEEDS FLUSH
STA ERFLAG ;NO ERROR IF NOT
ORA A
CNZ WRITEHST ;FLUSH IF SO, IF JADE
; WILL USE BUFFER
XRA A
STA HSTACT ;TOSS READ CONTENTS
STA UNACNT ;BUFFER LEAVING, NEED
; PRE-READ ON NEXT UNALLOC
;
NOJFL: LDA ERFLAG ;SET UP ERROR STATUS
ORA A
RET
;
; FORMAT A JADE DISK TRACK ROUTINE
;
FORMAT: LDA SEKDSK ;ONLY FORMAT JADE DISK
CPI 2
JC FMTER ;ERROR IF ANY OTHER
CALL JFLUSH ;FLUSH JADE BUF MAYBE
RNZ ;OUT ON ERROR
MVI A,DCMB1 ;SWITCH DD BANK ONE
OUT DPORT ; INTO SYS
LXI B,FMTSZ ;FORMAT PROG SIZE
LXI D,DDFBF ;CALC FORMAT BUF ADDR
LHLD DADDR
DAD D
XCHG ;GET IT IN DE
LHLD DMAADR ;FORMAT PROGRAM ADDR
CALL BLOCK ;BLOCK MOVE ROUTINE
MVI A,DCMB0 ;RESELECT DD BANK 0
OUT DPORT
MVI A,DCFMT ;LOAD FORMAT TRK CMND
CALL DSKEX ;CALL DISK EXEC
JMP DSKOK ;GO RETURN STATUS TO CALLER
;
; DOUBLE D EXECUTION SUBROUTINE
;
DSKEX: STA BTCMD ;STORE DCM COMMAND
LDA SEKDSK ;MAP DISK TO JADE DD #
SUI 2
STA BTDSK ; AND STORE JADE DISK #
LDA SEKTRK ;SET TRACK #
STA BTTRK
LDA SEKSEC ; AND SECTOR #
STA BTSEC
;
; HERE ON RETRY AFTER DISK NOT READY
;
DSKEXR: LXI B,7 ;# BYTES TO MOVE
LXI D,DDCBT ;CALC DCM COMMAND BUF ADDR
LHLD DADDR
DAD D
XCHG ;GET IT IN DE
LXI H,BTCMD ;BIOS COMMAND BLOCK
CALL BLOCK ;PERFORM BLOCK MOVE
MVI A,DCINT ;INTERRUPT DD
OUT DPORT
XCHG ;EXCHANGE SRC/DST
DSKWT: IN DPORT ;READ DD STATUS
ANI DSHLT ;TEST HALT* FLAG
JNZ DSKWT ;WAIT UNTIL DD HALTED
MVI A,DCSIN ;SWITCH DD INTO SYS
OUT DPORT
MOV A,M ;GET DD STATUS BYTE
STAX D ;SAVE IN MEM
STA ERFLAG ;SET ERFLAG FOR JHOP
ANA A ;TEST FOR ERRORS
RP ;RETURN TO CALLER IF DISK READY
CALL NOTRDY ;IF NOT READY, REPORT
JMP DSKEXR ;IF CAME BACK, RETRY
;
; BLOCK - BLOCK MOVE (Z80 LDIR REGISTER USAGE)
;
BLOCK: MOV A,M ;GET BYTE
STAX D ;STORE IT
INX H ;BOP PTRS
INX D
DCX B ;COUNT OFF BYTE
MOV A,B ;CHECK FOR DONE
ORA C
JNZ BLOCK ;GO BACK IF NOT
RET
;
;
; HERE TO REPORT DISK NOT READY. TELL CONSOLE WHICH
; DISK IT WAS, THEN SOLICIT REPLY. IF CTRL-C, WARM
; BOOT TO A:, ELSE RETURN TO CALLER.
;
NOTRDY: LDA SEKDSK ;STUFF DISK
ADI 'A'
;
; ENTER HERE TO REPORT LINE PRINTER NOT READY
;
PNTRDY: STA NRD ; INTO MSG
LXI H,NRDMSG
CALL MSGOT ;REPORT TO OPERATOR
CALL BCNSIN ;GET REPLY
SUI 3 ;IS ANSWER CTRL-C?
RNZ ;RETURN TO CALLER IF NOT
STA DEFDSK ;SELECT A: IF SO,
; THEN WARM BOOT IT
;
; WARM BOOT ENTRY. LOAD CCP/BDOS AND INITIALIZE
;
WARM: DI ;NO PROCESSOR INTS DURING BOOT
LDA DEFDSK ;GET CURRENT DEFAULT DISK
MOV B,A ;SAVE IT
ANI 0F0H ;GET USER #
MOV C,A ;SAVE THAT
MOV A,B
ANI 00FH ;ISOLATE DISK #
CPI NDRVS ;IS IT LEGAL?
JC WRMOK ;GO ON IF SO
XRA A ;BACK TO DRIVE ZERO IF NOT
MOV C,A ;USER # PROB BAD TOO
WRMOK: ORA C ;COMBINE WITH USER #
STA DFIMG ;PUT TO BASE PAGE IMAGE
LXI SP,HSTBUF+HSTSIZ ;SET SP TO SCRATCH RAM
LXI H,CCP+3 ;CP/M WARM START ADDR
PUSH H
;
; MERGE HERE FROM COLD BOOT
;
CPMLD: LDA IOBYTE ;GET CURRENT IOBYTE
STA IOIMG ; INTO BASE PAGE IMAGE
LXI B,8 ;MOVE ZERO PAGE STUFF
LXI D,0 ; DOWN TO ZERO
LXI H,BSIMG
CALL BLOCK
LXI H,05959H ;FORCE HOME OF N* DRIVES
SHLD NSTRK ; A, B
MOV A,H ;MAKE SURE NEW DISK SELECTED
STA CURDSK
XRA A ;DRIVE ZERO VALUE
STA HSTDSK
STA HSTACT ;HOST BUFFER INACTIVE
STA HSTWRT ;NO HOST WRITE PENDING
STA UNACNT ;CLEAR UNALLOC COUNT
LXI H,CCP ;CP/M CCP ADDRESS
SHLD HSTADR ;READ INTO THERE
INR A ;GET 1 IN ACC
STA HSTTRK ;READ FROM TRACK ONE
CALL WSETUP ;KICK MOTORS AND SEEK TRK
XRA A ;SECTOR ZERO
;
; READ ALL TEN SECTORS FROM TRACK ONE THEN ONE SECTOR
; FROM TRACK ZERO (SECTOR 3).
;
WREAD: STA HSTSEC ;SET CURRENT SECTOR TO READ
CALL WRMRD ;READ SECTOR AND CHK STATUS
LXI D,HSTSIZ ;SECTOR SIZE
LHLD HSTADR ;CALC NEW ADDRESS
DAD D
SHLD HSTADR
LDA HSTSEC ;BOP SECTOR #
INR A
CPI 10 ;OFF END OF TRACK ONE?
JNZ WREAD ;GO GET NEXT SECTOR IF NOT
XRA A ;TO TRACK ZERO,
STA HSTTRK
CALL WSETUP
MVI A,3 ; SECTOR 3 IF SO
STA HSTSEC
CALL WRMRD ;READ THE LAST SECTOR
LXI H,HSTBUF ;NOW READ AND WRITE
SHLD HSTADR ; USING DEBLOCK BUFFER
LDA DFIMG ;RETRIEVE LAST USED DRIVE
MOV C,A ; FOR BDOS
RET ; THEN GO TO CP/M
;
WSETUP: CALL SETUP ;KICK MOTORS AND SEEK TRK
JMP WECHK
;
WRMRD: CALL READNS ;READ HOST SECTOR
WECHK: LDA ERFLAG ;CHECK FOR ERROR
ORA A
RZ ;RETURN IF NONE
LXI H,MSGLE ;GET ERROR MESSAGE
CALL MSGOT ;TYPE IT
HLT ; THEN GIVE UP
;
; MSGOT DISPLAYS STRING OF CHARS PT'ED AT BY HL ON
; CONSOLE, UNTIL CHAR WITH PARITY BIT SET IS OUTPUT.
;
MSGOT: PUSH PSW ;SAVE CALLER FLAGS
MSGL: MOV C,M ;LOAD CHAR
PUSH H ;SAVE HL
CALL BCNSOT ;OUTPUT CHAR IN C
POP H ;RESTORE HL
MOV A,M ;GET CHAR BACK TO LOOK AT
INX H ;LEAVE PTR ON NEXT CHAR
RAL ;IS HIGH BIT ON?
JNC MSGL ;GO BACK IF NOT
POP PSW ; ELSE RESTORE FLAGS
RET ; AND RETURN
;
; DISK ERROR MESSAGES
;
WPEMSG: DB 'Protec','t'+80H
SDEMSG: DB 'Densit','y'+80H
RERMSG: DB 'CR','C'+80H
SYEMSG: DB 'Syn','c'+80H
NIPMSG: DB 'Inde','x'+80H
SNFMSG: DB 'Secto','r'+80H
JIOMSG: DB CR,LF,'Jade DD',' '+80H
;
ERRMSG: DB ' err '
ASCDSK: DB ' : trk',' '+80H
SECMSG: DB ' sec',' '+80H
NRDMSG: DB CR,LF,'Disk '
NRD: DB ' : not ready',' '+80H
CRLF: DB CR,LF+80H
;
MSGLE: DB CR,LF,'Boot er','r'+80H
;
; JADE ID LABEL DEFINITIONS
;
JADEID: DB 'Jade DD ' ;ID LABEL
IDSZE EQU $-JADEID ;LABEL SIZE
;
; NORTH STAR DD SECTOR TRANSLATE TABLE. AFTER
; DEBLOCKING, WORKS OUT TO SKEW FACTOR OF 5.
;
TRAN5D: DB 01,02,03,04
DB 21,22,23,24
DB 05,06,07,08
DB 25,26,27,28
DB 09,10,11,12
DB 29,30,31,32
DB 13,14,15,16
DB 33,34,35,36
DB 17,18,19,20
DB 37,38,39,40
;
; NORTH STAR DD DISK PARAMETER BLOCK. THIS IS OUR
; NORMAL DPB, AND IS COMPATIBLE WITH LIFEBOAT CP/M 1.4
; DISKS.
;
DPBNSD: DW 40 ;SECTORS PER TRACK
DB 3 ;BLOCK SHIFT FACTOR
DB 07H ;BLOCK MASK
DB 0 ;EXM MASK
DW 165-1 ;DISK SIZE - 1
DW 63 ;DIRECTORY MAX
DB 11000000B ;ALLOC 0
DB 0 ;ALLOC 1
DW 16 ;CHECK SIZE
DW 2 ;TRACK OFFSET
;
; THE NEXT BYTE IS ONE WE HAVE ADDED SPECIFICALLY
; FOR THIS BIOS TO CONVENIENCE OUR DEBLOCKING ROUTINES.
; IT IS A SECTOR SHIFT MASK, AND EACH DISK PARAMETER
; BLOCK HAS ONE IN THIS POSITION. THE ALLOWABLE VALUES
; ARE AS FOLLOWS:
;
; 1000B ;1024 BYTES/SECTOR
; 0100B ; 512 BYTES/SECTOR
; 0010B ; 256 BYTES/SECTOR
; 0000B ; 128 BYTES/SECTOR
;
; FOR THE NORTH STAR DD DISKS, 512 IS HARD-CODED. FOR
; THE NORTH STAR SD DISKS, 256 IS HARD-CODED. FOR
; JADE DISKS, THE VALUE IS READ IN FROM THE ID SECTOR.
; IF THE ID LOOKS BOGUS, THE STANDARD 8" DPB IS USED,
; WHICH HAS 128 CANNED-IN.
;
DB 0100B ;512 BYTES/SECTOR
;
; NORTH STAR DD DISK PARAMETER BLOCK, SET UP
; FOR COMPATIBILITY WITH LIFEBOAT CP/M 2.X
; FORMAT DISKS.
;
DPBNSL: DW 40 ;SECTORS PER TRACK
DB 4 ;BLOCK SHIFT FACTOR
DB 0FH ;BLOCK MASK
DB 1 ;EXM MASK
DW 82-1 ;DISK SIZE - 1
DW 63 ;DIRECTORY MAX
DB 10000000B ;ALLOC 0
DB 0 ;ALLOC 1
DW 16 ;CHECK SIZE
DW 2 ;TRACK OFFSET
DB 0100B ;512 BYTES/SECTOR
;
; THERE IS NO NORTH STAR SINGLE DENSITY TRANSLATE
; TABLE.
;
TRAN5S: EQU 0 ;TELL SECTRN TO JUST ADD 1
;
; NORTH STAR SD DISK PARAMETER BLOCK
;
DPBNSS: DW 20 ;SECTORS PER TRACK
DB 3 ;BLOCK SHIFT FACTOR
DB 07H ;BLOCK MASK
DB 0 ;EXM MASK
DW 80-1 ;DISK SIZE - 1
DW 63 ;DIRECTORY MAX
DB 11000000B ;ALLOC 0
DB 0 ;ALLOC 1
DW 16 ;CHECK SIZE
DW 3 ;TRACK OFFSET
DB 0010B ;256 BYTES/SECTOR
;
; STANDARD 8" SECTOR TRANSLATE TABLE
;
TRAN8: DB 1,7,13,19,25,5,11,17,23
DB 3,9,15,21,2,8,14,20,26
DB 6,12,18,24,4,10,16,22
;
; STANDARD 8" DISK PARAMETER BLOCK
;
DPB8: DW 26
DB 3
DB 7
DB 0
DW 242
DW 63
DB 0C0H
DB 0
DW 16
DW 2
;
DB 0000B ;128 BYTES/SECTOR
;
; 1024 BYTES/SECTOR TRANSLATE TABLE
;
TRN124: DB 1,2,3,4,5,6,7,8
DB 25,26,27,28,29,30,31,32
DB 49,50,51,52,53,54,55,56
DB 9,10,11,12,13,14,15,16
DB 33,34,35,36,37,38,39,40
DB 57,58,59,60,61,62,63,64
DB 17,18,19,20,21,22,23,24
DB 41,42,43,44,45,46,47,48
;
; DRIVE PARAMETER HEADER AREA
;
; DRIVES A: AND B: ARE NORTH STAR 5"
;
D0DPH: DW 0 ;SECTOR TRAN TBL SET BY SELDSK
DW 0 ;SCRATCH
DW 0 ;SCRATCH
DW 0 ;SCRATCH
DW DIRBF ;DIRECTORY BUFFER
DW 0 ;DRIVE PARAM BLK SET BY SELDSK
DW D0CHK ;DRIVE CHANGE BLK
DW D0ALL ;DRIVE ALLOCATION
;
D1DPH: DW 0,0,0,0,DIRBF,0,D1CHK,D1ALL
;
; DRIVES C: AND D: ARE JADE 8" SHUGART
;
D2DPH: DW 0,0,0,0,DIRBF,D2DPB,D2CHK,D2ALL
;
D3DPH: DW 0,0,0,0,DIRBF,D3DPB,D3CHK,D3ALL
;
; ZERO PAGE IMAGE -- BLOCK MOVED TO BASE PAGE
;
BSIMG: JMP BIOS+03H ;WARM BOOT VECTOR
IOIMG: DS 1 ;IOBYTE SET BY CPMLD
DFIMG: DB 0 ;DEFAULT DISK -- ZERO
; AFTER COLD BOOT
JMP BDOS+06H ;BDOS CALL VECTOR
;
; BIOS VARIABLE STORAGE
;
SEKDSK: DB 0 ;DRIVE NUMBER
SEKTRK: DS 1 ;TRACK NUMBER (MUST IMM FOLLOW
; SEKDSK FOR LHLD)
SEKSEC: DS 1 ;SECTOR NUMBER
SEKHST: DS 1 ;SEEK SHR SECSHF
HSTACT: DS 1 ;HOST ACTIVE FLAG
HSTWRT: DS 1 ;HOST WRITTEN FLAG
DTPTR: DW 0 ;DRIVE TABLE PTR
LOGFLG: DB 0 ;NON-ZERO IF SELDSK
; LOGGED ON JADE DISK
;
UNACNT: DS 1 ;UNALLOC REC CNT
UNADSK: DS 1 ;LAST UNALLOC DISK
UNATRK: DS 1 ;LAST UNALLOC TRACK (MUST IMM
; FOLLOW UNADSK FOR LHLD)
UNASEC: DS 1 ;LAST UNALLOC SECTOR
;
; DEBLOCKING INFO ABOUT THE CURRENTLY-SELECTED DISK
;
UNAVAL: DS 1 ;# UNALLOC RECS/GROUP
CPMSPT: DS 1 ;# CP/M SECTORS/TRACK
SECSHF: DS 1 ;SECTOR SHIFT COUNT,
; LOG2 (# CP/M SECTORS/HOST BLOCK)
SECMSK: DS 1 ;SECTOR MASK, # CP/M
; SECTORS/HOST BLOCK - 1
;
; JADE DOUBLE D DCM PARAMETER BLOCK. ENTRIES
; MUST BE IN THIS ORDER TO MATCH DCM ROUTINE
; BLOCK.
;
BTCMD: DB 0 ;DCM COMMAND
BTDSK: DS 1 ;JADE DD DRIVE #
BTTRK: DS 1 ;TRACK NUMBER
BTSEC: DS 1 ;SECTOR NUMBER
BTSP0: DB 0 ;SPARE BYTE 0
BTCHR: DB 0 ;LIST CHAR
BTMOD: DB 0 ;MODE CONTROLS
BTSTS: DB 0 ;COMMAND STATUS
BTLAD: DW 0 ;LOAD ADDRESS
BTLNG: DW 0 ;LOAD LENGTH
;
; JADE-ONLY VARIABLES
;
DADDR: DW 0 ;DD MEMORY WINDOW ADDRESS
;
; RESERVE DRIVE PARAMETER BLOCKS FOR JADE DRIVES
;
DPBSZ EQU 16 ;SIZE IS 16 BYTES
D2DPB: DS DPBSZ ;RESERVE 16 BYTES/DISK C-D
;
; EVERYTHING FROM THIS POINT FOR THE NEXT
; 512 BYTES IS READ INTO MEMORY BY THE NORTH
; STAR BOOT PROM. OUR GOAL HERE IS TO GET
; A REASONABLE AMOUNT OF NORMAL BIOS CODE IN,
; BUT AT THE SAME TIME WE NEED THE PORTIONS
; THAT CAN READ THE DISK.
;
; IF THIS SECTION OVERLAYS PREVIOUS BIOS CODE
; OR DATA SPACE, THE PRECEDING BIOS MUST BE
; TRIMMED DOWN.
;
PRVCHK EQU $ ;** MUST NOT EXCEED BOOTA **
;
ORG BIOS+(HSTSIZ*5) ;ORG TO COLD BOOT
;
BOOTA: DB BOOTA SHR 8 ;TELL PROM LOAD ADDR
;
; THE NEXT NINE LOCATIONS ARE SKIPPED OVER
; BY THE BOOT PROM, WHICH READS THIS SECTOR
; THEN JUMPS TO BOOTA+0AH, SO PUT USEFUL VARIABLES
; HERE. NOTE THAT ALL VARIABLES IN THIS SECTOR
; WITH GENNED-IN VALUES ARE SET UP FOR COLD
; BOOT LOADING OF BIOS.
;
HSTADR: DW BIOS ;READ BIOS INTO HERE TO START,
; BUT NORMALLY PTS TO HSTBUF
HSTDSK: DB 0 ;HOST DISK NUMBER
HSTTRK: DB 0 ;HOST TRACK NUMBER (MUST IMM
; FOLLOW HSTDSK FOR LHLD)
HSTSEC: DB 5 ;HOST SECTOR NUMBER
ERFLAG: DB 0 ;ERROR REPORTING
CURDSK: DB 059H ;CURRENT ACTIVE DISK,
; GENNED-IN FORCE SELECT
COLDB: DB 1 ;COLD BOOT WHEN NON-ZERO
ERSEC: DS 1 ;SECTOR IN ERROR
;
; THIS IS THE SECTION OF THE COLD BOOT THAT
; READS IN THE REST OF BIOS. ON MORE CONVENTIONAL
; CP/M SYSTEMS, THIS WOULD BE THE BLOCK ZERO
; BOOT. READ BIOS INTO MEMORY, THEN JUMP TO
; IT TO FINISH COLD BOOTING.
;
D3DPB: EQU $ ;*** OVERLAY N* COLD BOOT ***
;
BOOT: DI ;ALLOW NO PROCESSOR INTERRUPTS
LXI SP,HSTBUF+HSTSIZ ;SET SP TO SCRATCH RAM
CALL SETUP ;GIVE MOTORS EXTRA KICK
; AND SEEK TRK 0
;
BOOTL: CALL READNS ;READ NEXT SECTOR OF BIOS
;WITH COLDB NON-ZERO, NO
; RETURN IF I/O ERROR
LXI H,HSTSEC ;IF OK, BOP SEC NUM
INR M
LHLD HSTADR ; AND ADVANCE READ ADDR
LXI D,HSTSIZ
DAD D
SHLD HSTADR
MVI A,BOOTA SHR 8 ;SEE IF READ ENUFF
CMP H
JNZ BOOTL ;LOOP IF NOT
JMP INIT ;GO START BIOS IF SO
;
; REMAINING NEEDED VARIABLES
;
RTCNT: DS 1 ;ERROR RETRY COUNTER
NSDENS: DS 1 ;DENSITY OF LAST NS DISK BLOCK
; READ, SD=128, DD=0
NSCNT: DB 00H ;COUNT AND DENSITY FLAG, SET
; BY WRITEHST TO MATCH ID SECTOR
;
; NORTH STAR CURRENT TRACK TABLE
;
NSTRK: DB 059H ;NO CURRENT TRACK YET
DB 059H ;EACH ENTRY CONTAINS
; DB 059H ; THE LAST TRACK POSITION
; DB 059H ; FOR THE UNIT 1-4
;
; OTHER VARIABLES HERE BECAUSE THERE IS SPACE, CAN
; BE MOVED IF NECESSARY
;
RSFLAG: DS 1 ;READ SECTOR FLAG
READOP: DS 1 ;1 IF READ OPERATION
WRTYPE: DS 1 ;WRITE OPERATION TYPE
DMAADR: DS 2 ;LAST DMA ADDRESS
ENTPSW: DW 0 ;ENTRY PSW AT DISK READ/WRITE
;
; READHST PERFORMS THE PHYSICAL READ FROM THE
; NORTH STAR DISK. ON ENTRY, DRIVE IS IN HSTDSK,
; TRACK IS IN HSTTRK, SECTOR IS IN HSTSEC. ON
; EXIT, ERROR FLAG IS IN ERFLAG (ZERO IF NONE).
;
; *** INTERRUPTS MUST BE DISABLED HERE ***
;
READHST:
MVI A,10 ;RETRY COUNT ON ERROR
STA RTCNT
;
READRT: CALL SETUP ;SELECT DRIVE AND
; SEEK TO TRACK
LDA ERFLAG ;CHECK FOR ERRORS
ORA A
RNZ ;INDEX PULSE NOT FOUND IS FATAL
;
; HERE TO READ NORTH STAR WITHOUT TRACK SEEK FOR SPEED
;
READNS: CALL POSEC ;POSITION TO OUR SECTOR
JNZ SNFERR ;ERROR IF NOT FOUND
MVI B,08CH ;COUNT FOR SYNC CHAR LOOP
LXI D,CCMND+40H ;SET UP READ DATA REGS
;
; WAIT FOR RE SO WE CAN DO SECTOR READ, AND TEST
; THE DOUBLE DENSITY BIT.
;
WAITRE: LDA CCMND+10H ;GET A-STATUS
ANI 04H ;CHECK RE
JZ WAITRE ;LOOP UNTIL RE TRUE
XTHL ;KILL TIME TO GET INTO ZEROES
XTHL
XTHL
XTHL
XTHL
XTHL
XTHL
XTHL
LDA CCMND+10H ;GET A-STATUS AGAIN
ANI 20H ;ARE WE READING DOUBLE DENS?
RAL ;MAKE 80H IF NOT, ZERO IF SO
RAL
XRI 80H
STA NSDENS ;SAVE DENSITY FOR CALLER
;
; NOW WAIT FOR SYNC CHAR DETECTED. ERROR IF WE HAVE TO
; WAIT TOO LONG.
;
READ5: LDA CCMND+10H ;WAIT FOR SYNC CHAR DETECTED
RRC ;CHECK BIT
JC READ15 ;OUT IF GOT IT
DCR B ;COUNT DOWN IF NOT
JNZ READ5 ;GO BACK IF STILL OK
MVI A,1 ;SYNC ERROR IF WAITED TOO LONG
LXI H,SYEMSG ;SYNC ERROR MESSAGE
;
RERR: STA ERFLAG ;STORE ERROR CODE
LDA RTCNT ;COUNT OFF A RETRY
DCR A
STA RTCNT
JNZ READRT ;IF COUNT LEFT, GO RETRY
;
; READ ERROR RETRIES FAILED. FLAG ERROR.
;
JMP DSKERR ;TELL OPERATOR OF ERROR THEN OUT
;
SNFERR: STA ERFLAG ;SET ERROR FLAG
LXI H,SNFMSG
JMP DSKERR ;REPORT ERROR ON WAY OUT
;
; READ THE DATA INTO HSTBUF
;
READ15: LHLD HSTADR ;READ INTO HERE
MVI B,0 ;INIT CHECKSUM BYTE
LDA NSDENS ;GET # BYTES TO READ
MOV C,A ;PUT READ COUNT IN C-REG
;
READ20: LDAX D ;READ NEXT DATA BYTE
MOV M,A ; AND PUT IT IN BUFFER
XRA B ;ADD TO CHECKSUM
RLC
MOV B,A
INX H ;BOP BUFFER PTR
NOP ;KILL TIME
LDAX D ;GET NEXT BYTE
MOV M,A
XRA B
RLC
MOV B,A
INX H
DCR C ;COUNT OFF LAST PAIR
JNZ READ20 ;GO BACK IF MORE TO DO
LDAX D ; ELSE READ CRC BYTE
XRA B ; AND CHECK IT AGAINST OURS
STA ERFLAG ;IF OK, ZERO EFLAG
RZ ; AND RETURN TO CALLER
MVI A,2 ; ELSE FLAG CHECKSUM ERROR
LXI H,RERMSG ;MESSAGE IF NEEDED
JMP RERR ;GO MAYBE RETRY
;
; SETUP SELECTS THE UNIT CORRESPONDING TO HSTDSK,
; THEN SEEKS TO THE TRACK SPECIFIED BY HSTTRK.
; WRITE PRECOMPENSATION IS SET IF REQUIRED AS
; WELL. ON ERROR, ERFLAG CONTAINS A NON-ZERO
; VALUE ON RETURN. ONLY UNITS 1 AND 2 ARE SUPPORTED
; TO SAVE SPACE.
;
SETUP: LDA NSCNT ;GET DENSITY FLAG
XRI 80H ;INVERT TO SET DD
MOV C,A ;SAVE MASK
LDA HSTDSK ;WANT THIS DISK
INR A ;REMAP TO CONTROLLER MASK
; CPI 03H ;IF UNIT 1 OR 2,
; JC SET0 ; GOT CORRECT MASK
; RAL ;IF 3 OR 4, MUST MAP
; ANI 0CH ; TO 4 OR 8 RESPECTIVELY
;SET0:
ORA C ;OR IN DENSITY MASK
MOV C,A ;SAVE IN REG C
CALL WAIT1S ;WAIT A SECTOR TIME, GET A-STAT
ANI 10H ;ARE MOTORS ALREADY ON?
LDA CCMND+15H ;GIVE THEM EXTRA KICK ANYWAY
JNZ SET5 ;BRANCH IF SO
MVI D,17H ;WAIT FOR MOTORS TO
CALL SCWAIT ; COME UP TO SPEED IF NOT
JMP SET10 ; THEN GO SELECT DRIVE
;
SET5: LDA CURDSK ;IS THIS THE CURRENT DISK?
CMP C
JZ SET20 ;GO SEEK TO TRACK IF SO
;
; MUST SELECT NEW DISK
;
SET10: MOV A,C
STA CURDSK ;NEW CURRENT DISK
MVI B,CORDER SHR 8 ;SET UP FOR SELECT
LDAX B ; AND DO IT
MVI D,2 ;WAIT TWO SECTOR TIMES
CALL SCWAIT ; BEFORE LOOKING FOR INDEX
MVI B,12 ;DON'T LOOK TOO LONG
;
SET15: CALL WAIT1S ;WAIT A SECTOR TIME, GET A-STAT
ANI 40H ;INDEX HOLE SEEN?
JNZ SET20 ;CAN GO SEEK NOW IF SO
DCR B ;COUNT DOWN IF NOT
JNZ SET15 ; AND MAYBE GO LOOK AGAIN
;
; INDEX HOLE NOT FOUND. DISK IS PROBABLY NOT LOADED.
;
MVI A,4 ;NO INDEX PULSE
STA ERFLAG
LXI H,NIPMSG
CALL DSKERR ;TELL OPERATOR
CALL NOTRDY ; AND CLAIM DISK NOT READY
MVI A,059H ;FORCE RESELECT OF DISK
STA CURDSK
JMP SETUP ;TRY TO GET DISK AGAIN
;
; SEEK TO TRACK SPECIFIED BY HSTTRK NOW, AND SET
; WRITE PRECOMPENSATION IF APPROPRIATE.
;
SET20: LDA HSTDSK ;GET NSTRK INDEX
MOV C,A
MVI B,0
LXI H,NSTRK ;PT AT TABLE
DAD B ; THEN AT CORRECT ENTRY
MOV A,M ;GET CURRENT TRACK
PUSH H ;SAVE NSTRK PTR
XRI 59H ;DISK EVER ACCESSED?
CZ SEEK ;IF NOT, HOME DRIVE
POP H ;RESTORE NSTRK PTR
LDA HSTTRK ;SEEK TO THIS TRACK
PUSH PSW ;SAVE OVER CALL
CALL SEEK ;DO FINAL SEEK
POP PSW ;GET HSTTRK BACK
CPI 14H+1 ;ARE WE BEYOND TRACK 14H?
JC SET25 ;GO ON IF NOT
LDA NSCNT ;SEE IF DD OR SD
ORA A
JNZ SET25 ;NO PRECOMP IF SD
LDA CURDSK ;IF SO, GET CURRENT MASK
ORI 20H ; AND SET PRECOMP BIT
MVI H,CORDER SHR 8
MOV L,A
MOV A,M ;SET BIT IN CONTROLLER
;
SET25: XRA A
STA ERFLAG ;NO ERRORS
RET
;
; POSEC IS CALLED TO POSITION TO HSTSEC WITHIN
; THE CURRENT TRACK. ERROR IS RETURNED BY NON-ZERO
; IF WE CAN'T FIND THE SECTOR AFTER 30 TRIES.
;
POSEC: LDA HSTSEC ;GET TARGET SECTOR
MOV C,A ;IN C
STA ERSEC ;SET UP FOR POSSIBLE ERROR
MVI B,30 ;LOOK AT THIS MANY SECTORS
;
POSC5: CALL WAIT1S ;WAIT FOR NEXT SECTOR
LDA CCMND+35H ;KICK MOTORS AND GET SECNUM
ANI 0FH ;STRIP NON-SECTOR BITS
SUB C ;IS THIS THE TARGET SECTOR?
RZ ;OUT IF GOT IT
DCR B ;COUNT OFF IF DIDN'T
JNZ POSC5 ;GO BACK IF NOT GIVING UP
INR B ;SET NON-ZERO IF NOT FOUND
RET
;
; SEEK TO TRACK SPECIFIED BY ACC. CURRENT PTR INTO
; NSTRK TABLE IS GIVEN BY HL. IF TRACK SPECIFIED IS
; ZERO, SEEK WILL BE DONE UNTIL TRACK ZERO FLAG IS
; SEEN, REGARDLESS OF CURRENT POSITION, UNLESS
; WE ARE ALREADY THERE, SINCE NO SEEK IS DONE
; IF ALREADY AT THE DESIRED TRACK.
;
SEEK: MOV B,A ;SAVE TARGET TRK #
SUB M ;SEE HOW FAR AWAY WE ARE
; FROM TARGET TRACK
MOV M,B ; BUT ALWAYS SET NEW TRACK
RZ ;IF THERE, DONE
LXI H,CORDER+30H ;ASSUME STEPPING IN
MOV C,A ;SAVE STEP COUNT
JP STEPIN ;BRANCH IF RIGHT
CMA ;IF WRONG, NEGATE COUNT
INR A
MOV C,A ; THEN SAVE THAT
LDA CCMND+20H ;GET B-STATUS
ANI 01H ;ARE WE ON TRACK ZERO?
RNZ ;MUST BE DONE IF SO
MVI L,10H ;IF NOT, STEPPING OUT
;
STEPIN: LDA CURDSK ;GET CURRENT UNIT MASK
ORA L ;FORM FINAL CORDER VALUE
MOV L,A
MOV D,M ;SET THE STEP FLIP-FLOP
ORI 10H
MOV L,A
MOV D,M ;SET IT AGAIN FOR SOME REASON
XRI 10H
MOV L,A
MOV D,M ;NOW RESET THE STEP FLIP-FLOP
;
; WAIT WHILE HEAD STARTS MOVING
;
MVI A,14H
STEPW1: MVI D,38H
STEPW2: DCR D ;KILL TIME
JNZ STEPW2
DCR A
JNZ STEPW1
;
; THE STEP RATE DETERMINES HOW LONG TO WAIT. ONE SECTOR
; TIME IS 20 MSEC. A SLOW SHUGART SA400 MAY REQUIRE 40
; MSEC, OR TWO SECTOR TIMES. MOST TYPICAL SA400'S WILL
; WORK WITH 20 MSEC, SO THAT'S WHAT WE'LL USE HERE. WE
; WILL CALL SCWAIT INSTEAD OF WAIT1S IN CASE WE NEED TO
; PATCH THIS VALUE.
;
MVI D,1 ;NOW WAIT 20 MSEC
; MVI D,2 ;NOW WAIT 40 MSEC
CALL SCWAIT
LDA CCMND+25H ;GET B-STATUS AND KICK MOTORS
ANI 01H ;ARE WE AT TRACK ZERO?
JNZ WAIT1S ;DONE STEPPING IF SO
DCR C ; ELSE COUNT OFF LAST TRACK
JNZ STEPIN ;GO BACK IF MORE TO DO
CALL WAIT1S ;WAIT ONE MORE SECTOR TIME
; TO MAKE SURE DONE STEPPING
INR B ;SEEK TO TRACK ZERO?
DCR B
RNZ ;DONE IF NOT
LDA CCMND+25H ;MUST HAVE TRK ZERO FLAG IF SO
ANI 01H
RNZ ;OK IF SO
JMP STEPIN ;GO STEP MORE IF NOT
;
; SECTOR WAIT. ON ENTRY, # SECTORS TO WAIT IS IN D.
; ON EXIT, D=0 AND ACC=A-STATUS. CALL WAIT1S TO WAIT
; ONE SECTOR TIME.
;
WAIT1S: MVI D,1 ;WAIT ONE SECTOR TIME
;
SCWAIT: LDA CCMND+11H ;RESET SECTOR FLAG
SCW5: LDA CCMND+10H ;GET A-STATUS
ORA A ;CHECK SECTOR FLAG
JP SCW5 ;WAIT FOR IT IF NOT UP
LDA CCMND+11H ; ELSE RESET SECTOR FLAG
DCR D ;COUNT DOWN WAIT COUNTER
JNZ SCW5 ;GO BACK IF MORE TO DO
RET ; ELSE RETURN A-STATUS IN ACC
;
; DISK ERRORS REPORTED HERE, BECAUSE STUPID BDOS GIVES
; NO USEFUL INFORMATION.
;
DSKERR: LDA COLDB ;IN COLD BOOT?
ORA A ;IF SO, CNSOT NOT IN MEM YET
JNZ NSROM ;BACK TO N* BOOT ROM ON SAME
PUSH H ;SAVE BODY ADDRESS
LXI H,CRLF ;EJECT LINE
CALL MSGOT
POP H
CALL MSGOT ;REPORT BODY
LDA HSTDSK ;THIS DISK
;
; ENTER HERE AFTER JADE DD I/O ERROR
;
JAERR: ADI 'A'
STA ASCDSK
LXI H,ERRMSG
CALL MSGOT
LDA HSTTRK ;THIS TRACK
CALL HXBOT
LXI H,SECMSG
CALL MSGOT
LDA ERSEC ;THIS SECTOR
JMP HXBOT ;OFF TO HXBOT TO FINISH
;
EBOOT EQU $-1 ;LAST USED COLD BOOT BYTE
;
;
; NORTH STAR HOST SECTOR BUFFER
;
HSTBUF: DS HSTSIZ ;HOST BUFFER
;
LAST EQU $-1 ;LAST USED BYTE IN MEM
;
END