#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; using namespace std; using namespace boost::program_options; namespace po = boost::program_options; std::string progName; int main(int argc, char* argv[]) { progName = argv[0]; ifstream inFile; try { po::options_description desc("Allowed options"); desc.add_options() ("help,h","produce help message") ("file,f",value(), "input file") ; po::positional_options_description p; p.add("file",1); po::variables_map vm; po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm); po::notify(vm); if(vm.count("help")) { cout << desc << endl; return EXIT_FAILURE; } if(vm.count("file")) { #ifdef DEBUG cout << "going to open file " << vm["file"].as() << endl; #endif inFile.open(vm["file"].as(), ios::in); if(!inFile) { cerr << "Error opening file " << vm["file"].as() << endl; return EXIT_FAILURE; } } else { cout << "not input file given!" << endl << endl; cout << desc << endl; return EXIT_FAILURE; } } catch(std::exception& ex) { cout << ex.what() << endl; } string dir = "./instr/"; map instr; CInstrFactory instrFab; try { instrFab.loadLibsIntoMap(instr, dir); } catch(std::bad_alloc& e) { cerr << progName << ": bad_alloc caught " << e.what() << endl; exit(EXIT_FAILURE); } catch(std::string& s) { cerr << progName << ": " << s << endl; exit(EXIT_FAILURE); } CCpu cpu(REG_COUNT, RAM_END, PROG_END); 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); while(getline(inFile, str)) { int count = 0; tokens.assign(str); stringstream out; int type = 0; for(auto tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter) { if(tok_iter == tokens.begin()) { try { type = lexical_cast(*tok_iter); count++; continue; } catch(bad_lexical_cast &) { break; } cout << endl; } switch(type) { case 0: 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; exit(EXIT_FAILURE); } } else if(count == 2) { try { CDat data = lexical_cast(*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(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; exit(EXIT_FAILURE); } } else if(count == 2) { 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: 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; } count++; } } 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 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; }