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

简单介绍RegMapper的实现。

1. 简单介绍

RegMapper使用指定的输入接口,为一组寄存器生成读写访问逻辑。

2. RegMapperParams

定义RegMapper需要的参数:

a. indexBits:索引号占用的位数;

b. maskBits:数据掩码的位数;

c. extraBits:额外参数的位数;

3. RegMapperInput

访问逻辑使用的输入接口:

a. read:是否读请求;

b. index:访问的目的寄存器的索引号;

c. data:写请求时输入的数据;

d. mask:数据的掩码,每个字节一位掩码;

e. extra:额外的参数;

4. RegMapperOutput

访问逻辑的输出接口,用于返回请求的响应:

a. read:是否读请求的响应;

b. data:读请求的响应数据;

c. extra:返回的额外的数据;

5. RegMapper

1) 可以提取出来的方法

a. toBits/ofBits

Convert to and from Bits:

实例:

b. litOR

用于判断第一个参与OR的参数是否为值为真的字面量,如果是则直接截断返回判断结果,即Bool(true):

c. mux

a) MuxSeq使用index从cases中选择,如果没有则使用default值:

b) f的类型为Seq[(Bool, Bool)];

c) 每一组s/g/f返回一个out || !g;

d) f所有元组中第二个元素相与(and)的结果输出到out;

2) RegMapper.apply

下面使用重构之后的代码介绍。

A. 参数

a. beatBytes:总线宽度(字节数);

b. concurrency:支持多少个并发访问;

c. in:访问请求输入接口;

d. mapping:要访问的所有寄存器域:

根据注释,Map的第一个元素为字节地址,第二个元素为这个字节地址对应的寄存器包含的寄存器域;

B. 过滤掉长度为0的寄存器域

其中,offset为字节地址偏移量;

C. 寄存器的字节地址不能为负值

D. 把字节地址分组的寄存器域,展开成使用位偏移量的寄存器域

其中,元组的第一个元素为寄存器域的位偏移量。

E. 检查寄存器域是否重叠

因为bitmap中的寄存器域已经排序了,所以只需要比较相邻的两个寄存器域是否重叠即可:

F. 把bitmap转换为wordmap:

每个word包含beatBytes个字节。wordmap中的key为字偏移量。对比之下,bytemap中二元组的第一个元素为字节地址偏移量,bitmap中二元组的第一个元素为位偏移量。

G. 确保所有寄存器域都可以按照字偏移量进行索引:

从中可以看出:寄存器索引(index)以字为单位,每个字包含beatBytes个字节。

H. 使用out返回响应结果

I. 使用front接收请求信息

J. 处理并发请求

a. 若寄存器域的读写有一个是时序逻辑,则需要使用pipeline;

b. depth为可以缓存的请求数量,即可以同时处理的请求数量;

c. back为Queue的输出端,或者就是front本身;

K. 找到区分字偏移量所需要的最少的位

其中:

a. mask:使用AddressDecoder获取到的包含最少掩码位的掩码;

b. maskMatch:undefZero相关,这里不关注;

c. maskFilter:把mask中各个位的值转换为Boolean列表;

d. maskBits:统计mask中为1的位的个数;

L. 计算有效寄存器字的数量

M. 计算有效寄存器字索引号

a. 软件计算:regIndexI;

b. 硬件计算:regIndexU;

这里为什么不用重载呢?两个方法都可以叫做regIndex,参数类型不同,编译器可以区分。

N. 使用有效字偏移量,摊平寄存器域

返回值是三元组序列:

a. 第一个元素是使用regIndexI计算出来的有效字偏移量;

b. 第二个元素是寄存器域的字内位偏移量;

c. 第三个元素是寄存器域;

O. 为每个寄存器域和有效寄存器字声明控制信号

其中:

a. frontMask和backMask是把位掩码拓宽为字节掩码的结果;

b. xxvalid/xxready每个寄存器域一个;

c. xxfire每个有效寄存器字一个;

d. dataOut每个有效寄存器字一个,用于处理读取请求时返回寄存器字的数据;

P. 逐个处理每个寄存器域

Q. 提取寄存器域信息

a. reg为有效字索引号;

b. low为字内位起始偏移量;

c. high为字内位终止偏移量;high不能超过字的范围;

d. field为寄存器域;

R. 提取寄存器域对应的掩码

a. rimask:前端掩码相应位相或的结果,r指read,i指input,即读请求的输入掩码;orR()的意义为只要涉及寄存器域的一个位,该寄存器域就参与操作;

b. romask:后端掩码相应位相或的结果,r指read,o指output,即读请求的输出掩码;

c. wimask:前端掩码相应位相与的结果,w指write,i指input,即写请求的输入掩码;andR()的意义为需要涉及寄存器域的全部位,该寄存器域才参与操作;

d. womask:后端掩码相应位相与的结果,w指write,o指output,即写请求的输出掩码;

e. front和back分别是Queue的前端和后端,亦即输入端和输出端,所以这里i和o也有输入端和输出端的意涵(implication),接下来在使用中还要具体辨析其含义;

S. 生成寄存器域的读写逻辑

这里以读请求为例,寄存器域读请求相关信号如下图:

先看f_rivalid:

a. rimask表明请求涉及到当前寄存器域;

b. rivalid(i)标识该寄存器域所在寄存器字中的其他寄存器域是否都准备好接收读请求;

c. 可以想见,其他寄存器域是否准备好接收读请求,也依赖于当前这个寄存器域是否准备好接收(f_riready);也就是说当rivalid(i)为真时,f_riready为真;

d. f_rivalid的意义为读请求输入有效;

再看f_roready:

a. romask表示请求涉及到当前寄存器域;

b. roready(i)表示是否准备好接收,所属寄存器字中的其他寄存器域的响应;

c. 是否准备好接收其他寄存器域的响应,也依赖于是否准备好接收当前寄存器域的响应(f_rovalid),也就是说当roready(i)为真时,f_rovalid为真;

d. f_roready的意义为准备好接收该寄存器域的响应;

然后看i/o:

a. f_rivalid是rimask掩码后的结果,rimask是请求队列(Queue)输入端的掩码,也就是说,只有涉及到该寄存器域时,其输入才有效;

b. f_roready是romask掩码后的结果,romask是请求队列(Queue)输出端的掩码,也就是说只有涉及到该寄存器域的请求出队时,才打开接收响应的开关。Queue是请求队列,没有涉及到该寄存器域的请求出队,则没有对该寄存器域的请求,自然也不需要接收响应;

最后:

a. f_riready由寄存器域输出;

b. f_rovalid由寄存器域输出;

c. 由寄存器域输出的信号,由寄存器域的读函数(RegReadFn)决定,而RegMapper这里不涉及如何产生这些信号的问题;

T. 收集寄存器字的控制信号

a. reg为有效寄存器字索引号,随着对所有寄存器域的遍历,该寄存器字包含的所有寄存器域的控制信号二元组都会被归集到该序列中;

b. litOR(f_riready, !rimask)等效于f_riready || !rimask,即寄存器域准备好接收请求或者不涉及该寄存器域;如果不涉及该寄存器域,那么接收请求又何妨呢?

c. rivalid(i)的值使用所在寄存器字的其他寄存器域的litOR(f_riready, !rimask)决定,这在后续代码中实现;

根据mux的实现:

a) f中包含寄存器字包含的全部寄存器域;

b) ReduceOthers的第一个效果是把f中所有元组的第二个元素相与之后赋值给out;第二个作用就是给rivalid(i)赋值,使用的就是f中除i之外的所有元组的第二个元素相与,然后再与valid && s && g相与;

U. 使用寄存器域读出的数据,组合寄存器字读请求应该返回的数据

a. 如果寄存器域偏移量为0,则直接使用相与的f_data即可;

b. 如果不是0,则需要把已经搜集的寄存器域数据,与f_data组合;需要注意的是flat中的寄存器域都是排过序的,所以f_data应该被置在高位,而dataOut(reg)与UInt(0, width=low)相或,则把现有的dataOut(reg)的位数拓展为low位;

c. 然后再与f_data组合之后的prepend,位数为high位;

d. 更新dataOut(reg)的值为组合之后的新值;需要注意的是,这个更新是在循环中进行。也就是在软件构建过程中进行。当该寄存器字包含的所有寄存器域都遍历完之后,dataOut(reg)中就组合了所有寄存器域读取数据,最后硬件逻辑中使用的是这个构建结果;

V. 入队请求索引号/出队请求索引号

W. 是否可以入队/是否可以出队

a. rifireMux表示读请求是否可以入队;wifireMux表示写请求是否可以入队;

b. rofireMux表示读请求是否可以出队;wofireMux表示写请求是否可以出队;

c. 这里忽略iRightReg/oRightReg,假设其中所有值都为true;

d. 以rifireMux为例:

a) in.valid && front.ready && front.bits.read表示读请求合法,且队列允许输入;

b) 接下来就看各个寄存器域是否允许读请求;

c) f为寄存器字中包含的所有寄存器域对应的二元组:

d) ReduceOthers把f中所有二元组的第二个元素相与之后,输出给out;也就是所有寄存器域的litOR(f_riready, !rimask),即所有寄存器域都准备好接收输入了;

e) 忽略!g,mux方法的输出为out;

f) out只取决于所有寄存器域是否准备好接收输入(f_riready);

g) 每个寄存器域是否有合法输入(f_rivalid),除了取决于其他寄存器域是否准备好接收输入外,则同时取决于valid && s && g。也就是说,即便所有寄存器域都准备好接收请求了,也未必有合法请求输入,取决于valid && s && g:

h) 所有寄存器域的rivalid(i)都依赖于valid && s && g,也就是说,当valid && s && g为假时,所有寄存器域都没有合法请求输入;

i) valid = in.valid && front.ready && front.bits.read,参考a);g忽略;s的意义为请求是否针对当前寄存器字;

j) 可见out在意义上,只相当于ready;在ready为真的情况下,valid && s && g在意义上相当于valid;

X. 根据是否读请求,确定请求队列输入端和输出端的ready信号

Y. 把输入接口与队列输入端相连,把输出接口与队列输出端相连

Z. 输出响应

a. 输出是否读请求的响应;

b. 输出读请求响应的数据;

c. extra原封不动的返回;

从中可以看出,输出接口中包含的响应,是针对队列输出端输出的请求的响应。

当然,如果队列为空,输入其中的请求,可以即时输出。队列是先入先出的。

3) 遗留问题

A. undefZero及其相关的iRightReg/oRightReg:

B. field.write.combinational选择数据的差异:

Rocket - regmapper - RegMapper的更多相关文章

  1. Rocket - regmapper - RegisterCrossing

    https://mp.weixin.qq.com/s/82iLT-fmDg9Comp2p9bxKg 简单介绍RegisterCrossing的实现. 1. BusyRegisterCrossing 简 ...

  2. Rocket - regmapper - RegField

    https://mp.weixin.qq.com/s/7WKB1QxcVzqm2Q7bWcKHzA 简单介绍RegField的实现. 1. 简单介绍 定义寄存器域相关的参数类型. 2. RegFiel ...

  3. Rocket - tilelink - RegisterRouter

    https://mp.weixin.qq.com/s/DaJhf7hEoWsEi_AjwSrOfA   简单介绍RegisterRouter的实现.   ​​   1. 基本介绍   实现挂在Tile ...

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

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

  5. Slack 开源替代品 Rocket.Chat(聊天,文件上传等等)

    Rocket.Chat 是特性最丰富的 Slack 开源替代品之一. 主要功能:群组聊天,直接通信,私聊群,桌面通知,媒体嵌入,链接预览,文件上传,语音/视频 聊天,截图等等. Rocket.Chat ...

  6. web.py 学习(-)Rocket web框架

    Rocket是一个轻量级,多线程,符合WSGI规范的web框架. Rocket使用一个线程监听连接,接收到连接之后放到Queue中,有worker线程进行处理. Rocket含有以下属性: metho ...

  7. 参加完Rocket MQ Meetup深圳站,回顾和想法

    最近一段时间才开始关注云栖社区的公众号,在两周前看到要在深圳科兴科学园办一场Rocket MQ的Meetup.因为从来没有参加过这种线下活动,而且对Rocket MQ比较感兴趣,所以就立即报名参加. ...

  8. gitlab勾住rocket chat

    出于协作的要求, 需要在把gitlab的push event勾到rocket chat上面, 通知协作的其他人. BUT rocket chat提供的脚本没有具体的文件diff, so, 只好修改一下 ...

  9. Mac 下安装运行Rocket.chat

    最近花了一周的时间,复习了HTML.CSS.原生JS,并学习了Node.js.CoffeeScript.js.MongoDB,入了下门. 因为准备在Rocket.chat 上做二次开发,所以先下载和安 ...

随机推荐

  1. Oracle触发器之替代触发器

    替代触发器 替代视图增删改操作.视图可以认为成逻辑上的一张表,类似于把一个sql语句的执行结果永久的像表存储到数据 库中,视图一般用来做查询. 创建视图的语法: create view 视图名称 as ...

  2. 【Scala】用实例弄清楚scala几种函数的定义和特点

    文章目录 作为参数的函数 匿名函数 柯里化函数(currying) 闭包函数 作为参数的函数 scala> val a1 = Array(1,2,3,4) //这是一个数组 a1: Array[ ...

  3. hadoop问题

    如果启动hadoop集群时,无法启动datanode,则可以集群所有节点下dfs.datanode.data.dir的配置值所指示的路径下清空所有文件(夹),然后 hadoop namenode -f ...

  4. IO 模型知多少 | 代码篇

    引言 之前的一篇介绍IO 模型的文章IO 模型知多少 | 理论篇 比较偏理论,很多同学反应不是很好理解.这一篇咱们换一个角度,从代码角度来分析一下. socket 编程基础 开始之前,我们先来梳理一下 ...

  5. Java Stream 流如何进行合并操作

    1. 前言 Java Stream Api 提供了很多有用的 Api 让我们很方便将集合或者多个同类型的元素转换为流进行操作.今天我们来看看如何合并 Stream 流. 2. Stream 流的合并 ...

  6. MongoDB介绍及开发指南

    目录 一.MongoDB介绍 二.搭建MongoDB 三.Java With MongoDB 四.Spring Session MongoDB 五.MongoDB开发规范及示例 六.MongoDB + ...

  7. flink基础篇

    Flink面试--核心概念和基础考察 1.简单介绍一下 Flink 2.Flink 相比传统的 Spark Streaming 有什么区别? 3.Flink 的组件栈有哪些?         面试知识 ...

  8. 在dynamics 365 中,看字段的描述需要到系统字段设置里面才能看到,这里提供一种sql直接看字段和实体名描述的方法

    1.在crm对应的主数据库执行下面存储过程: -- ============================================= -- Author: <Author,,Name& ...

  9. net core中Vue.component单独一个文件不运行,不报错的处理

    Vue.component代码段原先是放到view下的cshtml中的,可以正常运行,后来为了方便代码管理,将这块代码块单独放到一个js文件中,结果点击按钮等等都没有任何反应了,同时js控制台也不报错 ...

  10. IDEA快捷键(windows)

    Ctrl+Shift + Enter,语句完成“!”,否定完成,输入表达式时按 “!”键Ctrl+E,最近的文件Ctrl+Shift+E,最近更改的文件Shift+Click,可以关闭文件Ctrl+[ ...