写在前面
本系列博客记录牛客网刷题记录
日拱一卒,功不唐捐!
目录
VL5 位拆分与运算
题目描述
信号示意图
波形示意图
输入描述
输出描述
题目分析
RTL 设计
testbench 设计
仿真测试
VL6 多功能数据处理器
题目描述
接口信号图
题目分析
RTL 设计
testbench 设计
仿真测试
VL7 求两个数的差值
题目描述
输入描述
输出描述
RTL 设计
testbench 设计
仿真测试
现在输入了一个压缩的16位数据,其实际上包含了四个数据[3:0][7:4][11:8][15:12],
现在请按照sel选择输出四个数据的相加结果,并输出valid_out信号(在不输出时候拉低)
0: 不输出且只有此时的输入有效
1:输出[3:0]+[7:4]
2:输出[3:0]+[11:8]
3:输出[3:0]+[15:12]
输入信号 | clk | rst | d |
类型 | wire | wire | wire |
在testbench中,clk为周期5ns的时钟,rst为低电平复位
输出信号 | validout | out |
类型 | reg | reg |
由输入的数据,根据 sel 的值输出相应的计算值,很明显就是一个选择器的选择结果,一般可以用两种方式:if 语句或者 case 语句,我使用 case 解决。并且需要注意的是,由于计算结果和输入的sel值是同步的,因为需要用组合逻辑,时序逻辑会延时一拍,不符合要求。
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// Author : Linest-5
// File : data_cal.v
// Create : 2022-10-07 21:48:59
// Revise : 2022-10-07 22:15:07
// Module Name : data_cal
// Description : 位拆分与运算
// Editor : sublime text3, tab size (4)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
`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_reg;
reg [4:0] out_reg;
reg validout_reg;
always @(*) begin
if (!rst) begin
d_reg = 'd0;
out_reg = 'd0;
validout_reg = 'd0;
end
else begin
case(sel)
2'd0: begin
d_reg = d;
out_reg = 'd0;
validout_reg = 'd0;
end
2'd1: begin
d_reg = d_reg;
out_reg = d_reg[3:0] + d_reg[7:4];
validout_reg = 'd1;
end
2'd2: begin
d_reg = d_reg;
out_reg = d_reg[3:0] + d_reg[11:8];
validout_reg = 'd1;
end
2'd3: begin
d_reg = d_reg;
out_reg = d_reg[3:0] + d_reg[15:12];
validout_reg = 'd1;
end
default: begin
d_reg = d_reg;
out_reg = out_reg;
validout_reg = 'd0;
end
endcase
end
end
//结果赋值
assign out = out_reg;
assign validout = validout_reg;
//*************code***********//
endmodule
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// Author : Linest-5
// File : tb_data_cal.v
// Create : 2022-10-07 22:12:35
// Revise : 2022-10-07 22:28:38
// Module Name :
// Description :
// Editor : sublime text3, tab size (4)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
`timescale 1ns/1ns
module tb_data_cal();
reg clk;
reg rst; //复位低有效
reg [15:0] d;
reg [1:0] sel;
wire [4:0] out;
wire validout;
initial begin
clk = 'd1;
rst <= 'd0;
#20
rst <= 'd1;
end
initial begin
d <= 'd0;
sel <= 'd0;
@(posedge rst);
@(posedge clk);
d <= 16'h8765;
@(posedge clk);
sel <= 'd1;
@(posedge clk);
@(posedge clk);
@(posedge clk);
d <= 16'h1234;
sel <= 'd2;
@(posedge clk);
@(posedge clk);
@(posedge clk);
sel <= 'd0;
@(posedge clk);
sel <= 'd3;
@(posedge clk);
@(posedge clk);
d <= 16'h2486;
@(posedge clk);
@(posedge clk);
@(posedge clk);
sel <= 'd0;
@(posedge clk);
sel <= 'd1;
@(posedge clk);
sel <= 'd0;
@(posedge clk);
sel <= 'd2;
@(posedge clk);
sel <= 'd0;
@(posedge clk);
sel <= 'd3;
#20
$finish;
end
always #5 clk = ~clk;
data_cal inst_data_cal (
.clk(clk),
.rst(rst),
.d(d),
.sel(sel),
.out(out),
.validout(validout)
);
//verdi
initial begin
$fsdbDumpfile("tb_data_cal.fsdb");
$fsdbDumpvars(0);
end
endmodule
可以看到输出结果是根据输入的数据和 sel 得到相应的计算值。
根据指示信号select的不同,对输入信号a,b实现不同的运算。输入信号a,b为8bit有符号数,当select信号为0,输出a;当select信号为1,输出b;当select信号为2,输出a+b;当select信号为3,输出a-b.
使用Verilog HDL实现以上功能并编写testbench验证。
输入描述
clk:系统时钟
rst_n:复位信号,低电平有效
a,b:8bit 位宽的有符号数
select:2bit 位宽的无符号数
输出描述
c:9bit位宽的有符号数
和上一题很类似,由输入的两个位宽为 8 的有符号数,根据 select 信号的值执行相应的操作,并输出计算结果。这里依然采用 case 语句并采用时序逻辑。
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// Author : Linest-5
// File : data_select.v
// Create : 2022-10-12 21:17:41
// Revise : 2022-10-12 21:21:41
// Module Name :
// Description :
// Editor : sublime text3, tab size (4)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
`timescale 1ns/1ns
module data_select(
input clk,
input rst_n,
input signed [7:0] a,
input signed [7:0] b,
input [1:0] select,
output reg signed [8:0] c
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
c <= 'd0;
end
else begin
case (select)
2'd0: begin
c <= a;
end
2'd1: begin
c <= b;
end
2'd2: begin
c <= a + b;
end
2'd3: begin
c <= a - b;
end
default: begin
c <= 'd0;
end
endcase
end
end
endmodule
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// Author : Linest-5
// File : tb_data_select.v
// Create : 2022-10-12 21:27:46
// Revise : 2022-10-20 21:35:40
// Module Name :
// Description :
// Editor : sublime text3, tab size (4)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
`timescale 1ns/1ns
module tb_data_select();
reg clk;
reg rst_n;
reg signed [7:0] a,b;
reg [1:0] select;
wire signed [8:0] c;
initial begin
clk = 1'd1;
rst_n <= 1'd0;
a <= 8'b10110011;
b <= 8'b00111000;
#10
rst_n <= 1'd1;
#200
$finish;
end
always #5 clk = ~clk;
always #5 select <= {$random}%4;
data_select dut_inst(
.clk (clk),
.rst_n (rst_n),
.a (a),
.b (b),
.select(select),
.c (c)
);
//verdi
initial begin
$fsdbDumpfile("tb_data_select.fsdb");
$fsdbDumpvars(0);
end
endmodule
仿真结果显示正确!
根据输入信号a,b的大小关系,求解两个数的差值:输入信号a,b为8bit位宽的无符号数。如果a>b,则输出a-b,如果a≤b,则输出b-a。接口信号图如下:
使用Verilog HDL实现以上功能并编写testbench验证。
clk:系统时钟
rst_n:复位信号,低电平有效
a,b:8bit 位宽的无符号数
c:8bit 位宽的无符号数
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// Author : Linest-5
// File : data_minus.v
// Create : 2022-10-19 20:29:34
// Revise : 2022-10-20 21:29:08
// Module Name :
// Description :
// Editor : sublime text3, tab size (4)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
`timescale 1ns/1ns
module data_minus(
input clk,
input rst_n,
input [7:0] a,
input [7:0] b,
output reg [7:0] c
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
c <= 9'd0;
end
else if (a > b) begin
c <= a - b;
end
else begin
c <= b - a;
end
end
endmodule
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// Author : Linest-5
// File : tb_data_minus.v
// Create : 2022-10-19 20:35:47
// Revise : 2022-10-20 21:33:12
// Module Name :
// Description :
// Editor : sublime text3, tab size (4)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
`timescale 1ns/1ns
module tb_data_minus();
reg clk;
reg rst_n;
reg [7:0] a;
reg [7:0] b;
wire [7:0] c;
initial begin
clk = 'd1;
rst_n <= 'd0;
#20
rst_n <= 'd1;
#100
$finish;
end
always #5 clk = ~clk;
always #5 a <= {$random} % 9'd256;
always #5 b <= {$random} % 9'd256;
data_minus inst_data_minus (
.clk(clk),
.rst_n(rst_n),
.a(a),
.b(b),
.c(c)
);
//verdi
initial begin
$fsdbDumpfile("tb_data_minus.fsdb");
$fsdbDumpvars(0);
end
endmodule
从仿真图可以看到,根据输入的a、b数据,在延一拍出结果。