该个栏目的博客都是基于南京大学的数字逻辑与计算机组成的课程设计,方便以后进行总结归纳而准备的。
这次实验是实验一:选择器。设计一个简单的选择器,介绍一些常用的多路选择器的设计方法。Verilog语言中的always语句块、if-else语句和case语句的使用等。最后请读者自行设计一个多路选择器。
1.二选一多路选择器
通过上述的真值表和卡诺图,可以得到二选一选择器的表达式y=(~s&a)|(a&b);以及通过表达式可以画出其实际的逻辑电路。
常用的有以下三种方式:数据流建模方式、结构化建模和行为级建模对电路的功能进行描述。应该要做到心中有电路,直接进行描述。而不是希望通过行为级建模的方式,让综合器生成某种行为的电路,这就偏离了“描述电路”的本质了。
基于vivado的综合,这里给出一个二选一多路选择器,采用行为级建模和数据流建模的不同之处。
数据流建模:
行为级建模
可以很明显的看出,行为级建模和数据流建模通过RTL的电路都并不相同,行为级建模是通过一个多路选择器实现的,而且数据流建模则是采用与非门实现的功能。MUX的最低的单元,可能不利于描述电路。
真正的描述电路=实例化+连线;
用HDL设计电路,就是在用HDL来描述电路图纸,图纸上有什么,就直接描述什么。所以,用HDL描述电路,无非是做两件事情:
实例化:在电路板上放一个元件/模块,可以是一个门电路,或者是由门电路组成的模块
连线:用导线将元件/模块的引脚正确地连起来
大家可以体会一下,数据流建模和结构化建模是如何体现这两件事的,而行为建模又是如何把这两件简单的事情复杂化的。所以在未掌握“描述电路”的思维而不被行为建模误导之前,我们应该远离行为建模方式,仅通过数据流建模和结构化建模方式直接描述电路。可以通过思考以下问题来帮助大家测试自己是否已经掌握了Verilog的本质:
1.在硬件描述语言中,“执行”的精确含义是什么?
2.是谁在执行Verilog的语句?是电路,综合器,还是其它的?
3.if的条件满足,就不执行else后的语句,这里的“不执行”又是什么意思? 和描述电路有什么联系?
4.有“并发执行”,又有“顺序执行”,还有“任何一个变量发生变化就立即执行”,以及“在任何情况下都执行”,它们都是如何在设计出来的电路中体现的?
**虽然学了有一段时间,但这几个问题依然没有什么思路。**所以目前,不采用行为建模的方式。
2.四选一多路选择器
module mux41(a,s,y);
input [3:0] a;
input [1:0] s;
output reg y;
always @ (s or a)
case (s)
0: y = a[0];
1: y = a[1];
2: y = a[2];
3: y = a[3];
default: y = 1'b0;
endcase
endmodule
但不建议初学者使用case语句,因为使用case语句描述电路属于行为建模方式。随着电路变的越来越复杂,你可能会写出case语句中包含if语句,if语句中嵌套case语句的代码,但你已经完全不了解它描述的电路是什么样的了。
课程提供了一个通用的选择器模板
module MuxKeyInternal #(NR_KEY = 2, KEY_LEN = 1, DATA_LEN = 1, HAS_DEFAULT = 0) (
output reg [DATA_LEN-1:0] out,
input [KEY_LEN-1:0] key,
input [DATA_LEN-1:0] default_out,
input [NR_KEY*(KEY_LEN + DATA_LEN)-1:0] lut
);
localparam PAIR_LEN = KEY_LEN + DATA_LEN;
wire [PAIR_LEN-1:0] pair_list [NR_KEY-1:0];
wire [KEY_LEN-1:0] key_list [NR_KEY-1:0];
wire [DATA_LEN-1:0] data_list [NR_KEY-1:0];
generate
for (genvar n = 0; n < NR_KEY; n = n + 1) begin
assign pair_list[n] = lut[PAIR_LEN*(n+1)-1 : PAIR_LEN*n];
assign data_list[n] = pair_list[n][DATA_LEN-1:0];
assign key_list[n] = pair_list[n][PAIR_LEN-1:DATA_LEN];
end
endgenerate
reg [DATA_LEN-1 : 0] lut_out;
reg hit;
integer i;
always @(*) begin
lut_out = 0;
hit = 0;
for (i = 0; i < NR_KEY; i = i + 1) begin
lut_out = lut_out | ({DATA_LEN{key == key_list[i]}} & data_list[i]);
hit = hit | (key == key_list[i]);
end
if (!HAS_DEFAULT) out = lut_out;
else out = (hit ? lut_out : default_out);
end
endmodule
这里提供的这个MuxKeyInternal的代码,等后面有时间进行解析。
但现在可以简单示范一下如何使用,需要提供键值对的数量NR_KEY,键值的位宽KEY_LEN以及数据的位宽DATA_LEN这三个参数,以及是否采用默认的输出值。当HAS_DEFAULT为0时,则默认输出全0的输出值。
3.二位四选一选择器
用选择器模板实现一个2位4选1的选择器,如下图所示,选择器有5个2位输入端,分别为X0, X1, X2, X3和Y,输出端为F;X0, X1, X2, X3是四个2位的输入变量。输出F端受控制端Y的控制,选择其中的一个X输出,当Y = 00时,输出端输出X0,即F = X0;当Y = 01时,输出端输出X1,即F = X1;以此类推。
mux4x1_2bit.v
module mux4x1_2bit(
input [1:0] X0 ,
input [1:0] X1 ,
input [1:0] X2 ,
input [1:0] X3 ,
input [1:0] Y ,
output [1:0] F
);
MuxKeyInternal #(4, 2, 2, 1) dut (F, Y, 2'b00,{
2'b00,X0,
2'b01,X1,
2'b10,X2,
2'b11,X3
});
endmodule
通过vivado进行综合:
4.通过NVboard实现小灯的控制
目前,还没有将NVboard配置完成,且其中的Makefile还没完全弄明白,所以等后续有时间了再补充该部分,将小灯的引脚挂载到F引脚上。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)