Merge remote-tracking branch 'origin/priv-1.10' into HEAD
authorMegan Wachs <megan@sifive.com>
Mon, 17 Apr 2017 17:59:38 +0000 (10:59 -0700)
committerMegan Wachs <megan@sifive.com>
Mon, 17 Apr 2017 17:59:38 +0000 (10:59 -0700)
1  2 
remote_bitbang.cc
remote_bitbang.h
riscv/decode.h
riscv/execute.cc
riscv/processor.cc
riscv/processor.h
riscv/riscv.mk.in
riscv/sim.cc
riscv/sim.h
spike_main/spike.cc

diff --combined remote_bitbang.cc
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9d0ca90a2b5584e38b5c14501a9e2de813d398aa
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,174 @@@
++#include <arpa/inet.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++#include <algorithm>
++#include <cassert>
++#include <cstdio>
++
++#include "remote_bitbang.h"
++
++#if 1
++#  define D(x) x
++#else
++#  define D(x)
++#endif
++
++/////////// remote_bitbang_t
++
++remote_bitbang_t::remote_bitbang_t(uint16_t port, jtag_dtm_t *tap) :
++  tap(tap),
++  socket_fd(0),
++  client_fd(0),
++  recv_start(0),
++  recv_end(0)
++{
++  socket_fd = socket(AF_INET, SOCK_STREAM, 0);
++  if (socket_fd == -1) {
++    fprintf(stderr, "remote_bitbang failed to make socket: %s (%d)\n",
++        strerror(errno), errno);
++    abort();
++  }
++
++  fcntl(socket_fd, F_SETFL, O_NONBLOCK);
++  int reuseaddr = 1;
++  if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
++        sizeof(int)) == -1) {
++    fprintf(stderr, "remote_bitbang failed setsockopt: %s (%d)\n",
++        strerror(errno), errno);
++    abort();
++  }
++
++  struct sockaddr_in addr;
++  memset(&addr, 0, sizeof(addr));
++  addr.sin_family = AF_INET;
++  addr.sin_addr.s_addr = INADDR_ANY;
++  addr.sin_port = htons(port);
++
++  if (bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
++    fprintf(stderr, "remote_bitbang failed to bind socket: %s (%d)\n",
++        strerror(errno), errno);
++    abort();
++  }
++
++  if (listen(socket_fd, 1) == -1) {
++    fprintf(stderr, "remote_bitbang failed to listen on socket: %s (%d)\n",
++        strerror(errno), errno);
++    abort();
++  }
++
++  socklen_t addrlen = sizeof(addr);
++  if (getsockname(socket_fd, (struct sockaddr *) &addr, &addrlen) == -1) {
++    fprintf(stderr, "remote_bitbang getsockname failed: %s (%d)\n",
++        strerror(errno), errno);
++    abort();
++  }
++
++  printf("Listening for remote bitbang connection on port %d.\n",
++      ntohs(addr.sin_port));
++  fflush(stdout);
++}
++
++void remote_bitbang_t::accept()
++{
++  client_fd = ::accept(socket_fd, NULL, NULL);
++  if (client_fd == -1) {
++    if (errno == EAGAIN) {
++      // No client waiting to connect right now.
++    } else {
++      fprintf(stderr, "failed to accept on socket: %s (%d)\n", strerror(errno),
++          errno);
++      abort();
++    }
++  } else {
++    fcntl(client_fd, F_SETFL, O_NONBLOCK);
++  }
++}
++
++void remote_bitbang_t::tick()
++{
++  if (client_fd > 0) {
++    execute_commands();
++  } else {
++    this->accept();
++  }
++}
++
++void remote_bitbang_t::execute_commands()
++{
++  static char send_buf[buf_size];
++  unsigned total_processed = 0;
++  bool quit = false;
++  bool in_rti = tap->state() == RUN_TEST_IDLE;
++  bool entered_rti = false;
++  while (1) {
++    if (recv_start < recv_end) {
++      unsigned send_offset = 0;
++      while (recv_start < recv_end) {
++        uint8_t command = recv_buf[recv_start];
++
++        switch (command) {
++          case 'B': /* fprintf(stderr, "*BLINK*\n"); */ break;
++          case 'b': /* fprintf(stderr, "_______\n"); */ break;
++          case 'r': tap->reset(); break;
++          case '0': tap->set_pins(0, 0, 0); break;
++          case '1': tap->set_pins(0, 0, 1); break;
++          case '2': tap->set_pins(0, 1, 0); break;
++          case '3': tap->set_pins(0, 1, 1); break;
++          case '4': tap->set_pins(1, 0, 0); break;
++          case '5': tap->set_pins(1, 0, 1); break;
++          case '6': tap->set_pins(1, 1, 0); break;
++          case '7': tap->set_pins(1, 1, 1); break;
++          case 'R': send_buf[send_offset++] = tap->tdo() ? '1' : '0'; break;
++          case 'Q': quit = true; break;
++          default:
++                    fprintf(stderr, "remote_bitbang got unsupported command '%c'\n",
++                        command);
++        }
++        recv_start++;
++        total_processed++;
++        if (!in_rti && tap->state() == RUN_TEST_IDLE) {
++          entered_rti = true;
++          break;
++        }
++        in_rti = false;
++      }
++      unsigned sent = 0;
++      while (sent < send_offset) {
++        ssize_t bytes = write(client_fd, send_buf + sent, send_offset);
++        if (bytes == -1) {
++          fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno);
++          abort();
++        }
++        sent += bytes;
++      }
++    }
++
++    if (total_processed > buf_size || quit || entered_rti) {
++      // Don't go forever, because that could starve the main simulation.
++      break;
++    }
++
++    recv_start = 0;
++    recv_end = read(client_fd, recv_buf, buf_size);
++
++    if (recv_end == -1) {
++      if (errno == EAGAIN) {
++        // We'll try again the next call.
++      } else {
++        fprintf(stderr, "remote_bitbang failed to read on socket: %s (%d)\n",
++            strerror(errno), errno);
++        abort();
++      }
++    }
++    if (recv_end == 0 || quit) {
++      // The remote disconnected.
++      close(client_fd);
++      client_fd = 0;
++      break;
++    }
++  }
++}
diff --combined remote_bitbang.h
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1db4d550140ea8bad605663911579bbe8e857501
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,34 @@@
++#ifndef REMOTE_BITBANG_H
++#define REMOTE_BITBANG_H
++
++#include <stdint.h>
++
++#include "jtag_dtm.h"
++
++class remote_bitbang_t
++{
++public:
++  // Create a new server, listening for connections from localhost on the given
++  // port.
++  remote_bitbang_t(uint16_t port, jtag_dtm_t *tap);
++
++  // Do a bit of work.
++  void tick();
++
++private:
++  jtag_dtm_t *tap;
++
++  int socket_fd;
++  int client_fd;
++
++  static const ssize_t buf_size = 64 * 1024;
++  char recv_buf[buf_size];
++  ssize_t recv_start, recv_end;
++
++  // Check for a client connecting, and accept if there is one.
++  void accept();
++  // Execute any commands the client has for us.
++  void execute_commands();
++};
++
++#endif
diff --combined riscv/decode.h
index e78a587ef7da9d8b9ef848e2ddc0bc71417d4ba1,c3487b103a25906575d2806f3646f2fe6da203bb..7667b273a7339af4a3d23413a807062b901779aa
@@@ -7,17 -7,22 +7,22 @@@
  # error spike requires a two''s-complement c++ implementation
  #endif
  
+ #ifdef WORDS_BIGENDIAN
+ # error spike requires a little-endian host
+ #endif
  #include <cstdint>
  #include <string.h>
  #include <strings.h>
  #include "encoding.h"
  #include "config.h"
  #include "common.h"
+ #include "softfloat_types.h"
+ #include "specialize.h"
  #include <cinttypes>
  
  typedef int64_t sreg_t;
  typedef uint64_t reg_t;
- typedef uint64_t freg_t;
  
  const int NXPR = 32;
  const int NFPR = 32;
@@@ -130,7 -135,7 +135,7 @@@ private
  
  #ifndef RISCV_ENABLE_COMMITLOG
  # define WRITE_REG(reg, value) STATE.XPR.write(reg, value)
- # define WRITE_FREG(reg, value) DO_WRITE_FREG(reg, value)
+ # define WRITE_FREG(reg, value) DO_WRITE_FREG(reg, freg(value))
  #else
  # define WRITE_REG(reg, value) ({ \
      reg_t wdata = (value); /* value may have side effects */ \
      STATE.XPR.write(reg, wdata); \
    })
  # define WRITE_FREG(reg, value) ({ \
-     freg_t wdata = (value); /* value may have side effects */ \
+     freg_t wdata = freg(value); /* value may have side effects */ \
      STATE.log_reg_write = (commit_log_reg_t){((reg) << 1) | 1, wdata}; \
      DO_WRITE_FREG(reg, wdata); \
    })
  #define JUMP_TARGET (pc + insn.uj_imm())
  #define RM ({ int rm = insn.rm(); \
                if(rm == 7) rm = STATE.frm; \
-               if(rm > 4) throw trap_illegal_instruction(); \
+               if(rm > 4) throw trap_illegal_instruction(0); \
                rm; })
  
  #define get_field(reg, mask) (((reg) & (decltype(reg))(mask)) / ((mask) & ~((mask) << 1)))
  #define set_field(reg, mask, val) (((reg) & ~(decltype(reg))(mask)) | (((decltype(reg))(val) * ((mask) & ~((mask) << 1))) & (decltype(reg))(mask)))
  
- #define require(x) if (unlikely(!(x))) throw trap_illegal_instruction()
+ #define require(x) if (unlikely(!(x))) throw trap_illegal_instruction(0)
  #define require_privilege(p) require(STATE.prv >= (p))
  #define require_rv64 require(xlen == 64)
  #define require_rv32 require(xlen == 32)
       } while(0)
  
  #define set_pc_and_serialize(x) \
-   do { set_pc(x); /* check alignment */ \
+   do { reg_t __npc = (x); \
+        set_pc(__npc); /* check alignment */ \
         npc = PC_SERIALIZE_AFTER; \
-        STATE.pc = (x); \
+        STATE.pc = __npc; \
       } while(0)
  
  /* Sentinel PC values to serialize simulator pipeline */
  #define invalid_pc(pc) ((pc) & 1)
  
  /* Convenience wrappers to simplify softfloat code sequences */
- #define f32(x) ((float32_t){(uint32_t)x})
- #define f64(x) ((float64_t){(uint64_t)x})
+ #define isBoxedF32(r) (((r) & 0xffffffff00000000) == 0xffffffff00000000)
+ #define unboxF32(r) (isBoxedF32(r) ? (r) : defaultNaNF32UI)
+ #define unboxF64(r) (r)
+ struct freg_t { uint64_t v; };
+ inline float32_t f32(uint32_t v) { return { v }; }
+ inline float64_t f64(uint64_t v) { return { v }; }
+ inline float32_t f32(freg_t r) { return f32(unboxF32(r.v)); }
+ inline float64_t f64(freg_t r) { return f64(unboxF64(r.v)); }
+ inline freg_t freg(float32_t f) { return { ((decltype(freg_t::v))-1 << 32) | f.v }; }
+ inline freg_t freg(float64_t f) { return { f.v }; }
+ inline freg_t freg(freg_t f) { return f; }
+ #define F64_SIGN ((decltype(freg_t::v))1 << 63)
+ #define F32_SIGN ((decltype(freg_t::v))1 << 31)
+ #define fsgnj32(a, b, n, x) \
+   f32((f32(a).v & ~F32_SIGN) | ((((x) ? f32(a).v : (n) ? F32_SIGN : 0) ^ f32(b).v) & F32_SIGN))
+ #define fsgnj64(a, b, n, x) \
+   f64((f64(a).v & ~F64_SIGN) | ((((x) ? f64(a).v : (n) ? F64_SIGN : 0) ^ f64(b).v) & F64_SIGN))
  
  #define validate_csr(which, write) ({ \
    if (!STATE.serialized) return PC_SERIALIZE_BEFORE; \
    unsigned csr_priv = get_field((which), 0x300); \
    unsigned csr_read_only = get_field((which), 0xC00) == 3; \
    if (((write) && csr_read_only) || STATE.prv < csr_priv) \
-     throw trap_illegal_instruction(); \
+     throw trap_illegal_instruction(0); \
    (which); })
  
 -#define DEBUG_START             0x100
 -#define DEBUG_ROM_START         0x800
 -#define DEBUG_ROM_RESUME        (DEBUG_ROM_START + 4)
 -#define DEBUG_ROM_EXCEPTION     (DEBUG_ROM_START + 8)
 -#define DEBUG_ROM_END           (DEBUG_ROM_START + debug_rom_raw_len)
 -#define DEBUG_RAM_START         0x400
 +#define DEBUG_START             0x20000
 +#define DEBUG_ROM_ENTRY         DEBUG_START
 +#define DEBUG_ROM_ENTRY_SIZE    (1024 * 4)
 +#define DEBUG_ROM_CODE          (DEBUG_ROM_ENTRY + DEBUG_ROM_ENTRY_SIZE)
 +#define DEBUG_ROM_CODE_SIZE     256
 +#define DEBUG_ROM_EXCEPTION     (DEBUG_ROM_CODE + DEBUG_ROM_CODE_SIZE)
 +#define DEBUG_ROM_EXCEPTION_SIZE        4
 +#define DEBUG_RAM_START         (DEBUG_ROM_EXCEPTION + DEBUG_ROM_EXCEPTION_SIZE)
  #define DEBUG_RAM_SIZE          64
  #define DEBUG_RAM_END           (DEBUG_RAM_START + DEBUG_RAM_SIZE)
 -#define DEBUG_END               0xfff
 -#define DEBUG_CLEARDEBINT       0x100
 -#define DEBUG_SETHALTNOT        0x10c
 -#define DEBUG_SIZE              (DEBUG_END - DEBUG_START + 1)
 +#define DEBUG_END               DEBUG_RAM_END
 +
 +#define DEBUG_EXCHANGE          0x400
 +#define DEBUG_EXCHANGE_SIZE     0x20
  
  #endif
diff --combined riscv/execute.cc
index 0ac0e0ac43c729cfa08f5c6a7b3dd079b1f2177e,1b53ccf7c3e4eeff9dfcf426f3b3024d5f354d99..7734ca2749d6756ca2270e6c359a3d28db712ec9
@@@ -63,11 -63,16 +63,11 @@@ bool processor_t::slow_path(
  void processor_t::step(size_t n)
  {
    if (state.dcsr.cause == DCSR_CAUSE_NONE) {
 -    // TODO: get_interrupt() isn't super fast. Does that matter?
 -    if (sim->debug_module.get_interrupt(id)) {
 +    if (halt_request) {
        enter_debug_mode(DCSR_CAUSE_DEBUGINT);
      } else if (state.dcsr.halt) {
        enter_debug_mode(DCSR_CAUSE_HALT);
      }
 -  } else {
 -    // In Debug Mode, just do 11 steps at a time. Otherwise we're going to be
 -    // spinning the rest of the time anyway.
 -    n = std::min(n, (size_t) 11);
    }
  
    while (n > 0) {
@@@ -79,7 -84,7 +79,7 @@@
       if (unlikely(invalid_pc(pc))) { \
         switch (pc) { \
           case PC_SERIALIZE_BEFORE: state.serialized = true; break; \
-          case PC_SERIALIZE_AFTER: instret++; break; \
+          case PC_SERIALIZE_AFTER: n = ++instret; break; \
           default: abort(); \
         } \
         pc = state.pc; \
@@@ -91,7 -96,7 +91,7 @@@
  
      try
      {
-       take_interrupt();
+       take_pending_interrupt();
  
        if (unlikely(slow_path()))
        {
              // enter_debug_mode changed state.pc, so we can't just continue.
              break;
            }
 +
 +          if (unlikely(state.pc >= DEBUG_ROM_ENTRY &&
 +                state.pc < DEBUG_ROM_ENTRY + DEBUG_ROM_ENTRY_SIZE)) {
 +            // We're spinning waiting for the debugger to tell us something.
 +            // Let's go talk to the debugger.
 +            return;
 +          }
          }
        }
        else while (instret < n)
diff --combined riscv/processor.cc
index 58837d12fa14c87673b5515c140a9be646f989cb,ab5640e23aaca13ee2013a5ca63304ce042df59a..ef529fc20c1d6d885b2fc7b22abad7060302a68c
@@@ -7,6 -7,7 +7,6 @@@
  #include "sim.h"
  #include "mmu.h"
  #include "disasm.h"
 -#include "gdbserver.h"
  #include <cinttypes>
  #include <cmath>
  #include <cstdlib>
@@@ -21,8 -22,7 +21,8 @@@
  
  processor_t::processor_t(const char* isa, sim_t* sim, uint32_t id,
          bool halt_on_reset)
 -  : debug(false), sim(sim), ext(NULL), id(id), halt_on_reset(halt_on_reset)
 +  : debug(false), halt_request(false), sim(sim), ext(NULL), id(id),
 +  halt_on_reset(halt_on_reset)
  {
    parse_isa_string(isa);
    register_base_instructions();
@@@ -118,7 -118,6 +118,6 @@@ void state_t::reset(
    memset(this, 0, sizeof(*this));
    prv = PRV_M;
    pc = DEFAULT_RSTVEC;
-   mtvec = DEFAULT_MTVEC;
    load_reservation = -1;
    tselect = 0;
    for (unsigned int i = 0; i < num_triggers; i++)
@@@ -154,11 -153,6 +153,6 @@@ void processor_t::reset(
      ext->reset(); // reset the extension
  }
  
- void processor_t::raise_interrupt(reg_t which)
- {
-   throw trap_t(((reg_t)1 << (max_xlen-1)) | which);
- }
  // Count number of contiguous 0 bits starting from the LSB.
  static int ctz(reg_t val)
  {
    return res;
  }
  
- void processor_t::take_interrupt()
+ void processor_t::take_interrupt(reg_t pending_interrupts)
  {
-   reg_t pending_interrupts = state.mip & state.mie;
    reg_t mie = get_field(state.mstatus, MSTATUS_MIE);
    reg_t m_enabled = state.prv < PRV_M || (state.prv == PRV_M && mie);
    reg_t enabled_interrupts = pending_interrupts & ~state.mideleg & -m_enabled;
  
    reg_t sie = get_field(state.mstatus, MSTATUS_SIE);
    reg_t s_enabled = state.prv < PRV_S || (state.prv == PRV_S && sie);
-   enabled_interrupts |= pending_interrupts & state.mideleg & -s_enabled;
+   if (enabled_interrupts == 0)
+     enabled_interrupts = pending_interrupts & state.mideleg & -s_enabled;
  
    if (enabled_interrupts)
-     raise_interrupt(ctz(enabled_interrupts));
+     throw trap_t(((reg_t)1 << (max_xlen-1)) | ctz(enabled_interrupts));
  }
  
  void processor_t::set_privilege(reg_t prv)
@@@ -200,7 -193,7 +193,7 @@@ void processor_t::enter_debug_mode(uint
    state.dcsr.prv = state.prv;
    set_privilege(PRV_M);
    state.dpc = state.pc;
 -  state.pc = DEBUG_ROM_START;
 +  state.pc = debug_rom_entry();
  }
  
  void processor_t::take_trap(trap_t& t, reg_t epc)
            t.get_badaddr());
    }
  
 +  if (state.dcsr.cause) {
 +    if (t.cause() == CAUSE_BREAKPOINT) {
 +      state.pc = debug_rom_entry();
 +    } else {
 +      state.pc = DEBUG_ROM_EXCEPTION;
 +    }
 +    return;
 +  }
 +
    if (t.cause() == CAUSE_BREAKPOINT && (
                (state.prv == PRV_M && state.dcsr.ebreakm) ||
                (state.prv == PRV_H && state.dcsr.ebreakh) ||
      return;
    }
  
 -  if (state.dcsr.cause) {
 -    state.pc = DEBUG_ROM_EXCEPTION;
 -    return;
 -  }
 -
    // by default, trap to M-mode, unless delegated to S-mode
    reg_t bit = t.cause();
    reg_t deleg = state.medeleg;
-   if (bit & ((reg_t)1 << (max_xlen-1)))
+   bool interrupt = (bit & ((reg_t)1 << (max_xlen-1))) != 0;
+   if (interrupt)
      deleg = state.mideleg, bit &= ~((reg_t)1 << (max_xlen-1));
    if (state.prv <= PRV_S && bit < max_xlen && ((deleg >> bit) & 1)) {
      // handle the trap in S-mode
        state.sbadaddr = t.get_badaddr();
  
      reg_t s = state.mstatus;
-     s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_UIE << state.prv));
+     s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_SIE));
      s = set_field(s, MSTATUS_SPP, state.prv);
      s = set_field(s, MSTATUS_SIE, 0);
      set_csr(CSR_MSTATUS, s);
      set_privilege(PRV_S);
    } else {
-     state.pc = state.mtvec;
+     reg_t vector = (state.mtvec & 1) && interrupt ? 4*bit : 0;
+     state.pc = (state.mtvec & ~(reg_t)1) + vector;
      state.mepc = epc;
      state.mcause = t.cause();
      if (t.has_badaddr())
        state.mbadaddr = t.get_badaddr();
  
      reg_t s = state.mstatus;
-     s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_UIE << state.prv));
+     s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE));
      s = set_field(s, MSTATUS_MPP, state.prv);
      s = set_field(s, MSTATUS_MIE, 0);
      set_csr(CSR_MSTATUS, s);
  
  void processor_t::disasm(insn_t insn)
  {
 +  static uint64_t last_pc = 1, last_bits;
 +  static uint64_t executions = 1;
 +
    uint64_t bits = insn.bits() & ((1ULL << (8 * insn_length(insn.bits()))) - 1);
 -  fprintf(stderr, "core %3d: 0x%016" PRIx64 " (0x%08" PRIx64 ") %s\n",
 -          id, state.pc, bits, disassembler->disassemble(insn).c_str());
 +  if (last_pc != state.pc || last_bits != bits) {
 +    if (executions != 1) {
 +      fprintf(stderr, "core %3d: Executed %" PRIx64 " times\n", id, executions);
 +    }
 +
 +    fprintf(stderr, "core %3d: 0x%016" PRIx64 " (0x%08" PRIx64 ") %s\n",
 +            id, state.pc, bits, disassembler->disassemble(insn).c_str());
 +    last_pc = state.pc;
 +    last_bits = bits;
 +    executions = 1;
 +  } else {
 +    executions++;
 +  }
  }
  
