     [Note from author: I am posting this software to the next due to the
      the request of such a driver. The following code is posted as 
      freeware. I expect no compensation other than due credit for the 
      creation of this source code. If you adapt and improve on this driver,
      I'd like to here from you.  Enjoy -- mstier@sun ]
 
     Okay, this is what I created several years ago when I purchased a 
 Saturn 128k for my ][plus. Its major limitation is that it supports on a
 single card in a single slot, slot 0. There are several more and they are:
 
 
 1) Currently its a BRUN-able program that tests for the presense of 64K or
    128K of Saturn compatible ram in slot 0.
 
 2) Upon finding sufficent ram, it will take over the complete card except 
    the 16k, ProDOS uses in block 0.
 
 3) It also consumes the 16 byte of the ProDOS global page used for Apple's
    Copyright notice. A few other programs also use this little know ram area.
    An overwrite of these bytes after the ramcard is initialized, will have
    unpredictable result.
 
 4) The core of the ram disk driver resides from $D000 thru $D0FF in bank 2
    of block 0. This is the section of unused memory right below the ProDOS
    quit code. As in note 3, overwriting of this code will have unpredictable
    result.
 
 5) The operation of the driver is quite simple. 
 
    A) The users application makes a call to the ProDOS MLI to access the
       ramdisk.
 
    B) The ProDOS MLI does bank switching an passes the request to the ProDOS
       kernel.
 
    C) The ProDOS kernel decides it needs a certain block from the ramdisk,
       so it sets up some bytes in zero page, and calls the driver thru the
       driver vectors in the ProDOS global page.
 
    D) The ProDOS global page driver vectors pass control to a short routine
       installed in place of the Apple Copyright notice in the ProDOS global
       page.
 
    E) The short routine installed in place of the Apple Copyright notice,
       does bank switching to make the main core of the driver availiable
       for execution, and then jumps to it.
 
    F) The main core of the routine analyzes the parameters placed in zero 
       page by the ProDOS kernel, and sets up a few parameters of its own.
 
    G) With everything in order, the ramdisk driver swaps a read/write routine
       with a section of zero page memory.
 
    H) The swapped read/write routine does the requested action and returns 
       to the ramdisk driver.
 
    I) The ramdisk driver then re-swaps the read/write routine with the
       section of stored zero page memory.
 
    J) The ramdisk driver cleans up shop and returns to the short routine
       installed in place of the Apple Copyright notice, which bank switchs
       the ProDOS kernel back in returns to the ProDOS kernel, which does 
       its cleanup, which in turn, returns to the ProDOS MLI, which does 
       its cleanup, and then it finally gets back to the calling Application.
 
 6) Notice 5 may seem like a lot of steps, but it is small and quite fast.
 
     Here is the code you requested. Have fun with it. If you improve on it,
 let me have a copy back. There are others who would gain from continued work
 on this program. I've helped you, now you have a chance to help others.
 
 
 ;
 ;ProDOS.disk.driver
 ;for
 ;64k/128k.Saturn.ramcard
 ;
 ;written.by.Matthew.Lee.Stier
 ;Copyright.(c).1986
 ;
 ;
 JMP       EQU  $4C
 LDA       EQU  $B1            ;INDIRECT,Y
 STA       EQU  $91            ;INDIRECT,Y
 FORMAT.C  EQU  $4
 WR.BLK.C  EQU  $81
 GET.TIME  EQU  $82
 NO.EC     EQU  $00
 IO.EC     EQU  $27
 WP.EC     EQU  $28
 ZPAGE     EQU  $0
 CMD       EQU  $42
 BUFFER    EQU  $44
 BLK.NUM   EQU  $46
 MLI       EQU  $BF00
 DATETIME  EQU  $BF06
 DEVADR31  EQU  $BF16
 DEVCNT    EQU  $BF31
 DEVLST    EQU  $BF32
 COPYRITE  EQU  $BF40
 DATE      EQU  $BF90
 LC        EQU  $C080
 ROMBNK2WE EQU  LC+$1
 LCBNK2WE  EQU  LC+$3
 LCBNK1WE  EQU  LC+$B
 BLK0      EQU  LC+$4
 ROMBNK1WE EQU  LC+$9
 BLK7      EQU  LC+$F
 ;
           ORG  $2000
           LST  ON,NOA,NOV,GEN
 ;
           LDY  #7
 NXTBLK16  LDX  LC.INDEX,Y     ;TEST FOR RAMCARD
           LDA  LC,X           ; SIZE
           BIT  LCBNK2WE       ;ENABLE BANK 2
           BIT  LCBNK2WE
           TYA
           STA  $D000
           DEY
           BPL  NXTBLK16
           BIT  BLK7
           LDY  $D000          ;GET RAMCARD SIZE
           BIT  BLK0           ;RESTORE BLOCK 0
           BIT  ROMBNK1WE      ; BANK 1
           BIT  ROMBNK1WE
           CPY  #8             ;ILLEGAL BANK SIZE?
           BCS  TESTRTN        ; YES...
           TYA
           ASL 
           TAY
           LDX  BLKSIZE+1,Y    ;GET RAMCARD SIZE
           LDA  BLKSIZE,Y      ; IN PRODOS BLOCKS
           BNE  INSTALL        ;IF NOT 0 THEN INSTALL
           SEC                 ;ELSE FLAG AN ERROR
 TESTRTN   RTS                 ; AND QUIT
 ;
 LC.INDEX  DB   $4,$5,$6,$7,$C,$D,$E,$F
 BLKSIZE   DW   0,0,0,96,0,0,0,224
 ;
 INSTALL   STX  MAX.BLK+1      ;SET I/O ROUTINE
           STA  MAX.BLK        ; MAX BLOCK
           STX  B2.D+1+$2A     ;SET DIRECTORY 
           STA  B2.D+1+$29     ; MAX BLOCK
           CPY  #3*2           ;IF 64K RAMCARD
           BNE  VBM128
           LDY  B1.96          ;USE 96 BLOCK VBM 
 SET.VBM   LDA  B1.96,Y
           STA  B1.D,Y
           DEY
           BPL  SET.VBM
 VBM128    JSR  MLI            ;GET CURRENT TIME
           DB   GET.TIME
           DW   0000
           LDY  #3
 MOV.DATE  LDA  DATE,Y         ;MOVE IT TO DIRECTORY
           STA  B2.D+1+$1C,Y   ; HEADER
           DEY
           BPL  MOV.DATE
 DO.MOVE1  BIT  ROMBNK2WE
           BIT  ROMBNK2WE
           LDY  #0
 MOVE1     LDA  CHCK.CMD,Y     ;MOVE I/O ROUTINE
           STA  CHCK.CMD+OS,Y  ; TO BANK 2 @ $D000
           INY
           BNE  MOVE1
           LDY  #15
 MOVE2     LDA  LC.ENTER,Y     ;MOVE LC.ENTER
           STA  COPYRITE,Y     ; TO PRODOS GLOBAL
           DEY                 ; PAGE
           BPL  MOVE2
           LDA  #<COPYRITE     ;INSTALL RAMCARD
           STA  DEVADR31+1     ; VECTOR IN DRIVE TABLE
           LDA  #>COPYRITE
           STA  DEVADR31
           INC  DEVCNT         ;INSTALL RAMCARD IN
           LDY  DEVCNT         ; LIST OF ATTACHED DRIVES
           LDA  #$3F           ;SLOT 3, DRIVE 2, TYPE-RAM
           STA  DEVLST,Y
           LDA  #2             ;FIRST DIRECTORY BLOCK
           LDX  #<B2.D
           LDY  #>B2.D
           JSR  WR.BLOCK
           LDA  #3             ;LAST DIRCETORY BLOCK
           LDX  #<B3.D
           LDY  #>B3.D
           JSR  WR.BLOCK
           LDA  #1             ;VOLUME BITMAP
           LDX  #<B1.D
           LDY  #>B1.D
           JSR  WR.BLOCK
           CLC
           RTS                 ;AND END
 ;
 WR.BLOCK  STA  WR.BLK.P+4     ;SETUP BLK.NUM
           LDA  #00
           STA  WR.BLK.P+5
           STX  LENGTH+2       ;SETUP DATA POINTER
           STY  LENGTH+1
           STX  MOVDATA+2
           STY  MOVDATA+1
           LDY  #0 
           LDA  #0
 ZBUFR     STA  BW.BUFR,Y      ;ZERO I/O BUFFER
           STA  BW.BUFR+256,Y
           INY
           BNE  ZBUFR
 LENGTH    LDX  BW.BUFR        ;GET LENGTH OF INFO
 MOVDATA   LDA  BW.BUFR,X
           STA  BW.BUFR-1,X    ;MOVE DATA TO I/O BUFFER
           DEX
           BNE  MOVDATA
           JSR  MLI            ;AND WRITE IT TO /RAM
           DB   WR.BLK.C
           DW   WR.BLK.P
           RTS
 ;
 WR.BLK.P  DB   3              ;NUMBER OF PARAMETERS
           DB   $30            ;SLOT/DRIVE NUMBER
           DW   BW.BUFR        ;DATA BUFFER
           DW   0000           ;BLOCK NUMBER
 ;
 B2.D      DB   B2.END-*-1
           DW   0              ;PREVIOUS.DIRECTORY.BLOCK
           DW   3              ;NEXT.DIRECTORY.BLOCK
 VTYPE     DB   $F3            ;VTYPE/VN.LEN
 VNAME     ASC  'RAM'          ;VNAME
           DS   VNAME+15-*,0
           DS   8,0            ;RESERVED
           DW   0              ;CREATION.DATE
           DW   0              ;CREATION.TIME
           DB   1              ;CREATION.VERSION
           DB   0              ;MINIMUM.VERSION
           DB   %01000011      ;ACCESS BITS
           DB   39             ;SIZE DIR ENTRIES
           DB   13             ;ENTRIES PER BLOCK
           DW   0              ;ACTIVE FILES
           DW   1              ;VBM
           DW   0              ;# OF BLOCKS
 B2.END    EQU  *
 ;
 B3.D      DB   B3.END-*-1
           DW   2              ;PREVIOUS.DIRECTORY.BLOCK
           DW   0              ;NEXT.DIRECTORY.BLOCK
 B3.END    EQU  *
 ;
 B1.D      DB   B1.END-*-1
           DB   %00001111      ;BLOCKS 0,1,2,3 ARE USED
           DS   27,$FF         ;ALL THE REST ARE FREE
 B1.END    EQU  *
 ;
 B1.96     DB   B1.96END-*-1
           DB   $0F            ;BLOCKS 0,1,2,3 ARE USED
           DS   11,$FF         ;ALL THE REST ARE FREE
 B1.96END  EQU  *
 ;
 LC.ENTER  CLD                 ;ALL ROUTINE BEGIN WITH
           BIT  LCBNK2WE       ;ENABLE BANK 2
           JSR  CHCK.CMD+OS    ; AND GOTO IT
 LC.EXIT   PHP                 ;SAVE THE STATUS REGISTER
           BIT  LCBNK1WE       ;ENABLE BANK 1
           BIT  LCBNK1WE
           PLP                 ;RESTORE THE STATUS REG.
           RTS                 ;AND RETURN
 ;
           DS   >0-*,0
 OS        EQU  $D000-*        ;OFFSET TO LANGUAGE CARD
 ;
 CHCK.CMD  BIT  LCBNK2WE       ;ENSURE BANK 2 IS SELECTED
           LDA  CMD            ;GET THE COMMAND
           BEQ  STATUS         ; IS IT 'STATUS'...
           CMP  #FORMAT.C      ; IS IT 'FORMAT'
           BCC  RD.WR          ; NO, READ OR WRITE...
           BNE  IO.EXIT        , NO, I/O ERROR
           LDA  #WP.EC         ;ITS FORMAT
           SEC                 ; MARK DRIVE AS
           RTS                 ; WRITE PROTECTED
 ;
 IO.EXIT   LDA  #IO.EC         ;ITS AN I/O ERROR
           SEC
           RTS
 ;
 STATUS    LDY  MAX.BLK+OS+1   ;GET VOLUME SIZE
           LDX  MAX.BLK+OS
 STATUS2   LDA  #NO.EC         ;AND RETURN
           CLC
           RTS
 ;
 MAX.BLK   DW   0              ;NUMBER OF BLOCKS
 ;
 RD.WR     LDA  BLK.NUM+1      ;CHECK VALID BLOCK NUM
           CMP  MAX.BLK+OS+1
           BNE  RD.WR2
           LDA  BLK.NUM
           CMP  MAX.BLK+OS     ;IF GREATER THAN
 RD.WR2    BCS  IO.EXIT        ; MARK AS I/O ERROR...
           PHA
           LSR  A              ;GET RAMCARD
           LSR  A              ; BLOCK NUMBER
           LSR  A
           LSR  A
           LSR  A
           TAY
           LDA  B16TBL+OS,Y    ;CONVERT TO I/O ADDRESS
           STA  RC.BLK+OS+1
           PLA
           AND  #%00011111     ;GET BLOCK NUMBER
           CMP  #8
           BCS  NO.FIX         ;SET CORRECT BANK
           ADC  #8
 NO.FIX    PHA
           LDA  #LCBNK2WE
           BCC  NO.FIX2
           LDA  #LCBNK1WE
 NO.FIX2   STA  RC.BNK+OS+1
           PLA
           ASL  A
           ADC  #$C0           ;AND RAMCARD ADDRESS
           TAX
           LDA  CMD
           AND  #%00000010     ;SETUP RAMCARD POINTERS
           TAY
           LDA  #00
           STA  S1+OS,Y
           STA  S2+OS,Y
           TXA
           STA  S1+OS+1,Y
           INX
           TXA
           STA  S2+OS+1,Y
           TYA
           ASL
           ASL
           ASL
           TAY
 RC.BLK    LDA  #00
           STA  MOVLOOP+OS+1,Y
 RC.BNK    LDA  #00
           STA  MOVLOOP+OS+4,Y
           LDA  CMD
           EOR  #%00000011     ;SETUP MAIN MEM. POINTERS
           AND  #%00000010
           TAY
           LDX  BUFFER+1
           LDA  BUFFER
           STA  S1+OS,Y
           STA  S2+OS,Y
           TXA
           STA  S1+OS+1,Y
           INX
           TXA
           STA  S2+OS+1,Y
           TYA
           ASL
           ASL
           ASL
           TAY
           LDA  #LCBNK1WE
           STA  MOVLOOP+OS+1,Y
           LDA  #BLK0
           STA  MOVLOOP+OS+4,Y
           PHP
           SEI                 ;DISABLE INTERUPTS
           JSR  SWAP+OS        ;PUT R/W IN ZPAGE
           JSR  ZPAGE          ; DO READ/WRITE
           JSR  SWAP+OS        ;PUT ZPAGE BACK
           PLP                 ;RESTORE INTERUPT FLAG
           JMP  STATUS2+OS     ;AND EXIT
 ;
 B16TBL    DB   $85,$86,$87,$8C,$8D,$8E,$8F
 ;
 SWAP      LDY  #RWR.END-RWR   ;GET LENGTH OF RWR
 SWAP2     LDX  RWR+OS,Y       ;AND SWAP ZPAGE
           LDA  ZPAGE,Y        ; WITH RWR
           STA  RWR+OS,Y
           STX  ZPAGE,Y
           DEY
           BPL  SWAP2
           RTS
 ;
 RWR       LDY  #00            ;INIT INDEX POINTER
 MOVLOOP   BIT  LC             ;ENABLE SOURCE
           BIT  LC
           DB   LDA,S1-RWR     ;GET THE DATA
           STA  T1-RWR
           DB   LDA,S2-RWR
           STA  T2-RWR
           BIT  LC             ;ENABLE DESTINATION
           BIT  LC
           LDA  T1-RWR         ;SAVE THE DATA
           DB   STA,D1-RWR
           LDA  T2-RWR
           DB   STA,D2-RWR
           INY                 ;DONE?
           BNE  MOVLOOP        ;NO...
           BIT  BLK0           ;RESET TO RAMCARD
           BIT  LCBNK2WE       ; BLOCK 0, BANK 2
           RTS                 ; AND RETURN
 ;
 S1        DW   0              ;SOURCE 1
 D1        DW   0              ;DESTINATION 1
 S2        DW   0              ;SOURCE 2
 D2        DW   0              ;DESTINATION 2
 T1        DB   0              ;DATA 1
 T2        DB   0              ;DATA 2
 RWR.END   EQU  *
 ;
           DS   >0-*,0
 BW.BUFR   EQU  *              ;I/O BUFFER
 *
