;IDE_PBI.ASM 12/19/2001 ;Based on IDE38.ASM by Bob Woolley ; ;Originally, the was an overlay for the Rev2 (XL/XE) OS ROM and the hardware ;was directly wired to the $D1xx page. The code is now for a PBI variation ;that only enables the $D1xx registers when the PBI device is enabled. The ;cassette buffer is currently used to hold the partition data to use. ; ;This code performs full 512 byte sector read/write operations. No special ;code is used to put 2 logical sectors within one physical sector. The ;performance may not be the best it could be as we are reading the sector to ;a private buffer and then copying the requested amount of data to the buffer ;address specified in the DCB. Or, in the case of writing, copying the given ;data from the DCB specified buffer to the private buffer and then sending it ;from there to the drive. ; ;A DOS that supported 512 byte sectors would be nice with this code. ; ; IDE Driver Equates ; STATUS = $30 CHKSUM = $31 BUFRLO = $32 BUFRHI = $33 BFENLO = $34 BFENHI = $35 BPTR = $3D ZTMP = $3E DEVMASK = $0247 NDEVREQ = $0248 DVSTAT = $02EA DDEVIC = $0300 DUNIT = $0301 DCOMND = $0302 DSTATS = $0303 DBUFLO = $0304 DBUFHI = $0305 DTIMLO = $0306 DUNUSE = $0307 DBYTLO = $0308 DBYTHI = $0309 DAUX1 = $030A DAUX2 = $030B DRVCFG = $D600 RES1 = $D60C RES2 = $D60D RES3 = $D60E RES4 = $D60F HDTABL = $D610 ; ; MageIDE ; IDE_DATA = $D100 IDE_ERROR = $D101 IDE_WRCOMP = $D101 IDE_SCNT = $D102 IDE_SNUM = $D103 IDE_CYLL = $D104 IDE_CYLH = $D105 IDE_SDH = $D106 IDE_STATUS = $D107 IDE_CMD = $D107 IDE_RESET = $D10E IDE_HIDATA = $D110 MEM_BANK = $D120 ; ; PBI Header ; *=$D800 .BYTE 'N,'H .BYTE $10 .BYTE $80 .BYTE 0 JMP IS_IT_OURS JMP _IRQV .BYTE $91 DEVNAME .BYTE 'R .WORD R_OPEN-1 .WORD R_CLOSE-1 .WORD R_GET-1 .WORD R_PUT-1 .WORD R_STATUS-1 .WORD R_SPECIAL-1 JMP INITCODE .BYTE 0 ; ; Dummy IRQ handler ; _IRQV RTS ; RAWMODE JMP CHECK_RAWCMD ; ; SIO code ; IS_IT_OURS ;Check for SELECT key LDA $D01F AND #$02 BEQ EXITPBI ;Check device ID LDA DDEVIC ;Dn: access? CMP #$31 BNE EXITPBI ;Raw drive access? (for such things as partition table editing) ;No OS known will pass a 0 DUNIT for Dn: access LDA DUNIT BEQ RAWMODE ;Set SRAM bank for drive/partition data tables LDA #$01 STA MEM_BANK ;Scan partition table LDX #$24 ; SRCH LDA HDTABL+3,X AND #$0F CMP DUNIT BEQ IDECODE DEX DEX DEX DEX BPL SRCH ; EXITPBI ;Exit to SIO CLC RTS ; READCMD JSR SETREGS BCS BADSECT LDA #$21 STA IDE_CMD LDA #$00 STA MEM_BANK JSR READSECTOR LDX DBYTHI LDY DBYTLO JSR SETPTRS JSR XFER_BUF LDY #$01 BNE RETURN ; PUTCMD JSR SETREGS BCS BADSECT LDA #$31 BNE _WRITE WRTCMD JSR SETREGS BCS BADSECT LDA #$30 _WRITE STA IDE_CMD LDA #$00 STA MEM_BANK JSR CLEAR_BUF LDX DBYTHI LDY DBYTLO JSR BUF_XFER JSR SETPTRS JSR WRITESECTOR LDY #$01 BNE RETURN ; BADSECT LDY #$AB ;POINT Invalid (invalid sector) BNE _RETURN ; IDECODE ;Wait for drive to not be busy LPBZY LDA IDE_STATUS AND #$80 BNE LPBZY ; LDA DCOMND ; STA $D1FE CMP #'S ;Query Drive Status BEQ STATUSCMD CMP #$20 ;Format (null function) BEQ FORMATCMD CMP #$21 ;Format (null function) BEQ FORMATCMD CMP #$22 ;Format (null function) BEQ FORMATCMD CMP #'N ;Get Drive Configuration BEQ GETCFGCMD CMP #'R ;Read Sector BEQ READCMD CMP #'P ;Put Sector w/o verify BEQ PUTCMD CMP #'W ;Write Sector w/verify BEQ WRTCMD CMP #$EC ;Read EIDE Drive ID BEQ READID ; CMDREJ LDA #$01 STA DVSTAT LDY #$92 ;Function Not Implemented ; _RETURN LDA #$01 STA DVSTAT RETURN SEC RTS ; CMDERR LDY #$8B ;Device Malfunctions or Refuses Command/Device NAK BNE _RETURN ; TIMEOUT LDY #$8A ;Device Does Not respond/Device Timeout BNE _RETURN ; STATUSCMD LDY #$00 LDA #$01 STA (BUFRLO),Y INY LDA IDE_ERROR EOR #$FF STA (BUFRLO),Y INY LDA HDTABL+2,X STA (BUFRLO),Y INY LDA #$FF STA (BUFRLO),Y LDA #$00 STA DBYTLO STA DBYTHI ; FORMATCMD CLRSTATUS LDY #$01 BNE _RETURN ; GETCFGCMD ; JSR SETREGS ; BCS CMDERR JSR SETPTRS LDA HDTABL+2,X STA DRVCFG+2 LDY #$00 GCLP LDA DRVCFG,Y STA (BUFRLO),Y INY CPY #$0C BNE GCLP BEQ CLRSTATUS ; READID ; JSR SETREGS ; BCC RDID2 ; JMP CMDERR JSR SETPTRS RDID2 LDA #$EC STA IDE_CMD LDA #$00 STA MEM_BANK JSR READSECTOR LDX DBYTHI LDY DBYTLO JSR XFER_BUF LDY #$01 BNE RETURN ; SETPTRS ;Copy buffer pointer from page 3 DCB to zero page pointer LDA DBUFLO STA BUFRLO LDA DBUFHI STA BUFRHI ;Set sector buffer pointer LDA #$00 STA BFENLO LDA #$D6 STA BFENHI RTS ; SETREGS JSR SETPTRS ;Set flag for drive select LDA HDTABL+3,X AND #$10 STA ZTMP ;Set IDE sector number and head select registers based on SIO sector number low byte ;Sector number is low nybble + 1 LDA DAUX1 AND #$0F CLC ADC #$01 STA IDE_SNUM ;Head select is high nybble LDA DAUX1 AND #$F0 LSR A LSR A LSR A LSR A ;Add sector size selection ORA #$A0 ;Add drive selection ORA ZTMP STA IDE_SDH ;Set IDE cylinder registers based on partition table data and SIO sector number high byte LDA HDTABL+2,X CMP #$FF BEQ MAXSZ LDA DAUX2 CMP HDTABL+2,X BCS SECTERR BCC SLC MAXSZ LDA DAUX2 CLC SLC ADC HDTABL+1,X STA IDE_CYLL LDA HDTABL,X ADC #$00 STA IDE_CYLH ;Set IDE sector count register to 1 (we only need single sector transfers) LDA #$01 STA IDE_SCNT CLC SECTERR RTS ; READSECTOR ;Read 512 byte buffer from 16-bit IDE interface LDX #$00 LDY #$00 RSL1 LDA IDE_STATUS AND #$80 BEQ RSL2 LDA $D01F AND #$02 BNE RSL1 JMP TIMEOUT RSL2 LDA IDE_STATUS AND #$08 BEQ RSL2 LDA IDE_DATA STA (BFENLO),Y INY LDA IDE_HIDATA STA (BFENLO),Y INY INX CPY #$00 BNE RSL2 CPX #$80 BNE RSL3 INC BFENHI RSL3 CPX #$00 BNE RSL2 RSL4 LDA IDE_DATA LDA IDE_STATUS AND #$08 BNE RSL4 DEC BFENHI RTS ; WRITESECTOR ;Send 512 byte buffer to 16-bit IDE interface LDX #$00 LDY #$00 WSL1 LDA IDE_STATUS AND #$80 BEQ WSL2 LDA $D01F AND #$02 BNE WSL1 JMP TIMEOUT WSL2 LDA IDE_STATUS AND #$08 BEQ WSL2 LDA (BFENLO),Y PHA INY LDA (BFENLO),Y INY STA IDE_HIDATA PLA STA IDE_DATA INX CPY #$00 BNE WSL2 CPX #$80 BNE WSL3 INC BFENHI WSL3 CPX #$00 BNE WSL2 DEC BFENHI RTS ; RAW_SETREGS JSR SETPTRS ;Use DUNIT to set flag for drive select LDA DUNIT AND #$01 ROL A ROL A ROL A ROL A STA ZTMP ;Set IDE sector number and head select registers based on SIO sector number low byte ;Sector number is low nybble + 1 LDA DAUX1 AND #$0F CLC ADC #$01 STA IDE_SNUM ;Head select is high nybble LDA DAUX1 AND #$F0 LSR A LSR A LSR A LSR A ;Add sector size selection ORA #$A0 ;Add drive selection ORA ZTMP STA IDE_SDH ;Set IDE cylinder registers based on SIO sector number high byte and location $307 LDA DAUX2 STA IDE_CYLL LDA DUNUSE STA IDE_CYLH ;Set IDE sector count register to 1 (we only need single sector transfers) LDA #$01 STA IDE_SCNT CLC RTS ; CHECK_RAWCMD ;Process raw drive access. 24-bit sector access (8GB drive limit) is possible. ;Cylinder=(DUNUSE << 8) | DAUX2 // DUNUSE=high byte of cylinder DAUX2=low byte of cylinder ; Head=((DAUX1 & 0xF0) >> 4) // DAUX1 bits 7-4 ; Sector=((DAUX1 & 0x0F) + 1) // DAUX1 bits 3-0 + 1 ;Wait for drive to not be busy _BUSY LDA IDE_STATUS AND #$80 BNE _BUSY ; LDA DCOMND CMP #'R ;Raw Read Sector BEQ RAW_READ CMP #'W ;Raw Write Sector BEQ RAW_WRITE JMP CMDREJ ; RAW_READ JSR RAW_SETREGS BCC RAW_GET2 JMP CMDERR RAW_GET2 LDA #$21 STA IDE_CMD LDA #$00 STA MEM_BANK JSR READSECTOR LDX DBYTHI LDY DBYTLO JSR XFER_BUF LDY #$01 JMP RETURN ; RAW_WRITE JSR RAW_SETREGS BCC RAW_PUT2 JMP CMDERR RAW_PUT2 LDA #$31 STA IDE_CMD LDA #$00 STA MEM_BANK JSR CLEAR_BUF LDX DBYTHI LDY DBYTLO JSR BUF_XFER JSR SETPTRS JSR WRITESECTOR LDY #$01 JMP RETURN ; CLEAR_BUF ;fill $D6xx and $D7xx with $00's LDA #$00 TAY CLR1 STA $D600,Y STA $D700,Y INY BNE CLR1 RTS ; XFER_BUF ;Transfer data from sector buffer to SIO buffer ;X/Y regs, byte count to copy (X high, Y low) CPY #$00 BNE XFER0 DEX CPX #$FF BNE XFER0 RTS XFER0 DEX XFER1 DEY LDA (BFENLO),Y STA (BUFRLO),Y CPY #$00 BNE XFER1 INC BFENHI INC BUFRHI CPX #$FF BNE XFER0 RTS ; BUF_XFER ;Transfer data from SIO buffer to sector buffer ;X/Y regs, byte count to copy (X high, Y low) CPY #$00 BNE _XFER0 DEX CPX #$FF BNE _XFER0 RTS _XFER0 DEX _XFER1 DEY LDA (BUFRLO),Y STA (BFENLO),Y CPY #$00 BNE _XFER1 INC BUFRHI INC BFENHI CPX #$FF BNE _XFER0 RTS ; INITCODE ;PBI ROM initialization code ;Check for SELECT key LDA $D01F AND #$02 BNE CHECK_IDE ;If we get here, SELECT was pressed RTS CHECK_IDE LDA #$50 CMP IDE_STATUS BNE INITCODE ;In theory, we have a valid IDE controller and it's in a ready state LDA DEVMASK ORA NDEVREQ STA DEVMASK ;Set drive geometry/parameters LDA #$10 STA IDE_SCNT LDA #$AF STA IDE_SDH LDA #$91 STA IDE_CMD ;Short delay for drive init LDX #$40 WLP DEY BNE WLP DEX BNE WLP ;Init drive/partition data tables LDA #$01 STA MEM_BANK JSR CLEAR_BUF LDY #$14 ICLP LDA DRVCFGTPL-1,Y STA DRVCFG-1,Y DEY BNE ICLP ;Read partition table from HD (master: C=0, H=0, S=1) ;Set data pointer high byte LDA #$80 STA BFENHI ;Clear data pointer low byte LDA #$00 STA BFENLO ;Clear IDE cylinder registers STA IDE_CYLL STA IDE_CYLH ;Set IDE sector number LDA #$01 STA IDE_SNUM ;Set IDE sector count register to 1 (we only need 1 sector) STA IDE_SCNT ;Set sector size/drive/head select LDA #$A0 STA IDE_SDH ;Tell IDE controller that we want to read now LDA #$21 STA IDE_CMD ;Read the data JSR READSECTOR ;Check for partition table signature LDA $81FF CMP #$AA BNE NOPARTS LDA $81FE CMP #$55 BNE NOPARTS LDA $81FD CMP #$10 BNE NOPARTS ;Copy the partition table into place LDY #$24 ICLP4 LDA $81CF,Y STA HDTABL-1,Y DEY BNE ICLP4 NOPARTS RTS ; ; BITMASK .BYTE $01,$02,$04,$08,$10,$20,$40,$80 DRVCFGTPL .BYTE $01 ;Tracks per side .BYTE $10 ;Code revision .BYTE $00 ;Sectors per track M .BYTE $FF ;Sectors per track L .BYTE $00 ;Sectors per track H - currently not used in this code .BYTE $0C ;Type code - b1=1: 8" disks, b2=1: DD, b3=1: IDE .BYTE $02 ;Sector size (high byte) .BYTE $00 ;Sector size (low byte) .BYTE $FF ;Unused? .BYTE $49,$44,$45 ;"IDE" ;Reserve 4 bytes for future use .BYTE $00,$00,$00,$00 ; R_OPEN JMP JUST_EXIT R_CLOSE JMP JUST_EXIT R_GET JMP JUST_EXIT R_PUT JMP JUST_EXIT R_STATUS JMP JUST_EXIT R_SPECIAL JMP JUST_EXIT JUST_EXIT RTS .DC $E000-* 0 END