前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >HDLBits:在线学习Verilog(八 · Problem 35-39)

HDLBits:在线学习Verilog(八 · Problem 35-39)

作者头像
数字积木
发布2021-04-15 11:44:19
5800
发布2021-04-15 11:44:19
举报
文章被收录于专栏:数字积木数字积木

本系列内容来自于知乎专栏,链接如下:https://zhuanlan.zhihu.com/c_1131528588117385216 本系列文章将和读者一起巡礼数字逻辑在线学习网站 HDLBits 的教程与习题,并附上解答和一些作者个人的理解,相信无论是想 7 分钟精通 Verilog,还是对 Verilog 和数电知识查漏补缺的同学,都能从中有所收获。

Problem 35: Always nolatches(Always nolatches)

牛刀小试

假设您再写一个来处理用于游戏PS/2键盘扫描码的电路。给出接收到扫描码的最后的两个字节,您需要判断是否有按键被按下。这是一个相当简单的映射,可以使用case语句或者if-else语句实现,一共有如下四种情况。

所设计的电路有一个16位的输入和4个输出,请您描述此电路,识别这四个按键的扫描码并输出。

同时为避免生成了不必要的锁存器,必须在所有条件下为所有的输出赋值(参见Problem 31: If statement latches(Always if2))。这可能会多打很多字,使你的代码变得冗长。一个简单的方法是在case语句之前为输出分配一个“默认值”:

代码语言:javascript
复制
always @(*) begin
    up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
    case (scancode)
        ... // Set to 1 as necessary.
    endcase
end

除非case语句覆盖赋值,否则这种代码样式可确保在所有可能的情况下输出0。这也意味着case的default项变得不必要。

提醒:always@(*)综合器会生成一个组合电路,其行为与代码描述的相同。硬件不会按顺序“执行”代码。

解答与分析

代码语言:javascript
复制
module top_module (
    input [15:0] scancode,
    output reg left,
    output reg down,
    output reg right,
    output reg up  );

always@(*)
    casez(scancode)
        16'he06b: begin up = 1'b0; down = 1'b0; left = 1'b1; right = 1'b0; end
        16'he072: begin up = 1'b0; down = 1'b1; left = 1'b0; right = 1'b0; end
        16'he074: begin up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b1; end
        16'he075: begin up = 1'b1; down = 1'b0; left = 1'b0; right = 1'b0; end
        default:  begin up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0; end
    endcase

endmodule

按照之前的逻辑写出来的代码应该是这个样子的但是题目中给了小Tips可以少打很多。

代码语言:javascript
复制
module top_module (
    input [15:0] scancode,
    output reg left,
    output reg down,
    output reg right,
    output reg up  );

always@(*)
begin
    up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
    casez(scancode)
        16'he06b: left = 1'b1;
        16'he072: down = 1'b1;
        16'he074: right = 1'b1;
        16'he075: up = 1'b1;
    endcase
end

endmodule

这能完成与上述代码相同的功能,是不是少了很多字符?但是,此时综合器会报一个case语句没有default的warning。上面的写法就不会报这个warning。实际两者综合出来的电路应该是一样的。

Problem 36: Conditional ternary operator(Conditional)

Verilog跟C语言一样有一个三元运算符( ? : )。

代码语言:javascript
复制
condition ? if_true : if_false

这可以在一行代码上实现一个MUX,而不需要在always块中使用if-else语句。

举个栗子:

代码语言:javascript
复制
(0 ? 3 : 5)     // 输出是5,因为条件"0"始终是false的
(sel ? b : a)   // 一个二选一MUX,通过sel的值选择a或者b

always @(posedge clk)         // 一个T触发器
  q <= toggle ? ~q : q;

always @(*)                   // 一输入的状态转换逻辑
    A: next = w ? B : A;
    B: next = w ? A : B;
  endcase

assign out = ena ? q : 1'bz;  // 三态缓冲器

((sel[1:0] == 2'h0) ? a :     // 一个三选一MUX
 (sel[1:0] == 2'h1) ? b :
                      c )

牛刀小试

给出四个无符号数,请找到其中的最小值。无符号数可以使用比较运算符进行比较(a<b)。使用条件运算符描述一个两路的最小值电路,然后组合它来创建一个4路最小电路。可能需要一些wire变量用于表述中间结果。

解答与分析

代码语言:javascript
复制
module top_module (
    input [7:0] a, b, c, d,
    output [7:0] min);//

    wire [7:0] intermediate_result1;
    wire [7:0] intermediate_result2;

    assign intermediate_result1 = a<b? a: b;
    assign intermediate_result2 = c<d? c: d;
    assign min = intermediate_result1<intermediate_result2? intermediate_result1: intermediate_result2;

endmodule

没什么好解释的吧?三个二选一的MUX组成的最小值电路,但电路的具体实现视综合器描述,如果可以使用四选一MUX也可能使用到。

Problem 37: Reduction operators(Reduction)

前面已经讲过两个变量之间的按位运算,例如a&b或a^b。有时候,我们想要构建一个输入比较多的门,对一个向量的所有位进行操作,如(a[0]&a[1]&a[2]&a[3]...),但这对于长的标量来说,这很麻烦。

归约运算符(Reduction Operators)可以对向量的每一位位进行AND,OR和XOR,产生一位输出:

代码语言:javascript
复制
&a [3:0] // AND:a[3]&a[2]&a[1]&a [0]相当于(a[3:0]== 4'hf)
|b [3:0] // OR: b[3]|b[2]|b[1]|b [0]相当于(b[3:0]!= 4'h0)
^c [2:0] // XOR:c[2]^c[1]^c[0]

这些是只有一个操作数的一元运算符(类似于NOT运算符!和~)。也可以将这些本节课的运算符的输出反相以创建NAND,NOR和XNOR门,例如(~&d[7:0])。

牛刀小试

奇偶校验通常用在通过道传输数据时检测错误的简单方法。构建一个电路,计算8位字节输入的校验位(将向该字节添加第9位)。我们将使用偶校验,其中奇偶校验位只是所有8个数据位的XOR。

解答与分析

代码语言:javascript
复制
module top_module (
    input [7:0] in,
    output parity);

    assign parity = ^in;
    
endmodule

答案好说,都告诉了是所有输入的异或。

但是我这里要说的不是答案,而是关于奇偶校验器,数字电路的初学者来说,对教材上给出的奇偶检验器的计算方式可能有些迷惑,什么是奇校验,什么是偶校验。

奇偶校验是检验传输数据中1的个数,当然有奇数有偶数,,这时候就需要用我们的校验位了,通过检验位将传输1的个数变成奇数就是奇校验,变成偶数就是偶校验。比如:

代码语言:javascript
复制
8'b01100100   //原数据
9'b01100100_0 //奇校验
9'b01100100_1 //偶校验

Problem 38: Reduction: Even wider gates(Gates100)

牛刀小试

构建具有100个输入的组合电路。

电路一共有3个输出:

解答与分析

上一个问题已经说过归约运算符了,这道题应该很简单吧~~~

代码语言:javascript
复制
module top_module(
    input [99:0] in,
    output out_and,
    output out_or,
    output out_xor
);
    
    assign out_and = & in;
    assign out_or  = | in;
    assign out_xor = ^ in;

endmodule

Problem 39: Combinational for-loop: Vector reversal2(Vector100r)

牛刀小试

给了一个长度是100的向量,请把它翻转输出一下。

提示:for循环(组合always块或者generate块)在这里很有用。这道题中,因为不需要模块实例化(必须使用generate块),建议使用always块。

解答与分析

提示中已经暗示了使用for循环,就不同多说了吧。在前面的练习中也练习过怎么在always中使用for循环生成组合逻辑。

代码语言:javascript
复制
module top_module(
    input [99:0] in,
    output [99:0] out
);

    always@(*)begin
        for (int i=0;i<=99;i=i+1)begin
            out[i]=in[99-i];
        end
    end
    
endmodule
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-09-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数字积木 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档