1 /*
2  * maincpu.c - Emulation of the main 6510 processor.
3  *
4  * Written by
5  *  Ettore Perazzoli <ettore@comm2000.it>
6  *  Andreas Boose <viceteam@t-online.de>
7  *
8  * This file is part of VICE, the Versatile Commodore Emulator.
9  * See README for copyright notice.
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24  *  02111-1307  USA.
25  *
26  */
27 
28 #include "vice.h"
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 
33 #include "6510core.h"
34 #include "alarm.h"
35 #include "archdep.h"
36 #include "clkguard.h"
37 #include "debug.h"
38 #include "interrupt.h"
39 #include "log.h"
40 #include "machine.h"
41 #include "maincpu.h"
42 #include "mem.h"
43 #include "monitor.h"
44 #ifdef C64DTV
45 #include "mos6510dtv.h"
46 #else
47 #include "mos6510.h"
48 #endif
49 #include "h6809regs.h"
50 #include "snapshot.h"
51 #include "traps.h"
52 #include "types.h"
53 
54 #ifndef EXIT_FAILURE
55 #define EXIT_FAILURE 1
56 #endif
57 
58 /* MACHINE_STUFF should define/undef
59 
60  - NEED_REG_PC
61 
62  The following are optional:
63 
64  - PAGE_ZERO
65  - PAGE_ONE
66  - STORE_IND
67  - LOAD_IND
68 
69 */
70 
71 /* ------------------------------------------------------------------------- */
72 
73 #define NEED_REG_PC
74 
75 /* ------------------------------------------------------------------------- */
76 
77 /* Implement the hack to make opcode fetches faster.  */
78 #define JUMP(addr)                                                                         \
79     do {                                                                                   \
80         reg_pc = (unsigned int)(addr);                                                     \
81         if (reg_pc >= (unsigned int)bank_limit || reg_pc < (unsigned int)bank_start) {     \
82             mem_mmu_translate((unsigned int)(addr), &bank_base, &bank_start, &bank_limit); \
83         }                                                                                  \
84     } while (0)
85 
86 /* ------------------------------------------------------------------------- */
87 
88 #ifdef FEATURE_CPUMEMHISTORY
89 #ifndef C64DTV /* FIXME: fix DTV and remove this */
90 
91 /* map access functions to memmap hooks */
92 #ifndef STORE
93 #define STORE(addr, value) \
94     memmap_mem_store(addr, value)
95 #endif
96 
97 #ifndef LOAD
98 #define LOAD(addr) \
99     memmap_mem_read(addr)
100 #endif
101 
102 #ifndef STORE_ZERO
103 #define STORE_ZERO(addr, value) \
104     memmap_mem_store((addr) & 0xff, value)
105 #endif
106 
107 #ifndef LOAD_ZERO
108 #define LOAD_ZERO(addr) \
109     memmap_mem_read((addr) & 0xff)
110 #endif
111 
112 #endif /* C64DTV */
113 #endif /* FEATURE_CPUMEMHISTORY */
114 
115 #ifndef STORE
116 #define STORE(addr, value) \
117     (*_mem_write_tab_ptr[(addr) >> 8])((uint16_t)(addr), (uint8_t)(value))
118 #endif
119 
120 #ifndef LOAD
121 #define LOAD(addr) \
122     (*_mem_read_tab_ptr[(addr) >> 8])((uint16_t)(addr))
123 #endif
124 
125 #ifndef STORE_ZERO
126 #define STORE_ZERO(addr, value) \
127     (*_mem_write_tab_ptr[0])((uint16_t)(addr), (uint8_t)(value))
128 #endif
129 
130 #ifndef LOAD_ZERO
131 #define LOAD_ZERO(addr) \
132     (*_mem_read_tab_ptr[0])((uint16_t)(addr))
133 #endif
134 
135 #define LOAD_ADDR(addr) \
136     ((LOAD((addr) + 1) << 8) | LOAD(addr))
137 
138 #define LOAD_ZERO_ADDR(addr) \
139     ((LOAD_ZERO((addr) + 1) << 8) | LOAD_ZERO(addr))
140 
141 /* Those may be overridden by the machine stuff.  Probably we want them in
142    the .def files, but if most of the machines do not use, we might keep it
143    here and only override it where needed.  */
144 #ifndef PAGE_ZERO
145 #define PAGE_ZERO mem_ram
146 #endif
147 
148 #ifndef PAGE_ONE
149 #define PAGE_ONE (mem_ram + 0x100)
150 #endif
151 
152 #ifndef STORE_IND
153 #define STORE_IND(addr, value) STORE((addr), (value))
154 #endif
155 
156 #ifndef LOAD_IND
157 #define LOAD_IND(addr) LOAD((addr))
158 #endif
159 
160 #ifndef DMA_FUNC
maincpu_generic_dma(void)161 static void maincpu_generic_dma(void)
162 {
163     /* Generic DMA hosts can be implemented here.
164        For example a very accurate REU emulation. */
165 }
166 #define DMA_FUNC maincpu_generic_dma()
167 #endif
168 
169 #ifndef DMA_ON_RESET
170 #define DMA_ON_RESET
171 #endif
172 
173 #ifndef CPU_ADDITIONAL_RESET
174 #define CPU_ADDITIONAL_RESET()
175 #endif
176 
177 #ifndef CPU_ADDITIONAL_INIT
178 #define CPU_ADDITIONAL_INIT()
179 #endif
180 
181 /* ------------------------------------------------------------------------- */
182 
183 struct interrupt_cpu_status_s *maincpu_int_status = NULL;
184 #ifndef CYCLE_EXACT_ALARM
185 alarm_context_t *maincpu_alarm_context = NULL;
186 #endif
187 clk_guard_t *maincpu_clk_guard = NULL;
188 monitor_interface_t *maincpu_monitor_interface = NULL;
189 
190 /* Global clock counter.  */
191 CLOCK maincpu_clk = 0L;
192 /* if != 0, exit when this many cycles have been executed */
193 CLOCK maincpu_clk_limit = 0L;
194 
195 /* This is flag is set to 1 each time a Read-Modify-Write instructions that
196    accesses memory is executed.  We can emulate the RMW behaviour of the 6510
197    this way.  VERY important notice: Always assign 1 for true, 0 for false!
198    Some functions depend on this to do some optimization.  */
199 int maincpu_rmw_flag = 0;
200 
201 /* Information about the last executed opcode.  This is used to know the
202    number of write cycles in the last executed opcode and to delay interrupts
203    by one more cycle if necessary, as happens with conditional branch opcodes
204    when the branch is taken.  */
205 unsigned int last_opcode_info;
206 
207 /* Address of the last executed opcode. This is used by watchpoints. */
208 unsigned int last_opcode_addr;
209 
210 /* Number of write cycles for each 6510 opcode.  */
211 const CLOCK maincpu_opcode_write_cycles[] = {
212             /* 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F */
213     /* $00 */  3, 0, 0, 2, 0, 0, 2, 2, 1, 0, 0, 0, 0, 0, 2, 2, /* $00 */
214     /* $10 */  0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 2, 2, /* $10 */
215     /* $20 */  2, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, /* $20 */
216     /* $30 */  0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 2, 2, /* $30 */
217     /* $40 */  0, 0, 0, 2, 0, 0, 2, 2, 1, 0, 0, 0, 0, 0, 2, 2, /* $40 */
218     /* $50 */  0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 2, 2, /* $50 */
219     /* $60 */  0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, /* $60 */
220     /* $70 */  0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 2, 2, /* $70 */
221     /* $80 */  0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, /* $80 */
222     /* $90 */  0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, /* $90 */
223     /* $A0 */  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $A0 */
224     /* $B0 */  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $B0 */
225     /* $C0 */  0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, /* $C0 */
226     /* $D0 */  0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 2, 2, /* $D0 */
227     /* $E0 */  0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, /* $E0 */
228     /* $F0 */  0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 2, 2  /* $F0 */
229             /* 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F */
230 };
231 
232 /* Public copy of the CPU registers.  As putting the registers into the
233    function makes it faster, you have to generate a `TRAP' interrupt to have
234    the values copied into this struct.  */
235 #ifdef C64DTV
236 mos6510dtv_regs_t maincpu_regs;
237 #else
238 mos6510_regs_t maincpu_regs;
239 #endif
240 
241 /* ------------------------------------------------------------------------- */
242 
maincpu_monitor_interface_get(void)243 monitor_interface_t *maincpu_monitor_interface_get(void)
244 {
245 #ifdef C64DTV
246     maincpu_monitor_interface->cpu_regs = NULL;
247     maincpu_monitor_interface->dtv_cpu_regs = &maincpu_regs;
248 #else
249     maincpu_monitor_interface->cpu_regs = &maincpu_regs;
250     maincpu_monitor_interface->cpu_R65C02_regs = NULL;
251     maincpu_monitor_interface->dtv_cpu_regs = NULL;
252 #endif
253 
254 #ifdef HAVE_Z80_REGS
255     maincpu_monitor_interface->z80_cpu_regs = &z80_regs;
256 #else
257     maincpu_monitor_interface->z80_cpu_regs = NULL;
258 #endif
259 #ifdef HAVE_6809_REGS
260     maincpu_monitor_interface->h6809_cpu_regs = &h6809_regs;
261 #else
262     maincpu_monitor_interface->h6809_cpu_regs = NULL;
263 #endif
264 
265     maincpu_monitor_interface->int_status = maincpu_int_status;
266 
267     maincpu_monitor_interface->clk = &maincpu_clk;
268 
269     maincpu_monitor_interface->current_bank = 0;
270     maincpu_monitor_interface->mem_bank_list = mem_bank_list;
271     maincpu_monitor_interface->mem_bank_from_name = mem_bank_from_name;
272     maincpu_monitor_interface->mem_bank_read = mem_bank_read;
273     maincpu_monitor_interface->mem_bank_peek = mem_bank_peek;
274     maincpu_monitor_interface->mem_bank_write = mem_bank_write;
275 
276     maincpu_monitor_interface->mem_ioreg_list_get = mem_ioreg_list_get;
277 
278     maincpu_monitor_interface->toggle_watchpoints_func = mem_toggle_watchpoints;
279 
280     maincpu_monitor_interface->set_bank_base = NULL;
281     maincpu_monitor_interface->get_line_cycle = machine_get_line_cycle;
282 
283     return maincpu_monitor_interface;
284 }
285 
286 /* ------------------------------------------------------------------------- */
287 
maincpu_early_init(void)288 void maincpu_early_init(void)
289 {
290     maincpu_int_status = interrupt_cpu_status_new();
291 }
292 
maincpu_init(void)293 void maincpu_init(void)
294 {
295     interrupt_cpu_status_init(maincpu_int_status, &last_opcode_info);
296 
297     /* cpu specifix additional init routine */
298     CPU_ADDITIONAL_INIT();
299 }
300 
maincpu_shutdown(void)301 void maincpu_shutdown(void)
302 {
303     interrupt_cpu_status_destroy(maincpu_int_status);
304 }
305 
cpu_reset(void)306 static void cpu_reset(void)
307 {
308     int preserve_monitor;
309 
310     preserve_monitor = maincpu_int_status->global_pending_int & IK_MONITOR;
311 
312     interrupt_cpu_status_reset(maincpu_int_status);
313 
314     if (preserve_monitor) {
315         interrupt_monitor_trap_on(maincpu_int_status);
316     }
317 
318     maincpu_clk = 6; /* # of clock cycles needed for RESET.  */
319 
320     /* CPU specific extra reset routine, currently only used
321        for 8502 fast mode refresh cycle. */
322     CPU_ADDITIONAL_RESET();
323 
324     /* Do machine-specific initialization.  */
325     machine_reset();
326 }
327 
maincpu_reset(void)328 void maincpu_reset(void)
329 {
330     cpu_reset();
331 }
332 
333 /* ------------------------------------------------------------------------- */
334 
335 /* Return nonzero if a pending NMI should be dispatched now.  This takes
336    account for the internal delays of the 6510, but does not actually check
337    the status of the NMI line.  */
interrupt_check_nmi_delay(interrupt_cpu_status_t * cs,CLOCK cpu_clk)338 inline static int interrupt_check_nmi_delay(interrupt_cpu_status_t *cs,
339                                             CLOCK cpu_clk)
340 {
341     CLOCK nmi_clk = cs->nmi_clk + INTERRUPT_DELAY;
342 
343     /* BRK (0x00) delays the NMI by one opcode.  */
344     /* TODO DO_INTERRUPT sets last opcode to 0: can NMI occur right after IRQ? */
345     if (OPINFO_NUMBER(*cs->last_opcode_info_ptr) == 0x00) {
346         return 0;
347     }
348 
349     /* Branch instructions delay IRQs and NMI by one cycle if branch
350        is taken with no page boundary crossing.  */
351     if (OPINFO_DELAYS_INTERRUPT(*cs->last_opcode_info_ptr)) {
352         nmi_clk++;
353     }
354 
355     if (cpu_clk >= nmi_clk) {
356         return 1;
357     }
358 
359     return 0;
360 }
361 
362 /* Return nonzero if a pending IRQ should be dispatched now.  This takes
363    account for the internal delays of the 6510, but does not actually check
364    the status of the IRQ line.  */
interrupt_check_irq_delay(interrupt_cpu_status_t * cs,CLOCK cpu_clk)365 inline static int interrupt_check_irq_delay(interrupt_cpu_status_t *cs,
366                                             CLOCK cpu_clk)
367 {
368     CLOCK irq_clk = cs->irq_clk + INTERRUPT_DELAY;
369 
370     /* Branch instructions delay IRQs and NMI by one cycle if branch
371        is taken with no page boundary crossing.  */
372     if (OPINFO_DELAYS_INTERRUPT(*cs->last_opcode_info_ptr)) {
373         irq_clk++;
374     }
375 
376     /* If an opcode changes the I flag from 1 to 0, the 6510 needs
377        one more opcode before it triggers the IRQ routine.  */
378     if (cpu_clk >= irq_clk) {
379         if (!OPINFO_ENABLES_IRQ(*cs->last_opcode_info_ptr)) {
380             return 1;
381         } else {
382             cs->global_pending_int |= IK_IRQPEND;
383         }
384     }
385     return 0;
386 }
387 
388 /* ------------------------------------------------------------------------- */
389 
390 #ifdef NEED_REG_PC
391 /* FIXME: this should really be uint16_t, but it breaks things (eg trap17.prg) */
392 unsigned int reg_pc;
393 #endif
394 
395 static uint8_t **o_bank_base;
396 static int *o_bank_start;
397 static int *o_bank_limit;
398 
maincpu_resync_limits(void)399 void maincpu_resync_limits(void)
400 {
401     if (o_bank_base) {
402         mem_mmu_translate(reg_pc, o_bank_base, o_bank_start, o_bank_limit);
403     }
404 }
405 
406 #ifdef __LIBRETRO__
maincpu_mainloop_retro(void)407 void maincpu_mainloop_retro(void)
408 {
409 #ifndef C64DTV
410     /* Notice that using a struct for these would make it a lot slower (at
411        least, on gcc 2.7.2.x).  */
412 static    uint8_t reg_a = 0;
413 static    uint8_t reg_x = 0;
414 static    uint8_t reg_y = 0;
415 #else
416 static    int reg_a_read_idx = 0;
417 static    int reg_a_write_idx = 0;
418 static    int reg_x_idx = 2;
419 static    int reg_y_idx = 1;
420 
421 #define reg_a_write(c)                      \
422     do {                                    \
423         dtv_registers[reg_a_write_idx] = c; \
424         if (reg_a_write_idx >= 3) {         \
425             maincpu_resync_limits();        \
426         }                                   \
427     } while (0);
428 #define reg_a_read dtv_registers[reg_a_read_idx]
429 #define reg_x_write(c)                \
430     do {                              \
431         dtv_registers[reg_x_idx] = c; \
432         if (reg_x_idx >= 3) {         \
433             maincpu_resync_limits();  \
434         }                             \
435     } while (0);
436 
437 #define reg_x_read dtv_registers[reg_x_idx]
438 #define reg_y_write(c)                \
439     do {                              \
440         dtv_registers[reg_y_idx] = c; \
441         if (reg_y_idx >= 3) {         \
442             maincpu_resync_limits();  \
443         }                             \
444     } while (0);
445 #define reg_y_read dtv_registers[reg_y_idx]
446 #endif
447 static    uint8_t reg_p = 0;
448 static    uint8_t reg_sp = 0;
449 static    uint8_t flag_n = 0;
450 static    uint8_t flag_z = 0;
451 #ifndef NEED_REG_PC
452 static    unsigned int reg_pc;
453 #endif
454 static    uint8_t *bank_base;
455 static    int bank_start = 0;
456 static    int bank_limit = 0;
457 
458 static int first1=0;
459 if(first1==0){
460     first1++;
461     o_bank_base = &bank_base;
462     o_bank_start = &bank_start;
463     o_bank_limit = &bank_limit;
464 
465     machine_trigger_reset(MACHINE_RESET_MODE_SOFT);
466 }
467 
468     /*while (1)*/ {
469 #define CLK maincpu_clk
470 #define RMW_FLAG maincpu_rmw_flag
471 #define LAST_OPCODE_INFO last_opcode_info
472 #define LAST_OPCODE_ADDR last_opcode_addr
473 #define TRACEFLG debug.maincpu_traceflg
474 
475 #define CPU_INT_STATUS maincpu_int_status
476 
477 #define ALARM_CONTEXT maincpu_alarm_context
478 
479 #define CHECK_PENDING_ALARM() (clk >= next_alarm_clk(maincpu_int_status))
480 
481 #define CHECK_PENDING_INTERRUPT() check_pending_interrupt(maincpu_int_status)
482 
483 #define TRAP(addr) maincpu_int_status->trap_func(addr);
484 
485 #define ROM_TRAP_HANDLER() traps_handler()
486 
487 #define JAM()                                                         \
488     do {                                                              \
489         unsigned int tmp;                                             \
490                                                                       \
491         EXPORT_REGISTERS();                                           \
492         tmp = machine_jam("   " CPU_STR ": JAM at $%04X   ", reg_pc); \
493         switch (tmp) {                                                \
494             case JAM_RESET:                                           \
495                 DO_INTERRUPT(IK_RESET);                               \
496                 break;                                                \
497             case JAM_HARD_RESET:                                      \
498                 mem_powerup();                                        \
499                 DO_INTERRUPT(IK_RESET);                               \
500                 break;                                                \
501             case JAM_MONITOR:                                         \
502                 monitor_startup(e_comp_space);                        \
503                 IMPORT_REGISTERS();                                   \
504                 break;                                                \
505             default:                                                  \
506                 CLK++;                                                \
507         }                                                             \
508     } while (0)
509 
510 #define CALLER e_comp_space
511 
512 #define ROM_TRAP_ALLOWED() mem_rom_trap_allowed((uint16_t)reg_pc)
513 
514 #define GLOBAL_REGS maincpu_regs
515 
516 #include "6510core.c"
517 
518         maincpu_int_status->num_dma_per_opcode = 0;
519 
520         if (maincpu_clk_limit && (maincpu_clk > maincpu_clk_limit)) {
521             log_error(LOG_DEFAULT, "cycle limit reached.");
522             archdep_vice_exit(EXIT_FAILURE);
523         }
524 #if 0
525         if (CLK > 246171754) {
526             debug.maincpu_traceflg = 1;
527         }
528 #endif
529     }
530 }
531 
532 #endif
533 
534 
maincpu_mainloop(void)535 void maincpu_mainloop(void)
536 {
537 #ifndef C64DTV
538     /* Notice that using a struct for these would make it a lot slower (at
539        least, on gcc 2.7.2.x).  */
540     uint8_t reg_a = 0;
541     uint8_t reg_x = 0;
542     uint8_t reg_y = 0;
543 #else
544     int reg_a_read_idx = 0;
545     int reg_a_write_idx = 0;
546     int reg_x_idx = 2;
547     int reg_y_idx = 1;
548 
549 #define reg_a_write(c)                      \
550     do {                                    \
551         dtv_registers[reg_a_write_idx] = c; \
552         if (reg_a_write_idx >= 3) {         \
553             maincpu_resync_limits();        \
554         }                                   \
555     } while (0);
556 #define reg_a_read dtv_registers[reg_a_read_idx]
557 #define reg_x_write(c)                \
558     do {                              \
559         dtv_registers[reg_x_idx] = c; \
560         if (reg_x_idx >= 3) {         \
561             maincpu_resync_limits();  \
562         }                             \
563     } while (0);
564 
565 #define reg_x_read dtv_registers[reg_x_idx]
566 #define reg_y_write(c)                \
567     do {                              \
568         dtv_registers[reg_y_idx] = c; \
569         if (reg_y_idx >= 3) {         \
570             maincpu_resync_limits();  \
571         }                             \
572     } while (0);
573 #define reg_y_read dtv_registers[reg_y_idx]
574 #endif
575     uint8_t reg_p = 0;
576     uint8_t reg_sp = 0;
577     uint8_t flag_n = 0;
578     uint8_t flag_z = 0;
579 #ifndef NEED_REG_PC
580     unsigned int reg_pc;
581 #endif
582     uint8_t *bank_base;
583     int bank_start = 0;
584     int bank_limit = 0;
585 
586     o_bank_base = &bank_base;
587     o_bank_start = &bank_start;
588     o_bank_limit = &bank_limit;
589 
590     machine_trigger_reset(MACHINE_RESET_MODE_SOFT);
591 
592     while (1) {
593 #define CLK maincpu_clk
594 #define RMW_FLAG maincpu_rmw_flag
595 #define LAST_OPCODE_INFO last_opcode_info
596 #define LAST_OPCODE_ADDR last_opcode_addr
597 #define TRACEFLG debug.maincpu_traceflg
598 
599 #define CPU_INT_STATUS maincpu_int_status
600 
601 #define ALARM_CONTEXT maincpu_alarm_context
602 
603 #define CHECK_PENDING_ALARM() (clk >= next_alarm_clk(maincpu_int_status))
604 
605 #define CHECK_PENDING_INTERRUPT() check_pending_interrupt(maincpu_int_status)
606 
607 #define TRAP(addr) maincpu_int_status->trap_func(addr);
608 
609 #define ROM_TRAP_HANDLER() traps_handler()
610 
611 #define JAM()                                                         \
612     do {                                                              \
613         unsigned int tmp;                                             \
614                                                                       \
615         EXPORT_REGISTERS();                                           \
616         tmp = machine_jam("   " CPU_STR ": JAM at $%04X   ", reg_pc); \
617         switch (tmp) {                                                \
618             case JAM_RESET:                                           \
619                 DO_INTERRUPT(IK_RESET);                               \
620                 break;                                                \
621             case JAM_HARD_RESET:                                      \
622                 mem_powerup();                                        \
623                 DO_INTERRUPT(IK_RESET);                               \
624                 break;                                                \
625             case JAM_MONITOR:                                         \
626                 monitor_startup(e_comp_space);                        \
627                 IMPORT_REGISTERS();                                   \
628                 break;                                                \
629             default:                                                  \
630                 CLK++;                                                \
631         }                                                             \
632     } while (0)
633 
634 #define CALLER e_comp_space
635 
636 #define ROM_TRAP_ALLOWED() mem_rom_trap_allowed((uint16_t)reg_pc)
637 
638 #define GLOBAL_REGS maincpu_regs
639 
640 #include "6510core.c"
641 
642         maincpu_int_status->num_dma_per_opcode = 0;
643 
644         if (maincpu_clk_limit && (maincpu_clk > maincpu_clk_limit)) {
645             log_error(LOG_DEFAULT, "cycle limit reached.");
646             archdep_vice_exit(EXIT_FAILURE);
647         }
648 #if 0
649         if (CLK > 246171754) {
650             debug.maincpu_traceflg = 1;
651         }
652 #endif
653     }
654 }
655 
656 /* ------------------------------------------------------------------------- */
657 
maincpu_set_pc(int pc)658 void maincpu_set_pc(int pc) {
659 #ifdef C64DTV
660     MOS6510DTV_REGS_SET_PC(&maincpu_regs, pc);
661 #else
662     MOS6510_REGS_SET_PC(&maincpu_regs, pc);
663 #endif
664 }
665 
maincpu_set_a(int a)666 void maincpu_set_a(int a) {
667 #ifdef C64DTV
668     MOS6510DTV_REGS_SET_A(&maincpu_regs, a);
669 #else
670     MOS6510_REGS_SET_A(&maincpu_regs, a);
671 #endif
672 }
673 
maincpu_set_x(int x)674 void maincpu_set_x(int x) {
675 #ifdef C64DTV
676     MOS6510DTV_REGS_SET_X(&maincpu_regs, x);
677 #else
678     MOS6510_REGS_SET_X(&maincpu_regs, x);
679 #endif
680 }
681 
maincpu_set_y(int y)682 void maincpu_set_y(int y) {
683 #ifdef C64DTV
684     MOS6510DTV_REGS_SET_Y(&maincpu_regs, y);
685 #else
686     MOS6510_REGS_SET_Y(&maincpu_regs, y);
687 #endif
688 }
689 
maincpu_set_sign(int n)690 void maincpu_set_sign(int n) {
691 #ifdef C64DTV
692     MOS6510DTV_REGS_SET_SIGN(&maincpu_regs, n);
693 #else
694     MOS6510_REGS_SET_SIGN(&maincpu_regs, n);
695 #endif
696 }
697 
maincpu_set_zero(int z)698 void maincpu_set_zero(int z) {
699 #ifdef C64DTV
700     MOS6510DTV_REGS_SET_ZERO(&maincpu_regs, z);
701 #else
702     MOS6510_REGS_SET_ZERO(&maincpu_regs, z);
703 #endif
704 }
705 
maincpu_set_carry(int c)706 void maincpu_set_carry(int c) {
707 #ifdef C64DTV
708     MOS6510DTV_REGS_SET_CARRY(&maincpu_regs, c);
709 #else
710     MOS6510_REGS_SET_CARRY(&maincpu_regs, c);
711 #endif
712 }
713 
maincpu_set_interrupt(int i)714 void maincpu_set_interrupt(int i) {
715 #ifdef C64DTV
716     MOS6510DTV_REGS_SET_INTERRUPT(&maincpu_regs, i);
717 #else
718     MOS6510_REGS_SET_INTERRUPT(&maincpu_regs, i);
719 #endif
720 }
721 
maincpu_get_pc(void)722 unsigned int maincpu_get_pc(void) {
723 #ifdef C64DTV
724     return MOS6510DTV_REGS_GET_PC(&maincpu_regs);
725 #else
726     return MOS6510_REGS_GET_PC(&maincpu_regs);
727 #endif
728 }
729 
maincpu_get_a(void)730 unsigned int maincpu_get_a(void) {
731 #ifdef C64DTV
732     return MOS6510DTV_REGS_GET_A(&maincpu_regs);
733 #else
734     return MOS6510_REGS_GET_A(&maincpu_regs);
735 #endif
736 }
737 
maincpu_get_x(void)738 unsigned int maincpu_get_x(void) {
739 #ifdef C64DTV
740     return MOS6510DTV_REGS_GET_X(&maincpu_regs);
741 #else
742     return MOS6510_REGS_GET_X(&maincpu_regs);
743 #endif
744 }
745 
maincpu_get_y(void)746 unsigned int maincpu_get_y(void) {
747 #ifdef C64DTV
748     return MOS6510DTV_REGS_GET_Y(&maincpu_regs);
749 #else
750     return MOS6510_REGS_GET_Y(&maincpu_regs);
751 #endif
752 }
753 
maincpu_get_sp(void)754 unsigned int maincpu_get_sp(void) {
755 #ifdef C64DTV
756     return MOS6510DTV_REGS_GET_SP(&maincpu_regs);
757 #else
758     return MOS6510_REGS_GET_SP(&maincpu_regs);
759 #endif
760 }
761 
762 /* ------------------------------------------------------------------------- */
763 
764 static char snap_module_name[] = "MAINCPU";
765 #define SNAP_MAJOR 1
766 #define SNAP_MINOR 1
767 
maincpu_snapshot_write_module(snapshot_t * s)768 int maincpu_snapshot_write_module(snapshot_t *s)
769 {
770     snapshot_module_t *m;
771 
772     m = snapshot_module_create(s, snap_module_name, ((uint8_t)SNAP_MAJOR),
773                                ((uint8_t)SNAP_MINOR));
774     if (m == NULL) {
775         return -1;
776     }
777 
778 #ifdef C64DTV
779     if (SMW_DW(m, maincpu_clk) < 0
780             || SMW_B(m, MOS6510DTV_REGS_GET_A(&maincpu_regs)) < 0
781             || SMW_B(m, MOS6510DTV_REGS_GET_X(&maincpu_regs)) < 0
782             || SMW_B(m, MOS6510DTV_REGS_GET_Y(&maincpu_regs)) < 0
783             || SMW_B(m, MOS6510DTV_REGS_GET_SP(&maincpu_regs)) < 0
784             || SMW_W(m, (uint16_t)MOS6510DTV_REGS_GET_PC(&maincpu_regs)) < 0
785             || SMW_B(m, (uint8_t)MOS6510DTV_REGS_GET_STATUS(&maincpu_regs)) < 0
786             || SMW_B(m, MOS6510DTV_REGS_GET_R3(&maincpu_regs)) < 0
787             || SMW_B(m, MOS6510DTV_REGS_GET_R4(&maincpu_regs)) < 0
788             || SMW_B(m, MOS6510DTV_REGS_GET_R5(&maincpu_regs)) < 0
789             || SMW_B(m, MOS6510DTV_REGS_GET_R6(&maincpu_regs)) < 0
790             || SMW_B(m, MOS6510DTV_REGS_GET_R7(&maincpu_regs)) < 0
791             || SMW_B(m, MOS6510DTV_REGS_GET_R8(&maincpu_regs)) < 0
792             || SMW_B(m, MOS6510DTV_REGS_GET_R9(&maincpu_regs)) < 0
793             || SMW_B(m, MOS6510DTV_REGS_GET_R10(&maincpu_regs)) < 0
794             || SMW_B(m, MOS6510DTV_REGS_GET_R11(&maincpu_regs)) < 0
795             || SMW_B(m, MOS6510DTV_REGS_GET_R12(&maincpu_regs)) < 0
796             || SMW_B(m, MOS6510DTV_REGS_GET_R13(&maincpu_regs)) < 0
797             || SMW_B(m, MOS6510DTV_REGS_GET_R14(&maincpu_regs)) < 0
798             || SMW_B(m, MOS6510DTV_REGS_GET_R15(&maincpu_regs)) < 0
799             || SMW_B(m, MOS6510DTV_REGS_GET_ACM(&maincpu_regs)) < 0
800             || SMW_B(m, MOS6510DTV_REGS_GET_YXM(&maincpu_regs)) < 0
801             || SMW_BA(m, burst_cache, 4) < 0
802             || SMW_W(m, burst_addr) < 0
803             || SMW_DW(m, dtvclockneg) < 0
804             || SMW_DW(m, (uint32_t)last_opcode_info) < 0) {
805         goto fail;
806     }
807 #else
808     if (SMW_DW(m, maincpu_clk) < 0
809             || SMW_B(m, MOS6510_REGS_GET_A(&maincpu_regs)) < 0
810             || SMW_B(m, MOS6510_REGS_GET_X(&maincpu_regs)) < 0
811             || SMW_B(m, MOS6510_REGS_GET_Y(&maincpu_regs)) < 0
812             || SMW_B(m, MOS6510_REGS_GET_SP(&maincpu_regs)) < 0
813             || SMW_W(m, (uint16_t)MOS6510_REGS_GET_PC(&maincpu_regs)) < 0
814             || SMW_B(m, (uint8_t)MOS6510_REGS_GET_STATUS(&maincpu_regs)) < 0
815             || SMW_DW(m, (uint32_t)last_opcode_info) < 0) {
816         goto fail;
817     }
818 #endif
819 
820     if (interrupt_write_snapshot(maincpu_int_status, m) < 0) {
821         goto fail;
822     }
823 
824     if (interrupt_write_new_snapshot(maincpu_int_status, m) < 0) {
825         goto fail;
826     }
827 
828     return snapshot_module_close(m);
829 
830 fail:
831     if (m != NULL) {
832         snapshot_module_close(m);
833     }
834     return -1;
835 }
836 
maincpu_snapshot_read_module(snapshot_t * s)837 int maincpu_snapshot_read_module(snapshot_t *s)
838 {
839     uint8_t a, x, y, sp, status;
840 #ifdef C64DTV
841     uint8_t r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, acm, yxm;
842 #endif
843     uint16_t pc;
844     uint8_t major, minor;
845     snapshot_module_t *m;
846 
847     m = snapshot_module_open(s, snap_module_name, &major, &minor);
848     if (m == NULL) {
849         return -1;
850     }
851 
852     /* FIXME: This is a mighty kludge to prevent VIC-II from stealing the
853        wrong number of cycles.  */
854     maincpu_rmw_flag = 0;
855 
856     /* XXX: Assumes `CLOCK' is the same size as a `DWORD'.  */
857     if (SMR_DW(m, &maincpu_clk) < 0
858             || SMR_B(m, &a) < 0
859             || SMR_B(m, &x) < 0
860             || SMR_B(m, &y) < 0
861             || SMR_B(m, &sp) < 0
862             || SMR_W(m, &pc) < 0
863             || SMR_B(m, &status) < 0
864 #ifdef C64DTV
865             || SMR_B(m, &r3) < 0
866             || SMR_B(m, &r4) < 0
867             || SMR_B(m, &r5) < 0
868             || SMR_B(m, &r6) < 0
869             || SMR_B(m, &r7) < 0
870             || SMR_B(m, &r8) < 0
871             || SMR_B(m, &r9) < 0
872             || SMR_B(m, &r10) < 0
873             || SMR_B(m, &r11) < 0
874             || SMR_B(m, &r12) < 0
875             || SMR_B(m, &r13) < 0
876             || SMR_B(m, &r14) < 0
877             || SMR_B(m, &r15) < 0
878             || SMR_B(m, &acm) < 0
879             || SMR_B(m, &yxm) < 0
880             || SMR_BA(m, burst_cache, 4) < 0
881             || SMR_W(m, &burst_addr) < 0
882             || SMR_DW_INT(m, &dtvclockneg) < 0
883 #endif
884             || SMR_DW_UINT(m, &last_opcode_info) < 0) {
885         goto fail;
886     }
887 
888 #ifdef C64DTV
889     MOS6510DTV_REGS_SET_A(&maincpu_regs, a);
890     MOS6510DTV_REGS_SET_X(&maincpu_regs, x);
891     MOS6510DTV_REGS_SET_Y(&maincpu_regs, y);
892     MOS6510DTV_REGS_SET_SP(&maincpu_regs, sp);
893     MOS6510DTV_REGS_SET_PC(&maincpu_regs, pc);
894     MOS6510DTV_REGS_SET_STATUS(&maincpu_regs, status);
895     MOS6510DTV_REGS_SET_R3(&maincpu_regs, r3);
896     MOS6510DTV_REGS_SET_R4(&maincpu_regs, r4);
897     MOS6510DTV_REGS_SET_R5(&maincpu_regs, r5);
898     MOS6510DTV_REGS_SET_R6(&maincpu_regs, r6);
899     MOS6510DTV_REGS_SET_R7(&maincpu_regs, r7);
900     MOS6510DTV_REGS_SET_R8(&maincpu_regs, r8);
901     MOS6510DTV_REGS_SET_R9(&maincpu_regs, r9);
902     MOS6510DTV_REGS_SET_R10(&maincpu_regs, r10);
903     MOS6510DTV_REGS_SET_R11(&maincpu_regs, r11);
904     MOS6510DTV_REGS_SET_R12(&maincpu_regs, r12);
905     MOS6510DTV_REGS_SET_R13(&maincpu_regs, r13);
906     MOS6510DTV_REGS_SET_R14(&maincpu_regs, r14);
907     MOS6510DTV_REGS_SET_R15(&maincpu_regs, r15);
908     MOS6510DTV_REGS_SET_ACM(&maincpu_regs, acm);
909     MOS6510DTV_REGS_SET_YXM(&maincpu_regs, yxm);
910 #else
911     MOS6510_REGS_SET_A(&maincpu_regs, a);
912     MOS6510_REGS_SET_X(&maincpu_regs, x);
913     MOS6510_REGS_SET_Y(&maincpu_regs, y);
914     MOS6510_REGS_SET_SP(&maincpu_regs, sp);
915     MOS6510_REGS_SET_PC(&maincpu_regs, pc);
916     MOS6510_REGS_SET_STATUS(&maincpu_regs, status);
917 #endif
918 
919     if (interrupt_read_snapshot(maincpu_int_status, m) < 0) {
920         goto fail;
921     }
922 
923     if (interrupt_read_new_snapshot(maincpu_int_status, m) < 0) {
924         goto fail;
925     }
926 
927     return snapshot_module_close(m);
928 
929 fail:
930     if (m != NULL) {
931         snapshot_module_close(m);
932     }
933     return -1;
934 }
935