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:
Eyck Jentzsch 2017-12-15 14:13:22 +01:00
parent b4871ac725
commit 873e4257f2
17 changed files with 2317 additions and 2347 deletions

View File

@ -7,6 +7,7 @@
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>

View File

@ -4,7 +4,7 @@ Am instruction set simulator based on DBT-RISE implementing the RISC-V ISA
**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.
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.

@ -1 +1 @@
Subproject commit cf9679475121f85a6333970f80bb6a40a8b4a0a5
Subproject commit 4bfcd8a10e81d610d46b329841ae3ba7cbc0627a

View File

@ -94,7 +94,9 @@ public:
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 {
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) {
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;
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) {
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;
else{
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) {
core_type::notify_phase(phase);
if (phase == ISTART) owner->sync();
void core_wrapper::notify_phase(exec_phase p) {
if(p == ISTART)
owner->sync();
}
core_complex::core_complex(sc_core::sc_module_name name)

View File

@ -222,6 +222,7 @@ struct vm_info {
int idxbits;
int ptesize;
uint64_t ptbase;
bool is_active() { return levels;}
};
class trap_load_access_fault : public trap_access {
@ -450,7 +451,7 @@ public:
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 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;
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 {
std::stringstream s;
s << "[p:" << lvl[this->reg.machine_state] << ";s:0x" << std::hex << std::setfill('0')
@ -486,6 +485,8 @@ protected:
mem_type mem;
csr_type csr;
hart_state<reg_t> state;
vm_info vm[2];
void update_vm_info();
unsigned to_host_wr_cnt = 0;
std::stringstream uart_buf;
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();
if (fsize > 0) {
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));
if (res != iss::Ok)
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;
}
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>
iss::status riscv_hart_msu_vp<BASE>::read(const iss::addr_t &addr, unsigned length, uint8_t *const data) {
#ifndef NDEBUG
if (addr.type & iss::DEBUG) {
if (addr.access && iss::access_type::DEBUG) {
LOG(DEBUG) << "debug read of " << length << " bytes @addr " << addr;
} else {
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 {
switch (addr.space) {
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;
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
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 res = read(addr, len1, data);
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;
}
}
phys_addr_t paddr = (addr.type & iss::ADDRESS_TYPE) == iss::PHYSICAL ? addr : v2p(addr);
auto res = read_mem(paddr, length, data);
auto res = read_mem( BASE::v2p(addr), length, data);
if (res != iss::Ok) this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
return res;
} 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>
iss::status riscv_hart_msu_vp<BASE>::write(const iss::addr_t &addr, unsigned length, const uint8_t *const data) {
#ifndef NDEBUG
const char *prefix = addr.type & iss::DEBUG ? "debug " : "";
const char *prefix = (addr.access && iss::access_type::DEBUG)? "debug " : "";
switch (length) {
case 8:
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 {
switch (addr.space) {
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;
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
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 res = write(addr, len1, data);
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;
}
}
phys_addr_t paddr = (addr.type & iss::ADDRESS_TYPE) == iss::PHYSICAL ? addr : v2p(addr);
auto res = write_mem(paddr, length, data);
auto res = write_mem(BASE::v2p(addr), length, data);
if (res != iss::Ok) this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 7 (Store/AMO access fault)
return res;
} 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;
}
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;
switch (paddr.val) {
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);
state.write_mstatus(val, req_priv_lvl);
check_interrupt();
update_vm_info();
return iss::Ok;
}
@ -901,6 +903,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_satp(unsigne
return iss::Err;
}
state.satp = val;
update_vm_info();
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;
switch (paddr.val) {
case 0x0200BFF8: { // CLINT base, mtime reg
if(sizeof(reg_t)<length) return iss::Err;
reg_t time_val=this->csr[time];
if(sizeof(reg_t)<length) return iss::Err;
reg_t time_val;
this->read_csr(time, time_val);
std::copy((uint8_t *)&time_val, ((uint8_t *)&time_val) + length, data);
} break;
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);
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
// 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)) ||
(traits<BASE>::XLEN == 64 && paddr.val == tohost);
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;
}
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>
inline void riscv_hart_msu_vp<BASE>::reset(uint64_t address) {
BASE::reset(address);
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() {
@ -1042,37 +1054,12 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::check_interrupt() {
}
template <typename BASE>
typename riscv_hart_msu_vp<BASE>::phys_addr_t riscv_hart_msu_vp<BASE>::v2p(const iss::addr_t &addr) {
const uint64_t tmp = reg_t(1) << (traits<BASE>::XLEN - 1);
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;
typename riscv_hart_msu_vp<BASE>::phys_addr_t riscv_hart_msu_vp<BASE>::virt2phys(const iss::addr_t &addr) {
const auto type = addr.access & iss::access_type::FUNC;
auto it = ptw.find(addr.val >> PGSHIFT);
if (it != ptw.end()) {
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
// set accessed and possibly dirty bits.
*(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
// take exception if access or possibly dirty bit is not set.
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
ptw.erase(it);
ptw.erase(it); // throw an exception
#endif
} 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
const int va_bits = PGSHIFT + vm.levels * vm.idxbits;
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
reg_t pte = 0;
const uint8_t res =
this->read(phys_addr_t(addr.getAccessType(), traits<BASE>::MEM, base + idx * vm.ptesize), vm.ptesize,
(uint8_t *)&pte);
this->read(phys_addr_t{addr.access, traits<BASE>::MEM, base + idx * vm.ptesize}, vm.ptesize, (uint8_t *)&pte);
if (res != 0) throw trap_load_access_fault(addr.val);
const reg_t ppn = pte >> PTE_PPN_SHIFT;
if (PTE_TABLE(pte)) { // next level of page table
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;
} else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) {
break;
} else if (type == iss::FETCH ? !(pte & PTE_X)
: type == iss::READ ? !(pte & PTE_R) && !(mxr && (pte & PTE_X))
} else if (type == iss::access_type::FETCH ? !(pte & PTE_X)
: type == iss::access_type::READ ? !(pte & PTE_R) && !(mxr && (pte & PTE_X))
: !((pte & PTE_R) && (pte & PTE_W))) {
break;
} else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) {
break;
} 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
// set accessed and possibly dirty bits.
*(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 offset = addr.val & PGMASK;
ptw[vpn] = value | (pte & 0xff);
return {addr.getAccessType(), addr.space, value | offset};
return {addr.access, addr.space, value | offset};
}
}
}
switch (type) {
case FETCH:
case access_type::FETCH:
this->fault_data = addr.val;
throw trap_instruction_page_fault(addr.val);
case READ:
case access_type::READ:
this->fault_data = addr.val;
throw trap_load_page_fault(addr.val);
case WRITE:
case access_type::WRITE:
this->fault_data = addr.val;
throw trap_store_page_fault(addr.val);
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<<")"
<< " at address " << buffer << " occurred, changing privilege level from " << lvl[cur_priv]
<< " to " << lvl[new_priv];
update_vm_info();
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.
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];
update_vm_info();
return this->reg.NEXT_PC;
}

View File

@ -28,7 +28,7 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// 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>
//
////////////////////////////////////////////////////////////////////////////////
@ -98,9 +98,9 @@ struct traits<rv32imac> {
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) {
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];
}
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
enum sreg_flag_e {FLAGS};
enum mem_type_e {MEM,CSR,FENCE,RES};
@ -140,19 +142,20 @@ struct rv32imac: public arch_if {
/// deprecated
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;}
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:
struct RV32IMAC_regs {
@ -193,6 +196,8 @@ protected:
uint32_t trap_state, pending_trap, machine_state;
uint64_t icount;
} reg;
address_type addr_mode[4];
};
}

