Conway‘s Game of Life 16x16(Conwaylife)

项目场景:

Conway’s Game of Life is a two-dimensional cellular automaton.

The “game” is played on a two-dimensional grid of cells, where each cell is either 1 (alive) or 0 (dead). At each time step, each cell changes state depending on how many neighbours it has:

0-1 neighbour: Cell becomes 0.
2 neighbours: Cell state does not change.
3 neighbours: Cell becomes 1.
4+ neighbours: Cell becomes 0.
The game is formulated for an infinite grid. In this circuit, we will use a 16x16 grid. To make things more interesting, we will use a 16x16 toroid, where the sides wrap around to the other side of the grid. For example, the corner cell (0,0) has 8 neighbours: (15,1), (15,0), (15,15), (0,1), (0,15), (1,1), (1,0), and (1,15). The 16x16 grid is represented by a length 256 vector, where each row of 16 cells is represented by a sub-vector: q[15:0] is row 0, q[31:16] is row 1, etc. (This tool accepts SystemVerilog, so you may use 2D vectors if you wish.)

load: Loads data into q at the next clock edge, for loading initial state.
q: The 16x16 current state of the game, updated every clock cycle.
The game state should advance by one timestep every clock cycle.

John Conway, mathematician and creator of the Game of Life cellular automaton, passed away from COVID-19 on April 11, 2020.

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

问题描述

康威的生命游戏是一个二维细胞自动机。
“游戏”是在一个二维的细胞网格上进行的,其中每个细胞要么是1(活着),要么是0(死亡)。在每个时间步,每个单元根据它有多少邻居改变状态:
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的网格由一个长度为256的向量表示,其中每一行16个单元格由一个子向量表示:q[15:0]是第0行,q[31:16]是第1行,以此类推(此工具接受SystemVerilog,因此如果你愿意,可以使用2D向量)
load:在下一个时钟边缘将数据加载到q中,用于加载初始状态。
q: 16x16的游戏当前状态,每个时钟周期更新。
游戏状态应该在每个时钟周期中前进一个时间步长。数学家、生命游戏细胞自动机的创造者John Conway于2020年4月11日因新冠肺炎去世。


原因分析:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
本题规则类似于卡诺图的功能,根据卡诺图的性质,把原有的16x16格子扩展为18X18的格子,这样就能使每个16x16格子的外围和内部一样都有8个格子相邻,避免了特殊情况的讨论。在[255:0] q中cell的地址与行和列i,j的关系为address = 16i +j;该地址在扩展格子[323:0]t中的对应位置为Address = 18(i+1) +(j +1);其相邻格子的坐标已经在上图中标识出来,只需要判断这8个相邻cell和的状态就能确定q_next[address]的状态。

扩展内容:
1.Verilog中二维数组的使用:
Verilog中提供了两维数组来帮助我们建立内存的行为模型。具体来说,就是可以将内存宣称为一个reg类型的数组,这个数组中的任何一个单元都可以通过一个下标去访问。这样的数组的定义方式如下:

reg [wordsize : 0] array_name [0 : arraysize];

例如:

reg [7:0] my_memory [0:255];

其中 [7:0] 是内存的宽度,而[0:255]则是内存的深度(也就是有多少存储单元),其中宽度为8位,深度为256。地址0对应着数组中的0存储单元。

如果要存储一个值到某个单元中去,可以这样做:

my_memory [address] = data_in;

而如果要从某个单元读出值,可以这么做:

data_out = my_memory [address];

但要是只需要读一位或者多个位,就要麻烦一点,因为Verilog不允许读/写一个位。这时,就需要使用一个变量转换一下:(wolf点评:菜鸟易犯的错误,注意!)

例如:

data_out = my_memory[address];

data_out_it_0 = data_out[0];

这里首先从一个单元里面读出数据,然后再取出读出的数据的某一位的值。
2.

 t[17:0] = {q[240],q[255:240],q[255]};
            t[323:306] = {q[0],q[15:0],q[15]};
            for(i=1;i<17;i=i+1) begin
                t[i*18 +:18] = {q[(i-1)*16],q[(i-1)*16 +: 16],q[i*16-1]};                
            end

解决方案:

module top_module(
    input clk,
    input load,
    input [255:0] data,
    output [255:0] q ); 
    
    reg  [323:0] t;
    wire [255:0] q_next;
    integer i,j;
    reg[3:0]	cnt;
    
    assign	t[17:0] 		= 	{q[240]	,	q[255:240]	,q[255]	};
    assign	t[35:18] 		= 	{q[0]	,	q[15:0]    	,q[15]	};
    assign	t[53:36] 		= 	{q[16]	,  	q[31:16]   	,q[31]	};
    assign	t[71:54] 		= 	{q[32]	,  	q[47:32]   	,q[47]	};
    assign	t[89:72] 		= 	{q[48]	,  	q[63:48]   	,q[63]	};
    assign	t[107:90] 		= 	{q[64]	,  	q[79:64]   	,q[79]	}; 
    assign	t[125:108] 		= 	{q[80]	,  	q[95:80]   	,q[95]	};
    assign	t[143:126] 		= 	{q[96]	,  	q[111:96]  	,q[111]	};
    assign	t[161:144] 		= 	{q[112]	, 	q[127:112] 	,q[127]	};
    assign	t[179:162] 		= 	{q[128]	, 	q[143:128] 	,q[143]	};
    assign	t[197:180] 		= 	{q[144]	,	q[159:144]	,q[159]	};
    assign	t[215:198] 		= 	{q[160]	,	q[175:160]	,q[175]	};
    assign	t[233:216] 		= 	{q[176]	,	q[191:176]	,q[191]	};
    assign	t[251:234] 		= 	{q[192]	,	q[207:192]	,q[207]	};
    assign	t[269:252] 		= 	{q[208]	,	q[223:208]	,q[223]	};
    assign	t[287:270] 		= 	{q[224]	,	q[239:224]	,q[239]	}; 
    assign	t[305:288] 		= 	{q[240]	,	q[255:240]	,q[255]	};
    assign	t[323:306] 		= 	{q[0]	,	q[15:0]		,q[15]	};
    
    always @(*)
        begin
            for(i=0;i<16;i=i+1) begin
                for(j=0;j<16;j=j+1) begin
                    cnt = t[(i+1)*18+j+1-1]+t[(i+1)*18+j+1+1]+t[i*18+j+1-1]
                    +t[i*18+j+1]+t[i*18+j+1+1]
                    +t[(i+2)*18+j+1-1]+t[(i+2)*18+j+1]+t[(i+2)*18+j+1+1];
                    if(cnt <= 1 | cnt >=4)
                        q_next[i*16+j] = 0;
                    else if(cnt == 3)
                        q_next[i*16+j] = 1;
                    else
                        q_next[i*16+j] = q[i*16+j];
                end             
            end
        end
    
    always @(posedge clk)
        begin
            if(load)
                q <= data;
            else
                q <= q_next;
        end
endmodule
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值