Vivado使用技巧-支持的Verilog语法
复杂的电路设计通常使用自顶向下的设计方法,设计过程中的不同阶段需要不同的设计规格。比如架构设计阶段,需要模块框图或算法状态机(ASM)图表这方面的设计说明。一个框图或算法的实现与寄存器(reg)和连线(wire)息息相关。Verilog便具有将ASM图表和电路框图用计算机语言表达的能力,本文将讲述Vivado综合支持的Verilog硬件描述语言;
Verilog提供了行为化和结构化两方面的语言结构,描述设计对象时可以选择高层次或低层次的抽象等级。使用Verilog设计硬件时,可以将其视作并行处理和面向对象编程。Vivado综合支持IEEE 1364标准。Vivado综合对Verilog的支持可以用最有效的方式描述整体电路和各个模块。综合会为每个模块选择最佳的综合流程,将高层次的行为级或低层次的结构级转换为门级网表;
1.Variable Part Selects 可变部分选择
除了用两个明确的值限定选择边界外(如assign out = data[8:2]),还可以使用变量从向量中选择一组bit。设置一个起始点和截取的宽度,起始点可以动态变化,示例如下:
reg [3:0] data;
reg [3:0] select;
wire [7:0] byte = data[select +: 8]; //+、-表示从起始点开始增加或减少
2.Structural Verilog 结构化verilog
Verilog可以进行多个代码块设计,并按一定的设计层次组合起来,下面给出于此相关的重要概念:
组件(Component):结构化设计中的一个基本块;
申明(Declaration):组件与外部交流的信息;
主体(Body):组件内部的行为或结构;
端口(Port):组件的I/O;
信号(Signal):组件与组件之间的连线;
一个组件用常见的模块(module)来表示,组件之间的连接由实例化(instantiation)声明实现,实例化声明规定一个组件在另外一个组件或电路中的实例,赋予标识符,并用关系列表设定信号与端口之间的联系;
除了自己设计的组件外,结构化Verilog还支持实例化预定义的原语:逻辑门、寄存器、Xilinx特定的原语(如CLKDLL、BUFG),这些原语都定义在Xilinx Verilog库文件unisim_comp.v中,逻辑门原语包括AND、OR、XOR、NAND、NOR、NOT,实例化这些逻辑门来搭建更大的逻辑电路,示例如下:
//实现2输入或非逻辑功能
module build_xor
(
input a, b,
output c
);
wire a_not, b_not;
//每个实例必须有不同的实例化名称
not a_inv (a_not, a);
not b_inv (b_not, b);
and a1 (x, a_not, b);
and a2 (y, b_not, a);
or out (c, x, y);
endmodule
//实例化预定义的原语FDC和BUFG
module example (sysclk, in, reset, out);
input sysclk, in, reset;
output out;
reg out;
wire sysclk_out;
FDC register (out, sysclk_out, reset, in); //position based referencing
BUFG clk (.O(sysclk_out),.I(sysclk)); //name based referencing
3.Verilog Parameters verilog参数
参数化代码提高了可读性和代码紧凑型、容易维护和再使用。一个Verilog参数(parameter)就是一个常数(不支持字符串),且实例化参数化模块时可以改写参数值,下面给出示例:
//Verilog参数控制实例化块寄存器的宽度
module myreg #(parameter SIZE = 1)
(
input clk, clken,
input [SIZE-1:0]d,
output reg [SIZE-1:0]q
);
always @(posedge clk)
if (clken) q <= d;
endmodule
//顶层模块
module test #(parameter SIZE = 8)
(
input clk, clken,
input [SIZE-1:0] di,
output [SIZE-1:0] do
);
myreg #SIZE inst_reg (clk, clken, di, do);
endmodule
module parameter_generate_for_1 (clk, si, so);
parameter SIZE = 8;
input clk;
input si;
output so;
reg [0:SIZE-1] s;
assign so = s[SIZE-1];
always @ (posedge clk)
s[0] <= si;
genvar i;
generate
for (i = 1; i < SIZE; i = i+1)
begin : shreg
always @ (posedge clk)
begin
s[i] <= s[i-1];
end
end
endgenerate
endmodule
4.Verilog Usage Restrictions Verilog使用限制
在Vivado综合中用到的Verilog语法有如下3点限制:
大小写敏感:Verilog是一种大小写敏感的语言,但在Vivado中,只有实例和信号名称会区分大小写。如果两个module名称只有大小写不同,综合时会报错
阻塞和非阻塞赋值:不要混合使用阻塞和非阻塞赋值。尽管综合时可能不会报错,但在仿真时会出现错误
整数的处理 某些情况下,Vivado综合器处理整数时与其它综合工具方法不同,因此必须使用特定的代码编写方式。例如在Case语句或拼接语句中,使用未定义大小的整数都会导致无法预料的结果;
下面给出两个错误例子:
//同一信号不要混用阻塞和非阻塞赋值
always @(in1)
if (in2) out1 = in1;
else out1 <= in2;
//同一信号的不同bit不要混用
if (in2) begin
out1[0] = 1'b0;
out1[1] <= in1;
end
else begin
out1[0] = in2;
out1[1] <= 1'b1;
end
整数处理方式不当引起错误的情况:
reg [2:0] condition1; always @(condition1) begin
case(condition1)
4 : data_out = 2; // Generates faulty logic 未声明4的位宽,而condition1的位宽为3
3'd4 : data_out = 2; // Does work
endcase
end
//拼接语句
reg [31:0] temp;
assign temp = 4'b1111 % 2; //未确定位宽的运算用临时信号存储
assign dout = {12/3,temp,din}; //12/3运算位宽不确定,结果错误
5. Verilog System Tasks and Functions 系统任务和函数
Vivado综合支持的Verilog构造与系统任务包括:
整数、实数、assign(有限制)、deassign(有限制)、repeat语法(重复值必须是常数)、for语法(范围必须是静态的)、disable(不能用于for循环和repeat循环)、module定义、defparam、实例数组、`default_nettype、`define、`ifdef、`ifndef、`elsif、`include、`file、`line、$fclose、$fgets、$fopen、$fscanf、$readmemb、$readmemh、$signed、$unsigned、$floor(仅用于参数)、$ceil(仅用于参数)。
Vivado综合不支持和会忽视的的Verilog构造和系统任务包括:
字符串、网络类型(tri0、tri1、trireg)、驱动强度、实数和实时寄存器、命名事件、事件(@)、延迟(#)、force、release、forever语法、wait、并行块、设定块、macromodule定义、层次结构名称、`celldefine、`endcelldefine、`resetall、`timescale、`unconnected_drive、`nounconnected_drive、`uselib、$display、$fdisplay、$finish、$fwrite、$monitor、$random、$stop、$strobe、$time、$write、$clog2(仅SystemVerilog支持)、$rtoi、$itor、all others。
介绍其中几个非常常用的系统任务:
$signed和$unsigned可以强制规定输入数据为带符号数或无符号数,并作为返回值,不用管之前的符号。
$readmemb和$readmemh可以用于初始化块存储器,两者分别用2进制和16进制表示。如“$readmemb(“ram.data”, ram, 0, 7)”;
6.Verilog Primitives 原语
Vivado支持上文列出的Verilog门级原语,但不支持上拉下拉、驱动强度和延迟、原语矩阵这些类型的门级原语,也不支持如下转换级原语:cmos、nmos、pmos、rcmos、rnmos、rpmos、rtran、rtranif0、rtranif1、tran、tranif0、tranif1;
实例化门级原语的示例如下:
gate_type instance_name (output, inputs); //语法模板
and U1 (out, in1, in2);
bufif1 U2 (triout, data, trienable);
7.Behavioral Verilog 行为级verilog
行为级Verilog中的变量都申明为整数,数据类型可以是reg(程序块中赋值)、wire(连续赋值)和integer(会被转换为寄存器类型);所有变量的默认位宽为1bit,称作标量(scalar);定义的N bits位宽变量称作向量(Vector);reg和wire可以定义为带符号数signed或无符号数unsigned;变量的每个bit可以是如下值:1(逻辑1)、0(逻辑0)、x(未知逻辑值)、z(高阻);
reg [3:0] arb_priority;
wire [31:0] arb_request;
wire signed [8:0] arb_signed;
寄存器在定义时可以初始化,初始值是一个常数或参数,不能是函数或任务的调用;在全局复位或上电时,Vivado综合会将初始化值作为寄存器的输出(作为寄存器的INIT属性值);而且该初始值与本地复位是相互独立的 ;
reg arb_onebit = 1'b0;
reg [3:0] arb_priority = 4'b1011;
Verilog支持定义wire和reg的数组,支持一维数组和二维数组,但每次从数组中选择的元素不能超过一个,数组也不能作为任务或函数的传递参数。数组的定义示例如下:
//有32个元素的数组,每个元素4bits位宽
reg [3:0] mem_array [31:0];
//包含64个8bits位宽元素的数组
wire [7:0] mem_array [63:0];
//包含256*16个8bits位宽wire元素的二维数组
wire [63:0] array2 [0:255][0:15];
//包含256*8个64bits位宽reg元素的二维数组
reg [63:0] array2 [255:0][7:0];
Vivado支持的所有表达式列在下表中:
其中“===”和“!==”在综合时与“==”和“!=”功能相同,没有任何差别。但在仿真中,可以用来判断变量是否与’x’和’z’是否相等。下表给出常用操作符的运算结果,以供查阅:
initial和always是两个程序块,每个块内部组织了一些语法声明,用begin和end表示范围。块内部的语法声明按顺序执行。综合时只会处理always块,会忽略initial块 ;
8.模块module
Verilog中描述组件(component)的方法便是模块(module),模块必须申明与实例化。模块申明包括模块名称、电路I/O端口列表、定义功能的主体,并以endmodule结束;
每个电路I/O端口要有名称、端口模式(input、output、inout),如果端口是数组类型还要有范围信息。下面给出两种模块申明方法的示例:
//方法1
module example (A, B, O);
input A, B;
output O;
assign O = A & B;
endmodule
//方法2,推荐用法
module example
(
input A, B,
output O
);
assign O = A & B;
endmodule
实例化模块时,要定义一个实例化名称和一个端口关系表。列表要规定实例与顶层模块之间如何连接,列表中的每一个元素将模块申明中的一个形式端口(port)和顶层模块中的实际网络(net)连接在一起。下面给出一个实例化上述模块的例子:
module top
(
input A, B, C,
output O
);
wire tmp;
example inst_example (.A(A), .B(B), .O(tmp));//实例化
assign O = tmp | C;
endmodule
连续赋值 Continuous Assignments
连续赋值语句常用于组合逻辑中,在综合时vivado会忽略组合逻辑的延时和强度,并且连续赋值只能对wire和tri数据类型赋值;
直接连续赋值用assign关键词开头,紧跟一个已经申明过的网络:“wire mysignal; assign mysignal = select ? b : a;”;
简介连续赋值在申明时便完成赋值:“wire misignal = a | b;”;
9.Procedural Assignments 过程赋值
如上所述,wire和三态类型要用连续赋值,reg类型变量则需要用过程赋值,借助always块、任务(task)、函数(function)实现;
always块中的组合逻辑由Verilog时间控制语句有效地建模。其中,延迟时间控制语句[#]仅用于仿真,综合时会忽略;组合逻辑建模主要由事件控制时间控制语句[@]实现;
每个always块都有一个敏感列表,列在“always @”后面的括号中。如果敏感列表中一个信号的相关事件发生(值变化或边沿到来),就会激活该always块。在always块中,如果信号没有在if或case的所有分支中明确地赋值,综合会产生一个锁存器保持之前的值。一个程序块中可以使用如下语句:
[1] if-else:
使用true和false条件来执行语句,执行多条语句要使用begin…end关键词,注意在前面的分支优先级最高;示例如下:
module mux4 (sel, a, b, c, d, outmux);
input [1:0] sel;
input [1:0] a, b, c, d;
output [1:0] outmux;
reg [1:0] outmux;
always @(sel or a or b or c or d)
begin
if (sel[1])
if (sel[0])
outmux = d;
else
else
outmux = c;
if (sel[0])
outmux = b;
end endmodule
else
outmux = a;
[2] case:
比较表达式和分支的值,比较顺序按照编写分支的顺序进行,执行第一个匹配的分支,在前面的分支优先级最高;如果没有匹配项则执行default分支;case语句中不要使用未指定位宽大小的整数,否则可能会产生错误结果;
casez将分支的任意bit位上的z值视作不关心;casex将分支的任意bit位上的x值视作不关心;casez和casex中不关心的bit用‘?’代替;
下面给出一个使用case的示例代码:
module mux4
(
input [1:0] sel,
input [1:0] a, b, c, d,
output reg [1:0] outmux
);
always @ *
case(sel)
2'b00 : outmux = a;
2'b01 : outmux = b;
2'b10 : outmux = c;
2'b11 : outmux = d;
endcase
endmodule
上述代码在评估输入值时,按照一定的优先级顺序进行。如果希望能并行地处理这个过程,使用paralled_case属性,将case语句替换为“(* paralled_case *)” case(sel)”;
[3] For与Repeat:
For循环的边界必须是常数,停止循环条件需要使用>、<、>=、<=四种运算符。使用“var = var +或- step”来控制执行下一轮运算,var为循环变量,step是一个常数值;
repeat语句,重复次数也必须是常数值;
[4] While循环:
While的测试表达式可以是任意合法的Verilog表达式。为了避免造成无限循环,可以使用-loop_iteration_limit选项。该语法很少使用,下面给出一个示例代码:
parameter P = 4;
always @(ID_complete)
begin : UNIDENTIFIED
integer i;
reg found;
unidentified = 0;
i = 0;
found = 0;
while (!found && (i < P))
begin
found = !ID_complete[i];
unidentified[i] = !ID_complete[i];
i = i + 1;
end
end
[5] 顺序always块:
always块可以描述带有顺序性的电路,敏感列表中需要包含如下边沿触发事件(上升沿posedge或下降沿negedge):必须有一个时钟事件、可选的置位/复位事件。如果不需要异步信号,always块模板如下:
always @(posedge CLK)
begin
//同步部分
end
如果需要异步控制信号,always块模板如下:
always @(posedge CLK or posedge ACTRL1 )
begin
if (ACTRL1)
//异步部分
else
//同步部分
end
下面给出四个不同触发方式的顺序always块示例代码:
//上升沿触发时钟控制的8bits寄存器
module seq1
(
input [7:0]DI,
input CLK,
output reg [7:0] DO
);
always @(posedge CLK)
DO <= DI ;
endmodule
//添加一个高电平有效异步复位信号
module seq1
(
input [7:0]DI,
input CLK, ARST,
output reg [7:0] DO
);
always @(posedge CLK or posedge ARST)
if (ARST == 1'b1) DO <= 8'h00;
else DO <= DI ;
endmodule
//再添加一个低电平有效异步置位信号
module seq1
(
input [7:0]DI,
input CLK, ARST, ASET
output reg [7:0] DO
);
always @(posedge CLK or posedge ARST or negedge ASET)
if (ARST == 1'b1) DO <= 8'h00;
else if (ASET == 1'b1) DO <= 8'hFF;
else DO <= DI ;
endmodule
//不使用异步控制逻辑,使用同步复位
module seq1
(
input [7:0]DI,
input CLK, SRST,
output reg [7:0] DO
);
always @(posedge CLK)
if (SRST == 1'b1) DO <= 8'h00;
else DO <= DI ;
endmodule
最后再补充一些与赋值有关的内容。如果表达式左边位宽大于右边的位宽,赋值时需要在高位填充:
如果表达式右边为无符号数,则高位补0;
如果表达式右边为带符号数,则高位补符号位;
如果表达式右边的最高位为x或z,则无论该数为无符号数还是带符号数,高位都补充为x或z;
[6] Tasks and Functions 任务和函数
对于设计中要多次使用重复的代码,可以使用任务task和函数function来减少代码量,提升可维护性;
任务和函数必须在模块中申明和使用;
函数头只包含输入参数;
任务头包含输入、输出和双向参数;
函数的返回值可以申明为无符号数或带符号数,函数内容与always块类似;
下面分别给出一个函数和任务的示例代码:
//函数function使用示例
module test
(
input [3:0] A, B,
input CIN,
output [3:0] S,
output COUT
);
wire [1:0] S0, S1, S2, S3;
function signed [1:0] ADD;//输出
input A, B, CIN;//输入
reg S, COUT;
begin
S = A ^ B ^ CIN;
COUT = (A&B) | (A&CIN) | (B&CIN);
ADD = {COUT, S};
end
endfunction
assign S0 = ADD (A[0], B[0], CIN),//例化的时候只需要例化输入
S1 = ADD (A[1], B[1], S0[1]),
S2 = ADD (A[2], B[2], S1[1]),
S3 = ADD (A[3], B[3], S2[1]),
S = {S3[0], S2[0], S1[0], S0[0]},
COUT = S3[1];
endmodule
//任务task使用示例
module test
(
input [3:0] A, B,
input CIN,
output [3:0] S,
output COUT
);
reg [1:0] S0, S1, S2, S3;
task ADD;//ADD为task名称,这与上面的function不同
input A, B, CIN;//输入
output [1:0] C;//输出
reg [1:0] C;
reg S, COUT;
begin
S = A ^ B ^ CIN;
COUT = (A&B) | (A&CIN) | (B&CIN);
C = {COUT, S};
end
endtask
always @(A or B or CIN)
begin
ADD (A[0], B[0], CIN, S0);
ADD (A[1], B[1], S0[1], S1);
ADD (A[2], B[2], S1[1], S2);
ADD (A[3], B[3], S2[1], S3);
S = {S3[0], S2[0], S1[0], S0[0]};
COUT = S3[1];
end
endmodule
Verilog还支持递归任务和递归函数,要使用automatic关键词申明。递归次数由-recursion_iteration_limit选项设置,默认为64,以避免无限递归;下面给出一个计算阶乘的递归函数的例子:
function automatic [31:0] fac;
input [15:0] n;
if (n == 1) fac = 1;
else fac = n * fac(n-1);
endfunction
Vivado综合支持函数调用来计算常数值,将其称之为常数函数。下面给出一个使用常数函数的例子:
module test #(parameter ADDRWIDTH = 8, DATAWIDTH = 4)
(
input clk, we,
input [ADDRWIDTH-1:0] a,
input [DATAWIDTH-1:0] di,
output [DATAWIDTH-1:0] do
);
function integer getSize;
input addrwidth;
begin
getSize = 2**addrwidth;//2的次方
end
endfunction
reg [DATAWIDTH-1:0] ram [getSize(ADDRWIDTH)-1:0];
always @(posedge clk)
if (we) ram[a] <= di;
assign do = ram[a];
endmodule
Verilog中的常数可以用2进制、8进制、10进制和16进制表示,没有明确表示时默认为10进制;
11.Verilog宏
Verilog可以像这样定义宏“`define TESTEQ1 4’b1101”。定义的宏可以用在后面的代码中,如“if (request == `TESTEQ1)”。使用`ifdef和`endif可以检测是否定义了某个宏,相当于条件编译。如果`ifedf调用的宏被定义过,则内部的代码将会编译;如果宏没有定义,则会编译`else中的代码。`else不是必须的,但必须有`endif。
使用宏可以在不修改源代码的情况下修改设计,在IP核生成和流程测试中很有用。下面给出两个使用宏的例子:
//示例1
'define myzero 0
assign mysig = 'myzero;//注意要加宏符号
//示例2,条件编译
'ifdef MYVAR
module if_MYVAR_is_declared;
...
endmodule
'else
module if_MYVAR_is_not_declared;
...
endmodule
'endif
12 Include文件(不太理解)
Verilog可以将源代码分散在多个文件中,当需要引用另一个文件中的代码时,可以使用如下语句:“`include <path/file-to-be-included>”。该代码可以将指定文件的内容全部插入到当前文件的`include行中。Vivado首先会在指定路径中查找,如果没有找到则会在-include_dirs选项设置的目录中查找。可以同时使用多个`include语句
13 Generate
使用generate可以简化代码编写工作,generate…endgenerate中的内容再RTL分析阶段会被转换为对应的电路;
使用generate语法可以创建原语或模块实例、initial或always程序块、连续赋值、网络和变量申明、参数重定义、任务或函数定义。Vivado支持全部三种generate语法:generate循环(generate-for)、generate条件(generate-if-else)和generate情况(generate-case);
[1] generate-for
使用generate-for主要用来创建多个实例化,与for循环用法基本相同,但必须使用genvar变量,且begin语句必须有一个单独的命名;下面给出一个示例代码:
generate genvar i;
for (i=0; i<=7; i=i+1)
begin : for_name
adder add (a[8*i+7 : 8*i], b[8*i+7 : 8*i], ci[i], sum_for[8*i+7 : 8*i],
c0_or[i+1]);
end
endgenerate
[2] generate-if-else
主要用来控制生成哪一个对象,每一个分支用begin…end限定,begin语句必须有一个单独的命名;下面给出一个示例代码:
//根据数据位宽选择不同的乘法器实现方式
generate
if (IF_WIDTH < 10)
begin : if_name
multiplier_imp1 # (IF_WIDTH) u1 (a, b, sum_if);
end
else
begin : else_name
multiplier_imp2 # (IF_WIDTH) u2 (a, b, sum_if);
end
endgenerate
[3] generate-case
主要用来控制在哪种条件下生成哪个对象。case的每一个分支用begin…end限定,begin语句必须有一个单独的命名;下面给出一个示例代码:
generate
case (WIDTH)
1:
begin : case1_name
adder #(WIDTH*8) x1 (a, b, ci, sum_case, c0_case);
end
2:
begin : case2_name
adder #(WIDTH*4) x2 (a, b, ci, sum_case, c0_case);
end default:
begin : d_case_name
adder x3 (a, b, ci, sum_case, c0_case);
end
endcase
endgenerate
反激拓扑,Verilog,SOI技术文章分享
反激拓扑1—反激电路的由来
反激拓扑的原型是buck-boost拓扑
图1 传统的buck-boost拓扑
其工作过程如下:①开关S闭合,电源Ui为电感L补充能量②开关S断开时,L储存的能量通过负载放出
图2 开关S闭合
图3 开关S断开
从上述分析可以看出,buck-boost拓扑输入Ui和输出Uo正负方向相反。当把电感L等效为两个电感并联,且其匝比为1:1,同时把开关S和二极管D移动到下方方便驱动信号设计,其工作原理及其效果与传统的buck-boost电路是一样的,如下图所示
图4 传统buck-boost拓扑变形
两个并联的电感让我们想到了变压器,变压器实质上就是两个具有磁耦合的电感线圈,在图4的基础上,把两个并联的绕组分开,并通过磁芯进行耦合来传递能量,即变压器,并将其匝比1:1更改为1:n(或者Np:Ns),以便于适应更多的电压变化范围
图5 由buck-boost拓扑演变而来的隔离buck-boost拓扑
图5中的拓扑,当S闭合是,绕组Np进行充电参与电路运行,根据同名端原理,绕组Ns感应电压为上正下负,由于二极管D反向截止,故无法进行放电运行,当开关S断开时,根据楞次定律,绕组Np会感生出下正上负的电压,同理,绕组Ns下正上负,二极管导通,电感储存的能量进行放电,我们把绕组Np侧称为原边,Ns侧称为副边,此时副边的输出电压还是上负下正,看起来有点不太符合一般的阅读习惯,我们将二极管D放在上端,并将绕组Ns的同名端调转到下方,如图6所示。因为其原边绕组在经历电压激励储存能量时,副边绕组无功率输出,而原边绕组回路断开时,副边绕组才进行功率输出的特点,因为得名反激。
图6 由buck-boost演变而来的反激拓扑
根据上述演变过程,可以清楚的了解到,反激变压器实际上等效为储能电感与具有隔离作用的变压器的集合体,实际使用时,可以其励磁电感作为储能电感。
查看原文:https://www.dianyuan.com/eestar/article-8370.html
联合Verilog和Modelsim模拟状态机
今天这篇文章想分享一下从零开始,使用Verilog写一个状态机,并用Modelsim软件仿真状态机的效果。文章的框架如下所示:
1. 前言
2. 什么是状态机
3. 状态机的分类
4. 定义一个场景
5. Verilog代码实现
6. Modelsim仿真
7. 总结
整篇文章阅读大概需要8分钟。
1.前言
去年在接触USB接口时,看到手册中描述要控制这个USB3.0的PHY,需要使用状态机,如下图所示。当时感觉这个玩意挺有意思,但是由于这是软件开发的内容,所以就没太在意具体细节是怎么实现的。
于是,从那时起状态机这个名字就一直停留在我的脑海里,但是也一直搁置,没有去尝试着自己做做看。最近打算自己写一个,因此就有了这篇文章,用Verilog写个状态机。
2.什么是状态机
逻辑电路根据是否包含记忆元件分为组合逻辑和时序逻辑。组合逻辑电路不包含记忆元件,因此组合逻辑的特点是当前的输出等于输入。时序逻辑电路含有记忆元件,因此时序逻辑电路的输出并不完全取决于当前的输入,还和过去的状态有关。时序逻辑电路的输出受到输入和记忆元件值的共同影响。
这里和我们以前学习的自动控制系统类似,对开环系统来说,输出和输入相对应。而对于闭环系统来说,会把过去的输出反馈到当前的输入上,所以当前的输出其实会受到过去输出的影响。
组合逻辑的输出和输入直接相关,直接用NOT-AND-OR就能描述清楚。而时序电路则可以使用有限状态机(FSM)来描述。
3.状态机的分类
状态机分类两种类型米勒Mealy型和摩尔Moore型。米勒型的状态机输出由内部状态和输入共同决定。摩尔型的输出仅由内部状态确定。
摩尔型
米勒型
从上面的结构图可以看出,摩尔型的输出,是直接和当前状态S(t)相同,但是米勒型的输出,不仅和当前的S(t)相关,与当前的状态也有关。
4.定义一个场景
状态机在我们生活中用的比较多,最常见的就是在寝室门口,地铁进站口的自动售货机,使用状态机就可以描述出来。比喻,售货机里面的烤面包2.5元一个,机器的投币口只接受硬币,假设我们去购买时,只有0.5元和1元的硬币,那么在购买面包的过程中,就可以用状态机来实现。
网络协议由三个要素组成,语义,语法,时序,采用类比的思想,状态机也有三个要素组成,分别是输入,输出,和状态。在设计状态机时,可以从这三个状态入手,一步一步完成状态机的建立。
以买烤面包的场景为例,输入为投入的硬币,可能是0.5元可能是1元,输入有两种可能性,而且输入会立刻影响状态机的跳转;输出是我们最终想要的结果,出面包或者找零钱;在买面包的过程中,不同的状态受到上一个状态和当前输入的影响。
以上的分析结果为:
输入:0.5元,1元
输出:出面包但是不找零;出面包而且找零
状态:初始状态,投入0.5元,投入0.5元,投入1.5元,投入2元,投入2.5元,投入3元
考虑状态在2.5元和状态在3元时,都会输出结果,因此将2.5元和3元的状态直接和初始的状态合并。出完面包或者找完零以后,机器会立马回到最初状态。画出整个系统的状态图如下:
其中:01/00:代表投入0.5元,没有输出;10/00:代表投入1元,没有输出;10/11:代表投入1元,出面包且找零,其他的可以类推。
5. Verilog代码实现
定义接口和状态
描述状态机的跳转,状态机只有在输入了硬币的条件下才转移,这也是触发状态机变化的条件。
描述输出面包和输出找零的结果。
从上面的代码可以看出来,状态机的描写可以看成是两个部分。第一个部分是只管状态的转移,仅仅是在有输入的情况下影响了状态,此时不管输出。这部分代码完成了状态机三要素中的两个要素,输入和状态。第二部分只管描述输出,这部分的输出是采用了米勒型来描述,不仅和当前的状态有关,还和输入有关。这部分代码完成了状态机三要素的另一个要素,输出。
6. Modelsim仿真
编写Testbench文件来仿真上面的状态机功能,看看在不同输入条件下,状态机是否能正常跳转。使用Modelsim软件查看波形。
定义接口列表
例化
仿真结果
从上面的仿真的结果来看,状态机的功能正常。截图所示是连续5次0.5元,此时出面包,但是没有找零。2次0.5元,2次1元,出面包,并且找零。仿真的结果和我们最初的设计吻合。
7.总结
当把这个状态机写完才发现,使用Verilog写状态机也不是很难。好像学习都是这样,没有做过的东西都感觉有难度,等自己学会了以后,就会发现并没有想象中的那么复杂。
学习状态机不难的原因是它和我们之前学过的EMC三要素差不多。在EMC设计中抓住三个要素,就能设计较好性能的单板,同样,写状态机时只要抓住了它的输入,输出,状态这三个要素,其实也可以搞定。
查看原文:https://www.dianyuan.com/eestar/article-8313.html
绝缘体上硅(SOI)驱动芯片技术优势及产品系列
在之前的技术文章中,介绍了驱动芯片的概览和PN结隔离(JI)技术,本文会继续介绍英飞凌的绝缘体上硅(SOI)驱动芯片技术。
高压栅极驱动IC的技术经过长期的发展,走向了绝缘体上硅(silicon-on-insulator,简称SOI),SOI指在硅的绝缘衬底上再形成一层薄的单晶硅,相对于传统的导电型的硅衬底,它有三层结构,第一层是厚的硅衬底层,用于提供机械支撑,第二层是薄的二氧化硅层,二氧化硅是一种绝缘体,从而形成一层绝缘结构,第三层是薄的单晶硅顶层,在这一层进行电路的刻蚀,形成驱动IC的工作层。
图1.绝缘体上硅SOI(左图)与传统体硅(Bulk CMOS)(右图)结构的比较
SOI在1964年由C.W. Miller和P.H. Robinson提出,经过几十年的发展,逐渐成熟。英飞凌采用了SOI的独特设计的栅极驱动IC,从设计上带来了诸多优势。其中,最大的优势在于,SOI的二氧化硅的绝缘层,能够彻底消除体硅(Bulk CMOS)结构中衬底中的寄生PN结,从而消除了闭锁效应,提高了驱动芯片耐受负压的能力。
图2.传统体硅(Bulk CMOS)(左图)与绝缘体上硅SOI(右图)寄生PN结的比较
从栅极驱动IC的设计结构上,如图3所示,可以清楚的看到相关电路的影响,在体硅(Bulk CMOS)的设计中,对于高边电路,衬底连接COM电位,MOS的源极SOURCE连接VS电位,因为衬底与VS之间存在一个寄生二极管,从而在某些工况下,当COM的电位高于VS的电位时,寄生二极管会导通,产生无法控制的电流,从而对电路的可靠性产生影响。在绝缘体上硅SOI的驱动IC中,因为二氧化硅绝缘层的存在,消除了连接COM和VS的寄生二极管,从而极大提升了驱动IC的可靠性。
图3.传统体硅(Bulk CMOS)(左图)与绝缘体上硅SOI(右图)寄生PN结对设计的影响
驱动芯片的耐受负压(VS的电压低于COM)的能力,对于电机驱动应用,或者桥式电路带感性负载的应用情况,都非常重要。如图4所示,当上管Q2关闭的时候,负载电流切换到下管D1,此时电流从负母线流向负载。考虑动态的情况,在D1上的电流逐步建立的过程中,在VS~COM之间,会产生由Ls1和Ld1的感生电压,以及Q1的二极管的导通电压,总的电压等于这三个电压的叠加,方向上电压在COM为正,VS为负。因为这类应用中,负压现象不可避免,所以驱动IC耐受这个负压的能力越高越好,图4的右图可以看出,英飞凌的SOI驱动IC,抗负压的能力可以达到-100V/300ns或者-60V/1000ns,这种抗负压的能力远远大于JI设计的驱动IC。
图4.桥式电路中负压的产生,及英飞凌的SOI驱动的负压耐受工作区
另外,SOI的结构中,因为寄生PN结的消失,器件的寄生效应减小,器件的开关损耗也可极大的降低,并且由于漏电流的减小,静态功耗也可以得到降低,从而使得采用SOI设计的驱动IC,工作频率能够更高,整体损耗更小。图5对比了300kHz的开关频率下,2ED2106(SOI设计)与IR2106(Bulk CMOS设计)的温升对比,可以看到,2ED2106的最高温度只有66°C,而IR2106的温度高达122°C。
图5.绝缘体上硅SOI与传统体硅(Bulk CMOS)的驱动IC的温升比较
再次,SOI因为存在良好的介质隔离,更方便进行集成。英飞凌的SOI的驱动IC集成了自举二极管,从而能够节省掉以前需要外加的高压自举二极管,从而节省系统成本。
图6.绝缘体上硅SOI集成自举二极管示意图
综上所述,绝缘体上硅SOI是栅极驱动器的一次技术飞跃,具有负压耐受能力强、损耗低、集成自举二极管等一系列的优异特性。
英飞凌已经推出了大量的绝缘体上硅SOI的驱动IC,电压覆盖200V至1200V,结构有高低边驱动、半桥及三相桥。
查看原文:https://www.dianyuan.com/eestar/article-8182.html
数字电路中传输延时的影响 — 竞争冒险
门电路的两个或多个输入信号同时向相反的逻辑电平跳变的现象叫做竞争 ,这种竞争可能在电路的输出端产生尖峰脉冲,这种现象称为竞争冒险 。
竞争冒险产生的根本原因是不同的输入信号是通过不同的路径传输的,每条路径的传输延时不同 ,从而导致信号不能同时到达,输出信号就会出现不应出现的毛刺。接下来,我们通过一个简单的例子了解一下竞争冒险现象。
这是一个组合逻辑电路,输入信号B取反后与输入信号A异或得到输出信号C。
假设输入信号由
A=0 ,B=1
变化为
A=1 ,B=0
理论上,输出信号C恒为0,时序图如下:
但是,实际信号在传播过程中必然会存在一定的延时,为分析简单起见,只考虑非门的延时,则时序图如下,输出信号C出现了毛刺 ,就有可能影响后级电路的逻辑功能,这就是竞争冒险 。
下面通过仿真来验证一下上述分析:
对于仅考虑逻辑功能的功能仿真 ,仿真结果与理想情况下的时序图一致,输出信号C恒为0,没有出现毛刺。
而考虑了传输延时的门级仿真 ,输出信号C出现毛刺,由于仿真过程考虑的信号延时情况更复杂,因此时序图与上述分析存在一定区别。
查看原文:https://www.dianyuan.com/eestar/article-8417.html
更多精彩内容,尽在电子星球 APP(https://www.eestar.com/)
六篇技术文章,让你秒懂电容的脾气秉性
七篇DIY技术文章献给你,让你脑洞全开
五篇文章帮你开启DSP的学习思路
汇总篇:关于PID知识,重点在此
相关问答
verilog --------求解释"输入端口可以由wire/reg驱动,但输入端口只能是wire”?reg相当于存储单元wire相当于物理连线Verilog中变量的物理数据分为线型和寄存器型。这两种类型的变量在定义时要设置位宽缺省为1位。变量的每一位可以是01X...
可实现模拟/数字电路的Spice仿真、VHDL/ Verilog 设计与仿真...[最佳回答]Today'ssociety,therhythmofpeople'slivesgreatlyacceleratedwhenatimertoremindpeo...
伪随机码(PN码)——m序列的发生器设计[回答]什么是伪随机序列呢?让我们看一个例子。序列α=0110100,其中0和1的个数相差1。把α看成周期为7的无限序列,左移1位得,α1=1101000,把α1也看成周...
全世界最强CPU-ZOL问答英特尔XeonPlatinum8180,28核心56线程,主频2.5-3.8GHz,三级缓存38.5MB,内存支持六通道DDR4-2666ECC(最大768GB),热设计功耗205W,目前国内没...
Verilog 语言中if语句里可以写两种条件吗,如if(a> 0 and b> 0...这4种情况表达方式是:if(a>0)if(b>0).//对应的是a>0,b>0;else.//对应的是a>0,b0).//对应的是a0;else.//对应...