bryan@ihnet.UUCP (b. k. delaney) (09/13/85)
; Ramdisk Controller for 256k atari 800xl
; by Claus Buchholz, Dec. ,1984
;
;
;
; This assembly language program provides a RAM-DISK for the
; 256k Atari 800XL described in the September issue of BYTE
;
;
; OPTIONS: Drive # and density
;
DRIVE = 2
DENSITY= SINGLE
;
;
; Equates
;
SINGLE = $80 SECTOR LENGTHS
DOUBLE = $00
DDEVIC = $300 SIO DEVICE CONTROL BLOCK
DUNIT = $301
DCOMND = $302
DSTATS = $303
DBUFLO = $304
DBYTLO = $308
DAUX1 = $30A
DOSINI = $0C Acess to RESET initialization
CHKSUM = $31 Temporary checksum
BUFRLO = $32 Temporary pointer to user's buffer
ZTEMP = $34 Temporary miscellaneous use
STACKP = $318 Stack pointer save
PORTB = $D301 PIA port B - memory control register
;
; Load-time code - Copy OS into RAM
;
*= $3000
GO
LDA PORTB Enable OS ROM
ORA #1
STA PORT
LDA #$CO Zero page pointer
STA $CC
LDA #0
STA $CB
SEI Disable Interrupts
STA $D40E
TAY
LOOP
LDA ($CB),Y Copy OS
DEC PORTB Enable RAM
STA ($CB),Y
INC PORTB Enable ROM
INY
BNE LOOP
LDX $CC
CPX #$CB Skip pages $CC to $D7
BNE NXPG
LDX #$D7
NXPG
INX
STX $CC
BNE LOOP
DEC PORTB Enable RAM
LDA #$40 Enable Interrupts
STA $D40E
CLI
RTS Continue Load
*= $2E2
.WORD GO Execute preliminary load-time code
;
; Ramdisk Controller Code
;
*= $CC00 Permanet Code - in place of alt. char. set
HOOK
CLC Hook into all SIO calls
LDA DDEVIC
ADC DUNIT
CMP #$31+DRIVE Right drive Number ?
BEQ HOOKED
OLDVEC = *+1
JMP * If not, goto SIO
HOOKED
TSX If so, intercept
STX STACKP Save Stack Pointer
LDA DCOMND Examine Command
CMP #'! Format ?
BNE NOFMT
JMP FORMAT
NOFMT
CMP #'P Put Sector ?
BNE NOPUT
JMP PUTSEC
NOPUT
CMP #'R Read Sector ?
BNE NOGET
JMP GETSEC
NOGET
CMP #'S Read Status ?
BNE NOSTT
JMP STATUS
NOSTT
CMP #'W Write Sector ?
BNE NAKRET
JMP PUTSEC
;
; Returms - Restore Stack Pointer, report error status and return
;
NAKRET
LDX STACKP
TXS
LDY #139 NAK error for improper command
STY DSTATS
RTS
ERRRET
LDX STACKP
TXS
LDY #144 Bad sector error
STY DSTATS
RTS
SUCRET
LDX STACKP
TXS
LDY #1 No error
STY DSTATS
RTS
;
; Subroutine - set pointer to user buffer
;
SETBUF
LDS DBUFLO Move from DCB to zero page
STA BUFRLO
LDA DBUFLO+1
STA BUFRLO+1
RTS
;
; Subroutine - Prepare to access sector of ramdisk
;
SETSEC
LDA #DENSITY
STA SECLEN Set sector length
LDA DAUX1+1 Check sector #
BNE NOTZ
LDA DAUX1
BEQ OUTRG Sector 0 invalid
CMP #4
BCS INRNG
LDA #$80 Sectors 1-3 are always 128 bytes long
STA SECLEN
BNE INRNG
OUTRG
JMP NAKRET Sector # out of range
NOTZ
CMP #2 Check for sector # > $2D0
BCC INRNG
BNE OUTRG
LDA #$D0
CMP DAUX1
BCC OUTRG
INRNG
LDA DAUX1 Sector # valid
LDY DAUX1+1
LDX #$FF
DIV121
INX Divide # 121 - Result is bank #, remainder is page #
SEC
SBC #121
BCS NOBOR
DEY
NOBOR
CPY #$FF
BNE DIVI121
AND #$7F Remainder+7
;
; Subroutine - Prepare to switch banks:
;
SETBNK
STA ZP Save page #
LDA PORTB
STA PBN Normal bank
AND #$8F
STA PB Bank 0
TXA
ASL A
ASL A
ASL A
ASL A
ORA PB
STA PB Bank X
LDA $FFFA NMI vector
STA ZTEMP
LDA $FFFB
STA ZTEMP+1
LDY #0
LDA #$40 RTI opcode
SEI Disable IRQ
STA (ZTEMP),Y Place RTI in NMI routine - disables NMI
LDA PB
STA PORTB Switch bank In
TYA
STA 0 Set up Zero-page pointer
LDA ZP
STA 1
LDA PBN
STA PORTB Switch normal bank back in
RTS Leave 0 in Y, bank # in X
;
; Format Routine
;
FORMAT
LDX #5 CLEAR BANKS 0 TO 5
CLOOP1
LDA #2 CLEAR PAGE 2 AND UP
JSR SETBNK PREPARE FOR SWITCH
LDA PB
STA PORTB SWITCH BANK IN
TYA
CLOOP2
STA (0),Y ZERO ENTIRE PAGE
INY
BNE CLOOP2
INC 1 NEXT PAGE
BPL CLOOP2
LDA PBN
STA PORTB SWITCH BANK OUT
LDA NMI
STA (ZTEMP),Y ENABLE INTERRUPTS
CLI
DEX NEXT BANK
BPL CLOOP1
JSR SETBUF
LDA #$FF RETURN A SECTOR WITH 2 $FF AND THE REST 0
LDY #0
FLOOP
CPY #2
BNE NOTFF
LDA #0
NOTFF
STA (BUFRLO),Y
INY
CPY SECLEN
BNE FLOOP
JMP SUCRET Done
;
; Write sector routine
;
PUTSEC
JSR SETBUF
LDA #0
STA CHKSUM ZERO CHECKSUM
JSR SETSEC POINT TO RAMDISK SECTOR
PLOOP
LDA (BUFRLO),Y GET BYTE FROM USERS BUFFER
LDX PB
STX PORTB
STA (0),Y PUT BYTE INTO RAMDISK
LDX PBN
STX PORTB NORMAL BANK
CLC
ADC CHKSUM ADD BYTE TO CHECKSUM
STA CHKSUM
INY NEXT BYTE
CPY SECLEN PROPER SECTOR LENGTH
BNE PLOOP
LDX #0 BANK 0 HOLDS CHECKSUM TABLE
LDA DAUX1+1
CLC
ADC #2 SECTOR # INDEXES CHECKSUM TABLE
JSR SETBNK
LDY DAUX1
LDA CHKSUM
LDX PB
STX PORTB SWITCH BANK
STA (0),Y STORE CHECKSUM
LDX PBN
STX PORTB NORMAL BANK
LDY #0
LDA MNI
STA (ZTEMP),Y ENABLE INTERRUPTS
CLI
JMP SUCRET DONE
;
; READ SECTOR ROUTINE
;
GETSEC
JSR SETBUF
LDA #0
STA CHKSUM ZERO CHECKSUM
JSR SETSEC
GLOOP
LDX PB
STX PORTB SWITCH BANK
LDA (0),Y GET BYTE FROM RAMDISK
LDX PBN
STX PORTB NORMAL BANK
STA (BUFRLO),Y PUT BYTE INTO USERS BUFFER
CLC
ADC CHKSUM ADD TO CHECKSUM
STA CHKSUM
INY NEXT BYTE
CPY SECLEN PROPER SECTOR LENGTH
BNE GLOOP
LDX #0 BANK 0 FOR CHECKSUM TABLE
LDA DAUX1+1
CLC
ADC #2
JSR SETBNK
LDY DAUX1
LDX PB
STX PORTB SWITCH BANK
LDA (0),Y GET ORIGNIAL CHECKSUM
LDX PBN
STX PORTB NORMAL BANK
TAX
LDY #0
LDA NMI
STA (ZTEMP),Y ENABLE INTERRUPTS
CLI
CPX CHKSUM COMPARE CHECKSUMS
BEQ GCSOK
JMP ERRRET IF DIFFERENT, BAD SECTOR
GCSOK
JMP SUCRET IF SAME, DONE
;
; READ STATUS ROUTINE
;
STATUS
JSR SETBUF
LDY #4 RETURN 4 BYTES
LDA #0 ALL ZEROS
SLOOP
DEY
BEQ STEND
STA (BUFRLO),Y
JMP SLOOP
STEND
FLAG = DENSITY/4
LDA #$20-FLAG
STA (BUFRLO),Y FIRST BYTE TELLS DENSITY OF DRIVE
JMP SUCRET DONE
;
; VARIABLE STORAGBE AREA
;
ZP *= *+1 HOLDS PAGE # IN RAMDISK TO BE ACCESSED
PB *= *+1 VALUE OF MEMORY CONTROL REGISTER FOR SELECTED BANK
PBN *= *+1 VALUE OF MEMORY CONTROL REGISTER FOR NORMAL BANK
NMI *= *+1 FIRST OPCODE IN NMI ROUTINE - USED TO RESTORE NMI
SECLEN *= *+1 LENGTH OF CURRENT SECTOR
;
; RESET INITIALIZATION ROUTINE
;
*= $100 HIDDEN (HOPEFULLY !)
NEWINI
DEC PORTB ENABLE RAM OS
OLDINI = *+1
JSR * CALL ORIGINAL DOSINI ROUTINE
MODINI
LDA #NEWINI$&FF set hook for next reset
STA DOSINI
LDA #NEWINI/$100
STA DOSINI+1
RTS
;
; LOAD-TIME CODE - INSTALL RAMDISK
;
*= $3000
DO
LDA $E45A SAVE ORIGNIAL SIO VECTOR
STA OLDVEC
LDA $E45B
STA OLDVEC+1
LDA #HOOK&$FF INSTALL NEW SIO VECTOR
STA $E45A
LDA #HOOK/$100
STA $E45B
LDA $FFFA SAVE FIRST OPCODE IN NMI ROUTINE
STA $CB
LDA $FFFB
STA $CC
LDY #0
LDA ($CB),Y
STA NMI
LDA DOSINI SAVE ORIGINAL DOSINI VECTOR
STA OLDINI
LDA DOSINI+1
STA DOSINI+1
JSR MODINI INSTALL NEW ONE
JSR $7E0 RE-INITIALIZE FMS TO SHOW RAMDISK PRESENT
RTS DONE
*= $2E2
.WORD DO EXECUTE FINAL LOAD-TIME CODE