Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 3.X/CPM 3.0/SOURCE/putrsx.asm
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

881 lines
20 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

title 'PUT.RSX 3.0 - CP/M 3.0 Output Redirection - August 1982'
;******************************************************************
;
; PUT 'Output Redirection Facility' version 3.0
;
; 11/30/82 - Doug Huskey
; This RSX redirects console or list output to a file.
;******************************************************************
;
;
; generation procedure
;
; rmac putrsx
; xref putrsx
; link putrsx[op]
; ERA put.RSX
; REN put.RSX=putRSX.PRL
; GENCOM put.com put.rsx
;
; initialization procedure
;
; PUTF makes a RSX function 60 call with a sub-function of
; 128. PUTRSX returns the address of a data table containing:
;
; init$table:
; dw kill ;remove PUT at warmboot flg
; dw 0 ;reserved
; dw bios$output ;BIOS entry point into PUT
; dw putfcb ;FCB address
;
; PUTF initializes the data are between movstart: and movend:
; and moves it into PUT.RSX. This means that data should not
; be reordered without also changing PUTF.ASM.
;
;
true equ 0ffffh
false equ 00000h
;
bios$functions equ true ;intercept BIOS console functions
remove$rsx equ false ;this RSX does its own removal
;
; low memory locations
;
wboot equ 0000h
wboota equ wboot+1
bdos equ 0005h
bdosl equ bdos+1
buf equ 0080h
;
; equates for non graphic characters
;
ctlc equ 03h ; control c
ctle equ 05h ; physical eol
ctlh equ 08h ; backspace
ctlp equ 10h ; prnt toggle
ctlr equ 12h ; repeat line
ctls equ 13h ; stop/start screen
ctlu equ 15h ; line delete
ctlx equ 18h ; =ctl-u
ctlz equ 1ah ; end of file
rubout equ 7fh ; char delete
tab equ 09h ; tab char
cr equ 0dh ; carriage return
lf equ 0ah ; line feed
ctl equ 5eh ; up arrow
;
; BDOS function equates
;
cinf equ 1 ;read character
coutf equ 2 ;output character
crawf equ 6 ;raw console I/O
creadf equ 10 ;read buffer
cstatf equ 11 ;status
lchrf equ 5 ;print character
pbuff equ 9 ;print buffer
resetf equ 13 ;reset drive
openf equ 15 ;open file
closef equ 16 ;close file
delf equ 19 ;delete file
dreadf equ 20 ;disk read
writef equ 21 ;disk write
dmaf equ 26 ;set dma function
userf equ 32 ;set/PUT user number
resdvf equ 37 ;reset drive function
flushf equ 48 ;flush buffers function
scbf equ 49 ;set/PUT system control block word
loadf equ 59 ;Program load function
rsxf equ 60 ;RSX function call
resalvf equ 98 ;reset allocation vector
pblkf equ 111 ;print block to console
lblkf equ 112 ;print block to list device
ginitf equ 128 ;GET initialization sub-function no.
gkillf equ 129 ;GET delete sub-function no.
gfcbf equ 130 ;GET file display sub-function no.
pinitf equ 132 ;PUT initialization sub-function no.
pckillf equ 133 ;PUT console delete sub-function no.
plkillf equ 137 ;PUT list delete sub-function no.
pcfcbf equ 134 ;return PUT console fcb address
plfcbf equ 138 ;return PUT list fcb address
jinitf equ 140 ;JOURNAL initialization sub-function no.
jkillf equ 141 ;JOURNAL delete sub-function no.
jfcbf equ 142 ;return JOURNAL fcb address
;
; System Control Block definitions
;
scba equ 03ah ;offset of scbadr from SCB base
ccpflg equ 0b3h ;offset of ccpflags word from page boundary
ccpres equ 020h ;ccp resident flag = bit 5
bdosoff equ 0feh ;offset of BDOS address from page boundary
errflg equ 0aah ;offset of error flag from page boundary
conmode equ 0cfh ;offset of console mode word from pag. bound.
outdel equ 0d3h ;offset of print buffer delimiter
listcp equ 0d4h ;offset of ^P flag from page boundary
usrcode equ 0e0h ;offset of user number from pg bnd.
dcnt equ 0e1h ;offset of dcnt, searcha & searchl from pg bnd.
constfx equ 06eh ;offset of constat JMP from page boundary
coninfx equ 074h ;offset of conin JMP from page boundary
;
;
;******************************************************************
; RSX HEADER
;******************************************************************
serial: db 0,0,0,0,0,0
trapjmp:
jmp trap ;trap read buff and DMA functions
next: jmp 0 ;go to BDOS
prev: dw bdos
kill: db 0FFh ;Remove at wstart if not zero
nbank: db 0
rname: db 'PUT ' ;RSX name
space: dw 0
patch: db 0
;******************************************************************
; START OF CODE
;******************************************************************
;
; ABORT ROUTINE
;
puteof: ;close output file and abort
lda cbufp
ora a
jz restor
mvi e,ctlz
call putc
jmp puteof
;
;******************************************************************
; BIOS TRAP ENTRY POINT
;******************************************************************
;
;
; ARRIVE HERE ON EACH INTERCEPTED BIOS CALL
;
;
bios$output:
;
if bios$functions
;
;enter here from BIOS constat
mov e,c ;character in E
lda bdosfunc ;BDOS function to use
mov c,a
mvi a,1 ;offset in exit table = 1
jmp bios$trap
endif
;
;
;******************************************************************
; BDOS TRAP ENTRY POINT
;******************************************************************
;
;
; ARRIVE HERE AT EACH BDOS CALL
;
trap:
;
if bios$functions
;
xra a
biostrap:
;enter here on BIOS calls
sta exit$off
endif
pop h ;return address
push h ;back to stack
lda trapjmp+2 ;PUT.RSX page address
cmp h ;high byte of return address
jc exit ;skip calls on bdos above here
mov a,c
cpi rsxf
jz rsxfunc ;check for initialize or abort
cpi dmaf
jz dmafunc ;save users DMA address
cpi 14 ;reset function + 1
jc tbl$srch ;search if func < 14
cpi 98
jnc tbl$srch ;search if func >= 98
cpi resdvf
jz tbl$srch ;search if func = 37
;
; EXIT - FUNCTION NOT MATCHED
;
exit:
if not bios$functions
;
exit1: jmp next ;go to next RSX or BDOS
else
lda exit$off ;PUT type of call:
exit1: lxi h,exit$table ;0=BDOS call, 1=BIOS call
endif
tbl$jmp:
; a = offset (rel 0)
; hl = table address
add a ;double for 2 byte addresses
call addhla ;HL = .(exit routine)
mov b,m ;get low byte from table
inx h
mov h,m
mov l,b ;HL = exit routine
pchl ;gone to BDOS or BIOS
tbl$srch:
;
;CHECK IF THIS FUNCTION IS IN FUNCTION TABLE
;if matched b = offset in table (rel 0)
;FF terminates table
;FE is used to mark non-intercepted functions
;
lxi h,func$tbl ;list of intercepted functions
mvi b,0 ;start at beginning
tbl$srch1:
mov a,m ;get next table entry
cmp c ;is it the same?
jz intercept ;we found a match, B = offset
inr b
inx h
inr a ;0FFh terminates list
jnz tbl$srch1 ;try next one
jmp exit ;end of table - not found
;
;
;******************************************************************
; REDIRECTION PROCESSOR
;******************************************************************
;
;
; INTERCEPTED BDOS FUNCTIONS ARRIVE HERE
;
; enter with
; B = routine offset in table
; C = function number
; DE = BDOS parameters
intercept:
;switch to local stack
lxi h,0
dad sp
shld oldstack
lxi sp,stack
redirect:
push d ;save info
push b ;save function
lhld scbadr
;
;are we active now?
;
lda program
ora a ;program output only?
cnz ckccp ;if not, test if CCP is calling
jz cklist ;jump if not CCP or program output
mov a,c
cpi 0ah ;is it function 10?
jnz skip ;skip if not
lxi h,ccpcnt ;decrement once for each
dcr m ;CCP function 10
cm puteof ;if 2nd appearance of CCP
jmp skip ;if CCP is active
;
;check for list processing and ^P status
;
cklist:
lda list
ora a ;list redirection?
jz ckecho ;jump if not
mvi l,listcp ;HL = .^P flag
mov a,m
ora a ; ^P on?
jnz setecho ;set echo on if so
mov a,b
cpi 2 ;console function?
jnc skip ;skip if so
ckecho: lda echoflg ;echo parameter
setecho:
sta echo
;
;go to function trap routine
;
gofunct:
lxi h,retmon ;program return routine
push h ;push on stack
mov a,b ;offset
lxi h,trap$tbl
jmp tbl$jmp ;go to table address
;
;
rawio:
;direct console i/o - read if 0ffh
;returns to retmon
mov a,e
cpi 0fdh
jc putchr
cpi 0feh
rz ;make the status call (FE)
jc conin ;make the input call (FD)
call next ;call for input/status (FF)
ora a
jz retmon1
jmp conin1
;
;input function
;
conin:
call exit ;make the call
conin1: mov e,a ;put character in E
push psw ;save character
call conout ;put character into file
pop psw ;character in A
;
; RETURN FROM FUNCTION TRAP ROUTINE
;
cpi cr
jnz retmon1
retmon2:
;output linefeed before returning
push psw ;save character
lda echo
ora a ;no echo mode
mvi e,lf
mvi c,coutf
cz next ;output lf if so
lda input
ora a
cnz conout
pop psw ;restore character
retmon1:
;return to calling program
lhld old$stack
sphl
mov l,a
retmon0:
ret ;to calling program
;
retmon:
;echo before returning?
lda echo
ora a
jz retmon1 ;return to program if no echo
;otherwise continue
;
; PERFORM INTERCEPTED BDOS CALL
;
skip:
;restore BDOS call and stack
pop b ;restore BDOS function no.
pop d ;restore BDOS parameter
lhld old$stack
sphl
jmp exit ;goto BDOS
;******************************************************************
; BIOS FUNCTIONS (REDIRECTION ROUTINES)
;******************************************************************
;
putchr:
;put out character in E unless putting input
lda input! ora a! rnz ;return (retmon) if input redirection
listf:
conout:
conoutf:
ctlout:
;send E character with possible preceding up-arrow
mov a,e! cpi ctlz! jz ctlout1 ;always convert ^Z
call echoc ;cy if not graphic (or special case)
jnc putc ;skip if graphic, tab, cr, lf, or ctlh
ctlout1:
;send preceding up arrow
push psw! mvi e,ctl! call putc ;up arrow
pop psw! ori 40h ;becomes graphic letter
mov e,a ;ready to print
;(drop through to PUTC)
;
;
; put next character into file
;
;
putc: ;write sector if full, close in each physical block
;abort PUT if any disk error occurs
;character in E
lxi h,cbufp
mov a,m ; A = cbufp
push h
inx h ;HL = .cbuf
call addhla ;HL = .char
mov m,e ;store character
pop h
inr m ;next chr position
rp ;minus flag set after 128 chars
;
; WRITE NEXT RECORD
;
write:
mvi c,writef
call putdos
cnz restor ;abort RSX if error
xra a
sta cbufp ;reset buffer position to 0
lxi h,record
dcr m ;did we cross the block boundary?
rp ;return if not
call close ;close the file if so
cnz restor ;abort RSX if error
lxi h,blm ;HL = .blm
mov a,m
dcx h
mov m,a ;set record = blm
ret
;
; CLOSE THE FILE
;
close:
mvi c,closef
;
; PUT FILE OPERATION
;
putdos:
push b ;function no. in C
lxi d,cbuf
call setdma ;set DMA to our buffer
pop b ;function no. in C
lhld scbadr
push h ;save for restore
lxi d,sav$area ;10 byte save area
push d ;save for restore
call mov7 ;save hash info in save area
mvi l,usrcode ;HL = .BDOS user number in SCB
call mov7 ;save user, dcnt, search addr, len &
dcx h ; multi-sector count
mvi m,1 ;set multi-sector count=1
mvi l,usrcode ;HL = .BDOS user number
lxi d,putusr
ldax d
mov m,a ;set BDOS user = putusr
inx d ;DE = .putfcb
call next ;write next record or close file
pop h ;HL = .sav$area
pop d ;DE = .scb
push psw ;save A (non-zero if error)
call mov7 ;restore hash info
mvi e,usrcode ;DE = .user num in scb
call mov7 ;restore dcnt search addr & len
lhld udma
xchg
call setdma ;restore DMA to program's buffer
pop psw
ora a
ret ;zero flag set if successful
;
; CLOSE FILE AND TERMINATE RSX
;
restor:
call close
lxi d,close$err
cnz msg ;print message if close error
lxi h,0ffffh
shld rsxfunctions ;set killf and fcbf to inactive
;
;set RSX aborted flag
;
lxi h,kill ;0=active, 0ffh=aborted
mvi m,0ffh ;set to 0ffh (in-active)
;are we the bottom RSX, if so remove ourselves immediately
;to save memory
lda bdosl+1 ;get high byte of top of tpa
CMP H ;Does location 6 point to us
if remove$rsx
jnz bios$fixup ;done, if not
lhld next+1
shld bdosl
xchg
lhld scbadr
mvi l,bdosoff ;HL = "BDOS" address in SCB
mov m,e ;put next address into SCB
inx h
mov m,d
xchg
mvi l,0ch ;HL = .previous RSX field in next RSX
mvi m,7
inx h
mvi m,0 ;put previous into previous
else
mvi c,loadf
lxi d,0
cz next ;fixup RSX chain, if this RSX on bottom
endif
if bios$functions
bios$fixup:
;
;restore bios jumps
lda restore$mode ;may be FF, 7f or 0
inr a
rz ; FF = no bios interception
lhld wmsta ;real warm start routine
xchg
lhld wmjmp ;wboot jump in bios
mov m,e
inx h
mov m,d ;restore real routine in jump
lhld biosout ;conin,conout or list jmp
xchg
lhld biosjmp ;address of real bios routine
mov m,e
inx h
mov m,d
rm ; 7f = RESBDOS jmps not changed
lhld wmfix
mvi m,jmp ;replace jmp for warm start
lhld biosfix
mvi m,jmp ;replace jmp for other trapped jump
endif
ret ; 0 = everything done
;
; set DMA address in DE
;
setdma: mvi c,dmaf
jmp next
;
; print message to console
;
msg: mvi c,pbuff
jmp next
;
; move routine
;
mov7: mvi b,7
; HL = source
; DE = destination
; B = count
move: mov a,m
stax d
inx h
inx d
dcr b
jnz move
ret
;
; add a to hl
;
addhla: add l
mov l,a
rnc
inr h
ret
;
; check if CCP is calling
;
ckccp:
;returns zero flag set if not CCP
lhld scbadr
mvi l,ccpflg+1 ;HL = .ccp flag 2
mov a,m
ani ccpres ;is it the CCP?
ret
;
;******************************************************************
; BDOS FUNCTION HANDLERS
;******************************************************************
;
;
; FUNCTION 26 - SET DMA ADDRESS
;
dmafunc:
xchg ;dma to hl
shld udma ;save it
xchg
jmp next
;
;
; BIOS WARM START TRAP FUNCTION
;
warmtrap:
lxi sp,stack
call close ;close if wboot originated below RSX
jmp wstart
;
; BDOS FUNCTION 60 - RSX FUNCTION CALL
;
rsxfunc: ;check for initialize or delete RSX functions
ldax d ;get sub-function number
cpi pinitf ;is it a PUT initialization
lxi h,init$table
rz ;return to caller if init call
;check for FCB display functions
mov b,a
lda fcbf ;is it a a PUT fcb request
cmp b
lxi h,putfcb
rz ;return if so
;check for kill function
lda killf ;local kill (kill only this one)
cmp b
jz puteof ;kill and return to caller
jmp exit ;abort any higher PUTs
;
;
;******************************************************************
; BDOS OUTPUT ROUTINES
;******************************************************************
;
;
; July 1982
;
;
; Console handlers
;
echoc:
;are we in cooked or raw mode?
lda cooked! ora a! mov a,e! rz ;return if raw
;echo character if graphic
;cr, lf, tab, or backspace
cpi cr! rz ;carriage return?
cpi lf! rz ;line feed?
cpi tab! rz ;tab?
cpi ctlh! rz ;backspace?
cpi ' '! ret ;carry set if not graphic
;
;
print:
;print message until M(DE) = '$'
lhld scbadr
mvi l,OUTDEL
ldax d! CMP M! rz ;stop on delimiter
;more to print
inx d! push d! mov e,a ;char to E
call conout ;another character printed
pop d! jmp print
;
;
read:
;put prompt if in no echo mode
lda echo! ora a! jnz read1
push d
lxi d,prompt! call msg ;output prompt
pop d! mvi c,creadf ;set for read call
read1:
;read console buffer
pop h ;throw away return address
push d
call next ;make the call
pop h! inx h! mov b,m! inr b ;get the buffer length
putnxt: dcr b! jz read2
inx h! mov e,m! push b! push h
call conout! pop h! pop b ;put character
jmp putnxt
read2: lda input! ora a! push psw
mvi e,cr! cnz conout ;call if putting input
pop psw! mvi e,lf! cnz conout ;call if putting input
jmp retmon1
;
func1: equ conin
;
func2: equ conout
;write console character
;
func5: equ listf
;write list character
;write to list device
;
func6: equ rawio
;
func9: equ print
;write line until $ encountered
;
func10: equ read
;
func11: equ retmon0
;
func13: equ close
;
func37: equ close
;
func98: equ close
;
FUNC111: ;PRINT BLOCK TO CONSOLE
FUNC112: ;LIST BLOCK
XCHG! MOV E,M! INX H! MOV D,M! INX H
MOV C,M! INX H! MOV B,M! XCHG
;HL = ADDR OF STRING
;BC = LENGTH OF STRING
BLK$OUT:
MOV A,B! ORA C! RZ ;is length 0, return if so
PUSH B! PUSH H
mov e,m! call conout ;put character
POP H! INX H! POP B! DCX B
JMP BLK$OUT
; end of BDOS Console module
;******************************************************************
; DATA AREA
;******************************************************************
exit$off db 0 ;offset in exit$table of destination
trap$tbl:
;function dispatch table (must match func$tbl below)
; db lchrf, lblkf, coutf, cstatf, crawf
; db pbuff, cinf, creadf, resetf, resdvf
; db resalvf, pblkf, eot
dw func5 ;function 5 - list output
dw func112 ;function 112 - list block
dw func2 ;function 2 - console output
dw func11 ;function 11 - console status
dw func6 ;function 6 - raw console I/O
dw func9 ;function 9 - print string
dw func1 ;function 1 - console input
dw func10 ;function 10 - read console buffer
dw func13 ;function 13 - disk reset (close first)
dw func37 ;function 37 - drive reset (close first)
dw func98 ;function 98 - reset allocation vector
dw func111 ;function 111 - print block
;******************************************************************
; Following variables and entry points are used by PUT.COM
; Their order and contents must not be changed without also
; changing PUT.COM.
;******************************************************************
movstart:
init$table: ;addresses used by PUT.COM for initial.
scbadr: ;address of System Control Block
dw kill ;kill flag for error on file make
;(passed to PUT.COM by RSX init function)
;
if bios$functions ;PUT.RSX initialization
;
gobios: mov c,e
db jmp
biosout dw bios$output ;set to real BIOS routine
;(passed to PUT.COM by RSXFUNC)
biosjmp
dw warm$trap ;address of bios jmp initialized by COM
biosfix
dw 0 ;address of jmp in resbdos to restore
;restore only if changed when removed.
wstart: db jmp
wmsta: dw 0 ;address of real warm start routine
wmjmp: dw 0 ;address of jmp in bios to restore
wmfix: dw 0 ;address of jmp in resbdos to restore
bdosfunc:
db coutf
restore$mode
db 0 ;0FFh = no bios restore, 07fh = restore
;only bios jmp, 0 = restore bios jump and
;resbdos jmp when removed.
endif
;
; equates function table
;
eot equ 0ffh ; end of function table
skipf equ 0feh ; skip this function
;
;
func$tbl: ;no trapping until initialized by PUT.COM
db eot,0,0,0,0,0,0,0,0,0,0,0,0
; db lchrf, lblkf, coutf, cstatf, crawf
; db pbuff, cinf, creadf, resetf, resdvf
; db resalvf, pblkf, eot
;
input db 0 ;put console input to a file
list db 0 ;intercept list functions
echoflg:
db 1 ;echo output to device
cooked: ;must be next after echo
db 0 ;TRUE if ctrl chars (except ^Z) placed
;in the output file
rsxfunctions:
killf: db 0ffh ;not used until PUT initialized
fcbf: db 0ffh ;not used until PUT initialized
record: db 0 ;counts down records to block boundary
blm: db 0 ;block mask = records per block (rel 0)
program: ;this flag must be @ .PUTFCB-2
db 0 ;true if put program output only
putusr: db 0 ;user number for redirection file
putfcb: db 0ffh ;preset to 0ffh to indicate not active
db 'SYSOUT '
db '$$$'
db 0,0
putmod: db 0
putrc: ds 1
ds 16 ;map
putcr: ds 1
;
cbufp db 0 ;current character position in cbuf
movend:
;*******************************************************************
cbuf: ;128 byte buffer (could be ds 128)
db 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3
db 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3
db 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3
db 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3
db 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3
db 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3
db 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3
db 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3
;
if bios$functions
;
exit$table: ;addresses to go to on exit
dw next ;BDOS
dw gobios
endif
;
udma: dw buf ;user dma
user: db 0 ;user user number
echo: db 0 ;echo output to console flag
ccpcnt: db 1 ;start at 1 (decremented each CCP)
sav$area: ;14 byte save area
db 68h,68h,68h,68h,68h, 68h,68h,68h,68h,68h
db 68h,68h,68h,68h
close$err:
db cr,lf,'PUT ERROR: FILE ERASED',cr,lf,'$'
prompt: db cr,lf,'PUT>$'
;
patch$area:
ds 30h
maclib makedate ;[JCE] move all dates to one file
db ' '
@BDATE
db ' '
@SCOPY
db 67h,67h,67h,67h, 67h,67h,67h,67h, 67h,67h,67h,67h
db 67h,67h,67h,67h, 67h,67h,67h,67h, 67h,67h,67h,67h
db 67h,67h,67h,67h, 67h,67h,67h,67h
;
stack: ;16 level stack
oldstack:
dw 0
end