8589084687a79e362a59335844980287fa11d41d
[calu.git] / 3b_sim / sim.cpp
1 #include <iostream>
2 #include <iomanip>
3 #include <fstream>
4 #include <boost/tokenizer.hpp>
5 #include <boost/program_options.hpp>
6 #include <boost/lexical_cast.hpp>
7 #include <string>
8 #include <map>
9 #include <list>
10
11 #include <boost/function.hpp>
12 #include <boost/functional.hpp>
13 #include <boost/tuple/tuple.hpp>
14
15 #include "disasm.h"
16 #include "ccpu.hpp"
17 #include "CInstrFactory.hpp"
18 #include "uint32_from_hex.hpp"
19
20 #include "SReadline/SReadline.h"
21 using namespace swift;
22
23 #define RAM_END (0x3000)
24 #define PROG_END (0x3000)
25 #define REG_COUNT (16)
26
27 typedef boost::function<void (const vector<string> &)> Func;
28 typedef boost::tuple<string, Func, string> CompleterElement;
29
30 typedef list<CompleterElement> MyCompleterContainer;
31
32 class LookupFunctor
33 {
34         public:
35                 // Creates a functor and memorises tokens
36                 LookupFunctor(const vector<string>&  tokens) : Tokens(tokens) {}
37
38                 // Compares the first token only
39                 bool operator()(const CompleterElement& ele) const
40                 {
41                         return (strncmp(Tokens.begin()->c_str(), ele.get<0>().c_str(), Tokens.begin()->size()) == 0);
42                 }
43
44         private:
45                 const vector<string> &Tokens;
46 };
47
48
49
50
51 class CHelpExec
52 {
53         private:
54                 const MyCompleterContainer &m_completers;
55
56         public:
57                 CHelpExec(const MyCompleterContainer &cont) : m_completers(cont) {}
58
59                 void operator() (const vector<string>&)
60                 {
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;
64                         }
65                 }
66 };
67
68 void close_prog(const std::vector<std::string> &);
69
70 CCpu* Iinstr::m_cpu;
71 disasm* Iinstr::m_disasm;
72
73 CCpu* global_cpu = NULL;
74
75 vector<CDat> breakpoints;
76
77 bool ignoreBreak = false;
78
79 bool exitProg = false;
80
81 void doExit(const vector<string>&)
82 {
83         exitProg = true;
84 }
85
86 unsigned int convertStringToNum(const std::string& in)
87 {
88         if(in.substr(0,2) == "0x") {
89                 return lexical_cast<uint32_from_hex>(in);
90         }
91         else {
92                 return lexical_cast<unsigned int>(in);
93         }
94 }
95
96
97 void execStep(const vector<string>& in)
98 {
99         int count = 1;
100         if(in.size() == 2) {
101                 try {
102                         count = convertStringToNum(in.back());
103                 }
104                 catch(bad_cast&) {
105                         cerr << "given parameter to step is not a number" << endl;
106                 }
107         }
108         while(count > 0) {
109                 try {
110                         auto breakp = find(breakpoints.begin(), breakpoints.end(), global_cpu->getNextPC());
111                         if(breakp == breakpoints.end() || ignoreBreak) {
112                                 global_cpu->tick();
113                                 ignoreBreak = false;
114                         }
115                         else {
116                                 ignoreBreak = true;
117                                 cout << color(white,red) << "Breakpoint" << color(white,black) << " 0x" << std::hex << setw(8) << setfill('0') << *breakp << std::hex << " hit" << endl;
118                                 break;
119                         }
120                 }
121                 catch(std::string& e) {
122                         cerr << e << endl;
123                 }
124                 count--;
125         }
126 }
127
128 void execRun(const vector<string>&)
129 {
130         while(1) {
131                 try {
132                         auto breakp = find(breakpoints.begin(), breakpoints.end(), global_cpu->getNextPC());
133                         if(breakp == breakpoints.end() || ignoreBreak) {
134                                 global_cpu->tick();
135                                 ignoreBreak = false;
136                         }
137                         else {
138                                 ignoreBreak = true;
139                                 cout << color(white,red) << "Breakpoint" << color(white,black) << " 0x" << std::hex << setw(8) << setfill('0') << *breakp << std::hex << " hit" << endl;
140                                 return;
141                         }
142                 }
143                 catch(std::string& e) {
144                         cerr << e << endl;
145                         return;
146                 }
147         }
148 }
149
150 void setPC(const vector<string>& in)
151 {
152         CDat addr = 0;
153         if(in.size() == 2) {
154                 try {
155                         addr = convertStringToNum(in.back());
156                 }
157                 catch(bad_cast&) {
158                         cerr << "given parameter is not a number" << endl;
159                         return;
160                 }
161         }
162         global_cpu->setNextPC(addr);
163         cout << "Set programcounter to 0x" << std::hex << setw(8) << setfill('0') << addr << std::dec << endl;
164 }
165
166
167 void printReg(const vector<string>& in)
168 {
169         int i, start = 0, end = REG_COUNT-1;
170         /* Todo: 
171          * 1) make 2 columns
172          */
173
174         if(in.size() >= 2) {
175                 try {
176                         start = convertStringToNum(in[1]);
177                         if(start < 0 || start > (REG_COUNT-1)) {
178                                 cerr << "start is out of range" << endl;
179                                 return;
180                         }
181                         end = start;
182                 }
183                 catch(bad_cast&) {
184                         cerr << "given parameter is not a number" << endl;
185                         return;
186                 }
187         }
188
189         if(in.size() >= 3) {
190                 try {
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;
194                                 return;
195                         }
196                 }
197                 catch(bad_cast&) {
198                         cerr << "given parameter is not a number" << endl;
199                         return;
200                 }
201         }
202         
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;
208         }
209 }
210
211 void setReg(const vector<string>& in)
212 {
213         int reg = 0;
214         CDat val = 0;
215
216         if(in.size() >= 3) {
217                 try {
218                         reg = convertStringToNum(in[1]);
219                         if(reg < 0 || reg > (REG_COUNT-1)) {
220                                 cerr << "register is out of range" << endl;
221                                 return;
222                         }
223
224                         val = convertStringToNum(in[2]);
225
226                         cout << "Setting register " << reg << " to 0x" << std::hex << setw(8) << setfill('0') << val << std::dec << endl;
227                         global_cpu->setRegister(reg,val);
228                 }
229                 catch(bad_cast&) {
230                         cerr << "given parameter is not a number" << endl;
231                         return;
232                 }
233         }
234 }
235
236 void printRAM(const vector<string>& in)
237 {
238         int i, start = 0, end = 15;
239         /* Todo: 
240          * 1) make 2 columns
241          */
242
243         if(in.size() >= 2) {
244                 try {
245                         start = convertStringToNum(in[1]);
246                         if(start < 0 || start > (RAM_END-1)) {
247                                 cerr << "start is out of range" << endl;
248                                 return;
249                         }
250                         start = (start & (~(BYTE_COUNT-1))) / BYTE_COUNT;
251                         end = start;
252                 }
253                 catch(bad_cast&) {
254                         cerr << "given parameter is not a number" << endl;
255                         return;
256                 }
257         }
258
259         if(in.size() >= 3) {
260                 try {
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;
264                                 return;
265                         }
266                         if(end % BYTE_COUNT != 0) {
267                                 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT)+1;
268                         }
269                         else {
270                                 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT);
271                         }
272                 }
273                 catch(bad_cast&) {
274                         cerr << "given parameter is not a number" << endl;
275                         return;
276                 }
277         }
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;
283         }
284 }
285
286 void setRam(const vector<string>& in)
287 {
288         int addr = 0;
289         CDat val = 0;
290
291         if(in.size() >= 3) {
292                 try {
293                         addr = convertStringToNum(in[1]);
294                         if(addr < 0 || addr > (RAM_END-1)) {
295                                 cerr << "RAM-Address is out of range" << endl;
296                                 return;
297                         }
298
299                         addr = (addr & (~(BYTE_COUNT-1))) / BYTE_COUNT;
300                         val = convertStringToNum(in[2]);
301
302                         addr *= BYTE_COUNT;
303
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);
307                 }
308                 catch(bad_cast&) {
309                         cerr << "given parameter is not a number" << endl;
310                         return;
311                 }
312         }
313 }
314 void printPROG(const vector<string>& in)
315 {
316         int i, start = 0, end = 15;
317         /* Todo: 
318          * 1) make 2 columns
319          */
320
321         if(in.size() >= 2 && in[1][0] == 'c') {
322                 start = global_cpu->getCurPC() / BYTE_COUNT;
323                 end = start + 9;
324         }
325         else if(in.size() >= 2) {
326                 try {
327                         start = convertStringToNum(in[1]);
328                         if(start < 0 || start > (PROG_END-1)) {
329                                 cerr << "start is out of range" << endl;
330                                 return;
331                         }
332                         start = (start & (~(BYTE_COUNT-1))) / BYTE_COUNT;
333                         end = start;
334                 }
335                 catch(bad_cast&) {
336                         cerr << "given parameter is not a number" << endl;
337                         return;
338                 }
339         }
340
341         if(in.size() >= 3) {
342                 try {
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;
346                                 return;
347                         }
348                         if(end % BYTE_COUNT != 0) {
349                                 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT)+1;
350                         }
351                         else {
352                                 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT);
353                         }
354
355                 }
356                 catch(bad_cast&) {
357                         cerr << "given parameter is not a number" << endl;
358                         return;
359                 }
360         }
361
362         
363         for(i = start*BYTE_COUNT; i <= end*BYTE_COUNT; i += BYTE_COUNT) {
364                 Iinstr* pi = global_cpu->getProg(i);
365                 if(pi == NULL) {
366                         cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": NOP" << endl;
367                 }
368                 else {
369                         cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": " << std::dec << pi->toString() << endl;
370                 }
371         }
372 }
373
374 void setBreak(const vector<string>& in)
375 {
376         unsigned int addr = 0;
377         if(in.size() == 2) {
378                 try {
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;
382                 }
383                 catch(bad_cast&) {
384                         cerr << "Given parameter is not a valid address" << endl;
385                 }
386         }
387         else {
388                 cerr << "Invalid parameter count!" << endl;
389         }
390 }
391
392 void listBreaks(const vector<string>&)
393 {
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;
396         }
397 }
398
399 void getPerf(const vector<string>&)
400 {
401         cout << "current perfcounter is " << std::dec << global_cpu->getPerf() << endl;
402 }
403
404 void resetPerf(const vector<string>&)
405 {
406         cout << "reset perfcounter" << endl;
407         global_cpu->setPerf(0);
408 }
409
410 void printStatus(const vector<string>&)
411 {
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;
417
418 }
419
420 using boost::lexical_cast;
421 using boost::bad_lexical_cast;
422
423 using namespace std;
424
425 using namespace boost::program_options;
426 namespace po = boost::program_options;
427
428 std::string progName;
429
430 int main(int argc, char* argv[])
431 {
432         progName = argv[0];
433         ifstream inFile;
434         try {
435                 po::options_description desc("Allowed options");
436                 desc.add_options()
437                 ("help,h","produce help message")
438                 ("file,f",value<string>(), "input file")
439                 ;
440
441                 po::positional_options_description p;
442                 p.add("file",1);
443
444                 po::variables_map vm;
445                 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
446                 po::notify(vm);
447
448                 if(vm.count("help")) {
449                         cout << desc << endl;
450                         return EXIT_FAILURE;
451                 }
452
453                 if(vm.count("file")) {
454 #ifdef DEBUG 
455                         cout << "going to open file " << vm["file"].as<string>() << endl;
456 #endif
457                         inFile.open(vm["file"].as<string>(), ios::in);
458                         if(!inFile) {
459                                 cerr << "Error opening file " << vm["file"].as<string>() << endl;
460                                 return EXIT_FAILURE;
461                         }
462                 }
463                 else {
464                         cout << "not input file given!" << endl << endl;
465                         cout << desc << endl;
466                         return EXIT_FAILURE;
467                 }
468         }
469         catch(std::exception& ex) {
470                 cout << ex.what() << endl;
471         }
472
473
474         string dir = "./instr/";
475
476         map<short, Iinstr*> instr;
477
478         CInstrFactory instrFab;
479         try {
480                 instrFab.loadLibsIntoMap(instr, dir);
481         }
482         catch(std::bad_alloc& e) {
483                 cerr << progName << ": bad_alloc caught " << e.what() << endl;
484                 exit(EXIT_FAILURE); 
485         }
486         catch(std::string& s) {
487                 cerr << progName << ": " << s << endl;
488                 exit(EXIT_FAILURE);
489         }
490
491         CCpu cpu(REG_COUNT, RAM_END, PROG_END);
492
493         global_cpu = &cpu;
494
495         Iinstr::setCPU(&cpu);
496
497         disasm disasm(instr);
498
499         Iinstr::setDisasm(&disasm);
500
501         std::string str = "";
502         int addr = 0;
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)) {
506                 int count = 0;
507                 tokens.assign(str);
508                 stringstream out;
509                 int type = 0;
510                 for(auto tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter) {
511                         if(tok_iter == tokens.begin()) {
512                                 try {
513                                         type = lexical_cast<int>(*tok_iter);
514                                         count++;
515                                         continue;
516                                 }
517                                 catch(bad_lexical_cast &) {
518                                         break;
519                                 }
520                                 cout << endl;
521                         }
522                         switch(type) {
523                                 case 0:
524                                         if(count == 1) {
525                                                 try {
526                                                         addr = lexical_cast<uint32_from_hex>(*tok_iter);
527                                                 }
528                                                 catch(bad_lexical_cast& e) {
529                                                         cerr << e.what() << endl;
530                                                         exit(EXIT_FAILURE);
531                                                 }
532                                         }
533                                         else if(count == 2) {
534                                                 try {
535                                                         CDat data = lexical_cast<uint32_from_hex>(*tok_iter);
536                                                         cpu.setRAM(addr, data);
537                                                 }
538                                                 catch(bad_lexical_cast& e) {
539                                                         cerr << e.what() << endl;
540                                                         exit(EXIT_FAILURE);
541                                                 }
542                                         }
543                                         break;
544                                 case 1:
545                                         if(count == 1) {
546                                                 try {
547                                                         addr = lexical_cast<uint32_from_hex>(*tok_iter);
548                                                 }
549                                                 catch(bad_lexical_cast& e) {
550                                                         cerr << e.what() << endl;
551                                                         exit(EXIT_FAILURE);
552                                                 }
553                                         }
554                                         else if(count == 2) {
555                                                 Iinstr *pi = disasm.decode(*tok_iter);
556                                                 cpu.setProg(addr, pi);
557                                         }
558                                         break;
559                                 case 2:
560                                 case 3:
561                                         cerr << "ignoring labels and comments for now" << endl;
562                                         break;
563                                 default:
564                                         cerr << "i was to lazy to implement the other format types for now" << endl;
565                         }
566                         count++;
567                 }
568         }
569         inFile.close();
570
571         cout << endl;
572
573 /*
574         for(int i = 0; i <= 32; i += 4) {
575                 Iinstr *pinstr = cpu.getProg(i);
576                 if(pinstr != NULL) {
577                         cout << i << " : " << std::hex << i << std::dec << " " << pinstr->toString() << endl;
578                 }
579                 else {
580                         cout << "Null at " << i << " : " << std::hex << i << endl;
581                 }
582         }
583
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;
587         }
588 */
589 /*      cpu.setRegister(1, 4);
590         cpu.setRegister(2, 0);
591         cpu.setRAM(0,5);
592         cpu.setRAM(4,0x66334455);
593         cpu.setRAM(8,32);
594         cpu.setRAM(12,45);
595 */
596         // following: job of the bootloader
597         //set stackpointer
598         cpu.setStack(500);
599         //set return to nowhere for ret
600         cpu.setRAM(500,500);
601
602         SReadline Reader;
603
604         MyCompleterContainer Completers;
605
606         CHelpExec HelpExec(Completers);
607
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."));
624
625         Reader.RegisterCompletions(Completers);
626
627         string UserInput;
628         vector<string> Tokens, lastTokens;
629         bool EndOfInput = false;
630
631         //tilab g++44 doesn't like auto here
632         MyCompleterContainer::iterator Found(Completers.end());
633
634         Func lastFunc = NULL;
635
636
637         while(!exitProg) {
638                 UserInput = Reader.GetLine("> ", Tokens, EndOfInput);
639                 if(EndOfInput) {
640                         break;
641                 }
642
643                 if(!Tokens.empty()) {
644                         Found = find_if(Completers.begin(), Completers.end(), LookupFunctor(Tokens));
645
646                         if(Found != Completers.end()) {
647                                 if((*Found).get<1>() != 0) {
648                                         lastFunc = (*Found).get<1>();
649                                         lastFunc(Tokens);
650                                         lastTokens = Tokens;
651                                         //(*Found).get<1>()(Tokens);
652                                 }
653                         }
654                         else {
655                                 lastFunc = NULL;
656                                 cout << "Unknown command. 'help' displays help" << endl;
657                         }
658                 }
659                 else {
660                         if(lastFunc != NULL) {
661                                 lastFunc(lastTokens);
662                         }
663                         else {
664                                 cout << "Unknown command. 'help' displays help" << endl;
665                         }
666                 }
667         }
668
669
670 /*
671         for(int i = 0; ; i++) {
672                 try {
673                         cpu.tick();
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;
678
679                 }
680                 catch(string& e) {
681                         cerr << e << endl;
682                         break;
683                 }
684         }
685 */
686         return EXIT_SUCCESS;
687 }