mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Takes a run at set_card_paging and simplifies method of shadowing.
This commit is contained in:
parent
74f9f6ad3b
commit
31cd45f8b5
@ -26,8 +26,9 @@ class MemoryMap {
|
|||||||
MemoryMap() : auxiliary_switches_(*this), language_card_(*this) {}
|
MemoryMap() : auxiliary_switches_(*this), language_card_(*this) {}
|
||||||
|
|
||||||
void set_storage(std::vector<uint8_t> &ram, std::vector<uint8_t> &rom) {
|
void set_storage(std::vector<uint8_t> &ram, std::vector<uint8_t> &rom) {
|
||||||
// Keep a pointer for later.
|
// Keep a pointer for later; also note the proper RAM offset.
|
||||||
ram_ = ram.data();
|
ram_ = ram.data();
|
||||||
|
shadow_offset = ram.size() - (128*1024);
|
||||||
|
|
||||||
// Establish bank mapping.
|
// Establish bank mapping.
|
||||||
uint8_t next_region = 0;
|
uint8_t next_region = 0;
|
||||||
@ -87,7 +88,7 @@ class MemoryMap {
|
|||||||
set_regions(0x01, {
|
set_regions(0x01, {
|
||||||
0x0400, 0x0800, 0x0c00,
|
0x0400, 0x0800, 0x0c00,
|
||||||
0x2000, 0x4000, 0x6000, 0xa000,
|
0x2000, 0x4000, 0x6000, 0xa000,
|
||||||
0xc000, /* I don't think ROM-over-$Cx00 works in bank $01? */
|
0xc000, 0xc100, 0xc300, 0xc400, 0xc800,
|
||||||
0xd000, 0xe000,
|
0xd000, 0xe000,
|
||||||
0xffff
|
0xffff
|
||||||
});
|
});
|
||||||
@ -123,9 +124,9 @@ class MemoryMap {
|
|||||||
// [Banks $80–$e0: empty].
|
// [Banks $80–$e0: empty].
|
||||||
|
|
||||||
// Banks $e0, $e1: all locations potentially affected by the language switches or marked for IO.
|
// Banks $e0, $e1: all locations potentially affected by the language switches or marked for IO.
|
||||||
// TODO: do I need to break up the Cx pages?
|
// Alas, separate regions are needed due to the same ROM appearing on both pages.
|
||||||
for(uint8_t c = 0; c < 2; c++) {
|
for(uint8_t c = 0; c < 2; c++) {
|
||||||
set_regions(0xe0 + c, {0xc000, 0xd000, 0xe000, 0xffff});
|
set_regions(0xe0 + c, {0xc000, 0xc100, 0xc300, 0xc400, 0xc800, 0xd000, 0xe000, 0xffff});
|
||||||
}
|
}
|
||||||
|
|
||||||
// [Banks $e2–[ROM start]: empty].
|
// [Banks $e2–[ROM start]: empty].
|
||||||
@ -170,10 +171,13 @@ class MemoryMap {
|
|||||||
set_storage((first_rom_bank + c) << 16, &rom[c << 16], nullptr);
|
set_storage((first_rom_bank + c) << 16, &rom[c << 16], nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply initial language/auxiliary state. [TODO: including shadowing register].
|
// TODO: set 1Mhz flags.
|
||||||
|
|
||||||
|
// Apply initial language/auxiliary state.
|
||||||
set_card_paging();
|
set_card_paging();
|
||||||
set_zero_page_paging();
|
set_zero_page_paging();
|
||||||
set_main_paging();
|
set_main_paging();
|
||||||
|
set_shadowing();
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Live bus access notifications.
|
// MARK: - Live bus access notifications.
|
||||||
@ -266,17 +270,62 @@ class MemoryMap {
|
|||||||
const bool inhibit_banks0001 = shadow_register_ & 0x40;
|
const bool inhibit_banks0001 = shadow_register_ & 0x40;
|
||||||
const auto state = auxiliary_switches_.card_state();
|
const auto state = auxiliary_switches_.card_state();
|
||||||
|
|
||||||
// TODO: all work.
|
auto apply = [&state, this](uint32_t bank_base) {
|
||||||
|
auto &c0_region = regions[region_map[bank_base | 0xc0]];
|
||||||
|
auto &c1_region = regions[region_map[bank_base | 0xc1]];
|
||||||
|
auto &c3_region = regions[region_map[bank_base | 0xc3]];
|
||||||
|
auto &c4_region = regions[region_map[bank_base | 0xc4]];
|
||||||
|
auto &c8_region = regions[region_map[bank_base | 0xc8]];
|
||||||
|
|
||||||
|
const uint8_t *const rom = ®ions[region_map[0xffd0]].read[0xffc100] - ((bank_base << 8) + 0xc100);
|
||||||
|
|
||||||
|
// This is applied dynamically as it may be added or lost in banks $00 and $01.
|
||||||
|
c0_region.flags |= Region::IsIO;
|
||||||
|
|
||||||
|
#define apply_region(flag, region) \
|
||||||
|
if(flag) { \
|
||||||
|
region.read = rom; \
|
||||||
|
region.flags &= ~Region::IsIO; \
|
||||||
|
} else { \
|
||||||
|
region.flags |= Region::IsIO; \
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_region(state.region_C1_C3, c1_region);
|
||||||
|
apply_region(state.region_C3, c3_region);
|
||||||
|
apply_region(state.region_C4_C8, c4_region);
|
||||||
|
apply_region(state.region_C8_D0, c8_region);
|
||||||
|
|
||||||
|
#undef apply_region
|
||||||
|
|
||||||
|
// Sanity checks.
|
||||||
|
assert(region_map[bank_base | 0xc1] == region_map[bank_base | 0xc0]+1);
|
||||||
|
assert(region_map[bank_base | 0xc3] == region_map[bank_base | 0xc1]+1);
|
||||||
|
assert(region_map[bank_base | 0xc4] == region_map[bank_base | 0xc3]+1);
|
||||||
|
assert(region_map[bank_base | 0xc8] == region_map[bank_base | 0xc4]+1);
|
||||||
|
};
|
||||||
|
|
||||||
if(inhibit_banks0001) {
|
if(inhibit_banks0001) {
|
||||||
// Set no IO anywhere, all the Cx regions point to regular RAM
|
// Set no IO in the Cx00 range for banks $00 and $01, just
|
||||||
// (or possibly auxiliary).
|
// regular RAM (or possibly auxiliary).
|
||||||
|
const auto auxiliary_state = auxiliary_switches_.main_state();
|
||||||
|
for(uint8_t region = region_map[0x00c0]; region < region_map[0x00d0]; region++) {
|
||||||
|
regions[region].read = auxiliary_state.base.read ? &ram_[0x10000] : ram_;
|
||||||
|
regions[region].write = auxiliary_state.base.write ? &ram_[0x10000] : ram_;
|
||||||
|
regions[region].flags &= ~Region::IsIO;
|
||||||
|
}
|
||||||
|
for(uint8_t region = region_map[0x01c0]; region < region_map[0x01d0]; region++) {
|
||||||
|
regions[region].read = regions[region].write = ram_;
|
||||||
|
regions[region].flags &= ~Region::IsIO;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Obey the card state for banks $00 and $01.
|
// Obey the card state for banks $00 and $01.
|
||||||
|
apply(0x0000);
|
||||||
|
apply(0x0100);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obey the card state for banks $e0 and $e1.
|
// Obey the card state for banks $e0 and $e1.
|
||||||
(void)state;
|
apply(0xe000);
|
||||||
|
apply(0xe100);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_zero_page_paging() {
|
void set_zero_page_paging() {
|
||||||
@ -291,6 +340,7 @@ class MemoryMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void set_shadowing() {
|
void set_shadowing() {
|
||||||
|
// TODO.
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_main_paging() {
|
void set_main_paging() {
|
||||||
@ -309,8 +359,11 @@ class MemoryMap {
|
|||||||
set(0x20, state.region_20_40);
|
set(0x20, state.region_20_40);
|
||||||
|
|
||||||
#undef set
|
#undef set
|
||||||
// This also affects shadowing flags, if shadowing is enabled at all.
|
// This also affects shadowing flags, if shadowing is enabled at all,
|
||||||
|
// and might affect RAM in the IO area of bank $00 because the language
|
||||||
|
// card can be inhibited on a IIgs.
|
||||||
set_shadowing();
|
set_shadowing();
|
||||||
|
set_card_paging();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -321,6 +374,7 @@ class MemoryMap {
|
|||||||
// Pointers are eight bytes at the time of writing, so the extra level of indirection
|
// Pointers are eight bytes at the time of writing, so the extra level of indirection
|
||||||
// reduces what would otherwise be a 1.25mb table down to not a great deal more than 64kb.
|
// reduces what would otherwise be a 1.25mb table down to not a great deal more than 64kb.
|
||||||
std::array<uint8_t, 65536> region_map;
|
std::array<uint8_t, 65536> region_map;
|
||||||
|
size_t shadow_offset;
|
||||||
|
|
||||||
struct Region {
|
struct Region {
|
||||||
uint8_t *write = nullptr;
|
uint8_t *write = nullptr;
|
||||||
@ -328,11 +382,10 @@ class MemoryMap {
|
|||||||
uint8_t flags = 0;
|
uint8_t flags = 0;
|
||||||
|
|
||||||
enum Flag: uint8_t {
|
enum Flag: uint8_t {
|
||||||
IsShadowedE0 = 1 << 0, // i.e. writes should also be written to bank $e0, and costed appropriately.
|
IsShadowed = 1 << 0, // Writes should be shadowed to [end of RAM - 128kb + base offset].
|
||||||
IsShadowedE1 = 1 << 1, // i.e. writes should also be written to bank $e1, and costed appropriately.
|
Is1Mhz = 1 << 1, // Both reads and writes should be synchronised with the 1Mhz clock.
|
||||||
IsShadowed = IsShadowedE0 | IsShadowedE1,
|
IsIO = 1 << 2, // Indicates that this region should be checked for soft switches, registers, etc;
|
||||||
Is1Mhz = 1 << 2, // Both reads and writes should be synchronised with the 1Mhz clock.
|
// usurps the shadowed flags.
|
||||||
IsIO = 1 << 3, // Indicates that this region should be checked for soft switches, registers, etc.
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
std::array<Region, 64> regions; // The assert above ensures that this is large enough; there's no
|
std::array<Region, 64> regions; // The assert above ensures that this is large enough; there's no
|
||||||
@ -345,9 +398,8 @@ class MemoryMap {
|
|||||||
#define MemoryMapWrite(map, region, address, value) \
|
#define MemoryMapWrite(map, region, address, value) \
|
||||||
if(region.write) { \
|
if(region.write) { \
|
||||||
region.write[address] = *value; \
|
region.write[address] = *value; \
|
||||||
if(region.flags & (MemoryMap::Region::IsShadowed)) { \
|
if(region.flags & MemoryMap::Region::IsShadowed) { \
|
||||||
const uint32_t shadowed_address = (address & 0xffff) + (uint32_t(0xe1 - (region.flags & MemoryMap::Region::IsShadowedE0)) << 16); \
|
region.write[address + map.shadow_offset] = *value; \
|
||||||
map.regions[map.region_map[shadowed_address >> 8]].write[shadowed_address] = *value; \
|
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user