Fix paddr_bits computation prior to VM setup
[riscv-isa-sim.git] / riscv / htif.cc
index d439f7b2e5d822de1797d4a1fd54d8f4ac1a0059..6e8fee9e462127e07f8ff8ac8ec962b3dd067974 100644 (file)
@@ -1,6 +1,9 @@
+// See LICENSE for license details.
+
 #include "htif.h"
-#include "common.h"
 #include "sim.h"
+#include "mmu.h"
+#include "encoding.h"
 #include <unistd.h>
 #include <stdexcept>
 #include <stdlib.h>
 #include <stddef.h>
 #include <poll.h>
 
-enum
-{
-  APP_CMD_READ_MEM,
-  APP_CMD_WRITE_MEM,
-  APP_CMD_READ_CONTROL_REG,
-  APP_CMD_WRITE_CONTROL_REG,
-  APP_CMD_START,
-  APP_CMD_STOP,
-  APP_CMD_ACK,
-  APP_CMD_NACK
-};
-
-#define APP_MAX_DATA_SIZE 1024
-#define HTIF_DATA_ALIGN 8
-struct packet
-{
-  reg_t cmd       :  4;
-  reg_t data_size : 12;
-  reg_t seqno     :  8;
-  reg_t addr      : 40;
-
-  uint8_t  data[APP_MAX_DATA_SIZE];
-};
-
-htif_t::htif_t(int _tohost_fd, int _fromhost_fd)
-  : sim(NULL), tohost_fd(_tohost_fd), fromhost_fd(_fromhost_fd), seqno(1)
-{
-}
-
-htif_t::~htif_t()
-{
-  close(tohost_fd);
-  close(fromhost_fd);
-}
-
-void htif_t::init(sim_t* _sim)
+htif_isasim_t::htif_isasim_t(sim_t* _sim, const std::vector<std::string>& args)
+  : htif_pthread_t(args), sim(_sim), reset(true), seqno(1)
 {
-  sim = _sim;
 }
 
-void htif_t::wait_for_start()
+bool htif_isasim_t::tick()
 {
-  while(wait_for_packet() != APP_CMD_START);
-}
-
-void htif_t::wait_for_tohost_write()
-{
-  while(wait_for_packet() != APP_CMD_READ_CONTROL_REG);
-}
+  if (done())
+    return false;
 
-void htif_t::wait_for_fromhost_write()
-{
-  while(wait_for_packet() != APP_CMD_WRITE_CONTROL_REG);
-}
+  do tick_once(); while (reset);
 
-void htif_t::send_packet(packet* p)
-{
-  size_t data_size = p->data_size*HTIF_DATA_ALIGN;
-  size_t bytes = write(tohost_fd, p, offsetof(packet,data) + data_size);
-  if(bytes != offsetof(packet,data) + data_size)
-  {
-    const char* error = (ssize_t)bytes == -1 ? strerror(errno) : "not all bytes sent";
-    fprintf(stderr,"HTIF error: %s\n", error);
-    exit(-1);
-  }
+  return true;
 }
 
-void htif_t::nack(uint8_t nack_seqno)
+void htif_isasim_t::tick_once()
 {
-  packet p = {APP_CMD_NACK,0,nack_seqno,0};
-  send_packet(&p);
-}
+  packet_header_t hdr;
+  recv(&hdr, sizeof(hdr));
 
-void htif_t::poll()
-{
-  struct pollfd pfd;
-  pfd.fd = fromhost_fd;
-  pfd.events = POLLIN;
-  pfd.revents = 0;
+  char buf[hdr.get_packet_size()];
+  memcpy(buf, &hdr, sizeof(hdr));
+  recv(buf + sizeof(hdr), hdr.get_payload_size());
+  packet_t p(buf);
 
-  if (::poll(&pfd, 1, 0) > 0)
-    wait_for_packet();
-}
+  assert(hdr.seqno == seqno);
 
