class UARTCommWriter(BusDriver): _signals = ["wr_stb", "wr_data", "wr_busy"] def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) self.bus.wr_stb <= 0 self.bus.wr_data <= 0 self.write_data_busy = Lock("%s_wbusy" % name) @cocotb.coroutine def write(self, data): yield self.write_data_busy.acquire() i = 0 while i < len(data): yield ReadOnly() yield RisingEdge(self.clock) if not (self.bus.wr_busy.value): if i == len(data): break self.bus.wr_data <= data[i] self.bus.wr_stb <= 1 i = i + 1 yield RisingEdge(self.clock) self.bus.wr_stb <= 0 self.write_data_busy.release()
class semaphore(): def __init__(self, count=1): self.max_count = count self.count = count self.lock = Lock("sem_lock") self.locked = False async def get(self, count=1): if self.count > count: self.count -= count await Timer(0, "NS") elif count > self.max_count: raise Exception("Tried to get {} > max count {}".format( count, self.max_count)) else: await self.lock.acquire() self.locked = True self.count -= count def put(self, count=1): if self.count < self.max_count: self.count += count if self.locked is True: self.locked = False self.lock.release() def try_get(self, count=1): if self.count >= count: self.count -= count return True return False
def __init__(self, entity, name, clock, memory, callback=None, event=None, big_endian=False, **kwargs): BusDriver.__init__(self, entity, name, clock, **kwargs) self.clock = clock self.big_endian = big_endian self.bus.ARREADY.setimmediatevalue(1) self.bus.RVALID.setimmediatevalue(0) self.bus.RLAST.setimmediatevalue(0) self.bus.AWREADY.setimmediatevalue(1) self._memory = memory self.write_address_busy = Lock("%s_wabusy" % name) self.read_address_busy = Lock("%s_rabusy" % name) self.write_data_busy = Lock("%s_wbusy" % name) cocotb.fork(self._read_data()) cocotb.fork(self._write_data())
def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) self.busy_channel = Lock("%s_busy"%(name)) self.bus.wr.setimmediatevalue(0) self.bus.rd.setimmediatevalue(0) _float_signals((self.bus.addr, self.bus.din)) self.name = name
def __init__(self, entity: SimHandleBase, name: str, clock: SimHandleBase, **kwargs: Any): BusDriver.__init__(self, entity, name, clock, **kwargs) # Drive some sensible defaults (setimmediatevalue to avoid x asserts) self.bus.AWVALID.setimmediatevalue(0) self.bus.WVALID.setimmediatevalue(0) self.bus.ARVALID.setimmediatevalue(0) self.bus.BREADY.setimmediatevalue(1) self.bus.RREADY.setimmediatevalue(1) # Set the default value (0) for the unsupported signals, which # translate to: # * Transaction IDs to 0 # * Region identifier to 0 # * Normal (non-exclusive) access # * Device non-bufferable access # * Unprivileged, secure data access # * No QoS unsupported_signals = [ "AWID", "AWREGION", "AWLOCK", "AWCACHE", "AWPROT", "AWQOS", "ARID", "ARREGION", "ARLOCK", "ARCACHE", "ARPROT", "ARQOS"] for signal in unsupported_signals: try: getattr(self.bus, signal).setimmediatevalue(0) except AttributeError: pass # Mutex for each channel to prevent contention self.write_address_busy = Lock(name + "_awbusy") self.read_address_busy = Lock(name + "_arbusy") self.write_data_busy = Lock(name + "_wbusy") self.read_data_busy = Lock(name + "_rbusy") self.write_response_busy = Lock(name + "_bbusy")
def __init__(self, scope): self.listener_l = [] self.lock = Lock() self.ev = Event() self.scope = scope cocotb.fork(self.run()) pass
class UARTCommReader(BusDriver): _signals = ["rd_data", "rd_stb"] def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) self.read_data_busy = Lock("%s_wbusy" % name) self.data = Array('B') @cocotb.coroutine def read(self, size): yield self.read_data_busy.acquire() self.data = Array('B') count = 0 while count < size: yield ReadOnly() yield RisingEdge(self.clock) if self.bus.rd_stb.value == 1: self.data.append(self.bus.rd_data.value) count += 1 yield RisingEdge(self.clock) self.read_data_busy.release() def get_data(self): return self.data
class VideoOutBus(BusDriver): """ Generate RGB Video Signals """ _signals = ["RGB", "HSYNC", "VSYNC", "DATA_EN", "HBLANK", "VBLANK"] def __init__(self, entity, name, clock, width, height, hblank, vblank): BusDriver.__init__(self, entity, name, clock) #Drive some sensible defaults self.bus.RGB.setimmediatevalue(0) self.bus.HSYNC.setimmediatevalue(0) self.bus.VSYNC.setimmediatevalue(0) self.bus.DATA_EN.setimmediatevalue(0) self.bus.HBLANK.setimmediatevalue(1) self.bus.VBLANK.setimmediatevalue(1) self.width = width self.height = height self.hblank = hblank self.vblank = vblank self.write_lock = Lock("%s_busy" % name) @cocotb.coroutine def write(self, video): #print "Video: %s" % video yield self.write_lock.acquire() yield RisingEdge(self.clock) self.bus.DATA_EN <= 1 for frame in video: for line in frame: for pixel in line: self.bus.HBLANK <= 0 self.bus.VBLANK <= 0 self.bus.HSYNC <= 1 self.bus.VSYNC <= 1 self.bus.RGB <= pixel yield RisingEdge(self.clock) #Horizontal Blank self.bus.HSYNC <= 0 self.bus.HBLANK <= 1 for i in range(self.hblank): yield RisingEdge(self.clock) self.bus.VSYNC <= 0 self.bus.VBLANK <= 1 #Vertical Blank for i in range(self.vblank): yield RisingEdge(self.clock) self.bus.DATA_EN <= 0 self.write_lock.release()
def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) # Drive some sensible defaults (setimmediatevalue to avoid x asserts) self.bus.rd_en.setimmediatevalue(0) self.bus.wr_strb.setimmediatevalue(0) # Mutex for each channel that we master to prevent contention self.write_busy = Lock("%s_wbusy" % name) self.read_busy = Lock("%s_rbusy" % name)
class BlockFIFOReadPath(BusDriver): _signals = ["RDY", "ACT", "STB", "SIZE", "DATA"] _optional_signals = ["INACTIVE"] def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) self.bus.ACT.setimmediatevalue(0) self.bus.STB.setimmediatevalue(0) self.busy = Lock("%s_busy" % name) @cocotb.coroutine def read(self, size=None): """ If set to None just keep reading """ fifo_size = 0 data = [] yield self.busy.acquire() pos = 0 while (size is None) or (pos < size): print "Within read loop: Pos: %d" % pos yield ReadOnly() #while True: while self.bus.ACT == 0: if self.bus.RDY == 1: yield RisingEdge(self.clock) self.bus.ACT <= 1 yield RisingEdge(self.clock) yield ReadOnly() print "Got act!" yield RisingEdge(self.clock) count = 0 yield ReadOnly() fifo_size = int(self.bus.SIZE) #print "FIFO Size: %d" % fifo_size while count < fifo_size: #print "Count: %d" % count yield RisingEdge(self.clock) self.bus.STB <= 1 yield ReadOnly() if size is not None: d = int(self.bus.DATA) #print "Data: %08X" % d data.append(d) count += 1 pos += 1 yield RisingEdge(self.clock) self.bus.STB <= 0 self.bus.ACT <= 0 yield RisingEdge(self.clock) self.busy.release() raise ReturnValue(data)
def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) self.bus.EN.setimmediatevalue(0) self.bus.ADR.setimmediatevalue(0) self.bus.WR_RD.setimmediatevalue(0) self.bus.BYTE_EN.setimmediatevalue(0) self.bus.WR_DATA.setimmediatevalue(0) # Mutex for each channel that we master to prevent contention self.rd_busy = Lock("%s_wbusy" % name) self.wr_busy = Lock("%s_rbusy" % name)
class AXI4StreamSlave(BusDriver): _signals = ["tvalid", "tready", "tdata"] _optional_signals = ["tlast", "tkeep", "tstrb", "tid", "tdest", "tuser"] def __init__(self, entity, name, clock, width = 32): BusDriver.__init__(self, entity, name, clock) self.width = width self.bus.tready <= 0; self.read_data_busy = Lock("%s_wbusy" % name) self.data = [] @cocotb.coroutine def read(self, wait_for_valid=True): """Read a packe of data from the Axi Ingress stream""" yield self.read_data_busy.acquire() try: # clear the data register and signal we're ready to receive some data self.data = [] self.bus.tready <= 1 if wait_for_valid: while not self.bus.tvalid.value: yield RisingEdge(self.clock) # while self.bus.tvalid.value and self.bus.tready.value: while True: if self.bus.tvalid.value and self.bus.tready.value: self.data.append(self.bus.tdata.value.integer) if self.bus.tlast.value: self.bus.tready <= 0 break yield RisingEdge(self.clock) else: self.bus.tready <= 1 while not self.bus.tlast.value: if self.bus.tvalid.value and self.bus.tready.value: self.data.append(self.bus.tdata.value.integer) yield RisingEdge(self.clock) self.bus.tready <= 0 finally: self.read_data_busy.release()
class PPFIFOWritePath(BusDriver): _signals = ["RDY", "ACT", "STB", "SIZE", "DATA"] _optional_signals = ["STARVED"] def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) self.bus.ACT.setimmediatevalue(0) self.bus.DATA.setimmediatevalue(0) self.bus.STB.setimmediatevalue(0) self.busy = Lock("%s_busy" % name) @cocotb.coroutine def write(self, data): yield self.busy.acquire() pos = 0 count = 0 total_length = len(data) rdy = 0 while pos < total_length: while True: yield ReadOnly() rdy = int(self.bus.RDY) if rdy != 0: yield RisingEdge(self.clock) break yield RisingEdge(self.clock) if (rdy & 0x01) > 0: self.bus.ACT <= 0x01 else: self.bus.ACT <= 0x02 yield RisingEdge(self.clock) length = total_length if length > int(self.bus.SIZE): length = self.bus.SIZE print "Length: %d" % length for d in data[pos:length]: self.bus.STB <= 1 self.bus.DATA <= d yield RisingEdge(self.clock) self.bus.STB <= 0 pos += length yield RisingEdge(self.clock) self.bus.ACT <= 0 yield RisingEdge(self.clock) self.busy.release()
def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) # Drive some sensible defaults (setimmediatevalue to avoid x asserts) self.bus.AWVALID.setimmediatevalue(0) self.bus.WVALID.setimmediatevalue(0) self.bus.ARVALID.setimmediatevalue(0) self.bus.BREADY.setimmediatevalue(1) self.bus.RREADY.setimmediatevalue(1) # Mutex for each channel that we master to prevent contention self.write_address_busy = Lock("%s_wabusy" % name) self.read_address_busy = Lock("%s_rabusy" % name) self.write_data_busy = Lock("%s_wbusy" % name)
def __init__(self, entity, name, clock, width=32): BusDriver.__init__(self, entity, name, clock) #Drive default values onto bus self.width = width self.strobe_width = width / 8 self.bus.TVALID.setimmediatevalue(0) self.bus.TLAST.setimmediatevalue(0) self.bus.TDATA.setimmediatevalue(0) self.bus.TKEEP.setimmediatevalue(0) self.bus.TID.setimmediatevalue(0) self.bus.TDEST.setimmediatevalue(0) self.bus.TUSER.setimmediatevalue(0) self.write_data_busy = Lock("%s_wbusy" % name)
def __init__(self, entity, name, clock, wr_fifo_name = "WR", wr_fifo_clk = None, wr_fifo_clk_period = 10, rd_fifo_name = "RD", rd_fifo_clk = None, rd_fifo_clk_period = 10): BusDriver.__init__(self, entity, name, clock) if wr_fifo_clk is None: wr_fifo_clk = entity.WR_CLK if rd_fifo_clk is None: rd_fifo_clk = entity.RD_CLK self.bus.EN.setimmediatevalue(0) self.bus.ADR.setimmediatevalue(0) self.bus.ADR_FIXED.setimmediatevalue(0) self.bus.ADR_WRAP.setimmediatevalue(0) self.bus.WR_RD.setimmediatevalue(0) self.bus.COUNT.setimmediatevalue(0) # Mutex for each channel that we master to prevent contention self.command_busy = Lock("%s_wabusy" % name) cocotb.fork(Clock(wr_fifo_clk, wr_fifo_clk_period).start()) cocotb.fork(Clock(rd_fifo_clk, rd_fifo_clk_period).start()) self.write_fifo = PPFIFOWritePath(entity, wr_fifo_name, wr_fifo_clk) self.read_fifo = PPFIFOReadPath(entity, rd_fifo_name, rd_fifo_clk)
async def test_trigger_lock(dut): """ Simple test that checks to see if context management is kept. The resource value is checked at certain points if it equals the expected amount, which is easily predictable if the context management is working. """ resource = 0 lock = Lock() async def co(): nonlocal resource await Timer(10, "ns") async with lock: for i in range(4): await Timer(10, "ns") resource += 1 cocotb.fork(co()) async with lock: for i in range(4): resource += 1 await Timer(10, "ns") assert resource == 4 await Timer(10, "ns") async with lock: assert resource == 8
def __init__(self, entity, name, clock, rdlag=None, blag=None): BusDriver.__init__(self, entity, name, clock) self.name = name # set read and write back channels simulation lag between AXI sets valid and host responds with # ready. If None - drive these signals self.log.debug ("MAXIGPMaster.__init__(): super done") if rdlag is None: self.bus.rready.setimmediatevalue(1) else: self.bus.xtra_rdlag.setimmediatevalue(rdlag) if blag is None: self.bus.bready.setimmediatevalue(1) else: self.bus.xtra_blag.setimmediatevalue(blag) self.bus.awvalid.setimmediatevalue(0) self.bus.wvalid.setimmediatevalue(0) self.bus.arvalid.setimmediatevalue(0) #just in case - set unimplemented in Zynq self.bus.arlock.setimmediatevalue(0) self.bus.arcache.setimmediatevalue(0) self.bus.arprot.setimmediatevalue(0) self.bus.arqos.setimmediatevalue(0) self.bus.awlock.setimmediatevalue(0) self.bus.awcache.setimmediatevalue(0) self.bus.awprot.setimmediatevalue(0) self.bus.awqos.setimmediatevalue(0) self.busy_channels = {} self.log.debug ("MAXIGPMaster.__init__(): pre-lock done") #Locks on each subchannel for chn in self._channels: self.log.debug ("MAXIGPMaster.__init__(): chn = %s"%(chn)) self.busy_channels[chn]=Lock("%s_%s_busy"%(name,chn))
def __init__(self, entity, name, clock, width, height, hblank, vblank): BusDriver.__init__(self, entity, name, clock) #Drive some sensible defaults self.bus.RGB.setimmediatevalue(0) self.bus.HSYNC.setimmediatevalue(0) self.bus.VSYNC.setimmediatevalue(0) self.bus.DATA_EN.setimmediatevalue(0) self.bus.HBLANK.setimmediatevalue(1) self.bus.VBLANK.setimmediatevalue(1) self.width = width self.height = height self.hblank = hblank self.vblank = vblank self.write_lock = Lock("%s_busy" % name)
class NESPPU(BusDriver): _signals = [ "X_OUT", "Y_OUT", "Y_NEXT_OUT", "PULSE_OUT", "VBLANK", "SYS_PALETTE" ] def __init__(self, entity, name, clock, width, height): BusDriver.__init__(self, entity, name, clock) self.width = width self.height = height self.bus.SYS_PALETTE.setimmediatevalue(0) self.busy = Lock("%s_busy" % name) @cocotb.coroutine def run(self, data=None): if data is None: #Generate a test image data = [[0] * self.width] * self.height for y in range(self.height): for x in range(self.width): #data[y][x] = x % 0x03F data[y][x] = 0x00 yield self.busy.acquire() print "Wait for pulse out to go high" while True: yield ReadOnly() if not self.bus.PULSE_OUT: print "Pulse out went high" yield RisingEdge(self.clock) continue yield RisingEdge(self.clock) ypos = int(self.bus.Y_OUT) xpos = int(self.bus.X_OUT) self.bus.SYS_PALETTE <= data[ypos][xpos] print "Exiting run..." self.busy.release()
def __init__(self, entity, name, clock, width=32): BusDriver.__init__(self, entity, name, clock) #drive default values onto bus self.width = width self.strobe_width = width / 8 self.bus.tvalid.setimmediatevalue(0) self.bus.tlast.setimmediatevalue(0) self.bus.tdata.setimmediatevalue(0) if hasattr(self.bus, 'tkeep'): self.bus.tkeep.setimmediatevalue(0) if hasattr(self.bus, 'tid'): self.bus.tid.setimmediatevalue(0) if hasattr(self.bus, 'tdest'): self.bus.tdest.setimmediatevalue(0) if hasattr(self.bus, 'tuser'): self.bus.tuser.setimmediatevalue(0) self.write_data_busy = Lock("%s_wbusy" % name)
def __init__(self, entity, name, clock, **kwargs): BusDriver.__init__(self, entity, name, clock) # Drive some sensible defaults (setimmediatevalue to avoid x asserts) self.bus.AWVALID.setimmediatevalue(0) self.bus.WVALID.setimmediatevalue(0) self.bus.ARVALID.setimmediatevalue(0) self.bus.BREADY.setimmediatevalue(1) self.bus.RREADY.setimmediatevalue(1) # Mutex for each channel that we master to prevent contention self.write_address_busy = Lock("%s_wabusy" % name) self.read_address_busy = Lock("%s_rabusy" % name) self.write_data_busy = Lock("%s_wbusy" % name) config = kwargs.pop('config', {}) self.config = AXI4LiteMaster._default_config.copy() for configoption, value in config.items(): self.config[configoption] = value self.log.debug("Setting config option %s to %s" % (configoption, str(value)))
async def test_except_lock(dut): """ Checks to see if exceptions cause the lock to be released. """ lock = Lock() try: async with lock: raise RuntimeError() except RuntimeError: pass async with lock: pass
class GlobalBuffer(BusDriver): _signals = ["rd_addr", "rd_data", "rd_en", "wr_addr", "wr_data", "wr_strb"] def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) # Drive some sensible defaults (setimmediatevalue to avoid x asserts) self.bus.rd_en.setimmediatevalue(0) self.bus.wr_strb.setimmediatevalue(0) # Mutex for each channel that we master to prevent contention self.write_busy = Lock("%s_wbusy" % name) self.read_busy = Lock("%s_rbusy" % name) @cocotb.coroutine def write(self, address, data, byte_enable=0b11111111, sync=True): """Write a value to an address. """ if sync: yield RisingEdge(self.clock) yield self.write_busy.acquire() self.bus.wr_addr <= address self.bus.wr_data <= data self.bus.wr_strb <= byte_enable yield RisingEdge(self.clock) self.bus.wr_strb <= 0 self.write_busy.release() @cocotb.coroutine def read(self, address, sync=True): """Read from an address. Returns: BinaryValue: The read data value. """ if sync: yield RisingEdge(self.clock) yield self.read_busy.acquire() self.bus.rd_addr <= address self.bus.rd_en <= 1 yield RisingEdge(self.clock) self.bus.rd_en <= 0 self.read_busy.release() # 2 cycle read latency yield RisingEdge(self.clock) yield ReadOnly() data = self.bus.rd_data raise ReturnValue(data)
def __init__(self, entity, name, clock, width = 100, height = 100, y_fp = 10, y_bp = 10, x_fp = 10, x_bp = 10): BusDriver.__init__(self, entity, name, clock) self.width = width self.height = height self.y_fp = y_fp self.y_bp = y_bp self.x_fp = x_fp self.x_bp = x_bp self.bus.SOF_STB.setimmediatevalue(0) self.bus.HSYNC.setimmediatevalue(0) self.bus.RED.setimmediatevalue(0) self.bus.BLUE.setimmediatevalue(0) self.bus.GREEN.setimmediatevalue(0) self.busy = Lock("%s_busy" % name)
def __init__(self, entity, name, clock, width=100, height=100, y_fp=10, y_bp=10, x_fp=10, x_bp=10): BusDriver.__init__(self, entity, name, clock) self.width = width self.height = height self.y_fp = y_fp self.y_bp = y_bp self.x_fp = x_fp self.x_bp = x_bp self.bus.SOF_STB.setimmediatevalue(0) self.bus.HSYNC.setimmediatevalue(0) self.bus.RED.setimmediatevalue(0) self.bus.BLUE.setimmediatevalue(0) self.bus.GREEN.setimmediatevalue(0) self.busy = Lock("%s_busy" % name)
class AXI4StreamSlave(BusDriver): _signals = ["TVALID", "TREADY", "TDATA"] _optional_signals = ["TLAST", "TKEEP", "TSTRB", "TID", "TDEST", "TUSER"] def __init__(self, entity, name, clock, width = 32): BusDriver.__init__(self, entity, name, clock) self.width = width self.bus.TREADY <= 0; self.read_data_busy = Lock("%s_wbusy" % name) self.data = [] @cocotb.coroutine def read(self, wait_for_valid = False): """Read a packe of data from the Axi Ingress stream""" yield self.read_data_busy.acquire() yield RisingEdge(self.clock) if wait_for_valid: while not self.bus.TVALID.value: #cocotb.log.info("Valid Not Detected") yield RisingEdge(self.clock) #cocotb.log.info("Found valid!") yield RisingEdge(self.clock) self.bus.TREADY <= 1 while self.bus.TVALID.value: yield RisingEdge(self.clock) self.data.extend(self.bus.TDATA.value) if self.bus.TLAST.value: break else: self.bus.TREADY <= 1 while True: yield ReadOnly() yield RisingEdge(self.clock) if self.bus.TVALID.value: cocotb.log.debug("Found Valid") break yield RisingEdge(self.clock) while self.bus.TVALID.value: yield RisingEdge(self.clock) self.data.extend(self.bus.TDATA.value) if self.bus.TLAST.value: break
class PSBus(BusDriver): """ Small subset of Zynq registers, used to access SAXI_HP* registers """ _signals=[ # i/o from the DUT side "clk", # output "addr", # input [31:0] "wr", # input "rd", # input "din", # input [31:0] "dout"] #output [31:0] def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) self.busy_channel = Lock("%s_busy"%(name)) self.bus.wr.setimmediatevalue(0) self.bus.rd.setimmediatevalue(0) _float_signals((self.bus.addr, self.bus.din)) self.name = name @cocotb.coroutine def write_reg(self,addr,data): yield self.busy_channel.acquire() #Only wait if it is too late (<1/2 cycle) if not int(self.clock): yield RisingEdge(self.clock) self.bus.addr <= addr self.bus.din <= data self.bus.wr <= 1 yield RisingEdge(self.clock) self.bus.wr <= 0 _float_signals((self.bus.addr, self.bus.din)) self.busy_channel.release() @cocotb.coroutine def read_reg(self,addr): yield self.busy_channel.acquire() #Only wait if it is too late (<1/2 cycle) if not int(self.clock): yield RisingEdge(self.clock) self.bus.addr <= addr self.bus.rd <= 1 yield RisingEdge(self.clock) try: data = self.bus.dout.value.integer except: bv = self.bus.dout.value bv.binstr = re.sub("[^1]","0",bv.binstr) data = bv.integer self.bus.rd <= 0 _float_signals((self.bus.addr, )) self.busy_channel.release() raise ReturnValue(data)
class AXI4LiteMaster(BusDriver): """ AXI4-Lite Master TODO: Kill all pending transactions if reset is asserted... """ _signals = ["AWVALID", "AWADDR", "AWREADY", # Write address channel "WVALID", "WREADY", "WDATA", "WSTRB", # Write data channel "BVALID", "BREADY", "BRESP", # Write response channel "ARVALID", "ARADDR", "ARREADY", # Read address channel "RVALID", "RREADY", "RRESP", "RDATA"] # Read data channel _default_config = { "address_latency" : 0, "data_latency" : 0, } def __init__(self, entity, name, clock, **kwargs): BusDriver.__init__(self, entity, name, clock) # Drive some sensible defaults (setimmediatevalue to avoid x asserts) self.bus.AWVALID.setimmediatevalue(0) self.bus.WVALID.setimmediatevalue(0) self.bus.ARVALID.setimmediatevalue(0) self.bus.BREADY.setimmediatevalue(1) self.bus.RREADY.setimmediatevalue(1) # Mutex for each channel that we master to prevent contention self.write_address_busy = Lock("%s_wabusy" % name) self.read_address_busy = Lock("%s_rabusy" % name) self.write_data_busy = Lock("%s_wbusy" % name) config = kwargs.pop('config', {}) self.config = AXI4LiteMaster._default_config.copy() for configoption, value in config.items(): self.config[configoption] = value self.log.debug("Setting config option %s to %s" % (configoption, str(value))) @cocotb.coroutine def _send_write_address(self, address, delay=0): """ Send the write address, with optional delay (in clocks) """ yield self.write_address_busy.acquire() for cycle in range(max(self.config["address_latency"], delay)): yield RisingEdge(self.clock) self.bus.AWADDR <= address self.bus.AWVALID <= 1 while True: yield ReadOnly() if self.bus.AWREADY.value: break yield RisingEdge(self.clock) yield RisingEdge(self.clock) self.bus.AWVALID <= 0 self.write_address_busy.release() @cocotb.coroutine def _send_write_data(self, data, delay=0, byte_enable=0xF): """ Send the write address, with optional delay (in clocks) """ yield self.write_data_busy.acquire() for cycle in range(max(self.config["data_latency"], delay)): yield RisingEdge(self.clock) self.bus.WDATA <= data self.bus.WVALID <= 1 self.bus.WSTRB <= byte_enable while True: yield ReadOnly() if self.bus.WREADY.value: break yield RisingEdge(self.clock) yield RisingEdge(self.clock) self.bus.WVALID <= 0 self.write_data_busy.release() @cocotb.coroutine def write(self, address, value, byte_enable=0xf, address_latency=0, data_latency=0, sync=True): """ Write a value to an address. Args: address (int): The address to write to value (int): The data value to write byte_enable (int, optional): Which bytes in value to actually write. Default is to write all bytes. address_latency (int, optional): Delay before setting the address (in clock cycles). Default is no delay. data_latency (int, optional): Delay before setting the data value (in clock cycles). Default is no delay. sync (bool, optional): Wait for rising edge on clock initially. Defaults to True. Returns: BinaryValue: The write response value Raises: AXIProtocolError: If write response from AXI is not ``OKAY`` """ if sync: yield RisingEdge(self.clock) c_addr = cocotb.fork(self._send_write_address(address, delay=address_latency)) c_data = cocotb.fork(self._send_write_data(value, byte_enable=byte_enable, delay=data_latency)) if c_addr: yield c_addr.join() if c_data: yield c_data.join() # Wait for the response while True: yield ReadOnly() if self.bus.BVALID.value and self.bus.BREADY.value: result = self.bus.BRESP.value self.log.debug("Writing to address 0x%08x with 0x%08x" % (address, value)) break yield RisingEdge(self.clock) yield RisingEdge(self.clock) if int(result): raise AXIProtocolError("Write to address 0x%08x failed with BRESP: %d" % (address, int(result))) raise ReturnValue(result) @cocotb.coroutine def read(self, address, sync=True): """ Read from an address. Args: address (int): The address to read from sync (bool, optional): Wait for rising edge on clock initially. Defaults to True. Returns: BinaryValue: The read data value Raises: AXIProtocolError: If read response from AXI is not ``OKAY`` """ if sync: yield RisingEdge(self.clock) self.bus.ARADDR <= address self.bus.ARVALID <= 1 while True: yield ReadOnly() if self.bus.ARREADY.value: break yield RisingEdge(self.clock) yield RisingEdge(self.clock) self.bus.ARVALID <= 0 while True: yield ReadOnly() if self.bus.RVALID.value and self.bus.RREADY.value: data = self.bus.RDATA.value result = self.bus.RRESP.value self.log.debug("Data at address 0x%08x is 0x%08x" % (address, data)) break yield RisingEdge(self.clock) if int(result): raise AXIProtocolError("Read address 0x%08x failed with RRESP: %d" % (address, int(result))) raise ReturnValue(data) def __len__(self): return 2**len(self.bus.ARADDR)
class AXI4StreamMaster(BusDriver): _signals = ["TVALID", "TREADY", "TDATA"] # Write data channel _optional_signals = ["TLAST", "TKEEP", "TSTRB", "TID", "TDEST", "TUSER"] def __init__(self, entity, name, clock, width=32): BusDriver.__init__(self, entity, name, clock) #Drive default values onto bus self.width = width self.strobe_width = width / 8 self.bus.TVALID.setimmediatevalue(0) self.bus.TLAST.setimmediatevalue(0) self.bus.TDATA.setimmediatevalue(0) self.bus.TKEEP.setimmediatevalue(0) self.bus.TID.setimmediatevalue(0) self.bus.TDEST.setimmediatevalue(0) self.bus.TUSER.setimmediatevalue(0) self.write_data_busy = Lock("%s_wbusy" % name) @cocotb.coroutine def write(self, data, byte_enable=-1, keep=1, tid=0, dest=0, user=0): """ Send the write data, with optional delay """ yield self.write_data_busy.acquire() self.bus.TVALID <= 0 self.bus.TLAST <= 0 self.bus.TID <= tid self.bus.TDEST <= dest self.bus.TUSER <= user self.bus.TSTRB <= (1 << self.strobe_width) - 1 if byte_enable == -1: byte_enable = (self.width >> 3) - 1 #Wait for the slave to assert tready while True: yield ReadOnly() if self.bus.TREADY.value: break yield RisingEdge(self.clock) yield RisingEdge(self.clock) #every clock cycle update the data for i in range (len(data)): self.bus.TVALID <= 1 self.bus.TDATA <= data[i] if i >= len(data) - 1: self.bus.TLAST <= 1; yield ReadOnly() if not self.bus.TREADY.value: while True: yield RisingEdge(self.clock) yield ReadOnly() if self.bus.TREADY.value: yield RisingEdge(self.clock) break continue yield RisingEdge(self.clock) self.bus.TLAST <= 0; self.bus.TVALID <= 0; yield RisingEdge(self.clock) self.write_data_busy.release() self.bus.TSTRB <= 0
def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) self.read_data_busy = Lock("%s_wbusy" % name) self.data = Array('B')
class AXI4LiteMaster(BusDriver): """ AXI4-Lite Master TODO: Kill all pending transactions if reset is asserted... """ _signals = ["AWVALID", "AWADDR", "AWREADY", # Write address channel "WVALID", "WREADY", "WDATA", "WSTRB", # Write data channel "BVALID", "BREADY", "BRESP", # Write response channel "ARVALID", "ARADDR", "ARREADY", # Read address channel "RVALID", "RREADY", "RRESP", "RDATA"] # Read data channel def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) # Drive some sensible defaults (setimmediatevalue to avoid x asserts) self.bus.AWVALID.setimmediatevalue(0) self.bus.WVALID.setimmediatevalue(0) self.bus.ARVALID.setimmediatevalue(0) self.bus.BREADY.setimmediatevalue(1) self.bus.RREADY.setimmediatevalue(1) # Mutex for each channel that we master to prevent contention self.write_address_busy = Lock("%s_wabusy" % name) self.read_address_busy = Lock("%s_rabusy" % name) self.write_data_busy = Lock("%s_wbusy" % name) @cocotb.coroutine def _send_write_address(self, address, delay=0): """ Send the write address, with optional delay """ yield self.write_address_busy.acquire() for cycle in range(delay): yield RisingEdge(self.clock) self.bus.AWADDR <= address self.bus.AWVALID <= 1 while True: yield ReadOnly() if self.bus.AWREADY.value: break yield RisingEdge(self.clock) yield RisingEdge(self.clock) self.bus.AWVALID <= 0 self.write_address_busy.release() @cocotb.coroutine def _send_write_data(self, data, delay=0, byte_enable=0xF): """ Send the write address, with optional delay """ yield self.write_data_busy.acquire() for cycle in range(delay): yield RisingEdge(self.clock) self.bus.WDATA <= data self.bus.WVALID <= 1 self.bus.WSTRB <= byte_enable while True: yield ReadOnly() if self.bus.WREADY.value: break yield RisingEdge(self.clock) yield RisingEdge(self.clock) self.bus.WVALID <= 0 self.write_data_busy.release() @cocotb.coroutine def write(self, address, value, byte_enable=0xf, address_latency=0, data_latency=0): """ Write a value to an address. The *_latency KWargs allow control over the delta """ c_addr = cocotb.fork(self._send_write_address(address, delay=address_latency)) c_data = cocotb.fork(self._send_write_data(value, byte_enable=byte_enable, delay=data_latency)) if c_addr: yield c_addr.join() if c_data: yield c_data.join() # Wait for the response while True: yield ReadOnly() if self.bus.BVALID.value and self.bus.BREADY.value: result = self.bus.BRESP.value break yield RisingEdge(self.clock) yield RisingEdge(self.clock) if int(result): raise AXIReadError("Write to address 0x%08x failed with BRESP: %d" %( address, int(result))) raise ReturnValue(result) @cocotb.coroutine def read(self, address, sync=True): """ Read from an address. """ if sync: yield RisingEdge(self.clock) self.bus.ARADDR <= address self.bus.ARVALID <= 1 while True: yield ReadOnly() if self.bus.ARREADY.value: break yield RisingEdge(self.clock) yield RisingEdge(self.clock) self.bus.ARVALID <= 0 while True: yield ReadOnly() if self.bus.RVALID.value and self.bus.RREADY.value: data = self.bus.RDATA.value result = self.bus.RRESP.value break yield RisingEdge(self.clock) if int(result): raise AXIReadError("Read address 0x%08x failed with RRESP: %d" %( address, int(result))) raise ReturnValue(data)
class CommandMaster (BusDriver): _signals = ["EN", "ERROR", "ACK", "STATUS", "INTERRUPT", "ADR", "WR_RD", "BYTE_EN", "WR_DATA", "RD_DATA"] def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) self.bus.EN.setimmediatevalue(0) self.bus.ADR.setimmediatevalue(0) self.bus.WR_RD.setimmediatevalue(0) self.bus.BYTE_EN.setimmediatevalue(0) self.bus.WR_DATA.setimmediatevalue(0) # Mutex for each channel that we master to prevent contention self.rd_busy = Lock("%s_wbusy" % name) self.wr_busy = Lock("%s_rbusy" % name) @cocotb.coroutine def write(self, address, data, byte_en = 0xF): yield self.wr_busy.acquire() yield RisingEdge(self.clock) self.bus.ADR <= address self.bus.WR_RD <= 1 self.bus.EN <= 1 self.bus.ADR <= address self.bus.WR_DATA <= data self.bus.BYTE_EN <= byte_en yield RisingEdge(self.clock) yield ReadOnly() rdy = int(self.bus.ACK) while (rdy == 0): yield RisingEdge(self.clock) yield ReadOnly() rdy = int(self.bus.ACK) yield RisingEdge(self.clock) self.bus.EN <= 0 self.wr_busy.release() @cocotb.coroutine def read(self, address): data = [] yield self.rd_busy.acquire() self.bus.ADR <= address self.bus.EN <= 1 self.bus.WR_RD <= 0 self.bus.BYTE_EN <= 0 yield RisingEdge(self.clock) yield ReadOnly() rdy = int(self.bus.ACK) while (rdy == 0): yield RisingEdge(self.clock) yield ReadOnly() rdy = int(self.bus.ACK) yield RisingEdge(self.clock) self.bus.EN <= 0
class AXI4LiteMaster(BusDriver): """AXI4-Lite Master. TODO: Kill all pending transactions if reset is asserted. """ _signals = [ "AWVALID", "AWADDR", "AWREADY", # Write address channel "WVALID", "WREADY", "WDATA", "WSTRB", # Write data channel "BVALID", "BREADY", "BRESP", # Write response channel "ARVALID", "ARADDR", "ARREADY", # Read address channel "RVALID", "RREADY", "RRESP", "RDATA" ] # Read data channel def __init__(self, entity, name, clock, **kwargs): BusDriver.__init__(self, entity, name, clock, **kwargs) # Drive some sensible defaults (setimmediatevalue to avoid x asserts) self.bus.AWVALID.setimmediatevalue(0) self.bus.WVALID.setimmediatevalue(0) self.bus.ARVALID.setimmediatevalue(0) self.bus.BREADY.setimmediatevalue(1) self.bus.RREADY.setimmediatevalue(1) # Mutex for each channel that we master to prevent contention self.write_address_busy = Lock("%s_wabusy" % name) self.read_address_busy = Lock("%s_rabusy" % name) self.write_data_busy = Lock("%s_wbusy" % name) @cocotb.coroutine def _send_write_address(self, address, delay=0): """ Send the write address, with optional delay (in clocks) """ yield self.write_address_busy.acquire() for cycle in range(delay): yield RisingEdge(self.clock) self.bus.AWADDR <= address self.bus.AWVALID <= 1 while True: yield ReadOnly() if self.bus.AWREADY.value: break yield RisingEdge(self.clock) yield RisingEdge(self.clock) self.bus.AWVALID <= 0 self.write_address_busy.release() @cocotb.coroutine def _send_write_data(self, data, delay=0, byte_enable=0xF): """Send the write address, with optional delay (in clocks).""" yield self.write_data_busy.acquire() for cycle in range(delay): yield RisingEdge(self.clock) self.bus.WDATA <= data self.bus.WVALID <= 1 self.bus.WSTRB <= byte_enable while True: yield ReadOnly() if self.bus.WREADY.value: break yield RisingEdge(self.clock) yield RisingEdge(self.clock) self.bus.WVALID <= 0 self.write_data_busy.release() @cocotb.coroutine def write(self, address, value, byte_enable=0xf, address_latency=0, data_latency=0, sync=True): """Write a value to an address. Args: address (int): The address to write to. value (int): The data value to write. byte_enable (int, optional): Which bytes in value to actually write. Default is to write all bytes. address_latency (int, optional): Delay before setting the address (in clock cycles). Default is no delay. data_latency (int, optional): Delay before setting the data value (in clock cycles). Default is no delay. sync (bool, optional): Wait for rising edge on clock initially. Defaults to True. Returns: BinaryValue: The write response value. Raises: AXIProtocolError: If write response from AXI is not ``OKAY``. """ if sync: yield RisingEdge(self.clock) c_addr = cocotb.fork( self._send_write_address(address, delay=address_latency)) c_data = cocotb.fork( self._send_write_data(value, byte_enable=byte_enable, delay=data_latency)) if c_addr: yield c_addr.join() if c_data: yield c_data.join() # Wait for the response while True: yield ReadOnly() if self.bus.BVALID.value and self.bus.BREADY.value: result = self.bus.BRESP.value break yield RisingEdge(self.clock) yield RisingEdge(self.clock) if int(result): raise AXIProtocolError( "Write to address 0x%08x failed with BRESP: %d" % (address, int(result))) return result @cocotb.coroutine def read(self, address, sync=True): """Read from an address. Args: address (int): The address to read from. sync (bool, optional): Wait for rising edge on clock initially. Defaults to True. Returns: BinaryValue: The read data value. Raises: AXIProtocolError: If read response from AXI is not ``OKAY``. """ if sync: yield RisingEdge(self.clock) self.bus.ARADDR <= address self.bus.ARVALID <= 1 while True: yield ReadOnly() if self.bus.ARREADY.value: break yield RisingEdge(self.clock) yield RisingEdge(self.clock) self.bus.ARVALID <= 0 while True: yield ReadOnly() if self.bus.RVALID.value and self.bus.RREADY.value: data = self.bus.RDATA.value result = self.bus.RRESP.value break yield RisingEdge(self.clock) if int(result): raise AXIProtocolError( "Read address 0x%08x failed with RRESP: %d" % (address, int(result))) return data def __len__(self): return 2**len(self.bus.ARADDR)
class BlockFIFOWritePath(BusDriver): _signals = ["HSYNC", "SOF_STB", "RED", "GREEN", "BLUE"] def __init__(self, entity, name, clock, width = 100, height = 100, y_fp = 10, y_bp = 10, x_fp = 10, x_bp = 10): BusDriver.__init__(self, entity, name, clock) self.width = width self.height = height self.y_fp = y_fp self.y_bp = y_bp self.x_fp = x_fp self.x_bp = x_bp self.bus.SOF_STB.setimmediatevalue(0) self.bus.HSYNC.setimmediatevalue(0) self.bus.RED.setimmediatevalue(0) self.bus.BLUE.setimmediatevalue(0) self.bus.GREEN.setimmediatevalue(0) self.busy = Lock("%s_busy" % name) @cocotb.coroutine def write(self, data = None): if data is None: #Generate a test image data = [[0] * width] * height for y in range(height): for x in range(width): data[y][x] = i % 256 yield self.busy.acquire() yield RisingEdge(self.clock) ''' self.bus.SOF_STB <= 1 yield RisingEdge(self.clock) self.bus.SOF_STB <= 0 ''' #Perform Y Front Porch Delay for i in range (self.y_fp): yield RisingEdge(self.clock) yield ReadOnly() for y in range(self.height): #Perform X Front Porch Delay for i in range (self.x_fp): yield RisingEdge(self.clock) yield ReadOnly() yield RisingEdge(self.clock) self.bus.SOF_STB <= 1 yield RisingEdge(self.clock) self.bus.SOF_STB <= 0 for x in range(self.width): yield RisingEdge() self.busy.HSYNC <= 1 self.bus.RED <= (data[y][x] >> 5) & 0x5 self.bus.GREEN <= (data[y][x] >> 2) & 0x5 self.bus.BLUE <= (data[y][x] >> 0) & 0x3 yield RisingEdge() self.busy.HSYNC <= 0 #Perform X Back Porch Delay for i in range (self.x_bp): yield RisingEdge(self.clock) yield ReadOnly() #Perform Y Back Porch Delay for i in range (self.y_bp): yield RisingEdge(self.clock) yield ReadOnly()
class CommandMaster (BusDriver): _signals = ["EN", "ERROR", "ACK", "STATUS", "INTERRUPT", "ADR", "ADR_FIXED", "ADR_WRAP", "WR_RD", "COUNT"] def __init__(self, entity, name, clock, wr_fifo_name = "WR", wr_fifo_clk = None, wr_fifo_clk_period = 10, rd_fifo_name = "RD", rd_fifo_clk = None, rd_fifo_clk_period = 10): BusDriver.__init__(self, entity, name, clock) if wr_fifo_clk is None: wr_fifo_clk = entity.WR_CLK if rd_fifo_clk is None: rd_fifo_clk = entity.RD_CLK self.bus.EN.setimmediatevalue(0) self.bus.ADR.setimmediatevalue(0) self.bus.ADR_FIXED.setimmediatevalue(0) self.bus.ADR_WRAP.setimmediatevalue(0) self.bus.WR_RD.setimmediatevalue(0) self.bus.COUNT.setimmediatevalue(0) # Mutex for each channel that we master to prevent contention self.command_busy = Lock("%s_wabusy" % name) cocotb.fork(Clock(wr_fifo_clk, wr_fifo_clk_period).start()) cocotb.fork(Clock(rd_fifo_clk, rd_fifo_clk_period).start()) self.write_fifo = PPFIFOWritePath(entity, wr_fifo_name, wr_fifo_clk) self.read_fifo = PPFIFOReadPath(entity, rd_fifo_name, rd_fifo_clk) @cocotb.coroutine def write(self, address, data): count = 0 yield self.command_busy.acquire() yield RisingEdge(self.clock) self.bus.ADR <= address self.bus.COUNT <= len(data) self.bus.WR_RD <= 1 self.bus.EN <= 1 yield RisingEdge(self.clock) print "Length of data: %d" % len(data) yield self.write_fifo.write(data) yield RisingEdge(self.clock) self.bus.EN <= 0 self.command_busy.release() @cocotb.coroutine def read(self, address, size, sync=True): count = 0 data = [] yield self.command_busy.acquire() self.bus.ADR <= address self.bus.COUNT <= size self.bus.EN <= 1 yield RisingEdge(self.clock) yield RisingEdge(self.clock) self.bus.EN <= 0 yield ReadOnly() self.command_busy.release()
def __init__(self, entity, name, clock, width = 32): BusDriver.__init__(self, entity, name, clock) self.width = width self.bus.TREADY <= 0; self.read_data_busy = Lock("%s_wbusy" % name) self.data = []
class AXI4LiteMaster(BusDriver): """ AXI4-Lite Master TODO: Kill all pending transactions if reset is asserted... """ _signals = ["AWVALID", "AWADDR", "AWREADY", # Write address channel "WVALID", "WREADY", "WDATA", "WSTRB", # Write data channel "BVALID", "BREADY", "BRESP", # Write response channel "ARVALID", "ARADDR", "ARREADY", # Read address channel "RVALID", "RREADY", "RRESP", "RDATA"] # Read data channel def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) # Drive some sensible defaults (setimmediatevalue to avoid x asserts) self.bus.AWVALID.setimmediatevalue(0) self.bus.WVALID.setimmediatevalue(0) self.bus.ARVALID.setimmediatevalue(0) self.bus.BREADY.setimmediatevalue(1) self.bus.RREADY.setimmediatevalue(1) # Mutex for each channel that we master to prevent contention self.write_address_busy = Lock("%s_wabusy" % name) self.read_address_busy = Lock("%s_rabusy" % name) self.write_data_busy = Lock("%s_wbusy" % name) @cocotb.coroutine def _send_write_address(self, address, delay=0): """ Send the write address, with optional delay """ yield self.write_address_busy.acquire() for cycle in range(delay): yield RisingEdge(self.clock) self.bus.AWADDR <= address self.bus.AWVALID <= 1 while True: yield ReadOnly() if self.bus.AWREADY.value: break yield RisingEdge(self.clock) yield RisingEdge(self.clock) self.bus.AWVALID <= 0 self.write_address_busy.release() @cocotb.coroutine def _send_write_data(self, data, delay=0, byte_enable=0xF): """ Send the write address, with optional delay """ yield self.write_data_busy.acquire() for cycle in range(delay): yield RisingEdge(self.clock) self.bus.WDATA <= data self.bus.WVALID <= 1 self.bus.WSTRB <= byte_enable while True: yield ReadOnly() if self.bus.WREADY.value: break yield RisingEdge(self.clock) yield RisingEdge(self.clock) self.bus.WVALID <= 0 self.write_data_busy.release() @cocotb.coroutine def write(self, address, value, byte_enable=0xf, address_latency=0, data_latency=0): """ Write a value to an address. The *_latency KWargs allow control over the delta """ c_addr = cocotb.fork(self._send_write_address(address, delay=address_latency)) c_data = cocotb.fork(self._send_write_data(value, byte_enable=byte_enable, delay=data_latency)) if c_addr: yield c_addr.join() if c_data: yield c_data.join() # Wait for the response while True: yield ReadOnly() if self.bus.BVALID.value and self.bus.BREADY.value: result = self.bus.BRESP.value break yield RisingEdge(self.clock) yield RisingEdge(self.clock) if int(result): raise AXIProtocolError("Write to address 0x%08x failed with BRESP: %d" % (address, int(result))) raise ReturnValue(result) @cocotb.coroutine def read(self, address, sync=True): """ Read from an address. """ if sync: yield RisingEdge(self.clock) self.bus.ARADDR <= address self.bus.ARVALID <= 1 while True: yield ReadOnly() if self.bus.ARREADY.value: break yield RisingEdge(self.clock) yield RisingEdge(self.clock) self.bus.ARVALID <= 0 while True: yield ReadOnly() if self.bus.RVALID.value and self.bus.RREADY.value: data = self.bus.RDATA.value result = self.bus.RRESP.value break yield RisingEdge(self.clock) if int(result): raise AXIProtocolError("Read address 0x%08x failed with RRESP: %d" % (address, int(result))) raise ReturnValue(data)
def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) self.bus.ACT.setimmediatevalue(0) self.bus.STB.setimmediatevalue(0) self.busy = Lock("%s_busy" % name)
def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) self.bus.wr_stb <= 0 self.bus.wr_data <= 0 self.write_data_busy = Lock("%s_wbusy" % name)
class VideoOutBus(BusDriver): """ Generate RGB Video Signals """ _signals = [ "RGB", "HSYNC", "VSYNC", "DATA_EN", "HBLANK", "VBLANK" ] def __init__(self, entity, name, clock, width, height, hblank, vblank): BusDriver.__init__(self, entity, name, clock) #Drive some sensible defaults self.bus.RGB.setimmediatevalue(0) self.bus.HSYNC.setimmediatevalue(0) self.bus.VSYNC.setimmediatevalue(0) self.bus.DATA_EN.setimmediatevalue(0) self.bus.HBLANK.setimmediatevalue(1) self.bus.VBLANK.setimmediatevalue(1) self.width = width self.height = height self.hblank = hblank self.vblank = vblank self.write_lock = Lock("%s_busy" % name) @cocotb.coroutine def write(self, video): #print "Video: %s" % video yield self.write_lock.acquire() yield RisingEdge(self.clock) self.bus.DATA_EN <= 1 for frame in video: for line in frame: for pixel in line: self.bus.HBLANK <= 0 self.bus.VBLANK <= 0 self.bus.HSYNC <= 1 self.bus.VSYNC <= 1 self.bus.RGB <= pixel yield RisingEdge(self.clock) #Horizontal Blank self.bus.HSYNC <= 0 self.bus.HBLANK <= 1 for i in range(self.hblank): yield RisingEdge(self.clock) self.bus.VSYNC <= 0 self.bus.VBLANK <= 1 #Vertical Blank for i in range(self.vblank): yield RisingEdge(self.clock) self.bus.DATA_EN <= 0 self.write_lock.release()