sky视频笔记:数字逻辑回顾&Hello World_哔哩哔哩_bilibili
逻辑 0:表示低电平,也就对应我们电路 GND;
逻辑 1:表示高电平,也就是对应我们电路的 VCC;
逻辑 X:表示未知,有可能是高电平,也有可能是低电平,仿真发生了不能解决的逻辑冲突;
逻辑 Z:表示高阻态,外部没有激励信号是一个悬空状态。相当于啥也没接,可以上拉或者下拉。
对于没有进行初始化的信号,一般处于不确定态(x),高阻态表示该信号没有被其他信号驱动,经常用于有多个驱动源的总线型数据上。
对于高阻态的理解:Verilog中三态门(高阻态)的理解与例子_CLL_caicai的博客-CSDN博客_verilog 高阻态
反相器(非门)
可综合描述:综合tool能够把Verilog描述转化(Comlile)为基本的数字电路底层cell(与或非门,寄存器等)
例如:assign y = a & b;—>
不可综合描述:不能把Verilog描述转化为基本的数字电路底层cell的描述
例如:$display("Hello world.\n");这种是需要串口。
何为仿真?
从仿真器的角度理解Verilog语言:从仿真器的角度理解Verilog语言 - 知乎
常用的仿真工具(所有verilog描述)
Verilog设计的物理实现(可综合verilog描述)
Top-Down:从顶层结构,算法/协议上开始。享下逐步划分功能模块;再细分各功能模块的功能和IO
完整关键字定义,见verilog标准:IEEE Std 1364-2001
Verilog标识符与关键字_FPGA&IC设计导师的博客-CSDN博客_verilog标识符
initial一般是不可综合的,always是可综合的
整数型(需要明确指定数据位宽):位宽代表转化为二进制数的位宽,达不到高位补0,多的,高位截断
16'd100 //10进制表示的“100”
16'h64 //16进制表示的“100”
16'b0110_0100 //2进制表示的“100”
实数型(可综合verilog不用)
字符型(每个字符按8bit ASCII码的整型存储)
“verilog” //占56bit
整数型(需要明确指定数据位宽)
{}是用来合并的
在 assign 赋值操作中,如果等号左右两侧信号的位宽不同,那么就会进行截断或者补零操作。
使用 [] 可以对信号进行片选,选择信号中特定几位比特,以下是一些片选的例子。
w[3:0] // Only the lower 4 bits of w
x[1] // The lowest bit of x
x[1:1] // ...also the lowest bit of x
z[-1:-2] // Z 最低两位
b[3:0] // 如果 b 在声明时 声明为 wire [0:3] b;则不能使用 b [3:0]进行选择
b[0:3] // b的高四位.
assign w[3:0] = b[0:3]; // 将 b 的高位赋予 w 的低位 w[3]=b[0], w[2]=b[1], etc.
if begin
end
case(*)
3'b001: out = 0;
...
end case
module mux4to1(s,d,y);
input wire[1:0] s;
input wire[3:0] d;
output reg y;
always @(*) begin
case (s[1:0])
2'd0:y = d[0];
2'd1:y = d[1];
2'd2:y = d[2];
default: y = d[3];
endcase
end
endmodule
对应的电路图如下:
module mux4to1(din,d,dout);
input wire[1:0] din;
input wire[3:0] d;
output reg dout;
always @(*) begin
if(din[2])
dout = d2;
else if(din[1])
dout = d1;
else if(din[0])
dout = d0;
else dout= d3;
end
endmodule
N-2^N译码器
独热码:每次只有一位输出。
3-8译码器
module dec_3to8(
din ,
dout
);
input wire [2:0] din;
ouput reg [7:0] dout;
always @(*) begin
case(din)
3'b000:dout = 8'h01;
3'b001:dout = 8'h02;
3'b010:dout = 8'h04;
3'b011:dout = 8'h08;
3'b100:dout = 8'h10;
3'b101:dout = 8'h20;
3'b110:dout = 8'h40;
3'b111:dout = 8'h80;
endcase
end
endmodule
//实现输出a+b-c
wire clk,rstn;
wire [15:0]a,b,c;
wire [17:0]out0;
reg [17:0[ out1;
assign out0 = {2'b0,a}+{2'b0,b}-{2'b0,c}; //连续赋值语句
always @(*) begin //过程赋值语句
//always @(a or b or c) begin
out1 = {2'b0,a}+{2'b0,b}-{2'b0,c};
end
CSA(Carry Save Adder,进位保存加法器)
【HDL系列】进位保存加法器原理与设计 - 知乎
工具会默认把wire数当作有符号数
wire [15:0] a,b; //singned number
wire [16:0] out0;
wire [16:0] out1;
assign out0 = {a[15],a}-{b[15],b}; //
assign out1 = a-b; //这种会出错
//实现输出a+b-c
wire clk,rstn;
wire [15:0]a,b,c;
reg [17:0[ out2,out3;
//1.同步复位
always @(posedge clk) begin
if(!rstn)
out2 <= 'd0;
else
out2 <= {2'b0,a}+{2'b0,b}-{2'b0,c};
end
//2.异步复位
always @(posedge clk or negedge rstn) begin
if(rstn)
out3 <= {2'b0,a}+{2'b0,b}-{2'b0,c};
else
out3 <= 'd0;
end
[FPGA复位——同步复位和异步复位]https://www.jianshu.com/p/f2f78b4be64c
同步复位等效电路
顾名思义,同步复位就是指复位信号只有在时钟上升沿到来时,才能有效。否则,无法完成对系统的复位工作。
异步复位等效电路
它是指无论时钟沿是否到来,只要复位信号有效,就对系统进行复位。
连续赋值(assign x=y;):不能在过程块内使用;
过程阻塞性赋值(x=y;):只能在过程块中使用;
过程费阻塞性复制(x<=y):只能在过程块内使用。
initial
只能执行一次,在仿真一开始就执行,begin...end
之间是顺序执行(非阻塞赋值除外)
initial
begin
语句1;
语句2;
......
语句n;
end
always
always 语句是重复执行的。always 语句块从 0 时刻开始执行其中的行为语句;当执行完最后一条语句后,便再次执行语句块中的第一条语句,如此循环反复。(非阻塞赋值除外)
对于硬件综合来说,存在两种always块:
组合逻辑:`always @(*)`
时序逻辑:`always @(posedge clk)`
时序always块也会像组合always块一样生成一系列的组合电路,但同时在组合逻辑的输出生成了一组触发器(或寄存器)。该输出在下一个时钟上升沿(posedge clk)后可见,而不是之前的立即可见。
always @ (event)
[statement]
always @ (event) begin
[multiple statements]
end
assign
assign相当于连线,一般是将一个变量的值不间断地赋值给另一个变量,就像把这两个变量连在一起,所以习惯性的当做连线用,比如把一个模块的输出给另一个模块当输入。只能用于阻塞赋值。
要更好的把握assign的使用,Verilog中有几个要点需要深入理解和掌握: - 在Verilog module中的所有过程块(如initial块和always块)、连续赋值语句(如assign语句)和实例引用都是并行的。在同一module中这三者出现的先后顺序没有关系。 - 只有连续赋值语句assign和实例引用语句可以独立于过程块而存在于module的功能定义部分。 - 连续赋值assign语句独立于过程块,所以不能在always过程块中使用assign语句。
b<=a;
c<=b;
/*
clk0 b0=初值 c0也等于初值
clk1 b1=a c1=b0
clk2 b2=a c2=b1=a
*/
wire clk,rstn;
wire din;
reg din_dly;
wire pulse;
assign pulse = din & (!din_dly);
always @(posedge clk or negedge rstn)
if(!rstn)
din_dly <= 1'b0;
else
din_dly <= din;
assign sum = a ^ b ^ cin;
assign cout = a&b | a&cin | b&cin;
<-->
{cout,sum} = a + b + cin;
在设计电路时,必须首先具体考虑电路:
1、我想实现一个逻辑门;
2、我想实现一个具有输入并产生输出的组合逻辑块;
3、我想实现一组组合逻辑,紧接着一组触发器。
不要上来就写代码,这样往往与你想象的电路相差很远。
除了你指定的情况以外,会发生些什么,答案是什么也不会发生,输出保持不变。而这往往就导致了电路的错误,所以说语法正确的代码不一定能产生合理的电路(组合逻辑+触发器)。
输出保持不变,这就意味着电路需要记住当前状态,从而产生锁存器。组合逻辑(比如逻辑门)不能记住任何状态。