Restructured DBT function to encapsulate the compilation process
This should enable the implementation of multi-threading of the compilation process
This commit is contained in:
parent
b4871ac725
commit
873e4257f2
1
.project
1
.project
|
@ -7,6 +7,7 @@
|
||||||
<buildSpec>
|
<buildSpec>
|
||||||
<buildCommand>
|
<buildCommand>
|
||||||
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||||
|
<triggers>clean,full,incremental,</triggers>
|
||||||
<arguments>
|
<arguments>
|
||||||
</arguments>
|
</arguments>
|
||||||
</buildCommand>
|
</buildCommand>
|
||||||
|
|
|
@ -4,7 +4,7 @@ Am instruction set simulator based on DBT-RISE implementing the RISC-V ISA
|
||||||
**DBT-RISE-RISCV README**
|
**DBT-RISE-RISCV README**
|
||||||
|
|
||||||
This is work in progress, so use at your own risk. Goal is to implement an open-source ISS which can easily embedded e.g. into SystemC Virtual Prototypes. It used code generation to allow easy extension and adaptation of the used instruction.
|
This is work in progress, so use at your own risk. Goal is to implement an open-source ISS which can easily embedded e.g. into SystemC Virtual Prototypes. It used code generation to allow easy extension and adaptation of the used instruction.
|
||||||
The RISC-V ISS reaches about 20MIPS at an Intel Core i7-2600K.
|
The RISC-V ISS reaches about 30MIPS running on Intel Core i7-2600K.
|
||||||
|
|
||||||
The implementation is based on LLVM 4.0. Eclipse CDT 4.7 (Oxygen) is recommended as IDE.
|
The implementation is based on LLVM 4.0. Eclipse CDT 4.7 (Oxygen) is recommended as IDE.
|
||||||
|
|
||||||
|
|
2
dbt-core
2
dbt-core
|
@ -1 +1 @@
|
||||||
Subproject commit cf9679475121f85a6333970f80bb6a40a8b4a0a5
|
Subproject commit 4bfcd8a10e81d610d46b329841ae3ba7cbc0627a
|
|
@ -94,7 +94,9 @@ public:
|
||||||
|
|
||||||
base_type::hart_state<base_type::reg_t>& get_state() { return this->state; }
|
base_type::hart_state<base_type::reg_t>& get_state() { return this->state; }
|
||||||
|
|
||||||
void notify_phase(iss::arch_if::exec_phase phase);
|
void notify_phase(exec_phase) override;
|
||||||
|
|
||||||
|
iss::sync_type needed_sync() const override { return iss::PRE_SYNC; }
|
||||||
|
|
||||||
void disass_output(uint64_t pc, const std::string instr) override {
|
void disass_output(uint64_t pc, const std::string instr) override {
|
||||||
if (logging::INFO <= logging::Log<logging::Output2FILE<logging::disass>>::reporting_level() && logging::Output2FILE<logging::disass>::stream()){
|
if (logging::INFO <= logging::Log<logging::Output2FILE<logging::disass>>::reporting_level() && logging::Output2FILE<logging::disass>::stream()){
|
||||||
|
@ -108,15 +110,15 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data) {
|
iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data) {
|
||||||
if (addr.type & iss::DEBUG)
|
if (addr.access && iss::access_type::DEBUG)
|
||||||
return owner->read_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err;
|
return owner->read_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err;
|
||||||
else {
|
else {
|
||||||
return owner->read_mem(addr.val, length, data,addr.type && iss::FETCH) ? iss::Ok : iss::Err;
|
return owner->read_mem(addr.val, length, data,addr.access && iss::access_type::FETCH) ? iss::Ok : iss::Err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data) {
|
iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data) {
|
||||||
if (addr.type & iss::DEBUG)
|
if (addr.access && iss::access_type::DEBUG)
|
||||||
return owner->write_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err;
|
return owner->write_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err;
|
||||||
else{
|
else{
|
||||||
auto res = owner->write_mem(addr.val, length, data) ? iss::Ok : iss::Err;
|
auto res = owner->write_mem(addr.val, length, data) ? iss::Ok : iss::Err;
|
||||||
|
@ -187,9 +189,9 @@ int cmd_sysc(int argc, char* argv[], iss::debugger::out_func of, iss::debugger::
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void core_wrapper::notify_phase(exec_phase phase) {
|
void core_wrapper::notify_phase(exec_phase p) {
|
||||||
core_type::notify_phase(phase);
|
if(p == ISTART)
|
||||||
if (phase == ISTART) owner->sync();
|
owner->sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
core_complex::core_complex(sc_core::sc_module_name name)
|
core_complex::core_complex(sc_core::sc_module_name name)
|
||||||
|
|
|
@ -222,6 +222,7 @@ struct vm_info {
|
||||||
int idxbits;
|
int idxbits;
|
||||||
int ptesize;
|
int ptesize;
|
||||||
uint64_t ptbase;
|
uint64_t ptbase;
|
||||||
|
bool is_active() { return levels;}
|
||||||
};
|
};
|
||||||
|
|
||||||
class trap_load_access_fault : public trap_access {
|
class trap_load_access_fault : public trap_access {
|
||||||
|
@ -450,7 +451,7 @@ public:
|
||||||
|
|
||||||
void load_file(std::string name, int type = -1) override;
|
void load_file(std::string name, int type = -1) override;
|
||||||
|
|
||||||
virtual phys_addr_t v2p(const iss::addr_t &addr);
|
virtual phys_addr_t virt2phys(const iss::addr_t &addr) override;
|
||||||
|
|
||||||
iss::status read(const iss::addr_t &addr, unsigned length, uint8_t *const data) override;
|
iss::status read(const iss::addr_t &addr, unsigned length, uint8_t *const data) override;
|
||||||
iss::status write(const iss::addr_t &addr, unsigned length, const uint8_t *const data) override;
|
iss::status write(const iss::addr_t &addr, unsigned length, const uint8_t *const data) override;
|
||||||
|
@ -460,8 +461,6 @@ public:
|
||||||
virtual uint64_t leave_trap(uint64_t flags) override;
|
virtual uint64_t leave_trap(uint64_t flags) override;
|
||||||
void wait_until(uint64_t flags) override;
|
void wait_until(uint64_t flags) override;
|
||||||
|
|
||||||
void notify_phase(iss::arch_if::exec_phase phase);
|
|
||||||
|
|
||||||
void disass_output(uint64_t pc, const std::string instr) override {
|
void disass_output(uint64_t pc, const std::string instr) override {
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
s << "[p:" << lvl[this->reg.machine_state] << ";s:0x" << std::hex << std::setfill('0')
|
s << "[p:" << lvl[this->reg.machine_state] << ";s:0x" << std::hex << std::setfill('0')
|
||||||
|
@ -486,6 +485,8 @@ protected:
|
||||||
mem_type mem;
|
mem_type mem;
|
||||||
csr_type csr;
|
csr_type csr;
|
||||||
hart_state<reg_t> state;
|
hart_state<reg_t> state;
|
||||||
|
vm_info vm[2];
|
||||||
|
void update_vm_info();
|
||||||
unsigned to_host_wr_cnt = 0;
|
unsigned to_host_wr_cnt = 0;
|
||||||
std::stringstream uart_buf;
|
std::stringstream uart_buf;
|
||||||
std::unordered_map<reg_t, uint64_t> ptw;
|
std::unordered_map<reg_t, uint64_t> ptw;
|
||||||
|
@ -571,7 +572,7 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::load_file(std::string nam
|
||||||
const auto seg_data = pseg->get_data();
|
const auto seg_data = pseg->get_data();
|
||||||
if (fsize > 0) {
|
if (fsize > 0) {
|
||||||
auto res = this->write(
|
auto res = this->write(
|
||||||
typed_addr_t<PHYSICAL>(iss::DEBUG_WRITE, traits<BASE>::MEM, pseg->get_physical_address()),
|
phys_addr_t(iss::access_type::DEBUG_WRITE, traits<BASE>::MEM, pseg->get_physical_address()),
|
||||||
fsize, reinterpret_cast<const uint8_t *const>(seg_data));
|
fsize, reinterpret_cast<const uint8_t *const>(seg_data));
|
||||||
if (res != iss::Ok)
|
if (res != iss::Ok)
|
||||||
LOG(ERROR) << "problem writing " << fsize << "bytes to 0x" << std::hex
|
LOG(ERROR) << "problem writing " << fsize << "bytes to 0x" << std::hex
|
||||||
|
@ -586,13 +587,15 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::load_file(std::string nam
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
throw std::runtime_error("memory load file is not a valid elf file");
|
||||||
}
|
}
|
||||||
|
throw std::runtime_error("memory load file not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE>
|
template <typename BASE>
|
||||||
iss::status riscv_hart_msu_vp<BASE>::read(const iss::addr_t &addr, unsigned length, uint8_t *const data) {
|
iss::status riscv_hart_msu_vp<BASE>::read(const iss::addr_t &addr, unsigned length, uint8_t *const data) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (addr.type & iss::DEBUG) {
|
if (addr.access && iss::access_type::DEBUG) {
|
||||||
LOG(DEBUG) << "debug read of " << length << " bytes @addr " << addr;
|
LOG(DEBUG) << "debug read of " << length << " bytes @addr " << addr;
|
||||||
} else {
|
} else {
|
||||||
LOG(DEBUG) << "read of " << length << " bytes @addr " << addr;
|
LOG(DEBUG) << "read of " << length << " bytes @addr " << addr;
|
||||||
|
@ -601,9 +604,9 @@ iss::status riscv_hart_msu_vp<BASE>::read(const iss::addr_t &addr, unsigned leng
|
||||||
try {
|
try {
|
||||||
switch (addr.space) {
|
switch (addr.space) {
|
||||||
case traits<BASE>::MEM: {
|
case traits<BASE>::MEM: {
|
||||||
if ((addr.type & (iss::ACCESS_TYPE - iss::DEBUG)) == iss::FETCH && (addr.val & 0x1) == 1) {
|
if ((addr.access == iss::access_type::FETCH || addr.access == iss::access_type::DEBUG_FETCH) && (addr.val & 0x1) == 1) {
|
||||||
fault_data = addr.val;
|
fault_data = addr.val;
|
||||||
if ((addr.type & iss::DEBUG)) throw trap_access(0, addr.val);
|
if (addr.access && iss::access_type::DEBUG) throw trap_access(0, addr.val);
|
||||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
this->reg.trap_state = (1 << 31); // issue trap 0
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
|
@ -615,12 +618,11 @@ iss::status riscv_hart_msu_vp<BASE>::read(const iss::addr_t &addr, unsigned leng
|
||||||
auto len1 = split_addr - addr.val;
|
auto len1 = split_addr - addr.val;
|
||||||
auto res = read(addr, len1, data);
|
auto res = read(addr, len1, data);
|
||||||
if (res == iss::Ok)
|
if (res == iss::Ok)
|
||||||
res = read(iss::addr_t{addr.type, addr.space, split_addr}, length - len1, data + len1);
|
res = read(iss::addr_t{addr.access, addr.type, addr.space, split_addr}, length - len1, data + len1);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
phys_addr_t paddr = (addr.type & iss::ADDRESS_TYPE) == iss::PHYSICAL ? addr : v2p(addr);
|
auto res = read_mem( BASE::v2p(addr), length, data);
|
||||||
auto res = read_mem(paddr, length, data);
|
|
||||||
if (res != iss::Ok) this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
if (res != iss::Ok) this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||||
return res;
|
return res;
|
||||||
} catch (trap_access &ta) {
|
} catch (trap_access &ta) {
|
||||||
|
@ -668,7 +670,7 @@ iss::status riscv_hart_msu_vp<BASE>::read(const iss::addr_t &addr, unsigned leng
|
||||||
template <typename BASE>
|
template <typename BASE>
|
||||||
iss::status riscv_hart_msu_vp<BASE>::write(const iss::addr_t &addr, unsigned length, const uint8_t *const data) {
|
iss::status riscv_hart_msu_vp<BASE>::write(const iss::addr_t &addr, unsigned length, const uint8_t *const data) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
const char *prefix = addr.type & iss::DEBUG ? "debug " : "";
|
const char *prefix = (addr.access && iss::access_type::DEBUG)? "debug " : "";
|
||||||
switch (length) {
|
switch (length) {
|
||||||
case 8:
|
case 8:
|
||||||
LOG(DEBUG) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t *)&data[0] << std::dec
|
LOG(DEBUG) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t *)&data[0] << std::dec
|
||||||
|
@ -693,9 +695,9 @@ iss::status riscv_hart_msu_vp<BASE>::write(const iss::addr_t &addr, unsigned len
|
||||||
try {
|
try {
|
||||||
switch (addr.space) {
|
switch (addr.space) {
|
||||||
case traits<BASE>::MEM: {
|
case traits<BASE>::MEM: {
|
||||||
if ((addr.type & (iss::ACCESS_TYPE - iss::DEBUG)) == iss::FETCH && (addr.val & 0x1) == 1) {
|
if ((addr.access && iss::access_type::FETCH) && (addr.val & 0x1) == 1) {
|
||||||
fault_data = addr.val;
|
fault_data = addr.val;
|
||||||
if ((addr.type & iss::DEBUG)) throw trap_access(0, addr.val);
|
if (addr.access && iss::access_type::DEBUG) throw trap_access(0, addr.val);
|
||||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
this->reg.trap_state = (1 << 31); // issue trap 0
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
|
@ -707,12 +709,11 @@ iss::status riscv_hart_msu_vp<BASE>::write(const iss::addr_t &addr, unsigned len
|
||||||
auto len1 = split_addr - addr.val;
|
auto len1 = split_addr - addr.val;
|
||||||
auto res = write(addr, len1, data);
|
auto res = write(addr, len1, data);
|
||||||
if (res == iss::Ok)
|
if (res == iss::Ok)
|
||||||
res = write(iss::addr_t{addr.type, addr.space, split_addr}, length - len1, data + len1);
|
res = write(iss::addr_t{addr.access, addr.type, addr.space, split_addr}, length - len1, data + len1);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
phys_addr_t paddr = (addr.type & iss::ADDRESS_TYPE) == iss::PHYSICAL ? addr : v2p(addr);
|
auto res = write_mem(BASE::v2p(addr), length, data);
|
||||||
auto res = write_mem(paddr, length, data);
|
|
||||||
if (res != iss::Ok) this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 7 (Store/AMO access fault)
|
if (res != iss::Ok) this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 7 (Store/AMO access fault)
|
||||||
return res;
|
return res;
|
||||||
} catch (trap_access &ta) {
|
} catch (trap_access &ta) {
|
||||||
|
@ -720,7 +721,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const iss::addr_t &addr, unsigned len
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
|
|
||||||
phys_addr_t paddr = (addr.type & iss::ADDRESS_TYPE) == iss::PHYSICAL ? addr : v2p(addr);
|
phys_addr_t paddr = BASE::v2p(addr);
|
||||||
if ((paddr.val + length) > mem.size()) return iss::Err;
|
if ((paddr.val + length) > mem.size()) return iss::Err;
|
||||||
switch (paddr.val) {
|
switch (paddr.val) {
|
||||||
case 0x10013000: // UART0 base, TXFIFO reg
|
case 0x10013000: // UART0 base, TXFIFO reg
|
||||||
|
@ -842,6 +843,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_status(unsig
|
||||||
if (this->reg.machine_state < req_priv_lvl) throw illegal_instruction_fault(this->fault_data);
|
if (this->reg.machine_state < req_priv_lvl) throw illegal_instruction_fault(this->fault_data);
|
||||||
state.write_mstatus(val, req_priv_lvl);
|
state.write_mstatus(val, req_priv_lvl);
|
||||||
check_interrupt();
|
check_interrupt();
|
||||||
|
update_vm_info();
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -901,6 +903,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_satp(unsigne
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
state.satp = val;
|
state.satp = val;
|
||||||
|
update_vm_info();
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -909,8 +912,9 @@ iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length
|
||||||
if ((paddr.val + length) > mem.size()) return iss::Err;
|
if ((paddr.val + length) > mem.size()) return iss::Err;
|
||||||
switch (paddr.val) {
|
switch (paddr.val) {
|
||||||
case 0x0200BFF8: { // CLINT base, mtime reg
|
case 0x0200BFF8: { // CLINT base, mtime reg
|
||||||
if(sizeof(reg_t)<length) return iss::Err;
|
if(sizeof(reg_t)<length) return iss::Err;
|
||||||
reg_t time_val=this->csr[time];
|
reg_t time_val;
|
||||||
|
this->read_csr(time, time_val);
|
||||||
std::copy((uint8_t *)&time_val, ((uint8_t *)&time_val) + length, data);
|
std::copy((uint8_t *)&time_val, ((uint8_t *)&time_val) + length, data);
|
||||||
} break;
|
} break;
|
||||||
case 0x10008000: {
|
case 0x10008000: {
|
||||||
|
@ -960,7 +964,7 @@ iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned lengt
|
||||||
mem_type::page_type &p = mem(paddr.val / mem.page_size);
|
mem_type::page_type &p = mem(paddr.val / mem.page_size);
|
||||||
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
|
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
|
||||||
// tohost handling in case of riscv-test
|
// tohost handling in case of riscv-test
|
||||||
if ((paddr.type & iss::DEBUG) == 0) {
|
if (paddr.access && iss::access_type::FUNC) {
|
||||||
auto tohost_upper = (traits<BASE>::XLEN == 32 && paddr.val == (tohost + 4)) ||
|
auto tohost_upper = (traits<BASE>::XLEN == 32 && paddr.val == (tohost + 4)) ||
|
||||||
(traits<BASE>::XLEN == 64 && paddr.val == tohost);
|
(traits<BASE>::XLEN == 64 && paddr.val == tohost);
|
||||||
auto tohost_lower =
|
auto tohost_lower =
|
||||||
|
@ -1003,15 +1007,23 @@ iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned lengt
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BASE>
|
|
||||||
inline void riscv_hart_msu_vp<BASE>::notify_phase(iss::arch_if::exec_phase phase) {
|
|
||||||
BASE::notify_phase(phase);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename BASE>
|
template<typename BASE>
|
||||||
inline void riscv_hart_msu_vp<BASE>::reset(uint64_t address) {
|
inline void riscv_hart_msu_vp<BASE>::reset(uint64_t address) {
|
||||||
BASE::reset(address);
|
BASE::reset(address);
|
||||||
state.mstatus = hart_state<reg_t>::mstatus_reset_val;
|
state.mstatus = hart_state<reg_t>::mstatus_reset_val;
|
||||||
|
update_vm_info();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BASE>
|
||||||
|
inline void riscv_hart_msu_vp<BASE>::update_vm_info() {
|
||||||
|
vm[1] = hart_state<reg_t>::decode_vm_info(this->reg.machine_state, state.satp);
|
||||||
|
BASE::addr_mode[3]=BASE::addr_mode[2]=vm[1].is_active()?iss::address_type::VIRTUAL:iss::address_type::PHYSICAL;
|
||||||
|
if(state.mstatus.MPRV)
|
||||||
|
vm[0] = hart_state<reg_t>::decode_vm_info(state.mstatus.MPP, state.satp);
|
||||||
|
else
|
||||||
|
vm[0] = vm[1];
|
||||||
|
BASE::addr_mode[1]=BASE::addr_mode[0]=vm[0].is_active()?iss::address_type::VIRTUAL:iss::address_type::PHYSICAL;
|
||||||
|
ptw.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> void riscv_hart_msu_vp<BASE>::check_interrupt() {
|
template <typename BASE> void riscv_hart_msu_vp<BASE>::check_interrupt() {
|
||||||
|
@ -1042,37 +1054,12 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::check_interrupt() {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE>
|
template <typename BASE>
|
||||||
typename riscv_hart_msu_vp<BASE>::phys_addr_t riscv_hart_msu_vp<BASE>::v2p(const iss::addr_t &addr) {
|
typename riscv_hart_msu_vp<BASE>::phys_addr_t riscv_hart_msu_vp<BASE>::virt2phys(const iss::addr_t &addr) {
|
||||||
const uint64_t tmp = reg_t(1) << (traits<BASE>::XLEN - 1);
|
const auto type = addr.access & iss::access_type::FUNC;
|
||||||
const uint64_t msk = tmp | (tmp - 1);
|
|
||||||
|
|
||||||
if (addr.space != traits<BASE>::MEM) { // non-memory access
|
|
||||||
phys_addr_t ret(addr);
|
|
||||||
ret.val &= msk;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto type = (access_type)(addr.getAccessType() & ~iss::DEBUG);
|
|
||||||
uint32_t mode = type != iss::FETCH && state.mstatus.MPRV ? // MPRV
|
|
||||||
mode = state.mstatus.MPP:
|
|
||||||
this->reg.machine_state;
|
|
||||||
|
|
||||||
const vm_info vm = hart_state<reg_t>::decode_vm_info(mode, state.satp);
|
|
||||||
|
|
||||||
if (vm.levels == 0) {
|
|
||||||
phys_addr_t ret(addr);
|
|
||||||
ret.val &= msk;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool s_mode = mode == PRIV_S;
|
|
||||||
const bool sum = state.mstatus.SUM;
|
|
||||||
const bool mxr = state.mstatus.MXR;
|
|
||||||
|
|
||||||
auto it = ptw.find(addr.val >> PGSHIFT);
|
auto it = ptw.find(addr.val >> PGSHIFT);
|
||||||
if (it != ptw.end()) {
|
if (it != ptw.end()) {
|
||||||
const reg_t pte = it->second;
|
const reg_t pte = it->second;
|
||||||
const reg_t ad = PTE_A | ((type == iss::WRITE) * PTE_D);
|
const reg_t ad = PTE_A | (type == iss::access_type::WRITE) * PTE_D;
|
||||||
#ifdef RISCV_ENABLE_DIRTY
|
#ifdef RISCV_ENABLE_DIRTY
|
||||||
// set accessed and possibly dirty bits.
|
// set accessed and possibly dirty bits.
|
||||||
*(uint32_t *)ppte |= ad;
|
*(uint32_t *)ppte |= ad;
|
||||||
|
@ -1080,11 +1067,21 @@ typename riscv_hart_msu_vp<BASE>::phys_addr_t riscv_hart_msu_vp<BASE>::v2p(const
|
||||||
#else
|
#else
|
||||||
// take exception if access or possibly dirty bit is not set.
|
// take exception if access or possibly dirty bit is not set.
|
||||||
if ((pte & ad) == ad)
|
if ((pte & ad) == ad)
|
||||||
return {addr.getAccessType(), addr.space, (pte & (~PGMASK)) | (addr.val & PGMASK)};
|
return {addr.access, addr.space, (pte & (~PGMASK)) | (addr.val & PGMASK)};
|
||||||
else
|
else
|
||||||
ptw.erase(it);
|
ptw.erase(it); // throw an exception
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
|
uint32_t mode = type != iss::access_type::FETCH && state.mstatus.MPRV ? // MPRV
|
||||||
|
state.mstatus.MPP:
|
||||||
|
this->reg.machine_state;
|
||||||
|
|
||||||
|
const vm_info& vm = this->vm[static_cast<uint16_t>(type)/2];
|
||||||
|
|
||||||
|
const bool s_mode = mode == PRIV_S;
|
||||||
|
const bool sum = state.mstatus.SUM;
|
||||||
|
const bool mxr = state.mstatus.MXR;
|
||||||
|
|
||||||
// verify bits xlen-1:va_bits-1 are all equal
|
// verify bits xlen-1:va_bits-1 are all equal
|
||||||
const int va_bits = PGSHIFT + vm.levels * vm.idxbits;
|
const int va_bits = PGSHIFT + vm.levels * vm.idxbits;
|
||||||
const reg_t mask = (reg_t(1) << (traits<BASE>::XLEN > -(va_bits - 1))) - 1;
|
const reg_t mask = (reg_t(1) << (traits<BASE>::XLEN > -(va_bits - 1))) - 1;
|
||||||
|
@ -1099,25 +1096,24 @@ typename riscv_hart_msu_vp<BASE>::phys_addr_t riscv_hart_msu_vp<BASE>::v2p(const
|
||||||
// check that physical address of PTE is legal
|
// check that physical address of PTE is legal
|
||||||
reg_t pte = 0;
|
reg_t pte = 0;
|
||||||
const uint8_t res =
|
const uint8_t res =
|
||||||
this->read(phys_addr_t(addr.getAccessType(), traits<BASE>::MEM, base + idx * vm.ptesize), vm.ptesize,
|
this->read(phys_addr_t{addr.access, traits<BASE>::MEM, base + idx * vm.ptesize}, vm.ptesize, (uint8_t *)&pte);
|
||||||
(uint8_t *)&pte);
|
|
||||||
if (res != 0) throw trap_load_access_fault(addr.val);
|
if (res != 0) throw trap_load_access_fault(addr.val);
|
||||||
const reg_t ppn = pte >> PTE_PPN_SHIFT;
|
const reg_t ppn = pte >> PTE_PPN_SHIFT;
|
||||||
|
|
||||||
if (PTE_TABLE(pte)) { // next level of page table
|
if (PTE_TABLE(pte)) { // next level of page table
|
||||||
base = ppn << PGSHIFT;
|
base = ppn << PGSHIFT;
|
||||||
} else if ((pte & PTE_U) ? s_mode && (type == iss::FETCH || !sum) : !s_mode) {
|
} else if ((pte & PTE_U) ? s_mode && (type == iss::access_type::FETCH || !sum) : !s_mode) {
|
||||||
break;
|
break;
|
||||||
} else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) {
|
} else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) {
|
||||||
break;
|
break;
|
||||||
} else if (type == iss::FETCH ? !(pte & PTE_X)
|
} else if (type == iss::access_type::FETCH ? !(pte & PTE_X)
|
||||||
: type == iss::READ ? !(pte & PTE_R) && !(mxr && (pte & PTE_X))
|
: type == iss::access_type::READ ? !(pte & PTE_R) && !(mxr && (pte & PTE_X))
|
||||||
: !((pte & PTE_R) && (pte & PTE_W))) {
|
: !((pte & PTE_R) && (pte & PTE_W))) {
|
||||||
break;
|
break;
|
||||||
} else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) {
|
} else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
const reg_t ad = PTE_A | ((type == iss::WRITE) * PTE_D);
|
const reg_t ad = PTE_A | ((type == iss::access_type::WRITE) * PTE_D);
|
||||||
#ifdef RISCV_ENABLE_DIRTY
|
#ifdef RISCV_ENABLE_DIRTY
|
||||||
// set accessed and possibly dirty bits.
|
// set accessed and possibly dirty bits.
|
||||||
*(uint32_t *)ppte |= ad;
|
*(uint32_t *)ppte |= ad;
|
||||||
|
@ -1130,18 +1126,18 @@ typename riscv_hart_msu_vp<BASE>::phys_addr_t riscv_hart_msu_vp<BASE>::v2p(const
|
||||||
const reg_t value = (ppn | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT;
|
const reg_t value = (ppn | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT;
|
||||||
const reg_t offset = addr.val & PGMASK;
|
const reg_t offset = addr.val & PGMASK;
|
||||||
ptw[vpn] = value | (pte & 0xff);
|
ptw[vpn] = value | (pte & 0xff);
|
||||||
return {addr.getAccessType(), addr.space, value | offset};
|
return {addr.access, addr.space, value | offset};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case FETCH:
|
case access_type::FETCH:
|
||||||
this->fault_data = addr.val;
|
this->fault_data = addr.val;
|
||||||
throw trap_instruction_page_fault(addr.val);
|
throw trap_instruction_page_fault(addr.val);
|
||||||
case READ:
|
case access_type::READ:
|
||||||
this->fault_data = addr.val;
|
this->fault_data = addr.val;
|
||||||
throw trap_load_page_fault(addr.val);
|
throw trap_load_page_fault(addr.val);
|
||||||
case WRITE:
|
case access_type::WRITE:
|
||||||
this->fault_data = addr.val;
|
this->fault_data = addr.val;
|
||||||
throw trap_store_page_fault(addr.val);
|
throw trap_store_page_fault(addr.val);
|
||||||
default:
|
default:
|
||||||
|
@ -1217,6 +1213,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
|
||||||
CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" << (trap_id ? irq_str[cause] : trap_str[cause])<<"' ("<<trap_id<<")"
|
CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" << (trap_id ? irq_str[cause] : trap_str[cause])<<"' ("<<trap_id<<")"
|
||||||
<< " at address " << buffer << " occurred, changing privilege level from " << lvl[cur_priv]
|
<< " at address " << buffer << " occurred, changing privilege level from " << lvl[cur_priv]
|
||||||
<< " to " << lvl[new_priv];
|
<< " to " << lvl[new_priv];
|
||||||
|
update_vm_info();
|
||||||
return this->reg.NEXT_PC;
|
return this->reg.NEXT_PC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1253,6 +1250,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::leave_trap(uint64_t f
|
||||||
// sets the pc to the value stored in the x epc register.
|
// sets the pc to the value stored in the x epc register.
|
||||||
this->reg.NEXT_PC = csr[uepc | inst_priv << 8];
|
this->reg.NEXT_PC = csr[uepc | inst_priv << 8];
|
||||||
CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[cur_priv] << " to " << lvl[this->reg.machine_state];
|
CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[cur_priv] << " to " << lvl[this->reg.machine_state];
|
||||||
|
update_vm_info();
|
||||||
return this->reg.NEXT_PC;
|
return this->reg.NEXT_PC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
// POSSIBILITY OF SUCH DAMAGE.
|
// POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
//
|
||||||
// Created on: Sun Nov 19 14:05:47 CET 2017
|
// Created on: Fri Dec 15 14:41:57 CET 2017
|
||||||
// * rv32imac.h Author: <CoreDSL Generator>
|
// * rv32imac.h Author: <CoreDSL Generator>
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -98,9 +98,9 @@ struct traits<rv32imac> {
|
||||||
|
|
||||||
using code_word_t = uint32_t; //TODO: check removal
|
using code_word_t = uint32_t; //TODO: check removal
|
||||||
|
|
||||||
using virt_addr_t = iss::typed_addr_t<iss::VIRTUAL>;
|
using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;
|
||||||
|
|
||||||
using phys_addr_t = iss::typed_addr_t<iss::PHYSICAL>;
|
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
||||||
|
|
||||||
constexpr static unsigned reg_bit_width(unsigned r) {
|
constexpr static unsigned reg_bit_width(unsigned r) {
|
||||||
const uint32_t RV32IMAC_reg_size[] = {32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,64};
|
const uint32_t RV32IMAC_reg_size[] = {32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,64};
|
||||||
|
@ -112,6 +112,8 @@ struct traits<rv32imac> {
|
||||||
return RV32IMAC_reg_byte_offset[r];
|
return RV32IMAC_reg_byte_offset[r];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||||
|
|
||||||
enum sreg_flag_e {FLAGS};
|
enum sreg_flag_e {FLAGS};
|
||||||
|
|
||||||
enum mem_type_e {MEM,CSR,FENCE,RES};
|
enum mem_type_e {MEM,CSR,FENCE,RES};
|
||||||
|
@ -140,19 +142,20 @@ struct rv32imac: public arch_if {
|
||||||
/// deprecated
|
/// deprecated
|
||||||
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
|
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
|
||||||
|
|
||||||
void notify_phase(exec_phase phase){
|
|
||||||
if(phase==ISTART){
|
|
||||||
++reg.icount;
|
|
||||||
reg.PC=reg.NEXT_PC;
|
|
||||||
reg.trap_state=reg.pending_trap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t get_icount() { return reg.icount;}
|
uint64_t get_icount() { return reg.icount;}
|
||||||
|
|
||||||
virtual phys_addr_t v2p(const iss::addr_t& pc);
|
inline phys_addr_t v2p(const iss::addr_t& addr){
|
||||||
|
if(addr.space != traits<rv32imac>::MEM ||
|
||||||
|
addr.type == iss::address_type::PHYSICAL ||
|
||||||
|
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL){
|
||||||
|
return phys_addr_t(addr.access, addr.space, addr.val&traits<rv32imac>::addr_mask);
|
||||||
|
} else
|
||||||
|
return virt2phys(addr);
|
||||||
|
}
|
||||||
|
|
||||||
virtual iss::sync_type needed_sync() const { return iss::PRE_SYNC; }
|
virtual phys_addr_t virt2phys(const iss::addr_t& addr);
|
||||||
|
|
||||||
|
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct RV32IMAC_regs {
|
struct RV32IMAC_regs {
|
||||||
|
@ -193,6 +196,8 @@ protected:
|
||||||
uint32_t trap_state, pending_trap, machine_state;
|
uint32_t trap_state, pending_trap, machine_state;
|
||||||
uint64_t icount;
|
uint64_t icount;
|
||||||
} reg;
|
} reg;
|
||||||
|
|
||||||
|
address_type addr_mode[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
// POSSIBILITY OF SUCH DAMAGE.
|
// POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
//
|
||||||
// Created on: Sun Nov 19 14:05:47 CET 2017
|
// Created on: Fri Dec 15 14:41:58 CET 2017
|
||||||
// * rv64ia.h Author: <CoreDSL Generator>
|
// * rv64ia.h Author: <CoreDSL Generator>
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -98,9 +98,9 @@ struct traits<rv64ia> {
|
||||||
|
|
||||||
using code_word_t = uint64_t; //TODO: check removal
|
using code_word_t = uint64_t; //TODO: check removal
|
||||||
|
|
||||||
using virt_addr_t = iss::typed_addr_t<iss::VIRTUAL>;
|
using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;
|
||||||
|
|
||||||
using phys_addr_t = iss::typed_addr_t<iss::PHYSICAL>;
|
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
||||||
|
|
||||||
constexpr static unsigned reg_bit_width(unsigned r) {
|
constexpr static unsigned reg_bit_width(unsigned r) {
|
||||||
const uint32_t RV64IA_reg_size[] = {64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,32,32,32,64};
|
const uint32_t RV64IA_reg_size[] = {64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,32,32,32,64};
|
||||||
|
@ -112,6 +112,8 @@ struct traits<rv64ia> {
|
||||||
return RV64IA_reg_byte_offset[r];
|
return RV64IA_reg_byte_offset[r];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||||
|
|
||||||
enum sreg_flag_e {FLAGS};
|
enum sreg_flag_e {FLAGS};
|
||||||
|
|
||||||
enum mem_type_e {MEM,CSR,FENCE,RES};
|
enum mem_type_e {MEM,CSR,FENCE,RES};
|
||||||
|
@ -140,19 +142,20 @@ struct rv64ia: public arch_if {
|
||||||
/// deprecated
|
/// deprecated
|
||||||
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
|
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
|
||||||
|
|
||||||
void notify_phase(exec_phase phase){
|
|
||||||
if(phase==ISTART){
|
|
||||||
++reg.icount;
|
|
||||||
reg.PC=reg.NEXT_PC;
|
|
||||||
reg.trap_state=reg.pending_trap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t get_icount() { return reg.icount;}
|
uint64_t get_icount() { return reg.icount;}
|
||||||
|
|
||||||
virtual phys_addr_t v2p(const iss::addr_t& pc);
|
inline phys_addr_t v2p(const iss::addr_t& addr){
|
||||||
|
if(addr.space != traits<rv64ia>::MEM ||
|
||||||
|
addr.type == iss::address_type::PHYSICAL ||
|
||||||
|
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL){
|
||||||
|
return phys_addr_t(addr.access, addr.space, addr.val&traits<rv64ia>::addr_mask);
|
||||||
|
} else
|
||||||
|
return virt2phys(addr);
|
||||||
|
}
|
||||||
|
|
||||||
virtual iss::sync_type needed_sync() const { return iss::PRE_SYNC; }
|
virtual phys_addr_t virt2phys(const iss::addr_t& addr);
|
||||||
|
|
||||||
|
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct RV64IA_regs {
|
struct RV64IA_regs {
|
||||||
|
@ -193,6 +196,8 @@ protected:
|
||||||
uint32_t trap_state, pending_trap, machine_state;
|
uint32_t trap_state, pending_trap, machine_state;
|
||||||
uint64_t icount;
|
uint64_t icount;
|
||||||
} reg;
|
} reg;
|
||||||
|
|
||||||
|
address_type addr_mode[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,7 +211,7 @@ status riscv_target_adapter<ARCH>::read_single_register(unsigned int reg_no, std
|
||||||
std::copy(reg_base + offset, reg_base + offset + reg_width, data.begin());
|
std::copy(reg_base + offset, reg_base + offset + reg_width, data.begin());
|
||||||
std::fill(avail.begin(), avail.end(), 0xff);
|
std::fill(avail.begin(), avail.end(), 0xff);
|
||||||
} else {
|
} else {
|
||||||
typed_addr_t<iss::PHYSICAL> a(iss::DEBUG_READ, traits<ARCH>::CSR, reg_no - 65);
|
typed_addr_t<iss::address_type::PHYSICAL> a(iss::access_type::DEBUG_READ, traits<ARCH>::CSR, reg_no - 65);
|
||||||
data.resize(sizeof(typename traits<ARCH>::reg_t));
|
data.resize(sizeof(typename traits<ARCH>::reg_t));
|
||||||
avail.resize(sizeof(typename traits<ARCH>::reg_t));
|
avail.resize(sizeof(typename traits<ARCH>::reg_t));
|
||||||
std::fill(avail.begin(), avail.end(), 0xff);
|
std::fill(avail.begin(), avail.end(), 0xff);
|
||||||
|
@ -228,20 +228,20 @@ status riscv_target_adapter<ARCH>::write_single_register(unsigned int reg_no, co
|
||||||
auto offset = traits<ARCH>::reg_byte_offset(reg_no);
|
auto offset = traits<ARCH>::reg_byte_offset(reg_no);
|
||||||
std::copy(data.begin(), data.begin() + reg_width, reg_base + offset);
|
std::copy(data.begin(), data.begin() + reg_width, reg_base + offset);
|
||||||
} else {
|
} else {
|
||||||
typed_addr_t<iss::PHYSICAL> a(iss::DEBUG_WRITE, traits<ARCH>::CSR, reg_no - 65);
|
typed_addr_t<iss::address_type::PHYSICAL> a(iss::access_type::DEBUG_WRITE, traits<ARCH>::CSR, reg_no - 65);
|
||||||
core->write(a, data.size(), data.data());
|
core->write(a, data.size(), data.data());
|
||||||
}
|
}
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH> status riscv_target_adapter<ARCH>::read_mem(uint64_t addr, std::vector<uint8_t> &data) {
|
template <typename ARCH> status riscv_target_adapter<ARCH>::read_mem(uint64_t addr, std::vector<uint8_t> &data) {
|
||||||
auto a = map_addr({iss::DEBUG_READ, iss::VIRTUAL, 0, addr});
|
auto a = map_addr({iss::access_type::DEBUG_READ, iss::address_type::VIRTUAL, 0, addr});
|
||||||
auto f = [&]() -> status { return core->read(a, data.size(), data.data()); };
|
auto f = [&]() -> status { return core->read(a, data.size(), data.data()); };
|
||||||
return srv->execute_syncronized(f);
|
return srv->execute_syncronized(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH> status riscv_target_adapter<ARCH>::write_mem(uint64_t addr, const std::vector<uint8_t> &data) {
|
template <typename ARCH> status riscv_target_adapter<ARCH>::write_mem(uint64_t addr, const std::vector<uint8_t> &data) {
|
||||||
auto a = map_addr({iss::DEBUG_READ, iss::VIRTUAL, 0, addr});
|
auto a = map_addr({iss::access_type::DEBUG_READ, iss::address_type::VIRTUAL, 0, addr});
|
||||||
return srv->execute_syncronized(&arch_if::write, core, a, data.size(), data.data());
|
return srv->execute_syncronized(&arch_if::write, core, a, data.size(), data.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,8 +292,8 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::packetsize_query(std
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH> status riscv_target_adapter<ARCH>::add_break(int type, uint64_t addr, unsigned int length) {
|
template <typename ARCH> status riscv_target_adapter<ARCH>::add_break(int type, uint64_t addr, unsigned int length) {
|
||||||
auto saddr = map_addr({iss::CODE, iss::PHYSICAL, addr});
|
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
|
||||||
auto eaddr = map_addr({iss::CODE, iss::PHYSICAL, addr + length});
|
auto eaddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr + length});
|
||||||
target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val - saddr.val);
|
target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val - saddr.val);
|
||||||
LOG(TRACE) << "Adding breakpoint with handle " << target_adapter_base::bp_count << " for addr 0x" << std::hex
|
LOG(TRACE) << "Adding breakpoint with handle " << target_adapter_base::bp_count << " for addr 0x" << std::hex
|
||||||
<< saddr.val << std::dec;
|
<< saddr.val << std::dec;
|
||||||
|
@ -302,7 +302,7 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::add_break(int type,
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH> status riscv_target_adapter<ARCH>::remove_break(int type, uint64_t addr, unsigned int length) {
|
template <typename ARCH> status riscv_target_adapter<ARCH>::remove_break(int type, uint64_t addr, unsigned int length) {
|
||||||
auto saddr = map_addr({iss::CODE, iss::PHYSICAL, addr});
|
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
|
||||||
unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val);
|
unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val);
|
||||||
if (handle) {
|
if (handle) {
|
||||||
LOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val
|
LOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val
|
||||||
|
|
|
@ -16,7 +16,8 @@ set(APP_SOURCES main.cpp)
|
||||||
set(LIBRARY_NAME risc-v)
|
set(LIBRARY_NAME risc-v)
|
||||||
|
|
||||||
# Define the library
|
# Define the library
|
||||||
add_library(${LIBRARY_NAME} SHARED ${LIB_SOURCES})
|
#add_library(${LIBRARY_NAME} SHARED ${LIB_SOURCES})
|
||||||
|
add_library(${LIBRARY_NAME} ${LIB_SOURCES})
|
||||||
SET(${LIBRARY_NAME} -Wl,-whole-archive -l${LIBRARY_NAME} -Wl,-no-whole-archive)
|
SET(${LIBRARY_NAME} -Wl,-whole-archive -l${LIBRARY_NAME} -Wl,-no-whole-archive)
|
||||||
set_target_properties(${LIBRARY_NAME} PROPERTIES
|
set_target_properties(${LIBRARY_NAME} PROPERTIES
|
||||||
VERSION ${VERSION} # ${VERSION} was defined in the main CMakeLists.
|
VERSION ${VERSION} # ${VERSION} was defined in the main CMakeLists.
|
||||||
|
|
|
@ -62,7 +62,7 @@ public:
|
||||||
|
|
||||||
vm_impl();
|
vm_impl();
|
||||||
|
|
||||||
vm_impl(ARCH &core, bool dump = false);
|
vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0);
|
||||||
|
|
||||||
void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; }
|
void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; }
|
||||||
|
|
||||||
|
@ -102,13 +102,13 @@ protected:
|
||||||
|
|
||||||
|
|
||||||
inline llvm::Value *gen_reg_load(unsigned i, unsigned level = 0) {
|
inline llvm::Value *gen_reg_load(unsigned i, unsigned level = 0) {
|
||||||
return this->builder->CreateLoad(get_reg_ptr(i), false);
|
return this->builder.CreateLoad(get_reg_ptr(i), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) {
|
inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) {
|
||||||
llvm::Value *next_pc_v = this->builder->CreateSExtOrTrunc(this->gen_const(traits<ARCH>::XLEN, pc.val),
|
llvm::Value *next_pc_v = this->builder.CreateSExtOrTrunc(this->gen_const(traits<ARCH>::XLEN, pc.val),
|
||||||
this->get_type(traits<ARCH>::XLEN));
|
this->get_type(traits<ARCH>::XLEN));
|
||||||
this->builder->CreateStore(next_pc_v, get_reg_ptr(reg_num), true);
|
this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// some compile time constants
|
// some compile time constants
|
||||||
|
@ -186,30 +186,11 @@ private:
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
std::tuple<vm::continuation_e, llvm::BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr,
|
std::tuple<vm::continuation_e, llvm::BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr,
|
||||||
llvm::BasicBlock *bb) {
|
llvm::BasicBlock *bb) {
|
||||||
bb->setName("illegal_instruction");
|
this->gen_sync(iss::PRE_SYNC);
|
||||||
|
this->builder.CreateStore(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), true),
|
||||||
// this->gen_sync(iss::PRE_SYNC);
|
|
||||||
// if(this->disass_enabled){
|
|
||||||
// /* generate console output when executing the command */
|
|
||||||
// boost::format ins_fmter("DB x%1$d");
|
|
||||||
// ins_fmter % (uint64_t)instr;
|
|
||||||
// std::vector<llvm::Value*> args {
|
|
||||||
// this->core_ptr,
|
|
||||||
// this->gen_const(64, pc.val),
|
|
||||||
// this->builder->CreateGlobalStringPtr(ins_fmter.str()),
|
|
||||||
// };
|
|
||||||
// this->builder->CreateCall(this->mod->getFunction("print_disass"), args);
|
|
||||||
// }
|
|
||||||
// pc = pc + ((instr & 3) == 3 ? 4 : 2);
|
|
||||||
// this->gen_raise_trap(0, 2); // illegal instruction trap
|
|
||||||
// this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
|
|
||||||
// this->gen_trap_check(this->leave_blk);
|
|
||||||
// return std::make_tuple(iss::vm::BRANCH, nullptr);
|
|
||||||
// this->gen_sync(iss::PRE_SYNC);
|
|
||||||
this->builder->CreateStore(this->builder->CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), true),
|
|
||||||
get_reg_ptr(traits<ARCH>::PC), true);
|
get_reg_ptr(traits<ARCH>::PC), true);
|
||||||
this->builder->CreateStore(
|
this->builder.CreateStore(
|
||||||
this->builder->CreateAdd(this->builder->CreateLoad(get_reg_ptr(traits<ARCH>::ICOUNT), true),
|
this->builder.CreateAdd(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::ICOUNT), true),
|
||||||
this->gen_const(64U, 1)),
|
this->gen_const(64U, 1)),
|
||||||
get_reg_ptr(traits<ARCH>::ICOUNT), true);
|
get_reg_ptr(traits<ARCH>::ICOUNT), true);
|
||||||
if (this->debugging_enabled()) this->gen_sync(iss::PRE_SYNC);
|
if (this->debugging_enabled()) this->gen_sync(iss::PRE_SYNC);
|
||||||
|
@ -229,8 +210,8 @@ template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
|
||||||
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
||||||
|
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
vm_impl<ARCH>::vm_impl(ARCH &core, bool dump)
|
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
|
||||||
: vm::vm_base<ARCH>(core, dump) {
|
: vm::vm_base<ARCH>(core, core_id, cluster_id) {
|
||||||
qlut[0] = lut_00.data();
|
qlut[0] = lut_00.data();
|
||||||
qlut[1] = lut_01.data();
|
qlut[1] = lut_01.data();
|
||||||
qlut[2] = lut_10.data();
|
qlut[2] = lut_10.data();
|
||||||
|
@ -239,7 +220,6 @@ vm_impl<ARCH>::vm_impl(ARCH &core, bool dump)
|
||||||
auto quantrant = instr.value & 0x3;
|
auto quantrant = instr.value & 0x3;
|
||||||
expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op);
|
expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op);
|
||||||
}
|
}
|
||||||
this->sync_exec = static_cast<sync_type>(this->sync_exec | core.needed_sync());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
|
@ -278,44 +258,44 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(llvm::BasicBlock *leave_blk) {
|
template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(llvm::BasicBlock *leave_blk) {
|
||||||
this->builder->SetInsertPoint(leave_blk);
|
this->builder.SetInsertPoint(leave_blk);
|
||||||
this->builder->CreateRet(this->builder->CreateLoad(get_reg_ptr(arch::traits<ARCH>::NEXT_PC), false));
|
this->builder.CreateRet(this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::NEXT_PC), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
|
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
|
||||||
auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id);
|
auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id);
|
||||||
this->builder->CreateStore(TRAP_val, get_reg_ptr(traits<ARCH>::TRAP_STATE), true);
|
this->builder.CreateStore(TRAP_val, get_reg_ptr(traits<ARCH>::TRAP_STATE), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
|
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
|
||||||
std::vector<llvm::Value *> args{
|
std::vector<llvm::Value *> args{
|
||||||
this->core_ptr, llvm::ConstantInt::get(getContext(), llvm::APInt(64, lvl)),
|
this->core_ptr, llvm::ConstantInt::get(getContext(), llvm::APInt(64, lvl)),
|
||||||
};
|
};
|
||||||
this->builder->CreateCall(this->mod->getFunction("leave_trap"), args);
|
this->builder.CreateCall(this->mod->getFunction("leave_trap"), args);
|
||||||
auto *PC_val = this->gen_read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN / 8);
|
auto *PC_val = this->gen_read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN / 8);
|
||||||
this->builder->CreateStore(PC_val, get_reg_ptr(traits<ARCH>::NEXT_PC), false);
|
this->builder.CreateStore(PC_val, get_reg_ptr(traits<ARCH>::NEXT_PC), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
|
template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) {
|
||||||
std::vector<llvm::Value *> args{
|
std::vector<llvm::Value *> args{
|
||||||
this->core_ptr, llvm::ConstantInt::get(getContext(), llvm::APInt(64, type)),
|
this->core_ptr, llvm::ConstantInt::get(getContext(), llvm::APInt(64, type)),
|
||||||
};
|
};
|
||||||
this->builder->CreateCall(this->mod->getFunction("wait"), args);
|
this->builder.CreateCall(this->mod->getFunction("wait"), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(llvm::BasicBlock *trap_blk) {
|
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(llvm::BasicBlock *trap_blk) {
|
||||||
this->builder->SetInsertPoint(trap_blk);
|
this->builder.SetInsertPoint(trap_blk);
|
||||||
auto *trap_state_val = this->builder->CreateLoad(get_reg_ptr(traits<ARCH>::TRAP_STATE), true);
|
auto *trap_state_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::TRAP_STATE), true);
|
||||||
std::vector<llvm::Value *> args{this->core_ptr, this->adj_to64(trap_state_val),
|
std::vector<llvm::Value *> args{this->core_ptr, this->adj_to64(trap_state_val),
|
||||||
this->adj_to64(this->builder->CreateLoad(get_reg_ptr(traits<ARCH>::PC), false))};
|
this->adj_to64(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::PC), false))};
|
||||||
this->builder->CreateCall(this->mod->getFunction("enter_trap"), args);
|
this->builder.CreateCall(this->mod->getFunction("enter_trap"), args);
|
||||||
auto *trap_addr_val = this->builder->CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), false);
|
auto *trap_addr_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), false);
|
||||||
this->builder->CreateRet(trap_addr_val);
|
this->builder.CreateRet(trap_addr_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(llvm::BasicBlock *bb) {
|
template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(llvm::BasicBlock *bb) {
|
||||||
auto *v = this->builder->CreateLoad(get_reg_ptr(arch::traits<ARCH>::TRAP_STATE), true);
|
auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::TRAP_STATE), true);
|
||||||
this->gen_cond_branch(this->builder->CreateICmp(
|
this->gen_cond_branch(this->builder.CreateICmp(
|
||||||
ICmpInst::ICMP_EQ, v,
|
ICmpInst::ICMP_EQ, v,
|
||||||
llvm::ConstantInt::get(getContext(), llvm::APInt(v->getType()->getIntegerBitWidth(), 0))),
|
llvm::ConstantInt::get(getContext(), llvm::APInt(v->getType()->getIntegerBitWidth(), 0))),
|
||||||
bb, this->trap_blk, 1);
|
bb, this->trap_blk, 1);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -67,6 +67,6 @@ void rv32imac::reset(uint64_t address) {
|
||||||
|
|
||||||
uint8_t *rv32imac::get_regs_base_ptr() { return reinterpret_cast<uint8_t *>(®); }
|
uint8_t *rv32imac::get_regs_base_ptr() { return reinterpret_cast<uint8_t *>(®); }
|
||||||
|
|
||||||
rv32imac::phys_addr_t rv32imac::v2p(const iss::addr_t &pc) {
|
rv32imac::phys_addr_t rv32imac::virt2phys(const iss::addr_t &pc) {
|
||||||
return phys_addr_t(pc); // change logical address to physical address
|
return phys_addr_t(pc); // change logical address to physical address
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,6 @@ void rv64ia::reset(uint64_t address) {
|
||||||
|
|
||||||
uint8_t *rv64ia::get_regs_base_ptr() { return reinterpret_cast<uint8_t *>(®); }
|
uint8_t *rv64ia::get_regs_base_ptr() { return reinterpret_cast<uint8_t *>(®); }
|
||||||
|
|
||||||
rv64ia::phys_addr_t rv64ia::v2p(const iss::addr_t &pc) {
|
rv64ia::phys_addr_t rv64ia::virt2phys(const iss::addr_t &pc) {
|
||||||
return phys_addr_t(pc); // change logical address to physical address
|
return phys_addr_t(pc); // change logical address to physical address
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ int main(int argc, char *argv[]) {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
desc.add_options()
|
desc.add_options()
|
||||||
("help,h", "Print help message")
|
("help,h", "Print help message")
|
||||||
("loglevel,l", po::value<int>()->implicit_value(2), "Sets logging verbosity")
|
("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity")
|
||||||
("logfile,f", po::value<std::string>(), "Sets default log file.")
|
("logfile,f", po::value<std::string>(), "Sets default log file.")
|
||||||
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
|
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
|
||||||
("elf", po::value<std::vector<std::string>>(), "ELF file(s) to load")
|
("elf", po::value<std::vector<std::string>>(), "ELF file(s) to load")
|
||||||
|
@ -62,10 +62,8 @@ int main(int argc, char *argv[]) {
|
||||||
("input,i", po::value<std::string>(), "the elf file to load (instead of hex files)")
|
("input,i", po::value<std::string>(), "the elf file to load (instead of hex files)")
|
||||||
("dump-ir", "dump the intermediate representation")
|
("dump-ir", "dump the intermediate representation")
|
||||||
("cycles,c", po::value<int64_t>()->default_value(-1), "number of cycles to run")
|
("cycles,c", po::value<int64_t>()->default_value(-1), "number of cycles to run")
|
||||||
("systemc,s", "Run as SystemC simulation")
|
|
||||||
("time", po::value<int>(), "SystemC simulation time in ms")
|
("time", po::value<int>(), "SystemC simulation time in ms")
|
||||||
("reset,r", po::value<std::string>(), "reset address")
|
("reset,r", po::value<std::string>(), "reset address")
|
||||||
("trace", po::value<uint8_t>(), "enable tracing, or cmbintation of 1=signals and 2=TX text, 4=TX compressed text, 6=TX in SQLite")
|
|
||||||
("mem,m", po::value<std::string>(), "the memory input file")
|
("mem,m", po::value<std::string>(), "the memory input file")
|
||||||
("isa", po::value<std::string>()->default_value("rv32imac"), "isa to use for simulation");
|
("isa", po::value<std::string>()->default_value("rv32imac"), "isa to use for simulation");
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -86,8 +84,8 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
std::vector<std::string> args = collect_unrecognized(parsed.options, po::include_positional);
|
std::vector<std::string> args = collect_unrecognized(parsed.options, po::include_positional);
|
||||||
|
|
||||||
if (clim.count("loglevel")) {
|
if (clim.count("verbose")) {
|
||||||
auto l = logging::as_log_level(clim["loglevel"].as<int>());
|
auto l = logging::as_log_level(clim["verbose"].as<int>());
|
||||||
LOGGER(DEFAULT)::reporting_level() = l;
|
LOGGER(DEFAULT)::reporting_level() = l;
|
||||||
LOGGER(connection)::reporting_level() = l;
|
LOGGER(connection)::reporting_level() = l;
|
||||||
}
|
}
|
||||||
|
@ -104,18 +102,20 @@ int main(int argc, char *argv[]) {
|
||||||
bool dump = clim.count("dump-ir");
|
bool dump = clim.count("dump-ir");
|
||||||
// instantiate the simulator
|
// instantiate the simulator
|
||||||
std::unique_ptr<iss::vm_if> vm{nullptr};
|
std::unique_ptr<iss::vm_if> vm{nullptr};
|
||||||
if (clim["isa"].as<std::string>().substr(0, 4)=="rv64") {
|
std::string isa_opt(clim["isa"].as<std::string>());
|
||||||
|
if (isa_opt.substr(0, 4)=="rv64") {
|
||||||
iss::arch::rv64ia* cpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv64ia>();
|
iss::arch::rv64ia* cpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv64ia>();
|
||||||
vm = iss::create(cpu, clim["gdb-port"].as<unsigned>(), dump);
|
vm = iss::create(cpu, clim["gdb-port"].as<unsigned>());
|
||||||
} else if (clim["isa"].as<std::string>().substr(0, 4)=="rv32") {
|
} else if (isa_opt.substr(0, 4)=="rv32") {
|
||||||
iss::arch::rv32imac* cpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv32imac>();
|
iss::arch::rv32imac* cpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv32imac>();
|
||||||
vm = iss::create(cpu, clim["gdb-port"].as<unsigned>(), dump);
|
vm = iss::create(cpu, clim["gdb-port"].as<unsigned>());
|
||||||
} else {
|
} else {
|
||||||
LOG(ERROR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl;
|
LOG(ERROR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl;
|
||||||
return 127;
|
return 127;
|
||||||
}
|
}
|
||||||
if (clim.count("elf"))
|
if (clim.count("elf"))
|
||||||
for (std::string input : clim["elf"].as<std::vector<std::string>>()) vm->get_arch()->load_file(input);
|
for (std::string input : clim["elf"].as<std::vector<std::string>>())
|
||||||
|
vm->get_arch()->load_file(input);
|
||||||
if (clim.count("mem"))
|
if (clim.count("mem"))
|
||||||
vm->get_arch()->load_file(clim["mem"].as<std::string>(), iss::arch::traits<iss::arch::rv32imac>::MEM);
|
vm->get_arch()->load_file(clim["mem"].as<std::string>(), iss::arch::traits<iss::arch::rv32imac>::MEM);
|
||||||
for (std::string input : args) vm->get_arch()->load_file(input);// treat remaining arguments as elf files
|
for (std::string input : args) vm->get_arch()->load_file(input);// treat remaining arguments as elf files
|
||||||
|
@ -138,7 +138,7 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
int64_t cycles = -1;
|
int64_t cycles = -1;
|
||||||
cycles = clim["cycles"].as<int64_t>();
|
cycles = clim["cycles"].as<int64_t>();
|
||||||
return vm->start(cycles);
|
return vm->start(cycles, dump);
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
LOG(ERROR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit"
|
LOG(ERROR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 02cb1756166adb7074f6e5dfa106ca5ab04176c6
|
Subproject commit 0122e4d3123eff995aa90a08b8fda3e5b94827d9
|
|
@ -1,13 +1,13 @@
|
||||||
{
|
{
|
||||||
"i_simple_system":{
|
"i_simple_system":{
|
||||||
"i_uart0":{
|
"i_uart0":{
|
||||||
"write_to_ws": false
|
"write_to_ws": true
|
||||||
},
|
},
|
||||||
"i_uart1":{
|
"i_uart1":{
|
||||||
"write_to_ws": false
|
"write_to_ws": false
|
||||||
},
|
},
|
||||||
"i_gpio0":{
|
"i_gpio0":{
|
||||||
"write_to_ws": false
|
"write_to_ws": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue