https://mp.weixin.qq.com/s/O7VTHqpCFNJQi3EpucXkIw

 
简单介绍AtomicAutomata的实现。(细节问题太多,恕不完全表述。)
 
 
1. 基本功能
 
AtomicAutomata是一个适配模块,为下游节点添加Atomic操作的支持。Atomic操作包括数学运算和逻辑运算两大类。
 
类参数如下:
a. logical:是否为下游节点添加logical操作支持,也就是AtomicAutomata这个节点是否实现logical原子操作;
b. arithmetic:同logical,是否实现数学运算原子操作;
c. concurrency:并行通道数目,也就是最大能够支持多少个原子操作同时进行;
d. passthrough:如果下游节点支持某原子操作,是否直接把消息传递给下游节点;如果不透传(passthrough == false),那么If !passthrough, intercept all Atomics. Otherwise, only intercept those unsupported downstream.
 
2. 基本原理
 
所有的节点都支持Get/Put消息,而TL-UL的节点不支持Atomic消息。所以可以通过Get/Put来模拟Atomic的消息。
 
AtomicAutomata节点处在中间做适配工作。流程如下:
a. 上游节点发送Atomic请求;
b. AtomicAutomata节点收到Atomic请求后,向下游节点发送Get请求获取数据;
c. Get响应(AccessAckData)返回数据;
d. AtomicAutomata节点收到数据后,执行数学或逻辑运算;
e. 把运算结果写回(Put)下游节点;
f. AtomicAutomata节点收到Put响应(AccessAck)后,返回Get的数据给上游节点;
 
3. 功能限制
 
为了避免缓存过多数据,AtomicAutomata节点只处理大小在beatBytes之内的请求,即数据传输只需要一个beat。
 
4. Diplomatic节点:node
 
用于与上下游节点协商参数的适配节点:
 
因为功能限制,所以参数在向上传递时需要做适配。
 
1) ourSupport
 
当前AtomicAutomata支持的传输大小:
最小为1个字节,最多为mp.beatBytes个字节。
mp为下游节点,根据下游节点的带宽,确定当前节点支持的数据宽度。
 
2) widen
 
相较于下游节点支持的传输大小,是否需要扩大:
a. 如果不透传,则支持的大小就是当前AtomicAutomata节点的能力大小(ourSupport);
b. x.min和mp.beatBytes都是2的幂,如果x.min > 2*mp.beatBytes,代表x和ourSupport没有交集。也就是说下游节点支持的最小传输大小都大于ourSupport;所以只能由我们来替下游节点实现原子操作,支持的传输大小为ourSupport;
c. 如果可以透传,并且x和ourSupport有交集,那么可以把x和ourSupport合并。传输大小在[1, mp.beatBytes]的由当前AtomicAutomata处理,传输大小在(mp.beatBytes, x.max](如果x.max大于mp.beatBytes的话)透传给下游节点处理。
 
3) canDoIt
 
能否代为实现原子操作,还要看下游节点支持的Get/Put传输大小,是否不小于ourSupport所需要的大小。
 
4) supportsArithmetic
 
把更新后的supportsArithmetic参数传递给AtomicAutomata节点的上游节点知道:
a. 如果AtomicAutomata节点不支持arithmetic功能或者无法根据原理实现arithmetic原子则做,则直接把下游节点的支持情况告知上有节点;
b. 如果可以代为实现,则把合并后的传输大小告知上游节点;
 
5) supportsLogical
 
参考supportsArithmetic。
 
5. 逻辑实现:module
 
1) 输入边与输出边
 
输入边连接上游节点,输出边连接下游节点,两者成对出现:
 
2) violations
 
最新版本的代码如下:
个人理解:为了保证实现原子操作的Get/Put中不被插入其他请求,要求下游节点只有一个输入边。
 
3) managersNeedingHelp
 
查找需要帮助的managers:
三个条件:
a. 需要帮:supportsLogical小于ourSupport:!m.supportsLogical .contains(ourSupport);
b. 可以帮:条件如:m.supportsGet.contains(ourSupport)等;
c. 我能帮:logical/arithmetic/passthrough;
 
4) domainsNeedingHelp
 
请求以fifoId排序,而非managers:
 
5) CAM
 
CAM中的每一个entry对应着一个并行的原子操作请求。上游节点的Atomic请求按fifoId划分,选择CAM entry存储,然后再向下游节点发起Get/Put请求。
 
a. camSize
 
CAM entry的数目:
 
concurrency是最多支持多少并行请求的数量,domainsNeedingHelp.size是存在的并行请求的数量。
 
