Compare commits
11 Commits
feature/re
...
49be143588
Author | SHA1 | Date | |
---|---|---|---|
49be143588 | |||
0aea1d0177 | |||
6ea7721961 | |||
b0cb997009 | |||
9dfca612b7 | |||
30ae743361 | |||
d91f5f9df4 | |||
5ec457c76b | |||
2e670c4d03 | |||
3d32c33333 | |||
521f40a3d6 |
@ -6,7 +6,7 @@ project(dbt-rise-tgc VERSION 1.0.0)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
find_package(elfio)
|
||||
find_package(elfio QUIET)
|
||||
find_package(Boost COMPONENTS coroutine)
|
||||
|
||||
if(WITH_LLVM)
|
||||
@ -35,13 +35,12 @@ FILE(GLOB TGC_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/vm/interp/vm_*.cpp)
|
||||
set(LIB_SOURCES
|
||||
src/vm/fp_functions.cpp
|
||||
src/plugin/instruction_count.cpp
|
||||
src/plugin/pctrace.cpp
|
||||
|
||||
${TGC_SOURCES}
|
||||
${TGC_VM_SOURCES}
|
||||
)
|
||||
if(TARGET RapidJSON)
|
||||
list(APPEND LIB_SOURCES src/plugin/cycle_estimate.cpp)
|
||||
list(APPEND LIB_SOURCES src/plugin/cycle_estimate.cpp src/plugin/pctrace.cpp)
|
||||
endif()
|
||||
|
||||
if(WITH_LLVM)
|
||||
|
1
gen_input/.gitignore
vendored
1
gen_input/.gitignore
vendored
@ -1 +1,2 @@
|
||||
/src-gen/
|
||||
/CoreDSL-Instruction-Set-Description
|
||||
|
@ -94,7 +94,7 @@ protected:
|
||||
|
||||
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
||||
|
||||
compile_func decode_inst(code_word_t instr) ;
|
||||
typename arch::traits<ARCH>::opcode_e decode_inst_id(code_word_t instr);
|
||||
virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override;
|
||||
|
||||
// some compile time constants
|
||||
@ -114,7 +114,7 @@ protected:
|
||||
struct instruction_pattern {
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
compile_func opc;
|
||||
typename arch::traits<ARCH>::opcode_e id;
|
||||
};
|
||||
|
||||
std::array<std::vector<instruction_pattern>, 4> qlut;
|
||||
@ -201,73 +201,13 @@ private:
|
||||
size_t length;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
compile_func op;
|
||||
typename arch::traits<ARCH>::opcode_e op;
|
||||
};
|
||||
|
||||
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
|
||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||
/* instruction ${instr.instruction.name} */
|
||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${instr.instruction.name}},<%}%>
|
||||
}};
|
||||
|
||||
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
||||
/* instruction ${idx}: ${instr.name} */
|
||||
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){
|
||||
// pre execution stuff
|
||||
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}
|
||||
<%}%>
|
||||
}
|
||||
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]);
|
||||
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
|
||||
// used registers<%instr.usedVariables.each{ k,v->
|
||||
if(v.isArray) {%>
|
||||
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(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${nativeTypeSize(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
|
||||
try {
|
||||
<%instr.behavior.eachLine{%>${it}
|
||||
<%}%>} catch(...){}
|
||||
// post execution stuff
|
||||
process_spawn_blocks();
|
||||
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, ${idx});
|
||||
// trap check
|
||||
if(*trap_state!=0){
|
||||
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;
|
||||
}
|
||||
<%}%>
|
||||
/****************************************************************************
|
||||
* end opcode definitions
|
||||
****************************************************************************/
|
||||
compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr) {
|
||||
this->do_sync(PRE_SYNC, static_cast<unsigned>(arch::traits<ARCH>::opcode_e::MAX_OPCODE));
|
||||
uint32_t* PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
|
||||
uint32_t* NEXT_PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
|
||||
*NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2);
|
||||
raise(0, 2);
|
||||
// post execution stuff
|
||||
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(arch::traits<ARCH>::opcode_e::MAX_OPCODE));
|
||||
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, instr);
|
||||
}
|
||||
pc.val=*NEXT_PC;
|
||||
return pc;
|
||||
}
|
||||
|
||||
//static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK;
|
||||
iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
|
||||
@ -307,6 +247,7 @@ constexpr size_t bit_count(uint32_t u) {
|
||||
template <typename ARCH>
|
||||
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
|
||||
: vm_base<ARCH>(core, core_id, cluster_id) {
|
||||
unsigned id=0;
|
||||
for (auto instr : instr_descr) {
|
||||
auto quadrant = instr.value & 0x3;
|
||||
qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op});
|
||||
@ -327,31 +268,74 @@ inline bool is_jump_to_self_enabled(finish_cond_e cond){
|
||||
}
|
||||
|
||||
template <typename ARCH>
|
||||
typename vm_impl<ARCH>::compile_func vm_impl<ARCH>::decode_inst(code_word_t instr){
|
||||
typename arch::traits<ARCH>::opcode_e vm_impl<ARCH>::decode_inst_id(code_word_t instr){
|
||||
for(auto& e: qlut[instr&0x3]){
|
||||
if(!((instr&e.mask) ^ e.value )) return e.opc;
|
||||
if(!((instr&e.mask) ^ e.value )) return e.id;
|
||||
}
|
||||
return &this_class::illegal_intruction;
|
||||
return arch::traits<ARCH>::opcode_e::MAX_OPCODE;
|
||||
}
|
||||
|
||||
template <typename ARCH>
|
||||
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){
|
||||
// we fetch at max 4 byte, alignment is 2
|
||||
code_word_t insn = 0;
|
||||
auto *const data = (uint8_t *)&insn;
|
||||
code_word_t instr = 0;
|
||||
auto *const data = (uint8_t *)&instr;
|
||||
auto pc=start;
|
||||
|
||||
auto* PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
|
||||
auto* NEXT_PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
|
||||
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
|
||||
auto* icount = reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::ICOUNT]);
|
||||
auto* instret = reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::INSTRET]);
|
||||
|
||||
while(!this->core.should_stop() &&
|
||||
!(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){
|
||||
auto res = fetch_ins(pc, data);
|
||||
if(res!=iss::Ok){
|
||||
if(fetch_ins(pc, data)!=iss::Ok){
|
||||
this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max());
|
||||
pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0);
|
||||
} else {
|
||||
if (is_jump_to_self_enabled(cond) &&
|
||||
(insn == 0x0000006f || (insn&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||
auto f = decode_inst(insn);
|
||||
auto old_pc = pc.val;
|
||||
pc = (this->*f)(pc, insn);
|
||||
(instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||
auto inst_id = decode_inst_id(instr);
|
||||
// pre execution stuff
|
||||
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
|
||||
switch(inst_id){<%instructions.eachWithIndex{instr, idx -> %>
|
||||
case arch::traits<ARCH>::opcode_e::${instr.name}: {
|
||||
<%instr.fields.eachLine{%>${it}
|
||||
<%}%>if(this->disass_enabled){
|
||||
/* generate console output when executing the command */
|
||||
<%instr.disass.eachLine{%>${it}
|
||||
<%}%>
|
||||
}
|
||||
// used registers<%instr.usedVariables.each{ k,v->
|
||||
if(v.isArray) {%>
|
||||
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(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${nativeTypeSize(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
|
||||
try {
|
||||
<%instr.behavior.eachLine{%>${it}
|
||||
<%}%>} catch(...){}
|
||||
}
|
||||
break;<%}%>
|
||||
default: {
|
||||
*NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2);
|
||||
raise(0, 2);
|
||||
}
|
||||
}
|
||||
// post execution stuff
|
||||
process_spawn_blocks();
|
||||
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(inst_id));
|
||||
// trap check
|
||||
if(*trap_state!=0){
|
||||
super::core.enter_trap(*trap_state, pc.val, instr);
|
||||
} else {
|
||||
(*icount)++;
|
||||
(*instret)++;
|
||||
}
|
||||
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::CYCLE]))++;
|
||||
pc.val=*NEXT_PC;
|
||||
this->core.reg.PC = this->core.reg.NEXT_PC;
|
||||
this->core.reg.trap_state = this->core.reg.pending_trap;
|
||||
}
|
||||
@ -359,7 +343,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
|
||||
return pc;
|
||||
}
|
||||
|
||||
} // namespace mnrv32
|
||||
}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
|
||||
|
100
incl/iss/arch/hwl.h
Normal file
100
incl/iss/arch/hwl.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2022 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Contributors:
|
||||
* eyck@minres.com - initial implementation
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _RISCV_HART_M_P_HWL_H
|
||||
#define _RISCV_HART_M_P_HWL_H
|
||||
|
||||
#include <iss/vm_types.h>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
template <typename BASE> class hwl : public BASE {
|
||||
public:
|
||||
using base_class = BASE;
|
||||
using this_class = hwl<BASE>;
|
||||
using reg_t = typename BASE::reg_t;
|
||||
|
||||
hwl();
|
||||
virtual ~hwl() = default;
|
||||
|
||||
protected:
|
||||
iss::status read_custom_csr_reg(unsigned addr, reg_t &val) override;
|
||||
iss::status write_custom_csr_reg(unsigned addr, reg_t val) override;
|
||||
};
|
||||
|
||||
|
||||
template<typename BASE>
|
||||
inline hwl<BASE>::hwl() {
|
||||
for (unsigned addr = 0x800; addr < 0x803; ++addr){
|
||||
this->register_custom_csr_rd(addr);
|
||||
this->register_custom_csr_wr(addr);
|
||||
}
|
||||
for (unsigned addr = 0x804; addr < 0x807; ++addr){
|
||||
this->register_custom_csr_rd(addr);
|
||||
this->register_custom_csr_wr(addr);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BASE>
|
||||
inline iss::status iss::arch::hwl<BASE>::read_custom_csr_reg(unsigned addr, reg_t &val) {
|
||||
switch(addr){
|
||||
case 0x800: val = this->reg.lpstart0; break;
|
||||
case 0x801: val = this->reg.lpend0; break;
|
||||
case 0x802: val = this->reg.lpcount0; break;
|
||||
case 0x804: val = this->reg.lpstart1; break;
|
||||
case 0x805: val = this->reg.lpend1; break;
|
||||
case 0x806: val = this->reg.lpcount1; break;
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template<typename BASE>
|
||||
inline iss::status iss::arch::hwl<BASE>::write_custom_csr_reg(unsigned addr, reg_t val) {
|
||||
switch(addr){
|
||||
case 0x800: this->reg.lpstart0 = val; break;
|
||||
case 0x801: this->reg.lpend0 = val; break;
|
||||
case 0x802: this->reg.lpcount0 = val; break;
|
||||
case 0x804: this->reg.lpstart1 = val; break;
|
||||
case 0x805: this->reg.lpend1 = val; break;
|
||||
case 0x806: this->reg.lpcount1 = val; break;
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
} // namespace arch
|
||||
} // namespace iss
|
||||
|
||||
|
||||
#endif /* _RISCV_HART_M_P_H */
|
@ -43,7 +43,7 @@ namespace arch {
|
||||
|
||||
enum { tohost_dflt = 0xF0001000, fromhost_dflt = 0xF0001040 };
|
||||
|
||||
enum features_e{FEAT_NONE, FEAT_PMP=1, FEAT_EXT_N=2, FEAT_CLIC=4, FEAT_DEBUG=8};
|
||||
enum features_e{FEAT_NONE, FEAT_PMP=1, FEAT_EXT_N=2, FEAT_CLIC=4, FEAT_DEBUG=8, FEAT_TCM=16};
|
||||
|
||||
enum riscv_csr {
|
||||
/* user-level CSR */
|
||||
@ -214,6 +214,14 @@ struct vm_info {
|
||||
bool is_active() { return levels; }
|
||||
};
|
||||
|
||||
struct feature_config {
|
||||
uint64_t clic_base{0xc0000000};
|
||||
unsigned clic_num_irq{16};
|
||||
unsigned clic_num_trigger{0};
|
||||
uint64_t tcm_base{0x10000000};
|
||||
uint64_t tcm_size{0x8000};
|
||||
};
|
||||
|
||||
class trap_load_access_fault : public trap_access {
|
||||
public:
|
||||
trap_load_access_fault(uint64_t badaddr)
|
||||
@ -239,6 +247,49 @@ public:
|
||||
trap_store_page_fault(uint64_t badaddr)
|
||||
: trap_access(15 << 16, badaddr) {}
|
||||
};
|
||||
|
||||
inline void read_reg_uint32(uint64_t offs, uint32_t& reg, uint8_t *const data, unsigned length) {
|
||||
auto reg_ptr = reinterpret_cast<uint8_t*>(®);
|
||||
switch (offs & 0x3) {
|
||||
case 0:
|
||||
for (auto i = 0U; i < length; ++i)
|
||||
*(data + i) = *(reg_ptr + i);
|
||||
break;
|
||||
case 1:
|
||||
for (auto i = 0U; i < length; ++i)
|
||||
*(data + i) = *(reg_ptr + 1 + i);
|
||||
break;
|
||||
case 2:
|
||||
for (auto i = 0U; i < length; ++i)
|
||||
*(data + i) = *(reg_ptr + 2 + i);
|
||||
break;
|
||||
case 3:
|
||||
*data = *(reg_ptr + 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void write_reg_uint32(uint64_t offs, uint32_t& reg, const uint8_t *const data, unsigned length) {
|
||||
auto reg_ptr = reinterpret_cast<uint8_t*>(®);
|
||||
switch (offs & 0x3) {
|
||||
case 0:
|
||||
for (auto i = 0U; i < length; ++i)
|
||||
*(reg_ptr + i) = *(data + i);
|
||||
break;
|
||||
case 1:
|
||||
for (auto i = 0U; i < length; ++i)
|
||||
*(reg_ptr + 1 + i) = *(data + i);
|
||||
break;
|
||||
case 2:
|
||||
for (auto i = 0U; i < length; ++i)
|
||||
*(reg_ptr + 2 + i) = *(data + i);
|
||||
break;
|
||||
case 3:
|
||||
*(reg_ptr + 3) = *data ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,8 +97,10 @@ public:
|
||||
using reg_t = typename core::reg_t;
|
||||
using addr_t = typename core::addr_t;
|
||||
|
||||
using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t &);
|
||||
using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t);
|
||||
using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t &);
|
||||
using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t);
|
||||
using mem_read_f = iss::status(phys_addr_t addr, unsigned, uint8_t *const);
|
||||
using mem_write_f = iss::status(phys_addr_t addr, unsigned, uint8_t const *const);
|
||||
|
||||
// primary template
|
||||
template <class T, class Enable = void> struct hart_state {};
|
||||
@ -294,6 +296,8 @@ protected:
|
||||
};
|
||||
std::vector<clic_int_reg_t> clic_int_reg;
|
||||
|
||||
std::vector<uint8_t> tcm;
|
||||
|
||||
iss::status read_csr_reg(unsigned addr, reg_t &val);
|
||||
iss::status write_csr_reg(unsigned addr, reg_t val);
|
||||
iss::status read_null(unsigned addr, reg_t &val);
|
||||
@ -321,12 +325,26 @@ protected:
|
||||
iss::status read_dpc_reg(unsigned addr, reg_t &val);
|
||||
iss::status write_dpc_reg(unsigned addr, reg_t val);
|
||||
|
||||
virtual iss::status read_custom_csr_reg(unsigned addr, reg_t &val) {return iss::status::Err;};
|
||||
virtual iss::status write_custom_csr_reg(unsigned addr, reg_t val) {return iss::status::Err;};
|
||||
|
||||
void register_custom_csr_rd(unsigned addr){
|
||||
csr_rd_cb[addr] = &this_class::read_custom_csr_reg;
|
||||
}
|
||||
void register_custom_csr_wr(unsigned addr){
|
||||
csr_wr_cb[addr] = &this_class::write_custom_csr_reg;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
void check_interrupt();
|
||||
bool pmp_check(const access_type type, const uint64_t addr, const unsigned len);
|
||||
std::vector<std::tuple<uint64_t, uint64_t>> memfn_range;
|
||||
std::vector<std::function<mem_read_f>> memfn_read;
|
||||
std::vector<std::function<mem_write_f>> memfn_write;
|
||||
void insert_mem_range(uint64_t, uint64_t, std::function<mem_read_f>, std::function<mem_write_f>);
|
||||
uint64_t clic_base_addr{0};
|
||||
unsigned clic_num_irq{0};
|
||||
unsigned clic_num_trigger{0};
|
||||
@ -401,6 +419,46 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p()
|
||||
csr_wr_cb[mvendorid] = &this_class::write_null;
|
||||
csr_wr_cb[marchid] = &this_class::write_null;
|
||||
csr_wr_cb[mimpid] = &this_class::write_null;
|
||||
if(FEAT & FEAT_CLIC) {
|
||||
csr_rd_cb[mtvt] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mtvt] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[mxnti] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mxnti] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[mintstatus] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mintstatus] = &this_class::write_null;
|
||||
csr_rd_cb[mscratchcsw] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mscratchcsw] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[mscratchcswl] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mscratchcswl] = &this_class::write_csr_reg;
|
||||
csr_rd_cb[mintthresh] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mintthresh] = &this_class::write_intthresh;
|
||||
csr_rd_cb[mclicbase] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mclicbase] = &this_class::write_null;
|
||||
|
||||
clic_base_addr=0xC0000000;
|
||||
clic_num_irq=16;
|
||||
clic_int_reg.resize(clic_num_irq);
|
||||
clic_cfg_reg=0x20;
|
||||
clic_info_reg = (/*CLICINTCTLBITS*/ 4U<<21) + clic_num_irq;
|
||||
mcause_max_irq=clic_num_irq+16;
|
||||
insert_mem_range(clic_base_addr, 0x5000UL,
|
||||
[this](phys_addr_t addr, unsigned length, uint8_t * const data) { return read_clic(addr.val, length, data);},
|
||||
[this](phys_addr_t addr, unsigned length, uint8_t const * const data) {return write_clic(addr.val, length, data);});
|
||||
}
|
||||
if(FEAT & FEAT_TCM) {
|
||||
tcm.resize(0x8000);
|
||||
std::function<mem_read_f> read_clic_cb = [this](phys_addr_t addr, unsigned length, uint8_t * const data) {
|
||||
auto offset=addr.val-0x10000000;
|
||||
std::copy(tcm.data() + offset, tcm.data() + offset + length, data);
|
||||
return iss::Ok;
|
||||
};
|
||||
std::function<mem_write_f> write_clic_cb = [this](phys_addr_t addr, unsigned length, uint8_t const * const data) {
|
||||
auto offset=addr.val-0x10000000;
|
||||
std::copy(data, data + length, tcm.data() + offset);
|
||||
return iss::Ok;
|
||||
};
|
||||
insert_mem_range(0x10000000, 0x8000UL, read_clic_cb, write_clic_cb);
|
||||
}
|
||||
if(FEAT & FEAT_DEBUG){
|
||||
csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
|
||||
csr_rd_cb[dscratch0] = &this_class::read_dcsr_reg;
|
||||
@ -479,6 +537,20 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
|
||||
throw std::runtime_error("memory load file not found");
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
inline void riscv_hart_m_p<BASE, FEAT>::insert_mem_range(uint64_t base, uint64_t size, std::function<mem_read_f> rd_f,
|
||||
std::function<mem_write_f> wr_fn) {
|
||||
std::tuple<uint64_t, uint64_t> entry{base, size};
|
||||
auto it = std::upper_bound( memfn_range.begin(), memfn_range.end(), entry,
|
||||
[](std::tuple<uint64_t, uint64_t> const& a, std::tuple<uint64_t, uint64_t> const& b){
|
||||
return std::get<0>(a)<std::get<0>(b);
|
||||
});
|
||||
auto idx = std::distance(memfn_range.begin(), it);
|
||||
memfn_range.insert(it, entry);
|
||||
memfn_read.insert(std::begin(memfn_read)+idx, rd_f);
|
||||
memfn_write.insert(std::begin(memfn_write)+idx, wr_fn);
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const access_type access, const uint32_t space,
|
||||
const uint64_t addr, const unsigned length, uint8_t *const data) {
|
||||
@ -507,9 +579,20 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
auto res = type==iss::address_type::PHYSICAL?
|
||||
read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
|
||||
read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
|
||||
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
auto res = iss::Err;
|
||||
if(access != access_type::FETCH && memfn_range.size()){
|
||||
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||
return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val;
|
||||
});
|
||||
if(it!=std::end(memfn_range)) {
|
||||
auto idx = std::distance(std::begin(memfn_range), it);
|
||||
res = memfn_read[idx](phys_addr, length, data);
|
||||
} else
|
||||
res = read_mem( phys_addr, length, data);
|
||||
} else {
|
||||
res = read_mem( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)){
|
||||
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
fault_data=addr;
|
||||
@ -584,14 +667,25 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
if(!(access && iss::access_type::DEBUG) && length>1 && (addr&(length-1))){
|
||||
if(length>1 && (addr&(length-1)) && (access&access_type::DEBUG) != access_type::DEBUG){
|
||||
this->reg.trap_state = 1<<31 | 6<<16;
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
auto res = type==iss::address_type::PHYSICAL?
|
||||
write_mem(phys_addr_t{access, space, addr}, length, data):
|
||||
write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
|
||||
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
auto res = iss::Err;
|
||||
if(access != access_type::FETCH && memfn_range.size()){
|
||||
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||
return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val;
|
||||
});
|
||||
if(it!=std::end(memfn_range)) {
|
||||
auto idx = std::distance(std::begin(memfn_range), it);
|
||||
res = memfn_write[idx]( phys_addr, length, data);
|
||||
} else
|
||||
res = write_mem( phys_addr, length, data);
|
||||
} else {
|
||||
res = write_mem( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)) {
|
||||
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
fault_data=addr;
|
||||
@ -864,6 +958,12 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::write_intthresh(unsigned addr, reg_t val) {
|
||||
csr[addr]= val &0xff;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
|
||||
if(mem_read_cb) return mem_read_cb(paddr, length, data);
|
||||
@ -967,6 +1067,42 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned length, uint8_t *const data) {
|
||||
if(addr==clic_base_addr) { // cliccfg
|
||||
*data=clic_cfg_reg;
|
||||
for(auto i=1; i<length; ++i) *(data+i)=0;
|
||||
} else if(addr>=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+8)){ // clicinfo
|
||||
read_reg_uint32(addr, clic_info_reg, data, length);
|
||||
} else if(addr>=(clic_base_addr+0x40) && (addr+length)<=(clic_base_addr+0x40+clic_num_trigger*4)){ // clicinttrig
|
||||
auto offset = ((addr&0x7fff)-0x40)/4;
|
||||
read_reg_uint32(addr, clic_inttrig_reg[offset], data, length);
|
||||
} else if(addr>=(clic_base_addr+0x1000) && (addr+length)<=(clic_base_addr+clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
|
||||
auto offset = ((addr&0x7fff)-0x1000)/4;
|
||||
read_reg_uint32(addr, clic_int_reg[offset].raw, data, length);
|
||||
} else {
|
||||
for(auto i = 0U; i<length; ++i) *(data+i)=0;
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_m_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned length, const uint8_t *const data) {
|
||||
if(addr==clic_base_addr) { // cliccfg
|
||||
clic_cfg_reg = *data;
|
||||
clic_cfg_reg&= 0x7e;
|
||||
// } else if(addr>=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+4)){ // clicinfo
|
||||
// write_uint32(addr, clic_info_reg, data, length);
|
||||
} else if(addr>=(clic_base_addr+0x40) && (addr+length)<=(clic_base_addr+0xC0)){ // clicinttrig
|
||||
auto offset = ((addr&0x7fff)-0x40)/4;
|
||||
write_reg_uint32(addr, clic_inttrig_reg[offset], data, length);
|
||||
} else if(addr>=(clic_base_addr+0x1000) && (addr+length)<=(clic_base_addr+clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
|
||||
auto offset = ((addr&0x7fff)-0x1000)/4;
|
||||
write_reg_uint32(addr, clic_int_reg[offset].raw, data, length);
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> inline void riscv_hart_m_p<BASE, FEAT>::reset(uint64_t address) {
|
||||
BASE::reset(address);
|
||||
state.mstatus = hart_state_type::mstatus_reset_val;
|
||||
|
@ -408,6 +408,16 @@ private:
|
||||
iss::status read_fcsr(unsigned addr, reg_t &val);
|
||||
iss::status write_fcsr(unsigned addr, reg_t val);
|
||||
|
||||
virtual iss::status read_custom_csr_reg(unsigned addr, reg_t &val) {return iss::status::Err;};
|
||||
virtual iss::status write_custom_csr_reg(unsigned addr, reg_t val) {return iss::status::Err;};
|
||||
|
||||
void register_custom_csr_rd(unsigned addr){
|
||||
csr_rd_cb[addr] = &this_class::read_custom_csr_reg;
|
||||
}
|
||||
void register_custom_csr_wr(unsigned addr){
|
||||
csr_wr_cb[addr] = &this_class::write_custom_csr_reg;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -97,8 +97,10 @@ public:
|
||||
using reg_t = typename core::reg_t;
|
||||
using addr_t = typename core::addr_t;
|
||||
|
||||
using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t &);
|
||||
using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t);
|
||||
using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t &);
|
||||
using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t);
|
||||
using mem_read_f = iss::status(phys_addr_t addr, unsigned, uint8_t *const);
|
||||
using mem_write_f = iss::status(phys_addr_t addr, unsigned, uint8_t const *const);
|
||||
|
||||
// primary template
|
||||
template <class T, class Enable = void> struct hart_state {};
|
||||
@ -195,7 +197,7 @@ public:
|
||||
return traits<BASE>::MISA_VAL&0b0100?~1:~3;
|
||||
}
|
||||
|
||||
riscv_hart_mu_p();
|
||||
riscv_hart_mu_p(feature_config cfg = feature_config{});
|
||||
virtual ~riscv_hart_mu_p() = default;
|
||||
|
||||
void reset(uint64_t address) override;
|
||||
@ -309,6 +311,8 @@ protected:
|
||||
};
|
||||
std::vector<clic_int_reg_t> clic_int_reg;
|
||||
|
||||
std::vector<uint8_t> tcm;
|
||||
|
||||
iss::status read_csr_reg(unsigned addr, reg_t &val);
|
||||
iss::status write_csr_reg(unsigned addr, reg_t val);
|
||||
iss::status read_null(unsigned addr, reg_t &val);
|
||||
@ -339,29 +343,42 @@ protected:
|
||||
iss::status write_dpc_reg(unsigned addr, reg_t val);
|
||||
iss::status write_pmpcfg_reg(unsigned addr, reg_t val);
|
||||
|
||||
virtual iss::status read_custom_csr_reg(unsigned addr, reg_t &val) {return iss::status::Err;};
|
||||
virtual iss::status write_custom_csr_reg(unsigned addr, reg_t val) {return iss::status::Err;};
|
||||
|
||||
void register_custom_csr_rd(unsigned addr){
|
||||
csr_rd_cb[addr] = &this_class::read_custom_csr_reg;
|
||||
}
|
||||
void register_custom_csr_wr(unsigned addr){
|
||||
csr_wr_cb[addr] = &this_class::write_custom_csr_reg;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
void check_interrupt();
|
||||
bool pmp_check(const access_type type, const uint64_t addr, const unsigned len);
|
||||
uint64_t clic_base_addr{0};
|
||||
unsigned clic_num_irq{0};
|
||||
unsigned clic_num_trigger{0};
|
||||
std::vector<std::tuple<uint64_t, uint64_t>> memfn_range;
|
||||
std::vector<std::function<mem_read_f>> memfn_read;
|
||||
std::vector<std::function<mem_write_f>> memfn_write;
|
||||
void insert_mem_range(uint64_t, uint64_t, std::function<mem_read_f>, std::function<mem_write_f>);
|
||||
feature_config cfg;
|
||||
unsigned mcause_max_irq{16};
|
||||
inline bool debug_mode_active() {return this->reg.PRIV&0x4;}
|
||||
};
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p()
|
||||
riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||
: state()
|
||||
, instr_if(*this) {
|
||||
, instr_if(*this)
|
||||
, cfg(cfg) {
|
||||
// reset values
|
||||
csr[misa] = traits<BASE>::MISA_VAL;
|
||||
csr[mvendorid] = 0x669;
|
||||
csr[marchid] = traits<BASE>::MARCHID_VAL;
|
||||
csr[mimpid] = 1;
|
||||
csr[mclicbase] = 0xc0000000; // TODO: should be taken from YAML file
|
||||
csr[mclicbase] = cfg.clic_base; // TODO: should be taken from YAML file
|
||||
|
||||
uart_buf.str("");
|
||||
for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){
|
||||
@ -467,12 +484,27 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p()
|
||||
csr_rd_cb[mclicbase] = &this_class::read_csr_reg;
|
||||
csr_wr_cb[mclicbase] = &this_class::write_null;
|
||||
|
||||
clic_base_addr=0xC0000000;
|
||||
clic_num_irq=16;
|
||||
clic_int_reg.resize(clic_num_irq);
|
||||
clic_int_reg.resize(cfg.clic_num_irq);
|
||||
clic_cfg_reg=0x20;
|
||||
clic_info_reg = (/*CLICINTCTLBITS*/ 4U<<21) + clic_num_irq;
|
||||
mcause_max_irq=clic_num_irq+16;
|
||||
clic_info_reg = (/*CLICINTCTLBITS*/ 4U<<21) + cfg.clic_num_irq;
|
||||
mcause_max_irq=cfg.clic_num_irq+16;
|
||||
insert_mem_range(cfg.clic_base, 0x5000UL,
|
||||
[this](phys_addr_t addr, unsigned length, uint8_t * const data) { return read_clic(addr.val, length, data);},
|
||||
[this](phys_addr_t addr, unsigned length, uint8_t const * const data) {return write_clic(addr.val, length, data);});
|
||||
}
|
||||
if(FEAT & FEAT_TCM) {
|
||||
tcm.resize(cfg.tcm_size);
|
||||
std::function<mem_read_f> read_clic_cb = [this](phys_addr_t addr, unsigned length, uint8_t * const data) {
|
||||
auto offset=addr.val-this->cfg.tcm_base;
|
||||
std::copy(tcm.data() + offset, tcm.data() + offset + length, data);
|
||||
return iss::Ok;
|
||||
};
|
||||
std::function<mem_write_f> write_clic_cb = [this](phys_addr_t addr, unsigned length, uint8_t const * const data) {
|
||||
auto offset=addr.val-this->cfg.tcm_base;
|
||||
std::copy(data, data + length, tcm.data() + offset);
|
||||
return iss::Ok;
|
||||
};
|
||||
insert_mem_range(cfg.tcm_base, cfg.tcm_size, read_clic_cb, write_clic_cb);
|
||||
}
|
||||
if(FEAT & FEAT_DEBUG){
|
||||
csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
|
||||
@ -552,6 +584,20 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
|
||||
throw std::runtime_error("memory load file not found");
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
inline void riscv_hart_mu_p<BASE, FEAT>::insert_mem_range(uint64_t base, uint64_t size, std::function<mem_read_f> rd_f,
|
||||
std::function<mem_write_f> wr_fn) {
|
||||
std::tuple<uint64_t, uint64_t> entry{base, size};
|
||||
auto it = std::upper_bound( memfn_range.begin(), memfn_range.end(), entry,
|
||||
[](std::tuple<uint64_t, uint64_t> const& a, std::tuple<uint64_t, uint64_t> const& b){
|
||||
return std::get<0>(a)<std::get<0>(b);
|
||||
});
|
||||
auto idx = std::distance(memfn_range.begin(), it);
|
||||
memfn_range.insert(it, entry);
|
||||
memfn_read.insert(std::begin(memfn_read)+idx, rd_f);
|
||||
memfn_write.insert(std::begin(memfn_write)+idx, wr_fn);
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
inline iss::status riscv_hart_mu_p<BASE, FEAT>::write_pmpcfg_reg(unsigned addr, reg_t val) {
|
||||
csr[addr] = val & 0x9f9f9f9f;
|
||||
@ -678,8 +724,15 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
|
||||
}
|
||||
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
auto res = iss::Err;
|
||||
if((FEAT & FEAT_CLIC) && access != access_type::FETCH && phys_addr.val>=clic_base_addr && (phys_addr.val+length)<=(clic_base_addr+0x5000)){ //TODO: should be a constant
|
||||
res = read_clic(phys_addr.val, length, data);
|
||||
if(access != access_type::FETCH && memfn_range.size()){
|
||||
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||
return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val;
|
||||
});
|
||||
if(it!=std::end(memfn_range)) {
|
||||
auto idx = std::distance(std::begin(memfn_range), it);
|
||||
res = memfn_read[idx](phys_addr, length, data);
|
||||
} else
|
||||
res = read_mem( phys_addr, length, data);
|
||||
} else {
|
||||
res = read_mem( phys_addr, length, data);
|
||||
}
|
||||
@ -771,8 +824,19 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||
return iss::Err;
|
||||
}
|
||||
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
auto res = ((FEAT & FEAT_CLIC) && phys_addr.val>=clic_base_addr && (phys_addr.val+length)<=(clic_base_addr+0x5000))? //TODO: should be a constant
|
||||
write_clic(phys_addr.val, length, data) : write_mem( phys_addr, length, data);
|
||||
auto res = iss::Err;
|
||||
if(access != access_type::FETCH && memfn_range.size()){
|
||||
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||
return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val;
|
||||
});
|
||||
if(it!=std::end(memfn_range)) {
|
||||
auto idx = std::distance(std::begin(memfn_range), it);
|
||||
res = memfn_write[idx]( phys_addr, length, data);
|
||||
} else
|
||||
res = write_mem( phys_addr, length, data);
|
||||
} else {
|
||||
res = write_mem( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)) {
|
||||
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
fault_data=addr;
|
||||
@ -1101,8 +1165,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
|
||||
case 0x10023000: // UART1 base, TXFIFO reg
|
||||
uart_buf << (char)data[0];
|
||||
if (((char)data[0]) == '\n' || data[0] == 0) {
|
||||
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
|
||||
// '"<<uart_buf.str()<<"'";
|
||||
LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send '"<<uart_buf.str()<<"'";
|
||||
std::cout << uart_buf.str();
|
||||
uart_buf.str("");
|
||||
}
|
||||
@ -1171,61 +1234,19 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
void read_uint32(uint64_t offs, uint32_t& reg, uint8_t *const data, unsigned length) {
|
||||
auto reg_ptr = reinterpret_cast<uint8_t*>(®);
|
||||
switch (offs & 0x3) {
|
||||
case 0:
|
||||
for (auto i = 0U; i < length; ++i)
|
||||
*(data + i) = *(reg_ptr + i);
|
||||
break;
|
||||
case 1:
|
||||
for (auto i = 0U; i < length; ++i)
|
||||
*(data + i) = *(reg_ptr + 1 + i);
|
||||
break;
|
||||
case 2:
|
||||
for (auto i = 0U; i < length; ++i)
|
||||
*(data + i) = *(reg_ptr + 2 + i);
|
||||
break;
|
||||
case 3:
|
||||
*data = *(reg_ptr + 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void write_uint32(uint64_t offs, uint32_t& reg, const uint8_t *const data, unsigned length) {
|
||||
auto reg_ptr = reinterpret_cast<uint8_t*>(®);
|
||||
switch (offs & 0x3) {
|
||||
case 0:
|
||||
for (auto i = 0U; i < length; ++i)
|
||||
*(reg_ptr + i) = *(data + i);
|
||||
break;
|
||||
case 1:
|
||||
for (auto i = 0U; i < length; ++i)
|
||||
*(reg_ptr + 1 + i) = *(data + i);
|
||||
break;
|
||||
case 2:
|
||||
for (auto i = 0U; i < length; ++i)
|
||||
*(reg_ptr + 2 + i) = *(data + i);
|
||||
break;
|
||||
case 3:
|
||||
*(reg_ptr + 3) = *data ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned length, uint8_t *const data) {
|
||||
if(addr==clic_base_addr) { // cliccfg
|
||||
if(addr==cfg.clic_base) { // cliccfg
|
||||
*data=clic_cfg_reg;
|
||||
for(auto i=1; i<length; ++i) *(data+i)=0;
|
||||
} else if(addr>=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+8)){ // clicinfo
|
||||
read_uint32(addr, clic_info_reg, data, length);
|
||||
} else if(addr>=(clic_base_addr+0x40) && (addr+length)<=(clic_base_addr+0x40+clic_num_trigger*4)){ // clicinttrig
|
||||
} else if(addr>=(cfg.clic_base+4) && (addr+length)<=(cfg.clic_base+8)){ // clicinfo
|
||||
read_reg_uint32(addr, clic_info_reg, data, length);
|
||||
} else if(addr>=(cfg.clic_base+0x40) && (addr+length)<=(cfg.clic_base+0x40+cfg.clic_num_trigger*4)){ // clicinttrig
|
||||
auto offset = ((addr&0x7fff)-0x40)/4;
|
||||
read_uint32(addr, clic_inttrig_reg[offset], data, length);
|
||||
} else if(addr>=(clic_base_addr+0x1000) && (addr+length)<=(clic_base_addr+clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
|
||||
read_reg_uint32(addr, clic_inttrig_reg[offset], data, length);
|
||||
} else if(addr>=(cfg.clic_base+0x1000) && (addr+length)<=(cfg.clic_base+cfg.clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
|
||||
auto offset = ((addr&0x7fff)-0x1000)/4;
|
||||
read_uint32(addr, clic_int_reg[offset].raw, data, length);
|
||||
read_reg_uint32(addr, clic_int_reg[offset].raw, data, length);
|
||||
} else {
|
||||
for(auto i = 0U; i<length; ++i) *(data+i)=0;
|
||||
}
|
||||
@ -1234,17 +1255,17 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned lengt
|
||||
|
||||
template<typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned length, const uint8_t *const data) {
|
||||
if(addr==clic_base_addr) { // cliccfg
|
||||
if(addr==cfg.clic_base) { // cliccfg
|
||||
clic_cfg_reg = *data;
|
||||
clic_cfg_reg&= 0x7e;
|
||||
// } else if(addr>=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+4)){ // clicinfo
|
||||
// } else if(addr>=(cfg.clic_base+4) && (addr+length)<=(cfg.clic_base+4)){ // clicinfo
|
||||
// write_uint32(addr, clic_info_reg, data, length);
|
||||
} else if(addr>=(clic_base_addr+0x40) && (addr+length)<=(clic_base_addr+0xC0)){ // clicinttrig
|
||||
} else if(addr>=(cfg.clic_base+0x40) && (addr+length)<=(cfg.clic_base+0xC0)){ // clicinttrig
|
||||
auto offset = ((addr&0x7fff)-0x40)/4;
|
||||
write_uint32(addr, clic_inttrig_reg[offset], data, length);
|
||||
} else if(addr>=(clic_base_addr+0x1000) && (addr+length)<=(clic_base_addr+clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
|
||||
write_reg_uint32(addr, clic_inttrig_reg[offset], data, length);
|
||||
} else if(addr>=(cfg.clic_base+0x1000) && (addr+length)<=(cfg.clic_base+cfg.clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
|
||||
auto offset = ((addr&0x7fff)-0x1000)/4;
|
||||
write_uint32(addr, clic_int_reg[offset].raw, data, length);
|
||||
write_reg_uint32(addr, clic_int_reg[offset].raw, data, length);
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ template <> struct traits<tgc_c> {
|
||||
static constexpr std::array<const char*, 36> reg_aliases{
|
||||
{"ZERO", "RA", "SP", "GP", "TP", "T0", "T1", "T2", "S0", "S1", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "T3", "T4", "T5", "T6", "PC", "NEXT_PC", "PRIV", "DPC"}};
|
||||
|
||||
enum constants {MISA_VAL=0b01000000000000000001000100000100, MARCHID_VAL=0x80000003, XLEN=32, CSR_SIZE=4096, INSTR_ALIGNMENT=2, fence=0, fencei=1, fencevmal=2, fencevmau=3, MUL_LEN=64};
|
||||
enum constants {MISA_VAL=0b01000000000000000001000100000100, MARCHID_VAL=0x80000003, RFS=32, XLEN=32, CSR_SIZE=4096, INSTR_ALIGNMENT=2, fence=0, fencei=1, fencevmal=2, fencevmau=3, MUL_LEN=64};
|
||||
|
||||
constexpr static unsigned FP_REGS_SIZE = 0;
|
||||
|
||||
|
43
incl/iss/arch/tgc_mapper.h
Normal file
43
incl/iss/arch/tgc_mapper.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef _ISS_ARCH_TGC_MAPPER_H
|
||||
#define _ISS_ARCH_TGC_MAPPER_H
|
||||
|
||||
#include "riscv_hart_m_p.h"
|
||||
#include "tgc_c.h"
|
||||
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
|
||||
#ifdef CORE_TGC_B
|
||||
#include "riscv_hart_m_p.h"
|
||||
#include "tgc_b.h"
|
||||
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_C_XRB_NN
|
||||
#include "riscv_hart_m_p.h"
|
||||
#include "tgc_c_xrb_nn.h"
|
||||
using tgc_c_xrb_nn_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c_xrb_nn>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D
|
||||
#include "riscv_hart_mu_p.h"
|
||||
#include "tgc_d.h"
|
||||
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_MAC
|
||||
#include "riscv_hart_mu_p.h"
|
||||
#include "tgc_d_xrb_mac.h"
|
||||
using tgc_d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_mac, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_NN
|
||||
#include "riscv_hart_mu_p.h"
|
||||
#include "tgc_d_xrb_nn.h"
|
||||
using tgc_d_xrb_nn_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_nn, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_E
|
||||
#include "riscv_hart_mu_p.h"
|
||||
#include "tgc_e.h"
|
||||
using tgc_e_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_e, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_X
|
||||
#include "riscv_hart_mu_p.h"
|
||||
#include "tgc_x.h"
|
||||
using tgc_x_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_x, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N | iss::arch::FEAT_TCM)>;
|
||||
#endif
|
||||
|
||||
#endif
|
@ -214,12 +214,26 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::write_registers(cons
|
||||
auto start_reg=arch::traits<ARCH>::X0;
|
||||
auto *reg_base = core->get_regs_base_ptr();
|
||||
auto iter = data.data();
|
||||
bool e_ext = arch::traits<ARCH>::PC<32;
|
||||
for (size_t reg_no = 0; reg_no < start_reg+33/*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
|
||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
|
||||
auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
|
||||
std::copy(iter, iter + reg_width, reg_base);
|
||||
iter += 4;
|
||||
reg_base += offset;
|
||||
if(e_ext && reg_no>15){
|
||||
if(reg_no==32){
|
||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[arch::traits<ARCH>::PC] / 8;
|
||||
auto offset = traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC];
|
||||
std::copy(iter, iter + reg_width, reg_base);
|
||||
} else {
|
||||
const uint64_t zero_val=0;
|
||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[15] / 8;
|
||||
auto iter = (uint8_t*)&zero_val;
|
||||
std::copy(iter, iter + reg_width, reg_base);
|
||||
}
|
||||
} else {
|
||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
|
||||
auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
|
||||
std::copy(iter, iter + reg_width, reg_base);
|
||||
iter += 4;
|
||||
reg_base += offset;
|
||||
}
|
||||
}
|
||||
return Ok;
|
||||
}
|
||||
|
42
src/main.cpp
42
src/main.cpp
@ -35,46 +35,14 @@
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include "iss/arch/riscv_hart_m_p.h"
|
||||
#include "iss/arch/tgc_c.h"
|
||||
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
|
||||
#ifdef CORE_TGC_B
|
||||
#include "iss/arch/riscv_hart_m_p.h"
|
||||
#include "iss/arch/tgc_b.h"
|
||||
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_C_XRB_NN
|
||||
#include "iss/arch/riscv_hart_m_p.h"
|
||||
#include "iss/arch/tgc_c_xrb_nn.h"
|
||||
using tgc_c_xrb_nn_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c_xrb_nn>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D
|
||||
#include "iss/arch/riscv_hart_mu_p.h"
|
||||
#include "iss/arch/tgc_d.h"
|
||||
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_MAC
|
||||
#include "iss/arch/riscv_hart_mu_p.h"
|
||||
#include "iss/arch/tgc_d_xrb_mac.h"
|
||||
using tgc_d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_mac, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_NN
|
||||
#include "iss/arch/riscv_hart_mu_p.h"
|
||||
#include "iss/arch/tgc_d_xrb_nn.h"
|
||||
using tgc_d_xrb_nn_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_nn, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_E
|
||||
#include "iss/arch/riscv_hart_mu_p.h"
|
||||
#include "iss/arch/tgc_e.h"
|
||||
using tgc_e_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_e, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
|
||||
#endif
|
||||
#include <iss/arch/tgc_mapper.h>
|
||||
#ifdef WITH_LLVM
|
||||
#include <iss/llvm/jit_helper.h>
|
||||
#endif
|
||||
#include <iss/log_categories.h>
|
||||
#include <iss/plugin/cycle_estimate.h>
|
||||
#include <iss/plugin/instruction_count.h>
|
||||
#include <iss/plugin/pctrace.h>
|
||||
#include <iss/plugin/loader.h>
|
||||
#if defined(HAS_LUA)
|
||||
#include <iss/plugin/lua.h>
|
||||
@ -208,7 +176,11 @@ int main(int argc, char *argv[]) {
|
||||
auto *ce_plugin = new iss::plugin::cycle_estimate(filename);
|
||||
vm->register_plugin(*ce_plugin);
|
||||
plugin_list.push_back(ce_plugin);
|
||||
} else {
|
||||
} else if (plugin_name == "pctrace") {
|
||||
auto *plugin = new iss::plugin::cov(filename);
|
||||
vm->register_plugin(*plugin);
|
||||
plugin_list.push_back(plugin);
|
||||
} else {
|
||||
std::array<char const*, 1> a{{filename.c_str()}};
|
||||
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
|
||||
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
|
||||
|
@ -31,37 +31,15 @@
|
||||
*******************************************************************************/
|
||||
|
||||
// clang-format off
|
||||
#include "iss/debugger/gdb_session.h"
|
||||
#include "iss/debugger/encoderdecoder.h"
|
||||
#include "iss/debugger/server.h"
|
||||
#include "iss/debugger/target_adapter_if.h"
|
||||
#include "iss/iss.h"
|
||||
#include "iss/vm_types.h"
|
||||
#include <iss/debugger/gdb_session.h>
|
||||
#include <iss/debugger/encoderdecoder.h>
|
||||
#include <iss/debugger/server.h>
|
||||
#include <iss/debugger/target_adapter_if.h>
|
||||
#include <iss/iss.h>
|
||||
#include <iss/vm_types.h>
|
||||
#include <iss/plugin/loader.h>
|
||||
#include "sysc/core_complex.h"
|
||||
#ifdef CORE_TGC_B
|
||||
#include "iss/arch/riscv_hart_m_p.h"
|
||||
#include "iss/arch/tgc_b.h"
|
||||
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
|
||||
#endif
|
||||
#include "iss/arch/riscv_hart_m_p.h"
|
||||
#include "iss/arch/tgc_c.h"
|
||||
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
|
||||
#ifdef CORE_TGC_D
|
||||
#include "iss/arch/riscv_hart_mu_p.h"
|
||||
#include "iss/arch/tgc_d.h"
|
||||
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, iss::arch::FEAT_PMP>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_MAC
|
||||
#include "iss/arch/riscv_hart_mu_p.h"
|
||||
#include "iss/arch/tgc_d_xrb_mac.h"
|
||||
using tgc_d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_mac, iss::arch::FEAT_PMP>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D_XRB_NN
|
||||
#include "iss/arch/riscv_hart_mu_p.h"
|
||||
#include "iss/arch/tgc_d_xrb_nn.h"
|
||||
using tgc_d_xrb_nn_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_nn, iss::arch::FEAT_PMP>;
|
||||
#endif
|
||||
#include <sysc/core_complex.h>
|
||||
#include <iss/arch/tgc_mapper.h>
|
||||
#include <scc/report.h>
|
||||
#include <util/ities.h>
|
||||
#include <iostream>
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user