Version 1 (modified by 5 years ago) (diff) | ,
---|
The uHAL / IPBus software+firmware package (source) provides a convenient way to read/write registers and memories on a hardware device. The original use case was to access programmable logic (FPGAs) on a board connected to a computer over Ethernet.
The software component (uHAL) queues requested operations (read and write) in a "packet" which is transmitted to the hardware device when a dispatch function is called. The firmware component (IPBus) parses the packet and performs the requested read and write operations in a logical 32-bit address space using a proprietary local bus (similar to Wishbone).
A key feature of the package is the address table which is represented by one or more XML files. Typically an address table names registers as in the following example:
<node id="REG" address="0x0001" permission="rw"> <node id="REG_TOP" mask="0xffff0000"/> <node id="REG_BOT" mask="0x0000ffff"/> </node> <node id="RESETS" address="0x0002" permission="w"> <node id="RST_ALL" mask="1"/> <node id="RST_LINKS" mask="2"/> </node>
A bit of sample code taken from the tutorial illustrates the key points:
ConnectionManager manager("file://path/to/connections.xml"); HwInterface hw = manager.getDevice("dummy.udp.0"); //write 1 in the address 0x0001 hw.getNode ("REG").write(1); //read back ValWord< uint32_t > reg = hw.getNode ("REG").read(); //send the IPbus transactions hw.dispatch(); std::cout << "REG = " << reg.value() << std::endl;
This code illustrates the typical use case, where one performs reads/writes on entire 32-bit registers using names from the address table. In addition, the address table can contain a mask, which can be used to read or write subsets of bits from a register. However one must be careful, as the protocol only supports full 32-bit reads and writes. Writing a masked value actually causes a read/modify/write which may not be what is desired.
Often we find that we want to do other things which are not trivially supported by uHAL, such as:
- Read/write to numeric addresses
- Read/write to an offset within a named region
- Write a fixed set of bits to a register with no read
All these things can be accomplished, but require some cleverness. To access the numeric address of a register, one can use the following code snippet:
addr = hw.getNode( "rx_buffer").getAddress();
To access an offset from a named register, one must resort to some slightly more intricate code:
val = hw.getClient().read( addr + offset);