RTL协议包拼凑

本文详细介绍了在模块B中利用状态机实现数据包的接收、解析与转发。设计重点在于状态机的状态转换、数据流控制以及校验和计算,同时考虑了FIFO读写同步和逻辑优化,确保高效无损地处理协议数据。测试验证了设计的正确性。
摘要由CSDN通过智能技术生成

这是本人在实际工作中遇到的设计任务,借此研究状态机设计的优化策略


1. 功能描述

作为模块B,当允许进行传输后,读出FIFO中的数据包,在模块B的相关项填上自身状态信息

协议如下

数据协议
1[15:0]头帧,应为ABCD
2[15:0]数据体长度,表示第3项至校验和前一项的项目个数,此处应为 5
3[15:0]模块A当前工作状态
4[15:0]模块B当前工作状态
5[15:0]模块A已完成调用补偿数据个数
6[15:0]模块B已完成调用补偿数据个数
7[15:0]备用
8[15:0]第2~7项按字累加校验和

2. 参数设计

Signal Direction Width(bits) Description
rstninput1异步复位
clkinput1时钟
rx_fifo_rdatainput15接受来自模块A的数据FIFO
rx_fifo_rdata_valinput1接受FIFO读出数据有效
rx_fifo_rd_enoutput1接受FIFO读使能
rx_fifo_emptyinput1接受FIFO空标志
tx_fifo_wdataoutput15发送FIFO写数据
tx_fifo_wr_en output1发送FIFO写使能
tx_fifo_fullinput1发送FIFO满标志
en_transinput1模块B允许传输数据包标志,是一个脉冲
work_modeinput15模块B当前工作状态
compensation_numinput15模块B已完成调用补偿数据个数

3. 逻辑设计

从状态机的角度起始,先等待en_trans的脉冲,有了脉冲就可以读RX_FIFO,注意读的时候可能读出的数据不属于协议包的数据,所以要判断帧头。并且在读的过程中也可能写的快、读的慢导致这一包数据断断续续。

在这里插入图片描述

3.1. IDLE

这个状态比较简单,什么都不做,只等待en_trans的脉冲

3.2. RD_RX_FIFO

该状态下一直拉高rx_fifo_rd_en,读出的数据有效且rx_fifo_rdata为16‘hABCD说明接下来读出的才是协议包。

在这里插入图片描述

3.3. PKG_GEN

在该状态下要在读出的数据包中的第4项和第6项填入work_mode和compensation_num,然后将该包发送出去。

实际上,我们也可以先将该数据包的所有内容解析并寄存下来,然后再打一个新的包发送出去。但是这样会额外消耗解析一个数据包的时间,而且这样的状态机设计会比较复杂。
本文的思路是直接将旧包发送出去,只不过在某些项目替换成新的内容,其实就是一种流水线

这个过程可能有点复杂,于是我们分成如下几个小任务:

使用data_num记录读出的是旧包的第几项数据,不可多读数据

即RX_FIFO如果存有多个旧包,不能将下一个旧包的数据读出

根据data_num,将旧协议包中第4项和第6项重新拼凑一个新的16bit量填入并发送

校验和重新计算

发送完毕后转回IDLE

同时还要注意RX_FIFO读出的有效数据不一定是时序连续的

设计思路如下

● data_num时序

data_num用来标记当前读出的数据是不是旧包、是旧包的第几项。注意data_num的初始值并不是我们写死的,而是从协议包的第2项获取的。

在RD_RX_FIFO最后一拍帧头已经读出来了,所以PKG_GEN状态下的第一个有效的读出数据就是协议包的第2项,应赋值给data_num,但是在这之后的每读出的一个有效数据都要令data_num减1。

即data_num要与rx_fifo_rdata时序对齐

那么PKG_GEN状态下,如何区分rx_fifo_rdata是要赋值给data_num,还是要data_num减1?最简单的方法——状态机增加一个新的状态,就叫GET_DATA_NUM吧。之前的RD_RX_FIFO也改叫GET_HEAD了。

读出帧头就转入GET_DATA_NUM,在GET_DATA_NUM状态下读出的数据就赋值给data_num,并转入GET_DATA,如下图所示

在这里插入图片描述

每次都会为data_num赋值,所以data_num无需担心减溢出问题

● rx_fifo_rd_en控制

从进入GET_HEAD之后rx_fifo_rd_en就要一直拉高,读出旧包。但什么时候拉低呢?在能够读出旧包最后一项就拉低,即不多读,万一多读读出来个16’hABCD第二个旧包的帧头,那不就麻烦了?

那到底是什么时候拉低呢?很简单——cur_state == GET_DATA && rx_fifo_rd_en && !rx_fifo_empty && data_num == 'd1

在这里插入图片描述

