|
|
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:
1.1.1.3 ! root 173: static Uint32 get_logical_sector(Uint32 sector_id) {
1.1.1.2 root 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 */
1.1.1.3 ! root 201: #define SECTOR_IO_DELAY 1250
! 202: #define CMD_DELAY 40
1.1.1.2 root 203:
1.1.1.3 ! root 204: #define SEEK_TIMING 1
1.1.1.2 root 205:
1.1.1.3 ! root 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);
1.1.1.2 root 252:
1.1.1.3 ! root 253: static int sector_increment = 0;
1.1.1.2 root 254:
1.1.1.3 ! root 255: static void osp_interrupt(Uint8 interrupt);
1.1.1.2 root 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: }
1.1 root 266:
1.1.1.2 root 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: }
1.1 root 271:
1.1.1.2 root 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;
1.1 root 303: }
1.1.1.2 root 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());
1.1 root 305: }
306:
1.1.1.2 root 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: }
1.1 root 312:
1.1.1.2 root 313: void MO_IntStatus_Write(void) {
1.1 root 314: Uint8 val = IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
1.1.1.2 root 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());
1.1 root 356:
1.1.1.2 root 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());
1.1 root 368:
1.1.1.2 root 369: mo_formatter_cmd();
370: }
1.1 root 371:
1.1.1.2 root 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:
1.1.1.3 ! root 489: #if 0
1.1.1.2 root 490: /* Register debugging */
1.1.1.3 ! root 491: static void print_regs(void) {
1.1.1.2 root 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: }
1.1.1.3 ! root 511: #endif
1.1.1.2 root 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();
1.1 root 680: }
681: break;
1.1.1.2 root 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();
1.1 root 696: break;
1.1.1.2 root 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();
1.1 root 704: }
705: break;
1.1.1.2 root 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: }
1.1 root 717: break;
1.1.1.2 root 718:
719: default:
720: abort();
1.1 root 721: break;
1.1.1.2 root 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);
1.1 root 840:
1.1.1.2 root 841: if (mo.ecc_cnt==0) {
842: mo.ecc_cnt=num_errors;
1.1 root 843: }
1.1.1.2 root 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 */
1.1.1.3 ! root 883: CycInt_AddRelativeInterruptUsCycles(ECC_DELAY, 80, INTERRUPT_ECC_IO);
1.1.1.2 root 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: }
1.1.1.3 ! root 895: CycInt_AddRelativeInterruptUsCycles(ECC_DELAY, 80, INTERRUPT_ECC_IO);
1.1.1.2 root 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;
1.1.1.3 ! root 904: CycInt_AddRelativeInterruptUsCycles(ECC_DELAY, 80, INTERRUPT_ECC_IO);
1.1.1.2 root 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: }
1.1.1.3 ! root 915: CycInt_AddRelativeInterruptUsCycles(ECC_DELAY, 80, INTERRUPT_ECC_IO);
1.1.1.2 root 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: }
1.1 root 944: }
1.1.1.2 root 945: if (ecc_buffer[eccin].size==ecc_buffer[eccin].limit) {
946: ecc_state=ECC_STATE_ECCING;
1.1 root 947: }
1.1.1.2 root 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;
1.1 root 986: }
1.1.1.2 root 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;
1.1 root 994: }
1.1.1.2 root 995: if (ecc_buffer[eccout].size==0) {
996: dma_mo_write_memory(); /* Flush buffer */
997: ecc_sequence_done();
998: return;
1.1 root 999: }
1000: break;
1.1.1.2 root 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!");
1.1 root 1010: break;
1.1.1.2 root 1011:
1.1 root 1012: default:
1.1.1.2 root 1013: Log_Printf(LOG_WARN, "[OSP] Warning: ECC was reset while busy!");
1014: return;
1015: }
1016:
1.1.1.3 ! root 1017: CycInt_AddRelativeInterruptUsCycles(ECC_DELAY, 80, INTERRUPT_ECC_IO);
1.1.1.2 root 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:
1.1.1.3 ! root 1031: File_Read(ecc_buffer[eccin].data, MO_SECTORSIZE_DISK, sector_num*MO_SECTORSIZE_DISK, modrv[dnum].dsk);
1.1.1.2 root 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) {
1.1.1.3 ! root 1043: File_Write(ecc_buffer[eccout].data, MO_SECTORSIZE_DISK, sector_num*MO_SECTORSIZE_DISK, modrv[dnum].dsk);
1.1.1.2 root 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:
1.1.1.3 ! root 1063: File_Write(erase_buf, MO_SECTORSIZE_DISK, sector_num*MO_SECTORSIZE_DISK, modrv[dnum].dsk);
1.1.1.2 root 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:
1.1.1.3 ! root 1072: File_Read(ecc_buffer[eccin].data, MO_SECTORSIZE_DISK, sector_num*MO_SECTORSIZE_DISK, modrv[dnum].dsk);
1.1.1.2 root 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;
1.1 root 1170: }
1.1.1.2 root 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;
1.1 root 1309: }
1310:
1.1.1.2 root 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 (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: }
1.1.1.3 ! root 1326: if (seek_time>95000) {
! 1327: seek_time=95000;
1.1.1.2 root 1328: }
1.1.1.3 ! root 1329: seek_time+=5000;
! 1330:
! 1331: mo_set_signals(true, false, seek_time);
1.1.1.2 root 1332: #else
1333: mo_set_signals(true, false, CMD_DELAY);
1334: #endif
1335: }
1.1 root 1336:
1.1.1.2 root 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;
1.1 root 1368: break;
1.1.1.2 root 1369: case RJ_VERIFY:
1370: modrv[dnum].head=VERIFY_HEAD;
1.1 root 1371: break;
1.1.1.2 root 1372: case RJ_WRITE:
1373: modrv[dnum].head=WRITE_HEAD;
1374: break;
1375: case RJ_ERASE:
1376: modrv[dnum].head=ERASE_HEAD;
1.1 root 1377: break;
1378:
1379: default:
1.1.1.2 root 1380: modrv[dnum].head=NO_HEAD;
1.1 root 1381: break;
1382: }
1.1.1.2 root 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
1.1.1.3 ! root 1394: mo_set_signals(true, false, 1600);
1.1.1.2 root 1395: #else
1396: mo_set_signals(true, false, CMD_DELAY);
1397: #endif
1.1 root 1398: }
1399:
1.1.1.2 root 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: }
1.1 root 1426:
1.1.1.2 root 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;
1.1.1.3 ! root 1476: mo_set_signals(true, false, 1600000);
1.1.1.2 root 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");
1.1.1.3 ! root 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: }
1.1.1.2 root 1517: } else {
1518: modrv[drv].dsk = File_Open(ConfigureParams.MO.drive[drv].szImageName, "rb+");
1.1.1.3 ! root 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: }
1.1.1.2 root 1536: }
1.1.1.3 ! root 1537:
1.1.1.2 root 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? */
1.1.1.3 ! root 1557: CycInt_AddRelativeInterruptUsCycles(SECTOR_IO_DELAY, 400, INTERRUPT_MO_IO);
1.1.1.2 root 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:
1.1 root 1577: int i;
1.1.1.2 root 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: }
1.1.1.3 ! root 1592: CycInt_AddRelativeInterruptUsCycles(SECTOR_IO_DELAY, 400, INTERRUPT_MO_IO);
1.1.1.2 root 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);
1.1 root 1608: }
1609:
1.1.1.2 root 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;
1.1.1.3 ! root 1690: CycInt_AddRelativeInterruptUsCycles(delay, CMD_DELAY, INTERRUPT_MO);
1.1.1.2 root 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");
1.1.1.3 ! root 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: }
1.1.1.2 root 1734: } else {
1735: modrv[i].dsk = File_Open(ConfigureParams.MO.drive[i].szImageName, "rb+");
1.1.1.3 ! root 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: }
1.1.1.2 root 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.