草庐IT

Xilinx Vivado复数乘法器Complex Multiplier IP核调用及其仿真

shuwei1990 2023-09-02 原文

 Complex Multiplier IP核的使用,尤其是输出数据的截位到底怎么弄,我感觉官方文档PG104写的不清楚。我个人在网上也没找到好的讲解文章,就自己琢磨了下,然后写成文档记录在此,方便将来也有疑问的同学。

目录

一、如下是我的仿真代码:

二、testbench中的IP设置如下: 

三、几个关键点的理解如下:

1、当IP输出位宽为默认的最大值25时,此时IP没有截位。如仿真例子中第一种方法:

2、当IP输出位宽设置为20时,此时IP相对于最大值25就截掉了5位。如仿真例子中第二种方法:

3、如上第2点使用同一个IP设置:IP输出位宽设置为20时,此时IP相对于最大值25就截掉了5位。但修改输入数据的使用方法,如仿真例子中第三种方法:

4、modelsim仿真结果如下所示,可以看到仿真结果是正确的。


一、如下是我的仿真代码:

/*-------------------------------------------------------------------------------------------------------------------
    Author:  Zheng Wei
    Date:    2022-10-10
    Version: 1.0
    Description: It is a tb_cmpy test.
-------------------------------------------------------------------------------------------------------------------*/

