HDLBits学习------Problem 115~117

参考链接:HDLBits导学


Problem 115 Rule90

        问题:Rule90 是一道根据一些有趣的规则来生成一维序列的题目。

规则很简单。一维序列中元素有 1,0 两种状态,分别对应开,关状态。

在每个时钟边沿到来时刻,元素的下一个状态为元素相邻两个元素的异或。

下表更详细地给出了跳变的规则,(可以视为状态转移表),元素下一个状态可以视作输出,输入为元素本身的状态与相应两个相邻元素的当前状态

         对于需要实现的电路,创建一个拥有 512 个元素的序列 (q[511:0]),每个时钟周期按照上述规则变换。load 信号有效时,序列更新 data 信号值为初始值。另外假设所有边界的值为 0 (q[-1] 以及 q[512])

        思路:使用for循环减少代码量,还有就是0异或x等于x

        解决:

module top_module(
    input clk,
    input load,
    input [511:0] data,
    output [511:0] q ); 

integer i;
	
always @(posedge clk) begin
	if(load)
		q <= data;
	else begin
		for(i=1;i<511;i=i+1) begin
            q[i] <= q[i-1] ^ q[i+1];
		end
		q[0] <= q[1];
		q[511] <= q[510];

        //牛x写法
        //     left           right
	    //  neighbour       neighbour
		//q <= q[511:1] ^ {q[510:0], 1'b0} ;
	end
end

endmodule

Problem 116 Rule110

        问题:规则:一维序列中元素有 1,0 两种状态,分别对应开,关状态。

在每个时钟边沿到来时刻,元素的下一个状态取决于元素本身的状态与前后两个相邻元素的当前状态。下表详细地给出了跳变的规则

        对于需要实现的电路,创建一个拥有 512 个元素的序列 (q[511:0]),每个时钟周期按照上述规则变换。load 信号有效时,序列更新 data 信号值为初始值。另外假设所有边界的值为 0 (q[-1] q[512])

        思路:借助卡洛图来化简(我也不太确定这个做法是不是对的)

         但是需要注意的是化简出来的这个式子只能单独应用于每一位,而不能整体或,不然整体或出来只会有0和1两种结果,而使用按位或出来的结果也是不正确的,一直被这个问题给难住

        解决:

module top_module(
    input clk,
    input load,
    input [511:0] data,
    output [511:0] q
); 

int i;

always @(posedge clk ) begin
	if(load)
		q <= data;
	else begin
		q[0] <= q[0];
		q[511] <= (q[511] ^ q[510] )|| ( q[510] );
		for(i = 1; i<511;i=i+1)
			q[i] <= (q[i] ^ q[i - 1]) || (!q[i+1] & q[i-1]); 
	end
end

endmodule

Problem 117 Conwaylift/conway's game of life 16x16

        问题:本题的变换工作在一个二维矩阵上,是一个二维序列生成器。

游戏规则如下:元素的下一个状态取决于当前状态九宫格中的 8 个邻居元素中 1 的个数,当邻居有 n 个 1 时:

  • 0-1 ,元素变为 0
  • 2 ,元素保持不变
  • 3 ,元素变为 1
  • 4+ ,元素变为 0

方便做题起见,本题中的这个二维矩阵设定为 16x16,广义上可以是无限的。

为了让事情变得更加有趣,这个16x16 矩阵的边界进行循环处理,回卷到对边,打个比方,上边界的上一行为下边界,左边界的左一列为右边界。所以对元素 (0,0) 来说,共有 8 个邻居 : (15,1), (15,0), (15,15), (0,1), (0,15), (1,1), (1,0) 以及 (1,15)。这个 16x16 矩阵表示为 256bit 长度的向量 q,其中 q[15:0] 代表第一行,q[31:16] 代表第二行,以此类推。

HDLBit 支持使用 SystemVerilog,所以你也可以使用二维向量表示这个矩阵。load 信号有效时,更新 q 信号值为初始值 data, q 每个周期变换一次

        思考:附上自己的想法,不过代码是错的,感觉把逻辑写得很复杂,留个纪念

module top_module(
    input clk,
    input load,
    input [255:0] data,
    output [255:0] q ); 

integer i,j;
reg num1,num1_up,num1_down,num1_left,num1_right;
reg num1_leftup,num1_rightup,num1_leftdown,num1_rightdown;

always @(posedge clk) begin
	if(load)
		q <= data;
	else
		for(i=1;i<15;i++) begin
			num1_up = q[i-1]+q[i+1]+	q[15*16+i-1]+q[15*16+i]+q[15*16+i+1]+	q[16+i-1]+q[16+i]+q[16+i+1];
			case(num1_up)
				0: q[i] <= 1'b0;
				1: q[i] <= 1'b0;
				2: q[i] <= q[i];
				3: q[i] <= 1'b1;
				default:q[i] <= 1'b0;
			endcase
			
			num1_down = q[i-1]+q[i+1]+	q[14*16+i-1]+q[14*16+i]+q[14*16+i+1]+	q[i-1]+q[i]+q[i+1];
			case(num1_down)
				0: q[15*16+i] <= 1'b0;
				1: q[15*16+i] <= 1'b0;
				2: q[15*16+i] <= q[15*16+i];
				3: q[15*16+i] <= 1'b1;
				default:q[15*16+i] <= 1'b0;
			endcase
			
			num1_left = q[i*16+15]+q[i*16+1]+	q[(i-1)*16+15]+q[(i-1)*16]+q[(i-1)*16+1]+	q[(i+1)*16+15]+q[(i+1)*16]+q[(i+1)*16+1];
			case(num1_left)
				0: q[i*16] <= 1'b0;
				1: q[i*16] <= 1'b0;
				2: q[i*16] <= q[i*16];
				3: q[i*16] <= 1'b1;
				default:q[i*16] <= 1'b0;
			endcase
			
			num1_right = q[i*16+14]+q[i*16]+	q[(i-1)*16+14]+q[(i-1)*16+15]+q[(i-1)*16]+	q[(i+1)*16+14]+q[(i+1)*16+15]+q[(i+1)*16];
			case(num1_right)
				0: q[i*16+15] <= 1'b0;
				1: q[i*16+15] <= 1'b0;
				2: q[i*16+15] <= q[i*16+15];
				3: q[i*16+15] <= 1'b1;
				default:q[i*16+15] <= 1'b0;
			endcase
		end
		
		num1_leftup = q[15]+q[1]+	q[15*16+15]+q[15*16]+q[15*16+1]+	q[16+15]+q[16]+q[16+1];
		case(num1_leftup)
			0: q[0] <= 1'b0;
			1: q[0] <= 1'b0;
			2: q[0] <= q[0];
			3: q[0] <= 1'b1;
			default:q[0] <= 1'b0;
		endcase
		num1_rightup = q[14]+q[0]+	q[15*16+14]+q[15*16+15]+q[15*16]+	q[16+14]+q[16+15]+q[16];
		case(num1_rightup)
			0: q[15] <= 1'b0;
			1: q[15] <= 1'b0;
			2: q[15] <= q[15];
			3: q[15] <= 1'b1;
			default:q[15] <= 1'b0;
		endcase
		num1_leftdown = q[15*16+15]+q[15*16+1]+		q[14*16+15]+q[14*16]+q[14*16+1]+	q[15]+q[0]+q[1];
		case(num1_leftdown)
			0: q[15*16] <= 1'b0;
			1: q[15*16] <= 1'b0;
			2: q[15*16] <= q[15*16];
			3: q[15*16] <= 1'b1;
			default:q[15*16] <= 1'b0;
		endcase
		num1_rightdown = q[15*16+14]+q[15*16]+		q[14*16+14]+q[14*16+15]+q[14*16]+	q[14]+q[15]+q[0];
		case(num1_rightdown)
			0: q[15*16+15] <= 1'b0;
			1: q[15*16+15] <= 1'b0;
			2: q[15*16+15] <= q[15*16+15];
			3: q[15*16+15] <= 1'b1;
			default:q[15*16+15] <= 1'b0;
		endcase
		
		for(i=1;i<15;i++) begin
			for(j=1;j<15;j++) begin
				num1 <= q[i*16+j-1]+q[i*16+j+1]+	q[(i-1)*16+j-1]+q[(i-1)*16+j]+q[(i-1)*16+j+1]+q[(i+1)*16+j-1]+	q[(i+1)*16+j]+q[(i+1)*16+j+1];
				case(num1)
					0: q[i*16+j] <= 1'b0;
					1: q[i*16+j] <= 1'b0;
					2: q[i*16+j] <= q[i*16+j];
					3: q[i*16+j] <= 1'b1;
					default:q[i*16+j] <= 1'b0;
				endcase
			end
		end
end

endmodule

        解决:来自大佬的源码,入口在上面的链接中

module top_module(
    input clk,
    input load,
    input [255:0] data,
    output [255:0] q ); 

    reg [15:0] q_2d [15:0]; //2-d q
    wire [2:0] nghbr_num [255:0];
    int idx_i_d,idx_i_u,idx_j_r,idx_j_l,i,j;

    //count num of neighbours
    always@(*) begin
        for(i = 0 ; i < 16 ; i = i + 1) begin
            for(j = 0 ; j < 16 ; j = j + 1) begin
                idx_i_u = (i == 0) ? i-1+16 :i-1; //up idx
                idx_i_d = (i == 15)? i+1-16 :i+1; //down idx
                idx_j_l = (j == 0) ? j-1+16 :j-1; //left idx
                idx_j_r = (j == 15)? j+1-16 :j+1; //right idx
                nghbr_num[i*16+j] = q_2d[idx_i_u][idx_j_l] + q_2d[idx_i_u][j  ] + q_2d[idx_i_u][idx_j_r]
                                +   q_2d[i      ][idx_j_l]                      + q_2d[i      ][idx_j_r]
                                +   q_2d[idx_i_d][idx_j_l] + q_2d[idx_i_d][j  ] + q_2d[idx_i_d][idx_j_r];
            end
        end
    end

    //next state transform base on num of neighbours
    always @(posedge clk) begin
        if(load) begin:init
            for(i = 0 ; i < 16 ; i = i + 1) begin
                for(j = 0 ; j < 16 ; j = j + 1) begin
                    q_2d[i][j]    <=  data[i*16+j];
                end
            end
        end
        else begin:set_val
            for(i = 0 ; i < 16 ; i = i + 1) begin
                for(j = 0 ; j < 16 ; j = j + 1) begin
                    if(nghbr_num[i*16+j] < 2)
                        q_2d[i][j]      <=  1'b0;
                    else if (nghbr_num[i*16+j] > 3)
                        q_2d[i][j]      <=  1'b0;
                    else if (nghbr_num[i*16+j] == 3)
                        q_2d[i][j]      <=  1'b1;
                    else
                        q_2d[i][j]      <=  q_2d[i][j];
                end
            end
        end
    end

    //output
    always@(*) begin
        for(i = 0 ; i < 16 ; i = i + 1) begin
            for(j = 0 ; j < 16 ; j = j + 1) begin
                q[i*16+j] = q_2d[i][j];
            end
        end
    end

endmodule

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值