|
|
1.1 ! root 1: /* Previous - mo.c ! 2: ! 3: This file is distributed under the GNU Public License, version 2 or at ! 4: your option any later version. Read the file gpl.txt for details. ! 5: ! 6: Canon Magneto-Optical Disk Drive and NeXT Optical Storage Processor emulation. ! 7: ! 8: NeXT Optical Storage Processor uses Reed-Solomon algorithm for error correction. ! 9: It has two 1296 (128?) byte internal buffers and uses double-buffering to perform ! 10: error correction. ! 11: ! 12: */ ! 13: ! 14: /* TODO: ! 15: * - Fix soft timeouts when polling empty second drive ! 16: * - Add realistic seek timings ! 17: * - Check drive error handling (attn conditions) ! 18: */ ! 19: ! 20: #include "ioMem.h" ! 21: #include "ioMemTables.h" ! 22: #include "m68000.h" ! 23: #include "configuration.h" ! 24: #include "mo.h" ! 25: #include "sysReg.h" ! 26: #include "dma.h" ! 27: #include "floppy.h" ! 28: #include "file.h" ! 29: #include "rs.h" ! 30: #include "statusbar.h" ! 31: ! 32: ! 33: #define LOG_MO_REG_LEVEL LOG_DEBUG ! 34: #define LOG_MO_CMD_LEVEL LOG_DEBUG ! 35: #define LOG_MO_ECC_LEVEL LOG_DEBUG ! 36: #define LOG_MO_IO_LEVEL LOG_DEBUG ! 37: ! 38: #define IO_SEG_MASK 0x1FFFF ! 39: ! 40: ! 41: /* Registers */ ! 42: ! 43: struct { ! 44: Uint8 tracknuml; ! 45: Uint8 tracknumh; ! 46: Uint8 sector_num; ! 47: Uint8 sector_count; ! 48: Uint8 intstatus; ! 49: Uint8 intmask; ! 50: Uint8 ctrlr_csr2; ! 51: Uint8 ctrlr_csr1; ! 52: Uint8 csrl; ! 53: Uint8 csrh; ! 54: Uint8 err_stat; ! 55: Uint8 ecc_cnt; ! 56: Uint8 init; ! 57: Uint8 format; ! 58: Uint8 mark; ! 59: Uint8 flag[7]; ! 60: } mo; ! 61: int sector_counter; ! 62: ! 63: struct { ! 64: Uint16 status; ! 65: Uint16 dstat; ! 66: Uint16 estat; ! 67: Uint16 hstat; ! 68: ! 69: Uint8 head; ! 70: ! 71: Uint32 head_pos; ! 72: Uint32 ho_head_pos; ! 73: Uint32 sec_offset; ! 74: ! 75: FILE* dsk; ! 76: ! 77: bool spinning; ! 78: bool spiraling; ! 79: bool seeking; ! 80: ! 81: bool attn; ! 82: bool complete; ! 83: ! 84: bool protected; ! 85: bool inserted; ! 86: bool connected; ! 87: } modrv[MO_MAX_DRIVES]; ! 88: ! 89: int dnum; ! 90: ! 91: ! 92: #define NO_HEAD 0 ! 93: #define READ_HEAD 1 ! 94: #define WRITE_HEAD 2 ! 95: #define ERASE_HEAD 3 ! 96: #define VERIFY_HEAD 4 ! 97: #define RF_HEAD 5 ! 98: ! 99: ! 100: /* Sector increment and number */ ! 101: #define MOSEC_NUM_MASK 0x0F /* rw */ ! 102: #define MOSEC_INCR_MASK 0xF0 /* wo */ ! 103: ! 104: /* Interrupt status */ ! 105: #define MOINT_CMD_COMPL 0x01 /* ro */ ! 106: #define MOINT_ATTN 0x02 /* ro */ ! 107: #define MOINT_OPER_COMPL 0x04 /* rw */ ! 108: #define MOINT_ECC_DONE 0x08 /* rw */ ! 109: #define MOINT_TIMEOUT 0x10 /* rw */ ! 110: #define MOINT_READ_FAULT 0x20 /* rw */ ! 111: #define MOINT_PARITY_ERR 0x40 /* rw */ ! 112: #define MOINT_DATA_ERR 0x80 /* rw */ ! 113: #define MOINT_RESET 0x01 /* wo */ ! 114: #define MOINT_GPO 0x02 /* wo */ ! 115: ! 116: #define MOINT_OSP_MASK 0xFC ! 117: #define MOINT_MO_MASK 0x03 ! 118: ! 119: /* Controller CSR 2 */ ! 120: #define MOCSR2_DRIVE_SEL 0x01 ! 121: #define MOCSR2_ECC_CMP 0x02 ! 122: #define MOCSR2_BUF_TOGGLE 0x04 ! 123: #define MOCSR2_CLR_BUFP 0x08 ! 124: #define MOCSR2_ECC_BLOCKS 0x10 ! 125: #define MOCSR2_ECC_MODE 0x20 ! 126: #define MOCSR2_ECC_DIS 0x40 ! 127: #define MOCSR2_SECT_TIMER 0x80 ! 128: ! 129: /* Controller CSR 1 */ ! 130: /* see below (formatter commands) */ ! 131: ! 132: /* Drive CSR (lo and hi) */ ! 133: /* see below (drive commands) */ ! 134: ! 135: /* Data error status */ ! 136: #define ERRSTAT_ECC 0x01 ! 137: #define ERRSTAT_CMP 0x02 ! 138: #define ERRSTAT_TIMING 0x04 ! 139: #define ERRSTAT_STARVE 0x08 ! 140: ! 141: /* Init */ ! 142: #define MOINIT_ID_MASK 0x03 ! 143: #define MOINIT_EVEN_PAR 0x04 ! 144: #define MOINIT_DMA_STV_ENA 0x08 ! 145: #define MOINIT_25_MHZ 0x10 ! 146: #define MOINIT_ID_CMP_TRK 0x20 ! 147: #define MOINIT_ECC_STV_DIS 0x40 ! 148: #define MOINIT_SEC_GREATER 0x80 ! 149: ! 150: #define MOINIT_ID_34 0 ! 151: #define MOINIT_ID_234 1 ! 152: #define MOINIT_ID_1234 3 ! 153: #define MOINIT_ID_0 2 ! 154: ! 155: /* Format */ ! 156: #define MOFORM_RD_GATE_NOM 0x06 ! 157: #define MOFORM_WR_GATE_NOM 0x30 ! 158: ! 159: #define MOFORM_RD_GATE_MIN 0x00 ! 160: #define MOFORM_RD_GATE_MAX 0x0F ! 161: #define MOFORM_RD_GATE_MASK 0x0F ! 162: ! 163: ! 164: /* Disk layout */ ! 165: #define MO_SEC_PER_TRACK 16 ! 166: #define MO_TRACK_OFFSET 4096 /* offset to first logical sector of kernel driver is 4149 */ ! 167: #define MO_TRACK_LIMIT (19819-(MO_TRACK_OFFSET)) /* no more tracks beyond this offset */ ! 168: ! 169: #define MO_SECTORSIZE_DISK 1296 /* size of encoded sector, like stored on disk */ ! 170: #define MO_SECTORSIZE_DATA 1024 /* size of decoded sector, like handled by software */ ! 171: ! 172: ! 173: static Uint32 get_logical_sector(Uint32 sector_id) { ! 174: Sint32 tracknum = (sector_id&0xFFFF00)>>8; ! 175: Uint8 sectornum = sector_id&0x0F; ! 176: ! 177: tracknum-=MO_TRACK_OFFSET; ! 178: if (tracknum<0 || tracknum>=MO_TRACK_LIMIT) { ! 179: Log_Printf(LOG_WARN, "MO disk %i: Error! Bad sector (%i)! Disk limit exceeded.", dnum, ! 180: (tracknum*MO_SEC_PER_TRACK)+mo.sector_num); ! 181: abort(); ! 182: } ! 183: ! 184: return (tracknum*MO_SEC_PER_TRACK)+sectornum; ! 185: } ! 186: ! 187: ! 188: ! 189: /* Functions */ ! 190: void mo_formatter_cmd(void); ! 191: void mo_formatter_cmd2(void); ! 192: void mo_drive_cmd(void); ! 193: ! 194: void mo_reset(void); ! 195: void osp_select(int drive); ! 196: ! 197: void MO_Init(void); ! 198: void MO_Uninit(void); ! 199: ! 200: /* Experimental */ ! 201: #define SECTOR_IO_DELAY 1250 ! 202: #define CMD_DELAY 40 ! 203: ! 204: #define SEEK_TIMING 1 ! 205: ! 206: static void mo_set_signals(bool complete, bool attn, int delay); ! 207: static void mo_push_signals(bool complete, bool attn, int drive); ! 208: static void osp_poll_mo_signals(void); ! 209: ! 210: static void ecc_read(void); ! 211: static void ecc_write(void); ! 212: static void ecc_verify(void); ! 213: ! 214: static void mo_read_sector(Uint32 sector_id); ! 215: static void mo_write_sector(Uint32 sector_id); ! 216: static void mo_erase_sector(Uint32 sector_id); ! 217: static void mo_verify_sector(Uint32 sector_id); ! 218: ! 219: static void mo_seek(Uint16 command); ! 220: static void mo_high_order_seek(Uint16 command); ! 221: static void mo_jump_head(Uint16 command); ! 222: static void mo_recalibrate(void); ! 223: static void mo_return_drive_status(void); ! 224: static void mo_return_track_addr(void); ! 225: static void mo_return_extended_status(void); ! 226: static void mo_return_hardware_status(void); ! 227: static void mo_return_version(void); ! 228: static void mo_select_head(int head); ! 229: static void mo_reset_attn_status(void); ! 230: static void mo_stop_spinning(void); ! 231: static void mo_start_spinning(void); ! 232: static void mo_eject_disk(int drv); ! 233: static void mo_start_spiraling(void); ! 234: static void mo_stop_spiraling(void); ! 235: static void mo_self_diagnostic(void); ! 236: ! 237: static Uint32 get_logical_sector(Uint32 sector_id); ! 238: static void fmt_sector_done(void); ! 239: static bool fmt_match_id(Uint32 sector_id); ! 240: static void fmt_io(Uint32 sector_id); ! 241: static void ecc_toggle_buffer(void); ! 242: static void ecc_clear_buffer(void); ! 243: static void ecc_decode(void); ! 244: static void ecc_encode(void); ! 245: static void ecc_sequence_done(void); ! 246: static bool mo_drive_empty(void); ! 247: static bool mo_protected(void); ! 248: static void mo_unimplemented_cmd(void); ! 249: static void mo_spiraling_operation(void); ! 250: static Uint32 get_logical_sector(Uint32 sector_id); ! 251: static void mo_insert_disk(int drv); ! 252: ! 253: static int sector_increment = 0; ! 254: ! 255: static void osp_interrupt(Uint8 interrupt); ! 256: ! 257: ! 258: /* ------------------------ OPTICAL STORAGE PROCESSOR ------------------------ */ ! 259: ! 260: /* OSP registers */ ! 261: ! 262: void MO_TrackNumH_Read(void) { // 0x02012000 ! 263: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.tracknumh; ! 264: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Track number hi read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 265: } ! 266: ! 267: void MO_TrackNumH_Write(void) { ! 268: mo.tracknumh=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 269: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Track number hi write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 270: } ! 271: ! 272: void MO_TrackNumL_Read(void) { // 0x02012001 ! 273: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.tracknuml; ! 274: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Track number lo read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 275: } ! 276: ! 277: void MO_TrackNumL_Write(void) { ! 278: mo.tracknuml=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 279: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Track number lo write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 280: } ! 281: ! 282: void MO_SectorIncr_Read(void) { // 0x02012002 ! 283: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.sector_num&MOSEC_NUM_MASK; ! 284: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Sector increment and number read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 285: } ! 286: ! 287: void MO_SectorIncr_Write(void) { ! 288: Uint8 val = IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 289: mo.sector_num = val&MOSEC_NUM_MASK; ! 290: sector_increment = (val&MOSEC_INCR_MASK)>>4; ! 291: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Sector increment and number write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 292: } ! 293: ! 294: void MO_SectorCnt_Read(void) { // 0x02012003 ! 295: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = sector_counter&0xFF; ! 296: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Sector count read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 297: } ! 298: ! 299: void MO_SectorCnt_Write(void) { ! 300: sector_counter=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 301: if (sector_counter==0) { ! 302: sector_counter=0x100; ! 303: } ! 304: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Sector count write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 305: } ! 306: ! 307: void MO_IntStatus_Read(void) { // 0x02012004 ! 308: osp_poll_mo_signals(); ! 309: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.intstatus; ! 310: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Interrupt status read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 311: } ! 312: ! 313: void MO_IntStatus_Write(void) { ! 314: Uint8 val = IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 315: osp_poll_mo_signals(); ! 316: mo.intstatus &= ~(val&MOINT_OSP_MASK); ! 317: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Interrupt status write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 318: ! 319: if ((mo.intstatus&mo.intmask)==0) { ! 320: set_interrupt(INT_DISK, RELEASE_INT); ! 321: } ! 322: if (ConfigureParams.System.nMachineType==NEXT_CUBE030) { ! 323: set_floppy_select(val&MOINT_GPO, true); ! 324: } ! 325: if (val&MOINT_RESET) { ! 326: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Hard reset\n"); ! 327: mo_reset(); ! 328: } ! 329: } ! 330: ! 331: void MO_IntMask_Read(void) { // 0x02012005 ! 332: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.intmask; ! 333: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Interrupt mask read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 334: } ! 335: ! 336: void MO_IntMask_Write(void) { ! 337: mo.intmask=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 338: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Interrupt mask write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 339: ! 340: osp_poll_mo_signals(); ! 341: if ((mo.intstatus&mo.intmask)==0) { ! 342: set_interrupt(INT_DISK, RELEASE_INT); ! 343: } else { ! 344: set_interrupt(INT_DISK, SET_INT); ! 345: } ! 346: } ! 347: ! 348: void MOctrl_CSR2_Read(void) { // 0x02012006 ! 349: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.ctrlr_csr2; ! 350: Log_Printf(LOG_MO_REG_LEVEL,"[MO Controller] CSR2 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 351: } ! 352: ! 353: void MOctrl_CSR2_Write(void) { ! 354: mo.ctrlr_csr2=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 355: Log_Printf(LOG_MO_REG_LEVEL,"[MO Controller] CSR2 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 356: ! 357: mo_formatter_cmd2(); ! 358: } ! 359: ! 360: void MOctrl_CSR1_Read(void) { // 0x02012007 ! 361: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.ctrlr_csr1; ! 362: Log_Printf(LOG_MO_REG_LEVEL,"[MO Controller] CSR1 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 363: } ! 364: ! 365: void MOctrl_CSR1_Write(void) { ! 366: mo.ctrlr_csr1=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 367: Log_Printf(LOG_MO_REG_LEVEL,"[MO Controller] CSR1 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 368: ! 369: mo_formatter_cmd(); ! 370: } ! 371: ! 372: void MO_CSR_H_Read(void) { // 0x02012009 ! 373: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.csrh; ! 374: Log_Printf(LOG_MO_REG_LEVEL,"[MO] CSR hi read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 375: } ! 376: ! 377: void MO_CSR_H_Write(void) { ! 378: mo.csrh=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 379: Log_Printf(LOG_MO_REG_LEVEL,"[MO] CSR hi write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 380: } ! 381: ! 382: void MO_CSR_L_Read(void) { // 0x02012008 ! 383: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.csrl; ! 384: Log_Printf(LOG_MO_REG_LEVEL,"[MO] CSR lo read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 385: } ! 386: ! 387: void MO_CSR_L_Write(void) { ! 388: mo.csrl=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 389: Log_Printf(LOG_MO_REG_LEVEL,"[MO] CSR lo write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 390: ! 391: mo_drive_cmd(); ! 392: } ! 393: ! 394: void MO_ErrStat_Read(void) { // 0x0201200a ! 395: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.err_stat; ! 396: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Error status read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 397: } ! 398: ! 399: void MO_EccCnt_Read(void) { // 0x0201200b ! 400: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.ecc_cnt; ! 401: Log_Printf(LOG_MO_REG_LEVEL,"[MO] ECC count read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 402: } ! 403: ! 404: void MO_Init_Write(void) { // 0x0201200c ! 405: mo.init=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 406: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Init write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 407: } ! 408: ! 409: void MO_Format_Write(void) { // 0x0201200d ! 410: mo.format=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 411: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Format write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 412: } ! 413: ! 414: void MO_Mark_Write(void) { // 0x0201200e ! 415: mo.mark=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 416: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Mark write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 417: } ! 418: ! 419: void MO_Flag0_Read(void) { // 0x02012010 ! 420: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.flag[0]; ! 421: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Flag 0 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 422: } ! 423: ! 424: void MO_Flag0_Write(void) { ! 425: mo.flag[0]=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 426: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Flag 0 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 427: } ! 428: ! 429: void MO_Flag1_Read(void) { // 0x02012011 ! 430: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.flag[1]; ! 431: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Flag 1 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 432: } ! 433: ! 434: void MO_Flag1_Write(void) { ! 435: mo.flag[1]=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 436: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Flag 1 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 437: } ! 438: ! 439: void MO_Flag2_Read(void) { // 0x02012012 ! 440: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.flag[2]; ! 441: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Flag 2 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 442: } ! 443: ! 444: void MO_Flag2_Write(void) { ! 445: mo.flag[2]=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 446: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Flag 2 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 447: } ! 448: ! 449: void MO_Flag3_Read(void) { // 0x02012013 ! 450: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.flag[3]; ! 451: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Flag 3 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 452: } ! 453: ! 454: void MO_Flag3_Write(void) { ! 455: mo.flag[3]=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 456: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Flag 3 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 457: } ! 458: ! 459: void MO_Flag4_Read(void) { // 0x02012014 ! 460: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.flag[4]; ! 461: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Flag 4 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 462: } ! 463: ! 464: void MO_Flag4_Write(void) { ! 465: mo.flag[4]=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 466: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Flag 4 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 467: } ! 468: ! 469: void MO_Flag5_Read(void) { // 0x02012015 ! 470: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.flag[5]; ! 471: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Flag 5 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 472: } ! 473: ! 474: void MO_Flag5_Write(void) { ! 475: mo.flag[5]=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 476: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Flag 5 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 477: } ! 478: ! 479: void MO_Flag6_Read(void) { // 0x02012016 ! 480: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = mo.flag[6]; ! 481: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Flag 6 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 482: } ! 483: ! 484: void MO_Flag6_Write(void) { ! 485: mo.flag[6]=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 486: Log_Printf(LOG_MO_REG_LEVEL,"[MO] Flag 6 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 487: } ! 488: ! 489: #if 0 ! 490: /* Register debugging */ ! 491: static void print_regs(void) { ! 492: int i; ! 493: Log_Printf(LOG_WARN,"sector ID: %02X%02X%02X",mo.tracknumh,mo.tracknuml,mo.sector_num); ! 494: Log_Printf(LOG_WARN,"head pos: %04X",modrv[dnum].head_pos); ! 495: Log_Printf(LOG_WARN,"sector cnt: %02X",sector_counter&0xFF); ! 496: Log_Printf(LOG_WARN,"intstatus: %02X",mo.intstatus); ! 497: Log_Printf(LOG_WARN,"intmask: %02X",mo.intmask); ! 498: Log_Printf(LOG_WARN,"ctrlr csr2: %02X",mo.ctrlr_csr2); ! 499: Log_Printf(LOG_WARN,"ctrlr csr1: %02X",mo.ctrlr_csr1); ! 500: Log_Printf(LOG_WARN,"drive csrl: %02X",mo.csrl); ! 501: Log_Printf(LOG_WARN,"drive csrh: %02X",mo.csrh); ! 502: Log_Printf(LOG_WARN,"errstat: %02X",mo.err_stat); ! 503: Log_Printf(LOG_WARN,"ecc count: %02X",mo.ecc_cnt); ! 504: Log_Printf(LOG_WARN,"init: %02X",mo.init); ! 505: Log_Printf(LOG_WARN,"format: %02X",mo.format); ! 506: Log_Printf(LOG_WARN,"mark: %02X",mo.mark); ! 507: for (i=0; i<7; i++) { ! 508: Log_Printf(LOG_WARN,"flag %i: %02X",i+1,mo.flag[i]); ! 509: } ! 510: } ! 511: #endif ! 512: ! 513: void osp_interrupt(Uint8 interrupt) { ! 514: mo.intstatus|=interrupt; ! 515: if (interrupt&mo.intmask) { ! 516: set_interrupt(INT_DISK, SET_INT); ! 517: } ! 518: } ! 519: ! 520: ! 521: enum { ! 522: ECC_MODE_READ, ! 523: ECC_MODE_WRITE, ! 524: ECC_MODE_VERIFY ! 525: } ecc_mode; ! 526: ! 527: enum { ! 528: ECC_STATE_FILLING, ! 529: ECC_STATE_DRAINING, ! 530: ECC_STATE_ECCING, ! 531: ECC_STATE_WAITING, ! 532: ECC_STATE_DONE ! 533: } ecc_state; ! 534: ! 535: /* Formatter commands */ ! 536: ! 537: #define FMT_RESET 0x00 ! 538: #define FMT_ECC_READ 0x80 ! 539: #define FMT_ECC_WRITE 0x40 ! 540: #define FMT_RD_STAT 0x20 ! 541: #define FMT_ID_READ 0x10 ! 542: #define FMT_VERIFY 0x08 ! 543: #define FMT_ERASE 0x04 ! 544: #define FMT_READ 0x02 ! 545: #define FMT_WRITE 0x01 ! 546: ! 547: enum { ! 548: FMT_MODE_READ, ! 549: FMT_MODE_WRITE, ! 550: FMT_MODE_ERASE, ! 551: FMT_MODE_VERIFY, ! 552: FMT_MODE_READ_ID, ! 553: FMT_MODE_IDLE ! 554: } fmt_mode; ! 555: ! 556: bool write_timing; ! 557: ! 558: void mo_formatter_cmd(void) { ! 559: ! 560: if (mo.ctrlr_csr1==FMT_RESET) { ! 561: Log_Printf(LOG_MO_CMD_LEVEL,"[OSP] Formatter command: Reset (%02X)\n", mo.ctrlr_csr1); ! 562: if (fmt_mode!=FMT_MODE_IDLE) { ! 563: Log_Printf(LOG_WARN,"[OSP] Warning: Formatter reset while busy!\n"); ! 564: } ! 565: fmt_mode = FMT_MODE_IDLE; ! 566: ecc_state = ECC_STATE_DONE; ! 567: mo.ecc_cnt=0; ! 568: mo.err_stat=0; ! 569: return; ! 570: } ! 571: if (mo.ctrlr_csr1&FMT_ECC_READ) { ! 572: Log_Printf(LOG_MO_CMD_LEVEL,"[OSP] Formatter command: ECC Read (%02X)\n", mo.ctrlr_csr1); ! 573: ecc_read(); ! 574: } ! 575: if (mo.ctrlr_csr1&FMT_ECC_WRITE) { ! 576: Log_Printf(LOG_MO_CMD_LEVEL,"[OSP] Formatter command: ECC Write (%02X)\n", mo.ctrlr_csr1); ! 577: ecc_write(); ! 578: } ! 579: if (mo.ctrlr_csr1&FMT_RD_STAT) { ! 580: Log_Printf(LOG_MO_CMD_LEVEL,"[OSP] Formatter command: Read Status (%02X)\n", mo.ctrlr_csr1); ! 581: mo.csrh = (modrv[dnum].status>>8)&0xFF; ! 582: mo.csrl = modrv[dnum].status&0xFF; ! 583: } ! 584: if (mo.ctrlr_csr1&FMT_ID_READ) { ! 585: Log_Printf(LOG_MO_CMD_LEVEL,"[OSP] Formatter command: ID Read (%02X)\n", mo.ctrlr_csr1); ! 586: fmt_mode = FMT_MODE_READ_ID; ! 587: } ! 588: if (mo.ctrlr_csr1&FMT_VERIFY) { ! 589: Log_Printf(LOG_MO_CMD_LEVEL,"[OSP] Formatter command: Verify (%02X)\n", mo.ctrlr_csr1); ! 590: fmt_mode = FMT_MODE_VERIFY; ! 591: } ! 592: if (mo.ctrlr_csr1&FMT_ERASE) { ! 593: Log_Printf(LOG_MO_CMD_LEVEL,"[OSP] Formatter command: Erase (%02X)\n", mo.ctrlr_csr1); ! 594: fmt_mode = FMT_MODE_ERASE; ! 595: } ! 596: if (mo.ctrlr_csr1&FMT_READ) { ! 597: Log_Printf(LOG_MO_CMD_LEVEL,"[OSP] Formatter command: Read (%02X)\n", mo.ctrlr_csr1); ! 598: fmt_mode = FMT_MODE_READ; ! 599: } ! 600: if (mo.ctrlr_csr1&FMT_WRITE) { ! 601: Log_Printf(LOG_MO_CMD_LEVEL,"[OSP] Formatter command: Write (%02X)\n", mo.ctrlr_csr1); ! 602: write_timing = false; ! 603: fmt_mode = FMT_MODE_WRITE; ! 604: } ! 605: } ! 606: ! 607: void fmt_sector_done(void) { ! 608: Uint16 track = (mo.tracknumh<<8)|mo.tracknuml; ! 609: mo.sector_num+=sector_increment; ! 610: track+=mo.sector_num/MO_SEC_PER_TRACK; ! 611: mo.sector_num%=MO_SEC_PER_TRACK; ! 612: mo.tracknumh = (track>>8)&0xFF; ! 613: mo.tracknuml = track&0xFF; ! 614: /* CHECK: decrement with sector_increment value? */ ! 615: sector_counter--; ! 616: /* Check if the operation is complete */ ! 617: if (sector_counter==0) { ! 618: fmt_mode = FMT_MODE_IDLE; ! 619: osp_interrupt(MOINT_OPER_COMPL); ! 620: } ! 621: } ! 622: ! 623: int sector_timer=0; ! 624: #define SECTOR_TIMEOUT_COUNT 100 /* FIXME: what is the correct value? */ ! 625: bool fmt_match_id(Uint32 sector_id) { ! 626: if ((mo.init&MOINIT_ID_MASK)==MOINIT_ID_0) { ! 627: Log_Printf(LOG_MO_CMD_LEVEL, "[OSP] Sector ID matching disabled!"); ! 628: abort(); /* CHECK: this routine is critical to disk image corruption, check if it gives correct results */ ! 629: return true; ! 630: } ! 631: ! 632: Uint32 fmt_id = (mo.tracknumh<<16)|(mo.tracknuml<<8)|mo.sector_num; ! 633: ! 634: if (mo.init&MOINIT_ID_CMP_TRK) { ! 635: Log_Printf(LOG_MO_CMD_LEVEL, "[OSP] Compare only track ID."); ! 636: fmt_id=(fmt_id>>8)&0xFFFF; ! 637: sector_id=(sector_id>>8)&0xFFFF; ! 638: } ! 639: ! 640: if (sector_id==fmt_id) { ! 641: sector_timer=0; ! 642: return true; ! 643: } else { ! 644: Log_Printf(LOG_MO_CMD_LEVEL, "[OSP] Sector ID mismatch (Sector ID=%06X, Looking for %06X)", ! 645: sector_id,fmt_id); ! 646: if (mo.ctrlr_csr2&MOCSR2_SECT_TIMER) { ! 647: sector_timer++; ! 648: if (sector_timer>SECTOR_TIMEOUT_COUNT) { ! 649: Log_Printf(LOG_WARN, "[OSP] Sector timeout!"); ! 650: sector_timer=0; ! 651: fmt_mode=FMT_MODE_IDLE; ! 652: osp_interrupt(MOINT_TIMEOUT); ! 653: } ! 654: } ! 655: return false; ! 656: } ! 657: } ! 658: ! 659: void fmt_io(Uint32 sector_id) { ! 660: ! 661: switch (fmt_mode) { ! 662: case FMT_MODE_IDLE: ! 663: return; ! 664: case FMT_MODE_READ_ID: ! 665: mo.tracknumh = (sector_id>>16)&0xFF; ! 666: mo.tracknuml = (sector_id>>8)&0xFF; ! 667: mo.sector_num = sector_id&0x0F; ! 668: osp_interrupt(MOINT_OPER_COMPL); ! 669: return; ! 670: case FMT_MODE_READ: ! 671: if (modrv[dnum].head!=READ_HEAD) { ! 672: abort(); ! 673: } ! 674: if (fmt_match_id(sector_id)) { ! 675: /* First read sector from disk to ECC buffer */ ! 676: mo_read_sector(sector_id); ! 677: /* Then decode data and write to memory using DMA */ ! 678: ecc_read(); ! 679: fmt_sector_done(); ! 680: } ! 681: break; ! 682: case FMT_MODE_WRITE: ! 683: if (modrv[dnum].head!=WRITE_HEAD) { ! 684: abort(); ! 685: } ! 686: /* WARNING: first sector must be mismatch to pre-fill the ECC buffer for writing */ ! 687: if (fmt_match_id(sector_id) && write_timing) { ! 688: /* Write sector from ECC buffer to disk */ ! 689: mo_write_sector(sector_id); ! 690: fmt_sector_done(); ! 691: } else { ! 692: write_timing = true; ! 693: } ! 694: /* (Re)fill ECC buffer from memory using DMA and encode data */ ! 695: ecc_write(); ! 696: break; ! 697: case FMT_MODE_ERASE: ! 698: if (modrv[dnum].head!=ERASE_HEAD) { ! 699: abort(); ! 700: } ! 701: if (fmt_match_id(sector_id)) { ! 702: mo_erase_sector(sector_id); ! 703: fmt_sector_done(); ! 704: } ! 705: break; ! 706: case FMT_MODE_VERIFY: ! 707: if (modrv[dnum].head!=VERIFY_HEAD) { ! 708: abort(); ! 709: } ! 710: if (fmt_match_id(sector_id)) { ! 711: /* First read sector from disk to ECC buffer */ ! 712: mo_verify_sector(sector_id); ! 713: /* Then verify data */ ! 714: ecc_verify(); ! 715: fmt_sector_done(); ! 716: } ! 717: break; ! 718: ! 719: default: ! 720: abort(); ! 721: break; ! 722: } ! 723: } ! 724: ! 725: ! 726: /* Drive selection (formatter command 2) */ ! 727: void osp_select(int drive) { ! 728: Log_Printf(LOG_MO_CMD_LEVEL, "[OSP] Selecting drive %i",drive); ! 729: dnum=drive; ! 730: if (!modrv[dnum].connected) { ! 731: Log_Printf(LOG_MO_CMD_LEVEL, "[OSP] Selection failed! Drive %i not connected.",drive); ! 732: } ! 733: } ! 734: ! 735: /* Check for MO drive signals (used for interrupt status register) */ ! 736: void osp_poll_mo_signals(void) { ! 737: if (modrv[dnum].complete) { ! 738: mo.intstatus |= MOINT_CMD_COMPL; ! 739: } else { ! 740: mo.intstatus &= ~MOINT_CMD_COMPL; ! 741: } ! 742: if (modrv[dnum].attn) { ! 743: mo.intstatus |= MOINT_ATTN; ! 744: } else { ! 745: mo.intstatus &= ~MOINT_ATTN; ! 746: } ! 747: } ! 748: ! 749: void ecc_toggle_buffer(void) { ! 750: if (eccin==0) { ! 751: eccout=0; ! 752: eccin=1; ! 753: } else { ! 754: eccout=1; ! 755: eccin=0; ! 756: } ! 757: Log_Printf(LOG_MO_ECC_LEVEL, "[OSP] ECC switching buffer (in: %i, out: %i)",eccin,eccout); ! 758: } ! 759: ! 760: void ecc_clear_buffer(void) { ! 761: ecc_buffer[eccin].size=ecc_buffer[eccout].size=0; ! 762: ecc_buffer[eccin].limit=ecc_buffer[eccout].limit=MO_SECTORSIZE_DATA; ! 763: } ! 764: ! 765: void mo_formatter_cmd2(void) { ! 766: if (mo.ctrlr_csr2&MOCSR2_BUF_TOGGLE) { ! 767: Log_Printf(LOG_MO_ECC_LEVEL, "[OSP] Toggle ECC buffer."); ! 768: ecc_toggle_buffer(); ! 769: } ! 770: if (mo.ctrlr_csr2&MOCSR2_ECC_CMP) { ! 771: Log_Printf(LOG_MO_ECC_LEVEL, "[OSP] ECC compare."); ! 772: } ! 773: if (mo.ctrlr_csr2&MOCSR2_CLR_BUFP) { ! 774: Log_Printf(LOG_MO_ECC_LEVEL, "[OSP] Clear ECC buffer."); ! 775: ecc_clear_buffer(); ! 776: } ! 777: if (mo.ctrlr_csr2&MOCSR2_ECC_BLOCKS) { ! 778: Log_Printf(LOG_MO_ECC_LEVEL, "[OSP] ECC blocks."); ! 779: } ! 780: if (mo.ctrlr_csr2&MOCSR2_ECC_MODE) { ! 781: Log_Printf(LOG_MO_ECC_LEVEL, "[OSP] ECC decoding mode."); ! 782: } else { ! 783: Log_Printf(LOG_MO_ECC_LEVEL, "[OSP] ECC encoding mode."); ! 784: } ! 785: if (mo.ctrlr_csr2&MOCSR2_SECT_TIMER) { ! 786: Log_Printf(LOG_MO_CMD_LEVEL, "[OSP] Sector timer enabled."); ! 787: } else { ! 788: Log_Printf(LOG_MO_CMD_LEVEL, "[OSP] Sector timer disabled."); ! 789: } ! 790: if (mo.ctrlr_csr2&MOCSR2_ECC_DIS) { ! 791: Log_Printf(LOG_MO_ECC_LEVEL, "[OSP] Disable ECC passthrough."); ! 792: } ! 793: ! 794: osp_select(mo.ctrlr_csr2&MOCSR2_DRIVE_SEL); ! 795: } ! 796: ! 797: ! 798: /* ECC emulation: ! 799: * ! 800: * read mem <----- buf <-de-- disk ! 801: * write mem -----> buf --en-> disk ! 802: * verify buf <-de-- disk ! 803: * ! 804: * ecc_dis ! 805: * read mem <-en-- buf ! 806: * write mem -----> buf ! 807: * ! 808: * ecc_dis|ecc_mode ! 809: * read mem <----- buf ! 810: * write mem --de-> buf ! 811: * ! 812: */ ! 813: ! 814: #define ECC_DELAY SECTOR_IO_DELAY/5 /* must be a fraction of sector delay */ ! 815: ! 816: bool ecc_repeat=false; /* This is for ECC blocks */ ! 817: ! 818: int eccin=0; ! 819: int eccout=1; ! 820: ! 821: void ecc_decode(void) { ! 822: if (mo.ctrlr_csr2&MOCSR2_ECC_DIS && !(mo.ctrlr_csr2&MOCSR2_ECC_MODE)) { ! 823: Log_Printf(LOG_MO_ECC_LEVEL, "[OSP] ECC decoding disabled."); ! 824: if (mo.ctrlr_csr2&MOCSR2_ECC_BLOCKS && ecc_repeat==true) { ! 825: ecc_toggle_buffer(); ! 826: } ! 827: } else if (ecc_buffer[eccin].size==MO_SECTORSIZE_DISK) { ! 828: Log_Printf(LOG_MO_ECC_LEVEL, "[OSP] ECC decoding buffer."); ! 829: ecc_buffer[eccin].limit=ecc_buffer[eccin].size=MO_SECTORSIZE_DATA; ! 830: ! 831: int num_errors = rs_decode(ecc_buffer[eccin].data); ! 832: ! 833: if (num_errors<0) { ! 834: Log_Printf(LOG_WARN, "[OSP] ECC: Sector has uncorrectable errors!"); ! 835: mo.err_stat = ERRSTAT_ECC; ! 836: osp_interrupt(MOINT_DATA_ERR); ! 837: /* CHECK: Stop ECC and formatter? */ ! 838: } else { ! 839: Log_Printf(LOG_MO_ECC_LEVEL, "[OSP] ECC: Number of corrected errors: %i\n",num_errors); ! 840: ! 841: if (mo.ecc_cnt==0) { ! 842: mo.ecc_cnt=num_errors; ! 843: } ! 844: } ! 845: ! 846: ecc_toggle_buffer(); ! 847: } else { ! 848: Log_Printf(LOG_WARN, "[OSP] ECC buffer is not ready (%i bytes)!",ecc_buffer[eccin].size); ! 849: abort(); ! 850: } ! 851: } ! 852: void ecc_encode(void) { ! 853: if (mo.ctrlr_csr2&MOCSR2_ECC_DIS && mo.ctrlr_csr2&MOCSR2_ECC_MODE) { ! 854: Log_Printf(LOG_MO_ECC_LEVEL, "[OSP] ECC encoding disabled."); ! 855: if (mo.ctrlr_csr2&MOCSR2_ECC_BLOCKS && ecc_repeat==false) { ! 856: ecc_toggle_buffer(); ! 857: } ! 858: } else if (ecc_buffer[eccin].limit==MO_SECTORSIZE_DATA) { ! 859: Log_Printf(LOG_MO_ECC_LEVEL, "[OSP] ECC encoding buffer."); ! 860: ecc_buffer[eccin].limit=ecc_buffer[eccin].size=MO_SECTORSIZE_DISK; ! 861: ! 862: rs_encode(ecc_buffer[eccin].data); ! 863: ! 864: ecc_toggle_buffer(); ! 865: } else { ! 866: Log_Printf(LOG_WARN, "[OSP] ECC buffer is not ready (%i bytes)!",ecc_buffer[eccin].size); ! 867: abort(); ! 868: } ! 869: } ! 870: ! 871: void ecc_write(void) { ! 872: if (ecc_state!=ECC_STATE_DONE) { ! 873: Log_Printf(LOG_MO_ECC_LEVEL,"[OSP] Warning: ECC not accepting command (busy %i)", ecc_state); ! 874: return; ! 875: } ! 876: ecc_mode=ECC_MODE_WRITE; ! 877: ecc_state=ECC_STATE_FILLING; ! 878: if (mo.ctrlr_csr2&MOCSR2_ECC_BLOCKS) { ! 879: ecc_repeat=true; ! 880: } ! 881: ecc_buffer[eccin].size=0; /* FIXME: find a better place for this */ ! 882: ecc_buffer[eccin].limit=MO_SECTORSIZE_DATA; /* and this */ ! 883: CycInt_AddRelativeInterruptUsCycles(ECC_DELAY, 80, INTERRUPT_ECC_IO); ! 884: } ! 885: void ecc_read(void) { ! 886: if (ecc_state!=ECC_STATE_DONE) { ! 887: Log_Printf(LOG_WARN,"[OSP] Warning: ECC not accepting command (busy %i)", ecc_state); ! 888: return; ! 889: } ! 890: ecc_mode=ECC_MODE_READ; ! 891: ecc_state=ECC_STATE_ECCING; ! 892: if (mo.ctrlr_csr2&MOCSR2_ECC_BLOCKS) { ! 893: ecc_repeat=true; ! 894: } ! 895: CycInt_AddRelativeInterruptUsCycles(ECC_DELAY, 80, INTERRUPT_ECC_IO); ! 896: } ! 897: void ecc_verify(void) { ! 898: if (ecc_state!=ECC_STATE_DONE) { ! 899: Log_Printf(LOG_WARN,"[OSP] Warning: ECC not accepting command (busy %i)", ecc_state); ! 900: return; ! 901: } ! 902: ecc_mode=ECC_MODE_VERIFY; ! 903: ecc_state=ECC_STATE_ECCING; ! 904: CycInt_AddRelativeInterruptUsCycles(ECC_DELAY, 80, INTERRUPT_ECC_IO); ! 905: } ! 906: void ecc_sequence_done(void) { ! 907: if (ecc_repeat==true) { ! 908: ecc_repeat=false; ! 909: if (ecc_mode==ECC_MODE_WRITE) { ! 910: ecc_buffer[eccin].size=0; /* FIXME: find a better place for this */ ! 911: ecc_state=ECC_STATE_FILLING; ! 912: } else { ! 913: ecc_state=ECC_STATE_ECCING; ! 914: } ! 915: CycInt_AddRelativeInterruptUsCycles(ECC_DELAY, 80, INTERRUPT_ECC_IO); ! 916: return; ! 917: } ! 918: ! 919: ecc_state=ECC_STATE_DONE; ! 920: if (mo.ctrlr_csr2&MOCSR2_ECC_DIS) { ! 921: osp_interrupt(MOINT_ECC_DONE); ! 922: } ! 923: } ! 924: Uint32 old_size; ! 925: void ECC_IO_Handler(void) { ! 926: CycInt_AcknowledgeInterrupt(); ! 927: ! 928: switch (ecc_state) { ! 929: case ECC_STATE_FILLING: ! 930: if (ecc_buffer[eccin].size<ecc_buffer[eccin].limit) { ! 931: if (mo.ctrlr_csr2&MOCSR2_ECC_MODE) { ! 932: ecc_buffer[eccin].limit=MO_SECTORSIZE_DISK; ! 933: } else { ! 934: ecc_buffer[eccin].limit=MO_SECTORSIZE_DATA; ! 935: } ! 936: old_size=ecc_buffer[eccin].size; ! 937: dma_mo_read_memory(); ! 938: ! 939: if (ecc_buffer[eccin].size==old_size) { ! 940: Log_Printf(LOG_WARN,"[OSP] No more data! ECC starve! (%i byte)", old_size); ! 941: mo.err_stat = ERRSTAT_STARVE; ! 942: osp_interrupt(MOINT_DATA_ERR); ! 943: } ! 944: } ! 945: if (ecc_buffer[eccin].size==ecc_buffer[eccin].limit) { ! 946: ecc_state=ECC_STATE_ECCING; ! 947: } ! 948: break; ! 949: case ECC_STATE_ECCING: ! 950: if (ecc_mode==ECC_MODE_WRITE) { ! 951: if (mo.ctrlr_csr2&MOCSR2_ECC_DIS) { ! 952: ecc_decode(); ! 953: ecc_sequence_done(); ! 954: return; ! 955: } else { /* Go to disk write */ ! 956: ecc_encode(); ! 957: ecc_state=ECC_STATE_WAITING; ! 958: if (sector_counter==1) { ! 959: osp_interrupt(MOINT_ECC_DONE); ! 960: } ! 961: break; ! 962: } ! 963: } else { /* mode is read or verify */ ! 964: if (mo.ctrlr_csr2&MOCSR2_ECC_DIS) { ! 965: if (mo.ctrlr_csr2&MOCSR2_ECC_BLOCKS) { ! 966: ecc_buffer[eccin].limit=ecc_buffer[eccin].size=MO_SECTORSIZE_DATA; ! 967: } ! 968: ecc_encode(); ! 969: } else { /* From disk read */ ! 970: if (ecc_buffer[eccin].size!=MO_SECTORSIZE_DISK) { ! 971: Log_Printf(LOG_WARN, "[OSP] ECC waiting for disk read!"); ! 972: break; /* Loop and wait for disk read */ ! 973: } ! 974: ecc_decode(); ! 975: if (sector_counter==0) { ! 976: osp_interrupt(MOINT_ECC_DONE); ! 977: } ! 978: if (ecc_mode==ECC_MODE_VERIFY) { ! 979: ecc_clear_buffer(); ! 980: ecc_sequence_done(); ! 981: return; ! 982: } ! 983: } ! 984: ecc_state=ECC_STATE_DRAINING; ! 985: break; ! 986: } ! 987: case ECC_STATE_DRAINING: ! 988: old_size=ecc_buffer[eccout].size; ! 989: dma_mo_write_memory(); ! 990: if (ecc_buffer[eccout].size==old_size) { ! 991: Log_Printf(LOG_WARN,"[OSP] DMA not ready! Stopping."); ! 992: ecc_sequence_done(); ! 993: return; ! 994: } ! 995: if (ecc_buffer[eccout].size==0) { ! 996: dma_mo_write_memory(); /* Flush buffer */ ! 997: ecc_sequence_done(); ! 998: return; ! 999: } ! 1000: break; ! 1001: case ECC_STATE_WAITING: ! 1002: if (ecc_buffer[eccout].size==0) { ! 1003: ecc_sequence_done(); ! 1004: if (sector_counter>0) { ! 1005: ecc_write(); ! 1006: } ! 1007: return; ! 1008: } ! 1009: Log_Printf(LOG_MO_ECC_LEVEL, "[OSP] ECC waiting for disk write!"); ! 1010: break; ! 1011: ! 1012: default: ! 1013: Log_Printf(LOG_WARN, "[OSP] Warning: ECC was reset while busy!"); ! 1014: return; ! 1015: } ! 1016: ! 1017: CycInt_AddRelativeInterruptUsCycles(ECC_DELAY, 80, INTERRUPT_ECC_IO); ! 1018: } ! 1019: ! 1020: ! 1021: /* ------------------------ MAGNETO-OPTICAL DISK DRIVE ------------------------ */ ! 1022: ! 1023: /* I/O functions */ ! 1024: ! 1025: void mo_read_sector(Uint32 sector_id) { ! 1026: Uint32 sector_num = get_logical_sector(sector_id); ! 1027: ! 1028: Log_Printf(LOG_MO_IO_LEVEL, "MO disk %i: Read sector at offset %i (%i sectors remaining)", ! 1029: dnum, sector_num, sector_counter-1); ! 1030: ! 1031: File_Read(ecc_buffer[eccin].data, MO_SECTORSIZE_DISK, sector_num*MO_SECTORSIZE_DISK, modrv[dnum].dsk); ! 1032: ! 1033: ecc_buffer[eccin].limit = ecc_buffer[eccin].size = MO_SECTORSIZE_DISK; ! 1034: } ! 1035: ! 1036: void mo_write_sector(Uint32 sector_id) { ! 1037: Uint32 sector_num = get_logical_sector(sector_id); ! 1038: ! 1039: Log_Printf(LOG_MO_IO_LEVEL, "MO disk %i: Write sector at offset %i (%i sectors remaining)", ! 1040: dnum, sector_num, sector_counter-1); ! 1041: ! 1042: if (ecc_buffer[eccout].limit==MO_SECTORSIZE_DISK) { ! 1043: File_Write(ecc_buffer[eccout].data, MO_SECTORSIZE_DISK, sector_num*MO_SECTORSIZE_DISK, modrv[dnum].dsk); ! 1044: ! 1045: ecc_buffer[eccout].size = 0; ! 1046: ecc_buffer[eccout].limit = MO_SECTORSIZE_DATA; ! 1047: } else { ! 1048: Log_Printf(LOG_WARN, "MO disk %i: Incomplete write (in: size=%i limit=%i, out: size=%i limit=%i)!", dnum, ! 1049: ecc_buffer[eccin].size, ecc_buffer[eccin].limit, ecc_buffer[eccout].size, ecc_buffer[eccout].limit); ! 1050: abort(); ! 1051: } ! 1052: } ! 1053: ! 1054: void mo_erase_sector(Uint32 sector_id) { ! 1055: Uint32 sector_num = get_logical_sector(sector_id); ! 1056: ! 1057: Log_Printf(LOG_MO_IO_LEVEL, "MO disk %i: Erase sector at offset %i (%i sectors remaining)", ! 1058: dnum, sector_num, sector_counter-1); ! 1059: ! 1060: Uint8 erase_buf[MO_SECTORSIZE_DISK]; ! 1061: memset(erase_buf, 0xFF, MO_SECTORSIZE_DISK); ! 1062: ! 1063: File_Write(erase_buf, MO_SECTORSIZE_DISK, sector_num*MO_SECTORSIZE_DISK, modrv[dnum].dsk); ! 1064: } ! 1065: ! 1066: void mo_verify_sector(Uint32 sector_id) { ! 1067: Uint32 sector_num = get_logical_sector(sector_id); ! 1068: ! 1069: Log_Printf(LOG_MO_IO_LEVEL, "MO disk %i: Verify sector at offset %i (%i sectors remaining)", ! 1070: dnum, sector_num, sector_counter-1); ! 1071: ! 1072: File_Read(ecc_buffer[eccin].data, MO_SECTORSIZE_DISK, sector_num*MO_SECTORSIZE_DISK, modrv[dnum].dsk); ! 1073: ! 1074: ecc_buffer[eccin].limit = ecc_buffer[eccin].size = MO_SECTORSIZE_DISK; ! 1075: } ! 1076: ! 1077: ! 1078: /* Drive commands */ ! 1079: ! 1080: #define DRV_SEK 0x0000 /* seek (last 12 bits are track position) */ ! 1081: #define DRV_HOS 0xA000 /* high order seek (last 4 bits are high order (<<12) track position) */ ! 1082: #define DRV_REC 0x1000 /* recalibrate */ ! 1083: #define DRV_RDS 0x2000 /* return drive status */ ! 1084: #define DRV_RCA 0x2200 /* return current track address */ ! 1085: #define DRV_RES 0x2800 /* return extended status */ ! 1086: #define DRV_RHS 0x2A00 /* return hardware status */ ! 1087: #define DRV_RGC 0x3000 /* return general config */ ! 1088: #define DRV_RVI 0x3F00 /* return drive version information */ ! 1089: #define DRV_SRH 0x4100 /* select read head */ ! 1090: #define DRV_SVH 0x4200 /* select verify head */ ! 1091: #define DRV_SWH 0x4300 /* select write head */ ! 1092: #define DRV_SEH 0x4400 /* select erase head */ ! 1093: #define DRV_SFH 0x4500 /* select RF head */ ! 1094: #define DRV_RID 0x5000 /* reset attn and status */ ! 1095: #define DRV_RJ 0x5100 /* relative jump (see below) */ ! 1096: #define DRV_SPM 0x5200 /* stop motor */ ! 1097: #define DRV_STM 0x5300 /* start motor */ ! 1098: #define DRV_LC 0x5400 /* lock cartridge */ ! 1099: #define DRV_ULC 0x5500 /* unlock cartridge */ ! 1100: #define DRV_EC 0x5600 /* eject */ ! 1101: #define DRV_SOO 0x5900 /* spiral operation on */ ! 1102: #define DRV_SOF 0x5A00 /* spiral operation off */ ! 1103: #define DRV_RSD 0x8000 /* request self-diagnostic */ ! 1104: #define DRV_SD 0xB000 /* send data (last 12 bits used) */ ! 1105: ! 1106: /* Relative jump: ! 1107: * bits 0 to 3: offset (signed -8 (0x8) to +7 (0x7) ! 1108: * bits 4 to 6: head select ! 1109: */ ! 1110: ! 1111: /* Head select for relative jump */ ! 1112: #define RJ_READ 0x10 ! 1113: #define RJ_VERIFY 0x20 ! 1114: #define RJ_WRITE 0x30 ! 1115: #define RJ_ERASE 0x40 ! 1116: ! 1117: /* Drive status information */ ! 1118: ! 1119: /* Disk status (returned for DRV_RDS) */ ! 1120: #define DS_INSERT 0x0004 /* load completed */ ! 1121: #define DS_RESET 0x0008 /* power on reset */ ! 1122: #define DS_SEEK 0x0010 /* address fault */ ! 1123: #define DS_CMD 0x0020 /* invalid or unimplemented command */ ! 1124: #define DS_INTFC 0x0040 /* interface fault */ ! 1125: #define DS_I_PARITY 0x0080 /* interface parity error */ ! 1126: #define DS_STOPPED 0x0200 /* not spinning */ ! 1127: #define DS_SIDE 0x0400 /* media upside down */ ! 1128: #define DS_SERVO 0x0800 /* servo not ready */ ! 1129: #define DS_POWER 0x1000 /* laser power alarm */ ! 1130: #define DS_WP 0x2000 /* disk write protected */ ! 1131: #define DS_EMPTY 0x4000 /* no disk inserted */ ! 1132: #define DS_BUSY 0x8000 /* execute busy */ ! 1133: ! 1134: /* Extended status (returned for DRV_RES) */ ! 1135: #define ES_RF 0x0002 /* RF detected */ ! 1136: #define ES_WR_INH 0x0008 /* write inhibit (high temperature) */ ! 1137: #define ES_WRITE 0x0010 /* write mode failed */ ! 1138: #define ES_COARSE 0x0020 /* coarse seek failed */ ! 1139: #define ES_TEST 0x0040 /* test write failed */ ! 1140: #define ES_SLEEP 0x0080 /* sleep/wakeup failed */ ! 1141: #define ES_LENS 0x0100 /* lens out of range */ ! 1142: #define ES_TRACKING 0x0200 /* tracking servo failed */ ! 1143: #define ES_PLL 0x0400 /* PLL failed */ ! 1144: #define ES_FOCUS 0x0800 /* focus failed */ ! 1145: #define ES_SPEED 0x1000 /* not at speed */ ! 1146: #define ES_STUCK 0x2000 /* disk cartridge stuck */ ! 1147: #define ES_ENCODER 0x4000 /* linear encoder failed */ ! 1148: #define ES_LOST 0x8000 /* tracing failure */ ! 1149: ! 1150: /* Hardware status (returned for DRV_RHS) */ ! 1151: #define HS_LASER 0x0040 /* laser power failed */ ! 1152: #define HS_INIT 0x0080 /* drive init failed */ ! 1153: #define HS_TEMP 0x0100 /* high drive temperature */ ! 1154: #define HS_CLAMP 0x0200 /* spindle clamp misaligned */ ! 1155: #define HS_STOP 0x0400 /* spindle stop timeout */ ! 1156: #define HS_TEMPSENS 0x0800 /* temperature sensor failed */ ! 1157: #define HS_LENSPOS 0x1000 /* lens position failure */ ! 1158: #define HS_SERVOCMD 0x2000 /* servo command failure */ ! 1159: #define HS_SERVOTO 0x4000 /* servo timeout failure */ ! 1160: #define HS_HEAD 0x8000 /* head select failure */ ! 1161: ! 1162: /* Version information (returned for DRV_RVI) */ ! 1163: #define VI_VERSION 0x0880 ! 1164: ! 1165: void mo_drive_cmd(void) { ! 1166: ! 1167: if (!modrv[dnum].connected) { ! 1168: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Drive %i not connected.\n", dnum); ! 1169: return; ! 1170: } ! 1171: ! 1172: Uint16 command = (mo.csrh<<8) | mo.csrl; ! 1173: ! 1174: /* Command in progress */ ! 1175: modrv[dnum].complete=false; ! 1176: ! 1177: if ((command&0xF000)==DRV_SEK) { ! 1178: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Seek (%04X)\n", command); ! 1179: mo_seek(command); ! 1180: } else if ((command&0xF000)==DRV_SD) { ! 1181: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Send Data (%04X)\n", command); ! 1182: abort(); ! 1183: } else if ((command&0xFF00)==DRV_RJ) { ! 1184: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Relative Jump (%04X)\n", command); ! 1185: mo_jump_head(command); ! 1186: } else if ((command&0xFFF0)==DRV_HOS) { ! 1187: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: High Order Seek (%04X)\n", command); ! 1188: mo_high_order_seek(command); ! 1189: } else { ! 1190: ! 1191: switch (command&0xFFFF) { ! 1192: case DRV_REC: ! 1193: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Recalibrate (%04X)\n", command); ! 1194: mo_recalibrate(); ! 1195: break; ! 1196: case DRV_RDS: ! 1197: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Return Drive Status (%04X)\n", command); ! 1198: mo_return_drive_status(); ! 1199: break; ! 1200: case DRV_RCA: ! 1201: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Return Current Track Address (%04X)\n", command); ! 1202: mo_return_track_addr(); ! 1203: break; ! 1204: case DRV_RES: ! 1205: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Return Extended Status (%04X)\n", command); ! 1206: mo_return_extended_status(); ! 1207: break; ! 1208: case DRV_RHS: ! 1209: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Return Hardware Status (%04X)\n", command); ! 1210: mo_return_hardware_status(); ! 1211: break; ! 1212: case DRV_RGC: ! 1213: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Return General Config (%04X)\n", command); ! 1214: abort(); ! 1215: break; ! 1216: case DRV_RVI: ! 1217: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Return Version Information (%04X)\n", command); ! 1218: mo_return_version(); ! 1219: break; ! 1220: case DRV_SRH: ! 1221: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Select Read Head (%04X)\n", command); ! 1222: mo_select_head(READ_HEAD); ! 1223: break; ! 1224: case DRV_SVH: ! 1225: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Select Verify Head (%04X)\n", command); ! 1226: mo_select_head(VERIFY_HEAD); ! 1227: break; ! 1228: case DRV_SWH: ! 1229: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Select Write Head (%04X)\n", command); ! 1230: mo_select_head(WRITE_HEAD); ! 1231: break; ! 1232: case DRV_SEH: ! 1233: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Select Erase Head (%04X)\n", command); ! 1234: mo_select_head(ERASE_HEAD); ! 1235: break; ! 1236: case DRV_SFH: ! 1237: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Select RF Head (%04X)\n", command); ! 1238: mo_select_head(RF_HEAD); ! 1239: break; ! 1240: case DRV_RID: ! 1241: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Reset Attn and Status (%04X)\n", command); ! 1242: mo_reset_attn_status(); ! 1243: break; ! 1244: case DRV_SPM: ! 1245: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Stop Spindle Motor (%04X)\n", command); ! 1246: mo_stop_spinning(); ! 1247: break; ! 1248: case DRV_STM: ! 1249: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Start Spindle Motor (%04X)\n", command); ! 1250: mo_start_spinning(); ! 1251: break; ! 1252: case DRV_LC: ! 1253: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Lock Cartridge (%04X)\n", command); ! 1254: abort(); ! 1255: break; ! 1256: case DRV_ULC: ! 1257: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Unlock Cartridge (%04X)\n", command); ! 1258: abort(); ! 1259: break; ! 1260: case DRV_EC: ! 1261: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Eject (%04X)\n", command); ! 1262: mo_eject_disk(-1); ! 1263: break; ! 1264: case DRV_SOO: ! 1265: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Start Spiraling (%04X)\n", command); ! 1266: mo_start_spiraling(); ! 1267: break; ! 1268: case DRV_SOF: ! 1269: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Stop Spiraling (%04X)\n", command); ! 1270: mo_stop_spiraling(); ! 1271: break; ! 1272: case DRV_RSD: ! 1273: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Request Self-Diagnostic (%04X)\n", command); ! 1274: mo_self_diagnostic(); ! 1275: break; ! 1276: ! 1277: default: ! 1278: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Unimplemented command! (%04X)\n", command); ! 1279: mo_unimplemented_cmd(); ! 1280: break; ! 1281: } ! 1282: } ! 1283: Statusbar_BlinkLed(DEVICE_LED_OD); ! 1284: } ! 1285: ! 1286: ! 1287: bool mo_drive_empty(void) { ! 1288: if (!modrv[dnum].inserted) { ! 1289: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Drive %i: No disk inserted.\n", dnum); ! 1290: modrv[dnum].dstat |= DS_EMPTY; ! 1291: mo_set_signals(true, true, CMD_DELAY); ! 1292: return true; ! 1293: } else { ! 1294: return false; ! 1295: } ! 1296: } ! 1297: ! 1298: bool mo_protected(void) { ! 1299: if (modrv[dnum].protected) { ! 1300: if (modrv[dnum].head==ERASE_HEAD || modrv[dnum].head==WRITE_HEAD) { ! 1301: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Drive command: Drive %i: Disk is write protected!\n", dnum); ! 1302: modrv[dnum].dstat|=DS_WP; ! 1303: modrv[dnum].head=NO_HEAD; ! 1304: mo_set_signals(true, true, CMD_DELAY); ! 1305: return true; ! 1306: } ! 1307: } ! 1308: return false; ! 1309: } ! 1310: ! 1311: void mo_seek(Uint16 command) { ! 1312: #if SEEK_TIMING ! 1313: int seek_time=modrv[dnum].head_pos; ! 1314: #endif ! 1315: if (mo_drive_empty()) { ! 1316: return; ! 1317: } ! 1318: modrv[dnum].seeking = true; ! 1319: modrv[dnum].head_pos = (modrv[dnum].ho_head_pos&0xF000) | (command&0x0FFF); ! 1320: #if SEEK_TIMING ! 1321: if ((Uint32)seek_time>modrv[dnum].head_pos) { ! 1322: seek_time=seek_time-modrv[dnum].head_pos; ! 1323: } else { ! 1324: seek_time=modrv[dnum].head_pos-seek_time; ! 1325: } ! 1326: if (seek_time>95000) { ! 1327: seek_time=95000; ! 1328: } ! 1329: seek_time+=5000; ! 1330: ! 1331: mo_set_signals(true, false, seek_time); ! 1332: #else ! 1333: mo_set_signals(true, false, CMD_DELAY); ! 1334: #endif ! 1335: } ! 1336: ! 1337: void mo_high_order_seek(Uint16 command) { ! 1338: if (mo_drive_empty()) { ! 1339: return; ! 1340: } ! 1341: if ((command&0xF)>4) { ! 1342: modrv[dnum].dstat|=DS_SEEK; ! 1343: mo_set_signals(true, true, CMD_DELAY); ! 1344: } else { ! 1345: modrv[dnum].ho_head_pos = (command&0xF)<<12; ! 1346: mo_set_signals(true, false, CMD_DELAY); ! 1347: } ! 1348: } ! 1349: ! 1350: void mo_jump_head(Uint16 command) { ! 1351: if (mo_drive_empty()) { ! 1352: return; ! 1353: } ! 1354: modrv[dnum].seeking = true; ! 1355: ! 1356: int offset = command&0x7; ! 1357: if (command&0x8) { ! 1358: offset = 8 - offset; ! 1359: modrv[dnum].head_pos-=offset; ! 1360: } else { ! 1361: modrv[dnum].head_pos+=offset; ! 1362: } ! 1363: modrv[dnum].sec_offset=0; ! 1364: ! 1365: switch (command&0xF0) { ! 1366: case RJ_READ: ! 1367: modrv[dnum].head=READ_HEAD; ! 1368: break; ! 1369: case RJ_VERIFY: ! 1370: modrv[dnum].head=VERIFY_HEAD; ! 1371: break; ! 1372: case RJ_WRITE: ! 1373: modrv[dnum].head=WRITE_HEAD; ! 1374: break; ! 1375: case RJ_ERASE: ! 1376: modrv[dnum].head=ERASE_HEAD; ! 1377: break; ! 1378: ! 1379: default: ! 1380: modrv[dnum].head=NO_HEAD; ! 1381: break; ! 1382: } ! 1383: Log_Printf(LOG_MO_CMD_LEVEL,"[MO] Relative Jump: %i sectors %s (%s head)\n", offset*16, ! 1384: (command&0x8)?"back":"forward", ! 1385: (command&0xF0)==RJ_READ?"read": ! 1386: (command&0xF0)==RJ_VERIFY?"verify": ! 1387: (command&0xF0)==RJ_WRITE?"write": ! 1388: (command&0xF0)==RJ_ERASE?"erase":"unknown"); ! 1389: ! 1390: if (mo_protected()) { ! 1391: return; ! 1392: } ! 1393: #if SEEK_TIMING ! 1394: mo_set_signals(true, false, 1600); ! 1395: #else ! 1396: mo_set_signals(true, false, CMD_DELAY); ! 1397: #endif ! 1398: } ! 1399: ! 1400: void mo_recalibrate(void) { ! 1401: if (mo_drive_empty()) { ! 1402: return; ! 1403: } ! 1404: modrv[dnum].head_pos = 0; ! 1405: modrv[dnum].sec_offset = 0; ! 1406: modrv[dnum].spiraling = false; ! 1407: ! 1408: mo_set_signals(true, false, CMD_DELAY); ! 1409: } ! 1410: ! 1411: void mo_return_drive_status(void) { ! 1412: if (!modrv[dnum].spinning) { ! 1413: modrv[dnum].dstat|=DS_STOPPED; ! 1414: } ! 1415: if (!modrv[dnum].inserted) { ! 1416: modrv[dnum].dstat|=DS_EMPTY; ! 1417: } ! 1418: modrv[dnum].status = modrv[dnum].dstat; ! 1419: mo_set_signals(true, false, CMD_DELAY); ! 1420: } ! 1421: ! 1422: void mo_return_track_addr(void) { ! 1423: modrv[dnum].status = modrv[dnum].head_pos; ! 1424: mo_set_signals(true, false, CMD_DELAY); ! 1425: } ! 1426: ! 1427: void mo_return_extended_status(void) { ! 1428: modrv[dnum].status = modrv[dnum].estat; ! 1429: mo_set_signals(true, false, CMD_DELAY); ! 1430: } ! 1431: ! 1432: void mo_return_hardware_status(void) { ! 1433: modrv[dnum].status = modrv[dnum].hstat; ! 1434: mo_set_signals(true, false, CMD_DELAY); ! 1435: } ! 1436: ! 1437: void mo_return_version(void) { ! 1438: modrv[dnum].status = VI_VERSION; ! 1439: mo_set_signals(true, false, CMD_DELAY); ! 1440: } ! 1441: ! 1442: void mo_select_head(int head) { ! 1443: if (mo_drive_empty()) { ! 1444: return; ! 1445: } ! 1446: modrv[dnum].head = head; ! 1447: if (mo_protected()) { ! 1448: return; ! 1449: } ! 1450: mo_set_signals(true, false, CMD_DELAY); ! 1451: } ! 1452: ! 1453: void mo_reset_attn_status(void) { ! 1454: modrv[dnum].dstat=modrv[dnum].estat=modrv[dnum].hstat=0; ! 1455: modrv[dnum].attn=false; ! 1456: mo_set_signals(true, false, CMD_DELAY); ! 1457: } ! 1458: ! 1459: void mo_stop_spinning(void) { ! 1460: if (mo_drive_empty()) { ! 1461: return; ! 1462: } ! 1463: Statusbar_AddMessage("Stop magneto-optical disk spin.", 0); ! 1464: modrv[dnum].spinning=false; ! 1465: modrv[dnum].spiraling=false; ! 1466: mo_set_signals(true, false, CMD_DELAY); ! 1467: } ! 1468: ! 1469: void mo_start_spinning(void) { ! 1470: if (mo_drive_empty()) { ! 1471: return; ! 1472: } ! 1473: Statusbar_AddMessage("Spin-up magneto-optical disk.", 0); ! 1474: modrv[dnum].dstat &= ~DS_STOPPED; ! 1475: modrv[dnum].spinning=true; ! 1476: mo_set_signals(true, false, 1600000); ! 1477: } ! 1478: ! 1479: void mo_eject_disk(int drv) { ! 1480: if (drv<0) { /* Called from emulator, else called from GUI */ ! 1481: drv=dnum; ! 1482: if (mo_drive_empty()) ! 1483: return; ! 1484: ! 1485: Statusbar_AddMessage("Ejecting magneto-optical disk.", 0); ! 1486: mo_set_signals(true, false, CMD_DELAY); ! 1487: } ! 1488: ! 1489: Log_Printf(LOG_WARN, "MO disk %i: Eject",drv); ! 1490: ! 1491: File_Close(modrv[drv].dsk); ! 1492: modrv[drv].dsk=NULL; ! 1493: modrv[drv].inserted=false; ! 1494: modrv[drv].spinning=false; ! 1495: modrv[drv].spiraling=false; ! 1496: ! 1497: ConfigureParams.MO.drive[drv].bDiskInserted=false; ! 1498: ConfigureParams.MO.drive[drv].szImageName[0]='\0'; ! 1499: } ! 1500: ! 1501: void mo_insert_disk(int drv) { ! 1502: Log_Printf(LOG_WARN, "MO disk %i: Insert",drv); ! 1503: ! 1504: if (ConfigureParams.MO.drive[drv].bWriteProtected) { ! 1505: modrv[drv].dsk = File_Open(ConfigureParams.MO.drive[drv].szImageName, "rb"); ! 1506: if (modrv[drv].dsk == NULL) { ! 1507: Log_Printf(LOG_WARN, "MO Disk%i: Cannot open image file %s\n", ! 1508: drv, ConfigureParams.MO.drive[drv].szImageName); ! 1509: modrv[drv].inserted=false; ! 1510: modrv[drv].protected=false; ! 1511: Statusbar_AddMessage("Cannot insert magneto-optical disk.", 0); ! 1512: return; ! 1513: } else { ! 1514: modrv[drv].inserted=true; ! 1515: modrv[drv].protected=true; ! 1516: } ! 1517: } else { ! 1518: modrv[drv].dsk = File_Open(ConfigureParams.MO.drive[drv].szImageName, "rb+"); ! 1519: if (modrv[drv].dsk == NULL) { ! 1520: modrv[drv].dsk = File_Open(ConfigureParams.MO.drive[drv].szImageName, "rb"); ! 1521: if (modrv[drv].dsk == NULL) { ! 1522: Log_Printf(LOG_WARN, "MO Disk%i: Cannot open image file %s\n", ! 1523: drv, ConfigureParams.MO.drive[drv].szImageName); ! 1524: modrv[drv].inserted=false; ! 1525: modrv[drv].protected=false; ! 1526: Statusbar_AddMessage("Cannot insert magneto-optical disk.", 0); ! 1527: return; ! 1528: } else { ! 1529: modrv[drv].inserted=true; ! 1530: modrv[drv].protected=true; ! 1531: } ! 1532: } else { ! 1533: modrv[drv].inserted=true; ! 1534: modrv[drv].protected=false; ! 1535: } ! 1536: } ! 1537: ! 1538: Statusbar_AddMessage("Inserting magneto-optical disk.", 0); ! 1539: modrv[drv].dstat&=~DS_EMPTY; ! 1540: modrv[drv].dstat|=DS_INSERT; ! 1541: modrv[drv].spinning=false; ! 1542: modrv[drv].spiraling=false; ! 1543: mo_push_signals(true, false, drv); ! 1544: } ! 1545: ! 1546: void mo_start_spiraling(void) { ! 1547: if (mo_drive_empty()) { ! 1548: return; ! 1549: } ! 1550: if (!modrv[dnum].spinning) { ! 1551: modrv[dnum].dstat|=DS_STOPPED; ! 1552: mo_set_signals(true, true, CMD_DELAY); ! 1553: return; ! 1554: } ! 1555: ! 1556: if (!modrv[0].spiraling && !modrv[1].spiraling) { /* periodic disk operation already active? */ ! 1557: CycInt_AddRelativeInterruptUsCycles(SECTOR_IO_DELAY, 400, INTERRUPT_MO_IO); ! 1558: } ! 1559: modrv[dnum].spiraling=true; ! 1560: ! 1561: mo_set_signals(true, false, CMD_DELAY); ! 1562: } ! 1563: ! 1564: void mo_stop_spiraling(void) { ! 1565: if (mo_drive_empty()) { ! 1566: return; ! 1567: } ! 1568: modrv[dnum].spiraling=false; ! 1569: mo_set_signals(true, false, CMD_DELAY); ! 1570: } ! 1571: ! 1572: void mo_spiraling_operation(void) { ! 1573: if (!modrv[0].spiraling && !modrv[1].spiraling) { /* this stops periodic disk operation */ ! 1574: return; /* nothing to do */ ! 1575: } ! 1576: ! 1577: int i; ! 1578: for (i=0; i<MO_MAX_DRIVES; i++) { ! 1579: if (modrv[i].spiraling && !modrv[i].seeking) { ! 1580: ! 1581: /* If the drive is selected, connect to formatter */ ! 1582: if (i==dnum) { ! 1583: fmt_io((modrv[i].head_pos<<8)|modrv[i].sec_offset); ! 1584: } ! 1585: ! 1586: /* Continue spiraling */ ! 1587: modrv[i].sec_offset++; ! 1588: modrv[i].head_pos+=modrv[i].sec_offset/MO_SEC_PER_TRACK; ! 1589: modrv[i].sec_offset%=MO_SEC_PER_TRACK; ! 1590: } ! 1591: } ! 1592: CycInt_AddRelativeInterruptUsCycles(SECTOR_IO_DELAY, 400, INTERRUPT_MO_IO); ! 1593: } ! 1594: ! 1595: void mo_self_diagnostic(void) { ! 1596: mo_set_signals(true, false, CMD_DELAY); ! 1597: } ! 1598: ! 1599: void MO_IO_Handler(void) { ! 1600: CycInt_AcknowledgeInterrupt(); ! 1601: ! 1602: mo_spiraling_operation(); ! 1603: } ! 1604: ! 1605: void mo_unimplemented_cmd(void) { ! 1606: modrv[dnum].dstat|=DS_CMD; ! 1607: mo_set_signals(true, true, CMD_DELAY); ! 1608: } ! 1609: ! 1610: void mo_reset(void) { ! 1611: int i; ! 1612: for (i=0; i<MO_MAX_DRIVES; i++) { ! 1613: if (modrv[i].connected) { ! 1614: modrv[i].head=NO_HEAD; ! 1615: modrv[i].head_pos=modrv[i].ho_head_pos=0; ! 1616: modrv[i].sec_offset=0; ! 1617: ! 1618: modrv[i].dstat=DS_RESET; ! 1619: modrv[i].estat=modrv[i].hstat=0; ! 1620: if (modrv[i].inserted) { /* CHECK: really spin up on reset? */ ! 1621: modrv[i].spinning=true; ! 1622: } else { ! 1623: modrv[i].spinning=false; ! 1624: } ! 1625: modrv[i].spiraling=false; ! 1626: ! 1627: if (!modrv[i].inserted) { ! 1628: modrv[i].dstat|=DS_EMPTY; ! 1629: } else if (!modrv[i].spinning) { ! 1630: modrv[i].dstat|=DS_STOPPED; ! 1631: } ! 1632: modrv[i].attn=false; ! 1633: modrv[i].complete=true; ! 1634: } ! 1635: } ! 1636: } ! 1637: ! 1638: ! 1639: /* MO drive signals */ ! 1640: ! 1641: void mo_push_signals(bool complete, bool attn, int drive) { ! 1642: if (drive<0) { ! 1643: Log_Printf(LOG_WARN, "[MO] Error: No drive specified for delayed interrupt."); ! 1644: abort(); ! 1645: } ! 1646: bool interrupt = false; ! 1647: ! 1648: if (!modrv[drive].complete) { ! 1649: modrv[drive].complete=complete; ! 1650: if (modrv[drive].complete) { ! 1651: if (drive==dnum && mo.intmask&MOINT_CMD_COMPL) { ! 1652: interrupt=true; ! 1653: } ! 1654: } ! 1655: } ! 1656: if (!modrv[drive].attn) { ! 1657: modrv[drive].attn=attn; ! 1658: if (modrv[drive].attn) { ! 1659: if (drive==dnum && mo.intmask&MOINT_ATTN) { ! 1660: interrupt=true; ! 1661: } ! 1662: } ! 1663: } ! 1664: ! 1665: modrv[drive].seeking=false; ! 1666: ! 1667: if (interrupt) { ! 1668: set_interrupt(INT_DISK, SET_INT); ! 1669: } ! 1670: } ! 1671: ! 1672: bool delayed_compl; ! 1673: bool delayed_attn; ! 1674: int delayed_drive=-1; ! 1675: ! 1676: void mo_set_signals(bool complete, bool attn, int delay) { ! 1677: if (delay>0) { ! 1678: if (delayed_drive>=0) { ! 1679: if (delayed_drive!=dnum) { ! 1680: Log_Printf(LOG_WARN, "[MO] Warning: Delayed interrupt from other drive (%i) in progress!",delayed_drive); ! 1681: mo_push_signals(delayed_compl, delayed_attn, delayed_drive); ! 1682: CycInt_RemovePendingInterrupt(INTERRUPT_MO); ! 1683: } else { ! 1684: Log_Printf(LOG_WARN, "[MO] Warning: Delayed interrupt already in progress!"); ! 1685: } ! 1686: } ! 1687: delayed_drive=dnum; ! 1688: delayed_compl=complete; ! 1689: delayed_attn=attn; ! 1690: CycInt_AddRelativeInterruptUsCycles(delay, CMD_DELAY, INTERRUPT_MO); ! 1691: } else { ! 1692: mo_push_signals(complete, attn, dnum); ! 1693: } ! 1694: } ! 1695: ! 1696: void MO_InterruptHandler(void) { ! 1697: CycInt_AcknowledgeInterrupt(); ! 1698: ! 1699: mo_push_signals(delayed_compl,delayed_attn,delayed_drive); ! 1700: ! 1701: delayed_compl=false; ! 1702: delayed_attn=false; ! 1703: delayed_drive=-1; ! 1704: } ! 1705: ! 1706: ! 1707: /* Initialize/Uninitialize MO disks */ ! 1708: void MO_Init(void) { ! 1709: Log_Printf(LOG_WARN, "Loading magneto-optical disks:"); ! 1710: int i; ! 1711: ! 1712: for (i=0; i<MO_MAX_DRIVES; i++) { ! 1713: modrv[i].spinning=false; ! 1714: modrv[i].spiraling=false; ! 1715: /* Check if files exist. */ ! 1716: if (ConfigureParams.MO.drive[i].bDriveConnected) { ! 1717: modrv[i].connected=true; ! 1718: modrv[i].complete=true; ! 1719: modrv[i].attn=false; ! 1720: modrv[i].dstat=modrv[i].estat=modrv[i].hstat=0; ! 1721: if (ConfigureParams.MO.drive[i].bDiskInserted && ! 1722: File_Exists(ConfigureParams.MO.drive[i].szImageName)) { ! 1723: if (ConfigureParams.MO.drive[i].bWriteProtected) { ! 1724: modrv[i].dsk = File_Open(ConfigureParams.MO.drive[i].szImageName, "rb"); ! 1725: if (modrv[i].dsk == NULL) { ! 1726: Log_Printf(LOG_WARN, "MO Disk%i: Cannot open image file %s\n", ! 1727: i, ConfigureParams.MO.drive[i].szImageName); ! 1728: modrv[i].inserted=false; ! 1729: modrv[i].protected=false; ! 1730: } else { ! 1731: modrv[i].inserted=true; ! 1732: modrv[i].protected=true; ! 1733: } ! 1734: } else { ! 1735: modrv[i].dsk = File_Open(ConfigureParams.MO.drive[i].szImageName, "rb+"); ! 1736: if (modrv[i].dsk == NULL) { ! 1737: modrv[i].dsk = File_Open(ConfigureParams.MO.drive[i].szImageName, "rb"); ! 1738: if (modrv[i].dsk == NULL) { ! 1739: Log_Printf(LOG_WARN, "MO Disk%i: Cannot open image file %s\n", ! 1740: i, ConfigureParams.MO.drive[i].szImageName); ! 1741: modrv[i].inserted=false; ! 1742: modrv[i].protected=false; ! 1743: } else { ! 1744: modrv[i].inserted=true; ! 1745: modrv[i].protected=true; ! 1746: } ! 1747: } else { ! 1748: modrv[i].inserted=true; ! 1749: modrv[i].protected=false; ! 1750: } ! 1751: } ! 1752: } else { ! 1753: modrv[i].dsk = NULL; ! 1754: modrv[i].inserted=false; ! 1755: } ! 1756: } else { ! 1757: modrv[i].connected=false; ! 1758: modrv[i].complete=false; ! 1759: modrv[i].attn=false; ! 1760: } ! 1761: ! 1762: Log_Printf(LOG_WARN, "MO Disk%i: %s\n",i,ConfigureParams.MO.drive[i].szImageName); ! 1763: } ! 1764: ! 1765: /* Initialize formatter variables */ ! 1766: ecc_state=ECC_STATE_DONE; ! 1767: } ! 1768: ! 1769: void MO_Uninit(void) { ! 1770: if (modrv[0].dsk) ! 1771: File_Close(modrv[0].dsk); ! 1772: if (modrv[1].dsk) { ! 1773: File_Close(modrv[1].dsk); ! 1774: } ! 1775: modrv[0].dsk = modrv[1].dsk = NULL; ! 1776: modrv[0].inserted = modrv[1].inserted = false; ! 1777: } ! 1778: ! 1779: void MO_Insert(int drive) { ! 1780: Log_Printf(LOG_WARN, "Loading magneto-optical disk:"); ! 1781: Log_Printf(LOG_WARN, "MO Disk%i: %s\n",drive,ConfigureParams.MO.drive[drive].szImageName); ! 1782: ! 1783: mo_insert_disk(drive); ! 1784: } ! 1785: ! 1786: void MO_Eject(int drive) { ! 1787: Log_Printf(LOG_WARN, "Unloading magneto-optical disk %i",drive); ! 1788: ! 1789: mo_eject_disk(drive); ! 1790: } ! 1791: ! 1792: void MO_Reset(void) { ! 1793: MO_Uninit(); ! 1794: MO_Init(); ! 1795: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.