blob: d1da4f4feff068baad691459d89978574ac21d17 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
<%!
from reggen import gen_dv
from reggen.access import HwAccess, SwRdAccess, SwWrAccess
%>
##
##
## make_ral_pkg
## ============
##
## Generate the RAL package for a device interface.
##
## dv_base_prefix a string naming the base register type. If it is FOO,
## then we will inherit from FOO_reg (assumed to
## be a subclass of uvm_reg).
##
## reg_width an integer giving the width of registers in bits
##
## reg_block_path the hierarchical path to the relevant register block in the
## design
##
## rb a RegBlock object
##
## esc_if_name a string giving the full, escaped, interface name. For
## a device interface called FOO on block BAR,
## this will be bar__foo. For an unnamed interface
## on block BAR, this will be just bar.
##
<%def name="make_ral_pkg(dv_base_prefix, reg_width, reg_block_path, rb, esc_if_name)">\
package ${esc_if_name}_ral_pkg;
${make_ral_pkg_hdr(dv_base_prefix, [])}
${make_ral_pkg_fwd_decls(esc_if_name, rb.flat_regs, rb.windows)}
% for reg in rb.flat_regs:
${make_ral_pkg_reg_class(dv_base_prefix, reg_width, esc_if_name, reg_block_path, reg)}
% endfor
% for window in rb.windows:
${make_ral_pkg_window_class(dv_base_prefix, esc_if_name, window)}
% endfor
<%
reg_block_name = gen_dv.bcname(esc_if_name)
%>\
class ${reg_block_name} extends ${dv_base_prefix}_reg_block;
% if rb.flat_regs:
// registers
% for r in rb.flat_regs:
rand ${gen_dv.rcname(esc_if_name, r)} ${r.name.lower()};
% endfor
% endif
% if rb.windows:
// memories
% for window in rb.windows:
rand ${gen_dv.mcname(esc_if_name, window)} ${gen_dv.miname(window)};
% endfor
% endif
`uvm_object_utils(${reg_block_name})
function new(string name = "${reg_block_name}",
int has_coverage = UVM_NO_COVERAGE);
super.new(name, has_coverage);
endfunction : new
virtual function void build(uvm_reg_addr_t base_addr,
csr_excl_item csr_excl = null);
// create default map
this.default_map = create_map(.name("default_map"),
.base_addr(base_addr),
.n_bytes(${reg_width//8}),
.endian(UVM_LITTLE_ENDIAN));
if (csr_excl == null) begin
csr_excl = csr_excl_item::type_id::create("csr_excl");
this.csr_excl = csr_excl;
end
% if rb.flat_regs:
set_hdl_path_root("tb.dut", "BkdrRegPathRtl");
set_hdl_path_root("tb.dut", "BkdrRegPathRtlCommitted");
set_hdl_path_root("tb.dut", "BkdrRegPathRtlShadow");
// create registers
% for r in rb.flat_regs:
<%
reg_name = r.name.lower()
reg_right = r.dv_rights()
reg_offset = "{}'h{:x}".format(reg_width, r.offset)
reg_tags = r.tags
reg_shadowed = r.shadowed
type_id_indent = ' ' * (len(reg_name) + 4)
%>\
${reg_name} = (${gen_dv.rcname(esc_if_name, r)}::
${type_id_indent}type_id::create("${reg_name}"));
${reg_name}.configure(.blk_parent(this));
${reg_name}.build(csr_excl);
default_map.add_reg(.rg(${reg_name}),
.offset(${reg_offset}),
.rights("${reg_right}"));
% if reg_shadowed:
${reg_name}.set_is_shadowed();
% endif
% if reg_tags:
// create register tags
% for reg_tag in reg_tags:
<%
tag = reg_tag.split(":")
%>\
% if tag[0] == "excl":
csr_excl.add_excl(${reg_name}.get_full_name(), ${tag[2]}, ${tag[1]});
% endif
% endfor
% endif
% endfor
<%
any_regwen = False
for r in rb.flat_regs:
if r.regwen:
any_regwen = True
break
%>\
% if any_regwen:
// assign locked reg to its regwen reg
% for r in rb.flat_regs:
% if r.regwen:
% for reg in rb.flat_regs:
% if r.regwen.lower() == reg.name.lower():
${r.regwen.lower()}.add_lockable_reg_or_fld(${r.name.lower()});
<% break %>\
% elif reg.name.lower() in r.regwen.lower():
% for field in reg.get_field_list():
% if r.regwen.lower() == (reg.name.lower() + "_" + field.name.lower()):
${r.regwen.lower()}.${field.name.lower()}.add_lockable_reg_or_fld(${r.name.lower()});
<% break %>\
% endif
% endfor
% endif
% endfor
% endif
% endfor
% endif
% endif
${make_ral_pkg_window_instances(reg_width, esc_if_name, rb)}
endfunction : build
endclass : ${reg_block_name}
endpackage
</%def>\
##
##
## make_ral_pkg_hdr
## ================
##
## Generate the header for a RAL package
##
## dv_base_prefix as for make_ral_pkg
##
## deps a list of names for packages that should be explicitly
## imported
##
<%def name="make_ral_pkg_hdr(dv_base_prefix, deps)">\
// dep packages
import uvm_pkg::*;
import dv_base_reg_pkg::*;
% if dv_base_prefix != "dv_base":
import ${dv_base_prefix}_reg_pkg::*;
% endif
% for dep in deps:
import ${dep}::*;
% endfor
// macro includes
`include "uvm_macros.svh"\
</%def>\
##
##
## make_ral_pkg_fwd_decls
## ======================
##
## Generate the forward declarations for a RAL package
##
## esc_if_name as for make_ral_pkg
##
## flat_regs a list of Register objects (expanding multiregs)
##
## windows a list of Window objects
##
<%def name="make_ral_pkg_fwd_decls(esc_if_name, flat_regs, windows)">\
// Forward declare all register/memory/block classes
% for r in flat_regs:
typedef class ${gen_dv.rcname(esc_if_name, r)};
% endfor
% for w in windows:
typedef class ${gen_dv.mcname(esc_if_name, w)};
% endfor
typedef class ${gen_dv.bcname(esc_if_name)};\
</%def>\
##
##
## make_ral_pkg_reg_class
## ======================
##
## Generate the classes for a register inside a RAL package
##
## dv_base_prefix as for make_ral_pkg
##
## reg_width as for make_ral_pkg
##
## esc_if_name as for make_ral_pkg
##
## reg_block_path as for make_ral_pkg
##
## reg a Register object
<%def name="make_ral_pkg_reg_class(dv_base_prefix, reg_width, esc_if_name, reg_block_path, reg)">\
<%
reg_name = reg.name.lower()
is_ext = reg.hwext
for field in reg.fields:
if (field.hwaccess.value[1] == HwAccess.NONE and
field.swaccess.swrd() == SwRdAccess.RD and
not field.swaccess.allows_write()):
is_ext = 1
class_name = gen_dv.rcname(esc_if_name, reg)
%>\
class ${class_name} extends ${dv_base_prefix}_reg;
// fields
% for f in reg.fields:
rand ${dv_base_prefix}_reg_field ${f.name.lower()};
% endfor
`uvm_object_utils(${class_name})
function new(string name = "${class_name}",
int unsigned n_bits = ${reg_width},
int has_coverage = UVM_NO_COVERAGE);
super.new(name, n_bits, has_coverage);
endfunction : new
virtual function void build(csr_excl_item csr_excl = null);
// create fields
% for field in reg.fields:
<%
if len(reg.fields) == 1:
reg_field_name = reg_name
else:
reg_field_name = reg_name + "_" + field.name.lower()
%>\
${_create_reg_field(dv_base_prefix, reg_width, reg_block_path, reg.shadowed, reg.hwext, reg_field_name, field)}
% endfor
% if reg.shadowed and reg.hwext:
<%
shadowed_reg_path = ''
for tag in reg.tags:
parts = tag.split(':')
if parts[0] == 'shadowed_reg_path':
shadowed_reg_path = parts[1]
if not shadowed_reg_path:
print("ERROR: ext shadow_reg does not have tags for shadowed_reg_path!")
assert 0
bit_idx = reg.fields[-1].bits.msb + 1
%>\
add_update_err_alert("${reg.update_err_alert}");
add_storage_err_alert("${reg.storage_err_alert}");
add_hdl_path_slice("${shadowed_reg_path}.committed_reg.q",
0, ${bit_idx}, 0, "BkdrRegPathRtlCommitted");
add_hdl_path_slice("${shadowed_reg_path}.shadow_reg.q",
0, ${bit_idx}, 0, "BkdrRegPathRtlShadow");
% endif
% if is_ext:
set_is_ext_reg(1);
% endif
endfunction : build
endclass : ${class_name}\
</%def>\
##
##
## _create_reg_field
## =================
##
## Generate the code that creates a uvm_reg_field object for a field
## in a register.
##
## dv_base_prefix as for make_ral_pkg
##
## reg_width as for make_ral_pkg
##
## reg_block_path as for make_ral_pkg
##
## shadowed true if the field's register is shadowed
##
## hwext true if the field's register is hwext
##
## reg_field_name a string with the name to give the field in the HDL
##
## field a Field object
<%def name="_create_reg_field(dv_base_prefix, reg_width, reg_block_path, shadowed, hwext, reg_field_name, field)">\
<%
field_size = field.bits.width()
if field.swaccess.key == "r0w1c":
field_access = "W1C"
else:
field_access = field.swaccess.value[1].name
if not field.hwaccess.allows_write():
field_volatile = 0
else:
field_volatile = 1
field_tags = field.tags
fname = field.name.lower()
type_id_indent = ' ' * (len(fname) + 4)
%>\
${fname} = (${dv_base_prefix}_reg_field::
${type_id_indent}type_id::create("${fname}"));
${fname}.configure(
.parent(this),
.size(${field_size}),
.lsb_pos(${field.bits.lsb}),
.access("${field_access}"),
.volatile(${field_volatile}),
.reset(${reg_width}'h${format(field.resval or 0, 'x')}),
.has_reset(1),
.is_rand(1),
.individually_accessible(1));
${fname}.set_original_access("${field_access}");
% if ((field.hwaccess.value[1] == HwAccess.NONE and\
field.swaccess.swrd() == SwRdAccess.RD and\
not field.swaccess.allows_write())):
// constant reg
add_hdl_path_slice("${reg_block_path}.${reg_field_name}_qs",
${field.bits.lsb}, ${field_size}, 0, "BkdrRegPathRtl");
% else:
add_hdl_path_slice("${reg_block_path}.u_${reg_field_name}.q${"s" if hwext else ""}",
${field.bits.lsb}, ${field_size}, 0, "BkdrRegPathRtl");
% endif
% if shadowed and not hwext:
add_hdl_path_slice("${reg_block_path}.u_${reg_field_name}.committed_reg.q",
${field.bits.lsb}, ${field_size}, 0, "BkdrRegPathRtlCommitted");
add_hdl_path_slice("${reg_block_path}.u_${reg_field_name}.shadow_reg.q",
${field.bits.lsb}, ${field_size}, 0, "BkdrRegPathRtlShadow");
% endif
% if field_tags:
// create field tags
% for field_tag in field_tags:
<%
tag = field_tag.split(":")
%>\
% if tag[0] == "excl":
csr_excl.add_excl(${field.name.lower()}.get_full_name(), ${tag[2]}, ${tag[1]});
% endif
% endfor
% endif
</%def>\
##
##
## make_ral_pkg_window_class
## =========================
##
## Generate the classes for a window inside a RAL package
##
## dv_base_prefix as for make_ral_pkg
##
## esc_if_name as for make_ral_pkg
##
## window a Window object
<%def name="make_ral_pkg_window_class(dv_base_prefix, esc_if_name, window)">\
<%
mem_name = window.name.lower()
mem_right = window.swaccess.dv_rights()
mem_n_bits = window.validbits
mem_size = window.items
class_name = gen_dv.mcname(esc_if_name, window)
%>\
class ${class_name} extends ${dv_base_prefix}_mem;
`uvm_object_utils(${class_name})
function new(string name = "${class_name}",
longint unsigned size = ${mem_size},
int unsigned n_bits = ${mem_n_bits},
string access = "${mem_right}",
int has_coverage = UVM_NO_COVERAGE);
super.new(name, size, n_bits, access, has_coverage);
% if window.byte_write:
set_mem_partial_write_support(1);
% endif
endfunction : new
endclass : ${class_name}
</%def>\
##
##
## make_ral_pkg_window_instances
## =============================
##
## Generate the classes for a window inside a RAL package
##
## reg_width as for make_ral_pkg
##
## esc_if_name as for make_ral_pkg
##
## rb a RegBlock object
##
<%def name="make_ral_pkg_window_instances(reg_width, esc_if_name, rb)">\
% if rb.windows:
// create memories
% for w in rb.windows:
<%
mem_name = w.name.lower()
mem_right = w.swaccess.dv_rights()
mem_offset = "{}'h{:x}".format(reg_width, w.offset)
mem_n_bits = w.validbits
mem_size = w.items
%>\
${mem_name} = ${gen_dv.mcname(esc_if_name, w)}::type_id::create("${mem_name}");
${mem_name}.configure(.parent(this));
default_map.add_mem(.mem(${mem_name}),
.offset(${mem_offset}),
.rights("${mem_right}"));
% endfor
% endif
</%def>\