ProDOS8/MLI.SRC/MEMMGR.S

298 lines
11 KiB
ArmAsm

**************************************************
* Allocate I/O buf
AllocBuf LDY #c_bufPtr+1 ;Index to user specified buffer
AllocBufZ LDA (parm),Y ;This buffer must be on a page boundary
TAX ;Save in X-reg for validation
CMP #$08
BCC BadBufr ;Cannot be lower than video!
CMP #$BC ;Nor greater than $BB00
BCS BadBufr ; since it would wipe out globals...
STA dataPtr+1
DEY
LDA (parm),Y ;Low addr should be zero!
STA dataPtr
BNE BadBufr ;Branch if it isn't
INX ;Add 4 pages for 1K buffer
INX
INX
INX
:loop1 DEX ;Test for conflicts
JSR CalcMemBit ;Test for free buffer space
AND memTabl,Y ;Report memory conflict
BNE BadBufr ; if any...
CPX dataPtr+1 ;Test all four pages
BNE :loop1
INX ;Add 4 pages again for allocation
INX
INX
INX
:loop2 DEX ;Set proper bits to 1
JSR CalcMemBit
ORA memTabl,Y ; to mark it's allocation
STA memTabl,Y
CPX dataPtr+1 ;Set all four pages
BNE :loop2
LDY fcbPtr ;Now calculate buffer number
LDA fcb+fcbRefNum,Y
ASL ;buffer number=(entnum)*2
STA fcb+fcbFileBuf,Y;Save it in FCB
TAX ;Use entnum*2 as index to global buffer addr tables
LDA dataPtr+1 ;Get addr already validated as good
STA GblBuf-1,X ;Store hi addr (entnums start at 1, not zero)
CLC
RTS ;All done allocating buffers
BadBufr LDA #badBufErr ;Tell user buf is in use or not legal otherwise
SEC ;Indicate error
RTS
**************************************************
* Locate ptr to I/O buf in global page
GetBufAdr TAX ;Index into global buffer table
LDA GblBuf-2,X ;Low buffer addr
STA bufAddrL
LDA GblBuf-1,X ;and high addr
STA bufAddrH
RTS
**************************************************
* Free I/O buf
ReleaseBuf JSR GetBufAdr ;Preserve buf adr in 'bufAddr'
TAY ;Returns high buffer addr in A
BEQ RelBufX ;Branch if unallocated buffer space
STZ GblBuf-1,X ;Take address out of buffer list
STZ GblBuf-2,X ;(X was set up by GetBufAdr)
FreeBuf LDX bufAddrH ;Get hi addr of buffer again
INX ;Add 4 pages to account for 1k space
INX
INX
INX
:loop DEX ;Drop to next lower page
JSR CalcMemBit ;Get bit and posn to memTabl of this page
EOR #$FF ;Invert mask
AND memTabl,Y ;Mark addr as free space now
STA memTabl,Y
CPX bufAddrH ;All pages freed yet?
BNE :loop ;Branch if not
RelBufX CLC ;Indicate no error
RTS
**************************************************
* Calculate memory allocation bit position
* entry: (X)=hi addr of buffer, low addr assumed zero.
*
* exit: (A)=allocation bit mask, (X)=unchanged,
* (Y)=pointer to memTabl byte
CalcMemBit TXA ;Move page address to A
AND #$07 ;Which page in any 2k set?
TAY ;Use as index to determine
LDA WhichBit,Y ; bit position representation
PHA ;Save bit position mask for now
TXA ;Get page address again
LSR
LSR ;Now determine 2K set
LSR
TAY ;Return it in Y
PLA ;Restore bit mask
RTS ;Return bit position in A&Y, ptr to memtabl in X
**************************************************
* Check buffer validity
ValDBuf LDA userBuf+1 ;Get high addr of user's buffer
CMP #$02 ;Must be greater than page 2
BCC BadBufr ;Report bad buffer
LDX cBytes+1
LDA cBytes ;Get cbytes-1 value
SBC #$01 ;(carry is set)
BCS :1
DEX
:1 CLC
ADC userBuf ;Calculate end of request addr
TXA ;Do hi addr
ADC userBuf+1 ;All we care about is final addr
TAX ;Must be less than $BF (globals)
CPX #$BF
BCS BadBufr
INX ;Loop thru all affected pages
ValDBufZ DEX ;Check next lower page
JSR CalcMemBit
AND memTabl,Y ;If zero then no conflict
BNE BadBufr ;Branch if conflict...
CPX userBuf+1 ;Was that the last (lowest) page?
BNE ValDBufZ ;Branch if not
CLC ;Indicate all pages ok
RTS ;All done here
**************************************************
* GETBUF Call
GetBuf LDY #c_bufAdr ;Give user address of file buffer
LDA bufAddrL ; referenced by refnum
STA (parm),Y
INY
LDA bufAddrH
STA (parm),Y ;No errors possible if this rtn is called
CLC
RTS
**************************************************
* SETBUF Call
SetBuf LDY #c_bufAdr+1
JSR AllocBufZ ;Allocate new buffer address over old one
BCS SetBufErr ;Report any conflicts immediately
LDA bufAddrH
STA userBuf+1
LDA bufAddrL
STA userBuf
JSR FreeBuf ;Now free address space of old buffer
LDY #$00
LDX #$03
:loop LDA (userBuf),Y ;Move all four pages of
STA (dataPtr),Y ; the buffer to new location
INY
BNE :loop
INC dataPtr+1
INC userBuf+1
DEX
BPL :loop
CLC
SetBufErr RTS
**************************************************
*
* This is the routine that moves the 3 pages of dispatcher 1
* from $D100 of the alt 4k bank to its execution address ($1000).
* Since it is in the MLI and must swap the $D000-$DFFF banks,
* it must be resident at all times above $E000.
*
**************************************************
* NB. There is a vector @ $FEFD which points to this rtn
CallDisp LDA LCBANK2
LDA LCBANK2 ;Bring in the other $D000 space
LDA #>DispAdr ;Destination address of user-code
STA A2+1
LDA #<DispAdr
STA A2
LDA #$D1 ;Dispatcher is stored at $D100-$D3FF
STA A1+1
STZ A1
LDY #$00
LDX #$03 ;3 pages of code to move
MovPage DEY ;Nifty routine to move a page of code
LDA (A1),Y ;Move all 255 bytes on the page
STA (A2),Y
TYA
BNE MovPage
INC A1+1 ;Move pointers to next page
INC A2+1
DEX
BNE MovPage
LDA LCBANK1
LDA LCBANK1 ;Swap MLI's $D000 space back in
STZ mliActv
STZ SOFTEV ;Set up the reset vector
LDA #>DispAdr
STA SOFTEV+1 ; to dispatch entry
EOR #$A5 ;Set up power up byte
STA PWREDUP
JMP DispAdr
**************************************************
* Handles calls to mirror devices
* ProDOS unit #s are of the form DSSS xxxx
* where the bits of the low nibble are the
* attributes of the device.
* D=0/1 (drive 1/drive 2)
* The handler only supports 14 mirror devices
* A statusCmd ($00) call will return the #
* of blocks in (Y,X)
MirrorDevEntry LDX #$03 ;Default parm cnt
LDA dhpCmd ;Get cmd
STA spCmdNum
BNE :1
LDY #<spStatList ;Its a statusCmd
STY bufPtr
LDY #>spStatList
STY bufPtr+1
STZ blockNum
:1 CMP #$03 ;FormatCmd?
BNE :2 ;No
LDX #$01 ;parm cnt for a formatCmd
:2 STX spCmdList
LDA unitNum ;(dsss 0000)
LSR
LSR
LSR
LSR
TAX ;0000 dsss ($01-$0F; $00,$08,$0B-invalid)
LDA spUnits-1,X ;Get actual SP unit # which
STA spUnitNum ; corr to this ProDOS unit #
LDA spDrvAdrL-1,X
STA CallSPort+1 ;Get addr of SP dev driver
LDA spDrvAdrH-1,X
STA CallSPort+2 ; which handles this SP unit
LDX #$04
:CpyLoop LDA bufPtr-1,X
STA blkIOParms-1,X
DEX
BNE :CpyLoop
CallSPort JSR $0000 ;Go do it!
spCmdNum DB $00
DA spCmdList
BCS :Rtn
LDX spCmdNum ;Was a SP STATUS call executed?
BNE :Rtn ;No
LDX spDevTotBlks ;# of blocks
LDY spDevTotBlks+1
LDA genStatus
BIT #$10 ;Is dev online/disk in drive?
BNE :1 ;Yes
LDA #drvrOffLine
BRA :2
:1 AND #$44 ;Retain bits 6,2
EOR #$40 ;Is it write-protected?
BEQ :Rtn ;No
LDA #drvrWrtProt
:2 SEC
:Rtn RTS
*-------------------------------------------------
* This table was built during a P8 boot
spDrvAdrL DS $F,0 ;Actual entry points
spDrvAdrH DS $F,0 ; of a device's driver
* Command List used for all 4 commands viz
* 0-Status, 1-Read Block, 2-Write Block, 3-Format
* The caller must pass the parms using the
* usual zp locations $42-$47
spCmdList DB $03 ;parm count
spUnitNum DB $00 ;unit #
blkIOParms DA $0000 ;Data I/O buf
blokNum DB 0,0,0 ;blk # (only 2 bytes used)