[xcc] minor performance tweaks
[riscv-isa-sim.git] / riscv / sim.cc
index dede8de570b4d51f96e2daa716c42f994cefeacf..9b2677c745a624fb9981fe3b9dccd65b832b4ba6 100644 (file)
@@ -1,68 +1,81 @@
 #include "sim.h"
 #include "applink.h"
 #include "common.h"
-#include "load_elf.h"
 #include <sys/mman.h>
 #include <map>
 #include <iostream>
+#include <climits>
+#include <assert.h>
 
-class memory_t : public loader_t
+sim_t::sim_t(int _nprocs, appserver_link_t* _applink, icsim_t* default_icache, icsim_t* default_dcache)
+  : applink(_applink),
+    procs(_nprocs)
 {
-public:
-  memory_t(char* _mem, size_t _size) : mem(_mem), size(_size) {}
+  size_t memsz0 = sizeof(size_t) == 8 ? 0x100000000ULL : 0x70000000UL;
+  size_t quantum = std::max(PGSIZE, (reg_t)sysconf(_SC_PAGESIZE));
+  memsz0 = memsz0/quantum*quantum;
+
+  memsz = memsz0;
+  mem = (char*)mmap64(NULL, memsz, PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
 
-  void write(size_t addr, size_t bytes, const void* src = NULL)
+  if(mem == MAP_FAILED)
   {
-    demand(addr < size && addr + bytes <= size, "out of bounds!");
-    if(src)
-      memcpy(mem+addr, src, bytes);
-    else
-      memset(mem+addr, 0, bytes);
+    while(mem == MAP_FAILED && (memsz = memsz*10/11/quantum*quantum))
+      mem = (char*)mmap64(NULL, memsz, PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
+    assert(mem != MAP_FAILED);
+    fprintf(stderr, "warning: only got %lu bytes of target mem (wanted %lu)\n",
+            (unsigned long)memsz, (unsigned long)memsz0);
   }
 
-private:
-  char* mem;
-  size_t size;
-};
+  mmu = new mmu_t(mem, memsz);
 
-sim_t::sim_t(int _nprocs, size_t _memsz, appserver_link_t* _applink)
-  : applink(_applink),
-    memsz(_memsz),
-    mem((char*)mmap64(NULL, memsz, PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)),
-    procs(std::vector<processor_t>(_nprocs,processor_t(this,mem,memsz)))
-{
-  demand(mem != MAP_FAILED, "couldn't allocate target machine's memory");
+  for(size_t i = 0; i < num_cores(); i++)
+  {
+    procs[i] = new processor_t(this, new mmu_t(mem, memsz));
+    procs[i]->init(i, default_icache, default_dcache);
+  }
 
-  for(int i = 0; i < (int)procs.size(); i++)
-    procs[i].init(i);
+  applink->init(this);
 }
 
 sim_t::~sim_t()
 {
+  for(size_t i = 0; i < num_cores(); i++)
+  {
+    mmu_t* pmmu = &procs[i]->mmu;
+    delete procs[i];
+    delete pmmu;
+  }
+  delete mmu;
+  munmap(mem, memsz);
 }
 
-void sim_t::load_elf(const char* fn)
-{
-  memory_t loader(mem, memsz);
-  ::load_elf(fn,&loader);
-}
 void sim_t::set_tohost(reg_t val)
 {
   fromhost = 0;
   tohost = val;
+  applink->wait_for_tohost();
 }
 
 reg_t sim_t::get_fromhost()
 {
-  while(fromhost == 0)
-    applink->wait_for_packet();
+  applink->wait_for_fromhost();
   return fromhost;
 }
 
+void sim_t::send_ipi(reg_t who)
+{
+  if(who < num_cores())
+    procs[who]->deliver_ipi();
+}
+
 void sim_t::run(bool debug)
 {
   applink->wait_for_start();
 
+  // start core 0
+  send_ipi(0);
+
   while(1)
   {
     if(!debug)
@@ -76,7 +89,7 @@ void sim_t::run(bool debug)
       char* p = strtok(s," ");
       if(!p)
       {
-        interactive_run_noisy(std::vector<std::string>(1,"1"));
+        interactive_run_noisy(std::string("r"), std::vector<std::string>(1,"1"));
         continue;
       }
       std::string cmd = p;
@@ -86,7 +99,7 @@ void sim_t::run(bool debug)
         args.push_back(p);
 
 
-      typedef void (sim_t::*interactive_func)(const std::vector<std::string>&);
+      typedef void (sim_t::*interactive_func)(const std::string&, const std::vector<std::string>&);
       std::map<std::string,interactive_func> funcs;
 
       funcs["r"] = &sim_t::interactive_run_noisy;
@@ -94,14 +107,18 @@ void sim_t::run(bool debug)
       funcs["rp"] = &sim_t::interactive_run_proc_noisy;
       funcs["rps"] = &sim_t::interactive_run_proc_silent;
       funcs["reg"] = &sim_t::interactive_reg;
+      funcs["fregs"] = &sim_t::interactive_fregs;
+      funcs["fregd"] = &sim_t::interactive_fregd;
       funcs["mem"] = &sim_t::interactive_mem;
+      funcs["str"] = &sim_t::interactive_str;
       funcs["until"] = &sim_t::interactive_until;
+      funcs["while"] = &sim_t::interactive_until;
       funcs["q"] = &sim_t::interactive_quit;
 
       try
       {
         if(funcs.count(cmd))
-          (this->*funcs[cmd])(args);
+          (this->*funcs[cmd])(cmd, args);
       }
       catch(trap_t t) {}
     }
@@ -111,56 +128,56 @@ void sim_t::run(bool debug)
 void sim_t::step_all(size_t n, size_t interleave, bool noisy)
 {
   for(size_t j = 0; j < n; j+=interleave)
-    for(int i = 0; i < (int)procs.size(); i++)
-      procs[i].step(interleave,noisy);
+    for(int i = 0; i < (int)num_cores(); i++)
+      procs[i]->step(interleave,noisy);
 }
 
-void sim_t::interactive_run_noisy(const std::vector<std::string>& args)
+void sim_t::interactive_run_noisy(const std::string& cmd, const std::vector<std::string>& args)
 {
-  interactive_run(args,true);
+  interactive_run(cmd,args,true);
 }
 
-void sim_t::interactive_run_silent(const std::vector<std::string>& args)
+void sim_t::interactive_run_silent(const std::string& cmd, const std::vector<std::string>& args)
 {
-  interactive_run(args,false);
+  interactive_run(cmd,args,false);
 }
 
-void sim_t::interactive_run(const std::vector<std::string>& args, bool noisy)
+void sim_t::interactive_run(const std::string& cmd, const std::vector<std::string>& args, bool noisy)
 {
   if(args.size())
-    step_all(atoi(args[0].c_str()),1,noisy);
+    step_all(atoll(args[0].c_str()),1,noisy);
   else
     while(1) step_all(1,1,noisy);
 }
 
-void sim_t::interactive_run_proc_noisy(const std::vector<std::string>& args)
+void sim_t::interactive_run_proc_noisy(const std::string& cmd, const std::vector<std::string>& args)
 {
-  interactive_run_proc(args,true);
+  interactive_run_proc(cmd,args,true);
 }
 
-void sim_t::interactive_run_proc_silent(const std::vector<std::string>& args)
+void sim_t::interactive_run_proc_silent(const std::string& cmd, const std::vector<std::string>& args)
 {
-  interactive_run_proc(args,false);
+  interactive_run_proc(cmd,args,false);
 }
 
-void sim_t::interactive_run_proc(const std::vector<std::string>& a, bool noisy)
+void sim_t::interactive_run_proc(const std::string& cmd, const std::vector<std::string>& a, bool noisy)
 {
   if(a.size() == 0)
     return;
 
   int p = atoi(a[0].c_str());
-  if(p >= (int)procs.size())
+  if(p >= (int)num_cores())
     return;
 
   if(a.size() == 2)
-    procs[p].step(atoi(a[1].c_str()),noisy);
+    procs[p]->step(atoi(a[1].c_str()),noisy);
   else
-    while(1) procs[p].step(1,noisy);
+    while(1) procs[p]->step(1,noisy);
 }
 
-void sim_t::interactive_quit(const std::vector<std::string>& args)
+void sim_t::interactive_quit(const std::string& cmd, const std::vector<std::string>& args)
 {
-  exit(0);
+  throw quit_sim();
 }
 
 reg_t sim_t::get_pc(const std::vector<std::string>& args)
@@ -169,10 +186,10 @@ reg_t sim_t::get_pc(const std::vector<std::string>& args)
     throw trap_illegal_instruction;
 
   int p = atoi(args[0].c_str());
-  if(p >= (int)procs.size())
+  if(p >= (int)num_cores())
     throw trap_illegal_instruction;
 
-  return procs[p].pc;
+  return procs[p]->pc;
 }
 
 reg_t sim_t::get_reg(const std::vector<std::string>& args)
@@ -182,55 +199,130 @@ reg_t sim_t::get_reg(const std::vector<std::string>& args)
 
   int p = atoi(args[0].c_str());
   int r = atoi(args[1].c_str());
-  if(p >= (int)procs.size() || r >= NGPR)
+  if(p >= (int)num_cores() || r >= NXPR)
+    throw trap_illegal_instruction;
+
+  return procs[p]->XPR[r];
+}
+
+reg_t sim_t::get_freg(const std::vector<std::string>& args)
+{
+  if(args.size() != 2)
+    throw trap_illegal_instruction;
+
+  int p = atoi(args[0].c_str());
+  int r = atoi(args[1].c_str());
+  if(p >= (int)num_cores() || r >= NFPR)
+    throw trap_illegal_instruction;
+
+  return procs[p]->FPR[r];
+}
+
+reg_t sim_t::get_tohost(const std::vector<std::string>& args)
+{
+  if(args.size() != 1)
+    throw trap_illegal_instruction;
+
+  int p = atoi(args[0].c_str());
+  if(p >= (int)num_cores())
     throw trap_illegal_instruction;
 
-  return procs[p].R[r];
+  return procs[p]->tohost;
 }
 
-void sim_t::interactive_reg(const std::vector<std::string>& args)
+void sim_t::interactive_reg(const std::string& cmd, const std::vector<std::string>& args)
 {
   printf("0x%016llx\n",(unsigned long long)get_reg(args));
 }
 
+union fpr
+{
+  reg_t r;
+  float s;
+  double d;
+};
+
+void sim_t::interactive_fregs(const std::string& cmd, const std::vector<std::string>& args)
+{
+  fpr f;
+  f.r = get_freg(args);
+  printf("%g\n",f.s);
+}
+
+void sim_t::interactive_fregd(const std::string& cmd, const std::vector<std::string>& args)
+{
+  fpr f;
+  f.r = get_freg(args);
+  printf("%g\n",f.d);
+}
+
 reg_t sim_t::get_mem(const std::vector<std::string>& args)
 {
-  if(args.size() != 1)
+  if(args.size() != 1 && args.size() != 2)
     throw trap_illegal_instruction;
 
-  reg_t addr = strtol(args[0].c_str(),NULL,16), val;
-  mmu_t mmu(mem,memsz);
+  std::string addr_str = args[0];
+  if(args.size() == 2)
+  {
+    int p = atoi(args[0].c_str());
+    if(p >= (int)num_cores())
+      throw trap_illegal_instruction;
+    mmu->set_vm_enabled(!!(procs[p]->sr & SR_VM));
+    mmu->set_ptbr(procs[p]->mmu.get_ptbr());
+    addr_str = args[1];
+  }
+
+  reg_t addr = strtol(addr_str.c_str(),NULL,16), val;
+  if(addr == LONG_MAX)
+    addr = strtoul(addr_str.c_str(),NULL,16);
+
   switch(addr % 8)
   {
     case 0:
-      val = mmu.load_uint64(addr);
+      val = mmu->load_uint64(addr);
       break;
     case 4:
-      val = mmu.load_uint32(addr);
+      val = mmu->load_uint32(addr);
       break;
     case 2:
     case 6:
-      val = mmu.load_uint16(addr);
+      val = mmu->load_uint16(addr);
       break;
     default:
-      val = mmu.load_uint8(addr);
+      val = mmu->load_uint8(addr);
       break;
   }
   return val;
 }
 
-void sim_t::interactive_mem(const std::vector<std::string>& args)
+void sim_t::interactive_mem(const std::string& cmd, const std::vector<std::string>& args)
 {
   printf("0x%016llx\n",(unsigned long long)get_mem(args));
 }
 
-void sim_t::interactive_until(const std::vector<std::string>& args)
+void sim_t::interactive_str(const std::string& cmd, const std::vector<std::string>& args)
+{
+  if(args.size() != 1)
+    throw trap_illegal_instruction;
+
+  reg_t addr = strtol(args[0].c_str(),NULL,16);
+
+  char ch;
+  while((ch = mmu->load_uint8(addr++)))
+    putchar(ch);
+
+  putchar('\n');
+}
+
+void sim_t::interactive_until(const std::string& cmd, const std::vector<std::string>& args)
 {
   if(args.size() < 3)
     return;
 
-  std::string cmd = args[0];
+  std::string scmd = args[0];
   reg_t val = strtol(args[args.size()-1].c_str(),NULL,16);
+  if(val == LONG_MAX)
+    val = strtoul(args[args.size()-1].c_str(),NULL,16);
   
   std::vector<std::string> args2;
   args2 = std::vector<std::string>(args.begin()+1,args.end()-1);
@@ -238,16 +330,20 @@ void sim_t::interactive_until(const std::vector<std::string>& args)
   while(1)
   {
     reg_t current;
-    if(args[0] == "reg")
+    if(scmd == "reg")
       current = get_reg(args2);
-    else if(args[0] == "pc")
+    else if(scmd == "pc")
       current = get_pc(args2);
-    else if(args[0] == "mem")
+    else if(scmd == "mem")
       current = get_mem(args2);
+    else if(scmd == "tohost")
+      current = get_tohost(args2);
     else
       return;
 
-    if(current == val)
+    if(cmd == "until" && current == val)
+      break;
+    if(cmd == "while" && current != val)
       break;
 
     step_all(1,1,false);