1
0
mirror of https://github.com/pevans/erc-c.git synced 2024-06-28 01:29:37 +00:00

Change memory_mode -> bank_switch

This also changes the concept of the field; bank_switch is a collection
of bit flags now.
This commit is contained in:
Peter Evans 2018-01-10 19:59:33 -06:00
parent 343d870399
commit 3db536a83d
5 changed files with 82 additions and 69 deletions

View File

@ -70,15 +70,30 @@ enum lores_colors {
LORES_WHITE,
};
// Write-protect on/off.
// Read target = ROM or RAM.
// Write target = RAM.
// Set mode of $Dxxx hexapage bank1 or bank2 ram.
// 0 - 0=off 1=on
// 1 - 0=ROM 1=RAM
// 2 - 0=BANK1 1=BANK2
/*
* These are the potential memory modes we understand. You can only have
* one memory mode at a time.
* An Apple II has bank-switched memory beginning with $D000 extending
* through $FFFF. The enums below define bit flag names to determine
* what is accessible through those addresses.
*
* Note that it _is_ possible to write while reading ROM, but your
* writes will not go to ROM; they'll go to _RAM_. Any write to $E000 -
* $FFFF may only be sent to bank 1 RAM. Writes to $D000-$DFFF may
* either be sent to bank 1 RAM or bank 2 RAM based upon the RAM2 bit
* flag below.
*/
enum memory_mode {
MEMORY_BANK_ROM, // the last 12k is system ROM
MEMORY_BANK_RAM1, // the last 12k is system RAM
MEMORY_BANK_RAM2, // the first 4k of the last 12k is a separate RAM
// block from that in RAM1
MEMORY_ROM = 1, // on = read ROM; off = read RAM
MEMORY_WRITE = 2, // on = allow writes to RAM; off = disallow writes
MEMORY_RAM2 = 4, // on = use bank 2 for $D000-$DFFF; off = use bank 1
};
typedef struct {
@ -140,7 +155,7 @@ typedef struct {
* our read/write mappers to know where writes into the
* bank-switched area of memory should target.
*/
int memory_mode;
vm_8bit bank_switch;
/*
* Our two disk drives.
@ -159,7 +174,7 @@ extern void apple2_release_key(apple2 *);
extern void apple2_reset(apple2 *);
extern void apple2_run_loop(apple2 *);
extern void apple2_set_color(apple2 *, int);
extern void apple2_set_memory(apple2 *, int);
extern void apple2_set_bank_switch(apple2 *, vm_8bit);
extern void apple2_set_video(apple2 *, int);
#endif

View File

@ -119,9 +119,10 @@ apple2_create(int width, int height)
// We default to lo-res mode.
apple2_set_video(mach, VIDEO_LORES);
// By default we should have ROM be the addressable last 12k of
// memory.
apple2_set_memory(mach, MEMORY_BANK_ROM);
// At cold boot, we don't care what the bank switch is; the reset
// function will do the right thing, so let's default the flags to
// zero.
mach->bank_switch = 0;
// Let's install our bitmap font.
mach->sysfont = vm_bitfont_create(mach->screen,
@ -139,12 +140,12 @@ apple2_create(int width, int height)
}
/*
* Change the memory mode of the apple2 to a given mode.
* Change the bank switch flags for the apple 2.
*/
void
apple2_set_memory(apple2 *mach, int mode)
apple2_set_bank_switch(apple2 *mach, vm_8bit flags)
{
mach->memory_mode = mode;
mach->bank_switch = flags;
}
/*
@ -224,8 +225,11 @@ apple2_reset(apple2 *mach)
// Switch video mode back to 40 column text
apple2_set_video(mach, VIDEO_40COL_TEXT);
// Default to read from ROM
apple2_set_memory(mach, MEMORY_BANK_ROM);
// Default to:
// - read from ROM
// - write to RAM
// - use bank 2 for $Dxxx hexapage
apple2_set_bank_switch(mach, MEMORY_ROM | MEMORY_WRITE | MEMORY_RAM2);
}
/*

View File

@ -17,33 +17,23 @@ apple2_mem_read_bank(vm_segment *segment, size_t address, void *_mach)
mach = (apple2 *)_mach;
switch (mach->memory_mode) {
// Return memory from the rom bank
case MEMORY_BANK_ROM:
// We need to account for the difference in address location
// before we can successfully get any data from ROM.
return vm_segment_get(mach->rom, address - APPLE2_BANK_OFFSET);
// If the address is $D000..$DFFF, then we need to get the byte
// from the ram2 bank. Otherwise, we break to use default
// behavior.
case MEMORY_BANK_RAM2:
if (address < 0xE000) {
// The same caution holds for getting data from the
// second RAM bank.
return vm_segment_get(mach->ram2,
address - APPLE2_BANK_OFFSET);
}
break;
case MEMORY_BANK_RAM1:
default:
break;
if (mach->bank_switch & MEMORY_ROM) {
// We need to account for the difference in address location
// before we can successfully get any data from ROM.
return vm_segment_get(mach->rom, address - APPLE2_BANK_OFFSET);
}
// The "default" behavior as referred-to above is simply to return
// the value as held in our primary memory bank.
// If the address is $D000..$DFFF, then we may need to get the byte
// from the ram2 bank.
if (address < 0xE000 && mach->bank_switch & MEMORY_RAM2) {
// The same caution holds for getting data from the
// second RAM bank.
return vm_segment_get(mach->ram2,
address - APPLE2_BANK_OFFSET);
}
// Otherwise, the byte is returned from bank 1 RAM, which is the
// literal memory available in the segment.
return segment->memory[address];
}
@ -59,24 +49,29 @@ apple2_mem_write_bank(vm_segment *segment,
mach = (apple2 *)_mach;
switch (mach->memory_mode) {
// Whoops -- we can't write any data into ROM.
case MEMORY_BANK_ROM:
return;
case MEMORY_BANK_RAM2:
if (address < 0xE000) {
vm_segment_set(mach->ram2,
address - APPLE2_BANK_OFFSET, value);
return;
}
case MEMORY_BANK_RAM1:
default:
break;
// No writes are allowed... sorry!
if (~mach->bank_switch & MEMORY_WRITE) {
return;
}
// Just set the value in main memory
// You will note, if we've gotten here, that it's possible to write
// to the bank-switch addresses even if the ROM flag is 1. It's
// true! Except that writes never go to ROM. That is to say, it's
// possible to read from ROM and write to RAM at the same
// time--well, nearly the same time, considering the 6502 does not
// allow parallel actions!
// If bank 2 RAM is turned on, and the address is in the $D000
// hexapage, then we write to our ram2 segment.
if (address < 0xE000 && mach->bank_switch & MEMORY_RAM2) {
vm_segment_set(mach->ram2,
address - APPLE2_BANK_OFFSET, value);
return;
}
// But if bank 2 RAM is not turned on, or the address is between
// $E000 - $FFFF, then writes go to bank 1 RAM, which is our main
// memory.
segment->memory[address] = value;
}

View File

@ -117,17 +117,16 @@ Test(apple2, set_video)
cr_assert_eq(mach->video_mode, VIDEO_LORES);
}
Test(apple2, set_memory)
Test(apple2, set_bank_switch)
{
apple2_set_memory(mach, MEMORY_BANK_RAM1);
cr_assert_eq(mach->memory_mode, MEMORY_BANK_RAM1);
apple2_set_memory(mach, MEMORY_BANK_RAM2);
cr_assert_eq(mach->memory_mode, MEMORY_BANK_RAM2);
cr_assert_eq(mach->bank_switch, 0);
apple2_set_bank_switch(mach, MEMORY_ROM | MEMORY_WRITE | MEMORY_RAM2);
cr_assert_eq(mach->bank_switch, MEMORY_ROM | MEMORY_WRITE | MEMORY_RAM2);
}
Test(apple2, reset)
{
apple2_set_memory(mach, MEMORY_BANK_ROM);
apple2_set_bank_switch(mach, MEMORY_ROM);
vm_segment_set(mach->rom, 0x2FFC, 0x34);
vm_segment_set(mach->rom, 0x2FFD, 0x12);
apple2_reset(mach);

View File

@ -40,7 +40,7 @@ Test(apple2_mem, read_bank)
// Test that setting a value in the rom segment is returned to us
// when addressing from main memory
mach->memory_mode = MEMORY_BANK_ROM;
apple2_set_bank_switch(mach, MEMORY_ROM | MEMORY_WRITE);
val = 123;
vm_segment_set(mach->rom, 0x77, val);
val = vm_segment_get(mach->rom, 0x77);
@ -50,7 +50,7 @@ Test(apple2_mem, read_bank)
// value in memory... but, as a twist, also check that the value is
// not set in ROM nor in RAM2.
val = 222;
mach->memory_mode = MEMORY_BANK_RAM1;
apple2_set_bank_switch(mach, MEMORY_WRITE);
vm_segment_set(mach->memory, 0xD077, val);
cr_assert_eq(vm_segment_get(mach->memory, 0xD077), val);
cr_assert_neq(vm_segment_get(mach->rom, 0x77), val);
@ -60,7 +60,7 @@ Test(apple2_mem, read_bank)
// the value directly in ram2 and see if it's there when addressing
// from main memory.
val = 111;
mach->memory_mode = MEMORY_BANK_RAM2;
apple2_set_bank_switch(mach, mach->bank_switch | MEMORY_RAM2);
vm_segment_set(mach->ram2, 0x77, val);
cr_assert_eq(vm_segment_get(mach->memory, 0xD077), val);
}
@ -80,7 +80,7 @@ Test(apple2_mem, write_bank)
// were).
right = 123;
wrong = 222;
mach->memory_mode = MEMORY_BANK_ROM;
apple2_set_bank_switch(mach, MEMORY_ROM);
vm_segment_set(mach->rom, 0x77, right);
vm_segment_set(mach->memory, 0xD077, wrong);
cr_assert_eq(vm_segment_get(mach->rom, 0x77), right);
@ -89,7 +89,7 @@ Test(apple2_mem, write_bank)
// RAM1 is the main bank; it's all 64k RAM in one chunk.
right = 111;
wrong = 232;
mach->memory_mode = MEMORY_BANK_RAM1;
apple2_set_bank_switch(mach, MEMORY_WRITE);
vm_segment_set(mach->memory, 0xD078, right);
vm_segment_set(mach->ram2, 0x78, wrong);
cr_assert_eq(vm_segment_get(mach->memory, 0xD078), right);
@ -99,7 +99,7 @@ Test(apple2_mem, write_bank)
// ($D000..$DFFF) is in ram2.
right = 210;
wrong = 132;
mach->memory_mode = MEMORY_BANK_RAM2;
apple2_set_bank_switch(mach, mach->bank_switch | MEMORY_RAM2);
vm_segment_set(mach->ram2, 0x73, wrong);
vm_segment_set(mach->memory, 0xD073, right);
cr_assert_eq(vm_segment_get(mach->ram2, 0x73), right);