X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=3b_sim%2Fsim.cpp;h=d93e11e44be4c717c9f4a809dcf15907a0465535;hb=483917f105857e85af8c6959b8ee533fc6561bc2;hp=9d2fb5a00d259c23ce42cd930958fdb166f2e9c4;hpb=12d2a7c14a42e01b6caf2a097db32404a403d213;p=calu.git diff --git a/3b_sim/sim.cpp b/3b_sim/sim.cpp index 9d2fb5a..d93e11e 100644 --- a/3b_sim/sim.cpp +++ b/3b_sim/sim.cpp @@ -1,17 +1,483 @@ #include +#include #include #include #include #include #include #include +#include + +#include +#include +#include #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 + +#include "SReadline/SReadline.h" +using namespace swift; + +#define RAM_END (0x3000) +#define PROG_END (0x3000) +#define REG_COUNT (16) + +typedef boost::function &)> Func; +typedef boost::tuple CompleterElement; + +typedef list MyCompleterContainer; + +class LookupFunctor +{ + public: + // Creates a functor and memorises tokens + LookupFunctor(const vector& 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 &Tokens; +}; + + + + +class CHelpExec +{ + private: + const MyCompleterContainer &m_completers; + + public: + CHelpExec(const MyCompleterContainer &cont) : m_completers(cont) {} + + void operator() (const vector&) + { + 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 &); + CCpu* Iinstr::m_cpu; +CCpu* Iext::m_cpu; +disasm* Iinstr::m_disasm; +disasm* Iext::m_disasm; + +CCpu* global_cpu = NULL; + +vector breakpoints; + + +#include + +multimap dataCommentsStore, progCommentsStore, dataLabelStore, progLabelStore; +map dataLineCommentStore, progLineCommentStore; + +bool ignoreBreak = false; + +bool exitProg = false; + +void signalCpuBreak(int) +{ + global_cpu->breakNext(); +} + +void doExit(const vector&) +{ + exitProg = true; +} + +unsigned int convertStringToNum(const std::string& in) +{ + if(in.substr(0,2) == "0x") { + return lexical_cast(in); + } + else { + return lexical_cast(in); + } +} + + +void execStep(const vector& 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&) +{ + while(1) { + try { + auto breakp = find(breakpoints.begin(), breakpoints.end(), global_cpu->getNextPC()); + if((breakp == breakpoints.end() || ignoreBreak) && !global_cpu->shouldBreak() ) { + 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& 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& 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& 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& 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& 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& 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& 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&) +{ + 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&) +{ + cout << "current perfcounter is " << std::dec << global_cpu->getPerf() << endl; +} + +void resetPerf(const vector&) +{ + cout << "reset perfcounter" << endl; + global_cpu->setPerf(0); +} + +void applyToExtensions(const vector& in) +{ + global_cpu->applyToExtensions(in); +} + + +void printStatus(const vector&) +{ + 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; @@ -84,17 +550,28 @@ int main(int argc, char* argv[]) exit(EXIT_FAILURE); } + CCpu cpu(REG_COUNT, RAM_END, PROG_END); - CCpu cpu(16,1000,1000); + global_cpu = &cpu; + signal(SIGINT, signalCpuBreak); 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 commentDefer; + vector labelDefer; std::string str = ""; int addr = 0; boost::char_separator sep(";", "", boost::keep_empty_tokens); boost::tokenizer > tokens(str, sep); - disasm disasm(instr); while(getline(inFile, str)) { int count = 0; tokens.assign(str); @@ -117,6 +594,15 @@ int main(int argc, char* argv[]) if(count == 1) { try { addr = lexical_cast(*tok_iter); + for(unsigned int i = 0; i < commentDefer.size(); i++) { + dataCommentsStore.insert(pair(addr, commentDefer.at(i))); + } + for(unsigned int i = 0; i < labelDefer.size(); i++) { + dataLabelStore.insert(pair(addr, labelDefer.at(i))); + } + + commentDefer.clear(); + labelDefer.clear(); } catch(bad_lexical_cast& e) { cerr << e.what() << endl; @@ -133,11 +619,30 @@ int main(int argc, char* argv[]) exit(EXIT_FAILURE); } } + else if(count == 4) { + if((*tok_iter).size() > 0) { + dataLabelStore.insert(pair(addr, *tok_iter)); + } + } + else if(count == 5) { + if((*tok_iter).size() > 0) { + dataLineCommentStore.insert(pair(addr, *tok_iter)); + } + } break; case 1: if(count == 1) { try { addr = lexical_cast(*tok_iter); + for(unsigned int i = 0; i < commentDefer.size(); i++) { + progCommentsStore.insert(pair(addr, commentDefer.at(i))); + } + for(unsigned int i = 0; i < labelDefer.size(); i++) { + progLabelStore.insert(pair(addr, labelDefer.at(i))); + } + + commentDefer.clear(); + labelDefer.clear(); } catch(bad_lexical_cast& e) { cerr << e.what() << endl; @@ -148,10 +653,28 @@ int main(int argc, char* argv[]) Iinstr *pi = disasm.decode(*tok_iter); cpu.setProg(addr, pi); } + else if(count == 4) { + if((*tok_iter).size() > 0) { + progLabelStore.insert(pair(addr, *tok_iter)); + } + } + else if(count == 5) { + if((*tok_iter).size() > 0) { + progLineCommentStore.insert(pair(addr, *tok_iter)); + } + } + break; case 2: + if((*tok_iter).size() > 0) { + commentDefer.push_back(*tok_iter); + } + break; case 3: - cerr << "ignoring labels and comments for now" << endl; + if((*tok_iter).size() > 0) { + labelDefer.push_back(*tok_iter); + } + break; default: cerr << "i was to lazy to implement the other format types for now" << endl; } @@ -162,7 +685,7 @@ int main(int argc, char* argv[]) cout << endl; - +/* for(int i = 0; i <= 32; i += 4) { Iinstr *pinstr = cpu.getProg(i); if(pinstr != NULL) { @@ -177,20 +700,89 @@ int main(int argc, char* argv[]) CDat data = cpu.getRAM(i); cout << i << " : " << std::hex << i << std::dec << " " << data << endl; } - - cpu.setRegister(1, 4); +*/ +/* cpu.setRegister(1, 4); cpu.setRegister(2, 0); cpu.setRAM(0,5); - cpu.setRAM(4,50); + 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,50); + 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 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(); @@ -205,6 +797,6 @@ int main(int argc, char* argv[]) break; } } - +*/ return EXIT_SUCCESS; }