Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 1 | // Copyright lowRISC contributors. |
| 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 3 | // SPDX-License-Identifier: Apache-2.0 |
| 4 | <%! |
| 5 | from reggen import gen_dv |
| 6 | from reggen.access import HwAccess, SwRdAccess, SwWrAccess |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 7 | from reggen.multi_register import MultiRegister |
| 8 | from reggen.register import Register |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 9 | from typing import Dict |
| 10 | |
| 11 | # Get a list reg and its instance name |
| 12 | # For single reg, return Dict[reg_inst:reg] |
| 13 | # For multireg, if it's dv_compact, return Dict[mr.name[idx]:mr.reg], |
| 14 | # if not, return all the mr.regs with their name |
| 15 | def get_inst_to_reg_dict(r) -> Dict: |
| 16 | inst_regs = {} # type: Dict[inst_name:Register] |
| 17 | if isinstance(r, MultiRegister): |
| 18 | if r.dv_compact: |
| 19 | inst_base = r.reg.name.lower() |
| 20 | for idx, reg in enumerate(r.regs): |
Weicai Yang | b146659 | 2021-08-20 16:08:37 -0700 | [diff] [blame] | 21 | inst_name = f'{inst_base}[{idx}]' |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 22 | inst_regs[inst_name] = reg |
| 23 | else: |
| 24 | for r0 in r.regs: |
| 25 | inst_regs[r0.name] = r0 |
| 26 | else: |
| 27 | inst_regs[r.name.lower()] = r |
| 28 | return inst_regs |
| 29 | %>\ |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 30 | ## |
| 31 | ## |
| 32 | ## make_ral_pkg |
| 33 | ## ============ |
| 34 | ## |
| 35 | ## Generate the RAL package for a device interface. |
| 36 | ## |
| 37 | ## dv_base_prefix a string naming the base register type. If it is FOO, |
| 38 | ## then we will inherit from FOO_reg (assumed to |
| 39 | ## be a subclass of uvm_reg). |
| 40 | ## |
| 41 | ## reg_width an integer giving the width of registers in bits |
| 42 | ## |
Rupert Swarbrick | be21285 | 2021-03-30 08:43:11 +0100 | [diff] [blame] | 43 | ## reg_block_path the hierarchical path to the relevant register block in the |
| 44 | ## design |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 45 | ## |
| 46 | ## rb a RegBlock object |
| 47 | ## |
| 48 | ## esc_if_name a string giving the full, escaped, interface name. For |
| 49 | ## a device interface called FOO on block BAR, |
| 50 | ## this will be bar__foo. For an unnamed interface |
| 51 | ## on block BAR, this will be just bar. |
| 52 | ## |
Rupert Swarbrick | be21285 | 2021-03-30 08:43:11 +0100 | [diff] [blame] | 53 | <%def name="make_ral_pkg(dv_base_prefix, reg_width, reg_block_path, rb, esc_if_name)">\ |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 54 | package ${esc_if_name}_ral_pkg; |
| 55 | ${make_ral_pkg_hdr(dv_base_prefix, [])} |
| 56 | |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 57 | ${make_ral_pkg_fwd_decls(esc_if_name, rb.type_regs, rb.windows)} |
| 58 | % for r in rb.all_regs: |
| 59 | <% |
Weicai Yang | 57dc8dc | 2021-07-22 18:10:14 -0700 | [diff] [blame] | 60 | mr = None |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 61 | if isinstance(r, MultiRegister): |
Weicai Yang | 57dc8dc | 2021-07-22 18:10:14 -0700 | [diff] [blame] | 62 | mr = r |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 63 | if r.dv_compact: |
Weicai Yang | 57dc8dc | 2021-07-22 18:10:14 -0700 | [diff] [blame] | 64 | regs = [r.reg] |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 65 | else: |
| 66 | regs = r.regs |
| 67 | else: |
| 68 | regs = [r] |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 69 | %>\ |
Weicai Yang | 57dc8dc | 2021-07-22 18:10:14 -0700 | [diff] [blame] | 70 | % for idx, reg in enumerate(regs): |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 71 | |
Weicai Yang | 57dc8dc | 2021-07-22 18:10:14 -0700 | [diff] [blame] | 72 | ${make_ral_pkg_reg_class(dv_base_prefix, reg_width, esc_if_name, reg_block_path, reg, mr, idx)} |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 73 | % endfor |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 74 | % endfor |
| 75 | % for window in rb.windows: |
| 76 | |
| 77 | ${make_ral_pkg_window_class(dv_base_prefix, esc_if_name, window)} |
| 78 | % endfor |
| 79 | |
| 80 | <% |
| 81 | reg_block_name = gen_dv.bcname(esc_if_name) |
| 82 | %>\ |
| 83 | class ${reg_block_name} extends ${dv_base_prefix}_reg_block; |
| 84 | % if rb.flat_regs: |
| 85 | // registers |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 86 | % for r in rb.all_regs: |
| 87 | <% |
Weicai Yang | b146659 | 2021-08-20 16:08:37 -0700 | [diff] [blame] | 88 | # If it's dv_compact, then create it as an array even when it only contains one item |
| 89 | count = 0 |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 90 | if isinstance(r, MultiRegister): |
| 91 | if r.dv_compact: |
| 92 | regs = [r.reg] |
| 93 | count = len(r.regs) |
| 94 | else: |
| 95 | regs = r.regs |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 96 | else: |
| 97 | regs = [r] |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 98 | %>\ |
| 99 | % for r0 in regs: |
| 100 | <% |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 101 | reg_type = gen_dv.rcname(esc_if_name, r0) |
| 102 | inst_name = r0.name.lower() |
Weicai Yang | b146659 | 2021-08-20 16:08:37 -0700 | [diff] [blame] | 103 | inst_decl = f'{inst_name}[{count}]' if count > 0 else inst_name |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 104 | %>\ |
| 105 | rand ${reg_type} ${inst_decl}; |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 106 | % endfor |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 107 | % endfor |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 108 | % endif |
| 109 | % if rb.windows: |
| 110 | // memories |
| 111 | % for window in rb.windows: |
| 112 | rand ${gen_dv.mcname(esc_if_name, window)} ${gen_dv.miname(window)}; |
| 113 | % endfor |
| 114 | % endif |
| 115 | |
| 116 | `uvm_object_utils(${reg_block_name}) |
| 117 | |
| 118 | function new(string name = "${reg_block_name}", |
| 119 | int has_coverage = UVM_NO_COVERAGE); |
| 120 | super.new(name, has_coverage); |
| 121 | endfunction : new |
| 122 | |
| 123 | virtual function void build(uvm_reg_addr_t base_addr, |
| 124 | csr_excl_item csr_excl = null); |
| 125 | // create default map |
| 126 | this.default_map = create_map(.name("default_map"), |
| 127 | .base_addr(base_addr), |
| 128 | .n_bytes(${reg_width//8}), |
| 129 | .endian(UVM_LITTLE_ENDIAN)); |
| 130 | if (csr_excl == null) begin |
| 131 | csr_excl = csr_excl_item::type_id::create("csr_excl"); |
| 132 | this.csr_excl = csr_excl; |
| 133 | end |
| 134 | % if rb.flat_regs: |
| 135 | set_hdl_path_root("tb.dut", "BkdrRegPathRtl"); |
| 136 | set_hdl_path_root("tb.dut", "BkdrRegPathRtlCommitted"); |
| 137 | set_hdl_path_root("tb.dut", "BkdrRegPathRtlShadow"); |
| 138 | // create registers |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 139 | % for r in rb.all_regs: |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 140 | <% |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 141 | r0 = r.reg if isinstance(r, MultiRegister) else r |
| 142 | reg_type = gen_dv.rcname(esc_if_name, r0) |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 143 | %>\ |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 144 | % if isinstance(r, MultiRegister): |
| 145 | % for idx, reg in enumerate(r.regs): |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 146 | <% |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 147 | if r.dv_compact: |
| 148 | inst_base = r0.name.lower() |
Weicai Yang | b146659 | 2021-08-20 16:08:37 -0700 | [diff] [blame] | 149 | inst_name = f'{inst_base}[{idx}]' |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 150 | else: |
| 151 | inst_name = reg.name.lower() |
| 152 | reg_type = gen_dv.rcname(esc_if_name, reg) |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 153 | %>\ |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 154 | ${instantiate_register(reg_width, reg_block_path, reg, reg_type, inst_name)}\ |
| 155 | % endfor |
| 156 | % else: |
| 157 | ${instantiate_register(reg_width, reg_block_path, r, reg_type, r.name.lower())}\ |
| 158 | % endif |
| 159 | % endfor |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 160 | <% |
| 161 | any_regwen = False |
| 162 | for r in rb.flat_regs: |
| 163 | if r.regwen: |
| 164 | any_regwen = True |
| 165 | break |
| 166 | %>\ |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 167 | % if any_regwen: |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 168 | // assign locked reg to its regwen reg |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 169 | % for r in rb.all_regs: |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 170 | % for inst, reg in get_inst_to_reg_dict(r).items(): |
| 171 | ${apply_regwen(rb, reg, inst)}\ |
| 172 | % endfor |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 173 | % endfor |
| 174 | % endif |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 175 | % endif |
| 176 | ${make_ral_pkg_window_instances(reg_width, esc_if_name, rb)} |
| 177 | endfunction : build |
| 178 | endclass : ${reg_block_name} |
| 179 | |
| 180 | endpackage |
| 181 | </%def>\ |
| 182 | ## |
| 183 | ## |
| 184 | ## make_ral_pkg_hdr |
| 185 | ## ================ |
| 186 | ## |
| 187 | ## Generate the header for a RAL package |
| 188 | ## |
| 189 | ## dv_base_prefix as for make_ral_pkg |
| 190 | ## |
| 191 | ## deps a list of names for packages that should be explicitly |
| 192 | ## imported |
| 193 | ## |
| 194 | <%def name="make_ral_pkg_hdr(dv_base_prefix, deps)">\ |
| 195 | // dep packages |
| 196 | import uvm_pkg::*; |
| 197 | import dv_base_reg_pkg::*; |
| 198 | % if dv_base_prefix != "dv_base": |
| 199 | import ${dv_base_prefix}_reg_pkg::*; |
| 200 | % endif |
| 201 | % for dep in deps: |
| 202 | import ${dep}::*; |
| 203 | % endfor |
| 204 | |
| 205 | // macro includes |
| 206 | `include "uvm_macros.svh"\ |
| 207 | </%def>\ |
| 208 | ## |
| 209 | ## |
| 210 | ## make_ral_pkg_fwd_decls |
| 211 | ## ====================== |
| 212 | ## |
| 213 | ## Generate the forward declarations for a RAL package |
| 214 | ## |
| 215 | ## esc_if_name as for make_ral_pkg |
| 216 | ## |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 217 | ## type_regs a list of Register objects, one for each type that |
| 218 | ## should be defined. Each MultiRegister will contribute |
| 219 | ## just one register to the list. |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 220 | ## |
| 221 | ## windows a list of Window objects |
| 222 | ## |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 223 | <%def name="make_ral_pkg_fwd_decls(esc_if_name, type_regs, windows)">\ |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 224 | // Forward declare all register/memory/block classes |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 225 | % for r in type_regs: |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 226 | typedef class ${gen_dv.rcname(esc_if_name, r)}; |
| 227 | % endfor |
| 228 | % for w in windows: |
| 229 | typedef class ${gen_dv.mcname(esc_if_name, w)}; |
| 230 | % endfor |
| 231 | typedef class ${gen_dv.bcname(esc_if_name)};\ |
| 232 | </%def>\ |
| 233 | ## |
| 234 | ## |
| 235 | ## make_ral_pkg_reg_class |
| 236 | ## ====================== |
| 237 | ## |
| 238 | ## Generate the classes for a register inside a RAL package |
| 239 | ## |
| 240 | ## dv_base_prefix as for make_ral_pkg |
| 241 | ## |
| 242 | ## reg_width as for make_ral_pkg |
| 243 | ## |
| 244 | ## esc_if_name as for make_ral_pkg |
| 245 | ## |
Rupert Swarbrick | be21285 | 2021-03-30 08:43:11 +0100 | [diff] [blame] | 246 | ## reg_block_path as for make_ral_pkg |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 247 | ## |
Weicai Yang | 57dc8dc | 2021-07-22 18:10:14 -0700 | [diff] [blame] | 248 | ## reg a Register object |
| 249 | ## |
| 250 | ## mr a MultiRegister object if this reg is from a MultiRegister |
| 251 | ## |
| 252 | ## reg_idx the index location of this reg if this reg is from a MultiRegister, |
| 253 | ## or zero if not |
| 254 | <%def name="make_ral_pkg_reg_class(dv_base_prefix, reg_width, esc_if_name, reg_block_path, |
| 255 | reg, mr, reg_idx)">\ |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 256 | <% |
| 257 | reg_name = reg.name.lower() |
| 258 | |
| 259 | is_ext = reg.hwext |
| 260 | for field in reg.fields: |
| 261 | if (field.hwaccess.value[1] == HwAccess.NONE and |
| 262 | field.swaccess.swrd() == SwRdAccess.RD and |
| 263 | not field.swaccess.allows_write()): |
| 264 | is_ext = 1 |
| 265 | |
| 266 | class_name = gen_dv.rcname(esc_if_name, reg) |
| 267 | %>\ |
| 268 | class ${class_name} extends ${dv_base_prefix}_reg; |
| 269 | // fields |
Weicai Yang | 57dc8dc | 2021-07-22 18:10:14 -0700 | [diff] [blame] | 270 | <% |
| 271 | suffix = "" |
| 272 | start_idx = 0 |
| 273 | add_style_waive = False |
| 274 | compact_field_inst_name = "" |
| 275 | if mr is None: |
| 276 | fields = reg.fields |
| 277 | else: |
| 278 | if not mr.compact: |
| 279 | fields = mr.reg.fields |
| 280 | else: |
| 281 | fields = mr.regs[reg_idx].fields |
| 282 | compact_field_inst_name = mr.reg.fields[0].name.lower() |
| 283 | if mr.dv_compact: |
| 284 | # The dv_compact flag means that the fields of the multi-reg divide equally into registers. |
| 285 | # In this case, there's an array of registers and make_ral_pkg_reg_class() gets called once |
| 286 | # to define that array's type, using the fields of the first register in the replication. |
| 287 | assert reg_idx == 0 |
| 288 | if len(fields) > 1: |
| 289 | suffix = f'[{len(fields)}]' |
| 290 | else: |
| 291 | # In this case, the multi-register is "compact", so there might be multiple copies of its |
| 292 | # single field in each generated register. But dv_compact is false, which probably means |
| 293 | # that the fields didn't divide equally into a whole number of registers. In this case, we |
| 294 | # are generating a different class for each output register and should spit out fields |
| 295 | # accordingly. Note that we generate an array, even if len(fields) = 1. If that happens, we |
| 296 | # know we're on the last generated register, so want to keep everything uniform. |
| 297 | num_fields_per_reg = 32 // fields[0].bits.width() |
| 298 | start_idx = num_fields_per_reg * reg_idx |
| 299 | end_idx = start_idx + len(fields) - 1 |
| 300 | suffix = f'[{start_idx}:{end_idx}]' |
| 301 | if start_idx == 0: |
| 302 | add_style_waive = True |
| 303 | %>\ |
| 304 | % if add_style_waive: |
| 305 | // verilog_lint: waive unpacked-dimensions-range-ordering |
| 306 | % endif |
| 307 | % if compact_field_inst_name: |
| 308 | rand ${dv_base_prefix}_reg_field ${compact_field_inst_name}${suffix}; |
| 309 | % else: |
| 310 | % for f in fields: |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 311 | rand ${dv_base_prefix}_reg_field ${f.name.lower()}; |
Weicai Yang | 57dc8dc | 2021-07-22 18:10:14 -0700 | [diff] [blame] | 312 | % endfor |
| 313 | % endif |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 314 | |
| 315 | `uvm_object_utils(${class_name}) |
| 316 | |
| 317 | function new(string name = "${class_name}", |
| 318 | int unsigned n_bits = ${reg_width}, |
| 319 | int has_coverage = UVM_NO_COVERAGE); |
| 320 | super.new(name, n_bits, has_coverage); |
| 321 | endfunction : new |
| 322 | |
| 323 | virtual function void build(csr_excl_item csr_excl = null); |
| 324 | // create fields |
Weicai Yang | 57dc8dc | 2021-07-22 18:10:14 -0700 | [diff] [blame] | 325 | % for idx, field in enumerate(fields): |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 326 | <% |
Weicai Yang | 57dc8dc | 2021-07-22 18:10:14 -0700 | [diff] [blame] | 327 | if compact_field_inst_name: |
| 328 | reg_field_name = compact_field_inst_name |
| 329 | if len(fields) > 1: |
| 330 | reg_field_name = reg_field_name + f'[{idx + start_idx}]' |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 331 | else: |
Weicai Yang | 57dc8dc | 2021-07-22 18:10:14 -0700 | [diff] [blame] | 332 | reg_field_name = field.name.lower() |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 333 | %>\ |
Rupert Swarbrick | be21285 | 2021-03-30 08:43:11 +0100 | [diff] [blame] | 334 | ${_create_reg_field(dv_base_prefix, reg_width, reg_block_path, reg.shadowed, reg.hwext, reg_field_name, field)} |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 335 | % endfor |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 336 | % if is_ext: |
| 337 | set_is_ext_reg(1); |
| 338 | % endif |
| 339 | endfunction : build |
| 340 | endclass : ${class_name}\ |
| 341 | </%def>\ |
| 342 | ## |
| 343 | ## |
| 344 | ## _create_reg_field |
| 345 | ## ================= |
| 346 | ## |
| 347 | ## Generate the code that creates a uvm_reg_field object for a field |
| 348 | ## in a register. |
| 349 | ## |
| 350 | ## dv_base_prefix as for make_ral_pkg |
| 351 | ## |
| 352 | ## reg_width as for make_ral_pkg |
| 353 | ## |
Rupert Swarbrick | be21285 | 2021-03-30 08:43:11 +0100 | [diff] [blame] | 354 | ## reg_block_path as for make_ral_pkg |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 355 | ## |
| 356 | ## shadowed true if the field's register is shadowed |
| 357 | ## |
| 358 | ## hwext true if the field's register is hwext |
| 359 | ## |
| 360 | ## reg_field_name a string with the name to give the field in the HDL |
| 361 | ## |
| 362 | ## field a Field object |
Rupert Swarbrick | be21285 | 2021-03-30 08:43:11 +0100 | [diff] [blame] | 363 | <%def name="_create_reg_field(dv_base_prefix, reg_width, reg_block_path, shadowed, hwext, reg_field_name, field)">\ |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 364 | <% |
| 365 | field_size = field.bits.width() |
Rupert Swarbrick | 7252f17 | 2021-06-17 17:04:20 +0100 | [diff] [blame] | 366 | field_access = field.swaccess.dv_rights() |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 367 | |
| 368 | if not field.hwaccess.allows_write(): |
| 369 | field_volatile = 0 |
| 370 | else: |
| 371 | field_volatile = 1 |
| 372 | field_tags = field.tags |
| 373 | |
Weicai Yang | 57dc8dc | 2021-07-22 18:10:14 -0700 | [diff] [blame] | 374 | fname = reg_field_name |
Rupert Swarbrick | 6357816 | 2021-04-22 10:53:46 +0100 | [diff] [blame] | 375 | type_id_indent = ' ' * (len(fname) + 4) |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 376 | %>\ |
Rupert Swarbrick | 6357816 | 2021-04-22 10:53:46 +0100 | [diff] [blame] | 377 | ${fname} = (${dv_base_prefix}_reg_field:: |
Weicai Yang | 57dc8dc | 2021-07-22 18:10:14 -0700 | [diff] [blame] | 378 | ${type_id_indent}type_id::create("${field.name.lower()}")); |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 379 | ${fname}.configure( |
| 380 | .parent(this), |
| 381 | .size(${field_size}), |
| 382 | .lsb_pos(${field.bits.lsb}), |
| 383 | .access("${field_access}"), |
| 384 | .volatile(${field_volatile}), |
| 385 | .reset(${reg_width}'h${format(field.resval or 0, 'x')}), |
| 386 | .has_reset(1), |
| 387 | .is_rand(1), |
| 388 | .individually_accessible(1)); |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 389 | |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 390 | ${fname}.set_original_access("${field_access}"); |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 391 | % if field_tags: |
| 392 | // create field tags |
| 393 | % for field_tag in field_tags: |
| 394 | <% |
| 395 | tag = field_tag.split(":") |
| 396 | %>\ |
| 397 | % if tag[0] == "excl": |
Weicai Yang | 57dc8dc | 2021-07-22 18:10:14 -0700 | [diff] [blame] | 398 | csr_excl.add_excl(${fname}.get_full_name(), ${tag[2]}, ${tag[1]}); |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 399 | % endif |
| 400 | % endfor |
| 401 | % endif |
| 402 | </%def>\ |
| 403 | ## |
| 404 | ## |
| 405 | ## make_ral_pkg_window_class |
| 406 | ## ========================= |
| 407 | ## |
| 408 | ## Generate the classes for a window inside a RAL package |
| 409 | ## |
| 410 | ## dv_base_prefix as for make_ral_pkg |
| 411 | ## |
| 412 | ## esc_if_name as for make_ral_pkg |
| 413 | ## |
| 414 | ## window a Window object |
| 415 | <%def name="make_ral_pkg_window_class(dv_base_prefix, esc_if_name, window)">\ |
| 416 | <% |
| 417 | mem_name = window.name.lower() |
| 418 | mem_right = window.swaccess.dv_rights() |
| 419 | mem_n_bits = window.validbits |
| 420 | mem_size = window.items |
| 421 | |
| 422 | class_name = gen_dv.mcname(esc_if_name, window) |
| 423 | %>\ |
| 424 | class ${class_name} extends ${dv_base_prefix}_mem; |
| 425 | |
| 426 | `uvm_object_utils(${class_name}) |
| 427 | |
| 428 | function new(string name = "${class_name}", |
| 429 | longint unsigned size = ${mem_size}, |
| 430 | int unsigned n_bits = ${mem_n_bits}, |
| 431 | string access = "${mem_right}", |
| 432 | int has_coverage = UVM_NO_COVERAGE); |
| 433 | super.new(name, size, n_bits, access, has_coverage); |
| 434 | % if window.byte_write: |
| 435 | set_mem_partial_write_support(1); |
| 436 | % endif |
| 437 | endfunction : new |
| 438 | |
| 439 | endclass : ${class_name} |
| 440 | </%def>\ |
| 441 | ## |
| 442 | ## |
| 443 | ## make_ral_pkg_window_instances |
| 444 | ## ============================= |
| 445 | ## |
| 446 | ## Generate the classes for a window inside a RAL package |
| 447 | ## |
| 448 | ## reg_width as for make_ral_pkg |
| 449 | ## |
| 450 | ## esc_if_name as for make_ral_pkg |
| 451 | ## |
| 452 | ## rb a RegBlock object |
| 453 | ## |
| 454 | <%def name="make_ral_pkg_window_instances(reg_width, esc_if_name, rb)">\ |
| 455 | % if rb.windows: |
| 456 | |
| 457 | // create memories |
| 458 | % for w in rb.windows: |
| 459 | <% |
| 460 | mem_name = w.name.lower() |
| 461 | mem_right = w.swaccess.dv_rights() |
| 462 | mem_offset = "{}'h{:x}".format(reg_width, w.offset) |
| 463 | mem_n_bits = w.validbits |
| 464 | mem_size = w.items |
| 465 | %>\ |
Michael Schaffner | 4e7114e | 2021-07-02 17:57:11 -0700 | [diff] [blame] | 466 | ${mem_name} = |
| 467 | ${gen_dv.mcname(esc_if_name, w)}::type_id::create("${mem_name}"); |
Rupert Swarbrick | 25468b4 | 2021-03-11 15:20:10 +0000 | [diff] [blame] | 468 | ${mem_name}.configure(.parent(this)); |
| 469 | default_map.add_mem(.mem(${mem_name}), |
| 470 | .offset(${mem_offset}), |
| 471 | .rights("${mem_right}")); |
| 472 | % endfor |
| 473 | % endif |
| 474 | </%def>\ |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 475 | ## |
| 476 | ## |
| 477 | ## instantiate_register |
| 478 | ## ==================== |
| 479 | ## |
| 480 | ## Actually instantiate a register in a register block |
| 481 | ## |
| 482 | ## reg_width an integer giving the width of registers in bits |
| 483 | ## |
| 484 | ## reg_block_path as for make_ral_pkg |
| 485 | ## |
| 486 | ## reg the Register to instantiate |
| 487 | ## |
| 488 | ## reg_type a string giving the type name (a subclass of |
| 489 | ## uvm_register) to instantiate. |
| 490 | ## |
| 491 | ## reg_inst a string giving the field of the uvm_reg_block that |
| 492 | ## should be set to this new register. For single |
| 493 | ## registers, this will just be the register name. For |
| 494 | ## elements of multi-registers, it will be the name of an |
| 495 | ## array item. |
| 496 | ## |
| 497 | <%def name="instantiate_register(reg_width, reg_block_path, reg, reg_type, reg_inst)">\ |
| 498 | <% |
| 499 | reg_name = reg.name.lower() |
| 500 | reg_offset = "{}'h{:x}".format(reg_width, reg.offset) |
| 501 | |
| 502 | inst_id_indent = ' ' * (len(reg_inst) + 4) |
| 503 | %>\ |
| 504 | ${reg_inst} = (${reg_type}:: |
| 505 | ${inst_id_indent}type_id::create("${reg_name}")); |
| 506 | ${reg_inst}.configure(.blk_parent(this)); |
| 507 | ${reg_inst}.build(csr_excl); |
| 508 | default_map.add_reg(.rg(${reg_inst}), |
| 509 | .offset(${reg_offset})); |
Timothy Chen | c58548c | 2021-08-02 19:17:24 -0700 | [diff] [blame] | 510 | % if reg.shadowed: |
Timothy Chen | c58548c | 2021-08-02 19:17:24 -0700 | [diff] [blame] | 511 | % if reg.update_err_alert: |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 512 | ${reg_inst}.add_update_err_alert("${reg.update_err_alert}"); |
Timothy Chen | c58548c | 2021-08-02 19:17:24 -0700 | [diff] [blame] | 513 | % endif |
| 514 | |
| 515 | % if reg.storage_err_alert: |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 516 | ${reg_inst}.add_storage_err_alert("${reg.storage_err_alert}"); |
Timothy Chen | c58548c | 2021-08-02 19:17:24 -0700 | [diff] [blame] | 517 | % endif |
| 518 | |
| 519 | % if reg.hwext: |
Pirmin Vogel | c473f70 | 2021-08-12 16:43:54 +0200 | [diff] [blame] | 520 | % for field in reg.fields: |
| 521 | <% |
| 522 | shadowed_reg_path = '' |
| 523 | for tag in field.tags: |
| 524 | parts = tag.split(':') |
| 525 | if parts[0] == 'shadowed_reg_path': |
| 526 | shadowed_reg_path = parts[1] |
| 527 | |
| 528 | if not shadowed_reg_path: |
| 529 | print("ERROR: ext shadow_reg does not have tags for shadowed_reg_path for each field!") |
| 530 | assert 0 |
| 531 | %>\ |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 532 | ${reg_inst}.add_hdl_path_slice( |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 533 | "${shadowed_reg_path}.committed_reg.q", |
Pirmin Vogel | c473f70 | 2021-08-12 16:43:54 +0200 | [diff] [blame] | 534 | ${field.bits.lsb}, ${field.bits.width()}, 0, "BkdrRegPathRtlCommitted"); |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 535 | ${reg_inst}.add_hdl_path_slice( |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 536 | "${shadowed_reg_path}.shadow_reg.q", |
Pirmin Vogel | c473f70 | 2021-08-12 16:43:54 +0200 | [diff] [blame] | 537 | ${field.bits.lsb}, ${field.bits.width()}, 0, "BkdrRegPathRtlShadow"); |
| 538 | % endfor |
Timothy Chen | c58548c | 2021-08-02 19:17:24 -0700 | [diff] [blame] | 539 | % endif |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 540 | % endif |
| 541 | % for field in reg.fields: |
| 542 | <% |
| 543 | field_size = field.bits.width() |
| 544 | if len(reg.fields) == 1: |
| 545 | reg_field_name = reg_name |
| 546 | else: |
| 547 | reg_field_name = reg_name + "_" + field.name.lower() |
Timothy Chen | c57e558 | 2021-07-30 22:06:24 -0700 | [diff] [blame] | 548 | |
Timothy Chen | 5d83537 | 2021-08-18 19:39:25 -0700 | [diff] [blame] | 549 | ##if reg.async_name and not reg.hwext: |
| 550 | ## reg_field_name += ".u_subreg" |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 551 | %>\ |
| 552 | % if ((field.hwaccess.value[1] == HwAccess.NONE and\ |
| 553 | field.swaccess.swrd() == SwRdAccess.RD and\ |
| 554 | not field.swaccess.allows_write())): |
| 555 | // constant reg |
| 556 | ${reg_inst}.add_hdl_path_slice( |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 557 | "${reg_block_path}.${reg_field_name}_qs", |
| 558 | ${field.bits.lsb}, ${field_size}, 0, "BkdrRegPathRtl"); |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 559 | % else: |
| 560 | ${reg_inst}.add_hdl_path_slice( |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 561 | "${reg_block_path}.u_${reg_field_name}.q${"s" if reg.hwext else ""}", |
| 562 | ${field.bits.lsb}, ${field_size}, 0, "BkdrRegPathRtl"); |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 563 | % endif |
Timothy Chen | c58548c | 2021-08-02 19:17:24 -0700 | [diff] [blame] | 564 | % if reg.shadowed and not reg.hwext: |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 565 | ${reg_inst}.add_hdl_path_slice( |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 566 | "${reg_block_path}.u_${reg_field_name}.committed_reg.q", |
| 567 | ${field.bits.lsb}, ${field_size}, 0, "BkdrRegPathRtlCommitted"); |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 568 | ${reg_inst}.add_hdl_path_slice( |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 569 | "${reg_block_path}.u_${reg_field_name}.shadow_reg.q", |
| 570 | ${field.bits.lsb}, ${field_size}, 0, "BkdrRegPathRtlShadow"); |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 571 | % endif |
| 572 | % endfor |
| 573 | |
| 574 | % if reg.shadowed: |
| 575 | ${reg_inst}.set_is_shadowed(); |
| 576 | % endif |
| 577 | % if reg.tags: |
| 578 | // create register tags |
| 579 | % for reg_tag in reg.tags: |
| 580 | <% |
| 581 | tag = reg_tag.split(":") |
| 582 | %>\ |
| 583 | % if tag[0] == "excl": |
| 584 | csr_excl.add_excl(${reg_inst}.get_full_name(), ${tag[2]}, ${tag[1]}); |
| 585 | % endif |
| 586 | % endfor |
| 587 | % endif |
| 588 | </%def>\ |
| 589 | ## |
| 590 | ## |
| 591 | ## apply_regwen |
| 592 | ## ============ |
| 593 | ## |
| 594 | ## Apply a regwen to a register |
| 595 | ## |
| 596 | ## rb the register block |
| 597 | ## |
| 598 | ## reg the Register that needs apply regwens |
| 599 | ## |
| 600 | ## reg_inst a string giving the field of the uvm_reg_block that |
| 601 | ## should be updated. For single registers, this will just |
| 602 | ## be the register name. For elements of multi-registers, |
| 603 | ## it will be the name of an array item. |
| 604 | ## |
| 605 | <%def name="apply_regwen(rb, reg, reg_inst)">\ |
| 606 | % if reg.regwen is None: |
| 607 | <% return "" %>\ |
| 608 | % endif |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 609 | % for wen in rb.all_regs: |
| 610 | % for wen_inst, wen_reg in get_inst_to_reg_dict(wen).items(): |
| 611 | % if reg.regwen.lower() == wen_reg.name.lower(): |
| 612 | ${wen_inst}.add_lockable_reg_or_fld(${reg_inst}); |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 613 | <% return "" %>\ |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 614 | % elif wen_reg.name.lower() in reg.regwen.lower(): |
| 615 | % for field in wen_reg.get_field_list(): |
| 616 | % if reg.regwen.lower() == (wen_reg.name.lower() + "_" + field.name.lower()): |
| 617 | ${wen_inst}.${field.name.lower()}.add_lockable_reg_or_fld(${reg_inst}); |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 618 | <% return "" %>\ |
Weicai Yang | f69b700 | 2021-07-12 17:06:49 -0700 | [diff] [blame] | 619 | % endif |
| 620 | % endfor |
| 621 | % endif |
| 622 | % endfor |
Weicai Yang | 00f6d78 | 2021-06-29 17:42:43 -0700 | [diff] [blame] | 623 | % endfor |
| 624 | </%def>\ |