VHDL知识补充

  • 有一些内容在前文提及过,但是并没有深入讲解,在此章节中进行梳理

VHDL库

库的种类

  • IEEE库

    最常用的库,其中的STD_LOGIC_1164是最常用、最重要的程序包,有了它才能使用标准逻辑位STD_LOGIC

  • STD库

    VHDL语言标准定义了两个标准程序包,收录在此库中,分别是STANDARD和TEXTIO(文件输入输出)

    由于它们的内容已经包含在VHDL语言内,因此使用时不必特别去调用

  • WORK库

    用户在当前工程中设计和定义的一些设计单元和程序包,用户把自己设计的各种模块元件放在其中,WORK库自动满足VHDL的要求,因此也不必进行显性调用

  • VITAL库

    使用这个库可以提高VHDL门级时序模拟的精度,因此只在VHDL仿真器里使用,但因为EDA开发工具包含这一功能,因此不必使用这个库

库的用法

  • 把库的语句放到实体单元前,在设计实体时就可以使用库中的数据,在一个设计实体中可以打开多个不同的库

    LIBRARY IEEE;--打开IEEE库
    USE IEEE.STD_LOGIC_1164.ALL;--使用库中某个程序包中的所有内容:USE 库名.程序包名.ALL
    
    USE IEEE.STD_LOGIC_1164.STD_ULOGIC;--使用库中某个项目:USE 库名.程序包名.项目名
    USE IEEE.STD_LOGIC_1164.RISING_EDGE;--因为RISING_EDGE需要用到数据类型STD_ULOGIC,所以这句必须跟在上句后
    
    --为了节约输入时间,可以把要用的资料放到自定义的资源库中,WORK库不需要上述的库文件语句指定
    USE WORK.STD_LOGIC_1164.ALL--这一语句就把IEEE库的STD_LOGIC_1164程序包复制到了WORK库中
    
    

VHDL程序包

程序包是什么

  • 在设计实体中定义的数据类型、子程序、数据对象对其他设计实体不可用,为了让这些已定义的内容能够复用,可用将它们收录在程序包中,而多个程序包可用并入一个库中

  • 一个程序包包含以下结构中至少一项:

    • 常数说明:比如定义系统数据总线通道的宽度
    • 数据类型说明
    • 元件定义
    • 子程序

定义程序包

  • 定义程序包的语句

    PACKAGE 程序包名 IS --程序包首
    		程序包首说明部分--包括多个VHDL设计的公共信息,比如数据类型、信号、子程序、元件说明等
    	END 程序包名;
    	PACKAGE BODY 程序包名 IS --程序包体
    		程序包体说明部分以及包体内容
    		--程序包体并非必须的,包首可独立使用,包体则用来写元件、函数的内容,如果只定义数据类型之类可用只写包首
    	END 程序包名
    

程序包定义与调用示例

  • --定义一个pacl程序包
    PACKAGE pacl IS
    	TYPE byte IS RANGE 0 TO 25;--定义一个数据类型byte
    	SUBTYPE nibble IS byte RANGE 0 TO 15;--定义一个子类型:对已有数据类型加一些约束条件,可用与原类型进行计算
    	CONSTANT byte_ff : byte := 255;--定义常数
    	SIGNAL addend : nibble;--定义信号,其数据类型是nibble
    	COMPONENT byte_adder--定义元件,在包首只写例化语句
    		PORT(a,b:IN byte; c:OUT byte);
    		END COMPONENT;
    	FUNCTION my_function (a:IN byte) Return byte;--定义函数,在包首只写函数首
    END pacl--包首结束
    
    --元件和函数的具体内容放在程序包体中
    
  • 在使用这个程序包时,参照调用库文件中程序包的语句

    LIBRARY WORK;--默认打开,可省略此句
    USE WORK.pacl.ALL;
    

子程序

什么是子程序

  • 子程序的是一个VHDL程序模块,只用顺序语句(类似进程),不同的是其不像进程那样可以从本结构体中直接读取信号值或向信号赋值
  • 子程序可以定义在程序包、结构体和进程中,不过只有定义在程序包里才能复用,所以一般只定义在程序包中
  • 子程序可重载:允许有同名的子程序,但这些子程序的参数类型和返回值数据类型是不同的
  • 子程序有两种形式:过程PROCEDURE和函数FUNCTION

函数FUNCTION

  • 函数的格式
    FUNCTION 函数名(参数表) RETURN 数据类型--函数首
    FUNCTION 函数名(参数表) RETURN 数据类型 IS --函数体
    	--说明部分
    	BEGIN
    	--顺序语句;
    	END FUNCTION 函数名; 
    
  • 函数的调用
    PACKAGE packexp IS
    FUNCTION max(a,b:IN STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;--在程序包首中定义函数首
    ……
    PACKAGE BODY packexp IS
    FUNCTION max(a,b:IN STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
    BEGIN
    	IF a>b THEN RETURN a; ELSE RETURN b; END IF;
    END FUNCTION max;
    END--结束包体
    
    USE WORK.packexp.all;
    ……--实体定义省略
    ARCHITECTURE bhv OF axamp IS
    	BEGIN
    		out1 <= max(dat1,dat2);--在赋值语句的并行函数调用
    	PROCESS(dat3,dat4)
    		BEGIN
    			out2 <= max(dat3,dat4);--在顺序语句中调用函数语句
    		END PROCESS;
    	END;
    
  • 重载函数

    VHDL允许以相同的函数名定义函数,但要求函数中定义的操作数要有不同的数据类型,以便调用时区分不同功能的函数,这样的数据类型不同但名称相同的函数就叫重载函数

    重载函数有一个应用是运算符重载:VHDL不允许不同数据类型的操作数进行直接操作或运算,利用运算符式的重载函数就能规避这一点

    FUNCTION "+" (L:STD_LOGIC_VECTOR; R:INTEGER) RETURN STD_LOGIC_VECTOR;
    FUNCTION "+" (L:INTEGER; R:STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
    ……
    FUNCTION "+" (L:STD_LOGIC_VECTOR; R:INTEGER) RETURN STD_LOGIC_VECTOR IS
    	VARIABLE RESULT:STD_LOGIC_VECTOR(L'range)--定义一个变量来暂存运算结果,其范围即L的范围
    	BEGIN
    		result:=UNSIGNED(L)+R;
    		RETURN std_logic_vector(result);
    	END;
    --其他重载函数定义省略,这样在使用+运算符时,就能让两个不同数据类型也能相加
    
  • 决断函数

    不可综合,用于解决信号被多个驱动源驱动时信号的竞争问题,其将对多个信号占用总线作出裁决

过程PROCEDURE

  • 过程的格式

    子程序的另一种形式是过程PROCEDURE

    PROCEDURE 过程名(参数表) --过程首
    PROCEDURE 过程名(参数表) IS --过程体
    	[说明部分]
    	BEGIN
    		顺序语句;
    	END PROCEDURE 过程名;
    
  • 与函数一样,过程也由过程首与过程体构成,过程首不是必须的,过程体可以单独使用,但在程序包在必须定义过程首,在进程或结构体中则不必写;过程体也由顺序语句组成,说明部分也只适用于过程体内部

  • 参数表可以由常数、变量、信号三类数据对象组成

    procedure pro1 (variable a,b :inout bit);
    procedure pro2 (constant a1:in integer
    				variable b1:out integer);
    --参量表中可以定义三种流向模式,IN/OUT/INOUT
    --如果不定义数据类型,只定义了IN,默认参量是常量,只定义了OUT/INOUT,默认是变量
    
  • 过程的调用

    有两种不同的方法:并行语句与顺序语句调用

    • 一般的顺序语句执行过程中,一个PROCEDURE被执行,其相当于一个小的进程
    • 当这个PROCEDURE处在并行语句环境中时,其过程体定义的任一IN或INOUT的目标参量发生变化时,将启动过程的调用
    • 函数与过程的不同在于:函数的调用把定义的函数视作语句中的一个因子,比如一个操作数或一个赋值数据对象,而过程则是作为语句来执行
    --并行语句中的调用
    ARCHITECTURE bhv OF EX IS
    	BEGIN
    		nand4a(e,f,g,h,x);--将实体端口连接到过程的参量
    	END
    
  • 重载过程

    类似重载函数,两个或两个以上有相同过程名和互不相同参数数量及数据类型的过程称重载过程/复用过程

RETURN语句

  • 用于子程序的语句,有两种形式

    RETURN;--只用于过程,只是结束了过程
    RETURN 表达式;--只用于函数,并且必须返回一个值
    

并行语句

  • 对并行语句的补充说明

可综合语句

  • 可综合的并行语句有七种:

    • 并行信号赋值语句
    • 进程语句PROCESS
    • 块语句
    • 条件信号赋值语句
    • 元件例化语句COMPONENT
    • 生成语句GENERATE
    • 并行过程调用语句
  • 块语句

    BLOCK是VHDL的一种划分机制,结构体本身就等价于一个块,这种机制用于把一个模块分成数个区域,在每个块中都能对其局部信号、数据类型和常量进行定义

    BLOCK语句是一种把结构体中的并行语句进行组合的方法,其主要用于改善并行语句的可读性,或者是利用BLOCK的保护表达式关闭某些信号,从综合的角度看块语句没什么用

    块标号:BLOCK 块保护表达式
    	接口说明
    		类属说明
    	BEGIN
    		并行语句
    	END BLOCK 块标号
    
  • 生成语句

    用于简化有规则设计结构的逻辑描述,其作用是把设定好的元件或设计单位进行复制

    复制方式有IF和FOR两种:

    标号不是必须的,但如果是嵌套式的生成语句就十分重要

    标号: FOR 循环变量 IN 取值范围 GENERATE--将并行语句复制取值范围那么多次,循环变量自动产生
    	说明
    	BEGIN
    		并行语句
    	END GENERATE 标号;
    
    标号: IF 条件 GENERATE--满足条件时复制
    	说明
    	BEGIN
    		并行语句
    	END GENERATE 标号;
    
  • 使用生成语句重复元件例化过程,产生并列电路结构的示例

    --component comp已经写好了
    gen: FOR i IN a'range GENERATE
    u1:comp PORT MAP(x=>a(i),y=>b(i));
    END GENERATE gen;
    

不可综合语句

  • REPORT语句

    用在仿真中,报告有关信息以提升可读性

    REPORT "字符串";
    
  • 断言语句

    用于程序调试,时序仿真时的人机对话

    ASSERT 条件表达式 --用于判断是否出错的条件
    REPORT "出错信息"
    SEVERITY 错误级别;--错误级别分四种
    --NOTE 通报,报告出错,可以编译
    --WARNING 警告,报告出错,可以编译
    --ERROR 错误,报告出错,暂停编译
    --Failure 失败,报告出错,暂停编译
    
  • 断言语句可以分为顺序和并行两种

    放在顺序语句中的断言语句按顺序执行,对程序进行检查,

    放在进程外部的则是并行断言语句,等价于一个只对断言语句条件表达式内循环敏感的进程语句

  • 断言语句只能放在结构体中

posted on 2024-12-17 23:25  无术师  阅读(45)  评论(0编辑  收藏  举报