core: add missing docstrings

This commit is contained in:
Jędrzej Boczar 2020-04-06 11:34:28 +02:00 committed by Jędrzej Boczar
parent 1f246cbb88
commit dbac83f411
4 changed files with 187 additions and 3 deletions

View file

@ -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)

View file

@ -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")
)
)

View file

@ -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

View file

@ -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,