【发布时间】:2017-11-21 21:13:35
【问题描述】:
问题
我正在尝试将多个基于硬件的产品的大型平台抽象库 (PAL) 移植到资源有限(即 千字节数)的小型嵌入式系统。
当前 PAL 有一个简单的getRegister() 函数,它返回特定产品的寄存器地址。例如,假设产品名为 coconut 和 pineapple,代码将如下所示:
#include "headers/Include/coconut.h"
#include "headers/Include/pineapple.h"
enum prodType {
PROD_COCONUT = 0,
PROD_PINEAPPLE,
PROD_MAX,
PROD_INVALID = (-1)
};
uint64_t getRegister(enum prodType prod, int regName) {
uint64_t r = 0;
switch (prodType) {
case PROD_COCONUT:
switch (regName) {
case REG_BASE:
r = COCONUT_REG_BASE;
break;
case REG_CORE:
r= COCONUT_REG_CORE;
break;
}
break;
case PROD_PINEAPPLE:
switch (regName) {
case REG_BASE:
r = PINEAPPLE_REG_BASE;
break;
case REG_CORE:
r= PINEAPPLE_REG_CORE;
break;
}
break;
default:
// Error.
break;
}
return r;
}
目标
我想将此函数更改为一个简单的编译时宏等效项,以便getRegister(PROD_COCONUT, REG_BASE) 只需查看值表并返回适当的寄存器值。这样做的原因是,如果我知道一个平台只支持coconut,我可以使用宏不包含其他产品的标题(即pineapple),并减少程序大小。
到目前为止工作
到目前为止,我正在考虑这样的事情:
enum regs {
REG_BASE = 0,
REG_CORE,
REG_MAX,
REG_INVALID = (-1)
};
struct keyValPair {
int idx;
enum reg;
uint64_t val;
};
struct keyValPair tableCoconut[] = {
{ 0, REG_BASE, COCONUT_REG_BASE },
{ 1, REG_CORE, COCONUT_REG_CORE },
};
所以,我希望能够对表进行索引,以便tableCoconut[REG_BASE] 返回COCONUT_REG_BASE,在O(1) 时间内返回一个值,而无需迭代/搜索通过表格。理想情况下,它是编译时宏扩展,而不是真正的函数调用。
问题
是否有一种(简单/干净)的方式来实现一些中间映射,以便:
- 我可以从我的
keyValPair结构中删除idx变量(可选)。 - 对映射有
O(1)(即非基于搜索的查找)(必需)?
这是假设寄存器值不连续且唯一? I'm considering using pieces from a slightly similar question of mine from years ago,但不能完全得到这个双射稀疏到连续的映射与宏。我试图通过宏和## 操作创建一个自动递增索引值,以通过## 与预处理器的连接操作创建一个中间索引,其前缀附加到REG_BASE/REG_CORE。
编辑
并非所有产品都具有相同的寄存器。可能有一个banana 产品不提供BANANA_REG_CORE 的条目。
【问题讨论】:
-
为什么包含标题会增加您的程序大小?
-
@melpomene 如果我要做一个巨人,
numProductsbynumRegisters用于数十种产品而不是单个产品的数组,查找表会变得很大。 -
即使您将
getRegister设为内联函数? -
@melpomene 是的,即使在这种情况下。如果结构数组使其更小,我试图通过删除函数来最小化字节数。
-
getRegister是否总是使用常量参数调用?
标签: c linux gcc macros c-preprocessor