2020-10-23 01:01:12 +00:00
|
|
|
|
//
|
2020-10-23 02:33:31 +00:00
|
|
|
|
// LanguageCardSwitches.hpp
|
2020-10-23 01:01:12 +00:00
|
|
|
|
// Clock Signal
|
|
|
|
|
//
|
|
|
|
|
// Created by Thomas Harte on 22/10/2020.
|
|
|
|
|
// Copyright © 2020 Thomas Harte. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
2020-10-23 02:33:31 +00:00
|
|
|
|
#ifndef LanguageCardSwitches_h
|
|
|
|
|
#define LanguageCardSwitches_h
|
2020-10-23 01:01:12 +00:00
|
|
|
|
|
2022-06-28 01:38:45 +00:00
|
|
|
|
#include "MemorySwitches.hpp"
|
|
|
|
|
|
2023-05-10 21:02:18 +00:00
|
|
|
|
namespace Apple::II {
|
2020-10-23 01:01:12 +00:00
|
|
|
|
|
2020-10-23 22:44:47 +00:00
|
|
|
|
/*!
|
|
|
|
|
Models the language card soft switches, present on any Apple II with a language card and provided built-in from the IIe onwards.
|
|
|
|
|
|
|
|
|
|
Relevant memory accesses should be fed to this class; it'll call:
|
|
|
|
|
* machine.set_language_card_paging() if the proper mapped state changes.
|
|
|
|
|
*/
|
2020-10-23 02:33:31 +00:00
|
|
|
|
template <typename Machine> class LanguageCardSwitches {
|
2020-10-23 01:01:12 +00:00
|
|
|
|
public:
|
|
|
|
|
struct State {
|
2020-11-05 02:15:10 +00:00
|
|
|
|
/// When RAM is visible in the range $D000–$FFFF:
|
2020-12-06 00:07:38 +00:00
|
|
|
|
/// @c true indicates that bank 2 should be used between $D000 and $DFFF;
|
2020-12-01 03:35:51 +00:00
|
|
|
|
/// @c false indicates bank 1.
|
|
|
|
|
bool bank2 = true;
|
2020-10-23 01:01:12 +00:00
|
|
|
|
|
|
|
|
|
/// @c true indicates that RAM should be readable in the range $D000–$FFFF;
|
2020-11-05 02:15:10 +00:00
|
|
|
|
/// @c false indicates ROM should be readable.
|
2020-10-23 01:01:12 +00:00
|
|
|
|
bool read = false;
|
|
|
|
|
|
|
|
|
|
/// @c true indicates that ROM is selected for 'writing' in the range $D000–$FFFF (i.e. writes are a no-op);
|
|
|
|
|
/// @c false indicates that RAM is selected for writing.
|
|
|
|
|
bool write = false;
|
|
|
|
|
|
2020-10-23 22:44:47 +00:00
|
|
|
|
bool operator != (const State &rhs) const {
|
|
|
|
|
return
|
2020-12-01 03:35:51 +00:00
|
|
|
|
bank2 != rhs.bank2 ||
|
2020-10-23 22:44:47 +00:00
|
|
|
|
read != rhs.read ||
|
|
|
|
|
write != rhs.write;
|
|
|
|
|
}
|
2020-10-23 01:01:12 +00:00
|
|
|
|
};
|
|
|
|
|
|
2020-10-23 02:33:31 +00:00
|
|
|
|
LanguageCardSwitches(Machine &machine) : machine_(machine) {}
|
2020-10-23 01:01:12 +00:00
|
|
|
|
|
2020-10-23 02:33:31 +00:00
|
|
|
|
/// Used by an owner to forward any access to $c08x.
|
2020-10-23 01:01:12 +00:00
|
|
|
|
void access(uint16_t address, bool is_read) {
|
2020-10-23 22:44:47 +00:00
|
|
|
|
const auto previous_state = state_;
|
|
|
|
|
|
2020-10-23 01:01:12 +00:00
|
|
|
|
// Quotes below taken from Understanding the Apple II, p. 5-28 and 5-29.
|
|
|
|
|
|
2020-11-05 02:15:10 +00:00
|
|
|
|
// "A3 controls the 4K bank selection"; 0 = bank 2, 1 = bank 1.
|
2020-12-01 03:35:51 +00:00
|
|
|
|
state_.bank2 = !(address & 8);
|
2020-10-23 01:01:12 +00:00
|
|
|
|
|
|
|
|
|
// "Access to $C080, $C083, $C084, $0087, $C088, $C08B, $C08C, or $C08F sets the READ ENABLE flip-flop"
|
|
|
|
|
// (other accesses reset it)
|
|
|
|
|
state_.read = !(((address&2) >> 1) ^ (address&1));
|
|
|
|
|
|
|
|
|
|
// "The WRITE ENABLE' flip-flop is reset by an odd read access to the $C08X range when the PRE-WRITE flip-flop is set."
|
2020-10-23 22:44:47 +00:00
|
|
|
|
if(pre_write_ && is_read && (address&1)) state_.write = false;
|
2020-10-23 01:01:12 +00:00
|
|
|
|
|
|
|
|
|
// "[The WRITE ENABLE' flip-flop] is set by an even access in the $C08X range."
|
|
|
|
|
if(!(address&1)) state_.write = true;
|
|
|
|
|
|
|
|
|
|
// ("Any other type of access causes the WRITE ENABLE' flip-flop to hold its current state.")
|
|
|
|
|
|
|
|
|
|
// "The PRE-WRITE flip-flop is set by an odd read access in the $C08X range. It is reset by an even access or a write access."
|
2020-10-23 22:44:47 +00:00
|
|
|
|
pre_write_ = is_read ? (address&1) : false;
|
2020-10-23 01:01:12 +00:00
|
|
|
|
|
|
|
|
|
// Apply whatever the net effect of all that is to the memory map.
|
2020-10-23 22:44:47 +00:00
|
|
|
|
if(previous_state != state_) {
|
2022-06-28 01:38:45 +00:00
|
|
|
|
machine_.template set_paging<PagingType::LanguageCard>();
|
2020-10-23 22:44:47 +00:00
|
|
|
|
}
|
2020-10-23 01:01:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Provides read-only access to the current language card switch state.
|
2020-10-29 01:58:20 +00:00
|
|
|
|
const State &state() const {
|
2020-10-23 01:01:12 +00:00
|
|
|
|
return state_;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-29 01:58:20 +00:00
|
|
|
|
/// Provides relevant parts of the IIgs interface.
|
|
|
|
|
void set_state(uint8_t value) {
|
|
|
|
|
const auto previous_state = state_;
|
|
|
|
|
|
2020-11-05 02:15:10 +00:00
|
|
|
|
// Bit 3: 1 => enable ROM, 0 => enable RAM.
|
|
|
|
|
state_.read = !(value & 0x08);
|
2020-12-11 03:11:53 +00:00
|
|
|
|
// Bit 2: 1 => select bank 2, 0 => select bank 1. [per errata to the Hardware Reference
|
|
|
|
|
// correcting the original, which lists them the other way around]
|
2020-12-01 03:35:51 +00:00
|
|
|
|
state_.bank2 = value & 0x04;
|
2020-10-29 01:58:20 +00:00
|
|
|
|
|
|
|
|
|
if(previous_state != state_) {
|
2022-06-28 01:38:45 +00:00
|
|
|
|
machine_.template set_paging<PagingType::LanguageCard>();
|
2020-10-29 01:58:20 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-10 03:11:20 +00:00
|
|
|
|
uint8_t get_state() const {
|
|
|
|
|
return
|
|
|
|
|
(state_.read ? 0x00 : 0x08) |
|
2020-12-01 03:35:51 +00:00
|
|
|
|
(state_.bank2 ? 0x04 : 0x00);
|
2020-11-10 03:11:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-23 01:01:12 +00:00
|
|
|
|
private:
|
|
|
|
|
Machine &machine_;
|
|
|
|
|
State state_;
|
2020-10-23 22:44:47 +00:00
|
|
|
|
|
|
|
|
|
// This is an additional flip flop contained on the language card, but
|
|
|
|
|
// it is one step removed from current banking state, so I've excluded it
|
|
|
|
|
// from the State struct.
|
|
|
|
|
bool pre_write_ = false;
|
2020-10-23 01:01:12 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* LanguageCard_h */
|