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
motherboard ram E 16K
motherboard ram D 16K
motherboard ram C 16K
motherboard ram E MM5290 MM5290 MM5290 MK4116 MM5290 MM5290 MM5290 MK4116
motherboard ram D MM5290 MM5290 MK4116 MK4116 MM5290 MK4116 MM5290 MCM4116
motherboard ram C MK4116 MK4116 MM5290 MM5290 MM5290 MM5290 MM5290 MM5290
motherboard strap E 16K 8000
motherboard strap D 16K 4000
motherboard strap C 16K 0000

View File

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

View File

@ -42,18 +42,7 @@
#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) {
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") {
throw ConfigException("expected row to be C, D, or E");
}
std::string chip_model;
tok >> chip_model;
std::uint16_t siz = chip_size(chip_model);
for (std::uint_fast8_t bit = 0u; bit < 8u; ++bit) {
if (siz) {
ram.insert_chip(row, MemoryChip(siz,chip_model), bit);
} else {
ram.remove_chip(row, bit);
}
ram.insert_chip(row, MemoryChip::instance(chip_model), bit);
std::string chip_model_optional;
tok >> chip_model_optional;
if (chip_model_optional.length()) {
chip_model = chip_model_optional;
}
siz = chip_size(chip_model);
}
} else if (op == "strap") {
/* strap ROM K start-addr
* strap c 4K 0000
* strap d 4K 1000
* strap e 4K 2000
* strap e 4K 5000
* strap d 4K 4000
* strap c 16K 0000
*/
std::string row;
tok >> row;

View File

@ -73,6 +73,7 @@ void Emulator::powerOffComputer() {
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);
this->apple2.ram.dump_config();
}
void Emulator::init() {

View File

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

View File

@ -2,9 +2,39 @@
#include <stdexcept>
#include <algorithm>
#include <vector>
#include <cstdlib>
#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):
size_bits(size),
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() {
}
@ -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 {
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;
std::uint8_t c = 0u;
for (std::uint16_t i = 0u; i < std::min(size, this->size_bits); ++i) {
bitflag(on, mask, bytes[i]);
if (CYCLE <= ++c) {
c = 0u;
for (std::uint_fast16_t i = 0u; i < 16*K; ++i) {
double r = static_cast<double>(std::rand())/RAND_MAX;
bool is_rand = false;
if (r < GLITCH && c_chaos16 == 65u) {
--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;
c_cycle = 0u;
}
}
}
MemoryChipEmptySocket::MemoryChipEmptySocket():
MemoryChip(4*K,"[empty]") {
}
@ -72,3 +114,41 @@ MemoryChipEmptySocket::~MemoryChipEmptySocket() {
bool MemoryChipEmptySocket::exists() const {
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 {
private:
std::uint16_t size_bits;
std::string id_model;
const std::uint16_t size_bits;
const std::string id_model;
public:
static MemoryChip *instance(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();
std::uint16_t size() 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 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 {
@ -27,4 +28,25 @@ class MemoryChipEmptySocket : public MemoryChip {
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

View File

@ -1,5 +1,6 @@
#include "memoryrandomaccess.h"
#include <cstdint>
#include <cstdio>
#include <exception>
#define K 1024u
@ -40,7 +41,7 @@ MemoryStrapping &MemoryRandomAccess::strapping_of(const std::string &row) {
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);
}
@ -147,3 +148,35 @@ void MemoryRandomAccess::powerOff() {
this->rowD.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:
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 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.
* 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) {
std::uint8_t bit = 1u;
for (std::uint_fast8_t i = 0; i < 8; ++i) {
if (bits & bit) {
double r = static_cast<double>(std::rand())/RAND_MAX;
if (r < 0.11) {
if (r < 0.04) {
v &= ~bit;
} else {
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):
label(label) {
this->chips.fill(MemoryChip::instance("-"));
}
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) {
remove_chip(socket);
if (chip.exists()) {
if (chip->exists()) {
this->chips[socket] = chip;
this->missing_bits &= ~(1u << socket);
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) {
if (socket < 8u) {
this->chips[socket] = MemoryChipEmptySocket();
this->chips[socket] = MemoryChip::instance("-");
this->missing_bits |= (1u << socket);
this->values_stored.resize(calculate_size());
} else {
@ -63,9 +64,9 @@ 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[i_chip];
if (chip.exists()) {
const std::uint16_t s = chip.size();
const MemoryChip *chip = this->chips[i_chip];
if (chip->exists()) {
const std::uint16_t s = chip->size();
if (size_new == 0u || s < size_new) {
size_new = s;
}
@ -88,9 +89,9 @@ void MemoryRow::powerOn() {
std::uint8_t mask_bit = 1u;
for (std::uint_fast8_t i_bit = 0; i_bit < 8; ++i_bit) {
const MemoryChip &chip = this->chips[i_bit];
if (chip.exists()) {
chip.init(mask_bit, this->values_stored, size());
const MemoryChip *chip = this->chips[i_bit];
if (chip->exists()) {
chip->init(mask_bit, this->values_stored, size());
}
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");
}
}
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;
/* 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 */
std::uint8_t missing_bits = 0xFFu;
@ -32,7 +32,7 @@ class MemoryRow {
MemoryRow(const char label);
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 powerOff();
void powerOn();
@ -44,6 +44,8 @@ class MemoryRow {
void write(const std::uint16_t address, const std::uint8_t data);
static std::uint8_t missing_memory_byte_value();
std::string chip_id(std::uint_fast8_t socket) const;
};
#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 {
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 {
@ -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) {
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;
std::uint8_t read(const std::uint16_t address) const;
void write(const std::uint16_t address, const std::uint8_t data);
std::uint16_t size() const;
};
#endif