Mercurial > hg > Members > kono > nitros9-code
changeset 3032:3afecdae6f53
Low level CoCo SDC driver updtate from Darren Atkinson
author | tlindner |
---|---|
date | Mon, 22 Dec 2014 21:06:37 -0800 |
parents | 75bf8852c390 |
children | 7028ce216ccf |
files | defs/cocosdc.d level1/modules/llcocosdc.asm |
diffstat | 2 files changed, 483 insertions(+), 174 deletions(-) [+] |
line wrap: on
line diff
--- a/defs/cocosdc.d Sat Dec 20 12:52:07 2014 -0600 +++ b/defs/cocosdc.d Mon Dec 22 21:06:37 2014 -0800 @@ -1,6 +1,3 @@ - IFNE COCOSDC.D-1 -COCOSDC.D SET 1 - ******************************************************************** * cocosdc.d - CoCo SDC definitions * @@ -11,8 +8,38 @@ * ------------------------------------------------------------------ * 2014/05/02 Boisy G. Pitre * Created +* 2014/12/22 Darren Atkinson +* Additional hardware symbols + + IFNE COCOSDC.D-1 +COCOSDC.D SET 1 +* Main Port Address (V.PORT) SDAddr SET $FF4A +* Hardware Addressing - CoCo Scheme +CTRLATCH equ $FF40 controller latch (write) +CMDREG equ $FF48 command register (write) +STATREG equ $FF48 status register (read) +PREG1 equ $FF49 param register 1 +PREG2 equ $FF4A param register 2 +PREG3 equ $FF4B param register 3 +DATREGA equ PREG2 first data register +DATREGB equ PREG3 second data register +FLSHDAT equ $FF42 flash data register + +* Status Register Masks +BUSY equ %00000001 set while a command is executing +READY equ %00000010 set when ready for a data transfer +FAILED equ %10000000 set on command failure + +* Command and Mode Values +CMDMODE equ $43 control latch value to enable command mode +CMDREAD equ $80 read logical sector +CMDWRITE equ $A0 write logical sector +CMDEX equ $C0 extended command +CMDEXD equ $E0 extended command with data block + + ENDC
--- a/level1/modules/llcocosdc.asm Sat Dec 20 12:52:07 2014 -0600 +++ b/level1/modules/llcocosdc.asm Mon Dec 22 21:06:37 2014 -0800 @@ -1,21 +1,34 @@ ******************************************************************** -* llcocosdc - CoCo SD Low-level driver +* llcocosdc - CoCo SDC Low-level driver * * $Id$ * * Edt/Rev YYYY/MM/DD Modified by * Comment * ------------------------------------------------------------------ -* 2004/??/?? Boisy G. Pitre +* 2013/05/?? Boisy G. Pitre * Created. * 2014/11/27 tim lindner -* Changed read and write routines to enter and leave command mode +* Changed read and write routines to enter and leave command mode. +* +* 2014/12/22 Darren Atkinson +* Total re-write. Provides MPI slot selection to permit co-existence +* with a real floppy controller. Sends command to controller during +* Init which locks out the floppy emulation capability. Adds GetStat +* functions for extended commands. Uses TFM to retrieve data blocks +* when a 6309 CPU is present. Supports the SS.DSize GetStat function +* to query controller for the disk size. +* NAM llcocosdc TTL CoCo SDC Low-level driver USE defsfile USE rbsuper.d + USE cocosdc.d + +MPIREG equ $FF7F + tylg SET Sbrtn+Objct atrv SET ReEnt+rev @@ -24,52 +37,28 @@ MOD eom,name,tylg,atrv,start,0 +* Low-level driver static memory area inside that of rbsuper ORG V.LLMem -* Low-level driver static memory area +V.SDCMPI rmb 1 MPI slot containing CoCo SDC +V.MaskIRQs rmb 1 contains $50 if IRQ/FIRQ should be masked name FCS /llcocosdc/ -start bra ll_init - nop - lbra ll_read - lbra ll_write +start lbra ll_init + bra ll_read + nop + bra ll_write + nop bra ll_getstat - nop - lbra ll_setstat -* lbra ll_term - -* ll_term -* -* Entry: -* Y = address of device descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -ll_term - clrb - rts - -* ll_init -* -* Entry: -* Y = address of device descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -ll_init -* ldy V.PORT-UOFFSET,u -* ldb #$43 -* stb -$0A,y - clrb - rts + nop + bra ll_setstat + nop + *** lbra ll_term *** + clrb + rts +*-------------------------------------------------------------------------- * ll_getstat * * Entry: @@ -80,35 +69,21 @@ * CC = carry set on error * B = error code * -ll_getstat - lda R$B,x +ll_getstat ldx PD.RGS,y point X at stacked registers + lda R$B,x get function code cmpa #SS.DSize - beq SSDSize - ldb #E$UnkSvc - coma - rts - + beq getSize branch if "get disk size" + tfr a,b + andb #$F0 keep hi nibble + cmpb #CMDEXD + beq exCmd branch if extended command with data + anda #$FF-4 make sure "TFM" bit is cleared + cmpb #CMDEX + beq exCmd branch if ext command without data -* SS.DSize - Return size information about a device -* -* Entry: B = SS.DSize -* Exit: Carry = 1; error with code in B -* Carry = 0: -* IF B = 0 -* A = Sector Size (1 = 256, 2 = 512, 4 = 1024, 8 = 2048) -* X = Number of Sectors (bits 31-16) -* Y = Number of Sectors (Bits 15-0) -* IF B != 0 -* A = Sector Size (1 = 256, 2 = 512, 4 = 1024, 8 = 2048) -* X = Number of Logical Cylinders -* B = Number of Logical Sides -* Y = Number of Logical Sectors/Track -* -SSDSize - clrb - rts + *** Fall Thru *** - +*-------------------------------------------------------------------------- * ll_setstat * * Entry: @@ -119,60 +94,259 @@ * CC = carry set on error * B = error code * -ll_setstat - clrb - rts +ll_setstat comb set carry + ldb #E$UnkSvc return error + rts + + +*-------------------------------------------------------------------------- +* SS.DSize - Return size information about a device +* +* Exit: +* Carry cleared for no error. +* A = Sector Size (1=256, 2=512, 4=1024, 8=2048) +* +* IF B = 0 +* X = Number of Sectors (bits 31-16) +* Y = Number of Sectors (Bits 15-0) +* +* IF B != 0 +* B = Number of Logical Sides +* X = Number of Logical Cylinders +* Y = Number of Logical Sectors/Track +* +getSize lda #CMDEX primary command code + ora PD.DRV,y combine drive num with command + ldb #'Q "Query Size" sub-command + ldu #$FFFF I/O buffer = none + pshs x save frame ptr + bsr CommSDC send query to controller + puls x restore frame ptr + ldb #E$NotRdy error code + bcs sizeRet return if error + clra bits 31-24 of size always zero + ldb -1,y bits 23-16 of size + std R$X,x return bits 31-16 in X + ldd ,y bits 15-0 of size + std R$Y,x return in Y + inca A = 1: 256 byte sectors + clrb B = 0: LBA device + std R$D,x return in D +sizeRet rts + +*-------------------------------------------------------------------------- +* SDC Extended Device Commands +* +* Entered with SDC command code in A. +* +* Parameters are passed indirectly via the register frame: +* X = address of 256 byte I/O buffer or $FFFF if none +* U.L = optional param byte 1 +* Y = optional param bytes 2 (hi) and 3 (low) +* +* Response values are returned indirectly via the register frame: +* A = controller status +* U.H = 0 +* U.L = response byte 1 +* Y = response bytes 2 (hi) and 3 (low) +* +exCmd pshs u,y,x preserve registers + leay ,u Y = device memory area + ldu R$X,x U = I/O buffer address + ldb R$U+1,x B = param byte 1 + ldx R$Y,x X = param bytes 2 and 3 + bsr CommSDC do command protocol + puls x restore register frame pointer + stb R$A,x [A] = controller status + lda #0 will clear top half of U + ldb -1,y get response byte 1 (FF49) + std R$U,x [U] = 1st response byte + ldd ,y get response bytes 2,3 (FF4A,B) + std R$Y,x [Y] = 2nd and 3rd response bytes + ldb #E$NotRdy error code + bcs exOut skip next if error + clrb no error +exOut puls y,u,pc return + + +*-------------------------------------------------------------------------- +* ll_write +* +* Write one sector. +* +* Entry: +* Y = address of path descriptor +* U = address of device memory area +* +* +ll_write lda #CMDWRITE command code for Write + bsr sectorIO common sector I/O + bcc wrRet return if success + ldb #E$Write error code for write +wrRet rts + + +*-------------------------------------------------------------------------- * ll_read * +* Read one sector. +* * Entry: * Y = address of path descriptor * U = address of device memory area * -* Static memory referenced: -* V.CchPSpot = address of spot in cache where physical sector data will go -* sectsize = sector size (0=256,1=512,2=1024,3=2048) -* V.SectCnt = sectors to read -* V.PhysSect = physical sector to start read from -ll_read - lda #$43 - sta $ff40 - ldx #0 -rdCmMd lda $ff48 - lsra - bcc rdStart - leax -1,x - bne rdCmMd - bra rdFail - -rdStart lda PD.DRV,y - ldb V.PhysSect,u - ldx V.PhysSect+1,u - ldy V.PORT-UOFFSET,u - ldu V.CchPSpot,u +ll_read lda #CMDREAD+4 command code for 6309 Read (TFM) + fcb $11 next instr is "LDE" on 6309 + lda #CMDREAD command code for 6809 Read + bsr sectorIO common sector I/O + bcc rdRet return if success + ldb #E$Read error code for read +rdRet rts + + +*-------------------------------------------------------------------------- +* Funnel code for sector read and write +* +* Entry: +* A = read/write command code +* Y = address of path descriptor +* U = address of device memory area +* +sectorIO ldb #1 highest drive number allowed + subb PD.DRV,y range check drive number + bcc drvOK branch if valid + ldb #E$Unit error code for bad drive number + puls x,pc pop top address then return + +drvOK ora PD.DRV,y combine drive num with command + leay ,u point Y at device mem + ldb V.PhysSect,u B = hi byte of LSN + ldx V.PhysSect+1,u X = lo word of LSN + ldu V.CchPSpot,u U = buffer address + + *** Fall Thru *** + +*-------------------------------------------------------------------------- +* CommSDC +* +* This is the core routine used for all +* transactions with the SDC controller. +* +* Entry: +* A = Command code +* B = LSN hi byte / First parameter byte +* X = LSN lo word / 2nd and third param bytes +* Y = Address of driver device memory area +* U = Address of I/O buffer ($FFFF = none) +* +* Exit: +* Carry set on error +* B = controller status code +* Y = address of SDC Data Register A (FF4A) +* +CommSDC + +* Save current MPI setting and activate the SDC slot + pshs cc preserve CC (interrupt masks) + lsr ,s shift carry out of saved CC + pshs a,b save cmd code, alloc byte for saving MPI + tfr cc,a get copy of current CC + ora V.MaskIRQs,y set I and F masks if FDC present + tfr a,cc update I and F in CC + lda MPIREG get current MPI slot + sta 1,s save on stack where B was pushed + anda #$30 mask out current SCS nibble + ora V.SDCMPI,y insert SCS nibble for SDC slot + ldy #DATREGA setup Y for hardware addressing + tsta was an SDC controller found? + bmi sdcNone exit if no + sta MPIREG activate MPI slot + +* Put controller in Command mode + lda #CMDMODE the magic number + sta -10,y send to control latch (FF40) + puls a pull saved command code back into A - stb -1,y - stx ,y - ora #$80 - sta -2,y - exg a,a +* Put input parameters into the registers. +* It does no harm to put random data in the +* registers for commands which dont use them. + stb -1,y high byte to param reg 1 + stx ,y low word to param regs 2 and 3 + +* Wait for Not Busy. + lbsr waitForIt run polling loop + bcs cmdExit exit if error or timed out + +* Send command to controller + sta -2,y to command register (FF48) + +* Determine if a data block should be sent. +* The code for any command which requires +* a data block will have bit 5 set. + bita #$20 test the "send block" command bit + beq rxBlock branch if no block to send + +* Wait for Ready to send + bsr waitForIt run polling loop + bcs cmdExit exit if error or timed out + leax ,u move data address to X + IFGT Level-1 + bita #$40 extended command or sector write? + lbne txCmd branch if extended command + ENDIF - ldx #0 -rdWait lda -2,y - bmi rdFail - bita #2 - bne rdRdy - leax -1,x - bne rdWait -rdFail - clr $ff40 - ldb #E$Read - coma - rts +* Send 256 bytes of data + ldd #32*256+8 32 chunks of 8 bytes +txChunk ldu ,x send one chunk... + stu ,y + ldu 2,x + stu ,y + ldu 4,x + stu ,y + ldu 6,x + stu ,y + abx point X at next chunk + deca decrement chunk counter + bne txChunk loop until all 256 bytes sent + +* Wait for command to complete +txCompl lda #5 timeout retries +txWait bsr waitForIt run polling loop + bitb #BUSY test BUSY bit + beq cmdExit exit if completed + deca decrement retry counter + bne txWait repeat if until 0 + coma set carry for timeout error + bra cmdExit exit -rdRdy leax ,u - ldd #32*256+8 -rdChnk ldu ,y +* Set error condition and exit when no SDC hardware found +sdcNone leas 1,s pop saved command code + comb set carry + ldb #E$Unit error number for missing hardware + bra cmdExit exit + +* For commands which return a 256 byte response block the +* controller will set the READY bit in the Status register +* when it has the data ready for transfer. For commands +* which do not return a response block the BUSY bit will +* be cleared to indicate that the command has completed. +* +rxBlock bsr longWait run long status polling loop + bls cmdExit exit if error, time out or completed + leax 1,u test the provided buffer address + beq cmdExit exit if "no buffer" ($FFFF) + bita #$04 test the "TFM" command bit + bne rx6309 branch if set + leax ,u move data address to X + IFGT Level-1 + bita #$40 extended command or sector read? + bne rxCmd branch if extended command + ENDIF + +* 6809 read transfer loop into current task space + ldd #32*256+8 32 chunks of 8 bytes +rxChunk ldu ,y read one chunk... stu ,x ldu ,y stu 2,x @@ -180,78 +354,186 @@ stu 4,x ldu ,y stu 6,x - abx - deca - bne rdChnk + abx update X for next chunk + deca decrement chunk counter + bne rxChunk loop until all 256 bytes transferred + bra cmdOK exit with SUCCESS - sta $ff40 - rts +* 6309 read transfer using TFM into current task space +rx6309 fcb $10,$86,$01,$00 [ldw #256] block size = 256 + orcc #$50 ensure interrupts are masked + leax 1,y point X at Data Register B (FF4B) + fcb $11,$3B,$13 [tfm x,u+] read block +cmdOK clrb status code for SUCCESS, clear carry + +* Exit +cmdExit puls a pull saved MPI settings + rol ,s rotate carry into saved CC on stack + clr -10,y end command mode + sta MPIREG restore saved MPI settings + puls cc,pc restore irq masks, update carry and return -* ll_write +*-------------------------------------------------------------------------- +* Wait for controller status to indicate either "Not Busy" or "Ready". +* Will time out if neither condition satisfied within a suitable period. +* +* Exit: +* CC.C set on error or time out. +* CC.Z set on "Not Busy" status (if carry cleared). +* B = status +* A, Y and U are preserved. +* +longWait bsr waitForIt enter here for doubled timeout + bcc waitRet return if cleared in 1st pass +waitForIt ldx #0 setup timeout counter +waitLp comb set carry for assumed FAIL + ldb -2,y read status + bmi waitRet return if FAILED + lsrb BUSY --> Carry + bcc waitDone branch if not busy + bitb #READY/2 test READY (shifted) + bne waitRdy branch if ready for transfer + bsr waitRet consume some time + ldb #$81 status = timeout + leax ,-x decrement timeout counter + beq waitRet return if timed out + bra waitLp try again + +waitDone clrb Not Busy: status = 0, set Z +waitRdy rolb On Ready: clear C and Z +waitRet rts return + + +*-------------------------------------------------------------------------- +* Transfers of command and response data require special handling +* in Level 2 due to separate address space for System/User tasks. +* + IFGT Level-1 +* Send command data from User task space +txCmd bsr tskPrep B = task#, push word counter +txWord os9 F$LDABX get byte from user space buffer + sta ,y send 1st half of word + leax 1,x increment buffer address + os9 F$LDABX get byte from user space buffer + sta 1,y send 2nd half of word + leax 1,x increment buffer address + dec ,s decrement word counter + bne txWord loop if more to send + leas 1,s pop word counter + lbra txCompl go wait for command completion + +tskPrep ldu D.Proc get current process ptr + ldb P$Task,u get task # for current process + lda #128 number of words to transfer (256 bytes) + ldu ,s+ half-pop return address into U + sta ,s leave word counter on the stack + tfr u,pc return + +* Read response data into User task space +rxCmd bsr tskPrep B = task#, push word counter +rxWord lda ,y read 1st half of word + os9 F$STABX store in user space buffer + leax 1,x increment buffer address + lda 1,y read 2nd half of word + os9 F$STABX store in user space buffer + leax 1,x increment buffer address + dec ,s decrement word counter + bne rxWord loop if more to read + leas 1,s pop word counter + bra cmdOK exit with SUCCESS + ENDIF + + +*-------------------------------------------------------------------------- +* ll_init * * Entry: -* Y = address of path descriptor +* Y = address of device descriptor * U = address of device memory area * -* Static memory referenced: -* V.CchPSpot = address of spot in cache where physical sector data is -* sectsize = sector size (0=256,1=512,2=1024,3=2048) -* V.SectCnt = sectors to read -* V.PhysSect = physical sector to start read from -ll_write - lda #$43 - sta $ff40 - ldx #0 -wrCmMd lda $ff48 - lsra - bcc rwStart - leax -1,x - bne wrCmMd - bra wrFail +* Exit: +* CC = carry set on error +* B = error code +* +ll_init pshs cc save irq masks + orcc #$50 mask irqs + ldd #$8080 prepare "not found" values + pshs dp,b,a alloc variables on stack + ldx #CMDREG point X at FDC command reg + ldb MPIREG get current MPI slot + andb #$33 mask out the unused bits + stb 2,s save on stack (in DP position) + orb #$03 start SCS scan at slot 4 -rwStart lda PD.DRV,y - ldb V.PhysSect,u - ldx V.PhysSect+1,u - ldy V.PORT-UOFFSET,u - ldu V.CchPSpot,u +chkSlot stb MPIREG activate slot being scanned + lda ,s have we already found CoCo SDC ? + bpl chkFDC branch if yes + lda #$64 test pattern + sta -6,x store at Flash Data Reg address + lda -5,x get value from Flash Ctrl Reg + clr -6,x clear Flash Data Reg + eora -5,x get changed bits from Ctrl Reg + suba #$60 did expected bits change? + bne chkFDC branch if not an SDC + stb ,s record the SDC slot + bra nxtSlot go scan next slot - stb -1,y - stx ,y - ora #$A0 - sta -2,y - exg a,a +chkFDC lda 1,s have we already found an FDC ? + bpl nxtSlot branch if yes + bsr fdcTest test if FDC present + bne nxtSlot branch if not present + stb 1,s record the FDC slot - ldx #0 -wrWait lda -2,y - bmi wrFail - bita #2 - bne wrRdy - leax -1,x - bne wrWait -wrFail - clr $ff40 - ldb #E$Write - coma - rts +nxtSlot decb decrement SCS slot number + bitb #$08 have we scanned all slots? + beq chkSlot loop if more to scan + lda ,s get slot with CoCo SDC + bmi saveSDC branch if none + cmpa 2,s same as original slot selection? + bne saveSDC branch if no + eora #$01 change original slot to.. + sta 2,s ..be something else + eora #$01 back to the true SDC slot +saveSDC anda #$83 keep SDC slot number or "not found" + sta V.SDCMPI,u store SDC slot info in device mem + lda #$50 irq masks will be needed if FDC present + ldb 1,s was an FDC found? + bpl useSlot branch if yes + clra irq masks not needed + ldb 2,s get original MPI slot selection +useSlot stb MPIREG activate default MPI slot + sta V.MaskIRQs,u store irq masks in device mem + lda $FF22 reset any latched CART interrupt + leas 3,s pop variables off the stack + puls cc restore saved irq masks -wrRdy leax ,u - ldd #64*256+4 -wrChnk ldu ,x - stu ,y - ldu 2,x - stu ,y - abx - deca - bne wrChnk +* Disable Floppy Emulation capability in SDC controller + lda #$C0 primary command code + ldb #'g secondary command to "Set Global Flags" + ldx #$FF80 mask/flag bytes + leay ,u point Y at static variables + ldu #$FFFF "no buffer" address + lbsr CommSDC send command to controller + clrb no error + rts return -wrComp lda -2,y - bmi wrFail - lsra - bcs wrComp +* Test for presence of FDC in active slot +fdcTest lda #$D0 FORCE INTERRUPT command + sta ,x send to FDC command register + bsr fdcDelay wait awhile + lda ,x read FDC status + lda 3,x read FDC data register + coma invert all bits + sta 3,x put inverted data back + bsr fdcDelay wait awhile + suba 3,x test if read matches write +fdcDelay pshs y,x,d,cc push regs + mul delay cycles + puls cc,d,x,y,pc restore regs and return - clr $ff40 - rts + +*-------------------------------------------------------------------------- EMOD eom EQU *