AMBA-AXI Register Slice

发布时间:2026/7/19 0:39:32
AMBA-AXI Register Slice RS按照在通道上的插入位置分为四种工作模式其分别为1、pass through mode这种模式常见直通模式在五个数据通道上等效于该模块不存在。2、forward timing mode针对的是valid和data信号的时序优化在模块内部为valid和data信号进行了插拍且没有对ready信号进行插拍现规定在fwd模式下RS模块中插拍寄存了valid和data的两个寄存器名为r_valid_fwd和r_data_fwd。由于在该模式下对valid和data的行为模式相对一致可优先针对valid和ready的握手行为进行分析。由于进行插拍处理那么握手协议就分为两部分A 来自Master/Source绿色端的信号valid_i和ready_o进行握手记为源端握手B 另一部分红色由插拍后的valid(r_valid_fwd)与部分组合逻辑形成的valid_o和来自Slave/Destination端的信号ready_i进行握手记为终端握手。此时插拍寄存器valid(to destination)和data(to destination)可视作一个深度为1存储体例如FIFO,且该存储体无法直通bypass。问题的关键就在于分析在插拍后valid_o和ready_o的形式应怎么组成。很明显的是valid_o和r_valid_fwd是绑定的由于插拍寄存器即存储体被视为不可直通的valid_o就是用于指示现有的插拍寄存器中是否存在使能有效数据即assign valid_o r_valid_fwd;至此valid_o和插拍寄存器r_valid_fwd的命运彻底绑在了一起而r_valid_fwd的变化又和源端握手行为有关即当ready_o和valid_i完成源端握手时下一拍插拍寄存器内的valid和data即可加载新的有效数据否则应维持原状即always (posedge clk or negedge rst_n) begin if (!rst_n) begin r_valid_fwd 1b0; end else begin r_valid_fwd (ready_o valid_i) ? valid_i : r_valid_fwd; end end那ready_o又究竟是什么样的呢由于没有插拍可以想象的是ready_o应是ready_i和某些信号组成的组合逻辑并且ready_o是服务于源端握手的只有当插拍寄存器使能无效有存储空间加载有效数据时ready_o才应使能为高即ready_o !r_valid_fwd。然而事实确实如此吗ready_o !r_valid_fwd(没满其实就是无数据)这个条件的确满足插拍寄存器加载有效数据的条件但是否决了一种可能性那就是pipeline流水加载。即假如插拍寄存器内有有效数据时如果源端握手和终端握手同时完成时在下一拍插拍寄存器内的有效数可以传递至Slave并加载新的有效数据实现数据流水传递。因此当前时刻实现终端握手的条件也是ready_o使能有效的条件之一。这比单纯的ready_o !r_valid_fwd情况下的效率更高结合上述两种情况分析结果即为assign ready_o !r_valid_fwd || r_valid_fwd valid_o ready_i前文提到r_valid_fwd和valid是一回事且在这种条件下它俩视作使能有效1所以上述表达式可简化成assign ready_o !r_valid_fwd || ready_i;data信号的处理同理代码总结如下//forward timing mode always (posedge clk or negedge rst_n) begin if (!rst_n) begin r_valid_fwd 1b0; end else begin r_valid_fwd ready_o ? valid_i : r_valid_fwd; end end always (posedge clk or negedge rst_n) begin if (!rst_n) begin r_data_fwd {(WIDTH){1b0}}; end else begin r_data_fwd ready_o ? data_i : r_data_fwd; end end assign valid_o r_valid_fwd; assign data_o r_data_fwd; assign ready_o !r_valid_fwd || ready_i;3、backward timing mode针对的是ready_i的时序优化在模块内部为ready信号进行了插拍。这里要说明一点所谓的寄存插拍本质上是对该信号在时间周期cycle上的一次延迟因为有了延迟所以在握手信号变化的时候变化的延迟会使得源端和终端的行为会有很大的差异。现在将valid信号视作直通而ready信号视作有寄存行为来分析此时valid_i和valid_o的变化保持时间一致而ready_o的变化比ready_i的变化慢一个时钟。因此当ready信号使能有效时valid信号的变化会使得源端握手和终端握手的行为在时间上保持一致。而当valid信号有效时当ready信号从无效0变化为有效1时终端握手会快于源端握手。当ready信号从有效1变化为无效0时终端的解握手会快于源端的解握手。终端的解握手会快于源端的解握手终端的解握手会快于源端的解握手终端的解握手会快于源端的解握手所谓重要的事情说三遍这句话的意思就是当终端发生解握手的那个cycle源端的握手是还有效的因为它是在下一个cycle才解开这意味着当前这个cycle的data会被视作有效而进入RS模块却不会被视作有效而传递给Slave因此当前这个cycle的数据会丢失为了防止有效数据的丢失RS模块内部必须有存储体存放这个数据。这就是为什么bwd模式下仍然会有valid和data的相应寄存器作为存储体。笔者一开始接触bwd模式的时候没有理解为什么valid和data会有寄存器貌似也在插拍。但实际上与fwd不同的是这个寄存器作为存储体是有可能不在关键路径上的因为它是可以被直通bypass的。它的存在的一大主因就是为了缓存因两端握手变化不一致而有丢失风险的数据。那这段分析为什么没有在fwd模式下讨论呢现在回过头来在fwd模式情景下讨论这个问题。在fwd模式下将ready信号视为直通而valid信号视作寄存行为来分析此时ready_i和ready_o的变化保持时间一致而valid_o的变化比valid_i的变化慢一个时钟。因此当valid信号使能有效时ready信号的变化会使得源端握手和终端握手的行为在时间上保持一致。而当ready信号有效时当valid信号从无效0变化为有效1时源端握手会快于终端握手。当valid信号从有效1变化为无效0时源端的解握手会快于终端的解握手。由于已经有了插拍寄存器作为存储体存放数据并且建立和解除握手的顺序和数据传输顺序是一致的此时没有任何风险。综上现将在bwd模式下valid和data的存储寄存器记为r_valid_bwd和r_data_bwd将ready的插拍寄存器记为r_ready_bwd。其中存储寄存器是可直通的可以想象会作为选择逻辑之一而插拍寄存器是不可直通的可以想象需要配合组合逻辑。先思考一下存储寄存器的行为它是用于保证将有丢失风险的那个数据缓存起来但是RS模块无法预知上下游的行为因此无法预知具体要存储的数据是哪个那在这种情况下通过源端握手成功后加载的数据都需要在该存储寄存器中存储并不断刷新。此时该寄存器的行为和fwd里的插拍寄存器行为是类似的always (posedge clk or negedge rst_n) begin if (!rst_n) begin r_valid_bwd 1b0; end else begin r_valid_bwd (ready_o valid_i) ? valid_i : r_valid_bwd; end end always (posedge clk or negedge rst_n) begin if (!rst_n) begin r_data_bwd {(WIDTH){1b0}}; end else begin r_data_bwd (ready_o valid_i) ? data_i : r_data_bwd; end end同上文ready_o valid_i的逻辑是可以优化的。然后思考一下valid和data的输出端信号valid_o和data_o首先在bwd模式下认为这两个信号是不做插拍的信号在正常的传输过程中是从输入端口通过组合逻辑直通到输出端这意味这里需要有一个选择控制信号在存储寄存器不断存放刷新源端握手成功而传输的有效信号的同时该有效信号还通过这个选择逻辑直通到了输出端。记选择信号为sel则记1为选择存储寄存器0为直通输入信号则assign valid_o sel ? r_valid_bwd : valid_i assign data_o sel ? r_data_bwd : data_i那sel的逻辑是如何考虑的呢结合上文的分析来看sel主要用以切换直通和存储寄存器而这种切换恰恰发生在ready信号发生变化时终端建立握手和解除握手的那个cycle。总结来说而当valid信号有效时当ready_i信号从无效0变化为有效1而ready_o信号还未从无效0变化为有效1的那个cycle时sel需要在下个cycle切换至选择直通0。当ready_i信号从有效1变化为无效0而ready_o信号还未从有效1变化为无效0的那个cycle时sel需要在下个cycle切换至选择存储寄存器1。换句人话讲在选择存储体模式下当终端建立握手而源端未建立握手时sel需要在下个时钟从存储寄存器切至直通。在直通模式下终端解除握手而源端未解除握手时sel需要在下个时钟从直通切至选择存储寄存器其余情况sel保持不变。由此可见sel逻辑是个时序逻辑记为r_sel。当终端建立握手而源端未建立握手时的条件在选择存储体模式下ready_o恒为0valid_o恒为1因此源端必不会握手终端握手依赖ready_i此时ready_i为1因此条件表达式为ready_i (!ready_o)。 满足此条件时r_sel需要在下一cycle置0。当终端解除握手而源端未解除握手时的条件在直通模式下ready_o恒为1源端握手依赖valid_i此时valid_i和valid_o都为1因此终端解除握手依赖ready_i此时ready_i为0。因此条件表达式为valid_i (!ready_i) ready_o。 满足此条件时r_sel需要在下一cycle置1。当RS模块复位时存储体内数据无效此时r_sel应选择直通因此r_sel的复位默认设置为0。always (posedge clk or negedge rst_n) begin if (!rst_n) begin r_sel 1b0; end else begin r_sel valid_i (!ready_i) ready_o || (ready_i (!ready_o) ? 1b0 : r_sel); end end而关于r_ready_bwd也可以类比fwd的插拍寄存器行为首先ready_o是用于指示当前存储体中是否有空间存放有效数据只有保证内部存储体有空间才能免除丢数的风险而保证存储体能加载新数据的条件是当前时刻终端握手加载入存储体的数据同时被直通传递给了Slave或者就是存储体里的数据通过终端握手传递给了Slave。此时在下一个cycle存储体里的数据就过时了视作无效。因此在终端握手的下一个cycleready_o应当为1。而在终端没握手而源端发生握手的下一个cycleready_o应当为0。其余情况则保持不变。很容易联想到用时序逻辑描述这个情景。下述则是代码描述assign ready_o r_ready_bwd; always (posedge clk or negedge rst_n) begin if (!rst_n) begin r_ready_bwd 1b1; end else begin r_ready_bwd valid_o ? ready_i : r_ready_bwd; end end那么为什么是这种写法呢想一想valid_o有两种可能一是直通模式此时如果valid_o为0则源端和终端都不握手r_ready_bwd不做变化符合预期。若valid_o为1则当ready_i为1时符合直通模式下终端握手情形r_ready_bwd将在下个cycle置1正好是ready_i的值符合预期。而当ready_i为0时符合终端没有发生握手并且源端发生握手的情形r_ready_bwd将在下个cycle置0正好是ready_i的值。在直通模式下会有可能出现两端都不发生握手的情形吗答案是不会的前述分析提到在出现源端握手而终端不握手的场景时valid_o将会切换到选择存储寄存器模式。而这就是valid_o的第二种可能在该模式下valid_o恒为1r_ready_bwd恒为0此时若ready_i为1则满足终端握手。r_ready_bwd将在下一个cycle置1正好是ready_i的值,而当ready_i为0则r_ready_bwd不变还是0正好是ready_i的值符合预期。当RS模块复位时存储体是可以存放数据的因此r_ready_bwd的复位默认设置为1。这里和fwd里的r_valid_fwd的逻辑几乎是对仗的这里提供一个思考所谓的valid/ready握手协议本身就要求valid信号和ready信号之间是独立无依赖关系的那仅针对这对信号Master/Slave之间valid/ready信号之间是可以互相对换名字的。虽然和上述一通分析没有什么关系但是也能感觉到这里有种对称的美感。综上对上述分析的代码进行优化可得//backward timing mode always (posedge clk or negedge rst_n) begin if (!rst_n) begin r_valid_bwd 1b0; end else begin r_valid_bwd ready_o ? valid_i : r_valid_bwd; end end always (posedge clk or negedge rst_n) begin if (!rst_n) begin r_data_bwd {(WIDTH){1b0}}; end else begin r_data_bwd ready_o ? data_i : r_data_bwd; end end always (posedge clk or negedge rst_n) begin if (!rst_n) begin r_ready_bwd 1b1; end else begin r_ready_bwd valid_o ? ready_i : r_ready_bwd; end end always (posedge clk or negedge rst_n) begin if (!rst_n) begin r_sel 1b0; end else begin r_sel valid_i (!ready_i) ready_o || (ready_i (!ready_o) ? 1b0 : r_sel); end end assign ready_o r_ready_bwd; assign valid_o r_sel ? r_valid_bwd : valid_i assign data_o r_sel ? r_data_bwd : data_i4、full timing mode兼顾了fwd模式和bwd模式是在两个方向上对这valid/ready都进行了插拍处理代码的本质就是上述的二合一版本将bwd中的valid的直通替换成fwd的增加一级寄存器的插拍处理同时数据需要从两个存储寄存器中ping pang切换选择。这里可能会有一个疑惑既然fwd已经有一个插拍寄存器作为存储体那么何必还需要用两个寄存器呢这是因为full模式下源端终端的valid/ready已各自独立如果仅用深度为1的存储体存放数据源端和终端必有其中之一握手效率会受到影响。举个例子如果存储体深度为1若存储了数据则为full此时对源端来说ready_o为0源端不能握手。若没存储数据则为empty此时对终端来说valid_o为0终端不能握手。而假若存储体深度为2当存储体里存放了深度1的数据时源端和终端的握手都能实现此时效率最高。