xclock: refine fast_mode_level==2
English Readme
xspcomm 为 picker 的公用数据定义与操作接口,包括接口读/写、时钟、协程、SWIG回调函数定义等。xspcomm以基础组件的方式被 DUT、MLVP、OVIP等上层应用或者库使用。xspcomm需要用到C++20的特征,建议使用g++ 11 以上版本, cmake 版本大于等于3.11。当通过SWIG导出Python接口时,需要 swig 版本大于等于 4.2.0。
编译: 通过make命令进行编译, 通过参数 BUILD_XSPCOMM_SWIG 可开启Python等语言支持 (目前swig接口支持python, javascript, java, scala, golang, lua),编译完成后生成文件位于 build目录:
make BUILD_XSPCOMM_SWIG=python,scala,java,golang,lua # results build/python/ └── xspcomm # python 模块 ├── __init__.py ├── _pyxspcomm.so -> _pyxspcomm.so.0.0.1 ├── _pyxspcomm.so.0.0.1 ├── info.py └── pyxspcomm.py build/scala/ └── xspcomm-scala.jar # scala 模块 build/java/ └── xspcomm-java.jar # java 模块 build/lua ├── luaxspcomm.so -> luaxspcomm.so.0.0.1 ├── luaxspcomm.so.0.0.1 └── xspcomm.lua build/golang/ └── src # golang 模块 └── xspcomm ├── golangxspcomm.so -> golangxspcomm.so.0.0.1 ├── golangxspcomm.so.0.0.1 └── xspcomm.go
测试: make命令默认编译执行 tests/test_xdata.cpp。 若要运行 tests/tests_python.py 执行如下命令:
$make BUILD_XSPCOMM_SWIG=python $make test_python
打包与安装:(python wheel) 默认打包so动态库和头文件,打包PYTHON需要开启 BUILD_XSPCOMM_SWIG=python
$pip install pipx $cd xcomm $BUILD_XSPCOMM_SWIG=python pipx run build // 打包
打包完成后,会在dist目录生成 whl 安装包
安装测试
$pip install dist/pyxspcomm-0.0.1-cp310-cp310-manylinux_2_35_x86_64.whl $python -m xspcomm.info --help # 仅在开启 BUILD_XSPCOMM_SWIG=python 后才有该命令 Usage: python -m xspcomm.info [option] --help: print this help --export: print export cmd of XSPCOMM_ROOT, XSPCOMM_INCLUDE, XSPCOMM_LIB --version: print python wrapper version --root: print xcomm root path --include: print xcomm include path --lib: print xcomm lib path --path: print xcomm all path [default]
xspcomm 包含操作DUT(Design Under Test)的基本数据类型:XData、XPort、XClock三种数据定义。
XData 主要接口与成员变量:
初始化
// 默认构造函数 XData(); // 重新初始化, width 表示引脚(Pin)宽度 // itype 表示引脚(Pin)输入输出模式:Input、Output、InOut // name 表示引脚(Pin)名称 void ReInit(uint32_t width, IOType itype, std::string name = ""); // 同 ReInit XData(uint32_t width, IOType itype, std::string name = "");
绑定DPI
void BindDPIRW(xfunction<void, void *> read, xfunction<void, void *> write); void BindDPIRW(xfunction<void, void *> read, xfunction<void, unsigned char> write);
设置引脚模式: WriteMode::Imme 立即写入, WriteMode::Rise 上升沿写入, WriteMode::Fall 下降沿写入。XData默认情况下为上升沿写入。
bool SetWriteMode(WriteMode mode);
赋值运算
XData a(128, IOType::Input); a = 0x1234 // 直接赋值 int, unsigned int 等 a = "0b11011" // 通过字符串进行二进制赋值 a = "0b1101z" // 通过字符串进行二进制赋值,最后一位设置成高阻态 a = "0xfffff" // 通过字符串进行八进制赋值 a = "::fffff" // 直接赋值字符串ascii码 a = "X" // 设置128位全为不定态 // 通过vector读写数据 uint8 buffer[128/8] a.GetBits(buffer, sizeof(buffer)); a.SetBits(buffer, sizeof(buffer)); // 读取数据到buffer 或者 vector std::vector<unsigned char> vector(buffer) auto ret = a.GetBytes() a.SetBytes(vector); uint32_t x = a.W(); // 转 uint32 uint64_t x =a.U(); // 转 uint64 int64_t x = a.S(); // 转 int64 bool x = a.B(); // 转 bool std::string a.String() // 转 string XData b(128, IOType::Input); a = b // 同类型赋值
成员变量
std::string mName; // XData 名字 IOType mIOType; // 输入输出类型 uint32_t mWidth; // 位宽(bit)
XPort 主要接口与成员变量:
XPort(std::string prefix = "");
主要方法
int PortCount(); // 引脚个数 bool Add(std::string pin, xspcomm::XData &pin_data); // 添加引脚 bool Del(std::string pin); // 删除引脚 bool Connect(XPort &target); // 和另外一个port进行连接 XPort &NewSubPort(std::string subprefix); // 创建子port xspcomm::XData &operator[](std::string key); // 按key获取引脚 xspcomm::XData &Get(std::string key, bool raw_key = false); // 同上 XPort &Flip(); // port中所有引脚值进行反转 XPort &AsBiIO(); // 把port中所有引脚设置为BiIO模式 XPort &WriteOnRise(); // 通过DPI写入所有引脚的值(在clock的上升沿被调用) XPort &WriteOnFall(); // 通过DPI写入所有引脚的值(在clock的下降沿被调用) XPort &ReadFresh(xspcomm::WriteMode m); // 刷新引脚读书(通过DPI) XPort &SetZero(); // 设置所有引脚的值为 0
std::string prefix; // 引脚(XData)名称前缀 std::map<std::string, xspcomm::XData *> port_list; // 引脚列表
XClock 主要接口与成员变量:
// stepfunc 为 DUT后端提供的电路推进方法,例如 verilaor 的 step_eval 等 // xfunction<ret, Args...> 功能等价于 std::function<ret(Args...)>,主用于SWIG导出 XClock(); XClock(xfunction<int, bool> stepfunc, std::initializer_list<xspcomm::XData *> clock_pins = {}, std::initializer_list<xspcomm::XPort *> ports = {}); void ReInit(xfunction<int, bool> stepfunc, std::initializer_list<xspcomm::XData *> clock_pins = {}, std::initializer_list<xspcomm::XPort *> ports = {});
void Add(xspcomm::XData &d); // 添加 clk 引脚 void Add(xspcomm::XPort &d); // 添加 port void Step(int s = 1); // 推进时钟 void RunStep(int s = 1); // 同上 void Reset(); // 重置 // 添加上升沿回调 void StepRis(xfunction<void, u_int64_t, void *> func, void *args = nullptr, std::string desc = ""); // 添加下降沿回调 void StepFal(xfunction<void, u_int64_t, void *> func, void *args = nullptr, std::string desc = ""); // 异步方法 XStep AStep(int i = 1); // 等待 i 个 step XCondition ACondition(std::function<bool(void)> checker); // 条件等待 XNext ANext(int n = 1); // 等待 i 个调度 void eval(); // 推动电路执行,不更新波形(仅用于组合逻辑,慎用) void eval_t(); // 推动电路执行,更新波形(不建议使用)
xspcomm在clock类中提供AStep(int i = 1)、ACondition(std::function<bool(void)> checker)、ANext(int n = 1) 三个协程方法,可用于异步编程,示例伪代码如下:
#include "xspcomm/xclock" #include "xspcomm/xcoroutine.h" ... // 接收数据 xcoroutine<bool> send(XClock &clk, XPort &port){ // 等待port中的 a_valid 信号拉高 co_await clck.ACondition([&port](){return port["a_valid"]==1;}); // 返回结果 co_return port["data"] == 0xffff; } // 循环接收,打印结果 xcoroutine<> infinite_loop(XClock &clk, XPort &port){ while(true){ auto ret = co_await send(clk, port); printf("send result is 0xffff: %s\n", ret ? "Yes":"No"); // 等待下一个时钟 co_await clk.AStep(); } } int main(){ ... // 开启协程 infinite_loop(clk, port); // 推动1000个时钟(协程默认会在Step过程中进行调度) clk.Step(1000); return 0; }
SWIG生成的python模块名称为 xspcomm,包含XData、XPort、XClock等基础类。同C++一样支持的异步方法有:XClock.AStep,XClock.ACondition,XClock.ANext。新增加异步方法 XClock.RunStep 用于驱动xclock,功能同同步模式下的 XClock.Step。
from xspcomm import * from asyncio import run, create_task async def test_async(): clk = XClock(lambda a: 0) clk.StepRis(lambda c : print("lambda ris: ", c)) task = create_task(clk.RunStep(30)) print("test AStep:", clk.clk) await clk.AStep(3) print("test ACondition:", clk.clk) await clk.ACondition(lambda: clk.clk == 20) print("test cpm:", clk.clk) await task if __name__ == "__main__": print("version: %s" % version()) run(test_async())
本项目提供基于 UVMC 的方式进行 UVM 和 Python(C++)的通信
以VCS为例,DUT示例编译骤如下:
... # 1 通过swig生成python wrapper $swig -D'MODULE_NAME="tlm_pbsb"' -python -c++ -DUSE_VCS -I${XSP_COMM_INCLUDE} \ -o tlmps.cpp ${XSP_COMM_INCLUDE}/xspcomm/python_tlm_pbsb.i # 2 编译通信模块 $SYSCAN -full64 -cflags -DUSE_VCS -cflags -I{PYTHON_INCLUDE} \ -cflags -I${XSP_COMM_INCLUDE} ${XSP_COMM_INCLUDE}/xspcomm/tlm_pbsb.cpp tlmps.cpp # 3 以slave模式编译 DUT $VLOGAN -full64 +incdir+common tlm.sv +define+UVM_OBJECT_MUST_HAVE_CONSTRUCTOR $VCS -e VcsMain -full64 sv_main ${VCS_HOME}/linux64/lib/vcs_tls.o -slave # 4 重命名 $mv simv _tlm_pbsb.so $mv simv.daidir _tlm_pbsb.so.daidir ...
编译完成后,可以通过 import 加载dut,具体例子请参考:tests/tlm
头文件 xspcomm/xutil.h 提供以下基本功能
LogLevel get_log_level() // 获取当前日志 level void set_log_level(LogLevel val) // 设置当前日志 level Info(fmt, ...) // 日志 Info Warn(fmt, ...) // 日志 Warn Error(fmt, ...) // 日志 Error Debug(fmt, ...) // 日志 Debug debug(c, fmt, ...) // 日志 Debug,但c为true时打印日志 Fatal(fmt, ...) // 日志 Fatal, 打印日志,退出执行 Assert(c, fmt, ...) // 断言,但c为false时,打印日志,退出执行 // 格式化字符串,eg: auto str = sFmt("Hello %s", "World!") std::string sFmt(const std::string &format, Args... args) // 数组转 hex (string 格式) inline std::string sArrayHex(unsigned char *buff, int size) // 判断string是否时 prefix开头 inline bool sWith(const std::string &str, const std::string &prefix) // 判断vector是否含有 a inline bool contians(std::vector<T> v, T a) // 字符串转小写 inline std::string sLower(std::string input) // 单位转换: int i 转 KB, MB, GB inline std::string FmtSize(u_int64_t s) // 编译优化指导 likely(cond) unlikely(cond) // 获取随机数 inline u_int64_t xRandom(u_int64_t a, u_int64_t b) // 设置随机种子 inline void XSeed(unsigned int seed) // 判断头文件版本与库版本是否匹配 inline bool checkVersion() // 循环 n 次,,eg: FOR_COUNT(10){i++;} FOR_COUNT(n)
xinstance.h 仅仅用于实例化模板类,无其他作用。
xspcomm encapsulates the DPI-based digital circuit and provides various high-level language operation interfaces.
©Copyright 2023 CCF 开源发展委员会 Powered by Trustie& IntelliDE 京ICP备13000930号
介绍
English Readme
xspcomm 为 picker 的公用数据定义与操作接口,包括接口读/写、时钟、协程、SWIG回调函数定义等。xspcomm以基础组件的方式被 DUT、MLVP、OVIP等上层应用或者库使用。xspcomm需要用到C++20的特征,建议使用g++ 11 以上版本, cmake 版本大于等于3.11。当通过SWIG导出Python接口时,需要 swig 版本大于等于 4.2.0。
编译: 通过make命令进行编译, 通过参数 BUILD_XSPCOMM_SWIG 可开启Python等语言支持 (目前swig接口支持python, javascript, java, scala, golang, lua),编译完成后生成文件位于 build目录:
测试: make命令默认编译执行 tests/test_xdata.cpp。 若要运行 tests/tests_python.py 执行如下命令:
打包与安装:(python wheel) 默认打包so动态库和头文件,打包PYTHON需要开启 BUILD_XSPCOMM_SWIG=python
打包完成后,会在dist目录生成 whl 安装包
安装测试
xspcomm的使用
一、基本数据操作
xspcomm 包含操作DUT(Design Under Test)的基本数据类型:XData、XPort、XClock三种数据定义。
XData 主要接口与成员变量:
初始化
绑定DPI
设置引脚模式: WriteMode::Imme 立即写入, WriteMode::Rise 上升沿写入, WriteMode::Fall 下降沿写入。XData默认情况下为上升沿写入。
赋值运算
成员变量
XPort 主要接口与成员变量:
初始化
主要方法
成员变量
XClock 主要接口与成员变量:
初始化
主要方法
二、异步(协程)编程
xspcomm在clock类中提供AStep(int i = 1)、ACondition(std::function<bool(void)> checker)、ANext(int n = 1) 三个协程方法,可用于异步编程,示例伪代码如下:
三、python 编程
SWIG生成的python模块名称为 xspcomm,包含XData、XPort、XClock等基础类。同C++一样支持的异步方法有:XClock.AStep,XClock.ACondition,XClock.ANext。新增加异步方法 XClock.RunStep 用于驱动xclock,功能同同步模式下的 XClock.Step。
四、通过 TLM 连通 UVM 与 Python
本项目提供基于 UVMC 的方式进行 UVM 和 Python(C++)的通信
以VCS为例,DUT示例编译骤如下:
编译完成后,可以通过 import 加载dut,具体例子请参考:tests/tlm
五、其他可用接口
头文件 xspcomm/xutil.h 提供以下基本功能
xinstance.h 仅仅用于实例化模板类,无其他作用。