|
|
1.1 root 1: /*
2: Hatari
3:
4: Floppy Disc Controller(FDC) emulation. We need to simulate the movement of the head of the
5: floppy disc drive to accurately perform the FDC commands, such as 'Step'. The is important
6: for ST demo disc images. We have to go into a lot of details - including the start up/stop
7: of the drive motor.
8: To help with this emulation, we keep our own internal commands which are checked each HBL
9: to perform the transfer of data from our disc image into the ST RAM area by simulating the
10: DMA.
11: */
12:
13: #include "main.h"
14: #include "debug.h"
15: #include "decode.h"
16: #include "dialog.h"
17: #include "fdc.h"
18: #include "floppy.h"
19: #include "ikbd.h"
20: #include "m68000.h"
21: #include "memorySnapShot.h"
22: #include "mfp.h"
23: #include "misc.h"
24: #include "psg.h"
25: #include "stMemory.h"
26:
27: /*
28: Floppy Disc Controller
29:
30: Programmable Sound Generator (YM-2149)
31:
32: 0xff8800(even byte) - PSG Register Data (Read, used for parallel port)
33: - PSG Register Select (Write)
34:
35: Write to bits 0-3 to select PSG register to use(then write data to 0xfff8802)
36: Value Register
37:
38: 0000 Channel A Fine Tune
39: 0001 Channel A Coarse Tune
40: 0010 Channel B Fine Tune
41: 0011 Channel B Coarse Tune
42: 0100 Channel C Fine Tune
43: 0101 Channel C Coarse Tune
44: 0110 Noise Generator Control
45: 0111 Mixer Control - I/O enable
46: 1000 Channel A Amplitude
47: 1001 Channel B Amplitude
48: 1010 Channel C Amplitude
49: 1011 Envelope Period Fine Tune
50: 1100 Envelope Peroid Coarse Tune
51: 1101 Envelope Shape
52: 1110 I/O Port A Select (Write only)
53: 1111 I/O Port B Select
54:
55: 0xfff8802(even byte) - Bits according to 0xff8800 Register select
56:
57: 1110(Register 14) - I/O Port A
58: Bit 0 - Floppy side 0/1
59: Bit 1 - Floppy drive 0 select
60: Bit 2 - Floppy drive 1 select
61: Bit 3 - RS232 Ready to send (RTS)
62: Bit 4 - RS232 Data Terminal Ready (DTR)
63: Bit 5 - Centronics Strobe
64: Bit 6 - General Purpose Output
65: Bit 7 - Reserved
66:
67: ACSI DMA and Floppy Disc Controller(FDC)
68: 0xff8604 - information from file '1772.info.txt, by David Gahris' (register r0)
69: (write) - Disk controller
70: (read) - Disk controller status
71: Bit 0 - Busy. This bit is 1 when the 177x is busy. This bit is 0 when the 177x is free for CPU commands.
72: Bit 1 - Index / Data Request. On Type I commands, this bit is high during the index pulse that occurs once
73: per disk rotation. This bit is low at all times other than the index pulse. For Type II and III commands,
74: Bit 1 high signals the CPU to handle the data register in order to maintain a continuous flow of data.
75: Bit 1 is high when the data register is full during a read or when the data register is empty during a write.
76: "Worst case service time" for Data Request is 23.5 cycles.
77: Bit 2 - Track Zero / Lost Data. After Type I commands, this bit is 0 if the mechanism is at track zero.
78: This bit is 1 if the head is not at track zero. After Type II or III commands, this bit is 1 if the
79: CPU did not respond to Data Request (Status bit 1) in time for the 177x to maintain a continuous data flow.
80: This bit is 0 if the CPU responded promptly to Data Request.
81: Bit 3 - CRC Error. This bit is high if a sector CRC on disk does not match the CRC which the 177x
82: computed from the data. The CRC polynomial is x^16+x^12+x^5+1. If the stored CRC matches the newly
83: calculated CRC, the CRC Error bit is low. If this bit and the Record Not Found bit are set, the error
84: was in an ID field. If this bit is set but Record Not Found is clear, the error was in a data field.
85: Bit 4 - Record Not Found. This bit is set if the 177x cannot find the track, sector, or side which
86: the CPU requested. Otherwise, this bit is clear.
87: Bit 5 - Spin-up / Record Type. For Type I commands, this bit is low during the 6-revolution motor
88: spin-up time. This bit is high after spin-up. For Type II and Type III commands, Bit 5 low
89: indicates a normal data mark. Bit 5 high indicates a deleted data mark.
90: Bit 6 - Write Protect. This bit is not used during reads. During writes, this bit is high when the disk is write protected.
91: Bit 7 - Motor On. This bit is high when the drive motor is on, and low when the motor is off.
92:
93: 0xff8606 - DMA Status(read), DMA Mode Control(write) - NOTE bits 0,9-15 are not used
94: Bit 1 - FDC Pin A0 (See below)
95: Bit 2 - FDC Pin A1
96: Bit 3 - FDC/HDC Register Select
97: Bit 4 - FDC/Sector count select
98: Bit 5 - Reserved
99: Bit 6 - Enable/Disable DMA
100: Bit 7 - HDC/FDC
101: Bit 8 - Read/Write
102:
103: A1 A0 Read Write(bit 8==1)
104: 0 0 Status Command
105: 0 1 Track Register Track Register
106: 1 0 Sector Register Sector Register
107: 1 1 Data Register Data Register
108:
109:
110: This handles any read/writes to the FDC and PSG. FDC commands are then sent through to read/write
111: disc sector code. We have full documents on 1772 FDC, but they use r0,r1,r2,r3 etc.. which are
112: not seen at first glance as Atari access them via the A0,A1 bits. Once this is understood it
113: is all relativly easy as a lot of information can be ignored as we are using disc images and
114: not actual discs. We do NOT support the reading of the PC's A: drive - newer PC's cannot read
115: an ST single sided disc, ST discs are very old and so are dirty which gets onto the PC drive heads
116: and ruins them and also support for disc sector access under Windows is... well not well documented!
117:
118: According to the documentation INTRQ is generated at the completion of each command(causes an interrupt
119: in the MFP). INTRQ is reset by reading the status register OR by loading a new command. So, does this
120: mean the GPIP? Or does it actually CANCEL the interrupt? Can this be done?
121: */
122:
123: #define ENABLE_FLOPPY_SAVING /* Save to floppies */
124:
125: unsigned short int DiscControllerStatus_ff8604rd; /* 0xff8604 (read) */
126: unsigned short int DiscControllerWord_ff8604wr; /* 0xff8604 (write) */
127: unsigned short int DMAStatus_ff8606rd; /* 0xff8606 (read) */
128: unsigned short int DMAModeControl_ff8606wr,DMAModeControl_ff8606wr_prev; /* 0xff8606 (write,store prev for 'toggle' checks) */
129:
130: unsigned short int FDCCommandRegister;
131: short int FDCTrackRegister,FDCSectorRegister,FDCDataRegister;
132: short int FDCSectorCountRegister;
133: int FDCEmulationCommand; /* FDC emulation command currently being exceuted */
134: int FDCEmulationRunning; /* Running command under above */
135: int FDCStepDirection; /* +Track on 'Step' command */
136: short int DiscControllerByte; /* Used to pass parameter back to assembler */
137: BOOL bDMAWaiting; /* Is DMA waiting to copy? */
138: int bMotorOn; /* Is motor on? */
139: int MotorSlowingCount; /* Counter used to slow motor before stopping */
140:
141: short int nReadWriteTrack; /* Parameters used in sector read/writes */
142: short int nReadWriteSector;
143: short int nReadWriteSide;
144: short int nReadWriteDev;
145: unsigned short int nReadWriteSectorsPerTrack;
146: short int nReadWriteSectors;
147:
148: unsigned char DMASectorWorkSpace[NUMBYTESPERSECTOR]; /* Workspace used to copy to/from for floppy DMA */
149:
150: //-----------------------------------------------------------------------
151: /*
152: Reset variables used in FDC
153: */
154: void FDC_Reset(void)
155: {
156: // Clear out FDC registers
157: DiscControllerStatus_ff8604rd = 0;
158: DiscControllerWord_ff8604wr = 0;
159: DMAStatus_ff8606rd = 0x01;
160: DMAModeControl_ff8606wr = DMAModeControl_ff8606wr_prev = 0;
161: FDC_ResetDMAStatus();
162: FDCCommandRegister = 0;
163: FDCTrackRegister = 0;
164: FDCSectorRegister = 1;
165: FDCDataRegister = 0;
166: FDCSectorCountRegister = 0;
167:
168: FDCEmulationCommand = FDCEMU_CMD_NULL; /* FDC emulation command currently being exceuted */
169: FDCEmulationRunning = FDCEMU_RUN_NULL; /* Running command under above */
170:
171: FDCStepDirection = 1; /* +Track on 'Step' command */
172: bDMAWaiting = FALSE; /* No DMA waiting */
173: bMotorOn = FALSE; /* Motor off */
174: MotorSlowingCount = 0; /* Counter for motor slowing down before stopping */
175: }
176:
177: //-----------------------------------------------------------------------
178: /*
179: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
180: */
181: void FDC_MemorySnapShot_Capture(BOOL bSave)
182: {
183: // Save/Restore details
184: MemorySnapShot_Store(&DiscControllerStatus_ff8604rd,sizeof(DiscControllerStatus_ff8604rd));
185: MemorySnapShot_Store(&DiscControllerWord_ff8604wr,sizeof(DiscControllerWord_ff8604wr));
186: MemorySnapShot_Store(&DMAStatus_ff8606rd,sizeof(DMAStatus_ff8606rd));
187: MemorySnapShot_Store(&DMAModeControl_ff8606wr,sizeof(DMAModeControl_ff8606wr));
188: MemorySnapShot_Store(&DMAModeControl_ff8606wr_prev,sizeof(DMAModeControl_ff8606wr_prev));
189: MemorySnapShot_Store(&FDCCommandRegister,sizeof(FDCCommandRegister));
190: MemorySnapShot_Store(&FDCTrackRegister,sizeof(FDCTrackRegister));
191: MemorySnapShot_Store(&FDCSectorRegister,sizeof(FDCSectorRegister));
192: MemorySnapShot_Store(&FDCDataRegister,sizeof(FDCDataRegister));
193: MemorySnapShot_Store(&FDCSectorCountRegister,sizeof(FDCSectorCountRegister));
194: MemorySnapShot_Store(&FDCEmulationCommand,sizeof(FDCEmulationCommand));
195: MemorySnapShot_Store(&FDCEmulationRunning,sizeof(FDCEmulationRunning));
196: MemorySnapShot_Store(&FDCStepDirection,sizeof(FDCStepDirection));
197: MemorySnapShot_Store(&DiscControllerByte,sizeof(DiscControllerByte));
198: MemorySnapShot_Store(&bDMAWaiting,sizeof(bDMAWaiting));
199: MemorySnapShot_Store(&bMotorOn,sizeof(bMotorOn));
200: MemorySnapShot_Store(&MotorSlowingCount,sizeof(MotorSlowingCount));
201: MemorySnapShot_Store(&nReadWriteTrack,sizeof(nReadWriteTrack));
202: MemorySnapShot_Store(&nReadWriteSector,sizeof(nReadWriteSector));
203: MemorySnapShot_Store(&nReadWriteSide,sizeof(nReadWriteSide));
204: MemorySnapShot_Store(&nReadWriteDev,sizeof(nReadWriteDev));
205: MemorySnapShot_Store(&nReadWriteSectorsPerTrack,sizeof(nReadWriteSectorsPerTrack));
206: MemorySnapShot_Store(&nReadWriteSectors,sizeof(nReadWriteSectors));
207: MemorySnapShot_Store(DMASectorWorkSpace,sizeof(DMASectorWorkSpace));
208: }
209:
210: //-----------------------------------------------------------------------
211: /*
212: Turn floppy motor on
213: */
214: void FDC_TurnMotorOn(void)
215: {
216: bMotorOn = TRUE; /* Turn motor on */
217: MotorSlowingCount = 0;
218: }
219:
220: //-----------------------------------------------------------------------
221: /*
222: Turn floppy motor off(this sets a count as it takes a set amount of time for the motor to slow to a halt)
223: */
224: void FDC_TurnMotorOff(void)
225: {
226: MotorSlowingCount = 10; /* Set timer so takes 'x' HBLs before turn off... */
227: }
228:
229: //-----------------------------------------------------------------------
230: /*
231: Update floppy drive motor each HBL, to simulate slowing down and stopping for drive; needed for New Zealand Story(PP_001)
232: */
233: void FDC_UpdateMotor(void)
234: {
235: // Is drive slowing down? Decrement counter
236: if (MotorSlowingCount>0) {
237: MotorSlowingCount--;
238:
239: if (MotorSlowingCount==0)
240: bMotorOn = FALSE; /* Motor finally stopped */
241: }
242: }
243:
244: //-----------------------------------------------------------------------
245: /*
246: Reset DMA Status (RD 0xff8606)
247:
248: This is done by 'toggling' bit 8 of the DMA Mode Control register
249: */
250: void FDC_ResetDMAStatus(void)
251: {
252: DMAStatus_ff8606rd = 0; /* Clear out */
253:
254: FDCSectorCountRegister = 0;
255: FDC_SetDMAStatus(FALSE); /* Set no error */
256: }
257:
258: //-----------------------------------------------------------------------
259: /*
260: Set DMA Status (RD 0xff8606)
261:
262: NOTE FDC Doc's are incorrect - Bit 0 is '0' on error (See TOS floprd, Ninja III etc...)
263: Look like Atari(yet again) connected the hardware up differently to the spec'
264:
265: Bit 0 - _Error Status (0=Error)
266: Bit 1 - _Sector Count Zero Status (0=Sector Count Zero)
267: Bit 2 - _Data Request Inactive Status
268: */
269: void FDC_SetDMAStatus(BOOL bError)
270: {
271: DMAStatus_ff8606rd &= 0x1; /* Clear(except for error) */
272:
273: // Set error condition - NOTE this is incorrect in the FDC Doc's!
274: if (!bError)
275: DMAStatus_ff8606rd |= 0x1;
276:
277: // Set zero sector count
278: if (FDCSectorCountRegister!=0)
279: DMAStatus_ff8606rd |= 0x2;
280: }
281:
282: //-----------------------------------------------------------------------
283: /*
284: Read DMA Status (RD 0xff8606)
285: */
286: long FDC_ReadDMAStatus(void)
287: {
288: return (0xffff0000|DMAStatus_ff8606rd);
289: }
290:
291: //-----------------------------------------------------------------------
292: /*
293: */
294: void FDC_UpdateDiscDrive(void)
295: {
296: /* Set details for current selecte drive */
297: nReadWriteDev = FDC_FindFloppyDrive();
298:
299: if (EmulationDrives[nReadWriteDev].bDiscInserted)
300: Floppy_FindDiscDetails(EmulationDrives[nReadWriteDev].pBuffer,EmulationDrives[nReadWriteDev].nImageBytes,&nReadWriteSectorsPerTrack,NULL);
301: }
302:
303: //-----------------------------------------------------------------------
304: /*
305: When write to 0xff8606 (DMA Mode Control) check bit '8' toggle. This causes DMA status reset
306: */
307: void FDC_CheckForDMAStatusReset(void)
308: {
309: /* Test for 'toggle' of _read/_write bit '8' */
310: if ((DMAModeControl_ff8606wr_prev ^ DMAModeControl_ff8606wr)&0x0100)
311: FDC_ResetDMAStatus();
312: }
313:
314: //-----------------------------------------------------------------------
315: /*
316: Set disc controller status (RD 0xff8604)
317: */
318: void FDC_SetDiscControllerStatus(void)
319: {
320: /* Update disc */
321: FDC_UpdateDiscDrive();
322:
323: /* Clear out to default */
324: DiscControllerStatus_ff8604rd = 0;
325:
326: /* ONLY do this if we are running a Type I command */
327: if ((FDCCommandRegister&0x80)==0) { /* Type I - Restore,Seek,Step,Step-In,Step-Out */
328: if (FDCTrackRegister==0)
329: DiscControllerStatus_ff8604rd |= 0x4; /* Bit 2 - Track Zero, '0' if head is NOT at zero */
330: }
331:
332: /* If no disc inserted, tag as error */
333: if (!EmulationDrives[nReadWriteDev].bDiscInserted)
334: DiscControllerStatus_ff8604rd |= 0x10; /* RNF - Record not found, ie no disc in drive */
335: }
336:
337: //-----------------------------------------------------------------------
338: /*
339: Return device for FDC, check PORTA bits 1,2(0=on,1=off)
340: */
341: int FDC_FindFloppyDrive(void)
342: {
343: /* Check Drive A first */
344: if ((PSGRegisters[PSG_REG_IO_PORTA]&0x2)==0)
345: return(0); // Device 0 (A:)
346: /* If off, check Drive B */
347: if ((PSGRegisters[PSG_REG_IO_PORTA]&0x4)==0)
348: return(1); // Device 1 (B:)
349:
350: /* None appear to be selected so default to Drive A */
351: return(0); // Device 0 (A:)
352: }
353:
354: //-----------------------------------------------------------------------
355: /*
356: Acknowledge FDC interrupt
357: */
358: void FDC_AcknowledgeInterrupt(void)
359: {
360: // Acknowledge in MFP circuit, pass bit,enable,pending
361: MFP_InputOnChannel(MFP_FDCHDC_BIT,MFP_IERB,&MFP_IPRB);
362: MFP_GPIP &= ~0x20;
363: }
364:
365: //-----------------------------------------------------------------------
366: /*
367: Copy parameters for disc sector/s read/write
368: */
369: void FDC_SetReadWriteParameters(int nSectors)
370: {
371: // Copy read/write details so we can modify them
372: nReadWriteTrack = FDCTrackRegister;
373: nReadWriteSector = FDCSectorRegister;
374: nReadWriteSide = (~PSGRegisters[PSG_REG_IO_PORTA]) & 0x01;
375: nReadWriteSectors = nSectors;
376: // Update disc
377: FDC_UpdateDiscDrive();
378: }
379:
380: //-----------------------------------------------------------------------
381: /*
382: Update floppy drive on each HBL(approx' 512 cycles)
383: */
384: void FDC_UpdateHBL(void)
385: {
386: // Do we have a DMA ready to copy?
387: if (bDMAWaiting) {
388: // Yes, copy it
389: FDC_DMADataFromFloppy();
390: // Signal done
391: bDMAWaiting = FALSE;
392: }
393:
394: // Update drive motor
395: FDC_UpdateMotor();
396:
397: // Is FDC active?
398: if (FDCEmulationCommand!=FDCEMU_CMD_NULL) {
399: // Which command are we running?
400: switch(FDCEmulationCommand) {
401: case FDCEMU_CMD_RESTORE:
402: FDC_UpdateRestoreCmd();
403: break;
404: case FDCEMU_CMD_SEEK:
405: FDC_UpdateSeekCmd();
406: break;
407: case FDCEMU_CMD_STEP:
408: FDC_UpdateStepCmd();
409: break;
410: case FDCEMU_CMD_STEPIN:
411: FDC_UpdateStepInCmd();
412: break;
413: case FDCEMU_CMD_STEPOUT:
414: FDC_UpdateStepOutCmd();
415: break;
416:
417: case FDCEMU_CMD_READSECTORS:
418: case FDCEMU_CMD_READMULTIPLESECTORS:
419: FDC_UpdateReadSectorsCmd();
420: break;
421: case FDCEMU_CMD_WRITESECTORS:
422: case FDCEMU_CMD_WRITEMULTIPLESECTORS:
423: FDC_UpdateWriteSectorsCmd();
424: break;
425: }
426:
427: // Set disc controller status(RD 0xff8604)
428: FDC_SetDiscControllerStatus();
429: }
430: }
431:
432: //-----------------------------------------------------------------------
433: /*
434: Run 'RESTORE' command
435: */
436: void FDC_UpdateRestoreCmd(void)
437: {
438: // Which command is running?
439: switch (FDCEmulationRunning) {
440: case FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO:
441: // Are we at track zero?
442: if (FDCTrackRegister>0)
443: FDCTrackRegister--; /* Move towards track zero */
444: else {
445: FDCTrackRegister = 0; /* We're there */
446: FDCEmulationRunning = FDCEMU_RUN_RESTORE_COMPLETE;
447: }
448: break;
449: case FDCEMU_RUN_RESTORE_COMPLETE:
450: // Acknowledge interrupt, move along there's nothing more to see
451: FDC_AcknowledgeInterrupt();
452: // Set error
453: FDC_SetDMAStatus(FALSE); /* No DMA error */
454: // Done
455: FDCEmulationCommand = FDCEMU_CMD_NULL;
456: // Turn motor off
457: FDC_TurnMotorOff();
458: break;
459: }
460: }
461:
462: //-----------------------------------------------------------------------
463: /*
464: Run 'SEEK' command
465: */
466: void FDC_UpdateSeekCmd(void)
467: {
468: // Which command is running?
469: switch (FDCEmulationRunning) {
470: case FDCEMU_RUN_SEEK_TOTRACK:
471: // Are we at the selected track?
472: if (FDCTrackRegister==FDCDataRegister)
473: FDCEmulationRunning = FDCEMU_RUN_SEEK_COMPLETE;
474: else {
475: // No, seek towards track
476: if (FDCDataRegister<FDCTrackRegister)
477: FDCTrackRegister--;
478: else
479: FDCTrackRegister++;
480: }
481: break;
482: case FDCEMU_RUN_SEEK_COMPLETE:
483: // Acknowledge interrupt, move along there's nothing more to see
484: FDC_AcknowledgeInterrupt();
485: // Set error
486: FDC_SetDMAStatus(FALSE); // No DMA error
487: // Done
488: FDCEmulationCommand = FDCEMU_CMD_NULL;
489: // Turn motor off
490: FDC_TurnMotorOff();
491: break;
492: }
493: }
494:
495: //-----------------------------------------------------------------------
496: /*
497: Run 'STEP' command
498: */
499: void FDC_UpdateStepCmd(void)
500: {
501: // Which command is running?
502: switch (FDCEmulationRunning) {
503: case FDCEMU_RUN_STEP_ONCE:
504: // Move head by one track in same direction as last step
505: FDCTrackRegister += FDCStepDirection;
506: if (FDCTrackRegister<0) /* Limit to stop */
507: FDCTrackRegister = 0;
508:
509: FDCEmulationRunning = FDCEMU_RUN_STEP_COMPLETE;
510: break;
511: case FDCEMU_RUN_STEP_COMPLETE:
512: // Acknowledge interrupt, move along there's nothing more to see
513: FDC_AcknowledgeInterrupt();
514: // Set error
515: FDC_SetDMAStatus(FALSE); /* No DMA error */
516: // Done
517: FDCEmulationCommand = FDCEMU_CMD_NULL;
518: // Turn motor off
519: FDC_TurnMotorOff();
520: break;
521: }
522: }
523:
524: //-----------------------------------------------------------------------
525: /*
526: Run 'STEP IN' command
527: */
528: void FDC_UpdateStepInCmd(void)
529: {
530: // Which command is running?
531: switch (FDCEmulationRunning) {
532: case FDCEMU_RUN_STEPIN_ONCE:
533: FDCTrackRegister++;
534:
535: FDCEmulationRunning = FDCEMU_RUN_STEPIN_COMPLETE;
536: break;
537: case FDCEMU_RUN_STEPIN_COMPLETE:
538: // Acknowledge interrupt, move along there's nothing more to see
539: FDC_AcknowledgeInterrupt();
540: // Set error
541: FDC_SetDMAStatus(FALSE); /* No DMA error */
542: // Done
543: FDCEmulationCommand = FDCEMU_CMD_NULL;
544: // Turn motor off
545: FDC_TurnMotorOff();
546: break;
547: }
548: }
549:
550: //-----------------------------------------------------------------------
551: /*
552: Run 'STEP OUT' command
553: */
554: void FDC_UpdateStepOutCmd(void)
555: {
556: // Which command is running?
557: switch (FDCEmulationRunning) {
558: case FDCEMU_RUN_STEPOUT_ONCE:
559: FDCTrackRegister--;
560: if (FDCTrackRegister<0) // Limit to stop
561: FDCTrackRegister = 0;
562:
563: FDCEmulationRunning = FDCEMU_RUN_STEPOUT_COMPLETE;
564: break;
565: case FDCEMU_RUN_STEPOUT_COMPLETE:
566: // Acknowledge interrupt, move along there's nothing more to see
567: FDC_AcknowledgeInterrupt();
568: // Set error
569: FDC_SetDMAStatus(FALSE); // No DMA error
570: // Done
571: FDCEmulationCommand = FDCEMU_CMD_NULL;
572: // Turn motor off
573: FDC_TurnMotorOff();
574: break;
575: }
576: }
577:
578: //-----------------------------------------------------------------------
579: /*
580: Run 'READ SECTOR/S' command
581: */
582: void FDC_UpdateReadSectorsCmd(void)
583: {
584: // Which command is running?
585: switch (FDCEmulationRunning) {
586: case FDCEMU_RUN_READSECTORS_READDATA:
587: // Read in a sector
588: if (FDC_ReadSectorFromFloppy()) { /* Read a single sector through DMA */
589: FDCSectorCountRegister--; /* Decrement FDCSectorCount */
590: if (FDCSectorCountRegister<=0)
591: FDCSectorCountRegister = 0;
592:
593: // Have we finished?
594: nReadWriteSectors--;
595: if (nReadWriteSectors<=0)
596: FDCEmulationRunning = FDCEMU_RUN_READSECTORS_COMPLETE;
597:
598: bDMAWaiting = TRUE;
599: }
600: else {
601: // Acknowledge interrupt, move along there's nothing more to see
602: FDC_AcknowledgeInterrupt();
603: // Set error
604: FDC_SetDMAStatus(TRUE); /* DMA error */
605: // Done
606: FDCEmulationCommand = FDCEMU_CMD_NULL;
607: // Turn motor off
608: FDC_TurnMotorOff();
609: }
610: break;
611: case FDCEMU_RUN_READSECTORS_COMPLETE:
612: // Acknowledge interrupt, move along there's nothing more to see
613: FDC_AcknowledgeInterrupt();
614: // Set error
615: FDC_SetDMAStatus(FALSE); /* No DMA error */
616: // Done
617: FDCEmulationCommand = FDCEMU_CMD_NULL;
618: // Turn motor off
619: FDC_TurnMotorOff();
620: break;
621: }
622: }
623:
624: //-----------------------------------------------------------------------
625: /*
626: Run 'WRITE SECTOR/S' command
627: */
628: void FDC_UpdateWriteSectorsCmd(void)
629: {
630: // Which command is running?
631: switch (FDCEmulationRunning) {
632: case FDCEMU_RUN_WRITESECTORS_WRITEDATA:
633: // Write out a sector
634: if (FDC_WriteSectorFromFloppy()) { /* Write a single sector through DMA */
635: // Decrement FDCsector count
636: FDCSectorCountRegister--; /* Decrement FDCSectorCount */
637: if (FDCSectorCountRegister<=0)
638: FDCSectorCountRegister = 0;
639:
640: // Have we finished?
641: nReadWriteSectors--;
642: if (nReadWriteSectors<=0)
643: FDCEmulationRunning = FDCEMU_RUN_WRITESECTORS_COMPLETE;
644:
645: // Update DMA pointer
646: FDC_WriteDMAAddress(FDC_ReadDMAAddress()+NUMBYTESPERSECTOR);
647: }
648: else {
649: // Acknowledge interrupt, move along there's nothing more to see
650: FDC_AcknowledgeInterrupt();
651: // Set error
652: FDC_SetDMAStatus(TRUE); /* DMA error */
653: // Done
654: FDCEmulationCommand = FDCEMU_CMD_NULL;
655: // Turn motor off
656: FDC_TurnMotorOff();
657: }
658: break;
659: case FDCEMU_RUN_WRITESECTORS_COMPLETE:
660: // Acknowledge interrupt, move along there's nothing more to see
661: FDC_AcknowledgeInterrupt();
662: // Set error
663: FDC_SetDMAStatus(FALSE); /* No DMA error */
664: // Done
665: FDCEmulationCommand = FDCEMU_CMD_NULL;
666: // Turn motor off
667: FDC_TurnMotorOff();
668: break;
669: }
670: }
671:
672: //-----------------------------------------------------------------------
673: /*
674: Type I Commands
675:
676: Restore, Seek, Step, Step-In and Step-Out
677: */
678:
679: //-----------------------------------------------------------------------
680: void FDC_TypeI_Restore(void)
681: {
682: // Set emulation to seek to track zero
683: FDCEmulationCommand = FDCEMU_CMD_RESTORE;
684: FDCEmulationRunning = FDCEMU_RUN_RESTORE_SEEKTOTRACKZERO;
685:
686: FDC_SetDiscControllerStatus();
687: }
688:
689: //-----------------------------------------------------------------------
690: void FDC_TypeI_Seek(void)
691: {
692: // Set emulation to seek to chosen track
693: FDCEmulationCommand = FDCEMU_CMD_SEEK;
694: FDCEmulationRunning = FDCEMU_RUN_SEEK_TOTRACK;
695:
696: FDC_SetDiscControllerStatus();
697: }
698:
699: //-----------------------------------------------------------------------
700: void FDC_TypeI_Step(void)
701: {
702: // Set emulation to step(same direction as last seek executed, eg 'FDCStepDirection')
703: FDCEmulationCommand = FDCEMU_CMD_STEP;
704: FDCEmulationRunning = FDCEMU_RUN_STEP_ONCE;
705:
706: FDC_SetDiscControllerStatus();
707: }
708:
709: //-----------------------------------------------------------------------
710: void FDC_TypeI_StepIn(void)
711: {
712: // Set emulation to step in(Set 'FDCStepDirection')
713: FDCEmulationCommand = FDCEMU_CMD_STEPIN;
714: FDCEmulationRunning = FDCEMU_RUN_STEPIN_ONCE;
715: FDCStepDirection = 1; // Increment track
716:
717: FDC_SetDiscControllerStatus();
718: }
719:
720: //-----------------------------------------------------------------------
721: void FDC_TypeI_StepOut(void)
722: {
723: // Set emulation to step out(Set 'FDCStepDirection')
724: FDCEmulationCommand = FDCEMU_CMD_STEPOUT;
725: FDCEmulationRunning = FDCEMU_RUN_STEPOUT_ONCE;
726: FDCStepDirection = -1; // Decrement track
727:
728: FDC_SetDiscControllerStatus();
729: }
730:
731: //-----------------------------------------------------------------------
732: /*
733: Type II Commands
734:
735: Read Sector, Read Multiple Sectors, Write Sector, Write Multiple Sectors
736: */
737:
738: //-----------------------------------------------------------------------
739: void FDC_TypeII_ReadSector(void)
740: {
741: // Set emulation to read a single sector
742: FDCEmulationCommand = FDCEMU_CMD_READSECTORS;
743: FDCEmulationRunning = FDCEMU_RUN_READSECTORS_READDATA;
744: // Set reading parameters
745: FDC_SetReadWriteParameters(1); // Read in a single sector
746:
747: FDC_SetDiscControllerStatus();
748: }
749:
750: //-----------------------------------------------------------------------
751: void FDC_TypeII_ReadMultipleSectors(void)
752: {
753: // Set emulation to read sectors
754: FDCEmulationCommand = FDCEMU_CMD_READMULTIPLESECTORS;
755: FDCEmulationRunning = FDCEMU_RUN_READSECTORS_READDATA;
756: // Set reading parameters
757: FDC_SetReadWriteParameters(FDCSectorCountRegister); // Read multiple sectors
758:
759: FDC_SetDiscControllerStatus();
760: }
761:
762: //-----------------------------------------------------------------------
763: void FDC_TypeII_WriteSector(void)
764: {
765: // Set emulation to write a single sector
766: FDCEmulationCommand = FDCEMU_CMD_WRITESECTORS;
767: FDCEmulationRunning = FDCEMU_RUN_WRITESECTORS_WRITEDATA;
768: // Set writing parameters
769: FDC_SetReadWriteParameters(1); // Write out a single sector
770:
771: FDC_SetDiscControllerStatus();
772: }
773:
774: //-----------------------------------------------------------------------
775: void FDC_TypeII_WriteMultipleSectors(void)
776: {
777: // Set emulation to write sectors
778: FDCEmulationCommand = FDCEMU_CMD_WRITEMULTIPLESECTORS;
779: FDCEmulationRunning = FDCEMU_RUN_WRITESECTORS_WRITEDATA;
780: // Set witing parameters
781: FDC_SetReadWriteParameters(FDCSectorCountRegister); // Write multiple sectors
782:
783: FDC_SetDiscControllerStatus();
784: }
785:
786: //-----------------------------------------------------------------------
787: /*
788: Type III Commands
789:
790: Read Address, Read Track, Write Track
791: */
792:
793: //-----------------------------------------------------------------------
794: void FDC_TypeIII_ReadAddress(void)
795: {
796: }
797:
798: //-----------------------------------------------------------------------
799: void FDC_TypeIII_ReadTrack(void)
800: {
801: // Set emulation to read a single track
802: FDCEmulationCommand = FDCEMU_CMD_READSECTORS;
803: FDCEmulationRunning = FDCEMU_RUN_READSECTORS_READDATA;
804: // Set reading parameters
805: FDC_SetReadWriteParameters(nReadWriteSectorsPerTrack); // Read whole track
806:
807: FDC_SetDiscControllerStatus();
808: }
809:
810: //-----------------------------------------------------------------------
811: void FDC_TypeIII_WriteTrack(void)
812: {
813: // Set emulation to write a single track
814: FDCEmulationCommand = FDCEMU_CMD_WRITESECTORS;
815: FDCEmulationRunning = FDCEMU_RUN_WRITESECTORS_WRITEDATA;
816: // Set writing parameters
817: FDC_SetReadWriteParameters(nReadWriteSectorsPerTrack); // Write whole track
818:
819: FDC_SetDiscControllerStatus();
820: }
821:
822: //-----------------------------------------------------------------------
823: /*
824: Type IV Commands
825:
826: Force Interrupt
827: */
828:
829: //-----------------------------------------------------------------------
830: void FDC_TypeIV_ForceInterrupt(BOOL bCauseCPUInterrupt)
831: {
832: // Acknowledge interrupt, move along there's nothing more to see
833: if (bCauseCPUInterrupt)
834: FDC_AcknowledgeInterrupt();
835:
836: // Reset FDC
837: FDCEmulationCommand = FDCEMU_CMD_NULL;
838: FDCEmulationRunning = FDCEMU_RUN_NULL;
839: }
840:
841: //-----------------------------------------------------------------------
842: /*
843: Execute Type I commands
844: */
845: void FDC_ExecuteTypeICommands(void)
846: {
847: MFP_GPIP |= 0x20;
848:
849: // Check Type I Command
850: switch(FDCCommandRegister&0xf0) {
851: case 0x00: // Restore
852: FDC_TypeI_Restore();
853: break;
854: case 0x10: // Seek
855: FDC_TypeI_Seek();
856: break;
857: case 0x20: // Step
858: case 0x30:
859: FDC_TypeI_Step();
860: break;
861: case 0x40: // Step-In
862: case 0x50:
863: FDC_TypeI_StepIn();
864: break;
865: case 0x60: // Step-Out
866: case 0x70:
867: FDC_TypeI_StepOut();
868: break;
869: }
870:
871: // Signal motor on as we need to execute command
872: FDC_TurnMotorOn();
873: }
874:
875: //-----------------------------------------------------------------------
876: /*
877: Execute Type II commands
878: */
879: void FDC_ExecuteTypeIICommands(void)
880: {
881: MFP_GPIP |= 0x20;
882:
883: // Check Type II Command
884: switch(FDCCommandRegister&0xf0) {
885: case 0x80: // Read Sector
886: FDC_TypeII_ReadSector();
887: break;
888: case 0x90: // Read Sectors
889: FDC_TypeII_ReadMultipleSectors();
890: break;
891: case 0xa0: // Write Sector
892: FDC_TypeII_WriteSector();
893: break;
894: case 0xb0: // Write Sectors
895: FDC_TypeII_WriteMultipleSectors();
896: break;
897: }
898:
899: // Signal motor on as we need to execute command
900: FDC_TurnMotorOn();
901: }
902:
903: //-----------------------------------------------------------------------
904: /*
905: Execute Type III commands
906: */
907: void FDC_ExecuteTypeIIICommands(void)
908: {
909: MFP_GPIP |= 0x20;
910:
911: // Check Type III Command
912: switch(FDCCommandRegister&0xf0) {
913: case 0xc0: // Read Address
914: FDC_TypeIII_ReadAddress();
915: break;
916: case 0xe0: // Read Track
917: FDC_TypeIII_ReadTrack();
918: break;
919: case 0xf0: // Write Track
920: FDC_TypeIII_WriteTrack();
921: break;
922: }
923:
924: // Signal motor on as we need to execute command
925: FDC_TurnMotorOn();
926: }
927:
928: //-----------------------------------------------------------------------
929: /*
930: Execute Type IV commands
931: */
932: void FDC_ExecuteTypeIVCommands(void)
933: {
934: if (FDCCommandRegister!=0xD8) /* Is an 'immediate interrupt command'? don't reset interrupt */
935: MFP_GPIP |= 0x20;
936:
937: // Check Type IV Command
938: if ((FDCCommandRegister&0x0c)==0) /* I3 and I2 are clear? If so we don't need a CPU interrupt */
939: FDC_TypeIV_ForceInterrupt(FALSE); /* Force Interrupt - no interrupt */
940: else
941: FDC_TypeIV_ForceInterrupt(TRUE); /* Force Interrupt */
942: }
943:
944: //-----------------------------------------------------------------------
945: /*
946: Find FDC command type and execute
947: */
948: void FDC_ExecuteCommand(void)
949: {
950: /* Check type of command and execute */
951: if ((FDCCommandRegister&0x80)==0) /* Type I - Restore,Seek,Step,Step-In,Step-Out */
952: FDC_ExecuteTypeICommands();
953: else if ((FDCCommandRegister&0x40)==0) /* Type II - Read Sector, Write Sector */
954: FDC_ExecuteTypeIICommands();
955: else if ((FDCCommandRegister&0xf0)!=0xd0) /* Type III - Read Address, Read Track, Write Track */
956: FDC_ExecuteTypeIIICommands();
957: else // Type IV - Force Interrupt
958: FDC_ExecuteTypeIVCommands();
959: }
960:
961: //-----------------------------------------------------------------------
962: /*
963: Write to SectorCount register (WR 0xff8604)
964: */
965: void FDC_WriteSectorCountRegister(void)
966: {
967: FDCSectorCountRegister = DiscControllerWord_ff8604wr;
968: }
969:
970: //-----------------------------------------------------------------------
971: /*
972: Write to Command register (WR 0xff8604)
973: */
974: void FDC_WriteCommandRegister(void)
975: {
976: FDCCommandRegister = DiscControllerWord_ff8604wr;
977: /* And execute */
978: FDC_ExecuteCommand();
979: }
980:
981: //-----------------------------------------------------------------------
982: /*
983: Write to Track register (WR 0xff8604)
984: */
985: void FDC_WriteTrackRegister(void)
986: {
987: FDCTrackRegister = DiscControllerWord_ff8604wr; /* 0...79 */
988: }
989:
990: //-----------------------------------------------------------------------
991: /*
992: Write to Track register (WR 0xff8604)
993: */
994: void FDC_WriteSectorRegister(void)
995: {
996: FDCSectorRegister = DiscControllerWord_ff8604wr; /* 1,2,3..... */
997: }
998:
999: //-----------------------------------------------------------------------
1000: /*
1001: Write to Data register (WR 0xff8604)
1002: */
1003: void FDC_WriteDataRegister(void)
1004: {
1005: FDCDataRegister = DiscControllerWord_ff8604wr;
1006: }
1007:
1008: //-----------------------------------------------------------------------
1009: /*
1010: Store byte in FDC registers, when write to 0xff8604
1011: */
1012: void FDC_WriteDiscControllerByte(void)
1013: {
1014: // Are we trying to set the SectorCount?
1015: if (DMAModeControl_ff8606wr&0x10) /* Bit 4 */
1016: FDC_WriteSectorCountRegister();
1017: else { // Write to FDC registers
1018: switch(DMAModeControl_ff8606wr&0x6) { /* Bits 1,2 (A1,A0) */
1019: case 0x0: /* 0 0 - Command register */
1020: FDC_WriteCommandRegister();
1021: break;
1022: case 0x2: /* 0 1 - Track register */
1023: FDC_WriteTrackRegister();
1024: break;
1025: case 0x4: /* 1 0 - Sector register */
1026: FDC_WriteSectorRegister();
1027: break;
1028: case 0x6: /* 1 1 - Data register */
1029: FDC_WriteDataRegister();
1030: break;
1031: }
1032: }
1033: }
1034:
1035: //-----------------------------------------------------------------------
1036: /*
1037: Read Status/FDC registers, when read from 0xff8604
1038: Return 'DiscControllerByte'
1039: */
1040: void FDC_ReadDiscControllerStatusByte(void)
1041: {
1042: switch(DMAModeControl_ff8606wr&0x6) { /* Bits 1,2 (A1,A0) */
1043: case 0x0: /* 0 0 - Status register */
1044: DiscControllerByte = DiscControllerStatus_ff8604rd;
1045: if (bMotorOn)
1046: DiscControllerByte |= 0x80;
1047:
1048: /* Reset FDC GPIP */
1049: MFP_GPIP |= 0x20;
1050: break;
1051: case 0x2: /* 0 1 - Track register */
1052: DiscControllerByte = FDCTrackRegister;
1053: break;
1054: case 0x4: /* 1 0 - Sector register */
1055: DiscControllerByte = FDCSectorRegister;
1056: break;
1057: case 0x6: /* 1 1 - Data register */
1058: DiscControllerByte = FDCDataRegister;
1059: break;
1060: }
1061: }
1062:
1063: //-----------------------------------------------------------------------
1064: /*
1065: Read DMA address from ST's RAM(always up-to-date)
1066: */
1067: unsigned long FDC_ReadDMAAddress(void)
1068: {
1069: unsigned long Address;
1070:
1071: /* Build up 24-bit address from hardware registers */
1072: Address = ((unsigned long)STMemory_ReadByte(0xff8609)<<16) | ((unsigned long)STMemory_ReadByte(0xff860b)<<8) | (unsigned long)STMemory_ReadByte(0xff860d);
1073:
1074: return(Address);
1075: }
1076:
1077: //-----------------------------------------------------------------------
1078: /*
1079: Write DMA address to ST's RAM(always keep up-to-date)
1080: */
1081: void FDC_WriteDMAAddress(unsigned long Address)
1082: {
1083: /* Store as 24-bit address */
1084: STMemory_WriteByte(0xff8609,Address>>16);
1085: STMemory_WriteByte(0xff860b,Address>>8);
1086: STMemory_WriteByte(0xff860d,Address);
1087: }
1088:
1089: //-----------------------------------------------------------------------
1090: /*
1091: Read sector from floppy drive into workspace
1092: We copy the bytes in chunks to simulate reading of the floppy using DMA
1093: */
1094: BOOL FDC_ReadSectorFromFloppy(void)
1095: {
1096: // Copy in 1 sector to our workspace
1097: if (Floppy_ReadSectors(nReadWriteDev,(char *)DMASectorWorkSpace,nReadWriteSector,nReadWriteTrack,nReadWriteSide,1,NULL)) {
1098: // Update reading/writing parameters
1099: nReadWriteSector++;
1100: if (nReadWriteSector>nReadWriteSectorsPerTrack) { // Advance into next track?
1101: nReadWriteSector = 1;
1102: nReadWriteTrack++;
1103: }
1104: return(TRUE);
1105: }
1106:
1107: // Failed
1108: return(FALSE);
1109: }
1110:
1111: //-----------------------------------------------------------------------
1112: /*
1113: Write sector from workspace to floppy drive
1114: We copy the bytes in chunks to simulate writing of the floppy using DMA
1115: */
1116: BOOL FDC_WriteSectorFromFloppy(void)
1117: {
1118: unsigned long Address;
1119:
1120: // Get DMA address
1121: Address = FDC_ReadDMAAddress();
1122:
1123: // Write out 1 sector from our workspace
1124: if (Floppy_WriteSectors(nReadWriteDev,(char *)((unsigned long)STRam+Address),nReadWriteSector,nReadWriteTrack,nReadWriteSide,1,NULL)) {
1125: // Update reading/writing parameters
1126: nReadWriteSector++;
1127: if (nReadWriteSector>nReadWriteSectorsPerTrack) { // Advance to next track?
1128: nReadWriteSector = 1;
1129: nReadWriteTrack++;
1130: }
1131: return(TRUE);
1132: }
1133:
1134: // Failed
1135: return(FALSE);
1136: }
1137:
1138:
1139: //-----------------------------------------------------------------------
1140: /*
1141: Copy data from DMA workspace into ST RAM
1142: */
1143: void FDC_DMADataFromFloppy(void)
1144: {
1145: // Copy data to DMA address
1146: memcpy( (char *)((unsigned long)STRam+FDC_ReadDMAAddress()), DMASectorWorkSpace, NUMBYTESPERSECTOR );
1147:
1148: // Update DMA pointer
1149: FDC_WriteDMAAddress(FDC_ReadDMAAddress()+NUMBYTESPERSECTOR);
1150: }
1151:
1152:
1153: //-----------------------------------------------------------------------
1154: /*
1155: Write byte to 0xff8604
1156: */
1157: void FDC_WriteDiscController(unsigned short v)
1158: {
1159: DiscControllerWord_ff8604wr = v;
1160: FDC_WriteDiscControllerByte();
1161: }
1162:
1163:
1164: //-----------------------------------------------------------------------
1165: /*
1166: Read word from 0xff8604
1167: */
1168: short FDC_ReadDiscControllerStatus(void)
1169: {
1170: FDC_ReadDiscControllerStatusByte(); /* Read Status/Track/Sector/Data according to 'DiscControllerWord_ff8604wr' */
1171: return DiscControllerByte;
1172: }
1173:
1174:
1175: //-----------------------------------------------------------------------
1176: /*
1177: Write word to 0xff8606 (DMA Mode Control)
1178:
1179: Eg.
1180: $80 - Selects command/status register
1181: $82 - Selects track register
1182: $84 - Selects sector register
1183: $86 - Selects data regsiter
1184: NOTE - OR above values with $100 is transfer from memory to floppy
1185: Also if bit 4 is set, write to sector count register
1186: */
1187: void FDC_WriteDMAModeControl(unsigned short v)
1188: {
1189: DMAModeControl_ff8606wr_prev = DMAModeControl_ff8606wr; /* Store previous to check for _read/_write toggle(DMA reset) */
1190: DMAModeControl_ff8606wr = v; /* Store to DMA Mode control */
1191: FDC_CheckForDMAStatusReset();
1192: }
1193:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.