在线学习SystemVerilog:移位寄存器

hdlbits 是一组小型电路设计习题集,使用 verilog/systemverilog 硬件描述语言 (hdl) 练习数字硬件设计~
网址如下:
https://hdlbits.01xz.net/
关于hdlbits的verilog实现可以查看下面专栏:
https://www.zhihu.com/column/c_1131528588117385216
缩略词索引:
sv:systemverilog 从今天开始新的一章-时序电路,包括触发器、计数器、移位寄存器、状态机等。
今天更新移位寄存器,移位寄存器在乘法、除法以及各种矩阵操作中非常重要,熟练使用移位寄存器是基本技能。
移位运算符 虽然移位运算和本系列没什么太大关系,但是还是回顾一下:
problem 106-shift4 题目说明 构建一个 4 位移位寄存器(右移),具有异步复位、同步加载和使能。
areset:将移位寄存器重置为零。 load : 用数据 [3:0]加载移位寄存器而不是移位。 ena:右移(q[3]变为零,q[0]移出并消失)。 q:移位寄存器的内容。 如果load和ena输入均有效 (1),则load输入具有更高的优先级。
模块端口声明 module top_module(    input clk,    input areset,  // async active-high reset to zero    input load,    input ena,    input [3:0] data,    output reg [3:0] q);  题目解析 这是一个基本移位寄存器示例。移位过程在ena控制下,实现q[3]q[2]q[1]q[0] ---> 0 q[3]q[2]q[1]---> 0 0 q[3]q[2]
因为这题增加了很多控制信号,所以只能使用时序电路进行描述。
module top_module(    input logic clk,    input logic areset,  // async active-high reset to zero    input logic load,    input logic ena,    input logic [3:0] data,    output logic [3:0] q );         always_ff@(posedge clk or posedge areset) begin        if(areset)       q <= '0 ;        else if (load)   q <= data ;        else if (ena)    q <= {1'd0,q[3:1]} ;        else             q <= q ;    endendmodule 点击submit,等待一会就能看到下图结果:
注意图中的ref是参考波形,yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红。
这一题就结束了。
problem 107-rotate100 题目说明 设计一个100bit的可左移或右移的移位寄存器,附带同步置位和左移或右移的使能信号。本题中,移位寄存器在左移或右移时,不同于problem106的补0和直接舍弃某一bit位,本题是要求在100bit内循环移动,不舍弃某一位同时也不补0。
比如说左移1bit,在problem106就是补0和丢弃q[0]。而在本题中左移1bit为{q[0], q[99:1]}。
load:load信号将data[99:0] 输入至寄存器内。ena[1:0] 信号选择是否移位和移位的具体方向2'b01 右移一位2'b10 左移一位2'b00 和 2'b11不移动q:移位后寄存器内的数据
模块端口声明 module top_module(    input clk,    input load,    input [1:0] ena,    input [99:0] data,    output reg [99:0] q);  题目解析 本题是一个桶型移位寄存器,题目的解答就是:{q[0], q[99:1]}。
module top_module(    input logic clk,    input logic load,    input logic [1:0] ena,    input logic [99:0] data,    output logic [99:0] q);         always_ff@(posedge clk) begin        if(load)             q <= data ;        else begin            case(ena)                2'b00,2'b11: q <= q ;                2'b01      : q <= {q[0],q[99:1]} ;                2'b10      : q <= {q[98:0],q[99]};            endcase        end    endendmodule 点击submit,等待一会就能看到下图结果:
注意图中无波形。
这一题就结束了。
problem 108-shift18 先补充一下算术移位寄存器和按位移位寄存器:
systemverilog具有按位和算术移位运算符。
按位移位只是将向量的位向右或向左移动指定的次数,移出向量的位丢失。移入的新位是零填充的。例如,操作8’b11000101 << 2将产生值8’b00010100。按位移位将执行相同的操作,无论被移位的值是有符号的还是无符号的。
算术左移位对有符号和无符号表达式执行与按位右移位相同的操作。算术右移位对“无符号”和“有符号”表达式执行不同的运算。如果要移位的表达式是无符号的,算术右移位的行为与按位右移相同,即用零填充输入位。如果表达式是有符号的,则算术右移将通过用符号位的值填充每个输入位来保持值的有符号性。
具体如下:
题目说明 构建一个具有同步加载功能的 64 位算术移位寄存器。移位器可以左右移动,移动 1 位或 8 位,由amount选择。
算术右移将移位寄存器(在本例中为q[63] )中数字的符号位移位,而不是像逻辑右移那样移入零。考虑算术右移的另一种方法是,它假设被移位的数字是带符号的并保留符号,因此算术右移将带符号的数字除以 2 的幂。
逻辑左移和算术左移之间没有区别。
load :用数据 [63:0]加载移位寄存器而不是移位。 ena:选择是否移动。 amount:选择移动的方向和移动量。 2'b00:左移一位。
2'b01:左移 8 位。
2'b10:右移一位。
2'b11:右移 8 位。
q:移位器的内容。 模块端口声明 module top_module(    input clk,    input load,    input ena,    input [1:0] amount,    input [63:0] data,    output reg [63:0] q);  题目解析 module top_module(    input logic clk,    input logic load,    input logic ena,    input logic [1:0] amount,    input logic [63:0] data,    output logic [63:0] q);         always_ff@(posedge clk) begin        if(load)           q <= data ;        else if(ena)        begin            case(amount)                2'b00:     q <= {q[62:0],1'd0} ;                2'b01:     q <= {q[55:0],8'd0} ;                2'b10:     q <= {q[63],q[63:1]};                2'b11:     q <= {{8{q[63]}},q[63:8]};            endcase        end    endendmodule 点击submit,等待一会就能看到下图结果:
注意图中的ref是参考波形,yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红。
这一题就结束了。
problem 109-lfsr5 题目说明 线性反馈移位寄存器(lfsr)是一种移位寄存器,通常带有几个异或门(xor)来产生移位寄存器的下一个状态。galois lfsr 是一种特殊的排列方式,其中带有“抽头(tap)”的位位置与输出位进行异或以产生其下一个值,而没有抽头移位的位位置。如果仔细选择抽头位置,则可以将 lfsr 设为“最大长度”。n 位的最大长度 lfsr 在重复之前循环通过 2^n -1 个状态(永远不会达到全零状态)。
下图显示了一个 5 位最大长度的 galois lfsr,在位置 5 和 3 处有抽头。(抽头位置通常从 1 开始编号)。请注意,为了保持一致性,我在位置 5 处绘制了 xor 门,但其中一个 xor 门输入为 0。
图片来自hdlbits 构建这个 lfsr。复位将 lfsr 重置为 1 。
模块端口声明 module top_module(    input clk,    input reset,    // active-high synchronous reset to 5'h1    output [4:0] q); 题目解析 module top_module(    input logic clk,    input logic reset,    // active-high synchronous reset to 5'h1    output logic [4:0] q);     always_ff@(posedge clk) begin        if(reset)         q <= 5'h1 ;        else begin        q[4] <= 1'd0 ^ q[0] ;        q[3] <= q[4];        q[2] <= q[3] ^ q[0] ;        q[1] <= q[2] ;        q[0] <= q[1] ;        end    end        endmodule 点击submit,等待一会就能看到下图结果:
注意图中的ref是参考波形,yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红。
这一题就结束了。
problem 110-mt2015_lfsr 题目说明 图片来自hdlbits 编写此时序电路的 verilog 代码(可以使用子模块进行构建,但顶层要命名为 top_module)。
模块端口声明 module top_module ( input [2:0] sw,      // r input [1:0] key,     // l and clk output [2:0] ledr);  // q 题目解析 本题的解答思路是将三个触发器的输出端 q,输入端 d,组合成一个 3bit 宽度的向量进行设计,使用一个 always 块实现寄存器组。与之相对的是思路是例化三个选择器+触发器的电路,分别连接三个部分的输入输出。
根据选择器的 select 端的电平,触发器组的输入分别为外部输入 sw 或者触发器组输出序列的组合逻辑,这里用:{ledr[1]^ledr[2],ledr[0],ledr[2]} 表示。
其他信号根据题目的要求连接。
module top_module ( input [2:0] sw,      // r input [1:0] key,     // l and clk output [2:0] ledr);  // q        reg [2:0] ledr_next;        always_comb begin     if(key)         ledr_next = sw;        else begin         ledr_next[0] = ledr[2];      ledr_next[1] = ledr[0];      ledr_next[2] = ledr[2] ^ ledr[1];        end    end        always_ff@(posedge key[0]) begin        ledr <= ledr_next;    end    endmodule 点击submit,等待一会就能看到下图结果:
注意图中无波形。
这一题就结束了。
problem 111-lfsr32 题目说明 参考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 [31:0] q);   题目解析 module top_module(    input clk,    input reset,    // active-high synchronous reset to 32'h1    output [31:0] q);         reg [31:0] q_next;    always_comb begin        q_next = {q[0], q[31:1]};        q_next[21] = q[0] ^ q[22];        q_next[1] = q[0] ^ q[2];        q_next[0] = q[0] ^ q[1];    end        always_ff@(posedge clk)begin        if(reset)            q <= 32'h1;        else begin            q <= q_next;        end    end endmodule 点击submit,等待一会就能看到下图结果:
注意图中无波形。
这一题就结束了。
problem 112-m2014_q4k 题目说明 实现下图中的电路
图片来自hdlbits 模块端口声明 module top_module (    input clk,    input resetn,   // synchronous reset    input in,    output out); 题目解析 实现一个带有异步复位的移位寄存器。
module top_module (    input logic clk,    input logic resetn,   // synchronous reset    input logic in,    output logic out);        var logic [3:0] q ;        always_ff@(posedge clk) begin        if(!resetn)     q <= '0 ;        else            q <= {in,q[3:1]} ;    end        assign out = q[0] ;endmodule 点击submit,等待一会就能看到下图结果:
注意图中无波形。
这一题就结束了。
problem 113-2014_q4b 题目说明 实现下图中的 n bit 移位寄存器电路,这题希望使用例化的方式,例化 4 个选择器+触发器模块实现一个 4bit 移位寄存器。另外还要进行一些连线工作。
图片来自hdlbits 模块端口声明 module top_module (    input [3:0] sw,    input [3:0] key,    output [3:0] ledr);  题目解析 muxdft 模块之前已经实现了,复制过来即可,剩下的就是例化。
module top_module (    input logic [3:0] sw,    input logic [3:0] key,    output logic [3:0] ledr); //    muxdff u1_muxdff(        .clk    (key[0] ),               .w  (key[3] ),        .r  (sw[3] ),        .e  (key[1] ),        .l  (key[2] ),        .q  (ledr[3])    );    muxdff u2_muxdff(        .clk (key[0] ),        .w  (ledr[3]),        .r  (sw[2] ),        .e  (key[1] ),        .l  (key[2] ),        .q  (ledr[2])    );    muxdff u3_muxdff(        .clk (key[0] ),        .w  (ledr[2]),        .r  (sw[1] ),        .e  (key[1] ),        .l  (key[2] ),        .q  (ledr[1])    );    muxdff u4_muxdff(        .clk (key[0] ),        .w  (ledr[1]),        .r  (sw[0] ),        .e  (key[1] ),        .l  (key[2] ),        .q  (ledr[0])    );                           endmodulemodule muxdff (    input logic clk,    input logic w, r, e, l,    output logic q);    always_ff@(posedge clk) begin        casex({e,l})            2'b00: q <= q ;            2'bx1: q <= r ;            2'b10: q <= w ;        endcase    endendmodule 点击submit,等待一会就能看到下图结果:
注意图中无波形。
这一题就结束了。
problem 114-ece241_2013_q12 题目说明 本题中实现的是一个和 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 z );  题目解析 module top_module (    input logic clk,    input logic enable,    input logic s,    input logic a, b, c,    output logic z );         var logic [7:0] q ;        always_ff@(posedge clk) begin        if(enable)  q <= {q[6:0],s} ;    end        always_comb begin        case({a, b, c})            3'b000:begin                z = q[0];            end            3'b001:begin                z = q[1];            end            3'b010:begin                z = q[2];            end            3'b011:begin                z = q[3];            end            3'b100:begin                z = q[4];            end            3'b101:begin                z = q[5];            end            3'b110:begin                z = q[6];            end            3'b111:begin                z = q[7];            end        endcase    endendmodule 点击submit,等待一会就能看到下图结果:
注意图中的ref是参考波形,yours是你的代码生成的波形,网站会对比这两个波形,一旦这两者不匹配,仿真结果会变红。
这一题就结束了。
总结 今天的几道题就结束了,对于移位寄存器的使用以及算术/按位移位的理解还是有益处的。
最后我这边做题的代码也是个人理解使用,有错误欢迎大家批评指正,祝大家学习愉快~
代码链接:
https://github.com/suisuisi/systemverilog/tree/main/systemveriloghdlbits


无缘骁龙660,vivoX9s单页已泄露 参数真机全曝光
狗尾草严汉明:智能家居的AI痛点与语音解决方案落地项目
小米max2什么时候上市?小米max2最新消息:小米max2提前发布,大屏爱好者福音,1499你买不买?
基于Multism的滤波电路仿真分析
使用Node-RED和Raspberry Pi实现按下按钮即可发布天气信息
在线学习SystemVerilog:移位寄存器
PyTorch教程-12.1. 优化和深度学习
超六类与六类网线相比超在哪些方面
脑机接口最新科研进展,以“半侵入性”方式植入大脑!
java中static和final的初始化
现代化机器学习工具,有助于数据科学开展更多工程功能
DCDC电源芯片 MT3540-F25 1.5A,最高可达28V输出1.2MHz升压转换器 西安航天民芯
C语言和其他高级语言的区别
关于SCA涂胶定量机的填充超时的几种论述
从工程师角度分析苹果手机电死人的可能性
环保数采仪如何将数据传输到云平台
赛灵思Zynq-7000 All Programmable SoC实现1GHz处理能力
AMS:天线主动放大器技术助推移动支付时代到来
直角减速电机的刹车整流器是什么
三箱式恒温恒湿试验箱的特点