implements and fixes CLIC CSR behavior

This commit is contained in:
Eyck Jentzsch 2023-03-17 09:09:09 +01:00
parent a943dd3bdf
commit 39b2788b7e
3 changed files with 43 additions and 14 deletions

View File

@ -221,6 +221,7 @@ struct vm_info {
struct feature_config {
uint64_t clic_base{0xc0000000};
unsigned clic_int_ctl_bits{4};
unsigned clic_num_irq{16};
unsigned clic_num_trigger{0};
uint64_t tcm_base{0x10000000};

View File

@ -289,6 +289,8 @@ protected:
uint32_t raw;
};
std::vector<clic_int_reg_t> clic_int_reg;
uint8_t clic_mprev_lvl{0};
uint8_t clic_mact_lvl{0};
std::vector<uint8_t> tcm;
@ -430,6 +432,8 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p(feature_config cfg)
clic_int_reg.resize(cfg.clic_num_irq, clic_int_reg_t{.raw=0});
clic_cfg_reg=0x20;
clic_info_reg = (/*CLICINTCTLBITS*/ 4U<<21) + cfg.clic_num_irq;
clic_mact_lvl = clic_mprev_lvl = (1<<(cfg.clic_int_ctl_bits)) - 1;
csr[mintthresh] = (1<<(cfg.clic_int_ctl_bits)) - 1;
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);});
@ -869,18 +873,26 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cause(unsigned addr, reg_t &val) {
auto res = csr[addr];
if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec]&0x3)==3) {
res |= state.mstatus.MPIE<<27;
res |= state.mstatus.MPP<<28;
}
val=res;
val = csr[addr] & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1) | (0xfUL<<16));
val |= clic_mprev_lvl<<16;
val |= state.mstatus.MPIE<<27;
val |= state.mstatus.MPP<<28;
} else
val = csr[addr] & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1));
return iss::Ok;
}
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
csr[addr] = val & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1));
if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec]&0x3)==3) {
auto mask = ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1) | (0xfUL<<16));
csr[addr] = (val & mask) | (csr[addr] & ~mask);
clic_mprev_lvl = ((val>>16)&0xff) | (1<<(8-cfg. clic_int_ctl_bits)) - 1;
state.mstatus.MPIE=(val>>27)&0x1;
state.mstatus.MPP=(val>>28)&0x3;
} else {
auto mask = ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1));
csr[addr] = (val & mask) | (csr[addr] & ~mask);
}
return iss::Ok;
}
@ -955,7 +967,7 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
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;
csr[addr]= (val &0xff) | (1<<(cfg.clic_int_ctl_bits)) - 1;
return iss::Ok;
}
@ -1107,6 +1119,7 @@ template <typename BASE, features_e FEAT> inline void riscv_hart_m_p<BASE, FEAT>
}
template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check_interrupt() {
//TODO: Implement CLIC functionality
//auto ideleg = csr[mideleg];
// Multiple simultaneous interrupts and traps at the same privilege level are
// handled in the following decreasing priority order:

View File

@ -304,6 +304,8 @@ protected:
uint32_t raw;
};
std::vector<clic_int_reg_t> clic_int_reg;
uint8_t clic_mprev_lvl{0}, clic_uprev_lvl{0};
uint8_t clic_mact_lvl{0}, clic_uact_lvl{0};
std::vector<uint8_t> tcm;
@ -486,6 +488,10 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
clic_int_reg.resize(cfg.clic_num_irq, clic_int_reg_t{.raw=0});
clic_cfg_reg=0x30;
clic_info_reg = (/*CLICINTCTLBITS*/ 4U<<21) + cfg.clic_num_irq;
clic_mact_lvl = clic_mprev_lvl = (1<<(cfg.clic_int_ctl_bits)) - 1;
clic_uact_lvl = clic_uprev_lvl = (1<<(cfg.clic_int_ctl_bits)) - 1;
csr[mintthresh] = (1<<(cfg.clic_int_ctl_bits)) - 1;
csr[uintthresh] = (1<<(cfg.clic_int_ctl_bits)) - 1;
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);});
@ -715,7 +721,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
return iss::Err;
}
try {
if(!is_debug(access) && (addr&(alignment-1))){
if(!is_debug(access) && (addr&(alignment-1))){
this->trap_state = (1UL << 31) | 4<<16;
fault_data=addr;
return iss::Err;
@ -1026,36 +1032,44 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
}
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_cause(unsigned addr, reg_t &val) {
auto res = csr[addr];
if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec]&0x3)==3) {
val = csr[addr] & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1) | (0xfUL<<16));
auto mode = (addr >> 8) & 0x3;
switch(mode) {
case 0:
res |= state.mstatus.UPIE<<27;
val |= clic_uprev_lvl<<16;
val |= state.mstatus.UPIE<<27;
break;
default:
res |= state.mstatus.MPIE<<27;
res |= state.mstatus.MPP<<28;
val |= clic_mprev_lvl<<16;
val |= state.mstatus.MPIE<<27;
val |= state.mstatus.MPP<<28;
break;
}
}
val=res;
} else
val = csr[addr] & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1));
return iss::Ok;
}
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
csr[addr] = val & ((1UL<<(traits<BASE>::XLEN-1))|(mcause_max_irq-1));
if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec]&0x3)==3) {
auto mask = ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1) | (0xfUL<<16));
csr[addr] = (val & mask) | (csr[addr] & ~mask);
auto mode = (addr >> 8) & 0x3;
switch(mode) {
case 0:
clic_uprev_lvl = ((val>>16)&0xff) | (1<<(8-cfg. clic_int_ctl_bits)) - 1;
state.mstatus.UPIE=(val>>27)&0x1;
break;
default:
clic_mprev_lvl = ((val>>16)&0xff) | (1<<(8-cfg. clic_int_ctl_bits)) - 1;
state.mstatus.MPIE=(val>>27)&0x1;
state.mstatus.MPP=(val>>28)&0x3;
break;
}
} else {
auto mask = ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1));
csr[addr] = (val & mask) | (csr[addr] & ~mask);
}
return iss::Ok;
}
@ -1146,7 +1160,7 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
template<typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, FEAT>::write_intthresh(unsigned addr, reg_t val) {
csr[addr]= val &0xff;
csr[addr]= (val &0xff) | (1<<(cfg.clic_int_ctl_bits)) - 1;
return iss::Ok;
}
@ -1298,6 +1312,7 @@ template <typename BASE, features_e FEAT> inline void riscv_hart_mu_p<BASE, FEAT
}
template <typename BASE, features_e FEAT> void riscv_hart_mu_p<BASE, FEAT>::check_interrupt() {
//TODO: Implement CLIC functionality
auto ideleg = csr[mideleg];
// Multiple simultaneous interrupts and traps at the same privilege level are
// handled in the following decreasing priority order: