README: structure + FHDL description
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 19 Dec 2011 21:15:10 +0000 (22:15 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 19 Dec 2011 21:15:10 +0000 (22:15 +0100)
README [new file with mode: 0644]

diff --git a/README b/README
new file mode 100644 (file)
index 0000000..7974e60
--- /dev/null
+++ b/README
@@ -0,0 +1,367 @@
+             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 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 be() 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].be(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.be(tx_bitcount + 1),
+       If(tx_bitcount == 8,
+               self.tx.be(1)
+       ).Elif(tx_bitcount == 9,
+               self.tx.be(1),
+               tx_busy.be(0)
+       ).Else(
+               self.tx.be(tx_reg[0]),
+               tx_reg.be(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 Bus
+=========
+
+  - 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)
+
+Migen Bank
+==========
+
+
+Migen Flow
+==========
+
+(TODO: there is no implementation of Migen Flow in the repository yet)
+
+
+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
+
+Practical information
+=====================
+Code repository:
+https://github.com/milkymist/migen
+Experimental version of the Milkymist SoC based on Migen:
+https://github.com/milkymist/milkymist-ng
+
+Migen is designed for Python 3.2.
+
+Send questions, comments and patches to devel [AT] lists.milkymist.org
+We are also on IRC: #milkymist on the Freenode network.
+
+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
+Software Foundation, version 3 of the License. This program is
+distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or 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
+Sebastien Bourdeauducq. Authors retain ownership of their contributions.