HDLBits:在线学习 Verilog (十三 · Problem 60-64)

本系列内容来自于知乎专栏,链接如下:https://zhuanlan.zhihu.com/c_1131528588117385216

本系列文章将和读者一起巡礼数字逻辑在线学习网站 HDLBits 的教程与习题,并附上解答和一些作者个人的理解,相信无论是想 7 分钟精通 Verilog,还是对 Verilog 和数电知识查漏补缺的同学,都能从中有所收获。

Problem 60 : 2-to-1 multiplexer (Mux2to1)

从本题开始的五道题将讨论数字电路中的多路选择器的使用。选择器是一个使用频次很高的模块,选择器从多个输入数据流中选取一个输出到公共的输出端。在综合的过程中一些 Verilog 语法会显式地被"翻译"为选择器,可以在综合结果中看到对应的选择器模块。

牛刀小试

本题中需要实现一个 2 选 1 选择器,sel 信号作为选择信号,当 sel = 1 时选择 b,反之选择 a。

解答与分析

module top_module(
    input a, b, sel,
    output out );
    
    assign out = (sel) ? b : a;
    
endmodule

本题中如果直接翻译题目要求中的逻辑,则对应的逻辑表达式为 (sel & b) | (~sel & a)。在解答中使用了三元运算符简化了逻辑表达,使其更加易读。

三元运算符(Ternary operator)的使用方式是这样的:

cond ? iftrue : iffalse 。cond 条件为真,则表达式的值为 iftrue,反之表达式的值为 iffalse。具体看 (sel)?b:a 式,当 sel 为真时,结果为 b,反之结果为 a。

Verilog 三元运算符原理和 C 语言中的三元运算符相同。但使用更加频繁,尤其是和 assign 的组合:

assign out = (sel)?b:a;

嵌套的用法也十分常用,比如求 a,b,c 中的最大值,可以在一个三元运算符中嵌套两个三元运算符。

assign max = (a > b) ?
    (a > c)?a:c
    :
    (b > c)?b:c
    ;

在嵌套使用时,为了防止混乱,最好将 cond iftrue iffalse 分行书写。

Problem 61 : 2-to-1 bus multiplexer (Mux2to1v)

本题与上一题的区别在于信号从单比特宽度变成总线信号,但选择器的原理以及对应的代码与前一题相同,这里不再赘述。

Problem 62 : 9-to-1 multiplexer (Mux9to1v)

牛刀小试

本题中需要实现一个 9 选 1 选择器,sel 信号作为选择信号,当 sel = 0 时选择 a,sel = 1 时选择 b,以此类推。sel 信号位宽为 4bit,当 sel 大于 8 时,输出 16'hffff。

解答与分析

module top_module(
    input [15:0] a, b, c, d, e, f, g, h, i,
    input [3:0] sel,
    output reg [15:0] out );
    always @(*)begin
        case(sel)
            4'd0:out = a;
            4'd1:out = b;
            4'd2:out = c;
            4'd3:out = d;
            4'd4:out = e;
            4'd5:out = f;
            4'd6:out = g;
            4'd7:out = h;
            4'd8:out = i;
            default:out=16'hffff;
        endcase
    end
endmodule

本题如果使用 assign 语句实现会非常繁复,这里使用逻辑上更加直观的 case 语句。case 语句只能在 always 块中使用。本题为组合逻辑,使用 @(*) 作为敏感列表。

Problem 63 : 256-to-1 multiplexer (Mux256to1)

牛刀小试

本题中需要实现一个 256 选 1 选择器,sel 信号作为选择信号,当 sel = 0 时选择 in[0],sel = 1 时选择 in[1],以此类推。

解答与分析

module top_module (
	input [255:0] in,
	input [7:0] sel,
	output  out
);

	// Select one bit from vector in[]. The bit being selected can be variable.
	assign out = in[sel];
        //assign out = in >> sel;
	
endmodule

