zoukankan      html  css  js  c++  java
  • 转特权

    Verilog中宏定义位宽带来的问题

             宏定义在C语言程序中的使用司空见惯,他的好处就在于可以大大提高代码的可读性和可移植性。而在verilog中,也支持这个语法,在很多开源代码中也都能看到`define的身影。但是它的使用和C语言可不完全一样,很多时候需要非常小心和谨慎。其中最可能让设计者犯错的就是它的位宽问题。特权同学就吃过这个亏,因此有必要在此专门撰文讨论一下,不仅给自己提个醒,它希望读者您少走弯路。

    先简单的复习一下define在verilog基本语法书中的一些定义和简单的使用说明。

    宏定义 `define:用一个指定的标识符(即名字)来代表一个字符串,它的一般形式为:

     `define 标识符(宏名)字符串(宏内容)

    如:`define signal string,它的作用是指定用标识符signal来代替string这个字符串,在编译预处理时,把代码中在该命令以后所有的signal都替换成string。这种方法使用户能以一个简单的名字代替一个长的字符串,也可以用一个有含义的名字来代替没有含义的数字和符号,因此把这个标识符(名字)称为“宏名”,在编译预处理时将宏名替换成字符串的过程称为“宏展开”。`define是宏定义命令。

    例:

    `define    SIZE         8

    module reg[`SIZE:1] db;   //相当于定义寄存器reg[8:1] db;

             那么下面特权同学拿一个简单的实例来说明define使用时容易遇到的位宽问题,其实也是特权同学自己遇到的,感觉很有典型性。

    input clk;      //外部输入时钟,25MHz

    input rst_n;    //外部输入复位信号,低电平有效

    input[9:0] mcu_wr_addr; //原始地址数据

    output[9:0] mcu_wr_ab;  //译码后地址数据

    `define LCDX_DIS    800

    `define LCDSD_PAGE  `LCDX_DIS/4

    `define LCDSD_2PAGE `LCDSD_PAGE*2  

    `define LCDSD_3PAGE `LCDSD_PAGE*3

    reg[11:0] mcu_wr_abr;  

    always @(posedge clk or negedge rst_n)

        if(!rst_n) mcu_wr_abr <= 12'd0;

        else if((mcu_wr_addr[9:0] >= 10'd0) && (mcu_wr_addr[9:0] < `LCDSD_PAGE)) mcu_wr_abr <= {2'b00,mcu_wr_addr[9:0]};

        else if((mcu_wr_addr[9:0] >= `LCDSD_PAGE) && (mcu_wr_addr[9:0] < `LCDSD_2PAGE)) mcu_wr_abr <= {2'b01,mcu_wr_addr[9:0]-`LCDSD_PAGE};

        else if((mcu_wr_addr[9:0] >= `LCDSD_2PAGE) && (mcu_wr_addr[9:0] < `LCDSD_3PAGE)) mcu_wr_abr <= {2'b10,mcu_wr_addr[9:0]-`LCDSD_2PAGE};

        else mcu_wr_abr <= {2'b11,mcu_wr_addr[9:0]-`LCDSD_3PAGE};

    assign mcu_wr_ab = {mcu_wr_abr[11:10],mcu_wr_abr[7:0]};

    上面一段代码希望实现的功能是这样的:对输入地址总线mcu_wr_addr[9:0]进行译码,当他的值比`LCDX_DIS/4小(肯定比256小),则mcu_wr_addr[9:0]直接赋值mcu_wr_ab[9:0],并且此时的mcu_wr_ab[9:8] = 2’b00;当他的值大等于`LCDX_DIS/4且小于(`LCDX_DIS/4)*2,则mcu_wr_addr[9:0]-`LCDX_DIS/4的值(肯定比256小)赋给mcu_wr_ab[7:0],并且此时的mcu_wr_ab[9:8]==2’b01;依此类推。

        写了一段简单的测试脚本,分别依次输入mcu_wr_addr = 55/255/455/655,预计的输出应该是55/(55+256)/(55+512)/(55+768),即55/311/567/823。而我们查看波形如图1所示,得到的结果mcu_wr_ab却都是55,很显然没有达到既定的期望。

    ef058028-75c6-4c33-ab22-dd0c5dec2e20.jpg

     

    图1

    那么是谁在作怪?很显然,是位宽!我们再返回源代码,其实在综合的时候,Quartus II给出了三条警告:

    Warning (10230): Verilog HDL assignment warning at cy3mcutest.v(39): truncated value with size 34 to match size of target (12)

    Warning (10230): Verilog HDL assignment warning at cy3mcutest.v(40): truncated value with size 34 to match size of target (12)

    Warning (10230): Verilog HDL assignment warning at cy3mcutest.v(41): truncated value with size 34 to match size of target (12)

             分别就是指前面always中的三个else if/else if/else语句。问题也就是出在这里,因为通常定义的宏参数都是32位的常量(也可能是64位的,和运行的PC有关),哪怕是定义了这个宏参数的位宽。LCDX_DIS是32位的常量,而后面的几个宏参数都是由LCDX_DIS进行运算得到,也是32位常量。运算式(mcu_wr_addr[9:0]-`LCDSD_PAGE)的结果当然也就是32位宽,它前面再补2位,那么整个运算结果就是34位宽,因此给出了Warning是说式子左侧的12位寄存器和右边的34位结果位宽不符合。那么,这也就容易明白为什么仿真得出的结果中,原本译码的最高两位赋值始终为0不变了。

             简单的,单对这个例子,可以对源代码的always块做如下修改:

    always @(posedge clk or negedge rst_n)

        if(!rst_n) mcu_wr_abr[9:0] <= 10'd0;

        else if((mcu_wr_addr[9:0] >= 10'd0) && (mcu_wr_addr[9:0] < `LCDSD_PAGE)) mcu_wr_abr[9:0] <= mcu_wr_addr[9:0];

        else if((mcu_wr_addr[9:0] >= `LCDSD_PAGE) && (mcu_wr_addr[9:0] < `LCDSD_2PAGE)) mcu_wr_abr[9:0] <= (mcu_wr_addr[9:0]-`LCDSD_PAGE);

        else if((mcu_wr_addr[9:0] >= `LCDSD_2PAGE) && (mcu_wr_addr[9:0] < `LCDSD_3PAGE)) mcu_wr_abr[9:0] <= (mcu_wr_addr[9:0]-`LCDSD_2PAGE);

        else mcu_wr_abr[9:0] <= (mcu_wr_addr[9:0]-`LCDSD_3PAGE);

       

    always @(posedge clk or negedge rst_n)

        if(!rst_n) mcu_wr_abr[11:10] <= 2'd0;

        else if((mcu_wr_addr[9:0] >= 10'd0) && (mcu_wr_addr[9:0] < `LCDSD_PAGE)) mcu_wr_abr[11:10] <= 2'b00;

        else if((mcu_wr_addr[9:0] >= `LCDSD_PAGE) && (mcu_wr_addr[9:0] < `LCDSD_2PAGE)) mcu_wr_abr[11:10] <= 2'b01;

        else if((mcu_wr_addr[9:0] >= `LCDSD_2PAGE) && (mcu_wr_addr[9:0] < `LCDSD_3PAGE)) mcu_wr_abr[11:10] <= 2'b10;

        else mcu_wr_abr[11:10] <= 2'b11;   

             当然,重新修改后的代码虽然没有解决位宽不匹配的问题(第一个always块仍会有Warning),但是对输出的高位独立处理,避免了无法正常赋值输出的问题,重新仿真后的结果如图2所示,达到了设计要求。

    fc92909d-476e-4fa3-a53e-e682094aa139.jpg

     

    图2

             个人认为,一种比较稳妥的做法应该如下代码所示:

    wire[31:0] mcu_abreg1 = mcu_wr_addr[9:0]-`LCDSD_PAGE;

    wire[31:0] mcu_abreg2 = mcu_wr_addr[9:0]-`LCDSD_2PAGE;

    wire[31:0] mcu_abreg3 = mcu_wr_addr[9:0]-`LCDSD_3PAGE;

    always @(posedge clk or negedge rst_n)

        if(!rst_n) mcu_wr_abr <= 12'd0;

        else if((mcu_wr_addr[9:0] >= 10'd0) && (mcu_wr_addr[9:0] < `LCDSD_PAGE)) mcu_wr_abr <= {2'b00,mcu_wr_addr[9:0]};

        else if((mcu_wr_addr[9:0] >= `LCDSD_PAGE) && (mcu_wr_addr[9:0] < `LCDSD_2PAGE)) mcu_wr_abr <= {2'b01,mcu_abreg1[9:0]};

        else if((mcu_wr_addr[9:0] >= `LCDSD_2PAGE) && (mcu_wr_addr[9:0] < `LCDSD_3PAGE)) mcu_wr_abr <= {2'b10,mcu_abreg2[9:0]};

        else mcu_wr_abr <= {2'b11,mcu_abreg3[9:0]};

             这样做不会产生任何Warning,也能够从某种程度上看出设计者非常重视位宽的问题,甚至于在也不是很确定需要在always块里取多大位宽的时候,也有宏定义来什么这个最高的位宽值。

             另外,这里提一下,其实很多时候使用parameter能够达到和`define一样的效果。这个实例如果做如下的修改,实现的功能也是一样的。

    parameter LCDX_DIS =    800;

    parameter LCDSD_PAGE =  LCDX_DIS/4;

    parameter LCDSD_2PAGE = LCDSD_PAGE*2;  

    parameter LCDSD_3PAGE = LCDSD_PAGE*3;

    reg[11:0] mcu_wr_abr;  

    always @(posedge clk or negedge rst_n)

        if(!rst_n) mcu_wr_abr <= 12'd0;

        else if((mcu_wr_addr[9:0] >= 10'd0) && (mcu_wr_addr[9:0] < LCDSD_PAGE[9:0])) mcu_wr_abr <= {2'b00,mcu_wr_addr[9:0]};

        else if((mcu_wr_addr[9:0] >= LCDSD_PAGE[9:0]) && (mcu_wr_addr[9:0] < LCDSD_2PAGE[9:0])) mcu_wr_abr <= {2'b01,mcu_wr_addr[9:0]-LCDSD_PAGE[9:0]};

        else if((mcu_wr_addr[9:0] >= LCDSD_2PAGE[9:0]) && (mcu_wr_addr[9:0] < LCDSD_3PAGE[9:0])) mcu_wr_abr <= {2'b10,mcu_wr_addr[9:0]-LCDSD_2PAGE[9:0]};

        else mcu_wr_abr <= {2'b11,mcu_wr_addr[9:0]-LCDSD_3PAGE[9:0]};

    http://bbs.ednchina.com/BLOG_ARTICLE_1813053.HTM

  • 相关阅读:
    js练习题2
    js样式
    js小练习
    css动画样式
    css盒子、布局样式
    css一般样式
    css样式、选择器
    html表格、表单
    html 标签
    mysql连接查询,子查询,联合查询
  • 原文地址:https://www.cnblogs.com/jutyy/p/2684745.html
Copyright © 2011-2022 走看看