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, 7 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

# User Rev Content
1 cebix 1.1 /*
2     * CPU1541.cpp - 6502 (1541) emulation (line based)
3     *
4 cebix 1.4 * Frodo (C) 1994-1997,2002-2005 Christian Bauer
5 cebix 1.1 *
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     }