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


    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116

    持续更新中…

  • 相关阅读:
    01.爱芳地产项目小程序全栈项目经验(已上线)
    Ubuntu20.04出现只显示本地环回,无法打开网卡解决方法
    mongoose 文件上传-表单形式
    SpringBoot中的application.properties等一系列的配置文件
    Linux安装Git-两种方式详细教程)
    【scikit-learn基础】--『数据加载』之样本生成器
    ProcessWindowFunction 结合自定义触发器的陷阱
    2.1 CSS 简介特性
    vue 实现图片以鼠标为中心放大,并可以随意在div内拖动
    浅入深出的微前端MicroApp
  • 原文地址:https://blog.csdn.net/qq_40549426/article/details/125410693