Skip to content

Commit

Permalink
Update simulation framework
Browse files Browse the repository at this point in the history
- move clock generation from bus to test
- add parameters to set clocks
- add wait timer before/after transaction 
  • Loading branch information
themperek committed Jun 23, 2021
1 parent 45e3552 commit c3ba370
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 142 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/regression-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ jobs:
- name: Install Python dependencies
shell: bash -l {0}
run: |
pip install pyvisa pyvisa-sim pytest coveralls pytest-cov cocotb==1.4.0
pip install pyvisa pyvisa-sim pytest coveralls pytest-cov cocotb==1.5.2
- name: Install Verilator
if: matrix.sim == 'verilator'
Expand Down
37 changes: 16 additions & 21 deletions basil/utils/sim/BasilBusDriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,14 @@
# pylint: disable=pointless-statement, expression-not-assigned


import cocotb
from cocotb.binary import BinaryValue
from cocotb.triggers import RisingEdge, Timer
from cocotb.drivers import BusDriver
from cocotb.clock import Clock
from cocotb_bus.drivers import BusDriver


class BasilBusDriver(BusDriver):
"""Abastract away interactions with the control bus.
"""
"""Abastract away interactions with the control bus."""

_signals = ["BUS_CLK", "BUS_RST", "BUS_DATA", "BUS_ADD", "BUS_RD", "BUS_WR"]
_optional_signals = ["BUS_BYTE_ACCESS"]

Expand All @@ -36,9 +34,6 @@ def __init__(self, entity):

self._has_byte_acces = False

# Kick off a clock generator
cocotb.fork(Clock(self.clock, 5000).start())

async def init(self):
# Defaults
self.bus.BUS_RST <= 1
Expand All @@ -57,7 +52,7 @@ async def init(self):

# why this does not work? hasattr(self.bus, 'BUS_BYTE_ACCESS'):
try:
getattr(self.bus, 'BUS_BYTE_ACCESS')
getattr(self.bus, "BUS_BYTE_ACCESS")
except Exception:
self._has_byte_acces = False
else:
Expand All @@ -73,8 +68,8 @@ async def read(self, address, size):
await RisingEdge(self.clock)

byte = 0
while(byte <= size):
if(byte == size):
while byte <= size:
if byte == size:
self.bus.BUS_RD <= 0
else:
self.bus.BUS_RD <= 1
Expand All @@ -83,20 +78,20 @@ async def read(self, address, size):

await RisingEdge(self.clock)

if(byte != 0):
if(self._has_byte_acces and self.bus.BUS_BYTE_ACCESS.value.integer == 0):
result.append(self.bus.BUS_DATA.value.integer & 0x000000ff)
result.append((self.bus.BUS_DATA.value.integer & 0x0000ff00) >> 8)
result.append((self.bus.BUS_DATA.value.integer & 0x00ff0000) >> 16)
result.append((self.bus.BUS_DATA.value.integer & 0xff000000) >> 24)
if byte != 0:
if self._has_byte_acces and self.bus.BUS_BYTE_ACCESS.value.integer == 0:
result.append(self.bus.BUS_DATA.value.integer & 0x000000FF)
result.append((self.bus.BUS_DATA.value.integer & 0x0000FF00) >> 8)
result.append((self.bus.BUS_DATA.value.integer & 0x00FF0000) >> 16)
result.append((self.bus.BUS_DATA.value.integer & 0xFF000000) >> 24)
else:
# result.append(self.bus.BUS_DATA.value[24:31].integer & 0xff)
if len(self.bus.BUS_DATA.value) == 8:
result.append(self.bus.BUS_DATA.value.integer & 0xff)
result.append(self.bus.BUS_DATA.value.integer & 0xFF)
else:
result.append(self.bus.BUS_DATA.value[24:31].integer & 0xff)
result.append(self.bus.BUS_DATA.value[24:31].integer & 0xFF)

