题解 | #位拆分与运算#

位拆分与运算

http://www.nowcoder.com/practice/1649582a755a4fabb9763d07e62a9752

题意整理

1、寄存器的位是可以分开单独运算的,并不是一个输入就一定是一个数据,在很多情况下,一个输入既包括数据又包括地址等其他有效信息

2、需要考虑数据锁存的问题,一定要在sel为0的时候进行锁存,只有此时的写入才是有效的(validout的下降沿写入有效),同时存在多种情况且没有优先级问题,建议使用case语句

题解主体

可以得到状态转换:

sel

out

validout

0

0  锁存输入

0

1

[3:0]+[7:4] 

1

2

[3:0]+[11:8]

1

3

[3:0]+[15:12]

1

根据激励方程和输出方程以及思路整理,关键电路如下:


这段电路的意思是首先将锁存的16位数据分段移位到4位数据,然后进行相加,再组合成一个20位的数据,按照选择器进行输出其中的5位。



将电路转换成Verilog代码描述如下

reg [15:0]data_lock; 


always@(posedge clk or negedge rst) begin

       if (!rst)

              data_lock <= 0;

       else if(!sel)

              data_lock <= d;

end


always@(posedge clk or negedge rst) begin

       if (!rst) begin

              out <= 'b0;

              validout <=0;

       end

       else begin

              case(sel)

                     0:begin 

                            out <= 'b0;

                            validout <=0;

                     end

                     1:begin 

                            out <= data_lock[3:0]+data_lock[7:4];

                            validout <=1;       

                     end

                     2:begin 

                            out <= data_lock[3:0]+data_lock[11:8];

                            validout <=1;                     

                     end              

                     3:begin 

                            out <= data_lock[3:0]+data_lock[15:12];

                            validout <=1;                     

                     end

        endcase

       end

end

因此实现方式为如下的电路,综合得到:

参考答案

`timescale 1ns/1ns

module data_cal(
input clk,
input rst,
input [15:0]d,
input [1:0]sel,

output reg[4:0]out,
output reg validout
);

reg [15:0]data_lock;  


always@(posedge clk or negedge rst) begin
	if (!rst)
		data_lock <= 0;
	else if(!sel)
		data_lock <= d;
end

always@(posedge clk or negedge rst) begin
	if (!rst) begin
		out <= 'b0;
		validout <=0;
	end	
	else begin
		case(sel)
			0:begin  
				out <= 'b0;
				validout <=0;
			end
			1:begin  
				out <= data_lock[3:0]+data_lock[7:4];
				validout <=1;		
			end
			2:begin  
				out <= data_lock[3:0]+data_lock[11:8];
				validout <=1;				
			end			
			3:begin  
				out <= data_lock[3:0]+data_lock[15:12];
				validout <=1;				
			end	
        endcase
	end
end


endmodule


全部评论
这个解答是不是不正确,sel与out之间肯定是组合逻辑的关系,不能用时序逻辑
15 回复 分享
发布于 2022-04-18 22:43
还需要定义out和validout为reg型
7 回复 分享
发布于 2022-06-08 11:19
应该用组合逻辑,把always块的敏感列表改成*,输出跟输入是同步的,用时序逻辑输出会延时一个周期
2 回复 分享
发布于 2023-10-12 00:24 四川
为啥需要将d锁存起来呀
2 回复 分享
发布于 2023-04-09 13:59 江苏
这个代码会报错,因为没用吧out和validout定义为reg型。在定义data_lock的时候加上就可以了。
2 回复 分享
发布于 2022-08-15 17:08
大佬们,请问为什么一定要data_lock呀,我用quartus写代码时没有锁存,但是modelsim仿真出来没有问题,这是为什么呀?
点赞 回复 分享
发布于 2023-03-10 19:33 山东
为什么data_lock一定要赋值0?
点赞 回复 分享
发布于 2023-03-07 16:51 广东
感觉写两个always块是不是没有必要,完全可以写在一个always块里呀
点赞 回复 分享
发布于 2022-06-06 21:51

相关推荐

评论
25
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务