393 lines
11 KiB
Smarty
393 lines
11 KiB
Smarty
// 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
|
|
|