#include <iostream>
+#include <iomanip>
#include <fstream>
#include <boost/tokenizer.hpp>
#include <boost/program_options.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
#include <map>
+#include <list>
+
+#include <boost/function.hpp>
+#include <boost/functional.hpp>
+#include <boost/tuple/tuple.hpp>
#include "disasm.h"
#include "ccpu.hpp"
#include "CInstrFactory.hpp"
+#include "uint32_from_hex.hpp"
+
+#include "iext.hpp"
+#include "extensions/cprog.hpp"
+#include "extensions/cuart.hpp"
+
+#include "SReadline/SReadline.h"
+using namespace swift;
+
+#define RAM_END (0x3000)
+#define PROG_END (0x3000)
+#define REG_COUNT (16)
+
+typedef boost::function<void (const vector<string> &)> Func;
+typedef boost::tuple<string, Func, string> CompleterElement;
+
+typedef list<CompleterElement> MyCompleterContainer;
+
+class LookupFunctor
+{
+ public:
+ // Creates a functor and memorises tokens
+ LookupFunctor(const vector<string>& tokens) : Tokens(tokens) {}
+
+ // Compares the first token only
+ bool operator()(const CompleterElement& ele) const
+ {
+ return (strncmp(Tokens.begin()->c_str(), ele.get<0>().c_str(), Tokens.begin()->size()) == 0);
+ }
+
+ private:
+ const vector<string> &Tokens;
+};
+
+
+
+
+class CHelpExec
+{
+ private:
+ const MyCompleterContainer &m_completers;
+
+ public:
+ CHelpExec(const MyCompleterContainer &cont) : m_completers(cont) {}
+
+ void operator() (const vector<string>&)
+ {
+ cout << "Available commands: " << endl;
+ for(auto iter = m_completers.begin(); iter != m_completers.end(); ++iter) {
+ cout << setw(19) << setfill(' ') << (*iter).get<0>() << ": " << (*iter).get<2>() << endl;
+ }
+ }
+};
+
+void close_prog(const std::vector<std::string> &);
+
+CCpu* Iinstr::m_cpu;
+CCpu* Iext::m_cpu;
+disasm* Iinstr::m_disasm;
+disasm* Iext::m_disasm;
+
+CCpu* global_cpu = NULL;
+
+vector<CDat> breakpoints;
+
+
+#include <map>
+
+multimap<int,string> dataCommentsStore, progCommentsStore, dataLabelStore, progLabelStore;
+map<int,string> dataLineCommentStore, progLineCommentStore;
+
+bool ignoreBreak = false;
+
+bool exitProg = false;
+
+void doExit(const vector<string>&)
+{
+ exitProg = true;
+}
+
+unsigned int convertStringToNum(const std::string& in)
+{
+ if(in.substr(0,2) == "0x") {
+ return lexical_cast<uint32_from_hex>(in);
+ }
+ else {
+ return lexical_cast<unsigned int>(in);
+ }
+}
+
+
+void execStep(const vector<string>& in)
+{
+ int count = 1;
+ if(in.size() == 2) {
+ try {
+ count = convertStringToNum(in.back());
+ }
+ catch(bad_cast&) {
+ cerr << "given parameter to step is not a number" << endl;
+ }
+ }
+ while(count > 0) {
+ try {
+ auto breakp = find(breakpoints.begin(), breakpoints.end(), global_cpu->getNextPC());
+ if(breakp == breakpoints.end() || ignoreBreak) {
+ global_cpu->tick();
+ ignoreBreak = false;
+ }
+ else {
+ ignoreBreak = true;
+ cout << color(white,red) << "Breakpoint" << color(white,black) << " 0x" << std::hex << setw(8) << setfill('0') << *breakp << std::hex << " hit" << endl;
+ break;
+ }
+ }
+ catch(std::string& e) {
+ cerr << e << endl;
+ }
+ count--;
+ }
+}
+
+void execRun(const vector<string>&)
+{
+ while(1) {
+ try {
+ auto breakp = find(breakpoints.begin(), breakpoints.end(), global_cpu->getNextPC());
+ if(breakp == breakpoints.end() || ignoreBreak) {
+ global_cpu->tick();
+ ignoreBreak = false;
+ }
+ else {
+ ignoreBreak = true;
+ cout << color(white,red) << "Breakpoint" << color(white,black) << " 0x" << std::hex << setw(8) << setfill('0') << *breakp << std::hex << " hit" << endl;
+ return;
+ }
+ }
+ catch(std::string& e) {
+ cerr << e << endl;
+ return;
+ }
+ }
+}
+
+void setPC(const vector<string>& in)
+{
+ CDat addr = 0;
+ if(in.size() == 2) {
+ try {
+ addr = convertStringToNum(in.back());
+ }
+ catch(bad_cast&) {
+ cerr << "given parameter is not a number" << endl;
+ return;
+ }
+ }
+ global_cpu->setNextPC(addr);
+ cout << "Set programcounter to 0x" << std::hex << setw(8) << setfill('0') << addr << std::dec << endl;
+}
+
+
+void printReg(const vector<string>& in)
+{
+ int i, start = 0, end = REG_COUNT-1;
+ /* Todo:
+ * 1) make 2 columns
+ */
+
+ if(in.size() >= 2) {
+ try {
+ start = convertStringToNum(in[1]);
+ if(start < 0 || start > (REG_COUNT-1)) {
+ cerr << "start is out of range" << endl;
+ return;
+ }
+ end = start;
+ }
+ catch(bad_cast&) {
+ cerr << "given parameter is not a number" << endl;
+ return;
+ }
+ }
+
+ if(in.size() >= 3) {
+ try {
+ end = convertStringToNum(in[2]);
+ if(start > end || end > (REG_COUNT-1)) {
+ cerr << "end is out of range or smaller than start" << endl;
+ return;
+ }
+ }
+ catch(bad_cast&) {
+ cerr << "given parameter is not a number" << endl;
+ return;
+ }
+ }
+
+ for(i = start; i <= end; i++) {
+ cout << setw(2) << setfill('0') << i << ": 0x";
+ cout << std::hex << setw(8) << setfill('0') << global_cpu->getRegister(i) << " ";
+ cout << std::dec << setw(10) << setfill(' ') << global_cpu->getRegister(i) << " ";
+ cout << std::dec << setw(10) << setfill(' ') << (int)global_cpu->getRegister(i) << endl;
+ }
+}
+
+void setReg(const vector<string>& in)
+{
+ int reg = 0;
+ CDat val = 0;
+
+ if(in.size() >= 3) {
+ try {
+ reg = convertStringToNum(in[1]);
+ if(reg < 0 || reg > (REG_COUNT-1)) {
+ cerr << "register is out of range" << endl;
+ return;
+ }
+
+ val = convertStringToNum(in[2]);
+
+ cout << "Setting register " << reg << " to 0x" << std::hex << setw(8) << setfill('0') << val << std::dec << endl;
+ global_cpu->setRegister(reg,val);
+ }
+ catch(bad_cast&) {
+ cerr << "given parameter is not a number" << endl;
+ return;
+ }
+ }
+}
+
+void printRAM(const vector<string>& in)
+{
+ int i, start = 0, end = 15;
+ /* Todo:
+ * 1) make 2 columns
+ */
+
+ if(in.size() >= 2) {
+ try {
+ start = convertStringToNum(in[1]);
+ if(start < 0 || start > (RAM_END-1)) {
+ cerr << "start is out of range" << endl;
+ return;
+ }
+ start = (start & (~(BYTE_COUNT-1))) / BYTE_COUNT;
+ end = start;
+ }
+ catch(bad_cast&) {
+ cerr << "given parameter is not a number" << endl;
+ return;
+ }
+ }
+
+ if(in.size() >= 3) {
+ try {
+ end = convertStringToNum(in[2]);
+ if(start > end || end > (RAM_END-1)) {
+ cerr << "end is out of range or smaller than start" << endl;
+ return;
+ }
+ if(end % BYTE_COUNT != 0) {
+ end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT)+1;
+ }
+ else {
+ end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT);
+ }
+ }
+ catch(bad_cast&) {
+ cerr << "given parameter is not a number" << endl;
+ return;
+ }
+ }
+ for(i = start*BYTE_COUNT; i <= end*BYTE_COUNT; i += BYTE_COUNT) {
+ {
+ auto range = dataLabelStore.equal_range(i);
+ for(auto iter = range.first; iter != range.second; ++iter) {
+ cout << color(yellow,black) << iter->second << ":" << color(white,black) << endl;
+ }
+ }
+ {
+ auto range = dataCommentsStore.equal_range(i);
+ for(auto iter = range.first; iter != range.second; ++iter) {
+ cout << color(blue,black) << ";" << iter->second << color(white,black) << endl;
+ }
+ }
+ cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": 0x";
+ cout << std::hex << setw(8) << setfill('0') << global_cpu->getRAM(i) << " ";
+ cout << std::dec << setw(10) << setfill(' ') << global_cpu->getRAM(i) << " ";
+ cout << std::dec << setw(10) << setfill(' ') << (int)global_cpu->getRAM(i);
+
+ auto iter = dataLineCommentStore.find(i);
+ if(iter != dataLineCommentStore.end()) {
+ cout << color(blue,black) << " ;" << iter->second << color(white,black);
+ }
+ cout << endl;
+
+ }
+}
+
+void setRam(const vector<string>& in)
+{
+ int addr = 0;
+ CDat val = 0;
+
+ if(in.size() >= 3) {
+ try {
+ addr = convertStringToNum(in[1]);
+ if(addr < 0 || addr > (RAM_END-1)) {
+ cerr << "RAM-Address is out of range" << endl;
+ return;
+ }
+
+ addr = (addr & (~(BYTE_COUNT-1))) / BYTE_COUNT;
+ val = convertStringToNum(in[2]);
+
+ addr *= BYTE_COUNT;
+
+ cout << "Setting RAM-Address 0x" << std::hex << setw(8) << setfill('0') << addr;
+ cout << " to 0x" << setw(8) << setfill('0') << val << std::dec << endl;
+ global_cpu->setRAM(addr,val);
+ }
+ catch(bad_cast&) {
+ cerr << "given parameter is not a number" << endl;
+ return;
+ }
+ }
+}
+void printPROG(const vector<string>& in)
+{
+ int i, start = 0, end = 15;
+ /* Todo:
+ * 1) make 2 columns
+ */
+
+ if(in.size() >= 2 && in[1][0] == 'c') {
+ start = global_cpu->getCurPC() / BYTE_COUNT;
+ end = start + 9;
+ }
+ else if(in.size() >= 2) {
+ try {
+ start = convertStringToNum(in[1]);
+ if(start < 0 || start > (PROG_END-1)) {
+ cerr << "start is out of range" << endl;
+ return;
+ }
+ start = (start & (~(BYTE_COUNT-1))) / BYTE_COUNT;
+ end = start;
+ }
+ catch(bad_cast&) {
+ cerr << "given parameter is not a number" << endl;
+ return;
+ }
+ }
+
+ if(in.size() >= 3) {
+ try {
+ end = convertStringToNum(in[2]);
+ if(start > end || end > (PROG_END-1)) {
+ cerr << "end is out of range or smaller than start" << endl;
+ return;
+ }
+ if(end % BYTE_COUNT != 0) {
+ end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT)+1;
+ }
+ else {
+ end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT);
+ }
+
+ }
+ catch(bad_cast&) {
+ cerr << "given parameter is not a number" << endl;
+ return;
+ }
+ }
+
+
+ for(i = start*BYTE_COUNT; i <= end*BYTE_COUNT; i += BYTE_COUNT) {
+ {
+ auto range = progLabelStore.equal_range(i);
+ for(auto iter = range.first; iter != range.second; ++iter) {
+ cout << color(yellow,black) << iter->second << ":" << color(white,black) << endl;
+ }
+ }
+ {
+ auto range = progCommentsStore.equal_range(i);
+ for(auto iter = range.first; iter != range.second; ++iter) {
+ cout << color(blue,black) << ";" << iter->second << color(white,black) << endl;
+ }
+ }
+
+ Iinstr* pi = global_cpu->getProg(i);
+ if(pi == NULL) {
+ cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": NOP";
+ }
+ else {
+ cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": " << std::dec << global_cpu->colorifyInstr(pi->toString());
+ }
+ auto iter = progLineCommentStore.find(i);
+ if(iter != progLineCommentStore.end()) {
+ cout << color(blue,black) << " ;" << iter->second << color(white,black);
+ }
+ cout << endl;
+ }
+}
+
+void setBreak(const vector<string>& in)
+{
+ unsigned int addr = 0;
+ if(in.size() == 2) {
+ try {
+ addr = convertStringToNum(in.back());
+ breakpoints.push_back(addr);
+ cout << "Breakpoint 0x" << std::hex << setw(8) << setfill('0') << addr << std::dec << " set" << endl;
+ }
+ catch(bad_cast&) {
+ cerr << "Given parameter is not a valid address" << endl;
+ }
+ }
+ else {
+ cerr << "Invalid parameter count!" << endl;
+ }
+}
+
+void listBreaks(const vector<string>&)
+{
+ for(auto iter = breakpoints.begin(); iter != breakpoints.end(); ++iter) {
+ cout << "Breakpoint at 0x" << std::hex << setw(8) << setfill('0') << *iter << std::dec << endl;
+ }
+}
+
+void getPerf(const vector<string>&)
+{
+ cout << "current perfcounter is " << std::dec << global_cpu->getPerf() << endl;
+}
+
+void resetPerf(const vector<string>&)
+{
+ cout << "reset perfcounter" << endl;
+ global_cpu->setPerf(0);
+}
+
+void applyToExtensions(const vector<string>& in)
+{
+ global_cpu->applyToExtensions(in);
+}
+
+
+void printStatus(const vector<string>&)
+{
+ CDat stackp = global_cpu->getStack();
+ CDat stackd = global_cpu->getRAM(stackp);
+ cout << "Stack pointer: 0x" << std::hex << setw(8) << setfill('0') << stackp << " @stackpointer: 0x" << setw(8) << stackd << std::dec << " (" << stackd << ")" << endl;
+ cout << "PSW: 0x" << std::hex << setw(8) << setfill('0') << global_cpu->getFlags() << std::dec << endl;
+ cout << "cur PC: 0x" << std::hex << setw(8) << setfill('0') << global_cpu->getCurPC() << " next PC: 0x" << setw(8) << setfill('0') << global_cpu->getNextPC() << std::dec << endl;
+
+}
using boost::lexical_cast;
using boost::bad_lexical_cast;
exit(EXIT_FAILURE);
}
+ CCpu cpu(REG_COUNT, RAM_END, PROG_END);
- CCpu cpu;
+ global_cpu = &cpu;
+ Iinstr::setCPU(&cpu);
+ Iext::setCPU(&cpu);
+ disasm disasm(instr);
+
+ Iinstr::setDisasm(&disasm);
+ Iext::setDisasm(&disasm);
+
+ global_cpu->registerExtension(new Cprog());
+ global_cpu->registerExtension(new Cuart());
+
+ vector<string> commentDefer;
+ vector<string> labelDefer;
std::string str = "";
int addr = 0;
boost::char_separator<char> sep(";", "", boost::keep_empty_tokens);
boost::tokenizer<boost::char_separator<char> > tokens(str, sep);
- disasm disasm(instr);
while(getline(inFile, str)) {
int count = 0;
tokens.assign(str);
cout << endl;
}
switch(type) {
- case 2:
+ case 0:
if(count == 1) {
- cout << "; ";
+ try {
+ addr = lexical_cast<uint32_from_hex>(*tok_iter);
+ for(unsigned int i = 0; i < commentDefer.size(); i++) {
+ dataCommentsStore.insert(pair<int,string>(addr, commentDefer.at(i)));
+ }
+ for(unsigned int i = 0; i < labelDefer.size(); i++) {
+ dataLabelStore.insert(pair<int,string>(addr, labelDefer.at(i)));
+ }
+
+ commentDefer.clear();
+ labelDefer.clear();
+ }
+ 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);
+ }
+ }
+ else if(count == 4) {
+ if((*tok_iter).size() > 0) {
+ dataLabelStore.insert(pair<int,string>(addr, *tok_iter));
+ }
+ }
+ else if(count == 5) {
+ if((*tok_iter).size() > 0) {
+ dataLineCommentStore.insert(pair<int,string>(addr, *tok_iter));
}
- cout << *tok_iter << ":";
}
break;
case 1:
if(count == 1) {
- out << "[0x" << *tok_iter << "]: ";
- addr = lexical_cast<int>(*tok_iter);
+ try {
+ addr = lexical_cast<uint32_from_hex>(*tok_iter);
+ for(unsigned int i = 0; i < commentDefer.size(); i++) {
+ progCommentsStore.insert(pair<int,string>(addr, commentDefer.at(i)));
+ }
+ for(unsigned int i = 0; i < labelDefer.size(); i++) {
+ progLabelStore.insert(pair<int,string>(addr, labelDefer.at(i)));
+ }
+
+ commentDefer.clear();
+ labelDefer.clear();
+ }
+ catch(bad_lexical_cast& e) {
+ cerr << e.what() << endl;
+ exit(EXIT_FAILURE);
+ }
}
else if(count == 2) {
- cpu.setProg(addr, disasm.decode(*tok_iter));
- }
- else if(count == 3) {
- //code saved in hex-file
- //cout << *tok_iter ;
+ Iinstr *pi = disasm.decode(*tok_iter);
+ cpu.setProg(addr, pi);
}
else if(count == 4) {
- /* label */
if((*tok_iter).size() > 0) {
- cout << *tok_iter << ":" << endl;
+ progLabelStore.insert(pair<int,string>(addr, *tok_iter));
}
- cout << out.str();
}
else if(count == 5) {
if((*tok_iter).size() > 0) {
- cout << " ;";
+ progLineCommentStore.insert(pair<int,string>(addr, *tok_iter));
}
}
- if(count >= 5) {
- cout << *tok_iter;
+ break;
+ case 2:
+ if((*tok_iter).size() > 0) {
+ commentDefer.push_back(*tok_iter);
+ }
+ break;
+ case 3:
+ if((*tok_iter).size() > 0) {
+ labelDefer.push_back(*tok_iter);
}
break;
default:
}
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,0x66334455);
+ 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,500);
+
+ SReadline Reader;
+
+ MyCompleterContainer Completers;
+
+ CHelpExec HelpExec(Completers);
+
+ Completers.push_back(CompleterElement("help", boost::bind1st( boost::mem_fun( &CHelpExec::operator()), &HelpExec), "Prints this message"));
+ Completers.push_back(CompleterElement("quit", &doExit, "Exits program"));
+ Completers.push_back(CompleterElement("exit", &doExit, "Exits program"));
+ Completers.push_back(CompleterElement("step [count]",&execStep, "Runs [count] ticks. if count is not given one tick is executed."));
+ Completers.push_back(CompleterElement("dreg [s] [e]",&printReg, "Prints registers. if s is given, only register s is printed. if s and e are given the registers from s to e are printed. if omitted all registers a printed."));
+ Completers.push_back(CompleterElement("ddata [s] [e]",&printRAM, "Prints RAM. if s is given, only RAM-Addr. s is printed. if s and e are given the RAM-Addrs from s to e are printed. if omitted the first 16 RAM-Addrs are printed."));
+ Completers.push_back(CompleterElement("dprog [s] [e]",&printPROG, "Prints program. if s is given, only Prog-Addr. s is printed. if s and e are given the Prog-Addrs from s to e are printed. if omitted the first 16 Prog-Addrs are printed."));
+ Completers.push_back(CompleterElement("break addr",&setBreak, "Sets a breakpoint for address addr."));
+ Completers.push_back(CompleterElement("listbreaks",&listBreaks, "Lists all breakpoints."));
+ Completers.push_back(CompleterElement("run",&execRun, "Runs till next breakpoint or end of program."));
+ Completers.push_back(CompleterElement("setpc [num]",&setPC, "Sets PC to num. if num is omitted 0 is used."));
+ Completers.push_back(CompleterElement("setreg [s] [num]",&setReg, "Sets Register s to num."));
+ Completers.push_back(CompleterElement("setdata [s] [num]",&setRam, "Sets RAM-Addr s to num."));
+ Completers.push_back(CompleterElement("status",&printStatus, "Prints status of CPU."));
+ Completers.push_back(CompleterElement("getperf",&getPerf, "Prints performance counter."));
+ Completers.push_back(CompleterElement("resetperf",&resetPerf, "Resets performance counter to 0."));
+ Completers.push_back(CompleterElement("extension",&applyToExtensions, "Write to extensions."));
+ Reader.RegisterCompletions(Completers);
+
+ string UserInput;
+ vector<string> Tokens, lastTokens;
+ bool EndOfInput = false;
+
+ //tilab g++44 doesn't like auto here
+ MyCompleterContainer::iterator Found(Completers.end());
+
+ Func lastFunc = NULL;
+
+
+ while(!exitProg) {
+ UserInput = Reader.GetLine("> ", Tokens, EndOfInput);
+ if(EndOfInput) {
+ break;
+ }
+
+ if(!Tokens.empty()) {
+ Found = find_if(Completers.begin(), Completers.end(), LookupFunctor(Tokens));
+
+ if(Found != Completers.end()) {
+ if((*Found).get<1>() != 0) {
+ lastFunc = (*Found).get<1>();
+ lastFunc(Tokens);
+ lastTokens = Tokens;
+ //(*Found).get<1>()(Tokens);
+ }
+ }
+ else {
+ lastFunc = NULL;
+ cout << "Unknown command. 'help' displays help" << endl;
+ }
+ }
+ else {
+ if(lastFunc != NULL) {
+ lastFunc(lastTokens);
+ }
+ else {
+ cout << "Unknown command. 'help' displays help" << endl;
+ }
+ }
+ }
+
+
+/*
+ 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;
}