close.o \
ctype.o \
cvline.o \
- diskerror.o \
+ diskcmd.o \
filedes.o \
filename.o \
filevars.o \
oserror.o \
read.o \
revers.o \
+ rwcommon.o \
scratch.o \
sysremove.o \
systime.o \
;-----------------------------------------------------------------------------
; Device numbers
;
-
+
CBMDEV_KBD = 0
CBMDEV_DATASETTE= 1
CBMDEV_RS232 = 2
CBMDEV_SCREEN = 3
+
+;-----------------------------------------------------------------------------
+; Disk stuff
+;
+
+MAX_DRIVES = 24
+FIRST_DRIVE = 8
+
+
.export _close
- .import getdiskerror
+ .import readdiskerror, closecmdchannel
.import __errno, __oserror
+ .importzp tmp2
.include "errno.inc"
.include "cbm.inc"
bne invalidfd
cmp #MAX_FDS ; Is it valid?
bcs invalidfd ; Jump if no
+ sta tmp2 ; Save the handle
-; Check if the LFN is valid and the file is open for writing
+; Check if the file is actually open
- adc #LFN_OFFS ; Carry is already clear
tax
- lda fdtab-LFN_OFFS,x; Get flags for this handle
+ lda fdtab,x ; Get flags for this handle
+ and #LFN_OPEN
beq notopen
; Valid lfn, close it. The close call is always error free, at least as far
; as the kernal is involved
lda #LFN_CLOSED
- sta fdtab-LFN_OFFS,x
- lda unittab,x
- pha ; Push unit for this file
- txa
+ sta fdtab,x
+ lda tmp2 ; Get the handle
+ clc
+ adc #LFN_OFFS ; Make LFN from handle
jsr CLOSE
- pla
-; Read the drive error channel
+; Read the drive error channel, then close it
- lda unittab,x
- tax
- jsr getdiskerror
- cmp #$00
- bne error
+ ldy tmp2 ; Get the handle
+ ldx unittab,y ; Get teh disk for this handle
+ jsr readdiskerror ; Read the disk error code
+ pha ; Save it on stack
+ ldy tmp2
+ ldx unittab,y
+ jsr closecmdchannel ; Close the disk command channel
+ pla ; Get the error code from the disk
+ bne error ; Jump if error
; Successful
- tax
+ tax ; Return zero in a/x
rts
; Error entry, file descriptor is invalid
--- /dev/null
+;
+; Ullrich von Bassewitz, 17.11.2002
+;
+; Handle disk command channels
+;
+
+ .export isdisk
+ .export opencmdchannel
+ .export closecmdchannel
+ .export readdiskerror
+ .export writediskcmd
+
+ .importzp tmp1, ptr1
+
+ .include "cbm.inc"
+ .include "filedes.inc"
+
+;--------------------------------------------------------------------------
+; isdisk: Return carry clear if the unit number in X is a disk, return
+; carry set if not.
+
+.proc isdisk
+
+ cpx #FIRST_DRIVE ; Disk unit?
+ bcc @L1 ; Branch if no disk
+ cpx #FIRST_DRIVE+MAX_DRIVES
+ rts
+
+@L1: sec
+ rts
+
+.endproc
+
+;--------------------------------------------------------------------------
+; Open the command channel for the disk unit in X. The function returns an
+; error code in A and sets the flags according to the contents of A.
+
+opencmdchannel:
+
+ jsr isdisk ; Disk unit?
+ bcs success
+
+; Is this channel already open?
+
+ ldy opentab-FIRST_DRIVE,x
+ bne isopen
+
+; Open the command channel, Carry is still clear
+
+ stx tmp1 ; Save the unit number
+ txa ; Get unit number
+ adc #(LFN_OFFS+MAX_FDS-FIRST_DRIVE)
+ ldy #15 ; Secondary address for cmd channel
+ jsr SETLFS
+
+ lda #0
+ jsr SETNAM ; No name supplied to OPEN
+
+ jsr OPEN
+ bcs done ; Error, code is in A
+
+; Command channel is open now. Increment the count
+
+ ldx tmp1 ; Unit number
+ ldy opentab-FIRST_DRIVE,x
+isopen: iny
+ tya
+ sta opentab-FIRST_DRIVE,x
+
+; Done, return success
+
+success:lda #$00
+done: cmp #$00 ; Set flags for return code
+ rts
+
+
+;--------------------------------------------------------------------------
+; closecmdchannel: Decrement the counter for the disk command channel and
+; close the channel if the counter drops to zero. The function expects the
+; drive number in X and returns an error code in A. The flags for the return
+; code are set when the function returns.
+
+closecmdchannel:
+
+ jsr isdisk ; Disk unit?
+ bcs success
+
+; Is this channel really open?
+
+ ldy opentab-FIRST_DRIVE,x
+ beq success ; OOPS! Channel is not open
+
+; Decrement the count and stor it back
+
+ dey
+ tya
+ sta opentab-FIRST_DRIVE,x
+
+; If the counter is now zero, close the channel. We still have carry clear
+; when we come here.
+
+ bne success
+ txa ; Make LFN from drive number
+ adc #(LFN_OFFS+MAX_FDS-FIRST_DRIVE)
+ jsr CLOSE
+ bcs done
+ bcc success
+
+;--------------------------------------------------------------------------
+; readdiskerror: Read a disk error from an already open command channel.
+; Returns an error code in A, which may either be the code read from the
+; command channel, or another error when accessing the command channel failed.
+
+readdiskerror:
+
+ jsr isdisk
+ bcs success
+
+; Read the command channel. We won't check the status after the channel is
+; open, because this seems to be unnecessary in most cases.
+
+ txa
+ clc ; Make LFN from drive number
+ adc #(LFN_OFFS+MAX_FDS-FIRST_DRIVE)
+ tax
+ jsr CHKIN ; Make the command channel input
+ bcs done ; Bail out with error code in A
+
+ jsr BASIN
+ and #$0F ; Make digit value from PETSCII
+ sta tmp1
+ asl a ; * 2
+ asl a ; * 4, carry clear
+ adc tmp1 ; * 5
+ asl a ; * 10
+ sta tmp1
+
+ jsr BASIN
+ and #$0F ; Make digit value from PETSCII
+ clc
+ adc tmp1
+
+; Errors below 20 are not real errors. Fix that
+
+ cmp #20+1
+ bcs @L1
+ lda #$00
+@L1: pha
+
+; Read the remainder of the message and throw it away
+
+@L2: jsr BASIN
+ cmp #$0D
+ bne @L2
+
+; Close the input channel
+
+ jsr CLRCH
+
+; Restore the error code (will also set the flags) and return
+
+ pla
+ rts
+
+;--------------------------------------------------------------------------
+; writediskcmd: Gets pointer to data in ptr1, length in A. Writes all data
+; to the command channel of the given drive. Returns an error code in A,
+; flags are set according to the contents of A.
+
+writediskcmd:
+
+ jsr isdisk
+ bcs success
+
+; Remember the length
+
+ sta tmp1
+
+; Write to the command channel.
+
+ txa
+ clc ; Make LFN from drive number
+ adc #(LFN_OFFS+MAX_FDS-FIRST_DRIVE)
+ tax
+ jsr CKOUT ; Make the command channel output
+ bcs done ; Bail out with error code in A
+
+ ldy #$00
+@L1: cpy tmp1
+ bcs @L3
+ lda (ptr1),y
+ iny
+ jsr BSOUT
+ bcc @L1
+
+@L2: pha
+ jsr CLRCH
+ pla
+ rts
+
+@L3: jsr CLRCH
+ lda #$00
+ rts
+
+
+
+;--------------------------------------------------------------------------
+; Data
+
+.bss
+
+opentab: .res MAX_DRIVES, 0
+++ /dev/null
-;
-; Ullrich von Bassewitz, 16.11.2002
-;
-; Read the disk error channel
-;
-
- .export readdiskerror, getdiskerror
- .import fnunit
- .importzp tmp1
-
- .include "cbm.inc"
-
-;--------------------------------------------------------------------------
-; readdiskerror: Read a disk error from an already open command channel.
-; Returns an error code in A, which may either be the code read from the
-; command channel, or another error when accessing the command channel failed.
-
-.proc readdiskerror
-
-; Read the command channel. We won't check the status after the channel is
-; open, because this seems to be unnecessary in most cases.
-
- ldx #15
- jsr CHKIN ; Read from LFN 15
- bcs done ; Bail out with error code in A
-
- jsr BASIN
- and #$0F ; Make digit value from PETSCII
- sta tmp1
- asl a ; * 2
- asl a ; * 4, carry clear
- adc tmp1 ; * 5
- asl a ; * 10
- sta tmp1
-
- jsr BASIN
- and #$0F ; Make digit value from PETSCII
- clc
- adc tmp1
-
-; Errors below 20 are not real errors. Fix that
-
- cmp #20+1
- bcs done
- lda #0
-
-done: rts
-
-.endproc
-
-
-;--------------------------------------------------------------------------
-; getdiskerror: Open the command channel to a disk unit with id in X. Read
-; the error and close it again. Returns an error code in A, which may either
-; be the code read from the command channel, or another error when accessing
-; the command channel failed.
-
-.proc getdiskerror
-
- cpx #8 ; Disk unit?
- bcc nodisk
-
- lda #15 ; Command channel
- tay ; Secondary address
- jsr SETLFS
-
- lda #$00
- jsr SETNAM ; No name supplied to OPEN
-
- jsr OPEN
- bcs err
-
- jsr readdiskerror
- pha ; Save error code
- lda #15
- jsr CLOSE
- pla
-
-err: rts
-
-nodisk: lda #$00
- rts
-
-.endproc
-
-
-
LFN_CLOSED = $00 ; LFN is closed
LFN_READ = $01 ; Open for reading
LFN_WRITE = $02 ; Open for writing
+LFN_OPEN = (LFN_READ | LFN_WRITE)
+LFN_EOF = $80 ; Read to EOF
LFN_STDIN = LFN_OFFS+0
LFN_STDOUT = LFN_OFFS+1
.import addysp, popax
.import scratch, fnparse, fncomplete, fnset
- .import getdiskerror
+ .import opencmdchannel, closecmdchannel, readdiskerror
.import __errno, __oserror
.import fnunit
.importzp sp, tmp2, tmp3
jsr OPEN
bcs error
-; Read the error channel
+; Open the the drive command channel and read it
ldx fnunit
- jsr getdiskerror
- cmp #0
- beq isopen ; Branch if no error
-
-; We had an error, close the file
-
- pha
- lda tmp2
- clc
- adc #LFN_OFFS
- jsr CLOSE
- pla
- bne error ; Branch always
+ jsr opencmdchannel
+ bne closeandexit
+ ldx fnunit
+ jsr readdiskerror
+ bne closeandexit ; Branch on error
; File is open. Mark it as open in the table
-isopen: ldx tmp2
+ ldx tmp2
lda tmp3
sta fdtab,x
lda fnunit
sta __errno+1
beq errout
+; Error entry: Close the file and exit
+closeandexit:
+ pha
+ lda tmp2
+ clc
+ adc #LFN_OFFS
+ jsr CLOSE
+ ldx fnunit
+ jsr closecmdchannel
+ pla
+ bne error ; Branch always
.endproc
.export _read
.constructor initstdin
-
+
+ .import rwcommon
.import popax
.import __errno, __oserror
- .importzp ptr1, ptr2, ptr3, tmp1, tmp2
+ .importzp ptr1, ptr2, ptr3, tmp1, tmp2, tmp3
.include "errno.inc"
.include "fcntl.inc"
.proc _read
-; Retrieve count
-
- jsr popax ; Get count
- eor #$FF
- sta ptr1
- txa
- eor #$FF
- sta ptr1+1 ; Remember -count-1
-
-; Retrieve buf
-
- jsr popax
- sta ptr2
- stx ptr2+1
-
-; Retrieve the handle
-
- jsr popax
-
-; Check if we have a valid handle
-
- cpx #$00
- bne invalidfd
- cmp #MAX_FDS ; Is it valid?
- bcs invalidfd ; Jump if no
+ jsr rwcommon ; Pop params, check handle
+ bcs invalidfd ; Branch if handle not ok
; Check if the LFN is valid and the file is open for writing
and #LFN_READ ; File open for writing?
beq notopen
+; Check the EOF flag. If it is set, don't read anything
+
+ lda fdtab-LFN_OFFS,x; Get flags for this handle
+ bmi eof
+
; Valid lfn. Make it the input file
jsr CHKIN
bcs error
-; Clear the byte counter
-
- lda #$00
- sta ptr3
- sta ptr3+1
-
-; Read the status to check if we are already at the end of the file
-
- jsr READST
- and #%01000000
- bne done
-
; Go looping...
- beq deccount ; Branch always
+ bcc @L3 ; Branch always
; Read the next byte
-loop: jsr BASIN
+@L0: jsr BASIN
sta tmp1 ; Save the input byte
jsr READST ; Read the IEEE status
- sta tmp2 ; Save it
+ sta tmp3 ; Save it
and #%10111111 ; Check anything but the EOI bit
bne error5 ; Assume device not present
; Get the status again and check the EOI bit
-@L2: lda tmp2
+@L2: lda tmp3
and #%01000000 ; Check for EOI
- bne done ; Jump if end of file reached
+ bne @L4 ; Jump if end of file reached
; Decrement the count
-deccount:
- inc ptr1
- bne loop
+@L3: inc ptr1
+ bne @L0
inc ptr1+1
- bne loop
+ bne @L0
+ beq done ; Branch always
+
+; Set the EOI flag and bail out
+
+@L4: ldx tmp2 ; Get the handle
+ lda #LFN_EOF
+ ora fdtab,x
+ sta fdtab,x
; Read done, close the input channel
; Return the number of chars read
- lda ptr3
+eof: lda ptr3
ldx ptr3+1
rts
notopen:
lda #3 ; File not open
bne error
-
+
; Error entry, status not ok
error5: lda #5 ; Device not present
--- /dev/null
+;
+; Ullrich von Bassewitz, 17.11.2002
+;
+; Common stuff for the read/write routines
+;
+
+ .export rwcommon
+
+ .import popax
+ .importzp ptr1, ptr2, ptr3, tmp2
+
+ .include "filedes.inc"
+
+
+;--------------------------------------------------------------------------
+; rwcommon: Pop the parameters from stack, preprocess them and place them
+; into zero page locations. Return carry set if the handle is invalid,
+; return carry clear if it is ok. If the carry is clear, the handle is
+; returned in A.
+
+.proc rwcommon
+
+ jsr popax ; Get count
+ eor #$FF
+ sta ptr1
+ txa
+ eor #$FF
+ sta ptr1+1 ; Remember -count-1
+
+ jsr popax ; Get buf
+ sta ptr2
+ stx ptr2+1
+
+ lda #$00
+ sta ptr3
+ sta ptr3+1 ; Clear ptr3
+
+ jsr popax ; Get the handle
+ sta tmp2
+ cpx #$01
+ bcs inv
+ cmp #MAX_FDS
+inv: rts
+
+.endproc
+
+
;
.export scratch
- .import readdiskerror
+ .import opencmdchannel, closecmdchannel, writediskcmd
.import fnunit, fnlen, fncmd
+ .importzp ptr1
.include "cbm.inc"
.proc scratch
- lda #15 ; Command channel
- ldx fnunit ; Unit
- tay ; Secondary address
- jsr SETLFS
+ ldx fnunit
+ jsr opencmdchannel
+ bne done
lda #'s' ; Scratch command
sta fncmd
+
+ lda #<fncmd
+ sta ptr1
+ lda #>fncmd
+ sta ptr1+1
+
ldx fnlen
inx ; Account for "S"
txa ; Length of name into A
- ldx #<fncmd
- ldy #>fncmd
- jsr SETNAM
-
- jsr OPEN
- bcs done
-
- jsr readdiskerror ; Read the command channel
+ ldx fnunit ; Unit
+ jsr writediskcmd
pha
- lda #15
- jsr CLOSE
+ ldx fnunit
+ jsr closecmdchannel
pla
done: rts
.export _write
.constructor initstdout
- .import incsp6
+ .import rwcommon
.import __errno, __oserror
- .importzp sp, ptr1, ptr2
+ .importzp sp, ptr1, ptr2, ptr3
.include "errno.inc"
.include "fcntl.inc"
.proc _write
- ldy #4
- lda (sp),y ; Get fd
-
-; Check if we have a valid handle
-
- cmp #MAX_FDS ; Is it valid?
- bcs invalidfd ; Jump if no
+ jsr rwcommon ; Pop params, check handle
+ bcs invalidfd ; Branch if handle not ok
; Check if the LFN is valid and the file is open for writing
jsr CKOUT
bcs error
-
-; Calculate -count-1 for easier looping
-
- ldy #0
- lda (sp),y
- eor #$FF
- sta ptr1
- iny
- lda (sp),y
- eor #$FF
- sta ptr1+1
-
-; Get the pointer to the data buffer
-
- iny
- lda (sp),y
- sta ptr2
- iny
- lda (sp),y
- sta ptr2+1
- jmp deccount
+ bcc @L2
; Read the IEEE488 status
-loop: jsr READST
+@L0: jsr READST
cmp #0
bne error5
+; Output the next character from the buffer
+
ldy #0
lda (ptr2),y
inc ptr2
bne @L1
inc ptr2+1 ; A = *buf++;
-
@L1: jsr BSOUT
+; Count characters written
+
+ inc ptr3
+ bne @L2
+ inc ptr3+1
+
; Decrement count
-deccount:
- inc ptr1
- bne loop
+@L2: inc ptr1
+ bne @L0
inc ptr1+1
- bne loop
+ bne @L0
; Wrote all chars, close the output channel
; Return the number of chars written
- ldy #1
- lda (sp),y
- tax
- dey
- lda (sp),y
- jmp incsp6
+ lda ptr3
+ ldx ptr3+1
+ rts
; Error entry, file descriptor is invalid
error: sta __oserror
errout: lda #$FF
tax ; Return -1
- jmp incsp6
+ rts
.endproc