1 加法器电路
//add.v
module add(a, b, in, c, out);
input a;
input b;
input in;
output c;
output out;
assign {out, c} = a + b + in;
endmodule
//test_add.v
`timescale 1ns/1ns
module count_t;
reg clk;
reg a;
reg b;
reg in;
wire c;
wire out;
add process(a, b, in, c, out);
initial
clk = 0;
always
forever #5 clk = ~clk;
initial
begin
a = 0; b = 0; in = 0;
#10 a = 0; b = 0; in = 1;
#10 a = 0; b = 1; in = 0;
#10 a = 0; b = 1; in = 1;
#10 a = 1; b = 0; in = 0;
#10 a = 1; b = 0; in = 1;
#10 a = 1; b = 1; in = 0;
#10 a = 1; b = 1; in = 1;
end
//initial
//$monitor(" out = %d, c = %d\n", out, c);//监视函数
endmodule
总结1
数据类型wire与reg的区别:reg和wire类似于C、C++的变量,
wire相当于电路中的导线,对应于连续赋值,如assign,属于组合电路;
reg相当于电路中的寄存器,对应于过程赋值,只能在always,initial语块中用等号赋值,属于时序电路。
执行顺序:Verilog中,每行语句都是并发执行的,而在always,initial语块中,语句是顺序执行的,可以使用if等判断语句。
$monitor提供了监控输出列表中的表达式或变量值的功能,当参数列表中变量或者表达式的值发生变化是,整个参数列表中变量或者表达式的值都将输出显示。
timescale是Verilog HDL 中的一种时间尺度预编译指令,它用来定义模块的仿真的时间单位和时间精度。格式如下:
`timescale 仿真时间单位/时间精度
注意:
1)时间精度就是模块仿真时间和延时的精确程序,比如:定义时间精度为10ns,那么时序中所有的延时至多能精确到10ns,而8ns或者18ns是不可能做到的。
2)用于说明仿真时间单位和时间精度的 数字只能是1、10、100,不能为其它的数字。
3)时间精度不能比时间单位还要大。最多两则一样大。
比如:
下面定义都是对的:
`timescale 1ns/1ps
`timescale 100ns/100ns
而下面的定义是错的:
`timescale 1ps/1ns
2 8 bits counter with async clear and sync load
//counter8.v
module counter8 (clk,aclr,load,load_din,dout);
input clk;
input aclr;
input load;
input [7:0] load_din;
output [7:0] dout;
//InternalVariables
wire clk ;
wire aclr;
wire load;
wire [7:0]load_din;
wire [7:0]dout;
reg [7:0]counter = 0;
//CodeStarts Here
always @(posedge clk or negedge aclr)
if(!aclr) counter <= 0;
else if(load == 1)
counter <= load_din;
else counter <= counter + 1;
assign dout = counter;
endmodule
//test_counter8.v
`timescale 1ns/1ns
module test_counter8;
reg clk;
reg aclr;
reg load;
reg [7:0] load_din;
wire [7:0] dout;
counter8 u(
.clk(clk),
.aclr(aclr),
.load(load),
.load_din(load_din),
.dout(dout));
initial
begin
clk = 0;
aclr = 1;
load = 0;
load_din = 0;
#40 aclr = 1;
#20 load = 1;
load_din = 100;
#20 load = 0;
#53 aclr = 0;
end
always #10 clk = ~clk;
endmodule
![波形图](file:///C:/Users/Administrator/Desktop/algorithms/wave1.png)
总结2
非阻塞(Non_Blocking)赋值方式( 如 b <= a; ),块结束后才完成赋值操作,值并不是立刻就改变的,这是一种比较常用的赋值方法。(特别在编写可综合模块时)。
阻塞(Blocking)赋值方式( 如 b = a; ),赋值语句执行完后,块才结束,值在赋值语句执行完后立刻就改变的, 可能会产生意想不到的结果。
一般情况下组合逻辑使用=赋值,时序逻辑使用<=赋值。
#40
时间都是累加的
3 16*16FIFO
//fifo.v
module fifo(clock,reset,read,write,fifo_in,fifo_out,fifo_empty,fifo_half,fifo_full);
input clock,reset,read,write;
input [15:0]fifo_in;
output[15:0]fifo_out;
output fifo_empty,fifo_half,fifo_full;//标志位
reg [15:0]fifo_out;
reg [15:0]ram[15:0];
reg [3:0]read_ptr,write_ptr,counter;//指针与计数
wire fifo_empty,fifo_half,fifo_full;
initial
begin
counter=0;
read_ptr=0;
write_ptr=0;
end
always@(*)
if(reset)
begin
read_ptr=0;
write_ptr=0;
counter=0;
fifo_out=0; //初始值
end
else
case({read,write})
2'b00:
counter=counter; //没有读写指令
2'b01: //写指令,数据输入fifo
begin
ram[write_ptr]=fifo_in;
counter=counter+1;
write_ptr=(write_ptr==15)?0:write_ptr+1;
end
2'b10: //读指令,数据读出fifo
begin
fifo_out=ram[read_ptr];
counter=counter-1;
read_ptr=(read_ptr==15)?0:read_ptr+1;
end
2'b11: //读写指令同时,数据可以直接输出
begin
if(counter==0)
fifo_out=fifo_in;
else
begin
ram[write_ptr]=fifo_in;
fifo_out=ram[read_ptr];
write_ptr=(write_ptr==15)?0:write_ptr+1;
read_ptr=(read_ptr==15)?0:write_ptr+1;
end
end
endcase
assign fifo_empty=(counter==0)?1:0; //标志位赋值 组合电路
assign fifo_half=(counter==8)?1:0;
assign fifo_full=(counter==15)?1:0;
endmodule
//test_fifo.v
`timescale 1ns/1ns
module test_fifo;
reg clock;
reg reset;
reg read;
reg write;
reg [15:0]fifo_in;
wire [15:0]fifo_out;
wire fifo_empty;
wire fifo_half;
wire fifo_full;
fifo process(clock,reset,read,write,fifo_in,fifo_out,fifo_empty,fifo_half,fifo_full);
initial
begin
read=0;
write=0;
clock=0;
reset=0;
fifo_in=0;
end
always
#4 clock=~clock;
always
#10 write=~write;
always
#20 read=~read;
always
#5 fifo_in=fifo_in+1;
endmodule
总结3
最开始仿真的时候输出总为x,重新检查了代码之后明白了是fifo内部变量没有赋初值,增加initial即可