from migen.fhdl.structure import * from migen.fhdl import verilog from migen.genlib.fsm import FSM s = Signal() myfsm = FSM("FOO", "BAR") myfsm.act(myfsm.FOO, s.eq(1), myfsm.next_state(myfsm.BAR)) myfsm.act(myfsm.BAR, s.eq(0), myfsm.next_state(myfsm.FOO)) print(verilog.convert(myfsm.get_fragment(), {s}))
def __init__(self): self.s = Signal() myfsm = FSM("FOO", "BAR") self.submodules += myfsm myfsm.act(myfsm.FOO, self.s.eq(1), myfsm.next_state(myfsm.BAR)) myfsm.act(myfsm.BAR, self.s.eq(0), myfsm.next_state(myfsm.FOO))
def __init__(self, pads, default=_default_edid): self.specials.mem = Memory(8, 128, init=default) ### scl_raw = Signal() sda_i = Signal() sda_drv = Signal() _sda_drv_reg = Signal() _sda_i_async = Signal() self.sync += _sda_drv_reg.eq(sda_drv) self.specials += [ MultiReg(pads.scl, scl_raw), Tristate(pads.sda, 0, _sda_drv_reg, _sda_i_async), MultiReg(_sda_i_async, sda_i) ] scl_i = Signal() samp_count = Signal(6) samp_carry = Signal() self.sync += [ Cat(samp_count, samp_carry).eq(samp_count + 1), If(samp_carry, scl_i.eq(scl_raw)) ] scl_r = Signal() sda_r = Signal() scl_rising = Signal() sda_rising = Signal() sda_falling = Signal() self.sync += [ scl_r.eq(scl_i), sda_r.eq(sda_i) ] self.comb += [ scl_rising.eq(scl_i & ~scl_r), sda_rising.eq(sda_i & ~sda_r), sda_falling.eq(~sda_i & sda_r) ] start = Signal() self.comb += start.eq(scl_i & sda_falling) din = Signal(8) counter = Signal(max=9) self.sync += [ If(start, counter.eq(0)), If(scl_rising, If(counter == 8, counter.eq(0) ).Else( counter.eq(counter + 1), din.eq(Cat(sda_i, din[:7])) ) ) ] is_read = Signal() update_is_read = Signal() self.sync += If(update_is_read, is_read.eq(din[0])) offset_counter = Signal(max=128) oc_load = Signal() oc_inc = Signal() self.sync += [ If(oc_load, offset_counter.eq(din) ).Elif(oc_inc, offset_counter.eq(offset_counter + 1) ) ] rdport = self.mem.get_port() self.comb += rdport.adr.eq(offset_counter) data_bit = Signal() zero_drv = Signal() data_drv = Signal() self.comb += If(zero_drv, sda_drv.eq(1)).Elif(data_drv, sda_drv.eq(~data_bit)) data_drv_en = Signal() data_drv_stop = Signal() self.sync += If(data_drv_en, data_drv.eq(1)).Elif(data_drv_stop, data_drv.eq(0)) self.sync += If(data_drv_en, chooser(rdport.dat_r, counter, data_bit, 8, reverse=True)) states = ["WAIT_START", "RCV_ADDRESS", "ACK_ADDRESS0", "ACK_ADDRESS1", "ACK_ADDRESS2", "RCV_OFFSET", "ACK_OFFSET0", "ACK_OFFSET1", "ACK_OFFSET2", "READ", "ACK_READ"] fsm = FSM(*states) self.submodules += fsm fsm.act(fsm.RCV_ADDRESS, If(counter == 8, If(din[1:] == 0x50, update_is_read.eq(1), fsm.next_state(fsm.ACK_ADDRESS0) ).Else( fsm.next_state(fsm.WAIT_START) ) ) ) fsm.act(fsm.ACK_ADDRESS0, If(~scl_i, fsm.next_state(fsm.ACK_ADDRESS1)) ) fsm.act(fsm.ACK_ADDRESS1, zero_drv.eq(1), If(scl_i, fsm.next_state(fsm.ACK_ADDRESS2)) ) fsm.act(fsm.ACK_ADDRESS2, zero_drv.eq(1), If(~scl_i, If(is_read, fsm.next_state(fsm.READ) ).Else( fsm.next_state(fsm.RCV_OFFSET) ) ) ) fsm.act(fsm.RCV_OFFSET, If(counter == 8, oc_load.eq(1), fsm.next_state(fsm.ACK_OFFSET0) ) ) fsm.act(fsm.ACK_OFFSET0, If(~scl_i, fsm.next_state(fsm.ACK_OFFSET1)) ) fsm.act(fsm.ACK_OFFSET1, zero_drv.eq(1), If(scl_i, fsm.next_state(fsm.ACK_OFFSET2)) ) fsm.act(fsm.ACK_OFFSET2, zero_drv.eq(1), If(~scl_i, fsm.next_state(fsm.RCV_ADDRESS)) ) fsm.act(fsm.READ, If(~scl_i, If(counter == 8, data_drv_stop.eq(1), fsm.next_state(fsm.ACK_READ) ).Else( data_drv_en.eq(1) ) ) ) fsm.act(fsm.ACK_READ, If(scl_rising, oc_inc.eq(1), If(sda_i, fsm.next_state(fsm.WAIT_START) ).Else( fsm.next_state(fsm.READ) ) ) ) for state in states: fsm.act(getattr(fsm, state), If(start, fsm.next_state(fsm.RCV_ADDRESS)))
def __init__(self, cachesize, lasmim): self.wishbone = wishbone.Interface() ### if lasmim.dw <= 32: raise ValueError("LASMI data width must be strictly larger than 32") if (lasmim.dw % 32) != 0: raise ValueError("LASMI data width must be a multiple of 32") # Split address: # TAG | LINE NUMBER | LINE OFFSET offsetbits = log2_int(lasmim.dw//32) addressbits = lasmim.aw + offsetbits linebits = log2_int(cachesize) - offsetbits tagbits = addressbits - linebits adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits) # Data memory data_mem = Memory(lasmim.dw, 2**linebits) data_port = data_mem.get_port(write_capable=True, we_granularity=8) self.specials += data_mem, data_port write_from_lasmi = Signal() write_to_lasmi = Signal() adr_offset_r = Signal(offsetbits) self.comb += [ data_port.adr.eq(adr_line), If(write_from_lasmi, data_port.dat_w.eq(lasmim.dat_r), data_port.we.eq(Replicate(1, lasmim.dw//8)) ).Else( data_port.dat_w.eq(Replicate(self.wishbone.dat_w, lasmim.dw//32)), If(self.wishbone.cyc & self.wishbone.stb & self.wishbone.we & self.wishbone.ack, displacer(self.wishbone.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True) ) ), If(write_to_lasmi, lasmim.dat_w.eq(data_port.dat_r), lasmim.dat_we.eq(2**(lasmim.dw//8)-1) ), chooser(data_port.dat_r, adr_offset_r, self.wishbone.dat_r, reverse=True) ] self.sync += adr_offset_r.eq(adr_offset) # Tag memory tag_layout = [("tag", tagbits), ("dirty", 1)] tag_mem = Memory(layout_len(tag_layout), 2**linebits) tag_port = tag_mem.get_port(write_capable=True) self.specials += tag_mem, tag_port tag_do = Record(tag_layout) tag_di = Record(tag_layout) self.comb += [ tag_do.raw_bits().eq(tag_port.dat_r), tag_port.dat_w.eq(tag_di.raw_bits()) ] self.comb += [ tag_port.adr.eq(adr_line), tag_di.tag.eq(adr_tag), lasmim.adr.eq(Cat(adr_line, tag_do.tag)) ] # Control FSM assert(lasmim.write_latency >= 1 and lasmim.read_latency >= 1) fsm = FSM("IDLE", "TEST_HIT", "EVICT_REQUEST", "EVICT_WAIT_DATA_ACK", "EVICT_DATA", "REFILL_WRTAG", "REFILL_REQUEST", "REFILL_WAIT_DATA_ACK", "REFILL_DATA", delayed_enters=[ ("EVICT_DATAD", "EVICT_DATA", lasmim.write_latency-1), ("REFILL_DATAD", "REFILL_DATA", lasmim.read_latency-1) ]) self.submodules += fsm fsm.act(fsm.IDLE, If(self.wishbone.cyc & self.wishbone.stb, fsm.next_state(fsm.TEST_HIT)) ) fsm.act(fsm.TEST_HIT, If(tag_do.tag == adr_tag, self.wishbone.ack.eq(1), If(self.wishbone.we, tag_di.dirty.eq(1), tag_port.we.eq(1) ), fsm.next_state(fsm.IDLE) ).Else( If(tag_do.dirty, fsm.next_state(fsm.EVICT_REQUEST) ).Else( fsm.next_state(fsm.REFILL_WRTAG) ) ) ) fsm.act(fsm.EVICT_REQUEST, lasmim.stb.eq(1), lasmim.we.eq(1), If(lasmim.req_ack, fsm.next_state(fsm.EVICT_WAIT_DATA_ACK)) ) fsm.act(fsm.EVICT_WAIT_DATA_ACK, If(lasmim.dat_ack, fsm.next_state(fsm.EVICT_DATAD)) ) fsm.act(fsm.EVICT_DATA, write_to_lasmi.eq(1), fsm.next_state(fsm.REFILL_WRTAG) ) fsm.act(fsm.REFILL_WRTAG, # Write the tag first to set the LASMI address tag_port.we.eq(1), fsm.next_state(fsm.REFILL_REQUEST) ) fsm.act(fsm.REFILL_REQUEST, lasmim.stb.eq(1), If(lasmim.req_ack, fsm.next_state(fsm.REFILL_WAIT_DATA_ACK)) ) fsm.act(fsm.REFILL_WAIT_DATA_ACK, If(lasmim.dat_ack, fsm.next_state(fsm.REFILL_DATAD)) ) fsm.act(fsm.REFILL_DATA, write_from_lasmi.eq(1), fsm.next_state(fsm.TEST_HIT) )
def __init__(self, a, ba, tRP, tREFI, tRFC): self.req = Signal() self.ack = Signal() # 1st command 1 cycle after assertion of ack self.cmd = CommandRequest(a, ba) ### # Refresh sequence generator: # PRECHARGE ALL --(tRP)--> AUTO REFRESH --(tRFC)--> done seq_start = Signal() seq_done = Signal() self.sync += [ self.cmd.a.eq(2**10), self.cmd.ba.eq(0), self.cmd.cas_n.eq(1), self.cmd.ras_n.eq(1), self.cmd.we_n.eq(1), seq_done.eq(0) ] self.sync += timeline(seq_start, [ (1, [ self.cmd.ras_n.eq(0), self.cmd.we_n.eq(0) ]), (1+tRP, [ self.cmd.cas_n.eq(0), self.cmd.ras_n.eq(0) ]), (1+tRP+tRFC, [ seq_done.eq(1) ]) ]) # Periodic refresh counter counter = Signal(max=tREFI) start = Signal() self.sync += [ start.eq(0), If(counter == 0, start.eq(1), counter.eq(tREFI - 1) ).Else( counter.eq(counter - 1) ) ] # Control FSM fsm = FSM("IDLE", "WAIT_GRANT", "WAIT_SEQ") self.submodules += fsm fsm.act(fsm.IDLE, If(start, fsm.next_state(fsm.WAIT_GRANT))) fsm.act(fsm.WAIT_GRANT, self.req.eq(1), If(self.ack, seq_start.eq(1), fsm.next_state(fsm.WAIT_SEQ) ) ) fsm.act(fsm.WAIT_SEQ, self.req.eq(1), If(seq_done, fsm.next_state(fsm.IDLE)) )
def get_fragment(self): comb = [] sync = [] aaw = self.asmiport.hub.aw adw = self.asmiport.hub.dw # Split address: # TAG | LINE NUMBER | LINE OFFSET offsetbits = log2_int(adw//32) addressbits = aaw + offsetbits linebits = log2_int(self.cachesize) - offsetbits tagbits = addressbits - linebits adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits) # Data memory data_mem = Memory(adw, 2**linebits) data_port = data_mem.get_port(write_capable=True, we_granularity=8) write_from_asmi = Signal() write_to_asmi = Signal() adr_offset_r = Signal(offsetbits) comb += [ data_port.adr.eq(adr_line), If(write_from_asmi, data_port.dat_w.eq(self.asmiport.dat_r), data_port.we.eq(Replicate(1, adw//8)) ).Else( data_port.dat_w.eq(Replicate(self.wishbone.dat_w, adw//32)), If(self.wishbone.cyc & self.wishbone.stb & self.wishbone.we & self.wishbone.ack, displacer(self.wishbone.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True) ) ), If(write_to_asmi, self.asmiport.dat_w.eq(data_port.dat_r)), self.asmiport.dat_wm.eq(0), chooser(data_port.dat_r, adr_offset_r, self.wishbone.dat_r, reverse=True) ] sync += [ adr_offset_r.eq(adr_offset) ] # Tag memory tag_layout = [("tag", tagbits), ("dirty", 1)] tag_mem = Memory(layout_len(tag_layout), 2**linebits) tag_port = tag_mem.get_port(write_capable=True) tag_do = Record(tag_layout) tag_di = Record(tag_layout) comb += [ tag_do.raw_bits().eq(tag_port.dat_r), tag_port.dat_w.eq(tag_di.raw_bits()) ] comb += [ tag_port.adr.eq(adr_line), tag_di.tag.eq(adr_tag), self.asmiport.adr.eq(Cat(adr_line, tag_do.tag)) ] # Control FSM write_to_asmi_pre = Signal() sync.append(write_to_asmi.eq(write_to_asmi_pre)) fsm = FSM("IDLE", "TEST_HIT", "EVICT_ISSUE", "EVICT_WAIT", "REFILL_WRTAG", "REFILL_ISSUE", "REFILL_WAIT", "REFILL_COMPLETE") fsm.act(fsm.IDLE, If(self.wishbone.cyc & self.wishbone.stb, fsm.next_state(fsm.TEST_HIT)) ) fsm.act(fsm.TEST_HIT, If(tag_do.tag == adr_tag, self.wishbone.ack.eq(1), If(self.wishbone.we, tag_di.dirty.eq(1), tag_port.we.eq(1) ), fsm.next_state(fsm.IDLE) ).Else( If(tag_do.dirty, fsm.next_state(fsm.EVICT_ISSUE) ).Else( fsm.next_state(fsm.REFILL_WRTAG) ) ) ) fsm.act(fsm.EVICT_ISSUE, self.asmiport.stb.eq(1), self.asmiport.we.eq(1), If(self.asmiport.ack, fsm.next_state(fsm.EVICT_WAIT)) ) fsm.act(fsm.EVICT_WAIT, # Data is actually sampled by the memory controller in the next state. # But since the data memory has one cycle latency, it gets the data # at the address given during this cycle. If(self.asmiport.get_call_expression(), write_to_asmi_pre.eq(1), fsm.next_state(fsm.REFILL_WRTAG) ) ) fsm.act(fsm.REFILL_WRTAG, # Write the tag first to set the ASMI address tag_port.we.eq(1), fsm.next_state(fsm.REFILL_ISSUE) ) fsm.act(fsm.REFILL_ISSUE, self.asmiport.stb.eq(1), If(self.asmiport.ack, fsm.next_state(fsm.REFILL_WAIT)) ) fsm.act(fsm.REFILL_WAIT, If(self.asmiport.get_call_expression(), fsm.next_state(fsm.REFILL_COMPLETE)) ) fsm.act(fsm.REFILL_COMPLETE, write_from_asmi.eq(1), fsm.next_state(fsm.TEST_HIT) ) return Fragment(comb, sync, specials={data_mem, tag_mem}) \ + fsm.get_fragment()
def __init__(self, phy_settings, geom_settings, timing_settings, bank_machines, refresher, dfi, hub): assert(phy_settings.nphases == len(dfi.phases)) if phy_settings.nphases != 2: raise NotImplementedError("TODO: multiplexer only supports 2 phases") # Command choosing requests = [bm.cmd for bm in bank_machines] tagbits = len(hub.tag_call) choose_cmd = _CommandChooser(requests, tagbits) choose_req = _CommandChooser(requests, tagbits) self.comb += [ choose_cmd.want_reads.eq(0), choose_cmd.want_writes.eq(0) ] self.submodules += choose_cmd, choose_req # Command steering nop = CommandRequest(geom_settings.mux_a, geom_settings.bank_a) commands = [nop, choose_cmd.cmd, choose_req.cmd, refresher.cmd] # nop must be 1st (STEER_NOP, STEER_CMD, STEER_REQ, STEER_REFRESH) = range(4) steerer = _Steerer(commands, dfi) self.submodules += steerer # Read/write turnaround read_available = Signal() write_available = Signal() self.comb += [ read_available.eq(optree("|", [req.stb & req.is_read for req in requests])), write_available.eq(optree("|", [req.stb & req.is_write for req in requests])) ] def anti_starvation(timeout): en = Signal() max_time = Signal() if timeout: t = timeout - 1 time = Signal(max=t+1) self.comb += max_time.eq(time == 0) self.sync += If(~en, time.eq(t) ).Elif(~max_time, time.eq(time - 1) ) else: self.comb += max_time.eq(0) return en, max_time read_time_en, max_read_time = anti_starvation(timing_settings.read_time) write_time_en, max_write_time = anti_starvation(timing_settings.write_time) # Refresh self.comb += [bm.refresh_req.eq(refresher.req) for bm in bank_machines] go_to_refresh = Signal() self.comb += go_to_refresh.eq(optree("&", [bm.refresh_gnt for bm in bank_machines])) # Datapath datapath = _Datapath(timing_settings, choose_req.cmd, dfi, hub) self.submodules += datapath # Control FSM fsm = FSM("READ", "WRITE", "REFRESH", delayed_enters=[ ("RTW", "WRITE", timing_settings.rd_delay), ("WTR", "READ", timing_settings.tWR) ]) self.submodules += fsm fsm.act(fsm.READ, read_time_en.eq(1), choose_req.want_reads.eq(1), choose_cmd.cmd.ack.eq(1), choose_req.cmd.ack.eq(1), steerer.sel[1-phy_settings.rdphase].eq(STEER_CMD), steerer.sel[phy_settings.rdphase].eq(STEER_REQ), If(write_available, # TODO: switch only after several cycles of ~read_available? If(~read_available | max_read_time, fsm.next_state(fsm.RTW)) ), If(go_to_refresh, fsm.next_state(fsm.REFRESH)) ) fsm.act(fsm.WRITE, write_time_en.eq(1), choose_req.want_writes.eq(1), choose_cmd.cmd.ack.eq(1), choose_req.cmd.ack.eq(1), steerer.sel[1-phy_settings.wrphase].eq(STEER_CMD), steerer.sel[phy_settings.wrphase].eq(STEER_REQ), If(read_available, If(~write_available | max_write_time, fsm.next_state(fsm.WTR)) ), If(go_to_refresh, fsm.next_state(fsm.REFRESH)) ) fsm.act(fsm.REFRESH, steerer.sel[0].eq(STEER_REFRESH), If(~refresher.req, fsm.next_state(fsm.READ)) ) # FIXME: workaround for zero-delay loop simulation problem with Icarus Verilog self.comb += refresher.ack.eq(fsm._state == fsm.REFRESH)
def __init__(self, geom_settings, timing_settings, address_align, bankn, slots, full_selector): self.refresh_req = Signal() self.refresh_gnt = Signal() self.cmd = CommandRequestRW(geom_settings.mux_a, geom_settings.bank_a, bits_for(len(slots)-1)) ### # Sub components slicer = _AddressSlicer(geom_settings, address_align) if full_selector: selector = _FullSelector(slicer, bankn, slots) self.submodules.buf = _Buffer(selector) cmdsource = self.buf else: selector = _SimpleSelector(slicer, bankn, slots) cmdsource = selector self.submodules += selector # Row tracking has_openrow = Signal() openrow = Signal(geom_settings.row_a) hit = Signal() self.comb += hit.eq(openrow == slicer.row(cmdsource.adr)) track_open = Signal() track_close = Signal() self.sync += [ If(track_open, has_openrow.eq(1), openrow.eq(slicer.row(cmdsource.adr)) ), If(track_close, has_openrow.eq(0) ) ] # Address generation s_row_adr = Signal() self.comb += [ self.cmd.ba.eq(bankn), If(s_row_adr, self.cmd.a.eq(slicer.row(cmdsource.adr)) ).Else( self.cmd.a.eq(slicer.col(cmdsource.adr)) ) ] self.comb += self.cmd.tag.eq(cmdsource.tag) # Respect write-to-precharge specification precharge_ok = Signal() t_unsafe_precharge = 2 + timing_settings.tWR - 1 unsafe_precharge_count = Signal(max=t_unsafe_precharge+1) self.comb += precharge_ok.eq(unsafe_precharge_count == 0) self.sync += [ If(self.cmd.stb & self.cmd.ack & self.cmd.is_write, unsafe_precharge_count.eq(t_unsafe_precharge) ).Elif(~precharge_ok, unsafe_precharge_count.eq(unsafe_precharge_count-1) ) ] # Control and command generation FSM fsm = FSM("REGULAR", "PRECHARGE", "ACTIVATE", "REFRESH", delayed_enters=[ ("TRP", "ACTIVATE", timing_settings.tRP-1), ("TRCD", "REGULAR", timing_settings.tRCD-1) ]) self.submodules += fsm fsm.act(fsm.REGULAR, If(self.refresh_req, fsm.next_state(fsm.REFRESH) ).Elif(cmdsource.stb, If(has_openrow, If(hit, # NB: write-to-read specification is enforced by multiplexer self.cmd.stb.eq(1), cmdsource.ack.eq(self.cmd.ack), self.cmd.is_read.eq(~cmdsource.we), self.cmd.is_write.eq(cmdsource.we), self.cmd.cas_n.eq(0), self.cmd.we_n.eq(~cmdsource.we) ).Else( fsm.next_state(fsm.PRECHARGE) ) ).Else( fsm.next_state(fsm.ACTIVATE) ) ) ) fsm.act(fsm.PRECHARGE, # Notes: # 1. we are presenting the column address, A10 is always low # 2. since we always go to the ACTIVATE state, we do not need # to assert track_close. If(precharge_ok, self.cmd.stb.eq(1), If(self.cmd.ack, fsm.next_state(fsm.TRP)), self.cmd.ras_n.eq(0), self.cmd.we_n.eq(0) ) ) fsm.act(fsm.ACTIVATE, s_row_adr.eq(1), track_open.eq(1), self.cmd.stb.eq(1), If(self.cmd.ack, fsm.next_state(fsm.TRCD)), self.cmd.ras_n.eq(0) ) fsm.act(fsm.REFRESH, self.refresh_gnt.eq(precharge_ok), track_close.eq(1), If(~self.refresh_req, fsm.next_state(fsm.REGULAR)) )