incorporate floating data bus in RAM (instead of just ROM) reads; some more refactoring and cleanup
This commit is contained in:
parent
5cdb608fe7
commit
17a714e550
|
@ -21,7 +21,7 @@ keyboard.cpp keyboardbuffermode.cpp languagecard.cpp filterchroma.cpp \
|
|||
filterluma.cpp lss.cpp main.cpp memory.cpp \
|
||||
memorychip.cpp memoryrow.cpp memorystrapping.cpp memoryrandomaccess.cpp \
|
||||
paddlebuttonstates.cpp \
|
||||
paddles.cpp picturegenerator.cpp powerupreset.cpp raminitializer.cpp \
|
||||
paddles.cpp picturegenerator.cpp powerupreset.cpp \
|
||||
screenimage.cpp slots.cpp speakerclicker.cpp standardin.cpp \
|
||||
standardinproducer.cpp standardout.cpp textcharacters.cpp \
|
||||
timable.cpp video.cpp videoaddressing.cpp videomode.cpp \
|
||||
|
@ -40,7 +40,7 @@ hypermode.h keyboardbuffermode.h keyboard.h languagecard.h filterchroma.h \
|
|||
filterluma.h lss.h memory.h \
|
||||
memorychip.h memoryrow.h memorystrapping.h memoryrandomaccess.h \
|
||||
paddlebuttonstates.h paddles.h picturegenerator.h \
|
||||
powerupreset.h raminitializer.h screenimage.h slots.h speakerclicker.h \
|
||||
powerupreset.h screenimage.h slots.h speakerclicker.h \
|
||||
standardin.h standardinproducer.h standardout.h \
|
||||
textcharacterimages.h textcharacters.h timable.h util.h \
|
||||
videoaddressing.h video.h videomode.h videostaticgenerator.h wozfile.h \
|
||||
|
|
|
@ -28,14 +28,11 @@
|
|||
#include "slots.h"
|
||||
|
||||
AddressBus::AddressBus(ScreenImage& gui, int& revision, MemoryRandomAccess& ram, Memory& rom, Keyboard& kbd, VideoMode& vid, Paddles& paddles, PaddleButtonStates& paddleButtonStates, SpeakerClicker& speaker, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Slots& slts):
|
||||
gui(gui), revision(revision), ram(ram), rom(rom), kbd(kbd), vid(vid), paddles(paddles), paddleButtonStates(paddleButtonStates), speaker(speaker), cassetteIn(cassetteIn), cassetteOut(cassetteOut), slts(slts)
|
||||
{
|
||||
gui(gui), revision(revision), ram(ram), rom(rom), kbd(kbd), vid(vid), paddles(paddles), paddleButtonStates(paddleButtonStates), speaker(speaker), cassetteIn(cassetteIn), cassetteOut(cassetteOut), slts(slts) {
|
||||
}
|
||||
|
||||
|
||||
AddressBus::~AddressBus()
|
||||
{
|
||||
}
|
||||
AddressBus::~AddressBus() = default;
|
||||
|
||||
|
||||
|
||||
|
@ -45,70 +42,51 @@ AddressBus::~AddressBus()
|
|||
|
||||
|
||||
|
||||
unsigned char AddressBus::read(const unsigned short address)
|
||||
{
|
||||
if ((address >> 14 == 3)) // >= $C000
|
||||
{
|
||||
if ((address >> 12) == 0xC)
|
||||
{
|
||||
unsigned char AddressBus::read(const unsigned short address) {
|
||||
if ((address >> 14) == 3) { // >= $C000
|
||||
if ((address >> 12) == 0xC) {
|
||||
// 11007sss,xxxxxxxx
|
||||
const bool seventh = address & 0x0800;
|
||||
const int slot = (address >> 8) & 7;
|
||||
if (seventh)
|
||||
{
|
||||
this->data = this->slts.readSeventhRom(address & 0x07FF, this->data);
|
||||
}
|
||||
else if (slot == 0)
|
||||
{
|
||||
this->data = readSwitch(address & 0x00FF);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->data = this->slts.readRom(slot,address & 0x00FF, this->data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->data = this->slts.ioBankRom(address - 0xD000,this->data,false);
|
||||
if (!this->slts.inhibitMotherboardRom())
|
||||
{
|
||||
this->data = this->rom.read(address - 0xD000);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // < $C000
|
||||
{
|
||||
this->data = this->ram.read(address);
|
||||
}
|
||||
const bool seventh = address & 0x0800;
|
||||
const int slot = (address >> 8) & 7;
|
||||
if (seventh) {
|
||||
this->data = this->slts.readSeventhRom(address & 0x07FF, this->data);
|
||||
} else if (slot == 0) {
|
||||
readSwitch(address & 0x00FF);
|
||||
} else {
|
||||
this->data = this->slts.readRom(slot, address & 0x00FF, this->data);
|
||||
}
|
||||
} else {
|
||||
this->data = this->slts.ioBankRom(address - 0xD000, this->data, false);
|
||||
if (!this->slts.inhibitMotherboardRom()) {
|
||||
this->data = this->rom.read(address - 0xD000, this->data);
|
||||
}
|
||||
}
|
||||
} else { // < $C000
|
||||
this->data = this->ram.read(address, this->data);
|
||||
}
|
||||
|
||||
return this->data;
|
||||
return this->data;
|
||||
}
|
||||
|
||||
void AddressBus::write(const unsigned short address, const unsigned char d)
|
||||
{
|
||||
this->data = d;
|
||||
void AddressBus::write(const unsigned short address, const unsigned char d) {
|
||||
this->data = d;
|
||||
|
||||
if ((address >> 14 == 3)) // >= $C000
|
||||
{
|
||||
if ((address >> 12) == 0xC)
|
||||
{
|
||||
if ((address >> 14 == 3)) { // >= $C000
|
||||
if ((address >> 12) == 0xC) {
|
||||
// 11007sss,xxxxxxxx
|
||||
const bool seventh = address & 0x0800;
|
||||
const int slot = (address >> 8) & 7;
|
||||
if (!seventh && slot == 0)
|
||||
{
|
||||
writeSwitch(address & 0x00FF);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->slts.ioBankRom(address - 0xD000,this->data,true);
|
||||
}
|
||||
}
|
||||
else // < $C000
|
||||
{
|
||||
this->ram.write(address,this->data);
|
||||
}
|
||||
const bool seventh = address & 0x0800;
|
||||
const int slot = (address >> 8) & 7;
|
||||
if (!seventh && slot == 0) {
|
||||
writeSwitch(address & 0x00FF);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->data = this->slts.ioBankRom(address - 0xD000, this->data, true);
|
||||
}
|
||||
}
|
||||
else { // < $C000
|
||||
this->ram.write(address, this->data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -118,122 +96,84 @@ void AddressBus::write(const unsigned short address, const unsigned char d)
|
|||
|
||||
|
||||
|
||||
unsigned char AddressBus::readSwitch(unsigned short address)
|
||||
{
|
||||
if (address < 0x80)
|
||||
{
|
||||
const int islot = (address >> 4) & 0xF;
|
||||
const int iswch = (address & 0xF);
|
||||
if (islot == 0x0)
|
||||
{
|
||||
this->data = this->kbd.get();
|
||||
}
|
||||
else if (islot == 0x1)
|
||||
{
|
||||
this->kbd.clear();
|
||||
}
|
||||
else if (islot == 0x2)
|
||||
{
|
||||
|
||||
void AddressBus::setD7(const bool set) {
|
||||
if (set) {
|
||||
this->data |= 0x80;
|
||||
} else {
|
||||
this->data &= 0x7F;
|
||||
}
|
||||
}
|
||||
|
||||
void AddressBus::readSwitch(unsigned short address) {
|
||||
if (address < 0x80) {
|
||||
const int islot = (address >> 4) & 0xF;
|
||||
const int iswch = (address & 0xF);
|
||||
if (islot == 0x0) {
|
||||
this->data = this->kbd.get();
|
||||
} else if (islot == 0x1) {
|
||||
this->kbd.clear();
|
||||
} else if (islot == 0x2) {
|
||||
this->cassetteOut.output();
|
||||
}
|
||||
else if (islot == 0x3)
|
||||
{
|
||||
} else if (islot == 0x3) {
|
||||
if (this->revision == 0) {
|
||||
this->cassetteOut.output();
|
||||
}
|
||||
this->speaker.click();
|
||||
}
|
||||
else if (islot == 0x4)
|
||||
{
|
||||
this->speaker.click();
|
||||
} else if (islot == 0x4) {
|
||||
// TODO ? utility strobe
|
||||
}
|
||||
else if (islot == 0x5)
|
||||
{
|
||||
if (iswch < 0x8)
|
||||
{
|
||||
this->data = this->vid.io(address,this->data);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else if (islot == 0x5) {
|
||||
if (iswch < 0x8) {
|
||||
this->data = this->vid.io(address, this->data);
|
||||
} else {
|
||||
// 11000000,01011aaf
|
||||
// aa = annunciator, 0-3
|
||||
// f == on/off
|
||||
const bool on = iswch & 1;
|
||||
const int ann = (iswch >> 1) & 3;
|
||||
this->gui.setAnnunciator(ann, on);
|
||||
}
|
||||
}
|
||||
else if (islot == 0x6)
|
||||
{
|
||||
int sw2 = iswch & 0x7;
|
||||
if (sw2 == 0)
|
||||
{
|
||||
}
|
||||
} else if (islot == 0x6) {
|
||||
int sw2 = iswch & 0x7;
|
||||
if (sw2 == 0) {
|
||||
setD7(this->cassetteIn.input());
|
||||
}
|
||||
else if (sw2 < 4)
|
||||
{
|
||||
setD7(this->paddleButtonStates.isDown(sw2-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
sw2 &= 3;
|
||||
setD7(!this->paddles.isTimedOut(sw2));
|
||||
}
|
||||
}
|
||||
else if (islot == 0x7)
|
||||
{
|
||||
this->paddles.startTimers();
|
||||
setD7(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// slot I/O switches
|
||||
address &= 0x7F;
|
||||
const int islot = (address >> 4) & 0xF;
|
||||
const int iswch = (address & 0xF);
|
||||
this->data = this->slts.io(islot,iswch,this->data,false);
|
||||
}
|
||||
|
||||
return this->data;
|
||||
} else if (sw2 < 4) {
|
||||
setD7(this->paddleButtonStates.isDown(sw2-1));
|
||||
} else {
|
||||
sw2 &= 3;
|
||||
setD7(!this->paddles.isTimedOut(sw2));
|
||||
}
|
||||
} else if (islot == 0x7) {
|
||||
this->paddles.startTimers();
|
||||
setD7(true);
|
||||
}
|
||||
} else {
|
||||
// slot I/O switches
|
||||
address &= 0x7F;
|
||||
const int islot = (address >> 4) & 0xF;
|
||||
const int iswch = (address & 0xF);
|
||||
this->data = this->slts.io(islot, iswch, this->data, false);
|
||||
}
|
||||
}
|
||||
|
||||
void AddressBus::setD7(const bool set)
|
||||
{
|
||||
if (set)
|
||||
{
|
||||
this->data |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->data &= 0x7F;
|
||||
}
|
||||
}
|
||||
void AddressBus::writeSwitch(unsigned short address){
|
||||
if (address < 0x80) {
|
||||
const int islot = (address >> 4) & 0xF;
|
||||
const int iswch = (address & 0xF);
|
||||
|
||||
void AddressBus::writeSwitch(unsigned short address)
|
||||
{
|
||||
if (address < 0x80)
|
||||
{
|
||||
const int islot = (address >> 4) & 0xF;
|
||||
const int iswch = (address & 0xF);
|
||||
|
||||
if (islot == 0x1)
|
||||
{
|
||||
this->kbd.clear();
|
||||
}
|
||||
else if (islot == 0x5)
|
||||
{
|
||||
if (iswch < 0x8)
|
||||
this->vid.io(address,this->data);
|
||||
}
|
||||
// ignore all other switch writes
|
||||
}
|
||||
else
|
||||
{
|
||||
// slot I/O switches
|
||||
address &= 0x7F;
|
||||
const int islot = (address >> 4) & 0xF;
|
||||
const int iswch = (address & 0xF);
|
||||
this->slts.io(islot,iswch,this->data,true);
|
||||
}
|
||||
if (islot == 0x1) {
|
||||
this->kbd.clear();
|
||||
} else if (islot == 0x5) {
|
||||
if (iswch < 0x8) {
|
||||
this->vid.io(address, this->data);
|
||||
}
|
||||
}
|
||||
// ignore all other switch writes
|
||||
} else {
|
||||
// slot I/O switches
|
||||
address &= 0x7F;
|
||||
const int islot = (address >> 4) & 0xF;
|
||||
const int iswch = (address & 0xF);
|
||||
this->slts.io(islot, iswch, this->data, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,9 +33,9 @@ class Slots;
|
|||
class AddressBus {
|
||||
private:
|
||||
ScreenImage& gui;
|
||||
int& revision;
|
||||
const int& revision;
|
||||
MemoryRandomAccess& ram;
|
||||
Memory& rom;
|
||||
Memory& rom; // TODO fix ROM so it doesn't use deprecated Memory class
|
||||
Keyboard& kbd;
|
||||
VideoMode& vid;
|
||||
Paddles& paddles;
|
||||
|
@ -47,21 +47,24 @@ class AddressBus {
|
|||
|
||||
unsigned char data; // this emulates the (floating) data bus
|
||||
|
||||
public:
|
||||
void setD7(const bool set);
|
||||
void readSwitch(unsigned short address);
|
||||
void writeSwitch(unsigned short address);
|
||||
|
||||
public:
|
||||
AddressBus(ScreenImage& gui, int& revision, MemoryRandomAccess& ram, Memory& rom, Keyboard& kbd, VideoMode& vid, Paddles& paddles, PaddleButtonStates& paddleButtonStates, SpeakerClicker& speaker, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Slots& slts);
|
||||
~AddressBus();
|
||||
|
||||
unsigned char read(const unsigned short address);
|
||||
void write(const unsigned short address, const unsigned char d);
|
||||
unsigned char readSwitch(unsigned short address);
|
||||
void setD7(const bool set);
|
||||
void writeSwitch(unsigned short address);
|
||||
enum { MOTHERBOARD_RAM_BAS = 0x00000 } ;
|
||||
enum { MOTHERBOARD_RAM_LIM = 0x0C000 } ;
|
||||
enum { MOTHERBOARD_RAM_SIZ = MOTHERBOARD_RAM_LIM-MOTHERBOARD_RAM_BAS };
|
||||
enum { MOTHERBOARD_ROM_BAS = 0x0D000 } ;
|
||||
enum { MOTHERBOARD_ROM_LIM = 0x10000 } ;
|
||||
enum { MOTHERBOARD_ROM_SIZ = MOTHERBOARD_ROM_LIM-MOTHERBOARD_ROM_BAS } ;
|
||||
|
||||
static const int MOTHERBOARD_RAM_BAS = 0x00000;
|
||||
static const int MOTHERBOARD_RAM_LIM = 0x0C000;
|
||||
static const int MOTHERBOARD_RAM_SIZ = MOTHERBOARD_RAM_LIM-MOTHERBOARD_RAM_BAS;
|
||||
|
||||
static const int MOTHERBOARD_ROM_BAS = 0x0D000;
|
||||
static const int MOTHERBOARD_ROM_LIM = 0x10000;
|
||||
static const int MOTHERBOARD_ROM_SIZ = MOTHERBOARD_ROM_LIM-MOTHERBOARD_ROM_BAS;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -49,7 +49,7 @@ unsigned char Card::io(const unsigned short /*address*/, const unsigned char dat
|
|||
unsigned char Card::readRom(const unsigned short address, const unsigned char data)
|
||||
{
|
||||
this->activeSeventhRom = true;
|
||||
return this->rom.read(address);
|
||||
return this->rom.read(address, data);
|
||||
}
|
||||
|
||||
void Card::readSeventhRom(const unsigned short address, unsigned char* const pb)
|
||||
|
@ -60,7 +60,7 @@ void Card::readSeventhRom(const unsigned short address, unsigned char* const pb)
|
|||
}
|
||||
else if (this->activeSeventhRom && hasSeventhRom())
|
||||
{
|
||||
*pb = this->seventhRom.read(address);
|
||||
*pb = this->seventhRom.read(address, *pb);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -96,14 +96,12 @@ void DiskController::tick() {
|
|||
this->ioStepped = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
this->motor.tick(); // only need to send tick when motor is powered on
|
||||
|
||||
/*
|
||||
* TODO
|
||||
* Every CPU clock, add 8 to your bit timing clock. If your bit timing clock is >= optimal bit timing,
|
||||
* then inject the next bit and subtract the optimal bit timing from your bit timing clock.
|
||||
* That will give you 125ns resolution on your bits being fed to the sequencer.
|
||||
*/
|
||||
|
||||
|
||||
// run two LSS cycles = 2MHz
|
||||
|
||||
|
@ -118,10 +116,10 @@ void DiskController::tick() {
|
|||
}
|
||||
|
||||
void DiskController::rotateCurrentDisk() {
|
||||
this->t += 1.0f;
|
||||
if (this->currentDrive->optimal_timing()/4.0f <= this->t) { // 4us interval between bits
|
||||
this->t += 1.0;
|
||||
if (this->currentDrive->optimal_timing()/4.0 <= this->t) { // wait for optimal interval between bits
|
||||
this->currentDrive->rotateDiskOneBit(); // (will also generate a read-pulse when it reads a 1-bit)
|
||||
this->t -= this->currentDrive->optimal_timing()/4.0f;
|
||||
this->t -= this->currentDrive->optimal_timing()/4.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ void FirmwareCard::ioBankRom(const unsigned short addr, unsigned char* const pb,
|
|||
{
|
||||
if (this->inhibitBankRom)
|
||||
{
|
||||
*pb = this->bankRom.read(addr);
|
||||
*pb = this->bankRom.read(addr, *pb);
|
||||
this->inhibit = true;
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ void FirmwareCard::ioBankRom(const unsigned short addr, unsigned char* const pb,
|
|||
{
|
||||
if (this->inhibitF8Rom)
|
||||
{
|
||||
*pb = this->bankRom.read(addr);
|
||||
*pb = this->bankRom.read(addr, *pb);
|
||||
this->inhibit = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,11 +73,11 @@ void LanguageCard::ioBankRom(const unsigned short addr, unsigned char* const pb,
|
|||
{
|
||||
if (addr < 0x1000)
|
||||
{
|
||||
*pb = this->ramBank[this->bank]->read(addr);
|
||||
*pb = this->ramBank[this->bank]->read(addr, *pb);
|
||||
}
|
||||
else
|
||||
{
|
||||
*pb = this->ramTop.read(addr-0x1000);
|
||||
*pb = this->ramTop.read(addr-0x1000, *pb);
|
||||
}
|
||||
this->inhibit = true;
|
||||
}
|
||||
|
|
|
@ -22,29 +22,6 @@
|
|||
#include <istream>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include "raminitializer.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* If any RAM IC sockets are empty, set the corresponding bits to 1 most of the time.
|
||||
* But set to 0 instead, with probability 1 in 137 (a rough estimate obtained empirically)
|
||||
*/
|
||||
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 < 1.0/137.0) {
|
||||
v &= ~bit;
|
||||
} else {
|
||||
v |= bit;
|
||||
}
|
||||
}
|
||||
bit <<= 1;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -54,25 +31,16 @@ Memory::Memory(const size_t n):
|
|||
missing_bits(0u) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Memory::clear() {
|
||||
std::fill(this->bytes.begin(), this->bytes.end(), this->clear_value);
|
||||
}
|
||||
|
||||
void Memory::init() {
|
||||
RAMInitializer initRam(*this);
|
||||
initRam.init();
|
||||
}
|
||||
|
||||
void Memory::load(const std::uint16_t base, std::istream& in) {
|
||||
in.read(reinterpret_cast<char*>(&this->bytes[base]), static_cast<ptrdiff_t>(this->bytes.size()-base));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Memory::powerOn() {
|
||||
init();
|
||||
clear();
|
||||
}
|
||||
|
||||
void Memory::powerOff() {
|
||||
|
@ -83,12 +51,8 @@ size_t Memory::size() const {
|
|||
return this->bytes.size();
|
||||
}
|
||||
|
||||
std::uint8_t Memory::read(const std::uint16_t address) const {
|
||||
std::uint8_t v = this->bytes[address];
|
||||
if (this->missing_bits) {
|
||||
v = randomize_missing_bits(v, this->missing_bits);
|
||||
}
|
||||
return v;
|
||||
std::uint8_t Memory::read(const std::uint16_t address, const std::uint8_t data) const {
|
||||
return (this->bytes[address] & ~this->missing_bits) | (data & this->missing_bits);
|
||||
}
|
||||
|
||||
void Memory::write(const std::uint16_t address, const std::uint8_t data) {
|
||||
|
|
|
@ -30,10 +30,10 @@ class Memory {
|
|||
|
||||
public:
|
||||
Memory(const size_t n);
|
||||
virtual ~Memory() { }
|
||||
virtual ~Memory() = default;
|
||||
|
||||
size_t size() const;
|
||||
std::uint8_t read(const std::uint16_t address) const;
|
||||
std::uint8_t read(const std::uint16_t address, const std::uint8_t data) const;
|
||||
void write(const std::uint16_t address, const std::uint8_t data);
|
||||
void powerOn();
|
||||
void powerOff();
|
||||
|
|
|
@ -59,44 +59,44 @@ bool MemoryRandomAccess::k20or24() const {
|
|||
}
|
||||
|
||||
/* for 20K or 24K on rev. 0: pages 40-5F are dup w/ 60-7F */
|
||||
std::uint8_t MemoryRandomAccess::buggyRamRead(const std::uint16_t address) const {
|
||||
std::uint8_t MemoryRandomAccess::buggyRamRead(const std::uint16_t address, std::uint8_t data) const {
|
||||
std::uint16_t ax = address & ~0x2000u;
|
||||
if (this->strapE.contains(ax)) {
|
||||
return this->strapE.read(ax);
|
||||
return this->strapE.read(ax, data);
|
||||
}
|
||||
if (this->strapD.contains(ax)) {
|
||||
return this->strapD.read(ax);
|
||||
return this->strapD.read(ax, data);
|
||||
}
|
||||
if (this->strapC.contains(ax)) {
|
||||
return this->strapC.read(ax);
|
||||
return this->strapC.read(ax, data);
|
||||
}
|
||||
ax = address | 0x2000u;
|
||||
if (this->strapE.contains(ax)) {
|
||||
return this->strapE.read(ax);
|
||||
return this->strapE.read(ax, data);
|
||||
}
|
||||
if (this->strapD.contains(ax)) {
|
||||
return this->strapD.read(ax);
|
||||
return this->strapD.read(ax, data);
|
||||
}
|
||||
if (this->strapC.contains(ax)) {
|
||||
return this->strapC.read(ax);
|
||||
return this->strapC.read(ax, data);
|
||||
}
|
||||
return MemoryRow::missing_memory_byte_value();
|
||||
return data;
|
||||
}
|
||||
|
||||
std::uint8_t MemoryRandomAccess::read(const std::uint16_t address) const {
|
||||
std::uint8_t MemoryRandomAccess::read(const std::uint16_t address, std::uint8_t data) const {
|
||||
if (this->revision == 0 && k20or24() && ((address & 0xC000u) == 0x4000u)) {
|
||||
return buggyRamRead(address);
|
||||
return buggyRamRead(address, data);
|
||||
}
|
||||
if (this->strapE.contains(address)) {
|
||||
return this->strapE.read(address);
|
||||
return this->strapE.read(address, data);
|
||||
}
|
||||
if (this->strapD.contains(address)) {
|
||||
return this->strapD.read(address);
|
||||
return this->strapD.read(address, data);
|
||||
}
|
||||
if (this->strapC.contains(address)) {
|
||||
return this->strapC.read(address);
|
||||
return this->strapC.read(address, data);
|
||||
}
|
||||
return MemoryRow::missing_memory_byte_value();
|
||||
return data;
|
||||
}
|
||||
|
||||
void MemoryRandomAccess::buggyRamWrite(std::uint16_t address, const std::uint8_t data) {
|
||||
|
|
|
@ -18,7 +18,7 @@ class MemoryRandomAccess {
|
|||
|
||||
MemoryRow &row_of(const std::string &row);
|
||||
MemoryStrapping &strapping_of(const std::string &row);
|
||||
std::uint8_t buggyRamRead(std::uint16_t address) const;
|
||||
std::uint8_t buggyRamRead(std::uint16_t address, std::uint8_t data) const;
|
||||
void buggyRamWrite(std::uint16_t address, const std::uint8_t data);
|
||||
bool k20or24() const;
|
||||
|
||||
|
@ -31,7 +31,7 @@ public:
|
|||
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);
|
||||
|
||||
std::uint8_t read(std::uint16_t address) const;
|
||||
std::uint8_t read(std::uint16_t address, const std::uint8_t data) const;
|
||||
void write(std::uint16_t address, const std::uint8_t data);
|
||||
void powerOn();
|
||||
void powerOff();
|
||||
|
|
|
@ -2,27 +2,6 @@
|
|||
#include <exception>
|
||||
#include <cstdlib>
|
||||
|
||||
/*
|
||||
* 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 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.04) {
|
||||
v &= ~bit;
|
||||
} else {
|
||||
v |= bit;
|
||||
}
|
||||
}
|
||||
bit <<= 1;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
MemoryRow::MemoryRow(const char label):
|
||||
|
@ -102,22 +81,23 @@ std::uint16_t MemoryRow::size() const {
|
|||
return static_cast<std::uint16_t>(this->values_stored.size());
|
||||
}
|
||||
|
||||
std::uint8_t MemoryRow::missing_memory_byte_value() {
|
||||
return randomize_missing_bits(0xFFu, 0xFFu);
|
||||
}
|
||||
|
||||
std::uint8_t MemoryRow::read(const std::uint16_t address_offset) const {
|
||||
std::uint8_t MemoryRow::read(const std::uint16_t address_offset, std::uint8_t data) const {
|
||||
if (this->power) {
|
||||
std::uint8_t v;
|
||||
if (address_offset < this->values_stored.size()) {
|
||||
v = this->values_stored[address_offset];
|
||||
if (this->missing_bits) {
|
||||
v = randomize_missing_bits(v, this->missing_bits);
|
||||
}
|
||||
} else {
|
||||
v = missing_memory_byte_value();
|
||||
/* 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[address_offset] & ~this->missing_bits) | (data & this->missing_bits);
|
||||
}
|
||||
return v;
|
||||
return data;
|
||||
} else {
|
||||
throw std::logic_error("cannot read memory when power is off");
|
||||
}
|
||||
|
@ -125,6 +105,8 @@ std::uint8_t MemoryRow::read(const std::uint16_t address_offset) const {
|
|||
|
||||
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[address] = data;
|
||||
} else {
|
||||
throw std::logic_error("cannot write memory when power is off");
|
||||
|
|
|
@ -40,11 +40,9 @@ class MemoryRow {
|
|||
/* 4K or 16K, size of each chip (or minimum in corner case of mixed sizes) */
|
||||
std::uint16_t size() const;
|
||||
|
||||
std::uint8_t read(const std::uint16_t address) const;
|
||||
std::uint8_t read(const std::uint16_t address, const std::uint8_t data) const;
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ bool MemoryStrapping::contains(std::uint16_t address) const {
|
|||
return this->addr_base <= address && address < this->addr_base + size();
|
||||
}
|
||||
|
||||
std::uint8_t MemoryStrapping::read(const std::uint16_t address) const {
|
||||
return this->row.read(address - this->addr_base);
|
||||
std::uint8_t MemoryStrapping::read(const std::uint16_t address, const std::uint8_t data) const {
|
||||
return this->row.read(address - this->addr_base, data);
|
||||
}
|
||||
|
||||
void MemoryStrapping::write(const std::uint16_t address, const std::uint8_t data) {
|
||||
|
|
|
@ -13,7 +13,7 @@ class MemoryStrapping {
|
|||
MemoryStrapping(MemoryRow &row);
|
||||
void strap_to(std::uint16_t addr_base, std::uint16_t addr_size);
|
||||
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 std::uint8_t data) const;
|
||||
void write(const std::uint16_t address, const std::uint8_t data);
|
||||
std::uint16_t size() const;
|
||||
};
|
||||
|
|
|
@ -1,137 +0,0 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY, without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "raminitializer.h"
|
||||
#include "memory.h"
|
||||
#include <ctime>
|
||||
#include <cstdlib>
|
||||
|
||||
RAMInitializer::RAMInitializer(Memory& mem):
|
||||
ram(mem)
|
||||
{
|
||||
srand(time(0));
|
||||
}
|
||||
|
||||
void RAMInitializer::init()
|
||||
{
|
||||
this->ram.clear();
|
||||
|
||||
int b(0);
|
||||
// TODO make the types of RAM chips configurable
|
||||
putBytesUntilFull(b++,1);
|
||||
putBytesUntilFull(b++,2);
|
||||
putBytesUntilFull(b++,1);
|
||||
putBytesUntilFull(b++,2);
|
||||
putBytesUntilFull(b++,1);
|
||||
putBytesUntilFull(b++,2);
|
||||
putBytesUntilFull(b++,2);
|
||||
putBytesUntilFull(b++,1);
|
||||
}
|
||||
|
||||
|
||||
void RAMInitializer::putBytesUntilFull(int bit, int pat)
|
||||
{
|
||||
this->nextinit = 0;
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (pat==1)
|
||||
ramPattern1(bit);
|
||||
else
|
||||
ramPattern2(bit);
|
||||
}
|
||||
}
|
||||
catch (const done&)
|
||||
{
|
||||
// done filling this bit in RAM
|
||||
}
|
||||
}
|
||||
|
||||
void RAMInitializer::ramPattern1(const int bit)
|
||||
{
|
||||
for (int k = 0; k < 2; ++k)
|
||||
{
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 0x10; ++i)
|
||||
{
|
||||
putn(4,false,bit);
|
||||
putn(2,true,bit);
|
||||
putn(2,false,bit);
|
||||
}
|
||||
for (i = 0; i < 0x40; ++i)
|
||||
{
|
||||
putn(2,true,bit);
|
||||
putn(2,false,bit);
|
||||
}
|
||||
for (i = 0; i < 0x08; ++i)
|
||||
{
|
||||
putn(2,true,bit);
|
||||
putn(1,false,bit);
|
||||
putn(3,true,bit);
|
||||
putn(2,false,bit);
|
||||
putn(2,true,bit);
|
||||
putn(2,false,bit);
|
||||
putn(2,true,bit);
|
||||
putn(2,false,bit);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 0x400; ++i)
|
||||
{
|
||||
putn(2,true,bit);
|
||||
putn(2,false,bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RAMInitializer::ramPattern2(const int bit)
|
||||
{
|
||||
for (int i = 0; i < 0x40; ++i)
|
||||
{
|
||||
putn(0x80,true,bit);
|
||||
putn(0x80,false,bit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RAMInitializer::putn(const int c, bool on, const int bit)
|
||||
{
|
||||
if (((rand() >> 9) & 0x1F) == 5)
|
||||
on = !on;
|
||||
const unsigned char mask(1 << bit);
|
||||
for (int i = 0; i < c; ++i)
|
||||
{
|
||||
if (this->nextinit >= this->ram.size())
|
||||
{
|
||||
throw done();
|
||||
}
|
||||
unsigned char b = this->ram.read(this->nextinit);
|
||||
if (on)
|
||||
{
|
||||
b |= mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
b &= ~mask;
|
||||
}
|
||||
this->ram.write(this->nextinit,b);
|
||||
++this->nextinit;
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY, without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef RAMINITIALIZER_H
|
||||
#define RAMINITIALIZER_H
|
||||
|
||||
class Memory;
|
||||
|
||||
class RAMInitializer
|
||||
{
|
||||
private:
|
||||
class done {};
|
||||
|
||||
Memory& ram;
|
||||
unsigned short nextinit;
|
||||
|
||||
void putBytesUntilFull(int bit, int pat);
|
||||
void ramPattern1(const int bit);
|
||||
void ramPattern2(const int bit);
|
||||
void putn(const int c, bool on, const int bit);
|
||||
|
||||
public:
|
||||
RAMInitializer(Memory& mem);
|
||||
void init();
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue