| // Copyright lowRISC contributors. | 
 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | // SPDX-License-Identifier: Apache-2.0 | 
 | // | 
 | // Register Package auto-generated by `reggen` containing data structure | 
 | <% | 
 |   from topgen import lib # TODO: Split lib to common lib module | 
 |  | 
 |   from reggen.access import HwAccess, SwRdAccess, SwWrAccess | 
 |   from reggen.register import Register | 
 |   from reggen.multi_register import MultiRegister | 
 |  | 
 |   from reggen import gen_rtl | 
 |  | 
 |   localparams = block.params.get_localparams() | 
 |  | 
 |   addr_widths = gen_rtl.get_addr_widths(block) | 
 |  | 
 |   lblock = block.name.lower() | 
 |   ublock = lblock.upper() | 
 |  | 
 |   def reg_pfx(reg): | 
 |     return '{}_{}'.format(ublock, reg.name.upper()) | 
 |  | 
 |   def reg_resname(reg): | 
 |     return '{}_RESVAL'.format(reg_pfx(reg)) | 
 |  | 
 |   def field_resname(reg, field): | 
 |     return '{}_{}_RESVAL'.format(reg_pfx(reg), field.name.upper()) | 
 |  | 
 | %>\ | 
 | <%def name="typedefs_for_iface(iface_name, iface_desc, for_iface, rb)">\ | 
 | <% | 
 |    hdr = gen_rtl.make_box_quote('Typedefs for registers' + for_iface) | 
 | %>\ | 
 | % for r in rb.all_regs: | 
 |   % if r.get_n_bits(["q"]): | 
 |     % if hdr: | 
 |  | 
 | ${hdr} | 
 |     % endif | 
 | <% | 
 |     r0 = gen_rtl.get_r0(r) | 
 |     hdr = None | 
 | %>\ | 
 |  | 
 |   typedef struct packed { | 
 |     % if r.is_homogeneous(): | 
 |       ## If we have a homogeneous register or multireg, there is just one field | 
 |       ## (possibly replicated many times). The typedef is for one copy of that | 
 |       ## field. | 
 | <% | 
 |       field = r.get_field_list()[0] | 
 |       field_q_width = field.get_n_bits(r0.hwext, r0.hwqe, r0.hwre, ['q']) | 
 |       field_q_bits = lib.bitarray(field_q_width, 2) | 
 | %>\ | 
 |     logic ${field_q_bits} q; | 
 |       % if r0.hwqe: | 
 |     logic        qe; | 
 |       % endif | 
 |       % if r0.hwre or (r0.shadowed and r0.hwext): | 
 |     logic        re; | 
 |       % endif | 
 |       % if r0.shadowed and not r0.hwext: | 
 |     logic        err_update; | 
 |     logic        err_storage; | 
 |       % endif | 
 |     % else: | 
 |       ## We are inhomogeneous, which means there is more than one different | 
 |       ## field. Generate a reg2hw typedef that packs together all the fields of | 
 |       ## the register. | 
 |       % for f in r0.fields: | 
 | <% | 
 |           field_q_width = f.get_n_bits(r0.hwext, r0.hwqe, r0.hwre, ["q"]) | 
 | %>\ | 
 |         % if field_q_width: | 
 | <% | 
 |             field_q_bits = lib.bitarray(field_q_width, 2) | 
 |             struct_name = f.name.lower() | 
 | %>\ | 
 |     struct packed { | 
 |       logic ${field_q_bits} q; | 
 |           % if r0.hwqe: | 
 |       logic        qe; | 
 |           % endif | 
 |           % if r0.hwre or (r0.shadowed and r0.hwext): | 
 |       logic        re; | 
 |           % endif | 
 |           % if r0.shadowed and not r0.hwext: | 
 |       logic        err_update; | 
 |       logic        err_storage; | 
 |           % endif | 
 |     } ${struct_name}; | 
 |         %endif | 
 |       %endfor | 
 |     %endif | 
 |   } ${gen_rtl.get_reg_tx_type(block, r, False)}; | 
 |   %endif | 
 | % endfor | 
 | % for r in rb.all_regs: | 
 |   % if r.get_n_bits(["d"]): | 
 |     % if hdr: | 
 |  | 
 | ${hdr} | 
 |     % endif | 
 | <% | 
 |     r0 = gen_rtl.get_r0(r) | 
 |     hdr = None | 
 | %>\ | 
 |  | 
 |   typedef struct packed { | 
 |     % if r.is_homogeneous(): | 
 |       ## If we have a homogeneous register or multireg, there is just one field | 
 |       ## (possibly replicated many times). The typedef is for one copy of that | 
 |       ## field. | 
 | <% | 
 |       field = r.get_field_list()[0] | 
 |       field_d_width = field.get_n_bits(r0.hwext, r0.hwqe, r0.hwre, ['d']) | 
 |       field_d_bits = lib.bitarray(field_d_width, 2) | 
 | %>\ | 
 |     logic ${field_d_bits} d; | 
 |       % if not r0.hwext: | 
 |     logic        de; | 
 |       % endif | 
 |     % else: | 
 |       ## We are inhomogeneous, which means there is more than one different | 
 |       ## field. Generate a hw2reg typedef that packs together all the fields of | 
 |       ## the register. | 
 |       % for f in r0.fields: | 
 | <% | 
 |           field_d_width = f.get_n_bits(r0.hwext, r0.hwqe, r0.hwre, ["d"]) | 
 | %>\ | 
 |         % if field_d_width: | 
 | <% | 
 |             field_d_bits = lib.bitarray(field_d_width, 2) | 
 |             struct_name = f.name.lower() | 
 | %>\ | 
 |     struct packed { | 
 |       logic ${field_d_bits} d; | 
 |           % if not r0.hwext: | 
 |       logic        de; | 
 |           % endif | 
 |     } ${struct_name}; | 
 |         %endif | 
 |       %endfor | 
 |     %endif | 
 |   } ${gen_rtl.get_reg_tx_type(block, r, True)}; | 
 |   % endif | 
 | % endfor | 
 | % if block.expose_reg_if: | 
 | <% | 
 |     lpfx = gen_rtl.get_type_name_pfx(block, iface_name) | 
 |     addr_width = rb.get_addr_width() | 
 |     data_width = block.regwidth | 
 |     data_byte_width = data_width // 8 | 
 |  | 
 |     # This will produce strings like "[0:0] " to let us keep | 
 |     # everything lined up whether there's 1 or 2 digits in the MSB. | 
 |     aw_bits = f'[{addr_width-1}:0]'.ljust(6) | 
 |     dw_bits = f'[{data_width-1}:0]'.ljust(6) | 
 |     dbw_bits = f'[{data_byte_width-1}:0]'.ljust(6) | 
 | %>\ | 
 |  | 
 |   typedef struct packed { | 
 |     logic        reg_we; | 
 |     logic        reg_re; | 
 |     logic ${aw_bits} reg_addr; | 
 |     logic ${dw_bits} reg_wdata; | 
 |     logic ${dbw_bits} reg_be; | 
 |   } ${lpfx}_reg2hw_reg_if_t; | 
 | % endif | 
 | </%def>\ | 
 | <%def name="reg2hw_for_iface(iface_name, iface_desc, for_iface, rb)">\ | 
 | <% | 
 | lpfx = gen_rtl.get_type_name_pfx(block, iface_name) | 
 | nbits = rb.get_n_bits(["q", "qe", "re"]) | 
 | packbit = 0 | 
 |  | 
 | addr_width = rb.get_addr_width() | 
 | data_width = block.regwidth | 
 | data_byte_width = data_width // 8 | 
 | reg_if_width = 2 + addr_width + data_width + data_byte_width | 
 | %>\ | 
 | % if nbits > 0: | 
 |  | 
 |   // Register -> HW type${for_iface} | 
 |   typedef struct packed { | 
 | % if block.expose_reg_if: | 
 |     ${lpfx}_reg2hw_reg_if_t reg_if; // [${reg_if_width + nbits - 1}:${nbits}] | 
 | % endif | 
 | % for r in rb.all_regs: | 
 |   % if r.get_n_bits(["q"]): | 
 | <% | 
 |     r0 = gen_rtl.get_r0(r) | 
 |     struct_type = gen_rtl.get_reg_tx_type(block, r, False) | 
 |     struct_width = r0.get_n_bits(['q', 'qe', 're']) | 
 |  | 
 |     if isinstance(r, MultiRegister): | 
 |       struct_type += " [{}:0]".format(r.count - 1) | 
 |       struct_width *= r.count | 
 |  | 
 |     msb = nbits - packbit - 1 | 
 |     lsb = msb - struct_width + 1 | 
 |     packbit += struct_width | 
 |     name_and_comment = f'{r0.name.lower()}; // [{msb}:{lsb}]' | 
 | %>\ | 
 |   % if 4 + len(struct_type) + 1 + len(name_and_comment) <= 100: | 
 |     ${struct_type} ${name_and_comment} | 
 |   % else: | 
 |     ${struct_type} | 
 |         ${name_and_comment} | 
 |   % endif | 
 |   % endif | 
 | % endfor | 
 |   } ${gen_rtl.get_iface_tx_type(block, iface_name, False)}; | 
 | % endif | 
 | </%def>\ | 
 | <%def name="hw2reg_for_iface(iface_name, iface_desc, for_iface, rb)">\ | 
 | <% | 
 | nbits = rb.get_n_bits(["d", "de"]) | 
 | packbit = 0 | 
 | %>\ | 
 | % if nbits > 0: | 
 |  | 
 |   // HW -> register type${for_iface} | 
 |   typedef struct packed { | 
 | % for r in rb.all_regs: | 
 |   % if r.get_n_bits(["d"]): | 
 | <% | 
 |     r0 = gen_rtl.get_r0(r) | 
 |     struct_type = gen_rtl.get_reg_tx_type(block, r, True) | 
 |     struct_width = r0.get_n_bits(['d', 'de']) | 
 |  | 
 |     if isinstance(r, MultiRegister): | 
 |       struct_type += " [{}:0]".format(r.count - 1) | 
 |       struct_width *= r.count | 
 |  | 
 |     msb = nbits - packbit - 1 | 
 |     lsb = msb - struct_width + 1 | 
 |     packbit += struct_width | 
 |     name_and_comment = f'{r0.name.lower()}; // [{msb}:{lsb}]' | 
 | %>\ | 
 |   % if 4 + len(struct_type) + 1 + len(name_and_comment) <= 100: | 
 |     ${struct_type} ${name_and_comment} | 
 |   % else: | 
 |     ${struct_type} | 
 |         ${name_and_comment} | 
 |   % endif | 
 |   % endif | 
 | % endfor | 
 |   } ${gen_rtl.get_iface_tx_type(block, iface_name, True)}; | 
 | % endif | 
 | </%def>\ | 
 | <%def name="offsets_for_iface(iface_name, iface_desc, for_iface, rb)">\ | 
 | % if not rb.flat_regs: | 
 | <% return STOP_RENDERING %> | 
 | % endif | 
 |  | 
 |   // Register offsets${for_iface} | 
 | <% | 
 | aw_name, aw = addr_widths[iface_name] | 
 | %>\ | 
 | % for r in rb.flat_regs: | 
 | <% | 
 | value = "{}'h {:x}".format(aw, r.offset) | 
 | %>\ | 
 |   parameter logic [${aw_name}-1:0] ${reg_pfx(r)}_OFFSET = ${value}; | 
 | % endfor | 
 | </%def>\ | 
 | <%def name="hwext_resvals_for_iface(iface_name, iface_desc, for_iface, rb)">\ | 
 | <% | 
 |   hwext_regs = [r for r in rb.flat_regs if r.hwext] | 
 | %>\ | 
 | % if hwext_regs: | 
 |  | 
 |   // Reset values for hwext registers and their fields${for_iface} | 
 |   % for reg in hwext_regs: | 
 | <% | 
 |     reg_width = reg.get_width() | 
 |     reg_msb = reg_width - 1 | 
 |     reg_resval = "{}'h {:x}".format(reg_width, reg.resval) | 
 | %>\ | 
 |   parameter logic [${reg_msb}:0] ${reg_resname(reg)} = ${reg_resval}; | 
 |     % for field in reg.fields: | 
 |       % if field.resval is not None: | 
 | <% | 
 |     field_width = field.bits.width() | 
 |     field_msb = field_width - 1 | 
 |     field_resval = "{}'h {:x}".format(field_width, field.resval) | 
 | %>\ | 
 |   parameter logic [${field_msb}:0] ${field_resname(reg, field)} = ${field_resval}; | 
 |       % endif | 
 |     % endfor | 
 |   % endfor | 
 | % endif | 
 | </%def>\ | 
 | <%def name="windows_for_iface(iface_name, iface_desc, for_iface, rb)">\ | 
 | % if rb.windows: | 
 | <% | 
 |   aw_name, aw = addr_widths[iface_name] | 
 | %>\ | 
 |  | 
 |   // Window parameters${for_iface} | 
 | % for i,w in enumerate(rb.windows): | 
 | <% | 
 |     win_pfx = '{}_{}'.format(ublock, w.name.upper()) | 
 |     base_txt_val = "{}'h {:x}".format(aw, w.offset) | 
 |     size_txt_val = "'h {:x}".format(w.size_in_bytes) | 
 |  | 
 |     offset_type = 'logic [{}-1:0]'.format(aw_name) | 
 |     size_type = 'int unsigned' | 
 |     max_type_len = max(len(offset_type), len(size_type)) | 
 |  | 
 |     offset_type += ' ' * (max_type_len - len(offset_type)) | 
 |     size_type += ' ' * (max_type_len - len(size_type)) | 
 |  | 
 | %>\ | 
 |   parameter ${offset_type} ${win_pfx}_OFFSET = ${base_txt_val}; | 
 |   parameter ${size_type} ${win_pfx}_SIZE   = ${size_txt_val}; | 
 | % endfor | 
 | % endif | 
 | </%def>\ | 
 | <%def name="reg_data_for_iface(iface_name, iface_desc, for_iface, rb)">\ | 
 | % if rb.flat_regs: | 
 | <% | 
 |   lpfx = gen_rtl.get_type_name_pfx(block, iface_name) | 
 |   upfx = lpfx.upper() | 
 |   idx_len = len("{}".format(len(rb.flat_regs) - 1)) | 
 | %>\ | 
 |  | 
 |   // Register index${for_iface} | 
 |   typedef enum int { | 
 | % for r in rb.flat_regs: | 
 |     ${ublock}_${r.name.upper()}${"" if loop.last else ","} | 
 | % endfor | 
 |   } ${lpfx}_id_e; | 
 |  | 
 |   // Register width information to check illegal writes${for_iface} | 
 |   parameter logic [3:0] ${upfx}_PERMIT [${len(rb.flat_regs)}] = '{ | 
 |   % for i, r in enumerate(rb.flat_regs): | 
 | <% | 
 |   index_str = "{}".format(i).rjust(idx_len) | 
 |   width = r.get_width() | 
 |   if width > 24: | 
 |     mask = '1111' | 
 |   elif width > 16: | 
 |     mask = '0111' | 
 |   elif width > 8: | 
 |     mask = '0011' | 
 |   else: | 
 |     mask = '0001' | 
 |  | 
 |   comma = ',' if i < len(rb.flat_regs) - 1 else ' ' | 
 | %>\ | 
 |     4'b ${mask}${comma} // index[${index_str}] ${ublock}_${r.name.upper()} | 
 |   % endfor | 
 |   }; | 
 | % endif | 
 | </%def>\ | 
 |  | 
 | package ${lblock}_reg_pkg; | 
 | % if localparams: | 
 |  | 
 |   // Param list | 
 | % for param in localparams: | 
 |   parameter ${param.param_type} ${param.name} = ${param.value}; | 
 | % endfor | 
 | % endif | 
 |  | 
 |   // Address widths within the block | 
 | % for param_name, width in addr_widths.values(): | 
 |   parameter int ${param_name} = ${width}; | 
 | % endfor | 
 | <% | 
 |   just_default = len(block.reg_blocks) == 1 and None in block.reg_blocks | 
 | %>\ | 
 | % for iface_name, rb in block.reg_blocks.items(): | 
 | <% | 
 |   iface_desc = iface_name or 'default' | 
 |   for_iface = '' if just_default else ' for {} interface'.format(iface_desc) | 
 | %>\ | 
 | ${typedefs_for_iface(iface_name, iface_desc, for_iface, rb)}\ | 
 | ${reg2hw_for_iface(iface_name, iface_desc, for_iface, rb)}\ | 
 | ${hw2reg_for_iface(iface_name, iface_desc, for_iface, rb)}\ | 
 | ${offsets_for_iface(iface_name, iface_desc, for_iface, rb)}\ | 
 | ${hwext_resvals_for_iface(iface_name, iface_desc, for_iface, rb)}\ | 
 | ${windows_for_iface(iface_name, iface_desc, for_iface, rb)}\ | 
 | ${reg_data_for_iface(iface_name, iface_desc, for_iface, rb)}\ | 
 | % endfor | 
 |  | 
 | endpackage | 
 |  |