题解 | #移位运算与乘法#
移位运算与乘法
https://www.nowcoder.com/practice/1dd22852bcac42ce8f781737f84a3272
1.题目
给定一个输入d[7:0],在每个时钟周期连续输出该值的1/3/7/8倍,并在输出d*1的值时,输出一个周期的有效信号
2. 解题思路
从给定的参考波形中可以看出,在clk上升沿时检测到d值,out会连续输出4个值(分别为d的1/3/7/8倍),连续输出完4个值后,clk会继续采集当前的d值,然后又连续输出4个值。
所以需要注意这种情况:在连续输出4个值的时候,d的值发生了变化,此时clk没有检测到新变化的d值(如波形图中6变化到128,在输出6的1/3/7/8倍的值时,中途d变化为128,此时的128是不会输出的,只有等连续输出完4个值后才会继续检测新的d)
所以可以使用一个计数器来记录输出个数,每当计数满4次后就清0,确保每次连续输出4次。
如何实现×1,×3,×7和×8呢,可以考虑使用移位寄存器,通常在最高位不为0的情况下,向左移n位 “<<n“ ,也就是将值扩大为原来的2^n倍;同理最低位不为0情况下,向右移 “>> n” 减少为原来的2^n倍
4. 参考波形图
5. 自己绘制的波形图
最初的想法是将d的值进行寄存为d_iniit,然后对寄存的d_int进行移位得到out,结果发现当使用时序逻辑时,在cnt==0时,d_init还未寄存到d的值(8),此时d_init是初始值0, out输出结果0;同理后面的值也是在cnt==0时没有输出正确的值。
后来我采用组合逻辑完成d_init的赋值, assign d_initial = ( cnt==0) ? d : d_initial; 当cnt == 0时,将d赋值给d_initial,其余时候保持不变。这样因为使用的是组合逻辑,在cnt ==0时会立马赋值给d_init,并且out是时序逻辑,所以正好满足。
wire [7:0] d_initial;
assign d_initial = ( cnt==0) ? d : d_initial;
always@(posedge clk or negedge rst)
if(!rst)
cnt <= 2'd0;
else if(cnt ==3)
cnt <= 2'd0;
else
cnt <= cnt + 1'b1;
always@(posedge clk or negedge rst)
if(!rst)
out <= 4'd0;
else
case(cnt)
0 : out <= d_initial ;
1 : out <= (d_initial <<1) + d_initial;
2 : out <= (d_initial <<3) - d_initial;
3 : out <= d_initial <<3;
endcase
always@(posedge clk or negedge rst)
if(!rst)
input_grant <= 1'd0;
else if(cnt == 0)
input_grant <= 1'b1;
else
input_grant <= 1'b0;
if(!rst) begin
out <= 48d0;
else
case(cnt)
0 : begin
1 : begin
2 : out <= (d_initial <<3) - d_initial;
3 : out <= d_initial <<3;
endcase