第四章
- 运算符,赋值语句,结构说明语句
逻辑运算符:&&,||,!。关系运算符:(<,>,<=,>=)。等式运算符(==,!=,===,!==)其中(!==,===可以用来比较高阻态和不定值,完全一样才能为1)。移位运算符(<<,>>空位补零),位拼接运算符({}),缩减运算符(c =&b 将第一位与第二位与结果再与第三位与)。 - 优先级(!~)(*,/,%)(+,-)(<<,>>)(<,<=,>>=)(==,===,!=,!==)(&)(^,^~)(|)(&&)(||)(?
赋值语句:非阻塞赋值(b<=a;)块(always块)结束时最后完成赋值操作。阻塞赋值(b=a)赋值语句执行完立即赋值,赋值语句执行完时块才结束。 - 块语句(begin end )顺序执行,(fork join 不可综合)并行执行。可以在块内申明语句。
- 逻辑运算符与逻辑运算符的区别,逻辑运算符的结果只能是0或1,而按位逻辑运算则位数同操作数相同。 Initial 内部具有多条语句时需使用begin end多个initial 之间是并行。
- 位拼接运算符{}使用方法:assign control ={read,write,sel[2:0],halt,load_instr…}
- 条件语句 循环语句 块语句 生成语句
if-else使用方法:
1)If (a<b) 或这(!rst)简写形式
语句1;
if(a<b) //嵌套块
Begin 语句1;语句2;语句3;end
Else
语句2;
If (a<b)
语句1;
Else if (a=b)
语句2;
Else if(a>b)
语句2;
Else
语句n;
Else 只与最近的if相匹配。
Case语句用法
Reg [15:0] rega;
Reg [9:0] result;
Case (rega)
16’b0: result = 10’b0111111111;
16’b7x: result = 10’b0111001111;
16’bz5: result = 10’b0000011111;
...
Default:result =10’bx;(可有可无但只有一个)
Endcase
casez(不比较高组态) casex(不比较高组态和不定值)
Reg[7:0] ir;
Casez(ir)
8’b1???????:instruction1(ir);
8’b100?????:instruction2(ir);
...
Default:instruction8(ir);
4、条件语句的语法
if (expression) true_statement; true_statement 执行或不执行
If(expression) true_statement; else false_statement ;
If(expression) true_statement_1; else if true_statement_1 else false_statement ; 只执行一条
多分支语句 多用循环语句加块语句
5.循环语句:forever begin 语句;end 或forever 语句;(只能在initial语句(不可综合)Repeat 语句;或
repeat begin 语句…;end for()用法与c类似 While 语句(不可综合);或while begin 语句…;end
7. 顺序 begin_end块。并行 fork_join 两个都可带(延时tb用)和嵌套. Disable block1;禁用块
生成块:矢量或模块重复操作时可动态生成代码。生成实例可以是多种类型:1)模块
8. 块 用户定义原语;3)门级原语;4)连续赋值语句;5)initial 和always块。
关键词 generate - endgenerate 能够在申明范围内生成的数据类型:1)线网net,寄存器reg;
integer ,real time,realtime;3)event.且生成的具有唯一标识可以被层次引用。不能生成1)参数,局部参数;2)输入输出和输入输出申明;3)指定块。
9. 循环生成语句:将循环语句,条件语句,case语句则可组成。循环生成块,条件生成块。
循环生成块:1)变量申明2)模块3)用户定义原语门级原语4)连续赋值语句5)initial,always
条件生成块:模块3)用户定义原语门级原语4)连续赋值语句5)initial,always
分支生成块:1)模块3)用户定义原语门级原语4)连续赋值语句5)initial,always
10. 程序实例:由25Mhz得到12Mhz的分频方法。思路:首先进行2倍分频然后在进行1.0415倍分频
module clk_divided_decimals(
sys_clk,
clk_out
);
input sys_clk;
output clk_out;
parameter K=10; //divided 2 ,tdivided 1.0415
parameter M=25; // rate 25/24 = 1.0415
parameter N=24; //25/12=2.083=1.0415*2=(25/24)*2
reg div; reg del;
reg clk_2_div; reg [K-1:0] p;
initial begin //initiate reg
p<=32'b0; div<=2'b0;
clk_2_div<=0;
end //devide sys_clk into 12.5M
always@(posedge sys_clk) begin
clk_2_div = ~clk_2_div; end
always@(posedge clk_2_div) begin
if(p<M) begin
p<=p+N;
end
if(p>=M) begin
p<=p-M+N; del<=2'b0;
end
if(N<=p&&p<M) begin
del<=2'b1;
end
end
always@( sys_clk ) begin
if(del==1)
div<=2'b1;
else
div<=clk_2_div;
end
assign clk_out = div;
endmodule
module clk_divided_decimals_tb;
reg sys_clk;
wire clk_out;
clk_divided_decimals uut (
.sys_clk(sys_clk),
.clk_out(clk_out)
);
initial begin
sys_clk = 0;
#100;
end
always #200 sys_clk = ~sys_clk;
endmodule
测试平台时钟25M,需得到12M就必须得2.083分频。于是先两倍分频再1.0415倍分频。非整数倍分频则采用去脉冲的方式实现。每输入25个脉冲就去除其中的一个脉冲,就能得到1.0415倍的分频。不过此种方法不易得到占空比为50%的时钟。即在模型中M/N即为实现非整数倍分频的比率。
10. 若想for语句按照时钟节拍进行初始化则须将其时钟敏感信号加入其中
Initial
Begin
For(i=0;i<=1024;i++)
Begin
Mem[i]=i;
@(posedge clk) /不可综合
End
End
case语句与拼接语句的使用实例(ls138)
module sim_74ls138(
g, y, a, b, c
);
input [1:0] g; output [7:0] y;
input a,b,c; reg [7:0] tmp;
/*if((g==2'b0x)||(g==2'bx1))
tmp=8'b1111_1111;
case ({a,b,c})
3'b000: tmp=8'b0111_1111;
3'b001: tmp=8'b1011_1111;
3'b010: tmp=8'b1101_1111;
3'b011: tmp=8'b1110_1111;
3'b100: tmp=8'b1111_0111;
3'b101: tmp=8'b1111_1011;
3'b110: tmp=8'b1111_1101;
3'b111: tmp=8'b1111_1110;
default : tmp=8'b1111_1111;
Endcase*/
always@(*) begin
case ({g,a,b,c})
5'b10000: tmp=8'b0111_1111;
5'b10001: tmp=8'b1011_1111;
5'b10010: tmp=8'b1101_1111;
5'b10011: tmp=8'b1110_1111;
5'b10100: tmp=8'b1111_0111;
5'b10101: tmp=8'b1111_1011;
5'b10110: tmp=8'b1111_1101;
5'b10111: tmp=8'b1111_1110;
default : tmp=8'b1111_1111;
endcase
end
assign y=tmp;
Endmodule
module sim_74ls138_tb;
reg [1:0] g; reg a; reg b; reg c;
wire [7:0] y;
sim_74ls138 uut (
.g(g),
.y(y),
.a(a),
.b(b),
.c(c)
);
initial begin
g = 2'b10;
a = 0;
b = 0;
c = 0;
#100;
end
always begin
fork
#100 begin a=1; b=0; c=0; end
#200 begin a=0; b=0; c=0; end
#300 begin a=1; b=0; c=1; end
#400 begin a=1; b=1; c=0; end
#500 begin a=1; b=1; c=1; end
join
end
Endmodule
循环生成语句的使用
module ripple_adder(
co,
sum,
a0,
a1,
ci
);
parameter N = 4;
output [N-1:0] sum;
output co;
input [N-1:0] a0,a1;
input ci;
wire [N-1:0] carry;
genvar i;
generate for(i=0;i<N;i=i+1) begin :r_loop
wire t1,t2,t3;
xor g1(t1,a0[i],a1[i]);
xor g2(sum[i],t1,carry[i]);
and g3(t2,a0[i],a1[i]);
and g4(t3,t1,carry[i]);
or g5(carry[i],t2,t3);
end
endgenerate
assign co= carry[N-1];
Endmodule
reg [3:0] a0;
reg [3:0] a1;
reg ci;
wire co;
wire [3:0] sum;
ripple_adder uut (
.co(co), .sum(sum),
.a0(a0), .a1(a1),
.ci(ci)
);
initial begin
a0 = 0; a1 = 0; ci = 0;#100;
end
always begin
fork
#100 begin a0=2'b10; a1=2'b01; ci=2'b1; end
#200 begin a0=2'b11; a1=2'b01; ci=2'b1; end
#300 begin a0=2'b10; a1=2'b11; ci=2'b1; end
join
end
endmodule
分析:书中的程序有错误
Assign carry[0]=c0;一直在赋值而在执行generate的同时也会对carry[0]进行操作。此处不可综合。
在书本的程序中当i为3时,generate中最后一句or g5(carry[i+1],t2,t3);carry此时为carry[4],而carry的定义为[3:0],因此超过了定义的范围。