From adeffe47ad09dfdc00502f90b1863ac01d6db3c6 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Thu, 12 Aug 2021 20:34:10 +0200 Subject: [PATCH] fix behavior of riscv_hart_mu_p to match TGC_D --- gen_input/CoreDSL-Instruction-Set-Description | 2 +- incl/iss/arch/riscv_hart_mu_p.h | 264 +++++++++++++----- 2 files changed, 201 insertions(+), 65 deletions(-) diff --git a/gen_input/CoreDSL-Instruction-Set-Description b/gen_input/CoreDSL-Instruction-Set-Description index 98cddb2..8d9a0fb 160000 --- a/gen_input/CoreDSL-Instruction-Set-Description +++ b/gen_input/CoreDSL-Instruction-Set-Description @@ -1 +1 @@ -Subproject commit 98cddb2999bfc05862a796b157500f7cd0f36ca4 +Subproject commit 8d9a0fb1493b762014c330c71ac8cef96753d302 diff --git a/incl/iss/arch/riscv_hart_mu_p.h b/incl/iss/arch/riscv_hart_mu_p.h index 457d64e..c59de82 100644 --- a/incl/iss/arch/riscv_hart_mu_p.h +++ b/incl/iss/arch/riscv_hart_mu_p.h @@ -183,10 +183,10 @@ public: }; using hart_state_type = hart_state; - constexpr reg_t get_irq_mask(size_t mode) { + constexpr reg_t get_irq_wrmask(size_t mode) { std::array m = {{ 0b000100010001, // U mode - 0, // S mode + 0b001100110011, // S mode 0, 0b100110011001 // M mode }}; @@ -263,6 +263,9 @@ protected: virtual iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data); virtual iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data); + iss::status read_clic(uint64_t addr, unsigned length, uint8_t *const data); + iss::status write_clic(uint64_t addr, unsigned length, const uint8_t *const data); + virtual iss::status read_csr(unsigned addr, reg_t &val); virtual iss::status write_csr(unsigned addr, reg_t val); @@ -287,10 +290,23 @@ protected: std::unordered_map atomic_reservation; std::unordered_map csr_rd_cb; std::unordered_map csr_wr_cb; + uint8_t clic_cfg_reg{0}; + uint32_t clic_info_reg{0}; + std::array clic_inttrig_reg; + union clic_int_reg_t { + struct{ + uint8_t ip; + uint8_t ie; + uint8_t attr; + uint8_t ctl; + }; + uint32_t raw; + }; + std::vector clic_int_reg; private: - iss::status read_reg(unsigned addr, reg_t &val); - iss::status write_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 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); @@ -306,8 +322,11 @@ 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 write_ideleg(unsigned addr, reg_t val); + iss::status write_edeleg(unsigned addr, reg_t val); iss::status read_hartid(unsigned addr, reg_t &val); iss::status write_epc(unsigned addr, reg_t val); + iss::status write_intthresh(unsigned addr, reg_t val); reg_t mhartid_reg{0x0}; std::functionmem_read_cb; @@ -316,6 +335,10 @@ private: protected: 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}; + unsigned mcause_max_irq{16}; }; template @@ -332,22 +355,22 @@ riscv_hart_mu_p::riscv_hart_mu_p() uart_buf.str(""); for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){ csr_rd_cb[addr] = &this_class::read_null; - csr_wr_cb[addr] = &this_class::write_reg; + csr_wr_cb[addr] = &this_class::write_csr_reg; } for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){ csr_rd_cb[addr] = &this_class::read_null; - csr_wr_cb[addr] = &this_class::write_reg; + csr_wr_cb[addr] = &this_class::write_csr_reg; } for (unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr){ csr_rd_cb[addr] = &this_class::read_null; - csr_wr_cb[addr] = &this_class::write_reg; + csr_wr_cb[addr] = &this_class::write_csr_reg; } for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){ csr_rd_cb[addr] = &this_class::read_null; } for (unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr){ csr_rd_cb[addr] = &this_class::read_null; - //csr_wr_cb[addr] = &this_class::write_reg; + //csr_wr_cb[addr] = &this_class::write_csr_reg; } // common regs const std::array addrs{{ @@ -356,8 +379,8 @@ riscv_hart_mu_p::riscv_hart_mu_p() uepc, utvec, uscratch, ucause, utval, }}; for(auto addr: addrs) { - csr_rd_cb[addr] = &this_class::read_reg; - csr_wr_cb[addr] = &this_class::write_reg; + csr_rd_cb[addr] = &this_class::read_csr_reg; + csr_wr_cb[addr] = &this_class::write_csr_reg; } // special handling & overrides csr_rd_cb[time] = &this_class::read_time; @@ -378,21 +401,12 @@ riscv_hart_mu_p::riscv_hart_mu_p() csr_rd_cb[mstatus] = &this_class::read_status; csr_wr_cb[mstatus] = &this_class::write_status; csr_wr_cb[mcause] = &this_class::write_cause; - csr_rd_cb[ustatus] = &this_class::read_status; - csr_wr_cb[ustatus] = &this_class::write_status; - csr_wr_cb[ucause] = &this_class::write_cause; csr_rd_cb[mtvec] = &this_class::read_tvec; - csr_rd_cb[utvec] = &this_class::read_tvec; csr_wr_cb[mepc] = &this_class::write_epc; - csr_wr_cb[uepc] = &this_class::write_epc; csr_rd_cb[mip] = &this_class::read_ip; csr_wr_cb[mip] = &this_class::write_ip; - csr_rd_cb[uip] = &this_class::read_ip; - csr_wr_cb[uip] = &this_class::write_ip; csr_rd_cb[mie] = &this_class::read_ie; csr_wr_cb[mie] = &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; csr_rd_cb[mcounteren] = &this_class::read_null; csr_wr_cb[mcounteren] = &this_class::write_null; @@ -403,35 +417,51 @@ riscv_hart_mu_p::riscv_hart_mu_p() if(FEAT & FEAT_PMP){ for(size_t i=pmpaddr0; i<=pmpaddr15; ++i){ - csr_rd_cb[i] = &this_class::read_reg; - csr_wr_cb[i] = &this_class::write_reg; + csr_rd_cb[i] = &this_class::read_csr_reg; + csr_wr_cb[i] = &this_class::write_csr_reg; } for(size_t i=pmpcfg0; i<=pmpcfg3; ++i){ - csr_rd_cb[i] = &this_class::read_reg; - csr_wr_cb[i] = &this_class::write_reg; + csr_rd_cb[i] = &this_class::read_csr_reg; + csr_wr_cb[i] = &this_class::write_csr_reg; } } if(FEAT & FEAT_EXT_N){ - csr_rd_cb[mideleg] = &this_class::read_reg; - csr_wr_cb[mideleg] = &this_class::write_reg; - csr_rd_cb[medeleg] = &this_class::read_reg; - csr_wr_cb[medeleg] = &this_class::write_reg; + csr_rd_cb[mideleg] = &this_class::read_csr_reg; + csr_wr_cb[mideleg] = &this_class::write_ideleg; + csr_rd_cb[medeleg] = &this_class::read_csr_reg; + csr_wr_cb[medeleg] = &this_class::write_edeleg; + csr_rd_cb[uie] = &this_class::read_ie; + csr_wr_cb[uie] = &this_class::write_ie; + csr_rd_cb[uip] = &this_class::read_ip; + csr_wr_cb[uip] = &this_class::write_ip; + csr_wr_cb[uepc] = &this_class::write_epc; + csr_rd_cb[ustatus] = &this_class::read_status; + csr_wr_cb[ustatus] = &this_class::write_status; + csr_wr_cb[ucause] = &this_class::write_cause; + csr_rd_cb[utvec] = &this_class::read_tvec; } if(FEAT & FEAT_CLIC) { - csr_rd_cb[mtvt] = &this_class::read_reg; - csr_wr_cb[mtvt] = &this_class::write_reg; - csr_rd_cb[mxnti] = &this_class::read_reg; - csr_wr_cb[mxnti] = &this_class::write_reg; - csr_rd_cb[mintstatus] = &this_class::read_reg; - csr_wr_cb[mintstatus] = &this_class::write_reg; - csr_rd_cb[mscratchcsw] = &this_class::read_reg; - csr_wr_cb[mscratchcsw] = &this_class::write_reg; - csr_rd_cb[mscratchcswl] = &this_class::read_reg; - csr_wr_cb[mscratchcswl] = &this_class::write_reg; - csr_rd_cb[mintthresh] = &this_class::read_reg; - csr_wr_cb[mintthresh] = &this_class::write_reg; - csr_rd_cb[mclicbase] = &this_class::read_reg; + 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_csr_reg; + 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=0x40; + clic_info_reg = (/*CLICINTCTLBITS*/ 4U<<21) + clic_num_irq; + mcause_max_irq=clic_num_irq+16; } } @@ -563,9 +593,13 @@ iss::status riscv_hart_mu_p::read(const address_type type, const acc 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((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); + } 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; @@ -653,9 +687,9 @@ iss::status riscv_hart_mu_p::write(const address_type type, const ac 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 = ((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); if (unlikely(res != iss::Ok)) { this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault) fault_data=addr; @@ -752,7 +786,7 @@ template iss::status riscv_hart_mu_p*(it->second))(addr, val); } -template iss::status riscv_hart_mu_p::read_reg(unsigned addr, reg_t &val) { +template iss::status riscv_hart_mu_p::read_csr_reg(unsigned addr, reg_t &val) { val = csr[addr]; return iss::Ok; } @@ -762,7 +796,7 @@ template iss::status riscv_hart_mu_p iss::status riscv_hart_mu_p::write_reg(unsigned addr, reg_t val) { +template iss::status riscv_hart_mu_p::write_csr_reg(unsigned addr, reg_t val) { csr[addr] = val; return iss::Ok; } @@ -849,13 +883,7 @@ template iss::status riscv_hart_mu_p iss::status riscv_hart_mu_p::write_cause(unsigned addr, reg_t val) { - csr[addr] = val & ((1UL<<(traits::XLEN-1))|0xf); //TODO: make exception code size configurable - return iss::Ok; -} - -template iss::status riscv_hart_mu_p::read_ie(unsigned addr, reg_t &val) { - val = csr[mie]; - val &= csr[mideleg]; + csr[addr] = val & ((1UL<<(traits::XLEN-1))|(mcause_max_irq-1)); //TODO: make exception code size configurable return iss::Ok; } @@ -864,34 +892,64 @@ template iss::status riscv_hart_mu_p iss::status riscv_hart_mu_p::read_ie(unsigned addr, reg_t &val) { + auto mask = get_irq_wrmask((addr >> 8) & 0x3); + val = csr[mie] & mask; + if(this->reg.PRIV!=3) + val &= csr[mideleg]; + return iss::Ok; +} + template iss::status riscv_hart_mu_p::write_ie(unsigned addr, reg_t val) { - auto req_priv_lvl = (addr >> 8) & 0x3; - auto mask = get_irq_mask(req_priv_lvl); + auto mask = get_irq_wrmask((addr >> 8) & 0x3); + if(this->reg.PRIV==0) + mask&= ~(0xff<<4); // STIE and UTIE are read only in user and supervisor mode csr[mie] = (csr[mie] & ~mask) | (val & mask); check_interrupt(); return iss::Ok; } template iss::status riscv_hart_mu_p::read_ip(unsigned addr, reg_t &val) { - val = csr[mip]; - val &= csr[mideleg]; + auto mask = get_irq_wrmask((addr >> 8) & 0x3); + val = csr[mip] & mask; + if(this->reg.PRIV!=3) + val &= csr[mideleg]; return iss::Ok; } template iss::status riscv_hart_mu_p::write_ip(unsigned addr, reg_t val) { - auto req_priv_lvl = (addr >> 8) & 0x3; - auto mask = get_irq_mask(req_priv_lvl); - mask &= ~(1 << 7); // MTIP is read only + auto mask = get_irq_wrmask((addr >> 8) & 0x3); + mask &= ~(8 << 4); // MTIP is read only + if(this->reg.PRIV!=3) + mask &= ~(3 << 4); // STIP and UTIP are read only in user and supervisor mode csr[mip] = (csr[mip] & ~mask) | (val & mask); check_interrupt(); return iss::Ok; } +template iss::status riscv_hart_mu_p::write_ideleg(unsigned addr, reg_t val) { + auto mask = 0b000100010001; // only U mode supported + csr[mideleg] = (csr[mideleg] & ~mask) | (val & mask); + return iss::Ok; +} + +template iss::status riscv_hart_mu_p::write_edeleg(unsigned addr, reg_t val) { + auto mask = 0xf7f7; // bit 11 (Env call) and 3 (break) are hardwired to 0 + csr[medeleg] = (csr[medeleg] & ~mask) | (val & mask); + return iss::Ok; +} + template iss::status riscv_hart_mu_p::write_epc(unsigned addr, reg_t val) { csr[addr] = val & get_pc_mask(); return iss::Ok; } +template +iss::status riscv_hart_mu_p::write_intthresh(unsigned addr, reg_t val) { + csr[addr]= val &0xff; + return iss::Ok; +} + template iss::status riscv_hart_mu_p::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { if(mem_read_cb) return mem_read_cb(paddr, length, data); @@ -995,6 +1053,84 @@ iss::status riscv_hart_mu_p::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(®); + 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(®); + 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 +iss::status riscv_hart_mu_p::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=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+4)){ // 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 + 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 + auto offset = ((addr&0x7fff)-0x1000)/4; + read_uint32(addr, clic_int_reg[offset].raw, data, length); + } else { + for(auto i = 0U; i +iss::status riscv_hart_mu_p::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&= 0x7f; + } 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_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_uint32(addr, clic_int_reg[offset].raw, data, length); + } + return iss::Ok; +} + template inline void riscv_hart_mu_p::reset(uint64_t address) { BASE::reset(address); state.mstatus = hart_state_type::mstatus_reset_val; @@ -1009,7 +1145,7 @@ template void riscv_hart_mu_p::chec auto ena_irq = csr[mip] & csr[mie]; bool mie = state.mstatus.MIE; - auto m_enabled = this->reg.PRIV < PRIV_M || (this->reg.PRIV == PRIV_M && mie); + auto m_enabled = this->reg.PRIV < PRIV_M || mie; auto enabled_interrupts = m_enabled ? ena_irq & ~ideleg : 0; if (enabled_interrupts != 0) { @@ -1078,7 +1214,7 @@ template uint64_t riscv_hart_mu_p:: auto ivec = csr[utvec | (new_priv << 8)]; // 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 = new_priv;