home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Oakland CPM Archive
/
oakcpm.iso
/
cpmug
/
cpmug082.ark
/
SDNBIOS.ASM
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
21KB
|
828 lines
TITLE 'SDNBIOS - N* SD CP/M 2.2 BIOS OF 06/19/81'
;
; THIS BIOS CONTAINS ROUTINES TO SUPPORT THE
; FOLLOWING HARDWARE:
;
; DISK: NORTH STAR MDC-A4 SINGLE DENSITY 5.25"
; FLOPPY DISK UNITS 1 AND 2 AS CP/M DRIVES
; A: AND B:
;
; CONSOLE AND LIST ROUTINES ARE LOCATED IN A
; SEPARATE MODULE LOADED BY THE BOOTSTRAP ROUTINE
; INTO HIGH MEMORY AT ADDRESS USER. THAT VALUE IS
; ASSUMED TO BE ON A 1K BOUNDARY, AND THE USER
; ROUTINES ARE RESTRICTED TO 2 PAGES (SEE BOOTSTRAP
; INFO BELOW), WITH 2 PAGES OF SCRATCH ABOVE AVAILABLE
; FOR USE. THIS BIOS USES THE 1ST OF THOSE SCRATCH
; PAGES FOR BDOS BUFFERS AND ITS OWN VARIABLES.
;
; SINCE THIS BIOS IS SO LARGE, MOVCPM SHOULD BE
; RUN FOR TWO LESS THAN THE DESIRED SYSTEM SIZE
; IN K, I.E. SPECIFY 18 FOR A 20K SYSTEM.
;
; *** IMPORTANT BOOTSTRAP INFORMATION ***
;
; OUR WARM BOOT EXPECTS CCP TO RESIDE ON TRACK
; 1, SECTORS 0-7 INCLUSIVE. BDOS MUST BE ON TRACK
; 1, SECTORS 8-9, THEN CONTINUE ON TRACK 2, SECTORS
; 0-9, THEN FINISH ON TRACK 0, SECTORS 1 AND 9.
;
; THE BOOTSTRAP BLOCK IS LOADED BY THE CONTROLLER
; PROM ROUTINES FROM TRACK 0, SECTOR 4 INTO MEMORY
; AT 2000H. THE BOOTSTRAP ROUTINE WILL THEN LOOK
; FOR THIS BIOS ON TRACK 0, SECTORS 5-8. THE USER
; ROUTINES FOR CONSOLE AND LIST ARE STORED ON TRACK
; 0, SECTORS 2-3. TRACK 0, SECTOR 0 IS RESERVED FOR
; LIFEBOAT-COMPATIBLE ID AND FUTURE EXPANSION.
;
; DISK OPERATING SYSTEM ADDRESSES
;
NKSYS EQU 20 ;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+200H ;DDT LOAD OFFSET
; (LEAVES ROOM FOR "USER")
USER EQU 0A000H ;NON-CONTIGUOUS 1K HIGH RAM
IOBYTE EQU 0003H ;CP/M I/O BYTE ADDRESS
TPA EQU 100H ;ADDRESS OF TPA
SECSZ EQU 128 ;BYTES PER SECTOR
HSTSIZ EQU 256*10 ;BYTES PER N* TRACK
NDRVS EQU 2 ;# DRIVES IN SYSTEM
;
CR EQU 0DH ;ASCII CARRIAGE RETURN
LF EQU 0AH ;ASCII LINE FEED
;
; 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
;
WDATA EQU 0EA00H ;WRITE DATA. DATA IS
; LOW 8 ADRESS BITS.
CCMND EQU 0EB00H ;CONTROLLER COMMAND
;
; KEYPAD LIGHTS
;
LHEX EQU 0DFH ;LEFT HEX LITES
MHEX EQU 0DDH ;MIDDLE HEX LITES
RHEX EQU 0DBH ;RIGHT HEX LITES
;
; BIOS JUMP VECTOR TABLE
;
ORG BIOS ;START OF BIOS CODE
;
JMP COLD ;COLD BOOT FROM ROM
JMP WARM ;RELOAD CCP/BDOS
JMP USER+3 ;GET CONSOLE STATUS
JMP USER+6 ;CONSOLE INPUT
JMP USER+9 ;CONSOLE OUTPUT
JMP USER+12 ;PRINTER OUTPUT
JMP USER+15 ;PUNCH OUTPUT
JMP USER+18 ;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 USER+21 ;RETURN LIST STAT
JMP SECTRN ;TRANSLATE SECTOR
;
MSGOT: EQU USER+24 ;MSG OUT ROUTINE
HXBOT: EQU USER+27 ;HEX CONVERSION ROUTINE
DISKER: EQU USER+30 ;DISK ERROR REPORTER
;
; SELECT DRIVE
;
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 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
RET ;RETURN THAT IN HL
;
; 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 H,B
MOV L,C
INX H ;JUST ADD ONE TO SECNUM
RET ; THEN DONE
;
; 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.
;
; TRACK BUFFERING IS DONE HERE. A HOST BLOCK IS
; CONSIDERED THE ENTIRE HOST TRACK.
;
DISKRD: XRA A ;END OF UNALLOC SECTORS
STA UNACNT ; AFTER READ
INR A
STA READOP ;READ OPERATION
STA RSFLAG ;MUST READ DATA
MVI A,WRUAL
STA WRTYPE ;TREAT AS UNALLOC
JMP RWOPER ;TO PERFORM THE READ
;
; DEBLOCKING DISK WRITE
;
DISKWR: 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 BLKMSK ;NEXT UNALLOC RECS
INR A
STA UNACNT
LDA SEKDSK ;DISK TO SEEK
STA UNADSK ;UNADSK = SEKDSK
LDA SEKTRK
STA UNATRK ;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 DPBNSS ;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)
;
; ACTIVE HOST TRACK?
;
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?
JZ MATCH ;SKIP IF MATCH
;
; MUST FLUSH HOST BUFFER FOR NEW TRACK
;
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: LDA SEKDSK ;MAY HAVE TO FILL HOST BUFFER
STA HSTDSK
LDA SEKTRK
STA HSTTRK
XRA A
STA HSTWRT ;NO PENDING WRITE
LDA RSFLAG ;NEED TO READ?
ORA A
JZ MATCH ;NO IF FLAG ZERO
CALL READHST ;READ HOST
LDA ERFLAG ;CHECK FOR ERRORS
ORA A
RNZ ;NO MORE IF SO
;
; COPY DATA TO OR FROM BUFFER
;
MATCH: LDA SEKSEC ;GET SECTOR NUMBER
DCR A ;ADJUST FOR 1-ORIGIN
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 ;PT TO TRACK BUFFER
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
;
; 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,
; AND TRACK IS IN HSTTRK. ON EXIT, ERROR FLAG
; IS IN ERFLAG (ZERO IF NONE).
; 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
STA ERSEC ;NO SECTOR IN ERROR YET
CALL SETUP ;SELECT DRIVE, SEEK, AND
; POSITION TO SECTOR ZERO
RNZ ;SECTOR NOT FOUND IS FATAL
LHLD HSTADR ;GET ADDRESS TO WRITE FROM
MVI A,10 ;INIT # BLKS TO WRITE
;
; HERE TO WRITE NEXT SECTOR. WRITE-PROTECT CHECK IS
; DONE EVERY SECTOR TO HELP KILL TIME.
;
WRIT5: PUSH PSW ;SAVE # BLKS LEFT
LDA CCMND+10H ;GET A-STATUS
ANI 02H ;IS DISK WRITE-PROTECTED?
MVI A,6 ;ASSUME SO, ERROR CODE 6
JNZ WPERR ;WRITE ALWAYS FAILS IF SO
LDA CCMND+04H ;INITIATE SECTOR WRITE
;
WRIT10: LDA CCMND+10H ;GET A-STATUS
ANI 08H ;MUST LOOP UNTIL 96 USEC WINDOW
JZ WRIT10 ; PAST, SO LOOP UNTIL WRT TRUE
;
; NOW WRITE THE 15 BYTES OF LEADING ZEROES ON THE SECTOR
;
LXI B,15 ;GET ZERO IN C-REG, AND
; LOAD CNT IN B-REG
;
WRIT15: MOV E,B ;KILL TIME AND GET ZERO IN E-REG
MVI D,WDATA SHR 8 ;KILL TIME BY LOADING D FOR LATER
LDAX D ;WRITE A ZERO BYTE
MOV A,M ;KILL MORE TIME
DCR C ;COUNT OFF A ZERO BYTE
JNZ WRIT15 ;DO THEM ALL
;
; FOLLOW WITH SYNCH BYTE
;
MOV E,A ;KILL TIME
MVI E,0FBH ;THIS IS THE SYNCH BYTE VALUE
LDAX D ;WRITE OUT SYNCH BYTE
MOV A,M ;KILL TIME
MOV A,M
;
; NOW WRITE OUT 256 BYTES. B IS ZERO FROM ABOVE TO INIT
; THE CRC BYTE. C IS ZERO FROM COUNTING OUT ABOVE TO INIT
; 256-BYTE COUNTER FOR HERE.
;
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
DCR C ;COUNT OFF LAST BYTE
JNZ WRIT20 ;GO BACK IF MORE TO WRITE
MOV E,B ;IF NOT, TIME TO WRITE CHECKSUM
MOV E,B ;KILL TIME
INX B ;KILL MORE TIME
LDAX D ; THEN WRITE THE BYTE
CALL WAIT1S ;WAIT FOR NEXT SECTOR
POP PSW ;GET COUNT OFF STACK
DCR A ;COUNT OFF LAST SECTOR
JNZ WRIT5 ;GO BACK IF MORE TO WRITE
STA ERFLAG ;FLAG NO ERRORS
RET ; THEN RETURN TO CALLER
;
WPERR: STA ERFLAG ;STORE ERROR CODE
POP PSW ;CLEAN OFF STACK
LXI H,WPEMSG ;WRITE PROTECT ERROR
;
DSKERR: XCHG
LHLD HSTDSK ;PICK UP DISK AND TRACK
XCHG ;LEAVE IN DE
LDA ERSEC ;GET SECTOR IN ERROR
JMP DISKER ;GO REPORT
;
; 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, SEEK, AND
; POSITION TO SECTOR ZERO
RNZ ;SECTOR NOT FOUND IS FATAL
XRA A
STA ERFLAG ;NO ERRORS YET
LHLD HSTADR ;READ INTO HERE
MVI A,10 ;INIT # BLKS TO READ
;
; HERE TO READ NEXT SECTOR. START BY LOOKING FOR
; SYNCH BYTE.
;
RNEXTS: PUSH PSW ;SAVE # BLKS LEFT TO READ
MVI B,08CH ;COUNT FOR SYNC CHAR LOOP
LXI D,CCMND+50H ;SET UP READ DATA REGS
MVI C,0 ;LOAD COUNT OF 256 FOR READ
;
; NOW WAIT FOR SYNC CHAR DETECTED. ERROR IF WE HAVE TO
; WAIT TOO LONG.
;
READ5: LDA CCMND+10H ;GET A-STATUS
ANI 04H ;SYNCH CHAR DETECTED?
JNZ 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
POP B ;GET BLK CNT IN B
MVI A,10
SUB B ;CALC SECTOR # IN ERROR
STA ERSEC ;SAVE FOR REPORTING
LDA RTCNT ;COUNT OFF A RETRY
DCR A
STA RTCNT
JNZ READRT ;IF COUNT LEFT, GO RETRY
;
; READ ERROR RETRIES FAILED. FLAG ERROR.
;
FRERR: JMP DSKERR ;TELL OPERATOR OF ERROR THEN OUT
;
; READ THE DATA INTO HSTBUF
;
READ15: MOV B,C ;INIT CHECKSUM FROM ZERO IN C
;
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
DCR C ;COUNT OFF LAST BYTE
JNZ READ20 ;GO BACK IF MORE TO DO
LDAX D ; ELSE READ CRC BYTE
XRA B ; AND CHECK IT AGAINST OURS
JZ READ25 ;GO ON IF READ OK
MVI A,2 ;IF NOT, FLAG CHECKSUM ERROR
LXI H,RERMSG ;MESSAGE IF NEEDED
JMP RERR ;GO MAYBE RETRY
;
READ25: CALL WAIT1S ;WAIT FOR NEXT SECTOR
POP PSW ;GET # BLKS LEFT
DCR A ;COUNT ONE OFF
JNZ RNEXTS ;GO BACK IF MORE
STA ERFLAG ;IF DONE, FLAG NO ERROR
RET ; THEN RETURN TO CALLER
;
; SETUP SELECTS THE UNIT CORRESPONDING TO HSTDSK,
; THEN SEEKS TO THE TRACK SPECIFIED BY HSTTRK.
; ON RETURN, ERFLAG CONTAINS A NON-ZERO VALUE IF
; AN ERROR WAS DETECTED. ONLY UNITS 1 AND 2 ARE
; SUPPORTED TO SAVE CODE.
;
SETUP: LDA HSTDSK ;WANT THIS DISK
INR A ;REMAP TO CONTROLLER MASK
MOV C,A ;SAVE IN REG C
LDA CCMND+90H ;KICK MOTORS AND GET A-STATUS
ANI 10H ;ARE MOTORS ALREADY ON?
JNZ SET5 ;BRANCH IF SO
MVI D,50 ;WAIT 1 SECOND 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,CCMND SHR 8 ;SET UP FOR SELECT
LDAX B ; AND DO IT
MVI D,13 ;WAIT 13 SECTOR TIMES AFTERWARDS
CALL SCWAIT
;
; SEEK TO TRACK SPECIFIED BY HSTTRK NOW.
;
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
XRI 59H ;WAS DISK EVER ACCESSED?
PUSH H ;SAVE TABLE PTR
CZ SEEK ;HOME DISK IF 1ST SEEK
POP H ;RESTORE TABLE PTR
LDA HSTTRK ;GET DESIRED TRACK #
CALL SEEK ;SEEK TO HSTTRK
;
; HERE TO POSITION TO SECTOR ZERO WITHIN THE
; CURRENT TRACK. ERROR IS RETURNED BY NON-ZERO
; IF WE CAN'T FIND THE SECTOR AFTER 30 TRIES.
;
MVI B,30 ;LOOK AT THIS MANY SECTORS
;
POSEC: CALL WAIT1S ;WAIT FOR NEXT SECTOR
LDA CCMND+030H ;GET B-STATUS WITH SECTOR #
ANI 0FH ;STRIP NON-SECTOR BITS
RZ ;OUT IF GOT SECTOR ZERO
DCR B ;COUNT OFF IF DIDN'T
JNZ POSEC ;GO BACK IF NOT GIVING UP
MVI A,1
STA ERFLAG ;SET ERROR FLAG
LXI H,SNFMSG
CALL DSKERR ;REPORT ERROR
XRA A
INR A
RET ;RETURN NON-ZERO TO CALLER
;
; SEEK TO TRACK SPECIFIED BY ACC. CURRENT PTR INTO
; NSTRK TABLE IS IN HL.
;
SEEK: MVI D,LHEX
MOV E,A
STAX D ;DISPLAY TARGET TRK #
MVI D,MHEX
MOV E,M
STAX D ;DISPLAY SOURCE TRK #
MOV C,A ;SAVE TARGET # IN C
SUB M ;SEE HOW FAR AWAY WE ARE
; FROM TARGET TRACK
MOV M,C ; BUT ALWAYS SET NEW TRACK
MVI D,RHEX
MOV E,A
STAX D ;DISPLAY DIFF
RZ ;IF THERE, DONE
LXI H,CCMND+1DH ;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
MOV E,A
STAX D ;SHOW CORRECTED COUNT
LDA CCMND+10H ;GET A-STATUS
ANI 01H ;ARE WE ON TRACK ZERO?
RNZ ;MUST BE DONE IF SO
LXI H,CCMND+1CH ;IF NOT, STEPPING OUT
;
STEPIN: MOV A,M ;SET STEP DIRECTION
;
STEP: LDA CCMND+09H ;SET STEP FLIP-FLOP
XTHL ;DELAY AT LEAST 10 USEC
XTHL
LDA CCMND+08H ; THEN RESET FLIP-FLOP TO PULSE
MVI D,2 ;NOW WAIT TWO SECTOR TIMES
CALL SCWAIT ; WHILE HEAD MOVES (40 MSEC)
LDA CCMND+10H ;GET A-STATUS
ANI 01H ;ARE WE AT TRACK ZERO?
JZ STEP5 ;PASS IF NOT
MVI C,1 ;LAST STEP IF SO
;
STEP5: DCR C ;COUNT OFF LAST TRACK
JNZ STEPIN ;GO BACK IF MORE TO DO
RET ; ELSE RETURN TO CALLER
;
; SECTOR WAIT. ON ENTRY, # SECTORS TO WAIT IS IN D.
; ON EXIT, D=0 AND ACC=GARBAGE. CALL WAIT1S TO WAIT
; ONE SECTOR TIME.
;
WAIT1S: MVI D,1 ;WAIT ONE SECTOR TIME
;
SCWAIT: LDA CCMND+14H ;RESET SECTOR FLAG
SCW5: LDA CCMND+90H ;GET A-STATUS AND KICK MOTORS
ANI 80H ;CHECK SECTOR FLAG
JZ SCW5 ;WAIT FOR IT IF NOT UP
DCR D ;COUNT DOWN WAIT COUNTER
RZ ;RETURN IF DONE COUNTING
JMP SCWAIT ; ELSE GO COUNT MORE
;
; 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
;
; COLD BOOT ENTRY. SET UP FIRST-TIME BIOS STUFF.
;
COLD: LXI SP,80H ;SET SP TO SCRATCH AREA
LXI H,CCP ;WHERE TO START CP/M
PUSH H
JMP CPMLD ;GO LOAD CCP/BDOS
;
; WARM BOOT ENTRY. LOAD CCP/BDOS AND INITIALIZE
;
WARM: LDA 4 ;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,80H ;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 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 WRMRD ; RIGHT INTO MEMORY
LXI H,CCP+HSTSIZ ;NEXT CHUNK
SHLD HSTADR
MVI A,2 ; OFF OF TRACK TWO
STA HSTTRK
CALL WRMRD ;READ IT
LXI H,HSTBUF ;NOW READ AND WRITE
SHLD HSTADR ; USING DEBLOCK BUFFER
XRA A ;READING TRACK ZERO
STA HSTTRK
CALL WRMRD ;READ IT
LXI H,HSTBUF+256 ;MOVE A SECTOR OF BDOS
LXI D,CCP+(HSTSIZ*2); TO HERE
LXI B,256
CALL BLOCK
LXI H,HSTBUF+(256*9);LAST BDOS SECTOR
LXI D,CCP+(HSTSIZ*2)+256
LXI B,256
CALL BLOCK
LDA DFIMG ;RETRIEVE LAST USED DRIVE
MOV C,A ; FOR BDOS
RET ; THEN GO TO CP/M
;
WRMRD: CALL READHST ;READ HOST TRACK
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
;
; DISK ERROR MESSAGES
;
WPEMSG: DB 'Protec','t'+80H
RERMSG: DB 'CR','C'+80H
SNFMSG: DB 'Secto','r'+80H
SYEMSG: DB 'Syn','c'+80H
;
MSGLE: DB CR,LF,'Boot er','r'+80H
;
; NORTH STAR SD DISK PARAMETER BLOCK
;
DPBNSS: DW 20 ;SECTORS PER TRACK
DB 3 ;BLOCK SHIFT FACTOR
BLKMSK: DB 07H ;BLOCK MASK
DB 0 ;NULL 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
;
; DRIVE PARAMETER HEADER AREA
;
D0DPH: DW 0 ;SECTOR TRAN TBL (NONE)
DW 0 ;SCRATCH
DW 0 ;SCRATCH
DW 0 ;SCRATCH
DW DIRBF ;DIRECTORY BUFFER
DW DPBNSS ;DRIVE PARAM BLK
DW D0CHK ;DRIVE CHANGE BLK
DW D0ALL ;DRIVE ALLOCATION
;
D1DPH: DW 0,0,0,0,DIRBF,DPBNSS,D1CHK,D1ALL
;
; 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
;
LASTG EQU $-1 ;LAST GENNED-IN BYTE
;
; BDOS DIRECTORY BUFFER
;
DIRBF: EQU USER+200H ;ALLOCATED ABOVE USER ROUTINES
;
; SCRATCH RAM FOR BDOS
;
D0ALL: EQU DIRBF+SECSZ ;A: ALLOCATION BUF
D0CHK: EQU D0ALL+12 ;A: CHECK BUF
D1ALL: EQU D0CHK+16 ;B: ALLOCATION BUF
D1CHK: EQU D1ALL+12 ;B: CHECK BUF
;
; BIOS VARIABLE STORAGE
;
SEKDSK: EQU D1CHK+16 ;DRIVE NUMBER
SEKTRK: EQU SEKDSK+1 ;TRACK NUMBER
SEKSEC: EQU SEKTRK+1 ;SECTOR NUMBER
CURDSK: EQU SEKSEC+1 ;CURRENT ACTIVE DISK,
; GENNED-IN FORCE SELECT
ERSEC: EQU CURDSK+1 ;SECTOR IN ERROR
HSTADR: EQU ERSEC+1 ;HOST BUFFER ADDRESS, NORMALLY
; PTS TO HSTBUF UNLESS BOOTING
;
; HSTDSK MUST BE IMMEDIATELY FOLLOWED BY HSTTRK
; FOR ERROR REPORTING, SO THEY CAN BE LOADED WITH
; A SINGLE LHLD.
;
HSTDSK: EQU HSTADR+2 ;HOST DISK NUMBER
HSTTRK: EQU HSTDSK+1 ;HOST TRACK NUMBER
HSTACT: EQU HSTTRK+1 ;HOST ACTIVE FLAG
HSTWRT: EQU HSTACT+1 ;HOST WRITTEN FLAG
ERFLAG: EQU HSTWRT+1 ;ERROR REPORTING
RTCNT: EQU ERFLAG+1 ;ERROR RETRY COUNTER
RSFLAG: EQU RTCNT+1 ;READ SECTOR FLAG
READOP: EQU RSFLAG+1 ;1 IF READ OPERATION
WRTYPE: EQU READOP+1 ;WRITE OPERATION TYPE
DMAADR: EQU WRTYPE+1 ;LAST DMA ADDRESS
;
UNACNT: EQU DMAADR+2 ;UNALLOC REC CNT
UNADSK: EQU UNACNT+1 ;LAST UNALLOC DISK
UNATRK: EQU UNADSK+1 ;LAST UNALLOC TRACK
UNASEC: EQU UNATRK+1 ;LAST UNALLOC SECTOR
;
; NORTH STAR CURRENT TRACK TABLE
;
NSTRK: EQU UNASEC+1 ;NO CURRENT TRACK YET
NSTRK1: EQU NSTRK+1 ;EACH ENTRY CONTAINS
; THE LAST TRACK POSITION
; FOR THE UNIT (1 OR 2)
;
; NORTH STAR HOST SECTOR BUFFER
;
HSTBUF: DS HSTSIZ ;HOST BUFFER
;
LAST EQU $-1 ;LAST USED BYTE IN MEM
;
END