| // 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.register import Register |
| from reggen.multi_register import MultiRegister |
| |
| flat_regs = block.reg_block.flat_regs |
| num_regs = len(flat_regs) |
| max_regs_char = len("{}".format(num_regs - 1)) |
| localparams = block.params.get_localparams() |
| %>\ |
| package ${block.name}_reg_pkg; |
| % if localparams: |
| |
| // Param list |
| % endif |
| % for param in localparams: |
| parameter ${param.param_type} ${param.name} = ${param.value}; |
| % endfor |
| |
| // Address width within the block |
| parameter int BlockAw = ${block.addr_width}; |
| |
| //////////////////////////// |
| // Typedefs for registers // |
| //////////////////////////// |
| % for r in block.reg_block.all_regs: |
| % if r.get_n_bits(["q"]): |
| <% |
| if isinstance(r, Register): |
| r0 = r |
| type_suff = 'reg_t' |
| else: |
| assert isinstance(r, MultiRegister) |
| r0 = r.reg |
| type_suff = 'mreg_t' |
| |
| reg2hw_name = ('{}_reg2hw_{}_{}' |
| .format(block.name, r0.name.lower(), type_suff)) |
| %>\ |
| 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, ['q']) |
| field_q_bits = lib.bitarray(field_q_width, 2) |
| %>\ |
| logic ${field_q_bits} q; |
| % if field.hwqe: |
| logic qe; |
| % endif |
| % if field.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: |
| % if f.get_n_bits(r0.hwext, ["q"]) >= 1: |
| <% |
| field_q_width = f.get_n_bits(r0.hwext, ['q']) |
| field_q_bits = lib.bitarray(field_q_width, 2) |
| |
| struct_name = f.name.lower() |
| %>\ |
| struct packed { |
| logic ${field_q_bits} q; |
| % if f.hwqe: |
| logic qe; |
| % endif |
| % if f.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 |
| } ${reg2hw_name}; |
| |
| %endif |
| % endfor |
| |
| % for r in block.reg_block.all_regs: |
| % if r.get_n_bits(["d"]): |
| <% |
| if isinstance(r, Register): |
| r0 = r |
| type_suff = 'reg_t' |
| else: |
| assert isinstance(r, MultiRegister) |
| r0 = r.reg |
| type_suff = 'mreg_t' |
| |
| hw2reg_name = ('{}_hw2reg_{}_{}' |
| .format(block.name, r0.name.lower(), type_suff)) |
| %>\ |
| 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, ['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: |
| % if f.get_n_bits(r0.hwext, ["d"]) >= 1: |
| <% |
| field_d_width = f.get_n_bits(r0.hwext, ['d']) |
| 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 |
| } ${hw2reg_name}; |
| |
| % endif |
| % endfor |
| |
| /////////////////////////////////////// |
| // Register to internal design logic // |
| /////////////////////////////////////// |
| <% |
| nbits = block.reg_block.get_n_bits(["q", "qe", "re"]) |
| packbit = 0 |
| %>\ |
| % if nbits > 0: |
| typedef struct packed { |
| % for r in block.reg_block.all_regs: |
| % if r.get_n_bits(["q"]): |
| <% |
| if isinstance(r, MultiRegister): |
| r0 = r.reg |
| repl_count = r.count |
| type_suff = 'mreg_t [{}:0]'.format(repl_count - 1) |
| else: |
| r0 = r |
| repl_count = 1 |
| type_suff = 'reg_t' |
| |
| struct_type = ('{}_reg2hw_{}_{}' |
| .format(block.name, r0.name.lower(), type_suff)) |
| |
| struct_width = r0.get_n_bits(['q', 'qe', 're']) * repl_count |
| msb = nbits - packbit - 1 |
| lsb = msb - struct_width + 1 |
| packbit += struct_width |
| %>\ |
| ${struct_type} ${r0.name.lower()}; // [${msb}:${lsb}] |
| % endif |
| % endfor |
| } ${block.name}_reg2hw_t; |
| % endif |
| |
| /////////////////////////////////////// |
| // Internal design logic to register // |
| /////////////////////////////////////// |
| <% |
| nbits = block.reg_block.get_n_bits(["d", "de"]) |
| packbit = 0 |
| %>\ |
| % if nbits > 0: |
| typedef struct packed { |
| % for r in block.reg_block.all_regs: |
| % if r.get_n_bits(["d"]): |
| <% |
| if isinstance(r, MultiRegister): |
| r0 = r.reg |
| repl_count = r.count |
| type_suff = 'mreg_t [{}:0]'.format(repl_count - 1) |
| else: |
| r0 = r |
| repl_count = 1 |
| type_suff = 'reg_t' |
| |
| struct_type = ('{}_hw2reg_{}_{}' |
| .format(block.name, r0.name.lower(), type_suff)) |
| |
| struct_width = r0.get_n_bits(['d', 'de']) * repl_count |
| msb = nbits - packbit - 1 |
| lsb = msb - struct_width + 1 |
| packbit += struct_width |
| %>\ |
| ${struct_type} ${r0.name.lower()}; // [${msb}:${lsb}] |
| % endif |
| % endfor |
| } ${block.name}_hw2reg_t; |
| % endif |
| |
| // Register Address |
| <% |
| ublock = block.name.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()) |
| |
| %>\ |
| % for r in flat_regs: |
| parameter logic [BlockAw-1:0] ${reg_pfx(r)}_OFFSET = ${block.addr_width}'h ${"%x" % r.offset}; |
| % endfor |
| |
| <% |
| hwext_regs = [r for r in flat_regs if r.hwext] |
| %>\ |
| % if hwext_regs: |
| // Reset values for hwext registers and their fields |
| % for reg in hwext_regs: |
| <% |
| reg_width = reg.get_width() |
| reg_msb = reg_width - 1 |
| %>\ |
| parameter logic [${reg_msb}:0] ${reg_resname(reg)} = ${"{}'h {:x}".format(reg_width, reg.resval)}; |
| % for field in reg.fields: |
| % if field.resval is not None: |
| <% |
| field_width = field.bits.width() |
| field_msb = field_width - 1 |
| %>\ |
| parameter logic [${field_msb}:0] ${field_resname(reg, field)} = ${"{}'h {:x}".format(field_width, field.resval)}; |
| % endif |
| % endfor |
| % endfor |
| |
| % endif |
| % if len(block.reg_block.windows) > 0: |
| // Window parameter |
| % for i,w in enumerate(block.reg_block.windows): |
| <% |
| win_pfx = '{}_{}'.format(ublock, w.name.upper()) |
| base_txt_val = "{}'h {:x}".format(block.addr_width, w.offset) |
| size_txt_val = "{}'h {:x}".format(block.addr_width, w.size_in_bytes) |
| %>\ |
| parameter logic [BlockAw-1:0] ${win_pfx}_OFFSET = ${base_txt_val}; |
| parameter logic [BlockAw-1:0] ${win_pfx}_SIZE = ${size_txt_val}; |
| % endfor |
| |
| % endif |
| // Register Index |
| typedef enum int { |
| % for r in flat_regs: |
| ${ublock}_${r.name.upper()}${"" if loop.last else ","} |
| % endfor |
| } ${block.name}_id_e; |
| |
| // Register width information to check illegal writes |
| parameter logic [3:0] ${ublock}_PERMIT [${len(flat_regs)}] = '{ |
| % for i,r in enumerate(flat_regs): |
| <% |
| index_str = "{}".format(i).rjust(max_regs_char) |
| width = r.get_width() |
| %>\ |
| % if width > 24: |
| 4'b 1111${" " if i == num_regs-1 else ","} // index[${index_str}] ${ublock}_${r.name.upper()} |
| % elif width > 16: |
| 4'b 0111${" " if i == num_regs-1 else ","} // index[${index_str}] ${ublock}_${r.name.upper()} |
| % elif width > 8: |
| 4'b 0011${" " if i == num_regs-1 else ","} // index[${index_str}] ${ublock}_${r.name.upper()} |
| % else: |
| 4'b 0001${" " if i == num_regs-1 else ","} // index[${index_str}] ${ublock}_${r.name.upper()} |
| % endif |
| % endfor |
| }; |
| endpackage |
| |