add TCM
This commit is contained in:
parent
b0cb997009
commit
6ea7721961
|
@ -43,7 +43,7 @@ namespace arch {
|
||||||
|
|
||||||
enum { tohost_dflt = 0xF0001000, fromhost_dflt = 0xF0001040 };
|
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 {
|
enum riscv_csr {
|
||||||
/* user-level CSR */
|
/* user-level CSR */
|
||||||
|
@ -239,6 +239,49 @@ public:
|
||||||
trap_store_page_fault(uint64_t badaddr)
|
trap_store_page_fault(uint64_t badaddr)
|
||||||
: trap_access(15 << 16, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,8 @@ public:
|
||||||
|
|
||||||
using rd_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 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
|
// primary template
|
||||||
template <class T, class Enable = void> struct hart_state {};
|
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<clic_int_reg_t> clic_int_reg;
|
||||||
|
|
||||||
|
std::vector<uint8_t> tcm;
|
||||||
|
|
||||||
iss::status read_csr_reg(unsigned addr, reg_t &val);
|
iss::status read_csr_reg(unsigned addr, reg_t &val);
|
||||||
iss::status write_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);
|
iss::status read_null(unsigned addr, reg_t &val);
|
||||||
|
@ -337,6 +341,10 @@ protected:
|
||||||
|
|
||||||
void check_interrupt();
|
void check_interrupt();
|
||||||
bool pmp_check(const access_type type, const uint64_t addr, const unsigned len);
|
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};
|
uint64_t clic_base_addr{0};
|
||||||
unsigned clic_num_irq{0};
|
unsigned clic_num_irq{0};
|
||||||
unsigned clic_num_trigger{0};
|
unsigned clic_num_trigger{0};
|
||||||
|
@ -407,10 +415,52 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p()
|
||||||
csr_rd_cb[mie] = &this_class::read_ie;
|
csr_rd_cb[mie] = &this_class::read_ie;
|
||||||
csr_wr_cb[mie] = &this_class::write_ie;
|
csr_wr_cb[mie] = &this_class::write_ie;
|
||||||
csr_rd_cb[mhartid] = &this_class::read_hartid;
|
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_wr_cb[misa] = &this_class::write_null;
|
csr_wr_cb[misa] = &this_class::write_null;
|
||||||
csr_wr_cb[mvendorid] = &this_class::write_null;
|
csr_wr_cb[mvendorid] = &this_class::write_null;
|
||||||
csr_wr_cb[marchid] = &this_class::write_null;
|
csr_wr_cb[marchid] = &this_class::write_null;
|
||||||
csr_wr_cb[mimpid] = &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){
|
if(FEAT & FEAT_DEBUG){
|
||||||
csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
|
csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
|
||||||
csr_rd_cb[dscratch0] = &this_class::read_dcsr_reg;
|
csr_rd_cb[dscratch0] = &this_class::read_dcsr_reg;
|
||||||
|
@ -489,6 +539,20 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
|
||||||
throw std::runtime_error("memory load file not found");
|
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>
|
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,
|
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) {
|
const uint64_t addr, const unsigned length, uint8_t *const data) {
|
||||||
|
@ -517,9 +581,20 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
||||||
fault_data=addr;
|
fault_data=addr;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
auto res = type==iss::address_type::PHYSICAL?
|
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||||
read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
|
auto res = iss::Err;
|
||||||
read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), 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);
|
||||||
|
}
|
||||||
if (unlikely(res != iss::Ok)){
|
if (unlikely(res != iss::Ok)){
|
||||||
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||||
fault_data=addr;
|
fault_data=addr;
|
||||||
|
@ -594,14 +669,25 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
try {
|
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;
|
this->reg.trap_state = 1<<31 | 6<<16;
|
||||||
fault_data=addr;
|
fault_data=addr;
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
}
|
}
|
||||||
auto res = type==iss::address_type::PHYSICAL?
|
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||||
write_mem(phys_addr_t{access, space, addr}, length, data):
|
auto res = iss::Err;
|
||||||
write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), 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_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)) {
|
if (unlikely(res != iss::Ok)) {
|
||||||
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||||
fault_data=addr;
|
fault_data=addr;
|
||||||
|
@ -874,6 +960,12 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||||
return iss::Ok;
|
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>
|
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) {
|
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);
|
if(mem_read_cb) return mem_read_cb(paddr, length, data);
|
||||||
|
@ -977,6 +1069,42 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le
|
||||||
return iss::Ok;
|
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) {
|
template <typename BASE, features_e FEAT> inline void riscv_hart_m_p<BASE, FEAT>::reset(uint64_t address) {
|
||||||
BASE::reset(address);
|
BASE::reset(address);
|
||||||
state.mstatus = hart_state_type::mstatus_reset_val;
|
state.mstatus = hart_state_type::mstatus_reset_val;
|
||||||
|
|
|
@ -99,6 +99,8 @@ public:
|
||||||
|
|
||||||
using rd_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 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
|
// primary template
|
||||||
template <class T, class Enable = void> struct hart_state {};
|
template <class T, class Enable = void> struct hart_state {};
|
||||||
|
@ -309,6 +311,8 @@ protected:
|
||||||
};
|
};
|
||||||
std::vector<clic_int_reg_t> clic_int_reg;
|
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 read_csr_reg(unsigned addr, reg_t &val);
|
||||||
iss::status write_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);
|
iss::status read_null(unsigned addr, reg_t &val);
|
||||||
|
@ -355,6 +359,10 @@ protected:
|
||||||
|
|
||||||
void check_interrupt();
|
void check_interrupt();
|
||||||
bool pmp_check(const access_type type, const uint64_t addr, const unsigned len);
|
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};
|
uint64_t clic_base_addr{0};
|
||||||
unsigned clic_num_irq{0};
|
unsigned clic_num_irq{0};
|
||||||
unsigned clic_num_trigger{0};
|
unsigned clic_num_trigger{0};
|
||||||
|
@ -483,6 +491,23 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p()
|
||||||
clic_cfg_reg=0x20;
|
clic_cfg_reg=0x20;
|
||||||
clic_info_reg = (/*CLICINTCTLBITS*/ 4U<<21) + clic_num_irq;
|
clic_info_reg = (/*CLICINTCTLBITS*/ 4U<<21) + clic_num_irq;
|
||||||
mcause_max_irq=clic_num_irq+16;
|
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){
|
if(FEAT & FEAT_DEBUG){
|
||||||
csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
|
csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
|
||||||
|
@ -562,6 +587,20 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
|
||||||
throw std::runtime_error("memory load file not found");
|
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>
|
template<typename BASE, features_e FEAT>
|
||||||
inline iss::status riscv_hart_mu_p<BASE, FEAT>::write_pmpcfg_reg(unsigned addr, reg_t val) {
|
inline iss::status riscv_hart_mu_p<BASE, FEAT>::write_pmpcfg_reg(unsigned addr, reg_t val) {
|
||||||
csr[addr] = val & 0x9f9f9f9f;
|
csr[addr] = val & 0x9f9f9f9f;
|
||||||
|
@ -688,8 +727,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 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;
|
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
|
if(access != access_type::FETCH && memfn_range.size()){
|
||||||
res = read_clic(phys_addr.val, length, data);
|
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 {
|
} else {
|
||||||
res = read_mem( phys_addr, length, data);
|
res = read_mem( phys_addr, length, data);
|
||||||
}
|
}
|
||||||
|
@ -781,8 +827,19 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||||
return iss::Err;
|
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 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
|
auto res = iss::Err;
|
||||||
write_clic(phys_addr.val, length, data) : write_mem( phys_addr, 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_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)) {
|
if (unlikely(res != iss::Ok)) {
|
||||||
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||||
fault_data=addr;
|
fault_data=addr;
|
||||||
|
@ -1111,8 +1168,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
|
||||||
case 0x10023000: // UART1 base, TXFIFO reg
|
case 0x10023000: // UART1 base, TXFIFO reg
|
||||||
uart_buf << (char)data[0];
|
uart_buf << (char)data[0];
|
||||||
if (((char)data[0]) == '\n' || data[0] == 0) {
|
if (((char)data[0]) == '\n' || data[0] == 0) {
|
||||||
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
|
LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send '"<<uart_buf.str()<<"'";
|
||||||
// '"<<uart_buf.str()<<"'";
|
|
||||||
std::cout << uart_buf.str();
|
std::cout << uart_buf.str();
|
||||||
uart_buf.str("");
|
uart_buf.str("");
|
||||||
}
|
}
|
||||||
|
@ -1181,61 +1237,19 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
|
||||||
return iss::Ok;
|
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>
|
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) {
|
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==clic_base_addr) { // cliccfg
|
||||||
*data=clic_cfg_reg;
|
*data=clic_cfg_reg;
|
||||||
for(auto i=1; i<length; ++i) *(data+i)=0;
|
for(auto i=1; i<length; ++i) *(data+i)=0;
|
||||||
} else if(addr>=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+8)){ // clicinfo
|
} else if(addr>=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+8)){ // clicinfo
|
||||||
read_uint32(addr, clic_info_reg, data, length);
|
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
|
} else if(addr>=(clic_base_addr+0x40) && (addr+length)<=(clic_base_addr+0x40+clic_num_trigger*4)){ // clicinttrig
|
||||||
auto offset = ((addr&0x7fff)-0x40)/4;
|
auto offset = ((addr&0x7fff)-0x40)/4;
|
||||||
read_uint32(addr, clic_inttrig_reg[offset], data, length);
|
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
|
} 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;
|
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 {
|
} else {
|
||||||
for(auto i = 0U; i<length; ++i) *(data+i)=0;
|
for(auto i = 0U; i<length; ++i) *(data+i)=0;
|
||||||
}
|
}
|
||||||
|
@ -1251,10 +1265,10 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned leng
|
||||||
// write_uint32(addr, clic_info_reg, data, length);
|
// 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>=(clic_base_addr+0x40) && (addr+length)<=(clic_base_addr+0xC0)){ // clicinttrig
|
||||||
auto offset = ((addr&0x7fff)-0x40)/4;
|
auto offset = ((addr&0x7fff)-0x40)/4;
|
||||||
write_uint32(addr, clic_inttrig_reg[offset], data, length);
|
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
|
} 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;
|
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;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ using tgc_e_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_e, (iss::arch:
|
||||||
#ifdef CORE_TGC_X
|
#ifdef CORE_TGC_X
|
||||||
#include "riscv_hart_mu_p.h"
|
#include "riscv_hart_mu_p.h"
|
||||||
#include "tgc_x.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)>;
|
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
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue