replace cpu with 6502 emulator

This commit is contained in:
Christopher Mosher 2013-12-19 19:44:06 -05:00
parent 97419f5538
commit a217a0a096
27 changed files with 4444 additions and 4 deletions

78
src/Circuit.cpp Normal file
View File

@ -0,0 +1,78 @@
/*
* File: Circuit.cpp
* Author: Christopher
*
* Created on December 12, 2013, 7:04 PM
*/
#include "Circuit.h"
#include "trans.h"
/*
* Adds segment extendFrom, and all segments electrically connected to it.
* This happens recursively, but we don't recurse past ground or voltage supply.
*/
void Circuit::extend(Segment* extendFrom) {
auto ret = this->segs.insert(extendFrom);
if (!ret.second) {
/* We've already processed this segment. */
return;
}
/* Don't recurse past ground or voltage supply. */
if (extendFrom->vss || extendFrom->vcc) {
return;
}
/*
* For every ON transistor this seg is connected to via a leg (source or
* drain), add the seg that's connected to the OTHER leg of the transistor.
* This is a RECURSIVE addition.
*
* Also note that, upon system startup, all transistors are initialized
* to OFF, so at the time of the very first recalcAll call, *no* other
* segments will be added here.
*/
for (auto t : extendFrom->c1c2s) {
if (t->on) {
if (t->c1 == extendFrom) {
extend(t->c2);
} else if (t->c2 == extendFrom) {
extend(t->c1);
}
}
}
}
/*
* Upon system startup, this will return the "pullup" value of
* each segment, except for VCC and VSS (which will of course be
* ON and OFF respectively).
*/
bool Circuit::getValue() {
/* If group contains ground, it's OFF, */
for (auto s : this->segs) {
if (s->vss) {
return false;
}
}
/*
* otherwise, if any segment in the group is not floating,
* return that segment as the value, otherwise if any floating
* segment is ON, then return ON as the value.
*/
for (auto s : this->segs) {
if (s->pull != Pull::FLOAT) {
return (s->pull == Pull::UP);
} else if (s->on) {
return true;
}
}
/*
* otherwise, if we get here, it means that all segments in the
* group are floating and OFF, so return OFF as the value.
*/
return false;
}

49
src/Circuit.h Normal file
View File

@ -0,0 +1,49 @@
/*
* File: Circuit.h
* Author: Christopher
*
* Created on December 12, 2013, 7:04 PM
*/
#ifndef CIRCUIT_H
#define CIRCUIT_H
#include "SegmentTypes.h"
#include <set>
/*
* Builds a circuit, given one segment in that circuit.
* Extends the given segment by traversing the ON
* transistors it is connected to, recursively, until
* hitting ground and voltage supply. Provides iterators
* for retrieving all the circuit's segments, and a method
* to get the ON value of the circuit.
*/
class Circuit final {
public:
Circuit(Segment* extendFrom) {
extend(extendFrom);
}
bool getValue();
SegmentSet::iterator begin() {
return this->segs.begin();
}
SegmentSet::iterator end() {
return this->segs.end();
}
private:
Circuit(const Circuit&) = delete;
Circuit& operator=(const Circuit&) = delete;
void extend(Segment* extendFrom);
SegmentSet segs;
};
#endif /* CIRCUIT_H */

83
src/Common.cpp Normal file
View File

@ -0,0 +1,83 @@
/*
* File: Common.cpp
* Author: Christopher
*
* Created on December 14, 2013, 8:47 PM
*/
#include "Common.h"
#include "TransNetwork.h"
#include "SegmentCache.h"
#include "trans.h"
Common::Common(const TransNetwork& tn) :
Common(
tn.segs.get("-vss"), tn.segs.get("+vcc"),
tn.segs.get("-clk0"),
tn.segs.get("-irq"), tn.segs.get("-res"), tn.segs.get("-nmi"),
tn.segs.get("+rdy"), tn.segs.get("+so"),
tn.segs.get("-db0"), tn.segs.get("-db1"), tn.segs.get("-db2"), tn.segs.get("-db3"), tn.segs.get("-db4"), tn.segs.get("-db5"), tn.segs.get("-db6"), tn.segs.get("-db7"),
tn.segs.get("-ab0"), tn.segs.get("-ab1"), tn.segs.get("-ab2"), tn.segs.get("-ab3"), tn.segs.get("-ab4"), tn.segs.get("-ab5"), tn.segs.get("-ab6"), tn.segs.get("-ab7"),
tn.segs.get("-ab8"), tn.segs.get("-ab9"), tn.segs.get("-ab10"), tn.segs.get("-ab11"), tn.segs.get("-ab12"), tn.segs.get("-ab13"), tn.segs.get("-ab14"), tn.segs.get("-ab15"),
tn.segs.get("-rw"), tn.segs.get("-sync"),
tn.segs.get("-clk1out"), tn.segs.get("-clk2out"),
tn.segs.get("-a0"), tn.segs.get("-a1"), tn.segs.get("-a2"), tn.segs.get("-a3"), tn.segs.get("-a4"), tn.segs.get("-a5"), tn.segs.get("-a6"), tn.segs.get("-a7"),
tn.segs.get("-x0"), tn.segs.get("-x1"), tn.segs.get("-x2"), tn.segs.get("-x3"), tn.segs.get("-x4"), tn.segs.get("-x5"), tn.segs.get("-x6"), tn.segs.get("-x7"),
tn.segs.get("-y0"), tn.segs.get("-y1"), tn.segs.get("-y2"), tn.segs.get("-y3"), tn.segs.get("-y4"), tn.segs.get("-y5"), tn.segs.get("-y6"), tn.segs.get("-y7"),
tn.segs.get("-pcl0"), tn.segs.get("-pcl1"), tn.segs.get("-pcl2"), tn.segs.get("-pcl3"), tn.segs.get("-pcl4"), tn.segs.get("-pcl5"), tn.segs.get("-pcl6"), tn.segs.get("-pcl7"),
tn.segs.get("-pch0"), tn.segs.get("-pch1"), tn.segs.get("-pch2"), tn.segs.get("-pch3"), tn.segs.get("-pch4"), tn.segs.get("-pch5"), tn.segs.get("-pch6"), tn.segs.get("-pch7"),
tn.segs.get("+Pout0"), tn.segs.get("+Pout1"), tn.segs.get("+Pout2"), tn.segs.get("+Pout3"), tn.segs.get("+Pout4"), /*no P5 */tn.segs.get("+Pout6"), tn.segs.get("+Pout7"),
tn.segs.get("-s0"), tn.segs.get("-s1"), tn.segs.get("-s2"), tn.segs.get("-s3"), tn.segs.get("-s4"), tn.segs.get("-s5"), tn.segs.get("-s6"), tn.segs.get("-s7")) {
}
unsigned short Common::rAddr() const {
return Segment::asWord(this->AB15, this->AB14, this->AB13, this->AB12, this->AB11, this->AB10, this->AB9, this->AB8, this->AB7, this->AB6, this->AB5, this->AB4, this->AB3, this->AB2, this->AB1, this->AB0);
}
unsigned char Common::rData() const {
return Segment::asByte(this->DB7, this->DB6, this->DB5, this->DB4, this->DB3, this->DB2, this->DB1, this->DB0);
}
unsigned char Common::rA() const {
return Segment::asByte(this->A7, this->A6, this->A5, this->A4, this->A3, this->A2, this->A1, this->A0);
}
unsigned char Common::rX() const {
return Segment::asByte(this->X7, this->X6, this->X5, this->X4, this->X3, this->X2, this->X1, this->X0);
}
unsigned char Common::rY() const {
return Segment::asByte(this->Y7, this->Y6, this->Y5, this->Y4, this->Y3, this->Y2, this->Y1, this->Y0);
}
unsigned char Common::rS() const {
return Segment::asByte(this->S7, this->S6, this->S5, this->S4, this->S3, this->S2, this->S1, this->S0);
}
unsigned short Common::rPC() const {
return Segment::asWord(this->PCH7, this->PCH6, this->PCH5, this->PCH4, this->PCH3, this->PCH2, this->PCH1, this->PCH0, this->PCL7, this->PCL6, this->PCL5, this->PCL4, this->PCL3, this->PCL2, this->PCL1, this->PCL0);
}
PinSettings Common::getDataPinSettings(const unsigned char data) const {
unsigned char x = data;
PinSettings ps;
ps.insert(std::make_pair(this->DB0,x & 1));
x >>= 1;
ps.insert(std::make_pair(this->DB1,x & 1));
x >>= 1;
ps.insert(std::make_pair(this->DB2,x & 1));
x >>= 1;
ps.insert(std::make_pair(this->DB3,x & 1));
x >>= 1;
ps.insert(std::make_pair(this->DB4,x & 1));
x >>= 1;
ps.insert(std::make_pair(this->DB5,x & 1));
x >>= 1;
ps.insert(std::make_pair(this->DB6,x & 1));
x >>= 1;
ps.insert(std::make_pair(this->DB7,x & 1));
return ps;
}

88
src/Common.h Normal file
View File

@ -0,0 +1,88 @@
/*
* File: Common.h
* Author: Christopher
*
* Created on December 14, 2013, 8:47 PM
*/
#ifndef COMMON_H
#define COMMON_H
#include "SegmentTypes.h"
class TransNetwork;
class Common final {
public:
Segment * const VSS, * const VCC;
Segment * const CLK0;
Segment * const IRQ, * const RES, * const NMI;
Segment * const RDY, * const SO;
Segment * const DB0, * const DB1, * const DB2, * const DB3, * const DB4, * const DB5, * const DB6, * const DB7;
Segment * const AB0, * const AB1, * const AB2, * const AB3, * const AB4, * const AB5, * const AB6, * const AB7, * const AB8, * const AB9, * const AB10, * const AB11, * const AB12, * const AB13, * const AB14, * const AB15;
Segment * const RW, * const SYNC;
Segment * const CLK1OUT, * const CLK2OUT;
Segment * const A0, * const A1, * const A2, * const A3, * const A4, * const A5, * const A6, * const A7;
Segment * const X0, * const X1, * const X2, * const X3, * const X4, * const X5, * const X6, * const X7;
Segment * const Y0, * const Y1, * const Y2, * const Y3, * const Y4, * const Y5, * const Y6, * const Y7;
Segment * const PCL0, * const PCL1, * const PCL2, * const PCL3, * const PCL4, * const PCL5, * const PCL6, * const PCL7;
Segment * const PCH0, * const PCH1, * const PCH2, * const PCH3, * const PCH4, * const PCH5, * const PCH6, * const PCH7;
Segment * const P0, * const P1, * const P2, * const P3, * const P4, /* no P5 */ * const P6, * const P7;
Segment * const S0, * const S1, * const S2, * const S3, * const S4, * const S5, * const S6, * const S7;
Common(const TransNetwork& segs);
unsigned char rA() const;
unsigned char rX() const;
unsigned char rY() const;
unsigned char rS() const;
unsigned short rPC() const;
unsigned short rAddr() const;
unsigned char rData() const;
PinSettings getDataPinSettings(const unsigned char data) const;
private:
Common(
Segment* VSS, Segment* VCC,
Segment* CLK0,
Segment* IRQ, Segment* RES, Segment* NMI,
Segment* RDY, Segment* SO,
Segment* DB0, Segment* DB1, Segment* DB2, Segment* DB3, Segment* DB4, Segment* DB5, Segment* DB6, Segment* DB7,
Segment* AB0, Segment* AB1, Segment* AB2, Segment* AB3, Segment* AB4, Segment* AB5, Segment* AB6, Segment* AB7,
Segment* AB8, Segment* AB9, Segment* AB10, Segment* AB11, Segment* AB12, Segment* AB13, Segment* AB14, Segment* AB15,
Segment* RW, Segment* SYNC,
Segment* CLK1OUT, Segment* CLK2OUT,
Segment* A0, Segment* A1, Segment* A2, Segment* A3, Segment* A4, Segment* A5, Segment* A6, Segment* A7,
Segment* X0, Segment* X1, Segment* X2, Segment* X3, Segment* X4, Segment* X5, Segment* X6, Segment* X7,
Segment* Y0, Segment* Y1, Segment* Y2, Segment* Y3, Segment* Y4, Segment* Y5, Segment* Y6, Segment* Y7,
Segment* PCL0, Segment* PCL1, Segment* PCL2, Segment* PCL3, Segment* PCL4, Segment* PCL5, Segment* PCL6, Segment* PCL7,
Segment* PCH0, Segment* PCH1, Segment* PCH2, Segment* PCH3, Segment* PCH4, Segment* PCH5, Segment* PCH6, Segment* PCH7,
Segment* P0, Segment* P1, Segment* P2, Segment* P3, Segment* P4, /* no P5 */ Segment* P6, Segment* P7,
Segment* S0, Segment* S1, Segment* S2, Segment* S3, Segment* S4, Segment* S5, Segment* S6, Segment* S7) :
VSS(VSS), VCC(VCC),
CLK0(CLK0),
IRQ(IRQ), RES(RES), NMI(NMI),
RDY(RDY), SO(SO),
DB0(DB0), DB1(DB1), DB2(DB2), DB3(DB3), DB4(DB4), DB5(DB5), DB6(DB6), DB7(DB7),
AB0(AB0), AB1(AB1), AB2(AB2), AB3(AB3), AB4(AB4), AB5(AB5), AB6(AB6), AB7(AB7),
AB8(AB8), AB9(AB9), AB10(AB10), AB11(AB11), AB12(AB12), AB13(AB13), AB14(AB14), AB15(AB15),
RW(RW), SYNC(SYNC),
CLK1OUT(CLK1OUT), CLK2OUT(CLK2OUT),
A0(A0), A1(A1), A2(A2), A3(A3), A4(A4), A5(A5), A6(A6), A7(A7),
X0(X0), X1(X1), X2(X2), X3(X3), X4(X4), X5(X5), X6(X6), X7(X7),
Y0(Y0), Y1(Y1), Y2(Y2), Y3(Y3), Y4(Y4), Y5(Y5), Y6(Y6), Y7(Y7),
PCL0(PCL0), PCL1(PCL1), PCL2(PCL2), PCL3(PCL3), PCL4(PCL4), PCL5(PCL5), PCL6(PCL6), PCL7(PCL7),
PCH0(PCH0), PCH1(PCH1), PCH2(PCH2), PCH3(PCH3), PCH4(PCH4), PCH5(PCH5), PCH6(PCH6), PCH7(PCH7),
P0(P0), P1(P1), P2(P2), P3(P3), P4(P4), /* no P5 */ P6(P6), P7(P7),
S0(S0), S1(S1), S2(S2), S3(S3), S4(S4), S5(S5), S6(S6), S7(S7) {
}
};
#endif /* COMMON_H */

63
src/Cpu6502.cpp Normal file
View File

@ -0,0 +1,63 @@
/*
* File: Cpu6502.cpp
* Author: Christopher
*
* Created on December 12, 2013, 10:14 PM
*/
#include "Cpu6502.h"
#include "addressbus.h"
#include "StateCalculator.h"
#include "Trace.h"
#include "Common.h"
#include "trans.h"
#define TRACEREG 1
//#define TRACESEG 1
void Cpu6502::setPins(const PinSettings& ps) {
SegmentSet rec;
for (auto p : ps) {
p.first->set(p.second);
rec.insert(p.first);
}
StateCalculator::recalc(rec);
}
void Cpu6502::clock(bool phase) {
setPins(PinSettings{std::make_pair(common.CLK0,phase)});
rw();
#ifdef TRACEREG
this->trace.dumpRegisters();
#endif
#ifdef TRACESEG
this->trace.dumpSegments();
#endif
}
void Cpu6502::rw() {
/* database read/write happens (only) during Clock Phase 2 */
if (common.CLK2OUT->on) {
readData();
writeData();
}
}
void Cpu6502::readData() {
if (this->common.RW->on) {
setPins(this->common.getDataPinSettings(this->addressBus.read(this->common.rAddr())));
}
}
void Cpu6502::writeData() {
if (!this->common.RW->on) {
this->addressBus.write(this->common.rAddr(), this->common.rData());
}
}

45
src/Cpu6502.h Normal file
View File

@ -0,0 +1,45 @@
/*
* File: Cpu6502.h
* Author: Christopher
*
* Created on December 12, 2013, 10:14 PM
*/
#ifndef CPU6502_H
#define CPU6502_H
#include "SegmentTypes.h"
#include "Trace.h"
class AddressBus;
class Trace;
class Common;
class Cpu6502 final {
public:
Cpu6502(AddressBus& addressBus, Trace& trace, Common& common) : addressBus(addressBus), trace(trace), common(common) {
#if 0
trace.dumpTransistors();
#endif
}
void setPins(const PinSettings& ps);
void clock(bool phase);
private:
Cpu6502(const Cpu6502&) = delete;
Cpu6502& operator=(const Cpu6502&) = delete;
void rw();
void readData();
void writeData();
AddressBus& addressBus;
Trace& trace;
Common& common;
};
#endif /* CPU6502_H */

72
src/Cpu6502Helper.cpp Normal file
View File

@ -0,0 +1,72 @@
/*
* File: Cpu6502Helper.cpp
* Author: Christopher
*
* Created on December 12, 2013, 10:22 PM
*/
#include "Cpu6502Helper.h"
#include "Cpu6502.h"
#include "Common.h"
#include "SegmentTypes.h"
void Cpu6502Helper::powerOn() {
PinSettings ps;
// set voltage supply and ground.
ps.insert(std::make_pair(this->common.VCC, true));
ps.insert(std::make_pair(this->common.VSS, false));
// don't do the set-overflow overriding functionality
ps.insert(std::make_pair(this->common.SO, false));
// ready to run (i.e., do not do single-stepping of instructions)
ps.insert(std::make_pair(this->common.RDY, true));
// pull up to indicate that we are not interrupting now
ps.insert(std::make_pair(this->common.IRQ, true));
ps.insert(std::make_pair(this->common.NMI, true));
/*
* RES_BAR pin means "not resetting". Since it is a negated pin, pulling it low means "resetting"
* and pulling it high means "not resetting" or equivalently "running".
*/
/*
* RES_BAR false: resetting now (i.e., in power-up now; pull high to begin normal operation)
* We want to hold RES_BAR low for a while, indicating power-up phase during which the
* CPU does not start up normal operations yet. The caller can set RES_BAR high (by calling
* reset) whenever he is ready to start the CPU running.
*/
ps.insert(std::make_pair(this->common.RES, false));
this->cpu.setPins(ps);
this->nextPhase = true;
}
void Cpu6502Helper::tick() {
step();
step();
}
void Cpu6502Helper::step() {
/*
* We cheat a little bit here: instead of requiring the
* caller to toggle clock-zero pin, we let him just call
* "step" and *we* keep track of which phase we are in.
* To do this, we just use the CLK0 segment value (as
* a kind of temporary variable), and just toggle it in
* order to know which phase we are going into.
*
* The real 6502, of course, does not do this.
*/
this->nextPhase = !this->nextPhase;
this->cpu.clock(this->nextPhase);
}
void Cpu6502Helper::reset() {
this->cpu.setPins(PinSettings{std::make_pair(this->common.RES, true)});
}

37
src/Cpu6502Helper.h Normal file
View File

@ -0,0 +1,37 @@
/*
* File: Cpu6502Helper.h
* Author: Christopher
*
* Created on December 12, 2013, 10:22 PM
*/
#ifndef CPU6502HELPER_H
#define CPU6502HELPER_H
class Cpu6502;
class Common;
class Cpu6502Helper final {
public:
Cpu6502Helper(Cpu6502& cpu, Common& common) : cpu(cpu), common(common), nextPhase(true) {
}
void powerOn();
void tick();
void reset();
private:
Cpu6502Helper(const Cpu6502Helper&) = delete;
Cpu6502Helper& operator=(const Cpu6502Helper&) = delete;
void step();
Cpu6502& cpu;
Common& common;
bool nextPhase;
};
#endif /* CPU6502HELPER_H */

8
src/Emu6502.cpp Normal file
View File

@ -0,0 +1,8 @@
/*
* File: Emu6502.cpp
* Author: Christopher
*
* Created on December 15, 2013, 12:43 AM
*/
#include "Emu6502.h"

57
src/Emu6502.h Normal file
View File

@ -0,0 +1,57 @@
/*
* File: Emu6502.h
* Author: Christopher
*
* Created on December 15, 2013, 12:43 AM
*/
#ifndef EMU6502_H
#define EMU6502_H
#include "Cpu6502Helper.h"
#include "Cpu6502.h"
#include "Trace.h"
#include "Common.h"
#include "TransNetwork.h"
#include "TransCache.h"
#include "SegmentCache.h"
#include <istream>
class AddressBus;
class Emu6502 {
public:
Emu6502(std::istream& transistors, AddressBus& mem) : tn(transistors, segs, transes), c(tn), trace(segs, transes, c), cpu(mem, trace, c), cpuhelper(cpu, c) {
}
virtual ~Emu6502() {
}
void powerOn() {
this->cpuhelper.powerOn();
}
void tick() {
this->cpuhelper.tick();
}
void reset() {
this->cpuhelper.reset();
}
private:
Emu6502(const Emu6502&) = delete;
Emu6502 operator=(const Emu6502&) = delete;
SegmentCache segs;
TransCache transes;
TransNetwork tn;
Common c;
Trace trace;
Cpu6502 cpu;
Cpu6502Helper cpuhelper;
};
#endif /* EMU6502_H */

View File

@ -20,7 +20,9 @@ epple2_SOURCES = a2colorsobserved.cpp addressbus.cpp analogtv.cpp apple2.cpp \
screenimage.cpp slots.cpp speakerclicker.cpp standardin.cpp \
standardinproducer.cpp standardout.cpp steppermotor.cpp textcharacters.cpp \
timable.cpp video.cpp videoaddressing.cpp videomode.cpp \
videostaticgenerator.cpp
videostaticgenerator.cpp \
Circuit.cpp Common.cpp Cpu6502.cpp Cpu6502Helper.cpp Emu6502.cpp SegmentCache.cpp \
StateCalculator.cpp Trace.cpp TransCache.cpp TransNetwork.cpp v6502.cpp
noinst_HEADERS = a2colorsobserved.h addressbus.h analogtv.h apple2.h applentsc.h \
card.h cassette.h clipboardhandler.h clockcard.h configep2.h cpu.h diskbytes.h \
@ -30,4 +32,6 @@ noinst_HEADERS = a2colorsobserved.h addressbus.h analogtv.h apple2.h applentsc.h
powerupreset.h raminitializer.h screenimage.h slots.h speakerclicker.h \
standardin.h standardinproducer.h standardout.h steppermotor.h \
textcharacterimages.h textcharacters.h timable.h util.h \
videoaddressing.h video.h videomode.h videostaticgenerator.h
videoaddressing.h video.h videomode.h videostaticgenerator.h \
Circuit.h Common.h Cpu6502.h Cpu6502Helper.h Emu6502.h SegmentCache.h SegmentTypes.h \
StateCalculator.h Trace.h TransCache.h TransNetwork.h addressbus.h ptr_less.h trans.h

53
src/SegmentCache.cpp Normal file
View File

@ -0,0 +1,53 @@
/*
* File: SegmentCache.cpp
* Author: cmosher
*
* Created on December 10, 2013, 9:56 PM
*/
#include "SegmentCache.h"
#include "trans.h"
#include <memory>
#include <string>
#include <map>
bool SegmentCache::cached(const std::string& id) const {
return this->cache.find(id) != this->cache.end();
}
Segment* SegmentCache::getOrAdd(const std::string& id) {
if (!cached(id)) {
this->cache[id] = std::make_shared<Segment>(id);
/*
* We want to optimize VSS and VCC checking in
* the rest of the program, so we check here
* for those two special cases, and flag them.
* So, for example, checking (s->vss) is equivalent
* to checking (s==VCC).
*/
if (id == "-vss") {
this->cache[id]->vss = true;
} else if (id == "+vcc") {
this->cache[id]->vcc = true;
}
}
return get(id);
}
Segment* SegmentCache::get(const std::string& id) const {
if (!cached(id)) {
throw "Cannot find segment: " + id;
}
return this->cache.at(id).get();
}
SegmentSet SegmentCache::all() const {
SegmentSet s;
for (auto i : this->cache) {
s.insert(i.second.get());
}
return s;
}

58
src/SegmentCache.h Normal file
View File

@ -0,0 +1,58 @@
/*
* File: SegmentCache.h
* Author: Christopher
*
* Created on December 10, 2013, 9:56 PM
*/
#ifndef SEGMENTCACHE_H
#define SEGMENTCACHE_H
#include "SegmentTypes.h"
#include <map>
#include <set>
#include <string>
#include <memory>
class Common;
class SegmentCache final {
public:
SegmentCache() {
}
Segment* getOrAdd(const std::string& id);
SegmentSet all() const;
typedef std::map<const std::string, std::shared_ptr<Segment>> Map;
Map::const_iterator begin() const {
return this->cache.begin();
}
Map::const_iterator end() const {
return this->cache.end();
}
Map::size_type size() const {
return this->cache.size();
}
private:
Map cache;
SegmentCache(const SegmentCache&) = delete;
SegmentCache& operator=(const SegmentCache&) = delete;
Segment* get(const std::string& id) const;
bool cached(const std::string& id) const;
friend Common;
};
#endif /* SEGMENTCACHE_H */

21
src/SegmentTypes.h Normal file
View File

@ -0,0 +1,21 @@
/*
* File: setpSeg.h
* Author: Christopher
*
* Created on December 15, 2013, 12:16 AM
*/
#ifndef SETPSEG_H
#define SETPSEG_H
#include "ptr_less.h"
#include <set>
#include <utility>
class Segment;
typedef std::set<Segment*,ptr_less<Segment>> SegmentSet;
typedef std::set<std::pair<Segment*, bool>> PinSettings;
#endif /* SETPSEG_H */

69
src/StateCalculator.cpp Normal file
View File

@ -0,0 +1,69 @@
/*
* File: StateCalculator.cpp
* Author: Christopher
*
* Created on December 12, 2013, 8:29 PM
*/
#include "StateCalculator.h"
#include "Circuit.h"
#include "trans.h"
/*
* Recalculate segment states (on/off), based on the fact that the segments
* in segs have just changed state. Keep track of which other segments are
* affected, and repeat the process on those segments. Repeat until no more
* segments change state.
*/
#define SANE (100)
void StateCalculator::recalc(const SegmentSet& segs) {
int sanity(0);
SegmentSet changed(segs);
while (!changed.empty()) {
if (++sanity >= SANE) {
throw "ERROR: reached maximum iteration limit while recalculating CPU state";
}
StateCalculator c;
for (auto s : changed) {
c.recalcNode(s);
}
changed = c.segs;
}
}
/*
* Gets group of segments currently electrically connected to seg,
* gets what their group value is (or should be), goes through all
* those segments and sets their "on" value. For all connected gates,
* turn on/off, and indicate that the segments connected to those
* transistors' source and drain legs have changed, by adding them
* to this->segs.
*/
void StateCalculator::recalcNode(Segment* seg) {
if (!(seg->vss || seg->vcc)) {
Circuit c(seg);
for (auto s : c) {
setSeg(s, c.getValue());
}
}
}
void StateCalculator::setSeg(Segment* s, const bool on) {
if (s->on != on) {
s->on = on;
for (auto t : s->gates) {
setTrans(t, on);
}
}
}
void StateCalculator::setTrans(Trans* t, const bool on) {
if (t->on != on) {
t->on = on;
this->segs.insert(t->c1);
this->segs.insert(t->c2);
}
}

36
src/StateCalculator.h Normal file
View File

@ -0,0 +1,36 @@
/*
* File: StateCalculator.h
* Author: Christopher
*
* Created on December 12, 2013, 8:29 PM
*/
#ifndef STATECALCULATOR_H
#define STATECALCULATOR_H
#include <set>
#include "SegmentTypes.h"
class Trans;
class StateCalculator final {
public:
static void recalc(const SegmentSet& rSeg);
private:
StateCalculator() {
}
StateCalculator(const StateCalculator&) = delete;
StateCalculator& operator=(const StateCalculator&) = delete;
void recalcNode(Segment* seg);
void setSeg(Segment* s, const bool on);
void setTrans(Trans* t, const bool on);
SegmentSet segs;
};
#endif /* STATECALCULATOR_H */

103
src/Trace.cpp Normal file
View File

