👉 写在前面
👉 本系列博客记录牛客网刷题记录
👉 日拱一卒,功不唐捐!
目录
题目描述
已知d为一个8位数,请在每个时钟周期分别输出该数乘1/3/7/8,并输出一个信号通知此时刻输入的d有效(d给出的信号的上升沿表示写入有效)
信号示意图
波形示意图
输入描述
输入信号 | d | clk | rst |
类型 | wire | wire | wire |
在testbench中,clk为周期 5ns 的时钟,rst 为低电平复位
输出描述
输出信号 | input_grant | out |
类型 | reg | reg |
题目分析
从题目的要求和时序上进行分析,复位信号拉高之后,对接收到的数据进行计算输出,依次输出乘1、乘3、乘7、乘8的数值,并且在第一个乘1的输出值同步拉高输出信号 input_grant,同时需要注意的是,在输入数据过于密集的时候,输入的数据是会被忽略的,也可以看到 input_grant 信号是每 4 个时钟周期拉高一次,因此可以申明一个计数器,用于判定输出值 out 和 有效信号 input_grant。
移位运算
Verilog 中移位操作符号有2种,分别是 “<<” 左移位运算符和 “>>” 右移位运算符。
格式如下:a<<n,a>>n。其中,a代表要移位的操作数,n代表要移几位。两种运算方式都用0来填补移出的空位。
移位操作符对左边的操作数进行向左或向右的位移位操作,第二个操作数,移位位数是无符号数,遵循的操作规律是“左移时先补后移,右移时先移后补”。
在进行移位运算时,应当注意移位前后变量的位数。如果操作数已经定义了位宽,则进行移位后操作数改变,但是其位宽不变。
Verilog 代码
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// Author : Linest-5
// File : multi_sel.v
// Create : 2022-10-07 18:59:24
// Revise : 2022-10-07 19:58:16
// Module Name : multi_sel
// Description : 选择乘积数输出
// Editor : sublime text3, tab size (4)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
`timescale 1ns/1ns
module multi_sel(
input [7:0] d ,
input clk,
input rst, //复位,低有效
output reg input_grant,
output reg [10:0] out
);
//*************code***********//
reg [7:0] d_reg;
reg [1:0] cnt;
//循环计数器
always @(posedge clk or negedge rst) begin
if (!rst) begin
cnt <= 'd0;
end
else begin
cnt <= cnt + 'd1;
end
end
//每当合适时间数据来临时将数据寄存
always @(posedge clk or negedge rst) begin
if (!rst) begin
d_reg <= 'd0;
end
else if (cnt == 'd0) begin
d_reg <= d;
end
else begin
d_reg <= d_reg;
end
end
//根据计数值输出相应的数值
always @(posedge clk or negedge rst) begin
if (!rst) begin
out <= 'd0;
end
else if (cnt == 'd0) begin
out <= d; //乘1
end
else if (cnt == 'd1) begin
out <= (d_reg << 2) - d_reg; //乘3
end
else if (cnt == 'd2) begin
out <= (d_reg << 3) - d_reg; //乘7
end
else if (cnt == 'd3) begin
out <= (d_reg << 3); //乘8
end
else begin
out <= out;
end
end
//输出有效数据标志信号
always @(posedge clk or negedge rst) begin
if (!rst) begin
input_grant <= 'd0;
end
else if (cnt == 'd0) begin
input_grant <= 'd1;
end
else begin
input_grant <= 'd0;
end
end
//*************code***********//
endmodule
testbench 代码
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// Author : Linest-5
// File : tb_multi_sel.v
// Create : 2022-10-07 19:58:57
// Revise : 2022-10-07 20:22:50
// Module Name :
// Description :
// Editor : sublime text3, tab size (4)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
`timescale 1ns/1ns
module tb_multi_sel();
reg clk;
reg rst; //复位,低有效
reg [7:0] d;
wire [10:0] out;
wire input_grant;
initial begin
clk = 'd1;
rst <= 'd0;
#50
rst <= 'd1;
end
initial begin
d <= 'd23;
@(posedge rst);
@(posedge clk);
@(posedge clk);
@(posedge clk);
@(posedge clk);
d <= 'd7;
@(posedge clk);
d <= 'd6;
@(posedge clk);
d <= 'd12;
@(posedge clk);
@(posedge clk);
@(posedge clk);
@(posedge clk);
@(posedge clk);
@(posedge clk);
@(posedge clk);
@(posedge clk);
d <= 'd4;
@(posedge clk);
@(posedge clk);
d <= 'd9;
@(posedge clk);
@(posedge clk);
@(posedge clk);
@(posedge clk);
@(posedge clk);
d <= 'd12;
#100
$finish;
end
always #5 clk = ~clk;
multi_sel inst_multi_sel (
.d(d),
.clk(clk),
.rst(rst),
.input_grant(input_grant),
.out(out)
);
//verdi
initial begin
$fsdbDumpfile("tb_multi_sel.fsdb");
$fsdbDumpvars(0);
end
endmodule
仿真结果
电路结构图
仿真波形图
在 testbench 中设计了输入几组数据,其中有些数据会输入的比较密集,仿真波形中也能很直观的看出。