#define MAX_FD 4
-#define OPDIR_READ 0
-#define OPDIR_NONE 1
+#define OPDIR_NONE 0
+#define OPDIR_READ 1
#define OPDIR_WRITE 2
#define FD_READ 0x88 /* 2797 needs 0x88, 1797 needs 0x80 */
* for our usage but would break for single density media.
*/
+/* static uint8_t selmap[4] = { 0x01, 0x02, 0x04, 0x40 }; - COCO */
+static uint8_t selmap[4] = {0x00, 0x01, 0x02, 0x03 };
+
static int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
{
blkno_t block;
int tries;
uint8_t err;
uint8_t *driveptr = fd_tab + minor;
- uint16_t cmd[5];
-
- /* FIXME: raw is broken unless nicely aligned */
+ uint8_t cmd[6];
if(rawflag)
goto bad2;
fd_motor_busy(); /* Touch the motor timer first so we don't
go and turn it off as we are doing this */
if (fd_selected != minor) {
- uint8_t err = fd_motor_on(driveptr);
+ uint8_t err = fd_motor_on(selmap[minor]);
if (err)
goto bad;
}
dptr = (uint16_t)udata.u_buf->bf_data;
block = udata.u_buf->bf_blk;
+// kprintf("Issue command: drive %d\n", minor);
cmd[0] = is_read ? FD_READ : FD_WRITE;
- cmd[1] = block / 18;
- cmd[2] = (block % 18) + 1; /*eww.. */
- cmd[3] = minor; /* FIXME: other bits ? */
- cmd[4] = is_read ? OPDIR_READ: OPDIR_WRITE;
- cmd[5] = block << 8;
- cmd[6] = block & 0xFF;
+ cmd[1] = block / 9; /* 2 sectors per block */
+ cmd[2] = ((block % 9) << 1) + 1; /*eww.. */
+ cmd[3] = is_read ? OPDIR_READ: OPDIR_WRITE;
+ cmd[4] = dptr >> 8;
+ cmd[5] = dptr & 0xFF;
while (ct < 2) {
- for (tries = 0; tries < 3 ; tries++) {
+ for (tries = 0; tries < 4 ; tries++) {
+// kprintf("Issue command: %d drive %d sec %d\n", cmd[0], minor, cmd[2]);
err = fd_operation(cmd, driveptr);
+// kprintf("Issue command: return %d\n", err);
if (err == 0)
break;
if (tries > 1)
/* FIXME: should we try the other half and then bale out ? */
if (tries == 3)
goto bad;
- cmd[5]++; /* Move on 256 bytes in the buffer */
+ cmd[4]++; /* Move on 256 bytes in the buffer */
cmd[2]++; /* Next sector for 2nd block */
ct++;
}
;
; MMIO for the floppy controller
;
+; For a Dragon cartridge
;
-; These four are a normal WD2797 under DragonDOS
+FDCCTRL EQU 0xFF48
+;
+; 0-1: drive select
+; 2: motor on
+; 3: density
+; 4: precomp
+; 5: nmi mode
;
FDCREG EQU 0xFF40
FDCTRK EQU 0xFF41
FDCSEC EQU 0xFF42
FDCDATA EQU 0xFF43
-;
-; This is the control logic
-;
-FDCCTRL EQU 0xFF48 ; drive select and motors
-; bit5: NMI enable, 4: Precomp ?, 3: Density, 2: Motor,
-; bits 0-1 are drive nymber 0-3
-
;
; Structures we use
CMD EQU 0
TRACK EQU 1
SECTOR EQU 2
-DRIVESEL EQU 3
-DIRECT EQU 4 ; 0 = read 2 = write 1 = status
-DATA EQU 5
+DIRECT EQU 3 ; 0 = read 2 = write 1 = status
+DATA EQU 4
.area .text
;
waitdisk_l:
leax -1,x
beq forceint ; try forcing an interrupt
- lda FDCREG
+ lda <FDCREG
bita #0x01
bne waitdisk_l
rts ; done, idle EQ true
forceint: ; no response, bigger stick
lda #0xD0 ; reset
- sta FDCREG
+ sta <FDCREG
nop
exg a,a
exg a,a
- lda FDCREG ; read to reset int status
+ lda <FDCREG ; read to reset int status
; ?? what to do next ??
lda #0xff ; force NEQ
rts
-;
; Set up the disk. On entry y points to our per drive data and
; x points to the command block
;
fdsetup:
lda TRKCOPY,y
- sta FDCTRK ; reset track register
+ sta <FDCTRK ; reset track register
pshs x,y
cmpa TRACK,x ; target track
beq fdiosetup
+
+ sta <FDCTRK ; target
+ ;
+ ; So we can verify
+ ;
+ lda SECTOR,x
+ sta <FDCSEC
;
; Need to seek the disk
;
lda #0x14
- sta FDCREG ; seek
+ sta <FDCREG ; seek
nop
exg a,a
exg a,a
; seek failed, not good
setuptimeout: ; NE = bad
puls x,y
- lda FDCTRK ; we have no idea where we are
- sta TRKCOPY,y ; so remember what the drive reported
+ ldb <FDCTRK ; we have no idea where we are
+ stb TRKCOPY,y ; so remember what the drive reported
rts
;
; Head in the right place
puls x,y
lda TRACK,x
sta TRKCOPY,y ; remember we arrived
- ldb FDCCTRL
- andb #0xEF
+ ldb fdcctrl
+ andb #0xEF ; precomp
cmpa #22
blo noprecomp
orb #0x10
noprecomp:
- stb FDCCTRL ; precomp configured
+ orb #0x20 ; NMI/halt on
+ stb <FDCCTRL ; precomp configured
lda SECTOR,x
- sta FDCSEC
- lda FDCREG ; clear any pending int
+ sta <FDCSEC
+ lda <FDCREG ; clear any pending int
lda CMD,x ; command to issue
ldy #fdxferdone
sty nmivector ; so our NMI handler will clean up
ldy #0 ; timeout handling
- orcc #0x10 ; irqs off or we'll miss bytes
- sta FDCREG ; issue the command
+ orcc #0x50 ; irqs off or we'll miss bytes
+ sta <FDCREG ; issue the command
nop ; give the FDC a moment to think
exg a,a
exg a,a
; Status registers
;
fdxferdone:
- andcc #0xef
- lda FDCREG
+ ldb fdcctrl
+ stb <FDCCTRL
+ lda <FDCREG
anda #0x7C ; Returns with A holding the status bits
rts
;
; Relies on B being 2...
;
wait_drq:
- bitb FDCREG
+ bitb <FDCREG
bne drq_on
leay -1,y
bne wait_drq
;
; Timed out - reset etc to clean up ??
;
- andcc #0xef
lda #0xff ; our error code
rts
; Once the controller decides it is finished it will flag an NMI
; and the NMI will switch the PC on the return to fdxferdone.
;
-; Begin the actual copy
+; Begin the actual copy to disk
;
drq_on:
- ldy DATA,x
+ ldx DATA,x
+ lda ,x+
+ bra drq_go
drq_loop:
- ldb ,y+
- stb FDCDATA ; hardware will stall this for us
- sta FDCREG
+ sync
+drq_go:
+ sta <FDCDATA
+ lda ,x+
bra drq_loop
;
-; Write to the disk
+; Read from the disk
;
fdio_in:
- ldy DATA,x
+ ldx DATA,x
+fdio_dwait:
+ ldb <FDCREG
+ bitb #0x02
+ bne fdio_go
+ leay -1,y
+ bne fdio_dwait
+ ldb fdcctrl
+ stb <FDCCTRL
+ lda #0xff
+ rts
+;
+; Now do the data
+;
fdio_loop:
- ldb FDCDATA ; Sync is done by hardware
- stb ,y+
- bra fdio_loop ; exit is via NMI to fdxferdone
+ sync
+fdio_go:
+ ldb <0xFF22 ; clear the FIR (PIA1DB)
+ lda <FDCDATA
+ sta ,x+
+ bra fdio_loop
+;
+; PIA management
+;
+piasave:
+ pshs x,y
+ ldx #0xFF01 ; PIA0CRA
+ ldy #pia_stash
+ lda ,x
+ sta ,y+
+ anda #0xFC
+ sta ,x++ ; move on to 0CRB
+ lda ,x
+ sta ,y+
+ anda #0xFC
+ sta ,x
+ leax 0x1e,x ; PIA1CRA
+ lda ,x
+ sta ,y+
+ anda #0xFC
+ sta ,x++ ; on to PIA1CRB
+ lda ,x
+ sta ,y
+ ora #0x37
+ sta ,x ; floppy FIR enabled
+ puls x,y,pc
+piaload:
+ ; Must leave B untouched
+ pshs x,y
+ ldx #0xFF01
+ ldy #pia_stash
+ lda ,y+
+ sta ,x++
+ lda ,y+
+ sta ,x
+ leax 0x1e,x
+ lda ,y+
+ sta ,x++
+ lda ,y+
+ sta ,x
+ puls x,y,pc
;
; C glue interface.
;
; fd_reset(uint16_t *drive)
;
_fd_reset:
- pshs x,y
+ pshs x,y,dp
+ lda #0xFF
+ tfr a,dp
+ ldb fdcctrl
+ stb <FDCCTRL
+ lda #0x01
+ sta <FDCSEC
lda #0x00 ; seek
- sta FDCREG
+ sta <FDCTRK
+ sta <FDCREG
nop
exg a,a
exg a,a
beq rstff ; Total fail
anda #0x10 ; Error bit from the reset
rstff:
- tfr a,b
- puls x, y, pc
+ tfr a,b
+ puls x,y,dp,pc
;
; fd_operation(uint16_t *cmd, uint16_t *drive)
;
; running.
;
_fd_operation:
- pshs y
- ldy 4,s ; Drive struct
- jsr fdsetup ; Set up for a command
- puls y
- tfr a,b ; Status code or 0xFF for total failure
- rts
-;
-; C interface fd_motor_on(uint8 drive)
+ pshs y,cc,dp
+ lda #0xFF
+ tfr a,dp
+ orcc #0x40 ; Make sure FIR is off
+ jsr piasave
+ ldy 6,s ; Drive struct
+ jsr fdsetup ; Set up for a command
+ tfr a,b ; Status code or 0xFF for total failure
+ bsr piaload
+ puls y,cc,dp,pc ; Restore IRQ state etc
+;
+; C interface fd_motor_on(uint8 drivesel)
;
; Selects this drive and turns on the motors
;
_fd_motor_on:
- pshs y
+ pshs y,dp
+ lda #0xFF
+ tfr a,dp
+
;
; Select drive B, turn on motor if needed
;
;
motor_was_on:
ldb #0
- puls y,pc
+ puls y,dp,pc
;
; Select our drive
;
notsel:
- orb #0xA8 ; NMI, motor on, density + our drive id
- lda FDCCTRL
- stb FDCCTRL
- bita #0x08
+ orb #0x04 ; motor on, single density + our drive id
+ stb <FDCCTRL
+ stb fdcctrl
+ bita #0x4
bne motor_was_on
jsr disknap
; FIXME: longer motor spin up delay goes here
jsr waitdisk
- tfr a,b ; return in the right place
- puls y,pc
+ tfr a,b ; return in the right place
+ puls y,dp,pc
;
; C interface fd_motor_off(void)
; Turns off the drive motors, deselects all drives
;
_fd_motor_off:
- pshs y
+ pshs y,dp
+ lda #0xFF
+ tfr a,dp
+
;
; Deselect drives and turn off motor
;
ldb motor_running
beq no_work_motor
; Should we seek to track 0 ?
- ldb FDCCTRL
+ ldb <FDCCTRL
andb #0xF0
- stb FDCCTRL
+ stb <FDCCTRL
clr motor_running
no_work_motor:
- puls y,pc
+ puls y,dp,pc
.area .data
.area .bss
motor_running:
.byte 0
+fdcctrl:
+ .byte 0
+pia_stash:
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 0
\ No newline at end of file