【基础知识】~ 数据位宽转换器

1. 概述

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

关于分频器,请移步到之前的一篇文章点击传送门

2. 两种转换

2.1 由宽到窄的数据转换

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

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

我们假设一个原时钟clk1,通过二分频,把原时钟变为时钟clk2,那么clk2的时钟周期就是clk1的两倍。在clk2的上升沿,我们读入32bit数据,在第一个clk1的上升沿我们输出读进来的高16bit数据,第二个clk1的上升沿我们输出读进来的低16bit数据,由于clk1的频率是clk2的两倍,每读入一次32bit数据,就会输出两次16bit数据,从而实现了数据位宽的转换。

2.1.1 代码实现以及仿真结果

参考文章
它里边可能有的地方有笔误,大家看的时候注意一下就行。

2.2 由窄到宽的数据转换

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

2.2.1 代码实现及仿真结果

同样参考2.1.1即可。

3. 抛砖引玉(另一种方式实现)

不知道大家有没有注意到,通过分频来做的话,我们拿到一个整数分频还好点,比如8位转16位,或者64位转16位,这样只要简单实现一下整数分频器;那要是小数分频器怎么办?虽然说也能实现,但是是不是有点麻烦了呢?那怎么解决呢?

答:我们都知道了多少位转多少位了,那不是意味着他俩的关系就确定了,是吧,我们可以用 计数器 来做呀!!!

3.1 原理

计数器计数,计到一定的数值之后,就对我们暂存的数进行拼接,之后输出。

3.2 例题

3.2.1 数据位宽转换8to16

题目VL10 整数倍数据位宽转换8to16

解题思路
首先,需要有个计数器计数(为什么该题以为计数器就行?因为我们一共就需要计2个数呀!!!),注意的是只有当输入valid_in 有效才计数,否则都是保持,同时呢,因为两个8位才能实现一个16位嘛,所以需要给先采进来的8位数据暂存起来,之后等到下一个8位数据之后一起给它输出出去。

代码实现

`timescale 1ns/1ns

module width_8to16(
	input 				   clk 		,   
	input 				   rst_n		,
	input				      valid_in	,
	input	   [7:0]		   data_in	,
 
 	output	reg			valid_out,
	output   reg [15:0]	data_out
);
    reg count;
    reg [7:0] temp_data;
    //counter
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
           count <= 0; 
        end
        else begin
            if(valid_in) begin
                count <= count + 1; 
            end
        end
    end
    //convert
    always @ (posedge clk or rst_n) begin
        if(!rst_n) begin
           valid_out <= 0;
            data_out <= 0;
        end
        else begin
            if(valid_in) begin
                if(count == 0) begin
                    temp_data <= data_in;
                    valid_out <= 0;
                end
                else begin
                    data_out <= {temp_data, data_in};
                    valid_out <= 1;
                end
            end
            else begin
               valid_out <= 0; 
            end
        end
    end
endmodule

3.2.2 数据位宽转换8to12

题目VL9 非整数倍数据位宽转换8to12

解题思路
其实和上一个题思路差不多,只不过这个题它不是整数转换了,而是非整数!
首先也是计数器,这次需要2位,为什么?3个8位数据可以拼成2个12位数据,需要计数三次,两位足够!
其次就是需要进行拼接操作了,参见代码就可以!

代码实现

`timescale 1ns/1ns

module width_8to12(
	input 				   clk 		,   
	input 			      rst_n		,
	input				      valid_in	,
	input	[7:0]			   data_in	,
 
 	output  reg			   valid_out,
	output  reg [11:0]   data_out
);
    reg [1:0] count;
    reg [7:0] data_reg;
    
    //counter
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
           count <= 0; 
        end
        else begin
            if(valid_in) begin
                if(count == 2) begin //3个8位数据可以拼成2个12位数据
                   count <= 2'b0; 
                end
                else begin
                   count <= count + 1; 
                end
            end
        end
    end
    
    //convert
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
           valid_out <= 0;
            data_out <= 0;
            data_reg <= 0;
        end
        else begin
            if(valid_in) begin
                case(count)
                    2'b00 : begin //注意加 begin - end
                        data_reg <= data_in;
                        valid_out <= 0;
                    end
                    2'b01 : begin
                        data_out <= {data_reg, data_in[7:4]};
                        data_reg[3:0] <= data_in[3:0];
                        valid_out <= 1;
                    end
                    2'b10 : begin
                        data_out <= {data_reg[3:0], data_in};
                        valid_out <= 1;
                    end
                    default : begin
                        valid_out <= 0;
                        data_out <= 0;
                        data_reg <= 0;
                    end
                endcase
            end
            else begin
               valid_out <= 0; 
            end
        end
    end
