前言:
本专栏旨在记录高频笔面试手撕代码题,以备数字前端秋招,本专栏所有文章提供原理分析、代码及波形,所有代码均经过本人验证。
目录如下:
10.数字IC手撕代码-数据位宽转换器(宽-窄,窄-宽转换)
13.数字IC手撕代码-流水握手(利用握手解决流水线断流、反压问题)
18.数字IC手撕代码-双端口RAM(dual-port-RAM)
...持续更新
更多手撕代码题可以前往 数字IC手撕代码--题库
目录
输入连续数据流,得出每 256 个数据流的加和值,时序示意图如下:

输入为 i0,i1,i2,…,i253,i254,….占 1 个时钟周期, 输出 sum0 为 i0 +i2+….+i254 的加和值(隔点相加), sum1 为 i1+i3+….+i255,sum2 为 i2+i4+….+i256,如此下去,每个输出占一个时钟周期 Sum0 和 i0 的相对延时关系任意即可。假设输入 i0,i1,i254,…为 8 比特值, 输出 sum 请选择认为不会损失精度且合适的位宽,并用你认为的最省资源的方式用 verilog 语言实现上述要求。
这道题求和其实比较简单,但是关键在于使用最省资源的方式来实现要求。所有的input都是8bit的,sum0加sum1是从i0加和到i255,256个8bit数相加。所以256个8bit数加和需要用16bit的数来表示,因此设置sum为15bit即可。并且还存在规律:
sum2=sum0-i0+i256,sum3=sum1-i1+i257
可以用一个深度为257*8bit位宽的空间datain_store来存储i0-i256,然后再每进一个值,datain_store就移位8bit把新进来的数存起来。再用两个sum,一个sum输出奇数128项求和,一个sum输出偶数128项求和即可。
- module pip_sum(
- input clk ,
- input rstn ,
- input [7:0] datain ,
- input datain_ena ,
-
- output [14:0] sum ,
- output dataout_ena
- );
-
- reg [8*257-1:0] datain_store; //DEPTH = 2056
-
- reg [7:0] count;
- reg [14:0] sum_odd,sum_even;
-
- reg datain_ena_onebeat;
-
- reg flag;
-
- always @(posedge clk)begin
- if(datain_ena)begin
- datain_store <= {datain_store[8*256-1:0],datain}; //left shift 8bit, store datain in low 8bit
- end
- end
-
- always @(posedge clk)begin
- if(!rstn)begin
- count <= 8'd0;
- end
- else if(datain_ena_onebeat == 1'b1 && count < 8'd255)begin
- count <= count + 1'b1;
- end
- else if(datain_ena_onebeat == 1'b1 && count == 8'd255)begin
- count <= 8'd0;
- end
- end
- always @(posedge clk)begin
- if(!rstn)
- flag <= 1'b0;
- else if(count == 8'd255)
- flag <= 1'b1; //
- end
- wire [7:0] look;
- assign look = datain_store[7:0];
- always @(posedge clk)begin
- if(!rstn)begin
- sum_odd <= 15'd0;
- sum_even <= 15'd0;
- end
- else begin
- datain_ena_onebeat <= datain_ena;
- if(datain_ena_onebeat)
- case(count[0])
- 0:begin
- if(flag==0)
- sum_even <= sum_even + datain_store[7:0];
- else
- sum_even <= sum_even - datain_store[8*257-1:8*256] + datain_store[7:0];
- end
- 1:begin
- if(flag==0)
- sum_odd <= sum_odd + datain_store[7:0];
- else
- sum_odd <= sum_odd - datain_store[8*257-1:8*256] + datain_store[7:0];
- end
- endcase
- end
- end
-
- reg [14:0] sum_odd_onebeat,sum_even_onebeat;
- always @(posedge clk)begin
- sum_odd_onebeat <= sum_odd;
- sum_even_onebeat <= sum_even;
- end
-
- assign sum = (count[0]) ? sum_odd_onebeat: sum_even_onebeat;
- assign dataout_ena = flag;
-
- endmodule
- module pip_sum_tb();
-
- reg clk,rstn;
- reg [15:0] count;
- reg [7:0] datain;
- reg datain_ena;
-
- wire [14:0] sum;
- wire dataout_ena;
-
- always #5 clk <= ~clk;
- initial begin
- clk <= 1'b0;
- rstn <= 1'b0;
- #16
- rstn <= 1'b1;
- #20
- datain_ena <= 1'b1;
-
- #10000
- $finish();
- end
-
- initial begin
- datain <= 8'd0;
- count <= 1'b0;
- forever begin
- @(posedge clk)begin
- if(datain_ena == 1)begin
- if(count < 255)begin
- datain <= 1'b0;
- end
- else
- datain <= datain + 1'b1;
- count <= count + 1'b1;
- end
- end
- end
- end
- //dump fsdb
- initial begin
- $fsdbDumpfile("pip_sum.fsdb");
- $fsdbDumpvars(0);
- end
- pip_sum u_pip_sum(
- .clk (clk) ,
- .rstn (rstn) ,
- .datain (datain) ,
- .datain_ena (datain_ena),
- .sum (sum) ,
- .dataout_ena (dataout_ena)
- );
- endmodule

为了方便看结果的正确性,让datain的前256个周期都为0,这样输出的sum0和sum1都为0,然后再让datain为正整数序列递增。 从输出结果可以看到,和我们预期一致,sum0=sum1=0,sum2=sum0-i0+i256=0-0+1=1;sum3=sum1-i1+i257=0-0+2=2,以此类推。
更多手撕代码题可以前往 数字IC手撕代码--题库