前言:
本专栏旨在记录高频笔面试手撕代码题,以备数字前端秋招,本专栏所有文章提供原理分析、代码及波形,所有代码均经过本人验证。
目录如下:
1.数字IC手撕代码-分频器(任意偶数分频)
2.数字IC手撕代码-分频器(任意奇数分频)
3.数字IC手撕代码-分频器(任意小数分频)
4.数字IC手撕代码-异步复位同步释放
5.数字IC手撕代码-边沿检测(上升沿、下降沿、双边沿)
6.数字IC手撕代码-序列检测(状态机写法)
7.数字IC手撕代码-序列检测(移位寄存器写法)
8.数字IC手撕代码-半加器、全加器
9.数字IC手撕代码-串转并、并转串
10.数字IC手撕代码-数据位宽转换器(宽-窄,窄-宽转换)
11.数字IC手撕代码-有限状态机FSM-饮料机
12.数字IC手撕代码-握手信号(READY-VALID)
13.数字IC手撕代码-流水握手(利用握手解决流水线断流、反压问题)
14.数字IC手撕代码-泰凌微笔试真题
15.数字IC手撕代码-平头哥技术终面手撕真题
16.数字IC手撕代码-兆易创新笔试真题
17.数字IC手撕代码-乐鑫科技笔试真题(4倍频)
18.数字IC手撕代码-双端口RAM(dual-port-RAM)
...持续更新
为了方便可以收藏导览博客:
目录
题目描述
解题思路
代码
testbench
输出波形
输入连续数据流,得出每 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,以此类推。