[libre-riscv-dev] libresoc memory architecture

Luke Kenneth Casson Leighton lkcl at lkcl.net
Tue Jun 23 19:04:36 BST 2020

On Tue, Jun 23, 2020 at 6:29 PM Michael Nolan <mtnolan2640 at gmail.com> wrote:

> Hello! One of my summer classes finished yesterday so I have some time I
> can dedicate to libre-soc again.


>  I was talking with Yehowshua Sunday,
> and he mentioned that Luke could use some help connecting the l0 cache
> to system memory. What all needs to be done regarding that?

the key diagram is here:

i have edited it and filled in the names of existing classes and
interfaces (Records/RecordObjects)

at present it *is* actually "connected" - via something called
TestMemoryPortInterface (pimem.py).

this is a *real* basic class that has a straight nmigen Memory of size
16 64-bit words.  it's enough to prove the concept... without extra
complex code in the way.

what we need is to connect multiple LDSTCompUnits to one Wishbone
Memory Bus, bearing in mind that the APIs (contracts) are *NOT*
directly compatible. see Contracts of Sale for an analogy:


* PortInterface is the top-level interface and it is **NOT** a
"fire-and-forget" or a "take-it-or-leave-it" contractual API: it is
what is termed a "house Contract of Sale" contractual API, which in
Contract Law has three time-transition points: "offer, exchange,

* Wishbone unfortunately is a "take-it-or-leave-it" API and we cannot
use it - not directly.  or, we can, but only under strict supervision
(atomic operations only).

* LDSTCompUnit talks PortInterface and it is LDSTCompUnit's
responsibility to perform LE/BE and Sign-Extend.  thus, LE/BE and
Sign-extend are *out of scope* for this discussion (already taken care
of, apart from a bug *sigh*).

* DualPortSplitter is where the crossbars are at the top of the
diagram.  these route STRAIGHT where addr[4] == 0 and CROSS where
addr[4] == 1.  they are also how mis-alignment is taken care of.

* each LDSTCompUnit connects its PortInterface to a DualPortSplitter
which generates *two* PortInterface requests, both of which *must* be
satisfiable *via the Contract API* before being allowed to proceed to
exchange-and-complete phase.  this is how we avoid data-corruption due
to one LD/ST actually requiring two separate memory reads/writes.

* L0CacheBuffer has been converted to the role of "Arbiter".  it takes
multiple incoming PortInterfaces and at present only has the one
outgoing PortInterface.  this needs to become 2 outgoing
PortInterfaces and the incoming needs to also be converted to *pairs*
of PortInterfaces

therefore, as you can see in the diagram, the connectivity is:


   * LDSTCompUnit -> PortInterface
   * PortInterface -> DualPortSplitter -> 2xPortInterfaces (odd/even)

QTY 1:

    * QTY N: 2xPortInterfaces -> L0CacheBuffer -> 2x DataMergers
(odd/even) -> 2x PortInterfaces

QTY 2 (odd/even)

    * PortInterface (128 bit) -> {insert converter class here} ->
Minerva LoadStoreInterface

at this point, things become slightly unclear because Minerva's
LoadStoreInterface width is (was) 32-bit (i widened it to 64-bit) and
we actually need 128-bit wide but Wishbone *cannot cope* with 128 bit.

options include:

* specifying 128 bit anyway and writing a special Arbiter class that
takes 128-bit-wide WB-non-compliant requests and turns them into twin

* creating a splitter at the *PortInterface* level which takes
incoming 128 bit PortInterface requests and turns them into pairs of
64 bit requests.

* other.

there is slightly more to it than that however that is quite enough for now.

any questions?


More information about the libre-riscv-dev mailing list