def m_fifo_2clock_cascade( wclk, # in: write side clock datain, # in: write data src_rdy_i, # in: dst_rdy_o, # out: space, # out: how many can be written rclk, # in: read side clock dataout, # out: read data src_rdy_o, # out: dst_rdy_i, # in: occupied, # out: number in the fifo reset, # in: system reset ): wr = Signal(bool(0)) rd = Signal(bool(0)) dataout_d = Signal(intbv(0, min=dataout.min, max=dataout.max)) args = Namespace(width=36, size=128, name='fifo_2clock_cascade') fbus = FIFOBus(args=args) # need to update the fbus refernces to reference the Signals in # the moudule port list (function arguments). fbus.wr = wr fbus.wdata = datain fbus.rd = rd fbus.rdata = dataout_d @always_comb def rtl_assign1(): wr.next = src_rdy_i & dst_rdy_o rd.next = dst_rdy_i & src_rdy_o @always_comb def rtl_assign2(): dst_rdy_o.next = not fbus.full src_rdy_o.next = not fbus.empty # the original was a chain: # m_fifo_fast (16) # m_fifo_async (??) # m_fifo_fast (16) gfifo = fifo_async(reset, wclk, rclk, fbus) # @todo: calculate space and occupied based on fbus.count # @todo: the output is delayed two clock from the "read" strobe # the m_fifo_async only has a delta of one (read valid strobe # aligns with valid data). Need to delay the data one more # clock cycle??? @always(rclk.posedge) def rtl_delay(): dataout.next = dataout_d return rtl_assign1, rtl_assign2, gfifo, rtl_delay
def fifo_2clock_cascade( wclk, # in: write side clock datain, # in: write data src_rdy_i, # in: dst_rdy_o, # out: space, # out: how many can be written rclk, # in: read side clock dataout, # out: read data src_rdy_o, # out: dst_rdy_i, # in: occupied, # out: number in the fifo reset, # in: system reset ): """ """ wr = Signal(bool(0)) rd = Signal(bool(0)) dataout_d = Signal(intbv(0, min=dataout.min, max=dataout.max)) args = Namespace(width=36, size=128, name='fifo_2clock_cascade') fbus = FIFOBus(width=args.width) # need to update the fbus references to reference the Signals in # the module port list (function arguments). fbus.write = wr fbus.write_data = datain fbus.read = rd fbus.read_data = dataout_d @always_comb def beh_assign1(): wr.next = src_rdy_i & dst_rdy_o rd.next = dst_rdy_i & src_rdy_o @always_comb def beh_assign2(): dst_rdy_o.next = not fbus.full src_rdy_o.next = not fbus.empty # the original was a chain: # fifo_fast (16) # fifo_async (??) # fifo_fast (16) fifo_inst = fifo_async(wclk, rclk, fbus, reset=reset, size=args.size) # @todo: calculate space and occupied based on fbus.count # @todo: the output is delayed two clock from the "read" strobe # the m_fifo_async only has a delta of one (read valid strobe # aligns with valid data). Need to delay the data one more # clock cycle??? @always(rclk.posedge) def beh_delay(): dataout.next = dataout_d return myhdl.instances()
def _test1(): tbdut = fifo_async(reset, wclk, rclk, fbus) @instance def tbstim(): print("start test 1") fbus.wdata.next = 0xFE reset.next = reset.active yield delay(3 * 33) reset.next = not reset.active # reset is delayed by at least two for ii in range(5): yield wclk.posedge # test normal cases for num_bytes in range(1, args.size + 1): # Write some byte for ii in range(num_bytes): yield wclk.posedge fbus.wdata.next = ii fbus.wr.next = True yield wclk.posedge fbus.wr.next = False # If 16 bytes written make sure FIFO is full yield wclk.posedge if num_bytes == args.size: assert fbus.full, "FIFO should be full!" while fbus.empty: yield rclk.posedge fbus.rd.next = True yield rclk.posedge for ii in range(num_bytes): yield rclk.posedge fbus.rd.next = True assert fbus.rvld assert fbus.rdata == ii, "rdata %x ii %x " % (fbus.rdata, ii) yield rclk.posedge fbus.rd.next = False yield rclk.posedge assert fbus.empty # Test overflows # Test underflows # Test write / read same time raise StopSimulation return tbdut, tbwclk, tbrclk, tbstim
def bench_async_fifo(): tbclkw = wclk.gen() tbclkr = rclk.gen() tbdut = fifo_async(wclk, rclk, fbus, reset) tbpr = procuder_consumer(wclk, rclk, fbus, start) @instance def tbstim(): print("start test 1") fbus.write_data.next = 0xFE reset.next = reset.active yield delay(3 * 33) reset.next = not reset.active # reset is delayed by at least two for ii in range(5): yield wclk.posedge # test normal cases for num_bytes in range(1, args.size + 1): # Write some byte for ii in range(num_bytes): yield wclk.posedge fbus.write_data.next = ii fbus.write.next = True yield wclk.posedge fbus.write.next = False # If 16 bytes written make sure FIFO is full yield wclk.posedge if num_bytes == args.size: assert fbus.full, "FIFO should be full!" while fbus.empty: yield rclk.posedge fbus.read.next = True yield rclk.posedge for ii in range(num_bytes): yield rclk.posedge fbus.read.next = True assert fbus.read_valid assert fbus.read_data == ii, "rdata %x ii %x " % ( fbus.read_data, ii) yield rclk.posedge fbus.read.next = False yield rclk.posedge assert fbus.empty raise StopSimulation return myhdl.instances()
def _test1(): tbdut = fifo_async(reset, wclk, rclk, fbus) @instance def tbstim(): print("start test 1") fbus.wdata.next = 0xFE reset.next = reset.active yield delay(3*33) reset.next = not reset.active # reset is delayed by at least two for ii in range(5): yield wclk.posedge # test normal cases for num_bytes in range(1, args.size+1): # Write some byte for ii in range(num_bytes): yield wclk.posedge fbus.wdata.next = ii fbus.wr.next = True yield wclk.posedge fbus.wr.next = False # If 16 bytes written make sure FIFO is full yield wclk.posedge if num_bytes == args.size: assert fbus.full, "FIFO should be full!" while fbus.empty: yield rclk.posedge fbus.rd.next = True yield rclk.posedge for ii in range(num_bytes): yield rclk.posedge fbus.rd.next = True assert fbus.rvld assert fbus.rdata == ii, "rdata %x ii %x " % (fbus.rdata, ii) yield rclk.posedge fbus.rd.next = False yield rclk.posedge assert fbus.empty # Test overflows # Test underflows # Test write / read same time raise StopSimulation return tbdut, tbwclk, tbrclk, tbstim
def bench_async_fifo(): tbclkw = wclk.gen() tbclkr = rclk.gen() tbdut = fifo_async(wclk, rclk, fbus, reset) tbpr = procuder_consumer(wclk, rclk, fbus, start) @instance def tbstim(): print("start test 1") fbus.write_data.next = 0xFE reset.next = reset.active yield delay(3*33) reset.next = not reset.active # reset is delayed by at least two for ii in range(5): yield wclk.posedge # test normal cases for num_bytes in range(1, args.size+1): # Write some byte for ii in range(num_bytes): yield wclk.posedge fbus.write_data.next = ii fbus.write.next = True yield wclk.posedge fbus.write.next = False # If 16 bytes written make sure FIFO is full yield wclk.posedge if num_bytes == args.size: assert fbus.full, "FIFO should be full!" while fbus.empty: yield rclk.posedge fbus.read.next = True yield rclk.posedge for ii in range(num_bytes): yield rclk.posedge fbus.read.next = True assert fbus.read_valid assert fbus.read_data == ii, "rdata %x ii %x " % (fbus.read_data, ii) yield rclk.posedge fbus.read.next = False yield rclk.posedge assert fbus.empty raise StopSimulation return myhdl.instances()
def _test2(): tbdut = fifo_async(reset, wclk, rclk, fbus) @instance def tbstim(): print("start test 2") fbus.wdata.next = 0xFE reset.next = reset.active yield delay(3 * 33) reset.next = not reset.active yield delay(44) start.next = True for ii in range(2048): yield delay(100) raise StopSimulation return (tbdut, tbwclk, tbrclk, tb_always_wr, tb_always_wr_gate, tb_always_rd, tbstim)
def _test2(): tbdut = fifo_async(reset, wclk, rclk, fbus) @instance def tbstim(): print("start test 2") fbus.wdata.next = 0xFE reset.next = reset.active yield delay(3*33) reset.next = not reset.active yield delay(44) start.next = True for ii in range(2048): yield delay(100) raise StopSimulation return (tbdut, tbwclk, tbrclk, tb_always_wr, tb_always_wr_gate, tb_always_rd, tbstim)
def bench_(): tbclkw = wclk.gen() tbclkr = rclk.gen() tbdut = fifo_async(wclk, rclk, fbus, reset) tbpr = procuder_consumer(wclk, rclk, fbus, start) @instance def tbstim(): print("start test 2") fbus.write_data.next = 0xFE reset.next = reset.active yield delay(3 * 33) reset.next = not reset.active yield delay(44) start.next = True for ii in range(2048): yield delay(100) raise StopSimulation return myhdl.instances()
def bench_(): tbclkw = wclk.gen() tbclkr = rclk.gen() tbdut = fifo_async(wclk, rclk, fbus, reset) tbpr = procuder_consumer(wclk, rclk, fbus, start) @instance def tbstim(): print("start test 2") fbus.write_data.next = 0xFE reset.next = reset.active yield delay(3*33) reset.next = not reset.active yield delay(44) start.next = True for ii in range(2048): yield delay(100) raise StopSimulation return myhdl.instances()
def emesh_fifo(reset, emesh_i, emesh_o): """ EMesh transmit FIFO """ # @todo: add rx channels ... nbits = len(emesh_i.txwr.bits) fbus_wr, fbus_rd, fbus_rr = [FIFOBus(width=nbits) for _ in range(3)] @myhdl.block def emesh_to_fifo(epkt, fbus): """ assign the EMesh inputs to the FIFO bus """ @always_comb def beh_assign(): fbus.write_data.next = epkt.bits print(epkt) if epkt.access: fbus.write.next = True else: fbus.write.next = False return beh_assign, def fifo_to_emesh(fbus, epkt, clock): """ assign FIFO bus to emesh output """ fpkt = EMeshPacket() # map the bit-vector to the EMeshPacket interface map_inst = epkt_from_bits(fpkt, fbus.read_data) # the FIFOs work with a read acknowledge vs. a read # request - meaning the data is available before the # read and transitions to the next data after the read # strobe # @todo: there is (might be) an error here if the FIFO # works in read-ack, if wait is set the same packet # will be stuck on the bus, need to make sure the EMesh # ignores the packet when wait is set @always_comb def beh_read(): if not fbus.empty and not epkt.wait: fbus.read.next = True else: fbus.read.next = False @always(clock.posedge) def beh_assign(): # @todo: check and see if this will convert fine # @todo: epkt.assign(fpkt) if fbus.read_valid: print("YES READ VALID {} {} {}".format(fbus.read_data, fpkt, epkt)) epkt.access.next = fpkt.access epkt.write.next = fpkt.write epkt.datamode.next = fpkt.datamode epkt.ctrlmode.next = fpkt.ctrlmode epkt.dstaddr.next = fpkt.dstaddr epkt.data.next = fpkt.data epkt.srcaddr.next = fpkt.srcaddr else: epkt.access.next = False return map_inst, beh_read, beh_assign # create a FIFO foreach channel: write, read, read-response fifo_insts = [] for epkt, fifobus in zip((emesh_i.txwr, emesh_i.txrd, emesh_i.txrr,), (fbus_wr, fbus_rd, fbus_rr,)): fifo_insts += emesh_to_fifo(epkt, fifobus) fifo_insts += fifo_async( clock_write=emesh_i.clock, clock_read=emesh_o.clock, fifobus=fifobus, reset=reset, size=16 ) # assign the output of the FIFO for epkt, fifobus in zip((emesh_o.txwr, emesh_o.txrd, emesh_o.txrr,), (fbus_wr, fbus_rd, fbus_rr,)): fifo_insts += fifo_to_emesh(fifobus, epkt, emesh_o.clock) return fifo_insts
def bench_conversion_fifo_async(): args = Namespace(width=8, size=32, fifosize=64, name='test') clock_write, clock_read = Signals(bool(0), 2) reset = ResetSignal(0, active=1, async=False) fbus = FIFOBus(width=args.width) fifosize = args.fifosize tbdut = fifo_async(clock_write, clock_read, fbus, reset, size=fifosize) @instance def tbclkr(): clock_read.next = False while True: yield delay(5) clock_read.next = not clock_read @instance def tbclkw(): clock_write.next = False while True: yield delay(5) clock_write.next = not clock_write @instance def tbstim(): print("start simulation") fbus.write.next = False fbus.write_data.next = 0 fbus.read.next = False fbus.clear.next = False print("reset") reset.next = reset.active yield delay(10) reset.next = not reset.active yield delay(10) print("some clock cycles") for ii in range(10): yield clock_write.posedge print("some writes") for ii in range(fifosize): fbus.write.next = True fbus.write_data.next = ii yield clock_write.posedge fbus.write.next = False yield clock_write.posedge for ii in range(fifosize): fbus.read.next = True yield clock_read.posedge print("%d %d %d %d" % ( fbus.write, fbus.write_data, fbus.read, fbus.read_data, )) fbus.read.next = False print("end simulation") raise StopSimulation return myhdl.instances()
def emesh_fifo(reset, emesh_i, emesh_o): """ EMesh transmit FIFO """ # @todo: add rx channels ... nbits = len(emesh_i.txwr.bits) fbus_wr, fbus_rd, fbus_rr = [FIFOBus(width=nbits) for _ in range(3)] @myhdl.block def emesh_to_fifo(epkt, fbus): """ assign the EMesh inputs to the FIFO bus """ @always_comb def beh_assign(): fbus.write_data.next = epkt.bits print(epkt) if epkt.access: fbus.write.next = True else: fbus.write.next = False return beh_assign, def fifo_to_emesh(fbus, epkt, clock): """ assign FIFO bus to emesh output """ fpkt = EMeshPacket() # map the bit-vector to the EMeshPacket interface map_inst = epkt_from_bits(fpkt, fbus.read_data) # the FIFOs work with a read acknowledge vs. a read # request - meaning the data is available before the # read and transitions to the next data after the read # strobe # @todo: there is (might be) an error here if the FIFO # works in read-ack, if wait is set the same packet # will be stuck on the bus, need to make sure the EMesh # ignores the packet when wait is set @always_comb def beh_read(): if not fbus.empty and not epkt.wait: fbus.read.next = True else: fbus.read.next = False @always(clock.posedge) def beh_assign(): # @todo: check and see if this will convert fine # @todo: epkt.assign(fpkt) if fbus.read_valid: print("YES READ VALID {} {} {}".format(fbus.read_data, fpkt, epkt)) epkt.access.next = fpkt.access epkt.write.next = fpkt.write epkt.datamode.next = fpkt.datamode epkt.ctrlmode.next = fpkt.ctrlmode epkt.dstaddr.next = fpkt.dstaddr epkt.data.next = fpkt.data epkt.srcaddr.next = fpkt.srcaddr else: epkt.access.next = False return map_inst, beh_read, beh_assign # create a FIFO foreach channel: write, read, read-response fifo_insts = [] for epkt, fifobus in zip(( emesh_i.txwr, emesh_i.txrd, emesh_i.txrr, ), ( fbus_wr, fbus_rd, fbus_rr, )): fifo_insts += emesh_to_fifo(epkt, fifobus) fifo_insts += fifo_async(clock_write=emesh_i.clock, clock_read=emesh_o.clock, fifobus=fifobus, reset=reset, size=16) # assign the output of the FIFO for epkt, fifobus in zip(( emesh_o.txwr, emesh_o.txrd, emesh_o.txrr, ), ( fbus_wr, fbus_rd, fbus_rr, )): fifo_insts += fifo_to_emesh(fifobus, epkt, emesh_o.clock) return fifo_insts
def bench_conversion_fifo_async(): args = Namespace(width=8, size=32, fifosize=64, name='test') clock_write, clock_read = Signals(bool(0), 2) reset = ResetSignal(0, active=1, async=False) fbus = FIFOBus(width=args.width) fifosize = args.fifosize tbdut = fifo_async(clock_write, clock_read, fbus, reset, size=fifosize) @instance def tbclkr(): clock_read.next = False while True: yield delay(5) clock_read.next = not clock_read @instance def tbclkw(): clock_write.next = False while True: yield delay(5) clock_write.next = not clock_write @instance def tbstim(): print("start simulation") fbus.write.next = False fbus.write_data.next = 0 fbus.read.next = False fbus.clear.next = False print("reset") reset.next = reset.active yield delay(10) reset.next = not reset.active yield delay(10) print("some clock cycles") for ii in range(10): yield clock_write.posedge print("some writes") for ii in range(fifosize): fbus.write.next = True fbus.write_data.next = ii yield clock_write.posedge fbus.write.next = False yield clock_write.posedge for ii in range(fifosize): fbus.read.next = True yield clock_read.posedge print("%d %d %d %d" % ( fbus.write, fbus.write_data, fbus.read, fbus.read_data,)) fbus.read.next = False print("end simulation") raise StopSimulation return myhdl.instances()
def spi_slave_fifo_async(glbl, spibus, fifobus): """ This is an SPI slave peripheral, when the master starts clocking any data in the TX FIFO (fifobus.write) will be sent (the next byte) and the received byte will be copied to RX FIFO (fifobus.read). The `cso` interface can be used to configure how the SPI slave peripheral behaves. (Arguments == Ports) Arguments: glbl (Global): global clock and reset spibus (SPIBus): the external SPI interface fifobus (FIFOBus): the fifo interface cso (ControlStatus): the control status signals """ fifosize = 8 # Use an async FIFO to transfer from the SPI SCK clock domain and # the internal clock domain. This allows for high-speed SCK. clock, reset = glbl.clock, glbl.reset assert isinstance(spibus, SPIBus) assert isinstance(fifobus, FIFOBus) sck, csn = spibus.sck, spibus.csn # the FIFOs for the receive and transmit (external perspective) readpath = FIFOBus(width=fifobus.width) writepath = FIFOBus(width=fifobus.width) # the FIFO instances #tx_fifo_inst = fifo_async(glbl, writepath, size=fifosize) #rx_fifo_inst = fifo_async(glbl, readpath, size=fifosize) #mp_fifo_inst = fifobus.assign_read_write_paths(readpath, writepath) tx_fifo_inst = fifo_async(fifobus.write_clock, clock, writepath, reset, size=fifosize) rx_fifo_inst = fifo_async(clock, fifobus.read_clock, readpath, reset, size=fifosize) mp_fifo_inst = fifobus.assign_read_write_paths(readpath, writepath) spi_start = Signal(bool(0)) ireg, icap, icaps = Signals(intbv(0)[8:], 3) oreg, ocap = Signals(intbv(0)[8:], 2) bitcnt, b2, b3 = Signals(intbv(0, min=0, max=10), 3) @always(csn.negedge) #, sck.posedge def csn_falls(): # if sck: spi_start.next = True # elif not csn: # spi_start.next = True # SCK clock domain, this allows high SCK rates @always(sck.posedge, csn.posedge) def sck_capture_send(): if csn: b2.next = 0 bitcnt.next = 0 else: if bitcnt == 0 or spi_start: spibus.miso.next = ocap[7] oreg.next = (ocap << 1) & 0xFF else: spibus.miso.next = oreg[7] oreg.next = (oreg << 1) & 0xFF ireg.next = concat(ireg[7:0], spibus.mosi) bitcnt.next = bitcnt + 1 if bitcnt == (8 - 1): bitcnt.next = 0 b2.next = 8 icap.next = concat(ireg[7:0], spibus.mosi) else: b2.next = 0 # synchronize the SCK domain to the clock domain s1 = syncro(clock, icap, icaps) s2 = syncro(clock, b2, b3) gotit = Signal(bool(0)) @always(clock.posedge) def beh_io_capture(): # default no writes readpath.write.next = False writepath.read.next = False if b3 == 0: gotit.next = False elif b3 == 8 and not gotit: readpath.write.next = True readpath.write_data.next = icaps gotit.next = True ocap.next = writepath.read_data if not writepath.empty: writepath.read.next = True return myhdl.instances()