1.冒号前后同时出现变量
在已知所需位宽的情况下,可使用":-“或”:+"代替;比如我们有一个变量i,我们需要取出从i×8+7到i×8这8位数据,直接写[i×8+7:i×8]是会报错的。正确的写法是:
[8×i+7 -: 8]
2.模块接口写法
// msg_generator.v
`timescale 1ns/1ns
`include "head.v"
module msg_generator #(
parameter VLAN_FLAG = 1'b1, // 指定是否Vlan
parameter PORT_TYPE = `PORT_GMII, // 指定接口类型(对应不同输出位宽 PORT_TYPE 和 msg_vaild 的不同含义)
parameter MSG_LEN = 11'd100, // 指定报文体总长度(E1588无效)(64:1:1518, 1600:64~1518随机)
parameter MSG_NUM = 32'd1, // 指定连续发送报文总数(0:32'hFFFF_FFFF包)
parameter PREOK_RATE = 7'd100, // 指定前导码完整概率(少字节数随机)(100:必完整, 0:必缺)
parameter CRCOK_RATE = 7'd100, // 指定CRC正确概率(fake_crc=actual_crc+1)(100:必正确, 0:必错)
parameter ALIGN_RATE = 7'd100 // 指定按DW对齐的概率(MSG_LEN 未对齐时上浮对齐)(100:必对齐, 0:忽略)
)
(
input clock,
input reset,
input [`LIST_MAX*`CODE_WIDE-1:0] msg_list, // 指定类型列表(参见head.v)(首包写在高位)
input [9:0] interval, // 指定报文发送间隔(单位:byte)(流量测试)
output reg [PORT_TYPE-1:0] msg_out,
output msg_vaild, // TX_EN, SMII: SYNC
output msg_over, // 单包结束标志
output all_finish, // 指定包数发完标志
output [31:0] info_msgcnt, // 当前已发包数
output [7:0] info_type, // 当前包报文类型
output [3:0] info_prelen, // 当前包前导码字节数
output [15:0] info_msglen // 当前包的实际长度(bytes)
);
例化调用:
// tb.v
localparam PORT_TYPE = `PORT_GMII;
wire [PORT_TYPE-1:0] msg_q;
always @(posedge msg_over or posedge reset) begin
rand_int <= 7+{$random}%6; //报文间隔 7-12
end
reg [200:0] msg_list={
`MSG_PDELAY_RESP,
`MSG_RESP_FOLLOW_UP
};
// 例化格式:
// input、output、parameter都没有要求必须写全
msg_generator #(
.VLAN_FLAG (1),
.PORT_TYPE (PORT_TYPE),
.MSG_LEN (64),
.MSG_NUM (20)
)gen_case(
.clock (clk125m),
.reset (reset),
.msg_list (msg_list),
.interval (12),
.msg_out (msg_q),
.msg_vaild (msg_vaild),
.msg_over (msg_over),
.all_finish (),
.info_msgcnt (),
.info_type (),
.info_prelen (),
.info_msglen ()
);
2.1 parameter 、 localparam、`define
parameter
区别于localparam
:parameter
写在模块接口中,在例化时更改,而localparam
则用于内部常量的定义;parameter
应提供默认值,在例化时即使没有“实参”与之对应,模块也能正常输出;parameter
在例化之初就被赋值,而input
、output
变量则是在例化初始化之后(如模块内的initial
块结束)才有值;- 因为
parameter
在例化时可以更改,而在reg
、input
、output
、inout
、wire
定义的时候须通过常量指定位宽,因此可用parameter
定义的常量来更改位宽以适应不同的例化需求; - define即宏定义,可定义各类常量(如数值、字符串等),一般单独写在一个
head.v
文件中:
// GOOSE SV
`define GO_APPID 16'h00
`define SV_APPID 16'h40
// TYPE STRING
`define S_NONE_NAMED ("Undefine Name String ")
`define S_GOOSE ("GOOSE ")
`define S_SV ("SV ")
在需要使用到该文件中定义的值时使用 :
`include "head.v"
其中元素的调用:
localparam TICK_SET = (PORT_TYPE==`PORT_SMII)?10:(8/PORT_TYPE);
// 报文实际类型
always @(reset or msg_cnt) begin
// 求余取type, 并调整次序
msg_type = msg_list[(list_deep-msg_cnt%list_deep)*`CODE_WIDE-1-:`CODE_WIDE];
end