zl程序教程

您现在的位置是:首页 >  其他

当前栏目

数字IC手撕代码-XX公司笔试真题(数据流pipeline加和)

公司IC代码 数字 真题 笔试 Pipeline 数据流
2023-09-14 09:15:33 时间

 前言: 

        本专栏旨在记录高频笔面试手撕代码题,以备数字前端秋招,本专栏所有文章提供原理分析、代码及波形,所有代码均经过本人验证。

目录如下:

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)

        ...持续更新

 更多手撕代码题可以前往 数字IC手撕代码--题库


目录

题目描述

解题思路

代码

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

testbench

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手撕代码--题库