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