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