2 * WD1793/uPD765 emulator
3 * Copyright (c) 2009-..., SAM style
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is furnished
10 * to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
17 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
20 * THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * changes by Ketmar // Invisible Vector
24 * Understanding is not required. Only obedience.
25 * git commit: 84b4cb3f749ff3cb954a202b3c65d7b53ee08273
30 // ////////////////////////////////////////////////////////////////////////// //
35 // currently, only bit 0 has a meaning
36 // bit0: set to turn on "turbo mode" (see `FDC_FAST` constant)
37 // WARNING! don't modify this directly, use `difSetTurbo()`
38 // this is because the code has to do some housekeeping
43 //==========================================================================
49 //==========================================================================
50 static void fdcUpdateCRC16 (FDC
*fdc
, uint8_t val
) {
51 uint32_t tkk
= fdc
->crc
;
53 for (unsigned i
= 8; i
--; ) {
54 if ((tkk
*= 2)&0x10000) tkk
^= 0x1021;
56 fdc
->crc
= tkk
&0xffff;
60 // ////////////////////////////////////////////////////////////////////////// //
61 #define LIBFDC_FDC_EMU_API static
63 /* flag for fdcFlag: "turbo mode" */
64 #define FDC_IS_TURBO_MODE (fdc->optionTurbo)
67 #include "emu_upd765.c"
70 // ////////////////////////////////////////////////////////////////////////// //
72 const int id
; /* hardware type */
73 void (*reset
) (DiskIF
*dif
);
74 int (*in
) (DiskIF
*dif
, int port
);
75 int (*out
) (DiskIF
*dif
, int port
, int val
);
76 void (*sync
) (DiskIF
*dif
, int ns
);
80 //**************************************************************************
84 //**************************************************************************
85 static void dumReset (DiskIF
* dif
) {}
86 static int dumIn (DiskIF
*dif
, int port
) { return -1; }
87 static int dumOut (DiskIF
*dif
, int port
, int val
) { return -1; }
88 static void dumSync (DiskIF
*dif
, int ns
) {}
92 //**************************************************************************
96 //**************************************************************************
98 //==========================================================================
102 //==========================================================================
103 static void fdcSync (FDC
*fdc
, int ns
) {
104 if (fdc
->plan
== NULL
) return; // fdc does nothing
105 //fprintf(stderr, "fdcSync:000: wait=%d; tns=%d; ns=%d; plan=%p\n", fdc->wait, fdc->tns, ns, fdc->plan);
108 //fprintf(stderr, "fdcSync:001: wait=%d; tns=%d; ns=%d; plan=%p\n", fdc->wait, fdc->tns, ns, fdc->plan);
109 while (fdc
->wait
< 0 && fdc
->plan
!= NULL
) {
110 //fprintf(stderr, " fdcSync:002: wait=%d; tns=%d; ns=%d; plan=%p\n", fdc->wait, fdc->tns, ns, fdc->plan);
111 if (fdc
->plan
[fdc
->pos
] != NULL
) {
112 fdc
->plan
[fdc
->pos
](fdc
);
120 //==========================================================================
124 //==========================================================================
125 static void dhwSync (DiskIF
*dif
, int ns
) {
126 fdcSync(dif
->fdc
, ns
);
131 //**************************************************************************
135 //**************************************************************************
137 //==========================================================================
141 //==========================================================================
142 static int bdiGetPort (int port
) {
144 if ((port
&0x9f) == 0x9f) {
145 // 1xxxxx11 : bdi system port
148 // 0xxxxx11 : vg93 registers
150 case 0x1f: res
= FDC_COM
; break; // 000xxx11
151 case 0x3f: res
= FDC_TRK
; break; // 001xxx11
152 case 0x5f: res
= FDC_SEC
; break; // 010xxx11
153 case 0x7f: res
= FDC_DATA
; break; // 011xxx11
160 //==========================================================================
164 //==========================================================================
165 static int bdiIn (DiskIF
*dif
, int port
) {
166 //const int origport = port;
167 port
= bdiGetPort(port
);
168 if (port
== 0) return -1; /* not FDC */
170 if (port
== BDI_SYS
) {
171 res
= ((dif
->fdc
->irq
? 0x80 : 0x00)|(dif
->fdc
->drq
? 0x40 : 0x00))&0xff;
173 res
= vgRead(dif
->fdc
, port
)&0xff;
175 //fprintf(stderr, "in BDI port #%04X (%02X); res=#%02X\n", (unsigned)origport, (unsigned)bdiGetPort(port), res&0xffU);
180 //==========================================================================
184 //==========================================================================
185 static int bdiOut (DiskIF
*dif
, int port
, int val
) {
186 //fprintf(stderr, "out BDI port #%04X (%02X) <- #%02X\n", (unsigned)port, (unsigned)bdiGetPort(port), val&0xffU);
187 port
= bdiGetPort(port
);
188 if (port
== 0) return -1;
189 if (port
== BDI_SYS
) {
190 dif
->fdc
->sysreg
= val
&0xffU
;
191 dif
->fdc
->flp
= dif
->fdc
->flop
[val
&3]; // select floppy
192 vgSetMR(dif
->fdc
, (val
&0x04 ? 1 : 0)); // master reset
193 dif
->fdc
->block
= (val
&0x08 ? 1 : 0);
194 dif
->fdc
->side
= (val
&0x10 ? 0 : 1); // side
195 dif
->fdc
->mfm
= (val
&0x40 ? 1 : 0);
197 vgWrite(dif
->fdc
, port
, val
);
203 //==========================================================================
207 //==========================================================================
208 static void bdiReset (DiskIF
*dif
) {
210 dif
->fdc
->sysreg
= 0x20|0x08; // MFM
211 bdiOut(dif
, 0xff, 0x00);
215 //==========================================================================
219 //==========================================================================
221 static void bdiSync (DiskIF *dif, int ns) {
222 fdcSync(dif->fdc, ns);
228 //**************************************************************************
232 //**************************************************************************
234 //==========================================================================
238 //==========================================================================
239 static int pdosGetPort (int p
) {
241 if ((p
&0xf002) == 0x2000) port
= 0; // A0 input of upd765
242 if ((p
&0xf002) == 0x3000) port
= 1; // 0:status(r), 1:data(rw)
247 //==========================================================================
251 //==========================================================================
252 static int pdosIn (DiskIF
*dif
, int port
) {
253 port
= pdosGetPort(port
);
254 if (port
< 0) return -1;
255 //fprintf(stderr, "in %.4X\n",port);
256 return uRead(dif
->fdc
, port
)&0xff;
260 //==========================================================================
264 //==========================================================================
265 static int pdosOut (DiskIF
*dif
, int port
, int val
) {
266 port
= pdosGetPort(port
);
267 if (port
< 0) return -1;
268 uWrite(dif
->fdc
, port
, val
);
273 //==========================================================================
277 //==========================================================================
278 static void pdosReset (DiskIF
*dif
) {
284 //**************************************************************************
288 //**************************************************************************
289 static const DiskHW dhwTab
[4] = {
290 {DIF_NONE
, &dumReset
, &dumIn
, &dumOut
, &dumSync
},
291 {DIF_BDI
, &bdiReset
, &bdiIn
, &bdiOut
, &dhwSync
},
292 {DIF_P3DOS
, &pdosReset
, &pdosIn
, &pdosOut
, &dhwSync
},
293 {DIF_END
, NULL
, NULL
, NULL
, NULL
}
297 //==========================================================================
301 //==========================================================================
302 static const DiskHW
*findDHW (int id
) {
303 for (unsigned idx
= 0; dhwTab
[idx
].id
!= DIF_END
; ++idx
) {
304 if (dhwTab
[idx
].id
== id
) return &dhwTab
[idx
];
310 //==========================================================================
314 //==========================================================================
315 void difSetHW (DiskIF
*dif
, int type
) {
317 dif
->hw
= findDHW(type
);
319 //fprintf(stderr, "difSetHW: unknown interface type %d!\n", type);
320 dif
->hw
= findDHW(DIF_NONE
);
322 dif
->type
= dif
->hw
->id
;
326 //==========================================================================
330 //==========================================================================
331 int difGetHW (const DiskIF
*dif
) {
332 return (dif
? dif
->type
: DIF_NONE
);
336 //==========================================================================
340 //==========================================================================
341 FDC
*difGetFDC (DiskIF
*dif
) {
342 return (dif
? dif
->fdc
: NULL
);
346 //==========================================================================
350 //==========================================================================
351 Floppy
*difGetFloppy (DiskIF
*dif
, int driveidx
) {
352 if (!dif
|| !dif
->fdc
|| driveidx
< 0 || driveidx
> 3) return NULL
;
353 return dif
->fdc
->flop
[driveidx
];
357 //==========================================================================
361 //==========================================================================
362 Floppy
*difGetCurrentFloppy (DiskIF
*dif
) {
363 if (!dif
|| !dif
->fdc
) return NULL
;
364 return dif
->fdc
->flp
;
368 //==========================================================================
372 //==========================================================================
373 void difSetTurbo (DiskIF
*dif
, int v
) {
375 v
= (v
? FDC_FAST
: 0);
376 if ((dif
->flags
&FDC_FAST
) != v
) {
377 if (v
) dif
->flags
|= FDC_FAST
; else dif
->flags
&= ~((unsigned)FDC_FAST
);
378 if (dif
->fdc
) dif
->fdc
->optionTurbo
= (v
? 1 : 0);
383 //==========================================================================
387 //==========================================================================
388 int difGetTurbo (const DiskIF
*dif
) {
389 return (dif
&& (dif
->flags
&FDC_FAST
) ? 1 : 0);
393 //==========================================================================
397 //==========================================================================
398 DiskIF
*difCreate (int type
) {
399 DiskIF
*dif
= malloc(sizeof(DiskIF
));
400 memset(dif
, 0, sizeof(DiskIF
));
401 dif
->fdc
= malloc(sizeof(FDC
));
402 memset(dif
->fdc
, 0x00, sizeof(FDC
));
404 dif
->fdc
->plan
= NULL
;
405 dif
->fdc
->flop
[0] = flpCreate(0);
406 dif
->fdc
->flop
[1] = flpCreate(1);
407 dif
->fdc
->flop
[2] = flpCreate(2);
408 dif
->fdc
->flop
[3] = flpCreate(3);
409 dif
->fdc
->flp
= dif
->fdc
->flop
[0];
415 //==========================================================================
419 //==========================================================================
420 void difDestroy (DiskIF
*dif
) {
422 flpDestroy(dif
->fdc
->flop
[0]);
423 flpDestroy(dif
->fdc
->flop
[1]);
424 flpDestroy(dif
->fdc
->flop
[2]);
425 flpDestroy(dif
->fdc
->flop
[3]);
426 dif
->fdc
->flp
= NULL
;
432 //==========================================================================
436 //==========================================================================
437 void difReset (DiskIF
*dif
) {
443 //==========================================================================
445 // difCalcNSFromTStates
447 // tstates: tstates passed
448 // cpufreq: 3500000 for ZX Spectrum
450 //==========================================================================
451 int difCalcNSFromTStates (int tstates
, int cpufreq
) {
452 // 3500000 must be converted to 3.5
454 const double nspt
= ((double)tstates
*(double)1e3
)/((double)cpufreq
/(double)1e6
);
457 // sadly, this can overflow, so use 64-bit integers
458 return (int)((int64_t)tstates
*1000LL*1000000LL/(int64_t)cpufreq
);
463 //==========================================================================
467 // update disk interface (up to the given `ns`)
468 // call this in emulation loop
469 // `ns` is time passed from the last call (in nanoseconds)
470 // it can be calculated with `difCalcNSFromTStates()`
472 //==========================================================================
473 void difSync (DiskIF
*dif
, int ns
) {
474 if (!dif
|| ns
<= 0) return;
475 dif
->hw
->sync(dif
, ns
);
479 //==========================================================================
483 //==========================================================================
484 int difOut (DiskIF
*dif
, int port
, int val
) {
486 return dif
->hw
->out(dif
, port
, val
);
490 //==========================================================================
494 //==========================================================================
495 int difIn (DiskIF
*dif
, int port
) {
497 return dif
->hw
->in(dif
, port
);