mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Merge branch 'IIgsMemoryMap' of github.com:TomHarte/CLK into IIgsMemoryMap
This commit is contained in:
commit
d0df156b05
@ -183,72 +183,72 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: The language card.
|
||||
// MARK: - The language card, auxiliary memory, and IIe-specific improvements.
|
||||
LanguageCardSwitches<ConcreteMachine> language_card_;
|
||||
AuxiliaryMemorySwitches<ConcreteMachine> auxiliary_switches_;
|
||||
friend LanguageCardSwitches<ConcreteMachine>;
|
||||
friend AuxiliaryMemorySwitches<ConcreteMachine>;
|
||||
|
||||
void set_language_card_paging() {
|
||||
const auto language_state = language_card_.state();
|
||||
const auto zero_state = auxiliary_switches_.zero_state();
|
||||
|
||||
uint8_t *const ram = zero_state ? aux_ram_ : ram_;
|
||||
uint8_t *const rom = is_iie() ? &rom_[3840] : rom_.data();
|
||||
|
||||
// Which way the region here is mapped to be banks 1 and 2 is
|
||||
// arbitrary.
|
||||
page(0xd0, 0xe0,
|
||||
language_state.read ? &ram[language_state.bank2 ? 0xd000 : 0xc000] : rom,
|
||||
language_state.write ? nullptr : &ram[language_state.bank2 ? 0xd000 : 0xc000]);
|
||||
|
||||
page(0xe0, 0x100,
|
||||
language_state.read ? &ram[0xe000] : &rom[0x1000],
|
||||
language_state.write ? nullptr : &ram[0xe000]);
|
||||
}
|
||||
|
||||
// MARK: Auxiliary memory and the other IIe improvements.
|
||||
void set_card_paging() {
|
||||
const auto state = auxiliary_switches_.card_state();
|
||||
|
||||
page(0xc1, 0xc4, state.region_C1_C3 ? &rom_[0xc100 - 0xc100] : nullptr, nullptr);
|
||||
read_pages_[0xc3] = state.region_C3 ? &rom_[0xc300 - 0xc100] : nullptr;
|
||||
page(0xc4, 0xc8, state.region_C4_C8 ? &rom_[0xc400 - 0xc100] : nullptr, nullptr);
|
||||
page(0xc8, 0xd0, state.region_C8_D0 ? &rom_[0xc800 - 0xc100] : nullptr, nullptr);
|
||||
}
|
||||
void set_zero_page_paging() {
|
||||
if(auxiliary_switches_.zero_state()) {
|
||||
write_pages_[0] = aux_ram_;
|
||||
} else {
|
||||
write_pages_[0] = ram_;
|
||||
template <int type> void set_paging() {
|
||||
if constexpr (bool(type & PagingType::ZeroPage)) {
|
||||
if(auxiliary_switches_.zero_state()) {
|
||||
write_pages_[0] = aux_ram_;
|
||||
} else {
|
||||
write_pages_[0] = ram_;
|
||||
}
|
||||
write_pages_[1] = write_pages_[0] + 256;
|
||||
read_pages_[0] = write_pages_[0];
|
||||
read_pages_[1] = write_pages_[1];
|
||||
}
|
||||
write_pages_[1] = write_pages_[0] + 256;
|
||||
read_pages_[0] = write_pages_[0];
|
||||
read_pages_[1] = write_pages_[1];
|
||||
|
||||
// Zero page banking also affects interpretation of the language card's switches.
|
||||
set_language_card_paging();
|
||||
}
|
||||
void set_main_paging() {
|
||||
const auto state = auxiliary_switches_.main_state();
|
||||
if constexpr (bool(type & (PagingType::LanguageCard | PagingType::ZeroPage))) {
|
||||
const auto language_state = language_card_.state();
|
||||
const auto zero_state = auxiliary_switches_.zero_state();
|
||||
|
||||
page(0x02, 0x04,
|
||||
state.base.read ? &aux_ram_[0x0200] : &ram_[0x0200],
|
||||
state.base.write ? &aux_ram_[0x0200] : &ram_[0x0200]);
|
||||
page(0x08, 0x20,
|
||||
state.base.read ? &aux_ram_[0x0800] : &ram_[0x0800],
|
||||
state.base.write ? &aux_ram_[0x0800] : &ram_[0x0800]);
|
||||
page(0x40, 0xc0,
|
||||
state.base.read ? &aux_ram_[0x4000] : &ram_[0x4000],
|
||||
state.base.write ? &aux_ram_[0x4000] : &ram_[0x4000]);
|
||||
uint8_t *const ram = zero_state ? aux_ram_ : ram_;
|
||||
uint8_t *const rom = is_iie() ? &rom_[3840] : rom_.data();
|
||||
|
||||
page(0x04, 0x08,
|
||||
state.region_04_08.read ? &aux_ram_[0x0400] : &ram_[0x0400],
|
||||
state.region_04_08.write ? &aux_ram_[0x0400] : &ram_[0x0400]);
|
||||
// Which way the region here is mapped to be banks 1 and 2 is
|
||||
// arbitrary.
|
||||
page(0xd0, 0xe0,
|
||||
language_state.read ? &ram[language_state.bank2 ? 0xd000 : 0xc000] : rom,
|
||||
language_state.write ? nullptr : &ram[language_state.bank2 ? 0xd000 : 0xc000]);
|
||||
|
||||
page(0x20, 0x40,
|
||||
state.region_20_40.read ? &aux_ram_[0x2000] : &ram_[0x2000],
|
||||
state.region_20_40.write ? &aux_ram_[0x2000] : &ram_[0x2000]);
|
||||
page(0xe0, 0x100,
|
||||
language_state.read ? &ram[0xe000] : &rom[0x1000],
|
||||
language_state.write ? nullptr : &ram[0xe000]);
|
||||
}
|
||||
|
||||
if constexpr (bool(type & PagingType::CardArea)) {
|
||||
const auto state = auxiliary_switches_.card_state();
|
||||
|
||||
page(0xc1, 0xc4, state.region_C1_C3 ? &rom_[0xc100 - 0xc100] : nullptr, nullptr);
|
||||
read_pages_[0xc3] = state.region_C3 ? &rom_[0xc300 - 0xc100] : nullptr;
|
||||
page(0xc4, 0xc8, state.region_C4_C8 ? &rom_[0xc400 - 0xc100] : nullptr, nullptr);
|
||||
page(0xc8, 0xd0, state.region_C8_D0 ? &rom_[0xc800 - 0xc100] : nullptr, nullptr);
|
||||
}
|
||||
|
||||
if constexpr (bool(type & PagingType::Main)) {
|
||||
const auto state = auxiliary_switches_.main_state();
|
||||
|
||||
page(0x02, 0x04,
|
||||
state.base.read ? &aux_ram_[0x0200] : &ram_[0x0200],
|
||||
state.base.write ? &aux_ram_[0x0200] : &ram_[0x0200]);
|
||||
page(0x08, 0x20,
|
||||
state.base.read ? &aux_ram_[0x0800] : &ram_[0x0800],
|
||||
state.base.write ? &aux_ram_[0x0800] : &ram_[0x0800]);
|
||||
page(0x40, 0xc0,
|
||||
state.base.read ? &aux_ram_[0x4000] : &ram_[0x4000],
|
||||
state.base.write ? &aux_ram_[0x4000] : &ram_[0x4000]);
|
||||
|
||||
page(0x04, 0x08,
|
||||
state.region_04_08.read ? &aux_ram_[0x0400] : &ram_[0x0400],
|
||||
state.region_04_08.write ? &aux_ram_[0x0400] : &ram_[0x0400]);
|
||||
|
||||
page(0x20, 0x40,
|
||||
state.region_20_40.read ? &aux_ram_[0x2000] : &ram_[0x2000],
|
||||
state.region_20_40.write ? &aux_ram_[0x2000] : &ram_[0x2000]);
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Keyboard and typing.
|
||||
@ -485,8 +485,7 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
|
||||
|
||||
// Set up the default memory blocks. On a II or II+ these values will never change.
|
||||
// On a IIe they'll be affected by selection of auxiliary RAM.
|
||||
set_main_paging();
|
||||
set_zero_page_paging();
|
||||
set_paging<PagingType::Main | PagingType::ZeroPage>();
|
||||
|
||||
// Set the whole card area to initially backed by nothing.
|
||||
page(0xc0, 0xd0, nullptr, nullptr);
|
||||
|
@ -9,6 +9,8 @@
|
||||
#ifndef AuxiliaryMemorySwitches_h
|
||||
#define AuxiliaryMemorySwitches_h
|
||||
|
||||
#include "MemorySwitches.hpp"
|
||||
|
||||
namespace Apple {
|
||||
namespace II {
|
||||
|
||||
@ -235,7 +237,7 @@ template <typename Machine> class AuxiliaryMemorySwitches {
|
||||
}
|
||||
|
||||
if(previous_state != main_state_) {
|
||||
machine_.set_main_paging();
|
||||
machine_.template set_paging<PagingType::Main>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,14 +260,14 @@ template <typename Machine> class AuxiliaryMemorySwitches {
|
||||
card_state_.region_C8_D0 = switches_.internal_CX_rom || switches_.internal_C8_rom;
|
||||
|
||||
if(previous_state != card_state_) {
|
||||
machine_.set_card_paging();
|
||||
machine_.template set_paging<PagingType::CardArea>();
|
||||
}
|
||||
}
|
||||
|
||||
void set_zero_page_paging() {
|
||||
// Believe it or not, the zero page is just set or cleared by a single flag.
|
||||
// As though life were rational.
|
||||
machine_.set_zero_page_paging();
|
||||
machine_.template set_paging<PagingType::ZeroPage>();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
#ifndef LanguageCardSwitches_h
|
||||
#define LanguageCardSwitches_h
|
||||
|
||||
#include "MemorySwitches.hpp"
|
||||
|
||||
namespace Apple {
|
||||
namespace II {
|
||||
|
||||
@ -70,7 +72,7 @@ template <typename Machine> class LanguageCardSwitches {
|
||||
|
||||
// Apply whatever the net effect of all that is to the memory map.
|
||||
if(previous_state != state_) {
|
||||
machine_.set_language_card_paging();
|
||||
machine_.template set_paging<PagingType::LanguageCard>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,7 +92,7 @@ template <typename Machine> class LanguageCardSwitches {
|
||||
state_.bank2 = value & 0x04;
|
||||
|
||||
if(previous_state != state_) {
|
||||
machine_.set_language_card_paging();
|
||||
machine_.template set_paging<PagingType::LanguageCard>();
|
||||
}
|
||||
}
|
||||
|
||||
|
25
Machines/Apple/AppleII/MemorySwitches.hpp
Normal file
25
Machines/Apple/AppleII/MemorySwitches.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// MemorySwitches.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 27/06/2022.
|
||||
// Copyright © 2022 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef MemorySwitches_h
|
||||
#define MemorySwitches_h
|
||||
|
||||
namespace Apple {
|
||||
namespace II {
|
||||
|
||||
enum PagingType: int {
|
||||
Main = 1 << 0,
|
||||
ZeroPage = 1 << 1,
|
||||
CardArea = 1 << 2,
|
||||
LanguageCard = 1 << 3,
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MemorySwitches_h */
|
@ -20,6 +20,9 @@ namespace Apple {
|
||||
namespace IIgs {
|
||||
|
||||
class MemoryMap {
|
||||
private:
|
||||
using PagingType = Apple::II::PagingType;
|
||||
|
||||
public:
|
||||
// MARK: - Initial construction and configuration.
|
||||
|
||||
@ -179,7 +182,7 @@ class MemoryMap {
|
||||
// TODO: set 1Mhz flags.
|
||||
|
||||
// Apply initial language/auxiliary state.
|
||||
set_all_paging();
|
||||
set_paging<~0>();
|
||||
}
|
||||
|
||||
// MARK: - Live bus access notifications and register access.
|
||||
@ -189,8 +192,7 @@ class MemoryMap {
|
||||
shadow_register_ = value;
|
||||
|
||||
if(diff & 0x40) { // IO/language-card inhibit.
|
||||
set_language_card_paging();
|
||||
set_card_paging();
|
||||
set_paging<PagingType::LanguageCard | PagingType::CardArea>();
|
||||
}
|
||||
|
||||
if(diff & 0x3f) {
|
||||
@ -251,150 +253,178 @@ class MemoryMap {
|
||||
assert(region_map[end-1] == region_map[start]); \
|
||||
assert(region_map[end] == region_map[end-1]+1);
|
||||
|
||||
// Cf. LanguageCardSwitches; this function should 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
|
||||
// may be drawn from either of two pools.
|
||||
void set_language_card_paging() {
|
||||
const auto language_state = language_card_.state();
|
||||
const auto zero_state = auxiliary_switches_.zero_state();
|
||||
const bool inhibit_banks0001 = shadow_register_ & 0x40;
|
||||
template <int type> void set_paging() {
|
||||
// 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
|
||||
// may be drawn from either of two pools.
|
||||
if constexpr (bool(type & (PagingType::LanguageCard | PagingType::ZeroPage))) {
|
||||
const auto language_state = language_card_.state();
|
||||
const auto zero_state = auxiliary_switches_.zero_state();
|
||||
const bool inhibit_banks0001 = shadow_register_ & 0x40;
|
||||
|
||||
auto apply = [&language_state, this](uint32_t bank_base, uint8_t *ram) {
|
||||
// This assumes bank 1 is the one before bank 2 when RAM is linear.
|
||||
uint8_t *const d0_ram_bank = ram - (language_state.bank2 ? 0x0000 : 0x1000);
|
||||
auto apply = [&language_state, this](uint32_t bank_base, uint8_t *ram) {
|
||||
// This assumes bank 1 is the one before bank 2 when RAM is linear.
|
||||
uint8_t *const d0_ram_bank = ram - (language_state.bank2 ? 0x0000 : 0x1000);
|
||||
|
||||
// Crib the ROM pointer from a page it's always visible on.
|
||||
const uint8_t *const rom = ®ions[region_map[0xffd0]].read[0xff'd000] - ((bank_base << 8) + 0xd000);
|
||||
// Crib the ROM pointer from a page it's always visible on.
|
||||
const uint8_t *const rom = ®ions[region_map[0xffd0]].read[0xff'd000] - ((bank_base << 8) + 0xd000);
|
||||
|
||||
auto &d0_region = regions[region_map[bank_base | 0xd0]];
|
||||
d0_region.read = language_state.read ? d0_ram_bank : rom;
|
||||
d0_region.write = language_state.write ? nullptr : d0_ram_bank;
|
||||
auto &d0_region = regions[region_map[bank_base | 0xd0]];
|
||||
d0_region.read = language_state.read ? d0_ram_bank : rom;
|
||||
d0_region.write = language_state.write ? nullptr : d0_ram_bank;
|
||||
|
||||
auto &e0_region = regions[region_map[bank_base | 0xe0]];
|
||||
e0_region.read = language_state.read ? ram : rom;
|
||||
e0_region.write = language_state.write ? nullptr : ram;
|
||||
auto &e0_region = regions[region_map[bank_base | 0xe0]];
|
||||
e0_region.read = language_state.read ? ram : rom;
|
||||
e0_region.write = language_state.write ? nullptr : ram;
|
||||
|
||||
// Assert assumptions made above re: memory layout.
|
||||
assert(region_map[bank_base | 0xd0] + 1 == region_map[bank_base | 0xe0]);
|
||||
assert(region_map[bank_base | 0xe0] == region_map[bank_base | 0xff]);
|
||||
};
|
||||
auto set_no_card = [this](uint32_t bank_base, uint8_t *ram) {
|
||||
auto &d0_region = regions[region_map[bank_base | 0xd0]];
|
||||
d0_region.read = ram;
|
||||
d0_region.write = ram;
|
||||
// Assert assumptions made above re: memory layout.
|
||||
assert(region_map[bank_base | 0xd0] + 1 == region_map[bank_base | 0xe0]);
|
||||
assert(region_map[bank_base | 0xe0] == region_map[bank_base | 0xff]);
|
||||
};
|
||||
auto set_no_card = [this](uint32_t bank_base, uint8_t *ram) {
|
||||
auto &d0_region = regions[region_map[bank_base | 0xd0]];
|
||||
d0_region.read = ram;
|
||||
d0_region.write = ram;
|
||||
|
||||
auto &e0_region = regions[region_map[bank_base | 0xe0]];
|
||||
e0_region.read = ram;
|
||||
e0_region.write = ram;
|
||||
auto &e0_region = regions[region_map[bank_base | 0xe0]];
|
||||
e0_region.read = ram;
|
||||
e0_region.write = ram;
|
||||
|
||||
// Assert assumptions made above re: memory layout.
|
||||
assert(region_map[bank_base | 0xd0] + 1 == region_map[bank_base | 0xe0]);
|
||||
assert(region_map[bank_base | 0xe0] == region_map[bank_base | 0xff]);
|
||||
};
|
||||
// Assert assumptions made above re: memory layout.
|
||||
assert(region_map[bank_base | 0xd0] + 1 == region_map[bank_base | 0xe0]);
|
||||
assert(region_map[bank_base | 0xe0] == region_map[bank_base | 0xff]);
|
||||
};
|
||||
|
||||
if(inhibit_banks0001) {
|
||||
set_no_card(0x0000, zero_state ? &ram_base[0x01'0000] : ram_base);
|
||||
set_no_card(0x0100, ram_base);
|
||||
} else {
|
||||
apply(0x0000, zero_state ? &ram_base[0x01'0000] : ram_base);
|
||||
apply(0x0100, ram_base);
|
||||
}
|
||||
|
||||
// The pointer stored in region_map[0xe000] has already been adjusted for
|
||||
// the 0xe0'0000 addressing offset.
|
||||
uint8_t *const e0_ram = regions[region_map[0xe000]].write;
|
||||
apply(0xe000, e0_ram);
|
||||
apply(0xe100, e0_ram);
|
||||
}
|
||||
|
||||
// Cf. AuxiliarySwitches; this should establish whether ROM or card switches
|
||||
// are exposed in the distinct regions C100–C2FF, C300–C3FF, C400–C7FF and
|
||||
// C800–CFFF.
|
||||
//
|
||||
// On the IIgs it intersects with the current shadow register.
|
||||
//
|
||||
// TODO: so... shouldn't the card mask be incorporated here? I've got it implemented
|
||||
// distinctly at present, but does that create any invalid state interactions?
|
||||
void set_card_paging() {
|
||||
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 = ®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; \
|
||||
if(inhibit_banks0001) {
|
||||
set_no_card(0x0000, zero_state ? &ram_base[0x01'0000] : ram_base);
|
||||
set_no_card(0x0100, ram_base);
|
||||
} else {
|
||||
apply(0x0000, zero_state ? &ram_base[0x01'0000] : ram_base);
|
||||
apply(0x0100, ram_base);
|
||||
}
|
||||
|
||||
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);
|
||||
// The pointer stored in region_map[0xe000] has already been adjusted for
|
||||
// the 0xe0'0000 addressing offset.
|
||||
uint8_t *const e0_ram = regions[region_map[0xe000]].write;
|
||||
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 ®ion = 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 ®ion = 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 C100–C2FF, C300–C3FF, C400–C7FF and C800–CFFF.
|
||||
//
|
||||
// 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 = ®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 | 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);
|
||||
};
|
||||
// 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;
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
// Obey the card state for banks $e0 and $e1.
|
||||
apply(0xe000);
|
||||
apply(0xe100);
|
||||
}
|
||||
|
||||
// Cf. LanguageCardSwitches; this should 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.
|
||||
void set_zero_page_paging() {
|
||||
// Affects bank $00 only, and should be a single region.
|
||||
auto ®ion = 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]);
|
||||
|
||||
// Switching to or from auxiliary RAM potentially affects the
|
||||
// language card area.
|
||||
set_language_card_paging();
|
||||
}
|
||||
|
||||
// IIgs specific: sets or resets the ::IsShadowed flag across affected banks as
|
||||
@ -466,52 +496,6 @@ class MemoryMap {
|
||||
}
|
||||
}
|
||||
|
||||
// Cf. the AuxiliarySwitches; establishes whether main or auxiliary RAM
|
||||
// is exposed in bank $00 for a bunch of regions.
|
||||
void set_main_paging() {
|
||||
const auto state = auxiliary_switches_.main_state();
|
||||
|
||||
#define set(page, flags) {\
|
||||
auto ®ion = 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
|
||||
|
||||
// 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_card_paging();
|
||||
}
|
||||
|
||||
void set_all_paging() {
|
||||
set_card_paging();
|
||||
set_zero_page_paging(); // ... which calls set_language_card_paging().
|
||||
set_main_paging();
|
||||
set_shadowing();
|
||||
}
|
||||
|
||||
void print_state() {
|
||||
uint8_t region = region_map[0];
|
||||
uint32_t start = 0;
|
||||
|
@ -2137,6 +2137,7 @@
|
||||
4BDB3D8522833321002D3CEE /* Keyboard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Keyboard.hpp; sourceTree = "<group>"; };
|
||||
4BDCC5F81FB27A5E001220C5 /* ROMMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ROMMachine.hpp; sourceTree = "<group>"; };
|
||||
4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80MachineCycleTests.swift; sourceTree = "<group>"; };
|
||||
4BE0151C286A8C8E00EA42E9 /* MemorySwitches.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MemorySwitches.hpp; sourceTree = "<group>"; };
|
||||
4BE0A3EC237BB170002AB46F /* ST.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ST.cpp; sourceTree = "<group>"; };
|
||||
4BE0A3ED237BB170002AB46F /* ST.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ST.hpp; sourceTree = "<group>"; };
|
||||
4BE211DD253E4E4800435408 /* 65C02_no_Rockwell_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = 65C02_no_Rockwell_test.bin; path = "Klaus Dormann/65C02_no_Rockwell_test.bin"; sourceTree = "<group>"; };
|
||||
@ -4628,6 +4629,7 @@
|
||||
4BCE004C227CE8CA000CA200 /* DiskIICard.hpp */,
|
||||
4B2E86E125DC95150024F1E9 /* Joystick.hpp */,
|
||||
4BF40A5525424C770033EA39 /* LanguageCardSwitches.hpp */,
|
||||
4BE0151C286A8C8E00EA42E9 /* MemorySwitches.hpp */,
|
||||
4BCE004F227CE8CA000CA200 /* Video.hpp */,
|
||||
4B8DF4F2254E141700F3433C /* VideoSwitches.hpp */,
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user