+++ /dev/null
-from migen.fhdl.std import *
-from migen.bus import dfi, asmibus
-
-from milkymist.asmicon.refresher import *
-from milkymist.asmicon.bankmachine import *
-from milkymist.asmicon.multiplexer import *
-
-class PhySettings:
- def __init__(self, dfi_d, nphases, rdphase, wrphase):
- self.dfi_d = dfi_d
- self.nphases = nphases
- self.rdphase = rdphase
- self.wrphase = wrphase
-
-class GeomSettings:
- def __init__(self, bank_a, row_a, col_a):
- self.bank_a = bank_a
- self.row_a = row_a
- self.col_a = col_a
- self.mux_a = max(row_a, col_a)
-
-class TimingSettings:
- def __init__(self, tRP, tRCD, tWR, tREFI, tRFC, CL, rd_delay, read_time, write_time, slot_time=0):
- self.tRP = tRP
- self.tRCD = tRCD
- self.tWR = tWR
- self.tREFI = tREFI
- self.tRFC = tRFC
-
- self.CL = CL
- self.rd_delay = rd_delay
-
- self.read_time = read_time
- self.write_time = write_time
- self.slot_time = slot_time
-
-class ASMIcon(Module):
- def __init__(self, phy_settings, geom_settings, timing_settings, full_selector=False):
- self.phy_settings = phy_settings
- self.geom_settings = geom_settings
- self.timing_settings = timing_settings
- self.full_selector = full_selector
-
- self.dfi = dfi.Interface(self.geom_settings.mux_a,
- self.geom_settings.bank_a,
- self.phy_settings.dfi_d,
- self.phy_settings.nphases)
- burst_length = self.phy_settings.nphases*2
- self.address_align = log2_int(burst_length)
- aw = self.geom_settings.bank_a + self.geom_settings.row_a + self.geom_settings.col_a - self.address_align
- dw = self.phy_settings.dfi_d*self.phy_settings.nphases
- self.submodules.hub = asmibus.Hub(aw, dw, self.timing_settings.slot_time)
-
- def do_finalize(self):
- slots = self.hub.get_slots()
- self.submodules.refresher = Refresher(self.geom_settings.mux_a, self.geom_settings.bank_a,
- self.timing_settings.tRP, self.timing_settings.tREFI, self.timing_settings.tRFC)
- self.submodules.bank_machines = [BankMachine(self.geom_settings, self.timing_settings, self.address_align, i, slots, self.full_selector)
- for i in range(2**self.geom_settings.bank_a)]
- self.submodules.multiplexer = Multiplexer(self.phy_settings, self.geom_settings, self.timing_settings,
- self.bank_machines, self.refresher,
- self.dfi, self.hub)
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bus.asmibus import *
-from migen.genlib.roundrobin import *
-from migen.genlib.fsm import FSM
-from migen.genlib.misc import optree
-
-from milkymist.asmicon.multiplexer import *
-
-# Row:Bank:Col address mapping
-class _AddressSlicer:
- def __init__(self, geom_settings, address_align):
- self.geom_settings = geom_settings
- self.address_align = address_align
-
- self._b1 = self.geom_settings.col_a - self.address_align
- self._b2 = self._b1 + self.geom_settings.bank_a
-
- def row(self, address):
- if isinstance(address, int):
- return address >> self._b2
- else:
- return address[self._b2:]
-
- def bank(self, address):
- if isinstance(address, int):
- return (address & (2**self._b2 - 1)) >> self._b1
- else:
- return address[self._b1:self._b2]
-
- def col(self, address):
- if isinstance(address, int):
- return (address & (2**self._b1 - 1)) << self.address_align
- else:
- return Cat(Replicate(0, self.address_align), address[:self._b1])
-
-class _Selector(Module):
- def __init__(self, slicer, bankn, slots):
- nslots = len(slots)
- self.stb = Signal()
- self.ack = Signal()
- self.tag = Signal(max=nslots)
- self.adr = Signal(slots[0].adr.nbits)
- self.we = Signal()
-
- # derived classes should drive rr.request
- self.submodules.rr = RoundRobin(nslots, SP_CE)
-
- ###
-
- # Multiplex
- rr = self.rr
- state = Signal(2)
- self.comb += [
- state.eq(Array(slot.state for slot in slots)[rr.grant]),
- self.adr.eq(Array(slot.adr for slot in slots)[rr.grant]),
- self.we.eq(Array(slot.we for slot in slots)[rr.grant]),
- self.stb.eq(
- (slicer.bank(self.adr) == bankn) \
- & (state == SLOT_PENDING)),
- rr.ce.eq(self.ack | ~self.stb),
- self.tag.eq(rr.grant)
- ]
- self.comb += [If((rr.grant == i) & self.stb & self.ack, slot.process.eq(1))
- for i, slot in enumerate(slots)]
-
- self.complete_selector(slicer, bankn, slots)
-
-class _SimpleSelector(_Selector):
- def complete_selector(self, slicer, bankn, slots):
- for i, slot in enumerate(slots):
- self.comb += self.rr.request[i].eq(
- (slicer.bank(slot.adr) == bankn) & \
- (slot.state == SLOT_PENDING))
-
-class _FullSelector(_Selector):
- def complete_selector(self, slicer, bankn, slots):
- rr = self.rr
-
- # List outstanding requests for our bank
- outstandings = []
- for slot in slots:
- outstanding = Signal()
- self.comb += outstanding.eq(
- (slicer.bank(slot.adr) == bankn) & \
- (slot.state == SLOT_PENDING))
- outstandings.append(outstanding)
-
- # Row tracking
- openrow_r = Signal(slicer.geom_settings.row_a)
- openrow_n = Signal(slicer.geom_settings.row_a)
- openrow = Signal(slicer.geom_settings.row_a)
- self.comb += [
- openrow_n.eq(slicer.row(self.adr)),
- If(self.stb,
- openrow.eq(openrow_n)
- ).Else(
- openrow.eq(openrow_r)
- )
- ]
- self.sync += If(self.stb & self.ack, openrow_r.eq(openrow_n))
- hits = []
- for slot, os in zip(slots, outstandings):
- hit = Signal()
- self.comb += hit.eq((slicer.row(slot.adr) == openrow) & os)
- hits.append(hit)
-
- # Determine best request
- rr = RoundRobin(self.nslots, SP_CE)
- has_hit = Signal()
- self.comb += has_hit.eq(optree("|", hits))
-
- best_hit = [rr.request[i].eq(hit)
- for i, hit in enumerate(hits)]
- best_fallback = [rr.request[i].eq(os)
- for i, os in enumerate(outstandings)]
- select_stmt = If(has_hit,
- *best_hit
- ).Else(
- *best_fallback
- )
-
- if slots[0].time:
- # Implement anti-starvation timer
- matures = []
- for slot, os in zip(slots, outstandings):
- mature = Signal()
- comb.append(mature.eq(slot.mature & os))
- matures.append(mature)
- has_mature = Signal()
- self.comb += has_mature.eq(optree("|", matures))
- best_mature = [rr.request[i].eq(mature)
- for i, mature in enumerate(matures)]
- select_stmt = If(has_mature, *best_mature).Else(select_stmt)
- self.comb += select_stmt
-
-class _Buffer(Module):
- def __init__(self, source):
- self.stb = Signal()
- self.ack = Signal()
- self.tag = Signal(source.tag.bv)
- self.adr = Signal(source.adr.bv)
- self.we = Signal()
-
- ###
-
- en = Signal()
- self.comb += [
- en.eq(self.ack | ~self.stb),
- source.ack.eq(en)
- ]
- self.sync += [
- If(en,
- self.stb.eq(source.stb),
- self.tag.eq(source.tag),
- self.adr.eq(source.adr),
- self.we.eq(source.we)
- )
- ]
-
-class BankMachine(Module):
- 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))
- )
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.roundrobin import *
-from migen.genlib.misc import optree
-from migen.genlib.fsm import FSM
-
-class CommandRequest:
- def __init__(self, a, ba):
- self.a = Signal(a)
- self.ba = Signal(ba)
- self.cas_n = Signal(reset=1)
- self.ras_n = Signal(reset=1)
- self.we_n = Signal(reset=1)
-
-class CommandRequestRW(CommandRequest):
- def __init__(self, a, ba, tagbits):
- CommandRequest.__init__(self, a, ba)
- self.stb = Signal()
- self.ack = Signal()
- self.is_read = Signal()
- self.is_write = Signal()
- self.tag = Signal(tagbits)
-
-class _CommandChooser(Module):
- def __init__(self, requests, tagbits):
- self.want_reads = Signal()
- self.want_writes = Signal()
- # NB: cas_n/ras_n/we_n are 1 when stb is inactive
- self.cmd = CommandRequestRW(flen(requests[0].a), flen(requests[0].ba), tagbits)
-
- ###
-
- rr = RoundRobin(len(requests), SP_CE)
- self.submodules += rr
-
- self.comb += [rr.request[i].eq(req.stb & ((req.is_read == self.want_reads) | (req.is_write == self.want_writes)))
- for i, req in enumerate(requests)]
-
- stb = Signal()
- self.comb += stb.eq(Array(req.stb for req in requests)[rr.grant])
- for name in ["a", "ba", "is_read", "is_write", "tag"]:
- choices = Array(getattr(req, name) for req in requests)
- self.comb += getattr(self.cmd, name).eq(choices[rr.grant])
- for name in ["cas_n", "ras_n", "we_n"]:
- # we should only assert those signals when stb is 1
- choices = Array(getattr(req, name) for req in requests)
- self.comb += If(self.cmd.stb, getattr(self.cmd, name).eq(choices[rr.grant]))
- self.comb += self.cmd.stb.eq(stb \
- & (self.cmd.is_read == self.want_reads) \
- & (self.cmd.is_write == self.want_writes))
-
- self.comb += [If(self.cmd.stb & self.cmd.ack & (rr.grant == i), req.ack.eq(1))
- for i, req in enumerate(requests)]
- self.comb += rr.ce.eq(self.cmd.ack)
-
-class _Steerer(Module):
- def __init__(self, commands, dfi):
- ncmd = len(commands)
- nph = len(dfi.phases)
- self.sel = [Signal(max=ncmd) for i in range(nph)]
-
- ###
-
- def stb_and(cmd, attr):
- if not hasattr(cmd, "stb"):
- return 0
- else:
- return cmd.stb & getattr(cmd, attr)
- for phase, sel in zip(dfi.phases, self.sel):
- self.comb += [
- phase.cke.eq(1),
- phase.cs_n.eq(0)
- ]
- self.sync += [
- phase.address.eq(Array(cmd.a for cmd in commands)[sel]),
- phase.bank.eq(Array(cmd.ba for cmd in commands)[sel]),
- phase.cas_n.eq(Array(cmd.cas_n for cmd in commands)[sel]),
- phase.ras_n.eq(Array(cmd.ras_n for cmd in commands)[sel]),
- phase.we_n.eq(Array(cmd.we_n for cmd in commands)[sel]),
- phase.rddata_en.eq(Array(stb_and(cmd, "is_read") for cmd in commands)[sel]),
- phase.wrdata_en.eq(Array(stb_and(cmd, "is_write") for cmd in commands)[sel])
- ]
-
-class _Datapath(Module):
- def __init__(self, timing_settings, command, dfi, hub):
- tagbits = flen(hub.tag_call)
-
- rd_valid = Signal()
- rd_tag = Signal(tagbits)
- wr_valid = Signal()
- wr_tag = Signal(tagbits)
- self.comb += [
- hub.call.eq(rd_valid | wr_valid),
- If(wr_valid,
- hub.tag_call.eq(wr_tag)
- ).Else(
- hub.tag_call.eq(rd_tag)
- )
- ]
-
- rd_delay = timing_settings.rd_delay + 1
- rd_valid_d = [Signal() for i in range(rd_delay)]
- rd_tag_d = [Signal(tagbits) for i in range(rd_delay)]
- for i in range(rd_delay):
- if i:
- self.sync += [
- rd_valid_d[i].eq(rd_valid_d[i-1]),
- rd_tag_d[i].eq(rd_tag_d[i-1])
- ]
- else:
- self.sync += [
- rd_valid_d[i].eq(command.stb & command.ack & command.is_read),
- rd_tag_d[i].eq(command.tag)
- ]
- self.comb += [
- rd_valid.eq(rd_valid_d[-1]),
- rd_tag.eq(rd_tag_d[-1]),
- wr_valid.eq(command.stb & command.ack & command.is_write),
- wr_tag.eq(command.tag),
- ]
-
- all_rddata = [p.rddata for p in dfi.phases]
- all_wrdata = [p.wrdata for p in dfi.phases]
- all_wrdata_mask = [p.wrdata_mask for p in dfi.phases]
- self.comb += [
- hub.dat_r.eq(Cat(*all_rddata)),
- Cat(*all_wrdata).eq(hub.dat_w),
- Cat(*all_wrdata_mask).eq(hub.dat_wm)
- ]
-
-class Multiplexer(Module):
- 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 = flen(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)
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.misc import timeline
-from migen.genlib.fsm import FSM
-
-from milkymist.asmicon.multiplexer import *
-
-class Refresher(Module):
- 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))
- )
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bank.description import *
-
-class ASMIprobe(Module):
- def __init__(self, hub, trace_depth=16):
- slots = hub.get_slots()
- slot_count = len(slots)
-
- self._slot_count = CSRStatus(bits_for(slot_count))
- self._trace_depth = CSRStatus(bits_for(trace_depth))
- self._slot_status = [CSRStatus(2, name="slot_status" + str(i)) for i in range(slot_count)]
- self._trace = [CSRStatus(bits_for(slot_count-1), name="trace" + str(i)) for i in range(trace_depth)]
-
- ###
-
- self.comb += [
- self._slot_count.status.eq(slot_count),
- self._trace_depth.status.eq(trace_depth)
- ]
- for slot, status in zip(slots, self._slot_status):
- self.sync += status.status.eq(slot.state)
- shift_tags = [self._trace[n].status.eq(self._trace[n+1].status)
- for n in range(len(self._trace) - 1)]
- shift_tags.append(self._trace[-1].status.eq(hub.tag_call))
- self.sync += If(hub.call, *shift_tags)
-
- def get_csrs(self):
- return [self._slot_count, self._trace_depth] + self._slot_status + self._trace
###
+ wrdata_en_adv = Signal()
self.comb += [
If(self._command_issue.re,
phase.cs_n.eq(~self._command.storage[0]),
),
phase.address.eq(self._address.storage),
phase.bank.eq(self._baddress.storage),
- phase.wrdata_en.eq(self._command_issue.re & self._command.storage[4]),
+ wrdata_en_adv.eq(self._command_issue.re & self._command.storage[4]),
phase.rddata_en.eq(self._command_issue.re & self._command.storage[5]),
phase.wrdata.eq(self._wrdata.storage),
phase.wrdata_mask.eq(0)
]
- self.sync += If(phase.rddata_valid, self._rddata.status.eq(phase.rddata))
+ self.sync += [
+ phase.wrdata_en.eq(wrdata_en_adv),
+ If(phase.rddata_valid, self._rddata.status.eq(phase.rddata))
+ ]
class DFIInjector(Module, AutoCSR):
def __init__(self, a, ba, d, nphases=1):
from migen.genlib.fifo import AsyncFIFO
from migen.genlib.record import layout_len
from migen.bank.description import AutoCSR
-from migen.actorlib import structuring, dma_asmi, spi
+from migen.actorlib import structuring, dma_lasmi, spi
from milkymist.dvisampler.edid import EDID
from milkymist.dvisampler.clocking import Clocking
pack_factor = asmiport.hub.dw//16
self.submodules.packer = structuring.Pack([("word", 10), ("pad", 6)], pack_factor)
self.submodules.cast = structuring.Cast(self.packer.source.payload.layout, asmiport.hub.dw)
- self.submodules.dma = spi.DMAWriteController(dma_asmi.Writer(asmiport), spi.MODE_SINGLE_SHOT, free_flow=True)
+ self.submodules.dma = spi.DMAWriteController(dma_lasmi.Writer(lasmim), spi.MODE_SINGLE_SHOT)
self.comb += [
self.packer.sink.stb.eq(fifo.readable),
fifo.re.eq(self.packer.sink.ack),
from migen.bank.description import *
from migen.bank.eventmanager import *
from migen.flow.actor import *
-from migen.actorlib import dma_asmi
+from migen.actorlib import dma_lasmi
from milkymist.dvisampler.common import frame_layout
self.comb += [slot.address_done.eq(self.address_done & (current_slot == n)) for n, slot in enumerate(slots)]
class DMA(Module):
- def __init__(self, asmiport, nslots):
- bus_aw = asmiport.hub.aw
- bus_dw = asmiport.hub.dw
+ def __init__(self, lasmim, nslots):
+ bus_aw = lasmim.aw
+ bus_dw = lasmim.dw
alignment_bits = bits_for(bus_dw//8) - 1
self.frame = Sink(frame_layout)
)
# bus accessor
- self.submodules._bus_accessor = dma_asmi.Writer(asmiport)
+ self.submodules._bus_accessor = dma_lasmi.Writer(lasmim)
self.comb += [
self._bus_accessor.address_data.payload.a.eq(current_address),
self._bus_accessor.address_data.payload.d.eq(cur_memory_word)
from migen.flow.actor import *
from migen.flow.network import *
from migen.bank.description import CSRStorage, AutoCSR
-from migen.actorlib import dma_asmi, structuring, sim, spi
+from migen.actorlib import dma_lasmi, structuring, sim, spi
from milkymist.framebuffer.lib import bpp, pixel_layout, dac_layout, FrameInitiator, VTG, FIFO
class Framebuffer(Module):
- def __init__(self, pads, asmiport, simulation=False):
- pack_factor = asmiport.hub.dw//(2*bpp)
+ def __init__(self, pads, lasmim, simulation=False):
+ pack_factor = lasmim.dw//(2*bpp)
packed_pixels = structuring.pack_layout(pixel_layout, pack_factor)
fi = FrameInitiator()
- dma = spi.DMAReadController(dma_asmi.Reader(asmiport), spi.MODE_EXTERNAL, length_reset=640*480*4)
- cast = structuring.Cast(asmiport.hub.dw, packed_pixels, reverse_to=True)
+ dma = spi.DMAReadController(dma_lasmi.Reader(lasmim), spi.MODE_EXTERNAL, length_reset=640*480*4)
+ cast = structuring.Cast(lasmim.dw, packed_pixels, reverse_to=True)
unpack = structuring.Unpack(pack_factor, pixel_layout)
vtg = VTG()
if simulation:
self.comb += self.source.payload.eq(outval)
class MixFramebuffer(Module, AutoCSR):
- def __init__(self, pads, *asmiports, blender_latency=5):
- pack_factor = asmiports[0].hub.dw//(2*bpp)
+ def __init__(self, pads, *lasmims, blender_latency=5):
+ pack_factor = lasmims[0].dw//(2*bpp)
packed_pixels = structuring.pack_layout(pixel_layout, pack_factor)
self._enable = CSRStorage()
self.fi = FrameInitiator()
- self.blender = Blender(len(asmiports), blender_latency)
+ self.blender = Blender(len(lasmims), blender_latency)
self.comb += self.fi.trigger.eq(self._enable.storage)
g = DataFlowGraph()
- for n, asmiport in enumerate(asmiports):
- dma = spi.DMAReadController(dma_asmi.Reader(asmiport), spi.MODE_EXTERNAL, length_reset=640*480*4)
- cast = structuring.Cast(asmiport.hub.dw, packed_pixels, reverse_to=True)
+ for n, lasmim in enumerate(lasmims):
+ dma = spi.DMAReadController(dma_lasmi.Reader(lasmim), spi.MODE_EXTERNAL, length_reset=640*480*4)
+ cast = structuring.Cast(lasmim.dw, packed_pixels, reverse_to=True)
unpack = structuring.Unpack(pack_factor, pixel_layout)
g.add_connection(dma, cast)
--- /dev/null
+from migen.fhdl.std import *
+from migen.bus import dfi, lasmibus
+
+from milkymist.lasmicon.refresher import *
+from milkymist.lasmicon.bankmachine import *
+from milkymist.lasmicon.multiplexer import *
+
+class PhySettings:
+ def __init__(self, dfi_d, nphases, rdphase, wrphase):
+ self.dfi_d = dfi_d
+ self.nphases = nphases
+ self.rdphase = rdphase
+ self.wrphase = wrphase
+
+class GeomSettings:
+ def __init__(self, bank_a, row_a, col_a):
+ self.bank_a = bank_a
+ self.row_a = row_a
+ self.col_a = col_a
+ self.mux_a = max(row_a, col_a)
+
+class TimingSettings:
+ def __init__(self, tRP, tRCD, tWR, tWTR, tREFI, tRFC, CL, read_latency, write_latency, read_time, write_time):
+ self.tRP = tRP
+ self.tRCD = tRCD
+ self.tWR = tWR
+ self.tWTR = tWTR
+ self.tREFI = tREFI
+ self.tRFC = tRFC
+
+ self.CL = CL
+ self.read_latency = read_latency
+ self.write_latency = write_latency
+
+ self.read_time = read_time
+ self.write_time = write_time
+
+class LASMIcon(Module):
+ def __init__(self, phy_settings, geom_settings, timing_settings):
+ burst_length = phy_settings.nphases*2 # command multiplication*DDR
+ address_align = log2_int(burst_length)
+
+ self.dfi = dfi.Interface(geom_settings.mux_a,
+ geom_settings.bank_a,
+ phy_settings.dfi_d,
+ phy_settings.nphases)
+ self.lasmic = lasmibus.Interface(
+ aw=geom_settings.row_a + geom_settings.col_a - address_align,
+ dw=phy_settings.dfi_d*phy_settings.nphases,
+ nbanks=2**geom_settings.bank_a,
+ read_latency=timing_settings.read_latency,
+ write_latency=timing_settings.write_latency)
+ self.nrowbits = geom_settings.col_a - address_align
+
+ ###
+
+ self.submodules.refresher = Refresher(geom_settings.mux_a, geom_settings.bank_a,
+ timing_settings.tRP, timing_settings.tREFI, timing_settings.tRFC)
+ self.submodules.bank_machines = [BankMachine(geom_settings, timing_settings, address_align, i,
+ getattr(self.lasmic, "bank"+str(i)))
+ for i in range(2**geom_settings.bank_a)]
+ self.submodules.multiplexer = Multiplexer(phy_settings, geom_settings, timing_settings,
+ self.bank_machines, self.refresher,
+ self.dfi, self.lasmic)
--- /dev/null
+from migen.fhdl.std import *
+from migen.bus.asmibus import *
+from migen.genlib.roundrobin import *
+from migen.genlib.fsm import FSM
+from migen.genlib.misc import optree
+
+from milkymist.lasmicon.multiplexer import *
+
+class _AddressSlicer:
+ def __init__(self, col_a, address_align):
+ self.col_a = col_a
+ self.address_align = address_align
+
+ def row(self, address):
+ split = self.col_a - self.address_align
+ if isinstance(address, int):
+ return address >> split
+ else:
+ return address[split:]
+
+ def col(self, address):
+ split = self.col_a - self.address_align
+ if isinstance(address, int):
+ return (address & (2**split - 1)) << self.address_align
+ else:
+ return Cat(Replicate(0, self.address_align), address[:split])
+
+class BankMachine(Module):
+ def __init__(self, geom_settings, timing_settings, address_align, bankn, req):
+ self.refresh_req = Signal()
+ self.refresh_gnt = Signal()
+ self.cmd = CommandRequestRW(geom_settings.mux_a, geom_settings.bank_a)
+
+ ###
+
+ slicer = _AddressSlicer(geom_settings.col_a, address_align)
+
+ # Row tracking
+ has_openrow = Signal()
+ openrow = Signal(geom_settings.row_a)
+ hit = Signal()
+ self.comb += hit.eq(openrow == slicer.row(req.adr))
+ track_open = Signal()
+ track_close = Signal()
+ self.sync += [
+ If(track_open,
+ has_openrow.eq(1),
+ openrow.eq(slicer.row(req.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(req.adr))
+ ).Else(
+ self.cmd.a.eq(slicer.col(req.adr))
+ )
+ ]
+
+ # 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(req.stb,
+ If(has_openrow,
+ If(hit,
+ # NB: write-to-read specification is enforced by multiplexer
+ self.cmd.stb.eq(1),
+ req.ack.eq(self.cmd.ack),
+ self.cmd.is_read.eq(~req.we),
+ self.cmd.is_write.eq(req.we),
+ self.cmd.cas_n.eq(0),
+ self.cmd.we_n.eq(~req.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))
+ )
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.roundrobin import *
+from migen.genlib.misc import optree
+from migen.genlib.fsm import FSM
+
+class CommandRequest:
+ def __init__(self, a, ba):
+ self.a = Signal(a)
+ self.ba = Signal(ba)
+ self.cas_n = Signal(reset=1)
+ self.ras_n = Signal(reset=1)
+ self.we_n = Signal(reset=1)
+
+class CommandRequestRW(CommandRequest):
+ def __init__(self, a, ba):
+ CommandRequest.__init__(self, a, ba)
+ self.stb = Signal()
+ self.ack = Signal()
+ self.is_read = Signal()
+ self.is_write = Signal()
+
+class _CommandChooser(Module):
+ def __init__(self, requests):
+ self.want_reads = Signal()
+ self.want_writes = Signal()
+ # NB: cas_n/ras_n/we_n are 1 when stb is inactive
+ self.cmd = CommandRequestRW(flen(requests[0].a), flen(requests[0].ba))
+
+ ###
+
+ rr = RoundRobin(len(requests), SP_CE)
+ self.submodules += rr
+
+ self.comb += [rr.request[i].eq(req.stb & ((req.is_read == self.want_reads) | (req.is_write == self.want_writes)))
+ for i, req in enumerate(requests)]
+
+ stb = Signal()
+ self.comb += stb.eq(Array(req.stb for req in requests)[rr.grant])
+ for name in ["a", "ba", "is_read", "is_write"]:
+ choices = Array(getattr(req, name) for req in requests)
+ self.comb += getattr(self.cmd, name).eq(choices[rr.grant])
+ for name in ["cas_n", "ras_n", "we_n"]:
+ # we should only assert those signals when stb is 1
+ choices = Array(getattr(req, name) for req in requests)
+ self.comb += If(self.cmd.stb, getattr(self.cmd, name).eq(choices[rr.grant]))
+ self.comb += self.cmd.stb.eq(stb \
+ & (self.cmd.is_read == self.want_reads) \
+ & (self.cmd.is_write == self.want_writes))
+
+ self.comb += [If(self.cmd.stb & self.cmd.ack & (rr.grant == i), req.ack.eq(1))
+ for i, req in enumerate(requests)]
+ self.comb += rr.ce.eq(self.cmd.ack)
+
+class _Steerer(Module):
+ def __init__(self, commands, dfi):
+ ncmd = len(commands)
+ nph = len(dfi.phases)
+ self.sel = [Signal(max=ncmd) for i in range(nph)]
+
+ ###
+
+ def stb_and(cmd, attr):
+ if not hasattr(cmd, "stb"):
+ return 0
+ else:
+ return cmd.stb & getattr(cmd, attr)
+ for phase, sel in zip(dfi.phases, self.sel):
+ wrdata_en_adv = Signal()
+ self.comb += [
+ phase.cke.eq(1),
+ phase.cs_n.eq(0)
+ ]
+ self.sync += [
+ phase.address.eq(Array(cmd.a for cmd in commands)[sel]),
+ phase.bank.eq(Array(cmd.ba for cmd in commands)[sel]),
+ phase.cas_n.eq(Array(cmd.cas_n for cmd in commands)[sel]),
+ phase.ras_n.eq(Array(cmd.ras_n for cmd in commands)[sel]),
+ phase.we_n.eq(Array(cmd.we_n for cmd in commands)[sel]),
+ phase.rddata_en.eq(Array(stb_and(cmd, "is_read") for cmd in commands)[sel]),
+ wrdata_en_adv.eq(Array(stb_and(cmd, "is_write") for cmd in commands)[sel]),
+ phase.wrdata_en.eq(wrdata_en_adv)
+ ]
+
+class Multiplexer(Module):
+ def __init__(self, phy_settings, geom_settings, timing_settings, bank_machines, refresher, dfi, lasmic):
+ 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]
+ choose_cmd = _CommandChooser(requests)
+ choose_req = _CommandChooser(requests)
+ 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
+ all_rddata = [p.rddata for p in dfi.phases]
+ all_wrdata = [p.wrdata for p in dfi.phases]
+ all_wrdata_mask = [p.wrdata_mask for p in dfi.phases]
+ self.comb += [
+ lasmic.dat_r.eq(Cat(*all_rddata)),
+ Cat(*all_wrdata).eq(lasmic.dat_w),
+ Cat(*all_wrdata_mask).eq(~lasmic.dat_we)
+ ]
+
+ # Control FSM
+ fsm = FSM("READ", "WRITE", "REFRESH", delayed_enters=[
+ ("RTW", "WRITE", timing_settings.read_latency),
+ ("WTR", "READ", timing_settings.tWTR)
+ ])
+ 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)
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.misc import timeline
+from migen.genlib.fsm import FSM
+
+from milkymist.lasmicon.multiplexer import *
+
+class Refresher(Module):
+ 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))
+ )
else if(strcmp(token, "ddrwr") == 0) ddrwr(get_token(&c));
else if(strcmp(token, "memtest") == 0) memtest();
else if(strcmp(token, "ddrinit") == 0) ddrinit();
- else if(strcmp(token, "asmiprobe") == 0) asmiprobe();
else if(strcmp(token, "dfs") == 0) dfs(get_token(&c));
cdelay(15);
for(i=0;i<8;i++)
- printf("%02x", MMPTR(0xe0000834+4*i));
+ printf("%02x", MMPTR(0xe0001038+4*i));
for(i=0;i<8;i++)
- printf("%02x", MMPTR(0xe0000884+4*i));
+ printf("%02x", MMPTR(0xe000108c+4*i));
printf("\n");
}
}
for(i=0;i<8;i++) {
- MMPTR(0xe0000814+4*i) = i;
- MMPTR(0xe0000864+4*i) = 0xf0 + i;
+ MMPTR(0xe0001018+4*i) = i;
+ MMPTR(0xe000106c+4*i) = 0xf0 + i;
}
dfii_pi1_address_write(addr);
return 1;
}
-
-static const char *format_slot_state(int state)
-{
- switch(state) {
- case 0: return "Empty";
- case 1: return "Pending";
- case 2: return "Processing";
- default: return "UNEXPECTED VALUE";
- }
-}
-
-void asmiprobe(void)
-{
- volatile unsigned int *regs = (unsigned int *)ASMIPROBE_BASE;
- int slot_count;
- int trace_depth;
- int i;
- int offset;
-
- offset = 0;
- slot_count = regs[offset++];
- trace_depth = regs[offset++];
- for(i=0;i<slot_count;i++)
- printf("Slot #%d: %s\n", i, format_slot_state(regs[offset++]));
- printf("Latest tags:\n");
- for(i=0;i<trace_depth;i++)
- printf("%d ", regs[offset++]);
- printf("\n");
-}
int memtest(void);
int ddrinit(void);
-void asmiprobe(void);
-
#endif /* __SDRAM_H */
from operator import itemgetter
from migen.fhdl.std import *
-from migen.bus import wishbone, wishbone2asmi, csr, wishbone2csr, dfi
+from migen.bus import wishbone, csr, lasmibus, dfi
+from migen.bus import wishbone2lasmi, wishbone2csr
from migen.bank import csrgen
-from milkymist import m1crg, lm32, norflash, uart, s6ddrphy, dfii, asmicon, \
- identifier, timer, minimac3, framebuffer, asmiprobe, dvisampler, \
+from milkymist import m1crg, lm32, norflash, uart, s6ddrphy, dfii, lasmicon, \
+ identifier, timer, minimac3, framebuffer, dvisampler, \
counteradc, gpio
from milkymist.cif import get_macros
t += clk_period_ns/2
return ceil(t/clk_period_ns)
-sdram_phy = asmicon.PhySettings(
+sdram_phy = lasmicon.PhySettings(
dfi_d=64,
nphases=2,
rdphase=0,
wrphase=1
)
-sdram_geom = asmicon.GeomSettings(
+sdram_geom = lasmicon.GeomSettings(
bank_a=2,
row_a=13,
col_a=10
)
-sdram_timing = asmicon.TimingSettings(
+sdram_timing = lasmicon.TimingSettings(
tRP=ns(15),
tRCD=ns(15),
tWR=ns(15),
+ tWTR=2,
tREFI=ns(7800, False),
tRFC=ns(70),
CL=3,
- rd_delay=4,
+ read_latency=5,
+ write_latency=1,
read_time=32,
write_time=16
"timer0": 4,
"minimac": 5,
"fb": 6,
- "asmiprobe": 7,
- "dvisampler0": 8,
- "dvisampler0_edid_mem": 9,
- "dvisampler1": 10,
- "dvisampler1_edid_mem": 11,
- "pots": 12,
- "buttons": 13,
- "leds": 14
+ "dvisampler0": 7,
+ "dvisampler0_edid_mem": 8,
+ "dvisampler1": 9,
+ "dvisampler1_edid_mem": 10,
+ "pots": 11,
+ "buttons": 12,
+ "leds": 13
}
interrupt_map = {
def __init__(self, platform):
#
- # ASMI
+ # LASMI
#
- self.submodules.asmicon = asmicon.ASMIcon(sdram_phy, sdram_geom, sdram_timing)
- asmiport_wb = self.asmicon.hub.get_port()
- asmiport_fb0 = self.asmicon.hub.get_port(4)
- asmiport_fb1 = self.asmicon.hub.get_port(4)
- asmiport_dvi0 = self.asmicon.hub.get_port(4)
- asmiport_dvi1 = self.asmicon.hub.get_port(4)
- self.asmicon.finalize()
+ self.submodules.lasmicon = lasmicon.LASMIcon(sdram_phy, sdram_geom, sdram_timing)
+ self.submodules.lasmixbar = lasmibus.Crossbar([self.lasmicon.lasmic], 5, self.lasmicon.nrowbits)
+ lasmim_wb, lasmim_fb0, lasmim_fb1, lasmim_dvi0, lasmim_dvi1 = self.lasmixbar.masters
#
# DFI
self.submodules.dfii = dfii.DFIInjector(sdram_geom.mux_a, sdram_geom.bank_a, sdram_phy.dfi_d,
sdram_phy.nphases)
self.submodules.dficon0 = dfi.Interconnect(self.dfii.master, self.ddrphy.dfi)
- self.submodules.dficon1 = dfi.Interconnect(self.asmicon.dfi, self.dfii.slave)
+ self.submodules.dficon1 = dfi.Interconnect(self.lasmicon.dfi, self.dfii.slave)
#
# WISHBONE
self.submodules.norflash = norflash.NorFlash(platform.request("norflash"), 12)
self.submodules.sram = wishbone.SRAM(sram_size)
self.submodules.minimac = minimac3.MiniMAC(platform.request("eth"))
- self.submodules.wishbone2asmi = wishbone2asmi.WB2ASMI(l2_size//4, asmiport_wb)
+ self.submodules.wishbone2lasmi = wishbone2lasmi.WB2LASMI(l2_size//4, lasmim_wb)
self.submodules.wishbone2csr = wishbone2csr.WB2CSR()
# norflash 0x00000000 (shadow @0x80000000)
(lambda a: a[26:29] == 0, self.norflash.bus),
(lambda a: a[26:29] == 1, self.sram.bus),
(lambda a: a[26:29] == 3, self.minimac.membus),
- (lambda a: a[27:29] == 2, self.wishbone2asmi.wishbone),
+ (lambda a: a[27:29] == 2, self.wishbone2lasmi.wishbone),
(lambda a: a[27:29] == 3, self.wishbone2csr.wishbone)
],
register=True)
self.submodules.uart = uart.UART(platform.request("serial"), clk_freq, baud=115200)
self.submodules.identifier = identifier.Identifier(0x4D31, version, int(clk_freq))
self.submodules.timer0 = timer.Timer()
- self.submodules.fb = framebuffer.MixFramebuffer(platform.request("vga"), asmiport_fb0, asmiport_fb1)
- self.submodules.asmiprobe = asmiprobe.ASMIprobe(self.asmicon.hub)
- self.submodules.dvisampler0 = dvisampler.DVISampler(platform.request("dvi_in", 0), asmiport_dvi0)
- self.submodules.dvisampler1 = dvisampler.DVISampler(platform.request("dvi_in", 1), asmiport_dvi1)
+ self.submodules.fb = framebuffer.MixFramebuffer(platform.request("vga"), lasmim_fb0, lasmim_fb1)
+ self.submodules.dvisampler0 = dvisampler.DVISampler(platform.request("dvi_in", 0), lasmim_dvi0)
+ self.submodules.dvisampler1 = dvisampler.DVISampler(platform.request("dvi_in", 1), lasmim_dvi1)
pots_pads = platform.request("dvi_pots")
self.submodules.pots = counteradc.CounterADC(pots_pads.charge,
[pots_pads.blackout, pots_pads.crossfade])
* 1:2 frequency-ratio DDR PHY for Spartan-6
*
* Assert dfi_wrdata_en and present the data
- * on dfi_wrdata_mask/dfi_wrdata in the same
- * cycle as the write command.
+ * on dfi_wrdata_mask/dfi_wrdata in the cycle
+ * immediately following the write command.
*
* Assert dfi_rddata_en in the same cycle as the read
* command. The data will come back on dfi_rddata
- * 4 cycles later, along with the assertion of
+ * 5 cycles later, along with the assertion of
* dfi_rddata_valid.
*
* This PHY only supports CAS Latency 3.
* Command/address
*/
+reg [NUM_AD-1:0] r0_dfi_address_p0;
+reg [NUM_BA-1:0] r0_dfi_bank_p0;
+reg r0_dfi_cs_n_p0;
+reg r0_dfi_cke_p0;
+reg r0_dfi_ras_n_p0;
+reg r0_dfi_cas_n_p0;
+reg r0_dfi_we_n_p0;
+reg [NUM_AD-1:0] r0_dfi_address_p1;
+reg [NUM_BA-1:0] r0_dfi_bank_p1;
+reg r0_dfi_cs_n_p1;
+reg r0_dfi_cke_p1;
+reg r0_dfi_ras_n_p1;
+reg r0_dfi_cas_n_p1;
+reg r0_dfi_we_n_p1;
+
+always @(posedge sys_clk) begin
+ r0_dfi_address_p0 <= dfi_address_p0;
+ r0_dfi_bank_p0 <= dfi_bank_p0;
+ r0_dfi_cs_n_p0 <= dfi_cs_n_p0;
+ r0_dfi_cke_p0 <= dfi_cke_p0;
+ r0_dfi_ras_n_p0 <= dfi_ras_n_p0;
+ r0_dfi_cas_n_p0 <= dfi_cas_n_p0;
+ r0_dfi_we_n_p0 <= dfi_we_n_p0;
+
+ r0_dfi_address_p1 <= dfi_address_p1;
+ r0_dfi_bank_p1 <= dfi_bank_p1;
+ r0_dfi_cs_n_p1 <= dfi_cs_n_p1;
+ r0_dfi_cke_p1 <= dfi_cke_p1;
+ r0_dfi_ras_n_p1 <= dfi_ras_n_p1;
+ r0_dfi_cas_n_p1 <= dfi_cas_n_p1;
+ r0_dfi_we_n_p1 <= dfi_we_n_p1;
+end
+
reg phase_sel;
always @(posedge clk2x_270)
phase_sel <= sys_clk;
reg r_dfi_we_n_p1;
always @(posedge clk2x_270) begin
- r_dfi_address_p0 <= dfi_address_p0;
- r_dfi_bank_p0 <= dfi_bank_p0;
- r_dfi_cs_n_p0 <= dfi_cs_n_p0;
- r_dfi_cke_p0 <= dfi_cke_p0;
- r_dfi_ras_n_p0 <= dfi_ras_n_p0;
- r_dfi_cas_n_p0 <= dfi_cas_n_p0;
- r_dfi_we_n_p0 <= dfi_we_n_p0;
+ r_dfi_address_p0 <= r0_dfi_address_p0;
+ r_dfi_bank_p0 <= r0_dfi_bank_p0;
+ r_dfi_cs_n_p0 <= r0_dfi_cs_n_p0;
+ r_dfi_cke_p0 <= r0_dfi_cke_p0;
+ r_dfi_ras_n_p0 <= r0_dfi_ras_n_p0;
+ r_dfi_cas_n_p0 <= r0_dfi_cas_n_p0;
+ r_dfi_we_n_p0 <= r0_dfi_we_n_p0;
- r_dfi_address_p1 <= dfi_address_p1;
- r_dfi_bank_p1 <= dfi_bank_p1;
- r_dfi_cs_n_p1 <= dfi_cs_n_p1;
- r_dfi_cke_p1 <= dfi_cke_p1;
- r_dfi_ras_n_p1 <= dfi_ras_n_p1;
- r_dfi_cas_n_p1 <= dfi_cas_n_p1;
- r_dfi_we_n_p1 <= dfi_we_n_p1;
+ r_dfi_address_p1 <= r0_dfi_address_p1;
+ r_dfi_bank_p1 <= r0_dfi_bank_p1;
+ r_dfi_cs_n_p1 <= r0_dfi_cs_n_p1;
+ r_dfi_cke_p1 <= r0_dfi_cke_p1;
+ r_dfi_ras_n_p1 <= r0_dfi_ras_n_p1;
+ r_dfi_cas_n_p1 <= r0_dfi_cas_n_p1;
+ r_dfi_we_n_p1 <= r0_dfi_we_n_p1;
end
always @(posedge clk2x_270) begin
assign drive_dqs = r2_dfi_wrdata_en;
wire rddata_valid;
-reg [4:0] rddata_sr;
+reg [5:0] rddata_sr;
assign dfi_rddata_valid_w0 = rddata_sr[0];
assign dfi_rddata_valid_w1 = rddata_sr[0];
always @(posedge sys_clk)
- rddata_sr <= {dfi_rddata_en_p0, rddata_sr[4:1]};
+ rddata_sr <= {dfi_rddata_en_p0, rddata_sr[5:1]};
endmodule