ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Verilog HDLBits 第十四期:3.2.4 More Circuits

2021-12-29 12:35:33  阅读:245  来源: 互联网

标签:15 HDLBits Circuits 单元格 module 16 3.2 511 input


目录

 前言 

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)

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

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


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

标签:15,HDLBits,Circuits,单元格,module,16,3.2,511,input
来源: https://blog.csdn.net/weixin_51915958/article/details/122198221

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有