代码简析
sin18b.mif文件用C语言生成,把0度到90度分成256等份,基值部分是取sin值乘219 - 1 = 524287再四舍五入后的值,斜率部分是下一点与当前点的差值。用45°值举例说明。对于45°角,对应xn地址是0x80,用文本查看器打开sin18b.mif文件看到0x80地址存放数值为0x5A8278DC。sin(45°)×524287四舍五入取整得0x5A827。同理(45+1/256)°对应的值是0x5B103。而0x5B103 - 0x5A827 = 0x8DC,正好是0x5A8278DC的低12位数值。
SinQ18b.vhd结构代码如下:
Architecture EP4C of SinQ18b is 12. alias x :std_vector(0 to 17) is x0in; Signal dlyTy :std_vector(0 to 2); Alias ty :std_logic is dlyTy(0); 15. Signal y :std_vector(0 to 15); Signal dlyYL,cof : std_vector(0 to 7); Signal sinQ :std_vector(1 to 31); Signal compens : std_vector(0 to12); Signal PIP1V,vBase : std_vector(0 to 18);
Begin
21. gTable : entity work.RamRom Generic Map(AW=>8, DW=>31,mif=>"sin18b.mif", rom_m=>true) 22. PortMap(clock=>clock, rdA=>y(0 to 7), q=>sinQ); 23. y <= bv_xor(x(1), x(2 to 17)) + (b_or(x(2 to 17)) and x(1)); 24. PIP1V <= vBase + compens(0 to 11) + compens(12);
Process(clock) begin if rising_edge(clock)then 27. dlyYL <= y(8to 15); cof <=dlyYL; vBase <=ascend(sinQ, 19); 30. compens <=ascend(descend(sinQ, 12) * cof, 13); ShiftLeft(dlyTy, x(0)); q4Sin <=bv_xor(ty, '0' & PIP1V(0 to 16)) + ty; end if; End process;
End EP4C;
行12对x0in重命名,目的当把端口改为x0in: in std_vector(17 downto 0);的降序形式时不影响后面逻辑。 行15定义的y是x在第一象限对应的位置。
行13定义的dlyTy,用于对x(0)的流水线延时,见行31。x(0)=0表示在一二象限,sin值>=0,x(0)=1表示三四象限,sin值按照一二象限规则计算后取负即得。
行21、22中调用RamRom,rdA为输入地址,q为查表输出,输出相对于地址输入延时两个时钟周期。AW=>8指明地址宽度8位,即256个地址。DW=>31指明数据宽度为31位。rom_m=>true指明使用ROM模式,即不需要写地址和写入数据。
行23完成x处于第一象限时保持不变,处于第二象限时对称折反即取补运算。原理上可简化为y <= bv_xor(x(1), x(2 to 17)) + x(1);其中函数bv_xor(b,v)返回比特b与向量v作异或操作的结果,当b=0时返回v,b=1时返回v的逐比特取反值。并考虑x(1 to 17)=0x10000时补运算溢出情况,所以用b_or(x(2 to 17)) and x(1)代替x(1)。
行24完成基值与补偿值相加,+compens(12)是四舍五入算法。
行27,28,29,31均是流水线延时,完成时序对齐。31行的过程ShiftLeft(v, b)是对v的左移操作,低位移入b。
行32是取补输出。
小结
SinQ18b是高精度快速sin函数生成器。
|