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