4 #include <boost/tokenizer.hpp>
5 #include <boost/program_options.hpp>
6 #include <boost/lexical_cast.hpp>
11 #include <boost/function.hpp>
12 #include <boost/functional.hpp>
13 #include <boost/tuple/tuple.hpp>
17 #include "CInstrFactory.hpp"
18 #include "uint32_from_hex.hpp"
20 #include "SReadline/SReadline.h"
21 using namespace swift;
23 #define RAM_END (0x3000)
24 #define PROG_END (0x3000)
25 #define REG_COUNT (16)
27 typedef boost::function<void (const vector<string> &)> Func;
28 typedef boost::tuple<string, Func, string> CompleterElement;
30 typedef list<CompleterElement> MyCompleterContainer;
35 // Creates a functor and memorises tokens
36 LookupFunctor(const vector<string>& tokens) : Tokens(tokens) {}
38 // Compares the first token only
39 bool operator()(const CompleterElement& ele) const
41 return (strncmp(Tokens.begin()->c_str(), ele.get<0>().c_str(), Tokens.begin()->size()) == 0);
45 const vector<string> &Tokens;
54 const MyCompleterContainer &m_completers;
57 CHelpExec(const MyCompleterContainer &cont) : m_completers(cont) {}
59 void operator() (const vector<string>&)
61 cout << "Available commands: " << endl;
62 for(auto iter = m_completers.begin(); iter != m_completers.end(); ++iter) {
63 cout << setw(19) << setfill(' ') << (*iter).get<0>() << ": " << (*iter).get<2>() << endl;
68 void close_prog(const std::vector<std::string> &);
71 disasm* Iinstr::m_disasm;
73 CCpu* global_cpu = NULL;
75 vector<CDat> breakpoints;
77 bool ignoreBreak = false;
79 bool exitProg = false;
81 void doExit(const vector<string>&)
86 unsigned int convertStringToNum(const std::string& in)
88 if(in.substr(0,2) == "0x") {
89 return lexical_cast<uint32_from_hex>(in);
92 return lexical_cast<unsigned int>(in);
97 void execStep(const vector<string>& in)
102 count = convertStringToNum(in.back());
105 cerr << "given parameter to step is not a number" << endl;
110 auto breakp = find(breakpoints.begin(), breakpoints.end(), global_cpu->getNextPC());
111 if(breakp == breakpoints.end() || ignoreBreak) {
117 cout << "Breakpoint 0x" << std::hex << setw(8) << setfill('0') << *breakp << std::hex << " hit" << endl;
121 catch(std::string& e) {
128 void execRun(const vector<string>&)
132 auto breakp = find(breakpoints.begin(), breakpoints.end(), global_cpu->getNextPC());
133 if(breakp == breakpoints.end() || ignoreBreak) {
139 cout << "Breakpoint 0x" << std::hex << setw(8) << setfill('0') << *breakp << std::hex << " hit" << endl;
143 catch(std::string& e) {
150 void setPC(const vector<string>& in)
155 addr = convertStringToNum(in.back());
158 cerr << "given parameter is not a number" << endl;
162 global_cpu->setNextPC(addr);
163 cout << "Set programcounter to 0x" << std::hex << setw(8) << setfill('0') << addr << std::dec << endl;
167 void printReg(const vector<string>& in)
169 int i, start = 0, end = REG_COUNT-1;
176 start = convertStringToNum(in[1]);
177 if(start < 0 || start > (REG_COUNT-1)) {
178 cerr << "start is out of range" << endl;
184 cerr << "given parameter is not a number" << endl;
191 end = convertStringToNum(in[2]);
192 if(start > end || end > (REG_COUNT-1)) {
193 cerr << "end is out of range or smaller than start" << endl;
198 cerr << "given parameter is not a number" << endl;
203 for(i = start; i <= end; i++) {
204 cout << setw(2) << setfill('0') << i << ": 0x";
205 cout << std::hex << setw(8) << setfill('0') << global_cpu->getRegister(i) << " ";
206 cout << std::dec << setw(10) << setfill(' ') << global_cpu->getRegister(i) << " ";
207 cout << std::dec << setw(10) << setfill(' ') << (int)global_cpu->getRegister(i) << endl;
211 void setReg(const vector<string>& in)
218 reg = convertStringToNum(in[1]);
219 if(reg < 0 || reg > (REG_COUNT-1)) {
220 cerr << "register is out of range" << endl;
224 val = convertStringToNum(in[2]);
226 cout << "Setting register " << reg << " to 0x" << std::hex << setw(8) << setfill('0') << val << std::dec << endl;
227 global_cpu->setRegister(reg,val);
230 cerr << "given parameter is not a number" << endl;
236 void printRAM(const vector<string>& in)
238 int i, start = 0, end = 15;
245 start = convertStringToNum(in[1]);
246 if(start < 0 || start > (RAM_END-1)) {
247 cerr << "start is out of range" << endl;
250 start = (start & (~(BYTE_COUNT-1))) / BYTE_COUNT;
254 cerr << "given parameter is not a number" << endl;
261 end = convertStringToNum(in[2]);
262 if(start > end || end > (RAM_END-1)) {
263 cerr << "end is out of range or smaller than start" << endl;
266 if(end % BYTE_COUNT != 0) {
267 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT)+1;
270 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT);
274 cerr << "given parameter is not a number" << endl;
278 for(i = start*BYTE_COUNT; i <= end*BYTE_COUNT; i += BYTE_COUNT) {
279 cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": 0x";
280 cout << std::hex << setw(8) << setfill('0') << global_cpu->getRAM(i) << " ";
281 cout << std::dec << setw(10) << setfill(' ') << global_cpu->getRAM(i) << " ";
282 cout << std::dec << setw(10) << setfill(' ') << (int)global_cpu->getRAM(i) << endl;
286 void setRam(const vector<string>& in)
293 addr = convertStringToNum(in[1]);
294 if(addr < 0 || addr > (RAM_END-1)) {
295 cerr << "RAM-Address is out of range" << endl;
299 addr = (addr & (~(BYTE_COUNT-1))) / BYTE_COUNT;
300 val = convertStringToNum(in[2]);
304 cout << "Setting RAM-Address 0x" << std::hex << setw(8) << setfill('0') << addr;
305 cout << " to 0x" << setw(8) << setfill('0') << val << std::dec << endl;
306 global_cpu->setRAM(addr,val);
309 cerr << "given parameter is not a number" << endl;
314 void printPROG(const vector<string>& in)
316 int i, start = 0, end = 15;
321 if(in.size() >= 2 && in[1][0] == 'c') {
322 start = global_cpu->getCurPC() / BYTE_COUNT;
325 else if(in.size() >= 2) {
327 start = convertStringToNum(in[1]);
328 if(start < 0 || start > (PROG_END-1)) {
329 cerr << "start is out of range" << endl;
332 start = (start & (~(BYTE_COUNT-1))) / BYTE_COUNT;
336 cerr << "given parameter is not a number" << endl;
343 end = convertStringToNum(in[2]);
344 if(start > end || end > (PROG_END-1)) {
345 cerr << "end is out of range or smaller than start" << endl;
348 if(end % BYTE_COUNT != 0) {
349 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT)+1;
352 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT);
357 cerr << "given parameter is not a number" << endl;
363 for(i = start*BYTE_COUNT; i <= end*BYTE_COUNT; i += BYTE_COUNT) {
364 Iinstr* pi = global_cpu->getProg(i);
366 cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": NOP" << endl;
369 cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": " << std::dec << pi->toString() << endl;
374 void setBreak(const vector<string>& in)
376 unsigned int addr = 0;
379 addr = convertStringToNum(in.back());
380 breakpoints.push_back(addr);
381 cout << "Breakpoint 0x" << std::hex << setw(8) << setfill('0') << addr << std::dec << " set" << endl;
384 cerr << "Given parameter is not a valid address" << endl;
388 cerr << "Invalid parameter count!" << endl;
392 void listBreaks(const vector<string>&)
394 for(auto iter = breakpoints.begin(); iter != breakpoints.end(); ++iter) {
395 cout << "Breakpoint at 0x" << std::hex << setw(8) << setfill('0') << *iter << std::dec << endl;
399 void getPerf(const vector<string>&)
401 cout << "current perfcounter is " << std::dec << global_cpu->getPerf() << endl;
404 void resetPerf(const vector<string>&)
406 cout << "reset perfcounter" << endl;
407 global_cpu->setPerf(0);
410 void printStatus(const vector<string>&)
412 CDat stackp = global_cpu->getStack();
413 CDat stackd = global_cpu->getRAM(stackp);
414 cout << "Stack pointer: 0x" << std::hex << setw(8) << setfill('0') << stackp << " @stackpointer: 0x" << setw(8) << stackd << std::dec << " (" << stackd << ")" << endl;
415 cout << "PSW: 0x" << std::hex << setw(8) << setfill('0') << global_cpu->getFlags() << std::dec << endl;
416 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;
420 using boost::lexical_cast;
421 using boost::bad_lexical_cast;
425 using namespace boost::program_options;
426 namespace po = boost::program_options;
428 std::string progName;
430 int main(int argc, char* argv[])
435 po::options_description desc("Allowed options");
437 ("help,h","produce help message")
438 ("file,f",value<string>(), "input file")
441 po::positional_options_description p;
444 po::variables_map vm;
445 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
448 if(vm.count("help")) {
449 cout << desc << endl;
453 if(vm.count("file")) {
455 cout << "going to open file " << vm["file"].as<string>() << endl;
457 inFile.open(vm["file"].as<string>(), ios::in);
459 cerr << "Error opening file " << vm["file"].as<string>() << endl;
464 cout << "not input file given!" << endl << endl;
465 cout << desc << endl;
469 catch(std::exception& ex) {
470 cout << ex.what() << endl;
474 string dir = "./instr/";
476 map<short, Iinstr*> instr;
478 CInstrFactory instrFab;
480 instrFab.loadLibsIntoMap(instr, dir);
482 catch(std::bad_alloc& e) {
483 cerr << progName << ": bad_alloc caught " << e.what() << endl;
486 catch(std::string& s) {
487 cerr << progName << ": " << s << endl;
491 CCpu cpu(REG_COUNT, RAM_END, PROG_END);
495 Iinstr::setCPU(&cpu);
497 disasm disasm(instr);
499 Iinstr::setDisasm(&disasm);
501 std::string str = "";
503 boost::char_separator<char> sep(";", "", boost::keep_empty_tokens);
504 boost::tokenizer<boost::char_separator<char> > tokens(str, sep);
505 while(getline(inFile, str)) {
510 for(auto tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter) {
511 if(tok_iter == tokens.begin()) {
513 type = lexical_cast<int>(*tok_iter);
517 catch(bad_lexical_cast &) {
526 addr = lexical_cast<uint32_from_hex>(*tok_iter);
528 catch(bad_lexical_cast& e) {
529 cerr << e.what() << endl;
533 else if(count == 2) {
535 CDat data = lexical_cast<uint32_from_hex>(*tok_iter);
536 cpu.setRAM(addr, data);
538 catch(bad_lexical_cast& e) {
539 cerr << e.what() << endl;
547 addr = lexical_cast<uint32_from_hex>(*tok_iter);
549 catch(bad_lexical_cast& e) {
550 cerr << e.what() << endl;
554 else if(count == 2) {
555 Iinstr *pi = disasm.decode(*tok_iter);
556 cpu.setProg(addr, pi);
561 cerr << "ignoring labels and comments for now" << endl;
564 cerr << "i was to lazy to implement the other format types for now" << endl;
574 for(int i = 0; i <= 32; i += 4) {
575 Iinstr *pinstr = cpu.getProg(i);
577 cout << i << " : " << std::hex << i << std::dec << " " << pinstr->toString() << endl;
580 cout << "Null at " << i << " : " << std::hex << i << endl;
584 for(int i = 0; i <= 32; i += 4) {
585 CDat data = cpu.getRAM(i);
586 cout << i << " : " << std::hex << i << std::dec << " " << data << endl;
589 /* cpu.setRegister(1, 4);
590 cpu.setRegister(2, 0);
592 cpu.setRAM(4,0x66334455);
596 // following: job of the bootloader
599 //set return to nowhere for ret
604 MyCompleterContainer Completers;
606 CHelpExec HelpExec(Completers);
608 Completers.push_back(CompleterElement("help", boost::bind1st( boost::mem_fun( &CHelpExec::operator()), &HelpExec), "Prints this message"));
609 Completers.push_back(CompleterElement("quit", &doExit, "Exits program"));
610 Completers.push_back(CompleterElement("exit", &doExit, "Exits program"));
611 Completers.push_back(CompleterElement("step [count]",&execStep, "Runs [count] ticks. if count is not given one tick is executed."));
612 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."));
613 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."));
614 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."));
615 Completers.push_back(CompleterElement("break addr",&setBreak, "Sets a breakpoint for address addr."));
616 Completers.push_back(CompleterElement("listbreaks",&listBreaks, "Lists all breakpoints."));
617 Completers.push_back(CompleterElement("run",&execRun, "Runs till next breakpoint or end of program."));
618 Completers.push_back(CompleterElement("setpc [num]",&setPC, "Sets PC to num. if num is omitted 0 is used."));
619 Completers.push_back(CompleterElement("setreg [s] [num]",&setReg, "Sets Register s to num."));
620 Completers.push_back(CompleterElement("setdata [s] [num]",&setRam, "Sets RAM-Addr s to num."));
621 Completers.push_back(CompleterElement("status",&printStatus, "Prints status of CPU."));
622 Completers.push_back(CompleterElement("getperf",&getPerf, "Prints performance counter."));
623 Completers.push_back(CompleterElement("resetperf",&resetPerf, "Resets performance counter to 0."));
625 Reader.RegisterCompletions(Completers);
628 vector<string> Tokens, lastTokens;
629 bool EndOfInput = false;
631 //tilab g++44 doesn't like auto here
632 MyCompleterContainer::iterator Found(Completers.end());
634 Func lastFunc = NULL;
638 UserInput = Reader.GetLine("> ", Tokens, EndOfInput);
643 if(!Tokens.empty()) {
644 Found = find_if(Completers.begin(), Completers.end(), LookupFunctor(Tokens));
646 if(Found != Completers.end()) {
647 if((*Found).get<1>() != 0) {
648 lastFunc = (*Found).get<1>();
651 //(*Found).get<1>()(Tokens);
656 cout << "Unknown command. 'help' displays help" << endl;
660 if(lastFunc != NULL) {
661 lastFunc(lastTokens);
664 cout << "Unknown command. 'help' displays help" << endl;
671 for(int i = 0; ; i++) {
674 cout << " reg0: " << cpu.getRegister(0) << " reg1: " << cpu.getRegister(1);
675 cout << " reg2: " << cpu.getRegister(2) << " reg3: " << cpu.getRegister(3);
676 cout << " reg4: " << cpu.getRegister(4) << " reg5: " << cpu.getRegister(5);
677 cout << endl << endl;