Advanced Feature: Reset Strategy
Relevant source files
The following files were used as context for generating this wiki page. While the project is primarily contained within a single script, related project files are included for comprehensive context.
The regif tool provides a flexible and configurable reset strategy for the generated Verilog register interface modules. This allows developers to adapt the reset behavior to various design requirements, including synchronous or asynchronous resets, with either active-high or active-low polarity. The entire strategy is controlled through a simple setting in the input Excel file, which injects a Verilog macro into the generated code.
This feature was introduced in version 1.3.3 to enhance the tool's adaptability to different hardware integration standards. The core of this functionality lies in a predefined Verilog macro, ctrl_always_ff_begin, which abstracts the reset condition within always blocks.
Sources: regif.py:15, regif.py:1330, readme.md:50
The Configurable Reset Macro
The reset strategy is implemented via a Verilog define macro named RESET_MACRO. This macro is conditionally included in the generated Verilog file based on a configuration setting in the source Excel file.
Sources: regif.py:302-303, regif.py:1330-1331
Macro Definition
The RESET_MACRO defines ctrl_always_ff_begin, which standardizes the beginning of a sequential always block. It uses ifdef directives to select the correct reset logic based on project-wide Verilog defines.
`ifndef __reset_macro_vh__
`define __reset_macro_vh__
`ifdef CTRL_RESET_ASYNC_LOW
`define ctrl_always_ff_begin(clk,rst) always @(posedge clk or negedge rst) if(!rst) begin
`elsif CTRL_RESET_ASYNC_HIGH
`define ctrl_always_ff_begin(clk,rst) always @(posedge clk or posedge rst) if(rst) begin
`elsif CTRL_RESET_SYNC_LOW
`define ctrl_always_ff_begin(clk,rst) always @(posedge clk) if(!rst) begin
`elsif CTRL_RESET_SYNC_HIGH
`define ctrl_always_ff_begin(clk,rst) always @(posedge clk) if(rst) begin
`else
`define ctrl_always_ff_begin(clk,rst) always @(posedge clk or negedge rst) if(!rst) begin
`endif
`endif
Sources: regif.py:284-298
Supported Reset Types
The macro supports four explicit reset strategies and a default case.
ifdef Condition | Resulting always Block Header | Description |
|---|---|---|
CTRL_RESET_ASYNC_LOW | always @(posedge clk or negedge rst) if(!rst) begin | Asynchronous, active-low reset. |
CTRL_RESET_ASYNC_HIGH | always @(posedge clk or posedge rst) if(rst) begin | Asynchronous, active-high reset. |
CTRL_RESET_SYNC_LOW | always @(posedge clk) if(!rst) begin | Synchronous, active-low reset. |
CTRL_RESET_SYNC_HIGH | always @(posedge clk) if(rst) begin | Synchronous, active-high reset. |
else (Default) | always @(posedge clk or negedge rst) if(!rst) begin | Defaults to asynchronous, active-low reset. |
Sources: regif.py:286-296
Configuration
The activation of the reset macro feature is controlled by a specific cell in the input Excel spreadsheet.
Enabling the Macro
In the Regif class constructor, the script checks cell F6 (row index 5, column index 10) in the Excel sheet. If its value is "YES" (case-insensitive), the RESET_MACRO string is stored and later written to the Verilog file.
# regif.py:1330-1331
self.always_ff_begin = ALWAYS_BEGIN_MACRO if(bs.cell(5,10).value.upper() == "YES") else ALWAYS_BEGIN
self.macros = RESET_MACRO if(bs.cell(5,10).value.upper()=="YES") else ""
If the cell value is not "YES", a default, non-macro-based always block header is used:
# regif.py:114-115
ALWAYS_BEGIN = '''always @(posedge bmi_clk or negedge bmi_rstn)
if(!bmi_rstn) begin '''
The following diagram illustrates this configuration flow.
Sources: regif.py:114-116, regif.py:1330-1331
Implementation in Generated Code
The configured reset strategy is applied to all sequential logic blocks (always blocks) throughout the generated register interface module.
Reset Logic Application
The always_ff_begin property, which holds either the macro call or the hardcoded string, is used in all Verilog templates for always blocks.
This diagram shows the structure of a typical write logic block for a register field.
Sources: regif.py:141-145, regif.py:150-153
Two primary reset signals are used:
bmi_rstn: The bus interface reset, used for logic clocked bybmi_clk.hw_rstn: The hardware-side reset, used for lock logic clocked byhw_clk.
Example usage in a write logic template:
# regif.py:150-153
W_ALWAYS_L3 = \
'''{always_ff_begin}{field_rst}
end else if(bmi_wr && (bmi_addr==`{reg_name})) begin{normal_wr}{rwt_wr}{protect_wr}{else_part}
end
'''
Here, {always_ff_begin} is replaced by the configured macro or string, and {field_rst} contains the reset assignments for each field.
Sources: regif.py:273-277, regif.py:150-154
Field-Level Reset Values
Each register field's reset value is specified in the "reset" column of the input Excel file. The script parses and validates this value.
Format and Validation
The reset value must be specified in one of the following Verilog formats:
width'h[hex_value]width'd[dec_value]width'b[bin_value]0(which is treated as a special case)
The format is enforced by a regular expression:
# regif.py:73
("reset ", r"(\d+'(h|H)[\da-fA-F]+\Z|\d+'(d|D)\d+\Z|\d+'(b|B)[01]+\Z|0\Z)", '''"0","3'd7", "12'hFFF", "2'b11"'''),
The Field.rst_val_check() method performs a dynamic check to ensure the specified bit width in the reset value matches the field's width and that the value does not exceed the maximum for that width.
Sources: regif.py:73, regif.py:882-905
Applying the Reset
During code generation, the reset value is applied within the initial if condition of the always block using the W_RST_L1 template.
# regif.py:139-140
W_RST_L1 = \
"\n {if_name:{fd_align}} <= {rstval:14} ;"
This template populates the reset section of the always block for each register field that has a reset behavior (e.g., RW, WO, RWT).
Sources: regif.py:139-140, regif.py:641
Summary
The reset strategy in regif is a powerful feature that enhances the tool's utility by allowing seamless integration into diverse hardware environments. By leveraging a configurable Verilog macro controlled from the input Excel file, it supports various synchronous/asynchronous and active-high/low reset schemes. This, combined with per-field reset value specification and robust validation, ensures the generation of correct, flexible, and maintainable register interface RTL.
Sources: regif.py:15, regif.py:284-298, readme.md:50