2

我正在编写一个用户空间驱动程序,用于在 Python 3.5 中访问 FPGA 寄存器,它mmap是 FPGA 的 PCI 地址空间,获得一个memoryview以提供对内存映射寄存器空间的直接访问,然后用于struct.pack_into("<I", ...)将 32 位值写入选定的 32 -位对齐地址。

def write_u32(address, data):
    assert address % 4 == 0, "Address must be 32-bit aligned"
    path = path.lib.Path("/dev/uio0")
    file_size = path.stat().st_size
    with path.open(mode='w+b') as f:
        mv = memoryview(mmap.mmap(f.fileno(), file_size))
        struct.pack_into("<I", mv, address, data)

不幸的是,似乎struct.pack_into写入memset(buf, 0, ...)实际值之前清除了寄存器。通过检查 FPGA 中的写操作,我可以看到寄存器在设置真值之前设置为 0x00000000,因此 PCI 总线上至少有两次写入(实际上对于 32 位访问,有 3 个,两个 0写入,然后是实际数据。64 位涉及六次写入)。这会导致一些寄存器对写入操作的次数进行计数,或者一些“写入时清除”或在写入时触发某些事件的副作用。

我想使用另一种方法将寄存器数据一次性写入内存映射寄存器空间。我已经研究过了ctypes.memmove,它看起来很有希望(还没有工作),但我想知道是否还有其他方法可以做到这一点。

请注意,寄存器读取使用struct.unpack_from效果很好。

请注意,我还通过使用记录所有访问的 QEMU 驱动程序消除了 FPGA——在写入数据之前,我看到了相同的双零写入访问。

4

2 回答 2

3

也许这会根据需要工作?

mv[address:address+4] = struct.pack("<I", data)

更新

从评论中可以看出,上面的代码并没有解决问题。但是,它的以下变体确实如此:

mv_as_int = mv.cast('I')
mv_as_int[address/4] = data

不幸的是,准确理解幕后发生的事情以及 memoryview 究竟为什么会以这种方式运行超出了现代技术的能力,因此将为未来的研究人员提供解决方案。

于 2018-11-27T04:30:54.613 回答
0

你可以尝试这样的事情:

 def __init__(self,offset,size=0x10000):
    self.offset = offset
    self.size = size
    
    mmap_file = os.open('/dev/mem', os.O_RDWR | os.O_SYNC)
    mem = mmap.mmap(mmap_file, self.size,
                    mmap.MAP_SHARED,
                    mmap.PROT_READ | mmap.PROT_WRITE,
                    offset=self.offset)
    os.close(mmap_file)
    self.array = np.frombuffer(mem, np.uint32, self.size >> 2)
    
def wread(self,address):
    idx = address >> 2
    return_val = int(self.array[idx])
    return return_val
    
def wwrite(self,address,data):
    idx = address >> 2
    self.array[idx] = np.uint32(data)
于 2021-01-29T03:42:47.243 回答