HDLBits:在线学习 Verilog (二十三 · Problem 110-114)

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

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

Problem 110 3-bit LFSR

牛刀小试

相比于上一题 5-bit 线性移位寄存器,本题原理上相同,但作者希望我们结合实际的板子(DE1-SoC,可能是一个教学板)和其外部接口(KEY&LED),实现一个线性移位寄存器电路。

使用 Verilog 实现上图中的时序电路,(可以使用子模块进行构建,但顶层要命名为 top_module)。假设你要在 DE1-SoC 教学板上实现这个电路,将输入端口 r 连接到板子上的拨动开关,clock 端口接到按键 KEY[0],端口 L 接到按键 KEY[1]。输出端口 Q 连接到板子上的红色 LED。

解答与分析

module top_module (
	input [2:0] SW,      // R
	input [1:0] KEY,     // L and clk
	output reg [2:0] LEDR);  // Q

    wire clk = KEY[0];
    wire l = KEY[1];
    wire [2:0] d = l?SW:{LEDR[1]^LEDR[2],LEDR[0],LEDR[2]};
    
    always @(posedge clk)begin
            LEDR	<=	d;
    end

endmodule

本题的解答思路是将三个触发器的输出端 Q,输入端 D,组合成一个 3bit 宽度的向量进行设计,使用一个 always 块实现寄存器组。与之相对的是思路是例化三个选择器+触发器的电路,分别连接三个部分的输入输出。

根据选择器的 select 端的电平,触发器组的输入分别为外部输入 SW 或者触发器组输出序列的组合逻辑,这里用:{LEDR[1]^LEDR[2],LEDR[0],LEDR[2]} 表示。

其他信号根据题目的要求连接。

Problem 111 32-bit LFSR

牛刀小试

参考109题中的 5bit LFSR,实现一个 32bit LFSR,

抽头点为32,22,2,1。

提示:32bit 的 LFSR 最好使用向量实现,而不是例化 32 个触发器。

解答与分析

module top_module(
    input clk,
    input reset,    // Active-high synchronous reset to 32'h1
    output reg [31:0] q
);

    always@(posedge clk)begin
        if(reset)
            q	<=	32'h1;
        else begin
            q	<=	{q[0],q[31-:9],q[22]^q[0],q[21:3],q[2]^q[0],q[1]^q[0]};
        end
    end
endmodule

因为 problem 109 来自 我的同伴

@木帅宇

 同学,思路和我并不完全相同,所以这里我们先分析一下这道先导题。

首先要理解什么是抽头点(tap),注意到图中有两个触发器的输入为前级输出与q[0]的异或,这些位置被称为 tap position,本题的抽头点为 5,3.通过观察上图,所谓抽头点指的就是第5个,第3个寄存器的输入经过了异或逻辑。

那么回到本题就是第 32,22,2,1 个寄存器的输入经过异或逻辑,也可以推断出这些寄存器的跳变逻辑。

  • q[21] <= q[22]^q[0]

  • q[1] <= q[2]^q[0]

  • q[0] <= q[1]^q[0]

q[31]则比较特殊,其为输入端,异或门的一端固定为低电平,所以相当于输入q[0]本身。

我们在完成具体代码时,可以先实现一个普通的循环右移寄存器。寄存器组的输出向量为输入向量向右移位一位,最低位循环移位至最高位。

q <= {q[0],q[31:1]};

然后将其中有异或逻辑参与的比特替换即可

q <= {q[0],q[31-:9],q[22]^q[0],q[21:3],q[2]^q[0],q[1]^q[0]};

q[31-:9] 这个语法表示从 q[31] 开始的 9 个 bit 。

Problem 112 Shift Register(Exams/m2014 q4k)

牛刀小试

实现下图中的电路

解答与分析

module top_module (
    input clk,
    input resetn,   // synchronous reset
    input in,
    output reg out);
	reg q0,q1,q2;
    
    always@(posedge clk)begin
        if(~resetn)begin
            q0	<=	1'b0;
            q1	<=	1'b0;
            q2	<=	1'b0;
            out	<=	1'b0;
        end else begin
            q0	<=	in;
            q1	<=	q0;
            q2	<=	q1;
            out	<=	q2;
        end
    end
endmodule

本题比较简单,实现一个带有异步复位的移位寄存器,你最少能用多少行代码实现呢?

Problem 113 Shift Register(Exams/m2014 q4b)

牛刀小试

实现下图中的 n bit 移位寄存器电路,这题希望使用例化的方式,例化 4 个选择器+触发器模块实现一个 4bit 移位寄存器。另外还要进行一些连线工作。

解答与分析

module top_module (
    input [3:0] SW,
    input [3:0] KEY,
    output [3:0] LEDR
); //
    
    wire [3:0] w_input = {KEY[3],LEDR[3],LEDR[2],LEDR[1]};
    generate 
        genvar i;
        for(i=0;i<4;i=i+1) begin:muxdff
            MUXDFF (
        	.clk(KEY[0]),
                .w(w_input[i]),
                .R(SW[i]),
        	.E(KEY[1]),
        	.L(KEY[2]),
                .Q(LEDR[i])
    		);
        end
    endgenerate
endmodule


module MUXDFF (
    input clk,
    input w, R, E, L,
    output  Q
);
    reg Q_r;
    wire d_in = (L)?
    			R:
    			(E)?
    			w:
    			Q_r;
	always@(posedge clk)begin
    	Q_r <= d_in;
    end
    
    assign Q = Q_r;
endmodule

本题中使用的 MUXDFT 模块实际上已经在之前的题目中完成:

Exams/2014 q4a - HDLBits hdlbits.01xz.net

使用 generate 语法例化四个 MUXDFT 模块,通过使用 generate 语法,实际上想例化多少个例化多少个,修改 i 的上限即可,但输入向量 w_input 还是需要手动构建。

Problem 114 Shift Register(Exams/m2014 q4k)

牛刀小试

本题中实现的是一个和 8x1 结构的存储体相关的电路。存储的输入通过移入比特进行,存储的读取类似于传统 RAM 中的随机读取,即可以指定读出比特的位置,通过 3 个输入端口指定读取位置。

首先通过 8 个触发器实现一个 8bit 深的移位寄存器。8个寄存器的输出依次为 Q[0]...Q[7]。移位寄存器的输入为 S,输入首先会填充到 MSB(最高位),Q[0]。当 enable 信号控制移位,当其有效时输入数据并移位。此外,该电路有三个输入端口 A,B,C 以及输出端口 Z。工作的功能如下:当 ABC = 000 时,Z = Q[0],当 ABC = 001 时,Z = Q[1],以此类推。你的电路中只能包括一个 8bit 移位寄存器以及一个多路选择器。(这就是个三输入查找表 LUT 电路)

解答与分析

module top_module (
    input clk,
    input enable,
    input S,
    input A, B, C,
    output reg Z );

    reg[7:0] shift_reg;
    always@(posedge clk)begin
        if(enable)begin
            shift_reg	<=	{S,shift_reg[7:1]};
        end
    end
    
    wire[2:0] output_index = {A,B,C};
    always@(*) begin
        case(output_index)
            3'd0:Z=shift_reg[7];
            3'd1:Z=shift_reg[6];
            3'd2:Z=shift_reg[5];
            3'd3:Z=shift_reg[4];
            3'd4:Z=shift_reg[3];
            3'd5:Z=shift_reg[2];
            3'd6:Z=shift_reg[1];
            3'd7:Z=shift_reg[0];
            endcase
    end
endmodule

首先实现移位寄存器,当 enable 信号有效时,寄存器将输入右移。其实本题中右移和左移都可以。右移相当于 shift_reg[7] 为最高位,在输出时和题目的定义有些不同,ABC = 0 时,Z=shift_reg[7]。如果左移,shift_reg[0] 为最高位,此时输出比特位的顺序和 ABC 的值相同。

接下来根据输入信号 ABC,产生输出信号 Z。这里用组合逻辑的形式,用 case 语法实现,比较直观但繁琐,这里作者在 solution 中提供了简便的方法:

assign Z = q[{A,B,C}];

在 assign 中,这样的语法是支持的,学到了。

【QQ交流群】

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

QQ群二维码

期待与您的添加!

‧  END  

长按识别图中二维码关注

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值