difftest.cpp 9.0 KB
Newer Older
Z
Zihao Yu 已提交
1 2 3 4 5 6
#include "common.h"
#include "difftest.h"
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

Z
Zihao Yu 已提交
7 8 9
#ifndef REF_SO
# error Please define REF_SO to the path of NEMU shared object file
#endif
Z
Zihao Yu 已提交
10

11
#define selectBit(src, x) (src & (1 << x))
Z
Zihao Yu 已提交
12 13
#define DEBUG_RETIRE_TRACE_SIZE 16
#define DEBUG_WB_TRACE_SIZE 16
14

Z
Zihao Yu 已提交
15
void (*ref_difftest_memcpy_from_dut)(paddr_t dest, void *src, size_t n) = NULL;
Z
Zihao Yu 已提交
16
void (*ref_difftest_memcpy_from_ref)(void *dest, paddr_t src, size_t n) = NULL;
Z
Zihao Yu 已提交
17 18
void (*ref_difftest_getregs)(void *c) = NULL;
void (*ref_difftest_setregs)(const void *c) = NULL;
19 20
void (*ref_difftest_get_mastatus)(void *s) = NULL;
void (*ref_difftest_set_mastatus)(const void *s) = NULL;
21 22
void (*ref_difftest_get_csr)(void *c) = NULL;
void (*ref_difftest_set_csr)(const void *c) = NULL;
23
vaddr_t (*ref_disambiguate_exec)(void *disambiguate_para) = NULL;
Z
Zihao Yu 已提交
24 25 26
static void (*ref_difftest_exec)(uint64_t n) = NULL;
static void (*ref_difftest_raise_intr)(uint64_t NO) = NULL;
static void (*ref_isa_reg_display)(void) = NULL;
Z
Zihao Yu 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

static bool is_skip_ref;
static bool is_skip_dut;

// this is used to let ref skip instructions which
// can not produce consistent behavior with NEMU
void difftest_skip_ref() {
  is_skip_ref = true;
}

// this is used to deal with instruction packing in QEMU.
// Sometimes letting QEMU step once will execute multiple instructions.
// We should skip checking until NEMU's pc catches up with QEMU's pc.
void difftest_skip_dut() {
  if (is_skip_dut) return;

  ref_difftest_exec(1);
  is_skip_dut = true;
}

Z
Zihao Yu 已提交
47
void init_difftest() {
Z
Zihao Yu 已提交
48 49
  void *handle;
  handle = dlopen(REF_SO, RTLD_LAZY | RTLD_DEEPBIND);
Z
Zihao Yu 已提交
50
  puts("Using " REF_SO " for difftest");
Z
Zihao Yu 已提交
51 52 53 54 55
  assert(handle);

  ref_difftest_memcpy_from_dut = (void (*)(paddr_t, void *, size_t))dlsym(handle, "difftest_memcpy_from_dut");
  assert(ref_difftest_memcpy_from_dut);

Z
Zihao Yu 已提交
56 57 58
  ref_difftest_memcpy_from_ref = (void (*)(void *, paddr_t, size_t))dlsym(handle, "difftest_memcpy_from_ref");
  assert(ref_difftest_memcpy_from_ref);

Z
Zihao Yu 已提交
59 60 61 62 63 64
  ref_difftest_getregs = (void (*)(void *))dlsym(handle, "difftest_getregs");
  assert(ref_difftest_getregs);

  ref_difftest_setregs = (void (*)(const void *))dlsym(handle, "difftest_setregs");
  assert(ref_difftest_setregs);

65
  ref_difftest_get_mastatus = (void (*)(void *))dlsym(handle, "difftest_get_mastatus");
W
William Wang 已提交
66 67
  assert(ref_difftest_get_mastatus);

68
  ref_difftest_set_mastatus = (void (*)(const void *))dlsym(handle, "difftest_set_mastatus");
W
William Wang 已提交
69 70
  assert(ref_difftest_set_mastatus);

71 72 73 74 75 76
  ref_difftest_get_csr = (void (*)(void *))dlsym(handle, "difftest_get_csr");
  assert(ref_difftest_get_csr);

  ref_difftest_set_csr = (void (*)(const void *))dlsym(handle, "difftest_set_csr");
  assert(ref_difftest_set_csr);

77
  ref_disambiguate_exec = (vaddr_t (*)(void *))dlsym(handle, "disambiguate_exec");
W
William Wang 已提交
78
  assert(ref_disambiguate_exec);
79

Z
Zihao Yu 已提交
80 81 82
  ref_difftest_exec = (void (*)(uint64_t))dlsym(handle, "difftest_exec");
  assert(ref_difftest_exec);

Z
Zihao Yu 已提交
83 84 85
  ref_difftest_raise_intr = (void (*)(uint64_t))dlsym(handle, "difftest_raise_intr");
  assert(ref_difftest_raise_intr);

Z
Zihao Yu 已提交
86 87 88 89 90 91 92 93 94
  ref_isa_reg_display = (void (*)(void))dlsym(handle, "isa_reg_display");
  assert(ref_isa_reg_display);

  void (*ref_difftest_init)(void) = (void (*)(void))dlsym(handle, "difftest_init");
  assert(ref_difftest_init);

  ref_difftest_init();
}

