文章目录
1.Verilog电路仿真和验证概述
2.Verilog测试程序设计基础
2.1Testbench及其结构
2.2测试平台举例
2.3Verilog仿真结果确认
2.4Verilog仿真效率
3.与仿真相关的系统任务
3.1$display和 $write
3.2$monitor与 $stobe
3.3$time和 $reltime
3.4$finish和 $stop
3.5$readmemh和 $readmem
3.6$random
4.信号时间赋值语句
4.1时间延迟的语法说明
4.2时间延迟的描述形式
4.3边沿触发时间控制
4.4电平敏感事件控制
5.任务和函数
6.典型测试向量的设计
6.1变量初始化
6.2数据信号测试向量产生
6.3时钟信号测试向量产生
6.4总线信号测试向量产生
7.用户自定义元件模型UDP
8.基本门级元件和模块的延时建模
8.2模块延时建模
9.编译预处理语句
9.1宏定义
9.2文件包含处理
9.3仿真时间标度
9.4条件编译命令
9.5其他语句
10.Verilog测试方法简介
来源:蔡觉平老师的Verilog课程
1.Verilog电路仿真和验证概述
仿真,也叫模拟,是通过使用EDA仿真工具,通过输入测试信号,比对输出信号(波形、文本或者VCD文件)和期望值,来确认是否得到与期望所一致的正确的设计结果,验证设计的正确性。 验证是一个证明设计思路如何实现,保证设计在功能上正确的一个过程。
验证在Verilog设计的整个流程中分为4个阶段:
阶段1:功能验证;
阶段2:综合后验证;
阶段3:时序验证;
阶段4:板级验证。
2.Verilog测试程序设计基础
2.1Testbench及其结构
在仿真的时候Testbench用来产生测试激励给待验证设计( Design Under Verification, DUV),或者称为待测设计(Design UnderTest, DUT) 。 测试程序的一般结构: Testbench是一个测试平台,信号集成在模块内部,没有输入输出。在Testbench模块内,例化待测设计的顶层模块,并把测试行为的代码封装在内,直接对待测系统提供测试激励。
例:T触发器测试程序
module TFF_tb;
reg clk, rst_n, T;
wire data_out;
TFF U1(.data_out(data_out), .T(T), .clk(clk), .rst_n(rst_n)); //对被测模块实例化
always
#5 clk = ~clk;
Initial
begin
clk = 0;
#3 rst_n = 0;
#5 rst_n = 1;
T = 1;
#30 T = 0;
#20 T = 1;
end
Initial
begin
$monitor($time,"T=%b, clk=%b,rst_n=%b,data_out=%b", T, clk, rst_n,data_out);
end
endmodule
T触发器的波形仿真和文本输出: 从下图可以清晰地看出Testbench的主要功能: (1)为DUT提供激励信号0。 (2)正确实例化DUT。 (3)将仿真数据显示在终端或者存为文件,也可以显示在波形窗口中以供分析检查。 (4)复杂设计可以使用EDA工具,或者通过用户接口自动比较仿真结果与理想值,实现结果的自动检查。
在编写Testbench时需要注意的问题: (1)testbench代码不需要可综合 Testbench代码只是硬件行为描述不是硬件设计。 (2)行为级描述效率高 Verilog HDL语言具备5个描述层次,分别为开关级、门级、RTL级、算法级和系统级。 (3)掌握结构化、程式化的描述方式 结构化的描述有利于设计维护,可通过initial、always以及assign语句将不同的测试激励划分开来。 一般不要将所有的测试都放在一个语句块中
2.2测试平台举例
测试平台需要产生时钟信号、复位信号和一系列的仿真向量,观察DUT的响应,确认仿真结果。 (1)组合逻辑电路仿真环境搭建 全加器真值表:
module adder1 (a, b, ci, so, co);
input a, b, ci ;
output so, co ;
assign { co , so } = a + b + ci ;
endmodule
根据全加器的真值表编写的全加器测试程序如下:
module adder1_tb ;
wire so, co;
reg a, b, ci;
adder1 U1(a, b, ci, so, co); //模块例化
initial //测试信号产生
begin
a = 0; b = 0; ci = 0;
#20 a = 0; b = 0; ci = 1;
#20 a = 0; b = 1; ci = 0;
#20 a = 0; b = 1; ci = 1;
#20 a = 1; b = 0; ci = 0;
#20 a = 1; b = 0; ci = 1;
#20 a = 1; b = 1; ci = 0;
#20 a = 1; b = 1; ci = 1;
#200 $finish;
end
endmodule
全加器的输入a、b和ci定义为reg型变量,把输出so和co定义为wire型变量;用模块例化语句 "adder1 U1(a,b,ci,so,co);"把全加器设计电路例化到测试仿真环境中;用initial块语句改变输入的变化并生成测试条件,输入的变化语句完全根据全加器的真值表编写 (2)时序逻辑电路仿真环境的搭建 在于时序逻辑电路仿真环境中,需要考虑时序、定时信息和全局复位、置位等信号,并定义这些信号。
用Verilog编写的十进制加法计数器:
module cnt10(cIk ,rst, ena, q, cout);
input clk,rst,ena;
output [3:0] q;
output cout;
reg [3:0] q;
always@(posedge clk or posedge rst)
begin
if(rst)q=4’b0000;
else if(ena)
begin
if(q<9)
q=q+1;
else
q=0;
end
end
assign cout=q[3]&q[0];
endmodule
测试程序代码:
module cnt10_tb;
reg clk, rst, ena;
wire [3:0] q;
wire cout;
cnt10 U1(clk ,rst, ena, q, cout);
always #50 clk = ~clk;
initial
begin
clk=0;rst=0;ena=1;
#1200 rst=1;
#120 rst=0;
#2000 ena=0;
#200 ena=1;
#20000 $finish;
end
endmodule
实例化语句"cnt10 U1(clk,rst,ena,q,cout);“把十进制计数模块例化到仿真环境中; 在always中用语句”#50 clk=~clk;"产生周期为100(标准时间单位)的时钟方波; 用initial块生成复位信号rst和使能控制信号ena的测试条件。 测试结果如图:
2.3Verilog仿真结果确认
(1)直接观察波形 通过直接观察各信号波形的输出,比较测试值和期望值的大小,来确定仿真结果的正确性。
(2)打印文本输出法
module adder1_tb;
wire so,co;
reg a,b,ci;
adderl U1(a,b,ci,so,co);
initial
begin
a=0;b=0;ci=0;
#20 a=0;b=0;ci=1;
#20 a=0;b=1 ;ci=0;
#20 a=0;b=1 ;ci=1;
#20 a=1 ;b=0;ci=0;
#20 a=1 ;b=0;ci=1;
#20 a=1 ;b=1 ;ci=0;
#20 a=1;b=1;ci=1;
#200 $finish;
end
$monitor($time, "%b %b %b -> %b %b”,a, b, ci, so, co);
endmodule
输出结果:
0 0 0 0 -> 0 0 20 0 0 1 -> 1 0 40 0 1 0 -> 1 0 60 0 1 1 -> 0 1 80 1 0 0-> 1 0
系统任务打印任务: $display:直接输出到标准输出设备; $monitor:监控参数变化; $fdisplay:输出到文件等。
(3)自动检查仿真结果 自动检查仿真结果是通过在设计代码中的关键节点添加断言监控器,形成对电路逻辑综合的注释或是对设计特点的说明,以提高设计模块的观察性。
(4)使用VCD文件 Verilog提供一系列系统任务用于记录信号值变化保存到标准的VCD(Value Change Dump)格式数据库中。VCD文件是一种标准格式的波形记录文件,只记录发生变化的波形。
2.4Verilog仿真效率
因为要通过串行软件代码完成并行语义的转化,Verilog行为级仿真代码的执行时间比较长。
提高Verilog HDL代码的仿真代码执行时间: (1)减小层次结构 仿真代码的层次越少,执行时间就越短。 (2) 减少门级代码的使用 由于门级建模属于结构级建模,建议仿真代码尽量使用行为级语句,建模层次越抽象,执行时间就越短。 (3) 仿真精度越高,效率越低 计时单位值与计时精度值的差距越大,则模拟时间越长。`timescale仿真时间标度。 (4) 进程越少,效率越高 代码中的语句块越少仿真越快,这是因为仿真器在不同进程之间进行切换也需要时间。 (5) 减少仿真器的输出显小 Verilog语言包含一些系统任务,可以在仿真器的控制台显示窗口输出一些提示信息,但会降低仿真器的执行效率。
3.与仿真相关的系统任务
3.1$display和 $write
语法格式: $display("", );
$write("", );
""通常称为“格式控制” ""为”信号输出列表“ $display自动地在输出后进行换行 $write输出特定信息是不换行
输出格式说明,由“%"和格式字符组成,其作用是将输出的数据转换成指定的格式输出。 常用的几种输出格式如下表: 一些特殊的字符可以通过表中的转换序列来输出: 例:$display和 $write语句
module disp_tb;
reg[31 :0] rval;
pulldown(pd);
initial
begin
rval=101;
$display("\\\t%%\n\"\123”);
$display("rval=%h hex %d decimal" rval, rval);
$display("rval=%o otal %b binary", rval, rval);
$display("rval has %c ascii character value",rval);
$display("pd strength value is %v", pd);
$display("current scope is %m");
$display("%s is ascii value for 101",101);
$write("simulation time is");
$write("%t\n", $time);
end
endmodule
在$display中,输出列表中数据的显示宽度是自动按照输出格式进行调整的,总是用表达式的最大值所占的位数来显示表达式的当前值。
3.2$monitor与 $stobe
$monitor与$stobe都提供了监控和输出参数列表中字符或变量的值的功能 (1)$monitor语法格式: $monitor("", );
任务$monitor提供了监控和输出参数列表中的表达式或变量值的功能。每当参数列表中变量或表达式的值发生变化时,整个参数列表中变量或表达式的值都将输出显示。 例如:$monitor($time, , “rxd=%b txd=%b”,rxd txd); 注意在上面的语句中,", ,"代表一个空参数。空参数在输出时显示为空格。
$monitoron和$monitoroff任务的作用是通过打开和关闭监控标志来控制监控任务$monitor的启动和停止,这样使得程序员可以很容易的控制$monitor何时发生。 $monitor与$display的不同处在于$monitor往往在initial块中调用,只要不调用$monitoroff,$monitor便不间断地对所设定的信号进行监视。
例:$monitor系统任务的应用
module monitor_tb;
integer a,b;
initial
begin
a = 2;
b = 2;
forever
begin
#5 a = a + b;
#5 b = a - 1;
end
end
initial $monitor($time,"a = %d,b = %d",a, b);
endmodule
(2)$strobe语法格式: $strobe();
$strobe("",);
探测任务用于在某时刻所有时间处理完后,在这个时间步的结尾输出一行格式化的文本。常用的系统任务如下: $stobe:在所有时间处理完后,以十进制格式输出一行格式化的文本; $strobeb:在所有时间处理完后,以二进制格式输出一行格式化的文本; $strobeo:在所有时间处理完后,以八进制格式输出一行格式化的文本; $strobeh:在所有时间处理完后,以十六进制格式输出一行格式化的文本。
$strobe任务在被调用的时刻所有的赋值语句都完成了,才输出相应的文字信息。$strobe任务提供了另一种数据显示机制,可以保证数据只在所有赋值语句被执行完毕后才被显示。
3.3$time和 $reltime
用这两个时间系统函数可以得到当前的仿真时刻,不同的是,$time函数以64位整数值的形式返回仿真时间,而 $realtime函数则以实数型数据返回仿真时间。 (1)系统函数 $time 例:$time系统任务的应用实例
`timescale 1ns/1ns
module time_tb;
reg ts;
parameter dalay = 2;
initial
begin
#delay ts = 1;
#delay ts = 0;
#delay ts = 1;
#delay ts = 0;
end
initial
$monitor($time,,"ts = %b",ts);
$time
endmodule
输出结果:
0 ts = x 3 ts = 1 5 ts = 0 8 ts = 1 10 ts = 0
(2) $realtime系统函数
$realtime返回的时间数字是一个实型数,该数字也是以时间尺度为基准的。 例:$realtime 系统任务的应用实例:
`timescalel 1ns/1ns
module realtime_tb;
reg set;
parameter p=2;
initial
begin
$monitor($realtime, ,"set=b%" ,set);
#p set=0;
#p set=1;
end
endmodule
输出结果:
0 set=x 2 set=0 4 set=1
3.4$finish和 $stop
系统任务$finish和$stop是用于对仿真过程进行控制,分别表示结束仿真和中断仿真。其语法格式: $finish; $fimsh(n); $stop; $stop(n); 其中,n是$finish和$stop的参数,n可以取0、1或2几个值,分别表示如下含义,如下表所示。
$finish的作用是退出仿真器,返回主操作系统,也就是结束仿真过程。任务$finish可以带参数,根据参数的值输出不同的特征信息。如果不带参数,默认$finish的参数值为1。 $stop任务的作用是把EDA工具(例如仿真器)置成暂停模式,在仿真环境下给出一个交互式的命令提示符,将控制权交给用户。这个任务可以带有参数表达式。根据参数值(0,1或2)的不同,输出不同的信息。参数值越大,输出的信息越多。
$finish的实例
module finish_tb;
integer a,b;
initial
begin
a = 2;
b = 4;
forever
begin
#5 a = a + b;
#5 b = a - 1;
end
end
initial #40 $finish; //程序执行到40个时间单位时退出仿真器
initial
begin
$monitor($time,"a = %d,b = %d",a,b);
end
endmodule
$stop的实例
module stop_tb;
integer a,b;
initial
begin
a = 2;
b = 4;
forever
begin
#5 a = a + b;
#5 b = a - 1;
end
end
initial #40 $stop; //程序执行到40个时间单位时停止仿真
initial
begin
$monitor($time,"a = %d,b = %d",a,b);
end
endmodule
3.5$readmemh和 $readmem
在Verilog程序中有两个系统任务$readmemh和$readmem用来从文件读取数据到存储器中。在两个系统任务可以在仿真的任何时刻被执行使用,其语法格式共有一下: (1) $readmemb(“”,); (2) $readmemb(“”,,); (3) $readmemb(“”,,,); (4) $readmemh(“” ,); (5) $readmemh(“”,,); (6) $readmemh(“”,,,);
例:$readmemh和$readmem系统任务实例
module read_mem_tb;
reg [7:0] memory_b [0:7];
reg [7:0] memory_h [0:31];
integer i;
initial
begin
$readmemb("init_b.txt",memory_b); //把数据文件init_b.txt读入存储器中的指定地址
$readmemh("init_h.txt",memory_h);
for(i = 0;i < 8; i=i+1)
begin
$display("memory_b[%0d] = %b",i.memory_b[i]);
$display("memory_h[%0h] = %h",i.memory_h[i]);
end
end
endmodule
文件init_b.txt和init_h.txt包含初始化数据。用@
在数据文件中指定地址。其中,"init_b.txt"指定二进制数据从第二位地址开始写入;而"init_h.txt"指定十六进制数据从地一位地址写入。样本文件如下:
init_b.txt:
@002
11111111 01010101
00000000 10101010
@001
1111zzzz 00001111
init_h.txt:
@001
00000000000000000000000000000011
00000000000000000000000000000111
00000000000000000000000000001111
00000000000000000000000000011111
3.6$random
$random是产生随机数的系统函数,每次调用该函数将返回一个32位的随机数,该随机数是一个带符号的整数。语法格式: $random%;
这个系统函数提供了一个产生随机数的手段。当函数被调用时返回一个32bit 的随机数。它是一个带符号的整形数。 $random一般的用法是:$ramdom%b,其中b>0,它给出了一个范围在(-b + 1):(b - 1)中的随机数。
实例:
`timescale 1ns/1ns
module random_pulse(dout);
output [9:0] dout;
reg dout;
integer delay1,delay2,k;
initial
begin
#10 dout=0;
for(k=0;k<100;k=k+1)
begin
delay1 = 20 * ({$random} % 6);
delay2 = 20 * (1 +{$random} % 3);
#delay1 dout= 1 << ({$random}%10);
$delay2 dout = 0;
end
end
endmodule
4.信号时间赋值语句
4.1时间延迟的语法说明
延迟语句用于对各条语句的执行时间进行控制,从而决速满足用户的时序要求。Verilog语言中延时控制的语法格式有两类: (1)#<延迟时间>行为语句; (2)#<延迟时间>; 其中,符号"#"是延迟控制的关键字符,<延迟时间>可以是直接指定的延迟时间量,并以多少个仿真时间单位的形式给出。在仿真过程中,所有时延都根据时间单位定义。
下面是带时延的赋值语句示例。 #2 Sum = A ^ B; //#2指定2个时间单位后,将A异或B的值赋值给Sum
根据时间控制部分在过程赋值语句中出现的位置,可以把过程赋值语句中的时间控制方式分为外部时间控制方式和内部时间控制方式。 (1)外部时间控制方式是时间控制出现在整个过程赋值语句的最左端,也就是出现赋值目标变量的左边的时间控制方式,其语法结构如: #5 a=b;
在仿真执行时就相当于如下几条语句:
initial
begin
#5;
a = b;
end
(2)内部时间控制方式是过程赋值语句中的时间控制部分还可以出现在“赋值操作符"和“赋值表达式"之间的时间控制方式。其语法结构如: a=#5b;
其中时间控制部分"#5"就出现在赋值操作符":"和赋值表达式"b"的中间,因此在这条过程赋值语句内带有内部时间控制方式的时间控制。它在执行时就相当于如下几条语句的执行:
initial
begin
temp=b; //先求b的值
#5;
a=temp;
end
4.2时间延迟的描述形式
此处时间延迟的描述形式是指延时控制的描述形式,其分为串行延迟控制、并行延迟控制、阻塞式延迟控制和非阻塞式延迟控制四种形式。以实现两组不同波形的信号为例(如图q0_out和q1_out),说明四种不同时间延迟的描述形式。 (1)串行延迟控制 串行延迟控制是最为常见的信号延迟控制,它是由begin、end过程块加上延迟赋值语句构成,其中延迟赋值语句可以为外部时间控制方式,也可以为内部时间控制方式。在<延迟时间>之后也可根据情况来确定是否执行相应的行为语句。 在<延迟时间>后面有相应的行为语句,则仿真进程遇到这条带有延迟控制的行为语句后并不立即执行行为语句指定的操作,而是要延迟等待到“<延迟时间> ’ 所指定的时间量过去后才真正开始执行行为语句指定的操作。
例:Verilog串行延迟控制方式设计上图的信号
`timescale 1ns/1ns
module serial_delay(q0_out, q1_out);
output q0_out, q1 _out;
reg q0_out, q1_out;
initial
begin
q0_out=1'b0;
#50 q0_out=l'b1;
#100 q0_out=1'b0;
#100 q0_out=1'b1;
#50 q0_out=1'b0;
#100 q0_out=1'b1;
#50 q0_out=1'b0;
#50 q0_out=1'b1;
#50 q0_out=1'b0;
end
initial
begin
q1_out=1'b0;
#100 q1_out=1'b1;
#100 q1_out=1'b0;
#50 q1_out=1'b1;
#100 q1_out=1'b0:
#50 q1_out=1'b1;
#100 q1_out=1'b0;
#50 q1_out=1'b1:
#50 q1_out=1'b0;
end
endmodule
(2)并行延迟控制 并行延迟控制方式是通过fork-join过程块加上延迟赋值语句构成,其中延迟赋值语句同串行延迟控制方式一样,既可以是外部时间控制方式,也可以是内部时间控制方式。在<延迟时间>之后也可根据情况来确定是否执行相应的行力语句。 在<延迟时间>后面有相应的行为语句,则仿真进程遇到这条带有延迟控制的行为语句后并不立即执行行为语句指定的操作,而是要延迟等待到"<延迟时间>"所指定的时间量过去后才真正开始执行行为语句指定的操作。但并行延迟控制方式与串行延迟控制方式不同在于并行延迟控制方式中的多条延迟语句时并行执行的,并不需要等待上一条语句的执行完成才开始执行当前的语句。
例:Verilog并行延迟控制方式设计上例波形图
`timescale 1ns/1ns
module parallel_delay (q0_out,q1_out);
output q0_out,q1_out;
reg q0_out,q1_out;
initial
fork
q0_out=1'b0;
#50 q0_out=1'b1;
#150 q0_out=1'b0;
#250 q0_out=1'b1;
#300 q0_out=1'b0;
#400 q0_out=1'b1;
#450 q0_out=1'b0;
#500 q0_out=1'b1;
#600 q0_out=1'b0;
join
initial
fork
ql_out=1'b0;
#100 q1_out=1'b1;
#200 q1_out=1'b0;
#250 q1_out=1'b1;
#350 q1_out=1'b0;
#400 q1_out=1'b1;
#500 q1_out=1'b0;
#550 q1_out=1'b1;
#600 q1_out=1'b0;
join
endmodule
(3)阻塞式延迟控制 以赋值操作符"=“来标识的赋值操作称为“阻塞式过程赋值”。阻塞式延迟控制是在阻塞式过程赋值基础上带有延时控制的情况,例如:
initial
begin
a = 0;
a = #5 1;
a = #10 0;
a = #15 1;
end
各条阻塞式赋值语句将依次得到执行,并且在第一条语句所指定的赋值操作没有完成之前第二条语句不会开始执行。因此在仿真进程开始时刻将"0"值赋给a,此条赋值语句完成之后才开始执行第二条赋值语句;在完成第一条赋值语句之后,延迟5个时间单位将"1"赋值给a;同理第三条赋值语句是在第二条赋值语句完成之后延迟10个时间单位才开始执行,将"0"赋值给a;最后一条赋值语句是在前三条语句都完成的时刻,延迟15个时间单位,将"1"赋值给a。下图给出了上例中信号a的波形。上述两例都采用的是阻塞式赋值语句。 4)非阻塞式延迟控制 以赋值操作符"<=“来标识的赋值操作称为"非阻塞式过程赋值”。非阻塞式延迟控制是在非阻塞式过程赋值基础上带有延时控制的情况。如下例所示:
initial
begin
a <= 0;
a <= #5 1;
a <= #10 0;
a <= #15 1;
end
在上例中各条非阻塞式赋值语句均以并行方式执行,虽然执行语句在begin-end串行块中,但其执行方式与并行延迟控制方式一致,在仿真进程开始时刻同时执行四条延迟赋值语句。在仿真进程开始时,将"0"值赋值给a;在离仿真开始时刻5个时间单位时,将"1"值赋值给a;在离仿真开始时刻10个时间单位时,将"0"值赋值给a;最后在离仿真开始时刻15个时间单位时,将"1"值赋值给a。下图给出了上例中信号a的波形。 例:Verilog非阻塞延迟控制方式设计
`timescale 1ns/1ns
module non_blocking_delay(q0_out,q1_out);
output q0_out,q1_out;
reg q0_out,q1_out;
initial
begin
q0_out <= 1'b0;
q0.out <= #50 1'b1;
q0_out <= #150 1'b0;
q0_out <= #250 1'b1;
q0_out <= #300 1'b0;
q0_out <= #400 1'b1;
q0_out <= #450 1'b0;
q0_out <= #500 1'b1;
q0_out <= #600 1'b0;
end
initial
begin
q1_out <= 1'b0;
q1_out <= #100 1'b1;
q1_out <= #200 1'b0;
q1_out <= #250 1'b1;
q1_out <= #350 1'b0;
q1_out <= #400 1'b1;
q1_out <= #500 1'b0;
q1_out <= #550 1'b1;
q1_out <= #600 1'b0;
end
endmodule
4.3边沿触发时间控制
边沿触发事件控制的语法格式可以为如下四种形式: 形式1:@(<事件表达式>)行为语句; 形式2:@(<事件表达式>); 形式3:@(<事件表达式1>or<事件表达式2>or…or<事件表达式n>) 行为语句; 形式4:@(<事件表达式1>or<事件表达式2>or…or<事件表达式n>);
1,事件表达式 在事件表达式中,可以以三种形式出现: 形式1:<信号名> 形式2:posedge<信号名> 形式3:negedge<信号名>
其中,"<信号名>“可以是任何数据类型的标量或矢量。 形式1中,代表触发事件的”<信号名>"在指定的信号发生逻辑变化时,执行下面的语句,如下例: @(in) out=in; 当敏感事件In发生逻辑变化时(包括正跳变和负跳变),执行对应的赋值语句,将in的值赋值给out。
形式2中,代表触发事件的"posedge <信号名>"在指定的信号发生了正跳变时,执行下面的语句,如下例: @(posedge(n) out=in; 当敏感事件in发生正跳变时,执行对应的赋值语句,将in的值赋值给out。
形式3中,代表触发事件的"negedge <信号名>"在指定的信号发生了负跳变时,执行下面的语句,如下例: @(negedge in) out=in; 当敏感事件in发生负跳变时,执行对应的赋值语句,将in的值赋值给out。
在信号发生逻辑变化(正跳变或负跳变)的过程中,信号的值是从0、1、x、 z四个值中的一个值变化到另一个值;而信号发生正跳变的过程是信号山低电平向高电平的转变,负跳变是信号山高电平向低电平的转变。下表为 Verilog HDL中规定的正跳变和负跳变:
正跳变
负跳变
0→x
1→x
0→z
1→z
0→1
1→0
x→1
x→0
z→1
z→0
2.边沿触发语法格式 形式1:@(<事件表达式>) 行为语句; 这种语法格式的敏感事件列表内只包含了一个触发事件,只有当这个指定的触发事件发生之后,后面的行为语句才能启动执行。在仿真进程中遇到这种带有事件控制的行为语句时,如果指定的触发事件还没有发生,则仿真进程就会停留在此处等待,直到指定触发事件发生之后再启动执行后面的行为语句,仿真进程继续向下进行。 例:时钟脉冲计数器
module clk_counter(clk, count_out);
input clk;
output count_out;
reg[3:0] count_out;
initial
count_out = 0;
always@(posedge clk)
count_out = count_out + 1; //在clk的每个正跳变边沿count_out增加1
endmodule
形式2:@(<事件表达式>); 这种语法格式的敏感事件列表内也只包含了一个触发事件,没有行为语句来指定触发事件发生时要执行的操作。这种格式的事件控制语句的执行过程与延时控制语句中没有行为语句的情况类似,仿真进程在遇到这条事件控制语句后会进入等待状态,直到指定的触发事件发生后才结束等待状态,退出该事件控制语句的执行并开始下一条语句的执行。
例:用于测定输入时钟正电平,负电平持续时间以及时钟周期的模块
module clk_time(clk);
input clk;
time posedge_time,negegde_time;
time high_last_time,low_last_time,last_time;
initial
begin
@(posedge clk);
posedge_time = $time;
@(negedge clk);
negedge_time = $time;
@(negedge clk);
last_time = $time - posedge_time;
high_last_time = negedge_time - posedge_time;
low_last_time = last_time - high_last_time;
$display("The clk stay in High level for: %t",high_last_time);
$display("The clk stay in Low level for: %t",low_last_time);
$display("The clk stay in signal Period for: %t",last_time);
end
endmodule
形式3:@(<事件表达式1>or<事件表达式2>…or<事件表达式n>) 行为语句; 这种语法格式的“敏感事件列表”内指定了由不同"<事件表达式>“代表的多个触发事件,这些”<事件表达式>"之间要用关键词”or“组合起来。只要这些触发事件中的任何一个得到发生,就启动行为语句的执行。在仿真进程遇到这种格式的边沿触发事件控制语句时,如果所有的触发事件都没有发生,则仿真进程就会进入等待状态,直到其中的某一个出发事件发生后才启动执行后面给出的行为语句,仿真进程继续向下进行。
形式4:@(<事件表达式1>or<事件表达式2>or…or<事件表达式n>) 同第三种语法格式一样,这种语法格式内指定了多个触发事件。但是在这种格式中没有行为语句。在这种情况下,该语句的执行过程与第二种语法格式的执行过程类似,仿真进程在遇到这条事件控制语句后会进入等待状态,直到敏感事件列表包含的多个触发事件中的任何一个得到发生后才结束等待状态,退出该事件控制语句并开始执行该事件控制语句后的下一条语句。 例:在触发事件发生后退出事件控制语句
module display(a,b);
input a,b;
wire a,b;
always@(posedge a or negndge b);
begin
$display("One of a and b changed in time: %t",$time);
end
endmodule
4.4电平敏感事件控制
电平敏感时间控制是另一种事件控制方式,与边沿触发事件控制不同,它是在指定的条件表达式为真时启动需要执行的语句。电平敏感时间控制是用关键词“wait"来表示。 电平触发事件控制的语法格式可以为如下两种: 形式1:wait(条件表达式)行为语句; 形式2:wait(条件表达式); 电平敏感事件控制的第一种形式中包含了行为语句,它可以是串行块(begin-end)语句或并行块(fork-join)语句,也可以是单条行为语句。在这种事件控制语句形式下,行为语句启动执行的触发条件是:条件表达式的值为"真(逻辑1)“。如果当仿真进程执行到这条电平敏感控制语句时条件表达式的值是"真”,那么语句块立即得到执行,否则语句块要一直等到条件表达式变为“真"时再开始执行。
例如:
wait(enable == 1)
begin
d = a & b;
d = d | c;
end
wait语句的作用是根据条件表达式的真假来控制下面begin-end语句块的执行,在使能信号enable变为高电平后,也就是enable==1的语句为真时进行a,b, c 之间的与或操作;若使能信号enable未变为高电平,则begin-end语句块的执行需要等到enable变为高电平之后才开始执行。
电平敏感事件控制的第2种形式中没有包含行为语句。在这种电平敏感事件控制语句形式下,如果当仿真进程执行到该wait控制语句时条件表达式的值是"真",那么立即结束该wait事件控制语句的执行,仿真进程继续往下进行;而如果当仿真进程执行到这条wait控制语句时条件表达式的值是"假",则仿真进程进入等待状态,一直等到条件表达式取值变为"真"时才退出等待状态同时结束该wait语句的执行,仿真进程继续往下进行。这种形式的电平敏感时间控制常常用来对串行块中各条语句的执行时序进行控制。
begin
wait(enable == 1)
d = a & b;
d = d | c;
end
5.任务和函数
在Verilog语言中提供了任务和函数,可以将较大的行为级设计划分为较小的代码段,允许设计者将需要在多个地方重复使用的相同代码提取出来,编写成任务和函数,这样可以使代码更加简洁和易懂。
5.1任务
任务的定义 任务定义的语法格式: task<任务名>;
端口和类型声明
局部变量声明
begin
语句1;
语句1;
......
语句n;
end
endtask
任务定义是嵌入在关键字task和endtask之间的,其中关键词task标志着一个任务定义结构的开端,endtask标志着一个任务定义结构的结束。“<任务名>” 是所定义任务的名称。在"<任务名>"后面不能出现输入输入端口列表。
例以读存储器数据为例说明任务定义的操作
task read_memory;
input[15:0] address;
output[31:0] data;
reg[3:0] counter;
reg[7:0] temp[1:4];
begin
for(counter=1;counter<=4;counter=counter+1)
temp[counter]=mem[address+counter-1];
data={temp[1],temp[2],temp[3],temp[4]};
end
endtask
任务定义时需注意以下事项: (1)在第一行"task"语句中不能列出端口名列表。 (2)任务中可以有延时语句、敏感事件控制语句等事件控制语句。 (3)任务可以没有或可以有一个或多个输入、输出和双向端口。 (4)任务可以没有返回值,也可以通过输出端口或双向端口返回一个或多个返回值。 (5)任务可以调用其它的任务或函数,也可以调用该任务本身。 (6)任务定义结构内不允许出现过程块(initial或always过程块)。 (7)任务定义结构内可以出现disable终止语句,这条语句的执行将中断正 在执行的任务。在任务被中断后,程序流程将返回到调用任务的地方继续向下执行 。
2.任务调用 任务的调用是通过"任务调用语句"来实现的。任务调用语句列出了传入任务的参数值和接收结果的变量值,任务的调用格式如下: <任务名>(端口1,端口,...,端口n);
例:以测试仿真中常用的方式来说明任务的调用
module task_tb;
reg[7:0] mem[127:0];
reg[15:0] a;
reg[31:0] b;
initial
begin
a = 0;
read_mem(a,b);//任务的第一次任务调用
#10;
a = 64;
read_mem(a,b);
end
task read_memory;
input[15:0] address;
output[31:0] data;
reg[3:0] counter;
reg[7:0] temp[1:4];
begin
for(counter=1;counter<=4;counter=counter+1)
temp[counter]=mem[address+counter-1];
data={temp[1],temp[2],temp[3],temp[4]};
end
endtask
使用任务可以使程序更加简洁易懂,以实际中的交通控制灯为例说明任务的定义,调用的特点。
module traffic_lights(red, amber, green);
output red, amber, green;
reg [2:1] order;
reg clock, red, amber, green;
parameter ON=1, OFF=0, RED_TICS=350,AMBER_TICS=30,GREEN_TICS=200;//产生时钟脉冲
always
begin
#100 clock = 0;
#100 clock= 1;
end
//任务的定义,该任务用于实现交通灯的开启
task light;
output red;
output amber;
output green;
input [31:0] tic_time;
input [2:1] order;
begin
red = OFF;
green = OFF;
amber = OFF;
case(order)
2'1b01: red = ON;
2'b10: green = ON;
2'b11: amber = ON;
endcase
repeat(tic_time)@(posedge clock);
red = OFF;
green = OFF;
amber = OFF;
end
endtask
//任务调用,交通灯初始化
initial
begin
order = 2'b00;
light(red, amber, green, 0, order);
end
//任务调用,交通灯控制时序
always
begin
order=2’b01;
light(red, amber, green,RED_TICS,order);//调用开灯任务,开红灯
order=2'b10;
light(red, amber, green,GREEN_TICS,order);//调用开灯任务,开绿灯
order=2'b11;
light(red, amber, green,AMBER_TICS,order);//调用开灯任务,开黄灯
end
endmodule
5.2函数
1.函数的定义 function<返回值类型或位宽><函数名>;
<输入参量与类型声明>
<局部变量声明>
begin
语句1;
语句;
...
语句n;
end
endfunction
函数定义是嵌入在关键字function和endfunction之间的,其中关键词function标志着一个函数定义结构的开端,endfunction标志着一个函数定义结构的结束。"<函数名>"是给被定义函数取的名称。这个函数名在函数定义结构内部还代表着一个内部变量,函数调用后的返回值是通过这个函数名变量传递给调用语句的。
<返回值类型或位宽>是一个可选项,它是用来对函数调用返回数据的类型或宽度进行说明,它可以有如下三种形式: (1)“[msb Isb]”:这种形式说明函数名所代表的返回数据变量时一个多位的寄存器变量,它的位宽由[ msb:lsb]指定,比函数定义语句:
function[7:0] adder;
就定义了一个函数"adder",它的函数名"adder"还代表着一个8位宽的寄存器变量,其中最高位为第7位,最低位为第0位。 (2)“integer”:这种形式说明函数名代表的返回变量是一个整数型变量。 (3)“real”:这种形式说明函数名代表的返回变量是一个实数型变量。
"<输入参量与类型声明> "是对函数各个输入端口的宽度和类型进行说明,在函数定义中,必须至少有一个输入端口(input)的声明,不能有输出端口(output)的声明。数据类型声明语句用来对函数内用到的局部变量进行宽度和类型说明,这个说明语句的语法与进行模块定义时的相应说明语句语法是一致的。 "<局部变量说明>"是对函数内部局部变量进行宽度和类型的说明。 由"begin与"end"关键词界定的一系列语句和任务一样,用来指明函数被调用时要执行的操作,在函数被调用时,这些语句将以串行方式得到执行。
例:统计输入数据中"0"的个数
function[3:0] out;
input[7:0] x;
reg[3:0] count;
integer i;
begin
count=0;
for(i=0;i<=7;i=i+1;)
if(x[i]==1'b0)
count=count+1;
out0=count;
end
endmodule
在进行函数定义时需要注意以下几点 (1)与任务一样,函数定义结构只能出现在模块中,而不能出现在过程块内。 (2)函数至少必须有一个输入端口。 (3)函数不能有任何类型的输出端口(output端口)和双向端口(inout端口)。 (4)在函数定义结构中的行为语句部分内不能出现任何类型的时间控制描述,也不允许使用disable终止语句。 (5)与任务定义一样,函数定义结构内部不能出现过程块。 (6)在一个函数内可以对其它函数进行调用,但是函数不能调用其它任务。 (7)在第一行"function"语句中不能出现端口名列表。 (8)在函数声明的时候,在Verilog的内部隐含地声明了一个名为function_identifier(函数标识符)的寄存器类型变量,函数的输出结果将通过这个寄存器类型变量被传递回来。
2.函数的调用 函数的调用是通过将函数作为表达式中的操作数来实现的。函数的调用格式如下: <函数名>(<输入表达式1>,<输入表达式2>,...,<输入表达式n>);
其中,输入表达式应与函数定义结构中说明的输入端口一 一对应,它们代表着各个输入端口的输入数据。 函数调用时要注意以下几点: (1)函数的调用不能单独作为一条语句出现,它只能作为一个操作数出现在调用语句内。 (2)函数的调用既能出现在过程块中,也能出现在assign连续赋值语句中。 (3)函数定义中声明的所有局部寄存器都是静态的,即函数中的局部寄存器在函数的多个调用之间保持它们的值。
module tryfact_tb;
function[31:0] factorial;
input[3:0] operand;
reg[3:0] index;
begin
factorial = 1;
for(index=1;index<=operand;index=index+1)
factorial = index * factorial;
end
endfunction
reg[31:0] result;
reg[3:O] n;
initial
begin
result=1;
for(n=1;n<=9;n=n+1)
begin
result = factorial(n);
$display("n= %d result= %d", n, result);
end
end
endmodule
上例由函数定义和initia|过程块构成,其中定义了一个名为factorial函数,该函数是一个进行阶乘运算的函数,具有一个4位的输入端口,同时返回一个32位的寄存器类型的值;在initial块中定义了两个寄存器变量分别为32位的result和4位的n,initial块对1至9进行阶乘运算,并打印出结果值。
5.3任务与函数的区别
6.典型测试向量的设计
6.1变量初始化
在Verilog语言中,有两种方法可以初始化变量 一种是利用初始化变量,另一种就是在定义变量时直接赋值初始化。这两种初始化任务是不可综合的,主要用于仿真过程。 (1)initial初始化方式 在大多数情况下,Testbench中变量初始化的工作通过initial过程块来完成,可以产生丰富的仿真激励。 initial语句只执行一次,即在设计被开始模拟执行时开始(0时刻)直到过程结束,专门用于对输入信号进行初始化和产生特定的信号波形。一个Testbench可以包含多initial过程语句块,所有的initia|过程都同时执行需要注意的是,initial语句中的变量必须为reg类型。
例:利用initial初始化方式的测试向量产出
module counter(clk,cnt);
output [3:0] cnt;
reg clk;
reg [3:0] temp;
initial temp = 0;
initial clk = 0;
endmodule
(2)定义变量时初始化在定义变量时初始化的语法非常简单,直接用"="在变量右端赋值即可,如: reg [7:0] cnt=8’b00000000; 就将8比特的寄存器变量cnt初始化为0。
6.2数据信号测试向量产生
数据信号的产生有两种形式:其一是初始化和产生都在单个initial块中进行;其一是初始化在initial语句中完成,而产生在always语句块中完成。前者适合不规则数据序列,并且要求长度较短;后者适合具有一定规律的数据序列,长度不限。
例:产生位宽为4的质数序列{1、2、3、5、7、11、13 },并且重复两次,其中样值间隔为4个仿真时间单位 由于该序列无明显规律,因此利用Initial语句最为合适。
`timescale 1ns/1ps
module sequence_tb;
reg [3:0] qout;
parameter sample_period = 4;
parameter queue_num = 2;
initial
begin
q_out =0;
repeat( queue_num)
begin
# sample_period q_out = 1;
# sample_period q_out = 2;
# sample_period q_out = 3;
# sample_period q out = 5;
# sample_period q_out = 7;
# sample_period q_out= 11;
# sample_period q_out = 13;
end
end
e ndmodule
6.3时钟信号测试向量产生
例:产生占空比为50%的时钟信号 (1)基于initial语句的方法
module clk1(clk);
output clk;
parameter clk_period = 10;
reg clk;
initial
begin
clk = 0;
forever #(clk_period/2) clk = ~clk;
end
endmodule
(2)基于always语句的方法
module clk2(clk);
output clk;
parameter clk_period = 10;
reg clk;
initial clk = 0;
always #(clk_period/2) clk = ~clk;
endmodule
6.4总线信号测试向量产生
总线是运算部件之间数据流通的公共通道。在RTL级描述中,总线指的是由逻辑单元、寄存器、存储器、电路输入或其它总线驱动的一个共享向量。而总线功能模型则是一种将物理的接口时序操作转化成更高抽象层次接口的总线模型,如图: 在总线中,对于每个请求端,有一个输入来选择驱动该总线所对应的请求端。选择多个请求端会产生总线冲突,根据总线的类型,冲突会产生不同的结果。当有多个请求端发出请求时,相应的操作由总线的类型决定。在Verilog测试中,总线测试信号通常是通过将片选信号,读(或者写)使能信号、地址信号以及数据信号以task任务的形式来描述,通过调用以task形式的总线信号测试向量来完成相应的总线功能 。 下面以工作频率为100MHz的AHB总线写操作为例,说明以task方式产生总线信号测试向量的方式。下图是AHB总线写操作的时序图,其中,在完成数据的写操作后将片选和写使能信号置为无效(低电平有效)。
例:产生一组具有写操作AHB总线功能模型
module bus_wr_tb;
reg clk;
reg cs;
reg wr;
reg [31:0] addr;
reg [31:0] data:
initial
begin
cs=1'b1;
wr=1'b1;
#30;
bus_wr(32'h1100008a, 32’h11113000);
bus_wr(32’h1100009a, 32'h11113001);
bus_wr(32'h110000aa, 32'h11113002);
bus_wr(32'h110000ba, 32’h11113003);
bus_wr(32'h110000ca, 32’h11113004);
addr=32’bx;
data=32’bx;
end
initial clk=1;
always #5 clk=~clk;
task bus_wr;
input [31:0] ADDR;
input [31:0] DATA;
begin
cs=1'b0;
wr=1'b0;
addr = ADDR;
data = DATA;
#30 cs=1'b1;
wr=1'b1;
end
endtask
endmodule
7.用户自定义元件模型UDP
通过UDP,可以把一块组合逻辑电路或时序逻辑电路封装在一个UDP内,并把这个UDP作为一个基本门元件来使用。需要注意的是,UDP是不能综合的,只能用于仿真。
7.1UDP的定义与调用
UDP的定义格式如下:
primitive <元件名称>(<输出端口名>,<输入端口名1 >,<输入端口名2>,...,<输入端口名n>)
输出端口类型声明(output);
输入端口类型声明(input);
输出端口寄存器变量说明(reg);
元件初始状态说明(initial);
table
;
;
...
;
endtable
endprimitive
和Verilog中的模块相比,UDP具备以下特点。 (1)UDP的输出端口只能有一个,且必须位于端口列表的第一项。只有输出端口能定义为reg类型。 (2)UDP的输入端可有多个,一般时序电路UDP的输入端口最多9个,组合电路UDP 的输入端口可多至10个。 (3)所有端口变量的位宽必须是1比特。 (4)在table表项中,只能出现0、1、x这三种状态,z将被认为是x状态。
根据UDP包含的基本逻辑功能,可以将UDP分为组合电路UDP、时序电路UDP及混合电路UDP,这几类UDP的差别主要体现在table表项的描述上。 UDP的调用和Verilog中模块的调用方法相似,通过位置映射,其语法格式如下: UDP名 例化名(连接端口1信号名,连接端口2信号名,连接端口3信号名,...);
例:用UDP方式定义一个全加器仿真模型
primitive summ(sum, cin, a, b);//本位和
output sum;
input a,b,cin;
table
//cin a b : sum
0 0 0 : 0;
0 0 1 : 1;
0 1 0 : 1;
0 1 1 : 0;
1 0 0 : 1;
1 0 1 : 0;
1 1 0 : 0;
1 1 1 : 1;
endtable
endprimitive
primitive summ(sum, cin, a, b);//进位
output cout;
input a,b,cin;
table
//cin a b : sum
0 0 0 : 0;
0 0 1 : 0;
0 1 0 : 0;
0 1 1 : 1;
1 0 0 : 0;
1 0 1 : 1;
1 1 0 : 1;
1 1 1 : 1;
endtable
endprimitive
7.2UDP应用实例
(1)组合电路UDP元件 组合逻辑电路的功能列表类似真值表,就是规定了不同的输入值和对应的输出值,表中每一行形式是output,input1,input2,…,排列顺序和端口列表中的顺序相同,合电路UDP的输入端口可多至10个。如果某个输入组合没有定义的输出,那么就把这种情况的输出置为x。
例:3选1多路选择器
primitive mux3_1(Y,in0,in1,in2,s2,s1);
input in0,in1,in2,s2,s1;
output Y;
table
//in0 in1 in2 s2 s1 : Y
0 ? ? 0 0 : 0;//当s2s1=00时,Y=in0
1 ? ? 0 0 : 1;
? 0 ? 0 1 : 0;//当s2s1=01时,Y=in1
? 1 ? 0 1 : 1;
? ? 0 1 ? : 0;//当s2s1=1?时,Y=in2
? ? 1 1 ? : 1;
0 0 ? 0 ? : 0;
1 1 ? 0 ? : 1;
0 ? 0 ? 0 : 0;
1 ? 1 ? 0 : 1;
? 0 0 ? 1 : 0;
? 1 1 ? 1 : 1;
endtable
endprimitive
(2)时序电路UDP元件 UDP还可以描述具有电平触发和边沿触发特性的时序电路。时序电路拥有内部状态序列,其内部状态必须用寄存器变量进行建模,该寄存器的值就是时序电路的当前状态,它的下一个状态是山放在基元功能列表中的状态转换表决定的,而且寄存器的下一个状态就是这个时序电路UDP的输出值。所以,时序电路UDP由两部分组成一状态寄存器和状态列表。定义时序UDP的工 作也分为两部分一初始化状态寄存器和描述状态列表。 在时序电路的UDP描述中,01、Ox、xl代表着信号的上升沿。下面给出一个上升沿D触发器的UDP开发实例。
例:通过Verilog给出D触发器UDP描述,并在模块中调用UDP组件
primitive D_Edge(Q,Clk,Data);
output Q;
reg Q;
input Data,Clk;
initial Q = 0;
table
//Clk Data : Q(Stata): Q(next)
(01) 0 : ? : 0;
(01) 1 : ? : 1;
(0x) 1 : 1 : 1;
(0x) 0 : 0 : 0;
(?0) ? : ? : -;// 忽略时钟负边沿
? (??) : ? : -;// 忽略在稳定时钟上的数据变化
endtable
endprimitive;
表项(01)表示从0转换到1,表项(0x)表示从0转换到x,表项(?0)表示从任意值(0、1或x)转换到0,表项(??)表示任意转换,输出默认为x。假定D_Edge为UDP定义,它现在就能像基本门一样在模块中使用。
(3)混合电路UDP元件 在同一个表中能够混合电平触发和边沿触发项。在这种情况下,边沿变化在电平触发之前处理,即电平触发项覆盖边沿触发项。下面给出一段带异步清空的D触发器的UDP描述。 例:利用Verilog语言完成异步清零D触发器的UDP描述
primitive D_Async_FF(0, Clk, Clr, Data);
output Q;
reg Q;
input Clk, Data, Clr;
table
//Clk Clr Data : (SQtate) : Q(next)
(01) 0 0 : ? : 0;
(01) 0 0 : ? : 0;
(0x) 0 1 : 1 : 1;
(0x) 0 0 : 0 : 0;
(?0) 0 ? : ? : -;
(??) 0 ? : ? : -;
? 1 ? : ? : 0;
endtable
endprimitive
8.基本门级元件和模块的延时建模
8.1门级延时建模
门级延时可以分为如下几类: (1)“上升延时”:表示信号由"x"或"z"状态变化到"1"状态时受到的门传输延时。 (2)“下降延时”:表示信号由"1",“x"或"z"状态变化到"0"状态时受到的门传输延时。 (3)“到不定态的延时”:表示信号由"0”、“1"或"z"状态变化到"x"状态时受到的门传输延时。 (4)“截止延时”:表示信号由"0”、"1"或"x"状态变化到"z"状态时受到的门传输延时。
1.门级延时的基本延时表达形式 在门级延时的基本表达形式下,“delay"内可以0至3个延时值,下表给出了指定的不同延时值个数时,delay的4种表达形式。 (1)当"delay"没有指定门延时值,则默认的延时值为0。这意味着元件实例的"上升延时值”、“下降延时值”、“截止延时值"和"到不定态的延时值"均为0。 在实例:notif1 U0(out, in, ctrl); 门级延时值为"0”,因为没有定义延迟,则元件实例UO的"上升延时值"、“下降延时值”、“截止延时值"和"到不定态的延时值"均为0。 (2)当"delay"内只包含1个延时值时,给定的延时值"d"将同时代表着元件实例的"上升延时值"、“下降延时值”、“截止延时值"和"到不定态的延时值”。在下面的实例引用中, notif1 #20 U1(out, in, ctrl); 门级延时值为"20",且只包含1个延时值,说明元件实例U1的所有类型的门级延时都是20个单位时间。 (3)当"delay"内包含了2个延时值时,元件实例的"上升延时值"由给定的“d1"指定;“下降延时值"由给定的"d2"指定;而"截止延时值"和"到不定态的延时值”“将由"dl"和"d2"中的最小值指定。在实例中: notif1 #(10,20)U2(out, in, ctrl); 门级延时值为”(10,20)“,包含了2个延时值10和20,这表明元件实例U2将具有10个单位时间的"上升延时"和20个单位时间的"下降延时”,而它的"截止延时"和"到不定态的延时"将是10和20中的最小值指定,即为10个单位时间。 (4)当"delay"内包含了3个延时值,元件实例的"上升延时值"由给定的"dA"指定;“下降延时值"由给定的“dB"指定;“截止延时"由给定的"dC '指定;而它的"到不定态的延时"将由dA、dB和dC中的最小值指定。在实例: notif1 #(10,20,30)U3(out, in, ctrl); 门级延时值为“ 00,20,30)”,包含了3个延时值10、20和30,这表明元件实例IJ3具有10个单位时间的“上升延时”、20个单位时间的“下降延时"和30个单位时间的“截止延时",而它的“到不定态的延时"将有 10、20和30中的最小值指定,即为10个单位时间。
2.门级延时的最小、典型、最大延时表达形式 除了基本延时表达形式外,门级延时量还可以采用”最小、典型、最大“延时表达形式,在这种表示方式下,门级延时量中的每一项将由“最小延时"、“典型延时"和”最大延时"二个值来表示,其语法格式如下: #(d min:d_typ:d_max)
采用"最小、典型、最大"延时表达形式时,delay"内可以包含为1至3个延时值,如下列几种情况:
#(dA_min: dA_typ: dA_max) #(dA_min: dA_typ: dA_max, dB_min: dB_typ: dB_max) #(dA_min :dA_typ: dA_max, dB_min: dB_typ: dB_max, dC_min: dC_typ: dC_max)
在实例:and #(4:5:6) U1(out,i1,i2); “delay"中只包含1个延迟值,其最小值为4、典型值为5、最大值为6。元件实例UI的"上升延时值”、“下降延时值”、"截止延时值"和“到不定态的延时值"如下表:
最小延时
上升延时=4
下降延时:4
到不定态的延时 =4
关断延时:4
典型延时
上升延时:5
下降延时=5
到不定态的延时
关断延时:5
最大延时
上升延时=6
下降延时=6
到不定态的延时
关断延时= 6
在实例:and #(3:4:5,5:6:7)U2(out, i1,i2); "delay"中包含了2个延迟值,第一个延迟值的最小值为3、典型值为4、最大值为5,第二个延迟值的最小值为5、典型值为6、最大值为7。元件实例U2的"上升延时值"由第一个延时值指定,下降延时值"山第二个延时值指定,"到不定态的延时值"和"截止延时值"均由两个延时值的最小值指定。各值的取值情况如下表:
最小延时
上升延时=3
下降延时=5
到不定态的延时=min(3,5)
关断延时=min(3,5)
典型延时
上升延时=4
下降延时=6
到不定态的延时=min(4,6)
关断延时=min(4,6)
最大延时
上升延时=5
下降延时=7
到不定态的延时=min(5,7)
关断延时=min(5,7)
and # (2:3:4,3:4:5,4:5:6) U3(out,i1,i2);
"delay"中包含了三个延迟值,第一个延迟值的最小值为2、典型值为3、最大值为4,第二个延迟值的最小值为3、典型值为4、最大值为5,第三个延迟值的最小值为4、典型值为5、最大值为6。元件实例U3的"上升延时值"由第一个延时值指定,"下降延时值"由第二个延时值指定,"截止延时值"由第三个延时值指定,而它的"到不定态的延时值"由三个延时值的最小值指定。各值的取值情况如下表。
最小延时
上升延时=2
下降延时=3
到不定态的延时=min(2,3,4)
关断延时=4
典型延时
上升延时=3
下降延时=4
到不定态的延时=min(3,4,5)
关断延时= 5
最大延时
上升延时=4
下降延时=5
到不定态的延时=min(4,5,6)
关断延时= 6
例:用Verilog建立模块D的延迟仿真模块 其门级实现如模块D的逻辑图如下,其中包含了延时时间为5个单位时间的与门和一个延时时间为4个单位时间的或门。 带有延迟的模块D代码:
module D(out,a,b,c);
output out;
input a,b,c;
wire e;
and #(5) a1(e,a,b);
or #(4) o1(out, e,c);
endmodule
带有延时的模块D的测试激励模块:
module D_tb;
reg A,B,C;
wire OUT;
D d1(.out(OUT), .a(A), .b(B), .c(C));
initial
begin
A=1'b0;B=1'b0;C=1'b0;
#10 A=1'b1;B=1'b1;C=1'b1;
#10 A=1'b1;B=1'b0;C=1'b0;
#20 $finish;
end
endmodule
8.2模块延时建模
1.延时说明块Specify Block 在模块输入和输出引脚之间的延迟称为模块路径延迟。在Verilog中,在关键字specify和endspecify之间给路径延迟赋值,关键字之间的语句组成specify块(即指定块)。"specify"与"endspeclfy"分别是延时说明块的起始标识符和终止标识符。
Specify块包含下列操作语句: (1)定义穿过模块的所有路径延迟 (2)在电路中设置时序检查 (2)定义specparam常量
例:上图为例,用specify块来描述途中M模块的路径延迟。代码如下:
module M(out,a,b,c,d);
input a,b,c,d;
output out;
wire e,f;
assign out=(a&b)|(c&b);//逻辑功能
specify //包含路径延迟语句的specify块
(a=>out)=9;
(b=>out)=9;
(c=>out)=11;
(d=>out)=11;
endspecify;
endmodule
2.径延迟描述方式 (1)并行连接 每条路径延迟语句都有一个源域或一个目标域。在上例的路径延迟语句中,a、b、c和d在源域位置,而out是目标域。 在specify块中,用符号"=> "说明并行连接,其语法格式如下: (=>)=;
其中可以包含1至3个延时量,也可以采用"最小、典型、最大"延时表达形式。在延时量由多个值组成的情况下,应在延时量的外面加上一对括号例如 (a=>out)=(8,9,10); 表示的是输入a到输出b的延迟最小、典型和最大延迟分别是8、9、10个时间单位。
在并行连接中,源域中的每一位与目标域中相应的位连接。如果源和目标域是向量,必须有相同的位数,否则会出现不匹配。因此,并行连接说明了源域的每一位到目标域的每一位之间的延迟。 下图显示了源域和目标域之间的位是如何并行连接的。同时例给出了并行连接的Verilog描述。
(2)全连接 在specify块中,用符号"*>"表示全连接,其语法格式如下: (*>)=;
在全连接中,源域中的每一位与目标域中的每一位相连接。如果源和目标是向量,则它们不必位数相同。全连接描述源中的每一位和目标中的每一位之间的延迟,如下图所示:
3.spacparam声明语句 spacparam用来定义specify块中的参数,如下例使用spacparam语句的specify块示例
module parallel_connected(out, a, b);
input a, b;
output out;
wire out;
assign out=a&b; //逻辑功能
//在指定块内部定义参数
specify
specparam a_to_out = 9;
specparam b_to_out = 11;
(a => out) = a_to_out;
(b => out) = b_to_out;
endspecify
endmodule
specparam语句的格式和作用都类似于parameter参数说明语句,但两者又有不同: (1)specparam语句只能在延时说明块(specify块)中出现;而parameter 语句则不能在延时说明块内出现。 (2)由specparam语句进行定义的参数只能是延时参数;而由parameter语句定义的参数可以是任何数据类型的常数参数。 (3)由specparam语句定义的延时参数只能在延时说明块内使用;而 parameter语句定义的参数则可以在模块内的任意位置处使用。 在模块中提供specify参数是为了方便给延迟赋值,建议用specify参数而不是数值来表示延迟。这样,如果电路的时序说明变化了,用户只需要改变 specify参数值,而不必逐个修改每条路径的延迟值。
8.3与时序检查相关的系统任务
9.编译预处理语句
编译预处理是Verilog编译系统的一个组成部分,指编译系统会对一些特殊命令进行预处理,然后将预处理结果和源程序一起再进行通常的编译处理。以"`"(反引号)开始的某些标识符是编译预处理语句。在verilog语言编译时,特定的编译器指令在整个编译过程中有效(编译过程可跨越多个文件),直到遇到其它的不同编译程序指令。常用的编译预处理语句如下:
9.1宏定义
`define指令是一个宏定义命令,通过一个指定的标识符来代表一个字符串,可以增加Verilog HDL代码的可读性和可维护性,找出参数或函数不正确或不允许的地方。 `define指令像C语言中的#define指令,可以在模块的内部或外部定义,编译器在编译过程中,遇到该语句将把宏文本替换为宏的名字。 `define的声明语法格式如下: `define 对于己声明的语法,在代码中的应用格式如下所示,不要漏掉宏名称前的"`"。 `macro_name 例如: `define MAX_BUS_SIZE 32 … reg [`MAX_BUS_SIZE-1:0] AddReg;
一旦`define指令被编译,其在整个编译过程中都有效。例如,通过另一个文件中的`define指令MAX_BUS_SIZE能被多个文件使用。 `undef指令取消前面定义的宏。例如: `define WORD 16 //建立一个文本宏替代 … wire[`WORD:1] Bus; … `undef WORD //在`undef编译指令后,WORD的宏定义不再有
关于宏定义指令,有下面8条规则需要注意。 (1)宏定义的名称可以是大写,也可以是小写,但要注意不要和变量名重复。 (2)和所有编译器伪指令一样,宏定义在超过单个文件边界时仍有效(对工程中的其它源文件),除非被后面的`define,`undef或`resetall伪指令覆盖,否则`define不受范围限制。 (3)当用变量定义宏时,变量可以在宏正文使用,并且在使用宏的时候可以用实际的变量表达式代替。 (4)通过用反斜杠"\"转义中间换行符,宏定义可以跨越几行,新的行是宏正文的一部分。 (5)宏定义行末不需要添加分号表示结束。 (6)宏正文不能分离的语言记号包括注释、数字、字符串、保留的关键字、运算符。 (7)编译器伪指令不允许作为宏的名字。 (8)宏定义的文本也可以是一个表达式。
`define和parameter是有区别的,`define和parameter都可以用于完成文本替换,但其存在本质上的不同,前者是编译之前就预处理,而后者是在正常编译过程中完成替换的。此外,`define和parameter存在下列两点不同之处。 (1)作用域不同:parameter作用于声明的那个文件;`define从编译器读到这条指令开始到编译结束都有效,或者遇到`undef命令使之失效,可以应用于整个工程。如果要让parameter作用于整个项目,可以将声明语句写于单独文件,并用`include让每个文件都包含声明文件。 `define也可以写在代码的任何位置,而parameter则必须在应用之前定义。通常编译器都可以定义编译顺序,或者从最底层模块开始编译,因此写在最底层就可以了。 (2)传递功能不同:parameter可以用作模块例化时的参数传递,实现参数化调用:`define语句则没有此作用。`define语句可以定义表达式,而parameter只能用于定义变量。
9.2文件包含处理
所谓“文件包含处理"是一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中。Verilog语言提供了`include命令用来实现"文件包含"的操作。其一般形式为:include “文件名”。
9.3仿真时间标度
在这条命令中,时间单位参量是用来定义模块中仿真时间和延迟时间的基准单位的。时间精度参量是用来声明该模块的仿真时间的精确程度的,该参量被用来对延迟时间值进行取整操作(仿真前),因此该参量又可以被称为取整精度。如果在同一个程序设计里,存在多个`timescale命令,则用最小的时间精度值来决定仿真的时间单位。另外,时间精度至少要和时间单位一样精确,时间精度值不能大于时间单位值。 在`timescale命令中,用于说明时间单位和时间精度参量值的数字必须是整数,其有效数字为1、10、100,单位为秒(s)、毫秒(ms)、微秒(us)、纳秒(ns)、皮秒(p司、亳皮秒〈fs)。下面举例说明`timescale命令的用法。 例仿真时间标度举例 (1)`timescale 1ns/1ps 模块中所有的时间值都表示是1ns的整数倍。这是因为在`timescale命令中,定义了时间单位是1ns。模因为`timescale命令定义时间精度为1ps,块中的延迟时间可表达为带三位小数的实型数。 (2)`timescale 10us/100ns 在这个例子中,模块中时间值均为10us的整数倍。因为`timesacle命令定义的时间单位是10us。延迟时间的最小分辨度为十分之一微秒(100ns),即延迟时间可表达为带一位小数的实型数。
9.4条件编译命令
9.5其他语句
10.Verilog测试方法简介
在集成电路测试领域,常用的测试方法有完全测试法、随机测试法和自动测试法。 (1)完全测试法对于复杂的设计来说,常常通过检查代码的覆盖率来检查验证工作是否完成的一种重要方法。代码覆盖率可以指示Verilog代码描述的功能有多少在仿真过程中被验证过。通常代码覆盖率包括以下内容: ·语句覆盖率 ·路径覆盖率 ·状态机覆盖率 ·触发覆盖率 ·表达式覆盖率 (2)随机测试法 在Verilog中提供了多个用于随机测试的系统命令,通常使用随机测试的系统函数来仿真真实应用的情况,如在通信领域中常用的帧同步搜索电路需要从接收的数据流中检测发送端固定插入的某个特殊的码型,而数据本身也有可能包括该码型,在这种情况下进行随机化测试就更接近于真实应用的情况。其中最常用的系统命令是随机数产生系统任务$random。 (3)自动测试法 在集成电路测试领域,全面准确的测试才能保证大规模集成电路的正常工作,而确保一个设计能够得到全面测试的唯一途径就是实现任务的自动化。通常通过创建一个检验表,使用相应个数的采样值。当修改过源代码后,所有的测试程序都自动被再次执行。但需要注意,使用自动测试可能会存在截断误差。
来源:蔡觉平老师的Verilog课程
你可能感兴趣的:(Verilog学习笔记,学习,fpga开发)
情绪觉察日记第37天
露露_e800
今天是家庭关系规划师的第二阶最后一天,慧萍老师帮我做了个案,帮我处理了埋在心底好多年的一份恐惧,并给了我深深的力量!这几天出来学习,爸妈过来婆家帮我带小孩,妈妈出于爱帮我收拾东西,并跟我先生和婆婆产生矛盾,妈妈觉得他们没有照顾好我…。今晚回家见到妈妈,我很欣赏她并赞扬她,妈妈说今晚要跟我睡我说好,当我们俩躺在床上准备睡觉的时候,我握着妈妈的手对她说:妈妈这几天辛苦你了,你看你多利害把我们的家收拾得
机器学习与深度学习间关系与区别
ℒℴѵℯ心·动ꦿ໊ོ꫞
人工智能 学习 深度学习 python
一、机器学习概述定义机器学习(MachineLearning,ML)是一种通过数据驱动的方法,利用统计学和计算算法来训练模型,使计算机能够从数据中学习并自动进行预测或决策。机器学习通过分析大量数据样本,识别其中的模式和规律,从而对新的数据进行判断。其核心在于通过训练过程,让模型不断优化和提升其预测准确性。主要类型1.监督学习(SupervisedLearning)监督学习是指在训练数据集中包含输入
铭刻于星(四十二)
随风至
69夜晚,绍敏同学做完功课后,看了眼房外,没听到动静才敢从书包的夹层里拿出那个心形纸团。折痕压得很深,都有些旧了,想来是已经写好很久了。绍敏同学慢慢地、轻轻地捏开折叠处,待到全部拆开后,又反复抚平纸张,然后仔细地一字字默看。只是开头的三个字是第一次看到,让她心漏跳了几拍。“亲爱的绍敏:从四年级的时候,我就喜欢你了,但是我一直不敢说,怕影响你学习。六年级的时候听说有人跟你表白,你接受了,我很难过,但
【iOS】MVC设计模式
Magnetic_h
ios mvc 设计模式 objective-c 学习 ui
MVC前言如何设计一个程序的结构,这是一门专门的学问,叫做"架构模式"(architecturalpattern),属于编程的方法论。MVC模式就是架构模式的一种。它是Apple官方推荐的App开发架构,也是一般开发者最先遇到、最经典的架构。MVC各层controller层Controller/ViewController/VC(控制器)负责协调Model和View,处理大部分逻辑它将数据从Mod
UI学习——cell的复用和自定义cell
Magnetic_h
ui 学习
目录cell的复用手动(非注册)自动(注册)自定义cellcell的复用在iOS开发中,单元格复用是一种提高表格(UITableView)和集合视图(UICollectionView)滚动性能的技术。当一个UITableViewCell或UICollectionViewCell首次需要显示时,如果没有可复用的单元格,则视图会创建一个新的单元格。一旦这个单元格滚动出屏幕,它就不会被销毁。相反,它被添
学点心理知识,呵护孩子健康
静候花开_7090
昨天听了华中师范大学教育管理学系副教授张玲老师的《哪里才是学生心理健康的最后庇护所,超越教育与技术的思考》的讲座。今天又重新学习了一遍,收获匪浅。张玲博士也注意到了当今社会上的孩子由于心理问题导致的自残、自杀及伤害他人等恶性事件。她向我们普及了一个重要的命题,她说心理健康的一些基本命题,我们与我们通常的一些教育命题是不同的,她还举了几个例子,让我们明白我们原来以为的健康并非心理学上的健康。比如如果
Linux下QT开发的动态库界面弹出操作(SDL2)
13jjyao
QT类 qt 开发语言 sdl2 linux
需求:操作系统为linux,开发框架为qt,做成需带界面的qt动态库,调用方为java等非qt程序难点:调用方为java等非qt程序,也就是说调用方肯定不带QApplication::exec(),缺少了这个,QTimer等事件和QT创建的窗口将不能弹出(包括opencv也是不能弹出);这与qt调用本身qt库是有本质的区别的思路:1.调用方缺QApplication::exec(),那么我们在接口
ArcGIS栅格计算器常见公式(赋值、0和空值的转换、补充栅格空值)
研学随笔
arcgis 经验分享
我们在使用ArcGIS时通常经常用到栅格计算器,今天主要给大家介绍我日常中经常用到的几个公式,供大家参考学习。将特定值(-9999)赋值为0,例如-9999.Con("raster"==-9999,0,"raster")2.给空值赋予特定的值(如0)Con(IsNull("raster"),0,"raster")3.将特定的栅格值(如1)赋值为空值,其他保留原值SetNull("raster"==
【一起学Rust | 设计模式】习惯语法——使用借用类型作为参数、格式化拼接字符串、构造函数
广龙宇
一起学Rust # Rust设计模式 rust 设计模式 开发语言
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、使用借用类型作为参数二、格式化拼接字符串三、使用构造函数总结前言Rust不是传统的面向对象编程语言,它的所有特性,使其独一无二。因此,学习特定于Rust的设计模式是必要的。本系列文章为作者学习《Rust设计模式》的学习笔记以及自己的见解。因此,本系列文章的结构也与此书的结构相同(后续可能会调成结构),基本上分为三个部分
回溯 Leetcode 332 重新安排行程
mmaerd
Leetcode刷题学习记录 leetcode 算法 职场和发展
重新安排行程Leetcode332学习记录自代码随想录给你一份航线列表tickets,其中tickets[i]=[fromi,toi]表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。所有这些机票都属于一个从JFK(肯尼迪国际机场)出发的先生,所以该行程必须从JFK开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。例如,行程[“JFK”,“LGA”]与[“JFK”,“LGB
Python数据分析与可视化实战指南
William数据分析
python python 数据
在数据驱动的时代,Python因其简洁的语法、强大的库生态系统以及活跃的社区,成为了数据分析与可视化的首选语言。本文将通过一个详细的案例,带领大家学习如何使用Python进行数据分析,并通过可视化来直观呈现分析结果。一、环境准备1.1安装必要库在开始数据分析和可视化之前,我们需要安装一些常用的库。主要包括pandas、numpy、matplotlib和seaborn等。这些库分别用于数据处理、数学
2019-12-22-22:30
涓涓1016
今天是冬至,写下我的日更,是因为这两天的学习真的是能量的满满,让我看到了自己,未来另外一种可能性,也让我看到了这两年这几年的过程中我所接受那些痛苦的来源。一切的根源和痛苦都来自于人生,家庭,而你的原生家庭,你的爸爸和妈妈,是因为你这个灵魂在那一刻选择他们作为你的爸爸和妈妈来的,所以你得接受他,你得接纳他,他就是因为他的存在而给你的学习和成长带来这些痛苦,那其实是你必然要经历的这个过程,当你去接纳的
linux sdl windows.h,Windows下的SDL安装
奔跑吧linux内核
linux sdl windows.h
首先你要下载并安装SDL开发包。如果装在C盘下,路径为C:\SDL1.2.5如果在WINDOWS下。你可以按以下步骤:1.打开VC++,点击"Tools",Options2,点击directories选项3.选择"Includefiles"增加一个新的路径。"C:\SDL1.2.5\include"4,现在选择"Libaryfiles“增加"C:\SDL1.2.5\lib"现在你可以开始编写你的第
将cmd中命令输出保存为txt文本文件
落难Coder
Windows cmd window
最近深度学习本地的训练中我们常常要在命令行中运行自己的代码,无可厚非,我们有必要保存我们的炼丹结果,但是复制命令行输出到txt是非常麻烦的,其实Windows下的命令行为我们提供了相应的操作。其基本的调用格式就是:运行指令>输出到的文件名称或者具体保存路径测试下,我打开cmd并且ping一下百度:pingwww.baidu.com>./data.txt看下相同目录下data.txt的输出:如果你再
PHP环境搭建详细教程
好看资源平台
前端 php
PHP是一个流行的服务器端脚本语言,广泛用于Web开发。为了使PHP能够在本地或服务器上运行,我们需要搭建一个合适的PHP环境。本教程将结合最新资料,介绍在不同操作系统上搭建PHP开发环境的多种方法,包括Windows、macOS和Linux系统的安装步骤,以及本地和Docker环境的配置。1.PHP环境搭建概述PHP环境的搭建主要分为以下几类:集成开发环境:例如XAMPP、WAMP、MAMP,这
使用 FinalShell 进行远程连接(ssh 远程连接 Linux 服务器)
编程经验分享
开发工具 服务器 ssh linux
目录前言基本使用教程新建远程连接连接主机自定义命令路由追踪前言后端开发,必然需要和服务器打交道,部署应用,排查问题,查看运行日志等等。一般服务器都是集中部署在机房中,也有一些直接是云服务器,总而言之,程序员不可能直接和服务器直接操作,一般都是通过ssh连接来登录服务器。刚接触远程连接时,使用的是XSHELL来远程连接服务器,连接上就能够操作远程服务器了,但是仅用XSHELL并没有上传下载文件的功能
关于提高复杂业务逻辑代码可读性的思考
编程经验分享
开发经验 java 数据库 开发语言
目录前言需求场景常规写法拆分方法领域对象总结前言实际工作中大部分时间都是在写业务逻辑,一般都是三层架构,表示层(Controller)接收客户端请求,并对入参做检验,业务逻辑层(Service)负责处理业务逻辑,一般开发都是在这一层中写具体的业务逻辑。数据访问层(Dao)是直接和数据库交互的,用于查数据给业务逻辑层,或者是将业务逻辑层处理后的数据写入数据库。简单的增删改查接口不用多说,基本上写好一
四章-32-点要素的聚合
彩云飘过
本文基于腾讯课堂老胡的课《跟我学Openlayers--基础实例详解》做的学习笔记,使用的openlayers5.3.xapi。源码见1032.html,对应的官网示例https://openlayers.org/en/latest/examples/cluster.htmlhttps://openlayers.org/en/latest/examples/earthquake-clusters.
【加密社】Solidity 中的事件机制及其应用
加密社
闲侃 区块链 智能合约 区块链
加密社引言在Solidity合约开发过程中,事件(Events)是一种非常重要的机制。它们不仅能够让开发者记录智能合约的重要状态变更,还能够让外部系统(如前端应用)监听这些状态的变化。本文将详细介绍Solidity中的事件机制以及如何利用不同的手段来触发、监听和获取这些事件。事件存储的地方当我们在Solidity合约中使用emit关键字触发事件时,该事件会被记录在区块链的交易收据中。具体而言,事件
使用Faiss进行高效相似度搜索
llzwxh888
faiss python
在现代AI应用中,快速和高效的相似度搜索是至关重要的。Faiss(FacebookAISimilaritySearch)是一个专门用于快速相似度搜索和聚类的库,特别适用于高维向量。本文将介绍如何使用Faiss来进行相似度搜索,并结合Python代码演示其基本用法。什么是Faiss?Faiss是一个由FacebookAIResearch团队开发的开源库,主要用于高维向量的相似性搜索和聚类。Faiss
利用Requests Toolkit轻松完成HTTP请求
nseejrukjhad
http 网络协议 网络 python
RequestsToolkit的力量:轻松构建HTTP请求Agent在现代软件开发中,API请求是与外部服务交互的核心。RequestsToolkit提供了一种便捷的方式,帮助开发者构建自动化的HTTP请求Agent。本文旨在详细介绍RequestsToolkit的设置、使用和潜在挑战。引言RequestsToolkit是一个强大的工具包,可用于构建执行HTTP请求的智能代理。这对于想要自动化与外
利用LangChain的StackExchange组件实现智能问答系统
nseejrukjhad
langchain microsoft 数据库 python
利用LangChain的StackExchange组件实现智能问答系统引言在当今的软件开发世界中,StackOverflow已经成为程序员解决问题的首选平台之一。而LangChain作为一个强大的AI应用开发框架,提供了StackExchange组件,使我们能够轻松地将StackOverflow的海量知识库集成到我们的应用中。本文将详细介绍如何使用LangChain的StackExchange组件
在一台Ubuntu计算机上构建Hyperledger Fabric网络
落叶无声9
区块链 超级账本 Hyperledger fabric 区块链 ubuntu 构建 hyperledger fabric
在一台Ubuntu计算机上构建HyperledgerFabric网络Hyperledgerfabric是一个开源的区块链应用程序平台,为开发基于区块链的应用程序提供了一个起点。当我们提到HyperledgerFabric网络时,我们指的是使用HyperledgerFabric的正在运行的系统。即使只使用最少数量的组件,部署Fabric网络也不是一件容易的事。Fabric社区创建了一个名为Cello
GitHub上克隆项目
bigbig猩猩
github
从GitHub上克隆项目是一个简单且直接的过程,它允许你将远程仓库中的项目复制到你的本地计算机上,以便进行进一步的开发、测试或学习。以下是一个详细的步骤指南,帮助你从GitHub上克隆项目。一、准备工作1.安装Git在克隆GitHub项目之前,你需要在你的计算机上安装Git工具。Git是一个开源的分布式版本控制系统,用于跟踪和管理代码变更。你可以从Git的官方网站(https://git-scm.
关于城市旅游的HTML网页设计——(旅游风景云南 5页)HTML+CSS+JavaScript
二挡起步
web前端期末大作业 javascript html css 旅游 风景
⛵源码获取文末联系✈Web前端开发技术描述网页设计题材,DIV+CSS布局制作,HTML+CSS网页设计期末课程大作业|游景点介绍|旅游风景区|家乡介绍|等网站的设计与制作|HTML期末大学生网页设计作业,Web大学生网页HTML:结构CSS:样式在操作方面上运用了html5和css3,采用了div+css结构、表单、超链接、浮动、绝对定位、相对定位、字体样式、引用视频等基础知识JavaScrip
HTML网页设计制作大作业(div+css) 云南我的家乡旅游景点 带文字滚动
二挡起步
web前端期末大作业 web设计网页规划与设计 html css javascript dreamweaver 前端
Web前端开发技术描述网页设计题材,DIV+CSS布局制作,HTML+CSS网页设计期末课程大作业游景点介绍|旅游风景区|家乡介绍|等网站的设计与制作HTML期末大学生网页设计作业HTML:结构CSS:样式在操作方面上运用了html5和css3,采用了div+css结构、表单、超链接、浮动、绝对定位、相对定位、字体样式、引用视频等基础知识JavaScript:做与用户的交互行为文章目录前端学习路线
Day1笔记-Python简介&标识符和关键字&输入输出
~在杰难逃~
Python python 开发语言 大数据 数据分析 数据挖掘
大家好,从今天开始呢,杰哥开展一个新的专栏,当然,数据分析部分也会不定时更新的,这个新的专栏主要是讲解一些Python的基础语法和知识,帮助0基础的小伙伴入门和学习Python,感兴趣的小伙伴可以开始认真学习啦!一、Python简介【了解】1.计算机工作原理编程语言就是用来定义计算机程序的形式语言。我们通过编程语言来编写程序代码,再通过语言处理程序执行向计算机发送指令,让计算机完成对应的工作,编程
人工智能时代,程序员如何保持核心竞争力?
jmoych
人工智能
随着AIGC(如chatgpt、midjourney、claude等)大语言模型接二连三的涌现,AI辅助编程工具日益普及,程序员的工作方式正在发生深刻变革。有人担心AI可能取代部分编程工作,也有人认为AI是提高效率的得力助手。面对这一趋势,程序员应该如何应对?是专注于某个领域深耕细作,还是广泛学习以适应快速变化的技术环境?又或者,我们是否应该将重点转向AI无法轻易替代的软技能?让我们一起探讨程序员
Faiss Tips:高效向量搜索与聚类的利器
焦习娜Samantha
FaissTips:高效向量搜索与聚类的利器faiss_tipsSomeusefultipsforfaiss项目地址:https://gitcode.com/gh_mirrors/fa/faiss_tips项目介绍Faiss是由FacebookAIResearch开发的一个用于高效相似性搜索和密集向量聚类的库。它支持多种硬件平台,包括CPU和GPU,能够在海量数据集上实现快速的近似最近邻搜索(AN
pyecharts——绘制柱形图折线图
2224070247
信息可视化 python java 数据可视化
一、pyecharts概述自2013年6月百度EFE(ExcellentFrontEnd)数据可视化团队研发的ECharts1.0发布到GitHub网站以来,ECharts一直备受业界权威的关注并获得广泛好评,成为目前成熟且流行的数据可视化图表工具,被应用到诸多数据可视化的开发领域。Python作为数据分析领域最受欢迎的语言,也加入ECharts的使用行列,并研发出方便Python开发者使用的数据
sql统计相同项个数并按名次显示
朱辉辉33
java oracle
现在有如下这样一个表:
A表
ID Name time
------------------------------
0001 aaa 2006-11-18
0002 ccc 2006-11-18
0003 eee 2006-11-18
0004 aaa 2006-11-18
0005 eee 2006-11-18
0004 aaa 2006-11-18
0002 ccc 20
Android+Jquery Mobile学习系列-目录
白糖_
JQuery Mobile
最近在研究学习基于Android的移动应用开发,准备给家里人做一个应用程序用用。向公司手机移动团队咨询了下,觉得使用Android的WebView上手最快,因为WebView等于是一个内置浏览器,可以基于html页面开发,不用去学习Android自带的七七八八的控件。然后加上Jquery mobile的样式渲染和事件等,就能非常方便的做动态应用了。
从现在起,往后一段时间,我打算
如何给线程池命名
daysinsun
线程池
在系统运行后,在线程快照里总是看到线程池的名字为pool-xx,这样导致很不好定位,怎么给线程池一个有意义的名字呢。参照ThreadPoolExecutor类的ThreadFactory,自己实现ThreadFactory接口,重写newThread方法即可。参考代码如下:
public class Named
IE 中"HTML Parsing Error:Unable to modify the parent container element before the
周凡杨
html 解析 error readyState
错误: IE 中"HTML Parsing Error:Unable to modify the parent container element before the child element is closed"
现象: 同事之间几个IE 测试情况下,有的报这个错,有的不报。经查询资料后,可归纳以下原因。
java上传
g21121
java
我们在做web项目中通常会遇到上传文件的情况,用struts等框架的会直接用的自带的标签和组件,今天说的是利用servlet来完成上传。
我们这里利用到commons-fileupload组件,相关jar包可以取apache官网下载:http://commons.apache.org/
下面是servlet的代码:
//定义一个磁盘文件工厂
DiskFileItemFactory fact
SpringMVC配置学习
510888780
spring mvc
spring MVC配置详解
现在主流的Web MVC框架除了Struts这个主力 外,其次就是Spring MVC了,因此这也是作为一名程序员需要掌握的主流框架,框架选择多了,应对多变的需求和业务时,可实行的方案自然就多了。不过要想灵活运用Spring MVC来应对大多数的Web开发,就必须要掌握它的配置及原理。
一、Spring MVC环境搭建:(Spring 2.5.6 + Hi
spring mvc-jfreeChart 柱图(1)
布衣凌宇
jfreechart
第一步:下载jfreeChart包,注意是jfreeChart文件lib目录下的,jcommon-1.0.23.jar和jfreechart-1.0.19.jar两个包即可;
第二步:配置web.xml;
web.xml代码如下
<servlet>
<servlet-name>jfreechart</servlet-nam
我的spring学习笔记13-容器扩展点之PropertyPlaceholderConfigurer
aijuans
Spring3
PropertyPlaceholderConfigurer是个bean工厂后置处理器的实现,也就是BeanFactoryPostProcessor接口的一个实现。关于BeanFactoryPostProcessor和BeanPostProcessor类似。我会在其他地方介绍。PropertyPlaceholderConfigurer可以将上下文(配置文件)中的属性值放在另一个单独的标准java P
java 线程池使用 Runnable&Callable&Future
antlove
java thread Runnable callable future
1. 创建线程池
ExecutorService executorService = Executors.newCachedThreadPool();
2. 执行一次线程,调用Runnable接口实现
Future<?> future = executorService.submit(new DefaultRunnable());
System.out.prin
XML语法元素结构的总结
百合不是茶
xml 树结构
1.XML介绍1969年 gml (主要目的是要在不同的机器进行通信的数据规范)1985年 sgml standard generralized markup language1993年 html(www网)1998年 xml extensible markup language
改变eclipse编码格式
bijian1013
eclipse 编码格式
1.改变整个工作空间的编码格式
改变整个工作空间的编码格式,这样以后新建的文件也是新设置的编码格式。
Eclipse->window->preferences->General->workspace-
javascript中return的设计缺陷
bijian1013
JavaScript AngularJS
代码1:
<script>
var gisService = (function(window)
{
return
{
name:function ()
{
alert(1);
}
};
})(this);
gisService.name();
&l
【持久化框架MyBatis3八】Spring集成MyBatis3
bit1129
Mybatis3
pom.xml配置
Maven的pom中主要包括:
MyBatis
MyBatis-Spring
Spring
MySQL-Connector-Java
Druid
applicationContext.xml配置
<?xml version="1.0" encoding="UTF-8"?>
&
java web项目启动时自动加载自定义properties文件
bitray
java Web 监听器 相对路径
创建一个类
public class ContextInitListener implements ServletContextListener
使得该类成为一个监听器。用于监听整个容器生命周期的,主要是初始化和销毁的。
类创建后要在web.xml配置文件中增加一个简单的监听器配置,即刚才我们定义的类。
<listener>
<des
用nginx区分文件大小做出不同响应
ronin47
昨晚和前21v的同事聊天,说到我离职后一些技术上的更新。其中有个给某大客户(游戏下载类)的特殊需求设计,因为文件大小差距很大——估计是大版本和补丁的区别——又走的是同一个域名,而squid在响应比较大的文件时,尤其是初次下载的时候,性能比较差,所以拆成两组服务器,squid服务于较小的文件,通过pull方式从peer层获取,nginx服务于较大的文件,通过push方式由peer层分发同步。外部发布
java-67-扑克牌的顺子.从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的.2-10为数字本身,A为1,J为11,Q为12,K为13,而大
bylijinnan
java
package com.ljn.base;
import java.util.Arrays;
import java.util.Random;
public class ContinuousPoker {
/**
* Q67 扑克牌的顺子 从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。
* 2-10为数字本身,A为1,J为1
翟鸿燊老师语录
ccii
翟鸿燊
一、国学应用智慧TAT之亮剑精神A
1. 角色就是人格
就像你一回家的时候,你一进屋里面,你已经是儿子,是姑娘啦,给老爸老妈倒怀水吧,你还觉得你是老总呢?还拿派呢?就像今天一样,你们往这儿一坐,你们之间是什么,同学,是朋友。
还有下属最忌讳的就是领导向他询问情况的时候,什么我不知道,我不清楚,该你知道的你凭什么不知道
[光速与宇宙]进行光速飞行的一些问题
comsci
问题
在人类整体进入宇宙时代,即将开展深空宇宙探索之前,我有几个猜想想告诉大家
仅仅是猜想。。。未经官方证实
1:要在宇宙中进行光速飞行,必须首先获得宇宙中的航行通行证,而这个航行通行证并不是我们平常认为的那种带钢印的证书,是什么呢? 下面我来告诉
oracle undo解析
cwqcwqmax9
oracle
oracle undo解析2012-09-24 09:02:01 我来说两句 作者:虫师收藏 我要投稿
Undo是干嘛用的? &nb
java中各种集合的详细介绍
dashuaifu
java 集合
一,java中各种集合的关系图 Collection 接口的接口 对象的集合 ├ List 子接口 &n
卸载windows服务的方法
dcj3sjt126com
windows service
卸载Windows服务的方法
在Windows中,有一类程序称为服务,在操作系统内核加载完成后就开始加载。这里程序往往运行在操作系统的底层,因此资源占用比较大、执行效率比较高,比较有代表性的就是杀毒软件。但是一旦因为特殊原因不能正确卸载这些程序了,其加载在Windows内的服务就不容易删除了。即便是删除注册表中的相 应项目,虽然不启动了,但是系统中仍然存在此项服务,只是没有加载而已。如果安装其他
Warning: The Copy Bundle Resources build phase contains this target's Info.plist
dcj3sjt126com
ios xcode
http://developer.apple.com/iphone/library/qa/qa2009/qa1649.html
Excerpt:
You are getting this warning because you probably added your Info.plist file to your Copy Bundle
2014之C++学习笔记(一)
Etwo
C++ Etwo Etwo iterator 迭代器
已经有很长一段时间没有写博客了,可能大家已经淡忘了Etwo这个人的存在,这一年多以来,本人从事了AS的相关开发工作,但最近一段时间,AS在天朝的没落,相信有很多码农也都清楚,现在的页游基本上达到饱和,手机上的游戏基本被unity3D与cocos占据,AS基本没有容身之处。so。。。最近我并不打算直接转型
js跨越获取数据问题记录
haifengwuch
jsonp json Ajax
js的跨越问题,普通的ajax无法获取服务器返回的值。
第一种解决方案,通过getson,后台配合方式,实现。
Java后台代码:
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String ca
蓝色jQuery导航条
ini
JavaScript html jquery Web html5
效果体验:http://keleyi.com/keleyi/phtml/jqtexiao/39.htmHTML文件代码:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>jQuery鼠标悬停上下滑动导航条 - 柯乐义<
linux部署jdk,tomcat,mysql
kerryg
jdk tomcat linux mysql
1、安装java环境jdk:
一般系统都会默认自带的JDK,但是不太好用,都会卸载了,然后重新安装。
1.1)、卸载:
(rpm -qa :查询已经安装哪些软件包;
rmp -q 软件包:查询指定包是否已
DOMContentLoaded VS onload VS onreadystatechange
mutongwu
jquery js
1. DOMContentLoaded 在页面html、script、style加载完毕即可触发,无需等待所有资源(image/iframe)加载完毕。(IE9+)
2. onload是最早支持的事件,要求所有资源加载完毕触发。
3. onreadystatechange 开始在IE引入,后来其它浏览器也有一定的实现。涉及以下 document , applet, embed, fra
sql批量插入数据
qifeifei
批量插入
hi,
自己在做工程的时候,遇到批量插入数据的数据修复场景。我的思路是在插入前准备一个临时表,临时表的整理就看当时的选择条件了,临时表就是要插入的数据集,最后再批量插入到数据库中。
WITH tempT AS (
SELECT
item_id AS combo_id,
item_id,
now() AS create_date
FROM
a
log4j打印日志文件 如何实现相对路径到 项目工程下
thinkfreer
Web log4j 应用服务器 日志
最近为了实现统计一个网站的访问量,记录用户的登录信息,以方便站长实时了解自己网站的访问情况,选择了Apache 的log4j,但是在选择相对路径那块 卡主了,X度了好多方法(其实大多都是一样的内用,还一个字都不差的),都没有能解决问题,无奈搞了2天终于解决了,与大家分享一下
需求:
用户登录该网站时,把用户的登录名,ip,时间。统计到一个txt文档里,以方便其他系统调用此txt。项目名
linux下mysql-5.6.23.tar.gz安装与配置
笑我痴狂
mysql linux unix
1.卸载系统默认的mysql
[root@localhost ~]# rpm -qa | grep mysql
mysql-libs-5.1.66-2.el6_3.x86_64
mysql-devel-5.1.66-2.el6_3.x86_64
mysql-5.1.66-2.el6_3.x86_64
[root@localhost ~]# rpm -e mysql-libs-5.1