题解 | #移位运算与乘法#
移位运算与乘法
https://www.nowcoder.com/practice/1dd22852bcac42ce8f781737f84a3272
`timescale 1ns/1ns module multi_sel( input [7:0]d , input clk, input rst, output input_grant, output reg [10:0]out ); reg [1:0] cnt; reg [7:0] d_reg; assign input_grant = (cnt == 2'd1) ? 1'b1 : 1'b0; always@(posedge clk, negedge rst) begin if(!rst) cnt <= 2'd0; else cnt <= cnt + 1'b1; end always@(posedge clk, negedge rst) begin if(!rst) out <= 11'd0; else if(cnt == 2'b00) out <= {3'b000, d_reg}; else if(cnt == 2'b01) out <= ({3'b000, d_reg} << 1) + {3'b000, d_reg}; else if(cnt == 2'b10) out <= ({3'b000, d_reg} << 2) + out; else if(cnt == 2'b11) out <= d_reg << 3; else out <= out; end always@(negedge clk, negedge rst) begin if(~rst) d_reg <= d; else if(cnt == 2'd0) d_reg <= d; end endmodule
`timescale 1ns / 1ps module multi_sel_tb; // multi_sel Parameters parameter PERIOD = 10; // multi_sel Inputs reg [7:0] d = 0 ; reg clk = 0 ; reg rst = 0 ; // multi_sel Outputs wire input_grant ; wire [10:0] out ; initial begin forever #(PERIOD/2) clk=~clk; end multi_sel u_multi_sel ( .d ( d [7:0] ), .clk ( clk ), .rst ( rst ), .input_grant ( input_grant ), .out ( out [10:0] ) ); initial begin d = 8'd143; repeat(2)@(negedge clk); #1; rst = 1'b1; #25; d = 8'd7; #50; d = 8'd6; #10; d = 8'd128; #10; d = 8'd129; end endmodule
看了一下大家的解题思路,用状态机去做这个题是一个常见思路。但个人认为这么简单的题目没必要写一个完整的状态机。
在提交代码块中使用一个简单的2位计数器cnt来记录电路的运行状态并执行相应的操作。
需要注意的是提交时网站进行验证时是有延时的,也就是跟modelsim那种信号变化是完全理想不带一点延迟的情况不同,因此在自测代码块中的第37行延迟了1ns才将复位信号拉高以便和网站保持一致。
在提交代码块中,第三十六行在cnt == 0时的时钟下降沿对d进行采样保存到d_reg中,在后续的移位相加中使用d_reg进行操作,防止在没完成一个数的四个乘法操作之前d再次发生变化而产生错误的输出。
划重点:
①之所以在cnt==0时的时钟下降沿对d进行采样是因为上面提到网站提供的testbench中信号的变化是存在延时的。如果改成在cnt==0时的时钟上升沿对d进行采样,并且将自测代码块中第37行的延时1ns去掉的话,在modelsim中进行仿真也是能得到正确的波形的。但这就是完全理想、信号跳变没有延迟的情况,直接提交到网站中就得不到正确的结果从而错误。
②切记移位操作符的优先级比加减操作符低!