Files
Digital-Research-Source-Code/MPM OPERATING SYSTEMS/MPM I/MPM I SOURCE/12/ldrbios.asm
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

677 lines
12 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; Support for CP/M 2.0 added 5 Sept 79 - J R Pierce
;HARD DISK VERSION 8-26-79
; BIOS FOR MICRO-2 COMPUTER
;
;THE IOBYTE IS IMPLEMENTED
;
;INTERRUPTS ARE NOT IMPLEMENTED
;
maclib diskdef
ndisks equ 2
;
;THIS VERSION CONTAINS DISK DRIVERS FOR THE DIGITAL SYSTEMS
;FDC-3 CONTROLLER BOARD. THIS BOARD CAN HANDLE DOUBLE DENSITY
;
; NOTE : MSIZE DETERMINES WHERE THIS CBIOS IS LOCATED
VERS EQU 20
on equ 0ffffh
off equ 00000h
ldr equ on
long equ off
if long
biosbase equ 1b00h
else
biosbase equ 1700h
endif
if ldr
bios equ biosbase
bdos equ 0D00h
warmboot equ 0
msize equ 0
else
MSIZE EQU 64 ;CP/M VERSION MEMORY SIZE IN KILOBYTES
ramtop equ msize*1024
bios equ ram$top-6*256
bdos equ bios-0e00h
ccp equ bdos-0800h
warm$boot equ ccp-0080h
endif
org bios
; WE WILL USE A SCRATCH AREA STARTING AT 40H
SCRAT EQU 40H ;START OF SCRATCH AREA
TRACK EQU SCRAT ;CURRENT TRACK ON DRIVE 0
TRAK1 EQU TRACK+1 ;CURRENT TRACK ON DRIVE 1
TRAK2 EQU TRAK1+1
TRAK3 EQU TRAK2+1
SECTOR EQU TRAK3+1 ;CURRENTLY SELECTED SECTOR
DMAAD EQU SECTOR+1 ;CURRENT DMA ADDRESS
DISKNO EQU DMAAD+2 ;CURRENT DISK NUMBER
DUMMY EQU DISKNO+1 ;MUST BE 0 FOR DOUBLE ADD
ERRORS EQU DUMMY+1
PORT EQU 4AH
PORTOUT EQU PORT+1
DENSITY EQU PORTOUT+1
;
IOBYTE EQU 3
;
;SET UP INPUT OUTPUT PORTS
DATA EQU 40H
STATUS EQU DATA+1
DATA1 EQU 48H
STATUS1 EQU DATA1+1
DATA2 EQU 50H
STATUS2 EQU DATA2+1
PARALLEL EQU 61H
;
;
; JUMP VECTOR FOR INDIVIDUAL SUBROUTINES
JMP WARMBOOT ;COLD START
WBOTE:
JMP WBOOT ;WARM START
JMP CONST ;CONSOLE STATUS
JMP CONIN ;CONSOLE CHARACTER IN
JMP CONOUT ;CONSOLE CHARACTER OUT
JMP LIST ;LIST CHARACTER OUT
JMP PUNCH ;PUNCH CHARACTER OUT
JMP READER ;READER CHARACTER OUT
JMP HOME ;MOVE HEAD TO HOME POSITION
JMP SELDSK ;SELECT DISK
JMP SETTRK ;SET TRACK NUMBER
JMP SETSEC ;SET SECTOR NUMBER
JMP SETDMA ;SET DMA ADDRESS
JMP READ ;READ DISK
JMP WRITE ;WRITE DISK
jmp lstat ; list status routine
jmp sectran ; logical->physical sector mapping
;THE WARM BOOT ROUTINE EXPECTS TO FIND THE LOG ON MESSAGE HERE
;SINCE THERE WAS NOT ENOUGH ROOM IN IT
DW 0D0AH ;CR,LF
DB MSIZE/10+'0',MSIZE MOD 10+'0'
DB 'k CP/M Vers'
DB VERS/10+'0','.',VERS MOD 10+'0'
DB 0
;
; INDIVIDUAL SUBROUTINES TO PERFORM EACH FUNCTION
;
WBOOT:
;READ IN TRACK 0 SECTOR 2 WHICH WILL DO THE REST OF THE WARM START
;
LXI SP,80H ;USE SPACE BELOW BUFFER FOR STACK
MVI C,0 ;SELECT DISK 0
CALL SELDSK
CALL HOME ;GO TO TRACK 00
;
;SET SINGLE DENSITY
LDA PORT
ANI 0F7H
STA PORT
;SET DMA ADDRESS TO 80 BELOW START OF CCP
LXI B,WARMBOOT
CALL SETDMA
MVI C,2
CALL SETSEC
;NOW READ
CALL READ
ORA A ;ANY ERRORS?
JNZ WBOOT ;RETRY THE ENTIRE BOOT IF AN ERROR OCCURS
;
;
JMP WARMBOOT+3 ;GO FINISH THE WARM START
;I/O HANDLERS
;
CONST: CALL CONS
ORA A
RZ
MVI A,0FFH
RET
;
CONS:
CALL condsptch
DW TTYST
DW CRTST
DW BATST
DW UC1ST
;
CONIN:
CALL condsptch
DW TTYIN
DW CRTIN
DW BATIN
DW UC1IN
;
CONOUT:
CALL condsptch
DW TTYOUT
DW CRTOUT
DW BATOUT
DW UC1OUT
;
LIST:
LDA IOBYTE
RLC! RLC
CALL IODSPRLC
DW TTYOUT
DW CRTOUT
DW LPTOUT
DW UL1OUT
lstat: ; Dummy Routine
xra a ! ret
PUNCH:
LDA IOBYTE
RRC! RRC! RRC
CALL IODISPATCH
DW TTYOUT
DW PTPOUT
DW UP1OUT
DW UP2OUT
;
READER:
LDA IOBYTE
RRC
CALL IODISPATCH
DW TTYIN
DW PTRIN
DW UR1IN
DW UR2IN
;
condsptch:
lda io$byte
IODSPRLC:
RLC
IODISPATCH:
ANI 6H
XTHL ;GET TABLE ADDRESS
PUSH D
MOV E,A
MVI D,0
DAD D
MOV A,M
INX H
MOV H,M
MOV L,A
POP D
XTHL
RET
;
;
PORT0ST: ;CONSOLE STATUS, RETURN 0FFH IF CHARACTER READY, 00H IF NOT
IN STATUS
ANI 2
RZ
MVI A,0FFH
RET
;
;
PORT0IN: ;CONSOLE CHARACTER INTO REGISTER A
CALL PORT0ST
JZ PORT0IN
IN DATA
ANI 7FH ;STRIP PARITY BIT
RET
;
;
PORT0OUT: ;CONSOLE CHARACTER OUTPUT FROM REGISTER C
in status
rrc
jnc port0out
MOV A,C
OUT DATA
RET
;
;
PORT1ST:
IN STATUS1
ANI 2
RZ
MVI A,0FFH
RET
;
PORT1IN:
CALL PORT1ST
JZ PORT1IN
IN DATA1
ANI 7FH ;STRIP PARITY BIT
RET
;
PORT1OUT: ;LIST CHARACTER FROM REGISTER C
IN STATUS1
RRC
JNC PORT1OUT
MOV A,C ;CHARACTER TO REGISTER A
OUT DATA1
RET ;NULL SUBROUTINE
;
PORT2ST:
IN STATUS2
ANI 2
RZ
MVI A,0FFH
RET
;
PORT2IN:
CALL PORT2ST
JZ PORT2IN
IN DATA2
ANI 7FH
RET
;
PORT2OUT:
IN STATUS2
RRC
JNC PORT2OUT
MOV A,C
OUT DATA2
RET
;
;
PORTPOUT:
IN PARALLEL
ANI 80H
JNZ PORTPOUT
MOV A,C
OUTIT:
ORI 80H
OUT PARALLEL
ANI 7FH
OUT PARALLEL
ORI 80H
OUT PARALLEL
RET
;
;CP/M PHYSICAL DEVICE TO MICRO2 PHYSICAL DEVICE MAP
;
TTYST EQU PORT0ST
TTYIN EQU PORT0IN
TTYOUT EQU PORT0OUT
CRTST EQU PORT1ST
CRTIN EQU PORT1IN
CRTOUT EQU PORT1OUT
BATST EQU PORT2ST
BATIN EQU PORT2IN
BATOUT EQU PORT2OUT
UC1ST EQU PORT0ST
UC1IN EQU PORT0IN
UC1OUT EQU PORT0OUT
LPTOUT EQU PORTPOUT
UL1OUT EQU PORT2OUT
PTPOUT EQU PORT2OUT
PTRIN EQU PORT2IN
UP1OUT EQU PORT0OUT
UP2OUT EQU PORT1OUT
UR1IN EQU PORT0IN
UR2IN EQU PORT1IN
;
;
COMAND1 EQU 80H
STAT EQU 80H
HADDR EQU 81H
LADDR EQU 82H
COMAND2 EQU 83H
;
;
; I/O DRIVERS FOR THE DISK FOLLOW
;
HOME: ;MOVE TO THE TRACK O0 POSITION OF CURRENT DRIVE
CALL HEADLOAD
; H,L POINT TO WORD WITH TRACK FOR SELECTED DISK
HOMEL:
MVI M,00 ;SET CURRENT TRACK PTR BACK TO 0
IN STAT ;READ FDC STATUS
ANI 4 ;TEST TRACK 0 BIT
RZ ;RETURN IF AT 0
STC ;DIRECTION=OUT
CALL STEP ;STEP ONE TRACK
JMP HOMEL ;LOOP
;
SELDSK: ;SELECT DISK GIVEN BY REGISTER C
;MAKE SURE DUMMY IS 0 (FOR USE IN DOUBLE ADD TO H,L)
cpi ndisks ! jnc bad$drive
XRA A
STA DUMMY
MOV A,C
ANI 07H ;GET ONLY DISK SELECT BITS
STA DISKNO
MOV C,A
MOV B,A
;GET DENSITY OF SELECTED DRIVE
;B HAS DRIVE NUMBER FROM 0-7
LDA DENSITY
;DENSITY BIT 0= DENSITY FOR DRIVE A, BIT 1=DRIVE B ETC
;A 1 MEANS DOUBLE DENSITY
GETDR:
DCR B
RRC
JP GETDR ;NOT AT PROPER BIT YET
JC SETDOB
SETSING:
LXI D,SINGTAB
lxi h,stagger
JMP OVERBOTH
SETDOB:
LXI D,DOBTAB
lxi h,0 ; no stagger table
MOV A,C
;SET THE CHANGE DENSITY BIT
ORI 08
MOV C,A
OVERBOTH:
lda port ! ani 0f0h ! ora c ! sta port
push h ; save stagger table address
lhld diskno
dad h ! dad h ! dad h ! dad h
lxi b,dpbase+10
dad b ; points HL to right disk parameter table
mov m,e ! inx h ! mov m,d ; save diskdef address
lxi b,-10 ; point back to tran table address
dad b
pop d ; get current tran table
mov m,d ! dcx h ! mov m,e ; store its address
; HL now points to appropriate drive parameter block
RET
bad$drive: ; here if invalid drive code
lxi h,0 ! ret ; zero means select error
SETTRK: ;SET TRACK GIVEN BY REGISTER C
CALL HEADLOAD
;H,L REFERENCE CORRECT TRACK INDICATOR ACCORDING TO
;SELECTED DISK
MOV A,C ;DESIRED TRACK
CMP M
RZ ;WE ARE ALREADY ON THE TRACK
SETTKX:
CALL STEP ;STEP TRACK-CARRY HAS DIRECTION
;STEP WILL UPDATE TRACK INDICATOR
MOV A,C
CMP M ;ARE WE WHERE WE WANT TO BE
JNZ SETTKX ;NOT YET
;HAVE STEPPED ENOUGH
SEEKRT:
;DELAY 10 MSEC FOR FINAL STEP TIME AND HEAD SETTLE TIME
;THE DELAY ROUTINE DELAYS .5 MILLISECOND
MVI A,20D
CALL DELAY
RET ;END OF SETTRK ROUTINE
;
DELAY: ;ROUTINE TO DELAY C(A) .5 MILLISECONDS
PUSH B
DELAY2:
MVI C,086H ;ADJUST FOR .5 MSEC LOOP DELAY
;THIS IS THE VALUE FOR OUR IMSAI
LDXA:
DCR C
JNZ LDXA ;LOOP 1 MSEC
DCR A
JNZ DELAY2
POP B
RET ;END OF DELAY ROUTINE
;
sectran:
mov h,b ! mov l,c ! inx h ; in case we aren't using translation
mov a,d ! ora e ! rz ; we return logical+1
xchg ! dad b ! mov l,m ! mvi h,0 ; else fetch physical
ret ; back to bdos
SETSEC: ;SET SECTOR GIVEN BY REGISTER C
MOV A,C
STA SECTOR
RET
;
SETDMA: ;SET DMA ADDRESS GIVEN BY REGISTERS B AND C
MOV L,C ;LOW ORDER ADDRESS
MOV H,B ;HIGH ORDER ADDRESS
SHLD DMAAD ;SAVE THE ADDRESS
RET
;
;
READ: ;PERFORM READ OPERATION.
;THIS IS SIMILAR TO WRITE, SO SET UP READ COMMAND AND USE
;COMMON CODE IN WRITE
MVI B,040H ;SET READ FLAG
JMP WAITIO ;TO PERFORM THE ACTUAL I/O
;
WRITE: ;PERFORM A WRITE OPERATION
MVI B,080H ;SET WRITE COMMAND
;
WAITIO:
;ENTER HERE FROM READ AND WRITE TO PERFORM THE ACTUAL I/O
;OPERATION. RETURN A 00H IN REGISTER A IF THE OPERATION COMPLETES
;PROPERLY, AND 01H IF AN ERROR OCCURS DURING THE READ OR WRITE
;
;IN THIS CASE, WE HAVE SAVED THE DISK NUMBER IN 'DISKNO'
; THE TRACK NUMBER IN 'TRACK'
; THE SECTOR NUMBER IN 'SECTOR'
; THE DMA ADDRESS IN 'DMAAD'
;B STILL HAS R/W FLAG
MVI A,10D ;SET ERROR COUNT
STA ERRORS ;RETRY SOME FAILURES 10 TIMES
;BEFORE GIVING UP
TRYAGN:
PUSH B
CALL HEADLOAD
;H,L POINT TO TRACK BYTE FOR SELECTED DISK
POP B
MOV C,M
; DECIDE WHETHER TO ALLOW DISK WRITE PROCOMPENSTATION
MVI A,39D ;PRECOMP SHOULD BE INHIBITED ON TRACKS
;0-39
CMP C
JC ALLOWIT
;INHIBIT PRECOMP
MVI A,10H
ORA B
MOV B,A ;GOES OUT ON THE SAME PORT AS READ/WRITE
ALLOWIT:
LHLD DMAAD ;GET BUFFER ADDRESS
PUSH B ;B HAS R/W CODE C HAS TRACK
DCX H ;SAVE AND REPLACE 3 BYTES BELOW
;BUF WITH TRACK,SECTOR,ADDRESS MARK
MOV E,M
;FIGURE CORRECT ADDRESS MARK
LDA PORT
ANI 08H
MVI A,0FBH
JZ SIN
ANI 0FH ;WAS DOUBLE
;0BH IS DOUBLE DENSITY
;0FBH IS SINGLE DENSITY
SIN:
MOV M,A
;FILL IN SECTOR
DCX H
MOV D,M
LDA SECTOR ;NOTE THAT INVALID SECTOR NUMBER
;WILL RESULT IN HEAD UNLOADED
;ERROR, SO DONT CHECK
MOV M,A
;FILL IN TRACK
DCX H
POP B
MOV A,C
MOV C,M
MOV M,A
MOV A,H ;SET UP FDC DMA ADDRESS
OUT HADDR ;HIGH BYTE
MOV A,L
OUT LADDR ;LOW BYTE
MOV A,B ;GET R/W FLAG
OUT COMAND1 ;START DISK READ/WRITE
RWWAIT: IN STAT ;READ FDC STATUS
ANI 088H ;TEST FOR HEAD UNLOAD OR IOF
JZ RWWAIT
MOV M,C ;RESTORE 3 BYTES BELOW BUF
INX H
MOV M,D
INX H
MOV M,E
IN STAT ;TEST FOR ERRORS
ANI 0F0H
RZ ;A WILL BE 0 IF NO ERRORS
ERRTN:
;COME HERE ON ERROR FROM DISK
PUSH PSW ;SAVE ERROR CONDITION
;CHECK FOR 10 ERRORS
LXI H,ERRORS
DCR M
JNZ REDO ;NOT TEN YET. DO A RETRY
;WE HAVE TOO MANY ERRORS. PRINT OUT HEX NUMBER FOR LAST
;RECEIVED ERROR TYPE. CPM WILL PRINT PERM ERROR MESSAGE.
POP PSW ;GET CODE
RRC
RRC
RRC
RRC
;MAKE IT ASCII
ORI 030H
STA BDOS+0A4H
;SET ERROR RETURN FOR OPERATING SYSTEM
MVI A,1
RET
REDO:
;B STILL HAS READ/WRITE FLAG
POP PSW ;GET ERROR CODE
ANI 0E0H ;RETRY IF NOT TRACK ERROR
JNZ TRYAGN ;
;WAS A TRACK ERROR SO NEED TO RESEEK
PUSH B ;SAVE READ/WRITE INDICATOR
;FIGURE OUT THE DESIRED TRACK
LXI D,TRACK
LHLD DISKNO ;SELECTED DISK
DAD D ;POINT TO CORRECT TRACK INDICATOR
MOV A,M ;DESIRED TRACK
PUSH PSW ;SAVE IT
CALL HOME
POP PSW
MOV C,A
CALL SETTRK
POP B ;GET READ/WRITE INDICATOR
JMP TRYAGN
;
;
;
STEP: ;STEP HEAD OUT TOWARDS ZERO
;IF CARRY IS SET; ELSE
;STEP IN
; H,L POINT TO CORRECT TRACK INDICATOR WORD
JC OUTX
INR M ;INCREMENT CURRENT TRACK BYTE
MVI A,04H ;SET DIRECTION = IN
DOSTEP:
ORI 2
OUT COMAND1 ;PULSE STEP BIT
ANI 0FDH
OUT COMAND1 ;TURN OFF PULSE
;THE FDC-2 HAD A STEPP READY LINE. THE FDC-3 RELIES ON
;SOFTWARE TIME OUT
MVI A,16D ;WAIT FOR STEP READY
;DELAY ROUTINE DELAYS FOR .5 MSEC TIMES THE CONTENTS OF REG A
CALL DELAY
RET
;
OUTX:
DCR M ;UPDATE TRACK BYTE
XRA A
JMP DOSTEP
;
HEADLOAD:
;SELECT AND LOAD THE HEAD ON THE CORRECT DRIVE
LXI H,PORTOUT ;OLD SLECT INFO
MOV B,M
DCX H ;NEW SELECT INFO
MOV A,M
INX H
MOV M,A
OUT COMAND2 ;SELECT THE DRIVE
;SET UP H.L TO POINT TO TRACK BYTE FOR SELECTED DISK
LXI D,TRACK
LHLD DISKNO
DAD D
;NOW CHECK FOR NEEDING A 35 MS DELAY
;IF WE HAVE CHANGED DRIVES OR IF THE HEAD IS UNLOADED
;WE NEED0TO WAIT 35 MS FOR HEAD SETTLE
CMP B ;ARE WE ON THE SAME DRIVE AS BEFORE
JNZ NEEDDLY
;WE ARE ON THE SAME DRIVE
;IS THE HEAD LOADED?
IN STAT
ANI 80H
RZ ;ALREADY LOADED
NEEDDLY:
XRA A
OUT COMAND1 ;LOAD THE HEAD
;THE DELAY ROUTINE DELAYS FOR .5 MSEC
MVI A,70D
CALL DELAY
RET
;
; disks 2
dpbase:
dpe0: dw $-$, 0
dw 0, 0
dw dirbuf, $-$
dw csv0, alv0
dpe1: dw $-$, 0
dw 0, 0
dw dirbuf, $-$
dw csv1, alv1
dobtab:
; diskdef 0,1,58,,2048,256,128,128,2
dw 58
db 4,15
if ldr
db 0
else
db 1
endif
dw 255,127
db 192,0
dw 32,2
singtab:
; diskdef 1,1,26,6,1024,243,64,64,2
dw 26
db 3,7,0
dw 242,63
db 192,0
dw 16,2
stagger: ; Standard CP/M Stagger Table (Skew 6)
db 1,7,13,19,25
db 5,11,17,23
db 3,9,15,21
db 2,8,14,20,26
db 6,12,18,24
db 4,10,16,22
; endef
begdat:
dirbuf:
ds 128
alv0:
ds 32
csv0:
ds 32
alv1:
ds 32
csv1:
ds 32
enddat equ $
end