引言
接上篇,完成了RS前向打拍器的CBB设计。RS后向打拍器的设计则主要是为了缓解ready信号的时序问题。后向打拍器是对ready以及数据信号进行寄存。
RS后向打拍器的设计逻辑是这样的,复位时,ready缓存器(深度为1)对上游拉高ready,如果上游发来valid以及对应的数据,那么valid信号以及数据信号直接传给下游,data不需要缓存。如果后续的传输下游ready信号一直不反压上游,那么数据和有效信号不需要缓存直接传给下游。如果下游ready信号反压上游,阻塞传输,那么数据信号缓存一拍送至输出端口,等待握手,如果下游继续反压,则RS前向打拍器则会继续反压上游。其实可以理解为深度为1的握手缓存器。
CBB设计源码
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// ________ ________ ________
// |\ ____\ |\ __ \ |\ __ \
// \ \ \___| \ \ \|\ /_ \ \ \|\ /_
// \ \ \ \ \ __ \ \ \ __ \
// \ \ \____ \ \ \|\ \ \ \ \|\ \
// \ \_______\ \ \_______\ \ \_______\
// \|_______| \|_______| \|_______|
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// CBB Module Name :CBB_RS_BACKWARD
// CBB Created Date :2024-08-16
// CBB Module Function:Register Slice mode:backward
// Usage Limitation :
// Author :在路上-正出发
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
`timescale 1ns/1ps
module CBB_RS_BACKWARD#(
// ---- parameter define
parameter P_DATA_WIDTH = 64
)(
// ---- port define
input i_clk,
input i_rstn,
input slv_i_valid,
input [P_DATA_WIDTH-1:0] slv_i_data,
output slv_o_ready,
output mst_o_valid,
output [P_DATA_WIDTH-1:0] mst_o_data,
input mst_i_ready
);
reg r_mst_i_ready;
always @(posedge i_clk or negedge i_rstn) begin : proc_ready
if(~i_rstn) begin
r_mst_i_ready <= 1'b1;
end else if (mst_o_valid)begin
r_mst_i_ready <= mst_i_ready;
end
end
reg [P_DATA_WIDTH-1:0] r_mst_o_data;
always @(posedge i_clk) begin : proc_data
if (slv_i_valid & slv_o_ready)begin
r_mst_o_data <= slv_i_data;
end
end
assign mst_o_data = slv_o_ready ? slv_i_data : r_mst_o_data;
assign slv_o_ready= r_mst_i_ready;
assign mst_o_valid= slv_i_valid | (~slv_o_ready);
endmodule
CBB验证
从侧 valid信号拉高的时间间隔随机,且拉高的时机与ready无关,主侧ready信号拉高的持续时间随机,相邻两个高电平之间的间隔随机。包括各种反压case。
验证源码
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// ________ ________ ________
// |\ ____\ |\ __ \ |\ __ \
// \ \ \___| \ \ \|\ /_ \ \ \|\ /_
// \ \ \ \ \ __ \ \ \ __ \
// \ \ \____ \ \ \|\ \ \ \ \|\ \
// \ \_______\ \ \_______\ \ \_______\
// \|_______| \|_______| \|_______|
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// CBB Module Name :TB_RS_BACKWARD
// CBB Created Date :2024-08-17
// CBB Module Function:
// Usage Limitation :
// Author :在路上-正出发
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
`timescale 1ns/1ps
module TB_RS_BACKWARD();
// ---- parameter define
parameter P_DATA_WIDTH = 32;
// ---- port define
reg i_clk;
reg i_rstn;
reg slv_i_valid;
reg [P_DATA_WIDTH-1:0] slv_i_data;
wire slv_o_ready;
wire mst_o_valid;
wire [P_DATA_WIDTH-1:0] mst_o_data;
reg mst_i_ready;
initial i_clk = 1'b0;
always #5 i_clk = ~i_clk;
integer time_dly1,time_dly2;
integer sim_ctrl;
initial
begin
i_rstn = 1'b0;
mst_i_ready = 1'b0;
#20;
i_rstn = 1'b1;
#20;
repeat(20)
begin
time_dly1 = $urandom_range(1,10);
repeat(time_dly1)
begin
@(posedge i_clk);
end
@(posedge i_clk)
mst_i_ready <= 1'b1;
time_dly1 = $urandom_range(1,10);
repeat(time_dly1)
begin
@(posedge i_clk);
end
@(posedge i_clk)
mst_i_ready <= 1'b0;
end
end
initial
begin
sim_ctrl = 1;
slv_i_valid = 1'b0;
slv_i_data = 0;
@(posedge i_rstn);
#20;
repeat(20)
begin
@(posedge i_clk)
slv_i_valid <= 1'b1;
slv_i_data <= $random();
while(~slv_o_ready) @(posedge i_clk);
@(posedge i_clk)
slv_i_valid <= 1'b0;
slv_i_data <= 0;
time_dly2 = $urandom_range(1,10);
repeat(time_dly2) @(posedge i_clk);
end
#200;
sim_ctrl = 0;
#100;
$finish;
end
integer file_handle_slv,file_handle_mst;
initial
begin
file_handle_slv = $fopen("D:/VIVADO_WORK_SPACE/CBB_DESIGN/SIM_TXT/CBB_RS_BACKWARD_SLV_DATA.txt","w+");
while(sim_ctrl)
begin
if(slv_i_valid&slv_o_ready)
begin
$fdisplayh(file_handle_slv,slv_i_data);
$display("slv_i_data = %h",slv_i_data);
@(posedge i_clk);
end
else
begin
@(posedge i_clk);
end
end
$fclose(file_handle_slv);
end
initial
begin
file_handle_mst = $fopen("D:/VIVADO_WORK_SPACE/CBB_DESIGN/SIM_TXT/CBB_RS_BACKWARD_MST_DATA.txt","w+");
while(sim_ctrl)
begin
if(mst_o_valid&mst_i_ready)
begin
$fdisplayh(file_handle_mst,mst_o_data);
@(posedge i_clk);
end
else
begin
@(posedge i_clk);
end
end
$fclose(file_handle_mst);
end
CBB_RS_BACKWARD #(
.P_DATA_WIDTH(P_DATA_WIDTH)
) U_CBB_RS_BACKWARD (
.i_clk (i_clk),
.i_rstn (i_rstn),
.slv_i_valid (slv_i_valid),
.slv_i_data (slv_i_data),
.slv_o_ready (slv_o_ready),
.mst_o_valid (mst_o_valid),
.mst_o_data (mst_o_data),
.mst_i_ready (mst_i_ready)
);
endmodule
波形
数据比对
验证时将主侧和从侧的握手数据记录下来并存放于文件中,利用perl脚本完成对数据的逐行比对。对比数据的完整性、准确性、顺序性。
perl脚本源码
=pod
=================================
时间:2024-08-17
作者:在路上-正出发
摘要:实现文本的逐行对比
=================================
=cut
use warnings;
my $txt_a_path = "D:\\VIVADO_WORK_SPACE\\CBB_DESIGN/SIM_TXT\\CBB_RS_BACKWARD_SLV_DATA.txt";
my $txt_b_path = "D:\\VIVADO_WORK_SPACE\\CBB_DESIGN/SIM_TXT\\CBB_RS_BACKWARD_MST_DATA.txt";
if((-e $txt_a_path) and (-e $txt_b_path))
{
if((-s $txt_a_path) != (-s $txt_b_path))
{
die "文件大小不一致!\n";
}
}
else
{
die "文件不存在!\n";
}
open txt_a_handle , "<$txt_a_path\n" || die "can't open $txt_a_path\n";
open txt_b_handle , "<$txt_b_path\n" || die "can't open $txt_b_path\n";
my $line_txt_a;
my $line_txt_b;
my $error_flag=0;
my $line_cnt = 0;
while($line_txt_a = <txt_a_handle>)
{
$line_cnt = $line_cnt + 1;
$line_txt_b = <txt_b_handle>;
if($line_txt_a ne $line_txt_b)
{
$error_flag = 1;
print "[ERROR]this line is not same!,line num = ".$line_cnt."\n";
}
}
close(txt_a_handle);
close(txt_b_handle);
if($error_flag)
{
print " _____ _ _ " . "\n";
print " |\" ___| U /\"\\ u ___ |\"| " . "\n";
print "U| |_ u \\/ _ \\/ |_\"_| U | | u " . "\n";
print "\\| _|/ / ___ \\ | | \\| |/__ " . "\n";
print " |_| /_/ \\_\\ U/| |\\u |_____|" . "\n";
print " )(\\\\,- \\\\ >> .-,_|___|_,-. // \\\\ " . "\n";
print "(__)(_/ (__) (__) \\_)-' '-(_/ (_\")(\"_)" . "\n";
}
else
{
print " ____ _ ____ ____ " ."\n";
print "U| _\"\\ u U /\"\\ u / __\"| u / __\"| u " ."\n";
print "\\| |_) |/ \\/ _ \\/ <\\___ \\/ <\\___ \\/ " ."\n";
print " | __/ / ___ \\ u___) | u___) | " ."\n";
print " |_| /_/ \\_\\ |____/>> |____/>> " ."\n";
print " ||>>_ \\\\ >> )( (__) )( (__)" ."\n";
print "(__)__) (__) (__) (__) (__) " ."\n";
}