● 拼包与转发

从帧头读出来开始到data_num为零结束,每读出一个有效数据,都需要判断是否是属于协议包的第4、6项。如果是则不发送,而是拼一个新的16bit发送,如果不是则直接转发。

如下图

在这里插入图片描述

发现没,tx_fifo_wdata不就是rx_fifo_rdata打了一拍的结果?tx_fifo_wr_en也是。

然后你就会遇到一个问题:数读出来了,结果TX_FIFO满了写不进去怎么办?

写满了那就等到不满了再写,可是RX_FIFO一直在读呀,这样就会丢失数据。所以rx_fifo_rd_en不能无脑拉高,必须与tx_fifo_wr_en配合。之前关于rx_fifo_rd_en设计有误。

● rx_fifo_rd_en与tx_fifo_wr_en 的协同

怎么配合?必须写成功之后再读下一个数

AXI2Standard_handshake_bridge 设计

如下图所示,当rx_fifo_rd_en && rx_fifo_empty时读出新的数据,同时拉低rx_fifo_rd_en等待写成功反馈。

tx_fifo_wdata寄存,并且tx_fifo_wr_en一直拉高,直到tr_fifo_wr_en && !tx_fifo_full成立表示写入成功,此时若data_num大于0就可以再次拉高rx_fifo_rd_en了。

在这里插入图片描述

同理在GET_HEAD和GET_DATA_NUM两个状态下也要保证成功写入之后再进入下一个状态

莫忘记tx_fifo_wdata还要判断data_num来判断要不要用rx_fifo_rdata的值
这里有一个伏笔。此处读出一个数,写入一个数,然后再读。那么是否可以在写数的时候读出新的数呢?因为读出的旧数已经被寄存到tx_fifo_wdata中了,可以读新的数了。

● 校验和与转回IDLE

校验和重新计算就可以,根据data_num。每从RX_FIFO中读出一个数据,若data_num不是0、4、6那么就加的是rx_fifo_rdata[7:0],如果data_num是0那么check_sum可以不加并给到tx_fifo_wdata

转回IDLE的条件也很简单,最后一个校验和写入TX_FIFO成功即可,即data_num == 'd0 && tx_fifo_wr_en && !tx_fifo_full

在这里插入图片描述

最终得到状态机为

在这里插入图片描述

4. 逻辑优化

RTL协议包拼凑 - 逻辑优化部分、代码优化部分

5. 测试

这里的测试用于证明设计优化后的逻辑没有问题,但是综合的代码可能还比较复杂。

在TB中使用mailbox充当RX_FIFO和TX_FIFO,并且预先向RX_FIFO填入以下数据,除了协议帧还包括乱数

	rx_fifo.put(16'h1651);
	rx_fifo.put(16'hFEAC);
	
	rx_fifo.put(16'hABCD);
	rx_fifo.put(16'h5);
	rx_fifo.put(16'hEEEE);
	rx_fifo.put(16'h0);
	rx_fifo.put(16'h137);
	rx_fifo.put(16'h0);
	rx_fifo.put(16'h0);
	rx_fifo.put(16'h1111);
	
	rx_fifo.put(16'h5455);
	rx_fifo.put(16'h5C9A);

输入的work_mode为16’hFFFF,输入的compensation_num为16’h250

之后的测试transcript如下,可以看出正确获取协议帧并填入了正确的数据

在这里插入图片描述
上波形

在IDLE状态下,en_trans拉高一拍进入GET_HEAD状态,并拉高rx_fifo_rd_en

之后rx_fifo_rdata读出两个没用的数据之后出现了帧头16’hABCD,并进入了GET_DATA_NUM状态,注意此时rx_fifo_rd_en采样为高,但是由于rx_fifo_rd_en && !rx_fifo_empty说明下一个有效数据能够读出因此拉低rx_fifo_rd_en,同时拉高rx_fifo_rdata_val_dly

GET_DATA_NUM的第一拍就直接是数据长度16’h5,并且data_num记录下16’h6,check_sum加上16’h5。写那边将16’hABCD写入了TX_FIFO,写入完成后,即满足rx_fifo_rdata_val_dly && !tx_fifo_wr_en,进入GET_DATA。

之后开始正常的并行流水过程,读新数据、写旧数据。直到最后data_num == 16'h1时不再读了,data_num == 16'h0时不再写入

在这里插入图片描述

如下图所示粉色表示读过程、蓝色表示写过程,可见因为rx_fifo_emptytx_fifo_full均未出现拉高的情况,所以不会出现不读也不写的时间,一直在读一直在写,速度很快。

在这里插入图片描述

6. 代码优化

代码优化见RTL协议包拼凑 - 逻辑优化部分、代码优化部分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Starry丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值