Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7606d7d7bd | ||
|
|
dd345e87c3 | ||
|
|
9c0592c16a | ||
|
|
8aab5a7294 | ||
|
|
4f26621e2b | ||
|
|
1b6993d80d | ||
|
|
6d9ed8a2d2 | ||
|
|
d772b73eb2 | ||
|
|
bd88eda17b | ||
|
|
53313699a9 | ||
|
|
3f7193b77c | ||
|
|
2b0b12c68d | ||
|
|
4a91212f37 |
2
.github/workflows/regression-tests.yml
vendored
2
.github/workflows/regression-tests.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [3.6, 3.7, 3.8, 3.9]
|
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ class MemoryInterface:
|
|||||||
self._parent = parent
|
self._parent = parent
|
||||||
self._size = size
|
self._size = size
|
||||||
self._base = base
|
self._base = base
|
||||||
|
self.window_type = Window
|
||||||
|
self.window_pool_type = WindowPool
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -125,17 +127,22 @@ class MemoryInterface:
|
|||||||
async def write_qword(self, address, data, byteorder='little', **kwargs):
|
async def write_qword(self, address, data, byteorder='little', **kwargs):
|
||||||
await self.write_qwords(address, [data], byteorder, **kwargs)
|
await self.write_qwords(address, [data], byteorder, **kwargs)
|
||||||
|
|
||||||
def create_window(self, offset, size):
|
def create_window(self, offset, size=None, window_type=None):
|
||||||
|
if not size or size < 0:
|
||||||
|
size = self.size - offset
|
||||||
|
window_type = window_type or self.window_type or Window
|
||||||
self.check_range(offset, size)
|
self.check_range(offset, size)
|
||||||
return Window(self, offset, size, base=self.get_absolute_address(offset))
|
return window_type(self, offset, size, base=self.get_absolute_address(offset))
|
||||||
|
|
||||||
def create_window_pool(self, offset=None, size=None):
|
def create_window_pool(self, offset=None, size=None, window_pool_type=None, window_type=None):
|
||||||
if offset is None:
|
if offset is None:
|
||||||
offset = 0
|
offset = 0
|
||||||
if size is None:
|
if size is None:
|
||||||
size = self.size - offset
|
size = self.size - offset
|
||||||
|
window_pool_type = window_pool_type or self.window_pool_type or WindowPool
|
||||||
|
window_type = window_type or self.window_type
|
||||||
self.check_range(offset, size)
|
self.check_range(offset, size)
|
||||||
return WindowPool(self, offset, size, base=self.get_absolute_address(offset))
|
return window_pool_type(self, offset, size, base=self.get_absolute_address(offset), window_type=window_type)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return self._size
|
return self._size
|
||||||
@@ -163,12 +170,13 @@ class Window(MemoryInterface):
|
|||||||
|
|
||||||
|
|
||||||
class WindowPool(Window):
|
class WindowPool(Window):
|
||||||
def __init__(self, parent, offset, size, base=None, **kwargs):
|
def __init__(self, parent, offset, size, base=None, window_type=None, **kwargs):
|
||||||
super().__init__(parent, offset, size, base=base, **kwargs)
|
super().__init__(parent, offset, size, base=base, **kwargs)
|
||||||
|
self.window_type = window_type or Window
|
||||||
self.allocator = BuddyAllocator(size)
|
self.allocator = BuddyAllocator(size)
|
||||||
|
|
||||||
def alloc_window(self, size):
|
def alloc_window(self, size, window_type=None):
|
||||||
return self.create_window(self.allocator.alloc(size), size)
|
return self.create_window(self.allocator.alloc(size), size, window_type)
|
||||||
|
|
||||||
|
|
||||||
class Region(MemoryInterface):
|
class Region(MemoryInterface):
|
||||||
@@ -229,6 +237,7 @@ class PeripheralRegion(Region):
|
|||||||
class AddressSpace(Region):
|
class AddressSpace(Region):
|
||||||
def __init__(self, size=2**64, base=0, parent=None, **kwargs):
|
def __init__(self, size=2**64, base=0, parent=None, **kwargs):
|
||||||
super().__init__(size=size, base=base, parent=parent, **kwargs)
|
super().__init__(size=size, base=base, parent=parent, **kwargs)
|
||||||
|
self.pool_type = Pool
|
||||||
self.regions = []
|
self.regions = []
|
||||||
|
|
||||||
def find_regions(self, address, length=1):
|
def find_regions(self, address, length=1):
|
||||||
@@ -297,24 +306,27 @@ class AddressSpace(Region):
|
|||||||
if length > 0:
|
if length > 0:
|
||||||
raise Exception("Invalid address")
|
raise Exception("Invalid address")
|
||||||
|
|
||||||
def create_pool(self, base=None, size=None):
|
def create_pool(self, base=None, size=None, pool_type=None, region_type=None):
|
||||||
if base is None:
|
if base is None:
|
||||||
base = 0
|
base = 0
|
||||||
if size is None:
|
if size is None:
|
||||||
size = self.size - base
|
size = self.size - base
|
||||||
|
pool_type = pool_type or self.pool_type or Pool
|
||||||
self.check_range(base, size)
|
self.check_range(base, size)
|
||||||
pool = Pool(self, base, size)
|
pool = pool_type(self, base, size, region_type=region_type)
|
||||||
self.register_region(pool, base, size)
|
self.register_region(pool, base, size)
|
||||||
return pool
|
return pool
|
||||||
|
|
||||||
|
|
||||||
class Pool(AddressSpace):
|
class Pool(AddressSpace):
|
||||||
def __init__(self, parent, base, size, **kwargs):
|
def __init__(self, parent, base, size, region_type=None, **kwargs):
|
||||||
super().__init__(parent=parent, base=base, size=size, **kwargs)
|
super().__init__(parent=parent, base=base, size=size, **kwargs)
|
||||||
|
self.region_type = region_type or MemoryRegion
|
||||||
self.allocator = BuddyAllocator(size)
|
self.allocator = BuddyAllocator(size)
|
||||||
|
|
||||||
def alloc_region(self, size):
|
def alloc_region(self, size, region_type=None):
|
||||||
|
region_type = region_type or self.region_type or MemoryRegion
|
||||||
base = self.allocator.alloc(size)
|
base = self.allocator.alloc(size)
|
||||||
region = MemoryRegion(size)
|
region = region_type(size)
|
||||||
self.register_region(region, base)
|
self.register_region(region, base)
|
||||||
return region
|
return region
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ AxiAWBus, AxiAWTransaction, AxiAWSource, AxiAWSink, AxiAWMonitor = define_stream
|
|||||||
|
|
||||||
# Write data channel
|
# Write data channel
|
||||||
AxiWBus, AxiWTransaction, AxiWSource, AxiWSink, AxiWMonitor = define_stream("AxiW",
|
AxiWBus, AxiWTransaction, AxiWSource, AxiWSink, AxiWMonitor = define_stream("AxiW",
|
||||||
signals=["wdata", "wstrb", "wlast", "wvalid", "wready"],
|
signals=["wdata", "wlast", "wvalid", "wready"],
|
||||||
optional_signals=["wuser"],
|
optional_signals=["wstrb", "wuser"],
|
||||||
signal_widths={"wlast": 1}
|
signal_widths={"wlast": 1}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ class TagContext:
|
|||||||
|
|
||||||
def _start(self):
|
def _start(self):
|
||||||
if self._cr is None:
|
if self._cr is None:
|
||||||
self._cr = cocotb.fork(self._process_queue())
|
self._cr = cocotb.start_soon(self._process_queue())
|
||||||
|
|
||||||
def _flush(self):
|
def _flush(self):
|
||||||
flushed_cmds = []
|
flushed_cmds = []
|
||||||
@@ -213,6 +213,7 @@ class AxiMasterWrite(Region, Reset):
|
|||||||
self.b_channel.queue_occupancy_limit = 2
|
self.b_channel.queue_occupancy_limit = 2
|
||||||
|
|
||||||
self.write_command_queue = Queue()
|
self.write_command_queue = Queue()
|
||||||
|
self.write_command_queue.queue_occupancy_limit = 2
|
||||||
self.current_write_command = None
|
self.current_write_command = None
|
||||||
|
|
||||||
self.id_count = 2**len(self.aw_channel.bus.awid)
|
self.id_count = 2**len(self.aw_channel.bus.awid)
|
||||||
@@ -241,6 +242,7 @@ class AxiMasterWrite(Region, Reset):
|
|||||||
self.awqos_present = hasattr(self.bus.aw, "awqos")
|
self.awqos_present = hasattr(self.bus.aw, "awqos")
|
||||||
self.awregion_present = hasattr(self.bus.aw, "awregion")
|
self.awregion_present = hasattr(self.bus.aw, "awregion")
|
||||||
self.awuser_present = hasattr(self.bus.aw, "awuser")
|
self.awuser_present = hasattr(self.bus.aw, "awuser")
|
||||||
|
self.wstrb_present = hasattr(self.bus.w, "wstrb")
|
||||||
self.wuser_present = hasattr(self.bus.w, "wuser")
|
self.wuser_present = hasattr(self.bus.w, "wuser")
|
||||||
self.buser_present = hasattr(self.bus.b, "buser")
|
self.buser_present = hasattr(self.bus.b, "buser")
|
||||||
|
|
||||||
@@ -263,7 +265,8 @@ class AxiMasterWrite(Region, Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info(" %s: not present", sig)
|
self.log.info(" %s: not present", sig)
|
||||||
|
|
||||||
assert self.byte_lanes == len(self.w_channel.bus.wstrb)
|
if self.wstrb_present:
|
||||||
|
assert self.byte_lanes == len(self.w_channel.bus.wstrb)
|
||||||
assert self.byte_lanes * self.byte_size == self.width
|
assert self.byte_lanes * self.byte_size == self.width
|
||||||
|
|
||||||
assert len(self.b_channel.bus.bid) == len(self.aw_channel.bus.awid)
|
assert len(self.b_channel.bus.bid) == len(self.aw_channel.bus.awid)
|
||||||
@@ -331,12 +334,10 @@ class AxiMasterWrite(Region, Reset):
|
|||||||
else:
|
else:
|
||||||
wuser = list(wuser)
|
wuser = list(wuser)
|
||||||
|
|
||||||
self.in_flight_operations += 1
|
data = bytes(data)
|
||||||
self._idle.clear()
|
|
||||||
|
|
||||||
cmd = AxiWriteCmd(address, bytes(data), awid, burst, size, lock,
|
cocotb.start_soon(self._write_wrapper(address, data, awid, burst, size,
|
||||||
cache, prot, qos, region, user, wuser, event)
|
lock, cache, prot, qos, region, user, wuser, event))
|
||||||
self.write_command_queue.put_nowait(cmd)
|
|
||||||
|
|
||||||
return event
|
return event
|
||||||
|
|
||||||
@@ -349,10 +350,74 @@ class AxiMasterWrite(Region, Reset):
|
|||||||
|
|
||||||
async def write(self, address, data, awid=None, burst=AxiBurstType.INCR, size=None,
|
async def write(self, address, data, awid=None, burst=AxiBurstType.INCR, size=None,
|
||||||
lock=AxiLockType.NORMAL, cache=0b0011, prot=AxiProt.NONSECURE, qos=0, region=0, user=0, wuser=0):
|
lock=AxiLockType.NORMAL, cache=0b0011, prot=AxiProt.NONSECURE, qos=0, region=0, user=0, wuser=0):
|
||||||
event = self.init_write(address, data, awid, burst, size, lock, cache, prot, qos, region, user, wuser)
|
|
||||||
|
if address < 0 or address >= 2**self.address_width:
|
||||||
|
raise ValueError("Address out of range")
|
||||||
|
|
||||||
|
if isinstance(data, int):
|
||||||
|
raise ValueError("Expected bytes or bytearray for data")
|
||||||
|
|
||||||
|
if awid is None or awid < 0:
|
||||||
|
awid = None
|
||||||
|
elif awid > self.id_count:
|
||||||
|
raise ValueError("Requested ID exceeds maximum ID allowed for ID signal width")
|
||||||
|
|
||||||
|
burst = AxiBurstType(burst)
|
||||||
|
|
||||||
|
if size is None or size < 0:
|
||||||
|
size = self.max_burst_size
|
||||||
|
elif size > self.max_burst_size:
|
||||||
|
raise ValueError("Requested burst size exceeds maximum burst size allowed for bus width")
|
||||||
|
|
||||||
|
lock = AxiLockType(lock)
|
||||||
|
prot = AxiProt(prot)
|
||||||
|
|
||||||
|
if not self.awlock_present and lock != AxiLockType.NORMAL:
|
||||||
|
raise ValueError("awlock sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
if not self.awcache_present and cache != 0b0011:
|
||||||
|
raise ValueError("awcache sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
if not self.awprot_present and prot != AxiProt.NONSECURE:
|
||||||
|
raise ValueError("awprot sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
if not self.awqos_present and qos != 0:
|
||||||
|
raise ValueError("awqos sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
if not self.awregion_present and region != 0:
|
||||||
|
raise ValueError("awregion sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
if not self.awuser_present and user != 0:
|
||||||
|
raise ValueError("awuser sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
if not self.wuser_present and wuser != 0:
|
||||||
|
raise ValueError("wuser sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
if wuser is None:
|
||||||
|
wuser = 0
|
||||||
|
elif isinstance(wuser, int):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
wuser = list(wuser)
|
||||||
|
|
||||||
|
event = Event()
|
||||||
|
data = bytes(data)
|
||||||
|
|
||||||
|
self.in_flight_operations += 1
|
||||||
|
self._idle.clear()
|
||||||
|
|
||||||
|
cmd = AxiWriteCmd(address, data, awid, burst, size, lock,
|
||||||
|
cache, prot, qos, region, user, wuser, event)
|
||||||
|
await self.write_command_queue.put(cmd)
|
||||||
|
|
||||||
await event.wait()
|
await event.wait()
|
||||||
return event.data
|
return event.data
|
||||||
|
|
||||||
|
async def _write_wrapper(self, address, data, awid, burst, size,
|
||||||
|
lock, cache, prot, qos, region, user, wuser, event):
|
||||||
|
event.set(await self.write(address, data, awid, burst, size,
|
||||||
|
lock, cache, prot, qos, region, user, wuser))
|
||||||
|
|
||||||
def _handle_reset(self, state):
|
def _handle_reset(self, state):
|
||||||
if state:
|
if state:
|
||||||
self.log.info("Reset asserted")
|
self.log.info("Reset asserted")
|
||||||
@@ -392,9 +457,9 @@ class AxiMasterWrite(Region, Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._process_write_cr is None:
|
if self._process_write_cr is None:
|
||||||
self._process_write_cr = cocotb.fork(self._process_write())
|
self._process_write_cr = cocotb.start_soon(self._process_write())
|
||||||
if self._process_write_resp_cr is None:
|
if self._process_write_resp_cr is None:
|
||||||
self._process_write_resp_cr = cocotb.fork(self._process_write_resp())
|
self._process_write_resp_cr = cocotb.start_soon(self._process_write_resp())
|
||||||
|
|
||||||
async def _process_write(self):
|
async def _process_write(self):
|
||||||
while True:
|
while True:
|
||||||
@@ -480,6 +545,9 @@ class AxiMasterWrite(Region, Reset):
|
|||||||
|
|
||||||
n += 1
|
n += 1
|
||||||
|
|
||||||
|
if not self.wstrb_present and strb != self.strb_mask:
|
||||||
|
self.log.warning("Partial operation requested with wstrb not connected, write will be zero-padded (0x%x != 0x%x)", strb, self.strb_mask)
|
||||||
|
|
||||||
w = self.w_channel._transaction_obj()
|
w = self.w_channel._transaction_obj()
|
||||||
w.wdata = val
|
w.wdata = val
|
||||||
w.wstrb = strb
|
w.wstrb = strb
|
||||||
@@ -573,6 +641,7 @@ class AxiMasterRead(Region, Reset):
|
|||||||
self.r_channel.queue_occupancy_limit = 2
|
self.r_channel.queue_occupancy_limit = 2
|
||||||
|
|
||||||
self.read_command_queue = Queue()
|
self.read_command_queue = Queue()
|
||||||
|
self.read_command_queue.queue_occupancy_limit = 2
|
||||||
self.current_read_command = None
|
self.current_read_command = None
|
||||||
|
|
||||||
self.id_count = 2**len(self.ar_channel.bus.arid)
|
self.id_count = 2**len(self.ar_channel.bus.arid)
|
||||||
@@ -678,11 +747,8 @@ class AxiMasterRead(Region, Reset):
|
|||||||
if not self.aruser_present and user != 0:
|
if not self.aruser_present and user != 0:
|
||||||
raise ValueError("aruser sideband signal value specified, but signal is not connected")
|
raise ValueError("aruser sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
self.in_flight_operations += 1
|
cocotb.start_soon(self._read_wrapper(address, length, arid, burst, size,
|
||||||
self._idle.clear()
|
lock, cache, prot, qos, region, user, event))
|
||||||
|
|
||||||
cmd = AxiReadCmd(address, length, arid, burst, size, lock, cache, prot, qos, region, user, event)
|
|
||||||
self.read_command_queue.put_nowait(cmd)
|
|
||||||
|
|
||||||
return event
|
return event
|
||||||
|
|
||||||
@@ -695,10 +761,62 @@ class AxiMasterRead(Region, Reset):
|
|||||||
|
|
||||||
async def read(self, address, length, arid=None, burst=AxiBurstType.INCR, size=None,
|
async def read(self, address, length, arid=None, burst=AxiBurstType.INCR, size=None,
|
||||||
lock=AxiLockType.NORMAL, cache=0b0011, prot=AxiProt.NONSECURE, qos=0, region=0, user=0):
|
lock=AxiLockType.NORMAL, cache=0b0011, prot=AxiProt.NONSECURE, qos=0, region=0, user=0):
|
||||||
event = self.init_read(address, length, arid, burst, size, lock, cache, prot, qos, region, user)
|
|
||||||
|
if address < 0 or address >= 2**self.address_width:
|
||||||
|
raise ValueError("Address out of range")
|
||||||
|
|
||||||
|
if length < 0:
|
||||||
|
raise ValueError("Read length must be positive")
|
||||||
|
|
||||||
|
if arid is None or arid < 0:
|
||||||
|
arid = None
|
||||||
|
elif arid > self.id_count:
|
||||||
|
raise ValueError("Requested ID exceeds maximum ID allowed for ID signal width")
|
||||||
|
|
||||||
|
burst = AxiBurstType(burst)
|
||||||
|
|
||||||
|
if size is None or size < 0:
|
||||||
|
size = self.max_burst_size
|
||||||
|
elif size > self.max_burst_size:
|
||||||
|
raise ValueError("Requested burst size exceeds maximum burst size allowed for bus width")
|
||||||
|
|
||||||
|
lock = AxiLockType(lock)
|
||||||
|
prot = AxiProt(prot)
|
||||||
|
|
||||||
|
if not self.arlock_present and lock != AxiLockType.NORMAL:
|
||||||
|
raise ValueError("arlock sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
if not self.arcache_present and cache != 0b0011:
|
||||||
|
raise ValueError("arcache sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
if not self.arprot_present and prot != AxiProt.NONSECURE:
|
||||||
|
raise ValueError("arprot sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
if not self.arqos_present and qos != 0:
|
||||||
|
raise ValueError("arqos sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
if not self.arregion_present and region != 0:
|
||||||
|
raise ValueError("arregion sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
if not self.aruser_present and user != 0:
|
||||||
|
raise ValueError("aruser sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
event = Event()
|
||||||
|
|
||||||
|
self.in_flight_operations += 1
|
||||||
|
self._idle.clear()
|
||||||
|
|
||||||
|
cmd = AxiReadCmd(address, length, arid, burst, size, lock, cache, prot, qos, region, user, event)
|
||||||
|
await self.read_command_queue.put(cmd)
|
||||||
|
|
||||||
await event.wait()
|
await event.wait()
|
||||||
return event.data
|
return event.data
|
||||||
|
|
||||||
|
async def _read_wrapper(self, address, length, arid, burst, size,
|
||||||
|
lock, cache, prot, qos, region, user, event):
|
||||||
|
event.set(await self.read(address, length, arid, burst, size,
|
||||||
|
lock, cache, prot, qos, region, user))
|
||||||
|
|
||||||
def _handle_reset(self, state):
|
def _handle_reset(self, state):
|
||||||
if state:
|
if state:
|
||||||
self.log.info("Reset asserted")
|
self.log.info("Reset asserted")
|
||||||
@@ -737,9 +855,9 @@ class AxiMasterRead(Region, Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._process_read_cr is None:
|
if self._process_read_cr is None:
|
||||||
self._process_read_cr = cocotb.fork(self._process_read())
|
self._process_read_cr = cocotb.start_soon(self._process_read())
|
||||||
if self._process_read_resp_cr is None:
|
if self._process_read_resp_cr is None:
|
||||||
self._process_read_resp_cr = cocotb.fork(self._process_read_resp())
|
self._process_read_resp_cr = cocotb.start_soon(self._process_read_resp())
|
||||||
|
|
||||||
async def _process_read(self):
|
async def _process_read(self):
|
||||||
while True:
|
while True:
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ class AxiSlaveWrite(Reset):
|
|||||||
|
|
||||||
self.max_burst_size = (self.byte_lanes-1).bit_length()
|
self.max_burst_size = (self.byte_lanes-1).bit_length()
|
||||||
|
|
||||||
|
self.wstrb_present = hasattr(self.bus.w, "wstrb")
|
||||||
|
|
||||||
self.log.info("AXI slave model configuration:")
|
self.log.info("AXI slave model configuration:")
|
||||||
self.log.info(" Address width: %d bits", self.address_width)
|
self.log.info(" Address width: %d bits", self.address_width)
|
||||||
self.log.info(" ID width: %d bits", self.id_width)
|
self.log.info(" ID width: %d bits", self.id_width)
|
||||||
@@ -77,7 +79,8 @@ class AxiSlaveWrite(Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info(" %s: not present", sig)
|
self.log.info(" %s: not present", sig)
|
||||||
|
|
||||||
assert self.byte_lanes == len(self.w_channel.bus.wstrb)
|
if self.wstrb_present:
|
||||||
|
assert self.byte_lanes == len(self.w_channel.bus.wstrb)
|
||||||
assert self.byte_lanes * self.byte_size == self.width
|
assert self.byte_lanes * self.byte_size == self.width
|
||||||
|
|
||||||
assert len(self.b_channel.bus.bid) == len(self.aw_channel.bus.awid)
|
assert len(self.b_channel.bus.bid) == len(self.aw_channel.bus.awid)
|
||||||
@@ -102,7 +105,7 @@ class AxiSlaveWrite(Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._process_write_cr is None:
|
if self._process_write_cr is None:
|
||||||
self._process_write_cr = cocotb.fork(self._process_write())
|
self._process_write_cr = cocotb.start_soon(self._process_write())
|
||||||
|
|
||||||
async def _process_write(self):
|
async def _process_write(self):
|
||||||
while True:
|
while True:
|
||||||
@@ -146,7 +149,10 @@ class AxiSlaveWrite(Reset):
|
|||||||
w = await self.w_channel.recv()
|
w = await self.w_channel.recv()
|
||||||
|
|
||||||
data = int(w.wdata)
|
data = int(w.wdata)
|
||||||
strb = int(getattr(w, 'wstrb', self.strb_mask))
|
if self.wstrb_present:
|
||||||
|
strb = int(getattr(w, 'wstrb', self.strb_mask))
|
||||||
|
else:
|
||||||
|
strb = self.strb_mask
|
||||||
last = int(w.wlast)
|
last = int(w.wlast)
|
||||||
|
|
||||||
# generate operation list
|
# generate operation list
|
||||||
@@ -259,7 +265,7 @@ class AxiSlaveRead(Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._process_read_cr is None:
|
if self._process_read_cr is None:
|
||||||
self._process_read_cr = cocotb.fork(self._process_read())
|
self._process_read_cr = cocotb.start_soon(self._process_read())
|
||||||
|
|
||||||
async def _process_read(self):
|
async def _process_read(self):
|
||||||
while True:
|
while True:
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ AxiLiteAWBus, AxiLiteAWTransaction, AxiLiteAWSource, AxiLiteAWSink, AxiLiteAWMon
|
|||||||
|
|
||||||
# Write data channel
|
# Write data channel
|
||||||
AxiLiteWBus, AxiLiteWTransaction, AxiLiteWSource, AxiLiteWSink, AxiLiteWMonitor = define_stream("AxiLiteW",
|
AxiLiteWBus, AxiLiteWTransaction, AxiLiteWSource, AxiLiteWSink, AxiLiteWMonitor = define_stream("AxiLiteW",
|
||||||
signals=["wdata", "wstrb", "wvalid", "wready"]
|
signals=["wdata", "wvalid", "wready"],
|
||||||
|
optional_signals=["wstrb"]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Write response channel
|
# Write response channel
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ class AxiLiteMasterWrite(Region, Reset):
|
|||||||
self.b_channel.queue_occupancy_limit = 2
|
self.b_channel.queue_occupancy_limit = 2
|
||||||
|
|
||||||
self.write_command_queue = Queue()
|
self.write_command_queue = Queue()
|
||||||
|
self.write_command_queue.queue_occupancy_limit = 2
|
||||||
self.current_write_command = None
|
self.current_write_command = None
|
||||||
|
|
||||||
self.int_write_resp_command_queue = Queue()
|
self.int_write_resp_command_queue = Queue()
|
||||||
@@ -119,6 +120,7 @@ class AxiLiteMasterWrite(Region, Reset):
|
|||||||
self.strb_mask = 2**self.byte_lanes-1
|
self.strb_mask = 2**self.byte_lanes-1
|
||||||
|
|
||||||
self.awprot_present = hasattr(self.bus.aw, "awprot")
|
self.awprot_present = hasattr(self.bus.aw, "awprot")
|
||||||
|
self.wstrb_present = hasattr(self.bus.w, "wstrb")
|
||||||
|
|
||||||
super().__init__(2**self.address_width, **kwargs)
|
super().__init__(2**self.address_width, **kwargs)
|
||||||
|
|
||||||
@@ -135,7 +137,8 @@ class AxiLiteMasterWrite(Region, Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info(" %s: not present", sig)
|
self.log.info(" %s: not present", sig)
|
||||||
|
|
||||||
assert self.byte_lanes == len(self.w_channel.bus.wstrb)
|
if self.wstrb_present:
|
||||||
|
assert self.byte_lanes == len(self.w_channel.bus.wstrb)
|
||||||
assert self.byte_lanes * self.byte_size == self.width
|
assert self.byte_lanes * self.byte_size == self.width
|
||||||
|
|
||||||
self._process_write_cr = None
|
self._process_write_cr = None
|
||||||
@@ -159,10 +162,9 @@ class AxiLiteMasterWrite(Region, Reset):
|
|||||||
if not self.awprot_present and prot != AxiProt.NONSECURE:
|
if not self.awprot_present and prot != AxiProt.NONSECURE:
|
||||||
raise ValueError("awprot sideband signal value specified, but signal is not connected")
|
raise ValueError("awprot sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
self.in_flight_operations += 1
|
data = bytes(data)
|
||||||
self._idle.clear()
|
|
||||||
|
|
||||||
self.write_command_queue.put_nowait(AxiLiteWriteCmd(address, bytes(data), prot, event))
|
cocotb.start_soon(self._write_wrapper(address, bytes(data), prot, event))
|
||||||
|
|
||||||
return event
|
return event
|
||||||
|
|
||||||
@@ -174,10 +176,28 @@ class AxiLiteMasterWrite(Region, Reset):
|
|||||||
await self._idle.wait()
|
await self._idle.wait()
|
||||||
|
|
||||||
async def write(self, address, data, prot=AxiProt.NONSECURE):
|
async def write(self, address, data, prot=AxiProt.NONSECURE):
|
||||||
event = self.init_write(address, data, prot)
|
if address < 0 or address >= 2**self.address_width:
|
||||||
|
raise ValueError("Address out of range")
|
||||||
|
|
||||||
|
if isinstance(data, int):
|
||||||
|
raise ValueError("Expected bytes or bytearray for data")
|
||||||
|
|
||||||
|
if not self.awprot_present and prot != AxiProt.NONSECURE:
|
||||||
|
raise ValueError("awprot sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
event = Event()
|
||||||
|
data = bytes(data)
|
||||||
|
|
||||||
|
self.in_flight_operations += 1
|
||||||
|
self._idle.clear()
|
||||||
|
|
||||||
|
await self.write_command_queue.put(AxiLiteWriteCmd(address, data, prot, event))
|
||||||
await event.wait()
|
await event.wait()
|
||||||
return event.data
|
return event.data
|
||||||
|
|
||||||
|
async def _write_wrapper(self, address, data, prot, event):
|
||||||
|
event.set(await self.write(address, data, prot))
|
||||||
|
|
||||||
def _handle_reset(self, state):
|
def _handle_reset(self, state):
|
||||||
if state:
|
if state:
|
||||||
self.log.info("Reset asserted")
|
self.log.info("Reset asserted")
|
||||||
@@ -220,9 +240,9 @@ class AxiLiteMasterWrite(Region, Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._process_write_cr is None:
|
if self._process_write_cr is None:
|
||||||
self._process_write_cr = cocotb.fork(self._process_write())
|
self._process_write_cr = cocotb.start_soon(self._process_write())
|
||||||
if self._process_write_resp_cr is None:
|
if self._process_write_resp_cr is None:
|
||||||
self._process_write_resp_cr = cocotb.fork(self._process_write_resp())
|
self._process_write_resp_cr = cocotb.start_soon(self._process_write_resp())
|
||||||
|
|
||||||
async def _process_write(self):
|
async def _process_write(self):
|
||||||
while True:
|
while True:
|
||||||
@@ -269,6 +289,9 @@ class AxiLiteMasterWrite(Region, Reset):
|
|||||||
aw.awaddr = word_addr + k*self.byte_lanes
|
aw.awaddr = word_addr + k*self.byte_lanes
|
||||||
aw.awprot = cmd.prot
|
aw.awprot = cmd.prot
|
||||||
|
|
||||||
|
if not self.wstrb_present and strb != self.strb_mask:
|
||||||
|
self.log.warning("Partial operation requested with wstrb not connected, write will be zero-padded (0x%x != 0x%x)", strb, self.strb_mask)
|
||||||
|
|
||||||
w = self.w_channel._transaction_obj()
|
w = self.w_channel._transaction_obj()
|
||||||
w.wdata = val
|
w.wdata = val
|
||||||
w.wstrb = strb
|
w.wstrb = strb
|
||||||
@@ -326,6 +349,7 @@ class AxiLiteMasterRead(Region, Reset):
|
|||||||
self.r_channel.queue_occupancy_limit = 2
|
self.r_channel.queue_occupancy_limit = 2
|
||||||
|
|
||||||
self.read_command_queue = Queue()
|
self.read_command_queue = Queue()
|
||||||
|
self.read_command_queue.queue_occupancy_limit = 2
|
||||||
self.current_read_command = None
|
self.current_read_command = None
|
||||||
|
|
||||||
self.int_read_resp_command_queue = Queue()
|
self.int_read_resp_command_queue = Queue()
|
||||||
@@ -377,10 +401,7 @@ class AxiLiteMasterRead(Region, Reset):
|
|||||||
if not self.arprot_present and prot != AxiProt.NONSECURE:
|
if not self.arprot_present and prot != AxiProt.NONSECURE:
|
||||||
raise ValueError("arprot sideband signal value specified, but signal is not connected")
|
raise ValueError("arprot sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
self.in_flight_operations += 1
|
cocotb.start_soon(self._read_wrapper(address, length, prot, event))
|
||||||
self._idle.clear()
|
|
||||||
|
|
||||||
self.read_command_queue.put_nowait(AxiLiteReadCmd(address, length, prot, event))
|
|
||||||
|
|
||||||
return event
|
return event
|
||||||
|
|
||||||
@@ -392,10 +413,25 @@ class AxiLiteMasterRead(Region, Reset):
|
|||||||
await self._idle.wait()
|
await self._idle.wait()
|
||||||
|
|
||||||
async def read(self, address, length, prot=AxiProt.NONSECURE):
|
async def read(self, address, length, prot=AxiProt.NONSECURE):
|
||||||
event = self.init_read(address, length, prot)
|
if address < 0 or address >= 2**self.address_width:
|
||||||
|
raise ValueError("Address out of range")
|
||||||
|
|
||||||
|
if not self.arprot_present and prot != AxiProt.NONSECURE:
|
||||||
|
raise ValueError("arprot sideband signal value specified, but signal is not connected")
|
||||||
|
|
||||||
|
event = Event()
|
||||||
|
|
||||||
|
self.in_flight_operations += 1
|
||||||
|
self._idle.clear()
|
||||||
|
|
||||||
|
await self.read_command_queue.put(AxiLiteReadCmd(address, length, prot, event))
|
||||||
|
|
||||||
await event.wait()
|
await event.wait()
|
||||||
return event.data
|
return event.data
|
||||||
|
|
||||||
|
async def _read_wrapper(self, address, length, prot, event):
|
||||||
|
event.set(await self.read(address, length, prot))
|
||||||
|
|
||||||
def _handle_reset(self, state):
|
def _handle_reset(self, state):
|
||||||
if state:
|
if state:
|
||||||
self.log.info("Reset asserted")
|
self.log.info("Reset asserted")
|
||||||
@@ -437,9 +473,9 @@ class AxiLiteMasterRead(Region, Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._process_read_cr is None:
|
if self._process_read_cr is None:
|
||||||
self._process_read_cr = cocotb.fork(self._process_read())
|
self._process_read_cr = cocotb.start_soon(self._process_read())
|
||||||
if self._process_read_resp_cr is None:
|
if self._process_read_resp_cr is None:
|
||||||
self._process_read_resp_cr = cocotb.fork(self._process_read_resp())
|
self._process_read_resp_cr = cocotb.start_soon(self._process_read_resp())
|
||||||
|
|
||||||
async def _process_read(self):
|
async def _process_read(self):
|
||||||
while True:
|
while True:
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ class AxiLiteSlaveWrite(Reset):
|
|||||||
self.byte_lanes = self.width // self.byte_size
|
self.byte_lanes = self.width // self.byte_size
|
||||||
self.strb_mask = 2**self.byte_lanes-1
|
self.strb_mask = 2**self.byte_lanes-1
|
||||||
|
|
||||||
|
self.wstrb_present = hasattr(self.bus.w, "wstrb")
|
||||||
|
|
||||||
self.log.info("AXI lite slave model configuration:")
|
self.log.info("AXI lite slave model configuration:")
|
||||||
self.log.info(" Memory size: %d bytes", len(self.mem))
|
self.log.info(" Memory size: %d bytes", len(self.mem))
|
||||||
self.log.info(" Address width: %d bits", self.address_width)
|
self.log.info(" Address width: %d bits", self.address_width)
|
||||||
@@ -74,7 +76,8 @@ class AxiLiteSlaveWrite(Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info(" %s: not present", sig)
|
self.log.info(" %s: not present", sig)
|
||||||
|
|
||||||
assert self.byte_lanes == len(self.w_channel.bus.wstrb)
|
if self.wstrb_present:
|
||||||
|
assert self.byte_lanes == len(self.w_channel.bus.wstrb)
|
||||||
assert self.byte_lanes * self.byte_size == self.width
|
assert self.byte_lanes * self.byte_size == self.width
|
||||||
|
|
||||||
self._process_write_cr = None
|
self._process_write_cr = None
|
||||||
@@ -97,7 +100,7 @@ class AxiLiteSlaveWrite(Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._process_write_cr is None:
|
if self._process_write_cr is None:
|
||||||
self._process_write_cr = cocotb.fork(self._process_write())
|
self._process_write_cr = cocotb.start_soon(self._process_write())
|
||||||
|
|
||||||
async def _process_write(self):
|
async def _process_write(self):
|
||||||
while True:
|
while True:
|
||||||
@@ -109,7 +112,10 @@ class AxiLiteSlaveWrite(Reset):
|
|||||||
w = await self.w_channel.recv()
|
w = await self.w_channel.recv()
|
||||||
|
|
||||||
data = int(w.wdata)
|
data = int(w.wdata)
|
||||||
strb = int(getattr(w, 'wstrb', self.strb_mask))
|
if self.wstrb_present:
|
||||||
|
strb = int(getattr(w, 'wstrb', self.strb_mask))
|
||||||
|
else:
|
||||||
|
strb = self.strb_mask
|
||||||
|
|
||||||
# generate operation list
|
# generate operation list
|
||||||
offset = 0
|
offset = 0
|
||||||
@@ -210,7 +216,7 @@ class AxiLiteSlaveRead(Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._process_read_cr is None:
|
if self._process_read_cr is None:
|
||||||
self._process_read_cr = cocotb.fork(self._process_read())
|
self._process_read_cr = cocotb.start_soon(self._process_read())
|
||||||
|
|
||||||
async def _process_read(self):
|
async def _process_read(self):
|
||||||
while True:
|
while True:
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ class AxiStreamBase(Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._run_cr is None:
|
if self._run_cr is None:
|
||||||
self._run_cr = cocotb.fork(self._run())
|
self._run_cr = cocotb.start_soon(self._run())
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
@@ -388,15 +388,17 @@ class AxiStreamPause:
|
|||||||
self._pause_generator = generator
|
self._pause_generator = generator
|
||||||
|
|
||||||
if self._pause_generator is not None:
|
if self._pause_generator is not None:
|
||||||
self._pause_cr = cocotb.fork(self._run_pause())
|
self._pause_cr = cocotb.start_soon(self._run_pause())
|
||||||
|
|
||||||
def clear_pause_generator(self):
|
def clear_pause_generator(self):
|
||||||
self.set_pause_generator(None)
|
self.set_pause_generator(None)
|
||||||
|
|
||||||
async def _run_pause(self):
|
async def _run_pause(self):
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
for val in self._pause_generator:
|
for val in self._pause_generator:
|
||||||
self.pause = val
|
self.pause = val
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
|
|
||||||
class AxiStreamSource(AxiStreamBase, AxiStreamPause):
|
class AxiStreamSource(AxiStreamBase, AxiStreamPause):
|
||||||
@@ -483,8 +485,10 @@ class AxiStreamSource(AxiStreamBase, AxiStreamPause):
|
|||||||
frame_offset = 0
|
frame_offset = 0
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
# read handshake signals
|
# read handshake signals
|
||||||
tready_sample = (not hasattr(self.bus, "tready")) or self.bus.tready.value
|
tready_sample = (not hasattr(self.bus, "tready")) or self.bus.tready.value
|
||||||
@@ -615,8 +619,10 @@ class AxiStreamMonitor(AxiStreamBase):
|
|||||||
frame = None
|
frame = None
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
# read handshake signals
|
# read handshake signals
|
||||||
tready_sample = (not hasattr(self.bus, "tready")) or self.bus.tready.value
|
tready_sample = (not hasattr(self.bus, "tready")) or self.bus.tready.value
|
||||||
@@ -693,8 +699,10 @@ class AxiStreamSink(AxiStreamMonitor, AxiStreamPause):
|
|||||||
frame = None
|
frame = None
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
# read handshake signals
|
# read handshake signals
|
||||||
tready_sample = (not hasattr(self.bus, "tready")) or self.bus.tready.value
|
tready_sample = (not hasattr(self.bus, "tready")) or self.bus.tready.value
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class Reset:
|
|||||||
self._reset_state = True
|
self._reset_state = True
|
||||||
|
|
||||||
if reset_signal is not None:
|
if reset_signal is not None:
|
||||||
cocotb.fork(self._run_reset(reset_signal, bool(active_level)))
|
cocotb.start_soon(self._run_reset(reset_signal, bool(active_level)))
|
||||||
|
|
||||||
self._update_reset()
|
self._update_reset()
|
||||||
|
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ class StreamBase(Reset):
|
|||||||
else:
|
else:
|
||||||
self.log.info("Reset de-asserted")
|
self.log.info("Reset de-asserted")
|
||||||
if self._run_cr is None:
|
if self._run_cr is None:
|
||||||
self._run_cr = cocotb.fork(self._run())
|
self._run_cr = cocotb.start_soon(self._run())
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
@@ -175,15 +175,17 @@ class StreamPause:
|
|||||||
self._pause_generator = generator
|
self._pause_generator = generator
|
||||||
|
|
||||||
if self._pause_generator is not None:
|
if self._pause_generator is not None:
|
||||||
self._pause_cr = cocotb.fork(self._run_pause())
|
self._pause_cr = cocotb.start_soon(self._run_pause())
|
||||||
|
|
||||||
def clear_pause_generator(self):
|
def clear_pause_generator(self):
|
||||||
self.set_pause_generator(None)
|
self.set_pause_generator(None)
|
||||||
|
|
||||||
async def _run_pause(self):
|
async def _run_pause(self):
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
for val in self._pause_generator:
|
for val in self._pause_generator:
|
||||||
self.pause = val
|
self.pause = val
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
|
|
||||||
class StreamSource(StreamBase, StreamPause):
|
class StreamSource(StreamBase, StreamPause):
|
||||||
@@ -231,8 +233,10 @@ class StreamSource(StreamBase, StreamPause):
|
|||||||
self.valid.value = 0
|
self.valid.value = 0
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
# read handshake signals
|
# read handshake signals
|
||||||
ready_sample = self.ready is None or self.ready.value
|
ready_sample = self.ready is None or self.ready.value
|
||||||
@@ -282,8 +286,10 @@ class StreamMonitor(StreamBase):
|
|||||||
await self.active_event.wait()
|
await self.active_event.wait()
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
# read handshake signals
|
# read handshake signals
|
||||||
ready_sample = self.ready is None or self.ready.value
|
ready_sample = self.ready is None or self.ready.value
|
||||||
@@ -322,8 +328,10 @@ class StreamSink(StreamMonitor, StreamPause):
|
|||||||
self.ready.value = 0
|
self.ready.value = 0
|
||||||
|
|
||||||
async def _run(self):
|
async def _run(self):
|
||||||
|
clock_edge_event = RisingEdge(self.clock)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await RisingEdge(self.clock)
|
await clock_edge_event
|
||||||
|
|
||||||
# read handshake signals
|
# read handshake signals
|
||||||
ready_sample = self.ready is None or self.ready.value
|
ready_sample = self.ready is None or self.ready.value
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "0.1.16"
|
__version__ = "0.1.18"
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ classifiers =
|
|||||||
packages = find_namespace:
|
packages = find_namespace:
|
||||||
python_requires = >=3.6
|
python_requires = >=3.6
|
||||||
install_requires =
|
install_requires =
|
||||||
cocotb
|
cocotb >= 1.6.0
|
||||||
cocotb-bus
|
cocotb-bus
|
||||||
|
|
||||||
[options.extras_require]
|
[options.extras_require]
|
||||||
@@ -47,7 +47,10 @@ addopts =
|
|||||||
|
|
||||||
# tox configuration
|
# tox configuration
|
||||||
[tox:tox]
|
[tox:tox]
|
||||||
envlist = py36, py37, py38, py39
|
envlist = py36, py37, py38, py39, py310
|
||||||
|
skip_missing_interpreters = true
|
||||||
|
minversion = 3.2.0
|
||||||
|
requires = virtualenv >= 16.1
|
||||||
|
|
||||||
[gh-actions]
|
[gh-actions]
|
||||||
python =
|
python =
|
||||||
@@ -55,6 +58,7 @@ python =
|
|||||||
3.7: py37
|
3.7: py37
|
||||||
3.8: py38
|
3.8: py38
|
||||||
3.9: py39
|
3.9: py39
|
||||||
|
3.10: py310
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
setenv =
|
setenv =
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class TB:
|
|||||||
self.log = logging.getLogger("cocotb.tb")
|
self.log = logging.getLogger("cocotb.tb")
|
||||||
self.log.setLevel(logging.DEBUG)
|
self.log.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
cocotb.fork(Clock(dut.clk, 2, units="ns").start())
|
cocotb.start_soon(Clock(dut.clk, 2, units="ns").start())
|
||||||
|
|
||||||
self.axi_master = AxiMaster(AxiBus.from_prefix(dut, "axi"), dut.clk, dut.rst)
|
self.axi_master = AxiMaster(AxiBus.from_prefix(dut, "axi"), dut.clk, dut.rst)
|
||||||
self.axi_ram = AxiRam(AxiBus.from_prefix(dut, "axi"), dut.clk, dut.rst, size=2**16)
|
self.axi_ram = AxiRam(AxiBus.from_prefix(dut, "axi"), dut.clk, dut.rst, size=2**16)
|
||||||
@@ -283,7 +283,7 @@ async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None):
|
|||||||
workers = []
|
workers = []
|
||||||
|
|
||||||
for k in range(16):
|
for k in range(16):
|
||||||
workers.append(cocotb.fork(worker(tb.axi_master, k*0x1000, 0x1000, count=16)))
|
workers.append(cocotb.start_soon(worker(tb.axi_master, k*0x1000, 0x1000, count=16)))
|
||||||
|
|
||||||
while workers:
|
while workers:
|
||||||
await workers.pop(0).join()
|
await workers.pop(0).join()
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class TB:
|
|||||||
self.log = logging.getLogger("cocotb.tb")
|
self.log = logging.getLogger("cocotb.tb")
|
||||||
self.log.setLevel(logging.DEBUG)
|
self.log.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
cocotb.fork(Clock(dut.clk, 2, units="ns").start())
|
cocotb.start_soon(Clock(dut.clk, 2, units="ns").start())
|
||||||
|
|
||||||
self.axil_master = AxiLiteMaster(AxiLiteBus.from_prefix(dut, "axil"), dut.clk, dut.rst)
|
self.axil_master = AxiLiteMaster(AxiLiteBus.from_prefix(dut, "axil"), dut.clk, dut.rst)
|
||||||
self.axil_ram = AxiLiteRam(AxiLiteBus.from_prefix(dut, "axil"), dut.clk, dut.rst, size=2**16)
|
self.axil_ram = AxiLiteRam(AxiLiteBus.from_prefix(dut, "axil"), dut.clk, dut.rst, size=2**16)
|
||||||
@@ -272,7 +272,7 @@ async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None):
|
|||||||
workers = []
|
workers = []
|
||||||
|
|
||||||
for k in range(16):
|
for k in range(16):
|
||||||
workers.append(cocotb.fork(worker(tb.axil_master, k*0x1000, 0x1000, count=16)))
|
workers.append(cocotb.start_soon(worker(tb.axil_master, k*0x1000, 0x1000, count=16)))
|
||||||
|
|
||||||
while workers:
|
while workers:
|
||||||
await workers.pop(0).join()
|
await workers.pop(0).join()
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class TB:
|
|||||||
self.log = logging.getLogger("cocotb.tb")
|
self.log = logging.getLogger("cocotb.tb")
|
||||||
self.log.setLevel(logging.DEBUG)
|
self.log.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
cocotb.fork(Clock(dut.clk, 2, units="ns").start())
|
cocotb.start_soon(Clock(dut.clk, 2, units="ns").start())
|
||||||
|
|
||||||
self.source = AxiStreamSource(AxiStreamBus.from_prefix(dut, "axis"), dut.clk, dut.rst)
|
self.source = AxiStreamSource(AxiStreamBus.from_prefix(dut, "axis"), dut.clk, dut.rst)
|
||||||
self.sink = AxiStreamSink(AxiStreamBus.from_prefix(dut, "axis"), dut.clk, dut.rst)
|
self.sink = AxiStreamSink(AxiStreamBus.from_prefix(dut, "axis"), dut.clk, dut.rst)
|
||||||
|
|||||||
Reference in New Issue
Block a user