最近在刷HDLBits准备今年的提前批和人秋招,目前刷到有限状态机后,发现前面的大部分题目比较基础。目前比较有难度和有意思的题目就是Conwaylife,二维元胞自动机。这里仅提供笔者自己的解法。
比较好想到的方法就是暴力枚举所有情况,给出该情况下所有的相邻坐标。思考过后觉得暴力枚举容易出现遗漏的情况。有没有一种通用的方法可以处理所有坐标呢。
参考生命游戏的前两道题,使用另外两个向量,表示出左移的对应坐标和右移的对应坐标,直接进行异或操作进行更新。那么对于本题也可以使用另外的八个向量,一一对应q的所有相邻坐标,最后执行相加和条件语句,即可实现一个cycle完成状态更新。
为了最简化代码编写的复杂度,进行了如下思考:
1.设计变量名称时,以方向作为命名后缀(west、east、north、south)
2.首先要得到相邻位置的两个向量,对于二维矩阵的一维表现形势,不是简单的整体左右移,而是以一行为单位的左右移,得到如下坐标关系
assign pos_e[i*16+15:i*16] = {q[(i+1)*16-2:i*16],q[i*16+15]};
assign pos_w[i*16+15:i*16] = {q[i*16],q[i*16+15:i*16+1]};
3.然后,要得到上下位置的对应向量,这个比较简单,整体左移或右移一行的位数(16)即可:
assign pos_n = {q[15:0],q[255:16]} ;
assign pos_s = {q[239:0],q[255:240]};
4.对于对角线的四个位置,没有必要单独去考虑其坐标,而是将其看作是pos_n和pos_s的相邻的左右坐标即可。即直接复制1.内的表达式,将等号右侧的索引替换为pos_n和pos_s。
5.这样便得到了全部8个对应坐标的向量,将其相加后判断即可
题目的要求为每个cycle更新一次,使用generate loop进行向量生成,使用for循环进行状态判断,得到题解如下:
module top_module(
input clk,
input load,
input [255:0] data,
output [255:0] q );
wire [255:0] pos_e ;
wire [255:0] pos_w ;
wire [255:0] pos_n ;
wire [255:0] pos_s ;
wire [255:0] pos_ne ;
wire [255:0] pos_se ;
wire [255:0] pos_nw ;
wire [255:0] pos_sw ;
reg [3:0] count ;
integer j ;
genvar i;
assign pos_n = {q[15:0],q[255:16]} ;
assign pos_s = {q[239:0],q[255:240]};
generate
for(i = 0;i < 16; i++)begin:test
assign pos_e[i*16+15:i*16] = {q[(i+1)*16-2:i*16],q[i*16+15]};
assign pos_w[i*16+15:i*16] = {q[i*16],q[i*16+15:i*16+1]};
assign pos_ne[i*16+15:i*16] = {pos_n[(i+1)*16-2:i*16],pos_n[i*16+15]};
assign pos_nw[i*16+15:i*16] = {pos_n[i*16],pos_n[i*16+15:i*16+1]};
assign pos_se[i*16+15:i*16] = {pos_s[(i+1)*16-2:i*16],pos_s[i*16+15]};
assign pos_sw[i*16+15:i*16] = {pos_s[i*16],pos_s[i*16+15:i*16+1]};
end
endgenerate
always@(posedge clk)begin
if(load)begin
q <= data ;
end else begin
for (j=0;j<=255;j++)begin
count = pos_e[j] +pos_w[j] +pos_n[j] +pos_s[j] +pos_ne[j] +pos_se[j] +pos_nw[j] +pos_sw[j] ;
case(count)
4'd2 : q[j] <= q[j] ;
4'd3 : q[j] <= 1'b1 ;
default:q[j] <= 1'b0 ;
endcase
end
end
end
endmodule