b. camFifoId
 
计算manager的fifoId在domainsNeedingHelp中的序号:
用于确定使用哪一个CAM entry。
 
c. state
 
标识原子请求的处理过程的几个状态:
a. FREE:当前CAM entry没有被使用,收到上游节点的Atomic请求后变为GET状态;
b. GET:已经向下游节点发出了Get请求;收到下游节点返回的数据后转入AMO状态;
c. AMO:Atomic Memory Operation,正在进行数学或逻辑运算;运算完成向下游节点发出写数据请求后转入ACK状态;
d. ACK:Put已经向下游节点发出,等待回复AccessAck;
 
6) 如果没有节点需要帮助:camSize == 0
 
则直接把in和out相连即可:
 
下面主要关注如何实现帮助下游节点实现原子操作的逻辑。
 
7) cam_s/a/d
 
cam_s:存放CAM entry的状态;
cam_a:存放上游节点在Atomic操作中发来的数据(in.a.data),为第一个运算数;
cam_d:存放下游节点在AccessAckData中发来的数据,为第二个运算数;
 
8) cam_free/amo/abusy/dmatch
 
把cam的状态转换为Bool类型的标志:
cam_free:每一个entry是否FREE;
cam_amo:每一个entry是否在AMO状态;
cam_abusy:如果已经缓存了一个同fifoId的Atomic请求,则不能再接收新的Atomic请求;
cam_dmatch:处理下游节点返回的消息时,是否需要检查这一个entry;
 
9) 检查上游节点的请求:in.a
 
a. a_address:取出访问地址;
b. a_size:取出访问大小;
c. a_canLogical
下游节点是否可以处理当前访问空间(起始地址、访问大小)上的逻辑运算,需要满足两个条件:
- 在请求的访问空间上,下游节点支持逻辑运算;
- 允许透传请求;
d. a_canArithmetic:同a_canLogical;
e. a_isLogical:是否逻辑运算原子操作请求;
f. a_isArithmetic:是否数学运算原子操作请求;
g. a_isSupported:下游节点是否可以处理这个请求;如果既非逻辑运算,亦非数学运算,则不是原子操作,默认可以支持。
 
10) 是否需要向下游节点发起Put请求
 
a. a_cam_any_put:是否存在AMO状态的entry,如果存在则需要发起Put请求;
b. a_cam_por_put:用于实现低序号entry的优先级;
c. a_cam_sel_put:找出第一个AMO状态的entry(按序号从低到高排序);
d. a_cam_a:根据cam_amo从cam_a中取出缓存的第一个运算数;PriorityMux低序号优先;
e. a_cam_d:根据cam_amo从cam_d中取出缓存的第二个运算数;
f. a_a:取出第一个运算数;
g. a_d:取出第二个运算数;
 
11) cam_a的entry是否已被占用
 
a. a_fifoId:计算Atomic请求的地址a_address所属的fifoId;
b. cam_a.map(_.fifoId === a_fifoId):检查每个entry中的请求所属的fifoId是否与当前请求的fifoId即a_fifoId相同;
c. a_cam_busy:如果有相同fifoId的请求存在,则无法处理当前请求,需要等待;
 
12) 找出第一个空闲的CAM entry,用于缓存Atomic请求:
 
 
13) 计算逻辑运算的结果:
 
 
参考Atomics中的介绍:
 
14) 计算数学运算的结果:
 
参考Atomics中的介绍:​
一点区别是:这里把高的无效字节使用符号位进行扩展。
 
15) 原子计算的结果:
 
 
16) source_i:源自in.a的消息
 
结合当前节点的状态,决定是否接收上游节点的请求:
 
A. a_allow
 
是否允许上游节点发送请求:
需要满足两个条件:
a. 没有相同fifoId的Atomic请求存在,即a_cam_busy为假;
b. 下游节点可以处理这个请求或者存在空闲的CAM entry;
 
B. a_isSupported
 
这里单独提一下,即便没有空闲的CAM entry(a_cam_any_free为假),只要下游节点可以处理这个请求(a_isSupported为真),也是可以接收这个请求的。即当前AtomicAutomata节点不处理,透传给下游节点处理。
 
另外一个角度看,如果a_cam_busy为真,即CAM中有一个相同fifoId的Atomic请求存在,为了保证FIFO的顺序,即便a_isSupported为真,也不能透传给下游处理。
 
C. in.a.ready
 
a. in.a.ready:同时满足source_i.ready和a_allow才允许上游节点发送;
b. source_i.valid:上游节点有需要发送,并且允许发送;
 
D. !a_isSupported
 
