mirror of
https://github.com/cmosher01/Epple-II.git
synced 2025-01-27 19:36:15 +00:00
119 lines
3.4 KiB
C++
119 lines
3.4 KiB
C++
#include "memoryrow.h"
|
|
#include <stdexcept>
|
|
#include <cstdlib>
|
|
|
|
|
|
|
|
MemoryRow::MemoryRow(const char label):
|
|
label(label) {
|
|
this->chips.fill(MemoryChip::instance("-"));
|
|
}
|
|
|
|
MemoryRow::~MemoryRow() {
|
|
}
|
|
|
|
void MemoryRow::insert_chip(MemoryChip *chip, const std::uint_fast8_t socket) {
|
|
if (socket < 8u) {
|
|
remove_chip(socket);
|
|
if (chip->exists()) {
|
|
this->chips.at(socket) = chip;
|
|
this->missing_bits &= ~(1u << socket);
|
|
this->values_stored.resize(calculate_size());
|
|
}
|
|
} else {
|
|
throw std::out_of_range("socket must be < 8");
|
|
}
|
|
}
|
|
|
|
void MemoryRow::remove_chip(const std::uint_fast8_t socket) {
|
|
if (socket < 8u) {
|
|
this->chips.at(socket) = MemoryChip::instance("-");
|
|
this->missing_bits |= (1u << socket);
|
|
this->values_stored.resize(calculate_size());
|
|
} else {
|
|
throw std::out_of_range("socket must be < 8");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If no chips, return 0.
|
|
* Otherwise, return minimum of existing chips (4K or 16K)
|
|
*/
|
|
std::uint16_t MemoryRow::calculate_size() const {
|
|
std::uint16_t size_new = 0u;
|
|
|
|
for (std::uint_fast8_t i_chip = 0; i_chip < 8; ++i_chip) {
|
|
const MemoryChip *chip = this->chips.at(i_chip);
|
|
if (chip->exists()) {
|
|
const std::uint16_t s = chip->size();
|
|
if (size_new == 0u || s < size_new) {
|
|
size_new = s;
|
|
}
|
|
}
|
|
}
|
|
|
|
return size_new;
|
|
}
|
|
|
|
void MemoryRow::powerOff() {
|
|
this->power = false;
|
|
}
|
|
|
|
/*
|
|
* Calls init of each chip, and uses a bit mask to assemble into bytes.
|
|
*/
|
|
void MemoryRow::powerOn() {
|
|
if (!this->power) {
|
|
this->power = true;
|
|
|
|
std::uint8_t mask_bit = 1u;
|
|
for (std::uint_fast8_t i_bit = 0; i_bit < 8; ++i_bit) {
|
|
const MemoryChip *chip = this->chips.at(i_bit);
|
|
if (chip->exists()) {
|
|
chip->init(mask_bit, this->values_stored, size());
|
|
}
|
|
mask_bit <<= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::uint16_t MemoryRow::size() const {
|
|
return static_cast<std::uint16_t>(this->values_stored.size());
|
|
}
|
|
|
|
std::uint8_t MemoryRow::read(const std::uint16_t address_offset, std::uint8_t data) const {
|
|
if (this->power) {
|
|
if (address_offset < this->values_stored.size()) {
|
|
/* We need to float the data bits corresponding to missing chips:
|
|
* 01010101 data bits (previously places on data bus from elsewhere)
|
|
* 00110011 mask of memory chips (1=missing, 0=present)
|
|
* 00001111 bits stored in chips
|
|
* --------
|
|
* 00010001 data & missing
|
|
* 11001100 ~missing
|
|
* 00001100 stored & ~missing
|
|
* --------
|
|
* 00011101 (stored & ~missing) | (data & missing)
|
|
*/
|
|
data = (this->values_stored.at(address_offset) & ~this->missing_bits) | (data & this->missing_bits);
|
|
}
|
|
return data;
|
|
} else {
|
|
throw std::logic_error("cannot read memory when power is off");
|
|
}
|
|
}
|
|
|
|
void MemoryRow::write(const std::uint16_t address, const std::uint8_t data) {
|
|
if (this->power) {
|
|
// if there are missing bits, they do get stored, so we need to
|
|
// be careful to mask them out when giving them back (in read method)
|
|
this->values_stored.at(address) = data;
|
|
} else {
|
|
throw std::logic_error("cannot write memory when power is off");
|
|
}
|
|
}
|
|
|
|
std::string MemoryRow::chip_id(std::uint_fast8_t socket) const {
|
|
return this->chips.at(socket)->id();
|
|
}
|