home *** CD-ROM | disk | FTP | other *** search
- ; ============================================================================
- ; * 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