endmodule

3.2.3 数据位宽转换24to128

题目VL8 非整数倍数据位宽转换24to128

解题思路
同样的,也是通过计数器实现,该题 16个24位数据可以拼成3个128位数据,所以需要16位计数器,剩下的我也不详细写了,参考上一个题就完全可以写出来的。

代码实现

`timescale 1ns/1ns

module width_24to128(
	input 				clk 		,   
	input 				rst_n		,
	input				valid_in	,
	input	[23:0]		data_in		,
 
 	output	reg			valid_out	,
	output  reg [127:0]	data_out
);
    reg [3:0] count;     //16个24位数据可以拼成3个128位数据
//     reg [23:0] data_reg;
    reg [127:0] data_out_reg;
    
    //counter
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
           count <= 4'b0; 
        end
        else begin
            if(valid_in) begin
                count <= count + 1; 
            end
        end
    end
    
    //convert
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
           valid_out <= 0;
            data_out <= 0;
            data_out_reg <= 0;
        end
        else begin
            if(valid_in) begin
                case(count)
                    4'b0000 : begin //注意加 begin - end
                        data_out_reg[127:104] <= data_in;
                        valid_out <= 0;
                    end
                    4'b0001 : begin
                        data_out_reg[103:80] <= data_in;
                        valid_out <= 0;
                    end
                    4'b0010 : begin
                        data_out_reg[79:56] <= data_in;
                        valid_out <= 0;
                    end
                    4'b0011 : begin
                        data_out_reg[55:32] <= data_in;
                        valid_out <= 0;
                    end
                    4'b0100 : begin
                        data_out_reg[31:8] <= data_in;
                        valid_out <= 0;
                    end
                    4'b0101 : begin
                        data_out <= {data_out_reg[127:8], data_in[23:16]};
                        data_out_reg[127:112] <= data_in[15:0];
                        valid_out <= 1;
                    end
                    4'b0110 : begin
                        data_out_reg[111:88] <= data_in;
                        valid_out <= 0;
                    end
                    4'b0111 : begin
                        data_out_reg[87:64] <= data_in;
                        valid_out <= 0;
                    end
                    4'b1000 : begin
                        data_out_reg[63:40] <= data_in;
                        valid_out <= 0;
                    end
                    4'b1001 : begin
                        data_out_reg[39:16] <= data_in;
                        valid_out <= 0;
                    end
                    4'b1010 : begin
                        data_out <= {data_out_reg[127:16], data_in[23:8]};
                        data_out_reg[127:120] <= data_in[7:0];
                        valid_out <= 1;
                    end
                    4'b1011 : begin
                        data_out_reg[119:96] <= data_in;
                        valid_out <= 0;
                    end
                    4'b1100 : begin
                        data_out_reg[95:72] <= data_in;
                        valid_out <= 0;
                    end
                    4'b1101 : begin
                        data_out_reg[71:48] <= data_in;
                        valid_out <= 0;
                    end
                    4'b1110 : begin
                        data_out_reg[47:24] <= data_in;
                        valid_out <= 0;
                    end
                    4'b1111 : begin
                        data_out <= {data_out_reg[127:24], data_in};
                        valid_out <= 1;
                    end
                    default : begin
                       valid_out <= 0;
                        data_out <= 0;
                        data_out_reg <= 0;
                    end
                endcase
            end
            else begin
               valid_out <= 0; 
            end
        end
    end
endmodule

持续更新中…

  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值