1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-09 20:25:19 +00:00

Tweak paging semantics, to allow simple multiple dependencies.

This commit is contained in:
Thomas Harte
2022-06-27 21:38:45 -04:00
parent 5cb0aebdf4
commit 7aeaa4a485
6 changed files with 254 additions and 240 deletions

View File

@@ -183,13 +183,25 @@ 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_; LanguageCardSwitches<ConcreteMachine> language_card_;
AuxiliaryMemorySwitches<ConcreteMachine> auxiliary_switches_; AuxiliaryMemorySwitches<ConcreteMachine> auxiliary_switches_;
friend LanguageCardSwitches<ConcreteMachine>; friend LanguageCardSwitches<ConcreteMachine>;
friend AuxiliaryMemorySwitches<ConcreteMachine>; friend AuxiliaryMemorySwitches<ConcreteMachine>;
void set_language_card_paging() { 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];
}
if constexpr (bool(type & (PagingType::LanguageCard | PagingType::ZeroPage))) {
const auto language_state = language_card_.state(); const auto language_state = language_card_.state();
const auto zero_state = auxiliary_switches_.zero_state(); const auto zero_state = auxiliary_switches_.zero_state();
@@ -207,8 +219,7 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
language_state.write ? nullptr : &ram[0xe000]); language_state.write ? nullptr : &ram[0xe000]);
} }
// MARK: Auxiliary memory and the other IIe improvements. if constexpr (bool(type & PagingType::CardArea)) {
void set_card_paging() {
const auto state = auxiliary_switches_.card_state(); const auto state = auxiliary_switches_.card_state();
page(0xc1, 0xc4, state.region_C1_C3 ? &rom_[0xc100 - 0xc100] : nullptr, nullptr); page(0xc1, 0xc4, state.region_C1_C3 ? &rom_[0xc100 - 0xc100] : nullptr, nullptr);
@@ -216,20 +227,8 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
page(0xc4, 0xc8, state.region_C4_C8 ? &rom_[0xc400 - 0xc100] : nullptr, 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); 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_;
}
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. if constexpr (bool(type & PagingType::Main)) {
set_language_card_paging();
}
void set_main_paging() {
const auto state = auxiliary_switches_.main_state(); const auto state = auxiliary_switches_.main_state();
page(0x02, 0x04, page(0x02, 0x04,
@@ -250,6 +249,7 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
state.region_20_40.read ? &aux_ram_[0x2000] : &ram_[0x2000], state.region_20_40.read ? &aux_ram_[0x2000] : &ram_[0x2000],
state.region_20_40.write ? &aux_ram_[0x2000] : &ram_[0x2000]); state.region_20_40.write ? &aux_ram_[0x2000] : &ram_[0x2000]);
} }
}
// MARK: - Keyboard and typing. // 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. // 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. // On a IIe they'll be affected by selection of auxiliary RAM.
set_main_paging(); set_paging<PagingType::Main | PagingType::ZeroPage>();
set_zero_page_paging();
// Set the whole card area to initially backed by nothing. // Set the whole card area to initially backed by nothing.
page(0xc0, 0xd0, nullptr, nullptr); page(0xc0, 0xd0, nullptr, nullptr);

View File

@@ -9,6 +9,8 @@
#ifndef AuxiliaryMemorySwitches_h #ifndef AuxiliaryMemorySwitches_h
#define AuxiliaryMemorySwitches_h #define AuxiliaryMemorySwitches_h
#include "MemorySwitches.hpp"
namespace Apple { namespace Apple {
namespace II { namespace II {
@@ -235,7 +237,7 @@ template <typename Machine> class AuxiliaryMemorySwitches {
} }
if(previous_state != main_state_) { 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; card_state_.region_C8_D0 = switches_.internal_CX_rom || switches_.internal_C8_rom;
if(previous_state != card_state_) { if(previous_state != card_state_) {
machine_.set_card_paging(); machine_.template set_paging<PagingType::CardArea>();
} }
} }
void set_zero_page_paging() { void set_zero_page_paging() {
// Believe it or not, the zero page is just set or cleared by a single flag. // Believe it or not, the zero page is just set or cleared by a single flag.
// As though life were rational. // As though life were rational.
machine_.set_zero_page_paging(); machine_.template set_paging<PagingType::ZeroPage>();
} }
}; };

View File