95 96 97 98 99
static const char *reg_name[DIFFTEST_NR_REG] = {
  "$0", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
  "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
  "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
  "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6",
100 101 102 103
  "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
  "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
  "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
  "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11",
104 105
  "this_pc",
  "mstatus", "mcause", "mepc",
106 107
  "sstatus", "scause", "sepc",
  "satp", 
108
  "mip", "mie", "mscratch", "sscratch", "mideleg", "medeleg", 
W
William Wang 已提交
109
  "mtval", "stval", "mtvec", "stvec", "mode"
110 111
};

Z
Zihao Yu 已提交
112
static uint64_t nemu_this_pc = 0x80000000;
Z
Zihao Yu 已提交
113 114 115 116 117 118 119 120 121
static uint64_t pc_retire_queue[DEBUG_RETIRE_TRACE_SIZE] = {0};
static uint32_t inst_retire_queue[DEBUG_RETIRE_TRACE_SIZE] = {0};
static uint32_t retire_cnt_queue[DEBUG_RETIRE_TRACE_SIZE] = {0};
static int pc_retire_pointer = DEBUG_RETIRE_TRACE_SIZE-1;
static uint64_t pc_wb_queue[DEBUG_WB_TRACE_SIZE] = {0};
static uint64_t wen_wb_queue[DEBUG_WB_TRACE_SIZE] = {0};
static uint32_t wdst_wb_queue[DEBUG_WB_TRACE_SIZE] = {0};
static uint64_t wdata_wb_queue[DEBUG_WB_TRACE_SIZE] = {0};
static int wb_pointer = 0;
Z
Zihao Yu 已提交
122 123 124 125

uint64_t get_nemu_this_pc() { return nemu_this_pc; }
void set_nemu_this_pc(uint64_t pc) { nemu_this_pc = pc; }

Z
Zihao Yu 已提交
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
void difftest_display(uint8_t mode) {
  printf("\n==============Retire Trace==============\n");
  int j;
  for(j = 0; j < DEBUG_RETIRE_TRACE_SIZE; j++){
    printf("retire trace [%x]: pc %010lx inst %08x cmtcnt %d %s\n",
        j, pc_retire_queue[j], inst_retire_queue[j], retire_cnt_queue[j], (j==pc_retire_pointer)?"<--":"");
  }
  printf("\n==============  WB Trace  ==============\n");
  for(j = 0; j < DEBUG_WB_TRACE_SIZE; j++){
    printf("wb trace [%x]: pc %010lx wen %x dst %08x data %016lx %s\n",
        j, pc_wb_queue[j], wen_wb_queue[j]!=0, wdst_wb_queue[j], wdata_wb_queue[j], (j==((wb_pointer-1)%DEBUG_WB_TRACE_SIZE))?"<--":"");
  }
  printf("\n==============  Reg Diff  ==============\n");
  ref_isa_reg_display();
  printf("priviledgeMode: %d\n", mode);
}
W
William Wang 已提交
142

Z
Zihao Yu 已提交
143
int difftest_step(DiffState *s) {
144
  // assert(!s->isRVC);
W
William Wang 已提交
145

146
  uint64_t ref_r[DIFFTEST_NR_REG];
Z
Zihao Yu 已提交
147
  uint64_t this_pc = s->reg_scala[DIFFTEST_THIS_PC];
148 149
  // ref_difftest_getregs() will get the next pc,
  // therefore we must keep track this one
150 151 152 153 154 155 156 157 158 159 160 161 162 163

  // if (skip) {
  //   // printf("diff pc: %x isRVC %x\n", this_pc, isRVC);
  //   // MMIO accessing should not be a branch or jump, just +2/+4 to get the next pc
  //   reg_scala[DIFFTEST_THIS_PC] += isRVC ? 2 : 4;
  //   nemu_this_pc += isRVC ? 2 : 4;
  //   // to skip the checking of an instruction, just copy the reg state to reference design
  //   ref_difftest_setregs(reg_scala);
  //   pc_retire_pointer = (pc_retire_pointer+1) % DEBUG_RETIRE_TRACE_SIZE;
  //   pc_retire_queue[pc_retire_pointer] = this_pc;
  //   inst_retire_queue[pc_retire_pointer] = this_inst;
  //   retire_cnt_queue[pc_retire_pointer] = commit;
  //   return 0;
  // }
Z
Zihao Yu 已提交
164

165 166
  // sync lr/sc reg status
  if(s->sync.scFailed){
W
William Wang 已提交
167
    struct SyncState sync;
168
    sync.lrscValid = 0;
169
    sync.lrscAddr = 0;
W
William Wang 已提交
170
    ref_difftest_set_mastatus((uint64_t*)&sync); // sync lr/sc microarchitectural regs
171
  }
172 173

  // single step difftest
Z
Zihao Yu 已提交
174 175
  if (s->intrNO) {
    ref_difftest_raise_intr(s->intrNO);
176
    // ref_difftest_exec(1);//TODO
Z
Zihao Yu 已提交
177
  }
178
  else {
Z
Zihao Yu 已提交
179 180 181 182 183 184
    assert(s->commit > 0 && s->commit <= 6);
    for(int i = 0; i < s->commit; i++){
      pc_wb_queue[wb_pointer] = s->wpc[i];
      wen_wb_queue[wb_pointer] = selectBit(s->wen, i);
      wdst_wb_queue[wb_pointer] = s->wdst[i];
      wdata_wb_queue[wb_pointer] = s->wdata[i];
185
      wb_pointer = (wb_pointer+1) % DEBUG_WB_TRACE_SIZE;
Z
Zihao Yu 已提交
186
      if(selectBit(s->skip, i)){
187 188 189 190
        // MMIO accessing should not be a branch or jump, just +2/+4 to get the next pc
        // printf("SKIP %d\n", i);
        // to skip the checking of an instruction, just copy the reg state to reference design
        ref_difftest_getregs(&ref_r);
191
        ref_r[DIFFTEST_THIS_PC] += selectBit(s->isRVC, i) ? 2 : 4;
Z
Zihao Yu 已提交
192
        if(selectBit(s->wen, i)){
193 194 195
          if(s->wdst[i] != 0){
            ref_r[s->wdst[i]] = s->wdata[i];
          }
196 197 198
        }
        ref_difftest_setregs(ref_r);
      }else{
199
        // single step exec
200 201
        // IPF, LPF, SPF
        if(s->cause == 12 || s->cause == 13 || s->cause == 15){
Y
Yinan Xu 已提交
202
          // printf("s->cause %ld\n", s->cause);
203 204 205 206
          struct DisambiguationState ds;
          ds.exceptionNo = s->cause;
          ds.mtval = s->reg_scala[DIFFTEST_MTVAL];
          ds.stval = s->reg_scala[DIFFTEST_STVAL];
207
          ref_disambiguate_exec(&ds);
208 209 210
        }else{
          ref_difftest_exec(1);
        }
211 212 213
      }
    }
  }
Z
Zihao Yu 已提交
214 215
  ref_difftest_getregs(&ref_r);

216
  uint64_t next_pc = ref_r[DIFFTEST_THIS_PC];
W
William Wang 已提交
217 218
  pc_retire_pointer = (pc_retire_pointer+1) % DEBUG_RETIRE_TRACE_SIZE;
  pc_retire_queue[pc_retire_pointer] = this_pc;
Z
Zihao Yu 已提交
219 220
  inst_retire_queue[pc_retire_pointer] = s->this_inst;
  retire_cnt_queue[pc_retire_pointer] = s->commit;
W
William Wang 已提交
221
  
222 223 224 225 226 227 228 229 230 231 232 233
  // TODO: fix mip.mtip
  // int isCSR = ((this_inst & 0x7f) ==  0x73);
  // int isCSRMip = ((this_inst >> 20) == 0x344) && isCSR;
  // if (isCSRMip) {
  //   // We can not handle NEMU.mip.mtip since it is driven by CLINT,
  //   // which is not accessed in NEMU due to MMIO.
  //   // Just sync the state of NEMU from NOOP.
  //   reg_scala[DIFFTEST_THIS_PC] = next_pc;
  //   nemu_this_pc = next_pc;
  //   ref_difftest_setregs(reg_scala);
  //   return 0;
  // }
234

235 236 237
  // replace with "this pc" for checking
  ref_r[DIFFTEST_THIS_PC] = nemu_this_pc;
  nemu_this_pc = next_pc;
Z
Zihao Yu 已提交
238

Z
Zihao Yu 已提交
239 240
  if (memcmp(s->reg_scala, ref_r, sizeof(ref_r)) != 0) {
    difftest_display(s->priviledgeMode);
Z
Zihao Yu 已提交
241
    int i;
242
    for (i = 0; i < DIFFTEST_NR_REG; i ++) {
Z
Zihao Yu 已提交
243
      if (s->reg_scala[i] != ref_r[i]) {
244
        printf("%s different at pc = 0x%010lx, right= 0x%016lx, wrong = 0x%016lx\n",
Z
Zihao Yu 已提交
245
            reg_name[i], this_pc, ref_r[i], s->reg_scala[i]);
Z
Zihao Yu 已提交
246 247 248 249 250 251
      }
    }
    return 1;
  }
  return 0;
}