mirror of
https://github.com/pevans/erc-c.git
synced 2024-12-21 23:29:16 +00:00
292 lines
7.6 KiB
C
292 lines
7.6 KiB
C
/*
|
|
* apple2.mem.c
|
|
*/
|
|
|
|
#include "apple2.bank.h"
|
|
#include "apple2.dbuf.h"
|
|
#include "apple2.dd.h"
|
|
#include "apple2.h"
|
|
#include "apple2.kb.h"
|
|
#include "apple2.mem.h"
|
|
#include "apple2.pc.h"
|
|
#include "objstore.h"
|
|
|
|
static size_t switch_reads[] = {
|
|
0xC013,
|
|
0xC014,
|
|
0xC018,
|
|
0xC01C,
|
|
0xC01D,
|
|
0xC054,
|
|
0xC055,
|
|
0xC056,
|
|
0xC057,
|
|
0xC059,
|
|
};
|
|
|
|
static size_t switch_writes[] = {
|
|
0xC000,
|
|
0xC001,
|
|
0xC002,
|
|
0xC003,
|
|
0xC004,
|
|
0xC005,
|
|
0xC054,
|
|
0xC055,
|
|
0xC056,
|
|
0xC057,
|
|
0xC059,
|
|
};
|
|
|
|
/*
|
|
* Set the memory map functions for main memory in an apple2 machine
|
|
*/
|
|
void
|
|
apple2_mem_map(apple2 *mach, vm_segment *segment)
|
|
{
|
|
size_t addr;
|
|
int i, rlen, wlen;
|
|
|
|
vm_segment_set_map_machine(mach);
|
|
|
|
// Set up all of the bank-switch-related mapping. Well--almost all
|
|
// of it.
|
|
apple2_bank_map(segment);
|
|
|
|
// Here we handle the 80STORE bit for our display buffers.
|
|
apple2_dbuf_map(segment);
|
|
|
|
// All of our peripheral card (PC) mapper functions are handled
|
|
// here.
|
|
apple2_pc_map(segment);
|
|
|
|
// And this handles our keyboard soft switches
|
|
apple2_kb_map(segment);
|
|
|
|
// Map our disk drive switches
|
|
apple2_dd_map(segment);
|
|
|
|
// We will do the mapping for the zero page and stack addresses.
|
|
// Accessing those addresses can be affected by bank-switching, but
|
|
// those addresses do not actually exist in the capital
|
|
// Bank-Switching address space.
|
|
for (addr = 0x0; addr < 0x200; addr++) {
|
|
vm_segment_read_map(segment, addr, apple2_mem_zp_read);
|
|
vm_segment_write_map(segment, addr, apple2_mem_zp_write);
|
|
}
|
|
|
|
rlen = sizeof(switch_reads) / sizeof(size_t);
|
|
wlen = sizeof(switch_writes) / sizeof(size_t);
|
|
|
|
for (i = 0; i < rlen; i++) {
|
|
vm_segment_read_map(segment, switch_reads[i], apple2_mem_switch_read);
|
|
}
|
|
|
|
for (i = 0; i < wlen; i++) {
|
|
vm_segment_write_map(segment, switch_writes[i], apple2_mem_switch_write);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* I'm still a bit hazy on how this _should_ work, but this function
|
|
* will copy as much as we can from the system rom into both main memory
|
|
* and into the rom segment.
|
|
*/
|
|
int
|
|
apple2_mem_init_sys_rom(apple2 *mach)
|
|
{
|
|
int err;
|
|
const vm_8bit *sysrom;
|
|
const vm_8bit *prom;
|
|
|
|
sysrom = objstore_apple2_sys_rom();
|
|
prom = objstore_apple2_peripheral_rom();
|
|
|
|
err = vm_segment_copy_buf(mach->rom, sysrom,
|
|
0, 0, APPLE2_SYSROM_SIZE);
|
|
if (err != OK) {
|
|
log_critical("Could not copy apple2 system rom");
|
|
return ERR_BADFILE;
|
|
}
|
|
|
|
err = vm_segment_copy_buf(mach->rom, prom,
|
|
APPLE2_SYSROM_SIZE, 0,
|
|
APPLE2_PERIPHERAL_SIZE);
|
|
if (err != OK) {
|
|
log_critical("Could not copy apple2 peripheral rom");
|
|
return ERR_BADFILE;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*
|
|
* This is a wrapper for reads in the zero and stack pages; if
|
|
* BANK_ALTZP is high, then we need to use aux memory regardless of the
|
|
* segment passed into the function. Otherwise, we need to use main
|
|
* memory--again, regardless of the passed-in segment.
|
|
*/
|
|
SEGMENT_READER(apple2_mem_zp_read)
|
|
{
|
|
apple2 *mach = (apple2 *)_mach;
|
|
|
|
// This is another case (see apple2.bank.c) where we don't care the
|
|
// originating segment was; we only care whether BANK_ALTZP is on or
|
|
// not. Like bank-switchable addresses, if it is on, then we should
|
|
// be referencing aux memory; if not, main memory.
|
|
segment = (mach->bank_switch & BANK_ALTZP)
|
|
? mach->aux
|
|
: mach->main;
|
|
|
|
return segment->memory[addr];
|
|
}
|
|
|
|
/*
|
|
* This write function will intercept writes to the zero page and the
|
|
* stack page; primarily as a wrapper to handle the BANK_ALTZP bit in
|
|
* the bank_switch field of the apple2 struct.
|
|
*/
|
|
SEGMENT_WRITER(apple2_mem_zp_write)
|
|
{
|
|
apple2 *mach = (apple2 *)_mach;
|
|
|
|
// See the zp_read function for further details; the same logic
|
|
// applies here.
|
|
segment = (mach->bank_switch & BANK_ALTZP)
|
|
? mach->aux
|
|
: mach->main;
|
|
|
|
segment->memory[addr] = value;
|
|
}
|
|
|
|
/*
|
|
* Handle all soft switches that ask for the status of certain memory
|
|
* conditions.
|
|
*/
|
|
SEGMENT_READER(apple2_mem_switch_read)
|
|
{
|
|
apple2 *mach = (apple2 *)_mach;
|
|
|
|
switch (addr) {
|
|
case 0xC013:
|
|
return mach->memory_mode & MEMORY_READ_AUX
|
|
? 0x80
|
|
: 0x00;
|
|
|
|
case 0xC014:
|
|
return mach->memory_mode & MEMORY_WRITE_AUX
|
|
? 0x80
|
|
: 0x00;
|
|
|
|
case 0xC018:
|
|
return mach->memory_mode & MEMORY_80STORE
|
|
? 0x80
|
|
: 0x00;
|
|
|
|
case 0xC01C:
|
|
return mach->memory_mode & MEMORY_PAGE2
|
|
? 0x80
|
|
: 0x00;
|
|
|
|
case 0xC01D:
|
|
return mach->memory_mode & MEMORY_HIRES
|
|
? 0x80
|
|
: 0x00;
|
|
|
|
// Note the following are intentionally duplicated from the
|
|
// write switch function. Apple II allows both reads and writes
|
|
// to have the same behavior here.
|
|
case 0xC055:
|
|
apple2_set_memory_mode(mach,
|
|
mach->memory_mode | MEMORY_PAGE2);
|
|
break;
|
|
|
|
case 0xC054:
|
|
apple2_set_memory_mode(mach,
|
|
mach->memory_mode & ~MEMORY_PAGE2);
|
|
break;
|
|
|
|
case 0xC059:
|
|
case 0xC057:
|
|
apple2_set_memory_mode(mach,
|
|
mach->memory_mode | MEMORY_HIRES);
|
|
break;
|
|
|
|
case 0xC056:
|
|
apple2_set_memory_mode(mach,
|
|
mach->memory_mode & ~MEMORY_HIRES);
|
|
break;
|
|
}
|
|
|
|
// ???
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Change memory settings based on the soft switches defined in the tech
|
|
* reference
|
|
*/
|
|
SEGMENT_WRITER(apple2_mem_switch_write)
|
|
{
|
|
apple2 *mach = (apple2 *)_mach;
|
|
|
|
switch (addr) {
|
|
case 0xC003:
|
|
apple2_set_memory_mode(mach,
|
|
mach->memory_mode | MEMORY_READ_AUX);
|
|
break;
|
|
|
|
case 0xC002:
|
|
apple2_set_memory_mode(mach,
|
|
mach->memory_mode & ~MEMORY_READ_AUX);
|
|
break;
|
|
|
|
case 0xC005:
|
|
apple2_set_memory_mode(mach,
|
|
mach->memory_mode | MEMORY_WRITE_AUX);
|
|
break;
|
|
|
|
case 0xC004:
|
|
apple2_set_memory_mode(mach,
|
|
mach->memory_mode & ~MEMORY_WRITE_AUX);
|
|
break;
|
|
|
|
case 0xC001:
|
|
apple2_set_memory_mode(mach,
|
|
mach->memory_mode | MEMORY_80STORE);
|
|
break;
|
|
|
|
case 0xC000:
|
|
apple2_set_memory_mode(mach,
|
|
mach->memory_mode & ~MEMORY_80STORE);
|
|
break;
|
|
|
|
case 0xC055:
|
|
apple2_set_memory_mode(mach,
|
|
mach->memory_mode | MEMORY_PAGE2);
|
|
break;
|
|
|
|
case 0xC054:
|
|
apple2_set_memory_mode(mach,
|
|
mach->memory_mode & ~MEMORY_PAGE2);
|
|
break;
|
|
|
|
// NOTE: in one place, the technical reference says $C057 is the
|
|
// soft switch to enable HIRES. In one other place, it says
|
|
// $C059. I'm assuming it's either one... It's otherwise
|
|
// consistent when mentioning soft switches in more than one
|
|
// table.
|
|
case 0xC059:
|
|
case 0xC057:
|
|
apple2_set_memory_mode(mach,
|
|
mach->memory_mode | MEMORY_HIRES);
|
|
break;
|
|
|
|
case 0xC056:
|
|
apple2_set_memory_mode(mach,
|
|
mach->memory_mode & ~MEMORY_HIRES);
|
|
break;
|
|
|
|
}
|
|
}
|