def migen_body(self, template): inp = template.add_pa_in_port('inp', dl.Optional(int)) trigger = template.add_pa_in_port('trigger', dl.Optional(int)) out = template.add_pa_out_port('out', int) # Declare input and output ports always happy to receive/transmit data self.comb += ( inp.ready.eq(1), trigger.ready.eq(1), out.ready.eq(1), ) commander_fsm = migen.FSM(reset_state="IDLE") self.submodules.commander_fsm = commander_fsm commander_fsm.act("IDLE", migen.If(inp.valid == 1, migen.NextState("LOADING"))) commander_fsm.act( "LOADING", migen.If(trigger.valid & trigger.data == 1, migen.NextState("RETURN")).Else( migen.NextValue(out.data, out.data + inp.data), )) commander_fsm.act("RETURN", migen.NextValue(out.valid, 1), migen.NextState("IDLE"))
def __init__(self, spi=None, bits=32): self.jtag = mg.Record([ ("sel", 1), ("shift", 1), ("capture", 1), ("tck", 1), ("tdi", 1), ("tdo", 1), ]) self.cs_n = mg.TSTriple() self.clk = mg.TSTriple() self.mosi = mg.TSTriple() self.miso = mg.TSTriple() # # # self.cs_n.o.reset = mg.Constant(1) self.submodules.fsm = fsm = mg.FSM("IDLE") en = mg.Signal() bits = mg.Signal(bits, reset_less=True) head = mg.Signal(max=len(bits), reset=len(bits) - 1) self.clock_domains.cd_sys = mg.ClockDomain() self.clock_domains.cd_rise = mg.ClockDomain(reset_less=True) if spi is not None: self.specials += [ self.cs_n.get_tristate(spi.cs_n), self.mosi.get_tristate(spi.mosi), self.miso.get_tristate(spi.miso), ] if hasattr(spi, "clk"): # 7 Series drive it fixed self.specials += self.clk.get_tristate(spi.clk) self.comb += [ en.eq(self.jtag.sel & self.jtag.shift), self.cd_sys.rst.eq(self.jtag.sel & self.jtag.capture), self.cd_sys.clk.eq(~self.jtag.tck), self.cd_rise.clk.eq(self.jtag.tck), self.cs_n.oe.eq(en), self.clk.oe.eq(en), self.mosi.oe.eq(en), self.miso.oe.eq(0), self.clk.o.eq(self.jtag.tck & ~self.cs_n.o), self.mosi.o.eq(self.jtag.tdi), ] # Some (Xilinx) bscan cells register TDO (from the fabric) on falling # TCK and output it (externally). # SPI requires sampling on rising CLK. This leads to one cycle of # latency. self.sync.rise += self.jtag.tdo.eq(self.miso.i) fsm.act("IDLE", mg.If(self.jtag.tdi, mg.NextState("HEAD"))) fsm.act("HEAD", mg.If(head == 0, mg.NextState("XFER"))) fsm.act( "XFER", mg.If(bits == 0, mg.NextState("IDLE")), self.cs_n.o.eq(0), ) self.sync += [ mg.If(fsm.ongoing("HEAD"), bits.eq(mg.Cat(self.jtag.tdi, bits)), head.eq(head - 1)), mg.If(fsm.ongoing("XFER"), bits.eq(bits - 1)) ]
def __init__(self, buf_width=8, buf_depth=16, buf_afull=5): # write port self.wr_valid_in = migen.Signal(1) self.wr_data_in = migen.Signal(buf_width) self.wr_ready_out = migen.Signal(1) # read port self.rd_data_out = migen.Signal(buf_width) self.rd_valid_out = migen.Signal(1) self.rd_ready_in = migen.Signal(1) self.num_fifo_elements = migen.Signal( math.ceil(math.log2(buf_depth)) + 1) # Create port map wr_itf = { self.wr_valid_in, self.wr_data_in, self.wr_ready_out, self.num_fifo_elements } rd_iff = {self.rd_data_out, self.rd_valid_out, self.rd_ready_in} self.ios = set(wr_itf) | set(rd_iff) # internals self.cnt = migen.Signal(math.ceil(math.log2(buf_depth)) + 1) self.almost_full = migen.Signal(1) #### # fifo submodule self.submodules.fifo = fifo = SyncFIFO(buf_width, buf_depth) self.comb += [ migen.If( # write logic fifo.writable & self.wr_valid_in & ~self.almost_full, fifo.we.eq(1), fifo.din.eq(self.wr_data_in)), migen.If( # read logic fifo.readable & self.rd_ready_in, fifo.re.eq(1), self.rd_data_out.eq(fifo.dout)), migen.If( # assert rd valid if fifo is not empty fifo.readable, self.rd_valid_out.eq(1)) ] # element counter self.sync += [ migen.If(fifo.we & (~fifo.re), self.cnt.eq(self.cnt + 1)).Elif( fifo.re & (~fifo.we), self.cnt.eq(self.cnt - 1)).Else(self.cnt.eq(self.cnt)) ] # almost full self.comb += [ migen.If((self.cnt >= buf_depth - buf_afull), self.almost_full.eq(1)).Else(self.almost_full.eq(0)), self.wr_ready_out.eq(~self.almost_full), # back-pressure self.num_fifo_elements.eq(self.cnt) # usedw ]
def migen_body(self, template): # Input/Outputs start here: # 2 inputs and 2 outputs. # # This block group ports which will be accessed by migen, using # the protocol adapters. # in_ports and out_ports implement a similar logic based on 3 # signals, ready, valid and data. # An input can be received when the ready signal is = '1'. # data contains the value of the message that we are receiving # and can considered sensible only when valid = '1', i.e. when # a new data has been received on the pa_input_port. # The opposite logic holds true for the outputs. in1 = template.add_pa_in_port('in1', dl.Optional(int)) in2 = template.add_pa_in_port('in2', dl.Optional(int)) out1 = template.add_pa_out_port('out1', int) out2 = template.add_pa_out_port('out2', int) # The main migen logic starts here: # Everything below is just an example that show different routines. # Add a 32-bit counter (0-2**32-1) which will increment at each clock # cycle. self.counter = migen.Signal(32) self.sync += self.counter.eq(self.counter + 1) # Add a condition when in_ports are ready. self.comb += migen.If( self.counter >= 3, in1.ready.eq(1), in2.ready.eq(1) ) # Pretend that we do a useful calculations. # Here we first check that the outputs are ready. # Then wait for the counter to reach 100. # And write outputs. # Note that the output should be marked as valid. self.comb += migen.If( (out1.ready & out2.ready) == 1, migen.If( self.counter == 5, out1.data.eq(in1.data + in2.data), out2.data.eq(self.counter), out1.valid.eq(in1.valid & in2.valid), out2.valid.eq(in1.valid & in2.valid) ).Else( out1.valid.eq(0), out2.valid.eq(0) ) )
def exec_stmts(stmts): results = [] for stmt in stmts: # now execute the statements if stmt[0] == "comb" or stmt[0] == "sync": # we need to evalue x.eq(y) # so do x and y first makeload(stmt[1]) # after a little hack x, y = ast_eval(stmt[1]), ast_eval(stmt[2]) # now execute x.eq(y) and save the result if fsm is None or stmt[0] == "comb": results.append((stmt[0], x.eq(y))) else: # sync with FSM requires a special object results.append((stmt[0], migen.genlib.fsm.NextValue(x, y))) elif stmt[0] == "if": # execute the predicate pred = ast_eval(stmt[2]) # get results of substatements if_true = tuple(r[1] for r in exec_stmts(stmt[3])) if_false = tuple(r[1] for r in exec_stmts(stmt[4])) the_if = migen.If(pred, *if_true) if len(if_false) > 0: the_if = the_if.Else(*if_false) results.append((stmt[1], the_if)) elif stmt[0] == "next_state": # the result is just a next state marker results.append( (None, migen.genlib.fsm.NextState(ast_eval(stmt[1])))) return results
def migen_body(self, template): # I/O: i1 = template.add_pa_in_port("i1", dl.Optional(int)) o1 = template.add_pa_out_port("o1", int) # LOGIC: self.counter = migen.Signal(1000) self.sync += self.counter.eq(self.counter + 1) # Two memories for testing self.specials.mem1 = mem1 = migen.Memory(32, 100, init=[5, 15, 32]) read_port1 = mem1.get_port() self.specials.mem2 = mem2 = migen.Memory(32, 100, init=[2, 4, 6, 8]) read_port2 = mem2.get_port() self.specials += read_port1 self.specials += read_port2 self.mem_out1 = migen.Signal(32) self.mem_out2 = migen.Signal(32) self.sync += (read_port1.adr.eq(self.counter), self.mem_out1.eq(read_port1.dat_r)) self.sync += (read_port2.adr.eq(self.counter), self.mem_out2.eq(read_port2.dat_r)) # DEBUGGING: # add any signal you want to see in debugging and printing format # (in_ports, out_ports, inputs, output are added by default): self.debug_signals = {'counter': (self.counter, '05b')} self.comb += migen.If( self.counter >= 5, i1.ready.eq(1) ) self.comb += migen.If( o1.ready == 1, migen.If( self.counter == 10, o1.data.eq(self.counter+i1.data), o1.valid.eq(1) ).Else( o1.valid.eq(0) ) )
def migen_body(self, template): # inputs and 1 output in1 = template.add_pa_in_port('in1', DOptional(int)) out1 = template.add_pa_out_port('out1', DOptional(int)) # Counter self.incremented = migen.Signal(10) # for instance, at this clock the node is ready to input self.comb += in1.ready.eq(1) self.sync += migen.If( out1.ready == 1, migen.If(in1.valid, out1.data.eq(self.incremented), out1.valid.eq(0x1), self.incremented.eq(in1.data+1) ).Else(out1.valid.eq(0)) )
def patch_csrs(self): for csr in self.dut.get_csrs(): if isinstance(csr, CSRStorage) and hasattr(csr, "dat_w"): self.dut.sync += [ migen.If(csr.we, csr.storage.eq(csr.dat_w), csr.re.eq(1), ).Else( csr.re.eq(0), ) ]
def migen_body(self, template): start = template.add_pa_in_port('start', dl.Optional(int)) out_a = template.add_pa_out_port('out_a', int) out_b = template.add_pa_out_port('out_b', int) # This will need to be converted to boolean when migen nodes support # boolean self.cnt = migen.Signal(10) self.comb += (out_a.ready.eq(1), out_b.ready.eq(1), start.ready.eq(1)) self.sync += migen.If(self.cnt & 0x1, out_a.valid.eq(start.data), out_b.valid.eq(0)).Else( out_a.valid.eq(0), out_b.valid.eq(start.data)) self.sync += (self.cnt.eq(self.cnt + 1), out_a.data.eq(self.cnt), out_b.data.eq(self.cnt))
def migen_body(self, template): # I/O: i1 = template.add_pa_in_port("i1", dl.Optional(int)) o1 = template.add_pa_out_port("o1", int) self.comb += ( i1.ready.eq(1), ) started = migen.Signal(1) self.sync += migen.If( i1.valid == 1, o1.valid.eq(1), o1.data.eq(i1.data+1) ).Else( o1.data.eq(0), migen.If(started == 0, o1.valid.eq(1), started.eq(1) ).Else( o1.valid.eq(0) ) )
def migen_body(self, template): # We are using a Optional here because the code should run # no matter the input. If you were to use an int (so a # not-optional input) we would stall the migen simulation until # an input is received. In this example, we have a cyclical graph # in which the hardware node (migenNode) must produce an output # (a reset signal) no matter the input. pulse_in = template.add_pa_in_port('pulse_in', dl.Optional(int)) reset_out = template.add_pa_out_port('reset_out', int) # Constants self.NUM_CLOCKS = 5 # We set the lowest NUM_CLOCKS bits of INIT_VAL to be '1's self.INIT_VAL = 2**self.NUM_CLOCKS-1 # Signal that generates a pulse of length NUM_CLOCKS self.shaper = migen.Signal(self.NUM_CLOCKS+1) # When I receive a reset signal -> initialise the shaper to contain # N '1's. # If I haven't received one just shift the value to the left # 01111 -> 00111. I will use the lowest bit for the reset_out signal # This equates to seconding N times a '1' after receiving a pulse_in # followed by '0'. Note: the sync construct instructs migen that the # logic contained within the block is sequential - i.e. it can only # change on a clock transaction (from low to high). self.sync += ( migen.If( (pulse_in.valid == 1) & (pulse_in.data == 1), self.shaper.eq(self.INIT_VAL) ).Else( self.shaper.eq(self.shaper >> 1) ) ) # Always generating an output self.sync += (reset_out.data.eq(self.shaper[0])) # Always ready to receive a reset, always generating an output. # Note: comb (combinatorial logic) is executed instantaneously # when inputs change. In this example, inputs for the # reset_out.valid is a constant 1 so it is always = 1. # If it was a signal the value of reset_out.valid would change # together with the input signal. self.comb += (reset_out.valid.eq(1), pulse_in.ready.eq(1), reset_out.ready.eq(1))
def __init__(self, spi=None, bits=32): self.jtag = mg.Record([ ("sel", 1), ("shift", 1), ("capture", 1), ("tck", 1), ("tdi", 1), ("tdo", 1), ]) self.cs_n = mg.TSTriple() self.clk = mg.TSTriple() self.mosi = mg.TSTriple() self.miso = mg.TSTriple() # # # self.cs_n.o.reset = mg.Constant(1) self.mosi.o.reset_less = True bits = mg.Signal(bits, reset_less=True) head = mg.Signal(max=len(bits), reset=len(bits) - 1) self.clock_domains.cd_sys = mg.ClockDomain() self.submodules.fsm = mg.FSM("IDLE") if spi is not None: self.specials += [ self.cs_n.get_tristate(spi.cs_n), self.mosi.get_tristate(spi.mosi), self.miso.get_tristate(spi.miso), ] if hasattr(spi, "clk"): # 7 Series drive it fixed self.specials += self.clk.get_tristate(spi.clk) # self.specials += io.DDROutput(1, 0, spi.clk, self.clk.o) self.comb += [ self.cd_sys.rst.eq(self.jtag.sel & self.jtag.capture), self.cd_sys.clk.eq(self.jtag.tck), self.cs_n.oe.eq(self.jtag.sel), self.clk.oe.eq(self.jtag.sel), self.mosi.oe.eq(self.jtag.sel), self.miso.oe.eq(0), # Do not suppress CLK toggles outside CS_N asserted. # Xilinx USRCCLK0 requires three dummy cycles to do anything # https://www.xilinx.com/support/answers/52626.html # This is fine since CS_N changes only on falling CLK. self.clk.o.eq(~self.jtag.tck), self.jtag.tdo.eq(self.miso.i), ] # Latency calculation (in half cycles): # 0 (falling TCK, rising CLK): # JTAG adapter: set TDI # 1 (rising TCK, falling CLK): # JTAG2SPI: sample TDI -> set MOSI # SPI: set MISO # 2 (falling TCK, rising CLK): # SPI: sample MOSI # JTAG2SPI (BSCAN primitive): sample MISO -> set TDO # 3 (rising TCK, falling CLK): # JTAG adapter: sample TDO self.fsm.act( "IDLE", mg.If(self.jtag.tdi & self.jtag.sel & self.jtag.shift, mg.NextState("HEAD"))) self.fsm.act("HEAD", mg.If(head == 0, mg.NextState("XFER"))) self.fsm.act( "XFER", mg.If(bits == 0, mg.NextState("IDLE")), ) self.sync += [ self.mosi.o.eq(self.jtag.tdi), self.cs_n.o.eq(~self.fsm.ongoing("XFER")), mg.If(self.fsm.ongoing("HEAD"), bits.eq(mg.Cat(self.jtag.tdi, bits)), head.eq(head - 1)), mg.If(self.fsm.ongoing("XFER"), bits.eq(bits - 1)) ]