Ada 在运行时修改变量地址
我有一个数组和一个像这样声明的变量
NextPacketRegister : array (1 .. Natural (Size)) of Unsigned_32;
PacketBufferPointer : Unsigned_32;
for PacketBufferPointer'Address use To_Address (SPW_PORT_0_OUT_REG_ADDR);
for NextPacketRegister'Address use To_Address (16#A000_0000# + Integer_Address (PacketBufferPointer));
PacketBufferPointer 指向您通过我们主板的 PCI 访问的硬件寄存器。 NextPacketRegister 使用此寄存器的值 + 16#A000_0000#
问题是每次我访问 NextPacketRegister 时,我都会在幕后执行 PCI 访问,这些访问非常慢,我们正在尝试消除此限制。
但我似乎找不到在运行时修改 NextPacketRegister'Address 的方法(我想读取一次 PacketBufferPointer 寄存器,然后仅添加该值 + 16#A000_0000# 一次,这样我就不必执行 PCI 访问每次
我环顾四周,但我不知道如何才能实现这一目标。
I have an array and a variable declared like this
NextPacketRegister : array (1 .. Natural (Size)) of Unsigned_32;
PacketBufferPointer : Unsigned_32;
for PacketBufferPointer'Address use To_Address (SPW_PORT_0_OUT_REG_ADDR);
for NextPacketRegister'Address use To_Address (16#A000_0000# + Integer_Address (PacketBufferPointer));
PacketBufferPointer points to an HW registers that you access thru the PCI of our board.
NextPacketRegister uses this register's value + 16#A000_0000#
The thing is everytime I access NextPacketRegister, behind the scene I perform a PCI access, these access are very slow and we are trying to remove this limitation.
But I can't seem to find a way to modify NextPacketRegister'Address during runtime (I'd like to read ONCE the PacketBufferPointer register and then add this value + 16#A000_0000# only once so I don't have to perform PCI access everytime.
I looked around but I have no clue how I could achieve this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是正确的;如果您使用
for ...'address use
来覆盖特定地址处的对象,则以后无法更改它。一般来说,我会尽量避免重叠。你所表现出来的对他们来说是一个缺点。另一个是,如果对象有任何需要初始化的部分,那么每次详细说明对象时,它们都会被重新初始化。
不过,我必须先问一件事:这看起来像一个设备驱动程序。如果您不喜欢 PCI 总线带来的影响,那也没关系。当然,解决您的问题的明显方法是将对象读入临时变量,并在您不想访问 PCI 总线时使用它。但显然,当您这样做时,您不再直接从设备读取,因此不会看到对其内存映射寄存器所做的更改(并且您的更改不会直接进入那些内存映射寄存器)。这就是你想要的,对吧? Ada 并不包含允许您在不影响 PCI 总线的情况下从 PCI 总线获取数据的魔法。
看起来您几乎认为这一行:
for NextPacketRegister'Address use To_Address (16#A000_0000# + Integer_Address (PacketBufferPointer));
意思是:“每次访问 NextPacketRegister 时,都去查找PacketBufferPointer 并将其覆盖在它现在所在的位置”。事实并非如此。 当您的声明得到处理时,这种情况只会发生一次。此后,对
NextPacketRegister[12]
等内容的每次访问都将前往同一位置,而不会访问PacketBufferPointer
。另一种方法是使用指针和 Unchecked_Conversion。这通常是我首选的覆盖解决方案。它看起来有毛,但你正在做的事情是有毛的,所以它应该看起来像这样。此外,它不会对覆盖的内存区域执行初始化。我想,如果你指望这些的话,这可能是一件坏事。当然,如果您愿意,以这种方式覆盖可能会导致访问
PacketBufferPointer
。您可以根据您的编码方式来控制它。既然您询问了指针,在这种情况下,我认为您有一个非常有效的使用包 System.Address_to_Access_Conversions。我手头没有编译器,但我认为它会是这样的:
现在当你“同步”时,我想你会想要点击 PacketBufferPointer 来获取寄存器值(作为 SYSTEM.ADDRESS),并且将其保存到变量中以供以后使用:
当您想要访问 Next_Packet_Array 时,它将是这样的:
Next_Packet_Array_Convert.To_Pointer (Synced_Next_Packet_Address).all
That is correct; if you use
for ...'address use
to overlay an object at a specific address, you cannot change it later.Generally I try to avoid overlays. What you show is one drawback to them. Another is that if the object has any parts that require initialization, they will be reinitialized every time the object is elaborated.
One thing I do have to ask up front though: This looks like a device driver. If you don't like the hit from going to the PCI bus then, fine. The obvious way around your problem of course is to just read the object into a temporary variable and use that when you don't want to hit the PCI bus. But obviously when you do that you are no longer reading directly from the device, and thus won't see changes it made to its memory-mapped registers (and your changes won't go straight to those memory-mapped registers). That's what you want, right? Ada contains no magic to allow you to get data on and off the PCI bus without hitting the PCI bus.
It almost looks like you are thinking that this line:
for NextPacketRegister'Address use To_Address (16#A000_0000# + Integer_Address (PacketBufferPointer));
Means: "Every time I access NextPacketRegister, go find the value of PacketBufferPointer and overlay it where it happens to be right now". That is not the case. This will only happen once when your declaration is processed. Thereafter, every access to something like
NextPacketRegister[12]
will go to the same place, without any access toPacketBufferPointer
.Another way would be to use pointers and Unchecked_Conversion. That's generally my preferred solution for overlays. It looks hairer, but what you are doing is hairy, so it should look that way. Also, it doesn't perform initializations on the overlaid memory area. I suppose that could be a bad thing though, if you count on those. Of course overlaying this way could cause an access to
PacketBufferPointer
, if you want. You'd have control over it depending on how you code it.Since you asked about pointers, in this case I think you have a very valid case for using the package System.Address_to_Access_Conversions. I don't have the compiler handy, but I think it would go something like this:
Now when you "sync", I guess you'd want to hit that PacketBufferPointer to get the register value (as a SYSTEM.ADDRESS), and save it into a variable for later use:
And when you want to access the Next_Packet_Array, it would be something like this:
Next_Packet_Array_Convert.To_Pointer (Synced_Next_Packet_Address).all
创建一个结构(缓冲区数组?),这就是您的数据包缓冲区集的样子,并将其放置在数组开头的地址处。
从寄存器中读取数组索引。
你可以用任何语言编写 C,甚至是 Ada。
至少它有效并且你得到了一些合理的边界检查。
Make a structure (array of buffers ? ) that is what your set of packet buffers looks like and sit that at the address of the start of the array.
read the array index from the register.
you can write C in any language, even Ada.
At least it works and you get some sensible bounds checks.