374 lines
13 KiB
ArmAsm
374 lines
13 KiB
ArmAsm
* * * * * * * * * * * * * * * * *
|
|
* The xdos machine language *
|
|
* interface (MLI) *
|
|
* system call processor *
|
|
* * * * * * * * * * * * * * * * *
|
|
|
|
ORG orig1
|
|
MX %11
|
|
EntryMLI CLD ;Cannot deal with decimal mode!!!
|
|
PLA ;Get processor status
|
|
STA Spare1 ;Save it on the global page temporarily
|
|
STY SaveY ;Preserve the y and x registers
|
|
STX SaveX
|
|
PLA ;Find out the address of the caller
|
|
STA parm
|
|
CLC ; & preserve the address of the call spec
|
|
ADC #$04
|
|
STA CmdAdr
|
|
PLA
|
|
STA parm+1
|
|
ADC #$00
|
|
STA CmdAdr+1 ;CmdAdr is in the globals
|
|
|
|
* Check cmd code
|
|
|
|
LDA Spare1
|
|
PHA
|
|
PLP ;Pull processor to re-enable interrupts
|
|
CLD ;No decimal! (** #46 **)
|
|
LDY #$00
|
|
STY SErr ;Clear any previous errors...
|
|
|
|
* Hashing algorithm used here adds high nibble
|
|
* (div by 16 first) to the whole cmd code
|
|
* and then masks it to 5 lower bits
|
|
* This compresses range of codes without any overlapping
|
|
|
|
INY ;Find out if we've got a valid command
|
|
LDA (parm),Y ;Get command #
|
|
LSR ;Hash it to a range of $00-$1F
|
|
LSR
|
|
LSR
|
|
LSR
|
|
CLC
|
|
ADC (parm),Y
|
|
AND #$1F
|
|
TAX
|
|
LDA (parm),Y ;Now see if result is a valid command number
|
|
CMP scNums,X ;Should match if it is
|
|
BNE scnErr ;Branch if not
|
|
|
|
* Get IOB address
|
|
|
|
INY ;Index to call spec parm list addr
|
|
LDA (parm),Y ;Make parm point to parameter count byte
|
|
PHA ; in parameter block
|
|
INY
|
|
LDA (parm),Y
|
|
STA parm+1
|
|
PLA
|
|
STA parm
|
|
|
|
* Check parm count
|
|
|
|
LDY #c_pCnt ;Now make sure parameter list has the
|
|
LDA pCntTbl,X ; proper number of parameters
|
|
BEQ GoClock ;Clock has 0 parameters
|
|
CMP (parm),Y
|
|
BNE scpErr ;Report error if wrong count
|
|
|
|
* Check class of function
|
|
|
|
LDA scNums,X ;Get call number again
|
|
CMP #$65
|
|
BEQ Special
|
|
ASL ;Carry set if bfm or dev mgr
|
|
BPL GoDevMgr
|
|
BCS GoBFMgr
|
|
LSR ;Shift back down for interupt mgr
|
|
|
|
* Isolate type
|
|
* 0-alloc, 1-dealloc, 2-special
|
|
|
|
AND #$03 ;Valid calls are 0 & 1
|
|
JSR IntMgr
|
|
BRA ExitMLI ;Command processed, all done
|
|
Special JMP jSpare ;QUIT
|
|
|
|
**************************************************
|
|
* Command $82 - Get the date and time
|
|
|
|
GoClock JSR DateTime ;go read clock
|
|
BRA ExitMLI ;No errors posible!
|
|
|
|
**************************************************
|
|
* READBLOCK and WRITEBLOCK commands ($80 and $81)
|
|
|
|
GoDevMgr LSR ;Save command #
|
|
ADC #$01 ;Valid commands are 1 & 2
|
|
STA dhpCmd ;(READ & WRITE)
|
|
JSR DevMgr ;Execute read or write request
|
|
BRA ExitMLI
|
|
|
|
*-------------------------------------------------
|
|
* Commands $C0 thru $D3
|
|
|
|
GoBFMgr LSR
|
|
AND #$1F ;Valid commands in range of $00-$13
|
|
TAX
|
|
JSR BFMgr ;Go do it...
|
|
|
|
ExitMLI STZ BUBit ;First clear bubit
|
|
LDY SErr ;Y holds error code thru most of exit
|
|
CPY #$01 ;If >0 then set carry
|
|
TYA ; & set z flag
|
|
PHP ;Disable interupts
|
|
SEI ; until exit complete
|
|
LSR mliActv ;Indicate MLI done.(** #46 **) (** #85 **)
|
|
PLX ;Save status register in X
|
|
LDA CmdAdr+1 ; until return address is placed
|
|
PHA ; on the stack returning is done via 'RTI'
|
|
LDA CmdAdr ; so that the status register is
|
|
PHA ; restored at the same time
|
|
PHX ;Place status back on the stack
|
|
TYA ;Return error, if any
|
|
LDX SaveX ;Restore x & y registers
|
|
LDY SaveY
|
|
ExitRPM PHA ; (exit point for rpm **en3**)
|
|
LDA BnkByt1 ;Restore language card status & return
|
|
JMP Exit
|
|
|
|
*-------------------------------------------------
|
|
|
|
gNoDev LDA #drvrNoDevice ;Report no device connected
|
|
JSR SysErr
|
|
scnErr LDA #badSystemCall ;Report no such command
|
|
BNE scErr1 ;Branch always
|
|
scpErr LDA #invalidPcount ;report parameter count is invalid
|
|
scErr1 JSR GoSysErr
|
|
BCS ExitMLI ;Branch always taken
|
|
|
|
TTL 'ProDOS Device Manager'
|
|
|
|
*-------------------------------------------------
|
|
* ProDOS device manager
|
|
* Block I/O setup
|
|
|
|
DevMgr LDY #$05 ;The call spec for devices must
|
|
PHP ;(do not allow interupts)
|
|
SEI
|
|
:loop LDA (parm),Y ; be passed to drivers in zero page
|
|
STA |dhpCmd,Y ;dhpCmd,unitNum,bufPtr,blockNum
|
|
DEY
|
|
BNE :loop
|
|
LDX bufPtr+1
|
|
STX userBuf+1
|
|
INX
|
|
INX ;Add 2 for 512 byte range
|
|
LDA bufPtr ;Is buffer page alligned?
|
|
BEQ :1 ;Branch if it is
|
|
INX ;Else account for 3-page straddle...
|
|
:1 JSR ValDBufZ ;Make sure user is not conflicting
|
|
BCS DevMgrErr ; with protected RAM
|
|
JSR DMgr ;Call internal entry for device dispatch
|
|
BCS DevMgrErr ;Branch if error occured
|
|
PLP
|
|
CLC ;Make sure carry is clear (no error)
|
|
RTS
|
|
|
|
DevMgrErr PLP
|
|
GoSysErr JSR SysErr
|
|
|
|
*-------------------------------------------------
|
|
* NOTE: interrupts must always be off when entering here
|
|
* Do block I/O rtn
|
|
|
|
DMgr LDA unitNum ;Get device number
|
|
AND #$F0 ;Strip misc lower nibble
|
|
STA unitNum ; & save it back
|
|
LSR ;Use as index to device table
|
|
LSR
|
|
LSR
|
|
TAX
|
|
LDA DevAdr01,X ;Fetch driver address
|
|
STA goAdr
|
|
LDA DevAdr01+1,X
|
|
STA goAdr+1
|
|
GoCmd JMP (goAdr) ;Goto driver (or error if no driver)
|
|
|
|
TTL 'ProDOS Interrupt Manager'
|
|
*-------------------------------------------------
|
|
* ProDOS interrupt manager
|
|
* Handle ALLOC_INTERRUPTS ($40) and
|
|
* DEALLOC_INTERRUPTS ($41) Calls
|
|
|
|
IntMgr STA intCmd ;Allocate intrupt or deallocate?
|
|
LSR ;(A=0, carry set=dealloc)
|
|
BCS DeAlocInt ;Branch if deallocation
|
|
LDX #$03 ;Test for a free interupt space in table
|
|
AlocInt LDA Intrup1-2,X ;Test high addr for zero
|
|
BNE :1 ;Branch if spot occupied
|
|
LDY #c_intAdr+1 ;Fetch addr of routine
|
|
LDA (parm),Y ;Must not be in zero page!!!!
|
|
BEQ BadInt ;Branch if the fool tried it
|
|
STA Intrup1-2,X ;Save high address
|
|
DEY
|
|
LDA (parm),Y
|
|
STA Intrup1-3,X ; & low address
|
|
TXA ;Now return interupt # in range of 1 to 4
|
|
LSR
|
|
DEY
|
|
STA (parm),Y ;Pass back to user
|
|
CLC ;Indicate success!
|
|
RTS
|
|
|
|
:1 INX
|
|
INX ;Bump to next lower priority spot
|
|
CPX #$0B ;Are all four allocated already?
|
|
BNE AlocInt ;Branch if not
|
|
|
|
LDA #irqTableFull ;Return news that four devices are active
|
|
BNE IntErr1
|
|
|
|
BadInt LDA #paramRangeErr ;Report invalid parameter
|
|
IntErr1 JSR SysErr
|
|
|
|
DeAlocInt LDY #c_intNum ;Zero out interupt vector
|
|
LDA (parm),Y ; but make sure it is valid #
|
|
BEQ BadInt ;Branch if it's <1
|
|
CMP #$05 ; or >4
|
|
BCS BadInt
|
|
ASL
|
|
TAX
|
|
LDA #$00 ;Now zip it
|
|
STA Intrup1-2,X
|
|
STA Intrup1-1,X
|
|
CLC
|
|
RTS
|
|
|
|
*-------------------------------------------------
|
|
* IRQ Handler - If an IRQ occurs, we eventually get HERE
|
|
|
|
IrqRecev LDA Acc ;Get Acc from 0-page where old ROM put it
|
|
STA IntAReg
|
|
STX IntXReg ;Entry point on RAM card interupt
|
|
STY IntYReg
|
|
TSX
|
|
STX IntSReg
|
|
LDA IrqFlag ;Irq flag byte = 0 if old ROMs
|
|
BNE :1 ; and 1 if new ROMs
|
|
PLA
|
|
STA IntPReg
|
|
PLA
|
|
STA IntAddr
|
|
PLA
|
|
STA IntAddr+1
|
|
:1 TXS ;Restore return addr & p-reg to stack
|
|
LDA MSLOT ;Set up to re-enable $cn00 rom
|
|
STA IrqDev+2
|
|
TSX ;Make sure stack has room for 16 bytes
|
|
BMI NoStkSave ;Branch if stack safe
|
|
LDY #16-1
|
|
StkSave PLA
|
|
STA SvStack,Y
|
|
DEY
|
|
BPL StkSave
|
|
|
|
NoStkSave LDX #$FA ;Save 6 bytes of zero page
|
|
ZPgSave LDA $00,X
|
|
STA SvZeroPg-$FA,X
|
|
INX
|
|
BNE ZPgSave
|
|
|
|
* Poll interupt routines for a claimer
|
|
|
|
LDA Intrup1+1 ;Test for valid routine
|
|
BEQ :1 ;Branch if no routine
|
|
JSR goInt1
|
|
BCC IrqDone
|
|
:1 LDA Intrup2+1 ;Test for valid routine
|
|
BEQ :2 ;Branch if no routine
|
|
JSR goInt2 ;Execute routine
|
|
BCC IrqDone
|
|
:2 LDA Intrup3+1 ;Test for valid routine
|
|
BEQ :3 ;Branch if no routine
|
|
JSR goInt3
|
|
BCC IrqDone
|
|
:3 LDA Intrup4+1 ;Test for valid routine
|
|
BEQ IrqDeath ;Branch if no routine
|
|
JSR goInt4 ;Execute routine
|
|
BCC IrqDone
|
|
|
|
*************** see rev note #35 *************************
|
|
|
|
IrqDeath INC IrqCount ;Allow 255 unclaimed interrupts
|
|
BNE IrqDone ; before going to system death...
|
|
LDA #unclaimedIntErr
|
|
JSR SysDeath
|
|
|
|
* IRQ processing complete
|
|
|
|
IrqDone LDX #$FA
|
|
:loop LDA SvZeroPg-$FA,X
|
|
STA $00,X
|
|
INX
|
|
BNE :loop
|
|
LDX IntSReg ;Test for necessity of restoring stack elements
|
|
BMI :1
|
|
LDY #$00
|
|
:loop2 LDA SvStack,Y
|
|
PHA
|
|
INY
|
|
CPY #16
|
|
BNE :loop2
|
|
|
|
:1 LDA IrqFlag ;Check for old ROMs
|
|
BNE IrqDoneX ;Branch if new ROMs
|
|
|
|
* Apple II or II+ monitor
|
|
|
|
LDY IntYReg ;Restore registers
|
|
LDX IntXReg
|
|
LDA CLRROM ;Re-enable I/O card
|
|
IrqDev LDA $C100 ;Warning, self modified
|
|
LDA IrqDev+2 ;Restore device ID
|
|
STA MSLOT
|
|
IrqDoneX JMP irqXit
|
|
|
|
IrqFlag DB $00 ;irq flag byte. 0=old ROMs; 1=new ROMs
|
|
IrqCount DB $00 ;Unclaimed interrupt counter.(note #35)
|
|
SvStack DS 16,0
|
|
SvZeroPg DS 6,0
|
|
|
|
goInt1 JMP (Intrup1)
|
|
goInt2 JMP (Intrup2)
|
|
goInt3 JMP (Intrup3)
|
|
goInt4 JMP (Intrup4)
|
|
|
|
*-------------------------------------------------
|
|
* System error handler
|
|
|
|
SysErr1 STA SErr
|
|
PLX
|
|
PLX ;Pop 1 level of return
|
|
SEC
|
|
RTS
|
|
|
|
*-------------------------------------------------
|
|
* System death handler
|
|
|
|
SysDeath1 TAX ;System death!!!
|
|
STA CLR80VID ;Force 40 columns on rev-e
|
|
LDA TXTSET ;Text mode on
|
|
LDA cortFlag ;Check if we're on a cortland
|
|
BEQ NoSupHires
|
|
STZ NEWVIDEO ;Force off SuperHires
|
|
NoSupHires LDA TXTPAGE1 ;Display page 1 on
|
|
LDY #$13
|
|
DspDeath LDA #' '
|
|
STA SLIN10+10,Y
|
|
STA SLIN12+10,Y
|
|
LDA Death,Y
|
|
STA SLIN11+10,Y
|
|
DEY
|
|
BPL DspDeath
|
|
TXA
|
|
AND #$0F
|
|
ORA #"0"
|
|
CMP #"9"+1
|
|
BCC :1 ;Branch if not >9
|
|
ADC #$06 ;Bump to alpha A-F
|
|
:1 STA SLIN11+28
|
|
Halt BRA Halt ;Hold forever
|