summaryrefslogtreecommitdiff
path: root/NewFloppy.HC
diff options
context:
space:
mode:
authorHarley Travis <harleytravis123@outlook.com>2026-05-23 23:55:17 -0500
committerHarley Travis <harleytravis123@outlook.com>2026-05-23 23:55:17 -0500
commitba700f0759a59551159e90aff2bd6d547c27179b (patch)
tree1c5e98679d0f76be4466b72c1142f3304e3a97d5 /NewFloppy.HC
parent04d039d43164f48f5266d32e783d11f166b6161c (diff)
TOSFloppy_2025-04-20T2103-0500.zip2025-04-20
This was the second and final Discord release of the TempleOS floppy disk controller driver, released April 20, 2025. This release saw mainly structure changes, plus the addition of a license file (the code, at this point, is licensed under Do What The Fuck You Want To Public License, version 2.0).
Diffstat (limited to 'NewFloppy.HC')
-rw-r--r--NewFloppy.HC477
1 files changed, 0 insertions, 477 deletions
diff --git a/NewFloppy.HC b/NewFloppy.HC
deleted file mode 100644
index 9e67467..0000000
--- a/NewFloppy.HC
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- New, (hopefully) Less Messy Floppy Driver
- Copyright (C) 2025 Yoshi128k.
- Licensed under version 2 of the Do What The Fuck You Want To Public License
- See COPYING for details.
-*/
-
-Bool FDCIrq = FALSE;
-
-U0 FDCDMAInit(U16 len)
-{
- U64 /*buf_lo, buf_hi, page,*/ cnt_lo, cnt_hi;
-
-// buf_lo = &FDC_DMA & 0xFF;
-// buf_hi = &FDC_DMA >> 8;
-// page = &FDC_DMA >> 16;
- cnt_lo = (len - 1) & 0xFF;
- cnt_hi = (len - 1) >> 8;
-
- OutU8(0x0A, 6); // mask ch 0 and 2
- Sleep(1);
- OutU8(0x0C, -1); // reset flip flop
- Sleep(1);
- OutU8(0x04, 0x75); // buf low byte
- Sleep(1);
- OutU8(0x04, 0x9F); // buf high byte
- Sleep(1);
- OutU8(0x0C, -1); // reset flip flop again
- Sleep(1);
- OutU8(0x05, cnt_lo); // cntr low byte
- Sleep(1);
- OutU8(0x05, cnt_hi); // cntr high byte
- Sleep(1);
- OutU8(0x81, 0); // page
- Sleep(1);
- OutU8(0x0A, 2); // unmask ch 0 and 2
- Sleep(1);
-}
-
-U0 FDCDMAPrepWrite()
-{
- OutU8(0x0A, 6); // mask ch 0 and 2
- Sleep(1);
- OutU8(0x0B, 0x5A); // single xfer, addr inc, auto init, write, ch 2
- Sleep(1);
- OutU8(0x0A, 2); // unmask ch 0 and 2
- Sleep(1);
-}
-
-U0 FDCDMAPrepRead()
-{
- OutU8(0x0A, 6); // mask ch 0 and 2
- Sleep(1);
- OutU8(0x0B, 0x56); // single xfer, addr inc, auto init, read, ch 2
- Sleep(1);
- OutU8(0x0A, 2); // unmask ch 0 and 2
- Sleep(1);
-}
-
-interrupt U0 FDCIrqHandler() {
- OutU8(0x20, 0x20); // EOI
- FDCIrq = TRUE;
-}
-
-U16 fdc_base = 0x03F0;
-
-static U8 *fd_types[8] = {
- "none",
- "360kB 5.25\"",
- "1.2MB 5.25\"",
- "720kB 3.5\"",
-
- "1.44MB 3.5\"",
- "2.88MB 3.5\"",
- "unknown type",
- "unknown type"
-};
-
-U0 CMOSGetFloppyDrives()
-{
- OutU8(0x70, 0x10);
- Sleep(1);
-
- U64 drives = InU8(0x71);
-
- AdamLog("Floppy Drive 0: %s\n", fd_types[drives >> 4]);
- AdamLog("Floppy Drive 1: %s\n", fd_types[drives & 0xF]);
-}
-
-U0 FDCSendCmd(U16 base, U8 cmd)
-{
- // Send a command to the floppy controller
-
- // 60 sec timeout
- U64 i;
- for (i = 0; i < 600; i++) {
- Sleep(10);
- if (0x80 & InU8(base + FDC_MSR_DSR)) {
- OutU8(base + FDC_DATA, cmd);
- Sleep(1);
- return;
- }
- }
- AdamErr("FDC Command TimeOut");
-}
-
-U8 FDCReadData(U16 base)
-{
- // Read data from the floppy controller
-
- // 60 sec timeout
- U64 i;
- for (i=0;i<600;i++) {
- Sleep(10);
- if (0x80 & InU8(base + FDC_MSR_DSR)) {
- return InU8(base + FDC_DATA);
- }
- }
- AdamErr("FDC Read TimeOut");
-}
-
-U0 FDCCheckInt(U16 base, U8 *st0, U8 *cyl)
-{
- FDCSendCmd(base, FDC_SENSE_INTR);
-
- *st0 = FDCReadData(base);
- *cyl = FDCReadData(base);
-}
-
-I16 fdc_mtr_ticks = 0;
-U8 fdc_mtr_state = FDC_MOTOR_OFF;
-
-U0 FDCMotorOff(U16 base)
-{
- OutU8(base + FDC_DOR, 0x0C);
- fdc_mtr_state = FDC_MOTOR_OFF;
-}
-
-U0 FDCMotorPwrOffTimer()
-{
- // You're supposed to run this function as a separate CTask. It will exit when the motor
- // exits the "wait" state (either because it has turned off or because something needs it to be on).
- // The driver only spawns this when the motor is moved from "on" to "wait".
- while (fdc_mtr_state == FDC_MOTOR_WAIT) {
- // Sanity check for if something wants the motor on at the last second
- if (fdc_mtr_state == FDC_MOTOR_ON) break;
-
- Sleep(500);
-
- fdc_mtr_ticks -= 50;
- if (fdc_mtr_ticks <= 0) {
- FDCMotorOff(fdc_base);
- }
- Yield; // Give control back to the scheduler
- }
-}
-
-U0 FDCMotorCtrl(U16 base, Bool onoff)
-{
- U64 prev_mtr_state;
- if (onoff) {
- if (!fdc_mtr_state) {
- // Turn on motor
- OutU8(base + FDC_DOR, 0x1C);
- Sleep(500); // Wait 500 ms to allow drive to spin up
- }
- fdc_mtr_state = FDC_MOTOR_ON;
- } else {
- prev_mtr_state = fdc_mtr_state;
- if (fdc_mtr_state == FDC_MOTOR_WAIT) {
- AdamLog("FDC: Motor PowerOff Already Pending\n");
- }
- fdc_mtr_ticks = 300; // 3 sec timeout before motor turns off
- fdc_mtr_state = FDC_MOTOR_WAIT;
- // Only spawn the timer task of the motor is currently on; infinitely-looping tasks peg the CPU
- if (prev_mtr_state != FDC_MOTOR_WAIT) Spawn(&FDCMotorPwrOffTimer,,"FDCMotorPwrOffTimer");
- }
-}
-
-I8 FDCRecalibrate(U16 base)
-{
- FDCIrq = FALSE;
-
- U64 i;
- U8 st0, cyl;
-
- FDCMotorCtrl(base, FDC_MOTOR_ON);
-
- for (i=0;i<10;i++) {
- FDCSendCmd(base, FDC_RECALIBRATE);
- FDCSendCmd(base, 0);
-
- // Wait for an interrupt, then get the status
- while (!FDCIrq) Yield;
- FDCCheckInt(base, &st0, &cyl);
- AdamLog("ST0: %d Cyl: %d\n",st0,cyl);
-
- if (st0 & 0xC0) {
- static U8 * status[4] = {0, "error", "invalid", "drive"};
- AdamLog("Calibration Status: %s\n", status[st0 >> 6]);
- }
-
- if (!cyl) {
- FDCMotorCtrl(base, FDC_MOTOR_OFF);
- return 0;
- }
- }
-
- AdamErr("FDC ReCalibrate TimeOut");
- FDCMotorCtrl(base, FDC_MOTOR_OFF);
- return -1;
-}
-
-I8 FDCReset(U16 base)
-{
- FDCIrq = FALSE;
-
- OutU8(base + FDC_DOR, 0x00);
- Sleep(1);
- OutU8(base + FDC_DOR, 0x0C);
- Sleep(1);
-
- while (!FDCIrq) Yield;
-
- // Ignore this
- U64 i, lck;
- U8 st0, cyl;
- for (i=0;i<4;i++) {
- FDCCheckInt(base, &st0, &cyl);
- }
-
- // Set xfer rate to 500kbps
- OutU8(base + FDC_CCR_DIR, 0x00);
- Sleep(1);
-
- // Set the mechanical params and disable DMA (Terry didn't use it)
- FDCSendCmd(base, FDC_SPECIFY);
- FDCSendCmd(base, 0b10000000); // SRT = 8 (8 ms), HUT = 0 (256 ms)
- FDCSendCmd(base, 0b00011110); // HLT = 15 (30 ms), NDMA = 0 (DMA enabled)
-
- // Configure the FIFO
- FDCSendCmd(base, FDC_CONFIGURE);
- FDCSendCmd(base, 0x00); // 1st param is a 0
- FDCSendCmd(base, 0b01011011); // 2nd param: Implied seek on, FIFO on, Drive polling disabled, threshold = 12
- FDCSendCmd(base, 0x00); // 3rd param: write precomp = 0
-
- // Lock the configuration
- FDCSendCmd(base, 0x94);
- lck = FDCReadData(base); // Result: lock status
-
- // contingency
- if (FDCRecalibrate(base)) return -1;
-
- return 0;
-}
-
-I8 FDCSeek(U16 base, U8 cyli, U8 head)
-{
- U64 i;
- U8 st0, cyl;
- FDCIrq = FALSE;
-
- FDCMotorCtrl(base, FDC_MOTOR_ON);
-
- for (i=0;i<10;i++) {
- // Attempt to move to given cyl
- // 1: X X X X X HD D1 D0
- // 2: Cyl No
- FDCSendCmd(base, FDC_SEEK);
- FDCSendCmd(base, head<<2);
- FDCSendCmd(base, cyli);
-
- while (!FDCIrq) Yield;
- FDCCheckInt(base, &st0, &cyl);
- AdamLog("ST0: %d Cyl: %d\n",st0,cyl);
-
- if (st0 & 0xC0) {
- static U8 * status[4] = {0, "error", "invalid", "drive"};
- AdamLog("Seek Status: %s\n", status[st0 >> 6]);
- }
-
- if (cyl == cyli) {
- FDCMotorCtrl(base, FDC_MOTOR_OFF);
- return 0;
- }
- }
-
- AdamErr("FDC Seek TimeOut");
- FDCMotorCtrl(base, FDC_MOTOR_OFF);
- return -1;
-}
-
-U0 FDCRead(U16 base, U8 cyl, U8 head, U8 sect, U8 trklen)
-{
- // Read data from disk (single-track)
- static U8 flags;
- flags = 0x40; // Multi-track off, MFM modulation
- static U64 cmd;
- cmd = FDC_READ_DATA | flags;
- FDCIrq = FALSE;
-
- U64 st0, st1, st2, rcyl, rhd, rsect, rsectsize;
-
- FDCMotorCtrl(base, FDC_MOTOR_ON);
-
- AdamLog("Cmd: %d\nParams: %d %d %d %d %d %d %d %d\n",cmd,head<<2,cyl,head,sect,2,trklen,0x1B,0xFF);
-
- // Prepare the DMA controller
- AdamLog("Preparing DMA\n");
- FDCDMAInit(512*(trklen - sect + 1));
- FDCDMAPrepRead();
-
- FDCSendCmd(base, cmd);
- FDCSendCmd(base, head << 2); // Drive 0, specified head
- FDCSendCmd(base, cyl);
- FDCSendCmd(base, head);
- FDCSendCmd(base, sect);
- FDCSendCmd(base, 2); // Sector size = 2 = 512 bytes
- FDCSendCmd(base, trklen); // Track Length/Max Sector No.
- FDCSendCmd(base, 0x1B); // GAP3 Length = 27 (3.5")
- FDCSendCmd(base, 0xFF); // Data Length (irrelevant)
-
- // Wait for xfer to complete
- while (!FDCIrq) Yield;
-
- st0 = FDCReadData(base);
- st1 = FDCReadData(base);
- st2 = FDCReadData(base);
- rcyl = FDCReadData(base);
- rhd = FDCReadData(base);
- rsect = FDCReadData(base);
- rsectsize = FDCReadData(base);
-
- AdamLog("Read Results:\nST0: %d\nST1: %d\nST2: %d\nCyl: %d\nHead: %d\nSect: %d\nSect Size: %d\n",st0,st1,st2,rcyl,rhd,rsect,rsectsize);
-
- FDCMotorCtrl(base, FDC_MOTOR_OFF);
-}
-
-
-U0 FDCReadMulti(U16 base, U8 cyl, U8 head, U8 sect, U8 trklen)
-{
- // Read data from disk (multi-track)
- static U8 flags;
- flags = 0xC0; // Multi-track on, MFM modulation
- static U64 cmd;
- cmd = FDC_READ_DATA | flags;
- FDCIrq = FALSE;
-
- U64 st0, st1, st2, rcyl, rhd, rsect, rsectsize;
-
- FDCMotorCtrl(base, FDC_MOTOR_ON);
-
- AdamLog("Cmd: %d\nParams: %d %d %d %d %d %d %d %d\n",cmd,head<<2,cyl,head,sect,2,trklen,0x1B,0xFF);
-
- // Prepare the DMA controller
- AdamLog("Preparing DMA\n");
- FDCDMAInit(512*(trklen - sect + 1)*2);
- FDCDMAPrepRead();
-
- FDCSendCmd(base, cmd);
- FDCSendCmd(base, head << 2); // Drive 0, specified head
- FDCSendCmd(base, cyl);
- FDCSendCmd(base, head);
- FDCSendCmd(base, sect);
- FDCSendCmd(base, 2); // Sector size = 2 = 512 bytes
- FDCSendCmd(base, trklen); // Track Length/Max Sector No.
- FDCSendCmd(base, 0x1B); // GAP3 Length = 27 (3.5")
- FDCSendCmd(base, 0xFF); // Data Length (irrelevant)
-
- // Wait for the xfer to complete
- while (!FDCIrq) Yield;
-
- st0 = FDCReadData(base);
- st1 = FDCReadData(base);
- st2 = FDCReadData(base);
- rcyl = FDCReadData(base);
- rhd = FDCReadData(base);
- rsect = FDCReadData(base);
- rsectsize = FDCReadData(base);
-
- AdamLog("Read Results:\nST0: %d\nST1: %d\nST2: %d\nCyl: %d\nHead: %d\nSect: %d\nSect Size: %d\n",st0,st1,st2,rcyl,rhd,rsect,rsectsize);
-
- FDCMotorCtrl(base, FDC_MOTOR_OFF);
-}
-
-U0 FDCWrite(U16 base, U8 cyl, U8 head, U8 sect, U8 trklen)
-{
- // Write data to disk (single-track)
- static U8 flags;
- flags = 0x40; // Multi-track off, MFM modulation
- static U64 cmd;
- cmd = FDC_WRITE_DATA | flags;
- FDCIrq = FALSE;
-
- U64 st0, st1, st2, rcyl, rhd, rsect, rsectsize;
-
- FDCMotorCtrl(base, FDC_MOTOR_ON);
-
- AdamLog("Cmd: %d\nParams: %d %d %d %d %d %d %d %d\n",cmd,head<<2,cyl,head,sect,2,trklen,0x1B,0xFF);
-
- // Prepare the DMA controller
- AdamLog("Preparing DMA\n");
- FDCDMAInit(512*(trklen - sect + 1));
- FDCDMAPrepWrite();
-
- FDCSendCmd(base, cmd);
- FDCSendCmd(base, head << 2); // Drive 0, specified head
- FDCSendCmd(base, cyl);
- FDCSendCmd(base, head);
- FDCSendCmd(base, sect);
- FDCSendCmd(base, 2); // Sector size = 2 = 512 bytes
- FDCSendCmd(base, trklen); // Track Length/Max Sector No.
- FDCSendCmd(base, 0x1B); // GAP3 Length = 27 (3.5")
- FDCSendCmd(base, 0xFF); // Data Length (irrelevant)
-
- // Wait for xfer to complete
- while (!FDCIrq) Yield;
-
- st0 = FDCReadData(base);
- st1 = FDCReadData(base);
- st2 = FDCReadData(base);
- rcyl = FDCReadData(base);
- rhd = FDCReadData(base);
- rsect = FDCReadData(base);
- rsectsize = FDCReadData(base);
-
- AdamLog("Read Results:\nST0: %d\nST1: %d\nST2: %d\nCyl: %d\nHead: %d\nSect: %d\nSect Size: %d\n",st0,st1,st2,rcyl,rhd,rsect,rsectsize);
-
- FDCMotorCtrl(base, FDC_MOTOR_OFF);
-}
-
-
-U0 FDCWriteMulti(U16 base, U8 cyl, U8 head, U8 sect, U8 trklen)
-{
- // Write data to disk (multi-track)
- static U8 flags;
- flags = 0xC0; // Multi-track on, MFM modulation
- static U64 cmd;
- cmd = FDC_WRITE_DATA | flags;
- FDCIrq = FALSE;
-
- U64 st0, st1, st2, rcyl, rhd, rsect, rsectsize;
-
- FDCMotorCtrl(base, FDC_MOTOR_ON);
-
- AdamLog("Cmd: %d\nParams: %d %d %d %d %d %d %d %d\n",cmd,head<<2,cyl,head,sect,2,trklen,0x1B,0xFF);
-
- // Prepare the DMA controller
- AdamLog("Preparing DMA\n");
- FDCDMAInit(512*(trklen - sect + 1)*2);
- FDCDMAPrepRead();
-
- FDCSendCmd(base, cmd);
- FDCSendCmd(base, head << 2); // Drive 0, specified head
- FDCSendCmd(base, cyl);
- FDCSendCmd(base, head);
- FDCSendCmd(base, sect);
- FDCSendCmd(base, 2); // Sector size = 2 = 512 bytes
- FDCSendCmd(base, trklen); // Track Length/Max Sector No.
- FDCSendCmd(base, 0x1B); // GAP3 Length = 27 (3.5")
- FDCSendCmd(base, 0xFF); // Data Length (irrelevant)
-
- // Wait for the xfer to complete
- while (!FDCIrq) Yield;
-
- st0 = FDCReadData(base);
- st1 = FDCReadData(base);
- st2 = FDCReadData(base);
- rcyl = FDCReadData(base);
- rhd = FDCReadData(base);
- rsect = FDCReadData(base);
- rsectsize = FDCReadData(base);
-
- AdamLog("Read Results:\nST0: %d\nST1: %d\nST2: %d\nCyl: %d\nHead: %d\nSect: %d\nSect Size: %d\n",st0,st1,st2,rcyl,rhd,rsect,rsectsize);
-
- FDCMotorCtrl(base, FDC_MOTOR_OFF);
-} \ No newline at end of file