1
0
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:
Thomas Harte 2020-10-27 19:33:47 -04:00
parent 74f9f6ad3b
commit 31cd45f8b5

View File

@ -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 = &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) \
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; \
} \ } \
} }