4.4 HDLBits —— 更多时序逻辑电路

90 号一维元胞自动机【FPGA 常用数字设计课题】

规则 90 是一种具备诸多有趣特性的一维元胞自动机。其演化规则十分简单:存在一排一维元胞阵列,每个元胞只有开启、关闭两种状态。每一次迭代时刻,任意元胞的下一状态等于它左右两个相邻元胞当前状态的异或值。

下面用更详尽的表格形式描述该规则:单个元胞的下一状态由它自身以及左右两侧邻居共同决定。

("规则 90" 这个名称来源于次态列的二进制数值:01011010 转换成十进制正好是 90。)

请设计该数字电路:搭建一套包含 512 个元胞的系统,状态寄存器为q511:0;每个时钟周期完成一次迭代(前进一个时间步)。 输入信号load有效时,需将data511:0的数值载入元胞系统,作为系统初始状态。 边界处理规则:虚拟边界元胞q-1(数组最左侧外)与q512(数组最右侧外)的状态均固定为 0(关闭状态)

参考答案

java 复制代码
/*
=====================================================================
模块功能:512位Rule90一维元胞自动机,支持并行载入初始数据
核心算法Rule90:单个细胞下一状态 = 左侧邻居值 XOR 右侧邻居值
控制逻辑:load=1并行加载外部data;load=0按Rule90迭代更新细胞阵列
边界处理:最左细胞无左邻居、最右细胞无右邻居,缺失邻居默认逻辑0
位序约定:q[511]最右端细胞、q[0]最左端细胞,整段共512个连续元胞
=====================================================================
*/
module top_module(
    input clk,              // 全局同步时钟,上升沿执行加载/迭代状态刷新
    input load,             // 并行加载使能(高电平有效):1载入初始值;0执行Rule90演化
    input [511:0] data,     // 512位并行预置数据,load有效时写入寄存器作为初始状态
    output reg [511:0] q    // 512位元胞状态寄存器,保存每一拍演化结果
);

always @(posedge clk) begin
    if (load) begin
        // 并行加载模式:时钟上升沿直接把外部data整体写入q,重置元胞初始状态
        q <= data;
    end
    else begin
        // ========== Rule90 核心迭代公式拆解 ==========
        // 规则定义:q[i]次态 = 左邻居q[i-1] XOR 右邻居q[i+1]
        // 1.{1'b0, q[511:1]}:整体右移1位、最高位补0 → 每一位对齐自身【右邻居】
        //   例:原q[i+1]移到当前i位置,最右端q[511]右邻居空缺补0
        // 2.{q[510:0], 1'b0}:整体左移1位、最低位补0 → 每一位对齐自身【左邻居】
        //   例:原q[i-1]移到当前i位置,最左端q[0]左邻居空缺补0
        // 3.两组向量逐位异或,一次性算出全部512个元胞下一时刻状态
        q <= {1'b0, q[511:1]} ^ {q[510:0], 1'b0};
    end
end

endmodule

输出结果

110 号一维元胞自动机

规则110是一种具备诸多有趣特性(例如具备图灵完备性)的一维元胞自动机。系统包含一维元胞阵列(元胞状态分为开启或关闭两种)。在每一个时间步长中,每个元胞的状态都会发生改变。在规则110中,每个元胞的下一状态仅由自身及其左右两个相邻元胞决定,具体遵循下表所示规则:

"规则110"这一名称来源于状态转移列的二进制数值:二进制数01101110转换为十进制即为110。在本电路中,搭建一个包含512个元胞的系统(信号q511:0),每个时钟周期完成一次单步状态演化。加载输入信号有效时,系统会将data511:0的数据载入作为初始状态。规定边界元胞q-1与q512的状态均为0(关闭状态)。

逻辑表达式为:nexti=(C⊕R)∣(L‾⋅C)next_i = (C \oplus R) | (\overline{L} \cdot C)nexti=(C⊕R)∣(L⋅C)

参考答案

java 复制代码
/*
=====================================================================
模块功能:512位Rule110一维元胞自动机,支持并行载入初始状态
经典Rule110规则:单格次态 = (本位 ^ 左邻) | ( ~右邻 & 本位 )
控制逻辑:load=1 全局并行加载外部data初始化阵列;load=0 按Rule110逐时钟迭代演化
边界约定:最左端元胞无左邻居、最右端元胞无右邻居,空缺邻居默认逻辑0
位序:q[511]最右端元胞、q[0]最左端元胞,总长度512bit
应用背景:Rule110是已被证明具备图灵完备性的一维元胞自动机,可实现通用计算
=====================================================================
*/
module top_module(
    input clk,                  // 系统同步时钟,仅上升沿触发元胞阵列整体状态刷新
    input load,                 // 并行加载使能(高电平有效):1载入初始数据;0执行Rule110演化迭代
    input [511:0] data,         // 512bit外部预置数据,load拉高时写入寄存器作为元胞初始状态
    output reg [511:0] q        // 512位元胞状态寄存器,保存当前迭代周期所有细胞电平
); 

always @(posedge clk) begin
    if (load) begin
        // 并行加载分支:时钟上升沿直接覆盖q的值,重置整列元胞初始分布
        q <= data;
    end else begin
        // ===================== Rule110核心迭代公式分步拆解 =====================
        // 基础符号定义(对任意中间位q[i]):
        // 本位:q[i];左邻居:L=q[i-1];右邻居:R=q[i+1]
        // 标准Rule110布尔式:q_next = (q[i]^L) | (~R & q[i])
        // 1.左邻居向量 {q[510:0],1'b0}:全体左移1位、最低位补0,q[i]位置对齐左邻q[i-1],q[0]左邻空缺补0
        // 2.右邻居向量 {1'b0,q[511:1]}:全体右移1位、最高位补0,q[i]位置对齐右邻q[i+1],q[511]右邻空缺补0
        // 运算优先级:取反~ > 与& > 异或^ > 或|,和代码书写顺序匹配
        q <= (q ^ {q[510:0], 1'b0}) | (~{1'b0, q[511:1]} & q);
    end
end

endmodule

输出结果

康威生命游戏(16×16 二维网格)

康威生命游戏是一种二维元胞自动机。

该"游戏"运行在二维元胞网格上,每个元胞状态为1(存活)或0(死亡)。每个时间步长,所有元胞会根据自身周围存活邻居的总数切换状态,规则如下:

  1. 存活邻居数量为0~1个:元胞变为死亡(0);
  2. 存活邻居数量为2个:元胞状态保持不变;
  3. 存活邻居数量为3个:元胞变为存活(1);
  4. 存活邻居数量≥4个:元胞变为死亡(0)。
    该游戏理论定义在无限网格上。本电路采用16×16有限网格,且网格为环面结构(边界首尾循环相连)。举例:角落元胞坐标(0,0)拥有8个相邻元胞,坐标分别为(15,1)、(15,0)、(15,15)、(0,1)、(0,15)、(1,1)、(1,0)、(1,15)。
    16×16网格由长度256的一维向量表示:每一行16个元胞对应一段子向量,其中q15:0代表第0行,q31:16代表第1行,以此类推。(本工具支持SystemVerilog语法,你也可以直接使用二维向量。)
    端口说明:
  • load:时钟上升沿将数据载入状态寄存器q,用于加载游戏初始布局;
  • q:存储16×16网格当前游戏状态,每个时钟周期更新一次。
    游戏状态需要在每个时钟周期向前推演一个时间步。
    补充背景:生命游戏发明者、数学家约翰·康威于2020年4月11日因新冠逝世。

参考答案

java 复制代码
/*
=====================================================================
模块功能:16×16康威生命游戏(环形环绕边界),支持并行加载初始状态+逐时钟迭代演化
网格存储:256bit一维向量映射二维网格,q[15:0]对应第0行、每行16个细胞,总行列范围r∈[0,15],c∈[0,15]
边界规则:环面(Torus)边界,首尾行、首尾列循环相邻,无边缘截断空缺邻居
演化规则:标准康威生命游戏4条核心判定规则
工作模式:load=1并行写入初始data;load=0时钟上升沿刷新下一代细胞状态
架构拆分:组合逻辑预计算全网格次态next_q + 时序逻辑同步刷新寄存器q,三段式经典写法
=====================================================================
*/
module top_module(
    input clk,                  // 系统同步时钟,上升沿统一刷新整张网格的细胞状态
    input load,                 // 并行加载使能(高电平有效):时钟沿载入初始网格数据,重置游戏状态
    input [255:0] data,         // 256bit一维初始向量,映射16×16二维网格,load拉高时写入寄存器
    output reg [255:0] q        // 细胞状态主寄存器,保存当前完整网格所有细胞存活/死亡状态
);

reg [255:0] next_q;             // 组合逻辑缓存:预计算得到下一时刻整张网格的细胞状态

