(WIP) more changes for new data structures

This commit is contained in:
Christopher Mosher 2013-12-12 23:31:47 -05:00
parent b6624094be
commit af2fe80221
12 changed files with 565 additions and 19 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
*.o
*.d
v6502
v6502.exe
/nbproject/

78
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"
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<Segment*>::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<Trans*>::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<Segment*>::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;
}

42
Circuit.h Normal file
View File

@ -0,0 +1,42 @@
/*
* File: Circuit.h
* Author: Christopher
*
* Created on December 12, 2013, 7:04 PM
*/
#ifndef CIRCUIT_H
#define CIRCUIT_H
#include <set>
class Segment;
class Circuit {
public:
Circuit(Segment* extendFrom, Segment* VSS, Segment* VCC);
virtual ~Circuit() {
}
bool getValue();
std::set<Segment*>::iterator begin() { return this->segs.begin(); }
std::set<Segment*>::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<Segment*> segs;
Segment* VSS;
Segment* VCC;
};
#endif /* CIRCUIT_H */

204
Cpu6502.cpp Normal file
View File

@ -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 <iostream>
#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<int> 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<int> riSeg;
for (int iSeg = 0; iSeg < segs.size(); ++iSeg) {
addRecalc(iSeg,riSeg);
}
recalc(riSeg);
}

46
Cpu6502.h Normal file
View File

@ -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 */

18
Cpu6502Helper.cpp Normal file
View File

@ -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() {
}

21
Cpu6502Helper.h Normal file
View File

@ -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 */

View File

@ -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)

93
StateCalculator.cpp Normal file
View File

@ -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 <set>
StateCalculator::StateCalculator(Segment* VSS, Segment* VCC) : VSS(VSS), VCC(VCC) {
}
//void StateCalculator::recalcAll() {
// std::set<int> 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<Segment*> 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<Segment*>& rSeg, Segment* VSS, Segment* VCC) {
int sanity(0);
std::set<Segment*> 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<Segment*>::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<Segment*>::iterator is = c.begin(); is != c.end(); ++is) {
Segment * s(*is);
if (s->on != c.getValue()) {
s->on = c.getValue();
for (std::set<Trans*>::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);
}
}

43
StateCalculator.h Normal file
View File

@ -0,0 +1,43 @@
/*
* File: StateCalculator.h
* Author: Christopher
*
* Created on December 12, 2013, 8:29 PM
*/
#ifndef STATECALCULATOR_H
#define STATECALCULATOR_H
#include <set>
class Segment;
class Trans;
class StateCalculator {
public:
static void recalc(const std::set<Segment*>& rSeg, Segment* VSS, Segment* VCC);
static void recalc(Segment* seg, Segment* VSS, Segment* VCC);
private:
std::set<Segment*> 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<Segment*> getChanged() {
return this->segs;
}
};
#endif /* STATECALCULATOR_H */

View File

@ -36,7 +36,7 @@ public:
};
class Trans {
private:
public:
Segment* c1;
Segment* gate;
Segment* c2;

View File

@ -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[]) {