|
|
DataMuseum.dkPresents historical artifacts from the history of: CP/M |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about CP/M Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 11648 (0x2d80)
Types: TextFile
Names: »LDRBIOS.ASM«
└─⟦b445f10af⟧ Bits:30004389 CP/M Plus Source files
└─⟦this⟧ »LDRBIOS.ASM«
TITLE 'LOADER MODULE FOR CP/M 3.0 BIOS - DATE:831107'
PAGE 43
EXTRN ?XMOVE,?MOVE,?BANK,MA3MIR
Extrn @DTBL
PUBLIC @ADRV,@RDRV,@TRK,@SECT,@DMA,@DBNK,@CNT,@CBNK
PUBLIC ?PMSG,?PDERR,?PDEC ;
PUBLIC @ERMDE
PUBLIC DSKTMR,MONCNT
MACLIB PORTS ;
MACLIB Z80 ;
MACLIB CPM3 ;
if banked
ERROR : banked must be equal false
endif
;EXTERNAL NAMES FOR BIOS ENTRY POINTS
PUBLIC ?BOOT,?WBOOT,?CONST,?CONIN,?CONO,?LIST,?AUXO,?AUXI
PUBLIC ?HOME,?SLDSK,?STTRK,?STSEC,?STDMA,?READ,?WRITE
PUBLIC ?LISTS,?SCTRN
PUBLIC ?CONOS,?AUXIS,?AUXOS,?DVTBL,?DEVIN,?DRTBL
PUBLIC ?MLTIO,?FLUSH,?MOV,?TIM,?BNKSL,?STBNK,?XMOV
;BIOS JUMP VECTOR
?BOOT: JMP BOOT
?WBOOT: JMP DUMMY
?CONST: JMP DUMMY
?CONIN: JMP DUMMY
?CONO: JMP CONOUT
?LIST: JMP DUMMY
?AUXO: JMP DUMMY
?AUXI: JMP DUMMY
?HOME: JMP HOME
?SLDSK: JMP SELDSK
?STTRK: JMP SETTRK
?STSEC: JMP SETSEC
?STDMA: JMP SETDMA
?READ: JMP READ
?WRITE: JMP DUMMY
?LISTS: JMP DUMMY
?SCTRN: JMP SECTRN
?CONOS: JMP DUMMY
?AUXIS: JMP DUMMY
?AUXOS: JMP DUMMY
?DVTBL: JMP DEVTBL
?DEVIN: JMP DUMMY
?DRTBL: JMP GETDRV
?MLTIO: JMP MULTIO
?FLUSH: JMP FLUSH
?MOV: JMP ?MOVE
?TIM: JMP DUMMY
?BNKSL: JMP DUMMY
?STBNK: JMP SETBNK
?XMOV: JMP DUMMY
JMP 0
JMP 0
JMP 0
BOOT:
;---
SSPD BDOS$SP
LXI SP,BOOT$STACK
CALL ?INIT
LXI B,16*256+0
LXI H,@DTBL
D$INIT$LOOP:
PUSH B
MOV E,M ! INX H ! MOV D,M ! INX H
MOV A,E
ORA D
JZ D$INIT$NEXT
PUSH H
XCHG
DCX H ! DCX H
MOV A,M
STA @RDRV
MOV A,C
STA @ADRV
DCX H ! MOV D,M ! DCX H ! MOV E,M
XCHG
CALL IPCHL
POP H
D$INIT$NEXT:
POP B
INR C
DCR B
JNZ D$INIT$LOOP
LSPD BDOS$SP
RET
BDOS$SP: DW 00H
DS 64
BOOT$STACK: EQU $
;***********************************************************************
; INTERRUPT VECTOR TABLE
;***********************************************************************
DS 1
CTCINT:
DW DMYINT
DW DMYINT
DW TIMER
DW DMYINT
;***********************************************************************
; DEVTBL Return address of character device table
devtbl:
lxi h,@ctbl ! ret
; GETDRV Return address of drive table
getdrv:
lxi h,@dtbl ! ret
; CONOUT Console Output. Send character in <C>
; to all selected devices
conout:
lhld @covec ; fetch console output bit vector
jmp out$scan
out$scan:
mvi b,0 ; start with device 0
co$next:
dad h ; shift out next bit
jnc not$out$device
push h ; save the vector
push b ; save the count and character
not$out$ready:
call coster ! ora a ! jz not$out$ready
pop b ! push b ; restore and resave the character and device
call ?co ; if device selected, print it
pop b ; recover count and character
pop h ; recover the rest of the vector
not$out$device:
inr b ; next device number
mov a,h ! ora l ; see if any devices left
jnz co$next ; and go find them...
ret
coster: ; check for output device ready
mov l,b ! mvi h,0 ; make device code 16 bits
jmp ?cost ; not a xon device, go get output status direct
; Utility Subroutines
ipchl: ; vectored CALL point
pchl
?pmsg: ; print message @<HL> up to a null
; saves <BC> & <DE>
push b
push d
pmsg$loop:
mov a,m ! ora a ! jz pmsg$exit
mov c,a ! push h
call ?cono ! pop h
inx h ! jmp pmsg$loop
pmsg$exit:
pop d
pop b
ret
?pdec: ; print binary number 0-65535 from <HL>
lxi b,table10! lxi d,-10000
next:
mvi a,'0'-1
pdecl:
push h! inr a! dad d! jnc stoploop
inx sp! inx sp! jmp pdecl
stoploop:
push d! push b
mov c,a! call ?cono
pop b! pop d
nextdigit:
pop h
ldax b! mov e,a! inx b
ldax b! mov d,a! inx b
mov a,e! ora d! jnz next
ret
table10:
dw -1000,-100,-10,-1,0
?pderr:
lxi h,drive$msg ! call ?pmsg ; error header
lda @adrv ! adi 'A' ! mov c,a ! call ?cono ; drive code
lxi h,track$msg ! call ?pmsg ; track header
lhld @trk ! call ?pdec ; track number
lxi h,sector$msg ! call ?pmsg ; sector header
lhld @sect ! call ?pdec ; sector number
ret
; Disk I/O interface routines
; SELDSK Select Disk Drive. Drive code in <C>.
; Invoke login procedure for drive
; if this is first select. Return
; address of disk parameter header
; in <HL>
seldsk:
mov a,c ! sta @adrv ; save drive select code
mov l,c ! mvi h,0 ! dad h ; create index from drive code
lxi b,@dtbl ! dad b ; get pointer to dispatch table
mov a,m ! inx h ! mov h,m ! mov l,a ; point at disk descriptor
ora h ! rz ; if no entry in table, no disk
mov a,e ! ani 1 ! jnz not$first$select ; examine login bit
push h ! xchg ; put pointer in stack & <DE>
lxi h,-2 ! dad d ! mov a,m ! sta @RDRV ; get relative drive
lxi h,-6 ! dad d ; find LOGIN addr
mov a,m ! inx h ! mov h,m ! mov l,a ; get address of LOGIN routine
call ipchl ; call LOGIN
pop h ; recover DPH pointer
not$first$select:
ret
; HOME Home selected drive. Treated as SETTRK(0).
home:
lxi b,0 ; same as set track zero
; SETTRK Set Track. Saves track address from <BC>
; in @TRK for further operations.
settrk:
mov l,c ! mov h,b
shld @trk
ret
; SETSEC Set Sector. Saves sector number from <BC>
; in @sect for further operations.
setsec:
mov l,c ! mov h,b
shld @sect
ret
; SETDMA Set Disk Memory Address. Saves DMA address
; from <BC> in @DMA and sets @DBNK to @CBNK
; so that further disk operations take place
; in current bank.
setdma:
mov l,c ! mov h,b
shld @dma
lda @cbnk ; default DMA bank is current bank
; fall through to set DMA bank
; SETBNK Set Disk Memory Bank. Saves bank number
; in @DBNK for future disk data
; transfers.
setbnk:
sta @dbnk
ret
; SECTRN Sector Translate. Indexes skew table in <DE>
; with sector in <BC>. Returns physical sector
; in <HL>. If no skew table (<DE>=0) then
; returns physical=logical.
sectrn:
mov l,c ! mov h,b
mov a,d ! ora e ! rz
xchg ! dad b ! mov l,m ! mvi h,0
ret
; READ Read physical record from currently selected drive.
; Finds address of proper read routine from
; extended disk parameter header (XDPH).
read:
lhld @adrv ! mvi h,0 ! dad h ; get drive code and double it
lxi d,@dtbl ! dad d ; make address of table entry
mov a,m ! inx h ! mov h,m ! mov l,a ; fetch table entry
push h ; save address of table
lxi d,-8 ! dad d ; point to read routine address
jmp rw$common ; use common code
rw$common:
mov a,m ! inx h ! mov h,m ! mov l,a ; get address of routine
pop d ; recover address of table
dcx d ! dcx d ; point to relative drive
ldax d ! sta @rdrv ; get relative drive code and post it
inx d ! inx d ; point to DPH again
pchl ; leap to driver
; MULTIO Set multiple sector count. Saves passed count in
; @CNT
multio:
sta @cnt ! ret
; FLUSH BIOS deblocking buffer flush. Not implemented.
flush:
xra a ! ret ; return with no error
DUMMY:
RET
; error message components
drive$msg db cr,lf,bell,'BIOS Error on ',0
track$msg db ': T-',0
sector$msg db ', S-',0
; disk communication data items
@adrv ds 1 ; currently selected disk drive
@rdrv ds 1 ; controller relative disk drive
@trk ds 2 ; current track number
@sect ds 2 ; current sector number
@dma ds 2 ; current DMA address
@cnt db 1 ; record count for multisector transfer
@dbnk db 1 ; bank for DMA operations
@cbnk db 1 ; bank for processor operations
@COVEC DW 0 ; Console Output Redirection
; Vector (word, r/w)
@ERMDE DW 0 ; BDOS Error Mode (byte, r/o)
;=========================================================================
?INIT: LXI H,8000H ;ASSIGN CONSOLE TO CRT
SHLD @COVEC ;
LXI H,0C200H
MOV A,L
STA 0FFFEH+0AH
MOV A,H
STA 0FFFEH+0AH+1H
LXI H,INIT$TABLE ;SET UP MISC. HARDWARE
CALL OUT$BLOCKS ;
CALL HW$INIT
RET ;
OUT$BLOCKS:
MOV A,M ;GET COUNT VALUE
ORA A ;
RZ ;
MOV B,A ;GET COUNT VALUE INTO <B>
INX H ;
MOV C,M ;GET PORT ADDRESS INTO <C>
INX H ;<HL> POINTER TO OUTPUT VALUE
OUTIR ;
JMP OUT$BLOCKS ;
INIT$TABLE:
DB 1,P$DMA$CLEAR,0 ;CLEAR DMA
DB 1,P$DMA$STAT,C$DMA$BYTE ;SET HARDWARE ATTRIBUTES
DB 4,P$DMA$MODE,88H,85H,82H,83H ;SET CH.0-3 MODE REG.
DB 00H ;TABLE TERMINATOR
;*************************************************************************
; I/O AND HARDWARE INITIALIZATION ROUTINE
;***********************************************************************
HW$INIT:
MVI A,0FFH ;DELAY 1/4 SECOND FOR ANY
;UART CHAR IN PROGRESS
CALL SDLY
DI
;
;INIT TIMER
MVI A,03H ;INIT ALSO SOFTWARE TIMER
OUT P$DMA$INT ;CH0 RESET
OUT P$MFD$INT ;CH1 RESET
OUT P$SCI$INT ;CH3 RESET
LXI H,CTCINT ;
MOV A,L ;
OUT P$CTC ;
MVI A,0A5H ;
OUT P$TIM$INT ;CH2 USED AS SOFTWARE TIMER
MVI A,195 ;...AND BUS TIMER
OUT P$TIM$INT ;INTERRUPT EVERY 12.5 MILLISECONDS
;INIT CPU
MOV A,H ;CTC INTERRUPT VECTOR TABLE ADDRESS
STAI ;MOV I,A INITIALIZE CPU PART OF
IM2 ;IM 2 INTERRUPT LOGIC
EI ;
RET ;FINALLY DONE WITH ALL THAT
;***********************************************************************
; 12.5 MSEC. TIMER INTERRUPT SERVICE ROUTINE
;***********************************************************************
MONCNT: DB 0
DSKTMR: DB 0
TIMER:
EXAF
MOTCHK:
LDA MA3MIR ;CHECK IF MOTORS IS OFF
ANI 080H ;MOTENB
JZ TIMER1 ;
LDA DSKTMR ;TEST IF 2 SEC HAS ELAPSED
ANA A ; WITHOUT DISK ACCESS
JNZ TIMER1 ;
LDA MONCNT ;
INR A ;
STA MONCNT ;
CPI 03H ;HAVE WE BEEN AT THIS FOR SIX SEC YET
JNZ NEXT2 ;
LDA MA3MIR ;IF SIX SEC HAS ELAPSED
ANI 0FH ;
STA MA3MIR ;
OUT P$MAP3 ;SHUT OFF MINI MOTOR
JMP TIMER1 ;
NEXT2:
MVI A,160 ;160*12.5 mSEC = 2 SEC
STA DSKTMR ;SET ANOTHER 2 SEC DELAY
TIMER1:
LDA DSKTMR ;GET MINI FLOPPY MOTOR ON COUNTER
ANA A
JZ TEXIT ;IF NOT TIMED OUT
DCR A ;COUNT DOWN
STA DSKTMR ;OPDATE MEMORY IMAGE
TEXIT:
EXAF
DMYINT: ;DUMMY INTERRUPTS CAN ENTER HERE
EI
RETI
;----------------------------------------------------------------------
SDLY:
MVI L,070H
DCR L
JNZ $-1
DCR A
JNZ SDLY
RET
;=========================================================================
MAX$DEVICE$NO EQU 01H ;DEVICE 0
?COST: MOV A,B ;GET DEVICE NUMBER
CPI MAX$DEVICE$NO ;
JNC NULL$STATUS ;
MOV L,B ;MAKE DEVICE NUMBER 16 BITS
MVI H,0 ;
PUSH H ;
LXI D,STAT$PORTS ;
DAD D ;MAKE POINTER TO PORT ADDRESS
MOV C,M ;
MVI A,10H ;RESET EXTERNAL STATUS
OUTP A ;
INP A ;GET STATUS
POP H ;GET DEVICE NUMBER
PUSH H ;
LXI D,OUT$STAT$MASK ;
DAD D ;MAKE POINTER TO MASK
MOV C,M ;
ANA C ;
POP H ;
LXI D,OUT$STAT$VALUE;
DAD D ;MAKE POINTER TO VALUE
MOV C,M ;
CMP C ;
JNZ NULL$STATUS ;
ORI 0FFH ;
RET ;
?CO: MOV A,B ;GET DEVICE NUMBER
CPI MAX$DEVICE$NO ;
JNC NULL$OUTPUT ;
MOV A,C ;GET OUTPUT CHARACTER
PUSH PSW ;SAVE CHARACTER
PUSH B ;
COL: CALL ?COST ;
JZ COL ;
POP B ;
MOV L,B ;
MVI H,0 ;MAKE DEVICE NUMBER 16 BITS
LXI D,DATA$PORTS ;
DAD D ;MAKE POINTER TO PORT ADDRESS
MOV C,M ;
POP PSW ;GET CHARACTER
ANI 7FH ;MASK PARITY BIT
OUTP A ;
NULL$OUTPUT:
RET
NULL$STATUS:
XRA A
RET
DATA$PORTS:
DB P$CRT$DATA ;
STAT$PORTS:
DB P$CRT$STAT ;
OUT$STAT$MASK:
DB M$CRT$OUT ;
OUT$STAT$VALUE:
DB V$CRT$OUT ;
@CTBL: DB 'CRT ' ;DEVICE 0
DB MB$IN$OUT+MB$SERIAL+MB$SOFT$BAUD
DB BAUD$9600 ;
;
DB 0 ;TABLE TERMINATOR
END
«eof»