电子产品世界 » 论坛首页 » 嵌入式开发 » FPGA/CPLD » Verilog HDL无符号数和有符号数运算(转)


共3条 1/1 1 跳转至

Verilog HDL无符号数和有符号数运算(转)

高工
2010-05-03 14:48:18    评分

(今天要用Verilog建立一个器件的行为模型,涉及到有符号数的加减和乘法运算,因此查阅了些相关资料,觉得不错,转载于此。)

执行算术操作和赋值时,注意哪些操作数为无符号数、哪些操作数为有符号数非常重要。无符号数存储在:

线网

一般寄存器

基数格式表示形式的整数

  有符号数存储在:

整数寄存器

十进制形式的整数

  下面是一些赋值语句的实例:

 

reg [0:5] Bar;

integer Tab;

. . .

Bar = -4'd12; //寄存器变量Bar的十进制数为52,向量值为110100。

Tab = -4'd12; //整数Tab的十进制数为-12,位形式为110100。

 

-4'd12 / 4 //结果是1073741821。

-12 / 4 //结果是-3

 

  因为Bar是普通寄存器类型变量,只存储无符号数。右端表达式的值为'b110100(12的二进制补码)。因此在赋值后,Bar存储十进制值52。在第二个赋值中,右端表达式相同,值为'b110100,但此时被赋值为存储有符号数的整数寄存器。Tab存储十进制值-12(位向量为110100)。注意在两种情况下,位向量存储内容都相同;但是在第一种情况下,向量被解释为无符号数,而在第二种情况下,向量被解释为有符号数。

  下面为具体实例:

 

Bar = - 4'd12/4;

Tab = - 4'd12 /4;

 

Bar = - 12/4

Tab = - 12/4

 

  在第一次赋值中,Bar被赋于十进制值61(位向量为111101)。而在第二个赋值中,Tab被赋于与十进制1073741821(位值为0011...11101)。Bar在第三个赋值中赋于与第一个赋值相同的值。这是因为Bar只存储无符号数。在第四个赋值中,Bar被赋于十进制值-3。

  下面是另一些例子:

 

Bar = 4 - 6;

Tab = 4 - 6;

Bar被赋于十进制值62(-2的二进制补码),而Tab被赋于十进制值-2(位向量为111110)。

 

  下面为另一个实例:

 

Bar = -2 + (-4);

Tab = -2 + (-4);

>Bar被赋于十进制值58(位向量为111010),而Tab被赋于十进制值-6(位向量为111010)。 

 

因为VERILOG对reg跟wire型变量的乘法(*)都默认为无符号数相乘,所以不能直接用*号来表示。我是这样处理的:先把两个操作数变为源码,再用FOR循环进行移位相加,结果是对的,但是综合出来的结果占有的资源比较多,比直接调用QUARTUS库里的乘法器占用资源多百分之二十左右。

如果你用verilog2001,可以直接声明有符号数,做有符号数乘法,你再用synplify综合一下看看资源如何。

module multiplier_8by8 (a, b, product);

input signed [7:0] a, b;

output signed [15:0] product;

assign product = a * b;

endmodule

 




关键词: Verilog     无符     号数     和有     运算     赋值     十进    

高工
2010-05-03 16:27:40    评分
2楼

Verilog-2001标准在2001年就发布了,不过翻了一些Verilog书籍,对Verilog-2001的新增特性很少有提及,即使提到了,也只是寥寥数语带过,其实在Verilog-2001中做了很多有用的改进,给编程带来很大的帮助,有必要详细了解。

         在Quartus II软件中现在支持的Verilog标准有三类,即Verilog-1995,Verilog-2001,以及SystemVerilog-2005.具体用那种标准进行编译综合,需要在设置对话框中进行设置

       下面对Verilog-2001新增特性进行详细说明,部分说明用实例进行解析。

