mirror of
https://github.com/pevans/erc-c.git
synced 2025-02-17 07:32:05 +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:
parent
343d870399
commit
3db536a83d
@ -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
|
||||
|
20
src/apple2.c
20
src/apple2.c
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user