28~36 Always块,if else,case,casez选择语句
强烈建议大家去看看HDLBits 中文导学,原文在知乎
链接: link.
28.Always blocks
简单的always块的介绍,
有两种always块是可以综合出电路硬件的:
1.综合逻辑:always @(*)
2.时序逻辑:always @(posedge clk)
always @(*) out_alwaysblock=a&b;
综合逻辑中“ * ”号,我理解的是默认全部变量,挨个去写的话,容易遗漏。
29.Always blocks2
always @(posedge clk)
时序逻辑会在生成的组合电路之后,添加一个触发器或者寄存器,在下一个时钟的上升沿才会触发。
Blocking vs. Non-Blocking Assignment(阻塞/非阻塞赋值)
Verilog三种赋值方法:
- 连续赋值:assign x = y,不能用于过程块;
- 阻塞赋值:x = y,只能用在过程块中;
- 非阻塞赋值:x <= y,只能用于过程块;
一般的,组合always块中,使用阻塞性赋值。在时序always块中,使用非阻塞性赋值;
30.Always_if
if语句只能在过程块使用,一般用来表示一个2选1选择器;
always @(*) begin
if (condition) begin
out = x;
end
else begin
out = y;
end
end
其功能和c语言中的条件赋值语句类似
assign out = (condition) ? x : y;
assign out_assign=(sel_b1&sel_b2)?b:a;
always@(*) begin
if(sel_b1&sel_b2) begin
out_always=b;
end
else begin
out_always=a;
end
end
31.Always if2–latch(锁存器)
这边大概的意思:首先,设计电路时不要急功近利,要自底向上一层层的去实现,再然后就是,可能你的电路设计出来,在没有触发器的情况下,在收到某些输入之后,输出可能保持不变,电路的输出要想保持不变就需要锁存器,当你没有时就会报错
Warning (10240): ... inferring latch(es)
即便你的Verilog代码没有语法上的错误这不代表着你的电路就是完全正确的;
always @(*) begin
if (cpu_overheated) begin
shut_off_computer = 1;
end
else begin
shut_off_computer = 0;
end
end
always @(*) begin
if (~arrived&& ~gas_tank_empty)begin //既没有到达并且还有油;
keep_driving = 1;
end
else begin
keep_driving = 0;
end
end
32 Always case
case语句
always @(*) begin // This is a combinational circuit
case (in)
1'b1: begin
out = 1'b1; // begin-end if >1 statement
end
1'b0: out = 1'b0;
default: out = 1'bx;
endcase
end
- 每条选择语句case开头,冒号结束;
- 一般一个case一个语句,多于一个的时候就要加上begin and;
- 允许重复的case ,优先执行第一条
always@(*) begin // This is a combinational circuit
case(sel)//sel 选择信号,3位2进制
3'b000: out=data0;
3'b001:out=data1;
3'b010: out=data2;
3'b011: out=data3;
3'b100: out=data4;
3'b101: out=data5;
default: out = 4'b0000;
endcase
end
33.Always case-priority encoder(优先编码器)
优先编码器:输出从右边往左的第一个1的位置;
简单译码器: 输入只能有一个1。出现多个1的时候视不同情况有不同的处理方式。
always@(*)
case(in)
4'b0000:pos=2'b00;//4'h0: pos = 2'h0;
4'b0001:pos=2'b00;//4'h1: pos = 2'h0;
4'b0010:pos=2'b01;//4'h2: pos = 2'h1;
4'b0011:pos=2'b00;//4'h3: pos = 2'h0;
4'b0100:pos=2'b10;//...
4'b0101:pos=2'b00;
4'b0110:pos=2'b01;
4'b0111:pos=2'b00;
4'b1000:pos=2'b11;
4'b1001:pos=2'b00;
4'b1010:pos=2'b01;//4'ha: pos = 2'h1;
4'b1011:pos=2'b00;//...
4'b1100:pos=2'b10;
4'b1101:pos=2'b00;
4'b1110:pos=2'b01;
4'b1111:pos=2'b00;
default: pos = 2'b00;//可以不写因为所有的16个数全都包含了;
//用16进制写更加方便不用写4位二进制数;
endcase
34.priority encoder–caseZ
我就说上一题为啥要这么写,没有模糊选项吗,它来了;
always@(*)
casez(in)
8'bzzzzzzz1:pos=3'h0;
8'bzzzzzz1z:pos=3'h1;
8'bzzzzz1zz:pos=3'h2;
8'bzzzz1zzz:pos=3'h3;
8'bzzz1zzzz:pos=3'h4;
8'bzz1zzzzz:pos=3'h5;
8'bz1zzzzzz:pos=3'h6;
8'b1zzzzzzz:pos=3'h7;
default : pos=3'h0;
//解析里pos直接等于1,2,3...不知道为啥可以;
endcase
35.Always nolatches
有时候输入可能很多,但是我们某些时候只用得到其中的一些,为了前面的不加锁存器原则,必须给那些用不到的也赋值默认值;
always@(*)
casez(scancode)
16'he06b: begin
up = 1'b0;
down = 1'b0;
left = 1'b1;
right = 1'b0;
end
16'he072: begin
up = 1'b0;
down = 1'b1;
left = 1'b0;
right = 1'b0;
end
16'he074: begin
up = 1'b0;
down = 1'b0;
left = 1'b0;
right = 1'b1;
end
16'he075: begin
up = 1'b1;
down = 1'b0;
left = 1'b0;
right = 1'b0;
end
default: begin
up = 1'b0;
down = 1'b0;
left = 1'b0;
right = 1'b0;
end
endcase
endmodule
赋值默认值之后;
always@(*)
begin
up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
casez(scancode)
16'he06b: left = 1'b1;
16'he072: down = 1'b1;
16'he074: right = 1'b1;
16'he075: up = 1'b1;
endcase
end
博客围绕Verilog的Always块展开,介绍了可综合出电路硬件的综合逻辑和时序逻辑两种Always块,还提及Verilog的三种赋值方法及适用场景。此外,讲解了if、case语句在过程块的使用,以及优先编码器、锁存器等电路设计要点,强调设计时要避免锁存器问题。
603

被折叠的 条评论
为什么被折叠?



