前言
今天我们做的是第五道题——位拆分与运算,这道题比较简单,我们只需要用到状态机的思想和“+”运算以及数据锁存的问题。接下来就让我们看看如何写这道题。位拆分和运算
一、题目描述
现在输入了一个压缩的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]
信号示意图
波形示意图
输入描述:
输入信号 d, clk, rst
类型 wire
在testbench中,clk为周期5ns的时钟,rst为低电平复位
输出描述:
输出信号 validout out
类型 reg
二、实现思路
1.题意分析
题中输入的是一个16位的数字,需要我们将其拆分成4个4位的数据并进行组合相加运算。但我们好像没有学过可以拆分数据的运算符,所以我们可以定义一个 reg 型的中间变量 data1 来存储输入变量 d ,因为 reg 型变量是可以一位一位进行单独运算的,并不是一个输入就一定是一个数据,在很多情况下,一个输入既包括数据又包括地址等其他有效信息。
另外我们还需要考虑的是数据锁存问题,根据题意我们知道,只有在sel为0的时候进行锁存,数据的写入才是有效的(validout的下降沿写入有效),同时存在多种情况且没有优先级问题,所以我们使用case语句。
2.状态分析
四个状态之间的转换如下:
sel | out | validout |
---|---|---|
0 | 0锁存输入 | 0 |
1 | [3:0]+[7:4] | 1 |
1 | [3:0]+[11:8] | 1 |
1 | [3:0]+[15:12] | 1 |
三、代码展示
按照我们正常的思路编写出来的代码是这样的,但它会报错(main.v:23: error: out is not a valid l-value in data_cal. main.v:9: : out is declared here as wire.……)其余错误与它类似,就不一 一例举了,他的大致意思就是说赋值符号左右两边的变量数据类型不同,我们可以发现题目中给出的输出都没有规定类型,所以都是默认(wire)类型,但我们却是用 reg 的变量 data1 作为中间变量赋值的,所以我们需要把输出变量 out 和 validout 的类型改为 reg 型。
`timescale 1ns/1ns
module data_cal(
input clk,
input rst,
input [15:0]d,
input [1:0]sel,
output [4:0]out,
output validout
);
reg [15:0]data1;
//位拆分,将输入的每一位存至寄存器类型变量data1中
always @(posedge clk or negedge rst) begin
if(!rst)
data1 <= 0;
else if(sel == 0)
data1 <= d;
end
//运算以及输出部分
always @(posedge clk or negedge rst) begin
if(!rst) begin
out <= 'b0;
validout <= 0;
end
else begin
case(sel)
0: begin
out <= 'b0;
validout <= 0;
end
1: begin
out <= data1[3:0]+data1[7:4];
validout <= 1;
end
2: begin
out <= data1[3:0]+data1[11:8];
validout <= 1;
end
3: begin
out <= data1[3:0]+data1[15:12];
validout <= 1;
end
endcase
end
end
endmodule
更改后的代码如下:
`timescale 1ns/1ns
module data_cal(
input clk,
input rst,
input [15:0]d,
input [1:0]sel,
output reg [4:0]out,
output reg validout
);
reg [15:0]data1;
//位拆分,将输入的每一位存至寄存器类型变量data1中
always @(posedge clk or negedge rst) begin
if(!rst)
data1 <= 0;
else if(sel == 0)
data1 <= d;
end
//运算以及输出部分
always @(posedge clk or negedge rst) begin
if(!rst) begin
out <= 'b0;
validout <= 0;
end
else begin
case(sel)
0: begin
out <= 'b0;
validout <= 0;
end
1: begin
out <= data1[3:0]+data1[7:4];
validout <= 1;
end
2: begin
out <= data1[3:0]+data1[11:8];
validout <= 1;
end
3: begin
out <= data1[3:0]+data1[15:12];
validout <= 1;
end
endcase
end
end
endmodule
总结
以上就是我在做这道题时的思路,以及代码的编写,如果还有更多更好的解法,欢迎读到这篇文章的朋友们在评论区告诉我,共同进步嘛。