FPGA实现任意倍率的位宽转换(Verilog HDL)

在数据的处理过程中,常常需要将数据的位宽进行转换。使用Xilinx提供的FIFO IP能够满足大部分位宽转换的使用场景,但是当面对输入与输出的位宽不是2^N(N只能为-3,-2,-1,0,1,2,3)倍时Xilinx所提供的FIFO IP就用不上了。


某个功能需要将数据从32路转换到50路
图1,某个功能需要将数据从32路转换到50路

 

这里博主提供两种方法来应对输入与输出不是2^N(N只能为-3,-2,-1,0,1,2,3)倍时的位宽转换,分别是使用移位寄存器和使用FIFO两种方式。我们先做一下简单的定义,使用I_WIDTH表示输入的位宽,O_WIDTH表示输出的位宽,N_frac = O_WIDTH/I_WIDTH表示转换倍率,这里的N_frac可以为任何的正值,使用din表示输入的数据,位宽是[I_WIDTH-1:0],din_vld为表示其有效信号,使用dout表示输出的数据,位宽是[O_WIDTH-1:0],dout_vld为表示其有效信号。

一,使用移位寄存器

使用移位寄存器的优点是结构方便,实现简单,但是当转换的位宽较大时会需要面临高扇出的问题,通常不好降低扇出。

1,直接移位

直接移位的实现方式是,对输入的数据进行计数,并且使用移位寄存器寄存,当移入的数据位宽大于输出的数据位宽的时候,移出输出的数据并给出相应的有效信号。
首先需要知道的是使用多大的移位寄存器,当I_WIDTH<O_WIDTH的时候,我们至少需要保证移位寄存器里面能够存储两次I_WIDTH的数据,一次O_WIDTH的数据,所以位宽需要定义成I_WIDTH+O_WIDTH,除此之外还需要一个计数器来计数输入数据以知道何时移出。代码实现如下:



localparam TEMP_DATA_WIDTH = I_WIDTH + O_WIDTH          ;
localparam COUNT_WIDTH     = $clog2(I_WIDTH + O_WIDTH+1);

reg [    COUNT_WIDTH-1:0] cnt_flop     ;
reg [TEMP_DATA_WIDTH-1:0] data_shift_in;

always @(posedge clk) begin
    if(din_vld) begin
        data_shift_in <= {data_shift_in[TEMP_DATA_WIDTH-1-I_WIDTH:0],din};
    end else begin
        data_shift_in <= data_shift_in;
    end
end

always @(posedge clk) begin
    if(rst) begin
        cnt_flop <= 'd0;
    end else if(din_vld) begin
        if(cnt_flop >= O_WIDTH) begin
            cnt_flop <= cnt_flop + I_WIDTH - O_WIDTH;
        end else begin
            cnt_flop <= cnt_flop + I_WIDTH;
        end
    end else begin
        cnt_flop <= cnt_flop;
    end
end

always @(posedge clk) begin
    if(din_vld && cnt_flop >= O_WIDTH) begin
        dout     <= data_shift_in[cnt_flop-1-:O_WIDTH];
        dout_vld <= 1'b1;
    end else begin
        dout     <= dout;
        dout_vld <= 1'b0;
    end
end


2,计数器移位

如果N_frac有一定规律,可以根据规律定制移位,这样可以以较低的扇出就能实现对应的功能。
比如I_WIDTH为16,O_WIDTH为25,我们可以拆成两个级联的I_WIDTH为4,O_WIDTH为5的模块,即16/25=(4/5)*(4/5),每个模块只需要一个逢5进位的计数器即可实现功能。

二,使用自建FIFO

使用FIFO的好处是时序负担较轻松,输入和输出的位宽可以更大,但是会面临着RAM占用较高的问题。由于Xilinx提供的FIFO无法胜任任意位宽转换的工作,所以自己编写FIFO是必要的。FIFO内的存储资源可以根据Xilinx提供的综合属性ram_style(例如(* ram_style=“block” *)) 来进行更改,这样可以直接使用BLOCK RAM的资源减少逻辑资源负担。FIFO不仅需要输入位宽可以配置,输入的深度也需要可以配置,并且输入数据的深度必须是输入位宽与输出位宽的最小公倍数。

三,总结

目前位宽转换功能无论写法,或多或少都有对应的缺点,这可能也是Xilinx没有提供相应IP的原因之一,所以设计过程中应该尽量减少任意倍率的位宽转换的情况,尽量使用官方提供的IP来实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值