上一篇对整个UDP/IP协议的电口通信设计有个整体了解,接下来就是对于每个模块的设计,这部分,计划用两篇文章完成,会尽量简洁一点,谢谢大家支持。
1
有些生命自然而来的缘份,是约定俗成好了的。无力改变。只能精心的筹划痴心的遥望耐心的守候动心的注目。
顶层模块设计
顶层模块如下:
图8‑20 UDP/IP顶层模块设计框图
表8‑8顶层模块信号说明表
clk, | 用户接口时钟 |
---|---|
phy_tx_clk, | phy GMII 发送接口时钟1G-->125Mhz 100M-->25M 10M-->2.5M |
phy_rx_clk, | phy GMII 接收接口时钟1G-->125Mhz 100M-->25M 10M-->2.5M |
reset, | 复位信号,高电平有效 |
udp_tx_ready, | 模块可接收外部用户数据输入标志信号,高电平有效 |
app_tx_ack, | app_tx_request 的反馈信号,高电平有效。表示此时外部模块可通过用户接口可向本模块输入数据 |
app_tx_request, | 用户接口数据发送请求,高电平有效 |
app_tx_data_valid, | 用户接口发送数据有效标志信号,高电平有效 |
app_tx_data, | 用户接口所需发送的数据 |
app_tx_data_length | 用户接口一次发送的数据包长度(不含 udp、ip、mac 首部),单位:字节 |
app_tx_dst_port, | 用户接口数据包的发送目的端口号 |
ip_tx_dst_address, | 用户接口数据包的发送目的 ip 地址 |
app_rx_data_valid, | 本模块从外部所接收的数据输出有效信号,高电平有效 |
app_rx_data | 本模块从外部所接收的数据输出 |
app_rx_data_length | 本模块从外部所接收的当前数据包的长度(不含udp、ip、mac 首部),单位:字节 |
app_rx_port_num | 本模块从外部所接收的数据包的源端口号 |
gmii_rx_data_valid | 从外部 phy 接口数据接收有效信号 |
gmii_rx_data | 从外部 phy 接口接收的数据 |
gmii_tx_data_valid | 向外部 phy 接口发送数据有效信号 |
gmii_tx_data | 向外部 phy 接口发送的数据 |
ip_rx_error | 接收数据包 ip 首部检验错误指示信号,低电平有效 |
mac_rx_error | 接收数据包 CRC32 校验错误指示信号,低电平有效 |
详细的信号定义说明可以参见源文件。
udp_ip_protocol_stack 是顶层模块,这个就相当于UDP/IP模块的顶层,使用该IP时,需要了解其接口和配置参数。
用户发送数据时序图,在调用顶层模块时,需要按照这个时序进行调用。
图8‑21用户发送数据时序图
用户接口数据发送结束时序如下图所示
图8‑22用户接口数据发送结束时序
上层应用只需要按照图8‑21、图8‑22时序进行调用IP即可。
用户接口数据接收起始时序如下图所示:
图8‑23用户接口数据接收起始时序图
用户接口数据接收结束时序如下图所示。
图8‑24用户接口数据接收结束时序图
2
有些生命自然而来的缘份,是约定俗成好了的。无力改变。只能精心的筹划痴心的遥望耐心的守候动心的注目。
UDP层模块设计
udp_layer 主要完成对上层应用数据的 udp 协议控制,其中包含了两个子模块 udp_send 和udp_receive,分别完成对上层应用数据 udp 报文的发送和接收。
udp_send 中例化了长度为 8 的移位寄存器组 udp_shift_register,用于发送 udp 首部时进行数据缓冲。
图8‑25 udp_layer模块设计
详细的管脚描述请见源文件。
表8‑9 udp_layer模块引脚说明
reset | 复位信号,高电平有效 |
---|---|
app_tx_request | 用户接口数据发送请求,高电平有效 |
app_tx_data_valid | 用户接口发送数据有效标志信号,高电平有效 |
app_tx_data | 用户接口所需发送的数据 |
app_tx_data_length | 用户接口一次发送的数据包长度(不含 udp、ip、mac 首部),单位:字节 |
app_tx_dst_port | 用户接口数据包的发送目的端口号 |
app_rx_data_valid | 本模块从外部所接收的数据输出有效信号,高电平有效 |
app_rx_data | 本模块从外部所接收的数据输出 |
app_rx_data_length | 本模块从外部所接收的当前数据包的长度(不含udp、ip、mac 首部),单位:字节 |
app_rx_port_num | 本模块从外部所接收的数据包的源端口号 |
ip_tx_ready | 握手是基于 ready、request、ack三个信号来实现的 |
ip_tx_ack | 握手是基于 ready、request、ack三个信号来实现的 |
udp_tx_ready | 握手是基于 ready、request、ack三个信号来实现的 |
udp_tx_ack | 握手是基于 ready、request、ack三个信号来实现的 |
udp_tx_clk | 接口时钟 |
udp_tx_request | UDP发送接口数据发送请求,高电平有效 |
udp_tx_data_valid | UDP发送接口发送数据有效标志信号,高电平有效 |
udp_tx_data | UDP发送接口所需发送的数据 |
udp_tx_data_length | UDP发送接口一次发送的数据包长度(不含 udp、ip、mac 首部),单位:字节 |
udp_rx_clk | 用户接口时钟 |
udp_rx_data_valid | UDP接收接口发送数据有效标志信号,高电平有效 |
udp_rx_data | UDP接收接口所需发送的数据 |
UDP顶层文件主要完成两个模块的例化,所以重点在udp_receive和 udp_send两个模块。
(一)udp_send 模块
udp_send 模块从上层协议模块接收数据、数据包长度和目的端口号,在数据包前端添加相应的 8 字节的 UDP 首部,由于本模块不进行首部校验和计算,因此,将首部中的检验和字段全部置 0。最后,将封装完成的 UDP 报文及报文长度输出至 ip_send 模块。上层模块向本模块发送数据以及本模块向ip_send 模块发送数据时均进行需要进行握手通信。状态机如下:
图8‑26 udp_send模块状态机设计
状态机程序(https://hifpga.com/fsm/):
# OpenFPGA
#状态机示例
digraph fsm {
"BEGIN"-> "IDLE" [label= "begin"]
"IDLE" -> "IDLE" [label= "no request"]
"IDLE" -> "WAIT ACK" [label= "udp sendrequest & ip send ready"]
"WAIT ACK" -> "WAIT ACK" [label= "noack"]
"WAIT ACK" -> "SEND UDP HEADER" [label= "ipsend ack"]
"SEND UDP HEADER" -> "SEND UDP PACKAGE" [label="app data in valid==0"]
"SEND UDP PACKAGE" -> "SEND UDP PACKAGE" [label="app data in valid==1"]
"SEND UDP PACKAGE" -> "IDLE" [label= "senddone"]
}
IDLE 状态
本模块复位后即进入本状态。在本状态时,本模块处于空闲状态,判断上层模块是否ready,若 ip_send_ready 为 1 时,等待 udp_send 模块的发送请求 request 信号。当收到请求后,同时进入 WAIT ACK 状态。否则在本状态循环。
WAIT ACK 状态
在本状态时,本模块等待 ip_send返回的请求许可反馈信号 ip_send_ack。当接收到 ack 信号时,若请求方为 ip_send 模块,则向其返回 ack 信号,并进入下一状态。否则在本状态循环。
SEND UDP HEADER 状态
在本状态时,本模块根据相应的发送请求,向下一层级发送相应的数据报包头。包头发送完
后进入 SEND UDP PACKET 状态。
SEND UDP PACKET 状态
在本状态时,本模块依次向下一模块发送从顶层模块接收的 udp 报文,发送完毕进入IDLE 状态。
(二)udp_receive 模块
udp_receive 模块从 ip_receive 模块接收 UDP 报文。本模块不对 UDP 首部进行校验和计算,提取其中的目的端口号和报文长度,计算出上层数据包长度输出。最后除去 8 字节的报文首部,得到上层协议数据包,依次输出至上层协议模块。
udp_receive 模块逻辑比较简单,所以不过多描述。