文章
背景:
在fpga开发项目的时候,尤其是模块比较多的时候,那么信号连接多,需要在多个模块内保持信号连接正确,并且位宽需要保持一致,在这个问题上经常会疏忽出错,近期开发fpga项目时使用了system verilog来进行开发FPGA,在这个过程中发现了一些优点,特此分享,syetem verilog的语法是兼容verilog的,在fpga开发时只会用到部分可综合的语法,恰是这部分语法让fpga开发变得更加方便。
1、system verilog中的 ** struct ** 在协议组包和参数读取处理等应用上比较方便
2、system verilog中的 ** interface ** 让模块间的连接变得非常简洁清晰,省区繁杂的连接
一、struct
在system verilog里体的使用结构体可以使逻辑开发的效率提高,并且具有非常高的可读性,下面举例结构体的具体使用的一个场景,我们在用fpga开发以太网时进行协议组包时请问之前是怎么进行操作的?可能不同的人做法不尽相同,可读性可参差不齐,今天我们来介绍下使用结构体来进行组包操作。
1、第一步使用结构体需要先声明一个结构体,和C++里的用法类似,下面一段代码就是对以太网的MAC头进行组包,对IP层的20个Byte进行组包。
typedef struct packed{
logic [63:0] preamble ;
logic [47:0] target_mac ; //arp_tx里的target 在这里看是pc端
logic [47:0] sender_mac ; //arp_tx里的sender 在这里看是板端
logic [15:0] eth_type ; //0806 代表arp协议 0800代表ip协议
}mac_t;
typedef struct packed{
logic [3:0] version ; //4 : ipv4
logic [3:0] header_len ; //5 : 5*32bit(4字节)=20字节
logic [7:0] tos ; //00
logic [15:0] total_len ; //xx : (ip头+udp首部+数据)/(ip头+icmp首部+数据)
logic [15:0] identification ; //xx : 0000
logic [15:0] flag_offset ; //xx : 0000
logic [7:0] time_to_live ; //xx : 80('d128)
logic [7:0] protocol ; //01 : icmp 11 : udp
logic [15:0] checksum ; //IP头部的校验和
logic [31:0] sender_ip ; //在这里看是板端
logic [31:0] target_ip ; //在这里看是PC端
}ip_t;
2、声明了结构体,就要实例化一下
mac_t mac ;
ip_t ip ;
3、上述是进行声明结构体,那么如何使用呢,我们下面看一下如何使用,
这样就可以对结构体的便利进行装载具体的参数,后续只要把结构体进行发送就可以了。
always @(posedge gmii_clk) eth.mac.preamble = 64'h55555555555555d5 ;
always @(posedge gmii_clk) eth.mac.target_mac = traget_mac_tx ;
always @(posedge gmii_clk) eth.mac.sender_mac = sender_mac ;
always @(posedge gmii_clk) eth.mac.eth_type = 16'h0800 ;
always @(posedge gmii_clk) eth.ip.version = 4'h4 ;
always @(posedge gmii_clk) eth.ip.header_len = 4'h5 ;
always @(posedge gmii_clk) eth.ip.tos = 8'h00 ;
always @(posedge gmii_clk) eth.ip.total_len = tx_dlen ;
always @(posedge gmii_clk) eth.ip.identification = 16'h0000 ;
always @(posedge gmii_clk) eth.ip.flag_offset = 16'h0000 ;
always @(posedge gmii_clk) eth.ip.time_to_live = 8'h80 ;
always @(posedge gmii_clk) eth.ip.protocol = 8'h11 ;
always @(posedge gmii_clk) eth.ip.checksum = 16'h0000 ;
always @(posedge gmii_clk) eth.ip.sender_ip = sender_ip ;
always @(posedge gmii_clk) eth.ip.target_ip = traget_ip_tx ;
4、结构体还支持继承的使用,如上已经有了MAC和IP的组包,,那么UDP该怎么使用呢,可以看如下用法:在UDP的结构体中可以直接继承使用前面已有的结构体。
typedef struct packed{
mac_t mac ;
ip_t ip ;
logic [15:0] sender_port ; //udp的发送端端口
logic [15:0] target_port ; //udp的目的端端口
logic [15:0] total_len ; //udp首部+数据 8+1024
logic [15:0] checksum ; //组包时先填0
}udp_tx_t;
4、上述结构中的eth.xx其实就是使用了system-verilog的 interface 使用interface有什么好处呢,在不使用的情况下,模块间的例化模块时会有很多信号接口,还要控制好信号的位宽,信号数量多的话,顶层模块会非常繁杂,那么使用 interface就会简化很多,下面举例使用interface进行例化的模块
RGMII_RX RGMII_RX (.sv(sv) );
RGMII_TX RGMII_TX (.sv(sv) );
GMII_ASYNC GMII_ASYNC (.sv(sv) );
ETH_Protocol ETH_Protocol (.sv(sv) );
CMD_Analysis CMD_Analysis (.sv(sv) );
Resp_Management Resp_Management (.sv(sv) );
5、结构体的使用还试用于一些参数的传递,在配合interface使用结构体传递参数也是非常的简单清晰。
欢迎讨论!
System Verilog助力FPGA开发
1223

被折叠的 条评论
为什么被折叠?



