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