✎ 编 者 按
基于RR的多路分发调用
》多路一出的场景
在SpinalHDL代码中,StreamArbiter提供了完善的多入一出的调度机制。里面可能应用的较多的是Round Robin调度。在之前的文章《你知道如何做多端口仲裁么》中详细讲述了Round Robin调度思想。然而还有一类应用场景就是针对一入多出的情况:
这其实也是之前微信群里面群友问的一个类似的场景。在一些应用里,来自上游的数据或者任务分发给多个Kernel来进行执行处理(如多个报文解析模块)。针对每个任务,其具体的执行时间会有差异(比如在网络报文头解析中,不同层协议所需要的时钟周期数并不相同)。那么为了尽可能避免Kernel空闲,显然如果采用简单的顺序分发至Kernel1~kerneln会存在潜在的Kernel空闲。比如(假定n=3):
- Task1——>Kernel1;100 Clock Cycle
- Task2——>Kernel2;50 Clock Cycle
- Task3——>Kernel3;10 Clock Cycle
- Task4——>Kernel1;10 Clock Cycle
显然,这里如果将Task4分发至Kernel1将会导致Dispatcher的阻塞。那么针对这种场景,显然是下游Kernel谁空闲将任务分发给谁更合适。
》StreamFragmentRoundRobinDispatcher
不同于StreamArbiter所针对的多入一出的谁有任务调度谁的RR调度,这里是一种一入多出的谁空闲任务给谁的RR调度,即Dispatcher By Round。如果你看过之前上面的文章,那么这里可以很容易做实现。考虑到真实的应用场景,这里仅针对Stream Fragment形式的调度实现:
相比于StreamArbiter中采用多路输入信号的valid信号作为调度请求request相反,这里(Line:19)采用多路输出端口的ready信号作为roundRobin的request请求,从而实现谁空闲把任务给谁。
如之前前文所说,Round Robin其实是一种优先级位置变化的最低优先级调度,故这里(Line:19)通过mask_locked的循环左移来实现优先级排序。故这里在初始化时将mask_locked的最高位初始化为1。
这里采用mask_route来标识对应的端口仲裁结果。对于一帧Fragment Stream流,其首拍时由于仲裁结果还未锁定,故采用mask_arbited来充当仲裁标示,而在随后报文锁定后采用mask_locked来执行(确保一帧任务的调度不会被下游ready信号的变化所影响。如果下游端口能一帧完整报文之间不会拉低ready那么这里还可以进一步进行优化)。
对于多Kernel处理结果需要保序输出的场景,这里提供了port_sel_oh信号来输出指示当前报文送至哪个端口。使用时可能需要再例化一个FIFO作为保序结果存储,此时在例化该模块连接port_in端口时可能需要一个continueWhen将保序Fifo的push.ready考虑进去。在port_in.firstFire时将port_sel_oh写入保序Fifo。
☆ END ☆
作者:玉骐
原文链接:Spinal FPGA
微信公众号:
推荐阅读
- Efficient Parsers on FPGA
- 二合一:ROM初始化放置到RTL中
- FPGAer浅入浅出DDR——容量规格篇(一)
- 偷点儿小懒 —— Stream 总线类模版
- SpinalHDL中不可不知的位拼接符
更多SpinalHDL技术干货请关注Spinal FPGA欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。