@@ -9,6 +9,8 @@
#ifndef LanguageCardSwitches_h #ifndef LanguageCardSwitches_h
#define LanguageCardSwitches_h #define LanguageCardSwitches_h
#include "MemorySwitches.hpp"
namespace Apple { namespace Apple {
namespace II { namespace II {
@@ -70,7 +72,7 @@ template <typename Machine> class LanguageCardSwitches {
// Apply whatever the net effect of all that is to the memory map. // Apply whatever the net effect of all that is to the memory map.
if(previous_state != state_) { 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; state_.bank2 = value & 0x04;
if(previous_state != state_) { if(previous_state != state_) {
machine_.set_language_card_paging(); machine_.template set_paging<PagingType::LanguageCard>();
} }
} }

View 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 */

View File

@@ -20,6 +20,9 @@ namespace Apple {
namespace IIgs { namespace IIgs {
class MemoryMap { class MemoryMap {
private:
using PagingType = Apple::II::PagingType;
public: public:
// MARK: - Initial construction and configuration. // MARK: - Initial construction and configuration.
@@ -179,7 +182,7 @@ class MemoryMap {
// TODO: set 1Mhz flags. // TODO: set 1Mhz flags.
// Apply initial language/auxiliary state. // Apply initial language/auxiliary state.
set_all_paging(); set_paging<~0>();
} }
// MARK: - Live bus access notifications and register access. // MARK: - Live bus access notifications and register access.
@@ -189,8 +192,7 @@ class MemoryMap {
shadow_register_ = value; shadow_register_ = value;
if(diff & 0x40) { // IO/language-card inhibit. if(diff & 0x40) { // IO/language-card inhibit.
set_language_card_paging(); set_paging<PagingType::LanguageCard | PagingType::CardArea>();
set_card_paging();
} }
if(diff & 0x3f) { if(diff & 0x3f) {
@@ -251,11 +253,12 @@ class MemoryMap {
assert(region_map[end-1] == region_map[start]); \ assert(region_map[end-1] == region_map[start]); \
assert(region_map[end] == region_map[end-1]+1); assert(region_map[end] == region_map[end-1]+1);
// Cf. LanguageCardSwitches; this function should update the region from template <int type> void set_paging() {
// Update the region from
// $D000 onwards as per the state of the language card flags — there may // $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 // end up being ROM or RAM (or auxiliary RAM), and the first 4kb of it
// may be drawn from either of two pools. // may be drawn from either of two pools.
void set_language_card_paging() { if constexpr (bool(type & (PagingType::LanguageCard | PagingType::ZeroPage))) {
const auto language_state = language_card_.state(); const auto language_state = language_card_.state();
const auto zero_state = auxiliary_switches_.zero_state(); const auto zero_state = auxiliary_switches_.zero_state();
const bool inhibit_banks0001 = shadow_register_ & 0x40; const bool inhibit_banks0001 = shadow_register_ & 0x40;
@@ -306,17 +309,58 @@ class MemoryMap {
uint8_t *const e0_ram = regions[region_map[0xe000]].write; uint8_t *const e0_ram = regions[region_map[0xe000]].write;
apply(0xe000, e0_ram); apply(0xe000, e0_ram);
apply(0xe100, e0_ram); apply(0xe100, e0_ram);
} }
// Cf. AuxiliarySwitches; this should establish whether ROM or card switches // Establish whether main or auxiliary RAM
// are exposed in the distinct regions C100C2FF, C300C3FF, C400C7FF and // is exposed in bank $00 for a bunch of regions.
// C800CFFF. 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. // On the IIgs it intersects with the current shadow register.
// if constexpr (bool(type & (PagingType::CardArea | PagingType::Main))) {
// 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 bool inhibit_banks0001 = shadow_register_ & 0x40;
const auto state = auxiliary_switches_.card_state(); const auto state = auxiliary_switches_.card_state();
@@ -381,20 +425,6 @@ class MemoryMap {
apply(0xe000); apply(0xe000);
apply(0xe100); 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 &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]);
// 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 // 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 &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
// 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() { void print_state() {
uint8_t region = region_map[0]; uint8_t region = region_map[0];
uint32_t start = 0; uint32_t start = 0;

View File

@@ -2137,6 +2137,7 @@
4BDB3D8522833321002D3CEE /* Keyboard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Keyboard.hpp; sourceTree = "<group>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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 */, 4BCE004C227CE8CA000CA200 /* DiskIICard.hpp */,
4B2E86E125DC95150024F1E9 /* Joystick.hpp */, 4B2E86E125DC95150024F1E9 /* Joystick.hpp */,
4BF40A5525424C770033EA39 /* LanguageCardSwitches.hpp */, 4BF40A5525424C770033EA39 /* LanguageCardSwitches.hpp */,
4BE0151C286A8C8E00EA42E9 /* MemorySwitches.hpp */,
4BCE004F227CE8CA000CA200 /* Video.hpp */, 4BCE004F227CE8CA000CA200 /* Video.hpp */,
4B8DF4F2254E141700F3433C /* VideoSwitches.hpp */, 4B8DF4F2254E141700F3433C /* VideoSwitches.hpp */,
); );