分类 FPGA&ASIC 下的文章 - 我的学记|刘航宇的博客
首页
📊归档
⏳时光机
📬留言
🐾友链
资助名单
推荐
🎓843课程班
🎵音乐
🏞️壁纸
搜 索
1
【NPN/PNP三极管】放大电路饱和失真和截止失真的区别
12,710 阅读
2
论文写作中如何把word里面所有数字和字母替换为新罗马字体
7,155 阅读
3
【高数】形心计算公式讲解大全
6,638 阅读
4
【1】基于STM32CubeMX-STM32GPIO端口开发
5,149 阅读
5
如何判断运放是工作在线性区还是非线性区
4,994 阅读
🌻微语&随笔
励志美文
我的随笔
写作办公
📖电子&通信
嵌入式&系统
通信&信息处理
编程&脚本笔记
🗜️IC&系统
FPGA&ASIC
VLSI&IC验证
EDA&虚拟机
💻电子&计算机
IP&SOC设计
机器学习
软硬件算法
登录
搜 索
标签搜索
嵌入式
ASIC/FPGA
VLSI
SOC设计
机器学习
天线设计
C/C++
EDA&虚拟机
软件算法
小实验
信号处理
电子线路
通信&射频
随笔
笔试面试
硬件算法
Verilog
软件无线电
Python
DL/ML
刘航宇
嵌入式系统&数字IC爱好者博客
累计撰写
302
篇文章
累计收到
527
条评论
首页
栏目
🌻微语&随笔
励志美文
我的随笔
写作办公
📖电子&通信
嵌入式&系统
通信&信息处理
编程&脚本笔记
🗜️IC&系统
FPGA&ASIC
VLSI&IC验证
EDA&虚拟机
💻电子&计算机
IP&SOC设计
机器学习
软硬件算法
页面
📊归档
⏳时光机
📬留言
🐾友链
资助名单
推荐
🎓843课程班
🎵音乐
🏞️壁纸
用户登录
登录
FPGA&ASIC(共56篇)
找到
56
篇与
FPGA&ASIC
相关的结果
2022-05-21
【2】Verilog练习-补码转化与7段译码逻辑设计
补码转化程序//补码转化逻辑 `timescale 1ns/10ps module comp_conv( a, a_comp ); input[7:0] a; output[7:0] a_comp; //wire[6:0] b;//按位取反的幅度位 //wire[7:0] y;//负数的补码; //assign b=~a[6:0]; //assign y[6:0]=b+1;//按位取反+1 //assign y[6:0]=~a[6:0]+1;//按位取反+1 //assign y[7]=a[7];//符号位不变 //assign y=; //assign a_comp=a[7]?y:a;//二选一 assign a_comp=a[7]?:a;//二选一 endmodule //----testbench of comp_conv--- module comp_conv_tb; reg[7:0] a_in; wire[7:0] y_out; comp_conv comp_conv( .a(a_in), .a_comp(y_out) ); initial begin a_in<=0; #3000 $stop; end always #10 a_in<=a_in+1; endmodule现象7段译码逻辑设计代码://七段码译码器 `timescale 1ns/10ps module seg_dec( num, a_g ); input[3:0] num; output[6:0] a_g;//a_g--> reg[6:0] a_g; always@(num)begin case(num) 4'd0: begin a_g<=7'b111_1110; end 4'd1: begin a_g<=7'b011_0000; end 4'd2: begin a_g<=7'b110_1101; end 4'd3: begin a_g<=7'b111_1100; end 4'd4: begin a_g<=7'b011_0011; end 4'd5: begin a_g<=7'b101_1011; end 4'd6: begin a_g<=7'b101_1111; end 4'd7: begin a_g<=7'b111_0000; end 4'd8: begin a_g<=7'b111_1111; end 4'd9: begin a_g<=7'b111_1011; end default: begin a_g<=7'b000_0001; end//中杠 endcase end endmodule //----testbench of seg_dec--- module seg_dec_tb; reg[3:0] num_in; wire[6:0] a_g_out; seg_dec seg_dec( .num(num_in), .a_g(a_g_out) ); initial begin num_in<=0; #200 $stop; end always #10 num_in<=num_in+1; endmodule现象
2022年05月21日
382 阅读
0 评论
3 点赞
2022-05-17
【2】Verilog练习-组合逻辑电路多路选择器
二选一逻辑设计程序//二选一逻辑设计 `timescale 1ns/10ps module fn_sw( a, b, sel, y ); input a; input b; input sel; output y; //assign y=sel?(a^b):(a&b); //用always语句块实现组合逻辑; reg y; always@(a or b or sel) if(sel==1)begin y<=a^b; end else begin y<=a&b; end endmodule //---testbench of fn_sw---- module fn_sw_tb; reg a,b,sel;//输入reg型 wire y;//输出wire型 fn_sw fn_sw( .a(a), .b(b), .sel(sel), .y(y) ); initial begin a<=0;b<=0;sel<=0; #10 a<=0;b<=0;sel<=1; #10 a<=0;b<=1;sel<=0; #10 a<=1;b<=0;sel<=0; #10 a<=1;b<=0;sel<=1; #10 a<=1;b<=1;sel<=0; #10 a<=1;b<=1;sel<=1; #10 $stop; end endmodule现象多路选择逻辑设计代码//四选一逻辑设计 `timescale 1ns/10ps module fn_sw_4( a, b, sel, y ); input a; input b; input[1:0] sel; output y; reg y; always@(a or b or sel)begin case(sel) 2'b00:begin y<=a&b;end 2'b01:begin y<=a|b;end 2'b10:begin y<=a^b;end 2'b11:begin y<=~(a^b);end endcase end endmodule //-----testbench of fn_sw_4-- module fn_sw_4_tb; reg[3:0] absel; wire y; fn_sw_4 fn_sw_4( .a(absel[0]), .b(absel[1]), .sel(absel[3:2]), .y(y) ); initial begin absel<=0; #300 $stop; end always #10 absel<=absel+1; endmodule现象
2022年05月17日
372 阅读
0 评论
2 点赞
2022-05-16
【4】Verilog-基础语法2
表达式表达式由操作符和操作数构成,其目的是根据操作符的意义得到一个计算结果。表达式可以在出现数值的任何地方使用。例如:a^b ; //a与b进行异或操作 address[9:0] + 10'b1 ; //地址累加 flag1 && flag2 ; //逻辑与操作操作数 操作数可以是任意的数据类型,只是某些特定的语法结构要求使用特定类型的操作数。操作数可以为常数,整数,实数,线网,寄存器,时间,位选,域选,存储器及函数调用等。module test; //实数 real a, b, c; c = a + b ; //寄存器 reg [3:0] cprmu_1, cprmu_2 ; always @(posedge clk) begin cprmu_2 = cprmu_1 ^ cprmu_2 ; end //函数 reg flag1 ; flag = calculate_result(A, B); //非法操作数 reg [3:0] res; wire [3:0] temp; always@ (*)begin res = cprmu_2 – cprmu_1 ; //temp = cprmu_2 – cprmu_1 ; //不合法,always块里赋值对象不能是wire型 end endmodule操作符 Verilog 中提供了大约 9 种操作符,分别是算术、关系、等价、逻辑、按位、归约、移位、拼接、条件操作符。大部分操作符与 C 语言中类似。同类型操作符之间,除条件操作符从右往左关联,其余操作符都是自左向右关联。圆括号内表达式优先执行。例如下面每组的 2 种写法都是等价的。不同操作符之间,优先级是不同的。下表列出了操作符优先级从高至低的排列顺序。当没有圆括号时,Verilog 会根据操作符优先级对表达式进行计算。为了避免由操作符优先级导致的计算混乱,在不确定优先级时,建议用圆括号将表达式区分开来。 算术操作符 算术操作符包括单目操作符和双目操作符。双目操作符对 2 个操作数进行算术运算,包括乘()、除(/)、加(+)、减(-)、求幂(*)、取模(%)。reg [3:0] a, b; reg [4:0] c ; a = 4'b0010 ; b = 4'b1001 ; c = a+b; //结果为c=b'b1011 c = a/b; //结果为c=4,取整如果操作数某一位为 X,则计算结果也会全部出现 X。例如:b = 4'b100x ; c = a+b ; //结果为c=4'bxxxx对变量进行声明时,要根据变量的操作符对变量的位宽进行合理声明,不要让结果溢出。上述例子中,相加的 2 个变量位宽为 4bit,那么结果寄存器变量位宽最少为 5bit。否则,高位将被截断,导致结果高位丢失。无符号数乘法时,结果变量位宽应该为 2 个操作数位宽之和。reg [3:0] mula ; reg [1:0] mulb; reg [5:0] res ; mula = 4'he ; mulb = 2'h3 ; res = mula * mulb ; //结果为res=6'h2a, 数据结果没有丢失位数和 - 也可以作为单目操作符来使用,表示操作数的正负性。此类操作符优先级最高。-4 //表示负4+3 //表示正3负数表示时,可以直接在十进制数字前面增加一个减号 -,也可以指定位宽。因为负数使用二进制补码来表示,不指定位宽来表示负数,编译器在转换时,会自动分配位宽,从而导致意想不到的结果。例如:mula = -4'd4 ; mulb = 2 ; res = mula * mulb ; //计算结果为res=-6'd8, 即res=6'h38,正常 res = mula * (-'d4) ; //(4的32次幂-4) * 2, 结果异常关系操作符 关系操作符有大于(>),小于(<),大于等于(>=),小于等于(<=)。关系操作符的正常结果有 2 种,真(1)或假(0)。如果操作数中有一位为 x 或 z,则关系表达式的结果为 x。A = 4 ; B = 3 ; X = 3'b1xx ; A > B //为真 A <= B //为假 A >= Z //为X,不确定等价操作符 等价操作符包括逻辑相等(==),逻辑不等(!=),全等(===),非全等(!==)。等价操作符的正常结果有 2 种:为真(1)或假(0)。逻辑相等/不等操作符不能比较 x 或 z,当操作数包含一个 x 或 z,则结果为不确定值。全等比较时,如果按位比较有相同的 x 或 z,返回结果也可以为 1,即全等比较可比较 x 或 z。所以,全等比较的结果一定不包含 x。举例如下:A = 4 ; B = 8'h04 ; C = 4'bxxxx ; D = 4'hx ; A == B //为真 A == (B + 1) //为假 A == C //为X,不确定 A === C //为假,返回值为0 C === D //为真,返回值为1逻辑操作符 逻辑操作符主要有 3 个:&&(逻辑与), ||(逻辑或),!(逻辑非)。逻辑操作符的计算结果是一个 1bit 的值,0 表示假,1 表示真,x 表示不确定。如果一个操作数不为 0,它等价于逻辑 1;如果一个操作数等于 0,它等价于逻辑 0。如果它任意一位为 x 或 z,它等价于 x。如果任意一个操作数包含 x,逻辑操作符运算结果不一定为 x。逻辑操作符的操作数可以为变量,也可以为表达式。例如:A = 3; B = 0; C = 2'b1x ; A && B // 为假 A || B // 为真 ! A // 为假 ! B // 为真 A && C // 为X,不确定 A || C // 为真,因为A为真 (A==2) && (! B) //为真,此时第一个操作数为表达式按位操作符 按位操作符包括:取反(~),与(&),或(|),异或(^),同或(~^)。按位操作符对 2 个操作数的每 1bit 数据进行按位操作。如果 2 个操作数位宽不相等,则用 0 向左扩展补充较短的操作数。取反操作符只有一个操作数,它对操作数的每 1bit 数据进行取反操作。下图给出了按位操作符的逻辑规则。A = 4'b0101 ; B = 4'b1001 ; C = 4'bx010 ; ~A //4'b1010 A & B //4'b0001 A | B //4'b1101 A^B //4'b1100 A ~^ B //4'b0011 B | C //4'b1011 B&C //4'bx000移位操作符 移位操作符包括左移(<<),右移(>>),算术左移(<<<),算术右移(>>>)。移位操作符是双目操作符,两个操作数分别表示要进行移位的向量信号(操作符左侧)与移动的位数(操作符右侧)。算术左移和逻辑左移时,右边低位会补 0。逻辑右移时,左边高位会补 0;而算术右移时,左边高位会补充符号位,以保证数据缩小后值的正确性。A = 4'b1100 ; B = 4'b0010 ; A = A >> 2 ; //结果为 4'b0011 A = A << 1; //结果为 4'b1000 A = A <<< 1 ; //结果为 4'b1000 C = B + (A>>>2); //结果为 2 + (-4/4) = 1, 4'b0001拼接操作符 拼接操作符用大括号 来表示,用于将多个操作数(向量)拼接成新的操作数(向量),信号间用逗号隔开。拼接符操作数必须指定位宽,常数的话也需要指定位宽。例如:A = 4'b1010 ; B = 1'b1 ; Y1 = ; //结果为Y1='b1100_0011 Y2 = , 3'd4}; //结果为 Y2=7'b111_1100 Y3 = }; //结果为 Y3=32h0,常用作寄存器初始化时匹配位宽的赋初值条件操作符条件表达式有 3 个操作符,结构描述如下:condition_expression ? true_expression : false_expression计算时,如果 condition_expression 为真(逻辑值为 1),则运算结果为 true_expression;如果 condition_expression 为假(逻辑值为 0),则计算结果为 false_expression。assign hsel = (addr[9:8] == 2'b0) ? hsel_p1 : hsel_p2 ;//当信号 addr 高 2bit 为 0 时,hsel 赋值为 hsel_p1; 否则,将 hsel_p2 赋值给 hsel。其实,条件表达式类似于 2 路(或多路)选择器,其描述方式完全可以用 if-else 语句代替。当然条件操作符也能进行嵌套,完成一个多次选择的逻辑。例如assign hsel = (addr[9:8] == 2'b00) ? hsel_p1 : (addr[9:8] == 2'b01) ? hsel_p2 : (addr[9:8] == 2'b10) ? hsel_p3 : (addr[9:8] == 2'b11) ? hsel_p4 ;Verilog 编译指令以反引号 ` 开始的某些标识符是 Verilog 系统编译指令。编译指令为 Verilog 代码的撰写、编译、调试等提供了极大的便利。下面介绍下完整的 8 种编译指令,其中前 4 种使用频率较高。`define`undef在编译阶段,`define 用于文本替换,类似于 C 语言中的 #define。一旦 `define 指令被编译,其在整个编译过程中都会有效。例如,在一个文件中定义: `define DATA_DW 32 则在另一个文件中也可以直接使用 DATA_DW`define S $stop; //用`S来代替系统函数$stop; (包括分号) `define WORD_DEF reg [31:0] //可以用`WORD_DEF来声明32bit寄存器变量`undef 用来取消之前的宏定义,例如`define DATA_DW 32 …… reg [DATA_DW-1:0] data_in ; …… `undef DATA_DW `ifdef, `ifndef, `elsif, `else, `endif`ifdef MCU51 parameter DATA_DW = 8 ; `elsif WINDOW parameter DATA_DW = 64 ; `else parameter DATA_DW = 32 ; `endif当然,也可用 `ifndef 来设置条件编译,表示如果没有相关的宏定义,则执行相关语句。下面例子中,如果定义了 WINDOW,则使用第二种参数说明。如果没有定义 WINDOW,则使用第一种参数说明。`ifndef WINDOW parameter DATA_DW = 32 ; `else parameter DATA_DW = 64 ; `endif`include 使用 `include 可以在编译时将一个 Verilog 文件内嵌到另一个 Verilog 文件中,作用类似于 C 语言中的 #include 结构。该指令通常用于将全局或公用的头文件包含在设计文件里。文件路径既可以使用相对路径,也可以使用绝对路径。`include "../../param.v" `include "header.v"`timescale 在 Verilog 模型中,时延有具体的单位时间表述,并用 `timescale 编译指令将时间单位与实际时间相关联。该指令用于定义时延、仿真的单位和精度,格式为:`timescale time_unit / time_precisiontime_unit 表示时间单位,time_precision 表示时间精度,它们均是由数字以及单位 s(秒),ms(毫秒),us(微妙),ns(纳秒),ps(皮秒)和 fs(飞秒)组成。时间精度可以和时间单位一样,但是时间精度大小不能超过时间单位大小,例如下面例子中,输出端 Z 会延迟 5.21ns 输出 A&B 的结果。`timescale 1ns/100ps //时间单位为1ns,精度为100ps,合法 //`timescale 100ps/1ns //不合法 module AndFunc(Z, A, B); output Z; input A, B ; assign #5.207 Z = A & B endmodule`timescale 10ns/1ns module test; reg A, B ; wire OUTZ ; initial begin A = 1; B = 0; # 1.28 B = 1; # 3.1 A = 0; end AndFunc u_and(OUTZ, A, B) ; endmodule在模块 AndFunc 中,5.207 对应 5.21ns。在模块 test 中,1.28 对应 13ns,3.1 对应 31ns。但是,当仿真 test 时,由于 AndFunc 中的最小精度为 100ps,因此 test 中的时延精度将进行重新调整。13ns 将对应 130100ps,31ns 将对应 310100ps。仿真时,时延精度也会使用 100ps。仿真时间单位大小没有影响。如果有并行子模块,子模块间的 `timescale 并不会相互影响。例如在模块 test 中再例化一个子模块 OrFunc。仿真 test 时,OrFunc 中的 #5.207 延时依然对应 52ns。//子模块: `timescale 10ns/1ns //时间单位为1ns,精度为100ps,合法 module OrFunc(Z, A, B); output Z; input A, B ; assign #5.207 Z = A | B endmodule //顶层模块: `timescale 10ns/1ns module test; reg A, B ; wire OUTZ ; wire OUTX ; initial begin A = 1; B = 0; # 1.28 B = 1; # 3.1 A = 0; end AndFunc u_and(OUTZ, A, B) ; OrFunc u_and(OUTX, A, B) ; endmodule此例中,仿真 test 时,OrFunc 中的 #5.207 延时依然对应 52ns。`timescale 的时间精度设置是会影响仿真时间的。时间精度越小,仿真时占用内存越多,实际使用的仿真时间就越长。所以如果没有必要,应尽量将时间精度设置的大一些。 `default_nettype 该指令用于为隐式的线网变量指定为线网类型,即将没有被声明的连线定义为线网类型。`default_nettype wand该实例定义的缺省的线网为线与类型。因此,如果在此指令后面的任何模块中的连线没有说明,那么该线网被假定为线与类型。`default_nettype none该实例定义后,将不再自动产生 wire 型变量。例如下面第一种写法编译时不会报 Error,第二种写法编译将不会通过。//Z1 无定义就使用,系统默认Z1为wire型变量,有 Warning 无 Error module test_and( input A, input B, output Z); assign Z1 = A & B ; endmodule//Z1无定义就使用,由于编译指令的存在,系统会报Error,从而检查出书写错误 `default_nettype none module test_and( input A, input B, output Z); assign Z1 = A & B ; endmodule`celldefine module ( input clk, input rst, output clk_pll, output flag); …… endmodule `endcelldefine
2022年05月16日
681 阅读
0 评论
1 点赞
【1】Verilog练习-基本门电路反相器&与非门
反相器//反相器设计 `timescale 1ns/10ps //1ns时间单位,10ps精度 module inv( A, Y ); input A; output Y; assign Y=~A; endmodule //---testbench of inv-- module inv_tb; //testbench无端口不写括号 reg aa; //输入 wire yy; //输出 inv inv( .A(aa), .Y(yy) ); //异名例化 initial begin aa<=0; #10 aa<=1; //过10个时间单位timescale #10 aa<=0; #10 aa<=1; #10 $stop; end endmodule现象:多位反相器与非门代码//与非门 `timescale 1ns/10ps module nand_gate( A, B, Y ); input A; input B; output Y; assign Y=~(A&B); endmodule //------testbench of nand_gate-- module nand_gate_tb; reg aa,bb; //输入定义为reg wire yy; nand_gate nand_gate( .A(aa), .B(bb), .Y(yy) ); initial begin aa<=0;bb<=0; //用箭头等号对应实际电路 #10 aa<=1;bb<=1; #10 aa<=0;bb<=1; #10 aa<=1;bb<=0; #10 aa<=0;bb<=0; #10 $stop; end endmodule现象多位与非门代码//与非门 `timescale 1ns/10ps module nand_gate_4bits( A, B, Y ); input[3:0] A; input[3:0] B; output[3:0] Y; assign Y=~(A&B); endmodule //------testbench of nand_gate-- module nand_gate_4bits_tb; reg[3:0] aa,bb; //输入定义为reg wire[3:0] yy; nand_gate_4bits nand_gate_4bits( .A(aa), .B(bb), .Y(yy) ); initial begin aa<=4'b0000;bb<=4'b1111; //用箭头等号对应实际电路 #10 aa<=4'b1110;bb<=4'b0011; #10 aa<=4'b0110;bb<=4'b0111; #10 aa<=4'b0111;bb<=4'b1110; #10 aa<=4'b1101;bb<=4'b1111; #10 $stop; end endmodule
2022年05月15日
424 阅读
0 评论
2 点赞
2022-05-14
【3】Verilog-基础语法1
标识符与关键字标识符(identifier)可以是任意一组字母、数字、$ 符号和 _(下划线)符号的合,但标识符的第一个字符必须是字母或者下划线,不能以数字或者美元符开始。另外,标识符是区分大小写的。关键字是 Verilog 中预留的用于定义语言结构的特殊标识符。Verilog 中关键字全部为小写。reg [3:0] counter ; //reg 为关键字, counter 为标识符 input clk; //input 为关键字,clk 为标识符 input CLK; //CLK 与 clk是 2 个不同的标识符数值种类Verilog HDL 有下列四种基本的值来表示硬件电路中的电平逻辑:0:逻辑 0 或 "假"1:逻辑 1 或 "真"x 或 X:未知z 或 Z:高阻x 意味着信号数值的不确定,即在实际电路里,信号可能为 1,也可能为 0。z 意味着信号处于高阻状态,常见于信号(input, reg)没有驱动时的逻辑结果。例如一个 pad 的 input 呈现高阻状态时,其逻辑值和上下拉的状态有关系。上拉则逻辑值为 1,下拉则为 0 。整数数值表示方法 数字声明时,合法的基数格式有 4 中,包括:十进制('d 或 'D),十六进制('h 或 'H),二进制('b 或 'B),八进制('o 或 'O)。数值可指明位宽,也可不指明位宽。指明位宽4'b1011 // 4bit 数值 32'h3022_c0de // 32bit 的数值其中,下划线 _ 是为了增强代码的可读性。不指明位宽 一般直接写数字时,默认为十进制表示,例如下面的 3 种写法是等效的:counter = 'd100 ; //一般会根据编译器自动分频位宽,常见的为32bit counter = 100 ; counter = 32'h64 ;负数表示 通常在表示位宽的数字前面加一个减号来表示负数。例如-6'd15 -15-15 在 5 位二进制中的形式为 5'b10001, 在 6 位二进制中的形式为 6'b11_0001。需要注意的是,减号放在基数和数字之间是非法的,例如下面的表示方法是错误的:4'd-2 //非法说明实数表示方法实数表示方法主要有两种方式: 十进制 30.1236.03.00.001 科学计数法 1.2e4 //大小为120001_0001e4 //大小为1000100001E-3 //大小为0.001字符串表示方法字符串是由双引号包起来的字符队列。字符串不能多行书写,即字符串中不能包含回车符。Verilog 将字符串当做一系列的单字节 ASCII 字符队列。例如,为存储字符串 "ee.ac.cn", 需要 14*8bit 的存储单元。例如:reg [0: 14*8-1] str ; initial begin str = "ee.ac.cn"; end Verilog 数据类型Verilog 最常用的 2 种数据类型就是线网(wire)与寄存器(reg),其余类型可以理解为这两种数据类型的扩展或辅助。 线网(wire) wire 类型表示硬件单元之间的物理连线,由其连接的器件输出端连续驱动。如果没有驱动元件连接到 wire 型变量,缺省值一般为 "Z"。举例如下:wire interrupt ; wire flag1, flag2 ; wire gnd = 1'b0 ;线网型还有其他数据类型,包括 wand,wor,wri,triand,trior,trireg 等。这些数据类型用的频率不是很高,这里不做介绍。寄存器(reg) 寄存器(reg)用来表示存储单元,它会保持数据原有的值,直到被改写。声明举例如下:reg clk_temp; reg flag1, flag2 ;例如在 always 块中,寄存器可能被综合成边沿触发器,在组合逻辑中可能被综合成 wire 型变量。寄存器不需要驱动源,也不一定需要时钟信号。在仿真时,寄存器的值可在任意时刻通过赋值操作进行改写。例如:reg rstn ; initial begin rstn = 1'b0 ; #100 ; //延时 rstn = 1'b1 ; end向量 当位宽大于 1 时,wire 或 reg 即可声明为向量的形式。例如:reg [3:0] counter ; //声明4bit位宽的寄存器counter wire [32-1:0] gpio_data; //声明32bit位宽的线型变量gpio_data wire [8:2] addr ; //声明7bit位宽的线型变量addr,位宽范围为8:2 reg [0:31] data ; //声明32bit位宽的寄存器变量data, 最高有效位为0对于上面的向量,我们可以指定某一位或若干相邻位,作为其他逻辑使用。例如:wire [9:0] data_low = data[0:9] ; addr_temp[3:2] = addr[8:7] + 1'b1 ;Verilog 支持可变的向量域选择,例如:reg [31:0] data1 ; reg [7:0] byte1 [3:0]; integer j ; always@* begin for (j=0; j<=3;j=j+1) begin byte1[j] = data1[(j+1)*8-1 : j*8]; //把data1[7:0]…data1[31:24]依次赋值给byte1[0][7:0]…byte[3][7:0] end endVerillog 还支持指定 bit 位后固定位宽的向量域选择访问。[bit+: width] : 从起始 bit 位开始递增,位宽为 width。[bit-: width] : 从起始 bit 位开始递减,位宽为 width。//下面 2 种赋值是等效的 A = data1[31-: 8] ; A = data1[31:24] ; //下面 2 种赋值是等效的 B = data1[0+ : 8] ; B = data1[0:7] ;对信号重新进行组合成新的向量时,需要借助大括号。例如:wire [31:0] temp1, temp2 ; assign temp1 = ; //数据拼接 assign temp2 = }; //赋值32位的数值0 整数,实数,时间寄存器变量 整数,实数,时间等数据类型实际也属于寄存器类型。整数(integer)整数类型用关键字 integer 来声明。声明时不用指明位宽,位宽和编译器有关,一般为32 bit。reg 型变量为无符号数,而 integer 型变量为有符号数。例如:reg [31:0] data1 ; reg [3:0] byte1 [7:0]; //数组变量,后续介绍 integer j ; //整型变量,用来辅助生成数字电路 always@* begin for (j=0; j<=3;j=j+1) begin byte1[j] = data1[(j+1)*8-1 : j*8]; //把data1[7:0]…data1[31:24]依次赋值给byte1[0][7:0]…byte[3][7:0] end end此例中,integer 信号 j 作为辅助信号,将 data1 的数据依次赋值给数组 byte1。综合后实际电路里并没有 j 这个信号,j 只是辅助生成相应的硬件电路。 实数(real) 实数用关键字 real 来声明,可用十进制或科学计数法来表示。实数声明不能带有范围,默认值为 0。如果将一个实数赋值给一个整数,则只有实数的整数部分会赋值给整数。例如:real data1 ; integer temp ; initial begin data1 = 2e3 ; data1 = 3.75 ; end initial begin temp = data1 ; //temp 值的大小为3 end时间(time) Verilog 使用特殊的时间寄存器 time 型变量,对仿真时间进行保存。其宽度一般为 64 bit,通过调用系统函数 $time 获取当前仿真时间。例如:time current_time ; initial begin #100 ; current_time = $time ; //current_time 的大小为 100 end数组 在 Verilog 中允许声明 reg, wire, integer, time, real 及其向量类型的数组。数组维数没有限制。线网数组也可以用于连接实例模块的端口。数组中的每个元素都可以作为一个标量或者向量,以同样的方式来使用,形如:<数组名>[<下标>]。对于多维数组来讲,用户需要说明其每一维的索引。例如:integer flag [7:0] ; //8个整数组成的数组 reg [3:0] counter [3:0] ; //由4个4bit计数器组成的数组 wire [7:0] addr_bus [3:0] ; //由4个8bit wire型变量组成的数组 wire data_bit[7:0][5:0] ; //声明1bit wire型变量的二维数组 reg [31:0] data_4d[11:0][3:0][3:0][255:0] ; //声明4维的32bit数据变量数组下面显示了对数组元素的赋值操作:flag [1] = 32'd0 ; //将flag数组中第二个元素赋值为32bit的0值 counter[3] = 4'hF ; //将数组counter中第4个元素的值赋值为4bit 十六进制数F,等效于counter[3][3:0] = 4'hF,即可省略宽度; assign addr_bus[0] = 8'b0 ; //将数组addr_bus中第一个元素的值赋值为0 assign data_bit[0][1] = 1'b1; //将数组data_bit的第1行第2列的元素赋值为1,这里不能省略第二个访问标号,即 assign data_bit[0] = 1'b1; 是非法的。 data_4d[0][0][0][0][15:0] = 15'd3 ; //将数组data_4d中标号为[0][0][0][0]的寄存器单元的15~0bit赋值为3虽然数组与向量的访问方式在一定程度上类似,但不要将向量和数组混淆。向量是一个单独的元件,位宽为 n;数组由多个元件组成,其中每个元件的位宽为 n 或 1。它们在结构的定义上就有所区别。 存储器 存储器变量就是一种寄存器数组,可用来描述 RAM 或 ROM 的行为。例如:reg membit[0:255] ; //256bit的1bit存储器 reg [7:0] mem[0:1023] ; //1Kbyte存储器,位宽8bit mem[511] = 8'b0 ; //令第512个8bit的存储单元值为0参数 参数用来表示常量,用关键字 parameter 声明,只能赋值一次。例如:parameter data_width = 10'd32 ; parameter i=1, j=2, k=3 ; parameter mem_size = data_width * 10 ;但是,通过实例化的方式,可以更改参数在模块中的值。此部分以后会介绍。局部参数用 localparam 来声明,其作用和用法与 parameter 相同,区别在于它的值不能被改变。所以当参数只在本模块中调用时,可用 localparam 来说明。 字符串 字符串保存在 reg 类型的变量中,每个字符占用一个字节(8bit)。因此寄存器变量的宽度应该足够大,以保证不会溢出。字符串不能多行书写,即字符串中不能包含回车符。如果寄存器变量的宽度大于字符串的大小,则使用 0 来填充左边的空余位;如果寄存器变量的宽度小于字符串大小,则会截去字符串左边多余的数据。例如,为存储字符串 "ee.ac.cn", 需要 14*8bit 的存储单元:reg [0: 14*8-1] str ; initial begin str = "ee.ac.cn"; end 有一些特殊字符在显示字符串中有特殊意义,例如换行符,制表符等。如果需要在字符串中显示这些特殊的字符,则需要在前面加前缀转义字符 \ 。例如下表所示:其实,在 SystemVerilog(主要用于 Verilog 仿真的编程语言)语言中,已经可以直接用关键字 string 来表示字符串变量类型,这为 Verilog 的仿真带来了极大的便利。有兴趣的学者可以简单学习下 SystemVerilog。
2022年05月14日
825 阅读
0 评论
2 点赞
2022-05-14
【2】Verilog-项目设计方法
设计方法Verilog 的设计多采用自上而下的设计方法(top-down)。即先定义顶层模块功能,进而分析要构成顶层模块的必要子模块;然后进一步对各个模块进行分解、设计,直到到达无法进一步分解的底层功能块。这样,可以把一个较大的系统,细化成多个小系统,从时间、工作量上分配给更多的人员去设计,从而提高了设计速度,缩短了开发周期。设计流程Verilog 的设计流程,一般包括以下几个步骤:需求分析工作人员需要对用户提出的功能要求进行分析理解,做出电路系统的整体规划,形成详细的技术指标,确定初步方案。例如,要设计一个电子屏,需要考虑供电方式、工作频率、产品体积、成本、功耗等,电路实现采用 ASIC 还是选用 FPGA/CPLD 器件等。功能划分正确地分析了用户的电路需求后,就可以进行逻辑功能的总体设计,设计整个电路的功能、接口和总体结构,考虑功能模块的划分和设计思路,各子模块的接口和时序(包括接口时序和内部信号的时序)等,向项目组成员合理分配子模块设计任务。文本描述可以用任意的文本编辑器,也可以用专用的 HDL 编辑环境,对所需求的数字电路进行设计建模,保存为 .v 文件。功能仿真(前仿真)对建模文件进行编译,对模型电路进行功能上的仿真验证,查找设计的错误并修正。此时的仿真验证并没有考虑到信号的延迟等一些 timing 因素,只是验证逻辑上的正确性。逻辑综合综合(synthesize),就是在标准单元库和特定的设计约束的基础上,将设计的高层次描述(Verilog 建模)转换为门级网表的过程。逻辑综合的目的是产生物理电路门级结构,并在逻辑、时序上进行一定程度的优化,寻求逻辑、面积、功耗的平衡,增强电路的可测试性。但不是所有的 Verilog 语句都是可以综合成逻辑单元的,例如时延语句。布局布线根据逻辑综合出的网表与约束文件,利用厂家提供的各种基本标准单元库,对门级电路进行布局布线。至此,已经将 Verilog 设计的数字电路,设计成由标准单元库组成的数字电路。时序仿真(后仿真)布局布线后,电路模型中已经包含了时延信息。利用在布局布线中获得的精确参数,用仿真软件验证电路的时序。单元器件的不同、布局布线方案都会给电路的时序造成影响,严重时会出现错误。出错后可能就需要重新修改 RTL(寄存器传输级描述,即 Verilog 初版描述),重复后面的步骤。这样的过程可能反复多次,直至错误完全排除。FPGA/CPLD 下载或 ASIC 制造工艺生产完成上面所有步骤后,就可以通过开发工具将设计的数字电路目标文件下载到 FPGA/CPLD 芯片中,然后在电路板上进行调试、验证。如果要在 ASIC 上实现,则需要制造芯片。一般芯片制造时,也需要先在 FPGA 板卡上进行逻辑功能的验证。
2022年05月14日
162 阅读
0 评论
1 点赞
【1】Verilog-初识、简介与环境搭建
Verilog 具有很强的电路描述与建模能力,能从多个层次对数字系统进行描述和建模。因此,在简化硬件设计任务、提高设计效率与可靠性、语言易读性、层次化和结构化设计等方面展现了强大的生命力与潜力。发展历史1983 年,Verilog 最初由 Gateway Design Automation 公司(GDA)的 Phil Moorby 创建,作为内部仿真器的语言,主要用于逻辑建模和仿真验证,被广泛使用。1989 年,GDA 公司被 Cadence 公司收购,Verilog 语言成为 Cadence 公司的私有财产。1990 年,Cadence 公司成立 OVI(Open Verilog International)组织,公开 Verilog 语言,促进 Verilog 向公众领域发展。1992 年,OVI 决定致力于将 Verilog OVI 标准推广为 IEEE(The Institute of Electrical and Electronics Engineers)标准。1995 年,OVI 的努力获得成功,IEEE 制定了 Verilog HDL 的第一个国际标准,即 IEEE Std 1364-1995,也称之为 Verilog 1.0。2001 年,IEEE 发布 Verilog 第二个标准(Verilog 2.0),即 IEEE Std 1364-2001, 简称为 Verilog-2001 标准。由于 Cadence 在集成电路设计领域的影响力及 Verilog 语言的简洁易用性,Verilog 成为电路设计中最流行的硬件描述语言。主要特性下面是 Verilog 的主要特性:可采用 3 种不同的方式进行设计建模:行为级描述——使用过程化结构建模;数据流描述——使用连续赋值语句建模;结构化方式——使用门和模块例化语句描述。两类数据类型:线网(wire)数据类型与寄存器(reg)数据类型,线网表示物理元件之间的连线,寄存器表示抽象的数据存储元件。能够描述层次设计,可使用模块实例化描述任何层次。用户定义原语(UDP)创建十分灵活。原语既可以是组合逻辑,也可以是时序逻辑。可提供显示语言结构指定设计中的指定端口到端口的时延,以及路径时延和时序检查。Verilog 支持其他编程语言接口(PLI)进行进一步扩展。PLI 允许外部函数访问 Verilog 模块内部信息,为仿真提供了更加丰富的测试方法。同一语言可用于生成模拟激励和指定测试的约束条件。设计逻辑功能时,设计者可不用关心不影响逻辑功能的因素,例如工艺、温度等。主要应用专用集成电路(ASIC),就是具有专门用途和特殊功能的独立集成电路器件。Verilog 作为硬件描述语言,主要用来生成专用集成电路。主要通过 3 个途径来完成:1、可编程逻辑器件FPGA 和 CPLD 是实现这一途径的主流器件。他们直接面向用户,具有极大的灵活性和通用性,实现快捷,测试方便,开发效率高而成本较低。2、半定制或全定制 ASIC通俗来讲,就是利用 Verilog 来设计具有某种特殊功能的专用芯片。根据基本单元工艺的差异,又可分为门阵列 ASIC,标准单元 ASIC,全定制 ASIC。3、混合 ASIC主要指既具有面向用户的 FPGA 可编程逻辑功能和逻辑资源,同时也含有可方便调用和配置的硬件标准单元模块,如CPU,RAM,锁相环,乘法器等。Verilog 环境搭建学习 Verilog 做仿真时,可选择不同仿真环境。FPGA 开发环境有 Xilinx 公司的 ISE(目前已停止更新),VIVADO;因特尔公司的 Quartus II;ASIC 开发环境有 Synopsys 公司的 VCS ;很多人也在用 Icarus Verilog 和 GTKwave 的方法,更加的轻便。虽然 ISE 或者 Quartus II 都会自带仿真器,但功能还是有欠缺。所以,这里介绍下 Quartus II + Modelsim 联合仿真的测试方法,运行环境为 64bit-win10 系统。Quartus II 安装本次介绍使用的 Quartus 版本为 10.1。目前 Quartus II 官网已经没有 13.1 以下版本的安装包,大家可以安装 13.1 以上版本的软件。功能都是大同小异,下载地址:https://fpgasoftware.intel.com/13.1/?edition=subscription&platform=windows下载 13.1 以上的 quartus II 时,官网也会推荐相应版本的 Modelsim,一起下载即可。开始安装,修改安装路径,其他按照默认设置一步步操作即可。下图是成功安装的截图。如果提示需要 License file,如下图所示,则需要指定购买该软件时的 license 文件。如果 license 文件需要替换 Host-ID,只需要 license 文件中的 HOSTID 替换为 NIC 选项中随便一个 ID 即可,如下图红色框所示:Quartus II 10.1 安装完还需要安装 Device,即安装支持各种可编程逻辑器件型号的库文件,否则 Quartus II 不能正常建立工程。安装路径需要选择 Quartus II 的安装路径,此时 Device 安装可自动识别 Quartus II。最新 Quartus II(例如 2016 版本)已经支持一套化安装了。Modelsim 安装Modelsim 选择 modelsim-win64-10.1c-se 版本。也需要修改下安装路径,然后按照默认设置进行操作即可。安装完毕后可能提示需要重启电脑,重启即可。建立 Quartus II 工程建立工程File->New project Wizard设置工作路径与工程名字、top module名字。注意,路径与名字设置时,不能包含中文。选择器件型号我们只进行简单的仿真,不进行下载、烧录等,所以我们不用关心具体信号,随便选一种即可。然后一直点击 Next,直到 Finish。新建 Verilog 源文件下面就对 4 位宽 10 进制计数器进行简单的仿真。点击:File->New->Verilog HDL File->OK点击:File->Save As输入 module 名字为:counter10.v需要注意的是,top module 名字一定要和 project 名字一致,否则会报错(如图中所示)。把 Verilog 代码复制到文件 counter10.v 中,进行一键编译(实际包含了编译、综合、布局布线等)。代码:module counter10( //端口定义 input rstn, //复位端,低有效 input clk, //输入时钟 output [3:0] cnt, //计数输出 output cout); //溢出位 reg [3:0] cnt_temp ; //计数器寄存器 always@(posedge clk or negedge rstn) begin if(! rstn)begin //复位时,计时归0 cnt_temp <= 4'b0 ; end else if (cnt_temp==4'd9) begin //计时10个cycle时,计时归0 cnt_temp <=4'b000; end else begin //计时加1 cnt_temp <= cnt_temp + 1'b1 ; end end assign cout = (cnt_temp==4'd9) ; //输出周期位 assign cnt = cnt_temp ; //输出实时计时器 endmodule报错时,可通过点击 Error log 来定位错误,进行修改,直至没有 Error。Quartus II 调用 Modelsim 仿真仿真设置为 Modelsim-altera点击:Tool->Options->EDA Tool Options将 Modelsim 后面的地址改为 Modelsim 启动程序的路径。选择仿真器点击:Assignments -> SimulationTool name 选择 ModelSim,并设置 Format、Time scale 等,如图写 testbench 文件点击:Processing->start->Start TestBench Template Writer如果设置正确,会在工程路径 simulation/modelsim 下产生 .vt 文件。.vt 文件模板已经给出了端口部分的代码、接口变量的声明和例化语句映射等。我们要做的就是将测试代码填入到 testbench 合适的位置。这里简单的写一下时钟、复位驱动代码,如下图所示。将 testbench 添加到工程中点击:Assignments -> Settings -> Simulation在 Compile test bench 选项中,选择 new,设置 Test bench name,并通过 File name 查找的方式,将上一步生成的 .vt 文件添加到工程中。需要注意的是,testbench 文件名字需要和 testbench 里的 top module 名字保持一致,否则后续启动 Modelsim 时会报错,不能进行正常的仿真。重新一键编译此时,你会发现,Tasks 栏编译的状态变成了问号,需要重新进行一键编译。调用 Modelsim 仿真点击:Tools->Run simulation Tool->RTL Simulation这时就会自动启动 Modelsim 软件。Modelsim 操作这里不做具体介绍。由仿真图可知,我们的设计完成了 10 进制计数的基本功能。总结记忆中,Quartus II + Modelsim 的联合仿真功能既强大,又安装方便。几年后重新进行此过程,发现步骤也有些许繁琐,花费了我一晚上的时间来搞定。很多细节也在上面提出,多多注意就好。不过,大家以后有机会进行大型的数字模块仿真时,就会发现此方法的有效性。在接下来的教程里,有些简单的仿真可能用其他软件进行,截图界面可能与 Modelsim 不一致。大家看到后不用怀疑仿真的准确性,这里特别说明。设计模块与 testbench 源码也会全部给出,大家完全可以自己仿真、验证。
2022年05月14日
406 阅读
0 评论
2 点赞
2022-05-14
ASIC/FPGA应该学习Verilog还是VHDL?
正文对于FPGA或者ASIC的初学者来说,选择哪种语言貌似应该根据自身的需求而定,例如实验室项目需要使用哪种语言,或者实验室师兄师姐使用了哪种语言,或者导师推荐你学习哪种原因,这都是硬性需求了,因为你需要完成项目的接手,所以必须根据要求而来!常识讨论但如果你没有这些顾虑呢?该如何做出选择?这时,您应该注意几点。VHDL是强类型的。这使初学者更难犯错误,因为编译器不允许您编写有效的代码。Verilog是弱类型的。它允许您编写错误的代码,但更为简洁。Verilog看起来更像C之类的软件语言。这使熟悉C的人更容易阅读和理解Verilog的工作。VHDL需要大量输入。Verilog通常只需要较少的代码即可完成相同的操作。VHDL是非常确定的,因为在某些情况下Verilog是不确定的。当然,这里并不是评论Verilog或者VHDL的优劣的,对于语言的选择是根据需求而定的!有人喜欢用Verilog,自然喜欢它的优点,也能包它的缺点,VHDL也是如此!例如1995年OVI主题演讲时,时任Cadence首席执行官的Joe Costello,认为:VHDL is one of the biggest mistakes the Electronics Design Automation industry has ever made. A $400 million mistake. Wouldn’t this money have been better spent on handling sub-micron design, testability issues, or even a new type of HDL that had significantly more capabilities than what Verilog and VHDL offer today?翻译过来就是:VHDL是电子设计自动化行业有史以来最大的错误之一。4亿美元的错误。这笔钱不会花在处理亚微米设计,可测试性问题,甚至是比Verilog和VHDL提供的功能明显更多的新型HDL上吗?这明显是对VHDL的负面评论!这也很好理解:在那些年里,Verilog和VHDL是主要的HDL竞争者,而Cadence主导了Verilog仿真市场。也有一些反对Verilog的声音,大概是认为:一方面,如果仅存Verilog,那么是形成垄断,垄断并不符合行业及其客户的普遍利益。有了垄断,就没有竞争。当竞争消失时,创新也会消失。另一方面,诟病Verilog的编程陷阱?例如非阻塞赋值等等!对于事情的好坏,声音总是很多,都是利益相关,这与我们的主题无关,到此为止!数据分析下面我们来从更多的数据方面看看Verilog还有VHDL的对比情况:谷歌网页搜索热度:全球红色代表Verilog,蓝色代表VHDL,可以明显看出Verilog从追赶到反超的这样一个事实(还有一点有趣的是,很多年龄较大的领导或者导师更熟悉VHDL,和他们所处的年代有关!),我们把时间线拉近感受一下: 从2018年初至今,Verilog的搜索热度还是高于VHDL,这是一个趋势!中国上面是全球的情况,那么对于中国来说呢? 可见,大概2008年以前还平分秋色,但是之后,Verilog热度越来越大于VHDL!结束语考虑到国内大势,Verilog更受欢迎!verilog强大的仿真功能,相比之下VHDL的仿真功能弱爆了。verilog这么多年的市场占有率远胜于VHDL,除了一些以前的设计需要支持以及很多学校还是以VHDL教学,基本用的很少了。
2022年05月14日
300 阅读
0 评论
2 点赞
1
...
4
5