home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
norge.freeshell.org (192.94.73.8)
/
192.94.73.8.tar
/
192.94.73.8
/
pub
/
computers
/
cpm
/
alphatronic
/
DRIPAK.ZIP
/
CPM_3-0
/
SOURCES
/
SAVE.ASM
< prev
next >
Wrap
Assembly Source File
|
1982-12-31
|
14KB
|
805 lines
title 'SAVE.RSX - CP/M 3.0 save routine. July 1982'
; *************************************************
; *
; * Title: SAVE.RSX Resident System eXtension
; * Date: 7/28/82
; * Author: Thomas J. Mason
; *
; * Modified:
; * 11/30/82 - Thomas J. Mason
; * Added trap for function 60 to fix PUT and SAVE
; * bios vector mods.
; *
; *********************************************************
;
; Copyright (c) 1982
; Digital Research
; PO Box 579
; Pacific Grove, Ca. 93950
;
TRUE equ 0FFFFh
FALSE equ not TRUE
;
; BIOS and BDOS Jump vectors
;
WBOOT equ 0
WBTADR equ 1 ;address of boot in BIOS
BDOS equ 5 ;BDOS jump vector
BDOSAD equ 6 ;location of instructions
DFCB equ 05Ch ;default FCB
;
; BDOS Function calls
;
BDOSAD equ 6 ;BDOS jump address
PSTRING equ 9 ;print string
BUFIN equ 10 ;console buffer input
CFILE equ 16 ;file close
DFILE equ 19 ;file delete
WFILE equ 21 ;file write
MFILE equ 22 ;make file
SETDMA equ 26 ;set DMA function
BDOSER equ 45 ;Set BDOS error mode
GETSCB equ 49 ;get/set scb func #
LDRSX equ 59 ;function for RSX load
CALRSX equ 60 ;call rsx func #
CONMOD equ 109 ;GET/SET Console Mode
;
; Non Printable ASCII characters
;
CTL$C equ 03 ;CONTROL-C
CR equ 13 ;ASCII Carrige Return
LF equ 10 ;ASCII Line Feed
;
VERSION equ 30
;
; Buffer size
;
CONMAX equ 13 ;console buffer maximum
STKSZE equ 010h ;size fo stack
SCBOST equ 068h ;page boundary + to jmp instr
RETDSP equ 0FEh ;RETurn and DiSPlay mode
JUMP equ 0C3h ;opcode for jump
LXIH equ 21h ;lxi instr to poke
BSNLY equ 07Fh ;restore bios jump table only
CMMON equ 0F9h ;offset of common memory base from pg. bound
;
; *********************************
; * *
; * The Save Program *
; * *
; *********************************
;
db 0,0,0,0,0,0
jmp PREFIX
NEXTJ:
db JUMP ;jump
NEXT:
db 0,0 ;next module in line
PREV:
dw 5 ;previous, initialized to 5
STKYBT: db 00h ;for warm start
db 0
db 'SAVE '
ds 3
;
;
; This is the check performed every time the BDOS is
; called to see if the RSX is to be invoked
;
PREFIX:
mov a,c ;set up for compare
cpi CALRSX
jnz GETGOING
push b
push d
push h
lxi h,0000h ;zero out HL
dad d ; <HL> -> RSXPB
mov a,m ;get the byte
cpi 160 ; sub function defined
pop h
pop d
pop b
jz GOODBYE ;remove this RSX
GETGOING:
;
cpi LDRSX ;do the compare
jz START
lhld NEXT ;get address for continue
pchl ;get going.....
;
;
;
START:
;
; They are equal so get the BIOS address to point here
; in case of a Func 0 call
;
push b ;save state
push d ; of registers
;
; check for jump byte before the SCB
call GETSET$SCB
shld SCBADR ;save address for later
;
mvi l,CMMON+1 ;offset into scb to check BIOS
mov a,m ;get byte
ora a ;check for zero
mvi a,FALSE ;store for insurance
sta CHGJMP ;non-banked = FALSE
jz NBNKED ;high byte zero if non-banked
;
lhld SCBADR ;restor SCB
mvi l,SCBOST ;offset from page for instr
mov a,m ;get byte
cpi JUMP ;is it a jump?
jnz MORRSX ;we are not alone
mvi a,TRUE
sta CHGJMP ;set flag
mvi m,LXIH ;put in lxi h,xxxx mnemonic
;
MORRSX:
; continue with processing
NBNKED:
;
;
lhld WBTADR ;get address at 01h
inx h ;now points to address of jmp xxxx
mov a,m ;get low order byte
sta BIOSAD
inx h ;next byte
mov a,m
sta BIOSAD+1 ;high order byte
;
; Now poke the BIOS address to point to
; the save routine.
;
lxi d,BEGIN ;begining of routine
mov m,d
dcx h ;point back to first byte
mov m,e ;low order
;
mvi c,BDOSER ;now set BDOS errormode
mvi e,RETDSP ;to trap any hard
call BDOS ;errors
;
;
pop d
pop b
lhld NEXT
pchl ;continue on
;
BEGIN:
; Start of the save routine
; Notify the user which program is running
;
lxi sp,STACK ;initialize stack
lxi d,SIGNON ;prompt
call PSTR
;
; Get the file from the user
;
FLEGET:
lxi d,FLEPRMPT ;ask for file name
call PSTR
call GETBUF
; zero at end of string for parser
lxi h,CONBUF-1 ;address of #
mov a,m ;get it
cpi 0
jz REPLCE
inx h ;HL->CONBUF
mvi d,0 ;zero out high order
mov e,a ;fill low
dad d ;add to h
mvi m,00 ;zero out byte for parse
push h
;
;
call PARSE
mov a,h
cpi 0FFh
jz FLEGET
;
pop h ;get end of string address back
inx h
mvi m,'?' ;put in question mark
inx h ;bump
mvi m,' ' ;blank in string
inx h ;bump
mvi m,'$' ;end of string
;
mvi c,17 ;Search for first
lxi d,DFCB
call BDOS ;find it
inr a ;bump Acc
jz FLECLR ;file no present skip prompt
;
lxi d,DELFLE
call PSTR ;print out delete prompt
lxi d,CONBUF ;buffer address
call PSTR ;print out filename
call GETBUF ;get answer
call GNC ;get the next char
cpi 'Y' ;is it yes
jnz FLEGET ;another name if not
;
; Delete any existing file, then make a new one
FLECLR:
mvi c,DFILE ;file delete func
lxi d,DFCB ;default FCB
call BDOS ;real BDOS call
;
mvi a,0
lxi h,07ch ;M -> record count in FCB
mov m,a ;zero out record count
;
mvi c,MFILE ;make file function
lxi d,DFCB ;default FCB
call BDOS
; Get the address of start of write
;
STRADD:
lxi d,SPRMPT ;first address
call PSTR
call GETBUF
;
lda BUFFER+1 ;get # of chars read
cpi 0
jz STRADD
;
call SCANAD ;get address
jc STRADD
;
shld SADDR ;store in SADDR
;
; Get the finish address
ENDADD:
lxi d,FPRMPT ;load prompt
call PSTR ;print
call GETBUF ;read in
;
lda BUFFER+1
cpi 0
jz ENDADD
;
call SCANAD ;get finish address
jc ENDADD
;
shld FADDR ;store it
xchg
lhld SADDR
xchg
;
call CHECK
jc STRADD
;
;
lhld SADDR ;beginning DMA address
xchg ;DE=DMA address
;
; Write the first record then check the beginning address
; if DMA address ends up larger exit
;
WLOOP:
call WFLAG
push d ;save DMA address
mvi c,SETDMA
call BDOS ;set DMA address
;
mvi c,WFILE
lxi d,DFCB
call BDOS ;write
;
; Check for directory space on disk for extents
lxi d,NODIR
cpi 01h ;no more directory
jz FINIS
;
; CHECK data block error
lxi d,NOBLK
cpi 02h
jz FINIS ;out of disk space!
; final check
ora a ;if bad write occured...
jnz REPLCE ;restore BIOS address
;
; Write OK now check write address
pop d ;get DMA address
lxi h,080h
dad d
xchg
lhld FADDR ;HL=end of write
;
call CHECK
;
lda ONEFLG
cpi TRUE
jnz WLOOP ;WLOOP if not done
;
; Else, Close file and print out ending prompt
CLOSE:
mvi c,CFILE ;close function
lxi d,DFCB ;get filename
call BDOS
;
inr a ;check for close error
lxi d,CERROR
jz FINIS ;maybe write protected
;
;good copy
lxi d,ENDMSG
FINIS:
call PSTR
;
; Replace the BIOS Address to correct one
REPLCE:
lhld BIOSAD ;HL=BIOS warm jump
xchg ;DE=" " "
lhld WBTADR
inx h
mov m,e
inx h
mov m,d
;
GOODBYE:
mvi a,0FFh
sta STKYBT ;change sticky byte for
; ; removal of RSX
;
; check to see if JMP changed for BANKED system
lda CHGJMP
cpi TRUE ;has it been done?
jnz CHGBIOS
lhld SCBADR ;retreive SCB address
mvi l,SCBOST ;points to page + offset
mvi m,JUMP ;restore original code
;
CHGBIOS:
mvi c,13 ;reset the disk system
call BDOS
;
mvi c,0 ;set up for wboot
call BDOS
;****************************************
;* *
;* Logical end of the program *
;* *
;****************************************
;
GETSET$SCB:
mvi c,GETSCB
lxi d,SCBPB
call BDOS
ret
;
WFLAG:
mvi a,FALSE
sta ONEFLG
lda RSLT+1
cpi 00h
rnz
lda RSLT
cpi 080h
jc WFLAG1
jz WFLAG1
ret
;
WFLAG1:
mvi a,TRUE
sta ONEFLG
ret
;
;
;
CHECK:
; Subtract the two to find out if finished
mov a,l ;low order
sub e ;subtraction
sta RSLT
mov a,h ;now ...
sbb d ;high order subtraction
sta RSLT+1 ;saved
ret
;
GETBUF:
;buffer input routine
;
lxi h,CONBUF ;address of buffer
shld NEXTCOM ;store it
mvi c,BUFIN
lxi d,BUFFER
call BDOS
ret
;
PSTR:
; String output routine for messages
;
mvi c,PSTRING
call BDOS
ret
;
PARSE:
; General purpose parser
;
; Filename = [d:]file[.type][;password]
;
; FCB assignments
;
; 0 => drive, 0=default, 1=A, 2=B
; 1-8 => file, converted to upper case,
; padded with blanks
; 9-11 => type, converted to upper case,
; padded with blanks
; 12-15 => set to zero
; 16-23 => passwords, converted to upper case,
; padded with blanks
; 24-25 => address of password field in "filename",
; set to zero if password length=0.
; 26 => length of password (0-8)
;
; Upon return, HL is set to FFFFh if BC locates
; an invalid file name;
; otherwise, HL is set to 0000h if the delimiter
; following the file name is a 00h (null)
; or a 0Dh (CR);
; otherwise, HL is set to the address of the delimiter
; following the file name.
;
;
lxi h,0
push h
push h
lxi d,CONBUF ;set up source address
lxi h,DFCB ;set up dest address
call DEBLNK ;scan the blanks
call DELIM ;check for delimeter
jnz PARSE1
mov a,c
ora a
jnz PARSE9
mov m,a
jmp PARSE3
;
PARSE1:
mov b,a
inx d
ldax d
cpi ':'
jnz PARSE2
;
mov a,b
sui 'A'
jc PARSE9
cpi 16
jnc PARSE9
inr a
mov m,a
inx d
call DELIM
jnz PARSE3
cpi '.'
jz PARSE9
cpi ':'
jz PARSE9
cpi ';'
jz PARSE9
jmp PARSE3
;
PARSE2:
dcx d
mvi m,0
PARSE3:
mvi b,8
call SETFLD
mvi b,3
cpi '.'
jz PARSE4
call PADFLD
jmp PARSE5
;
PARSE4:
inx d
call SETFLD
PARSE5:
mvi b,4
PARSE6:
inx h
mvi m,0
dcr b
jnz PARSE6
mvi b,8
cpi ';'
jz PARSE7
call PADFLD
jmp PARSE8
PARSE7:
inx d
call PWFLD
PARSE8:
push d
call DEBLNK
call DELIM
jnz PARSE81
inx sp
inx sp
jmp PARSE82
PARSE81:
pop d
PARSE82:
mov a,c
ora a
pop b
mov a,c
pop b
inx h
mov m,c
inx h
mov m,b
inx h
mov m,a
xchg
rnz
lxi h,0
ret
PARSE9:
pop h
pop h
lxi h,0FFFFh
ret
;
SETFLD:
call DELIM
jz PADFLD
inx h
cpi '*'
jnz SETFD1
mvi m,'?'
dcr b
jnz SETFLD
jmp SETFD2
SETFD1:
mov m,a
dcr b
SETFD2:
inx d
jnz SETFLD
SETFD3:
call DELIM
rz
pop h
jmp PARSE9
;
PWFLD:
call DELIM
jz PADFLD
inx sp
inx sp
inx sp
inx sp
inx sp
inx sp
push d
push h
mvi l,0
xthl
dcx sp
dcx sp
PWFLD1:
inx sp
inx sp
xthl
inr l
xthl
dcx sp
dcx sp
inx h
mov m,a
inx d
dcr b
jz SETFD3
call DELIM
jnz PWFLD1
;
PADFLD:
inx h
mvi m,' '
dcr b
jnz PADFLD
ret
;
DELIM:
ldax d
mov c,a
ora a
rz
mvi c,0
cpi 0Dh
rz
mov c,a
cpi 09h
rz
cpi ' '
jc DELIM2
rz
cpi '.'
rz
cpi ':'
rz
cpi ';'
rz
cpi '='
rz
cpi ','
rz
cpi '/'
rz
cpi '['
rz
cpi ']'
rz
cpi '<'
rz
cpi '>'
rz
cpi 'a'
rc
cpi 'z'+1
jnc DELIM1
ani 05Fh
DELIM1:
ani 07Fh
ret
DELIM2:
pop h
jmp PARSE9
;
DEBLNK:
ldax d
cpi ' '
jz DBLNK1
cpi 09h
jz DBLNK1
ret
DBLNK1:
inx d
jmp DEBLNK
; End of the Parser
;
; GET a character from the console buffer
GNC:
push h
lxi h,CONBUF-1 ;get length
mov a,m
ora a ;zero?
mvi a,CR ;return with CR if so
jz GNCRET
dcr m ;lenght = length-1
lhld NEXTCOM ;next char address
mov a,m
inx h ;bump to next
shld NEXTCOM ;update
GNCRET:
pop h
TRANS:
cpi 7Fh ;Rubout?
rz
cpi ('A' or 0100000b)
rc
ani 1011111b ; clear upper case bit
ret
;
;
; Scan the buffer for the address read in ASCII from the terminal
;
SCANAD:
lxi d,00h ;zero out address
push d ;and save
;
lda CONBUF-1 ;get character count
cpi 05 ;5 is too many
jc SCAN0
stc ;set carry for routine
jmp SCNRET
SCAN0:
call GNC ;get a char
cpi CR ;end?
jz SCNRET ;to scnret if so
cpi '0' ;is it >0?
jnc SCAN01 ;bad character
jmp SCNRET
SCAN01:
cpi '@'
jnz SCAN02 ;bad character
stc
jmp SCNRET ;return on bad file
SCAN02:
jnc SCAN1 ;must be A-F
sui 030h ;normalize 0-9
jmp SCAN2
SCAN1:
cpi 'G' ;is it out of range?
jc SCAN11
stc
jmp SCNRET
SCAN11:
sui 037h ;normalize
SCAN2:
mov l,a ;character in low of DE
lda CONBUF-1 ;get # left
adi 1 ;readjust
mov c,a
mvi h,00 ;zero out high order
SCAN3:
dcr c ;dec to set flag
jz SCAN4 ;were done
dad h ;shift 1bit left
dad h ;same
dad h ;same
dad h ;finally
jmp SCAN3 ;back for more
;
SCAN4:
pop d ;ready for or
mov a,d ;high order
ora h ;
mov d,a
mov a,e ;low order
ora l ;ORed
mov e,a ;back
push d ;save
jmp SCAN0 ;get more characters
SCNRET:
pop d ;hl = address
xchg ;DE->HL
ret
;
;
; *********************************
; * *
; * Data Structures *
; * *
; *********************************
;
SCBPB:
db 03Ah ;SCB address
db 0
;
SADDR: dw 0 ;write start address
FADDR: dw 0 ;write finish address
BIOSAD: dw 0 ;WarmBOOT bios address
NEXTCOM: dw 0 ;address of next character to read
ONEFLG: db 0
RSLT: dw 0
CHGJMP db FALSE
;
SCBADR: dw 0 ;Scb address
;
BIOSMD: db 0 ;if non-zero change LXI @jmpadr to
;JUMP when removed.
;
BUFFER: db CONMAX
db 0 ;# of console characters read
CONBUF: ds CONMAX
;
SIGNON: db CR,LF,'CP/M 3 SAVE - Version ',VERSION/10+'0','.',VERSION mod 10+'0','$'
FLEPRMPT: db CR,LF,'Enter file '
db '(type RETURN to exit): $'
DELFLE: db CR,LF,'Delete $'
SPRMPT: db CR,LF,'Beginning hex address $'
FPRMPT: db CR,LF,'Ending hex address $'
ENDMSG: db CR,LF,'$'
;
; Error messages......
CERROR: db CR,LF,'ERROR: Bad close.$'
NODIR: db CR,LF,'ERROR: No directory space.$'
NOBLK: db CR,LF,'ERROR: No disk space.$'
;
; Stack for program
ds STKSZE
STACK:
end ;Physical end of program