Mercurial > hg > Members > kono > nitros9-code
changeset 3252:c505ae3120c4
modules: Make source file line endings consistent
Only a few had the "other" CR/LF endings.
author | Tormod Volden <debian.tormod@gmail.com> |
---|---|
date | Sat, 07 Apr 2018 21:00:59 +0200 |
parents | 4393a2b5b9a0 |
children | 6dec962b072d |
files | level1/modules/ddisk.asm level1/modules/dwinit.asm level1/modules/dwrdmess.asm level1/modules/dwwrmess.asm level1/modules/llcoco3fpga.asm level1/modules/scdpp.asm |
diffstat | 6 files changed, 1942 insertions(+), 1942 deletions(-) [+] |
line wrap: on
line diff
--- a/level1/modules/ddisk.asm Sat Apr 07 19:28:53 2018 +0200 +++ b/level1/modules/ddisk.asm Sat Apr 07 21:00:59 2018 +0200 @@ -1,1095 +1,1095 @@ -******************************************************************** -* DDisk - Dragon Floppy driver -* -* $Id$ -* -* Edt/Rev YYYY/MM/DD Modified by -* Comment -* ------------------------------------------------------------------ -* - ????/??/?? -* Original Dragon Data distribution version -* -* Added Defines for IO ports. -* 2004/11/09, P.Harvey-Smith -* -* Dragon Alpha code, 2004-11-09, P.Harvey-Smith. -* I am not sure of how to disable NMI on the Alpha, it is -* simulated in software using the NMIFlag. -* -* The Dragon Alpha/Professional uses the same FDC chip as -* DragonDos, however it is mapped between FF2C and FF2F, -* also the register order is REVERSED, so command/status is at -* FF2F. -* -* Drive Selects, motor and write precompensation is controled -* through the IO port of an AY-8912, which itself is connected -* to a 3rd PIA mapped at FF24 to FF27, this PIA also has it's -* inturrupt lines connected to the CPU's FIRQ. -* -* 2004-11-15, P.Harvey-Smith. -* Fixed bug in inturrupt handling code that was making the -* Dragon Alpha crash if a disk was accessed with no disk -* in the drive. As the Alpha is using a simulated NMI disable -* we have to ensure that the NMI enabling routine has completed -* BEFORE isuing a command to the disk controler, or if the -* inturrupt happens in the middle of the enable routine it -* causes the machine to crash ! -* -* 2004-11-24, P.Harvey-Smith. -* Fixed up so that double sided disks now work, origional -* double sided code taken from Jon Bird's pages at : -* http://www.onastick.clara.net/dragon.html and modified -* for NitrOS9. -* -* 2004-11-27, P.Harvey-Smith. -* Reformatted with tab=8. -* -* 2005-04-22, P.Harvey-Smith. -* Hopefully fixed a bug that was causing the Dragon 64 target to -* crash and burn when reading disks, this made a successfull boot -* almost imposible ! Fixed by writing disk command before writing -* disc control register, the Alpha target needs them the other way -* around. Still has a problem doing lots of retries. -* -* 2005-04-24, P.Harvey-Smith. -* Fixed constant lost data errors reading disks, again by slightly -* re-ordering the instructions in the read data loop. -* -* 2005-04-24, P.Harvey-Smith. -* Removed debugging code/messages. -* -* 2005-05-31, P.Harvey-Smith. -* Added ability to read, write and format standard OS-9 format disks -* including single denity, and disks with track 0 single denisity, but -* all other tracks double density. -* -* Added code to make step rates work as on the rb1773 driver, they where -* previously working back to front. -* -* 2005-06-06, P.Harvey-Smith. -* Verified as working on a real Alpha, by Richard Harding. -* -* 2005-06-16, P.Harvey-Smith. -* Added NMI enable/disable code, as I know know how to enable/disable -* NMI on the Alpha, having disasembled the Alpha's OS9's ddisk. -* -* 2005-06-17, P.Harvey-Smith. -* Ok, this'll teach me to submit code before testing on the real hardware ! -* Seperated NMI disable/drive select code on alpha, as above patches -* worked fine on Mess, but not on real hardware (timing problems). -* -* 2006-01-08, P.Harvey-Smith. -* Added support for Dragon 32, that has had a memory upgraded to 64K, -* this is treated like the Dragon 64 EXCEPT that the code to manipulate -* the ACIA is not included. This is required due to the incomplete -* address decoding, writes to the non-existant ACIA would hit the PIA -* at FF00, and cause a crash. -* -* 2006-01-08, P.Harvey-Smith. -* Since I now have a genuine Dragon 5.25" drive, found that nitros format -* fell over accessing it, this was due to the step rate not being set -* correctly in the drive recalibrate routine, I ahve corrected this to -* use the value in the descriptor. -* - - nam DDisk - ttl Dragon Floppy driver - -* Disassembled 02/04/21 22:37:46 by Disasm v1.6 (C) 1988 by RML - - ifp1 - use defsfile - endc - - IFNE dalpha - -* Dragon Alpha has a third PIA at FF24, this is used for -* Drive select / motor control, and provides FIRQ from the -* disk controler. - -DPPIADA EQU DPPIA2DA -DPPIACRA EQU DPPIA2CRA -DPPIADB EQU DPPIA2DB -DPPIACRB EQU DPPIA2CRB - -PIADA EQU DPPIADA+IO ; Side A Data/DDR -PIACRA EQU DPPIACRA+IO ; Side A Control. -PIADB EQU DPPIADB+IO ; Side A Data/DDR -PIACRB EQU DPPIACRB+IO ; Side A Control. - -;WD2797 Floppy disk controler, used in Alpha Note registers in reverse order ! -DPCMDREG EQU DPCmdRegA ; command/status -DPTRKREG EQU DPTrkRegA ; Track register -DPSECREG EQU DPSecRegA ; Sector register -DPDATAREG EQU DPDataRegA ; Data register - -CMDREG EQU DPCMDREG+IO ; command/status -TRKREG EQU DPTRKREG+IO ; Track register -SECREG EQU DPSECREG+IO ; Sector register -DATAREG EQU DPDATAREG+IO ; Data register - -; Disk IO bitmasks - -NMIEn EQU NMIEnA -WPCEn EQU WPCEnA -SDensEn EQU SDensEnA -MotorOn EQU MotorOnA - -; These are the bits that we know the function of on the Alpha interface -KnownBits EQU Drive0A+Drive1A+Drive2A+Drive3A+MotorOnA+SDensEnA+WPCEnA - - ELSE - -DPPIADA EQU DPPIA1DA -DPPIACRA EQU DPPIA1CRA -DPPIADB EQU DPPIA1DB -DPPIACRB EQU DPPIA1CRB - -PIADA EQU DPPIADA+IO ; Side A Data/DDR -PIACRA EQU DPPIACRA+IO ; Side A Control. -PIADB EQU DPPIADB+IO ; Side A Data/DDR -PIACRB EQU DPPIACRB+IO ; Side A Control. - -;WD2797 Floppy disk controler, used in DragonDos. -DPCMDREG EQU DPCmdRegD ; command/status -DPTRKREG EQU DPTrkRegD ; Track register -DPSECREG EQU DPSecRegD ; Sector register -DPDATAREG EQU DPDataRegD ; Data register - -CMDREG EQU DPCMDREG+IO ; command/status -TRKREG EQU DPTRKREG+IO ; Track register -SECREG EQU DPSECREG+IO ; Sector register -DATAREG EQU DPDATAREG+IO ; Data register - -; Disk IO bitmasks - -NMIEn EQU NMIEnD -WPCEn EQU WPCEnD -SDensEn EQU SDensEnD -MotorOn EQU MotorOnD - - ENDC - -tylg set Drivr+Objct -atrv set ReEnt+rev -rev set $00 -edition set 3 - -MaxDrv set 4 - - mod eom,name,tylg,atrv,start,size - - org DrvBeg -DrvTab RMB MaxDrv*DrvMem ; Drive tables, 1 per drive -CDrvTab rmb 2 ; Pointer to current drive table entry above -DrivSel rmb 1 ; Saved drive mask -Settle rmb 1 ; Head settle time -SavePIA0CRB rmb 1 ; Saved copy of PIA0 control reg b -SaveACIACmd rmb 1 ; Saved copy of ACIA command reg -BuffPtr rmb 2 ; Buffer pointer -SideSel rmb 1 ; Side select. -Density rmb 1 ; Density 0=double, %00001000=single D64, %00100000=single Alpha - -DskError rmb 1 ; hardware disk error - -VIRQPak rmb 2 ; Vi.Cnt word for VIRQ -u00B3 rmb 2 ; Vi.Rst word for VIRQ -u00B5 rmb 1 ; Vi.Stat byte for VIRQ (drive motor timeout) - -VIRQInstalled rmb 1 ; Is VIRQ Installed yet ? -size equ . - - fcb $FF -name equ * - fcs /DDisk/ - fcb edition - -VIRQCnt fdb TkPerSec*4 Initial count for VIRQ (4 seconds) - -start lbra Init ; Initialise Driver - lbra Read ; Read sector - lbra Write ; Write sector - lbra GetStat ; Get status - lbra SetStat ; Set status - lbra Term ; Terminate device - -IRQPkt fcb $00 ; Normal bits (flip byte) - fcb $01 ; Bit 1 is interrupt request flag (Mask byte) - fcb 10 ; Priority byte - - - nop - nop - nop - lbsr ResetTrack0 -* Init -* -* Entry: -* Y = address of device descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -DragonDebug EQU 0 -Init - IFNE DragonDebug - pshs y ; This is here so I can find disk driver in mess - ldy #$AA55 ; by setting register breakpoint to y=$AA55 ! - sty $8000 - puls y - ENDC - - clra - sta >D.DskTmr ; Zero motor timer - - IFNE dalpha ; Turn off all drives - lbsr AlphaDskCtl - - lda #NMICA2Dis ; Set PIA2 CA2 as output & disable NMI - sta PIA2CRA - - ELSE - sta >DskCtl - ENDC - - ldx #CmdReg ; Reset controler - lda #FrcInt - sta ,x - lbsr Delay - lda ,x - lda #$FF - ldb #MaxDrv - leax DrvBeg,u - -InitDriveData - sta DD.Tot,x ; Set total sectors = $FF - sta <V.Trak,x ; Set current track = 0 - leax <DrvMem,x ; Skip to next drive - decb - bne InitDriveData - - leax >NMIService,pcr ; Setup NMI handler - stx >D.XNMI+1 - lda #$7E ; $7E = JMP - sta >D.XNMI - - clr VIRQInstalled,u ;flag not installed yet - - pshs y ; save device dsc. ptr - leay >u00B5,u ; point to Vi.Stat in VIRQ packet - tfr y,d ; make it the status register ptr for IRQ - leay >IRQSvc,pc ; point to IRQ service routine - leax >IRQPkt,pc ; point to IRQ packet - os9 F$IRQ ; install IRQ - puls y ; Get back device dsc. ptr - - ldd #$0100 ; Request a page of system ram - pshs u ; used to verify writes - os9 F$SRqMem - tfr u,x - puls u - bcs Return - stx >BuffPtr,u ; Save verify page pointer - clrb -Return rts - - -* GetStat -* -* Entry: -* A = function code -* Y = address of path descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -GetStat - -* Term -* -* Entry: -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -Term clrb - rts - -* 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 -* -Read - lda #$91 ; Retry count - cmpx #$0000 ; LSN ? - bne ReadDataWithRetry ; No : Just do read, - bsr ReadDataWithRetry ; Yes : do read and copy disk params - bcs ReadDataExit - ldx PD.Buf,y - pshs y,x - ldy >CDrvTab,u - ldb #DD.Siz-1 -L0082 lda b,x - sta b,y - decb - bpl L0082 - clrb - puls pc,y,x -ReadDataExit - rts - -; Read Retry - -ReadDataRetry - bcc ReadDataWithRetry ; Retry entry point - pshs x,b,a - lbsr ResetTrack0 ; Reset track 0 - puls x,b,a - -ReadDataWithRetry - pshs x,b,a ; Normal entry point - bsr DoReadData - puls x,b,a - bcc ReadDataExit - lsra ; Check for retry - bne ReadDataRetry - -DoReadData - lbsr SeekTrack - bcs ReadDataExit - ldx PD.Buf,y ; Target address for data - pshs y,dp,cc - ldb #ReadCmnd ; Read command - bsr PrepDiskRW ; Prepare disk - -DoReadDataLoop - lda <DPPIACRB ; Is data ready ? - bmi ReadDataReady ; Yes : read it - - leay -1,y - bne DoReadDataLoop - bsr RestoreSavedIO - puls y,dp,cc - lbra RetReadError ; Return read error to caller - -ReadDataWait - sync ; Sync to inturrupts, wait for data - -ReadDataReady - lda <DPDataReg ; Read data from FDC - ldb <DPPIADB ; Clear PIA inturrupt status - sta ,x+ ; save data in memory - bra ReadDataWait ; do next - -; -; Prepare to do disk read/write. -; - -PrepDiskRW - - clr DskError,u - - lda #$FF ; Make DP=$FF, to make i/o faster - tfr a,dp - -; -; Do not attempt to talk to ACIA if this machine does not have one ! -; - - IFEQ Upgraded32 - lda <DPAciaCmd ; Save ACIA Command reg - sta >SaveACIACmd,u - anda #$FE ; Disable ACIA inturrupt - sta <DPAciaCmd - bita #$40 ; Is Tx inturrupt enabled ? - beq L00DE -L00D8 lda <DPAciaStat ; Yes, wait for Tx to complete - bita #$10 - beq L00D8 - ENDC - -L00DE orcc #$50 ; Mask inturrupts - lda <DPPia0CRB ; Save PIA0 IRQ Status - sta >SavePIA0CRB,u - lda #$34 ; Disable it. - sta <DPPia0CRB - - IFEQ Upgraded32 - lda <DPACIACmd ; Disable ACIA Inturrupt - anda #$FE - sta <DPACIACmd - ENDC - - lda <DPPIACRB ; Set PIA to generate FIRQ on FDC DRQ - ora #$03 - sta <DPPIACRB - lda <DPPIADB ; Clear any outstanding inturrupt - ldy #$FFFF - - lda #NMIEn+MotorOn ; Enable NMI, and turn motor on - ora >DrivSel,u ; mask in drives - ora >Density,u ; mask in density - - ORB >SideSel,U ; Set up Side - - IFNE dalpha ; Turn on drives & NMI - lbsr AlphaDskCtl - stb <DPCmdReg ; issue command to controler - lda #NMICA2En ; Enable NMI - sta <DPPIA2CRA - ELSE - stb <DPCmdReg ; issue command to controler - sta <DPDskCtl - ENDC - - - rts - -; -; Restore saved iO states of peripherals. -; - -RestoreSavedIO - IFNE dalpha - lda #NMICA2Dis ; Disable NMI (Alpha) - sta <DPPIA2CRA - ENDC - - lda >DrivSel,u ; Deselect drives, but leave motor on - ora #MotorOn - - IFNE dalpha ; Turn off drives & NMI - lbsr AlphaDskCtl - ELSE - sta <DPDskCtl - ENDC - - lda >SavePIA0CRB,u ; Recover PIA0 state - sta <DPPia0CRB - - lda <DPPIACRB ; Disable Drive FIRQ source. - anda #$FC - sta <DPPIACRB - - IFEQ Upgraded32 - lda >SaveACIACmd,u ; Recover ACIA state - sta <DPAciaCmd - ENDC - - rts - -* Write -* -* 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 #$91 ; Retry byte -L0124 pshs x,b,a - bsr DoWrite ; Attempt to do write - puls x,b,a - bcs WriteDataRetry ; On error, retry - tst <PD.Vfy,y ; Written, should we verify ? - bne WriteDone ; no : return - lbsr WriteVerify ; yes : verify write - bcs WriteDataRetry ; verify error, retry write -WriteDone - clrb ; Return status ok - rts - -WriteDataRetry - lsra ; Retry data write - lbeq RetWriteError ; All retries exhausted ?, return error - bcc L0124 - pshs x,b,a ; Reset to track 0 - lbsr ResetTrack0 - puls x,b,a - bra L0124 - -DoWrite lbsr SeekTrack ; Seek to correct track & sector - lbcs ReadDataExit - ldx PD.Buf,y ; Get data buffer in X - pshs y,dp,cc - ldb #WritCmnd ; Write command - -WriteTrackCmd - lbsr PrepDiskRW ; Prepare for disk r/w - lda ,x+ ; get byte to write -L015A ldb <DPPIACRB ; Ready to write ? - bmi WriteDataReady ; Yes, do it. - leay -1,y - bne L015A - bsr RestoreSavedIO ; Restore saved peripheral states - puls y,dp,cc - lbra RetWriteError ; Return write error - -WriteDataWait - lda ,x+ ; Get next byte to write - sync ; Wait for drive -WriteDataReady - sta <DPDataReg ; Write data to FDC - ldb <DPPIADB ; Clear pending FDC inturrupt - bra WriteDataWait - - -; -; NMI Handler code. -; - -NMIService - leas R$Size,s ; Drop regs from stack - bsr RestoreSavedIO ; Restore saved IO states - puls y,dp,cc - ldb >CmdReg - - stb DskError,u - - bitb #LostMask ; check for lost record - lbne RetReadError ; yes : return read error - lbra TestForError ; esle test for other errors - -; Verify a written sector. -WriteVerify - pshs x,b,a - ldx PD.Buf,y ; Swap buffer pointers - pshs x - ldx >BuffPtr,u - stx PD.Buf,y - ldx 4,s - lbsr DoReadData ; Read data back in - puls x - stx PD.Buf,y ; Swab buffer pointers back - bcs VerifyEnd - lda #$20 - pshs u,y,a - ldy >BuffPtr,u - tfr x,u -VerifyLoop - ldx ,u ; Compare every 4th word - cmpx ,y - bne VerifyErrorEnd - leau 8,u - leay 8,y ; Increment pointers - dec ,s - bne VerifyLoop - bra VerifyEndOk ; Verify succeeded. -VerifyErrorEnd - orcc #Carry ; Flag error -VerifyEndOk - puls u,y,a -VerifyEnd - puls pc,x,b,a -; -; Seek to a track -; -SeekTrack - CLR >Settle,U ; default no settle - LBSR SelectDrive ; select and start correct drive - TSTB - BNE E.Sect - - TFR X,D - LDX >CDrvTab,U - CMPD #0 ; Skip calculation of track 0 - BEQ SeekT1 - CMPD DD.TOT+1,X ; Has an illegal LSN been - BLO SeekT2 -E.Sect COMB - LDB #E$Sect - RTS - -SeekT2 CLR ,-S ; Calculate track number - SUBD PD.T0S,Y ; subtract no. of sectors in track 0 - BHS SeekT4 - ADDD PD.T0S,Y ; if -ve we are on track 0, so add back on again - BRA SeekT3 -SeekT4 INC ,S - SUBD DD.Spt,X ; sectors per track for rest of disk - BHS SeekT4 ; repeat, until -ve, incrementing track count - ADDD DD.Spt,X ; re add sectors/track to get sector number on track - -; At this point the byte on the top of the stack contains the track -; number, and B contains the sector number on that track. - -SeekT3 PULS A ; retrieve track count - LBSR SetWPC ; set write precompensation - LBSR SetDensity ; Set density - PSHS B - LDB DD.Fmt,X ; Is the media double sided ? - LSRB - BCC SingleSidedDisk ; skip if not - LDB PD.Sid,Y ; Is the drive double sided ? - DECB - BNE SetupSideMask ; yes : deal with it. - PULS B ; No then its an error - COMB - LDB #E$BTyp - RTS - -SetupSideMask - BSR SetSide ; Media & drive are double sided - BRA SeekT9 - -SingleSidedDisk - clr >SideSel,U ; Single sided, make sure sidesel set correctly - BRA SeekT9 - -SeekT1 LBSR SetDensity ; make sure density set correctly even for LSN0 ! - - clr >SideSel,U ; make sure sidesel is always 0 if lsn0 - PSHS B -SeekT9 LDB PD.Typ,Y ; Dragon and Coco disks - BITB #TYP.CCF ; count sectors from 1 no - BEQ SeekT8 - PULS B - INCB ; so increment sector number - BRA SeekT11 -SeekT8 PULS B ; Count from 0 for other types - -SeekT11 STB >SecReg ; Write sector number to controler - LBSR Delay - CMPB >SecReg - BNE SeekT11 - -SeekTS LDB <V.Trak,X ; Entry point for SS.WTrk command - STB >TrkReg - TST >Settle,U ; If settle has been flagged then wait for settle - BNE SeekT5 - CMPA <V.Trak,X ; otherwise check if this is - BEQ SeekT6 ; track number to the last - -SeekT5 STA <V.Trak,X ; Do the seek - STA >DataReg ; Write track no to controler - bsr GetStepInB ; get step rate - ORB #SeekCmnd ; add seek command - LBSR FDCCommand - PSHS X - LDX #$222E ; Wait for head to settle -SeekT7 LEAX -1,X - BNE SeekT7 - PULS X - -SeekT6 CLRB ; return no error to caller - RTS - -; -; Get step rate in bottom 2 bits of B -; -GetStepInB - ldb PD.Stp,Y ; Set Step Rate according to Parameter block - andb #%00000011 ; mask in only step rate bits - eorb #%00000011 ; flip bits to make correct encoding - rts - -; Set Side2 Mask -; A contains the track number on entry -SetSide LSRA ; Get bit 0 into carry & devide track no by 2 - PSHS A - BCC Side0 ; Side 0 if even track no. - LDA #Sid2Sel ; Odd track no. so side 2 - BRA Side -Side0 CLRA -Side STA >SideSel,U - PULS A,PC - -; -; Select drive and start drive motors. -; On entry A=drive number. -; - -SelectDrive - lbsr StartMotor ; Start motor - lda <PD.Drv,y ; Check it's a valid drive - cmpa #MaxDrv - bcs SelectDriveValid ; yes : continue - -RetErrorBadUnit - comb ; Return bad unit error - ldb #E$Unit - rts - -SelectDriveValid - pshs x,b,a ; Unit valid so slect it - sta >DrivSel,u ; Get DD table address - leax DrvBeg,u ; Calculate offset into table - ldb #DrvMem - mul - leax d,x - cmpx >CDrvTab,u - beq SelectDriveEnd - stx >CDrvTab,u ; Force seek if different drive - com >Settle,u -SelectDriveEnd - puls pc,x,b,a - -; -; Analise device status return. -; - -TestForError - bitb #ErrMask - beq TestErrorEnd - bitb #NotRMask ; not ready - bne RetErrorNotReady - bitb #WPMask ; Write protect - bne RetErrorWP - bitb #RTypMask ; Wrong type ? - bne RetWriteError - bitb #RNFMask ; Record Not found - bne RetErrorSeek - bitb #CRCMask - bne RetErrorCRC -TestErrorEnd - clrb - rts -; -; Return error code -; - -RetErrorNotReady - comb - ldb #E$NotRdy - rts -RetErrorWP - comb - ldb #E$WP - rts -RetWriteError - comb - ldb #E$Write - rts -RetErrorSeek - comb - ldb #E$Seek - rts -RetErrorCRC - comb - ldb #E$CRC - rts -RetReadError - comb - ldb #E$Read - rts -; -; Issue a command to FDC and wait till it's ready -; - -FDCCommand - bsr FDCCmd -FDCCmdWait - ldb >CmdReg ; Poll until not busy - bitb #$01 - beq Delay3 - bra FDCCmdWait - -FDCCmdMotorOn - lda #MotorOn ; Turn on motor - ora >DrivSel,u - - IFNE dalpha - lbsr AlphaDskCtl - ELSE - sta >DskCtl - ENDC - - bsr SetupVIRQ - - stb >CmdReg ; Send Command to FDC - rts - -SetupVIRQ - pshs D - ldd >VIRQCnt,pc ; Get VIRQ initial count value - std >VIRQPak,u ; Save it - lda VIRQInstalled,u ; Installed yet ? - beq DoInsVIRQ ; Not installed yet, try installing it -SetupVIRQExit - PULS D - rts - -DoInsVIRQ - bsr InsVIRQ - bra SetupVIRQExit - -InsVIRQ pshs D,y,x - lda #$01 ; Flag drive motor is up to speed - IFEQ Level-1 - sta >D.DskTmr - ELSE - sta <D.MotOn - ENDC - - ldx #$0001 ; Install VIRQ entry - leay >VIRQPak,u ; Point to packet - clr Vi.Stat,y ; Reset Status byte - ldd >VIRQCnt,pc ; Get initial VIRQ count value - os9 F$VIRQ ; Install VIRQ - bcs VIRQOut ; Error, exit - inc VIRQInstalled,u ; Flag it's installed -VIRQOut puls X,Y,D - rts - -* IRQ service routine for VIRQ (drive motor time) -* Entry: U=Ptr to VIRQ memory area -IRQSvc pshs a - lda <D.DMAReq - beq L0509 - bsr InsVIRQ - bra IRQOut -L0509 - IFNE dalpha - lbsr AlphaDskCtl - ELSE - sta >DskCtl - ENDC - - clr u00B5,u - clr VIRQInstalled,u - IFEQ Level-1 - clr >D.DskTmr - ELSE - clr <D.MotOn - ENDC -IRQOut puls pc,a - - -FDCCmd - bsr FDCCmdMotorOn - -; Delay routine ! -Delay lbsr Delay2 -Delay2 lbsr Delay3 -Delay3 rts - -* SetStat -* -* Entry: -* A = function code -* Y = address of path descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -SetStat - ldx PD.Rgs,y ; Retrieve request - ldb R$B,x - - cmpb #SS.Reset ; Restore to track 0. - beq ResetTrack0 - cmpb #SS.Wtrk ; Write (format) a track - beq DoWriteTrack - comb - ldb #E$UnkSvc -SetStatEnd - rts -; -; Write (format) a track -; - -DoWriteTrack - - lbsr SelectDrive ; Select drive - lda R$Y+1,x - LBSR SetSide ; Set Side 2 if appropriate - LDA R$U+1,X - BSR SetWPC ; Set WPC by disk type - bsr SetDensity ; Set density - -;L02D5 - ldx >CDrvTab,u - lbsr SeekTS ; Move to correct track - bcs SetStatEnd - - ldx PD.Rgs,y - ldx R$X,x - ldb #WtTkCmnd - pshs y,dp,cc - lbra WriteTrackCmd - -; Reset track 0 -ResetTrack0 - lbsr SelectDrive ; Select drive - ldx >CDrvTab,u - clr <V.Trak,x ; Set current track as 0 - lda #$05 - -ResetTrack0Loop - lbsr GetStepInB ; Get step rate for this drive - orb #StpICmnd ; Step away from track 0 5 times - pshs a - lbsr FDCCommand - puls a - deca - bne ResetTrack0Loop - - lbsr GetStepInB ; Get step rate for this drive - orb #RestCmnd ; Now issue a restore - lbra FDCCommand -; -;Start drive motors -; - -StartMotor - pshs x,b,a - lda >D.DskTmr ; if timer <> 0 then skip as motor already on - bne MotorsRunning - lda #MotorOn ; else spin up - - IFNE dalpha - bsr AlphaDskCtl - ELSE - sta >DskCtl - ENDC - - ldx #$A000 ; Wait a little while for motors to get up to speed -StartMotorLoop - nop - nop - leax -1,x - bne StartMotorLoop - -MotorsRunning - lbsr SetupVIRQ -; lda #$F0 ; Start external motor timer -; sta >D.DskTmr ; external to driver - puls pc,x,b,a - -; -; Set Write Precompensation according to media type -; -; Entry : -; A = Track no - -SetWPC PSHS A,B - LDB PD.DNS,Y - BITB #T80Mask ; Is it 96 tpi drive - BNE SetWP1 - ASLA ; no then double -SetWP1 CMPA #32 ; WPC needed ? - BLS SetWP2 - LDA >DrivSel,U - ORA #WPCEn - STA >DrivSel,U -SetWP2 PULS A,B,PC - - -; -; Set density acording to disk type. -; -; Entry A = Track no -; - -SetDensity - PSHS A,B - ldb PD.TYP,Y ; Dragon/CoCo disk ? - bitb #TYP.CCF - bne SetDouble ; Always double density - - LDB PD.DNS,Y ; Get density flags from Path descriptor - - bitb #DNS.MFM ; Disk is MFM ? - beq SetSingle ; no : set single density - - cmpa #0 ; track 0 ? - bne SetDouble ; not track 0, exit - - tst SideSel,u ; is this side 0 ? - bne SetDouble ; no : use double density - - bitb #DNS.MFM0 ; track 0 mfm ? - bne SetDouble - -SetSingle - lda #SDensEn ; flag single density - sta Density,u - bra ExitDensity - -SetDouble - clr Density,u ; flag double density - -ExitDensity - puls a,b,pc - - IFNE dalpha - -; Translate DragonDos Drive select mechinisim to work on Alpha -; Takes byte that would be output to $FF48, reformats it and -; outputs to Alpha AY-8912's IO port, which is connected to -; Drive selects, motor on and enable precomp. -; This code now expects Alpha NMI/DDEN etc codes, as defined -; at top of this file (and dgndefs). The exception to this is -; the drive number is still passed in the bottom 2 bits and -; converted with a lookup table. -; We do not need to preserve the ROM select bit as this code -; operates in RAM only mode. - -ADrvTab FCB Drive0A,Drive1A,Drive2A,Drive3A - -AlphaDskCtl - PSHS x,A,B,CC - - PSHS A - anda #DDosDriveMask ; mask out dragondos format drive number - leax ADrvTab,pcr ; point at table - lda a,x ; get bitmap - ldb ,s - andb #AlphaCtrlMask ; mask out drive number bits - stb ,s - ora ,s ; recombine drive no & ctrl bits -; sta ,s - - bita #MotorOn ; test motor on ? - bne MotorRunning - - clra ; No, turn off other bits. -MotorRunning - anda #Mask58 ; Mask out 5/8 bit to force the use of 5.25" clock - sta ,s - - orcc #$50 ; disable inturrupts - - lda #AYIOREG ; AY-8912 IO register - sta PIA2DB ; Output to PIA - ldb #AYREGLatch ; Latch register to modify - stb PIA2DA - - clr PIA2DA ; Idle AY - - lda ,s+ ; Fetch saved Drive Selects etc - sta PIA2DB ; output to PIA - ldb #AYWriteReg ; Write value to latched register - stb PIA2DA ; Set register - - clr PIA2DA ; Idle AY - - PULS x,A,B,CC - RTS - - ENDC - - - emod -eom equ * - end +******************************************************************** +* DDisk - Dragon Floppy driver +* +* $Id$ +* +* Edt/Rev YYYY/MM/DD Modified by +* Comment +* ------------------------------------------------------------------ +* - ????/??/?? +* Original Dragon Data distribution version +* +* Added Defines for IO ports. +* 2004/11/09, P.Harvey-Smith +* +* Dragon Alpha code, 2004-11-09, P.Harvey-Smith. +* I am not sure of how to disable NMI on the Alpha, it is +* simulated in software using the NMIFlag. +* +* The Dragon Alpha/Professional uses the same FDC chip as +* DragonDos, however it is mapped between FF2C and FF2F, +* also the register order is REVERSED, so command/status is at +* FF2F. +* +* Drive Selects, motor and write precompensation is controled +* through the IO port of an AY-8912, which itself is connected +* to a 3rd PIA mapped at FF24 to FF27, this PIA also has it's +* inturrupt lines connected to the CPU's FIRQ. +* +* 2004-11-15, P.Harvey-Smith. +* Fixed bug in inturrupt handling code that was making the +* Dragon Alpha crash if a disk was accessed with no disk +* in the drive. As the Alpha is using a simulated NMI disable +* we have to ensure that the NMI enabling routine has completed +* BEFORE isuing a command to the disk controler, or if the +* inturrupt happens in the middle of the enable routine it +* causes the machine to crash ! +* +* 2004-11-24, P.Harvey-Smith. +* Fixed up so that double sided disks now work, origional +* double sided code taken from Jon Bird's pages at : +* http://www.onastick.clara.net/dragon.html and modified +* for NitrOS9. +* +* 2004-11-27, P.Harvey-Smith. +* Reformatted with tab=8. +* +* 2005-04-22, P.Harvey-Smith. +* Hopefully fixed a bug that was causing the Dragon 64 target to +* crash and burn when reading disks, this made a successfull boot +* almost imposible ! Fixed by writing disk command before writing +* disc control register, the Alpha target needs them the other way +* around. Still has a problem doing lots of retries. +* +* 2005-04-24, P.Harvey-Smith. +* Fixed constant lost data errors reading disks, again by slightly +* re-ordering the instructions in the read data loop. +* +* 2005-04-24, P.Harvey-Smith. +* Removed debugging code/messages. +* +* 2005-05-31, P.Harvey-Smith. +* Added ability to read, write and format standard OS-9 format disks +* including single denity, and disks with track 0 single denisity, but +* all other tracks double density. +* +* Added code to make step rates work as on the rb1773 driver, they where +* previously working back to front. +* +* 2005-06-06, P.Harvey-Smith. +* Verified as working on a real Alpha, by Richard Harding. +* +* 2005-06-16, P.Harvey-Smith. +* Added NMI enable/disable code, as I know know how to enable/disable +* NMI on the Alpha, having disasembled the Alpha's OS9's ddisk. +* +* 2005-06-17, P.Harvey-Smith. +* Ok, this'll teach me to submit code before testing on the real hardware ! +* Seperated NMI disable/drive select code on alpha, as above patches +* worked fine on Mess, but not on real hardware (timing problems). +* +* 2006-01-08, P.Harvey-Smith. +* Added support for Dragon 32, that has had a memory upgraded to 64K, +* this is treated like the Dragon 64 EXCEPT that the code to manipulate +* the ACIA is not included. This is required due to the incomplete +* address decoding, writes to the non-existant ACIA would hit the PIA +* at FF00, and cause a crash. +* +* 2006-01-08, P.Harvey-Smith. +* Since I now have a genuine Dragon 5.25" drive, found that nitros format +* fell over accessing it, this was due to the step rate not being set +* correctly in the drive recalibrate routine, I ahve corrected this to +* use the value in the descriptor. +* + + nam DDisk + ttl Dragon Floppy driver + +* Disassembled 02/04/21 22:37:46 by Disasm v1.6 (C) 1988 by RML + + ifp1 + use defsfile + endc + + IFNE dalpha + +* Dragon Alpha has a third PIA at FF24, this is used for +* Drive select / motor control, and provides FIRQ from the +* disk controler. + +DPPIADA EQU DPPIA2DA +DPPIACRA EQU DPPIA2CRA +DPPIADB EQU DPPIA2DB +DPPIACRB EQU DPPIA2CRB + +PIADA EQU DPPIADA+IO ; Side A Data/DDR +PIACRA EQU DPPIACRA+IO ; Side A Control. +PIADB EQU DPPIADB+IO ; Side A Data/DDR +PIACRB EQU DPPIACRB+IO ; Side A Control. + +;WD2797 Floppy disk controler, used in Alpha Note registers in reverse order ! +DPCMDREG EQU DPCmdRegA ; command/status +DPTRKREG EQU DPTrkRegA ; Track register +DPSECREG EQU DPSecRegA ; Sector register +DPDATAREG EQU DPDataRegA ; Data register + +CMDREG EQU DPCMDREG+IO ; command/status +TRKREG EQU DPTRKREG+IO ; Track register +SECREG EQU DPSECREG+IO ; Sector register +DATAREG EQU DPDATAREG+IO ; Data register + +; Disk IO bitmasks + +NMIEn EQU NMIEnA +WPCEn EQU WPCEnA +SDensEn EQU SDensEnA +MotorOn EQU MotorOnA + +; These are the bits that we know the function of on the Alpha interface +KnownBits EQU Drive0A+Drive1A+Drive2A+Drive3A+MotorOnA+SDensEnA+WPCEnA + + ELSE + +DPPIADA EQU DPPIA1DA +DPPIACRA EQU DPPIA1CRA +DPPIADB EQU DPPIA1DB +DPPIACRB EQU DPPIA1CRB + +PIADA EQU DPPIADA+IO ; Side A Data/DDR +PIACRA EQU DPPIACRA+IO ; Side A Control. +PIADB EQU DPPIADB+IO ; Side A Data/DDR +PIACRB EQU DPPIACRB+IO ; Side A Control. + +;WD2797 Floppy disk controler, used in DragonDos. +DPCMDREG EQU DPCmdRegD ; command/status +DPTRKREG EQU DPTrkRegD ; Track register +DPSECREG EQU DPSecRegD ; Sector register +DPDATAREG EQU DPDataRegD ; Data register + +CMDREG EQU DPCMDREG+IO ; command/status +TRKREG EQU DPTRKREG+IO ; Track register +SECREG EQU DPSECREG+IO ; Sector register +DATAREG EQU DPDATAREG+IO ; Data register + +; Disk IO bitmasks + +NMIEn EQU NMIEnD +WPCEn EQU WPCEnD +SDensEn EQU SDensEnD +MotorOn EQU MotorOnD + + ENDC + +tylg set Drivr+Objct +atrv set ReEnt+rev +rev set $00 +edition set 3 + +MaxDrv set 4 + + mod eom,name,tylg,atrv,start,size + + org DrvBeg +DrvTab RMB MaxDrv*DrvMem ; Drive tables, 1 per drive +CDrvTab rmb 2 ; Pointer to current drive table entry above +DrivSel rmb 1 ; Saved drive mask +Settle rmb 1 ; Head settle time +SavePIA0CRB rmb 1 ; Saved copy of PIA0 control reg b +SaveACIACmd rmb 1 ; Saved copy of ACIA command reg +BuffPtr rmb 2 ; Buffer pointer +SideSel rmb 1 ; Side select. +Density rmb 1 ; Density 0=double, %00001000=single D64, %00100000=single Alpha + +DskError rmb 1 ; hardware disk error + +VIRQPak rmb 2 ; Vi.Cnt word for VIRQ +u00B3 rmb 2 ; Vi.Rst word for VIRQ +u00B5 rmb 1 ; Vi.Stat byte for VIRQ (drive motor timeout) + +VIRQInstalled rmb 1 ; Is VIRQ Installed yet ? +size equ . + + fcb $FF +name equ * + fcs /DDisk/ + fcb edition + +VIRQCnt fdb TkPerSec*4 Initial count for VIRQ (4 seconds) + +start lbra Init ; Initialise Driver + lbra Read ; Read sector + lbra Write ; Write sector + lbra GetStat ; Get status + lbra SetStat ; Set status + lbra Term ; Terminate device + +IRQPkt fcb $00 ; Normal bits (flip byte) + fcb $01 ; Bit 1 is interrupt request flag (Mask byte) + fcb 10 ; Priority byte + + + nop + nop + nop + lbsr ResetTrack0 +* Init +* +* Entry: +* Y = address of device descriptor +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +DragonDebug EQU 0 +Init + IFNE DragonDebug + pshs y ; This is here so I can find disk driver in mess + ldy #$AA55 ; by setting register breakpoint to y=$AA55 ! + sty $8000 + puls y + ENDC + + clra + sta >D.DskTmr ; Zero motor timer + + IFNE dalpha ; Turn off all drives + lbsr AlphaDskCtl + + lda #NMICA2Dis ; Set PIA2 CA2 as output & disable NMI + sta PIA2CRA + + ELSE + sta >DskCtl + ENDC + + ldx #CmdReg ; Reset controler + lda #FrcInt + sta ,x + lbsr Delay + lda ,x + lda #$FF + ldb #MaxDrv + leax DrvBeg,u + +InitDriveData + sta DD.Tot,x ; Set total sectors = $FF + sta <V.Trak,x ; Set current track = 0 + leax <DrvMem,x ; Skip to next drive + decb + bne InitDriveData + + leax >NMIService,pcr ; Setup NMI handler + stx >D.XNMI+1 + lda #$7E ; $7E = JMP + sta >D.XNMI + + clr VIRQInstalled,u ;flag not installed yet + + pshs y ; save device dsc. ptr + leay >u00B5,u ; point to Vi.Stat in VIRQ packet + tfr y,d ; make it the status register ptr for IRQ + leay >IRQSvc,pc ; point to IRQ service routine + leax >IRQPkt,pc ; point to IRQ packet + os9 F$IRQ ; install IRQ + puls y ; Get back device dsc. ptr + + ldd #$0100 ; Request a page of system ram + pshs u ; used to verify writes + os9 F$SRqMem + tfr u,x + puls u + bcs Return + stx >BuffPtr,u ; Save verify page pointer + clrb +Return rts + + +* GetStat +* +* Entry: +* A = function code +* Y = address of path descriptor +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +GetStat + +* Term +* +* Entry: +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +Term clrb + rts + +* 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 +* +Read + lda #$91 ; Retry count + cmpx #$0000 ; LSN ? + bne ReadDataWithRetry ; No : Just do read, + bsr ReadDataWithRetry ; Yes : do read and copy disk params + bcs ReadDataExit + ldx PD.Buf,y + pshs y,x + ldy >CDrvTab,u + ldb #DD.Siz-1 +L0082 lda b,x + sta b,y + decb + bpl L0082 + clrb + puls pc,y,x +ReadDataExit + rts + +; Read Retry + +ReadDataRetry + bcc ReadDataWithRetry ; Retry entry point + pshs x,b,a + lbsr ResetTrack0 ; Reset track 0 + puls x,b,a + +ReadDataWithRetry + pshs x,b,a ; Normal entry point + bsr DoReadData + puls x,b,a + bcc ReadDataExit + lsra ; Check for retry + bne ReadDataRetry + +DoReadData + lbsr SeekTrack + bcs ReadDataExit + ldx PD.Buf,y ; Target address for data + pshs y,dp,cc + ldb #ReadCmnd ; Read command + bsr PrepDiskRW ; Prepare disk + +DoReadDataLoop + lda <DPPIACRB ; Is data ready ? + bmi ReadDataReady ; Yes : read it + + leay -1,y + bne DoReadDataLoop + bsr RestoreSavedIO + puls y,dp,cc + lbra RetReadError ; Return read error to caller + +ReadDataWait + sync ; Sync to inturrupts, wait for data + +ReadDataReady + lda <DPDataReg ; Read data from FDC + ldb <DPPIADB ; Clear PIA inturrupt status + sta ,x+ ; save data in memory + bra ReadDataWait ; do next + +; +; Prepare to do disk read/write. +; + +PrepDiskRW + + clr DskError,u + + lda #$FF ; Make DP=$FF, to make i/o faster + tfr a,dp + +; +; Do not attempt to talk to ACIA if this machine does not have one ! +; + + IFEQ Upgraded32 + lda <DPAciaCmd ; Save ACIA Command reg + sta >SaveACIACmd,u + anda #$FE ; Disable ACIA inturrupt + sta <DPAciaCmd + bita #$40 ; Is Tx inturrupt enabled ? + beq L00DE +L00D8 lda <DPAciaStat ; Yes, wait for Tx to complete + bita #$10 + beq L00D8 + ENDC + +L00DE orcc #$50 ; Mask inturrupts + lda <DPPia0CRB ; Save PIA0 IRQ Status + sta >SavePIA0CRB,u + lda #$34 ; Disable it. + sta <DPPia0CRB + + IFEQ Upgraded32 + lda <DPACIACmd ; Disable ACIA Inturrupt + anda #$FE + sta <DPACIACmd + ENDC + + lda <DPPIACRB ; Set PIA to generate FIRQ on FDC DRQ + ora #$03 + sta <DPPIACRB + lda <DPPIADB ; Clear any outstanding inturrupt + ldy #$FFFF + + lda #NMIEn+MotorOn ; Enable NMI, and turn motor on + ora >DrivSel,u ; mask in drives + ora >Density,u ; mask in density + + ORB >SideSel,U ; Set up Side + + IFNE dalpha ; Turn on drives & NMI + lbsr AlphaDskCtl + stb <DPCmdReg ; issue command to controler + lda #NMICA2En ; Enable NMI + sta <DPPIA2CRA + ELSE + stb <DPCmdReg ; issue command to controler + sta <DPDskCtl + ENDC + + + rts + +; +; Restore saved iO states of peripherals. +; + +RestoreSavedIO + IFNE dalpha + lda #NMICA2Dis ; Disable NMI (Alpha) + sta <DPPIA2CRA + ENDC + + lda >DrivSel,u ; Deselect drives, but leave motor on + ora #MotorOn + + IFNE dalpha ; Turn off drives & NMI + lbsr AlphaDskCtl + ELSE + sta <DPDskCtl + ENDC + + lda >SavePIA0CRB,u ; Recover PIA0 state + sta <DPPia0CRB + + lda <DPPIACRB ; Disable Drive FIRQ source. + anda #$FC + sta <DPPIACRB + + IFEQ Upgraded32 + lda >SaveACIACmd,u ; Recover ACIA state + sta <DPAciaCmd + ENDC + + rts + +* Write +* +* 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 #$91 ; Retry byte +L0124 pshs x,b,a + bsr DoWrite ; Attempt to do write + puls x,b,a + bcs WriteDataRetry ; On error, retry + tst <PD.Vfy,y ; Written, should we verify ? + bne WriteDone ; no : return + lbsr WriteVerify ; yes : verify write + bcs WriteDataRetry ; verify error, retry write +WriteDone + clrb ; Return status ok + rts + +WriteDataRetry + lsra ; Retry data write + lbeq RetWriteError ; All retries exhausted ?, return error + bcc L0124 + pshs x,b,a ; Reset to track 0 + lbsr ResetTrack0 + puls x,b,a + bra L0124 + +DoWrite lbsr SeekTrack ; Seek to correct track & sector + lbcs ReadDataExit + ldx PD.Buf,y ; Get data buffer in X + pshs y,dp,cc + ldb #WritCmnd ; Write command + +WriteTrackCmd + lbsr PrepDiskRW ; Prepare for disk r/w + lda ,x+ ; get byte to write +L015A ldb <DPPIACRB ; Ready to write ? + bmi WriteDataReady ; Yes, do it. + leay -1,y + bne L015A + bsr RestoreSavedIO ; Restore saved peripheral states + puls y,dp,cc + lbra RetWriteError ; Return write error + +WriteDataWait + lda ,x+ ; Get next byte to write + sync ; Wait for drive +WriteDataReady + sta <DPDataReg ; Write data to FDC + ldb <DPPIADB ; Clear pending FDC inturrupt + bra WriteDataWait + + +; +; NMI Handler code. +; + +NMIService + leas R$Size,s ; Drop regs from stack + bsr RestoreSavedIO ; Restore saved IO states + puls y,dp,cc + ldb >CmdReg + + stb DskError,u + + bitb #LostMask ; check for lost record + lbne RetReadError ; yes : return read error + lbra TestForError ; esle test for other errors + +; Verify a written sector. +WriteVerify + pshs x,b,a + ldx PD.Buf,y ; Swap buffer pointers + pshs x + ldx >BuffPtr,u + stx PD.Buf,y + ldx 4,s + lbsr DoReadData ; Read data back in + puls x + stx PD.Buf,y ; Swab buffer pointers back + bcs VerifyEnd + lda #$20 + pshs u,y,a + ldy >BuffPtr,u + tfr x,u +VerifyLoop + ldx ,u ; Compare every 4th word + cmpx ,y + bne VerifyErrorEnd + leau 8,u + leay 8,y ; Increment pointers + dec ,s + bne VerifyLoop + bra VerifyEndOk ; Verify succeeded. +VerifyErrorEnd + orcc #Carry ; Flag error +VerifyEndOk + puls u,y,a +VerifyEnd + puls pc,x,b,a +; +; Seek to a track +; +SeekTrack + CLR >Settle,U ; default no settle + LBSR SelectDrive ; select and start correct drive + TSTB + BNE E.Sect + + TFR X,D + LDX >CDrvTab,U + CMPD #0 ; Skip calculation of track 0 + BEQ SeekT1 + CMPD DD.TOT+1,X ; Has an illegal LSN been + BLO SeekT2 +E.Sect COMB + LDB #E$Sect + RTS + +SeekT2 CLR ,-S ; Calculate track number + SUBD PD.T0S,Y ; subtract no. of sectors in track 0 + BHS SeekT4 + ADDD PD.T0S,Y ; if -ve we are on track 0, so add back on again + BRA SeekT3 +SeekT4 INC ,S + SUBD DD.Spt,X ; sectors per track for rest of disk + BHS SeekT4 ; repeat, until -ve, incrementing track count + ADDD DD.Spt,X ; re add sectors/track to get sector number on track + +; At this point the byte on the top of the stack contains the track +; number, and B contains the sector number on that track. + +SeekT3 PULS A ; retrieve track count + LBSR SetWPC ; set write precompensation + LBSR SetDensity ; Set density + PSHS B + LDB DD.Fmt,X ; Is the media double sided ? + LSRB + BCC SingleSidedDisk ; skip if not + LDB PD.Sid,Y ; Is the drive double sided ? + DECB + BNE SetupSideMask ; yes : deal with it. + PULS B ; No then its an error + COMB + LDB #E$BTyp + RTS + +SetupSideMask + BSR SetSide ; Media & drive are double sided + BRA SeekT9 + +SingleSidedDisk + clr >SideSel,U ; Single sided, make sure sidesel set correctly + BRA SeekT9 + +SeekT1 LBSR SetDensity ; make sure density set correctly even for LSN0 ! + + clr >SideSel,U ; make sure sidesel is always 0 if lsn0 + PSHS B +SeekT9 LDB PD.Typ,Y ; Dragon and Coco disks + BITB #TYP.CCF ; count sectors from 1 no + BEQ SeekT8 + PULS B + INCB ; so increment sector number + BRA SeekT11 +SeekT8 PULS B ; Count from 0 for other types + +SeekT11 STB >SecReg ; Write sector number to controler + LBSR Delay + CMPB >SecReg + BNE SeekT11 + +SeekTS LDB <V.Trak,X ; Entry point for SS.WTrk command + STB >TrkReg + TST >Settle,U ; If settle has been flagged then wait for settle + BNE SeekT5 + CMPA <V.Trak,X ; otherwise check if this is + BEQ SeekT6 ; track number to the last + +SeekT5 STA <V.Trak,X ; Do the seek + STA >DataReg ; Write track no to controler + bsr GetStepInB ; get step rate + ORB #SeekCmnd ; add seek command + LBSR FDCCommand + PSHS X + LDX #$222E ; Wait for head to settle +SeekT7 LEAX -1,X + BNE SeekT7 + PULS X + +SeekT6 CLRB ; return no error to caller + RTS + +; +; Get step rate in bottom 2 bits of B +; +GetStepInB + ldb PD.Stp,Y ; Set Step Rate according to Parameter block + andb #%00000011 ; mask in only step rate bits + eorb #%00000011 ; flip bits to make correct encoding + rts + +; Set Side2 Mask +; A contains the track number on entry +SetSide LSRA ; Get bit 0 into carry & devide track no by 2 + PSHS A + BCC Side0 ; Side 0 if even track no. + LDA #Sid2Sel ; Odd track no. so side 2 + BRA Side +Side0 CLRA +Side STA >SideSel,U + PULS A,PC + +; +; Select drive and start drive motors. +; On entry A=drive number. +; + +SelectDrive + lbsr StartMotor ; Start motor + lda <PD.Drv,y ; Check it's a valid drive + cmpa #MaxDrv + bcs SelectDriveValid ; yes : continue + +RetErrorBadUnit + comb ; Return bad unit error + ldb #E$Unit + rts + +SelectDriveValid + pshs x,b,a ; Unit valid so slect it + sta >DrivSel,u ; Get DD table address + leax DrvBeg,u ; Calculate offset into table + ldb #DrvMem + mul + leax d,x + cmpx >CDrvTab,u + beq SelectDriveEnd + stx >CDrvTab,u ; Force seek if different drive + com >Settle,u +SelectDriveEnd + puls pc,x,b,a + +; +; Analise device status return. +; + +TestForError + bitb #ErrMask + beq TestErrorEnd + bitb #NotRMask ; not ready + bne RetErrorNotReady + bitb #WPMask ; Write protect + bne RetErrorWP + bitb #RTypMask ; Wrong type ? + bne RetWriteError + bitb #RNFMask ; Record Not found + bne RetErrorSeek + bitb #CRCMask + bne RetErrorCRC +TestErrorEnd + clrb + rts +; +; Return error code +; + +RetErrorNotReady + comb + ldb #E$NotRdy + rts +RetErrorWP + comb + ldb #E$WP + rts +RetWriteError + comb + ldb #E$Write + rts +RetErrorSeek + comb + ldb #E$Seek + rts +RetErrorCRC + comb + ldb #E$CRC + rts +RetReadError + comb + ldb #E$Read + rts +; +; Issue a command to FDC and wait till it's ready +; + +FDCCommand + bsr FDCCmd +FDCCmdWait + ldb >CmdReg ; Poll until not busy + bitb #$01 + beq Delay3 + bra FDCCmdWait + +FDCCmdMotorOn + lda #MotorOn ; Turn on motor + ora >DrivSel,u + + IFNE dalpha + lbsr AlphaDskCtl + ELSE + sta >DskCtl + ENDC + + bsr SetupVIRQ + + stb >CmdReg ; Send Command to FDC + rts + +SetupVIRQ + pshs D + ldd >VIRQCnt,pc ; Get VIRQ initial count value + std >VIRQPak,u ; Save it + lda VIRQInstalled,u ; Installed yet ? + beq DoInsVIRQ ; Not installed yet, try installing it +SetupVIRQExit + PULS D + rts + +DoInsVIRQ + bsr InsVIRQ + bra SetupVIRQExit + +InsVIRQ pshs D,y,x + lda #$01 ; Flag drive motor is up to speed + IFEQ Level-1 + sta >D.DskTmr + ELSE + sta <D.MotOn + ENDC + + ldx #$0001 ; Install VIRQ entry + leay >VIRQPak,u ; Point to packet + clr Vi.Stat,y ; Reset Status byte + ldd >VIRQCnt,pc ; Get initial VIRQ count value + os9 F$VIRQ ; Install VIRQ + bcs VIRQOut ; Error, exit + inc VIRQInstalled,u ; Flag it's installed +VIRQOut puls X,Y,D + rts + +* IRQ service routine for VIRQ (drive motor time) +* Entry: U=Ptr to VIRQ memory area +IRQSvc pshs a + lda <D.DMAReq + beq L0509 + bsr InsVIRQ + bra IRQOut +L0509 + IFNE dalpha + lbsr AlphaDskCtl + ELSE + sta >DskCtl + ENDC + + clr u00B5,u + clr VIRQInstalled,u + IFEQ Level-1 + clr >D.DskTmr + ELSE + clr <D.MotOn + ENDC +IRQOut puls pc,a + + +FDCCmd + bsr FDCCmdMotorOn + +; Delay routine ! +Delay lbsr Delay2 +Delay2 lbsr Delay3 +Delay3 rts + +* SetStat +* +* Entry: +* A = function code +* Y = address of path descriptor +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +SetStat + ldx PD.Rgs,y ; Retrieve request + ldb R$B,x + + cmpb #SS.Reset ; Restore to track 0. + beq ResetTrack0 + cmpb #SS.Wtrk ; Write (format) a track + beq DoWriteTrack + comb + ldb #E$UnkSvc +SetStatEnd + rts +; +; Write (format) a track +; + +DoWriteTrack + + lbsr SelectDrive ; Select drive + lda R$Y+1,x + LBSR SetSide ; Set Side 2 if appropriate + LDA R$U+1,X + BSR SetWPC ; Set WPC by disk type + bsr SetDensity ; Set density + +;L02D5 + ldx >CDrvTab,u + lbsr SeekTS ; Move to correct track + bcs SetStatEnd + + ldx PD.Rgs,y + ldx R$X,x + ldb #WtTkCmnd + pshs y,dp,cc + lbra WriteTrackCmd + +; Reset track 0 +ResetTrack0 + lbsr SelectDrive ; Select drive + ldx >CDrvTab,u + clr <V.Trak,x ; Set current track as 0 + lda #$05 + +ResetTrack0Loop + lbsr GetStepInB ; Get step rate for this drive + orb #StpICmnd ; Step away from track 0 5 times + pshs a + lbsr FDCCommand + puls a + deca + bne ResetTrack0Loop + + lbsr GetStepInB ; Get step rate for this drive + orb #RestCmnd ; Now issue a restore + lbra FDCCommand +; +;Start drive motors +; + +StartMotor + pshs x,b,a + lda >D.DskTmr ; if timer <> 0 then skip as motor already on + bne MotorsRunning + lda #MotorOn ; else spin up + + IFNE dalpha + bsr AlphaDskCtl + ELSE + sta >DskCtl + ENDC + + ldx #$A000 ; Wait a little while for motors to get up to speed +StartMotorLoop + nop + nop + leax -1,x + bne StartMotorLoop + +MotorsRunning + lbsr SetupVIRQ +; lda #$F0 ; Start external motor timer +; sta >D.DskTmr ; external to driver + puls pc,x,b,a + +; +; Set Write Precompensation according to media type +; +; Entry : +; A = Track no + +SetWPC PSHS A,B + LDB PD.DNS,Y + BITB #T80Mask ; Is it 96 tpi drive + BNE SetWP1 + ASLA ; no then double +SetWP1 CMPA #32 ; WPC needed ? + BLS SetWP2 + LDA >DrivSel,U + ORA #WPCEn + STA >DrivSel,U +SetWP2 PULS A,B,PC + + +; +; Set density acording to disk type. +; +; Entry A = Track no +; + +SetDensity + PSHS A,B + ldb PD.TYP,Y ; Dragon/CoCo disk ? + bitb #TYP.CCF + bne SetDouble ; Always double density + + LDB PD.DNS,Y ; Get density flags from Path descriptor + + bitb #DNS.MFM ; Disk is MFM ? + beq SetSingle ; no : set single density + + cmpa #0 ; track 0 ? + bne SetDouble ; not track 0, exit + + tst SideSel,u ; is this side 0 ? + bne SetDouble ; no : use double density + + bitb #DNS.MFM0 ; track 0 mfm ? + bne SetDouble + +SetSingle + lda #SDensEn ; flag single density + sta Density,u + bra ExitDensity + +SetDouble + clr Density,u ; flag double density + +ExitDensity + puls a,b,pc + + IFNE dalpha + +; Translate DragonDos Drive select mechinisim to work on Alpha +; Takes byte that would be output to $FF48, reformats it and +; outputs to Alpha AY-8912's IO port, which is connected to +; Drive selects, motor on and enable precomp. +; This code now expects Alpha NMI/DDEN etc codes, as defined +; at top of this file (and dgndefs). The exception to this is +; the drive number is still passed in the bottom 2 bits and +; converted with a lookup table. +; We do not need to preserve the ROM select bit as this code +; operates in RAM only mode. + +ADrvTab FCB Drive0A,Drive1A,Drive2A,Drive3A + +AlphaDskCtl + PSHS x,A,B,CC + + PSHS A + anda #DDosDriveMask ; mask out dragondos format drive number + leax ADrvTab,pcr ; point at table + lda a,x ; get bitmap + ldb ,s + andb #AlphaCtrlMask ; mask out drive number bits + stb ,s + ora ,s ; recombine drive no & ctrl bits +; sta ,s + + bita #MotorOn ; test motor on ? + bne MotorRunning + + clra ; No, turn off other bits. +MotorRunning + anda #Mask58 ; Mask out 5/8 bit to force the use of 5.25" clock + sta ,s + + orcc #$50 ; disable inturrupts + + lda #AYIOREG ; AY-8912 IO register + sta PIA2DB ; Output to PIA + ldb #AYREGLatch ; Latch register to modify + stb PIA2DA + + clr PIA2DA ; Idle AY + + lda ,s+ ; Fetch saved Drive Selects etc + sta PIA2DB ; output to PIA + ldb #AYWriteReg ; Write value to latched register + stb PIA2DA ; Set register + + clr PIA2DA ; Idle AY + + PULS x,A,B,CC + RTS + + ENDC + + + emod +eom equ * + end
--- a/level1/modules/dwinit.asm Sat Apr 07 19:28:53 2018 +0200 +++ b/level1/modules/dwinit.asm Sat Apr 07 21:00:59 2018 +0200 @@ -1,37 +1,37 @@ -******************************************************* -* -* DWInit -* Initialize DriveWire for CoCo Bit Banger - -DWInit - IFNE ARDUINO - -* setup PIA PORTA (read) - clr $FF51 - clr $FF50 - lda #$2C - sta $FF51 - -* setup PIA PORTB (write) - clr $FF53 - lda #$FF - sta $FF52 - lda #$2C - sta $FF53 - rts - - ELSE - - pshs a,x - IFDEF PIA1Base - ldx #PIA1Base $FF20 - clr 1,x clear CD - lda #%11111110 - sta ,x - lda #%00110100 - sta 1,x - lda ,x - ENDC - puls a,x,pc - - ENDC +******************************************************* +* +* DWInit +* Initialize DriveWire for CoCo Bit Banger + +DWInit + IFNE ARDUINO + +* setup PIA PORTA (read) + clr $FF51 + clr $FF50 + lda #$2C + sta $FF51 + +* setup PIA PORTB (write) + clr $FF53 + lda #$FF + sta $FF52 + lda #$2C + sta $FF53 + rts + + ELSE + + pshs a,x + IFDEF PIA1Base + ldx #PIA1Base $FF20 + clr 1,x clear CD + lda #%11111110 + sta ,x + lda #%00110100 + sta 1,x + lda ,x + ENDC + puls a,x,pc + + ENDC
--- a/level1/modules/dwrdmess.asm Sat Apr 07 19:28:53 2018 +0200 +++ b/level1/modules/dwrdmess.asm Sat Apr 07 21:00:59 2018 +0200 @@ -1,41 +1,41 @@ -******************************************************* -* -* DWRdMess -* Receive a response from the DriveWire server via MESS FIFO -* 4/27/10 AAW - Based on John Linville's example driver -* -* Entry: -* X = starting address where data is to be stored -* Y = number of bytes expected -* -* Exit: -* CC = carry set on framing error, Z set if all bytes received -* X = starting address of data received -* Y = checksum -* U is preserved. All accumulators are clobbered -* - -DWRead clra ; clear Carry (no framing error) - pshs u,x,cc ; preserve registers, push timeout msb - orcc #$50 ; mask interrupts - - leau ,x ; U = storage ptr - ldx #0 ; initialize checksum - -* Read a byte -rxByte ldb $ffe1 ; check for data in FIFO - beq rxByte ; loop while empty - ldb $ffe0 ; read data value - - stb ,u+ ; store received byte to memory - abx ; update checksum - leay ,-y ; decrement request count - bne rxByte ; loop if another byte wanted - - -* Clean up, set status and return -rxExit leay ,x ; return checksum in Y - puls cc,x,u,pc ; restore registers and return - setdp $00 - - +******************************************************* +* +* DWRdMess +* Receive a response from the DriveWire server via MESS FIFO +* 4/27/10 AAW - Based on John Linville's example driver +* +* Entry: +* X = starting address where data is to be stored +* Y = number of bytes expected +* +* Exit: +* CC = carry set on framing error, Z set if all bytes received +* X = starting address of data received +* Y = checksum +* U is preserved. All accumulators are clobbered +* + +DWRead clra ; clear Carry (no framing error) + pshs u,x,cc ; preserve registers, push timeout msb + orcc #$50 ; mask interrupts + + leau ,x ; U = storage ptr + ldx #0 ; initialize checksum + +* Read a byte +rxByte ldb $ffe1 ; check for data in FIFO + beq rxByte ; loop while empty + ldb $ffe0 ; read data value + + stb ,u+ ; store received byte to memory + abx ; update checksum + leay ,-y ; decrement request count + bne rxByte ; loop if another byte wanted + + +* Clean up, set status and return +rxExit leay ,x ; return checksum in Y + puls cc,x,u,pc ; restore registers and return + setdp $00 + +
--- a/level1/modules/dwwrmess.asm Sat Apr 07 19:28:53 2018 +0200 +++ b/level1/modules/dwwrmess.asm Sat Apr 07 21:00:59 2018 +0200 @@ -1,28 +1,28 @@ -******************************************************* -* -* DWWriteMESS -* -* 4/27/10 AAW - Based on John Linville's example -* -* Entry: -* X = starting address of data to send -* Y = number of bytes to send -* -* Exit: -* X = address of last byte sent + 1 -* Y = 0 -* All others preserved -* - - -DWWrite pshs u,d,cc ; preserve registers - orcc #$50 ; mask interrupts - -txByte ldb ,x+ ; get a byte to transmit - stb $ffe0 ; write it to the FIFO - leay ,-y ; decrement byte counter - bne txByte ; loop if more to send - - puls cc,d,u,pc ; restore registers and return - - +******************************************************* +* +* DWWriteMESS +* +* 4/27/10 AAW - Based on John Linville's example +* +* Entry: +* X = starting address of data to send +* Y = number of bytes to send +* +* Exit: +* X = address of last byte sent + 1 +* Y = 0 +* All others preserved +* + + +DWWrite pshs u,d,cc ; preserve registers + orcc #$50 ; mask interrupts + +txByte ldb ,x+ ; get a byte to transmit + stb $ffe0 ; write it to the FIFO + leay ,-y ; decrement byte counter + bne txByte ; loop if more to send + + puls cc,d,u,pc ; restore registers and return + +
--- a/level1/modules/llcoco3fpga.asm Sat Apr 07 19:28:53 2018 +0200 +++ b/level1/modules/llcoco3fpga.asm Sat Apr 07 21:00:59 2018 +0200 @@ -1,567 +1,567 @@ -******************************************************************* -* llsd - Low-level SDHC/SD/MMC driver -* -* This driver talks to the SD card interface on the DE1 utilizing the CoCo3FPGA -* -* $FF64 (Control Register Write) -* Bit 7 : SD Enable -* Bit 6 : Enable Interrupt -* Bits 5-1 : not used -* Bit 0 : SPI Device Select #1 (DE1 SD Card) -* -* $FF64 (Status Register Read) -* Bit 7 : IRQ Active -* Bits 6-2 : not used -* Bit 1 : SD Card Locked (Write Protect) -* Bit 0 : SD Installed -* -* $FF65 (Data Register R/W) -* -* Edt/Rev YYYY/MM/DD Modified by -* Comment -* ------------------------------------------------------------------ -* 1 2012/06/16 Gary Becker -* Rewritten to work with 8 bit SPI on CoCo3FPGA -* 2 2015/06/06 Gary Becker -* Removed any code to enable multiple slots (single slot only) - -*Level EQU 2 - - NAM llcoco3fpga - TTL Low-level SDHC/SD/MMC driver - - USE defsfile - USE rbsuper.d - -tylg SET Sbrtn+Objct -atrv SET ReEnt+rev -rev SET 0 -edition SET 4 - - MOD eom,name,tylg,atrv,start,0 - - ORG V.LLMem -* Low-level driver static memory area -SEC_CNT RMB 1 Number of sectors to transfer -SEC_LOC RMB 2 Where they are or where they go -SEC_ADD RMB 3 LSN of sector -SDVersion RMB 1 0 = Byte Addressable SD -* !0 = Sector Addressable SD -CMDStorage RMB 1 Command storage area for read/write CMDs -SD_SEC_ADD RMB 4 Four bytes because some devices are byte addressable -CMDCRC RMB 1 - -************************************** -* Command bytes storage area -************************************** -CMD0 fcb $40,$00,$00,$00,$00,$95 -*CMD1 fcb $41,$00,$00,$00,$00,$95 -CMD8 fcb $48,$00,$00,$01,$AA,$87 -*CMD13 fcb $4D,$00,$00,$00,$00,$95 -CMD16 fcb $50,$00,$00,$02,$00,$FF was 95 -ACMD41V1 fcb $69,$00,$00,$00,$00,$FF was 95 -ACMD41V2 fcb $69,$40,$00,$00,$00,$FF was 95 -CMD55 fcb $77,$00,$00,$00,$00,$FF was 95 -CMD58 fcb $7A,$00,$00,$00,$00,$FF was 95 - -* Read/Write commands -CMDRead EQU $5100 Command to read a single block -CMDWrite EQU $5800 Command to write a sector -CMDEnd EQU $00FF Every command ends with $95 -* SPI Address Equates -* SPI Control Register -SPICTRL EQU 0 -SLOT_SEL_0 EQU 1 -SPI_IRQ_EN EQU $40 -SPI_EN EQU $80 Sets SPI enable and IRQ enable -* SPI Status Register -SPISTAT EQU 0 -CARD_DET_0 EQU 1 -CARD_LOCK_0 EQU 2 -IRQ_SLOT_0 EQU $80 -* SPI Transmit / Receive Register -SPIDAT EQU 1 -* Test 8 bit LED display -SPITRACE EQU $FF66 - -name FCS /llcoco3fpga/ - -start lbra ll_init - bra ll_read - nop - lbra ll_write - lbra ll_getstat - lbra ll_setstat - lbra ll_term - -EREAD - ldd #$0000+E$Read A=Disable SPI Interface, but not CS -* B=Read Error - lbra RETERR - -* ll_read - Low level read routine -* -* Entry: -* Registers: -* Y = address of path descriptor -* U = address of device memory area -* Static Variables of interest: -* V.PhysSect = starting physical sector to read from -* V.SectCnt = number of physical sectors to read -* V.SectSize = physical sector size (0=256,1=512,2=1024,3=2048) -* V.CchPSpot = address where physical sector(s) will go -* -* Exit: -* All registers may be modified -* Static variables may NOT be modified -* Initialization errors are not flagged as an error -* SDCards are hot pluggable and card might be plugged in later -ll_read -* Setup read command - orcc #IntMasks disable interrupts - ldx V.Port-UOFFSET,u Get address of hardware - lda V.SectCnt,u Get number of sectors to read - sta SEC_CNT,u Save it to our usable storage - ldd V.CchPSpot,u get the location to copy the sector into - std SEC_LOC,u Save it into our usable storage - ldd V.PhysSect,u Copy Sector Adrress into our storage - std SEC_ADD,u - lda V.PhysSect+2,u - sta SEC_ADD+2,u - lda SPISTAT,x - lsra - bcc EREAD No card installed, so no reads -lphr lda SEC_CNT,u - ldd #CMDRead - std CMDStorage,u Read command and clear MSB of address - ldd #CMDEnd - std SD_SEC_ADD+3,u Clear LSB of address and CRC -rd_loop lda #(SPI_EN+SLOT_SEL_0) but not IRQ enable - bsr LSNMap0 Setup the appropriate LSN value for the card, build command, -* setup SPI to access the card, and sends command - bcs EREAD If we timed out, branch with error - bne EREAD If the R1 was not 0 - - ldy SEC_LOC,u Get the sector buffer address - ldb #$00 256 loops of 2 reads of 1 bytes is 512 bytes -lprd lda SPIDAT,x Send FF (receive a byte) until we get FE - cmpa #$FE Do we need more cycles?????? - nop - bne lprd -* Read the 512 Byte sector -* we need a minumum of 4 CPU cycles to read in the 8 bits -RDSectorLoop lda SPIDAT,x - sta ,y+ ? cycles ????????????? - nop might be too much ??????? - lda SPIDAT,x - sta ,y+ - decb - bne RDSectorLoop -* Get the last two bytes of the sector (CRC bytes) - lda SPIDAT,x Send 2x FF to get the CRC - sty SEC_LOC,u Save out buffer pointer -* nop Might be too many cycles ????????? - lda SPIDAT,x We ignore the CRC - dec SEC_CNT,u decrement # of hw sectors to read - beq finird if zero, we are finished -*Increment sector number by 1 for sector addressable or $200 for byte addressable -incsec inc SEC_ADD+2,u add one to 3 byte LSN - bne lphr if we are at 0 then we need to add - inc SEC_ADD+1,u the carry to the next byte - bne lphr - inc SEC_ADD,u - bra lphr - -* No errors, exit -finird - ldd #$0000 Disable SPI and exit - sta SPICTRL,x - andcc #^(IntMasks+Carry) Renable Interrupts and clear carry - rts return - -************** -* LSNMap -* Take physical LSN and convert into SDHC/SD/MMC LSN -* SD/MMC uses a 32 bit byte mapping for the LSN, so we must shift the logical LSN up one bit -* and then clear the 4th byte to build the correct LSN string -* SDHC uses a 32 bit 512 byte sector mapping for the LSN.So there is no need to shift the LSN -* we can just write it as is and clear out the upper LSN byte, because we only get 3 bytes from coco for LSN -* does not preserve Reg A -************** -LSNMap0 - sta SPICTRL,x - nop - lda SPIDAT,x Send 1 FF - lda SDVersion,u - bne secadd GoTo Sector Address type -*Save the sector number into the command - ldd SEC_ADD+1,u bytes 1 and 2 (middle and LSB) - aslb Byte address needs to be shifter one more bit - rola - std SD_SEC_ADD+1,u and stored in the first 3 bytes of a 4 byte address - lda SEC_ADD,u MSB - rola - sta SD_SEC_ADD,u - bra merge -secadd - ldd SEC_ADD+1,u Save the sector number into our storage - std SD_SEC_ADD+2,u Store in the last three bytes of the 4 byte address - lda SEC_ADD,u - sta SD_SEC_ADD+1,u -merge lda SPIDAT,x Send 1 FF -LSNMap1 - leay CMDStorage,u -* Fall through to cmdsend - -* cmdsend - Sends a 6 byte command -* Entry: X = HW addr -* Y = Address of first byte of command sequence -* Exit: -* Registers preserved: all but A/B/X -cmdsend - lda ,y - sta $FF66 - ldb #6 -cslp lda ,y+ - sta SPIDAT,x - decb - bne cslp -* If finished, fall through to GETR1 - -* Entry: X = HW addr -* Exit: A = R1 -* CC.C = 0 OK -* CC.C = 1 ERROR -* Registers preserved: all but A/B -GetR1 - andcc #^Carry Clear Carry - ldb #$00 Probably too much -lpgtr1 lda SPIDAT,x - bpl finigtr1 - decb - bne lpgtr1 - comb set carry for error -finigtr1 rts - -* ll_write - Low level write routine -* -* Entry: -* Registers: -* Y = address of path descrip -* U = address of device memory area -* Static Variables of interest: -* V.PhysSect = starting physical sector to write to -* V.SectCnt = number of physical sectors to write -* V.SectSize = physical sector size (0=256,1=512,2=1024,3=2048) -* V.CchPSpot = address of data to write to device -* -* Exit: -* All registers may be modified -* Static variables may NOT be modified -ll_write - orcc #IntMasks disable interrupts - ldx V.Port-UOFFSET,u Get address of hardware - lda V.SectCnt,u Get number of sectors to write` - sta SEC_CNT,u Save it to our usable storage - ldd V.CchPSpot,u get the location to of the sector send - std SEC_LOC,u Save it into our usable storage - ldd V.PhysSect,u Copy Sector Adrress into our storage - std SEC_ADD,u - lda V.PhysSect+2,u - sta SEC_ADD+2,u - lda SPISTAT,x - lsra - lbcc EWRITE No card installed, so no writes - lsra - lbcs EWP Write Protected, then exit with WP error -* The big read sector loop comes to here -lphw ldd #CMDWrite - std CMDStorage,u - ldd #CMDEnd - std SD_SEC_ADD+3,u LSB of address and CRC -wr_loop lda #(SPI_EN+SLOT_SEL_0) - bsr LSNMap0 Setup the appropriate LSN value for the card, build command, -* setup SPI to access the card, and sends command - bcs EWRITE - bne EWRITE - - lda SPIDAT,x 2 bytes >= 1 byte after R1 - nop Might not be enough ????? - nop - lda SPIDAT,x - ldd #$FE00 Start of sector byte and clear counter - ldy SEC_LOC,u get the location of the sectors(s) to write - sta SPIDAT,x Mark the start of the sector - nop Too much ??????? -* Write the 512 Byte sector -WRSectorLoop lda ,y+ - sta SPIDAT,x - nop - lda ,y+ - sta SPIDAT,x - decb - bne WRSectorLoop - lda SPIDAT,x send two FFs as CRC - sty SEC_LOC,u Save out buffer pointer - nop Might not be enough ??????? - stb SPIDAT,x Second FF (send 0 to check) - cmpa #$E5 Response - Data accepted token - beq fnd0 First byte? if not, check four more bytes. -* Make sure the response was accepted - lda SPIDAT,x This should be the data we got back during the write of the last CRC -* nop But we do send another ff so we can get the E5 - cmpa #$E5 Response - Data accepted token - beq fnd0 First byte? if not, check three more bytes. - lda SPIDAT,x - cmpa #$E5 Response - Data accepted token if this is not it, then we have an issue - beq fnd0 First byte? if not, check two more bytes. - lda SPIDAT,x - cmpa #$E5 Response - Data accepted token if this is not it, then we have an issue - beq fnd0 First byte? if not, check one more byte. - lda SPIDAT,x - cmpa #$E5 Response - Data accepted token if this is not it, then we have an issue - bne EWRITE Write error -* Check to see if the write is complete -fnd0 lda SPIDAT,x - beq lpwr2 - bra fnd0 Ths beq and bra could be a bne, but I want the extra cycles -lpwr2 lda SPIDAT,x - cmpa #$FF - beq wfin - bra lpwr2 -wfin ldb #10 Lets send 16 more FF just in case -finlp lda SPIDAT,x - decb - bne finlp - dec SEC_CNT,u decrement # of hw sectors to read - beq finiwr if zero, we are finished - inc SEC_ADD+2,u add one to 3 byte LSN - bne lphw if we are at 0 then we need to add - inc SEC_ADD+1,u the carry to the next byte - lbne lphw - inc SEC_ADD,u - lbra lphw -* No errors, exit -finiwr - ldd #$0000 Diable SPI and exit - sta SPICTRL,x - andcc #^(IntMasks+Carry) Renable Interrupts and clear carry - rts - -* Error handlers -EWRITE - ldd #$0000+E$Write A=Enable SPI Interface, but not CS -* B=Write Error - bra RETERR -EWP - ldd #$0000+E$WP A=Enable SPI Interface, but not CS -* B=Write Protect Error - -RETERR - sta SPICTRL,x Set the hardware - andcc #^IntMasks Enable interrupts - coma Set Carry - rts -NOTRDY - ldd #$0000+E$NotRdy Turn off controller and turn on IRQ and flag not ready error - bra RETERR -* ll_init - Low level init routine -* Entry: -* Y = address of device descriptor -* U = address of low level device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -* Note: This routine is called ONCE: for the first device -* IT IS NOT CALLED PER DEVICE! -* -ll_init - orcc #IntMasks disable interrupts - lda $FFD9 Speed up - ldx V.PORT-UOFFSET,u load x with the hw address for the IRQ routine - lda SPISTAT,x - lsra - bcc NOTRDY If there is no card, nothing to do -* Enable SPI - ldd #SPI_EN*256+$10 Enable SPI Interface, but not CS -* 16*8 cycles is >= 74 - sta SPICTRL,x - -*send at least 74 clock cycles with no SS, 12*8 = 96 -lpff lda SPIDAT,x Send FF - decb 2 cycles, need 4 -* nop 2 cycles - bne lpff 3 Cycles -*Initialize card 0 -CRD0 lda #SPI_EN+SLOT_SEL_0 Enable SPI and lower CS - sta SPICTRL,x - -* sdinit - initializes SD Cards, if installed -sdinit -* Send CMD0 - lda SPIDAT,x Send 1 FF - nop ????????? enough - leay CMD0,pcr Might need more cycles ??????? - lda SPIDAT,x Send 1 more FF - lbsr cmdsend Also does a GETR1 - bcs NOTRDY - anda #$7E Idle is ok - bne NOTRDY but nothing else - -* Send CMD8 - lda SPIDAT,x Send 1 FF - nop ?????? enough - leay CMD8,pcr Might need more cycles ?????? - lda SPIDAT,x Sens 1 more FF - lbsr cmdsend Also does an GETR1 - bcs SDV1 - anda #$7E - bne SDV1 - lda SPIDAT,x Byte 1 of R3/R7, through it away - nop - nop might need more ???????? - nop - lda SPIDAT,x Byte 2 of R3/R7, throught it away - nop - nop - nop - lda SPIDAT,x Byte 3 of R3/R7, should be 1 - cmpa #$01 2 cycles - bne NOTRDY 2 cycles - nop - lda SPIDAT,x Byte 4 of R3/R7, should be $AA - cmpa #$AA 2 cycles - bne NOTRDY 2 cycles - nop - -* Send ACMD41 by first CMD55 -loop41V2 lda SPIDAT,x Send 1 FF - nop - leay CMD55,pcr might need more ?????? - lda SPIDAT,x Send 1 FF - lbsr cmdsend Also does an GETR1 - bcs NOTRDY - anda #$7E Idle is ok - bne NOTRDY but nothing else - -* Then send ACMD41 - lda SPIDAT,x - nop - leay ACMD41V2,pcr - lda SPIDAT,x - lbsr cmdsend - bcs NOTRDY No response - beq Send58 If 0 then CMD58 - cmpa #$01 if 1 then try again - beq loop41V2 - lbra NOTRDY - -* Send CMD58 to V2 card -Send58 lda SPIDAT,x - nop ?????? ENOUGH - leay CMD58,pcr Read OCR - lda SPIDAT,x - lbsr cmdsend - lbcs NOTRDY - lda SPIDAT,x Byte 1 of OCR - anda #$40 CCS bit 1= sector 0= byte - sta SDVersion,u - lda SPIDAT,x Byte 2 of R3/R7, through it away - nop - nop - lda SPIDAT,x Byte 3 of R3/R7, through it away - nop - nop - lda SPIDAT,x Byte 4 of R3/R7, through it away - lda SDVersion,u 0 = byte addressable, !0 = block addressable - bne FININIT - bra Send16 - -* Send ACMD41 by first CMD55 -SDV1 - -loop41V1 lda SPIDAT,x Get extra bytes in case we got a bad R7 previously - nop - lda SPIDAT,x -* nop - clr SDVersion,u Byte addressable - lda SPIDAT,x -* nop - leay CMD55,pcr - lda SPIDAT,x - lbsr cmdsend - lbcs NOTRDY - anda #$7E Idle is ok - lbne NOTRDY but nothing else - -* Then send ACMD41 - lda SPIDAT,x -* nop - leay ACMD41V1,pcr - lda SPIDAT,x - lbsr cmdsend - lbcs NOTRDY - beq Send16 If 0 then CMD16 - cmpa #$01 if 1 then try again - beq loop41V1 - lbra NOTRDY -* Send CMD16 -Send16 lda SPIDAT,x -* nop - leay CMD16,pcr - lda SPIDAT,x - lbsr cmdsend - lbne NOTRDY but nothing else -* Finish INIT -FININIT - lda SPIDAT,x Send last FF -* nop -* lda SDVersion,u -* sta $ff66 -* lda #SPI_EN+SPI_IRQ_EN Turn on SPI and Interrupt and turn off CS - lda #SPI_EN Turn on SPI and turn off CS - sta SPICTRL,x - -*Finished with initialization -*Use the stat routine to return - -* ll_getstat - Low level GetStat routine -* ll_setstat - Low level SetStat routine -* -* Entry: -* Y = address of path descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -ll_getstat -ll_setstat - andcc #^Carry - clrb - rts - -* ll_term - Low level term routine -* -* Entry: -* Y = address of device descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -* Note: This routine is called ONCE: for the last device -* IT IS NOT CALLED PER DEVICE! -* -ll_term - clrb - andcc #^Carry - rts - - EMOD -eom EQU * - END +******************************************************************* +* llsd - Low-level SDHC/SD/MMC driver +* +* This driver talks to the SD card interface on the DE1 utilizing the CoCo3FPGA +* +* $FF64 (Control Register Write) +* Bit 7 : SD Enable +* Bit 6 : Enable Interrupt +* Bits 5-1 : not used +* Bit 0 : SPI Device Select #1 (DE1 SD Card) +* +* $FF64 (Status Register Read) +* Bit 7 : IRQ Active +* Bits 6-2 : not used +* Bit 1 : SD Card Locked (Write Protect) +* Bit 0 : SD Installed +* +* $FF65 (Data Register R/W) +* +* Edt/Rev YYYY/MM/DD Modified by +* Comment +* ------------------------------------------------------------------ +* 1 2012/06/16 Gary Becker +* Rewritten to work with 8 bit SPI on CoCo3FPGA +* 2 2015/06/06 Gary Becker +* Removed any code to enable multiple slots (single slot only) + +*Level EQU 2 + + NAM llcoco3fpga + TTL Low-level SDHC/SD/MMC driver + + USE defsfile + USE rbsuper.d + +tylg SET Sbrtn+Objct +atrv SET ReEnt+rev +rev SET 0 +edition SET 4 + + MOD eom,name,tylg,atrv,start,0 + + ORG V.LLMem +* Low-level driver static memory area +SEC_CNT RMB 1 Number of sectors to transfer +SEC_LOC RMB 2 Where they are or where they go +SEC_ADD RMB 3 LSN of sector +SDVersion RMB 1 0 = Byte Addressable SD +* !0 = Sector Addressable SD +CMDStorage RMB 1 Command storage area for read/write CMDs +SD_SEC_ADD RMB 4 Four bytes because some devices are byte addressable +CMDCRC RMB 1 + +************************************** +* Command bytes storage area +************************************** +CMD0 fcb $40,$00,$00,$00,$00,$95 +*CMD1 fcb $41,$00,$00,$00,$00,$95 +CMD8 fcb $48,$00,$00,$01,$AA,$87 +*CMD13 fcb $4D,$00,$00,$00,$00,$95 +CMD16 fcb $50,$00,$00,$02,$00,$FF was 95 +ACMD41V1 fcb $69,$00,$00,$00,$00,$FF was 95 +ACMD41V2 fcb $69,$40,$00,$00,$00,$FF was 95 +CMD55 fcb $77,$00,$00,$00,$00,$FF was 95 +CMD58 fcb $7A,$00,$00,$00,$00,$FF was 95 + +* Read/Write commands +CMDRead EQU $5100 Command to read a single block +CMDWrite EQU $5800 Command to write a sector +CMDEnd EQU $00FF Every command ends with $95 +* SPI Address Equates +* SPI Control Register +SPICTRL EQU 0 +SLOT_SEL_0 EQU 1 +SPI_IRQ_EN EQU $40 +SPI_EN EQU $80 Sets SPI enable and IRQ enable +* SPI Status Register +SPISTAT EQU 0 +CARD_DET_0 EQU 1 +CARD_LOCK_0 EQU 2 +IRQ_SLOT_0 EQU $80 +* SPI Transmit / Receive Register +SPIDAT EQU 1 +* Test 8 bit LED display +SPITRACE EQU $FF66 + +name FCS /llcoco3fpga/ + +start lbra ll_init + bra ll_read + nop + lbra ll_write + lbra ll_getstat + lbra ll_setstat + lbra ll_term + +EREAD + ldd #$0000+E$Read A=Disable SPI Interface, but not CS +* B=Read Error + lbra RETERR + +* ll_read - Low level read routine +* +* Entry: +* Registers: +* Y = address of path descriptor +* U = address of device memory area +* Static Variables of interest: +* V.PhysSect = starting physical sector to read from +* V.SectCnt = number of physical sectors to read +* V.SectSize = physical sector size (0=256,1=512,2=1024,3=2048) +* V.CchPSpot = address where physical sector(s) will go +* +* Exit: +* All registers may be modified +* Static variables may NOT be modified +* Initialization errors are not flagged as an error +* SDCards are hot pluggable and card might be plugged in later +ll_read +* Setup read command + orcc #IntMasks disable interrupts + ldx V.Port-UOFFSET,u Get address of hardware + lda V.SectCnt,u Get number of sectors to read + sta SEC_CNT,u Save it to our usable storage + ldd V.CchPSpot,u get the location to copy the sector into + std SEC_LOC,u Save it into our usable storage + ldd V.PhysSect,u Copy Sector Adrress into our storage + std SEC_ADD,u + lda V.PhysSect+2,u + sta SEC_ADD+2,u + lda SPISTAT,x + lsra + bcc EREAD No card installed, so no reads +lphr lda SEC_CNT,u + ldd #CMDRead + std CMDStorage,u Read command and clear MSB of address + ldd #CMDEnd + std SD_SEC_ADD+3,u Clear LSB of address and CRC +rd_loop lda #(SPI_EN+SLOT_SEL_0) but not IRQ enable + bsr LSNMap0 Setup the appropriate LSN value for the card, build command, +* setup SPI to access the card, and sends command + bcs EREAD If we timed out, branch with error + bne EREAD If the R1 was not 0 + + ldy SEC_LOC,u Get the sector buffer address + ldb #$00 256 loops of 2 reads of 1 bytes is 512 bytes +lprd lda SPIDAT,x Send FF (receive a byte) until we get FE + cmpa #$FE Do we need more cycles?????? + nop + bne lprd +* Read the 512 Byte sector +* we need a minumum of 4 CPU cycles to read in the 8 bits +RDSectorLoop lda SPIDAT,x + sta ,y+ ? cycles ????????????? + nop might be too much ??????? + lda SPIDAT,x + sta ,y+ + decb + bne RDSectorLoop +* Get the last two bytes of the sector (CRC bytes) + lda SPIDAT,x Send 2x FF to get the CRC + sty SEC_LOC,u Save out buffer pointer +* nop Might be too many cycles ????????? + lda SPIDAT,x We ignore the CRC + dec SEC_CNT,u decrement # of hw sectors to read + beq finird if zero, we are finished +*Increment sector number by 1 for sector addressable or $200 for byte addressable +incsec inc SEC_ADD+2,u add one to 3 byte LSN + bne lphr if we are at 0 then we need to add + inc SEC_ADD+1,u the carry to the next byte + bne lphr + inc SEC_ADD,u + bra lphr + +* No errors, exit +finird + ldd #$0000 Disable SPI and exit + sta SPICTRL,x + andcc #^(IntMasks+Carry) Renable Interrupts and clear carry + rts return + +************** +* LSNMap +* Take physical LSN and convert into SDHC/SD/MMC LSN +* SD/MMC uses a 32 bit byte mapping for the LSN, so we must shift the logical LSN up one bit +* and then clear the 4th byte to build the correct LSN string +* SDHC uses a 32 bit 512 byte sector mapping for the LSN.So there is no need to shift the LSN +* we can just write it as is and clear out the upper LSN byte, because we only get 3 bytes from coco for LSN +* does not preserve Reg A +************** +LSNMap0 + sta SPICTRL,x + nop + lda SPIDAT,x Send 1 FF + lda SDVersion,u + bne secadd GoTo Sector Address type +*Save the sector number into the command + ldd SEC_ADD+1,u bytes 1 and 2 (middle and LSB) + aslb Byte address needs to be shifter one more bit + rola + std SD_SEC_ADD+1,u and stored in the first 3 bytes of a 4 byte address + lda SEC_ADD,u MSB + rola + sta SD_SEC_ADD,u + bra merge +secadd + ldd SEC_ADD+1,u Save the sector number into our storage + std SD_SEC_ADD+2,u Store in the last three bytes of the 4 byte address + lda SEC_ADD,u + sta SD_SEC_ADD+1,u +merge lda SPIDAT,x Send 1 FF +LSNMap1 + leay CMDStorage,u +* Fall through to cmdsend + +* cmdsend - Sends a 6 byte command +* Entry: X = HW addr +* Y = Address of first byte of command sequence +* Exit: +* Registers preserved: all but A/B/X +cmdsend + lda ,y + sta $FF66 + ldb #6 +cslp lda ,y+ + sta SPIDAT,x + decb + bne cslp +* If finished, fall through to GETR1 + +* Entry: X = HW addr +* Exit: A = R1 +* CC.C = 0 OK +* CC.C = 1 ERROR +* Registers preserved: all but A/B +GetR1 + andcc #^Carry Clear Carry + ldb #$00 Probably too much +lpgtr1 lda SPIDAT,x + bpl finigtr1 + decb + bne lpgtr1 + comb set carry for error +finigtr1 rts + +* ll_write - Low level write routine +* +* Entry: +* Registers: +* Y = address of path descrip +* U = address of device memory area +* Static Variables of interest: +* V.PhysSect = starting physical sector to write to +* V.SectCnt = number of physical sectors to write +* V.SectSize = physical sector size (0=256,1=512,2=1024,3=2048) +* V.CchPSpot = address of data to write to device +* +* Exit: +* All registers may be modified +* Static variables may NOT be modified +ll_write + orcc #IntMasks disable interrupts + ldx V.Port-UOFFSET,u Get address of hardware + lda V.SectCnt,u Get number of sectors to write` + sta SEC_CNT,u Save it to our usable storage + ldd V.CchPSpot,u get the location to of the sector send + std SEC_LOC,u Save it into our usable storage + ldd V.PhysSect,u Copy Sector Adrress into our storage + std SEC_ADD,u + lda V.PhysSect+2,u + sta SEC_ADD+2,u + lda SPISTAT,x + lsra + lbcc EWRITE No card installed, so no writes + lsra + lbcs EWP Write Protected, then exit with WP error +* The big read sector loop comes to here +lphw ldd #CMDWrite + std CMDStorage,u + ldd #CMDEnd + std SD_SEC_ADD+3,u LSB of address and CRC +wr_loop lda #(SPI_EN+SLOT_SEL_0) + bsr LSNMap0 Setup the appropriate LSN value for the card, build command, +* setup SPI to access the card, and sends command + bcs EWRITE + bne EWRITE + + lda SPIDAT,x 2 bytes >= 1 byte after R1 + nop Might not be enough ????? + nop + lda SPIDAT,x + ldd #$FE00 Start of sector byte and clear counter + ldy SEC_LOC,u get the location of the sectors(s) to write + sta SPIDAT,x Mark the start of the sector + nop Too much ??????? +* Write the 512 Byte sector +WRSectorLoop lda ,y+ + sta SPIDAT,x + nop + lda ,y+ + sta SPIDAT,x + decb + bne WRSectorLoop + lda SPIDAT,x send two FFs as CRC + sty SEC_LOC,u Save out buffer pointer + nop Might not be enough ??????? + stb SPIDAT,x Second FF (send 0 to check) + cmpa #$E5 Response - Data accepted token + beq fnd0 First byte? if not, check four more bytes. +* Make sure the response was accepted + lda SPIDAT,x This should be the data we got back during the write of the last CRC +* nop But we do send another ff so we can get the E5 + cmpa #$E5 Response - Data accepted token + beq fnd0 First byte? if not, check three more bytes. + lda SPIDAT,x + cmpa #$E5 Response - Data accepted token if this is not it, then we have an issue + beq fnd0 First byte? if not, check two more bytes. + lda SPIDAT,x + cmpa #$E5 Response - Data accepted token if this is not it, then we have an issue + beq fnd0 First byte? if not, check one more byte. + lda SPIDAT,x + cmpa #$E5 Response - Data accepted token if this is not it, then we have an issue + bne EWRITE Write error +* Check to see if the write is complete +fnd0 lda SPIDAT,x + beq lpwr2 + bra fnd0 Ths beq and bra could be a bne, but I want the extra cycles +lpwr2 lda SPIDAT,x + cmpa #$FF + beq wfin + bra lpwr2 +wfin ldb #10 Lets send 16 more FF just in case +finlp lda SPIDAT,x + decb + bne finlp + dec SEC_CNT,u decrement # of hw sectors to read + beq finiwr if zero, we are finished + inc SEC_ADD+2,u add one to 3 byte LSN + bne lphw if we are at 0 then we need to add + inc SEC_ADD+1,u the carry to the next byte + lbne lphw + inc SEC_ADD,u + lbra lphw +* No errors, exit +finiwr + ldd #$0000 Diable SPI and exit + sta SPICTRL,x + andcc #^(IntMasks+Carry) Renable Interrupts and clear carry + rts + +* Error handlers +EWRITE + ldd #$0000+E$Write A=Enable SPI Interface, but not CS +* B=Write Error + bra RETERR +EWP + ldd #$0000+E$WP A=Enable SPI Interface, but not CS +* B=Write Protect Error + +RETERR + sta SPICTRL,x Set the hardware + andcc #^IntMasks Enable interrupts + coma Set Carry + rts +NOTRDY + ldd #$0000+E$NotRdy Turn off controller and turn on IRQ and flag not ready error + bra RETERR +* ll_init - Low level init routine +* Entry: +* Y = address of device descriptor +* U = address of low level device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +* Note: This routine is called ONCE: for the first device +* IT IS NOT CALLED PER DEVICE! +* +ll_init + orcc #IntMasks disable interrupts + lda $FFD9 Speed up + ldx V.PORT-UOFFSET,u load x with the hw address for the IRQ routine + lda SPISTAT,x + lsra + bcc NOTRDY If there is no card, nothing to do +* Enable SPI + ldd #SPI_EN*256+$10 Enable SPI Interface, but not CS +* 16*8 cycles is >= 74 + sta SPICTRL,x + +*send at least 74 clock cycles with no SS, 12*8 = 96 +lpff lda SPIDAT,x Send FF + decb 2 cycles, need 4 +* nop 2 cycles + bne lpff 3 Cycles +*Initialize card 0 +CRD0 lda #SPI_EN+SLOT_SEL_0 Enable SPI and lower CS + sta SPICTRL,x + +* sdinit - initializes SD Cards, if installed +sdinit +* Send CMD0 + lda SPIDAT,x Send 1 FF + nop ????????? enough + leay CMD0,pcr Might need more cycles ??????? + lda SPIDAT,x Send 1 more FF + lbsr cmdsend Also does a GETR1 + bcs NOTRDY + anda #$7E Idle is ok + bne NOTRDY but nothing else + +* Send CMD8 + lda SPIDAT,x Send 1 FF + nop ?????? enough + leay CMD8,pcr Might need more cycles ?????? + lda SPIDAT,x Sens 1 more FF + lbsr cmdsend Also does an GETR1 + bcs SDV1 + anda #$7E + bne SDV1 + lda SPIDAT,x Byte 1 of R3/R7, through it away + nop + nop might need more ???????? + nop + lda SPIDAT,x Byte 2 of R3/R7, throught it away + nop + nop + nop + lda SPIDAT,x Byte 3 of R3/R7, should be 1 + cmpa #$01 2 cycles + bne NOTRDY 2 cycles + nop + lda SPIDAT,x Byte 4 of R3/R7, should be $AA + cmpa #$AA 2 cycles + bne NOTRDY 2 cycles + nop + +* Send ACMD41 by first CMD55 +loop41V2 lda SPIDAT,x Send 1 FF + nop + leay CMD55,pcr might need more ?????? + lda SPIDAT,x Send 1 FF + lbsr cmdsend Also does an GETR1 + bcs NOTRDY + anda #$7E Idle is ok + bne NOTRDY but nothing else + +* Then send ACMD41 + lda SPIDAT,x + nop + leay ACMD41V2,pcr + lda SPIDAT,x + lbsr cmdsend + bcs NOTRDY No response + beq Send58 If 0 then CMD58 + cmpa #$01 if 1 then try again + beq loop41V2 + lbra NOTRDY + +* Send CMD58 to V2 card +Send58 lda SPIDAT,x + nop ?????? ENOUGH + leay CMD58,pcr Read OCR + lda SPIDAT,x + lbsr cmdsend + lbcs NOTRDY + lda SPIDAT,x Byte 1 of OCR + anda #$40 CCS bit 1= sector 0= byte + sta SDVersion,u + lda SPIDAT,x Byte 2 of R3/R7, through it away + nop + nop + lda SPIDAT,x Byte 3 of R3/R7, through it away + nop + nop + lda SPIDAT,x Byte 4 of R3/R7, through it away + lda SDVersion,u 0 = byte addressable, !0 = block addressable + bne FININIT + bra Send16 + +* Send ACMD41 by first CMD55 +SDV1 + +loop41V1 lda SPIDAT,x Get extra bytes in case we got a bad R7 previously + nop + lda SPIDAT,x +* nop + clr SDVersion,u Byte addressable + lda SPIDAT,x +* nop + leay CMD55,pcr + lda SPIDAT,x + lbsr cmdsend + lbcs NOTRDY + anda #$7E Idle is ok + lbne NOTRDY but nothing else + +* Then send ACMD41 + lda SPIDAT,x +* nop + leay ACMD41V1,pcr + lda SPIDAT,x + lbsr cmdsend + lbcs NOTRDY + beq Send16 If 0 then CMD16 + cmpa #$01 if 1 then try again + beq loop41V1 + lbra NOTRDY +* Send CMD16 +Send16 lda SPIDAT,x +* nop + leay CMD16,pcr + lda SPIDAT,x + lbsr cmdsend + lbne NOTRDY but nothing else +* Finish INIT +FININIT + lda SPIDAT,x Send last FF +* nop +* lda SDVersion,u +* sta $ff66 +* lda #SPI_EN+SPI_IRQ_EN Turn on SPI and Interrupt and turn off CS + lda #SPI_EN Turn on SPI and turn off CS + sta SPICTRL,x + +*Finished with initialization +*Use the stat routine to return + +* ll_getstat - Low level GetStat routine +* ll_setstat - Low level SetStat routine +* +* Entry: +* Y = address of path descriptor +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +ll_getstat +ll_setstat + andcc #^Carry + clrb + rts + +* ll_term - Low level term routine +* +* Entry: +* Y = address of device descriptor +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +* Note: This routine is called ONCE: for the last device +* IT IS NOT CALLED PER DEVICE! +* +ll_term + clrb + andcc #^Carry + rts + + EMOD +eom EQU * + END
--- a/level1/modules/scdpp.asm Sat Apr 07 19:28:53 2018 +0200 +++ b/level1/modules/scdpp.asm Sat Apr 07 21:00:59 2018 +0200 @@ -1,174 +1,174 @@ -* Parallel Printer device for Dragon 32/64/Alpha. -* -* Disassembled from the Alpha OS-9 2005-06-14, P.Harvey-Smith. -* - - nam scdpp - ttl Dragon Parallel Printer Driver - -* Disassembled 1900/00/00 00:08:11 by Disasm v1.5 (C) 1988 by RML - - ifp1 - use defsfile - endc - -tylg set Drivr+Objct -atrv set ReEnt+rev -rev set $01 -edition set 3 - mod eom,name,tylg,atrv,start,size - -u0000 rmb 29 -size equ . - - fcb $03 -name equ * - fcs /scdpp/ - fcb edition - -start equ * - lbra Init - lbra Read - lbra Write - lbra GetStat - lbra SetStat - lbra Term - -* Init -* -* Entry: -* Y = address of device descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -Init pshs cc - orcc #$50 ; Disable Inturrupts - ldx #PIA1DA ; Point to PIA1DA - ldb 1,x ; Get CRA - clr 1,x ; Zero CR and select DDRA - lda #$FE ; Set bit 0 as input (cassette in), all others as input - sta ,x - stb 1,x ; Restore CRA - ldx #PIA1DB ; Point at PIA1DB - ldb 1,x ; Save CRB - clr 1,x ; Zero CR and select DDRB - lda ,x ; get DDRB - anda #$FE ; Set bit 0 as input (printer busy), all others leave alone - sta ,x - stb 1,x ; restore CRB - puls cc - clrb ; Flag no error - rts - -* 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 -* - -Read ldb #$CB ; Ilegal mode, cannot read from printer ! - orcc #$01 - rts - -* Write -* -* 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 pshs a -L0053 ldb #$08 ; retry count -L0055 lda >PIA1DB ; Get printer busy flag - lsra ; Get busy bit into carry - bcc WriteNotBusy ; Not busy : continue - nop ; wait a little while - nop - decb ; decrement retry counter - bne L0055 ; Non zero : check flag again - - pshs x ; Still busy: send calling process to sleep - ldx #$0001 - os9 F$Sleep - puls x - bra L0053 ; When we wake, poll busy again - -WriteNotBusy - puls a - pshs cc - orcc #$50 ; disable inturrupts - sta >PIA0DB ; Send character to printer - lda >PIA1DA ; Toggle printer strobe line - ora #$02 ; high - sta >PIA1DA - anda #$FD ; and low again - sta >PIA1DA - puls pc,cc ; restore and return - -* GetStat -* -* Entry: -* A = function code -* Y = address of path descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -GetStat - cmpa #$01 - bne L008A -L0088 clrb - rts - -L008A cmpa #$06 - beq L0088 -* -* SetStat -* -* Entry: -* A = function code -* Y = address of path descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -SetStat - comb - ldb #$D0 - rts -* -* Term -* -* Entry: -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* - -Term rts - - emod -eom equ * - end +* Parallel Printer device for Dragon 32/64/Alpha. +* +* Disassembled from the Alpha OS-9 2005-06-14, P.Harvey-Smith. +* + + nam scdpp + ttl Dragon Parallel Printer Driver + +* Disassembled 1900/00/00 00:08:11 by Disasm v1.5 (C) 1988 by RML + + ifp1 + use defsfile + endc + +tylg set Drivr+Objct +atrv set ReEnt+rev +rev set $01 +edition set 3 + mod eom,name,tylg,atrv,start,size + +u0000 rmb 29 +size equ . + + fcb $03 +name equ * + fcs /scdpp/ + fcb edition + +start equ * + lbra Init + lbra Read + lbra Write + lbra GetStat + lbra SetStat + lbra Term + +* Init +* +* Entry: +* Y = address of device descriptor +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +Init pshs cc + orcc #$50 ; Disable Inturrupts + ldx #PIA1DA ; Point to PIA1DA + ldb 1,x ; Get CRA + clr 1,x ; Zero CR and select DDRA + lda #$FE ; Set bit 0 as input (cassette in), all others as input + sta ,x + stb 1,x ; Restore CRA + ldx #PIA1DB ; Point at PIA1DB + ldb 1,x ; Save CRB + clr 1,x ; Zero CR and select DDRB + lda ,x ; get DDRB + anda #$FE ; Set bit 0 as input (printer busy), all others leave alone + sta ,x + stb 1,x ; restore CRB + puls cc + clrb ; Flag no error + rts + +* 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 +* + +Read ldb #$CB ; Ilegal mode, cannot read from printer ! + orcc #$01 + rts + +* Write +* +* 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 pshs a +L0053 ldb #$08 ; retry count +L0055 lda >PIA1DB ; Get printer busy flag + lsra ; Get busy bit into carry + bcc WriteNotBusy ; Not busy : continue + nop ; wait a little while + nop + decb ; decrement retry counter + bne L0055 ; Non zero : check flag again + + pshs x ; Still busy: send calling process to sleep + ldx #$0001 + os9 F$Sleep + puls x + bra L0053 ; When we wake, poll busy again + +WriteNotBusy + puls a + pshs cc + orcc #$50 ; disable inturrupts + sta >PIA0DB ; Send character to printer + lda >PIA1DA ; Toggle printer strobe line + ora #$02 ; high + sta >PIA1DA + anda #$FD ; and low again + sta >PIA1DA + puls pc,cc ; restore and return + +* GetStat +* +* Entry: +* A = function code +* Y = address of path descriptor +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +GetStat + cmpa #$01 + bne L008A +L0088 clrb + rts + +L008A cmpa #$06 + beq L0088 +* +* SetStat +* +* Entry: +* A = function code +* Y = address of path descriptor +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +SetStat + comb + ldb #$D0 + rts +* +* Term +* +* Entry: +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* + +Term rts + + emod +eom equ * + end