View File

@ -28,7 +28,7 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// 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>
//
////////////////////////////////////////////////////////////////////////////////
@ -98,9 +98,9 @@ struct traits<rv64ia> {
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) {
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];
}
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
enum sreg_flag_e {FLAGS};
enum mem_type_e {MEM,CSR,FENCE,RES};
@ -140,19 +142,20 @@ struct rv64ia: public arch_if {
/// deprecated
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;}
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:
struct RV64IA_regs {
@ -193,6 +196,8 @@ protected:
uint32_t trap_state, pending_trap, machine_state;
uint64_t icount;
} reg;
address_type addr_mode[4];
};
}

View File

@ -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::fill(avail.begin(), avail.end(), 0xff);
} 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));
avail.resize(sizeof(typename traits<ARCH>::reg_t));
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);
std::copy(data.begin(), data.begin() + reg_width, reg_base + offset);
} 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());
}
return Ok;
}
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()); };
return srv->execute_syncronized(f);
}
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());
}
@ -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) {
auto saddr = map_addr({iss::CODE, iss::PHYSICAL, addr});
auto eaddr = map_addr({iss::CODE, iss::PHYSICAL, addr + length});
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
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);
LOG(TRACE) << "Adding breakpoint with handle " << target_adapter_base::bp_count << " for addr 0x" << std::hex
<< 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) {
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);
if (handle) {
LOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val

View File

@ -16,7 +16,8 @@ set(APP_SOURCES main.cpp)
set(LIBRARY_NAME risc-v)
# 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_target_properties(${LIBRARY_NAME} PROPERTIES
VERSION ${VERSION} # ${VERSION} was defined in the main CMakeLists.

View File

@ -62,7 +62,7 @@ public:
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; }
@ -102,13 +102,13 @@ protected:
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) {
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->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
@ -186,30 +186,11 @@ private:
****************************************************************************/
std::tuple<vm::continuation_e, llvm::BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr,
llvm::BasicBlock *bb) {
bb->setName("illegal_instruction");
// 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),
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);
this->builder->CreateStore(
this->builder->CreateAdd(this->builder->CreateLoad(get_reg_ptr(traits<ARCH>::ICOUNT), true),
this->builder.CreateStore(
this->builder.CreateAdd(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::ICOUNT), true),
this->gen_const(64U, 1)),
get_reg_ptr(traits<ARCH>::ICOUNT), true);
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(ARCH &core, bool dump)
: vm::vm_base<ARCH>(core, dump) {
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm::vm_base<ARCH>(core, core_id, cluster_id) {
qlut[0] = lut_00.data();
qlut[1] = lut_01.data();
qlut[2] = lut_10.data();
@ -239,7 +220,6 @@ vm_impl<ARCH>::vm_impl(ARCH &core, bool dump)
auto quantrant = instr.value & 0x3;
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>
@ -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) {
this->builder->SetInsertPoint(leave_blk);
this->builder->CreateRet(this->builder->CreateLoad(get_reg_ptr(arch::traits<ARCH>::NEXT_PC), false));
this->builder.SetInsertPoint(leave_blk);
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) {
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) {
std::vector<llvm::Value *> args{
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);
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) {
std::vector<llvm::Value *> args{
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) {
this->builder->SetInsertPoint(trap_blk);
auto *trap_state_val = this->builder->CreateLoad(get_reg_ptr(traits<ARCH>::TRAP_STATE), true);
this->builder.SetInsertPoint(trap_blk);
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),
this->adj_to64(this->builder->CreateLoad(get_reg_ptr(traits<ARCH>::PC), false))};
this->builder->CreateCall(this->mod->getFunction("enter_trap"), args);
auto *trap_addr_val = this->builder->CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), false);
this->builder->CreateRet(trap_addr_val);
this->adj_to64(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::PC), false))};
this->builder.CreateCall(this->mod->getFunction("enter_trap"), args);
auto *trap_addr_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), false);
this->builder.CreateRet(trap_addr_val);
}
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);
this->gen_cond_branch(this->builder->CreateICmp(
auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::TRAP_STATE), true);
this->gen_cond_branch(this->builder.CreateICmp(
ICmpInst::ICMP_EQ, v,
llvm::ConstantInt::get(getContext(), llvm::APInt(v->getType()->getIntegerBitWidth(), 0))),
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

View File

@ -67,6 +67,6 @@ void rv32imac::reset(uint64_t address) {
uint8_t *rv32imac::get_regs_base_ptr() { return reinterpret_cast<uint8_t *>(&reg); }
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
}

View File

@ -67,6 +67,6 @@ void rv64ia::reset(uint64_t address) {
uint8_t *rv64ia::get_regs_base_ptr() { return reinterpret_cast<uint8_t *>(&reg); }
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
}

View File

@ -54,7 +54,7 @@ int main(int argc, char *argv[]) {
// clang-format off
desc.add_options()
("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.")
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
("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)")
("dump-ir", "dump the intermediate representation")
("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")
("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")
("isa", po::value<std::string>()->default_value("rv32imac"), "isa to use for simulation");
// 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);
if (clim.count("loglevel")) {
auto l = logging::as_log_level(clim["loglevel"].as<int>());
if (clim.count("verbose")) {
auto l = logging::as_log_level(clim["verbose"].as<int>());
LOGGER(DEFAULT)::reporting_level() = l;
LOGGER(connection)::reporting_level() = l;
}
@ -104,18 +102,20 @@ int main(int argc, char *argv[]) {
bool dump = clim.count("dump-ir");
// instantiate the simulator
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>();
vm = iss::create(cpu, clim["gdb-port"].as<unsigned>(), dump);
} else if (clim["isa"].as<std::string>().substr(0, 4)=="rv32") {
vm = iss::create(cpu, clim["gdb-port"].as<unsigned>());
} else if (isa_opt.substr(0, 4)=="rv32") {
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 {
LOG(ERROR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl;
return 127;
}
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"))
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
@ -138,7 +138,7 @@ int main(int argc, char *argv[]) {
}
int64_t cycles = -1;
cycles = clim["cycles"].as<int64_t>();
return vm->start(cycles);
return vm->start(cycles, dump);
} catch (std::exception &e) {
LOG(ERROR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit"
<< std::endl;

@ -1 +1 @@
Subproject commit 02cb1756166adb7074f6e5dfa106ca5ab04176c6
Subproject commit 0122e4d3123eff995aa90a08b8fda3e5b94827d9

View File

@ -1,13 +1,13 @@
{
"i_simple_system":{
"i_uart0":{
"write_to_ws": false
"write_to_ws": true
},
"i_uart1":{
"write_to_ws": false
},
"i_gpio0":{
"write_to_ws": false
"write_to_ws": true
}
}
}