第一到五章
–二选一多路选择器
always@(sl or a or b)
if(! sl) out = a;
其中always表示,sl或a或b其中有一个变化时就执行下面的语句。
–定义参数
parameter
wordsize=16,
memsize=256;
reg[wordsize-1:0]
mem[mensize-1:0],
writereg, reading;
//同时定义存储类类型和reg数据类型
reg [n-1:0] rega;
//一个n位的寄存器,n位寄存器可以直接赋值
rega = 0;
---
reg mema[n-1:0]
//一个有n个1位寄存器构成的存储器组,存储器不能直接赋值
mema[3]=0;
–运算符表达式
位运算符
~ //取反
& //按位与
| //按位或
^ //按位异或
^~ //按位同或(异或非)
与门:有0则0,同1为1
或门:有1则1,同0为0
异或门:相异为1(助记:把那个“或”的一撇堪称是1)
同或门:相同为1,也可理解为异或门加上非门
位移运算
module shift;
reg[3:0] start, //四位reg
reg[3:0] result;
initial;
begin;
start=1;
//设定start的初始值为0001
reault=(start<<2);
//移位后,start的值0100,然后赋值给result
end
endmodule
位拼接运算
{a, b[3:0], w, 3'b101}
{a, b[3], b[2], b[1], b[0], w, 1'b1, 1'b0, 1'b1}
{4{w}} //{w, w, w, w}
{b,3{a, b}} //{b, a, b, a, b, a, b}
–赋值语句和块语句
1、非阻塞赋值(Non_Blocking)赋值方式(b<=a)
1)在语句块当中,上面语句所赋的变量值不能立即就为下面的语句所用;
2)块结束后才能完成这次的赋值操作,而所赋的变量值是上一次赋值得到的;
3)在编写可综合的时序逻辑模块时,这是最常用的赋值方法。
2、阻塞(Blocking)赋值(b=a)
1)赋值语句完成执行后块才结束;
2)b的赋值在语句执行完成后就立刻改变;
3)在时序逻辑中使用可能会产生意想不到的结果;
–循环语句
1)forever,连续执行语句
forever
begin
xxx
end
2)repeat,连续执行一条语句n次
3)while,执行一条语句知道某个条件不满足。
4)for,循环语句
–顺序块和并行块
module top;
initial
begin:block1
integer i; //整形变量时静态本地变量
end
//可以通过top.block1.i被他模块访问
initial
fork:block2l
reg i;
join
可以通过top.block2.i被他模块访问
–部分简单的案例
//四选一多路选择器
moudule mux4_to_1(
input i0,
input i1,
input i2,
input i3,
input s1,
input s2,
output out
);
always @(s1 or s0 or i0 or i1 or i2 or i3)
begin
case({s1, s0})
2'b00:out=i0;
2'b01:out=i1;
2'b10:out=i2;
2'b01:out=i3;
default:out=1'bx;
endcase
end
endmodule
//四位计数器
module counter(
input clock,
input clear,
output reg[3:0] Q
);
always @(posedge clear or negedge clock)
begin
if(clear)
Q<=4'd0; //为了实现注入触发器一类的时序逻辑,使用非阻塞赋值
else
Q<=Q+1; //Q是一个四位寄存器,计数超过15之后会归零,因为模16没有必要
end
endmodule
第六章
–Task & Function
//红绿灯举例
//红绿灯举例
module traffic_lights
reg clock;
reg red;
reg amber;
reg green;
parameter on =1, off=0, red_tics=350,
amber_tics=30,green_tics=200;
initial red=off;
initial amber=off;
initial green=off;
//交通灯控制程序
always
begin
red=on;
light(red, red_tics);
green=on;
light(green, green_tics);
amber=on;
light(amber, amber_tics);
end
task light;
output color;
input[31:0] tics;
begin
repeat(tics)
//这个是 Verilog 的一个关键字,表示重复执行接下来的语句 tics 次。在这个例子中,就是让 @(posedge clock) 这个语句重复执行 tics 次
@(posedge clock);
color=off;
end
endtask
//产生时钟脉冲的always模块
always
begin
#100 clock=0;
#100 clock=1;
end
endmodule
//偶校验位的函数(cal_parity)
//定义一个模块,其中包含能计算偶校验位的函数(cal_parity)
module parity
reg[31:0] addr;
reg parity;
initial
begin
addr=32'h3456_789a;
#10 addr=32'hc4c6_78ff;
#10 addr=32'hff56_ff9a;
#10 addr=32'h3faa_aaaa;
end
//每当地址值发生变化,计算新的偶校验位
always @(addr)
begin
parity=cal_parity(addr); //第一次启动校验位计算函数
$display("Parity calculated =%b", calc_parity(addr))
//第二次去启动校验位计算函数
end
//定义偶校验计算函数
function calc_parity
input[31:0] address;
begin
//适当地设置输出值,使用隐含的内部寄存器calc_parity
calc_parity = ^address; //返回所有地址位的异或值
end
endfunction
endmodule
//C语言风格声明
function calc_parity(input[31:0] address);
begin
calc_parity= ^address;
end
endfunction
//左/右移位寄存器
//定义一个左/右移位寄存器
module shifter;
`define LEFT_SHIFT 1'b0;
`define RIGHT_SHIFT 1'b1;
reg[31:0] addr;
reg[31:0] left_addr;
reg[31:0] right_addr;
reg control;
//每当新地址出现的时候就计算右移位和左移位的值
always @(addr)
begin
//调用下面的定义的具有左右移位功能的函数
left_addr=shift(addr, `LEFT_SHIFT);
right_addr=shift(addr, `RIGHT_SHIFT);
end
function[31:0] shift;
input[31:0] address;
input control;
begin
//根据控制信号适当地设置输出值
shift=(control==`LEFT_SHIFT)?(address<<1):(address>>1);
end
endfunction
endmodule
//自动(递归)函数
module top;
//定义自动(递归)函数
function automatic integer factorial;
input[31:0] oper;
integer i;
begin
if(operand>=2)
factorial=factorial(oper-1)*oper; //递归调用
else
factorial = 1;
end
endfunction
//调用该函数
integer result;
initial
begin
result=factorial(4); //调用4的阶乘
$display("Factorial of 4 is %0d", result); //显示24
end
endmodule
//计算地址总线的宽度
module ram(......);
parameter RAM_DEPTH=256;
input [clog2(RAM_DEPTH)-1:0] addr_bus;
function integer clogb2(input integer depth)
begin
for(clogb2=0; depth>0; clogb2=clogb2+1)
depth=depth>>1;
end
endfunction
endmodule