Initial source push
This commit is contained in:
parent
a505407392
commit
1873055fa3
|
@ -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)
|
|
@ -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"`
|
|
@ -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"
|
||||
}
|
||||
]
|
|
@ -0,0 +1 @@
|
|||
# Apple /// driver for the Focus IDE Interface Card
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
# Apple /// driver for the Compact Flash for Apple 3000 Interface Card
|
|
@ -0,0 +1 @@
|
|||
# Apple /// driver for ADTPro Virtual Serial Drive
|
|
@ -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
|
Loading…
Reference in New Issue