This is petmem.c in view mode; [Download] [Up]
/* * petmem.c - PET memory handling. * * Written by * Ettore Perazzoli (ettore@comm2000.it) * André Fachat (fachat@physik.tu-chemnitz.de) * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA. * */ #ifndef PET #define PET /* for mkdep */ #endif #include "vice.h" #include <stdio.h> #include "types.h" #include "memutils.h" #include "pia.h" #include "pet.h" #include "petvia.h" #include "crtc.h" #include "kbd.h" #include "kbdbuf.h" #include "autostart.h" #include "resources.h" #include "cmdline.h" #include "tapeunit.h" #include "pets.h" #include "interrupt.h" #include "vmachine.h" #include "maincpu.h" #include "petmem.h" #include "emuid.h" #include "utils.h" /* ------------------------------------------------------------------------- */ /* The PET memory. */ #define RAM_ARRAY 0x20000 /* this includes 8x96 expansion RAM */ BYTE ram[RAM_ARRAY]; /* 128K to make things easier. Real size is 4-128K. */ BYTE rom[PET_ROM_SIZE]; BYTE chargen_rom[PET_CHARGEN_ROM_SIZE]; int ram_size = RAM_ARRAY; /* FIXME? */ /* Memory read and write tables. */ read_func_ptr_t _mem_read_tab[0x101]; store_func_ptr_t _mem_write_tab[0x101]; read_func_ptr_t _mem_read_tab_watch[0x101]; store_func_ptr_t _mem_write_tab_watch[0x101]; BYTE *_mem_read_base_tab[0x101]; read_func_ptr_t *_mem_read_tab_ptr; store_func_ptr_t *_mem_write_tab_ptr; BYTE **_mem_read_base_tab_ptr; /* Flag: nonzero if the ROM has been loaded. */ int rom_loaded = 0; /* CRTC register pointer. */ static BYTE crtc_ptr = 0; /* 8x96 mapping register */ static BYTE map_reg = 0; static int bank8offset = 0; static int bankCoffset = 0; #define IS_NULL(s) (s == NULL || *s == '\0') /* prototype */ void set_screen(void); static trap_t pet4_tape_traps[]; static trap_t pet3_tape_traps[]; static trap_t pet2_tape_traps[]; /* ------------------------------------------------------------------------- */ /* Flag: Do we enable the Emulator ID? */ static int emu_id_enabled; static int set_emu_id_enabled(resource_value_t v) { emu_id_enabled = (int)v; return 0; } /* Enable/disable the Emulator ID. */ void mem_toggle_emu_id(int flag) { emu_id_enabled = flag; } static resource_t resources[] = { { "EmuID", RES_INTEGER, (resource_value_t) 0, (resource_value_t *) &emu_id_enabled, set_emu_id_enabled }, { NULL } }; int pet_mem_init_resources(void) { return resources_register(resources); } static cmdline_option_t cmdline_options[] = { { "-emuid", SET_RESOURCE, 0, NULL, NULL, "EmuID", (resource_value_t) 1, NULL, "Enable emulator identification" }, { "+emuid", SET_RESOURCE, 0, NULL, NULL, "EmuID", (resource_value_t) 0, NULL, "Disable emulator identification" }, { NULL } }; int pet_mem_init_cmdline_options(void) { return cmdline_register_options(cmdline_options); } /* ------------------------------------------------------------------------- */ BYTE REGPARM1 read_zero(ADDRESS addr) { return ram[addr & 0xff]; } void REGPARM2 store_zero(ADDRESS addr, BYTE value) { ram[addr & 0xff] = value; } BYTE REGPARM1 read_ram(ADDRESS addr) { return ram[addr]; } void REGPARM2 store_ram(ADDRESS addr, BYTE value) { ram[addr] = value; } static BYTE REGPARM1 read_ext8(ADDRESS addr) { return ram[addr + bank8offset]; } static void REGPARM2 store_ext8(ADDRESS addr, BYTE value) { ram[addr + bank8offset] = value; } static BYTE REGPARM1 read_extC(ADDRESS addr) { return ram[addr + bankCoffset]; } static void REGPARM2 store_extC(ADDRESS addr, BYTE value) { ram[addr + bankCoffset] = value; } static BYTE REGPARM1 read_vmirror(ADDRESS addr) { return ram[0x8000 + (addr & (pet.videoSize - 1))]; } static void REGPARM2 store_vmirror(ADDRESS addr, BYTE value) { ram[0x8000 + (addr & (pet.videoSize - 1))] = value; } BYTE REGPARM1 read_rom(ADDRESS addr) { return rom[addr & 0x7fff]; } void REGPARM2 store_rom(ADDRESS addr, BYTE value) { rom[addr & 0x7fff] = value; } static BYTE REGPARM1 read_unused(ADDRESS addr) { return (addr >> 8) & 0xff; } /* ------------------------------------------------------------------------- */ /* Functions for watchpoint memory access. */ BYTE REGPARM1 read_watch(ADDRESS addr) { mon_watch_push_load_addr(addr, e_comp_space); return _mem_read_tab[addr >> 8](addr); } void REGPARM2 store_watch(ADDRESS addr, BYTE value) { mon_watch_push_store_addr(addr, e_comp_space); _mem_write_tab[addr >> 8](addr, value); } /* ------------------------------------------------------------------------- */ /* Generic memory access. */ void REGPARM2 mem_store(ADDRESS addr, BYTE value) { _mem_write_tab_ptr[addr >> 8](addr, value); } BYTE REGPARM1 mem_read(ADDRESS addr) { return _mem_read_tab_ptr[addr >> 8](addr); } /* ------------------------------------------------------------------------- */ /* The PET have all I/O chips connected to the same select lines. Only one address lines is used as separate (high-active) select input. I.e. PIA1 always reacts when address & 0x10 is high, for example $e810, $e830, $e850, etc. PIA2 reacts when address & 0x20 is high, for example $e820, $e830 $e860,... The next two functions try to reflect this behaviour. */ /* When we write, we write all involved chips. */ void REGPARM2 store_io(ADDRESS addr, BYTE value) { if (addr & 0x10) store_pia1(addr, value); if (addr & 0x20) store_pia2(addr, value); if (addr & 0x40) store_via(addr, value); if ((addr & 0x80) && pet.crtc) { if (addr & 1) store_crtc(crtc_ptr, value); else crtc_ptr = value; } } /* * When we read, we only read sensible values. In real operation, * the bus drivers of all involved chips interact and you get strange * results... */ BYTE REGPARM1 read_io(ADDRESS addr) { BYTE v1, v2, v3, v4; if (emu_id_enabled && addr >= 0xE8A0) { addr &= 0xff; if (addr == 0xff) emulator_id[addr - 0xa0] ^= 0xff; return emulator_id[addr - 0xa0]; } switch (addr & 0xf0) { case 0x10: /* PIA1 */ return read_pia1(addr); case 0x20: /* PIA2 */ return read_pia2(addr); case 0x40: return read_via(addr); /* VIA */ case 0x80: /* CRTC */ if (pet.crtc) { if (addr & 1) return read_crtc(crtc_ptr); else return 0x9f; /* Status. */ } case 0x00: return addr >> 8; default: /* 0x30, 0x50, 0x60, 0x70, 0x90-0xf0 */ if (addr & 0x10) v1 = read_pia1(addr); else v1 = 0xff; if (addr & 0x20) v2 = read_pia2(addr); else v2 = 0xff; if (addr & 0x40) v3 = read_via(addr); else v3 = 0xff; v4 = 0xff; if ((addr & 0x80) && pet.crtc) { if (addr & 1) v4 = read_crtc(crtc_ptr); else v4 = 0x9f; /* Status. */ } return v1 & v2 & v3 & v4; } } static void REGPARM2 store_dummy(ADDRESS addr, BYTE value) { return; } /* * This sets the standard PET memory configuration from $9000-$10000. * It is used in store_8x96() and initialize_memory(). */ static void set_std_9tof(void) { int i, l; static void (*store)(ADDRESS, BYTE); int ram9, rama; store = (pet.map == 2) ? store_ram : store_dummy; ram9 = (pet.map == 2 && pet.mem9) ? 1 : 0; rama = (pet.map == 2 && pet.memA) ? 1 : 0; /* Setup RAM/ROM at $9000 - $9FFF. */ for (i = 0x90; i < 0xa0; i++) { _mem_read_tab[i] = ram9 ? read_ram : read_rom; _mem_write_tab[i] = store; _mem_read_base_tab[i] = ram9 ? ram + (i << 8) : rom + ((i & 0x7f) << 8); } /* Setup RAM/ROM at $9000 - $9FFF. */ for (i = 0xa0; i < 0xb0; i++) { _mem_read_tab[i] = rama ? read_ram : read_rom; _mem_write_tab[i] = store; _mem_read_base_tab[i] = rama ? ram + (i << 8) : rom + ((i & 0x7f) << 8); } /* Setup ROM at $B000 - $E7FF. */ for (i = 0xb0; i <= 0xe7; i++) { _mem_read_tab[i] = read_rom; _mem_write_tab[i] = store; _mem_read_base_tab[i] = rom + ((i & 0x7f) << 8); } l = ((0xe800 + pet.IOSize) >> 8) & 0xff; /* Setup I/O at $e800 - $e800 + pet.IOSize. */ /* i.e. IO at $e800... */ _mem_read_tab[0xe8] = read_io; _mem_write_tab[0xe8] = store_io; _mem_read_base_tab[0xe8] = NULL; /* ... and unused address space behind it */ for (i = 0xe9; i < l; i++) { _mem_read_tab[i] = read_unused; _mem_write_tab[i] = store; _mem_read_base_tab[i] = NULL;; } /* Setup ROM at $e800 + pet.IOSize - $ffff */ for (i = l; i <= 0xff; i++) { _mem_read_tab[i] = read_rom; _mem_write_tab[i] = store; _mem_read_base_tab[i] = rom + ((i & 0x7f) << 8); } _mem_read_base_tab_ptr = _mem_read_base_tab; } /* FIXME: TODO! */ void mem_toggle_watchpoints(int flag) { if (flag) { _mem_read_tab_ptr = _mem_read_tab_watch; _mem_write_tab_ptr = _mem_write_tab_watch; } else { _mem_read_tab_ptr = _mem_read_tab; _mem_write_tab_ptr = _mem_write_tab; } } /* * From the PETio.doc (ftp.funet.fi/firmware/pet/) * * $fff0 register in PET 8x96 * 8096 exp-mem (64K): * The control register is at $FFF0/65520 * You have 4 16K-banks, 0...3 * * $8000 $9000 $C000 $E800 $F000 $FFFF * !----------------------------!!--------------------------------------! * Bank 0 or 2 Bank 1 or 3 * !--------! !-------! * screen io * * Control Register $FFF0: * bit 7: 0 normal 8032 configuration (screen, ROMs, IO, ROMs) * 80 expansion memory * bit 6: 0 RAM $E800-$EFFF (only when bit7=1) * 40 IO peek through * bit 5: 0 exp-mem $8000-$8FFF (-"-) * 20 screen peek through * bit 4: 10 not used * bit 3: 0 bank 1 $C000-$FFFF * 08 bank 3 * bit 2: 0 bank 0 $8000-$BFFF * 04 bank 2 * bit 1: 02 write protect bank 1/3 * bit 0: 01 write protect bank 0/2 * when bit7=0, all other bits are ignored * * The missing 32K can't be accessed witout hardware modifications. * You can only use the 2K "behind" the screen $8800-$8FFF (exact: 34768- * 36863), available in the normal configuration. * The register is write-only, and the value is written through to the * previously selected ram bank. * */ /* Save old store function for last byte. */ static void REGPARM2 (*store_ff)(ADDRESS addr, BYTE value) = NULL; /* Write to last page of memory in 8x96. */ static void REGPARM2 store_8x96(ADDRESS addr, BYTE value) { BYTE changed; int l, protected; if (store_ff) store_ff(addr, value); changed = map_reg ^ value; if (addr == 0xfff0 && changed && ((map_reg | changed) & 0x80)) { #if 0 printf("Change $fff0 to %02x\n", value); #endif if (value & 0x80) { /* ext. RAM enabled */ if (changed & 0xa5) { /* $8000-$bfff */ protected = value & 0x01; l = 0x80; if (value & 0x20) { /* screen memory mapped through */ for (; l < 0x90; l++) { _mem_read_tab[l] = read_ram; _mem_write_tab[l] = store_ram; _mem_read_base_tab[l] = ram + (l << 8); } } bank8offset = 0x8000 + ((value & 0x04) ? 0x8000 : 0); for (; l < 0xc0; l++) { _mem_read_tab[l] = read_ext8; if (protected) _mem_write_tab[l] = store_dummy; else _mem_write_tab[l] = store_ext8; _mem_read_base_tab[l] = ram + bank8offset + (l << 8); } } if (changed & 0xca) { /* $c000-$ffff */ protected = value & 0x02; bankCoffset = 0x8000 + ((value & 0x08) ? 0x8000 : 0); for (l = 0xc0; l < 0x100; l++) { if ((l == 0xe8) && (value & 0x40)) { _mem_read_tab[l] = read_io; _mem_write_tab[l] = store_io; _mem_read_base_tab[l] = NULL; } else { _mem_read_tab[l] = read_extC; if (protected) _mem_write_tab[l] = store_dummy; else _mem_write_tab[l] = store_extC; _mem_read_base_tab[l] = ram + bankCoffset + (l << 8); } } store_ff = _mem_write_tab[0xff]; _mem_write_tab[0xff] = store_8x96; } } else { /* disable ext. RAM */ for (l = 0x80; l < 0x90; l++) { _mem_read_tab[l] = read_ram; _mem_write_tab[l] = store_ram; _mem_read_base_tab[l] = ram + (l << 8); } set_std_9tof(); store_ff = _mem_write_tab[0xff]; _mem_write_tab[0xff] = store_8x96; } map_reg = value; } return; } /* ------------------------------------------------------------------------- */ /* This does the plain 8032 configuration, as 8096 stuff only comes up when writing to $fff0. */ void initialize_memory(void) { int i, l; l = pet.ramSize << 2; /* ramSize in kB, l in 256 Byte */ if (l > 128) l = 128; /* fix 8096 / 8296 */ /*printf("PET: initialize memory, ramSize=%04x -> l=%d\n", pet.ramSize * 1024,l); */ /* Setup RAM from $0000 to pet.ramSize */ for (i = 0x00; i < l; i++) { _mem_read_tab[i] = read_ram; _mem_write_tab[i] = store_ram; _mem_read_base_tab[i] = ram + (i << 8); } /* Setup unused from pet.ramSize to $7fff */ for (i = l; i < 0x80; i++) { _mem_read_tab[i] = read_unused; _mem_write_tab[i] = store_dummy; _mem_read_base_tab[i] = NULL; } l = ((0x8000 + pet.videoSize) >> 8) & 0xff; /* Setup RAM from $8000 to $8000 + pet.videoSize */ for (i = 0x80; i < l; i++) { _mem_read_tab[i] = read_ram; _mem_write_tab[i] = store_ram; _mem_read_base_tab[i] = ram + (i << 8); } /* Setup unused from $8000 + pet.videoSize to $87ff */ /* falls through if videoSize >= 0x800 */ for (; i < 0x88; i++) { _mem_read_tab[i] = read_vmirror; _mem_write_tab[i] = store_vmirror; _mem_read_base_tab[i] = ram + 0x8000 + ((i << 8) & (pet.videoSize - 1)); } /* Setup unused from $8800 to $8fff */ /* falls through if videoSize >= 0x1000 */ for (; i < 0x90; i++) { _mem_read_tab[i] = read_unused; _mem_write_tab[i] = store_dummy; _mem_read_base_tab[i] = NULL; } set_std_9tof(); if (pet.map) { /* catch writes to $fff0 register */ store_ff = _mem_write_tab[0xff]; _mem_write_tab[0xff] = store_8x96; } if (pet.pet2k) { /* map in IEEE488 bug fixes */ _mem_read_tab[0xef] = read_rom; _mem_read_base_tab[0xef] = rom + ((0xef & 0x7f) << 8); } _mem_read_tab[0x100] = _mem_read_tab[0]; _mem_write_tab[0x100] = _mem_write_tab[0]; _mem_read_base_tab[0x100] = _mem_read_base_tab[0]; map_reg = 0; ram_size = pet.ramSize * 1024; _mem_read_tab_ptr = _mem_read_tab; _mem_write_tab_ptr = _mem_write_tab; for (i = 0; i < 0x101; i++) { _mem_read_tab_watch[i] = read_watch; _mem_write_tab_watch[i] = store_watch; } } /* ------------------------------------------------------------------------- */ void patch_2001(void) { int i; int rp; char dat0[] = {0xa9, 0x60, 0x85, 0xf0, 0x60}; char dat1[] = {0x20, 0xb6, 0xf0, 0xa5, 0xf0, 0x20, 0x5b, 0xf1, 0x20, 0x87, 0xf1, 0x85, 0xf7, 0x20, 0x87, 0xf1, 0x85, 0xf8, 0x60}; char dat2[] = {0x20, 0x7a, 0xf1, 0x20, 0xe6, 0xf6, 0xad, 0x0b, 0x02, 0x60}; char dat3[] = {0xa9, 0x61, 0x85, 0xf0, 0x60}; char dat4[] = {0x20, 0xba, 0xf0, 0xa5, 0xf0, 0x20, 0x2c, 0xf1, 0xa5, 0xf7, 0x20, 0x67, 0xf1, 0xa5, 0xf8, 0x4c, 0x67, 0xf1}; char dat5[] = {0xae, 0x0c, 0x02, 0x70, 0x46, 0x20, 0x87, 0xf1}; char dat6[] = {0x20, 0x2c, 0xf1, 0x4c, 0x7e, 0xf1}; printf("PET: patching 2001 ROM to make IEEE488 work!\n"); /* Patch PET2001 IEEE488 routines to make them work */ rom[0x7471] = rom[0x7472] = 0xea; /* NOP */ rom[0x7180] = rom[0x7181] = 0xea; /* NOP */ rom[0x73ef] = 0xf8; rom[0x73f3] = 0xf7; rp = 0x6f00; /* $ef00 */ rom[0x7370] = rp & 0xff; rom[0x7371] = ((rp >> 8) & 0xff) | 0x80; for (i = 0; i < 5; i++) rom[rp++] = dat0[i]; rom[0x7379] = rp & 0xff; rom[0x737a] = ((rp >> 8) & 0xff) | 0x80; for (i = 0; i < 19; i++) rom[rp++] = dat1[i]; rom[0x73cc] = 0x20; rom[0x73cd] = rp & 0xff; rom[0x73ce] = ((rp >> 8) & 0xff) | 0x80; for (i = 0; i < 10; i++) rom[rp++] = dat2[i]; for (i = 0; i < 8; i++) rom[0x7381 + i] = dat5[i]; rom[0x76c1] = rp & 0xff; rom[0x76c2] = ((rp >> 8) & 0xff) | 0x80; for (i = 0; i < 5; i++) rom[rp++] = dat3[i]; rom[0x76c7] = rp & 0xff; rom[0x76c8] = ((rp >> 8) & 0xff) | 0x80; for (i = 0; i < 18; i++) rom[rp++] = dat4[i]; rom[0x76f4] = rp & 0xff; rom[0x76f5] = ((rp >> 8) & 0xff) | 0x80; for (i = 0; i < 6; i++) rom[rp++] = dat6[i]; strcpy(rom + rp, "vice pet2001 rom patch $ef00-$efff"); } void mem_powerup(void) { int i; #ifndef __MSDOS__ printf("Initializing RAM for power-up...\n"); #endif for (i = 0; i < RAM_ARRAY; i += 0x80) { memset(ram + i, 0, 0x40); memset(ram + i + 0x40, 0xff, 0x40); } } /* Load memory image files. This also selects the PET model. */ int mem_load(void) { WORD sum; /* ROM checksum */ int i; int rsize, krsize; /* De-initialize kbd-buf, autostart and tape stuff here before reloading the ROM the traps are installed in. */ kbd_buf_init(0, 0, 0, 0); autostart_init(0, 0, 0, 0, 0, 0); tape_init(0, 0, 0, 0, 0, 0, 0, NULL, 0, 0); /* Load chargen ROM - we load 2k, and generate the inverted 2k. */ if (mem_load_sys_file(pet.chargenName, chargen_rom, 2048, 2048) < 0) { fprintf(stderr, "Couldn't load character ROM.\n"); return -1; } /* Copy graphics charom to second part. */ memmove(chargen_rom + 2048, chargen_rom + 1024, 1024); if (pet.pet2k) { int j; /* If pet2001 then exchange upper and lower case letters. */ for (i = 8; i < (0x1b * 8); i++) { j = chargen_rom[0x800 + i]; chargen_rom[i + 0x800] = chargen_rom[i + 0xa00]; chargen_rom[i + 0xa00] = j; } } /* Inverted chargen into second half. This is a PET hardware feature. */ for (i = 0; i < 1024; i++) { chargen_rom[i + 1024] = chargen_rom[i] ^ 0xff; chargen_rom[i + 3072] = chargen_rom[i + 2048] ^ 0xff; } /* Init ROM with 'unused address' values. */ for (i = 0; i < PET_ROM_SIZE; i++) { rom[i] = 0x80 + ((i >> 8) & 0xff); } /* Load Kernal ROM. */ { const char *name = /* (IS_NULL(kernal_rom_name) ? */ pet.kernalName /*: kernal_rom_name) */ ; if ((krsize = mem_load_sys_file(name, rom, 0x2000, PET_ROM_SIZE)) < 0) { fprintf(stderr, "Couldn't load ROM `%s'.\n\n", name); return -1; } } /* Load extension ROMs. */ #if 0 if (!IS_NULL(basic_rom_name) && ((rsize = mem_load_sys_file(basic_rom_name, rom + 0x3000, 0x2000, 0x3000)) < 0)) { fprintf(stderr, "Couldn't load ROM `%s'.\n\n", basic_rom_name); return -1; } #endif { const char *name = pet.editorName; if (!IS_NULL(name) && ((rsize = mem_load_sys_file(name, rom + 0x6000, 0x0800, 0x0800)) < 0)) { fprintf(stderr, "Couldn't load ROM `%s'.\n\n", name); return -1; } } if (!IS_NULL(pet.mem9name) && ((rsize = mem_load_sys_file(pet.mem9name, rom + 0x1000, 0x1000, 0x1000)) < 0)) { fprintf(stderr, "Couldn't load ROM `%s'.\n\n", pet.mem9name); return -1; } if (!IS_NULL(pet.memAname) && ((rsize = mem_load_sys_file(pet.memAname, rom + 0x2000, 0x1000, 0x1000)) < 0)) { fprintf(stderr, "Couldn't load ROM `%s'.\n\n", pet.memAname); return -1; } if (!IS_NULL(pet.memBname)) { if (krsize <= 0x4000) { if ((rsize = mem_load_sys_file(pet.memBname, rom + 0x3000, 0x1000, 0x1000)) < 0) { fprintf(stderr, "Couldn't load ROM `%s'.\n\n", pet.memBname); return -1; } } else { printf("PET: internal ROM too large for extension ROM at $b000 - " "ignoring `%s'\n", pet.memBname); } } /* Checksum over top 4 kByte PET kernal. */ for (i = 0x7000, sum = 0; i < 0x8000; i++) sum += rom[i]; /* 4032 and 8032 have the same kernals, so we have to test more, here $E000 - $E800. */ for (i = 0x6000; i < 0x6800; i++) sum += rom[i]; printf("PET: Loaded ROM, checksum is %d ($%04X).\n", sum, sum); if (pet.pet2k) { if (sum != PET2001_CHECKSUM) { printf("PET2001 model chosen, but ROM is unknown. Cannot patch IEEE488!\n"); } else { patch_2001(); } } pet.screen_width = 0; /* The length of the keyboard buffer might actually differ from 10 - in the 4032 and 8032 50Hz editor ROMs it is checked against different memory locations (0xe3 and 0x3eb) but by default (power-up) it's 10 anyway. AF 30jun1998 */ if (sum == PET8032_CHECKSUM_A || sum == PET8032_CHECKSUM_B) { printf("Identified PET 8032 ROM by checksum.\n"); pet.screen_width = 80; kbd_buf_init(0x26f, 0x9e, 10, PET_PAL_CYCLES_PER_RFSH * PET_PAL_RFSH_PER_SEC); autostart_init(3 * PET_PAL_RFSH_PER_SEC * PET_PAL_CYCLES_PER_RFSH, 0, 0xa7, 0xc4, 0xc6, -80); tape_init(214, 150, 157, 144, 0xe455, 251, 201, pet4_tape_traps, 0x26f, 0x9e); } else if (sum == PET3032_CHECKSUM_A || sum == PET3032_CHECKSUM_B) { printf("Identified PET 3032 ROM by checksum.\n"); pet.screen_width = 40; kbd_buf_init(0x26f, 0x9e, 10, PET_PAL_CYCLES_PER_RFSH * PET_PAL_RFSH_PER_SEC); autostart_init(3 * PET_PAL_RFSH_PER_SEC * PET_PAL_CYCLES_PER_RFSH, 0, 0xa7, 0xc4, 0xc6, -40); tape_init(214, 150, 157, 144, 0xe62e, 251, 201, pet3_tape_traps, 0x26f, 0x9e); } else if (sum == PET4032_CHECKSUM_A || sum == PET4032_CHECKSUM_B) { printf("Identified PET 4032 ROM by checksum.\n"); pet.screen_width = 40; kbd_buf_init(0x26f, 0x9e, 10, PET_PAL_CYCLES_PER_RFSH * PET_PAL_RFSH_PER_SEC); autostart_init(3 * PET_PAL_RFSH_PER_SEC * PET_PAL_CYCLES_PER_RFSH, 0, 0xa7, 0xc4, 0xc6, -40); tape_init(214, 150, 157, 144, 0xe455, 251, 201, pet4_tape_traps, 0x26f, 0x9e); } else if (sum == PET2001_CHECKSUM) { printf("Identified PET 2001 ROM by checksum.\n"); pet.screen_width = 40; kbd_buf_init(0x20f, 0x20d, 10, PET_PAL_CYCLES_PER_RFSH * PET_PAL_RFSH_PER_SEC); autostart_init(3 * PET_PAL_RFSH_PER_SEC * PET_PAL_CYCLES_PER_RFSH, 0, 0x224, 0xe0, 0xe2, -40); tape_init(243, 0x20c, 0x20b, 0x219, 0xe685, 247, 229, pet2_tape_traps, 0x20f, 0x20d); } else { printf("Unknown PET ROM.\n"); } if (pet.screen_width) { set_screen(); } rom_loaded = 1; return 0; } void set_screen(void) { int cols, vmask; cols = pet.video; vmask = pet.vmask; if (!cols) { cols = pet.screen_width; vmask = (cols == 40) ? 0x3ff : 0x7ff; } if (!cols) { cols = PET_COLS; vmask = (cols == 40) ? 0x3ff : 0x7ff; } printf("Setting screen width to %d columns (vmask=%04x).\n", cols, vmask); crtc_set_screen_mode(ram + 0x8000, vmask, cols); } /* ------------------------------------------------------------------------- */ /* FIXME: this does not work for PET 2001. */ void mem_get_basic_text(ADDRESS *start, ADDRESS *end) { if (start != NULL) *start = ram[0x28] | (ram[0x29] << 8); if (end != NULL) *end = ram[0x2a] | (ram[0x2b] << 8); } void mem_set_basic_text(ADDRESS start, ADDRESS end) { ram[0x28] = ram[0xc7] = start & 0xff; ram[0x29] = ram[0xc8] = start >> 8; ram[0x2a] = ram[0x2c] = ram[0x2e] = ram[0xc9] = end & 0xff; ram[0x2b] = ram[0x2d] = ram[0x2f] = ram[0xca] = end >> 8; } /* ------------------------------------------------------------------------- */ int mem_rom_trap_allowed(ADDRESS addr) { return (addr >= 0xf000) && !(map_reg & 0x80); } /* Tape traps. */ static trap_t pet4_tape_traps[] = { { "FindHeader", 0xF5E8, 0xF5EB, {0x20, 0x9A, 0xF8}, findheader }, { "WriteHeader", 0xF66B, 0xF66E, {0x20, 0xD5, 0xF8}, writeheader }, { "TapeReceive", 0xF8E0, 0xFCC0, {0x20, 0xE0, 0xFC}, tapereceive }, { NULL, 0, 0, {0, 0, 0}, NULL } }; static trap_t pet3_tape_traps[] = { { "FindHeader", 0xF5A9, 0xF5AC, {0x20, 0x55, 0xF8}, findheader }, { "WriteHeader", 0xF62C, 0xF62F, {0x20, 0x90, 0xF8}, writeheader }, { "TapeReceive", 0xF89B, 0xFC7B, {0x20, 0x9B, 0xFC}, tapereceive }, { NULL, 0, 0, {0, 0, 0}, NULL } }; static trap_t pet2_tape_traps[] = { { "FindHeader", 0xF5B2, 0xF5B5, {0x20, 0x7F, 0xF8}, findheader }, { "WriteHeader", 0xF63D, 0xF640, {0x20, 0xC4, 0xF8}, writeheader }, { "TapeReceive", 0xF8A5, 0xFCFB, {0x20, 0x1B, 0xFD}, tapereceive }, { NULL, 0, 0, {0, 0, 0}, NULL } }; /* ------------------------------------------------------------------------- */ /* Banked memory access functions for the monitor. */ static BYTE peek_bank_io(ADDRESS addr) { BYTE v1, v2, v3, v4; if (emu_id_enabled && addr >= 0xE8A0) { addr &= 0xff; if (addr == 0xff) emulator_id[addr - 0xa0] ^= 0xff; return emulator_id[addr - 0xa0]; } switch (addr & 0xf0) { case 0x10: /* PIA1 */ return peek_pia1(addr); case 0x20: /* PIA2 */ return peek_pia2(addr); case 0x40: return peek_via(addr); /* VIA */ case 0x80: /* CRTC */ if (pet.crtc) { if (addr & 1) return read_crtc(crtc_ptr); else return 0x9f; /* Status. */ } case 0x00: return addr >> 8; default: /* 0x30, 0x50, 0x60, 0x70, 0x90-0xf0 */ if (addr & 0x10) v1 = peek_pia1(addr); else v1 = 0xff; if (addr & 0x20) v2 = peek_pia2(addr); else v2 = 0xff; if (addr & 0x40) v3 = peek_via(addr); else v3 = 0xff; v4 = 0xff; if ((addr & 0x80) && pet.crtc) { if (addr & 1) v4 = read_crtc(crtc_ptr); else v4 = 0x9f; /* Status. */ } return v1 & v2 & v3 & v4; } return 0xff; } /* Exported banked memory access functions for the monitor. */ static const char *banknames[] = { "default", "cpu", "ram", "rom", "io", "extram", NULL }; static int banknums[] = { 0, 0, 1, 2, 3, 4 }; const char **mem_bank_list(void) { return banknames; } int mem_bank_from_name(const char *name) { int i = 0; while (banknames[i]) { if (!strcmp(name, banknames[i])) { return banknums[i]; } i++; } return -1; } BYTE mem_bank_read(int bank, ADDRESS addr) { switch (bank) { case 0: /* current */ return mem_read(addr); break; case 4: /* extended RAM area (8x96) */ return ram[addr + 0x10000]; break; case 3: /* io */ if (addr >= 0xE000 && addr <= 0xE0FF) { return read_io(addr); } case 2: /* rom */ if (addr >= 0x9000 && addr <= 0xFFFF) { return rom[addr & 0x7fff]; } case 1: /* ram */ } return ram[addr]; } BYTE mem_bank_peek(int bank, ADDRESS addr) { switch (bank) { case 0: /* current */ return mem_read(addr); /* FIXME */ break; case 3: /* io */ if (addr >= 0xE000 && addr <= 0xE0FF) { return peek_bank_io(addr); } } return mem_bank_read(bank, addr); } void mem_bank_write(int bank, ADDRESS addr, BYTE byte) { switch (bank) { case 0: /* current */ mem_store(addr, byte); return; case 4: /* extended RAM area (8x96) */ ram[addr + 0x10000] = byte; return; case 3: /* io */ if (addr >= 0xE000 && addr <= 0xE0FF) { store_io(addr, byte); return; } case 2: /* rom */ if (addr >= 0x9000 && addr <= 0xFFFF) { return; } case 1: /* ram */ } ram[addr] = byte; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.