Verilog学习之位拆分与运算设计


前言

今天我们做的是第五道题——位拆分与运算,这道题比较简单,我们只需要用到状态机的思想和“+”运算以及数据锁存的问题。接下来就让我们看看如何写这道题。位拆分和运算


一、题目描述

现在输入了一个压缩的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.状态分析

四个状态之间的转换如下:

seloutvalidout
00锁存输入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


总结

以上就是我在做这道题时的思路,以及代码的编写,如果还有更多更好的解法,欢迎读到这篇文章的朋友们在评论区告诉我,共同进步嘛。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个默默无闻的小程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值