1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-23 05:29:23 +00:00

Pull PagingType::Main to top, eliminate macros.

This commit is contained in:
Thomas Harte 2024-01-03 11:40:04 -05:00
parent 439535e44b
commit d01c306187

View File

@ -248,13 +248,124 @@ class MemoryMap {
uint8_t speed_register_ = 0x00;
// MARK: - Memory banking.
#define assert_is_region(start, end) \
assert(region_map[start] == region_map[start-1]+1); \
assert(region_map[end-1] == region_map[start]); \
assert(region_map[end] == region_map[end-1]+1);
void assert_is_region(uint8_t start, uint8_t end) {
assert(region_map[start] == region_map[start-1]+1);
assert(region_map[end-1] == region_map[start]);
assert(region_map[end] == region_map[end-1]+1);
}
template <int type> void set_paging() {
// Establish whether main or auxiliary RAM
// is exposed in bank $00 for a bunch of regions.
if constexpr (type & PagingType::Main) {
const auto set = [&](std::size_t page, const auto &flags) {
auto &region = regions[region_map[page]];
region.read = flags.read ? &ram_base[0x01'0000] : ram_base;
region.write = flags.write ? &ram_base[0x01'0000] : ram_base;
};
const auto state = auxiliary_switches_.main_state();
// Base: $0200$03FF.
set(0x02, state.base);
assert_is_region(0x02, 0x04);
// Region $0400$07ff.
set(0x04, state.region_04_08);
assert_is_region(0x04, 0x08);
// Base: $0800$1FFF.
set(0x08, state.base);
assert_is_region(0x08, 0x20);
// Region $2000$3FFF.
set(0x20, state.region_20_40);
assert_is_region(0x20, 0x40);
// Base: $4000$BFFF.
set(0x40, state.base);
assert_is_region(0x40, 0xc0);
}
// Update whether base or auxiliary RAM is visible in: (i) the zero
// and stack pages; and (ii) anywhere that the language card is exposing RAM instead of ROM.
if constexpr (bool(type & PagingType::ZeroPage)) {
// Affects bank $00 only, and should be a single region.
auto &region = regions[region_map[0]];
region.read = region.write = auxiliary_switches_.zero_state() ? &ram_base[0x01'0000] : ram_base;
assert(region_map[0x0000] == region_map[0x0001]);
assert(region_map[0x0001]+1 == region_map[0x0002]);
}
// Establish whether ROM or card switches are exposed in the distinct
// regions C100C2FF, C300C3FF, C400C7FF and C800CFFF.
//
// On the IIgs it intersects with the current shadow register.
if constexpr (bool(type & (PagingType::CardArea | PagingType::Main))) {
const bool inhibit_banks0001 = shadow_register_ & 0x40;
const auto state = auxiliary_switches_.card_state();
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 = &regions[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;
const auto apply_region = [&](bool flag, auto &region) {
region.write = nullptr;
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);
// Sanity checks.
assert(region_map[bank_base | 0xc1] == region_map[bank_base | 0xc0]+1);
assert(region_map[bank_base | 0xc2] == region_map[bank_base | 0xc1]);
assert(region_map[bank_base | 0xc3] == region_map[bank_base | 0xc2]+1);
assert(region_map[bank_base | 0xc4] == region_map[bank_base | 0xc3]+1);
assert(region_map[bank_base | 0xc7] == region_map[bank_base | 0xc4]);
assert(region_map[bank_base | 0xc8] == region_map[bank_base | 0xc7]+1);
assert(region_map[bank_base | 0xcf] == region_map[bank_base | 0xc8]);
assert(region_map[bank_base | 0xd0] == region_map[bank_base | 0xcf]+1);
};
if(inhibit_banks0001) {
// Set no IO in the Cx00 range for banks $00 and $01, just
// 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_base[0x01'0000] : ram_base;
regions[region].write = auxiliary_state.base.write ? &ram_base[0x01'0000] : ram_base;
regions[region].flags &= ~Region::IsIO;
}
for(uint8_t region = region_map[0x01c0]; region < region_map[0x01d0]; region++) {
regions[region].read = regions[region].write = ram_base;
regions[region].flags &= ~Region::IsIO;
}
} else {
// Obey the card state for banks $00 and $01.
apply(0x0000);
apply(0x0100);
}
// Obey the card state for banks $e0 and $e1.
apply(0xe000);
apply(0xe100);
}
// Update the region from
// $D000 onwards as per the state of the language card flags — there may
// end up being ROM or RAM (or auxiliary RAM), and the first 4kb of it
@ -314,121 +425,6 @@ class MemoryMap {
apply(0xe000, e0_ram);
apply(0xe100, e0_ram);
}
// Establish whether main or auxiliary RAM
// is exposed in bank $00 for a bunch of regions.
if constexpr (type & PagingType::Main) {
const auto state = auxiliary_switches_.main_state();
#define set(page, flags) {\
auto &region = regions[region_map[page]]; \
region.read = flags.read ? &ram_base[0x01'0000] : ram_base; \
region.write = flags.write ? &ram_base[0x01'0000] : ram_base; \
}
// Base: $0200$03FF.
set(0x02, state.base);
assert_is_region(0x02, 0x04);
// Region $0400$07ff.
set(0x04, state.region_04_08);
assert_is_region(0x04, 0x08);
// Base: $0800$1FFF.
set(0x08, state.base);
assert_is_region(0x08, 0x20);
// Region $2000$3FFF.
set(0x20, state.region_20_40);
assert_is_region(0x20, 0x40);
// Base: $4000$BFFF.
set(0x40, state.base);
assert_is_region(0x40, 0xc0);
#undef set
}
// Update whether base or auxiliary RAM is visible in: (i) the zero
// and stack pages; and (ii) anywhere that the language card is exposing RAM instead of ROM.
if constexpr (bool(type & PagingType::ZeroPage)) {
// Affects bank $00 only, and should be a single region.
auto &region = regions[region_map[0]];
region.read = region.write = auxiliary_switches_.zero_state() ? &ram_base[0x01'0000] : ram_base;
assert(region_map[0x0000] == region_map[0x0001]);
assert(region_map[0x0001]+1 == region_map[0x0002]);
}
// Establish whether ROM or card switches are exposed in the distinct
// regions C100C2FF, C300C3FF, C400C7FF and C800CFFF.
//
// On the IIgs it intersects with the current shadow register.
if constexpr (bool(type & (PagingType::CardArea | PagingType::Main))) {
const bool inhibit_banks0001 = shadow_register_ & 0x40;
const auto state = auxiliary_switches_.card_state();
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 = &regions[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) \
region.write = nullptr; \
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 | 0xc2] == region_map[bank_base | 0xc1]);
assert(region_map[bank_base | 0xc3] == region_map[bank_base | 0xc2]+1);
assert(region_map[bank_base | 0xc4] == region_map[bank_base | 0xc3]+1);
assert(region_map[bank_base | 0xc7] == region_map[bank_base | 0xc4]);
assert(region_map[bank_base | 0xc8] == region_map[bank_base | 0xc7]+1);
assert(region_map[bank_base | 0xcf] == region_map[bank_base | 0xc8]);
assert(region_map[bank_base | 0xd0] == region_map[bank_base | 0xcf]+1);
};
if(inhibit_banks0001) {
// Set no IO in the Cx00 range for banks $00 and $01, just
// 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_base[0x01'0000] : ram_base;
regions[region].write = auxiliary_state.base.write ? &ram_base[0x01'0000] : ram_base;
regions[region].flags &= ~Region::IsIO;
}
for(uint8_t region = region_map[0x01c0]; region < region_map[0x01d0]; region++) {
regions[region].read = regions[region].write = ram_base;
regions[region].flags &= ~Region::IsIO;
}
} else {
// Obey the card state for banks $00 and $01.
apply(0x0000);
apply(0x0100);
}
// Obey the card state for banks $e0 and $e1.
apply(0xe000);
apply(0xe100);
}
}
// IIgs specific: sets or resets the ::IsShadowed flag across affected banks as
@ -563,8 +559,6 @@ class MemoryMap {
}
}
#undef assert_is_region
private:
// Various precomputed bitsets describing key regions; std::bitset doesn't support constexpr instantiation
// beyond the first 64 bits at the time of writing, alas, so these are generated at runtime.