:::info 【分析】
- 根据要求,在sel = 0的时候输入才是有效的,其他时刻的输入是没用的,因此必须声明一个reg类型来对输入进行暂存(与移位运算和乘法题目相同);
- 位分割;
:::
1. Verilog代码实现
``verilog
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@(posedge clk or negedge rst) begin if(!rst) begin out_reg <= 5’b0; validout_reg <= 1’b0; end else begin case(sel)
endcase end end assign validout = validout_reg; assign out = out_reg; //**code*// endmodule // Method2 reg [15:0] d_reg; wire [3:0] d0; wire [3:0] d1; wire [3:0] d2; wire [3:0] d3; assign d0 = d_reg[3:0]; assign d1 = d_reg[7:4]; assign d2 = d_reg[11:8]; assign d3 = d_reg[15:12]; reg [4:0] out_reg; //**code*// endmodule2'b00 : begin
validout_reg <= 1'b0;
d_reg <= d;
out_reg <= 5'b0;
end
2'b01 : begin
validout_reg <= 1'b1;
out_reg <= d_reg[3:0] + d_reg[7:4];
end
2'b10 : begin
validout_reg <= 1'b1;
out_reg <= d_reg[3:0] + d_reg[11:8];
end
2'b11 : begin
validout_reg <= 1'b1;
out_reg <= d_reg[3:0] + d_reg[15:12];
end
default : begin
validout_reg <= 1'b0;
out_reg <= 5'b0;
end
![image.png](https://cdn.nlark.com/yuque/0/2022/png/22348254/1655277874651-b31fbd09-635b-4452-8308-1af949934459.png#clientId=u82c5e2b5-7e45-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=376&id=uccc8482c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=470&originWidth=1271&originalType=binary&ratio=1&rotation=0&showTitle=false&size=25190&status=done&style=none&taskId=uba2f744a-a35a-4ccf-b3e5-c612120378a&title=&width=1016.8)
> 过程中遇到的问题:
> 1. 复位的时候是只对output信号进行复位;
> 1. always块中必须使用reg类型,因此必须声明reg类型的变量来进行存放并在之后使用assign连接;
> 1. 使用第二种方法对寄存器提前进行位拆分,在以后的大型逻辑电路中可以更方便对照。
<a name="yUE7Z"></a>
# 2. Testbench自测模式
:::info
`timescale 1ns/1ns:<br />前面的1ns指的是时间的间隔:比如 #5就是5ns;<br />后面的1ns指的是时间的精度,设置的越小仿真就越慢。
:::
```verilog
`timescale 1ns/1ns
module data_cal_tb;
bit clk;
bit rst;
reg [15:0] d;
reg [1:0] sel;
wire [4:0] out;
wire validout;
data_cal dut(
.clk(clk),
.rst(rst),
.d(d),
.sel(sel),
.out(out),
.validout(validout)
);
initial begin : gen_clk
forever #5 clk <= !clk;
end
initial begin
clk = 0;
rst = 0;
d = 16'd0;
sel = 2'b00;
#30;
rst = 1;
sel = 2'b00;
d = 16'b1000_0100_0010_0001;
#10;
sel = 2'b01;
d = 16'b1111_1111_1111_1111;
#10;
sel = 2'b10;
d = 16'b1000_0000_0000_0000;
#10;
sel = 2'b11;
d = 16'b1000_0000_0000_0000;
#10;
sel = 2'b00;
d = 16'b1000_0100_0010_0001;
#30;
$finish();
end
endmodule
将data_cal.v和tb.sv文件放在Questasim中编译并仿真,观察tb中信号的波形,结果如上:
- 在SEL为0的时候输入有效,输入的值是十六进制的8421并保存在寄存器中;
- 在SEL为1的时候输出低8位相加,相加以后的结果就是3。
在写tb的时候需要注意:
- 功能方面需要和设计文件保持一致,从复位以后的值开始。
- 在rst拉高以后其他信号有效,此时观察序列运算后的结果。