一、题目描述
已知d为一个8位数,请在每个时钟周期分别输出该数乘1/3/7/8,并输出一个信号通知此时刻输入的d有效(d给出的信号的上升沿表示写入有效)
信号示意图:
波形示意图:
输入描述:
输入信号 d, clk, rst; 类型 wire
在testbench中,clk为周期5ns的时钟,rst为低电平复位
输出描述:
输出信号 input_grant out; 类型 reg
二、实现思路
首先由题意可知为时序逻辑且为异步复位
always @ (posedge clk or negedge rst) begin
if (~rst) begin
out<=11'b0;
input_grant<=1'b0;
end
else begin
//*************code***********//
//*************code***********//
end
end
其次,每个时钟周期分别输出该数乘1/3/7/8 (四个状态)
且该数乘1时,input_grant为1
FSM 有限状态机思想可得
reg [1:0] count; //2位有0 1 2 3 四种状态
always @ (posedge clk or negedge rst) begin
if (~rst) begin
count<=2'b0;
end
else begin
count<=count+1'b1;
end
end
三、代码展示
`timescale 1ns/1ns
module multi_sel(
input [7:0]d ,
input clk,
input rst,
output reg input_grant,
output reg [10:0]out
);
//*************code***********//
reg [1:0] count;
always @ (posedge clk or negedge rst) begin
if (~rst) begin
count<=2'b0;
end
else begin
count<=count+1'b1;
end
end
reg [7:0] d_temp;
always @ (posedge clk or negedge rst) begin
if (~rst) begin
out<=11'b0;
input_grant<=1'b0;
d_temp<=8'b0;
end
else begin
case (count)
2'b00 : begin
out<=d;
d_temp<=d;
input_grant<=1'b1;
end
2'b01 : begin
out<=d_temp+{d_temp,1'b0}; //左移一位乘2,再加上本身就是3倍
// out <= (d_temp<<2)-d_temp;
input_grant<=1'b0;
end
2'b10 : begin
out<=d_temp+{d_temp, 1'b0}+{d_temp, 2'b0}; //左移二位乘4+左移一位乘2,再加上本身就是7倍
// out <= (d_temp<<3)-d_temp;
input_grant<=1'b0;
end
2'b11 : begin
out<={d_temp, 3'b0}; //左移三位乘3就是8倍
//out <= (d_temp<<3);
input_grant<=1'b0;
end
default : begin
out<=d;
input_grant<=1'b0;
end
endcase
end
end
//*************code***********//
endmodule
为什么要加 reg [7:0] d_temp;
而不是直接对d
进行操作呢?
放一张别人分析的图,一目了然
引用这位的话:如下图所示的红框和绿框内的数据非常关键。如果对输入的d在连续的4个时钟周期内分别进行d*1、d*3、d*7
和d*8
操作,那么当出现如红框内所示的6时,这个数据只持续了1个clk,显然这时候做的操作是:
6*1、128*3、129*7、129*8
,和预期不符。
所以引入 reg [7:0] d_temp;
的作用是保证做的移位乘法都是基于第一次的输入
所以我们做题的时候要一定要结合题目的文字描述和波形示意图进行分析