Generated Output: Verilog Wrapper (_wrap.v)
Relevant source files
The following files were used as context for generating this wiki page:
The regif tool can generate a Verilog wrapper file, {modulename}_regif_wrap.v, under specific conditions. This wrapper extends the functionality of the primary register interface module ({modulename}_regif.v) by adding a hardware-side clock domain and logic for implementing lockable registers. The generation of this file is not default; it is triggered only when at least one register field is defined with a locksig attribute.
The primary purpose of the wrapper is to provide a mechanism to protect certain registers from being written to after an initial configuration, a scenario described as "configure lockable" in the project's documentation. This is achieved by instantiating the main register module and adding a layer of logic controlled by external hardware signals (hw_clk, hw_rstn, and one or more lock_sig inputs).
Sources: regif.py:1300-1304, readme.md:47
Generation Trigger
The {modulename}_regif_wrap.v file is generated if and only if the genverilog function detects that lockable fields are present in the register definition Excel file. The script determines this by calling getlockdict(), which scans all register fields. If it finds a field with a non-empty lock_sig attribute and the field's type is not inherently unlocked (e.g., not RO, RC, RWT), it is considered a lockable field. The presence of any such field will trigger the wrapper file's generation.
Sources: regif.py:1260-1268, regif.py:1300-1304, regif.py:904-906
The following diagram illustrates the logic for generating the wrapper file.
This diagram shows the conditional generation flow for the _regif_wrap.v file based on the presence of lock signals.
Sources: regif.py:1290-1304
Wrapper Architecture
The wrapper module serves as a container for the main _regif.v module, adding external ports and logic to handle the register locking mechanism.
This diagram illustrates the architecture of the _regif_wrap.v module, showing how it wraps the main _regif.v instance and adds the locking logic in a separate hardware clock domain.
Sources: regif.py:328-359
Key Components
1. Module Definition
The wrapper module includes all the ports of the base _regif.v module, plus additional inputs for the locking functionality.
| Port | Direction | Description |
|---|---|---|
hw_clk | input | Clock for the hardware-side locking logic. |
hw_rstn | input | Active-low reset for the hardware-side locking logic. |
<lock_sig> | input | One or more signals defined in the Excel sheet to control the locking of registers. |
| ...other BMI ports | input/output | Standard BMI interface ports passed to the inner _regif module. |
Sources: regif.py:331-333, regif.py:1276
The module definition is generated from the WFILE template string.
module {modulename}_regif_wrap(/*autoarg*/
{wioports}
);
input hw_clk ;
input hw_rstn ;
{bmi_io}{lock_io}{iodeclars}
//...
endmodule
Sources: regif.py:328-359
2. _regif Module Instantiation
The wrapper instantiates the main {modulename}_regif module, connecting the BMI (Bus Master Interface) ports directly. The outputs of the _regif module that correspond to lockable fields are then used by the locking logic.
{modulename}_regif u_{modulename}_regif(
.bmi_clk (bmi_clk ),//i
.bmi_rstn (bmi_rstn ),//i
.bmi_rd (bmi_rd ),//i
.bmi_wr (bmi_wr ),//i
.bmi_addr (bmi_addr ),//i
.bmi_wdata (bmi_wdata ),//i
.bmi_rdata (bmi_rdata ),//o
.bmi_rdvld (bmi_rdvld ),//o
{instports}
);
Sources: regif.py:342-352
3. Locking Logic
The core of the wrapper's functionality is the locking logic, generated by the gen_lock_segment function. This function creates one or more always blocks, one for each unique lock_sig found.
This logic operates on the hw_clk and hw_rstn domain.
- On reset (
!hw_rstn): The locked register fields are set to their specified reset values. - When the lock is enabled (
lock_en): The values from the corresponding outputs of theu_{modulename}_regifinstance are passed through to the final wrapper outputs. This effectively "locks" the register values, as they can no longer be changed by BMI writes once thelock_ensignal is de-asserted.
The structure of this logic is defined by the LOCK_ALWAYS_L2 template:
always @(posedge hw_clk or negedge hw_rstn)
if(!hw_rstn) begin{lock_rsts}
end else if({lock_en}) begin
{lock_express} end
Sources: regif.py:318-326, regif.py:1269-1277
The {lock_express} part is filled with assignments like:
o_reg_pre_FIELD_NAME <= reg_pre_FIELD_NAME;
This shows that when the lock signal is active, the output of the wrapper (o_...) follows the output of the internal register file. If the lock signal is inactive, the flip-flop holds its value, preventing updates.
Sources: regif.py:315-316, regif.py:905
Data Flow for a Locked Register
The diagram below shows the data path for a write to a lockable register field.
This sequence shows how a write operation updates an internal register, but the final output is only updated when the corresponding lock signal is active.
Sources: regif.py:318-326, regif.py:1260-1277
Conclusion
The {modulename}_regif_wrap.v file is a key feature for designs requiring secure, lockable configurations. It is automatically generated by the regif tool (version 1.3.3 and later) when fields are marked with a locksig. By separating the bus clock domain from a hardware clock domain, it provides a robust mechanism to prevent unintended or malicious modification of critical registers after system initialization, instantiating the base register file and adding a layer of protection around it.
Sources: regif.py, setup.py:8