参考链接: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