@ -0,0 +1,103 @@
/*
* File: Trace.cpp
* Author: cmosher
*
* Created on December 12, 2013, 3:39 PM
*/
#include "Trace.h"
#include "TransCache.h"
#include "SegmentCache.h"
#include "Common.h"
#include "trans.h"
#include <iostream>
#include <iomanip>
static void pHex(const unsigned long x, const int width) {
std::cout << std::setw(width) << std::setfill('0') << std::hex << x << std::dec;
}
static void pHexb(const unsigned char x) {
pHex(x, 2);
}
static void pHexw(const unsigned short x) {
pHex(x, 4);
}
void Trace::dumpSegments() const {
for (auto sp : this->segs) {
Segment* seg = sp.second.get();
if (seg->pull == Pull::UP) {
std::cout << (seg->on ? "U" : "u");
} else if (seg->pull == Pull::DOWN) {
std::cout << (seg->on ? "D" : "d");
} else {
std::cout << (seg->on ? "F" : "f");
}
}
std::cout << std::endl;
}
void Trace::dumpRegisters() const {
std::cout << "A";
pHexb(this->common.rA());
std::cout << " X";
pHexb(this->common.rX());
std::cout << " Y";
pHexb(this->common.rY());
std::cout << " ";
std::cout << (this->common.P7->on ? "N" : "n");
std::cout << (this->common.P6->on ? "V" : "v");
std::cout << ".";
std::cout << (this->common.P4->on ? "B" : "b");
std::cout << (this->common.P3->on ? "D" : "d");
std::cout << (this->common.P2->on ? "I" : "i");
std::cout << (this->common.P1->on ? "Z" : "z");
std::cout << (this->common.P0->on ? "C" : "c");
std::cout << " S";
pHexb(this->common.rS());
std::cout << " PC";
pHexw(this->common.rPC());
if (this->common.CLK1OUT->on) {
std::cout << " PH1 ";
}
if (this->common.CLK2OUT->on) {
std::cout << " PH2";
if (this->common.RW->on) {
std::cout << " R";
} else {
std::cout << " W";
}
}
if (!(this->common.CLK1OUT->on || this->common.CLK2OUT->on)) {
std::cout << " PH- ";
}
std::cout << " DB";
pHexb(this->common.rData());
std::cout << " AB";
pHexw(this->common.rAddr());
std::cout << std::endl;
}
void Trace::dumpTransistors() const {
/* count depletion-mode MOSFETs */
int cd(0);
for (auto sp : this->segs) {
Segment* seg = sp.second.get();
if (seg->dmos) {
++cd;
}
}
std::cout << "eMOSFETs: " << this->transes.size() << ", dMOSFETs: " << cd << std::endl;
}

35
src/Trace.h Normal file
View File

@ -0,0 +1,35 @@
/*
* File: Trace.h
* Author: cmosher
*
* Created on December 12, 2013, 3:39 PM
*/
#ifndef TRACE_H
#define TRACE_H
class SegmentCache;
class TransCache;
class Common;
class Trace final {
public:
Trace(const SegmentCache& segs, const TransCache& transes, const Common& common) : segs(segs), transes(transes), common(common) {
}
void dumpSegments() const;
void dumpTransistors() const;
void dumpRegisters() const;
private:
Trace(const Trace&) = delete;
Trace& operator=(const Trace&) = delete;
const SegmentCache& segs;
const TransCache& transes;
const Common& common;
};
#endif /* TRACE_H */

13
src/TransCache.cpp Normal file
View File

@ -0,0 +1,13 @@
/*
* File: TransCache.cpp
* Author: Christopher
*
* Created on December 15, 2013, 1:39 PM
*/
#include "TransCache.h"
#include "trans.h"
void TransCache::add(Segment* c1, Segment* gate, Segment* c2) {
this->cache.insert(std::make_shared<Trans>(c1,gate,c2));
}

47
src/TransCache.h Normal file
View File

@ -0,0 +1,47 @@
/*
* File: TransCache.h
* Author: Christopher
*
* Created on December 15, 2013, 1:39 PM
*/
#ifndef TRANSCACHE_H
#define TRANSCACHE_H
#include <set>
#include <memory>
class Trans;
class Segment;
class TransCache final {
public:
TransCache() {
}
void add(Segment* c1, Segment* gate, Segment* c2);
typedef std::set<std::shared_ptr<Trans>> Set;
Set::const_iterator begin() const {
return this->cache.begin();
}
Set::const_iterator end() const {
return this->cache.end();
}
Set::size_type size() const {
return this->cache.size();
}
private:
TransCache(const TransCache&) = delete;
TransCache& operator=(const TransCache&) = delete;
Set cache;
};
#endif /* TRANSCACHE_H */

27
src/TransNetwork.cpp Normal file
View File

@ -0,0 +1,27 @@
/*
* File: TransNetwork.cpp
* Author: cmosher
*
* Created on December 11, 2013, 10:44 AM
*/
#include "TransNetwork.h"
#include "TransCache.h"
#include "SegmentCache.h"
#include "StateCalculator.h"
#include "trans.h"
#include <iostream>
#include <set>
#include <string>
#include <memory>
TransNetwork::TransNetwork(std::istream& in, SegmentCache& segs, TransCache& transes) : segs(segs), transes(transes) {
std::string c1, gate, c2;
in >> c1 >> gate >> c2;
while (in.good()) {
this->transes.add(this->segs.getOrAdd(c1), this->segs.getOrAdd(gate), this->segs.getOrAdd(c2));
in >> c1 >> gate >> c2;
}
StateCalculator::recalc(this->segs.all());
}

