Initial source push

This commit is contained in:
David Schmidt 2021-07-02 23:02:31 -04:00
parent a505407392
commit 1873055fa3
9 changed files with 2875 additions and 0 deletions

9
README.md Normal file
View File

@ -0,0 +1,9 @@
# Apple /// Driver Depot
### Repository for all Apple /// drivers, buildable with `ca65`
## Idea
Be able to maintain all known Apple /// device drivers with "modern" tools (Have _you_ used the Apple Pascal Assembler?!?)
The `ca65` assembler is part of the `cc65` toolchain: [cc65](https://github.com/cc65/cc65)

19
build/README.md Normal file
View File

@ -0,0 +1,19 @@
# Build System
### Json database
```
{
"driver_dib1": ".VSDRIVE",
"description": "Apple /// Virtual Serial Drive Driver by David Schmidt 2012 - 2014",
"dir": "vsdrive",
"repo": "https://github.com/ADTPro/adtpro",
"asm": "blob/main/src/client/sos/serial/drive/vsdrive.asm",
"sha": "552170569181b05e810bdbcca6828efab3b3ae83",
"local_asm": "vsdrive.asm"
}
```
`"repo`: The GitHub repo, or other source of truth for this driver
`"asm"`: The upstream source of the main assembly file
`"sha`: If from a GitHub repo, the sha of the commit resulting in the upstream source
`"local_asm"`: The downstream ca65-assembly version of `"asm"`

29
build/manifest.json Normal file
View File

@ -0,0 +1,29 @@
[
{
"driver_dib1": ".VSDRIVE",
"description": "Apple /// Virtual Serial Drive Driver by David Schmidt 2012 - 2014",
"dir": "vsdrive",
"repo": "https://github.com/ADTPro/adtpro",
"asm": "blob/main/src/client/sos/serial/drive/vsdrive.asm",
"sha": "552170569181b05e810bdbcca6828efab3b3ae83",
"local_asm": "vsdrive.asm"
},
{
"driver_dib1": ".CFFA3000D1",
"description": "Apple /// CFFA3000 (Compact Flash For Apple 3000) Driver by David Schmidt 2011",
"dir": "cffa3000",
"repo": "https://github.com/david-schmidt/apple-iii-cffa3000-driver",
"asm": "blob/master/src/CFFA3000.s",
"sha": "1500353920197bec5ddfe96803340063b4cacc38",
"local_asm": "CFFA3000.s"
},
{
"driver_dib1": ".FOCUSD1",
"description": "Apple /// Focus Driver - by David Schmidt 2019",
"dir": "FocusDrive3",
"repo": "https://github.com/david-schmidt/FocusDrive3",
"asm": "blob/master/src/focus3.s"
"sha": "5699c3146c4f8c3577b1cbe1f9b8b726c09e0cfd",
"local_asm": "focus3.s"
}
]

View File

@ -0,0 +1 @@
# Apple /// driver for the Focus IDE Interface Card

1084
drivers/FocusDrive3/focus3.s Normal file

File diff suppressed because it is too large Load Diff

985
drivers/cffa3000/CFFA3000.s Normal file
View File

@ -0,0 +1,985 @@
; CFFA3000
; .TITLE "Apple /// Compact Flash For Apple 3000 (CFFA3000) Driver"
.PROC CFFA3000
.feature labels_without_colons
.setcpu "6502"
.reloc
DriverVersion = $1000 ; Version number
DriverMfgr = $4453 ; Driver Manufacturer - DS
;
; SOS Equates
;
ExtPG = $1401 ; Driver extended bank address offset
AllocSIR = $1913 ; Allocate system internal resource
SELC800 = $1922 ; Enable Expansion ROM Space
SysErr = $1928 ; Report error to system
EReg = $FFDF ; Environment register
ReqCode = $C0 ; Request code
SOS_Unit = $C1 ; Unit number
SosBuf = $C2 ; SOS buffer pointer (2 bytes)
ReqCnt = $C4 ; Requested byte count
CtlStat = $C2 ; Control/status code
CSList = $C3 ; Control/status list pointer
SosBlk = $C6 ; Starting block number
QtyRead = $C8 ; Pointer to bytes read return by D_READ
;
; Our temps in zero page
;
Count = $CD ; 2 bytes
C800Ptr = $CF ; 2 bytes
;
; Parameter block specific to current SOS request
;
CFFAUnit = $D1
Num_Blks = $D4 ; 2 bytes lsb, msb
DataBuf = $D6 ; 2 bytes
;
; SOS Error Codes
;
XDNFERR = $10 ; Device not found
XBADDNUM = $11 ; Invalid device number
XREQCODE = $20 ; Invalid request code
XCTLCODE = $21 ; Invalid control/status code
XCTLPARAM = $22 ; Invalid control/status parameter
XNORESRC = $25 ; Resources not available
XBADOP = $26 ; Invalid operation
XIOERROR = $27 ; I/O error
XNODRIVE = $28 ; Drive not connected
XBYTECNT = $2C ; Byte count not a multiple of 512
XBLKNUM = $2D ; Block number to large
XDISKSW = $2E ; Disk switched
XNORESET = $33 ; Device reset failed
;
; CFFA3000 Constants
;
kCmd3K_SetEnvironment = $01 ; Set X = 0xa3 for Apple ///
kCmd3K_Status = $10
kCmd3K_Read = $11
kCmd3K_Write = $12
CFFA3K_API = $CFED ; CFFA3000 API entry point
shUnitNumber = $CFDF
shStatusByte = $CFE0
shBlockNumber = $CFE1
;
; Switch Macro
;
.MACRO SWITCH index,bounds,adrs_table,noexec ;See SOS Reference
.IFNBLANK index ;If PARM1 is present,
LDA index ; load A with switch index
.ENDIF
.IFNBLANK bounds ;If PARM2 is present,
CMP #bounds+1 ; perform bounds checking
BCS @110 ; on switch index
.ENDIF
ASL A ;Multiply by 2 for table index
TAY
LDA adrs_table+1,Y ;Get switch address from table
PHA ; and push onto Stack
LDA adrs_table,Y
PHA
.IFBLANK noexec
; .IF noexec <> '*' ;If PARM4 is omitted,
RTS ; exit to code
; .ENDIF
.ENDIF
@110
.ENDMACRO
.SEGMENT "TEXT"
;
; Comment Field of driver
;
.WORD $FFFF ; Signal that we have a comment
.WORD COMMENT_END - COMMENT
COMMENT: .BYTE "Apple /// CFFA3000 (Compact Flash For Apple 3000) Driver by David Schmidt 2018"
COMMENT_END:
.SEGMENT "DATA"
;------------------------------------
;
; Device identification Block (DIB) - Volume #0
;
;------------------------------------
DIB_0 .WORD DIB_1 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D1 "; Device name
.BYTE $80 ; Active, no page alignment
DIB0_Slot .BYTE $01 ; Slot number
.BYTE $00 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB0_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;
; Device identification Block (DIB) - Volume #1
; Page alignment begins here
;
DIB_1 .WORD DIB_2 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D2 "; Device name
.BYTE $80 ; Active
DIB1_Slot .BYTE $01 ; Slot number
.BYTE $01 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB1_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Driver manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;
; Device identification Block (DIB) - Volume #2
;
DIB_2 .WORD DIB_3 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D3 "; Device name
.BYTE $80 ; Active
DIB2_Slot .BYTE $01 ; Slot number
.BYTE $02 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB2_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Driver manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;
; Device identification Block (DIB) - Volume #3
;
DIB_3 .WORD DIB_4 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D4 "; Device name
.BYTE $80 ; Active
DIB3_Slot .BYTE $01 ; Slot number
.BYTE $03 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB3_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Driver manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;
; Device identification Block (DIB) - Volume #4
;
DIB_4 .WORD DIB_5 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D5 "; Device name
.BYTE $80 ; Active
DIB4_Slot .BYTE $01 ; Slot number
.BYTE $04 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB4_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Driver manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;
; Device identification Block (DIB) - Volume #5
;
DIB_5 .WORD DIB_6 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D6 "; Device name
.BYTE $80 ; Active
DIB5_Slot .BYTE $01 ; Slot number
.BYTE $05 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB5_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Driver manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;
; Device identification Block (DIB) - Volume #6
;
DIB_6 .WORD DIB_7 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D7 "; Device name
.BYTE $80 ; Active
DIB6_Slot .BYTE $01 ; Slot number
.BYTE $06 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB6_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Driver manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;
; Device identification Block (DIB) - Volume #7
;
DIB_7 .WORD $0000 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D8 "; Device name
.BYTE $80 ; Active
DIB7_Slot .BYTE $01 ; Slot number
.BYTE $07 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB7_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Driver manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;------------------------------------
;
; Local storage locations
;
;------------------------------------
LastOP .RES $08, $FF ; Last operation for D_REPEAT calls
SIR_Addr .WORD SIR_Tbl
SIR_Tbl .RES $05, $00
SIR_Len = *-SIR_Tbl
RdBlk_Proc .WORD $0000
WrBlk_Proc .WORD $0000
MaxUnits .BYTE $00 ; The maximum number of units
DCB_Idx .BYTE $00 ; DCB 0's blocks
.BYTE DIB1_Blks-DIB0_Blks ; DCB 1's blocks
.BYTE DIB2_Blks-DIB0_Blks ; DCB 2's blocks
.BYTE DIB3_Blks-DIB0_Blks ; DCB 3's blocks
.BYTE DIB4_Blks-DIB0_Blks ; DCB 4's blocks
.BYTE DIB5_Blks-DIB0_Blks ; DCB 5's blocks
.BYTE DIB6_Blks-DIB0_Blks ; DCB 6's blocks
.BYTE DIB7_Blks-DIB0_Blks ; DCB 7's blocks
SigCF3K .BYTE "CF3K" ; CFFA3000 signature in memory
CardIsOK .BYTE $00 ; Have we found the CFFA3000 yet?
LastError .BYTE $00 ; Recent error RC from CFFA3000
;------------------------------------
;
; Driver request handlers
;
;------------------------------------
Entry LDA DIB0_Slot
JSR SELC800 ; Turn on C800 ROM space from our slot
LDA SOS_Unit
STA CFFAUnit
INC CFFAUnit ; CFFA3000 unit is 1-based vs. SOS 0-based
JSR Dispatch ; Call the dispatcher
LDX SOS_Unit ; Get drive number for this unit
LDA ReqCode ; Keep request around for D_REPEAT
STA LastOP,X ; Keep track of last operation
LDA #$00
JSR SELC800 ; Unselect C800 ROM space
RTS
;
; The Dispatcher. Note that if we came in on a D_INIT call,
; we do a branch to Dispatch normally.
; Dispatch is called as a subroutine!
;
DoTable .WORD DRead-1 ; 0 Read request
.WORD DWrite-1 ; 1 Write request
.WORD DStatus-1 ; 2 Status request
.WORD DControl-1 ; 3 Control request
.WORD BadReq-1 ; 4 Unused
.WORD BadReq-1 ; 5 Unused
.WORD BadOp-1 ; 6 Open - valid for character devices
.WORD BadOp-1 ; 7 Close - valid for character devices
.WORD DInit-1 ; 8 Init request
.WORD DRepeat-1 ; 9 Repeat last read or write request
Dispatch SWITCH ReqCode,9,DoTable ; Serve the request
;
; Dispatch errors
;
BadReq LDA #XREQCODE ; Bad request code!
JSR SysErr ; Return to SOS with error in A
BadOp LDA #XBADOP ; Invalid operation!
JSR SysErr ; Return to SOS with error in A
;
; D_REPEAT - repeat the last D_READ or D_WRITE call
;
DRepeat LDX SOS_Unit
LDA LastOP,X ; Recall the last thing we did
CMP #$02 ; Looking for operation < 2
BCS BadOp ; Can only repeat a read or write
STA ReqCode
JMP Dispatch
NoDevice LDA #XDNFERR ; Device not found
JSR SysErr ; Return to SOS with error in A
;
; D_INIT call processing - called once each for all volumes.
;
DInit LDA SOS_Unit ; Check if we're initting the zeroeth unit
BNE UnitInit ; No - then skip the signature check
CheckSig LDA #$C0 ; Form a $CsF6 address, where s = slot #
ORA DIB0_Slot ; Add in slot number
STA Count+1
LDA #$F6
STA Count
LDY #$03
@1 LDA (Count),Y
CMP SigCF3K,Y ; Check for 'CF3K' signature in our slot
BNE NoDevice ; No device if all four bytes don't match
DEY
BPL @1
LDA DIB0_Slot ; Found a CFFA3000!
ORA #$10 ; SIR = 16+slot#
STA SIR_Tbl
STA CardIsOK ; Remember that we found the card
LDA #SIR_Len
LDX SIR_Addr
LDY SIR_Addr+1
JSR AllocSIR ; This one's mine!
BCS NoDevice
LDX #$A3
LDA #kCmd3K_SetEnvironment
JSR CFFA3K_API ; Get CFFA3000 set up for us
BCS NoDevice
LDA #$00
STA shUnitNumber
LDA #kCmd3K_Status
JSR CFFA3K_API ; How many units can we expect at maximum?
BCS NoDevice
LDA shUnitNumber
STA MaxUnits
UnitInit
LDA CardIsOK ; Did we previously find a card?
BEQ NoDevice ; If not... then bail
LDA CFFAUnit ; Which unit did we get called with?
STA shUnitNumber
LDA #kCmd3K_Status ; Ask for the status of this unit
JSR CFFA3K_API
LDA #$00
STA shBlockNumber
STA shBlockNumber+1
STA shBlockNumber+2
STA shBlockNumber+3
LDA #kCmd3K_Read ; Do a dummy read of block zero
JSR CFFA3K_API ; to clear out a device switched error
LDA #kCmd3K_Status
JSR CFFA3K_API
BCS NoDevice
SaveCapacity
LDX SOS_Unit ; Get the stats on this unit
LDY DCB_Idx,X
LDA shBlockNumber
STA DIB0_Blks,Y
LDA shBlockNumber+1
STA DIB0_Blks+1,Y
LDA shBlockNumber+2
CMP #$01 ; Do we have 65536 (or more) blocks?
BNE UIDone
LDA #$FF ; Then we really only have 65535 blocks.
STA DIB0_Blks,Y
STA DIB0_Blks+1,Y
UIDone CLC
RTS
;
; D_READ call processing
;
DRead
LDA CardIsOK ; Did we previously find a card?
BNE DReadGo
JMP NoDevice ; If not... then bail
DReadGo
JSR CkCnt ; Checks for validity, aborts if not
JSR CkUnit ; Checks for unit below unit max
LDA #$00 ; Zero # bytes read
STA Count ; Local count of bytes read
STA Count+1
TAY
STA (QtyRead),Y ; Userland count of bytes read
INY
STA (QtyRead),Y ; Msb of userland bytes read
LDA Num_Blks ; Check for Num_Blks greater than zero
ORA Num_Blks+1
BEQ ReadExit
JSR FixUp ; Correct for addressing anomalies
JSR Read_Block ; Transfer a block to/from the disk
LDY #$00
LDA Count ; Local count of bytes read
STA (QtyRead),y ; Update # of bytes actually read
INY
LDA Count+1
STA (QtyRead),y
BCS IO_Error ; An error occurred
ReadExit RTS ; Exit read routines
IO_Error LDA #XIOERROR ; I/O error
JSR SysErr ; Return to SOS with error in A
;
; D_WRITE call processing
;
DWrite
LDA CardIsOK ; Did we previously find a card?
BNE DWriteGo
JMP NoDevice ; If not... then bail
DWriteGo
JSR CkCnt ; Checks for validity
JSR CkUnit ; Checks for unit below unit max
CWrite LDA Num_Blks ; Check for Num_Blks greater than zero
ORA Num_Blks+1
BEQ WriteExit ; Quantity to write is zero - so done
JSR FixUp
JSR Write_Block
BCS IO_Error
WriteExit RTS
;
; D_STATUS call processing
; $00 = Driver Status
; $FE = Return preferrred bitmap location ($FFFF)
;
DStatus
LDA CardIsOK ; Did we previously find a card?
BNE DStatusGo
JMP NoDevice ; If not... then bail
DStatusGo
LDA CFFAUnit ; Get the unit number we're talking about
STA shUnitNumber
LDA CtlStat ; Which status code to run?
BNE DS0
LDA #kCmd3K_Status ; Status code 0 - return the status byte
JSR CFFA3K_API
BCS DS1
LDY #$00
LDA shStatusByte
STA (CSList),Y
JSR SaveCapacity
CLC
RTS
DS1 CMP #$2F ; Did we get a fancy new $2f error?
BNE DS2
LDA #XDNFERR ; Then change it to XDNFERR instead.
DS2 JSR SysErr ; Return to SOS with error in A
DS0 CMP #$FE
BNE DSWhat
LDY #$00 ; Return preferred bit map locations.
LDA #$FF ; We return FFFF, don't care
STA (CSList),Y
INY
STA (CSList),Y
CLC
RTS
DSWhat LDA #XCTLCODE ; Control/status code no good
JSR SysErr ; Return to SOS with error in A
;
; D_CONTROL call processing
; $00 = Reset device
; $FE = Perform media formatting
;
DControl
LDA CardIsOK ; Did we previously find a card?
BNE DContGo
JMP NoDevice ; If not... then bail
DContGo LDA CtlStat ; Control command
BEQ CReset
CMP #$FE ; Format?
BEQ DCFormat
JMP DCWhat ; Control code no good!
CReset JSR UnitInit ; Reset this unit
BCS DCNoReset
DCDone RTS
DCNoReset LDA #XNORESET ; Things went bad after reset
JSR SysErr ; Return to SOS with error in A
DCWhat LDA #XCTLCODE ; Control/status code no good
JSR SysErr ; Return to SOS with error in A
DCFormat
;
; Write Block0, Block1 to disk
;
LDX SOS_Unit ; Get the stats on this unit
LDY DCB_Idx,X
LDA DIB0_Blks,Y
STA VolBlks ; Fill VolBlks with capacity
LDA DIB0_Blks+1,Y
STA VolBlks+1
LDA #$00
STA VolBlks+2
STA shBlockNumber
STA shBlockNumber+1
STA shBlockNumber+2
STA shBlockNumber+3
JSR ZeroFillC800
LDA CFFAUnit ; Get the unit number we're talking about
STA shUnitNumber
LDA #kCmd3K_Write
JSR CFFA3K_API
BCS Error
INC shBlockNumber
LDA #kCmd3K_Write
JSR CFFA3K_API
BCS Error
JSR FormatFill
JSR Catalog ; Write Directory information to the disk
RTS
Error SEC
JSR SysErr ; Return to SOS with error in A
;------------------------------------
;
; Utility routines
;
;------------------------------------
;
; Read_Block - Read requested blocks from device into memory
;
Read_Block
LDA SosBuf ; Copy out buffer pointers
STA DataBuf
LDA SosBuf+1
STA DataBuf+1
LDA SosBuf+ExtPG
STA DataBuf+ExtPG
LDA CFFAUnit
STA shUnitNumber ; Now we have the CFFA3000 unit
LDA SosBlk
STA shBlockNumber
LDA SosBlk+1
STA shBlockNumber+1
LDA #$00
STA shBlockNumber+2
STA shBlockNumber+3
Read3k LDA #kCmd3K_Read
JSR CFFA3K_API
BCC @1 ; Branch past error
STA LastError
CMP #XDISKSW
BNE @0
JSR ZeroUnit
JSR UnitInit ; Re-initialize this unit
JMP Dispatch ; Go around again!
@0 LDA LastError
JSR SysErr ; Return to SOS with error in A
@1 LDA #$00
STA C800Ptr
LDA #$C8
STA C800Ptr+1 ; Establish a pointer to C800
LDY #$00
@2 LDA (C800Ptr),Y
STA (DataBuf),Y
INY
BNE @2
JSR IncrAdr
@3 LDA (C800Ptr),Y
STA (DataBuf),Y
INY
BNE @3
JSR IncrAdr
DEC Num_Blks ; Did we get what was asked for?
BNE RdBlk2
DEC Num_Blks+1
BPL RdBlk2
CLC
RTS
RdBlk2 INC shBlockNumber ; 16-bit increment of block number
BNE Read3k
INC shBlockNumber+1
JMP Read3k
;
; Write_Block - write memory out to requested blocks
;
Write_Block
LDA SosBuf ; Copy out buffer pointers
STA DataBuf
LDA SosBuf+1
STA DataBuf+1
LDA SosBuf+ExtPG
STA DataBuf+ExtPG
LDA SOS_Unit
STA shUnitNumber
CLC
INC shUnitNumber ; Now we have the CFFA3000 unit
LDA SosBlk
STA shBlockNumber
LDA SosBlk+1
STA shBlockNumber+1
LDA #$00
STA shBlockNumber+2
STA shBlockNumber+3
Write3k LDA #$00
TAY
STA C800Ptr
LDA #$C8
STA C800Ptr+1 ; Establish a pointer to C800
@2 LDA (DataBuf),Y
STA (C800Ptr),Y
INY
BNE @2
JSR IncrAdr
@3 LDA (DataBuf),Y
STA (C800Ptr),Y
INY
BNE @3
LDA #kCmd3K_Write
JSR CFFA3K_API
BCC @1 ; Branch past error
STA LastError
CMP #XDISKSW
BNE @0
JSR ZeroUnit
JSR UnitInit ; Re-initialize this unit
JMP Dispatch ; Go around again!
@0 LDA LastError
JSR SysErr ; Return to SOS with error in A
@1 JSR IncrAdr
DEC Num_Blks ; Did we put what was asked for?
BNE WrBlk2 ; Not done yet... go around again
DEC Num_Blks+1 ; (16 bit decrement)
BPL WrBlk2 ; Not done yet... go around again
CLC
RTS ; We're done
WrBlk2 INC shBlockNumber ; 16-bit increment of block number
BNE Write3k
INC shBlockNumber+1
JMP Write3k
;
; ZeroUnit - clear out the capacity bytes of this unit
;
ZeroUnit LDX SOS_Unit
LDY DCB_Idx,X
LDA #$00
STA DIB0_Blks,Y
STA DIB0_Blks+1,Y
RTS
;
; Check ReqCnt to ensure it's a multiple of 512.
;
CkCnt LDA ReqCnt ; Look at the lsb of bytes requested
BNE @1 ; No good! lsb should be 00
STA Num_Blks+1 ; Zero out the high byte of blocks
LDA ReqCnt+1 ; Look at the msb
LSR A ; Put bottom bit into carry, 0 into top
STA Num_Blks ; Convert bytes to number of blks to xfer
BCC CvtBlk ; Carry is set from LSR to mark error.
@1 LDA #XBYTECNT
JSR SysErr ; Return to SOS with error in A
;
; Test for valid block number; abort on error
;
CvtBlk LDX SOS_Unit
LDY DCB_Idx,X
SEC
LDA DIB0_Blks+1,Y ; Blocks on unit msb
SBC SosBlk+1 ; User requested block number msb
BVS BlkErr ; Not enough blocks on device for request
BEQ @1 ; Equal msb; check lsb.
RTS ; Greater msb; we're ok.
@1 LDA DIB0_Blks,Y ; Blocks on unit lsb
SBC SosBlk ; User requested block number lsb
BVS BlkErr ; Not enough blocks on device for request
RTS ; Equal or greater msb; we're ok.
BlkErr LDA #XBLKNUM
JSR SysErr ; Return to SOS with error in A
IncrAdr INC C800Ptr+1 ; Increment buffer MSB from CFFA3000
INC Count+1 ; Increment byte count MSB
BumpAdr INC DataBuf+1 ; Increment DataBuf MSB in userland
;
; Fix up the buffer pointer to correct for addressing
; anomalies. We just need to do the initial checking
; for two cases:
; 00xx bank N -> 80xx bank N-1
; 20xx bank 8F if N was 0
; FDxx bank N -> 7Dxx bank N+1
; If pointer is adjusted, return with carry set
;
FixUp LDA DataBuf+1 ; Look at msb
BEQ @1 ; That's one!
CMP #$FD ; Is it the other one?
BCS @2 ; Yep. fix it!
RTS ; Pointer unchanged, return carry clear.
@1 LDA #$80 ; 00xx -> 80xx
STA DataBuf+1
DEC DataBuf+ExtPG ; Bank N -> band N-1
LDA DataBuf+ExtPG ; See if it was bank 0
CMP #$7F ; (80) before the DEC.
BNE @3 ; Nope! all fixed.
LDA #$20 ; If it was, change both
STA DataBuf+1 ; Msb of address and
LDA #$8F
STA DataBuf+ExtPG ; Bank number for bank 8F
RTS ; Return carry set
@2 AND #$7F ; Strip off high bit
STA DataBuf+1 ; FDxx ->7Dxx
INC DataBuf+ExtPG ; Bank N -> bank N+1
@3 RTS ; Return carry set
CkUnit LDA SOS_Unit ; Checks for unit below unit max
CMP MaxUnits
BMI UnitOk
NoUnit LDA #$11 ; Report no unit to SOS
JSR SysErr
UnitOk CLC
RTS
;
; Prepare BitMap and Link blocks for writing to disk
; Part of formatting support
;
FormatFill
LDA #$05 ; Block 5 on Disk
STA shBlockNumber
STA Storage ; Length of DirTbl
JSR ZeroFillC800
LLink LDX Storage
LDA DirTbl,X ; Move Directory Link values into Buffer
STA $C802 ; Store next Directory block #
DEX
LDA DirTbl,X ; Fetch another # from DirTbl
STA $C800 ; Store previous Directory block #
DEX
STX Storage
LDA #kCmd3K_Write
JSR CFFA3K_API ; Write Directory Link values to disk
LDec DEC shBlockNumber ; Decrement MLI block number
LDA shBlockNumber ; See if MLIBlk = 2
CMP #$02
BNE LLink ; Process another Link block
;
; Calculate BitMap Size and cndo
; Part of formatting support
;
BlkCount ; Fill full pages first, then remainder
LDA #$06 ; First block to deal with: $06
STA shBlockNumber
CLC
LDA VolBlks+1
STA FullPages
LDA VolBlks+2
BEQ @1
SEC
@1 ROR FullPages ; VolBlks is now divided by 512
LSR FullPages ; ... by 1024
LSR FullPages ; ... by 2048
LSR FullPages ; ... by 4096
BEQ LastBlock ; No full blocks? Skip to remainder part.
JSR FFFillC800 ; Set up to fill pages with $FFs
LDA #kCmd3K_Write
JSR CFFA3K_API
LDA #$00
STA BlkCnt
STA $C800 ; Mark first blocks as used
STA $C801
LDA #$03
STA $C802
@2
LDA #kCmd3K_Write
JSR CFFA3K_API ; Write Buffer BitMap to block on the disk
LDA #$FF ; Mark first blocks as unused again
STA $C800
STA $C801
STA $C802
INC shBlockNumber
INC BlkCnt
LDA BlkCnt
CMP FullPages
BNE @2
LastBlock
JSR BlkRemainder
LDA #kCmd3K_Write
JSR CFFA3K_API
RTS
BlkRemainder
JSR ZeroFillC800
LDA VolBlks+1 ; Where # of blocks are stored
LDX VolBlks
LDY #$00
STX Storage+1 ; Divide the # of blocks by 8 for bitmap
LSR A ; calculation
ROR Storage+1
LSR A
ROR Storage+1
LSR A
ROR Storage+1
STA Storage+2
BitMapCode
LDA FullPages ; Only tick off 7 blocks if
BNE BitMapNotFirst ; this is the only page in the BAM
LDA #$01 ; Clear first 7 blocks (i.e. %00000001)
STA (C800Ptr),Y
JMP BitMapGo
BitMapNotFirst
LDA #$FF
STA (C800Ptr),Y
BitMapGo
LDY Storage+1 ; Original low block count value
BNE Jump11 ; If it is 0 then make FF
DEY ; Make FF
DEC Storage+2 ; Make 256 blocks less one
STY Storage+1 ; Make FF new low block value
Jump11 LDX Storage+2 ; High Block Value
BNE Jump15 ; If it isn't equal to 0 then branch
LDY Storage+1
JMP Jump19
Jump15 LDA #$C9 ; Set the address of the upper part of
STA C800Ptr+1 ; Block in bitmap being created
LDA #$FF
LDY Storage+1 ; Using the low byte count
Jump20 DEY
STA (C800Ptr),Y ; Store them
BEQ Jump17
JMP Jump20
Jump17 DEY ; Fill in first part of block
LDA #$C8
STA C800Ptr+1
Jump19
LDA #$FF
DEY
STA (C800Ptr),Y
CPY #$01 ; Except the first byte.
BEQ Jump18
JMP Jump19
Jump18 RTS
BlkCnt .BYTE $00
;
; Catalog - Build a Directory Track
; Part of formatting support
;
Catalog CLC
LDA #$06
ADC FullPages
STA shBlockNumber
LDA #kCmd3K_Write
JSR CFFA3K_API ; Write Buffer (BitMap) to block #6
JSR ZeroFillC800
LDY #$2A ; Move Block2 information to $C800
CLoop LDA Block2,Y
STA (C800Ptr),Y
DEY
BPL CLoop
LDA #$02 ; Write block #2 to the disk
STA shBlockNumber
LDA #kCmd3K_Write
JSR CFFA3K_API
RTS
;
; FillC800: clear buffer at $C800
;
FFFillC800
LDA #$FF
PHA
JMP FillC800Go
ZeroFillC800
LDA #$00
PHA
FillC800Go
LDA #$C8
STA C800Ptr+1
LDA #$00
STA C800Ptr
TAY
LDX #$01 ; Loop twice... 512 bytes
PLA
FillLoop
STA (C800Ptr),Y
INY
BNE FillLoop
INC C800Ptr+1
DEX
BPL FillLoop
LDA #$C8
STA C800Ptr+1
LDA #$00
STA C800Ptr
RTS
;
; Formatter Variable Storage Area
;
VolBlks .BYTE $00, $00, $00 ; Number of blocks available
DirTbl .BYTE $02, $04, $03 ; Linked list for directory blocks
.BYTE $05, $04, $00
BitTbl .BYTE $7f ; '01111111' ; BitMap mask for bad blocks
.BYTE $bf ; '10111111'
.BYTE $df ; '11011111'
.BYTE $ef ; '11101111'
.BYTE $f7 ; '11110111'
.BYTE $fb ; '11111011'
.BYTE $fd ; '11111101'
.BYTE $fe ; '11111110'
Storage .BYTE $00, $00, $00 ; General purpose counter/storage byte
Pointer .BYTE $00, $00 ; Storage for track count (8 blocks/track)
Track .BYTE $00, $00 ; Track number being FORMATted
Sector .BYTE $00, $00 ; Current sector number (max=16)
SlotF .BYTE $00, $00 ; Slot/Drive of device to FORMAT
TRKcur .BYTE $00, $00 ; Current track position
TRKdes .BYTE $00, $00 ; Destination track position
TRKbeg .BYTE $00 ; Starting track number
TRKend .BYTE $35 ; Ending track number
FullPages
.BYTE $00 ; Number of BAM pages to fill
DevIndex .BYTE $00 ; Space for index into DEVICES table
Util .BYTE $00
Block2 .BYTE $00, $00, $03, $00 ; Image of block 2 - for $42 bytes
VolLen .BYTE $F5 ; $F0 + length of Volume Name
Volnam .BYTE "BLANK " ; Volume Name
Reserved .BYTE $00, $00, $00, $00, $00, $00
UpLowCase
.BYTE $00, $00
Datime .BYTE $00, $00, $00, $00
Version .BYTE $01
.BYTE $00, $C3, $27, $0D
.BYTE $00, $00, $06, $00
.ENDPROC
.END

View File

@ -0,0 +1 @@
# Apple /// driver for the Compact Flash for Apple 3000 Interface Card

View File

@ -0,0 +1 @@
# Apple /// driver for ADTPro Virtual Serial Drive

746
drivers/vsdrive/vsdrive.txt Normal file
View File

@ -0,0 +1,746 @@
; VSDrive
; 0.01A - Initial release
; 0.02B - Fill in block sizes, implement reset control action
; 1.26 - More bounds checking for block writes, remove underscrores from
; names, clean up module name, synchronize version number with ADTPro release
; 1.28 - Use newer time-transporting protocol, add second drive as .VSDRIVE2
; 1.31 - Add null interrupt handler for ACIA
.TITLE "Apple /// Virtual Serial Drive Driver"
.PROC VSDRIVE
DriverVersion .EQU 1310 ; Version number
DriverMfgr .EQU 4453 ; Driver Manufacturer - DS
;
; SOS Equates
;
ExtPG .EQU 1401 ; Driver extended bank address offset
AllocSIR .EQU 1913 ; Allocate system internal resource
SysErr .EQU 1928 ; Report error to system
EReg .EQU 0FFDF ; Environment register
ReqCode .EQU 0C0 ; Request code
SOS_Unit .EQU 0C1 ; Unit number
SosBuf .EQU 0C2 ; SOS buffer pointer (2 bytes)
ReqCnt .EQU 0C4 ; Requested byte count
CtlStat .EQU 0C2 ; Control/status code
CSList .EQU 0C3 ; Control/status list pointer
SosBlk .EQU 0C6 ; Starting block number
QtyRead .EQU 0C8 ; Pointer to bytes read returned by D_READ
;
; Our temps in zero page
;
Count .EQU 0CE ; 2 bytes
Timer .EQU 0D0 ; 2 bytes
NumBlks .EQU 0D2 ; 2 bytes lb,hb
DataBuf .EQU 0D4 ; 2 bytes
EnvCmd .EQU 0D6 ; 1 byte envelope command
Checksum .EQU 0D7 ; 1 byte checksum calc
;
; Communications hardware constants
;
ACIADR .EQU 0c0f0 ; ACIA Data register
ACIASR .EQU 0c0f1 ; ACIA Status register
ACIACMD .EQU 0c0f2 ; ACIA Command mode register
ACIACTL .EQU 0c0f3 ; ACIA Control register
;
; SOS Error Codes
;
XDNFERR .EQU 010 ; Device not found
XBADDNUM .EQU 011 ; Invalid device number
XREQCODE .EQU 020 ; Invalid request code
XCTLCODE .EQU 021 ; Invalid control/status code
XCTLPARAM .EQU 022 ; Invalid control/status parameter
XNORESRC .EQU 025 ; Resources not available
XBADOP .EQU 026 ; Invalid operation
XIOERROR .EQU 027 ; I/O error
XNODRIVE .EQU 028 ; Drive not connected
XBYTECNT .EQU 02C ; Byte count not a multiple of 512
XBLKNUM .EQU 02D ; Block number to large
XDISKSW .EQU 02E ; Disk switched
XNORESET .EQU 033 ; Device reset failed
;
; Switch Macro
;
.MACRO switch
.IF "%1" <> "" ; If parameter 1 is present
LDA %1 ; Load A with switch index
.ENDC
CMP #%2+1 ; Do bounds check
BCS $010
ASL A
TAY
LDA %3+1,Y ; Get switch index from table
PHA
LDA %3,Y
PHA
.IF "%4" <> "*" ; If parameter 4 omitted,
RTS ; then go to code
.ENDC
$010 .ENDM
;
; GoSlow macro - slow down via E-Register
;
.MACRO GoSlow
PHA
LDA EReg
ORA #080 ; Set 1MHz switch
STA EReg
PLA
.ENDM
;
; GoFast macro - speed up via E-Register
;
.MACRO GoFast
PHA
LDA EReg
AND #07f
STA EReg ; Whatever it was - set it back
PLA
.ENDM
;
; Comment Field of driver
;
.WORD 0FFFF ; Signal that we have a comment
.WORD 66. ; Length of comment field... entered manually.
; The Pascal Assembler can't count forward references.
; SCP only shows 78 characters' worth of information.
.ASCII "Apple /// Virtual Serial Drive Driver by"
.ASCII " David Schmidt 2012 - 2014"
; 1 2 3 4
; 1234567890123456789012345678901234567890
;------------------------------------
;
; Device identification Block (DIB) - VSDRIVE
;
;------------------------------------
DIB_0 .WORD DIB_1 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE 008 ; Name length byte
.ASCII ".VSDRIVE "; Device name
.BYTE 080 ; Active, no page alignment
.BYTE 000 ; Slot number
.BYTE 000 ; Unit number
.BYTE 0E1 ; Type
.BYTE 010 ; Subtype
.BYTE 000 ; Filler
DIB0_Blks .WORD 0000 ; # Blocks in device
.WORD DriverMfgr ; Manufacturer
.WORD DriverVersion ; Driver version
.WORD 0000 ; DCB length followed by DCB
;------------------------------------
;
; Device identification Block (DIB) - VSDRIVE2
;
;------------------------------------
DIB_1 .WORD 0000 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE 009 ; Name length byte
.ASCII ".VSDRIVE2 "; Device name
.BYTE 080 ; Active, no page alignment
.BYTE 000 ; Slot number
.BYTE 001 ; Unit number
.BYTE 0E1 ; Type
.BYTE 010 ; Subtype
.BYTE 000 ; Filler
DIB1_Blks .WORD 0000 ; # Blocks in device
.WORD DriverMfgr ; Manufacturer
.WORD DriverVersion ; Driver version
.WORD 0000 ; DCB length followed by DCB
;------------------------------------
;
; Local storage locations
;
;------------------------------------
LastOP .BLOCK 002, 0FF ; Last operation for D_REPEAT calls
SIRAddr .WORD SIRTbl
SIRTbl .BYTE 001 ; ACIA resource
.BYTE 000
.WORD 0FEC4 ; Do-nothing interrupt vector
.BYTE 000 ; Bank register
SIRLen .EQU *-SIRTbl
RdBlkProc .WORD 0000
WrBlkProc .WORD 0000
StackPtr .BYTE 000
DCB_Idx .BYTE 000 ; DCB 0's blocks
.BYTE DIB1_Blks-DIB0_Blks ; DCB 1's blocks
;------------------------------------
;
; Driver request handlers
;
;------------------------------------
Entry JSR Dispatch ; Call the dispatcher
LDX SOS_Unit ; Get drive number for this unit
LDA ReqCode ; Keep request around for D_REPEAT
STA LastOP,X ; Keep track of last operation
LDA #000
RTS
;
; The Dispatcher. Note that if we came in on a D_INIT call,
; we do a branch to Dispatch normally.
; Dispatch is called as a subroutine!
;
DoTable .WORD DRead-1 ; 0 Read request
.WORD DWrite-1 ; 1 Write request
.WORD DStatus-1 ; 2 Status request
.WORD DControl-1 ; 3 Control request
.WORD BadReq-1 ; 4 Unused
.WORD BadReq-1 ; 5 Unused
.WORD BadOp-1 ; 6 Open - valid for character devices
.WORD BadOp-1 ; 7 Close - valid for character devices
.WORD DInit-1 ; 8 Init request
.WORD DRepeat-1 ; 9 Repeat last read or write request
Dispatch SWITCH ReqCode,9,DoTable ; Serve the request
;
; Dispatch errors
;
BadReq LDA #XREQCODE ; Bad request code!
JSR SysErr ; Return to SOS with error in A
BadOp LDA #XBADOP ; Invalid operation!
JSR SysErr ; Return to SOS with error in A
;
; D_REPEAT - repeat the last D_READ or D_WRITE call
;
DRepeat LDX SOS_Unit
LDA LastOP,X ; Recall the last thing we did
CMP #002 ; Looking for operation < 2
BCS BadOp ; Can only repeat a read or write
STA ReqCode
JMP Dispatch
NoDevice LDA #XDNFERR ; Device not found
JSR SysErr ; Return to SOS with error in A
;
; D_INIT call processing - called at initialization
;
DInit
LDA SOS_Unit ; Check if we're initting the zeroeth unit
BNE DInitDone ; If not - skip the serial setup
LDA #SIRLen
LDX SIRAddr
LDY SIRAddr+1
JSR AllocSIR ; Allocate the ACIA
BCS NoACIA
PHP
SEI ; Disable system interrupts
GoSlow ; Set up the communications environment
LDA #00b ; No parity, no interrupts
STA ACIACMD ; Store via ACIA command register
LDA #010 ; $16=300, $1e=9600, $1f=19200, $10=115k
STA ACIACTL ; Store via ACIA control register
LDA ACIASR ; Clear any prior ACIA interrupts
GoFast
PLP ; Re-enable system interrupt state
DInitDone
CLC
RTS
NoACIA
LDA #XNORESRC
JSR SysErr ; Return to SOS with error in A
;
; D_READ call processing
;
DRead
TSX
STX StackPtr ; Hang on to the stack pointer for hasty exits
JSR CkCnt ; Checks for validity, aborts if not
JSR CkUnit ; Checks for unit below unit max
LDA #000 ; Zero # bytes read
STA Count ; Local count of bytes read
STA Count+1
TAY
STA (QtyRead),Y ; Userland count of bytes read
INY
STA (QtyRead),Y ; Msb of userland bytes read
LDA NumBlks ; Check for NumBlks greater than zero
ORA NumBlks+1
BEQ ReadExit
JSR FixUp ; Correct for addressing anomalies
JSR ReadBlock ; Transfer a block to/from the disk
LDY #000
LDA Count ; Local count of bytes read
STA (QtyRead),y ; Update # of bytes actually read
INY
LDA Count+1
STA (QtyRead),y
BCS IOError ; An error occurred
ReadExit RTS ; Exit read routines
IOError LDA #XIOERROR ; I/O error
JSR SysErr ; Return to SOS with error in A
;
; D_WRITE call processing
;
DWrite
TSX
STX StackPtr ; Hang on to the stack pointer for hasty exits
JSR CkCnt ; Checks for validity
JSR CkUnit ; Checks for unit below unit max
LDA NumBlks ; Check for NumBlks greater than zero
ORA NumBlks+1
BEQ WriteExit ; Quantity to write is zero - so done
JSR FixUp
JSR WriteBlock
BCS IOError
WriteExit RTS
;
; D_STATUS call processing
; $00 = Driver Status
; $01 = Report drive size
; $FE = Return preferred bitmap location ($FFFF)
;
DStatus
LDA CtlStat ; Which status code to run?
BNE DS0
LDY #000 ; 000 - Driver status, return zero
STA (CSList),Y
CLC
RTS
DS0 CMP #0FE
BNE DSWhat
LDY #000 ; Return preferred bit map locations.
LDA #0FF ; We return FFFF, don't care
STA (CSList),Y
INY
STA (CSList),Y
CLC
RTS
DSWhat LDA #XCTLCODE ; Control/status code no good
JSR SysErr ; Return to SOS with error in A
;
; D_CONTROL call processing
; $00 = Reset device
; $FE = Perform media formatting
;
DControl
LDA CtlStat ; Control command
BEQ CReset
JMP DCWhat ; Control code no good!
CReset GoSlow
BIT ACIADR ; Clear ACIA Data register
GoFast
DCDone RTS
DCNoReset LDA #XNORESET ; Things went bad after reset
JSR SysErr ; Return to SOS with error in A
DCWhat LDA #XCTLCODE ; Control/status code no good
JSR SysErr ; Return to SOS with error in A
;------------------------------------
;
; Utility routines
;
;------------------------------------
;
; ReadBlock - Read requested blocks from device into memory
;
ReadBlock
LDA SosBuf ; Copy out buffer pointers
STA DataBuf
LDA SosBuf+1
STA DataBuf+1
LDA SosBuf+ExtPG
STA DataBuf+ExtPG
LDA #003 ; Read request with current time information
CLC
ADC SOS_Unit ; Add two to the request if this is the second unit
ADC SOS_Unit
STA EnvCmd
ReadSend
JSR SendEnvelope
JSR DTReceiveEnvelope
BCS ReadFail
LDY #000
STY Checksum
RdBlk2 JSR GETC
BCS ReadFail
STA (DataBuf),Y
EOR Checksum
STA Checksum
INY
BNE RdBlk2
JSR IncrAdr
RdBlk3 JSR GETC
BCS ReadFail
STA (DataBuf),Y
EOR Checksum
STA Checksum
INY
BNE RdBlk3
JSR IncrAdr
JSR GETC ; Pull Checksum
BCS ReadFail
CMP Checksum
BNE ReadFail
DEC NumBlks ; Did we get what was asked for?
BNE RdMore
DEC NumBlks+1
BPL RdMore
LDA SosBlk
CMP #002 ; Is this block #2 (lsb=2)?
BNE RdDone
LDA SosBlk+1
BNE RdDone ; Is this block #2 (msb=0)?
LDY #029 ; Yes - store off the disk size
LDA (SosBuf),Y
PHA
INY
LDA (SosBuf),Y
PHA
LDX SOS_Unit ; Get the stats on this unit
LDY DCB_Idx,X
PLA
STA DIB0_Blks+1,Y
PLA
STA DIB0_Blks,Y
RdDone CLC
RTS
RdMore INC SosBlk
BNE ReadSend
INC SosBlk+1
JMP ReadSend
;
; ReadFail - Complain with an OS I/O error
;
ReadFail
LDX StackPtr
TXS ; Pop! Goes the stack pointer
LDA #XIOERROR ; Nearby branch point
JSR SysErr ; Return to SOS with error in A
;
; WriteBlock - write memory out to requested blocks
;
WriteBlock
LDA SosBuf ; Copy out buffer pointers
STA DataBuf
LDA SosBuf+1
STA DataBuf+1
LDA SosBuf+ExtPG
STA DataBuf+ExtPG
LDA #002 ; Write request
CLC
ADC SOS_Unit ; Add two to the request if this is the second unit
ADC SOS_Unit
STA EnvCmd
WriteSend
JSR SendEnvelope
LDX #000
STX Checksum
WrBkLoop
LDY #000
WRLOOP:
LDA (DataBuf),Y
JSR PUTCC
INY
BNE WRLOOP
JSR IncrAdr
INX
CPX #002
BNE WRBKLOOP
LDA Checksum ; Checksum
JSR PUTC
JSR ReceiveEnvelope
BCS WriteFail
DEC NumBlks ; Did we put what was asked for?
BNE WrMore ; Not done yet... go around again
DEC NumBlks+1 ; (16 bit decrement)
BPL WrMore ; Not done yet... go around again
CLC
RTS ; We're done
WrMore INC SosBlk
BNE WriteSend
INC SosBlk+1
JMP WriteSend
;
; WriteFail - Complain with an OS I/O error
;
WriteFail
LDX StackPtr
TXS ; Pop! Goes the stack pointer
LDA #XIOERROR
JSR SysErr ; Return to SOS with error in A
;
; SendEnvelope - send the command envelope
;
SendEnvelope ; Send a command envelope
LDA #000
STA Checksum
LDA #0c5 ; "E"
JSR PUTCC ; Envelope
LDA EnvCmd
JSR PUTCC ; Send command
LDA SosBlk
JSR PUTCC ; Send LSB of requested block
LDA SosBlk+1
JSR PUTCC ; Send MSB of requested block
LDA Checksum
JSR PUTC ; Send envelope Checksum
RTS ; Carry is clear, return
;
; DTReceiveEnvelope - receive the command envelope back from host, with time data
;
; Note that we can't set the date and time through a SOS call, since device drivers
; are not allowed to make SOS calls.
;
DTReceiveEnvelope
LDA #000
STA Checksum
JSR GETC
BCS DTEnvelopeFail
CMP #0c5 ; "E" - S/B Command envelope
BNE DTEnvelopeFail
EOR Checksum
STA Checksum
JSR GETC
BCS DTEnvelopeFail
CMP EnvCmd ; Command requested
BNE DTEnvelopeFail
EOR Checksum
STA Checksum
JSR GETC ; Read LSB of requested block
BCS DTEnvelopeFail
CMP SosBlk
BNE DTEnvelopeFail
EOR Checksum
STA Checksum
JSR GETC ; Read MSB of requested block
BCS DTEnvelopeFail
CMP SosBlk+1
BNE DTEnvelopeFail
EOR Checksum
STA Checksum
LDX #004 ; Pull the four date/time bytes
DTRETime JSR GETC ; Ignore except for checksum calculations
BCS DTEnvelopeFail
EOR Checksum
STA Checksum
DEX
BNE DTRETime
JSR GETC ; Checksum
BCS DTEnvelopeFail
CMP Checksum
BNE DTEnvelopeFail
LDA #000
CLC
RTS
DTEnvelopeFail
SEC
RTS
;
; ReceiveEnvelope - receive the command envelope back from host
;
ReceiveEnvelope
JSR GETC
BCS EnvelopeFail
CMP #0c5 ; "E" - S/B Command envelope
BNE EnvelopeFail
JSR GETC
BCS EnvelopeFail
CMP EnvCmd ; Command requested
BNE EnvelopeFail
JSR GETC ; Read LSB of requested block
BCS EnvelopeFail
CMP SosBlk
BNE EnvelopeFail
JSR GETC ; Read MSB of requested block
BCS EnvelopeFail
CMP SosBlk+1
BNE EnvelopeFail
JSR GETC ; Checksum
BCS EnvelopeFail
CMP Checksum
BNE EnvelopeFail
LDA #000
CLC
RTS
EnvelopeFail
SEC
RTS
;
; CalcChecksum - Calculate the checksum of the block at DataBuf
;
CalcChecksum ; Calculate the checksum
LDA SosBuf ; Copy out buffer pointers again
STA DataBuf
LDA SosBuf+1
STA DataBuf+1
LDA #000 ; Clean everyone out
TAX
TAY
CCLoop:
EOR (DataBuf),Y
STA Checksum ; Save that tally in CHECKSUM
INY
BNE CCLoop
JSR IncrAdr ; Y just wrapped; bump buffer MSB
INX ; Need two loops
CPX #002 ; Second loop?
BNE CCLoop
RTS
;
; GETC - Get a byte from the ACIA
;
; Carry set on timeout, clear on data (returned in Accumulator)
;
GETC
LDA #000
STA Timer
STA Timer+1
GoSlow
GETC1 LDA ACIASR ; Check status bits via ACIA status register
AND #068
CMP #008
BEQ GETIT ; Data is ready, go get it
INC TIMER
BNE GETC1 ; Input register empty, no timeout; loop
INC TIMER+1
BNE GETC1 ; Input register empty, no timeout; loop
GoFast
SEC ; Timeout; return to caller
RTS
GETIT
LDA ACIADR ; Get character via ACIA data register
GoFast
CLC
RTS
;
; PUTCC - Put a byte to the ACIA, adding to the checksum
;
PUTCC PHA
EOR Checksum
STA Checksum
JMP PUTC0
;
; PUTC - Put a byte to the ACIA
;
PUTC
PHA ; Push 'character to send' onto the stack
PUTC0 LDA #000
STA Timer
STA Timer+1
GoSlow
PUTC1
LDA ACIASR ; Check status bits
AND #070
CMP #010
BNE PUTC1 ; Output register is full, no timeout; so loop
PLA ; Pull 'character to send' back off the stack
STA ACIADR ; Put character
GoFast
RTS
;
; Check ReqCnt to ensure it's a multiple of 512.
;
CkCnt LDA ReqCnt ; Look at the lsb of bytes requested
BNE $1 ; No good! lsb should be 00
STA NumBlks+1 ; Zero out the high byte of blocks
LDA ReqCnt+1 ; Look at the msb
LSR A ; Put bottom bit into carry, 0 into top
STA NumBlks ; Convert bytes to number of blks to xfer
BCC CvtBlk ; Carry is set from LSR to mark error.
$1 LDA #XBYTECNT
JSR SysErr ; Return to SOS with error in A
;
; Test for valid block number; abort on error
;
CvtBlk LDX SOS_Unit
LDY DCB_Idx,X
SEC
LDA DIB0_Blks+1,Y ; Blocks on unit msb
SBC SosBlk+1 ; User requested block number msb
BVS BlkErr ; Not enough blocks on device for request
BEQ $1 ; Equal msb; check lsb.
RTS ; Greater msb; we're ok.
$1 LDA DIB0_Blks,Y ; Blocks on unit lsb
SBC SosBlk ; User requested block number lsb
BVS BlkErr ; Not enough blocks on device for request
RTS ; Equal or greater msb; we're ok.
BlkErr LDA #XBLKNUM
JSR SysErr ; Return to SOS with erorr in A
IncrAdr
INC Count+1 ; Increment byte count MSB
INC DataBuf+1 ; Increment DataBuf MSB in userland
;
; Fix up the buffer pointer to correct for addressing
; anomalies. We just need to do the initial checking
; for two cases:
; 00xx bank N -> 80xx bank N-1
; 20xx bank 8F if N was 0
; FDxx bank N -> 7Dxx bank N+1
; If pointer is adjusted, return with carry set
;
FixUp LDA DataBuf+1 ; Look at msb
BEQ $1 ; That's one!
CMP #0FD ; Is it the other one?
BCS $2 ; Yep. fix it!
RTS ; Pointer unchanged, return carry clear.
$1 LDA #080 ; 00xx -> 80xx
STA DataBuf+1
DEC DataBuf+ExtPG ; Bank N -> band N-1
LDA DataBuf+ExtPG ; See if it was bank 0
CMP #07F ; (80) before the DEC.
BNE $3 ; Nope! all fixed.
LDA #020 ; If it was, change both
STA DataBuf+1 ; Msb of address and
LDA #08F
STA DataBuf+ExtPG ; Bank number for bank 8F
RTS ; Return carry set
$2 AND #07F ; Strip off high bit
STA DataBuf+1 ; FDxx ->7Dxx
INC DataBuf+ExtPG ; Bank N -> bank N+1
$3 RTS ; Return carry set
CkUnit
CLC
RTS
.END