From 2e79ef233f8cd383c3f8b2a33ef636d59bb101ac Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sun, 3 Jan 2021 12:39:25 -0800 Subject: [PATCH] Rework resets --- cocotbext/axi/axi_master.py | 88 ++++++++++++++++++++++++++++++++---- cocotbext/axi/axi_ram.py | 46 +++++++++++++++---- cocotbext/axi/axil_master.py | 88 ++++++++++++++++++++++++++++++++---- cocotbext/axi/axil_ram.py | 46 +++++++++++++++---- 4 files changed, 236 insertions(+), 32 deletions(-) diff --git a/cocotbext/axi/axi_master.py b/cocotbext/axi/axi_master.py index 731b85b..21f6f40 100644 --- a/cocotbext/axi/axi_master.py +++ b/cocotbext/axi/axi_master.py @@ -31,6 +31,7 @@ from cocotb.triggers import Event from .version import __version__ from .constants import AxiBurstType, AxiLockType, AxiProt, AxiResp from .axi_channels import AxiAWSource, AxiWSource, AxiBSink, AxiARSource, AxiRSink +from .reset import Reset # AXI master write helper objects AxiWriteCmd = namedtuple("AxiWriteCmd", ["address", "data", "awid", "burst", "size", @@ -47,7 +48,7 @@ AxiReadRespCmd = namedtuple("AxiReadRespCmd", ["address", "length", "size", "cyc AxiReadResp = namedtuple("AxiReadResp", ["address", "data", "resp", "user"]) -class AxiMasterWrite: +class AxiMasterWrite(Reset): def __init__(self, entity, name, clock, reset=None, max_burst_len=256): self.log = logging.getLogger(f"cocotb.{entity._name}.{name}") @@ -66,7 +67,6 @@ class AxiMasterWrite: self.write_command_sync = Event() self.write_resp_queue = deque() self.write_resp_sync = Event() - self.write_resp_set = set() self.id_count = 2**len(self.aw_channel.bus.awid) self.cur_id = 0 @@ -102,8 +102,10 @@ class AxiMasterWrite: assert len(self.b_channel.bus.bid) == len(self.aw_channel.bus.awid) - cocotb.fork(self._process_write()) - cocotb.fork(self._process_write_resp()) + self._process_write_cr = None + self._process_write_resp_cr = None + + self._init_reset(reset) 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, event=None): @@ -200,6 +202,41 @@ class AxiMasterWrite: await self.write_qwords(address, [data], byteorder, awid, burst, size, lock, cache, prot, qos, region, user, wuser) + def _handle_reset(self, state): + if state: + self.log.info("Reset asserted") + if self._process_write_cr is not None: + self._process_write_cr.kill() + self._process_write_cr = None + if self._process_write_resp_cr is not None: + self._process_write_resp_cr.kill() + self._process_write_resp_cr = None + else: + self.log.info("Reset de-asserted") + if self._process_write_cr is None: + self._process_write_cr = cocotb.fork(self._process_write()) + if self._process_write_resp_cr is None: + self._process_write_resp_cr = cocotb.fork(self._process_write_resp()) + + self.aw_channel.clear() + self.w_channel.clear() + self.b_channel.clear() + + while self.write_command_queue: + cmd = self.write_command_queue.popleft() + if cmd.event: + cmd.event.set(None) + + while self.int_write_resp_command_queue: + cmd = self.int_write_resp_command_queue.popleft() + if cmd.event: + cmd.event.set(None) + + self.write_resp_queue.clear() + + self.in_flight_operations = 0 + self._idle.set() + async def _process_write(self): while True: if not self.write_command_queue: @@ -366,7 +403,7 @@ class AxiMasterWrite: self._idle.set() -class AxiMasterRead: +class AxiMasterRead(Reset): def __init__(self, entity, name, clock, reset=None, max_burst_len=256): self.log = logging.getLogger(f"cocotb.{entity._name}.{name}") @@ -384,7 +421,6 @@ class AxiMasterRead: self.read_command_sync = Event() self.read_data_queue = deque() self.read_data_sync = Event() - self.read_data_set = set() self.id_count = 2**len(self.ar_channel.bus.arid) self.cur_id = 0 @@ -418,8 +454,10 @@ class AxiMasterRead: assert len(self.r_channel.bus.rid) == len(self.ar_channel.bus.arid) - cocotb.fork(self._process_read()) - cocotb.fork(self._process_read_resp()) + self._process_read_cr = None + self._process_read_resp_cr = None + + self._init_reset(reset) 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, event=None): @@ -511,6 +549,40 @@ class AxiMasterRead: return (await self.read_qwords(address, 1, byteorder, arid, burst, size, lock, cache, prot, qos, region, user))[0] + def _handle_reset(self, state): + if state: + self.log.info("Reset asserted") + if self._process_read_cr is not None: + self._process_read_cr.kill() + self._process_read_cr = None + if self._process_read_resp_cr is not None: + self._process_read_resp_cr.kill() + self._process_read_resp_cr = None + else: + self.log.info("Reset de-asserted") + if self._process_read_cr is None: + self._process_read_cr = cocotb.fork(self._process_read()) + if self._process_read_resp_cr is None: + self._process_read_resp_cr = cocotb.fork(self._process_read_resp()) + + self.ar_channel.clear() + self.r_channel.clear() + + while self.read_command_queue: + cmd = self.read_command_queue.popleft() + if cmd.event: + cmd.event.set(None) + + while self.int_read_resp_command_queue: + cmd = self.int_read_resp_command_queue.popleft() + if cmd.event: + cmd.event.set(None) + + self.read_data_queue.clear() + + self.in_flight_operations = 0 + self._idle.set() + async def _process_read(self): while True: if not self.read_command_queue: diff --git a/cocotbext/axi/axi_ram.py b/cocotbext/axi/axi_ram.py index 0e647e0..359d1c6 100644 --- a/cocotbext/axi/axi_ram.py +++ b/cocotbext/axi/axi_ram.py @@ -30,9 +30,10 @@ from .version import __version__ from .constants import AxiBurstType, AxiProt, AxiResp from .axi_channels import AxiAWSink, AxiWSink, AxiBSource, AxiARSink, AxiRSource from .memory import Memory +from .reset import Reset -class AxiRamWrite(Memory): +class AxiRamWrite(Memory, Reset): def __init__(self, entity, name, clock, reset=None, size=1024, mem=None, *args, **kwargs): self.log = logging.getLogger(f"cocotb.{entity._name}.{name}") @@ -49,8 +50,6 @@ class AxiRamWrite(Memory): self.w_channel = AxiWSink(entity, name, clock, reset) self.b_channel = AxiBSource(entity, name, clock, reset) - self.in_flight_operations = 0 - self.width = len(self.w_channel.bus.wdata) self.byte_size = 8 self.byte_width = self.width // self.byte_size @@ -68,7 +67,24 @@ class AxiRamWrite(Memory): assert len(self.b_channel.bus.bid) == len(self.aw_channel.bus.awid) - cocotb.fork(self._process_write()) + self._process_write_cr = None + + self._init_reset(reset) + + def _handle_reset(self, state): + if state: + self.log.info("Reset asserted") + if self._process_write_cr is not None: + self._process_write_cr.kill() + self._process_write_cr = None + else: + self.log.info("Reset de-asserted") + if self._process_write_cr is None: + self._process_write_cr = cocotb.fork(self._process_write()) + + self.aw_channel.clear() + self.w_channel.clear() + self.b_channel.clear() async def _process_write(self): while True: @@ -142,7 +158,7 @@ class AxiRamWrite(Memory): await self.b_channel.send(b) -class AxiRamRead(Memory): +class AxiRamRead(Memory, Reset): def __init__(self, entity, name, clock, reset=None, size=1024, mem=None, *args, **kwargs): self.log = logging.getLogger(f"cocotb.{entity._name}.{name}") @@ -158,8 +174,6 @@ class AxiRamRead(Memory): self.ar_channel = AxiARSink(entity, name, clock, reset) self.r_channel = AxiRSource(entity, name, clock, reset) - self.in_flight_operations = 0 - self.width = len(self.r_channel.bus.rdata) self.byte_size = 8 self.byte_width = self.width // self.byte_size @@ -175,7 +189,23 @@ class AxiRamRead(Memory): assert len(self.r_channel.bus.rid) == len(self.ar_channel.bus.arid) - cocotb.fork(self._process_read()) + self._process_read_cr = None + + self._init_reset(reset) + + def _handle_reset(self, state): + if state: + self.log.info("Reset asserted") + if self._process_read_cr is not None: + self._process_read_cr.kill() + self._process_read_cr = None + else: + self.log.info("Reset de-asserted") + if self._process_read_cr is None: + self._process_read_cr = cocotb.fork(self._process_read()) + + self.ar_channel.clear() + self.r_channel.clear() async def _process_read(self): while True: diff --git a/cocotbext/axi/axil_master.py b/cocotbext/axi/axil_master.py index 229fe2f..7494e33 100644 --- a/cocotbext/axi/axil_master.py +++ b/cocotbext/axi/axil_master.py @@ -31,6 +31,7 @@ from cocotb.triggers import Event from .version import __version__ from .constants import AxiProt, AxiResp from .axil_channels import AxiLiteAWSource, AxiLiteWSource, AxiLiteBSink, AxiLiteARSource, AxiLiteRSink +from .reset import Reset # AXI lite master write AxiLiteWriteCmd = namedtuple("AxiLiteWriteCmd", ["address", "data", "prot", "event"]) @@ -43,7 +44,7 @@ AxiLiteReadRespCmd = namedtuple("AxiLiteReadRespCmd", ["address", "length", "cyc AxiLiteReadResp = namedtuple("AxiLiteReadResp", ["address", "data", "resp"]) -class AxiLiteMasterWrite: +class AxiLiteMasterWrite(Reset): def __init__(self, entity, name, clock, reset=None): self.log = logging.getLogger(f"cocotb.{entity._name}.{name}") @@ -62,7 +63,6 @@ class AxiLiteMasterWrite: self.write_command_sync = Event() self.write_resp_queue = deque() self.write_resp_sync = Event() - self.write_resp_set = set() self.int_write_resp_command_queue = deque() self.int_write_resp_command_sync = Event() @@ -84,8 +84,10 @@ class AxiLiteMasterWrite: assert self.byte_width == len(self.w_channel.bus.wstrb) assert self.byte_width * self.byte_size == self.width - cocotb.fork(self._process_write()) - cocotb.fork(self._process_write_resp()) + self._process_write_cr = None + self._process_write_resp_cr = None + + self._init_reset(reset) def init_write(self, address, data, prot=AxiProt.NONSECURE, event=None): if event is not None and not isinstance(event, Event): @@ -143,6 +145,41 @@ class AxiLiteMasterWrite: async def write_qword(self, address, data, byteorder='little', prot=AxiProt.NONSECURE): await self.write_qwords(address, [data], byteorder, prot) + def _handle_reset(self, state): + if state: + self.log.info("Reset asserted") + if self._process_write_cr is not None: + self._process_write_cr.kill() + self._process_write_cr = None + if self._process_write_resp_cr is not None: + self._process_write_resp_cr.kill() + self._process_write_resp_cr = None + else: + self.log.info("Reset de-asserted") + if self._process_write_cr is None: + self._process_write_cr = cocotb.fork(self._process_write()) + if self._process_write_resp_cr is None: + self._process_write_resp_cr = cocotb.fork(self._process_write_resp()) + + self.aw_channel.clear() + self.w_channel.clear() + self.b_channel.clear() + + while self.write_command_queue: + cmd = self.write_command_queue.popleft() + if cmd.event: + cmd.event.set(None) + + while self.int_write_resp_command_queue: + cmd = self.int_write_resp_command_queue.popleft() + if cmd.event: + cmd.event.set(None) + + self.write_resp_queue.clear() + + self.in_flight_operations = 0 + self._idle.set() + async def _process_write(self): while True: if not self.write_command_queue: @@ -233,7 +270,7 @@ class AxiLiteMasterWrite: self._idle.set() -class AxiLiteMasterRead: +class AxiLiteMasterRead(Reset): def __init__(self, entity, name, clock, reset=None): self.log = logging.getLogger(f"cocotb.{entity._name}.{name}") @@ -251,7 +288,6 @@ class AxiLiteMasterRead: self.read_command_sync = Event() self.read_data_queue = deque() self.read_data_sync = Event() - self.read_data_set = set() self.int_read_resp_command_queue = deque() self.int_read_resp_command_sync = Event() @@ -271,8 +307,10 @@ class AxiLiteMasterRead: assert self.byte_width * self.byte_size == self.width - cocotb.fork(self._process_read()) - cocotb.fork(self._process_read_resp()) + self._process_read_cr = None + self._process_read_resp_cr = None + + self._init_reset(reset) def init_read(self, address, length, prot=AxiProt.NONSECURE, event=None): if event is not None and not isinstance(event, Event): @@ -330,6 +368,40 @@ class AxiLiteMasterRead: async def read_qword(self, address, byteorder='little', prot=AxiProt.NONSECURE): return (await self.read_qwords(address, 1, byteorder, prot))[0] + def _handle_reset(self, state): + if state: + self.log.info("Reset asserted") + if self._process_read_cr is not None: + self._process_read_cr.kill() + self._process_read_cr = None + if self._process_read_resp_cr is not None: + self._process_read_resp_cr.kill() + self._process_read_resp_cr = None + else: + self.log.info("Reset de-asserted") + if self._process_read_cr is None: + self._process_read_cr = cocotb.fork(self._process_read()) + if self._process_read_resp_cr is None: + self._process_read_resp_cr = cocotb.fork(self._process_read_resp()) + + self.ar_channel.clear() + self.r_channel.clear() + + while self.read_command_queue: + cmd = self.read_command_queue.popleft() + if cmd.event: + cmd.event.set(None) + + while self.int_read_resp_command_queue: + cmd = self.int_read_resp_command_queue.popleft() + if cmd.event: + cmd.event.set(None) + + self.read_data_queue.clear() + + self.in_flight_operations = 0 + self._idle.set() + async def _process_read(self): while True: if not self.read_command_queue: diff --git a/cocotbext/axi/axil_ram.py b/cocotbext/axi/axil_ram.py index ad4ebcb..f82b165 100644 --- a/cocotbext/axi/axil_ram.py +++ b/cocotbext/axi/axil_ram.py @@ -30,9 +30,10 @@ from .version import __version__ from .constants import AxiProt, AxiResp from .axil_channels import AxiLiteAWSink, AxiLiteWSink, AxiLiteBSource, AxiLiteARSink, AxiLiteRSource from .memory import Memory +from .reset import Reset -class AxiLiteRamWrite(Memory): +class AxiLiteRamWrite(Memory, Reset): def __init__(self, entity, name, clock, reset=None, size=1024, mem=None, *args, **kwargs): self.log = logging.getLogger(f"cocotb.{entity._name}.{name}") @@ -49,8 +50,6 @@ class AxiLiteRamWrite(Memory): self.w_channel = AxiLiteWSink(entity, name, clock, reset) self.b_channel = AxiLiteBSource(entity, name, clock, reset) - self.in_flight_operations = 0 - self.width = len(self.w_channel.bus.wdata) self.byte_size = 8 self.byte_width = self.width // self.byte_size @@ -65,7 +64,24 @@ class AxiLiteRamWrite(Memory): assert self.byte_width == len(self.w_channel.bus.wstrb) assert self.byte_width * self.byte_size == self.width - cocotb.fork(self._process_write()) + self._process_write_cr = None + + self._init_reset(reset) + + def _handle_reset(self, state): + if state: + self.log.info("Reset asserted") + if self._process_write_cr is not None: + self._process_write_cr.kill() + self._process_write_cr = None + else: + self.log.info("Reset de-asserted") + if self._process_write_cr is None: + self._process_write_cr = cocotb.fork(self._process_write()) + + self.aw_channel.clear() + self.w_channel.clear() + self.b_channel.clear() async def _process_write(self): while True: @@ -100,7 +116,7 @@ class AxiLiteRamWrite(Memory): await self.b_channel.send(b) -class AxiLiteRamRead(Memory): +class AxiLiteRamRead(Memory, Reset): def __init__(self, entity, name, clock, reset=None, size=1024, mem=None, *args, **kwargs): self.log = logging.getLogger(f"cocotb.{entity._name}.{name}") @@ -116,8 +132,6 @@ class AxiLiteRamRead(Memory): self.ar_channel = AxiLiteARSink(entity, name, clock, reset) self.r_channel = AxiLiteRSource(entity, name, clock, reset) - self.in_flight_operations = 0 - self.width = len(self.r_channel.bus.rdata) self.byte_size = 8 self.byte_width = self.width // self.byte_size @@ -130,7 +144,23 @@ class AxiLiteRamRead(Memory): assert self.byte_width * self.byte_size == self.width - cocotb.fork(self._process_read()) + self._process_read_cr = None + + self._init_reset(reset) + + def _handle_reset(self, state): + if state: + self.log.info("Reset asserted") + if self._process_read_cr is not None: + self._process_read_cr.kill() + self._process_read_cr = None + else: + self.log.info("Reset de-asserted") + if self._process_read_cr is None: + self._process_read_cr = cocotb.fork(self._process_read()) + + self.ar_channel.clear() + self.r_channel.clear() async def _process_read(self): while True: