sim: bugfix/feature @ help/status
[calu.git] / 3b_sim / sim.cpp
index ae5b16bfc781818a9dc2eee0c2aa03ec3e589526..764f21632d82adaeda7073cbf328667f8f71d448 100644 (file)
 #include <iostream>
+#include <iomanip>
 #include <fstream>
 #include <boost/tokenizer.hpp>
 #include <boost/program_options.hpp>
 #include <boost/lexical_cast.hpp>
 #include <string>
 #include <map>
+#include <list>
+
+#include <boost/function.hpp>
+#include <boost/functional.hpp>
+#include <boost/tuple/tuple.hpp>
 
 #include "disasm.h"
 #include "ccpu.hpp"
 #include "CInstrFactory.hpp"
+#include "uint32_from_hex.hpp"
+
+#include "SReadline/SReadline.h"
+using namespace swift;
+
+#define RAM_END (1000)
+#define PROG_END (1000)
+#define REG_COUNT (16)
+
+typedef boost::function<void (const vector<string> &)> Func;
+typedef boost::tuple<string, Func, string> CompleterElement;
+
+typedef list<CompleterElement> MyCompleterContainer;
+
+class LookupFunctor
+{
+       public:
+               // Creates a functor and memorises tokens
+               LookupFunctor(const vector<string>&  tokens) : Tokens(tokens) {}
+
+               // Compares the first token only
+               bool operator()(const CompleterElement& ele) const
+               {
+                       return (strncmp(Tokens.begin()->c_str(), ele.get<0>().c_str(), Tokens.begin()->size()) == 0);
+               }
+
+       private:
+               const vector<string> &Tokens;
+};
+
+
+
+
+class CHelpExec
+{
+       private:
+               const MyCompleterContainer &m_completers;
+
+       public:
+               CHelpExec(const MyCompleterContainer &cont) : m_completers(cont) {}
+
+               void operator() (const vector<string>&)
+               {
+                       cout << "Available commands: " << endl;
+                       for(auto iter = m_completers.begin(); iter != m_completers.end(); ++iter) {
+                               cout << setw(19) << setfill(' ') << (*iter).get<0>() << ": " << (*iter).get<2>() << endl;
+                       }
+               }
+};
+
+void close_prog(const std::vector<std::string> &);
+
+CCpu* Iinstr::m_cpu;
+
+CCpu* global_cpu = NULL;
+
+vector<CDat> breakpoints;
+
+bool ignoreBreak = false;
+
+void doExit(const vector<string>&)
+{
+       exit(EXIT_SUCCESS);
+}
+
+unsigned int convertStringToNum(const std::string& in)
+{
+       if(in.substr(0,2) == "0x") {
+               return lexical_cast<uint32_from_hex>(in);
+       }
+       else {
+               return lexical_cast<unsigned int>(in);
+       }
+}
+
+
+void execStep(const vector<string>& in)
+{
+       int count = 1;
+       if(in.size() == 2) {
+               try {
+                       count = convertStringToNum(in.back());
+               }
+               catch(bad_cast&) {
+                       cerr << "given parameter to step is not a number" << endl;
+               }
+       }
+       while(count > 0) {
+               try {
+                       auto breakp = find(breakpoints.begin(), breakpoints.end(), global_cpu->getNextPC());
+                       if(breakp == breakpoints.end() || ignoreBreak) {
+                               global_cpu->tick();
+                               ignoreBreak = false;
+                       }
+                       else {
+                               ignoreBreak = true;
+                               cout << "Breakpoint 0x" << std::hex << setw(8) << setfill('0') << *breakp << std::hex << " hit" << endl;
+                               break;
+                       }
+               }
+               catch(std::string& e) {
+                       cerr << e << endl;
+               }
+               count--;
+       }
+}
+
+void execRun(const vector<string>&)
+{
+       while(1) {
+               try {
+                       auto breakp = find(breakpoints.begin(), breakpoints.end(), global_cpu->getNextPC());
+                       if(breakp == breakpoints.end() || ignoreBreak) {
+                               global_cpu->tick();
+                               ignoreBreak = false;
+                       }
+                       else {
+                               ignoreBreak = true;
+                               cout << "Breakpoint 0x" << std::hex << setw(8) << setfill('0') << *breakp << std::hex << " hit" << endl;
+                               return;
+                       }
+               }
+               catch(std::string& e) {
+                       cerr << e << endl;
+                       return;
+               }
+       }
+}
+
+void setPC(const vector<string>& in)
+{
+       CDat addr = 0;
+       if(in.size() == 2) {
+               try {
+                       addr = convertStringToNum(in.back());
+               }
+               catch(bad_cast&) {
+                       cerr << "given parameter is not a number" << endl;
+                       return;
+               }
+       }
+       global_cpu->setNextPC(addr);
+       cout << "Set programcounter to 0x" << std::hex << setw(8) << setfill('0') << addr << std::dec << endl;
+}
+
+
+void printReg(const vector<string>& in)
+{
+       int i, start = 0, end = REG_COUNT-1;
+       /* Todo: 
+        * 1) make 2 columns
+        */
+
+       if(in.size() >= 2) {
+               try {
+                       start = convertStringToNum(in[1]);
+                       if(start < 0 || start > (REG_COUNT-1)) {
+                               cerr << "start is out of range" << endl;
+                               return;
+                       }
+                       end = start;
+               }
+               catch(bad_cast&) {
+                       cerr << "given parameter is not a number" << endl;
+                       return;
+               }
+       }
+
+       if(in.size() >= 3) {
+               try {
+                       end = convertStringToNum(in[2]);
+                       if(start > end || end > (REG_COUNT-1)) {
+                               cerr << "end is out of range or smaller than start" << endl;
+                               return;
+                       }
+               }
+               catch(bad_cast&) {
+                       cerr << "given parameter is not a number" << endl;
+                       return;
+               }
+       }
+       
+       for(i = start; i <= end; i++) {
+               cout << setw(2) << setfill('0') << i << ": 0x";
+               cout << std::hex <<  setw(8) << setfill('0') << global_cpu->getRegister(i) << " ";
+               cout << std::dec << setw(10) << setfill(' ') << global_cpu->getRegister(i) << " ";
+               cout << std::dec << setw(10) << setfill(' ') << (int)global_cpu->getRegister(i) << endl;
+       }
+}
+
+void setReg(const vector<string>& in)
+{
+       int reg = 0;
+       CDat val = 0;
+
+       if(in.size() >= 3) {
+               try {
+                       reg = convertStringToNum(in[1]);
+                       if(reg < 0 || reg > (REG_COUNT-1)) {
+                               cerr << "register is out of range" << endl;
+                               return;
+                       }
+
+                       val = convertStringToNum(in[2]);
+
+                       cout << "Setting register " << reg << " to 0x" << std::hex << setw(8) << setfill('0') << val << std::dec << endl;
+                       global_cpu->setRegister(reg,val);
+               }
+               catch(bad_cast&) {
+                       cerr << "given parameter is not a number" << endl;
+                       return;
+               }
+       }
+}
+
+void printRAM(const vector<string>& in)
+{
+       int i, start = 0, end = 15;
+       /* Todo: 
+        * 1) make 2 columns
+        */
+
+       if(in.size() >= 2) {
+               try {
+                       start = convertStringToNum(in[1]);
+                       if(start < 0 || start > (RAM_END-1)) {
+                               cerr << "start is out of range" << endl;
+                               return;
+                       }
+                       start = (start & (~(BYTE_COUNT-1))) / BYTE_COUNT;
+                       end = start;
+               }
+               catch(bad_cast&) {
+                       cerr << "given parameter is not a number" << endl;
+                       return;
+               }
+       }
+
+       if(in.size() >= 3) {
+               try {
+                       end = convertStringToNum(in[2]);
+                       if(start > end || end > (RAM_END-1)) {
+                               cerr << "end is out of range or smaller than start" << endl;
+                               return;
+                       }
+                       if(end % BYTE_COUNT != 0) {
+                               end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT)+1;
+                       }
+                       else {
+                               end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT);
+                       }
+               }
+               catch(bad_cast&) {
+                       cerr << "given parameter is not a number" << endl;
+                       return;
+               }
+       }
+       for(i = start*BYTE_COUNT; i <= end*BYTE_COUNT; i += BYTE_COUNT) {
+               cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": 0x";
+               cout << std::hex << setw(8)  << setfill('0') << global_cpu->getRAM(i) << " ";
+               cout << std::dec << setw(10) << setfill(' ') << global_cpu->getRAM(i) << " ";
+               cout << std::dec << setw(10) << setfill(' ') << (int)global_cpu->getRAM(i) << endl;
+       }
+}
+
+void setRam(const vector<string>& in)
+{
+       int addr = 0;
+       CDat val = 0;
+
+       if(in.size() >= 3) {
+               try {
+                       addr = convertStringToNum(in[1]);
+                       if(addr < 0 || addr > (RAM_END-1)) {
+                               cerr << "RAM-Address is out of range" << endl;
+                               return;
+                       }
+
+                       addr = (addr & (~(BYTE_COUNT-1))) / BYTE_COUNT;
+                       val = convertStringToNum(in[2]);
+
+                       cout << "Setting RAM-Address " << addr << " to 0x" << std::hex << setw(8) << setfill('0') << val << std::dec << endl;
+                       global_cpu->setRAM(addr,val);
+               }
+               catch(bad_cast&) {
+                       cerr << "given parameter is not a number" << endl;
+                       return;
+               }
+       }
+}
+void printPROG(const vector<string>& in)
+{
+       int i, start = 0, end = 15;
+       /* Todo: 
+        * 1) make 2 columns
+        */
+
+       if(in.size() >= 2) {
+               try {
+                       start = convertStringToNum(in[1]);
+                       if(start < 0 || start > (PROG_END-1)) {
+                               cerr << "start is out of range" << endl;
+                               return;
+                       }
+                       start = (start & (~(BYTE_COUNT-1))) / BYTE_COUNT;
+                       end = start;
+               }
+               catch(bad_cast&) {
+                       cerr << "given parameter is not a number" << endl;
+                       return;
+               }
+       }
+
+       if(in.size() >= 3) {
+               try {
+                       end = convertStringToNum(in[2]);
+                       if(start > end || end > (PROG_END-1)) {
+                               cerr << "end is out of range or smaller than start" << endl;
+                               return;
+                       }
+                       if(end % BYTE_COUNT != 0) {
+                               end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT)+1;
+                       }
+                       else {
+                               end = ((end & (~(BYTE_COUNT-1))) / BYTE_COUNT);
+                       }
+
+               }
+               catch(bad_cast&) {
+                       cerr << "given parameter is not a number" << endl;
+                       return;
+               }
+       }
+       
+       for(i = start*BYTE_COUNT; i <= end*BYTE_COUNT; i += BYTE_COUNT) {
+               Iinstr* pi = global_cpu->getProg(i);
+               if(pi == NULL) {
+                       cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": NOP" << endl;
+               }
+               else {
+                       cout << std::hex << "0x" << setw(8) << setfill('0') << i << ": " << std::dec << pi->toString() << endl;
+               }
+       }
+}
+
+void setBreak(const vector<string>& in)
+{
+       unsigned int addr = 0;
+       if(in.size() == 2) {
+               try {
+                       addr = convertStringToNum(in.back());
+                       breakpoints.push_back(addr);
+                       cout << "Breakpoint 0x" << std::hex << setw(8) << setfill('0') << addr << std::dec << " set" << endl;
+               }
+               catch(bad_cast&) {
+                       cerr << "Given parameter is not a valid address" << endl;
+               }
+       }
+       else {
+               cerr << "Invalid parameter count!" << endl;
+       }
+}
+
+void listBreaks(const vector<string>&)
+{
+       for(auto iter = breakpoints.begin(); iter != breakpoints.end(); ++iter) {
+               cout << "Breakpoint at 0x" << std::hex << setw(8) << setfill('0') << *iter << std::dec << endl;
+       }
+}
+
+void printStatus(const vector<string>&)
+{
+       CDat stackp = global_cpu->getStack();
+       CDat stackd = global_cpu->getRAM(stackp);
+       cout << "Stack pointer: 0x" << std::hex << setw(8) << setfill('0') << stackp << " @stackpointer: 0x" << setw(8) << stackd << std::dec << " (" << stackd << ")" << endl;
+       cout << "PSW: 0x" << std::hex << setw(8) << setfill('0') << global_cpu->getFlags() << std::dec << endl;
+       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;
+
+}
 
 using boost::lexical_cast;
 using boost::bad_lexical_cast;
@@ -81,8 +466,11 @@ int main(int argc, char* argv[])
                exit(EXIT_FAILURE);
        }
 
+       CCpu cpu(REG_COUNT, RAM_END, PROG_END);
 
-       CCpu cpu;
+       global_cpu = &cpu;
+
+       Iinstr::setCPU(&cpu);
 
 
        std::string str = "";
@@ -108,61 +496,166 @@ int main(int argc, char* argv[])
                                cout << endl;
                        }
                        switch(type) {
-                               case 2:
+                               case 0:
                                        if(count == 1) {
-                                               cout << "; ";
+                                               try {
+                                                       addr = lexical_cast<uint32_from_hex>(*tok_iter);
+                                               }
+                                               catch(bad_lexical_cast& e) {
+                                                       cerr << e.what() << endl;
+                                                       exit(EXIT_FAILURE);
+                                               }
                                        }
-                                       cout << *tok_iter;
-                                       break;
-                               case 3:
-                                       if((*tok_iter).size() > 0) {
-                                               if(count > 1) {
-                                                       cout << endl;
+                                       else if(count == 2) {
+                                               try {
+                                                       CDat data = lexical_cast<uint32_from_hex>(*tok_iter);
+                                                       cpu.setRAM(addr, data);
+                                               }
+                                               catch(bad_lexical_cast& e) {
+                                                       cerr << e.what() << endl;
+                                                       exit(EXIT_FAILURE);
                                                }
-                                               cout << *tok_iter << ":";
                                        }
                                        break;
                                case 1:
                                        if(count == 1) {
-                                               out << "[0x" << *tok_iter << "]: ";
-                                               addr = lexical_cast<int>(*tok_iter);
-                                       }
-                                       else if(count == 2) {
-                                               cpu.setProg(addr, disasm.decode(*tok_iter));
-                                       }
-                                       else if(count == 3) {
-                                               //code saved in hex-file
-                                               //cout << *tok_iter ;
-                                       }
-                                       else if(count == 4) {
-                                               /* label */
-                                               if((*tok_iter).size() > 0) {
-                                                       cout << *tok_iter << ":" << endl;
+                                               try {
+                                                       addr = lexical_cast<uint32_from_hex>(*tok_iter);
                                                }
-                                               cout << out.str();
-                                       }
-                                       else if(count == 5) {
-                                               if((*tok_iter).size() > 0) {
-                                                       cout << " ;";
+                                               catch(bad_lexical_cast& e) {
+                                                       cerr << e.what() << endl;
+                                                       exit(EXIT_FAILURE);
                                                }
                                        }
-
-                                       if(count >= 5) {
-                                               cout << *tok_iter;
+                                       else if(count == 2) {
+                                               Iinstr *pi = disasm.decode(*tok_iter);
+                                               cpu.setProg(addr, pi);
                                        }
                                        break;
+                               case 2:
+                               case 3:
+                                       cerr << "ignoring labels and comments for now" << endl;
+                                       break;
                                default:
                                        cerr << "i was to lazy to implement the other format types for now" << endl;
                        }
                        count++;
                }
-               if(type == 1 && count <= 4) {
-                       cout << out.str();
-               }
-               cout << endl;
        }
        inFile.close();
 
        cout << endl;
+
+/*
+       for(int i = 0; i <= 32; i += 4) {
+               Iinstr *pinstr = cpu.getProg(i);
+               if(pinstr != NULL) {
+                       cout << i << " : " << std::hex << i << std::dec << " " << pinstr->toString() << endl;
+               }
+               else {
+                       cout << "Null at " << i << " : " << std::hex << i << endl;
+               }
+       }
+
+       for(int i = 0; i <= 32; i += 4) {
+               CDat data = cpu.getRAM(i);
+               cout << i << " : " << std::hex << i << std::dec << " " << data << endl;
+       }
+*/
+       cpu.setRegister(1, 4);
+       cpu.setRegister(2, 0);
+       cpu.setRAM(0,5);
+       cpu.setRAM(4,50);
+       cpu.setRAM(8,32);
+       cpu.setRAM(12,45);
+
+       // following: job of the bootloader
+       //set stackpointer
+       cpu.setStack(500);
+       //set return to nowhere for ret
+       cpu.setRAM(500,50);
+
+       SReadline Reader;
+
+       MyCompleterContainer Completers;
+
+       CHelpExec HelpExec(Completers);
+
+       Completers.push_back(CompleterElement("help", boost::bind1st( boost::mem_fun( &CHelpExec::operator()), &HelpExec), "Prints this message"));
+       Completers.push_back(CompleterElement("quit", &doExit, "Exits program"));
+       Completers.push_back(CompleterElement("exit", &doExit, "Exits program"));
+       Completers.push_back(CompleterElement("step [count]",&execStep, "Runs [count] ticks. if count is not given one tick is executed."));
+       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."));
+       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."));
+       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."));
+       Completers.push_back(CompleterElement("break addr",&setBreak, "Sets a breakpoint for address addr."));
+       Completers.push_back(CompleterElement("listbreaks",&listBreaks, "Lists all breakpoints."));
+       Completers.push_back(CompleterElement("run",&execRun, "Runs till next breakpoint or end of program."));
+       Completers.push_back(CompleterElement("setpc [num]",&setPC, "Sets PC to num. if num is omitted 0 is used."));
+       Completers.push_back(CompleterElement("setreg [s] [num]",&setReg, "Sets Register s to num."));
+       Completers.push_back(CompleterElement("setdata [s] [num]",&setRam, "Sets RAM-Addr s to num."));
+       Completers.push_back(CompleterElement("status",&printStatus, "Prints status of CPU."));
+
+       Reader.RegisterCompletions(Completers);
+
+       string UserInput;
+       vector<string> Tokens, lastTokens;
+       bool EndOfInput = false;
+
+       //tilab g++44 doesn't like auto here
+       MyCompleterContainer::iterator Found(Completers.end());
+
+       Func lastFunc = NULL;
+
+
+       while(1) {
+               UserInput = Reader.GetLine("> ", Tokens, EndOfInput);
+               if(EndOfInput) {
+                       break;
+               }
+
+               if(!Tokens.empty()) {
+                       Found = find_if(Completers.begin(), Completers.end(), LookupFunctor(Tokens));
+
+                       if(Found != Completers.end()) {
+                               if((*Found).get<1>() != 0) {
+                                       lastFunc = (*Found).get<1>();
+                                       lastFunc(Tokens);
+                                       lastTokens = Tokens;
+                                       //(*Found).get<1>()(Tokens);
+                               }
+                       }
+                       else {
+                               lastFunc = NULL;
+                               cout << "Unknown command. 'help' displays help" << endl;
+                       }
+               }
+               else {
+                       if(lastFunc != NULL) {
+                               lastFunc(lastTokens);
+                       }
+                       else {
+                               cout << "Unknown command. 'help' displays help" << endl;
+                       }
+               }
+       }
+
+
+/*
+       for(int i = 0; ; i++) {
+               try {
+                       cpu.tick();
+                       cout << " reg0: " << cpu.getRegister(0) <<  " reg1: " << cpu.getRegister(1);
+                       cout << " reg2: " << cpu.getRegister(2) <<  " reg3: " << cpu.getRegister(3);
+                       cout << " reg4: " << cpu.getRegister(4) <<  " reg5: " << cpu.getRegister(5);
+                       cout << endl << endl;
+
+               }
+               catch(string& e) {
+                       cerr << e << endl;
+                       break;
+               }
+       }
+*/
        return EXIT_SUCCESS;
 }