Refactor CCC tests for sim target - #197
Conversation
mkj121
left a comment
There was a problem hiding this comment.
I've really only reviewed ccc_descriptors.py because it will require rework of the others. Once reworked then I am happy to review everything else.
| async def do_ccc_read(i3c_controller, desc, addr, target=None, *, count=None): | ||
| """Send a directed read CCC to a single target. Returns (ack, data). | ||
|
|
||
| If `count` is None, uses descriptor.count(target) when available, else | ||
| descriptor.base_count. | ||
| """ | ||
| assert desc.kind == "read", f"do_ccc_read called with kind={desc.kind}" | ||
| if count is None: | ||
| count = descriptor_count(desc, target) | ||
| responses = await i3c_controller.i3c_ccc_read( | ||
| ccc=desc.code, addr=addr, count=count) | ||
| ack, data = responses[0] | ||
| cocotb.log.info( | ||
| f"{desc.name} addr=0x{addr:02X} ack={ack} -> {bytes(data).hex()}" | ||
| ) | ||
| return ack, data | ||
|
|
||
|
|
||
| async def do_ccc_read_multi(i3c_controller, desc, addr_list, target=None, | ||
| *, count=None): | ||
| """Send a directed read CCC across multiple targets in one frame. | ||
|
|
||
| Returns the raw list of (ack, data) tuples, one per address. | ||
| """ | ||
| assert desc.kind == "read", ( | ||
| f"do_ccc_read_multi called with kind={desc.kind}" | ||
| ) | ||
| if count is None: | ||
| count = descriptor_count(desc, target) | ||
| responses = await i3c_controller.i3c_ccc_read( | ||
| ccc=desc.code, addr=addr_list, count=count) | ||
| cocotb.log.info( | ||
| f"{desc.name} multi addr={['0x%02X' % a for a in addr_list]} " | ||
| f"-> {len(responses)} responses" | ||
| ) | ||
| return responses | ||
|
|
||
|
|
||
| async def do_ccc_write(i3c_controller, desc, addr, target=None): | ||
| """Send a directed write CCC. Returns True if ACKed. | ||
|
|
||
| If `desc.apply_write` is not None and a target is provided, the | ||
| side-effect is mirrored on the target so subsequent reads can verify | ||
| state. | ||
| """ | ||
| assert desc.kind == "write", f"do_ccc_write called with kind={desc.kind}" | ||
| defining_byte, data_bytes = desc.gen_data(target) | ||
| kwargs = {"directed_data": [(addr, list(data_bytes))]} | ||
| if defining_byte is not None: | ||
| kwargs["defining_byte"] = defining_byte | ||
| kwargs["stop"] = True | ||
| acks = await i3c_controller.i3c_ccc_write(ccc=desc.code, **kwargs) | ||
| ok = bool(acks and acks[0]) | ||
| cocotb.log.info( | ||
| f"{desc.name} write addr=0x{addr:02X} db={defining_byte} " | ||
| f"data={list(data_bytes)} ack={ok}" | ||
| ) | ||
| if ok and desc.apply_write is not None and target is not None: | ||
| desc.apply_write(target, list(data_bytes)) | ||
| return ok | ||
|
|
||
|
|
||
| async def do_ccc_bcast(i3c_controller, desc, target=None): | ||
| """Send a broadcast write CCC. Returns True (no per-target ACK).""" | ||
| assert desc.kind == "bcast_write", ( | ||
| f"do_ccc_bcast called with kind={desc.kind}" | ||
| ) | ||
| defining_byte, data_bytes = desc.gen_data(target) | ||
| kwargs = {"broadcast_data": list(data_bytes)} | ||
| if defining_byte is not None: | ||
| kwargs["defining_byte"] = defining_byte | ||
| await i3c_controller.i3c_ccc_write(ccc=desc.code, **kwargs) | ||
| cocotb.log.info( | ||
| f"{desc.name} bcast db={defining_byte} data={list(data_bytes)}" | ||
| ) | ||
| if desc.apply_write is not None and target is not None: | ||
| desc.apply_write(target, list(data_bytes)) | ||
| return True | ||
|
|
||
|
|
||
| async def do_ccc_read_verify(i3c_controller, desc, addr, target): | ||
| """Send a directed read CCC, assert ACK, verify the value. | ||
|
|
||
| Also runs post_read_check if the descriptor supplies one. | ||
| """ | ||
| ack, data = await do_ccc_read(i3c_controller, desc, addr, target) | ||
| assert ack, f"{desc.name} NACK addr=0x{addr:02X}" | ||
| desc.verify(target, data) | ||
| if desc.post_read_check is not None: | ||
| desc.post_read_check(target) | ||
| return data |
There was a problem hiding this comment.
I am not clear why many of these functions are being re-implemented. There are routines within i3c_controller_fixed.py that implement both CCC Read (i3c_ccc_read) and CCC Write (i3c_ccc_write).
The advantages that both of the existing routines over these routines are:
- You can chain CCC commands together, e.g. by setting
stop=False - Each routine can handle either a CCC command with single or multiple Target addresses
- The write routine handles broadcast data
I would suggest the code is re-worked to re-use these existing routines.
There was a problem hiding this comment.
As I understand it, these functions are just wrappers that inherently use the functions from i3c_controller_fixed. They're there to help keep the tests smaller in terms of lines of code so it looks more readable, specially for tests that issue more than 1 CCC
There was a problem hiding this comment.
OK, let me take another look.
mkj121
left a comment
There was a problem hiding this comment.
Some additional comments
No description provided.