|
|
1.1 ! root 1: /* Floppy drive emulation */ ! 2: ! 3: ! 4: #include "ioMem.h" ! 5: #include "ioMemTables.h" ! 6: #include "m68000.h" ! 7: #include "configuration.h" ! 8: #include "sysReg.h" ! 9: #include "dma.h" ! 10: #include "floppy.h" ! 11: #include "cycInt.h" ! 12: #include "file.h" ! 13: #include "statusbar.h" ! 14: ! 15: ! 16: #define LOG_FLP_REG_LEVEL LOG_DEBUG ! 17: #define LOG_FLP_CMD_LEVEL LOG_DEBUG ! 18: ! 19: #define IO_SEG_MASK 0x1FFFF ! 20: ! 21: ! 22: /* Controller */ ! 23: struct { ! 24: Uint8 sra; /* Status Register A (ro) */ ! 25: Uint8 srb; /* Status Register B (ro) */ ! 26: Uint8 dor; /* Digital Output Register (rw) */ ! 27: Uint8 msr; /* Main Status Register (ro) */ ! 28: Uint8 dsr; /* Data Rate Select Register (wo) */ ! 29: Uint8 fifo[16]; /* Data FIFO (rw) */ ! 30: Uint8 din; /* Digital Input Register (wo) */ ! 31: Uint8 ccr; /* Configuration Control Register (ro) */ ! 32: Uint8 ctrl; /* External Control (rw) */ ! 33: ! 34: Uint8 st[4]; /* Internal Status Registers */ ! 35: Uint8 pcn; /* Cylinder Number */ ! 36: ! 37: Uint8 sel; ! 38: Uint8 eis; ! 39: } flp; ! 40: ! 41: Uint8 floppy_select = 0; ! 42: ! 43: /* Drives */ ! 44: struct { ! 45: Uint8 cyl; ! 46: Uint8 head; ! 47: Uint8 sector; ! 48: Uint8 blocksize; ! 49: ! 50: FILE* dsk; ! 51: Uint32 floppysize; ! 52: ! 53: Uint32 seekoffset; ! 54: ! 55: bool spinning; ! 56: ! 57: bool protected; ! 58: bool inserted; ! 59: bool connected; ! 60: } flpdrv[FLP_MAX_DRIVES]; ! 61: ! 62: ! 63: /* Register bits */ ! 64: ! 65: #define SRA_INT 0x80 ! 66: #define SRA_DRV1_N 0x40 ! 67: #define SRA_STEP 0x20 ! 68: #define SRA_TRK0_N 0x10 ! 69: #define SRA_HDSEL 0x08 ! 70: #define SRA_INDEX_N 0x04 ! 71: #define SRA_WP_N 0x02 ! 72: #define SRA_DIR 0x01 ! 73: ! 74: #define SRB_ALL1 0xC0 ! 75: #define SRB_DRVSEL0_N 0x20 ! 76: #define SRB_W_TOGGLE 0x10 ! 77: #define SRB_R_TOGGLE 0x08 ! 78: #define SRB_W_ENABLE 0x04 ! 79: #define SRB_MOTEN_MASK 0x03 ! 80: ! 81: #define DOR_MOT3EN 0x80 ! 82: #define DOR_MOT2EN 0x40 ! 83: #define DOR_MOT1EN 0x20 ! 84: #define DOR_MOT0EN 0x10 ! 85: #define DOR_MOTEN_MASK 0xF0 ! 86: #define DOR_DMA_N 0x08 ! 87: #define DOR_RESET_N 0x04 ! 88: #define DOR_SEL_MSK 0x03 ! 89: ! 90: #define STAT_RQM 0x80 ! 91: #define STAT_DIO 0x40 /* read = 1 */ ! 92: #define STAT_NONDMA 0x20 ! 93: #define STAT_CMDBSY 0x10 ! 94: #define STAT_DRV3BSY 0x08 ! 95: #define STAT_DRV2BSY 0x04 ! 96: #define STAT_DRV1BSY 0x02 ! 97: #define STAT_DRV0BSY 0x01 ! 98: #define STAT_BSY_MASK 0x0F ! 99: ! 100: #define DSR_RESET 0x80 ! 101: #define DSR_PDOWN 0x40 ! 102: #define DSR_0 0x20 ! 103: #define DSR_PRE_MASK 0x1C ! 104: #define DSR_RATE_MASK 0x03 ! 105: ! 106: #define DIR_DSKCHG 0x80 ! 107: #define DIR_HIDENS_N 0x01 ! 108: ! 109: #define CCR_RATE_MASK 0x03 ! 110: ! 111: #define CTRL_EJECT 0x80 ! 112: #define CTRL_82077 0x40 ! 113: #define CTRL_DRV_ID 0x04 ! 114: #define CTRL_MEDIA_ID1 0x02 ! 115: #define CTRL_MEDIA_ID0 0x01 ! 116: ! 117: ! 118: /* Functions */ ! 119: void floppy_reset(bool hard); ! 120: Uint8 floppy_fifo_read(void); ! 121: void floppy_fifo_write(Uint8 val); ! 122: Uint8 floppy_dor_read(void); ! 123: void floppy_dor_write(Uint8 val); ! 124: Uint8 floppy_sra_read(void); ! 125: ! 126: ! 127: void FLP_StatA_Read(void) { // 0x02014100 ! 128: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = floppy_sra_read(); ! 129: Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Status A read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 130: } ! 131: ! 132: void FLP_StatB_Read(void) { // 0x02014101 ! 133: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = flp.srb|SRB_ALL1; ! 134: Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Status B read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 135: } ! 136: ! 137: void FLP_DataOut_Read(void) { // 0x02014102 ! 138: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = floppy_dor_read(); ! 139: Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Data out read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 140: } ! 141: ! 142: void FLP_DataOut_Write(void) { ! 143: floppy_dor_write(IoMem[IoAccessCurrentAddress & IO_SEG_MASK]); ! 144: Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Data out write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 145: } ! 146: ! 147: void FLP_Status_Read(void) { // 0x02014104 ! 148: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = flp.msr; ! 149: Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Main status read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 150: } ! 151: ! 152: void FLP_DataRate_Write(void) { ! 153: flp.dsr = IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 154: Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Data rate write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 155: ! 156: if (flp.dsr&DSR_RESET) { ! 157: floppy_reset(false); ! 158: flp.dsr&=~DSR_RESET; ! 159: } ! 160: } ! 161: ! 162: void FLP_FIFO_Read(void) { // 0x02014105 ! 163: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = floppy_fifo_read(); ! 164: Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] FIFO read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 165: } ! 166: ! 167: void FLP_FIFO_Write(void) { ! 168: Uint8 val = IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 169: Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] FIFO write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 170: ! 171: floppy_fifo_write(val); ! 172: } ! 173: ! 174: void FLP_DataIn_Read(void) { // 0x02014107 ! 175: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = flp.din; ! 176: Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Data in read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 177: } ! 178: ! 179: void FLP_Configuration_Write(void) { ! 180: flp.ccr = IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 181: Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Configuration write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 182: } ! 183: ! 184: void FLP_Control_Read(void) { // 0x02014108 ! 185: Uint8 val; ! 186: if (ConfigureParams.System.nMachineType==NEXT_CUBE030) ! 187: val=flp.ctrl&~CTRL_DRV_ID; ! 188: else ! 189: val=flp.ctrl; ! 190: ! 191: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = val; ! 192: Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Control read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 193: } ! 194: ! 195: void FLP_Select_Write(void) { ! 196: Uint8 val; ! 197: val = IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 198: Log_Printf(LOG_DEBUG,"[Floppy] Select write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 199: ! 200: if (ConfigureParams.System.nMachineType!=NEXT_CUBE030) { ! 201: set_floppy_select(val&CTRL_82077,false); ! 202: } ! 203: ! 204: if (val&CTRL_EJECT) { ! 205: Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Ejecting floppy disk"); ! 206: Floppy_Eject(-1); ! 207: } ! 208: } ! 209: ! 210: void set_floppy_select(Uint8 sel, bool osp) { ! 211: if (sel) { ! 212: Log_Printf(LOG_DEBUG,"[%s] Selecting floppy controller",osp?"OSP":"Floppy"); ! 213: floppy_select = 1; ! 214: } else { ! 215: Log_Printf(LOG_FLP_REG_LEVEL,"[%s] Selecting SCSI controller",osp?"OSP":"Floppy"); ! 216: floppy_select = 0; ! 217: } ! 218: } ! 219: ! 220: enum { ! 221: FLP_STATE_WRITE, ! 222: FLP_STATE_READ, ! 223: FLP_STATE_FORMAT, ! 224: FLP_STATE_INTERRUPT, ! 225: FLP_STATE_DONE ! 226: } flp_io_state; ! 227: ! 228: int flp_sector_counter = 0; ! 229: int flp_io_drv = 0; ! 230: ! 231: ! 232: /* Internal registers */ ! 233: ! 234: #define ST0_IC 0xC0 /* Interrupt Code (0 = normal termination) */ ! 235: #define ST0_SE 0x20 /* Seek End */ ! 236: #define ST0_EC 0x10 /* Equipment Check */ ! 237: #define ST0_H 0x04 /* Head Address */ ! 238: #define ST0_DS 0x03 /* Drive Select */ ! 239: ! 240: #define ST1_EN 0x80 /* End of Cylinder */ ! 241: #define ST1_DE 0x20 /* Data Error */ ! 242: #define ST1_OR 0x10 /* Overrun/Underrun */ ! 243: #define ST1_ND 0x04 /* No Data */ ! 244: #define ST1_NW 0x02 /* Not writable */ ! 245: #define ST1_MA 0x01 /* Missing Address Mark */ ! 246: ! 247: #define ST2_CM 0x40 /* Control Mark */ ! 248: #define ST2_DD 0x20 /* Data Error in Data Field */ ! 249: #define ST2_WC 0x10 /* Wrong Cylinder */ ! 250: #define ST2_BC 0x02 /* Bad Cylinder */ ! 251: #define ST2_MD 0x01 /* Missing Data Address Mark */ ! 252: ! 253: #define ST3_WP 0x40 /* Write Protected */ ! 254: #define ST3_T0 0x10 /* Track 0 */ ! 255: #define ST3_HD 0x04 /* Head Address */ ! 256: #define ST3_DS 0x03 /* Drive Select */ ! 257: ! 258: ! 259: #define IC_NORMAL 0x00 ! 260: #define IC_ABNORMAL 0x40 ! 261: #define IC_INV_CMD 0x80 ! 262: ! 263: ! 264: ! 265: void floppy_reset(bool hard) { ! 266: Log_Printf(LOG_WARN,"[Floppy] Reset."); ! 267: ! 268: flp.sra &= ~(SRA_INT|SRA_STEP|SRA_HDSEL|SRA_DIR); ! 269: flp.srb &= ~(SRB_R_TOGGLE|SRB_W_TOGGLE); ! 270: flp.msr |= STAT_RQM; ! 271: flp.msr &= ~STAT_DIO; ! 272: ! 273: if (hard) { ! 274: flp_io_state = FLP_STATE_DONE; ! 275: flp.dor &= ~DOR_RESET_N; ! 276: flp.srb &= ~(SRB_MOTEN_MASK|SRB_DRVSEL0_N); ! 277: flp.din &= ~DIR_HIDENS_N; ! 278: flp.st[0]=flp.st[1]=flp.st[2]=flp.st[3]=0; ! 279: flp.pcn=0; ! 280: } else { ! 281: /* Single poll interrupt after reset (delay = 250 ms) */ ! 282: flp_io_state = FLP_STATE_INTERRUPT; ! 283: CycInt_AddRelativeInterruptUs(250*1000, 0, INTERRUPT_FLP_IO); ! 284: } ! 285: } ! 286: ! 287: /* Floppy commands */ ! 288: ! 289: #define CMD_MT_MSK 0x80 ! 290: #define CMD_MFM_MSK 0x40 ! 291: #define CMD_SK_MSK 0x20 ! 292: #define CMD_OPCODE_MSK 0x1F ! 293: ! 294: #define CMD_READ 0x06 ! 295: #define CMD_READ_DEL 0x0C ! 296: #define CMD_WRITE 0x05 ! 297: #define CMD_WRITE_DEL 0x09 ! 298: #define CMD_READ_TRK 0x02 ! 299: #define CMD_VERIFY 0x16 ! 300: #define CMD_VERSION 0x10 ! 301: #define CMD_FORMAT 0x0D ! 302: #define CMD_SCAN_E 0x11 ! 303: #define CMD_SCAN_LE 0x19 ! 304: #define CMD_SCAN_HE 0x1D ! 305: #define CMD_RECAL 0x07 ! 306: #define CMD_INTSTAT 0x08 ! 307: #define CMD_SPECIFY 0x03 ! 308: #define CMD_DRV_STATUS 0x04 ! 309: #define CMD_SEEK 0x0F ! 310: #define CMD_CONFIGURE 0x13 ! 311: #define CMD_DUMPREG 0x0E ! 312: #define CMD_READ_ID 0x0A ! 313: #define CMD_PERPEND 0x12 ! 314: #define CMD_LOCK 0x14 ! 315: ! 316: Uint8 cmd_data_size[] = { ! 317: 0,0,8,2,1,8,8,1, ! 318: 0,8,1,0,8,5,0,2, ! 319: 0,8,1,3,0,0,8,0, ! 320: 0,8,0,0,0,8,0,0 ! 321: }; ! 322: ! 323: bool cmd_phase = false; ! 324: int cmd_size = 0; ! 325: int cmd_limit = 0; ! 326: Uint8 command; ! 327: Uint8 cmd_data[8]; ! 328: ! 329: int result_size = 0; ! 330: ! 331: static void floppy_interrupt(void) { ! 332: Log_Printf(LOG_FLP_CMD_LEVEL,"[Floppy] Interrupt."); ! 333: ! 334: if (result_size>0) { ! 335: /* Go to result phase */ ! 336: flp.msr |= (STAT_RQM|STAT_DIO); ! 337: } else { ! 338: flp.msr |= STAT_RQM; ! 339: } ! 340: ! 341: flp.msr &= ~(STAT_BSY_MASK); ! 342: flp.sra |= SRA_INT; ! 343: set_interrupt(INT_PHONE, SET_INT); ! 344: } ! 345: ! 346: /* -- Helpers -- */ ! 347: ! 348: /* Geometry */ ! 349: #define SIZE_720K 737280 ! 350: #define SIZE_1440K 1474560 ! 351: #define SIZE_2880K 2949120 ! 352: ! 353: #define NUM_CYLINDERS 80 ! 354: #define TRACKS_PER_CYL 2 ! 355: ! 356: static Uint32 physical_to_logical_sector(Uint8 c, Uint8 h, Uint8 s, int drive) { ! 357: Uint32 disksize = flpdrv[drive].floppysize; ! 358: Uint32 blocksize = 0x80<<flpdrv[drive].blocksize; ! 359: Uint32 spt = disksize/blocksize/TRACKS_PER_CYL/NUM_CYLINDERS; ! 360: ! 361: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Geometry: Cylinders: %i, Tracks per cylinder: %i, Sectors per track: %i, Blocksize: %i", ! 362: NUM_CYLINDERS,TRACKS_PER_CYL,spt,blocksize); ! 363: ! 364: if (s>spt) { ! 365: Log_Printf(LOG_WARN, "[Floppy] Geometry error: sector (%i) beyond limit (%i)!",s,spt); ! 366: flp.st[0] |= IC_ABNORMAL; ! 367: flp.st[1] |= ST1_EN; ! 368: } ! 369: ! 370: return (((c*TRACKS_PER_CYL)+h)*spt)+s-1; ! 371: } ! 372: ! 373: static void check_blocksize(int drive, Uint8 blocksize) { ! 374: if (blocksize!=flpdrv[drive].blocksize) { ! 375: Log_Printf(LOG_WARN, "[Floppy] Geometry error: Blocksize not supported (%i)!",blocksize); ! 376: flp.st[0] |= IC_ABNORMAL; ! 377: flp.st[1] |= ST1_ND; ! 378: } ! 379: } ! 380: ! 381: static void check_protection(int drive) { ! 382: if (flpdrv[drive].protected) { ! 383: Log_Printf(LOG_WARN, "[Floppy] Protection error: Disk is read-only!"); ! 384: flp.st[0] |= IC_ABNORMAL; ! 385: flp.st[1] |= ST1_NW; ! 386: } ! 387: } ! 388: ! 389: static void floppy_seek_track(Uint8 c, Uint8 h, int drive) { ! 390: if (c>(NUM_CYLINDERS-1)) /* CHECK: does this cause an error? */ ! 391: c=(NUM_CYLINDERS-1); ! 392: ! 393: flp.st[0] |= ST0_SE; ! 394: ! 395: flpdrv[drive].seekoffset = (flpdrv[drive].cyl < c) ? (c - flpdrv[drive].cyl) : (flpdrv[drive].cyl - c); ! 396: flpdrv[drive].cyl = c; ! 397: flpdrv[drive].head = h; ! 398: } ! 399: ! 400: /* Timings */ ! 401: #define FLP_SEEK_TIME 200000 /* 200 ms */ ! 402: ! 403: static int get_sector_time(int drive) { ! 404: switch (flpdrv[drive].floppysize) { ! 405: case SIZE_720K: return 22000; ! 406: case SIZE_1440K: return 11000; ! 407: case SIZE_2880K: return 5500; ! 408: default: return 1000; ! 409: } ! 410: } ! 411: ! 412: static int get_seek_time(int drive) { ! 413: if (flpdrv[drive].seekoffset > NUM_CYLINDERS) { ! 414: return FLP_SEEK_TIME; ! 415: } ! 416: ! 417: return (flpdrv[drive].seekoffset * FLP_SEEK_TIME / NUM_CYLINDERS); ! 418: } ! 419: ! 420: /* Media IDs for control register */ ! 421: #define MEDIA_ID_NONE 0 ! 422: #define MEDIA_ID_720K 3 ! 423: #define MEDIA_ID_1440K 2 ! 424: #define MEDIA_ID_2880K 1 ! 425: #define MEDIA_ID_MSK 3 ! 426: ! 427: static Uint8 get_media_id(int drive) { ! 428: if (!flpdrv[drive].inserted) { ! 429: return MEDIA_ID_NONE; ! 430: } else { ! 431: switch (flpdrv[drive].floppysize) { ! 432: case SIZE_720K: return MEDIA_ID_720K; ! 433: case SIZE_1440K: return MEDIA_ID_1440K; ! 434: case SIZE_2880K: return MEDIA_ID_2880K; ! 435: default: return MEDIA_ID_NONE; ! 436: } ! 437: } ! 438: } ! 439: ! 440: /* Validate data rate */ ! 441: #define CCR_RATE250 0x02 ! 442: #define CCR_RATE500 0x00 ! 443: #define CCR_RATE1000 0x03 ! 444: ! 445: static void check_data_rate(int drive) { ! 446: switch (flpdrv[drive].floppysize) { ! 447: case SIZE_720K: ! 448: if ((flp.ccr&CCR_RATE_MASK)==CCR_RATE250) { ! 449: return; ! 450: } ! 451: break; ! 452: case SIZE_1440K: ! 453: if ((flp.ccr&CCR_RATE_MASK)==CCR_RATE500) { ! 454: return; ! 455: } ! 456: break; ! 457: case SIZE_2880K: ! 458: if ((flp.ccr&CCR_RATE_MASK)==CCR_RATE1000) { ! 459: return; ! 460: } ! 461: break; ! 462: ! 463: default: ! 464: break; ! 465: } ! 466: Log_Printf(LOG_WARN, "[Floppy] Invalid data rate %02X",flp.ccr&CCR_RATE_MASK); ! 467: flp.st[0] |= IC_ABNORMAL; ! 468: flp.st[1] |= ST1_ND; ! 469: } ! 470: ! 471: static void send_rw_status(int drive) { ! 472: flp.st[0] |= drive|(flpdrv[drive].head<<2); ! 473: flp.fifo[0] = flp.st[0]; ! 474: flp.fifo[1] = flp.st[1]; ! 475: flp.fifo[2] = flp.st[2]; ! 476: flp.fifo[3] = flpdrv[drive].cyl; ! 477: flp.fifo[4] = flpdrv[drive].head; ! 478: flp.fifo[5] = flpdrv[drive].sector; ! 479: flp.fifo[6] = flpdrv[drive].blocksize; ! 480: result_size = 7; ! 481: } ! 482: ! 483: /* -- Floppy commands -- */ ! 484: ! 485: static void floppy_read(void) { ! 486: int drive = cmd_data[0]&0x03; ! 487: int head = (cmd_data[0]&0x04)>>2; ! 488: Uint8 c = cmd_data[1]; ! 489: Uint8 h = cmd_data[2]; ! 490: Uint8 s = cmd_data[3]; ! 491: Uint8 bs = cmd_data[4]; ! 492: ! 493: Uint32 sector_size, num_sectors, logical_sec; ! 494: ! 495: flp.st[0] = flp.st[1] = flp.st[2] = 0; ! 496: ! 497: /* If implied seek is enabled, seek track */ ! 498: if (flp.eis) { ! 499: floppy_seek_track(c, h, drive); ! 500: } ! 501: /* Set start sector */ ! 502: flpdrv[drive].sector = s; ! 503: ! 504: /* Match actual track with specified track */ ! 505: if (flpdrv[drive].cyl!=c || flpdrv[drive].head!=h || flpdrv[drive].head!=head) { ! 506: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Read: track mismatch!"); ! 507: flp.st[0]|=IC_ABNORMAL; ! 508: flp.st[2]|=ST2_WC; ! 509: } ! 510: /* Validate blocksize */ ! 511: check_blocksize(drive,bs); ! 512: sector_size = 0x80<<bs; ! 513: ! 514: /* Validate data rate */ ! 515: check_data_rate(drive); ! 516: ! 517: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Read: Cylinder=%i, Head=%i, Sector=%i, Blocksize=%i", ! 518: flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,sector_size); ! 519: ! 520: /* Get sector transfer count and logical sector offset */ ! 521: num_sectors = cmd_data[5]-cmd_data[3]+1; ! 522: logical_sec = physical_to_logical_sector(flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,drive); ! 523: ! 524: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Read %i sectors at offset %i",num_sectors,logical_sec); ! 525: ! 526: if (flp.st[0]&IC_ABNORMAL) { ! 527: send_rw_status(drive); ! 528: flp_io_state = FLP_STATE_INTERRUPT; ! 529: } else { ! 530: flp_buffer.size = 0; ! 531: flp_buffer.limit = sector_size; ! 532: flp_sector_counter = num_sectors; ! 533: flp_io_drv = drive; ! 534: flp_io_state = FLP_STATE_READ; ! 535: } ! 536: CycInt_AddRelativeInterruptUs(get_seek_time(drive) + get_sector_time(drive), 100, INTERRUPT_FLP_IO); ! 537: } ! 538: ! 539: static void floppy_write(void) { ! 540: int drive = cmd_data[0]&0x03; ! 541: int head = (cmd_data[0]&0x04)>>2; ! 542: Uint8 c = cmd_data[1]; ! 543: Uint8 h = cmd_data[2]; ! 544: Uint8 s = cmd_data[3]; ! 545: Uint8 bs = cmd_data[4]; ! 546: ! 547: Uint32 sector_size, num_sectors, logical_sec; ! 548: ! 549: flp.st[0] = flp.st[1] = flp.st[2] = 0; ! 550: ! 551: /* If implied seek is enabled, seek track */ ! 552: if (flp.eis) { ! 553: floppy_seek_track(c, h, drive); ! 554: } ! 555: /* Set start sector */ ! 556: flpdrv[drive].sector = s; ! 557: ! 558: /* Match actual track with specified track */ ! 559: if (flpdrv[drive].cyl!=c || flpdrv[drive].head!=h || flpdrv[drive].head!=head) { ! 560: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Write: track mismatch!"); ! 561: flp.st[0]|=IC_ABNORMAL; ! 562: flp.st[2]|=ST2_WC; ! 563: } ! 564: /* Validate blocksize */ ! 565: check_blocksize(drive,bs); ! 566: sector_size = 0x80<<bs; ! 567: ! 568: /* Validate data rate */ ! 569: check_data_rate(drive); ! 570: ! 571: /* Check protection */ ! 572: check_protection(drive); ! 573: ! 574: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Write: Cylinder=%i, Head=%i, Sector=%i, Blocksize=%i", ! 575: flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,sector_size); ! 576: ! 577: /* Get sector transfer count and logical sector offset */ ! 578: num_sectors = cmd_data[5]-cmd_data[3]+1; ! 579: logical_sec = physical_to_logical_sector(flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,drive); ! 580: ! 581: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Write %i sectors at offset %i",num_sectors,logical_sec); ! 582: ! 583: if (flp.st[0]&IC_ABNORMAL) { ! 584: send_rw_status(drive); ! 585: flp_io_state = FLP_STATE_INTERRUPT; ! 586: } else { ! 587: flp_buffer.size = 0; ! 588: flp_buffer.limit = sector_size; ! 589: flp_sector_counter = num_sectors; ! 590: flp_io_drv = drive; ! 591: flp_io_state = FLP_STATE_WRITE; ! 592: } ! 593: CycInt_AddRelativeInterruptUs(get_seek_time(drive) + get_sector_time(drive), 100, INTERRUPT_FLP_IO); ! 594: } ! 595: ! 596: static void floppy_format(void) { ! 597: int drive = cmd_data[0]&0x03; ! 598: int head = (cmd_data[0]&0x04)>>2; ! 599: ! 600: flp.st[0] = flp.st[1] = flp.st[2] = 0; ! 601: ! 602: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Format: Cylinder=%i, Head=%i",flpdrv[drive].cyl,head); ! 603: ! 604: /* Validate data rate */ ! 605: check_data_rate(drive); ! 606: ! 607: /* Check protection */ ! 608: check_protection(drive); ! 609: ! 610: if (flp.st[0]&IC_ABNORMAL) { ! 611: send_rw_status(drive); ! 612: flp_io_state = FLP_STATE_INTERRUPT; ! 613: } else { ! 614: flp_buffer.size = 0; ! 615: flp_buffer.limit = 4; ! 616: flp_io_drv = drive; ! 617: flp_io_state = FLP_STATE_FORMAT; ! 618: CycInt_AddRelativeInterruptUs(get_seek_time(drive) + get_sector_time(drive), 100, INTERRUPT_FLP_IO); ! 619: } ! 620: } ! 621: ! 622: static void floppy_read_id(void) { ! 623: int drive = cmd_data[0]&0x03; ! 624: int head = (cmd_data[0]&0x04)>>2; ! 625: ! 626: Uint32 sec_size = 0x80<<flpdrv[drive].blocksize; ! 627: ! 628: if (flpdrv[drive].head!=head) ! 629: abort(); ! 630: ! 631: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Read ID: Cylinder=%i, Head=%i, Sector=%i, Blocksize=%i", ! 632: flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,sec_size); ! 633: ! 634: flp.st[0] = flp.st[1] = flp.st[2] = 0; ! 635: ! 636: check_data_rate(drive); /* check data rate */ ! 637: send_rw_status(drive); ! 638: ! 639: flp_io_state = FLP_STATE_INTERRUPT; ! 640: CycInt_AddRelativeInterruptUs(get_seek_time(drive), 100, INTERRUPT_FLP_IO); ! 641: } ! 642: ! 643: static void floppy_recalibrate(void) { ! 644: int drive = cmd_data[0]&0x03; ! 645: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Drive = %i",drive); ! 646: ! 647: if (flpdrv[drive].connected) { ! 648: flp.msr |= (1<<drive); /* drive busy */ ! 649: flp.dor &= 0xFC; /* CHECK: really needed? */ ! 650: flp.dor |= drive; ! 651: flpdrv[drive].cyl = flp.pcn = 0; ! 652: ! 653: flp.st[0] = flp.st[1] = flp.st[2] = 0; ! 654: floppy_seek_track(0, 0, drive); ! 655: ! 656: /* Done */ ! 657: flp.st[0] = IC_NORMAL|ST0_SE; ! 658: flp.sra &= ~SRA_TRK0_N; ! 659: ! 660: flp_io_state = FLP_STATE_INTERRUPT; ! 661: CycInt_AddRelativeInterruptUs(get_seek_time(drive), 100, INTERRUPT_FLP_IO); ! 662: } ! 663: } ! 664: ! 665: static void floppy_seek(Uint8 relative) { ! 666: int drive = cmd_data[0]&0x03; ! 667: int head = (cmd_data[0]&0x04)>>2; ! 668: flp.st[0] = flp.st[1] = flp.st[2] = 0; ! 669: ! 670: if (relative) { ! 671: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Relative seek: Head %i: %i cylinders",head,0); ! 672: abort(); ! 673: } else { ! 674: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Seek: Head %i to cylinder %i",head,flpdrv[drive].cyl); ! 675: flp.st[0] = IC_NORMAL; ! 676: ! 677: floppy_seek_track(cmd_data[1], head, drive); ! 678: if (!(flp.st[0]&IC_ABNORMAL)) { ! 679: flp.pcn = flpdrv[drive].cyl; ! 680: } ! 681: } ! 682: ! 683: flp_io_state = FLP_STATE_INTERRUPT; ! 684: CycInt_AddRelativeInterruptUs(get_seek_time(drive), 100, INTERRUPT_FLP_IO); ! 685: } ! 686: ! 687: static void floppy_interrupt_status(void) { ! 688: /* Release interrupt */ ! 689: set_interrupt(INT_PHONE, RELEASE_INT); ! 690: flp.sra &= ~SRA_INT; ! 691: /* Go to result phase */ ! 692: flp.msr |= (STAT_RQM|STAT_DIO); ! 693: /* Return data */ ! 694: flp.fifo[0] = flp.st[0]; ! 695: flp.fifo[1] = flp.pcn; ! 696: result_size = 2; ! 697: } ! 698: ! 699: static void floppy_specify(void) { ! 700: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Specify: %02X %02X",cmd_data[0],cmd_data[1]); ! 701: ! 702: if (cmd_data[1]&0x01) { ! 703: Log_Printf(LOG_WARN, "[Floppy] Specify: Non-DMA mode"); ! 704: } else { ! 705: Log_Printf(LOG_WARN, "[Floppy] Specify: DMA mode"); ! 706: } ! 707: flp.msr |= STAT_RQM; ! 708: } ! 709: ! 710: static void floppy_configure(void) { ! 711: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Configure: %02X %02X %02X",cmd_data[0],cmd_data[1],cmd_data[2]); ! 712: ! 713: flp.eis = cmd_data[1]&0x40; /* Enable or disable implied seek */ ! 714: ! 715: if (cmd_data[1]&0x10) { ! 716: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Configure: disable polling"); ! 717: if (CycInt_InterruptActive(INTERRUPT_FLP_IO)) { ! 718: Log_Printf(LOG_WARN, "[Floppy] Disable pending reset poll interrupt"); ! 719: CycInt_RemovePendingInterrupt(INTERRUPT_FLP_IO); ! 720: } ! 721: } ! 722: if (cmd_data[2]) { ! 723: abort(); ! 724: } ! 725: flp.msr |= STAT_RQM; ! 726: } ! 727: ! 728: static void floppy_perpendicular(void) { ! 729: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Perpendicular: %02X",cmd_data[0]); ! 730: flp.msr |= STAT_RQM; ! 731: } ! 732: ! 733: static void floppy_unimplemented(void) { ! 734: flp.st[0] = IC_INV_CMD; ! 735: ! 736: flp.fifo[0] = flp.st[0]; ! 737: result_size = 1; ! 738: ! 739: flp_io_state = FLP_STATE_INTERRUPT; ! 740: CycInt_AddRelativeInterruptUs(1000, 100, INTERRUPT_FLP_IO); ! 741: } ! 742: ! 743: static void floppy_execute_cmd(void) { ! 744: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Executing %02X",command); ! 745: ! 746: switch (command&CMD_OPCODE_MSK) { ! 747: case CMD_READ: ! 748: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Read"); ! 749: floppy_read(); ! 750: break; ! 751: case CMD_READ_DEL: ! 752: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Read and delete"); ! 753: abort(); ! 754: break; ! 755: case CMD_WRITE: ! 756: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Write"); ! 757: floppy_write(); ! 758: break; ! 759: case CMD_WRITE_DEL: ! 760: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Write and delete"); ! 761: abort(); ! 762: break; ! 763: case CMD_READ_TRK: ! 764: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Read track"); ! 765: abort(); ! 766: break; ! 767: case CMD_VERIFY: ! 768: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Verify"); ! 769: abort(); ! 770: break; ! 771: case CMD_VERSION: ! 772: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Version"); ! 773: abort(); ! 774: break; ! 775: case CMD_FORMAT: ! 776: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Format"); ! 777: floppy_format(); ! 778: break; ! 779: case CMD_SCAN_E: ! 780: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Scan equal"); ! 781: abort(); ! 782: break; ! 783: case CMD_SCAN_LE: ! 784: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Scan lower or equal"); ! 785: abort(); ! 786: break; ! 787: case CMD_SCAN_HE: ! 788: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Scan higher or equal"); ! 789: abort(); ! 790: break; ! 791: case CMD_RECAL: ! 792: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Recalibrate"); ! 793: floppy_recalibrate(); ! 794: break; ! 795: case CMD_INTSTAT: ! 796: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Interrupt status"); ! 797: floppy_interrupt_status(); ! 798: break; ! 799: case CMD_SPECIFY: ! 800: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Specify"); ! 801: floppy_specify(); ! 802: break; ! 803: case CMD_DRV_STATUS: ! 804: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Drive status"); ! 805: abort(); ! 806: break; ! 807: case CMD_SEEK: ! 808: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Seek"); ! 809: floppy_seek(command&0x80); ! 810: break; ! 811: case CMD_CONFIGURE: ! 812: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Configure"); ! 813: floppy_configure(); ! 814: break; ! 815: case CMD_DUMPREG: ! 816: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Dump register"); ! 817: abort(); ! 818: break; ! 819: case CMD_READ_ID: ! 820: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Read ID"); ! 821: floppy_read_id(); ! 822: break; ! 823: case CMD_PERPEND: ! 824: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Perpendicular"); ! 825: floppy_perpendicular(); ! 826: break; ! 827: case CMD_LOCK: ! 828: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Lock"); ! 829: abort(); ! 830: break; ! 831: ! 832: default: ! 833: Log_Printf(LOG_WARN, "[Floppy] Command: Unknown"); ! 834: floppy_unimplemented(); ! 835: break; ! 836: } ! 837: Statusbar_BlinkLed(DEVICE_LED_FD); ! 838: } ! 839: ! 840: void floppy_fifo_write(Uint8 val) { ! 841: ! 842: flp.msr &= ~STAT_RQM; ! 843: ! 844: if (!cmd_phase) { ! 845: cmd_phase = true; ! 846: command = val; ! 847: cmd_limit = cmd_size = cmd_data_size[val&CMD_OPCODE_MSK]; ! 848: flp.msr |= STAT_RQM; ! 849: } else if (cmd_size>0) { ! 850: cmd_data[cmd_limit-cmd_size]=val; ! 851: cmd_size--; ! 852: flp.msr |= STAT_RQM; ! 853: } ! 854: ! 855: if (cmd_size==0) { ! 856: cmd_phase = false; ! 857: floppy_execute_cmd(); ! 858: } ! 859: } ! 860: ! 861: Uint8 floppy_fifo_read(void) { ! 862: int i; ! 863: Uint8 val; ! 864: if (result_size>0) { ! 865: val = flp.fifo[0]; ! 866: for (i=0; i<(16-1); i++) ! 867: flp.fifo[i]=flp.fifo[i+1]; ! 868: flp.fifo[16-1] = 0x00; ! 869: result_size--; ! 870: Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] FIFO reading byte, val=%02x", val); ! 871: } else { ! 872: Log_Printf(LOG_WARN,"[Floppy] FIFO is emtpy!"); ! 873: val = 0; ! 874: } ! 875: ! 876: if (result_size==0) { ! 877: flp.msr |= STAT_RQM; ! 878: flp.msr &= ~STAT_DIO; ! 879: /* FIXME: does this really belong here? */ ! 880: set_interrupt(INT_PHONE, RELEASE_INT); ! 881: flp.sra &= ~SRA_INT; ! 882: } ! 883: ! 884: return val; ! 885: } ! 886: ! 887: void floppy_dor_write(Uint8 val) { ! 888: if ((val&DOR_SEL_MSK)!=flp.sel) { ! 889: Log_Printf(LOG_FLP_CMD_LEVEL,"[Floppy] Selecting drive %i.",val&DOR_SEL_MSK); ! 890: } ! 891: flp.sel = val&DOR_SEL_MSK; ! 892: ! 893: flp.dor &= ~DOR_SEL_MSK; ! 894: flp.dor |= flp.sel; ! 895: ! 896: ! 897: if (!(val&DOR_RESET_N)) { ! 898: flp.dor &= ~DOR_RESET_N; ! 899: floppy_reset(false); ! 900: } else { ! 901: flp.dor |= DOR_RESET_N; ! 902: Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Clear reset state."); ! 903: } ! 904: if (flpdrv[flp.sel].connected) { ! 905: flp.ctrl &= ~CTRL_DRV_ID; ! 906: ! 907: if (val&(0x10<<flp.sel)) { /* motor enable */ ! 908: Log_Printf(LOG_FLP_CMD_LEVEL,"[Floppy] Starting motor of drive %i.",flp.sel); ! 909: flp.ctrl &= ~MEDIA_ID_MSK; ! 910: flp.ctrl |= get_media_id(flp.sel); ! 911: flpdrv[flp.sel].spinning = true; ! 912: } else { ! 913: Log_Printf(LOG_FLP_CMD_LEVEL,"[Floppy] Stopping motor of drive %i.",flp.sel); ! 914: flp.ctrl &= ~MEDIA_ID_MSK; /* CHECK: really delete ID? */ ! 915: flpdrv[flp.sel].spinning = false; ! 916: } ! 917: } else { ! 918: flp.ctrl |= CTRL_DRV_ID; ! 919: } ! 920: } ! 921: ! 922: Uint8 floppy_dor_read(void) { ! 923: int i; ! 924: Uint8 val = flp.dor&~DOR_MOTEN_MASK; /* clear motor bits */ ! 925: for (i=0; i<FLP_MAX_DRIVES; i++) { ! 926: if (flpdrv[i].spinning) { /* set motor bit if motor is on */ ! 927: val |= 0x10<<i; ! 928: } ! 929: } ! 930: return val; ! 931: } ! 932: ! 933: Uint8 floppy_sra_read(void) { ! 934: Uint8 val = flp.sra; ! 935: if (!flpdrv[flp.sel].protected) { ! 936: val|=SRA_WP_N; ! 937: } ! 938: return val; ! 939: } ! 940: ! 941: ! 942: /* -- Floppy I/O functions -- */ ! 943: ! 944: static void floppy_rw_nodata(void) { ! 945: Log_Printf(LOG_WARN, "[Floppy] Write: No more data from DMA. Stopping."); ! 946: /* Stop transfer */ ! 947: flp_sector_counter=0; ! 948: flp.st[0] |= IC_ABNORMAL; ! 949: flp.st[1] |= ST1_OR; ! 950: send_rw_status(flp_io_drv); ! 951: } ! 952: ! 953: static void floppy_format_done(void) { ! 954: int drive = flp_io_drv; ! 955: ! 956: Log_Printf(LOG_WARN, "[Floppy] Format: No more data from DMA. Done."); ! 957: ! 958: flp.st[0] = IC_NORMAL; ! 959: send_rw_status(drive); ! 960: } ! 961: ! 962: static void floppy_read_sector(void) { ! 963: int drive = flp_io_drv; ! 964: ! 965: /* Read from image */ ! 966: Uint32 sec_size = 0x80<<flpdrv[drive].blocksize; ! 967: Uint32 logical_sec = physical_to_logical_sector(flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,drive); ! 968: ! 969: if (flp.st[0]&IC_ABNORMAL) { ! 970: Log_Printf(LOG_WARN, "[Floppy] Read error. Bad sector offset (%i).",logical_sec); ! 971: flp_sector_counter=0; /* stop the transfer */ ! 972: flp_io_state = FLP_STATE_INTERRUPT; ! 973: send_rw_status(drive); ! 974: return; ! 975: } else { ! 976: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Read sector at offset %i",logical_sec); ! 977: ! 978: flp_buffer.size = flp_buffer.limit = sec_size; ! 979: File_Read(flp_buffer.data, flp_buffer.size, logical_sec*sec_size, flpdrv[drive].dsk); ! 980: flpdrv[drive].sector++; ! 981: flp_sector_counter--; ! 982: } ! 983: ! 984: if (flp_sector_counter==0) { ! 985: flp.st[0] = IC_ABNORMAL; /* Strange behavior of NeXT hardware */ ! 986: flp.st[1] |= ST1_EN; ! 987: send_rw_status(drive); ! 988: } ! 989: } ! 990: ! 991: static void floppy_write_sector(void) { ! 992: int drive = flp_io_drv; ! 993: ! 994: /* Write to image */ ! 995: Uint32 sec_size = 0x80<<flpdrv[drive].blocksize; ! 996: Uint32 logical_sec = physical_to_logical_sector(flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,drive); ! 997: ! 998: if (flp.st[0]&IC_ABNORMAL) { ! 999: Log_Printf(LOG_WARN, "[Floppy] Write error. Bad sector offset (%i).",logical_sec); ! 1000: flp_sector_counter=0; /* stop the transfer */ ! 1001: flp_io_state = FLP_STATE_INTERRUPT; ! 1002: send_rw_status(drive); ! 1003: return; ! 1004: } else { ! 1005: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Write sector at offset %i",logical_sec); ! 1006: ! 1007: File_Write(flp_buffer.data, flp_buffer.size, logical_sec*sec_size, flpdrv[drive].dsk); ! 1008: flp_buffer.size = 0; ! 1009: flp_buffer.limit = sec_size; ! 1010: flpdrv[drive].sector++; ! 1011: flp_sector_counter--; ! 1012: } ! 1013: ! 1014: if (flp_sector_counter==0) { ! 1015: flp.st[0] = IC_ABNORMAL; /* Strange behavior of NeXT hardware */ ! 1016: flp.st[1] |= ST1_EN; ! 1017: send_rw_status(drive); ! 1018: } ! 1019: } ! 1020: ! 1021: static void floppy_format_sector(void) { ! 1022: int drive = flp_io_drv; ! 1023: Uint8 c = flp_buffer.data[0]; ! 1024: Uint8 h = flp_buffer.data[1]; ! 1025: Uint8 s = flp_buffer.data[2]; ! 1026: Uint8 bs = flp_buffer.data[3]; ! 1027: ! 1028: if (c!=flpdrv[drive].cyl || h!=flpdrv[drive].head || bs!=flpdrv[drive].blocksize) { ! 1029: Log_Printf(LOG_WARN, "[Floppy] Format error. Bad sector data. Stopping."); ! 1030: flp_io_state = FLP_STATE_INTERRUPT; /* This is a hack */ ! 1031: floppy_format_done(); ! 1032: flp_buffer.size = 0; ! 1033: return; ! 1034: } ! 1035: flpdrv[drive].sector = s; ! 1036: ! 1037: /* Erase data */ ! 1038: Uint32 sec_size = 0x80<<bs; ! 1039: Uint32 logical_sec = physical_to_logical_sector(flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,drive); ! 1040: flp_buffer.size = sec_size; ! 1041: memset(flp_buffer.data, 0, flp_buffer.size); ! 1042: ! 1043: if (flp.st[0]&IC_ABNORMAL) { ! 1044: Log_Printf(LOG_WARN, "[Floppy] Format error. Bad sector offset (%i).",logical_sec); ! 1045: flp_buffer.size = flp_buffer.limit = 0; ! 1046: send_rw_status(drive); ! 1047: } else { ! 1048: Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Format sector at offset %i (%i/%i/%i), blocksize: %i", ! 1049: logical_sec,c,h,s,sec_size); ! 1050: File_Write(flp_buffer.data, flp_buffer.size, logical_sec*sec_size, flpdrv[drive].dsk); ! 1051: flp_buffer.size = 0; ! 1052: flp_buffer.limit = 4; ! 1053: } ! 1054: } ! 1055: ! 1056: ! 1057: static Uint32 old_size; ! 1058: ! 1059: void FLP_IO_Handler(void) { ! 1060: CycInt_AcknowledgeInterrupt(); ! 1061: ! 1062: switch (flp_io_state) { ! 1063: case FLP_STATE_WRITE: ! 1064: if (flp_buffer.size==flp_buffer.limit) { ! 1065: floppy_write_sector(); ! 1066: if (flp_sector_counter==0) { /* done */ ! 1067: floppy_interrupt(); ! 1068: flp_io_state = FLP_STATE_DONE; ! 1069: return; ! 1070: } ! 1071: } else if (flp_buffer.size<flp_buffer.limit) { /* loop in filling mode */ ! 1072: old_size = flp_buffer.size; ! 1073: dma_esp_read_memory(); ! 1074: if (flp_buffer.size==old_size) { ! 1075: floppy_rw_nodata(); ! 1076: floppy_interrupt(); ! 1077: flp_io_state = FLP_STATE_DONE; ! 1078: return; ! 1079: } ! 1080: } ! 1081: break; ! 1082: ! 1083: case FLP_STATE_READ: ! 1084: if (flp_buffer.size==0 && flp_sector_counter>0) { ! 1085: floppy_read_sector(); ! 1086: } ! 1087: if (flp_buffer.size>0) { /* loop in draining mode */ ! 1088: old_size = flp_buffer.size; ! 1089: dma_esp_write_memory(); ! 1090: if (flp_buffer.size==old_size) { ! 1091: floppy_rw_nodata(); ! 1092: floppy_interrupt(); ! 1093: flp_io_state = FLP_STATE_DONE; ! 1094: return; ! 1095: } ! 1096: } ! 1097: if (flp_buffer.size==0 && flp_sector_counter==0) { /* done */ ! 1098: floppy_interrupt(); ! 1099: flp_io_state = FLP_STATE_DONE; ! 1100: return; ! 1101: } ! 1102: break; ! 1103: ! 1104: case FLP_STATE_FORMAT: ! 1105: if (flp_buffer.size<flp_buffer.limit) { ! 1106: old_size = flp_buffer.size; ! 1107: dma_esp_read_memory(); ! 1108: if (flp_buffer.size==old_size) { ! 1109: floppy_format_done(); ! 1110: floppy_interrupt(); ! 1111: flp_io_state = FLP_STATE_DONE; ! 1112: return; ! 1113: } ! 1114: } else if (flp_buffer.size==flp_buffer.limit) { ! 1115: floppy_format_sector(); ! 1116: } ! 1117: break; ! 1118: ! 1119: case FLP_STATE_INTERRUPT: ! 1120: floppy_interrupt(); ! 1121: flp_io_state = FLP_STATE_DONE; ! 1122: /* fall through */ ! 1123: ! 1124: case FLP_STATE_DONE: ! 1125: return; ! 1126: ! 1127: default: ! 1128: return; ! 1129: } ! 1130: ! 1131: CycInt_AddRelativeInterruptUs(get_sector_time(flp_io_drv), 250, INTERRUPT_FLP_IO); ! 1132: } ! 1133: ! 1134: ! 1135: /* Initialize/Uninitialize floppy disks */ ! 1136: ! 1137: static void Floppy_Init(void) { ! 1138: Log_Printf(LOG_WARN, "Loading floppy disks:"); ! 1139: int i; ! 1140: ! 1141: for (i=0; i<FLP_MAX_DRIVES; i++) { ! 1142: flpdrv[i].spinning=false; ! 1143: /* Check if files exist. */ ! 1144: if (ConfigureParams.Floppy.drive[i].bDriveConnected) { ! 1145: flpdrv[i].connected=true; ! 1146: if (ConfigureParams.Floppy.drive[i].bDiskInserted && ! 1147: File_Exists(ConfigureParams.Floppy.drive[i].szImageName)) { ! 1148: Floppy_Insert(i); ! 1149: } else { ! 1150: flpdrv[i].dsk = NULL; ! 1151: flpdrv[i].inserted=false; ! 1152: } ! 1153: } else { ! 1154: flpdrv[i].connected=false; ! 1155: } ! 1156: } ! 1157: ! 1158: floppy_reset(true); ! 1159: } ! 1160: ! 1161: static void Floppy_Uninit(void) { ! 1162: if (flpdrv[0].dsk) ! 1163: File_Close(flpdrv[0].dsk); ! 1164: if (flpdrv[1].dsk) { ! 1165: File_Close(flpdrv[1].dsk); ! 1166: } ! 1167: flpdrv[0].dsk = flpdrv[1].dsk = NULL; ! 1168: flpdrv[0].inserted = flpdrv[1].inserted = false; ! 1169: } ! 1170: ! 1171: static Uint32 Floppy_CheckSize(int drive) { ! 1172: Uint32 size = File_Length(ConfigureParams.Floppy.drive[drive].szImageName); ! 1173: ! 1174: switch (size) { ! 1175: case SIZE_720K: ! 1176: case SIZE_1440K: ! 1177: case SIZE_2880K: ! 1178: return size; ! 1179: ! 1180: default: ! 1181: Log_Printf(LOG_WARN, "Floppy Disk%i: Invalid size (%i byte)\n",drive,size); ! 1182: return 0; ! 1183: } ! 1184: } ! 1185: ! 1186: int Floppy_Insert(int drive) { ! 1187: Uint32 size; ! 1188: ! 1189: /* Check floppy size. */ ! 1190: size = Floppy_CheckSize(drive); ! 1191: if (size) { ! 1192: flpdrv[drive].floppysize = size; ! 1193: flpdrv[drive].blocksize = 2; /* 512 byte */ ! 1194: flpdrv[drive].cyl = flpdrv[drive].head = flpdrv[drive].sector = 0; ! 1195: flpdrv[drive].seekoffset = 0; ! 1196: } else { ! 1197: flpdrv[drive].dsk = NULL; ! 1198: flpdrv[drive].inserted=false; ! 1199: flpdrv[drive].floppysize = 0; ! 1200: return 1; /* bad size, do not insert */ ! 1201: } ! 1202: ! 1203: if (ConfigureParams.Floppy.drive[drive].bWriteProtected) { ! 1204: flpdrv[drive].dsk = File_Open(ConfigureParams.Floppy.drive[drive].szImageName, "rb"); ! 1205: if (flpdrv[drive].dsk == NULL) { ! 1206: Log_Printf(LOG_WARN, "Floppy Disk%i: Cannot open image file %s\n", ! 1207: drive, ConfigureParams.Floppy.drive[drive].szImageName); ! 1208: flpdrv[drive].inserted=false; ! 1209: flpdrv[drive].spinning=false; ! 1210: Statusbar_AddMessage("Cannot insert floppy disk", 0); ! 1211: return 1; ! 1212: } ! 1213: flpdrv[drive].protected=true; ! 1214: } else { ! 1215: flpdrv[drive].dsk = File_Open(ConfigureParams.Floppy.drive[drive].szImageName, "rb+"); ! 1216: flpdrv[drive].protected=false; ! 1217: if (flpdrv[drive].dsk == NULL) { ! 1218: flpdrv[drive].dsk = File_Open(ConfigureParams.Floppy.drive[drive].szImageName, "rb"); ! 1219: if (flpdrv[drive].dsk == NULL) { ! 1220: Log_Printf(LOG_WARN, "Floppy Disk%i: Cannot open image file %s\n", ! 1221: drive, ConfigureParams.Floppy.drive[drive].szImageName); ! 1222: flpdrv[drive].inserted=false; ! 1223: flpdrv[drive].spinning=false; ! 1224: Statusbar_AddMessage("Cannot insert floppy disk", 0); ! 1225: return 1; ! 1226: } ! 1227: flpdrv[drive].protected=true; ! 1228: Log_Printf(LOG_WARN, "Floppy Disk%i: Image file is not writable. Enabling write protection.\n", ! 1229: drive); ! 1230: } ! 1231: } ! 1232: ! 1233: flpdrv[drive].inserted=true; ! 1234: flpdrv[drive].spinning=false; ! 1235: ! 1236: Log_Printf(LOG_WARN, "Floppy Disk%i: %s, %iK\n",drive, ! 1237: ConfigureParams.Floppy.drive[drive].szImageName,flpdrv[drive].floppysize/1024); ! 1238: ! 1239: Statusbar_AddMessage("Inserting floppy disk.", 0); ! 1240: ! 1241: return 0; ! 1242: } ! 1243: ! 1244: void Floppy_Eject(int drive) { ! 1245: if (drive<0) { /* Called from emulator, else called from GUI */ ! 1246: drive=flp.sel; ! 1247: ! 1248: Statusbar_AddMessage("Ejecting floppy disk.", 0); ! 1249: } ! 1250: ! 1251: Log_Printf(LOG_WARN, "Unloading floppy disk %i",drive); ! 1252: Log_Printf(LOG_WARN, "Floppy disk %i: Eject",drive); ! 1253: ! 1254: File_Close(flpdrv[drive].dsk); ! 1255: flpdrv[drive].floppysize = 0; ! 1256: flpdrv[drive].blocksize = 0; ! 1257: flpdrv[drive].dsk=NULL; ! 1258: flpdrv[drive].inserted=false; ! 1259: flpdrv[drive].spinning=false; ! 1260: ! 1261: ConfigureParams.Floppy.drive[drive].bDiskInserted=false; ! 1262: ConfigureParams.Floppy.drive[drive].szImageName[0]='\0'; ! 1263: } ! 1264: ! 1265: void Floppy_Reset(void) { ! 1266: Floppy_Uninit(); ! 1267: Floppy_Init(); ! 1268: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.