代码参考重庆大学计算机组成实验,并且在此基础上添加了刷新和暂停,主要目的是理解一下阻塞流水线。
代码
`timescale 1ns / 1ps
// 带有暂停与刷新功能的八位四级流水线,
module adder8Bits4StepsWithStopAndClear
(
input [7 : 0] num1,
input [7 : 0] num2,
// 上一位的进位
input cin,
// 输入是否有效
input validIn,
// 刷新
input rst,
// 暂停
input stop,
input clk,
input outAllow,
// 判断输出是否有效
output wire validOut,
output wire count,
output wire [7 : 0] sum
);
reg count1, count2, count3;
// 记录每一层是否有效
reg pipe1Valid;
reg pipe2Valid;
reg pipe3Valid;
reg pipe4Valid;
// 第一级流水
reg [1:0] sum1;
// 控制变量:和之前的一样
// 表示pipe1能否被上一级刷新
wire pipe1AllowIn;
// 表示pipe1是否可以用于刷新下一级
wire pipe1ReadyGo;
// 表示pipe1能否进入pipe2
wire pipe1ToPipe2Valid;
//第二级流水
reg [3:0] sum2;
wire pipe2AllowIn;
wire pipe2ReadyGo;
wire pipe2ToPipe3Valid;
//第三级流水
reg [5:0] sum3;
wire pipe3AllowIn;
wire pipe3ReadyGo;
wire pipe3ToPipe4Valid;
//第四级流水
wire pipe4AllowIn;
wire pipe4ReadyGo;
reg [7 : 0]sum4;
reg count4;
// 如果没有暂停,那么就可以Go
assign pipe1ReadyGo = !stop;
// 如果pipe1中的值已经无效,或者这一轮一定会传给下一个,那么就可以进行接收
assign pipe1AllowIn = ! pipe1Valid || pipe1ReadyGo && pipe2AllowIn;
// 如果pipe1有效,并且pipe1可以进行传输,那么pipe1ToPipe2Valid可以进行。
assign pipe1ToPipe2Valid = pipe1Valid && pipe1ReadyGo;
// 是否有效
always @ (posedge clk) begin
// 如果需要刷新,那么pipe1Valid 变为0,表示pipe1中的值不再有效
if( rst ) begin
pipe1Valid <= 1'b0;
end
// 不需要刷新,并且pipe1可以进行刷新
// 如果输入端有输入,就代表下一个状态pipe1Valid的值有效
// 如果无输入,就代表下一个状态无效
else if(pipe1AllowIn)begin
pipe1Valid <= validIn;
end
// 如果输入值有效,并且pipe1可以读入,那么就从输入端进行读入
if(validIn && pipe1AllowIn)begin
{count1, sum1} <= {1'b0, num1[1:0]} + {1'b0, num2[1:0]} + cin;
end
end
// 第二级流水
assign pipe2ReadyGo = !stop;
assign pipe2AllowIn = ! pipe2Valid || pipe2ReadyGo && pipe3AllowIn;
assign pipe2ToPipe3Valid = pipe2Valid && pipe2ReadyGo;
always @ (posedge clk) begin
if( rst ) begin
pipe2Valid <= 1'b0;
end
else if(pipe2AllowIn)begin
pipe2Valid <= pipe1ToPipe2Valid;
end
if(pipe1ToPipe2Valid && pipe2AllowIn)begin
{count2, sum2} <= {{1'b0, num1[3:2]} + {1'b0, num2[3:2]} + count1, sum1};
end
end
// 第三级流水
assign pipe3ReadyGo = !stop;
assign pipe3AllowIn = ! pipe3Valid || pipe3ReadyGo && pipe4AllowIn;
assign pipe3ToPipe4Valid = pipe3Valid && pipe3ReadyGo;
always @ (posedge clk) begin
if( rst ) begin
pipe3Valid <= 1'b0;
end
else if(pipe2AllowIn)begin
pipe3Valid <= pipe2ToPipe3Valid;
end
if(pipe2ToPipe3Valid && pipe3AllowIn)begin
{count3, sum3} <= {{1'b0, num1[5:4]} + {1'b0, num2[5:4]} + count2, sum2};
end
end
// 第四级流水
// 一样一样的
assign pipe4ReadyGo = !stop;
assign pipe4AllowIn = ! pipe4Valid || pipe4ReadyGo && outAllow;
always @(posedge clk)begin
if( rst ) begin
pipe4Valid <= 1'b0;
end
else if(pipe3AllowIn)begin
pipe4Valid <= pipe3ToPipe4Valid;
end
if(pipe3ToPipe4Valid && pipe4AllowIn)begin
{count4, sum4} <= {{1'b0, num1[7:6]} + {1'b0, num2[7:6]} + count3, sum3};
end
end
assign validOut = pipe4Valid && pipe4ReadyGo;
assign sum = sum4;
assign count = count4;
endmodule
仿真文件verilog代码
`timescale 1ns / 1ps
// 测试最后一个模型
module finalSim();
reg [7 : 0] num1;
reg [7 : 0] num2;
// 上一位的进位
reg cin;
// 输入是否有效
reg validIn;
// 刷新
reg rst;
// 暂停
reg stop;
reg clk;
reg outAllow;
// 判断输出是否有效
wire validOut;
wire count;
wire [7 : 0] sum;
adder8Bits4StepsWithStopAndClear test1(
num1,
num2,
cin,
validIn,
rst,
stop,
clk,
outAllow,
validOut,
count,
sum
);
initial begin
num1 = 8'd1;
num2 = 8'd1;
cin = 1'd0;
validIn = 1'd1;
rst = 1'd0;
stop = 1'd0;
clk = 1'd0;
outAllow = 1'd1;
# 30 rst = 1'b1;
# 30 rst = 1'b0;
end
always # 5 begin
clk = ~ clk;
end
always # 10 begin
stop = ~ stop;
end
endmodule
仿真结果分析
在分析前首先应该知道四级流水线的8位全加器,完成整个的运算需要4个时钟周期。
一、只添加周期暂停的结果如下,可以发现当stop信号为0时,即正常运行时,4个时钟周期完成运算。
二、当加入刷新和暂停时。可以看到复位的加入直接重新开始计算,并且在不暂停的4个时钟周期后正常输出数据。
当然大家也可以修改复位和暂停来看一下仿真的结果。主要理解复位和暂停的含义,和读懂代码。
参考
重庆大学计算机组成实验
lvyufeng@cqu.edu.cn