1 /* `Deep Thought', a softcore CPU implemented on a FPGA
3 Copyright (C) 2010 Markus Hofstaetter <markus.manrow@gmx.at>
4 Copyright (C) 2010 Martin Perner <e0725782@student.tuwien.ac.at>
5 Copyright (C) 2010 Stefan Rebernig <stefan.rebernig@gmail.com>
6 Copyright (C) 2010 Manfred Schwarz <e0725898@student.tuwien.ac.at>
7 Copyright (C) 2010 Bernhard Urban <lewurm@gmail.com>
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
25 #include <boost/tokenizer.hpp>
26 #include <boost/program_options.hpp>
27 #include <boost/lexical_cast.hpp>
32 #include <boost/function.hpp>
33 #include <boost/functional.hpp>
34 #include <boost/tuple/tuple.hpp>
38 #include "CInstrFactory.hpp"
39 #include "uint32_from_hex.hpp"
42 #include "extensions/cprog.hpp"
43 #include "extensions/cuart.hpp"
47 #include "SReadline/SReadline.h"
48 using namespace swift;
50 #define RAM_END (0x3000)
51 #define PROG_END (0x3000)
52 #define REG_COUNT (16)
54 typedef boost::function<void (const vector<string> &)> Func;
55 typedef boost::tuple<string, Func, string> CompleterElement;
57 typedef list<CompleterElement> MyCompleterContainer;
62 // Creates a functor and memorises tokens
63 LookupFunctor(const vector<string>& tokens) : Tokens(tokens) {}
65 // Compares the first token only
66 bool operator()(const CompleterElement& ele) const
68 return (strncmp(Tokens.begin()->c_str(), ele.get<0>().c_str(), Tokens.begin()->size()) == 0);
72 const vector<string> &Tokens;
81 const MyCompleterContainer &m_completers;
84 CHelpExec(const MyCompleterContainer &cont) : m_completers(cont) {}
86 void operator() (const vector<string>&)
88 cout << "Available commands: " << endl;
89 for(auto iter = m_completers.begin(); iter != m_completers.end(); ++iter) {
90 cout << setw(19) << setfill(' ') << (*iter).get<0>() << ": " << (*iter).get<2>() << endl;
95 void close_prog(const std::vector<std::string> &);
99 disasm* Iinstr::m_disasm;
100 disasm* Iext::m_disasm;
102 CCpu* global_cpu = NULL;
104 vector<CDat> breakpoints;
109 multimap<int,string> dataCommentsStore, progCommentsStore, dataLabelStore, progLabelStore;
110 map<int,string> dataLineCommentStore, progLineCommentStore;
112 bool ignoreBreak = false;
114 bool exitProg = false;
116 void signalCpuBreak(int)
118 global_cpu->breakNext();
121 void doExit(const vector<string>&)
126 unsigned int convertStringToNum(const std::string& in)
128 if(in.substr(0,2) == "0x") {
129 return lexical_cast<uint32_from_hex>(in);
132 return lexical_cast<unsigned int>(in);
137 void execStep(const vector<string>& in)
142 count = convertStringToNum(in.back());
145 cerr << "given parameter to step is not a number" << endl;
150 auto breakp = find(breakpoints.begin(), breakpoints.end(), global_cpu->getNextPC());
151 if(breakp == breakpoints.end() || ignoreBreak) {
157 cout << color(white,red) << "Breakpoint" << color(white,black) << " 0x" << std::hex << setw(8) << setfill('0') << *breakp << std::hex << " hit" << endl;
161 catch(std::string& e) {
168 void execRun(const vector<string>&)
172 auto breakp = find(breakpoints.begin(), breakpoints.end(), global_cpu->getNextPC());
173 if((breakp == breakpoints.end() || ignoreBreak) && !global_cpu->shouldBreak() ) {
179 cout << color(white,red) << "Breakpoint" << color(white,black) << " 0x" << std::hex << setw(8) << setfill('0') << *breakp << std::hex << " hit" << endl;
183 catch(std::string& e) {
190 void setPC(const vector<string>& in)
195 addr = convertStringToNum(in.back());
198 cerr << "given parameter is not a number" << endl;
202 global_cpu->setNextPC(addr);
203 cout << "Set programcounter to 0x" << std::hex << setw(8) << setfill('0') << addr << std::dec << endl;
207 void printReg(const vector<string>& in)
209 int i, start = 0, end = REG_COUNT-1;
216 start = convertStringToNum(in[1]);
217 if(start < 0 || start > (REG_COUNT-1)) {
218 cerr << "start is out of range" << endl;
224 cerr << "given parameter is not a number" << endl;
231 end = convertStringToNum(in[2]);
232 if(start > end || end > (REG_COUNT-1)) {
233 cerr << "end is out of range or smaller than start" << endl;
238 cerr << "given parameter is not a number" << endl;
243 for(i = start; i <= end; i++) {
244 cout << setw(2) << setfill('0') << i << ": 0x";
245 cout << std::hex << setw(8) << setfill('0') << global_cpu->getRegister(i) << " ";
246 cout << std::dec << setw(10) << setfill(' ') << global_cpu->getRegister(i) << " ";
247 cout << std::dec << setw(10) << setfill(' ') << (int)global_cpu->getRegister(i) << endl;
251 void setReg(const vector<string>& in)
258 reg = convertStringToNum(in[1]);
259 if(reg < 0 || reg > (REG_COUNT-1)) {
260 cerr << "register is out of range" << endl;
264 val = convertStringToNum(in[2]);
266 cout << "Setting register " << reg << " to 0x" << std::hex << setw(8) << setfill('0') << val << std::dec << endl;
267 global_cpu->setRegister(reg,val);
270 cerr << "given parameter is not a number" << endl;
276 void printRAM(const vector<string>& in)
278 int i, start = 0, end = 15;
285 start = convertStringToNum(in[1]);
286 if(start < 0 || start > (RAM_END-1)) {
287 cerr << "start is out of range" << endl;
290 start = (start & (~(BYTE_COUNT-1))) / BYTE_COUNT;
294 cerr << "given parameter is not a number" << endl;
301 end = convertStringToNum(in[2]);
302 if(start > end || end > (RAM_END-1)) {
303 cerr << "end is out of range or smaller than start" << endl;
306 if(end % BYTE_COUNT != 0) {
307 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT)+1;
310 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT);
314 cerr << "given parameter is not a number" << endl;
318 for(i = start*BYTE_COUNT; i <= end*BYTE_COUNT; i += BYTE_COUNT) {
320 auto range = dataLabelStore.equal_range(i);
321 for(auto iter = range.first; iter != range.second; ++iter) {
322 cout << color(yellow,black) << iter->second << ":" << color(white,black) << endl;
326 auto range = dataCommentsStore.equal_range(i);
327 for(auto iter = range.first; iter != range.second; ++iter) {
328 cout << color(blue,black) << ";" << iter->second << color(white,black) << endl;
331 cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": 0x";
332 cout << std::hex << setw(8) << setfill('0') << global_cpu->getRAM(i) << " ";
333 cout << std::dec << setw(10) << setfill(' ') << global_cpu->getRAM(i) << " ";
334 cout << std::dec << setw(10) << setfill(' ') << (int)global_cpu->getRAM(i);
336 auto iter = dataLineCommentStore.find(i);
337 if(iter != dataLineCommentStore.end()) {
338 cout << color(blue,black) << " ;" << iter->second << color(white,black);
345 void setRam(const vector<string>& in)
352 addr = convertStringToNum(in[1]);
353 if(addr < 0 || addr > (RAM_END-1)) {
354 cerr << "RAM-Address is out of range" << endl;
358 addr = (addr & (~(BYTE_COUNT-1))) / BYTE_COUNT;
359 val = convertStringToNum(in[2]);
363 cout << "Setting RAM-Address 0x" << std::hex << setw(8) << setfill('0') << addr;
364 cout << " to 0x" << setw(8) << setfill('0') << val << std::dec << endl;
365 global_cpu->setRAM(addr,val);
368 cerr << "given parameter is not a number" << endl;
373 void printPROG(const vector<string>& in)
375 int i, start = 0, end = 15;
380 if(in.size() >= 2 && in[1][0] == 'c') {
381 start = global_cpu->getCurPC() / BYTE_COUNT;
384 else if(in.size() >= 2) {
386 start = convertStringToNum(in[1]);
387 if(start < 0 || start > (PROG_END-1)) {
388 cerr << "start is out of range" << endl;
391 start = (start & (~(BYTE_COUNT-1))) / BYTE_COUNT;
395 cerr << "given parameter is not a number" << endl;
402 end = convertStringToNum(in[2]);
403 if(start > end || end > (PROG_END-1)) {
404 cerr << "end is out of range or smaller than start" << endl;
407 if(end % BYTE_COUNT != 0) {
408 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT)+1;
411 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT);
416 cerr << "given parameter is not a number" << endl;
422 for(i = start*BYTE_COUNT; i <= end*BYTE_COUNT; i += BYTE_COUNT) {
424 auto range = progLabelStore.equal_range(i);
425 for(auto iter = range.first; iter != range.second; ++iter) {
426 cout << color(yellow,black) << iter->second << ":" << color(white,black) << endl;
430 auto range = progCommentsStore.equal_range(i);
431 for(auto iter = range.first; iter != range.second; ++iter) {
432 cout << color(blue,black) << ";" << iter->second << color(white,black) << endl;
436 Iinstr* pi = global_cpu->getProg(i);
438 cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": NOP";
441 cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": " << std::dec << global_cpu->colorifyInstr(pi->toString());
443 auto iter = progLineCommentStore.find(i);
444 if(iter != progLineCommentStore.end()) {
445 cout << color(blue,black) << " ;" << iter->second << color(white,black);
451 void setBreak(const vector<string>& in)
453 unsigned int addr = 0;
456 addr = convertStringToNum(in.back());
457 breakpoints.push_back(addr);
458 cout << "Breakpoint 0x" << std::hex << setw(8) << setfill('0') << addr << std::dec << " set" << endl;
461 cerr << "Given parameter is not a valid address" << endl;
465 cerr << "Invalid parameter count!" << endl;
469 void listBreaks(const vector<string>&)
471 for(auto iter = breakpoints.begin(); iter != breakpoints.end(); ++iter) {
472 cout << "Breakpoint at 0x" << std::hex << setw(8) << setfill('0') << *iter << std::dec << endl;
476 void getPerf(const vector<string>&)
478 cout << "current perfcounter is " << std::dec << global_cpu->getPerf() << endl;
481 void resetPerf(const vector<string>&)
483 cout << "reset perfcounter" << endl;
484 global_cpu->setPerf(0);
487 void applyToExtensions(const vector<string>& in)
489 global_cpu->applyToExtensions(in);
493 void printStatus(const vector<string>&)
495 CDat stackp = global_cpu->getStack();
496 CDat stackd = global_cpu->getRAM(stackp);
497 cout << "Stack pointer: 0x" << std::hex << setw(8) << setfill('0') << stackp << " @stackpointer: 0x" << setw(8) << stackd << std::dec << " (" << stackd << ")" << endl;
498 cout << "PSW: 0x" << std::hex << setw(8) << setfill('0') << global_cpu->getFlags() << std::dec << endl;
499 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;
503 using boost::lexical_cast;
504 using boost::bad_lexical_cast;
508 using namespace boost::program_options;
509 namespace po = boost::program_options;
511 std::string progName;
513 int main(int argc, char* argv[])
518 po::options_description desc("Allowed options");
520 ("help,h","produce help message")
521 ("file,f",value<string>(), "input file")
524 po::positional_options_description p;
527 po::variables_map vm;
528 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
531 if(vm.count("help")) {
532 cout << desc << endl;
536 if(vm.count("file")) {
538 cout << "going to open file " << vm["file"].as<string>() << endl;
540 inFile.open(vm["file"].as<string>(), ios::in);
542 cerr << "Error opening file " << vm["file"].as<string>() << endl;
547 cout << "not input file given!" << endl << endl;
548 cout << desc << endl;
552 catch(std::exception& ex) {
553 cout << ex.what() << endl;
557 string dir = "./instr/";
559 map<short, Iinstr*> instr;
561 CInstrFactory instrFab;
563 instrFab.loadLibsIntoMap(instr, dir);
565 catch(std::bad_alloc& e) {
566 cerr << progName << ": bad_alloc caught " << e.what() << endl;
569 catch(std::string& s) {
570 cerr << progName << ": " << s << endl;
574 CCpu cpu(REG_COUNT, RAM_END, PROG_END);
578 signal(SIGINT, signalCpuBreak);
579 Iinstr::setCPU(&cpu);
582 disasm disasm(instr);
584 Iinstr::setDisasm(&disasm);
585 Iext::setDisasm(&disasm);
587 global_cpu->registerExtension(new Cprog());
588 global_cpu->registerExtension(new Cuart());
590 vector<string> commentDefer;
591 vector<string> labelDefer;
592 std::string str = "";
594 boost::char_separator<char> sep(";", "", boost::keep_empty_tokens);
595 boost::tokenizer<boost::char_separator<char> > tokens(str, sep);
596 while(getline(inFile, str)) {
601 for(auto tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter) {
602 if(tok_iter == tokens.begin()) {
604 type = lexical_cast<int>(*tok_iter);
608 catch(bad_lexical_cast &) {
617 addr = lexical_cast<uint32_from_hex>(*tok_iter);
618 for(unsigned int i = 0; i < commentDefer.size(); i++) {
619 dataCommentsStore.insert(pair<int,string>(addr, commentDefer.at(i)));
621 for(unsigned int i = 0; i < labelDefer.size(); i++) {
622 dataLabelStore.insert(pair<int,string>(addr, labelDefer.at(i)));
625 commentDefer.clear();
628 catch(bad_lexical_cast& e) {
629 cerr << e.what() << endl;
633 else if(count == 2) {
635 CDat data = lexical_cast<uint32_from_hex>(*tok_iter);
636 cpu.setRAM(addr, data);
638 catch(bad_lexical_cast& e) {
639 cerr << e.what() << endl;
643 else if(count == 4) {
644 if((*tok_iter).size() > 0) {
645 dataLabelStore.insert(pair<int,string>(addr, *tok_iter));
648 else if(count == 5) {
649 if((*tok_iter).size() > 0) {
650 dataLineCommentStore.insert(pair<int,string>(addr, *tok_iter));
657 addr = lexical_cast<uint32_from_hex>(*tok_iter);
658 for(unsigned int i = 0; i < commentDefer.size(); i++) {
659 progCommentsStore.insert(pair<int,string>(addr, commentDefer.at(i)));
661 for(unsigned int i = 0; i < labelDefer.size(); i++) {
662 progLabelStore.insert(pair<int,string>(addr, labelDefer.at(i)));
665 commentDefer.clear();
668 catch(bad_lexical_cast& e) {
669 cerr << e.what() << endl;
673 else if(count == 2) {
674 Iinstr *pi = disasm.decode(*tok_iter);
675 cpu.setProg(addr, pi);
677 else if(count == 4) {
678 if((*tok_iter).size() > 0) {
679 progLabelStore.insert(pair<int,string>(addr, *tok_iter));
682 else if(count == 5) {
683 if((*tok_iter).size() > 0) {
684 progLineCommentStore.insert(pair<int,string>(addr, *tok_iter));
690 if((*tok_iter).size() > 0) {
691 commentDefer.push_back(*tok_iter);
695 if((*tok_iter).size() > 0) {
696 labelDefer.push_back(*tok_iter);
700 cerr << "i was to lazy to implement the other format types for now" << endl;
710 for(int i = 0; i <= 32; i += 4) {
711 Iinstr *pinstr = cpu.getProg(i);
713 cout << i << " : " << std::hex << i << std::dec << " " << pinstr->toString() << endl;
716 cout << "Null at " << i << " : " << std::hex << i << endl;
720 for(int i = 0; i <= 32; i += 4) {
721 CDat data = cpu.getRAM(i);
722 cout << i << " : " << std::hex << i << std::dec << " " << data << endl;
725 /* cpu.setRegister(1, 4);
726 cpu.setRegister(2, 0);
728 cpu.setRAM(4,0x66334455);
732 // following: job of the bootloader
735 //set return to nowhere for ret
740 MyCompleterContainer Completers;
742 CHelpExec HelpExec(Completers);
744 Completers.push_back(CompleterElement("help", boost::bind1st( boost::mem_fun( &CHelpExec::operator()), &HelpExec), "Prints this message"));
745 Completers.push_back(CompleterElement("quit", &doExit, "Exits program"));
746 Completers.push_back(CompleterElement("exit", &doExit, "Exits program"));
747 Completers.push_back(CompleterElement("step [count]",&execStep, "Runs [count] ticks. if count is not given one tick is executed."));
748 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."));
749 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."));
750 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."));
751 Completers.push_back(CompleterElement("break addr",&setBreak, "Sets a breakpoint for address addr."));
752 Completers.push_back(CompleterElement("listbreaks",&listBreaks, "Lists all breakpoints."));
753 Completers.push_back(CompleterElement("run",&execRun, "Runs till next breakpoint or end of program."));
754 Completers.push_back(CompleterElement("setpc [num]",&setPC, "Sets PC to num. if num is omitted 0 is used."));
755 Completers.push_back(CompleterElement("setreg [s] [num]",&setReg, "Sets Register s to num."));
756 Completers.push_back(CompleterElement("setdata [s] [num]",&setRam, "Sets RAM-Addr s to num."));
757 Completers.push_back(CompleterElement("status",&printStatus, "Prints status of CPU."));
758 Completers.push_back(CompleterElement("getperf",&getPerf, "Prints performance counter."));
759 Completers.push_back(CompleterElement("resetperf",&resetPerf, "Resets performance counter to 0."));
760 Completers.push_back(CompleterElement("extension",&applyToExtensions, "Write to extensions."));
761 Reader.RegisterCompletions(Completers);
764 vector<string> Tokens, lastTokens;
765 bool EndOfInput = false;
767 //tilab g++44 doesn't like auto here
768 MyCompleterContainer::iterator Found(Completers.end());
770 Func lastFunc = NULL;
774 UserInput = Reader.GetLine("> ", Tokens, EndOfInput);
779 if(!Tokens.empty()) {
780 Found = find_if(Completers.begin(), Completers.end(), LookupFunctor(Tokens));
782 if(Found != Completers.end()) {
783 if((*Found).get<1>() != 0) {
784 lastFunc = (*Found).get<1>();
787 //(*Found).get<1>()(Tokens);
792 cout << "Unknown command. 'help' displays help" << endl;
796 if(lastFunc != NULL) {
797 lastFunc(lastTokens);
800 cout << "Unknown command. 'help' displays help" << endl;
807 for(int i = 0; ; i++) {
810 cout << " reg0: " << cpu.getRegister(0) << " reg1: " << cpu.getRegister(1);
811 cout << " reg2: " << cpu.getRegister(2) << " reg3: " << cpu.getRegister(3);
812 cout << " reg4: " << cpu.getRegister(4) << " reg5: " << cpu.getRegister(5);
813 cout << endl << endl;