home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
mbug
/
mbug097.arc
/
B512T.Z
< prev
next >
Wrap
Text File
|
1979-12-31
|
68KB
|
3,406 lines
; *********************************************************
; * *
; * ========================================= *
; * --- MicroBee Enhanced DRAM BIOS --- *
; * *
; * Bios for 128k, 256k & 512k MicroBees. *
; * (c) 1986 by Peter Broughton. *
; * ========================================= *
; * *
; * Derived from 128k BIOS ( ver. 6 ) *
; * (c) Matthew Starr for MicroBee Systems. *
; * *
; * Features : *
; * Compatable with 128k BIOS version 7, *
; * 32k - 416k Memory drives (M: & N:), *
; * 32k - 128k Disk Cache, *
; * Preselectable disk types, *
; * 12 128 byte function keys, *
; * Storage of BDOS, CCP, SHELL in backplane, *
; * User selectable keyboard driver in backplane, *
; * System configuration window in backplane. *
; * Etc., etc... *
; * *
; *********************************************************
;
;
;
;
; Structure of code :
; 1. Customisation file ( include CUSTOM.OPT ).
; - also include standard file CPMCALLS.MAC.
; 2. Boot sector ( 512 bytes, max 128 used ).
; 3. BDOS ( include BDOS.MAC ).
; 4. Visible BIOS ( < F000h ),
; - tables, boot, serial, links to later code etc.
; *** From this point code is hidden by screen RAM.
; 5. Initial handling of some standard calls,
; ( including disk IO ), disk select routine,
; RAM disk routines.
; 6. Console IO ( include CON512.MAC ),
; - screen, keyboard link, serial, parallel IO.
; 7. Disk cache ( include DB512.MAC ),
; - all disk cache routines
; 8. Disk IO ( include FL512.MAC ),
; - low level disk IO.
; 9. Data storage etc. etc. to end of RAM.
; 10. Routines that are moved to address 0 in system page.
;
;
; PJB's nth law of programming:
; The number of bugs that will appear when completing a program
; is inversly proportional to the time you have told people it
; will take to complete.
; For an example of this see below:
ASEG
.Z80
TITLE Microbee 512k CP/M 2.2, Enhanced BIOS.
; Approx date of last modification, version num. to indicate
; released versions only.
version macro
db '2.2'
endm
date macro
db '17th May, 1988'
endm
true equ -1
false equ not true
; Include file containing customisation options.
include CUSTOMT.OPT
test_code equ false ; useful for testing (if code in place)
name_protect equ true
scramble equ false
out_50h equ 50D3h
; write value to map port
map macro value
ld a,value
out (map_port),a
endm
; screen flag testing code
sflag macro sc_offs,char,oldmap
if test_code
map sys_vdr
ld a,char
ld (8000h+sc_offs),a
map oldmap
endif
endm
psflag macro sc_offs,char,oldmap
if test_code
push af
map sys_vdr
ld a,char
ld (8000h+sc_offs),a
map oldmap
pop af
endif
endm
; Disk types ...
ds40 macro
; double sided, 40 track, 386k, Microbee standard 5.25"
db xltd-xlt_base
db 1
db 3
;
dw 40
db 4
db 15
db 1
dw 194
dw 127
db 192,0
dw 32
dw 2
endm
ss80 macro
; single sided, 80 track, 386k, Microbee standard 3.5" CIAB
db xltd-xlt_base
db 2
db 3
;
dw 40
db 4
db 15
db 1
dw 194
dw 127
db 192,0
dw 32
dw 2
endm
ds80 macro
; double sided, 80 track, 776k, MicroBee standard 3.5" Modular
db xltc-xlt_base
db 5
db 3
;
dw 40
db 5
db 31
db 3
dw 0C2h
dw 127
db 80h,0
dw 32
dw 4
endm
ds82 macro
;double sided, 80 track, 782k space, Dreamdisk format
db xltd-xlt_base
db 1
db 3
;
dw 40
db 4
db 15
db 0
dw 391
dw 255
db 0F0h,0
dw 64
dw 2
endm
ds84 macro
; double sided, 80 track, 784k, PJB's format
db xltd-xlt_base
db 1
db 3
;
dw 40
db 5
db 31
db 3
dw 196
dw 127
db 128,0
dw 32
dw 2
endm
ds8b macro
;double sided, 80 track, 776k space, Beeboard format
db xltd-xlt_base
db 1
db 3
;
dw 40
db 4
db 15
db 0
dw 389
dw 127
db 0C0h,0
dw 32
dw 4
endm
include CPMCALLS.MAC
biosv equ 0 ;points to BIOS warm start
iobyte equ 3 ;iobyte
usrdfd equ 4 ;byte with user_num*16+def_drive
cpmv equ 5 ;system call vector
viewdrive equ 8 ;b0-3 are currently viewed drive
L0050 equ 50h
DFCB equ 5Ch
DBUFF equ 80h
TPA equ 100h
ORGAD equ system_start
; Where CP/M is loaded to by 'offload' in the BOOT RAM
boot_pos equ 0A000h
; BOOT ROM location (for bootup only)
boot_rom equ 0E000H
; system page addresses
check_ram_m equ end_sys_r ; previous pages for m (for check)
check_ram_n equ end_sys_r+1 ; previous pages for n
bdos_save_addr equ end_sys_r+2 ; where BDOS is saved to
;******************************************************************
;* *
;* BOOT SECTOR *
;* *
;******************************************************************
org 100h ; not writing a sysgen compatible file,
; but a SETSYS compatible file.
.phase 80h
; Boot sector has been modified to boot a double sided disk from a
; BN54, BN55 or BN56 boot ROM.
; NB. This only means checking for a BN55, it requires track # 159 for
; the first track on side 1, rest require # 79.
; byte to check for BN55
bn55_flag equ 0EF00h
bn55_val equ 0
ld sp,80h
ld de,0*100H+1 ; track 0 sector 1
ld hl,boot_pos
ld bc,512*10
call boot_rom+39H
jr bc_1
; double side boot flag must be at offset 11h for compatability with SETSYS
if $ gt 91h
error boot flag not in correct position
else
ds $-91h
endif
boot_flag:
if boot_ds
db 79
else
db 1
endif
bc_1:
; next track
jr nz,un_boot
ld de,1*100h+1 ; single sided
ld a,(boot_flag)
cp 1
jr z,bc_2
ld de,79*100h+1 ; double sided on BN54, BN56
ld a,(bn55_flag)
or a
jr nz,bc_2
ld de,159*100h ; double sided on BN55
bc_2:
ld hl,boot_pos+512*10
ld bc,512*10 ; +(cpm_end-orgad-512*9)+1
call boot_rom+39H ;offload into RAM
jp z,good_boot
; print message saying BOOT unsuccessful
un_boot
ld c,'Z'-40H
call boot_rom+0CH ;CONOUT
ld hl,message
call boot_rom+33H ;flash message, get key
jp boot_rom ;try again
message:
; db ' SYSTEM UNREADABLE - PRESS <RETURN> TO TRY AGAIN ',80h
db ' BAD SYSTEM ',80h
if ($-80h) gt 80h
error boot part 1 is too big !!!!
endif
.dephase
.phase boot_pos+($-100h)
good_boot
di
map sys_page
; move system to correct locations
ld hl,boot_pos+512
ld de,orgad
ld bc,cpm_end-orgad
ldir
; move stuff into system page
ld hl,boot_pos+sys_page_r-100h
ld de,0
ld bc,end_sys_r
ldir
; put bdos into system page
ld hl,orgad
ld de,bdos_save_addr
ld bc,bios-orgad
ldir
map bios_map
; Cold start BIOS
jp boot_accept
; INIT ( the ratbags! ) destroys boot sectors > 128 bytes
if ($-boot_pos) gt 128 ;512
error boot sector too big
dw $-boot_pos+zero
else
ds 512-($-boot_pos)
endif
boot_length equ $-boot_pos
.dephase
;-----------------------------------------------------------------------
.RADIX 16D
.PHASE ORGAD
include BDOS.MAC
;----------------------------------------------------------------------
; **** START OF BIOS
.radix 0AH
bios_type equ 7 ;diff. for each radical change
bios_type_name macro
db '7'
endm
; Configuration constants
; see CONFIG block for rest of constants
num_drives equ tot_dr
; hardware values
pioa_data equ 0
pioa_ctrl equ 1
piob_data equ 2
piob_ctrl equ 3
; 146818 Real time clock addresses if fitted
rtc_addr equ 4
rtc_read equ 7
rtc_write equ 6
col_port equ 8 ;color control, background port
vwait_off equ 9 ;out anything to this to kill vwait
rom_port equ 0Bh ;bit 0 controls rom-read
crtc equ 0Ch ;6545 .. 4 ports
beep_port equ piob_data
vml equ 1Ch ; premium pcg control etc.
;vml equ 0 ; Equate to 0 to test for standard
map_port equ 50h ;memory map control port
speed_port equ 9 ;IN here controls CPU speed
speed_value equ 2 ;'IN' value for fast (A9 high)
vdu equ 8000h ;character RAM/ CHAR ROM
pcg equ 8800h ;PCG ram/ colour
col_ram equ 8800h ;where colour ram starts
dden_sel equ 3 ;bit for DD in dden_byte
; status line positions
status_start equ vdu+(24*80)+2
pjb_sl equ status_start+2
fast_sl equ status_start+16 ; 'fast' message
swap_a_m_sl equ status_start+23 ; pos of 'A<>M' message
lock_sl equ status_start+30 ; pos of lock message
fn_sl equ status_start+42 ; 'fn pressed' message
fn_on_sl equ status_start+37 ; 'fn active'
clock_sl equ status_start+52 ; pos of time on status line
num_sl_msgs equ 5 ; number of messages on status line
; status line refreshed after this number of BIOS calls
cycle_max equ 16
; Start addresses for routines in system page (from .SYS file)
bios_sys_start equ 5800h
print_s_line equ bios_sys_start+6
set_up_s_line equ bios_sys_start+9
; .SYS file header values
hdr_pos equ 8000h ;examine header here
load_pos equ 8080h ;where to initially load to
dbs_start equ 0 ;must be <= the bios address
dsh_start equ 2 ;where file loads to
dsh_length equ 4 ;file length
; page 0 addresses
xbs_rst equ 28h
cpm_fcb equ 5Ch
fcb_len equ 16
bdos equ 5 ;where system call vector goes
; values to write to mapping port ..
normal_map equ 4 ;screen switched in at F000
bios_map equ 0Ch ;screen switched out
vdr_map equ 14h ;screen switched in at 8000
; important pages
sys_page equ 0Dh ; page for system save etc
md_page_1 equ 0Fh ; page with m_drive directory
sys_screen equ 5 ; system page plus screen enabled
sys_vdr equ 15h ; ditto at 8000h
; system page addresses
grafix_addr equ 4000h ; graphics driver default
num_fn_keys equ 12 ; number of fn keys
; function key store in system page
fn_store equ 8000h-(num_fn_keys*128)
; extended DPB offsets
dxlt equ -3 ;ix offsets for xlt tab offset
dflags equ -2 ;b0 if up/down, b1 if 80 track
dsecmsk equ -1 ;AND sector mask
; Misc
wrual equ 2 ;write to unalloc from CP/M
; ASCII codes
cr equ 0Dh
lf equ 0Ah
tb equ 9
cls equ 1Ah
xon equ 11h ;Xon code (start xmission)
xoff equ 13h ;Xoff code (stop xmission)
; .list
; BIOS jump table...
bios: jp boot_accept ;Post cold boot
wboote: jp wboot ;Warm boot
instat: jp v2 ;Console status
conin: jp v3 ;Read KBD
bconout:jp vconout ;Write cons char in C
prntr: jp vlistout ;Print char in C
puncho: jp v6 ;PUNCH out (1200bd output)
punchi: jp v7 ;READER in (1200bd input)
; disk routines
home: jp v8 ;Restore to trk 0
seldsk: jp v9 ;Select disk (can be logical disk)
settrk: jp v10 ;Seek track [C]
setsec: jp v11 ;Set sec [C]
bsetdma:jp v12 ;Set "DMA" address
read: jp v13 ;Read a CP/M sector
write: jp v14 ;Write a CP/M sector
jp vlistst ;printer ready check
l5430: jp v16 ;sectran
;
defb bios_type
; default 6545 table, reloaded on warm boot
crtc_tab
defb 108-1,80,89,37H,28-1,5
; this value is used as an ON/OFF flag for the status line
s_line
if status_line
db 25
else
db 24
endif
defb 26,48h,10,10+20h,10,20H,0,0,0
if preset_disks
; DPH's for preset disk types
dpbase: dw 0,0,0,0,dirbuf,disk_A+3,csv0,alv0
dw 0,0,0,0,dirbuf,disk_B+3,csv1,alv1
dw 0,0,0,0,dirbuf,disk_C+3,csv2,alv2
dw 0,0,0,0,dirbuf,disk_D+3,csv3,alv3
else
; DPH's for non preset types
dpbase: dw 0,0,0,0,dirbuf,0,csv0,alv0
dw 0,0,0,0,dirbuf,0,csv1,alv1
dw 0,0,0,0,dirbuf,0,csv2,alv2
dw 0,0,0,0,dirbuf,0,csv3,alv3
endif
dpb_base equ $+3
disk_type_def ; puts in selected dpb's
; spare data room for custom format setup
db xlte-xlt_base ;sector xlate
db 0 ;"cylinder" and "don't correct" flag
db 0 ;sector mask
;
spare_dpb:dw 0 ;sectors per cylinder
db 0 ;block shift factor
db 0 ;block mask
db 0 ;extent mask
dw 0 ;blocks per diskette
dw 0 ;# directory entries
db 0 ;alloc 0
db 0 ;alloc 1
dw 0 ;dir check vector size
dw 0 ;system track offset
; Sector translation tables
xlt_base equ $
; spare room for up to 54 sector long xlt table
xlte: db 01,02,03,04,05,06,07,08,09
db 10,11,12,13,14,15,16,17,18
db 19,20,21,22,23,24,25,26,27
db 28,29,30,31,32,33,34,35,36
db 37,38,39,40,41,42,43,44,45
db 46,47,48,49,50,51,52,53,54
;
; The positions of xltc & xltd must not be changed
; strange modification of xltd for standard 3.5" ds
xltc: db 22,25,28
db 21,24,27,30
db 23,26,29
;
; "shifted" 3 sector skew for 10 sectors designed to maximize
; the time between steps
xltd: db 2,5,8
db 1,4,7,10
db 3,6,9
; .list
; Data which is changed by INIT for varying requirements ..
sh_wanted
defb init_sh ;=0 for CCP, =1 for shell
col_mode
defb init_col_mode ;color mode port value
col_char
defb init_col ;color character value
snum_drives
defb tot_dr ;number of drives starting at A:
snum_floppies
defb tot_dr ;number of above which are floppies
pr_baud
defb 2 ;printer baud rate code - 1200 baud default
send_lf
defb 1 ;zero if linefeeds are to be filtered
; changed by INIT for serial/ parallel printer selection ..
i_iobyte
defb 81h ;initial IOBYTE - parallel
use_xonxoff
defb 0 ;nz if xon/xoff used for serial port
submit_flag
defb 0 ;nz if submit in progress (or is that process?)
defs 5 ;expansion
; RS232 comm. parameters which set format
num_data defb 8 ;number of data bits
parity defb 1 ;1=no par, 2=odd, 3=even
; +1 in next gives mid to late sampling; +0 early to mid
; parity is ignored but read through
r_num defb 4*(1+8)+0 ;4*(nstrt+ndata)+0
totalq defb (1+8+0+1)*4 ;(nstrt+ndata+npar+nstop)*4
adj_fact defb 13-1-8-0 ;13-nstrt-ndata-npar
; default settings for options in Bshell companion programs
xfer_options
defb 0,0,0,0,0,0,0,0
init_options
defb 0,0 ;these are actually used
others
defb 0,0,0,0,0,0,0,0
defb 0,0,0,0,0,0,0,0
defb 0,0
; map of which drives are 80 track ones
; this isn't actually used
tk80_drives
; It's now used to indicate 'cache-able' drives (set by user)
; 0FFh = don't cache
cache_map
db 0,0,0,0
; Stuff for ZCPR
defw free_128_bytes
defb 128
defb 0
; 128 bytes for ZCPR and Bshell to hold multiple commands
; ** STARTUP command buffer
free_128_bytes
ds 128,0
; align to 2 byte boundary ..
defs ($ and 1)
pioa_vect defw par_int ;pio a int vector
piob_vect defw int_rtn ;pio b int vector
defw 0 ;some spares
defw 0
defw 0
defw 0
; may need to make some space here for 8530 VIS INT vector
; ...
dtr_max equ (end_queue-RS_queue)-5
r_ptr defw end_queue-RS_queue ;q_base index -
; last posn read from
w_ptr defw end_queue-RS_queue ;q_base index -
; last posn. written to
q_base defw RS_queue ;holds addr. of start of queue
q_max defw end_queue-RS_queue ;max index onto queue
; (1 less than size)
dtr_limit defw dtr_max ;# safe chars left in buffer
; RS232 timing (setup by set_baud)
simult defw l1200 ;address of txrx controller (l300/l1200)
; M-drive data
md_DPH
DW 0,0,0,0,DIRBUF,md_DPB,CSV3,ALVM
;
DB 0 ;128 byte physical sectors
md_DPB: dw 32 ;128 byte sectors per 16k track
db 4 ;Shift factor for 2k blocks
db 15 ;Block mask
db 1 ;Extent mask
dw md_pages*16-1 ;Largest block number - patchable
if md_pages lt 8
dw 63 ;Max directory entry (if < 256k)
db 80h ;Blank allocation map (1 block = 2k)
else
dw 127 ;Max directory entries (if >= 256k)
db 0C0h ;Blank allocation map (2 blocks = 4k)
endif
db 0 ;
dw 0 ;Check dir length
dw 0 ;System tracks
; 16 bit flag indicating it is PJB's BIOS
bios_flag
dw 0AA55h
; type of system bios is assembled for
bios_id
if telecomputer
db 7
else
db 3
endif
; Space for 16 preset values etc.
; non zero to map logical A onto physical M
swap_a_with_m
db 0
is_premium
db false ; initial value only
; force formatting of ram disk on cold boot
force_format
db format_m
; graphics driver start address, can be changed by graphics installation
; program
gr_addr
dw 0
; function keys active
fn_active
db true
; where WINDOW.SYS ends up
window_addr
dw 0
click_length
db 7
click_tone
db 22
pages_for_md
db md_pages
dbuff_pages
db db_pages
pages_for_nd
db nd_pages
col_stat
db stat_col
max_pages
db total_pages
user_page
db 0 ;default value indicating no user program
ds 16-($-swap_a_with_m)
; these are FCB's for shell, CCP, window and fn key def's file
sh_fcb
db 1 ;drive A
db 'SHELL SYS'
db 0,0,0,0 ;ex, s1, s2, rc
ccp_fcb
db 1
db 'CCP SYS'
db 0,0,0,0
window_fcb:
db 1
db 'WINDOW SYS'
db 0,0,0,0
fn_key_fcb
db 1
db 'DEFAULT FK '
db 0,0,0,0
; space for definition of cursor keys etc.
curs_key_tab
db 'E'-40h,0,'X'-40h,'S'-40h,'_' ,'Q'-40h,'D'-40h,0
db 'R'-40h,0,'C'-40h,'A'-40h,'J'-40h,'K'-40h,'F'-40h,0
; required by window program etc.
window_needs:
dw scn_in
dw get_rtc
dw put_rtc
in_fnstr
db false
fn_ptr
dw 0
dw ptr_out
linpos
db 0 ; cursor line
colpos
db 0 ; cursor column
cursor
dw vdu ; cursor address
dw is_closed ; check for key pressed
al_rev
db false ; caps lock
fast_cpu
db fast_speed ; run at 6.75 MHz
no_clock
db false ; set up by code
restore_db_pages
db db_pages ; So disable cache program can re-enable
user_addr
dw 0 ; Address of user program
dw mem_page ; Address of mem_page routine
ds 32-($-window_needs)
keyboard_fcb:
db 1
db 'BIOS SYS'
db 0,0,0,0
; N-drive data
Nd_DPH
DW 0,0,0,0,DIRBUF,nd_DPB,CSV3,ALVM+(md_pages*2)
;
DB 0 ;128 byte physical sectors
nd_DPB: dw 32 ;128 byte sectors per 4k track
db 4 ;Shift factor for 2k blocks
db 15 ;Block mask
db 1 ;Extent mask
dw nd_pages*16-1 ;Largest block number - patchable
if nd_pages lt 8
dw 63 ;Max directory entry (if < 256k)
db 80h ;Blank allocation map (1 block = 2k)
else
dw 127 ;Max directory entries (if >= 256k)
db 0C0h ;Blank allocation map (2 blocks = 4k)
endif
db 0 ;
dw 0 ;Check dir length
dw md_pages*8 ;System tracks
sl_table
dw sl_pointers
sl_messages
dw sl_msgs
;-------------------------------------------------------
; BDOS scratch which needs to be referenced while the rest
; of the BIOS is swapped out
dirbuf
; dirbuf is shared with COLD BOOT code ..
if name_protect
start_check
db 0FFh,11h,22h,00h
endif
boot_accept
ld sp,boot_stack
; bring this stuff down from CONIO.Z
ld hl,iotabl ;set up PIO
if scramble
ld a,high decrypt
ld (jp_decrypt+2),a
endif
; initialization of PIO
; requires hl=pointer to dgos type IO initialization table
{
ld a,(hl)
or a
#if z,brk
ld b,a
inc hl
ld c,(hl)
inc hl
otir
#cont
}
; baud rate set to 1200 (set to correct value in go_cpm)
call pio_clr ;unconfuse PIO with reti
im 2
ld a,pioa_vect shr 8
ld i,a
xor a
ld (usrdfd),a ;set boot-up disk to A0
ld (viewdrive),a ;clear initial viewed drive
; set IOBYTE to initial value
ld a,(i_iobyte)
ld (iobyte),a
map sys_vdr
call check_premium
if scramble
call jp_decrypt
endif
sflag 0,'1',sys_vdr
call check_ramdisks
sflag 0,'5',sys_vdr
; initialise disk buffer (if enabled)
call db_init
; print boot up message
ld de,smsg ;opening message
ld c,pristr
call bdosin
ei
; now go onto common routines
jp gocpm
smsg
db cls,lf,tb,'Microbee '
if mem_128
db '128'
else
db '512'
endif
db 'k CP/M 2.2, BIOS v'
bios_type_name
db '.',cr,lf,lf
db tb,'Enhanced BIOS (c) '
my_name:
db 'Peter Broughton.',cr,lf,tb,'Version '
version
if not telecomputer
smsg_premium
db 'P' ; changed by check code
else
db 'T'
endif
if scramble
db 'S'
endif
db ', '
date
db '.',cr,lf,lf
if name_protect
db 'This disk belongs to '
user_name:
db '!@#'
ds 30-($-user_name)
db '.',cr,lf,lf
endif
db '$'
; I/O initialisation table
iotabl
; set up port A as a parallel output port
defb 3,pioa_ctrl
defb pioa_vect and 0FFh ; parallel port o/p vector
defb 0Fh,83h
; set up port B for correct directions, enable serial ints
defb 5,piob_ctrl
defb piob_vect and 0FFh
defb 0FFh ; bit mode
piob_dir
; if new_keyboard
; db 09Ah ; b7,b4,b3,b0 & b1 for keyboard
; else
db 099h ; b7;b4;b3;b0 inputs
; endif
defb 80h+37h,255-10h ; b7=1 of first -> interrupt (on)
defb 1,piob_data
defb 20h ;24h ; initial port B output (DTR=1)
defb 0
if name_protect
end_check
db 0FFh,33h,44h
endif
; checksum vectors
if dreamdisk_available
csv_size equ 64
else
csv_size equ 32
endif
csv0 equ dirbuf+128 ;32 reqd for DD 512 bytes/sector format
csv1 equ csv0+csv_size ; or 64 required for dreamdisk fmt
csv2 equ csv1+csv_size
; move $ on to correct position for csv3
if ($-dirbuf) lt 128+(3*csv_size)
ds (128+(3*csv_size))-($-dirbuf)
endif
csv3: defs csv_size
; COLD and WARM boot stack - csv3 not used at BOOT-UP
boot_stack
; allocation vector space
; may be shared with code to load in .SYS files ( except for alv0 )
if dreamdisk_available
alv_size equ 50 ; enough space for ds 80 track with 2k blocks
else
alv_size equ 25
endif
alv0 equ $
alv1 equ alv0+alv_size
alv2 equ alv1+alv_size
alv3 equ alv2+alv_size
alvm equ alv3+alv_size
end_alv equ alvm+(((32/2)/8)*13) ;=26 bytes
if scramble
decrypt:
ld hl,(start_check)
ld de,start_check+4-11FFh
add hl,de
ld de,end_check-start_check-4
ld c,0
dcr1:
ld a,l
add a,(hl)
and 7
ld b,a
inc hl
ld a,(hl)
dcr2:
rrca
djnz dcr2
add a,c
ld c,a
dec de
ld a,d
or e
jr nz,dcr1
ld hl,encrypt_start
ld de,end_encrypt+4-encrypt_start
ld b,0
dcr3:
ld a,b
add a,c
ld b,a
xor (hl)
xor l
ld (hl),a
inc hl
dec de
ld a,d
or e
jr nz,dcr3
ret
endif
if $ lt alv1
ds alv1-$
endif
; load in .SYS files according to FCB's in configuration block
load_sys_files:
map bios_map
syscall resdis
; loop to load in all files
ld a,5 ; five files
ld hl,sh_fcb ; first FCB
ld iy,sh_loaded ; first data pos
sys_load_loop:
ld (temp_1),a
push iy
push hl
; copy file name into message
inc hl
ld de,loading_name
ld bc,8
ldir
inc de
ld c,3
ldir
ld de,loading_mes
syscall pristr
pop hl
push hl
; get .SYS file from A: drive.
; requires : hl -> FCB
ld de,cpm_fcb
; move this FCB to a working one
ld bc,fcb_len
ldir
xor a
ld (cpm_fcb+32),a ;clear CR
ld de,cpm_fcb
syscall opefil
inc a
jp z,sys_not_loaded
; read in header block
ld de,hdr_pos
syscall setdma
ld de,cpm_fcb
syscall reaseq
or a
jp nz,sys_not_loaded
; is the bios start value low enough ?
ld hl,(hdr_pos+dbs_start)
ld de,bios+3
and a
sbc hl,de ;get NC if bios < sh_bios
jp nc,sys_not_loaded
ld hl,load_pos
; read rest of file
{
; hl = where to put it
ex de,hl
push de
syscall setdma
ld de,cpm_fcb
syscall reaseq
or a ;finished?
pop de
#if nz,brk
ld hl,128 ;point to next position
add hl,de
#cont
}
ld hl,load_pos
ld bc,(hdr_pos+dsh_length)
map sys_page
ld a,(temp_1) ; is this WINDOW.SYS
cp 4 ; or DEFAULT.FK
jr nc,not_window
; move WINDOW.SYS or DEFAULT.FK to correct position
ld de,(hdr_pos+dsh_start)
push de
ldir
pop hl
cp 3
jr z,is_window
cp 1 ; is KEYBOARD.SYS ?
jr z,loaded
; if .FK then load cursor key defs.
ld hl,hdr_pos+40h
ld de,curs_key_tab
ld c,16 ; b already 0
ldir
jr loaded
is_window:
; if window then load start address
ld (window_addr),hl
jr loaded
not_window:
; is SHELL or CCP so move into first available address in system page
ld de,(sys_avail)
push de
ld (iy+3),c
ld (iy+4),b
ldir
; if it exceeded available memory then reject it
ld h,d
ld l,e
ld bc,bios_sys_start
or a
sbc hl,bc
pop hl ; hl -> address in system page
ld (iy+5),l
ld (iy+6),h
jr nc,sys_not_loaded
ld (sys_avail),de ; next available address
ld hl,(hdr_pos+dsh_start) ; run position
ld (iy+1),l
ld (iy+2),h
loaded:
ld (iy+0),true ; it is actually there
ld de,ld_mes_end
jr cont_loop
; file was not there or an error occured
sys_not_loaded
ld de,not_loaded_mes
ld (iy+0),false ; file not loaded
; continuation of loop
cont_loop:
map bios_map
; print CR, LF or 'not loaded'
syscall pristr
pop hl
ld bc,16
add hl,bc ; next FCB
ld c,7
pop iy
add iy,bc ; next data section
ld a,(temp_1) ; counter
cp 4
jr nc,next_not_fk
; no 'loaded' variable for KEYBOARD.SYS or .FK file so use dummy position
ld iy,save_p
next_not_fk:
cp 2 ; if next KEYBOARD then move to correct fcb
jr nz,next_not_kbd
ld hl,keyboard_fcb
next_not_kbd:
dec a
jp nz,sys_load_loop
ld de,ld_mes_end ; cr & lf
syscall pristr
ld de,ld_mes_end ; cr & lf
syscall pristr
map bios_map
; now delete call to this routine so it is only called once
pop hl
xor a
dec hl
ld (hl),a
dec hl
ld (hl),a
dec hl
ld (hl),a
; enable keyboard, previously this is disabled to stop the user
; interrupting the cold boot routines
; Actually the keyboard driver probably wasn't there anyway !
ld (disable_kbd),a
; Return from this routine
jp (hl)
loading_mes:
db 'Loading '
loading_name:
db 'FILENAME.EXT ... $'
not_loaded_mes:
db 'not loaded.'
ld_mes_end:
db cr,lf,'$'
; make sure sufficent space for alv's
if $ lt end_alv
ds end_alv-$
endif
; Warm boot
WBOOT
map sys_page
ld sp,boot_stack
ld hl,3
ld (offs_start),hl ;on warm boot, go in 3 bytes after
; Get BDOS from system page, system page must already be enabled
call bdos_from_bp
; and into common routines..
; Common code used after COLD or WARM boot
gocpm
; call common routines
map bios_map
call common_boot
; Load in .SYS files
; this call is deleted by last part of load_sys_files subroutine
call load_sys_files
; Call to set up status line, must be done after loading system files
map sys_vdr
call set_up_s_line
; now get selected user interface from system page
; and get hl --> address of start
; sys_vdr must still be enabled as this is in system page
call load_user_int
; Now jump to user interface
map normal_map
ld a,(usrdfd) ;Get last default disk
ld c,a ;CCP req this in C
jp (hl)
; execute extended BIOS function
x_bios_calls
push ix ;save ix
ld (save_sp),sp
ld sp,bios_stack
push af
map sys_page ; VDU MUST be out, switch in address table
; map bios_map
pop af
; rest of routine is now behind screen
jp call_xbios
; BIOS entry points vector through here
v2: call accept
dw const ;Console status
v3: call accept
dw mchinw ;Read KBD
vconout
ld a,(iobyte)
com_out
and 3
dec a
jp z,govdu
call accept
dw ptr_out ;handles parallel AND serial
vlistout
ld a,(iobyte)
rlca
rlca
jr com_out
v6: call accept
dw pun_out ;PUNCH out (serial output)
v7: call accept
dw pun_in ;READER in (serial input)
; disk routines
v8: call accept
dw d_home ;Restore to trk 0
v9: call accept
dw d_seldsk ;Select disk (can be logical disk)
v10: call accept
dw d_stk ;Seek track [C]
v11: call accept
dw d_ssc ;Set sec [C]
v12: call accept
dw d_sdm ;Set "DMA" address
v13: call accept
dw d_read ;Read a CP/M sector
v14: call accept
dw d_write ;Write a CP/M sector
vlistst
call accept
dw all_listst
v16: call accept
dw sectran
accept
; turn off the video so we don't execute it.
push af
map bios_map
pop af
ex (sp),ix ;get return address/ save ix
ld (save_sp),sp
ld sp,bios_stack ;local stack to avoid bank sw crash
push hl ;save hl
call display_time
ld l,(ix+0) ;get address of routine
ld h,(ix+1)
ex (sp),hl ;put address on stack/ get hl back
ret ;perform BIOS function
; .. and return to here ..
; bios_map must be enabled here
recover
ld sp,(save_sp) ;get old stack back
pop ix ;get ix back
push af
map normal_map ;turn video back on
pop af
ret
; Intermediate stage before recover if wrong page is in
recover_bmap
push af
map bios_map
pop af
ret
; a faster bank swapping routine for the VDU driver,
; which puts the VDU at 8000h
govdu
ld (save_sp),sp
; use local stack in case user stack is at 8000h-8FFFh ..
ld sp,bios_stack
map bios_map
call display_time
map vdr_map
jp vduout
; which then jumps to here
retvdu
map normal_map
ld sp,(save_sp)
ret
; do a BDOS call from the BIOS
bdos_func
call bdos
push af
map bios_map
pop af
ret
; link to premium graphics driver in backplane
link_graphics
push hl
ld hl,(gr_addr)
ld a,h
or l
jr z,no_grfx
ld (grfx_jp),hl
ld hl,recover_bmap
ex (sp),hl ; Restore HL, put return address on stack
map sys_screen ; system page with screen at 0F000h
grfx_jp equ $+1
call 4000h ; Jump to graphics program
map bios_map
ret
no_grfx:
pop hl
or -1
ret
chk_break
; given char to save in c, store it on the queue
; but shift right if only 7 bits of data (8 bits including
; start bit) were read
ld a,(num_data)
cp 7
jr nz,st2
srl c ;since only 7 data bits
st2
call will_fit
ret z ;full, so no more can fit
ld (w_ptr),de
ld (ix+0),c
in a,(piob_data)
; now negate DTR if the buffer is too full
{
ld hl,(dtr_limit)
dec hl
ld (dtr_limit),hl
bit 7,h
#if z,brk
; negate DTR if less than 4 chars left in buffer
res ser_dtr,a
out (piob_data),a
}
; we now know that a character was got, so if still spacing,
; wait for a bit time (this means a parity bit)
; Therefore, breaking the input line will not affect operation
; of anything except that an extra stop bit time is added onto each
; character transmitted
bit ser_in,a
ret z ;it is already marking (stop bit)
; we may be reading through a parity bit, so wait a bit time ..
ld de,0*256+4
; and follow on to jp_simul ..
; set up for txrx call; ix=(simult), (flag)=-1, b=(piob_data) ..
jp_simul
out (vwait_off),a ;stop video waiting
ld ix,(simult) ;address of io routine
ld a,-1
ld (flag),a ;set for no char recvd
in a,(piob_data)
ld b,a
res ser_out,b ;base for output
; and follow on to txrx ..
; the routine which handles one quarter bit time ..
; this was written so that each path in the program has the
; same time (except for start bit detection)
; (orig 146 T-states for txrx alone)
; the delay routine must delay for (3.375e+6) / Fbr / 4 - 162 Tstates
; excluding its final jump to CONT
txrx
ld a,d ;finished tx ing?
or a
jr z,nsend1
and 3 ;sending quarter?
jr nz,nsend2
add hl,hl ;shift hl up one
ld a,h
and +(1 shl ser_out)
or b ;b=the old pio B data with ser_out 0
out (piob_data),a
tecov2
dec d ;decrement tx counter
tecov1
ld a,e ;started rcving yet?
or a
jr z,notyet
and 3 ;receive quarter?
jr nz,norcv2
in a,(piob_data)
and +(1 shl ser_in)
sub 1
rr c
rxcov1
dec e
rxcov2
jp (ix)
cont
ld a,d ;any rxing or txing to go?
or e
jp nz,txrx
ret
;
nsend2
or a
or a
or a
or a
or a
jr tecov2
;
nsend1
ex (sp),hl
ex (sp),hl
jr tecov1
;
norcv2
or a
or a
or a
or a
jr rxcov1
;
notyet
in a,(piob_data)
bit ser_in,a
jr z,mark
;
; note this path is longer, but it only happens once at start bit
ld a,(r_num)
ld e,a
xor a
ld (flag),a
jp (ix) ;(was ret)
;
mark
ld a,0
jp rxcov2
; Timing routines for each baud rate 300, 600, 1200, 2400, 4800
;l110 hahaha
l300
ld a,165
{
dec a
#if nz,cont
}
jr cont
l600
ld a,77
{
dec a
#if nz,cont
}
jr cont
l1200
ld a,33
{
dec a
#if nz,cont
}
jr cont
l2400
ld a,11
{
dec a
#if nz,cont
}
jr cont
l4800
or a
jp cont
; interrupt routine which receives an asynchronous character
int_rtn
ld (ssave_sp),sp
ld sp,int_sp
push af
push bc
push de
push hl
push ix
;; was it a false interrupt (i.e. pending but now irrelevant?)
;in a,(piob_data)
;and 1 shl ser_in ;ignore old interrupts
;call nz,will_fit ;if good int., is buffer full?
;jr z,abort
ld d,0 ;set for no transmit
ld a,(r_num)
ld e,a
; Adjust e:=e-2 for 4800bd or e:=e+1 for others
inc e
{
ld a,(simult) ;low byte
cp l4800 and 0FFh
#if nz,break ;compensate for long lead in time
dec e ;to sample early to mid
dec e ;and not sample start bit (which is OK)
dec e
}
; set up some things, then call simult routine ..
call jp_simul
; store character, and wait for parity bit to be gone ..
call chk_break
;
abort
pop ix
pop hl
pop de
pop bc
pop af
ld sp,(ssave_sp)
ei
pio_clr
reti
; given de as an RS buffer index, give the next index in the
; circular queue and return address in ix
next_RS
push af
dec de
ld a,d
or e
jr nz,cal_ix
ld de,(q_max)
cal_ix
ld ix,(q_base)
add ix,de
pop af
ret
; return de=next w_ptr and nz if there is room
will_fit
ld hl,(r_ptr)
ld de,(w_ptr)
call next_RS
and a
sbc hl,de
ret
; save acc in memory to avoid an extra stack level
par_int
ld (ssave_sp),a
ld a,0
ld (par_flag),a
ld a,(ssave_sp)
ei
reti
par_flag defb 0 ;nz if printer has NOT ACKed yet
ssave_sp defs 2 ;for saving SP when int. comes along
save_sp defs 2 ;save main stack in BIOS routines
; these defs belong to conio.z
; 10 levels of stack (need 9)
defs 20
int_sp ;temp stack for int. RS232 input
RS_queue defs 129 ;where incoming RS232 chars are stored
end_queue ;last byte avail to RS232 buffer
defs 2*32
bios_stack
defw recover ;final return address
map_save
db bios_map
; *******************************************************
; * All code and data beyond this point may be occluded *
; * by the VDU at F000 when "out" of the BIOS *
; *******************************************************
if $ gt 0F000h
error critical code above F000h
dw $-0F000h+zero
endif
; Continuation of routine to call XBIOS functions
call_xbios:
push hl
push de
ld e,a ;function number
sla e
ld d,0
ld hl,func_tab
add hl,de ;hl=table address
ld e,(hl)
inc hl
ld d,(hl)
ex de,hl ;hl=function address
pop de
ex (sp),hl ;put hl on stack/ pop hl
push af
map bios_map
pop af
cp func_max+1
ret c ;execute function if valid
pop ix ;ignore function address
; a call to an 'unused' xbios function will end up here
dud_ret
or -1 ;error return - no such function
ret ;go to recover
; XBIOS Function 0,1 : Set CCP mode
set_mode
ld (sh_wanted),a
; At this stage the pointers to the extended command line should be restored
; to their correct values
push hl
ld hl,free_128_bytes
ld (free_128_bytes-4),hl
ld hl,128
ld (free_128_bytes-2),hl
pop hl
ret
; The next 2 functions allow a program to check for legal
; drives BEFORE calling the BDOS, thus stopping fatal
; "select" errors ..
; Function 2 : return number of drives starting at A
ret_drives
ld a,(snum_drives)
ret
; Function 3 : return 1 if M drive implemented, 0 if not
ret_mdrive
ld a,1
ret
; Function 4 : return interrupt vector table base
ret_ivec_base
ld hl,pioa_vect
ret
; Function 5 : return ptr in hl to 128 bytes free
ret_128_byte_block
ld hl,free_128_bytes
xor a ;set Z flag - you can have it
ret
; Function 6 : purge all buffering for drive [c]
; (elsewhere)
; Function 7 : purge all directory buffers for drive [c]
; (elsewhere)
; Function 8 : return number of floppies in system (follow hards)
num_floppies
ld a,(snum_floppies)
ret
; Function 9 : tell BIOS to reselect drive on next access
ext_access
ld a,-1
ld (log_disk),a ;so match fails
ret
; Function 10 : set serial port baud rate to [c] until next warm boot
xbs_baud
ld a,c
jp set_baud
; Function 11 : receive serial character if available
; return Z if character in A, NZ if none available
; (RS_in is elsewhere)
; Function 12 : send serial RS232 character in C
send_RSc
ld a,c
jp RS_out
; Function 13 : set desired disk error mode in [c]:
; [c] = FF -> normal CP/M mode - bomb out if an error occurs
; [c] = 0 -> ignore errors (then use function 14 to detect them)
error_mode
ld a,c
ld (derr_mode),a
ret
; Function 14 : return status of last disk operation in [a]
; Z -> all OK
; NZ -> physical error occured
ret_status
ld a,(erflag)
ret
; Function 15 : Test status of key (in CON512.MAC)
;key_pressed
; Function 16 : Set programmable key buffer according to Microbee's definition
;set_mb_fkeys
; Function 17 : Read programmable key buffer
get_mb_fkeys
; zero fill as if all are empty (zero length)
push bc
ld b,12 ; 12 fkeys
{
ld (hl),0
#djnz
}
ld hl,1024 ; Maximum available space, hahahaha !!!
pop bc
set_mb_fkeys
xor a
ret
; Function 24 : call graphics driver (elsewhere)
; Function 25 : Call user program.
link_user
push hl
ld a,(user_page)
or a
jp z,no_grfx
call mem_page ; Enable user's page (+ screen at 8000h ??)
ld hl,(user_addr)
inc hl ; Entry point for XBIOS call at +3
inc hl
inc hl
ld (user_jp),hl
ld hl,recover_bmap
ex (sp),hl ; Restore HL / put return address on stack
user_jp equ $+1
jp 0 ; Jump to user program
; Function 26 : get data from the RTC chip (maybe over a network)
; this retries to ensure that no updates occurred during the read
; without disabling interrupts for too long
; Requires: HL = data pointer
; E = starting LOGICAL register (see ahead)
; B = number of registers to read
; Returns: A, HL, DE registers corrupted
get_rtc
call rtc_pars
{
call read_clock
call verify_clock
#if nz,cont
}
ret
; Function 27 : put data to the RTC chip (maybe over a network)
; this retries to ensure we don't get updated at the wrong time
; Requires: HL = data pointer
; E = starting LOGICAL register (see ahead)
; B = number of registers to write
; Returns: A, HL, DE registers corrupted
put_rtc
call rtc_pars
{
call write_clock
call verify_clock
#if nz,cont
}
ret
; support subroutines for get_rtc and put_rtc ..
; RTC_PARS:
; Requires: HL = data address
; B = number of registers to operate on
; E = LOGICAL starting register
; Returns: HL = pointer to RTC address list (xlat table+offset)
; DE = data address
; B = number of registers to operate upon
rtc_pars
push hl
ld hl,rtc_xlat
ld d,0
add hl,de ;addresses pointer
pop de ;data pointer
ret
; The RTC mapping table gives the following logical register numbers
; 0 Year of century
; 1 Month
; 2 Date
; 3 Weekday
; 4 Hours
; 5 Minutes
; 6 Seconds
; 7 Alarm hours
; 8 Alarm minutes
; 9 Alarm seconds
; A-D RTC Registers A-D
;
rtc_xlat
db 9,8,7,6,4,2,0,5,3,1,10,11,12,13
; READ_CLOCK: read B bytes from the RTC with addresses in the
; table at (hl) and put the data at (de)
; All regs preserved except A
read_clock
push bc
push de
push hl
{
; Sync to the UIP bit with interrupts disabled, and then restore
; after the operation has been done
call rtc_sync ;sync with DI
ld a,(hl)
out (rtc_addr),a
in a,(rtc_read)
ei
ld (de),a
inc hl
inc de
#djnz
}
com_pop
pop hl
pop de
pop bc
ret
; WRITE_CLOCK: as for READ_CLOCK, but write the data to the RTC
write_clock
push bc
push de
push hl
{
call rtc_sync
ld a,(hl)
out (rtc_addr),a
ld a,(de)
out (rtc_write),a
ei
inc hl
inc de
#djnz
}
jr com_pop
; VERIFY_CLOCK: return Z if the data at (de) matches the data in
; the RTC registers pointed to by (hl) for B bytes
verify_clock
push bc
push de
push hl
{
call rtc_sync
ld a,(hl)
out (rtc_addr),a
in a,(rtc_read)
ei
ld c,a
ld a,(de)
cp c
#if nz,brk
inc hl
inc de
#djnz
}
jr com_pop
; RTC_SYNC: Wait for Update in progress bit to go to 0, and
; return with interrupts disabled to allow one register operation
; Returns: AF destroyed
rtc_sync
{
ei
nop ;allow interrupt window
ld a,10
di
out (rtc_addr),a
in a,(rtc_read)
bit 7,a
#if nz,cont
}
ret
if scramble
jp_decrypt:
ret
nop
nop
encrypt_start:
db 98h,76h,54h,32h
endif
; select page number in A using table
mem_page
push hl
push de
if mem_128
and 3 ; max allowed is 128k
else
if telecomputer
and 7 ; max allowed is 256k
else
and 15 ; max allowed is 512k
endif
endif
ld hl,page_table
ld e,a
ld d,0
add hl,de
ld a,(hl)
pop de
pop hl
out (map_port),a
ret
; values corresponding to pages 0 .. max (15)
; may be modified for different memory configuration
; eg. 256k, 320k
page_table
; if mem_128
; db 14h,15h,16h,17h ; forced to be 128k only system
; else
; if telecomputer
; db 14h,15h,16h,17h ; Telecomputer seems to use bit 5
; db 34h,35h,36h,37h
; else
; db 14h,15h,16h,17h ; 'Standard' 512k system
; db 54h,55h,56h,57h ; with screen in at 8000h
; db 94h,95h,96h,97h
; db 0D4h,0D5h,0D6h,0D7h
; endif
; endif
if mem_128
db 0Ch,0Dh,0Eh,0Fh ; forced to be 128k only system
else
if telecomputer
db 0Ch,0Dh,0Eh,0Fh ; Telecomputer seems to use bit 5
db 2Ch,2Dh,2Eh,2Fh
else
db 0Ch,0Dh,0Eh,0Fh ; 'Standard' 512k system
db 4Ch,4Dh,4Eh,4Fh
db 8Ch,8Dh,8Eh,8Fh
db 0CCh,0CDh,0CEh,0CFh
endif
endif
; boot routines that can be stuck behind screen to cut down
; code size before F000h
common_boot
; Set CPU speed
ld a,(fast_cpu) ;True (FF) for fast
and speed_value ;Set appropriate bit
in a,(speed_port) ;Set hardware
; put system linkages at 0000h, 0005h and 0028h
; set BIOS warm start and BIOS pointer
; map bios_map
ld a,0C3H ;JP opcode
ld (biosv),a
ld hl,wboote
ld (biosv+1),hl
; set up system call entry point
ld (cpmv),a ;JP at 5
ld hl,bdosin
ld (cpmv+1),hl
; set up restart for extended BIOS calls
ld (xbs_rst),a
ld hl,x_bios_calls
ld (xbs_rst+1),hl
; make BIOS look at drive before using it
;;;; call ext_access
; set baud rate
ld a,(pr_baud)
call set_baud
; reset deblocking flags
xor a ;block/deblock initialization
ld (hstact),a ;set host inactive
ld (unacnt),a ;set for no unall. left
; initialise 6545-1/6845E
ld hl,crtc_tab+15
call crtc_fill ;set up 6545 as desired (patchable)
map sys_vdr
call copy_inv ;set up inverses
ret
; Call to check validity of ram disks and format if invalid
; system page must be enabled at this point
check_ramdisks
; Format M: if force_format is true
; or if previous size is different to current size
; Must also format N: if M: size is different
sflag 0,'2',sys_vdr
ld ix,check_ram_m ; previous value for M:, +1 = N:
ld iy,pages_for_md ; +2 = pages for N:
ld a,(iy)
cp (ix)
ld (ix),a
jr nz,fmt_m_n
ld a,(force_format)
or a
call nz,fmt_m
; Format N: if previous size is different
sflag 0,'3',sys_vdr
ld a,(iy+2)
cp (ix+1)
ret z
fmt_n:
ld a,(iy+2) ; is N: enabled ?
ld (ix+1),a ; this must be updated here
or a
ret z
ld a,(iy) ; find first N drive page
add a,3
call mem_page
call do_fmt
ld a,'N'
ld (9),a
ret
fmt_m_n:
call fmt_n
sflag 0,'4',sys_vdr
fmt_m:
map md_page_1
call do_fmt
ld a,'M'
ld (9),a
map sys_page
ret
do_fmt:
ld hl,0
ld de,1
ld bc,256*32-1 ; 256 directory entries is plenty
ld (hl),0E5h
ldir
ld hl,md_name ; put label into ram disk
ld de,0
ld c,16
ldir
xor a
ld b,16
d_f1:
ld (de),a
inc de
djnz d_f1
ret
; directory label for RAM disk ( '-RAMDISK.M: ' set to $SYS )
md_name
db 0,'-RAMDISKM',':'+80h,' ',0,0,0,0
; on every nth call to this subroutine
; and if status line enabled
; call status update routine (in system page, from bios file)
; all used registers must be saved
display_time
push hl
ld hl,time_cycle
dec (hl)
jr nz,dt_ret
ld (hl),cycle_max
push af
ld a,(s_line)
cp 25
jr nz,dt_ret1
map sys_vdr
call print_s_line
map bios_map
dt_ret1:
pop af
dt_ret:
pop hl
ret
; PRINTER and PUNCH routines
; allow for most printers ..
ptr_out
ld a,(send_lf)
or a
#if nz,nxt
ld a,c
; if send_lf=0, ignore linefeeds
cp lf
ret z ;ignore linefeeds
#mark
ld a,(iobyte)
bit 6,a
ld a,c
jp z,bpar_out ;PARALLEL printer
; must be SERIAL, so if not Xon/Xoff, just send it
; also entry point for PUNCH output
pun_out
ld a,(use_xonxoff)
or a
ld a,c
jp z,RS_out
; Xon/Xoff serial ..
{
call set_se ;update status
ld a,(x_flag)
or a
#if z,cont ;wait for ^Q to continue
}
ld a,c
jp RS_out ;send byte
; assume speed is already set, and check for Xon, Xoff
set_se
push af
call RS_in ;RS232 check and input
#if nz,nxt ;no char was received
res 7,a
sub xoff
ld (x_flag),a ;nz if O.K. to send
#mark
pop af
ret
; RS232 input routine to acc.
pun_in
{
call RS_in ;RS232 check and input
#if nz,cont
}
res 7,a
ret
; Common LIST status routine
all_listst
ld a,(iobyte)
and 0C0h
cp 80h ;PARALLEL printer?
jp z,p_listst
cp 0C0h ;serial mode?
ld a,0FFh
ret nz ;VDU is always ready
; serial status - either XON/XOFF or CTS based
ld a,(use_xonxoff)
or a
jp z,s_listst ;use CTS based status
; Use Xon/Xoff status
xlistst
call set_se ;update status
ld a,(x_flag)
or a
ret z ;not ready to print
cpl ;to 0FFH -> ready to print
ret
; Select drive and return hl= DPH address
; given bc=drive number, bit 0 of e=1 if not new unit
d_seldsk
; Swap A: and M:/N: if required
ld hl,swap_a_with_m ; = 'M'-'A' or 'N'-'A'
ld a,c
or a ; cp 'A'-'A'
jr z,ds_is_a
cp (hl)
jr nz,no_m_swap
ds_is_a
xor (hl)
ld c,a
no_m_swap
ld (sekdsk),a ;for deblocking routines
ld hl,md_dph ;request for M: ?
cp 'M'-'A'
ret z
ld hl,nd_dph ;request for N: ?
cp 'N'-'A'
jr nz,not_n
ld a,(pages_for_nd) ;is it there ?
or a
jr z,sel_err
; jp z,sel_err
ret
not_n
ld hl,snum_drives
cp (hl) ;drive A,B,C or D?
jr c,valid_drive
cp 'L'-'A'
jr nz,sel_err
ld a,(hl) ;Only allow L: if < 4 drives
cp 4
jr z,sel_err
ld a,'D'-'A' ;drive L -> D
ld (sekdsk),a ;sekdsk as well
ld c,a ;reg c as well
valid_drive
ld h,0
ld l,c
add hl,hl
add hl,hl
add hl,hl
add hl,hl ;hl=drive_num*16
ld a,e
ld de,dpbase ;Index into DPBASE
add hl,de
rrca ;test the new unit bit
ret c ;old unit, so don't worry
; a new unit has been selected, so check its format
push hl ;save start of this DPH
; purge everything buffered for drive c since disk has changed
call purge_c
ld a,c ;drive number
call log_select ;select that drive (hard)
#if nz,nxt ;error - no disk in drive etc.
;
; All the following denstiy select stuff is irrelevant if ...
if not preset_disks
ld hl,dden_byte ;=08H if double density, 0 if not
ld a,(sec_length) ;00=128; 01=256; 02=512
rlca ;*2
bit dden_sel,(hl)
jr z,sd_sel ;if single density format
dec a
sd_sel
#if m,next ;error - 128 byte double density !
cp 4
#if nc,nxt ;error - 512 single density or 1024 !
; now multiply by 18 (length of DPB+xlt_word+mask_byte)
rlca ;*2
ld l,a
rlca ;*4
rlca ;*8
rlca ;*16
add a,l ;*18
ld l,a
ld h,0
ld de,dpb_base ;first DPB in list
add hl,de ;hl points to correct DPB
push hl
ld a,c ;sekdsk (disk being selected)
call dpfnd ;hl=1+posn of DPB ptr in DPH
; de=old contents of DPB pointer, has this been set to user def'd?
ld a,e
pop de
{
cp low spare_dpb ;lower byte of spare dpb address?
#if z,brk ;if so, leave it alone
; set DPB pointer in DPH to point to correct DPB for this disk
ld (hl),d
dec hl
ld (hl),e
}
endif
pop hl ;pop off start of relevant DPH
ret
#mark
; Select error !
pop hl
sel_err
ld hl,usrdfd ;reboot to A0:
ld (hl),0
ld hl,0 ;tell CP/M its an error
ret
; Sector translate table routine (skewing done in h_setup)
sectran
ld h,b ;return exactly what we are given
ld l,c
ret
; select the drive in a (maybe logically)
; return z if no errors (a is undefined)
; or nz and a<>0 if an error occurs
; a "logical" disk is selected if the number of the disk
; asked for is greater than the last physical drive in
; the system
; Destroys C
log_select
ld c,a
ld a,(log_disk) ;previously selected disk
sub c
ret z ;same as before, return z,0
ld a,c
ld (log_disk),a ;same as required
;
or a
jr z,drive_a ;if drive A is selected
; compare with number of drives set by INIT
push hl
ld hl,snum_drives
cp (hl)
pop hl
jr c,log_fn ;select physical disk
; select a logical (virtual) disk
do_swap
ld a,(active) ;(active)=-1 -> log. disk in A
or a
jr nz,sel_a ;already swapped
sel_tog
cpl ;active <-> non-active
ld (active),a
ld a,c
; if not drive A, replace with drive L
or a
#if z,nxt
ld a,'L'-'A' ;logical drive !
#mark
add a,'A' ;put drive name into message
ld (name_mnt),a
push hl
push bc
ld hl,mnt_mess
call flash ;FLASH
; purge all buffers for drive a since disk has been changed
ld c,0
call purge_c
pop bc
pop hl
sel_a
xor a ;use drive A
log_fn
jp sel_floppy
;
; drive A has been selected, so if necc., swap
; and clear (active)
drive_a
ld a,(active)
or a
jr z,sel_a ;not active
jr sel_tog ;has wrong disk in drive A, so swap
;
;
d_sdm
ld (dmaadr),bc
ret
;
d_ssc
ld a,c
ld (seksec),a
ret
;
d_home
ld c,0
d_stk
ld a,c
ld (sektrk),a
ret
;
;
; Deblocked read and write a CP/M record (128 bytes)
d_read
push ix ;used to access DPB bits
call ix_tab ;point ix to relevant DPB
ld a,wrual ;treat read as unallocated
ld (wrtype),a
ld (readop),a ;set for read operation
jr alloc
;
d_write
push ix
call ix_tab ;point ix to relevant DPB
xor a ;set for write operation
ld (readop),a
ld a,c ;write type from CP/M
ld (wrtype),a
cp wrual ;unallocated write (first of block)
jr nz,chkuna
; this is the first record of an unallocated block, so
; remember where it is in case we are writing sequentially
ld hl,(sekdsk) ;disk and track number
ld (unadsk),hl
ld a,(seksec) ;sector number
ld (unasec),a
; now find out how many CP/M records in a "block", the fundamental
; allocation unit (1024 for small disks, 2048 for large)
; this is so that we know when the unallocated block is all
; gone (assuming sequential writes)
ld a,(ix+3) ;BLM
inc a
ld (unacnt),a
; check to see whether the current record being written is the
; next in a sequential series of writes
chkuna
ld hl,unacnt
xor a
cp (hl) ;any left ?
jr z,alloc ;if not, then preread (allocated)
dec (hl) ;decrement # remaining
; now see if this is the CORRECT record for seq. writing of a block
ld hl,(unadsk)
call comp ;compare (unadsk) with (sekdsk)
jr nz,alloc ;not the next record
ld hl,unasec ;compare (unasec) with (seksec)
ld a,(seksec)
cp (hl)
jr nz,alloc ;not the next record
; now step unatrk/unasec to next record so that we can tell whether
; the next record to be written after this one is the next of the block
inc (hl)
ld a,(hl)
cp (ix+0) ;# CP/M records per track
jr c,noovf ;stays on the same track
ld (hl),0 ;start with first sector
dec hl ;point to track number
inc (hl) ;next track inwards
; no pre-read is required, so set rsflag=0
noovf
xor a
jr alloc1
;
; not an unallocated record, so requires pre-read ..
alloc
xor a ;a=0
ld (unacnt),a ;kill current sequence
inc a ;a=1
alloc1
ld (rsflag),a
;
; rwoper:
xor a
ld (erflag),a ;reset error flag (no errors yet)
; now calculate (unskewed) host sector number
ld a,(seksec) ;CP/M record number
rlca ;once left
ld e,(ix+dsecmsk)
{
srl a ;then right to kill unwanted bits
rrc e
#if c,cont ;continue until mask shifted out
}
ld (sekhst),a
;
ld hl,hstact
ld a,(hl) ;see if already active
ld (hl),1 ;set it to active anyway
or a ;was it already?
jr z,filhst ;if it wasn't, may need to fill
; host buffer is active, but is it the same as seek buffer ?
ld hl,(hstdsk) ;disk # and track #
call comp ;compare (hstdsk) with (sekdsk)
jr nz,nomatch
ld hl,hstsec
ld a,(sekhst) ;physical but unskewed sector #
cp (hl)
jr z,match ;host buffer is the same as before
nomatch
call hst_flush ;write out old host buffer if necc.
; now set host buffer to suit "sek" sector
filhst
ld hl,(sekdsk) ;desired disk, track
ld (hstdsk),hl
ld a,(sekhst) ;physical (unskewed) sector #
ld (hstsec),a
; now pre-read (or just read) if neccessary
ld a,(rsflag)
or a
call nz,readhst
xor a
ld (hstwrt),a ;kill pending write flag
; copy data to or from buffer
match
ld a,(seksec) ;CP/M record number
and (ix+dsecmsk) ;keep ls bits to index into buffer
ld h,a
ld l,0
srl h
rr l ;hl=offset into buffer for record
ld de,hstbuf
add hl,de ;hl=start of record in buffer
ld de,(dmaadr) ;where in main memory to get/put
; now if it is a write, swap hl,de and mark the pending write
ld a,(readop)
or a
#if nz,nxt ;READing
ex de,hl ;swap so moving into buffer
inc a
ld (hstwrt),a ;(hstwrt)=1
#mark
ld bc,128 ;length of CP/M record
ldir ;nice quick transfer
; now flush buffer immediately if a directory write
ld a,(wrtype)
dec a ;directory write?
#if nz,nxt ;if not a directory write
ld a,(erflag) ;=1 if any errors occurred
or a
#if nz,nxt ;don't try to write if bad read
ld (hstwrt),a ;buffer written
call writehst
#mark
ld a,(erflag) ;return error code to CP/M
ld hl,derr_mode
and (hl) ;mask off errors maybe
pop ix
ret
; flush the host buffer if necc.
; All regs except [a] preserved
hst_flush
push bc
push de
push hl
ld a,(hstwrt)
or a
call nz,writehst
xor a
ld (hstwrt),a
pop hl
pop de
pop bc
ret
; write host sector with
; (hstdsk)= disk drive number to use (0-15)
; (hstsec)= unskewed physical sector number (0-17)
; (hsttrk)= track number (0-79)
writehst
ld a,(hstdsk)
cp 'M'-'A' ;M: or N: ?
jp nc,md_write
call fl_write ;do physical write (write-thru)
call db_sector_type
jr nz,ret_bmap ; can't be buffered
jp db_disk_write
fl_write
call hsetup
{
call z,wr_floppy ;write tk-d, sec-e, adr-hl
#if z,brk
in a,(status)
bit 6,a ;protect fault ?
ld a,1 ;CP/M wants a one
#if z,brk ;if not bomb out
; prompt with message and wait for RETURN
ld a,(log_disk)
add a,'A'
ld (wp_name),a ;store name of WPed drive
ld hl,wp_mess
call flash
call hsetup ;try to write once more
call z,wr_floppy
}
ret_err
ld hl,erflag
or (hl) ;OR in the error
ld (hl),a
jr ret_bmap
fl_read
push bc
call hsetup
call z,rd_floppy ;read tk-d, sec-e, adr-hl
pop bc
jr ret_err
; read host sector, parameters as for write
readhst
ld a,(hstdsk)
cp 'M'-'A' ; M: or N: ?
jp nc,md_read
call db_sector_type
jr nz,fl_read ; can't be buffered
call db_disk_preread ; get it from buffer if available
ret z ; yes it was so don't read from disk
call fl_read ; otherwise get it from disk
jp z,db_disk_postread ; only buffer if no error
ret_bmap:
map bios_map ; This is oh so important !!
ret
; return :
; d=(hsttrk) with b7=1 for side 1
; e=skewed (hstsec)
; hl=hstbuf and Z flag set, a=0
; OR NZ, a=1 if cannot select required drive
; destroys bc
hsetup
ld a,(hstdsk)
call log_select ;select logical (or physical disk)
ld a,1 ;standard error return value
ret nz ;hardware error
push ix ;save ix for (secdsk)
;
ld a,(hstdsk)
call x_tab ;ix=dpb for drive (hst_dsk)
; put track number in d so can select other side for "cylinder" disks
ld a,(hsttrk) ;desired track
bit 1,(ix+dflags)
jr nz,calc_sec ;don't modify tk number at all
bit 0,(ix+dflags)
jr z,old_format
; use bottom bit to select side number (cylinder format)
rrca
;
calc_sec
ld d,a
ld a,(hstsec) ;logical sector number (shifted)
add a,(ix+dxlt) ;add on start for this xlt table
ld c,a
ld b,0
ld hl,xlt_base
add hl,bc
;
ld e,(hl) ;get skewed sector number
ld hl,hstbuf ;where to put/get data
xor a ;indicate no errors
pop ix
ret
;
; handle formats which go in on side 0 first, and then
; come back out on side 1
old_format
cp 40
jr c,calc_sec ;track number 0..39
; range 40..79, so reduce it to 0..39 and set b7 for side 1
ld d,a
ld a,79
sub d
set 7,a ;indicate other side
jr calc_sec
;
;
; compare hl with (sekdsk)
comp
ld de,(sekdsk)
and a
sbc hl,de
ret
;
; find address of DPB (and xlt table address and secmsk)
; for the drive in a
; return address of DPH ptr + 1 in hl and DPB address in de
dpfnd
ld hl,Md_DPH+10
cp 'M'-'A'
jr z,dpf_got
ld hl,Nd_DPH+10
cp 'N'-'A'
jr z,dpf_got
ld h,0
ld l,a
add hl,hl
add hl,hl
add hl,hl
add hl,hl ;hl*drive_num*16
ld de,dpbase+10
add hl,de ;hl=posn of DPB ptr in DPH
dpf_got
ld e,(hl)
inc hl
ld d,(hl)
ret
;
; return ix pointing to the DPB etc for (sekdsk) drive
; destroy af
ix_tab
ld a,(sekdsk)
x_tab
push hl
push de
call dpfnd
push de
pop ix
pop de
pop hl
ret
; Read sector from either ramdisk
md_read
; select correct page and get addr in de, hl=hstbuf, bc=512
call md_addr
ex de,hl
ldir
out (map_port),a ; revert to bios map
xor a ; no error occured
ret
; Write sector to either ramdisk
md_write
call md_addr
ldir
out (map_port),a ; revert to bios map
ret
; get addresses for block move to host buffer
; returns: de = position in 0-7FFF of sector
; hl = hstbuf
; bc = mdrive sector size
; a = bios_map
md_addr
ld a,(hstsec)
ld e,0
srl a
rr e
ld d,a
ld a,(hsttrk)
rrca
rrca
rrca
ld b,a
rrca
and 70h
add a,d
ld d,a
ld a,b
add a,3
call mem_page
ld hl,hstbuf
ld bc,128
ld a,bios_map
ret
; I/O include files :
; console IO
include CON512T.MAC
; disk cache
include DB512.MAC
if scramble
end_encrypt:
db 12h,34h,56h,78h
endif
; floppy disk IO
include FL512.MAC
;;%%%%%%%%%%%
;; purge all directory entries for drive [c]
;; this is used before the BDOS delete/rename function is performed
;; to ensure that we don't write bad data on a changed disk
;; this also kills the deblocking buffer
;; All regs preserved except a
;purgedir_c
;;* ld a,flop_dir_trk ;purge all less/equal to this number
;;* #nxt
;; purge all entries for drive [c]
;; this is used during seldsk to ensure that the reboot
;; actually gets new data from the new disk
;; All regs preserved except a
;; bank 1 map set
;purge_c
;;* ld a,255 ;all sectors will be purged
;;*#mark
; call hst_flush
; xor a
; ld (hstact),a
; ret
;;%%%%%%%%%%%%
mnt_mess
defm ' INSERT "DISK '
name_mnt
defm 'M:" INTO DRIVE A, THEN PRESS <RETURN> ',80H
wp_mess
defm ' DISK '
wp_name
defm 'M: IS WRITE PROTECTED - PRESS <RETURN> TO TRY AGAIN ',80H
; Non-critical preset BIOS scratch ..
log_disk
db 0 ;disk currently selected
active
db 0 ;0 -> logical disk not active
x_flag
db 0FFh ;nz -> can send initially
offs_start
dw 0 ; offset for jumping to user interface
; first available address in system page (for shell, ccp)
sys_avail
dw bios-orgad+bdos_save_addr
derr_mode
db 0FFh ;0 to ignore disk error returns
time_cycle
db cycle_max ; update status line after n'th BIOS call
; The B##### SOD who wrote the 128k system has just caused me about three
; weeks of fruitless searching for an elusive bug. All because the B######
; put this label in the 'ds' section (implies uninitialised) when it MUST
; be initialised. If not then it can cause the BIOS to attempt to write to
; a random disk/track/sector.
; Fixed - 14/1/88
hstwrt
db 0 ;=1 if host buffer has pending write
cpm_end equ $ ;end marker for boot and reboot
; Non-critical uninitialised BIOS scratch ..
; DO NOT alter the relative postions of the following labels
sh_loaded equ $ ; nz if shell loaded
sh_start equ sh_loaded+1 ;where shell should go
sh_length equ sh_start+2 ;length of shell
sh_save_start equ sh_length+2 ;address of saved shell
ccp_loaded equ sh_save_start+2 ; ditto for CCP
ccp_start equ ccp_loaded+1
ccp_length equ ccp_start+2
ccp_save_start equ ccp_length+2
window_loaded equ ccp_save_start+2 ; nz if WINDOW.SYS loaded
temp_1 equ window_loaded+1 ; 2 bytes for any temp value
temp_2 equ temp_1+1
flag equ temp_2+1 ;indicates RS232 input during last o/p
;
; BDOS scratch
dmaadr equ flag+1 ;last address to transfer record to
;
sekdsk equ dmaadr+2 ;seek disk number (0-3)
sektrk equ sekdsk+1 ;seek track number
seksec equ sektrk+1 ;seek sector number
; do not rearrange the order of these ..
hstdsk equ seksec+1 ;host disk number (args to hstread/hstwrite)
hsttrk equ hstdsk+1 ;host track number
hstsec equ hsttrk+1 ;host sector number
;
sekhst equ hstsec+1 ;(seksec) shr secshf
hstact equ sekhst+1 ;=1 if host buffer active
; hstwrt must be initialised !!
;hstwrt equ hstact+1 ;=1 if host buffer has pending write
;
unacnt equ hstact+1 ;unalloc record count
unadsk equ unacnt+1 ;next unalloc record's disk
unatrk equ unadsk+1 ;next unalloc record's track
unasec equ unatrk+1 ;next unalloc record's sector
;
erflag equ unasec+1 ;=1 if an error occurred
rsflag equ erflag+1 ;=1 if host sector must be read
readop equ rsflag+1 ;=1 if read operation
wrtype equ readop+1 ;write type from CP/M
; This seems to be necessary to assemble - Why ??
; Z80.COM seems to be adding refs to it.
total_errs equ wrtype+1
last_equ equ total_errs+2
; Host buffer (512 bytes)
hstbuf equ 0FE00h
; somewhere to flash to
save_p equ hstbuf-60
if last_equ gt save_p
error too big for memory !!!
dw last_equ-save_p+zero
endif
.dephase
sys_page_r equ $
.phase 0
; Start of routines that are shoved down into the system page to stop
; those annoying memory overflow errors
; Check if this is a premium
; also perform a few other cold boot functions
check_premium:
if not telecomputer
; Find if premium : check if more than 1 PCG page
ld hl,pcg
ld a,81h ;PCG 1
out (vml),a
ld a,(hl) ;Get a test byte
cpl ;Complement it ("What lovely bits you have!")
ld c,a ;Remember it
ld a,80h ;PCG 0
out (vml),a
ld (hl),c ;Write new test value in PCG 0
ld a,81h
out (vml),a ;PCG 1
ld a,c ;Get new test value
sub (hl) ;if PCG 1 changed then not premium
jr z,not_prem
is_prem:
ld a,true
ld (is_premium),a
not_prem:
and 'P'
ld (smsg_premium),a
xor a
out (vml),a
; out (crtc),a
endif
if scramble
ld hl,0C3h+((low decrypt)*256)
ld (jp_decrypt),hl
endif
; Put end char at start of function key strings.
ld hl,fn_store
ld b,num_fn_keys
ld de,80h
{
ld (hl),fn_str_end
add hl,de
#djnz
}
; Place RET's at locations in system page, so calls fail before BIOS.SYS loaded
ld hl,bios_sys_start
ld b,+(3*20)
{
ld (hl),0C9h
inc hl
#djnz
}
; Clear status line
ld hl,vdu+(24*80)
ld b,80
{
ld (hl),' '
inc hl
#djnz
}
ret
; Copy inverses from ROM to PCG
copy_inv:
; push af
; push bc
; push de
; push hl
; fill in colour ram with desired value and fix inverses
ld a,40H ;turn on colour ram
out (col_port),a
c_b_3:
ld hl,col_ram
ld a,(col_char)
{
ld (hl),a
inc hl
bit 3,h
#if nz,cont
}
; Set up status line colour
ld a,(col_stat)
ld hl,status_start-2+800h
ld b,80
{
ld (hl),a
inc hl
#djnz
}
ld a,(col_mode) ;low intensity background (patchable)
out (col_port),a ;give it zero -> select PCG
; If premium then enable and zero attribute RAM
if not telecomputer
ld ix,is_premium
bit 0,(ix)
jr z,c_b_1
endif
ld a,90h
out (vml),a
ld hl,vdu
{
ld (hl),0
inc hl
bit 3,h
#if z,cont
}
; this is done later
; ld a,80h
; out (vml),a
c_b_1:
ld a,1
out (rom_port),a ; rom-read=1
if not telecomputer
bit 0,(ix)
jr z,c_i_1 ; not premium
endif
; is premium so load PCG 1 with bold
ld a,81h
out (vml),a
ld hl,vdu
ld de,pcg
copy1_bold:
ld a,(hl)
sla a
or (hl)
ld (de),a
inc hl
inc de
bit 3,h
jr z,copy1_bold
ld a,80h ; PCG 0 and leave graphics etc. enabled
out (vml),a
c_i_1:
ld hl,vdu ; now inverse
ld de,pcg
copy1_inv:
ld a,(hl)
cpl ; inverse character
ld (de),a
inc hl
inc de
bit 3,h
jr z,copy1_inv
xor a
out (rom_port),a ; back to display
; pop hl
; pop de
; pop bc
; pop af
ret
; table of pointers etc. for updating status line
sl_pointers:
; 'fn key'
dw in_fnstr ; pointer to value
db fn_mes-sl_msgs ; offset of message
db fn_sl-status_start ; offset on status line
db len_fn_mes ; length of message
; 'lock'
dw al_rev
db lock_mes-sl_msgs
db lock_sl-status_start
db len_lock_mes
; 'fn active'
dw fn_active
db fn_on_mes-sl_msgs
db fn_on_sl-status_start
db len_fn_on_mes
; 'a<>m'
dw swap_a_with_m
db swap_a_m_mes-sl_msgs
db swap_a_m_sl-status_start
db len_swap_a_m_mes
; 'fast'
dw fast_cpu
db fast_mes-sl_msgs
db fast_sl-status_start
db len_fast_mes
; status line messages
sl_msgs:
fast_mes:
db 'FAST'
len_fast_mes equ $-fast_mes
swap_a_m_mes:
db 'A<>M'
len_swap_a_m_mes equ $-swap_a_m_mes
lock_mes:
db 'LOCK'
len_lock_mes equ $-lock_mes
fn_on_mes:
db 'FKEY'
len_fn_on_mes equ $-fn_on_mes
fn_mes:
db 'PRESSED'
len_fn_mes equ $-fn_mes
; get shell / CCP out of system page
load_user_int
;; map sys_page
ld hl,sh_wanted ;0 for CCP, 1 for shell
ld a,(hl)
load_user_int_1
or a
jr z,l_u2
ld a,(sh_loaded)
or a
jr z,not_in_mem
ld hl,(sh_save_start)
ld de,(sh_start)
push de
ld bc,(sh_length)
jr l_u1
l_u2:
ld a,(ccp_loaded)
or a
jr z,not_in_mem
ld hl,(ccp_save_start)
ld de,(ccp_start)
push de
ld bc,(ccp_length)
l_u1:
ldir
pop hl ; hl --> start of shell/ccp
ld de,(offs_start)
add hl,de
ret
; wanted shell or ccp but it isn't in memory
not_in_mem:
ld a,(hl)
xor 1
ld (hl),a
jr load_user_int_1
; get bdos from system page
bdos_from_bp
ld hl,bdos_save_addr
ld de,orgad
ld bc,bios-orgad
ldir
ret
; Extended BIOS function call table ..
func_tab
dw set_mode ;0 - set CCP
dw set_mode ;1 - set shell
dw ret_drives ;2 - # drives to a
dw ret_mdrive ;3 - if Mdrive, a=1, else 0
dw ret_ivec_base ;4 - hl = ivec base
dw ret_128_byte_block ;5 - hl points to 128 bytes free
dw purge_c ;6 - purge all buffers for drive c
dw purgedir_c ;7 - purge dir for drive c
dw num_floppies ;8 - returns number of floppies
dw ext_access ;9 - inform BIOS to reselect drive
dw xbs_baud ;10 - set baud rate to c (0..)
dw RS_in ;11 - get RS232 char if available
dw send_RSc ;12 - send RS232 char in C
dw error_mode ;13 - set disk error mode (0=ignore)
dw ret_status ;14 - return status of disk operation
dw key_pressed ;15 - check if key is down
dw set_mb_fkeys ;16 - set Microbee style fkeys
dw get_mb_fkeys ;17 - get ditto. Haha - ignored!!!!
dw dud_ret ;18
dw dud_ret ;19
dw link_graphics ;20 - link to graphics driver
dw dud_ret ;21
dw dud_ret ;22
dw dud_ret ;23
dw link_graphics ;24 - link to graphics driver
dw link_user ;25 - link to user program
dw get_rtc ;26 - fetch data from RTC chip
dw put_rtc ;27 - put data to the RTC chip
func_end
; maximum function number allowed
func_max equ (func_end-func_tab)/2-1
end_sys_r equ $
.dephase
if ($-100h) gt (10240)
error too big to fit on system tracks !!!
dw zero+$-100h
endif
if ($-100h) lt 10240
; pad out code to occupy 10k for compatibility with SETSYS.
ds 10240-($-100h)
endif
end