Merge branch 'master' into trigger
authorTim Newsome <tim@sifive.com>
Fri, 2 Sep 2016 20:28:14 +0000 (13:28 -0700)
committerTim Newsome <tim@sifive.com>
Fri, 2 Sep 2016 20:28:14 +0000 (13:28 -0700)
Conflicts:
riscv/encoding.h
riscv/processor.cc

1  2 
riscv/processor.cc
riscv/processor.h

diff --combined riscv/processor.cc
index e1f132e8b66ab11ba38c48f273bd1a50133bd77c,78fb5f11ec20ab87205b41360a95907674e10265..6d0b98356d6b11fb410c3db8a141ce29ac435b4b
@@@ -118,9 -118,6 +118,9 @@@ void state_t::reset(
    pc = DEFAULT_RSTVEC;
    mtvec = DEFAULT_MTVEC;
    load_reservation = -1;
 +  tselect = 0;
 +  for (unsigned int i = 0; i < num_triggers; i++)
 +    mcontrol[i].type = 2;
  }
  
  void processor_t::set_debug(bool value)
@@@ -157,7 -154,6 +157,7 @@@ void processor_t::raise_interrupt(reg_
    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)
  {
    int res = 0;
@@@ -199,6 -195,7 +199,6 @@@ void processor_t::enter_debug_mode(uint
    set_privilege(PRV_M);
    state.dpc = state.pc;
    state.pc = DEBUG_ROM_START;
 -  //debug = true; // TODO
  }
  
  void processor_t::take_trap(trap_t& t, reg_t epc)
@@@ -349,11 -346,22 +349,22 @@@ void processor_t::set_csr(int which, re
        state.medeleg = (state.medeleg & ~mask) | (val & mask);
        break;
      }
+     case CSR_MINSTRET:
+     case CSR_MCYCLE:
+       if (xlen == 32)
+         state.minstret = (state.minstret >> 32 << 32) | (val & 0xffffffffU);
+       else
+         state.minstret = val;
+       break;
+     case CSR_MINSTRETH:
+     case CSR_MCYCLEH:
+       state.minstret = (val << 32) | (state.minstret << 32 >> 32);
+       break;
      case CSR_MUCOUNTEREN:
-       state.mucounteren = val & 7;
+       state.mucounteren = val;
        break;
      case CSR_MSCOUNTEREN:
-       state.mscounteren = val & 7;
+       state.mscounteren = val;
        break;
      case CSR_SSTATUS: {
        reg_t mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP | SSTATUS_FS
      case CSR_MSCRATCH: state.mscratch = val; break;
      case CSR_MCAUSE: state.mcause = val; break;
      case CSR_MBADADDR: state.mbadaddr = val; break;
 +    case CSR_TSELECT:
 +      if (val < state.num_triggers) {
 +        state.tselect = val;
 +      }
 +      break;
 +    case CSR_TDATA1:
 +      {
 +        mcontrol_t *mc = &state.mcontrol[state.tselect];
 +        if (mc->dmode && !state.dcsr.cause) {
 +          throw trap_illegal_instruction();
 +        }
 +        mc->dmode = get_field(val, MCONTROL_DMODE(xlen));
 +        mc->select = get_field(val, MCONTROL_SELECT);
 +        mc->timing = get_field(val, MCONTROL_TIMING);
 +        mc->action = (mcontrol_action_t) get_field(val, MCONTROL_ACTION);
 +        mc->chain = get_field(val, MCONTROL_CHAIN);
 +        mc->match = (mcontrol_match_t) get_field(val, MCONTROL_MATCH);
 +        mc->m = get_field(val, MCONTROL_M);
 +        mc->h = get_field(val, MCONTROL_H);
 +        mc->s = get_field(val, MCONTROL_S);
 +        mc->u = get_field(val, MCONTROL_U);
 +        mc->execute = get_field(val, MCONTROL_EXECUTE);
 +        mc->store = get_field(val, MCONTROL_STORE);
 +        mc->load = get_field(val, MCONTROL_LOAD);
 +        // Assume we're here because of csrw.
 +        if (mc->execute)
 +          mc->timing = 0;
 +        if (mc->load)
 +          mc->timing = 1;
 +        trigger_updated();
 +      }
 +      break;
 +    case CSR_TDATA2:
 +      if (state.tselect < state.num_triggers) {
 +        state.tdata2[state.tselect] = val;
 +      }
 +      break;
      case CSR_DCSR:
        state.dcsr.prv = get_field(val, DCSR_PRV);
        state.dcsr.step = get_field(val, DCSR_STEP);
  
  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;
+   bool ctr_ok = (ctr_en >> (which & 31)) & 1;
+   if (ctr_ok) {
+     if (which >= CSR_HPMCOUNTER3 && which <= CSR_HPMCOUNTER31)
+       return 0;
+     if (xlen == 32 && which >= CSR_HPMCOUNTER3H && which <= CSR_HPMCOUNTER31H)
+       return 0;
+   }
+   if (which >= CSR_MHPMCOUNTER3 && which <= CSR_MHPMCOUNTER31)
+     return 0;
+   if (xlen == 32 && which >= CSR_MHPMCOUNTER3 && which <= CSR_MHPMCOUNTER31)
+     return 0;
+   if (which >= CSR_MHPMEVENT3 && which <= CSR_MHPMEVENT31)
+     return 0;
    switch (which)
    {
      case CSR_FFLAGS:
        if (!supports_extension('F'))
          break;
        return (state.fflags << FSR_AEXC_SHIFT) | (state.frm << FSR_RD_SHIFT);
-     case CSR_TIME:
      case CSR_INSTRET:
      case CSR_CYCLE:
-       if ((state.mucounteren >> (which & (xlen-1))) & 1)
-         return get_csr(which + (CSR_MCYCLE - CSR_CYCLE));
+       if (ctr_ok)
+         return state.minstret;
        break;
-     case CSR_STIME:
-     case CSR_SINSTRET:
-     case CSR_SCYCLE:
-       if ((state.mscounteren >> (which & (xlen-1))) & 1)
-         return get_csr(which + (CSR_MCYCLE - CSR_SCYCLE));
+     case CSR_MINSTRET:
+     case CSR_MCYCLE:
+       return state.minstret;
+     case CSR_MINSTRETH:
+     case CSR_MCYCLEH:
+       if (xlen == 32)
+         return state.minstret >> 32;
        break;
      case CSR_MUCOUNTEREN: return state.mucounteren;
      case CSR_MSCOUNTEREN: return state.mscounteren;
-     case CSR_MUCYCLE_DELTA: return 0;
-     case CSR_MUTIME_DELTA: return 0;
-     case CSR_MUINSTRET_DELTA: return 0;
-     case CSR_MSCYCLE_DELTA: return 0;
-     case CSR_MSTIME_DELTA: return 0;
-     case CSR_MSINSTRET_DELTA: return 0;
-     case CSR_MUCYCLE_DELTAH: if (xlen > 32) break; else return 0;
-     case CSR_MUTIME_DELTAH: if (xlen > 32) break; else return 0;
-     case CSR_MUINSTRET_DELTAH: if (xlen > 32) break; else return 0;
-     case CSR_MSCYCLE_DELTAH: if (xlen > 32) break; else return 0;
-     case CSR_MSTIME_DELTAH: if (xlen > 32) break; else return 0;
-     case CSR_MSINSTRET_DELTAH: if (xlen > 32) break; else return 0;
-     case CSR_MCYCLE: return state.minstret;
-     case CSR_MINSTRET: return state.minstret;
-     case CSR_MCYCLEH: if (xlen > 32) break; else return state.minstret >> 32;
-     case CSR_MINSTRETH: if (xlen > 32) break; else return state.minstret >> 32;
      case CSR_SSTATUS: {
        reg_t mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP | SSTATUS_FS
                   | SSTATUS_XS | SSTATUS_PUM;
      case CSR_MTVEC: return state.mtvec;
      case CSR_MEDELEG: return state.medeleg;
      case CSR_MIDELEG: return state.mideleg;
 -    case CSR_TSELECT: return 0;
 -    case CSR_TDATA1: return 0;
 -    case CSR_TDATA2: return 0;
 +    case CSR_TSELECT: return state.tselect;
 +    case CSR_TDATA1:
 +      if (state.tselect < state.num_triggers) {
 +        reg_t v = 0;
 +        mcontrol_t *mc = &state.mcontrol[state.tselect];
 +        v = set_field(v, MCONTROL_TYPE(xlen), mc->type);
 +        v = set_field(v, MCONTROL_DMODE(xlen), mc->dmode);
 +        v = set_field(v, MCONTROL_MASKMAX(xlen), mc->maskmax);
 +        v = set_field(v, MCONTROL_SELECT, mc->select);
 +        v = set_field(v, MCONTROL_TIMING, mc->timing);
 +        v = set_field(v, MCONTROL_ACTION, mc->action);
 +        v = set_field(v, MCONTROL_CHAIN, mc->chain);
 +        v = set_field(v, MCONTROL_MATCH, mc->match);
 +        v = set_field(v, MCONTROL_M, mc->m);
 +        v = set_field(v, MCONTROL_H, mc->h);
 +        v = set_field(v, MCONTROL_S, mc->s);
 +        v = set_field(v, MCONTROL_U, mc->u);
 +        v = set_field(v, MCONTROL_EXECUTE, mc->execute);
 +        v = set_field(v, MCONTROL_STORE, mc->store);
 +        v = set_field(v, MCONTROL_LOAD, mc->load);
 +        return v;
 +      } else {
 +        return 0;
 +      }
 +      break;
 +    case CSR_TDATA2:
 +      if (state.tselect < state.num_triggers) {
 +        return state.tdata2[state.tselect];
 +      } else {
 +        return 0;
 +      }
 +      break;
+     case CSR_TDATA3: return 0;
      case CSR_DCSR:
        {
          uint32_t v = 0;
@@@ -682,23 -627,3 +696,23 @@@ bool processor_t::store(reg_t addr, siz
        return false;
    }
  }
 +
 +void processor_t::trigger_updated()
 +{
 +  mmu->flush_tlb();
 +  mmu->check_triggers_fetch = false;
 +  mmu->check_triggers_load = false;
 +  mmu->check_triggers_store = false;
 +
 +  for (unsigned i = 0; i < state.num_triggers; i++) {
 +    if (state.mcontrol[i].execute) {
 +      mmu->check_triggers_fetch = true;
 +    }
 +    if (state.mcontrol[i].load) {
 +      mmu->check_triggers_load = true;
 +    }
 +    if (state.mcontrol[i].store) {
 +      mmu->check_triggers_store = true;
 +    }
 +  }
 +}
diff --combined riscv/processor.h
index d5e8bc05a3841392423d5b81c7c60728766250e9,3f3d66b10849ab335a5234bd73745bf82434ec89..4d8dd640b72a921b9de01d03b4528a096f749305
@@@ -43,57 -43,17 +43,57 @@@ typedef struc
    uint8_t cause;
  } dcsr_t;
  
 +typedef enum
 +{
 +  ACTION_DEBUG_EXCEPTION = MCONTROL_ACTION_DEBUG_EXCEPTION,
 +  ACTION_DEBUG_MODE = MCONTROL_ACTION_DEBUG_MODE,
 +  ACTION_TRACE_START = MCONTROL_ACTION_TRACE_START,
 +  ACTION_TRACE_STOP = MCONTROL_ACTION_TRACE_STOP,
 +  ACTION_TRACE_EMIT = MCONTROL_ACTION_TRACE_EMIT
 +} mcontrol_action_t;
 +
 +typedef enum
 +{
 +  MATCH_EQUAL = MCONTROL_MATCH_EQUAL,
 +  MATCH_NAPOT = MCONTROL_MATCH_NAPOT,
 +  MATCH_GE = MCONTROL_MATCH_GE,
 +  MATCH_LT = MCONTROL_MATCH_LT,
 +  MATCH_MASK_LOW = MCONTROL_MATCH_MASK_LOW,
 +  MATCH_MASK_HIGH = MCONTROL_MATCH_MASK_HIGH
 +} mcontrol_match_t;
 +
 +typedef struct
 +{
 +  uint8_t type;
 +  bool dmode;
 +  uint8_t maskmax;
 +  bool select;
 +  bool timing;
 +  mcontrol_action_t action;
 +  bool chain;
 +  mcontrol_match_t match;
 +  bool m;
 +  bool h;
 +  bool s;
 +  bool u;
 +  bool execute;
 +  bool store;
 +  bool load;
 +} mcontrol_t;
 +
  // architectural state of a RISC-V hart
  struct state_t
  {
    void reset();
  
 +  static const int num_triggers = 4;
 +
    reg_t pc;
    regfile_t<reg_t, NXPR, true> XPR;
    regfile_t<freg_t, NFPR, false> FPR;
  
    // control and status registers
 -  reg_t prv;
 +  reg_t prv;    // TODO: Can this be an enum instead?
    reg_t mstatus;
    reg_t mepc;
    reg_t mbadaddr;
    reg_t mip;
    reg_t medeleg;
    reg_t mideleg;
-   reg_t mucounteren;
-   reg_t mscounteren;
+   uint32_t mucounteren;
+   uint32_t mscounteren;
    reg_t sepc;
    reg_t sbadaddr;
    reg_t sscratch;
    reg_t dpc;
    reg_t dscratch;
    dcsr_t dcsr;
 +  reg_t tselect;
 +  mcontrol_t mcontrol[num_triggers];
 +  reg_t tdata2[num_triggers];
  
    uint32_t fflags;
    uint32_t frm;
  #endif
  };
  
 +typedef enum {
 +  OPERATION_EXECUTE,
 +  OPERATION_STORE,
 +  OPERATION_LOAD,
 +} trigger_operation_t;
 +
 +// Count number of contiguous 1 bits starting from the LSB.
 +static int cto(reg_t val)
 +{
 +  int res = 0;
 +  while ((val & 1) == 1)
 +    val >>= 1, res++;
 +  return res;
 +}
 +
  // this class represents one processor in a RISC-V machine.
  class processor_t : public abstract_device_t
  {
@@@ -190,91 -132,6 +190,91 @@@ public
  
    // When true, display disassembly of each instruction that's executed.
    bool debug;
 +  // When true, take the slow simulation path.
 +  bool slow_path();
 +
 +  // Return the index of a trigger that matched, or -1.
 +  inline int trigger_match(trigger_operation_t operation, reg_t address, reg_t data)
 +  {
 +    if (state.dcsr.cause)
 +      return -1;
 +
 +    bool chain_ok = true;
 +
 +    for (unsigned int i = 0; i < state.num_triggers; i++) {
 +      if (!chain_ok) {
 +        chain_ok |= !state.mcontrol[i].chain;
 +        continue;
 +      }
 +
 +      if ((operation == OPERATION_EXECUTE && !state.mcontrol[i].execute) ||
 +          (operation == OPERATION_STORE && !state.mcontrol[i].store) ||
 +          (operation == OPERATION_LOAD && !state.mcontrol[i].load) ||
 +          (state.prv == PRV_M && !state.mcontrol[i].m) ||
 +          (state.prv == PRV_H && !state.mcontrol[i].h) ||
 +          (state.prv == PRV_S && !state.mcontrol[i].s) ||
 +          (state.prv == PRV_U && !state.mcontrol[i].u)) {
 +        continue;
 +      }
 +
 +      reg_t value;
 +      if (state.mcontrol[i].select) {
 +        value = data;
 +      } else {
 +        value = address;
 +      }
 +
 +      // We need this because in 32-bit mode sometimes the PC bits get sign
 +      // extended.
 +      if (xlen == 32) {
 +        value &= 0xffffffff;
 +      }
 +
 +      switch (state.mcontrol[i].match) {
 +        case MATCH_EQUAL:
 +          if (value != state.tdata2[i])
 +            continue;
 +          break;
 +        case MATCH_NAPOT:
 +          {
 +            reg_t mask = ~((1 << cto(state.tdata2[i])) - 1);
 +            if ((value & mask) != (state.tdata2[i] & mask))
 +              continue;
 +          }
 +          break;
 +        case MATCH_GE:
 +          if (value < state.tdata2[i])
 +            continue;
 +          break;
 +        case MATCH_LT:
 +          if (value >= state.tdata2[i])
 +            continue;
 +          break;
 +        case MATCH_MASK_LOW:
 +          {
 +            reg_t mask = state.tdata2[i] >> (xlen/2);
 +            if ((value & mask) != (state.tdata2[i] & mask))
 +              continue;
 +          }
 +          break;
 +        case MATCH_MASK_HIGH:
 +          {
 +            reg_t mask = state.tdata2[i] >> (xlen/2);
 +            if (((value >> (xlen/2)) & mask) != (state.tdata2[i] & mask))
 +              continue;
 +          }
 +          break;
 +      }
 +
 +      if (!state.mcontrol[i].chain) {
 +        return i;
 +      }
 +      chain_ok = true;
 +    }
 +    return -1;
 +  }
 +
 +  void trigger_updated();
  
  private:
    sim_t* sim;