if(self._has_byte_acces and self.bus.BUS_BYTE_ACCESS.value.integer == 0):
if self._has_byte_acces and self.bus.BUS_BYTE_ACCESS.value.integer == 0:
byte += 4
else:
byte += 1
Expand Down Expand Up @@ -126,7 +121,7 @@ async def write(self, address, data):

await RisingEdge(self.clock)

if(self._has_byte_acces and self.bus.BUS_BYTE_ACCESS.value.integer == 0):
if self._has_byte_acces and self.bus.BUS_BYTE_ACCESS.value.integer == 0:
raise NotImplementedError("BUS_BYTE_ACCESS for write to be implemented.")

self.bus.BUS_DATA <= self._high_impedence
Expand Down
80 changes: 34 additions & 46 deletions basil/utils/sim/BasilSbusDriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,18 @@
# SiLab, Institute of Physics, University of Bonn
# ------------------------------------------------------------
#
# Initial version by Chris Higgs <[email protected]>
#

# pylint: disable=pointless-statement, expression-not-assigned


import cocotb
from cocotb.binary import BinaryValue
from cocotb.triggers import RisingEdge
from cocotb.drivers import BusDriver
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, ReadOnly
from cocotb_bus.drivers import BusDriver


class BasilSbusDriver(BusDriver):
"""Abastract away interactions with the control bus.
"""
"""Abastract away interactions with the control bus."""

_signals = ["BUS_CLK", "BUS_RST", "BUS_DATA_IN", "BUS_DATA_OUT", "BUS_ADD", "BUS_RD", "BUS_WR"]
_optional_signals = ["BUS_BYTE_ACCESS"]

Expand All @@ -36,9 +32,6 @@ def __init__(self, entity):

self._has_byte_acces = False

# Kick off a clock generator
cocotb.fork(Clock(self.clock, 5000).start())

async def init(self):
# Defaults
self.bus.BUS_RST <= 1
Expand All @@ -57,7 +50,7 @@ async def init(self):

# why this does not work? hasattr(self.bus, 'BUS_BYTE_ACCESS'):
try:
getattr(self.bus, 'BUS_BYTE_ACCESS')
getattr(self.bus, "BUS_BYTE_ACCESS")
except Exception:
self._has_byte_acces = False
else:
Expand All @@ -66,55 +59,52 @@ async def init(self):
async def read(self, address, size):
result = []

self.bus.BUS_ADD <= self._x
self.bus.BUS_DATA_IN <= self._high_impedance
self.bus.BUS_RD <= 0

await RisingEdge(self.clock)

if size == 0:
return result

self.bus.BUS_RD <= 1
self.bus.BUS_ADD <= address

byte = 0
while(byte <= size):
if(byte == size):
self.bus.BUS_RD <= 0
else:
self.bus.BUS_RD <= 1

self.bus.BUS_ADD <= address + byte
while byte < size:

await RisingEdge(self.clock)

if(byte != 0):
if(self._has_byte_acces and self.bus.BUS_BYTE_ACCESS.value.integer == 0):
result.append(self.bus.BUS_DATA_OUT.value.integer & 0x000000ff)
result.append((self.bus.BUS_DATA_OUT.value.integer & 0x0000ff00) >> 8)
result.append((self.bus.BUS_DATA_OUT.value.integer & 0x00ff0000) >> 16)
result.append((self.bus.BUS_DATA_OUT.value.integer & 0xff000000) >> 24)
else:
# result.append(self.bus.BUS_DATA_OUT.value[24:31].integer & 0xff)
if len(self.bus.BUS_DATA_OUT.value) == 8:
result.append(self.bus.BUS_DATA_OUT.value.integer & 0xff)
else:
result.append(self.bus.BUS_DATA_OUT.value[24:31].integer & 0xff)

if(self._has_byte_acces and self.bus.BUS_BYTE_ACCESS.value.integer == 0):
if self._has_byte_acces and self.bus.BUS_BYTE_ACCESS.value.integer == 0:
byte += 4
else:
byte += 1

self.bus.BUS_ADD <= self._x
self.bus.BUS_DATA_IN <= self._high_impedance
self.bus.BUS_RD <= 0
self.bus.BUS_ADD <= address + byte
if byte >= size:
self.bus.BUS_RD <= 0

await ReadOnly()

value = self.bus.BUS_DATA_OUT.value

if self._has_byte_acces and self.bus.BUS_BYTE_ACCESS.value.integer == 0:
result.append(value.integer & 0x000000FF)
result.append((value.integer & 0x0000FF00) >> 8)
result.append((value.integer & 0x00FF0000) >> 16)
result.append((value.integer & 0xFF000000) >> 24)
elif len(value) == 8:
result.append(value.integer & 0xFF)
else:
result.append(value[24:31].integer & 0xFF)

await RisingEdge(self.clock)

self.bus.BUS_ADD <= self._x
self.bus.BUS_RD <= 0

return result

async def write(self, address, data):

self.bus.BUS_ADD <= self._x
self.bus.BUS_DATA_IN <= self._high_impedance
self.bus.BUS_WR <= 0

await RisingEdge(self.clock)

for index, byte in enumerate(data):
Expand All @@ -124,11 +114,9 @@ async def write(self, address, data):

await RisingEdge(self.clock)

if(self._has_byte_acces and self.bus.BUS_BYTE_ACCESS.value.integer == 0):
if self._has_byte_acces and self.bus.BUS_BYTE_ACCESS.value.integer == 0:
raise NotImplementedError("BUS_BYTE_ACCESS for write to be implemented.")

self.bus.BUS_ADD <= self._x
self.bus.BUS_DATA_IN <= self._high_impedance
self.bus.BUS_WR <= 0

await RisingEdge(self.clock)
6 changes: 1 addition & 5 deletions basil/utils/sim/Protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ class ProtocolBase(object):


class WriteRequest(ProtocolBase):

def __init__(self, address, data):
self.address = address
self.data = data
Expand All @@ -31,7 +30,6 @@ def __str__(self):


class ReadRequest(ProtocolBase):

def __init__(self, address, size):
self.address = address
self.size = size
Expand All @@ -41,7 +39,6 @@ def __str__(self):


class ReadResponse(ProtocolBase):

def __init__(self, data):
self.data = data

Expand All @@ -50,7 +47,6 @@ def __str__(self):


class PickleInterface(ProtocolBase):

def __init__(self, sock):
self.sock = sock

Expand Down Expand Up @@ -79,7 +75,7 @@ def try_recv(self):

def _get_next_obj(self, length):
"""Assumes we've already read the object length"""
data = b''
data = b""
while len(data) < length:
data += self.sock.recv(length - len(data))

Expand Down
14 changes: 7 additions & 7 deletions basil/utils/sim/SiLibUsb.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ class SiUSBDevice(object):
HIGH_ADDRESS_EXTERNAL = 0x10000 + 0x10000

BASE_ADDRESS_BLOCK = 0x0001000000000000
HIGH_ADDRESS_BLOCK = 0xffffffffffffffff
HIGH_ADDRESS_BLOCK = 0xFFFFFFFFFFFFFFFF

def __init__(self, device=None, simulation_host='localhost', simulation_port=12345):
def __init__(self, device=None, simulation_host="localhost", simulation_port=12345):
self._sock = None
self.simulation_host = simulation_host
self.simulation_port = simulation_port
Expand Down Expand Up @@ -70,23 +70,23 @@ def ReadExternal(self, address, size):
resp = self._iface.recv()
if not isinstance(resp, ReadResponse):
raise ValueError("Communication error with Simulation: got %s" % repr(resp))
return array.array('B', resp.data)
return array.array("B", resp.data)

def FastBlockRead(self, size):
req = ReadRequest(self.BASE_ADDRESS_BLOCK, size)
self._iface.send(req)
resp = self._iface.recv()
if not isinstance(resp, ReadResponse):
raise ValueError("Communication error with Simulation: got %s" % repr(resp))
return array.array('B', resp.data)
return array.array("B", resp.data)

def FastBlockWrite(self, data):
req = WriteRequest(self.BASE_ADDRESS_BLOCK, data)
self._iface.send(req)

def WriteI2C(self, address, data):
print('SiUSBDevice:WriteI2C: {} {}'.format(address, data))
print("SiUSBDevice:WriteI2C: {} {}".format(address, data))

def ReadI2C(self, address, size):
print('SiUSBDevice:ReadI2C')
return array.array('B', range(size))
print("SiUSBDevice:ReadI2C")
return array.array("B", range(size))
21 changes: 8 additions & 13 deletions basil/utils/sim/SiLibUsbBusDriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@
"""
Abastract away interactions with the control bus
"""
import cocotb
from cocotb.binary import BinaryValue
from cocotb.triggers import RisingEdge, ReadOnly, Timer
from cocotb.drivers import BusDriver
from cocotb.clock import Clock
from cocotb_bus.drivers import BusDriver


class SiLibUsbBusDriver(BusDriver):
Expand All @@ -30,7 +28,7 @@ class SiLibUsbBusDriver(BusDriver):
HIGH_ADDRESS_EXTERNAL = 0x10000 + 0x10000

BASE_ADDRESS_BLOCK = 0x0001000000000000
HIGH_ADDRESS_BLOCK = 0xffffffffffffffff
HIGH_ADDRESS_BLOCK = 0xFFFFFFFFFFFFFFFF

def __init__(self, entity):
BusDriver.__init__(self, entity, "", entity.FCLK_IN)
Expand All @@ -43,9 +41,6 @@ def __init__(self, entity):
self._x = BinaryValue(n_bits=16)
self._x.binstr = "x" * 16

# Kick off a clock generator
cocotb.fork(Clock(self.clock, 20800).start())

async def init(self):
# Defaults
# self.bus.BUS_RST<= 1
Expand All @@ -64,15 +59,15 @@ async def init(self):

async def read(self, address, size):
result = []
if(address >= self.BASE_ADDRESS_I2C and address < self.HIGH_ADDRESS_I2C):
if address >= self.BASE_ADDRESS_I2C and address < self.HIGH_ADDRESS_I2C:
self.entity._log.warning("I2C address space supported in simulation!")
for byte in range(size):
result.append(0)
elif(address >= self.BASE_ADDRESS_EXTERNAL and address < self.HIGH_ADDRESS_EXTERNAL):
elif address >= self.BASE_ADDRESS_EXTERNAL and address < self.HIGH_ADDRESS_EXTERNAL:
for byte in range(size):
val = await self.read_external(address - self.BASE_ADDRESS_EXTERNAL + byte)
result.append(val)
elif(address >= self.BASE_ADDRESS_BLOCK and address < self.HIGH_ADDRESS_BLOCK):
elif address >= self.BASE_ADDRESS_BLOCK and address < self.HIGH_ADDRESS_BLOCK:
for byte in range(size):
val = await self.fast_block_read()
result.append(val)
Expand All @@ -82,12 +77,12 @@ async def read(self, address, size):
return result

async def write(self, address, data):
if(address >= self.BASE_ADDRESS_I2C and address < self.HIGH_ADDRESS_I2C):
if address >= self.BASE_ADDRESS_I2C and address < self.HIGH_ADDRESS_I2C:
self.entity._log.warning("I2C address space supported in simulation!")
elif(address >= self.BASE_ADDRESS_EXTERNAL and address < self.HIGH_ADDRESS_EXTERNAL):
elif address >= self.BASE_ADDRESS_EXTERNAL and address < self.HIGH_ADDRESS_EXTERNAL:
for index, byte in enumerate(data):
await self.write_external(address - self.BASE_ADDRESS_EXTERNAL + index, byte)
elif(address >= self.BASE_ADDRESS_BLOCK and address < self.HIGH_ADDRESS_BLOCK):
elif address >= self.BASE_ADDRESS_BLOCK and address < self.HIGH_ADDRESS_BLOCK:
raise NotImplementedError("Unsupported request")
# self._sidev.FastBlockWrite(data)
else:
Expand Down
Loading

0 comments on commit c3ba370

Please sign in to comment.