.. _memory_detail:

内存访问与标签管理范式
======================

在 **NPU-SIM** 的实现中，所有数据块在SRAM读写的过程中都拥有一个唯一的标签，该标签在 :doc:`workload_config_detail` 中定义，用于标识数据块，并作为内存访问的索引。

内存标签在工作负载配置文件中的命名规范见下，作为 :doc:`workload_config_detail` 的补充说明。

1. 标签保留规则
~~~~~~~~~~~~~~~~~~

在一个计算原语执行完毕后，默认会从内存中删除 **输入标签** 所对应的数据块。如果希望在后续的计算中使用该数据块，应在标签名前加上下划线 ``_`` 。

.. admonition:: 示例
    :class: tip

    假设标签 ``x_out`` 作为原语1的输出，并在原语2中作为输入被使用。通常情况下，当原语2执行完毕之后，会从内存中删除 ``x_out`` 所对应的数据块（无论其在SRAM还是DRAM中）。然而当原语2在使用标签时，加上了下划线 ``_`` ，则表示该数据块在原语2执行完毕后，不会被删除。

    .. code-block:: json

        {
            "worklist": [
                {
                    "type": "prim_1",
                    "sram_address": {
                        "indata": "some_label",
                        "outdata": "x_out"
                    }
                },
                {
                    "type": "prim_2",
                    "sram_address": {
                        "indata": "_x_out",
                        "outdata": "y_out"
                    }
                },
                {
                    "type": "prim_3",
                    "sram_address": {
                        "indata": "y_out x_out",
                        "outdata": "z_out"
                    }
                }
            ]
        }

2. 多输入与多输出
~~~~~~~~~~~~~~~~~~

在一个计算原语需要多个输入的情况下（如残差连接算子），使用空格分隔多个标签。（见上文中的示例， ``prim_3`` 的输入标签由两个标签 ``y_out`` 和 ``x_out`` 组成）

原则上，一个计算原语只允许有一个输出标签。如若希望将输出均匀分割为多块，可参考原语的 :doc:`advanced_primitive_detail` 或使用 ``cast`` 的 ``weight`` 字段指定。

3. 特殊标签
~~~~~~~~~~~~~~~~~

- ``input_label`` 指代由其他工作核传入本工作核的数据块。当工作核A向工作核B发送数据时，会自动在B的内存中创建一个名为 ``input_label`` 的数据块，并覆盖先前的同名数据块。此标签代表的数据块实际大小将由计算原语的参数自行决定。

- ``dram_label x`` 指代该数据块应主动从DRAM中读取，在读取加载至SRAM中后会被命名为 ``x`` 。

- ``unset_label`` 指代未被定义的标签名， **不应** 出现在任何配置文件及日志输出文件中。