Structure
In systemverilog, struct is introduced to pack some signals into an integrated signal.
Advantage
Code length can be significantly reduced.
Code readability is improved.
Maintenance cost of code is significantly reduced.
Defination
The defination of struct is shown below:
// AXI AW channel
typedef struct packed {
logic [AXI_AW_ID_WIDTH-1:0] id ;
logic [AXI_AW_ADDR_WIDTH-1:0] addr ;
logic [AXI_AW_LEN_WIDTH-1:0] len ;
logic [AXI_AW_SIZE_WIDTH-1:0] size ;
logic [1:0] burst ;
logic lock ;
logic [3:0] cache ;
logic [2:0] prot ;
logic [3:0] qos ;
axi_aw_userbit_pack user ; // another struct
} axi_aw_pack;
In this example, it can be concluded that struct can be nested. The struct of “axi_aw_pack” nests the struct of “axi_aw_userbit_pack”.
In addition, if some field is deleted or added, or its width is changed, you only need to update the struct defination rather than update all code this field involved. It is the advantage for maintenance cost of code.
invoking
Struct can be invoked to define both IO and internal signal. For example:
// a reg slice defination
// support three mode: forward mode (4'b0001), backward mode (4'b0010), full mode (4'b0100), and bypass mode (4'b1000)
module reg_slice#(
parameter logic [2:0] FUNC_MODE = 4'b0001
parameter type PLD_TYPE = axi_aw_pack
)(
input logic clk ,
input logic rst_n ,
input logic s_vld ,
output logic s_rdy ,
input PLD_TYPE s_pld , // invoked for IO
output logic m_vld ,
input logic m_rdy ,
output PLD_TYPE m_pld // invoked for IO
);
......
PLD_TYPE pld_buffer ; // invoked for internal signal
......
// Main Code Start
......
// Main Code End
endmodule
// instance 1: forward mode
reg_slice #(
.FUNC_MODE (4'b0001 ),
.PLD_TYPE (axi_aw_pack )) // passed into instance
u_rs_gpu_aw(
.clk (clk ),
.rst_n (rst_n ),
.s_vld (gpu_aw_vld ),
.s_rdy (gpu_aw_rdy ),
.s_pld (gpu_aw_pld ),
.m_vld (gpu_aw_vld_rs ),
.m_rdy (gpu_aw_rdy_rs ),
.m_pld (gpu_aw_pld_rs )
);
For this example, struct is used as a special parameter. And both IO and internal signal releated to payload are defined by this struct. When the module is instantiated, this struct is passed in fromat of parameter.
accessing
You can use the foramt of “struct_signal.internal_field” to access the desired field.
And the struct type signal can be assigened as a whole just using a blocking or nonblocking assignment, which is very usefull in reset phase and clear operation.
The following code shows the goal mentioned above:
// replace original qos with configured value
always_comb begin
aw_pld_new = aw_pld ; // assign all
aw_pld_new.qos = rf_write_qos ; // re-assign a desired field
end
// reset struct type registers
always_ff @(posedge clk or negedge rst_n) begin
if(~rst_n)
aw_pld_buffer <= {$bits(axi_aw_pack){1'b0}} ; // reset all
else if(aw_vld && aw_rdy)
aw_pld_buffer <= aw_pld ;
end