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 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
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()
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)
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)
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()
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 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()
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
class FwriscTracerSignalBfm(): ''' Implements a signal-level BFM for the FWRISC tracer ''' def __init__(self, scope): self.listener_l = [] self.lock = Lock() self.ev = Event() self.scope = scope cocotb.fork(self.run()) pass @cocotb.coroutine def run(self): while True: yield RisingEdge(self.scope.clock) if self.scope.rd_write and self.scope.rd_waddr != 0: # print("reg_write") self.reg_write(int(self.scope.rd_waddr), int(self.scope.rd_wdata)) if self.scope.ivalid: # print("instr_exec") self.instr_exec(int(self.scope.pc), int(self.scope.instr)) if self.scope.mvalid and self.scope.mwrite: self.mem_write( int(self.scope.maddr), int(self.scope.mstrb), int(self.scope.mdata)) pass def add_addr_region(self, base, limit): # NOP pass def set_trace_all_memwrite(self, t): pass def set_trace_instr(self, all_instr, jump_instr, call_instr): pass def set_trace_reg_writes(self, t): pass def add_listener(self, l): self.listener_l.append(l) def instr_exec(self, pc, instr): for l in self.listener_l: l.instr_exec(pc, instr) def reg_write(self, waddr, wdata): for l in self.listener_l: l.reg_write(waddr, wdata) def mem_write(self, maddr, mstrb, mdata): for l in self.listener_l: l.mem_write(maddr, mstrb, mdata) @cocotb.coroutine def get_reg_info(self, raddr): yield self.lock.acquire() self.get_reg_info_req(raddr) yield self.ev.wait() ret = self.ev.data self.ev.clear() self.lock.release() return ret
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 FwriscTracerBfm(): def __init__(self): self.listener_l = [] self.lock = Lock() self.ev = Event() self.addr_region_idx = 0 pass def add_listener(self, l): self.listener_l.append(l) def add_addr_region(self, base, limit): self.set_addr_region(self.addr_region_idx, base, limit, 1) self.addr_region_idx += 1 @cocotb.bfm_export(cocotb.bfm_uint32_t, cocotb.bfm_uint32_t) def instr_exec(self, pc, instr): # print("instr_exec: " + hex(pc)) for l in self.listener_l: l.instr_exec(pc, instr) @cocotb.bfm_export(cocotb.bfm_uint32_t, cocotb.bfm_uint32_t) def reg_write(self, waddr, wdata): # print("reg_write: " + hex(waddr)) for l in self.listener_l: l.reg_write(waddr, wdata) @cocotb.bfm_export(cocotb.bfm_uint32_t, cocotb.bfm_uint32_t, cocotb.bfm_uint32_t) def mem_write(self, maddr, mstrb, mdata): # print("mem_write: " + hex(maddr)) for l in self.listener_l: l.mem_write(maddr, mstrb, mdata) @cocotb.coroutine def get_reg_info(self, raddr): yield self.lock.acquire() self.get_reg_info_req(raddr) yield self.ev.wait() ret = self.ev.data self.ev.clear() self.lock.release() return ret @cocotb.bfm_import(cocotb.bfm_uint32_t) def get_reg_info_req(self, raddr): pass @cocotb.bfm_import(cocotb.bfm_uint32_t, cocotb.bfm_uint32_t, cocotb.bfm_uint32_t, cocotb.bfm_uint32_t) def set_addr_region(self, i, base, limit, valid): pass @cocotb.bfm_export(cocotb.bfm_uint32_t, cocotb.bfm_uint32_t) def get_reg_info_ack(self, rdata, accessed): self.ev.set((rdata, accessed)) @cocotb.bfm_import(cocotb.bfm_uint32_t) def set_trace_all_memwrite(self, t): pass @cocotb.bfm_import(cocotb.bfm_uint32_t, cocotb.bfm_uint32_t, cocotb.bfm_uint32_t) def set_trace_instr(self, all_instr, jump_instr, call_instr): pass @cocotb.bfm_import(cocotb.bfm_uint32_t) def set_trace_reg_writes(self, t): pass
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 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()
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 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 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) 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) @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 if hasattr(self.bus, 'tid'): self.bus.tid <= tid if hasattr(self.bus, 'tdest'): self.bus.tdest <= dest if hasattr(self.bus, 'tuser'): self.bus.tuser <= user if hasattr(self.bus, 'tstrb'): 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()
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)
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()