From af2fe80221b76925ab74cfd44bb260503b169113 Mon Sep 17 00:00:00 2001 From: Christopher Mosher Date: Thu, 12 Dec 2013 23:31:47 -0500 Subject: [PATCH] (WIP) more changes for new data structures --- .gitignore | 1 + Circuit.cpp | 78 +++++++++++++++++ Circuit.h | 42 +++++++++ Cpu6502.cpp | 204 ++++++++++++++++++++++++++++++++++++++++++++ Cpu6502.h | 46 ++++++++++ Cpu6502Helper.cpp | 18 ++++ Cpu6502Helper.h | 21 +++++ Makefile | 31 ++++--- StateCalculator.cpp | 93 ++++++++++++++++++++ StateCalculator.h | 43 ++++++++++ trans.h | 2 +- v6502.cpp | 5 +- 12 files changed, 565 insertions(+), 19 deletions(-) create mode 100644 Circuit.cpp create mode 100644 Circuit.h create mode 100644 Cpu6502.cpp create mode 100644 Cpu6502.h create mode 100644 Cpu6502Helper.cpp create mode 100644 Cpu6502Helper.h create mode 100644 StateCalculator.cpp create mode 100644 StateCalculator.h diff --git a/.gitignore b/.gitignore index 50701e1..5ccae9a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.o +*.d v6502 v6502.exe /nbproject/ diff --git a/Circuit.cpp b/Circuit.cpp new file mode 100644 index 0000000..9c34d6c --- /dev/null +++ b/Circuit.cpp @@ -0,0 +1,78 @@ +/* + * File: Circuit.cpp + * Author: Christopher + * + * Created on December 12, 2013, 7:04 PM + */ + +#include "Circuit.h" +#include "trans.h" + +Circuit::Circuit(Segment* extendFrom, Segment* VSS, Segment* VCC) : VSS(VSS), VCC(VCC) { + extend(extendFrom); +} + +/* + * 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) { + const std::pair < std::set::iterator, bool> ret = this->segs.insert(extendFrom); + if (!ret.second) { + return; + } + if (extendFrom == this->VCC || extendFrom == this->VSS) { + 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 (std::set::const_iterator iTrn = extendFrom->c1c2s.begin(); iTrn != extendFrom->c1c2s.end(); ++iTrn) { + const Trans * t(*iTrn); + 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, */ + if (contains(this->VSS)) { + return false; + }/* otherwise, if group contains voltage supply, it's ON. */ + else if (contains(this->VCC)) { + return true; + } + + + + for (std::set::const_iterator iSeg = this->segs.begin(); iSeg != this->segs.end(); ++iSeg) { + Segment * s(*iSeg); + if (s->pullup) { + return true; + } + if (s->pulldown) { + return false; + } + if (s->on) { + return true; + } + } + return false; +} diff --git a/Circuit.h b/Circuit.h new file mode 100644 index 0000000..a55ac17 --- /dev/null +++ b/Circuit.h @@ -0,0 +1,42 @@ +/* + * File: Circuit.h + * Author: Christopher + * + * Created on December 12, 2013, 7:04 PM + */ + +#ifndef CIRCUIT_H +#define CIRCUIT_H + +#include + +class Segment; + +class Circuit { +public: + Circuit(Segment* extendFrom, Segment* VSS, Segment* VCC); + + virtual ~Circuit() { + } + + bool getValue(); + std::set::iterator begin() { return this->segs.begin(); } + std::set::iterator end() { return this->segs.end(); } + +private: + Circuit(const Circuit&); + Circuit& operator=(const Circuit&); + + void extend(Segment* extendFrom); + + bool contains(Segment* s) const { + return this->segs.find(s) != this->segs.end(); + } + + std::set segs; + Segment* VSS; + Segment* VCC; +}; + +#endif /* CIRCUIT_H */ + diff --git a/Cpu6502.cpp b/Cpu6502.cpp new file mode 100644 index 0000000..2b2a154 --- /dev/null +++ b/Cpu6502.cpp @@ -0,0 +1,204 @@ +/* + * File: Cpu6502.cpp + * Author: Christopher + * + * Created on December 12, 2013, 10:14 PM + */ + +#include "Cpu6502.h" +#include "TransNetwork.h" +#include "trans.h" +#include "AddressBus.h" +#include "Trace.h" +#include + + + + + + + +#define TRACEREG 1 +//#define TRACESEG 1 +//#define TRACEMEM 1 + +#ifdef TRACEREG +#define dumpRegs() this->trace.dumpRegisters() +#else +#define dumpRegs() +#endif + +#ifdef TRACESEG +#define dumpSegs() dumpSegments() +#else +#define dumpSegs() +#endif + + + + + + +void Cpu6502::powerOn() { + std::cout << "initial state" << std::endl; + dumpRegs(); + dumpSegs(); + + + + /* + * Since we use segs[CLK0].on as our own + * temporary variable (see "step" method), we + * need to initialize it here, to "phase one". + */ + segs[n->CLK0].on = true; + + + + std::cout << "setting input pins..." << std::endl; + initPins(); + + std::cout << "initial full calculation..." << std::endl; + recalcAll(); + dumpRegs(); + dumpSegs(); +} + +void Cpu6502::initPins() { + // set voltage supply and ground. + setSeg(n->VCC, true); + setSeg(n->VSS, false); + + // don't do the set-overflow overriding functionality + setSeg(n->SO, false); + + // ready to run (i.e., do not do single-stepping of instructions) + setSeg(n->RDY, true); + + // pull up to indicate that we are not interrupting now + setSeg(n->IRQ, true); + setSeg(n->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. + */ + setSeg(n->RES, false); +} + +void Cpu6502::reset() { + setSeg(n->RES, true); + recalc(n->RES); +} + +void Cpu6502::tick() { + step(); + step(); +} + +void Cpu6502::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. + */ + const bool nextPhase = !segs[n->CLK0].on; + + clock(nextPhase); + rw(); + + dumpRegs(); + dumpSegs(); +} + +void Cpu6502::clock(bool phase) { + setSeg(n->CLK0, phase); + recalc(n->CLK0); +} + +void Cpu6502::rw() { + // database read/write happens during Clock Phase 2 (only) + if (segs[n->CLK2OUT].on) { + readBus(); + + std::set s; + addDataToRecalc(s); + recalc(s); + + writeBus(); + } +} + + + + + + + + +void Cpu6502::readBus() { + if (this->transNetwork.segs.c->RW->on) { + this->transNetwork.segs.setDataSegs(read(this->transNetwork.segs.rAddr())); + } +} + +void Cpu6502::writeBus() { + if (!this->transNetwork.segs.c->RW->on) { + write(this->transNetwork.segs.rAddr(), this->transNetwork.segs.rData()); + } +} + + + + + + +unsigned char Cpu6502::read(unsigned short addr) { + const unsigned char x = this->addressBus.read(addr); +#ifdef TRACEMEM + std::cout << "-------------------------------------------------- "; + pHex(x); + std::cout << "<"; + pHexw(addr); + std::cout << std::endl; +#endif + return x; +} + +void Cpu6502::write(unsigned short addr, unsigned char data) { + this->addressBus.write(addr, data); +#ifdef TRACEMEM + std::cout << "-------------------------------------------------- "; + pHex(data); + std::cout << ">"; + pHexw(addr); + std::cout << std::endl; +#endif +} + + + + + + + +void Cpu6502::recalcAll() { + std::set riSeg; + for (int iSeg = 0; iSeg < segs.size(); ++iSeg) { + addRecalc(iSeg,riSeg); + } + recalc(riSeg); +} diff --git a/Cpu6502.h b/Cpu6502.h new file mode 100644 index 0000000..0e4b83f --- /dev/null +++ b/Cpu6502.h @@ -0,0 +1,46 @@ +/* + * File: Cpu6502.h + * Author: Christopher + * + * Created on December 12, 2013, 10:14 PM + */ + +#ifndef CPU6502_H +#define CPU6502_H + +class TransNetwork; +class AddressBus; +class Trace; + +class Cpu6502 { +public: + + Cpu6502(TransNetwork& transNetwork, AddressBus& addressBus, Trace& trace) : transNetwork(transNetwork), addressBus(addressBus), trace(trace) { + } + + virtual ~Cpu6502() { + } + +private: + Cpu6502(const Cpu6502&); + Cpu6502& operator=(const Cpu6502&); + + void powerOn(); + void initPins(); + void reset(); + void tick(); + void step(); + void clock(bool phase); + void rw(); + void readBus(); + void writeBus(); + unsigned char read(unsigned short addr); + void write(unsigned short addr, unsigned char data); + + TransNetwork& transNetwork; + AddressBus& addressBus; + + Trace& trace; +}; + +#endif /* CPU6502_H */ diff --git a/Cpu6502Helper.cpp b/Cpu6502Helper.cpp new file mode 100644 index 0000000..7c50a89 --- /dev/null +++ b/Cpu6502Helper.cpp @@ -0,0 +1,18 @@ +/* + * File: Cpu6502Helper.cpp + * Author: Christopher + * + * Created on December 12, 2013, 10:22 PM + */ + +#include "Cpu6502Helper.h" + +Cpu6502Helper::Cpu6502Helper() { +} + +Cpu6502Helper::Cpu6502Helper(const Cpu6502Helper& orig) { +} + +Cpu6502Helper::~Cpu6502Helper() { +} + diff --git a/Cpu6502Helper.h b/Cpu6502Helper.h new file mode 100644 index 0000000..2ad637c --- /dev/null +++ b/Cpu6502Helper.h @@ -0,0 +1,21 @@ +/* + * File: Cpu6502Helper.h + * Author: Christopher + * + * Created on December 12, 2013, 10:22 PM + */ + +#ifndef CPU6502HELPER_H +#define CPU6502HELPER_H + +class Cpu6502Helper { +public: + Cpu6502Helper(); + Cpu6502Helper(const Cpu6502Helper& orig); + virtual ~Cpu6502Helper(); +private: + +}; + +#endif /* CPU6502HELPER_H */ + diff --git a/Makefile b/Makefile index 92d6c9a..05dd785 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,24 @@ CXXFLAGS=-g -std=c++11 +SRCS = v6502.cpp cpu.cpp nodes.cpp trans.cpp SegmentCache.cpp TransNetwork.cpp Trace.cpp Circuit.cpp StateCalculator.cpp Cpu6502.cpp +OBJS = $(SRCS:.cpp=.o) +DEPS = $(SRCS:.cpp=.d) + +.cpp.o: + $(COMPILE.cpp) -MMD $(OUTPUT_OPTION) $< + +.PHONY: all clean + + + all: v6502 -v6502: v6502.o cpu.o nodes.o trans.o SegmentCache.o TransNetwork.o Trace.o - g++ $^ -o $@ +v6502: $(OBJS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET) -v6502.o: v6502.cpp cpu.h addressbus.h TransNetwork.h +-include $(DEPS) -cpu.o: cpu.cpp cpu.h addressbus.h nodes.h -nodes.o: nodes.cpp nodes.h - -trans.o: trans.cpp trans.h - -SegmentCache.o: SegmentCache.cpp SegmentCache.h - -TransNetwork.o: TransNetwork.cpp TransNetwork.h trans.h - -Trace.o: Trace.cpp Trace.h SegmentCache.h clean: - -rm *.o - -rm v6502 - -rm v6502.exe + -rm -f v6502 v6502.exe $(OBJS) $(DEPS) diff --git a/StateCalculator.cpp b/StateCalculator.cpp new file mode 100644 index 0000000..d04a5f7 --- /dev/null +++ b/StateCalculator.cpp @@ -0,0 +1,93 @@ +/* + * File: StateCalculator.cpp + * Author: Christopher + * + * Created on December 12, 2013, 8:29 PM + */ + +#include "StateCalculator.h" +#include "Circuit.h" +#include "trans.h" +#include "cpu.h" +#include + +StateCalculator::StateCalculator(Segment* VSS, Segment* VCC) : VSS(VSS), VCC(VCC) { +} + +//void StateCalculator::recalcAll() { +// std::set riSeg; +// for (int iSeg = 0; iSeg < segs.size(); ++iSeg) { +// addRecalc(iSeg,riSeg); +// } +// recalc(riSeg); +//} + +void StateCalculator::recalc(Segment* seg, Segment* VSS, Segment* VCC) { + std::set rSeg; + rSeg.insert(seg); + recalc(rSeg,VSS,VCC); +} + +/* + * Recalculate segment states (on/off), based on the fact that the segments + * in riSeg 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 std::set& rSeg, Segment* VSS, Segment* VCC) { + int sanity(0); + + std::set riSegRecalc(rSeg); + while (!riSegRecalc.empty()) { + if (++sanity >= SANE) { + throw "ERROR: reached maximum iteration limit while recalculating CPU state"; + } + + StateCalculator c(VSS, VCC); + for (std::set::const_iterator is = riSegRecalc.begin(); is != riSegRecalc.end(); ++is) { + c.recalcNode(*is); + } + riSegRecalc = c.getChanged(); + } +} + +/* + * Gets group of segments currently electrically connected to iSeg, + * 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 riSegChanged. + */ +void StateCalculator::recalcNode(Segment* seg) { + if (!(seg == this->VSS || seg == this->VCC)) { + Circuit c(seg, this->VSS, this->VCC); + + for (std::set::iterator is = c.begin(); is != c.end(); ++is) { + Segment * s(*is); + if (s->on != c.getValue()) { + s->on = c.getValue(); + for (std::set::iterator it = s->gates.begin(); it != s->gates.end(); ++it) { + Trans * t(*it); + setTrans(t, c.getValue()); + } + } + } + } +} + +void StateCalculator::setTrans(Trans* t, const bool on) { + if (t->on != on) { + t->on = on; + addRecalc(t->c1); + addRecalc(t->c2); + } +} + +void StateCalculator::addRecalc(Segment* seg) { + if (!(seg == this->VSS || seg == this->VCC)) { + this->segs.insert(seg); + } +} diff --git a/StateCalculator.h b/StateCalculator.h new file mode 100644 index 0000000..4716b0d --- /dev/null +++ b/StateCalculator.h @@ -0,0 +1,43 @@ +/* + * File: StateCalculator.h + * Author: Christopher + * + * Created on December 12, 2013, 8:29 PM + */ + +#ifndef STATECALCULATOR_H +#define STATECALCULATOR_H + +#include + +class Segment; +class Trans; + +class StateCalculator { +public: + static void recalc(const std::set& rSeg, Segment* VSS, Segment* VCC); + static void recalc(Segment* seg, Segment* VSS, Segment* VCC); + +private: + std::set segs; + Segment* VSS; + Segment* VCC; + + StateCalculator(Segment* VSS, Segment* VCC); + + virtual ~StateCalculator() { + } + + StateCalculator(const StateCalculator&); + StateCalculator& operator=(const StateCalculator&); + + void recalcNode(Segment* seg); + void setTrans(Trans* t, const bool on); + void addRecalc(Segment* seg); + + std::set getChanged() { + return this->segs; + } +}; + +#endif /* STATECALCULATOR_H */ diff --git a/trans.h b/trans.h index d75739c..345c658 100644 --- a/trans.h +++ b/trans.h @@ -36,7 +36,7 @@ public: }; class Trans { -private: +public: Segment* c1; Segment* gate; Segment* c2; diff --git a/v6502.cpp b/v6502.cpp index a163589..32f227e 100644 --- a/v6502.cpp +++ b/v6502.cpp @@ -12,6 +12,7 @@ #include "addressbus.h" #include "cpu.h" +#include "Cpu6502.h" #include "TransNetwork.h" //memory[0xFF] = 0x68; // PLA @@ -44,8 +45,8 @@ int main(int argc, char *argv[]) { exit(EXIT_FAILURE); } TransNetwork tn(if_trans); - SegmentCache::Common* n = tn.segs.c; - n->CLK0->on = true; + + Cpu6502 cpu(tn); } int xxxmain(int argc, char *argv[]) {