Switch to LASMI, bug pandemonium
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Tue, 11 Jun 2013 12:18:16 +0000 (14:18 +0200)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Tue, 11 Jun 2013 12:18:16 +0000 (14:18 +0200)
18 files changed:
milkymist/asmicon/__init__.py [deleted file]
milkymist/asmicon/bankmachine.py [deleted file]
milkymist/asmicon/multiplexer.py [deleted file]
milkymist/asmicon/refresher.py [deleted file]
milkymist/asmiprobe/__init__.py [deleted file]
milkymist/dfii/__init__.py
milkymist/dvisampler/debug.py
milkymist/dvisampler/dma.py
milkymist/framebuffer/__init__.py
milkymist/lasmicon/__init__.py [new file with mode: 0644]
milkymist/lasmicon/bankmachine.py [new file with mode: 0644]
milkymist/lasmicon/multiplexer.py [new file with mode: 0644]
milkymist/lasmicon/refresher.py [new file with mode: 0644]
software/bios/main.c
software/bios/sdram.c
software/bios/sdram.h
top.py
verilog/s6ddrphy/s6ddrphy.v

diff --git a/milkymist/asmicon/__init__.py b/milkymist/asmicon/__init__.py
deleted file mode 100644 (file)
index 5ea25c1..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-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)
diff --git a/milkymist/asmicon/bankmachine.py b/milkymist/asmicon/bankmachine.py
deleted file mode 100644 (file)
index 361631d..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-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))
-               )
diff --git a/milkymist/asmicon/multiplexer.py b/milkymist/asmicon/multiplexer.py
deleted file mode 100644 (file)
index 9793c55..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-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)
diff --git a/milkymist/asmicon/refresher.py b/milkymist/asmicon/refresher.py
deleted file mode 100644 (file)
index cda7043..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-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))
-               )
diff --git a/milkymist/asmiprobe/__init__.py b/milkymist/asmiprobe/__init__.py
deleted file mode 100644 (file)
index ca9f985..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-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
index 22a5bcd5e905bcc8d9280d54df84796941e94610..c6fc834e943d4220756b702564b562a64cdb556a 100644 (file)
@@ -13,6 +13,7 @@ class PhaseInjector(Module, AutoCSR):
        
                ###
 
+               wrdata_en_adv = Signal()
                self.comb += [
                        If(self._command_issue.re,
                                phase.cs_n.eq(~self._command.storage[0]),
@@ -27,12 +28,15 @@ class PhaseInjector(Module, AutoCSR):
                        ),
                        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):
index 21d937ed87f536dbf060a030352e969b096fa8c9..52df4e6d95b3a82487c888a773428459972adba2 100644 (file)
@@ -2,7 +2,7 @@ from migen.fhdl.std import *
 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
@@ -35,7 +35,7 @@ class RawDVISampler(Module, AutoCSR):
                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),
index 1a361b17fed0b81cc347835a90ec5057e9afa179..48442bfe573dc1f8791ec8a1d950e149b163eda6 100644 (file)
@@ -3,7 +3,7 @@ from migen.genlib.fsm import FSM
 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
 
@@ -55,9 +55,9 @@ class _SlotArray(Module, AutoCSR):
                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)
@@ -112,7 +112,7 @@ class DMA(Module):
                        )
 
                # 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)
index 58ebfbc91d275a57d1f5bd67ef7bbfaf6fb24008..dff5817ae671fa58f33db49da2e7a19c8026836d 100644 (file)
@@ -2,18 +2,18 @@ from migen.fhdl.std import *
 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:
@@ -93,19 +93,19 @@ class Blender(PipelinedActor, AutoCSR):
                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)
diff --git a/milkymist/lasmicon/__init__.py b/milkymist/lasmicon/__init__.py
new file mode 100644 (file)
index 0000000..bdc4dc7
--- /dev/null
@@ -0,0 +1,64 @@
+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)
diff --git a/milkymist/lasmicon/bankmachine.py b/milkymist/lasmicon/bankmachine.py
new file mode 100644 (file)
index 0000000..ce0a2b3
--- /dev/null
@@ -0,0 +1,129 @@
+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))
+               )
diff --git a/milkymist/lasmicon/multiplexer.py b/milkymist/lasmicon/multiplexer.py
new file mode 100644 (file)
index 0000000..d1260b4
--- /dev/null
@@ -0,0 +1,184 @@
+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)
diff --git a/milkymist/lasmicon/refresher.py b/milkymist/lasmicon/refresher.py
new file mode 100644 (file)
index 0000000..190a93b
--- /dev/null
@@ -0,0 +1,68 @@
+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))
+               )
index 618217e74f1a2951372cd3d1cd27e291e54ce539..c3e9a9a49284e0c19f3dcc958174c0d2c6acc5fc 100644 (file)
@@ -367,7 +367,6 @@ static void do_command(char *c)
        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));
 
index 40196941728b4732487848c7d1cade4ce64d77f5..5604cc923737863ecbda5f0f7fd75f779ffaf968 100644 (file)
@@ -127,9 +127,9 @@ void ddrrd(char *startaddr)
        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");
 }
 
@@ -150,8 +150,8 @@ void ddrwr(char *startaddr)
        }
        
        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);
@@ -209,32 +209,3 @@ int ddrinit(void)
        
        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");
-}
index 807e2764d30edf9850dd07fe20c41f813cb476aa..e32df186416fd53e84c2aeb22c31a5076732b21e 100644 (file)
@@ -10,6 +10,4 @@ int memtest_silent(void);
 int memtest(void);
 int ddrinit(void);
 
-void asmiprobe(void);
-
 #endif /* __SDRAM_H */
diff --git a/top.py b/top.py
index fabfe62332efcce23b07e2016c8ccf117574dbbc..77a4ce9b50dac7971b120d5d91136a5527abce8c 100644 (file)
--- a/top.py
+++ b/top.py
@@ -3,11 +3,12 @@ from math import ceil
 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
 
@@ -23,26 +24,28 @@ def ns(t, margin=True):
                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
@@ -72,14 +75,13 @@ class SoC(Module):
                "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 = {
@@ -92,15 +94,11 @@ class SoC(Module):
 
        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
@@ -109,7 +107,7 @@ class SoC(Module):
                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
@@ -118,7 +116,7 @@ class SoC(Module):
                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)
@@ -135,7 +133,7 @@ class SoC(Module):
                                (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)
@@ -147,10 +145,9 @@ class SoC(Module):
                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])
index dc4a49b6ee3e9d0316ddd45cf5a14553f675dfa9..86001f14f68f4603546d0856536e75b0b3b835b2 100644 (file)
@@ -2,12 +2,12 @@
  * 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.
@@ -75,6 +75,39 @@ module s6ddrphy #(
  * 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;
@@ -95,21 +128,21 @@ reg r_dfi_cas_n_p1;
 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
@@ -334,10 +367,10 @@ end
 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