提交 3476f400 编写于 作者: Z Zihao Yu

emu: move unnecessary out of the Emulator class

上级 68d56209
......@@ -7,13 +7,6 @@
#include <stdint.h>
#include <assert.h>
#ifdef __cplusplus
# include <stdexcept>
# define print_and_die(s) throw std::runtime_error(s)
#else
# define print_and_die(s) do { fprintf(stderr,"%s\n",s); abort(); } while(0)
#endif
#define ANSI_COLOR_RED "\x1b[31m"
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_YELLOW "\x1b[33m"
......@@ -24,25 +17,4 @@
#define eprintf(...) fprintf(stdout, ## __VA_ARGS__)
#define demand(cond,str,...) \
do { if(!(cond)) { \
char __str[256]; \
snprintf(__str,256,"in %s, line %d: " str, \
__FILE__,__LINE__,##__VA_ARGS__); \
print_and_die(__str); \
} } while(0)
// for debugging
int sc(unsigned int ncycle, int *ret_code);
int si(unsigned int ninstr, int *ret_code);
unsigned int read_reg(int reg_no);
// device
void init_device(void);
bool is_finished(void);
int get_exit_code(void);
void app_error(const char *fmt, ...);
int monitor(void);
#endif // __COMMON_H
#include "emu.h"
#include "difftest.h"
void* get_ram_start();
long get_ram_size();
uint64_t get_nemu_this_pc();
void set_nemu_this_pc(uint64_t pc);
Emulator::Emulator(EmuArgs &args):
dut_ptr(new VXSSimTop),
cycles(0), hascommit(0)
{
// srand
srand(args.seed);
srand48(args.seed);
Verilated::randReset(2);
// init ram
extern void init_ram(const char *img);
init_ram(args.image);
// init device
extern void init_device(void);
init_device();
// init core
reset_ncycles(10);
if (args.snapshot_path != NULL) {
init_difftest();
snapshot_load(args.snapshot_path);
hascommit = 1;
}
// set log time range and log level
dut_ptr->io_logCtrl_log_begin = args.log_begin;
dut_ptr->io_logCtrl_log_end = args.log_end;
}
Emulator::~Emulator() {
snapshot_slot[0].save();
snapshot_slot[1].save();
printf("Please remove unused snapshots manually\n");
}
inline void Emulator::read_emu_regs(uint64_t *r) {
#define macro(x) r[x] = dut_ptr->io_difftest_r_##x
macro(0); macro(1); macro(2); macro(3); macro(4); macro(5); macro(6); macro(7);
macro(8); macro(9); macro(10); macro(11); macro(12); macro(13); macro(14); macro(15);
macro(16); macro(17); macro(18); macro(19); macro(20); macro(21); macro(22); macro(23);
macro(24); macro(25); macro(26); macro(27); macro(28); macro(29); macro(30); macro(31);
macro(32); macro(33); macro(34); macro(35); macro(36); macro(37); macro(38); macro(39);
macro(40); macro(41); macro(42); macro(43); macro(44); macro(45); macro(46); macro(47);
macro(48); macro(49); macro(50); macro(51); macro(52); macro(53); macro(54); macro(55);
macro(56); macro(57); macro(58); macro(59); macro(60); macro(61); macro(62); macro(63);
r[DIFFTEST_THIS_PC] = dut_ptr->io_difftest_thisPC;
r[DIFFTEST_MSTATUS] = dut_ptr->io_difftest_mstatus;
r[DIFFTEST_SSTATUS] = dut_ptr->io_difftest_sstatus;
r[DIFFTEST_MEPC ] = dut_ptr->io_difftest_mepc;
r[DIFFTEST_SEPC ] = dut_ptr->io_difftest_sepc;
r[DIFFTEST_MCAUSE ] = dut_ptr->io_difftest_mcause;
r[DIFFTEST_SCAUSE ] = dut_ptr->io_difftest_scause;
}
inline void Emulator::read_wb_info(uint64_t *wpc, uint64_t *wdata, uint32_t *wdst) {
#define dut_ptr_wpc(x) wpc[x] = dut_ptr->io_difftest_wpc_##x
#define dut_ptr_wdata(x) wdata[x] = dut_ptr->io_difftest_wdata_##x
#define dut_ptr_wdst(x) wdst[x] = dut_ptr->io_difftest_wdst_##x
dut_ptr_wpc(0); dut_ptr_wdata(0); dut_ptr_wdst(0);
dut_ptr_wpc(1); dut_ptr_wdata(1); dut_ptr_wdst(1);
dut_ptr_wpc(2); dut_ptr_wdata(2); dut_ptr_wdst(2);
dut_ptr_wpc(3); dut_ptr_wdata(3); dut_ptr_wdst(3);
dut_ptr_wpc(4); dut_ptr_wdata(4); dut_ptr_wdst(4);
dut_ptr_wpc(5); dut_ptr_wdata(5); dut_ptr_wdst(5);
}
inline void Emulator::reset_ncycles(size_t cycles) {
for(int i = 0; i < cycles; i++) {
dut_ptr->reset = 1;
dut_ptr->clock = 0;
dut_ptr->eval();
dut_ptr->clock = 1;
dut_ptr->eval();
dut_ptr->reset = 0;
}
}
inline void Emulator::single_cycle() {
dut_ptr->clock = 0;
dut_ptr->eval();
dut_ptr->clock = 1;
dut_ptr->eval();
#if VM_TRACE
tfp->dump(cycles);
#endif
cycles ++;
}
uint64_t Emulator::execute(uint64_t n) {
extern bool is_finish();
extern void poll_event(void);
extern uint32_t uptime(void);
extern void set_abort(void);
uint32_t lasttime_poll = 0;
uint32_t lasttime_snapshot = 0;
uint64_t lastcommit = n;
const int stuck_limit = 500;
static uint32_t wdst[DIFFTEST_WIDTH];
static uint64_t wdata[DIFFTEST_WIDTH];
static uint64_t wpc[DIFFTEST_WIDTH];
extern int difftest_step(int commit, uint64_t *reg_scala, uint32_t this_inst,
int skip, int isRVC, uint64_t *wpc, uint64_t *wdata, uint32_t *wdst, int wen, uint64_t intrNO, int priviledgeMode);
#if VM_TRACE
Verilated::traceEverOn(true); // Verilator must compute traced signals
VL_PRINTF("Enabling waves...\n");
tfp = new VerilatedVcdC;
dut_ptr->trace(tfp, 99); // Trace 99 levels of hierarchy
tfp->open("vlt_dump.vcd"); // Open the dump file
#endif
while (!is_finish() && n > 0) {
single_cycle();
n --;
if(is_finish()) break;
if (lastcommit - n > stuck_limit && hascommit) {
eprintf("No instruction commits for %d cycles, maybe get stuck\n"
"(please also check whether a fence.i instruction requires more than %d cycles to flush the icache)\n",
stuck_limit, stuck_limit);
#if VM_TRACE
tfp->close();
#endif
// commit a fake inst to trigger error
uint64_t reg[DIFFTEST_NR_REG];
difftest_step(1, reg, 0, 0, 0, wpc, wdata, wdst, 0, 0, 0);
set_abort();
}
if (!hascommit && dut_ptr->io_difftest_commit && dut_ptr->io_difftest_thisPC == 0x80000000u) {
hascommit = 1;
uint64_t reg[DIFFTEST_NR_REG];
read_emu_regs(reg);
init_difftest();
void* get_img_start();
long get_img_size();
ref_difftest_memcpy_from_dut(0x80000000, get_img_start(), get_img_size());
ref_difftest_setregs(reg);
}
// difftest
if (dut_ptr->io_difftest_commit && hascommit) {
uint64_t reg[DIFFTEST_NR_REG];
read_emu_regs(reg);
read_wb_info(wpc, wdata, wdst);
if (difftest_step(dut_ptr->io_difftest_commit, reg, dut_ptr->io_difftest_thisINST,
dut_ptr->io_difftest_skip, dut_ptr->io_difftest_isRVC,
wpc, wdata, wdst, dut_ptr->io_difftest_wen,
dut_ptr->io_difftest_intrNO, dut_ptr->io_difftest_priviledgeMode)) {
#if VM_TRACE
tfp->close();
#endif
set_abort();
}
lastcommit = n;
}
uint32_t t = uptime();
if (t - lasttime_poll > 100) {
poll_event();
lasttime_poll = t;
}
if (t - lasttime_snapshot > 1000 * SNAPSHOT_INTERVAL) {
// save snapshot every 10s
time_t now = time(NULL);
snapshot_save(snapshot_filename(now));
lasttime_snapshot = t;
}
}
return cycles;
}
inline char* Emulator::snapshot_filename(time_t t) {
static char buf[1024];
char buf_time[64];
strftime(buf_time, sizeof(buf_time), "%F@%T", localtime(&t));
char *noop_home = getenv("NOOP_HOME");
assert(noop_home != NULL);
snprintf(buf, 1024, "%s/build/%s.snapshot", noop_home, buf_time);
return buf;
}
void Emulator::snapshot_save(const char *filename) {
static int last_slot = 0;
VerilatedSaveMem &stream = snapshot_slot[last_slot];
last_slot = !last_slot;
stream.init(filename);
stream << *dut_ptr;
stream.flush();
long size = get_ram_size();
stream.unbuf_write(&size, sizeof(size));
stream.unbuf_write(get_ram_start(), size);
uint64_t ref_r[DIFFTEST_NR_REG];
ref_difftest_getregs(&ref_r);
stream.unbuf_write(ref_r, sizeof(ref_r));
uint64_t nemu_this_pc = get_nemu_this_pc();
stream.unbuf_write(&nemu_this_pc, sizeof(nemu_this_pc));
char *buf = new char[size];
ref_difftest_memcpy_from_ref(buf, 0x80000000, size);
stream.unbuf_write(buf, size);
delete buf;
// actually write to file in snapshot_finalize()
}
void Emulator::snapshot_load(const char *filename) {
VerilatedRestore stream;
stream.open(filename);
stream >> *dut_ptr;
long size;
stream.read(&size, sizeof(size));
assert(size == get_ram_size());
stream.read(get_ram_start(), size);
uint64_t ref_r[DIFFTEST_NR_REG];
stream.read(ref_r, sizeof(ref_r));
ref_difftest_setregs(&ref_r);
uint64_t nemu_this_pc;
stream.read(&nemu_this_pc, sizeof(nemu_this_pc));
set_nemu_this_pc(nemu_this_pc);
char *buf = new char[size];
stream.read(buf, size);
ref_difftest_memcpy_from_dut(0x80000000, buf, size);
delete buf;
}
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <memory>
#include <time.h>
#include "difftest.h"
//#include "VSimTop__Dpi.h"
#include "common.h"
#include "snapshot.h"
#include "VXSSimTop.h"
#if VM_TRACE
#include <verilated_vcd_c.h> // Trace file format header
#endif
......@@ -18,243 +9,45 @@
#define DIFFTEST_WIDTH 6
#define SNAPSHOT_INTERVAL 10 // unit: second
static char mybuf[BUFSIZ];
class Emulator {
const char *image;
const char *mainargs;
std::shared_ptr<VXSSimTop> dut_ptr;
#if VM_TRACE
VerilatedVcdC* tfp;
#endif
// emu control variable
struct EmuArgs {
uint32_t seed;
uint64_t max_cycles, cycles;
uint64_t max_cycles;
uint64_t log_begin, log_end;
const char *image;
const char *snapshot_path;
int hascommit;
std::vector<const char *> parse_args(int argc, const char *argv[]);
static void print_help(const char *file);
void read_emu_regs(uint64_t *r) {
#define macro(x) r[x] = dut_ptr->io_difftest_r_##x
macro(0); macro(1); macro(2); macro(3); macro(4); macro(5); macro(6); macro(7);
macro(8); macro(9); macro(10); macro(11); macro(12); macro(13); macro(14); macro(15);
macro(16); macro(17); macro(18); macro(19); macro(20); macro(21); macro(22); macro(23);
macro(24); macro(25); macro(26); macro(27); macro(28); macro(29); macro(30); macro(31);
macro(32); macro(33); macro(34); macro(35); macro(36); macro(37); macro(38); macro(39);
macro(40); macro(41); macro(42); macro(43); macro(44); macro(45); macro(46); macro(47);
macro(48); macro(49); macro(50); macro(51); macro(52); macro(53); macro(54); macro(55);
macro(56); macro(57); macro(58); macro(59); macro(60); macro(61); macro(62); macro(63);
r[DIFFTEST_THIS_PC] = dut_ptr->io_difftest_thisPC;
r[DIFFTEST_MSTATUS] = dut_ptr->io_difftest_mstatus;
r[DIFFTEST_SSTATUS] = dut_ptr->io_difftest_sstatus;
r[DIFFTEST_MEPC ] = dut_ptr->io_difftest_mepc;
r[DIFFTEST_SEPC ] = dut_ptr->io_difftest_sepc;
r[DIFFTEST_MCAUSE ] = dut_ptr->io_difftest_mcause;
r[DIFFTEST_SCAUSE ] = dut_ptr->io_difftest_scause;
}
void read_wb_info(uint64_t *wpc, uint64_t *wdata, uint32_t *wdst) {
#define dut_ptr_wpc(x) wpc[x] = dut_ptr->io_difftest_wpc_##x
#define dut_ptr_wdata(x) wdata[x] = dut_ptr->io_difftest_wdata_##x
#define dut_ptr_wdst(x) wdst[x] = dut_ptr->io_difftest_wdst_##x
dut_ptr_wpc(0); dut_ptr_wdata(0); dut_ptr_wdst(0);
dut_ptr_wpc(1); dut_ptr_wdata(1); dut_ptr_wdst(1);
dut_ptr_wpc(2); dut_ptr_wdata(2); dut_ptr_wdst(2);
dut_ptr_wpc(3); dut_ptr_wdata(3); dut_ptr_wdst(3);
dut_ptr_wpc(4); dut_ptr_wdata(4); dut_ptr_wdst(4);
dut_ptr_wpc(5); dut_ptr_wdata(5); dut_ptr_wdst(5);
return;
EmuArgs() {
seed = 0;
max_cycles = -1;
log_begin = 1;
log_end = -1;
snapshot_path = NULL;
image = NULL;
}
};
public:
// argv decay to the secondary pointer
Emulator(int argc, const char *argv[]):
image(nullptr),
dut_ptr(new std::remove_reference<decltype(*dut_ptr)>::type),
seed(0), max_cycles(-1), cycles(0),
log_begin(0), log_end(-1),
snapshot_path(NULL), hascommit(0)
{
// init emu
auto args = parse_args(argc, argv);
setbuf(stderr, mybuf);
// srand
srand(seed);
srand48(seed);
Verilated::randReset(2);
// init ram
extern void init_ram(const char *img);
init_ram(image);
// init device
extern void init_device(void);
init_device();
// init core
reset_ncycles(10);
}
~Emulator() {
snapshot_finalize();
}
void reset_ncycles(size_t cycles) {
for(int i = 0; i < cycles; i++) {
dut_ptr->reset = 1;
dut_ptr->clock = 0;
dut_ptr->eval();
dut_ptr->clock = 1;
dut_ptr->eval();
dut_ptr->reset = 0;
}
}
void single_cycle() {
dut_ptr->clock = 0;
dut_ptr->eval();
dut_ptr->clock = 1;
dut_ptr->eval();
#if VM_TRACE
tfp->dump(cycles);
#endif
cycles ++;
}
void execute_cycles(uint64_t n) {
extern bool is_finish();
extern void poll_event(void);
extern uint32_t uptime(void);
extern void set_abort(void);
uint32_t lasttime_poll = 0;
uint32_t lasttime_snapshot = 0;
uint64_t lastcommit = n;
const int stuck_limit = 500;
static uint32_t wdst[DIFFTEST_WIDTH];
static uint64_t wdata[DIFFTEST_WIDTH];
static uint64_t wpc[DIFFTEST_WIDTH];
extern int difftest_step(int commit, uint64_t *reg_scala, uint32_t this_inst,
int skip, int isRVC, uint64_t *wpc, uint64_t *wdata, uint32_t *wdst, int wen, uint64_t intrNO, int priviledgeMode);
#if VM_TRACE
Verilated::traceEverOn(true); // Verilator must compute traced signals
VL_PRINTF("Enabling waves...\n");
tfp = new VerilatedVcdC;
dut_ptr->trace(tfp, 99); // Trace 99 levels of hierarchy
tfp->open("vlt_dump.vcd"); // Open the dump file
#endif
while (!is_finish() && n > 0) {
single_cycle();
n --;
if(is_finish()) return;
if (lastcommit - n > stuck_limit && hascommit) {
eprintf("No instruction commits for %d cycles, maybe get stuck\n"
"(please also check whether a fence.i instruction requires more than %d cycles to flush the icache)\n",
stuck_limit, stuck_limit);
#if VM_TRACE
tfp->close();
#endif
// commit a fake inst to trigger error
uint64_t reg[DIFFTEST_NR_REG];
difftest_step(1, reg, 0, 0, 0, wpc, wdata, wdst, 0, 0, 0);
set_abort();
}
//printf("xsstatus pc=%lx commit=%d\n", dut_ptr->io_difftest_thisPC, dut_ptr->io_difftest_commit);//FIXIT: delete me when dummy test is passed
if (!hascommit && dut_ptr->io_difftest_commit && dut_ptr->io_difftest_thisPC == 0x80000000u) {
hascommit = 1;
uint64_t reg[DIFFTEST_NR_REG];
read_emu_regs(reg);
init_difftest();
void* get_img_start();
long get_img_size();
ref_difftest_memcpy_from_dut(0x80000000, get_img_start(), get_img_size());
ref_difftest_setregs(reg);
}
// difftest
if (dut_ptr->io_difftest_commit && hascommit) {
uint64_t reg[DIFFTEST_NR_REG];
read_emu_regs(reg);
read_wb_info(wpc, wdata, wdst);
if (difftest_step(dut_ptr->io_difftest_commit, reg, dut_ptr->io_difftest_thisINST,
dut_ptr->io_difftest_skip, dut_ptr->io_difftest_isRVC,
wpc, wdata, wdst, dut_ptr->io_difftest_wen,
dut_ptr->io_difftest_intrNO, dut_ptr->io_difftest_priviledgeMode)) {
class Emulator {
VXSSimTop *dut_ptr;
#if VM_TRACE
tfp->close();
VerilatedVcdC* tfp;
#endif
set_abort();
}
lastcommit = n;
}
uint32_t t = uptime();
if (t - lasttime_poll > 100) {
poll_event();
lasttime_poll = t;
}
if (t - lasttime_snapshot > 1000 * SNAPSHOT_INTERVAL) {
// save snapshot every 10s
time_t now = time(NULL);
snapshot_save(snapshot_filename(my_strftime(now)));
lasttime_snapshot = t;
}
}
}
void cache_test(uint64_t n) {
while (n > 0) {
single_cycle();
n --;
}
}
void execute() {
//#define CACHE_TEST
#ifdef CACHE_TEST
eprintf(ANSI_COLOR_MAGENTA "This is random test for cache.\n" ANSI_COLOR_RESET);
cache_test(max_cycles);
#else
if (snapshot_path != NULL) {
init_difftest();
snapshot_load(snapshot_path);
hascommit = 1;
}
VerilatedSaveMem snapshot_slot[2];
// set log time range and log level
dut_ptr->io_logCtrl_log_begin = log_begin;
dut_ptr->io_logCtrl_log_end = log_end;
execute_cycles(max_cycles);
#endif
}
uint64_t get_cycles() const { return cycles; }
uint64_t get_max_cycles() const { return max_cycles; }
uint32_t get_seed() const { return seed; }
// emu control variable
uint64_t cycles;
int hascommit;
char* my_strftime(time_t time);
char* snapshot_filename(const char *name);
inline void read_emu_regs(uint64_t *r);
inline void read_wb_info(uint64_t *wpc, uint64_t *wdata, uint32_t *wdst);
inline void reset_ncycles(size_t cycles);
inline void single_cycle();
inline char* snapshot_filename(time_t t);
void snapshot_save(const char *filename);
void snapshot_load(const char *filename);
void snapshot_finalize();
public:
Emulator(EmuArgs &args);
~Emulator();
uint64_t execute(uint64_t n);
uint64_t get_cycles() const { return cycles; }
};
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include "emu.h"
#include <getopt.h>
#include <string.h>
#include <sys/time.h>
#include <iomanip>
#include <fstream>
#include <functional>
#include <inttypes.h>
#include "emu.h"
static char mybuf[BUFSIZ];
// junk, link for verilator
std::function<double()> get_sc_time_stamp = []() -> double { return 0; };
double sc_time_stamp() { return get_sc_time_stamp(); }
void Emulator::print_help(const char *file) {
static inline void print_help(const char *file) {
printf("Usage: %s [OPTION...]\n", file);
printf("\n");
printf(" -s, --seed=NUM use this seed\n");
......@@ -27,8 +20,8 @@ void Emulator::print_help(const char *file) {
printf("\n");
}
std::vector<const char *> Emulator::parse_args(int argc, const char *argv[]) {
std::vector<const char *> args = { argv[0] };
static inline EmuArgs parse_args(int argc, const char *argv[]) {
EmuArgs args;
int long_index = 0;
const struct option long_options[] = {
{ "load-snapshot", 1, NULL, 0 },
......@@ -47,7 +40,7 @@ std::vector<const char *> Emulator::parse_args(int argc, const char *argv[]) {
switch (o) {
case 0:
if (long_index == 0) {
snapshot_path = optarg;
args.snapshot_path = optarg;
break;
}
// fall through
......@@ -56,40 +49,42 @@ std::vector<const char *> Emulator::parse_args(int argc, const char *argv[]) {
exit(0);
case 's':
if(std::string(optarg) != "NO_SEED") {
seed = atoll(optarg);
printf("Using seed = %d\n", seed);
args.seed = atoll(optarg);
printf("Using seed = %d\n", args.seed);
}
break;
case 'C': max_cycles = atoll(optarg); break;
case 'i': image = optarg;
args.push_back("-i");
args.push_back(optarg);
break;
case 'b': log_begin = atoll(optarg); break;
case 'e': log_end = atoll(optarg); break;
case 'C': args.max_cycles = atoll(optarg); break;
case 'i': args.image = optarg; break;
case 'b': args.log_begin = atoll(optarg); break;
case 'e': args.log_end = atoll(optarg); break;
}
}
return args; // optimized by rvo
return args;
}
int main(int argc, const char** argv) {
auto emu = Emulator(argc, argv);
setbuf(stderr, mybuf);
auto args = parse_args(argc, argv);
auto emu = new Emulator(args);
get_sc_time_stamp = [&emu]() -> double {
return emu.get_cycles();
return emu->get_cycles();
};
emu.execute();
uint64_t cycles = emu->execute(args.max_cycles);
delete emu;
extern uint32_t uptime(void);
uint32_t ms = uptime();
int display_trapinfo(uint64_t max_cycles);
int ret = display_trapinfo(emu.get_max_cycles());
int ret = display_trapinfo(args.max_cycles);
eprintf(ANSI_COLOR_BLUE "Seed=%d Guest cycle spent: %" PRIu64
" (this will be different from cycleCnt if emu loads a snapshot)\n" ANSI_COLOR_RESET, emu.get_seed(), emu.get_cycles());
" (this will be different from cycleCnt if emu loads a snapshot)\n" ANSI_COLOR_RESET, args.seed, cycles);
eprintf(ANSI_COLOR_BLUE "Host time spent: %dms\n" ANSI_COLOR_RESET, ms);
return ret;
}
#include "emu.h"
#include <verilated_save.h>
#include "difftest.h"
class VerilatedSaveMem : public VerilatedSave {
const static long buf_size = 1024 * 1024 * 1024;
uint8_t *buf;
long size;
public:
VerilatedSaveMem() {
buf = new uint8_t[buf_size];
size = 0;
}
~VerilatedSaveMem() { delete buf; }
void init(const char *filename) {
size = 0;
m_filename = filename;
header();
}
void mywrite(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
memcpy(buf + this->size, datap, size);
this->size += size;
}
void close() { }
void flush() {
long flush_size = m_cp - m_bufp;
assert(buf_size - size > flush_size);
memcpy(buf + size, m_bufp, flush_size);
size += flush_size;
m_cp = m_bufp;
}
void clear() { size = 0; }
void save() {
if (size == 0) return;
trailer();
flush();
FILE *fp = fopen(m_filename.c_str(), "w");
assert(fp != NULL);
fwrite(buf, size, 1, fp);
fclose(fp);
size = 0;
printf("save snapshot to %s...\n", m_filename.c_str());
}
};
static VerilatedSaveMem snapshot_slot[2];
void* get_ram_start();
long get_ram_size();
uint64_t get_nemu_this_pc();
void set_nemu_this_pc(uint64_t pc);
extern void (*ref_difftest_memcpy_from_dut)(paddr_t dest, void *src, size_t n);
extern void (*ref_difftest_memcpy_from_ref)(void *dest, paddr_t src, size_t n);
char* Emulator::my_strftime(time_t time) {
static char buf[64];
strftime(buf, sizeof(buf), "%F@%T", localtime(&time));
return buf;
}
char* Emulator::snapshot_filename(const char *name) {
static char buf[1024];
char *noop_home = getenv("NOOP_HOME");
assert(noop_home != NULL);
snprintf(buf, 1024, "%s/build/%s.snapshot", noop_home, name);
return buf;
}
void Emulator::snapshot_save(const char *filename) {
static int last_slot = 0;
VerilatedSaveMem &stream = snapshot_slot[last_slot];
last_slot = !last_slot;
stream.init(filename);
stream << *dut_ptr;
stream.flush();
long size = get_ram_size();
stream.mywrite(&size, sizeof(size));
stream.mywrite(get_ram_start(), size);
uint64_t ref_r[DIFFTEST_NR_REG];
ref_difftest_getregs(&ref_r);
stream.mywrite(ref_r, sizeof(ref_r));
uint64_t nemu_this_pc = get_nemu_this_pc();
stream.mywrite(&nemu_this_pc, sizeof(nemu_this_pc));
char *buf = new char[size];
ref_difftest_memcpy_from_ref(buf, 0x80000000, size);
stream.mywrite(buf, size);
delete buf;
// actually write to file in snapshot_finalize()
}
void Emulator::snapshot_load(const char *filename) {
VerilatedRestore stream;
stream.open(filename);
stream >> *dut_ptr;
long size;
stream.read(&size, sizeof(size));
assert(size == get_ram_size());
stream.read(get_ram_start(), size);
uint64_t ref_r[DIFFTEST_NR_REG];
stream.read(ref_r, sizeof(ref_r));
ref_difftest_setregs(&ref_r);
uint64_t nemu_this_pc;
stream.read(&nemu_this_pc, sizeof(nemu_this_pc));
set_nemu_this_pc(nemu_this_pc);
char *buf = new char[size];
stream.read(buf, size);
ref_difftest_memcpy_from_dut(0x80000000, buf, size);
delete buf;
#include "snapshot.h"
void VerilatedSaveMem::flush() {
long flush_size = m_cp - m_bufp;
assert(buf_size - size > flush_size);
memcpy(buf + size, m_bufp, flush_size);
size += flush_size;
m_cp = m_bufp;
}
void Emulator::snapshot_finalize() {
snapshot_slot[0].save();
snapshot_slot[1].save();
printf("Please remove unused snapshots manually\n");
void VerilatedSaveMem::save() {
if (size == 0) return;
trailer();
flush();
FILE *fp = fopen(m_filename.c_str(), "w");
assert(fp != NULL);
fwrite(buf, size, 1, fp);
fclose(fp);
size = 0;
printf("save snapshot to %s...\n", m_filename.c_str());
}
#include "VXSSimTop.h"
#include <verilated_save.h>
class VerilatedSaveMem : public VerilatedSave {
const static long buf_size = 1024 * 1024 * 1024;
uint8_t *buf;
long size;
public:
VerilatedSaveMem() {
buf = new uint8_t[buf_size];
size = 0;
}
~VerilatedSaveMem() { delete buf; }
void init(const char *filename) {
size = 0;
m_filename = filename;
header();
}
void unbuf_write(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
memcpy(buf + this->size, datap, size);
this->size += size;
}
void close() { }
void flush();
void save();
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册