Minicon: small SDRAM controller
This commit is contained in:
parent
5202f89db1
commit
f33b285af1
|
@ -9,6 +9,7 @@ from migen.bus import wishbone, csr, lasmibus, dfi
|
||||||
from migen.bus import wishbone2lasmi, wishbone2csr
|
from migen.bus import wishbone2lasmi, wishbone2csr
|
||||||
|
|
||||||
from misoclib import lm32, mor1kx, uart, dfii, lasmicon, identifier, timer, memtest
|
from misoclib import lm32, mor1kx, uart, dfii, lasmicon, identifier, timer, memtest
|
||||||
|
from misoclib.lasmicon.minicon import Minicon
|
||||||
|
|
||||||
class GenSoC(Module):
|
class GenSoC(Module):
|
||||||
csr_base = 0xe0000000
|
csr_base = 0xe0000000
|
||||||
|
@ -141,9 +142,10 @@ class SDRAMSoC(GenSoC):
|
||||||
}
|
}
|
||||||
csr_map.update(GenSoC.csr_map)
|
csr_map.update(GenSoC.csr_map)
|
||||||
|
|
||||||
def __init__(self, platform, clk_freq, cpu_reset_address, with_memtest=False, sram_size=4096, l2_size=8192, with_uart=True, **kwargs):
|
def __init__(self, platform, clk_freq, cpu_reset_address, with_memtest=False, sram_size=4096, l2_size=8192, with_uart=True, ramcon_type="lasmicon", **kwargs):
|
||||||
GenSoC.__init__(self, platform, clk_freq, cpu_reset_address, sram_size, l2_size, with_uart, **kwargs)
|
GenSoC.__init__(self, platform, clk_freq, cpu_reset_address, sram_size, l2_size, with_uart, **kwargs)
|
||||||
self.with_memtest = with_memtest
|
self.with_memtest = with_memtest
|
||||||
|
self.ramcon_type = ramcon_type
|
||||||
self._sdram_phy_registered = False
|
self._sdram_phy_registered = False
|
||||||
|
|
||||||
def register_sdram_phy(self, phy_dfi, phy_settings, sdram_geom, sdram_timing):
|
def register_sdram_phy(self, phy_dfi, phy_settings, sdram_geom, sdram_timing):
|
||||||
|
@ -156,6 +158,7 @@ class SDRAMSoC(GenSoC):
|
||||||
phy_settings.dfi_d, phy_settings.nphases)
|
phy_settings.dfi_d, phy_settings.nphases)
|
||||||
self.submodules.dficon0 = dfi.Interconnect(self.dfii.master, phy_dfi)
|
self.submodules.dficon0 = dfi.Interconnect(self.dfii.master, phy_dfi)
|
||||||
|
|
||||||
|
if self.ramcon_type == "lasmicon":
|
||||||
# LASMI
|
# LASMI
|
||||||
self.submodules.lasmicon = lasmicon.LASMIcon(phy_settings, sdram_geom, sdram_timing)
|
self.submodules.lasmicon = lasmicon.LASMIcon(phy_settings, sdram_geom, sdram_timing)
|
||||||
self.submodules.dficon1 = dfi.Interconnect(self.lasmicon.dfi, self.dfii.slave)
|
self.submodules.dficon1 = dfi.Interconnect(self.lasmicon.dfi, self.dfii.slave)
|
||||||
|
@ -171,6 +174,26 @@ class SDRAMSoC(GenSoC):
|
||||||
self.add_wb_slave(lambda a: a[27:29] == 2, self.wishbone2lasmi.wishbone)
|
self.add_wb_slave(lambda a: a[27:29] == 2, self.wishbone2lasmi.wishbone)
|
||||||
self.add_cpu_memory_region("sdram", 0x40000000,
|
self.add_cpu_memory_region("sdram", 0x40000000,
|
||||||
2**self.lasmicon.lasmic.aw*self.lasmicon.lasmic.dw*self.lasmicon.lasmic.nbanks//8)
|
2**self.lasmicon.lasmic.aw*self.lasmicon.lasmic.dw*self.lasmicon.lasmic.nbanks//8)
|
||||||
|
elif self.ramcon_type == "minicon":
|
||||||
|
rdphase = phy_settings.rdphase
|
||||||
|
self.submodules.minicon = sdramcon = Minicon(phy_settings, sdram_geom, sdram_timing)
|
||||||
|
self.submodules.dficon1 = dfi.Interconnect(sdramcon.dfi, self.dfii.slave)
|
||||||
|
sdram_width = flen(sdramcon.bus.dat_r)
|
||||||
|
|
||||||
|
if (sdram_width == 32):
|
||||||
|
self.add_wb_slave(lambda a: a[27:29] == 2, sdramcon.bus)
|
||||||
|
elif (sdram_width < 32):
|
||||||
|
self.submodules.dc = dc = wishbone.DownConverter(32, sdram_width)
|
||||||
|
self.submodules.intercon = wishbone.InterconnectPointToPoint(dc.wishbone_o, sdramcon.bus)
|
||||||
|
self.add_wb_slave(lambda a: a[27:29] == 2, dc.wishbone_i)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError("Unsupported SDRAM width of {} > 32".format(sdram_width))
|
||||||
|
|
||||||
|
# map SDRAM at 0x40000000 (shadow @0xc0000000)
|
||||||
|
self.add_cpu_memory_region("sdram", 0x40000000,
|
||||||
|
2**(sdram_geom.bank_a+sdram_geom.row_a+sdram_geom.col_a)*sdram_width//8)
|
||||||
|
else:
|
||||||
|
raise ValueError("Unsupported SDRAM controller type: {}".format(self.ramcon_type))
|
||||||
|
|
||||||
def do_finalize(self):
|
def do_finalize(self):
|
||||||
if not self._sdram_phy_registered:
|
if not self._sdram_phy_registered:
|
||||||
|
|
|
@ -0,0 +1,203 @@
|
||||||
|
from migen.fhdl.std import *
|
||||||
|
from migen.bus import wishbone
|
||||||
|
from migen.bus import dfi as dfibus
|
||||||
|
from migen.genlib.fsm import FSM, NextState
|
||||||
|
|
||||||
|
class _AddressSlicer:
|
||||||
|
def __init__(self, col_a, bank_a, row_a, address_align):
|
||||||
|
self.col_a = col_a
|
||||||
|
self.bank_a = bank_a
|
||||||
|
self.row_a = row_a
|
||||||
|
self.max_a = col_a + row_a + bank_a
|
||||||
|
self.address_align = address_align
|
||||||
|
|
||||||
|
def row(self, address):
|
||||||
|
split = self.bank_a + self.col_a
|
||||||
|
if isinstance(address, int):
|
||||||
|
return address >> split
|
||||||
|
else:
|
||||||
|
return address[split:self.max_a]
|
||||||
|
|
||||||
|
def bank(self, address):
|
||||||
|
mask = 2**(self.bank_a + self.col_a) - 1
|
||||||
|
shift = self.col_a
|
||||||
|
if isinstance(address, int):
|
||||||
|
return (address & mask) >> shift
|
||||||
|
else:
|
||||||
|
return address[self.col_a:self.col_a+self.bank_a]
|
||||||
|
|
||||||
|
def col(self, address):
|
||||||
|
split = self.col_a
|
||||||
|
if isinstance(address, int):
|
||||||
|
return (address & (2**split - 1)) << self.address_align
|
||||||
|
else:
|
||||||
|
return Cat(Replicate(0, self.address_align), address[:split])
|
||||||
|
|
||||||
|
class Minicon(Module):
|
||||||
|
def __init__(self, phy_settings, geom_settings, timing_settings):
|
||||||
|
if phy_settings.memtype in ["SDR"]:
|
||||||
|
burst_length = phy_settings.nphases*1 # command multiplication*SDR
|
||||||
|
elif phy_settings.memtype in ["DDR", "LPDDR", "DDR2", "DDR3"]:
|
||||||
|
burst_length = phy_settings.nphases*2 # command multiplication*DDR
|
||||||
|
address_align = log2_int(burst_length)
|
||||||
|
|
||||||
|
nbanks = range(2**geom_settings.bank_a)
|
||||||
|
A10_ENABLED = 0
|
||||||
|
COLUMN = 1
|
||||||
|
ROW = 2
|
||||||
|
rdphase = phy_settings.rdphase
|
||||||
|
wrphase = phy_settings.wrphase
|
||||||
|
rdcmdphase = phy_settings.rdcmdphase
|
||||||
|
wrcmdphase = phy_settings.wrcmdphase
|
||||||
|
|
||||||
|
self.dfi = dfi = dfibus.Interface(geom_settings.mux_a,
|
||||||
|
geom_settings.bank_a,
|
||||||
|
phy_settings.dfi_d,
|
||||||
|
phy_settings.nphases)
|
||||||
|
|
||||||
|
self.bus = bus = wishbone.Interface(data_width=phy_settings.nphases*flen(dfi.phases[rdphase].rddata))
|
||||||
|
slicer = _AddressSlicer(geom_settings.col_a, geom_settings.bank_a, geom_settings.row_a, address_align)
|
||||||
|
req_addr = Signal(geom_settings.col_a + geom_settings.bank_a + geom_settings.row_a)
|
||||||
|
refresh_req = Signal()
|
||||||
|
refresh_ack = Signal()
|
||||||
|
wb_access = Signal()
|
||||||
|
refresh_counter = Signal(max=timing_settings.tREFI+1)
|
||||||
|
hit = Signal()
|
||||||
|
row_open = Signal()
|
||||||
|
row_closeall = Signal()
|
||||||
|
addr_sel = Signal(max=3, reset=A10_ENABLED)
|
||||||
|
has_curbank_openrow = Signal()
|
||||||
|
cl_counter = Signal(max=phy_settings.cl+1)
|
||||||
|
|
||||||
|
# Extra bit means row is active when asserted
|
||||||
|
self.openrow = openrow = Array(Signal(geom_settings.row_a + 1) for b in nbanks)
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
hit.eq(openrow[slicer.bank(bus.adr)] == Cat(slicer.row(bus.adr), 1)),
|
||||||
|
has_curbank_openrow.eq(openrow[slicer.bank(bus.adr)][-1]),
|
||||||
|
wb_access.eq(bus.stb & bus.cyc),
|
||||||
|
bus.dat_r.eq(Cat([phase.rddata for phase in dfi.phases])),
|
||||||
|
Cat([phase.wrdata for phase in dfi.phases]).eq(bus.dat_w),
|
||||||
|
Cat([phase.wrdata_mask for phase in dfi.phases]).eq(~bus.sel),
|
||||||
|
]
|
||||||
|
|
||||||
|
for phase in dfi.phases:
|
||||||
|
self.comb += [
|
||||||
|
phase.cke.eq(1),
|
||||||
|
phase.address.eq(Array([2**10, slicer.col(bus.adr), slicer.row(bus.adr)])[addr_sel]),
|
||||||
|
If(wb_access,
|
||||||
|
phase.bank.eq(slicer.bank(bus.adr))
|
||||||
|
)
|
||||||
|
]
|
||||||
|
phase.cs_n.reset = 0
|
||||||
|
phase.ras_n.reset = 1
|
||||||
|
phase.cas_n.reset = 1
|
||||||
|
phase.we_n.reset = 1
|
||||||
|
|
||||||
|
for b in nbanks:
|
||||||
|
self.sync += [
|
||||||
|
If(row_open & (b == slicer.bank(bus.adr)),
|
||||||
|
openrow[b].eq(Cat(slicer.row(bus.adr), 1)),
|
||||||
|
),
|
||||||
|
If(row_closeall,
|
||||||
|
openrow[b][-1].eq(0)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
self.sync += [
|
||||||
|
If(refresh_ack,
|
||||||
|
refresh_req.eq(0)
|
||||||
|
),
|
||||||
|
If(refresh_counter == 0,
|
||||||
|
refresh_counter.eq(timing_settings.tREFI),
|
||||||
|
refresh_req.eq(1)
|
||||||
|
).Else(
|
||||||
|
refresh_counter.eq(refresh_counter - 1)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
fsm = FSM()
|
||||||
|
self.submodules += fsm
|
||||||
|
fsm.act("IDLE",
|
||||||
|
If(refresh_req,
|
||||||
|
NextState("PRECHARGEALL")
|
||||||
|
).Elif(wb_access,
|
||||||
|
If(hit & bus.we,
|
||||||
|
NextState("WRITE"),
|
||||||
|
),
|
||||||
|
If(hit & ~bus.we,
|
||||||
|
NextState("READ"),
|
||||||
|
),
|
||||||
|
If(has_curbank_openrow & ~hit,
|
||||||
|
NextState("PRECHARGE")
|
||||||
|
),
|
||||||
|
If(~has_curbank_openrow,
|
||||||
|
NextState("ACTIVATE")
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
fsm.act("READ",
|
||||||
|
# We output Column bits at address pins so that A10 is 0
|
||||||
|
# to disable row Auto-Precharge
|
||||||
|
dfi.phases[rdcmdphase].ras_n.eq(1),
|
||||||
|
dfi.phases[rdcmdphase].cas_n.eq(0),
|
||||||
|
dfi.phases[rdcmdphase].we_n.eq(1),
|
||||||
|
dfi.phases[rdphase].rddata_en.eq(1),
|
||||||
|
addr_sel.eq(COLUMN),
|
||||||
|
NextState("READ-WAIT-ACK"),
|
||||||
|
)
|
||||||
|
fsm.act("READ-WAIT-ACK",
|
||||||
|
If(dfi.phases[rdphase].rddata_valid,
|
||||||
|
NextState("IDLE"),
|
||||||
|
bus.ack.eq(1)
|
||||||
|
).Else(
|
||||||
|
NextState("READ-WAIT-ACK")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
fsm.act("WRITE",
|
||||||
|
dfi.phases[wrcmdphase].ras_n.eq(1),
|
||||||
|
dfi.phases[wrcmdphase].cas_n.eq(0),
|
||||||
|
dfi.phases[wrcmdphase].we_n.eq(0),
|
||||||
|
dfi.phases[wrphase].wrdata_en.eq(1),
|
||||||
|
addr_sel.eq(COLUMN),
|
||||||
|
bus.ack.eq(1),
|
||||||
|
NextState("IDLE")
|
||||||
|
)
|
||||||
|
fsm.act("PRECHARGEALL",
|
||||||
|
row_closeall.eq(1),
|
||||||
|
dfi.phases[rdphase].ras_n.eq(0),
|
||||||
|
dfi.phases[rdphase].cas_n.eq(1),
|
||||||
|
dfi.phases[rdphase].we_n.eq(0),
|
||||||
|
addr_sel.eq(A10_ENABLED),
|
||||||
|
NextState("PRE-REFRESH")
|
||||||
|
)
|
||||||
|
fsm.act("PRECHARGE",
|
||||||
|
# Notes:
|
||||||
|
# 1. we are presenting the column address so that A10 is low
|
||||||
|
# 2. since we always go to the ACTIVATE state, we do not need
|
||||||
|
# to assert row_close because it will be reopen right after.
|
||||||
|
NextState("TRP"),
|
||||||
|
addr_sel.eq(COLUMN),
|
||||||
|
dfi.phases[rdphase].ras_n.eq(0),
|
||||||
|
dfi.phases[rdphase].cas_n.eq(1),
|
||||||
|
dfi.phases[rdphase].we_n.eq(0)
|
||||||
|
)
|
||||||
|
fsm.act("ACTIVATE",
|
||||||
|
row_open.eq(1),
|
||||||
|
NextState("TRCD"),
|
||||||
|
dfi.phases[rdphase].ras_n.eq(0),
|
||||||
|
dfi.phases[rdphase].cas_n.eq(1),
|
||||||
|
dfi.phases[rdphase].we_n.eq(1),
|
||||||
|
addr_sel.eq(ROW)
|
||||||
|
)
|
||||||
|
fsm.act("REFRESH",
|
||||||
|
refresh_ack.eq(1),
|
||||||
|
dfi.phases[rdphase].ras_n.eq(0),
|
||||||
|
dfi.phases[rdphase].cas_n.eq(0),
|
||||||
|
dfi.phases[rdphase].we_n.eq(1),
|
||||||
|
NextState("POST-REFRESH")
|
||||||
|
)
|
||||||
|
fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP-1)
|
||||||
|
fsm.delayed_enter("PRE-REFRESH", "REFRESH", timing_settings.tRP-1)
|
||||||
|
fsm.delayed_enter("TRCD", "IDLE", timing_settings.tRCD-1)
|
||||||
|
fsm.delayed_enter("POST-REFRESH", "IDLE", timing_settings.tRFC-1)
|
|
@ -0,0 +1,192 @@
|
||||||
|
from migen.fhdl.std import *
|
||||||
|
from migen.bus.transactions import TRead, TWrite
|
||||||
|
from migen.bus import wishbone
|
||||||
|
from migen.sim.generic import Simulator
|
||||||
|
from migen.sim import icarus
|
||||||
|
from mibuild.platforms import papilio_pro as board
|
||||||
|
from misoclib import lasmicon
|
||||||
|
from misoclib.lasmicon.minicon import Minicon
|
||||||
|
from misoclib.sdramphy import gensdrphy
|
||||||
|
from itertools import chain
|
||||||
|
from os.path import isfile
|
||||||
|
import sys
|
||||||
|
|
||||||
|
clk_freq = 80000000
|
||||||
|
|
||||||
|
from math import ceil
|
||||||
|
|
||||||
|
def ns(t, margin=True):
|
||||||
|
clk_period_ns = 1000000000/clk_freq
|
||||||
|
if margin:
|
||||||
|
t += clk_period_ns/2
|
||||||
|
return ceil(t/clk_period_ns)
|
||||||
|
|
||||||
|
class MiniconTB(Module):
|
||||||
|
def __init__(self, sdrphy, dfi, sdram_geom, sdram_timing, pads, sdram_clk):
|
||||||
|
|
||||||
|
self.clk_freq = 80000000
|
||||||
|
phy_settings = sdrphy.phy_settings
|
||||||
|
rdphase = phy_settings.rdphase
|
||||||
|
self.submodules.slave = Minicon(phy_settings, sdram_geom, sdram_timing)
|
||||||
|
|
||||||
|
self.submodules.tap = wishbone.Tap(self.slave.bus)
|
||||||
|
self.submodules.dc = dc = wishbone.DownConverter(32, phy_settings.nphases*flen(dfi.phases[rdphase].rddata))
|
||||||
|
self.submodules.master = wishbone.Initiator(self.genxfers(), bus=dc.wishbone_i)
|
||||||
|
self.submodules.intercon = wishbone.InterconnectPointToPoint(dc.wishbone_o, self.slave.bus)
|
||||||
|
|
||||||
|
self.submodules.sdrphy = self.sdrphy = sdrphy
|
||||||
|
self.dfi = dfi
|
||||||
|
self.pads = pads
|
||||||
|
|
||||||
|
self.specials += Instance("mt48lc4m16a2",
|
||||||
|
io_Dq=pads.dq,
|
||||||
|
i_Addr=pads.a,
|
||||||
|
i_Ba=pads.ba,
|
||||||
|
i_Clk=ClockSignal(),
|
||||||
|
i_Cke=pads.cke,
|
||||||
|
i_Cs_n=pads.cs_n,
|
||||||
|
i_Ras_n=pads.ras_n,
|
||||||
|
i_Cas_n=pads.cas_n,
|
||||||
|
i_We_n=pads.we_n,
|
||||||
|
i_Dqm=pads.dm
|
||||||
|
)
|
||||||
|
|
||||||
|
def genxfers(self):
|
||||||
|
cycle = 0
|
||||||
|
for a in chain(range(4),range(256,260),range(1024,1028)):
|
||||||
|
t = TRead(a)
|
||||||
|
yield t
|
||||||
|
print("read {} in {} cycles".format(t.data, t.latency))
|
||||||
|
for a in chain(range(4),range(256,260),range(1024,1028),range(4096,4100)):
|
||||||
|
t = TWrite(a, 0xaa55aa55+cycle)
|
||||||
|
cycle += 1
|
||||||
|
yield t
|
||||||
|
print("read {} in {} cycles".format(t.data, t.latency))
|
||||||
|
for a in chain(range(4),range(256,260),range(1024,1028),range(4096,4100)):
|
||||||
|
t = TRead(a)
|
||||||
|
yield t
|
||||||
|
print("read {} in {} cycles".format(t.data, t.latency))
|
||||||
|
|
||||||
|
def gen_simulation(self, selfp):
|
||||||
|
dfi = selfp.dfi
|
||||||
|
phy = self.sdrphy
|
||||||
|
rdphase = phy.phy_settings.rdphase
|
||||||
|
cycle = 0
|
||||||
|
|
||||||
|
while True:
|
||||||
|
yield
|
||||||
|
|
||||||
|
class MyTopLevel:
|
||||||
|
def __init__(self, vcd_name=None, vcd_level=1,
|
||||||
|
top_name="top", dut_type="dut", dut_name="dut",
|
||||||
|
cd_name="sys", clk_period=10):
|
||||||
|
self.vcd_name = vcd_name
|
||||||
|
self.vcd_level = vcd_level
|
||||||
|
self.top_name = top_name
|
||||||
|
self.dut_type = dut_type
|
||||||
|
self.dut_name = dut_name
|
||||||
|
|
||||||
|
self._cd_name = cd_name
|
||||||
|
self._clk_period = clk_period
|
||||||
|
|
||||||
|
cd = ClockDomain(self._cd_name)
|
||||||
|
cd_ps = ClockDomain("sys_ps")
|
||||||
|
self.clock_domains = [cd, cd_ps]
|
||||||
|
self.ios = {cd.clk, cd.rst, cd_ps.clk}
|
||||||
|
|
||||||
|
def get(self, sockaddr):
|
||||||
|
template1 = """`timescale 1ns / 1ps
|
||||||
|
|
||||||
|
module {top_name}();
|
||||||
|
|
||||||
|
reg {clk_name};
|
||||||
|
reg {rst_name};
|
||||||
|
reg sys_ps_clk;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
{rst_name} <= 1'b1;
|
||||||
|
@(posedge {clk_name});
|
||||||
|
{rst_name} <= 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
always begin
|
||||||
|
{clk_name} <= 1'b0;
|
||||||
|
#{hclk_period};
|
||||||
|
{clk_name} <= 1'b1;
|
||||||
|
#{hclk_period};
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge {clk_name} or negedge {clk_name})
|
||||||
|
sys_ps_clk <= #({hclk_period}*2-3) {clk_name};
|
||||||
|
|
||||||
|
{dut_type} {dut_name}(
|
||||||
|
.{rst_name}({rst_name}),
|
||||||
|
.{clk_name}({clk_name}),
|
||||||
|
.sys_ps_clk(sys_ps_clk)
|
||||||
|
);
|
||||||
|
|
||||||
|
initial $migensim_connect("{sockaddr}");
|
||||||
|
always @(posedge {clk_name}) $migensim_tick;
|
||||||
|
"""
|
||||||
|
template2 = """
|
||||||
|
initial begin
|
||||||
|
$dumpfile("{vcd_name}");
|
||||||
|
$dumpvars({vcd_level}, {dut_name});
|
||||||
|
end
|
||||||
|
"""
|
||||||
|
r = template1.format(top_name=self.top_name,
|
||||||
|
dut_type=self.dut_type,
|
||||||
|
dut_name=self.dut_name,
|
||||||
|
clk_name=self._cd_name + "_clk",
|
||||||
|
rst_name=self._cd_name + "_rst",
|
||||||
|
hclk_period=str(self._clk_period/2),
|
||||||
|
sockaddr=sockaddr)
|
||||||
|
if self.vcd_name is not None:
|
||||||
|
r += template2.format(vcd_name=self.vcd_name,
|
||||||
|
vcd_level=str(self.vcd_level),
|
||||||
|
dut_name=self.dut_name)
|
||||||
|
r += "\nendmodule"
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
plat = board.Platform()
|
||||||
|
|
||||||
|
sdram_geom = lasmicon.GeomSettings(
|
||||||
|
bank_a=2,
|
||||||
|
row_a=12,
|
||||||
|
col_a=8
|
||||||
|
)
|
||||||
|
|
||||||
|
sdram_timing = lasmicon.TimingSettings(
|
||||||
|
tRP=ns(15),
|
||||||
|
tRCD=ns(15),
|
||||||
|
tWR=ns(14),
|
||||||
|
tWTR=2,
|
||||||
|
tREFI=ns(64*1000*1000/4096, False),
|
||||||
|
tRFC=ns(66),
|
||||||
|
req_queue_size=8,
|
||||||
|
read_time=32,
|
||||||
|
write_time=16
|
||||||
|
)
|
||||||
|
|
||||||
|
sdram_pads = plat.request("sdram")
|
||||||
|
sdram_clk = plat.request("sdram_clock")
|
||||||
|
|
||||||
|
sdrphy = gensdrphy.GENSDRPHY(sdram_pads)
|
||||||
|
|
||||||
|
# This sets CL to 2 during LMR done on 1st cycle
|
||||||
|
sdram_pads.a.reset = 1<<5
|
||||||
|
|
||||||
|
s = MiniconTB(sdrphy, sdrphy.dfi, sdram_geom, sdram_timing, pads=sdram_pads, sdram_clk=sdram_clk)
|
||||||
|
|
||||||
|
extra_files = [ "sdram_model/mt48lc4m16a2.v" ]
|
||||||
|
|
||||||
|
if not isfile(extra_files[0]):
|
||||||
|
print("ERROR: You need to download Micron Verilog simulation model for MT48LC4M16A2 and put it in sdram_model/mt48lc4m16a2.v")
|
||||||
|
print("File can be downloaded from this URL: http://www.micron.com/-/media/documents/products/sim%20model/dram/dram/4054mt48lc4m16a2.zip")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with Simulator(s, MyTopLevel("top.vcd", clk_period=int(1/0.08)), icarus.Runner(extra_files=extra_files, keep_files=True)) as sim:
|
||||||
|
sim.run(5000)
|
Loading…
Reference in New Issue