******************************************************************** * IDEdrv RBF Device Driver * * (C) 2026 Roelof van Silfhout * * IDEdrv is a RBF type device driver * that fetches 256bytes from 512-byte PHYSICAL sectors. * * This driver does DMA transfers of data and uses the Suspend state * mechanism whilst waiting for data to become ready * * Note that this driver doesn't do verify * * * Edt/Rev YYYY/MM/DD Modified by Comment * ------------------------------------------------------------------ * 0 2026/03/18 RvS Initial version * 1 2026/03/27 RvS IRQ enabled version nam IDEdrv ttl RBF ATA/IDE Device Driver use defsfile tylg set Drivr+Objct atrv set ReEnt+rev rev set 1 edition set 1 mod eom,name,tylg,atrv,start,DSKSTA fcb DIR.+SHARE.+PEXEC.+PREAD.+PWRIT.+EXEC.+UPDAT. name fcs /IDEdrv/ fcb edition ********************************************************************* * * Static Storage * * org DRVBEG rmb DRVMEM*DrvCnt V.IDECMD rmb 1 last IDE command V.SAVE rmb 2 temporary Storage DSKSTA equ . * Start of driver code start lbra Init lbra Read lbra Write lbra GetStat lbra SetStat * run terminate direct without lbra instruction! * * Terminate * * Entry: * U = address of device memory area * * Exit: * CC = carry set on error * B = error code * Term ldx #0 os9 F$IRQ remove device from IRQ polling list rts * **** Init * * Entry: * Y = address of device descriptor * U = address of device memory area * * Exit: * CC = carry set on error * B = error code * Init ldb #DrvCnt get maximum drives supported stb V.NDRV,u save in our device memory leax DRVBEG,u point X to the drive tables lda #$FF load max capacity value * Invalidate V.NDRV drive tables drvx sta DD.TOT+2,x sta V.TRAK,X Iniz to high track count leax DRVMEM,x point to next drive table decb decrement counter bne drvx if not zero, continue * initialise IDE controller ldx V.PORT,u get hw address get controller base address clr dmaltc,x disable everything force 256byte mode ldb #IDE_LBA set LBA mode stb ideadr3,x LBA 24...27 save ldb idecmst,x read status cmpb #(IDERDY+IDEDSC) idle? bne initerr drive not ready ldb #H.RST stb idecmst,x restore drive bsr delay isnrdy bsr delay ldb idecmst,x check if done bitb #IDEBSY bne isnrdy * place interrupt service routine on the polling table leax idestat,x reading it will clear IRQ tfr x,d put status register address in D leax FDMASK,pcr point to flipbit, mask & priority leay IRQSVC,pcr point to interrupt service routine os9 F$IRQ rts ierr ldb #E$BTyp flag error sector size rts initerr ldb #E$NotRdy set not ready error rts delay lda #64 set up a delay counter del deca decrement the delay count bne del hang in there for the count rts * interrupt service routine IRQSVC lda V.WAKE,u beq IRQSERR Nothing waiting return clrb stb D.DMAReq clear DMA inuse flag stb V.WAKE,u clear waiting flag tfr d,x lda P$State,x get state flag anda #^Suspend clear suspend state sta P$State,x save it clrb IRQEND rts IRQSERR comb rts FDMASK fcb $00 no flip bits fcb $20 mask bit of IRQset bit fcb $01 priority ******************** * Read * * Entry: * B = MSB of the disk's LSN * X = LSB of the disk's LSN * Y = address of path descriptor * U = address of device memory area * * Exit: * CC = carry set on error * B = error code * * First check if LSN0 is wanted * it is special since it has * disk info which will be copied to * drive table Read cmpx #$0000 LSN 0? bne ReadSect branch if not tstb LSN 0? bne ReadSect branch if not bsr ReadSect else read LSN0 bcs rret if error, return * copying LSN0 data to path descriptor leax DRVBEG,u point X to start of drive table ldb PD.DRV,y get drive number lsn@ beq CopyLSN0 branch if drive zero leax DRVMEM,x else increase X by drive table size decb decrement drive number bra lsn@ branch to loop * X = drive table pointer for PD.DRV * Copy DD.SIZ bytes (LSN0) from buffer to drive table CopyLSN0 ldu PD.BUF,y ldb #DD.SIZ CpyLSNLp pulu a one cycle less than lda ,u+ sta ,x+ decb bne CpyLSNLp rret rts ****** Read Sector * * Single sector read routine * Entry: * Y = address of path descriptor * U = address of device memory area * B = Sector bits 23-16 * X = Sector bits 15-0 * ReadSect lda #H.DMARD IDE read command using DMA sta V.IDECMD,u bra idesetup deal with the hardware settings ****** Write Sector * * Entry: * B = MSB of the disk's LSN * X = LSB of the disk's LSN * Y = address of path descriptor * U = address of device memory area * * Exit: * CC = carry set on error * B = error code * Write lda #H.DMAWR IDE write command using DMA sta V.IDECMD,u * fall into idesetup ******************** * common setup IDE sector transfer using DMA * ***** Setup IDE controller * Entry: U = address of device memory area * Exit: B = status byte for device * destroys A,X idesetup pshs b,y ldd PD.BUF,y get buffer address and save std V.SAVE,u keep copy * fix for LBA mode of addressing sectors ldb #IDE_LBA always use LBA addressing mode lda PD.DRV,y get drive number even numbers are master, odd are slave lsra shift LSBit into carry bcc ex1@ is it a slave drive? orb #IDE_DSL yes ex1@ ldy V.PORT,u base address device in Y stb ideadr3,y LBA 24...27 taken to be 0 puls b stb ideadr2,y LBA 16...23 tfr x,d sta ideadr1,y LBA 8...15 stb ideadr0,y LBA 0...7 ldb #1 one sector at a time stb idescnt,y WCR01 lda D.DMAReq is DMA free to use? beq WCR02 ..yes; continue ldx #1 sleep for a tick os9 F$Sleep bra WCR01 WCR02 inc D.DMAReq reserve DMA * check if IDE is ready ldb idecmst,y read controller status cmpb #IDERDY+IDEDSC bne ider2 error, not there * issue IDE command ldb V.IDECMD,u get IDE command to do stb idecmst,y issue command ldb idestat,y clear any lingering IRQset before allowing them to IRQ * wait for data transfer lda D.Proc sta V.WAKE,u prep for re-awakening * enable interrupts from IDE ldb #L_INTEN stb dmaltc,y allow interrupts to be generated once data is ready bra Cmd50 Cmd30 ldx D.Proc get ptr to process descriptor lda P$State,x get state flag ora #Suspend put proc in suspend state sta P$State,x save it in process descriptor andcc #^IntMasks unmask interrupts ldx #1 give up timeslice os9 F$Sleep suspend * setup DMA control bits Cmd50 orcc #IntMasks make sure nothing gets between here, messing up DMA settings lda V.WAKE,u true interrupt? bne Cmd30 branch if not * at this stage keep interrupt masks on lda #EXTDMA enable external IO DMA ldb V.IDECMD,u get IDE command to do cmpb #H.DMARD is it a read operation? beq iderwt branch if so * if writing then add in DMA_RW bit ora #DMAWRT iderwt sta DMA.SCH place in DMA control register * data is ready so setup DMA * set DMA start address ldd V.SAVE,u recover buffer address std DMA.SAD DMAC source address register * DMA through MMU select task to use clra system task sta DMA.STSK Task to copy to * set byte count ldd #256 one sector for OS9 std DMA.SBC save in DMA byte counter * arm DMA controller lda #3 sta DAT.CTRL arm DMA controller * enable DMA for IDE device lda #L_DMAEN sta dmaltc,y enable IDE DMA, no more interrupts * wait for DMA to complete ider1 lda idestat,y reading idestat doesn't clear interrupt flag bita #IDEIRQ beq ider1 wait for completion * DMA done - continue with disable device DMA * and check error status clr dmaltc,y prevent DMA & IRQ activity IDE board * put DMA back in MEM2MEM mode for OS9 calls ldb #MEM2MEM stb DMA.SCH put back in register andcc #^IntMasks clear interrupt masks * check IDE status ldb idecmst,y check status andb #IDEERR leave error bit beq ider2 return if no error ldb #E$NotRdy load error in back puls pc,y ider2 clrb no errors puls pc,y ****** GetStat/SetStat * * Entry: * R$B = function code * Y = address of path descriptor * U = address of device memory area * * Exit: * CC = carry set on error * B = error code * SetStat clrb no action rts GetStat ldx PD.RGS,y get registers ldb R$B,x get caller's B * B has function to do, for now return error ldb #E$UnkSvc unknown service coma ex1 rts emod eom equ * end