Access Type: WO (Write Only)
Relevant source files
The following files were used as context for generating this wiki page:The regif tool supports various register access types for generating Verilog register interface modules. The WO (Write Only) access type is used to define register fields that can be written to by a bus interface (e.g., bmi_bus) but cannot be read from. This is a common pattern for registers that trigger actions, clear status bits, or write data to a resource like a FIFO where a read-back is not meaningful or desired.
When a field is designated as WO, the generator creates logic to update an internal register on a write operation. However, any attempt to read from the register address containing a WO field will return a hardcoded value of 0 for those bits, effectively making it write-only from the bus perspective. The WO type is one of several access types supported, including RW, RO, and RC.
Sources: readme.md:41, regif.py:80, regif.py:640-642
Core Functionality
The primary role of a WO field is to capture data from the bus during a write cycle. The generated Verilog ensures that this happens only when the bmi_wr signal is active and the bmi_addr matches the register's address.
Sources: regif.py:158-162
Verilog Generation for Write Operations
For a standard WO field, the value of the bmi_wdata bus is latched into the corresponding internal register when a valid write occurs. The RegFields class identifies WO fields and includes them in the list of fields to be updated during a write operation.
The following diagram illustrates the logic flow for a bus write to a register containing a WO field.
This diagram shows the conditions required to update a WO register field.
The Verilog code for this is generated from the W_ALWAYS_L3 and W_L1 templates.
// From W_ALWAYS_L3 template
always @(posedge bmi_clk or negedge bmi_rstn)
if(!bmi_rstn) begin
// ... reset logic ...
if_name <= {rstval:14} ; // From W_RST_L1
end else if(bmi_wr && (bmi_addr==`{reg_name})) begin
// ... other write logic ...
if_name <= bmi_wdata{section:7};//WO // From W_L1
end
Sources: regif.py:158-162, regif.py:171
Verilog Generation for Read Operations
When a read operation occurs on a register containing a WO field, the regif generator ensures that the bits corresponding to the WO field return 0. The read_express method in the RegFields class explicitly handles this case.
# regif.py:640-642
if (fd.type in ("WO", "BP", "CP")) or (fd.name == "RESERVED"):
_read += "{}\'b0,".format(fd.bits_width)
This logic is embedded within a larger case statement for the read address map.
// From R_ALWAYS and R_L2 templates
case(bmi_addr)
`MY_REG_ADDR : begin bmi_rdvld <= 1'b1; bmi_rdata <= {..., N'b0, ...} ;end // N is the width of the WO field
// ... other registers
endcase
Sources: regif.py:207-220, regif.py:638-642
Special Features
The WO access type also integrates with other advanced features of the regif generator, such as clock gating and FIFO interfaces.
Clock Gating (rw_cg)
If clock gating is enabled for write operations (rw_cg option is "YES" in the Excel file), WO fields are included in the clock-gated logic. This is an optimization to reduce power consumption by only clocking the registers when a write is occurring. The cg_type tuple explicitly includes 'WO'.
The generation logic uses the W_CG_ALWAYS_L3 template instead of W_ALWAYS_L3, and the always block is sensitive to the gated clock (bmi_clk_wr_cg).
| Feature | Description | Relevant Code |
|---|---|---|
| Clock Gating | WO fields can be placed under a clock gate to save power. | rw_cg property in Regif class |
| Enabling Tuple | 'WO' is part of the cg_type tuple, enabling this feature. | RegFields class: self.cg_type = ("RW", "WO", "RWT") |
| Verilog Template | A specific template W_CG_ALWAYS_L3 is used for gated writes. | regif.py:151-155 |
Sources: regif.py:413, regif.py:1000, regif.py:151-155
FIFO Interface (FIFO_IF)
A register can be marked with the FIFO_IF property. If a field within this register is of type WO, it is not synthesized as a storage register. Instead, it is treated as a data input to a FIFO, and a _push signal is generated.
The fifomap method in the Field class is responsible for this behavior. When called for a WO field within a FIFO_IF register, it generates an assignment for the FIFO's write data. The fifo_push_declar method generates the _push signal logic.
This sequence diagram shows how a write to a WO field in a FIFO_IF register results in a FIFO push.
This diagram shows the interaction when writing to a WO field that is part of a FIFO interface.
The generated Verilog for this case is based on the FIFO_PUSH_L4 and FIFOMAP templates.
// From FIFO_PUSH_L4
//-------------------------------------------------------------------
//{addr} : {reg_name} FIFO interface
wire {reg_name}_push ;
assign {reg_name}_push = bmi_wr && (bmi_addr==`{reg_name});
// From FIFOMAP, generated by fifomap() method
//assign {if_name:20} = fifo_rdata{section:8} ; // Note: This template seems to be for read, but the logic implies a write mapping. The python code `fifo_map` is only called for WO type.
Sources: regif.py:355, regif.py:615-617, regif.py:126-130, regif.py:107
Summary
The WO access type is a fundamental feature of the regif tool, providing a standardized method for creating write-only register fields. It correctly models the behavior of writing data from a bus and ensures that reads return a benign value of zero. Its integration with advanced features like clock gating and FIFO interfaces makes it a versatile tool for efficient and complex hardware design, automating what would otherwise be a manual and error-prone coding task.