; 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