1 /*
2  * c64mem.c -- C64 memory handling.
3  *
4  * Written by
5  *  Andreas Boose <viceteam@t-online.de>
6  *  Ettore Perazzoli <ettore@comm2000.it>
7  *  Marco van den Heuvel <blackystardust68@yahoo.com>
8  *
9  * This file is part of VICE, the Versatile Commodore Emulator.
10  * See README for copyright notice.
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  This program is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program; if not, write to the Free Software
24  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25  *  02111-1307  USA.
26  *
27  */
28 
29 #include "vice.h"
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "alarm.h"
36 #include "c64.h"
37 #include "c64-resources.h"
38 #include "c64_256k.h"
39 #include "c64cart.h"
40 #include "c64cia.h"
41 #include "c64mem.h"
42 #include "c64meminit.h"
43 #include "c64memlimit.h"
44 #include "c64memrom.h"
45 #include "c64pla.h"
46 #include "c64ui.h"
47 #include "c64cartmem.h"
48 #include "cartio.h"
49 #include "cartridge.h"
50 #include "cia.h"
51 #include "clkguard.h"
52 #include "machine.h"
53 #include "maincpu.h"
54 #include "mem.h"
55 #include "monitor.h"
56 #include "plus256k.h"
57 #include "plus60k.h"
58 #include "ram.h"
59 #include "resources.h"
60 #include "reu.h"
61 #include "sid.h"
62 #include "tpi.h"
63 #include "vicii-mem.h"
64 #include "vicii-phi1.h"
65 #include "vicii.h"
66 
67 /* Machine class (moved from c64.c to distinguish between x64 and x64sc) */
68 int machine_class = VICE_MACHINE_C64;
69 
70 /* C64 memory-related resources.  */
71 
72 /* ------------------------------------------------------------------------- */
73 
74 /* Number of possible memory configurations.  */
75 #define NUM_CONFIGS     32
76 
77 /* Number of possible video banks (16K each).  */
78 #define NUM_VBANKS      4
79 
80 /* The C64 memory.  */
81 uint8_t mem_ram[C64_RAM_SIZE];
82 
83 #ifdef USE_EMBEDDED
84 #include "c64chargen.h"
85 #else
86 uint8_t mem_chargen_rom[C64_CHARGEN_ROM_SIZE];
87 #endif
88 
89 /* Internal color memory.  */
90 static uint8_t mem_color_ram[0x400];
91 uint8_t *mem_color_ram_cpu, *mem_color_ram_vicii;
92 
93 /* Pointer to the chargen ROM.  */
94 uint8_t *mem_chargen_rom_ptr;
95 
96 /* Pointers to the currently used memory read and write tables.  */
97 read_func_ptr_t *_mem_read_tab_ptr;
98 store_func_ptr_t *_mem_write_tab_ptr;
99 static uint8_t **_mem_read_base_tab_ptr;
100 static uint32_t *mem_read_limit_tab_ptr;
101 
102 /* Memory read and write tables.  */
103 static store_func_ptr_t mem_write_tab[NUM_VBANKS][NUM_CONFIGS][0x101];
104 static read_func_ptr_t mem_read_tab[NUM_CONFIGS][0x101];
105 static uint8_t *mem_read_base_tab[NUM_CONFIGS][0x101];
106 static uint32_t mem_read_limit_tab[NUM_CONFIGS][0x101];
107 
108 static store_func_ptr_t mem_write_tab_watch[0x101];
109 static read_func_ptr_t mem_read_tab_watch[0x101];
110 
111 /* Current video bank (0, 1, 2 or 3).  */
112 static int vbank;
113 
114 /* Current memory configuration.  */
115 static int mem_config;
116 
117 /* Tape sense status: 1 = some button pressed, 0 = no buttons pressed.  */
118 static int tape_sense = 0;
119 
120 static int tape_write_in = 0;
121 static int tape_motor_in = 0;
122 
123 /* Current watchpoint state. 1 = watchpoints active, 0 = no watchpoints */
124 static int watchpoints_active;
125 
126 /* ------------------------------------------------------------------------- */
127 
zero_read_watch(uint16_t addr)128 static uint8_t zero_read_watch(uint16_t addr)
129 {
130     addr &= 0xff;
131     monitor_watch_push_load_addr(addr, e_comp_space);
132     return mem_read_tab[mem_config][0](addr);
133 }
134 
zero_store_watch(uint16_t addr,uint8_t value)135 static void zero_store_watch(uint16_t addr, uint8_t value)
136 {
137     addr &= 0xff;
138     monitor_watch_push_store_addr(addr, e_comp_space);
139     mem_write_tab[vbank][mem_config][0](addr, value);
140 }
141 
read_watch(uint16_t addr)142 static uint8_t read_watch(uint16_t addr)
143 {
144     monitor_watch_push_load_addr(addr, e_comp_space);
145     return mem_read_tab[mem_config][addr >> 8](addr);
146 }
147 
store_watch(uint16_t addr,uint8_t value)148 static void store_watch(uint16_t addr, uint8_t value)
149 {
150     monitor_watch_push_store_addr(addr, e_comp_space);
151     mem_write_tab[vbank][mem_config][addr >> 8](addr, value);
152 }
153 
mem_toggle_watchpoints(int flag,void * context)154 void mem_toggle_watchpoints(int flag, void *context)
155 {
156     if (flag) {
157         _mem_read_tab_ptr = mem_read_tab_watch;
158         _mem_write_tab_ptr = mem_write_tab_watch;
159     } else {
160         _mem_read_tab_ptr = mem_read_tab[mem_config];
161         _mem_write_tab_ptr = mem_write_tab[vbank][mem_config];
162     }
163     watchpoints_active = flag;
164 }
165 
166 /* ------------------------------------------------------------------------- */
167 
168 /* $00/$01 unused bits emulation
169 
170    - There are 2 different unused bits, 1) the output bits, 2) the input bits
171    - The output bits can be (re)set when the data-direction is set to output
172      for those bits and the output bits will not drop-off to 0.
173    - When the data-direction for the unused bits is set to output then the
174      unused input bits can be (re)set by writing to them, when set to 1 the
175      drop-off timer will start which will cause the unused input bits to drop
176      down to 0 in a certain amount of time.
177    - When an unused input bit already had the drop-off timer running, and is
178      set to 1 again, the drop-off timer will restart.
179    - when a an unused bit changes from output to input, and the current output
180      bit is 1, the drop-off timer will restart again
181 
182     see testprogs/CPU/cpuport for details and tests
183 */
184 
clk_overflow_callback(CLOCK sub,void * unused_data)185 static void clk_overflow_callback(CLOCK sub, void *unused_data)
186 {
187     if (pport.data_set_clk_bit6 > (CLOCK)0) {
188         pport.data_set_clk_bit6 -= sub;
189     }
190     if (pport.data_falloff_bit6 && (pport.data_set_clk_bit6 < maincpu_clk)) {
191         pport.data_falloff_bit6 = 0;
192         pport.data_set_bit6 = 0;
193     }
194     if (pport.data_set_clk_bit7 > (CLOCK)0) {
195         pport.data_set_clk_bit7 -= sub;
196     }
197     if (pport.data_falloff_bit7 && (pport.data_set_clk_bit7 < maincpu_clk)) {
198         pport.data_falloff_bit7 = 0;
199         pport.data_set_bit7 = 0;
200     }
201 }
202 
c64_mem_init(void)203 void c64_mem_init(void)
204 {
205     clk_guard_add_callback(maincpu_clk_guard, clk_overflow_callback, NULL);
206 }
207 
mem_pla_config_changed(void)208 void mem_pla_config_changed(void)
209 {
210     mem_config = (((~pport.dir | pport.data) & 0x7) | (export.exrom << 3) | (export.game << 4));
211 
212     c64pla_config_changed(tape_sense, tape_write_in, tape_motor_in, 1, 0x17);
213 
214     if (watchpoints_active) {
215         _mem_read_tab_ptr = mem_read_tab_watch;
216         _mem_write_tab_ptr = mem_write_tab_watch;
217     } else {
218         _mem_read_tab_ptr = mem_read_tab[mem_config];
219         _mem_write_tab_ptr = mem_write_tab[vbank][mem_config];
220     }
221 
222     _mem_read_base_tab_ptr = mem_read_base_tab[mem_config];
223     mem_read_limit_tab_ptr = mem_read_limit_tab[mem_config];
224 
225     maincpu_resync_limits();
226 }
227 
zero_read(uint16_t addr)228 uint8_t zero_read(uint16_t addr)
229 {
230     uint8_t retval;
231 
232     addr &= 0xff;
233 #ifdef FEATURE_CPUMEMHISTORY
234     if (!(memmap_state & MEMMAP_STATE_IGNORE)) {
235         monitor_memmap_store(addr, (memmap_state & MEMMAP_STATE_OPCODE) ? MEMMAP_RAM_X : (memmap_state & MEMMAP_STATE_INSTR) ? 0 : MEMMAP_RAM_R);
236         memmap_state &= ~(MEMMAP_STATE_OPCODE);
237     }
238 #endif
239     switch ((uint8_t)addr) {
240         case 0:
241             return pport.dir_read;
242         case 1:
243             retval = pport.data_read;
244 
245             /* discharge the "capacitor" */
246 
247             /* set real value of read bit 6 */
248             if (pport.data_falloff_bit6 && (pport.data_set_clk_bit6 < maincpu_clk)) {
249                 pport.data_falloff_bit6 = 0;
250                 pport.data_set_bit6 = 0;
251             }
252 
253             /* set real value of read bit 7 */
254             if (pport.data_falloff_bit7 && (pport.data_set_clk_bit7 < maincpu_clk)) {
255                 pport.data_falloff_bit7 = 0;
256                 pport.data_set_bit7 = 0;
257             }
258 
259             /* for unused bits in input mode, the value comes from the "capacitor" */
260 
261             /* set real value of bit 6 */
262             if (!(pport.dir_read & 0x40)) {
263                 retval &= ~0x40;
264                 retval |= pport.data_set_bit6;
265             }
266 
267             /* set real value of bit 7 */
268             if (!(pport.dir_read & 0x80)) {
269                 retval &= ~0x80;
270                 retval |= pport.data_set_bit7;
271             }
272 
273             return retval;
274     }
275 
276     if (c64_256k_enabled) {
277         return c64_256k_ram_segment0_read(addr);
278     } else {
279         if (plus256k_enabled) {
280             return plus256k_ram_low_read(addr);
281         } else {
282             return mem_ram[addr & 0xff];
283         }
284     }
285 }
286 
zero_store(uint16_t addr,uint8_t value)287 void zero_store(uint16_t addr, uint8_t value)
288 {
289     addr &= 0xff;
290 #ifdef FEATURE_CPUMEMHISTORY
291     monitor_memmap_store(addr, MEMMAP_RAM_W);
292 #endif
293     switch ((uint8_t)addr) {
294         case 0:
295             if (vbank == 0) {
296                 if (c64_256k_enabled) {
297                     c64_256k_ram_segment0_store((uint16_t)0, vicii_read_phi1_lowlevel());
298                 } else {
299                     if (plus256k_enabled) {
300                         plus256k_ram_low_store((uint16_t)0, vicii_read_phi1_lowlevel());
301                     } else {
302                         vicii_mem_vbank_store((uint16_t)0, vicii_read_phi1_lowlevel());
303                     }
304                 }
305             } else {
306                 mem_ram[0] = vicii_read_phi1_lowlevel();
307                 machine_handle_pending_alarms(maincpu_rmw_flag + 1);
308             }
309             /* when switching an unused bit from output (where it contained a
310                stable value) to input mode (where the input is floating), some
311                of the charge is transferred to the floating input */
312 
313             /* check if bit 6 has flipped */
314             if ((pport.dir & 0x40)) {
315                 if ((pport.dir ^ value) & 0x40) {
316                     pport.data_set_clk_bit6 = maincpu_clk + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES;
317                     pport.data_set_bit6 = pport.data & 0x40;
318                     pport.data_falloff_bit6 = 1;
319                 }
320             }
321 
322             /* check if bit 7 has flipped */
323             if ((pport.dir & 0x80)) {
324                 if ((pport.dir ^ value) & 0x80) {
325                     pport.data_set_clk_bit7 = maincpu_clk + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES;
326                     pport.data_set_bit7 = pport.data & 0x80;
327                     pport.data_falloff_bit7 = 1;
328                 }
329             }
330 
331             if (pport.dir != value) {
332                 pport.dir = value;
333                 mem_pla_config_changed();
334             }
335             break;
336         case 1:
337             if (vbank == 0) {
338                 if (c64_256k_enabled) {
339                     c64_256k_ram_segment0_store((uint16_t)1, vicii_read_phi1_lowlevel());
340                 } else {
341                     if (plus256k_enabled) {
342                         plus256k_ram_low_store((uint16_t)1, vicii_read_phi1_lowlevel());
343                     } else {
344                         vicii_mem_vbank_store((uint16_t)1, vicii_read_phi1_lowlevel());
345                     }
346                 }
347             } else {
348                 mem_ram[1] = vicii_read_phi1_lowlevel();
349                 machine_handle_pending_alarms(maincpu_rmw_flag + 1);
350             }
351 
352             /* when writing to an unused bit that is output, charge the "capacitor",
353                otherwise don't touch it */
354             if (pport.dir & 0x80) {
355                 pport.data_set_bit7 = value & 0x80;
356                 pport.data_set_clk_bit7 = maincpu_clk + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES;
357                 pport.data_falloff_bit7 = 1;
358             }
359 
360             if (pport.dir & 0x40) {
361                 pport.data_set_bit6 = value & 0x40;
362                 pport.data_set_clk_bit6 = maincpu_clk + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES;
363                 pport.data_falloff_bit6 = 1;
364             }
365 
366             if (pport.data != value) {
367                 pport.data = value;
368                 mem_pla_config_changed();
369             }
370             break;
371         default:
372             if (vbank == 0) {
373                 if (c64_256k_enabled) {
374                     c64_256k_ram_segment0_store(addr, value);
375                 } else {
376                     if (plus256k_enabled) {
377                         plus256k_ram_low_store(addr, value);
378                     } else {
379                         vicii_mem_vbank_store(addr, value);
380                     }
381                 }
382             } else {
383                 mem_ram[addr] = value;
384             }
385     }
386 }
387 
388 /* ------------------------------------------------------------------------- */
389 
chargen_read(uint16_t addr)390 uint8_t chargen_read(uint16_t addr)
391 {
392     return mem_chargen_rom[addr & 0xfff];
393 }
394 
chargen_store(uint16_t addr,uint8_t value)395 void chargen_store(uint16_t addr, uint8_t value)
396 {
397     mem_chargen_rom[addr & 0xfff] = value;
398 }
399 
ram_read(uint16_t addr)400 uint8_t ram_read(uint16_t addr)
401 {
402     return mem_ram[addr];
403 }
404 
ram_store(uint16_t addr,uint8_t value)405 void ram_store(uint16_t addr, uint8_t value)
406 {
407     mem_ram[addr] = value;
408 }
409 
ram_hi_store(uint16_t addr,uint8_t value)410 void ram_hi_store(uint16_t addr, uint8_t value)
411 {
412     if (vbank == 3) {
413         vicii_mem_vbank_3fxx_store(addr, value);
414     } else {
415         mem_ram[addr] = value;
416     }
417 
418     if (addr == 0xff00) {
419         reu_dma(-1);
420     }
421 }
422 
423 /* unconnected memory space */
void_read(uint16_t addr)424 static uint8_t void_read(uint16_t addr)
425 {
426     return vicii_read_phi1();
427 }
428 
void_store(uint16_t addr,uint8_t value)429 static void void_store(uint16_t addr, uint8_t value)
430 {
431     return;
432 }
433 
434 /* ------------------------------------------------------------------------- */
435 
436 /* Generic memory access.  */
437 
mem_store(uint16_t addr,uint8_t value)438 void mem_store(uint16_t addr, uint8_t value)
439 {
440     _mem_write_tab_ptr[addr >> 8](addr, value);
441 }
442 
mem_read(uint16_t addr)443 uint8_t mem_read(uint16_t addr)
444 {
445     return _mem_read_tab_ptr[addr >> 8](addr);
446 }
447 
mem_store_without_ultimax(uint16_t addr,uint8_t value)448 void mem_store_without_ultimax(uint16_t addr, uint8_t value)
449 {
450     store_func_ptr_t *write_tab_ptr;
451 
452     write_tab_ptr = mem_write_tab[vbank][mem_config & 7];
453 
454     write_tab_ptr[addr >> 8](addr, value);
455 }
456 
mem_read_without_ultimax(uint16_t addr)457 uint8_t mem_read_without_ultimax(uint16_t addr)
458 {
459     read_func_ptr_t *read_tab_ptr;
460 
461     read_tab_ptr = mem_read_tab[mem_config & 7];
462 
463     return read_tab_ptr[addr >> 8](addr);
464 }
465 
mem_store_without_romlh(uint16_t addr,uint8_t value)466 void mem_store_without_romlh(uint16_t addr, uint8_t value)
467 {
468     store_func_ptr_t *write_tab_ptr;
469 
470     write_tab_ptr = mem_write_tab[vbank][0];
471 
472     write_tab_ptr[addr >> 8](addr, value);
473 }
474 
475 /* ------------------------------------------------------------------------- */
476 
colorram_store(uint16_t addr,uint8_t value)477 void colorram_store(uint16_t addr, uint8_t value)
478 {
479     mem_color_ram[addr & 0x3ff] = value & 0xf;
480 }
481 
colorram_read(uint16_t addr)482 uint8_t colorram_read(uint16_t addr)
483 {
484     return mem_color_ram[addr & 0x3ff] | (vicii_read_phi1() & 0xf0);
485 }
486 
487 /* ------------------------------------------------------------------------- */
488 
489 /* init 256k memory table changes */
490 /* FIXME: make sure all cartridge related callbacks are hooked correctly */
check_256k_ram_write(int k,int i,int j)491 static int check_256k_ram_write(int k, int i, int j)
492 {
493     if (mem_write_tab[k][i][j] == vicii_mem_vbank_39xx_store) {
494         return 1;
495     }
496     if (mem_write_tab[k][i][j] == vicii_mem_vbank_3fxx_store) {
497         return 1;
498     }
499     if (mem_write_tab[k][i][j] == vicii_mem_vbank_store) {
500         return 1;
501     }
502     if (mem_write_tab[k][i][j] == ram_hi_store) {
503         return 1;
504     }
505     if (mem_write_tab[k][i][j] == ram_store) {
506         return 1;
507     }
508     if (mem_write_tab[k][i][j] == raml_no_ultimax_store) { /* possibly breaks mmc64 and expert */
509         return 1;
510     }
511     if (mem_write_tab[k][i][j] == romh_no_ultimax_store) { /* possibly breaks mmc64 and expert */
512         return 1;
513     }
514     if (mem_write_tab[k][i][j] == ramh_no_ultimax_store) { /* possibly breaks mmc64 and expert */
515         return 1;
516     }
517     if (mem_write_tab[k][i][j] == romh_store) {
518         return 1;
519     }
520     return 0;
521 }
522 
c64_256k_init_config(void)523 static void c64_256k_init_config(void)
524 {
525     int i, j, k;
526 
527     if (c64_256k_enabled) {
528         mem_limit_256k_init(mem_read_limit_tab);
529         for (i = 0; i < NUM_CONFIGS; i++) {
530             for (j = 1; j <= 0xff; j++) {
531                 for (k = 0; k < NUM_VBANKS; k++) {
532                     if (check_256k_ram_write(k, i, j) == 1) {
533                         if (j < 0x40) {
534                             mem_write_tab[k][i][j] = c64_256k_ram_segment0_store;
535                         }
536                         if (j > 0x3f && j < 0x80) {
537                             mem_write_tab[k][i][j] = c64_256k_ram_segment1_store;
538                         }
539                         if (j > 0x7f && j < 0xc0) {
540                             mem_write_tab[k][i][j] = c64_256k_ram_segment2_store;
541                         }
542                         if (j > 0xbf) {
543                             mem_write_tab[k][i][j] = c64_256k_ram_segment3_store;
544                         }
545                     }
546                 }
547                 if (mem_read_tab[i][j] == ram_read) {
548                     if (j < 0x40) {
549                         mem_read_tab[i][j] = c64_256k_ram_segment0_read;
550                     }
551                     if (j > 0x3f && j < 0x80) {
552                         mem_read_tab[i][j] = c64_256k_ram_segment1_read;
553                     }
554                     if (j > 0x7f && j < 0xc0) {
555                         mem_read_tab[i][j] = c64_256k_ram_segment2_read;
556                     }
557                     if (j > 0xbf) {
558                         mem_read_tab[i][j] = c64_256k_ram_segment3_read;
559                     }
560                 }
561             }
562         }
563     }
564 }
565 
566 /* ------------------------------------------------------------------------- */
567 
568 /* init plus256k memory table changes */
569 /* FIXME: make sure all cartridge related callbacks are hooked correctly */
plus256k_init_config(void)570 static void plus256k_init_config(void)
571 {
572     int i, j, k;
573 
574     if (plus256k_enabled) {
575         mem_limit_256k_init(mem_read_limit_tab);
576         for (i = 0; i < NUM_CONFIGS; i++) {
577             for (j = 1; j <= 0xff; j++) {
578                 for (k = 0; k < NUM_VBANKS; k++) {
579                     if (check_256k_ram_write(k, i, j) == 1) {
580                         if (j < 0x10) {
581                             mem_write_tab[k][i][j] = plus256k_ram_low_store;
582                         } else {
583                             mem_write_tab[k][i][j] = plus256k_ram_high_store;
584                         }
585                     }
586                 }
587                 if (mem_read_tab[i][j] == ram_read) {
588                     if (j < 0x10) {
589                         mem_read_tab[i][j] = plus256k_ram_low_read;
590                     } else {
591                         mem_read_tab[i][j] = plus256k_ram_high_read;
592                     }
593                 }
594             }
595         }
596     }
597 }
598 
599 /* init plus60k memory table changes */
600 /* FIXME: make sure all cartridge related callbacks are hooked correctly */
plus60k_init_config(void)601 static void plus60k_init_config(void)
602 {
603     int i, j, k;
604 
605     if (plus60k_enabled) {
606         mem_limit_plus60k_init(mem_read_limit_tab);
607         for (i = 0; i < NUM_CONFIGS; i++) {
608             for (j = 0x10; j <= 0xff; j++) {
609                 for (k = 0; k < NUM_VBANKS; k++) {
610                     if (mem_write_tab[k][i][j] == vicii_mem_vbank_39xx_store) {
611                         mem_write_tab[k][i][j] = plus60k_vicii_mem_vbank_39xx_store;
612                     }
613                     if (mem_write_tab[k][i][j] == vicii_mem_vbank_3fxx_store) {
614                         mem_write_tab[k][i][j] = plus60k_vicii_mem_vbank_3fxx_store;
615                     }
616                     if (mem_write_tab[k][i][j] == vicii_mem_vbank_store) {
617                         mem_write_tab[k][i][j] = plus60k_vicii_mem_vbank_store;
618                     }
619                     if (mem_write_tab[k][i][j] == ram_hi_store) {
620                         mem_write_tab[k][i][j] = plus60k_ram_hi_store;
621                     }
622                     if (mem_write_tab[k][i][j] == ram_store) {
623                         mem_write_tab[k][i][j] = plus60k_ram_store;
624                     }
625                     if (mem_write_tab[k][i][j] == raml_no_ultimax_store) {
626                         mem_write_tab[k][i][j] = plus60k_ram_store; /* possibly breaks mmc64 and expert */
627                     }
628                     if (mem_write_tab[k][i][j] == romh_no_ultimax_store) {
629                         mem_write_tab[k][i][j] = plus60k_ram_store; /* possibly breaks mmc64 and expert */
630                     }
631                     if (mem_write_tab[k][i][j] == ramh_no_ultimax_store) {
632                         mem_write_tab[k][i][j] = plus60k_ram_store; /* possibly breaks mmc64 and expert */
633                     }
634                     if (mem_write_tab[k][i][j] == romh_store) {
635                         mem_write_tab[k][i][j] = plus60k_ram_store;
636                     }
637                 }
638                 if (mem_read_tab[i][j] == ram_read) {
639                     mem_read_tab[i][j] = plus60k_ram_read;
640                 }
641             }
642         }
643     }
644 }
645 
646 /* ------------------------------------------------------------------------- */
647 
mem_set_write_hook(int config,int page,store_func_t * f)648 void mem_set_write_hook(int config, int page, store_func_t *f)
649 {
650     int i;
651 
652     for (i = 0; i < NUM_VBANKS; i++) {
653         mem_write_tab[i][config][page] = f;
654     }
655 }
656 
mem_read_tab_set(unsigned int base,unsigned int index,read_func_ptr_t read_func)657 void mem_read_tab_set(unsigned int base, unsigned int index, read_func_ptr_t read_func)
658 {
659     mem_read_tab[base][index] = read_func;
660 }
661 
mem_read_base_set(unsigned int base,unsigned int index,uint8_t * mem_ptr)662 void mem_read_base_set(unsigned int base, unsigned int index, uint8_t *mem_ptr)
663 {
664     mem_read_base_tab[base][index] = mem_ptr;
665 }
666 
mem_initialize_memory(void)667 void mem_initialize_memory(void)
668 {
669     int i, j, k;
670     int board;
671 
672     mem_chargen_rom_ptr = mem_chargen_rom;
673     mem_color_ram_cpu = mem_color_ram;
674     mem_color_ram_vicii = mem_color_ram;
675 
676     mem_limit_init(mem_read_limit_tab);
677 
678     /* setup watchpoint tables */
679     mem_read_tab_watch[0] = zero_read_watch;
680     mem_write_tab_watch[0] = zero_store_watch;
681     for (i = 1; i <= 0x100; i++) {
682         mem_read_tab_watch[i] = read_watch;
683         mem_write_tab_watch[i] = store_watch;
684     }
685 
686     resources_get_int("BoardType", &board);
687 
688     /* Default is RAM.  */
689     for (i = 0; i < NUM_CONFIGS; i++) {
690         mem_set_write_hook(i, 0, zero_store);
691         mem_read_tab[i][0] = zero_read;
692         mem_read_base_tab[i][0] = mem_ram;
693         for (j = 1; j <= 0xfe; j++) {
694             if (board == 1 && j >= 0x08) {
695                 mem_read_tab[i][j] = void_read;
696                 mem_read_base_tab[i][j] = NULL;
697                 mem_set_write_hook(0, j, void_store);
698                 continue;
699             }
700             mem_read_tab[i][j] = ram_read;
701             mem_read_base_tab[i][j] = mem_ram;
702             for (k = 0; k < NUM_VBANKS; k++) {
703                 if ((j & 0xc0) == (k << 6)) {
704                     switch (j & 0x3f) {
705                         case 0x39:
706                             mem_write_tab[k][i][j] = vicii_mem_vbank_39xx_store;
707                             break;
708                         case 0x3f:
709                             mem_write_tab[k][i][j] = vicii_mem_vbank_3fxx_store;
710                             break;
711                         default:
712                             mem_write_tab[k][i][j] = vicii_mem_vbank_store;
713                     }
714                 } else {
715                     mem_write_tab[k][i][j] = ram_store;
716                 }
717             }
718         }
719         if (board == 1) {
720             mem_read_tab[i][0xff] = void_read;
721             mem_read_base_tab[i][0xff] = NULL;
722             mem_set_write_hook(0, 0xff, void_store);
723         } else {
724             mem_read_tab[i][0xff] = ram_read;
725             mem_read_base_tab[i][0xff] = mem_ram;
726 
727             /* vbank access is handled within `ram_hi_store()'.  */
728             mem_set_write_hook(i, 0xff, ram_hi_store);
729         }
730     }
731 
732     /* Setup character generator ROM at $D000-$DFFF (memory configs 1, 2, 3, 9, 10, 11, 26, 27).  */
733     for (i = 0xd0; i <= 0xdf; i++) {
734         mem_read_tab[1][i] = chargen_read;
735         mem_read_tab[2][i] = chargen_read;
736         mem_read_tab[3][i] = chargen_read;
737         mem_read_tab[9][i] = chargen_read;
738         mem_read_tab[10][i] = chargen_read;
739         mem_read_tab[11][i] = chargen_read;
740         mem_read_tab[26][i] = chargen_read;
741         mem_read_tab[27][i] = chargen_read;
742         mem_read_base_tab[1][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000);
743         mem_read_base_tab[2][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000);
744         mem_read_base_tab[3][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000);
745         mem_read_base_tab[9][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000);
746         mem_read_base_tab[10][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000);
747         mem_read_base_tab[11][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000);
748         mem_read_base_tab[26][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000);
749         mem_read_base_tab[27][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000);
750     }
751 
752     c64meminit(0);
753 
754     for (i = 0; i < NUM_CONFIGS; i++) {
755         mem_read_tab[i][0x100] = mem_read_tab[i][0];
756         for (j = 0; j < NUM_VBANKS; j++) {
757             mem_write_tab[j][i][0x100] = mem_write_tab[j][i][0];
758         }
759         mem_read_base_tab[i][0x100] = mem_read_base_tab[i][0];
760     }
761 
762     _mem_read_tab_ptr = mem_read_tab[7];
763     _mem_write_tab_ptr = mem_write_tab[vbank][7];
764     _mem_read_base_tab_ptr = mem_read_base_tab[7];
765     mem_read_limit_tab_ptr = mem_read_limit_tab[7];
766 
767     vicii_set_chargen_addr_options(0x7000, 0x1000);
768 
769     c64pla_pport_reset();
770     export.exrom = 0;
771     export.game = 0;
772 
773     /* Setup initial memory configuration.  */
774     mem_pla_config_changed();
775     cartridge_init_config();
776     /* internal expansions, these may modify the above mappings and must take
777        care of hooking up all callbacks correctly.
778     */
779     plus60k_init_config();
780     plus256k_init_config();
781     c64_256k_init_config();
782 
783     if (board == 1) {
784         mem_limit_max_init(mem_read_limit_tab);
785     }
786 }
787 
mem_mmu_translate(unsigned int addr,uint8_t ** base,int * start,int * limit)788 void mem_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit)
789 {
790     uint8_t *p = _mem_read_base_tab_ptr[addr >> 8];
791     uint32_t limits;
792 
793     if (p != NULL && addr > 1) {
794         *base = p;
795         limits = mem_read_limit_tab_ptr[addr >> 8];
796         *limit = limits & 0xffff;
797         *start = limits >> 16;
798     } else {
799         cartridge_mmu_translate(addr, base, start, limit);
800     }
801 }
802 
803 /* ------------------------------------------------------------------------- */
804 
805 /* Initialize RAM for power-up.  */
mem_powerup(void)806 void mem_powerup(void)
807 {
808     ram_init(mem_ram, 0x10000);
809     cartridge_ram_init();  /* Clean cartridge ram too */
810 }
811 
812 /* ------------------------------------------------------------------------- */
813 
814 /* Change the current video bank.  Call this routine only when the vbank
815    has really changed.  */
mem_set_vbank(int new_vbank)816 void mem_set_vbank(int new_vbank)
817 {
818     vbank = new_vbank;
819 
820     /* Do not override watchpoints on vbank switches.  */
821     if (_mem_write_tab_ptr != mem_write_tab_watch) {
822         _mem_write_tab_ptr = mem_write_tab[new_vbank][mem_config];
823     }
824 
825     vicii_set_vbank(new_vbank);
826 }
827 
828 /* Set the tape sense status.  */
mem_set_tape_sense(int sense)829 void mem_set_tape_sense(int sense)
830 {
831     tape_sense = sense;
832     mem_pla_config_changed();
833 }
834 
835 /* Set the tape write in.  */
mem_set_tape_write_in(int val)836 void mem_set_tape_write_in(int val)
837 {
838     tape_write_in = val;
839     mem_pla_config_changed();
840 }
841 
842 /* Set the tape motor in.  */
mem_set_tape_motor_in(int val)843 void mem_set_tape_motor_in(int val)
844 {
845     tape_motor_in = val;
846     mem_pla_config_changed();
847 }
848 
849 /* ------------------------------------------------------------------------- */
850 
851 /* FIXME: this part needs to be checked.  */
852 
mem_get_basic_text(uint16_t * start,uint16_t * end)853 void mem_get_basic_text(uint16_t *start, uint16_t *end)
854 {
855     if (start != NULL) {
856         *start = mem_ram[0x2b] | (mem_ram[0x2c] << 8);
857     }
858     if (end != NULL) {
859         *end = mem_ram[0x2d] | (mem_ram[0x2e] << 8);
860     }
861 }
862 
mem_set_basic_text(uint16_t start,uint16_t end)863 void mem_set_basic_text(uint16_t start, uint16_t end)
864 {
865     mem_ram[0x2b] = mem_ram[0xac] = start & 0xff;
866     mem_ram[0x2c] = mem_ram[0xad] = start >> 8;
867     mem_ram[0x2d] = mem_ram[0x2f] = mem_ram[0x31] = mem_ram[0xae] = end & 0xff;
868     mem_ram[0x2e] = mem_ram[0x30] = mem_ram[0x32] = mem_ram[0xaf] = end >> 8;
869 }
870 
mem_inject(uint32_t addr,uint8_t value)871 void mem_inject(uint32_t addr, uint8_t value)
872 {
873     /* could be made to handle various internal expansions in some sane way */
874     mem_ram[addr & 0xffff] = value;
875 }
876 
877 /* ------------------------------------------------------------------------- */
878 
mem_rom_trap_allowed(uint16_t addr)879 int mem_rom_trap_allowed(uint16_t addr)
880 {
881     if (addr >= 0xe000) {
882         switch (mem_config) {
883             case 2:
884             case 3:
885             case 6:
886             case 7:
887             case 10:
888             case 11:
889             case 14:
890             case 15:
891             case 26:
892             case 27:
893             case 30:
894             case 31:
895                 return 1;
896             default:
897                 return 0;
898         }
899     }
900 
901     return 0;
902 }
903 
904 /* ------------------------------------------------------------------------- */
905 
906 /* Banked memory access functions for the monitor.  */
907 
store_bank_io(uint16_t addr,uint8_t byte)908 void store_bank_io(uint16_t addr, uint8_t byte)
909 {
910     switch (addr & 0xff00) {
911         case 0xd000:
912             c64io_d000_store(addr, byte);
913             break;
914         case 0xd100:
915             c64io_d100_store(addr, byte);
916             break;
917         case 0xd200:
918             c64io_d200_store(addr, byte);
919             break;
920         case 0xd300:
921             c64io_d300_store(addr, byte);
922             break;
923         case 0xd400:
924             c64io_d400_store(addr, byte);
925             break;
926         case 0xd500:
927             c64io_d500_store(addr, byte);
928             break;
929         case 0xd600:
930             c64io_d600_store(addr, byte);
931             break;
932         case 0xd700:
933             c64io_d700_store(addr, byte);
934             break;
935         case 0xd800:
936         case 0xd900:
937         case 0xda00:
938         case 0xdb00:
939             colorram_store(addr, byte);
940             break;
941         case 0xdc00:
942             cia1_store(addr, byte);
943             break;
944         case 0xdd00:
945             cia2_store(addr, byte);
946             break;
947         case 0xde00:
948             c64io_de00_store(addr, byte);
949             break;
950         case 0xdf00:
951             c64io_df00_store(addr, byte);
952             break;
953     }
954     return;
955 }
956 
read_bank_io(uint16_t addr)957 uint8_t read_bank_io(uint16_t addr)
958 {
959     switch (addr & 0xff00) {
960         case 0xd000:
961             return c64io_d000_read(addr);
962         case 0xd100:
963             return c64io_d100_read(addr);
964         case 0xd200:
965             return c64io_d200_read(addr);
966         case 0xd300:
967             return c64io_d300_read(addr);
968         case 0xd400:
969             return c64io_d400_read(addr);
970         case 0xd500:
971             return c64io_d500_read(addr);
972         case 0xd600:
973             return c64io_d600_read(addr);
974         case 0xd700:
975             return c64io_d700_read(addr);
976         case 0xd800:
977         case 0xd900:
978         case 0xda00:
979         case 0xdb00:
980             return colorram_read(addr);
981         case 0xdc00:
982             return cia1_read(addr);
983         case 0xdd00:
984             return cia2_read(addr);
985         case 0xde00:
986             return c64io_de00_read(addr);
987         case 0xdf00:
988             return c64io_df00_read(addr);
989     }
990     return 0xff;
991 }
992 
peek_bank_io(uint16_t addr)993 static uint8_t peek_bank_io(uint16_t addr)
994 {
995     switch (addr & 0xff00) {
996         case 0xd000:
997             return c64io_d000_peek(addr);
998         case 0xd100:
999             return c64io_d100_peek(addr);
1000         case 0xd200:
1001             return c64io_d200_peek(addr);
1002         case 0xd300:
1003             return c64io_d300_peek(addr);
1004         case 0xd400:
1005             return c64io_d400_peek(addr);
1006         case 0xd500:
1007             return c64io_d500_peek(addr);
1008         case 0xd600:
1009             return c64io_d600_peek(addr);
1010         case 0xd700:
1011             return c64io_d700_peek(addr);
1012         case 0xd800:
1013         case 0xd900:
1014         case 0xda00:
1015         case 0xdb00:
1016             return colorram_read(addr);
1017         case 0xdc00:
1018             return cia1_peek(addr);
1019         case 0xdd00:
1020             return cia2_peek(addr);
1021         case 0xde00:
1022             return c64io_de00_peek(addr);
1023         case 0xdf00:
1024             return c64io_df00_peek(addr);
1025     }
1026     return 0xff;
1027 }
1028 
1029 /* ------------------------------------------------------------------------- */
1030 
1031 /* Exported banked memory access functions for the monitor.  */
1032 
1033 static const char *banknames[] = {
1034     "default",
1035     "cpu",
1036     "ram",
1037     "rom",
1038     "io",
1039     "cart",
1040     NULL
1041 };
1042 
1043 static const int banknums[] = { 1, 0, 1, 2, 3, 4 };
1044 
mem_bank_list(void)1045 const char **mem_bank_list(void)
1046 {
1047     return banknames;
1048 }
1049 
mem_bank_from_name(const char * name)1050 int mem_bank_from_name(const char *name)
1051 {
1052     int i = 0;
1053 
1054     while (banknames[i]) {
1055         if (!strcmp(name, banknames[i])) {
1056             return banknums[i];
1057         }
1058         i++;
1059     }
1060     return -1;
1061 }
1062 
1063 /* read memory with side-effects */
mem_bank_read(int bank,uint16_t addr,void * context)1064 uint8_t mem_bank_read(int bank, uint16_t addr, void *context)
1065 {
1066     switch (bank) {
1067         case 0:                   /* current */
1068             return mem_read(addr);
1069             break;
1070         case 3:                   /* io */
1071             if (addr >= 0xd000 && addr < 0xe000) {
1072                 return read_bank_io(addr);
1073             }
1074             /* FALL THROUGH */
1075         case 4:                   /* cart */
1076             return cartridge_peek_mem(addr);
1077         case 2:                   /* rom */
1078             if (addr >= 0xa000 && addr <= 0xbfff) {
1079                 return c64memrom_basic64_rom[addr & 0x1fff];
1080             }
1081             if (addr >= 0xd000 && addr <= 0xdfff) {
1082                 return mem_chargen_rom[addr & 0x0fff];
1083             }
1084             if (addr >= 0xe000) {
1085                 return c64memrom_kernal64_rom[addr & 0x1fff];
1086             }
1087             /* FALL THROUGH */
1088         case 1:                   /* ram */
1089             break;
1090     }
1091     return mem_ram[addr];
1092 }
1093 
1094 /* read memory without side-effects */
mem_bank_peek(int bank,uint16_t addr,void * context)1095 uint8_t mem_bank_peek(int bank, uint16_t addr, void *context)
1096 {
1097     switch (bank) {
1098         case 0:                   /* current */
1099             /* we must check for which bank is currently active, and only use peek_bank_io
1100                when needed to avoid side effects */
1101             if (c64meminit_io_config[mem_config]) {
1102                 if ((addr >= 0xd000) && (addr < 0xe000)) {
1103                     return peek_bank_io(addr);
1104                 }
1105             }
1106             return mem_read(addr);
1107             break;
1108         case 3:                   /* io */
1109             if ((addr >= 0xd000) && (addr < 0xe000)) {
1110                 return peek_bank_io(addr);
1111             }
1112             break;
1113         case 4:                   /* cart */
1114             return cartridge_peek_mem(addr);
1115     }
1116     return mem_bank_read(bank, addr, context);
1117 }
1118 
mem_bank_write(int bank,uint16_t addr,uint8_t byte,void * context)1119 void mem_bank_write(int bank, uint16_t addr, uint8_t byte, void *context)
1120 {
1121     switch (bank) {
1122         case 0:                   /* current */
1123             mem_store(addr, byte);
1124             return;
1125         case 3:                   /* io */
1126             if (addr >= 0xd000 && addr < 0xe000) {
1127                 store_bank_io(addr, byte);
1128                 return;
1129             }
1130             /* FALL THROUGH */
1131         case 2:                   /* rom */
1132             if (addr >= 0xa000 && addr <= 0xbfff) {
1133                 return;
1134             }
1135             if (addr >= 0xd000 && addr <= 0xdfff) {
1136                 return;
1137             }
1138             if (addr >= 0xe000) {
1139                 return;
1140             }
1141             /* FALL THROUGH */
1142         case 1:                   /* ram */
1143             break;
1144     }
1145     mem_ram[addr] = byte;
1146 }
1147 
mem_dump_io(void * context,uint16_t addr)1148 static int mem_dump_io(void *context, uint16_t addr)
1149 {
1150     if ((addr >= 0xdc00) && (addr <= 0xdc3f)) {
1151         return ciacore_dump(machine_context.cia1);
1152     } else if ((addr >= 0xdd00) && (addr <= 0xdd3f)) {
1153         return ciacore_dump(machine_context.cia2);
1154     }
1155     return -1;
1156 }
1157 
mem_ioreg_list_get(void * context)1158 mem_ioreg_list_t *mem_ioreg_list_get(void *context)
1159 {
1160     mem_ioreg_list_t *mem_ioreg_list = NULL;
1161 
1162     mon_ioreg_add_list(&mem_ioreg_list, "CIA1", 0xdc00, 0xdc0f, mem_dump_io, NULL);
1163     mon_ioreg_add_list(&mem_ioreg_list, "CIA2", 0xdd00, 0xdd0f, mem_dump_io, NULL);
1164 
1165     io_source_ioreg_add_list(&mem_ioreg_list);
1166 
1167     return mem_ioreg_list;
1168 }
1169 
mem_get_screen_parameter(uint16_t * base,uint8_t * rows,uint8_t * columns,int * bank)1170 void mem_get_screen_parameter(uint16_t *base, uint8_t *rows, uint8_t *columns, int *bank)
1171 {
1172     *base = ((vicii_peek(0xd018) & 0xf0) << 6) | ((~cia2_peek(0xdd00) & 0x03) << 14);
1173     *rows = 25;
1174     *columns = 40;
1175     *bank = 0;
1176 }
1177 
1178 /* ------------------------------------------------------------------------- */
1179 
mem_color_ram_to_snapshot(uint8_t * color_ram)1180 void mem_color_ram_to_snapshot(uint8_t *color_ram)
1181 {
1182     memcpy(color_ram, mem_color_ram, 0x400);
1183 }
1184 
mem_color_ram_from_snapshot(uint8_t * color_ram)1185 void mem_color_ram_from_snapshot(uint8_t *color_ram)
1186 {
1187     memcpy(mem_color_ram, color_ram, 0x400);
1188 }
1189 
1190 /* ------------------------------------------------------------------------- */
1191 
1192 /* UI functions (used to distinguish between x64 and x64sc) */
c64_mem_ui_init_early(void)1193 int c64_mem_ui_init_early(void)
1194 {
1195     return c64ui_init_early();
1196 }
1197 
c64_mem_ui_init(void)1198 int c64_mem_ui_init(void)
1199 {
1200     return c64ui_init();
1201 }
1202 
c64_mem_ui_shutdown(void)1203 void c64_mem_ui_shutdown(void)
1204 {
1205     c64ui_shutdown();
1206 }
1207