a5c970f46302524d2a5d62235e999aaf5d86c8b9
[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 (0x1000)
24 #define PROG_END (0x1000)
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 void doExit(const vector<string>&)
80 {
81         exit(EXIT_SUCCESS);
82 }
83
84 unsigned int convertStringToNum(const std::string& in)
85 {
86         if(in.substr(0,2) == "0x") {
87                 return lexical_cast<uint32_from_hex>(in);
88         }
89         else {
90                 return lexical_cast<unsigned int>(in);
91         }
92 }
93
94
95 void execStep(const vector<string>& in)
96 {
97         int count = 1;
98         if(in.size() == 2) {
99                 try {
100                         count = convertStringToNum(in.back());
101                 }
102                 catch(bad_cast&) {
103                         cerr << "given parameter to step is not a number" << endl;
104                 }
105         }
106         while(count > 0) {
107                 try {
108                         auto breakp = find(breakpoints.begin(), breakpoints.end(), global_cpu->getNextPC());
109                         if(breakp == breakpoints.end() || ignoreBreak) {
110                                 global_cpu->tick();
111                                 ignoreBreak = false;
112                         }
113                         else {
114                                 ignoreBreak = true;
115                                 cout << "Breakpoint 0x" << std::hex << setw(8) << setfill('0') << *breakp << std::hex << " hit" << endl;
116                                 break;
117                         }
118                 }
119                 catch(std::string& e) {
120                         cerr << e << endl;
121                 }
122                 count--;
123         }
124 }
125
126 void execRun(const vector<string>&)
127 {
128         while(1) {
129                 try {
130                         auto breakp = find(breakpoints.begin(), breakpoints.end(), global_cpu->getNextPC());
131                         if(breakp == breakpoints.end() || ignoreBreak) {
132                                 global_cpu->tick();
133                                 ignoreBreak = false;
134                         }
135                         else {
136                                 ignoreBreak = true;
137                                 cout << "Breakpoint 0x" << std::hex << setw(8) << setfill('0') << *breakp << std::hex << " hit" << endl;
138                                 return;
139                         }
140                 }
141                 catch(std::string& e) {
142                         cerr << e << endl;
143                         return;
144                 }
145         }
146 }
147
148 void setPC(const vector<string>& in)
149 {
150         CDat addr = 0;
151         if(in.size() == 2) {
152                 try {
153                         addr = convertStringToNum(in.back());
154                 }
155                 catch(bad_cast&) {
156                         cerr << "given parameter is not a number" << endl;
157                         return;
158                 }
159         }
160         global_cpu->setNextPC(addr);
161         cout << "Set programcounter to 0x" << std::hex << setw(8) << setfill('0') << addr << std::dec << endl;
162 }
163
164
165 void printReg(const vector<string>& in)
166 {
167         int i, start = 0, end = REG_COUNT-1;
168         /* Todo: 
169          * 1) make 2 columns
170          */
171
172         if(in.size() >= 2) {
173                 try {
174                         start = convertStringToNum(in[1]);
175                         if(start < 0 || start > (REG_COUNT-1)) {
176                                 cerr << "start is out of range" << endl;
177                                 return;
178                         }
179                         end = start;
180                 }
181                 catch(bad_cast&) {
182                         cerr << "given parameter is not a number" << endl;
183                         return;
184                 }
185         }
186
187         if(in.size() >= 3) {
188                 try {
189                         end = convertStringToNum(in[2]);
190                         if(start > end || end > (REG_COUNT-1)) {
191                                 cerr << "end is out of range or smaller than start" << endl;
192                                 return;
193                         }
194                 }
195                 catch(bad_cast&) {
196                         cerr << "given parameter is not a number" << endl;
197                         return;
198                 }
199         }
200         
201         for(i = start; i <= end; i++) {
202                 cout << setw(2) << setfill('0') << i << ": 0x";
203                 cout << std::hex <<  setw(8) << setfill('0') << global_cpu->getRegister(i) << " ";
204                 cout << std::dec << setw(10) << setfill(' ') << global_cpu->getRegister(i) << " ";
205                 cout << std::dec << setw(10) << setfill(' ') << (int)global_cpu->getRegister(i) << endl;
206         }
207 }
208
209 void setReg(const vector<string>& in)
210 {
211         int reg = 0;
212         CDat val = 0;
213
214         if(in.size() >= 3) {
215                 try {
216                         reg = convertStringToNum(in[1]);
217                         if(reg < 0 || reg > (REG_COUNT-1)) {
218                                 cerr << "register is out of range" << endl;
219                                 return;
220                         }
221
222                         val = convertStringToNum(in[2]);
223
224                         cout << "Setting register " << reg << " to 0x" << std::hex << setw(8) << setfill('0') << val << std::dec << endl;
225                         global_cpu->setRegister(reg,val);
226                 }
227                 catch(bad_cast&) {
228                         cerr << "given parameter is not a number" << endl;
229                         return;
230                 }
231         }
232 }
233
234 void printRAM(const vector<string>& in)
235 {
236         int i, start = 0, end = 15;
237         /* Todo: 
238          * 1) make 2 columns
239          */
240
241         if(in.size() >= 2) {
242                 try {
243                         start = convertStringToNum(in[1]);
244                         if(start < 0 || start > (RAM_END-1)) {
245                                 cerr << "start is out of range" << endl;
246                                 return;
247                         }
248                         start = (start & (~(BYTE_COUNT-1))) / BYTE_COUNT;
249                         end = start;
250                 }
251                 catch(bad_cast&) {
252                         cerr << "given parameter is not a number" << endl;
253                         return;
254                 }
255         }
256
257         if(in.size() >= 3) {
258                 try {
259                         end = convertStringToNum(in[2]);
260                         if(start > end || end > (RAM_END-1)) {
261                                 cerr << "end is out of range or smaller than start" << endl;
262                                 return;
263                         }
264                         if(end % BYTE_COUNT != 0) {
265                                 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT)+1;
266                         }
267                         else {
268                                 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT);
269                         }
270                 }
271                 catch(bad_cast&) {
272                         cerr << "given parameter is not a number" << endl;
273                         return;
274                 }
275         }
276         for(i = start*BYTE_COUNT; i <= end*BYTE_COUNT; i += BYTE_COUNT) {
277                 cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": 0x";
278                 cout << std::hex << setw(8)  << setfill('0') << global_cpu->getRAM(i) << " ";
279                 cout << std::dec << setw(10) << setfill(' ') << global_cpu->getRAM(i) << " ";
280                 cout << std::dec << setw(10) << setfill(' ') << (int)global_cpu->getRAM(i) << endl;
281         }
282 }
283
284 void setRam(const vector<string>& in)
285 {
286         int addr = 0;
287         CDat val = 0;
288
289         if(in.size() >= 3) {
290                 try {
291                         addr = convertStringToNum(in[1]);
292                         if(addr < 0 || addr > (RAM_END-1)) {
293                                 cerr << "RAM-Address is out of range" << endl;
294                                 return;
295                         }
296
297                         addr = (addr & (~(BYTE_COUNT-1))) / BYTE_COUNT;
298                         val = convertStringToNum(in[2]);
299
300                         addr *= BYTE_COUNT;
301
302                         cout << "Setting RAM-Address 0x" << std::hex << setw(8) << setfill('0') << addr;
303                         cout << " to 0x" << setw(8) << setfill('0') << val << std::dec << endl;
304                         global_cpu->setRAM(addr,val);
305                 }
306                 catch(bad_cast&) {
307                         cerr << "given parameter is not a number" << endl;
308                         return;
309                 }
310         }
311 }
312 void printPROG(const vector<string>& in)
313 {
314         int i, start = 0, end = 15;
315         /* Todo: 
316          * 1) make 2 columns
317          */
318
319         if(in.size() >= 2 && in[1][0] == 'c') {
320                 start = global_cpu->getCurPC() / BYTE_COUNT;
321                 end = start + 9;
322         }
323         else if(in.size() >= 2) {
324                 try {
325                         start = convertStringToNum(in[1]);
326                         if(start < 0 || start > (PROG_END-1)) {
327                                 cerr << "start is out of range" << endl;
328                                 return;
329                         }
330                         start = (start & (~(BYTE_COUNT-1))) / BYTE_COUNT;
331                         end = start;
332                 }
333                 catch(bad_cast&) {
334                         cerr << "given parameter is not a number" << endl;
335                         return;
336                 }
337         }
338
339         if(in.size() >= 3) {
340                 try {
341                         end = convertStringToNum(in[2]);
342                         if(start > end || end > (PROG_END-1)) {
343                                 cerr << "end is out of range or smaller than start" << endl;
344                                 return;
345                         }
346                         if(end % BYTE_COUNT != 0) {
347                                 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT)+1;
348                         }
349                         else {
350                                 end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT);
351                         }
352
353                 }
354                 catch(bad_cast&) {
355                         cerr << "given parameter is not a number" << endl;
356                         return;
357                 }
358         }
359
360         
361         for(i = start*BYTE_COUNT; i <= end*BYTE_COUNT; i += BYTE_COUNT) {
362                 Iinstr* pi = global_cpu->getProg(i);
363                 if(pi == NULL) {
364                         cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": NOP" << endl;
365                 }
366                 else {
367                         cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": " << std::dec << pi->toString() << endl;
368                 }
369         }
370 }
371
372 void setBreak(const vector<string>& in)
373 {
374         unsigned int addr = 0;
375         if(in.size() == 2) {
376                 try {
377                         addr = convertStringToNum(in.back());
378                         breakpoints.push_back(addr);
379                         cout << "Breakpoint 0x" << std::hex << setw(8) << setfill('0') << addr << std::dec << " set" << endl;
380                 }
381                 catch(bad_cast&) {
382                         cerr << "Given parameter is not a valid address" << endl;
383                 }
384         }
385         else {
386                 cerr << "Invalid parameter count!" << endl;
387         }
388 }
389
390 void listBreaks(const vector<string>&)
391 {
392         for(auto iter = breakpoints.begin(); iter != breakpoints.end(); ++iter) {
393                 cout << "Breakpoint at 0x" << std::hex << setw(8) << setfill('0') << *iter << std::dec << endl;
394         }
395 }
396
397 void getPerf(const vector<string>&)
398 {
399         cout << "current perfcounter is " << std::dec << global_cpu->getPerf() << endl;
400 }
401
402 void resetPerf(const vector<string>&)
403 {
404         cout << "reset perfcounter" << endl;
405         global_cpu->setPerf(0);
406 }
407
408 void printStatus(const vector<string>&)
409 {
410         CDat stackp = global_cpu->getStack();
411         CDat stackd = global_cpu->getRAM(stackp);
412         cout << "Stack pointer: 0x" << std::hex << setw(8) << setfill('0') << stackp << " @stackpointer: 0x" << setw(8) << stackd << std::dec << " (" << stackd << ")" << endl;
413         cout << "PSW: 0x" << std::hex << setw(8) << setfill('0') << global_cpu->getFlags() << std::dec << endl;
414         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;
415
416 }
417
418 using boost::lexical_cast;
419 using boost::bad_lexical_cast;
420
421 using namespace std;
422
423 using namespace boost::program_options;
424 namespace po = boost::program_options;
425
426 std::string progName;
427
428 int main(int argc, char* argv[])
429 {
430         progName = argv[0];
431         ifstream inFile;
432         try {
433                 po::options_description desc("Allowed options");
434                 desc.add_options()
435                 ("help,h","produce help message")
436                 ("file,f",value<string>(), "input file")
437                 ;
438
439                 po::positional_options_description p;
440                 p.add("file",1);
441
442                 po::variables_map vm;
443                 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
444                 po::notify(vm);
445
446                 if(vm.count("help")) {
447                         cout << desc << endl;
448                         return EXIT_FAILURE;
449                 }
450
451                 if(vm.count("file")) {
452 #ifdef DEBUG 
453                         cout << "going to open file " << vm["file"].as<string>() << endl;
454 #endif
455                         inFile.open(vm["file"].as<string>(), ios::in);
456                         if(!inFile) {
457                                 cerr << "Error opening file " << vm["file"].as<string>() << endl;
458                                 return EXIT_FAILURE;
459                         }
460                 }
461                 else {
462                         cout << "not input file given!" << endl << endl;
463                         cout << desc << endl;
464                         return EXIT_FAILURE;
465                 }
466         }
467         catch(std::exception& ex) {
468                 cout << ex.what() << endl;
469         }
470
471
472         string dir = "./instr/";
473
474         map<short, Iinstr*> instr;
475
476         CInstrFactory instrFab;
477         try {
478                 instrFab.loadLibsIntoMap(instr, dir);
479         }
480         catch(std::bad_alloc& e) {
481                 cerr << progName << ": bad_alloc caught " << e.what() << endl;
482                 exit(EXIT_FAILURE); 
483         }
484         catch(std::string& s) {
485                 cerr << progName << ": " << s << endl;
486                 exit(EXIT_FAILURE);
487         }
488
489         CCpu cpu(REG_COUNT, RAM_END, PROG_END);
490
491         global_cpu = &cpu;
492
493         Iinstr::setCPU(&cpu);
494
495         disasm disasm(instr);
496
497         Iinstr::setDisasm(&disasm);
498
499         std::string str = "";
500         int addr = 0;
501         boost::char_separator<char> sep(";", "", boost::keep_empty_tokens);
502         boost::tokenizer<boost::char_separator<char> > tokens(str, sep);
503         while(getline(inFile, str)) {
504                 int count = 0;
505                 tokens.assign(str);
506                 stringstream out;
507                 int type = 0;
508                 for(auto tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter) {
509                         if(tok_iter == tokens.begin()) {
510                                 try {
511                                         type = lexical_cast<int>(*tok_iter);
512                                         count++;
513                                         continue;
514                                 }
515                                 catch(bad_lexical_cast &) {
516                                         break;
517                                 }
518                                 cout << endl;
519                         }
520                         switch(type) {
521                                 case 0:
522                                         if(count == 1) {
523                                                 try {
524                                                         addr = lexical_cast<uint32_from_hex>(*tok_iter);
525                                                 }
526                                                 catch(bad_lexical_cast& e) {
527                                                         cerr << e.what() << endl;
528                                                         exit(EXIT_FAILURE);
529                                                 }
530                                         }
531                                         else if(count == 2) {
532                                                 try {
533                                                         CDat data = lexical_cast<uint32_from_hex>(*tok_iter);
534                                                         cpu.setRAM(addr, data);
535                                                 }
536                                                 catch(bad_lexical_cast& e) {
537                                                         cerr << e.what() << endl;
538                                                         exit(EXIT_FAILURE);
539                                                 }
540                                         }
541                                         break;
542                                 case 1:
543                                         if(count == 1) {
544                                                 try {
545                                                         addr = lexical_cast<uint32_from_hex>(*tok_iter);
546                                                 }
547                                                 catch(bad_lexical_cast& e) {
548                                                         cerr << e.what() << endl;
549                                                         exit(EXIT_FAILURE);
550                                                 }
551                                         }
552                                         else if(count == 2) {
553                                                 Iinstr *pi = disasm.decode(*tok_iter);
554                                                 cpu.setProg(addr, pi);
555                                         }
556                                         break;
557                                 case 2:
558                                 case 3:
559                                         cerr << "ignoring labels and comments for now" << endl;
560                                         break;
561                                 default:
562                                         cerr << "i was to lazy to implement the other format types for now" << endl;
563                         }
564                         count++;
565                 }
566         }
567         inFile.close();
568
569         cout << endl;
570
571 /*
572         for(int i = 0; i <= 32; i += 4) {
573                 Iinstr *pinstr = cpu.getProg(i);
574                 if(pinstr != NULL) {
575                         cout << i << " : " << std::hex << i << std::dec << " " << pinstr->toString() << endl;
576                 }
577                 else {
578                         cout << "Null at " << i << " : " << std::hex << i << endl;
579                 }
580         }
581
582         for(int i = 0; i <= 32; i += 4) {
583                 CDat data = cpu.getRAM(i);
584                 cout << i << " : " << std::hex << i << std::dec << " " << data << endl;
585         }
586 */
587 /*      cpu.setRegister(1, 4);
588         cpu.setRegister(2, 0);
589         cpu.setRAM(0,5);
590         cpu.setRAM(4,0x66334455);
591         cpu.setRAM(8,32);
592         cpu.setRAM(12,45);
593 */
594         // following: job of the bootloader
595         //set stackpointer
596         cpu.setStack(500);
597         //set return to nowhere for ret
598         cpu.setRAM(500,500);
599
600         SReadline Reader;
601
602         MyCompleterContainer Completers;
603
604         CHelpExec HelpExec(Completers);
605
606         Completers.push_back(CompleterElement("help", boost::bind1st( boost::mem_fun( &CHelpExec::operator()), &HelpExec), "Prints this message"));
607         Completers.push_back(CompleterElement("quit", &doExit, "Exits program"));
608         Completers.push_back(CompleterElement("exit", &doExit, "Exits program"));
609         Completers.push_back(CompleterElement("step [count]",&execStep, "Runs [count] ticks. if count is not given one tick is executed."));
610         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."));
611         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."));
612         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."));
613         Completers.push_back(CompleterElement("break addr",&setBreak, "Sets a breakpoint for address addr."));
614         Completers.push_back(CompleterElement("listbreaks",&listBreaks, "Lists all breakpoints."));
615         Completers.push_back(CompleterElement("run",&execRun, "Runs till next breakpoint or end of program."));
616         Completers.push_back(CompleterElement("setpc [num]",&setPC, "Sets PC to num. if num is omitted 0 is used."));
617         Completers.push_back(CompleterElement("setreg [s] [num]",&setReg, "Sets Register s to num."));
618         Completers.push_back(CompleterElement("setdata [s] [num]",&setRam, "Sets RAM-Addr s to num."));
619         Completers.push_back(CompleterElement("status",&printStatus, "Prints status of CPU."));
620         Completers.push_back(CompleterElement("getperf",&getPerf, "Prints performance counter."));
621         Completers.push_back(CompleterElement("resetperf",&resetPerf, "Resets performance counter to 0."));
622
623         Reader.RegisterCompletions(Completers);
624
625         string UserInput;
626         vector<string> Tokens, lastTokens;
627         bool EndOfInput = false;
628
629         //tilab g++44 doesn't like auto here
630         MyCompleterContainer::iterator Found(Completers.end());
631
632         Func lastFunc = NULL;
633
634
635         while(1) {
636                 UserInput = Reader.GetLine("> ", Tokens, EndOfInput);
637                 if(EndOfInput) {
638                         break;
639                 }
640
641                 if(!Tokens.empty()) {
642                         Found = find_if(Completers.begin(), Completers.end(), LookupFunctor(Tokens));
643
644                         if(Found != Completers.end()) {
645                                 if((*Found).get<1>() != 0) {
646                                         lastFunc = (*Found).get<1>();
647                                         lastFunc(Tokens);
648                                         lastTokens = Tokens;
649                                         //(*Found).get<1>()(Tokens);
650                                 }
651                         }
652                         else {
653                                 lastFunc = NULL;
654                                 cout << "Unknown command. 'help' displays help" << endl;
655                         }
656                 }
657                 else {
658                         if(lastFunc != NULL) {
659                                 lastFunc(lastTokens);
660                         }
661                         else {
662                                 cout << "Unknown command. 'help' displays help" << endl;
663                         }
664                 }
665         }
666
667
668 /*
669         for(int i = 0; ; i++) {
670                 try {
671                         cpu.tick();
672                         cout << " reg0: " << cpu.getRegister(0) <<  " reg1: " << cpu.getRegister(1);
673                         cout << " reg2: " << cpu.getRegister(2) <<  " reg3: " << cpu.getRegister(3);
674                         cout << " reg4: " << cpu.getRegister(4) <<  " reg5: " << cpu.getRegister(5);
675                         cout << endl << endl;
676
677                 }
678                 catch(string& e) {
679                         cerr << e << endl;
680                         break;
681                 }
682         }
683 */
684         return EXIT_SUCCESS;
685 }