Danny Mok Altera HK FAE (dmok@altera.com) AHDL培训教材 Danny Mok Altera HK FAE (dmok@altera.com) 2018/12/9 P.1
什么是 AHDL? AHDL是Altera Hardware Description Language的缩写 由 Altera公司开发 集成在 Altera的开发软件Max+Plus II中 以语言的形式而不是图形的形式描述硬件 容易修改 容易维护 尤其适合实现以下的逻辑功能 复杂的组合逻辑 BCD码向 7段字形的转换器 状态机 地址译码 其他你还没想到的功能…….. 2018/12/9 P.2
接上页 与图形输入方式一样容易 功能与其他硬件描述语言( HDL)同样强大 如:标准VHDL、 Verilog HDL 等 2018/12/9 P.3
怎样使用 ADHL? 使用任何一个文本编辑器创建设计文件 点击这 个按钮 Altera的开发软件Max+Plus II 也提供了一个文本编辑器 输入你的 AHDL设计文件 点击这 个按钮 2018/12/9 P.4
接上页 创建 AHDL文件 2018/12/9 P.5
接上页 把你的 ADHL保存为 name.TDF的形式 两者必 须相同 2018/12/9 P.6
接上页 点击这 个图标 2018/12/9 P.7
编译过程中的错误定位 错误定位容易 点击错 误消息 点击定位按钮 错误 定位 2018/12/9 P.8
AHDL模板 If-then-else case-end case loop-end loop 忘了怎么办? ??…??? 修改代码
一般的AHDL文件格式 关键字 SUBDESIGN decode1 ( input_pin_name : INPUT; input_bus_name[15..0] : INPUT; output_pin_name : OUTPUT; output_bus_name : OUTPUT; ) BEGIN ouptut_pin_name = input_pin_name; output_bus_name = input_bus_name; END; 定义I/O端口 逻辑表达式 AHDL格式 2018/12/9 P.10
第一个 AHDL设计-地址译码器 SUBDESIGN decode1 ( a[3..0] : input; Chip_enable = a0 & a1 & a2 & !a3 SUBDESIGN decode1 ( a[3..0] : input; chip_enable : output; ) begin chip_enable = (a[3..0] == H"7"); end; 2018/12/9 P.11
为什么使用 AHDL 而不用图形输入方式 容易修改 输入代码和证实逻辑同时进行 将译码输出条件由H”7” 改为H”A” SUBDESIGN decode1 ( a[3..0] : input; chip_enable : output; ) begin chip_enable = (a[3..0] == H"A"); end; 编译器自己解释函数 只需修改一个字母 修改更麻烦 Chip_enable = !a0 & a1 & !a2 & a3 2018/12/9 P.12
更多的优势 SUBDESIGN decode1 ( a[3..0] : input; chip_enable : output; ) begin chip_enable = (a[3..0] == B"1x0x"); end; 比较器的某些输入比特可以忽略 2018/12/9 P.13
AHDL基本知识 “加”运算符: + “减”运算符: - 数量“相等”运算符: == “不等”运算符: != “大于”运算符: > “大于或等于”运算符: >= “小于”运算符: < “小于或等于”运算符: <= 逻辑“或”运算符: # 逻辑“逻辑与”运算符: & 2018/12/9 P.14
使用常数(Constant)功能 如果文件中相同的数字、字符串或者算术表达式重复出现多次,使用常数(Constant)来表示它们 优点 如果修改,只需改变一个声明 修改一处即可修 改整个设计文件 CONSTANT IO_ADDRESS = H"A"; SUBDESIGN decode1 ( a[3..0] : input; chip_enable : output; ) begin chip_enable = (a[3..0] == IO_ADDRESS); if (a[3..0] == IO_ADDRESS) then ……... end; 在关键字 SUBDESIGN 之前,定义常数 ( CONSTANT) 2018/12/9 P.15
常数( Constant)的其他用途 常数使用举例 定义一个常数值 定义一个算术表达式 通过预先定义的常数 定义新的常数 Constant IO_ADDRESS = H”370”; Constant FOO = 1+2*3 - LOG2(256); Constant FOO_PLUS_one = FOO + 1; 定义一个常数值 定义一个算术表达式 通过预先定义的常数 定义新的常数 2018/12/9 P.16
组合逻辑的实现 out1 = a0 & !a1 out2 = a0 & !a1 # b AHDL设计文件 SUBSDESIGN decode1 ( a0, a1, b : input; out1, out2 : output; ) begin out1 = a0 & !a1; out2 = out1 # b; end; 图形设计文件 2018/12/9 P.17
定义节点 图形方式 AHDL 方式 SUBDESIGN decode1 ( a0, a1, b, d: input; out2, out3 : output; ) variable temp : node; begin temp = a0 & !a1; out2 = temp # b; out3 = temp & d; end; out2 = a0 & !a1 # b out3 = a0 & !a1 & d temp 图形方式 2018/12/9 P.18
总线操作 功能相同 但容易描述 SUBDESIGN decode1 ( a[3..0], b[3..0] : input; out[3..0] : output; ) begin out0 = a0 & b0; out1 = a1 & b1; out2 = a2 & b2; out3 = a3 & b3; end; SUBDESIGN decode1 ( a[3..0], b[3..0] : input; out[3..0]: output; ) begin out1[] = a[] & b[]; end; 功能相同 但容易描述 2018/12/9 P.19
总线操作的其他方式 总线操作 a[9..0], b[9..0] a7=b9, a6=b8, a5=b7, a4=b6 a[9..8] = VCC; a[9..8] = 1; a[9..8] = 2; a[9..8] = 3; a[3..0] = GND a[3..0] = 0; temp = b0& b1; a[2..1] = temp a7=b9, a6=b8, a5=b7, a4=b6 a[9..8] connect to VCC a[9..8] = B”01” a[9..8] = B”10” a[9..8] = B”11” a[3..0] connect to GND a[3..0] = B”0000” a2 = temp, a1 = temp 2018/12/9 P.20
高级总线操作 总线 总线阵列 a[3..2][1..0] = b[]; 首先对低位比特赋值 a3_1 = b3 a3_0 = b2 b3, b2, b1, b0 (having 4 members) MSB is b3, LSB is b0 总线阵列 a[3..0][2..0] a3_2, a3_1, a3_0, a2_2, a2_1, a2_0, a1_2, a1_1, a1_0, a0_2, a0_1, a0_0 (having 12 members) MSB is a3_2, LSB is a0_0 a[3..2][1..0] = b[]; a3_1 = b3 a3_0 = b2 a2_1 = b1 a2_0 = b0 首先对低位比特赋值 2018/12/9 P.21
真值表 i[3..0] Segment 7 0 0 1 1 2 2 F F 修改非常方便 a 2018/12/9 P.22 b f g e 0 0 1 1 2 2 F F a b c d e f g 2018/12/9 P.22 修改非常方便
IF-THEN-ELSE语句 SUBDESIGN priority ( low, medium, high : input; highest_level[3..0] : output; ) begin if ( high == B”1”) then highest_level[] = B”1000”; elsif (medium == B”1”) then highest_level[] = B”0100”; elsif (low == B”1”) then highest_level[] = B”0010”; else highest_level[] = B”0001”; end if; end; 2018/12/9 P.23
需要4个逻辑单元 2018/12/9 P.24
CASE语句 SUBDESIGN decoder (low, medium, high : input; highest_level[3..0] : output; ) variable code[2..0] : node; begin code2=high; code1=medium; code0=low; case code[] is when 4 => highest_level[] = B”1000”; when 2 => highest_level[] = B”0100”; when 1 => highest_level[] = B”0010”; when others => highest_level[] = B”0001”; end case; end; 注意这一行的用法 2018/12/9 P.25
2018/12/9 P.26
循环语句FOR...LOOP... CONSTANT num_of_bit = 8; SUBDESIGN numbit ( a[num_of_bit..0] : input; b[num_of_bit..0] : output; ) begin b[8] = a[0]; b[7] = a[1]; b[6] = a[2]; b[5] = a[3]; b[4] = a[4]; b[3] = a[5]; b[2] = a[6]; b[1] = a[7]; b[0] = a[8]; end; for i in 0 to num_of_bit generate b[num_of_bit - i] = a[i]; end generate; 实现相同的功能更加容易 (a[num_of_bit..0] : input; b[num_of_bit..0] : otuput; b[num_of_bit..0] = a[0..num_of_bit]; 2018/12/9 P.27
用图形方式调用AHDL 使用文件菜单的“Create Default Symbol”条目为 AHDL 设计创建默认符号 在图形输入中使用这个默认符号 2018/12/9 P.28
寄存器逻辑的实现 方法 2 方法 1 SUBDESIGN flip_flop SUBDESIGN flip_flop ( d, clk : input; q : output;) begin q = dff(d,clk, ,); end; SUBDESIGN flip_flop ( d, clk : input; q : output;) variable temp : dff; begin temp.d = d; temp.clk = clk; q = temp.q; end; 调用一个 D-Flipflop 2018/12/9 P.29
更详细的说明 2018/12/9 P.30
关于寄存器的其他问题 如何实现总线寄存器 其他类型的寄存器的应用 DFFE: 带使能端的D触发器 TFF/TFFE:T触发器和带使能端的T触发器 JKFF/JKFFE :JK触发器和带使能端的JK触发器 SRFF/SRFFE:SR触发器和带使能端的SR触发器 2018/12/9 P.31
总线寄存器的实现 SUBDESIGN bus_reg ff[0].clk = clk; ( clk, d[7..0] : input; q[7..0] : output; ) variable ff[7..0] : dff; begin ff[].clk = clk; ff[].d = d[]; q[] = ff[].q; end; ff[0].clk = clk; ff[1].clk = clk; ff[2].clk = clk; ff[3].clk = clk; ff[4].clk = clk; ff[5].clk = clk; ff[6].clk = clk; ff[7].clk = clk; ff[0].d = d[0]; ff[1].d = d[1]; ff[2].d = d[2]; ff[3].d = d[3]; ff[4].d = d[4]; ff[5].d = d[5]; ff[6].d = d[6]; ff[7].d = d[7]; q[0] = ff[0].q; q[1] = ff[1].q; q[2] = ff[2].q; q[3] = ff[3].q; q[4] = ff[4].q; q[5] = ff[5].q; q[6] = ff[6].q; q[7] = ff[7].q; 2018/12/9 P.32
带清零端、预置端和使能端的D触发器 SUBDESIGN flip_flop_enable ( clock, data, enable, preset, clear : input; qout : output; ) variable temp : dffe; begin temp.d = data; temp.clk = clock; temp.clrn = clear; temp.prn = preset; temp.ena = enable; qout = temp.q; end; D CLK CLRN PRN ENA Q SUBDESIGN flip_flop_enable ( clock, data, enable, preset, clear : input; qout : output; ) variable temp : dffe; begin temp.d = data; temp.clk = clock; temp.clrn = clear; temp.prn = preset; temp.ena = enable; qout = temp.q; end; D CLK CLRN PRN ENA Q SUBDESIGN flip_flop_enable ( clock, data, enable, preset, clear : input; qout : output; ) variable temp : dffe; begin temp.d = data; temp.clk = clock; temp.clrn = clear; temp.prn = preset; temp.ena = enable; qout = temp.q; end; D CLK CLRN PRN ENA Q SUBDESIGN flip_flop_enable ( clock, data, enable, preset, clear : input; qout : output; ) variable temp : dffe; begin temp.d = data; temp.clk = clock; temp.clrn = clear; temp.prn = preset; temp.ena = enable; qout = temp.q; end; D CLK CLRN PRN ENA Q SUBDESIGN flip_flop_enable ( clock, data, enable, preset, clear : input; qout : output; ) variable temp : dffe; begin temp.d = data; temp.clk = clock; temp.clrn = clear; temp.prn = preset; temp.ena = enable; qout = temp.q; end; D CLK CLRN PRN ENA Q SUBDESIGN flip_flop_enable ( clock, data, enable, preset, clear : input; qout : output; ) variable temp : dffe; begin temp.d = data; temp.clk = clock; temp.clrn = clear; temp.prn = preset; temp.ena = enable; qout = temp.q; end; D CLK CLRN PRN ENA Q SUBDESIGN flip_flop_enable ( clock, data, enable, preset, clear : input; qout : output; ) variable temp : dffe; begin temp.d = data; temp.clk = clock; temp.clrn = clear; temp.prn = preset; temp.ena = enable; qout = temp.q; end; PRN D Q CLK ENA CLRN 2018/12/9 P.33
其他类型的触发器 2018/12/9 P.34
帮助菜单的使用 问:我不知道怎样使用 Altera的D触发器和带使能端的JK触发器,我该怎么办 ? 问:怎样使用帮助菜单 ? 答: 很容易而且很有趣 DFFE 2018/12/9 P.35
帮助菜单的使用 2018/12/9 P.36
三态缓冲器的实现 方法 1 方法 2 SUBDESIGN tri_state (a, enable : input; b : output;) begin b = tri(a, enable); end; ( a, enable : input; variable temp : tri; temp.in = a; temp.oe = enable; b = temp.out; 2018/12/9 P.37
更详细的说明 2018/12/9 P.38
OPNDRN -漏极开路缓冲器 Method 1 Method 2 SUBDESIGN tri_state SUBDESIGN opn_drn (enable : input; b : output;) begin b = opndrn(enable); end; SUBDESIGN tri_state ( enable : input; variable temp : opndrn; temp.in= enable; b = temp.out; 2018/12/9 P.39
更详细的说明 2018/12/9 P.40
使用 AHDL 与使用原理图同样方便 但是 AHDL 功能更强大 2018/12/9 P.41
练习部分 AHDL SUBDESIGN tri_io ( clk, enable : input; io : bidir;) variable temp1 : dff; temp2 : tri; begin temp1.d = io; temp1.clk = clk; temp2.in = temp1.q; temp2.oe = enable; io = temp2.out; end; 输入引脚 双向引脚 clk, enable : input; io : bidir; 2018/12/9 P.42
轻松地设计一个8位计数器 SUBDESIGN 8bits (clk : input; q[7..0] : output; ) variable temp[7..0] : dff; begin temp[].clk = clk; temp[].d = temp[].q +1 ; q[] = temp[].q; end; 2018/12/9 P.43
状态机设计 状态转移图 jump=0 q = 0 S0 jump=1 S1 q = 1 SUBDESIGN simple ( clk, reset, jump : input; q : output; ) variable ss : MACHINE WITH STATES (S0,S1); begin ss.clk = clk; ss.reset = reset; case ss is when s0 => q = gnd; if (jump) then ss = s1; end if; when s1 => q = vcc; ss = s0; end case; end; 状态转移图 注 : 所有的状态机都必须受时钟驱动 S0 S1 jump=1 q = 0 q = 1 jump=0 2018/12/9 P.44
状态转移波形图 if (jump) then ss = s1; end if; ss = s0; 2018/12/9 P.45
状态机设计的其他问题 SUBDESIGN stepper TABLE ( reset, ccw, cw, clk : input; phase[3..0] : output;) variable ss : MACHINE OF BITS (temp[3..0]) WITH STATES ( s0 = B”0001”, s1 = B”0010”, s2 = B”0100”, s3 = B”1000”); begin ss.clk = clk; if (reset) then ss = s2; end if; phase[] = temp[]; TABLE ss, ccw, cw => ss; s0, 1, x => s3; s0, x, 1 => s1; s1, 1, x => s0; s1, x, 1 => s2; s2, 1, x => s1; s2, x, 1 => s3; s3, 1, x => s2; s3, x, 1 => s0; END TABLE; end; 注 : 不必对 TEMP进行声明 它会自动声明为D触发器 2018/12/9 P.46
状态转移图 用户可以控制初始状态 2018/12/9 P.47
练习题 SUBDESIGN stepper TABLE ( reset, ccw, cw, clk : input; phase[3..0] : output;) variable ss : MACHINE OF BITS (temp[3..0]) WITH STATES ( s0 = B”0001”, s1 = B”0010”, s2 = B”0100”, s3 = B”1000”); begin ss.clk = clk; if (reset) then ss = s2; end if; phase[] = temp[]; TABLE ss, ccw, cw => ss; s0, 1, x => s3; s0, x, 1 => s1; s1, 1, x => s0; s1, x, 1 => s2; s2, 1, x => s1; s2, x, 1 => s3; s3, 1, x => s2; s3, x, 1 => s0; END TABLE; end; 试着修改CASE语句的真值表 2018/12/9 P.48
没有恢复状态的状态机 SUBDESIGN recover ( clk, go : input; ok : output;) variable sequence : MACHINE OF BITS (q[2..0]) with STATES ( idle, one, two, three, four, illegal1, illegal2, illegal3); begin sequence.clk = clk; case sequence is when idle => if (go) then sequence = one; end if; when one => sequence = two; when two => sequence = three; when three => sequence = four; end case; ok = (sequence == four); end; 状态机停留在状态“ FOUR”上面 2018/12/9 P.49
状态机最好具有自启动功能 SUBDESIGN recover 三比特实现八个状态 ( clk, go : input; ok : output;) variable sequence : MACHINE OF BITS (q[2..0]) with STATES ( idle, one, two, three, four, illegal1, illegal2, illegal3); begin sequence.clk = clk; case sequence is when idle => if (go) then sequence = one; end if; when one => sequence = two; when two => sequence = three; when three => sequence = four; when OTHERS => sequence = idle; end case; ok = (sequence == four); end; 三比特实现八个状态 只有五个状态有用时, 最好使用自启动选项 2018/12/9 P.50
结论 合适的工具 帮助你实现成功的产品 电路规模大或者设计比较复杂时使用下列设计方法: 在优化设计或者实现高速电路时 AHDL VHDL或者Verilog HDL 在优化设计或者实现高速电路时 采用 AHDL方式、图形方式、 VHDL方式或者Verilog HDL方式混合输入 尽可能发挥工程师的聪明才智 合适的工具 帮助你实现成功的产品 2018/12/9 P.51