如果需要我们代理这个Atomic请求,则把这个Atomic请求修改为发向下游节点的Get请求:
 
17) source_c:源自cam_a的消息
 
a. source_c.valid:取决于是否有cam要发起Put请求;
b. source_c.bits:使用a_cam_a生成一个Put请求(a_cam_a为第一个要发起Put的CAM entry)。需要注意的是amo_data是使用a_cam_a和a_cam_d计算产生的。
 
也就是说Atomic请求最多可以缓存camSize个,而运算单元(数学运算、逻辑运算)只有一个,所以这些请求要使用运输单元需要排队,低序号的优先级高。
 
18) 谁向out.a输出
 
需要使用仲裁器(低序优先):
这里是source_c优先,也就是先到先得(first come, first serve),否则可能会导致CAM中缓存的请求一直得不到响应。
 
因为AtomicAutomata节点只支持[1, m.beatBytes]大小的传输,所以只需要一个beat。而source_i则需要计算一下。
 
这里理一下流程:
A. 如果仲裁结果是source_i输出到out.a,那么发给下游节点的消息,分两种情况:
如果是下游节点可以处理的请求(a_isSupported为真),那么直接透传;
如果是下游节点不可以处理的请求(a_isSupported为假),那么发送的是被转换之后的Get请求:
 
B. 如果仲裁结果是source_c输出到out.a,那么发给下游节点的是Put请求,写入AMO的计算结果;
 
19) source_i输出
 
记录上游节点的Atomic请求消息到第一个空闲的CAM entry中:
这个entry的状态,从FREE转变为了GET,因为source_i.fire()即是把Get请求通过out.a发给了下游节点。
 
需要注意的是这里是a_isSupported为假的情况,即下游节点不可以处理这个Atomic请求的情况。如果下游节点可以处理这个请求,那么就不需要缓存到CAM entry中,而是直接透传了。
 
20) source_c输出
 
向下游节点发出了Put请求之后,状态就从AMO,转换为了ACK:
 
21) out.d
 
输出边的channel d即out.d,用于接收下游节点返回的AccessAckData和AccessAck消息。
 
22) d_first
 
是否响应消息的第一个beat。
 
23) d_cam_sel
 
a. d_cam_sel_raw:根据CAM entry中存放的Atomic请求的source字段,确定响应消息所属的CAM entry;
 
如何保证同样source的Atomic请求在CAM中只有一个?相同的source必然具有相同的fifoId,CAM中不存在两个相同fifoId的请求,所以也就不存在两个相同source的请求。
 
这里有一个隐含条件是正在处理的Atomic请求。
 
因为缓存在cam_a中并且处理完的Atomic请求,并不会擦掉_.bits.source这一个字段,而只是修改对应的状态为空闲。所以cam_a中可能存在两个以上source为in.d.bits.source的entry。需要使用状态再过滤一下。
 
为什么使用in.d.bits.source,而非out.d.bits.source?因为两者相同:
 
b. d_cam_sel_match:过滤掉空闲的CAM entry,只剩下一个唯一的非空闲的entry。
 
24) d_cam_data
 
使用d_cam_sel_match从cam_d中选出data/denied/corrupt:
 
25) 先忽略d_cam_sel_bypass
 
a. d_cam_sel = d_cam_sel_match;
b. d_cam_sel_any:是否有一个缓存的Atomic请求,匹配当前响应;
 
26) d_ack/d_ackd
 
判断channel d返回的响应的类型,以决定CAM entry下一步的状态:
a. d_ackd:返回的是AccessAckData消息,是针对Get请求的响应;
b. d_ack:返回的是AccessAck消息,是针对Put请求的响应;
 
27) out.d.fire()
 
a. 使用d_cam_sel确定匹配的CAM entry;
b. d_ackd为真时,才需要缓存返回的数据到cam_d中:
c. d_ackd为真时,状态转为AMO,下一步进行原子运算;为假时状态转为FREE,已经与下游节点完成了最后的Put流程。
 
28) d_drop
 
out.d返回的AccessAckData响应消息会被丢弃:
 
不向in.d传递:
 
29) d_replace
 
 
out.d返回的AccessAck响应消息会被替换,并发送给in.d:
发送的数据为d_cam_data,即读取的原值。
 
30) d_first
 
功能所限,AtomicAutomata节点只处理响应的第一个beat。
 
a. 只缓存返回的AccessAckData消息的第一个beat中的数据:
 
b. 只drop返回的AccessAckData消息的第一个beat中的数据:
c. 只替换返回的AccessAck消息的第一个beat(实际上AccessAck也只有一个beat):
 
 
31) d_cam_sel_bypass
 