36
src/TransNetwork.h Normal file
View File

@ -0,0 +1,36 @@
/*
* File: TransNetwork.h
* Author: cmosher
*
* Created on December 11, 2013, 10:44 AM
*/
#ifndef TRANSNETWORK_H
#define TRANSNETWORK_H
#include <istream>
#include <set>
#include <memory>
class TransCache;
class SegmentCache;
class Common;
class Trans;
class TransNetwork final {
public:
TransNetwork(std::istream& readFromHere, SegmentCache& segs, TransCache& transes);
private:
TransNetwork(const TransNetwork&) = delete;
TransNetwork& operator=(const TransNetwork&) = delete;
SegmentCache& segs;
TransCache& transes;
friend Common;
};
#endif /* TRANSNETWORK_H */

View File

@ -35,6 +35,7 @@
#include "screenimage.h"
#include <iostream>
#include <istream>
#include <fstream>
Apple2::Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui):
@ -46,7 +47,9 @@ Apple2::Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates
addressBus(ram,rom,kbd,videoMode,paddles,paddleButtonStates,speaker,cassette,slts),
picgen(tv,videoMode,this->revision),
video(videoMode,addressBus,picgen,textRows),
cpu(addressBus),
transistors("transistors"),
cpu(transistors,addressBus),
// cpu(addressBus),
powerUpReset(*this),
revision(1)
{

View File

@ -34,6 +34,8 @@
#include "analogtv.h"
#include "powerupreset.h"
#include "cassette.h"
#include "Emu6502.h"
#include <fstream>
class Emulator;
class ScreenImage;
@ -51,7 +53,9 @@ class Apple2 : public Timable
PictureGenerator picgen;
TextCharacters textRows;
Video video;
CPU cpu;
// CPU cpu;
std::ifstream transistors;
Emu6502 cpu;
PowerUpReset powerUpReset;
int revision;

20
src/ptr_less.h Normal file
View File

@ -0,0 +1,20 @@
/*
* File: ptr_less.h
* Author: Christopher
*
* Created on December 14, 2013, 5:44 PM
*/
#ifndef PTR_LESS_H
#define PTR_LESS_H
template<typename T>
struct ptr_less {
bool operator()(T* pa, T* pb) {
return *pa < *pb;
}
};
#endif /* PTR_LESS_H */

92
src/trans.h Normal file
View File

@ -0,0 +1,92 @@
/*
* File: trans.h
* Author: cmosher
*
* Created on December 10, 2013, 2:37 PM
*/
#ifndef TRANS_H
#define TRANS_H
#include "SegmentTypes.h"
#include <set>
#include <string>
class Trans;
enum class Pull { UP, DOWN, FLOAT };
class Segment final {
private:
const std::string id;
public:
std::set<Trans*> gates;
std::set<Trans*> c1c2s;
bool dmos;
bool vss;
bool vcc;
Pull pull;
bool on;
Segment(const std::string& id) : id(id), dmos(id[0]=='+'), vss(false), vcc(false), pull(dmos ? Pull::UP : Pull::FLOAT), on(false) {
}
void set(const bool up) {
this->pull = (up ? Pull::UP : Pull::DOWN);
}
bool operator<(const Segment& that) const { return this->id < that.id; }
static unsigned char asByte(Segment* b7, Segment* b6, Segment* b5, Segment* b4, Segment* b3, Segment* b2, Segment* b1, Segment* b0) {
return b7->on << 0x7 | b6->on << 0x6 | b5->on << 0x5 | b4->on << 0x4 | b3->on << 0x3 | b2->on << 0x2 | b1->on << 0x1 | b0->on;
}
static unsigned short asWord(Segment* bf, Segment* be, Segment* bd, Segment* bc, Segment* bb, Segment* ba, Segment* b9, Segment* b8, Segment* b7, Segment* b6, Segment* b5, Segment* b4, Segment* b3, Segment* b2, Segment* b1, Segment* b0) {
return bf->on << 0xf | be->on << 0xe | bd->on << 0xd | bc->on << 0xc | bb->on << 0xb | ba->on << 0xa | b9->on << 0x9 | b8->on << 0x8 | b7->on << 0x7 | b6->on << 0x6 | b5->on << 0x5 | b4->on << 0x4 | b3->on << 0x3 | b2->on << 0x2 | b1->on << 0x1 | b0->on;
}
private:
Segment(const Segment&) = delete;
Segment& operator=(const Segment&) = delete;
};
class Trans final {
public:
Segment* c1;
Segment* c2;
bool on;
Trans(Segment* c1, Segment* gate, Segment* c2) : c1(c1), c2(c2), on(false) {
c1->c1c2s.insert(this);
gate->gates.insert(this);
c2->c1c2s.insert(this);
}
private:
Trans(const Trans&) = delete;
Trans& operator=(const Trans&) = delete;
};
#endif /* TRANS_H */

3239
transistors Normal file

File diff suppressed because it is too large Load Diff