前言
Conwaylife - HDLBits
康威的生命游戏在科学美国人上刊登过,小时候还看到过,印象很深。
简单来说,就是对一个矩阵进行轮次变换,对每个元素的变换规则如下:
0-1 个邻居:单元格变为 0
2 个邻居:单元格状态不变
3 个邻居:单元格变为 1
4 个及以上邻居:单元格变为 0
要注意的是矩阵四周是“连续”的,即首尾相接。可以理解成桌面壁纸的平铺。
思路
连续的意思就是说边界处会发生“跳变”。那我整一个四周大一圈的矩阵把它包进去就可以了。
然后在每个时钟沿进行判断,再赋新的值给寄存器即可。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 module top_module ( input clk, input load, input [255 :0 ] data, output reg [255 :0 ] q ); wire [18 *18 -1 :0 ] temp; wire [ 255 :0 ] out_temp; assign temp[17 :0 ] = {q[240 ], q[255 :240 ], q[255 ]}; assign temp[18 *18 -1 :18 *17 ] = {q[0 ], q[15 :0 ], q[15 ]}; genvar i; generate for (i = 1 ; i < 17 ; i = i + 1 ) begin : origin_mat assign temp[18 *(i+1 )-1 :18 *i] = {q[16 *(i-1 )], q[16 *i-1 :16 *(i-1 )], q[16 *i-1 ]}; end endgenerate genvar j, k; generate for (j = 0 ; j < 16 ; j = j + 1 ) begin : temp_row for (k = 0 ; k < 16 ; k = k + 1 ) begin : temp_col localparam integer idx = 18 * (j + 1 ) + k + 1 ; wire [3 :0 ] nbr_sum; wire loc_inst; assign nbr_sum = temp[idx-1 ] + temp[idx+1 ] + temp[idx-18 ] + temp[idx+18 ] + temp[idx-18 -1 ]+ temp[idx-18 +1 ] + temp[idx+18 -1 ]+ temp[idx+18 +1 ]; assign loc_inst = (nbr_sum < 2 ) ? 1'b0 : (nbr_sum == 2 ) ? temp[idx] : (nbr_sum == 3 ) ? 1'b1 : 1'b0 ; assign out_temp[16 *j + k] = loc_inst; end end endgenerate always @(posedge clk) begin if (load) begin q <= data; end else begin q <= out_temp; end end endmodule
改进
HDLbits: verilog实现Conwaylife二维元胞自动机 - CSDN 简化了数组的表示,采用二维数组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 module top_module( input clk, input load, input [255 :0 ] data, output reg [255 :0 ] q ); initial begin q = 256'h0 ; end wire [17 :0 ] q_t [17 :0 ]; genvar i; generate for (i=0 ;i<16 ;i=i+1 )begin : assign_value assign q_t[i+1 ][17 :0 ] = {q[i*16 ], q[i*16 +:16 ], q[i*16 +15 ]}; end assign q_t[0 ][17 :0 ] = {q[15 *16 ], q[15 *16 +:16 ], q[15 *16 +15 ]}; assign q_t[17 ][17 :0 ] = {q[0 ], q[0 *16 +:16 ], q[0 *16 +15 ]}; endgenerate wire [3 :0 ] q_cnt[15 :0 ][15 :0 ]; wire [255 :0 ] q_temp; genvar j,k; generate for (j = 0 ; j<16 ; j=j+1 ) begin :loop_out for (k = 0 ; k<16 ; k=k+1 ) begin :loop_in assign q_cnt[j][k] = q_t[j+1 ][k] + q_t[j+1 ][k+2 ] + q_t[j][k] + q_t[j][k+2 ] + q_t[j][k+1 ] + q_t[j+2 ][k] + q_t[j+2 ][k+2 ] + q_t[j+2 ][k+1 ]; assign q_temp[j*16 +k] = (q_cnt[j][k]==4'd3 )? 1'b1 : ((q_cnt[j][k]==4'b0010 )? q[j*16 +k] : 1'b0 ); end end endgenerate integer m; always @(posedge clk)begin if (load) begin q<=data; end else begin q<=q_temp; end end endmodule