`timescale 1ns / 1ps

module tb_cmpy;
                                                
    reg                 i_sys_clk   ; 
    reg                 i_sys_rst   ;
                                     
    reg                 din_ena     ;    
    reg     [9 :0]      din_re0     ;
    reg     [9 :0]      din_im0     ;
    reg     [9 :0]      din_re1     ;
    reg     [9 :0]      din_im1     ;
                                                          
                                                          
    //  clock generate module
    parameter  period = 10;           // 100MHz
    initial begin
        i_sys_clk = 1'b0;
        forever     #(period/2)  i_sys_clk = ~i_sys_clk;
    end
                                                                         
	//-------------------------------------------------------------------	
	
	//  system initialization
	task task_sysinit;
		begin
            			
		end
	endtask
	
	//  system reset
	task task_reset;
        begin
            i_sys_rst = 1'b1;
            repeat(2)  @(negedge i_sys_clk);
            i_sys_rst = 1'b0;
        end
    endtask                                                      
                                                          
                                                          
                                                          
    initial begin
        task_sysinit;
	    task_reset  ;
                                  
        repeat(10)  @(posedge i_sys_clk);
                                  
        // 10bit: 1 sign bit, 1 integer bit, 8 fraction bit
        // case1: x0 = 0.5 + j; x1 = 1 - 0.5j
        // result: x0 * x1 = 1 + 0.75j, 1 sign bit, 1 integer bit, 8 fraction bit
        din_ena = 1;
        din_re0 = 10'b00_1000_0000;
        din_im0 = 10'b01_0000_0000;
        din_re1 = 10'b01_0000_0000;
        din_im1 = 10'b11_1000_0000;
                                      
        @(posedge i_sys_clk); 
        din_ena = 0;
                                      
        repeat(20) @(posedge i_sys_clk);                               
                                                           
        // 10bit: 1 sign bit, 1 integer bit, 8 fraction bit
        // case2: x0 = 0.5 - j; x1 = 1 - 0.75j
        // result: x0 * x1 = -0.25 - 1.375j, 1 sign bit, 1 integer bit, 8 fraction bit
        din_ena = 1;
        din_re0 = 10'b00_1000_0000;
        din_im0 = 10'b11_0000_0000;
        din_re1 = 10'b01_0000_0000;
        din_im1 = 10'b11_0100_0000;
                                         
        @(posedge i_sys_clk); 
        din_ena = 0;                                 
                                         
        repeat(500) @(posedge i_sys_clk);
		                                  
		$stop;                          
    end                                                                                           
                                                                                                  
                                                                                                  
//------------ first method ---------------------------------------------------------------                                                                    
    wire                    fft1_ena    ;
    wire    signed  [31:0]  fft1_real   ;
    wire    signed  [31:0]  fft1_imag   ;
    wire    signed  [11:0]  fft1_re_dout;
    wire    signed  [11:0]  fft1_im_dout;   
                                                                                                  
    // din: real[11:0], image[27:16]; dout: real[24:0], image[56:32].
    cmpy_1 u1_cmpy(
        .aclk               (i_sys_clk                                                  ),  // input wire aclk
        .s_axis_a_tvalid    (din_ena                                                    ),  // input wire s_axis_a_tvalid
        .s_axis_a_tdata     ({4'd0,{2{din_im0[9]}},din_im0,4'd0,{2{din_re0[9]}},din_re0}),  // input wire [31 : 0] s_axis_a_tdata
        .s_axis_b_tvalid    ( 1'b1                                                      ),  // input wire s_axis_b_tvalid
        .s_axis_b_tdata     ({4'd0,{2{din_im1[9]}},din_im1,4'd0,{2{din_re1[9]}},din_re1}),  // input wire [31 : 0] s_axis_b_tdata
        .m_axis_dout_tvalid (fft1_ena                                                   ),  // output wire m_axis_dout_tvalid
        .m_axis_dout_tdata  ({fft1_imag,fft1_real}                                      )   // output wire [63 : 0] m_axis_dout_tdata
    );
                                               
    assign  fft1_re_dout = fft1_real[8+:12];  // [19:8]: shift right 8 bit
    assign  fft1_im_dout = fft1_imag[8+:12];  // [19:8]: shift right 8 bit                                                                                                 
                                                                                                 
                                                                                                 
//------------ second method ---------------------------------------------------------------
    wire                    fft2_ena    ;
    wire    signed  [23:0]  fft2_real   ;
    wire    signed  [23:0]  fft2_imag   ;
    wire    signed  [11:0]  fft2_re_dout;
    wire    signed  [11:0]  fft2_im_dout;                                                                                             
                                                                                                  
    // din: real[11:0], image[27:16]; dout: real[19:0], image[43:24].
    cmpy_0 u2_cmpy(
        .aclk               (i_sys_clk                                                  ),  // input wire aclk
        .s_axis_a_tvalid    (din_ena                                                    ),  // input wire s_axis_a_tvalid
        .s_axis_a_tdata     ({4'd0,{2{din_im0[9]}},din_im0,4'd0,{2{din_re0[9]}},din_re0}),  // input wire [31 : 0] s_axis_a_tdata
        .s_axis_b_tvalid    ( 1'b1                                                      ),  // input wire s_axis_b_tvalid
        .s_axis_b_tdata     ({4'd0,{2{din_im1[9]}},din_im1,4'd0,{2{din_re1[9]}},din_re1}),  // input wire [31 : 0] s_axis_b_tdata
        .m_axis_dout_tvalid (fft2_ena                                                   ),  // output wire m_axis_dout_tvalid
        .m_axis_dout_tdata  ({fft2_imag,fft2_real}                                      )   // output wire [47 : 0] m_axis_dout_tdata
    );
                                               
    assign  fft2_re_dout = fft2_real[3+:12]; // [14:3]: shift right 8-5=3 bit
    assign  fft2_im_dout = fft2_imag[3+:12]; // [14:3]: shift right 8-5=3 bit                                                                                                 
                                                                                                 
                                                                                                 
//------------ third method ---------------------------------------------------------------
    wire                    fft3_ena    ;
    wire    signed  [23:0]  fft3_real   ;
    wire    signed  [23:0]  fft3_imag   ;
    wire    signed  [11:0]  fft3_re_dout;
    wire    signed  [11:0]  fft3_im_dout;                                                                                             
                                                                                                  
    // din: real[11:0], image[27:16]; dout: real[19:0], image[43:24].
    cmpy_0 u3_cmpy(
        .aclk               (i_sys_clk                            ),  // input wire aclk
        .s_axis_a_tvalid    (din_ena                              ),  // input wire s_axis_a_tvalid
        .s_axis_a_tdata     ({4'd0,din_im0,2'd0,4'd0,din_re0,2'd0}),  // input wire [31 : 0] s_axis_a_tdata
        .s_axis_b_tvalid    ( 1'b1                                ),  // input wire s_axis_b_tvalid
        .s_axis_b_tdata     ({4'd0,din_im1,2'd0,4'd0,din_re1,2'd0}),  // input wire [31 : 0] s_axis_b_tdata
        .m_axis_dout_tvalid (fft3_ena                             ),  // output wire m_axis_dout_tvalid
        .m_axis_dout_tdata  ({fft3_imag,fft3_real}                )   // output wire [47 : 0] m_axis_dout_tdata
    );
                                                                                                  
    assign  fft3_re_dout = fft3_real[7+:12]; // [18:7]: shift right 8+4-5=7 bit
    assign  fft3_im_dout = fft3_imag[7+:12]; // [18:7]: shift right 8+4-5=7 bit                                                                                                 
                                                                                                  
                                                                                                 
endmodule

二、testbench中的IP设置如下: 

  1. IP cmpy_1的设置如下:两个输入都设置成12bit,输出默认的25bit;
  2. IP cmpy_0的设置如下:两个输入都设置成12bit,但输出设置为20bit;

三、几个关键点的理解如下:

1、当IP输出位宽为默认的最大值25时,此时IP没有截位。如仿真例子中第一种方法:

两个输入数据都是10bit宽,其中8bit为定点小数,实际上就是都左移8bit;那么相乘的结果就是左移了16bit,如果相乘的结果也是取8位为定点小数(即实际上右移8bit),那么就还需要右移8bit才能得到正确的值,也即如下代码:

assign  fft1_re_dout = fft1_real[8+:12];  // [19:8]: shift right 8 bit

2、当IP输出位宽设置为20时,此时IP相对于最大值25就截掉了5位。如仿真例子中第二种方法:

两个输入数据都是10bit宽,其中8bit为定点小数,实际上就是都左移8bit;那么相乘的结果就是左移了16bit,如果相乘的结果也是取8位为定点小数(即实际上右移8bit),那么就还需要右移8bit才能得到正确的值。但是因为IP已经帮我们截掉了5bit,所以此时我们只需要再截掉8-5=3bit就行了,也即如下代码:

assign  fft2_re_dout = fft2_real[3+:12]; // [14:3]: shift right 8-5=3 bit

3、如上第2点使用同一个IP设置:IP输出位宽设置为20时,此时IP相对于最大值25就截掉了5位。但修改输入数据的使用方法,如仿真例子中第三种方法:

仿真中给的两个输入数据都是10bit,但IP设置的输入数据位宽是12bit,那么就需要将10bit拓宽到12bit。有两种办法:

  • 如前面两个仿真例子,都是直接复制符号位进行拓宽到指定长度;
  • 如第三个仿真例子,是直接在结尾补0进行拓宽到指定长度。

现在来仔细讲下结尾补0的方法如何进行截位。本来两个都是10bit的数据,其中8bit为定点小数,实际上就是都左移8bit;但现在结尾补了2bit的0,那也就是总共左移了8+2=10bit了。

那么相乘的结果就是左移了20bit,如果相乘的结果也是取8位为定点小数(即实际上右移8bit),那么就还需要右移12bit才能得到正确的值。但是因为IP已经帮我们截掉了5bit,所以此时我们只需要再截掉12-5=7bit就行了,也即如下代码:

assign  fft3_re_dout = fft3_real[7+:12]; // [18:7]: shift right 8+4-5=7 bit

4、modelsim仿真结果如下所示,可以看到仿真结果是正确的。

 本文完结!

有关Xilinx Vivado复数乘法器Complex Multiplier IP核调用及其仿真的更多相关文章

  1. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  2. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  3. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  4. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

    我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

  5. ruby-on-rails - 复数 for fields_for has_many 关联未显示在 View 中 - 2

    目前,Itembelongs_toCompany和has_manyItemVariants。我正在尝试使用嵌套的fields_for通过Item表单添加ItemVariant字段,但是使用:item_variants不显示该表单。只有当我使用单数时才会显示。我检查了我的关联,它们似乎是正确的,这可能与嵌套在公司下的项目有关,还是我遗漏了其他东西?提前致谢。注意:下面的代码片段中省略了不相关的代码。编辑:不知道这是否相关,但我正在使用CanCan进行身份验证。routes.rbresources:companiesdoresources:itemsenditem.rbclassItemi

  6. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  7. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  8. ruby - 如何找到调用当前方法的方法 - 2

    如何找到调用此方法的位置?defto_xml(options={})binding.pryoptions=options.to_hifoptions&&options.respond_to?(:to_h)serializable_hash(options).to_xml(options)end 最佳答案 键入caller。这将返回当前调用堆栈。文档:Kernel#caller.例子[0]%rspecspec10/16|===================================================62=====

  9. ruby-on-rails - 使用 HTTParty 的非常基本的 Rails 4.1 API 调用 - 2

    Rails相对较新。我正在尝试调用一个API,它应该向我返回一个唯一的URL。我的应用程序中捆绑了HTTParty。我已经创建了一个UniqueNumberController,并且我已经阅读了几个HTTParty指南,直到我想要什么,但也许我只是有点迷路,真的不知道该怎么做。基本上,我需要做的就是调用API,获取它返回的URL,然后将该URL插入到用户的数据库中。谁能给我指出正确的方向或与我分享一些代码? 最佳答案 假设API为JSON格式并返回如下数据:{"url":"http://example.com/unique-url"

  10. ruby - ruby 乘法语句中星号中断语法前的空格 - 2

    在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl

随机推荐