VHDL描述基本逻辑门
简单地说,逻辑门是数字电路的基本结构,所有数字电路都由与门和、与非门、或非和反相器组成。逻辑门电路常用于各种电子设备硬件,如计算机、数字手表、电视、手机…
1,非门,又称反相器,简称非门,是逻辑电路的基本单元。非门有一个输入和一个输出端。当其输入端为高电平(逻辑1)时输出端为低电平(逻辑0),当其输入端为低电平时输出端为高电平。也就是说,输入端和输出端的电平状态总是反相的。非门的逻辑功能相当于逻辑代数中的非,电路功能相当于反相,这种运算亦称非运算。
非门符号
非门真值表
非门真值表
VHDL 代码library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity NOT_GATE is
Port ( A : in STD_LOGIC;
B : out STD_LOGIC);
end NOT_GATE;
architecture Behavioral of NOT_GATE is
begin
B <= NOT A;
end Behavioral;
仿真波形
非门仿真波形
2,与门是执行“与”运算的基本逻辑门电路。有多个输入端,一个输出端。当所有的输入同时为高电平(逻辑1)时,输出才为高电平,否则输出为低电平(逻辑0)。
与门符号
与门真值表
与门真值表
VHDL 代码
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity AND_GATE is
Port ( A : in STD_LOGIC;
B : in STD_LOGIC;
C : out STD_LOGIC);
end AND_GATE;
architecture Behavioral of AND_GATE is
begin
C <= A AND B;
end Behavioral;
仿真波形图
与门仿真波形图
3,与非门是数字电路的一种基本逻辑电路。若当输入均为高电平,则输出为低电平;若输入中至少有一个为低电平,则输出为高电平。与非门是与门和非门的叠加。
与非门符号
与非门真值表
与非门真值表
VHDL 代码
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity NAND_GATE is
Port ( A : in STD_LOGIC;
B : in STD_LOGIC;
C : out STD_LOGIC);
end NAND_GATE;
architecture Behavioral of NAND_GATE is
begin
C <= A NAND B;
end Behavioral;
与非门仿真波形图
4,或门又称或电路、逻辑和电路。或门有多个输入端,一个输出端,只要输入中有一个为高电平时(逻辑“1”),输出就为高电平(逻辑“1”);只有当所有的输入全为低电平(逻辑“0”)时,输出才为低电平(逻辑“0”)。
或门符号
或门真值表
或门真值表
VHDL 代码
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity OR_GATE is
Port ( A : in STD_LOGIC;
B : in STD_LOGIC;
C : out STD_LOGIC);
end OR_GATE;
architecture Behavioral of OR_GATE is
begin
C <= A OR B;
end Behavioral;
或门仿真波形图
或门仿真波形图
5,或非门是数字逻辑电路中的基本元件,实现逻辑或非功能。有多个输入端,一个输出端,多输入或非门可由2输入或非门和反相器构成。只有当两个输入A和B为低电平时输出为高电平。
或非门符号
或非门真值表
或非门真值表
VHDL 代码
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity NOR_GATE is
Port ( A : in STD_LOGIC;
B : in STD_LOGIC;
C : out STD_LOGIC);
end NOR_GATE;
architecture Behavioral of NOR_GATE is
begin
C <= A NOR B;
end Behavioral;
或非门仿真波形图
或非门仿真波形图
6,异或门是数字逻辑中实现逻辑异或的逻辑门。有多个输入端、1个输出端。若两个输入的电平相异,则输出为高电平1;若两个输入的电平相同,则输出为低电平0。亦即,如果两个输入不同,则异或门输出高电平。
异或门符号
异或门真值表
异或门真值表
VHDL 代码
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity XOR_GATE is
Port ( A : in STD_LOGIC;
B : in STD_LOGIC;
C : out STD_LOGIC);
end XOR_GATE;
architecture Behavioral of XOR_GATE is
begin
C <= A XOR B;
end Behavioral;
异或门仿真波形图
异或门仿真波形图
7,同或门也称为异或非门,是数字逻辑电路的基本单元,有2个输入端、1个输出端。当2个输入端中有且只有一个是低电平时,输出为低电平。亦即当输入电平相同时,输出为高电平。
同或门符号
同或门真值表
同或门真值表
VHDL 代码
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity XNOR_GATE is
Port ( A : in STD_LOGIC;
B : in STD_LOGIC;
C : out STD_LOGIC);
end XNOR_GATE;
architecture Behavioral of XNOR_GATE is
begin
C <= A XNOR B;
end Behavioral;
同或门仿真波形图
同或门仿真波形图
System C的模块和过程
模块和过程
本节包含一个完整的简单设计,以演示SystemC中模块和过程的使用。为了简单起见,它是非常低的级别-而不是您通常期望的系统级别设计语言中的编码样式!
展示的要点是
建立阶层
所述sc_signal原始信道
(专用)端口
进程(SC_METHOD,SC_THREAD,SC_CTHREAD)
一个简单的测试台
SystemC背景
为什么要查看模块和流程?原因是SystemC旨在应付硬件和软件,并允许对大型系统进行建模。
进程是与其他进程同时运行的一小段代码。几乎所有已开发的高级系统级设计(SLD)工具都使用流程网络的基础模型。SystemC提供了支持独立(并行/并行)代码段网络构建的过程。
SLD需要处理大型设计。为了解决这个问题,通常使用层次结构。层次结构是通过使用模块在SystemC中实现的,该模块可以使用端口链接到其他模块。模块允许单独进行一项设计。模块可以包含进程和其他模块的实例。
实例设计
该设计包括一个EXOR门和四个NAND门。同样,必须注意,这不是典型的设计风格-很好理解。设计看起来像这样
第一步是对“与非”门建模。NAND门是组合电路;它的输出纯粹是输入值的函数。它没有内存,并且不需要时钟。因此,模型可以使用最简单的SystemC进程SC_METHOD。
SC_METHOD只是C ++函数。因此,SystemC类库必须使它们的行为像进程一样。尤其是
SystemC类库包含一个仿真内核,这是一段代码,用于模拟时间的流逝,并在函数的输入发生更改时调用函数以计算其输出。
该函数必须声明为SC_METHOD,并且对其输入敏感。
这是一个与非门的代码,位于一个文件nand.h中
#include“ systemc.h”SC_MODULE(nand2)//声明nand2 sc_module{
sc_in <布尔> A,B; //输入信号端口
sc_out <布尔> F; //输出信号端口
void do_nand2()//一个C ++函数
{
F.write(!(A.read()&& B.read()));
}
SC_CTOR(nand2)// nand2的构造函数
{
SC_METHOD(do_nand2); //向内核注册do_nand2
敏感<< A << B; //敏感度列表
}};
SystemC中的层次结构是使用类sc_module创建的。sc_module可以直接使用,也可以使用宏SC_MODULE “隐藏” 。上面的示例SC_MODULE创建了一个名为nand2的sc_module类对象。
接下来是声明的输入和输出端口。通常,使用类sc_port声明端口。例如,将声明 使用sc_signal的输入端口
sc_port <sc_signal_in_if <bool>,1> A,B;
但正如您所看到的,这是很多输入。为了方便起见,还可以创建和使用专用端口。sc_in是sc_signal类的专用端口的示例。
端口可以是任何C ++或SystemC类型-该示例使用内置的C ++类型bool。
接下来,声明完成工作的函数。输入和输出(专用)端口包括方法read()和write(),以允许读写端口。读取A和B,计算NAND函数,然后使用write()方法将结果写入F。
请注意,由于=运算符和类型转换运算符已被重载,因此您通常可以不使用read()和write()方法而逃脱。所以你可以写
F =!(A && B);
但是使用read()和write()是一个好习惯,因为它有助于C ++编译器消除表达式的歧义。
编写函数do_nand2()之后,将为sc_module实例nand2提供一个构造函数。SystemC使用宏SC_CTOR提供了一种简便的方法。构造函数执行以下操作
创建层次结构(在这种情况下为无)
将功能注册为模拟内核中的进程
声明流程的敏感度列表
也可以在此处初始化需要初始化的任何内容,例如,可以初始化类数据成员。
在上面的示例中,构造函数声明do_nand2是SC_METHOD,并说端口A和B上的任何事件都必须使内核运行该函数(从而为F计算一个新值)。
层次结构
EXOR门由NAND门的四个副本(或实例)组成。这是通过使用EXOR门构造器连接NAND门实例来实现的。这是EXOR门的代码
#include“ systemc.h”#include“ nand2.h”SC_MODULE(exor2){
sc_in <布尔> A,B;
sc_out <布尔> F;
nand2 n1,n2,n3,n4;
sc_signal <布尔> S1,S2,S3;
SC_CTOR(exor2):n1(“ N1”),n2(“ N2”),n3(“ N3”),n4(“ N4”)
{
n1.A(A);
n1.B(B);
n1.F(S1);
n2.A(A);
n2.B(S1);
n2.F(S2);
n3.A(S1);
n3.B(B);
n3.F(S3);
n4.A(S2);
n4.B(S3);
n4.F(F);
}};
该开始看起来与NAND门非常相似,但请注意,它包括文件nand2.h。这允许访问包含与非门的模块。
创建模块exor2,并声明端口。请注意,由于这是层次结构的不同级别,因此允许重复使用名称A,B 和F。
原始图显示了一些“线段”以连接NAND门。这些通过声明创建 sc_signal小号S1, S2和S3。 sc_signal是带有模板参数的类,该模板参数指定信号可以保存的数据类型- 在此示例中为bool。sc_signal是基本通道的一个示例,它是SystemC类库中的内置通道。它的行为类似于VHDL中的信号。
EXOR门的构造函数比NAND门的构造函数复杂,因为它必须具有nand2的四个实例。在端口声明之后,声明了nand2的四个实例:n1,n2,n3和n4。必须为每个实例赋予标签。通过使用exor2构造函数上的初始化器列表,将四个标签“ N1”,“ N2”,“ N3”和“ N4”传递给nand2实例的构造函数。
最后,将端口连接起来。如图所示,这是在构造函数中完成的。
试验台
为了测试设计,有一个激励发生器。这是另一个模块,与上面的非常相似。唯一重要的一点是,它使用线程(SC_THREAD),这是一种可以挂起的进程。这是stim.h的代码
#include“ systemc.h”SC_MODULE(刺激){
sc_out <bool> A,B;
sc_in <bool> Clk;
无效StimGen()
{
A.write(false);
B.write(false);
等待();
A.write(false);
B.write(true);
等待();
A.write(true);
B.write(false);
等待();
A.write(true);
B.write(true);
等待();
sc_stop();
}
SC_CTOR(刺激)
{
SC_THREAD(StimGen);
敏感<< Clk.pos();
}};
请注意对sc_stop()的最终调用,这将使模拟停止。监视代码看起来非常相似,因此被省略了-它位于mon.h文件中。
这是顶层-位于文件main.cpp中,该文件包含上述所有子模块
#include“ systemc.h”#include“ stim.h”#include“ exor2.h”#include“ mon.h”int sc_main(int argc,char * argv []){
sc_signal <bool> ASig,BSig,FSig;
sc_clock TestClk(“ TestClock”,10,SC_NS,0.5);
刺激Stim1(“ Stimulus”);
Stim1.A(ASig);
Stim1.B(BSig);
Stim1.Clk(TestClk);
exor2 DUT(“ exor2”);
DUT.A(ASig);
DUT.B(BSig);
DUT.F(FSig);
mon Monitor1(“ Monitor”);
Monitor1.A(ASig);
Monitor1.B(BSig);
Monitor1.F(FSig);
Monitor1.Clk(TestClk);
sc_start(); //永远运行
返回0;}
包含模块的头文件,声明进行连接的顶级信号以及使用sc_clock创建的时钟;然后每个模块都被实例化并连接。
此后,调用sc_start()将启动模拟,并且模拟将永久运行(或者直到遇到刺激模块中对sc_stop()的调用)。
这是此示例的输出
时间ABF
0秒0 0 1
10 ns 0 0 0
20 ns 0 1 1
30 ns 1 0 1
40 ns 1 1 0
如果您看一下,您会发现一些很奇怪的东西-时间0的第一行说F为1(真),而A和B为0-这不是一个非常有说服力的EXOR门!到10 ns时,一切都应达到预期。在时间0发生了什么事?
模拟
SystemC库包含一个仿真内核。这决定了要运行的进程(软件线程)。在时间0,所有SC_METHOD和SC_THREAD将以不确定的顺序运行,直到它们暂停。然后,当出现时钟沿时,SC_CTHREAD将运行。
上面的问题是由于多种情况造成的
所述sc_clock语句结果在上升沿在时间0,因此监视器和刺激的过程将运行(在未定义的顺序,它不知道其将第一运行)
C ++中的变量并不总是具有定义的初始值(除非将其声明为静态)。因此,F持有的数据值恰好是从1开始(真)
所述do_nand2 SC_METHOD运行在时间0,和时间表˚F更新,但˚F是一个信号,它不能立即更新,因此该值1是仍然存在的监视处理运行时。
为了证明是这种情况,可以修改sc_clock语句以延迟时钟的第一个边沿,如下所示
sc_clock TestClk(“ TestClock”,10,SC_NS,0.5,1,SC_NS);
最后的1个SC_NS参数指定在第一个时钟沿出现之前的1 ns延迟。现在时间已经过去,所以F将被更新。这是对应的输出
时间ABF
1 ns 0 0 0
11 ns 0 0 0
21 ns 0 1 1
31 ns 1 0 1
41 ns 1 1 0
现在您可以看到F总是正确的。
结论
总结了模块和流程的快速浏览。您已经了解了了解SystemC仿真内核的并发本质以及sc_signal基本通道的行为的重要性。
您还看到了一些在顶层模块中实例化底层模块的基本示例,以及如何使用sc_main。
相关问答
vhdl 中信号都能进行哪些运算?VHDL提供了6种预定义的运算操作符,分别是:赋值运算符,逻辑运算符,算术运算符,关系运算符,移位运算符,并置运算符。VHDLl赋值运算符:在VHDL中,赋值运...如果...