一、数字逻辑通信基础
数字逻辑通信研究超大规模集成电路内部,诸多逻辑单元/IP信息交换。为支持大量复杂高速集成电路内部的通信,需要定制某些规则,以满足以下目的:
- 保证信息交换的可靠性。
- 在信息可靠的前提下追求最高的传输速率。
- 支持和保证所有参与传输的单元,具有对传输加以控制的权利和义务(不对等)。
1.1数字逻辑通信的概念和术语
1.1.1 单向传输(Uindirectional Transfer)
数据仅仅在一个方向流动,称为单向传输。
1.1.2 双向传输(Bidirectional Transfer)
数据仅在两个模块之间往返流动,称为双向传输。
1.1.3 存储器映射传输(Memory-Mapped Transfer)
伴随有地址信息和控制信息,访问存储器类设备的传输,称为存储器映射传输。
1.1.4 流传输(Streaming Transfer)
无伴随地址信息的单向或双向传输,称为流传输。
流传输定义可以是单向或双向,但大部分的电路中,流传输以单向传输(AXI的流单向化基础)
1.1.5 无反制单向传输(Transfer Without BackPressure)
在两个模块之间发生的传输中,仅仅上游模块具传输控制权利,下游模块仅仅有被控制义务,这种权利义务不对等的形式,称为无反制流传输。
1.1.6 源宿传输(Source-Sink Transfer)
单向流传输中,将上游模块接口称为源接口(Source Interface),将下游模块接口称为宿接口(Sink Interface),据此构成的通信称为源宿通信。
1.1.7 主从传输(Master-Slave Transfer)
存储器映射传输中,将发出地址和主控信息的电路逻辑,称为主机接口(Master Interface),响应地址信息和主控信息的电路逻辑,称为从机接口(Slave Interface),据此构成的通信称为主从通信。
1.1.8 随机传输(Random Transfer)
主从传输中,每一个数据信息都伴随以后对应的地址信息,称为随机传输。
1.1.9 突发传输(Burst Transfer)
主从传输或者流传输中,一次握手成功,传输若干个信号的传输(信号要大于一),称为突发传输。
二、无反制流传输ST
无反制流传输是一种权力义务不对等的传输,源接口具有控制权,而宿接口没有。
2.1 传输模型
st_source:源接口
st_sink:宿接口
data:信息
valid:握手信息
2.2 传输规则
源接口:
- 源模块需要发送信息,则将信息送往data,并且将握手信息valid设置为真。
- 源模块需要停止发送,则将握手信息valid设置为假。(data不影响信息传送的停止)
宿接口:
- 宿接口需时刻准备着接受主机发送的握手信号valid。
- 宿主接口接收到握手信号valid时,需立刻响应。
总结:源接口具有对传输的控制权(断言,反断言),宿接口仅仅有响应的义务。(响应源接口的命令)
2.3 传输例子
2.4 典型解决方案
上游源接口获得全部控制权,故可以直接用FSM(有限状态机)来解决。这里我用两个案例来说明。
-
宿接口架构:
-
宿接口状态机(SINK_FSM)状态转移图:
2.5 无反制传输设计例子一
下图所示,宿接口接收上游的8位无反制传输数据,传递给其下游的七段数码管显示电路。
任务目标:
为其设计,建模和ABV验证(基于断言的验证)
2.5.1 架构
引用典型解决方案,得到架构:
2.5.2 状态转移图
引用典型解决方案的STG:
2.5.3 验证架构
ABV验证架构:
2.5.4 设计代码
设计模块:
`timescale 1ns / 1ps
module st_exampel1(clk, rst_n, valid, data, q, write);
input clk, rst_n;
input valid;
input [7:0] data;
output reg [7:0] q;
output reg write;
always @ (posedge clk)
begin : FSM
if (!rst_n)
begin
q <= 0;
write <= 0;
end
else if (valid)
begin
q <= data;
write <= 1;
end
else
write <= 0;
end
endmodule
仿真模块:
`timescale 1ns / 1ps
module st_exampel1_tb;
logic clk, rst_n;
logic [7:0] data, q;
logic valid, write;
stimulate STIM(
.clk(clk),
.rst_n(rst_n),
.data(data),
.valid(valid)
);
st_exampel1 DUT(
.clk(clk),
.rst_n(rst_n),
.valid(valid),
.data(data),
.q(q),
.write(write)
);
scoreboard SC(
.clk(clk),
.rst_n(rst_n),
.data(data),
.valid(valid),
.q(q),
.write(write)
);
endmodule
stimulate模块:
`timescale 1ns / 1ps
module stimulate(clk, rst_n, data, valid);
output reg clk, rst_n;
output reg [7:0] data;
output reg valid;
initial begin
clk <= 1;
rst_n <= 0;
data <= 0;
valid <= 0;
#200ns
@ (posedge clk)
rst_n <= 1;
#200ns
forever begin
@ (posedge clk)
if (({$random} % 16)>=4)
begin
data <= {$random}%256;
valid <= 1;
end
else
begin
data <= 0;
valid <= 0;
end
end
end
always #10ns clk <= ~clk;
initial #2us $stop;
endmodule
记分牌模块:
`timescale 1ns / 1ps
module scoreboard(clk, rst_n, data, valid, q, write);
input clk, rst_n;
input [7:0] data, q;
input valid, write;
//因为data和valid要和q和write做对比,所以要晚一拍,所以设置了data1,valid1。
reg [7:0] data1;
reg valid1;
//产生均衡寄存器,用来对齐data和q。
always @ (posedge clk)
begin
data1 <= data;
valid1 <= valid;
end
//断言判断
always @ (posedge clk)
begin
if (write) begin
assert (q == data1)//这里if换成了断言assert,优点是断言可以做覆盖,做基于断言的验证ABV。
$display("OK: data=%0d q=%0d",data1,q);
else
$error("ERROR: data=%0d q=%0d",data1,q);
end
end
endmodule
2.5.5 验证
功能仿真截图:
断言报告:
2.6 无反制传输例子二
下图所示的无反制流节点SE2,接收上游的8位无反制传输数据,传递给其下游的七段数码管显示电路。
任务目标:
- 若检测到data为奇数,并且小于250,则将data+1送下游q;
- 若检测到data为奇数,并且大于等于250,则将data直接送下游q;
- 若检测到data为偶数,则将0写入下游q;
- 为其设计,建模和ABV验证(基于断言的验证)
2.6.1 架构
引用典型方案,得到架构:
2.6.2 状态转移图
2.6.3 验证架构
基于断言的验证架构:
2.6.4 设计代码
设计模块:
`timescale 1ns / 1ps
module st_exampel2(clk, rst_n, valid, data, q, write);
input clk, rst_n;
input valid;
input [7:0] data;
output reg [7:0] q;
output reg write;
always @ (posedge clk)
begin : FSM
if (!rst_n)
begin
q <= 0;
write <= 0;
end
else if (valid && data <250 && data[0])
begin
q <= data + 1;
write <= 1;
end
else if (valid && data >= 250 && data[0])
begin
q <= data;
write <= 1;
end
else if (valid && ~data[0])
begin
q <= 0;
write <= 1;
end
else
write <= 0;
end
endmodule
验证模块:
`timescale 1ns / 1ps
module st_exampel2_tb;
logic clk, rst_n;
logic valid;
logic [7:0] data;
logic [7:0] q;
logic write;
stimulate STIM(
.clk(clk),
.rst_n(rst_n),
.valid(valid),
.data(data)
);
st_exampel2 DUT(
.clk(clk),
.rst_n(rst_n),
.valid(valid),
.data(data),
.q(q),
.write(write)
);
scoreboard SC(
.clk(clk),
.rst_n(rst_n),
.valid(valid),
.data(data),
.q(q),
.write(write)
);
endmodule
stimulate模块:
`timescale 1ns / 1ps
module stimulate(clk, rst_n, valid, data);
output reg clk, rst_n;
output reg valid;
output reg [7:0] data;
initial begin
clk <= 1;
rst_n <= 0;
data <= 0;
valid <= 0;
#200ns
@ (posedge clk)
rst_n <= 1;
#200ns
forever begin
@ (posedge clk)
if (({$random} % 16) >= 4)
begin
data <= {$random} % 256;
valid <= 1;
end
else
begin
data <= 0;
valid <= 0;
end
end
end
always #10ns clk <= ~clk;
initial #2us $stop;
endmodule
记分牌模块:
`timescale 1ns / 1ps
module scoreboard(clk, rst_n, valid, data, q, write);
input clk, rst_n;
input valid, write;
input [7:0] data, q;
reg [7:0] data1;
reg valid1;
always @ (posedge clk)
begin
data1 <= data;
valid1 <= valid;
end
always @ (posedge clk)
begin
if (write)
begin
if (data1 < 250 && data1[0])
begin
assert (q == data1 + 1)
$display("OK1: data=%0d q=%0d", data1, q);
else
$error("ERROR1: data=%0d q=%0d", data1, q);
end
else if (data1 >= 250 && data1[0])
begin
assert (q == data1)
$display("OK2: data=%0d q=%0d", data1, q);
else
$error("ERROR2: data=%0d q=%0d", data1, q);
end
else if (~data1[0])
begin
assert (q == 0)
$display("OK3: data=%0d q=%0d", data1, q);
else
$error("ERROR3: data=%0d q=%0d", data1, q);
end
end
end
endmodule
2.6.5 验证
功能仿真截图:
断言报告:
三 、流传输
流传输是所有复杂传输的基础。或者说,任何一种复杂数字逻辑通信,都可能被化简为流传输的组合。基于此,ARM的AMBR总线协议(AXI)提出:
1.将所有的复杂的通信形式,都进行流的单向化处理。
2.使得支持流单向化的AXI协议满足所有的通信协议。
3.1 流传输模型
ready:流传输的握手信息,下游的权力信号,由宿模块发出。其余均和2.1一样。
3.2 不对等规则
3.2.1 下游主动反制规则
下游主动反制规则是下游权重规则中的一种,称为SAB(Sink-Active Backpressure mode),在SAB中下游ready有最高优先级,全程主动,上游配合下游,获得条件主动。
3.2.2 下游快速反制规则
下游快速反制规则也是下游权重规则中的一种,称为SFB(Sink-Fast Backpressure),在SFB中仍然是下游的ready优先,但是与SAB不同的是,SFB中上游模块在没有下游信号时获得条件主动,当上游信号出现变化时,信号将被动保持,必须等待下游信号来,然后重新获得条件主动。
3.2.3 下游被动反制规则
下游被动反制规则其实是上游权重规则的一种,称为SPB(Sink-Passivity Backpressure),下游根据上游的valid决定是否ready。
3.3 就绪潜伏期和请求潜伏期
从下游宿接口发出就绪信号ready,至上游源接口发出数据,其时钟延迟称为就绪潜伏期ReadyLatency;
从上游源接口发出valid和data,至下游宿接口响应就绪ready,其时钟延迟称为请求潜伏期ValidLatency;
这里下游宿主接口发出ready到宿主接口接收到数据或者上游源接口发出valid到上游源接口得到响应的ready,其至少两拍的时钟延迟称为访问潜伏期AccessLatency。(这里特别强调访问潜伏期不一定等于就绪潜伏期加上请求潜伏期)
3.4 对称潜伏期
数字逻辑通信中,为保证最高传输效率,其架构模型要求对称潜伏期。从输入激励有效到输出响应有效的时钟延迟,称为进入潜伏期EntryLatency;从输入激励无效至输出响应无效的时钟延迟,称为退出潜伏期ExitLatency。数字逻辑通信的流节点架构要求:Entry Latency=Exit Latency
3.5 流域Streaming和流节点
数据信息在集成电路内部,从源头经过多个节点的加工处理后,到达最下游。这样的传输路径,称为流域Streaming。其中的节点称为流节点(StreamNode)。
为了保证最高效率和正确性。可以证明,流域中若所有节点遵循唯一规则,称为单规则流域。否则为多规则流域。
对于单规则流域:
- 对于下游主动反制SAB或者下游快速反制SFB单规则流域,流域中的所有流节点,必须具有唯一而且相同的就绪潜伏期ReadyLatency。
- 对于下游被动反制SPB的单规则流域,所有流节点,必须具有唯一而且相同的请求潜伏期ValidLatency。
四、下游主动反制SAB
4.1 传输模型
sab_source:SAB中的流传输源接口
sab_sink:SAB中的流传输宿接口
data:流传输的数据信息,单向,并且是从源流向宿
valid:流传输的握手信息,源权力信号
ready:流传输的握手信号,宿权力信号
4.2 传输规则
源接口传输规则:
- 源接口全程必须监听宿接口发出的就绪信号(ready)。
- 若源接口监听到ready为真,此时源接口进入条件主动。
- 源接口进入条件主动后,可以选择走,发出valid为真,并加载数据;也可以选择停,发出valid为假。
- 若源接口监听到ready为假,此时源接口进入被动等待。
宿接口传输规则:
- 下游宿接口全程主动,随时根据自身需要,发出走或者停。
- 若下游宿接口能够接收数据,则随时将ready设置为真;若不能够接收数据,则随时将ready设置为假。
- 若下游设置为真,则后续周期必须监听valid信号,若valid为真,则必须立即捕获data数据。否则停止捕获。
4.3 传输例子时序
当valid为真时传输数据,当valid为假时不用管
4.4 典型解决方案一(发散不参与源控)
下游主动反制SAB流节点的典型方案,采用流节点不参与反制。对上游的控制,称为源控(反制),对下游的控制,称为宿控。该典型解决方案一则是SAB的流节点,无源控,仅仅保留宿控。
- 架构
- 下游就绪潜伏期发散
证明:
DownReadyLatency = UpReadyLatency + LogicLatency
可以证明,在SAB的上述典型方案一中,下游就绪潜伏期满足:
DownReadyLatency = UpReadyLatency + LogicLatency
这里:
DownReadyLatency:下游就绪潜伏期
UpReadyLatency:上游就绪潜伏期
LogicLatency:本地流节点逻辑潜伏期
4.5 下游主动反制方案设计例子一
任务目标:
下图所示的两级异或电路,SAB设计方案一,建模和ABV验证;
4.5.1 架构
其ABV验证平台:
4.5.2 验证架构
4.5.3 设计代码
设计模块:
`timescale 1ns / 1ps
module sab_example1(clk, rst_n, up_data, up_valid, up_ready, down_data, down_valid, down_ready);
input clk, rst_n;
input [7:0] up_data;
input up_valid;
output up_ready;
output [7:0] down_data;
output down_valid;
input down_ready;
wire [7:0] sr0_data;
wire sr0_valid;
se1_reg SR0(
.clk(clk),
.rst_n(rst_n),
.data_in(up_data),
.valid_in(up_valid),
.data_out(sr0_data),
.valid_out(sr0_valid)
);
se1_reg SR1(
.clk(clk),
.rst_n(rst_n),
.data_in(sr0_data),
.valid_in(sr0_valid),
.data_out(down_data),
.valid_out(down_valid)
);
assign up_ready = down_ready;
endmodule
reg模块:
`timescale 1ns / 1ps
module se1_reg(clk, rst_n, data_in, valid_in, data_out, valid_out);
parameter KEY = 8'h55; //因为需要用异或所以定义parameter
input clk, rst_n;
input [7:0] data_in;
input valid_in;
output reg [7:0] data_out;
output reg valid_out;
always @ (posedge clk)
begin
if (!rst_n)
begin
data_out <= 0;
valid_out <= 0;
end
else
begin
data_out <= data_in ^ KEY; //同一个值异或两次还原;
valid_out <= valid_in; //上游为真(假),下游为真(假);
end
end
endmodule
仿真模块:
`timescale 1ns / 1ps
module sab_example1_tb;
logic clk, rst_n;
logic [7:0] down_data, up_data;
logic down_valid, up_valid, up_ready, down_ready;
stimulate STIM(
.clk(clk),
.rst_n(rst_n),
.up_data(up_data),
.up_valid(up_valid),
.up_ready(up_ready),
.down_ready(down_ready)
);
sab_example1 DUT(
.clk(clk),
.rst_n(rst_n),
.up_data(up_data),
.up_valid(up_valid),
.up_ready(up_ready),
.down_data(down_data),
.down_valid(down_valid),
.down_ready(down_ready)
);
scoreboard SC(
.clk(clk),
.rst_n(rst_n),
.down_data(down_data),
.down_valid(down_valid),
.up_data(up_data),
.up_valid(up_valid),
.up_ready(up_ready),
.down_ready(down_ready)
);
endmodule
stimulate模块:
`timescale 1ns / 1ps
module stimulate(clk, rst_n, up_data, up_valid, up_ready, down_ready);
output reg clk, rst_n;
output reg [7:0] up_data;
output reg up_valid, down_ready;
input up_ready; //握手
//时钟复位;
initial begin
clk <= 1;
rst_n <= 0;
#200ns
@ (posedge clk)
rst_n <= 1;
#20us $stop;
end
always #10ns clk <= ~clk;
//SAB上游源接口;
initial begin
up_data <= 0;
up_valid <= 0;
#200ns
forever begin
@ (posedge clk)
if (up_ready) //上游获得条件主动的前提是up_ready为真;
begin
if (({$random} % 16) > 4) //上游四分之三几率条件主动走;
begin
up_data <= {$random} % 256;
up_valid <= 1;
end
else //上游四分之一几率条件主动停;
up_valid <= 0;
end
else //上游被动停,必须停;
begin
up_valid <= 0;
end
end
end
//下游宿接口;
initial begin
down_ready <= 0;
#220ns
forever begin
@ (posedge clk)
if (({$random} % 16) > 4) //下游四分之三几率主动走;
down_ready <= 1;
else //下游四分之一几率主动停;
down_ready <= 0;
end
end
endmodule
记分牌模块:
`timescale 1ns / 1ps
module scoreboard(clk, rst_n, down_data, down_valid, up_data, up_valid, up_ready, down_ready);
input clk, rst_n;
input [7:0] down_data, up_data;
input down_valid, up_valid, up_ready, down_ready;
reg [7:0] mem [65535:0]; //验证存储器;
reg up_ready1; //上游就绪潜伏期需要均衡出来和上游的valid对齐;
reg down_ready1, down_ready2, down_ready3; //同理;
integer i,j; //验证存储器的指针,i=写指针,j=读指针;
//上游就绪潜伏期均衡;
always @ (posedge clk)
up_ready1 <= up_ready;
//下游就绪潜伏期均衡;
always @ (posedge clk)
begin
down_ready1 <= up_ready;
down_ready2 <= down_ready1;
down_ready3 <= down_ready2;
end
//上游数据捕获至存储器;
initial begin
i <= 0;
#200ns
forever begin
@ (posedge clk)
if (up_valid && up_ready1)
begin
mem[i] <= up_data;
i <= i + 1;
end
end
end
//下游数据捕获并且与验证存储器数据断言比较;
initial begin
j <= 0;
#220ns
forever begin
@ (posedge clk)
if (down_valid && down_ready3)
begin
assert (down_data == mem[j])
$display("OK: up_data=%0d down_data=%0d",mem[j],down_data);
else
$error("ERROR: up_data=%0d down_data=%0d",mem[j],down_data);
j <= j + 1;
end
end
end
endmodule
4.5.4 验证
功能仿真截图:
断言报告: