IPbus Software——uHAL

2024-05-08 06:18
文章标签 software ipbus uhal

本文主要是介绍IPbus Software——uHAL,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

IPbus Software——uHAL

  • Pre-requisites
    • Connection file
    • Address table
      • 单寄存器地址表
      • hierarchical地址表中单个寄存器
      • 具有绝对地址和相对地址的多个模块
      • 结构相同的多个模块
      • 设置对内存位置的读写访问
      • 内存块和 FIFO
      • 使用位掩码进行单寄存器读写访问
      • fwinfo属性
  • Using IPbus in Python
  • IPbus Example
    • IPbus Example Address Table
    • Connection File
    • IPbus Example Software
  • Reference

uHAL 是硬件访问库 (HAL),它为终端用户提供 C++/Python API实现IPbus 读取、写入和 RMW 事务 。

Pre-requisites

  1. 安装IPbus套件
  2. 添加IPbus路径:IPbus-Software默认安装路径为/opt/cactus
    export LD_LIBRARY_PATH=/opt/cactus/lib:$LD_LIBRARY_PATH
    export PATH=/opt/cactus/bin:$PATH
    
  3. 创建connection or device file
    connection文件中描述了使用何种协议(UDP、PCIe 等)以及 IP 地址;
    与每个 IPbus 端点进行通信的device 文件.
    :IPbus端点:即每个硬件设备 - 通常是 FPGA - 包含控制总线主控器
  4. 创建address table
    address table描述IPbus 端点的地址布局
  5. 如果多个客户端/线程/进程必须同时访问 IPbus UDP 端点,那么你将需要使用 Control Hub

Connection file

在使用 uHAL 与FPGA电路板(其他IPbus端点设备)通信之前,首先需要创建一个配置文件,告诉 uHAL 与哪个电路板通信。
配置文件是一个 XML 文件,例如:

<?xml version="1.0" encoding="UTF-8"?><connections><connection id="dummy.udp.0"        uri="ipbusudp-2.0://localhost:50001"                     address_table="file://dummy_address.xml" /><connection id="dummy.tcp.0"        uri="ipbustcp-2.0://localhost:50002"                     address_table="file://dummy_address.xml" /><connection id="dummy.controlhub.0" uri="chtcp-2.0://localhost:10203?target=127.0.0.1:50001" address_table="file://dummy_address.xml" />
</connections>

每个连接标签都包含三个属性,用于描述设备和用于访问它的协议:

  • id字符串标识符。 CMS 触发器升级项目中 id 的标准命名法是 subsystem.crate.slot。
  • uri:以 URI 格式访问目标设备的协议和位置。 目前有 8 种协议可用:
    • 对于 IPbus 1.3 硬件:chtcp-1.3、ipbusudp-1.3 和 ipbustcp-1.3
    • 对于 IPbus 2.0 硬件:chtcp-2.0、ipbusudp-2.0、ipbustcp-2.0、ipbuspcie-2.0 和 ipbusmmap-2.0
  • address_file:地址表文件的位置,描述了目标设备的寄存器空间。 URI 可以是绝对的或相对于本地文件系统中的连接文件(例如 file://my_adress_file.xml)

如需要与一块烧录了IPbus_firmware的KC705通信,地址表文件my_address_tab.xml, connection file设置如下:

<connections>
<connection id="kc705.udp.0" uri="ipbusudp-2.0://192.168.200.16:50001" address_table="file://my_address_tab.xml"/>
</connections>

Address table

注: IPbus 是 A32/D32 总线,也就是说,它支持高达 32 位宽的地址和高达 32 位宽的数据空间。 然而,任何特定的设备/固件都可以选择仅使用总地址空间的一个受限子集。

<node><node id="reg1" address="0x00000000"/><node id="reg2" address="0x00000001" permission="r"/><node id="reg3" address="0x00000002"><node id="fieldA" mask="0x0000fff"/><node id="fieldB" mask="0x07ff000"/><node id="fieldC" mask="0xf800000"/><node id="reset" mask="0x10000000"/></node><node id="mem1" address="0x00000100" size="256" mode="incremental"/><node id="mem2" address="0x00000200" size="512" mode="incremental" permission="r"/><node id="fifo" address="0x00000003" mode="port" size="16"/><node id="componentA" address="0x00010000" module="file://example-address-componentA.xml"/><node id="componentB" address="0x00020000" module="file://example-address-componentB.xml"/>
</node>

单寄存器地址表

最简单的地址表是一个 XML 文件,例如:

<node><node id="A" address="0x00000000"/>
</node>

该地址表可按如下方式读取:地址 0x00000000 处的 32 位内存空间可通过 id “A”访问。

hierarchical地址表中单个寄存器

为了与固件模块的分层结构一一对应,uHAL 提供 hierarchical结构的地址表。 一个简单hierarchical结构的地址表,如下所示:

<node><node id="B"><node id="A" address="0x00000100"/></node>
</node>

该地址表可按如下方式读取:固件模块“B”在地址 0x00000100 处包含一个 ID 为“A”的 32 位存储单元。

具有绝对地址和相对地址的多个模块

假设有两个不同地址的固件模块,您可以有一个地址表,如:

<node><node id="C1"><node id="A1" address="0x00000200" /><node id="A2" address="0x00000201" /><node id="A3" address="0x00000202" /><node id="A4" address="0x00000203" /></node><node id="C2" address="0x00000300"><node id="A1" address="0x000" /><node id="A2" address="0x001" /><node id="A3" address="0x002" /><node id="A4" address="0x003" /></node>
</node>

在此示例中,模块“C1”和“C2”指的是不同的固件模块。 对于“C1”中的内存位置,我们明确指定了绝对地址,而在“C2”中,我们指定了内存位置相对于父模块的相对地址。 例如,“C2.A2”节点的地址计算如下:

AbsoluteAddress( C2.A2 ) = Address( C2 ) + RelativeAddress( C2.A2 )=   0x00000300  +         0x001=   0x00000301

结构相同的多个模块

假设我们有两个可从单个 IPbus 设备(例如“D1”和“D2”)访问的相同固件模块的实例。 模块的内部地址表结构将是相同的,因此多次键入相同的结构会浪费时间(并且容易出错)。 相反,我们可以通过创建两个地址表来避免重复:

  1. 更高级别的地址表,包含对应于 firwmare 模块的两个实例的两个节点(具有不同的基地址):
 <node><node id="D1" module="file://mymodule.xml" address="0x00000400" /><node id="D2" module="file://mymodule.xml" address="0x00000500" />
</node>
  1. mymodule.xml 文件,它指定了复制模块中寄存器、块 RAM、FIFO 等的布局,并指定了相对于父节点的相对地址:
<node><node id="A1" address="0x00000001" /><node id="A2" address="0x00000002" /><node id="A3" address="0x00000003" /><node id="A4" address="0x00000004" />
</node>

设置对内存位置的读写访问

可以使用权限属性设置节点的访问权限(例如只读、读写等):

<node><node id="EBA" address="0x600" permission="r"/><node id="EBB" address="0x601" permission="read"/><node id="EBC" address="0x602" permission="rw"/><node id="EBD" address="0x603" permission="wr"/><node id="EBE" address="0x604" permission="readwrite"/><node id="EBF" address="0x605" permission="writeread"/><node id="EBG" address="0x606" permission="w" /><node id="EBH" address="0x607" permission="write" />
</node>

这些属性的含义希望是不言而喻的:r 和 read 表示只读 IPbus 端点,而 w 和 write 表示只写端点。 其他四个选项表明 IPbus 端点既可读又可写。 默认情况下,假定 IPbus 端点既可读又可写。

权限当前没有从父级继承到子级,因此在分支上设置权限而不是最终内存位置没有效果。

内存块和 FIFO

可以使用 mode 属性配置对内存块和 FIFO 的访问:

<node><node id="F" address="0x00000700"><node id="A1" address="0x000" /><node id="A2" address="0x001" mode="single"/><node id="A3" address="0x010" mode="block" size="16" /><node id="A4" address="0x020" mode="incremental" size="16" /><node id="A5" address="0x030" mode="inc" size="16" /><node id="A6" address="0x040" mode="port" /><node id="A7" address="0x041" mode="non-incremental" /><node id="A8" address="0x042" mode="non-inc" /></node>
</node>

single表示节点引用单个字(即 32 位)寄存器(例如“F.A1”和“F.A2”)。 如果没有显式声明模式,则 single 是默认模式。 例如,这可用于束过零 (BC0) 计数器。

blockincrementalinc 表示给定地址是具有连续地址空间的寄存器块的基地址。 在这种情况下,尺寸属性是强制性的(例如“F.A3”、“F.A4”和“F.A5”)。 例如,这可以用于捕获 RAM。

portnon-incrementalnon-inc 表示给定地址是一个访问端口,可以接收或提供数据流,但其地址是固定的(例如“F.A6”、“F.A7”和“F.A6”)。 A8”)。 例如,这可用于 JTAG 访问端口。

使用位掩码进行单寄存器读写访问

尽管 IPbus 是面向字的,但能够标记各个位还是很方便的。 如下所示:

<node><node id="G" address="0x00000800"><node id="G0" mask="0x01" /><node id="G1" mask="0x02" /><node id="G2" mask="0x04" /><node id="G3" mask="0x08" /><node id="G4" mask="0xF0" /></node>
</node>

例如,在“G.G3”上执行 IPbus 读取或写入,将在后台执行所有必要的位移。 例如,从 id 为“G.G4”的节点读取一个值实际上会执行适当的操作并返回一个从 0x0 到 0xF 的值,而不是从 0x00 到 0xF0 的值。

应当注意的是,与在完整的 32 位寄存器上操作相比,在位掩码节点上执行许多操作可能会增加不小的开销。 这是由于 IPbus 指令的性质,而不是软件开销。 软件无法知道它是否可以将多个位掩码操作合并到一条指令中,用户需要考虑与此相关的代码结构。

fwinfo属性

比如,如下所示的地址表中,包含两个寄存器,两个存储器和一个包含三个寄存器的子模块。

地址表中对应于固件中独立从机总线的节点fwinfo 属性标识。节点树中的每个“叶”节点必须自己定义“fwinfo”属性,或者有一个定义该属性的祖先节点。在定义此属性的地方,它的值必须是“endpoint”或“endpoint;width=N”,其中“N”是连接到总线分支的从站使用的地址范围的位宽;必须在此属性中为总线解码树中的每个“叶”端点指定宽度。

 <node><node id="reg1" mode="single" address="0x0000" fwinfo="endpoint;width=0"/><node id="reg2" address="0x0002" fwinfo="endpoint;width=0"><node id="upper" mask="0xffff0000"/><node id="lower" mask="0xffff"/></node><node id="mem1" address="0x1000" mode="incremental" size="1024" fwinfo="endpoint;width=10"/><node id="mem2" address="0x1400" mode="incremental" size="1024" fwinfo="endpoint;width=10"/><node id="submodule" address="0x8000" fwinfo="endpoint;width=2"><node id="reg1" address="0x0"/><node id="reg2" address="0x1"/><node id="reg3" address="0x2"/></node></node>

gen_ipbus_addr_decode 脚本沿着节点树向下爬,并创建地址解码逻辑,用于多路复用到具有沿着节点树向下所有路径遇到的fwinfo 属性的第一个节点。例如给定上面的地址表,通过运行 gen_ipbus_addr_decode my_module.xml,下面的 VHDL 将被打印到标准输出:

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use ieee.numeric_std.all;package ipbus_decode_my_module isconstant IPBUS_SEL_WIDTH: positive := 3;subtype ipbus_sel_t is std_logic_vector(IPBUS_SEL_WIDTH - 1 downto 0);function ipbus_sel_my_module(addr : in std_logic_vector(31 downto 0)) return ipbus_sel_t;-- START automatically  generated VHDL the Thu Feb  7 22:57:04 2019 constant N_SLV_REG1: integer := 0;constant N_SLV_REG2: integer := 1;constant N_SLV_MEM1: integer := 2;constant N_SLV_MEM2: integer := 3;constant N_SLV_SUBMODULE: integer := 4;constant N_SLAVES: integer := 5;-- END automatically generated VHDLend ipbus_decode_my_module;package body ipbus_decode_my_module isfunction ipbus_sel_my_module(addr : in std_logic_vector(31 downto 0)) return ipbus_sel_t isvariable sel: ipbus_sel_t;begin-- START automatically  generated VHDL the Thu Feb  7 22:57:04 2019 if    std_match(addr, "----------------0--0-0--------0-") thensel := ipbus_sel_t(to_unsigned(N_SLV_REG1, IPBUS_SEL_WIDTH)); -- reg1 / base 0x00000000 / mask 0x00009402elsif std_match(addr, "----------------0--0-0--------1-") thensel := ipbus_sel_t(to_unsigned(N_SLV_REG2, IPBUS_SEL_WIDTH)); -- reg2 / base 0x00000002 / mask 0x00009402elsif std_match(addr, "----------------0--1-0----------") thensel := ipbus_sel_t(to_unsigned(N_SLV_MEM1, IPBUS_SEL_WIDTH)); -- mem1 / base 0x00001000 / mask 0x00009400elsif std_match(addr, "----------------0--1-1----------") thensel := ipbus_sel_t(to_unsigned(N_SLV_MEM2, IPBUS_SEL_WIDTH)); -- mem2 / base 0x00001400 / mask 0x00009400elsif std_match(addr, "----------------1--0-0----------") thensel := ipbus_sel_t(to_unsigned(N_SLV_SUBMODULE, IPBUS_SEL_WIDTH)); -- submodule / base 0x00008000 / mask 0x00009400-- END automatically generated VHDLelsesel := ipbus_sel_t(to_unsigned(N_SLAVES, IPBUS_SEL_WIDTH));end if;return sel;end function ipbus_sel_my_module;end ipbus_decode_my_module;

可以看到这个 VHDL 定义了一个包,ipbus_decode_my_module,包含:

  • 一个整数常量 - 名为 N_SLV_<node id path> - 用于在上述地址表中具有 fwinfo 属性的每个节点
  • 一个函数,ipbus_sel_my_module,当给定总线地址时返回适当常量的值

Using IPbus in Python

Python API(即函数和类名)与 C++ 中的基本相同,但所有 std::vector 实例都替换为 Python 列表。

import uhal
# Or if using uHAL v1.0.6 (now an old version)
import pycohal as uhal# PART 1: Creating the HwInterface
usingConnectionFile = True
manager = uhal.ConnectionManager("file://path/to/connection/file/connections.xml")
hw = manager.getDevice("hcal.crate1.slot1")# PART 2: Reading from the register
# Queue a write to register
hw.getNode("REG").write(1)# Read the value back.
# NB: the reg variable below is a uHAL "ValWord", not just a simple integer
reg = hw.getNode("REG").read()# Send IPbus transactions
hw.dispatch()# Print the register value to screen as a decimal:
print " REG =", reg# Print the register value to screen in hex:
print " REG =", hex(reg)# Get the underlying integer value from the reg "ValWord"
value = int(reg) # Equivalent to reg.value()

IPbus Example

以IPbus-Firmware中top_kc705_gmii中的demo为例

IPbus Example Address Table

top_kc705_gmii中的address table文件内容如下:

<node><node id="csr" address="0x0" description="ctrl/stat register" fwinfo="endpoint;width=1"><node id="ctrl" address="0x0"><node id="rst" mask="0x1"/><node id="nuke" mask="0x2"/><node id="led" mask="0x4"/></node><node id="stat" address="0x1"/></node><node id="reg" address="0x2" description="read-write register" fwinfo="endpoint;width=0"/><node id="ram" address="0x1000" mode="block" size="0x400" description="1kword RAM" fwinfo="endpoint;width=12"/><node id="pram" address="0x2000" description="1kword peephole RAM" fwinfo="endpoint;width=1"><node id="addr" address="0x0"/><node id="data" mode="port" size="0x400" address="0x1"/></node>
</node>

Connection File

<connections><connection id="ipbus_example.udp.0"        uri="ipbusudp-2.0://192.168.1.16:50001"                  address_table="file://etc/address_tab.xml" />
</connections>

IPbus Example Software

