数字IC手撕代码-泰凌微笔试真题

 前言:

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

目录如下:

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

波形


题目

以上是泰凌微公司的笔试真题,手撕一个代码,题目描述如下:

        假设每个clock cycle输入是一个3-bit数据信号,现在需要按次序整形成5-bit数据信号输出,并给出valid信号。其中LSB First,请用Verilog/VHDL给出代码。

sample data:

输入:000,110,011,011,010,010,011...   即:(000|11 0|011 |0 11|010|010|01 1)

输出:00011,00110,11010,01001,1...     即:(000 11|0 011  0|11010| 010 01|1)

        该题目,仔细阅读就会发现,序列都是同一条序列,分割方式不同;说白了其实就是一个位宽转换题,然后加握手信号。实现一个含握手的3-5bit的位宽转换模块。这个题目,华子也考过类似的,或者说很多公司爱考这玩意。


概念解释

下面解释下,题目中出现的概念

1、LSB(Least Significant Bit)--最低有效位

    LSB代表二进制中最小的单位,可以用来指示数字很小的变化。也就是说,LSB是一个二进制数字中的第0位(即最低位),具有权值为2^0,可以用来检测数的奇偶性。

2、MSB(Most Significant Bit)--最高有效位

    MSB代表一个n位二进制数字中的n-1位,具有最高的权值2^(n-1).对于有符号的二进制数,负数采用反码或补码形式,此时MSB用来表示符号,msb为1表示负数,0表示正数。


实现原理

         好的,解释完概念,题目的意思就非常明白了,实现一个含有握手信号的3-5 bit位宽转换器,输入为3bit,输出5bit,且输入的3bit从低位开始排,即输入000,110时,第一个5bit输出的是000 11,而不是10 000,也就是题目说的LSB First

思路分析

        ① 输入第一个3bit,无法输出;

        ② 输入第二个3bit,此时存数6bit,可以输出一次5bit,余下1bit;valid=1;

        ③ 输入第三个3bit,此时由于输出过一次5bit,余下1bit,加上这第三次输入的3bit,此时存数4bit,无法输出;

        ④ 输入第四个3bit,此时存数7bit,可以输出一次5bit,余下2bit;valid=1;

        ⑤ 输入第五个3bit,此时存数5bit,可以输出一次5bit,存数为0bit,状态循环可回到初始状态。valid=1;

        显然每五次输入是一个轮回,这是因为15bit是3bit和5bit 的最小公倍数,因此每输入15/3=5次,就输出15/5=3次。如此反复循环。

        根据分析我们看到,输出有效的时间点是第二次输入后、第四次输入后、第五次输入后,因此我们可以用一个计数器counter来作为valid信号的判据,当计数器为2、4、5时,valid都拉高即可。理清思路,代码就很好写了。

代码:

计数器,来计入总共输入了几次3bit数据: 

reg [2:0] counter;
always @(posedge clk)begin  //handshake counter
  if(!rstn)begin
    counter <= 3'd0; 
  end
  else if(ready_i && valid_i && (counter<=3))begin
    counter <= counter + 1'b1; 
  end
  else if(ready_i && valid_i && (counter==4))begin
    counter <= 3'd0;
  end
en

当输入第二次、第四次、第五次时,valid信号拉高:

reg [6:0] data_store;
always @(posedge clk)begin
  if(!rstn)begin
    valid_o_temp <= 1'b0;
  end
  else if(ready_i && valid_i)begin

    if((counter==1) || (counter==3) || (counter==4))begin     //valid_o output
      valid_o_temp <= 1'b1;
    end
    else begin
      valid_o_temp <= 1'b0;
    end

    case(counter)
      3'd0:data_store[6:4] <=  data_in;                       //store 3bit no output
      3'd1:data_store      <= {data_store[6:4],data_in,1'b0}; //store 6bit but output 5bit 
      3'd2:data_store      <= {data_store[3:0],data_in};      //store 4bit no output
      3'd3:data_store      <= {data_store[3:0],data_in};      //store 7bit output 5bit
      3'd4:data_store      <= {data_store[1:0],data_in,2'd0}; //store 5bit output 5bit
    endcase

  end
end

        case语句内的作用是将数据进行移位。因为最多情况下是存储7bit数据,然后输出5bit,所以存储输入数据的空间只需要7bit就够了。用7bit 的 data_store来存储输入数据;

第一次输入的3bit数据存储在data_store的高3位,不输出5bit数据;

第二次输入的3bit数据存储在data_store的高4-6位。此时,valid信号拉高,然后输出5bit 数据 data_out 等于data_store的高5bit即可;

第三次输入的3bit数据,让data_store左移三位,然后存储在低三位,不输出5bit数据;

第四次输入的3bit数据,让data_store左移三位,然后存储在低三位,此时7bit空间存满,因为进行了两次“左移三位”,所以此时7bit数据的最高位,就是原来7bit数据的最低位,也就是在第二次输入数据时,存储6bit输出5bit后,剩下的那1bit数据。再输出高5bit数据;余2bit

低五次输入的3bit数据,与上一阶段余下的2bit数据,凑5bit,放在data_store的高5位,输出。 


代码

module tailinwei#(

)(
  input         clk       ,
  input         rstn      ,
  input   [2:0] data_in   ,
  output  [4:0] data_out  ,
  
  input         ready_i   ,
  input         valid_i   ,
  output        ready_o   ,
  output        valid_o
);

reg valid_o_temp,valid_onebeat;
reg [2:0] counter;
always @(posedge clk)begin  //handshake counter
  if(!rstn)begin
    counter <= 3'd0; 
  end
  else if(ready_i && valid_i && (counter<=3))begin
    counter <= counter + 1'b1; 
  end
  else if(ready_i && valid_i && (counter==4))begin
    counter <= 3'd0;
  end
end

always @(posedge clk)begin
  if(ready_i)begin
    valid_onebeat <= valid_i;   //valid_i one beat
  end
end

reg [6:0] data_store;
always @(posedge clk)begin
  if(!rstn)begin
    valid_o_temp <= 1'b0;
  end
  else if(ready_i && valid_i)begin

    if((counter==1) || (counter==3) || (counter==4))begin     //valid_o output
      valid_o_temp <= 1'b1;
    end
    else begin
      valid_o_temp <= 1'b0;
    end

    case(counter)
      3'd0:data_store[6:4] <=  data_in;                       //store 3bit no output
      3'd1:data_store      <= {data_store[6:4],data_in,1'b0}; //store 6bit but output 5bit 
      3'd2:data_store      <= {data_store[3:0],data_in};      //store 4bit no output
      3'd3:data_store      <= {data_store[3:0],data_in};      //store 7bit output 5bit
      3'd4:data_store      <= {data_store[1:0],data_in,2'd0}; //store 5bit output 5bit
    endcase

  end
end

assign data_out = data_store[6:2];          // get high 5bit to output 
assign valid_o  = valid_o_temp && valid_onebeat;

endmodule

testbench

tb:整个testbench部分的激励,就按照题目的意思生成。 

module tailinwei_tb();

reg clk,rstn;

always #5 clk = ~clk;

wire ready_o,valid_o;
reg  ready_i,valid_i;

reg   [2:0] data_in;
wire  [4:0] data_out;

initial begin
  clk     <= 1'b0;
  rstn    <= 1'b0;
  ready_i <= 1'b1;
  valid_i <= 1'b0;
  #20
  rstn    <= 1'b1;
  data_in <= 3'b000;
  valid_i <= 1'b1; 

  #10 data_in <= 3'b110;
  #10 data_in <= 3'b011;
  #10 data_in <= 3'b011;
  #10 data_in <= 3'b010;
  #10 data_in <= 3'b010;
  #10 data_in <= 3'b011;
  #10
  valid_i <= 1'b0;
  #50
  $stop();
end

tailinwei u_tailinwei(
  .clk(clk),
  .rstn(rstn),
  .data_in(data_in),
  .data_out(data_out),

  .ready_i(ready_i),
  .valid_i(valid_i),
  .ready_o(ready_o),
  .valid_o(valid_o)
);

endmodule

波形

输入:000,110,011,011,010,010,011...   即:(000|11 0|011 |0 11|010|010|01 1)

输出:00011,00110,11010,01001,1...     即:(000 11|0 011  0|11010| 010 01|1)

每次输出数据时,valid信号有效,如波形所示。 


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

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃葱的酸菜鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值