- static bool validate_vm(int max_xlen, reg_t vm)
- {
-   if (max_xlen == 64 && (vm == VM_SV39 || vm == VM_SV48))
-     return true;
-   if (max_xlen == 32 && vm == VM_SV32)
-     return true;
-   return vm == VM_MBARE;
- }
  int processor_t::paddr_bits()
  {
    assert(xlen == max_xlen);
@@@ -326,15 -294,13 +312,13 @@@ void processor_t::set_csr(int which, re
        break;
      case CSR_MSTATUS: {
        if ((val ^ state.mstatus) &
-           (MSTATUS_VM | MSTATUS_MPP | MSTATUS_MPRV | MSTATUS_PUM | MSTATUS_MXR))
+           (MSTATUS_MPP | MSTATUS_MPRV | MSTATUS_SUM | MSTATUS_MXR))
          mmu->flush_tlb();
  
        reg_t mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE
-                  | MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_PUM
-                  | MSTATUS_MPP | MSTATUS_MXR | (ext ? MSTATUS_XS : 0);
-       if (validate_vm(max_xlen, get_field(val, MSTATUS_VM)))
-         mask |= MSTATUS_VM;
+                  | MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM
+                  | MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TW | MSTATUS_TVM
+                  | MSTATUS_TSR | (ext ? MSTATUS_XS : 0);
  
        state.mstatus = (state.mstatus & ~mask) | (val & mask);
  
      case CSR_MCYCLEH:
        state.minstret = (val << 32) | (state.minstret << 32 >> 32);
        break;
-     case CSR_MUCOUNTEREN:
-       state.mucounteren = val;
+     case CSR_SCOUNTEREN:
+       state.scounteren = val;
        break;
-     case CSR_MSCOUNTEREN:
-       state.mscounteren = val;
+     case CSR_MCOUNTEREN:
+       state.mcounteren = val;
        break;
      case CSR_SSTATUS: {
        reg_t mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP | SSTATUS_FS
-                  | SSTATUS_XS | SSTATUS_PUM;
+                  | SSTATUS_XS | SSTATUS_SUM | SSTATUS_MXR;
        return set_csr(CSR_MSTATUS, (state.mstatus & ~mask) | (val & mask));
      }
      case CSR_SIP: {
        return set_csr(CSR_MIE,
                       (state.mie & ~state.mideleg) | (val & state.mideleg));
      case CSR_SPTBR: {
-       // upper bits of sptbr are the ASID; we only support ASID = 0
-       state.sptbr = val & (((reg_t)1 << (paddr_bits() - PGSHIFT)) - 1);
+       mmu->flush_tlb();
+       if (max_xlen == 32)
+         state.sptbr = val & (SPTBR32_PPN | SPTBR32_MODE);
+       if (max_xlen == 64 && (get_field(val, SPTBR64_MODE) == SPTBR_MODE_OFF ||
+                              get_field(val, SPTBR64_MODE) == SPTBR_MODE_SV39 ||
+                              get_field(val, SPTBR64_MODE) == SPTBR_MODE_SV48))
+         state.sptbr = val & (SPTBR64_PPN | SPTBR64_MODE);
        break;
      }
      case CSR_SEPC: state.sepc = val; break;
      case CSR_SCAUSE: state.scause = val; break;
      case CSR_SBADADDR: state.sbadaddr = val; break;
      case CSR_MEPC: state.mepc = val; break;
-     case CSR_MTVEC: state.mtvec = val >> 2 << 2; break;
+     case CSR_MTVEC: state.mtvec = val & ~(reg_t)2; break;
      case CSR_MSCRATCH: state.mscratch = val; break;
      case CSR_MCAUSE: state.mcause = val; break;
      case CSR_MBADADDR: state.mbadaddr = val; break;
  
  reg_t processor_t::get_csr(int which)
  {
-   reg_t ctr_en = state.prv == PRV_U ? state.mucounteren :
-                  state.prv == PRV_S ? state.mscounteren : -1U;
+   uint32_t ctr_en = -1;
+   if (state.prv < PRV_M)
+     ctr_en &= state.mcounteren;
+   if (state.prv < PRV_S)
+     ctr_en &= state.scounteren;
    bool ctr_ok = (ctr_en >> (which & 31)) & 1;
  
    if (ctr_ok) {
    }
    if (which >= CSR_MHPMCOUNTER3 && which <= CSR_MHPMCOUNTER31)
      return 0;
-   if (xlen == 32 && which >= CSR_MHPMCOUNTER3 && which <= CSR_MHPMCOUNTER31)
+   if (xlen == 32 && which >= CSR_MHPMCOUNTER3H && which <= CSR_MHPMCOUNTER31H)
      return 0;
    if (which >= CSR_MHPMEVENT3 && which <= CSR_MHPMEVENT31)
      return 0;
        if (xlen == 32)
          return state.minstret >> 32;
        break;
-     case CSR_MUCOUNTEREN: return state.mucounteren;
-     case CSR_MSCOUNTEREN: return state.mscounteren;
+     case CSR_SCOUNTEREN: return state.scounteren;
+     case CSR_MCOUNTEREN: return state.mcounteren;
      case CSR_SSTATUS: {
        reg_t mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP | SSTATUS_FS
-                  | SSTATUS_XS | SSTATUS_PUM;
+                  | SSTATUS_XS | SSTATUS_SUM;
        reg_t sstatus = state.mstatus & mask;
        if ((sstatus & SSTATUS_FS) == SSTATUS_FS ||
            (sstatus & SSTATUS_XS) == SSTATUS_XS)
        if (max_xlen > xlen)
          return state.scause | ((state.scause >> (max_xlen-1)) << (xlen-1));
        return state.scause;
-     case CSR_SPTBR: return state.sptbr;
+     case CSR_SPTBR:
+       if (get_field(state.mstatus, MSTATUS_TVM))
+         require_privilege(PRV_M);
+       return state.sptbr;
      case CSR_SSCRATCH: return state.sscratch;
      case CSR_MSTATUS: return state.mstatus;
      case CSR_MIP: return state.mip;
        {
          uint32_t v = 0;
          v = set_field(v, DCSR_XDEBUGVER, 1);
 -        v = set_field(v, DCSR_NDRESET, 0);
 -        v = set_field(v, DCSR_FULLRESET, 0);
 -        v = set_field(v, DCSR_PRV, state.dcsr.prv);
 -        v = set_field(v, DCSR_STEP, state.dcsr.step);
 -        v = set_field(v, DCSR_DEBUGINT, sim->debug_module.get_interrupt(id));
 -        v = set_field(v, DCSR_STOPCYCLE, 0);
 -        v = set_field(v, DCSR_STOPTIME, 0);
          v = set_field(v, DCSR_EBREAKM, state.dcsr.ebreakm);
          v = set_field(v, DCSR_EBREAKH, state.dcsr.ebreakh);
          v = set_field(v, DCSR_EBREAKS, state.dcsr.ebreaks);
          v = set_field(v, DCSR_EBREAKU, state.dcsr.ebreaku);
 -        v = set_field(v, DCSR_HALT, state.dcsr.halt);
 +        v = set_field(v, DCSR_STOPCYCLE, 0);
 +        v = set_field(v, DCSR_STOPTIME, 0);
          v = set_field(v, DCSR_CAUSE, state.dcsr.cause);
 +        v = set_field(v, DCSR_STEP, state.dcsr.step);
 +        v = set_field(v, DCSR_PRV, state.dcsr.prv);
          return v;
        }
      case CSR_DPC:
      case CSR_DSCRATCH:
        return state.dscratch;
    }
-   throw trap_illegal_instruction();
+   throw trap_illegal_instruction(0);
  }
  
  reg_t illegal_instruction(processor_t* p, insn_t insn, reg_t pc)
  {
-   throw trap_illegal_instruction();
+   throw trap_illegal_instruction(0);
  }
  
  insn_func_t processor_t::decode_insn(insn_t insn)
@@@ -713,6 -694,17 +708,17 @@@ void processor_t::register_base_instruc
  
  bool processor_t::load(reg_t addr, size_t len, uint8_t* bytes)
  {
+   switch (addr)
+   {
+     case 0:
+       if (len <= 4) {
+         memset(bytes, 0, len);
+         bytes[0] = get_field(state.mip, MIP_MSIP);
+         return true;
+       }
+       break;
+   }
    return false;
  }
  
@@@ -721,14 -713,14 +727,14 @@@ bool processor_t::store(reg_t addr, siz
    switch (addr)
    {
      case 0:
-       state.mip &= ~MIP_MSIP;
-       if (bytes[0] & 1)
-         state.mip |= MIP_MSIP;
-       return true;
-     default:
-       return false;
+       if (len <= 4) {
+         state.mip = set_field(state.mip, MIP_MSIP, bytes[0]);
+         return true;
+       }
+       break;
    }
+   return false;
  }
  
  void processor_t::trigger_updated()
diff --combined riscv/processor.h
index 3268029e458d5832bd09b274bace4a88ca05a249,7e9e932f7b13a8c5cd4cb3275c3a697913c6f0f1..4d94d5b42a9a181886c4a520fead3cd0edf67a97
@@@ -105,8 -105,8 +105,8 @@@ struct state_
    reg_t mip;
    reg_t medeleg;
    reg_t mideleg;
-   uint32_t mucounteren;
-   uint32_t mscounteren;
+   uint32_t mcounteren;
+   uint32_t scounteren;
    reg_t sepc;
    reg_t sbadaddr;
    reg_t sscratch;
@@@ -167,7 -167,6 +167,6 @@@ public
    void reset();
    void step(size_t n); // run for n cycles
    void set_csr(int which, reg_t val);
-   void raise_interrupt(reg_t which);
    reg_t get_csr(int which);
    mmu_t* get_mmu() { return mmu; }
    state_t* get_state() { return &state; }
    bool debug;
    // When true, take the slow simulation path.
    bool slow_path();
 +  bool halted() { return state.dcsr.cause ? true : false; }
 +  bool halt_request;
 +  // The unique debug rom address that this hart jumps to when entering debug
 +  // mode. Rely on the fact that spike hart IDs start at 0 and are consecutive.
 +  uint32_t debug_rom_entry() {
 +    return DEBUG_ROM_ENTRY + 4 * id;
 +  }
  
    // Return the index of a trigger that matched, or -1.
    inline int trigger_match(trigger_operation_t operation, reg_t address, reg_t data)
@@@ -304,8 -296,8 +303,8 @@@ private
    static const size_t OPCODE_CACHE_SIZE = 8191;
    insn_desc_t opcode_cache[OPCODE_CACHE_SIZE];
  
-   void check_timer();
-   void take_interrupt(); // take a trap if any interrupts are pending
+   void take_pending_interrupt() { take_interrupt(state.mip & state.mie); }
+   void take_interrupt(reg_t mask); // take first enabled interrupt in mask
    void take_trap(trap_t& t, reg_t epc); // take an exception
    void disasm(insn_t insn); // disassemble and print an instruction
    int paddr_bits();
  
    friend class sim_t;
    friend class mmu_t;
-   friend class rtc_t;
+   friend class clint_t;
    friend class extension_t;
  
    void parse_isa_string(const char* isa);
diff --combined riscv/riscv.mk.in
index 6f12b846a5f30935709e6a3d8a3f9aae1257c250,e9544162f756250c0c5b61493c3709c2a43eec2c..9cd8f4dbef2c08599371c3880e0498d260e19eaf
@@@ -23,9 -23,8 +23,9 @@@ riscv_hdrs = 
        rocc.h \
        insn_template.h \
        mulhi.h \
 -      gdbserver.h \
        debug_module.h \
 +      remote_bitbang.h \
 +      jtag_dtm.h \
  
  riscv_precompiled_hdrs = \
        insn_template.h \
@@@ -45,10 -44,9 +45,12 @@@ riscv_srcs = 
        regnames.cc \
        devices.cc \
        rom.cc \
 +      rtc.cc \
+       clint.cc \
+       gdbserver.cc \
        debug_module.cc \
 +      remote_bitbang.cc \
 +      jtag_dtm.cc \
        $(riscv_gen_srcs) \
  
  riscv_test_srcs =
@@@ -229,7 -227,7 +231,7 @@@ riscv_insn_list = 
        sc_d \
        sc_w \
        sd \
-       sfence_vm \
+       sfence_vma \
        sh \
        sll \
        slli \
diff --combined riscv/sim.cc
index 033f12bc40983c211e09693037d56fcc8dcc2e26,7a10c9b4d2c9a4705cf726c0bd638e242950f7b4..a44ced6a832a67950bd4d620b1b66cccde310c15
@@@ -2,7 -2,7 +2,7 @@@
  
  #include "sim.h"
  #include "mmu.h"
 -#include "gdbserver.h"
 +#include "remote_bitbang.h"
  #include <map>
  #include <iostream>
  #include <sstream>
@@@ -10,6 -10,9 +10,9 @@@
  #include <cstdlib>
  #include <cassert>
  #include <signal.h>
+ #include <unistd.h>
+ #include <sys/wait.h>
+ #include <sys/types.h>
  
  volatile bool ctrlc_pressed = false;
  static void handle_signal(int sig)
@@@ -22,8 -25,8 +25,8 @@@
  
  sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb, bool halted,
               const std::vector<std::string>& args)
 -  : htif_t(args), procs(std::max(nprocs, size_t(1))),
 -    current_step(0), current_proc(0), debug(false), gdbserver(NULL)
 +  : htif_t(args), debug_module(this), procs(std::max(nprocs, size_t(1))),
 +    current_step(0), current_proc(0), debug(false), remote_bitbang(NULL)
  {
    signal(SIGINT, &handle_signal);
    // allocate target machine's memory, shrinking it as necessary
@@@ -31,7 -34,7 +34,7 @@@
    size_t memsz0 = (size_t)mem_mb << 20;
    size_t quantum = 1L << 20;
    if (memsz0 == 0)
-     memsz0 = (size_t)((sizeof(size_t) == 8 ? 4096 : 2048) - 256) << 20;
+     memsz0 = (size_t)2048 << 20;
  
    memsz = memsz0;
    while ((mem = (char*)calloc(1, memsz)) == NULL)
@@@ -41,7 -44,7 +44,7 @@@
      fprintf(stderr, "warning: only got %zu bytes of target mem (wanted %zu)\n",
              memsz, memsz0);
  
 -  bus.add_device(DEBUG_START, &debug_module);
 +  debug_module.add_device(&bus);
  
    debug_mmu = new mmu_t(this, NULL);
  
      procs[i] = new processor_t(isa, this, i, halted);
    }
  
-   rtc.reset(new rtc_t(procs));
-   make_config_string();
+   clint.reset(new clint_t(procs));
+   bus.add_device(CLINT_BASE, clint.get());
+   make_dtb();
  }
  
  sim_t::~sim_t()
@@@ -77,8 -82,8 +82,8 @@@ void sim_t::main(
        interactive();
      else
        step(INTERLEAVE);
 -    if (gdbserver) {
 -      gdbserver->handle();
 +    if (remote_bitbang) {
 +      remote_bitbang->tick();
      }
    }
  }
@@@ -104,7 -109,7 +109,7 @@@ void sim_t::step(size_t n
        procs[current_proc]->yield_load_reservation();
        if (++current_proc == procs.size()) {
          current_proc = 0;
-         rtc->increment(INTERLEAVE / INSNS_PER_RTC_TICK);
+         clint->increment(INTERLEAVE / INSNS_PER_RTC_TICK);
        }
  
        host->switch_to();
@@@ -150,59 -155,162 +155,162 @@@ bool sim_t::mmio_store(reg_t addr, size
    return bus.store(addr, len, bytes);
  }
  
void sim_t::make_config_string()
static std::string dts_compile(const std::string& dts)
  {
-   reg_t rtc_addr = EXT_IO_BASE;
-   bus.add_device(rtc_addr, rtc.get());
+   // Convert the DTS to DTB
+   int dts_pipe[2];
+   pid_t dts_pid;
  
-   const int align = 0x1000;
-   reg_t cpu_addr = rtc_addr + ((rtc->size() - 1) / align + 1) * align;
-   reg_t cpu_size = align;
-   uint32_t reset_vec[8] = {
-     0x297 + DRAM_BASE - DEFAULT_RSTVEC, // reset vector
-     0x00028067,                         //   jump straight to DRAM_BASE
-     0x00000000,                         // reserved
-     0,                                  // config string pointer
-     0, 0, 0, 0                          // trap vector
+   if (pipe(dts_pipe) != 0 || (dts_pid = fork()) < 0) {
+     std::cerr << "Failed to fork dts child: " << strerror(errno) << std::endl;
+     exit(1);
+   }
+   // Child process to output dts
+   if (dts_pid == 0) {
+     close(dts_pipe[0]);
+     int step, len = dts.length();
+     const char *buf = dts.c_str();
+     for (int done = 0; done < len; done += step) {
+       step = write(dts_pipe[1], buf+done, len-done);
+       if (step == -1) {
+         std::cerr << "Failed to write dts: " << strerror(errno) << std::endl;
+         exit(1);
+       }
+     }
+     close(dts_pipe[1]);
+     exit(0);
+   }
+   pid_t dtb_pid;
+   int dtb_pipe[2];
+   if (pipe(dtb_pipe) != 0 || (dtb_pid = fork()) < 0) {
+     std::cerr << "Failed to fork dtb child: " << strerror(errno) << std::endl;
+     exit(1);
+   }
+   // Child process to output dtb
+   if (dtb_pid == 0) {
+     dup2(dts_pipe[0], 0);
+     dup2(dtb_pipe[1], 1);
+     close(dts_pipe[0]);
+     close(dts_pipe[1]);
+     close(dtb_pipe[0]);
+     close(dtb_pipe[1]);
+     execl(DTC, DTC, "-O", "dtb", 0);
+     std::cerr << "Failed to run " DTC ": " << strerror(errno) << std::endl;
+     exit(1);
+   }
+   close(dts_pipe[1]);
+   close(dts_pipe[0]);
+   close(dtb_pipe[1]);
+   // Read-out dtb
+   std::stringstream dtb;
+   int got;
+   char buf[4096];
+   while ((got = read(dtb_pipe[0], buf, sizeof(buf))) > 0) {
+     dtb.write(buf, got);
+   }
+   if (got == -1) {
+     std::cerr << "Failed to read dtb: " << strerror(errno) << std::endl;
+     exit(1);
+   }
+   close(dtb_pipe[0]);
+   // Reap children
+   int status;
+   waitpid(dts_pid, &status, 0);
+   if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+     std::cerr << "Child dts process failed" << std::endl;
+     exit(1);
+   }
+   waitpid(dtb_pid, &status, 0);
+   if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+     std::cerr << "Child dtb process failed" << std::endl;
+     exit(1);
+   }
+   return dtb.str();
+ }
+ void sim_t::make_dtb()
+ {
+   uint32_t reset_vec[] = {
+     0x297 + DRAM_BASE - DEFAULT_RSTVEC, // auipc t0, DRAM_BASE
+     0x597,                              // auipc a1, 0
+     0x58593,                            // addi a1, a1, 0
+     0xf1402573,                               // csrr a0,mhartid
+     0x00028067                          // jalr zero, t0, 0 (jump straight to DRAM_BASE)
    };
-   reset_vec[3] = DEFAULT_RSTVEC + sizeof(reset_vec); // config string pointer
+   reset_vec[2] += (sizeof(reset_vec) - 4) << 20; // addi a1, a1, sizeof(reset_vec) - 4 = DTB start
  
    std::vector<char> rom((char*)reset_vec, (char*)reset_vec + sizeof(reset_vec));
  
    std::stringstream s;
-   s << std::hex <<
-         "platform {\n"
-         "  vendor ucb;\n"
-         "  arch spike;\n"
-         "};\n"
-         "rtc {\n"
-         "  addr 0x" << rtc_addr << ";\n"
-         "};\n"
-         "ram {\n"
-         "  0 {\n"
-         "    addr 0x" << DRAM_BASE << ";\n"
-         "    size 0x" << memsz << ";\n"
-         "  };\n"
-         "};\n"
-         "core {\n";
+   s << std::dec <<
+          "/dts-v1/;\n"
+          "\n"
+          "/ {\n"
+          "  #address-cells = <2>;\n"
+          "  #size-cells = <2>;\n"
+          "  compatible = \"ucbbar,spike-bare-dev\";\n"
+          "  model = \"ucbbar,spike-bare\";\n"
+          "  cpus {\n"
+          "    #address-cells = <1>;\n"
+          "    #size-cells = <0>;\n"
+          "    timebase-frequency = <" << (CPU_HZ/INSNS_PER_RTC_TICK) << ">;\n";
    for (size_t i = 0; i < procs.size(); i++) {
-     s <<
-         "  " << i << " {\n"
-         "    " << "0 {\n" << // hart 0 on core i
-         "      isa " << procs[i]->isa_string << ";\n"
-         "      timecmp 0x" << (rtc_addr + 8*(1+i)) << ";\n"
-         "      ipi 0x" << cpu_addr << ";\n"
-         "    };\n"
-         "  };\n";
-     bus.add_device(cpu_addr, procs[i]);
-     cpu_addr += cpu_size;
+     s << "    CPU" << i << ": cpu@" << i << " {\n"
+          "      device_type = \"cpu\";\n"
+          "      reg = <" << i << ">;\n"
+          "      status = \"okay\";\n"
+          "      compatible = \"riscv\";\n"
+          "      riscv,isa = \"" << procs[i]->isa_string << "\";\n"
+          "      mmu-type = \"riscv," << (procs[i]->max_xlen <= 32 ? "sv32" : "sv48") << "\";\n"
+          "      clock-frequency = <" << CPU_HZ << ">;\n"
+          "      CPU" << i << "_intc: interrupt-controller {\n"
+          "        #interrupt-cells = <1>;\n"
+          "        interrupt-controller;\n"
+          "        compatible = \"riscv,cpu-intc\";\n"
+          "      };\n"
+          "    };\n";
    }
-   s <<  "};\n";
-   config_string = s.str();
-   rom.insert(rom.end(), config_string.begin(), config_string.end());
-   rom.resize((rom.size() / align + 1) * align);
+   reg_t membs = DRAM_BASE;
+   s << std::hex <<
+          "  };\n"
+          "  memory@" << DRAM_BASE << " {\n"
+          "    device_type = \"memory\";\n"
+          "    reg = <0x" << (membs >> 32) << " 0x" << (membs & (uint32_t)-1) <<
+                    " 0x" << (memsz >> 32) << " 0x" << (memsz & (uint32_t)-1) << ">;\n"
+          "  };\n"
+          "  soc {\n"
+          "    #address-cells = <2>;\n"
+          "    #size-cells = <2>;\n"
+          "    compatible = \"ucbbar,spike-bare-soc\", \"simple-bus\";\n"
+          "    ranges;\n"
+          "    clint@" << CLINT_BASE << " {\n"
+          "      compatible = \"riscv,clint0\";\n"
+          "      interrupts-extended = <" << std::dec;
+   for (size_t i = 0; i < procs.size(); i++)
+     s << "&CPU" << i << "_intc 3 &CPU" << i << "_intc 7 ";
+   reg_t clintbs = CLINT_BASE;
+   reg_t clintsz = CLINT_SIZE;
+   s << std::hex << ">;\n"
+          "      reg = <0x" << (clintbs >> 32) << " 0x" << (clintbs & (uint32_t)-1) <<
+                      " 0x" << (clintsz >> 32) << " 0x" << (clintsz & (uint32_t)-1) << ">;\n"
+          "    };\n"
+          "  };\n"
+          "};\n";
+   dts = s.str();
+   std::string dtb = dts_compile(dts);
+   rom.insert(rom.end(), dtb.begin(), dtb.end());
+   const int align = 0x1000;
+   rom.resize((rom.size() + align - 1) / align * align);
  
    boot_rom.reset(new rom_device_t(rom));
    bus.add_device(DEFAULT_RSTVEC, boot_rom.get());
diff --combined riscv/sim.h
index 4cb70b4d47deee29839968be430810be2e75e4d2,8586bee2cf970ee449227af57b72f6da991c5f3b..d3353a1bbcfd4cebb79abcfddadd11c552b14ea1
@@@ -13,7 -13,7 +13,7 @@@
  #include <memory>
  
  class mmu_t;
 -class gdbserver_t;
 +class remote_bitbang_t;
  
  // this class encapsulates the processors and memory in a RISC-V machine.
  class sim_t : public htif_t
@@@ -29,35 -29,32 +29,36 @@@ public
    void set_log(bool value);
    void set_histogram(bool value);
    void set_procs_debug(bool value);
 -  void set_gdbserver(gdbserver_t* gdbserver) { this->gdbserver = gdbserver; }
 +  void set_remote_bitbang(remote_bitbang_t* remote_bitbang) {
 +    this->remote_bitbang = remote_bitbang;
 +  }
-   const char* get_config_string() { return config_string.c_str(); }
+   const char* get_dts() { return dts.c_str(); }
    processor_t* get_core(size_t i) { return procs.at(i); }
 +  unsigned nprocs() const { return procs.size(); }
 +
 +  debug_module_t debug_module;
  
  private:
    char* mem; // main memory
    size_t memsz; // memory size in bytes
    mmu_t* debug_mmu;  // debug port into main memory
    std::vector<processor_t*> procs;
-   std::string config_string;
+   std::string dts;
    std::unique_ptr<rom_device_t> boot_rom;
-   std::unique_ptr<rtc_t> rtc;
+   std::unique_ptr<clint_t> clint;
    bus_t bus;
 -  debug_module_t debug_module;
  
    processor_t* get_core(const std::string& i);
    void step(size_t n); // step through simulation
    static const size_t INTERLEAVE = 5000;
    static const size_t INSNS_PER_RTC_TICK = 100; // 10 MHz clock for 1 BIPS core
+   static const size_t CPU_HZ = 1000000000; // 1GHz CPU
    size_t current_step;
    size_t current_proc;
    bool debug;
    bool log;
    bool histogram_enabled; // provide a histogram of PCs
 -  gdbserver_t* gdbserver;
 +  remote_bitbang_t* remote_bitbang;
  
    // memory-mapped I/O routines
    bool addr_is_mem(reg_t addr) {
@@@ -67,7 -64,7 +68,7 @@@
    reg_t mem_to_addr(char* x) { return x - mem + DRAM_BASE; }
    bool mmio_load(reg_t addr, size_t len, uint8_t* bytes);
    bool mmio_store(reg_t addr, size_t len, const uint8_t* bytes);
-   void make_config_string();
+   void make_dtb();
  
    // presents a prompt for introspection into the simulation
    void interactive();
@@@ -79,6 -76,7 +80,7 @@@
    void interactive_run_noisy(const std::string& cmd, const std::vector<std::string>& args);
    void interactive_run_silent(const std::string& cmd, const std::vector<std::string>& args);
    void interactive_reg(const std::string& cmd, const std::vector<std::string>& args);
+   void interactive_freg(const std::string& cmd, const std::vector<std::string>& args);
    void interactive_fregs(const std::string& cmd, const std::vector<std::string>& args);
    void interactive_fregd(const std::string& cmd, const std::vector<std::string>& args);
    void interactive_pc(const std::string& cmd, const std::vector<std::string>& args);
    void interactive_str(const std::string& cmd, const std::vector<std::string>& args);
    void interactive_until(const std::string& cmd, const std::vector<std::string>& args);
    reg_t get_reg(const std::vector<std::string>& args);
-   reg_t get_freg(const std::vector<std::string>& args);
+   freg_t get_freg(const std::vector<std::string>& args);
    reg_t get_mem(const std::vector<std::string>& args);
    reg_t get_pc(const std::vector<std::string>& args);
  
    friend class processor_t;
    friend class mmu_t;
 -  friend class gdbserver_t;
  
    // htif
    friend void sim_thread_main(void*);
diff --combined spike_main/spike.cc
index 846b1d9bdbd51ff8daec6715337427b69a395572,dde6f5a5b902e458c9b3b7f9a0ffd7aefc188590..38529b2504e3297e2101e7594cd63ec9c6db305a
@@@ -2,7 -2,7 +2,7 @@@
  
  #include "sim.h"
  #include "mmu.h"
 -#include "gdbserver.h"
 +#include "remote_bitbang.h"
  #include "cachesim.h"
  #include "extension.h"
  #include <dlfcn.h>
@@@ -30,8 -30,8 +30,8 @@@ static void help(
    fprintf(stderr, "  --l2=<S>:<W>:<B>        B both powers of 2).\n");
    fprintf(stderr, "  --extension=<name>    Specify RoCC Extension\n");
    fprintf(stderr, "  --extlib=<name>       Shared library to load\n");
 -  fprintf(stderr, "  --gdb-port=<port>  Listen on <port> for gdb to connect\n");
 +  fprintf(stderr, "  --rbb-port=<port>     Listen on <port> for remote bitbang connection\n");
-   fprintf(stderr, "  --dump-config-string  Print platform configuration string and exit\n");
+   fprintf(stderr, "  --dump-dts  Print device tree string and exit\n");
    exit(1);
  }
  
@@@ -41,7 -41,7 +41,7 @@@ int main(int argc, char** argv
    bool halted = false;
    bool histogram = false;
    bool log = false;
-   bool dump_config_string = false;
+   bool dump_dts = false;
    size_t nprocs = 1;
    size_t mem_mb = 0;
    std::unique_ptr<icache_sim_t> ic;
@@@ -49,8 -49,7 +49,8 @@@
    std::unique_ptr<cache_sim_t> l2;
    std::function<extension_t*()> extension;
    const char* isa = DEFAULT_ISA;
 -  uint16_t gdb_port = 0;
 +  uint16_t rbb_port = 0;
 +  bool use_rbb = false;
  
    option_parser_t parser;
    parser.help(&help);
    parser.option('m', 0, 1, [&](const char* s){mem_mb = atoi(s);});
    // I wanted to use --halted, but for some reason that doesn't work.
    parser.option('H', 0, 0, [&](const char* s){halted = true;});
 -  parser.option(0, "gdb-port", 1, [&](const char* s){gdb_port = atoi(s);});
 +  parser.option(0, "rbb-port", 1, [&](const char* s){use_rbb = true; rbb_port = atoi(s);});
    parser.option(0, "ic", 1, [&](const char* s){ic.reset(new icache_sim_t(s));});
    parser.option(0, "dc", 1, [&](const char* s){dc.reset(new dcache_sim_t(s));});
    parser.option(0, "l2", 1, [&](const char* s){l2.reset(cache_sim_t::construct(s, "L2$"));});
    parser.option(0, "isa", 1, [&](const char* s){isa = s;});
    parser.option(0, "extension", 1, [&](const char* s){extension = find_extension(s);});
-   parser.option(0, "dump-config-string", 0, [&](const char *s){dump_config_string = true;});
+   parser.option(0, "dump-dts", 0, [&](const char *s){dump_dts = true;});
    parser.option(0, "extlib", 1, [&](const char *s){
      void *lib = dlopen(s, RTLD_NOW | RTLD_GLOBAL);
      if (lib == NULL) {
    auto argv1 = parser.parse(argv);
    std::vector<std::string> htif_args(argv1, (const char*const*)argv + argc);
    sim_t s(isa, nprocs, mem_mb, halted, htif_args);
 -  std::unique_ptr<gdbserver_t> gdbserver;
 -  if (gdb_port) {
 -    gdbserver = std::unique_ptr<gdbserver_t>(new gdbserver_t(gdb_port, &s));
 -    s.set_gdbserver(&(*gdbserver));
 +  std::unique_ptr<jtag_dtm_t> jtag_dtm(new jtag_dtm_t(&s.debug_module));
 +  std::unique_ptr<remote_bitbang_t> remote_bitbang((remote_bitbang_t *) NULL);
 +  if (use_rbb) {
 +    remote_bitbang.reset(new remote_bitbang_t(rbb_port, &(*jtag_dtm)));
 +    s.set_remote_bitbang(&(*remote_bitbang));
    }
  
-   if (dump_config_string) {
-     printf("%s", s.get_config_string());
+   if (dump_dts) {
+     printf("%s", s.get_dts());
      return 0;
    }