def testbench_memmap(args=None): """ """ args = tb_default_args(args) clock = Clock(0, frequency=50e6) reset = Reset(0, active=1, isasync=False) glbl = Global(clock, reset) csbus = Barebone(glbl, data_width=8, address_width=16) @myhdl.block def bench_memmap(): tbdut = peripheral(csbus) tbclk = clock.gen() print(csbus.regfiles) @instance def tbstim(): yield reset.pulse(111) raise StopSimulation return tbdut, tbclk, tbstim run_testbench(bench_memmap)
def test_spi_models(args=None): args = tb_default_args(args) clock = Clock(0, frequency=125e6) glbl = Global(clock) ibus = Barebone(glbl) spibus = SPIBus() def bench(): tbdut = spi_controller_model(clock, ibus, spibus) tbspi = SPISlave().process(spibus) tbclk = clock.gen() @instance def tbstim(): yield clock.posedge yield ibus.writetrans(0x00, 0xBE) yield delay(100) yield ibus.readtrans(0x00) raise StopSimulation return tbdut, tbspi, tbclk, tbstim run_testbench(bench, args=args)
def led_blinker_top(clock, reset, leds, buttons): glbl = Global(clock, reset) csrbus = Barebone() dbtns = Signal(buttons.val) led_inst = led_blinker(glbl, csrbus, leds) dbn_inst = button_debounce(glbl, buttons, dbtns) btn_inst = button_controller(glbl, csrbus, dbtns) # above all the components have been added, now build the # register file (figures out addresses, etc) and then get # the memory-mapped bus interconnect csrbus.regfile_build() bus_inst = csrbus.interconnect() return myhdl.instances()
def test_memmap_command_bridge(args=None): nloops = 37 args = tb_default_args(args) clock = Clock(0, frequency=50e6) reset = Reset(0, active=1, async=False) glbl = Global(clock, reset) fbtx, fbrx = FIFOBus(), FIFOBus() memmap = Barebone(glbl, data_width=32, address_width=28) fbtx.clock = clock fbrx.clock = clock def _bench_command_bridge(): tbclk = clock.gen() tbdut = memmap_command_bridge(glbl, fbtx, fbrx, memmap) tbfii = fifo_fast(clock, reset, fbtx) tbfio = fifo_fast(clock, reset, fbrx) # @todo: add other bus types tbmem = memmap_peripheral_bb(clock, reset, memmap) # save the data read ... read_value = [] @instance def tbstim(): yield reset.pulse(32) try: # test a single address pkt = CommandPacket(True, 0x0000) yield pkt.put(fbtx) yield pkt.get(fbrx, read_value, [0]) pkt = CommandPacket(False, 0x0000, [0x5555AAAA]) yield pkt.put(fbtx) yield pkt.get(fbrx, read_value, [0x5555AAAA]) # test a bunch of random addresses for ii in range(nloops): randaddr = randint(0, (2**20) - 1) randdata = randint(0, (2**32) - 1) pkt = CommandPacket(False, randaddr, [randdata]) yield pkt.put(fbtx) yield pkt.get(fbrx, read_value, [randdata]) except Exception as err: print("Error: {}".format(str(err))) traceback.print_exc() yield delay(2000) raise StopSimulation return tbclk, tbdut, tbfii, tbfio, tbmem, tbstim run_testbench(_bench_command_bridge, args=args)
def catboard_blinky_host(clock, led, uart_tx, uart_rx): """ The LEDs are controlled from the RPi over the UART to the FPGA. """ glbl = Global(clock, None) ledreg = Signal(intbv(0)[8:]) # create the timer tick instance tick_inst = glbl_timer_ticks(glbl, include_seconds=True) # create the interfaces to the UART fbustx = FIFOBus(width=8, size=4) fbusrx = FIFOBus(width=8, size=4) # create the memmap (CSR) interface memmap = Barebone(glbl, data_width=32, address_width=32) # create the UART instance. uart_inst = uartlite(glbl, fbustx, fbusrx, serial_in=uart_rx, serial_out=uart_tx) # create the packet command instance cmd_inst = command_bridge(glbl, fbusrx, fbustx, memmap) @always_seq(clock.posedge, reset=None) def beh_led_control(): memmap.done.next = not (memmap.write or memmap.read) if memmap.write and memmap.mem_addr == 0x20: ledreg.next = memmap.write_data @always_comb def beh_led_read(): if memmap.read and memmap.mem_addr == 0x20: memmap.read_data.next = ledreg else: memmap.read_data.next = 0 # blink one of the LEDs tone = Signal(intbv(0)[8:]) @always_seq(clock.posedge, reset=None) def beh_assign(): if glbl.tick_sec: tone.next = (~tone) & 0x1 led.next = ledreg | tone[5:] return (tick_inst, uart_inst, cmd_inst, beh_led_control, beh_led_read, beh_assign)
def m_btn_led_mm(clock, reset, leds, btns, bus_type='W'): """ A toy example to demostrate bus agnosticism This example instantiates a memory-map controller and a memory-map peripheral. This example shows how the controllers and peripherals can be passed the memmap interface. The passing of the interface allows the modules (components) to be bus agnostic. This example solves a simple task in a complicated manner to show the point. When a button press is detected a bus cycle is generated to write the "flash" pattern to the LED peripheral. Note: for easy FPGA bit-stream generation the port names match the board names defined in the *gizflo* board definitions. """ glbl = Global(clock=clock, reset=reset) if bus_type == 'B': regbus = Barebone(glbl, data_width=8, address_width=16) elif bus_type == 'W': regbus = Wishbone(glbl, data_width=8, address_width=16) elif bus_type == 'A': regbus = AvalonMM(glbl, data_width=8, address_width=16) #elif bus_type == 'X': # regbus = AXI4Lite(glbl, data_wdith=8, address_width=16) else: raise Exception("Invalid bus type {}".format(bus_type)) gbtn = button_controller(glbl, regbus, btns) # memmap controller gled = led_peripheral(glbl, regbus, leds) # memmap peripheral gmap = regbus.interconnect() # bus combiner print(vars(regbus.regfiles['LED_000'])) return gbtn, gled, gmap
def atlys_blinky_host(clock, reset, led, sw, pmod, uart_tx, uart_rx): """ This example is similar to the other examples in this directory but the LEDs are controlled externally via command packets sent from a host via the UART on the icestick. """ glbl = Global(clock, reset) ledreg = Signal(intbv(0)[8:]) # create the timer tick instance tick_inst = glbl_timer_ticks(glbl, include_seconds=True) # create the interfaces to the UART fbustx = FIFOBus(width=8, size=32) fbusrx = FIFOBus(width=8, size=32) # create the memmap (CSR) interface memmap = Barebone(glbl, data_width=32, address_width=32) # create the UART instance. cmd_tx = Signal(bool(0)) uart_inst = uartlite(glbl, fbustx, fbusrx, uart_rx, cmd_tx) # create the packet command instance cmd_inst = memmap_command_bridge(glbl, fbusrx, fbustx, memmap) @always_seq(clock.posedge, reset=reset) def beh_led_control(): memmap.done.next = not (memmap.write or memmap.read) if memmap.write: # and memmap.mem_addr == 0x20: ledreg.next = memmap.write_data @always_comb def beh_led_read(): if memmap.read and memmap.mem_addr == 0x20: memmap.read_data.next = ledreg else: memmap.read_data.next = 0 # blink one of the LEDs status = [Signal(bool(0)) for _ in range(8)] statusbv = ConcatSignal(*reversed(status)) @always_seq(clock.posedge, reset=reset) def beh_assign(): # status / debug signals if glbl.tick_sec: status[0].next = not status[0] status[1].next = memmap.mem_addr == 0x20 status[2].next = uart_rx status[3].next = uart_tx led.next = ledreg | statusbv | sw pmod.next = 0 if sw[0]: uart_tx.next = uart_rx else: uart_tx.next = cmd_tx # @todo: PMOD OLED memmap control return (tick_inst, uart_inst, cmd_inst, beh_led_control, beh_led_read, beh_assign)
def testbench_to_generic(args=None): """ Test memory-mapped bus and the mapping to a generic bus :param args: :return: """ depth = 16 # number of memory address width = 32 # memory-mapped bus data width maxval = 2**width run = False if args is None else True args = tb_default_args(args) if not hasattr(args, 'num_loops'): args.num_loops = 10 clock = Clock(0, frequency=100e6) reset = Reset(0, active=1, async=False) glbl = Global(clock, reset) if hasattr(args, 'bustype'): address_width = 18 membus = busmap[args.bustype](glbl, data_width=width, address_width=address_width) else: address_width = int(ceil(log(depth, 2))) + 4 membus = Barebone(glbl, data_width=width, address_width=address_width) @myhdl.block def bench_to_generic(): tbdut = peripheral_memory(membus, depth=depth) tbitx = membus.interconnect() tbclk = clock.gen() testvals = {} @instance def tbstim(): yield reset.pulse(42) yield clock.posedge # only testing one peripheral, set the peripheral/slave # address to the first ... if isinstance(membus, Barebone): membus.per_addr.next = 1 peraddr = 0 else: peraddr = 0x10000 yield clock.posedge for ii in range(args.num_loops): randaddr = randint(0, depth - 1) | peraddr randdata = randint(0, maxval - 1) testvals[randaddr] = randdata yield membus.writetrans(randaddr, randdata) yield clock.posedge for addr, data in testvals.items(): yield membus.readtrans(addr) read_data = membus.get_read_data() assert read_data == data, "{:08X} != {:08X}".format( read_data, data) yield clock.posedge yield delay(100) raise StopSimulation return tbdut, tbitx, tbclk, tbstim if run: run_testbench(bench_to_generic, args=args)
def uart_blinky(clock, led, uart_tx, uart_rx): """ Uses UART module to control LEDs while blinking the first LED. LEDs used are pins 0-7 on wing A. Expected behavior after upload is that LED[0] blinks on/off. When sending 0xDE 0x02 0x00 0x00 0x00 0x20 0x04 0xCA 0x00 0x00 0x00 0xFF via serial connection, all LEDs should turn on. For details about the message format see /rhea/cores/memmap/command_bridge.py """ reset = ResetSignal(0, active=0, async=True) glbl = Global(clock, reset) ledreg = Signal(intbv(0)[8:]) # create the timer tick instance tick_inst = glbl_timer_ticks(glbl, include_seconds=True) # create the interfaces to the UART fifobus = FIFOBus(width=8) # create the memmap (CSR) interface memmap = Barebone(glbl, data_width=32, address_width=32) # create the UART instance. uart_inst = uartlite(glbl, fifobus, serial_in=uart_rx, serial_out=uart_tx, fifosize=4) # create the packet command instance cmd_inst = command_bridge(glbl, fifobus, memmap) @always_seq(clock.posedge, reset=reset) def beh_led_control(): memmap.done.next = not (memmap.write or memmap.read) if memmap.write and memmap.mem_addr == 0x20: ledreg.next = memmap.write_data @always_comb def beh_led_read(): if memmap.read and memmap.mem_addr == 0x20: memmap.read_data.next = ledreg else: memmap.read_data.next = 0 # blink one of the LEDs tone = Signal(intbv(0)[8:]) reset_dly_cnt = Signal(intbv(0)[5:]) @always_seq(clock.posedge, reset=None) def beh_assign(): if glbl.tick_sec: tone.next = (~tone) & 0x1 led.next = ledreg | tone[5:] @always(clock.posedge) def reset_tst(): ''' For the first 4 clocks the reset is forced to lo for clock 6 to 31 the reset is set hi then the reset is lo ''' if (reset_dly_cnt < 31): reset_dly_cnt.next = reset_dly_cnt + 1 if (reset_dly_cnt <= 4): reset.next = 1 if (reset_dly_cnt >= 5): reset.next = 0 else: reset.next = 1 return (tick_inst, cmd_inst, uart_inst, beh_led_control, beh_led_read, beh_assign, reset_tst)
def memmap_command_bridge(glbl, fifobusi, fifobuso, mmbus): """ Convert a command packet to a memory-mapped bus transaction This module will decode the incomming packet and start a bus transaction, the memmap_controller_basic is used to generate the bus transactions, it convertes the Barebone interface to the MemoryMapped interface being used. The variable length command packet is: 00: 0xDE 01: command byte (response msb indicates error) 02: address high byte 03: address byte 04: address byte 05: address low byte 06: length of data (max length 256 bytes) 07: 0xCA # sequence number, fixed for now 08: data high byte 09: data byte 10: data byte 11: data low byte Fixed 12 byte packet currently supported, future to support block write/reads up to 256-8-4 12 - 253: write / read (big-endian) @todo: last 2 bytes crc The total packet length is 16 + data_length Ports: glbl: global signals and control fifobusi: input fifobus, host packets to device (interface) fifobuso: output fifobus, device responses to host (interface) mmbus: memory-mapped bus (interface) this module is convertible """ assert isinstance(fifobusi, FIFOBus) assert isinstance(fifobuso, FIFOBus) assert isinstance(mmbus, MemoryMapped) fbrx, fbtx = fifobusi, fifobuso clock, reset = glbl.clock, glbl.reset bb = Barebone(glbl, data_width=mmbus.data_width, address_width=mmbus.address_width) states = enum( 'idle', 'wait_for_packet', # receive a command packet 'check_packet', # basic command check 'write', # bus write 'write_end', # end of the write cycle 'read', # read bus cycles for response 'read_end', # end of the read cycle 'response', # send response packet 'response_full', # check of RX FIFO full 'error', # error occurred 'end' # end state ) state = Signal(states.idle) ready = Signal(bool(0)) error = Signal(bool(0)) bytecnt = intbv(0, min=0, max=256) # known knows pidx = ( 0, 7, ) pval = ( 0xDE, 0xCA, ) assert len(pidx) == len(pval) nknown = len(pidx) bytemon = Signal(intbv(0)[8:]) # only supporting 12byte packets (single read/write) for now packet_length = 12 data_offset = 8 packet = [Signal(intbv(0)[8:]) for _ in range(packet_length)] command = packet[1] address = ConcatSignal(*packet[2:6]) data = ConcatSignal(*packet[8:12]) datalen = packet[6] # convert generic memory-mapped bus to the memory-mapped interface # passed to the controller mmc_inst = memmap_controller_basic(bb, mmbus) @always_comb def beh_fifo_read(): if ready and not fbrx.empty: fbrx.rd.next = True else: fbrx.rd.next = False @always_seq(clock.posedge, reset=reset) def beh_state_machine(): if state == states.idle: state.next = states.wait_for_packet ready.next = True bytecnt[:] = 0 elif state == states.wait_for_packet: if fbrx.rvld: # check the known bytes, if the values is unexpected # goto the error state and flush all received bytes. for ii in range(nknown): idx = pidx[ii] val = pval[ii] if bytecnt == idx: if fbrx.rdata != val: error.next = True state.next = states.error packet[bytecnt].next = fbrx.rdata bytecnt[:] = bytecnt + 1 # @todo: replace 20 with len(CommandPacket().header) if bytecnt == packet_length: ready.next = False state.next = states.check_packet elif state == states.check_packet: # @todo: some packet checking # @todo: need to support different address widths, use # @todo: `bb` attributes to determine which bits to assign bb.per_addr.next = address[32:28] bb.mem_addr.next = address[28:0] assert bb.done bytecnt[:] = 0 if command == 1: state.next = states.read elif command == 2: bb.write_data.next = data state.next = states.write else: error.next = True state.next = states.error elif state == states.write: # @todo: add timeout if bb.done: bb.write.next = True state.next = states.write_end elif state == states.write_end: bb.write.next = False if bb.done: state.next = states.read elif state == states.read: # @todo: add timeout if bb.done: bb.read.next = True state.next = states.read_end elif state == states.read_end: bb.read.next = False if bb.done: # @todo: support different data_width bus packet[data_offset + 0].next = bb.read_data[32:24] packet[data_offset + 1].next = bb.read_data[24:16] packet[data_offset + 2].next = bb.read_data[16:8] packet[data_offset + 3].next = bb.read_data[8:0] state.next = states.response elif state == states.response: fbtx.wr.next = False if bytecnt < packet_length: if not fbtx.full: fbtx.wr.next = True fbtx.wdata.next = packet[bytecnt] bytecnt[:] = bytecnt + 1 state.next = states.response_full else: state.next = states.end elif state == states.response_full: fbtx.wr.next = False state.next = states.response elif state == states.error: if not fbrx.rvld: state.next = states.end ready.next = False elif state == states.end: error.next = False ready.next = False state.next = states.idle else: assert False, "Invalid state %s" % (state, ) bytemon.next = bytecnt return beh_fifo_read, mmc_inst, beh_state_machine
def test_memmap_command_bridge(args=None): nloops = 37 args = tb_default_args(args) clock = Clock(0, frequency=50e6) reset = Reset(0, active=1, async=False) glbl = Global(clock, reset) fifobus = FIFOBus() memmap = Barebone(glbl, data_width=32, address_width=28) fifobus.clock = clock def bench_command_bridge(): tbclk = clock.gen() tbdut = command_bridge(glbl, fifobus, memmap) readpath, writepath = FIFOBus(), FIFOBus() readpath.clock = writepath.clock = clock tbmap = fifobus.assign_read_write_paths(readpath, writepath) tbftx = fifo_fast(reset, clock, writepath) # user write path tbfrx = fifo_fast(reset, clock, readpath) # user read path # @todo: add other bus types tbmem = memmap_peripheral_bb(clock, reset, memmap) # save the data read ... read_value = [] @instance def tbstim(): yield reset.pulse(32) fifobus.read.next = False fifobus.write.next = False assert not fifobus.full assert fifobus.empty assert fifobus.read_data == 0 fifobus.write_data.next = 0 try: # test a single address pkt = CommandPacket(True, 0x0000) yield pkt.put(readpath) yield pkt.get(writepath, read_value, [0]) pkt = CommandPacket(False, 0x0000, [0x5555AAAA]) yield pkt.put(readpath) yield pkt.get(writepath, read_value, [0x5555AAAA]) # test a bunch of random addresses for ii in range(nloops): randaddr = randint(0, (2**20) - 1) randdata = randint(0, (2**32) - 1) pkt = CommandPacket(False, randaddr, [randdata]) yield pkt.put(readpath) yield pkt.get(writepath, read_value, [randdata]) except Exception as err: print("Error: {}".format(str(err))) traceback.print_exc() yield delay(2000) raise StopSimulation wp_read, wp_valid = Signals(bool(0), 2) wp_read_data = Signal(intbv(0)[8:]) wp_empty, wp_full = Signals(bool(0), 2) @always_comb def tbmon(): wp_read.next = writepath.read wp_read_data.next = writepath.read_data wp_valid.next = writepath.read_valid wp_full.next = writepath.full wp_empty.next = writepath.empty return tbclk, tbdut, tbmap, tbftx, tbfrx, tbmem, tbstim, tbmon run_testbench(bench_command_bridge, args=args)
def icestick_blinky_host(clock, led, pmod, uart_tx, uart_rx, uart_dtr, uart_rts): """ This example is similar to the other examples in this directory but the LEDs are controlled externally via command packets sent from a host via the UART on the icestick. (arguments == ports) Arguments: clock: led: pmod: uart_tx: uart_rx: """ glbl = Global(clock, None) ledreg = Signal(intbv(0)[8:]) # create the timer tick instance tick_inst = glbl_timer_ticks(glbl, include_seconds=True) # create the interfaces to the UART fifobus = FIFOBus(width=8) # create the memmap (CSR) interface memmap = Barebone(glbl, data_width=32, address_width=32) # create the UART instance. uart_inst = uartlite(glbl, fifobus, uart_rx, uart_tx) # create the packet command instance cmd_inst = command_bridge(glbl, fifobus, memmap) @always_seq(clock.posedge, reset=None) def beh_led_control(): memmap.done.next = not (memmap.write or memmap.read) if memmap.write and memmap.mem_addr == 0x20: ledreg.next = memmap.write_data @always_comb def beh_led_read(): if memmap.read and memmap.mem_addr == 0x20: memmap.read_data.next = ledreg else: memmap.read_data.next = 0 # blink one of the LEDs tone = Signal(intbv(0)[8:]) @always_seq(clock.posedge, reset=None) def beh_assign(): if glbl.tick_sec: tone.next = (~tone) & 0x1 led.next = ledreg | tone[5:] pmod.next = 0 # @todo: PMOD OLED memmap control return myhdl.instances()