学习目标:
通过分析三八译码器的功能,总结其特点,进而用VERILOG语言来描述,在ISE12.2里编写代码并下载板子上进行实验验证。
学习所得:
1,        三八译码器的原理。
2,        VERILOG语言的学习和应用。
3,        熟练ISE的开发流程以及熟练开发板的使用。
4,        学习使用ISE查看硬件描述语言产生的原理图。
5,        学习和感受解决的问题的思考过程。
6,        if,case 在所有条件没有罗列完整的情况下生成锁存器。///LATCH
7,        试感受组合逻辑电路的最本质:所有的输出跟输入状态存在一种可查表的一一对应关系,VERILOG的描述都是在某种思路表达出这个列表。
学习步骤:
  在实际应用中三八译码器一般用来做片选的译码,可以将地址总线的三位做为三八译码器的输入,得到了8个输出,每个输出可以选择一个器件,达到所谓的片选的目的。
  我们来看一下三八译码器的输入和输出对应关系:
  A[2]        A[1]        A[0]        Y[7]        Y[6]        Y[5]        Y[4]        Y[3]        Y[2]        Y[1]        Y[0]
0        0        0        0        0        0        0        0        0        0        1
0        0        1        0        0        0        0        0        0        1        0
0        1        0        0        0        0        0        0        1        0        0
0        1        1        0        0        0        0        1        0        0        0
1        0        0        0        0        0        1        0        0        0        0
1        0        1        0        0        1        0        0        0        0        0
1        1        0        0        1        0        0        0        0        0        0
1        1        1        1        0        0        0        0        0        0        0
  按照二进值表达方式理解输入,三根输入地址能表示2的三次方8个状态,分别是0-7,这里面每一个状态都有一根输出线与之对应。这是三八译码器的基本特点。
有了上面分析,就开始编程了:首先想到,这个里面将三个输入的所有状态罗列出来,之后罗列出对应的输出就得到了一个实现。这种并行的罗列,我们用到了case语句,实现代码如下:
module decoder38( //使用CASE 语句
input [2:0]a,
output reg [7:0]y
);
  always @*
