home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
mbug
/
mbug097.arc
/
CON512T.MAC
< prev
next >
Wrap
Text File
|
1979-12-31
|
16KB
|
873 lines
; *************************************************************
; Console (and other) I/O drivers for 512k BIOS
; *************************************************************
; location of keyboard driver program in system page
keyboard_driver equ bios_sys_start
; Function keys:
fn_key_1 equ 81h ; value returned by scn_in
fn_str_end equ 0FFh ; end function char
fn_str_pause equ 0FEh ; pause char
fn_str_wait equ 0FDh ; wait for fkey char
window_char equ 0A0h ; value returned by scn_in to get window
user_char equ 0A1h ; value returned by scn_in to get user program
;
; language options ..
ENGLISH equ 1 ;=1 if english version
DANISH equ 0 ;=1 if danish version
SWEDISH equ 0 ;=1 if swedish version
;
VDUH equ 24
VDUW equ 80
;
; PIO B bits of interest
BEEP_BIT equ 6
SER_OUT equ 5 ;serial comm. lines
SER_IN equ 4
SER_CTS equ 3 ;printer busy line= clear to send
SER_DTR equ 2 ;DTR output
CASS_OUT equ 1
CASS_IN equ 0 ;cassette bits
;
; SEE ALSO RS232 routines for other timing changes
;
; software dependent timing for 3.375 Mhz
; dump values calculated for "cycle" loop
; formula reqd. is #T states for cycle = 26n + 97
; with video waiting OFF
LONG equ 104 ;1200 Hz
SHORT equ 50 ;2400 Hz
; load value taken for freq. of (1200+2400)/2
; n = ( f/3400 - 141 ) / 36 for GETBIT II
CUTOFF equ 28 ;receive half-way point (redundancy)
;BELL_T equ 164 ;G two above mid C (784hz)
bell_t equ 165
MILLISEC equ 122 ;disk timing parameter (vwait ON)
;
BELL_Z equ 100 ;fairly short (number of cycles)
; the following two are 100Hz multiples (CPU speed independent)
REPT_START equ 100 ;gives 1 second repeat delay
RP_SPEED equ 10 ;gives 10 Hz repeat rate
;
; 6545 register definitions
H_LPEN equ 16
L_LPEN equ 17
H_UPDATE equ 18
L_UPDATE equ 19
DUMMY equ 31
; status bit definitions
RETRACE equ 5
LPEN_FULL equ 6
UPDATE_RDY equ 7
; initialize 6545 crt controller - no int disabling
; but wait for 50 ms to allow font selection to take place
crtc_fill:
push bc
push hl
;
ld b,16
cz_a defl $
ld a,b
dec a
out (crtc),a
ld a,(hl)
out (crtc+1),a
dec hl
djnz cz_a
cz_aabc:
ld b,75 ;also works at 3.375 Mhz
call dely1
pop hl
pop bc
ret
;
; Console status. This routine actually gets a key from the keyboard if no key
; is already pending.
;
; return a=FF and nz if there would be a key to get,
; a=0 and z if nothing there
const:
; Must call status update as mchinw sits in a loop calling const
call display_time
xor a
disable_kbd:
ret
; ld a,(fn_active) ; Disables keyboard also (for testing)
; or a
; ret z
map sys_vdr
push hl
ld hl,save_key
ld a,(hl)
inc a
jr nz,still_got
jr try
got_key:
pop bc
pop hl
ld (hl),a
still_got:
or 0FFh
common_ret:
ld h,a
map bios_map
ld a,h
pop hl
ret
not_got_key:
pop bc
pop hl
ld a,0FFh
ld (hl),a
xor a
jr common_ret
; Try to get key from keyboard or from function string.
; It is here that the function keys and code conversions are handled.
try:
push hl
push bc
ld a,(in_fnstr)
or a
jr z,not_fn
ld hl,pause_count
ld a,(hl)
dec a
jp m,not_pse
ld (hl),a ; if in pause then decr count and no key
jr not_got_key
not_pse:
ld hl,(fn_ptr)
start_fn:
; if <ESC> is pressed then stop reading function string
call scn_in
; jr nz,esc_not_pr
cp '['-40h
jr nz,esc_not_pr
end_fn:
xor a ; and quit function string
ld (in_fnstr),a
jr not_got_key
esc_not_pr:
ld a,(hl) ; get next 'key'
inc hl
ld (fn_ptr),hl
cp fn_str_end ; quit
jr z,end_fn
ld b,a
ld a,l ; quit next time if reached end
and 7Fh
ld a,b
jr nz,not_end_fn
ld hl,in_fnstr
ld (hl),false
not_end_fn:
cp fn_str_pause
jr nz,not_pse1
ld hl,pause_count ; if pause then wait 20 calls (or 50)
ld (hl),30 ; or 30? Pick a number, any number.
jr z,not_got_key
not_pse1:
cp fn_str_wait
jr nz,not_wait
ld hl,in_fnstr
ld a,(hl) ; Wait until this function key is pressed again
ld (fn_waiting),a
ld (hl),0
jr not_got_key
not_wait:
cp fn_key_1 ; if function number then chain to new fn key
jr c,got_key
cp fn_key_1+num_fn_keys
jr nc,got_key
jr chain_fk
; Get key from keyboard, if function key pressed and fn keys enabled
; then start reading from function string.
not_fn:
; ld a,(fn_active) ;%%%%%
; or a
; jr z,not_got_key
call scn_in
jr nz,not_got_key
cp fn_key_1
jp c,got_key
cp fn_key_1+num_fn_keys
jr c,chain_fk
cp window_char
jr z,control_window
cp user_char
jr z,link_user_kbd
; now must convert cursor keys (90h..9Fh) to correct value
cp 90h
jp c,got_key
cp 0A0h
jp nc,got_key
ld hl,curs_key_tab-90h
ld c,a
ld b,0
add hl,bc
ld a,(hl)
or a ; if 0 then no char for this key
jp z,not_got_key
jp got_key
chain_fk:
ld h,a
ld a,(fn_active)
or a
jp z,not_got_key
ld a,h
ld (in_fnstr),a
ld hl,fn_waiting
cp (hl)
ld (hl),0
jp z,not_pse
sub fn_key_1 ; convert to 0..11
ld hl,fn_store ; start of stored strings
rr a
rr l ; 128 bytes each, -> LS bit to L
add a,h ; MS bits to H
ld h,a
ld a,(hl)
cp fn_str_end
jp z,not_got_key
jp start_fn
control_window:
xor a
ld (fn_waiting),a
ld a,(window_loaded)
or a
jr z,no_w
ld hl,not_got_key ; return from subr to not_got_key routine
push hl
ld hl,(window_addr)
jp (hl)
; WINDOW.SYS not loaded so toggle fn keys on/off
no_w:
ld hl,fn_active
ld a,(hl)
cpl
ld (hl),a
jp not_got_key
; link to user program
link_user_kbd:
ld a,(user_page)
or a
jp z,not_got_key
ld hl,not_got_key ; return to this address
push hl
call mem_page ; Enable user's page (+ screen at 8000h ??)
ld hl,(user_addr) ; 'Call' program at offset of 0
jp (hl)
mchinw:
call mchinl
jr z,mchinw
ret
; DGOS type (and CP/M CONIN) keyboard routines
; return Z if no key available (and a=0)
; NZ and a=char if there is one there
mchinl:
call const
ret z ;no new key available
; CONST returned nz, so there must be a key at (save_key) ..
push hl
ld hl,save_key
ld a,(hl)
ld (hl),-1 ;reset save_key
pop hl
ret ;(status is nz)
;
; calls to keyboard driver program in system page
;
scn_in:
map sys_vdr
jp keyboard_driver
; XBIOS call 15
key_pressed:
ld a,c
is_closed:
push af
map sys_vdr
pop af
call keyboard_driver+3
jp recover_bmap
; call scn_in and return with other page (in A) enabled ( for FLASH routine )
scn_in_m:
ld (temp_2),a
map sys_vdr
call keyboard_driver
push af
ld a,(temp_2)
out (map_port),a
pop af
ret
; Character to be output is in C
; (conout)
; ADM-3A emulator plus some functions from the TVI-912C terminal
; i.e. line insert, delete, clear to eol and eop
; ### put in char insert and delete from BETI
INV_SET:
rrca ;get bit 7=1 if char was ')' = 029H
and 080H
ld (inv_byte),a
jp kilseq
;
LINE_INS:
call do_cret
push hl ;save posn. at start of curr. line
ex de,hl ;de=start of line
ld hl,vdu+vduw*vduh-1 ;end of last line
push hl
and a
sbc hl,de
ld b,h ;enough bytes?
ld c,l
pop de
ld hl,vdu+vduw*(vduh-1)-1
lddr
;
; due to lddr
pop hl ;get start of curr. line
EOL_CLR:
call bclr_tel ;clear line at (hl) for vduw-b
jp kilseq
;
; delete the line underneath the cursor
LINE_DEL:
call do_cret
push hl
push hl ;initial dst is start of curr line
ld bc,vduw
add hl,bc
push hl ;save start of line under curr line
ex de,hl ;de=start of line under curr. line
ld hl,vdu+vduh*vduw+1
and a
sbc hl,de
ld b,h ;enough bytes to move and >0
ld c,l
pop hl ;initial src = line under curr. line
pop de ;initial dst = curr line
ldir
; also b=0 (column position)
call bclr_bot ;clear bottom line (if b=0)
pop hl
jr kilseq
CURS_SET:
sub '{' ;'{' turns cursor off -> a=0
ld (curs_flag),a
jr kilseq
ESCSEQ:
dec a
jr z,final
dec a
ld a,c
jr z,second
FIRST:
cp '}'
jr z,curs_set
cp '{'
jr z,curs_set
cp ')' ;half intensity for 912C
jr z,inv_set
cp '(' ;hi off for 912C
jr z,inv_set
cp '='
jr z,cur_pos ;cursor positioning
res 5,a ;lower case -> upper case
cp 'E' ;line insert
jr z,line_ins
cp 'R'
jr z,line_del ;line delete
cp 'T'
jr z,eol_clr ;clear to end of line
cp 'Y' ;page erase
jr z,cls_entry
xor a
ld (esctrp),a ; kill ESC sequence anyway
ld a,c
cp 'Z' ; if >= Z then attribute, so do space instead
jr c,kilseq
ld c,' '
jr put_c
CLS_ENTRY:
call z,clr_tep
jr kilseq ; kill sequence
;
CUR_POS:
ld a,2
jr rst_esc ; was esc =
;
FINAL:
ld a,c
sub 020H
ld b,a ;column position
ld hl,(linpos) ;really ld l,(linpos)
ld h,0
ld d,h
ld e,l
add hl,hl
add hl,hl
add hl,de
add hl,hl
add hl,hl
add hl,hl
add hl,hl ; mult by 80 decimal
ld e,a
add hl,de ; add col pos
; keep it within bounds of 2048 (columns get confused anyway)
ld a,h
and 07H
ld h,a
ld de,vdu
add hl,de ; add base
KILSEQ:
xor a
jr rst_esc
;
SECOND:
sub 020H
ld (linpos),a
ld a,1
jr rst_esc
;
SETESC:
ld a,3
RST_ESC:
ld (esctrp),a
jr vrecovr
;
; home and clear screen, entered with Z flag set
CLRVDU:
ld hl,vdu
ld b,0 ;first column
jr cls_entry
;
VDUOUT:
push af
push bc
push de
push hl
;
ld hl,(cursor)
call csr_flip ; invert (hl)
ld a,(colpos) ; get column position in b ..
ld b,a
ld a,(esctrp) ; is esc sequence in progress?
or a
jp nz,escseq
PUT_C:
ld a,c
cp 020H
jr c,try_ctrl ;ctrl char ?
ld a,(inv_byte)
or c
ld (hl),a
CSRIGHT:
inc hl
inc b
EOL_CHECK:
ld a,b
sub vduw
jr nz,chkscr
ld b,a
CHKSCR:
ex de,hl
ld hl,vdu+vduw*vduh-1
or a
sbc hl,de
ex de,hl
jr nc,vrecovr
; scroll the screen ...
push bc ; save old column posn.
push hl
ld bc,vduw*vduh-vduw
ld hl,vdu+vduw
ld de,vdu
ldir
; .. b=0 from ldir
call bclr_bot ; clear bottom line (if b=0)
pop hl
pop bc ; get old column posn.
ld de,-vduw
add hl,de
jr vrecovr
;
TRY_CTRL:
cp 01EH
jr z,vhome
cp 01BH ; escape
jr z,setesc
cp 01AH
jr z,clrvdu
cp 09H ; tab function to '8' boundaries only
jr z,tab
cp 08H ; backspace
jr z,bspc
cp 0AH
jr z,lfeed
cp 0BH ; cursor up a line
jr z,csup
cp 0CH ; cursor to right (not CLS)
jr z,csright
cp 07H ; bell code
jr z,beep
cp 0DH ; carriage return
call z,do_cret
VRECOVR:
ld a,b
RECOV1:
ld (colpos),a
RECOV2:
ld (cursor),hl
call csr_flip
pop hl
pop de
pop bc
pop af
jp retvdu ; switch VDU to F000, return
;
CSUP:
ld de,-vduw
add hl,de
ld a,h
cp +(vdu shr 8)
jr nc,recov2
LFEED:
ld de,vduw
add hl,de
jr chkscr
;
VHOME:
ld hl,vdu
xor a
jr recov1
;
BSPC:
dec hl
dec b
ld a,h
cp +(vdu shr 8)-1
jr z,vhome
bit 7,b
jr z,vrecovr
ld b,vduw-1
jr vrecovr
;
TAB:
ld a,(inv_byte)
or ' '
ld (hl),a
inc hl
inc b
ld a,b
and 07H ; are we at tab stop yet ?
jr nz,tab
jp eol_check
;
BEEP:
push de
ld a,(fast_cpu)
or a
ld d,bell_t ; 6.75 MHz
jr nz,b_1
ld d,+(bell_t shr 1) ; 3.375 MHz
b_1:
out (vwait_off),a
ld c,2*bell_z ; 100 cycles of tone
in a,(beep_port)
B_LOOP:
xor 40h
out (beep_port),a
ld b,d
DJ1:
ld a,a
ld a,a
ld a,a
djnz dj1
dec c
jr nz,b_loop
pop de
jr recov2
;
; subroutine to do "carriage return"
; (also used by delete line, insert line)
DO_CRET:
ld a,b
or a
ret z
CRLOOP:
dec hl
djnz crloop
ret
;
; clear bottom line, assuming b=0 ..
BCLR_BOT:
ld hl,vdu+(vduh-1)*vduw ;start of last line
; clear to end of line at (hl) for vduw-b bytes
BCLR_TEL:
ld a,vduw
sub b
push hl
CLRT_1:
ld (hl),' '
inc hl
dec a
jr nz,clrt_1
pop hl
ret
;
; clear to end of page from (hl)
CLR_TEP:
push hl
ex de,hl
ld a,' '
CLRTP:
ld (de),a
inc de
ld hl,-(vdu+vduh*vduw+1) ;clear one past end of vdu
add hl,de
jr nc,clrtp
pop hl
ret
;
CSR_FLIP:
ld a,(curs_flag)
or a
ret z
ld a,(hl)
xor 80h
ld (hl),a
ret
; Software UART routines which do not need to live below
; 0F000H ..
SET_BAUD:
; look up delay routine in table and place in simult
push hl
push de
ld l,a
ld h,0
add hl,hl ;*2
ld de,baud_tab
add hl,de
ld e,(hl)
inc hl
ld d,(hl)
ld (simult),de
pop de
pop hl
ret
BAUD_TAB:
defw l300
defw l600
defw l1200
defw l2400
defw l4800
defw l1200 ;provision for 110 baud
RS_OUT:
push af
push bc
push de
push hl
push ix
ld ix,num_data ;start of RS scratchpads
ld l,0 ;start bit
ld b,(ix+num_data-num_data)
bit 3,b
jr z,eight ;if eight data bits
res 7,a
EIGHT:
rrca ;rotating does not affect parity
adc hl,hl
djnz eight
; now calculate parity if reqd. to do so
ld b,(ix+parity-num_data)
dec b
jr z,no_par ;no parity at all
dec b
jr z,odd_par ;odd parity is set
; even parity is selected ..
or a ;set P flag
jp pe,send_par ;parity is already even
; parity of data is odd, so add a bit to make it even
W_PAR:
scf ;turn on extra parity bit
jr send_par
ODD_PAR:
or a
jp pe,w_par ;turn on P bit to make it odd
SEND_PAR:
adc hl,hl
NO_PAR:
ld b,(ix+adj_fact-num_data) ;must rotate hl to starting posn.
ALIGN:
scf
adc hl,hl
djnz align
ld d,(ix+totalq-num_data) ;tx control
ld e,0
;
; now wait for modem ready i.e. CTS to go high
W_CTS:
in a,(piob_data)
bit ser_cts,a
jr z,w_cts
;
di ;stop int_rtn during this
call jp_simul
ld a,(flag) ;z -> we got a char in
or a
call z,chk_break ;store character, wait for mark
;
ei
pop ix
pop hl
pop de
pop bc
pop af
ret
; return char in A and Z, or NZ if no char available from q
RS_IN:
push de
push hl
push ix
ld hl,(w_ptr)
ld de,(r_ptr)
or a
sbc hl,de
jr nz,got_RS
; buffer empty, so allow it to be refilled
in a,(piob_data)
set ser_dtr,a
out (piob_data),a
or -1 ;nz => got nothing
RS_EX:
pop ix
pop hl
pop de
ret
GOT_RS:
call next_RS
; update count of "safe" space remaining in buffer
di
ld hl,(dtr_limit)
inc hl
ld (dtr_limit),hl
ei
ld a,(ix+0) ;get data first
ld (r_ptr),de ;and acknowledge
cp a
jr RS_ex
; return 0 if busy, FF if ready for serial printer
; used by DESPOOL (can also be used by WordStar)
S_LISTST:
in a,(piob_data)
bit ser_cts,a
jr nz,prnt_ready
xor a
ret
PRNT_READY:
ld a,0FFH
ret
flash_max equ 60 ;number of bytes to flash
; flash inverse message to top of screen
flash:
map vdr_map
push hl ;save message location
ld hl,vdu
ld de,save_p
ld bc,flash_max
ldir
pop hl
;
ld de,vdu
fl_loop:
ld a,(hl)
xor 080H
jr z,fl_wait
ld (de),a
inc de
inc hl
jr fl_loop
fl_wait:
call scn_in
cp cr
jr nz,fl_wait
ld hl,save_p
ld de,vdu
ld bc,flash_max
ldir
map bios_map
ret
BPAR_OUT:
push hl
ld hl,par_flag
PAR_O1:
bit 0,(hl)
jr nz,par_o1
ld (hl),-1
out (pioa_data),a ;send byte to printer
pop hl
ret
;
P_LISTST:
ld a,(par_flag)
cpl
ret
INV_BYTE: defb 0 ;=080H if CONOUT in "INVERSE" mode
ESCTRP: defb 0 ;indicates esc sequence
CURS_FLAG: defb -1 ;non-zero if cursor is ON
SAVE_KEY: defb -1 ;=-1 if no keys saved, else=ascii code
pause_count: db 0 ;count of number of con status calls to ignore
;disable_kbd: db true ; initially disabled
fn_waiting: db 0 ; Function key currently waiting for repress