ins ('32', 'jumpop', 'Branch/ret operation', '4 | 5 | 16 | 3 | 2 | 1 | 1',
'Conditions | OpCode (10110) | Immediate | - | Type | +/- | S',
'This instruction should be used with it\'s aliases branch, call, ret and reti. No flags will be affected by this instructions.','','',
-'branch-Branch relative-4/00|call-Branch relative and save pc to stack-4/01|ret-Return to adress on stack-4/10|ret-Return from interrupt to adress on stack-4/11');
+'br-Branch relative-4/00|call-Branch relative and save pc to stack-4/01|ret-Return to adress on stack-4/10|ret-Return from interrupt to adress on stack-4/11');
ins ('32', 'branchreg', 'Branch; jump to value of reg', '4 | 5 | 4 | 16 | 1 | 1 | 1',
'Conditions | OpCode (10111) | Register A | - | Type | +/- | -',
--- /dev/null
+../3c_disasm/CInstrFactory.cpp
\ No newline at end of file
--- /dev/null
+../3c_disasm/CInstrFactory.hpp
\ No newline at end of file
--- /dev/null
+../3c_disasm/Iinstr.hpp
\ No newline at end of file
void CCpu::tick()
{
+ // signal extensions
+ // Todo
+
m_pc = m_pc_next;
m_pc_next += 4;
+ Iinstr* instr = this->getProg(m_pc);
+ if(instr == NULL) {
+ throw string("Out of Instructions!");
+ }
+ if(this->conditionMet(instr->getCondition())) {
+ instr->execInstr();
+ }
+}
+
+bool CCpu::conditionMet(short cond)
+{
+ switch(cond) {
+ case NOT_EQUAL:
+ return !this->m_Z;
+ break;
+ case EQUAL:
+ return this->m_Z;
+ break;
+ case NOT_OVERFLOW:
+ return !this->m_O;
+ break;
+ case OVER_FLOW:
+ return this->m_O;
+ break;
+ case NOT_CARRY:
+ return !this->m_C;
+ break;
+ case CARRY:
+ return this->m_C;
+ break;
+ case NOT_SIGNED:
+ return !this->m_S;
+ break;
+ case SIGNED:
+ return this->m_S;
+ break;
+ case ABOVE:
+ return (!this->m_C && !this->m_Z);
+ break;
+ case BELOW_EQ:
+ return (this->m_C || this->m_Z);
+ break;
+ case GREATER_EQ:
+ return (this->m_S == this->m_O);
+ break;
+ case LESS:
+ return (this->m_S != this->m_O);
+ break;
+ case GREATER:
+ return (!this->m_Z && (this->m_S == this->m_O));
+ break;
+ case LESS_EQ:
+ return (!this->m_Z || (this->m_S != this->m_O));
+ break;
+ case ALWAYS:
+ return true;
+ break;
+ case NEVER:
+ return false;
+ break;
+ default:
+ cerr << "What did you do? more than 16 values in 5 bits?!" << endl;
+ return false;
+ }
+
+}
+
+CDat CCpu::getCurPC() const
+{
+ return m_pc;
}
-CDat CCpu::getNextPC() const
+void CCpu::setNextPC(CDat val)
{
- return m_pc_next;
+ m_pc_next = val;
}
+void CCpu::updateFlags(CDat val) {
+ this->m_Z = (val == 0);
+ this->m_S = ((val >> (BIT_LEN-1)) & 0x1);
+ this->m_C = false;
+ this->m_O = false;
+}
+
+void CCpu::updateFlags(bool z, bool o, bool c, bool s)
+{
+ this->m_Z = z;
+ this->m_O = o;
+ this->m_C = c;
+ this->m_S = s;
+}
+
+CDat CCpu::getRegister(const int addr) const
+{
+ return m_reg.get(addr);
+}
-// CDat getRegister(const short) const {};
-// void setRegister(const short, CDat&) {};
+void CCpu::setRegister(const int addr, CDat data)
+{
+ m_reg.set(addr, data);
+}
-// CDat getRAM(const short) const {};
-// void setRAM(const short, CDat&) {};
+CDat CCpu::getRAM(const int addr) const
+{
+ return m_ram.get(addr);
+}
+void CCpu::setRAM(const int addr, CDat data)
+{
+ m_ram.set(addr, data);
+}
void CCpu::setProg(int addr, Iinstr* instr)
{
m_prog.set(addr, instr);
}
-CCpu::CCpu() : m_pc(0), m_pc_next(0), m_regfile(0), m_ram(0), m_prog(0)
+Iinstr* CCpu::getProg(const int addr) const
+{
+ return m_prog.get(addr);
+}
+
+int CCpu::getStack() const
+{
+ return this->m_stack;
+}
+
+void CCpu::setStack(const int val)
+{
+ this->m_stack = val;
+}
+
+CCpu::CCpu(int regs, int ram, int prog) : m_Z(false), m_S(false), m_C(false), m_O(false), m_pc(0), m_pc_next(0), m_reg(regs), m_ram(ram), m_prog(prog), m_stack(0)
{
}
-
-
#ifndef __CPU__H__
#define __CPU__H__
#include "cdat.hpp"
#include "cmem.hpp"
#include "cpmem.hpp"
+
+class Iinstr;
+
#include "Iinstr.hpp"
+
class CCpu {
private:
+ bool m_Z, m_S, m_C, m_O;
+
CDat m_pc, m_pc_next;
- CMem<CDat> m_regfile, m_ram;
+ CMem<CDat> m_reg, m_ram;
CPMem<Iinstr*> m_prog;
+ CDat m_stack;
+
public:
void registerExtension() {};
void tick();
CDat getRegister(const int) const;
- void setRegister(const int, CDat&);
+ void setRegister(const int, CDat);
CDat getRAM(const int) const;
- void setRAM(const int, CDat&);
+ void setRAM(const int, CDat);
Iinstr* getProg(const int) const;
void setProg(const int, Iinstr*);
- CDat getNextPC() const;
+ CDat getCurPC() const;
+ void setNextPC(CDat);
+
+ void updateFlags(CDat);
+ void updateFlags(bool z, bool o, bool c, bool s);
+
+ bool conditionMet(short);
+
+ int getStack() const;
+ void setStack(const int);
- CCpu();
+ CCpu(int,int,int);
};
typedef int CDat;
-static_assert(sizeof(CDat) == 4, "The size of the datatype for int is NOT 4 bytes (32 Bit!)");
+#define BIT_LEN 32
+
+//static_assert(sizeof(CDat) == 4, "The size of the datatype for int is NOT 4 bytes (32 Bit!)");
#endif
using namespace std;
-template <class T>
+template <typename T>
void CMem<T>::set(const MEMORY_ADDRESS address, const T& data)
{
if(address >= MAX_MEMORY) {
m_memory.erase(iter);
}
-template <class T>
-void CMem<T>::get(const MEMORY_ADDRESS address, T& value) const
+template <typename T>
+T CMem<T>::get(const MEMORY_ADDRESS address) const
{
if(address >= MAX_MEMORY) {
stringstream error;
error << "memoryaddress " << address << " out of range";
throw out_of_range(error.str());
}
- value = m_memory[address];
+ return m_memory[address];
}
+
+
+template class CMem<int>;
#include <vector>
#include <stdexcept>
+
typedef int MEMORY_ADDRESS;
+
/**
* Name: CMem
* Purpose: Class representing the memory of our emulated machine
*/
-template <class T>
+template <typename T>
class CMem
{
private:
const int MAX_MEMORY;
std::vector<T> m_memory;
public:
- //wert aus referenz auslesen und in vetor speichern (index zugriff!)
- //address 0 ist ProgramCounter
void set(const MEMORY_ADDRESS address, const T& data);
- //retuniert referenz eines cdat objekts mit dem Wert von address
- void get(const MEMORY_ADDRESS address, T& data) const;
+ T get(const MEMORY_ADDRESS address) const;
CMem(int size) : MAX_MEMORY(size), m_memory(size) {};
};
--- /dev/null
+
+//i'm sorry
+//pervert forwarding
+//didn't know (or was to lazy) to find another fix
+#define __CPU__H__
+class CCpu;
+
+#include "cpmem.hpp"
+
+using namespace std;
+
+template <typename T>
+void CPMem<T>::set(const MEMORY_ADDRESS address, const T data)
+{
+ if(address >= MAX_MEMORY) {
+ stringstream error;
+ error << "memoryaddress " << address << " out of range";
+ throw out_of_range(error.str());
+ }
+
+ MEMORY_ADDRESS temp = address;
+ auto iter = m_memory.begin();
+ while(temp > 0) {
+ ++iter;
+ temp--;
+ }
+
+ iter = m_memory.insert(iter, data);
+ ++iter;
+ m_memory.erase(iter);
+}
+
+template <typename T>
+T CPMem<T>::get(const MEMORY_ADDRESS address) const
+{
+ if(address >= MAX_MEMORY) {
+ stringstream error;
+ error << "memoryaddress " << address << " out of range";
+ throw out_of_range(error.str());
+ }
+ return m_memory[address];
+}
+
+template <typename T>
+CPMem<T>::~CPMem()
+{
+ for(auto iter = m_memory.begin(); iter != m_memory.end(); ++iter) {
+ delete (*iter);
+ }
+}
+
+
+template class CPMem<Iinstr*>;
--- /dev/null
+#ifndef __CPMEM_H__
+#define __CPMEM_H__
+
+template <typename T>
+class CPMem;
+
+#include "cdat.hpp"
+#include <vector>
+#include <stdexcept>
+#include <stdlib.h>
+
+#include "Iinstr.hpp"
+
+typedef int MEMORY_ADDRESS;
+
+/**
+ * Name: CMem
+ * Purpose: Class representing the memory of our emulated machine
+ */
+template <typename T>
+class CPMem
+{
+private:
+ //MAX_MEMORY-1 zugreifbare Speicherzellen
+ const int MAX_MEMORY;
+ std::vector<T> m_memory;
+public:
+ //wert aus referenz auslesen und in vetor speichern (index zugriff!)
+ //address 0 ist ProgramCounter
+ void set(const MEMORY_ADDRESS address, const T data);
+ //retuniert referenz eines cdat objekts mit dem Wert von address
+ T get(const MEMORY_ADDRESS address) const;
+ CPMem(int size) : MAX_MEMORY(size), m_memory(size, NULL) {};
+ ~CPMem();
+};
+
+#endif
--- /dev/null
+../3c_disasm/disasm.cpp
\ No newline at end of file
--- /dev/null
+../3c_disasm/disasm.h
\ No newline at end of file
--- /dev/null
+../3c_disasm/instr
\ No newline at end of file
#include "disasm.h"
#include "ccpu.hpp"
#include "CInstrFactory.hpp"
+#include "uint32_from_hex.hpp"
+
+CCpu* Iinstr::m_cpu;
using boost::lexical_cast;
using boost::bad_lexical_cast;
}
- CCpu cpu;
+ CCpu cpu(16,1000,1000);
+
+ Iinstr::setCPU(&cpu);
std::string str = "";
cout << endl;
}
switch(type) {
- case 2:
+ case 0:
if(count == 1) {
- cout << "; ";
+ try {
+ addr = lexical_cast<uint32_from_hex>(*tok_iter);
+ }
+ catch(bad_lexical_cast& e) {
+ cerr << e.what() << endl;
+ exit(EXIT_FAILURE);
+ }
}
- cout << *tok_iter;
- break;
- case 3:
- if((*tok_iter).size() > 0) {
- if(count > 1) {
- cout << endl;
+ else if(count == 2) {
+ try {
+ CDat data = lexical_cast<uint32_from_hex>(*tok_iter);
+ cpu.setRAM(addr, data);
+ }
+ catch(bad_lexical_cast& e) {
+ cerr << e.what() << endl;
+ exit(EXIT_FAILURE);
}
- cout << *tok_iter << ":";
}
break;
case 1:
if(count == 1) {
- out << "[0x" << *tok_iter << "]: ";
- addr = lexical_cast<int>(*tok_iter);
- }
- else if(count == 2) {
- cpu.setProg(addr, disasm.decode(*tok_iter));
- }
- else if(count == 3) {
- //code saved in hex-file
- //cout << *tok_iter ;
- }
- else if(count == 4) {
- /* label */
- if((*tok_iter).size() > 0) {
- cout << *tok_iter << ":" << endl;
+ try {
+ addr = lexical_cast<uint32_from_hex>(*tok_iter);
}
- cout << out.str();
- }
- else if(count == 5) {
- if((*tok_iter).size() > 0) {
- cout << " ;";
+ catch(bad_lexical_cast& e) {
+ cerr << e.what() << endl;
+ exit(EXIT_FAILURE);
}
}
-
- if(count >= 5) {
- cout << *tok_iter;
+ else if(count == 2) {
+ Iinstr *pi = disasm.decode(*tok_iter);
+ cpu.setProg(addr, pi);
}
break;
+ case 2:
+ case 3:
+ cerr << "ignoring labels and comments for now" << endl;
default:
cerr << "i was to lazy to implement the other format types for now" << endl;
}
count++;
}
- if(type == 1 && count <= 4) {
- cout << out.str();
- }
- cout << endl;
}
inFile.close();
cout << endl;
+
+
+ for(int i = 0; i <= 32; i += 4) {
+ Iinstr *pinstr = cpu.getProg(i);
+ if(pinstr != NULL) {
+ cout << i << " : " << std::hex << i << std::dec << " " << pinstr->toString() << endl;
+ }
+ else {
+ cout << "Null at " << i << " : " << std::hex << i << endl;
+ }
+ }
+
+ for(int i = 0; i <= 32; i += 4) {
+ CDat data = cpu.getRAM(i);
+ cout << i << " : " << std::hex << i << std::dec << " " << data << endl;
+ }
+
+ cpu.setRegister(1, 4);
+ cpu.setRegister(2, 0);
+ cpu.setRAM(0,5);
+ cpu.setRAM(4,50);
+ cpu.setRAM(8,32);
+ cpu.setRAM(12,45);
+
+ // following: job of the bootloader
+ //set stackpointer
+ cpu.setStack(500);
+ //set return to nowhere for ret
+ cpu.setRAM(500,50);
+
+ for(int i = 0; ; i++) {
+ try {
+ cpu.tick();
+ cout << " reg0: " << cpu.getRegister(0) << " reg1: " << cpu.getRegister(1);
+ cout << " reg2: " << cpu.getRegister(2) << " reg3: " << cpu.getRegister(3);
+ cout << " reg4: " << cpu.getRegister(4) << " reg5: " << cpu.getRegister(5);
+ cout << endl << endl;
+
+ }
+ catch(string& e) {
+ cerr << e << endl;
+ break;
+ }
+ }
+
return EXIT_SUCCESS;
}
--- /dev/null
+../3c_disasm/uint32_from_hex.hpp
\ No newline at end of file
return m_files.size();
}
+void CInstrFactory::loadLibsIntoMap(map<short, Iinstr*>& instr, string dir)
+{
+#ifdef DEBUG
+ cout << "Loaded " << this->searchLibsInDir(dir) << " Libraryfiles" << endl;
+#else
+ this->searchLibsInDir(dir);
+#endif
+ while(this->getNumFiles() >= 1) {
+ Iinstr* pinstr = this->getNextInstr();
+ instr.insert(make_pair(pinstr->getOpcode(),pinstr));
+#ifdef DEBUG
+ cout << "found: " << pinstr->getName() << " its opcode is : " << pinstr->getOpcode() << endl;
+#endif
+ }
+}
+
+
/**
* Name: ~CInstrFactory
* Purpose: Destructor of the Object
Iinstr* getNextInstr();
size_t getNumFiles();
size_t searchLibsInDir(std::string dir);
+ void loadLibsIntoMap(map<short, Iinstr*>& instr, string dir);
CInstrFactory() : m_libStore(), m_files() {};
~CInstrFactory();
};
+#ifndef __IINSTR_I_
+#define __IINSTR_I_
+
#include <string>
#include <boost/dynamic_bitset.hpp>
#include <iostream>
#include <sstream>
-#ifndef __IINSTR_I_
-#define __IINSTR_I_
+class CCpu;
+
+#include "ccpu.hpp"
+
/* concept from https://groups.google.com/group/comp.arch.embedded/msg/9d430b6d3da12c8f */
#define to_HEX__(x) 0x##x##LU
+((x & 0xF0000UL) ? 16 : 0)
#define B5(x) ((unsigned char)to_B5__(to_HEX__(x)))
+/* end concept */
using namespace std;
using namespace boost;
return bits.to_ulong();
}
+ static CCpu* m_cpu;
+
public:
+
+ static void setCPU(CCpu* cpu) { m_cpu = cpu; }
+
virtual ~Iinstr() {}
virtual short getOpcode() { return this->opcode; }
virtual std::string getName() { return this->name; }
virtual void evalInstr() = 0;
virtual void execInstr() = 0;
virtual std::string toString() = 0;
+ virtual Iinstr* getNew() = 0;
+
+ short getCondition() {
+ return m_cond;
+ }
void decodeCondition(short condition) {
if(condition >= 0 && condition <= 15) {
}
protected:
+
std::string getConditionFlag()
{
stringstream cond;
return cond.str();
}
};
+
#endif
CInstrFactory instrFab;
try {
-#ifdef DEBUG
- cout << "Loaded " << instrFab.searchLibsInDir(dir) << " Libraryfiles" << endl;
-#else
- instrFab.searchLibsInDir(dir);
-#endif
- while(instrFab.getNumFiles() >= 1) {
- Iinstr* pinstr = instrFab.getNextInstr();
- instr.insert(make_pair(pinstr->getOpcode(),pinstr));
-#ifdef DEBUG
- cout << "found: " << instr->getName() << " its opcode is : " << instr->getOpcode() << endl;
-#endif
- }
+ instrFab.loadLibsIntoMap(instr, dir);
}
catch(std::bad_alloc& e) {
cerr << progName << ": bad_alloc caught " << e.what() << endl;
out << "[0x" << *tok_iter << "]: ";
}
else if(count == 2) {
- out << disasm.decode(*tok_iter);
+ out << disasm.decodeToString(*tok_iter);
}
else if(count == 3) {
//code saved in hex-file
using namespace boost;
-std::string disasm::decode(std::string str)
+Iinstr* disasm::decode(std::string str)
{
/* we need 0x prefix */
string hex = "0x";
instr->decodeCondition(condition.to_ulong());
instr->loadBits(args);
instr->evalInstr();
- return instr->toString();
+ return instr;
}
catch(std::string &e) {
cerr << " Error: " << e << endl;
}
- return "";
+ return NULL;
+}
+
+std::string disasm::decodeToString(std::string str)
+{
+ return this->decode(str)->toString();
}
Iinstr* disasm::decodeOpcode(short opcode)
{
auto iter = instrs.find(opcode);
if(iter != instrs.end()) {
- return iter->second;
+ Iinstr* p = (iter->second)->getNew();
+ return p;
}
else {
stringstream err;
#include <string>
#include <map>
+#include "uint32_from_hex.hpp"
#include "Iinstr.hpp"
using namespace std;
private:
std::map<short,Iinstr*> instrs;
- class uint32_from_hex // For use with boost::lexical_cast
- {
- typedef unsigned int uint32;
- uint32 value;
- public:
- operator uint32() const {
- return value;
- }
- friend std::istream& operator>>(std::istream& in, uint32_from_hex& outValue)
- {
- in >> std::hex >> outValue.value;
- return in;
- }
- };
-
protected:
void decodeCondition(short);
Iinstr* decodeOpcode(short);
public:
disasm(std::map<short,Iinstr*> map) : instrs(map) {};
- std::string decode(std::string);
+ Iinstr* decode(std::string);
+ std::string decodeToString(std::string str);
};
void evalInstr();
void execInstr();
std::string toString();
+ Iinstr* getNew();
};
/**
return new Cadd();
}
+Iinstr* Cadd::getNew() {
+ return new Cadd();
+}
+
/**
* Name: destroy_instruction
* Purpose: if compiled as shared library, this functions destoys the
void Cadd::execInstr()
{
- cout << "should exec" << this->toString() << endl;
+ cout << "should exec " << this->toString() << endl;
+ CDat val = this->m_cpu->getRegister(m_ra) + this->m_cpu->getRegister(m_rb);
+ this->m_cpu->setRegister(m_rd, val);
+ this->m_cpu->updateFlags(val);
}
std::string Cadd::toString()
void evalInstr();
void execInstr();
std::string toString();
+ Iinstr* getNew();
};
/**
return new Caddi();
}
+Iinstr* Caddi::getNew() {
+ return new Caddi();
+}
+
+
/**
* Name: destroy_instruction
* Purpose: if compiled as shared library, this functions destoys the
void Caddi::execInstr()
{
cout << "should exec " << this->toString() << endl;
+ CDat reg = this->m_cpu->getRegister(m_ra) + this->m_imm;
+ this->m_cpu->setRegister(m_rd, reg);
+ this->m_cpu->updateFlags(reg);
}
std::string Caddi::toString()
void evalInstr();
void execInstr();
std::string toString();
+ Iinstr* getNew();
};
/**
return new Cbranch();
}
+Iinstr* Cbranch::getNew()
+{
+ return new Cbranch();
+}
/**
* Name: destroy_instruction
* Purpose: if compiled as shared library, this functions destoys the
type.resize(2);
this->m_typ = type.to_ulong();
- switch(m_typ) {
+ switch(this->m_typ) {
case 0:
- this->name = "branch";
+ this->name = "br";
break;
case 1:
this->name = "call";
void Cbranch::execInstr()
{
- cout << "should exec" << this->toString() << endl;
+ cout << "should exec " << this->toString() << endl;
+ CDat pc = this->m_cpu->getCurPC();
+ switch(this->m_typ) {
+ case 1:
+ {
+ CDat sp = this->m_cpu->getStack();
+ this->m_cpu->setRAM(sp, pc);
+ sp -= 4;
+ this->m_cpu->setStack(sp);
+ }
+ case 0:
+ this->m_cpu->setNextPC(pc+this->m_imm);
+ break;
+ case 2:
+ case 3:
+ this->m_cpu->setNextPC(this->m_cpu->getRAM(this->m_cpu->getStack()));
+ this->m_cpu->setStack(this->m_cpu->getStack()+4);
+ break;
+ default:
+ // nothing
+ this->m_cpu->setNextPC(400);
+ }
}
std::string Cbranch::toString()
void evalInstr();
void execInstr();
std::string toString();
+ Iinstr* getNew();
};
/**
return new Cldi();
}
+Iinstr* Cldi::getNew()
+{
+ return new Cldi();
+}
/**
* Name: destroy_instruction
* Purpose: if compiled as shared library, this functions destoys the
void Cldi::execInstr()
{
cout << "should exec " << this->toString() << endl;
+ this->m_cpu->setRegister(this->m_rd, this->m_imm);
}
std::string Cldi::toString()
void evalInstr();
void execInstr();
std::string toString();
+ Iinstr* getNew();
};
/**
return new Cldw();
}
+Iinstr* Cldw::getNew()
+{
+ return new Cldw();
+}
+
/**
* Name: destroy_instruction
* Purpose: if compiled as shared library, this functions destoys the
void Cldw::execInstr()
{
cout << "should exec " << this->toString() << endl;
+ CDat val = this->m_cpu->getRegister(this->m_ra);
+ val += m_imm;
+ val = this->m_cpu->getRAM(val);
+ this->m_cpu->setRegister(this->m_rd,val);
}
std::string Cldw::toString()
void evalInstr();
void execInstr();
std::string toString();
+ Iinstr* getNew();
};
/**
return new Csubi();
}
+Iinstr* Csubi::getNew() {
+ return new Csubi();
+}
+
/**
* Name: destroy_instruction
* Purpose: if compiled as shared library, this functions destoys the
void Csubi::execInstr()
{
cout << "should exec " << this->toString() << endl;
+ CDat reg = this->m_cpu->getRegister(m_ra) - this->m_imm;
+ this->m_cpu->setRegister(m_rd, reg);
+ this->m_cpu->updateFlags(reg);
}
std::string Csubi::toString()
--- /dev/null
+#ifndef __UINT32_FROM_HEX_H__
+#define __UINT32_FROM_HEX_H__
+
+class uint32_from_hex // For use with boost::lexical_cast
+{
+ typedef unsigned int uint32;
+ uint32 value;
+ public:
+ operator uint32() const {
+ return value;
+ }
+ friend std::istream& operator>>(std::istream& in, uint32_from_hex& outValue)
+ {
+ in >> std::hex >> outValue.value;
+ return in;
+ }
+};
+
+#endif