声明:因为这是个人项目,仅提供于学习交流展示。所以我将我的代码删减了一些重要部分,我也没有提供完整的测试文件,因此我的代码无法直接运行。这样做的主要目的是避免有人恶意抄袭,借本项目冒充个人成果。
对于硬件神经网络的实现,可以大致区分为硬件神经元本身以及神经网络本身。
对于硬件神经网络的单个节点,其主要功能为与内部的神经元进行数据交互,同时它也要负责与外部的神经元进行信息交互。
首先是其内部单元架构,其内部单元主要包括发送数据单元,接收数据单元,存储数据单元,以及与Neuron Core相连接的单元,大致示意图如下所示:
其次是网络节点与外部的连接,整体架构如下图所示。我们设定的是平面网络结构,因此可以将其分为东南西北四个方向。 每一个连接线路中间都有一个reg作为数据的缓存,以及一个flag作为数据缓存位的标志位。
其中,Router连接之间的reg的标志位是由连接双方所决定的。也就是说,在接受双方都会提供一个标志位来共同决定缓存reg的标志位。其具体架构以及使用办法如下图所示:
下面是例程代码:
1.1 发送数据模块
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2025/04/11 00:38:25
// Design Name:
// Module Name: send_one
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module send_one(
input sys_clk ,
input sys_rst_n ,
// 来自FIFO的数据指示
input empty ,
// data input
// 来自FIFO的数据输出
input [ 7:0] data_output ,
// data output
// 即将传输给四个方向,以及内核core的数据
output reg [ 7:0] send_west_data ,
output reg [ 7:0] send_east_data ,
output reg [ 7:0] send_north_data ,
output reg [ 7:0] send_south_data ,
output reg [ 7:0] send_core_data ,
// flag singal, 1 means there is data data
// 传输标志位,已在Router_One文件中解释清楚
input send_west_flag ,
input send_east_flag ,
input send_north_flag ,
input send_south_flag ,
input send_core_flag ,
// self singal
// 已在Router_One文件中解释清楚
output reg send_west_flag_B ,
output reg send_east_flag_B ,
output reg send_north_flag_B ,
output reg send_south_flag_B ,
output reg send_core_flag_B ,
output reg rd_en
);
// any data have, sign is valid
// flag==0, means there is empty reg
// 数据中转标志,表示当前的数据是否已经被处理
reg send_center_flag ;
// 表示当前Router的位置,用于判断数据传输方向
parameter localpostion=2'b00 ;
always @(negedge sys_rst_n or negedge sys_clk) begin
if (!sys_rst_n) begin
// 在复位时所有的标志位都清0
send_west_flag_B<=0;
send_east_flag_B<=0;
send_north_flag_B<=0;
send_south_flag_B<=0;
send_core_flag_B<=0;
// 数据的存储寄存器也清零
send_west_data<=0;
send_east_data<=0;
send_north_data<=0;
send_south_data<=0;
send_core_data<=0;
// 数据的核心中转标志也清零
send_center_flag<=0;
end
// 首先判断是否已将准备好将数据传输到别的方向
else if (send_center_flag==1) begin
// North //
// West Center East //
// South //
// judge the East and West
// 先判断东西方向(左右)
if (data_output[7]>localpostion[1]) begin
// 再判断这个位置是否已经空出来了
if (send_west_flag==0) begin
// 如果空出来了,那么就将数据传输到此位
// 将向外发送标志位取反,告诉外面这里已经有数据了
// 将向内的标志位清零,表示可以接受新的数据
send_center_flag<=0;
end
else begin
// 如果没有空出来,就继续等待,同时向内的标志位置1,表示还不能接受新的数据
send_center_flag<=1;
end
end
else if (data_output[7]<localpostion[1]) begin
if(send_east_flag==0) begin
send_east_data<=data_output;
send_center_flag<=0;
end
else begin
send_center_flag<=1;
end
end
// judge the North and South
// 在判断南北方向(上下)
else if (data_output[6]>localpostion[0]) begin
if (send_north_flag==0) begin
send_north_data<=data_output;
send_center_flag<=0;
end
else begin
send_center_flag<=1;
end
end
else if (data_output[6]<localpostion[0]) begin
if (send_south_flag==0) begin
send_south_data<=data_output;
send_center_flag<=0;
end
else begin
send_center_flag<=1;
end
end
// if the data arrive the terminal, send it to the core
// 如果到了这里,那说明该数据已经抵达目标位置了
else begin
// 同样,还是判断传向core block的位置有没有空出来
if (send_core_flag==0) begin
// 如果空出来了,那么就将数据传输到此位
send_core_data<=data_output;
// 将向外发送标志位取反,告诉外面这里已经有数据了
// 将向内的标志位清零,表示可以接受新的数据
end
else begin
// 如果没有空出来,就继续等待,同时向内的标志位置1,表示还不能接受新的数据
end
end
end
else begin
end
end
// manage the fifo
// 管理FIFO的数据出入
always @(negedge sys_rst_n or negedge sys_clk) begin
if (!sys_rst_n) begin
rd_en<=0;
end
// 如果要更新一次输出数据,首先判断FIFO内是否还有数据,同时判断外部的寄存器是否能接受新的数据
// 可以的话,下一个clk刷新新的数据
// 同时更新标志位,表示当前已经有数据需要被处理了
// 如果条件不满足,那就不更新数据
else begin
rd_en<=0;
end
end
endmodule
1.2 发送数据模块测试文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2025/04/15 22:04:45
// Design Name:
// Module Name: tb_send_one
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_send_one(
);
// Inputs
reg sys_clk ;
reg sys_rst_n ;
reg send_west_flag ;
reg send_east_flag ;
reg send_north_flag ;
reg send_south_flag ;
reg send_core_flag ;
// Outputs
wire [ 7:0] send_west_data ;
wire [ 7:0] send_east_data ;
wire [ 7:0] send_north_data ;
wire [ 7:0] send_south_data ;
wire [ 7:0] send_core_data ;
// send_one data
wire send_west_flag_B ;
wire send_east_flag_B ;
wire send_north_flag_B ;
wire send_south_flag_B ;
wire send_core_flag_B ;
// fifo data
reg wr_en ;
reg [ 7:0] data_in ;
wire fifo_full ;
wire empty ;
wire [ 7:0] data_output ;
wire [ 9:0] wr_data_count ;
wire [ 9:0] rd_data_count ;
wire rd_en ;
// Instantiate the Unit Under Test (UUT)
send_one uut (
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.empty (empty ),
.data_output (data_output ),
.send_west_data (send_west_data ),
.send_east_data (send_east_data ),
.send_north_data (send_north_data ),
.send_south_data (send_south_data ),
.send_core_data (send_core_data ),
.send_west_flag (send_west_flag ),
.send_east_flag (send_east_flag ),
.send_north_flag (send_north_flag ),
.send_south_flag (send_south_flag ),
.send_core_flag (send_core_flag ),
.send_west_flag_B (send_west_flag_B ),
.send_east_flag_B (send_east_flag_B ),
.send_north_flag_B (send_north_flag_B ),
.send_south_flag_B (send_south_flag_B ),
.send_core_flag_B (send_core_flag_B ),
.rd_en (rd_en )
);
// Instantiate fifo_one
fifo_generator_0 u_fifo_generator_0(
.rst (~sys_rst_n ),
.wr_clk (sys_clk ),
.rd_clk (sys_clk ),
.wr_en (wr_en ),
.rd_en (rd_en ),
.din (data_in ),
.dout (data_output ),
.almost_full (almost_full ),
.almost_empty (almost_empty ),
.full (fifo_full ),
.empty (empty ),
.wr_data_count (wr_data_count ),
.rd_data_count (rd_data_count ),
.wr_rst_busy (wr_rst_busy ),
.rd_rst_busy (rd_rst_busy )
);
// store the data in fifo
initial begin
wr_en<=0;
sys_rst_n = 0;
send_west_flag<=0;
send_east_flag<=0;
send_north_flag<=0;
send_south_flag<=0;
send_core_flag<=0;
data_in<=0;
// open the fifo and restore some data
// Release reset
#200 sys_rst_n = 1;
// write data to fifo
#600 wr_en<=1;
data_in<=8'b00_000001;
#20 data_in<=8'b01_000001;
#20 data_in<=8'b10_000001;
#20 data_in<=8'b01_000010;
#20 data_in<=8'b11_000010;
end
endmodule
2.1 接受数据模块
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2025/04/11 00:37:51
// Design Name:
// Module Name: recive_one
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module recive_one(
input sys_clk ,
input sys_rst_n ,
input full ,
// flag input
input [ 7:0] recive_west_data ,
input [ 7:0] recive_east_data ,
input [ 7:0] recive_north_data ,
input [ 7:0] recive_south_data ,
input [ 7:0] recive_local1_data ,
input [ 7:0] recive_local2_data ,
// flag singal, 1 means there is data data
input recive_west_flag ,
input recive_east_flag ,
input recive_north_flag ,
input recive_south_flag ,
input recive_local1_flag ,
input recive_local2_flag ,
// self flag
output reg recive_west_flag_A ,
output reg recive_east_flag_A ,
output reg recive_north_flag_A ,
output reg recive_south_flag_A ,
output reg recive_local1_flag_A ,
output reg recive_local2_flag_A ,
// write flag
output reg wr_en ,
// data output
output reg [ 7:0] data_in
);
// flag to judge there is data or not
// 这个标志位表示一个总的数据汇总
wire recive_flag ;
// any data have, sign is valid
parameter localpostion=2'b00 ;
always @(negedge sys_rst_n or posedge sys_clk) begin
if (!sys_rst_n) begin
recive_west_flag_A<=0;
recive_east_flag_A<=0;
recive_north_flag_A<=0;
recive_south_flag_A<=0;
recive_local1_flag_A<=0;
recive_local2_flag_A<=0;
wr_en<=0;
data_in<=0;
end
// 如果有数据需要被接受,且FIFO也还没满
else if (recive_flag==1&&full!=1) begin
// 先判断是哪一个方向有数据需要被接受了
// 这里一定要注意!!!
// 虽然可能会有很多个数据都需要被接受,也就是下面的判定可能会被满足很多次
// 但我们只允许执行一次写操作,因为只有一个FIFO,如果同时处理,则可能会遗漏数据
if (recive_west_flag==1) begin
// 将这个需要被接受的数据传给FIFO
data_in<=recive_west_data;
end
else if (recive_east_flag==1) begin
data_in<=recive_east_data;
end
else if (recive_north_flag==1) begin
data_in<=recive_north_data;
end
else if (recive_south_flag==1) begin
data_in<=recive_south_data;
end
else if (recive_local1_flag==1) begin
data_in<=recive_local1_data;
end
else if (recive_local2_flag==1) begin
data_in<=recive_local2_data;
end
// 在准备好数据过后,写使能有效,将数据给写进去
end
else begin
// 否则就不管
end
end
endmodule
2.2 接受数据模块测试文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2025/04/11 17:59:59
// Design Name:
// Module Name: tb_recive_one
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_recive_one(
);
// Clock and reset
reg sys_clk ;
reg sys_rst_n ;
// Inputs to recive_one
reg [ 7:0] recive_west_data, recive_east_data, recive_north_data, recive_south_data, recive_local1_data, recive_local2_data;
wire recive_west_flag, recive_east_flag, recive_north_flag, recive_south_flag, recive_local1_flag, recive_local2_flag;
// Outputs from recive_one
wire wr_en ;
wire [ 7:0] data_in ;
wire recive_west_flag_A ;
wire recive_east_flag_A ;
wire recive_north_flag_A ;
wire recive_south_flag_A ;
wire recive_local1_flag_A ;
wire recive_local2_flag_A ;
reg recive_west_flag_B ;
reg recive_east_flag_B ;
reg recive_north_flag_B ;
reg recive_south_flag_B ;
reg recive_local1_flag_B ;
reg recive_local2_flag_B ;
// FIFO signals
wire fifo_full ,fifo_empty ;
wire [ 7:0] fifo_rd_data ;
wire [ 9:0] wr_data_count ;
wire [ 9:0] rd_data_count ;
reg rd_en ;
assign recive_local1_flag=(recive_local1_flag_A^recive_local1_flag_B);
assign recive_local2_flag=(recive_local2_flag_A^recive_local2_flag_B);
recive_one uut_recive_one (
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.full (fifo_full ),
.recive_west_data (recive_west_data ),
.recive_east_data (recive_east_data ),
.recive_north_data (recive_north_data ),
.recive_south_data (recive_south_data ),
.recive_local1_data (recive_local1_data ),
.recive_local2_data (recive_local2_data ),
.recive_west_flag (recive_west_flag ),
.recive_east_flag (recive_east_flag ),
.recive_north_flag (recive_north_flag ),
.recive_south_flag (recive_south_flag ),
.recive_local1_flag (recive_local1_flag ),
.recive_local2_flag (recive_local2_flag ),
.recive_west_flag_A (recive_west_flag_A ),
.recive_east_flag_A (recive_east_flag_A ),
.recive_north_flag_A (recive_north_flag_A ),
.recive_south_flag_A (recive_south_flag_A ),
.recive_local1_flag_A (recive_local1_flag_A ),
.recive_local2_flag_A (recive_local2_flag_A ),
.wr_en (wr_en ),
.data_in (data_in )
);
// Instantiate fifo_one
fifo_generator_0 u_fifo_generator_0(
.rst (~sys_rst_n ),//
.wr_clk (sys_clk ),//
.rd_clk (sys_clk ),//
.wr_en (wr_en ),
.rd_en (rd_en ),
.din (data_in ),
.dout (fifo_rd_data ),
.almost_full (almost_full ),
.almost_empty (almost_empty ),
.full (fifo_full ),
.empty (fifo_empty ),
.wr_data_count (wr_data_count ),
.rd_data_count (rd_data_count ),
.wr_rst_busy (wr_rst_busy ),
.rd_rst_busy (rd_rst_busy )
);
// Test sequence
initial begin
// Initialize inputs
sys_rst_n = 0;
recive_west_data = 8'h00;
recive_east_data = 8'h00;
recive_north_data = 8'h00;
recive_south_data = 8'h00;
recive_local1_data = 8'h00;
recive_local2_data = 8'h00;
recive_west_flag_B=0;
recive_east_flag_B=0;
recive_north_flag_B=0;
recive_south_flag_B=0;
recive_local1_flag_B=0;
recive_local2_flag_B=0;
rd_en = 0;
// Release reset
#400 sys_rst_n = 1;
// Test case 1: Send a data from the west
#3000
recive_west_data = 8'hAA;
recive_south_data = 8'hDD;
recive_west_flag_B=~recive_west_flag_B;
recive_south_flag_B=~recive_south_flag_B;
// Test case 3: Read data from FIFO
#200 rd_en = 1;
end
endmodule
3.1 顶层文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2025/04/08 23:12:41
// Design Name:
// Module Name: Router_5
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module Router_One(
// system input
input sys_clk ,
input sys_rst_n ,
// Recive Data //
// Recive Data //
// Recive Data //
// flag input
// 下面的是针对Router的来自四个方向的输入
input [ 7:0] recive_west_data ,
input [ 7:0] recive_east_data ,
input [ 7:0] recive_north_data ,
input [ 7:0] recive_south_data ,
// flag singal (1 means there is data data)
// 下面是接受标志位,一但其中某个flag为1,则表示有数据包
input recive_west_flag ,
input recive_east_flag ,
input recive_north_flag ,
input recive_south_flag ,
// self flag
// flag_A是来自接受方的标志位
// flag_B是来自发送方的标志位
// 一般flag与flag_A与flag_B之间存在关系:
// send_west_flag=(send_west_flag_A^send_west_flag_B);
// 一开始,flag_A与flag_B都为0,表示没有数据
// 一但自己完成了对数据的处理,此时flag_A反转,表示可以接受新数据
// 当外方放入新的数据,flag_B反转,表示已经放入新数据
output recive_west_flag_A ,
output recive_east_flag_A ,
output recive_north_flag_A ,
output recive_south_flag_A ,
// Send Data //
// Send Data //
// Send Data //
// data output
// 下面是往外面四个方向的传输数据
output [ 7:0] send_west_data ,
output [ 7:0] send_east_data ,
output [ 7:0] send_north_data ,
output [ 7:0] send_south_data ,
// flag singal (1 means there is data data)
// 数据发送标志位,以上面的接受flag类似(事实上就是同一个信号)
// 为0表示位置为空,可以传输数据,为1表示位置有数据,不能传输数据
input send_west_flag ,
input send_east_flag ,
input send_north_flag ,
input send_south_flag ,
// self singal
// flag_B已经在上面解释过了
output send_west_flag_B ,
output send_east_flag_B ,
output send_north_flag_B ,
output send_south_flag_B ,
// Core Data //
// Core Data //
// Core Data //
// data connect with buffer
// send_core_flag是与内核计算单元的数据中转量
input send_core_flag ,
// send_core_flag_B来自发送给core block一方的标志位
output send_core_flag_B ,
// 最终发送到core block的buffer
output reg [ 63:0] buffer_64 ,
// recive_local1_data和recive_local2_data是来自core block一方的数据
input [ 7:0] recive_local1_data ,
input [ 7:0] recive_local2_data ,
// 类似的,表示数据是否已经接受的标志位
input recive_local1_flag ,
input recive_local2_flag ,
// 来自core block一方的标志位
output recive_local1_flag_A ,
output recive_local2_flag_A
);
// 即将发送给Router的一个中间变量
wire [ 7:0] send_core_data ;
// 给FIFO的中间变量
wire [ 7:0] data_in ;
wire [ 7:0] data_output ;
wire wr_en ;
wire rd_en ;
wire almost_full ;
wire almost_empty ;
wire full ;
wire empty ;
wire [ 7:0] wr_data_count ;
wire [ 7:0] rd_data_count ;
wire wr_rst_busy ;
wire rd_rst_busy ;
// Instantiate fifo_one
fifo_generator_0 u_fifo_generator_0(
.rst (~sys_rst_n ),
.wr_clk (sys_clk ),
.rd_clk (sys_clk ),
.wr_en (wr_en ),
.rd_en (rd_en ),
.din (data_in ),
.dout (data_output ),
.almost_full (almost_full ),
.almost_empty (almost_empty ),
.full (full ),
.empty (empty ),
.wr_data_count (wr_data_count ),
.rd_data_count (rd_data_count ),
.wr_rst_busy (wr_rst_busy ),
.rd_rst_busy (rd_rst_busy )
);
// recive part
recive_one u_recive_one(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.full (full ),
// flag input
.recive_west_data (recive_west_data ),
.recive_east_data (recive_east_data ),
.recive_north_data (recive_north_data ),
.recive_south_data (recive_south_data ),
.recive_local1_data (recive_local1_data ),
.recive_local2_data (recive_local2_data ),
// flag singal, 1 means there is data data
.recive_west_flag (recive_west_flag ),
.recive_east_flag (recive_east_flag ),
.recive_north_flag (recive_north_flag ),
.recive_south_flag (recive_south_flag ),
.recive_local1_flag (recive_local1_flag ),
.recive_local2_flag (recive_local2_flag ),
// self flag
.recive_west_flag_A (recive_west_flag_A ),
.recive_east_flag_A (recive_east_flag_A ),
.recive_north_flag_A (recive_north_flag_A ),
.recive_south_flag_A (recive_south_flag_A ),
.recive_local1_flag_A (recive_local1_flag_A ),
.recive_local2_flag_A (recive_local2_flag_A ),
// write flag
.wr_en (wr_en ),
// data output
.data_in (data_in )
);
// send part
send_one u_send_one(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.empty (empty ),
// data input
.data_output (data_output ),
// data output
.send_west_data (send_west_data ),
.send_east_data (send_east_data ),
.send_north_data (send_north_data ),
.send_south_data (send_south_data ),
.send_core_data (send_core_data ),
// flag singal, 1 means there is data data
.send_west_flag (send_west_flag ),
.send_east_flag (send_east_flag ),
.send_north_flag (send_north_flag ),
.send_south_flag (send_south_flag ),
.send_core_flag (send_core_flag ),
// self singal
.send_west_flag_B (send_west_flag_B ),
.send_east_flag_B (send_east_flag_B ),
.send_north_flag_B (send_north_flag_B ),
.send_south_flag_B (send_south_flag_B ),
.send_core_flag_B (send_core_flag_B ),
.rd_en (rd_en )
);
// deal with the data from send to center part
// 这里是把data最后传输给buffer的实际位置
always @(negedge sys_rst_n or posedge sys_clk) begin
if (!sys_rst_n) begin
buffer_64<=0;
end
// 先判断是否有有需要处理的数据,然后在进行分配
else if () begin
case ()
6'b000000:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001;
6'b000001:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0010;
6'b000010:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100;
6'b000011:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_1000;
6'b000100:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000;
6'b000101:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0010_0000;
6'b000110:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000;
6'b000111:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_1000_0000;
6'b001000:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0000;
6'b001001:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0010_0000_0000;
6'b001010:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_0000;
6'b001011:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_1000_0000_0000;
6'b001100:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0000_0000;
6'b001101:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0010_0000_0000_0000;
6'b001110:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_0000_0000;
6'b001111:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_1000_0000_0000_0000;
6'b010000:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0000_0000_0000;
6'b010001:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0010_0000_0000_0000_0000;
6'b010010:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_0000_0000_0000;
6'b010011:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_1000_0000_0000_0000_0000;
6'b010100:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0000_0000_0000_0000;
6'b010101:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0010_0000_0000_0000_0000_0000;
6'b010110:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_0000_0000_0000_0000;
6'b010111:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_1000_0000_0000_0000_0000_0000;
6'b011000:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0000_0000_0000_0000_0000;
6'b011001:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0010_0000_0000_0000_0000_0000_0000;
6'b011010:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_0000_0000_0000_0000_0000;
6'b011011:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0000_1000_0000_0000_0000_0000_0000_0000;
6'b011100:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0001_0000_0000_0000_0000_0000_0000_0000;
6'b011101:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0010_0000_0000_0000_0000_0000_0000_0000;
6'b011110:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_0100_0000_0000_0000_0000_0000_0000_0000;
6'b011111:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0000_1000_0000_0000_0000_0000_0000_0000_0000;
6'b100000:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0001_0000_0000_0000_0000_0000_0000_0000_0000;
6'b100001:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0010_0000_0000_0000_0000_0000_0000_0000_0000;
6'b100010:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_0100_0000_0000_0000_0000_0000_0000_0000_0000;
6'b100011:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0000_1000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b100100:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0001_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b100101:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0010_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b100110:buffer_64<=64'b0000_0000_0000_0000_0000_0000_0100_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b100111:buffer_64<=64'b0000_0000_0000_0000_0000_0000_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b101000:buffer_64<=64'b0000_0000_0000_0000_0000_0001_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b101001:buffer_64<=64'b0000_0000_0000_0000_0000_0010_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b101010:buffer_64<=64'b0000_0000_0000_0000_0000_0100_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b101011:buffer_64<=64'b0000_0000_0000_0000_0000_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b101100:buffer_64<=64'b0000_0000_0000_0000_0001_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b101101:buffer_64<=64'b0000_0000_0000_0000_0010_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b101110:buffer_64<=64'b0000_0000_0000_0000_0100_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b101111:buffer_64<=64'b0000_0000_0000_0000_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b110000:buffer_64<=64'b0000_0000_0000_0001_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b110001:buffer_64<=64'b0000_0000_0000_0010_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b110010:buffer_64<=64'b0000_0000_0000_0100_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b110011:buffer_64<=64'b0000_0000_0000_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b110100:buffer_64<=64'b0000_0000_0001_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b110101:buffer_64<=64'b0000_0000_0010_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b110110:buffer_64<=64'b0000_0000_0100_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b110111:buffer_64<=64'b0000_0000_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b111000:buffer_64<=64'b0000_0001_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b111001:buffer_64<=64'b0000_0010_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b111010:buffer_64<=64'b0000_0100_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b111011:buffer_64<=64'b0000_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b111100:buffer_64<=64'b0001_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b111101:buffer_64<=64'b0010_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b111110:buffer_64<=64'b0100_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
6'b111111:buffer_64<=64'b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
default:buffer_64<=0;
endcase
end
end
endmodule
3.2 顶层测试文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2025/04/19 23:24:38
// Design Name:
// Module Name: tb_Router_one
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_Router_one(
);
reg sys_clk ;
reg sys_rst_n ;
// Recive Data //
// Recive Data //
// Recive Data //
reg [ 7:0] recive_west_data ;
reg [ 7:0] recive_east_data ;
reg [ 7:0] recive_north_data ;
reg [ 7:0] recive_south_data ;
reg [ 7:0] recive_local1_data ;
reg [ 7:0] recive_local2_data ;
wire recive_west_flag_A ;
wire recive_east_flag_A ;
wire recive_north_flag_A ;
wire recive_south_flag_A ;
wire recive_local1_flag_A ;
wire recive_local2_flag_A ;
// Send Data //
// Send Data //
// Send Data //
wire [ 7:0] send_west_data ;
wire [ 7:0] send_east_data ;
wire [ 7:0] send_north_data ;
wire [ 7:0] send_south_data ;
reg send_west_flag ;
reg send_east_flag ;
reg send_north_flag ;
reg send_south_flag ;
wire send_core_flag ;
wire send_west_flag_B ;
wire send_east_flag_B ;
wire send_north_flag_B ;
wire send_south_flag_B ;
wire send_core_flag_B ;
reg recive_west_flag_B ;
reg recive_east_flag_B ;
reg recive_north_flag_B ;
reg recive_south_flag_B ;
reg recive_local1_flag_B ;
reg recive_local2_flag_B ;
// Core Data //
// Core Data //
// Core Data //
// output to buffer
wire [ 63:0] buffer_64 ;
// 上面的数据变量基本都在Router_One中定义了,这里依据变量的名字也大概能判断
// 这里就是将flag_A和flag_B进行异或,得到flag,这样就可以判断flag是否发生变化
wire recive_west_flag ;
wire recive_east_flag ;
wire recive_north_flag ;
wire recive_south_flag ;
wire recive_local1_flag ;
wire recive_local2_flag ;
// 这里也是一样,只是没有core block单元,所以这里的测试文件我们代替core block进行操作
// 理论上这里send_core_flag_A由core block控制
// 如果他完成了buffer输入数据的处理,这里就是改变flag_A表示已经处理好了,可以接受新数据
reg send_core_flag_A ;
assign send_core_flag = (send_core_flag_B^send_core_flag_A);
// 下面的Router_One已经在之前的文件里定义过了
Router_One u_Router_One(
// system input
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
// Recive Data //
// Recive Data //
// Recive Data //
// flag input
.recive_west_data (recive_west_data ),
.recive_east_data (recive_east_data ),
.recive_north_data (recive_north_data ),
.recive_south_data (recive_south_data ),
.recive_local1_data (recive_local1_data ),
.recive_local2_data (recive_local2_data ),
// flag singal(1 means there is data data)
.recive_west_flag (recive_west_flag ),
.recive_east_flag (recive_east_flag ),
.recive_north_flag (recive_north_flag ),
.recive_south_flag (recive_south_flag ),
.recive_local1_flag (recive_local1_flag ),
.recive_local2_flag (recive_local2_flag ),
// self flag
.recive_west_flag_A (recive_west_flag_A ),
.recive_east_flag_A (recive_east_flag_A ),
.recive_north_flag_A (recive_north_flag_A ),
.recive_south_flag_A (recive_south_flag_A ),
.recive_local1_flag_A (recive_local1_flag_A ),
.recive_local2_flag_A (recive_local2_flag_A ),
// Send Data //
// Send Data //
// Send Data //
// data output
.send_west_data (send_west_data ),
.send_east_data (send_east_data ),
.send_north_data (send_north_data ),
.send_south_data (send_south_data ),
// flag singal(1 means there is data data)
.send_west_flag (send_west_flag ),
.send_east_flag (send_east_flag ),
.send_north_flag (send_north_flag ),
.send_south_flag (send_south_flag ),
.send_core_flag (send_core_flag ),
// self singal
.send_west_flag_B (send_west_flag_B ),
.send_east_flag_B (send_east_flag_B ),
.send_north_flag_B (send_north_flag_B ),
.send_south_flag_B (send_south_flag_B ),
.send_core_flag_B (send_core_flag_B ),
// Core Data //
// Core Data //
// Core Data //
// output to buffer
.buffer_64 (buffer_64 )
);
// Test sequence
// 开始设定测试程序
initial begin
// 刚开始时,假定没有任何数据,所有的flag与reg都是空的
// Initialize inputs
sys_rst_n <= 0;
sys_clk <= 0;
recive_west_data<=8'h00;
recive_east_data<=8'h00;
recive_north_data<=8'h00;
recive_south_flag_B=0;
recive_local1_flag_B=0;
recive_local2_flag_B=0;
send_west_flag<=0;
send_east_flag<=0;
send_north_flag<=0;
send_south_flag<=0;
// Release reset
// 现在开始初始化FIFO
#200 sys_rst_n = 1;
// Test case 1: Send a data from the west
// 留上充分的时间等待FIFO初始化完成
#600
// 此时我们一次性一口气同时给4个数据,来测试recive模块的能力
recive_west_data = 8'b10_000001;
recive_south_data =8'b11_000100;
// 标志位去反,表示有数据
recive_north_flag_B=~recive_north_flag_B;
recive_south_flag_B=~recive_south_flag_B;
// 当recive模块完成对外部数据的接受后,FIFO内存有待处理的数据,empty为0
// 此时send模块检测到FIFO有数据,开始向外部传输数据
// 在测试中途改变west的flag,假装此时west有数据,以此来判定send是否正常
// 过一段时间后,west_flag恢复为0,表示reg已经空出来了,可以存数据了
// 再等一会,又一次同时给5个数据,并且还有core block方向的数据
#10
recive_west_data = 8'b00_000001;
recive_north_data =8'b01_000111;
recive_south_flag_B=~recive_south_flag_B;
recive_local1_flag_B=~recive_local1_flag_B;
// 同样的,在测试中途改变core的flag,假装此时core有数据,以此来判定send是否正常
#150;
// 过一段时间,core的flag恢复,再来看看是否正常
send_core_flag_A<=~send_core_flag_A;
// 最后观察传输过程中,是否有数据遗漏,或者方向出错。
end
endmodule
声明:因为这是个人项目,仅提供于学习交流展示。所以我将我的代码删减了一些重要部分,我也没有提供完整的测试文件,因此我的代码无法直接运行。这样做的主要目的是避免有人恶意抄袭,借本项目冒充个人成果。