标志着manager是否可以在同一个时钟周期内,返回Get请求的响应数据:
 
A. 定义
 
a. 如果manager的最小延迟大于或等于1个时钟周期,则manager无法在同一个时钟周期内返回数据,即d_cam_sel_bypass = Bool(false);
b. !a_isSupported:即Atomic请求不是透传给下游节点(manager)处理的;
c. out.d.bits.source === in.a.bits.source: out.d返回的响应与in.a发送的Atomic请求相匹配;
d. in.a.valid:in.a的发送还没有结束;
 
B. d_cam_sel
 
因为cam_s是寄存器,寄存器的值无法在同一个时钟周期内变两次,所以需要从a_cam_sel_free和d_cam_sel_match两组值中选择。
 
原本是FREE状态的CAM entry,需要在下一个时钟周期才能变为Get发送之后的GET状态,进而驱动d_cam_sel_match产生变化。所以如果d_cam_sel_bypass为真,直接从a_cam_sel_free中取对应的CAM entry。第一个为1的比特对应的CAM entry就是刚刚选择用来缓存in.a的entry,也是out.d返回的AccessAckData消息对应的CAM entry。
 
C. d_cam_sel_any
 
如果d_cam_sel_bypass为真,则必然与out.d返回消息相匹配的CAM entry:
 
32) 不处理channel b/c/e:
 
无论是否支持,简单连接即可:
 
6. 一般流程
 
简要介绍需要当前AtomicAutomata节点处理的Atomic请求的一般流程,这个流程通过状态机控制(cam_s)。
 
1) in.a发出Atomic请求
 
请求被改写为Get请求:
 
2) 请求缓存到cam_a
 
 
3) 发送Get请求到out.a
 
source_i.fire()时,Atomic请求更改成的Get请求,即发送到out.a:
 
4) out.a返回AccessAckData响应消息
 
 
5) 执行AMO运算
 
从cam_a和cam_d中选择第一个和第二个运算数,进行运算:
 
6) 把运算结果通过Put请求通过out.a发送
 
 
更新状态机:
 
7) out.a返回AccessAck响应消息
 
把AccessAck消息转换为AccessAckData消息,发送给in.a:
 
更新状态机:
 
7. 透传流程
 
简要介绍当前AtomicAutomata节点透传到下游节点处理的Atomic请求的处理流程。
 
透传具体到代码中的标志为:a_isSupported为真。
 
1) 单beat
 
A. 透传Atomic请求
 
a. 即便没有空闲的CAM entry,也可以向out.a输出:
 
b. 不会被缓存到CAM中:
 
c. 不会被更改为Get请求:
 
结果就是:
a. 直接通过source_i发送到out.a;
b. 这个请求会阻塞in.a,直到被仲裁器选中,发送给out.a;
c. 仲裁器选中时,cam_a中缓存的Atomic请求已经全部都处理完了,也就是说cam_a和cam_d中的所有CAM entry都是空闲的;
 
B. 透传Atomic响应
 
a. cam_dmatch为全0(所有entry都FREE),进而d_cam_sel_match为全0:
 
 
b. d_cam_sel_bypass为假:
 
 
c. d_cam_sel为全0,d_cam_sel_any为假:
 
 
d. cam_d不缓存数据,不更改状态:
 
 
e. d_drop为假:
 
 
out.d可以发送到in.d:
- in.d.valid取决于out.d.valid;
- out.d.ready取决于in.d.ready;
- in.d.bits连接到out.d.bits;
相当于直连。
 
f. d_replace为假:
 
 
不会更改out.d返回的响应消息:
 
2) 多beat:burst
 
Diplomatic节点中对managerFn的适配,决定了如果下游节点无法处理大于beatBytes的Atomic请求,那么传递给上游节点的参数supportsArithmetic最大是ourSupport。也就是说上游节点最大只能发起beatBytes大小的Atomic请求,不存在burst请求的情况。
 
也就是说,burst请求只存在于透传给下游节点处理的情况。即:a_isSupported为真。
 
具体分析与单beat一致,相当于in.a与out.a直连,in.d与out.d直连。

转载于:https://www.cnblogs.com/wjcdx/p/11211465.html

Rocket - tilelink - AtomicAutomata相关推荐

  1. Rocket - tilelink - FIFOFixer

    https://mp.weixin.qq.com/s/JS4Pguwa6LXjPsMq6nW8HA   简单介绍FIFOFixer的实现.   ​​   1. 基本介绍   按照一定的策略把某一部分m ...

  2. Rocket - tilelink - Delayer

    https://mp.weixin.qq.com/s/pc8f_DOJ7w8k8BeM9gPzVw   简单介绍Delayer的实现.   1. 基本介绍   以一定的概率延迟消息的传递.   类参数 ...

  3. Rocket - tilelink - Atomics

    https://mp.weixin.qq.com/s/TSwKL_qm-b-0e8x7r--hhg   简单介绍Atomics中数学运算.逻辑运算的实现.   ​​   1. io   Atomics ...

  4. 片上总线协议学习(1)——SiFive的TileLink与ARM系列总线的概述与对比

    link 片上总线协议学习(1)--SiFive的TileLink与ARM系列总线的概述与对比 finally 27 人赞同了该文章 一.背景介绍 随着超大规模集成电路的迅速发展,半导体工业进入深亚微 ...

  5. chisel(Rocket Chip)中如何参数化芯片系统

    2021.9.5 有些地方添加了一点自己的理解!!! 0 绪论 前面已经介绍了chisel的初级和高级参数化. 如何把这些东西有效的在系统中组织起来呢?如何在系统中快捷的使用他们?这篇文章主要解决这个 ...

  6. canal+mysql+rocket

    版本 canal.deployer-1.1.5 canal.admin-1.1.5 rocketmq-all-4.9.3-bin-release rocketmq-deshboard-master m ...

  7. Rocket - diplomacy - AddressAdjuster

    https://mp.weixin.qq.com/s/X0s5CWN84GEiwpNR7tiRgA 基于AddressAdjuster介绍LazyModule的实现.   参考链接:https://g ...

  8. 基于 RT-Thread智能车控制算法开发-河南科技大学ROCKET

    学校:河南科技大学 队伍名称: ROCKET 参赛队员:王思杰.王磊 胡彧奇.程钟鑫 带队教师:王新勇.付江涛 §01 引言   在第 16届全国大学生智能汽车竞赛中,我们选择了双车接力组这一比赛项目 ...

  9. 64位开源处理器Rocket该人士介绍

    最近大概读一点UCB发布时间Rocket处理器的源代码,的每个文件的源代码的功能有一定的一般理解,Mark一点点. Rocket是一家64bit标量处理器,5第一阶段管道,用途risc-v指令集.综合 ...

  10. 使用宝塔面板安装Rocket.Chat多功能团队聊天室

    安装 官方文档:https://rocket.chat/docs/ 环境要求:NodeJS 8.11.4.Mongodb 4.0.9.Nginx(非必需). 提示:由于官方建议的最低内存1G,所以51 ...

最新文章

  1. 【Spark】Spark基础练习题(一)
  2. 想学大数据?大数据处理的开源框架推荐
  3. openstack常用命令及控制节点端口一览
  4. Windows 8 Hello World
  5. 代码示例:使用redis计数来控制单位时间内对某接口的访问量
  6. 使用VSCode写Python代码的推荐安装的插件
  7. 内存中数据模型和大数据持久性
  8. 系统间账号认证系统同步方案
  9. python布尔类型运算_python基础之布尔运算、集合
  10. 盘点10种局域网联机游戏
  11. 计算机桌面文件能单独设密码吗,文件夹怎么设置密码,教您如何给电脑上文件夹设置密码...
  12. 怎样学计算机打字最快,怎样学电脑快速打字
  13. C++ 读取文件时报错“将一个无效参数传递给了将无效参数视为严重错误的函数”解决方法
  14. C#文件选择和另存为
  15. LabVIEW 调用 BarTender 进行标签打印
  16. three.js网页demo展示
  17. 如何成为一个漏洞赏金猎人
  18. Ant Design中select框往下滑动会自动回到顶部的问题
  19. 解决Mac执行Mono的EXE的问题
  20. php 恶汉单例,单例模式的两种方式(恶汉式,懒汉式)

热门文章

  1. const定义常量_JS声明变量var、let 、const(含重点示例)
  2. oracle查看脚本,oracle 查看表空间的脚本
  3. fill函数 神奇的迭代器
  4. radar nyoj 287
  5. this指向问题 php,js中的this指向问题
  6. 什么是信用评分分析?
  7. mysql innodb count 优化_MySQL · 引擎特性 · InnoDB COUNT(*) 优化(?)
  8. 乘2取整法_关于十进制小数转二进制是“乘2取整,顺序排列”,请问为什么要这么做?这样做有什么根据?最好举上例子...
  9. linux 防火墙安装在哪,Linux下Shorewall防火墙安装和配置
  10. wex5 java_[Java教程]WEX5中ajax跨域访问的几种方式