refine and fix TGC_C iss to becoem compliant

This commit is contained in:
Eyck Jentzsch 2021-06-29 11:51:19 +02:00
parent 5d8da08ce5
commit 23b9741adf
10 changed files with 1437 additions and 774 deletions

@ -1 +1 @@
Subproject commit cf601042edaef9661b42a4ab295812d0eca48264
Subproject commit 0c70a41376fb3a529e4f56a9b9d7167c9613958e

View File

@ -33,7 +33,7 @@
def getRegisterSizes(){
def regs = registers.collect{it.size}
regs[-1]=64 // correct for NEXT_PC
regs+=[32, 32, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT
regs+=[32, 32, 64, 64, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET
return regs
}
%>

View File

@ -37,7 +37,7 @@ def nativeTypeSize(int size){
}
def getRegisterSizes(){
def regs = registers.collect{nativeTypeSize(it.size)}
regs+=[32,32, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT
regs+=[32,32, 64, 64, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET
return regs
}
def getRegisterOffsets(){
@ -94,7 +94,9 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
${registers.collect{it.name}.join(', ')}, NUM_REGS,
TRAP_STATE=NUM_REGS,
PENDING_TRAP,
ICOUNT
ICOUNT,
CYCLE,
INSTRET
};
using reg_t = uint${addrDataWidth}_t;
@ -175,6 +177,8 @@ protected:
}}%>
uint32_t trap_state = 0, pending_trap = 0;
uint64_t icount = 0;
uint64_t cycle = 0;
uint64_t instret = 0;
uint32_t last_branch;
} reg;
#pragma pack(pop)

View File

@ -219,20 +219,22 @@ private:
/* instruction ${idx}: ${instr.name} */
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){
// pre execution stuff
this->do_sync(PRE_SYNC, ${idx});
auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
auto NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
*PC=*NEXT_PC;
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
*trap_state = *reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PENDING_TRAP]);
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, ${idx});
<%instr.fields.eachLine{%>${it}
<%}%>if(this->disass_enabled){
/* generate console output when executing the command */
<%instr.disass.eachLine{%>${it}
<%}%>
}
// prepare execution
uint${addrDataWidth}_t* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
uint${addrDataWidth}_t* NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
// used registers<%instr.usedVariables.each{ k,v->
if(v.isArray) {%>
uint${v.type.size}_t* ${k} = reinterpret_cast<uint${v.type.size}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}0]);<% }else{ %>
uint${v.type.size}_t* ${k} = reinterpret_cast<uint${v.type.size}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]);
auto* ${k} = reinterpret_cast<uint${v.type.size}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}0]);<% }else{ %>
auto* ${k} = reinterpret_cast<uint${v.type.size}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]);
<%}}%>// calculate next pc value
*NEXT_PC = *PC + ${instr.length/8};
// execute instruction
@ -241,11 +243,14 @@ private:
<%}%>} catch(...){}
// post execution stuff
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, ${idx});
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
// trap check
if(*trap_state!=0){
super::core.enter_trap(*trap_state, pc.val);
super::core.enter_trap(*trap_state, pc.val, instr);
} else {
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::ICOUNT]))++;
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::INSTRET]))++;
}
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::CYCLE]))++;
pc.val=*NEXT_PC;
return pc;
}
@ -264,7 +269,7 @@ private:
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
// trap check
if(*trap_state!=0){
super::core.enter_trap(*trap_state, pc.val);
super::core.enter_trap(*trap_state, pc.val, instr);
}
pc.val=*NEXT_PC;
return pc;
@ -318,7 +323,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
!(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){
auto res = fetch_ins(pc, data);
if(res!=iss::Ok){
auto new_pc = super::core.enter_trap(TRAP_ID, pc.val);
auto new_pc = super::core.enter_trap(TRAP_ID, pc.val, 0);
res = fetch_ins(virt_addr_t{access_type::FETCH, new_pc}, data);
if(res!=iss::Ok) throw simulation_stopped(0);
}

View File

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (C) 2021, MINRES Technologies GmbH
* Copyright (C) 2021 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -176,8 +176,8 @@ public:
iss::status write(const address_type type, const access_type access, const uint32_t space,
const uint64_t addr, const unsigned length, const uint8_t *const data) override;
virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_m_p::enter_trap(flags, fault_data); }
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr) override;
virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_m_p::enter_trap(flags, fault_data, fault_data); }
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
virtual uint64_t leave_trap(uint64_t flags) override;
const reg_t& get_mhartid() const { return mhartid_reg; }
@ -234,7 +234,10 @@ protected:
virtual iss::status write_csr(unsigned addr, reg_t val);
hart_state_type state;
uint64_t cycle_offset;
int64_t cycle_offset{0};
uint64_t mcycle_csr{0};
int64_t instret_offset{0};
uint64_t minstret_csr{0};
reg_t fault_data;
uint64_t tohost = tohost_dflt;
uint64_t fromhost = fromhost_dflt;
@ -255,7 +258,13 @@ protected:
private:
iss::status read_reg(unsigned addr, reg_t &val);
iss::status write_reg(unsigned addr, reg_t val);
iss::status read_null(unsigned addr, reg_t &val);
iss::status write_null(unsigned addr, reg_t val){return iss::status::Ok;}
iss::status read_cycle(unsigned addr, reg_t &val);
iss::status write_cycle(unsigned addr, reg_t val);
iss::status read_instret(unsigned addr, reg_t &val);
iss::status write_instret(unsigned addr, reg_t val);
iss::status read_mtvec(unsigned addr, reg_t &val);
iss::status read_time(unsigned addr, reg_t &val);
iss::status read_status(unsigned addr, reg_t &val);
iss::status write_status(unsigned addr, reg_t val);
@ -276,37 +285,59 @@ protected:
template <typename BASE>
riscv_hart_m_p<BASE>::riscv_hart_m_p()
: state()
, cycle_offset(0)
, instr_if(*this) {
csr[misa] = traits<BASE>::MISA_VAL;
uart_buf.str("");
for (unsigned addr = mcycle; addr <= hpmcounter31; ++addr) csr_wr_cb[addr] = nullptr;
for (unsigned addr = mcycleh; addr <= hpmcounter31h; ++addr) csr_wr_cb[addr] = nullptr;
// special handling
csr_rd_cb[time] = &riscv_hart_m_p<BASE>::read_time;
csr_wr_cb[time] = nullptr;
csr_rd_cb[timeh] = &riscv_hart_m_p<BASE>::read_time;
csr_wr_cb[timeh] = nullptr;
csr_rd_cb[mcycle] = &riscv_hart_m_p<BASE>::read_cycle;
csr_rd_cb[mcycleh] = &riscv_hart_m_p<BASE>::read_cycle;
csr_rd_cb[minstret] = &riscv_hart_m_p<BASE>::read_cycle;
csr_rd_cb[minstreth] = &riscv_hart_m_p<BASE>::read_cycle;
csr_rd_cb[mstatus] = &riscv_hart_m_p<BASE>::read_status;
csr_wr_cb[mstatus] = &riscv_hart_m_p<BASE>::write_status;
csr_rd_cb[mip] = &riscv_hart_m_p<BASE>::read_ip;
csr_wr_cb[mip] = &riscv_hart_m_p<BASE>::write_ip;
csr_rd_cb[mie] = &riscv_hart_m_p<BASE>::read_ie;
csr_wr_cb[mie] = &riscv_hart_m_p<BASE>::write_ie;
csr_rd_cb[mhartid] = &riscv_hart_m_p<BASE>::read_hartid;
// common regs
const std::array<unsigned, 6> addrs{{mepc, mtvec, mscratch, mcause, mtval, mscratch}};
for(auto addr: addrs) {
csr_rd_cb[addr] = &riscv_hart_m_p<BASE>::read_reg;
csr_wr_cb[addr] = &riscv_hart_m_p<BASE>::write_reg;
for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
// read-only registers
csr_rd_cb[misa] = &riscv_hart_m_p<BASE>::read_reg;
csr_wr_cb[misa] = nullptr;
for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = cycle; addr <= hpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = cycleh; addr <= hpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
// common regs
const std::array<unsigned, 7> addrs{{misa, mepc, mtvec, mscratch, mcause, mtval, mscratch}};
for(auto addr: addrs) {
csr_rd_cb[addr] = &this_class::read_reg;
csr_wr_cb[addr] = &this_class::write_reg;
}
// special handling & overrides
csr_rd_cb[time] = &this_class::read_time;
csr_wr_cb[time] = nullptr;
csr_rd_cb[timeh] = &this_class::read_time;
csr_wr_cb[timeh] = nullptr;
csr_rd_cb[mcycle] = &this_class::read_cycle;
csr_wr_cb[mcycle] = &this_class::write_cycle;
csr_rd_cb[mcycleh] = &this_class::read_cycle;
csr_wr_cb[mcycleh] = &this_class::write_cycle;
csr_rd_cb[minstret] = &this_class::read_instret;
csr_wr_cb[minstret] = &this_class::write_instret;
csr_rd_cb[minstreth] = &this_class::read_instret;
csr_wr_cb[minstreth] = &this_class::write_instret;
csr_rd_cb[mstatus] = &this_class::read_status;
csr_wr_cb[mstatus] = &this_class::write_status;
csr_rd_cb[mip] = &this_class::read_ip;
csr_wr_cb[mip] = &this_class::write_ip;
csr_rd_cb[mie] = &this_class::read_ie;
csr_wr_cb[mie] = &this_class::write_ie;
csr_rd_cb[mhartid] = &this_class::read_hartid;
csr_rd_cb[mcounteren] = &this_class::read_null;
csr_wr_cb[mcounteren] = &this_class::write_null;
csr_rd_cb[mtvec] = &this_class::read_mtvec;
csr_wr_cb[misa] = &this_class::write_null;
}
template <typename BASE> std::pair<uint64_t, bool> riscv_hart_m_p<BASE>::load_file(std::string name, int type) {
@ -547,6 +578,11 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_reg(unsigned add
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_null(unsigned addr, reg_t &val) {
val = 0;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_reg(unsigned addr, reg_t val) {
csr[addr] = val;
return iss::Ok;
@ -563,8 +599,50 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned a
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned addr, reg_t val) {
if (sizeof(typename traits<BASE>::reg_t) != 4) {
if (addr == mcycleh)
return iss::Err;
mcycle_csr = static_cast<uint64_t>(val);
} else {
if (addr == mcycle) {
mcycle_csr = (mcycle_csr & 0xffffffff00000000) + val;
} else {
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
}
}
cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned addr, reg_t &val) {
if (addr == minstret) {
val = static_cast<reg_t>(this->reg.instret);
} else if (addr == minstreth) {
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(this->reg.instret >> 32);
}
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigned addr, reg_t val) {
if (sizeof(typename traits<BASE>::reg_t) != 4) {
if (addr == minstreth)
return iss::Err;
this->reg.instret = static_cast<uint64_t>(val);
} else {
if (addr == minstret) {
this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
} else {
this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
}
}
this->reg.instret--;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned addr, reg_t &val) {
uint64_t time_val = (this->reg.icount + cycle_offset) / (100000000 / 32768 - 1); //-> ~3052;
uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
if (addr == time) {
val = static_cast<reg_t>(time_val);
} else if (addr == timeh) {
@ -574,6 +652,11 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned ad
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_mtvec(unsigned addr, reg_t &val) {
val = csr[mtvec] & ~2;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_status(unsigned addr, reg_t &val) {
val = state.mstatus & hart_state_type::get_mask();
return iss::Ok;
@ -619,7 +702,6 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ip(unsigned add
template <typename BASE>
iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
if ((paddr.val + length) > mem.size()) return iss::Err;
if(mem_read_cb) return mem_read_cb(paddr, length, data);
switch (paddr.val) {
case 0x0200BFF8: { // CLINT base, mtime reg
@ -635,9 +717,9 @@ iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, u
if (this->reg.icount > 30000) data[3] |= 0x80;
} break;
default: {
const auto &p = mem(paddr.val / mem.page_size);
auto offs = paddr.val & mem.page_addr_mask;
std::copy(p.data() + offs, p.data() + offs + length, data);
for(auto offs=0U; offs<length; ++offs) {
*(data + offs)=mem[(paddr.val+offs)%mem.size()];
}
}
}
return iss::Ok;
@ -747,7 +829,7 @@ template <typename BASE> void riscv_hart_m_p<BASE>::check_interrupt() {
}
}
template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flags, uint64_t addr) {
template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) {
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
// calculate and write mcause val
auto trap_id = bit_sub<0, 16>(flags);
@ -757,7 +839,7 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flag
if (trap_id == 0) { // exception
// store ret addr in xepc register
csr[mepc] = static_cast<reg_t>(addr); // store actual address instruction of exception
csr[mtval] = fault_data;
csr[mtval] = cause==2?instr:fault_data;
fault_data = 0;
} else {
csr[mepc] = this->reg.NEXT_PC; // store next address if interrupt
@ -779,7 +861,7 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flag
auto ivec = csr[mtvec];
// calculate addr// set NEXT_PC to trap addressess to jump to based on MODE
// bits in mtvec
this->reg.NEXT_PC = ivec & ~0x1UL;
this->reg.NEXT_PC = ivec & ~0x3UL;
if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
// reset trap state
this->reg.PRIV = PRIV_M;

View File

@ -43,13 +43,14 @@
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <fmt/format.h>
#include <array>
#include <elfio/elfio.hpp>
#include <fmt/format.h>
#include <iomanip>
#include <sstream>
#include <type_traits>
#include <unordered_map>
#include <functional>
#include <util/bit_field.h>
#include <util/ities.h>
#include <util/sparse_array.h>
@ -299,18 +300,30 @@ public:
iss::status write(const address_type type, const access_type access, const uint32_t space,
const uint64_t addr, const unsigned length, const uint8_t *const data) override;
virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_msu_vp::enter_trap(flags, fault_data); }
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr) override;
virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_msu_vp::enter_trap(flags, fault_data, fault_data); }
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
virtual uint64_t leave_trap(uint64_t flags) override;
void wait_until(uint64_t flags) override;
void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount);
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.ccount);
};
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
void setMemReadCb(std::function<iss::status(phys_addr_t, unsigned, uint8_t* const)> const& memReadCb) {
mem_read_cb = memReadCb;
}
void setMemWriteCb(std::function<iss::status(phys_addr_t, unsigned, const uint8_t* const)> const& memWriteCb) {
mem_write_cb = memWriteCb;
}
void set_csr(unsigned addr, reg_t val){
csr[addr & csr.page_addr_mask] = val;
}
protected:
struct riscv_instrumentation_if : public iss::instrumentation_if {
@ -364,6 +377,9 @@ protected:
std::unordered_map<unsigned, wr_csr_f> csr_wr_cb;
private:
iss::status read_null(unsigned addr, reg_t &val);
iss::status read_reg(unsigned addr, reg_t &val);
iss::status write_reg(unsigned addr, reg_t val);
iss::status read_cycle(unsigned addr, reg_t &val);
iss::status read_time(unsigned addr, reg_t &val);
iss::status read_status(unsigned addr, reg_t &val);
@ -372,11 +388,16 @@ private:
iss::status write_ie(unsigned addr, reg_t val);
iss::status read_ip(unsigned addr, reg_t &val);
iss::status write_ip(unsigned addr, reg_t val);
iss::status read_hartid(unsigned addr, reg_t &val);
iss::status read_satp(unsigned addr, reg_t &val);
iss::status write_satp(unsigned addr, reg_t val);
iss::status read_fcsr(unsigned addr, reg_t &val);
iss::status write_fcsr(unsigned addr, reg_t val);
reg_t mhartid_reg{0x0};
std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb;
std::function<iss::status(phys_addr_t, unsigned, const uint8_t *const)> mem_write_cb;
protected:
void check_interrupt();
};
@ -388,10 +409,26 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
, instr_if(*this) {
csr[misa] = hart_state_type::get_misa();
uart_buf.str("");
// read-only registers
csr_wr_cb[misa] = nullptr;
for (unsigned addr = mcycle; addr <= hpmcounter31; ++addr) csr_wr_cb[addr] = nullptr;
for (unsigned addr = mcycleh; addr <= hpmcounter31h; ++addr) csr_wr_cb[addr] = nullptr;
for (unsigned addr = mcycle; addr <= mhpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = mcycleh; addr <= mhpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = cycle; addr <= hpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = cycleh; addr <= hpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
// special handling
csr_rd_cb[time] = &this_class::read_time;
csr_wr_cb[time] = nullptr;
@ -419,6 +456,17 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
csr_wr_cb[sie] = &this_class::write_ie;
csr_rd_cb[uie] = &this_class::read_ie;
csr_wr_cb[uie] = &this_class::write_ie;
csr_rd_cb[mhartid] = &this_class::read_hartid;
// common regs
const std::array<unsigned, 6> addrs{{mepc, mtvec, mscratch, mcause, mtval, mscratch}};
for(auto addr: addrs) {
csr_rd_cb[addr] = &this_class::read_reg;
csr_wr_cb[addr] = &this_class::write_reg;
}
// read-only registers
csr_rd_cb[misa] = &this_class::read_reg;
csr_wr_cb[misa] = nullptr;
csr_rd_cb[satp] = &this_class::read_satp;
csr_wr_cb[satp] = &this_class::write_satp;
csr_rd_cb[fcsr] = &this_class::read_fcsr;
@ -679,35 +727,43 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_csr(unsigned addr, reg_t &val) {
if (addr >= csr.size()) return iss::Err;
auto req_priv_lvl = (addr >> 8) & 0x3;
if (this->reg.PRIV < req_priv_lvl) throw illegal_instruction_fault(this->fault_data);
if (this->reg.PRIV < req_priv_lvl) // not having required privileges
throw illegal_instruction_fault(this->fault_data);
auto it = csr_rd_cb.find(addr);
if (it == csr_rd_cb.end()) {
val = csr[addr & csr.page_addr_mask];
return iss::Ok;
}
rd_csr_f f = it->second;
if (f == nullptr) throw illegal_instruction_fault(this->fault_data);
return (this->*f)(addr, val);
if (it == csr_rd_cb.end() || !it->second) // non existent register
throw illegal_instruction_fault(this->fault_data);
return (this->*(it->second))(addr, val);
}
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_csr(unsigned addr, reg_t val) {
if (addr >= csr.size()) return iss::Err;
auto req_priv_lvl = (addr >> 8) & 0x3;
if (this->reg.PRIV < req_priv_lvl)
if (this->reg.PRIV < req_priv_lvl) // not having required privileges
throw illegal_instruction_fault(this->fault_data);
if((addr&0xc00)==0xc00)
if((addr&0xc00)==0xc00) // writing to read-only region
throw illegal_instruction_fault(this->fault_data);
auto it = csr_wr_cb.find(addr);
if (it == csr_wr_cb.end()) {
csr[addr & csr.page_addr_mask] = val;
return iss::Ok;
}
wr_csr_f f = it->second;
if (f == nullptr) throw illegal_instruction_fault(this->fault_data);
return (this->*f)(addr, val);
if (it == csr_wr_cb.end() || !it->second) // non existent register
throw illegal_instruction_fault(this->fault_data);
return (this->*(it->second))(addr, val);
}
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_cycle(unsigned addr, reg_t &val) {
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_reg(unsigned addr, reg_t &val) {
val = csr[addr];
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_null(unsigned addr, reg_t &val) {
val = 0;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_reg(unsigned addr, reg_t val) {
csr[addr] = val;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned addr, reg_t &val) {
auto cycle_val = this->reg.icount + cycle_offset;
if (addr == mcycle) {
val = static_cast<reg_t>(cycle_val);
@ -750,6 +806,11 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_ie(unsigned a
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_hartid(unsigned addr, reg_t &val) {
val = mhartid_reg;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_ie(unsigned addr, reg_t val) {
auto req_priv_lvl = (addr >> 8) & 0x3;
auto mask = get_irq_mask(req_priv_lvl);
@ -832,7 +893,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_fcsr(unsigne
template <typename BASE>
iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
if ((paddr.val + length) > mem.size()) return iss::Err;
if(mem_read_cb) return mem_read_cb(paddr, length, data);
switch (paddr.val) {
case 0x0200BFF8: { // CLINT base, mtime reg
if (sizeof(reg_t) < length) return iss::Err;
@ -847,9 +908,9 @@ iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length
if (this->reg.icount > 30000) data[3] |= 0x80;
} break;
default: {
const auto &p = mem(paddr.val / mem.page_size);
auto offs = paddr.val & mem.page_addr_mask;
std::copy(p.data() + offs, p.data() + offs + length, data);
for(auto offs=0U; offs<length; ++offs) {
*(data + offs)=mem[(paddr.val+offs)%mem.size()];
}
}
}
return iss::Ok;
@ -858,6 +919,7 @@ iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length
template <typename BASE>
iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
if ((paddr.val + length) > mem.size()) return iss::Err;
if(mem_write_cb) return mem_write_cb(paddr, length, data);
switch (paddr.val) {
case 0x10013000: // UART0 base, TXFIFO reg
case 0x10023000: // UART1 base, TXFIFO reg
@ -1070,7 +1132,7 @@ typename riscv_hart_msu_vp<BASE>::phys_addr_t riscv_hart_msu_vp<BASE>::virt2phys
}
}
template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t flags, uint64_t addr) {
template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) {
auto cur_priv = this->reg.PRIV;
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
// calculate and write mcause val
@ -1091,7 +1153,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
* access, or page-fault exception occurs, mtval is written with the
* faulting effective address.
*/
csr[utval | (new_priv << 8)] = fault_data;
csr[utval | (new_priv << 8)] = cause==2?instr : fault_data;
fault_data = 0;
} else {
if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)

View File

@ -191,8 +191,8 @@ public:
iss::status write(const address_type type, const access_type access, const uint32_t space,
const uint64_t addr, const unsigned length, const uint8_t *const data) override;
virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_mu_p::enter_trap(flags, fault_data); }
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr) override;
virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_mu_p::enter_trap(flags, fault_data, fault_data); }
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
virtual uint64_t leave_trap(uint64_t flags) override;
const reg_t& get_mhartid() const { return mhartid_reg; }
@ -200,7 +200,7 @@ public:
void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount);
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.ccount);
};
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
@ -789,7 +789,7 @@ template <typename BASE, features_e FEAT> void riscv_hart_mu_p<BASE, FEAT>::chec
}
}
template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::enter_trap(uint64_t flags, uint64_t addr) {
template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) {
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
// calculate and write mcause val
auto trap_id = bit_sub<0, 16>(flags);
@ -809,7 +809,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
* access, or page-fault exception occurs, mtval is written with the
* faulting effective address.
*/
csr[utval | (new_priv << 8)] = fault_data;
csr[utval | (new_priv << 8)] = cause==2?instr:fault_data;
fault_data = 0;
} else {
if (this->reg.PRIV != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)

View File

@ -61,7 +61,9 @@ template <> struct traits<tgc_c> {
X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, PC, NEXT_PC, PRIV, NUM_REGS,
TRAP_STATE=NUM_REGS,
PENDING_TRAP,
ICOUNT
ICOUNT,
CYCLE,
INSTRET
};
using reg_t = uint32_t;
@ -74,11 +76,11 @@ template <> struct traits<tgc_c> {
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
static constexpr std::array<const uint32_t, 38> reg_bit_widths{
{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,8,32,32,64}};
static constexpr std::array<const uint32_t, 40> reg_bit_widths{
{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,8,32,32,64,64,64}};
static constexpr std::array<const uint32_t, 38> reg_byte_offsets{
{0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,137,141,145}};
static constexpr std::array<const uint32_t, 40> reg_byte_offsets{
{0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,137,141,145,153,161}};
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
@ -154,25 +156,27 @@ template <> struct traits<tgc_c> {
CLI = 64,
CLUI = 65,
CADDI16SP = 66,
CSRLI = 67,
CSRAI = 68,
CANDI = 69,
CSUB = 70,
CXOR = 71,
COR = 72,
CAND = 73,
CJ = 74,
CBEQZ = 75,
CBNEZ = 76,
CSLLI = 77,
CLWSP = 78,
CMV = 79,
CJR = 80,
CADD = 81,
CJALR = 82,
CEBREAK = 83,
CSWSP = 84,
DII = 85,
__reserved_clui = 67,
CSRLI = 68,
CSRAI = 69,
CANDI = 70,
CSUB = 71,
CXOR = 72,
COR = 73,
CAND = 74,
CJ = 75,
CBEQZ = 76,
CBNEZ = 77,
CSLLI = 78,
CLWSP = 79,
CMV = 80,
CJR = 81,
__reserved_cmv = 82,
CADD = 83,
CJALR = 84,
CEBREAK = 85,
CSWSP = 86,
DII = 87,
MAX_OPCODE
};
};
@ -259,6 +263,8 @@ protected:
uint8_t PRIV = 0;
uint32_t trap_state = 0, pending_trap = 0;
uint64_t icount = 0;
uint64_t cycle = 0;
uint64_t instret = 0;
uint32_t last_branch;
} reg;
#pragma pack(pop)

View File

@ -41,8 +41,8 @@ using namespace iss::arch;
constexpr std::array<const char*, 35> iss::arch::traits<iss::arch::tgc_c>::reg_names;
constexpr std::array<const char*, 35> iss::arch::traits<iss::arch::tgc_c>::reg_aliases;
constexpr std::array<const uint32_t, 38> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths;
constexpr std::array<const uint32_t, 38> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths;
constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
tgc_c::tgc_c() {
reg.icount = 0;

File diff suppressed because it is too large Load Diff