1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
// See LICENSE for license details.
#ifndef _RISCV_SIM_H
#define _RISCV_SIM_H
#include "debug_module.h"
#include "devices.h"
#include "log_file.h"
#include "processor.h"
#include "simif.h"
#include <fesvr/htif.h>
#include <fesvr/context.h>
#include <vector>
#include <string>
#include <memory>
#include <sys/types.h>
class mmu_t;
class remote_bitbang_t;
// this class encapsulates the processors and memory in a RISC-V machine.
class sim_t : public htif_t, public simif_t
{
public:
sim_t(const char* isa, const char* priv, const char* varch, size_t _nprocs,
bool halted, bool real_time_clint,
reg_t initrd_start, reg_t initrd_end,
reg_t start_pc, std::vector<std::pair<reg_t, mem_t*>> mems,
std::vector<std::pair<reg_t, abstract_device_t*>> plugin_devices,
const std::vector<std::string>& args, const std::vector<int> hartids,
const debug_module_config_t &dm_config, const char *log_path,
bool dtb_enabled, const char *dtb_file);
~sim_t();
// run the simulation to completion
int run();
void set_debug(bool value);
void set_histogram(bool value);
// Configure logging
//
// If enable_log is true, an instruction trace will be generated. If
// enable_commitlog is true, so will the commit results (if this
// build was configured without support for commit logging, the
// function will print an error message and abort).
void configure_log(bool enable_log, bool enable_commitlog);
void set_procs_debug(bool value);
void set_remote_bitbang(remote_bitbang_t* remote_bitbang) {
this->remote_bitbang = remote_bitbang;
}
const char* get_dts() { if (dts.empty()) reset(); return dts.c_str(); }
processor_t* get_core(size_t i) { return procs.at(i); }
unsigned nprocs() const { return procs.size(); }
// Callback for processors to let the simulation know they were reset.
void proc_reset(unsigned id);
private:
std::vector<std::pair<reg_t, mem_t*>> mems;
std::vector<std::pair<reg_t, abstract_device_t*>> plugin_devices;
mmu_t* debug_mmu; // debug port into main memory
std::vector<processor_t*> procs;
reg_t initrd_start;
reg_t initrd_end;
reg_t start_pc;
std::string dts;
std::string dtb;
std::string dtb_file;
bool dtb_enabled;
std::unique_ptr<rom_device_t> boot_rom;
std::unique_ptr<clint_t> clint;
bus_t bus;
log_file_t log_file;
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 histogram_enabled; // provide a histogram of PCs
bool log;
remote_bitbang_t* remote_bitbang;
// memory-mapped I/O routines
char* addr_to_mem(reg_t addr);
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_dtb();
void set_rom();
// presents a prompt for introspection into the simulation
void interactive();
// functions that help implement interactive()
void interactive_help(const std::string& cmd, const std::vector<std::string>& args);
void interactive_quit(const std::string& cmd, const std::vector<std::string>& args);
void interactive_run(const std::string& cmd, const std::vector<std::string>& args, bool noisy);
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_vreg(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_fregh(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_mem(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, bool noisy);
void interactive_until_silent(const std::string& cmd, const std::vector<std::string>& args);
void interactive_until_noisy(const std::string& cmd, const std::vector<std::string>& args);
reg_t get_reg(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 debug_module_t;
// htif
friend void sim_thread_main(void*);
void main();
context_t* host;
context_t target;
void reset();
void idle();
void read_chunk(addr_t taddr, size_t len, void* dst);
void write_chunk(addr_t taddr, size_t len, const void* src);
size_t chunk_align() { return 8; }
size_t chunk_max_size() { return 8; }
public:
// Initialize this after procs, because in debug_module_t::reset() we
// enumerate processors, which segfaults if procs hasn't been initialized
// yet.
debug_module_t debug_module;
};
extern volatile bool ctrlc_pressed;
#endif
|