mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
Switch to LASMI, bug pandemonium
This commit is contained in:
parent
6f2c05d436
commit
91d7b656a9
16 changed files with 321 additions and 530 deletions
|
@ -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)
|
|
@ -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))
|
||||
)
|
|
@ -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
|
|
@ -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):
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
64
milkymist/lasmicon/__init__.py
Normal file
64
milkymist/lasmicon/__init__.py
Normal file
|
@ -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)
|
129
milkymist/lasmicon/bankmachine.py
Normal file
129
milkymist/lasmicon/bankmachine.py
Normal file
|
@ -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))
|
||||
)
|
|
@ -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])
|
||||
]
|
||||
|
||||
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)
|
||||
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, 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,
|
|
@ -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):
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -10,6 +10,4 @@ int memtest_silent(void);
|
|||
int memtest(void);
|
||||
int ddrinit(void);
|
||||
|
||||
void asmiprobe(void);
|
||||
|
||||
#endif /* __SDRAM_H */
|
||||
|
|
57
top.py
57
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])
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue