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