mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
doc: refactor
This commit is contained in:
parent
1966117e17
commit
009ebd1106
3 changed files with 691 additions and 451 deletions
471
README
471
README
|
@ -1,453 +1,13 @@
|
||||||
Migen (Milkymist Generator)
|
Migen (Milkymist Generator)
|
||||||
a Python toolbox for building complex digital hardware
|
a Python toolbox for building complex digital hardware
|
||||||
======================================================
|
|
||||||
|
|
||||||
Background
|
Migen aims at automating further the VLSI design process. It provides
|
||||||
==========
|
tools to build synchronous designs more productively, integrate
|
||||||
Even though the Milkymist system-on-chip [1] is technically successful,
|
system-on-chips, design dataflow systems, and more. Migen will become
|
||||||
it suffers from several limitations stemming from its implementation in
|
the foundation for the next-generation Milkymist SoC.
|
||||||
manually written Verilog HDL:
|
|
||||||
|
|
||||||
(1) The "event-driven" paradigm of today's dominant hardware descriptions
|
See doc/migen.txt for a more complete description.
|
||||||
languages (Verilog and VHDL, collectively referred to as "V*HDL" in the
|
|
||||||
rest of this document) is often too general. Today's FPGA architectures
|
|
||||||
are optimized for the implementation of fully synchronous circuits. This
|
|
||||||
means that the bulk of the code for an efficient FPGA design falls into
|
|
||||||
three categories:
|
|
||||||
(a) Combinatorial statements
|
|
||||||
(b) Synchronous statements
|
|
||||||
(c) Initialization of registers at reset
|
|
||||||
V*HDL do not follow this organization. This means that a lot of
|
|
||||||
repetitive manual coding is needed, which brings sources of human errors,
|
|
||||||
petty issues, and confusion for beginners:
|
|
||||||
- wire vs. reg in Verilog
|
|
||||||
- forgetting to initialize a register at reset
|
|
||||||
- deciding whether a combinatorial statement must go into a
|
|
||||||
process/always block or not
|
|
||||||
- simulation mismatches with combinatorial processes/always blocks
|
|
||||||
- and more...
|
|
||||||
A little-known fact about FPGAs is that many of them have to ability to
|
|
||||||
initialize their registers from the bitstream contents. This can be done
|
|
||||||
in a portable and standard way using an "initial" block in Verilog, and
|
|
||||||
by affecting a value at the signal declaration in VHDL. This renders an
|
|
||||||
explicit reset signal unnecessary in practice in some cases, which opens
|
|
||||||
the way for further design optimization. However, this form of
|
|
||||||
initialization is entirely not synthesizable for ASIC targets, and it is
|
|
||||||
not easy to switch between the two forms of reset using V*HDL.
|
|
||||||
|
|
||||||
(2) V*HDL support for composite types is very limited. Signals having a
|
|
||||||
record type in VHDL are unidirectional, which makes them clumsy to use
|
|
||||||
e.g. in bus interfaces. There is no record type support in Verilog, which
|
|
||||||
means that a lot of copy-and-paste has to be done when forwarding grouped
|
|
||||||
signals.
|
|
||||||
|
|
||||||
(3) V*HDL support for procedurally generated logic is extremely limited.
|
|
||||||
The most advanced forms of procedural generation of synthesizable logic
|
|
||||||
that V*HDL offers are CPP-style directives in Verilog, combinatorial
|
|
||||||
functions, and generate statements. Nothing really fancy, and it shows.
|
|
||||||
To give a few examples:
|
|
||||||
- Building highly flexible bus interconnect is not possible. Even
|
|
||||||
arbitrating any given number of bus masters for commonplace protocols
|
|
||||||
such as Wishbone cannot be done with the tools at V*HDL puts at our
|
|
||||||
disposal. This requires manual recoding of parts of the arbiter to add or
|
|
||||||
remove a master, which is tedious and often cause frustrating errors.
|
|
||||||
Each occurence of the latter can easily cause one or two hours of lost
|
|
||||||
productivity when combined with the long compilation times of moderately
|
|
||||||
complex system-on-chip designs.
|
|
||||||
- Building a memory infrastructure (including bus interconnect, bridges
|
|
||||||
and caches) that can automatically adapt itself at compile-time to any
|
|
||||||
word size of the SDRAM is clumsy and tedious.
|
|
||||||
- Building register banks for control, status and interrupt management
|
|
||||||
of cores can also largely benefit from automation.
|
|
||||||
- Many hardware acceleration problems can fit into the dataflow
|
|
||||||
programming model. Manual dataflow implementation in V*HDL has, again, a
|
|
||||||
lot of redundancy and potential for human errors. See the Milkymist
|
|
||||||
texture mapping unit [3][4] for an example of this. The amount of detail
|
|
||||||
to deal with manually also makes the design space exploration difficult,
|
|
||||||
and therefore hinders the design of efficient architectures.
|
|
||||||
- Pre-computation of values, such as filter coefficients for DSP or
|
|
||||||
even simply trigonometric tables, must often be done using external tools
|
|
||||||
whose results are copy-and-pasted (in the best cases, automatically) into
|
|
||||||
the V*HDL source.
|
|
||||||
|
|
||||||
Enter Migen, a Python toolbox for building complex digital hardware. We
|
|
||||||
could have designed a brand new programming language, but that would have
|
|
||||||
been reinventing the wheel instead of being able to benefit from Python's
|
|
||||||
rich features and immense library. The price to pay is a slightly
|
|
||||||
cluttered syntax at times when writing descriptions in FHDL, but we
|
|
||||||
believe this is totally acceptable, particularly when compared to VHDL
|
|
||||||
;-)
|
|
||||||
|
|
||||||
Migen is made up of several related components, which are briefly
|
|
||||||
described below.
|
|
||||||
|
|
||||||
Migen FHDL
|
|
||||||
==========
|
|
||||||
The Fragmented Hardware Description Language (FHDL) is the lowest layer
|
|
||||||
of Migen. It consists of a formal system to describe signals, and
|
|
||||||
combinatorial and synchronous statements operating on them. The formal
|
|
||||||
system itself is low level and close to the synthesizable subset of
|
|
||||||
Verilog, and we then rely on Python algorithms to build complex
|
|
||||||
structures by combining FHDL elements and encapsulating them in
|
|
||||||
"fragments".
|
|
||||||
The FHDL module also contains a back-end to produce synthesizable
|
|
||||||
Verilog, and some basic analysis functions. It would be possible to
|
|
||||||
develop a VHDL back-end as well, though more difficult than for Verilog -
|
|
||||||
we are "cheating" a bit now as Verilog provides most of the FHDL
|
|
||||||
semantics.
|
|
||||||
|
|
||||||
FHDL differs from MyHDL [2] in fundamental ways. MyHDL follows the
|
|
||||||
event-driven paradigm of traditional HDLs (see Background, #1) while FHDL
|
|
||||||
separates the code into combinatorial statements, synchronous statements,
|
|
||||||
and reset values. In MyHDL, the logic is described directly in the Python
|
|
||||||
AST. The converter to Verilog or VHDL then examines the Python AST and
|
|
||||||
recognizes a subset of Python that it translates into V*HDL statements.
|
|
||||||
This seriously impedes the capability of MyHDL to generate logic
|
|
||||||
procedurally. With FHDL, you manipulate a custom AST from Python, and you
|
|
||||||
can more easily design algorithms that operate on it.
|
|
||||||
|
|
||||||
FHDL is made of several elements, which are briefly explained below.
|
|
||||||
|
|
||||||
BV
|
|
||||||
--
|
|
||||||
The bit vector (BV) object defines if a constant or signal is signed or
|
|
||||||
unsigned, and how many bits it has. This is useful e.g. to:
|
|
||||||
- determine when to perform sign extension (FHDL uses the same rules as
|
|
||||||
Verilog).
|
|
||||||
- determine the size of registers.
|
|
||||||
- determine how many bits should be used by each value in
|
|
||||||
concatenations.
|
|
||||||
|
|
||||||
Constant
|
|
||||||
--------
|
|
||||||
This object should be self-explanatory. All constant objects contain a BV
|
|
||||||
object and a value. If no BV object is specified, one will be made up
|
|
||||||
using the following rules:
|
|
||||||
- If the value is positive, the BV is unsigned and has the minimum
|
|
||||||
number of bits needed to represent the constant's value in the canonical
|
|
||||||
base-2 system.
|
|
||||||
- If the value is negative, the BV is signed, and has the minimum
|
|
||||||
number of bits needed to represent the constant's value in the canonical
|
|
||||||
two's complement, base-2 system.
|
|
||||||
|
|
||||||
Signal
|
|
||||||
------
|
|
||||||
The signal object represents a value that is expected to change in the
|
|
||||||
circuit. It does exactly what Verilog's "wire" and "reg" and VHDL's
|
|
||||||
"signal" and "variable" do.
|
|
||||||
|
|
||||||
The main point of the signal object is that it is identified by its
|
|
||||||
Python ID (as returned by the id() function), and nothing else. It is the
|
|
||||||
responsibility of the V*HDL back-end to establish an injective mapping
|
|
||||||
between Python IDs and the V*HDL namespace. It should perform name
|
|
||||||
mangling to ensure this. The consequence of this is that signal objects
|
|
||||||
can safely become members of arbitrary Python classes, or be passed as
|
|
||||||
parameters to functions or methods that generate logic involving them.
|
|
||||||
|
|
||||||
The properties of a signal object are:
|
|
||||||
- a bit vector description
|
|
||||||
- a name, used as a hint for the V*HDL back-end name mangler.
|
|
||||||
- a boolean "variable". If true, the signal will behave like a VHDL
|
|
||||||
variable, or a Verilog reg that uses blocking assignment. This parameter
|
|
||||||
only has an effect when the signal's value is modified in a synchronous
|
|
||||||
statement.
|
|
||||||
- the signal's reset value. It must be an integer, and defaults to 0.
|
|
||||||
When the signal's value is modified with a synchronous statement, the
|
|
||||||
reset value is the initialization value of the associated register.
|
|
||||||
When the signal is assigned to in a conditional combinatorial statement
|
|
||||||
(If or Case), the reset value is the value that the signal has when no
|
|
||||||
condition that causes the signal to be driven is verified. This enforces
|
|
||||||
the absence of latches in designs. If the signal is permanently driven
|
|
||||||
using a combinatorial statement, the reset value has no effect.
|
|
||||||
|
|
||||||
The sole purpose of the name property is to make the generated V*HDL code
|
|
||||||
easier to understand and debug. From a purely functional point of view,
|
|
||||||
it is perfectly OK to have several signals with the same name property.
|
|
||||||
The back-end will generate a unique name for each object. If no name
|
|
||||||
property is specified, Migen will analyze the code that created the
|
|
||||||
signal object, and try to extract the variable or member name from there.
|
|
||||||
It then uses the module name that created the signal, a underscore, and
|
|
||||||
the variable name. For example, if we are in module "foo", the following
|
|
||||||
statements will create one or several signal(s) named "foo_bar":
|
|
||||||
bar = Signal()
|
|
||||||
self.bar = Signal()
|
|
||||||
self.baz.bar = Signal()
|
|
||||||
bar = [Signal() for x in range(42)]
|
|
||||||
|
|
||||||
Operators
|
|
||||||
---------
|
|
||||||
Operators are represented by the _Operator object, which generally should
|
|
||||||
not be used directly. Instead, most FHDL objects overload the usual
|
|
||||||
Python logic and arithmetic operators, which allows a much lighter syntax
|
|
||||||
to be used. For example, the expression:
|
|
||||||
a * b + c
|
|
||||||
is equivalent to:
|
|
||||||
_Operator('+', [_Operator('*', [a, b]), c])
|
|
||||||
|
|
||||||
Slices
|
|
||||||
------
|
|
||||||
Likewise, slices are represented by the _Slice object, which often should
|
|
||||||
not be used in favor of the Python slice operation [x:y].
|
|
||||||
Implicit indices using the forms [x], [x:] and [:y] are supported.
|
|
||||||
Beware! Slices work like Python slices, not like VHDL or Verilog slices.
|
|
||||||
The first bound is the index of the LSB and is inclusive. The second
|
|
||||||
bound is the index of MSB and is exclusive. In V*HDL, bounds are MSB:LSB
|
|
||||||
and both are inclusive.
|
|
||||||
|
|
||||||
Concatenations
|
|
||||||
--------------
|
|
||||||
Concatenations are done using the Cat object. To make the syntax lighter,
|
|
||||||
its constructor takes a variable number of arguments, which are the
|
|
||||||
signals to be concatenated together (you can use the Python '*' operator
|
|
||||||
to pass a list instead).
|
|
||||||
To be consistent with slices, the first signal is connected to the bits
|
|
||||||
with the lowest indices in the result. This is the opposite of the way
|
|
||||||
the '{}' construct works in Verilog.
|
|
||||||
|
|
||||||
Replications
|
|
||||||
------------
|
|
||||||
The Replicate object represents the equivalent of {count{expression}} in
|
|
||||||
Verilog.
|
|
||||||
|
|
||||||
Assignments
|
|
||||||
-----------
|
|
||||||
Assignments are represented with the _Assign object. Since using it
|
|
||||||
directly would result in a cluttered syntax, the preferred technique for
|
|
||||||
assignments is to use the eq() method provided by objects that can have a
|
|
||||||
value assigned to them. They are signals, and their combinations with the
|
|
||||||
slice and concatenation operators.
|
|
||||||
As an example, the statement:
|
|
||||||
a[0].eq(b)
|
|
||||||
is equivalent to:
|
|
||||||
_Assign(_Slice(a, 0, 1), b)
|
|
||||||
|
|
||||||
If statement
|
|
||||||
------------
|
|
||||||
The If object takes a first parameter which must be an expression
|
|
||||||
(combination of the Constant, Signal, _Operator, _Slice, etc. objects)
|
|
||||||
representing the condition, then a variable number of parameters
|
|
||||||
representing the statements (_Assign, If, Case, etc. objects) to be
|
|
||||||
executed when the condition is verified.
|
|
||||||
|
|
||||||
The If object defines a Else() method, which when called defines the
|
|
||||||
statements to be executed when the condition is not true. Those
|
|
||||||
statements are passed as parameters to the variadic method.
|
|
||||||
|
|
||||||
For convenience, there is also a Elif() method.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
If(tx_count16 == 0,
|
|
||||||
tx_bitcount.eq(tx_bitcount + 1),
|
|
||||||
If(tx_bitcount == 8,
|
|
||||||
self.tx.eq(1)
|
|
||||||
).Elif(tx_bitcount == 9,
|
|
||||||
self.tx.eq(1),
|
|
||||||
tx_busy.eq(0)
|
|
||||||
).Else(
|
|
||||||
self.tx.eq(tx_reg[0]),
|
|
||||||
tx_reg.eq(Cat(tx_reg[1:], 0))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
Case statement
|
|
||||||
--------------
|
|
||||||
The Case object constructor takes as first parameter the expression to be
|
|
||||||
tested, then a variable number of lists describing the various cases.
|
|
||||||
|
|
||||||
Each list contains an expression (typically a constant) describing the
|
|
||||||
value to be matched, followed by the statements to be executed when there
|
|
||||||
is a match. The head of the list can be the an instance of the Default
|
|
||||||
object.
|
|
||||||
|
|
||||||
Instances
|
|
||||||
---------
|
|
||||||
Instance objects represent the parametrized instantiation of a V*HDL
|
|
||||||
module, and the connection of its ports to FHDL signals. They are useful
|
|
||||||
in a number of cases:
|
|
||||||
- reusing legacy or third-party V*HDL code.
|
|
||||||
- using special FPGA features (DCM, ICAP, ...).
|
|
||||||
- implementing logic that cannot be expressed with FHDL (asynchronous
|
|
||||||
circuits, ...).
|
|
||||||
- breaking down a Migen system into multiple sub-systems, possibly
|
|
||||||
using different clock domains.
|
|
||||||
|
|
||||||
The properties of the instance object are:
|
|
||||||
- the type of the instance (i.e. name of the instantiated module).
|
|
||||||
- a list of output ports of the instantiated module. Each element of
|
|
||||||
the list is a pair containing a string, which is the name of the
|
|
||||||
module's port, and either an existing signal (on which the port will
|
|
||||||
be connected to) or a BV (which will cause the creation of a new
|
|
||||||
signal).
|
|
||||||
- a list of input ports (likewise).
|
|
||||||
- a list of (name, value) pairs for the parameters ("generics" in VHDL)
|
|
||||||
of the module.
|
|
||||||
- the name of the clock port of the module (if any). If this is
|
|
||||||
specified, the port will be connected to the system clock.
|
|
||||||
- the name of the reset port of the module (likewise).
|
|
||||||
- the name of the instance (can be mangled like signal names).
|
|
||||||
|
|
||||||
Memories
|
|
||||||
--------
|
|
||||||
Memories (on-chip SRAM) are not supported, but will be soon, using a
|
|
||||||
mechanism similar to instances. (TODO)
|
|
||||||
|
|
||||||
Fragments
|
|
||||||
---------
|
|
||||||
A "fragment" is a unit of logic, which is composed of:
|
|
||||||
- a list of combinatorial statements.
|
|
||||||
- a list of synchronous statements.
|
|
||||||
- a list of instances.
|
|
||||||
- a list of memories.
|
|
||||||
- a set of pads, which are signals intended to be connected to
|
|
||||||
off-chip devices.
|
|
||||||
|
|
||||||
Fragments can reference arbitrary signals, including signals that are
|
|
||||||
referenced in other fragments. Fragments can be combined using the "+"
|
|
||||||
operator, which returns a new fragment containing the concatenation of
|
|
||||||
each pair of lists.
|
|
||||||
|
|
||||||
Fragments can be passed to the back-end for conversion to Verilog.
|
|
||||||
|
|
||||||
By convention, classes that generate logic implement a method called
|
|
||||||
"get_fragment". When called, this method builds a new fragment
|
|
||||||
implementing the desired functionality of the class, and returns it. This
|
|
||||||
convention allows fragments to be built automatically by combining the
|
|
||||||
fragments from all relevant objects in the local scope, by using the
|
|
||||||
autofragment module.
|
|
||||||
|
|
||||||
Migen Core Logic
|
|
||||||
================
|
|
||||||
Migen Core Logic is a convenience library of common logic circuits
|
|
||||||
implemented using FHDL:
|
|
||||||
- a multi-cycle integer divider.
|
|
||||||
- a round-robin arbiter, useful to build bus arbiters.
|
|
||||||
- a multiplexer bank (multimux), useful to multiplex composite
|
|
||||||
(grouped) signals.
|
|
||||||
- a condition-triggered static scheduler of FHDL synchronous statements
|
|
||||||
(timeline).
|
|
||||||
|
|
||||||
Migen Bus
|
|
||||||
=========
|
|
||||||
Migen Bus contains classes providing a common structure for master and
|
|
||||||
slave interfaces of the following buses:
|
|
||||||
- Wishbone [5], the general purpose bus recommended by Opencores.
|
|
||||||
- CSR-NG, a low-bandwidth, resource-sensitive bus designed for
|
|
||||||
accessing the configuration and status registers of cores from
|
|
||||||
software.
|
|
||||||
- FastMemoryLink-NG, a split-transaction bus optimized for use with a
|
|
||||||
high-performance, out-of-order SDRAM controller. (TODO)
|
|
||||||
|
|
||||||
It also provides interconnect components for these buses, such as
|
|
||||||
arbiters and address decoders. The strength of the Migen procedurally
|
|
||||||
generated logic can be illustrated by the following example:
|
|
||||||
wbcon = wishbone.InterconnectShared(
|
|
||||||
[cpu.ibus, cpu.dbus, ethernet.dma, audio.dma],
|
|
||||||
[(0, norflash.bus), (1, wishbone2fml.wishbone),
|
|
||||||
(3, wishbone2csr.wishbone)])
|
|
||||||
In this example, the interconnect component generates a 4-way round-robin
|
|
||||||
arbiter, multiplexes the master bus signals into a shared bus, determines
|
|
||||||
that the address decoding must occur on 2 bits, and connects all slave
|
|
||||||
interfaces to the shared bus, inserting the address decoder logic in the
|
|
||||||
bus cycle qualification signals and multiplexing the data return path. It
|
|
||||||
can recognize the signals in each core's bus interface thanks to the
|
|
||||||
common structure mandated by Migen Bus. All this happens automatically,
|
|
||||||
using only that much user code. The resulting interconnect logic can be
|
|
||||||
retrieved using wbcon.get_fragment(), and combined with the fragments
|
|
||||||
from the rest of the system.
|
|
||||||
|
|
||||||
Migen Bank
|
|
||||||
==========
|
|
||||||
Migen Bank is a system comparable to wishbone-gen [6], which automates
|
|
||||||
the creation of configuration and status register banks and
|
|
||||||
(TODO) interrupt/event managers implemented in cores.
|
|
||||||
|
|
||||||
Bank takes a description made up of a list of registers and generates
|
|
||||||
logic implementing it with a slave interface compatible with Migen Bus.
|
|
||||||
|
|
||||||
A register can be "raw", which means that the core has direct access to
|
|
||||||
it. It also means that the register width must be less or equal to the
|
|
||||||
bus word width. In that case, the register object provides the following
|
|
||||||
signals:
|
|
||||||
- dev_r, which contains the data written from the bus interface.
|
|
||||||
- dev_re, which is the strobe signal for dev_r. It is active for one
|
|
||||||
cycle, after or during a write from the bus. dev_r is only valid when
|
|
||||||
dev_re is high.
|
|
||||||
- dev_w, which must provide at all times the value to be read from the
|
|
||||||
bus.
|
|
||||||
|
|
||||||
Registers that are not raw are managed by Bank and contain fields. If the
|
|
||||||
sum of the widths of all fields attached to a register exceeds the bus
|
|
||||||
word width, the register will automatically be sliced into words of the
|
|
||||||
maximum size and implemented at consecutive bus addresses, MSB first.
|
|
||||||
Field objects have two parameters, access_bus and access_dev, determining
|
|
||||||
respectively the access policies for the bus and core sides. They can
|
|
||||||
take the values READ_ONLY, WRITE_ONLY and READ_WRITE.
|
|
||||||
If the device can read, the field object provides the dev_r signal, which
|
|
||||||
contains at all times the current value of the field (kept by the logic
|
|
||||||
generated by Bank).
|
|
||||||
If the device can write, the field object provides the following signals:
|
|
||||||
- dev_w, which provides the value to be written into the field.
|
|
||||||
- dev_we, which strobes the value into the field.
|
|
||||||
|
|
||||||
Migen Flow (TODO)
|
|
||||||
==========
|
|
||||||
Many hardware acceleration problems can be expressed in the dataflow
|
|
||||||
paradigm, that is, using a directed graph representing the flow of data
|
|
||||||
between actors.
|
|
||||||
|
|
||||||
Actors in Migen are written directly in FHDL. This maximizes the
|
|
||||||
flexibility: for example, an actor can implement a DMA master to read
|
|
||||||
data from system memory. It is conceivable that a CAL [7] to FHDL
|
|
||||||
compiler be implemented at some point, to support higher level
|
|
||||||
descriptions of some actors and reuse of third-party RVC-CAL
|
|
||||||
applications. [8] [9] [10]
|
|
||||||
|
|
||||||
Actors communicate by exchanging tokens, whose flow is typically
|
|
||||||
controlled using handshake signals (strobe/ack).
|
|
||||||
|
|
||||||
Each actor has a "scheduling model". It can be:
|
|
||||||
- N-sequential: the actor fires when tokens are available at all its
|
|
||||||
inputs, and it produces one output token after N cycles. It cannot
|
|
||||||
accept new input tokens until it has produced its output. A
|
|
||||||
multicycle integer divider would use this model.
|
|
||||||
- N-pipelined: similar to the sequential model, but the actor can
|
|
||||||
always accept new input tokens. It produces an output token N cycles
|
|
||||||
of latency after accepting input tokens. A pipelined multiplier would
|
|
||||||
use this model.
|
|
||||||
- Dynamic: the general case, when no simple hypothesis can be made on
|
|
||||||
the token flow behaviour of the actor. An actor accessing system
|
|
||||||
memory on a shared bus would use this model.
|
|
||||||
|
|
||||||
Migen Flow automatically generates handshake logic for the first two
|
|
||||||
scheduling models. In the third case, the FHDL descriptions for the logic
|
|
||||||
driving the handshake signals must be provided by the actor.
|
|
||||||
|
|
||||||
If sequential or pipelined actors are connected together, Migen Flow will
|
|
||||||
attempt to find a static schedule, remove the handshake signals, optimize
|
|
||||||
away the control logic in each actor and replace it with a centralized
|
|
||||||
FSM implementing the static schedule.
|
|
||||||
|
|
||||||
An actor can be a composition of other actors.
|
|
||||||
|
|
||||||
Actor graphs are managed using the NetworkX [11] library.
|
|
||||||
|
|
||||||
|
|
||||||
References:
|
|
||||||
[ 1] http://milkymist.org
|
|
||||||
[ 2] http://www.myhdl.org
|
|
||||||
[ 3] http://milkymist.org/thesis/thesis.pdf
|
|
||||||
[ 4] http://www.xilinx.com/publications/archives/xcell/Xcell77.pdf p30-35
|
|
||||||
[ 5] http://cdn.opencores.org/downloads/wbspec_b4.pdf
|
|
||||||
[ 6] http://www.ohwr.org/projects/wishbone-gen
|
|
||||||
[ 7] http://opendf.svn.sourceforge.net/viewvc/opendf/trunk/doc/
|
|
||||||
GentleIntro/GentleIntro.pdf
|
|
||||||
[ 8] http://orcc.sourceforge.net/
|
|
||||||
[ 9] http://orc-apps.sourceforge.net/
|
|
||||||
[10] http://opendf.sourceforge.net/
|
|
||||||
[11] http://networkx.lanl.gov/
|
|
||||||
|
|
||||||
Practical information
|
|
||||||
=====================
|
|
||||||
Code repository:
|
Code repository:
|
||||||
https://github.com/milkymist/migen
|
https://github.com/milkymist/migen
|
||||||
Experimental version of the Milkymist SoC based on Migen:
|
Experimental version of the Milkymist SoC based on Migen:
|
||||||
|
@ -461,8 +21,17 @@ We are also on IRC: #milkymist on the Freenode network.
|
||||||
Migen is free software: you can redistribute it and/or modify it under
|
Migen is free software: you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free
|
the terms of the GNU General Public License as published by the Free
|
||||||
Software Foundation, version 3 of the License. This program is
|
Software Foundation, version 3 of the License. This program is
|
||||||
distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
Unless otherwise noted, Migen's source code is copyright (C) 2011-2012
|
Unless otherwise noted, Migen's source code is copyright (C) 2011-2012
|
||||||
Sebastien Bourdeauducq. Authors retain ownership of their contributions.
|
Sebastien Bourdeauducq. Other authors retain ownership of their
|
||||||
|
contributions. If a submission can reasonably be considered
|
||||||
|
independently copyrightable, it's yours and I encourage you to claim it
|
||||||
|
with appropriate copyright notices. This submission then falls under the
|
||||||
|
"otherwise noted" category. All submissions must use a license
|
||||||
|
compatible with the GPL.
|
||||||
|
|
||||||
|
"Electricity! It's like magic!"
|
||||||
|
|
447
doc/migen.txt
Normal file
447
doc/migen.txt
Normal file
|
@ -0,0 +1,447 @@
|
||||||
|
Migen (Milkymist Generator)
|
||||||
|
a Python toolbox for building complex digital hardware
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
Background
|
||||||
|
==========
|
||||||
|
Even though the Milkymist system-on-chip [1] is technically successful,
|
||||||
|
it suffers from several limitations stemming from its implementation in
|
||||||
|
manually written Verilog HDL:
|
||||||
|
|
||||||
|
(1) The "event-driven" paradigm of today's dominant hardware descriptions
|
||||||
|
languages (Verilog and VHDL, collectively referred to as "V*HDL" in the
|
||||||
|
rest of this document) is often too general. Today's FPGA architectures
|
||||||
|
are optimized for the implementation of fully synchronous circuits. This
|
||||||
|
means that the bulk of the code for an efficient FPGA design falls into
|
||||||
|
three categories:
|
||||||
|
(a) Combinatorial statements
|
||||||
|
(b) Synchronous statements
|
||||||
|
(c) Initialization of registers at reset
|
||||||
|
V*HDL do not follow this organization. This means that a lot of
|
||||||
|
repetitive manual coding is needed, which brings sources of human errors,
|
||||||
|
petty issues, and confusion for beginners:
|
||||||
|
- wire vs. reg in Verilog
|
||||||
|
- forgetting to initialize a register at reset
|
||||||
|
- deciding whether a combinatorial statement must go into a
|
||||||
|
process/always block or not
|
||||||
|
- simulation mismatches with combinatorial processes/always blocks
|
||||||
|
- and more...
|
||||||
|
A little-known fact about FPGAs is that many of them have to ability to
|
||||||
|
initialize their registers from the bitstream contents. This can be done
|
||||||
|
in a portable and standard way using an "initial" block in Verilog, and
|
||||||
|
by affecting a value at the signal declaration in VHDL. This renders an
|
||||||
|
explicit reset signal unnecessary in practice in some cases, which opens
|
||||||
|
the way for further design optimization. However, this form of
|
||||||
|
initialization is entirely not synthesizable for ASIC targets, and it is
|
||||||
|
not easy to switch between the two forms of reset using V*HDL.
|
||||||
|
|
||||||
|
(2) V*HDL support for composite types is very limited. Signals having a
|
||||||
|
record type in VHDL are unidirectional, which makes them clumsy to use
|
||||||
|
e.g. in bus interfaces. There is no record type support in Verilog, which
|
||||||
|
means that a lot of copy-and-paste has to be done when forwarding grouped
|
||||||
|
signals.
|
||||||
|
|
||||||
|
(3) V*HDL support for procedurally generated logic is extremely limited.
|
||||||
|
The most advanced forms of procedural generation of synthesizable logic
|
||||||
|
that V*HDL offers are CPP-style directives in Verilog, combinatorial
|
||||||
|
functions, and generate statements. Nothing really fancy, and it shows.
|
||||||
|
To give a few examples:
|
||||||
|
- Building highly flexible bus interconnect is not possible. Even
|
||||||
|
arbitrating any given number of bus masters for commonplace protocols
|
||||||
|
such as Wishbone cannot be done with the tools at V*HDL puts at our
|
||||||
|
disposal. This requires manual recoding of parts of the arbiter to add or
|
||||||
|
remove a master, which is tedious and often cause frustrating errors.
|
||||||
|
Each occurence of the latter can easily cause one or two hours of lost
|
||||||
|
productivity when combined with the long compilation times of moderately
|
||||||
|
complex system-on-chip designs.
|
||||||
|
- Building a memory infrastructure (including bus interconnect, bridges
|
||||||
|
and caches) that can automatically adapt itself at compile-time to any
|
||||||
|
word size of the SDRAM is clumsy and tedious.
|
||||||
|
- Building register banks for control, status and interrupt management
|
||||||
|
of cores can also largely benefit from automation.
|
||||||
|
- Many hardware acceleration problems can fit into the dataflow
|
||||||
|
programming model. Manual dataflow implementation in V*HDL has, again, a
|
||||||
|
lot of redundancy and potential for human errors. See the Milkymist
|
||||||
|
texture mapping unit [3][4] for an example of this. The amount of detail
|
||||||
|
to deal with manually also makes the design space exploration difficult,
|
||||||
|
and therefore hinders the design of efficient architectures.
|
||||||
|
- Pre-computation of values, such as filter coefficients for DSP or
|
||||||
|
even simply trigonometric tables, must often be done using external tools
|
||||||
|
whose results are copy-and-pasted (in the best cases, automatically) into
|
||||||
|
the V*HDL source.
|
||||||
|
|
||||||
|
Enter Migen, a Python toolbox for building complex digital hardware. We
|
||||||
|
could have designed a brand new programming language, but that would have
|
||||||
|
been reinventing the wheel instead of being able to benefit from Python's
|
||||||
|
rich features and immense library. The price to pay is a slightly
|
||||||
|
cluttered syntax at times when writing descriptions in FHDL, but we
|
||||||
|
believe this is totally acceptable, particularly when compared to VHDL
|
||||||
|
;-)
|
||||||
|
|
||||||
|
Migen is made up of several related components, which are briefly
|
||||||
|
described below.
|
||||||
|
|
||||||
|
Migen FHDL
|
||||||
|
==========
|
||||||
|
The Fragmented Hardware Description Language (FHDL) is the lowest layer
|
||||||
|
of Migen. It consists of a formal system to describe signals, and
|
||||||
|
combinatorial and synchronous statements operating on them. The formal
|
||||||
|
system itself is low level and close to the synthesizable subset of
|
||||||
|
Verilog, and we then rely on Python algorithms to build complex
|
||||||
|
structures by combining FHDL elements and encapsulating them in
|
||||||
|
"fragments".
|
||||||
|
The FHDL module also contains a back-end to produce synthesizable
|
||||||
|
Verilog, and some basic analysis functions. It would be possible to
|
||||||
|
develop a VHDL back-end as well, though more difficult than for Verilog -
|
||||||
|
we are "cheating" a bit now as Verilog provides most of the FHDL
|
||||||
|
semantics.
|
||||||
|
|
||||||
|
FHDL differs from MyHDL [2] in fundamental ways. MyHDL follows the
|
||||||
|
event-driven paradigm of traditional HDLs (see Background, #1) while FHDL
|
||||||
|
separates the code into combinatorial statements, synchronous statements,
|
||||||
|
and reset values. In MyHDL, the logic is described directly in the Python
|
||||||
|
AST. The converter to Verilog or VHDL then examines the Python AST and
|
||||||
|
recognizes a subset of Python that it translates into V*HDL statements.
|
||||||
|
This seriously impedes the capability of MyHDL to generate logic
|
||||||
|
procedurally. With FHDL, you manipulate a custom AST from Python, and you
|
||||||
|
can more easily design algorithms that operate on it.
|
||||||
|
|
||||||
|
FHDL is made of several elements, which are briefly explained below.
|
||||||
|
|
||||||
|
BV
|
||||||
|
--
|
||||||
|
The bit vector (BV) object defines if a constant or signal is signed or
|
||||||
|
unsigned, and how many bits it has. This is useful e.g. to:
|
||||||
|
- determine when to perform sign extension (FHDL uses the same rules as
|
||||||
|
Verilog).
|
||||||
|
- determine the size of registers.
|
||||||
|
- determine how many bits should be used by each value in
|
||||||
|
concatenations.
|
||||||
|
|
||||||
|
Constant
|
||||||
|
--------
|
||||||
|
This object should be self-explanatory. All constant objects contain a BV
|
||||||
|
object and a value. If no BV object is specified, one will be made up
|
||||||
|
using the following rules:
|
||||||
|
- If the value is positive, the BV is unsigned and has the minimum
|
||||||
|
number of bits needed to represent the constant's value in the canonical
|
||||||
|
base-2 system.
|
||||||
|
- If the value is negative, the BV is signed, and has the minimum
|
||||||
|
number of bits needed to represent the constant's value in the canonical
|
||||||
|
two's complement, base-2 system.
|
||||||
|
|
||||||
|
Signal
|
||||||
|
------
|
||||||
|
The signal object represents a value that is expected to change in the
|
||||||
|
circuit. It does exactly what Verilog's "wire" and "reg" and VHDL's
|
||||||
|
"signal" and "variable" do.
|
||||||
|
|
||||||
|
The main point of the signal object is that it is identified by its
|
||||||
|
Python ID (as returned by the id() function), and nothing else. It is the
|
||||||
|
responsibility of the V*HDL back-end to establish an injective mapping
|
||||||
|
between Python IDs and the V*HDL namespace. It should perform name
|
||||||
|
mangling to ensure this. The consequence of this is that signal objects
|
||||||
|
can safely become members of arbitrary Python classes, or be passed as
|
||||||
|
parameters to functions or methods that generate logic involving them.
|
||||||
|
|
||||||
|
The properties of a signal object are:
|
||||||
|
- a bit vector description
|
||||||
|
- a name, used as a hint for the V*HDL back-end name mangler.
|
||||||
|
- a boolean "variable". If true, the signal will behave like a VHDL
|
||||||
|
variable, or a Verilog reg that uses blocking assignment. This parameter
|
||||||
|
only has an effect when the signal's value is modified in a synchronous
|
||||||
|
statement.
|
||||||
|
- the signal's reset value. It must be an integer, and defaults to 0.
|
||||||
|
When the signal's value is modified with a synchronous statement, the
|
||||||
|
reset value is the initialization value of the associated register.
|
||||||
|
When the signal is assigned to in a conditional combinatorial statement
|
||||||
|
(If or Case), the reset value is the value that the signal has when no
|
||||||
|
condition that causes the signal to be driven is verified. This enforces
|
||||||
|
the absence of latches in designs. If the signal is permanently driven
|
||||||
|
using a combinatorial statement, the reset value has no effect.
|
||||||
|
|
||||||
|
The sole purpose of the name property is to make the generated V*HDL code
|
||||||
|
easier to understand and debug. From a purely functional point of view,
|
||||||
|
it is perfectly OK to have several signals with the same name property.
|
||||||
|
The back-end will generate a unique name for each object. If no name
|
||||||
|
property is specified, Migen will analyze the code that created the
|
||||||
|
signal object, and try to extract the variable or member name from there.
|
||||||
|
It then uses the module name that created the signal, a underscore, and
|
||||||
|
the variable name. For example, if we are in module "foo", the following
|
||||||
|
statements will create one or several signal(s) named "foo_bar":
|
||||||
|
bar = Signal()
|
||||||
|
self.bar = Signal()
|
||||||
|
self.baz.bar = Signal()
|
||||||
|
bar = [Signal() for x in range(42)]
|
||||||
|
|
||||||
|
Operators
|
||||||
|
---------
|
||||||
|
Operators are represented by the _Operator object, which generally should
|
||||||
|
not be used directly. Instead, most FHDL objects overload the usual
|
||||||
|
Python logic and arithmetic operators, which allows a much lighter syntax
|
||||||
|
to be used. For example, the expression:
|
||||||
|
a * b + c
|
||||||
|
is equivalent to:
|
||||||
|
_Operator('+', [_Operator('*', [a, b]), c])
|
||||||
|
|
||||||
|
Slices
|
||||||
|
------
|
||||||
|
Likewise, slices are represented by the _Slice object, which often should
|
||||||
|
not be used in favor of the Python slice operation [x:y].
|
||||||
|
Implicit indices using the forms [x], [x:] and [:y] are supported.
|
||||||
|
Beware! Slices work like Python slices, not like VHDL or Verilog slices.
|
||||||
|
The first bound is the index of the LSB and is inclusive. The second
|
||||||
|
bound is the index of MSB and is exclusive. In V*HDL, bounds are MSB:LSB
|
||||||
|
and both are inclusive.
|
||||||
|
|
||||||
|
Concatenations
|
||||||
|
--------------
|
||||||
|
Concatenations are done using the Cat object. To make the syntax lighter,
|
||||||
|
its constructor takes a variable number of arguments, which are the
|
||||||
|
signals to be concatenated together (you can use the Python '*' operator
|
||||||
|
to pass a list instead).
|
||||||
|
To be consistent with slices, the first signal is connected to the bits
|
||||||
|
with the lowest indices in the result. This is the opposite of the way
|
||||||
|
the '{}' construct works in Verilog.
|
||||||
|
|
||||||
|
Replications
|
||||||
|
------------
|
||||||
|
The Replicate object represents the equivalent of {count{expression}} in
|
||||||
|
Verilog.
|
||||||
|
|
||||||
|
Assignments
|
||||||
|
-----------
|
||||||
|
Assignments are represented with the _Assign object. Since using it
|
||||||
|
directly would result in a cluttered syntax, the preferred technique for
|
||||||
|
assignments is to use the eq() method provided by objects that can have a
|
||||||
|
value assigned to them. They are signals, and their combinations with the
|
||||||
|
slice and concatenation operators.
|
||||||
|
As an example, the statement:
|
||||||
|
a[0].eq(b)
|
||||||
|
is equivalent to:
|
||||||
|
_Assign(_Slice(a, 0, 1), b)
|
||||||
|
|
||||||
|
If statement
|
||||||
|
------------
|
||||||
|
The If object takes a first parameter which must be an expression
|
||||||
|
(combination of the Constant, Signal, _Operator, _Slice, etc. objects)
|
||||||
|
representing the condition, then a variable number of parameters
|
||||||
|
representing the statements (_Assign, If, Case, etc. objects) to be
|
||||||
|
executed when the condition is verified.
|
||||||
|
|
||||||
|
The If object defines a Else() method, which when called defines the
|
||||||
|
statements to be executed when the condition is not true. Those
|
||||||
|
statements are passed as parameters to the variadic method.
|
||||||
|
|
||||||
|
For convenience, there is also a Elif() method.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
If(tx_count16 == 0,
|
||||||
|
tx_bitcount.eq(tx_bitcount + 1),
|
||||||
|
If(tx_bitcount == 8,
|
||||||
|
self.tx.eq(1)
|
||||||
|
).Elif(tx_bitcount == 9,
|
||||||
|
self.tx.eq(1),
|
||||||
|
tx_busy.eq(0)
|
||||||
|
).Else(
|
||||||
|
self.tx.eq(tx_reg[0]),
|
||||||
|
tx_reg.eq(Cat(tx_reg[1:], 0))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
Case statement
|
||||||
|
--------------
|
||||||
|
The Case object constructor takes as first parameter the expression to be
|
||||||
|
tested, then a variable number of lists describing the various cases.
|
||||||
|
|
||||||
|
Each list contains an expression (typically a constant) describing the
|
||||||
|
value to be matched, followed by the statements to be executed when there
|
||||||
|
is a match. The head of the list can be the an instance of the Default
|
||||||
|
object.
|
||||||
|
|
||||||
|
Instances
|
||||||
|
---------
|
||||||
|
Instance objects represent the parametrized instantiation of a V*HDL
|
||||||
|
module, and the connection of its ports to FHDL signals. They are useful
|
||||||
|
in a number of cases:
|
||||||
|
- reusing legacy or third-party V*HDL code.
|
||||||
|
- using special FPGA features (DCM, ICAP, ...).
|
||||||
|
- implementing logic that cannot be expressed with FHDL (asynchronous
|
||||||
|
circuits, ...).
|
||||||
|
- breaking down a Migen system into multiple sub-systems, possibly
|
||||||
|
using different clock domains.
|
||||||
|
|
||||||
|
The properties of the instance object are:
|
||||||
|
- the type of the instance (i.e. name of the instantiated module).
|
||||||
|
- a list of output ports of the instantiated module. Each element of
|
||||||
|
the list is a pair containing a string, which is the name of the
|
||||||
|
module's port, and either an existing signal (on which the port will
|
||||||
|
be connected to) or a BV (which will cause the creation of a new
|
||||||
|
signal).
|
||||||
|
- a list of input ports (likewise).
|
||||||
|
- a list of (name, value) pairs for the parameters ("generics" in VHDL)
|
||||||
|
of the module.
|
||||||
|
- the name of the clock port of the module (if any). If this is
|
||||||
|
specified, the port will be connected to the system clock.
|
||||||
|
- the name of the reset port of the module (likewise).
|
||||||
|
- the name of the instance (can be mangled like signal names).
|
||||||
|
|
||||||
|
Memories
|
||||||
|
--------
|
||||||
|
Memories (on-chip SRAM) are not supported, but will be soon, using a
|
||||||
|
mechanism similar to instances. (TODO)
|
||||||
|
|
||||||
|
Fragments
|
||||||
|
---------
|
||||||
|
A "fragment" is a unit of logic, which is composed of:
|
||||||
|
- a list of combinatorial statements.
|
||||||
|
- a list of synchronous statements.
|
||||||
|
- a list of instances.
|
||||||
|
- a list of memories.
|
||||||
|
- a set of pads, which are signals intended to be connected to
|
||||||
|
off-chip devices.
|
||||||
|
|
||||||
|
Fragments can reference arbitrary signals, including signals that are
|
||||||
|
referenced in other fragments. Fragments can be combined using the "+"
|
||||||
|
operator, which returns a new fragment containing the concatenation of
|
||||||
|
each pair of lists.
|
||||||
|
|
||||||
|
Fragments can be passed to the back-end for conversion to Verilog.
|
||||||
|
|
||||||
|
By convention, classes that generate logic implement a method called
|
||||||
|
"get_fragment". When called, this method builds a new fragment
|
||||||
|
implementing the desired functionality of the class, and returns it. This
|
||||||
|
convention allows fragments to be built automatically by combining the
|
||||||
|
fragments from all relevant objects in the local scope, by using the
|
||||||
|
autofragment module.
|
||||||
|
|
||||||
|
Migen Core Logic
|
||||||
|
================
|
||||||
|
Migen Core Logic is a convenience library of common logic circuits
|
||||||
|
implemented using FHDL:
|
||||||
|
- a multi-cycle integer divider.
|
||||||
|
- a round-robin arbiter, useful to build bus arbiters.
|
||||||
|
- a multiplexer bank (multimux), useful to multiplex composite
|
||||||
|
(grouped) signals.
|
||||||
|
- a condition-triggered static scheduler of FHDL synchronous statements
|
||||||
|
(timeline).
|
||||||
|
|
||||||
|
Migen Bus
|
||||||
|
=========
|
||||||
|
Migen Bus contains classes providing a common structure for master and
|
||||||
|
slave interfaces of the following buses:
|
||||||
|
- Wishbone [5], the general purpose bus recommended by Opencores.
|
||||||
|
- CSR-NG, a low-bandwidth, resource-sensitive bus designed for
|
||||||
|
accessing the configuration and status registers of cores from
|
||||||
|
software.
|
||||||
|
- FastMemoryLink-NG, a split-transaction bus optimized for use with a
|
||||||
|
high-performance, out-of-order SDRAM controller. (TODO)
|
||||||
|
|
||||||
|
It also provides interconnect components for these buses, such as
|
||||||
|
arbiters and address decoders. The strength of the Migen procedurally
|
||||||
|
generated logic can be illustrated by the following example:
|
||||||
|
wbcon = wishbone.InterconnectShared(
|
||||||
|
[cpu.ibus, cpu.dbus, ethernet.dma, audio.dma],
|
||||||
|
[(0, norflash.bus), (1, wishbone2fml.wishbone),
|
||||||
|
(3, wishbone2csr.wishbone)])
|
||||||
|
In this example, the interconnect component generates a 4-way round-robin
|
||||||
|
arbiter, multiplexes the master bus signals into a shared bus, determines
|
||||||
|
that the address decoding must occur on 2 bits, and connects all slave
|
||||||
|
interfaces to the shared bus, inserting the address decoder logic in the
|
||||||
|
bus cycle qualification signals and multiplexing the data return path. It
|
||||||
|
can recognize the signals in each core's bus interface thanks to the
|
||||||
|
common structure mandated by Migen Bus. All this happens automatically,
|
||||||
|
using only that much user code. The resulting interconnect logic can be
|
||||||
|
retrieved using wbcon.get_fragment(), and combined with the fragments
|
||||||
|
from the rest of the system.
|
||||||
|
|
||||||
|
Migen Bank
|
||||||
|
==========
|
||||||
|
Migen Bank is a system comparable to wishbone-gen [6], which automates
|
||||||
|
the creation of configuration and status register banks and
|
||||||
|
(TODO) interrupt/event managers implemented in cores.
|
||||||
|
|
||||||
|
Bank takes a description made up of a list of registers and generates
|
||||||
|
logic implementing it with a slave interface compatible with Migen Bus.
|
||||||
|
|
||||||
|
A register can be "raw", which means that the core has direct access to
|
||||||
|
it. It also means that the register width must be less or equal to the
|
||||||
|
bus word width. In that case, the register object provides the following
|
||||||
|
signals:
|
||||||
|
- dev_r, which contains the data written from the bus interface.
|
||||||
|
- dev_re, which is the strobe signal for dev_r. It is active for one
|
||||||
|
cycle, after or during a write from the bus. dev_r is only valid when
|
||||||
|
dev_re is high.
|
||||||
|
- dev_w, which must provide at all times the value to be read from the
|
||||||
|
bus.
|
||||||
|
|
||||||
|
Registers that are not raw are managed by Bank and contain fields. If the
|
||||||
|
sum of the widths of all fields attached to a register exceeds the bus
|
||||||
|
word width, the register will automatically be sliced into words of the
|
||||||
|
maximum size and implemented at consecutive bus addresses, MSB first.
|
||||||
|
Field objects have two parameters, access_bus and access_dev, determining
|
||||||
|
respectively the access policies for the bus and core sides. They can
|
||||||
|
take the values READ_ONLY, WRITE_ONLY and READ_WRITE.
|
||||||
|
If the device can read, the field object provides the dev_r signal, which
|
||||||
|
contains at all times the current value of the field (kept by the logic
|
||||||
|
generated by Bank).
|
||||||
|
If the device can write, the field object provides the following signals:
|
||||||
|
- dev_w, which provides the value to be written into the field.
|
||||||
|
- dev_we, which strobes the value into the field.
|
||||||
|
|
||||||
|
Migen Flow (TODO)
|
||||||
|
==========
|
||||||
|
Many hardware acceleration problems can be expressed in the dataflow
|
||||||
|
paradigm, that is, using a directed graph representing the flow of data
|
||||||
|
between actors.
|
||||||
|
|
||||||
|
Actors in Migen are written directly in FHDL. This maximizes the
|
||||||
|
flexibility: for example, an actor can implement a DMA master to read
|
||||||
|
data from system memory. It is conceivable that a CAL [7] to FHDL
|
||||||
|
compiler be implemented at some point, to support higher level
|
||||||
|
descriptions of some actors and reuse of third-party RVC-CAL
|
||||||
|
applications. [8] [9] [10]
|
||||||
|
|
||||||
|
Actors communicate by exchanging tokens, whose flow is typically
|
||||||
|
controlled using handshake signals (strobe/ack).
|
||||||
|
|
||||||
|
Each actor has a "scheduling model". It can be:
|
||||||
|
- N-sequential: the actor fires when tokens are available at all its
|
||||||
|
inputs, and it produces one output token after N cycles. It cannot
|
||||||
|
accept new input tokens until it has produced its output. A
|
||||||
|
multicycle integer divider would use this model.
|
||||||
|
- N-pipelined: similar to the sequential model, but the actor can
|
||||||
|
always accept new input tokens. It produces an output token N cycles
|
||||||
|
of latency after accepting input tokens. A pipelined multiplier would
|
||||||
|
use this model.
|
||||||
|
- Dynamic: the general case, when no simple hypothesis can be made on
|
||||||
|
the token flow behaviour of the actor. An actor accessing system
|
||||||
|
memory on a shared bus would use this model.
|
||||||
|
|
||||||
|
Migen Flow automatically generates handshake logic for the first two
|
||||||
|
scheduling models. In the third case, the FHDL descriptions for the logic
|
||||||
|
driving the handshake signals must be provided by the actor.
|
||||||
|
|
||||||
|
If sequential or pipelined actors are connected together, Migen Flow will
|
||||||
|
attempt to find a static schedule, remove the handshake signals, optimize
|
||||||
|
away the control logic in each actor and replace it with a centralized
|
||||||
|
FSM implementing the static schedule.
|
||||||
|
|
||||||
|
An actor can be a composition of other actors.
|
||||||
|
|
||||||
|
Actor graphs are managed using the NetworkX [11] library.
|
||||||
|
|
||||||
|
|
||||||
|
References:
|
||||||
|
[ 1] http://milkymist.org
|
||||||
|
[ 2] http://www.myhdl.org
|
||||||
|
[ 3] http://milkymist.org/thesis/thesis.pdf
|
||||||
|
[ 4] http://www.xilinx.com/publications/archives/xcell/Xcell77.pdf p30-35
|
||||||
|
[ 5] http://cdn.opencores.org/downloads/wbspec_b4.pdf
|
||||||
|
[ 6] http://www.ohwr.org/projects/wishbone-gen
|
||||||
|
[ 7] http://opendf.svn.sourceforge.net/viewvc/opendf/trunk/doc/
|
||||||
|
GentleIntro/GentleIntro.pdf
|
||||||
|
[ 8] http://orcc.sourceforge.net/
|
||||||
|
[ 9] http://orc-apps.sourceforge.net/
|
||||||
|
[10] http://opendf.sourceforge.net/
|
||||||
|
[11] http://networkx.lanl.gov/
|
224
doc/migen_logo.svg
Normal file
224
doc/migen_logo.svg
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="159.05869"
|
||||||
|
height="106.55"
|
||||||
|
id="svg3245"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.1 r9760"
|
||||||
|
sodipodi:docname="migen.svg"
|
||||||
|
inkscape:export-filename="/home/lekernel/migen.png"
|
||||||
|
inkscape:export-xdpi="184.10001"
|
||||||
|
inkscape:export-ydpi="184.10001">
|
||||||
|
<defs
|
||||||
|
id="defs3247">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient6093">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#2ca22c;stop-opacity:0;"
|
||||||
|
offset="0"
|
||||||
|
id="stop6095" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#2ca22c;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop6097" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient6047">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop6049" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop6051" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#a"
|
||||||
|
id="linearGradient6176"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.24477,0,0,0.24477,203.271,213.559)"
|
||||||
|
x1="150.95"
|
||||||
|
y1="-22.384001"
|
||||||
|
x2="252.2"
|
||||||
|
y2="204.03999" />
|
||||||
|
<linearGradient
|
||||||
|
id="a"
|
||||||
|
y2="150.32001"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y1="13.899"
|
||||||
|
x2="200.5"
|
||||||
|
x1="200.5">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#fff"
|
||||||
|
offset=".1374"
|
||||||
|
id="stop7" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#509e10;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop9" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#a"
|
||||||
|
id="linearGradient3345"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.24477,0,0,0.24477,203.271,213.559)"
|
||||||
|
x1="150.95"
|
||||||
|
y1="-22.384001"
|
||||||
|
x2="252.2"
|
||||||
|
y2="204.03999" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#a"
|
||||||
|
id="linearGradient3349"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.24477,0,0,0.24477,280.71427,440.33237)"
|
||||||
|
x1="150.95"
|
||||||
|
y1="-22.384001"
|
||||||
|
x2="252.2"
|
||||||
|
y2="204.03999" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient6047"
|
||||||
|
id="linearGradient6053"
|
||||||
|
x1="178.04323"
|
||||||
|
y1="474.42865"
|
||||||
|
x2="235.87062"
|
||||||
|
y2="474.42865"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.78422775,0,0,1,105.91918,-2.4999996)" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient6093"
|
||||||
|
id="linearGradient6099"
|
||||||
|
x1="242.87946"
|
||||||
|
y1="471.54514"
|
||||||
|
x2="289.73526"
|
||||||
|
y2="471.54514"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,1.1424088,0,-67.150429)" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="2.8"
|
||||||
|
inkscape:cx="134.13698"
|
||||||
|
inkscape:cy="59.325232"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1916"
|
||||||
|
inkscape:window-height="1117"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0" />
|
||||||
|
<metadata
|
||||||
|
id="metadata3250">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-242.87946,-440.32929)">
|
||||||
|
<rect
|
||||||
|
style="fill:url(#linearGradient6099);fill-opacity:1;stroke:none"
|
||||||
|
id="rect6043"
|
||||||
|
width="66.843575"
|
||||||
|
height="23.704336"
|
||||||
|
x="242.87946"
|
||||||
|
y="459.6947" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path29"
|
||||||
|
d="m 366.02427,471.24237 c -22.519,36.716 -73.921,29.454 -73.921,29.454 32.229,-32.229 0.16326,-57.929 0.16326,-57.929 0,0 51.973,-7.996 73.758,28.475"
|
||||||
|
style="font-size:18px;fill:#00ad00;fill-opacity:1;font-family:'DejaVu Sans, Arial, Sans'" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path31"
|
||||||
|
d="m 366.02427,471.24237 c -22.519,36.716 -73.921,29.454 -73.921,29.454 32.229,-32.229 0.16326,-57.929 0.16326,-57.929 0,0 51.973,-7.996 73.758,28.475"
|
||||||
|
style="font-size:18px;fill:none;font-family:'DejaVu Sans, Arial, Sans'" />
|
||||||
|
<path
|
||||||
|
style="font-size:18px;font-family:'DejaVu Sans, Arial, Sans'"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path33"
|
||||||
|
d="m 364.64427,470.43237 c -5.3108,8.6038 -12.825,15.435 -21.719,20.199 -7.7214,4.1357 -16.268,6.5868 -24.897,7.9228 -6.0011,0.92916 -12.11,1.2491 -18.178,1.0907 -1.8804,-0.0489 -3.76,-0.15102 -5.6339,-0.31747 -0.51696,-0.046 -1.0334,-0.0977 -1.5489,-0.15739 -0.29226,-0.0338 -0.85842,-0.11431 -0.14808,-0.0144 0.234,0.88632 0.468,1.7726 0.702,2.6592 8.3771,-8.431 15.128,-19.206 14.819,-31.472 -0.20072,-7.9507 -3.4638,-15.551 -8.2374,-21.816 -1.8852,-2.4739 -3.9815,-4.9329 -6.418,-6.8911 -0.234,0.88633 -0.46801,1.7729 -0.70201,2.6592 0.61487,-0.0942 -0.31747,0.0377 0.24551,-0.0343 0.60361,-0.0769 1.2087,-0.14221 1.814,-0.20194 2.1765,-0.21442 4.3616,-0.33925 6.5477,-0.40461 7.0088,-0.20928 14.057,0.24796 20.959,1.4953 7.9781,1.442 15.783,3.9756 22.86,7.9654 8.0388,4.532 14.777,11.012 19.535,18.924 1.0557,1.756 3.8079,0.15739 2.7476,-1.606 -5.1914,-8.6336 -12.6,-15.613 -21.408,-20.474 -7.7483,-4.275 -16.361,-6.8644 -25.074,-8.2486 -9.4825,-1.5066 -19.54,-1.944 -29.073,-0.48367 -1.1345,0.17379 -1.5874,1.9477 -0.70201,2.6592 3.0624,2.4612 5.6283,5.6205 7.7454,8.8104 4.5202,6.8118 6.9303,14.977 5.6423,23.154 -1.4588,9.2607 -7.0781,17.201 -13.551,23.715 -0.75977,0.76492 -0.53067,2.4859 0.70201,2.6592 9.9738,1.4023 20.482,0.7025 30.334,-1.1362 8.4689,-1.5805 16.759,-4.3922 24.256,-8.6664 8.6297,-4.9199 15.91,-11.93 21.128,-20.383 1.0812,-1.7514 -1.6723,-3.3482 -2.7473,-1.606 z" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path35"
|
||||||
|
d="m 295.19427,443.74237 c 0,0 12.67,11.257 12.67,27.475 0,0 9.8236,-9.7551 23.069,0 0,0 15.098,13.305 33.229,0 0,0 -15.539,-32.087 -68.968,-27.475 z"
|
||||||
|
style="font-size:18px;fill:url(#linearGradient3349);fill-opacity:1;font-family:'DejaVu Sans, Arial, Sans'" />
|
||||||
|
<line
|
||||||
|
id="line39"
|
||||||
|
y2="471.03238"
|
||||||
|
x2="400.71429"
|
||||||
|
y1="471.03238"
|
||||||
|
x1="366.79425"
|
||||||
|
style="font-size:18px;fill:none;stroke:#000000;stroke-width:2.44770002;font-family:'DejaVu Sans, Arial, Sans'" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path59"
|
||||||
|
d="m 344.15733,461.16448 4.84652,0"
|
||||||
|
style="font-size:18px;fill:none;stroke:#000000;stroke-width:2.44799995;stroke-miterlimit:4;stroke-dasharray:none;font-family:'DejaVu Sans, Arial, Sans'"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cc"
|
||||||
|
style="font-size:18px;fill:none;stroke:#000000;stroke-width:2.44799995;stroke-miterlimit:4;stroke-dasharray:none;font-family:'DejaVu Sans, Arial, Sans'"
|
||||||
|
d="m 344.15733,481.90109 4.84652,0"
|
||||||
|
id="path6037"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Orbitron;-inkscape-font-specification:Orbitron Light"
|
||||||
|
x="257.14285"
|
||||||
|
y="537.7193"
|
||||||
|
id="text6055"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan6057"
|
||||||
|
x="257.14285"
|
||||||
|
y="537.7193">migen</tspan></text>
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cc"
|
||||||
|
style="font-size:18px;fill:none;stroke:#000000;stroke-width:2.61650872;stroke-miterlimit:4;stroke-dasharray:none;font-family:'DejaVu Sans, Arial, Sans'"
|
||||||
|
d="m 289.42519,459.68794 14.57866,0"
|
||||||
|
id="path6105"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path6107"
|
||||||
|
d="m 289.42519,483.37763 14.57866,0"
|
||||||
|
style="font-size:18px;fill:none;stroke:#000000;stroke-width:2.61650872;stroke-miterlimit:4;stroke-dasharray:none;font-family:'DejaVu Sans, Arial, Sans'"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After (image error) Size: 9 KiB |
Loading…
Reference in a new issue