数字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手撕代码-导览目录


目录

数据位宽转换器

 1.由宽到窄的数据转换

代码

testbench

波形图

 2.由窄到宽的数据转换

代码

testbench

波形图

总结


数据位宽转换器

        数据位宽转换器,一般常用于模块接口处,比如一个电路模块的输出数据位宽大于另一个模块的输入数据位宽,此时就需要进行数据位宽转换。比如SATA控制器中,内部数据位宽为32bit,但外部物理收发器PHY的接口通常为16bit,或者8bit,在不使用FIFO进行缓存的情况下,可以使用数据位宽转换器,通过时钟倍频在实现数据位宽的转换

 1.由宽到窄的数据转换

        假设数据从模块A传入到模块B,模块A的输出数据为32位,模块B的输入数据位宽为16位,那么如何能把数据从A传入B而不损失数据呢。

        答:通过时钟的分频与倍频实现。

        我们假设一个原时钟clk2x,通过二分频,把原时钟变为时钟clk1x,那么clk2x的时钟频率就是clk1x的两倍。在clk2x的上升沿,我们读入32bit数据,在clk2x的上升沿我们输出16bit数据,由于clk2x的频率是clk1x的两倍,每读入一次32bit数据,就会输出两次16bit数据,从而实现了数据位宽的转换,如图:

代码

(代码内写的clk1频率是clk2的两倍,结尾附波形,和上图有些出入)

module wide_to_narrow(
    input           rstn      ,
    input           clk1      ,
    input   [31:0]  data_in   ,
    output  [15:0]  data_out  
);
reg [31:0] data_sync;
reg clk2;
always @(posedge clk1)begin
  if(!rstn)begin
    clk2 <= 1'b0;
  end
  else begin
    clk2 <= ~clk2; //div_2
  end
end

always @(posedge clk2)begin
  data_sync <= data_in;
end

assign data_out = clk2 ? data_sync[31:16] : data_sync[15:0];

endmodule

testbench

module wide_to_narrow_tb();
reg clk1,rstn;
reg [31:0]  data_in;
wire [15:0] data_out;

always #5 clk1 = ~clk1;

initial begin
  clk1 <= 1'b0;
  rstn <= 1'b0;
  #10
  rstn <= 1'b1;
  #5
  data_in <= 32'h0000_1111;
  #20
  data_in <= 32'h2222_3333;
  #20
  data_in <= 32'h4444_5555;
  #20
  data_in <= 32'h6666_7777;
  #20
  data_in <= 32'h8888_9999;
  #20
  $stop();
end
wide_to_narrow u_wide_to_narrow(
  .clk1     (clk1)    ,
  .rstn     (rstn)    ,
  .data_in  (data_in) ,
  .data_out (data_out)
);

endmodule

波形图

 2.由窄到宽的数据转换

        由窄到宽的数据位宽转换原理和由宽到窄的是一样的。把频率高一点的时钟用来采样16bit数据,频率低一点的时钟用来输出32bit数据。

代码

module narrow_to_wide(
    input              rstn      ,
    input              clk1      ,
    input      [15:0]  data_in   ,
    output reg [31:0]  data_out  
);
reg [31:0]  data_sync;
reg [15:0]  data_temp;
reg clk2;

always @(posedge clk1)begin
  if(!rstn)begin
    clk2 <= 1'b0;
  end
  else begin
    clk2 <= ~clk2; //div_2
  end
end

always @(posedge clk1)begin
  data_temp <= data_in;
  data_sync <= {data_temp,data_in};
end

always @(posedge clk2)begin
  data_out <= data_sync;
end

endmodule

testbench

module narrow_to_wide_tb();
reg clk1,rstn;
reg   [15:0]  data_in;
wire  [31:0] data_out;

always #5 clk1 = ~clk1;

initial begin
  clk1 <= 1'b0;
  rstn <= 1'b0;
  #10
  rstn <= 1'b1;
  #5
  data_in <= 16'h1111;
  #10
  data_in <= 16'h2222;
  #10
  data_in <= 16'h3333;
  #10
  data_in <= 16'h4444;
  #10
  data_in <= 16'h5555;
  #10
  data_in <= 16'h6666;
  #20
  $stop();
end
narrow_to_wide u_narrow_to_wide(
  .clk1     (clk1)    ,
  .rstn     (rstn)    ,
  .data_in  (data_in) ,
  .data_out (data_out)
);

endmodule

波形图

总结

        位宽转换的核心就在于生成一个与原时钟成比例关系的时钟,这样时钟频率的比例关系就可以和数据的位宽扯上联系。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不吃葱的酸菜鱼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值