第一篇:verilog作业题
1、以结构描述方式实现下列逻辑:
F=AB+ACD(CD的非)
2、以连续赋值语句设计8位总线驱动器。
3、以always语句设计8位总线驱动器。
4、以always语句设计8位双向总线驱动器。
1、设计一个具有低电平使能端和高电平使能端的2-4译码器。
2、设计一个JK触发器。
3、设计一个24分频期,要求输出信号占空比为1:1。
4、一个挂在总线上的16位寄存器。
5、设计一个8位线编码器,输入为D7 - D0,D7优先级最高,D0最低。当Di为高电平输入时,F=1,OUT为其编码,否则F=0。
1、以结构描述方式实现下列逻辑:
Y=ABC(BC的非)+DE+ CFG(CFG的非)
2、试设计一个具有使能端ncs的2-4译码器。
3、试设计一个4位加减运算器,输入为A、B、CIN、M,输出为OUT和COUT。当M=0时执行加法运算,M=1时,执行减法运算。
4、试设计一个14分频器,要求占空比1:1。
5、试设计一个具有三态输出缓冲的8位数据寄存器。
6、试设计一个具有清0和置数功能的8位二进制加1计数器。
7、设计一个16位移位寄存器。
8、设计一个16位双向移位寄存器,当d=0时右移, d=1时左移。
1设中断请求有效电平为高电平,中断请求输入线INTR0—INTR15中INTR15优先权最高。试设计一个中断优先权编码器。当有中断请求时,INT=1,同时输出中断请求输入线的编码V;否则INT=0,V的输出任意。
2试设计一个具有同步清0和同步置数功能的8位二进制加1计数器。
3试设计一个“11010100”序列检测器.4设计一个8位双向移位寄存器。其I/O端口和控制端口包括d(移位方向控制,当d=0时右移, d=1时左移)、数据串行输入din、数据并行输入data(8位)、dout数据串行输出、数据并行输出q(8位)、同步时钟clk、并行置数load等。
5设计每周期8个采样点的锯齿波信号发生器。
6设计每周期8个采样点的正弦波信号发生器。
第二篇:verilog学习日志
1.解决xilinx的仿真库的编辑问题
2.模块的做法和调用方法,带参数模块的应用:两种方法modelname #(value)madelcase();
二、用defparam 改变参数。
3.Begin ……end之间是串行执行的语句。在实际的电路中各条语句并不是完全串行的。4.Fork……join之间是并行执行的语句,但是不可综合;
5.表征过程模块的四种工程模块:initial模块,always模块,task模块,function模块;一个程序中可以有多个initial模块和always模块,但是initial模块只执行一次,不可综合,而always模块是不断重复执行的,可以综合。6.数据类型两大类:线网类型和寄存器类型
7.线网类型:结构化原件之间的物理连接,默认值高阻z;寄存器表示数据的存储单元,默认值为x;寄存器类型数据保持最后一次赋值,而线型数据需要持续的驱动; 8.线网数据场用来以关键字assign指定组合逻辑信号。模块中输入输出默认为wire类型,可综合的线网类型有wire,tri,supply0,supply1;线网类型的变量赋值只能通过assign来完成,不能用于always语句。
9.寄存器类型的数据没有强弱之分,且所有的寄存器类型变量都必须明确给出类型说明(无默认状态)。10.If语句指定了一个有限编码逻辑,case结果是并行的,没有优先级,if……else占用面积小但速度较慢,case语句占用面积大,但速度较快。11.如果if……else语句块为单句则直接写就可以,如果不只一句则要用begin……end括起来。12.循环语句for,while,repeat可以综合,forever不可综合。13.对于reg型数据不能用assign赋值。
14.拼接数据时最好将数据的进制形式都写详细,否则仿真出错,不知为何?例如:parameter a = 8;b = {{a{1’b0}},c};
15.module mult_8b_for(16.a,b,q 17.);18.parameter bsize = 8;19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.input [bsize1:0] b_t;reg [bsize1)begin
if(b_t[0])
begin
q = q + a_t;//一定要使用阻塞赋值
end else 36.37.38.39.40.begin
q = q;//一定要使用阻塞赋值
end
a_t = a_t <<1;//一定要使用阻塞赋值 b_t = b_t >>1;//一定要使用阻塞赋值
41.42.end end
43.Endmodule
44.Always语句中使用非阻塞赋值“<=”时,只有在always结束后才会把右端的赋值给左边的寄存器,如果采用非阻塞赋值,则会造成循环语句只执行一次。虽然模块整体是时序逻辑,但是循环部分却是组合逻辑。
45.Task和function是综合的,不过综合出来都是组合电路。46.在第一行Task语句中不能列出端口名称。
47.Task中可以调用其他的任务或函数,也可以调用自身;
48.任务定义的结构体内部能出现always或initial过程块(可能是因为其只能综合成组合电路的缘故吧)。但是可以在always或initial中调用。调用时要与声明的端口顺序相同。且只能在过程块中调用。
49.任务的输出端口必须和寄存器类型的数据变量对应。50.Function不允许有输出端口的声明,函数定义在函数内部会隐式的定义一个寄存器变量,该寄存器变量和函数同名并且位宽也一致。函数内部不能调用任务。
51.触摸板如何禁止:下载一个UltraNav驱动按上,到控制面板鼠标里面就可以禁止触摸板了。Win7下可以直接去禁止,不用安装驱动程序。
52.保证敏感信号列表的完备性。不要在组合逻辑中引入环路。
53.同步时序电路的准则:
1、单时钟策略,单时钟沿策略。
2、避免使用门控时钟。
3、不要再子模块内部使用计数器分频产生所需时钟。推荐的方式是有一个专门的子模块来管理系统时钟。
54.同步电路在目前数字电路系统中占绝对优势,和异步电路相比有下列优势:对温度、电压、生产过程等外部参数的适应性强;可以消除毛刺和内部的歪斜的数据,能将设计频率提高的吉赫兹。但是需要更多的资源,而且其时钟翻转频率高,功耗也比较大。55.关键路径:最大的可能时钟频率是由电路中最慢的逻辑路径决定的。一种消除这种限制的方法是将复杂的运算分开成为数个简单的运算,这种技术称为pipelining。56.要输就输给追求,要嫁就嫁给幸福。
57.第九章的二级流水线仿真时结果中显示不对,不知道为何,可能是testbench写的不好,有时间一定要搞明白。58.提高工作速度的两种方式:并行方式和流水线方式。核心思想是面积换速度。59.‘timescale 1ns / 1ps 代表时延单位为1ns,时延精度为1ps。
60.亚稳态:多时钟设计中,必然存在亚稳态,当触发器的建立时间和保持时间没有达到要求是,触发器就会处于逻辑1和逻辑0之间的第3中状态。及亚稳态。
61.状态机不仅仅是一种电路,而且是一种设计思想,他可以说是一个广义时序电路,状态机是数字设计的“大脑”。
62.状态机开发流程:首先要抽象出事物的状态,再次明确状态和输入输出之间的关系,让后得到系统的状态转移图,并用verilog实现。
63.Moore状态机输出仅仅依赖于当前状态,与输入无关,下一个状态与输入和当前状态有关,64.Mealy状态机的输出与输入和当前状态有关,65.状态机的容错处理:对剩余状态进行处理。方法:转入空闲状态、转入特定状态、转入预定义的专门处理错误的状态,如报警。66.状态机设计原则:单独用一个verilog模块来描述一个有限状态机。使用代表状态名的参数parameter来给状态赋值,而不是用宏定义。在组合always块中使用阻塞赋值,在时序always块中使用非阻塞赋值,67.利用三段式设计状态机。第一段处理当前状态的赋值。第二段处理下一个状态的赋值。第三段处理输出的赋值。
68.Case后面没有begin 结尾处加endcase;
69.利用stateCAD做状态机,注意填写条件是没有标点符号,而在写输出时有标点;ise软件在10版本以后就没有自带的CAD软件了,下了一个单独运行的一样可以用。70.同步整形电路:同步电路具备最稳定的工作状态和工作能力因此经常需要将外部输入的异步信号进行同步处理(与系统时钟同步)和整形(经输入信号由不规则的波形提取为具有一个时钟周期长的脉冲信号)。313页。71.Assign只能用来给wire和output赋值,不能用来给reg类型赋值;
72.Xst:528-Multi-source in Unit
75.综合synthesize:查看综合报告、查看RTL级原理图、检查语法。实现:implement,翻译、映射、布局布线,实现之前要进行约束条件的编辑。76.
第三篇:学verilog小结
学习verilog一段时间 小结 学习verilog, verilog, verilog小结
一:基本
Verilog中的变量有线网类型和寄存器类型。线网型变量综合成wire,而寄存器可能综合成WIRE,锁存器和触发器。
二:verilog语句结构到门级的映射
1、连续性赋值:assign 连续性赋值语句逻辑结构上就是将等式右边的驱动左边的结点。因些连续性赋值的目标结点总是综合成由组合逻辑驱动的结点。Assign语句中的延时综合时都将忽视。
2、过程性赋值:
过程性赋值只出现在always语句中。
阻塞赋值和非阻塞赋值就该赋值本身是没有区别的,只是对后面的语句有不同的影响。
建议设计组合逻辑电路时用阻塞赋值,设计时序电路时用非阻塞赋值。
过程性赋值的赋值对象有可能综合成wire,latch,和flip-flop,取决于具体状况。如,时钟控制下的非阻塞赋值综合成flip-flop。
过程性赋值语句中的任何延时在综合时都将忽略。
建议同一个变量单一地使用阻塞或者非阻塞赋值。
3、逻辑操作符:
逻辑操作符对应于硬件中已有的逻辑门
4、算术操作符:
Verilog中将reg视为无符号数,而integer视为有符号数。因此,进行有符号操作时使用
integer,使用无符号操作时使用reg。
5、进位:
通常会将进行运算操作的结果比原操作数扩展一位,用来存放进位或者借位。如:
Wire [3:0] A,B;
Wire [4:0] C;Assign C=A+B;C的最高位用来存放进位。
6、关系运算符: 关系运算符:<,>,<=,>= 和算术操作符一样,可以进行有符号和无符号运算,取决于数据类型是reg,net还是
integer。
7、相等运算符:==,!= 注意:===和!==是不可综合的。
可以进行有符号或无符号操作,取决于数据类型
8、移位运算符:
左移,右移,右边操作数可以是常数或者是变量,二者综合出来的结果不同。
9、部分选择: 部分选择索引必须是常量。
10、BIT选择:
BIT选择中的索引可以用变量,这样将综合成多路(复用)器。
11、敏感表:
Always过程中,所有被读取的数据,即等号右边的变量都要应放在敏感表中,不然,综合时不能正确地映射到所用的门。
12、IF:
如果变量没有在IF语句的每个分支中进行赋值,将会产生latch。如果IF语句中产生了latch,则IF的条件中最好不要用到算术操作。Case语句类似。Case的条款可以是变量。
如果一个变量在同一个IF条件分支中先赎值然后读取,则不会产生latch。如果先读取,后赎值,则会产生latch。
13、循环:
只有for-loop语句是可以综合的。
14、设计时序电路时,建议变量在always语句中赋值,而在该always语句外使用,使综合时能准确地匹配。建议不要使用局部变量。
15、不能在多个always块中对同一个变量赎值
16、函数
函数代表一个组合逻辑,所有内部定义的变量都是临时的,这些变量综合后为wire。
17、任务:
任务可能是组合逻辑或者时序逻辑,取决于何种情况下调用任务。
18、Z:
Z会综合成一个三态门,必须在条件语句中赋值
19、参数化设计:
优点:参数可重载,不需要多次定义模块
四:模块优化
1、资源共享:
当进程涉及到共用ALU时,要考虑资源分配问题。可以共享的操作符主要有:关系操作符、加减乘除操作符。通常乘和加不共用ALU,乘除通常在其内部共用。
2、共用表达式: 如:C=A+B;D=G+(A+B);两者虽然有共用的A+B,但是有些综合工具不能识别.可以将第二句改为:D=G+C;这样
只需两个加法器.
3、转移代码:
如循环语句中没有发生变化的语句移出循环.
4、避免latch:
两种方法:
1、在每一个IF分支中对变量赋值。
2、在每一个IF语句中都对变量赋初值。
5:模块:
综合生成的存储器如ROM或RAM不是一种好方法。最好用库自带的存储器模块。
五、验证: 1、敏感表:
在always语句中,如果敏感表不含时钟,最好将所有的被读取的信号都放在敏感表中。
2、异步复位:
建议不要在异步时对变量读取,即异步复位时,对信号赎以常数值。
第四篇:EDA技术Verilog密码锁
电 子 科 技 大 学
实
验
报
告
学生姓名:吴成峰
学 号:2014070906016
指导教师:黄志奇
一、实验室名称: 主楼C2-514
二、实验项目名称:
密码锁
三、实验原理:
利用FPGA开发班上的3个按钮开关btn[2:0]来输入4位数字的密码。例如,输入“2-0-1-2”打开门锁。将用拨位开关sw[7:0]来设置密码,通过按钮开关btn[2:0]来输入密码。其中,btn[0]、btn[1]和btn[2]分别对应的有效输入为“00”(十进制0)、“01”(十进制1)和“10”(十进制2),sw[7:6]、sw[5:4]、sw[3:2]和sw[1:0] 分别对应密码的1、2、3、4位。
用sw[7:0]设置密码的同时,通过7段数码管复用电路,将其显示到7段数码管上。注意:需将8位输入扩展成16位,即,x[15:0]={2’b00,sw[7:6], 2’b00,sw[5:4], 2’b00,sw[3:2], 2’b00,sw[1:0]} 输入4位数字后,才能知道所输入的密码是否正确。如果密码是正确的,led[1]亮起;如果密码错误,led[0]将亮起。图1给出了设计的顶层模块。当按下btn[0]、btn[1]、btn[2]中任何一个按钮时,将会产生一个时钟脉冲。当分别按下按钮btn[0]、btn[1]、btn[2]时,锁模块对应的2位输入bn[1:0]为“00”、“01”和“10”。输入的密码与拨位开关上设置的密码相比较,产生图2所示的状态转移图。注意:即使密码输入错误,也必须完成完整的4位密码输入,才能进入“fail”状态E4。
图1.门锁电路的顶层模块
图2.门锁电路的状态转移图
四、实验目的:
熟悉利用HDL代码输入方式进行组合逻辑电路的设计和仿真的流程,掌握Verilog语言的基本语法。并通过一个密码锁的设计把握利用EDA软件(Xilinx ISE 10.1)进行HDL代码输入方式的电子线路设计与仿真的详细流程,熟悉摩尔状态机。
五、实验内容:
1)利用HDL代码输入方式在Xilinx ISE 10.1平台上实现一个密码锁设计,可以设定密码并显示,输入密码以解锁; 2)设计密码锁的顶层模块,使用模块实例语句连接前面所设计的密码锁模块;
3)生成比特流文件下载到开发板上进行验证。
六、实验器材(设备、元器件): 1)计算机(安装Xilinx ISE 10.1软件平台);
2)BASYS2 FPGA开发板一套(带USB-MIniUSB下载线)。
七、实验步骤:
1、在Xilinx ISE 10.1平台中,新建一个工程lock。我们选用的BASYS2 FPGA开发板采用的是Spartan3E XA3S100E芯片和CPG132封装,设置好器件属性,如图3所示。
图3.设置器件属性
2、在工程管理区任意位置单击鼠标右键,在弹出的快捷菜单中选择“New Source”命令,弹出新建源代码对话框,这里我们选择“Verilog Module”类型,输入Verilog文件名“lock”。
ISE会自动创建一个Verilog的模板,并在源代码编辑区打开,接下来的工作就是将代码编写完整。完整代码如下: module lock(input clk,input clr,input [7:0] sw,input [1:0] bn,output reg pass,output reg fail);
reg [3:0] pre_s,nex_s;
parameter S0=4'b0000,S1=4'b0001,S2=4'b0010,S3=4'b0011,S4=4'b0100,E1=4'b0101,E2=4'b0110,E3=4'b0111,E4=4'b1000;
//state registers
always@(posedge clk or posedge clr)
begin
if(clr==1)
pre_s<=S0;
else
pre_s<=nex_s;
end
//C1
always@(*)
begin
case(pre_s)
S0:if(bn==sw[7:6])
nex_s<=S1;
else
nex_s<=E1;
S1:if(bn==sw[5:4])
nex_s<=S2;
else
nex_s<=E2;
S2:if(bn==sw[3:2])
nex_s<=S3;
else
nex_s<=E3;
S3:if(bn==sw[1:0])
nex_s<=S4;
else
nex_s<=E4;
S4:if(bn==sw[7:6])
nex_s<=S1;
else
nex_s<=E1;
E1:nex_s<=E2;
E2:nex_s<=E3;
E3:nex_s<=E4;
E4:if(bn==sw[7:6])
nex_s<=S1;
else
nex_s<=E1;
default:nex_s<=S0;
endcase
end
//C2
always@(*)
begin
if(pre_s==S4)
pass=1;
else
pass=0;
if(pre_s==E4)
fail=1;
else
fail=0;
end
endmodule
3、建立分频模块“clkdiv”,过程如上,代码如下:
module clkdiv(input mclk, input clr, output clk190);
reg [24:0] q;
always@(posedge mclk or posedge clr)
begin
if(clr==1)
q<=0;
else
q<=q+1;
end
assign clk190=q[17];//190Hz endmodule
4、建立时钟脉冲模块“clock_pulse”,代码如下:
module clock_pulse(input inp,input cclk,input clr,output outp);
reg delay1;
reg delay2;
reg delay3;
always@(posedge clr or posedge cclk)
begin
if(clr==1)
begin
delay1<=0;
delay2<=0;
delay3<=0;
end
else
begin
delay1<=inp;
delay2<=delay1;
delay3<=delay2;
end
end
assign outp=delay1&delay2&~delay3;endmodule
5、建立七段数码管复用模块“hex7seg”,代码如下:
module hex7seg(input [15:0] x, input clk, input clr, output reg [6:0] a_to_g, output reg [3:0] an, output dp);wire [1:0] s;reg [3:0] digit;wire [3:0] aen;reg [19:0] clkdiv;
assign dp=1;assign s=clkdiv[19:18];
assign aen[3]=1;assign aen[2]=1;assign aen[1]=1;assign aen[0]=1;
//四位四选一 always@(*)case(s)0:digit=x[3:0];1:digit=x[7:4];2:digit=x[11:8];3:digit=x[15:12];default:digit=x[3:0];endcase
//数码管显示 always@(*)case(digit)0:a_to_g=7'b0000001;1:a_to_g=7'b1001111;2:a_to_g=7'b0010010;3:a_to_g=7'b0000110;4:a_to_g=7'b1001100;5:a_to_g=7'b0100100;6:a_to_g=7'b0100000;7:a_to_g=7'b0001111;8:a_to_g=7'b0000000;9:a_to_g=7'b0000100;'hA:a_to_g=7'b0001000;'hB:a_to_g=7'b1100000;'hC:a_to_g=7'b0110001;'hD:a_to_g=7'b1000010;'hE:a_to_g=7'b0110000;'hF:a_to_g=7'b0111000;default:a_to_g=7'b0000001;endcase
//digit select always@(*)begin
an=4'b1111;if(aen[s]==1)
an[s]=0;end
//时钟分频器
always@(posedge clk or posedge clr)begin
if(clr==1)
clkdiv<=0;
else
clkdiv<=clkdiv+1;end endmodule
6、顶层模块lock_top设计。代码如下:
module lock_top(input mclk,input [7:0] sw,input [3:0] btn,output [1:0] led,output [6:0] seg,output [3:0] an,output dp);wire clr,clk190,clkp,btn012;wire [1:0] bn;wire [15:0] x;
assign x={2'b00,sw[7:6],2'b00,sw[5:4],2'b00,sw[3:2],2'b00,sw[1:0]};assign clr=btn[3];assign btn012=btn[0]|btn[1]|btn[2];assign bn[1]=btn[2];assign bn[0]=btn[1];
clkdiv U1(.mclk(mclk),.clr(clr),.clk190(clk190));
clock_pulse U2(.inp(btn012),.cclk(clk190),.clr(clr),.outp(clkp));
lock U3(.clk(clkp),.clr(clr),.sw(sw),.bn(bn),.pass(led[1]),.fail(led[0]));
hex7seg U4(.x(x),.clk(mclk),.clr(btn[3]),.a_to_g(seg),.an(an),.dp(dp));Endmodule
7、将工程编译、综合与实现。在工程管理区的“Source for”中选取“Implementation”选项,然后在进程管理区双击“Synthesize-XST”进行综合,如图4所示。
图4.综合进程与源程序结构
综合完成以后是实现,实现主要分为三个步骤:翻译逻辑网表、映射到器件单元和布局布线,如图4所示。注意的是,在实现前还必须为模块中的输入/输出信号添加引脚约束,即添加UCF文件。开发板BASYS2的UCF文件可以在其网站上www.xiexiebang.com上下载,当然也可以自己编辑UCF文件。实验所用的UCF文件如图5所示。
图5.BASYS2开发板所需的UCF文件
6、器件配置。首先生成可以下载到硬件中的二进制比特文件。双击图10中的“Generate Programming File”的选线,ISE就会为设计生成相应的二进制比特文件。
BASYS2开发板提供了非常方便的JTAG配置方案,使用USB-miniUSB线缆结合Digilent Adept软件实现FPGA的配置,配置界面如图6所示。这里我们对FPGA进行配置,配置成功状态栏会显示“Programming Successful”信息,如图6所示。然后可在器件上验证设计。
图6.Digilent Adept 界面与配置
八、实验数据及结果分析:
图7.设定密码为2012
图8.输入密码0000,led[0]亮,输入错误
图8.输入密码2012,led[1]亮,输入正确
九、实验结论: 由上面实验结果可得,实验仿真结果证明了设计的正确性,该设计是合理的,能够满足实验所需的,完成了题设要求。
十、总结及心得体会: 此次实验结合了前几次的学习的成果,将七段数码管复用的部分结合进来,并通过分频电路和时钟脉冲电路来实现通过按键对时序系统的输入,而密码锁本身即是时序电路摩尔机的利用。至此,我们完整的梳理了一遍这个学期的所学,组合电路设计,时序电路设计合为一体,更能深刻的理解Verilog语言和EDA,收获良多。
报告评分:
指导教师签字:
第五篇:Verilog学习心得
Verilog学习心得
因为Verilog是一种硬件描述语言,所以在写Verilog语言时,首先要有所要写的module在硬件上如何实现的概念,而不是去想编译器如何去解释这个module.比如在决定是否使用reg定义时,要问问自己物理上是不是真正存在这个register, 如果是,它的clock是什么? D端是什么?Q端是什么?有没有清零和置位?同步还是异步?再比如上面讨论的三态输出问题,首先想到的应该是在register的输出后面加一个三态门,而不是如何才能让编译器知道要“赋值”给一个信号为三态。同样,Verilog中没有“编译”的概念,而只有综合的概念。
写硬件描述语言的目的是为了综合,所以说要想写的好就要对综合器有很深的了解,这样写出来的代码才有效率。
曾经接触过motorola苏州设计中心的一位资深工程师,他忠告了一句:就是用verilog描述电路的时候,一定要清楚它实现的电路,很多人只顾学习verilog语言,而不熟悉它实现的电路,这是设计不出好的电路来的.一般写verilog code时,对整个硬件的结构应该是很清楚了,最好有详细的电路图画出,时序问题等都应该考虑清楚了。可以看着图直接写code。
要知道,最初Verilog是为了实现仿真而发明的.不可综合的Verilog语句也是很重要的.因为在实际设计电路时,除了要实现一个可综合的module外,你还要知道它的外围电路是怎样的,以及我的这个电路与这些外围电路能否协调工作.这些外围电路就可以用不可综合的语句来实现而不必管它是如何实现的.因为它们可能已经实际存在了,我仅是用它来模拟的.所以,在写verilog的时候应该要先明确我是用它来仿真的还是综合的.要是用来综合的话,就必须要严格地使用可综合的语句,而且不同的写法可能产生的电路会有很大差别,这时就要懂一些verilog综合方法的知识.就像前面说的,脑子里要有一个硬件的概念.特别是当综合报错时,就要想一想我这种写法能不能用硬件来实现,verilog毕竟还不是C,很多写法是不可实现的.要是这个module仅是用来仿真的,就要灵活得多了,这时你大可不必太在意硬件实现.只要满足它的语法,实现你要的功能就行了.有网友说关于#10 clk=~clk的问题,虽然这种语句是不可综合的,但是在做simulation和verification是常常用它在testbench中来产生一个clock信号。再比如常常用到的大容量memory, 一般是不会在片上实现的,这个时候也需要一个unsynthesizable module.mengxy所言切中肯罄。
我们设计的module的目的是为了可以综合出功能正确,符合标准的电路来。我想这是个反复的过程,就像我们在写design flow中总要注明前仿真,综合后的仿真,以及后仿真等。仿真是用来验证我们的设计的非常重要的手段。而verilog里那些看是无聊的语句这个时候就会发挥很大的作用。我想,用过verilog_xl的兄弟应该深有体会。verilog_xl里的操作,可以用verilog里的系统命令来完成。通过最近的应聘我也深有体会,很多公司看中你在写code时,是否考虑到timing, architecture,DFT等,这也说明verilog中的任何语句都非常重要的。要写代码前必须对具体的硬件有一个比较清晰的概念但是想一次完成可综合代码就太夸张了,verilog的自顶向下设计方法就是从行为建模开始的,功能验证了以后再转向可综合模型.太在意与可综合令初期设计变得太累
很同意这种看法,在做逻辑结构设计时,综合的因素是要考虑的,但是有很多东西不能考虑的过于细致,就是在设计的时候不能过于紧卡时延,面积等因素,因为这样以来综合后优化的余量就会很小,反而不利与设计的优化,如果在时延和面积要求不是很紧张的情况下,其实代码写的行为级,利用综合工具进行优化也是一种方法。偶就听说有一家很有名的公司,非常相信综合工具的优化能力,从来不作综合后仿真的,hehe.当然,如果面积和时延的要求很高,最好还是把代码写的底层一点,调用库单元时,也要充分考虑其面积和时延的因素。
Verilog与C++的类比
1.Verilog中的module对应C++中的class。它们都可以实例化。例如可以写一个FullAdder module,表示全加器这种器件。module FullAdder(a, b, cin, sum, cout);input a, b, cin;output sum, cout;
assign {cout, sum} = a + b + cin;endmodule
然后在执行8-bit补码加减运算的ALU module中实例化8个FullAdder,表示ALU用到了8个FullAdder。
module ALU(a, b, result, cout, is_add);input[7:0] a, b;input is_add;output[7:0] result;output cout;
wire[7:0] b_not = ~b;wire[7:0] b_in = is_add ? b : b_not;wire[7:0] carry;
assign carry[0] = is_add ? 1'b0 : 1'b1;
// module 实例化
// 8-bit ripple adder FullAdder fa0(a[0], b_in[0], carry[0], result[0], carry[1]);FullAdder fa1(a[1], b_in[1], carry[1], result[1], carry[2]);FullAdder fa2(a[2], b_in[2], carry[2], result[2], carry[3]);FullAdder fa3(a[3], b_in[3], carry[3], result[3], carry[4]);FullAdder fa4(a[4], b_in[4], carry[4], result[4], carry[5]);FullAdder fa5(a[5], b_in[5], carry[5], result[5], carry[6]);FullAdder fa6(a[6], b_in[6], carry[6], result[6], carry[7]);FullAdder fa7(a[7], b_in[7], carry[7], result[7], cout);endmodule
对应在C++中先写FullAdder class,然后在ALU class中以FullAdder作为data member。
class FullAdder { };
class ALU { FullAdder fa[8];};另外一点,moudle声明port的方式,像是从早期C语言的函数定义中学来的:
char* strcpy(dst, src)char* dst;char* src;{ //...}
2.Verilog中的模块调用时,指定端口可以使用名称绑定。C++在调用函数时,参数只能按顺序书写。例如memset()的原型是:
void *memset(void *s, int c, size_t n);
如果你想将某个buf清零,应该这么写: char buf[256];memset(buf, 0, sizeof(buf));
但是如果你不小心写成了: memset(buf, sizeof(buf), 0);
编译器不会报错,但运行的实际效果是根本没有对buf清零。(记得Richard Stevens的书里提到过这一点。)
在Verilog中,如果要写一个测试ALU的module,那么其中对ALU实例化的指令可以这么写:
module alu_test;reg[8:0] a_in, b_in;reg op_in;wire[7:0] result_out;wire carry_out;
ALU alu0(.a(a_in[7:0]),.b(b_in[7:0]),.is_add(op_in),.result(result_out),.cout(carry_out));//...endmodule 这样就比较容易检查接线错误。
另外,在C++中,如果所有参数类型不同,而且之间没有隐式类型转换,那么可以利用C++的强类型机制在编译期检查出这种调用错误。
3.Verilog中把大括弧{}用作bit的并置,因此语句块要用begin/end标示。Verilog中小括号()和中括号[]的作用与C++中类似,前者用于函数或模块调用,后者用于下标索引。我想如果Verilog把尖括号<>用作bit并置的话,就能把大括号{}解放出来,用作标示语句块,这样写起来更舒服一些。
4.Verilog本质上是测试驱动开发的。对于每个module都应该有对应的test bench(或称test fixture)。比较好的情况是,一个工程师写module,另一个工程师写对应的testbench,这样很容易检查出对电路功能需求理解不一致的地方。因此还可以说Verilog主张结对编程(pair programming)。例如对前面的ALU module的test bench可以写成: `timescale 1ns / 1ns module alu_test;
reg[8:0] a_in, b_in;reg op_in;
wire[7:0] result_out;wire carry_out;
ALU alu0(.a(a_in[7:0]),.b(b_in[7:0]),.is_add(op_in),.result(result_out),.cout(carry_out));
reg[9:0] get, expected;reg has_error;
initial begin has_error = 1'b0;
op_in = 1'b1;// test addition
for(a_in = 9'b0;a_in!= 256;a_in = a_in + 1)for(b_in = 9'b0;b_in!= 256;b_in = b_in + 1)begin #1;get = {carry_out, result_out};expected = a_in + b_in;if(get!== expected)begin $display(“a_in = %d, b_in = %d, expected %d, get %d”,a_in, b_in, expected, get);has_error = 1'b1;end end
op_in = 1'b0;// test subtraction //...if(has_error === 1'b0)begin $display(“ALL TESTS PASSED!”);end $finish;end endmodule
5.Verilog比起VHDL的不足之处在于,它只能定义concrete class,不能定义abstract class。也就是说interface和implementation不能分离。这在设计大型电路时就显得表现力不足。不过这关系不大,因为可以在编译时选择同一模块的不同实现版本,间接实现了接口与实现的分离。
在VHDL中,强制将接口与实现分离。对每个模块,你都得先写接口(定义输入输出信号),即ENTITY;然后至少写一份实现,即ARCHITECTURE。每个ENTITY可以有不止一份实现,例如可以有行为描述的,也有数据流描述的。然后在配置文件中选择该ENTITY到底用哪一份实现。举例来说(选自《VHDL入门·解惑·经典实例·经验总结》一书),分频器模块可以这么写,先定义其接口FreqDevider,然后定义两份实现Behavior和Dataflow:
LIBRARY IEEE;USE IEEE.Std_Logic_1164.All;
ENTITY FreqDevider IS PORT(Clock : IN Std_Logic;Clkout : OUT Std_Logic);END;
ARCHITECTURE Behavior OF FreqDevider IS SIGNAL Clk : Std_Logic;BEGIN PROCESS(Clock)BEGIN IF rising_edge(Clock)THEN Clk <= NOT Clk;END IF;END PROCESS;Clkout <= Clk;END;
ARCHITECTURE Dataflow OF FreqDevider IS--signal declarations BEGIN--processes END;在C++中,既可以写concrete class,也可以写abstract class。比Verilog和VHDL都方便。
6.Verilog和VHDL都有模板的概念,Verilog称为参数(parameter),VHDL称为类属(generic)。不过好像都只能用整数作为模板参数,不能像C++那样用类型作为模板参数。
7.目前来看,Verilog是硬件描述语言,不是硬件设计语言。在用Verilog设计电路的时候,我们是把脑子中想好的电路用Verilog“描述”出来:哪里是寄存器、哪里是组合逻辑、数据通路是怎样、流水线如何运作等等都要在脑子里有清晰的映象。然后用RTL代码写出来,经过综合器综合出的电路与大脑中的设想相比八九不离十。这就像说C语言是可移植的汇编语言,以前好的C程序员在写代码的时候,能够知道每条语句背后对应的汇编代码是什么。verilog设计经验点滴 1,敏感变量的描述完备性
Verilog中,用always块设计组合逻辑电路时,在赋值表达式右端参与赋值的所有信号都必须在always @(敏感电平列表)中列出,always中if语句的判断表达式必须在敏感电平列表中列出。如果在赋值表达式右端引用了敏感电平列表中没有列出的信号,在综合时将会为没有列出的信号隐含地产生一个透明锁存器。这是因为该信号的变化不会立刻引起所赋值的变化,而必须等到敏感电平列表中的某一个信号变化时,它的作用才表现出来,即相当于存在一个透明锁存器,把该信号的变化暂存起来,待敏感电平列表中的某一个信号变化时再起作用,纯组合逻辑电路不可能作到这一点。综合器会发出警告。Example1: input a,b,c;reg e,d;always @(a or b or c)
begin
e=d&a&b;/*d没有在敏感电平列表中,d变化时e不会立刻变化,直到a,b,c中某一个变化*/
d=e |c;
end
Example2: input a,b,c;reg e,d;always @(a or b or c or d)
begin
e=d&a&b;/*d在敏感电平列表中,d变化时e立刻变化*/
d=e |c;
end
2, 条件的描述完备性
如果if语句和case语句的条件描述不完备,也会造成不必要的锁存器。Example1: if(a==1'b1)q=1'b1;//如果a==1'b0,q=? q将保持原值不变,生成锁存器!
Example2: if(a==1'b1)q=1'b1;else
q=1'b0;//q有明确的值。不会生成锁存器!Example3: reg[1:0] a,q;....case(a)
2'b00 : q=2'b00;
2'b01 : q=2'b11;//如果a==2'b10或a==2'b11,q=? q将保持原值不变,锁存器!
endcase Example4: reg[1:0] a,q;....case(a)
2'b00 : q=2'b00;
2'b01 : q=2'b11;
default: q=2'b00;//q有明确的值。不会生成锁存器!
endcase
Verilog中端口的描述
1,端口的位宽最好定义在I/O说明中,不要放在数据类型定义中; Example1: module test(addr,read,write,datain,dataout)
input[7:0] datain;input[15:0] addr;input
read,write;
output[7:0] dataout;//要这样定义端口的位宽!
wire addr,read,write,datain;
reg dataout;
Example2: module test(addr,read,write,datain,dataout)input datain,addr,read,write;output dataout;wire[15:0] addr;wire[7:0] datain;wire
read,write;reg[7:0] dataout;// 不要这样定义端口的位宽!
2,端口的I/O与数据类型的关系:
端口的I/O
端 口 的 数 据 类 型
module内部 module外部
input
wire wire或reg
output
wire或reg
wire
inout
wire
wire
3,assign语句的左端变量必须是wire;直接用“=”给变量赋值时左端变量必须是reg!Example: assign a=b;//a必须被定义为wire!******** begin a=b;//a必须被定义为reg!end
VHDL 中 STD_LOGIC_VECTOR 和 INTEGER 的区别
例如 A 是INTEGER型,范围从0到255;B是STD_LOGIC_VECTOR,定义为8位。A累加到255时,再加1就一直保持255不变,不会自动反转到0,除非令其为0;而B累加到255时,再加1就会自动反转到0。所以在使用时要特别注意!
以触发器为例说明描述的规范性 1,无置位/清零的时序逻辑
always @(posedge CLK)
begin
Q<=D;
end
2,有异步置位/清零的时序逻辑
异步置位/清零是与时钟无关的,当异步置位/清零信号到来时,触发器的输出立即被置为1或0,不需要等到时钟沿到来才置位/清零。所以,必须要把置位/清零信号列入always块的事件控制表达式。
always @(posedge CLK or negedge RESET)
begin
if(!RESET)
Q=0;
else
Q<=D;
end
3,有同步置位/清零的时序逻辑
同步置位/清零是指只有在时钟的有效跳变时刻置位/清零,才能使触发器的输出分别转换为1或0。所以,不要把置位/清零信号列入always块的事件控制表达式。但是必须在always块中首先检查置位/清零信号的电平。
always @(posedge CLK)
begin
if(!RESET)
Q=0;
else
Q<=D;
end
结构规范性
在整个芯片设计项目中,行为设计和结构设计的编码是最重要的一个步骤。它对逻辑综合和布线结果、时序测定、校验能力、测试能力甚至产品支持都有重要的影响。考虑到仿真器和真实的逻辑电路之间的差异,为了有效的进行仿真测试: 1,避免使用内部生成的时钟
内部生成的时钟称为门生时钟(gated clock)。如果外部输入时钟和门生时钟同时驱动,则不可避免的两者的步调不一致,造成逻辑混乱。而且,门生时钟将会增加测试的难度和时间。
2,绝对避免使用内部生成的异步置位/清零信号
内部生成的置位/清零信号会引起测试问题。使某些输出信号被置位或清零,无法正常测试。
3,避免使用锁存器
锁存器可能引起测试问题。对于测试向量自动生成(ATPG),为了使扫描进行,锁存器需要置为透明模式(transparent mode),反过来,测试锁存器需要构造特定的向量,这可非同一般。
4,时序过程要有明确的复位值
使触发器带有复位端,在制造测试、ATPG以及模拟初始化时,可以对整个电路进行快速复位。
5,避免模块内的三态/双向
内部三态信号在制造测试和逻辑综合过程中难于处理.补充不知你看了verilog 2001版本吗?现在的verilog在尽量往C语言的风格上靠拢。
1。敏感变量的描述完备性,我现在用always实现组合逻辑时,都是写成always@(*),这样很很好,自动把所有右端赋值信号加入。
2。module编写时这样更好: module(input [23:0] rx_data , //CRC_chk interface
output reg
CRC_en ,output reg
CRC_init , input
CRC_err);