本题实质上和 9-to-1 选择器相同,但写一个有 256 case 的 case 语句有些疲劳(手写没有必要,但可以用脚本生成一个)。这里我们可以根据题目的要求,结合选择运算符的特性实现。根据提示:选择运算符的 index 可以为变量,只要变量的位宽和向量的长度匹配即可。

所以我们直接将 sel ,这个变量,作为片选向量 in 的 index。

根据题意,也可以将输入向量 in 右移 sel 位,高位被截去,输出最低位上的 in[sel]。同样,移位的长度也可以使用变量。

Problem 64 : 256-to-1 4-bit multiplexer (Mux256to1v)

牛刀小试

本题中需要实现一个 256 选 1 选择器,sel 信号作为选择信号,当 sel = 0 时选择 in[3:0],sel = 1 时选择 in[7:4],以此类推。同上一题的区别在于,位宽从 1 位变到了 4 位。

解答与分析

module top_module (
	input [1023:0] in,
	input [7:0] sel,
	output [3:0] out
);

	// We can't part-select multiple bits without an error, but we can select one bit at a time,
	// four times, then concatenate them together.
	assign out = {in[sel*4+3], in[sel*4+2], in[sel*4+1], in[sel*4+0]};

	// Alternatively, "indexed vector part select" works better, but has an unfamiliar syntax:
	// assign out = in[sel*4 +: 4];		// Select starting at index "sel*4", then select a total width of 4 bits with increasing (+:) index number.
	// assign out = in[sel*4+3 -: 4];	// Select starting at index "sel*4+3", then select a total width of 4 bits with decreasing (-:) index number.
	// Note: The width (4 in this case) must be constant.

endmodule

本题如果延续上一题的思考方式: assign out = in[ sel*4+3 : sel*4 ]; 但这个表达式不符合 Verilog 片选操作符的语法。片选多个比特的正确语法有两种:

assign out = in[sel*4 +: 4];// 从 sel*4 开始,选择比特序号大于sel*4 的 4 位比特,相当于[sel*4+3:sel*4]
assign out = in[sel*4+3 -: 4];	// 从 sel*4+3 开始,选择比特序号小于 sel*4+3 的 4 位比特,相当于[sel*4+3:sel*4]

当然本身 in[ sel*4+3 : sel*4 ] 这样的语法是不能使用。还有一种思路是将 4 bit 分开选择,再使用位连接符连城宽度为 4 的向量。

其实移位的思路也可以继续使用,只要将 in 右移 4 位,因为高位被截断,仍能够实现题意。但值得注意的是,虽然移位操作符可以使用变量,但不能在移位操作符中对变量进行操作:

assign out = in >> (sel << 2); 这样是不行的,只能通过使用一次中间变量来将 sel 移位。

wire [9:0] sel_shift = sel << 2;

assign out = in >> sel_shift;

结语

至此,多路选择器的题目就结束了。在位宽较小的多路选择器中,我们可以使用 assign 语句,三元表达式,case 语句等。在位宽较宽的多路选择器中,需要根据需求灵活地使用位选择符或者位连接符。

【打个广告】

各位对数字IC和FPGA设计感兴趣的盆友们,我们搭建了一个QQ交流群。经过这一段时间的发展,群聊中已经有将近900个志同道合的同学加入。QQ群里已经整理了许多的资料,其中包含有视频,资料,教程,芯片手册,软件安装包,虚拟机环境。覆盖了从FPGA开发,数字前端,电路设计等等一系列的内容。QQ群号为810689010 ,进群暗号:公众号。欢迎进群交流!

为了能让这个群长期发展下去,用于支付扩建群聊所需的会员费,无奈将这个群设置成付费入群,仅需一元即可,多谢大家支持。

QQ群二维码

期待与您的添加!

‧  END  

长按识别图中二维码关注

欢迎关注微信公众号【数字积木】,更精彩的内容等着你!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值