mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-23 08:24:18 +00:00
3908 lines
113 KiB
Plaintext
3908 lines
113 KiB
Plaintext
;*********************************************
|
||
|
||
;this file is included in M4LDBIOS or M4CBIOS
|
||
;to generate a complete BIOS for M4LOADER
|
||
;or CPM.SYS respectively
|
||
|
||
;************************************************
|
||
;* *
|
||
;* M-Four Basic I/O System (M4BIOS) *
|
||
;* *
|
||
;* Version: 21 Date: 24 May 1983 *
|
||
;* *
|
||
;* For CP/M version 1.1 *
|
||
;* *
|
||
;************************************************
|
||
|
||
|
||
;*********************************************
|
||
;* *
|
||
;* Loader_bios is true if assembling the *
|
||
;* LOADER BIOS, otherwise BIOS is for the *
|
||
;* CPM.SYS file. *
|
||
;* *
|
||
;*********************************************
|
||
|
||
IF NOT cal
|
||
keybd_int_typ equ 65h ;keyboard int. (parallel)
|
||
|
||
ENDIF
|
||
|
||
IF cal
|
||
keybd_int_typ equ 60h
|
||
ENDIF
|
||
|
||
bdos_int equ 224 ;reserved BDOS interrupt
|
||
|
||
dpblen equ 24
|
||
|
||
xon equ 11h
|
||
xoff equ 13h
|
||
cntrl_Z equ 26
|
||
|
||
flop_flags equ .45aah ;only used by special version
|
||
flop_step_rate equ .45adh ;ditto
|
||
|
||
IF not loader_bios
|
||
;---------------------------------------------
|
||
;| |
|
||
|
||
bios_code equ 2500h
|
||
ccp_offset equ 0000h
|
||
bdos_ofst equ 0B06h ;BDOS entry point
|
||
|
||
;| |
|
||
;---------------------------------------------
|
||
ENDIF ;not loader_bios
|
||
|
||
IF loader_bios
|
||
;---------------------------------------------
|
||
;| |
|
||
|
||
bios_code equ 1200h ;start of LDBIOS
|
||
bdos_ofst equ 0406h ;stripped BDOS entry
|
||
|
||
IF NOT mpm
|
||
ccp_offset equ 0003h ;base of CPMLOADER
|
||
ENDIF
|
||
|
||
IF mpm
|
||
ccp_offset equ 0103h ;base of MPMLDR
|
||
ENDIF
|
||
|
||
;| |
|
||
;---------------------------------------------
|
||
ENDIF ;loader_bios
|
||
|
||
|
||
;*********************************************
|
||
;* *
|
||
;* Dummy Data Section *
|
||
;* *
|
||
;*********************************************
|
||
|
||
dseg 0 ;absolute low memory
|
||
org 0 ;(interrupt vectors)
|
||
|
||
first equ $
|
||
|
||
int0_offset rw 1
|
||
int0_segment rw 1
|
||
|
||
org 4 * 4
|
||
|
||
int4_offset rw 1
|
||
int4_segment rw 1
|
||
|
||
org 61h * 4
|
||
|
||
crt_int_offset rw 1
|
||
crt_int_segment rw 1
|
||
|
||
org 64h * 4
|
||
|
||
clock_int_offset rw 1
|
||
|
||
org keybd_int_typ * 4
|
||
|
||
keybd_int_offset rw 1
|
||
|
||
org 67h * 4
|
||
|
||
printer_int_offset rw 1
|
||
|
||
org bdos_int * 4
|
||
|
||
bdos_int_offset rw 1
|
||
bdos_int_segment rw 1
|
||
|
||
org 0400h
|
||
|
||
msdos_jmp rb 128
|
||
debug_wrksp rb 256
|
||
prom_wrksp rb 128
|
||
nvram rb 128
|
||
keytab rb 512
|
||
|
||
cseg
|
||
|
||
;********************************************************************
|
||
|
||
; equates / locations in cpm to be patched/used at run time
|
||
; to run cpm 80 com files.
|
||
|
||
ccp_file equ .0827h ; filename to be loaded
|
||
ccp_file_type equ .0831h ; filetype of ^
|
||
ccp_file_rec equ .0847h ; record count of ^
|
||
ccp_file_ext equ .0833h ; extent number of ^
|
||
|
||
com_patch equ .0727h ; address in ccp to be patched to force
|
||
; jump to bios routine to check for .com
|
||
; file if not .cmd file.
|
||
com_desc equ .000ah ; location of command line descriptor
|
||
com_line equ .000bh ; location of command line cpm 86, as input
|
||
|
||
ccp_parse_patch equ .07a0h ; here is put a temporary ret to end ccp parse
|
||
; routine
|
||
|
||
org 00edh
|
||
ccp_open: ; routine to open a file
|
||
|
||
org 46ch
|
||
ccp_cleanup: ; cleanup routine to be called before running
|
||
; cpm80, or if allocation of z80 bank/ load
|
||
; of cpm80 file fail.
|
||
|
||
org 3deh
|
||
ccp_exit: ; back to cpm86 command level
|
||
|
||
org 732h
|
||
ccp_cmd: ; back to load .CMD file
|
||
|
||
org 738h
|
||
ccp_parse: ; routine to parse command line to fcb1/fcb2
|
||
; + dma buffer
|
||
org 072ch
|
||
ccp_error: ; routine to give cpm86 command error
|
||
|
||
;***************************************************************************
|
||
|
||
org ccpoffset
|
||
ccp:
|
||
|
||
org bios_code
|
||
|
||
;*********************************************
|
||
;* *
|
||
;* BIOS Jump Vector for Individual Routines *
|
||
;* *
|
||
;*********************************************
|
||
|
||
JMP INIT ;Enter from BOOT ROM or LOADER
|
||
JMP WBOOT ;Arrive here from BDOS call 0
|
||
JMP CONST ;Return console keyboard status
|
||
JMP CONIN ;Return console keyboard char
|
||
JMP CONOUT ;Write char to console device
|
||
JMP LISTOUT ;Write character to list device
|
||
JMP PUNCH ;Write character to punch device
|
||
JMP READER ;Return char from reader device
|
||
JMP HOME ;Move to trk 00 on cur sel drive
|
||
JMP SELDSK ;Select disk for next rd/write
|
||
JMP SETTRK ;Set track for next rd/write
|
||
JMP SETSEC ;Set sector for next rd/write
|
||
JMP SETDMA ;Set offset for user buff (DMA)
|
||
JMP READ ;Read a 128 byte sector
|
||
JMP WRITE ;Write a 128 byte sector
|
||
JMP LISTST ;Return list status
|
||
JMP SECTRAN ;Xlate logical->physical sector
|
||
JMP SETDMAB ;Set seg base for buff (DMA)
|
||
JMP GETSEGT ;Return offset of Mem Desc Table
|
||
JMP GETIOB ;Return I/O map byte (IOBYTE)
|
||
JMP SETIOB ;Set I/O map byte (IOBYTE)
|
||
|
||
;*********************************************
|
||
;* *
|
||
;* INIT Entry Point, Differs for LDBIOS and *
|
||
;* BIOS, according to "Loader_Bios" value *
|
||
;* *
|
||
;*********************************************
|
||
|
||
INIT: ;print signon message and initialize hardware
|
||
int 3 ; DEBUG
|
||
mov ax,cs ;we entered with a JMPF so use
|
||
mov ds,ax ;CS: as the initial value of DS:,
|
||
mov es,ax ;ES:
|
||
|
||
;use local stack during initialization
|
||
|
||
mov ss,ax
|
||
mov sp,offset stkbase
|
||
|
||
IF loader_bios
|
||
;---------------------------------------------
|
||
;| |
|
||
push bp ;tells which boot disc
|
||
;| |
|
||
;---------------------------------------------
|
||
ENDIF
|
||
|
||
IF not loader_bios
|
||
;---------------------------------------------
|
||
;| |
|
||
; This is a BIOS for the CPM.SYS file.
|
||
|
||
mov ax,cs
|
||
mov kstat_ptr_seg,ax ; bios is segment relocatable
|
||
mov iobyte_ptr_seg,ax
|
||
mov cl,4
|
||
shl ax,cl
|
||
add fn_expand_ptr,ax ; so bios is segment relocatable
|
||
|
||
; establish if 128 or 256 k system
|
||
|
||
push es
|
||
mov ax,1000h
|
||
mov es,ax
|
||
mov di,0ffffh ; write to top of 128k,55
|
||
mov es:byte ptr [di],55h
|
||
mov ax,3000h
|
||
mov es,ax
|
||
mov es:byte ptr [di],00 ; write to top of 256,0
|
||
mov ax,1000h
|
||
mov es,ax
|
||
cmp es:byte ptr [di],55h ; see if 128 top changed
|
||
pop es ; top 128 mirrored to bottom if absent
|
||
je big_sys ; must be 256 k system
|
||
sub seg_len,2000h
|
||
mov si,offset size_txt_small ; amend signon
|
||
mov di,offset size_txt
|
||
mov cx,3
|
||
cld
|
||
rep movs al,al ; replace 256k with 128k at sign-on
|
||
|
||
big_sys:
|
||
|
||
; Print firmware revision number
|
||
|
||
push ds
|
||
mov ax,0fc00h
|
||
mov ds,ax
|
||
mov al,byte ptr .3fffh
|
||
pop ds
|
||
aam
|
||
add ax,3030h
|
||
xchg al,ah
|
||
mov word ptr firm_rev,ax
|
||
|
||
;Give sign-on message
|
||
|
||
mov bx,offset signon ;print sign on message
|
||
call pmsg
|
||
|
||
; Patch cpm to include routine to test for .com files
|
||
|
||
mov byte ptr com_patch,0e9h ;jump instruction
|
||
mov word ptr com_patch+1,offset cmd_chk - (offset com_patch + 3)
|
||
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF ;not loader_bios
|
||
|
||
;If Winchester present then find CP/M partitions
|
||
|
||
callf get_switch
|
||
; test al,bit2 ;8" drives?
|
||
; jz not_8_in
|
||
; mov buffer_size,8 * 1024 ;ensure buffer big enough
|
||
;not_8_in:
|
||
test al,bit3
|
||
jz no_winch
|
||
mov dx,1 ;read sector 1
|
||
mov cx,1
|
||
mov bx,offset part_buf
|
||
mov al,20h
|
||
callf hdsk_all
|
||
jz hd_read_ok
|
||
|
||
mov cl,true ;indicate hard disc access
|
||
call print_error
|
||
mov bx,offset part_err_msg
|
||
call pmsg
|
||
jmps $
|
||
|
||
hd_read_ok:
|
||
mov si,offset part_buf
|
||
mov di,offset dpb_7
|
||
call set_size
|
||
mov si,offset part_buf + 2
|
||
mov di,offset dpb_8
|
||
call set_size
|
||
|
||
no_winch:
|
||
xor bx,bx
|
||
push ds ;save the DS register
|
||
mov ds,bx
|
||
|
||
IF NOT loader_bios
|
||
;------------------------------------------------
|
||
;| |
|
||
push es
|
||
mov es,bx
|
||
|
||
mov int0_segment,cs
|
||
mov int0_offset,offset div_trap
|
||
|
||
mov si,offset int4_offset
|
||
mov word ptr [si],offset int_trap
|
||
mov 2[si],cs
|
||
mov cx,512 - 10
|
||
lea di,4[si]
|
||
pushf
|
||
push crt_int_offset
|
||
push crt_int_segment
|
||
cld
|
||
cli
|
||
rep movsw
|
||
pop crt_int_segment
|
||
pop crt_int_offset
|
||
popf
|
||
pop es
|
||
|
||
mov clock_int_offset,offset clock_int
|
||
mov keybd_int_offset,offset keybd_int
|
||
mov printer_int_offset,offset printer_int
|
||
|
||
;| |
|
||
;------------------------------------------------
|
||
ENDIF ;not loader_bios
|
||
|
||
; BDOS offset to proper interrupt
|
||
|
||
mov bdos_int_offset,bdos_ofst
|
||
mov bdos_int_segment,cs ;for loader bios
|
||
|
||
pop ds ;restore the DS register
|
||
|
||
|
||
IF (NOT cal) AND (NOT loader_bios)
|
||
;------------------------------------------------
|
||
;| |
|
||
|
||
;clear type-ahead buffer
|
||
|
||
key_buf_test:
|
||
mov dl,0
|
||
callf sio_in_stat
|
||
jz key_buf_clear ; if no chars in buffer
|
||
callf sio_in
|
||
jmps key_buf_test
|
||
|
||
key_buf_clear:
|
||
mov al,5
|
||
out kybd_cntl,al ; enable keyboard irq
|
||
|
||
cli
|
||
in al,pic_imr
|
||
and al,not bit5 ; enable its level
|
||
out pic_imr,al
|
||
sti
|
||
|
||
;| |
|
||
;------------------------------------------------
|
||
ENDIF ;(not cal) and (not loader_bios)
|
||
IF cal AND (NOT loader_bios)
|
||
;------------------------------------------------
|
||
;| |
|
||
|
||
mov dx,sio_0b_stat
|
||
mov al,12h
|
||
out dx,al
|
||
mov al,0
|
||
out dx,al ;set up dart vector
|
||
mov al,11h
|
||
out dx,al
|
||
mov al,1ch
|
||
out dx,al ;status affects vector & enable rx interrupt
|
||
|
||
cli
|
||
in al,pic_imr
|
||
and al,not bit0
|
||
out pic_imr,al
|
||
sti
|
||
;| |
|
||
;------------------------------------------------
|
||
ENDIF ;cal and (not loader_bios)
|
||
|
||
|
||
; set up dph's & dpb's
|
||
|
||
callf get_switch
|
||
mov ah,al
|
||
and al,1111b
|
||
cmp al,0101b ; double sided 8", no Winchester ?
|
||
mov al,ah
|
||
jne ds8 ; if no
|
||
|
||
;If d.s. 8 inch and no Winchester, test for double sided disc actually present
|
||
|
||
in al,kybd_stat
|
||
test al,bit3
|
||
mov al,ah
|
||
jz ds8 ;8" ds there
|
||
and al,not bit0 ;8" ss there
|
||
ds8:
|
||
|
||
IF NOT loader_bios
|
||
and ax,1fh
|
||
ENDIF
|
||
|
||
IF loader_bios
|
||
pop bp
|
||
cmp bp,offset hdsk_all
|
||
mov dx,07h ;mask all but 1st floppy
|
||
jne not_hdsk_boot
|
||
mov dx,08h ;mask all but Winchester
|
||
not_hdsk_boot:
|
||
and ax,dx
|
||
ENDIF
|
||
|
||
mov bx,offset avail_tab
|
||
scan_sys:
|
||
cmp word ptr [bx],-1
|
||
je not_recog
|
||
cmp [bx],ax
|
||
je sys_recog
|
||
add bx,22
|
||
jmps scan_sys
|
||
|
||
not_recog:
|
||
mov bx,offset unrecd_tx ;unrecognised system type
|
||
call pmsg
|
||
jmps $ ;hard stop
|
||
|
||
sys_recog:
|
||
lea si,2[bx]
|
||
mov dx,offset bdos_scr
|
||
|
||
; mov dx,offset hst_buf
|
||
; add dx,buffer_size ;get address if 1st free byte
|
||
|
||
mov bx,offset dph_a
|
||
mov di,offset dpb_a
|
||
xor cl,cl
|
||
|
||
set_hdr_loop:
|
||
call set_header
|
||
add si,4 ;length of AVAIL_TAB entry
|
||
add di,dpblen ;length of DPB
|
||
add bx,16 ;length of DPH
|
||
inc cl
|
||
cmp cl,5
|
||
jb set_hdr_loop
|
||
|
||
; dx = offset of first free byte
|
||
|
||
add dx,15 ;round up to paragraph
|
||
mov cl,4
|
||
shr dx,cl ;cvt to paragraph
|
||
mov ax,cs
|
||
add ax,dx
|
||
mov seg_start,ax ;store 1st free para in seg table
|
||
sub seg_len,ax ;and update free space
|
||
|
||
|
||
IF NOT loader_bios
|
||
;------------------------------------------------
|
||
;| |
|
||
push es
|
||
|
||
; clear keyboard table
|
||
|
||
xor ax,ax
|
||
mov es,ax
|
||
mov di,offset keytab
|
||
mov cx,length keytab
|
||
mov al,8dh
|
||
rep stos al
|
||
|
||
; Get address of system data area
|
||
|
||
mov cl,49
|
||
int 224
|
||
mov word ptr sysdat_offset,bx
|
||
mov word ptr sysdat_segment,es
|
||
|
||
; Enable clock interrupt (if clock present)
|
||
|
||
mov dx,010ah
|
||
in al,dx
|
||
or al,0fh ;max period (500 ms)
|
||
out dx,al
|
||
inc dx
|
||
mov al,01000110b
|
||
out dx,al ;24h,enable interrupt
|
||
cli
|
||
in al,pic_imr
|
||
and al,not bit4
|
||
out pic_imr,al
|
||
sti
|
||
|
||
pop es
|
||
;| |
|
||
;------------------------------------------------
|
||
ENDIF
|
||
|
||
|
||
mov cl,0 ;default to dr A: on coldstart
|
||
jmp ccp ;jump to cold start entry of CCP
|
||
|
||
|
||
;Routine to set up drive parameter header
|
||
|
||
set_header:
|
||
|
||
xor ax,ax
|
||
mov [bx],ax
|
||
mov 2[bx],ax
|
||
mov 4[bx],ax
|
||
mov 6[bx],ax
|
||
|
||
push si
|
||
mov si,[si]
|
||
test si,si
|
||
jz null_header
|
||
|
||
test byte ptr 15[si],bit3 ;single density ?
|
||
jz set_hdr_1
|
||
mov [bx],offset xlt26 ;if yes
|
||
|
||
set_hdr_1:
|
||
mov 8[bx],offset dirbuf
|
||
mov 10[bx],di
|
||
mov 12[bx],dx
|
||
add dx,11[si]
|
||
mov 14[bx],dx
|
||
mov ax,5[si] ;get disk size
|
||
add ax,15 ;to round up
|
||
push cx
|
||
mov cl,3
|
||
shr ax,cl ;divide by 8 to get alloc vec size
|
||
add dx,ax
|
||
|
||
push di
|
||
mov cx,dpblen ;max. dpb length
|
||
cld
|
||
rep movs al,al
|
||
pop di
|
||
pop cx
|
||
pop si
|
||
|
||
mov ax,2[si]
|
||
mov 18[di],al ;set drive number
|
||
|
||
IF NOT loader_bios
|
||
;----------------------------------------
|
||
;| |
|
||
call print_drive
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF ;not loader_bios
|
||
|
||
ret
|
||
|
||
null_header:
|
||
mov word ptr 10[bx],0
|
||
pop si
|
||
ret
|
||
|
||
|
||
; Routine to set size of hard disc partition in DPB
|
||
; Enter with SI pointing to partition table and DI to DPB
|
||
|
||
set_size:
|
||
push si
|
||
push di
|
||
callf hdsk_size ;sectors/track to CL
|
||
|
||
; mov ax,512
|
||
; mov ch,0
|
||
; mul cx ;get required buffer size
|
||
; cmp ax,buffer_size
|
||
; jbe no_set_bufsize
|
||
; mov buffer_size,ax
|
||
;no_set_bufsize:
|
||
|
||
pop di
|
||
pop si
|
||
|
||
mov 17[di],cl ;store sectors/track
|
||
mov ax,cx
|
||
shl ax,1
|
||
shl ax,1 ;get CP/M sectors/track
|
||
mov [di],ax
|
||
|
||
mov ax,[si] ;get track offset of partition
|
||
mul cx ;convert to sector
|
||
mov 20[di],ax ;save sector offset
|
||
|
||
mov ax,2[si] ;start of next partition
|
||
sub ax,[si] ;get partition size
|
||
dec ax ;less 1 reserved track
|
||
js no_part
|
||
|
||
mul cx ;get no of 512b sectors
|
||
mov cl,4
|
||
shr ax,cl ;convert 512b sectors to 8K blocks
|
||
dec ax ;get last available block no.
|
||
mov 5[di],ax ;store number of free blocks
|
||
test ah,ah ;DSM > 255?
|
||
jnz exm_3_ok
|
||
mov byte ptr 4[di],7 ;reset EXM from 3 to 7
|
||
exm_3_ok:
|
||
ret
|
||
|
||
no_part:
|
||
mov bx,offset no_part_msg
|
||
call pmsg
|
||
jmps $
|
||
|
||
|
||
IF NOT loader_bios
|
||
;----------------------------------------
|
||
;| |
|
||
|
||
; print drive name and type
|
||
; cl= drive name (A..), di= associated dpb
|
||
|
||
print_drive:
|
||
push bx
|
||
push cx
|
||
push si
|
||
push di
|
||
add cl,'A'
|
||
call conout
|
||
mov cl,':'
|
||
call conout
|
||
mov cl,' '
|
||
call conout
|
||
pop di
|
||
push di
|
||
mov bx,offset win_tx
|
||
|
||
test dpb_flags[di],bit4 ;see if disk is floppy or winch
|
||
jnz chk4 ;skip if winchester
|
||
test dpb_phy_disk[di],bit0
|
||
mov cl,'L'
|
||
jz chk1
|
||
mov cl,'R'
|
||
chk1:
|
||
call conout
|
||
mov bx,offset floptx
|
||
call pmsg
|
||
pop di
|
||
push di
|
||
mov al,dpb_flags[di] ;get flags
|
||
|
||
IF NOT cal ;nested IF
|
||
;----------------------------------------
|
||
;| |
|
||
mov cl,'5' ;print disk size
|
||
test al,bit2
|
||
jz boot5
|
||
mov cl,'8'
|
||
boot5:
|
||
push ax
|
||
call conout ;print 5 or 8
|
||
mov bx,offset driv_tx
|
||
call pmsg
|
||
pop ax
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
test al,bit0
|
||
mov bx,offset single_tx
|
||
jz chk2
|
||
mov bx,offset double_tx
|
||
chk2:
|
||
push ax
|
||
call pmsg
|
||
mov bx,offset sides_tx
|
||
call pmsg
|
||
pop ax
|
||
test al,bit1
|
||
mov bx,offset quad_tx
|
||
jnz chk3
|
||
test al,bit3
|
||
mov bx,offset double_tx
|
||
jz chk3
|
||
mov bx,offset single_tx
|
||
chk3:
|
||
call pmsg
|
||
mov bx,offset density_tx
|
||
chk4:
|
||
call pmsg
|
||
pop di
|
||
pop si
|
||
pop cx
|
||
pop bx
|
||
ret ; from print_drive
|
||
|
||
|
||
; default divide overflow trap
|
||
|
||
div_trap:
|
||
mov bx,offset divide_error_tx
|
||
jmps int_trap_1
|
||
|
||
; trap for other uninitialised interrupts
|
||
|
||
int_trap:
|
||
mov bx,offset int_trap_tx
|
||
int_trap_1:
|
||
sti
|
||
call pmsg
|
||
mov cl,0
|
||
mov dl,0
|
||
int 224 ;exit to ccp
|
||
|
||
|
||
; Level 7 interrupt routine (8259A cleanup)
|
||
|
||
printer_int:
|
||
mov cs:ax_save_7,ax
|
||
mov al,67h
|
||
out pic_icw,al
|
||
mov ax,cs:ax_save_7
|
||
iret
|
||
|
||
|
||
; Real time clock interrupt (frequency 2 Hz)
|
||
|
||
clock_int:
|
||
mov cs:ss_save,ss
|
||
mov cs:sp_save,sp
|
||
mov cs:clock_stack,ax
|
||
mov ax,cs
|
||
mov ss,ax
|
||
mov sp,offset clock_stack
|
||
sti
|
||
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push si
|
||
push di
|
||
push bp
|
||
push ds
|
||
push es
|
||
|
||
mov ds,ax ;AX still holds copy of CS
|
||
|
||
mov dx,010ch
|
||
in al,dx ; clear interrupt
|
||
|
||
call gettim ; get the time /date
|
||
jnz time_not_ok
|
||
|
||
les di,dword ptr sysdat_offset
|
||
lea di,32[di] ;point to TOD field
|
||
|
||
mov ch,'/'
|
||
mov al,month
|
||
call dec2
|
||
|
||
mov al,day_no
|
||
call dec2
|
||
|
||
mov ch,','
|
||
mov al,yr
|
||
add al,80 ;year is from 1980
|
||
call dec2
|
||
|
||
mov ch,':'
|
||
mov al,byte ptr hour
|
||
call dec2
|
||
|
||
mov al,byte ptr minute
|
||
call dec2
|
||
|
||
mov ch,','
|
||
mov al,byte ptr second
|
||
call dec2
|
||
|
||
time_not_ok:
|
||
cli
|
||
mov al,64h
|
||
out pic_icw,al ;eoi to PIC
|
||
|
||
pop es
|
||
pop ds
|
||
pop bp
|
||
pop di
|
||
pop si
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
|
||
cli
|
||
mov ss,cs:ss_save
|
||
mov sp,cs:sp_save
|
||
iret
|
||
|
||
|
||
; Routine to get date and time from clock
|
||
; Returns Z if ok
|
||
|
||
gettim:
|
||
mov cx,1500 ; timeout loop
|
||
mov dx,100h+10 ; adress
|
||
clk_wait:
|
||
in al,dx
|
||
test al,10000000b ;bit7
|
||
loopnz clk_wait
|
||
jz clk_ok
|
||
or al,0ffh ; clock u/s: return al = ff
|
||
ret
|
||
|
||
clk_ok:
|
||
mov dx,100h
|
||
mov di,offset clock_temp
|
||
|
||
read_time: ; loop round reading clock registers
|
||
in al,dx
|
||
mov [di],al
|
||
inc di
|
||
inc dx
|
||
cmp dx,100h+10
|
||
jne read_time
|
||
; Test data for validity
|
||
|
||
cmp second,59 ; check all clock inputs
|
||
ja error ; 0 - 59 ok
|
||
cmp minute,59
|
||
ja error ; 0 - 59 ok
|
||
cmp hour,23
|
||
ja error ; 0 - 23 ok
|
||
cmp day_no,1
|
||
jb error
|
||
cmp day_no,31
|
||
ja error ; 1 - 31 ok
|
||
cmp month,1
|
||
jb error
|
||
cmp month,12
|
||
ja error ; 1 - 12 ok
|
||
cmp yr,99
|
||
ja error ; 0 - 99 ok (1980 - 2079)
|
||
xor ax,ax
|
||
ret
|
||
|
||
error:
|
||
or ax,1 ; 1 is duf date return
|
||
ret
|
||
|
||
; Routine to convert AL to 2-character ASCII number
|
||
; and store at [ES:DI] followed by character in CH
|
||
; DI is incremented by 3
|
||
|
||
dec2:
|
||
cld
|
||
mov ah,0
|
||
mov cl,10
|
||
div cl
|
||
add al,'0'
|
||
stos al
|
||
mov al,ah
|
||
add al,'0'
|
||
stos al
|
||
mov al,ch
|
||
stos al
|
||
ret
|
||
|
||
|
||
;| |
|
||
;-------------------------------------------
|
||
ENDIF
|
||
|
||
|
||
WBOOT:
|
||
mov ax,cs
|
||
mov ds,ax
|
||
mov es,ax
|
||
mov ss,ax
|
||
mov sp,offset stkbase ;to prevent re-use of stack
|
||
|
||
IF not loader_bios
|
||
;------------------------------------------------
|
||
;| |
|
||
|
||
call z80_abort ; cleanup z80 bank if needed
|
||
|
||
; write out host buffer if necessary
|
||
|
||
cmp write_req,0
|
||
je no_flush
|
||
call rw_command ;can't do much about errors here
|
||
mov write_req,0
|
||
no_flush:
|
||
|
||
; No need to deselect host buffer - this is better done in SELDSK
|
||
|
||
;| |
|
||
;------------------------------------------------
|
||
ENDIF
|
||
|
||
jmp ccp+6 ;direct entry to CCP at command level
|
||
|
||
|
||
|
||
;*********************************************
|
||
;* *
|
||
;* CP/M Character I/O Interface Routines *
|
||
;* *
|
||
;*********************************************
|
||
;
|
||
;IOBYTE descriptions and actions (what this bios does):
|
||
;
|
||
; Values for M-Four:
|
||
;
|
||
;CONSOLE FIELD (bits 0 & 1)
|
||
; 0 - Port 1 (TTY:)
|
||
; 1 - Monitor (CRT:)
|
||
; 2 - Port 2 (BAT:)
|
||
; 3 - Port 3 (UC1:)
|
||
;
|
||
;READER FIELD (bits 2 & 3)
|
||
; 0 - Port 1 (TTY:)
|
||
; 1 - Port 2 (PTR:)
|
||
; 2 - Port 3 (UR1:)
|
||
; 3 - Port 4 (UR2:)
|
||
;
|
||
;PUNCH FIELD (bits 4 & 5)
|
||
; 0 - Port 1 (TTY:)
|
||
; 1 - Port 2 (PUN:)
|
||
; 2 - Port 3 (UP1:)
|
||
; 3 - Port 4 (UP2:)
|
||
;
|
||
;LIST FIELD (bits 6 & 7)
|
||
; 0 - Port 1 (TTY:)
|
||
; 1 - Monitor (CRT:)
|
||
; 2 - Centronics (LPT:)
|
||
; 3 - Port 2 (UL1:)
|
||
|
||
; Values for Cal-PC:
|
||
;
|
||
;CONSOLE FIELD (bits 0 & 1)
|
||
; 0 - Port 2 (TTY:)
|
||
; 1 - Monitor (CRT:)
|
||
; 2 - Port 3 (BAT:)
|
||
; 3 - Port 2 (UC1:)
|
||
;
|
||
;READER FIELD (bits 2 & 3)
|
||
; 0 - Port 2 (TTY:)
|
||
; 1 - Port 3 (PTR:)
|
||
; 2 - Port 4 (UR1:)
|
||
; 3 - Null (UR2:)
|
||
;
|
||
;PUNCH FIELD (bits 4 & 5)
|
||
; 0 - Port 2 (TTY:)
|
||
; 1 - Port 3 (PUN:)
|
||
; 2 - Port 4 (UP1:)
|
||
; 3 - Null (UP2:)
|
||
;
|
||
;LIST FIELD (bits 6 & 7)
|
||
; 0 - Port 2 (TTY:)
|
||
; 1 - Monitor (CRT:)
|
||
; 2 - Centronics (LPT:)
|
||
; 3 - Port 3 (UL1:)
|
||
|
||
; Loader bios does not use IOBYTE or interrupts
|
||
|
||
IF NOT loader_bios ;using nested IFs here
|
||
;------------------------------------------------
|
||
;| |
|
||
|
||
IF NOT cal
|
||
console_tab db 1, 0, 2, 3
|
||
list_tab db 1, 0, 5, 2
|
||
ENDIF
|
||
|
||
IF cal
|
||
console_tab db 2, 0, 3, 2
|
||
list_tab db 2, 0, 5, 3
|
||
ENDIF
|
||
|
||
; service keyboard int
|
||
keybd_int:
|
||
mov cs:saved_ax,ax
|
||
mov cs:saved_ds,ds
|
||
mov cs:saved_bx,bx
|
||
|
||
IF NOT cal
|
||
;----------------------------------------
|
||
;| |
|
||
in al,kybd_data
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
IF cal
|
||
;----------------------------------------
|
||
;| |
|
||
in al,sio_int_vec
|
||
cmp al,04h
|
||
je rec_chr_int
|
||
cmp al,06h
|
||
je rec_chr_int
|
||
int 68h ;user interrupt
|
||
jmps sio_int_eoi
|
||
|
||
rec_chr_int:
|
||
in al,sio0b_data
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
mov bx,cs
|
||
mov ds,bx
|
||
mov bx,kbuf_put_ptr
|
||
inc bx
|
||
cmp bx,offset kbuf_end
|
||
jne no_putp_ovf
|
||
mov bx,offset kbuf_start
|
||
no_putp_ovf:
|
||
cmp bx,kbuf_get_ptr
|
||
je kbuf_full
|
||
xchg bx,kbuf_put_ptr
|
||
mov [bx],al
|
||
lds bx,kstat_ptr
|
||
mov byte ptr [bx],-1
|
||
kbuf_full:
|
||
|
||
IF NOT cal
|
||
;----------------------------------------
|
||
;| |
|
||
mov al,65h
|
||
out pic_icw,al
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
IF cal
|
||
;----------------------------------------
|
||
;| |
|
||
sio_int_ret:
|
||
mov al,38h
|
||
out sio0a_stat,al ;eio to DART
|
||
sio_int_eoi:
|
||
mov al,60h
|
||
out pic_icw,al
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
mov bx,cs:saved_bx
|
||
mov ds,cs:saved_ds
|
||
mov ax,cs:saved_ax
|
||
iret
|
||
|
||
|
||
;Console status routine
|
||
; Input: none
|
||
; Output: IF ready THEN AL:=0FFH
|
||
; ELSE AL:=00
|
||
|
||
CONST:
|
||
push bx
|
||
push ds
|
||
lds bx,iobyte_ptr
|
||
mov al,[bx]
|
||
pop ds
|
||
|
||
and al,11b ;get console bits from iobyte
|
||
cmp al,01b
|
||
jz fkybdst
|
||
|
||
;Here if (IOBYTE & 11b) <> 01b
|
||
|
||
mov bx,offset console_tab
|
||
xlat al
|
||
push dx
|
||
mov dl,al
|
||
callf sio_in_stat
|
||
pop dx
|
||
mov al,0
|
||
jz const_out
|
||
or al,-1
|
||
const_out:
|
||
pop bx
|
||
ret
|
||
|
||
|
||
;Here if (IOBYTE & 11b) = 01b
|
||
|
||
fkybdst:
|
||
push ds
|
||
lds bx,kstat_ptr
|
||
mov al,byte ptr [bx]
|
||
pop ds
|
||
pop bx
|
||
ret
|
||
|
||
; Console input routine
|
||
; Input: none
|
||
; Output: AL:=char AND 07FH
|
||
|
||
CONIN:
|
||
push ds
|
||
push bx
|
||
lds bx,iobyte_ptr
|
||
mov al,[bx]
|
||
pop bx
|
||
pop ds
|
||
|
||
and al,11b ;get CONSOLE bits from IOBYTE
|
||
cmp al,01b
|
||
jz fkybdin
|
||
|
||
;Here if CONSOLE field <> 1
|
||
|
||
push bx
|
||
mov bx,offset console_tab
|
||
xlat al
|
||
pop bx
|
||
push dx
|
||
mov dl,al
|
||
callf sio_in
|
||
pop dx
|
||
and al,not bit7 ;mask parity bit
|
||
ret
|
||
|
||
;Here if CONSOLE field = 01b
|
||
;Decode keyboard function keys
|
||
|
||
fkybdin:
|
||
push bx
|
||
cmp fn_expand_flag,false ;jump if key not being decoded
|
||
je no_dec_in_prog
|
||
dec_in_prog:
|
||
push ds
|
||
xor bx,bx
|
||
mov ds,bx ;DS := 0
|
||
mov bx,cs: fn_expand_ptr ;BX := pointer
|
||
|
||
fn_decode:
|
||
inc bx
|
||
mov al,[bx] ;get character from bottom segment
|
||
mov cs: fn_expand_ptr,bx ;store new pointer of char just got
|
||
|
||
fn_decode2:
|
||
pop ds
|
||
test al,bit7 ;end of this key's data ?
|
||
jz fkey_don ;return if not
|
||
mov fn_expand_flag,false ;else reset
|
||
|
||
fkybdin_out:
|
||
call set_kstat
|
||
|
||
fkey_don:
|
||
pop bx
|
||
and al,not bit7 ;and return
|
||
ret
|
||
|
||
no_dec_in_prog:
|
||
wait_for_key:
|
||
mov bx,kbuf_get_ptr
|
||
cmp bx,kbuf_put_ptr
|
||
jz wait_for_key
|
||
mov al,[bx]
|
||
inc bx
|
||
cmp bx,offset kbuf_end
|
||
jne no_getp_ovf
|
||
mov bx,offset kbuf_start
|
||
no_getp_ovf:
|
||
mov kbuf_get_ptr,bx
|
||
|
||
IF NOT cal
|
||
;----------------------------------------
|
||
;| |
|
||
test al,bit7 ;function key ?
|
||
jz fkybdin_out ;return if not
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
|
||
IF cal
|
||
;----------------------------------------
|
||
;| |
|
||
mov bx,offset fn_key_tab
|
||
mov ah,80h ;map function keys to 80h upwards
|
||
fn_key_chk:
|
||
cmp al,[bx]
|
||
jz do_decode
|
||
cmp byte ptr [bx],-1
|
||
jz fkybdin_out
|
||
inc ah
|
||
inc bx
|
||
jmps fn_key_chk
|
||
|
||
do_decode:
|
||
mov al,ah
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
push ds
|
||
push cx
|
||
xor cx,cx
|
||
mov ds,cx ;else DS := 0
|
||
mov bx,offset keytab -1 ;start at KEYTAB in bottom segment
|
||
mov cx,length keytab ;for length KEYTAB chars
|
||
and al,not bit7 ;mask function bit
|
||
jz lookup_end ;skip if first function key
|
||
mov ah,al ;else AH := fn. key no.
|
||
|
||
fn_key_lookup:
|
||
inc bx
|
||
test byte ptr [bx],bit7
|
||
loopz fn_key_lookup
|
||
jz fn_overflow
|
||
dec ah
|
||
jnz fn_key_lookup
|
||
|
||
lookup_end:
|
||
pop cx
|
||
not cs: fn_expand_flag ;was false, now true.
|
||
jmps fn_decode ;go get char from memory & return
|
||
|
||
fn_overflow:
|
||
pop cx
|
||
mov al,bit7 ;here if past end of fn_table
|
||
jmps fn_decode2
|
||
|
||
|
||
IF cal
|
||
;----------------------------------------
|
||
;| |
|
||
fn_key_tab db 80h,81h,82h,83h,84h,85h,86h,87h,88h
|
||
db 8ah,8bh
|
||
db 0b7h,0b9h
|
||
db 0aah,0b1h,0b3h
|
||
db 0b0h
|
||
db -1
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
;Console output routine
|
||
; Input: CL:=char
|
||
; Output: none
|
||
|
||
CONOUT:
|
||
push bx
|
||
push ds
|
||
lds bx,iobyte_ptr
|
||
mov al,[bx]
|
||
pop ds
|
||
|
||
conout0:
|
||
and al,11b
|
||
cmp al,1
|
||
jz mon_out
|
||
|
||
;Here if console field <> 1
|
||
|
||
mov bx,offset console_tab
|
||
xlat al
|
||
push dx
|
||
mov dl,al
|
||
sio_out_wait:
|
||
call cpm_sio_out_stat ;don't use PROM as early ones don't test CTS or DTR
|
||
jnz sio_out_wait
|
||
mov al,cl
|
||
callf sio_out ;PROM ok here
|
||
pop dx
|
||
pop bx
|
||
ret
|
||
|
||
; Routine to test if SIO ready to transmit
|
||
; Like PROM routine but tests CTS and DTR
|
||
; Returns opposite flags, i.e. Z = ready to transmit
|
||
|
||
cpm_sio_out_stat:
|
||
push dx
|
||
push bx
|
||
mov bx,offset port_table -1
|
||
xchg ax,dx
|
||
xlat al
|
||
pop bx
|
||
xchg ax,dx
|
||
mov dh,0
|
||
mov al,10h
|
||
out dx,al ;flush CTS/DSR fifo
|
||
in al,dx
|
||
and al,00101100b ;test for CTS, DSR and transmit buf empty
|
||
cmp al,00101100b
|
||
pop dx
|
||
ret
|
||
|
||
port_table db sio0b_stat, sio0a_stat, sio1b_stat, sio1a_stat
|
||
|
||
;Here if CONSOLE field = 1
|
||
mon_out:
|
||
mov al,cl
|
||
push dx
|
||
mov dl,0
|
||
callf sio_out ;Send byte to screen
|
||
pop dx
|
||
pop bx
|
||
ret
|
||
|
||
|
||
; List output routine
|
||
; Input: CL:=char
|
||
; Output: none
|
||
|
||
LISTOUT:
|
||
push ds
|
||
lds bx,iobyte_ptr
|
||
mov al,[bx]
|
||
pop ds
|
||
|
||
rol al,1
|
||
rol al,1
|
||
and al,11b
|
||
cmp al,2
|
||
jz print_out ;Output to printer if 2
|
||
|
||
; Here if output to VDU or serial port
|
||
|
||
mov bx,offset list_tab
|
||
xlat al
|
||
mov dl,al
|
||
list_wait:
|
||
call list_stat
|
||
jnz list_wait
|
||
mov al,cl
|
||
callf sio_out
|
||
ret
|
||
|
||
; Here if output to Centronics port
|
||
|
||
print_out:
|
||
mov al,cl ;get data
|
||
callf prntr_out
|
||
ret
|
||
|
||
; Routine to get list device status for port DL
|
||
; Return Z if ready for output
|
||
; XON, XOFF recognised
|
||
|
||
list_stat:
|
||
cmp dl,0
|
||
jz list_stat_ret ;monitor always ready
|
||
more_stat:
|
||
callf sio_in_stat ;test for XON, XOFF
|
||
jz test_stat ;if no received character
|
||
callf sio_in
|
||
and al,7fh
|
||
cmp al,xon
|
||
jz setx
|
||
cmp al,xoff
|
||
jne more_stat
|
||
setx:
|
||
mov xonxoff,al
|
||
jmps more_stat
|
||
|
||
test_stat:
|
||
cmp xonxoff,xon
|
||
jne list_stat_ret ;if XOFF received last
|
||
call cpm_sio_out_stat ;test buffer empty, CTS, DCD
|
||
list_stat_ret:
|
||
ret
|
||
|
||
|
||
;List status routine
|
||
; Input: none
|
||
; Output: IF ready THEN AL:=0FFH
|
||
; ELSE AL:=00
|
||
|
||
LISTST:
|
||
push ds
|
||
lds bx,iobyte_ptr
|
||
mov al,[bx]
|
||
pop ds
|
||
|
||
rol al,1
|
||
rol al,1
|
||
and al,11b
|
||
cmp al,2
|
||
jz print_stat ;Jump if printer
|
||
mov bx,offset list_tab
|
||
xlat al
|
||
mov dl,al
|
||
call list_stat
|
||
mov al,0
|
||
jnz listst_ret
|
||
mov al,-1
|
||
listst_ret:
|
||
ret
|
||
|
||
;Here if LIST field = 2
|
||
print_stat:
|
||
callf prntr_st
|
||
mov al,0
|
||
jz listst_ret_2
|
||
mov al,-1
|
||
listst_ret_2:
|
||
ret
|
||
|
||
|
||
;Punch output routine
|
||
; Input: CL:=char
|
||
; Output: none
|
||
|
||
PUNCH:
|
||
push ds
|
||
lds bx,iobyte_ptr
|
||
mov al,[bx]
|
||
pop ds
|
||
|
||
ror al,1
|
||
ror al,1
|
||
ror al,1
|
||
ror al,1
|
||
and al,11
|
||
inc ax
|
||
|
||
IF cal
|
||
inc ax
|
||
cmp al,4
|
||
ja punch_ret
|
||
ENDIF
|
||
|
||
mov dl,al
|
||
mov al,cl
|
||
callf sio_out
|
||
punch_ret:
|
||
ret
|
||
|
||
;Reader input routine
|
||
; Input: none
|
||
; Output: AL:=char AND 07FH
|
||
|
||
READER:
|
||
push ds
|
||
lds bx,iobyte_ptr
|
||
mov al,[bx]
|
||
pop ds
|
||
ror al,1
|
||
ror al,1
|
||
and al,11b
|
||
inc ax
|
||
|
||
IF cal
|
||
inc ax
|
||
cmp al,4
|
||
jbe rdr_1
|
||
mov al,cntrl_Z
|
||
ret
|
||
|
||
rdr_1:
|
||
ENDIF
|
||
|
||
mov dl,al
|
||
callf sio_in
|
||
and al,07fh
|
||
ret
|
||
|
||
;| |
|
||
;------------------------------------------------
|
||
ENDIF ;not loader_bios
|
||
|
||
IF loader_bios
|
||
;------------------------------------------------
|
||
;| |
|
||
|
||
CONST:
|
||
push dx
|
||
mov dl,0
|
||
callf sio_in_stat
|
||
pop dx
|
||
mov al,0
|
||
jz const_ret
|
||
mov al,0ffh
|
||
const_ret:
|
||
ret
|
||
|
||
|
||
CONIN:
|
||
push dx
|
||
mov dl,0
|
||
callf sio_in
|
||
pop dx
|
||
test al,bit7
|
||
jnz conin ;ignore function keys
|
||
ret
|
||
|
||
|
||
CONOUT:
|
||
mov al,cl
|
||
push dx
|
||
mov dl,0
|
||
callf sio_out ;Send byte to screen
|
||
pop dx
|
||
|
||
LISTOUT:
|
||
LISTST:
|
||
PUNCH:
|
||
READER:
|
||
ret
|
||
;| |
|
||
;------------------------------------------------
|
||
ENDIF ;loader_bios
|
||
|
||
|
||
;Get IOBYTE
|
||
; Input: none
|
||
; Output: AL:=IOBYTE
|
||
|
||
GETIOB:
|
||
push ds
|
||
lds bx,iobyte_ptr
|
||
mov al,[bx]
|
||
pop ds
|
||
ret
|
||
|
||
;Set IOBYTE
|
||
; Input: CL:=IOBYTE
|
||
; Output: none
|
||
|
||
SETIOB:
|
||
push ds
|
||
lds bx,iobyte_ptr
|
||
mov al,[bx]
|
||
mov [bx],cl
|
||
pop ds
|
||
xor al,cl
|
||
test al,bit6+bit7 ;see if printer assignment changed
|
||
jz no_set_xon
|
||
mov xonxoff,xon
|
||
no_set_xon:
|
||
ret
|
||
|
||
|
||
;*********************************************
|
||
;* *
|
||
;* Disk Input/Output Routines *
|
||
;* *
|
||
;*********************************************
|
||
|
||
SELDSK: ;select disk given by register CL
|
||
test dl,bit0 ;1st time selected?
|
||
jnz seldsk_1 ;if no
|
||
cmp cl,hst_disk ;same drive as sector in buffer?
|
||
jne seldsk_1 ;if no
|
||
|
||
mov hst_disk,-1 ;deselect buffer
|
||
|
||
IF NOT loader_bios
|
||
;----------------------------------------
|
||
;| |
|
||
cmp write_req,0 ;check no write was pending
|
||
je seldsk_1
|
||
|
||
; Error - write pending and disc may have been changed
|
||
|
||
mov write_req,0
|
||
push cx
|
||
mov bx,offset write_pending_tx
|
||
call pmsg
|
||
pop cx
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
seldsk_1:
|
||
xor bx,bx ;ready for error return
|
||
cmp cl,5 ;n beyond max disks?
|
||
jnb return ;return if so
|
||
|
||
mov al,cl ;save required disk
|
||
mov req_disk,al ;store disk_no in M4 memory
|
||
set_prm:
|
||
cbw ;ah := 0
|
||
mov cl,4 ;multiply by 16 (length of dp_block)
|
||
shl ax,cl
|
||
add ax,offset dph_A ;add base of dpbase
|
||
mov bx,ax ;bx := .dph
|
||
mov ax,10[bx] ;get address of dpb
|
||
test ax,ax ;drive exists ?
|
||
jne return ;if yes
|
||
mov bx,ax ;no, return 0
|
||
return: ret
|
||
|
||
HOME: ;move selected disk to home position (Track 0)
|
||
xor cx,cx ;set disk i/o to track zero
|
||
;drop through to SETTRK
|
||
|
||
SETTRK: ;set track address given by CX
|
||
mov req_trk,cx
|
||
ret
|
||
|
||
SETSEC: ;set sector number given by CL
|
||
mov req_sect,cl
|
||
ret
|
||
|
||
SECTRAN: ;translate sector CX using table at [DX]
|
||
mov bx,cx
|
||
test dx,dx
|
||
jz no_tran
|
||
add bx,dx ;add sector to tran table address
|
||
mov bl,[bx] ;get logical sector
|
||
no_tran:
|
||
ret
|
||
|
||
SETDMA: ;set DMA offset given by CX
|
||
mov dma_adr,CX
|
||
ret
|
||
|
||
SETDMAB: ;set DMA segment given by CX
|
||
mov dma_seg,CX
|
||
ret
|
||
;
|
||
GETSEGT: ;return address of physical memory table
|
||
mov bx,offset seg_table
|
||
ret
|
||
|
||
;*********************************************
|
||
;* *
|
||
;* All disk I/O parameters are setup: *
|
||
;* DISK is disk number (SELDSK) *
|
||
;* TRK is track number (SETTRK) *
|
||
;* SECT is sector number (SETSEC) *
|
||
;* DMA_ADR is the DMA offset (SETDMA) *
|
||
;* DMA_SEG is the DMA segment (SETDMAB)*
|
||
;* READ reads the selected sector to the DMA*
|
||
;* address, and WRITE writes the data from *
|
||
;* the DMA address to the selected sector *
|
||
;* (return 00 if successful, 01 if perm err)*
|
||
;* *
|
||
;*********************************************
|
||
|
||
READ:
|
||
mov al,false
|
||
jmps disc_tfr
|
||
|
||
WRITE:
|
||
mov write_type,cl ;save write information
|
||
mov al,true
|
||
disc_tfr:
|
||
mov write_flag,al ;save read or write flag
|
||
|
||
; IF (hst_disc = req_disc) & (hst_trk = req_trk)
|
||
; THEN no read required
|
||
|
||
mov al,hst_disk
|
||
cmp al,req_disk
|
||
jne rd_req
|
||
mov ax,hst_trk
|
||
cmp ax,req_trk
|
||
je do_tfr
|
||
|
||
rd_req:
|
||
cmp write_req,0 ;skip if write not required
|
||
je rd_req2
|
||
call rw_command
|
||
mov write_req,0
|
||
jnz j_wr_err
|
||
rd_req2:
|
||
mov ax,req_trk ;hst_trk := req_trk
|
||
mov hst_trk,ax
|
||
mov al,req_disk ;hst_disc := req_disc
|
||
mov hst_disk,al
|
||
|
||
mov ah,0 ;reset m4prom in case CPM has read discs
|
||
mov cl,4
|
||
shl ax,cl ;ax := ax * 16
|
||
add ax,offset dph_A
|
||
mov bx,ax ;save start of header table
|
||
mov bx,10[bx] ;get start of parameter block
|
||
mov hst_dpb,bx
|
||
mov al,dpb_flags[bx] ;get flags
|
||
mov cx,dpb_ret_sidleng[bx] ;get retries + sideleng
|
||
mov si,dpb_max_sectors[bx] ;get max_sectors
|
||
mov bp,dpb_secsiz[bx] ;get sec_size
|
||
|
||
test al,bit4 ;Winchester?
|
||
jnz no_set ;if so
|
||
test al,bit1 ;quad density?
|
||
jnz do_set ;if yes
|
||
xchg al,ah
|
||
callf get_switch
|
||
xchg al,ah
|
||
test ah,bit1 ;quad density drives?
|
||
jz do_set ;if no
|
||
or al,bit4 ;read alternate tracks
|
||
do_set:
|
||
callf flop_set
|
||
|
||
IF special
|
||
;----------------------------------------
|
||
;| |
|
||
mov si,0fc00h ;PROM segment
|
||
push ds
|
||
mov ds,si
|
||
mov byte ptr flop_flags,al ;ensure 8"/5" set
|
||
mov byte ptr flop_step_rate,3 ;set slow step rate in case 5"
|
||
pop ds
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
no_set:
|
||
call rw_command ;read since write_req = 0
|
||
j_wr_err:
|
||
jnz rd_err
|
||
do_tfr:
|
||
mov al,req_sect
|
||
mov ah,0
|
||
xchg al,ah
|
||
shr ax,1 ;ax := req_sect * 128
|
||
add ax,offset hst_buff
|
||
mov si,ax
|
||
mov di,dma_adr
|
||
mov cx,128 /2
|
||
push ds
|
||
push es
|
||
mov es,dma_seg
|
||
cmp byte ptr write_flag,false
|
||
je rw_move ;skip if read
|
||
xchg si,di
|
||
push es
|
||
push ds
|
||
pop es
|
||
pop ds
|
||
rw_move:
|
||
cld
|
||
rep movsw
|
||
pop es
|
||
pop ds
|
||
|
||
cmp write_flag,false ;return if (write_flag = false)
|
||
je rw_out_ok
|
||
|
||
cmp write_req,2
|
||
jnb no_wr_inc
|
||
|
||
mov si,hst_dpb
|
||
mov al,dpb_secsiz_msb[si] ;al := 0,1,2,4
|
||
cmp al,4
|
||
jb flip4to3
|
||
dec ax ;if 4, al := 3
|
||
flip4to3:
|
||
mov cl,al
|
||
mov al,req_sect ;divide req_sect
|
||
shr al,cl ;... by 1,2,4 or 8
|
||
|
||
cmp write_req,0 ;first write?
|
||
je set_rw_sec ;if yes
|
||
cmp al,hst_sect ;same sector as before?
|
||
je no_wr_inc ;if yes
|
||
|
||
; fall thru to increment write_req if no
|
||
|
||
set_rw_sec:
|
||
mov hst_sect,al ;and store
|
||
inc write_req
|
||
|
||
no_wr_inc:
|
||
cmp byte ptr write_type,1 ;write to directory ?
|
||
jne rw_out_ok
|
||
call rw_command
|
||
mov write_req,0
|
||
jnz wr_err
|
||
rw_out_ok:
|
||
mov al,0
|
||
ret
|
||
|
||
|
||
rd_err:
|
||
wr_err:
|
||
mov hst_disk,-1 ;deselect host buffer
|
||
mov al,1
|
||
ret
|
||
|
||
|
||
; Routine to do actual read/write transfers
|
||
; Does a read if write_req is 0, otherwise a write
|
||
; Parameters used are hst_track, hst_sect, hst_dpb
|
||
; Error Correction will take place in this routine
|
||
|
||
rw_command:
|
||
mov si,hst_dpb
|
||
|
||
; Check here for SS/DS same as before
|
||
|
||
IF (NOT special) AND (NOT cal)
|
||
;------------------------------------------------
|
||
;| |
|
||
test dpb_flags[si],bit4
|
||
jnz no_test ;don't check if winnie
|
||
callf get_switch
|
||
and al,101b
|
||
cmp al,101b
|
||
jne no_test ; dont check if not ds 8"
|
||
cli
|
||
in al,aux_cmd ; select side 0
|
||
and al,not bit6 ; to ensure can go ready
|
||
out aux_cmd,al ; if single sided
|
||
sti
|
||
rwait:
|
||
mov al,dpb_phy_disk[si]
|
||
mov ah,0
|
||
xor dx,dx
|
||
callf flopall ; select drive
|
||
test ah,bit7
|
||
jnz rwait ; wait till ready
|
||
in al,kybd_stat
|
||
mov cl,3
|
||
shr al,cl
|
||
xor al,dpb_flags[si]
|
||
test al,1
|
||
jnz test_ok
|
||
|
||
mov bx,offset change_msg
|
||
call pmsg
|
||
or al,-1
|
||
ret
|
||
;| |
|
||
;------------------------------------------------
|
||
ENDIF
|
||
|
||
no_test:
|
||
test_ok:
|
||
rw_retry:
|
||
mov si,hst_dpb ;in case here from retry
|
||
mov cl,dpb_sidleng[si] ;1 physical track to read
|
||
mov ch,0
|
||
mov ax,hst_trk
|
||
mul cx
|
||
mov dx,ax ;logsec := trk * (sects per trk)
|
||
mov bx,offset hst_buff
|
||
|
||
; Check here for only 1 write needed
|
||
|
||
cmp write_req,1 ;IF only 1 write
|
||
jne whole_trk
|
||
mov cx,1 ;THEN just do 1 sector
|
||
mov al,hst_sect
|
||
cbw
|
||
add dx,ax ;remembering to update log sector no.
|
||
push dx
|
||
mul dpb_secsiz[si] ;corrupts dx
|
||
pop dx
|
||
add bx,ax ;update buffer address
|
||
|
||
whole_trk:
|
||
mov al,dpb_phy_disk[si]
|
||
and al,0fh
|
||
or al,20h ;read
|
||
cmp write_req,0
|
||
je is_read
|
||
xor al,50h XOR 20h ;write + verify
|
||
|
||
is_read:
|
||
test dpb_flags[si],bit4
|
||
jnz rw_winch
|
||
callf flopall
|
||
mov cl,false
|
||
jnz first_err
|
||
ret
|
||
|
||
rw_winch:
|
||
add dx,dpb_part_offset[si] ;add partition offset
|
||
callf hdsk_all
|
||
mov cl,true
|
||
jnz first_err
|
||
ret
|
||
|
||
first_err: ;code here to give error, wait for key
|
||
;and repeat or exit with error
|
||
;CL is true if hard disc
|
||
call print_err ;print error type here
|
||
|
||
repeat:
|
||
call flush
|
||
mov bx,offset retry_msg
|
||
call pmsg
|
||
|
||
call conin ;get response
|
||
push ax
|
||
mov cl,al ;echo it
|
||
call conout
|
||
mov cl,cr ;print <CR>
|
||
call conout
|
||
pop ax
|
||
and al,5fh ;check for Y/N
|
||
cmp al,'Y'
|
||
jne repeat1
|
||
mov bx,offset crlf
|
||
call pmsg
|
||
jmps rw_retry ;retry if "Y"
|
||
|
||
repeat1:
|
||
cmp al,'N'
|
||
jne repeat
|
||
|
||
IF NOT loader_bios
|
||
;----------------------------------------
|
||
;| |
|
||
call z80_abort
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
or al,0ffh
|
||
ret
|
||
|
||
; Print first part of disc error message
|
||
; Called from INIT and PRINT_ERR
|
||
; CL is true if was a hard disc error
|
||
|
||
print_error:
|
||
push ax
|
||
push cx
|
||
mov bx,offset crlf
|
||
call pmsg
|
||
pop cx
|
||
pop ax
|
||
push ax
|
||
and al,0f8h ;mask off retry count
|
||
mov bx,offset floppy_error_tab
|
||
cmp cl,true
|
||
jne error_scan ;if floppy
|
||
mov bx,offset hd_error_tab_1
|
||
cmp al,78h
|
||
jnz error_scan ;if hard disc handshake error
|
||
mov bx,offset hd_error_tab_2
|
||
mov al,ah ;controller gave error code
|
||
and al,3fh
|
||
|
||
error_scan:
|
||
cmp al,[bx]
|
||
jz got_error
|
||
cmp byte ptr [bx], -1
|
||
jz got_error
|
||
add bx,3
|
||
jmps error_scan
|
||
|
||
got_error:
|
||
mov bx,1[bx] ;get address of error text
|
||
call pmsg
|
||
|
||
mov bx,offset err_msg1 ;print ' Error ('
|
||
call pmsg
|
||
|
||
pop ax
|
||
call print_ax_hex
|
||
|
||
mov bx,offset err_msg2 ;print 'H) '
|
||
call pmsg
|
||
ret
|
||
|
||
; Print full error message
|
||
; CL is true if hard disc
|
||
|
||
print_err:
|
||
call print_error
|
||
cmp write_req,0
|
||
mov bx,offset write_msg
|
||
jnz writing
|
||
mov bx,offset read_msg
|
||
writing:
|
||
call pmsg ;print 'writ' or 'read'
|
||
|
||
mov bx,offset drive_msg ;print 'ing drive '
|
||
call pmsg
|
||
|
||
mov al,hst_disk
|
||
add al,'A'
|
||
mov cl,al
|
||
call conout
|
||
ret
|
||
|
||
flush:
|
||
call const
|
||
test al,al
|
||
jz end_flush
|
||
call conin
|
||
jmp flush
|
||
|
||
end_flush:
|
||
preturn:
|
||
ret
|
||
|
||
|
||
; Print message at CS:BX until zero terminator found
|
||
|
||
pmsg:
|
||
mov cl,cs:[bx]
|
||
inc bx
|
||
test cl,cl
|
||
jz preturn
|
||
call conout
|
||
jmp pmsg
|
||
|
||
|
||
print_ax_hex:
|
||
push ax
|
||
mov al,ah
|
||
call print_al_hex
|
||
pop ax
|
||
print_al_hex:
|
||
push ax
|
||
mov cl,4
|
||
shr al,cl
|
||
call print_al_nib
|
||
pop ax
|
||
print_al_nib:
|
||
and al,15
|
||
add al,'0'
|
||
cmp al,'9'
|
||
jbe pnib1
|
||
add al,'A'-'0'-10
|
||
pnib1:
|
||
mov cl,al
|
||
call conout
|
||
ret
|
||
|
||
|
||
;*** CP/M entry codes for disk r/w **
|
||
|
||
wr_all equ 0 ;write allocated
|
||
wr_dir equ 1 ;write directory - forced physical write
|
||
wr_ual equ 2 ;write unallocated
|
||
|
||
|
||
change_msg db bell,cr,lf,'Disc has wrong number of sides',0
|
||
|
||
|
||
|
||
|
||
|
||
err_msg1 db ' Error (',0
|
||
|
||
err_msg2 db 'H) ',0
|
||
retry_msg db cr,lf,'Retry (Y/N) ?',0
|
||
|
||
|
||
read_msg db 'read',0
|
||
write_msg db 'writ',0
|
||
drive_msg db 'ing drive ',0
|
||
|
||
|
||
floppy_error_tab:
|
||
db 10h ! dw err1
|
||
db 20h ! dw err2
|
||
db 30h ! dw err3
|
||
db 38h ! dw err4
|
||
db 40h ! dw err5
|
||
db 50h ! dw err6
|
||
db 60h ! dw err7
|
||
db 70h ! dw err8
|
||
db 80h ! dw err9
|
||
db 90h ! dw err10
|
||
db 0a0h ! dw err11
|
||
db 0b0h ! dw err3
|
||
db -1 ! dw err0
|
||
|
||
hd_error_tab_1:
|
||
db 08h ! dw err12
|
||
db 10h ! dw err12
|
||
db 18h ! dw err12
|
||
db 20h ! dw err12
|
||
db 28h ! dw err12
|
||
db 48h ! dw err13
|
||
db 70h ! dw err8
|
||
db 80h ! dw err9
|
||
db -1 ! dw err0
|
||
|
||
hd_error_tab_2:
|
||
db 01h ! dw err14
|
||
db 02h ! dw err15
|
||
db 03h ! dw err16
|
||
db 04h ! dw err17
|
||
db 06h ! dw err4
|
||
db 10h ! dw err2
|
||
db 11h ! dw err7
|
||
db 12h ! dw err18
|
||
db 14h ! dw err5
|
||
db 15h ! dw err1
|
||
db 19h ! dw err19
|
||
db -1 ! dw err0
|
||
|
||
|
||
err1 db 'Seek',0
|
||
err2 db 'ID CRC',0
|
||
|
||
err3 db 'Write Protect',0
|
||
|
||
|
||
err4 db 'No Trk 00',0
|
||
|
||
err5 db 'Record Not Found',0
|
||
|
||
|
||
err6 db 'Lost Data',0
|
||
|
||
err7 db 'Data CRC',0
|
||
|
||
err8 db 'DMA',0
|
||
err9 db 'Busy',0
|
||
err10 db 'Sector out of range',0
|
||
|
||
|
||
|
||
err11 db 'Bank Cross',0
|
||
|
||
err12 db 'Handshake',0
|
||
|
||
err13 db 'Error Enquiry',0
|
||
|
||
|
||
err14 db 'No Index',0
|
||
|
||
err15 db 'No Seek Complete',0
|
||
|
||
|
||
err16 db 'Write Fault',0
|
||
|
||
err17 db 'Drive Not Ready',0
|
||
|
||
|
||
err18 db 'No Address Mark',0
|
||
|
||
|
||
err19 db 'Bad Track Flag',0
|
||
|
||
|
||
err0 db 'Unknown',0
|
||
|
||
|
||
crlf db cr,lf,0
|
||
|
||
|
||
IF NOT loader_bios
|
||
;------------------------------------------------
|
||
;| |
|
||
|
||
; Code to run 8-bit CP/M applications
|
||
|
||
; Enter here when CCP is about to look for .CMD file
|
||
|
||
cmd_chk:
|
||
push dx
|
||
call z80_abort
|
||
pop dx
|
||
|
||
call ccp_open ; this replaces code patched
|
||
je com_chk ; if .CMD file not found
|
||
jmp ccp_cmd ; back to ccp to load .CMD file
|
||
|
||
com_chk:
|
||
|
||
; check for SAVE command
|
||
|
||
mov si,offset ccp_file+1
|
||
mov di,offset save_tx
|
||
mov cx,5
|
||
cld
|
||
repe cmps al,al
|
||
je save_0
|
||
jmp com_chk_0
|
||
|
||
; SAVE command - save contents of z80 bank
|
||
|
||
save_0:
|
||
call parse_tail
|
||
mov ds,mcb_base ; get bank
|
||
mov si,offset zfcb_1+1 ; ready to get no of pages
|
||
xor ah,ah
|
||
save_1:
|
||
mov al,[si]
|
||
sub al,'0'
|
||
jb save_error
|
||
cmp al,9
|
||
ja save_error
|
||
inc si
|
||
add al,ah
|
||
cmp byte ptr [si],' '
|
||
je save_2
|
||
cmp al,20
|
||
ja save_error
|
||
mov cl,10
|
||
mul cl
|
||
mov ah,al
|
||
jmps save_1
|
||
|
||
save_2:
|
||
mov cs:save_pages,al
|
||
|
||
; create save file
|
||
|
||
mov dx,offset zfcb_2
|
||
push dx
|
||
mov cl,19 ;delete old file
|
||
int 224
|
||
pop dx
|
||
mov cl,22
|
||
int 224 ;make file
|
||
test al,al
|
||
js save_error
|
||
mov bx,offset zfcb_2
|
||
mov byte ptr 12[bx],0 ;initialise extent no.
|
||
mov byte ptr 32[bx],0 ;initialise current record
|
||
mov dx,ds
|
||
mov cl,51
|
||
int 224 ;set DMA segment
|
||
mov dx,0100h ;initial DMA offset
|
||
mov cl,cs:save_pages
|
||
mov ch,0
|
||
add cx,cx
|
||
save_3:
|
||
push cx
|
||
push dx
|
||
mov cl,26
|
||
int 224 ;set DMA offset
|
||
mov dx,offset zfcb_2
|
||
mov cl,21
|
||
int 224 ;write sequential
|
||
pop dx
|
||
pop cx
|
||
test al,al
|
||
jne save_error
|
||
add dx,080h
|
||
loop save_3
|
||
|
||
; close file
|
||
|
||
mov dx,offset zfcb_2
|
||
mov cl,16
|
||
int 224
|
||
|
||
; end of SAVE
|
||
|
||
mov bx,offset save_ok_tx
|
||
jmps end_of_save
|
||
|
||
save_error:
|
||
mov bx,offset save_error_tx
|
||
end_of_save:
|
||
mov ax,cs
|
||
mov ds,ax
|
||
mov es,ax
|
||
call pmsg
|
||
jmp back_2_ccp
|
||
|
||
|
||
com_chk_0:
|
||
mov ccp_file_type,'MO'
|
||
mov dx,offset ccp_file
|
||
call ccp_open ; open .com file
|
||
jne com_chk_1
|
||
jmp ccp_error ; not found
|
||
|
||
com_chk_1:
|
||
mov bx,offset crlf
|
||
call pmsg
|
||
cmp z80_flag,0
|
||
jne got_bank ; if have mem from last time
|
||
mov mcb_base,1000h ; get a bank to run cpm in
|
||
get_bank:
|
||
mov dx,offset mcb_base
|
||
mov cl,38h
|
||
push es
|
||
int 224 ; attempt to allocate memory
|
||
pop es
|
||
test al,al
|
||
jz got_bank
|
||
add mcb_base,1000h ; failed to get bank, try next
|
||
cmp mcb_base,4000h ; but not past 4
|
||
jne get_bank
|
||
mov bx,offset no_bank_message
|
||
call pmsg
|
||
call ccp_cleanup
|
||
jmp back_2_ccp ; go back to cpm86
|
||
|
||
got_bank:
|
||
mov z80_flag,1 ; memory allocated,not executing yet
|
||
mov byte ptr ccp_file_rec,0 ; zero record count + extent in cpm80
|
||
mov byte ptr ccp_file_ext,0 ; fcb to be loaded
|
||
mov cl,33h ; set dma segment
|
||
mov dx,mcb_base ; to z80 bank
|
||
int 224
|
||
|
||
mov dx,0100h ; to 80h
|
||
red:
|
||
push dx
|
||
mov cl,1ah ; set dma
|
||
int 224
|
||
|
||
mov cl,14h
|
||
mov dx,offset ccp_file
|
||
int 224 ; read .com file sequentially
|
||
pop dx
|
||
cmp al,01
|
||
je eof ; got to end
|
||
add dx,128 ; increment dma address
|
||
cmp dx,0f800h ; make sure less than 64k read
|
||
jb red
|
||
mov bx,offset com_2_big
|
||
call pmsg
|
||
call ccp_cleanup
|
||
jmp dealloc_exit ; de-allocate & exit
|
||
|
||
eof:
|
||
mov ax,mcb_base ; z80 bank
|
||
cli ; disable keybd int
|
||
mov kstat_ptr_seg,ax
|
||
mov kstat_ptr_off,offset kstat_80 ;offset of kstat 80 (z80 bank)
|
||
mov iobyte_ptr_seg,ax
|
||
mov iobyte_ptr_off,offset iobyte_80
|
||
sti
|
||
|
||
mov z80_flag,2
|
||
call set_kstat
|
||
|
||
call ccp_cleanup ; reset default disc
|
||
mov cl,19h
|
||
int 224 ; get current(default) disc
|
||
mov def_drive_tmp,al ; to Z80
|
||
|
||
call parse_tail
|
||
mov bx,offset copy_table
|
||
call copy ; copy all to Z80 bank
|
||
|
||
mov cl,1ah ; set dma address
|
||
mov dx,080h
|
||
int 224
|
||
|
||
mov ax,mcb_base
|
||
mov cl,4
|
||
shr ah,cl
|
||
mov al,ah
|
||
out 30h,al
|
||
|
||
|
||
; loop on function call
|
||
; Wait for function to process
|
||
|
||
push es
|
||
mov z80_flag,3 ; z80 now executing
|
||
|
||
poll:
|
||
mov es,mcb_base
|
||
mov es:fncode,0
|
||
|
||
out 38h,al ;start Z80 mode
|
||
nop
|
||
mov bl,es:byte ptr fncode
|
||
mov bh,0
|
||
call word ptr jumptab[bx] ; Process function
|
||
jmps poll
|
||
|
||
; return here at end of z80 prog
|
||
|
||
end_cpm_80:
|
||
pop es
|
||
mov z80_flag,2
|
||
call z80_abort
|
||
|
||
mov cl,0
|
||
mov dl,1
|
||
int 224 ; warm boot : normal end
|
||
|
||
dealloc_exit:
|
||
call z80_abort ; exit here if program load failed
|
||
|
||
back_2_ccp:
|
||
jmp ccp_exit ; exit here if alllocation failed
|
||
|
||
|
||
; Use ccp code to process command line tail
|
||
parse_tail:
|
||
mov al,byte ptr ccp_parse_patch ; save patch contents
|
||
push ax
|
||
mov byte ptr ccp_parse_patch,0c3h ; insert ret
|
||
mov bx,mcb_base ; set bx = cpm80 bank
|
||
call ccp_parse ; parse command line
|
||
; to fcb1/2 in 80 bank
|
||
pop ax
|
||
mov byte ptr ccp_parse_patch,al ; un-patch it.
|
||
mov byte ptr com_desc,0 ; reset descriptor
|
||
ret
|
||
|
||
|
||
; copy copies according to a table at [bx].
|
||
; each entry is 3 words long.
|
||
; word 1 = source offset (in this segment, i.e. 0100h)
|
||
; word 2 = destination offset (in z80 segment)
|
||
; word 3 = number of bytes to copy (0 = end of table)
|
||
|
||
copy:
|
||
push es ;save es
|
||
mov ax,mcb_base ; get the z80 bank
|
||
mov es,ax ; to es
|
||
cld
|
||
|
||
more_copy:
|
||
mov si,[bx] ; from in si
|
||
mov di,2[bx] ; to in di
|
||
mov cx,4[bx] ; no words
|
||
cmp cx,0 ; end of table?
|
||
jz end_copy
|
||
rep movs al,al ; move
|
||
add bx,6
|
||
jmps more_copy
|
||
|
||
end_copy:
|
||
pop es
|
||
ret
|
||
|
||
|
||
set_kstat_ptr:
|
||
cli
|
||
mov kstat_ptr_off,offset kstat_86
|
||
mov kstat_ptr_seg,cs
|
||
sti
|
||
call set_kstat
|
||
ret
|
||
|
||
|
||
; Abort Z80 if it is running and deallocate its memory
|
||
|
||
z80_abort:
|
||
cmp z80_flag,3 ; z80 running ?
|
||
jne z80_abort_1 ; if no
|
||
|
||
dec z80_flag
|
||
push ds
|
||
mov ds,mcb_base
|
||
abort_lp_2:
|
||
mov byte ptr z80_nmi,jump
|
||
mov word ptr z80_nmi+1,0
|
||
mov al,1*2 ; clear bit 1 to pulse NMI low
|
||
out ptr_flag,al
|
||
mov fncode,0
|
||
mov al,1*2+1
|
||
out ptr_flag,al ; reset NMI high
|
||
abort_loop:
|
||
out 38h,al ; enable z80
|
||
cmp fncode,0
|
||
jz abort_loop
|
||
cmp fncode,4 ; wait for warm boot request
|
||
jne abort_lp_2
|
||
pop ds
|
||
|
||
z80_abort_1:
|
||
cmp z80_flag,2
|
||
jne z80_abort_2
|
||
|
||
dec z80_flag
|
||
call set_kstat_ptr
|
||
mov iobyte_ptr_seg,cs
|
||
mov iobyte_ptr_off,offset iobyte
|
||
push es
|
||
mov es,mcb_base
|
||
mov cl,es:iobyte_80
|
||
pop es
|
||
call setiob
|
||
|
||
z80_abort_2:
|
||
cmp z80_flag,1
|
||
jne z80_abort_ret
|
||
|
||
dec z80_flag
|
||
mov mcb_ext,0
|
||
mov cl,39h
|
||
mov dx,offset mcb_base
|
||
push es
|
||
int 224
|
||
pop es
|
||
|
||
z80_abort_ret:
|
||
ret
|
||
|
||
; Routine to set kstat
|
||
; All registers except flags preserved
|
||
|
||
set_kstat:
|
||
push ax
|
||
push bx
|
||
push ds
|
||
lds bx,kstat_ptr
|
||
|
||
cli
|
||
mov al,cs:byte ptr kbuf_get_ptr
|
||
xor al,cs:byte ptr kbuf_put_ptr
|
||
jz kbuf_empty
|
||
mov al,-1
|
||
kbuf_empty:
|
||
mov byte ptr [bx],al
|
||
sti
|
||
|
||
pop ds
|
||
pop bx
|
||
pop ax
|
||
ret
|
||
|
||
|
||
no_bank_message db 'No bank available to run CP/M-80',cr,lf,0
|
||
|
||
|
||
|
||
|
||
|
||
com_2_big db '.COM file too large !',cr,lf,0
|
||
|
||
|
||
|
||
|
||
|
||
|
||
;Order of parms in list:
|
||
; Flags - only stored, not loaded
|
||
; AX
|
||
; BX
|
||
; CX
|
||
; DX
|
||
; SI
|
||
; DI
|
||
; BP
|
||
; DS
|
||
; ES not loaded so we know where Z80 is running
|
||
|
||
ESC8088:
|
||
push ds ;these need to be saved
|
||
push es
|
||
|
||
mov ax,es:desav
|
||
mov esc_addr,ax
|
||
mov word ptr esc_addr+2,es
|
||
|
||
mov bx,es:bcsav
|
||
mov ax,es:2[bx]
|
||
push es:word ptr 4[bx]
|
||
mov cx,es:6[bx]
|
||
mov dx,es:8[bx]
|
||
mov si,es:10[bx]
|
||
mov di,es:12[bx]
|
||
mov bp,es:14[bx]
|
||
mov ds,es:16[bx]
|
||
pop bx
|
||
|
||
push es
|
||
callf cs:dword ptr esc_addr
|
||
pop es
|
||
|
||
push bx
|
||
mov bx,cs:mcb_base
|
||
mov es,bx
|
||
|
||
mov bx,es:bcsav
|
||
pushf
|
||
pop es:word ptr [bx] ;flags
|
||
mov es:2[bx],ax
|
||
mov es:6[bx],cx
|
||
mov es:8[bx],dx
|
||
mov es:10[bx],si
|
||
mov es:12[bx],di
|
||
mov es:14[bx],bp
|
||
mov es:16[bx],ds
|
||
pop es:word ptr 4[bx] ;bx
|
||
|
||
pop es
|
||
pop ds
|
||
exitint:
|
||
ret
|
||
|
||
zerror:
|
||
mov bx,offset duf_bios_call
|
||
call pmsg
|
||
jmp zwboot
|
||
|
||
duf_bios_call db cr,lf,'Unsupported direct bios call',cr,lf,0
|
||
|
||
zconst:
|
||
call const ; get console status
|
||
test al,al
|
||
jz zconst1 ; 0 = no char
|
||
mov al,0ffh ;-86 = 01 for char: change to ff for -80
|
||
zconst1:
|
||
mov es:asav,al
|
||
ret
|
||
|
||
zconin:
|
||
call conin
|
||
mov es:asav,al
|
||
ret
|
||
|
||
zconout:
|
||
mov cl,es:csav
|
||
jmp conout
|
||
|
||
zlist:
|
||
mov cl,es:csav
|
||
jmp listout
|
||
|
||
zpunch:
|
||
mov cl,es:csav
|
||
jmp punch
|
||
|
||
zreader:
|
||
call reader
|
||
mov es:asav,al
|
||
ret
|
||
|
||
zlistst:
|
||
call listst
|
||
mov es:asav,al
|
||
ret
|
||
|
||
RDKTAB:
|
||
push ds
|
||
xor si,si
|
||
mov ds,si ; table is in seg 0
|
||
mov si,offset keytab
|
||
mov di,es:hlsav
|
||
mov cx,512 /2
|
||
cld
|
||
rep movs ax,ax
|
||
pop ds
|
||
ret
|
||
|
||
WRKTAB:
|
||
push es ;save regs
|
||
push ds
|
||
xor si,si
|
||
mov ds,si
|
||
mov di,offset keytab
|
||
mov si,es:hlsav
|
||
push es ;xchg es,ds
|
||
push ds
|
||
pop es
|
||
pop ds
|
||
mov cx,512 /2
|
||
cld
|
||
rep movs ax,ax
|
||
pop ds ;restore regs
|
||
pop es
|
||
ret
|
||
|
||
WRFONT1:
|
||
mov di,1000h
|
||
jmp wrfnt
|
||
WRFONT2:
|
||
mov di,1800h
|
||
wrfnt:
|
||
push es
|
||
push ds
|
||
mov si,es:hlsav
|
||
push es ;xchg es,ds
|
||
push ds
|
||
pop es
|
||
pop ds
|
||
mov cx,0fc00h
|
||
mov es,cx
|
||
mov bx,8 ;8 passes
|
||
wt_v_end:
|
||
in al,crt_stat
|
||
test al,bit5
|
||
jnz wt_v_end
|
||
|
||
wt_v_start:
|
||
in al,crt_stat
|
||
test al,bit5
|
||
jz wt_v_start
|
||
|
||
mov cx,1024 /8 ;1/8 of 2K in words
|
||
rep movs ax,ax
|
||
|
||
dec bx
|
||
jnz wt_v_end
|
||
|
||
mov al,31
|
||
out crt_addr,al
|
||
|
||
pop ds
|
||
pop es
|
||
ret
|
||
|
||
|
||
zwboot:
|
||
pop bx
|
||
jmp end_cpm_80
|
||
|
||
|
||
PORTIN: ;read from port C , data into reg A
|
||
mov dl,es:csav
|
||
mov dh,0
|
||
in al,dx
|
||
mov es:asav,al
|
||
ret
|
||
|
||
PORTOUT: ;write to port C , data in reg B
|
||
mov ax,es:bcsav
|
||
mov dl,al
|
||
mov dh,0
|
||
mov al,ah
|
||
out dx,al
|
||
ret
|
||
|
||
zbdos:
|
||
mov cl,es:csav
|
||
mov dx,es:desav
|
||
cmp cl,6
|
||
jz zbdos6
|
||
cmp cl,27
|
||
jz zbdos27
|
||
cmp cl,31
|
||
jz zbdos31
|
||
zbdos0:
|
||
push ds
|
||
push es
|
||
pop ds
|
||
int 224
|
||
push ds
|
||
pop es
|
||
pop ds
|
||
|
||
zbdos_end:
|
||
mov es:hlsav,ax
|
||
ret
|
||
|
||
zbdos6:
|
||
cmp dl,0fdh ; console input (like MPM-II) ?
|
||
jz zbdos6a
|
||
cmp dl,0feh ; console status ?
|
||
jz zbdos6b
|
||
cmp dl,0ffh ; console input/status request?
|
||
jz zbdos6c
|
||
mov cl,dl
|
||
call conout
|
||
ret
|
||
|
||
zbdos6c:
|
||
call const
|
||
test al,al
|
||
jz zbdos_end ; if no character available
|
||
zbdos6a:
|
||
call conin
|
||
jmps zbdos_end
|
||
|
||
zbdos6b:
|
||
call const
|
||
jmps zbdos_end
|
||
|
||
zbdos27:
|
||
mov di,offset zalloc
|
||
mov ax,256 ;largest alloc vector is 512 bytes
|
||
jmps zbdos31a
|
||
|
||
zbdos31:
|
||
mov di,offset mfcb_a
|
||
mov ax,8 ;count of bytes
|
||
zbdos31a:
|
||
push di ;save destination offset
|
||
push ax ;save count
|
||
push es
|
||
int 224
|
||
mov ax,es
|
||
pop es
|
||
pop cx ;count to cx
|
||
pop di
|
||
push ds
|
||
mov ds,ax
|
||
mov si,bx
|
||
mov ax,di
|
||
cld
|
||
rep movs ax,ax
|
||
pop ds
|
||
jmps zbdos_end
|
||
|
||
bdos6:
|
||
mov cl,6
|
||
bdos:
|
||
push es
|
||
int 224
|
||
pop es
|
||
ret
|
||
;| |
|
||
;------------------------------------------------
|
||
ENDIF ;not loader_bios
|
||
|
||
;***********************************************************************
|
||
|
||
; Data areas
|
||
|
||
data_offset equ offset $
|
||
|
||
dseg
|
||
org data_offset
|
||
|
||
IF NOT loader_bios
|
||
;---------------------------------------------
|
||
;| |
|
||
|
||
divide_error_tx db cr,lf,'*** Divide overflow - execution terminated',cr,lf,0
|
||
int_trap_tx db cr,lf,'*** Uninitialised interrupt - execution terminated',cr,lf,0
|
||
save_tx db 'SAVE '
|
||
save_ok_tx db cr,lf,'Save complete.',0
|
||
save_error_tx db cr,lf,'Error in SAVE command or disc full.',0
|
||
writepending_tx db cr,lf,'*** Error - disc logged in has write pending!',cr,lf,0
|
||
|
||
submit_txt db 'submit autoexec',cr+bit7
|
||
|
||
;| |
|
||
;---------------------------------------------
|
||
ENDIF ;not loader_bios
|
||
|
||
unrecd_tx db cr,lf,'System not recognized',0
|
||
|
||
;*** Variables here can be accessed by utilities, using BIOS GETSEGT call ***
|
||
|
||
;*** System Memory Segment Table ***
|
||
|
||
segtable db 1 ;1 active segment out of 8 maximum
|
||
seg_start dw 0 ;1st seg starts after BIOS
|
||
seg_len dw 4000h ;and extends to 40000h (256K)
|
||
rw 2*7 ;reserve space for 7 more regions
|
||
|
||
xlt26:
|
||
db 0,6,12,18,24,4,10,16,22,2,8,14,20
|
||
db 1,7,13,19,25,5,11,17,23,3,9,15,21
|
||
|
||
;*** M4 specific variables - values inserted depend on configuration ***
|
||
|
||
;*** Disk parameter headers - values inserted depend on configuration ***
|
||
;*** Header format : xlt, scr, scr, scr, dirbuf, dpb, csv, alv ***
|
||
|
||
DPBASE EQU $ ;Base of disk parameter table
|
||
|
||
;Header here for drive A
|
||
DPH_A DW 0,0,0,0, offset dirbuf , offset dpb_A ,0,0
|
||
|
||
;Header here for drive B
|
||
DPH_B DW 0,0,0,0, offset dirbuf , offset dpb_B ,0,0
|
||
|
||
;Header here for drive C
|
||
DPH_C DW 0,0,0,0, offset dirbuf , offset dpb_C ,0,0
|
||
|
||
;Header here for drive D
|
||
DPH_D DW 0,0,0,0, offset dirbuf , offset dpb_D ,0,0
|
||
|
||
dph_e dw 0,0,0,0, offset dirbuf, offset dpb_e, 0,0
|
||
|
||
IF not loader_bios
|
||
;---------------------------------------------------
|
||
;| |
|
||
; Data to be copied to z80 bank prior to running cpm80 programs
|
||
|
||
copy_table dw offset iobyte ; from offset in ds
|
||
dw offset iobyte_80 ; to offset in z80 bank
|
||
dw 1 ; number of words to copy
|
||
|
||
dw offset def_drive_tmp
|
||
dw offset def_drive
|
||
dw 1
|
||
|
||
dw offset mbios ; copy z80 code
|
||
dw offset bios_80
|
||
dw offset z80_end_bios - offset mbios
|
||
|
||
dw offset tmp_jmp ; set up temp jump
|
||
dw offset bios_jmp
|
||
dw 3
|
||
|
||
dw offset bdos_jmp_80
|
||
dw offset bdos_jmp
|
||
dw 3
|
||
|
||
dw offset mbdos
|
||
dw offset bdos_80
|
||
dw offset z80_end_bdos - offset mbdos
|
||
|
||
dw 0 ; Hard stopper block
|
||
dw 0
|
||
dw 0
|
||
|
||
def_drive_tmp db 0
|
||
tmp_jmp db jump ; first time at cpm loc 0
|
||
dw offset put_bios_jmp - offset mbios + offset bios_80
|
||
|
||
bdos_jmp_80 db jump
|
||
dw offset bdos_80
|
||
|
||
esc_addr rw 2
|
||
|
||
|
||
; all 'zerror' entries are illegal direct bios calls
|
||
jumptab:
|
||
dw exitint ;exit after an interrupt
|
||
dw zerror ;this will be endcpm function call
|
||
dw zwboot ;arrive here for warm boot
|
||
dw zconst ;check for console char ready
|
||
dw zconin ;read console character in
|
||
;10
|
||
dw zconout ;write console character out
|
||
dw zlist ;write listing character out
|
||
dw zpunch ;punch
|
||
dw zreader ;read reader
|
||
dw zerror ;move to track 00
|
||
;20
|
||
dw zerror ;select disc driv
|
||
dw zerror ;set track number
|
||
dw zerror ;set sector number (eg 1-8)
|
||
dw zerror ;set dma address
|
||
dw zerror ;read selected secto
|
||
;30
|
||
dw zerror ;write selected sector
|
||
dw zlistst ;return list status
|
||
dw zerror ;sector translate subroutine
|
||
dw exitint ;dummy XIOS functions for MP/M compatability
|
||
dw exitint
|
||
;40
|
||
dw exitint
|
||
dw exitint
|
||
dw exitint
|
||
dw exitint
|
||
dw exitint
|
||
;50
|
||
dw exitint
|
||
dw exitint
|
||
dw exitint
|
||
dw exitint
|
||
dw exitint
|
||
;60
|
||
dw exitint
|
||
dw zwboot ;end CP/M function call
|
||
dw portin ;input character from port C
|
||
dw portout ;output char in B to port C
|
||
dw rdktab ;read 512 bytes of keytab to (HL)
|
||
;70
|
||
dw wrktab ;write 512 bytes from (HL) to keytab
|
||
dw esc8088 ;8088 escape routine at (HL:DE), parms at (BC)
|
||
dw wrfont1 ;write 2048 bytes at (HL) to font ram 1
|
||
dw wrfont2 ;write 2048 bytes at (HL) to font ram 2
|
||
dw exitint ;set/reset drive logging
|
||
;80
|
||
dw zbdos
|
||
dw zerror
|
||
dw exitint
|
||
dw exitint
|
||
dw exitint
|
||
;90
|
||
dw exitint ;only got limited amount of space
|
||
dw exitint ;so only allow max of 48 functions
|
||
dw exitint ;ie code 0-94
|
||
|
||
;
|
||
; Below is the skeletal BIOS which will be moved to Z80 bank
|
||
; This BIOS will transfer function calls back to the 8088
|
||
;
|
||
jump equ 0c3h
|
||
lda equ 3ah
|
||
sta equ 32h
|
||
lhld equ 2ah
|
||
shld equ 22h
|
||
movac equ 79h
|
||
movca equ 4fh
|
||
movad equ 7ah
|
||
movhb equ 60h
|
||
movlc equ 69h
|
||
movlm equ 6eh
|
||
movbh equ 44h
|
||
moval equ 7dh
|
||
lxib equ 01h
|
||
lxisp equ 31h
|
||
lxih equ 21h
|
||
dadb equ 09h
|
||
mvia equ 3eh
|
||
mvih equ 26h
|
||
ani equ 0e6h
|
||
orae equ 0b3h
|
||
jrz equ 28h
|
||
rz equ 0c8h
|
||
exdehl equ 0ebh
|
||
pushh equ 0e5h
|
||
oraa equ 0b7h
|
||
jumpz equ 0cah
|
||
retun equ 0c9h
|
||
znop equ 00h
|
||
|
||
mbios:
|
||
db jump ;Z80 jmp
|
||
dw (offset mcboot - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mwboot - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mconst - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mconin - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mconout - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mlist - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mpunch - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mreader - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mhome - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mseldsk - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset msettrk - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset msetsec - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset msetdma - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mread - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mwrite - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mlistst - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset msectran - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mwboot - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mportin - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mportout - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mrdktab - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mwrktab - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mesc8088 - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mwrfont1 - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mwrfont2 - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
db jump ;Z80 jmp
|
||
dw (offset mempty - offset mbios) + offset bios_80
|
||
|
||
mcboot:
|
||
mwboot:
|
||
db mvia,4
|
||
mwboot1:
|
||
db sta
|
||
dw fncode
|
||
db 0dbh,50h,0
|
||
db jump
|
||
dw 0000
|
||
|
||
mconst:
|
||
db lda ;Z80 ld a,(iobyte)
|
||
dw offset iobyte
|
||
db ani,3 ;Z80 and a,3
|
||
|
||
db jrz,4 ;Z80 jr z,$+4
|
||
|
||
db lda ;Z80 ld a,(kstat_80)
|
||
dw offset kstat_80
|
||
|
||
db retun ;Z80 ret
|
||
|
||
db mvia,6 ;Z80 ld a,6
|
||
|
||
db sta ;Z80 ld (fncode),a
|
||
dw fncode
|
||
|
||
db 0dbh,50h,0 ;Z80 in a,(50h) ; nop
|
||
|
||
db lda ;Z80 ld a,(asav)
|
||
dw asav
|
||
|
||
db retun ;Z80 ret
|
||
|
||
mconin:
|
||
db mvia,8 ;Z80 ld a,8
|
||
|
||
db sta ;Z80 ld (fncode),a
|
||
dw fncode
|
||
|
||
db 0dbh,50h,0 ;Z80 in a,(50h) ; nop
|
||
|
||
db lda ;Z80 ld a,(asav)
|
||
dw asav
|
||
|
||
db retun ;Z80 ret
|
||
|
||
mconout:
|
||
db movac ;Z80 ld a,c
|
||
|
||
db sta ;Z80 ld csav,a
|
||
dw csav
|
||
|
||
db mvia,10 ;Z80 ld a,10
|
||
|
||
db sta ;Z80 ld (fncode),a
|
||
dw fncode
|
||
|
||
db 0dbh,50h,0 ;Z80 in a,(50h) ; nop
|
||
|
||
db retun ;Z80 ret
|
||
|
||
mlist:
|
||
db movac ;Z80 ld a,c
|
||
db sta ;Z80 ld csav,a
|
||
dw csav
|
||
|
||
db mvia,12 ;Z80 ld a,12
|
||
|
||
db sta ;Z80 ld (fncode),a
|
||
dw fncode
|
||
|
||
db 0dbh,50h,0 ;Z80 in a,(50h) ; nop
|
||
|
||
db retun ;Z80 ret
|
||
|
||
mpunch:
|
||
db movac ;Z80 ld a,c
|
||
|
||
db sta ;Z80 ld csav,a
|
||
dw csav
|
||
|
||
db mvia,14 ;Z80 ld a,14
|
||
|
||
db sta ;Z80 ld (fncode),a
|
||
dw fncode
|
||
|
||
db 0dbh,50h,0 ;Z80 in a,(50h) ; nop
|
||
|
||
db retun ;Z80 ret
|
||
|
||
mreader:
|
||
db mvia,16 ;Z80 ld a,16
|
||
|
||
db sta ;Z80 ld (fncode),a
|
||
dw fncode
|
||
|
||
db 0dbh,50h,0 ;Z80 in a,(50h) ; nop
|
||
|
||
db lda ;Z80 ld a,(asav)
|
||
dw asav
|
||
|
||
db retun ;Z80 ret
|
||
|
||
mhome:
|
||
mseldsk:
|
||
msettrk:
|
||
msetsec:
|
||
msetdma:
|
||
mread:
|
||
mwrite:
|
||
msectran:
|
||
db mvia,62
|
||
db jump
|
||
dw (offset mwboot1 - offset mbios) + offset bios_80
|
||
mportin:
|
||
db movac
|
||
db sta
|
||
dw csav
|
||
db mvia,64
|
||
db sta
|
||
dw fncode
|
||
db 0dbh,50h,0
|
||
db lda
|
||
dw asav
|
||
db retun
|
||
|
||
mportout:
|
||
db 0edh,043h ; ld (bcsav),bc
|
||
dw bcsav
|
||
db mvia,66
|
||
db sta
|
||
dw fncode
|
||
db 0dbh,50h,0
|
||
db retun
|
||
|
||
mrdktab:
|
||
db shld
|
||
dw hlsav
|
||
db mvia,68
|
||
db sta
|
||
dw fncode
|
||
db 0dbh,50h,0
|
||
db retun
|
||
|
||
mwrktab:
|
||
db shld
|
||
dw hlsav
|
||
db mvia,70
|
||
db sta
|
||
dw fncode
|
||
db 0dbh,50h,0
|
||
db retun
|
||
|
||
mlistst:
|
||
db mvia,32 ;Z80 ld a,32
|
||
|
||
db sta ;Z80 ld (fncode),a
|
||
dw fncode
|
||
|
||
db 0dbh,50h,0 ;Z80 in a,(50h) ; nop
|
||
|
||
db lda ;Z80 ld a,(asav)
|
||
dw asav
|
||
db retun ;Z80 ret
|
||
|
||
mesc8088:
|
||
db shld ;Z80 ld (hlsav),hl ;segment
|
||
dw hlsav
|
||
|
||
db 0edh,053h ;Z80 ld (desav),de ;offset
|
||
dw desav
|
||
|
||
db 0edh,043h ;Z80 ld (bcsav),bc ;parm list
|
||
dw bcsav
|
||
|
||
db mvia,72 ;Z80 ld a,72
|
||
|
||
db sta ;Z80 ld (fncode),a
|
||
dw fncode
|
||
|
||
db 0dbh,50h,0 ;Z80 in a,(50h) ; nop
|
||
|
||
db 0edh,04bh ;Z80 ld bc,(bcsav) ;parm list
|
||
dw bcsav
|
||
|
||
db lda ;Z80 ld a,(asav) ;status
|
||
dw asav
|
||
|
||
db retun ;Z80 ret
|
||
|
||
mwrfont1:
|
||
db shld ;Z80 ld (hlsav),hl
|
||
dw hlsav
|
||
|
||
db mvia,74 ;Z80 ld a,74
|
||
|
||
db sta ;Z80 ld (fncode),a
|
||
dw fncode
|
||
|
||
db 0dbh,50h,0 ;Z80 in a,(50h) ; nop
|
||
|
||
db retun ;Z80 ret
|
||
|
||
mwrfont2:
|
||
db shld ;Z80 ld (hlsav),hl
|
||
dw hlsav
|
||
|
||
db mvia,76 ;Z80 ld a,76
|
||
|
||
db sta ;Z80 ld (fncode),a
|
||
dw fncode
|
||
|
||
db 0dbh,50h,0 ;Z80 in a,(50h) ; nop
|
||
|
||
db retun ;Z80 ret
|
||
|
||
mempty:
|
||
db retun ;Z80 ret
|
||
|
||
|
||
put_bios_jmp:
|
||
db lxih
|
||
dw offset bios_80 + 3
|
||
db shld
|
||
dw 0001h
|
||
db lxisp ; set stack to top of TPA
|
||
dw offset z80_stack
|
||
db pushh
|
||
db jump
|
||
dw 0100h ; go execute program
|
||
|
||
z80_end_bios equ $
|
||
|
||
|
||
mbdos:
|
||
db movac
|
||
db oraa
|
||
db jumpz
|
||
dw 0000
|
||
|
||
db sta
|
||
dw csav
|
||
|
||
db 0edh,053h ; ld(desav),de
|
||
dw desav
|
||
db mvia,80 ; ld a,80
|
||
db sta
|
||
dw fncode
|
||
db 0dbh,50h,0
|
||
db lhld
|
||
dw hlsav
|
||
db movbh
|
||
db moval
|
||
db retun
|
||
|
||
z80_end_bdos equ $
|
||
|
||
;| |
|
||
;------------------------------------------------
|
||
ENDIF
|
||
|
||
;************************************************************
|
||
|
||
; initialised data space
|
||
|
||
mcb_base dw 1000h ; memory control block for z80
|
||
dw 1000h ; length 64k
|
||
mcb_ext dw 0
|
||
|
||
|
||
IOBYTE db 95h ; CON:=CRT:, LST:=LPT:
|
||
iobyte_ptr_off dw offset iobyte
|
||
iobyte_ptr_seg rw 1 ;filled in
|
||
iobyte_ptr equ dword ptr iobyte_ptr_off
|
||
|
||
xonxoff db xon
|
||
|
||
dma_adr dw 0 ; DMA offset from DS
|
||
dma_seg dw 0 ; DMA Base Segment
|
||
|
||
hst_disk db -1
|
||
hst_sect db 0
|
||
hst_trk dw 0
|
||
hst_dpb dw 0
|
||
|
||
req_disk db 0
|
||
req_sect db 0
|
||
req_trk dw 0
|
||
req_ofs db 0
|
||
|
||
write_flag db 0
|
||
write_type db 0
|
||
write_req db 0
|
||
|
||
;buffer_size dw 5 * 1024 ;5" value
|
||
|
||
|
||
IF not loader_bios
|
||
;----------------------------------------
|
||
;| |
|
||
|
||
fn_expand_flag db true
|
||
fn_expand_ptr dw offset submit_txt - 1 ;gets modified by INIT
|
||
|
||
kstat_86 db true
|
||
|
||
kstat_ptr_off dw offset kstat_86
|
||
kstat_ptr_seg rw 1
|
||
|
||
kstat_ptr equ dword ptr kstat_ptr_off
|
||
|
||
saved_ax rw 1
|
||
saved_ds rw 1
|
||
saved_bx rw 1 ;used by keyboard interrupt
|
||
|
||
ax_save_7 rw 1 ;used by level 7 interrupt
|
||
|
||
kbuf_get_ptr dw offset kbuf_start
|
||
kbuf_put_ptr dw offset kbuf_start
|
||
|
||
z80_flag db 0 ; 0 if 8088, 1 if z80 allocated,2 if running
|
||
save_pages rb 1 ; number of pages to SAVE
|
||
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
|
||
;************* end of initialised data
|
||
|
||
temp_data equ offset $
|
||
|
||
; data here is only needed at system startup
|
||
; so is overwritten by disc buffer etc.
|
||
|
||
|
||
IF loader_bios
|
||
;------------------------------------------------
|
||
;| |
|
||
|
||
avail_tab:
|
||
dw 0h, dpb_0,0, 0,0, 0,0, 0,0, 0,0 ;5" ss dd
|
||
dw 1h, dpb_1,0, 0,0, 0,0, 0,0, 0,0 ;5" ds dd
|
||
dw 2h, dpb_2,0, 0,0, 0,0, 0,0, 0,0 ;5" ss qd
|
||
dw 3h, dpb_3,0, 0,0, 0,0, 0,0, 0,0 ;5" ds qd
|
||
dw 4h, dpb_4,0, 0,0, 0,0, 0,0, 0,0 ;8" ss dd
|
||
dw 5h, dpb_5,0, 0,0, 0,0, 0,0, 0,0 ;8" ds dd
|
||
dw 8h, dpb_7,80h, 0,0, 0,0, 0,0, 0,0 ;Winchester
|
||
dw -1
|
||
|
||
;| |
|
||
;------------------------------------------------
|
||
ENDIF
|
||
|
||
IF (NOT loader_bios) AND (NOT special)
|
||
;------------------------------------------------
|
||
;| |
|
||
|
||
avail_tab:
|
||
dw 10h, dpb_0,0, dpb_0,1, 0,0, 0,0, 0,0 ;5" ss/dd + 5"ss/dd
|
||
|
||
|
||
|
||
dw 11h, dpb_1,0, dpb_1,1, dpb_0,1, 0,0, 0,0 ;5 ds dd + 5 ds dd
|
||
|
||
|
||
|
||
dw 12h, dpb_2,0, dpb_2,1, dpb_0,1, 0,0, 0,0 ;5 ss qd + 5 ss qd
|
||
|
||
|
||
dw 13h, dpb_3,0, dpb_3,1, dpb_2,1, dpb_1,1, dpb_0,1 ;5 ds qd + 5 ds qd
|
||
|
||
|
||
|
||
dw 14h, dpb_4,0, dpb_4,1, dpb_6,1, 0,0, 0,0 ;8 ss dd + 8 ss dd
|
||
|
||
|
||
|
||
dw 15h, dpb_5,0, dpb_5,1, dpb_4,1, dpb_6,1, 0,0 ;8 ds dd + 8 ds dd
|
||
|
||
|
||
|
||
dw 09h, dpb_7,80h, dpb_8,80h, dpb_1,0, dpb_0,0, 0,0 ;5 ds dd + w
|
||
|
||
|
||
|
||
dw 0bh, dpb_7,80h, dpb_8,80h, dpb_3,0, dpb_1,0, dpb_0,0 ;5 ds qd + w
|
||
|
||
|
||
|
||
dw 0dh, dpb_7,80h, dpb_8,80h, dpb_5,0, dpb_4,0, dpb_6,0 ;8 ds dd + w
|
||
|
||
|
||
|
||
dw -1 ; stopper
|
||
|
||
;| |
|
||
;------------------------------------------------
|
||
ENDIF
|
||
|
||
IF (NOT loader_bios) AND special
|
||
;------------------------------------------------
|
||
|
|
||
avail_tab:
|
||
dw 15h, dpb_5,0, dpb_1,1, 0,0, 0,0, 0,0
|
||
dw -1
|
||
;| |
|
||
;------------------------------------------------
|
||
ENDIF
|
||
|
||
|
||
; Extended disc parameter block layout
|
||
|
||
dpb_flags equ byte ptr 15 ;flags
|
||
dpb_ret_sidleng equ word ptr 16 ;retries and sectors/track
|
||
dpb_sidleng equ byte ptr 17 ;sectors/track
|
||
dpb_phy_disk equ byte ptr 18 ;drive number
|
||
dpb_max_sectors equ word ptr 20 ;total sectors on floppy disc
|
||
dpb_part_offset equ word ptr 20 ;hard disc partition offset
|
||
dpb_secsiz equ word ptr 22 ;bytes per sector
|
||
dpb_secsiz_msb equ byte ptr 23 ;msb of above
|
||
|
||
; Disc parameter blocks
|
||
|
||
; Single Sided, Double Density 5" drives (SA 400L)
|
||
DPB_0:
|
||
;Block allocation size = 1024 (BLS)
|
||
DW 40 ;CP/M Sectors per track (SPT)
|
||
DB 03 ;Block shift factor (BSH)
|
||
DB 07 ;Block mask (BLM)
|
||
DB 00 ;Null mask (EXM)
|
||
DW 189 ;Disk size - 1 (DSM)
|
||
DW 063 ;Directory max (DRM)
|
||
DB 11000000b ;Alloc 0 (AL0)
|
||
DB 0 ;Alloc 1 (AL1)
|
||
DW 16 ;Check size (CKS)
|
||
DW 2 ;Track offset (OFF)
|
||
|
||
db 0000b ;Flags - 5" SS
|
||
db 10 ;10 retries
|
||
db 5 ;no. of sectors per side of trk
|
||
db 0 ;space for drive no.
|
||
db 0 ;spare
|
||
dw 40*5 ;total sectors per disc
|
||
dw 1024 ;sector size
|
||
|
||
;Double Sided, Double Density 5" drives (SA 450L)
|
||
DPB_1:
|
||
;Block allocation size = 2048 (BLS)
|
||
DW 40 ;CP/M Sectors per track (SPT)
|
||
DB 04 ;Block shift factor (BSH)
|
||
DB 15 ;Block mask (BLM)
|
||
DB 01 ;Null mask (EXM)
|
||
DW 194 ;Disk size - 1 (DSM)
|
||
DW 127 ;Directory max (DRM)
|
||
DB 11000000b ;Alloc 0 (AL0)
|
||
DB 0 ;Alloc 1 (AL1)
|
||
DW 32 ;Check size (CKS)
|
||
DW 2 ;Track offset (OFF)
|
||
|
||
db 0001b ;Flags - 5" DS
|
||
db 10 ;10 retries
|
||
db 5 ;no. of sectors per side of trk
|
||
db 0 ;drive no.
|
||
db 0 ;spare
|
||
dw 40*5*2 ;total sectors per disc
|
||
dw 1024 ;sector size
|
||
|
||
;Single Sided, Quad Density 5" drives (SA 410)
|
||
DPB_2:
|
||
;Block allocation size = 2048 (BLS)
|
||
DW 40 ;CP/M Sectors per track (SPT)
|
||
DB 04 ;Block shift factor (BSH)
|
||
DB 15 ;Block mask (BLM)
|
||
DB 01 ;Null mask (EXM)
|
||
DW 194 ;Disk size - 1 (DSM)
|
||
DW 127 ;Directory max (DRM)
|
||
DB 11000000b ;Alloc 0 (AL0)
|
||
DB 0 ;Alloc 1 (AL1)
|
||
DW 32 ;Check size (CKS)
|
||
DW 2 ;Track offset (OFF)
|
||
|
||
db 0010b ;Flags - 5" SS quad
|
||
db 10 ;10 retries
|
||
db 5 ;no. of sectors per side of trk
|
||
db 0 ;drive no.
|
||
db 0 ;spare
|
||
dw 80*5 ;total sectors per disc
|
||
dw 1024 ;sector size
|
||
|
||
;Double Sided, Quad Density 5" drives (SA 460)
|
||
DPB_3:
|
||
;Block allocation size = 2048 (BLS)
|
||
DW 40 ;CP/M Sectors per track (SPT)
|
||
DB 04 ;Block shift factor (BSH)
|
||
DB 15 ;Block mask (BLM)
|
||
DB 00 ;Null mask (EXM)
|
||
DW 394 ;Disk size - 1 (DSM)
|
||
DW 255 ;Directory max (DRM)
|
||
DB 11110000b ;Alloc 0 (AL0)
|
||
DB 0 ;Alloc 1 (AL1)
|
||
DW 64 ;Check size (CKS)
|
||
DW 2 ;Track offset (OFF)
|
||
|
||
db 0011b ;Flags - 5" DS quad
|
||
db 10 ;10 retries
|
||
db 5 ;no. of sectors per side of trk
|
||
db 0 ;drive no.
|
||
db 0 ;spare
|
||
dw 80*5*2 ;total sectors per disc
|
||
dw 1024 ;sector size
|
||
|
||
;Single Sided, Double Density 8" drives (SA 800)
|
||
DPB_4:
|
||
;Block allocation size = 2048 (BLS)
|
||
DW 64 ;CP/M Sectors per track (SPT)
|
||
DB 04 ;Block shift factor (BSH)
|
||
DB 15 ;Block mask (BLM)
|
||
DB 00 ;Null mask (EXM)
|
||
DW 303 ;Disk size - 1 (DSM)
|
||
DW 127 ;Directory max (DRM)
|
||
DB 11000000b ;Alloc 0 (AL0)
|
||
DB 0 ;Alloc 1 (AL1)
|
||
DW 32 ;Check size (CKS)
|
||
DW 1 ;Track offset (OFF)
|
||
db 0100b ;Flags - 8" SS
|
||
db 10 ;10 retries
|
||
db 8 ;no. of sectors per side of trk
|
||
db 0 ;drive no.
|
||
db 0 ;spare
|
||
dw 77*8 ;total sectors per disc
|
||
dw 1024 ;sector size
|
||
|
||
;Double Sided, Double Density 8" drives (SA 850)
|
||
DPB_5:
|
||
;Block allocation size = 2048 (BLS)
|
||
DW 64 ;CP/M Sectors per track (SPT)
|
||
DB 04 ;Block shift factor (BSH)
|
||
DB 15 ;Block mask (BLM)
|
||
DB 00 ;Null mask (EXM)
|
||
DW 611 ;Disk size - 1 (DSM)
|
||
DW 255 ;Directory max (DRM)
|
||
DB 11110000b ;Alloc 0 (AL0)
|
||
DB 0 ;Alloc 1 (AL1)
|
||
DW 64 ;Check size (CKS)
|
||
DW 1 ;Track offset (OFF)
|
||
|
||
db 0101b ;Flags - 8" DS
|
||
db 10 ;10 retries
|
||
db 8 ;no. of sectors per side of trk
|
||
db 0 ;drive no.
|
||
db 0 ;spare
|
||
dw 77*8*2 ;total sectors per disc
|
||
dw 1024 ;sector size
|
||
|
||
;Single Sided, Single Density 8" drives (SA 800)
|
||
DPB_6:
|
||
;Block allocation size = 1024 (BLS)
|
||
DW 26 ;CP/M Sectors per track (SPT)
|
||
DB 03 ;Block shift factor (BSH)
|
||
DB 07 ;Block mask (BLM)
|
||
DB 00 ;Null mask (EXM)
|
||
DW 242 ;Disk size - 1 (DSM)
|
||
DW 063 ;Directory max (DRM)
|
||
DB 11110000b ;Alloc 0 (AL0)
|
||
DB 0 ;Alloc 1 (AL1)
|
||
DW 16 ;Check size (CKS)
|
||
DW 2 ;Track offset (OFF)
|
||
|
||
db 1100b ;Flags - 8" SS SDen
|
||
db 10 ;10 retries
|
||
db 26 ;no. of sectors per side of trk
|
||
db 0 ;drive no.
|
||
db 0 ;spare
|
||
dw 77*26 ;total sectors per disc
|
||
dw 128 ;sector size
|
||
;Winnie, partition A
|
||
DPB_7:
|
||
;Block allocation size = 8192 (BLS)
|
||
DW 17*4 ;CP/M Sectors per track (SPT)
|
||
DB 06 ;Block shift factor (BSH)
|
||
DB 63 ;Block mask (BLM)
|
||
DB 03 ;Extent mask, mod. by set_size (EXM)
|
||
DW 0 ;Disk size (filled in) (DSM)
|
||
DW 511 ;Directory max (DRM)
|
||
DB 11000000b ;Alloc 0 (AL0)
|
||
DB 0 ;Alloc 1 (AL1)
|
||
DW 0 ;Check size (CKS)
|
||
DW 1 ;Track offset (OFF)
|
||
|
||
db 10000b ;Flags - Winchester
|
||
db 10 ;10 retries
|
||
db 17 ;no. of sectors per side of trk
|
||
db 0 ;drive no. (filled in later)
|
||
db 0 ;spare
|
||
dw 0 ;partition offset (filled in)
|
||
dw 512 ;sector size
|
||
|
||
DPB_8:
|
||
;Block allocation size = 8192 (BLS)
|
||
DW 17*4 ;CP/M Sectors per track (SPT)
|
||
DB 06 ;Block shift factor (BSH)
|
||
DB 63 ;Block mask (BLM)
|
||
DB 03 ;Extent mask, mod. by set_size (EXM)
|
||
DW 0 ;Disk size (filled in) (DSM)
|
||
DW 511 ;Directory max (DRM)
|
||
DB 11000000b ;Alloc 0 (AL0)
|
||
DB 0 ;Alloc 1 (AL1)
|
||
DW 0 ;Check size (CKS)
|
||
DW 1 ;Track offset (OFF)
|
||
|
||
db 10000b ;Flags - Winchester
|
||
db 10 ;10 retries
|
||
db 17 ;no. of sectors per side of trk
|
||
db 0 ;drive no. (filled in later)
|
||
db 0 ;spare
|
||
dw 0 ;partition offset (filled in)
|
||
dw 512 ;sector size
|
||
|
||
|
||
IF NOT loader_bios
|
||
;----------------------------------------
|
||
;| |
|
||
signon db esc,'E','CP/M-86/80 Version 1.1, '
|
||
db 'Level 21 (24/05/83)',cr,lf
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
IF (NOT loader_bios) AND (NOT cal)
|
||
;----------------------------------------
|
||
;| |
|
||
db 'LSI Computers Ltd, Woking',cr,lf
|
||
size_txt db '256K System M-Four'
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
IF (NOT loader_bios) AND cal
|
||
;----------------------------------------
|
||
;| |
|
||
size_txt db '256K CAL Personal Computer'
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
IF NOT loader_bios
|
||
;----------------------------------------
|
||
;| |
|
||
db ', Firmware Level '
|
||
firm_rev db '00',cr,lf,lf
|
||
db 'Available drives :-',cr,lf,0
|
||
win_tx db 'Winchester',cr,lf,0
|
||
flop_tx db '.H. drive, ',0
|
||
driv_tx db '" ',0
|
||
single_tx db 'single',0
|
||
double_tx db 'double',0
|
||
quad_tx db 'quad',0
|
||
sides_tx db ' sided, ',0
|
||
density_tx db ' density',cr,lf,0
|
||
size_txt_small db '128'
|
||
;| |
|
||
;----------------------------------------
|
||
ENDIF
|
||
|
||
part_err_msg db 'reading Winchester partition table',0
|
||
no_part_msg db 'Winchester disc has no CP/M partition.',0
|
||
part_buf rb 512 ;for reading partition table
|
||
|
||
; end of temporary data
|
||
|
||
org temp_data
|
||
|
||
; uninitialised data space
|
||
|
||
dirbuf rb 128 ;overwritten by temp_data
|
||
hst_buff rb 19 * 512 ;overwritten by temp_data
|
||
|
||
rw 32 ;local stack for init. & warm boot
|
||
stkbase equ $
|
||
|
||
;*** Disk parameter blocks ***
|
||
|
||
DPB_A rb dpblen
|
||
DPB_B rb dpblen
|
||
DPB_C rb dpblen
|
||
DPB_D rb dpblen
|
||
dpb_e rb dpblen
|
||
|
||
; Keyboard buffer
|
||
|
||
kbuf_start rb 32
|
||
kbuf_end equ $
|
||
|
||
|
||
; Workspace used by clock interrupt
|
||
|
||
clock_temp: ;data read from clock to here (image of clock registers)
|
||
second rb 1 ;seconds 0 0 - 60
|
||
rb 1 ; 1
|
||
minute rb 1 ;minutes 2 0 - 60
|
||
rb 1 ; 3
|
||
hour rb 1 ;hour 4 0 - 24
|
||
rb 1 ; 5
|
||
rb 1 ; 6
|
||
day_no rb 1 ;day 7 1 - 31
|
||
month rb 1 ;month 8 1 - 12
|
||
yr rb 1 ;year 9 0 - 99 (from 1980)
|
||
rb 1 ; 10
|
||
|
||
sysdat_offset rw 1
|
||
sysdat_segment rw 1 ;must come after sysdat_offset
|
||
|
||
ss_save rw 1
|
||
sp_save rw 1
|
||
rw 30 ;space for clock stack, allowing for interrupts
|
||
clock_stack rw 1 ;must be at end of stack space
|
||
|
||
; End of clock workspace
|
||
|
||
bdos_scr rs 1
|
||
|
||
;******** end of everything
|
||
|
||
;**********************************************************
|
||
|
||
IF NOT loader_bios
|
||
;----------------------------------------
|
||
;| |
|
||
|
||
; Map of skeletal cpm 80 bios to be put in Z80 bank
|
||
|
||
org 0
|
||
bios_jmp rs 3
|
||
iobyte_80 rs 1
|
||
def_drive rs 1
|
||
bdos_jmp rs 3
|
||
|
||
org 5ch
|
||
zfcb_1 rs 36
|
||
|
||
org 66h
|
||
z80_nmi rs 3
|
||
|
||
org 6ch
|
||
zfcb_2 rs 36
|
||
|
||
org 80h
|
||
dma_buf rs 80h
|
||
prog_80 equ $
|
||
|
||
org 0fb00h
|
||
z80_stack equ $
|
||
|
||
org 0fb06h
|
||
bdos_80 equ $
|
||
|
||
org 0fc00h
|
||
z_alloc rs 512 ;allocation vector
|
||
|
||
org 0fe00h
|
||
bios_80 equ $
|
||
|
||
org 0ffe0h
|
||
mfcb_a rb 16
|
||
asav rb 1
|
||
csav rb 1
|
||
bcsav rw 1
|
||
esav rb 1
|
||
desav rw 1
|
||
lsav rb 1
|
||
hlsav rw 1
|
||
|
||
kstat_80 rb 1
|
||
|
||
org 0fffeh
|
||
fncode rw 2
|
||
|
||
;| |
|
||
;------------------------------------------------
|
||
ENDIF ; not loader bios
|
||
|
||
; End of M4BIOS.ASM file
|
||
|
||
|
||
END
|
||
|