题目描述:
已知d为一个8位数,请在每个时钟周期分别输出该数乘1/3/7/8,并输出一个信号通知此时刻输入的d有效(d给出的信号的上升沿表示写入有效)
信号示意图:
波形示意图:
输入描述:
输入信号 d, clk, rst
类型 wire
在testbench中,clk为周期5ns的时钟,rst为低电平复位
输出描述:
输出信号 input_grant out
类型 reg
解题分析:
在硬件中进行乘除法运算是比较消耗资源的一种方法,想要在不影响延迟并尽量减少资源消耗,必须从硬件的特点上进行设计。根据寄存器的原理,由于是二进制,所以进位和退位为x2或者/2,同样除7可以使用进位3然后减去本身的做法,这样就将乘除法运算转化为位运算,这是一种比较简单的整数运算处理。
需要给出一个计数器的状态机,注意d输入不是随时有效的,只有在cnt计数为0的那个时钟沿,d输入有效,因此需要设计一个寄存器din,在cnt为0时候锁存d的值。
代码如下:
- `timescale 1ns/1ns
- module vl4 (
- input [7:0]d ,
- input clk,
- input rst,
- output reg input_grant,
- output reg [10:0]out
- );
- //*************code***********//
- reg [1:0] cnt;
- reg [7:0] reg_d;
- //*******计数器初始化及赋值*******//
- always@(posedge clk or negedge rst)
- if(rst == 1'b0)
- cnt <= 2'd0;
- else if(cnt == 2'd3)
- cnt <= 2'd0;
- else
- cnt <= cnt + 1'b1;
- //***数据寄存器(reg_d)和输入有效标志(input_grant)初始化及赋值***//
- always@(posedge clk or negedge rst)
- if(rst == 1'b0)begin
- reg_d <= 8'd0;
- input_grant <= 1'b0;
- end
- else if(cnt == 2'd0)begin
- reg_d <= d;
- input_grant <= 1'b1;
- end
- else begin
- reg_d <= reg_d;
- input_grant <= 1'b0;
- end
- //****乘法运算****//
- always@(posedge clk or negedge rst)
- if(rst == 1'b0)
- out <= 11'd0;
- else case (cnt)
- 2'd0 : out <= d;
- 2'd1 : out <= (reg_d<<2)-reg_d;
- 2'd2 : out <= (reg_d<<3)-reg_d;
- 2'd3 : out <= (reg_d<<3);
- default : out <= 11'd0;
- endcase
- //*************code***********//
- endmodule
测试代码:
- `timescale 1ns/1ns
- module tb_vl4();
- reg clk;
- reg rst;
- reg [7:0] d;
-
- wire input_grant;
- wire [10:0] out;
- //***时钟,复位,d信号赋值***//
- initial
- begin
- clk = 1'b0;
- rst = 1'b0;
- d = 8'd0;
- #30
- rst = 1'b1;
- d = 8'd8;
- #80
- d = 8'd9;
- #80
- d = 8'd10;
- end
- //***生成时钟信号***//
- always #10 clk =~clk;
- //***模块实例化***//
- vl4 vl4_inst
- (
- .d (d) ,
- .clk (clk) ,
- .rst (rst) ,
- .input_grant(input_grant) ,
- .out (out)
- );
-
- endmodule
波形图: