赞
踩
trigonometric_function/cos_function/cos_function_x1.v
:ROM空间优化的余弦函数发生器trigonometric_function/cos_function/cos_function_x4.v
:LUT规模优化的余弦函数发生器trigonometric_function/cos_function/Makefile
:用于测试的make脚本文件trigonometric_function/cos_function/testbench.sv
:测试激励文件trigonometric_function/cos_function/python/gen_cos_data.py
:用于生成余弦函数数据的python脚本虽然两种优化方向的余弦函数发生器的模块名稍有区别,但是参数配置、信号和信号的时序都是一样的。
// trigonometric_function/cos_function/cos_function_x1.v module cos_function_x1 #( parameter DEPTH_BITWIDTH = 8, parameter DATA_BITWIDTH = 8 ) ( input clk, input rstn, input [DEPTH_BITWIDTH-1:0] pword, output reg [ DATA_BITWIDTH-1:0] cos ); // trigonometric_function/cos_function/cos_function_x4.v module cos_function_x4 #( parameter DEPTH_BITWIDTH = 8, parameter DATA_BITWIDTH = 8 ) ( input clk, input rstn, input [DEPTH_BITWIDTH-1:0] pword, output reg [ DATA_BITWIDTH-1:0] cos );
以下是参数的相关解释:
参数 | 备注 |
---|---|
DEPTH_BITWIDTH | 余弦函数发生器地址深度 |
DATA_BITWIDTH | 输出的数据位宽 |
需要注意的是,这里建议DEPTH_BITWIDTH
和DATA_BITWIDTH
相等,因为这样在经验上可以获得精度和空间利用的最高性价比。
以下是信号的相关解释:
方向 | 位宽 | 信号 | 备注 |
---|---|---|---|
输入 | 1 | clk | 系统时钟信号 |
输入 | 1 | rstn | 同步复位信号,低有效 |
输入 | DEPTH_BITWIDTH | pword | 余弦函数相位 |
输入 | DATA_BITWIDTH | cos | 余弦函数输出 |
这个的时序很简单,pword
与cos
同周期。
利用trigonometric_function/cos_function/python/gen_cos_data.py
可以生成余弦函数数据,具体用法如下:
python gen_cos_data.py 深度位宽 数据位宽
这样就会在本目录下生成cos_data_x1.dat
和cos_data_x4.dat
两个数据文件,分别对应ROM空间优化版本和LUIT资源优化版本。
本设计主要利用了查表的原理。
LUT优化的实现(cos_function_x4
)如下:
// trigonometric_function/cos_function/cos_function_x4.v module cos_function_x4 #( parameter DEPTH_BITWIDTH = 8, parameter DATA_BITWIDTH = 8 ) ( input clk, input rstn, input [DEPTH_BITWIDTH-1:0] pword, output reg [ DATA_BITWIDTH-1:0] cos ); reg [DATA_BITWIDTH-1:0] cos_rom[0:2**DEPTH_BITWIDTH-1]; initial $readmemh("./python/cos_data_x4.dat", cos_rom); always @(posedge clk) begin if (!rstn) begin cos <= {DATA_BITWIDTH{1'b0}}; end else begin cos <= cos_rom[pword]; end end endmodule //cos_function_x4
很简单,就是用pword
为地址读取cos_rom
中的数据,然后直接输出。
以下为ROM优化版本(cos_function_x1
)的实现:
// trigonometric_function/cos_function/cos_function_x1.v module cos_function_x1 #( parameter DEPTH_BITWIDTH = 8, parameter DATA_BITWIDTH = 8 ) ( input clk, input rstn, input [DEPTH_BITWIDTH-1:0] pword, output reg [ DATA_BITWIDTH-1:0] cos ); localparam DEPTH = 2 ** (DEPTH_BITWIDTH - 2); localparam DATA_MAX_VALUE = 2 ** DATA_BITWIDTH; reg [DATA_BITWIDTH-1:0] cos_rom[0:DEPTH-1]; initial $readmemh("./python/cos_data_x1.dat", cos_rom); always @(posedge clk) begin if (!rstn) begin cos <= {DATA_BITWIDTH{1'b0}}; end else begin if (pword < DEPTH) begin cos <= cos_rom[pword]; end else if ((pword >= DEPTH) && (pword < 2 * DEPTH)) begin cos <= DATA_MAX_VALUE - cos_rom[2*DEPTH-pword-1]; end else if ((pword >= 2 * DEPTH) && (pword < 3 * DEPTH)) begin cos <= DATA_MAX_VALUE - cos_rom[pword-2*DEPTH]; end else begin cos <= cos_rom[4*DEPTH-pword-1]; end end end endmodule //cos_function_x1
在这个实现中,利用了余弦函数单周期内的特性求解,节省了 3 4 \frac{3}{4} 43的ROM资源。
cos \cos cos函数的一个周期为 2 π 2\pi 2π,但是在这一个周期中可以将其分解为4段(暂不考虑边界情况): ( 0 , 0.5 π ) (0,0.5\pi) (0,0.5π)、 ( 0.5 π , π ) (0.5\pi,\pi) (0.5π,π)、 ( π , 1.5 π ) (\pi,1.5\pi) (π,1.5π)和 ( 1.5 π , 2 π ) (1.5\pi,2\pi) (1.5π,2π),这四个区间其实都可以用同一段区间的数据生成。假设 a ∈ ( 0 , 0.5 π ) a\in(0,0.5\pi) a∈(0,0.5π)、 b ∈ ( 0.5 π , π ) b\in(0.5\pi,\pi) b∈(0.5π,π)、 c ∈ ( π , 1.5 π ) c\in(\pi,1.5\pi) c∈(π,1.5π)、 d ∈ ( 1.5 π , 2 π ) d\in(1.5\pi,2\pi) d∈(1.5π,2π),储存区 R R R长度为 0.5 π 0.5\pi 0.5π,输出数据 D [ a ] = R [ a ] D[a]=R[a] D[a]=R[a],则易得以下式子:
D [ b ] = 0 − R [ π − b ] D[b]=0-R[\pi-b] D[b]=0−R[π−b]
D [ c ] = R [ c − π ] D[c]=R[c-\pi] D[c]=R[c−π]
D [ d ] = R [ 2 π − d ] D[d]=R[2\pi-d] D[d]=R[2π−d]
然后看边界情况,如果下溢出(寻址到小于0的空间)就+1,如果上溢出(寻址到大于 a a a的空间)就-1,就可以得到代码中的转换式了。
cos_ram
在具体用在某一块FPGA上的时候最好用IP进行替代,实测安路TD没有办法将这个储存区综合为ROM。使用ROM时时序基本跟用储存区是一样的,具体可以参考具体器件开发环境(如Vivado、Pango)相关IP的数据手册。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。