Verilog 入门基础


Verilog 入门基础 胡敬朋 北京理工大学珠海学院 第一章 Verilog HDL入门 • 学习内容 – HDL概念 – Verilog的历史 – Verilog的用途– Verilog的用途 – 示例 •语言特点 什么是硬件描述语言HDL • 具有特殊结构能够对硬件逻辑电路的功能进行描述的 一种高级编程语言 • 这种特殊结构能够: – 描述电路的连接 – 描述电路的功能 – 在不同抽象级上描述电路 – 描述电路的时序 – 表达具有并行性 • HDL主要有两种:Verilog和VHDL – Verilog起源于C语言,因此非常类似于C语言,容易掌握 – VHDL起源于ADA语言,格式严谨,不易学习。 – VHDL出现较晚,但标准化早。IEEE 1706-1985标准。 Verilog的历史 • Verilog HDL是在1983年由GDA(GateWay Design Automation)公司的 Phil Moorby所创。Phi Moorby 后来成为Verilog-XL 的主要设计者和 Cadence 公司的第一个合伙人。 • 在1984~1985 年间,Moorby 设计出了第一个Verilog-XL 的仿真器。 • 1986 年,Moorby 提出了用于快速门级仿真的XL 算法。• 1986 年,Moorby 提出了用于快速门级仿真的XL 算法。 • 1990 年,Cadence 公司收购了GDA 公司 • 1991 年,Cadence 公司公开发表Verilog语言,成立了OVI(Open Verilog International)组织来负责Verilog HDL语言的发展。 • 1995 年制定了Verilog HDL的IEEE 标准,即IEEE1364 。 Verilog的用途 • Verilog的主要应用包括: –ASIC 和FPGA 工程师编写可综合的RTL 代码 – 高抽象级系统仿真进行系统结构开发 – 测试工程师用于编写各种层次的测试程序 – 用于ASIC 和FPGA 单元或更高层次的模块的模型开发 示例 边沿触发型D触发器 module DFF1 (d, clk, q); //D触发器基本模块 output q; input clk,d; reg q; always @ (posedge clk) //clk上升沿启动always @ (posedge clk) //clk上升沿启动 q<=d; //当clk有上升沿时d被锁入q endmodule 语言的主要特点 module(模块) module是层 次化设计的基 本构件 逻辑描述放在 • module能够表示: – 物理块,如IC或ASIC单元 – 逻辑块,如一个CPU设计的ALU部分 – 整个系统 • 每一个模块的描述从关键词module开始,有一个名称(如 SN74LS74,DFF,ALU等等),由关键词endmodule结束。 逻辑描述放在 module内部 语言的主要特点— 模块端口(module ports) 端口在模块名字 后的括号中列出 端口可以说明为 input, output 端口等价于硬件 的引脚(pin) input, output及 inout • 注意模块的名称DFF,端口列表及说明 • 模块通过端口与外部通信 语言的主要特点 模块实例化(module instances) module DFF (d, clk, clr, q, qb); .... endmodule module REG4( d, clk, clr, q, qb); output [3: 0] q, qb;output [3: 0] q, qb; input [3: 0] d; input clk, clr; DFF d0 (d[ 0], clk, clr, q[ 0], qb[ 0]); DFF d1 (d[ 1], clk, clr, q[ 1], qb[ 1]); DFF d2 (d[ 2], clk, clr, q[ 2], qb[ 2]); DFF d3 (d[ 3], clk, clr, q[ 3], qb[ 3]); endmodule 语言的主要特点 • 可以将模块的实例通过端口连接起来构成一个大的系 统或元件。 • 在上面的例子中,REG4有模块DFF的四个实例。注 意,每个实例都有自己的名字(d0, d1, d2, d3)。实例 名是每个对象唯一的标记,通过这个标记可以查看每 模块实例化(module instances) 名是每个对象唯一的标记,通过这个标记可以查看每 个实例的内部。 • 实例中端口的次序与模块定义的次序相同。 • 模块实例化与调用程序不同。每个实例都是模块的一 个完全的拷贝,相互独立、并行。 第二章 Verilog的语言规则 1. 文字规则 2. 操作符 学习内容: 文字规则— 空白符和注释 module MUX2_1 (out, a, b, sel); // Port declarations output out; input sel, // control input b, /* data inputs */ a; /* 格式自由 使用空白符提高可读性及代码组 织。Verilog忽略空白符除非用于 分开其它的语言标记。 单行注释 到行末结束 The netlist logic selects input ”a”when sel = 0 and it selects ”b”when sel = 1. */ not (sel_, sel); and (a1, a, sel_), (b1, b, sel); // What does this line do? or (out, a1, b1); endmodule 多行注释,在/* */内 文字规则— 整数常量和实数常量 • 整数的大小可以定义也可以不定义。整数表示为: 其中 size :大小,由十进制数表示的位数(bit)表示。缺省为32位 base:数基,可为2(b)、8(o)、10(d)、16(h)进制。缺省为10进 制 value:是所选数基内任意有效数字,包括X、Z。 • 实数常量可以用十进制或科学表示法表示。 Verilog中,常量(literals)可是整数也可以是实数 • 实数常量可以用十进制或科学表示法表示。 12 unsized decimal (zero-extended to 32 bits) 'H83a unsized hexadecimal (zero- extended to 32 bits) 8'b1100_ 0001 8-bit binary 64'hff01 64-bit hexadecimal (zero- extended to 64 bits) 9'O17 9-bit octal 32'bz01x Z-extended to 32 bits 3’b1010_ 1101 3-bit number, truncated to 3’b101 6.3 decimal notation 32e- 4 scientific notation for 0.0032 4.1E3 scientific notation for 4100 文字规则— 整数常量和实数常量 • 整数的大小可以定义也可以不定义。整数表示为: – 数字中(_)忽略,便于查看 – 没有定义大小(size)整数缺省为32位 – 缺省数基为十进制 – 数基(base)和数字(16进制)中的字母无大小写之分– 数基(base)和数字(16进制)中的字母无大小写之分 – 当数值value大于指定的大小时,截去高位。如 2’b1101表 示的是2’b01 • 实数常量 – 实数可用科学表示法或十进制表示 – 科学表示法表示方式: <尾数><指数>, 表示: 尾数×10指数 文字规则— 字符串(string) • 字符串要在一行中用双引号括起来,也就是不能跨行。 • 字符串中可以使用一些C语言转义(escape)符,如\t \n Verilog中,字符串大多用于显示信息的命令中。Verilog没 有字符串数据类型 • 可以使用一些C语言格式符(如%b)在仿真时产生格式 化输出: ”This is a normal string” ”This string has a \t tab and ends with a new line\n” ”This string formats a value: val = %b” 文字规则— 字符串(string) 转义符及格式符将在验证支持部分讨论 格式符 %h %o %d %b %c %s %v %m %t hex oct dec bin ACSII string strength module time 转义符 \t \n \\ \” \<1-3 digit octal number> tab 换行 反斜杠 双引号 ASCII representation of above 格式符%0d表示没有前导0的十进制数 文字规则— 标识符(identifiers) • 标识符是用户在描述时给Verilog对象起的名字 • 标识符必须以字母(a-z, A-Z)或(_)开头,后面可以是字母、数字、( $ )或 (_)。 • 最长可以是1023个字符 • 标识符区分大小写,sel和SEL是不同的标识符 • 模块、端口和实例的名字都是标识符 module MUX2_1 (out, a, b, sel); output out; input a, b, sel; not not1 (sel_, sel); and and1 (a1, a, sel_); and and2 (b1, b, sel); or or1 (out, a1, b1); endmodule Verilog标识符 文字规则— 标识符(identifiers) • 有效标识符举例: shift_reg_a busa_index _bus3 • 无效标识符举例:• 无效标识符举例: 34net // 开头不是字母或“_” a*b_net // 包含了非字母或数字,“$”“_” n@238 //包含了非字母或数字,“$”“_” • Verilog区分大小写,所有Verilog关键词使用小写字母。 操作符 下表以优先级顺序列出了Verilog操作符。 操作符类型 符号 最高 连接及复制操作符 算术操作符 逻辑移位操作符 关系操作符 相等操作符 按位操作符 逻辑操作符 条件操作符 {} {{}} * / % + - << >> > < >= <= = = = = = != != = ~ & | ^ ~^或^~ ! && || ?: 最低 优先级 Verilog中的大小(size)与符号 • Verilog根据表达式中变量的长度对表达式的值自动地进行调整。 • Verilog自动截断或扩展赋值语句中右边的值以适应左边变量的长度。 • 当一个负数赋值给无符号变量如reg时,Verilog自动完成二进制补码计算 module sign_size; reg [3:0] a, b; reg [15:0] c; initial begin a = -1; // a是无符号数,因此其值为1111 b = 8; c= 8; // b = c = 1000 #10 b = b + a; // 结果10111截断, b = 0111 #10 c = c + a; // c = 10111 end endmodule 算术操作符 module arithops (); parameter five = 5; integer ans, int; reg [3: 0] rega, regb; reg [3: 0] num; initial begin rega = 3; regb = 4'b1010; int = -3; //int = 1111… … 1111_1101 + 加 - 减 * 乘 / 除 % 模 integer和reg类型在 算术运算,integer是 有符号数,而reg是 无符号数。 int = -3; //int = 1111… … 1111_1101 end initial fork #10 ans = five * int; // ans = -15 #20 ans = (int + 5)/ 2; // ans = 1 #30 ans = five/ int; // ans = -1 #40 num = rega + regb; // num = 1101 #50 num = rega + 1; // num = 0100 #60 num = int; // num = 1101 #70 num = regb % rega; // num = 1 #80 $finish; join endmodule •将负数赋值给reg或其它无符号变量 使用2的补码算术。 •如果操作数的某一位是x或z,则结 果为x •在整数除法中,余数舍弃 •模运算中使用第一个操作数的符号 按位操作符 module bitwise (); reg [3: 0] rega, regb, regc; reg [3: 0] num; initial begin rega = 4'b1001; regb = 4'b1010; regc = 4'b11x0; end initial fork ~ not & and | or ^ xor ~ ^ xnor ^ ~ xnor •按位操作符对矢量中相对应位运算。 initial fork #10 num = rega & 0; // num = 0000 #20 num = rega & regb; // num = 1000 #30 num = rega | regb; // num = 1011 #40 num = regb & regc; // num = 10x0 #50 num = regb | regc; // num = 1110 #60 $finish; join endmodule •按位操作符对矢量中相对应位运算。 regb = 4'b1 0 1 0 regc = 4'b1 x 1 0 num = regb & regc = 1 0 1 0 ; •位值为x时不一定产生x结果。 当两个操作数位数不同时,位数 少的操作数零扩展到相同位数。 a = 4'b1011; b = 8'b01010011; c = a | b; // a零扩展为 8'b00001011 逻辑操作符 module logical (); parameter five = 5; reg ans; reg [3: 0] rega, regb, regc; initial begin rega = 4‘b0011; //逻辑值为 “1” regb = 4‘b10xz; //逻辑值为“1” ! not && and || or •逻辑操作符的结果为一位1,0或x。 •逻辑操作符只对逻辑值运算。 •如操作数为全0,则其逻辑值为false regb = 4‘b10xz; //逻辑值为“1” regc = 4‘b0z0x; //逻辑值为“x” end initial fork #10 ans = rega && 0; // ans = 0 #20 ans = rega || 0; // ans = 1 #30 ans = rega && five; // ans = 1 #40 ans = regb && rega; // ans = 1 #50 ans = regc || 0; // ans = x #60 $finish; join endmodule •如操作数为全0,则其逻辑值为false •如操作数有一位为1,则其逻辑值为true •若操作数只包含0、x、z,则逻辑值为x 逻辑反操作符将操作数的 逻辑值取反。例如,若操 作数为全0,则其逻辑值为 0,逻辑反操作值为1。 逻辑反与位反的对比 module negation(); reg [3: 0] rega, regb; reg [3: 0] bit; reg log; initial begin rega = 4'b1011; regb = 4'b0000; end initial fork ! logical not 逻辑反 ~ bit-wise not 位反 •逻辑反的结果为一位1,0或x。 •位反的结果与操作数的位数相同 initial fork #10 bit = ~rega; // num = 0100 #20 bit = ~regb; // num = 1111 #30 log = !rega; // num = 0 #40 log = !regb; // num = 1 #50 $finish; join endmodule 逻辑反操作符将操作数的 逻辑值取反。例如,若操 作数为全0,则其逻辑值为 0,逻辑反操作值为1。 移位操作符 module shift (); reg [9: 0] num, num1; reg [7: 0] rega, regb; initial rega = 8'b00001100; initial fork #10 num <= rega << 5 ; // num = 01_1000_0000 #10 regb <= rega << 5 ; // regb = 1000_0000 #20 num <= rega >> 3; // num = 00_0000_0001 #20 regb <= rega >> 3 ; // regb = 0000_0001 #30 num <= 10'b11_1111_0000; >> 逻辑右移 << 逻辑左移 •移位操作符对其左边的操作数进行 向左或向右的位移位操作。 •第二个操作数(移位位数)是无符 号数 左移先补后移 右移先移后补 #30 num <= 10'b11_1111_0000; #40 rega <= num << 2; //rega = 1100_0000 #40 num1 <= num << 2;//num1=11_1100_0000 #50 rega <= num >> 2; //rega = 1111_1100 #50 num1 <= num >> 2;//num1=00_1111_1100 #60 $finish; join endmodule •若第二个操作数是x或z则结果为x 在赋值语句中,如果右边(RHS)的结果: 位宽大于左边,则把最高位截去 位宽小于左边,则零扩展 << 将左边的操作数左移右边 操作数指定的位数 >> 将左边的操作数右移右边 操作数指定的位数 建议:表达式左右位数一致 关系操作符 module relationals (); reg [3: 0] rega, regb, regc; reg val; initial begin rega = 4'b0011; regb = 4'b1010; regc = 4'b0x10; end initial fork > 大于 < 小于 >= 大于等于 <= 小于等于 •其结果是1’b1、1’b0或1’bx。 rega和regc 的关系取决 于xinitial fork #10 val = regc > rega ; // val = x #20 val = regb < rega ; // val = 0 #30 val = regb >= rega ; // val = 1 #40 val = regb > regc ; // val = 1 #50 $finish; join endmodule •其结果是1’b1、1’b0或1’bx。 无论x为何值, regb>regc 于x 相等操作符 赋值操作符,将等式右边表达式的值拷贝到左边。 注意逻辑等与 case等的差别 = 逻辑等= = = = 0 1 x z 0 1 0 x x 1 0 1 x x x x x x x 2‘b1x==2’b0x 值为0,因为不相等 2‘b1x==2’b1x 值为x,因为可能不相 等,也可能相等 a = 2'b1x; b = 2'b1x; if (a == b) $display(" a is equal to b"); elsex x x x x z x x x x case等= = = = = 0 1 x z 0 1 0 0 0 1 0 1 0 0 x 0 0 1 0 z 0 0 0 1 等,也可能相等 2‘b1x===2’b0x 值为0,因为不相同 2‘b1x==2’b1x 值为1,因为相同 else $display(" a is not equal to b"); a = 2'b1x; b = 2'b1x; if (a === b) $display(" a is identical to b"); else $display(" a is not identical to b"); Case等只能用于行为描述,不能用于RTL描述。 相等操作符 逻辑等 逻辑不等 == ! = module equalities1(); reg [3: 0] rega, regb, regc; reg val; initial begin rega = 4'b0011; regb = 4'b1010; regc = 4'b1x10; end initial fork •其结果是1’b1、1’b0或1’bx。 •如果左边及右边为确定值并且 相等,则结果为1。 •如果左边及右边为确定值并且 不相等,则结果为0。 initial fork #10 val = rega == regb ; // val = 0 #20 val = rega != regc; // val = 1 #30 val = regb != regc; // val = x #40 val = regc == regc; // val = x #50 $finish; join endmodule 不相等,则结果为0。 •如果左边及右边有值不能确定 的位,但值确定的位相等,则 结果为x。 •!=的结果与= =相反 值确定是指所有的位 为0或1。不确定值是 有值为x或z的位。 相等操作符 相同(case等) 不相同(case不等) === ! == module equalities2(); reg [3: 0] rega, regb, regc; reg val; initial begin rega = 4'b0011; regb = 4'b1010; regc = 4'b1x10; end initial fork •其结果是1’b1、1’b0或1’bx。 •如果左边及右边的值相同(包 括x、z),则结果为1。 •如果左边及右边的值不相同, 则结果为0。 initial fork #10 val = rega === regb ; // val = 0 #20 val = rega !== regc; // val = 1 #30 val = regb === regc; // val = 0 #40 val = regc === regc; // val = 1 #50 $finish; join endmodule 则结果为0。 •!==的结果与 === 相反 综合工具不支持 条件操作符 条件?: module likebufif( in, en, out); input in; input en; output out; assign out = (en == 1) ? in : 'bz; endmodule module like4to1( a, b, c, d, sel, out); input a, b, c, d; input [1: 0] sel; output out; assign out = sel == 2'b00 ? a : sel == 2'b01 ? b : sel == 2'b10 ? c : d; endmodule 如果条件值为x或z,则结果可能为x或z 条件操作符 条件操作符的语法为: = ? : 其意思是:if condition is TRUE, then LHS=true_expression, else LHS = false_expression 每个条件操作符必须有三个参数,缺少任何一个都会产生错误。 最后一个操作数作为缺省值。 registger = condition ? true_value:false_value; 上式中,若condition为真则register等于true_value;若condition为假则register等 于false_value。一个很有意思的地方是,如果条件值不确定,且true_value和 false_value不相等,则输出不确定值。 例如:assign out = (sel == 0) ? a : b; 若sel为0则out =a;若sel为1则out = b。如果sel为x或z,若a = b =0,则out = 0;若 a≠ b,则out值不确定。 级联操作符 级联{} 可以从不同的矢量中选择位并 用它们组成一个新的矢量。 用于位的重组和矢量构造 module concatenation; reg [7: 0] rega, regb, regc, regd; reg [7: 0] new; initial begin rega = 8'b0000_0011; regb = 8'b0000_0100; regc = 8'b0001_1000;在级联和复制时,必须指定位 数,否则将产生错误。 regd = 8'b1110_0000; end initial fork #10 new = {regc[ 4: 3], regd[ 7: 5], regb[ 2], rega[ 1: 0]}; // new = 8'b11111111 #20 $finish; join endmodule 数,否则将产生错误。 下面是类似错误的例子: a[7:0] = {4{ ´b10}}; b[7:0] = {2{ 5}}; c[3:0] = {3´b011, ´b0}; 级联时不限定操作数的数目。 在操作符符号{}中,用逗号将 操作数分开。例如: {A, B, C, D} 复制 复制{ {} } 复制一个变量或在{}中的值 module replicate (); reg [3: 0] rega; reg [1: 0] regb, regc; reg [7: 0] bus; initial begin rega = 4’b1001; regb = 2'b11; regc = 2'b00; end initial fork 前两个{ 符号之间的正整数指定 复制次数。 initial fork #10 bus <= {4{ regb}}; // bus = 11111111 // regb is replicated 4 times. #20 bus <= { {2{ regb}}, {2{ regc}} }; // bus = 11110000. regc and regb are each // replicated, and the resulting vectors // are concatenated together #30 bus <= { {4{ rega[1]}}, rega }; // bus = 00001001. rega is sign-extended #40 $finish; join endmodule 复制次数。 第三章 Verilog的逻辑系统及数据类型 – 学习Verilog逻辑值系统 – 学习Verilog中不同类的数据类型 – 理解每种数据类型的用途及用法 – 数据类型说明的语法 学习内容: – 数据类型说明的语法 Verilog采用的四值逻辑系统 ’0’, Low, False, Logic Low, Ground,VSS, Negative Assertion ‘1’, High, True, Logic High, Power, VDD, VCC, Positive AssertionVDD, VCC, Positive Assertion ’X’ Unknown: Occurs at Logical Which Cannot be Resolved Conflict HiZ, High Impedance, Tri- Stated, Disabled Driver (Unknown) 主要数据类型 Verilog主要有三类(class)数据类型: • net (线网): 表示器件之间的物理连接 • register (寄存器):表示抽象存储元件 • parameters(参数): 运行时的常数(run-time constants) net(线网) net需要被持续的驱动,驱动它的可以是门和模块。 当net驱动器的值发生变化时, Verilog自动的将新值传送到 net上。在例子中,线网out由or门驱动。当or门的输入信号置位时将传 输到线网net上。 net类的类型(线网) • 有多种net类型用于设计(design-specific)建模和工艺 (technology-specific)建模 net类型 功 能 wire, tri supply1, supply0 wor, trior 标准内部连接线(缺省) 电源和地 多驱动源线或综合编译 • 没有声明的net的缺省类型为 1 位(标量)wire类型。 wor, trior wand, triand trireg tri1, tri0 多驱动源线或 多驱动源线与 能保存电荷的net 无驱动时上拉/下拉 综合编译 器不支持 的net类型 net类的类型(线网) • 常用于组合电路描述。 • wire类型是最常用的类型,只有连接功能。 • wire和tri类型有相同的功能。用户可根据需要将线网定义为wire或tri以 提高可读性。tri型的信号综合后具有三态的功能。 • wand、wor有线逻辑功能。 • trireg类型很象wire类型,但trireg类型在没有驱动时保持以前的值。这 个值的强度随时间减弱。 • 修改net缺省类型的编译指导: `default_nettype nettype不能是supply1和supply0。 寄存器类 (register) • 寄存器类型在赋新值以前保持原值 • 寄存器类型大量应用于行为模型描述及激励描述。在下面的例子 中,reg_a、reg_b、reg_sel用于施加激励给2:1多路器。 • 用行为描述结构给寄存器类型赋值。给reg类型赋值是在过程块 中。 寄存器类的类型 • 寄存器类有四种数据类型 寄存器类型 功能 reg 可定义的无符号整数变量,可以是标量(1位)或矢量,是 最常用的寄存器类型 integer 32位有符号整数变量,算术操作产生二进制补码形式的integer 32位有符号整数变量,算术操作产生二进制补码形式的 结果。通常用作不会由硬件实现的的数据处理。 real 双精度的带符号浮点变量,用法与integer相同。 time 64位无符号整数变量,用于仿真时间的保存与处理 realtime 与real内容一致,但可以用作实数仿真时间的保存与 处理 Verilog中net和register声明语法 •net声明 [range] [delay] [, net_name]; net_type: net类型 range: 矢量范围,以[MSB:LSB]格式 delay: 定义与net相关的延时 net_name: net名称,一次可定义多个net, 用逗号分开。 •寄存器声明 [range] [, reg_name]; reg_type:寄存器类型 range: 矢量范围,以[MSB:LSB]格式。只对reg类型有效 reg_name :寄存器名称,一次可定义多个寄存器,用逗号分开 Verilog中net和register声明语法 • 举例: reg a; //一个标量寄存器 wand w; // 一个标量wand类型net reg [3: 0] v; // 从MSB到LSB的4位寄存器向量 reg [7: 0] m, n; // 两个8位寄存器reg [7: 0] m, n; // 8 tri [15: 0] busa; // 16位三态总线 wire [0: 31] w1, w2; // 两个32位wire,MSB为bit0 选择正确的数据类型 输入端口可以由 net/register驱动,但 输入端口只能是net 输出端口可以是 net/register类型,输 出端口只能驱动net in 1in 2 O A B Y 双向端口输入/输出 只能是net类型 module top; wire y; reg a, b; DUT u1 (y, a, b) ; initial begin a = 0; b = 0; #5 a = 1; end endmodule module DUT (Y, A, B); output Y; input A, B; wire Y, A, B; and (Y, A, B) ; endmodule 在过程块中只 能给register 类型赋值 若Y,A,B说 明为reg则会 产生错误。 选择数据类型时常犯的错误 • 信号可以分为端口信号和内部信号。出现在端口列表中的信号是端口信号,其它的信 号为内部信号。 • 对于端口信号,输入端口只能是net类型。输出端口可以是net类型,也可以是register 类型。若输出端口在过程块中赋值则为register类型;若在过程块外赋值(包括实例化语 句),则为net类型。 • 内部信号类型与输出端口相同,可以是net或register类型。判断方法也与输出端口相同。 若在过程块中赋值,则为register类型;若在过程块外赋值,则为net类型。 信号类型确定方法总结如下: • 用过程语句给一个net类型的或忘记声明类型的信号赋值。 信息:illegal … … assignment. • 将实例的输出连接到声明为register类型的信号上。 信息: has illegal output port specification. • 将模块的输入信号声明为register类型。 信息:incompatible declaration, … … 下面所列是常出的错误及相应的错误信息(error message) 选择数据类型时常犯的错误举例 修改前: module example(o1, o2, a, b, c, d); input a, b, c, d; output o1, o2; 修改后: module example(o1, o2, a, b, c, d); input a, b, c, d; output o1, o2; // reg c, d; example.v output o1, o2; reg c, d; reg o2 and u1(o2, c, d); always @(a or b) if (a) o1 = b; else o1 = 0; endmodule // reg c, d; // reg o2 reg o1; and u1(o2, c, d); always @(a or b) if (a) o1 = b; else o1 = 0; endmodule 选择数据类型时常犯的错误举例 第一次编译信 息 verilog –c example.v Compiling source file "example.v" Error! Incompatible declaration, (c) defined as input at line 2 [Verilog-IDDIL] "example.v", 5: Error! Incompatible declaration, (d) defined as input at line 2 [Verilog-IDDIL] "example.v", 5: Error! Gate (u1) has illegal output specification [Verilog-GHIOS] Compiling source file "example.v" Error! Illegal left-hand-side assignment [Verilog-ILHSA] "example.v", 11: o1 = b; Error! Illegal left-hand-side assignment [Verilog-ILHSA] "example.v", 12: o1 = 0; 2 errors 第二次编译信 息 Error! Gate (u1) has illegal output specification [Verilog-GHIOS] "example.v", 8: 3 errors 参数(parameters) • 用参数声明一个可变常量,常用于定义延时及宽度变量。 • 参数定义的语法:parameter ; • 可一次定义多个参数,用逗号隔开。 • 在使用文字(literal)的地方都可以使用参数。 • 参数的定义是局部的,只在当前模块中有效。 • 参数定义可使用以前定义的整数和实数参数。 module mod1( out, in1, in2); ... parameter cycle = 20, prop_ del = 3, setup = cycle/2 - prop_del, p1 = 8, x_ word = 16’bx, ... wire [p1: 0] w1; // A wire declaration using parameter ... endmodule 参数重载(overriding) module mod1( out, in1, in2); ... parameter p1 = 8, real_constant = 2.039, x_word = 16’bx, file = "/usr1/jdough/design/mem_file.dat"; ... 模块实例化时参数重载 不需要给所有参数赋 新值,但不能跳跃赋 值 因为#说明延时的时候只能 用于gate或过程语句,不能 用于模块实例。 gate(primitives)在实例化时 只能有延时,不能有模块... endmodule module top; ... mod1 #( 5, 3.0, 16’bx, "../ my_mem. dat") I1( out, in1, in2); ... endmodule 使用# 次序与原 说明相同 为什么编译器 认为这是参数 而不是延时呢? 只能有延时,不能有模块 参数。 寄存器数组(Register Arrays) • 在Verilog中可以说明一个寄存器数组。 integer NUMS [7: 0]; // 包含8个整数数组变量 time t_vals [3: 0]; // 4个时间数组变量 • reg类型的数组通常用于描述存储器 其语法为: reg [MSB:LSB] [first_addr:last_addr]; [MSB:LSB]定义存储器字的位数[MSB:LSB]定义存储器字的位数 [first_addr:last_addr]定义存储器的深度 例如: reg [15: 0] MEM [0:1023]; // 1K x 16存储器 reg [7: 0] PREP [‘hFFFE: ’hFFFF]; // 2 x 8存储器 • 描述存储器时可以使用参数或任何合法表达式 parameter wordsize = 16; parameter memsize = 1024; reg [wordsize-1: 0] MEM3 [memsize-1: 0];
还剩49页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

a134234

贡献于2017-03-22

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf