精华内容
下载资源
问答
  • VHDL并行语句于顺序语句的理解

    千次阅读 2018-03-08 10:08:49
    VHDL的并行语句用来描述一组并发行为,它是并发执行的,与程序的书写顺序无关。进程语句begin进程语句包含在结构体中,一个结构体可以有多个进程语句,多个进程语句间是并行的,并可访问结构体或实体中定义的信号。...

    VHDL的并行语句用来描述一组并发行为,它是并发执行的,与程序的书写顺序无关。

    进程语句

    begin
    进程语句包含在结构体中,一个结构体可以有多个进程语句,多个进程语句间是并行的,并可访问结构体或实体中定义的信号。因此进程语句称为并行描述语句。

    进行语句结构内部所有语句都是顺序执行的
    进程语句的启动是由process后敏感信号表中所标明的敏感信号触发来的。
    各进程间的通信是由信号来传递的
    语法如下:
    标记:

    process(敏感信号表)
                              变量说明语句;
    begin 
                               一组顺序语句;
    end process 标记;

    标记:为进程标号
    敏感信号表:是进程用来读取所有敏感信号(包括端口)的列表。
    变量说明:主要包括变量的数据类型说明、子程序说明等
    从begin到end process之间是一组顺序执行语句。

    敏感信号表
    所 谓敏感信号表:就是用来存放敏感信号的列表。在进程语句中,敏感信号指那些发生改变后能引起进程语句执行的信号。敏感信号表中可以使用一个或多个信号,当 其中一个或多个信号值改变时,就在进程内部引起语句执行。敏感信号表也可忽略,但程序中必须有其他形式的敏感信号激励。例如wait、wait for、wait until和wait on。

    进程语句的启动
    在VHDL语言中,进程有两种工作状态:等待和执行。当敏感信号表中的信号没有变化时,进程处于等待状态;当敏感信号表中的信号有变化时,进程处于执行状态
    进程语句的同步
    同一个结构体中不仅可以有多个进程存在,同一个结构体中的多个进程还可以同步。VHDL中通常采用时钟信号来同步进程,具体方法是:结构体中的几个进程共用同一个时钟信号来进行激励。

    并发信号赋值语句
    信号赋值语句在进程内部出现时,它是一种顺序描述语句。

    信号赋值语句在结构体的进程之外出现时,它将以一种并发语句的形式出现。它们在结构体中是并行执行的。

    注意:并发信号赋值语句是靠事件来驱动的,因此对于并发信号赋值语句来说,只有当赋值符号“<=”右边的对象有事件发生时才会执行该语句。

    条件信号赋值语句
    语法结构:
    目标信号<=表达式1 when 条件1 else
                         表达式2 when 条件2 else
                         表达式3 when 条件3 else
                          ...
                         表达式n-1 when 条件n-1 else
                         表达式n;
     
    VHDL 语言程序执行到该语句时,首先要进行条件判断,之后才进行信号赋值。如果满足条件,就将该条件前面那个表达式的值赋给目标信号;如果不满足条件按,就继续 判断,直到最后一个表达式,如果前面的条件均不满足就无条件的赋值给最后一个表达式,因为最后一个表达式赋值无需条件。

    选择信号赋值语句
    语法结构:
    with 表达式 select
              目标信号<=表达式1 when 选择条件1,
                                   表达式2 when 选择条件2,
                                    ...
                                    表达式n when 选择条件n;
     
    该语句在赋值之前需要对条件进行判断,附和条件则赋值,否则继续判断,直到最后一个语句。选择赋值语句需要把表达式的值在条件中都列举出来。

    元件例化语句
    在VHDL中,引用元件或者模块的说明采用component语句,他的作用是在结构体说明部分说明引用的元件或者模块,是元件说明语句。
    语法格式:
    component 引用的元件名
                     generic 参数说明;
                     port 端口说明;
    end componet;
    引用的元件名 :

    是将一个设计现成的实体定义为一个元件,是已经设计好的实体名,用来制定要在结构体中使用的元件名称
    如果结构体中要进行参数的传递,那么component语句中需要类属参数说明--可选项;
    引用元件端口的说明,是已经设计好的实体端口名表;
    元件说明语句在architecture和begin之间。

    元件例化引用
    采用componet语句对要引用的原件进行说明后,为了引用的元件正确地嵌入到高一层的结构体描述中,就必须把被引用的元件端口信号于结构体中相应端口信号正确地连接起来,这就是元件例化语句要实现的功能。
    语法结构:
    标号名:元件名
                    generic map(参数映射)
                    prot map(端口映射);
     
    其中标号:是元件例化语句的惟一标识,结构体中的标号名应该是惟一的
    generic map语句:它的功能是实现对参数的赋值操作,从而可以灵活地改变引用元件的参数,为可选项
    prot map:它的功能是把引用元件的端口信号与实际连接的信号对应起来,从而进行元件的引用操作。
    VHDL中,为了实现引用元件的端口信号与结构体中的实际信号相连接,往往采用两种映射方法:
    1、位置映射方法:指port map语句中实际信号的书写顺序于componet语句中端口说明的信号书写语句顺序一致
    2、名称映射方法:指在port map中将引用的元件的端口信号名称赋值给结构体中要使用例化元件的各个信号
    (名称映射语句的书写要求不是十分严格,只要把映射的对应信号连接起来就可以,顺序可以颠倒)。

    生成语句 
    规则结构
    某些电路部分是由同类元件组成的阵列,这些同类元件叫规则结构,例如:随机RAM、只读ROM、移位寄存器等规则结构一般用生成语句来描述。
    生成语句有两种形式:for_generate和if_generate
    for_generate主要用来描述规则
    if_generate主要用来描述结构在其端部表现出的不规则性,例如边界条件的特殊性
    for_generate语句
    标号:for 循环变量 in 离散范围 generate
                      并行处理语句;
                end generate 标号;
     
    标号:用来作为for_generate语句的唯一标识符,可选项;
    循环变量:它的值在每次循环中都将发生变化;
    离散范围:用来指定循环变量的取值范围,循环变量的取值将从取值范围最左边的值开始并且递增到取值范围的最右边,实际上限定了循环次数
    for_generate与for_loop语句很类似,但二者有区别。for_loop语句的循环体中的处理语句是顺序的,而for_generate语句中处理的语句是并行处理的,具有并发性。

    if_generate语句
    标号:if 条件 generate
                并行处理语句;
    end generate 标号;
    if_generate语句是并行处理语句,其中不允许出现else子语句

     

     

    初学VHDL,对一些问题总是感到困惑。比如,同样的赋值语句,在什么场合是并行的,什么时候又是顺序的?信号与变量有什么区别,为什么在PROCESS 里,对信号赋值的结果要等到进程挂起才起作用,而变量赋值却立刻起作用?其实,从语句产生的电路这个角度,可以更深刻地理解这些问题,下面是我自己摸索的 一些理解方法,有不妥之处请大虾们指正!

    1、赋值语句。
        同样a <= b的赋值语句,会形成什么电路,起关键作用的是敏感信号。
        a) 如果a <= b是在进程之外,那么隐含的敏感信号就是b,那么,这个赋值语句就形成一条连线。
        b) 如果是在一个同步进程中,如if (rising_edge(CLK)) then a <= b,这时候,就会形成一个触发器,因为敏感信号是时钟边沿。
       c) 如果敏感信号是一个电平信号,那么会形成一个锁存器。如一个不完整的if条件:if (cond = '1') then a <= b;

    2、并行语句和顺序语句。
        从形成的电路的角度,并行语句最终会有两种形式:
        a) 并联或不相联的逻辑门或组合电路。因为是并联或不相联的,当然是同时执行,这个好理解。
        b) 由同一个时钟边沿驱动的D触发器,不论D触发器之间是并联、串联或者不相连的。为什么呢?因为触发器是在同一个时钟边沿同时翻转的,也就是同时执行,所以本质上就是并行。
        顺序语句只有一种情况,就是形成串联的逻辑门或组合电路。

    3、信号与变量有什么不同?为什么信号赋值要等到进程挂起生效,变量赋值却立刻生效?
        其实,了解了上一点并行语句和顺序语句所生成的电路,这个问题就好理解了。因为在同步进程里的并行语句,大多是形成b的情况,就是多个由同一时钟驱动的触 发 器。由于从触发器的输入到翻转、输出需要一定的延时,这个延时基本就是进程执行完毕的时间,所以,触发器翻转后的输出在同一个时钟边沿中是看不到的,因为 它还没翻转过来呢。这就是信号赋值要等到进程挂起才生效的原因。
        那为什么变量赋值却能立刻生效呢?这是因为,变量其实是为了帮助在同步进程中生成一些逻辑门或组合电路用的。看一看代码:var1 := not i1; var2 := var1 and i2 ; sig <= var2; 生成的RTL,就会看到,两个变量赋值语句其实生成了一个非门、一个与门。而且,输入信号i1和i2到var2这段是个组合电路,是不受时钟边沿控制的, 而到信号赋值语句sig <= var2,才形成一个D触发器。所以,这两个变量赋值语句生成了一个串联的非门和与门,那当然var2取到的是var1赋值后的值了。
        最后顺便提一下为什么变量必须只能在进程内可见,我猜可能是为了防止在同步进程中输出异步信号,造成混乱吧。因为如果变量是外部可见的,如上面的 var2,那么var2的值就可以异步输出到进程外了。所以限制变量只能进程内可见后,要输出变量的值就只能赋值给一个信号,在同步进程中,就是加了一个 触发器了。

    展开全文
  • VHDL并行语句(Concurrent Statements)

    千次阅读 2017-02-23 12:46:05
    VHDL并行语句(Concurrent Statements)并行语句和其他并行语句同步执行。以为为并行语句: Concurrent statements are concurrent with respect to all other such statements. The following are concurrent ...

    VHDL并行语句(Concurrent Statements)

    并行语句和其他并行语句同步执行。以为为并行语句:
    Concurrent statements are concurrent with respect to all other such statements. The following are concurrent statements:

    • 进程 Process
    • 块 Block
    • 实例 Instantiation
    • 断言 Assert
    • 生成 Generate
    • 过程调用 Procedure call
    • 信号赋值 Signal assignment

    进程(Process)

    进程语句定义了一些独立的连续进程,来完成设计的部分行为功能。
    A process statement defines an independent sequential process representing the behavior of some portion of the design.

    语法(Syntax)

    [ 标号: ] [ postponed ] process [ ( 敏感列表 ) ] [ is ] 
      进程声明 
    begin 
      顺序语句 
    end [ postponed ] process [ 标号 ] ;
    [ label: ] [ postponed ] process [ ( sensitivity_list ) ] [ is ] 
      process_declarations 
    begin 
      sequential_statements 
    end [ postponed ] process [ label ] ;

    说明(Description)

    进程语句实现设计的一部分行为功能。他包含一些用户定义的顺序语句。
    The process statement represents the behavior of some portion of the design. It consists of the sequential statements whose execution is made in order defined by the user.
    进程声明部分定义的项仅对进程可见。声明部分可以包含以下几种声明:子程序,类型,子类型,常量,变量,文件,断言,属性,使用实例和组声明。不允许在进程里声明信号或者共享变量。
    The process declarative part defines items that are only visible within that process. The declarative part may contain declarations of: subprograms, types, subtypes, constants, variables, files, aliases, attributes, use clauses and group declarations. It is not allowed to declare signals or shared variables inside processes.
    Loop中进程语句的执行顺序为自顶至下。当执行完最后一条语句,将继续执行第一条语句。进程可以使用wait语句来挂起和继续。当进程的下一条语句是wait语句时,进程暂停执行直到满足wait条件。
    A process is a loop in which the statements are executed from top to bottom. After the last statement is executed, execution will continue with the first statement. The loop can be suspended and resumed with wait statements. When the next statement to be executed is a wait statement, the process suspends its execution until the wait condition is met.
    敏感列表是可选项,包含一些进程敏感信号列表。敏感信号列表中的信号值改变将唤醒暂停的进程。敏感信号列表等同于在进程底部的wait敏感列表语句。
    The sensitivity list is optional and contains a list of signals to which the process is sensitive. A change of a value of one of these signals causes the suspended process to resume. A sensitivity list is equivalent to wait on sensitivity_list at the end of the process.
    在仿真尾部,当所有其他进程完成后将运行一个延迟(postponed)进程。他们的主要应用是基于信号的稳定状态(steady-state)值来实现时间(timing)或者函数(functional)检测。
    A postponed process runs when all other processes have completed, at the end of a simulation. Their main use is to perform timing or functional checks, based on the ‘steady-state’ values of signals.

    例程(Example)

    Counter: process (Clk, Reset)
      variable Increment: integer := 1;
    begin 
      if Reset = '0' then
        Q <=  (others => '0');
      elsif rising_edge(Clk) then
        if Count = '1' then 
          Q <= Q + Increment;
        end if; 
      end if; 
    end process;

    注释(Notes)

    • 不允许在同一进程中同时使用wait语句和敏感列表。
    • It is not allowed to use wait statements and sensitivity list in the
      same process.

    • 有敏感列表的进程叫做过程,过程中不允许包含wait语句。

    • If a process with a sensitivity list calls a procedure, then the
      procedure cannot contain a wait statement.

    敏感列表(Sensitivity List)
    信号列表来触发进程继续执行。
    A list of signals that triggers a process to resume.

    语法(Syntax)

    ( signal_name, ... ) 

    说明(Description)

    敏感列表等同于wait语句。敏感列表中的一个(或多个)信号事件将使进程继续。当一个进程有敏感列表,进程将在执行完最后一条顺序语句后停止执行,直到敏感信号列表中的信号事件发生。
    The sensitivity list is equivalent to the wait on statement. An event on one (or more) of the signals listed in the sensitivity list will make the process to resume. When a process has a sensitivity list, then that process will always stop executing at the end of the sequential statements, and wait on an event on one (or more) of the signals listed in the sensitivity list.
    仅可读的静态信号名才能出现在进程的敏感列表中。
    Only static signal names, for which reading is permitted, may appear in the sensitivity list of a process.

    例程(Example)

    Dff : process (Clk, Reset) 
    begin 
      ...
    end process;

    注释(Notes)

    • 有敏感列表的进程不能有wait语句。
    • A process with a sensitivity list may not contain any explicit wait
      statements.

    块(Block)

    块语句用来组织结构体的并行语句。
    The block statement is used to group together concurrent statements in an architecture.

    语法(Syntax)

    快标号: block [ ( 保护条件 ) ] [ is ] 
      [ generic; [ 类属映射; ] ] 
      [ port; [ 端口映射; ] ] 
      [ 块声明 ] 
    begin 
      并行语句 
    end block [ 块标号 ]; 
    block_label: block [ ( guard_condition ) ] [ is ] 
      [ generic; [ generic_map; ] ] 
      [ port; [ port_map; ] ] 
      [ block_declarations ] 
    begin 
      concurrent_statements 
    end block [ block_label ]; 

    说明(Description)

    块语句在结构体中组织并行语句。块应用主要有两个应用:提高代码可读性和来通过使用guarded表达式来屏蔽一些信用。
    The block statement groups concurrent statements in an architecture. The two main purposes for using blocks are: improve readability of the specification and to disable some signals by using the guarded expression (see Guarded).
    块语句仅用于提高组织性。块的使用不会影响仿真模式的执行。
    The block statement is organisational only - the use of a block does not directly affect the execution of a simulation model.
    端口映射和类属映射语句用来将块外部声明的对象和快内声明的对象分别来对应。然而,这种结构只有一点实用价值。
    The purpose of the port map and generic map statements is to map signals and other objects declared outside of the block into the ports and generic parameters that have been declared inside of the block, respectively. This construct, however, has only a small practical importance.
    块内声明的对象不对块外部可见。
    The block declarations are local to the block and are not visible outside it.

    例程(Example)

    signal P, Q, R: std_logic;
    ...
    level1: block
      port(A, B: in std_logic;
           C: out std_logic);
      port map(A => P, B => Q, C => R); 
    begin 
      C <= A and B;
    end block level1;

    注释(Notes)

    • 没有必要去学习块和相关语法的使用。通常使用进程语句来代替他。
    • It is not necessary to learn and use blocks and related syntax (such as guarded signal assignments). It is generally more efficient for simulation to use processes instead.
    • 不建议在non-VITAL设计中使用块。
    • It is strongly recommended not to use blocks in non-VITAL designs.
    • VITAL规格需要使用块。
    • VITAL specifications require the use of blocks.

    Guarded

    块中一个有关布尔型值的表达式用来控制保护信号的赋值。保护表达式定义了一个隐式信号GUARD,用来控制确定语句的操作(通过连接或断开这些语句的驱动源)。
    A Boolean-valued expression associated with a block statement that controls assignments to guarded signals within a block. A guard expression defines an implicit signal GUARD that may be used to control the operation of certain statements within the block (by connecting or disconnecting the drivers of those statements).

    语法(Syntax)

    block_signal <= guarded expression; 

    说明(Description)

    块语法的一个特性就是保护表达式。保护表达式是一个布尔型的逻辑表达式,无论有没有保护表达式出现,该表达式都会被隐式声明。
    The characteristic feature of the block statement is the guard expression. It is a logical expression of the Boolean type, declared implicitly after the reserved word block whenever a guarded expression appears inside the block.
    保护表达式隐式声明了一个名字为‘guarded’的信号。这个信号可以被块语句中的任何其他信号读取,但是不能被赋值表达式赋值。信号仅对本块可见。
    The guard expression implies a signal named ‘guarded’ at the beginning of the block declaration part. This signal can be read as any other signal inside the block statement but no assignment statement can update it. This signal is visible only within the given block.
    当给保护表达式右边的任何信号传递值时,表达式的值被计算并立即更新‘guarded’信号的值。如果表达式的值为真,则‘guarded’信号接收真值,否则接收假值。
    Whenever a transaction occurs on any of the signals on the right hand side of the guard expression, the expression is evaluated and the ‘guarded’ signal is immediately updated. The ‘guarded’ signal takes on the True value when the value of the guard expression is True. Otherwise, ‘guarded’ takes on the False value.
    ‘guarded’信号也可以在块语句中特别声明。这种方法的优势是可是使用较复杂的算法来控制保护信号。在这种情况下,将使用一个单独的进程来驱动保护信号。
    The ‘guarded’ signal may also be declared explicitly as a Boolean signal in the block statement. The advantage of this approach is that more complex (than a simple Boolean expression) algorithm to control the guard signal can be used. In particular, a separate process can drive the guard signal.
    如果没有保护表达式和没有保护信号声明,则默认保护信号总是真。
    If there is no guard expression and the guard signal is not declared explicitly, then by default the guard signal is always True.
    保护信号用来控制所谓的保护并行信号赋值语句。每一个这种该语句在字符“<=”后添加一个保留字guarded。只有当保护信号为真时才给信号赋新值。否则,信号赋值语句将不更新给定信号的值。
    The guard signal is used to control so called guarded concurrent signal assignment statements contained inside the block. Each such statement contains the reserved word guarded placed after the symbol “<=”. They assign a new value to the signal only when the guard signal is true. Otherwise, the signal assignment statement does not change the value of the given signal.

    例程(Example)

    RisingEdge : block (Clk'Event and Clk ='1') 
    begin 
      Output1 <= guarded not Input1 after 15 ns; 
    end block RisingEdge; 
    
    Blk1 : block 
      signal SGuard: boolean := false; 
    begin 
      Output1 <= guarded not Input1 after 15 ns; 
      Pr1: process 
      begin 
        SGuard <= true; 
      end process Pr1; 
    end block Blk1;

    注释(Note)

    • 综合工具通常不支持保护型块。
    • Guarded blocks are usually not supported for synthesis.

    实例(Instantiation)

    实例语句定义了一个设计实体中子元件。
    An instantiation statement defines a sub-component of the design entity.

    语法(Syntax)

    实例标号: [ component ] 元件名 
      [ 类属映射 ] [ 端口映射 ];
    实例标号: entity 实体名 [ ( 结构体名 ) ] 
      [ 类属映射 ] [ 端口映射 ];
    实例标号: configuration 配置名 
      [ 类属映射 ] [ 端口映射 ]; 
    instance_label: [ component ] component_name 
      [ generic map ] [ port map ];
    instance_label: entity entity_name [ ( architecture_name ) ] 
      [ generic map ] [ port map ];
    instance_label: configuration configuration_name 
      [ generic map ] [ port map ]; 

    说明(Description)

    实例是个并行语句,通过赋值一个底层的设计实体来定义一个多层级的设计。实例语句引用外部定义的子系统。
    An instantiation is a concurrent statement which is used to define the design hierarchy by making a copy of a lower level design entity within an architecture. The instantiation statement introduces a subsystem declared elsewhere.
    实例包含一个实例单元的引用和类属的实际值和端口。有三种形式的实例:
    The instantiation contains a reference to the instantiated unit and actual values for generics and ports. There are three forms of instantiation:

    • 元件实例化 instantiation of a component;
    • 设计实体实例化 instantiation of a design entity;
    • 配置实例化 instantiation of a configuration;

    元件实例化表示已定义元件的关系单元。实例的元件名必须和已定义的元件名相同。调用实例化元件时要有类属的确切参数和端口。关系列表可以是位置对应的也可以是名字对应的。
    Instantiation of a component introduces a relationship to a unit defined earlier as a component (see Component). The name of the instantiated component must match the name of the declared component. The instantiated component is called with the actual parameters for generics and ports. The association list can be either positional or named.
    没有必要为了实例化元件而定一个元件:实体/结构体对可以直接被实例。在这种直接实例化里,实例化语句包含设计实体的名字,用于该设计实体的结构体名可有可无。
    It is not necessary to define a component to instantiate it: the entity/architecture pair can be instantiated directly. In such a direct instantiation, the instantiation statement contains the design entity name and optionally the name of the architecture to be used for this design entity.

    例程(Example)

    u1: Nand4 port map(A, B, Q);
    u2: entity work.Parity
      generic map(N => 8)
      port map(A => Data,
               Odd => ParityByte);

    注释(Note)

    • 实体,结构体或结构体必须在库中编译,才能被实例。但是元件实例可以在相对应的设计实体前编译。
    • An entity, architecture or configuration must be compiled into a
      library before the corresponding instance can be compiled. However, an instance of a component can be compiled before the corresponding design entity has even be written.

    生成(Generate)

    描述功能中迭代或条件细化机制。
    A mechanism for iterative or conditional elaboration of a portion of a description.

    语法(Syntax)

    标号: for 参数 in 范围 generate 
      [ 生成声明
    begin ]  
       并行语句 
    end generate [ 标号 ]; 
    
    标号: if 条件 generate 
      [ 生成声明 
    begin ] 
       并行语句 
    end generate [ 标号 ]; 
    label: for parameter in range generate 
      [ generate_declarations
    begin ]  
       concurrent_statements 
    end generate [ label ]; 
    
    label: if condition generate 
      [ generate_declarations 
    begin ] 
       concurrent_statements 
    end generate [ label ]; 

    说明(Description)

    生成语句简化了设计结构描述。通常用来用一个元件说明并使用生成机制的重复来实现一组相同的元件。
    The generate statement simplifies the description of regular design structures. Usually it is used to specify a group of identical components using just one component specification and repeating it using the generate mechanism.
    生成语句包含三个主要部分:
    A generate statement consists of three main parts:

    • 生成机制(for机制或if机制)
    • generation scheme (either for scheme or if scheme);
    • 声明部分(子程序,类型,信号,常量,元件,属性,配置,文件和组的本地声明)
    • declaration part (local declarations of subprograms, types, signals,
      constants, components, attributes, configurations, files and groups);

    • 并行语句。

    • concurrent statements.
      生成机制来指定如何来生成并行结构语句。有两种生成机制:for和if。
      The generation scheme specifies how the concurrent structure statement should be generated. There are two generation schemes available: for scheme and if scheme.
      For生成机制用来描述设计中规律性的结构。这种情况下,生成参数和其生成范围方式类似于顺序语句loop。
      The for generation scheme is used to describe regular structures in the design. In such a case, the generation parameter and its scope of values are generated in similar way as in the sequential loop statement.
      If生成机制用在那些在规律性结构中包含特例时。
      The if generation scheme is used when the regular structure contains some irregularities.

    例程(Example)

    G1: for I in 1 to N-1 generate 
      L: Blk port map (A(I), B(I+1)); 
    end generate G1;
    
    G2: if I = 3 generate 
      L: Blk port map (A(I+1), B(I+2)); 
    end generate; 

    注释(Notes)

    • 每个生成语句都必须有标号。
    • Each generate statement must have a label.
    • 生成语句可能被分配网表资源。
    • Generate statements can be nested.
    展开全文
  • 硬件描述语言VHDL——并行语句

    千次阅读 2019-04-07 22:37:16
    并行语句是是硬件描述语言的特殊之处,这也是硬件描述语言不可少的一部分。硬件电路例如:总线,它需要多个输入。这个时候,我们必须并发的给出总线上的数据。软件程序设计语言也有并发,但是在性能要求不是苛刻的...

     并行语句是是硬件描述语言的特殊之处,这也是硬件描述语言不可少的一部分。硬件电路例如:总线,它需要多个输入。这个时候,我们必须并发的给出总线上的数据。软件程序设计语言也有并发,但是在性能要求不是苛刻的情形下,无需使用并发。软件的并发由多线程和多进程来实现。

    在VHDL中,并发语句是同时执行的。它们的书写顺序和执行顺序没有关系。在结构体中的并行语句主要有一下几种:

    1. 进程语句;

    2. 并行信号赋值语句;

    3. 并行过程调用语句;

    4. 元件例化语句;

    5. 生成语句;

    6. 块语句。

    简单信号赋值语句

    信号<=表达式;

    选择信号赋值语句

    WITH 选择表达式 SELECT
    信号<=表达式1 WHEN 选择值1,
    	  表达式2 WHEN 选择值2,
    	  ......
    	  表达式n WHEN OTHERS;        --最后一行这里是分号。其余行是逗号
    	  

    WITH——SELECT语句是当“选择表达式”的值等于WHEN后面的选择值时,将WHEN前面的表达式值赋给信号。

    • 选择值必须互斥,不能重复。

    • 该语句不能用于进程(PROCESS)中。

    • 选择信号赋值语句不允许出现范围覆盖不全的情况。

    条件信号赋值语句

    信号<=表达式1 WHEN 赋值条件1 ELSE
    	  表达式2 WHEN 赋值条件2 ELSE
    	  ......
    	  表达式n WHEN 赋值条件n ELSE
    	  表达式;		--最后一项可以不跟条件子句,用于表示以上赋值条件都不满足的情形。
    	  
    • 条件信号赋值语句允许赋值条件重叠,因为,它赋值条件根据书写顺序来逐项测试。一旦发现某一赋值条件得到满足,即将相应表达式的值赋给信号,并且不在测试后面的赋值条件。也就是说,语句之间有优先级顺序,按照书写的先后顺序从高到低排列优先级。适合实现优先级编码器。

    进程语句

    进程语句PROCESS是VHDL中最重要的语句之一。它的特点如下:

    • 进程与进程之间是并发,这点和软件程序设计语言是一致的。进程内部是顺序执行的。
    • 进程只有在敏感信号发生变化的时候才会执行。

    进程语句的格式如下

    进程名:]PROCESS[(敏感信号列表)]	--进程名不是必须的
    [声明区];			--定义进程内部使用的变量,不能在此处定义信号,信号在ARCHITECTURE中定义
    BEGIN
    顺序语句;
    END PROCESS[进程名];
    • 当敏感信号列表中的任意一个发生变化的时候,PROCESS将被启动。
    • PROCESS内部执行是顺序的
    • 在进程内对同一个信号的多次赋值只有最后一次生效。
    • 在不同进程之中不能对同一信号进行赋值。
    • 在一个进程中不能同时对时钟上升,下降沿都敏感。

    进程与时钟

    进程是由敏感信号的变化来启动的,因此可将时钟作为进程启动的敏感信号。时钟信号的上升沿和下降沿是我们最常使用的。当时钟信号clk是STD_LOGIC类型的时候,时钟信号在VHDL中的描述方法如下:

    上升沿描述:clk'EVENT AND clk = '1';
    下降沿描述:clk'EVENT AND clk = '0';

    除此之外,VHDL语言还预定义了两个函数来描述上升沿和下降沿。

    上升沿描述:rising_edge(clk);
    下降沿描述:falling_edge(clk);

    注意下面的错误格式:

    --错误格式1
    PROCESS(clk)
    BEGIN
    IF rising_edge(clk) THEN		--不能同时对上升沿和下降沿都敏感
    ......
    ELSIF falling_edge(clk) THEN
    ......
    END IF;
    END PROCESS;
    --错误格式2
    PROCESS(clk)
    BEGIN
    IF rising_edge(clk) THEN
    ......
    ELSE			--不能有ELSE,这相当于除了对上升沿敏感,还对下降沿敏感
    ......
    END IF;
    END PROCESS;

     

    展开全文
  • VHDL的并行语句 在VHDL的基本程序框架一节中,我们了解到,architecture语句部分里面的语句都是并行的。 那么到底VHDL里面有哪些并行语句可以供我们使用呢?请看如下描述: architecture <arch_name> of ...

    前言

    VHDL的并行语句类似于Verilog的always块,下面摘自《FPGA之道》的讲解,一起学习。

    VHDL的并行语句

    在VHDL的基本程序框架一节中,我们了解到,architecture语句部分里面的语句都是并行的。 那么到底VHDL里面有哪些并行语句可以供我们使用呢?请看如下描述:
    architecture <arch_name> of <entity_name> is
    begin
    <VHDL直接信号赋值语句>;
    <VHDL条件式信号设置语句>;
    <VHDL选择式信号设置语句>;
    <VHDL进程语句>;
    <VHDL块语句>;
    <VHDL元件例化语句>;
    <VHDL生成语句>;
    <VHDL函数调用语句>;
    end <arch_name>;
    以上这些并行语句,没有哪一类是不可或缺的,但是一个architecture中怎么着也得至少有一条,否则虽然从语法上来讲没什么问题,但是这个architecture就不具有任何功能了。一般来说,只要有元件例化、进程语句和信号赋值语句这三类语句就足够描述FPGA的功能了 ,下面详细介绍一下这些并行语句。

    VHDL直接信号赋值语句

    直接信号赋值语句语法如下:
    <signal_name> <= ;
    entity中的非输入端口以及architecture声明与定义部分中声明的signal,都可以在这个地方进行赋值。例如:

    a <= (others => '0'); -- e.g. a is a signal, type std_logic_vector(3 downto 0);
    b <= c or d; -- e.g. b, c, d are type std_logic;	
    

    VHDL条件式信号设置语句

    条件式信号设置语句语法如下:
    
    <signal_name> <= <expression 1> When <logic_expression1> Else
        			   <expression 2> When <logic_expression2> Else
    				   ……
                       <expressions n>;
    
    举例如下:
    
    equal <= '1' when data1 = data2 else 
        	    '0';
    

    VHDL选择式信号设置语句

    除了条件式信号设置语句外,还有另一种语句可以实现类似的功能,那就是选择式信号设置语句。语法如下:

    with <expression> select
    <signal_name> <= <expression 1> When <constant_value 1> ,
                       <expression 2> When <constant_value 2>,
    				   ……	
    				   <expression n> When others;
    

    举例如下:

    	signal a, b : std_logic;
    	signal c : std_logic_vector(1 downto 0);
    	signal xorOfAB : std_logic;
    	c <= a & b;
    	With c Select
    xorOfAB <= '1' when "01",
    		  '1' when "10",
    		  '0' when others;
    

    那么,条件式赋值语句和选择式赋值语句到底有什么区别和联系呢?首先,将上例用条件赋值语句改写如下:

    xorOfAB <=0’ when a = b else1;
    

    对比这两种写法,从表面上来看,选择式赋值语句的语法要求更为严格点,且constant_value的值必须互不相同,而条件式赋值语句的logic_expression却没有这种严格的要求。从本质上来看,条件式赋值语句之所以对logic_expression没有严格的要求,是因为它是有优先级的,即写在前面的logic_expression优先级高于写在后面的。
    在VHDL基本程序框架一小节,我们说过,architecture中的独立语句其实就相当于只有一条代码的纯组合逻辑process。那么如果把条件式赋值语句和选择式赋值语句都改写为进程语句来实现的话,那么,条件式赋值语句就相当于if-else语法,而选择式赋值语句就相当于case语法。

    VHDL进程语句

    进程语句是VHDL中非常重要的一种语句体,在VHDL的基本程序框架一节中,我们已经有过简单介绍。Process是一种并行语句结构,位于一个architecture下的若干个process是并发执行的,但是Process内的语句却是顺序执行的顺序语句,process的语法结构如下:

    <lable> : process (<sensitive_signals_list>)
       variable <name>: <type> := <value>;
       <other variables>...
    begin  
       <statements>;
    end process;
    

    其中,是可选的,它是进程的标号,主要起到提高代码可读性的作用。之前已经介绍过,按照<sensitive_signals_list>的形式来分,process共有三个“纯种”的基本类型:纯组合process、纯同步时序逻辑process、具有异步复位的同步时序逻辑process。 不过如果从process的结构入手,我们的可以将process的语法划分可以更细一些,即:纯组合process、纯时序process、具有同步复位的process、具有异步复位的process以及具有混合复位的process。 可见,基于结构的划分比基于<sensitive_signals_list>的划分更细致一些、面更广一些。基于结构的划分其实就是基于时钟描述结构的划分,因此,首先来介绍一下在process中表示时钟事件的方法。

    时钟事件表示方法

    'event属性
    首先要介绍一下’event属性,这个属性是VHDL进程语句中常用的描述信号事件的手段(进程语句最开始的敏感量表也是描述信号事件的手段,只不过它们所处的位置不同)。一般来说,时序逻辑主要响应两种时钟事件,即时钟的上升沿和下降沿。在process中,要表示这两种事件,我们可以采用如下代码:

    	signal clk : std_logic;
    	if (clk'event and clk = '1') then – 表示时钟上升沿
    	if (clk'event and clk = '0') then – 表示时钟下降沿
    
    rising_edge() & falling_edge()
    

    除了’event属性之外,VHDL还提供了一种方法用来描述时钟事件,参考例子如下:

    signal clk : std_logic;
    if (rising_edge(clk)) then – 表示时钟上升沿
    if (falling_edge(clk)) then – 表示时钟下降沿

    切记!在一个process中,只能出现一个时钟信号的一种边沿事件,并且针对边沿事件的if(或elsif)条件分支,后续不得再有else或elsif分支存在。 这是由寄存器的结构决定的,因为一个寄存器只有一个时钟端口,并且只敏感这个端口的某一个边沿,因此凡是不尊重这个事实的代码都是不可综合的。并且,即便该寄存器存在异步复位信号,由于异步复位信号的优先级要高于时钟信号,而if语句是具有优先级的条件语句,故异步复位所处的条件分支也只能出现在时钟事件所处的分支之前(就像【具有异步复位的process】和【具有混合复位的process】中介绍的那样)。

    下面根据时钟描述结构的不同,分别介绍五种基本process代码结构如下:

    纯组合process

    纯组合process语法如下:

    process (<sensitive_signals_list>)
    begin  
       <statements>;
    end process;
    

    参考例子如下:
    – e.g. all signals are std_logic

    process(a, b)
    begin
    	c <= a and b;
    	d <= not c;
    end process;
    

    上述例子描述了一个与非门的结构,我们可以注意信号c并不在敏感量列表里面,因为c只是一个中间信号,而不是输入信号。

    纯时序process

    纯时序process的语法如下:

    process (clk) -- only clk in the sensitive list
    begin  
       if (clk'event and clk = '1') then -- or if (clk'event and clk = '0') then
          <statements>;
       end if;
    end process;
    

    参考例子如下:
    – all signals are std_logic

    process(clk)
    begin
    	if(clk’event and clk = '1')	then	
    		a <= b;
    	end if;
    end process;
    

    具有同步复位的process

    具有同步复位的process的语法如下:

    process (clk) -- only clk in the sensitive list
    begin  
       if (clk’event and clk = '1') then -- or if (clk’event and clk = '0') then
          if (rst = '1') then -- or if (rst = '0') then
             <reset statements>;
          else
             <function statements>;
          end if;
       end if;
    end process;
    

    参考例子如下:

    -- all signals are std_logic
    process(clk)
    begin
    if(clk'event and clk = '1') then	
    if (rst = '1') then
             a <= '0';
    else
    a <= b and c;
    end if;
    end if;
    	end process;
    

    具有异步复位的process

    具有异步复位的process语法如下:

    process (clk, aRst) -- clk and asynchronous reset
    begin  
       if (aRst = '1') then -- or if (aRst = '0') then 
          <reset statements>;
       elsif (clk'event and clk = '1') then -- or elsif (clk'event and clk = '0') then
             <function statements>;
          end if;
       end if;
    end process;
    

    也可以写成如下形式:

    process (clk, aRst) -- clk and asynchronous reset
    begin  
       if (aRst = '1') then -- or if (aRst = '0') then 
          <reset statements>;
       elsif (clk'event and clk = '1') then -- or elsif (clk'event and clk = '0') then
             <function statements>;
       end if;
    end process;
    

    参考例子如下:
    – all signals are std_logic

    process(clk, aRst)
    begin
    if (aRst = '1') then
          a <= '0';
    else
    if(clk'event and clk = '1') then
    a <= b and c;
    end if;
    end if;
    	end process;
    

    具有混合复位的process

    具有混合复位的process的语法如下:

    process (clk, aRst) -- clk and asynchronous reset
    begin  
       if (aRst = '1') then -- or if (aRst = '0') then 
          <asynchronous reset statements>;
       else
          if (clk'event and clk = '1') then -- or if (clk'event and clk = '0') then
             if (rst = '1') then -- or if (rst = '0') then
                < sync reset statements>;
             else
                <function statements>;
             end if;
          end if;
       end if;
    end process;
    

    也可以写成如下形式:

    process (clk, aRst) -- clk and asynchronous reset
    begin  
       if (aRst = '1') then -- or if (aRst = '0') then 
          <reset statements>;
       elsif (clk'event and clk = '1') then -- or elsif (clk'event and clk = '0') then
          if (rst = '1') then -- or if (rst = '0') then
             < sync reset statements>;
          else
             <function statements>;
          end if;
       end if;
    end process;
    

    参考例子如下:

    -- all signals are std_logic
    process(clk, aRst)
    begin
    if (aRst = '1') then
          a <= '0';
    elsif(clk'event and clk = '1') then
       if (rst = '1') then
          a <= '1';
       else
    a <= b and c;
    end if;
    end if;
    	end process;
    

    VHDL块语句

    块语句即block语句,语法如下:
    label:BLOCK <(expression)>

    BEGIN
    ;
    END BLOCK label;
    关于block语句有几点说明:
    首先,block中的语句都是并发执行的。
    其次,关键字后紧跟的表达式逻辑是可选的,如果有表达式,那么当表达式为真时内部语句才执行;如果没有表达式,则语句一直执行。
    第三,block中可以嵌套block。
    最后,建议大家尽量不要用block语句。因为它的功能仅仅是对原有代码进行区域分割,增强整个代码的可读性和可维护性。当我们的设计真的需要分模块时,我们完全可以写多个entity,而没有必要用block;当我们需要让代码结构清晰时,我们完全可以用注释和空白,而没有必要用block。所以,建议大家对于block只做了解即可。

    VHDL元件例化语句

    元件例化语句即是instance语句。关于它的语法及相关知识已经在VHDL基本程序框架中做了比较详细的介绍.在这里,关于instance语句,我们再做两点说明:

    • 第一点,在某些情况下,例化元件时可以只对元件的部分端口进行映射赋值。道理很简单,对于那些你不需要使用的引脚,你可以不去管它(尤其是输出引脚,但输入引脚是否可以忽略不管则取决于功能),最形象的例子就是FIFO,关于空、满有非常多的信号,而我们的设计中一般只能用到其中的一部分。
    • 第二点,元件例化的时候,映射给输入端口的值也可以是常数或者非常简单的表达式,例如:
    	-- all signals are of type std_logic_vector(3 downto 0)
    m0: And3 
    	PORT MAP(
    		a => "0000",
    		b => not b, -- this is ok!
    		c => a and c, -- this is not allowed!
    		d => d
    	);
    

    使用简单的表达式进行映射,有时候能够给我们带来一些便利,不过并不提倡大家这么去做,因为这样写有些不太规范。

    VHDL生成语句

    VHDL中的生成语句可分为三种,分别是参数生成、循环生成与条件生成,我们这里所说的并行语句主要指后两种。关于这三种生成语句分别介绍如下:

    • 参数生成
      参数生成的语法是generic,主要用在entity定义和元件例化时。

    • 循环生成
      循环生成也叫for-generate语句,主要用于生成一组信号赋值或元件例化语句。它的语法如下:

    <generate_LABEL>:
    for <name> in <lower_limit> to <upper_limit> generate
    begin
    <statements>;
    end generate;
    

    关于循环生成语句的语法,有一点需要注意,那就是<generate_LABEL>必须要有,也就是说一定要为循环生成语句定义一个标签,否则会被识别为for语句,而for语句是串行语句,不能单独出现在architecture中。
    先看一个循环生成语句在信号赋值方面的例子:

    	signal a, b : std_logic_vector(99 downto 0);
    invertVector:
    for i in 0 to 99 generate
    begin
    a(i) <= b(99 - i);
    end generate;
    

    由此可见,通过使用循环生成语句可以非常方便的实现a、b逻辑向量间的反转赋值,这样我们就不用写上100行啰嗦的直接信号赋值语句了。当然,这样的功能也可以通过在process中调用for循环语句来实现,不过下面这个利用循环生成语句进行元件例化的例子,就不那么容易找到同样简洁的替代方案了,代码入下:

    COMPONENT cellAdd
    PORT(
    		a : IN std_logic_vector(7 downto 0);
    		b : IN std_logic_vector(7 downto 0);          
    		c : OUT std_logic_vector(7 downto 0)
    		);
    	END COMPONENT;
    type rt is array (7 downto 0) of std_logic_vector (7 downto 0);
    signal arrayA, arrayB, arrayC: rt;
    	adderGen : for i in 7 downto 0 generate
        begin
             arrayAdder: cellAdd Port map(
    a => arrayA(i),
    b => arrayB(i), 
    c => arrayC(i));
    end generate;
    

    可见,本例的方式也极大的简化了我们的代码编写,并且这种代码节省更加不容易被替代,除非从cellAdd上下功夫,但是这样会复杂基本模块,不可取。

    条件生成

    条件生成语句也叫if-generate语句,主要用于一些预编译前的代码控制,类似于C语言中的条件选择宏定义,根据一些初始参数来决定载入哪部分代码来进行编译(即,有选择的让部分代码生效)。例如,我们有时候不确定这个地方是需要一个乘法还是一个除法,可是如果同时实现一个乘法器和一个除法器,那么资源的占用会很多,那么这个时候,可以通过条件生成语句,来方便的在乘法器与除法器之间切换,并且只占用一份资源。注意!这种切换不是动态的,它是通过修改设计中的参数来实现的,所以需要重新编译。if-generate语句的语法如下:

    < generate_LABEL >:
    if <condition> generate
    begin
    <statements>;
    end generate;
    

    举例如下:

    constant sel : integer := 0;
    signal a, b, c: std_logic_vector(15 downto 0);
    
    myMul:
       if sel = 1 generate
       begin
    c <= a * b;	
       end generate;
    myDiv:
       if sel = 0 generate
       begin
          c <= a / b;
       end generate;
    

    关于上例有四点需要注意:一、必须确保两个条件生成语句不能同时有效,否则就会出现c变量的赋值冲突错误。二、条件生成语句不支持else分支。三、判断条件必须为静态条件。四、标签不能省略。
    请大家仔细思考第三点注意,绝对不能利用条件分支做一些动态生成的事情,因为硬件不像软件,不支持对象的动态生成与释放。条件生成语句是为了辅助编译器来预先知道到底该加载哪些语句去进行编译、综合的,而不能根据变量来在编译后动态决定现在选择哪一个代码结构。例如,如果把上例的
    constant sel : integer := 0;
    改为
    signal sel : integer := 0;
    那么编译会报错,表示判断条件不是一个静态条件。如果真的需要根据条件来判断做乘法还是做除法,应该写成这样:
    signal sel : integer := 0;
    cMul <= a * b;
    cDiv <= a / b;
    c <= cMul when sel = ‘1’ else
    cDiv;
    但是注意,这个时候,在FPGA中可是需要调用相应资源来同时实现一个乘法器与一个除法器的,只不过会根据sel来判断此时需要的是乘法器还是除法器的输出。而如果用条件生成语句的话,每一次实现FPGA的设计中,只会有一个乘法器或者一个加法器,资源方面会有很多节省,不过带来的不便就是如果需要另外一种功能时,需要修改代码重新编译实现新的FPGA配置文件。
    需要强调一下,以上例子中,我们为了说明方便和代码简洁,直接使用了“*”、“/”符号来完成乘法与除法运算。在现实情况中,强烈不推荐如此简单的来处理乘、除运算.

    VHDL函数调用语句

    函数——function,是VHDL子程序的一种,函数的调用是一种并行的调用,它可以直接出现在architecture的语句部分当中,例如:
    – e.g. function min() is predefined

    smaller <= min(a, b);
    
    展开全文
  • 并行语句的特点:2.结构体2.1 并行信号赋值语句2.2条件信号赋值语句2.3选择信号赋值语句3.元件例化语句4.生成语句5.参数传递映射语句及其使用方法参数传递说明的一般书写格式如下:6.参数传递映射语句及其使用方法...
  • EDA技术与VHDL第四版课件,潘松——第5章 VHDL并行语句
  • EDA笔记(6)--并行语句

    2020-04-29 17:28:19
    一.进程语句 1.进程(PROCESS)语句 ...一个结构体中可以有多个并行运行的进程结构,而每一个进程的内部结构却是由一系列顺序语句来构成的。 PROCESS结构中既可以有时序逻辑的描述,也可以有组合逻辑的描述,它们...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,420
精华内容 968
关键字:

并行语句