case (a[2:0])
3’b000:y<=8'b0000_0001;
3’b001:y<=8'b0000_0010;
3’b010:y<=8'b0000_0100;
3’b011:y<=8'b0000_1000;
3’b100:y<=8'b0001_0000;
3’b101:y<=8'b0010_0000;
3’b110:y<=8'b0100_0000;
3’b111:y<=8'b1000_0000;
endcase
endmodule
有了这个代码,立即启动ISE12.2建立一个项目,将次三八译码器实现一下。
建立项目,拷贝代码,对照原理图锁定引脚,讲解代码,综合,实现,下载运行,不需要烧写在板子里。实现功能了,之后查看生成的原理图。
以此实验如下代码,并且学习更优的VERILOG语法 :
module decoder38_1( //使用位移操作
input [2:0]a,
output [7:0]y
);
assign y=1<<a;//我们看到并没有生成任何移位寄存器,而是由编译器分析了我们要实现内容,用等效方式实现了。
endmodule
  module decoder38_2( //使用CASE 语句
input [2:0]a,
output reg  [7:0]y
);
always @*
case (a[2:0])
0:y<=8'b0000_0001;//罗列了所有输入的可能
1:y<=8'b0000_0010;
2:y<=8'b0000_0100;
3:y<=8'b0000_1000;
4:y<=8'b0001_0000;
5:y<=8'b0010_0000;
6:y<=8'b0100_0000;
7:y<=8'b1000_0000;
endcase
endmodule
  module decoder38_3( //使用if
input [2:0]a,
output  reg   [7:0]y
);
always @*
if (a==0)y<='h01;else  //在此例子中不是很合适。但是由于条件不重叠,编译器会自动优化,不会生成优先级级别。(将在之后将到优先级编码)
if (a==1)y<='h02;else
if (a==2)y<='h04;else
if (a==3)y<='h08;else
if (a==4)y<='h10;else
if (a==5)y<='h20;else
if (a==6)y<='h40;else  // 如果没有罗列所有输入,就会生成生成锁存器。
if  (a==7)y<='h80;else  //锁存器在FPGA设计中尽力避免使用,因为会给时序分析带来很大苦难,导致可能到不到时序要求
y<='hx;
endmodule
  module decoder38_4( //**使用assign**
input [2:0]a,
output [7:0]y
);
assign y[0] = a==0 ; //y[0]这跟输出线总是在输入线是0的时候输出1
assign y[1] = a==1 ;
assign y[2] = a==2 ;
assign y[3] = a==3 ;
assign y[4] = a==4 ;
assign y[5] = a==5 ;
assign y[6] = a==6 ;
assign y[7] = a==7 ;
endmodule
  module decoder38_7(//使用循环
input [2:0]a,
output  reg  [7:0]y
);
integer i ;//or reg [3:0]i ;
always @*        //这里的循环实际是一种行为描述了。从一个比较抽象的层面上实现。
for(i=0;i<=7;i=1+i) //这里的for循环也是一种描述,类似于脚本语言,编译器会将这多次循环逐一展开。
//if(a==i)y=1;else y=0;
y=a==i;
endmodule
    module decoder38_5( //使用位逻辑运算
input [2:0]a,
output [7:0]y
);
assign y[0] = ~a[2] & ~a[1] & ~a[0] ;//3'b000
assign y[1] = ~a[2] & ~a[1] & a[0] ;//3'b001
assign y[2] = ~a[2] & a[1] & ~a[0] ;//3'b010
assign y[3] = ~a[2] & a[1] & a[0] ;//3'b011
assign y[4] = a[2] & ~a[1] & ~a[0] ;//3'b100
assign y[5] = a[2] & ~a[1] & a[0] ;//3'b101
assign y[6] = a[2] & a[1] & ~a[0] ;//3'b110
assign y[7] = a[2] & a[1] & a[0] ;//3'b111
endmodule  
  module decoder38_10( //例化模块实现。
input [2:0]a,
output [7:0]y
);
and3 y0_logic (.a0(~a[0]),.a1(~a[1]),.a2(~a[2]),.b(y[0]));
and3 y1_logic (.a0(~a[0]),.a1(~a[1]),.a2(a[2]),.b(y[1]));
and3 y2_logic (.a0(~a[0]),.a1(a[1]),.a2(~a[2]),.b(y[2]));
and3 y3_logic (.a0(~a[0]),.a1(a[1]),.a2(a[2]),.b(y[3]));
and3 y4_logic (.a0(a[0]),.a1(~a[1]),.a2(~a[2]),.b(y[4]));
and3 y5_logic (.a0(a[0]),.a1(~a[1]),.a2(a[2]),.b(y[5]));
and3 y6_logic (.a0(a[0]),.a1(a[1]),.a2(~a[2]),.b(y[6]));
and3 y7_logic (.a0(a[0]),.a1(a[1]),.a2(a[2]),.b(y[7]));
endmodule
  module and3( //被例化模块:三输入与门
input a0,a1,a2,
output b
);
assign b = a0 & a1 & a2;
endmodule
  module decoder38_6(//使用?:表达式
input [2:0]a,
output [7:0]y
);
assign y = (a==0)?'h01://这个连续赋值和if else语句类似,使用问好表达式也可能生成长的优先级逻辑,所以不是很提倡,由于罗列了所有的输入条件,所以没有生成优先级。
           (a==1)?'h02:
           (a==2)?'h04:
           (a==3)?'h08:
           (a==4)?'h10:
           (a==5)?'h20:
           (a==6)?'h40:
           (a==7)?'h80: 'hx;
endmodule
  module decoder38_8( //使用 function 调用
input [2:0]a,
output [7:0]y
);
function [7:0]do_dec38;  //函数要写在模块里面
input [2:0]din;
do_dec38 = 1<<din;
endfunction
assign y=do_dec38(a);
endmodule
  module decoder38_9( //task一般用于仿真比较多,使用task 调用,此处可以综合
input [2:0]a, //这种写法不是很提倡
output reg  [7:0]y
);
task do_dec38;
input [2:0]din;
y = 1<<din;
endtask
always @*do_dec38(a);
endmodule
  总结:希望能达到我在开头所罗列的目标,这节的内容比较多,尽量去**学习总结积累**,不要负担,一个相同是知识点在之后还要多次重复,一些重点的遇到一次着重复习总结一次。希望我能够坚定信心。