Verilog HDLBits 第十四期:3.2.4 More Circuits

目录

 前言 

3.2.4.1 Rule 90(Rule90)

Solution:

3.2.4.2 Rule 110(Rule110)

Solution:

3.2.4.3 Conway's Game of Life 16×16(Conwaylife)

Solution:


 前言 

HDLbits网站如下

Problem sets - HDLBits (01xz.net)

从本期开始我们继续HDLbits第三章Circuits的学习,本期的内容是3.2.4 More Circuits


3.2.4.1 Rule 90(Rule90)

规则很简单。有一维单元格数组(打开或关闭)。在每个时间步,每个单元格的下一个状态是该单元格的两个当前邻居的异或。表达此规则的一种更详细的方式是下表,其中单元格的下一个状态是其自身及其两个邻居的函数:

Verilog HDLBits 第十四期:3.2.4 More Circuits

(“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 中,每个单元格的下一个状态仅取决于它自己和它的两个邻居,根据下表:

Verilog HDLBits 第十四期:3.2.4 More Circuits

(“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 中是不能出现变量的。 


本小节的三道题都有些挑战性,值得多思考

上一篇:【无标题】


下一篇:3.4 Go语言从入门到精通:包管理工具之Go module