From a48da65f55d3cf6233921431b3ed37ccac02d0e7 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Wed, 2 Dec 2020 16:07:25 -0800 Subject: [PATCH] Replace token with event --- README.md | 31 ++++-- cocotbext/axi/axi_master.py | 200 +++++++++++++---------------------- cocotbext/axi/axil_master.py | 198 +++++++++++++--------------------- 3 files changed, 171 insertions(+), 258 deletions(-) diff --git a/README.md b/README.md index 9f7ec5c..b190e7c 100644 --- a/README.md +++ b/README.md @@ -50,12 +50,23 @@ First, non-blocking operations can be started with `init_read()` and `init_write await axi_master.wait() data = axi_master.get_read_data() +Alternatively, an event object can be provided as an argument to `init_read()` and `init_write()`, and the result can be retrieved from `Event.data`. For example: + + event = Event() + axi_master.init_write(0x0000, b'test', event=event) + await event.wait() + resp = event.data + event = Event() + axi_master.init_read(0x0000, 4, event=event) + await event.wait() + resp = event.data + Second, blocking operations can be carried out with `read()` and `write()` and their associated word-access wrappers. Multiple concurrent operations started from different coroutines are handled correctly. For example: await axi_master.write(0x0000, b'test') data = await axi_master.read(0x0000, 4) -`read()`, `write()`, `get_read_data()`, and `get_write_resp()` return `namedtuple` objects containing _address_, _data_ or _length_, _resp_, and _token_. +`read()`, `write()`, `get_read_data()`, and `get_write_resp()` return `namedtuple` objects containing _address_, _data_ or _length_, and _resp_. #### `AxiMaster` and `AxiLiteMaster` constructor parameters @@ -73,13 +84,13 @@ Second, blocking operations can be carried out with `read()` and `write()` and t * `init_read(address, length, ...)`: initiate reading _length_ bytes, starting at _address_ * `init_write(address, data, ...)`: initiate writing _data_ (bytes), starting from _address_ * `idle()`: returns _True_ when there are no outstanding operations in progress -* `wait(token)`: blocking wait until all outstanding operations complete, or a specific operation if token is provided -* `wait_read(token)`: wait until all outstanding read operations complete, or a specific operation if token is provided -* `wait_write(token)`: wait until all outstanding write operations complete, or a specific operation if token is provided -* `read_data_ready(token)`: determine if any read read data is available, check specific operation if token is provided -* `get_read_data(token)`: fetch first available read data, or read data for specific operation if token is provided -* `write_resp_ready(token)`: determine if any write response is available, check specific operation if token is provided -* `get_write_resp(token)`: fetch first available write response, or write response for specific operation if token is provided +* `wait()`: blocking wait until all outstanding operations complete +* `wait_read()`: wait until all outstanding read operations complete +* `wait_write()`: wait until all outstanding write operations complete +* `read_data_ready()`: determine if any read read data is available +* `get_read_data()`: fetch first available read data +* `write_resp_ready()`: determine if any write response is available +* `get_write_resp()`: fetch first available write response * `read(address, length, ...)`: read _length_ bytes, starting at _address_ * `read_words(address, count, byteorder, ws, ...)`: read _count_ _ws_-byte words, starting at _address_, default word size of `2`, default _byteorder_ `"little"` * `read_dwords(address, count, byteorder, ...)`: read _count_ 4-byte dwords, starting at _address_, default _byteorder_ `"little"` @@ -109,12 +120,12 @@ Second, blocking operations can be carried out with `read()` and `write()` and t * _region_: AXI region field, default `0` * _user_: AXI user signal (awuser/aruser), default `0` * _wuser_: AXI wuser signal, default `0` (write-related methods only) -* _token_: Token used to retrieve result for operation, default `None` (`init_read()` and `init_write()` only) +* _event_: `Event` object used to wait on and retrieve result for specific operation, default `None` (`init_read()` and `init_write()` only). If provided, the event will be triggered when the operation completes and the result returned via `Event.data` instead of `get_read_data()` or `get_write_resp()`. #### Additional optional arguments for `AxiLiteMaster` * _prot_: AXI protection flags, default `AxiProt.NONSECURE` -* _token_: Token used to retrieve result for operation, default `None` (`init_read()` and `init_write()` only) +* _event_: `Event` object used to wait on and retrieve result for specific operation, default `None` (`init_read()` and `init_write()` only). If provided, the event will be triggered when the operation completes and the result returned via `Event.data` instead of `get_read_data()` or `get_write_resp()`. ### AXI and AXI lite RAM diff --git a/cocotbext/axi/axi_master.py b/cocotbext/axi/axi_master.py index 639790c..b2b684a 100644 --- a/cocotbext/axi/axi_master.py +++ b/cocotbext/axi/axi_master.py @@ -34,17 +34,17 @@ from .axi_channels import AxiAWSource, AxiWSource, AxiBSink, AxiARSource, AxiRSi # AXI master write helper objects AxiWriteCmd = namedtuple("AxiWriteCmd", ["address", "data", "awid", "burst", "size", - "lock", "cache", "prot", "qos", "region", "user", "wuser", "token"]) + "lock", "cache", "prot", "qos", "region", "user", "wuser", "event"]) AxiWriteRespCmd = namedtuple("AxiWriteRespCmd", ["address", "length", "size", "cycles", - "prot", "burst_list", "token"]) -AxiWriteResp = namedtuple("AxiWriteResp", ["address", "length", "resp", "user", "token"]) + "prot", "burst_list", "event"]) +AxiWriteResp = namedtuple("AxiWriteResp", ["address", "length", "resp", "user"]) # AXI master read helper objects AxiReadCmd = namedtuple("AxiReadCmd", ["address", "length", "arid", "burst", "size", - "lock", "cache", "prot", "qos", "region", "user", "token"]) + "lock", "cache", "prot", "qos", "region", "user", "event"]) AxiReadRespCmd = namedtuple("AxiReadRespCmd", ["address", "length", "size", "cycles", - "prot", "burst_list", "token"]) -AxiReadResp = namedtuple("AxiReadResp", ["address", "data", "resp", "user", "token"]) + "prot", "burst_list", "event"]) +AxiReadResp = namedtuple("AxiReadResp", ["address", "data", "resp", "user"]) class AxiMasterWrite(object): @@ -62,8 +62,6 @@ class AxiMasterWrite(object): self.w_channel = AxiWSource(entity, name, clock, reset) self.b_channel = AxiBSink(entity, name, clock, reset) - self.active_tokens = set() - self.write_command_queue = deque() self.write_command_sync = Event() self.write_resp_queue = deque() @@ -106,11 +104,10 @@ class AxiMasterWrite(object): cocotb.fork(self._process_write_resp()) def init_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, token=None): - if token is not None: - if token in self.active_tokens: - raise Exception("Token is not unique") - self.active_tokens.add(token) + cache=0b0011, prot=AxiProt.NONSECURE, qos=0, region=0, user=0, wuser=0, event=None): + + if event is not None and not isinstance(event, Event): + raise ValueError("Expected event object") if awid is None or awid < 0: awid = None @@ -137,54 +134,32 @@ class AxiMasterWrite(object): self.in_flight_operations += 1 cmd = AxiWriteCmd(address, bytearray(data), awid, burst, size, lock, - cache, prot, qos, region, user, wuser, token) + cache, prot, qos, region, user, wuser, event) self.write_command_queue.append(cmd) self.write_command_sync.set() def idle(self): return not self.in_flight_operations - async def wait(self, token=None): - if token is None: - while not self.idle(): - self.write_resp_sync.clear() - await self.write_resp_sync.wait() - else: - if token not in self.active_tokens: - raise ValueError("Unknown token") - while token not in self.write_resp_set: - self.write_resp_sync.clear() - await self.write_resp_sync.wait() + async def wait(self): + while not self.idle(): + self.write_resp_sync.clear() + await self.write_resp_sync.wait() - def write_resp_ready(self, token=None): - if token is not None: - return token in self.write_resp_set + def write_resp_ready(self): return bool(self.write_resp_queue) - def get_write_resp(self, token=None): - if token is not None: - if token in self.write_resp_set: - for resp in self.write_resp_queue: - if resp.token == token: - self.write_resp_queue.remove(resp) - self.active_tokens.remove(resp.token) - self.write_resp_set.remove(resp.token) - return resp - return None + def get_write_resp(self): if self.write_resp_queue: - resp = self.write_resp_queue.popleft() - if resp.token is not None: - self.active_tokens.remove(resp.token) - self.write_resp_set.remove(resp.token) - return resp + return self.write_resp_queue.popleft() return 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): - token = object() - self.init_write(address, data, awid, burst, size, lock, cache, prot, qos, region, user, wuser, token) - await self.wait(token) - return self.get_write_resp(token) + event = Event() + self.init_write(address, data, awid, burst, size, lock, cache, prot, qos, region, user, wuser, event) + await event.wait() + return event.data async def write_words(self, address, data, byteorder='little', ws=2, awid=None, burst=AxiBurstType.INCR, size=None, lock=AxiLockType.NORMAL, cache=0b0011, prot=AxiProt.NONSECURE, qos=0, region=0, user=0, wuser=0): @@ -327,7 +302,7 @@ class AxiMasterWrite(object): cur_addr += num_bytes cycle_offset = (cycle_offset + num_bytes) % self.byte_width - resp_cmd = AxiWriteRespCmd(cmd.address, len(cmd.data), cmd.size, cycles, cmd.prot, burst_list, cmd.token) + resp_cmd = AxiWriteRespCmd(cmd.address, len(cmd.data), cmd.size, cycles, cmd.prot, burst_list, cmd.event) self.int_write_resp_command_queue.append(resp_cmd) self.int_write_resp_command_sync.set() @@ -378,10 +353,14 @@ class AxiMasterWrite(object): self.log.info("Write complete addr: 0x%08x prot: %s resp: %s length: %d", cmd.address, cmd.prot, resp, cmd.length) - self.write_resp_queue.append(AxiWriteResp(cmd.address, cmd.length, resp, user, cmd.token)) - self.write_resp_sync.set() - if cmd.token is not None: - self.write_resp_set.add(cmd.token) + write_resp = AxiWriteResp(cmd.address, cmd.length, resp, user) + + if cmd.event is not None: + cmd.event.set(write_resp) + else: + self.write_resp_queue.append(write_resp) + self.write_resp_sync.set() + self.in_flight_operations -= 1 @@ -399,8 +378,6 @@ class AxiMasterRead(object): self.ar_channel = AxiARSource(entity, name, clock, reset) self.r_channel = AxiRSink(entity, name, clock, reset) - self.active_tokens = set() - self.read_command_queue = deque() self.read_command_sync = Event() self.read_data_queue = deque() @@ -441,11 +418,10 @@ class AxiMasterRead(object): cocotb.fork(self._process_read_resp()) def init_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, token=None): - if token is not None: - if token in self.active_tokens: - raise Exception("Token is not unique") - self.active_tokens.add(token) + lock=AxiLockType.NORMAL, cache=0b0011, prot=AxiProt.NONSECURE, qos=0, region=0, user=0, event=None): + + if event is not None and not isinstance(event, Event): + raise ValueError("Expected event object") if length < 0: raise ValueError("Read length must be positive") @@ -467,54 +443,32 @@ class AxiMasterRead(object): self.in_flight_operations += 1 - cmd = AxiReadCmd(address, length, arid, burst, size, lock, cache, prot, qos, region, user, token) + cmd = AxiReadCmd(address, length, arid, burst, size, lock, cache, prot, qos, region, user, event) self.read_command_queue.append(cmd) self.read_command_sync.set() def idle(self): return not self.in_flight_operations - async def wait(self, token=None): - if token is None: - while not self.idle(): - self.read_data_sync.clear() - await self.read_data_sync.wait() - else: - if token not in self.active_tokens: - raise ValueError("Unknown token") - while token not in self.read_data_set: - self.read_data_sync.clear() - await self.read_data_sync.wait() + async def wait(self): + while not self.idle(): + self.read_data_sync.clear() + await self.read_data_sync.wait() - def read_data_ready(self, token=None): - if token is not None: - return token in self.read_data_set + def read_data_ready(self): return bool(self.read_data_queue) - def get_read_data(self, token=None): - if token is not None: - if token in self.read_data_set: - for resp in self.read_data_queue: - if resp.token == token: - self.read_data_queue.remove(resp) - self.active_tokens.remove(resp.token) - self.read_data_set.remove(resp.token) - return resp - return None + def get_read_data(self): if self.read_data_queue: - resp = self.read_data_queue.popleft() - if resp.token is not None: - self.active_tokens.remove(resp.token) - self.read_data_set.remove(resp.token) - return resp + return self.read_data_queue.popleft() return 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): - token = object() - self.init_read(address, length, arid, burst, size, lock, cache, prot, qos, region, user, token) - await self.wait(token) - return self.get_read_data(token) + event = Event() + self.init_read(address, length, arid, burst, size, lock, cache, prot, qos, region, user, event) + await event.wait() + return event.data async def read_words(self, address, count, byteorder='little', ws=2, arid=None, burst=AxiBurstType.INCR, size=None, lock=AxiLockType.NORMAL, cache=0b0011, prot=AxiProt.NONSECURE, qos=0, region=0, user=0): @@ -616,7 +570,7 @@ class AxiMasterRead(object): cur_addr += num_bytes - resp_cmd = AxiReadRespCmd(cmd.address, cmd.length, cmd.size, cycles, cmd.prot, burst_list, cmd.token) + resp_cmd = AxiReadRespCmd(cmd.address, cmd.length, cmd.size, cycles, cmd.prot, burst_list, cmd.event) self.int_read_resp_command_queue.append(resp_cmd) self.int_read_resp_command_sync.set() @@ -699,10 +653,14 @@ class AxiMasterRead(object): self.log.info("Read complete addr: 0x%08x prot: %s resp: %s data: %s", cmd.address, cmd.prot, resp, ' '.join((f'{c:02x}' for c in data))) - self.read_data_queue.append(AxiReadResp(cmd.address, data, resp, user, cmd.token)) - self.read_data_sync.set() - if cmd.token is not None: - self.read_data_set.add(cmd.token) + read_resp = AxiReadResp(cmd.address, data, resp, user) + + if cmd.event is not None: + cmd.event.set(read_resp) + else: + self.read_data_queue.append(read_resp) + self.read_data_sync.set() + self.in_flight_operations -= 1 @@ -715,44 +673,38 @@ class AxiMaster(object): self.read_if = AxiMasterRead(entity, name, clock, reset, max_burst_len) def init_read(self, address, length, burst=AxiBurstType.INCR, size=None, - lock=AxiLockType.NORMAL, cache=0b0011, prot=AxiProt.NONSECURE, qos=0, region=0, user=0, token=None): - self.read_if.init_read(address, length, burst, size, lock, cache, prot, qos, region, user, token) + lock=AxiLockType.NORMAL, cache=0b0011, prot=AxiProt.NONSECURE, qos=0, region=0, user=0, event=None): + self.read_if.init_read(address, length, burst, size, lock, cache, prot, qos, region, user, event) def init_write(self, address, data, burst=AxiBurstType.INCR, size=None, lock=AxiLockType.NORMAL, - cache=0b0011, prot=AxiProt.NONSECURE, qos=0, region=0, user=0, wuser=0, token=None): - self.write_if.init_write(address, data, burst, size, lock, cache, prot, qos, region, user, wuser, token) + cache=0b0011, prot=AxiProt.NONSECURE, qos=0, region=0, user=0, wuser=0, event=None): + self.write_if.init_write(address, data, burst, size, lock, cache, prot, qos, region, user, wuser, event) def idle(self): return (not self.read_if or self.read_if.idle()) and (not self.write_if or self.write_if.idle()) - async def wait(self, token=None): - if token is None: - while not self.idle(): - await self.write_if.wait() - await self.read_if.wait() - else: - if token in self.write_if.active_tokens: - await self.write_if.wait(token) - else: - await self.read_if.wait(token) + async def wait(self): + while not self.idle(): + await self.write_if.wait() + await self.read_if.wait() - async def wait_read(self, token=None): - await self.read_if.wait(token) + async def wait_read(self): + await self.read_if.wait() - async def wait_write(self, token=None): - await self.write_if.wait(token) + async def wait_write(self): + await self.write_if.wait() - def read_data_ready(self, token=None): - return self.read_if.read_data_ready(token) + def read_data_ready(self): + return self.read_if.read_data_ready() - def get_read_data(self, token=None): - return self.read_if.get_read_data(token) + def get_read_data(self): + return self.read_if.get_read_data() - def write_resp_ready(self, token=None): - return self.write_if.write_resp_ready(token) + def write_resp_ready(self): + return self.write_if.write_resp_ready() - def get_write_resp(self, token=None): - return self.write_if.get_write_resp(token) + def get_write_resp(self): + return self.write_if.get_write_resp() 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): diff --git a/cocotbext/axi/axil_master.py b/cocotbext/axi/axil_master.py index 192b8bc..949d641 100644 --- a/cocotbext/axi/axil_master.py +++ b/cocotbext/axi/axil_master.py @@ -33,14 +33,14 @@ from .constants import AxiProt, AxiResp from .axil_channels import AxiLiteAWSource, AxiLiteWSource, AxiLiteBSink, AxiLiteARSource, AxiLiteRSink # AXI lite master write -AxiLiteWriteCmd = namedtuple("AxiLiteWriteCmd", ["address", "data", "prot", "token"]) -AxiLiteWriteRespCmd = namedtuple("AxiLiteWriteRespCmd", ["address", "length", "cycles", "prot", "token"]) -AxiLiteWriteResp = namedtuple("AxiLiteWriteResp", ["address", "length", "resp", "token"]) +AxiLiteWriteCmd = namedtuple("AxiLiteWriteCmd", ["address", "data", "prot", "event"]) +AxiLiteWriteRespCmd = namedtuple("AxiLiteWriteRespCmd", ["address", "length", "cycles", "prot", "event"]) +AxiLiteWriteResp = namedtuple("AxiLiteWriteResp", ["address", "length", "resp"]) # AXI lite master read -AxiLiteReadCmd = namedtuple("AxiLiteReadCmd", ["address", "length", "prot", "token"]) -AxiLiteReadRespCmd = namedtuple("AxiLiteReadRespCmd", ["address", "length", "cycles", "prot", "token"]) -AxiLiteReadResp = namedtuple("AxiLiteReadResp", ["address", "data", "resp", "token"]) +AxiLiteReadCmd = namedtuple("AxiLiteReadCmd", ["address", "length", "prot", "event"]) +AxiLiteReadRespCmd = namedtuple("AxiLiteReadRespCmd", ["address", "length", "cycles", "prot", "event"]) +AxiLiteReadResp = namedtuple("AxiLiteReadResp", ["address", "data", "resp"]) class AxiLiteMasterWrite(object): @@ -58,8 +58,6 @@ class AxiLiteMasterWrite(object): self.w_channel = AxiLiteWSource(entity, name, clock, reset) self.b_channel = AxiLiteBSink(entity, name, clock, reset) - self.active_tokens = set() - self.write_command_queue = deque() self.write_command_sync = Event() self.write_resp_queue = deque() @@ -87,60 +85,36 @@ class AxiLiteMasterWrite(object): cocotb.fork(self._process_write()) cocotb.fork(self._process_write_resp()) - def init_write(self, address, data, prot=AxiProt.NONSECURE, token=None): - if token is not None: - if token in self.active_tokens: - raise Exception("Token is not unique") - self.active_tokens.add(token) + def init_write(self, address, data, prot=AxiProt.NONSECURE, event=None): + if event is not None and not isinstance(event, Event): + raise ValueError("Expected event object") self.in_flight_operations += 1 - self.write_command_queue.append(AxiLiteWriteCmd(address, bytearray(data), prot, token)) + self.write_command_queue.append(AxiLiteWriteCmd(address, bytearray(data), prot, event)) self.write_command_sync.set() def idle(self): return not self.in_flight_operations - async def wait(self, token=None): - if token is None: - while not self.idle(): - self.write_resp_sync.clear() - await self.write_resp_sync.wait() - else: - if token not in self.active_tokens: - raise ValueError("Unknown token") - while token not in self.write_resp_set: - self.write_resp_sync.clear() - await self.write_resp_sync.wait() + async def wait(self): + while not self.idle(): + self.write_resp_sync.clear() + await self.write_resp_sync.wait() - def write_resp_ready(self, token=None): - if token is not None: - return token in self.write_resp_set + def write_resp_ready(self): return bool(self.write_resp_queue) - def get_write_resp(self, token=None): - if token is not None: - if token in self.write_resp_set: - for resp in self.write_resp_queue: - if resp.token == token: - self.write_resp_queue.remove(resp) - self.active_tokens.remove(resp.token) - self.write_resp_set.remove(resp.token) - return resp - return None + def get_write_resp(self): if self.write_resp_queue: - resp = self.write_resp_queue.popleft() - if resp.token is not None: - self.active_tokens.remove(resp.token) - self.write_resp_set.remove(resp.token) - return resp + return self.write_resp_queue.popleft() return None async def write(self, address, data, prot=AxiProt.NONSECURE): - token = object() - self.init_write(address, data, prot, token) - await self.wait(token) - return self.get_write_resp(token) + event = Event() + self.init_write(address, data, prot, event) + await event.wait() + return event.data async def write_words(self, address, data, byteorder='little', ws=2, prot=AxiProt.NONSECURE): words = data @@ -185,7 +159,7 @@ class AxiLiteMasterWrite(object): cycles = (len(cmd.data) + (cmd.address % self.byte_width) + self.byte_width-1) // self.byte_width - resp_cmd = AxiLiteWriteRespCmd(cmd.address, len(cmd.data), cycles, cmd.prot, cmd.token) + resp_cmd = AxiLiteWriteRespCmd(cmd.address, len(cmd.data), cycles, cmd.prot, cmd.event) self.int_write_resp_command_queue.append(resp_cmd) self.int_write_resp_command_sync.set() @@ -244,10 +218,14 @@ class AxiLiteMasterWrite(object): self.log.info("Write complete addr: 0x%08x prot: %s resp: %s length: %d", cmd.address, cmd.prot, resp, cmd.length) - self.write_resp_queue.append(AxiLiteWriteResp(cmd.address, cmd.length, resp, cmd.token)) - self.write_resp_sync.set() - if cmd.token is not None: - self.write_resp_set.add(cmd.token) + write_resp = AxiLiteWriteResp(cmd.address, cmd.length, resp) + + if cmd.event is not None: + cmd.event.set(write_resp) + else: + self.write_resp_queue.append(write_resp) + self.write_resp_sync.set() + self.in_flight_operations -= 1 @@ -265,8 +243,6 @@ class AxiLiteMasterRead(object): self.ar_channel = AxiLiteARSource(entity, name, clock, reset) self.r_channel = AxiLiteRSink(entity, name, clock, reset) - self.active_tokens = set() - self.read_command_queue = deque() self.read_command_sync = Event() self.read_data_queue = deque() @@ -292,60 +268,36 @@ class AxiLiteMasterRead(object): cocotb.fork(self._process_read()) cocotb.fork(self._process_read_resp()) - def init_read(self, address, length, prot=AxiProt.NONSECURE, token=None): - if token is not None: - if token in self.active_tokens: - raise Exception("Token is not unique") - self.active_tokens.add(token) + def init_read(self, address, length, prot=AxiProt.NONSECURE, event=None): + if event is not None and not isinstance(event, Event): + raise ValueError("Expected event object") self.in_flight_operations += 1 - self.read_command_queue.append(AxiLiteReadCmd(address, length, prot, token)) + self.read_command_queue.append(AxiLiteReadCmd(address, length, prot, event)) self.read_command_sync.set() def idle(self): return not self.in_flight_operations - async def wait(self, token=None): - if token is None: - while not self.idle(): - self.read_data_sync.clear() - await self.read_data_sync.wait() - else: - if token not in self.active_tokens: - raise ValueError("Unknown token") - while token not in self.read_data_set: - self.read_data_sync.clear() - await self.read_data_sync.wait() + async def wait(self): + while not self.idle(): + self.read_data_sync.clear() + await self.read_data_sync.wait() - def read_data_ready(self, token=None): - if token is not None: - return token in self.read_data_set + def read_data_ready(self): return bool(self.read_data_queue) - def get_read_data(self, token=None): - if token is not None: - if token in self.read_data_set: - for resp in self.read_data_queue: - if resp.token == token: - self.read_data_queue.remove(resp) - self.active_tokens.remove(resp.token) - self.read_data_set.remove(resp.token) - return resp - return None + def get_read_data(self): if self.read_data_queue: - resp = self.read_data_queue.popleft() - if resp.token is not None: - self.active_tokens.remove(resp.token) - self.read_data_set.remove(resp.token) - return resp + return self.read_data_queue.popleft() return None async def read(self, address, length, prot=AxiProt.NONSECURE): - token = object() - self.init_read(address, length, prot, token) - await self.wait(token) - return self.get_read_data(token) + event = Event() + self.init_read(address, length, prot, event) + await event.wait() + return event.data async def read_words(self, address, count, byteorder='little', ws=2, prot=AxiProt.NONSECURE): data = await self.read(address, count*ws, prot) @@ -384,7 +336,7 @@ class AxiLiteMasterRead(object): cycles = (cmd.length + self.byte_width-1 + (cmd.address % self.byte_width)) // self.byte_width - resp_cmd = AxiLiteReadRespCmd(cmd.address, cmd.length, cycles, cmd.prot, cmd.token) + resp_cmd = AxiLiteReadRespCmd(cmd.address, cmd.length, cycles, cmd.prot, cmd.event) self.int_read_resp_command_queue.append(resp_cmd) self.int_read_resp_command_sync.set() @@ -437,10 +389,14 @@ class AxiLiteMasterRead(object): self.log.info("Read complete addr: 0x%08x prot: %s resp: %s data: %s", cmd.address, cmd.prot, resp, ' '.join((f'{c:02x}' for c in data))) - self.read_data_queue.append(AxiLiteReadResp(cmd.address, data, resp, cmd.token)) - self.read_data_sync.set() - if cmd.token is not None: - self.read_data_set.add(cmd.token) + read_resp = AxiLiteReadResp(cmd.address, data, resp) + + if cmd.event is not None: + cmd.event.set(read_resp) + else: + self.read_data_queue.append(read_resp) + self.read_data_sync.set() + self.in_flight_operations -= 1 @@ -452,43 +408,37 @@ class AxiLiteMaster(object): self.write_if = AxiLiteMasterWrite(entity, name, clock, reset) self.read_if = AxiLiteMasterRead(entity, name, clock, reset) - def init_read(self, address, length, prot=AxiProt.NONSECURE, token=None): - self.read_if.init_read(address, length, prot, token) + def init_read(self, address, length, prot=AxiProt.NONSECURE, event=None): + self.read_if.init_read(address, length, prot, event) - def init_write(self, address, data, prot=AxiProt.NONSECURE, token=None): - self.write_if.init_write(address, data, prot, token) + def init_write(self, address, data, prot=AxiProt.NONSECURE, event=None): + self.write_if.init_write(address, data, prot, event) def idle(self): return (not self.read_if or self.read_if.idle()) and (not self.write_if or self.write_if.idle()) - async def wait(self, token=None): - if token is None: - while not self.idle(): - await self.write_if.wait() - await self.read_if.wait() - else: - if token in self.write_if.active_tokens: - await self.write_if.wait(token) - else: - await self.read_if.wait(token) + async def wait(self): + while not self.idle(): + await self.write_if.wait() + await self.read_if.wait() - async def wait_read(self, token=None): - await self.read_if.wait(token) + async def wait_read(self): + await self.read_if.wait() - async def wait_write(self, token=None): - await self.write_if.wait(token) + async def wait_write(self): + await self.write_if.wait() - def read_data_ready(self, token=None): - return self.read_if.read_data_ready(token) + def read_data_ready(self): + return self.read_if.read_data_ready() - def get_read_data(self, token=None): - return self.read_if.get_read_data(token) + def get_read_data(self): + return self.read_if.get_read_data() - def write_resp_ready(self, token=None): - return self.write_if.write_resp_ready(token) + def write_resp_ready(self): + return self.write_if.write_resp_ready() - def get_write_resp(self, token=None): - return self.write_if.get_write_resp(token) + def get_write_resp(self): + return self.write_if.get_write_resp() async def read(self, address, length, prot=AxiProt.NONSECURE): return await self.read_if.read(address, length, prot)