3-8译码器的结构

image-20231018234830377

真值表如下:

image-20231018235126588

显然就是用三个二进制表示8个要选择的电平。

译码器的代码编写

我们译码器的的代码和解释如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module decoder_3_8(a, b, c, out);
input a;
input b;
input c;
output reg[7:0] out;
//或者always@(a, b, c)
//以always块描述的信号赋值,被赋值对象肯定定义为reg类型。
//reg [7:0] out;//此时看到下面红线报错消失了。或者在output后面直接加上reg
always@(*)
case({a, b, c})
3'b000: out[7:0] = 8'b00000001;
3'b001: out = 8'b00000010;
3'b010: out = 8'b00000100;
3'b011: out = 8'b00001000;
3'b100: out = 8'b00010000;
3'b101: out = 8'b00100000;
3'b110: out = 8'b01000000;
3'b111: out = 8'b10000000;
endcase
//{a, b, c}变成了一个三位的信号,这是位拼接。我们之前见过的,还有位复制等操作。
//这里位数的表示比如3'b111也就是表示十进制的7,可以写为3'd7或者16进制的3'h7,八进制并不常用。

endmodule

synthesis语法测试

然后我们在左侧点击运行测试。

image-20231019002748193

这是用来检查语法是否有错误的。出现弹框会让我们选cpu的个数,默认即可!等待一段时间,即可跑完,之后我们可以点击查看报告来确认是否正确。

image-20231019002852332

然后还可以从message里面查看是否有语法错误。

仿真测试

仿真测试我们在数字电路中学习过,其实就是加入一个示波器,并且给定不同状态的输入信号,output连接示波器,在输入变化期间,观察示波器的显示,确认电路逻辑无误。

先点击添加源文件,创建一个仿真源文件

image-20231019003220304

然后点击create_file创建文件。

image-20231019003245380

然后输入我们给仿真文件的名字,就可以和我们工程的名字相同,这里统一用decoder_3_8来命名。

image-20231019003426121

当然我在后面加上了testbench因为testbench是仿真文件的标识符。然后完成创建,开始编辑testbench文件。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
`timescale 1ns/1ns
//先定义时间,然后定义测试模块(也就是外层模块)
module decoder_3_8_testbench;
//设置激励信号,用于三个输入端口
reg s_a;
reg s_b;
reg s_c;//都是reg型。
wire [7:0] out;
//在里面实例化小模块,连接到示波器等。
decoder_3_8 instant(.a(s_a), .b(s_b), .c(s_c), .out(out));
//或者用更好的方法
//decoder_3_8_instant(s_a, s_b, s_c, output)//直接指向外面接口,但是顺序一定要对!用于有多个小模块,内部端口
//都是a的时候,无法分清楚,就不写内部端口了,只需要每个小模块对应好外部端口,顺序也正确即可。

//下面给出激励的变化!注意激励产生在外部端口
initial begin
s_a = 0; s_b = 0; s_c = 0;
#200;
s_a = 0; s_b = 0; s_c = 1;
#200;
s_a = 0; s_b = 1; s_c = 0;
#200;
s_a = 0; s_b = 1; s_c = 1;
#200;
s_a = 1; s_b = 0; s_c = 0;
#200;
s_a = 1; s_b = 0; s_c = 1;
#200;
s_a = 1; s_b = 1; s_c = 0;
#200;
s_a = 1; s_b = 1; s_c = 1;
#200;
end
endmodule

我们可以先再运行一下synthesis来检查一下语法问题,当然这里我就跳过了,不建议大家都跳过,如果是刚开始学没多久的话。

点击上面栏里的求和

符号可以查看simulationsynthesis状态。

image-20231019005047501

可以看到没有错误,然后运行仿真。

image-20231019005115928

我们先运行behavior仿真,也就是理想仿真情况,不存在门电路延迟现象。结果如图所示:

image-20231019005234249

软件默认只能跑1000ns,但是我们程序总共要跑1600ns,所以可以让他跑完。

image-20231019005313075

点击这里的播放键,就可以跑完了。

然后放大可以看到全图。我这里点击了图中栏上的四个箭头扩张键,就可以放大时间轴了。

image-20231019005347685

引脚分配

然后我们开始硬件的引脚分配

image-20231019010041813

点击下面的open synthesized design

然后看到弹出的device画面,再点击layout中的io planning

image-20231019010133400

便显示出了我们选的具体板子的io引脚图。

image-20231019010218818

然后在下面我们点击这个,更方便的查看引脚对应我们的变量名。

image-20231019010313760

然后把所有的IO表准都改成如下格式。

image-20231019010356570

都改成33结尾的。

在实际开发板上

image-20231019010511778

我们看到8个拨动开关,超过3个,可以用来选三个作为输入。

我们看一下引脚说明书。

image-20231019010648308

这是这8个拨动开关的名字和编号。比如我们把输入a给SW2,那么对应就要选择E22。

image-20231019010802795

比如我们把b给SW1,那么就要选择D22。我不再截图。

out我们用LED灯来显示,找一个灯的接口赋值给output即可。观察输出即可看亮度。

image-20231019011000307

对应此LED接口表连接即可。

image-20231019011044877

我们直接让out[0]输出到灯LED0,以此类推。

然后ctrl+s保存即可。遇见弹框直接点OK。然后输入文件名。

image-20231019011404669

保存即可。

image-20231019011503184

可以找到一些被我们分配的IO口。

implementation or directly generate bitstream

也就是我们可以直接点击generate bitstream键一步到位。implementation用来布局布线,generate bitstream自动执行布局布线的操作。

image-20231019012033338

我重启了项目之后点击了implementation可以看到它会自动先从synthesis开始运行。

结束之后我们点击打开implemented design

image-20231019012309838

如图所示,没有什么我们需要关注的。

image-20231019012327181

然后生成比特流即可!

image-20231019012403041

这里会显示状态。

image-20231019012456469

然后我们打开硬件管理器,准备连接到硬件并且将比特流下载到硬件。

插上硬件之后点击

image-20231019012600642

即可。

最后点击program devive即可下载过去。然后直接在开发板对应输入开关处来回拨动即可。查看LED灯状态。

image-20231019012640469