home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
MBUG
/
MBUG150.ARC
/
P.LBR
/
P.Z80
< prev
next >
Wrap
Text File
|
1979-12-31
|
28KB
|
1,475 lines
;******************************************************************************
;
; P.AS
;
; Z80 Version
;
; V2.0 860201
;
; Anthony C. Howe
;
;******************************************************************************
;
SECSIZ equ 128 ;sector size
CMDLEN equ 80 ;command line length
;
;******************************************************************************
;
;*** Declaration Block of Constant Terms
;
;*** Important Locations
;
BASE equ 00000H ;start of memory
BDOS equ BASE+00005H ;CPM BDOS jump vector
FCB equ BASE+0005CH ;file control block
DMA equ BASE+00080H ;direct memory address
TPA equ BASE+00100H ;transient progam area
;
;*** BDOS Call Equates
;
SYSR equ 000 ;system reset
CONIN equ 001 ;console input
CONOUT equ 002 ;console output
RDRIN equ 003 ;card reader input
PUNOUT equ 004 ;card punch output
LSTOUT equ 005 ;list device output
DCIO equ 006 ;direct console I/O
GIOB equ 007 ;get I/O byte
SIOB equ 008 ;set I/O byte
PMSG equ 009 ;print string
RCB equ 010 ;read console buffer
GCST equ 011 ;get console status
RVER equ 012 ;return version number
RESET equ 013 ;reset disk
SEL equ 014 ;select drive
OPEN equ 015 ;open file
CLOSE equ 016 ;close file
SFIRST equ 017 ;search for first
SNEXT equ 018 ;search for next
DELETE equ 019 ;delete file
RDSEQ equ 020 ;read sequentially
WRSEQ equ 021 ;write sequentially
MAKE equ 022 ;create file
RENAME equ 023 ;rename file
RLOGV equ 024 ;get login vector
RCDSK equ 025 ;get current drive
SETDMA equ 026 ;set DMA address
GALLOC equ 027 ;get addr (allocation)
WPDSK equ 028 ;write protect drive
GROV equ 029 ;get read only vector
SETATT equ 030 ;set file attributes
GDSKP equ 031 ;get addr (disk prams)
SGUSER equ 032 ;set/get user level
RDRND equ 033 ;read randomly
WRRND equ 034 ;write randomly
CFS equ 035 ;compute file size
SRNDR equ 036 ;set random record
;
;*** Constants
;
;*** ASCII Control Signal Codes
;
NUL equ 000 ;ctrl-@ null
SOH equ 001 ;ctrl-A start of header
STX equ 002 ;ctrl-B start of text
ETX equ 003 ;ctrl-C end of text
EOT equ 004 ;ctrl-D end tranmission
ENQ equ 005 ;ctrl-E enquire
ACK equ 006 ;ctrl-F acknowledge
BEL equ 007 ;ctrl-G bell
BS equ 008 ;ctrl-H backspace
HT equ 009 ;ctrl-I horizontal tab
LF equ 00AH ;ctrl-J line feed
VT equ 00BH ;ctrl-K vertical tab
FF equ 00CH ;ctrl-L form feed
CR equ 00DH ;ctrl-M return
SO equ 00EH ;ctrl-N shift out
SI equ 00FH ;ctrl-O shift in
DLE equ 010H ;ctrl-P
DC1 equ 011H ;ctrl-Q
DC2 equ 012H ;ctrl-R
DC3 equ 013H ;ctrl-S
DC4 equ 014H ;ctrl-T
NAK equ 015H ;ctrl-U neg acknowledge
SYN equ 016H ;ctrl-V sync
ETB equ 017H ;ctrl-W
CAN equ 018H ;ctrl-X cancel
EM equ 019H ;ctrl-Y
SUBSIT equ 01AH ;ctrl-Z subsitute
ESC equ 01BH ;ctrl-[ escape
FS equ 01CH ;ctrl-\ file separator
GS equ 01DH ;ctrl-] group separator
RS equ 01EH ;ctrl-^ rec separator
US equ 01FH ;ctrl-_ unit separator
SPACE equ 020H ;space
;
EOF equ 01AH ;ctrl-Z, EOF char
;
;*** Others
;
FALSE equ 0
TRUE equ 0FFH
;
PORTA equ TRUE
;
;
;
;******************************************************************************
;
;
; Code Text Section
;
ORG TPA
;
START: call INIT ;set up parameter table
;
ld a,(ARGC) ;get value of command line string count
or a
jp z,BASE ;if this count equals zero then nogo
;
xor a ;zero all variables
ld hl,PY1
ld (hl),a
ld de,PY1+1
ld bc,255
ldir
;
ld hl,BUFF+1
ld (BUFPNT),hl ;initialize buffer pointer
ld hl,DMA+1
ld (DMACHR),hl ;initialize pointer to command line
ld hl,WORK
ld (FRESPC),hl ;initialize start of free space pointer
ld a,1
ld (FCBSUB),a ;drive that $$$.SUB is to be on
ld hl,SUBNOM
ld de,FCBSUB+1
ld bc,11
ldir ;copy name of $$$.SUB to FCBSUB
;
ld hl,(ARGV) ;get pointer to command string pointers then
ld a,(hl) ; fetch pointer in ARGV [0] which is the first
inc hl ; pointer to the 1st string
ld h,(hl)
ld l,a
inc hl
push hl
call GDELIM ;find 1st delimeter in 1st string.
pop de
cp '.' ;if not filename/extension separator the treat
jp nz,CMDEXE ; as a command line, else continue here
;
xor a
ld (DMA),a
ld hl,FIN ;point to I/O Buffer
ld a,1 ;open for input
call OPNIO ;open buffered input
or a ;check for successful opening
jp z,CMDEXE
;
ld de,MSG1 ;send error message
MSGOUT: ld c,PMSG
call BDOS
jp BASE
;
;
CMDBLK: ld a,(FIN)
or a
jp z,IMMCMD
ld a,(hl)
or a
jr z,CMDFIN
cp ';' ;command separator
jp z,IMMCMD
;
CMDFIN: call SUBIN ;get an input line
;
ld hl,(DMACHR)
CMD1: inc hl ;skip all spaces till text
ld (DMACHR),hl
ld a,(hl)
cp SPACE
jr z,CMD1
;
ld a,(hl) ;check for comment line or conditional line
cp ';'
jr nz,CMD2
call STRLEN
ld (BUFF),a
ld hl,(DMACHR)
ld de,(BUFPNT)
call STRCPY
ld hl,LSTP
call LSTADD
jr CMDFIN
;
CMD2: ld hl,DMA ;point to start of command line
ld (DMACHR),hl
xor a
ld (BUFF),a ;zap character count
;
IMMCMD: ld hl,(DMACHR)
IMM1: inc hl ;skip leading spaces
ld (DMACHR),hl
ld a,(hl)
cp SPACE
jr z,IMM1
;
jr CMDPRO ;perform while loop test first
;
IMM2: cp '$' ;if '$' and a digit are found then process
jr nz,IMM3 ; the parameter.
inc hl
call ISNUM
jr z,IMM3
call PARAM
jr CMDPRO
;
IMM3: ld hl,(DMACHR)
ld a,(hl) ;if vertical bar is found then handle pipes
cp '|'
jr nz,IMM4
call PIPES
jr CMDPRO
;
IMM4: cp CR ;if CR is found just skip over it
jr nz,IMM5
inc hl
ld (DMACHR),hl
jr CMDPRO
;
IMM5: ld de,(BUFPNT)
ld (de),a ;move character to current working buffer and
inc de ; adjust both fetch and store pointers, and
ld (BUFPNT),de ; add 1 to the character count in working
inc hl ; buffer
ld (DMACHR),hl
ld hl,BUFF
inc (hl)
;
CMDPRO: ld hl,(DMACHR) ;while no command separators found or the end
ld a,(hl) ; of the command line then continue to process
cp ';' ; the command
jr z,ENDPIP
or a
jr nz,IMM2
;
ENDPIP: ld a,(PY1) ;check to see if last pipe input is required
or a
jr nz,END1
ld a,(PY2)
or a
jr z,ENDCMD
;
END1: ld a,(PY1) ;handle PIPE1 file input
or a
jr z,END2
ld hl,PIPE1
;
;
ld de,(BUFPNT) ;we tack PIPE1 on to end of end of work buffer
call STRCPY
;
END2: ld a,(PY2) ;handle PIPE2 file input, note only one pipe
or a ; can be marked for IN at any one time, thus
jr z,END3 ; if PIPE1 was copied then this copy will be
ld hl,PIPE2 ; bypasssed.
;
ld de,(BUFPNT)
call STRCPY
;
END3: ld a,(BUFF) ;both pipe strings are 6 characters long and
add a,6 ; must update the working buffer character
ld (BUFF),a ; count
ld hl,LSTP
call LSTADD
;
ld a,8
ld (BUFF),a ;set up work buffer with erase pipe command
ld de,BUFF+1
ld hl,ERAPIP
call STRCPY
;
;
ld hl,LSTP
call LSTADD
xor a
ld (PY1),a ;reset pipes
ld (PY2),a
jr ENDC1
;
ENDCMD: ld de,(BUFPNT) ;finish off command with string terminator
xor a
ld (de),a
ld hl,LSTP
call LSTADD
;
ENDC1: ld de,BUFF+1 ;reset working buffer
ld (BUFPNT),de
xor a
ld (BUFF),a
;
CMDEXE: ld hl,(DMACHR) ;get command line pointer
ld a,(hl) ;A = *DMACHR
or a
jp nz,CMDBLK ;if not end of command line then continue
ld a,(FIN) ;get buffered file channel byte
or a
jp nz,CMDBLK ;if not zero then file still open, continue
;
MAKSUB: ld de,FCBSUB ;check if file exists and open if it does
ld c,OPEN
call BDOS
inc a
jr z,MAK1
;
ld de,BUFF
ld c,SETDMA
call BDOS
;
ld c,CFS ;get the length of the $$$.SUB
ld de,FCBSUB
call BDOS
jr MAK3
;
MAK1: ld de,FCBSUB
ld c,MAKE
call BDOS
inc a
jr nz,MAK2
;
ld de,MSG4
jp MSGOUT
;
MAK2: ld de,FCBSUB ;reset random record pointer to zero
ld c,SRNDR
call BDOS
;
MAK3: ld hl,(LSTP)
call OUTLST
ld de,FCBSUB
ld c,CLOSE
call BDOS
inc a
jp nz,BASE ;all done!!!!
;
ld de,MSG5
jp MSGOUT
;
;******************************************************************************
;
; Find Delimeter in String
;
; e HL = pnt to string
; x A = delimeter found or 0 for no delimeter (end of string)
; HL = pnt to delimeter
;
GDELIM: ld a,(hl) ;get character at address pnt to by HL
or a ;if character is zero then end of string, exit
ret z
cp '.' ;filename/extension separator
ret z
cp ';' ;command separator or comment line
ret z
cp '|' ;pipe separator
ret z
cp '<' ;IO separator (I)
ret z
cp '>' ;IO separator (O)
ret z
cp SPACE ;word separator
ret z
inc hl
jr GDELIM
;
;******************************************************************************
;
; Get line in from submit file
;
SUBIN: ld b,CMDLEN ;get a new command line from file no longer
ld hl,DMA+1 ; than 80 characters
SUB1: ld (DMACHR),hl ;store updated command line pointer
push bc ;store counter
ld hl,FIN
call IOCHAR
ex af,af' ;hold recieved character
ld a,b ;get function result
pop bc ;restore character count and command line
ld hl,(DMACHR) ; pointer
inc a
jr nz,SUB2 ;if an error then continue
;
ld de,MSG2 ;read error
jp MSGOUT
;
SUB2: inc a
jp z,MAKSUB ;if not end of physical file then continue
ex af,af' ;get characeter recieved
cp EOF
jp z,MAKSUB ;if not end of text file then continue
cp CR ;strip CR from input line
jr z,SUB1
cp LF ;if LF then that is end of fetched command line
jr z,SUB3
ld (hl),a ;store recieved byte in command line buffer
inc hl
djnz SUB1 ;repeat until command line filled
;
SUB3: ld (hl),0 ;place string terminator
ld hl,DMA ;reset command line pointer
ld (DMACHR),hl
ld (hl),SPACE ;store an initial space
ret
;
;******************************************************************************
;
; String Length
;
; e HL = points to string
; x A = length of string
;
STRLEN: ld b,0
STR1: ld a,(hl)
or a
jr z,STR2
inc b
inc hl
jr STR1
STR2: ld a,b
ret
;
;******************************************************************************
;
; Copy String1 to String2
;
; e HL = points to source string
; DE = points to target string
;
STRCPY: ld a,(hl)
ld (de),a
or a
ret z
inc hl
inc de
jr STRCPY
;
;******************************************************************************
;
; Isdigit
;
; e HL = points to string
; x A = 0 if no digit else ASCII digit
; ZY = 1 if no digit else 0 if a digit
;
ISNUM: ld a,(hl)
cp '0'
jr c,ISN1
cp '9'+1
jr nc,ISN1
ret
ISN1: xor a
ret
;
;******************************************************************************
;
; ASCII Digits to Decimal
;
; e DE = points to start of ASCII decimal number
; x DE = points to byte after last digit character
; HL = integer number from 0 to 65535
;
CONDEC: ld hl,0
CON1: ld a,(de)
cp '9'+1
ret nc
cp '0'
ret c
push de
ld de,10 ;shift units to 10's
call UMUL
pop de
ld a,(de)
sub '0'
ld c,a
ld b,0
add hl,bc
inc de
jr CON1
;
;******************************************************************************
;
; Process Parameter Table
;
; e HL = points to ASCII digit in string
;
PARAM: ex de,hl
call CONDEC ;convert ASCII digits to hex
ld (DMACHR),de ;save updated pointer to string
add hl,hl ;double array offset for indexing pointer array
ex de,hl ;hold index here
;
ld hl,(ARGV) ;fetch base address to pointer array
add hl,de
;
ld a,(hl) ;get pointer to parameter string
inc hl
ld h,(hl)
ld l,a
;
push hl
call STRLEN ;calculate the length of the parameter string
pop hl ; and add to the character count in the working
push af ; buffer
ld b,a
ld a,(BUFF)
add a,b
ld (BUFF),a
;
ld de,(BUFPNT)
call STRCPY
;
pop af ;adjust buffer pointer so as to point to the
ld l,a ; new end of working buffer after the insertion
ld h,0 ; of the parameter
ld de,(BUFPNT)
add hl,de
ld (BUFPNT),hl
ret
;
;******************************************************************************
;
; Pipes
;
; e HL = points to pipe separator
;
PIPES: inc hl ;skip all spaces till text
ld (DMACHR),hl
ld a,(hl)
cp SPACE
jr z,PIPES
;
ld a,(PY1) ;if both pipe flags are false then this is the
or a ; first pipe and must be set to OUT
jr nz,PIP1
ld a,(PY2)
or a
jr nz,PIP1
;
ld hl,POUT1
ld a,TRUE
ld (PY1),a
xor a
ld (PY2),a
ld b,6
jr PIPDON
;
PIP1: ld a,(PY1) ;if PIPE1 is mark for input then continue
or a
jr z,PIP2
;
ld hl,PIN1
ld b,12
xor a
ld (PY1),a
ld a,TRUE
ld (PY2),a
jr PIPDON
;
PIP2: ld a,(PY2)
or a
jr z,PIP3
;
ld hl,PIN2
ld b,12
ld a,TRUE
ld (PY1),a
xor a
ld (PY2),a
;
PIPDON: ld a,(BUFF)
add a,b
ld (BUFF),a
ld de,(BUFPNT)
call STRCPY
;
PIP3: ld hl,LSTP
call LSTADD
xor a
ld (BUFF),a
ld de,BUFF+1
ld (BUFPNT),de
ret
;
;******************************************************************************
;
; Add another sector to the linked list
;
; e HL = points to pointer to a linked list
;
LSTADD: ld e,(hl) ;get pointer to next node
inc hl
ld d,(hl)
ex de,hl
;
ld a,h ;if not yet at bottom node then make a
or l ; a recursive call back to this routine till
jr nz,LSTADD ; the end node is found
;
ld hl,(FRESPC)
ld bc,SECSIZ+2 ;size of block required for list
add hl,bc ;take this from free space
ld (FRESPC),hl ;update free space
;
ex de,hl ;update this node pointer to new node
ld (hl),d
dec hl
ld (hl),e
ex de,hl
;
ld (hl),0 ;store NULL in pointer in new node
inc hl
ld (hl),0
inc hl
;
ex de,hl
ld hl,BUFF
ld bc,SECSIZ
ldir
ret
;
;******************************************************************************
;
; Output linked list to $$$.SUB
;
OUTLST: ld e,(hl) ;get pointer to next node
inc hl
ld d,(hl)
ex de,hl
;
push de ;save pointer to this node
ld a,h ;if not yet at bottom node then make a
or l ; a recursive call back to this routine till
call nz,OUTLST ; the end node is found
;
pop de ;fetch pointer to this node
inc de ;point to the start of submit line
;
ld c,SETDMA ;set DMA to this submit line
call BDOS
;
ld de,FCBSUB
ld c,WRRND ;write it to the submit file
call BDOS
or a
jr z,OUT1
;
ld de,MSG6
jp MSGOUT
;
OUT1: xor a ;increment record pointer to next record to
ld hl,FCBREC+2 ; write
ld (hl),a
dec hl
ld d,(hl)
dec hl
ld e,(hl)
inc de
ld (hl),e
inc hl
ld (hl),d
ret
;
;******************************************************************************
;
; Initialize
;
; e Default DMA will have the command line
; x ARGV = pointer to an array of pointers that point to character strings
; ARGC = number of elements in ARGV, ARGV [ARGC] = -1
;
; note: a CALL must be made to INIT if the routine is to execute properly!!!!
;
;
INIT: pop hl ;get and save return address as the stack
ld (RETADD),hl ; will be moved.
;
ld hl,(BDOS+1) ;get base of BDOS
dec hl ;adjust
ld sp,hl ;put stack here
;
ld hl,DMA ;point to default DMA and command line
ld c,(hl) ;get character count of command line
ld b,0
ld (hl),SPACE ;kill character count byte
add hl,bc ;find end of parameter string
inc hl
inc bc
xor a
ld (hl),a ;place a double terminator at end of string
inc hl
inc bc
ld (hl),a
;
ex de,hl
ld hl,0 ;set terminator
add hl,sp ;get copy of start pointer
ex de,hl
lddr
ex de,hl
inc hl
ld sp,hl
;
ld de,-1 ;last element of ARGV[] = -1
push de ;save this element
ld de,ARGC ;get ARGC address for later
xor a
ld (de),a ;reset in case of re-execute
;
INIT2: ld a,(hl) ;get character
or a
jr z,INIT7 ;end of command line yet?
inc hl
cp SPACE
jr z,INIT2 ;skip leading spaces
ld c,a ;default string separator is a space
cp '"' ;check for single and double quotes
jr z,INIT5 ;if double quote found use for separator
cp 27h ;single quote
jr z,INIT5 ;if single quote found use for a separator
ld c,SPACE ;use single/double quote for string separator
dec hl
;
INIT5: ld a,(hl)
or a
jr z,INIT6 ;end of command line yet?
cp c
inc hl
jr nz,INIT5
dec hl
ld (hl),0
inc hl
INIT6: ex de,hl
inc (hl)
ex de,hl
jr INIT2
;
INIT7: dec hl
ld a,(hl)
cp -1
jr z,INIT8
or a
jr nz,INIT7
inc hl ;point to start of string
push hl ;save pointer to that string
dec hl
jr INIT7
;
INIT8: inc hl
push hl
ld (ARGV),sp ;save pointer to pointer array ARGV
ld hl,(RETADD)
jp (hl)
;
RETADD: DEFW 0
ARGC: DEFW 0
ARGV: DEFW 0
;
;*** Get File Name to FCB
;
; e HL = points to file name [x:]<filename.ext>
; DE = points to File Control Block
;
;
GETNOM: ld a,(hl) ;get first letter &
sub 040H ; treat it as x:
ld (de),a ; save presumed drive
inc hl
ld a,(hl)
cp ':' ; was it a drive name ?
inc hl
jr z,GNOM1
xor a ;no, so default drive
ld (de),a
dec hl
dec hl
;
GNOM1: inc de
push de ;clear old name
ld b,11
ld a,SPACE
GNOM2: ld (de),a
inc de
djnz GNOM2
ld b,24
xor a
GNOM3: ld (de),a ;set rest to 0
inc de
djnz GNOM3
pop de
push de
;
ld b,8 ;get file name
GNOM4: call CHKSEP ;leavee Control Block
ret z ; end of file name
cp '.' ;ext sepatator ?
inc hl
jr z,GNOM5
ld (de),a
inc de
djnz GNOM4
inc hl ;jump dot
;
GNOM5: pop de
ld bc,8
ex de,hl
add hl,bc
ex de,hl
ld b,3
GNOM6: call CHKSEP
ret z
ld (de),a
inc de
inc hl
djnz GNOM6
ret
;
;
;
;*** Check for Separator
;
; e HL = points to character to check
; x A = character
; ZY = 1 if separator / 0 if not
;
;
CHKSEP: ld a,(hl)
or a ;end of string
ret z
cp ';' ;command separator
ret z
cp '|' ;pipe separator
ret z
cp '<' ;IO separator (I)
ret z
cp '>' ;IO separator (O)
ret z
cp SPACE ;word separator
ret
;
;
;
;*** Open I/O Buffer
;
; e A = 0 for output / 1 for input
; HL = pointer to I/O Buffer Area
; DE = points to file name string
; x A = 0 success / FF error / FE file exists
;
;
OPNIO: ld (hl),10000000B ;set bit 7 for CON: out
push hl ;save IObuf address
ld bc,38 ;clear DMA buffer
add hl,bc
ld (hl),0 ;set buffer count to zero
call CLRBUF
;
or a ;check if input or output
jr nz,OPN3
;
ld hl,OUTDEV ;open OUTPUT
ld b,3
OPN1: ex de,hl
push hl ;HL pnts to a filename
push de ;DE pnts to device name string
call SUBSTR ;chk if DE starts HL
pop hl ;get device array pnt
pop de ;get filename pnt
or a ;if A = 0 then no match
jr nz,OPN5 ; else a match so continue
pop hl ;garbage
ret ;return OK (A = 0)
;
OPN5: ld a,b ;protect counter
ld bc,05
add hl,bc ;HL pnt to next device string
ld b,a ;get counter
;
ex (sp),hl ;get IObuf pnt, hold device pnt
rr (hl) ;shift device bit in IObuf
ex (sp),hl ;filp again
djnz OPN1
;
pop hl ;get IObuf pnt
inc hl ;pnt to FCB
push hl ;hold it again
ex de,hl ;DE = FCB HL = filename
call GETNOM ;copy filename to FCB
pop de ;fresh FCB pnt
push de
ld c,OPEN ;try to open file
call BDOS
pop de ;get FCB pnt
cp 0FFH ;if no file (FF) then
jr z,OPN2 ; try to create a new file
ld a,0FEH ;return FE if file
ret ; already exists
;
OPN2: ld c,MAKE
call BDOS
cp 0FFh ;return FF for error
ret z
xor a ;return 0 for success
ret
;
OPN3: pop hl ;copy of IObuf
push hl
ld (hl),00000001B ;set bit 0 for CON: in
ld bc,37
add hl,bc
ld (hl),080H ;force initial read for file input
;
ld b,2
ld hl,INDEV
OPN4: ex de,hl
push hl
push de
call SUBSTR
pop hl
pop de
or a
jr nz,OPN6
pop hl
ret
;
OPN6: ld a,b
ld bc,05
add hl,bc
ld b,a
;
ex (sp),hl
rl (hl)
ex (sp),hl
djnz OPN4
;
pop hl
inc hl
push hl
ex de,hl
call GETNOM
pop de
ld c,OPEN
call BDOS
cp 0FFh
ret z
xor a
ret
;
OUTDEV: DEFM 'CON:'
DEFB 0
DEFM 'PUN:'
DEFB 0
DEFM 'LST:'
DEFB 0
INDEV: DEFM 'CON:'
DEFB 0
DEFM 'RDR:'
DEFB 0
;
;
;
;*** I/O Character
;
; This routine will determine the direction of the buffer and
; either send or receive, but not both, a character. More than
; one output device may be specified for an output buffer, but
; only one input device may be specified for an input buffer.
;
; e A = character to send if any
; HL = pointer to I/O Buffer
; x A = character if any received
; B = 0 success / FF error / FE EOF
;
; I/O Buffer :
;
; IOBUF +0 channel and direction byte
; +1 FCB
; +37 put/get offset into DMA buffer
; +38 DMA buffer
; +166 end of buffer + 1
;
; Channel Byte Format :
;
; Output Nibble / Input nibble
; 7 6 5 4 3 2 1 0
; CON: PUN: LST: FILE --- FILE RDR: CON:
;
; Note: that CON: out is not allowed to send a ctrl-Z (EOF) code.
; This is so that both text and object files have only one common
; EOF code which is a physical end.
;
;
IOCHAR: ld e,a
ld b,0FEh ;assume failure
ld a,(hl) ;get direction
or a
ret z ;channel closed
;
and 11110000B
jr nz,IOC3
;
ld a,(hl) ;INPUT section
inc hl
rrca
jr nc,IOC1
ld c,CONIN ;always get char
jp BDOS ;never fails
;
IOC1: rrca
jr nc,IOC2
ld c,RDRIN ;always get char
jp BDOS ;never fails
;
IOC2: ld a,e
ld e,l ;DE = FCB
ld d,h
ld bc,36
add hl,bc ;HL = GDMA
jp GETF ;this could fail
;
IOC3: inc hl ;OUTPUT section
rlca
jr nc,IOC5
ld a,EOF ;do not allow EOF
cp e ; to go to screen
ret z
ld c,CONOUT ;always send char
IOC4: jp BDOS ;never fails
;
IOC5: rlca
jr nc,IOC6
ld c,PUNOUT ;always send char
jr IOC4 ;never fails
;
IOC6: rlca
jr nc,IOC7
ld c,LSTOUT ;always send char
jr IOC4 ;never fails either
;
IOC7: ld a,e
ld d,h
ld e,l
ld bc,36
add hl,bc
jp PUTF ;this could fail
;
;
;
;*** GETF - get character from file buffer
;
; e HL = pointer to GDMA
; DE = pointer to FCB
; x A = fetched byte
; B = 0 success / FF error / FE EOF
;
;
GETF: ld a,07FH ;get length N
cp (hl) ;compare N & OUT offset
jr nc,GETF1
push hl
inc hl
call GETBUF ;wrap buffer so fill it
ld b,a
pop hl
ld (hl),0 ;OUT = 0 if N < OUT
GETF1: ld e,(hl) ;get OUT offset
inc (hl) ;OUT++
inc hl
ld d,0
add hl,de ;add offset to location
ld a,(hl) ;fetch byte
ret
;
;
;
;*** GETBUF - get sector
;
; e HL = DMA
; DE = FCB
; x A = 0 success / FF error / FE EOF
;
;
GETBUF: call CLRBUF ;clear it anyway
push de ;hold on to FCB pnt
ex de,hl ;set DMA area
ld c,SETDMA
call BDOS
pop de ;get a copy of
push de ; FCB pnt
ld c,RDSEQ ;read sector
call BDOS
pop de
or a ;return 0 if not EOF
ret z
dec a
ld a,0FFh ;return FF if error
ret nz
;
; if PORTA
; ld c,SNEXT ;PortaPak system bug
; call BDOS ; double chk EOF
; inc a
; ld a,0 ;return 0 if not EOF
; ret nz
; dec a
; endif
;
dec a ;return FE if EOF
ret
;
;
;
;*** Fill DMA Buffer with EOF
;
; e HL = pointer to DMA
;
;
CLRBUF: push af
push bc
push de
push hl
ld d,h
ld e,l
inc de
ld bc,127
ld a,EOF
ld (hl),a
ldir
pop hl
pop de
pop bc
pop af
ret
;
;
;*** PUTF - send character to file buffer
;
; e A = byte to store
; HL = pointer to PDMA
; DE = pointer to FCB
; x B = 0 success / FF error
;
;
PUTF: ld c,a ;hold this
ld a,07FH ;get length N
cp (hl) ;compare N & IN offset
jr nc,PUTF1
push bc
push hl
inc hl
call PUTBUF
pop hl
pop bc
ld b,a ;get error condition
or a ;do not write out char
ret nz ; if a write error
;
ld (hl),0 ;IN = 0 if N < IN
PUTF1: ld e,(hl) ;get IN offset
inc (hl) ;IN++
inc hl
ld d,0
add hl,de ;add offset to location
ld (hl),c ;store byte
ret
;
;
;
;*** PUTBUF - send sector
;
; e HL = DMA
; DE = FCB
; x A = 0 success / FF error
;
;
PUTBUF: push hl
push de
ex de,hl
ld c,SETDMA
call BDOS
pop de
ld c,WRSEQ
call BDOS
or a ;return 0 if OK
pop hl
jp z,CLRBUF
ld a,0FFh ;return FF if error
ret
;
;
;
;*** Close I/O
;
; e HL = pointer to I/O Buffer
; x A = 0 success / FF error
;
;
CLSIO: xor a
bit 4,(hl) ;chk if write file open
ld (hl),a ;close channel
ret z ;not a write file
inc hl
ld d,h
ld e,l
ld bc,37
add hl,bc
push de
call PUTBUF ;send last sector
pop de
or a
ret nz
ld c,CLOSE ;close write file
call BDOS
cp 0FFh
ret z ;return on error
xor a ; else zero A &
ret ; return success
;
;
;
;*** String Compare
;
; e HL = pointer to string A
; DE = pointer to string B
; x A = FF A < B
; 0 A = B
; 1 A > B
;
;
STRCMP: ld a,(de)
ld b,(hl)
or a
jr z,SCMP2
ld c,a
ld a,b
or a
ld b,a
ld a,c
jr z,SCMP2
cp b
inc hl
inc de
jr z,STRCMP
SCMP1: ld a,1
ret c
ld a,0FFH
ret
SCMP2: cp b
ld a,0
ret z
jr SCMP1
;
;
;
;*** Sub-String Match
;
; e HL = poniter to larger string
; DE = pointer to smaller substring
; x A = 0 substring match
; 1 no match
;
;
SUBSTR: ld a,(de)
or a
ret z
cp (hl)
inc hl
inc de
ld a,0FFh
jr z,SUBSTR
ret
;
;
;
;*** Unsigned Multiplication for 16x16 & 16x8 & 8x8
;
; e HL x DE
; x DEHL
;
;
UMUL: ld b,h
ld c,l
ld hl,0
ld a,16
UMUL1: add hl,hl
ex de,hl
adc hl,hl
ex de,hl
jr nc,UMUL2
add hl,bc
jr nc,UMUL2
inc de
UMUL2: dec a
jr nz,UMUL1
ret
;
;
;
;*** Unsigned Division for 16/16 and 16/8
;
; e DE = dividend
; HL = divisor
; (DE / HL)
; x HL = quoitent
; DE = remainder
;
;
UDIV: xor a
push af
jr DIVDIV
;
;*** Signed Division for 16/16 and 16/8
;
; e DE = dividend
; HL = divisor
; (DE / HL)
; x HL = quoitent
; DE = remainder
;
;
ADIV: ld a,d
xor h
push af
xor h
ex de,hl
call m,TWOS
ex de,hl
ld a,h
or a
;
;
DIVDIV: call p,TWOS
ld c,l
ld b,h
ld hl,0
ld a,b
inc a
jr nz,DIV1
;
ld a,d
add a,c
ld a,16
jr c,DIV2
;
DIV1: ld l,d
ld d,e
ld e,h
ld a,8
DIV2: ex de,hl
add hl,hl
ex de,hl
adc hl,hl
;
DIV3: push hl
add hl,bc
pop hl
jr nc,DIV3
add hl,bc
inc de
;
DIV4: dec a
jr nz,DIV2
ex de,hl
pop af
ret p
ex de,hl
call TWOS
ex de,hl
;
;*** Negate & Compilment
;
; TWOS e HL
; x HL' + 1
; COM e HL
; x HL'
;
;
TWOS: dec hl
COM: ld a,h
cpl
ld h,a
ld a,l
cpl
ld l,a
ret
;
;
;
;******************************************************************************
;
; Message / Text Section
;
SUBNOM: DEFM '$$$ SUB'
;
MSG1: DEFM 'p: cannot open file'
DEFB CR
DEFB LF
DEFB '$'
;
MSG2: DEFM 'p: read error'
DEFB CR
DEFB LF
DEFB '$'
;
MSG4: DEFM 'p: cannot create file'
DEFB CR
DEFB LF
DEFB '$'
;
MSG5: DEFM 'p: close error'
DEFB CR
DEFB LF
DEFB '$'
;
MSG6: DEFM 'p: write error'
DEFB CR
DEFB LF
DEFB '$'
;
ERAPIP: DEFM 'ERA .PY?'
DEFB 0
;
PIPE1: DEFM ' <.PY1'
DEFB 0
;
PIPE2: DEFM ' <.PY2'
DEFB 0
;
POUT1: DEFM ' >.PY1'
DEFB 0
;
PIN1: DEFM ' <.PY1 >.PY2'
DEFB 0
;
PIN2: DEFM ' <.PY2 >.PY1'
DEFB 0
;
;*****************************************************************************
;
; Data Section
;
PY1 equ $+1 ;pipe direction flags
PY2 equ PY1+1
BUFPNT equ PY2+2 ;pointer to working buffer
LSTP equ BUFPNT+2 ;base node to linked list
FRESPC equ LSTP+2 ;we need know where free space starts
DMACHR equ FRESPC+2 ;pointer to command line
FCBSUB equ DMACHR+2
FCBREC equ FCBSUB+33
FIN equ FCBSUB+36 ;submit file I/O buffer
BUFF equ FIN+1+36+1+128+1
WORK equ BUFF+SECSIZ
;
;
;
END