您当前的位置:首页 > 美文分享

寄存器的基本知识点(寄存器的基本知识)

时间:2023-02-10 02:15:02

寄存器的基本知识点(寄存器的基本知识)

1.寄存器的功能

1)时序逻辑存储数据。例如,如果计数器在每个周期增加1,则应该通过寄存器来实现。纯组合逻辑是无法实现的。

2)CPU和硬件协同工作,提高设计的灵活性。比如睡觉的时候,我们可能会关掉某个模块的时钟,正常工作的时候再打开。这可以通过CPU来实现。

2.基址/偏移地址

我们设计的几乎每个模块都会有寄存器,它们的寄存器或多或少都会被CPU访问。但是CPU的接口通常只有一组总线来访问这些模块,所以在设计上CPU和各个模块都会链接到总线上。这样,作为主机,CPU可以访问所有模块。

CPU地址如何映射到特定的寄存器?这就是基址和偏移地址的概念。首先,我们在设置架构的时候,会做一个地址映射表。我们以下图为例。假设每个外设接口分配了32KB的地址空间,32KB占用15位。因此,32位CPU地址的高17位是基址,而低15位是偏移地址。当CPU发送地址0x46018000时,硬件会根据其基址自动判断要访问I2C。然后,根据偏移量地址,就可以知道I2C的哪个寄存器被访问了。

3.重置寄存器。

不需要复位。

如上图,就面积而言,在相同驱动电平下,带复位的寄存器大于不带复位的寄存器。所以在实际中,为了节省面积,一些寄存器可以被复位。那么,什么样的寄存器不需要复位呢?答案很简单:如果一个寄存器的值在其他信号的控制下被更新,并且只有在更新后才会被使用,那么这个寄存器就不需要复位。例如流水线的数据路径;比如总线设计中的一些寄存器。我们以AXI总线的地址通道为例,因为addr和size这些控制信号都是在valid和ready的控制下更新的。换句话说,在时钟边沿下,只要valid和ready都为高,addr和size就会立即更新;但是,只要valid和ready中的一个不为高,总线就不会使用addr和size的值(此时,它们的值都是无关紧要的)。在这个前提下,addr和size不需要重置;但是有效和就绪必须被重置。参考代码如下:

另一方面,没有复位的寄存器的设计风险会比较高,所以建议在设计初期就加入复位,以后需要该区域的时候再回来修改。

同步复位或异步复位

在电路结构上,同步复位比异步复位多了一个与门。如果采用同步复位设计,相当于每个寄存器多了一个与门,无疑会占用很大的面积。所以现在的设计基本都是采用异步复位,然后在前面加一个异步复位同步释放电路。

由于异步复位和同步释放是时钟下复位的两个节拍,所以在一些源同步设计中,要特别注意在时序上是否允许你同步的问题。比如在SPI从机的设计中,假设我们用CS来复位。由于时钟由主机发送,每个数据对应一个时钟。这时候master发来的时钟就不能用来同步了。

重置源

在复杂的设计中,一个寄存器可能有许多复位源。例如,上电复位、软复位、看门狗复位等。所以在设计时,首先要根据寄存器的功能和应用场景,将寄存器划分为不同的复位域。并画出具体的复位电路图,然后对照电路图进行编码。

重置原因记录寄存器

当复位源比较复杂时,建议在设计中增加一个寄存器。用来记录上次复位的原因,方便调试。如下所示,对于不同的复位,该寄存器将被复位为不同的值。此外,可以添加一个计数器来记录复位次数等。

4.寄存器的时钟域

这里,的时钟域是指配置寄存器的时钟域和使用寄存器的时钟域。如果它们在同一个时钟域,就没什么好担心的。但是如果它们属于异步时钟域。这时候就需要对寄存器进行静态和动态甚至更精细的划分。所谓静态寄存器,就是寄存器在使用过程中不会被改变;并且不得在变更过程中使用。举个例子,假设某个模块的时钟是分频得到的,上电初始化后分频系数可能不被修改,模块只有初始化后才会开始工作。那么这个分频系数寄存器可以认为是静态的。否则,该寄存器是动态的。

在跨时钟域处理的情况下,区分静态寄存器和动态寄存器尤为重要。例如,假设寄存器在clka下配置,但在clkb下使用。此时,如果是静态寄存器,就不需要做跨时钟域处理。因为无论clkb在哪个时间采样,都只能得到一个固定值;然而,动态寄存器可能会在采样期间发生变化,从而导致亚稳态。当然,有些人为了保险起见,对静态和动态寄存器都进行了统一的跨时钟域处理。

5.访问权限

寄存器的访问权限有多种类型,包括但不限于下图。我们在设计中要考虑的是哪些寄存器可以被CPU访问,哪些寄存器可以被硬件访问。特别是在安全相关的设计中(比如安全引导),要特别注意这个访问权限。因为CPU能读取的东西,随时会被别人看到。

访问权限在注册描述文档中是不可或缺的。下面给出了参考格式。

6.字节屏蔽

CPU访问寄存器的数据总线是32位或64位。也就是说,数据总线将是多字节的。如果没有字节掩码,CPU在修改时会读取并重写一个字节。所以通常在设计中,我们会在寄存器中加入字节掩码的属性。例如,如果寄存器是32位的,写操作可以由4位byte_en控制。

7.多址源仲裁

一个寄存器有多个访问源是很常见的。比如CPU等硬件可以访问;例如,多个CPU可以访问它。例如,假设模块A和模块B都有一个SPI控制器,但它们共享一组IO,并使用一个寄存器spi_switch来选择模块A或模块B的控制器是否连接到IO。而spi_switch这种好死的,正好可以用两个CPU配置。那么,假设CPU10把IO给了模块A,如果SPI传输时模块A把IO切给了模块B,就会出问题。所以只要在寄存器spi_switch的设计上下功夫就行了。如何设计才能避免上述问题?答案是肯定的,但是我打算卖掉它。你们想去。

8.保留寄存器

在实际项目中,固件的完成时间往往滞后于RTL设计,你总会遇到流片和固件还在设计的情况。也就是说,当我们设计RTL时,可能固件的某些功能或架构不够清晰。所以在设计的时候,我们可以根据情况预留更多的寄存器。这些寄存器在RTL设计中没有明确的功能,所以我称之为保留寄存器,如下图所示。万一固件需要用寄存器来标记某一天,就用这些预留的寄存器。

9.寄存器和RAM之间的选择

在项目中使用内存作为缓存是常见的做法。从实现的角度来看,这些存储器可以通过寄存器实现,也可以通过调用RAM来实现。选择寄存器和RAM时,有三点需要考虑:

1)面积。一般小内存可以用寄存器;而较大的存储器使用RAM进行比较和转换。两者的界限很难区分,需要根据具体的流程来评价。

2)因为寄存器的读取是单个节拍,所以出来了,而RAM的读取要到下一个节拍才会出来。所以在做选择的时候,我们要看下一步能不能允许数据被拍出来。

3)3)RAM的读取延迟很大,这可能是项目计时的瓶颈。特别是当RAM很大,或者RAM的访问源很多的时候。在评估期间,您可以打开RAM库来检查具体的延迟。

10.缺省值

设置寄存器的默认值也是一门艺术,下面是我暂时记住的几条规则:

1)不要给IO驱动的默认值太小。

MCU复位自身软复位寄存器的默认值不能有效。否则在复位状态下,MCU根本不会动,更不用说释放软复位了。

3)时钟门相关寄存器应防止死锁。举个极端的例子,假设MCU的时钟门是由MCU自己的配置寄存器控制的。那么这个门寄存器的默认值将被打开。否则,复位后,时钟将被门控,MCU将完全不动。

1.寄存器复用

或者为该死的区域。例如,假设一个系统是半双工的,也就是说,它只能同时读或写。然后读写可以共享一些寄存器。

12.寄存器访问接口

有三种常见的寄存器接口:

1.APB总线

2.AHB公共汽车

3.用户定义的总线

具体设计实例,去知识星球看I2C控制器代码。

13.自动生成登记文件和代码。

手工敲注册码,单独维护MAS文档和代码都是很痛苦的事情。所以很多公司只会维护一个excel表,在excel表的存放上生成MAS和代码,甚至C语言头文件和注册RALF文件。这个具体的脚本还在开发中,稍后会更新到知识星球。

14.寄存器的建立和保持时间

请看我之前写的这篇文章,《从寄存器结构上理解setup和hold time》。

这是我目前能想到的。洗洗睡吧。

审计唐子红

标签:器寄存器复位

寄存器

最新文章