mirror of
https://github.com/enjoy-digital/litedram.git
synced 2025-01-04 09:52:25 -05:00
core: add missing docstrings
This commit is contained in:
parent
1f246cbb88
commit
dbac83f411
4 changed files with 187 additions and 3 deletions
litedram/core
|
@ -12,6 +12,33 @@ from litex.soc.interconnect.csr import *
|
|||
# Bandwidth ----------------------------------------------------------------------------------------
|
||||
|
||||
class Bandwidth(Module, AutoCSR):
|
||||
"""Measures LiteDRAM bandwidth
|
||||
|
||||
This module works by counting the number of read/write commands issued by
|
||||
the controller during a fixed time period. To copy the values registered
|
||||
during the last finished period, user must write to the `update` register.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
cmd : Endpoint(cmd_request_rw_layout)
|
||||
Multiplexer endpoint on which all read/write requests are being sent
|
||||
data_width : int, in
|
||||
Data width that can be read back from CSR
|
||||
period_bits : int, in
|
||||
Defines length of bandwidth measurement period = 2^period_bits
|
||||
|
||||
Attributes
|
||||
----------
|
||||
update : CSR, in
|
||||
Copy the values from last finished period to the status registers
|
||||
nreads : CSRStatus, out
|
||||
Number of READ commands issued during a period
|
||||
nwrites : CSRStatus, out
|
||||
Number of WRITE commands issued during a period
|
||||
data_width : CSRStatus, out
|
||||
Can be read to calculate bandwidth in bits/sec as:
|
||||
bandwidth = (nreads+nwrites) * data_width / period
|
||||
"""
|
||||
def __init__(self, cmd, data_width, period_bits=24):
|
||||
self.update = CSR()
|
||||
self.nreads = CSRStatus(period_bits)
|
||||
|
|
|
@ -16,6 +16,11 @@ from litedram.core.multiplexer import *
|
|||
# AddressSlicer ------------------------------------------------------------------------------------
|
||||
|
||||
class _AddressSlicer:
|
||||
"""Helper for extracting row/col from address
|
||||
|
||||
Column occupies lower bits of the address, row - higher bits. Address has
|
||||
a forced alignment, so column does not contain alignment bits.
|
||||
"""
|
||||
def __init__(self, colbits, address_align):
|
||||
self.colbits = colbits
|
||||
self.address_align = address_align
|
||||
|
@ -31,6 +36,53 @@ class _AddressSlicer:
|
|||
# BankMachine --------------------------------------------------------------------------------------
|
||||
|
||||
class BankMachine(Module):
|
||||
"""Converts requests from ports into DRAM commands
|
||||
|
||||
BankMachine abstracts single DRAM bank by keeping track of the currently
|
||||
selected row. It converts requests from LiteDRAMCrossbar to targetted
|
||||
to that bank into DRAM commands that go to the Multiplexer, inserting any
|
||||
needed activate/precharge commands (with optional auto-precharge). It also
|
||||
keeps track and enforces some DRAM timings (other timings are enforced in
|
||||
the Multiplexer).
|
||||
|
||||
BankMachines work independently from the data path (which connects
|
||||
LiteDRAMCrossbar with the Multiplexer directly).
|
||||
|
||||
Stream of requests from LiteDRAMCrossbar is being queued, so that reqeust
|
||||
can be "looked ahead", and auto-precharge can be performed (if enabled in
|
||||
settings).
|
||||
|
||||
Lock (cmd_layout.lock) is used to synchronise with LiteDRAMCrossbar. It is
|
||||
being held when:
|
||||
- there is a valid command awaiting in `cmd_buffer_lookahead` - this buffer
|
||||
becomes ready simply when the next data gets fetched to the `cmd_buffer`
|
||||
- there is a valid command in `cmd_buffer` - `cmd_buffer` becomes ready
|
||||
when the BankMachine sends wdata_ready/rdata_valid back to the crossbar
|
||||
|
||||
Parameters
|
||||
----------
|
||||
n : int
|
||||
Bank number
|
||||
address_width : int
|
||||
LiteDRAMInterface address width
|
||||
address_align : int
|
||||
Address alignment depending on burst length
|
||||
nranks : int
|
||||
Number of separate DRAM chips (width of chip select)
|
||||
settings : ControllerSettings
|
||||
LiteDRAMController settings
|
||||
|
||||
Attributes
|
||||
----------
|
||||
req : Record(cmd_layout)
|
||||
Stream of requests from LiteDRAMCrossbar
|
||||
refresh_req : Signal(), in
|
||||
Indicates that refresh needs to be done, connects to Refresher.cmd.valid
|
||||
refresh_gnt : Signal(), out
|
||||
Indicates that refresh permission has been granted, satisfying timings
|
||||
cmd : Endpoint(cmd_request_rw_layout)
|
||||
Stream of commands to the Multiplexer
|
||||
"""
|
||||
def __init__(self, n, address_width, address_align, nranks, settings):
|
||||
self.req = req = Record(cmd_layout(address_width))
|
||||
self.refresh_req = refresh_req = Signal()
|
||||
|
@ -101,6 +153,7 @@ class BankMachine(Module):
|
|||
self.comb += trascon.valid.eq(cmd.valid & cmd.ready & row_open)
|
||||
|
||||
# Auto Precharge generation ----------------------------------------------------------------
|
||||
# generate auto precharge when current and next cmds are to different rows
|
||||
if settings.with_auto_precharge:
|
||||
self.comb += \
|
||||
If(cmd_buffer_lookahead.source.valid & cmd_buffer.source.valid,
|
||||
|
@ -132,10 +185,10 @@ class BankMachine(Module):
|
|||
If(cmd.ready & auto_precharge,
|
||||
NextState("AUTOPRECHARGE")
|
||||
)
|
||||
).Else(
|
||||
).Else( # row_opened & ~row_hit
|
||||
NextState("PRECHARGE")
|
||||
)
|
||||
).Else(
|
||||
).Else( # ~row_opened
|
||||
NextState("ACTIVATE")
|
||||
)
|
||||
)
|
||||
|
|
|
@ -20,6 +20,44 @@ from litedram.frontend.adaptation import *
|
|||
# LiteDRAMCrossbar ---------------------------------------------------------------------------------
|
||||
|
||||
class LiteDRAMCrossbar(Module):
|
||||
"""Multiplexes LiteDRAMController (slave) between ports (masters)
|
||||
|
||||
To get a port to LiteDRAM, use the `get_port` method. It handles data width
|
||||
conversion and clock domain crossing, returning LiteDRAMNativePort.
|
||||
|
||||
The crossbar routes requests from masters to the BankMachines
|
||||
(bankN.cmd_layout) and connects data path directly to the Multiplexer
|
||||
(data_layout). It performs address translation based on chosen
|
||||
`controller.settings.address_mapping`.
|
||||
Internally, all masters are multiplexed between controller banks based on
|
||||
the bank address (extracted from the presented address). Each bank has
|
||||
a RoundRobin arbiter, that selects from masters that want to access this
|
||||
bank and are not already locked.
|
||||
|
||||
Locks (cmd_layout.lock) make sure that, when a master starts a transaction
|
||||
with given bank (which may include multiple reads/writes), no other bank
|
||||
will be assigned to it during this time.
|
||||
Arbiter (of a bank) considers given master as a candidate for selection if:
|
||||
- given master's command is valid
|
||||
- given master addresses the arbiter's bank
|
||||
- given master is not locked
|
||||
* i.e. it is not during transaction with another bank
|
||||
* i.e. no other bank's arbiter granted permission for this master (with
|
||||
bank.lock being active)
|
||||
|
||||
Data ready/valid signals for banks are routed from bankmachines with
|
||||
a latency that synchronizes them with the data coming over datapath.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
controller : LiteDRAMInterface
|
||||
Interface to LiteDRAMController
|
||||
|
||||
Attributes
|
||||
----------
|
||||
masters : [LiteDRAMNativePort, ...]
|
||||
LiteDRAM memory ports
|
||||
"""
|
||||
def __init__(self, controller):
|
||||
self.controller = controller
|
||||
|
||||
|
|
|
@ -22,6 +22,29 @@ from litedram.core.bandwidth import Bandwidth
|
|||
# _CommandChooser ----------------------------------------------------------------------------------
|
||||
|
||||
class _CommandChooser(Module):
|
||||
"""Arbitrates between requests, filtering them based on their type
|
||||
|
||||
Uses RoundRobin to choose current request, filters requests based on
|
||||
`want_*` signals.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
requests : [Endpoint(cmd_request_rw_layout), ...]
|
||||
Request streams to consider for arbitration
|
||||
|
||||
Attributes
|
||||
----------
|
||||
want_reads : Signal, in
|
||||
Consider read requests
|
||||
want_writes : Signal, in
|
||||
Consider write requests
|
||||
want_cmds : Signal, in
|
||||
Consider command requests (without ACT)
|
||||
want_activates : Signal, in
|
||||
Also consider ACT commands
|
||||
cmd : Endpoint(cmd_request_rw_layout)
|
||||
Currently selected request stream (when ~cmd.valid, cas/ras/we are 0)
|
||||
"""
|
||||
def __init__(self, requests):
|
||||
self.want_reads = Signal()
|
||||
self.want_writes = Signal()
|
||||
|
@ -94,6 +117,29 @@ class _CommandChooser(Module):
|
|||
(STEER_NOP, STEER_CMD, STEER_REQ, STEER_REFRESH) = range(4)
|
||||
|
||||
class _Steerer(Module):
|
||||
"""Connects selected request to DFI interface
|
||||
|
||||
cas/ras/we/is_write/is_read are connected only when `cmd.valid & cmd.ready`.
|
||||
Rank bits are decoded and used to drive cs_n in multi-rank systems,
|
||||
STEER_REFRESH always enables all ranks.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
commands : [Endpoint(cmd_request_rw_layout), ...]
|
||||
Command streams to choose from. Must be of len=4 in the order:
|
||||
NOP, CMD, REQ, REFRESH
|
||||
NOP can be of type Record(cmd_request_rw_layout) instead, so that it is
|
||||
always considered invalid (because of lack of the `valid` attribute).
|
||||
dfi : dfi.Interface
|
||||
DFI interface connected to PHY
|
||||
|
||||
Attributes
|
||||
----------
|
||||
sel : [Signal(max=len(commands)), ...], in
|
||||
Signals for selecting which request gets connected to the corresponding
|
||||
DFI phase. The signals should take one of the values from STEER_* to
|
||||
select given source.
|
||||
"""
|
||||
def __init__(self, commands, dfi):
|
||||
ncmd = len(commands)
|
||||
nph = len(dfi.phases)
|
||||
|
@ -143,9 +189,29 @@ class _Steerer(Module):
|
|||
phase.wrdata_en.eq(wrdata_ens[sel])
|
||||
]
|
||||
|
||||
# Multiplexe ---------------------------------------------------------------------------------------
|
||||
# Multiplexer --------------------------------------------------------------------------------------
|
||||
|
||||
class Multiplexer(Module, AutoCSR):
|
||||
"""Multplexes requets from BankMachines to DFI
|
||||
|
||||
This module multiplexes requests from BankMachines (and Refresher) and
|
||||
connects them to DFI. Refresh commands are coordinated between the Refresher
|
||||
and BankMachines to ensure there are no conflicts. Enforces required timings
|
||||
between commands (some timings are enforced by BankMachines).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
settings : ControllerSettings
|
||||
Controller settings (with .phy, .geom and .timing settings)
|
||||
bank_machines : [BankMachine, ...]
|
||||
Bank machines that generate command requests to the Multiplexer
|
||||
refresher : Refresher
|
||||
Generates REFRESH command requests
|
||||
dfi : dfi.Interface
|
||||
DFI connected to the PHY
|
||||
interface : LiteDRAMInterface
|
||||
Data interface connected directly to LiteDRAMCrossbar
|
||||
"""
|
||||
def __init__(self,
|
||||
settings,
|
||||
bank_machines,
|
||||
|
|
Loading…
Reference in a new issue