add RAM chips and better init algorithm; dump RAM

This commit is contained in:
Christopher Mosher 2019-02-07 00:45:54 -05:00
parent 4964d8af84
commit 270e94a76a
13 changed files with 203 additions and 67 deletions

View File

@ -10,9 +10,9 @@
# 48K RAM # 48K RAM
motherboard ram E 16K motherboard ram E MM5290 MM5290 MM5290 MK4116 MM5290 MM5290 MM5290 MK4116
motherboard ram D 16K motherboard ram D MM5290 MM5290 MK4116 MK4116 MM5290 MK4116 MM5290 MCM4116
motherboard ram C 16K motherboard ram C MK4116 MK4116 MM5290 MM5290 MM5290 MM5290 MM5290 MM5290
motherboard strap E 16K 8000 motherboard strap E 16K 8000
motherboard strap D 16K 4000 motherboard strap D 16K 4000
motherboard strap C 16K 0000 motherboard strap C 16K 0000

View File

@ -12,9 +12,9 @@
# standard 48K RAM # standard 48K RAM
motherboard ram E 16K motherboard ram E MM5290 MM5290 MM5290 MK4116 MM5290 MM5290 MM5290 MK4116
motherboard ram D 16K motherboard ram D MM5290 MM5290 MK4116 MK4116 MM5290 MK4116 MM5290 MCM4116
motherboard ram C 16K motherboard ram C MK4116 MK4116 MM5290 MM5290 MM5290 MM5290 MM5290 MM5290
motherboard strap E 16K 8000 motherboard strap E 16K 8000
motherboard strap D 16K 4000 motherboard strap D 16K 4000
motherboard strap C 16K 0000 motherboard strap C 16K 0000

View File

@ -42,18 +42,7 @@
#define K 1024u #define K 1024u
static std::uint16_t chip_size(const std::string &chip_model) {
if (chip_model == "4K") {
return 4u*K;
}
if (chip_model == "16K") {
return 16u*K;
}
if (chip_model == "-") {
return 0u;
}
throw ConfigException("unrecognized RAM chip model");
}
static std::uint16_t memory_block_size(const std::string &block_size) { static std::uint16_t memory_block_size(const std::string &block_size) {
if (block_size == "4K") { if (block_size == "4K") {
@ -233,27 +222,23 @@ void Config::tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memo
if (row != "C" && row != "D" && row != "E") { if (row != "C" && row != "D" && row != "E") {
throw ConfigException("expected row to be C, D, or E"); throw ConfigException("expected row to be C, D, or E");
} }
std::string chip_model; std::string chip_model;
tok >> chip_model; tok >> chip_model;
std::uint16_t siz = chip_size(chip_model);
for (std::uint_fast8_t bit = 0u; bit < 8u; ++bit) { for (std::uint_fast8_t bit = 0u; bit < 8u; ++bit) {
if (siz) { ram.insert_chip(row, MemoryChip::instance(chip_model), bit);
ram.insert_chip(row, MemoryChip(siz,chip_model), bit);
} else {
ram.remove_chip(row, bit);
}
std::string chip_model_optional; std::string chip_model_optional;
tok >> chip_model_optional; tok >> chip_model_optional;
if (chip_model_optional.length()) { if (chip_model_optional.length()) {
chip_model = chip_model_optional; chip_model = chip_model_optional;
} }
siz = chip_size(chip_model);
} }
} else if (op == "strap") { } else if (op == "strap") {
/* strap ROM K start-addr /* strap ROM K start-addr
* strap c 4K 0000 * strap e 4K 5000
* strap d 4K 1000 * strap d 4K 4000
* strap e 4K 2000 * strap c 16K 0000
*/ */
std::string row; std::string row;
tok >> row; tok >> row;

View File

@ -73,6 +73,7 @@ void Emulator::powerOffComputer() {
void Emulator::config(Config& cfg) { void Emulator::config(Config& cfg) {
cfg.parse(this->apple2.ram, this->apple2.rom, this->apple2.slts, this->apple2.revision, this->screenImage, this->apple2.cassetteIn, this->apple2.cassetteOut); cfg.parse(this->apple2.ram, this->apple2.rom, this->apple2.slts, this->apple2.revision, this->screenImage, this->apple2.cassetteIn, this->apple2.cassetteOut);
this->apple2.ram.dump_config();
} }
void Emulator::init() { void Emulator::init() {

View File

@ -217,6 +217,7 @@ LSS::LSS(bool use13SectorDos32LSS):
setseq(lss13rom,0x23u,0x30u); setseq(lss13rom,0x23u,0x30u);
setseq(lss13rom,0x33u,0xD0u); setseq(lss13rom,0x33u,0xD0u);
printf("Disk ][ Controller Logic State Sequencer ROM:\n");
if (use13Sector) { if (use13Sector) {
for (unsigned int seq = 0; seq < 0x100u; seq += 0x10u) { for (unsigned int seq = 0; seq < 0x100u; seq += 0x10u) {
showua2seq(lss13rom,seq); showua2seq(lss13rom,seq);

View File

@ -2,9 +2,39 @@
#include <stdexcept> #include <stdexcept>
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include <cstdlib>
#define K 1024 #define K 1024
static MemoryChip *chip_empty = new MemoryChipEmptySocket();
static MemoryChip *chip_4096 = new MemoryChip(4u*K, "4096");
static MemoryChip *chip_4116 = new MemoryChip(16u*K, "4116");
static MemoryChip *chip_mm5290 = new MemoryChipMM5290();
static MemoryChip *chip_mk4116 = new MemoryChipMK4116();
static MemoryChip *chip_mcm4116 = new MemoryChipMCM4116();
MemoryChip *MemoryChip::instance(const std::string &id_model) {
if (id_model == "-") {
return chip_empty;
}
if (id_model == "4K" || id_model == "4096") {
return chip_4096;
}
if (id_model == "16K" || id_model == "4116") {
return chip_4116;
}
if (id_model == "MM5290") {
return chip_mm5290;
}
if (id_model == "MK4116") {
return chip_mk4116;
}
if (id_model == "MCM4116") {
return chip_mcm4116;
}
throw std::logic_error("unrecognized RAM chip model: "+id_model);
}
MemoryChip::MemoryChip(const std::uint16_t size, const std::string &id_model): MemoryChip::MemoryChip(const std::uint16_t size, const std::string &id_model):
size_bits(size), size_bits(size),
id_model(id_model) { id_model(id_model) {
@ -13,17 +43,6 @@ MemoryChip::MemoryChip(const std::uint16_t size, const std::string &id_model):
} }
} }
MemoryChip::MemoryChip(const MemoryChip &that):
size_bits(that.size_bits),
id_model(that.id_model) {
}
MemoryChip &MemoryChip::operator=(const MemoryChip &that) {
this->size_bits = that.size_bits;
this->id_model = that.id_model;
return *this;
}
MemoryChip::~MemoryChip() { MemoryChip::~MemoryChip() {
} }
@ -47,21 +66,44 @@ static void bitflag(const bool on, const std::uint8_t mask, std::uint8_t &byte)
} }
} }
//#define CYCLE 128u
#define CYCLE 2u
void MemoryChip::init(const std::uint8_t mask, std::vector<std::uint8_t> &bytes, const std::uint16_t size) const { void MemoryChip::init(const std::uint8_t mask, std::vector<std::uint8_t> &bytes, const std::uint16_t size) const {
rand_init(mask, bytes, size, 128u, 0.0, 0.0);
}
void MemoryChip::rand_init(const std::uint8_t mask, std::vector<std::uint8_t> &bytes, const std::uint16_t size, const std::uint_fast32_t cycle, const double glitch, const double chaos) const {
const double GLITCH = glitch*0.001;
const double CHAOS = chaos*0.05;
std::uint_fast32_t c_cycle = 0u;
std::uint_fast32_t c_chaos16 = 65u;
std::uint_fast32_t c_chaos16sub = 15u;
bool on = false; bool on = false;
std::uint8_t c = 0u; for (std::uint_fast16_t i = 0u; i < 16*K; ++i) {
for (std::uint16_t i = 0u; i < std::min(size, this->size_bits); ++i) { double r = static_cast<double>(std::rand())/RAND_MAX;
bitflag(on, mask, bytes[i]); bool is_rand = false;
if (CYCLE <= ++c) { if (r < GLITCH && c_chaos16 == 65u) {
c = 0u; --c_chaos16;
}
if (c_chaos16 < 65u) {
if (c_chaos16sub-- == 0u) {
is_rand = true;
c_chaos16sub = 15u;
if (c_chaos16-- == 0u) {
c_chaos16 = 65u;
}
}
}
is_rand |= (r < CHAOS);
bitflag(is_rand?!on:on, mask, bytes[i]);
if (c_cycle++ == cycle-1) {
on = !on; on = !on;
c_cycle = 0u;
} }
} }
} }
MemoryChipEmptySocket::MemoryChipEmptySocket(): MemoryChipEmptySocket::MemoryChipEmptySocket():
MemoryChip(4*K,"[empty]") { MemoryChip(4*K,"[empty]") {
} }
@ -72,3 +114,41 @@ MemoryChipEmptySocket::~MemoryChipEmptySocket() {
bool MemoryChipEmptySocket::exists() const { bool MemoryChipEmptySocket::exists() const {
return false; return false;
} }
MemoryChipMM5290::MemoryChipMM5290(): // National Semiconductor
MemoryChip(16*K,"MM5290") {
}
MemoryChipMM5290::~MemoryChipMM5290() {
}
void MemoryChipMM5290::init(const std::uint8_t mask, std::vector<std::uint8_t> &bytes, const std::uint16_t size) const {
rand_init(mask, bytes, size, 128u, 0.1, 0.05);
}
MemoryChipMK4116::MemoryChipMK4116(): // Mostek
MemoryChip(16*K,"MK4116") {
}
MemoryChipMK4116::~MemoryChipMK4116() {
}
void MemoryChipMK4116::init(const std::uint8_t mask, std::vector<std::uint8_t> &bytes, const std::uint16_t size) const {
rand_init(mask, bytes, size, 2u, 0.1, 0.05);
}
MemoryChipMCM4116::MemoryChipMCM4116(): // Motorola
MemoryChip(16*K,"MCM4116") {
}
MemoryChipMCM4116::~MemoryChipMCM4116() {
}
void MemoryChipMCM4116::init(const std::uint8_t mask, std::vector<std::uint8_t> &bytes, const std::uint16_t size) const {
rand_init(mask, bytes, size, 4096u, 0.1, 0.05);
}

View File

@ -7,17 +7,18 @@
class MemoryChip { class MemoryChip {
private: private:
std::uint16_t size_bits; const std::uint16_t size_bits;
std::string id_model; const std::string id_model;
public: public:
static MemoryChip *instance(const std::string &id_model);
MemoryChip(const std::uint16_t size, const std::string &id_model); MemoryChip(const std::uint16_t size, const std::string &id_model);
MemoryChip(const MemoryChip &that);
MemoryChip &operator=(const MemoryChip &that);
virtual ~MemoryChip(); virtual ~MemoryChip();
std::uint16_t size() const; std::uint16_t size() const;
std::string id() const; std::string id() const;
virtual void init(const std::uint8_t mask, std::vector<std::uint8_t> &bytes, const std::uint16_t size) const; virtual void init(const std::uint8_t mask, std::vector<std::uint8_t> &bytes, const std::uint16_t size) const;
virtual bool exists() const; virtual bool exists() const;
protected:
virtual void rand_init(const std::uint8_t mask, std::vector<std::uint8_t> &bytes, const std::uint16_t size, const std::uint_fast32_t cycle, const double glitch, const double chaos) const;
}; };
class MemoryChipEmptySocket : public MemoryChip { class MemoryChipEmptySocket : public MemoryChip {
@ -27,4 +28,25 @@ class MemoryChipEmptySocket : public MemoryChip {
virtual bool exists() const; virtual bool exists() const;
}; };
class MemoryChipMM5290 : public MemoryChip {
public:
MemoryChipMM5290();
virtual ~MemoryChipMM5290();
virtual void init(const std::uint8_t mask, std::vector<std::uint8_t> &bytes, const std::uint16_t size) const;
};
class MemoryChipMK4116 : public MemoryChip {
public:
MemoryChipMK4116();
virtual ~MemoryChipMK4116();
virtual void init(const std::uint8_t mask, std::vector<std::uint8_t> &bytes, const std::uint16_t size) const;
};
class MemoryChipMCM4116 : public MemoryChip {
public:
MemoryChipMCM4116();
virtual ~MemoryChipMCM4116();
virtual void init(const std::uint8_t mask, std::vector<std::uint8_t> &bytes, const std::uint16_t size) const;
};
#endif // MEMORYCHIP_H #endif // MEMORYCHIP_H

View File

@ -1,5 +1,6 @@
#include "memoryrandomaccess.h" #include "memoryrandomaccess.h"
#include <cstdint> #include <cstdint>
#include <cstdio>
#include <exception> #include <exception>
#define K 1024u #define K 1024u
@ -40,7 +41,7 @@ MemoryStrapping &MemoryRandomAccess::strapping_of(const std::string &row) {
throw std::logic_error("expected C/D/E"); throw std::logic_error("expected C/D/E");
} }
void MemoryRandomAccess::insert_chip(const std::string &row, MemoryChip chip, const std::uint_fast8_t socket) { void MemoryRandomAccess::insert_chip(const std::string &row, MemoryChip *chip, const std::uint_fast8_t socket) {
row_of(row).insert_chip(chip, socket); row_of(row).insert_chip(chip, socket);
} }
@ -147,3 +148,35 @@ void MemoryRandomAccess::powerOff() {
this->rowD.powerOff(); this->rowD.powerOff();
this->rowC.powerOff(); this->rowC.powerOff();
} }
static void dump_row(const std::string &name, const MemoryRow &row) {
std::printf("RAM %s ", name.c_str());
for (std::uint_fast8_t i = 0u; i < 8u; ++i) {
std::printf("%s ", row.chip_id(i).c_str());
}
std::printf("\n");
}
void MemoryRandomAccess::dump_config() const {
std::printf("motherboard RAM rows contain chips:\n");
std::printf(" "); dump_row("E", this->rowE);
std::printf(" "); dump_row("D", this->rowD);
std::printf(" "); dump_row("C", this->rowC);
std::printf("address $1000 blocks strapped to RAM row:\n");
std::uint_fast8_t i = 0xCu;
while (i--) {
std::string r;
const uint16_t addr = i*0x1000u;
if (this->strapE.contains(addr)) {
r = "E";
} else if (this->strapD.contains(addr)) {
r = "D";
} else if (this->strapC.contains(addr)) {
r = "C";
} else {
r = "[not strapped]";
}
std::printf(" $%X %s\n", i, r.c_str());
}
std::printf("total RAM: %dK\n", (this->strapE.size()+this->strapD.size()+this->strapC.size())/1024u);
}

View File

@ -25,7 +25,9 @@ class MemoryRandomAccess {
public: public:
MemoryRandomAccess(int &revision); MemoryRandomAccess(int &revision);
void insert_chip(const std::string &row, MemoryChip chip, const std::uint_fast8_t socket); void dump_config() const;
void insert_chip(const std::string &row, MemoryChip *chip, const std::uint_fast8_t socket);
void remove_chip(const std::string &row, const std::uint_fast8_t socket); void remove_chip(const std::string &row, const std::uint_fast8_t socket);
void strap_to(const std::string &row, std::uint16_t addr_base, std::uint16_t addr_size); void strap_to(const std::string &row, std::uint16_t addr_base, std::uint16_t addr_size);

View File

@ -5,14 +5,14 @@
/* /*
* If any RAM IC sockets are empty, set the corresponding bits to 1 most of the time. * If any RAM IC sockets are empty, set the corresponding bits to 1 most of the time.
* For some addresses it seems they are always 1, but for other addresses they can return * For some addresses it seems they are always 1, but for other addresses they can return
* 0 sometimes, empirically I've seen anywhere from 8% to 15% of the time. * 0 sometimes, empirically about 4% of the time.
*/ */
static std::uint8_t randomize_missing_bits(std::uint8_t v, const std::uint8_t bits) { static std::uint8_t randomize_missing_bits(std::uint8_t v, const std::uint8_t bits) {
std::uint8_t bit = 1u; std::uint8_t bit = 1u;
for (std::uint_fast8_t i = 0; i < 8; ++i) { for (std::uint_fast8_t i = 0; i < 8; ++i) {
if (bits & bit) { if (bits & bit) {
double r = static_cast<double>(std::rand())/RAND_MAX; double r = static_cast<double>(std::rand())/RAND_MAX;
if (r < 0.11) { if (r < 0.04) {
v &= ~bit; v &= ~bit;
} else { } else {
v |= bit; v |= bit;
@ -27,15 +27,16 @@ static std::uint8_t randomize_missing_bits(std::uint8_t v, const std::uint8_t bi
MemoryRow::MemoryRow(const char label): MemoryRow::MemoryRow(const char label):
label(label) { label(label) {
this->chips.fill(MemoryChip::instance("-"));
} }
MemoryRow::~MemoryRow() { MemoryRow::~MemoryRow() {
} }
void MemoryRow::insert_chip(MemoryChip chip, const std::uint_fast8_t socket) { void MemoryRow::insert_chip(MemoryChip *chip, const std::uint_fast8_t socket) {
if (socket < 8u) { if (socket < 8u) {
remove_chip(socket); remove_chip(socket);
if (chip.exists()) { if (chip->exists()) {
this->chips[socket] = chip; this->chips[socket] = chip;
this->missing_bits &= ~(1u << socket); this->missing_bits &= ~(1u << socket);
this->values_stored.resize(calculate_size()); this->values_stored.resize(calculate_size());
@ -47,7 +48,7 @@ void MemoryRow::insert_chip(MemoryChip chip, const std::uint_fast8_t socket) {
void MemoryRow::remove_chip(const std::uint_fast8_t socket) { void MemoryRow::remove_chip(const std::uint_fast8_t socket) {
if (socket < 8u) { if (socket < 8u) {
this->chips[socket] = MemoryChipEmptySocket(); this->chips[socket] = MemoryChip::instance("-");
this->missing_bits |= (1u << socket); this->missing_bits |= (1u << socket);
this->values_stored.resize(calculate_size()); this->values_stored.resize(calculate_size());
} else { } else {
@ -63,9 +64,9 @@ std::uint16_t MemoryRow::calculate_size() const {
std::uint16_t size_new = 0u; std::uint16_t size_new = 0u;
for (std::uint_fast8_t i_chip = 0; i_chip < 8; ++i_chip) { for (std::uint_fast8_t i_chip = 0; i_chip < 8; ++i_chip) {
const MemoryChip &chip = this->chips[i_chip]; const MemoryChip *chip = this->chips[i_chip];
if (chip.exists()) { if (chip->exists()) {
const std::uint16_t s = chip.size(); const std::uint16_t s = chip->size();
if (size_new == 0u || s < size_new) { if (size_new == 0u || s < size_new) {
size_new = s; size_new = s;
} }
@ -88,9 +89,9 @@ void MemoryRow::powerOn() {
std::uint8_t mask_bit = 1u; std::uint8_t mask_bit = 1u;
for (std::uint_fast8_t i_bit = 0; i_bit < 8; ++i_bit) { for (std::uint_fast8_t i_bit = 0; i_bit < 8; ++i_bit) {
const MemoryChip &chip = this->chips[i_bit]; const MemoryChip *chip = this->chips[i_bit];
if (chip.exists()) { if (chip->exists()) {
chip.init(mask_bit, this->values_stored, size()); chip->init(mask_bit, this->values_stored, size());
} }
mask_bit <<= 1; mask_bit <<= 1;
} }
@ -129,3 +130,7 @@ void MemoryRow::write(const std::uint16_t address, const std::uint8_t data) {
throw std::logic_error("cannot write memory when power is off"); 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[socket]->id();
}

View File

@ -15,7 +15,7 @@ class MemoryRow {
bool power = false; bool power = false;
/* 8 sockets for memory chips (empty socket represented by MemoryChipEmptySocket) */ /* 8 sockets for memory chips (empty socket represented by MemoryChipEmptySocket) */
std::array<MemoryChip,8> chips = {{MemoryChipEmptySocket(),MemoryChipEmptySocket(),MemoryChipEmptySocket(),MemoryChipEmptySocket(),MemoryChipEmptySocket(),MemoryChipEmptySocket(),MemoryChipEmptySocket(),MemoryChipEmptySocket()}}; std::array<MemoryChip*,8> chips;
/* bit mask of empty chip sockets */ /* bit mask of empty chip sockets */
std::uint8_t missing_bits = 0xFFu; std::uint8_t missing_bits = 0xFFu;
@ -32,7 +32,7 @@ class MemoryRow {
MemoryRow(const char label); MemoryRow(const char label);
virtual ~MemoryRow(); virtual ~MemoryRow();
void insert_chip(MemoryChip chip, const std::uint_fast8_t socket); void insert_chip(MemoryChip *chip, const std::uint_fast8_t socket);
void remove_chip(const std::uint_fast8_t socket); void remove_chip(const std::uint_fast8_t socket);
void powerOff(); void powerOff();
void powerOn(); void powerOn();
@ -44,6 +44,8 @@ class MemoryRow {
void write(const std::uint16_t address, const std::uint8_t data); void write(const std::uint16_t address, const std::uint8_t data);
static std::uint8_t missing_memory_byte_value(); static std::uint8_t missing_memory_byte_value();
std::string chip_id(std::uint_fast8_t socket) const;
}; };
#endif // MEMORYROW_H #endif // MEMORYROW_H

View File

@ -11,7 +11,7 @@ void MemoryStrapping::strap_to(std::uint16_t addr_base, std::uint16_t addr_size)
} }
bool MemoryStrapping::contains(std::uint16_t address) const { bool MemoryStrapping::contains(std::uint16_t address) const {
return this->addr_base <= address && address < this->addr_base + std::min(this->row.size(), this->addr_size); return this->addr_base <= address && address < this->addr_base + size();
} }
std::uint8_t MemoryStrapping::read(const std::uint16_t address) const { std::uint8_t MemoryStrapping::read(const std::uint16_t address) const {
@ -21,3 +21,7 @@ std::uint8_t MemoryStrapping::read(const std::uint16_t address) const {
void MemoryStrapping::write(const std::uint16_t address, const std::uint8_t data) { void MemoryStrapping::write(const std::uint16_t address, const std::uint8_t data) {
this->row.write(address - this->addr_base, data); this->row.write(address - this->addr_base, data);
} }
std::uint16_t MemoryStrapping::size() const {
return std::min(this->row.size(), this->addr_size);
}

View File

@ -15,6 +15,7 @@ class MemoryStrapping {
bool contains(std::uint16_t address) const; bool contains(std::uint16_t address) const;
std::uint8_t read(const std::uint16_t address) const; std::uint8_t read(const std::uint16_t address) const;
void write(const std::uint16_t address, const std::uint8_t data); void write(const std::uint16_t address, const std::uint8_t data);
std::uint16_t size() const;
}; };
#endif #endif