From 6ea772196149a37c568f761a8851565622a1b9e3 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Sun, 27 Mar 2022 15:38:18 +0200 Subject: [PATCH] add TCM --- incl/iss/arch/riscv_hart_common.h | 45 ++++++++- incl/iss/arch/riscv_hart_m_p.h | 146 ++++++++++++++++++++++++++++-- incl/iss/arch/riscv_hart_mu_p.h | 124 ++++++++++++++----------- incl/iss/arch/tgc_mapper.h | 2 +- 4 files changed, 251 insertions(+), 66 deletions(-) diff --git a/incl/iss/arch/riscv_hart_common.h b/incl/iss/arch/riscv_hart_common.h index ffe87bc..8f79290 100644 --- a/incl/iss/arch/riscv_hart_common.h +++ b/incl/iss/arch/riscv_hart_common.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 */ @@ -239,6 +239,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(®); + 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(®); + 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; + } +} + } } diff --git a/incl/iss/arch/riscv_hart_m_p.h b/incl/iss/arch/riscv_hart_m_p.h index b55625c..4405b28 100644 --- a/incl/iss/arch/riscv_hart_m_p.h +++ b/incl/iss/arch/riscv_hart_m_p.h @@ -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 struct hart_state {}; @@ -294,6 +296,8 @@ protected: }; std::vector clic_int_reg; + std::vector 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); @@ -337,6 +341,10 @@ protected: void check_interrupt(); bool pmp_check(const access_type type, const uint64_t addr, const unsigned len); + std::vector> memfn_range; + std::vector> memfn_read; + std::vector> memfn_write; + void insert_mem_range(uint64_t, uint64_t, std::function, std::function); uint64_t clic_base_addr{0}; unsigned clic_num_irq{0}; unsigned clic_num_trigger{0}; @@ -407,10 +415,52 @@ riscv_hart_m_p::riscv_hart_m_p() csr_rd_cb[mie] = &this_class::read_ie; csr_wr_cb[mie] = &this_class::write_ie; csr_rd_cb[mhartid] = &this_class::read_hartid; + csr_rd_cb[mcounteren] = &this_class::read_null; + csr_wr_cb[mcounteren] = &this_class::write_null; csr_wr_cb[misa] = &this_class::write_null; 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 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 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; @@ -489,6 +539,20 @@ template std::pair riscv_hart_m throw std::runtime_error("memory load file not found"); } +template +inline void riscv_hart_m_p::insert_mem_range(uint64_t base, uint64_t size, std::function rd_f, + std::function wr_fn) { + std::tuple entry{base, size}; + auto it = std::upper_bound( memfn_range.begin(), memfn_range.end(), entry, + [](std::tuple const& a, std::tuple const& b){ + return std::get<0>(a)(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 iss::status riscv_hart_m_p::read(const address_type type, const access_type access, const uint32_t space, const uint64_t addr, const unsigned length, uint8_t *const data) { @@ -517,9 +581,20 @@ iss::status riscv_hart_m_p::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 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; @@ -594,14 +669,25 @@ iss::status riscv_hart_m_p::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 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; @@ -874,6 +960,12 @@ template iss::status riscv_hart_m_p return iss::Ok; } +template +iss::status riscv_hart_m_p::write_intthresh(unsigned addr, reg_t val) { + csr[addr]= val &0xff; + return iss::Ok; +} + template iss::status riscv_hart_m_p::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { if(mem_read_cb) return mem_read_cb(paddr, length, data); @@ -977,6 +1069,42 @@ iss::status riscv_hart_m_p::write_mem(phys_addr_t paddr, unsigned le return iss::Ok; } +template +iss::status riscv_hart_m_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+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 +iss::status riscv_hart_m_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&= 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 inline void riscv_hart_m_p::reset(uint64_t address) { BASE::reset(address); state.mstatus = hart_state_type::mstatus_reset_val; diff --git a/incl/iss/arch/riscv_hart_mu_p.h b/incl/iss/arch/riscv_hart_mu_p.h index aafd204..722e221 100644 --- a/incl/iss/arch/riscv_hart_mu_p.h +++ b/incl/iss/arch/riscv_hart_mu_p.h @@ -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 struct hart_state {}; @@ -309,6 +311,8 @@ protected: }; std::vector clic_int_reg; + std::vector 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); @@ -355,6 +359,10 @@ protected: void check_interrupt(); bool pmp_check(const access_type type, const uint64_t addr, const unsigned len); + std::vector> memfn_range; + std::vector> memfn_read; + std::vector> memfn_write; + void insert_mem_range(uint64_t, uint64_t, std::function, std::function); uint64_t clic_base_addr{0}; unsigned clic_num_irq{0}; unsigned clic_num_trigger{0}; @@ -483,6 +491,23 @@ riscv_hart_mu_p::riscv_hart_mu_p() 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 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 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; @@ -562,6 +587,20 @@ template std::pair riscv_hart_m throw std::runtime_error("memory load file not found"); } +template +inline void riscv_hart_mu_p::insert_mem_range(uint64_t base, uint64_t size, std::function rd_f, + std::function wr_fn) { + std::tuple entry{base, size}; + auto it = std::upper_bound( memfn_range.begin(), memfn_range.end(), entry, + [](std::tuple const& a, std::tuple const& b){ + return std::get<0>(a)(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 inline iss::status riscv_hart_mu_p::write_pmpcfg_reg(unsigned addr, reg_t val) { csr[addr] = val & 0x9f9f9f9f; @@ -688,8 +727,15 @@ iss::status riscv_hart_mu_p::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 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); } @@ -781,8 +827,19 @@ iss::status riscv_hart_mu_p::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 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; @@ -1111,8 +1168,7 @@ iss::status riscv_hart_mu_p::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 - // '"<>16)&0x3)<<" send '"<::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+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 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 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::write_clic(uint64_t addr, unsigned leng // 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); + 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_uint32(addr, clic_int_reg[offset].raw, data, length); + write_reg_uint32(addr, clic_int_reg[offset].raw, data, length); } return iss::Ok; } diff --git a/incl/iss/arch/tgc_mapper.h b/incl/iss/arch/tgc_mapper.h index 1d4dd73..7173d7b 100644 --- a/incl/iss/arch/tgc_mapper.h +++ b/incl/iss/arch/tgc_mapper.h @@ -37,7 +37,7 @@ using tgc_e_plat_type = iss::arch::riscv_hart_mu_p; +using tgc_x_plat_type = iss::arch::riscv_hart_mu_p; #endif #endif