import uhal
import timeif __name__  == '__main__':device_name = "ipbus_example.udp.0"device_ip = "192.168.1.16"protocol = "ipbusudp-2.0"socket_port = "50001"address_file = "address_tab.xml"device_uri = protocol + "://" + device_ip + ":" + socket_portaddr_tab_uri ="file://" + address_fileprint("device_uri :", device_uri)print("address_uri:", addr_tab_uri)usingConnectionFile = Falseif usingConnectionFile:hw = uhal.ConnectionManager("file://connection_file.xml")else:hw = uhal.getDevice(device_name,device_uri,addr_tab_uri)timeout = hw.getTimeoutPeriod()  print("Connected With IPbus Firmware Using " ,timeout, "Period")# turn led onhw.getNode("csr.ctrl.led").write(1)hw.dispatch()time.sleep(10)# turn led offhw.getNode("csr.ctrl.led").write(0)hw.dispatch()

Reference

  1. uHAL quick tutoiral
  2. fwinfo属性

这篇关于IPbus Software——uHAL的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/969544

相关文章

关于javaSocket中 Software caused connection abort: recv failed问题

在学习Socket中今天突然遇到了下面这样的问题 原来是网路连接出了问题,因为我测试的是远程连接所以是在学校的局域网下,结果很不稳定,开始还以为怎么了一会连上了一会又出现问题然后把IP地址改为本机的127.0.0.1之后就没有 出现过了.

myeclipse中没有software update选项

方法一:你在myeclipse中点Windows-->Preferences 在弹出的对话框的左侧栏,点General-->点Capabilities,然后把Classic Update前的框选上,OK了。 方法二:也可以通过Help-->MyEclipse Configuration Center-->Software-->Add Site的方式进行插件安装。。

导入项目启动报错Unexpectedexception parsing XML document from file[H:\software\apache-tomcat-7.0.77\webapps\

导入项目启动报错Unexpectedexception parsing XML document from file[H:\software\apache-tomcat-7.0.77\webapps\ItcastOA\WEB-INF\classes\applicationContext.xml]       背景介绍: 导入项目报错1: ER

Agile Software Development

Individuals and interactions over processes and tools.(个人和协作超过过程和工具) working software over comprehensive documentation.(工作软件超过完全文档) Customer collaboration over contract negotiation.(客户协作超过合同谈判)

《计算机英语》 Unit 3 Software Engineering 软件工程

Section A Software Engineering Methodologies 软件工程方法论 Software development is an engineering process. 软件开发是一个工程过程。 The goal of researchers in software engineering is to find principles that guide the

MPC5 software example list

MPC5 software example list

开发基于Java语言的SaaS(Software-as-a-Service,软件即服务)模式的HIS系统详解 HIS系统源码 支持二开

开发基于Java语言的SaaS(Software-as-a-Service,软件即服务)模式的HIS系统详解  HIS系统源码 支持二开 开发基于Java语言的SaaS(Software-as-a-Service,软件即服务)模式的HIS(Hospital Information System,医院信息系统)是一个复杂的项目,它涉及多个方面,包括技术选型、系统架构、安全性、多租户支持等。

Comparative Study of Deep Learning Software Frameworks( caffe、Neon、TensorFlow、Theano、Torch 之比较)

reference:http://blog.csdn.net/u010167269/article/details/51810613 Preface 最近不少人问我哪个开源框架好用,我自己用过 caffe、TensorFlow、Theano、Torch,用过之后虽然有一定的感觉。但我想很多东西需要实验来具体的验证。 正好我看自己的 Mendeley 中有一篇这个文章:《Comp

从软件设计角度下的操作系统发展轨迹——From the perspective of the software design of operating system course

操作系统首先是一个软件,它的设计脱离不了软件设计的范畴。从纯软件发展的角度对其进行考察,有助于我们了解操作系统的历史。下表给出了软件设计角度下的操作系统发展轨迹。     主流操作系统 系统特点 计算机语言 软件特点 背  景 无软件时期 无 手工操作 无编程语言,直接使用机器代码 手工操作 1936年图灵提出图灵机模型 系

node环境问题(无法加载文件D:\Software\Node.js\node_global\vue.ps1,因为在此系统上禁止运行脚本。)

问题:npm安装lerna显示安装成功,但是lerna -v的时候报错 解决步骤: 1、输入:Get-ExecutionPolicy 2、输入:Set-ExecutionPolicy -Scope CurrentUser(有选项的选Y) 3、输入:RemoteSigned,回车即可 4、输入:lerna -v 5、显示lerna 的版本,则能正常使用