-int htif_t::wait_for_packet()
-{
-  while(1)
+  switch (hdr.cmd)
   {
-    packet p;
-    int bytes = read(fromhost_fd,&p,sizeof(p));
-    if(bytes < (int)offsetof(packet,data))
+    case HTIF_CMD_READ_MEM:
     {
-      const char* error = bytes == -1 ? strerror(errno) : "too few bytes read";
-      fprintf(stderr,"HTIF error: %s\n", error);
-      exit(-1);
+      packet_header_t ack(HTIF_CMD_ACK, seqno, hdr.data_size, 0);
+      send(&ack, sizeof(ack));
+
+      uint64_t buf[hdr.data_size];
+      for (size_t i = 0; i < hdr.data_size; i++) {
+        reg_t addr = (hdr.addr + i) * HTIF_DATA_ALIGN;
+        try {
+          buf[i] = sim->debug_mmu->load_uint64(addr);
+        } catch (trap_load_access_fault& e) {
+          fprintf(stderr, "HTIF: attempt to read from illegal address 0x%" PRIx64 "\n", addr);
+          exit(-1);
+        }
+      }
+      send(buf, hdr.data_size * sizeof(buf[0]));
+      break;
     }
-  
-    if(p.seqno != seqno)
+    case HTIF_CMD_WRITE_MEM:
     {
-      nack(p.seqno);
-      continue;
+      const uint64_t* buf = (const uint64_t*)p.get_payload();
+      for (size_t i = 0; i < hdr.data_size; i++) {
+        reg_t addr = (hdr.addr + i) * HTIF_DATA_ALIGN;
+        try {
+          sim->debug_mmu->store_uint64(addr, buf[i]);
+        } catch (trap_store_access_fault& e) {
+          fprintf(stderr, "HTIF: attempt to write to illegal address 0x%" PRIx64 "\n", addr);
+          exit(-1);
+        }
+      }
+      packet_header_t ack(HTIF_CMD_ACK, seqno, 0, 0);
+      send(&ack, sizeof(ack));
+      break;
     }
-
-    packet ackpacket = {APP_CMD_ACK,0,seqno,0};
-
-    switch(p.cmd)
+    case HTIF_CMD_READ_CONTROL_REG:
+    case HTIF_CMD_WRITE_CONTROL_REG:
     {
-      case APP_CMD_START:
-        break;
-      case APP_CMD_STOP:
-        sim->stop();
-        break;
-      case APP_CMD_READ_MEM:
-        assert(p.data_size <= APP_MAX_DATA_SIZE/HTIF_DATA_ALIGN);
-        assert(p.addr < sim->memsz/HTIF_DATA_ALIGN);
-        assert(p.addr+p.data_size <= sim->memsz/HTIF_DATA_ALIGN);
-        ackpacket.data_size = p.data_size;
-
-        assert(HTIF_DATA_ALIGN == sizeof(uint64_t));
-        for(size_t i = 0; i < p.data_size; i++)
-          ((uint64_t*)ackpacket.data)[i] = sim->mmu->load_uint64((p.addr+i)*HTIF_DATA_ALIGN);
-        break;
-      case APP_CMD_WRITE_MEM:
-        assert(p.data_size*HTIF_DATA_ALIGN <= bytes - offsetof(packet,data));
-        assert(p.addr < sim->memsz/HTIF_DATA_ALIGN);
-        assert(p.addr+p.data_size <= sim->memsz/HTIF_DATA_ALIGN);
-
-        for(size_t i = 0; i < p.data_size; i++)
-          sim->mmu->store_uint64((p.addr+i)*HTIF_DATA_ALIGN, ((uint64_t*)p.data)[i]);
-        break;
-      case APP_CMD_READ_CONTROL_REG:
-        assert(p.addr == 16);
-        assert(p.data_size == 1);
-        ackpacket.data_size = 1;
-        memcpy(ackpacket.data,&sim->tohost,sizeof(reg_t));
-        break;
-      case APP_CMD_WRITE_CONTROL_REG:
-        assert(p.addr == 17);
-        assert(p.data_size == 1);
-        sim->tohost = 0;
-        memcpy(&sim->fromhost,p.data,sizeof(reg_t));
-        break;
+      assert(hdr.data_size == 1);
+      reg_t coreid = hdr.addr >> 20;
+      reg_t regno = hdr.addr & ((1<<20)-1);
+      uint64_t old_val, new_val = 0 /* shut up gcc */;
+
+      packet_header_t ack(HTIF_CMD_ACK, seqno, 1, 0);
+      send(&ack, sizeof(ack));
+
+      processor_t* proc = sim->get_core(coreid);
+      bool write = hdr.cmd == HTIF_CMD_WRITE_CONTROL_REG;
+      if (write)
+        memcpy(&new_val, p.get_payload(), sizeof(new_val));
+
+      switch (regno)
+      {
+        case CSR_MRESET:
+          old_val = !proc->running();
+          if (write)
+          {
+            reset = reset & (new_val & 1);
+            proc->reset(new_val & 1);
+          }
+          break;
+        default:
+          abort();
+      }
+
+      send(&old_val, sizeof(old_val));
+      break;
     }
-
-    send_packet(&ackpacket);
-    seqno++;
-    return p.cmd;
+    default:
+      abort();
   }
+  seqno++;
 }
 
+bool htif_isasim_t::done()
+{
+  if (reset)
+    return false;
+  return !sim->running();
+}