牛客网Verilog刷题(1)

简介: 牛客网Verilog刷题(1)

本次带来牛客网Verilog的第一题到第五题,本人才疏学浅,如有不对之处欢迎评论区指正。

VL1 四选一多路器

一个四选一MUX,题目本身没有难度,但是这个题目很坑,做的时候要看清状态转移关系。它提供的波形图是不太完整的。

sel 输出
00 d3
01 d2
10 d1
11 d0

具体的思路就是采用三目运算符,首先判断sel高比特,再判断sel的低比特。三目运算符本身就是一个2选一的MUX。当然这个题也可以用case语句做,那样逻辑更加清晰。

`timescale 1ns/1ns 
module mux4_1( 
input [1:0]d1,d2,d3,d0, 
input [1:0]sel, 
output[1:0]mux_out
 ); 
//*************code***********// 
assign mux_out = sel[1] ? (sel[0] ? d0 : d1) : (sel[0] ? d2 : d3); 
//*************code***********// 
endmodule

VL2 异步复位的串联T触发器

这个题目信号给的是rst,结果波形是低电平复位。大家学习的时候千万不要这么写,低电平复位用rst_n,resetn等都是可以的,用于表示negative。

回到题目本身,T触发器是指当输入为1时,对当前输出取反,否则保持不变。假设不知道这点也没关系,大家仔细观察波形应该可以发现,在第一轮data拉低的时候,q保持不变。而在data拉高以后,连续采集到两个高电平以后拉高,又过了两个时钟周期拉低。然后在第二轮data拉低的时候,q发生变化。这中间一定是什么影响了q的输出。

由于这是串联逻辑,可以思考一下q和data之间的信号temp是如何变化的。由于第一轮data拉低的时候q始终保持不变,因此可假设data拉低的时候T触发器的输出保持不变(而不是为0,思考一下为什么)。当data拉高两个周期以后,q拉高,然后又拉低。因此可以认为在data拉高的时候T触发器输出的值会发生翻转(而不是变为1,思考一下为什么)。将上述推理带入完整的波形,发现符合要求。因此可以实现代码如下:

`timescale 1ns/1ns
module Tff_2 (
input wire data, clk, rst,
output reg q 
);
//*************code***********//
    reg tmp;
    always @(posedge clk, negedge rst) begin
        if(~rst) begin
            q <= 1'b0;
            tmp <= 1'b0;
        end else begin
            tmp <= data^tmp;
            q <= tmp^q;
        end
    end
//*************code***********//

当然最简单的方法还是知道T触发器的原理。关于T触发器,大家心里有个概念即可。实际的数字电路设计中已经没有使用T触发器的了。


VL3 奇偶校验

奇偶校验就是数1的个数!注意:无论是奇校验还是偶校验跟0都没有关系。奇校验就是要使得1的个数为奇数,偶校验就是要保证1的个数为偶数。

基于此,我们首先要判断输入d中的1的个数是奇数还是偶数。如何判断呢?熟悉数字电路的小伙伴应该知道了,使用异或操作符即可。奇数个1互相异或得到的结果是1,而偶数个1互相异或得到的结果是0,而任何数和0异或的结果都是本身。因此对输入d进行异或如果为1,则代表d中1的个数为奇数。

因此当奇校验的时候,如果输入是奇数个1,则补0,反之补1。总而言之是要让1的个数为奇数。对于偶校验也是类似的道理。

回到题目本身,这个出题人题目应该出错了。根据它波形的意思,输入d有奇数个1且sel为1的时候,此时check为1,当输入d有奇数个1且sel为0的时候,此时check为0。d有偶数个1的时候则相反,此时应该叫做奇偶检测而不是奇偶校验。其代码如下。

`timescale 1ns/1ns
module odd_sel(
input [31:0] bus,
input sel,
output check
);
//*************code***********//
    assign check=(^bus)?sel:~sel;
//*************code***********//
endmodule

VL4 移位运算与乘法

对于硬件电路,其乘法本质都是转换成加法和移位来进行运算的。乘以2相当于左移。写代码的时候将乘法运算转换为位运算,是一种比较常见的定点数运算处理方式。这种技巧在C语言中也很常用

对于本题而言,可以看到输入不是每一拍都能采到的。该模块实际上是4个周期一个循环,只有第一个时钟周期才能采到输入进行运算。因此需要一个计数器来协助功能实现(计数器在Verilog设计中非常常见,很多波形,逻辑都能通过计数器凑出来,希望读者好好理解这一点),以下代码合并成一个always块了,实际写的时候最好将计数器单独弄一个always块。

always@(posedge clk or negedge rst) begin
       if(!rst) begin
              cnt <= 0;
              out <= 0;
              input_grant <= 0;
              din <= 0;
       end
       else begin
              cnt <= cnt+1;
              case (cnt)
                     0: begin
                            din <= d;
                            input_grant <= 1;
                            out <= d;
                     end
                     1: begin
                            input_grant <= 0;
                            out <= (din<<2)-din;
                     end       
                     2: begin
                            input_grant <= 0;
                            out <= (din<<3)-din;
                     end
                     3: begin
                            input_grant <= 0;
                            out <= (din<<3);
                     end
              endcase
       end
end

VL5 位拆分与运算

寄存器的各个比特是可以分开单独运算的。其中每一段可能有不同的含义。这就是俗称的字段,在很多情况下一个输入既包括数据又包括地址等信息。

此外根据sel选择四个数据相加结果。换言之四个数据的相加结果都要算出来,通过sel进行选择即可。而多选一对应的是case语句。因此可以很容易的知道代码如下

`timescale 1ns/1ns
module data_cal(
input clk,
input rst,
input [15:0]d,
input [1:0]sel,
output [4:0]out,
output validout
);
//*************code***********//
    reg[15:0] d_in;
    reg[4:0] out;
    reg validout;
    always@(posedge clk or negedge rst) begin
       if (!rst)
              d_in <= 0;
       else if(!sel)
              d_in <= d;
    end
    always @(posedge clk, negedge rst) begin
        if(~rst) begin
            out <= 5'd0;
            validout <= 5'd0;
        end else begin
            case(sel)
                2'b00: begin
                    validout <= 1'b0;
                    out <= 5'd0;
                end
                2'b01: begin
                    validout <= 1'b1;
                    out <= d_in[3:0] + d_in[7:4];
                end
                2'b10: begin
                    validout <= 1'b1;
                    out <= d_in[3:0] + d_in[11:8];
                end
                2'b11: begin
                    validout <= 1'b1;
                    out <= d_in[3:0] + d_in[15:12];
                end
            endcase
        end
    end
//*************code***********//
endmodule
目录
相关文章
|
6月前
|
存储 算法 C语言
C语言刷题~Leetcode与牛客网简单题
C语言刷题~Leetcode与牛客网简单题
|
11月前
牛客网刷题-(7)
牛客网刷题-(7)
37 1
|
11月前
|
算法 C语言
C语言 每日一题 牛客网习题 10.20 day2
C语言 每日一题 牛客网习题 10.20 day2
51 0
|
11月前
牛客网刷题-(8)
牛客网刷题-(8)
41 0
|
芯片
牛客网Verilog刷题(2)
牛客网Verilog刷题(2)
102 0
|
前端开发
牛客网DAY2(编程题)
牛客网DAY2(编程题)
63 0
|
C语言
牛客网C语言刷题(三)
牛客网C语言刷题(三)
382 0
牛客网C语言刷题(三)
|
存储 算法 异构计算
牛客网verilog刷题知识点盘点(75道题的版本)
还有几个坑没填,知识点整理总结自互联网,本人csdn博客搬运
585 0
原来牛客网练习题还能这么做?
原来牛客网练习题还能这么做?
109 0
练习题之牛客网
练习题之牛客网
112 0