目录
3.2.4.3 Conway's Game of Life 16×16(Conwaylife)
前言
HDLbits网站如下
Problem sets - HDLBits (01xz.net)
从本期开始我们继续HDLbits第三章Circuits的学习,本期的内容是3.2.4 More Circuits
3.2.4.1 Rule 90(Rule90)
规则很简单。有一维单元格数组(打开或关闭)。在每个时间步,每个单元格的下一个状态是该单元格的两个当前邻居的异或。表达此规则的一种更详细的方式是下表,其中单元格的下一个状态是其自身及其两个邻居的函数:
(“rule90”这个名字来自阅读“下一状态”一栏:01011010是十进制的90。)
在此电路中,创建一个 512 单元的系统 (q[511:0]),并在每个时钟周期前进一个时间步长。加载输入指示系统的状态应该加载data[511:0]。假设边界(q[-1] 和 q[512])都为零(关闭)。
Hint:对于 q[511:0] = 1 的初始状态,前几次迭代是:
1 10 101 1000 10100 100010 1010101 10000000
这形成了Sierpiński triangle的一半。
Solution:
module top_module(
input clk,
input load,
input [511:0] data,
output reg [511:0] q);
int i;
always @(posedge clk) begin
if (load)
q <= data;
else begin
q[0]<=q[1]^1'b0;
q[511]<=1'b0^q[510];
for(i=1;i<511;i=i+1)
q[i]<=q[i-1]^q[i+1];
end
end
endmodule
参考答案更加简洁,不用for循环
module top_module(
input clk,
input load,
input [511:0] data,
output reg [511:0] q);
always @(posedge clk) begin
if (load)
q <= data; // Load the DFFs with a value.
else begin
// At each clock, the DFF storing each bit position becomes the XOR of its left neighbour
// and its right neighbour. Since the operation is the same for every
// bit position, it can be written as a single operation on vectors.
// The shifts are accomplished using part select and concatenation operators.
// left right
// neighbour neighbour
q <= q[511:1] ^ {q[510:0], 1'b0} ;
end
end
endmodule
3.2.4.2 Rule 110(Rule110)
规则很简单。有一维单元格数组(打开或关闭)。在每个时间边沿到来的时刻,每个单元格的状态都会发生变化。在rule 110 中,每个单元格的下一个状态仅取决于它自己和它的两个邻居,根据下表:
(“rule110”这个名字来自阅读“下一状态”一栏:01101110是十进制110。)
在此电路中,创建一个 512 单元的系统 (q[511:0]),并在每个时钟周期前进一个时间步长。加载输入指示系统的状态应该加载data[511:0]。假设边界(q[-1] 和 q[512])都为零(关闭)。
Hint:对于 q[511:0] = 1 的初始状态,前几次迭代是:
1 11 111 1101 11111 110001 1110011 11010111
Solution:
module top_module(
input clk,
input load,
input [511:0] data,
output [511:0] q
);
always@(posedge clk) begin
if(load)
q<=data;
else
q<=(q[511:0]^{q[510:0],1'b0})|(~{1'b0,q[511:1]}&q);
end
endmodule
进行卡诺图化简
3.2.4.3 Conway's Game of Life 16×16(Conwaylife)
Conway's Game of Life 是一个二维序列生成机。
“游戏”是在二维网格单元格上进行的,其中每个单元格要么是 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,因此您可以根据需要使用 二维向量。)
- load:在下一个时钟沿将数据加载到 q 中,用于加载初始状态。
- q:游戏的 16x16 当前状态,每个时钟周期更新。
游戏状态应该在每个时钟周期前进一个时间步长。
Solution:
module top_module(
input clk,
input load,
input [255:0] data,
output [255:0] q );
int idx_up,idx_down,idx_right,idx_left,idx_ul,idx_ur,idx_dl,idx_dr;
reg[3:0]u,d,l,r;
reg[3:0]qtemp[255:0];
reg[255:0]q_t;
always@(posedge clk) begin
if(load)
q<=data;
else
q<=q_t;
end
always@(*) begin
for(int i=0;i<16;i++)
for(int j=0;j<16;j++) begin
u=i[3:0]+1;
d=i[3:0]-1;
l=j[3:0]-1;
r=j[3:0]+1;
idx_up=u*16+j;
idx_down=d*16+j;
idx_right=i*16+r;
idx_left=i*16+l;
idx_ul=u*16+l;
idx_ur=u*16+r;
idx_dl=d*16+l;
idx_dr=d*16+r;
qtemp[i*16+j]=q[idx_up]+q[idx_down]+q[idx_right]+q[idx_left]+q[idx_ul]+q[idx_ur]+q[idx_dl]+q[idx_dr];
q_t[i*16+j]=qtemp[i*16+j]==2?q[i*16+j]:(qtemp[i*16+j]==3?1:0);
end
end
endmodule
方法二:将16*16数组扩展为18*18数组,易于理解
module top_module(
input clk,
input load,
input [255:0] data,
output [255:0] q );
reg[17:0]qtemp[17:0];
reg[15:0]qnext[15:0];
reg[3:0]num;
integer i,j;
always@(*) begin
qtemp[0][17:0]={q[240],q[255:240],q[255]};
qtemp[17][17:0]={q[0],q[15:0],q[15]};
for(i=1;i<17;i++)
begin
qtemp[i][17:0]={q[i*16-16],q[(i*16-1)-:16],q[i*16-1]};
end
for(i=1;i<17;i++)
for(j=1;j<17;j++)
begin
num=qtemp[i][j-1]+qtemp[i][j+1]+qtemp[i-1][j]+qtemp[i+1][j]+qtemp[i-1][j-1]+qtemp[i-1][j+1]+qtemp[i+1][j-1]+qtemp[i+1][j+1];
qnext[i-1][j-1]=(num==2)?qtemp[i][j]:(num==3?1:0);
end
end
always@(posedge clk) begin
if(load)
q<=data;
else
begin
for(int i=0;i<16;i++)
q[(i*16+15)-:16]<=qnext[i];
end
end
endmodule
关于这一行代码q[(i*16+15)-:16]<=qnext[i]; 楼主之前用q[i*16+15:i*16]<=qnext[i]; 一直报错
i is not a constant
经查阅资料得知,Verilog不支持q[i*16+15:i*16]这种形式,如果把向量的位选取写成 vect[msb:lsb] 这种形式,下标 msb 和 lsb 中是不能出现变量的。
本小节的三道题都有些挑战性,值得多思考