【Day30】Pipelined 加法器

什麽是 Pipelined?

先以RISC-V架构来举例:

我们先来看看这张图:

图片出处:源自 Computer Organization and Design RISC-V edition 这本书中的 524 页

我们先来看上面那张图:

一道指令从进来到执行结束一共得花 800 ps,而上一笔指令执行完下一道指令才会继续进来,那麽 Pipeline 的意思就是把硬体共享最大化,例如一道指令要经历五个步骤才能做完的话,那麽在前一道指令做到第二步骤时,其实第一个步骤的硬体是闲置的,这样并没有达到资源最大利用,也就是说,其实在此时下一道指令就可以先进来了,如此一来就会像是下图那样,先解释一下为什麽上面 800 ps 切成五份後会变成 200 ps,不是应该是 160 ps 吗?

因为每一阶的执行时间必须一样,也就是要以执行时间最久的那阶为准(Critical Path),可以看到 Reg 那阶,其实只要 100 ps 就执行完了,但还是得等满 200 ps 因此有了上图 800 ps 与下图却总共要 1000 ps 的差异,所以做了 pipeline 并不会提高每一道指令的总执行时间,却可以提高 Throughput,可以看到没有做 pipeline 的话要每 800 ps 才能执行完一道指令,而有做 pipeline 则在 1000 ps 以後就可以每过 200 ps就完成一道指令~~

那麽今天要来完成的 pipeline 加法器背後的想法也是类似这样,因为越多位元的加法器可能所需的时间就越久,所以我们可以把它们拆成几个等分,最後再一起输出结果,如此一来就可以提高 throughput。

但是做 pipeline 还有一点是,每一阶之间都需要暂存器来存放上一阶的执行结果。

那麽我们来试着写个切一阶 pipeline 的加法器吧~

宣告输入输出

module pipelinedAdderOneStage#(
/*--------parameter-------*/
parameter width    = 19,
          widthLsb = 9,
          widthMsb = 10)
(
  clkSys, 
  rst_n, 
  x, 
  y, 
  sum
);
/*--------ports declaration-------*/
input             clkSys;
input             rst_n;
input  [width-1:0]x;
input  [width-1:0]y;
output [width-1:0]sum;
wire   [width-1:0]sum;

宣告中间的暂存变数

/*--------variables-------*/
//lsb
reg    [widthLsb-1:0]lsbTemp1; //9bit
reg    [widthLsb-1:0]lsbTemp2; //9bit
reg      [widthLsb:0]sumTemp1; //10bits(9bits sum of lsb & 1-bit carry)
reg    [widthLsb-1:0]sumOutLsb;//9bit
//msb
reg    [widthMsb-1:0]msbTemp1; //10bit
reg    [widthMsb-1:0]msbTemp2; //10bit
reg    [widthMsb-1:0]sumTemp2; //10bit
reg    [widthMsb-1:0]sumOutMsb;//10bit

再 lsb 有一个 10bit 变数是因为可能低位元加完後会有 carry 项,不能漏掉了

将输入变数切成高位元及低位元

/*--------catch data-------*/
always@(posedge clkSys or negedge rst_n)begin
  if(!rst_n)begin
    lsbTemp1 <= 'd0;
    lsbTemp2 <= 'd0;
    msbTemp1 <= 'd0;
    msbTemp2 <= 'd0;
  end
  else begin
    lsbTemp1 <= x[widthLsb-1:0];//8~0 bits
    lsbTemp2 <= y[widthLsb-1:0];//8~0 bits
    msbTemp1 <= x[widthMsb+widthLsb-1:widthLsb];//18~9 bits
    msbTemp2 <= y[widthMsb+widthLsb-1:widthLsb];//18~9 bits
  end
end

第一阶加法器(LSB 与 MSB 先各自相加)

/*--------first stage or the adder-------*/
//add lsb
always@(posedge clkSys or negedge rst_n)begin
  if(!rst_n)sumTemp1 <= 'd0;
  else      sumTemp1 <= {1'b0, lsbTemp1}+{1'b0, lsbTemp2};
end
//add msb
always@(posedge clkSys or negedge rst_n)begin
  if(!rst_n)sumTemp2 <= 'd0;
  else      sumTemp2 <= msbTemp1 + msbTemp2;
end

第二阶加法器

  • LSB 的话直接拿掉 carry 项然後输出
  • MSB 要加上刚刚 LSB 的 carry 项
/*--------second stage or the adder-------*/
//sum of Lsb
always@(posedge clkSys or negedge rst_n)begin
  if(!rst_n)sumOutLsb <= 'd0;
  else      sumOutLsb <= sumTemp1[widthLsb-1:0];
end
//sum of Msb
always@(posedge clkSys or negedge rst_n)begin
  if(!rst_n)sumOutMsb <= 'd0;
  else      sumOutMsb <= sumTemp1[widthLsb] + sumTemp2;
end

endmodule

TestBench


`timescale 1ns/1ns
module tb_adder();

localparam width    = 19;
localparam widthLsb = 9;
localparam widthMsb = 10;

reg             clkSys;
reg             rst_n;
reg  [width-1:0]x;
reg  [width-1:0]y;
wire [width-1:0]sum;
integer i, j;

pipelinedAdderOneStage UUT(
  .clkSys(clkSys), 
  .rst_n(rst_n), 
  .x(x), 
  .y(y), 
  .sum(sum)
);
//variables
initial begin
  i = 0;
  j = 0;
end
//input port
initial begin
  x = 0;
  y = 0;
  rst_n = 0;
  clkSys = 0;
end

always #10 clkSys = ~clkSys;//50MHZ

initial begin
  repeat(5)@(posedge clkSys)rst_n = 0;
  rst_n = 1;
  for(i=0;i<=10;i=i+1)begin
    for(j=0;j<=10;j=j+1)begin
      y = y + 1;
      #100;
    end
    x = x + 1;
  end
  #100 $stop;
end

initial begin
  $monitor("time=%3d, %3d + %3d = %3d",$time, x, y, sum);
end

endmodule

Wave

可以看到加法功能正确(你们可以去看看有 carry 的部分有没有功能正常)

RTL Viewer

你们也可以写切更多层的试试看欧~~

那麽 30 天也很快的过去了,希望对你在学习 verilog 这条路上多少有些帮助~~!


<<:  冒险村30 - Handle API response with value objects

>>:  Not only MordernWeb,But also Data Club—阅读建议、文章索引、结语

Day7 用python写UI-聊聊标签Label方法(二)

今天要主要会介绍几个 widget 的共通方法,後面的部分会介绍如何在介面上加上图片还有其他几个实用...

Day15 - BST(Delete Case 1)

大家好,我是长风青云。今天是铁人赛第十五天。 今天心情有点糟,有点感慨。原谅我东西很少。详细内容我等...

时间管理

你的时间不是你的时间 当年当上管理者几个月之後,突然感觉到一阵茫然。我会发现都过了一个季了,为什麽...

Day5 Let's ODOO: Model(2) Fields

延续前日介绍,今天我们来讲Model内的fields延续昨日范例 # -*- coding: utf...

[第三只羊] 迷雾森林建筑工事 II vite好吃吗

天亮了 昨晚是平安夜 关於迷雾森林故事 化装舞会 阿虎简单布置了一个入口指引 招集迷雾森林里的动物们...