[net.micro.atari] RAMDISK256.ASM for 800XL

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