LV4_移位运算与乘法
题目来源于牛客网
[牛客网在线编程_Verilog篇_Verilog快速入门 (nowcoder.com)](https://www.nowcoder.com/exam/oj?page=1&tab=Verilog篇&topicId=301)
题目
题目描述:
已知d为一个8位数,请在每个时钟周期分别输出该数乘1/3/7/8,并输出一个信号通知此时刻输入的d有效(d给出的信号的上升沿表示写入有效)
信号示意图:
波形示意图:
输入描述:
输入信号 d, clk, rst
类型 wire
在testbench中,clk为周期5ns的时钟,rst为低电平复位
输出描述:
输出信号 input_grant out
类型 reg
状态机
在Verilog中,可以使用always
语句和case
语句来实现状态机。
首先,声明一个状态寄存器state_reg
,用于存储当前状态的值。状态寄存器通常是一个有限状态机中的关键变量。
reg [2:0] state_reg;
在always @(posedge clk)
块中,使用case
语句根据当前的状态值执行相应的操作。在时钟的上升沿触发该always
块。
always @(posedge clk) begincase (state_reg)// 根据当前状态执行相应操作// 每个状态对应一个case// 每个case中描述该状态下的行为endcase
end
在每个case中,根据当前的状态值执行相应的操作。每个case对应一个状态,并描述在该状态下的行为。
always @(posedge clk) begincase (state_reg)// 状态12'd0: begin// 在状态1执行的操作// 可以包括信号的赋值、状态变迁等end// 状态22'd1: begin// 在状态2执行的操作end// 状态32'd2: begin// 在状态3执行的操作enddefault: begin// 默认情况下的操作,当状态寄存器的值不匹配任何已定义的状态时执行endendcase
end
代码
`timescale 1ns/1nsmodule multi_sel(input [7:0]d ,input clk,input rst,output reg input_grant,output reg [10:0]out
);
//*************code***********//
/*代码思路:使用状态机,进行逻辑跳转。可以借此题来练习状态机
1.声明状态寄存器
2.状态之间的转换
3.每个状态执行的操作将乘法改为移位来计算,可以节省资源*///声明参数,状态寄存器parameter IDLE = 3'd0; //空状态parameter M1 = 3'd1; //M1时,输入有效(input_grant=1)parameter M3 = 3'd2;parameter M7 = 3'd3;parameter M8 = 3'd4;reg [2:0] current_state;reg [2:0] next_state;reg [7:0] d_tool; //此变量是存储输入有效时d的值//状态之间的转换always @(posedge clk or negedge rst) beginif(!rst)current_state <= IDLE;else current_state <= next_state;end
//不同状态所要执行的操作always @(*) begin //和时钟、复位无关case (current_state)IDLE : begininput_grant <= 0;out <= 0;next_state <= M1;endM1 : begininput_grant <= 1;out <= d_tool;next_state <= M3;endM3 : begininput_grant <= 0;out <= (d_tool << 2'd2) - d_tool;next_state <= M7;endM7 : begininput_grant <= 0;out <= (d_tool << 2'd3) - d_tool;next_state <= M8;endM8 : begininput_grant <= 0;out <= (d_tool << 2'd3);next_state <= M1;enddefault : begininput_grant <= 0;out <= 0;next_state <= IDLE;end endcase end
//输入有效数据 d_tool 和实际的输入 d 的关系always @(posedge clk or negedge rst) beginif(!rst)d_tool <= 0;else beginif(current_state == IDLE)d_tool <= d;else if(current_state == M8)d_tool <= d;else d_tool <= d_tool;endend//*************code***********//
endmodule