我正在尝试通过PCI总线执行小于32位的读取操作,以读取VME桥接芯片(Tundra Universe II),然后将其连接到VME总线上并由目标读取。

目标VME应用程序仅接受D32(读取32位数据宽度),并且将忽略其他任何内容。

如果我使用映射到VME窗口上的位域结构(nmap到主内存),则可以读取> 24位的位域,但是失败的地方最少。即:-

struct works {
    unsigned int a:24;
};

struct fails {
    unsigned int a:1;
    unsigned int b:1;
    unsigned int c:1;
};

struct main {
    works work;
    fails fail;
}
volatile *reg = function_that_creates_and_maps_the_vme_windows_returns_address()

这表明该结构作品被读取为32位,但是a的read via失败结构(例如reg-> fail.a)被分解为X位读取。 (其中X可能是16或8?)

所以问题是:
a)这在哪里缩小?编译器?操作系统?或Tundra芯片?
b)读取操作的实际大小是多少?

我基本上想排除除芯片以外的所有东西。有关该文档的信息可以在网上找到,但是如果可以证明PCI总线上请求的数据宽度为32位,则可以将问题归咎于Tundra芯片!

编辑:-
具体示例,代码为:-
struct SVersion
{
    unsigned title         : 8;
    unsigned pecversion    : 8;
    unsigned majorversion  : 8;
    unsigned minorversion  : 8;
} Version;

所以现在我将其更改为:-
union UPECVersion
{
    struct SVersion
    {
        unsigned title         : 8;
        unsigned pecversion    : 8;
        unsigned majorversion  : 8;
        unsigned minorversion  : 8;
    } Version;
    unsigned int dummy;
};

和基本的主要结构:-
typedef struct SEPUMap
{
    ...
    ...
    UPECVersion PECVersion;

};

所以我仍然必须更改所有基准代码
// perform dummy 32bit read
pEpuMap->PECVersion.dummy;

// get the bits out
x = pEpuMap->PECVersion.Version.minorversion;

而且我怎么知道二读是否真的会像我的原始代码那样再次进行真正的读取呢? (而不是通过联合使用已读取的位!)

最佳答案

例如,Linux内核具有内联函数,这些函数显式处理内存映射的IO读写。在较新的内核中,它是一个很大的宏包装程序,可归结为一个内联汇编movl指令,但在较旧的内核中,其定义如下:

#define readl(addr) (*(volatile unsigned int *) (addr))
#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))

07-24 09:47
查看更多