# Path: basil/utils/sim/Protocol.py
# class WriteRequest(ProtocolBase):
#     def __init__(self, address, data):
#         self.address = address
#         self.data = data
# 
#     def __str__(self):
#         return "WriteRequest: 0x%04x <- %s" % (self.address, self.data)
# 
# class ReadRequest(ProtocolBase):
#     def __init__(self, address, size):
#         self.address = address
#         self.size = size
# 
#     def __str__(self):
#         return "ReadRequest: 0x%04x (size %d)" % (self.address, self.size)
# 
# class ReadResponse(ProtocolBase):
#     def __init__(self, data):
#         self.data = data
# 
#     def __str__(self):
#         return "ReadResponse: %s" % str(self.data)
# 
# class PickleInterface(ProtocolBase):
#     def __init__(self, sock):
#         self.sock = sock
# 
#     def send(self, obj):
#         """Prepend a 4-byte length to the string"""
#         assert isinstance(obj, ProtocolBase)
#         string = pickle.dumps(obj)
#         length = len(string)
#         self.sock.sendall(struct.pack("<I", length) + string)
# 
#     def recv(self, blocking=True):
#         """Receive the next object from the socket"""
#         length = struct.unpack("<I", self.sock.recv(4))[0]
#         return self._get_next_obj(length)
# 
#     def try_recv(self):
#         """Return None immediately if nothing is waiting"""
#         try:
#             lenstr = self.sock.recv(4, socket.MSG_DONTWAIT)
#         except socket.error:
#             return None
#         if len(lenstr) < 4:
#             raise EOFError("Socket closed")
#         length = struct.unpack("<I", lenstr)[0]
#         return self._get_next_obj(length)
# 
#     def _get_next_obj(self, length):
#         """Assumes we've already read the object length"""
#         data = b""
#         while len(data) < length:
#             data += self.sock.recv(length - len(data))
# 
#         return pickle.loads(data)


import logging
import os
import socket
import yaml
import cocotb
from cocotb.triggers import Timer
from cocotb.clock import Clock
from basil.utils.sim.Protocol import WriteRequest, ReadRequest, ReadResponse, PickleInterface

    while True:
        dut._log.info("Waiting for incoming connection on %s:%d" % (host, int(port)))
        clientsocket, socket_address = s.accept()
        dut._log.info("New connection from %s:%d" % (socket_address[0], socket_address[1]))
        iface = PickleInterface(clientsocket)

        while True:
            # uncomment for constantly advancing clock
            # await RisingEdge(bus.clock)

            try:
                req = iface.try_recv()
            except EOFError:
                dut._log.info("Remote server closed the connection")
                clientsocket.shutdown(socket.SHUT_RDWR)
                clientsocket.close()
                break
            if req is None:
                continue

            dut._log.debug("Received: %s" % str(req))

            # add few clocks
            # for _ in range(10):
            #    await RisingEdge(bus.clock)
            await Timer(bus_transaction_wait)

            if isinstance(req, WriteRequest):
                await bus.write(req.address, req.data)

# Path: basil/utils/sim/Protocol.py
# class WriteRequest(ProtocolBase):
#     def __init__(self, address, data):
#         self.address = address
#         self.data = data
# 
#     def __str__(self):
#         return "WriteRequest: 0x%04x <- %s" % (self.address, self.data)
# 
# class ReadRequest(ProtocolBase):
#     def __init__(self, address, size):
#         self.address = address
#         self.size = size
# 
#     def __str__(self):
#         return "ReadRequest: 0x%04x (size %d)" % (self.address, self.size)
# 
# class ReadResponse(ProtocolBase):
#     def __init__(self, data):
#         self.data = data
# 
#     def __str__(self):
#         return "ReadResponse: %s" % str(self.data)
# 
# class PickleInterface(ProtocolBase):
#     def __init__(self, sock):
#         self.sock = sock
# 
#     def send(self, obj):
#         """Prepend a 4-byte length to the string"""
#         assert isinstance(obj, ProtocolBase)
#         string = pickle.dumps(obj)
#         length = len(string)
#         self.sock.sendall(struct.pack("<I", length) + string)
# 
#     def recv(self, blocking=True):
#         """Receive the next object from the socket"""
#         length = struct.unpack("<I", self.sock.recv(4))[0]
#         return self._get_next_obj(length)
# 
#     def try_recv(self):
#         """Return None immediately if nothing is waiting"""
#         try:
#             lenstr = self.sock.recv(4, socket.MSG_DONTWAIT)
#         except socket.error:
#             return None
#         if len(lenstr) < 4:
#             raise EOFError("Socket closed")
#         length = struct.unpack("<I", lenstr)[0]
#         return self._get_next_obj(length)
# 
#     def _get_next_obj(self, length):
#         """Assumes we've already read the object length"""
#         data = b""
#         while len(data) < length:
#             data += self.sock.recv(length - len(data))
# 
#         return pickle.loads(data)


# Path: basil/utils/sim/Test.py
import logging
import os
import socket
import yaml
import cocotb
from cocotb.triggers import Timer
from cocotb.clock import Clock
from basil.utils.sim.Protocol import WriteRequest, ReadRequest, ReadResponse, PickleInterface


    while True:
        dut._log.info("Waiting for incoming connection on %s:%d" % (host, int(port)))
        clientsocket, socket_address = s.accept()
        dut._log.info("New connection from %s:%d" % (socket_address[0], socket_address[1]))
        iface = PickleInterface(clientsocket)

        while True:
            # uncomment for constantly advancing clock
            # await RisingEdge(bus.clock)

            try:
                req = iface.try_recv()
            except EOFError:
                dut._log.info("Remote server closed the connection")
                clientsocket.shutdown(socket.SHUT_RDWR)
                clientsocket.close()
                break
            if req is None:
                continue

            dut._log.debug("Received: %s" % str(req))

            # add few clocks
            # for _ in range(10):
            #    await RisingEdge(bus.clock)
            await Timer(bus_transaction_wait)

            if isinstance(req, WriteRequest):
                await bus.write(req.address, req.data)

            elif isinstance(req, ReadRequest):