ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/CPU1541.cpp
Revision: 1.4
Committed: 2005-06-27T19:55:48Z (17 years, 5 months ago) by cebix
Branch: MAIN
CVS Tags: VERSION_4_2, HEAD
Changes since 1.3: +1 -1 lines
Log Message:
updated copyright dates

File Contents

# Content
1 /*
2 * CPU1541.cpp - 6502 (1541) emulation (line based)
3 *
4 * Frodo (C) 1994-1997,2002-2005 Christian Bauer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 /*
22 * Notes:
23 * ------
24 *
25 * - The EmulateLine() function is called for every emulated
26 * raster line. It has a cycle counter that is decremented
27 * by every executed opcode and if the counter goes below
28 * zero, the function returns.
29 * - Memory map (1541C, the 1541 and 1541-II are a bit different):
30 * $0000-$07ff RAM (2K)
31 * $0800-$0fff RAM mirror
32 * $1000-$17ff free
33 * $1800-$1bff VIA 1
34 * $1c00-$1fff VIA 2
35 * $2000-$bfff free
36 * $c000-$ffff ROM (16K)
37 * - All memory accesses are done with the read_byte() and
38 * write_byte() functions which also do the memory address
39 * decoding. The read_zp() and write_zp() functions allow
40 * faster access to the zero page, the pop_byte() and
41 * push_byte() macros for the stack.
42 * - The PC is either emulated with a 16 bit address or a
43 * direct memory pointer (for faster access), depending on
44 * the PC_IS_POINTER #define. In the latter case, a second
45 * pointer, pc_base, is kept to allow recalculating the
46 * 16 bit 6502 PC if it has to be pushed on the stack.
47 * - The possible interrupt sources are:
48 * INT_VIA1IRQ: I flag is checked, jump to ($fffe) (unused)
49 * INT_VIA2IRQ: I flag is checked, jump to ($fffe) (unused)
50 * INT_IECIRQ: I flag is checked, jump to ($fffe) (unused)
51 * INT_RESET: Jump to ($fffc)
52 * - Interrupts are not checked before every opcode but only
53 * at certain times:
54 * On entering EmulateLine()
55 * On CLI
56 * On PLP if the I flag was cleared
57 * On RTI if the I flag was cleared
58 * - The z_flag variable has the inverse meaning of the
59 * 6502 Z flag
60 * - Only the highest bit of the n_flag variable is used
61 * - The $f2 opcode that would normally crash the 6502 is
62 * used to implement emulator-specific functions
63 * - The 1541 6502 emulation also includes a very simple VIA
64 * emulation (enough to make the IEC bus and GCR loading work).
65 * It's too small to move it to a source file of its own.
66 *
67 * Incompatibilities:
68 * ------------------
69 *
70 * - If PC_IS_POINTER is set, neither branches accross memory
71 * areas nor jumps to I/O space are possible
72 * - Extra cycles for crossing page boundaries are not
73 * accounted for
74 */
75
76 #include "sysdeps.h"
77
78 #include "CPU1541.h"
79 #include "1541job.h"
80 #include "C64.h"
81 #include "CIA.h"
82 #include "Display.h"
83
84
85 enum {
86 INT_RESET = 3
87 };
88
89
90 /*
91 * 6502 constructor: Initialize registers
92 */
93
94 MOS6502_1541::MOS6502_1541(C64 *c64, Job1541 *job, C64Display *disp, uint8 *Ram, uint8 *Rom)
95 : ram(Ram), rom(Rom), the_c64(c64), the_display(disp), the_job(job)
96 {
97 a = x = y = 0;
98 sp = 0xff;
99 n_flag = z_flag = 0;
100 v_flag = d_flag = c_flag = false;
101 i_flag = true;
102
103 borrowed_cycles = 0;
104
105 via1_t1c = via1_t1l = via1_t2c = via1_t2l = 0;
106 via1_sr = 0;
107 via2_t1c = via2_t1l = via2_t2c = via2_t2l = 0;
108 via2_sr = 0;
109
110 Idle = false;
111 }
112
113
114 /*
115 * Reset CPU asynchronously
116 */
117
118 void MOS6502_1541::AsyncReset(void)
119 {
120 interrupt.intr[INT_RESET] = true;
121 Idle = false;
122 }
123
124
125 /*
126 * Read a byte from I/O space
127 */
128
129 inline uint8 MOS6502_1541::read_byte_io(uint16 adr)
130 {
131 if ((adr & 0xfc00) == 0x1800) // VIA 1
132 switch (adr & 0xf) {
133 case 0:
134 return (via1_prb & 0x1a
135 | ((IECLines & TheCIA2->IECLines) >> 7) // DATA
136 | ((IECLines & TheCIA2->IECLines) >> 4) & 0x04 // CLK
137 | (TheCIA2->IECLines << 3) & 0x80) ^ 0x85; // ATN
138 case 1:
139 case 15:
140 return 0xff; // Keep 1541C ROMs happy (track 0 sensor)
141 case 2:
142 return via1_ddrb;
143 case 3:
144 return via1_ddra;
145 case 4:
146 via1_ifr &= 0xbf;
147 return via1_t1c;
148 case 5:
149 return via1_t1c >> 8;
150 case 6:
151 return via1_t1l;
152 case 7:
153 return via1_t1l >> 8;
154 case 8:
155 via1_ifr &= 0xdf;
156 return via1_t2c;
157 case 9:
158 return via1_t2c >> 8;
159 case 10:
160 return via1_sr;
161 case 11:
162 return via1_acr;
163 case 12:
164 return via1_pcr;
165 case 13:
166 return via1_ifr | (via1_ifr & via1_ier ? 0x80 : 0);
167 case 14:
168 return via1_ier | 0x80;
169 default: // Can't happen
170 return 0;
171 }
172
173 else if ((adr & 0xfc00) == 0x1c00) // VIA 2
174 switch (adr & 0xf) {
175 case 0:
176 if (the_job->SyncFound())
177 return via2_prb & 0x7f | the_job->WPState();
178 else
179 return via2_prb | 0x80 | the_job->WPState();
180 case 1:
181 case 15:
182 return the_job->ReadGCRByte();
183 case 2:
184 return via2_ddrb;
185 case 3:
186 return via2_ddra;
187 case 4:
188 via2_ifr &= 0xbf;
189 interrupt.intr[INT_VIA2IRQ] = false; // Clear job IRQ
190 return via2_t1c;
191 case 5:
192 return via2_t1c >> 8;
193 case 6:
194 return via2_t1l;
195 case 7:
196 return via2_t1l >> 8;
197 case 8:
198 via2_ifr &= 0xdf;
199 return via2_t2c;
200 case 9:
201 return via2_t2c >> 8;
202 case 10:
203 return via2_sr;
204 case 11:
205 return via2_acr;
206 case 12:
207 return via2_pcr;
208 case 13:
209 return via2_ifr | (via2_ifr & via2_ier ? 0x80 : 0);
210 case 14:
211 return via2_ier | 0x80;
212 default: // Can't happen
213 return 0;
214 }
215
216 else
217 return adr >> 8;
218 }
219
220
221 /*
222 * Read a byte from the CPU's address space
223 */
224
225 uint8 MOS6502_1541::read_byte(uint16 adr)
226 {
227 if (adr >= 0xc000)
228 return rom[adr & 0x3fff];
229 else if (adr < 0x1000)
230 return ram[adr & 0x07ff];
231 else
232 return read_byte_io(adr);
233 }
234
235
236 /*
237 * Read a word (little-endian) from the CPU's address space
238 */
239
240 inline uint16 MOS6502_1541::read_word(uint16 adr)
241 {
242 return read_byte(adr) | (read_byte(adr+1) << 8);
243 }
244
245
246 /*
247 * Write a byte to I/O space
248 */
249
250 void MOS6502_1541::write_byte_io(uint16 adr, uint8 byte)
251 {
252 if ((adr & 0xfc00) == 0x1800) // VIA 1
253 switch (adr & 0xf) {
254 case 0:
255 via1_prb = byte;
256 byte = ~via1_prb & via1_ddrb;
257 IECLines = (byte << 6) & ((~byte ^ TheCIA2->IECLines) << 3) & 0x80
258 | (byte << 3) & 0x40;
259 break;
260 case 1:
261 case 15:
262 via1_pra = byte;
263 break;
264 case 2:
265 via1_ddrb = byte;
266 byte &= ~via1_prb;
267 IECLines = (byte << 6) & ((~byte ^ TheCIA2->IECLines) << 3) & 0x80
268 | (byte << 3) & 0x40;
269 break;
270 case 3:
271 via1_ddra = byte;
272 break;
273 case 4:
274 case 6:
275 via1_t1l = via1_t1l & 0xff00 | byte;
276 break;
277 case 5:
278 via1_t1l = via1_t1l & 0xff | (byte << 8);
279 via1_ifr &= 0xbf;
280 via1_t1c = via1_t1l;
281 break;
282 case 7:
283 via1_t1l = via1_t1l & 0xff | (byte << 8);
284 break;
285 case 8:
286 via1_t2l = via1_t2l & 0xff00 | byte;
287 break;
288 case 9:
289 via1_t2l = via1_t2l & 0xff | (byte << 8);
290 via1_ifr &= 0xdf;
291 via1_t2c = via1_t2l;
292 break;
293 case 10:
294 via1_sr = byte;
295 break;
296 case 11:
297 via1_acr = byte;
298 break;
299 case 12:
300 via1_pcr = byte;
301 break;
302 case 13:
303 via1_ifr &= ~byte;
304 break;
305 case 14:
306 if (byte & 0x80)
307 via1_ier |= byte & 0x7f;
308 else
309 via1_ier &= ~byte;
310 break;
311 }
312
313 else if ((adr & 0xfc00) == 0x1c00) // VIA 2
314 switch (adr & 0xf) {
315 case 0:
316 if ((via2_prb ^ byte) & 8) // Bit 3: Drive LED
317 the_display->UpdateLEDs(byte & 8 ? 1 : 0, 0, 0, 0);
318 if ((via2_prb ^ byte) & 3) // Bits 0/1: Stepper motor
319 if ((via2_prb & 3) == ((byte+1) & 3))
320 the_job->MoveHeadOut();
321 else if ((via2_prb & 3) == ((byte-1) & 3))
322 the_job->MoveHeadIn();
323 via2_prb = byte & 0xef;
324 break;
325 case 1:
326 case 15:
327 via2_pra = byte;
328 break;
329 case 2:
330 via2_ddrb = byte;
331 break;
332 case 3:
333 via2_ddra = byte;
334 break;
335 case 4:
336 case 6:
337 via2_t1l = via2_t1l & 0xff00 | byte;
338 break;
339 case 5:
340 via2_t1l = via2_t1l & 0xff | (byte << 8);
341 via2_ifr &= 0xbf;
342 via2_t1c = via2_t1l;
343 break;
344 case 7:
345 via2_t1l = via2_t1l & 0xff | (byte << 8);
346 break;
347 case 8:
348 via2_t2l = via2_t2l & 0xff00 | byte;
349 break;
350 case 9:
351 via2_t2l = via2_t2l & 0xff | (byte << 8);
352 via2_ifr &= 0xdf;
353 via2_t2c = via2_t2l;
354 break;
355 case 10:
356 via2_sr = byte;
357 break;
358 case 11:
359 via2_acr = byte;
360 break;
361 case 12:
362 via2_pcr = byte;
363 break;
364 case 13:
365 via2_ifr &= ~byte;
366 break;
367 case 14:
368 if (byte & 0x80)
369 via2_ier |= byte & 0x7f;
370 else
371 via2_ier &= ~byte;
372 break;
373 }
374 }
375
376
377 /*
378 * Write a byte to the CPU's address space
379 */
380
381 inline void MOS6502_1541::write_byte(uint16 adr, uint8 byte)
382 {
383 if (adr < 0x1000)
384 ram[adr & 0x7ff] = byte;
385 else
386 write_byte_io(adr, byte);
387 }
388
389
390 /*
391 * Read a byte from the zeropage
392 */
393
394 inline uint8 MOS6502_1541::read_zp(uint16 adr)
395 {
396 return ram[adr];
397 }
398
399
400 /*
401 * Read a word (little-endian) from the zeropage
402 */
403
404 inline uint16 MOS6502_1541::read_zp_word(uint16 adr)
405 {
406 return ram[adr & 0xff] | (ram[(adr+1) & 0xff] << 8);
407 }
408
409
410 /*
411 * Write a byte to the zeropage
412 */
413
414 inline void MOS6502_1541::write_zp(uint16 adr, uint8 byte)
415 {
416 ram[adr] = byte;
417 }
418
419
420 /*
421 * Read byte from 6502/1541 address space (used by SAM)
422 */
423
424 uint8 MOS6502_1541::ExtReadByte(uint16 adr)
425 {
426 return read_byte(adr);
427 }
428
429
430 /*
431 * Write byte to 6502/1541 address space (used by SAM)
432 */
433
434 void MOS6502_1541::ExtWriteByte(uint16 adr, uint8 byte)
435 {
436 write_byte(adr, byte);
437 }
438
439
440 /*
441 * Jump to address
442 */
443
444 #if PC_IS_POINTER
445 void MOS6502_1541::jump(uint16 adr)
446 {
447 if (adr >= 0xc000) {
448 pc = rom + (adr & 0x3fff);
449 pc_base = rom - 0xc000;
450 } else if (adr < 0x800) {
451 pc = ram + adr;
452 pc_base = ram;
453 } else
454 illegal_jump(pc-pc_base, adr);
455 }
456 #else
457 inline void MOS6502_1541::jump(uint16 adr)
458 {
459 pc = adr;
460 }
461 #endif
462
463
464 /*
465 * Adc instruction
466 */
467
468 void MOS6502_1541::do_adc(uint8 byte)
469 {
470 if (!d_flag) {
471 uint16 tmp;
472
473 // Binary mode
474 tmp = a + byte + (c_flag ? 1 : 0);
475 c_flag = tmp > 0xff;
476 v_flag = !((a ^ byte) & 0x80) && ((a ^ tmp) & 0x80);
477 z_flag = n_flag = a = tmp;
478
479 } else {
480 uint16 al, ah;
481
482 // Decimal mode
483 al = (a & 0x0f) + (byte & 0x0f) + (c_flag ? 1 : 0); // Calculate lower nybble
484 if (al > 9) al += 6; // BCD fixup for lower nybble
485
486 ah = (a >> 4) + (byte >> 4); // Calculate upper nybble
487 if (al > 0x0f) ah++;
488
489 z_flag = a + byte + (c_flag ? 1 : 0); // Set flags
490 n_flag = ah << 4; // Only highest bit used
491 v_flag = (((ah << 4) ^ a) & 0x80) && !((a ^ byte) & 0x80);
492
493 if (ah > 9) ah += 6; // BCD fixup for upper nybble
494 c_flag = ah > 0x0f; // Set carry flag
495 a = (ah << 4) | (al & 0x0f); // Compose result
496 }
497 }
498
499
500 /*
501 * Sbc instruction
502 */
503
504 void MOS6502_1541::do_sbc(uint8 byte)
505 {
506 uint16 tmp = a - byte - (c_flag ? 0 : 1);
507
508 if (!d_flag) {
509
510 // Binary mode
511 c_flag = tmp < 0x100;
512 v_flag = ((a ^ tmp) & 0x80) && ((a ^ byte) & 0x80);
513 z_flag = n_flag = a = tmp;
514
515 } else {
516 uint16 al, ah;
517
518 // Decimal mode
519 al = (a & 0x0f) - (byte & 0x0f) - (c_flag ? 0 : 1); // Calculate lower nybble
520 ah = (a >> 4) - (byte >> 4); // Calculate upper nybble
521 if (al & 0x10) {
522 al -= 6; // BCD fixup for lower nybble
523 ah--;
524 }
525 if (ah & 0x10) ah -= 6; // BCD fixup for upper nybble
526
527 c_flag = tmp < 0x100; // Set flags
528 v_flag = ((a ^ tmp) & 0x80) && ((a ^ byte) & 0x80);
529 z_flag = n_flag = tmp;
530
531 a = (ah << 4) | (al & 0x0f); // Compose result
532 }
533 }
534
535
536 /*
537 * Get 6502 register state
538 */
539
540 void MOS6502_1541::GetState(MOS6502State *s)
541 {
542 s->a = a;
543 s->x = x;
544 s->y = y;
545
546 s->p = 0x20 | (n_flag & 0x80);
547 if (v_flag) s->p |= 0x40;
548 if (d_flag) s->p |= 0x08;
549 if (i_flag) s->p |= 0x04;
550 if (!z_flag) s->p |= 0x02;
551 if (c_flag) s->p |= 0x01;
552
553 #if PC_IS_POINTER
554 s->pc = pc - pc_base;
555 #else
556 s->pc = pc;
557 #endif
558 s->sp = sp | 0x0100;
559
560 s->intr[INT_VIA1IRQ] = interrupt.intr[INT_VIA1IRQ];
561 s->intr[INT_VIA2IRQ] = interrupt.intr[INT_VIA2IRQ];
562 s->intr[INT_IECIRQ] = interrupt.intr[INT_IECIRQ];
563 s->intr[INT_RESET] = interrupt.intr[INT_RESET];
564 s->instruction_complete = true;
565 s->idle = Idle;
566
567 s->via1_pra = via1_pra; s->via1_ddra = via1_ddra;
568 s->via1_prb = via1_prb; s->via1_ddrb = via1_ddrb;
569 s->via1_t1c = via1_t1c; s->via1_t1l = via1_t1l;
570 s->via1_t2c = via1_t2c; s->via1_t2l = via1_t2l;
571 s->via1_sr = via1_sr;
572 s->via1_acr = via1_acr; s->via1_pcr = via1_pcr;
573 s->via1_ifr = via1_ifr; s->via1_ier = via1_ier;
574
575 s->via2_pra = via2_pra; s->via2_ddra = via2_ddra;
576 s->via2_prb = via2_prb; s->via2_ddrb = via2_ddrb;
577 s->via2_t1c = via2_t1c; s->via2_t1l = via2_t1l;
578 s->via2_t2c = via2_t2c; s->via2_t2l = via2_t2l;
579 s->via2_sr = via2_sr;
580 s->via2_acr = via2_acr; s->via2_pcr = via2_pcr;
581 s->via2_ifr = via2_ifr; s->via2_ier = via2_ier;
582 }
583
584
585 /*
586 * Restore 6502 state
587 */
588
589 void MOS6502_1541::SetState(MOS6502State *s)
590 {
591 a = s->a;
592 x = s->x;
593 y = s->y;
594
595 n_flag = s->p;
596 v_flag = s->p & 0x40;
597 d_flag = s->p & 0x08;
598 i_flag = s->p & 0x04;
599 z_flag = !(s->p & 0x02);
600 c_flag = s->p & 0x01;
601
602 jump(s->pc);
603 sp = s->sp & 0xff;
604
605 interrupt.intr[INT_VIA1IRQ] = s->intr[INT_VIA1IRQ];
606 interrupt.intr[INT_VIA2IRQ] = s->intr[INT_VIA2IRQ];
607 interrupt.intr[INT_IECIRQ] = s->intr[INT_IECIRQ];
608 interrupt.intr[INT_RESET] = s->intr[INT_RESET];
609 Idle = s->idle;
610
611 via1_pra = s->via1_pra; via1_ddra = s->via1_ddra;
612 via1_prb = s->via1_prb; via1_ddrb = s->via1_ddrb;
613 via1_t1c = s->via1_t1c; via1_t1l = s->via1_t1l;
614 via1_t2c = s->via1_t2c; via1_t2l = s->via1_t2l;
615 via1_sr = s->via1_sr;
616 via1_acr = s->via1_acr; via1_pcr = s->via1_pcr;
617 via1_ifr = s->via1_ifr; via1_ier = s->via1_ier;
618
619 via2_pra = s->via2_pra; via2_ddra = s->via2_ddra;
620 via2_prb = s->via2_prb; via2_ddrb = s->via2_ddrb;
621 via2_t1c = s->via2_t1c; via2_t1l = s->via2_t1l;
622 via2_t2c = s->via2_t2c; via2_t2l = s->via2_t2l;
623 via2_sr = s->via2_sr;
624 via2_acr = s->via2_acr; via2_pcr = s->via2_pcr;
625 via2_ifr = s->via2_ifr; via2_ier = s->via2_ier;
626 }
627
628
629 /*
630 * Reset CPU
631 */
632
633 void MOS6502_1541::Reset(void)
634 {
635 // IEC lines and VIA registers
636 IECLines = 0xc0;
637
638 via1_pra = via1_ddra = via1_prb = via1_ddrb = 0;
639 via1_acr = via1_pcr = 0;
640 via1_ifr = via1_ier = 0;
641 via2_pra = via2_ddra = via2_prb = via2_ddrb = 0;
642 via2_acr = via2_pcr = 0;
643 via2_ifr = via2_ier = 0;
644
645 // Clear all interrupt lines
646 interrupt.intr_any = 0;
647
648 // Read reset vector
649 jump(read_word(0xfffc));
650
651 // Wake up 1541
652 Idle = false;
653 }
654
655
656 /*
657 * Illegal opcode encountered
658 */
659
660 void MOS6502_1541::illegal_op(uint8 op, uint16 at)
661 {
662 char illop_msg[80];
663
664 sprintf(illop_msg, "1541: Illegal opcode %02x at %04x.", op, at);
665 if (ShowRequester(illop_msg, "Reset 1541", "Reset C64"))
666 the_c64->Reset();
667 Reset();
668 }
669
670
671 /*
672 * Jump to illegal address space (PC_IS_POINTER only)
673 */
674
675 void MOS6502_1541::illegal_jump(uint16 at, uint16 to)
676 {
677 char illop_msg[80];
678
679 sprintf(illop_msg, "1541: Jump to I/O space at %04x to %04x.", at, to);
680 if (ShowRequester(illop_msg, "Reset 1541", "Reset C64"))
681 the_c64->Reset();
682 Reset();
683 }
684
685
686 /*
687 * Stack macros
688 */
689
690 // Pop a byte from the stack
691 #define pop_byte() ram[(++sp) | 0x0100]
692
693 // Push a byte onto the stack
694 #define push_byte(byte) (ram[(sp--) & 0xff | 0x0100] = (byte))
695
696 // Pop processor flags from the stack
697 #define pop_flags() \
698 n_flag = tmp = pop_byte(); \
699 v_flag = tmp & 0x40; \
700 d_flag = tmp & 0x08; \
701 i_flag = tmp & 0x04; \
702 z_flag = !(tmp & 0x02); \
703 c_flag = tmp & 0x01;
704
705 // Push processor flags onto the stack
706 #define push_flags(b_flag) \
707 tmp = 0x20 | (n_flag & 0x80); \
708 if (v_flag) tmp |= 0x40; \
709 if (b_flag) tmp |= 0x10; \
710 if (d_flag) tmp |= 0x08; \
711 if (i_flag) tmp |= 0x04; \
712 if (!z_flag) tmp |= 0x02; \
713 if (c_flag) tmp |= 0x01; \
714 push_byte(tmp);
715
716
717 /*
718 * Emulate cycles_left worth of 6502 instructions
719 * Returns number of cycles of last instruction
720 */
721
722 int MOS6502_1541::EmulateLine(int cycles_left)
723 {
724 uint8 tmp, tmp2;
725 uint16 adr;
726 int last_cycles = 0;
727
728 // Any pending interrupts?
729 if (interrupt.intr_any) {
730 handle_int:
731 if (interrupt.intr[INT_RESET])
732 Reset();
733
734 else if ((interrupt.intr[INT_VIA1IRQ] || interrupt.intr[INT_VIA2IRQ] || interrupt.intr[INT_IECIRQ]) && !i_flag) {
735 #if PC_IS_POINTER
736 push_byte((pc-pc_base) >> 8); push_byte(pc-pc_base);
737 #else
738 push_byte(pc >> 8); push_byte(pc);
739 #endif
740 push_flags(false);
741 i_flag = true;
742 jump(read_word(0xfffe));
743 last_cycles = 7;
744 }
745 }
746
747 #define IS_CPU_1541
748 #include "CPU_emulline.h"
749
750 // Extension opcode
751 case 0xf2:
752 #if PC_IS_POINTER
753 if ((pc-pc_base) < 0xc000) {
754 illegal_op(0xf2, pc-pc_base-1);
755 #else
756 if (pc < 0xc000) {
757 illegal_op(0xf2, pc-1);
758 #endif
759 break;
760 }
761 switch (read_byte_imm()) {
762 case 0x00: // Go to sleep in DOS idle loop if error flag is clear and no command received
763 Idle = !(ram[0x26c] | ram[0x7c]);
764 jump(0xebff);
765 break;
766 case 0x01: // Write sector
767 the_job->WriteSector();
768 jump(0xf5dc);
769 break;
770 case 0x02: // Format track
771 the_job->FormatTrack();
772 jump(0xfd8b);
773 break;
774 default:
775 #if PC_IS_POINTER
776 illegal_op(0xf2, pc-pc_base-1);
777 #else
778 illegal_op(0xf2, pc-1);
779 #endif
780 break;
781 }
782 break;
783 }
784 }
785 return last_cycles;
786 }