//====================组合逻辑块:遍历全网格、按生命游戏规则计算次态====================
always @(*) begin
    // Verilog规范:循环计数、临时整型变量统一在always块开头声明
    integer idx;                // 一维向量全局遍历下标,取值0~255,逐个访问每个细胞
    integer r, c;               // 当前细胞对应的二维行号r(0~15)、列号c(0~15)
    integer ru, rd, cl, cr;     // 环绕修正后的上一行、下一行、左一列、右一列编号
    integer n0,n1,n2,n3,n4,n5,n6,n7; // 8邻域邻居对应的一维向量下标
    integer sum;                // 统计8个邻居里存活(电平=1)的细胞总数量
    reg curr;                   // 寄存当前中心细胞自身的存活状态(1存活/0死亡)

    next_q = 256'd0;            // 初始化下一代网格缓存全0,避免未赋值位出现不定态

    // 双层逻辑等价单层循环:遍历全部256个网格细胞
    for(idx = 0; idx < 256; idx = idx + 1) begin
        // 一维下标转二维行列:每行固定16列,整除取行、取余取列
        r = idx / 16;           
        c = idx % 16;           

        // 环面边界环绕运算:首尾行列循环衔接,解决边缘细胞邻居缺失问题
        ru = (r - 1 + 16) % 16; // 上一行:首行r=0向上跳转至末行15,+16规避负数取余异常
        rd = (r + 1) % 16;      // 下一行:末行r=15向下跳转至首行0
        cl = (c - 1 + 16) % 16; // 左一列:首列c=0向左跳转至末列15
        cr = (c + 1) % 16;      // 右一列:末列c=15向右跳转至首列0

        // 计算8个相邻细胞一维下标,完整覆盖摩尔8邻域
        n0 = ru * 16 + cl;      // 左上邻居
        n1 = ru * 16 + c;       // 正上邻居
        n2 = ru * 16 + cr;      // 右上邻居
        n3 = r  * 16 + cl;      // 左侧邻居
        n4 = r  * 16 + cr;      // 右侧邻居
        n5 = rd * 16 + cl;      // 左下邻居
        n6 = rd * 16 + c;       // 正下邻居
        n7 = rd * 16 + cr;      // 右下邻居

        // 累加邻居存活总数:高电平代表细胞存活,直接数值求和
        sum = q[n0] + q[n1] + q[n2] + q[n3] + q[n4] + q[n5] + q[n6] + q[n7];
        curr = q[idx];          // 读取当前中心细胞本身状态

        //============康威生命游戏标准演化规则============
        if(sum == 3) begin
            // 规则1:任意位置有恰好3个存活邻居,细胞复活(无论原本生死)
            next_q[idx] = 1'b1;
        end
        else if(sum == 2) begin
            // 规则2:恰好2个存活邻居,细胞维持原有状态不变
            next_q[idx] = curr;
        end
        else begin
            // 规则3:邻居≤2(饥饿消亡)或≥4(拥挤消亡),细胞直接死亡
            next_q[idx] = 1'b0;
        end
    end
end

//====================时序逻辑块:时钟同步执行加载/状态迭代====================
always @(posedge clk) begin
    if(load) begin
        // 加载模式:时钟上升沿用外部data覆盖全局状态,初始化/重置网格
        q <= data;
    end
    else begin
        // 演化模式:载入组合逻辑提前算好的下一代网格状态,推进一个时间步
        q <= next_q;
    end
end

endmodule

输出结果

相关推荐
HUSTCH20211 天前
有符号数无符号数加法器逻辑
fpga开发
LCMICRO-133108477461 天前
国产长芯微LP4807完全P2P替代ADA4807,1mA、300MHz 增益带宽、电压反馈运算放大器
arm开发·嵌入式硬件·fpga开发·硬件工程·运算放大器·ada4807
LCMICRO-133108477461 天前
国产长芯微LP8628完全P2P替代AD8628,零漂移、单电源、输入输出轨到轨高精度运放
arm开发·嵌入式硬件·fpga开发·硬件工程·精密运放·ad8628
芯路行者2 天前
7 HDLBits —— 验证:编写测试激励文件
fpga开发·verilog·fpga·hdlbits
芯路行者2 天前
4.1 HDLBits —— 时序逻辑电路之锁存器与触发器
fpga开发·verilog·fpga·hdlbits
芯路行者2 天前
5 HDLBits —— 构建更大的电路
fpga开发·verilog·fpga·hdlbits
156082072192 天前
直流耦合采集卡前端电路调试
嵌入式硬件·fpga开发
芯路行者2 天前
4.3 HDLBits —— 时序逻辑电路之移位寄存器
fpga开发·verilog·fpga·hdlbits
芯路行者2 天前
4.2 HDLBits —— 时序逻辑电路之计数器
fpga开发·verilog·fpga·hdlbits