1 /*
2 * petmem.c - PET memory handling.
3 *
4 * Written by
5 * Ettore Perazzoli <ettore@comm2000.it>
6 * Andre Fachat <fachat@physik.tu-chemnitz.de>
7 * Andreas Boose <viceteam@t-online.de>
8 * Marco van den Heuvel <blackystardust68@yahoo.com>
9 *
10 * This file is part of VICE, the Versatile Commodore Emulator.
11 * See README for copyright notice.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 * 02111-1307 USA.
27 *
28 */
29
30 #include "vice.h"
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35
36 #include "6809.h"
37 #include "cartio.h"
38 #include "cartridge.h"
39 #include "crtc-mem.h"
40 #include "crtctypes.h"
41 #include "lib.h"
42 #include "log.h"
43 #include "machine.h"
44 #include "maincpu.h"
45 #include "mem.h"
46 #include "monitor.h"
47 #include "pet.h"
48 #include "pet-resources.h"
49 #include "petacia.h"
50 #include "petcolour.h"
51 #include "petdww.h"
52 #include "pethre.h"
53 #include "petmem.h"
54 #include "petmodel.h"
55 #include "petpia.h"
56 #include "pets.h"
57 #include "petvia.h"
58 #include "ram.h"
59 #include "resources.h"
60 #include "types.h"
61 #include "via.h"
62 #include "vsync.h"
63
64 static uint8_t mem_read_patchbuf(uint16_t addr);
65 static void mem_initialize_memory_6809_flat(void);
66
67 uint8_t petmem_2001_buf_ef[256];
68
69 /* ------------------------------------------------------------------------- */
70
71 /*
72 * We keep the current system config in here.
73 * It is initialized to defaults from the default resource values.
74 */
75
76 petres_t petres;
77
78 /* if the above is true, there's no need for this: */
79 #if 0
80 = {
81 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
82 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
83 { NULL, NULL, NULL, NULL, NULL, NULL }, /* h6809romName[] */
84 0, 0, 0, 0, 0, 0, 0, 0, 0
85 };
86 #endif
87
88 /* ------------------------------------------------------------------------- */
89
90 /* The PET memory. */
91
92 #define RAM_ARRAY 0x20000 /* this includes 8x96 expansion RAM */
93
94 uint8_t mem_ram[RAM_ARRAY]; /* 128K to make things easier. Real size is 4-128K. */
95 uint8_t mem_rom[PET_ROM_SIZE];
96 uint8_t mem_chargen_rom[PET_CHARGEN_ROM_SIZE];
97 uint8_t mem_6809rom[PET_6809_ROMSIZE];
98
99 #define EXT_RAM (64 * 1024)
100
101 static int ram_size = RAM_ARRAY; /* FIXME? */
102
103 /* Memory read and write tables. */
104 static read_func_ptr_t _mem_read_tab[0x101];
105 static store_func_ptr_t _mem_write_tab[0x101];
106 static read_func_ptr_t _mem_read_tab_watch[0x101];
107 static store_func_ptr_t _mem_write_tab_watch[0x101];
108 static uint8_t *_mem_read_base_tab[0x101];
109 static int mem_read_limit_tab[0x101];
110
111 read_func_ptr_t *_mem_read_tab_ptr;
112 store_func_ptr_t *_mem_write_tab_ptr;
113 static uint8_t **_mem_read_base_tab_ptr;
114 static int *mem_read_limit_tab_ptr;
115
116 /* 8x96 mapping register */
117 uint8_t petmem_map_reg = 0;
118 #define FFF0_ENABLED 0x80
119 #define FFF0_IO_PEEK_THROUGH 0x40
120 #define FFF0_SCREEN_PEEK_THROUGH 0x20
121 /* Internal jumper, used by HRE board */
122 uint8_t petmem_ramON = 0;
123
124 static int bank8offset = 0;
125 static int bankCoffset = 0;
126
127 /* memory tables for the 6809 */
128 static read_func_ptr_t _mem6809_read_tab[0x101];
129 static store_func_ptr_t _mem6809_write_tab[0x101];
130 static read_func_ptr_t _mem6809_read_tab_watch[0x101];
131 static store_func_ptr_t _mem6809_write_tab_watch[0x101];
132 static uint8_t *_mem6809_read_base_tab[0x101];
133 static int mem6809_read_limit_tab[0x101];
134
135 read_func_ptr_t *_mem6809_read_tab_ptr;
136 store_func_ptr_t *_mem6809_write_tab_ptr;
137
138 static log_t pet_mem_log = LOG_ERR;
139
140 static uint8_t last_access = 0;
141
142 /* ------------------------------------------------------------------------- */
143
zero_read(uint16_t addr)144 uint8_t zero_read(uint16_t addr)
145 {
146 last_access = mem_ram[addr & 0xff];
147 return last_access;
148 }
149
zero_store(uint16_t addr,uint8_t value)150 void zero_store(uint16_t addr, uint8_t value)
151 {
152 mem_ram[addr & 0xff] = value;
153 last_access = value;
154 }
155
ram_read(uint16_t addr)156 static uint8_t ram_read(uint16_t addr)
157 {
158 last_access = mem_ram[addr];
159 return last_access;
160 }
161
ram_store(uint16_t addr,uint8_t value)162 static void ram_store(uint16_t addr, uint8_t value)
163 {
164 mem_ram[addr] = value;
165 last_access = value;
166 }
167
read_ext8(uint16_t addr)168 static uint8_t read_ext8(uint16_t addr)
169 {
170 last_access = mem_ram[addr + bank8offset];
171 return last_access;
172 }
173
store_ext8(uint16_t addr,uint8_t value)174 static void store_ext8(uint16_t addr, uint8_t value)
175 {
176 mem_ram[addr + bank8offset] = value;
177 last_access = value;
178 }
179
read_extC(uint16_t addr)180 static uint8_t read_extC(uint16_t addr)
181 {
182 last_access = mem_ram[addr + bankCoffset];
183 return last_access;
184 }
185
store_extC(uint16_t addr,uint8_t value)186 static void store_extC(uint16_t addr, uint8_t value)
187 {
188 mem_ram[addr + bankCoffset] = value;
189 last_access = value;
190 }
191
192 /*
193 * Map $8400-$87FF to $8000-$83FF and $8C00-$8FFF to $8800-$8BFF.
194 * This is only relevant for 40 column models, since 80 column models
195 * don't have a mirror image of the screen memory.
196 * Above $8800 there is normally empty space, but the colour extension
197 * places its colour memory there, which in turn may have a mirror
198 * if it is the 40 column model.
199 */
read_vmirror(uint16_t addr)200 static uint8_t read_vmirror(uint16_t addr)
201 {
202 last_access = mem_ram[0x8000 + (addr & 0x0bff)]; /* 0x3FF + 0x800 */
203 return last_access;
204 }
205
store_vmirror(uint16_t addr,uint8_t value)206 static void store_vmirror(uint16_t addr, uint8_t value)
207 {
208 mem_ram[0x8000 + (addr & 0xbff)] = value;
209 last_access = value;
210 }
211
rom_read(uint16_t addr)212 uint8_t rom_read(uint16_t addr)
213 {
214 last_access = mem_rom[addr & 0x7fff];
215 return last_access;
216 }
217
rom_store(uint16_t addr,uint8_t value)218 void rom_store(uint16_t addr, uint8_t value)
219 {
220 mem_rom[addr & 0x7fff] = value;
221 last_access = value;
222 }
223
224 #define ROM6809_BASE 0xA000
225
rom6809_read(uint16_t addr)226 static uint8_t rom6809_read(uint16_t addr)
227 {
228 last_access = mem_6809rom[addr - ROM6809_BASE];
229 return last_access;
230 }
231
232 #if 0
233 static void rom6809_store(uint16_t addr, uint8_t value)
234 {
235 mem_6809rom[addr - ROM6809_BASE] = value;
236 last_access = value;
237 }
238 #endif
239
read_unused(uint16_t addr)240 uint8_t read_unused(uint16_t addr)
241 {
242 return last_access;
243 }
244
read_io_88_8f(uint16_t addr)245 static uint8_t read_io_88_8f(uint16_t addr)
246 {
247 switch (addr & 0xff00) {
248 case 0x8800:
249 return petio_8800_read(addr);
250 case 0x8900:
251 return petio_8900_read(addr);
252 case 0x8a00:
253 return petio_8a00_read(addr);
254 case 0x8b00:
255 return petio_8b00_read(addr);
256 case 0x8c00:
257 return petio_8c00_read(addr);
258 case 0x8d00:
259 return petio_8d00_read(addr);
260 case 0x8e00:
261 return petio_8e00_read(addr);
262 case 0x8f00:
263 return petio_8f00_read(addr);
264 }
265
266 return last_access;
267 }
268
read_io_e9_ef(uint16_t addr)269 static uint8_t read_io_e9_ef(uint16_t addr)
270 {
271 switch (addr & 0xff00) {
272 case 0xe900:
273 return petio_e900_read(addr);
274 case 0xea00:
275 return petio_ea00_read(addr);
276 case 0xeb00:
277 return petio_eb00_read(addr);
278 case 0xec00:
279 return petio_ec00_read(addr);
280 case 0xed00:
281 return petio_ed00_read(addr);
282 case 0xee00:
283 return petio_ee00_read(addr);
284 case 0xef00:
285 return petio_ef00_read(addr);
286 }
287
288 return last_access;
289 }
290
mem_read_patchbuf(uint16_t addr)291 static uint8_t mem_read_patchbuf(uint16_t addr)
292 {
293 last_access = petmem_2001_buf_ef[addr & 0xff];
294 return last_access;
295 }
296
297 /* ------------------------------------------------------------------------- */
298
299 /* Functions for watchpoint memory access. */
300
zero_read_watch(uint16_t addr)301 static uint8_t zero_read_watch(uint16_t addr)
302 {
303 addr &= 0xff;
304 monitor_watch_push_load_addr(addr, e_comp_space);
305 return _mem_read_tab[0](addr);
306 }
307
zero_store_watch(uint16_t addr,uint8_t value)308 static void zero_store_watch(uint16_t addr, uint8_t value)
309 {
310 addr &= 0xff;
311 monitor_watch_push_store_addr(addr, e_comp_space);
312 _mem_write_tab[0](addr, value);
313 }
314
read_watch(uint16_t addr)315 static uint8_t read_watch(uint16_t addr)
316 {
317 monitor_watch_push_load_addr(addr, e_comp_space);
318 return _mem_read_tab[addr >> 8](addr);
319 }
320
store_watch(uint16_t addr,uint8_t value)321 static void store_watch(uint16_t addr, uint8_t value)
322 {
323 monitor_watch_push_store_addr(addr, e_comp_space);
324 _mem_write_tab[addr >> 8](addr, value);
325 }
326
read6809_watch(uint16_t addr)327 static uint8_t read6809_watch(uint16_t addr)
328 {
329 monitor_watch_push_load_addr(addr, e_comp_space);
330 return _mem6809_read_tab[addr >> 8](addr);
331 }
332
store6809_watch(uint16_t addr,uint8_t value)333 static void store6809_watch(uint16_t addr, uint8_t value)
334 {
335 monitor_watch_push_store_addr(addr, e_comp_space);
336 _mem6809_write_tab[addr >> 8](addr, value);
337 }
338
339 /* ------------------------------------------------------------------------- */
340
341 /* SuperPET handling
342 *
343 * This adds some write-only registers at $eff*, an ACIA at $eff0 and
344 * 64k RAM that are mapped in 4k pages at $9***.
345 * Here the 8x96 expansion RAM doubles as the SuperPET banked RAM.
346 * There is also a dongle (6702) at $efe0.
347 */
348
349 int spet_ramen = 1;
350 int spet_bank = 0;
351 static uint8_t *spet_bank_ptr;
352 int spet_ctrlwp = 1;
353 int spet_diag = 0;
354 int spet_ramwp = 0;
355 int spet_flat_mode = 0; /* This is for the extra TPUG-designed */
356 int spet_firq_disabled = 0; /* ...Super OS/9 MMU. */
357 #define DEBUG_DONGLE 0
358
359 /* Internal state of the 6702 dongle */
360 #define DONGLE_MAGIC (128 + 64 + 16 + 4 + 2) /* = 214 = $D6 = %1101 0110 */
361 static const int leftmost[8] = {
362 1 << (6 - 1), /* 1 The size of each shift register is 6, 3, 7... */
363 1 << (3 - 1), /* 2 and therefore those are also the periods of */
364 1 << (7 - 1), /* 4 the output bits. */
365 1 << (8 - 1), /* 8 */
366 1 << (1 - 1), /* 16 */
367 1 << (3 - 1), /* 32 */
368 1 << (5 - 1), /* 64 */
369 1 << (2 - 1), /* 128 */
370 };
371 struct dongle6702_s dongle6702;
372
reset6702(void)373 static void reset6702(void)
374 {
375 int i;
376
377 for (i = 0; i < 8; i++) {
378 if ((1 << i) & (DONGLE_MAGIC | 1)) {
379 dongle6702.shift[i] = leftmost[i];
380 } else {
381 dongle6702.shift[i] = 0;
382 }
383 }
384 dongle6702.val = DONGLE_MAGIC;
385 dongle6702.prevodd = 1;
386 dongle6702.wantodd = 0;
387 }
388
read6702(void)389 static inline uint8_t read6702(void)
390 {
391 last_access = dongle6702.val;
392 return last_access;
393 }
394
395 /*
396 * Only the first odd value which is written after
397 * an even value has an effect.
398 *
399 * Thanks to Ruud Baltissen, William Levak, Rob Clarke,
400 * Kajtar Zsolt and Segher Boessenkool, Dave E Roberts,
401 * from cbm-hackers, for their contributions.
402 * -Olaf Seibert.
403 */
write6702(uint8_t input)404 static inline void write6702(uint8_t input)
405 {
406 last_access = input;
407
408 if ((input & 1) == dongle6702.wantodd) {
409 if (dongle6702.wantodd) {
410 int i;
411 int v = dongle6702.val;
412 int changed = dongle6702.prevodd ^ input;
413 int mask = 0x80;
414
415 /* loop over all 8 output bits / shift registers */
416 for (i = 7; i >= 0; i--, mask >>= 1) {
417 /* If the input bit changed: toggle leftmost bit */
418 if (changed & mask) {
419 dongle6702.shift[i] ^= leftmost[i];
420 }
421 /* The rightmost bit (the one that gets shifted out in
422 * a moment) determines if the output changes.
423 * I.e., if the rightmost bit is set, toggle it in v.
424 * Also simulate a rotate of the shift register by setting
425 * a 1 just left of the leftmost bit, so that the
426 * subsequent right-shift will put a 1 at the left.
427 * (If there is a 0, all this is a no-op.)
428 */
429 if (dongle6702.shift[i] & 1) {
430 v ^= mask;
431 dongle6702.shift[i] |= leftmost[i] << 1; /* wrap bit around */
432 }
433 dongle6702.shift[i] >>= 1;
434 }
435
436 dongle6702.prevodd = input;
437 dongle6702.val = v;
438 }
439 dongle6702.wantodd ^= 1;
440 }
441 }
442
efe0_dump(void)443 static int efe0_dump(void)
444 {
445 int i;
446 int mask = 1;
447
448 mon_out("efe0 = $%02x; previous in = $%02x; odd/even = %d\n", dongle6702.val, dongle6702.prevodd, dongle6702.wantodd);
449 for (i = 0; i < 8; i++, mask <<= 1) {
450 int j;
451 int maskj;
452 int sh = dongle6702.shift[i];
453 int lm = leftmost[i];
454
455 mon_out("%d %3d: $%02x %%", i, mask, sh);
456
457 for (j = 7, maskj = 1 << j; j >= 0; j--, maskj >>= 1) {
458 if (maskj > lm) {
459 mon_out(" ");
460 } else if (sh & maskj) {
461 mon_out("1");
462 } else {
463 mon_out("0");
464 }
465 }
466 mon_out("\n");
467 }
468
469 return 0;
470 }
471
set_spet_bank(int banknr)472 void set_spet_bank(int banknr)
473 {
474 spet_bank_ptr = &mem_ram[EXT_RAM + (banknr << 12)];
475 }
476
petmem_reset(void)477 void petmem_reset(void)
478 {
479 spet_ramen = 1;
480 set_spet_bank(0);
481 spet_ctrlwp = 1;
482 spet_flat_mode = 0;
483 spet_firq_disabled = 0;
484
485 petmem_map_reg = 0;
486 petmem_ramON = 0;
487 #if DEBUG_DONGLE
488 printf("reset 6702\n");
489 #endif
490 reset6702();
491 }
492
superpet_mem_powerup(void)493 static void superpet_mem_powerup(void)
494 {
495 /* Those two are not reset by a soft reset (/RES), only by power down */
496 spet_diag = 0;
497 spet_ramwp = 0; /* should look at hardware switch */
498 }
499
petmem_superpet_diag(void)500 int petmem_superpet_diag(void)
501 {
502 return petres.superpet && spet_diag;
503 }
504
read_super_io(uint16_t addr)505 static uint8_t read_super_io(uint16_t addr)
506 {
507 if (addr >= 0xeff4) { /* unused / readonly */
508 return last_access;
509 } else if (addr >= 0xeff0) { /* ACIA */
510 last_access = acia1_read((uint16_t)(addr & 0x03));
511 } else if ((addr & 0x0010) == 0) {
512 /* Dongle E F xxx0 xxxx, see zimmers.net,
513 * schematics/computers/pet/SuperPET/324055.gif.
514 * Typical address is $EFE0, possibly EFE0...3.
515 */
516 if (addr >= 0xefe0 && addr < 0xefe4) {
517 last_access = read6702();
518 #if DEBUG_DONGLE
519 log_message(pet_mem_log, "*** DONGLE %04x -> 0x%02X %3d", addr, last_access, last_access);
520 #endif /* DEBUG_DONGLE */
521 } else {
522 last_access = 0xff;
523 }
524 }
525 return last_access; /* fallback */
526 }
527
store_super_io(uint16_t addr,uint8_t value)528 static void store_super_io(uint16_t addr, uint8_t value)
529 {
530 last_access = value;
531
532 if (addr >= 0xeffe) { /* RAM/ROM switch */
533 spet_ramen = !(value & 1);
534 /* printf("spet_ramen := %d\n", spet_ramen); */
535 } else
536 if (addr >= 0xeffc) { /* Bank select */
537 set_spet_bank(value & 0x0F);
538 spet_firq_disabled = (value & 0x20);
539 spet_flat_mode = (value & 0x40);
540 spet_ctrlwp = !(value & 0x80);
541 /* printf("spet_bank := %x ", spet_bank);
542 printf("spet_flat_mode := %d ", !!spet_flat_mode);
543 printf("spet_firq_disabled := %d ", !!spet_firq_disabled);
544 printf("spet_ctrlwp := %d\n", !!spet_ctrlwp); */
545 if (spet_flat_mode) {
546 /* This is for the extra TPUG-designed Super OS/9 MMU.
547 * There is no need to check if this is a change in value,
548 * since in the new state there is no access to I/O;
549 * it it switched off by the SYNC instruction.
550 * See http://mikenaberezny.com/hardware/superpet/super-os9-mmu/
551 */
552 mem_initialize_memory_6809_flat();
553 /* mon_bank(e_default_space, "extram");
554 extern WORD PC;
555 printf("next opcode: %04X: banked %02X, flat %02X\n",
556 PC,
557 mem_ram[EXT_RAM + spet_bank_4k + (PC & 0x0FFF)],
558 mem_ram[EXT_RAM + PC]
559 ); */
560 }
561 /* else if (spet_bank_4k != old_spet_bank_4k) {
562 * maincpu_resync_limits(); notyet: 6809 doesn't use bank_base yet.
563 * }
564 */
565 } else {
566 if (addr >= 0xeff8) {
567 if (!spet_ctrlwp) {
568 if (!(value & 1)) {
569 log_error(pet_mem_log, "SuperPET: switching to 6809 not emulated!");
570 machine_trigger_reset(MACHINE_RESET_MODE_SOFT);
571 }
572 spet_ramwp = !(value & 0x2); /* IF hardware w/p switch is PROG */
573 /* printf("spet_ramwp := %d\n", spet_ramwp); */
574 spet_diag = (value & 0x8);
575 }
576 } else
577 if (addr >= 0xeff4) { /* unused */
578 } else
579 if (addr >= 0xeff0) { /* ACIA */
580 acia1_store((uint16_t)(addr & 0x03), value);
581 } else if (addr >= 0xefe0 && addr < 0xefe4) { /* dongle */
582 #if DEBUG_DONGLE
583 log_message(pet_mem_log, "*** DONGLE %04x := %02X %3d", addr, value, value);
584 #endif
585 write6702(value);
586 }
587 }
588 }
589
read_super_9(uint16_t addr)590 static uint8_t read_super_9(uint16_t addr)
591 {
592 if (spet_ramen) {
593 last_access = spet_bank_ptr[addr & 0x0fff];
594 } else {
595 last_access = rom_read(addr);
596 }
597 return last_access;
598 }
599
store_super_9(uint16_t addr,uint8_t value)600 static void store_super_9(uint16_t addr, uint8_t value)
601 {
602 last_access = value;
603
604 if (spet_ramen && !spet_ramwp) {
605 spet_bank_ptr[addr & 0x0fff] = value;
606 }
607 }
608
read_super_flat(uint16_t addr)609 static uint8_t read_super_flat(uint16_t addr)
610 {
611 last_access = (mem_ram + EXT_RAM)[addr];
612 return last_access;
613 }
614
store_super_flat(uint16_t addr,uint8_t value)615 static void store_super_flat(uint16_t addr, uint8_t value)
616 {
617 last_access = value;
618 (mem_ram + EXT_RAM)[addr] = value;
619 }
620
621
622 /* ------------------------------------------------------------------------- */
623
624 /* Generic memory access. */
625
mem_store(uint16_t addr,uint8_t value)626 void mem_store(uint16_t addr, uint8_t value)
627 {
628 _mem_write_tab_ptr[addr >> 8](addr, value);
629 }
630
mem_read(uint16_t addr)631 uint8_t mem_read(uint16_t addr)
632 {
633 return _mem_read_tab_ptr[addr >> 8](addr);
634 }
635
636 #define PRINT_6809_STORE 0
637 #define PRINT_6809_READ 0
638
mem6809_store(uint16_t addr,uint8_t value)639 void mem6809_store(uint16_t addr, uint8_t value)
640 {
641 #if PRINT_6809_STORE
642 if (addr >= 0x8000 && addr < 0x9000) {
643 printf("mem6809_store %04x <- %02x\n", addr, value);
644 }
645 #endif
646 _mem6809_write_tab_ptr[addr >> 8](addr, value);
647 }
648
mem6809_read(uint16_t addr)649 uint8_t mem6809_read(uint16_t addr)
650 {
651 #if PRINT_6809_READ
652 uint8_t v;
653 v = _mem6809_read_tab_ptr[addr >> 8](addr);
654 printf("mem6809_read %04x -> %02x\n", addr, v);
655 return v;
656 #else
657 return _mem6809_read_tab_ptr[addr >> 8](addr);
658 #endif
659 }
660
mem6809_store16(uint16_t addr,uint16_t value)661 void mem6809_store16(uint16_t addr, uint16_t value)
662 {
663 #if PRINT_6809_STORE0
664 printf("mem6809_store16 %04x <- %04x\n", addr, value);
665 #endif
666 addr++;
667 _mem6809_write_tab_ptr[addr >> 8](addr, (uint8_t)(value & 0xFF));
668 addr--;
669 _mem6809_write_tab_ptr[addr >> 8](addr, (uint8_t)(value >> 8));
670 }
671
mem6809_read16(uint16_t addr)672 uint16_t mem6809_read16(uint16_t addr)
673 {
674 uint16_t val;
675 val = _mem6809_read_tab_ptr[addr >> 8](addr) << 8;
676 addr++;
677 val |= _mem6809_read_tab_ptr[addr >> 8](addr);
678 #if PRINT_6809_READ
679 printf("mem6809_read16 %04x -> %04x\n", addr, val);
680 #endif
681 return val;
682 }
683
684 #ifdef H6309
mem6809_store32(uint16_t addr,uint32_t value)685 void mem6809_store32(uint16_t addr, uint32_t value)
686 {
687 #if PRINT_6809_STORE0
688 printf("mem6809_store32 %04x <- %04x\n", addr, value);
689 #endif
690 addr += 3;
691 _mem6809_write_tab_ptr[addr >> 8](addr, (uint8_t)(value & 0xFF));
692 addr--;
693 _mem6809_write_tab_ptr[addr >> 8](addr, (uint8_t)((value >> 8) & 0xFF));
694 addr--;
695 _mem6809_write_tab_ptr[addr >> 8](addr, (uint8_t)((value >> 16) & 0xFF));
696 addr--;
697 _mem6809_write_tab_ptr[addr >> 8](addr, (uint8_t)(value >> 24));
698 }
699
mem6809_read32(uint16_t addr)700 uint32_t mem6809_read32(uint16_t addr)
701 {
702 uint32_t val;
703 val = _mem6809_read_tab_ptr[addr >> 8](addr) << 24;
704 addr++;
705 val |= _mem6809_read_tab_ptr[addr >> 8](addr) << 16;
706 addr++;
707 val |= _mem6809_read_tab_ptr[addr >> 8](addr) << 8;
708 addr++;
709 val |= _mem6809_read_tab_ptr[addr >> 8](addr);
710 #if PRINT_6809_READ
711 printf("mem6809_read32 %04x -> %04x\n", addr, val);
712 #endif
713 return val;
714 }
715 #endif
716
717 /* ------------------------------------------------------------------------- */
718
719 /* The PET have all I/O chips connected to the same select lines. Only one
720 address lines is used as separate (high-active) select input. I.e. PIA1
721 always reacts when address & 0x10 is high, for example $e810, $e830,
722 $e850, etc. PIA2 reacts when address & 0x20 is high, for example $e820,
723 $e830 $e860,... The next two functions try to reflect this behaviour. */
724
725 /* When we write, we write all involved chips. */
726
store_io_e8(uint16_t addr,uint8_t value)727 static void store_io_e8(uint16_t addr, uint8_t value)
728 {
729 last_access = value;
730
731 if (addr & 0x10) {
732 pia1_store(addr, value);
733 }
734
735 if (addr & 0x20) {
736 pia2_store(addr, value);
737 }
738
739 if (addr & 0x40) {
740 via_store(addr, value);
741 }
742
743 if ((addr & 0x80) && petres.crtc) {
744 crtc_store(addr, value);
745 crtc_store_hre(addr, value);
746 }
747 }
748
749
750 /*
751 * When we read, we only read sensible values. In real operation,
752 * the bus drivers of all involved chips interact and you get strange
753 * results...
754 */
read_io_e8(uint16_t addr)755 static uint8_t read_io_e8(uint16_t addr)
756 {
757 uint8_t v1, v2, v3, v4;
758
759 switch (addr & 0xf0) {
760 case 0x10: /* PIA1 */
761 last_access = pia1_read(addr);
762 break;
763 case 0x20: /* PIA2 */
764 last_access = pia2_read(addr);
765 break;
766 case 0x40:
767 last_access = via_read(addr); /* VIA */
768 break;
769 case 0x80: /* CRTC */
770 if (petres.crtc) {
771 last_access = crtc_read(addr);
772 } /* fall through */
773 case 0x00:
774 return last_access;
775 default: /* 0x30, 0x50, 0x60, 0x70, 0x90-0xf0 */
776 if (addr & 0x10) {
777 v1 = pia1_read(addr);
778 } else {
779 v1 = 0xff;
780 }
781 if (addr & 0x20) {
782 v2 = pia2_read(addr);
783 } else {
784 v2 = 0xff;
785 }
786 if (addr & 0x40) {
787 v3 = via_read(addr);
788 } else {
789 v3 = 0xff;
790 }
791 v4 = 0xff;
792 if ((addr & 0x80) && petres.crtc) {
793 v4 = crtc_read(addr);
794 }
795 last_access = v1 & v2 & v3 & v4;
796 }
797 return last_access;
798 }
799
store_void(uint16_t addr,uint8_t value)800 static void store_void(uint16_t addr, uint8_t value)
801 {
802 last_access = value;
803 }
804
805 /*
806 * store_dummy() stores in normally-unassigned memory space,
807 * except that some hardware expansions may be there.
808 * For adresses < 0x8000 it is faster to use store_void().
809 */
store_dummy(uint16_t addr,uint8_t value)810 static void store_dummy(uint16_t addr, uint8_t value)
811 {
812 last_access = value;
813 }
814
store_io_88_8f(uint16_t addr,uint8_t value)815 static void store_io_88_8f(uint16_t addr, uint8_t value)
816 {
817 last_access = value;
818
819 switch (addr & 0xff00) {
820 case 0x8800:
821 petio_8800_store(addr, value);
822 break;
823 case 0x8900:
824 petio_8900_store(addr, value);
825 break;
826 case 0x8a00:
827 petio_8a00_store(addr, value);
828 break;
829 case 0x8b00:
830 petio_8b00_store(addr, value);
831 break;
832 case 0x8c00:
833 petio_8c00_store(addr, value);
834 break;
835 case 0x8d00:
836 petio_8d00_store(addr, value);
837 break;
838 case 0x8e00:
839 petio_8e00_store(addr, value);
840 break;
841 case 0x8f00:
842 petio_8f00_store(addr, value);
843 break;
844 }
845 }
846
store_io_e9_ef(uint16_t addr,uint8_t value)847 static void store_io_e9_ef(uint16_t addr, uint8_t value)
848 {
849 last_access = value;
850
851 switch (addr & 0xff00) {
852 case 0xe900:
853 petio_e900_store(addr, value);
854 break;
855 case 0xea00:
856 petio_ea00_store(addr, value);
857 break;
858 case 0xeb00:
859 petio_eb00_store(addr, value);
860 break;
861 case 0xec00:
862 petio_ec00_store(addr, value);
863 break;
864 case 0xed00:
865 petio_ed00_store(addr, value);
866 break;
867 case 0xee00:
868 petio_ee00_store(addr, value);
869 break;
870 case 0xef00:
871 petio_ef00_store(addr, value);
872 break;
873 }
874 }
875
876 /*
877 * This sets the standard PET memory configuration from $9000-$10000.
878 * It is used in store_8x96() and mem_initialize_memory().
879 *
880 [/NO ROM = 1; see page 12 for more cases]
881 +-----+--------+------------+-------------------------------------------------+
882 | |Control | | |
883 | |Register| | main memory $8000 - $FFFF [UB1-UB8] |
884 | | | | [$0000 - $7FFF is always RAM from UB1-UB8] |
885 | |$FFF0 | | |
886 +-----+--------+------------+-------------------------------------------------+
887 | | I/O |___ ___ ___ | E000 |
888 | ___ | peek|RAM RAM RAM | E800 F000 -E7FF B000 A000 9000 8000 |
889 | NO_ | thr.|___ ___ ___ | E900 |
890 | ROM |CR7 CR6 |ON S.9 S.A |-E8FF -FFFF -EFFF -DFFF -AFFF -9FFF -8FFF |
891 +-----+--------+------------+-------------------------------------------------+
892 | | | | |
893 | 1 | 0 X | 1 1 1 | I/O Kernal Editor BASIC EPROM EPROM SCREEN |
894 | | | | |
895 | 1 | 0 X | 1 1 0 | I/O Kernal Editor BASIC RAM EPROM SCREEN |
896 | | | | +-----+ |
897 | 1 | 0 X | 1 0 1 | I/O Kernal Editor BASIC EPROM RAM SCREEN |
898 | | | | +-----+ |
899 | 1 | 0 X | 1 0 0 | I/O Kernal Editor BASIC RAM RAM SCREEN |
900 | | | | +-----+ |
901 | 1 | 0 X | 0 1 1 | I/O Kernal Editor RAM RAM RAM SCREEN |
902 | | | | +------+ |
903 | 1 | 0 X | 0 0 1 | I/O Kernal RAM RAM RAM RAM SCREEN |
904 | | | | +------+ |
905 | 1 | 0 1 | 0 X 0 | I/O RAM RAM RAM RAM RAM SCREEN |
906 | | | |+----+ |
907 | 1 | 0 0 | 0 X 0 | RAM RAM RAM RAM RAM RAM SCREEN |
908 | | | | |
909 +-----+--------+------------+-------------------------------------------------+
910 SCREEN: 2000 bytes for screen memory, and 2096 bytes of available RAM.
911 *
912 */
913
set_std_9tof(void)914 static void set_std_9tof(void)
915 {
916 int i, l;
917 void (*store)(uint16_t, uint8_t);
918 uint8_t (*fetch)(uint16_t);
919 int ram9, ramA, ramBCD, ramE, ramE8, ramF;
920
921 /* printf("set_std_9tof: petres.ramSize=%d, petres.map=%d\n", petres.ramSize, petres.map); */
922 if (petres.map == PET_MAP_8296) {
923 store = ram_store;
924
925 if (petmem_ramON) {
926 ram9 = ramA = ramBCD = 1;
927 ramE = petres.ramsel9 || petres.ramselA;
928 ramE8 = petres.ramselA && !(petmem_map_reg & FFF0_IO_PEEK_THROUGH);
929 ramF = petres.ramselA;
930 /*
931 * XXX: If there is no I/O peek through, how can we write
932 * again to the E888 register to restore I/O?
933 */
934 } else {
935 ram9 = petres.ramsel9;
936 ramA = petres.ramselA;
937 ramBCD = ramE = ramE8 = ramF = 0;
938 }
939 } else {
940 store = store_dummy;
941 ram9 = ramA = ramBCD = ramE = ramE8 = ramF = 0;
942 }
943
944 /* Setup RAM/ROM at $9000 - $9FFF. */
945 if (petres.superpet) {
946 for (i = 0x90; i < 0xa0; i++) {
947 _mem_read_tab[i] = read_super_9;
948 _mem_write_tab[i] = store_super_9;
949 _mem_read_base_tab[i] = NULL;
950 mem_read_limit_tab[i] = 0;
951 }
952 } else {
953 fetch = ram9 ? ram_read : rom_read;
954 for (i = 0x90; i < 0xa0; i++) {
955 _mem_read_tab[i] = fetch;
956 _mem_write_tab[i] = store;
957 _mem_read_base_tab[i] = NULL;
958 mem_read_limit_tab[i] = 0;
959 }
960 }
961
962 /* Possibly set up the Double-W HiRes board at $9000 - $9FFF. */
963 if (petdww_enabled && petdww_mem_at_9000()) {
964 petdww_override_std_9toa(_mem_read_tab, _mem_write_tab,
965 _mem_read_base_tab, mem_read_limit_tab);
966 }
967
968 /* Setup RAM/ROM at $A000 - $AFFF. */
969 fetch = ramA ? ram_read : rom_read;
970 for (i = 0xa0; i < 0xb0; i++) {
971 _mem_read_tab[i] = fetch;
972 _mem_write_tab[i] = store;
973 _mem_read_base_tab[i] = NULL;
974 mem_read_limit_tab[i] = 0;
975 }
976
977 /* Setup RAM/ROM at $B000 - $DFFF: Basic. */
978 fetch = ramBCD ? ram_read : rom_read;
979 for (i = 0xb0; i <= 0xdf; i++) {
980 _mem_read_tab[i] = fetch;
981 _mem_write_tab[i] = store;
982 _mem_read_base_tab[i] = NULL;
983 mem_read_limit_tab[i] = 0;
984 }
985
986 /* Setup RAM/ROM at $E000 - $E7FF: Editor. */
987 fetch = ramE ? ram_read : rom_read;
988 for (i = 0xe0; i <= 0xe7; i++) {
989 _mem_read_tab[i] = fetch;
990 _mem_write_tab[i] = store;
991 _mem_read_base_tab[i] = NULL;
992 mem_read_limit_tab[i] = 0;
993 }
994
995 /* End of I/O address space */
996 l = ((0xe800 + petres.IOSize) >> 8) & 0xff;
997
998 if (ramE8) {
999 /* Setup RAM at $E800 - $E800 + petres.IOSize. */
1000 for (i = 0xe0; i < l; i++) {
1001 _mem_read_tab[i] = ram_read;
1002 _mem_write_tab[i] = store;
1003 _mem_read_base_tab[i] = NULL;
1004 mem_read_limit_tab[i] = 0;
1005 }
1006 } else {
1007 /* Setup I/O at $e800 - $e800 + petres.IOSize. */
1008 /* i.e. IO at $e800... */
1009 _mem_read_tab[0xe8] = read_io_e8;
1010 _mem_write_tab[0xe8] = store_io_e8;
1011 _mem_read_base_tab[0xe8] = NULL;
1012 mem_read_limit_tab[0xe8] = 0;
1013
1014 /* ... and unused address space following it, if any. */
1015 for (i = 0xe9; i < l; i++) {
1016 _mem_read_tab[i] = read_io_e9_ef;
1017 _mem_write_tab[i] = store_io_e9_ef;
1018 _mem_read_base_tab[i] = NULL;
1019 mem_read_limit_tab[i] = 0;
1020 }
1021 }
1022
1023 /* Setup RAM/ROM at $E800 + petres.IOSize - $EFFF: Extended Editor */
1024 fetch = ramE ? ram_read : rom_read;
1025 for (i = l; i <= 0xef; i++) {
1026 _mem_read_tab[i] = fetch;
1027 _mem_write_tab[i] = store;
1028 _mem_read_base_tab[i] = NULL;
1029 mem_read_limit_tab[i] = 0;
1030 }
1031
1032 /*
1033 * $EF00 is needed for SuperPET I/O or 2001 ROM patch.
1034 * This means that those models can't support an extended editor ROM.
1035 */
1036 if (petres.superpet) {
1037 _mem_read_tab[0xef] = read_super_io;
1038 _mem_write_tab[0xef] = store_super_io;
1039 _mem_read_base_tab[0xef] = NULL;
1040 mem_read_limit_tab[0xef] = 0;
1041 } else if (petres.rompatch) {
1042 _mem_read_tab[0xef] = mem_read_patchbuf;
1043 _mem_write_tab[0xef] = store_void;
1044 _mem_read_base_tab[0xef] = NULL;
1045 mem_read_limit_tab[0xef] = 0;
1046 }
1047
1048 /* Setup RAM/ROM at $f000 - $ffff: Kernal */
1049 fetch = ramF ? ram_read : rom_read;
1050 for (i = 0xf0; i <= 0xff; i++) {
1051 _mem_read_tab[i] = fetch;
1052 _mem_write_tab[i] = store;
1053 _mem_read_base_tab[i] = NULL;
1054 mem_read_limit_tab[i] = 0;
1055 }
1056
1057 _mem_read_base_tab_ptr = _mem_read_base_tab;
1058 mem_read_limit_tab_ptr = mem_read_limit_tab;
1059 }
1060
ramsel_changed()1061 void ramsel_changed()
1062 {
1063 set_std_9tof();
1064 maincpu_resync_limits();
1065 }
1066
get_mem_access_tables(read_func_ptr_t ** read,store_func_ptr_t ** write,uint8_t *** base,int ** limit)1067 void get_mem_access_tables(read_func_ptr_t **read, store_func_ptr_t **write, uint8_t ***base, int **limit)
1068 {
1069 *read = _mem_read_tab;
1070 *write = _mem_write_tab;
1071 *base = _mem_read_base_tab;
1072 *limit = mem_read_limit_tab;
1073 }
1074
mem_toggle_watchpoints(int flag,void * context)1075 void mem_toggle_watchpoints(int flag, void *context)
1076 {
1077 if (flag) {
1078 _mem_read_tab_ptr = _mem_read_tab_watch;
1079 _mem_write_tab_ptr = _mem_write_tab_watch;
1080 _mem6809_read_tab_ptr = _mem6809_read_tab_watch;
1081 _mem6809_write_tab_ptr = _mem6809_write_tab_watch;
1082 } else {
1083 _mem_read_tab_ptr = _mem_read_tab;
1084 _mem_write_tab_ptr = _mem_write_tab;
1085 _mem6809_read_tab_ptr = _mem6809_read_tab;
1086 _mem6809_write_tab_ptr = _mem6809_write_tab;
1087 }
1088 }
1089
1090 /*
1091 * From PETdoc.txt:
1092 *
1093 * $fff0 register in PET 8x96
1094 * 8096 exp-mem (64K):
1095 * The control register is at $FFF0/65520
1096 * You have 4 16K-banks, 0...3
1097 *
1098 * $8000 $9000 $C000 $E800 $F000 $FFFF
1099 * !----------------------------!!--------------------------------------!
1100 * Bank 0 or 2 Bank 1 or 3
1101 * !--------! !-------!
1102 * screen io
1103 *
1104 * Control Register $FFF0:
1105 * bit 7: 0 normal 8032 configuration (screen, ROMs, IO, ROMs)
1106 * 80 expansion memory
1107 * bit 6: 0 RAM $E800-$EFFF (only when bit7=1)
1108 * 40 IO peek through
1109 * bit 5: 0 exp-mem $8000-$8FFF (-"-)
1110 * 20 screen peek through
1111 * bit 4: 10 not used
1112 * bit 3: 0 bank 1 $C000-$FFFF
1113 * 08 bank 3
1114 * bit 2: 0 bank 0 $8000-$BFFF
1115 * 04 bank 2
1116 * bit 1: 02 write protect bank 1/3
1117 * bit 0: 01 write protect bank 0/2
1118 * when bit7=0, all other bits are ignored
1119 *
1120 * The missing 32K can't be accessed witout hardware modifications.
1121 * You can only use the 2K "behind" the screen $8800-$8FFF (exact: 34768-
1122 * 36863), available in the normal configuration.
1123 * The register is write-only, and the value is written through to the
1124 * previously selected ram bank.
1125 *
1126 */
1127
1128 #define FFF0_BANK_C 0x08
1129 #define FFF0_BANK_8 0x04
1130 #define FFF0_BANK_C_WP 0x02
1131 #define FFF0_BANK_8_WP 0x01
1132
1133 /* Save old store function for last byte. */
1134 static void (*store_ff)(uint16_t addr, uint8_t value) = NULL;
1135
1136 /* Write to last page of memory in 8x96. */
store_8x96(uint16_t addr,uint8_t value)1137 static void store_8x96(uint16_t addr, uint8_t value)
1138 {
1139 uint8_t changed;
1140 int l, protected;
1141
1142 last_access = value;
1143
1144 if (store_ff) {
1145 store_ff(addr, value);
1146 }
1147
1148 changed = petmem_map_reg ^ value;
1149
1150 if (addr == 0xfff0 && changed &&
1151 ((petmem_map_reg | changed) & FFF0_ENABLED)) {
1152 if (value & FFF0_ENABLED) { /* ext. RAM enabled */
1153 /* A5 = FFF0_ENABLED | FFF0_SCREEN_PEEK_THROUGH |
1154 * FFF0_BANK_8 | FFF0_BANK_8_WP
1155 */
1156 if (changed & 0xa5) { /* $8000-$bfff */
1157 protected = value & FFF0_BANK_8_WP;
1158 l = 0x80;
1159 if (value & FFF0_SCREEN_PEEK_THROUGH) {
1160 /* screen memory mapped through */
1161 for (; l < 0x90; l++) {
1162 _mem_read_tab[l] = ram_read;
1163 _mem_write_tab[l] = ram_store;
1164 _mem_read_base_tab[l] = NULL;
1165 mem_read_limit_tab[l] = 0;
1166 }
1167 }
1168 bank8offset = 0x8000 + ((value & FFF0_BANK_8) ? 0x8000 : 0);
1169 for (; l < 0xc0; l++) {
1170 _mem_read_tab[l] = read_ext8;
1171 if (protected) {
1172 _mem_write_tab[l] = store_dummy;
1173 } else {
1174 _mem_write_tab[l] = store_ext8;
1175 }
1176 _mem_read_base_tab[l] = NULL;
1177 mem_read_limit_tab[l] = 0;
1178 }
1179 maincpu_resync_limits();
1180 }
1181 /* CA = FFF0_ENABLED | FFF0_IO_PEEK_THROUGH |
1182 * FFF0_BANK_C | FFF0_BANK_C_WP
1183 */
1184 if (changed & 0xca) { /* $c000-$ffff */
1185 protected = value & FFF0_BANK_C_WP;
1186 bankCoffset = 0x8000 + ((value & FFF0_BANK_C) ? 0x8000 : 0);
1187 for (l = 0xc0; l < 0x100; l++) {
1188 if ((l == 0xe8) && (value & FFF0_IO_PEEK_THROUGH)) {
1189 _mem_read_tab[l] = read_io_e8;
1190 _mem_write_tab[l] = store_io_e8;
1191 _mem_read_base_tab[l] = NULL;
1192 mem_read_limit_tab[l] = 0;
1193 } else {
1194 _mem_read_tab[l] = read_extC;
1195 if (protected) {
1196 _mem_write_tab[l] = store_dummy;
1197 } else {
1198 _mem_write_tab[l] = store_extC;
1199 }
1200 _mem_read_base_tab[l] = NULL;
1201 mem_read_limit_tab[l] = 0;
1202 }
1203 }
1204 store_ff = _mem_write_tab[0xff];
1205 _mem_write_tab[0xff] = store_8x96;
1206 maincpu_resync_limits();
1207 }
1208 } else { /* disable ext. RAM */
1209 petmem_set_vidmem();
1210 set_std_9tof();
1211 store_ff = _mem_write_tab[0xff];
1212 _mem_write_tab[0xff] = store_8x96;
1213 maincpu_resync_limits();
1214 }
1215 petmem_map_reg = value;
1216 }
1217 }
1218
fff0_dump(void)1219 static int fff0_dump(void)
1220 {
1221 mon_out("%s memory mapping.\n",
1222 (petres.map == PET_MAP_8296 ? "8296" :
1223 petres.map == PET_MAP_8096 ? "8096" :
1224 petres.map == PET_MAP_LINEAR ? "plain" :
1225 "unknown"));
1226 mon_out("fff0 = %02x: ", petmem_map_reg);
1227 if (petmem_map_reg & FFF0_ENABLED) {
1228 mon_out("enabled, ");
1229 if (petmem_map_reg & FFF0_IO_PEEK_THROUGH) {
1230 mon_out("I/O peek through, ");
1231 }
1232 if (petmem_map_reg & FFF0_SCREEN_PEEK_THROUGH) {
1233 mon_out("screen peek through, ");
1234 }
1235 if (petmem_map_reg & 0x10) {
1236 mon_out("$10 unused bit set, ");
1237 }
1238 mon_out("\nC000-FFFF: bank %d %s, ",
1239 ((petmem_map_reg & FFF0_BANK_C) ? 3 : 1),
1240 ((petmem_map_reg & FFF0_BANK_C_WP) ? "(write protected)" : "(r/w)")
1241 );
1242 mon_out("8000-BFFF: bank %d %s.\n",
1243 ((petmem_map_reg & FFF0_BANK_8) ? 2 : 0),
1244 ((petmem_map_reg & FFF0_BANK_8_WP) ? "(write protected)" : "(r/w)")
1245 );
1246 } else {
1247 mon_out("disabled.\n");
1248 }
1249 return 0;
1250 }
1251
1252 /* ------------------------------------------------------------------------- */
1253
petmem_set_vidmem(void)1254 void petmem_set_vidmem(void)
1255 {
1256 int i, l;
1257
1258 l = ((0x8000 + petres.videoSize) >> 8) & 0xff;
1259 /*
1260 log_message(pet_mem_log, "petmem_set_vidmem(videoSize=%04x, l=%d)",
1261 petres.videoSize,l);
1262 */
1263 /* Setup RAM from $8000 to $8000 + petres.videoSize ($8400 or $8800) */
1264 for (i = 0x80; i < l; i++) {
1265 _mem_read_tab[i] = ram_read;
1266 _mem_write_tab[i] = ram_store;
1267 _mem_read_base_tab[i] = NULL;
1268 mem_read_limit_tab[i] = 0;
1269 }
1270
1271 /* Setup video mirror from $8000 + petres.videoSize to $87ff */
1272 /* falls through if videoSize >= 0x800 */
1273 for (; i < 0x88; i++) {
1274 _mem_read_tab[i] = read_vmirror;
1275 _mem_write_tab[i] = store_vmirror;
1276 _mem_read_base_tab[i] = NULL;
1277 mem_read_limit_tab[i] = 0;
1278 }
1279
1280 if (pet_colour_type == PET_COLOUR_TYPE_OFF) {
1281 /* Setup unused from $8800 to $8FFF */
1282 /* falls through if videoSize >= 0x1000 */
1283 for (; i < 0x90; i++) {
1284 _mem_read_tab[i] = read_io_88_8f;
1285 _mem_write_tab[i] = store_io_88_8f;
1286 _mem_read_base_tab[i] = NULL;
1287 mem_read_limit_tab[i] = 0;
1288 }
1289 } else {
1290 /* Setup colour RAM from $8800 to $8BFF or $8FFF */
1291 int c = 0x8000 + COLOUR_MEMORY_START;
1292 i = (c >> 8) & 0xff;
1293 l = ((c + petres.videoSize) >> 8) & 0xff;
1294 if (l > 0x90) { /* compatibility with 8296 */
1295 l = 0x90;
1296 }
1297
1298 for (; i < l; i++) {
1299 _mem_read_tab[i] = ram_read;
1300 _mem_write_tab[i] = ram_store;
1301 _mem_read_base_tab[i] = NULL;
1302 mem_read_limit_tab[i] = 0;
1303 }
1304
1305 /* Setup colour mirror from $8800 + petres.videoSize to $8FFF */
1306 /* falls through if videoSize >= 0x800 */
1307 for (; i < 0x90; i++) {
1308 _mem_read_tab[i] = read_vmirror;
1309 _mem_write_tab[i] = store_vmirror;
1310 _mem_read_base_tab[i] = NULL;
1311 mem_read_limit_tab[i] = 0;
1312 }
1313 }
1314 }
1315
1316 /* ------------------------------------------------------------------------- */
1317
mem_initialize_memory_6809_banked(void)1318 static void mem_initialize_memory_6809_banked(void)
1319 {
1320 int i;
1321
1322 /* extern WORD iPC; printf("mem_initialize_memory_6809_banked %04x bank %x\n", iPC, spet_bank); */
1323 for (i = 0x00; i < 0xa0; i++) {
1324 _mem6809_read_tab[i] = _mem_read_tab[i];
1325 _mem6809_write_tab[i] = _mem_write_tab[i];
1326 _mem6809_read_base_tab[i] = _mem_read_base_tab[i];
1327 mem6809_read_limit_tab[i] = mem_read_limit_tab[i];
1328 }
1329 /*
1330 * Set up the ROMs.
1331 */
1332 for (i = 0xa0; i < 0xe8; i++) {
1333 _mem6809_read_tab[i] = rom6809_read;
1334 _mem6809_write_tab[i] = store_void;
1335 _mem6809_read_base_tab[i] = mem_6809rom + i - (ROM6809_BASE >> 8);
1336 mem6809_read_limit_tab[i] = 0xe7fc;
1337 }
1338 for (i = 0xf0; i < 0x100; i++) {
1339 _mem6809_read_tab[i] = rom6809_read;
1340 _mem6809_write_tab[i] = store_void;
1341 _mem6809_read_base_tab[i] = mem_6809rom + i - (ROM6809_BASE >> 8);
1342 mem6809_read_limit_tab[i] = 0xfffc;
1343 }
1344 /*
1345 * Also copy the I/O setup from the 6502 view.
1346 */
1347 for (i = 0xe8; i < 0xf0; i++) {
1348 _mem6809_read_tab[i] = _mem_read_tab[i];
1349 _mem6809_write_tab[i] = _mem_write_tab[i];
1350 _mem6809_read_base_tab[i] = _mem_read_base_tab[i];
1351 mem6809_read_limit_tab[i] = mem_read_limit_tab[i];
1352 }
1353
1354 _mem6809_read_tab[0x100] = _mem6809_read_tab[0];
1355 _mem6809_write_tab[0x100] = _mem6809_write_tab[0];
1356 _mem6809_read_base_tab[0x100] = _mem6809_read_base_tab[0];
1357 mem6809_read_limit_tab[0x100] = -1;
1358
1359 /* maincpu_resync_limits(); notyet: 6809 doesn't use bank_base yet. */
1360 }
1361
mem_initialize_memory_6809_flat(void)1362 static void mem_initialize_memory_6809_flat(void)
1363 {
1364 int i;
1365
1366 /* extern WORD iPC; printf("mem_initialize_memory_6809_flat %04X bank %x\n", iPC, spet_bank); */
1367
1368 for (i = 0x00; i < 0x101; i++) {
1369 _mem6809_read_tab[i] = read_super_flat;
1370 _mem6809_write_tab[i] = store_super_flat;
1371 _mem6809_read_base_tab[i] = mem_ram + EXT_RAM + (i << 8);
1372 mem6809_read_limit_tab[i] = 0xfffc;
1373 }
1374
1375 _mem6809_read_base_tab[0x100] = _mem6809_read_base_tab[0];
1376 mem6809_read_limit_tab[0x100] = -1;
1377 /* maincpu_resync_limits(); notyet: 6809 doesn't use bank_base yet. */
1378 }
1379
mem_initialize_memory_6809()1380 void mem_initialize_memory_6809()
1381 {
1382 if (spet_flat_mode) {
1383 mem_initialize_memory_6809_flat();
1384 } else {
1385 mem_initialize_memory_6809_banked();
1386 }
1387 }
1388
superpet_sync(void)1389 int superpet_sync(void)
1390 {
1391 if (spet_firq_disabled) {
1392 log_error(pet_mem_log, "SuperPET: SYNC encountered, but no FIRQ possible!");
1393 return 1;
1394 } else {
1395 spet_flat_mode = 0;
1396 mem_initialize_memory_6809_banked();
1397 /* mon_bank(e_default_space, "6809");
1398 extern WORD PC;
1399 printf("next opcode: %04X: banked %02X, flat %02X\n",
1400 PC,
1401 mem_ram[EXT_RAM + spet_bank_4k + (PC & 0x0FFF)],
1402 mem_ram[EXT_RAM + PC]
1403 ); */
1404
1405 return 0;
1406 }
1407 }
1408
1409 /* This does the plain 8032 configuration, as 8096 stuff only comes up when
1410 writing to $fff0. */
mem_initialize_memory(void)1411 void mem_initialize_memory(void)
1412 {
1413 int i, l;
1414
1415 l = petres.ramSize << 2; /* ramSize in kB, l in 256 Byte */
1416 if (l > (32 << 2)) {
1417 l = (32 << 2); /* fix 8096 / 8296 */
1418 }
1419 /* Setup RAM from $0000 to petres.ramSize */
1420 _mem_read_tab[0] = zero_read;
1421 _mem_write_tab[0] = zero_store;
1422 _mem_read_base_tab[0] = NULL;
1423 mem_read_limit_tab[0] = 0;
1424
1425 for (i = 0x01; i < l; i++) {
1426 _mem_read_tab[i] = ram_read;
1427 _mem_write_tab[i] = ram_store;
1428 _mem_read_base_tab[i] = NULL;
1429 mem_read_limit_tab[i] = 0;
1430 }
1431
1432 /* Setup unused from petres.ramSize to $7fff */
1433 for (i = l; i < 0x80; i++) {
1434 _mem_read_tab[i] = read_unused;
1435 _mem_write_tab[i] = store_void;
1436 _mem_read_base_tab[i] = NULL;
1437 mem_read_limit_tab[i] = 0;
1438 }
1439
1440 petmem_set_vidmem();
1441
1442 set_std_9tof();
1443
1444 if (petres.map) { /* catch writes to $fff0 register */
1445 store_ff = _mem_write_tab[0xff];
1446 _mem_write_tab[0xff] = store_8x96;
1447 }
1448 _mem_read_tab[0x100] = _mem_read_tab[0];
1449 _mem_write_tab[0x100] = _mem_write_tab[0];
1450 _mem_read_base_tab[0x100] = _mem_read_base_tab[0];
1451 mem_read_limit_tab[0x100] = 0;
1452
1453 ram_size = petres.ramSize * 1024;
1454 _mem_read_tab_ptr = _mem_read_tab;
1455 _mem_write_tab_ptr = _mem_write_tab;
1456
1457 /* setup watchpoint tables */
1458 _mem_read_tab_watch[0] = zero_read_watch;
1459 _mem_write_tab_watch[0] = zero_store_watch;
1460 for (i = 1; i < 0x101; i++) {
1461 _mem_read_tab_watch[i] = read_watch;
1462 _mem_write_tab_watch[i] = store_watch;
1463 }
1464
1465 if (petres.map && petmem_map_reg) {
1466 uint8_t old_map_reg;
1467
1468 old_map_reg = petmem_map_reg;
1469 petmem_map_reg = 0;
1470 store_8x96(0xfff0, old_map_reg);
1471 } else {
1472 petmem_map_reg = 0;
1473 }
1474
1475
1476 if (petres.superpet) {
1477 /*
1478 * Initialize SuperPET 6809 memory view.
1479 * Basically, it is the same as the 6502 view, except for the
1480 * ROMs in addresses $A000 - $FFFF and but including the I/O range
1481 * of $E800 - $EFFF.
1482 */
1483 mem_initialize_memory_6809();
1484
1485 for (i = 0; i < 0x101; i++) {
1486 _mem6809_read_tab_watch[i] = read6809_watch;
1487 _mem6809_write_tab_watch[i] = store6809_watch;
1488 }
1489
1490 _mem6809_read_tab_ptr = _mem6809_read_tab;
1491 _mem6809_write_tab_ptr = _mem6809_write_tab;
1492 }
1493
1494 maincpu_resync_limits();
1495 }
1496
mem_mmu_translate(unsigned int addr,uint8_t ** base,int * start,int * limit)1497 void mem_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit)
1498 {
1499 uint8_t *p = _mem_read_base_tab_ptr[addr >> 8];
1500
1501 *base = (p == NULL) ? NULL : (p - (addr & 0xff00));
1502 *start = addr; /* TODO */
1503 *limit = mem_read_limit_tab_ptr[addr >> 8];
1504 }
1505
mem_powerup(void)1506 void mem_powerup(void)
1507 {
1508 int i;
1509 ram_init(mem_ram, RAM_ARRAY);
1510 /*
1511 * A more realistic initial memory is random.
1512 * Especially on the screen, which is different memory in most
1513 * models.
1514 * (And it helps a bit with the colour option when a proper editor
1515 * ROM isn't installed)
1516 *
1517 * FIXME: use memory init pattern
1518 *
1519 */
1520 for (i = 0; i < 0x1000; i++) {
1521 mem_ram[0x8000 + i] = (uint8_t)lib_unsigned_rand(0, 255);
1522 }
1523
1524 superpet_mem_powerup();
1525 }
1526
1527 /* ------------------------------------------------------------------------- */
1528
mem_get_basic_text(uint16_t * start,uint16_t * end)1529 void mem_get_basic_text(uint16_t *start, uint16_t *end)
1530 {
1531 int basicstart;
1532
1533 /* FIXME: should really check a basic_checksum */
1534 if (petres.kernal_checksum == PET_KERNAL1_CHECKSUM) {
1535 basicstart = 0x7a;
1536 } else {
1537 basicstart = 0x28;
1538 }
1539
1540 if (start != NULL) {
1541 *start = mem_ram[basicstart] | (mem_ram[basicstart + 1] << 8);
1542 }
1543 if (end != NULL) {
1544 *end = mem_ram[basicstart + 2] | (mem_ram[basicstart + 3] << 8);
1545 }
1546 }
1547
mem_set_basic_text(uint16_t start,uint16_t end)1548 void mem_set_basic_text(uint16_t start, uint16_t end)
1549 {
1550 int basicstart, loadadr;
1551
1552 if (petres.kernal_checksum == PET_KERNAL1_CHECKSUM) {
1553 basicstart = 0x7a; /* Pointers to Basic program + variables */
1554 loadadr = 0xe3; /* Utility pointers for start and end of load */
1555 } else {
1556 basicstart = 0x28;
1557 loadadr = 0xc7;
1558 }
1559
1560 mem_ram[basicstart] = mem_ram[loadadr] = start & 0xff;
1561 mem_ram[basicstart + 1] = mem_ram[loadadr + 1] = start >> 8;
1562
1563 mem_ram[basicstart + 2] =
1564 mem_ram[basicstart + 4] =
1565 mem_ram[basicstart + 6] = mem_ram[loadadr + 2] = end & 0xff;
1566 mem_ram[basicstart + 3] =
1567 mem_ram[basicstart + 5] =
1568 mem_ram[basicstart + 7] = mem_ram[loadadr + 3] = end >> 8;
1569 }
1570
mem_inject(uint32_t addr,uint8_t value)1571 void mem_inject(uint32_t addr, uint8_t value)
1572 {
1573 /* just call mem_store() to be safe.
1574 This could possibly be changed to write straight into the
1575 memory array. mem_ram[addr & mask] = value; */
1576 mem_store((uint16_t)(addr & 0xffff), value);
1577 }
1578
1579 /* ------------------------------------------------------------------------- */
1580
mem_rom_trap_allowed(uint16_t addr)1581 int mem_rom_trap_allowed(uint16_t addr)
1582 {
1583 return (addr >= 0xf000) && !(petmem_map_reg & 0x80);
1584 }
1585
1586 /* ------------------------------------------------------------------------- */
1587
1588 /* Banked memory access functions for the monitor. */
1589
peek_bank_io(uint16_t addr)1590 static uint8_t peek_bank_io(uint16_t addr)
1591 {
1592 uint8_t v1, v2, v3, v4;
1593
1594 switch (addr & 0xf0) {
1595 case 0x10: /* PIA1 */
1596 return pia1_peek(addr);
1597 case 0x20: /* PIA2 */
1598 return pia2_peek(addr);
1599 case 0x40:
1600 return via_peek(addr); /* VIA */
1601 case 0x80: /* CRTC */
1602 if (petres.crtc) {
1603 return crtc_read(addr);
1604 }
1605 /* FALL THROUGH */
1606 case 0x00:
1607 return addr >> 8;
1608 default: /* 0x30, 0x50, 0x60, 0x70, 0x90-0xf0 */
1609 break;
1610 }
1611
1612 if (addr & 0x10) {
1613 v1 = pia1_peek(addr);
1614 } else {
1615 v1 = 0xff;
1616 }
1617 if (addr & 0x20) {
1618 v2 = pia2_peek(addr);
1619 } else {
1620 v2 = 0xff;
1621 }
1622 if (addr & 0x40) {
1623 v3 = via_peek(addr);
1624 } else {
1625 v3 = 0xff;
1626 }
1627 v4 = 0xff;
1628 if ((addr & 0x80) && petres.crtc) {
1629 v4 = crtc_read(addr);
1630 }
1631 return v1 & v2 & v3 & v4;
1632 }
1633
1634 /* Exported banked memory access functions for the monitor. */
1635
1636 static const char *banknames[] = {
1637 "default", "cpu", "ram", "rom", "io", "extram", "6809", NULL
1638 };
1639
1640 enum {
1641 bank_default, bank_cpu = 0, bank_ram, bank_rom, bank_io, bank_extram,
1642 bank_cpu6809
1643 };
1644
1645 static const int banknums[] = {
1646 bank_default, bank_cpu, bank_ram, bank_rom, bank_io, bank_extram,
1647 bank_cpu6809,
1648 };
1649
mem_bank_list(void)1650 const char **mem_bank_list(void)
1651 {
1652 return banknames;
1653 }
1654
mem_bank_from_name(const char * name)1655 int mem_bank_from_name(const char *name)
1656 {
1657 int i = 0;
1658
1659 while (banknames[i]) {
1660 if (!strcmp(name, banknames[i])) {
1661 return banknums[i];
1662 }
1663 i++;
1664 }
1665 return -1;
1666 }
1667
mem_bank_read(int bank,uint16_t addr,void * context)1668 uint8_t mem_bank_read(int bank, uint16_t addr, void *context)
1669 {
1670 switch (bank) {
1671 case bank_default: /* current */
1672 return mem_read(addr);
1673 break;
1674 case bank_extram: /* extended RAM area (8x96, SuperPET) */
1675 return mem_ram[addr + EXT_RAM];
1676 break;
1677 case bank_io: /* io */
1678 if (addr >= 0xe800 && addr < 0xe900) {
1679 return read_io_e8(addr);
1680 }
1681 if (petres.superpet && (addr & 0xff00) == 0xef00) {
1682 return read_super_io(addr);
1683 }
1684 if (addr >= 0xe900 && addr < 0xe800 + petres.IOSize) {
1685 return read_io_e9_ef(addr);
1686 }
1687 /* FALL THROUGH */
1688 case bank_rom: /* rom */
1689 if (addr >= 0x9000) {
1690 return mem_rom[addr & 0x7fff];
1691 }
1692 break;
1693 case bank_cpu6809: /* 6809 */
1694 return mem6809_read(addr);
1695 case bank_ram: /* ram */
1696 break;
1697 }
1698 return mem_ram[addr];
1699 }
1700
mem_bank_peek(int bank,uint16_t addr,void * context)1701 uint8_t mem_bank_peek(int bank, uint16_t addr, void *context)
1702 {
1703 switch (bank) {
1704 case bank_default: /* current */
1705 return mem_read(addr); /* FIXME */
1706 break;
1707 case bank_io: /* io */
1708 if (addr >= 0xe800 && addr < 0xe900) {
1709 return peek_bank_io(addr);
1710 }
1711 if (petres.superpet && (addr & 0xff00) == 0xef00) {
1712 return read_super_io(addr);
1713 }
1714 if (addr >= 0xe900 && addr < 0xe800 + petres.IOSize) {
1715 uint8_t result;
1716 /* is_peek_access = 1; FIXME */
1717 result = read_unused(addr);
1718 /* is_peek_access = 0; FIXME */
1719 return result;
1720 }
1721 }
1722 return mem_bank_read(bank, addr, context);
1723 }
1724
mem_bank_write(int bank,uint16_t addr,uint8_t byte,void * context)1725 void mem_bank_write(int bank, uint16_t addr, uint8_t byte, void *context)
1726 {
1727 switch (bank) {
1728 case bank_default: /* current */
1729 mem_store(addr, byte);
1730 return;
1731 case bank_extram: /* extended RAM area (8x96, SuperPET) */
1732 mem_ram[addr + EXT_RAM] = byte;
1733 return;
1734 case bank_io: /* io */
1735 if (addr >= 0xe800 && addr < 0xe900) {
1736 store_io_e8(addr, byte);
1737 return;
1738 }
1739 if (petres.superpet && (addr & 0xff00) == 0xef00) {
1740 store_super_io(addr, byte);
1741 return;
1742 }
1743 if (addr >= 0xe900 && addr < 0xe800 + petres.IOSize) {
1744 store_io_e9_ef(addr, byte);
1745 return;
1746 }
1747 /* FALL THROUGH */
1748 case bank_rom: /* rom */
1749 if (addr >= 0x9000) {
1750 return;
1751 }
1752 break;
1753 case bank_cpu6809: /* rom */
1754 mem6809_store(addr, byte);
1755 return;
1756 case 1: /* ram */
1757 break;
1758 }
1759 mem_ram[addr] = byte;
1760 }
1761
mem_dump_io(void * context,uint16_t addr)1762 static int mem_dump_io(void *context, uint16_t addr)
1763 {
1764 if ((addr >= 0xe810) && (addr <= 0xe81f)) {
1765 return pia1_dump();
1766 } else if ((addr >= 0xe820) && (addr <= 0xe82f)) {
1767 return pia2_dump();
1768 } else if ((addr >= 0xe840) && (addr <= 0xe84f)) {
1769 return viacore_dump(machine_context.via);
1770 } else if ((addr >= 0xe880) && (addr <= 0xe881)) {
1771 if (petres.crtc) {
1772 return crtc_dump();
1773 }
1774 } else if (addr == 0xe888) {
1775 return e888_dump();
1776 } else if ((addr >= 0xeb00) && (addr <= 0xeb0f)) {
1777 if (petdww_enabled) {
1778 return petdwwpia_dump();
1779 }
1780 } else if (addr == 0xfff0) {
1781 if (petres.map) {
1782 return fff0_dump();
1783 }
1784 }
1785 if (petres.superpet) {
1786 if (addr >= 0xefe0 && addr <= 0xefe3) {
1787 return efe0_dump();
1788 } else if (addr >= 0xeff0 && addr <= 0xeff3) {
1789 /* ACIA */
1790 /* return aciacore_dump(); */
1791 } else if (addr == 0xeff8) {
1792 /* Control switch */
1793 mon_out("CPU: %s\n",
1794 petres.superpet_cpu_switch == SUPERPET_CPU_6502 ? "6502" :
1795 petres.superpet_cpu_switch == SUPERPET_CPU_6809 ? "6809" :
1796 "PROG (unimpl)");
1797 mon_out("RAM write protect: $%x\n", spet_ramwp);
1798 mon_out("diagnostic sense: $%x\n", spet_diag);
1799 return 0;
1800 } else if (addr == 0xeffc) {
1801 /* Bank select */
1802 mon_out("bank: $%x\n", spet_bank);
1803 mon_out("control write protect: %d\n", spet_ctrlwp);
1804 mon_out("flat (super-os9) mode: %d\n", !!spet_flat_mode);
1805 mon_out("firq disabled: %d\n", !!spet_firq_disabled);
1806 return 0;
1807 } else if (addr == 0xeffe) {
1808 /* RAM/ROM switch */
1809 mon_out("ram_enable: %d\n", spet_ramen);
1810 return 0;
1811 }
1812 }
1813 return -1;
1814 }
1815
mem_ioreg_list_get(void * context)1816 mem_ioreg_list_t *mem_ioreg_list_get(void *context)
1817 {
1818 mem_ioreg_list_t *mem_ioreg_list = NULL;
1819
1820 io_source_ioreg_add_list(&mem_ioreg_list);
1821 mon_ioreg_add_list(&mem_ioreg_list, "PIA1", 0xe810, 0xe81f, mem_dump_io, NULL);
1822 mon_ioreg_add_list(&mem_ioreg_list, "PIA2", 0xe820, 0xe82f, mem_dump_io, NULL);
1823 mon_ioreg_add_list(&mem_ioreg_list, "VIA", 0xe840, 0xe84f, mem_dump_io, NULL);
1824 if (petres.crtc) {
1825 mon_ioreg_add_list(&mem_ioreg_list, "CRTC", 0xe880, 0xe881, mem_dump_io, NULL);
1826 }
1827 if (pethre_enabled) {
1828 mon_ioreg_add_list(&mem_ioreg_list, "HRE", 0xe888, 0xe888, mem_dump_io, NULL);
1829 }
1830 if (petres.map) {
1831 mon_ioreg_add_list(&mem_ioreg_list, "8096", 0xfff0, 0xfff0, mem_dump_io, NULL);
1832 }
1833 if (petres.superpet) {
1834 mon_ioreg_add_list(&mem_ioreg_list, "6702", 0xefe0, 0xefe3, mem_dump_io, NULL);
1835 mon_ioreg_add_list(&mem_ioreg_list, "ACIA", 0xeff0, 0xeff3, mem_dump_io, NULL);
1836 mon_ioreg_add_list(&mem_ioreg_list, "Control", 0xeff8, 0xeff8, mem_dump_io, NULL);
1837 mon_ioreg_add_list(&mem_ioreg_list, "Bank", 0xeffc, 0xeffc, mem_dump_io, NULL);
1838 mon_ioreg_add_list(&mem_ioreg_list, "RAM/ROM", 0xeffe, 0xeffe, mem_dump_io, NULL);
1839 }
1840
1841 return mem_ioreg_list;
1842 }
1843
petmem_get_screen_columns(void)1844 int petmem_get_screen_columns(void)
1845 {
1846 int cols;
1847
1848 cols = petres.video;
1849 if (!cols) {
1850 cols = petres.rom_video;
1851 if (!cols) {
1852 cols = PET_COLS;
1853 }
1854 }
1855
1856 return cols;
1857 }
1858
petmem_get_rom_columns(void)1859 int petmem_get_rom_columns(void)
1860 {
1861 return petres.rom_video;
1862 }
1863
mem_get_screen_parameter(uint16_t * base,uint8_t * rows,uint8_t * columns,int * bank)1864 void mem_get_screen_parameter(uint16_t *base, uint8_t *rows, uint8_t *columns, int *bank)
1865 {
1866 *base = 0x8000;
1867 *rows = 25;
1868 *columns = (uint8_t)petmem_get_screen_columns();
1869 *bank = 0;
1870 }
1871
1872 /************************** PET resource handling ************************/
1873
1874 /* check PetInfo struct for consistency after change? */
1875
petmem_check_info(petres_t * pi)1876 void petmem_check_info(petres_t *pi)
1877 {
1878 if (pi->video == 40 || (pi->video == 0 && pi->rom_video == 40)) {
1879 pi->vmask = 0x3ff;
1880 pi->videoSize = 0x400;
1881 } else {
1882 pi->vmask = 0x7ff;
1883 pi->videoSize = 0x800;
1884 }
1885
1886 if (pi->ramSize == 128) {
1887 pi->vmask = 0x1fff;
1888 pi->videoSize = 0x1000;
1889 }
1890 }
1891
1892 /* dummy function to satisfy the global cartridge system */
cartridge_attach_image(int type,const char * name)1893 int cartridge_attach_image(int type, const char *name)
1894 {
1895 return -1;
1896 }
1897