From 91d7b656a9be99e0e7d3812f915f41af74c76440 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Jun 2013 14:18:16 +0200 Subject: [PATCH] Switch to LASMI, bug pandemonium --- milkymist/asmicon/__init__.py | 62 ---- milkymist/asmicon/bankmachine.py | 273 ------------------ milkymist/asmiprobe/__init__.py | 28 -- milkymist/dfii/__init__.py | 8 +- milkymist/dvisampler/debug.py | 4 +- milkymist/dvisampler/dma.py | 10 +- milkymist/framebuffer/__init__.py | 22 +- milkymist/lasmicon/__init__.py | 64 ++++ milkymist/lasmicon/bankmachine.py | 129 +++++++++ .../{asmicon => lasmicon}/multiplexer.py | 81 ++---- milkymist/{asmicon => lasmicon}/refresher.py | 2 +- software/bios/main.c | 1 - software/bios/sdram.c | 37 +-- software/bios/sdram.h | 2 - top.py | 57 ++-- verilog/s6ddrphy/s6ddrphy.v | 71 +++-- 16 files changed, 321 insertions(+), 530 deletions(-) delete mode 100644 milkymist/asmicon/__init__.py delete mode 100644 milkymist/asmicon/bankmachine.py delete mode 100644 milkymist/asmiprobe/__init__.py create mode 100644 milkymist/lasmicon/__init__.py create mode 100644 milkymist/lasmicon/bankmachine.py rename milkymist/{asmicon => lasmicon}/multiplexer.py (76%) rename milkymist/{asmicon => lasmicon}/refresher.py (96%) diff --git a/milkymist/asmicon/__init__.py b/milkymist/asmicon/__init__.py deleted file mode 100644 index 5ea25c11..00000000 --- a/milkymist/asmicon/__init__.py +++ /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 index 361631de..00000000 --- a/milkymist/asmicon/bankmachine.py +++ /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/asmiprobe/__init__.py b/milkymist/asmiprobe/__init__.py deleted file mode 100644 index ca9f9851..00000000 --- a/milkymist/asmiprobe/__init__.py +++ /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 diff --git a/milkymist/dfii/__init__.py b/milkymist/dfii/__init__.py index 22a5bcd5..c6fc834e 100644 --- a/milkymist/dfii/__init__.py +++ b/milkymist/dfii/__init__.py @@ -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): diff --git a/milkymist/dvisampler/debug.py b/milkymist/dvisampler/debug.py index 21d937ed..52df4e6d 100644 --- a/milkymist/dvisampler/debug.py +++ b/milkymist/dvisampler/debug.py @@ -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), diff --git a/milkymist/dvisampler/dma.py b/milkymist/dvisampler/dma.py index 1a361b17..48442bfe 100644 --- a/milkymist/dvisampler/dma.py +++ b/milkymist/dvisampler/dma.py @@ -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) diff --git a/milkymist/framebuffer/__init__.py b/milkymist/framebuffer/__init__.py index 58ebfbc9..dff5817a 100644 --- a/milkymist/framebuffer/__init__.py +++ b/milkymist/framebuffer/__init__.py @@ -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 index 00000000..bdc4dc74 --- /dev/null +++ b/milkymist/lasmicon/__init__.py @@ -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 index 00000000..ce0a2b3b --- /dev/null +++ b/milkymist/lasmicon/bankmachine.py @@ -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/asmicon/multiplexer.py b/milkymist/lasmicon/multiplexer.py similarity index 76% rename from milkymist/asmicon/multiplexer.py rename to milkymist/lasmicon/multiplexer.py index 9793c551..d1260b40 100644 --- a/milkymist/asmicon/multiplexer.py +++ b/milkymist/lasmicon/multiplexer.py @@ -12,20 +12,19 @@ class CommandRequest: self.we_n = Signal(reset=1) class CommandRequestRW(CommandRequest): - def __init__(self, a, ba, tagbits): + def __init__(self, a, ba): 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): + 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), tagbits) + self.cmd = CommandRequestRW(flen(requests[0].a), flen(requests[0].ba)) ### @@ -37,7 +36,7 @@ class _CommandChooser(Module): 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"]: + 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"]: @@ -66,6 +65,7 @@ class _Steerer(Module): 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) @@ -77,67 +77,20 @@ class _Steerer(Module): 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]) + wrdata_en_adv.eq(Array(stb_and(cmd, "is_write") for cmd in commands)[sel]), + phase.wrdata_en.eq(wrdata_en_adv) ] -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): + 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] - tagbits = flen(hub.tag_call) - choose_cmd = _CommandChooser(requests, tagbits) - choose_req = _CommandChooser(requests, tagbits) + choose_cmd = _CommandChooser(requests) + choose_req = _CommandChooser(requests) self.comb += [ choose_cmd.want_reads.eq(0), choose_cmd.want_writes.eq(0) @@ -183,13 +136,19 @@ class Multiplexer(Module): 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 + 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.rd_delay), - ("WTR", "READ", timing_settings.tWR) + ("RTW", "WRITE", timing_settings.read_latency), + ("WTR", "READ", timing_settings.tWTR) ]) self.submodules += fsm fsm.act(fsm.READ, diff --git a/milkymist/asmicon/refresher.py b/milkymist/lasmicon/refresher.py similarity index 96% rename from milkymist/asmicon/refresher.py rename to milkymist/lasmicon/refresher.py index cda70433..190a93b3 100644 --- a/milkymist/asmicon/refresher.py +++ b/milkymist/lasmicon/refresher.py @@ -2,7 +2,7 @@ from migen.fhdl.std import * from migen.genlib.misc import timeline from migen.genlib.fsm import FSM -from milkymist.asmicon.multiplexer import * +from milkymist.lasmicon.multiplexer import * class Refresher(Module): def __init__(self, a, ba, tRP, tREFI, tRFC): diff --git a/software/bios/main.c b/software/bios/main.c index 618217e7..c3e9a9a4 100644 --- a/software/bios/main.c +++ b/software/bios/main.c @@ -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)); diff --git a/software/bios/sdram.c b/software/bios/sdram.c index 40196941..5604cc92 100644 --- a/software/bios/sdram.c +++ b/software/bios/sdram.c @@ -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