网站的页面设计/个人网站设计作品
数字硬件建模SystemVerilog-使用结构体和联合体的例子

使用结构体和联合体的例子
结构体和联合体可以包括压缩或非压缩数组,压缩结构体或联合体只能包括压缩数组。

压缩和非压缩的数组可以将结构体和联合体作为元素包含在数组中。在压缩数组中,结构体或联合体也必须是压缩的。

数组可以包含自定义结构体和自定义联合体。综合支持数组中的压缩或非压缩结构体。
示例4-8说明了如何使用结构体数组,该示例是一个指令寄存器模型,其中包含32条指令的非压缩数组,每条指令是一个复合值,表示为压缩结构体。指令中的操作数可以是有符号的或无符号的,表示为两种类型的联合体。
该指令寄存器的输入包括单独的操作数、一个操作码和一个指示操作数是有符号的还是无符号的标志。该模型将这些单独的输入值加载到指令寄存器阵列中。一种写入指针输入控件,用于加载数据。该模型的输出是单个指令结构体,使用读指针输入从指令寄存器中选择。
本例使用了前面示例4-6中所示的相同包项。
示例4-6:包含结构体和联合体定义的包//
// Package with union and structure definitions
//
//`begin_keywords "1800-2012" // use SystemVerilog-2012 keywords
`define _4bit // use 4-bit data for testing synthesis
//`define _32bit // use 32-bit data word size
//`define _64bit // use 64-bit data word size
package definitions_pkg;`ifdef _4bittypedef logic [ 3:0] uword_t;typedef logic signed [ 3:0] sword_t;`elsif _64bittypedef logic [63:0] uword_t;typedef logic signed [63:0] sword_t;`else // default is 32-bit vectors typedef logic [31:0] uword_t;typedef logic signed [31:0] sword_t;`endif typedef enum logic [2:0] {ADD, SUB, MULT, DIV} op_t;typedef enum logic {UNSIGNED, SIGNED} operand_type_t;// Packed union represents a variable that can store // different typestypedef union packed {uword_t u_data;sword_t s_data;} data_t;// Packed structure represents a collection of variables // that can referenced and passed through ports as a grouptypedef struct packed {op_t opcode;operand_type_t op_type;data_t op_a;data_t op_b;} instruction_t;
endpackage: definitions_pkg
//`end_keywords
示例4-8:使用结构体数组对指令寄存器建模
//`begin_keywords "1800-2012" // use SystemVerilog-2012 keywords
module instruction_register
import definitions_pkg::*; // wildcard import the package
(input logic clk, rstN, load_en,
input data_t op_a,
input data_t op_b,
input operand_type_t op_type,
input op_t opcode,
input logic [4:0] write_pointer,
input logic [4:0] read_pointer,
output instruction_t iw
);timeunit 1ns; timeprecision 1ns;instruction_t iw_reg [0:31]; // array of structures// write to the register arrayalways_ff @(posedge clk or negedge rstN) // async resetif (!rstN) begin // active-low resetforeach (iw_reg[i])iw_reg[i] <= '{opcode:ADD,default:0}; // reset valuesend else if (load_en) begin case (op_type)SIGNED: iw_reg[write_pointer] <= '{opcode,op_type,op_a.s_data,op_b.s_data};UNSIGNED: iw_reg[write_pointer] <='{opcode,op_type,op_a.u_data,op_b.u_data};endcase end // read from the register arrayassign iw = iw_reg[read_pointer];endmodule: instruction_register
//`end_keywords
图4-5显示了综合该示例的结果。说明了如何使用结构体和联合体、数组来建模大量设计功能,只需很少的代码。示意图右上角的矩形符号是综合编译器选择报告的通用RAM的实例(在RTL模型中数组的存储。)综合编译器将在综合的最后一步将该通用RAM作为一个或多个同步存储设备来实现,其中通用门级功能映射到特定的ASIC或FPGA设备。
图4-5:示例4-8的综合结果:带结构体的指令寄存器
附录-TestBench
//`begin_keywords "1800-2012"
module testimport definitions_pkg::*;(input logic test_clk,output logic load_en,output logic rstN,output data_t op_a,output data_t op_b,output op_t opcode,output operand_type_t op_type,output logic [4:0] write_pointer,output logic [4:0] read_pointer,input instruction_t iw);timeunit 1ns; timeprecision 1ns;int seed = 555;initial begin$display("\nReseting the instruction register...");write_pointer = 5'h00; // initialize write pointerread_pointer = 5'h1F; // initialize read pointerload_en = 1'b0; // initialize load control linerstN <= 1'b0; // assert rstN (active low)repeat (2) @(posedge test_clk) ; // hold in reset for 2 clk cyclesrstN = 1'b1; // deassert reset_n (active low)$display("\nWriting values to register stack...");op_type = SIGNED;op_a.s_data = 3;op_b.s_data = -5;opcode = ADD;load_en = 1'b1; // enable writing to register@(posedge test_clk) ;for (int i=0; i<=2; i++) beginwrite_pointer = i;$display("Writing to register location %0d: ", write_pointer);$display(" opcode = %0d (%s)", opcode, opcode.name);$display(" op_type = %0d (%s)", op_type, op_type.name);if (op_type == SIGNED) begin$display(" op_a.s_data = %0d", op_a.s_data);$display(" op_b.s_data = %0d\n", op_b.s_data);end else begin$display(" op_a.s_data = %0d", op_a.u_data);$display(" op_b.s_data = %0d\n", op_b.u_data);end@(negedge test_clk) ;op_a++;op_b--;opcode = op_t'(opcode + 1);op_type = op_type.next;endload_en = 1'b0; // turn-off writing to register// read back and display same three register locations$display("\nReading back the same register locations written...");for (int i=0; i<=2; i++) begin@(posedge test_clk) read_pointer = i;@(negedge test_clk) ;$display("Read from register location %0d: ", read_pointer);$display(" iw.opcode = %0d (%s)", iw.opcode, iw.opcode.name);$display(" iw.op_type = %0d (%s)", iw.op_type, iw.op_type.name);if (iw.op_type == SIGNED) begin$display(" iw.op_a.s_data = %0d", iw.op_a.s_data);$display(" iw.op_b.s_data = %0d\n", iw.op_b.s_data);end else begin$display(" iw.op_a.s_data = %0d", iw.op_a.u_data);$display(" iw.op_b.s_data = %0d\n", iw.op_b.u_data);endend@(posedge test_clk) $finish;end
endmodule: testmodule top;timeunit 1ns; timeprecision 1ns;import definitions_pkg::*;logic clk;logic test_clk;logic rstN;logic load_en;logic reset_n;op_t opcode;operand_type_t op_type;data_t op_a, op_b;logic [4:0] write_pointer, read_pointer;instruction_t iw;test test (.*);instruction_register dut (.*);initial beginclk <= 0;forever #5 clk = ~clk;endinitial begintest_clk <=0;// offset test_clk edges from clk to prevent races between// the testbench and the design#4 forever begin#2ns test_clk = 1'b1;#8ns test_clk = 1'b0;endend
endmodule: top
//`end_keywords
SystemVerilog-联合体(union)
SystemVerilog-结构体(二)
SystemVerilog-结构体(一)