toffee基本使用
1. 异步环境
toffee 使用了 Python 的协程来完成对异步程序的管理,其在单线程之上建立了一个事件循环,用于管理多个同时运行的协程,协程之间可以相互等待并通过事件循环来进行切换。
1.1 基本关键字
当函数前加上async
关键字时,这个函数就变成了一个协程函数,例如:
async def my_coro():...
当我们在协程函数内部使用 await
关键字时,我们就可以执行一个协程函数,并等待其执行完成并返回结果,例如:
async def my_coro():return "my_coro"async def my_coro2():result = await my_coro()print(result)
如果不需要等待函数完成,使用create_task
方法将函数加入后台运行:
import toffeeasync def my_coro():return "my_coro"async def my_coro2():toffee.create_task(my_coro())
在toffee中使用toffee.run
启动事件循环,并运行异步程序:
import toffeetoffee.run(my_coro2())
在toffee中需要先启动事件循环,然后才能在事件循环中创建验证环境:
import toffeeasync def start_test():# 创建验证环境env = MyEnv()...toffee.run(start_test())
1.2 时钟管理
在 toffee 中,通过start_clock
来创建后台时钟:
import toffeeasync def start_test():dut = MyDUT()toffee.start_clock(dut)toffee.run(start_test())
在其他协程中,我们可以通过 ClockCycles
来等待时钟信号到来,ClockCycles
的参数可以是 DUT,也可以是 DUT 的每一个引脚。例如:
import toffee
from toffee.triggers import *async my_coro(dut):await ClockCycles(dut, 10)print("10 cycles passed")async def start_test():dut = MyDUT()toffee.start_clock(dut)await my_coro(dut)toffee.run(start_test())
每当十个周期,my_coro()就会继续执行,打印文字。更多等待时钟信号的方法见API文档(?还没完善)。
2. Bundle 使用
Bundle用于测试环境与DUT的解耦,一个简单的Bundle定义如下:
from toffee import Bundle, Signalsclass AdderBundle(Bundle):a, b, sum, cin, cout = Signals(5)
它继承toffee中的Bundle类,定义了几个接口。随后可以创建AdderBundle实例,通过x.value来访问信号:
adder_bundle = AdderBundle()adder_bundle.a.value = 1
adder_bundle.b.value = 2
adder_bundle.cin.value = 0
print(adder_bundle.sum.value)
print(adder_bundle.cout.value)
2.1 DUT与Bundle的绑定
如果一个DUT与一个Bundle的接口信号完全相同,可以使用bind
方法进行绑定:
adder = DUTAdder()adder_bundle = AdderBundle()
adder_bundle.bind(adder)
同时toffee也提供了一些方法用于两者的绑定
2.1.1 通过字典进行绑定
假设 Bundle 中的接口名称与 DUT 中的接口名称拥有如下对应关系:
a -> a_in
b -> b_in
sum -> sum_out
cin -> cin_in
cout -> cout_out
在创建Bundle
时可以使用from_dict
方法传入一个字典,告知Bundle
以这种方式绑定DUT引脚:
adder = DUTAdder()
adder_bundle = AdderBundle.from_dict({'a': 'a_in','b': 'b_in','sum': 'sum_out','cin': 'cin_in','cout': 'cout_out'
})
adder_bundle.bind(adder)
2.1.2 通过前缀进行绑定
假设 DUT 中的接口名称与 Bundle 中的接口名称如上所示,实际 DUT 的接口名称比Bundle中的名称多了一个io_
,
可以使用from_prefix
方法创建Bundle
,告知Bundle
以前缀的方式完成绑定:
adder = DUTAdder()
adder_bundle = AdderBundle.from_prefix('io_')
adder_bundle.bind(adder)
2.1.3 通过正则表达式进行绑定
有时候DUT 中的接口名称与 Bundle 中的接口名称之间有一些复杂的前缀后缀:
a -> io_a_in
b -> io_b_in
sum -> io_sum_out
cin -> io_cin_in
cout -> io_cout_out
在这种情况下,我们可以通过传入正则表达式,来告知 Bundle
以正则表达式的方式进行绑定:
adder = DUTAdder()
adder_bundle = AdderBundle.from_regex(r'io_(.*)_.*')
adder_bundle.bind(adder)
2.2 创建子Bundle
未完待续