4040
4141namespace iss {
4242namespace mem {
43- struct clic_config {
44- uint64_t clic_base{0xc0000000 };
45- unsigned clic_int_ctl_bits{4 };
46- unsigned clic_num_irq{16 };
47- unsigned clic_num_trigger{0 };
48- bool nmode{false };
49- };
50-
51- inline void read_reg_with_offset (uint32_t reg, uint8_t offs, uint8_t * const data, unsigned length) {
52- auto reg_ptr = reinterpret_cast <uint8_t *>(®);
53- switch (offs) {
54- default :
55- for (auto i = 0U ; i < length; ++i)
56- *(data + i) = *(reg_ptr + i);
57- break ;
58- case 1 :
59- for (auto i = 0U ; i < length; ++i)
60- *(data + i) = *(reg_ptr + 1 + i);
61- break ;
62- case 2 :
63- for (auto i = 0U ; i < length; ++i)
64- *(data + i) = *(reg_ptr + 2 + i);
65- break ;
66- case 3 :
67- *data = *(reg_ptr + 3 );
68- break ;
69- }
70- }
71-
72- inline void write_reg_with_offset (uint32_t & reg, uint8_t offs, const uint8_t * const data, unsigned length) {
73- auto reg_ptr = reinterpret_cast <uint8_t *>(®);
74- switch (offs) {
75- default :
76- for (auto i = 0U ; i < length; ++i)
77- *(reg_ptr + i) = *(data + i);
78- break ;
79- case 1 :
80- for (auto i = 0U ; i < length; ++i)
81- *(reg_ptr + 1 + i) = *(data + i);
82- break ;
83- case 2 :
84- for (auto i = 0U ; i < length; ++i)
85- *(reg_ptr + 2 + i) = *(data + i);
86- break ;
87- case 3 :
88- *(reg_ptr + 3 ) = *data;
89- break ;
90- }
91- }
9243
9344template <typename PLAT > struct pmp : public memory_elem {
9445 using this_class = pmp<PLAT >;
9546 using reg_t = typename PLAT ::reg_t ;
47+ static constexpr auto cfg_reg_size = sizeof (reg_t );
48+ static constexpr auto PMP_SHIFT = 2U ;
49+ static constexpr auto PMP_R = 0x1U ;
50+ static constexpr auto PMP_W = 0x2U ;
51+ static constexpr auto PMP_X = 0x4U ;
52+ static constexpr auto PMP_A = 0x18U ;
53+ static constexpr auto PMP_L = 0x80U ;
54+ static constexpr auto PMP_TOR = 0x1U ;
55+ static constexpr auto PMP_NA4 = 0x2U ;
56+ static constexpr auto PMP_NAPOT = 0x3U ;
9657
9758 pmp (arch::priv_if<reg_t > hart_if)
9859 : hart_if(hart_if) {
9960 for (size_t i = arch::pmpaddr0; i <= arch::pmpaddr15; ++i) {
100- hart_if.csr_rd_cb [i] = MK_CSR_RD_CB (read_plain );
101- hart_if.csr_wr_cb [i] = MK_CSR_WR_CB (write_plain );
61+ hart_if.csr_rd_cb [i] = MK_CSR_RD_CB (read_pmpaddr );
62+ hart_if.csr_wr_cb [i] = MK_CSR_WR_CB (write_pmpaddr );
10263 }
10364 for (size_t i = arch::pmpcfg0; i < arch::pmpcfg0 + 16 / sizeof (reg_t ); ++i) {
104- hart_if.csr_rd_cb [i] = MK_CSR_RD_CB (read_plain );
65+ hart_if.csr_rd_cb [i] = MK_CSR_RD_CB (read_pmpcfg );
10566 hart_if.csr_wr_cb [i] = MK_CSR_WR_CB (write_pmpcfg);
10667 }
10768 }
@@ -116,13 +77,16 @@ template <typename PLAT> struct pmp : public memory_elem {
11677 void set_next (memory_if mem) override { down_stream_mem = mem; }
11778
11879private:
80+ std::array<reg_t , 16 > pmpaddr;
81+ std::array<reg_t , 16 / sizeof (reg_t )> pmpcfg;
82+
11983 iss::status read_mem (const addr_t & addr, unsigned length, uint8_t * data) {
12084 assert ((addr.type == iss::address_type::PHYSICAL || is_debug (addr.access )) && " Only physical addresses are expected in pmp" );
121- if (likely (addr.space == arch::traits<PLAT >::MEM ) && ! pmp_check (addr. access , addr. val , length) && ! is_debug (addr. access )) {
122- hart_if. fault_data = addr;
85+ if (likely (addr.space == arch::traits<PLAT >::MEM || std::numeric_limits< decltype ( phys_addr_t ::space)>:: max ( )) &&
86+ ! pmp_check (addr. access , addr. val , length) && ! is_debug ( addr. access )) {
12387 if (is_debug (addr.access ))
12488 throw trap_access (0 , addr.val );
125- hart_if.reg . trap_state = ( 1UL << 31 ) | (( addr.access == access_type::FETCH ? 1 : 5 ) << 16 ); // issue trap 1
89+ hart_if.raise_trap ( /* trap_id */ 0 , /* cause */ ( addr.access == access_type::FETCH ) ? 1 : 5 , /* fault_data */ addr. val );
12690 return iss::Err;
12791 }
12892 return down_stream_mem.rd_mem (addr, length, data);
@@ -131,62 +95,71 @@ template <typename PLAT> struct pmp : public memory_elem {
13195 iss::status write_mem (const addr_t & addr, unsigned length, uint8_t const * data) {
13296 assert ((addr.type == iss::address_type::PHYSICAL || is_debug (addr.access )) && " Only physical addresses are expected in pmp" );
13397 if (likely (addr.space == arch::traits<PLAT >::MEM ) && !pmp_check (addr.access , addr.val , length) && !is_debug (addr.access )) {
134- hart_if.fault_data = addr;
13598 if (is_debug (addr.access ))
13699 throw trap_access (0 , addr.val );
137- hart_if.reg . trap_state = ( 1UL << 31 ) | ( 7 << 16 ); // issue trap 1
100+ hart_if.raise_trap ( /* trap_id */ 0 , /* cause */ 7 , /* fault_data */ addr. val );
138101 return iss::Err;
139102 }
140103 return down_stream_mem.wr_mem (addr, length, data);
141104 }
142105
143- iss::status read_plain (unsigned addr, reg_t & val) {
144- val = hart_if.csr [addr];
145- return iss::Ok;
106+ iss::status read_pmpaddr (unsigned addr, reg_t & val) {
107+ if (addr >= arch::pmpaddr0 && addr <= arch::pmpaddr15) {
108+ val = pmpaddr[addr - arch::pmpaddr0];
109+ return iss::Ok;
110+ }
111+ return iss::Err;
146112 }
147113
148- iss::status write_plain (unsigned addr, reg_t const & val) {
149- hart_if.csr [addr] = val;
150- return iss::Ok;
114+ iss::status write_pmpaddr (unsigned addr, reg_t const & val) {
115+ if (addr >= arch::pmpaddr0 && addr <= arch::pmpaddr15) {
116+ pmpaddr[addr - arch::pmpaddr0] = val;
117+ return iss::Ok;
118+ }
119+ return iss::Err;
151120 }
152121
122+ iss::status read_pmpcfg (unsigned addr, reg_t & val) {
123+ if (addr >= arch::pmpcfg0 && addr < (arch::pmpcfg0 + 16 / sizeof (reg_t ))) {
124+ val = pmpaddr[addr - arch::pmpcfg0];
125+ return iss::Ok;
126+ }
127+ return iss::Err;
128+ }
153129 iss::status write_pmpcfg (unsigned addr, reg_t val) {
154- hart_if.csr [addr] = val & 0x9f9f9f9f ;
155- return iss::Ok;
130+ if (addr >= arch::pmpcfg0 && addr < (arch::pmpcfg0 + 16 / sizeof (reg_t ))) {
131+ pmpaddr[addr - arch::pmpcfg0] = val & 0x9f9f9f9f ;
132+ any_active = false ;
133+ for (size_t i = 0 ; i < 16 ; i++) {
134+ auto cfg = pmpcfg[i / cfg_reg_size] >> (i % cfg_reg_size);
135+ any_active |= cfg & PMP_A ;
136+ }
137+ return iss::Ok;
138+ }
139+ return iss::Err;
156140 }
157141
158- bool pmp_check (const access_type type, const uint64_t addr, const unsigned len);
142+ bool pmp_check (access_type type, uint64_t addr, unsigned len);
159143
160144protected:
145+ bool any_active = false ;
161146 arch::priv_if<reg_t > hart_if;
162147 memory_if down_stream_mem;
163148};
164149
165- template <typename PLAT > bool pmp<PLAT >::pmp_check(const access_type type, const uint64_t addr, const unsigned len) {
166- constexpr auto PMP_SHIFT = 2U ;
167- constexpr auto PMP_R = 0x1U ;
168- constexpr auto PMP_W = 0x2U ;
169- constexpr auto PMP_X = 0x4U ;
170- constexpr auto PMP_A = 0x18U ;
171- constexpr auto PMP_L = 0x80U ;
172- constexpr auto PMP_TOR = 0x1U ;
173- constexpr auto PMP_NA4 = 0x2U ;
174- constexpr auto PMP_NAPOT = 0x3U ;
150+ template <typename PLAT > bool pmp<PLAT >::pmp_check(access_type type, uint64_t addr, unsigned len) {
151+ if (!any_active)
152+ return true ;
175153 reg_t base = 0 ;
176- auto any_active = false ;
177- auto const cfg_reg_size = sizeof (reg_t );
178154 for (size_t i = 0 ; i < 16 ; i++) {
179- reg_t tor = hart_if. csr [arch::pmpaddr0 + i] << PMP_SHIFT ;
180- uint8_t cfg = hart_if. csr [arch::pmpcfg0 + ( i / cfg_reg_size) ] >> (i % cfg_reg_size);
155+ reg_t tor = pmpaddr[ i] << PMP_SHIFT ;
156+ reg_t cfg = pmpcfg[ i / cfg_reg_size] >> (i % cfg_reg_size);
181157 if (cfg & PMP_A ) {
182- any_active = true ;
183158 auto pmp_a = (cfg & PMP_A ) >> 3 ;
184159 auto is_tor = pmp_a == PMP_TOR ;
185160 auto is_na4 = pmp_a == PMP_NA4 ;
186-
187- reg_t mask = (hart_if.csr [arch::pmpaddr0 + i] << 1 ) | (!is_na4);
161+ reg_t mask = (pmpaddr[i] << 1 ) | (!is_na4);
188162 mask = ~(mask & ~(mask + 1 )) << PMP_SHIFT ;
189-
190163 // Check each 4-byte sector of the access
191164 auto any_match = false ;
192165 auto all_match = true ;
@@ -202,7 +175,7 @@ template <typename PLAT> bool pmp<PLAT>::pmp_check(const access_type type, const
202175 // If the PMP matches only a strict subset of the access, fail it
203176 if (!all_match)
204177 return false ;
205- return (hart_if.reg . PRIV == arch::PRIV_M && !(cfg & PMP_L )) || (type == access_type::READ && (cfg & PMP_R )) ||
178+ return (hart_if.PRIV == arch::PRIV_M && !(cfg & PMP_L )) || (type == access_type::READ && (cfg & PMP_R )) ||
206179 (type == access_type::WRITE && (cfg & PMP_W )) || (type == access_type::FETCH && (cfg & PMP_X ));
207180 }
208181 }
@@ -239,7 +212,7 @@ template <typename PLAT> bool pmp<PLAT>::pmp_check(const access_type type, const
239212 // }
240213 // tor_base = pmpaddr;
241214 // }
242- return !any_active || hart_if. reg .PRIV == arch::PRIV_M ;
215+ return hart_if.PRIV == arch::PRIV_M ;
243216}
244217
245218} // namespace mem
0 commit comments