1 /*
2  * main65816cpu.c - Emulation of the main 65816 processor.
3  *
4  * Written by
5  *  Marco van den Heuvel <blackystardust68@yahoo.com>
6  *  Kajtar Zsolt <soci@c64.rulez.org>
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 "main65816cpu.h"
42 #include "mem.h"
43 #include "monitor.h"
44 #include "snapshot.h"
45 #include "traps.h"
46 #include "types.h"
47 #include "wdc65816.h"
48 
49 #ifndef EXIT_FAILURE
50 #define EXIT_FAILURE 1
51 #endif
52 
53 /* MACHINE_STUFF should define/undef
54 
55  - NEED_REG_PC
56 
57 */
58 
59 /* ------------------------------------------------------------------------- */
60 
61 #define NEED_REG_PC
62 
63 /* ------------------------------------------------------------------------- */
64 
65 /* Implement the hack to make opcode fetches faster.  */
66 #define JUMP(addr)                            \
67     do {                                      \
68         reg_pc = (unsigned int)(addr);        \
69         if (reg_pbr != bank_bank || reg_pc >= (unsigned int)bank_limit || reg_pc < (unsigned int)bank_start) { \
70             mem_mmu_translate((unsigned int)(addr) | (reg_pbr << 16), &bank_base, &bank_start, &bank_limit); \
71             bank_bank = reg_pbr;              \
72         }                                     \
73     } while (0)
74 
75 /* ------------------------------------------------------------------------- */
76 
77 #ifndef STORE
78 #define STORE(addr, value) \
79     (*_mem_write_tab_ptr[(addr) >> 8])((uint16_t)(addr), (uint8_t)(value))
80 #endif
81 
82 #ifndef LOAD
83 #define LOAD(addr) \
84     (*_mem_read_tab_ptr[(addr) >> 8])((uint16_t)(addr))
85 #endif
86 
87 /* Those may be overridden by the machine stuff.  Probably we want them in
88    the .def files, but if most of the machines do not use, we might keep it
89    here and only override it where needed.  */
90 
91 #ifndef DMA_FUNC
maincpu_generic_dma(void)92 static void maincpu_generic_dma(void)
93 {
94     /* Generic DMA hosts can be implemented here.
95        For example a very accurate REU emulation. */
96 }
97 #define DMA_FUNC maincpu_generic_dma()
98 #endif
99 
100 #ifndef DMA_ON_RESET
101 #define DMA_ON_RESET
102 #endif
103 
104 #ifndef CPU_ADDITIONAL_RESET
105 #define CPU_ADDITIONAL_RESET()
106 #endif
107 
108 #ifndef CPU_ADDITIONAL_INIT
109 #define CPU_ADDITIONAL_INIT()
110 #endif
111 
112 /* ------------------------------------------------------------------------- */
113 
114 struct interrupt_cpu_status_s *maincpu_int_status = NULL;
115 #ifndef CYCLE_EXACT_ALARM
116 alarm_context_t *maincpu_alarm_context = NULL;
117 #endif
118 clk_guard_t *maincpu_clk_guard = NULL;
119 monitor_interface_t *maincpu_monitor_interface = NULL;
120 
121 /* This flag is an obsolete optimization. It's always 0 for the 65816 CPU,
122    but has to be kept for the common code. */
123 int maincpu_rmw_flag = 0;
124 
125 /* Global clock counter.  */
126 CLOCK maincpu_clk = 0L;
127 /* if != 0, exit when this many cycles have been executed */
128 CLOCK maincpu_clk_limit = 0L;
129 
130 /* Information about the last executed opcode.  This is used to know the
131    number of write cycles in the last executed opcode and to delay interrupts
132    by one more cycle if necessary, as happens with conditional branch opcodes
133    when the branch is taken.  */
134 unsigned int last_opcode_info;
135 
136 /* Address of the last executed opcode. This is used by watchpoints. */
137 unsigned int last_opcode_addr;
138 
139 /* Public copy of the CPU registers.  As putting the registers into the
140    function makes it faster, you have to generate a `TRAP' interrupt to have
141    the values copied into this struct.  */
142 WDC65816_regs_t maincpu_regs;
143 
144 /* ------------------------------------------------------------------------- */
145 
maincpu_monitor_interface_get(void)146 monitor_interface_t *maincpu_monitor_interface_get(void)
147 {
148     maincpu_monitor_interface->cpu_regs = NULL;
149     maincpu_monitor_interface->cpu_R65C02_regs = NULL;
150     maincpu_monitor_interface->cpu_65816_regs = &maincpu_regs;
151     maincpu_monitor_interface->dtv_cpu_regs = NULL;
152     maincpu_monitor_interface->z80_cpu_regs = NULL;
153     maincpu_monitor_interface->h6809_cpu_regs = NULL;
154 
155     maincpu_monitor_interface->int_status = maincpu_int_status;
156 
157     maincpu_monitor_interface->clk = &maincpu_clk;
158 
159     maincpu_monitor_interface->current_bank = 0;
160     maincpu_monitor_interface->current_bank_index = 0;
161 
162     maincpu_monitor_interface->mem_bank_list = mem_bank_list;
163     maincpu_monitor_interface->mem_bank_list_nos = mem_bank_list_nos;
164 
165     maincpu_monitor_interface->mem_bank_from_name = mem_bank_from_name;
166     maincpu_monitor_interface->mem_bank_index_from_bank = mem_bank_index_from_bank;
167     maincpu_monitor_interface->mem_bank_flags_from_bank = mem_bank_flags_from_bank;
168 
169     maincpu_monitor_interface->mem_bank_read = mem_bank_read;
170     maincpu_monitor_interface->mem_bank_peek = mem_bank_peek;
171     maincpu_monitor_interface->mem_bank_write = mem_bank_write;
172     maincpu_monitor_interface->mem_bank_poke = mem_bank_poke;
173 
174     maincpu_monitor_interface->mem_ioreg_list_get = mem_ioreg_list_get;
175 
176     maincpu_monitor_interface->toggle_watchpoints_func = mem_toggle_watchpoints;
177 
178     maincpu_monitor_interface->set_bank_base = NULL;
179     maincpu_monitor_interface->get_line_cycle = machine_get_line_cycle;
180 
181     return maincpu_monitor_interface;
182 }
183 
184 /* ------------------------------------------------------------------------- */
185 
maincpu_early_init(void)186 void maincpu_early_init(void)
187 {
188     maincpu_int_status = interrupt_cpu_status_new();
189 }
190 
maincpu_init(void)191 void maincpu_init(void)
192 {
193     interrupt_cpu_status_init(maincpu_int_status, &last_opcode_info);
194 
195     /* cpu specific additional init routine */
196     CPU_ADDITIONAL_INIT();
197 }
198 
maincpu_shutdown(void)199 void maincpu_shutdown(void)
200 {
201     interrupt_cpu_status_destroy(maincpu_int_status);
202 }
203 
cpu_reset(void)204 static void cpu_reset(void)
205 {
206     int preserve_monitor;
207 
208     preserve_monitor = maincpu_int_status->global_pending_int & IK_MONITOR;
209 
210     interrupt_cpu_status_reset(maincpu_int_status);
211 
212     if (preserve_monitor) {
213         interrupt_monitor_trap_on(maincpu_int_status);
214     }
215 
216     maincpu_clk = 6; /* # of clock cycles needed for RESET.  */
217 
218     /* CPU specific extra reset routine, currently only used
219        for 8502 fast mode refresh cycle. */
220     CPU_ADDITIONAL_RESET();
221 
222     /* Do machine-specific initialization.  */
223     machine_reset();
224 }
225 
maincpu_reset(void)226 void maincpu_reset(void)
227 {
228     cpu_reset();
229 }
230 
231 /* ------------------------------------------------------------------------- */
232 
233 #ifdef NEED_REG_PC
234 unsigned int reg_pc;
235 #endif
236 
237 static bool bank_base_ready = false;
238 static uint8_t *bank_base = NULL;
239 static int bank_start = 0;
240 static int bank_limit = 0;
241 static uint8_t bank_bank = 0;
242 
maincpu_resync_limits(void)243 void maincpu_resync_limits(void)
244 {
245     if (bank_base_ready) {
246         mem_mmu_translate(reg_pc | (bank_bank << 16), &bank_base, &bank_start, &bank_limit);
247     }
248 }
249 
maincpu_mainloop(void)250 void maincpu_mainloop(void)
251 {
252     /* Notice that using a struct for these would make it a lot slower (at
253        least, on gcc 2.7.2.x).  */
254  union regs {
255      uint16_t reg_s;
256      uint8_t reg_q[2];
257  } regs65802;
258 
259 #define reg_c regs65802.reg_s
260 #ifndef WORDS_BIGENDIAN
261 #define reg_a regs65802.reg_q[0]
262 #define reg_b regs65802.reg_q[1]
263 #else
264 #define reg_a regs65802.reg_q[1]
265 #define reg_b regs65802.reg_q[0]
266 #endif
267 
268     uint16_t reg_x = 0;
269     uint16_t reg_y = 0;
270     uint8_t reg_pbr = 0;
271     uint8_t reg_dbr = 0;
272     uint16_t reg_dpr = 0;
273     uint8_t reg_p = 0;
274     uint16_t reg_sp = 0x100;
275     uint8_t flag_n = 0;
276     uint8_t flag_z = 0;
277     uint8_t reg_emul = 1;
278     int interrupt65816 = IK_RESET;
279 #ifndef NEED_REG_PC
280     unsigned int reg_pc;
281 #endif
282 
283     /*
284      * Enable maincpu_resync_limits functionality .. in the old code
285      * this is where the local stack var had its address copied to
286      * the global.
287      */
288     bank_base_ready = true;
289 
290     reg_c = 0;
291 
292     machine_trigger_reset(MACHINE_RESET_MODE_SOFT);
293 
294     while (1) {
295 
296 #define CLK maincpu_clk
297 #define LAST_OPCODE_INFO last_opcode_info
298 #define LAST_OPCODE_ADDR last_opcode_addr
299 #define TRACEFLG debug.maincpu_traceflg
300 
301 #define CPU_INT_STATUS maincpu_int_status
302 
303 #define ALARM_CONTEXT maincpu_alarm_context
304 
305 #define CHECK_PENDING_ALARM() \
306    (clk >= next_alarm_clk(maincpu_int_status))
307 
308 #define CHECK_PENDING_INTERRUPT() \
309    check_pending_interrupt(maincpu_int_status)
310 
311 #define TRAP(addr) \
312    maincpu_int_status->trap_func(addr);
313 
314 #define ROM_TRAP_HANDLER() \
315    traps_handler()
316 
317 #define JAM()                                                         \
318     do {                                                              \
319         unsigned int tmp;                                             \
320                                                                       \
321         EXPORT_REGISTERS();                                           \
322         tmp = machine_jam("   " CPU_STR ": JAM at $%02x%04X   ", reg_pbr, reg_pc); \
323         switch (tmp) {                                                \
324             case JAM_RESET:                                           \
325                 DO_INTERRUPT(IK_RESET);                               \
326                 break;                                                \
327             case JAM_HARD_RESET:                                      \
328                 mem_powerup();                                        \
329                 DO_INTERRUPT(IK_RESET);                               \
330                 break;                                                \
331             case JAM_MONITOR:                                         \
332                 monitor_startup(e_comp_space);                        \
333                 IMPORT_REGISTERS();                                   \
334                 break;                                                \
335             default:                                                  \
336                 STP();                                                \
337         }                                                             \
338     } while (0)
339 
340 #define STP_65816() JAM()
341 #define WAI_65816() WAI()
342 #define COP_65816(value) COP()
343 
344 #define CALLER e_comp_space
345 
346 #define ROM_TRAP_ALLOWED() mem_rom_trap_allowed((uint16_t)reg_pc)
347 
348 #define GLOBAL_REGS maincpu_regs
349 
350 #include "65816core.c"
351 
352         maincpu_int_status->num_dma_per_opcode = 0;
353 
354         if (maincpu_clk_limit && (maincpu_clk > maincpu_clk_limit)) {
355             log_error(LOG_DEFAULT, "cycle limit reached.");
356             archdep_vice_exit(EXIT_FAILURE);
357         }
358 #if 0
359         if (CLK > 246171754)
360             debug.maincpu_traceflg = 1;
361 #endif
362     }
363 }
364 
365 /* ------------------------------------------------------------------------- */
366 
maincpu_set_pc(int pc)367 void maincpu_set_pc(int pc) {
368     WDC65816_REGS_SET_PC(&maincpu_regs, pc);
369 }
370 
maincpu_set_a(int a)371 void maincpu_set_a(int a) {
372     WDC65816_REGS_SET_A(&maincpu_regs, a);
373 }
374 
maincpu_set_x(int x)375 void maincpu_set_x(int x) {
376     WDC65816_REGS_SET_X(&maincpu_regs, x);
377 }
378 
maincpu_set_y(int y)379 void maincpu_set_y(int y) {
380     WDC65816_REGS_SET_Y(&maincpu_regs, y);
381 }
382 
maincpu_set_sign(int n)383 void maincpu_set_sign(int n) {
384     WDC65816_REGS_SET_SIGN(&maincpu_regs, n);
385 }
386 
maincpu_set_zero(int z)387 void maincpu_set_zero(int z) {
388     WDC65816_REGS_SET_ZERO(&maincpu_regs, z);
389 }
390 
maincpu_set_carry(int c)391 void maincpu_set_carry(int c) {
392     WDC65816_REGS_SET_CARRY(&maincpu_regs, c);
393 }
394 
maincpu_set_interrupt(int i)395 void maincpu_set_interrupt(int i) {
396     WDC65816_REGS_SET_INTERRUPT(&maincpu_regs, i);
397 }
398 
maincpu_get_pc(void)399 unsigned int maincpu_get_pc(void) {
400     return WDC65816_REGS_GET_PC(&maincpu_regs);
401 }
402 
maincpu_get_a(void)403 unsigned int maincpu_get_a(void) {
404     return WDC65816_REGS_GET_A(&maincpu_regs);
405 }
406 
maincpu_get_x(void)407 unsigned int maincpu_get_x(void) {
408     return WDC65816_REGS_GET_X(&maincpu_regs);
409 }
410 
maincpu_get_y(void)411 unsigned int maincpu_get_y(void) {
412     return WDC65816_REGS_GET_Y(&maincpu_regs);
413 }
414 
maincpu_get_sp(void)415 unsigned int maincpu_get_sp(void) {
416     return WDC65816_REGS_GET_SP(&maincpu_regs);
417 }
418 
419 /* ------------------------------------------------------------------------- */
420 
421 static char snap_module_name[] = "MAIN6565802CPU";
422 #define SNAP_MAJOR 1
423 #define SNAP_MINOR 1
424 
maincpu_snapshot_write_module(snapshot_t * s)425 int maincpu_snapshot_write_module(snapshot_t *s)
426 {
427     snapshot_module_t *m;
428 
429     m = snapshot_module_create(s, snap_module_name, ((uint8_t)SNAP_MAJOR),
430                                ((uint8_t)SNAP_MINOR));
431     if (m == NULL)
432         return -1;
433 
434     if (0
435         || SMW_DW(m, maincpu_clk) < 0
436         || SMW_B(m, (uint8_t)WDC65816_REGS_GET_A(&maincpu_regs)) < 0
437         || SMW_B(m, (uint8_t)WDC65816_REGS_GET_B(&maincpu_regs)) < 0
438         || SMW_W(m, (uint16_t)WDC65816_REGS_GET_X(&maincpu_regs)) < 0
439         || SMW_W(m, (uint16_t)WDC65816_REGS_GET_Y(&maincpu_regs)) < 0
440         || SMW_W(m, (uint16_t)WDC65816_REGS_GET_SP(&maincpu_regs)) < 0
441         || SMW_W(m, (uint16_t)WDC65816_REGS_GET_DPR(&maincpu_regs)) < 0
442         || SMW_B(m, (uint8_t)WDC65816_REGS_GET_PBR(&maincpu_regs)) < 0
443         || SMW_B(m, (uint8_t)WDC65816_REGS_GET_DBR(&maincpu_regs)) < 0
444         || SMW_B(m, (uint8_t)WDC65816_REGS_GET_EMUL(&maincpu_regs)) < 0
445         || SMW_W(m, (uint16_t)WDC65816_REGS_GET_PC(&maincpu_regs)) < 0
446         || SMW_B(m, (uint8_t)WDC65816_REGS_GET_STATUS(&maincpu_regs)) < 0
447         || SMW_DW(m, (uint8_t)last_opcode_info) < 0)
448         goto fail;
449 
450     if (interrupt_write_snapshot(maincpu_int_status, m) < 0) {
451         goto fail;
452     }
453 
454     if (interrupt_write_new_snapshot(maincpu_int_status, m) < 0) {
455         goto fail;
456     }
457 
458     return snapshot_module_close(m);
459 
460 fail:
461     if (m != NULL) {
462         snapshot_module_close(m);
463     }
464     return -1;
465 }
466 
maincpu_snapshot_read_module(snapshot_t * s)467 int maincpu_snapshot_read_module(snapshot_t *s)
468 {
469     uint8_t a, b, pbr, dbr, emul, status;
470     uint16_t x, y, sp, pc, dpr;
471     uint8_t major, minor;
472     snapshot_module_t *m;
473 
474     m = snapshot_module_open(s, snap_module_name, &major, &minor);
475     if (m == NULL) {
476         return -1;
477     }
478 
479     /* XXX: Assumes `CLOCK' is the same size as a `DWORD'.  */
480     if (0
481         || SMR_DW(m, &maincpu_clk) < 0
482         || SMR_B(m, &a) < 0
483         || SMR_B(m, &b) < 0
484         || SMR_W(m, &x) < 0
485         || SMR_W(m, &y) < 0
486         || SMR_W(m, &sp) < 0
487         || SMR_W(m, &dpr) < 0
488         || SMR_B(m, &pbr) < 0
489         || SMR_B(m, &dbr) < 0
490         || SMR_B(m, &emul) < 0
491         || SMR_W(m, &pc) < 0
492         || SMR_B(m, &status) < 0
493         || SMR_DW_UINT(m, &last_opcode_info) < 0)
494         goto fail;
495 
496     WDC65816_REGS_SET_A(&maincpu_regs, a);
497     WDC65816_REGS_SET_B(&maincpu_regs, b);
498     WDC65816_REGS_SET_X(&maincpu_regs, x);
499     WDC65816_REGS_SET_Y(&maincpu_regs, y);
500     WDC65816_REGS_SET_SP(&maincpu_regs, sp);
501     WDC65816_REGS_SET_DPR(&maincpu_regs, dpr);
502     WDC65816_REGS_SET_PBR(&maincpu_regs, pbr);
503     WDC65816_REGS_SET_DBR(&maincpu_regs, dbr);
504     WDC65816_REGS_SET_EMUL(&maincpu_regs, emul);
505     WDC65816_REGS_SET_PC(&maincpu_regs, pc);
506     WDC65816_REGS_SET_STATUS(&maincpu_regs, status);
507 
508     if (interrupt_read_snapshot(maincpu_int_status, m) < 0) {
509         goto fail;
510     }
511 
512     if (interrupt_read_new_snapshot(maincpu_int_status, m) < 0) {
513         goto fail;
514     }
515 
516     return snapshot_module_close(m);
517 
518 fail:
519     if (m != NULL)
520         snapshot_module_close(m);
521     return -1;
522 }
523