1
0
mirror of https://github.com/pevans/erc-c.git synced 2024-06-30 14:29:27 +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, 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 * An Apple II has bank-switched memory beginning with $D000 extending
* one memory mode at a time. * 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 { enum memory_mode {
MEMORY_BANK_ROM, // the last 12k is system ROM MEMORY_ROM = 1, // on = read ROM; off = read RAM
MEMORY_BANK_RAM1, // the last 12k is system RAM MEMORY_WRITE = 2, // on = allow writes to RAM; off = disallow writes
MEMORY_BANK_RAM2, // the first 4k of the last 12k is a separate RAM MEMORY_RAM2 = 4, // on = use bank 2 for $D000-$DFFF; off = use bank 1
// block from that in RAM1
}; };
typedef struct { typedef struct {
@ -140,7 +155,7 @@ typedef struct {
* our read/write mappers to know where writes into the * our read/write mappers to know where writes into the
* bank-switched area of memory should target. * bank-switched area of memory should target.
*/ */
int memory_mode; vm_8bit bank_switch;
/* /*
* Our two disk drives. * Our two disk drives.
@ -159,7 +174,7 @@ extern void apple2_release_key(apple2 *);
extern void apple2_reset(apple2 *); extern void apple2_reset(apple2 *);
extern void apple2_run_loop(apple2 *); extern void apple2_run_loop(apple2 *);
extern void apple2_set_color(apple2 *, int); 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); extern void apple2_set_video(apple2 *, int);
#endif #endif

View File

@ -119,9 +119,10 @@ apple2_create(int width, int height)
// We default to lo-res mode. // We default to lo-res mode.
apple2_set_video(mach, VIDEO_LORES); apple2_set_video(mach, VIDEO_LORES);
// By default we should have ROM be the addressable last 12k of // At cold boot, we don't care what the bank switch is; the reset
// memory. // function will do the right thing, so let's default the flags to
apple2_set_memory(mach, MEMORY_BANK_ROM); // zero.
mach->bank_switch = 0;
// Let's install our bitmap font. // Let's install our bitmap font.
mach->sysfont = vm_bitfont_create(mach->screen, 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 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 // Switch video mode back to 40 column text
apple2_set_video(mach, VIDEO_40COL_TEXT); apple2_set_video(mach, VIDEO_40COL_TEXT);
// Default to read from ROM // Default to:
apple2_set_memory(mach, MEMORY_BANK_ROM); // - 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; mach = (apple2 *)_mach;
switch (mach->memory_mode) { if (mach->bank_switch & MEMORY_ROM) {
// Return memory from the rom bank // We need to account for the difference in address location
case MEMORY_BANK_ROM: // before we can successfully get any data from ROM.
// We need to account for the difference in address location return vm_segment_get(mach->rom, address - APPLE2_BANK_OFFSET);
// 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;
} }
// The "default" behavior as referred-to above is simply to return // If the address is $D000..$DFFF, then we may need to get the byte
// the value as held in our primary memory bank. // 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]; return segment->memory[address];
} }
@ -59,24 +49,29 @@ apple2_mem_write_bank(vm_segment *segment,
mach = (apple2 *)_mach; mach = (apple2 *)_mach;
switch (mach->memory_mode) { // No writes are allowed... sorry!
// Whoops -- we can't write any data into ROM. if (~mach->bank_switch & MEMORY_WRITE) {
case MEMORY_BANK_ROM: return;
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;
} }
// 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; segment->memory[address] = value;
} }

View File

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