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 \
|
filterluma.cpp lss.cpp main.cpp memory.cpp \
|
||||||
memorychip.cpp memoryrow.cpp memorystrapping.cpp memoryrandomaccess.cpp \
|
memorychip.cpp memoryrow.cpp memorystrapping.cpp memoryrandomaccess.cpp \
|
||||||
paddlebuttonstates.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 \
|
screenimage.cpp slots.cpp speakerclicker.cpp standardin.cpp \
|
||||||
standardinproducer.cpp standardout.cpp textcharacters.cpp \
|
standardinproducer.cpp standardout.cpp textcharacters.cpp \
|
||||||
timable.cpp video.cpp videoaddressing.cpp videomode.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 \
|
filterluma.h lss.h memory.h \
|
||||||
memorychip.h memoryrow.h memorystrapping.h memoryrandomaccess.h \
|
memorychip.h memoryrow.h memorystrapping.h memoryrandomaccess.h \
|
||||||
paddlebuttonstates.h paddles.h picturegenerator.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 \
|
standardin.h standardinproducer.h standardout.h \
|
||||||
textcharacterimages.h textcharacters.h timable.h util.h \
|
textcharacterimages.h textcharacters.h timable.h util.h \
|
||||||
videoaddressing.h video.h videomode.h videostaticgenerator.h wozfile.h \
|
videoaddressing.h video.h videomode.h videostaticgenerator.h wozfile.h \
|
||||||
|
|
|
@ -28,14 +28,11 @@
|
||||||
#include "slots.h"
|
#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):
|
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)
|
unsigned char AddressBus::read(const unsigned short address) {
|
||||||
{
|
if ((address >> 14) == 3) { // >= $C000
|
||||||
if ((address >> 14 == 3)) // >= $C000
|
if ((address >> 12) == 0xC) {
|
||||||
{
|
|
||||||
if ((address >> 12) == 0xC)
|
|
||||||
{
|
|
||||||
// 11007sss,xxxxxxxx
|
// 11007sss,xxxxxxxx
|
||||||
const bool seventh = address & 0x0800;
|
const bool seventh = address & 0x0800;
|
||||||
const int slot = (address >> 8) & 7;
|
const int slot = (address >> 8) & 7;
|
||||||
if (seventh)
|
if (seventh) {
|
||||||
{
|
this->data = this->slts.readSeventhRom(address & 0x07FF, this->data);
|
||||||
this->data = this->slts.readSeventhRom(address & 0x07FF, this->data);
|
} else if (slot == 0) {
|
||||||
}
|
readSwitch(address & 0x00FF);
|
||||||
else if (slot == 0)
|
} else {
|
||||||
{
|
this->data = this->slts.readRom(slot, address & 0x00FF, this->data);
|
||||||
this->data = readSwitch(address & 0x00FF);
|
}
|
||||||
}
|
} else {
|
||||||
else
|
this->data = this->slts.ioBankRom(address - 0xD000, this->data, false);
|
||||||
{
|
if (!this->slts.inhibitMotherboardRom()) {
|
||||||
this->data = this->slts.readRom(slot,address & 0x00FF, this->data);
|
this->data = this->rom.read(address - 0xD000, this->data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
} else { // < $C000
|
||||||
{
|
this->data = this->ram.read(address, this->data);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->data;
|
return this->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressBus::write(const unsigned short address, const unsigned char d)
|
void AddressBus::write(const unsigned short address, const unsigned char d) {
|
||||||
{
|
this->data = d;
|
||||||
this->data = d;
|
|
||||||
|
|
||||||
if ((address >> 14 == 3)) // >= $C000
|
if ((address >> 14 == 3)) { // >= $C000
|
||||||
{
|
if ((address >> 12) == 0xC) {
|
||||||
if ((address >> 12) == 0xC)
|
|
||||||
{
|
|
||||||
// 11007sss,xxxxxxxx
|
// 11007sss,xxxxxxxx
|
||||||
const bool seventh = address & 0x0800;
|
const bool seventh = address & 0x0800;
|
||||||
const int slot = (address >> 8) & 7;
|
const int slot = (address >> 8) & 7;
|
||||||
if (!seventh && slot == 0)
|
if (!seventh && slot == 0) {
|
||||||
{
|
writeSwitch(address & 0x00FF);
|
||||||
writeSwitch(address & 0x00FF);
|
}
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
else
|
this->data = this->slts.ioBankRom(address - 0xD000, this->data, true);
|
||||||
{
|
}
|
||||||
this->slts.ioBankRom(address - 0xD000,this->data,true);
|
}
|
||||||
}
|
else { // < $C000
|
||||||
}
|
this->ram.write(address, this->data);
|
||||||
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)
|
|
||||||
{
|
void AddressBus::setD7(const bool set) {
|
||||||
if (address < 0x80)
|
if (set) {
|
||||||
{
|
this->data |= 0x80;
|
||||||
const int islot = (address >> 4) & 0xF;
|
} else {
|
||||||
const int iswch = (address & 0xF);
|
this->data &= 0x7F;
|
||||||
if (islot == 0x0)
|
}
|
||||||
{
|
}
|
||||||
this->data = this->kbd.get();
|
|
||||||
}
|
void AddressBus::readSwitch(unsigned short address) {
|
||||||
else if (islot == 0x1)
|
if (address < 0x80) {
|
||||||
{
|
const int islot = (address >> 4) & 0xF;
|
||||||
this->kbd.clear();
|
const int iswch = (address & 0xF);
|
||||||
}
|
if (islot == 0x0) {
|
||||||
else if (islot == 0x2)
|
this->data = this->kbd.get();
|
||||||
{
|
} else if (islot == 0x1) {
|
||||||
|
this->kbd.clear();
|
||||||
|
} else if (islot == 0x2) {
|
||||||
this->cassetteOut.output();
|
this->cassetteOut.output();
|
||||||
}
|
} else if (islot == 0x3) {
|
||||||
else if (islot == 0x3)
|
|
||||||
{
|
|
||||||
if (this->revision == 0) {
|
if (this->revision == 0) {
|
||||||
this->cassetteOut.output();
|
this->cassetteOut.output();
|
||||||
}
|
}
|
||||||
this->speaker.click();
|
this->speaker.click();
|
||||||
}
|
} else if (islot == 0x4) {
|
||||||
else if (islot == 0x4)
|
|
||||||
{
|
|
||||||
// TODO ? utility strobe
|
// TODO ? utility strobe
|
||||||
}
|
} else if (islot == 0x5) {
|
||||||
else if (islot == 0x5)
|
if (iswch < 0x8) {
|
||||||
{
|
this->data = this->vid.io(address, this->data);
|
||||||
if (iswch < 0x8)
|
} else {
|
||||||
{
|
|
||||||
this->data = this->vid.io(address,this->data);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 11000000,01011aaf
|
// 11000000,01011aaf
|
||||||
// aa = annunciator, 0-3
|
// aa = annunciator, 0-3
|
||||||
// f == on/off
|
// f == on/off
|
||||||
const bool on = iswch & 1;
|
const bool on = iswch & 1;
|
||||||
const int ann = (iswch >> 1) & 3;
|
const int ann = (iswch >> 1) & 3;
|
||||||
this->gui.setAnnunciator(ann, on);
|
this->gui.setAnnunciator(ann, on);
|
||||||
}
|
}
|
||||||
}
|
} else if (islot == 0x6) {
|
||||||
else if (islot == 0x6)
|
int sw2 = iswch & 0x7;
|
||||||
{
|
if (sw2 == 0) {
|
||||||
int sw2 = iswch & 0x7;
|
|
||||||
if (sw2 == 0)
|
|
||||||
{
|
|
||||||
setD7(this->cassetteIn.input());
|
setD7(this->cassetteIn.input());
|
||||||
}
|
} else if (sw2 < 4) {
|
||||||
else if (sw2 < 4)
|
setD7(this->paddleButtonStates.isDown(sw2-1));
|
||||||
{
|
} else {
|
||||||
setD7(this->paddleButtonStates.isDown(sw2-1));
|
sw2 &= 3;
|
||||||
}
|
setD7(!this->paddles.isTimedOut(sw2));
|
||||||
else
|
}
|
||||||
{
|
} else if (islot == 0x7) {
|
||||||
sw2 &= 3;
|
this->paddles.startTimers();
|
||||||
setD7(!this->paddles.isTimedOut(sw2));
|
setD7(true);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else if (islot == 0x7)
|
// slot I/O switches
|
||||||
{
|
address &= 0x7F;
|
||||||
this->paddles.startTimers();
|
const int islot = (address >> 4) & 0xF;
|
||||||
setD7(true);
|
const int iswch = (address & 0xF);
|
||||||
}
|
this->data = this->slts.io(islot, iswch, this->data, false);
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressBus::setD7(const bool set)
|
void AddressBus::writeSwitch(unsigned short address){
|
||||||
{
|
if (address < 0x80) {
|
||||||
if (set)
|
const int islot = (address >> 4) & 0xF;
|
||||||
{
|
const int iswch = (address & 0xF);
|
||||||
this->data |= 0x80;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->data &= 0x7F;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddressBus::writeSwitch(unsigned short address)
|
if (islot == 0x1) {
|
||||||
{
|
this->kbd.clear();
|
||||||
if (address < 0x80)
|
} else if (islot == 0x5) {
|
||||||
{
|
if (iswch < 0x8) {
|
||||||
const int islot = (address >> 4) & 0xF;
|
this->vid.io(address, this->data);
|
||||||
const int iswch = (address & 0xF);
|
}
|
||||||
|
}
|
||||||
if (islot == 0x1)
|
// ignore all other switch writes
|
||||||
{
|
} else {
|
||||||
this->kbd.clear();
|
// slot I/O switches
|
||||||
}
|
address &= 0x7F;
|
||||||
else if (islot == 0x5)
|
const int islot = (address >> 4) & 0xF;
|
||||||
{
|
const int iswch = (address & 0xF);
|
||||||
if (iswch < 0x8)
|
this->slts.io(islot, iswch, this->data, true);
|
||||||
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 {
|
class AddressBus {
|
||||||
private:
|
private:
|
||||||
ScreenImage& gui;
|
ScreenImage& gui;
|
||||||
int& revision;
|
const int& revision;
|
||||||
MemoryRandomAccess& ram;
|
MemoryRandomAccess& ram;
|
||||||
Memory& rom;
|
Memory& rom; // TODO fix ROM so it doesn't use deprecated Memory class
|
||||||
Keyboard& kbd;
|
Keyboard& kbd;
|
||||||
VideoMode& vid;
|
VideoMode& vid;
|
||||||
Paddles& paddles;
|
Paddles& paddles;
|
||||||
|
@ -47,21 +47,24 @@ class AddressBus {
|
||||||
|
|
||||||
unsigned char data; // this emulates the (floating) data bus
|
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(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();
|
~AddressBus();
|
||||||
|
|
||||||
unsigned char read(const unsigned short address);
|
unsigned char read(const unsigned short address);
|
||||||
void write(const unsigned short address, const unsigned char d);
|
void write(const unsigned short address, const unsigned char d);
|
||||||
unsigned char readSwitch(unsigned short address);
|
|
||||||
void setD7(const bool set);
|
static const int MOTHERBOARD_RAM_BAS = 0x00000;
|
||||||
void writeSwitch(unsigned short address);
|
static const int MOTHERBOARD_RAM_LIM = 0x0C000;
|
||||||
enum { MOTHERBOARD_RAM_BAS = 0x00000 } ;
|
static const int MOTHERBOARD_RAM_SIZ = MOTHERBOARD_RAM_LIM-MOTHERBOARD_RAM_BAS;
|
||||||
enum { MOTHERBOARD_RAM_LIM = 0x0C000 } ;
|
|
||||||
enum { MOTHERBOARD_RAM_SIZ = MOTHERBOARD_RAM_LIM-MOTHERBOARD_RAM_BAS };
|
static const int MOTHERBOARD_ROM_BAS = 0x0D000;
|
||||||
enum { MOTHERBOARD_ROM_BAS = 0x0D000 } ;
|
static const int MOTHERBOARD_ROM_LIM = 0x10000;
|
||||||
enum { MOTHERBOARD_ROM_LIM = 0x10000 } ;
|
static const int MOTHERBOARD_ROM_SIZ = MOTHERBOARD_ROM_LIM-MOTHERBOARD_ROM_BAS;
|
||||||
enum { MOTHERBOARD_ROM_SIZ = MOTHERBOARD_ROM_LIM-MOTHERBOARD_ROM_BAS } ;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#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)
|
unsigned char Card::readRom(const unsigned short address, const unsigned char data)
|
||||||
{
|
{
|
||||||
this->activeSeventhRom = true;
|
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)
|
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())
|
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;
|
this->ioStepped = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
this->motor.tick(); // only need to send tick when motor is powered on
|
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
|
// run two LSS cycles = 2MHz
|
||||||
|
|
||||||
|
@ -118,10 +116,10 @@ void DiskController::tick() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiskController::rotateCurrentDisk() {
|
void DiskController::rotateCurrentDisk() {
|
||||||
this->t += 1.0f;
|
this->t += 1.0;
|
||||||
if (this->currentDrive->optimal_timing()/4.0f <= this->t) { // 4us interval between bits
|
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->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)
|
if (this->inhibitBankRom)
|
||||||
{
|
{
|
||||||
*pb = this->bankRom.read(addr);
|
*pb = this->bankRom.read(addr, *pb);
|
||||||
this->inhibit = true;
|
this->inhibit = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ void FirmwareCard::ioBankRom(const unsigned short addr, unsigned char* const pb,
|
||||||
{
|
{
|
||||||
if (this->inhibitF8Rom)
|
if (this->inhibitF8Rom)
|
||||||
{
|
{
|
||||||
*pb = this->bankRom.read(addr);
|
*pb = this->bankRom.read(addr, *pb);
|
||||||
this->inhibit = true;
|
this->inhibit = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,11 +73,11 @@ void LanguageCard::ioBankRom(const unsigned short addr, unsigned char* const pb,
|
||||||
{
|
{
|
||||||
if (addr < 0x1000)
|
if (addr < 0x1000)
|
||||||
{
|
{
|
||||||
*pb = this->ramBank[this->bank]->read(addr);
|
*pb = this->ramBank[this->bank]->read(addr, *pb);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*pb = this->ramTop.read(addr-0x1000);
|
*pb = this->ramTop.read(addr-0x1000, *pb);
|
||||||
}
|
}
|
||||||
this->inhibit = true;
|
this->inhibit = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,29 +22,6 @@
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstddef>
|
#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) {
|
missing_bits(0u) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Memory::clear() {
|
void Memory::clear() {
|
||||||
std::fill(this->bytes.begin(), this->bytes.end(), this->clear_value);
|
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) {
|
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));
|
in.read(reinterpret_cast<char*>(&this->bytes[base]), static_cast<ptrdiff_t>(this->bytes.size()-base));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Memory::powerOn() {
|
void Memory::powerOn() {
|
||||||
init();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Memory::powerOff() {
|
void Memory::powerOff() {
|
||||||
|
@ -83,12 +51,8 @@ size_t Memory::size() const {
|
||||||
return this->bytes.size();
|
return this->bytes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint8_t Memory::read(const std::uint16_t address) const {
|
std::uint8_t Memory::read(const std::uint16_t address, const std::uint8_t data) const {
|
||||||
std::uint8_t v = this->bytes[address];
|
return (this->bytes[address] & ~this->missing_bits) | (data & this->missing_bits);
|
||||||
if (this->missing_bits) {
|
|
||||||
v = randomize_missing_bits(v, this->missing_bits);
|
|
||||||
}
|
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Memory::write(const std::uint16_t address, const std::uint8_t data) {
|
void Memory::write(const std::uint16_t address, const std::uint8_t data) {
|
||||||
|
|
|
@ -30,10 +30,10 @@ class Memory {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Memory(const size_t n);
|
Memory(const size_t n);
|
||||||
virtual ~Memory() { }
|
virtual ~Memory() = default;
|
||||||
|
|
||||||
size_t size() const;
|
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 write(const std::uint16_t address, const std::uint8_t data);
|
||||||
void powerOn();
|
void powerOn();
|
||||||
void powerOff();
|
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 */
|
/* 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;
|
std::uint16_t ax = address & ~0x2000u;
|
||||||
if (this->strapE.contains(ax)) {
|
if (this->strapE.contains(ax)) {
|
||||||
return this->strapE.read(ax);
|
return this->strapE.read(ax, data);
|
||||||
}
|
}
|
||||||
if (this->strapD.contains(ax)) {
|
if (this->strapD.contains(ax)) {
|
||||||
return this->strapD.read(ax);
|
return this->strapD.read(ax, data);
|
||||||
}
|
}
|
||||||
if (this->strapC.contains(ax)) {
|
if (this->strapC.contains(ax)) {
|
||||||
return this->strapC.read(ax);
|
return this->strapC.read(ax, data);
|
||||||
}
|
}
|
||||||
ax = address | 0x2000u;
|
ax = address | 0x2000u;
|
||||||
if (this->strapE.contains(ax)) {
|
if (this->strapE.contains(ax)) {
|
||||||
return this->strapE.read(ax);
|
return this->strapE.read(ax, data);
|
||||||
}
|
}
|
||||||
if (this->strapD.contains(ax)) {
|
if (this->strapD.contains(ax)) {
|
||||||
return this->strapD.read(ax);
|
return this->strapD.read(ax, data);
|
||||||
}
|
}
|
||||||
if (this->strapC.contains(ax)) {
|
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)) {
|
if (this->revision == 0 && k20or24() && ((address & 0xC000u) == 0x4000u)) {
|
||||||
return buggyRamRead(address);
|
return buggyRamRead(address, data);
|
||||||
}
|
}
|
||||||
if (this->strapE.contains(address)) {
|
if (this->strapE.contains(address)) {
|
||||||
return this->strapE.read(address);
|
return this->strapE.read(address, data);
|
||||||
}
|
}
|
||||||
if (this->strapD.contains(address)) {
|
if (this->strapD.contains(address)) {
|
||||||
return this->strapD.read(address);
|
return this->strapD.read(address, data);
|
||||||
}
|
}
|
||||||
if (this->strapC.contains(address)) {
|
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) {
|
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);
|
MemoryRow &row_of(const std::string &row);
|
||||||
MemoryStrapping &strapping_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);
|
void buggyRamWrite(std::uint16_t address, const std::uint8_t data);
|
||||||
bool k20or24() const;
|
bool k20or24() const;
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ public:
|
||||||
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);
|
||||||
|
|
||||||
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 write(std::uint16_t address, const std::uint8_t data);
|
||||||
void powerOn();
|
void powerOn();
|
||||||
void powerOff();
|
void powerOff();
|
||||||
|
|
|
@ -2,27 +2,6 @@
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <cstdlib>
|
#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):
|
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());
|
return static_cast<std::uint16_t>(this->values_stored.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint8_t MemoryRow::missing_memory_byte_value() {
|
std::uint8_t MemoryRow::read(const std::uint16_t address_offset, std::uint8_t data) const {
|
||||||
return randomize_missing_bits(0xFFu, 0xFFu);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint8_t MemoryRow::read(const std::uint16_t address_offset) const {
|
|
||||||
if (this->power) {
|
if (this->power) {
|
||||||
std::uint8_t v;
|
|
||||||
if (address_offset < this->values_stored.size()) {
|
if (address_offset < this->values_stored.size()) {
|
||||||
v = this->values_stored[address_offset];
|
/* We need to float the data bits corresponding to missing chips:
|
||||||
if (this->missing_bits) {
|
* 01010101 data bits (previously places on data bus from elsewhere)
|
||||||
v = randomize_missing_bits(v, this->missing_bits);
|
* 00110011 mask of memory chips (1=missing, 0=present)
|
||||||
}
|
* 00001111 bits stored in chips
|
||||||
} else {
|
* --------
|
||||||
v = missing_memory_byte_value();
|
* 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 {
|
} else {
|
||||||
throw std::logic_error("cannot read memory when power is off");
|
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) {
|
void MemoryRow::write(const std::uint16_t address, const std::uint8_t data) {
|
||||||
if (this->power) {
|
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;
|
this->values_stored[address] = data;
|
||||||
} else {
|
} else {
|
||||||
throw std::logic_error("cannot write memory when power is off");
|
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) */
|
/* 4K or 16K, size of each chip (or minimum in corner case of mixed sizes) */
|
||||||
std::uint16_t size() const;
|
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);
|
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;
|
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();
|
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 std::uint8_t data) const {
|
||||||
return this->row.read(address - this->addr_base);
|
return this->row.read(address - this->addr_base, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ class MemoryStrapping {
|
||||||
MemoryStrapping(MemoryRow &row);
|
MemoryStrapping(MemoryRow &row);
|
||||||
void strap_to(std::uint16_t addr_base, std::uint16_t addr_size);
|
void strap_to(std::uint16_t addr_base, std::uint16_t addr_size);
|
||||||
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 std::uint8_t data) 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;
|
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