mirror of
https://github.com/pevans/erc-c.git
synced 2024-08-20 09:29:01 +00:00
Add pc file for peripheral card ROM
This commit is contained in:
parent
2db5c791ba
commit
a0a5132099
@ -128,6 +128,30 @@ enum memory_mode {
|
|||||||
*/
|
*/
|
||||||
MEMORY_PAGE2 = 0x8,
|
MEMORY_PAGE2 = 0x8,
|
||||||
MEMORY_HIRES = 0x10,
|
MEMORY_HIRES = 0x10,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When this is high, expansion ROM is considered in use. That means
|
||||||
|
* that the $C800..$CFFF range will be mapped to the expansion ROM
|
||||||
|
* area of the rom segment (which is at the end), vs. the internal
|
||||||
|
* ROM area, which is at the $0800..$0FFF range within the rom
|
||||||
|
* segment.
|
||||||
|
*/
|
||||||
|
MEMORY_EXPROM = 0x20,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When SLOTCXROM is high, the entire range of $C100..$C7FF will be
|
||||||
|
* mapped to the peripheral ROM area of the rom segment (which is in
|
||||||
|
* the $4100..$47FF address range there); otherwise, $C100...$C7FF
|
||||||
|
* is mapped to internal ROM, located at $0100..$07FF within the
|
||||||
|
* same rom segment.
|
||||||
|
*
|
||||||
|
* It's not possible to map a single peripheral ROM page, with the
|
||||||
|
* exception of slot 3 (via SLOTC3ROM). That page is special because
|
||||||
|
* of its use by the 80-column text card. You can have SLOTC3ROM
|
||||||
|
* high but SLOTCXROM low.
|
||||||
|
*/
|
||||||
|
MEMORY_SLOTCXROM = 0x40,
|
||||||
|
MEMORY_SLOTC3ROM = 0x80,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum bank_switch {
|
enum bank_switch {
|
||||||
|
14
include/apple2.pc.h
Normal file
14
include/apple2.pc.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef _APPLE2_PC_H_
|
||||||
|
#define _APPLE2_PC_H_
|
||||||
|
|
||||||
|
#include "apple2.h"
|
||||||
|
#include "vm_segment.h"
|
||||||
|
|
||||||
|
extern SEGMENT_READER(apple2_pc_read);
|
||||||
|
extern SEGMENT_READER(apple2_pc_switch_read);
|
||||||
|
extern SEGMENT_WRITER(apple2_pc_switch_write);
|
||||||
|
extern SEGMENT_WRITER(apple2_pc_write);
|
||||||
|
extern size_t apple2_pc_rom_addr(size_t, vm_8bit);
|
||||||
|
extern void apple2_pc_map(vm_segment *);
|
||||||
|
|
||||||
|
#endif
|
@ -5,6 +5,7 @@ set(erc_sources
|
|||||||
apple2.dd.c
|
apple2.dd.c
|
||||||
apple2.draw.c
|
apple2.draw.c
|
||||||
apple2.mem.c
|
apple2.mem.c
|
||||||
|
apple2.pc.c
|
||||||
log.c
|
log.c
|
||||||
mos6502.c
|
mos6502.c
|
||||||
mos6502.addr.c
|
mos6502.addr.c
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "apple2.bank.h"
|
#include "apple2.bank.h"
|
||||||
#include "apple2.dbuf.h"
|
#include "apple2.dbuf.h"
|
||||||
|
#include "apple2.pc.h"
|
||||||
#include "apple2.h"
|
#include "apple2.h"
|
||||||
#include "apple2.mem.h"
|
#include "apple2.mem.h"
|
||||||
#include "objstore.h"
|
#include "objstore.h"
|
||||||
@ -25,6 +26,8 @@ apple2_mem_map(apple2 *mach, vm_segment *segment)
|
|||||||
// Here we handle the 80STORE bit for our display buffers.
|
// Here we handle the 80STORE bit for our display buffers.
|
||||||
apple2_dbuf_map(segment);
|
apple2_dbuf_map(segment);
|
||||||
|
|
||||||
|
apple2_pc_map(segment);
|
||||||
|
|
||||||
// We will do the mapping for the zero page and stack addresses.
|
// We will do the mapping for the zero page and stack addresses.
|
||||||
// Accessing those addresses can be affected by bank-switching, but
|
// Accessing those addresses can be affected by bank-switching, but
|
||||||
// those addresses do not actually exist in the capital
|
// those addresses do not actually exist in the capital
|
||||||
|
162
src/apple2.pc.c
162
src/apple2.pc.c
@ -7,8 +7,19 @@
|
|||||||
* (apple2.dd.c).
|
* (apple2.dd.c).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "apple2.h"
|
#include "apple2.pc.h"
|
||||||
#include "vm_segment.h"
|
|
||||||
|
static size_t switch_reads[] = {
|
||||||
|
0xC015,
|
||||||
|
0xC017,
|
||||||
|
};
|
||||||
|
|
||||||
|
static size_t switch_writes[] = {
|
||||||
|
0xC006,
|
||||||
|
0xC007,
|
||||||
|
0xC00A,
|
||||||
|
0xC00B,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Map all of the peripheral ROM space (and peripheral expansion ROM
|
* Map all of the peripheral ROM space (and peripheral expansion ROM
|
||||||
@ -17,24 +28,163 @@
|
|||||||
* $C800..$CFFF.
|
* $C800..$CFFF.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
apple2_pc_map(apple2 *mach, vm_segment *seg)
|
apple2_pc_map(vm_segment *seg)
|
||||||
{
|
{
|
||||||
size_t addr;
|
size_t addr;
|
||||||
|
int i;
|
||||||
|
int rlen, wlen;
|
||||||
|
|
||||||
for (addr = 0xC100; addr < 0xD000; addr++) {
|
for (addr = 0xC100; addr < 0xD000; addr++) {
|
||||||
vm_segment_read_map(seg, addr, apple2_pc_read);
|
vm_segment_read_map(seg, addr, apple2_pc_read);
|
||||||
vm_segment_write_map(seg, addr, apple2_pc_write);
|
vm_segment_write_map(seg, addr, apple2_pc_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(seg, switch_reads[i], apple2_pc_switch_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < wlen; i++) {
|
||||||
|
vm_segment_write_map(seg, switch_writes[i], apple2_pc_switch_write);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This mapper handles the entire potential peripheral ROM space; we
|
||||||
|
* either need to return an address from the beginning of memory, or
|
||||||
|
* near the end.
|
||||||
|
*/
|
||||||
SEGMENT_READER(apple2_pc_read)
|
SEGMENT_READER(apple2_pc_read)
|
||||||
{
|
{
|
||||||
apple2 *mach = (apple2 *)_mach;
|
apple2 *mach = (apple2 *)_mach;
|
||||||
|
|
||||||
if (mach->memory_mode & MEMORY_EXPROM) {
|
// The address in the rom segment gets translated through a number
|
||||||
|
// of factors
|
||||||
|
addr = apple2_pc_rom_addr(addr, mach->memory_mode);
|
||||||
|
|
||||||
|
// No matter what we do, the segment we return from will always be
|
||||||
|
// the rom segment. This part is non-negotiable.
|
||||||
|
return mach->rom->memory[addr];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since all of our address spaces are mapped to ROM, we can't write
|
||||||
|
* anything!
|
||||||
|
*/
|
||||||
|
SEGMENT_WRITER(apple2_pc_write)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given an address from program code, return the corresponding address
|
||||||
|
* in our rom segment. The machine's memory mode is also given as a
|
||||||
|
* factor.
|
||||||
|
*/
|
||||||
|
size_t
|
||||||
|
apple2_pc_rom_addr(size_t addr, vm_8bit mode)
|
||||||
|
{
|
||||||
|
size_t rom_addr;
|
||||||
|
|
||||||
|
// This mapper should only be called from the $C000..$CFFF range;
|
||||||
|
// in the rom segment, this group of pages is addressed at
|
||||||
|
// $0000..$0FFF. We can assume that regardless of what addr is, a
|
||||||
|
// subtraction of $C000 would result in a valid address.
|
||||||
|
rom_addr = addr - 0xC000;
|
||||||
|
|
||||||
|
// However, if the EXPROM bit is high, then we want to use expansion
|
||||||
|
// ROM which is located at the _end_ of the rom segment; specifically
|
||||||
|
// in the $4800..$4FFF range.
|
||||||
|
if (rom_addr >= 0x0800 && rom_addr < 0x1000 &&
|
||||||
|
mode & MEMORY_EXPROM
|
||||||
|
) {
|
||||||
|
rom_addr += 0x4000;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mach->memory_mode & MEMORY_SLOTCXROM) {
|
// If SLOTCXROM is high, then we want any byte addressed in this
|
||||||
segment = mach->rom;
|
// space to reference peripheral ROM (which is again located at the
|
||||||
|
// end of the segment, in exactly the same way that expansion ROM is
|
||||||
|
// placed).
|
||||||
|
if (rom_addr >= 0x0100 && rom_addr < 0x0800 &&
|
||||||
|
mode & MEMORY_SLOTCXROM
|
||||||
|
) {
|
||||||
|
rom_addr += 0x4000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// One final thing to account for is if the SLOTC3ROM bit is high.
|
||||||
|
// If it is, and if the address has not already been incremented
|
||||||
|
// because SLOTCXROM was _also_ high, then we need to increment just
|
||||||
|
// for this specific page of memory.
|
||||||
|
if (rom_addr >= 0x0300 && rom_addr < 0x0400 &&
|
||||||
|
mode & MEMORY_SLOTC3ROM
|
||||||
|
) {
|
||||||
|
rom_addr += 0x4000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rom_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle reads to the slot / peripheral ROM switches. I'm not
|
||||||
|
* _entirely_ sure what Apple expects to be returned here, since they
|
||||||
|
* don't indicate as clearly as they did with bank-switch modes; there,
|
||||||
|
* they said you need to return a byte with the 7 bit high, which you
|
||||||
|
* can then use a BPL or a BMI to branch with. Here, they don't specify
|
||||||
|
* bit 7, but I'm going to go with that until I see otherwise.
|
||||||
|
*/
|
||||||
|
SEGMENT_READER(apple2_pc_switch_read)
|
||||||
|
{
|
||||||
|
apple2 *mach = (apple2 *)_mach;
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
case 0xC015:
|
||||||
|
return (mach->memory_mode & MEMORY_SLOTCXROM)
|
||||||
|
? 0x80
|
||||||
|
: 0x00;
|
||||||
|
case 0xC017:
|
||||||
|
return (mach->memory_mode & MEMORY_SLOTC3ROM)
|
||||||
|
? 0x80
|
||||||
|
: 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We shouldn't get here for any practical reason, but...
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle writes to the slot switches. There are separate writes to turn
|
||||||
|
* these switches on and off, for each switch, respectively. The value
|
||||||
|
* being written doesn't matter (indeed--you won't see us reference the
|
||||||
|
* value parameter).
|
||||||
|
*/
|
||||||
|
SEGMENT_WRITER(apple2_pc_switch_write)
|
||||||
|
{
|
||||||
|
apple2 *mach = (apple2 *)_mach;
|
||||||
|
|
||||||
|
// We don't care what the value is; if a write happens to any of the
|
||||||
|
// following addresses, we must change the peripheral memory
|
||||||
|
// behavior accordingly.
|
||||||
|
switch (addr) {
|
||||||
|
case 0xC00B:
|
||||||
|
apple2_set_memory_mode(mach,
|
||||||
|
mach->memory_mode | MEMORY_SLOTC3ROM);
|
||||||
|
break;
|
||||||
|
case 0xC00A:
|
||||||
|
apple2_set_memory_mode(mach,
|
||||||
|
mach->memory_mode & ~MEMORY_SLOTC3ROM);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC006:
|
||||||
|
apple2_set_memory_mode(mach,
|
||||||
|
mach->memory_mode | MEMORY_SLOTCXROM);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC007:
|
||||||
|
apple2_set_memory_mode(mach,
|
||||||
|
mach->memory_mode & ~MEMORY_SLOTCXROM);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
58
tests/apple2.pc.c
Normal file
58
tests/apple2.pc.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include <criterion/criterion.h>
|
||||||
|
|
||||||
|
#include "apple2.h"
|
||||||
|
#include "apple2.pc.h"
|
||||||
|
|
||||||
|
static apple2 *mach = NULL;
|
||||||
|
|
||||||
|
static void
|
||||||
|
setup()
|
||||||
|
{
|
||||||
|
mach = apple2_create(100, 100);
|
||||||
|
vm_segment_set_map_machine(mach);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
teardown()
|
||||||
|
{
|
||||||
|
apple2_free(mach);
|
||||||
|
vm_segment_set_map_machine(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestSuite(apple2_pc, .init = setup, .fini = teardown);
|
||||||
|
|
||||||
|
Test(apple2_pc, map)
|
||||||
|
{
|
||||||
|
size_t addr;
|
||||||
|
int i;
|
||||||
|
vm_segment *segments[2];
|
||||||
|
|
||||||
|
segments[0] = mach->main;
|
||||||
|
segments[1] = mach->aux;
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
for (addr = 0xC100; addr < 0xD000; addr++) {
|
||||||
|
cr_assert_eq(segments[i]->read_table[addr], apple2_pc_read);
|
||||||
|
cr_assert_eq(segments[i]->write_table[addr], apple2_pc_write);
|
||||||
|
}
|
||||||
|
|
||||||
|
cr_assert_eq(segments[i]->read_table[0xC015], apple2_pc_switch_read);
|
||||||
|
cr_assert_eq(segments[i]->read_table[0xC017], apple2_pc_switch_read);
|
||||||
|
cr_assert_eq(segments[i]->write_table[0xC00B], apple2_pc_switch_write);
|
||||||
|
cr_assert_eq(segments[i]->write_table[0xC00A], apple2_pc_switch_write);
|
||||||
|
cr_assert_eq(segments[i]->write_table[0xC006], apple2_pc_switch_write);
|
||||||
|
cr_assert_eq(segments[i]->write_table[0xC007], apple2_pc_switch_write);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(apple2_pc, rom_addr)
|
||||||
|
{
|
||||||
|
cr_assert_eq(apple2_pc_rom_addr(0xC832, MEMORY_DEFAULT), 0x832);
|
||||||
|
cr_assert_eq(apple2_pc_rom_addr(0xC832, MEMORY_SLOTCXROM), 0x832);
|
||||||
|
cr_assert_eq(apple2_pc_rom_addr(0xC832, MEMORY_SLOTC3ROM), 0x832);
|
||||||
|
cr_assert_eq(apple2_pc_rom_addr(0xC232, MEMORY_EXPROM), 0x0232);
|
||||||
|
|
||||||
|
cr_assert_eq(apple2_pc_rom_addr(0xC832, MEMORY_EXPROM), 0x4832);
|
||||||
|
cr_assert_eq(apple2_pc_rom_addr(0xC732, MEMORY_SLOTCXROM), 0x4732);
|
||||||
|
cr_assert_eq(apple2_pc_rom_addr(0xC332, MEMORY_SLOTC3ROM), 0x4332);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user