l         generate语句 Verilog-2001添加了generate循环,允许产生module和primitive的多个实例化,同时也可以产生多个variable,net,task,function,continous assignment,initial和always。在generate语句中可以引入if-else和case语句,根据条件不同产生不同的实例化。 为此,Verilog-2001还增加了以下关键字:generate,endgenerate,genvar,localparam。genvar为新增数据类型,存储正的integer。在generate语句中使用的index必须定义成genvar类型。localparam与parameter有些类似,不过其不能通过redefinition改变值。除了可以在generate语句中使用if-else,case外,还能使用for语句进行循环。 下面是一个使用generate的例子,根据a_width和b_width的不同,实例化不同的multiplier。 module multiplier (a, b, product); parameter a_width = 8, b_width = 8; localparam product_width = a_width+b_width; input [a_width-1:0] a; input [b_width-1:0] b; output[product_width-1:0]product; generate if((a_width < 8) || (b_width < 8)) CLA_multiplier #(a_width, b_width) u1 (a, b, product); else WALLACE_multiplier #(a_width, b_width) u1 (a, b, product); endgenerate endmodule 在下面的例子中,在generate语句中使用了for语句。 module Nbit_adder (co, sum, a, b, ci); parameter SIZE = 4; output [SIZE-1:0] sum; output co; input [SIZE-1:0] a, b; input ci; wire [SIZE:0] c; genvar i; assign c[0] = ci; assign co = c[SIZE]; generate for(i=0; i begin:addbit wire n1,n2,n3; //internal nets xor g1 ( n1, a[i], b[i]); xor g2 (sum[i],n1, c[i]); and g3 ( n2, a[i], b[i]); and g4 ( n3, n1, c[i]); or g5 (c[i+1],n2, n3); end endgenerate endmodule generate执行过程中,每一个generated net在每次循环中有唯一的名字,比如n1在4次循环中会产生如下名字: addbit[0].n1 addbit[1].n1 addbit[2].n1 addbit[3].n1 这也是为什么在begin-end块语句需要名字的一个原因。同样,实例化的module,gate等在每次循环中也有不同的名字。 addbit[0].g1 addbit[1].g1 addbit[2].g1 addbit[3].g1   l         constant functions Verilog的语法要求定义向量的宽度或数组大小时其值必须是一个确定的数字或一个常量表达式。比如: parameter WIDTH = 8; wire [WIDTH-1:0] data; 在Verilog-1995标准中,常量表达式只能是基于一些常量的算术操作。而在Verilog-2001中增加了constant function,其定义与普通的function一样,不过constant function只允许操作常量。下面是一个使用constant function的例子,clogb2函数返回输入值2次方的次数。 module ram (address_bus, write, select, data); parameter SIZE = 1024; input [clogb2(SIZE)-1:0] address_bus; ... function integer clogb2 (input integer depth); begin for(clogb2=0; depth>0; clogb2=clogb2+1) depth = depth >> 1; end endfunction ... endmodule   l         Indexed vector part selects 在Verilog-1995中,可以选择向量的任一位输出,也可以选择向量的连续几位输出,不过此时连续几位的始末数值的index需要是常量。而在Verilog-2001中,可以用变量作为index,进行part select。 [base_expr +: width_expr] //positive offset [base_expr -: width_expr] //negative offset        其中base_expr可以是变量,而width_expr必须是常量。+:表示由base_expr向上增长width_expr位,-:表示由base_expr向上递减width_expr位。例如: reg [63:0] word; reg [3:0] byte_num; //a value from 0 to 7 wire [7:0] byteN = word[byte_num*8 +: 8];        如果byte_num的值为4,则word[39:32]赋值给byteN。   l         多维数组 Verilog-1995只允许一维数组,而Verilog-2001允许多维数组。 //1-dimensional array of 8-bit reg variables //(allowed in Verilog-1995 and Verilog-2001) reg [7:0] array1 [0:255]; wire [7:0] out1 = array1[address]; //3-dimensional array of 8-bit wire nets //(new for Verilog-2001) wire [7:0] array3 [0:255][0:255][0:15]; wire [7:0] out3 = array3[addr1][addr2][addr3]; 而且在Verilog-1995中不能对一维数组中取出其中的一位,比如要取出上面array1[7][5],需要将array1[7]赋给一个reg变量比如arrayreg <= array1[7],再从arrayreg中取出bit5,即arrayreg[5]。而在Verilog-2001中,可以任意取出多维数组中的一位或连续几位,比如: //select the high-order byte of one word in a //2-dimensional array of 32-bit reg variables reg [31:0] array2 [0:255][0:15]; wire [7:0] out2 = array2[100][7][31:24];   l         符号运算 在Verilog-1995中,integer数据类型为有符号类型,而reg和wire类型为无符号类型。而且integer大小固定,即为32位数据。在Verilog-2001中对符号运算进行了如下扩展。 Reg和wire变量可以定义为有符号类型: reg signed [63:0] data; wire signed [7:0] vector; input signed [31:0] a; function signed [128:0] alu; 函数返回类型可以定义为有符号类型。 带有基数的整数也可以定义为有符号数,在基数符号前加入s符号。 16'hC501 //an unsigned 16-bit hex value 16'shC501 //a signed 16-bit hex value 操作数可以在无符号和有符号之间转变。通过系统函数$signed和$unsigned实现。 reg [63:0] a; //unsigned data type always @(a) begin result1 = a / 2; //unsigned arithmetic result2 = $signed(a) / 2;//signed arithmetic end 增加了算术移位操作,在Verilog-1995中只有逻辑移位操作。比如D的初始值为8’b10100011,则: D >> 3 //logical shift yields 8'b00010100 D >>> 3 //arithmetic shift yields 8'b11110100   l         指数运算 Verilog-2001中增加了指数运算操作,操作符为**。 always @(posedge clock) result = base ** exponent;   l         递归函数和任务 在Verilog-2001中增加了一个新的关键字:automatic。该关键字可以让任务或函数在运行中从新调用该任务和函数。 function automatic [63:0] factorial; input [31:0] n; if (n == 1) factorial = 1; else factorial = n * factorial(n-1); endfunction   l         组合逻辑敏感信号通配符 在组合逻辑设计中,需要在敏感信号列表中包含所有组合逻辑输入信号,以免产生锁存器。在大型的组合逻辑中比较容易遗忘一些敏感信号,因此在Verilog-2001中可以使用@*包含所有的输入信号作为敏感信号。 always @* //combinational logic sensitivity if (sel) y = a; else y = b;   l         使用逗号隔开敏感信号 Verilog-2001中可以用逗号来代替or隔开敏感信号。 always @(a or b or c or d or sel) always @(a, b, c, d, sel)   l         Automatic width extension beyond 32 bits 在Verilog-1995中,在不指定基数的情况下为大于32位的变量赋高阻值,只能使其低32位为高阻值,其他高位会被设置为0,此时需要指定基数值才能将高位赋值为高阻。 Verilog-1995: parameter WIDTH = 64; reg [WIDTH-1:0] data; data = 'bz; //fills with 'h00000000zzzzzzzz data = 64'bz; //fills with 'hzzzzzzzzzzzzzzzz 而在Verilog-2001中并没有这一限制。 Verilog-2001: parameter WIDTH = 64; reg [WIDTH-1:0] data; data = 'bz; //fills with 'hzzzzzzzzzzzzzzzz   l         组合端口及数据类型定义 在Verilog-1995中,端口定义和数据类型定义需要在两条语句中执行,而Verilog-2001中可以将其组合在一起。 module mux8 (y, a, b, en); output reg [7:0] y; input wire [7:0] a, b; input wire en;   l         ANSI格式的端口定义 在定义端口的同时并定义其数据类型,比上一个改进更简洁。 module mux8 (output reg [7:0] y, input wire [7:0] a, input wire [7:0] b, input wire en );   function [63:0] alu ( input [63:0] a, b, input [7:0] opcode );   l         定义reg并初始化 在Verilog-1995中定义和初始化reg需要两条语句,而在Verilog中可以合成一条语句。 Verilog-1995: reg clock; initial clk = 0; Verilog-2001: reg clock = 0;

 


菜鸟
2010-07-12 00:39:11    评分
3楼
很详细,喜欢,谢谢

共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]