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
/
ENTERPRS
/
CPM
/
UTILS
/
A
/
CPM22EM.ASM
< prev
next >
Wrap
Assembly Source File
|
2000-06-30
|
12KB
|
498 lines
; ============================================================================
; * CP/M 2.2 BIOS EMULATOR FOR CP/M 3.x *
; ============================================================================
; This program, by Mike Griswold, is a Resident System Extension (RSX) which
; runs under CP/M-Plus. This RSX intercepts certain BIOS function calls,
; and resolves differences between CP/M 2.2 and CP/M 3.x. It allows many
; programs that do not normally work with CP/M-Plus to work correctly.
; So far, I have installed this RSX on DU2, which normally does not work
; at all, and with the RSX, it works perfectly.
; Installation instructions:
; 1. RMAC CPM22 $pz $sz
; 2. LINK CPM22[OP]
; 3. REN CPM22.RSX=CPM22.PRL
; 4. GENCOM <program name> CPM22
; NOTE: <program name> is a .COM file which is the CP/M 2.2 command
; file.
;
; Program typed from Doctor Dobbs Journal #93, July 1984.
; Typed & Instructions written by Charles Foreman.
; Uploaded to CURA RCP/M - (212) 625-5931 - by Charles Foreman.
;
;
title 'CP/M 2.2 BIOS RSX'
;
; 18Jan84 By Mike Griswold
;
; This RSX will provide CP/M 2.2 compatible BIOS support
; for CP/M 3.x. Primarily it performs logical sector
; blocking and deblocking needed for some programs.
; All actual I/O is done by the CP/M 3.0 BIOS.
;
maclib z80 ; Z80 opcode equates
cseg
;
; This equate is the only hardware dependant value.
; It should be set to the largest sector size that
; will be used.
;
max$sector$size: equ 512
;
;
; RSX prefix structure
;
db 0,0,0,0,0,0
entry: jmp boot
next: db jmp ; jump
dw 0 ; next module in line
prev: db 0 ; previous module
remove: db 00fh ; remove flag
nonbnk: db 0
db 'BIOS2.21'
db 0,0,0
;
; Align jump table on next page boundary. This is needed
; for programs that cheat when getting the addresses of
; BIOS jump table entries. Optimization freaks could move
; some code up here. With a 60k TPA though its hard to
; get excited.
;
ds 229
;
; BIOS Jump Table
;
cbt: jmp wboot ; cold boot entry
wbt: jmp wboot ; warm boot entry
jmp xconst ; console status
jmp xconin ; console input
jmp xconout ; console output
jmp xlist ; list output
jmp xauxout ; aux device output
jmp xauxin ; aux device input
jmp home ; home disk head
jmp seldsk ; select drive
jmp settrk ; select track
jmp setsec ; select sector
jmp setdma ; set dma address
jmp read ; read a sector
jmp write ; write a sector
jmp xlistst ; list status
jmp sectran ; sector translation
;
; The CP/M 3.0 BIOS jump table is copied here
; to allow easy access to its routines. The disk
; I/O routines are potentially in banked memory
; so they cannot be called directly.
;
xwboot: jmp 0 ; warm boot
xconst: jmp 0
xconin: jmp 0
xconout:jmp 0
xlist: jmp 0
xauxout:jmp 0
xauxin: jmp 0
jmp 0
jmp 0
jmp 0
jmp 0
jmp 0
jmp 0
jmp 0
xlistst:jmp 0
;
; Signon message
;
signon: db 0dh,0ah,'BIOS ver 2.21 ACTIVE',0dh,0ah,0
;
; Cold boot
;
boot: push psw ; a BDOS call is in progress
push h ; so save CPU state
push d
push b
lxi h,next ; now bypass this RSX on
shld entry+1 ; all subsequent BDOS calls
call init ; initialize BIOS variables
lhld 1 ; save the CP/M 3.0 BIOS jump
shld old$addr ; at location 0
lxi d,xwboot ; set up to move jump table
lxi b,15*3 ; byte count
ldir
lxi h,wbt ; substitute new jump address
shld 1
lxi h,signon ; sound off
call prmsg
pop b ; restore BDOS call state
pop d
pop h
pop psw
jmp next ; carry on
;
; Warm boot
;
wboot: lhld old$addr
shld 1 ; restore normal BIOS address
jmp 0 ; jump to CP/M 3.0 warm boot
;
; Initialize BIOS internal variables for cold boot
;
init: xra a
sta hstwrt ; host buffer written
sta hstact ; host buffer inactive
lxi h,80h
shld dmaadr
ret
;
; Routine to call banked BIOS routines via BDOS
; function 50. All disk I/O calls are made through
; here.
;
xbios: sta biospb ; set BIOS function
mvi c,50 ; direct BIOS call function
lxi d,biospb ; BIOS parameter block
jmp next ; jump to BDOS
;
biospb: db 0 ; BIOS function
areg: db 0 ; A reguster
bcreg: dw 0 ; BC register
dereg: dw 0 ; DE register
hlreg: dw 0 ; HL register
;
; Home disk.
;
home: lda hstwrt ; check if pending write
ora a
cnz writehst ; dump buffer to disk
xra a
sta hstwrt ; buffer written
sta hstact ; buffer inactive
sta unacnt ; zero alloc count
sta sektrk ; zero track count
sta sektrk+1
ret
;
; Select disk. Create a fake DPH for programs
; that might use it.
;
seldsk: mov a,c ; requested drive number
sta sekdsk
sta bcreg ; set C reg in BIOSPB
mvi a,9 ; BIOS function number
call xbios ; CP/M 3.0 select
mov a,h
ora l ; check for HL=0
rz ; select error
mov e,m ; get address of xlat table
inx h
mov d,m
xchg
shld xlat ; save xlat address
lxi h,11 ; offset to dpb address
dad d
mov e,m ; fetch address to dpb
inx h
mov d,m
xchg
shld dpb ; address of dpb
mov a,m ; cpm sectors per track
sta spt
inx h
inx h ; point to block shift mask
inx h
mov a,m
sta bsm ; save block shift mask
lxi d,12 ; offset to psh
dad d
mov a,m
sta psh ; save physical shift factor
lxi h,dph ; return DPH address
ret
;
; This fake DPH holds the addresses of the actual
; DPB. The CP/M 3.0 DPH is *not* understood
; by CP/M 2.2 programs.
;
dph: equ $
dw 0 ; no translation
ds 6 ; scratch words
ds 2 ; directory buffer
dpb: ds 2 ; DPB
ds 2 ; CSV
ds 2 ; ALV
;
; Set track.
;
settrk: sbcd sektrk
ret
;
; Set dma.
;
setdma: sbcd dmaadr
ret
;
; Translate sectors. Sectors are not translated yet.
; Wait until we know the physical sector number.
; This works fine as long as the program trusts
; the BIOS to do the translation. Some programs
; access the XLAT table directly to do their own
; translation. These programs will get the wrong
; idea about disk skew but it should cause no
; harm.
;
sectran:mov l,c ; return sector in HL
mov h,b
ret
;
; Set sector number.
;
setsec: mov a,c
sta seksec
ret
;
; Read the selected CP/M sector.
;
read: mvi a,1
sta readop ; read operation
inr a ; a=2 (wrual)
sta wrtype ; treat as unalloc
jmp alloc ; perform read
;
; Write the selected CP/M sector.
;
write: xra a
sta readop ; not a read operation
mov a,c
sta wrtype ; save write type
cpi 2 ; unalloc block?
jrnz chkuna
;
; Write to first sector of unallocated block.
;
lda bsm ; get block shift mask
inr a ; adjust value
sta unacnt ; unalloc record count
lda sekdsk ; set up values for
sta unadsk ; writing to an unallocated
lda sektrk ; block
sta unatrk
lda seksec
sta unasec
;
chkuna: lda unacnt ; any unalloc sectors
ora a ; in this block
jrz alloc ; skip if not
dcr a ; --unacnt
sta unacnt
lda sekdsk
lxi h,unadsk
cmp m ; sekdsk = unadsk ?
jrnz alloc ; skip if not
lda sektrk
cmp m ; sektrk = unatrk ?
jrnz alloc ; skip if not
lda seksec
lxi h,unasec
cmp m ; sektrk = unasec ?
jrnz alloc ; skip if not
inr m ; move to next sector
mov a,m
lxi h,spt ; addr of spt
cmp m ; sector > spt ?
jrc noovf ; skip if no overflow
lhld unatrk
inx h
shld unatrk ; bump track
xra a
sta unasec ; reset sector count
noovf: xra a
sta rsflag ; don't pre-read
jr rwoper ; perform write
;
alloc: xra a ; requires pre-read
sta unacnt
inr a
sta rsflag ; force pre-read
;
rwoper: xra a
sta erflag ; no errors yet
lda psh ; get physical shift factor
ora a ; set flags
mov b,a
lda seksec ; logical sector
lxi h,hstbuf ; addr of buffer
lxi d,128
jrz noblk ; no blocking
xchg ; shuffle registers
shift: xchg
rrc
jrnc sh1
dad d ; bump buffer address
sh1: xchg
dad h
ani 07fh ; zero high bit
djnz shift
xchg ; HL=buffer addr
noblk: sta sekhst
shld sekbuf
lxi h,hstact ; buffer active flag
mov a,m
mvi m,1 ; set buffer active
ora a ; was it already?
jrz filhst ; fill buffer if not
lda sekdsk
lxi h,hstdsk ; same disk ?
cmp m
jrnz nomatch
lda sektrk
lxi h,hsttrk ; same track ?
cmp m
jrnz nomatch
lda sekhst ; same buffer ?
lxi h,hstsec
cmp m
jrz match
;
nomatch:
lda hstwrt ; buffer changed?
ora a
cnz writehst ; clear buffer
;
filhst: lda sekdsk
sta hstdsk
lhld sektrk
shld hsttrk
lda sekhst
sta hstsec
lda rsflag ; need to read ?
ora a
cnz readhst ; yes
xra a
sta hstwrt ; no pending write
;
match: lhld dmaadr
xchg
lhld sekbuf
lda readop ; which way to move ?
ora a
jrnz rwmove ; skip if read
mvi a,1
sta hstwrt ; mark buffer changed
xchg ; hl=dma de=buffer
;
rwmove: lxi b,128 ; byte count
ldir ; block move
lda wrtype ; write type
cpi 1 ; to directory ?
jrnz exit ; done
lda erflag ; check for errors
ora a
jrnz exit ; don't write dir if so
xra a
sta hstwrt ; show buffer written
call writehst ; write buffer
exit: lda erflag
ret
;
; Disk read. Call CP/M 3.0 BIOS to fill the buffer
; with one physical sector.
;
readhst:
call rw$init ; init CP/M 3.0 BIOS
mvi a,13 ; read function number
call xbios ; read sector
sta erflag
ret
;
; Disk write. Call CP/M 3.0 BIOS to write one
; physical sector from buffer.
;
writehst:
call rw$init ; init CP/M 3.0 BIOS
mvi a,14 ; write function number
call xbios ; write sector
sta erflag
ret
;
; Translate sector. Set CP/M 3.0 track, sector,
; DMA buffer and DMA bank.
;
rw$init:
lda hstsec ; physical sector number
mov l,a
mvi h,0
shld bcreg ; sector number in BC
lhld xlat ; address of xlat table
shld dereg ; xlat address in DE
mvi a,16 ; sectrn function number
call xbios ; get skewed sector number
mov a,l
sta actsec ; actual sector
shld bcreg ; sector number in BC
mvi a,11 ; setsec function number
call xbios ; set CP/M 3.0 sector
lhld hsttrk ; physical track number
shld bcreg ; track number in BC
mvi a,10 ; settrk function number
call xbios
lxi h,hstbuf ; sector buffer
shld bcreg ; buffer address in BC
mvi a,12 ; setdma function number
call xbios
mvi a,1 ; DMA bank number
sta areg ; bank number in A
mvi a,28 ; setbnk function number
call xbios ; set DMA bank
ret
;
; Print message at HL until null.
;
prmsg: mov a,m
ora a
rz
mov c,m
push h
call xconout
pop h
inx h
jmp prmsg
;
; disk i/o buffer
;
hstbuf: ds max$sector$size
;
; variable storage area
;
sekdsk: ds 1 ; logical disk number
sektrk: ds 2 ; logical track number
seksec: ds 1 ; logical sector number
;
hstdsk: ds 1 ; physical disk number
hsttrk: ds 2 ; physical track number
hstsec: ds 1 ; physical sector number
;
actsec: ds 1 ; skewed physical sector
sekhst: ds 1 ; temp physical sector
hstact: ds 1 ; buffer active flag
hstwrt: ds 1 ; buffer changed flag
;
unacnt: ds 1 ; unallocated sector count
unadsk: ds 1 ; unalloc disk number
unatrk: ds 2 ; unalloc track number
unasec: ds 1 ; unalloc sector number
sekbuf: ds 2 ; logical sector address in buffer
;
spt: ds 1 ; cpm sectors per track
xlat: ds 2 ; xlat address
bsm: ds 1 ; block shift mask
psh: ds 1 ; physical shift factor
;
erflag: ds 1 ; error reporting
rsflag: ds 1 ; force sector read
readop: ds 1 ; 1 if read operation
rwflag: ds 1 ; physical read flag
wrtype: ds 1 ; write operation type
dmaadr: ds 2 ; last dma address
oldaddr:ds 2 ; address of old BIOS
;
end