我是靠谱客的博主 兴奋发带,最近开发中收集的这篇文章主要介绍整数倍与非整数倍位宽转换电路,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

以下内容摘自:《正点原子逻辑设计指南》

一、整数倍位宽转换简介

位宽转换在项目开发中会经常用到,比如两个模块对接,一个模块是 8bit 信号位宽,另外一个模块是16bit 信号位宽,那么两个模块实现对接就需要一个位宽转换电路,把 8bit 信号位宽转换为 16bit 信号位宽。

位宽转换包括两种,一种是整数倍位宽转换,一种是非整数倍位宽转换,整数倍的位宽转换相对简单,非整数倍的位宽转换比较复杂。

我们先来看下整数倍的位宽转换,如下图所示,一个是 A 模块,一个是 B 模块,一般模块的接口由数据信号和数据有效指示 vld 构成,A 模块的位宽是 8bit,B 模块的位宽是 16bit,这两个模块是没有办法直接对接的,中间需要一个位宽转换模块。

在这里插入图片描述
位宽转换模块如下图所示,输入是 8bit 信号,输出是 16bit 信号,有了这个模块,A 模块和 B 模块就可以对接了。
在这里插入图片描述
下面我们来分析下如何设计这个位宽转换,我们假设位宽转换输入信号为数据 a 和 a_vld,a 为 8bit信号,输出信号为数据 b 和 b_vld,b 为 16bit 信号。

我们先来画下位宽转换的输入信号的时序图,如下图所示。

在这里插入图片描述
如上图所示,假设 a 信号会持续四个时钟周期,即 a_vld 在四个时钟周期全部为 1,每个时钟周期都有数据,分别是 0x55、0xaa、0xbb 和 0xcc。而输出信号 b 是 16bit,16bit 数据需要两个 8bit 数据,由此我们可以画出 b 的时序图,如上图所示,我们通过上面的图可以看出,b_vld 都是在 a 传输了两个 8bit 数据后才为高 1 次,a_vld 在四个时钟周期全部为 1,b_vld 只在周期 2 和周期 4 为 1。a 的数据在周期 1 和周期 4 分别是 0x55、0xaa、0xbb 和 0xcc,那么可以得出 b 的数据为 0x55aa 和 0xbbcc,b 的数据只在周期 2 和周期 4有效。

由于我们需要控制 b_vld 的产生,a_vld 每两次有效,才产生一个 b_vld 有效信号,因此我们需要一个标记,标记 a_vld 是否已经两次有效。

二、程序设计

设计一个 8bit 到 16bit 位宽转换电路。

module width_change_8to16 
( 
    input clk , // system clock 50Mhz on board
    input rst_n , // system rst, low active 
    input a_vld , // input a_vld 
    input [7:0] a , // input a 
    output reg b_vld , // output b_vld 
    output reg [15:0] b // output b
);
 
 // reg define 
 
 reg flag ; 
 reg [7:0] a_lock ; 
 
 //=======================================================
 // ------------------------- MAIN CODE -----------------
 //=======================================================
 
 always @ (posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0)
        flag <= 1'b0 ;
    else if ( a_vld == 1'b1 )
        flag <= ~flag ;
 end
 
 always @ (posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0)
        a_lock <= 8'b0 ;
    else if ( a_vld == 1'b1 )
        a_lock <= a ;
 end
 
 always @ (posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0)
        b_vld <= 1'b0 ;
    else if ( a_vld == 1'b1 && flag == 1'b1 )
        b_vld <= 1'b1 ; // 产生 vld 信息
    else
        b_vld <= 1'b0 ;
 end
 
 always @ (posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0)
        b <= 16'b0 ;
    else if ( a_vld == 1'b1 && flag == 1'b1 )
        b <= { a_lock, a } ; // 拼接数据
end
 
 endmodule

代码中的 flag 信号是表示 a_vld 是否已经为 1,在 a_vld 为 1 时不停的取反赋值给本身,然后我们通过 flag=1 和 a_vld=1 组合判断即可得到 a_vld 已经有效两次。此时可以产生 b_vld 信号。

代码中的 a_lock 表示是 a 信号在 a_vld 有效时的锁存数据,因为 b 信号的拼接是由 a 上一次的数据和当前 a 的数据进行拼接,因此需要产生一个 a 上一次的数据,就是 a_lock。

三、设计验证

`timescale 1ns / 1ps

module TB();

reg sys_clk; 
reg sys_rst_n; 

reg [7:0] a ; 
reg a_vld ;

wire [15:0] b ;
wire b_vld ;
 
initial begin
    sys_clk = 1'b0;
    sys_rst_n = 1'b0;
    
    a = 8'b0; 
    a_vld = 1'b0; 
    
    #200
    sys_rst_n = 1'b1;
    
    #28
    a_vld = 1'b1; 
    a = 8'h55; 
    #20
    a = 8'haa;
    #20
    a = 8'hbb;
    #20
    a = 8'hcc;
    #20
    a_vld = 1'b0; 
 end
 
 always #10 sys_clk = ~sys_clk;
 
 width_change_8to16 u_width_change_8to16 (
    .clk (sys_clk ),
    .rst_n (sys_rst_n),
    .a_vld (a_vld ),
    .a (a ),
    .b_vld (b_vld ),
    .b (b )
    );
 
 endmodule

在这里插入图片描述


一、非整数倍位宽转换简介

非整数倍的位宽转换与整数倍相比会稍微复杂一些。非整数倍的位宽转换指的是 1.5 倍位宽转换或者 2.5 倍位宽转换等等,比如位宽 8bit,需要转换为 12bit 的位宽转换。

非整数倍的位宽转换指的是进行 1.5 倍位宽转换或者其他带有小数倍数的位宽转换设计,非整数倍的位宽转换比较复杂,为什么比较复杂呢?大家可以先思考下,下面我们来进行分析,假设 a 数据位宽为 8bit, b 信号位宽为 12bit,刚好是 1.5 倍的位宽转换,如下图所示,我们可以看出,两个周期的 a 数据才能发送一次b 数据,但是 b 只能发送 12bit 数据,两个周期的 a 数据量有 16bit,还剩下 4bit 数据没有发送完,这 4bit 数据需要和下一个周期的 a 数据继续拼接产生一个 b 数据,1.5 倍的位宽转换刚好是三个 a 数据,产生两个 b 数据信息,如下图所示所示。

在这里插入图片描述
我们来看下非整数倍的位宽转换,如下图所示,一个是 A 模块,一个是 B 模块,一般模块的接口由数据信号和数据有效指示 vld 构成,A 模块的位宽是8bit,B 模块的位宽是 12bit,这两个模块是没有办法直接对接的,中间需要一个位宽转换模块。

在这里插入图片描述
在这里插入图片描述
下面我们来分析下如何设计这个位宽转换,我们假设位宽转换输入信号为数据 a 和 a_vld,a 为 8bit信号,输出信号为数据 b 和 b_vld,b 为 12bit 信号。

我们先来画下位宽转换的输入信号的时序图,如下图所示。
在这里插入图片描述
如上图所示,假设 a 信号会持续五个时钟周期,即 a_vld 在五个时钟周期全部为 1,每个时钟周期都有数据,分别是 0x55、0xaa、0xbb、0xcc 和0xdd。而输出信号 b 是 12bit,12bit 数据需要 1.5 个 8bit 数据,由此我们可以画出 b 的时序图,如上图所示。

由上图可以看出,b_vld 都是在 a 传输了两个 8bit 数据后才为高 1 次,但是会持续 2 拍,b_vld 在周期 2 和周期 3 都为 1,因为此时有 3 个 8bit 数据,刚好可以传输两个 12bit 数据。在两个 b_vld 产生之后,b_vld 为 0,等待 a 数据继续来,当再次出现两个 a_vld 时,b_vld和 b 数据继续产生,和周期 2 和周期 3 类似。

二、程序设计

module width_change_8to12 
( 
    input clk , // system clock 50Mhz on board
    input rst_n , // system rst, low active 
    input a_vld , // input a_vld
    input [7:0] a , // input a 
    output reg b_vld , // output b_vld 
    output reg [11:0] b // output b
);
 
 // reg define 
 
 reg [1:0] vld_cnt ; 
 reg [7:0] a_lock ; 
 
 //===========================================================================
 // ------------------------- MAIN CODE -------------------------------------
 //===========================================================================
 
 always @ (posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0)
        vld_cnt <= 2'b0 ;
    else if ( a_vld == 1'b1 ) begin
        if ( vld_cnt == 2'd2 )
            vld_cnt <= 2'b0 ;
        else
            vld_cnt <= vld_cnt + 2'b1 ;
    end
 end
 
 always @ (posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0)
        a_lock <= 8'b0 ;
    else if ( a_vld == 1'b1 )
        a_lock <= a ;
 end
 
 always @ (posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0)
        b_vld <= 1'b0 ;
    else if ( a_vld == 1'b1 && vld_cnt == 2'd1 )
        b_vld <= 1'b1 ;
    else if ( a_vld == 1'b1 && vld_cnt == 2'd2 )
        b_vld <= 1'b1 ;
    else
        b_vld <= 1'b0 ;
 end
 
 always @ (posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0)
        b <= 12'b0 ;
    else if ( a_vld == 1'b1 && vld_cnt == 2'd1 )
        b <= { a_lock, a[7:4] } ;
    else if ( a_vld == 1'b1 && vld_cnt == 2'd2 )
        b <= { a_lock[3:0], a} ;
    end
 
 endmodule

代码中的 vld_cnt 信号是表示 a_vld 有效了几个时钟周期,在 a_vld 为 1 时不停的加 1,等到 vld_cnt 为 2 的时候清零重新开始计数,然后我们通过 vld_cnt 和 a_vld=1 组合判断即可得到b_vld 信号。

代码中的 a_lock 表示是 a 信号在 a_vld 有效时的锁存数据,因为 b 信号的拼接是由 a 上一次的数据和当前 a 的数据进行拼接,因此需要产生一个 a 上一次的数据,就是a_lock。

三、设计验证

`timescale 1ns / 1ps

module TB();

reg sys_clk; 
reg sys_rst_n; 

reg [7:0] a ; 
reg a_vld ;
 
wire [15:0] b ;
wire b_vld ;

initial begin
    sys_clk = 1'b0;
    sys_rst_n = 1'b0;
    
    a = 8'b0; 
    a_vld = 1'b0; 
    
    #200
    sys_rst_n = 1'b1;
    
    #28
    a_vld = 1'b1; 
    a = 8'h55; 
    #20
    a = 8'haa;
    #20
    a = 8'hbb;
    #20
    a = 8'hcc;
    #20
    a = 8'hdd;
    #20
    a = 8'hee;
    #20
    a_vld = 1'b0; 
end
 
always #10 sys_clk = ~sys_clk;
 
 width_change_8to12 u_width_change_8to12 (
    .clk (sys_clk ),
    .rst_n (sys_rst_n),
    .a_vld (a_vld ),
    .a (a ),
    .b_vld (b_vld ),
    .b (b )
    );
 
 endmodule

在这里插入图片描述

最后

以上就是兴奋发带为你收集整理的整数倍与非整数倍位宽转换电路的全部内容,希望文章能够帮你解决整数倍与非整数倍位宽转换电路所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部