【问题标题】:Gracefully access memory that may not be there优雅地访问可能不存在的内存
【发布时间】:2020-08-07 17:50:42
【问题描述】:

我正在使用类似 arduino 的微控制器(ARM 指令集),它具有一些不连续的 32 位内存映射寄存器(控制/状态寄存器,CSR),如下所示:

#define Comparator0_CSR0  0xA000
(No 0xA004 register)
#define Comparator0_CSR2  0xA008
#define Comparator0_CSR3  0xA00C

#define Comparator1_CSR0  0xB000
#define Comparator1_CSR1  0xB004
(No 0xB008 register)
#define Comparator1_CSR3  0xB00C
.... on and on, the 0xF000 field ranges from 0x3000-0xD000, the 0xF field ranges from 0>0xC in steps of 0x4 (32b)

我正在尝试调试一些代码,并且需要将整个内存区域从 0x3000 到 0xD00C 读取到设备崩溃时我可以读取的持久存储中(这就是 read_and_store(register_address) 函数的作用)。

不幸的是,我剩下的代码空间非常有限,无法编写可以独立读取每个寄存器的长代码(相信我,我试过了,下面的示例)

我已经提出了一个合理的基于循环的可能解决方案(由于下面描述的原因不起作用),它适合代码空间:

for(int i=3;i<=0xD;i++)
{
    for(int j=0;j<=0x10;j+=4)
    {
        read_and_store_register((0x1000 * i) + (0x4 * j))
    }
}

但我显然正在阅读不存在的内存,这导致我的设备崩溃。有什么方法可以让我通过在读取之前检查它是否存在或其他方法来安全地读取此内存?


尝试读取一个代码块中的所有寄存器会占用比我更多的代码空间:

{    
    read_and_store_register(Comparator0_CSR0)
    read_and_store_register(Comparator0_CSR2)
    read_and_store_register(Comparator0_CSR3)
    read_and_store_register(Comparator1_CSR0)    
    ....
}

所以我需要某种受控循环。

我还想知道是否可以将所有寄存器名称#define 为宏,并在宏中为那些没有与之关联的真实寄存器的寄存器执行某种 read(0),然后执行以下操作:

#define COMP_NAME(x,y) Comparator##x##CSR##y
for(int i=3;i<=0xD;i++)
{
    for(int j=0;j<=0x4;j+=1)
    {
        read_and_store_register(COMP_NAME(i,j))
    }
}

但显然这不是 x##y##z 宏的工作方式(它试图读取一个字面上名为 COMPARATORiCSRj 的寄存器,这根本不是我想要的)


如果答案是否合理,我会接受这个答案。但我觉得我不得不问。感谢您的宝贵时间。

【问题讨论】:

  • 你要读取多少个寄存器,read_and_store_register 是做什么的?也许您可以定义一个包含所有寄存器地址的常量数组并循环遍历该数组?
  • (0xD-0x3)*4=40,在本例中,但无论我需要阅读的数字如何,问题都存在。 Read_and_store 将内存复制到设备崩溃时我可以读取的持久存储系统,我已相应地编辑了问题,谢谢。
  • 如果 CPU 在无效访问时引发中断,则有可能使用 ISR 中止读取/存储的特定调用并推动 for 循环。
  • 您必须研究您的特定设备提供了什么,以测试特定寄存器是否存在,或者如果不存在如何恢复。这个问题没有通用的答案——C 语言本身当然没有这样的概念。因此,为了获得答案,您必须更具体地了解您的设备、编译器、环境等(并请相应地标记)。
  • 在我看来,Bodo 对数组的建议最多需要(0xd - 0x3 + 1) * 4 * 2 bytes = 88 bytes。然后你可以编写一个小而简单的循环来遍历数组。或者,您可以拥有一个不存在的寄存器数组,循环整个集合并跳过数组中的每个寄存器。如果数组是有序的,那么这也不难。

标签: c microcontroller c99


【解决方案1】:

有什么方法可以让我通过在读取之前检查它是否存在或其他方法来安全地读取此内存吗?

C 语言没有定义任何这样的工具。 C 语言也没有定义任何机制来读取存在于程序范围之外的对象。必须这样做的程序(通常在独立的 C 实现中)依赖于其特定实现和执行环境的规定来做到这一点。可以想象,您的实现提供了一个有目的的机制来做您所要求的,但我不会打赌。

我喜欢 @Bodo 在 cmets 中的建议,即创建一个寄存器地址表并在其上循环,而不是探测整个连续范围的地址空间。这样您就可以避免尝试读取无效地址,同时在一定程度上减少代码(+数据)的大小。或者,您可以通过循环连续的寄存器范围来减少代码,而不是使用单独的函数/宏调用来读取每个寄存器。如果您想在汇编中编写代码的某些部分,可能还有其他方法。

但同样,不,C 语言没有定义一种方法来预先检查内存访问是否有效,也没有从无效访问事件中可能发生的任何事情中恢复。

【讨论】:

    猜你喜欢
    • 2012-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-27
    相关资源
    最近更新 更多