From e7d59c7777ed1a557d3ca0b97886427503e0db39 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 12 Feb 2015 23:21:32 +0000 Subject: [PATCH] zx128: first pieces towards a disciple disk driver Lots of work needed yet. --- Kernel/platform-zx128/disciple.s | 375 +++++++++++++++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100644 Kernel/platform-zx128/disciple.s diff --git a/Kernel/platform-zx128/disciple.s b/Kernel/platform-zx128/disciple.s new file mode 100644 index 00000000..1bd7300e --- /dev/null +++ b/Kernel/platform-zx128/disciple.s @@ -0,0 +1,375 @@ +; +; Supporting routines for the DISCiple floppy controller +; +; This a WD177x controller coupled to an extra magic switching ROM +; chip with its own RAM. From our perspective the other bits don't +; matter just the hardware +; +; The timings for the WD1770 on the spectrum are such that +; we can't check all the bits each loop. We must also be in +; an uncontended bank (even numbered) eg _CODE +; +; Ports +; 0x1B - status/cmd +; 0x5B - track +; 0x9B - sector +; 0xDB - data +; +; Also uses +; 0xFB - printer data +; 0xBB - read to page in DISCiple ROM/RAM, write to page out +; *don't do this with IRQ's on for FUZIX* +; 0x7B - read puts the disciple ROM in the low 8K, write puts the +; RAM there (the other of the pair lives at 8K) +; +; 0x1F - control (w/o) +; bit 0: drive 0/1 (1 = drive 0) +; bit 1: side 0/1 (1 = side 1) +; bit 2: SD/DD (1 = SD?) +; bit 3-5: interface paging control +; bit 6: printer strobe +; bit 7: network +; +; Commands are like other WD177x with the usual variation +; 0x78 - step out (for 0 keep stepping out until give up or zero set) +; 0x58 - step in +; 0xA0 - write + 0x02 for spin up etc, + 0x08? for precomp +; 0xD0 - reset (then wait about 1mS) +; + + .globl _fd_reset + .globl _fd_operation + .globl _fd_motor_on + .globl _fd_motor_off + .globl _fd_selected + .globl _fd_tab + .globl _fd_cmd + +FDCREG .equ 0x1B +FDCTRK .equ 0x5B +FDCSEC .equ 0x9B +FDCDATA .equ 0xDB + +FDCCTRL .equ 0x1F + + + .area _CODE +; +; The timings on this are ugly and we don't get to do a sanity +; length check as would be nice. We may need to double buffer user +; copies as our common is contended memory. +; +; FIXME: save original HL - subtract and compare with sector size +; +; Entry: HL = input buffer (sector size) +; Exit: Z = ok, NZ A = error or 0 for short +; Uses: AF, BC, HL +; +; +; Timeout useful ? +; +cmd1772: + in a, (0x1B) ; read status + bit 0, a + jr nz, cmd1772 + ld a,b + out (0x1B),a ; write the CMD register + ld b, #32 +cmd1772w: + djnz cmd1772w ; fixme - reduce for DD (test and use 30/15) + ret + +; +; interrupt register reports 0x80 for interrut, 0x40 for drq +; (0x20 is the unrelated reset button) +; + +; +; Structures we use +; +; +; Per disk structure to hold device state +; +TRKCOPY .equ 0 + +; +; Command issue +; +CMD .equ 0 +TRACK .equ 1 +SECTOR .equ 2 +DIRECT .equ 3 ; 0 = read 2 = write 1 = status +DATA .equ 4 + +; +; Wait for the drive controller to become ready +; Preserve HL, DE +; +waitdisk: + ld bc, #0 +waitdisk_l: + in a, (FDCREG) + bit 0, a + ret z + ; + ; Keep poking fdcctrl to avoid a hardware motor timeout + ; + djnz waitdisk_l + dec c + jr nz, waitdisk_l + ld c, #0xD0 ; reset + call cmd1772 + in a, (FDCREG) ; read to reset int status + bit 0, a + ret +; +; Set up and perform a disk operation +; +; IX points to the command block +; HL points to the buffer +; DE points to the track reg copy +; +; The caller is responsible for setting up the drive and side bits +; and the precomp fieeld in write commands (tracks > 64 for 80 or +; > 32 for 40 track drives) +; +fdsetup: + ld a, (de) + out (FDCTRK), a + cp TRACK(ix) +; jr z, fdiosetup ; FIXME + + ; + ; So we can verify + ; + ld a, TRACK(ix) + out (FDCDATA), a + ld a, SECTOR(ix) + out (FDCSEC), a + ; + ; Need to seek the disk + ; + ld b, #0x18 ; seek (18 or 10 ?) + call cmd1772 + call waitdisk + jr nz, setuptimeout + and #0x18 ; error bits + jr z, fdiosetup + ; seek failed, not good +setuptimeout: ; NE = bad + ld a, #0xff ; we have no idea where we are, force a seek + ld (de), a ; zap track info + ret +; +; Head in the right place +; +fdiosetup: + ld a, TRACK(ix) + ld (de), a ; save track + ld a, SECTOR(ix) + out (FDCSEC), a + in a, (FDCREG) ; Clear any pending status + + ld c, CMD(ix) + + ld de, #0 ; timeout handling + + call cmd1772 + + ld a, DIRECT(ix) + dec a + jr z, fdio_in + jr nc, fdio_out +; +; Status registers +; +fdxferdone: + ei +fdxferdone2: + in a, (FDCREG) + ; FIXME: mask varies by type - WP on write etc + and #0x19 ; Error bits + busy + bit 0, a ; Wait for busy to drop, return in a + ret z + jr fdxferdone2 +; +; Read from the disk - HL points to the target buffer +; +fdio_in: + ld bc, #0xDB ; 256 count, port DB (data of 1770) + jr sector_idrq +sector_byte: + ini ; 16 + nop ; 4 the ROM does - not clear why +sector_idrq: + in a,(0x1B) ; 11 like all spectrum hw ports splattered + ; all over + bit 1,a ; 8 + jr nz, sector_byte ; 7 / 12 if taken + in a,(0x1B) ; 11 like all spectrum hw ports splattered + ; all over + bit 1,a ; 8 + jr nz, sector_byte ; 7 / 12 if taken + in a,(0x1B) ; 11 like all spectrum hw ports splattered + ; all over + bit 1,a ; 8 + jr nz, sector_byte ; 7 / 12 if taken + in a,(0x1B) ; 11 like all spectrum hw ports splattered + ; all over + bit 1,a ; 8 + jr nz, sector_byte ; 7 / 12 if taken + + ; + ; We should have had bits by now + ; + + bit 0,a ; 8 + jr nz, sector_idrq ; 7 / 12 if taken + + ; + ; Gone non busy + ; + and #0x1C + jr fdxferdone + +; +; Read from the disk - HL points to the target buffer +; +fdio_out: + ld bc, #0xDB ; 256 count, port DB (data of 1770) + jr sector_odrq +sector_obyte: + outi ; 16 + nop ; 4 the ROM does - not clear why +sector_odrq: + in a,(0x1B) ; 11 like all spectrum hw ports splattered + ; all over + bit 1,a ; 8 + jr nz, sector_obyte ; 7 / 12 if taken + in a,(0x1B) ; 11 like all spectrum hw ports splattered + ; all over + bit 1,a ; 8 + jr nz, sector_obyte ; 7 / 12 if taken + in a,(0x1B) ; 11 like all spectrum hw ports splattered + ; all over + bit 1,a ; 8 + jr nz, sector_obyte ; 7 / 12 if taken + in a,(0x1B) ; 11 like all spectrum hw ports splattered + ; all over + bit 1,a ; 8 + jr nz, sector_obyte ; 7 / 12 if taken + + ; + ; We should have done the bits by now + ; + + bit 0,a ; 8 + jr nz, sector_idrq ; 7 / 12 if taken + + ; + ; Gone non busy + ; + and #0x5C ; error bits and WP bit (to us an error) + jr nz, fdxferdone + xor a ; 256 bytes ?? + cp b + jr z, fdxferdone +fdxferbad: + ld a, #0xff + ret + +; +; C glue interface. +; +; Because of the brain dead memory paging we dump the bits into +; kernel space always. The thought of taking an NMI while in the +; user memory and bank flipping to recover is just too odious ! +; + +; +; Reset to track 0, wait for the command then idle +; +; fd_reset(uint8_t *drvptr) +; +_fd_reset: + pop bc + pop de + pop hl + push hl + push de + push bc + ld a, #1 + out (FDCSEC), a + xor a + out (FDCTRK), a + ld c, #0x0C + call cmd1772 + ld a, #0xFF + ld (hl), a ; Zap track pointer + call waitdisk + cp #0xff + ret z + and #0x99 ; Error bit from the reset + ret nz + ld (hl), a ; Track 0 correctly hit (so 0) + ret +; +; fd_operation(uint16_t *cmd, uint16_t *drive) +; +; The caller must ensure the drive has been selected and the motor is +; running. +; +_fd_operation: + pop hl ; return address + pop bc ; padding + pop de ; drive track ptr + push de + push bc + push hl + push ix + ld ix, #_fd_cmd + ld l, DATA(ix) + ld h, DATA+1(ix) + call fdsetup ; Set up for a command + ld l, a + ld h, #0 + pop ix + ret +; +; C interface fd_motor_on(uint16_t drivesel) +; +; Selects this drive and turns on the motors. Also pass in the +; choice of density +; +; bits 0-3: select that drive +; bit 4: side (must rewrite each drive change) +; bit 5: precompensation (not set here but in the I/O ops) +; bit 6: synchronize I/O by stalling the CPU (don't set this) +; bit 7: set for double density (MFM) +; +; +_fd_motor_on: + ret + +; +; C interface fd_motor_off(void) +; +; Turns off the drive motors, deselects all drives +; +_fd_motor_off: + ret + +curdrive: + .db 0xff +motor_running: + .db 0 +fdcctrl: + .db 0 +fdc_active: + .db 0 +_fd_selected: + .db 0xFF +_fd_tab: + .db 0xFF, 0xFF +_fd_cmd: + .ds 6 -- 2.34.1