core: use a single structure to pass settings / simplify
This commit is contained in:
parent
7ce42d5324
commit
8c0e732c24
|
@ -59,16 +59,14 @@ def data_layout(dw):
|
||||||
|
|
||||||
|
|
||||||
class InternalInterface(Record):
|
class InternalInterface(Record):
|
||||||
def __init__(self, aw, dw, nbanks, cmd_buffer_depth, read_latency, write_latency):
|
def __init__(self, address_align, settings):
|
||||||
self.aw = aw
|
self.aw = settings.geom.rowbits + settings.geom.colbits - address_align
|
||||||
self.dw = dw
|
self.dw = settings.phy.dfi_databits*settings.phy.nphases
|
||||||
self.nbanks = nbanks
|
self.nbanks = 2**settings.geom.bankbits
|
||||||
self.cmd_buffer_depth = cmd_buffer_depth
|
self.settings = settings
|
||||||
self.read_latency = read_latency
|
|
||||||
self.write_latency = write_latency
|
|
||||||
|
|
||||||
layout = [("bank"+str(i), cmd_layout(aw)) for i in range(nbanks)]
|
layout = [("bank"+str(i), cmd_layout(self.aw)) for i in range(self.nbanks)]
|
||||||
layout += data_layout(dw)
|
layout += data_layout(self.dw)
|
||||||
Record.__init__(self, layout)
|
Record.__init__(self, layout)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,28 +28,26 @@ class AddressSlicer:
|
||||||
|
|
||||||
class BankMachine(Module):
|
class BankMachine(Module):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
aw,
|
|
||||||
n,
|
n,
|
||||||
|
aw,
|
||||||
address_align,
|
address_align,
|
||||||
geom_settings,
|
settings):
|
||||||
timing_settings,
|
|
||||||
controller_settings):
|
|
||||||
self.req = req = Record(cmd_layout(aw))
|
self.req = req = Record(cmd_layout(aw))
|
||||||
self.refresh_req = Signal()
|
self.refresh_req = Signal()
|
||||||
self.refresh_gnt = Signal()
|
self.refresh_gnt = Signal()
|
||||||
a = geom_settings.addressbits
|
a = settings.geom.addressbits
|
||||||
ba = geom_settings.bankbits
|
ba = settings.geom.bankbits
|
||||||
self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(a, ba))
|
self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(a, ba))
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
# Command buffer
|
# Command buffer
|
||||||
cmd_buffer_layout = [("we", 1), ("adr", len(req.adr))]
|
cmd_buffer_layout = [("we", 1), ("adr", len(req.adr))]
|
||||||
if controller_settings.cmd_buffer_depth < 2:
|
if settings.cmd_buffer_depth < 2:
|
||||||
cmd_buffer = stream.Buffer(cmd_buffer_layout)
|
cmd_buffer = stream.Buffer(cmd_buffer_layout)
|
||||||
else:
|
else:
|
||||||
cmd_buffer = stream.SyncFIFO(cmd_buffer_layout,
|
cmd_buffer = stream.SyncFIFO(cmd_buffer_layout,
|
||||||
controller_settings.cmd_buffer_depth)
|
settings.cmd_buffer_depth)
|
||||||
self.submodules += cmd_buffer
|
self.submodules += cmd_buffer
|
||||||
self.comb += [
|
self.comb += [
|
||||||
req.connect(cmd_buffer.sink, omit=["dat_w_ack", "dat_r_ack", "lock"]),
|
req.connect(cmd_buffer.sink, omit=["dat_w_ack", "dat_r_ack", "lock"]),
|
||||||
|
@ -57,11 +55,11 @@ class BankMachine(Module):
|
||||||
req.lock.eq(cmd_buffer.source.valid),
|
req.lock.eq(cmd_buffer.source.valid),
|
||||||
]
|
]
|
||||||
|
|
||||||
slicer = AddressSlicer(geom_settings.colbits, address_align)
|
slicer = AddressSlicer(settings.geom.colbits, address_align)
|
||||||
|
|
||||||
# Row tracking
|
# Row tracking
|
||||||
has_openrow = Signal()
|
has_openrow = Signal()
|
||||||
openrow = Signal(geom_settings.rowbits)
|
openrow = Signal(settings.geom.rowbits)
|
||||||
hit = Signal()
|
hit = Signal()
|
||||||
self.comb += hit.eq(openrow == slicer.row(cmd_buffer.source.adr))
|
self.comb += hit.eq(openrow == slicer.row(cmd_buffer.source.adr))
|
||||||
track_open = Signal()
|
track_open = Signal()
|
||||||
|
@ -86,7 +84,7 @@ class BankMachine(Module):
|
||||||
]
|
]
|
||||||
|
|
||||||
# Respect write-to-precharge specification
|
# Respect write-to-precharge specification
|
||||||
precharge_time = 2 + timing_settings.tWR - 1 + 1
|
precharge_time = 2 + settings.timing.tWR - 1 + 1
|
||||||
self.submodules.precharge_timer = WaitTimer(precharge_time)
|
self.submodules.precharge_timer = WaitTimer(precharge_time)
|
||||||
self.comb += self.precharge_timer.wait.eq(~(cmd.valid &
|
self.comb += self.precharge_timer.wait.eq(~(cmd.valid &
|
||||||
cmd.ready &
|
cmd.ready &
|
||||||
|
@ -153,5 +151,5 @@ class BankMachine(Module):
|
||||||
NextState("REGULAR")
|
NextState("REGULAR")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP-1)
|
fsm.delayed_enter("TRP", "ACTIVATE", settings.timing.tRP-1)
|
||||||
fsm.delayed_enter("TRCD", "REGULAR", timing_settings.tRCD-1)
|
fsm.delayed_enter("TRCD", "REGULAR", settings.timing.tRCD-1)
|
||||||
|
|
|
@ -34,40 +34,29 @@ class LiteDRAMController(Module):
|
||||||
phy_settings.dfi_databits,
|
phy_settings.dfi_databits,
|
||||||
phy_settings.nphases)
|
phy_settings.nphases)
|
||||||
|
|
||||||
self.lasmic = common.InternalInterface(
|
self.settings = settings = controller_settings
|
||||||
aw=geom_settings.rowbits + geom_settings.colbits - address_align,
|
self.settings.phy = phy_settings
|
||||||
dw=phy_settings.dfi_databits*phy_settings.nphases,
|
self.settings.geom = geom_settings
|
||||||
nbanks=2**geom_settings.bankbits,
|
self.settings.timing = timing_settings
|
||||||
cmd_buffer_depth=controller_settings.cmd_buffer_depth,
|
|
||||||
read_latency=phy_settings.read_latency+1,
|
self.lasmic = common.InternalInterface(address_align, settings)
|
||||||
write_latency=phy_settings.write_latency+1)
|
self.nrowbits = settings.geom.colbits - address_align
|
||||||
self.nrowbits = geom_settings.colbits - address_align
|
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
self.submodules.refresher = Refresher(geom_settings.addressbits,
|
self.submodules.refresher = Refresher(self.settings)
|
||||||
geom_settings.bankbits,
|
|
||||||
timing_settings.tRP,
|
|
||||||
timing_settings.tREFI,
|
|
||||||
timing_settings.tRFC,
|
|
||||||
controller_settings.with_refresh)
|
|
||||||
|
|
||||||
bank_machines = []
|
bank_machines = []
|
||||||
for i in range(2**geom_settings.bankbits):
|
for i in range(2**geom_settings.bankbits):
|
||||||
bank_machine = BankMachine(self.lasmic.aw,
|
bank_machine = BankMachine(i,
|
||||||
i,
|
self.lasmic.aw,
|
||||||
address_align,
|
address_align,
|
||||||
geom_settings,
|
settings)
|
||||||
timing_settings,
|
|
||||||
controller_settings)
|
|
||||||
bank_machines.append(bank_machine)
|
bank_machines.append(bank_machine)
|
||||||
self.submodules += bank_machine
|
self.submodules += bank_machine
|
||||||
self.comb += getattr(self.lasmic, "bank"+str(i)).connect(bank_machine.req)
|
self.comb += getattr(self.lasmic, "bank"+str(i)).connect(bank_machine.req)
|
||||||
|
|
||||||
self.submodules.multiplexer = Multiplexer(phy_settings,
|
self.submodules.multiplexer = Multiplexer(settings,
|
||||||
geom_settings,
|
|
||||||
timing_settings,
|
|
||||||
controller_settings,
|
|
||||||
bank_machines,
|
bank_machines,
|
||||||
self.refresher,
|
self.refresher,
|
||||||
self.dfi,
|
self.dfi,
|
||||||
|
|
|
@ -102,31 +102,27 @@ class _Steerer(Module):
|
||||||
|
|
||||||
class Multiplexer(Module, AutoCSR):
|
class Multiplexer(Module, AutoCSR):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
phy_settings,
|
settings,
|
||||||
geom_settings,
|
|
||||||
timing_settings,
|
|
||||||
controller_settings,
|
|
||||||
bank_machines,
|
bank_machines,
|
||||||
refresher,
|
refresher,
|
||||||
dfi,
|
dfi,
|
||||||
lasmic,
|
lasmic,
|
||||||
with_bandwidth=False):
|
with_bandwidth=False):
|
||||||
assert(phy_settings.nphases == len(dfi.phases))
|
assert(settings.phy.nphases == len(dfi.phases))
|
||||||
self.phy_settings = phy_settings
|
|
||||||
|
|
||||||
# Command choosing
|
# Command choosing
|
||||||
requests = [bm.cmd for bm in bank_machines]
|
requests = [bm.cmd for bm in bank_machines]
|
||||||
self.submodules.choose_cmd = choose_cmd = _CommandChooser(requests)
|
self.submodules.choose_cmd = choose_cmd = _CommandChooser(requests)
|
||||||
self.submodules.choose_req = choose_req = _CommandChooser(requests)
|
self.submodules.choose_req = choose_req = _CommandChooser(requests)
|
||||||
if phy_settings.nphases == 1:
|
if settings.phy.nphases == 1:
|
||||||
self.comb += [
|
self.comb += [
|
||||||
choose_cmd.want_cmds.eq(1),
|
choose_cmd.want_cmds.eq(1),
|
||||||
choose_req.want_cmds.eq(1)
|
choose_req.want_cmds.eq(1)
|
||||||
]
|
]
|
||||||
|
|
||||||
# Command steering
|
# Command steering
|
||||||
nop = Record(cmd_request_layout(geom_settings.addressbits,
|
nop = Record(cmd_request_layout(settings.geom.addressbits,
|
||||||
geom_settings.bankbits))
|
settings.geom.bankbits))
|
||||||
# nop must be 1st
|
# nop must be 1st
|
||||||
commands = [nop, choose_cmd.cmd, choose_req.cmd, refresher.cmd]
|
commands = [nop, choose_cmd.cmd, choose_req.cmd, refresher.cmd]
|
||||||
(STEER_NOP, STEER_CMD, STEER_REQ, STEER_REFRESH) = range(4)
|
(STEER_NOP, STEER_CMD, STEER_REQ, STEER_REFRESH) = range(4)
|
||||||
|
@ -159,8 +155,8 @@ class Multiplexer(Module, AutoCSR):
|
||||||
self.comb += max_time.eq(0)
|
self.comb += max_time.eq(0)
|
||||||
return en, max_time
|
return en, max_time
|
||||||
|
|
||||||
read_time_en, max_read_time = anti_starvation(controller_settings.read_time)
|
read_time_en, max_read_time = anti_starvation(settings.read_time)
|
||||||
write_time_en, max_write_time = anti_starvation(controller_settings.write_time)
|
write_time_en, max_write_time = anti_starvation(settings.write_time)
|
||||||
|
|
||||||
# Refresh
|
# Refresh
|
||||||
self.comb += [bm.refresh_req.eq(refresher.req) for bm in bank_machines]
|
self.comb += [bm.refresh_req.eq(refresher.req) for bm in bank_machines]
|
||||||
|
@ -178,19 +174,19 @@ class Multiplexer(Module, AutoCSR):
|
||||||
Cat(*all_wrdata_mask).eq(~lasmic.dat_we)
|
Cat(*all_wrdata_mask).eq(~lasmic.dat_we)
|
||||||
]
|
]
|
||||||
|
|
||||||
def steerer_sel(steerer, phy_settings, r_w_n):
|
def steerer_sel(steerer, r_w_n):
|
||||||
r = []
|
r = []
|
||||||
for i in range(phy_settings.nphases):
|
for i in range(settings.phy.nphases):
|
||||||
s = steerer.sel[i].eq(STEER_NOP)
|
s = steerer.sel[i].eq(STEER_NOP)
|
||||||
if r_w_n == "read":
|
if r_w_n == "read":
|
||||||
if i == phy_settings.rdphase:
|
if i == settings.phy.rdphase:
|
||||||
s = steerer.sel[i].eq(STEER_REQ)
|
s = steerer.sel[i].eq(STEER_REQ)
|
||||||
elif i == phy_settings.rdcmdphase:
|
elif i == settings.phy.rdcmdphase:
|
||||||
s = steerer.sel[i].eq(STEER_CMD)
|
s = steerer.sel[i].eq(STEER_CMD)
|
||||||
elif r_w_n == "write":
|
elif r_w_n == "write":
|
||||||
if i == phy_settings.wrphase:
|
if i == settings.phy.wrphase:
|
||||||
s = steerer.sel[i].eq(STEER_REQ)
|
s = steerer.sel[i].eq(STEER_REQ)
|
||||||
elif i == phy_settings.wrcmdphase:
|
elif i == settings.phy.wrcmdphase:
|
||||||
s = steerer.sel[i].eq(STEER_CMD)
|
s = steerer.sel[i].eq(STEER_CMD)
|
||||||
else:
|
else:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
@ -204,7 +200,7 @@ class Multiplexer(Module, AutoCSR):
|
||||||
choose_req.want_reads.eq(1),
|
choose_req.want_reads.eq(1),
|
||||||
choose_cmd.cmd.ready.eq(1),
|
choose_cmd.cmd.ready.eq(1),
|
||||||
choose_req.cmd.ready.eq(1),
|
choose_req.cmd.ready.eq(1),
|
||||||
steerer_sel(steerer, phy_settings, "read"),
|
steerer_sel(steerer, "read"),
|
||||||
If(write_available,
|
If(write_available,
|
||||||
# TODO: switch only after several cycles of ~read_available?
|
# TODO: switch only after several cycles of ~read_available?
|
||||||
If(~read_available | max_read_time,
|
If(~read_available | max_read_time,
|
||||||
|
@ -220,7 +216,7 @@ class Multiplexer(Module, AutoCSR):
|
||||||
choose_req.want_writes.eq(1),
|
choose_req.want_writes.eq(1),
|
||||||
choose_cmd.cmd.ready.eq(1),
|
choose_cmd.cmd.ready.eq(1),
|
||||||
choose_req.cmd.ready.eq(1),
|
choose_req.cmd.ready.eq(1),
|
||||||
steerer_sel(steerer, phy_settings, "write"),
|
steerer_sel(steerer, "write"),
|
||||||
If(read_available,
|
If(read_available,
|
||||||
If(~write_available | max_write_time,
|
If(~write_available | max_write_time,
|
||||||
NextState("WTR")
|
NextState("WTR")
|
||||||
|
@ -238,9 +234,9 @@ class Multiplexer(Module, AutoCSR):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# TODO: reduce this, actual limit is around (cl+1)/nphases
|
# TODO: reduce this, actual limit is around (cl+1)/nphases
|
||||||
fsm.delayed_enter("RTW", "WRITE", phy_settings.read_latency-1)
|
fsm.delayed_enter("RTW", "WRITE", settings.phy.read_latency-1)
|
||||||
fsm.delayed_enter("WTR", "READ", timing_settings.tWTR-1)
|
fsm.delayed_enter("WTR", "READ", settings.timing.tWTR-1)
|
||||||
|
|
||||||
if controller_settings.with_bandwidth:
|
if settings.with_bandwidth:
|
||||||
data_width = phy_settings.dfi_databits*phy_settings.nphases
|
data_width = settings.phy.dfi_databits*settings.phy.nphases
|
||||||
self.submodules.bandwidth = Bandwidth(self.choose_req.cmd, data_width)
|
self.submodules.bandwidth = Bandwidth(self.choose_req.cmd, data_width)
|
||||||
|
|
|
@ -5,10 +5,11 @@ from litedram.core.multiplexer import *
|
||||||
|
|
||||||
|
|
||||||
class Refresher(Module):
|
class Refresher(Module):
|
||||||
def __init__(self, a, ba, tRP, tREFI, tRFC, enable):
|
def __init__(self, settings):
|
||||||
self.req = Signal()
|
self.req = Signal()
|
||||||
self.ack = Signal() # 1st command 1 cycle after assertion of ack
|
self.ack = Signal() # 1st command 1 cycle after assertion of ack
|
||||||
self.cmd = cmd = Record(cmd_request_layout(a, ba))
|
self.cmd = cmd = Record(cmd_request_layout(settings.geom.addressbits,
|
||||||
|
settings.geom.bankbits))
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
|
@ -29,18 +30,18 @@ class Refresher(Module):
|
||||||
cmd.ras.eq(1),
|
cmd.ras.eq(1),
|
||||||
cmd.we.eq(1)
|
cmd.we.eq(1)
|
||||||
]),
|
]),
|
||||||
(1+tRP, [
|
(1+settings.timing.tRP, [
|
||||||
cmd.cas.eq(1),
|
cmd.cas.eq(1),
|
||||||
cmd.ras.eq(1)
|
cmd.ras.eq(1)
|
||||||
]),
|
]),
|
||||||
(1+tRP+tRFC, [
|
(1+settings.timing.tRP+settings.timing.tRFC, [
|
||||||
seq_done.eq(1)
|
seq_done.eq(1)
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
# Periodic refresh counter
|
# Periodic refresh counter
|
||||||
self.submodules.timer = WaitTimer(tREFI)
|
self.submodules.timer = WaitTimer(settings.timing.tREFI)
|
||||||
self.comb += self.timer.wait.eq(enable & ~self.timer.done)
|
self.comb += self.timer.wait.eq(settings.with_refresh & ~self.timer.done)
|
||||||
|
|
||||||
# Control FSM
|
# Control FSM
|
||||||
self.submodules.fsm = fsm = FSM()
|
self.submodules.fsm = fsm = FSM()
|
||||||
|
|
|
@ -15,9 +15,9 @@ class LiteDRAMCrossbar(Module):
|
||||||
self.rca_bits = controller.aw
|
self.rca_bits = controller.aw
|
||||||
self.dw = controller.dw
|
self.dw = controller.dw
|
||||||
self.nbanks = controller.nbanks
|
self.nbanks = controller.nbanks
|
||||||
self.cmd_buffer_depth = controller.cmd_buffer_depth
|
self.cmd_buffer_depth = controller.settings.cmd_buffer_depth
|
||||||
self.read_latency = controller.read_latency
|
self.read_latency = controller.settings.phy.read_latency + 1
|
||||||
self.write_latency = controller.write_latency
|
self.write_latency = controller.settings.phy.write_latency + 1
|
||||||
|
|
||||||
self.bank_bits = log2_int(self.nbanks, False)
|
self.bank_bits = log2_int(self.nbanks, False)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue