资源描述
个人收集整理 勿做商业用途
3。5用AHDL语言设计数字系统
AHDL语言是ALTERA公司开发的高效、易学的硬件描述语言,在max+plus2软件中使用它比VHDL语言更有效。
3.5.1 AHDL 简介
一个AHDL逻辑设计至少必须包含一个分设计段(Subdesign Section)和一个逻辑设计段(Logic Section),
其它段和语句是可选择的,AHDL的设计文件是用Max+PlusⅡ软件的文本编辑器编写的源程序(*.tdf)
下面介绍AHDL的一些语句。
(1) 常数叙述语句
该语句可以用一个字符串代表数字、算数表达式
例:
CONSTANT UPPER_LIMIT = 130;
CONSTANT BAR = 1 + 2 DIV 3 + LOG2(256);
CONSTANT FOO = 1;
CONSTANT FOO_PLUS_ONE = FOO + 1;
(2) 定义函数语句
该语句可以定义一个在分设计中使用函数,
例:
DEFINE MAX(a,b) = (a > b) ? a : b;
SUBDESIGN
(
dataa[MAX(WIDTH,0)。.0]: INPUT;
datab[MAX(WIDTH,0).。0]: OUTPUT;
)
BEGIN
datab[] = dataa[];
END;
此例中MAX函数保证最小的数据位宽度。
(3)参数叙述语句
该语句可以声明参数化巨功能模块和宏功能模块的一个或几个参数
例:
PARAMETERS
(
FILENAME = ”myfile.mif”, —- optional default value follows ”=” sign
WIDTH,
AD_WIDTH = 8,
NUMWORDS = 2^AD_WIDTH
);
(4)函数描述语句
共有4种形式的逻辑函数可以供用户调用,它们是:
Megafunction-具有复杂逻辑功能的巨功能模块,放在mega_LPM库中,可以供用户调用
Primitive—一些基本逻辑功能函数,可以直接调用
Macrofunction—具有高水平的逻辑宏功能模块,共有300多种,放在max2lib子目录中
State Machine-一种具有多个状态的时序电路,可以形成符号图形,用户可以调用
以上几种逻辑功能函数都可以以逻辑函数名和符号图形的方式被调用,在AHDL源文件中调用时要首先进行声明,见如下例子。
1)参数化函数:
FUNCTION lpm_add_sub (cin, dataa[LPM_WIDTH—1。。0], datab[LPM_WIDTH—1。。0], add_sub)
WITH (LPM_WIDTH, LPM_REPRESENTATION, LPM_DIRECTION, ADDERTYPE,
ONE_INPUT_IS_CONSTANT)
RETURNS (result[LPM_WIDTH-1..0], cout, overflow);
该函数名为lpm_add_sub,输入端口为 cin, dataa[LPM_WIDTH-1。。0], and datab[LPM_WIDTH-1。。0];
关键字WITH后是参数表,
关键字RETURN后是输出口result[LPM_WIDTH-1。。0], cout, and overflow
2)非参数化函数:
FUNCTION compare (a[3。.0], b[3..0])
RETURNS (less, equal, greater);
该函数名为compare,输入端口为a3, a2, a1, a0, b3, b2, b1, and b0.
关键字RETURN后是输出口less, equal, greater
3)状态机函数:
当输入和输出是状态机时,应该按照如下例子定义函数,在返回结果语句中加MACHINE关键字
FUNCTION ss_def (clock, reset, count)
RETURNS (MACHINE ss_out);
(5) 最小位数选择语句
定义一组数据中的最小数位是否是MSB(most significant bit)或LSB(least significant bit)
例:
OPTIONS BIT0 = MSB;
(6)断言语句
该语句可以检验表达式、参数、数据、计算函数有效性和端口的使用情况。
例:
ASSERT (WIDTH 〉 0)
REPORT "Width (%) must be a positive integer" WIDTH
SEVERITY ERROR
HELP_ID INTVALUE; -- for internal Altera use only
在该例中,WIDTH〉0是断言条件,若此条件不满足,将显示REPORT后的内容和SEVERITY后的错误等级。
(7)分设计段
分设计段声明输入、输出和双向口
例:
SUBDESIGN top
(
foo, bar, clk1, clk2 : INPUT = VCC;
a0, a1, a2, a3, a4 : OUTPUT;
b[7.。0] : BIDIR;
)
端口类型可以是:
INPUT, OUTPUT, BIDIR, MACHINE INPUT, 或 MACHINE OUTPU
其中MACHINE INPUT或MACHINE OUTPUT口不能用于TDF的顶层,在端口类型说明后可以加端口当前电平-VCC或者是GND。
(8)变量段
该段是声明和产生逻辑段中使用的变量的地方,如下是变量段的例子。
VARIABLE
a, b, c : NODE;
temp : halfadd;
ts_node : TRI_STATE_NODE;
IF DEVICE_FAMILY == ”FLEX8000" GENERATE
8kadder : flex_adder;
d,e : NODE;
ELSE GENERATE
7kadder : pterm_adder;
f,g : NODE;
END GENERATE;
1)函数变量声明例:
VARIABLE
comp : compare;
adder : lpm_add_sub WITH (LPM_WIDTH = 8);
该变量段声明comp为函数compare的引用变量,声明adder为函数lpm_add_sub的引用变量,一旦声明完毕,就意味着:
变量comp就是如下端口的代表:
a[3。.0], b[3。.0] : INPUT; —— inputs to compare
less, equal, greater : OUTPUT; —— outputs of compare
而变量adder是如下端口的代表:
a[8..1], b[8..1] : INPUT; -- inputs of adder
sum[8.。1] : OUTPUT; —— outputs of adder
也就是如下的引用变量可以使用在当前的设计文件中:
comp。a[], comp.b[], comp。less, comp.equal, comp。greater
adder.dataa[], adder。datab[], adder。result[]
2)节点变量声明
AHDL 软件支持两种节点形式:NODE and TRI_STATE_NODE。
例:
SUBDESIGN node_ex
(
a, oe : INPUT;
b : OUTPUT;
c : BIDIR;
)
VARIABLE
b : NODE;
t : TRI_STATE_NODE;
BEGIN
b = a;
out = b % therefore out = a %
t = TRI(a, oe);
t = c; % t is bus of c and tri_stated a %
END;
如下的端口和功能模块能连接三态节点(TRI_STATE_NODE):
TRI 三态功能模块
输入端口(INPUT) 端口从高层向下
输出或双向口(OUTPUT, BIDIR)从低层向上
当前文件中的双向口(BIDIR)
当前文件中的三态节点TRI_STATE_NODE
3)寄存器变量声明
该声明用于声明寄存器:
D型:DFF,DFFE,
T型:TFF,TFFE
JK型:JKFF,JKFFE,SRFF,SRFFE
琐存器:LATCH
例:
VARIABLE ff : TFF;
该变量一旦声明完毕,就可以使用如下变量:
ff.t, ff.clk,ff.clrn,ff.prn,ff。q
对于只有一个输出的功能模块,可以简化使用。
DFF的功能说明为:
FUNCTION DFF(d, clk, clrn, prn) RETURNS (q);。
则对于如下的变量段,逻辑段的意思是a.d = b。q;
VARIABLE
a, b : DFF;
BEGIN
a = b;
END;
4)状态机变量声明
例:
VARIABLE
ss : MACHINE
OF BITS (q1, q2, q3)
WITH STATES (
s1 = B"000”,
s2 = B”010”,
s3 = B”111”);
该例的意思是:
状态机的名字是ss,状态位q1, q2, 和 q3是该机寄存器的输出,状态机的状态是s1,s2,和s3, 并给出了当前状态值.
(9)逻辑段
在逻辑段中,说明设计文件的逻辑操作。
1) 布尔方程
逻辑段中布尔方程用于表达节点之间的逻辑关系,该关系必须遵从逻辑规则.
例:
a[] = ((c[] & -B”001101”) + e[6..1]) # (p, q, r, s, t, v);
表达式的左边可以是一个字符变量、端口和组,右边是布尔方程表达式。
2) 布尔控制方程
该控制方程用于建立状态机的时钟、复位和时钟使能信号,见下例:
ss.clk = clk1;
ss.reset = a & b;
ss.ena = clk1ena;
该控制方程的格式为<状态机名>。<端口名>,所以该例中状态机名是ss,三个端口:时钟、复位和使能。
3)CASE语句
例:
CASE f[].q IS
WHEN H”00" =〉
addr[] = 0;
s = a & b;
WHEN H”01" =>
count[].d = count[]。q + 1;
WHEN H"02", H"03”, H”04" =〉
f[3。.0]。d = addr[4。.1];
WHEN OTHERS =>
f[].d = f[].q;
END CASE;
3) 缺省叙述语句
该语句指定真值表中变量的缺省值,
例:
BEGIN
DEFAULTS
a = VCC;
END DEFAULTS;
IF y & z THEN
a = GND;
END IF;
END;
4)IF THEN语句
例:
IF a[] == b[] THEN
c[8。。1] = H ”77”;
addr[3.。1] = f[3。.1].q;
f[]。d = addr[] + 1;
ELSIF g3 $ g4 THEN
f[]。d = addr[];
ELSE
d = VCC;
END IF;
4) FOR GENERATE 语句
例:
CONSTANT NUM_OF_ADDERS = 8;
SUBDESIGN 4gentst
(
a[NUM_OF_ADDERS.。1], b[NUM_OF_ADDERS。。1], cin : INPUT;
c[NUM_OF_ADDERS..1], cout : OUTPUT;
)
VARIABLE
carry_out[(NUM_OF_ADDERS+1).。1] : NODE;
BEGIN
carry_out[1] = cin;
FOR i IN 1 TO NUM_OF_ADDERS GENERATE
c[i] = a[i] $ b[i] $ carry_out[i]; % Full Adder %
carry_out[i+1] = a[i] & b[i] # carry_out[i] & (a[i] $ b[i]);
END GENERATE;
cout = carry_out[NUM_OF_ADDERS+1];
END;
5) 真值表语句
该语句用于指定组合逻辑和状态机的输入和输出行为。
例:
TABLE
a0, f[4。.1]。q => f[4..1].d, control;
0, B”0000" => B"0001", 1;
0, B”0100” =〉 B"0010”, 0;
1, B"0XXX” => B”0100", 0;
X, B”1111” =〉 B”0101", 1;
END TABLE;
该例中,a0和f[4。。1]。q 是输入,f[4。.1].d和control是输出,
3.5.2 AHDL中的语言元素
(1) AHDL中的保留关键字
AHDL语言建议用大写字母书写如下关键字:
AND FUNCTION OUTPUT
ASSERT GENERATE PARAMETERS
BEGIN GND REPORT
BIDIR HELP_ID RETURNS
BITS IF SEGMENTS
BURIED INCLUDE SEVERITY
CASE INPUT STATES
CLIQUE IS SUBDESIGN
CONNECTED_PINS LOG2 TABLE
CONSTANT MACHINE THEN
DEFAULTS MOD TITLE
DEFINE NAND TO
DESIGN NODE TRI_STATE_NODE
DEVICE NOR VARIABLE
DIV NOT VCC
ELSE OF WHEN
ELSIF OPTIONS WITH
END OR XNOR
FOR OTHERS XOR
(2) 保留识别符
AHDL中的保留识别符:
CARRY JKFFE SRFFE
CASCADE JKFF SRFF
CEIL LATCH TFFE
DFFE LCELL TFF
DFF M CELL TRI
EXP MEMORY USED
FLOOR OPENDRN WIRE
GLOBAL SOFT X
(3) AHDL中运算符
符号
功能
+
加号
—
减
==
数和串相等
!
NOT
!=
不等于
〉
大于
>=
大于等于
〈
小于
〈=
小于等于
&
AND
!&
NAND
$
XOR
!$
XNOR
#
OR
!#
BOR
(4)AHDL中的组
具有相同类型的端口可以形成一个组,该组可以有256个成员“BIT”,
如下的组虽然表达方式不同,但实际是同一个组.
b[5。。0]
(b5, b4, b3, b2, b1, b0)
b[]
(5)AHDL中的数
二进制例: B”0110X1X10”
八进制例: Q"4671223"
十六进制例:H"123AECF"
(6)AHDL中的算数表达式
运算符
说明
优先级别
+
(unary)+1 positive
1
—
(unary)-1 negative
1
!
!a NOT
1
^
a ^ 2 exponent
1
MOD
4 MOD 2 modulus
2
DIV
4 DIV 2 division
2
*
a * 2 multiplication
2
LOG2
LOG2(4—3) logarithm base2
2
+
1+1 addition
3
-
1-1 subtraction
3
==
(numeric) 5 == 5 numeric equality
4
==
(string) ”a" == "b" string equality
4
!=
5 != 4 not equal to
4
>
5 > 4 greater than
4
〉=
5 〉= 5 greater than or equal to
4
〈
a < b+2 less than
4
<=
a <= b+2 less than or equal to
4
&
a & b AND
5
AND
a AND b
!&
1 !& 0 NAND (AND inverter)
5
NAND
1 NAND 0
$
1 $ 1 XOR (exclusive OR)
6
XOR
1 XOR 1
!$ )
1 !$ 1 XNOR (exclusive NOR
6
XNOR
1 XNOR 1
#
a # b OR
7
OR
a OR b
!#
a !# b NOR (OR inverter)
7
NOR
a NOR b
?
(5<4) ? 3:4 ternary
8
(7)巨功能模块(LPM功能)
Mega功能模块列表:
门类:
lpm_and lpm_inv
lpm_bustri lpm_mux
lpm_clshift lpm_or
lpm_constant lpm_xor
lpm_decode mux
busmux
运算类:
lpm_abs lpm_counter
lpm_add_sub lpm_mult
lpm_compare
存储类:
csfifo lpm_ram_dq
csdpram lpm_ram_io
lpm_ff lpm_rom
lpm_latch lpm_dff (for backward compatibility only)
lpm_shiftreg lpm_tff (for backward compatibility only)
其它类:
clklock pll
ntsc
核心类:
a16450 a8255
a6402 fft
a6850 rgb2ycrcb
a8237 ycrcb2rgb
a8251
具体的功能块输入输出信号见Max+plusⅡ软件帮助。
(8)老逻辑功能块(Old—Style Macrofunctions)和宏功能块(Macrofunction)
分类列表:
功能模块
Adders
Latches
Arithmetic Logic Units
Multipliers
Buffers
Multiplexers
Comparators
Parity Generators/Checkers
Converters
Rate Multipliers
Counters
Registers
Decoders
Shift Registers
Digital Filters
Storage Registers
EDAC
SSI Functions
Encoders
True/Complement I/O Elements
Frequency Dividers
具体的功能块输入输出信号见Max+plusⅡ软件帮助。
(9)基本逻辑功能块(Primitives)
缓冲器类:
CARRY
OPNDRN
CASCADE
SOFT
EXP TRI
GLOBAL (SCLK)
WIRE (GDFs only)
LCELL (MCELL)
触发器和琐存器类:
DFF SRFF
DFFE
SRFFE
JKFF
TFF
JKFFE
TFFE
LATCH
输入输出端口类:
BIDIR
INOUT
INPUT
IN
OUTPUT
OUT
BIDIRC (GDFs only)
INPUTC (GDFs only)
OUTPUTC (GDFs only)
逻辑类:
AND
NOR
NOT
OR
XNOR
XOR
NAND
VCC (GDFs only)
BAND (GDFs only)
BNAND (GDFs only)
BNOR (GDFs only)
BOR (GDFs only)
GND (GDFs only)
具体的功能块的功能和输入输出信号见Max+plusⅡ软件帮助.
3.5.3 AHDL的使用例子
(1)使用AHDL中的数
例1:
SUBDESIGN decode1
(
address[15。。0] : INPUT;
chip_enable : OUTPUT;
)
BEGIN
chip_enable = (address[15。.0] == H”0370");
END;
在该例中当地址为十六进制数370时,输出端“chip_enable"输出高电平。
(2)常数和定义函数功能的使用
例1:常数使用例.
CONSTANT IO_ADDRESS = H”0370"; %常数%
SUBDESIGN decode2
(
a[15..0] : INPUT;
ce : OUTPUT;
)
BEGIN
ce = (a[15。.0] == IO_ADDRESS);
END;
例2:定义函数使用例.
PARAMETERS (WIDTH);
DEFINE MAX(a,b) = (a > b) ? a : b; %使用定义功能定义的函数,该函数保证端口位数的数量%
SUBDESIGN minport
(
dataA[MAX(WIDTH,0).。0] : INPUT;
dataB[MAX(WIDTH,0)。。0] : OUTPUT;
)
BEGIN
dataB[] = dataA[];
END;
(3)布尔表达式的使用
例1:
SUBDESIGN boole1
(
a0, a1, b : INPUT;
out1, out2 : OUTPUT;
)
BEGIN
out1 = a1 & !a0;
out2 = out1 # b;
END;
例2:具有一个声明的节点
SUBDESIGN boole2
(
a0, a1, b : INPUT;
out : OUTPUT;
)
VARIABLE
a_equals_2 : NODE; %被声明的节点%
BEGIN
a_equals_2 = a1 & !a0;
out = a_equals_2 # b;
END;
例3:具有组的例。
OPTIONS BIT0 = MSB; %指定BIT0是MSB%
CONSTANT MAX_WIDTH = 1+2+3—3-1; % 声明常数MAX_WIDTH = 2 %
SUBDESIGN group1
(
a[1.。2], use_exp_in[1+2—2。.MAX_WIDTH] : INPUT;
d[1.。2], use_exp_out[1+2*2—4..MAX_WIDTH] : OUTPUT;
dual_range[5。。4][3..2] : OUTPUT;
)
BEGIN
d[] = a[] + B"10";
use_exp_out[] = use_exp_in[];
dual_range[][] = VCC;
END;
例4:具有条件语句的例.
SUBDESIGN priority
(
low, middle, high : INPUT;
highest_level[1..0] : OUTPUT;
)
BEGIN
IF high THEN
highest_level[] = 3;
ELSIF middle THEN
highest_level[] = 2;
ELSIF low THEN
highest_level[] = 1;
ELSE
highest_level[] = 0;
END IF;
END;
在本例中,high信号具有最高优先权,若三个信号high,middle和low都被VCC驱动,则只有high信号起作用,输出highest_level[] = 3。
例5:有CASE的语句的例.
SUBDESIGN decoder
(
code[1..0] : INPUT;
out[3。.0] : OUTPUT;
)
BEGIN
CASE code[] IS
WHEN 0 =〉 out[] = B”0001";
WHEN 1 =〉 out[] = B”0010";
WHEN 2 => out[] = B”0100";
WHEN 3 => out[] = B”1000”;
END CASE;
END;
例6:7段显示译码器例
7段显示器的笔划顺序
% -a- %
% f| |b %
% -g- %
% e| |c %
% -d— %
该显示器可以显示如下数字和字母:
% 0 1 2 3 4 5 6 7 8 9 A b C d E F %
7段译码器程序:
SUBDESIGN 7segment
(
i[3.。0] : INPUT;
a, b, c, d, e, f, g : OUTPUT;
)
BEGIN
TABLE
i[3.。0] => a, b, c, d, e, f, g;
H"0" => 1, 1, 1, 1, 1, 1, 0;
H”1" =〉 0, 1, 1, 0, 0, 0, 0;
H"2” => 1, 1, 0, 1, 1, 0, 1;
H"3” => 1, 1, 1, 1, 0, 0, 1;
H"4” =〉 0, 1, 1, 0, 0, 1, 1;
H"5” =〉 1, 0, 1, 1, 0, 1, 1;
H"6" => 1, 0, 1, 1, 1, 1, 1;
H”7” => 1, 1, 1, 0, 0, 0, 0;
H”8” =〉 1, 1, 1, 1, 1, 1, 1;
H"9” =〉 1, 1, 1, 1, 0, 1, 1;
H”A” => 1, 1, 1, 0, 1, 1, 1;
H”B” =〉 0, 0, 1, 1, 1, 1, 1;
H”C” =〉 1, 0, 0, 1, 1, 1, 0;
H”D” =〉 0, 1, 1, 1, 1, 0, 1;
H”E" =〉 1, 0, 0, 1, 1, 1, 1;
H”F" => 1, 0, 0, 0, 1, 1, 1;
END TABLE;
END;
例7:地址译码器例。
SUBDESIGN decode3
(
addr[15。.0], m/io : INPUT;
rom, ram, print, sp[2.。1] : OUTPUT;
)
BEGIN
TABLE
m/io, addr[15..0] => rom, ram, print, sp[];
1, B"00XXXXXXXXXXXXXX" => 1, 0, 0, B"00”;
1, B”100XXXXXXXXXXXXX" =〉 0, 1, 0, B"00";
0, B"0000001010101110” =〉 0, 0, 1, B"00";
0, B"0000001011011110” => 0, 0, 0, B"01";
0, B”0000001101110000" =〉 0, 0, 0, B"10”;
END TABLE;
END;
例8:使用lpm译码功能译码
该译码器功能:
Enable
data[LPM_WIDTH1.。0]
eq[LPM_DECODES—1。.0]
0
X
0000.。.00
1
LPM_DECODES 1
1000...00
1
L_DECODES PM 2
0100..。00
…
…
…
1
1
0000...10
1
0
0000。..01
该函数的AHDL说明:
FUNCTION lpm_decode (data[LPM_WIDTH-1.。0], enable, clock, aclr)
WITH (LPM_WIDTH, LPM_DECODES, LPM_PIPELINE)
RETURNS (eq[LPM_DECODES-1。。0]);
在此例中不需要enable,clock和acir端口。
该译码器源文件:
INCLUDE "lpm_decode.inc”;
SUBDESIGN decode4
(
address[15。。0] : INPUT;
chip_enable : OUTPUT;
)
BEGIN
chip_enable = lpm_decode(data[]=address[])
WITH (LPM_WIDTH=16, LPM_DECODES=2^10)
RETURNS (。eq[H"0370"]); %返回地址为H"0370"位置的码%
END;
(4) 变量缺省值的使用
例1:
SUBDESIGN default1
(
i[3。.0] : INPUT;
ascii_code[7.。0] : OUTPUT;
)
BEGIN
DEFAULTS
ascii_code[] = B”00111111”; % 问号的ASCII码 %
END DEFAULTS;
TABLE
i[3。。0] =〉 ascii_code[];
B”1000" =〉 B”01100001"; % ”a” %
B”0100" => B"01100010"; % "b" %
B"0010” => B"01100011”; % "c” %
B"0001" =〉 B"01100100"; % "d" %
END TABLE;
END;
在该例中若没有译码输出时,输出问号.
例2:
SUBDESIGN default2
(
a, b, c : INPUT;
select_a, select_b, select_c : INPUT;
wire_or, wire_and : OUTPUT;
)
BEGIN
DEFAULTS
wire_or = GND;
wire_and = VCC;
END DEFAULTS;
IF select_a THEN
wire_or = a;
wire_and = a;
END IF;
IF select_b THEN
wire_or = b;
wire_and = b;
END IF;
IF select_c THEN
wire_or = c;
wire_and = c;
展开阅读全文