From 2cf26ba655e59937f5a52aa50db2d97538d1fdde Mon Sep 17 00:00:00 2001 From: azidar Date: Wed, 13 May 2015 10:42:36 -0700 Subject: Updated Spec. Added scoped-reg which exposes on-reset bug. Fixed lowering bug --- TODO | 11 +- notes/primop-inference.txt | 39 +- spec/spec.pdf | Bin 144166 -> 142340 bytes spec/spec.tex | 727 +++++++++++++++----------------- src/main/stanza/errors.stanza | 120 ++++-- src/main/stanza/passes.stanza | 41 +- test/chisel3/Memory.fir | 204 +++++++++ test/passes/expand-whens/scoped-reg.fir | 12 + test/passes/lower-to-ground/test.fir | 13 + 9 files changed, 725 insertions(+), 442 deletions(-) create mode 100644 test/chisel3/Memory.fir create mode 100644 test/passes/expand-whens/scoped-reg.fir create mode 100644 test/passes/lower-to-ground/test.fir diff --git a/TODO b/TODO index e2f8b339..2f58ab0d 100644 --- a/TODO +++ b/TODO @@ -3,6 +3,9 @@ ================================================ ======== Current Tasks ======== +Declared references needs to understand scope +Size of vector type must be non-negative +Check for recursively defined instances Update spec <> Add Unit Tests for each pass @@ -10,9 +13,13 @@ Add Unit Tests for each pass Push all tests entirely through Check after each pass write test that checks instance types are correctly lowered +move width inference earlier ======== Update Core ========== Add source locaters +Add exmodule +Add vptype +Add readwriteport ======== Check Passes ========== Well-formed high firrtl @@ -83,7 +90,9 @@ Convert to scala Firrtl interpreter (in scala) ======== Update Spec ======== -Add Not to spec +Look through all primops +change parser to other unknown thing for vptype? +Add optional type to node add assertions and printfs cannot connect directly to a mem (loc can never contain a mem) Front-end needs to guarantee unique names per module. diff --git a/notes/primop-inference.txt b/notes/primop-inference.txt index ec704ba6..7c1cd43b 100644 --- a/notes/primop-inference.txt +++ b/notes/primop-inference.txt @@ -1,3 +1,28 @@ +Support on-reset for now, but it will get deprecated. It was originally included to make it easier for the front-end to support Vec(Reg), but since this was a bad decision in Chisel, we shouldn't muddy up FIRRTL to compensate. + For now, we will add which of the reset signal for registers in their declaration, so on-reset will use that instead of the implicit reset +Delete implicit reset, always make it explicit +Clock will be a subtype of Port. Need to make sure it isn't used in any logic. It will be included in the declaration of registers. + +Primops - Different widths +Backends will emit different things based on the type of the input arguments, and the widths. +e.g. +SInt<7> + SInt<4> +For C++ : need to sign-extend SInt<4> and add to SInt<7> +For Verilog : Emit as is, which will generate a 4-bit add and an increment circuit +Verilog does not want it sign extended, so we should not ensure that widths should be different +For backends that need strict width inference, you should write your own padding pass, and checking pass. + +Primops - Input Type dependence +To simplify all passes other than the backend, only the generic ops will be supported. All combinations (-uu,-us,...) that actually require different behaviors will need to look at the type of the operands. +We decided to make a resolve&check pass that is separate from lowering, and is done immediately after parsing the file. This will do all the type inference. By making this pass available, the backends can + guarantee the in-memory AST will have types and be type-checked. + +Assignment - expanding? +We didn't discuss this, but my hunch is we should make it loose in that it allows connections of a smaller width expression to a larger width expression + + + + The design of the primitive operations follows the following principles: (1) if operand types are known (i.e. FIRRTL front-end), primops whose return type is statically known (no future type introspection needed) are available (2) if operand types are not known (i.e. hand-writing FIRRTL pass), generic primops can be used, and a future pass will perform type introspection to replace the generic with the specific primop @@ -36,15 +61,21 @@ div divus(a,b) -> s,a.w+1 ; if divide by -1 divsu(a,b) -> s,a.w ; if divide by 1 divss(a,b) -> s,a.w+1 ; if divide by -1 - + +quo + quouu -> u, a.w + quous -> s, a.w + 1 + quosu -> s, a.w + quoss -> u, a.w + 1 + mod moduu(a,d) -> u,d.w - modus(a,d) -> u,d.w-1 + modus(a,d) -> u,d.w modsu(a,d) -> u,d.w - modss(a,d) -> u,d.w-1 + modss(a,d) -> u,d.w rem - remuu(a,b) -> u,min(a.w,b.w) ; 15 % 16 = 15. All remainders must be less than b or a. + remuu(a,b) -> u,b.w ; 15 % 16 = 15. All remainders must be less than b or a. remus(a,b) -> u,b.w ; -1 % 32 = 31. Remainder can be larger than abs(a), but not larger than b. remsu(a,b) -> s,b.w ; 1 % -32 = -31. abs(rem) can be larger than abs(a), but not larger than abs(b). remss(a,b) -> s,b.w ; strictly superset of us and su. diff --git a/spec/spec.pdf b/spec/spec.pdf index f8a00185..504a511b 100644 Binary files a/spec/spec.pdf and b/spec/spec.pdf differ diff --git a/spec/spec.tex b/spec/spec.tex index f7f1a2ee..3d4611e2 100644 --- a/spec/spec.tex +++ b/spec/spec.tex @@ -1,4 +1,4 @@ -\title{Specification for the FIRRTL Language: Version 0.1.0} +\title{Specification for the FIRRTL Language: Version 0.1.1} \author{Patrick S. Li, Adam M. Izraelevitz, Jonathan Bachrach} \documentclass[12pt]{article} \usepackage{listings} @@ -32,42 +32,38 @@ &\vert &\info \kw{exmodule} \id \kw{:} (\pd{port*}) &\text{External Module}\\ \pd{port} &= &\info \pd{dir} \id \kw{:} \pd{type} &\text{Port}\\ \pd{dir} &= &\kws{input} \vert \kws{output} &\text{Input/Output}\\ -\pd{type} &= &\kws{UInt}(\pd{width}) &\text{Unsigned Integer}\\ - &\vert &\kws{SInt}(\pd{width}) &\text{Signed Integer}\\ +\pd{type} &= &\kws{UInt}<\pd{width}> &\text{Unsigned Integer}\\ + &\vert &\kws{SInt}<\pd{width}> &\text{Signed Integer}\\ &\vert &\bundleT{\pd{field*}} &\text{Bundle}\\ &\vert &\pds{type}[\ints] &\text{Vector}\\ -\pd{field} &= &\pd{gender} \id \kw{:} \pd{type} &\text{Bundle Field}\\ -\pd{gender} &= &\kws{female} \vert \kws{male} &\text{Gender}\\ -\pd{vptype} &= &\kws{read} \vert \kws{write} \vert \kws{rdwr} &\text{Known Vector Port-Type}\\ - &\vert &\kw{?} &\text{Unknown Vector Port-Type}\\ +\pd{field} &= &\pd{orientation} \id \kw{:} \pd{type} &\text{Bundle Field}\\ +\pd{orientation}&= &\kws{default} \vert \kws{reverse} &\text{Orientation}\\ \pd{width} &= &\ints &\text{Known Integer Width}\\ &\vert &\kw{?} &\text{Unknown Width}\\ +\pd{atype} &= &\kws{read} \vert \kws{write} \vert \kws{unknown} &\text{Accessor Type}\\ \pd{stmt} &= &\info \kw{wire} \id \kw{:} \pd{type} &\text{Wire Declaration}\\ &\vert &\info \kw{reg} \id \kw{:} \pd{type} &\text{Register Declaration}\\ &\vert &\info \kw{mem} \id \kw{:} \pd{type} &\text{Memory Declaration}\\ - &\vert &\info \kw{inst} \id \kw{of} \id &\text{Instance Declaration}\\ + &\vert &\info \kw{inst} \id \kw{:} \id &\text{Instance Declaration}\\ &\vert &\info \kw{node} \id = \pd{exp} &\text{Node Declaration}\\ - &\vert &\info \pd{vptype} \kw{accessor} \id = \pds{exp}[\pds{exp}] &\text{Accessor Declaration}\\ + &\vert &\info \pd{atype} \kw{accessor} \id = \pds{exp}[\pds{exp}] &\text{Accessor Declaration}\\ &\vert &\info \pd{exp} \kw{:=} \pd{exp} &\text{Connect}\\ + &\vert &\info \kw{on-reset} \pd{exp} \kw{:=} \pd{exp} &\text{On Reset}\\ &\vert &\info \kw{when} \pd{exp} \kw{:} \pd{stmt} \kw{else :} \pd{stmt} &\text{Conditional}\\ &\vert &\info (\pd{stmt*}) &\text{Statement Group}\\ &\vert &\info \kw{skip} &\text{Empty Statement}\\ -\pd{exp} &= &\info \kws{UInt}(\ints, \pds{width}) &\text{Literal Unsigned Integer}\\ - &\vert &\info \kws{SInt}(\ints, \pds{width}) &\text{Literal Signed Integer}\\ +\pd{exp} &= &\info \kws{UInt}<\pds{width}>(ints) &\text{Literal Unsigned Integer}\\ + &\vert &\info \kws{SInt}<\pds{width}>(ints) &\text{Literal Signed Integer}\\ &\vert &\info \id &\text{Reference}\\ &\vert &\info \pds{exp}.\id &\text{Subfield}\\ - &\vert &\info \pds{exp}.\ints &\text{Subindex}\\ - &\vert &\info \kws{Register}(\pds{exp}, \pds{exp}) &\text{Register}\\ + &\vert &\info \pds{exp}[\ints] &\text{Subindex}\\ + &\vert &\info \kws{Register}(\pds{exp}, \pds{exp}) &\text{Structural Register}\\ &\vert &\info \kws{WritePort}(\id, \pds{exp}, \pds{exp}) &\text{Write Port}\\ &\vert &\info \kws{ReadPort}(\id, \pds{exp}, \pds{exp}) &\text{Read Port}\\ - &\vert &\info \kws{ReadWritePort}(\id, \pds{exp}, \pds{exp}) &\text{ReadWrite Port}\\ \end{array} \] \[ \begin{array}{rrll} - &\vert &\info \pds{pad!}(\pds{exp}, \pds{width}) &\text{Generic Pad to Width}\\ - &\vert &\info \pds{pad!-u}(\pds{exp}, \pds{width}) &\text{Unsigned Pad to Width}\\ - &\vert &\info \pds{pad!-s}(\pds{exp}, \pds{width}) &\text{Signed Pad to Width}\\ &\vert &\info \pds{primop}(\pds{exp*}, \ints\text{*}) &\text{Primitive Operation}\\ \pd{info} &= &\text{filename } \kw{:} \text{line} . \text{col} &\text{File Location}\\ &\vert &\kw{noinfo} &\text{No File Location}\\ @@ -77,35 +73,39 @@ \[ \begin{array}{rll} \pd{primop} &= \\ - &\kws{add} \vert \kws{add-uu} \vert \kws{add-us} \vert \kws{add-su} \vert \kws{add-ss} &\text{Unsigned/Signed Add}\\ -\vert &\kws{sub} \vert \kws{sub-uu} \vert \kws{sub-us} \vert \kws{sub-su} \vert \kws{sub-ss} &\text{Unsigned/Signed Subtract}\\ -\vert &\kws{mul} \vert \kws{mul-uu} \vert \kws{mul-us} \vert \kws{mul-su} \vert \kws{mul-ss} &\text{Unsigned/Signed Multiply}\\ -\vert &\kws{div} \vert \kws{div-uu} \vert \kws{div-us} \vert \kws{div-su} \vert \kws{div-ss} &\text{Unsigned/Signed Divide}\\ -\vert &\kws{rem} \vert \kws{rem-uu} \vert \kws{rem-us} \vert \kws{rem-su} \vert \kws{rem-ss} &\text{Unsigned/Signed Remainder}\\ -\vert &\kws{quo} \vert \kws{quo-uu} \vert \kws{quo-us} \vert \kws{quo-su} \vert \kws{quo-ss} &\text{Unsigned/Signed Quotient}\\ -\vert &\kws{mod} \vert \kws{mod-uu} \vert \kws{mod-us} \vert \kws{mod-su} \vert \kws{mod-ss} &\text{Unsigned/Signed Modulo}\\ -\vert &\kws{add-wrap} \vert \kws{add-wrap-uu} \vert \kws{add-wrap-us} \vert &\text{Unsigned/Signed Add Wrap}\\ - &\kws{add-wrap-su} \vert \kws{add-wrap-ss} &\\ -\vert &\kws{sub-wrap} \vert \kws{sub-wrap-uu} \vert \kws{sub-wrap-us} \vert &\text{Unsigned/Signed Subtract Wrap}\\ - &\kws{sub-wrap-su} \vert \kws{sub-wrap-ss} &\\ -\vert &\kws{lt} \vert \kws{lt-uu} \vert \kws{lt-us} \vert \kws{lt-su} \vert \kws{lt-ss} &\text{Unsigned/Signed Less Than}\\ -\vert &\kws{leq} \vert \kws{leq-uu} \vert \kws{leq-us} \vert \kws{leq-su} \vert \kws{leq-ss} &\text{Unsigned/Signed Less or Equal}\\ -\vert &\kws{gt} \vert \kws{gt-uu} \vert \kws{gt-us} \vert \kws{gt-su} \vert \kws{gt-ss} &\text{Unsigned/Signed Greater Than}\\ -\vert &\kws{geq} \vert \kws{geq-uu} \vert \kws{geq-us} \vert \kws{geq-su} \vert \kws{geq-ss} &\text{Unsigned/Signed Greater or Equal}\\ -\vert &\kws{equal} \vert \kws{equal-uu} \vert \kws{equal-ss} &\text{Unsigned/Signed Equal}\\ -\vert &\kws{mux} \vert \kws{mux-uu} \vert \kws{mux-ss} &\text{Unsigned/Signed Multiplex}\\ -\vert &\kws{pad} \vert \kws{pad-u} \vert \kws{pad-s} &\text{Unsigned/Signed Pad to Length}\\ -\vert &\kws{asUInt} \vert \kws{asUInt-u} \vert \kws{asUInt-s} &\text{Unsigned/Signed Reinterpret Bits as UInt}\\ -\vert &\kws{asSInt} \vert \kws{asSInt-u} \vert \kws{asSInt-s} &\text{Unsigned/Signed Reinterpret Bits as SInt}\\ -\vert &\kws{shl} \vert \kws{shl-u} \vert \kws{shl-s} &\text{Unsigned/Signed Shift Left}\\ -\vert &\kws{shr} \vert \kws{shr-u} \vert \kws{shr-s} &\text{Unsigned/Signed Shift Right}\\ -\vert &\kws{convert} \vert \kws{convert-u} \vert \kws{convert-s} &\text{Unsigned to Signed Conversion}\\ -\vert &\kws{not} &\text{Unsigned Not}\\ -\vert &\kws{and} &\text{Unsigned And}\\ -\vert &\kws{or} &\text{Unsigned Or}\\ -\vert &\kws{xor} &\text{Unsigned Xor}\\ -\vert &\kws{concat} &\text{Unsigned Concatenation}\\ -\vert &\kws{bit} \vert \kws{bits} &\text{Single/Multiple Bit Extraction}\\ + &\kws{add} &\text{Unsigned/Signed Add}\\ +\vert &\kws{sub} &\text{Unsigned/Signed Subtract}\\ +\vert &\kws{mul} &\text{Unsigned/Signed Multiply}\\ +\vert &\kws{div} &\text{Unsigned/Signed Divide}\\ +\vert &\kws{rem} &\text{Unsigned/Signed Remainder}\\ +\vert &\kws{quo} &\text{Unsigned/Signed Quotient}\\ +\vert &\kws{mod} &\text{Unsigned/Signed Modulo}\\ +\vert &\kws{add-wrap} &\text{Unsigned/Signed Add Wrap}\\ +\vert &\kws{sub-wrap} &\text{Unsigned/Signed Subtract Wrap}\\ +\vert &\kws{lt} &\text{Unsigned/Signed Less Than}\\ +\vert &\kws{leq} &\text{Unsigned/Signed Less or Equal}\\ +\vert &\kws{gt} &\text{Unsigned/Signed Greater Than}\\ +\vert &\kws{geq} &\text{Unsigned/Signed Greater or Equal}\\ +\vert &\kws{eq} &\text{Unsigned/Signed Equal}\\ +\vert &\kws{neq} &\text{Unsigned/Signed Not-Equal}\\ +\vert &\kws{mux} &\text{Unsigned/Signed Multiplex}\\ +\vert &\kws{pad} &\text{Unsigned/Signed Pad to Length}\\ +\vert &\kws{asUInt} &\text{Unsigned/Signed Reinterpret Bits as UInt}\\ +\vert &\kws{asSInt} &\text{Unsigned/Signed Reinterpret Bits as SInt}\\ +\vert &\kws{shl} &\text{Unsigned/Signed Shift Left}\\ +\vert &\kws{shr} &\text{Unsigned/Signed Shift Right}\\ +\vert &\kws{toSInt} &\text{Unsigned/Signed to Signed Conversion}\\ +\vert &\kws{neg} &\text{Unsigned/Signed Negate}\\ +\vert &\kws{bit-not} &\text{Unsigned Not}\\ +\vert &\kws{bit-and} &\text{Unsigned And}\\ +\vert &\kws{bit-or} &\text{Unsigned Or}\\ +\vert &\kws{bit-xor} &\text{Unsigned Xor}\\ +\vert &\kws{bit-and-reduce} &\text{Unsigned And}\\ +\vert &\kws{bit-or-reduce} &\text{Unsigned Or}\\ +\vert &\kws{bit-xor-reduce} &\text{Unsigned Xor}\\ +\vert &\kws{cat} &\text{Unsigned Concatenation}\\ +\vert &\kws{bit} &\text{Single Bit Extraction}\\ +\vert &\kws{bits} &\text{Multiple Bit Extraction}\\ \end{array} \] @@ -133,6 +133,7 @@ Module names exist in their own namespace, and all modules must have a unique na A module port is specified by a direction, which may be input or output, a name, and the data type for the port. The port names exist in the identifier namespace for the module, and must be unique. +In addition, all references within a module must be unique. The special port name, {\em reset}, is used to carry the module reset signal for circuit initialization, and has special meaning. Circuit initialization is described in section \ref{initialization}. @@ -142,8 +143,8 @@ Circuit initialization is described in section \ref{initialization}. \subsection{Ground Types} \[ \begin{array}{rrl} -\pd{type} &= &\kws{UInt}(\pd{width}) \\ - &\vert &\kws{SInt}(\pd{width}) \\ +\pd{type} &= &\kws{UInt}<\pd{width}> \\ + &\vert &\kws{SInt}<\pd{width}> \\ \pd{width} &= &\ints \\ &\vert &\kw{?} \\ \end{array} @@ -164,17 +165,18 @@ Vector types in FIRRTL indicate a structure consisting of multiple elements of s This is akin to array types in the C programming language. Note that the number of elements must be known, and non-negative. -As an example, the type $\kws{UInt}(16)[10]$ indicates a ten element vector of 16-bit unsigned integers. -The type $\kws{UInt}(\kws{?})[10]$ indicates a ten element vector of unsigned integers, with unknown and possibly differing bitwidths. +As an example, the type $\kws{UInt}<16>[10]$ indicates a ten element vector of 16-bit unsigned integers. +The type $\kws{UInt}<\kws{?}>[10]$ indicates a ten element vector of unsigned integers, with unknown but the same bitwidths. Vector types may be nested ad infinitum. -The type $\kws{UInt}(16)[10][5]$ indicates a five element vector {\em of} ten element vectors of 16-bit unsigned integers. +The type $\kws{UInt}<16>[10][5]$ indicates a five element vector {\em of} ten element vectors of 16-bit unsigned integers. \subsection{Bundle Types} \[ \begin{array}{rrl} \pd{type} &= &\bundleT{\pd{field*}} \\ -\pd{field} &= &\pd{dir} \text{name } \kw{:} \pd{type} \\ +\pd{field} &= &\pd{orientation} \text{name } \kw{:} \pd{type} \\ +\pd{orientation}&= &\kws{default} \vert \kws{reverse} \\ \end{array} \] @@ -182,28 +184,25 @@ Bundle types in FIRRTL are composite types formed from an ordered sequence of na All fields in a bundle must have a given direction, name, and type. The following is an example of a possible type for representing a complex number. \[ -\bundleT{\kw{output} \text{real } \kw{:} \kws{SInt}(10), - \kw{output} \text{imag } \kw{:} \kws{SInt}(10)} +\bundleT{\kw{default} \text{real } \kw{:} \kws{SInt}<10>, + \kw{default} \text{imag } \kw{:} \kws{SInt}<10>} \] It has two fields, real, and imag, both 10-bit signed integers. Here is an example of a possible type for a decoupled port. \[ \begin{aligned} -\{ \kw{output} &\text{data } \kw{:} \kws{UInt}(10), \\ - \kw{output} &\text{valid } \kw{:} \kws{UInt}(1), \\ - \kw{input} &\text{ready } \kw{:} \kws{UInt}(1)\} \\ +\{ \kw{default} &\text{data } \kw{:} \kws{UInt}<10>, \\ + \kw{default} &\text{valid } \kw{:} \kws{UInt}<1>, \\ + \kw{reverse} &\text{ready } \kw{:} \kws{UInt}<1>\} \\ \end{aligned} \] -It has a data field that is specified to be a 10-bit unsigned integer, a valid signal that must be a 1-bit unsigned integer, and an {\em input} ready signal that must be a 1-bit unsigned integer. +It has a data field that is specified to be a 10-bit unsigned integer, a valid signal that must be a 1-bit unsigned integer, and a flipped ready signal that must be a 1-bit unsigned integer. -By convention, we specify the directions within a bundle type consistently with how the fields would be defined if they were {\em output} ports for a module. -For this reason, the real and imag fields for the complex number bundle type are both specified to have direction \kws{output}. -I.e., if a module were to output a complex number, we would declare it to have an output port real, and an output port imag. -Similarly, if a module were to output a value using a decoupled protocol, we would declare the module to have an output port, data, which would contain the value itself, an output port, valid, which would indicate when the value is valid, and accept an {\em input} port, ready, from the receiving component, which would indicate when the component is ready to receive the value. +By convention, we specify the directions within a bundle type with their relative orientation. +For this reason, the real and imag fields for the complex number bundle type are both specified to be {\em default}. +Similarly, if a module were to output a value using a decoupled protocol, we would declare the module to have an output port, data, which would contain the value itself, a non-flipped field, valid, which would indicate when the value is valid, and accept an {\em reverse} field, ready, from the receiving component, which would indicate when the component is ready to receive the value. Note that all field names within a bundle type must be unique. -The special field name, {\em init}, is reserved for register initialization and is not available to the user. -Register initialization is covered in section \ref{initialization}. As in the case of vector types, bundle types may also be nested ad infinitum. I.e., the types of the fields themselves may also be bundle types, which will in turn contain more fields, etc. @@ -230,7 +229,7 @@ A register with a given name and type can be instantiated with the following sta Like wires, registers are also {\em bidirectional}, which means that they can be used as both an input (by being on the left-hand side of a connect statement), or as an output (by being on the right-hand side of a connect statement). -The distinguished field, {\em init}, is used to specify the initialization value for a register, and is described in section \ref{initialization}. +The statement {\em on-reset} is used to specify the initialization value for a register, and is described in section \ref{initialization}. \subsection{Memories} A memory is a stateful circuit element containing multiple elements. @@ -244,6 +243,7 @@ A memory with a given name and type can be instantiated with the following state Note that, by definition, memories contain multiple elements, and hence {\em must} be declared with a vector type. It is an error to specify any other type for a memory. +However, the internal type to the vector type may be a non-ground type, with the caveat that the internal type, if a bundle type, cannot contain any reverse fields. Additionally, the type for a memory must be completely specified and cannot contain any unknown widths. \subsection{Nodes} @@ -254,34 +254,35 @@ A node with a given name and value can be instantiated with the following statem \] Unlike wires, nodes can only be used in {\em output} directions. They can be connected from, but not connected to. +Consequentially, their expression cannot be a bundle type with any flipped fields. \subsection{Accessors} Accessors are used for either connecting to or from a vector-typed expression, from some {\em variable} index. An accessor can be instantiated with the following statement. \[ \begin{aligned} -\kw{accessor} \text{name } \kw{:} \pds{exp}[\text{index}] \\ +\pd{atype} \kw{accessor} \text{name} = \pds{exp}[\text{index}] \\ +\pd{atype} &= &\kws{read} \vert \kws{write} \vert \kws{unknown} \\ \end{aligned} \] -Given a name, an expression to access, and the index at which to access, the above statement creates an accessor that may be used for connecting to or from the expression. -The expression must have a vector type, and the index must be an unsigned integer. +Given a name, an expression to access, the index at which to access, and optionally the accessor type, the above statement creates an accessor that may be used for connecting to or from the expression. +The expression must have a vector type, and the index must be an variable with a UInt type. -Note that, though their directions are not explicitly specified, accessors are {\em not} bidirectional. -They may be used as outputs, by being on the right-hand side of a connect statement, in which case the accessor acts as a reader from the given expression at the given index. -Or they may be used as inputs, by being on the left-hand side of a connect statement, in which case the accessor acts as a writer to the given expression at the given index. -An accessor must consistently be used either as an input, or as an output, but not as both. +An untyped (unknown) accessor or a read accessor may be used as outputs, by being on the right-hand side of a connect statement, in which case the accessor acts as a reader from the given expression at the given index. +Or, an untyped accessor or a write accessor may be used as inputs, by being on the left-hand side of a connect statement, in which case the accessor acts as a writer to the given expression at the given index. +An accessor must consistently be used either as an input, or as an output, but not as both. -The following example demonstrates using accessors to read and write to a memory. +The following example demonstrates using untyped accessors to read and write to a memory. The accessor, reader, acts as a memory read port that reads from the index specified by the wire i. The accessor, writer, acts as a memory write port that writes 42 to the index specified by wire j. \[ \begin{aligned} -&\kw{wire} i : \kws{UInt}(5) \\ -&\kw{wire} j : \kws{UInt}(5) \\ -&\kw{mem} m : \kws{UInt}(10)[10] \\ +&\kw{wire} i : \kws{UInt}<5> \\ +&\kw{wire} j : \kws{UInt}<5> \\ +&\kw{mem} m : \kws{UInt}<10>[10] \\ &\kw{accessor} reader = m[i] \\ &\kw{accessor} writer = m[j] \\ -&writer := \kws{UInt}(42, ?) \\ +&writer := \kws{UInt}(42) \\ &\kw{node} temp = reader \\ \end{aligned} \] @@ -302,6 +303,8 @@ An instance with some given name, of a given module can be created using the fol The ports of an instance may be accessed using the subfield expression. The output ports of an instance may only be used in output positions, e.g. the right-hand side of a connect statement, and the input ports of an instance may only be used in input positions, e.g. the left-hand side of a connect statement. +An instance may be directly connected to a value. However, it can only be used as an input, or on the right side of a connect. + There are restrictions upon which modules the user is allowed to instantiate, so as not to create infinitely recursive hardware. We define a module with no instances as a {\em level 0} module. A module containing only instances of {\em level 0} modules is a {\em level 1} module, and a module containing only instances of {\em level 1} or below modules is a {\em level 2} module. @@ -314,9 +317,18 @@ The following statement is used to connect the output of some component, to the \text{input } \kw{:=} \text{output} \] -For a connection to be legal, the types of the two expressions must match. +For a connection to be legal, the types of the two expressions must match exactly, including all field flips if the wires contain bundle types. The component on the right-hand side must be able to be used as an output, and the component on the left-hand side must be able to be used as an input. +\subsection{The On Reset Statement} +The on-reset statement is used to specify the default value for a register. Its semantics are described in Section \ref{initialization}. +\[ +\kw{on-reset} \text{reg } \kw{:=} \text{output} +\] + +For a connection to be legal, the types of the two expressions must match exactly, including all field flips if the wires contain bundle types. +The component on the right-hand side must be able to be used as an output, and the component on the left-hand side must be able to be used as an input, and must be a reg. + \subsection{The Conditional Statement} The conditional statement is used to specify a condition that must be asserted under which a list of statements hold. The condition must be a 1-bit unsigned integer. @@ -335,9 +347,9 @@ In the following example, the wire w is connected to 42 when enable is asserted This is an illegal FIRRTL circuit, and will throw a \kws{wire not initialized} error during compilation. \[ \begin{aligned} -&\kw{wire} w : \kws{UInt}(\kws{?}) \\ +&\kw{wire} w : \kws{UInt}<\kws{?}> \\ &\kw{when} enable : \\ -&\quad w := \kws{UInt}(42, \kws{?}) \\ +&\quad w := \kws{UInt}<\kws{?}>(42) \\ \end{aligned} \] @@ -366,8 +378,8 @@ In the following example, the wire w is connected to 42, not 20. \[ \begin{aligned} &\kw{wire} w : \kws{UInt}(\kws{?}) \\ -&w := \kws{UInt}(20, \kws{?}) \\ -&w := \kws{UInt}(42, \kws{?}) \\ +&w := \kws{UInt}<\kws{?}>(20) \\ +&w := \kws{UInt}<\kws{?}>(42) \\ \end{aligned} \] @@ -376,9 +388,9 @@ In the following example, the wire w is connected to 20 unless the enable expres \[ \begin{aligned} &\kw{wire} w : \kws{UInt}(\kws{?}) \\ -&w := \kws{UInt}(20, \kws{?}) \\ +&w := \kws{UInt}<\kws{?}>(20) \\ &\kw{when} enable : \\ -&\quad w := \kws{UInt}(42, \kws{?}) \\ +&\quad w := \kws{UInt}<\kws{?}>(42) \\ \end{aligned} \] @@ -391,59 +403,7 @@ The empty statement is specified using the following. \] The empty statement does nothing and is used simply as a placeholder where a statement is expected. It is typically used as the alternative branch in a conditional statement. - -\subsection{The LetRec Statement} -The letrec statement is used for declaring {\em structural} elements, and is an important part of {\em lowered form}. -It is essentially a netlist representation of a piece of circuitry, but a representation that may exist and that operates correctly together with the other FIRRTL statements. - -\[ -\kw{letrec :} \pd{elem*} \kw{in :} \pd{stmt} -\] - -A letrec statement is defined by a given list of structural elements, which are described in the following section (section \ref{elements}), and a body which contain statements that may refer to the structural elements. - -Unlike in a statement group, the ordering of the structural elements have no meaning. -The structural elements can be thought of as being declared {\em simultaneously}, and any structural element may refer to any other structural element, no matter the order in which they are declared. - -[TODO: No combinational loops] - -\section{Structural Elements} \label{elements} - -Structural elements appear in letrec statements, and are simply circuit components whose input connections are fully specified upon declaration. -They {\em cannot} be used as inputs, and hence can never be on the left-hand side of a connect statement. - -\subsection{Structural Register} -\[ -\kw{reg} \text{name } \kw{:} \pd{type} = \kws{Register}(\text{value}, \text{enable}) -\] -A structural register is specified given a name, a type, the input value for the register, and the enable signal for the register. -The type must be a ground type, the value must be of the given ground type, and the enable signal must be a 1-bit unsigned integer. - -\subsection{Structural Node} -\[ -\kw{node} \text{name } \kw{:} \pd{type} = \pd{exp} -\] -A structural node is specified given a name, a type, and its value. -The type must be a ground type, and the given value must match the ground type. - -\subsection{Structural Memory} -\[ -\kw{mem} \text{name } \kw{:} \pd{type} = -\kws{Memory}(\kws{WritePort}(\text{index}, \text{value}, \text{enable})\text{*}) -\] -A structural memory is specified given a name, a type, and a list of write ports. -The given type must be a vector of some ground type. -Each write port must specify the index at which to write the value, the value to write, and the enable signal determining when to write the value. -The index must be an unsigned integer, the value must match the declared ground type of the memory, and the enable signal must be a 1-bit unsigned integer. - -The only method of reading from a structural memory is through the \kws{ReadPort} expression. - -\subsection{Structural Instance} -\[ -\kw{inst} \text{name} = \text{module}(\kws{Input}(\text{field},\pds{exp})\text{*}) -\] -A structural instance is specified given the instance name, the name of the module, and a list of the expressions to connect to the instance's input ports. -An expression must be specified for every one of the instance's input ports, and the expression's type must match the port type. +In addition, it is useful for transformational pass writers. \section{Expressions} @@ -453,7 +413,7 @@ FIRRTL expressions are used for creating values corresponding to the ground type A value of type \kws{UInt} can be directly created using the following expression. \[ -\kws{UInt}(\text{value}, \text{width}) +\kws{UInt}<\text{width}>(\text{value}) \] The given value must be non-negative, and the given width, if known, must be large enough to hold the value. If the width is specified as unknown, then FIRRTL infers the minimum possible width necessary to hold the value. @@ -462,7 +422,7 @@ If the width is specified as unknown, then FIRRTL infers the minimum possible wi A value of type \kws{SInt} can be directly created using the following expression. \[ -\kws{SInt}(\text{value}, \text{width}) +\kws{SInt}<\text{width}>(\text{value}) \] The given width, if known, must be large enough to hold the given value in two's complement format. If the width is specified as unknown, then FIRRTL infers the minimum possible width necessary to hold the value. @@ -472,7 +432,7 @@ If the width is specified as unknown, then FIRRTL infers the minimum possible wi \text{name} \] A reference is simply a name that refers to some declared circuit component. -A reference may refer to a port, a node, a wire, a register, an instance, a memory, a structural node, a structural wire, a structural register, or a structural instance. +A reference may refer to a port, a node, a wire, a register, an instance, a memory, a node, or a structural register. \subsection{Subfields} \[ @@ -480,25 +440,41 @@ A reference may refer to a port, a node, a wire, a register, an instance, a memo \] The subfield expression may be used for one of three purposes: \begin{enumerate} -\item To refer to the initialization value of a register, using register-name.init. \item To refer to a specific port of an instance, using instance-name.port-name. \item To refer to a specific field within a bundle-typed expression. \end{enumerate} \subsection{Subindex} \[ -\pds{exp}.\text{index} +\pds{exp}[\text{index}] \] The subindex expression is used for referring to a specific element within a vector-valued expression. -It is legal to use the subindex expression on any vector-valued expression, except for structural and non-structural memories. +It is legal to use the subindex expression on any vector-valued expression, except for memories. -\subsection{Structural Read Port} +\subsection{Structural Register} \[ -\kws{ReadPort}(\text{mem}, \text{index}) +\kws{Register}(\text{value}, \text{enable}) \] -The structural read port expression is used to read from declared structural memories. -A read port is created given the name of a declared structural memory, and the index at which to read from. +A structural register is an unnamed register specified by the input value for the register and the enable signal for the register. +The type of the input must be a ground type and the enable signal must be a 1-bit unsigned integer. +\subsection{WritePort} +\[ +\kws{WritePort}(\text{mem},\text{index},\text{enable}) +\] +A write port is specified given the memory it accesses, the index into the memory, and the enable signal determining when to write the value. +The index must be an expression with an unsigned integer type and the enable signal must be a 1-bit unsigned integer. +The type of the WritePort is the inside type of the memory's vector type. +A WritePort can only be used as an output (on the left side of a connect statement). + +\subsection{ReadPort} +\[ +\kws{ReadPort}(\text{mem},\text{index},\text{enable}) +\] +A read port is specified given the memory it accesses, the index into the memory, and the enable signal determining when to read the value. +The index must be an expression with an unsigned integer type and the enable signal must be a 1-bit unsigned integer. +The type of the ReadPort is the inside type of the memory's vector type. +A ReadPort can only be used as an input (on the right side of a connect statement). \subsection{Primitive Operation} \[ @@ -511,113 +487,118 @@ Section \ref{primitives} will describe the format and semantics of each operatio \section{Primitive Operations} \label{primitives} +All primitive operations expression operands must be ground types. +In addition, some allow all permutations of operand ground types, while others on allow subsets. +When well defined, input arguments are allowed to be differing widths. + +FAQ: Why have generic operations instead of explicit types (e.g. add-uu, where the two inputs are unsigned) +FAQ: Why allow operations to allow inputs of differing widths? + \subsection{Add Operation} \[ \begin{array}{rll} -\kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{add}( \pds{op1}, \pds{op2}) & UInt|SInt & max(width(op1),width(op2)) + 1 \\ -\kws{add-uu}(\pds{op1}, \pds{op2}) & UInt & max(width(op1),width(op2)) + 1 \\ -\kws{add-us}(\pds{op1}, \pds{op2}) & SInt & max(width(op1),width(op2)) + 1 \\ -\kws{add-su}(\pds{op1}, \pds{op2}) & SInt & max(width(op1),width(op2)) + 1 \\ -\kws{add-ss}(\pds{op1}, \pds{op2}) & SInt & max(width(op1),width(op2)) + 1 \\ +\kws{Input Types} & \kws{Resultant Type} & \kws{Resultant Width} \\ +\kws{add}(\pds{op1}:UInt, \pds{op2}:UInt) & UInt & max(width(op1),width(op2)) + 1 \\ +\kws{add}(\pds{op1}:UInt, \pds{op2}:SInt) & SInt & max(width(op1),width(op2)) + 1 \\ +\kws{add}(\pds{op1}:SInt, \pds{op2}:UInt) & SInt & max(width(op1),width(op2)) + 1 \\ +\kws{add}(\pds{op1}:SInt, \pds{op2}:SInt) & SInt & max(width(op1),width(op2)) + 1 \\ \end{array} \] -FIRRTL supports generic, unsigned, and signed versions of the add operation. -The generic version supports adding of any combination of two unsigned or signed integers. The other versions support only a specific permutation of operand types. -If the two operands differ in width, the operand of narrower width is automatically padded to be the same width as the wider operand. The resultant's value is 1-bit larger than the wider of the two operands and has a signed type if either operand is signed (otherwise is unsigned). \subsection{Subtract Operation} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{sub}( \pds{op1}, \pds{op2}) & SInt & max(width(op1),width(op2)) + 1 \\ -\kws{sub-uu}(\pds{op1}, \pds{op2}) & SInt & max(width(op1),width(op2)) + 1 \\ -\kws{sub-us}(\pds{op1}, \pds{op2}) & SInt & max(width(op1),width(op2)) + 1 \\ -\kws{sub-su}(\pds{op1}, \pds{op2}) & SInt & max(width(op1),width(op2)) + 1 \\ -\kws{sub-ss}(\pds{op1}, \pds{op2}) & SInt & max(width(op1),width(op2)) + 1 \\ +\kws{sub}(\pds{op1}:UInt, \pds{op2}:UInt) & SInt & max(width(op1),width(op2)) + 1 \\ +\kws{sub}(\pds{op1}:UInt, \pds{op2}:SInt) & SInt & max(width(op1),width(op2)) + 1 \\ +\kws{sub}(\pds{op1}:SInt, \pds{op2}:UInt) & SInt & max(width(op1),width(op2)) + 1 \\ +\kws{sub}(\pds{op1}:SInt, \pds{op2}:SInt) & SInt & max(width(op1),width(op2)) + 1 \\ \end{array} \] -The subtraction operation works similarly to the add operation. +The subtraction operation works similarly to the add operation, but always returns a signed integer with a width that is 1-bit wider than the max of the widths of the two operands. \subsection{Multiply Operation} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{mul}( \pds{op1}, \pds{op2}) & UInt|SInt & width(op1) + width(op2) \\ -\kws{mul-uu}(\pds{op1}, \pds{op2}) & UInt & width(op1) + width(op2) \\ -\kws{mul-us}(\pds{op1}, \pds{op2}) & SInt & width(op1) + width(op2) \\ -\kws{mul-su}(\pds{op1}, \pds{op2}) & SInt & width(op1) + width(op2) \\ -\kws{mul-ss}(\pds{op1}, \pds{op2}) & SInt & width(op1) + width(op2) \\ +\kws{mul}(\pds{op1}:UInt, \pds{op2}:UInt) & UInt & width(op1) + width(op2) \\ +\kws{mul}(\pds{op1}:UInt, \pds{op2}:SInt) & SInt & width(op1) + width(op2) \\ +\kws{mul}(\pds{op1}:SInt, \pds{op2}:UInt) & SInt & width(op1) + width(op2) \\ +\kws{mul}(\pds{op1}:SInt, \pds{op2}:SInt) & SInt & width(op1) + width(op2) \\ \end{array} \] -As with add and subtract, there is a generic, unsigned, and signed version of the multiply operation. The resultant value has width equal to the sum of the widths of its two operands. \subsection{Divide Operation} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{div}( \pds{op1}, \pds{op2}) & UInt|SInt & width(op1)|width(op1) + 1 \\ -\kws{div-uu}(\pds{op1}, \pds{op2}) & UInt & width(op1) \\ -\kws{div-us}(\pds{op1}, \pds{op2}) & SInt & width(op1) + 1 \\ -\kws{div-su}(\pds{op1}, \pds{op2}) & SInt & width(op1) \\ -\kws{div-ss}(\pds{op1}, \pds{op2}) & SInt & width(op1) + 1 \\ +\kws{div}(\pds{op1}:UInt, \pds{op2}:UInt) & UInt & width(op1) \\ +\kws{div}(\pds{op1}:UInt, \pds{op2}:SInt) & SInt & width(op1) + 1 \\ +\kws{div}(\pds{op1}:SInt, \pds{op2}:UInt) & SInt & width(op1) \\ +\kws{div}(\pds{op1}:SInt, \pds{op2}:SInt) & SInt & width(op1) + 1 \\ \end{array} \] The first argument is the dividend, the second argument is the divisor. -The resultant value of a divide operation has width equal to the width of the dividend minus the width of the divisor. +The resultant width of a divide operation is equal to the width of the dividend, plus one if the divisor is an SInt. +The resultant value follows the following formula : div(a,b) = round-towards-zero(a/b) + mod(a,b) -\subsection{Modulo Operation} +\subsection{Modulus Operation} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{mod}( \pds{op1}, \pds{op2}) & UInt & width(op1)|width(op2) - 1 \\ -\kws{mod-uu}(\pds{op1}, \pds{op2}) & UInt & width(op2) \\ -\kws{mod-us}(\pds{op1}, \pds{op2}) & UInt & width(op2) - 1? \\ -\kws{mod-su}(\pds{op1}, \pds{op2}) & SInt & width(op2) \\ -\kws{mod-ss}(\pds{op1}, \pds{op2}) & SInt & width(op2) - 1? \\ +\kws{mod}(\pds{op1}:UInt, \pds{op2}:UInt) & UInt & width(op2) \\ +\kws{mod}(\pds{op1}:UInt, \pds{op2}:SInt) & UInt & width(op2) \\ +\kws{mod}(\pds{op1}:SInt, \pds{op2}:UInt) & SInt & width(op2) + 1 \\ +\kws{mod}(\pds{op1}:SInt, \pds{op2}:SInt) & SInt & width(op2) \\ \end{array} \] +The first argument is the dividend, the second argument is the divisor. +The resultant width of a modulus operation is equal to the width of the divisor, except when the modulus is positive and the result can be negative. +The resultant value follows the following formula : div(a,b) = round-towards-zero(a/b) + mod(a,b) + \subsection{Quotient Operation} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{quo}( \pds{op1}, \pds{op2}) & UInt|SInt & width(?) \\ -\kws{quo-uu}(\pds{op1}, \pds{op2}) & UInt & width(?) \\ -\kws{quo-us}(\pds{op1}, \pds{op2}) & SInt & width(?) \\ -\kws{quo-su}(\pds{op1}, \pds{op2}) & SInt & width(?) \\ -\kws{quo-ss}(\pds{op1}, \pds{op2}) & SInt & width(?) \\ +\kws{quo}(\pds{op1}:UInt, \pds{op2}:UInt) & UInt & width(op1) + 1 \\ +\kws{quo}(\pds{op1}:UInt, \pds{op2}:SInt) & SInt & width(op1) \\ +\kws{quo}(\pds{op1}:SInt, \pds{op2}:UInt) & SInt & width(op1) + 1 \\ +\kws{quo}(\pds{op1}:SInt, \pds{op2}:SInt) & SInt & width(op1) \\ \end{array} \] + The first argument is the dividend, the second argument is the divisor. -The resultant value of a divide operation has width equal to the width of the dividend minus the width of the divisor. +The resultant width of a quotient operation is equal to the width of the dividend, plus one if the divisor is an SInt. +The resultant value follows the following formula : quo(a,b) = floor(a/b) + rem(a,b) \subsection{Remainder Operation} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{rem}( \pds{op1}, \pds{op2}) & UInt|SInt & width(op2)|min(width(op1),width(op2)) \\ -\kws{rem-uu}(\pds{op1}, \pds{op2}) & UInt & min(width(op1),width(op2)) \\ -\kws{rem-us}(\pds{op1}, \pds{op2}) & SInt & width(op2) \\ -\kws{rem-su}(\pds{op1}, \pds{op2}) & UInt & width(op2) \\ -\kws{rem-ss}(\pds{op1}, \pds{op2}) & SInt & width(op2) \\ +\kws{rem}(\pds{op1}:UInt, \pds{op2}:UInt) & UInt & width(op2) \\ +\kws{rem}(\pds{op1}:UInt, \pds{op2}:SInt) & SInt & width(op2) \\ +\kws{rem}(\pds{op1}:SInt, \pds{op2}:UInt) & UInt & width(op2) + 1 \\ +\kws{rem}(\pds{op1}:SInt, \pds{op2}:SInt) & SInt & width(op2) \\ \end{array} \] + The first argument is the dividend, the second argument is the divisor. -The resultant value of a modulo operation has the same width as the divisor. +The resultant width of a modulus operation is equal to the width of the divisor, except when the divisor is positive and the result can be negative. +The resultant value follows the following formula : quo(a,b) = floor(a/b) + rem(a,b) + \subsection{Add Wrap Operation} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{add-wrap}( \pds{op1}, \pds{op2}) & UInt|SInt & max(width(op1),width(op2)) \\ -\kws{add-wrap-uu}(\pds{op1}, \pds{op2}) & UInt & max(width(op1),width(op2)) \\ -\kws{add-wrap-us}(\pds{op1}, \pds{op2}) & SInt & max(width(op1),width(op2)) \\ -\kws{add-wrap-su}(\pds{op1}, \pds{op2}) & SInt & max(width(op1),width(op2)) \\ -\kws{add-wrap-ss}(\pds{op1}, \pds{op2}) & SInt & max(width(op1),width(op2)) \\ +\kws{add-wrap}(\pds{op1}:UInt, \pds{op2}:UInt) & UInt & max(width(op1),width(op2)) \\ +\kws{add-wrap}(\pds{op1}:UInt, \pds{op2}:SInt) & SInt & max(width(op1),width(op2)) \\ +\kws{add-wrap}(\pds{op1}:SInt, \pds{op2}:UInt) & SInt & max(width(op1),width(op2)) \\ +\kws{add-wrap}(\pds{op1}:SInt, \pds{op2}:SInt) & SInt & max(width(op1),width(op2)) \\ \end{array} \] The add wrap operation works identically to the normal add operation except that the resultant width is the maximum of the width of the two operands, instead of 1 bit greater than the maximum. @@ -627,11 +608,10 @@ In the case of overflow, the result silently rolls over. \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{sub-wrap}( \pds{op1}, \pds{op2}) & UInt|SInt & max(width(op1),width(op2)) \\ -\kws{sub-wrap-uu}(\pds{op1}, \pds{op2}) & UInt & max(width(op1),width(op2)) \\ -\kws{sub-wrap-us}(\pds{op1}, \pds{op2}) & SInt & max(width(op1),width(op2)) \\ -\kws{sub-wrap-su}(\pds{op1}, \pds{op2}) & SInt & max(width(op1),width(op2)) \\ -\kws{sub-wrap-ss}(\pds{op1}, \pds{op2}) & SInt & max(width(op1),width(op2)) \\ +\kws{sub-wrap}(\pds{op1}:UInt, \pds{op2}:UInt) & UInt & max(width(op1),width(op2)) \\ +\kws{sub-wrap}(\pds{op1}:UInt, \pds{op2}:SInt) & SInt & max(width(op1),width(op2)) \\ +\kws{sub-wrap}(\pds{op1}:SInt, \pds{op2}:UInt) & SInt & max(width(op1),width(op2)) \\ +\kws{sub-wrap}(\pds{op1}:SInt, \pds{op2}:SInt) & SInt & max(width(op1),width(op2)) \\ \end{array} \] Similarly to the add wrap operation, the subtract wrap operation works identically to the normal subtract operation except that the resultant width is the maximum of the width of the two operands. @@ -641,106 +621,103 @@ In the case of overflow, the result silently rolls over. \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{lt} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{lt-uu} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{lt-us} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{lt-su} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{lt-ss} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{leq} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{leq-uu} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{leq-us} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{leq-su} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{leq-ss} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{gt} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{gt-uu} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{gt-us} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{gt-su} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{gt-ss} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{geq} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{geq-uu} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{geq-us} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{geq-su} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{geq-ss} (\pds{op1}, \pds{op2}) & UInt & 1 \\ +\kws{lt} (\pds{op1}:UInt, \pds{op2}:UInt) & UInt & 1 \\ +\kws{lt} (\pds{op1}:UInt, \pds{op2}:SInt) & UInt & 1 \\ +\kws{lt} (\pds{op1}:SInt, \pds{op2}:UInt) & UInt & 1 \\ +\kws{lt} (\pds{op1}:SInt, \pds{op2}:SInt) & UInt & 1 \\ +\kws{leq} (\pds{op1}:UInt, \pds{op2}:UInt) & UInt & 1 \\ +\kws{leq} (\pds{op1}:UInt, \pds{op2}:SInt) & UInt & 1 \\ +\kws{leq} (\pds{op1}:SInt, \pds{op2}:UInt) & UInt & 1 \\ +\kws{leq} (\pds{op1}:SInt, \pds{op2}:SInt) & UInt & 1 \\ +\kws{gt} (\pds{op1}:UInt, \pds{op2}:UInt) & UInt & 1 \\ +\kws{gt} (\pds{op1}:UInt, \pds{op2}:SInt) & UInt & 1 \\ +\kws{gt} (\pds{op1}:SInt, \pds{op2}:UInt) & UInt & 1 \\ +\kws{gt} (\pds{op1}:SInt, \pds{op2}:SInt) & UInt & 1 \\ +\kws{geq} (\pds{op1}:UInt, \pds{op2}:UInt) & UInt & 1 \\ +\kws{geq} (\pds{op1}:UInt, \pds{op2}:SInt) & UInt & 1 \\ +\kws{geq} (\pds{op1}:SInt, \pds{op2}:UInt) & UInt & 1 \\ +\kws{geq} (\pds{op1}:SInt, \pds{op2}:SInt) & UInt & 1 \\ \end{array} \] -Generic, unsigned, and signed versions of the less than (\kws{lt}), less than or equal to (\kws{leq}), greater than (\kws{gt}), and greater than or equal to (\kws{geq}) comparison operations are provided. -The generic versions of each operation accept either two unsigned integers, or two signed integers, but not a mixture of the two. -The resultant value is a single-bit unsigned integer. +Each operation accept any combination of SInt or UInt input arguements, and always returns a single-bit unsigned integer. \subsection{Equality Comparison} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{equal} (\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{equal-u}(\pds{op1}, \pds{op2}) & UInt & 1 \\ -\kws{equal-s}(\pds{op1}, \pds{op2}) & UInt & 1 \\ +\kws{eq}(\pds{op1}:UInt, \pds{op2}:UInt) & UInt & 1 \\ +\kws{eq}(\pds{op1}:SInt, \pds{op2}:SInt) & UInt & 1 \\ \end{array} \] The equality comparison operator accepts either two unsigned or two signed integers and checks whether they are bitwise equivalent. The resulting value is a 1-bit unsigned integer. -The two operands may differ in width, in which case the narrower of the two operands is padded to the width of the larger operand. +If an arithmetic equals between a signed and unsigned integer is desired, one must first use convert on the unsigned integer, then use the equal primop. -If an arithmetic equals between a signed and unsigned integer is desired, one must first use convert on the unsigned integer, then use the equal-s primop. +\subsection{Not-Equality Comparison} +\[ +\begin{array}{rll} +\kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ +\kws{neq}(\pds{op1}:UInt, \pds{op2}:UInt) & UInt & 1 \\ +\kws{neq}(\pds{op1}:SInt, \pds{op2}:SInt) & UInt & 1 \\ +\end{array} +\] +The not-equality comparison operator accepts either two unsigned or two signed integers and checks whether they are not bitwise equivalent. +The resulting value is a 1-bit unsigned integer. + +If an arithmetic not-equals between a signed and unsigned integer is desired, one must first use convert on the unsigned integer, then use the not-equal primop. \subsection{Multiplex} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{mux} (\pds{condition}, \pds{op1}, \pds{op2}) & UInt|SInt & width(op1) \\ -\kws{mux-u}(\pds{condition}, \pds{op1}, \pds{op2}) & UInt & width(op1) \\ -\kws{mux-s}(\pds{condition}, \pds{op1}, \pds{op2}) & SInt & width(op1) \\ +\kws{mux} (\pds{condition}, \pds{op1}, \pds{op2}) & UInt & width(op1) \\ +\kws{mux} (\pds{condition}, \pds{op1}, \pds{op2}) & SInt & width(op1) \\ \end{array} \] The multiplex operation accepts three signals, a 1-bit unsigned integer for the condition expression, followed by either two unsigned integers, or two signed integers. If the condition is high, then the result is equal to the first of the two following operands. If the condition is low, then the result is the second of the two following operands. -This operation is the only primop where the two operands may not differ in width. The output is of the same width as the inputs. +The output is of the same width as the max width of the inputs. \subsection{Padding Operation} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{pad}(\pds{op}, \text{num}) & UInt|SInt & num \\ -\kws{pad-u}(\pds{op}, \text{num}) & UInt & num \\ -\kws{pad-s}(\pds{op}, \text{num}) & SInt & num \\ +\kws{pad}(\pds{op}:UInt, \text{num}) & UInt & num \\ +\kws{pad}(\pds{op}:SInt, \text{num}) & SInt & num \\ \end{array} \] -A generic, unsigned, and signed version of the pad operation is provided which pads some expression to a specified width. -The unsigned pad operation zero-extends the given value until the specified width, while the signed pad operation sign-extends the given value. -The generic operation performs either zero-extension or sign-extension depending on the type of its operand. +A pad operation is provided which either zero-extends or sign-extends an expression to a specified width. The given width must be equal to or greater than the existing width of the expression. \subsection{Reinterpret Bits as UInt} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{asUInt}(\pds{op1}) & UInt & width(op1) \\ -\kws{asUInt-u}(\pds{op1}) & UInt & width(op1) \\ -\kws{asUInt-s}(\pds{op1}) & UInt & width(op1) \\ +\kws{asUInt}(\pds{op1}:UInt) & UInt & width(op1) \\ +\kws{asUInt}(\pds{op1}:SInt) & UInt & width(op1) \\ \end{array} \] -A generic, unsigned and signed version of asUInt is provided. All versions return a UInt with the same width as the operand. +Regardless of input type, primop returns a UInt with the same width as the operand. \subsection{Reinterpret Bits as SInt} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{asSInt}(\pds{op1}) & SInt & width(op1) \\ -\kws{asSInt-u}(\pds{op1}) & SInt & width(op1) \\ -\kws{asSInt-s}(\pds{op1}) & SInt & width(op1) \\ +\kws{asSInt}(\pds{op1}:UInt) & SInt & width(op1) \\ +\kws{asSInt}(\pds{op1}:SInt) & SInt & width(op1) \\ \end{array} \] -A generic, unsighed and signed version of asSInt is provided. All versions return a SInt with the same width as the operand. +Regardless of input type, primop returns a SInt with the same width as the operand. \subsection{Shift Left Operation} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\pd{shl} & UInt|SInt & width(op) + num \\ -\pd{shl-u} & UInt & width(op) + num \\ -\pd{shl-s} & SInt & width(op) + num \\ +\kws{shl}(\pds{op}:UInt, \text{num}) & UInt & width(op) + num \\ +\kws{shl}(\pds{op}:SInt, \text{num}) & SInt & width(op) + num \\ \end{array} \] The shift left operation accepts either an unsigned or a signed integer, plus a non-negative integer literal specifying the number of bits to shift. @@ -751,9 +728,8 @@ The output of a shift left operation is equal to the original signal concatenate \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\pd{shr} & UInt|SInt & width(op) - num \\ -\pd{shr-u} & UInt & width(op) - num \\ -\pd{shr-s} & SInt & width(op) - num \\ +\kws{shr}(\pds{op}:UInt, \text{num}) & UInt & width(op) - num \\ +\kws{shr}(\pds{op}:SInt, \text{num}) & SInt & width(op) - num \\ \end{array} \] The shift right operation accepts either an unsigned or a signed integer, plus a non-negative integer literal specifying the number of bits to shift. @@ -761,37 +737,88 @@ The resultant value has the same type as the operand. The shift amount must be less than or equal to the width of the operand. The output of a shift right operation is equal to the original signal with the least significant $num$ bits truncated, where $num$ is the shift amount. +\subsection{Dynamic Shift Left Operation} +\[ +\begin{array}{rll} +\kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ +\kws{dshl}(\pds{op1}:UInt, \pds{op2}:UInt) & UInt & width(op1) + pow(2,width(op2)) \\ +\kws{dshl}(\pds{op1}:SInt, \pds{op2}:UInt) & SInt & width(op1) + pow(2,width(op2)) \\ +\end{array} +\] +The dynamic shift left operation accepts either an unsigned or a signed integer, plus an unsigned integer dynamically specifying the number of bits to shift. +The resultant value has the same type as the operand. +The output of a dynamic shift left operation is equal to the original signal concatenated with $n$ zeros at the end, where $n$ is the dynamic shift amount. +The output width of a dynamic shift left operation is the width of the original signal plus 2 raised to the width of the dynamic shift amount. + +\subsection{Dynamic Shift Right Operation} +\[ +\begin{array}{rll} +\kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ +\kws{dshr}(\pds{op}:UInt, \pds{op2}:UInt) & UInt & width(op) - pow(2,width(op2)) \\ +\kws{dshr}(\pds{op}:SInt, \pds{op2}:UInt) & SInt & width(op) - pow(2,width(op2)) \\ +\end{array} +\] +The shift right operation accepts either an unsigned or a signed integer, plus a non-negative integer literal specifying the number of bits to shift. +The resultant value has the same type as the operand. +The shift amount must be less than or equal to the width of the operand. +The output of a shift right operation is equal to the original signal with the least significant $n$ bits truncated, where $n$ is the dynamic shift amount. +The output width of a dynamic shift right operation is the width of the original signal minus 2 raised to the width of the dynamic shift amount. + \subsection{Convert to Signed} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\pd{convert} & SInt & width(op)|width(op) + 1 \\ -\pd{convert-u} & SInt & width(op) + 1 \\ -\pd{convert-s} & SInt & width(op) \\ +\kws{toSInt}(\pds{op}:UInt) & SInt & width(op) + 1 \\ +\kws{toSInt}(\pds{op}:SInt) & SInt & width(op) \\ \end{array} \] -The convert operation accepts either an unsigned or a signed integer. +The toSInt operation accepts either an unsigned or a signed integer. The resultant value is always a signed integer. -The output of a convert operation will be the same arithmetic value as the input value. +The output of a toSInt operation will be the same arithmetic value as the input value. The output width is the same as the input width if the input is signed, and increased by one if the input is unsigned. +\subsection{Negate} +\[ +\begin{array}{rll} +\kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ +\kws{neg}(\pds{op1}:UInt) & SInt & width(op1) + 1 \\ +\kws{neg}(\pds{op1}:SInt) & SInt & width(op1) \\ +\end{array} +\] +If the input type is UInt, primop returns the negative value as an SInt with the width of the operand plus one. +If the input type is SInt, primop returns -1 * input value, as an SInt with the same width of the operand. + \subsection{Bitwise Operations} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{and} (\pds{op1}, \pds{op2}) & UInt & max(width(op1),width(op2)) \\ -\kws{or} (\pds{op1}, \pds{op2}) & UInt & max(width(op1),width(op2)) \\ -\kws{xor} (\pds{op1}, \pds{op2}) & UInt & max(width(op1),width(op2)) \\ +\kws{bit-not} (\pds{op1:UInt}, \pds{op2:UInt}) & UInt & max(width(op1),width(op2)) \\ +\kws{bit-and} (\pds{op1:UInt}, \pds{op2:UInt}) & UInt & max(width(op1),width(op2)) \\ +\kws{bit-or} (\pds{op1:UInt}, \pds{op2:UInt}) & UInt & max(width(op1),width(op2)) \\ +\kws{bit-xor} (\pds{op1:UInt}, \pds{op2:UInt}) & UInt & max(width(op1),width(op2)) \\ \end{array} \] -The above operations correspond to bitwise and, or, and exclusive or respectively. +The above operations correspond to bitwise not, and, or, and exclusive or respectively. The operands must be unsigned integers, and the resultant width is equal to the width of the wider of the two operands. +\subsection{Reduce Bitwise Operations} +\[ +\begin{array}{rll} +\kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ +\kws{bit-not-reduce} (\pds{op:UInt}*) & UInt & max(width(op)*) \\ +\kws{bit-and-reduce} (\pds{op:UInt}*) & UInt & max(width(op)*) \\ +\kws{bit-or-reduce} (\pds{op:UInt}*) & UInt & max(width(op)*) \\ +\kws{bit-xor-reduce} (\pds{op:UInt}*) & UInt & max(width(op)*) \\ +\end{array} +\] +The above operations correspond to bitwise not, and, or, and exclusive or respectively, reduced over a list of unsigned integers. +The resultant width is equal to the width of the widest operand. + \subsection{Concatenation} \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{concat}(\pds{op1}, \pds{op2}) & UInt & width(op1) + width(op2) \\ +\kws{cat}(\pds{op1}:UInt, \pds{op2}:UInt) & UInt & width(op1) + width(op2) \\ \end{array} \] The concatenation operator accepts two unsigned integers and returns the bitwise concatenation of the two values as an unsigned integer. @@ -801,7 +828,8 @@ The resultant width is the sum of the widths of the two operands. \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{bit}(\pds{op}, \text{index}) & UInt & 1 \\ +\kws{bit}(\pds{op}:UInt, \text{index}) & UInt & 1 \\ +\kws{bit}(\pds{op}:SInt, \text{index}) & UInt & 1 \\ \end{array} \] The bit extraction operation accepts either an unsigned or a signed integer, plus an integer literal specifying the index of the bit to extract. @@ -813,7 +841,8 @@ An index of zero indicates the least significant bit in the operand, and an inde \[ \begin{array}{rll} \kws{primop} & \kws{Resultant Type} & \kws{Resultant Width} \\ -\kws{bits}(\pds{op}, \text{high}, \text{low}) & UInt & high - low \\ +\kws{bits}(\pds{op}:UInt, \text{high}, \text{low}) & UInt & high - low \\ +\kws{bits}(\pds{op}:SInt, \text{high}, \text{low}) & UInt & high - low \\ \end{array} \] The bit range extraction operation accepts either an unsigned or a signed integer, plus two integer literals that specify the high (inclusive) and low (inclusive) index of the bit range to extract. @@ -821,80 +850,27 @@ Regardless of the type of the operand, the resultant value is a $n$-bit unsigned \section{Circuit Initialization} \label{initialization} -This section describes FIRRTL's facilities for expressing circuit initialization, and how it is customized through the reset port for modules, and the init field for registers. +This section describes FIRRTL's facilities for expressing circuit initialization, and how it is customized through the reset port for modules, and the on-reset construct for registers. + +\subsection{Module Initialization} +As stated before, all modules must have a port named reset defined. \subsection{Register Initialization} -On circuit reset, registers are automatically set to their {\em initialization value}. -By default, a register's initialization value is set to be equal to the value of the register itself. +By default, a register will not have a initialization value and will not be enabled during reset. Hence, the default reset behavior for registers is to maintain their current value. -However, an explicit initialization value can be provided for a register by connecting an expression to the register's init field. +However, an explicit initialization value can be provided for a register by connecting an expression to the register via the on-reset construct. The following example demonstrates declaring a register, and changing its initialization value to forty two. \[ \begin{aligned} -& \kw{reg} r : \kws{UInt}(10) \\ -& r.\text{init} := \kws{UInt}(42, \kws{?}) +& \kw{reg} r : \kws{UInt}<10> \\ +& on-reset r := \kws{UInt}<\kws{?}>(42) \end{aligned} \] The type of the initialization value must match the declared type of the register. In the above example, the register, r, will be set to forty two when the circuit is reset. -Note that structural registers declared within letrec statements do not have an init field. - -\subsection{Module Reset Port} -Every module has an input reset port declared to be a 1-bit unsigned integer. -If the user chooses, the reset port may be explicitly declared. -If the user does not explicitly declare a reset port, then FIRRTL will implicitly insert a reset port for the module. - -When an instance of a module with an implicit reset is created, the reset signal of the module in which the instance was created is automatically connected to the instance's reset port. -Consider the following example: -\[ -\begin{aligned} -&\kw{module} A : \\ -&\quad \kw{input} x \kw{ :} \kws{UInt}(\kws{?})\\ -&\quad ... \\ -&\kw{module} B : \\ -&\quad \kw{inst} a \kw{ of} A \\ -&\quad a.\text{x} \kw{ :=} \kws{UInt}(42, \kws{?}) \\ -\end{aligned} -\] -The module A has an implicit reset port, and the module B creates an instance of A. -In this case, there is an implicit connect statement inserted, connecting the instance's reset port to the implicit reset port of B. -\[ -\begin{aligned} -&\kw{inst} a \kw{ of} A \\ -&a.\text{reset} \kw{ :=} \text{reset} \\ -&\ldots -\end{aligned} -\] - -The user may choose to explicitly override this default behavior by explicitly connecting an instance's reset port to a value. -\[ -\begin{aligned} -&\kw{module} B : \\ -&\quad \kw{inst} a \kw{ of} A \\ -&\quad a.\text{reset} \kw{ :=} \kws{UInt}(0, \kws{?}) \\ -&\quad a.\text{x} \kw{ :=} \kws{UInt}(42, \kws{?}) \\ -\end{aligned} -\] -The above code explicitly connects the instance's reset port to zero, indicating that its registers are {\em never} reset. - -Should the user choose to explicitly declare the reset port for a module, then the port {\em must} be appropriately declared as an {\em input} port with a declared type of unsigned integer with width one. -Additionally, if the user explicitly declares the reset port for a module, then all instances of that module must have its reset port connected explicitly. -For example, the following code -\[ -\begin{aligned} -&\kw{module} A : \\ -&\quad \kw{input} \text{x} \kw{ :} \kws{UInt}(\kws{?})\\ -&\quad \kw{input} \text{reset} \kw{ :} \kws{UInt}(1)\\ -&\quad ... \\ -&\kw{module} B : \\ -&\quad \kw{inst} a \kw{ of} A \\ -&\quad a.\text{x} \kw{ :=} \kws{UInt}(42, \kws{?}) \\ -\end{aligned} -\] -is not legal. -The module, A, has an explicitly declared reset port, but the reset port for its instance, a, is not explicitly connected to any value. +Note that structural registers cannot be assigned an initial value because they can only be used on the right side of a connect statement. \section{Lowered Form} @@ -906,37 +882,32 @@ In lowered form, every module has exactly the following form. \begin{aligned} &\kw{module} \text{name} : \\ &\quad \pds{port} \ldots \\ -&\quad \kw{letrec :} \\ -&\quad \quad \pds{elem} \ldots \\ -&\quad \kw{in :} \\ -&\quad \quad \text{connections to output ports} \ldots \\ +&\quad \kw{wire} \ldots \\ +&\quad \text{connections to output ports} \ldots \\ \end{aligned} \] -The body of the module must consist of a single letrec statement, in which every component within the module is declared as a structural element. -The only statements that may appear in the body of the letrec statement are connect statements for each of the module's output ports. +The body of the module must consist of a list of wire declarations, followed by a series of connect statements. The following restrictions also hold for modules in lowered form. \subsection{No Nested Expressions} In the declaration of the structural elements, the only nested expressions allowed are references, and unsigned and signed literals. -All other nested expressions must be lifted to a named structural node, and referred to through a reference. +All other nested expressions must be lifted to a named node, and referred to through a reference. \subsection{No Composite Types} -No module port may be declared with a bundle or vector type. +No module port or wire may be declared with a bundle or vector type. The lowering pass will recursively expand ports into its constituent elements until all ports are declared with ground types. -Additionally, by virtue of requiring all module components to be declared as structural elements, which support ground types only, there will be no composite types left in lowered form. + +\subsection{Single Connect} +Every wire declared can only be assigned to once within a module. \subsection{No Unknown Widths} No port or structural element may be declared with unknown width. The FIRRTL width inferencer will compute the widths for all structural elements and ports. If a width for some element cannot be calculated, then the lowering pass will fail with an error. -\subsection{Explicit Resets} -All modules will contain an explicitly declared reset port and the structural instances within a module will explicitly specify the values connected to their reset ports. - - \section{Inlined Lowered Form} -A further pass provided by FIRRTL is the inlining pass, which recursively inlines all instances in the top-level module until the top-level module is the only remaining module in the circuit. +A further (and optional) pass provided by FIRRTL is the inlining pass, which recursively inlines all instances in the top-level module until the top-level module is the only remaining module in the circuit. Inlined lowered form is essentially a flat netlist which specifies every component used in a circuit and their input connections. \section{Concrete Syntax}\label{concrete} @@ -980,8 +951,8 @@ module name : The following shows an example of a simple module. \begin{verbatim} module mymodule : - input a: UInt(1) - output b: UInt(1) + input a: UInt<1> + output b: UInt<1> b := a \end{verbatim} @@ -989,34 +960,34 @@ module mymodule : The unsigned and signed integer types are specified the following way. The following examples demonstrate a unsigned integer with known bitwidth, signed integer with known bitwidth, an unsigned integer with unknown bitwidth, and signed integer with unknown bitwidth. \begin{verbatim} -UInt(42) -SInt(42) -UInt(?) -SInt(?) +UInt<42> +SInt<42> +UInt +SInt \end{verbatim} The bundle type consists of a number of fields surrounded with parenthesis. The following shows an example of a decoupled bundle type. Note that the commas are for clarity only and are not necessary. \begin{verbatim} -{output data: UInt(10), - output valid: UInt(1), - input ready: UInt(1)} +{data: UInt<10>, + valid: UInt<1>, + flip ready: UInt<1>} \end{verbatim} The vector type is specified by immediately postfixing a type with a bracketed integer literal. The following example demonstrates a ten-element vector of 16-bit unsigned integers. \begin{verbatim} -UInt(16)[10] +UInt<16>[10] \end{verbatim} \subsection*{Statements} The following examples demonstrate declaring wires, registers, memories, nodes, instances, and accessors. \begin{verbatim} -wire mywire : UInt(10) -reg myreg : UInt(10) -mem mymem : UInt(10)[16] -inst myinst of MyModule +wire mywire : UInt<10> +reg myreg : UInt<10> +mem mymem : UInt<10>[16] +inst myinst : MyModule accessor myaccessor = e[i] \end{verbatim} @@ -1025,6 +996,11 @@ The connect statement is specified using the \verb|:=| operator. x := y \end{verbatim} +The on-reset statement is specified using the on-reset keyword and the \verb|:=| operator. +\begin{verbatim} +on-reset x := y +\end{verbatim} + The conditional statement is specified with the \verb|when| keyword. \begin{verbatim} when x : x := y else : x := z @@ -1053,27 +1029,15 @@ else : x := w \end{verbatim} -Letrec statements are expressed using the \verb|letrec| keyword. -The following example demonstrates a letrec statement containing the four structural elements. -\begin{verbatim} -letrec : - reg r : UInt(4) = Register(x, e) - node n : UInt(?) = y - mem m : UInt(4)[10] = Memory(WritePort(i, x, e), WritePort(j, x, e)) - inst i = MyAdder(Input(data, x), Input(valid, e)) -in : - y := x -\end{verbatim} - \subsection*{Expressions} The UInt and SInt constructors create literal integers from a given value and bitwidth. The following examples demonstrate creating literal integers of both known and unknown bitwidth. \begin{verbatim} -UInt(42, 4) -SInt(-42, 4) -UInt(42, ?) -SInt(-42, ?) +UInt<4>(42) +SInt<4>(-42) +UInt(42) +SInt(-42) \end{verbatim} References are specified with a identifier. @@ -1081,21 +1045,30 @@ References are specified with a identifier. x \end{verbatim} -Subfields and subindexes are expressed using the dot operator. +Subfields are expressed using the dot operator. \begin{verbatim} x.data -x.10 \end{verbatim} -Structural read ports are expressed using the ReadPort constructor. +Subindicies are expressed using the \verb|[]| operator. +\begin{verbatim} +x[10] +\end{verbatim} + +Read ports are expressed using the ReadPort constructor. +\begin{verbatim} +ReadPort(m, index, enable) +\end{verbatim} + +Write ports are expressed using the WritePort constructor. \begin{verbatim} -ReadPort(m, index) +WritePort(m, index, enable) \end{verbatim} Primitive operations are expressed by following the name of the primitive with a list containing the operands. \begin{verbatim} add(x, y) -addu(x, addu(x, y)) +add(x, add(x, y)) shl(x, 42) \end{verbatim} diff --git a/src/main/stanza/errors.stanza b/src/main/stanza/errors.stanza index fb537083..53ed1bdf 100644 --- a/src/main/stanza/errors.stanza +++ b/src/main/stanza/errors.stanza @@ -194,7 +194,10 @@ public defn check-high-form (c:Circuit) -> Circuit : defn check-high-form-m (m:Module) -> False : val names = Vector() + for m in modules(c) do : + add(names,name(m)) for p in ports(m) do : + add(names,name(p)) if name(p) == `reset : if direction(p) == OUTPUT : add(errors,WrongReset(info!(m),name(m))) @@ -205,6 +208,8 @@ public defn check-high-form (c:Circuit) -> Circuit : else : add(errors,WrongReset(info!(m),name(m))) + + add(names,`reset) check-high-form-s(body(m),names) false @@ -238,28 +243,32 @@ defn OnResetNotReg (info:FileInfo, name:Symbol) : ; I may have been overeager in looking for places where mems can't be, as mems are guaranteed to have a vector ; type, and this will get caught in the type check pass public defn check-kinds (c:Circuit) -> Circuit : - val errors = Vector() + val errors = Vector() defn check-not-mem (info:FileInfo,e:Expression) -> False : - match(map(check-not-mem{info,_},e)) : + do(check-not-mem{info,_},e) + match(e) : (e:WRef) : if kind(e) == MemKind() : add(errors,IsMem(info,name(e))) - (e:WSubfield) : check-not-mem(exp(e)) - (e:WIndex) : check-not-mem(exp(e)) + (e:WSubfield) : check-not-mem(info,exp(e)) + (e:WIndex) : check-not-mem(info,exp(e)) (e) : false defn check-is-reg (info:FileInfo,e:Expression) -> False : - match(map(check-is-reg{info,_},e)) : + do(check-is-reg{info,_},e) + match(e) : (e:WRef) : if kind(e) != RegKind() : add(errors,OnResetNotReg(info,name(e))) - (e:WSubfield) : check-is-reg(exp(e)) - (e:WIndex) : check-is-reg(exp(e)) + (e:WSubfield) : check-is-reg(info,exp(e)) + (e:WIndex) : check-is-reg(info,exp(e)) (e) : false defn check-is-mem (info:FileInfo,e:Expression) -> False : - match(map(check-is-mem{info,_},e)) : + do(check-is-mem{info,_},e) + match(e) : (e:WRef) : if kind(e) != MemKind() : add(errors,NotMem(info,name(e))) - (e:WSubfield) : check-is-mem(exp(e)) - (e:WIndex) : check-is-mem(exp(e)) + (e:WSubfield) : check-is-mem(info,exp(e)) + (e:WIndex) : check-is-mem(info,exp(e)) (e) : false defn check-kinds-e (info:FileInfo,e:Expression) -> False : - match(map(check-kinds-e{info,_},e)) : + do(check-kinds-e{info,_},e) + match(e) : (e:ReadPort) : check-is-mem(info,mem(e)) check-not-mem(info,index(e)) @@ -270,21 +279,21 @@ public defn check-kinds (c:Circuit) -> Circuit : check-not-mem(info,enable(e)) (e:Pad) : check-not-mem(info,value(e)) - (e) : map(check-not-mem{info,_},e) - defn check-kinds-s (s:Stmt) -> Stmt : - map{check-kinds-s,_} $ { - match(map(check-kinds-e{info!(s),_},s)) : - (s:DefNode) : check-not-mem(info!(s),value(s)) - (s:DefAccessor) : check-not-mem(info!(s),index(s)) - (s:Conditionally) : check-not-mem(info!(s),pred(s)) - (s:Connect) : - check-not-mem(info!(s),loc(s)) - check-not-mem(info!(s),exp(s)) - (s:OnReset) : - check-is-reg(info!(s),loc(s)) - check-not-mem(info!(s),exp(s)) - (s) : false - s }() + (e) : do(check-not-mem{info,_},e) + defn check-kinds-s (s:Stmt) -> False : + do(check-kinds-e{info!(s),_:Expression},s) + match(s) : + (s:DefNode) : check-not-mem(info!(s),value(s)) + (s:DefAccessor) : check-not-mem(info!(s),index(s)) + (s:Conditionally) : check-not-mem(info!(s),pred(s)) + (s:Connect) : + check-not-mem(info!(s),loc(s)) + check-not-mem(info!(s),exp(s)) + (s:OnReset) : + check-is-reg(info!(s),loc(s)) + check-not-mem(info!(s),exp(s)) + (s) : false + do(check-kinds-s,s) for m in modules(c) do : check-kinds-s(body(m)) @@ -307,13 +316,45 @@ defn SubfieldNotInBundle (info:FileInfo, name:Symbol) : PassException $ string-join $ [info ": Subfield " name " is not in bundle."] +defn SubfieldOnNonBundle (info:FileInfo, name:Symbol) : + PassException $ string-join $ + [info ": Subfield " name " is accessed on a non-bundle."] + +defn IndexTooLarge (info:FileInfo, value:Int) : + PassException $ string-join $ + [info ": Index with value " value " is too large."] + +defn IndexOnNonVector (info:FileInfo) : + PassException $ string-join $ + [info ": Index illegal on non-vector type."] + +defn IndexNotUInt (info:FileInfo) : + PassException $ string-join $ + [info ": Index is not of UIntType."] + +defn EnableNotUInt (info:FileInfo) : + PassException $ string-join $ + [info ": Enable is not of UIntType."] + +defn PadNotGround (info:FileInfo) : + PassException $ string-join $ + [info ": Illegal Pad on non-ground type."] + +defn InvalidConnect (info:FileInfo) : + PassException $ string-join $ + [info ": Type mismatch."] + +defn PredNotUInt (info:FileInfo) : + PassException $ string-join $ + [info ": Predicate not a UIntType."] + ;---------------- Helper Functions -------------- -defn equal? (t1:Type,t2:Type) -> True|False : +defmethod equal? (t1:Type,t2:Type) -> True|False : match(t1,t2) : (t1:UIntType,t2:UIntType) : true (t1:SIntType,t2:SIntType) : true (t1:BundleType,t2:BundleType) : - val same? = true + var same? = true for (f1 in fields(t1),f2 in fields(t2)) do : if flip(f1) != flip(f2) : same? = false if name(f1) != name(f2) : same? = false @@ -324,19 +365,19 @@ defn equal? (t1:Type,t2:Type) -> True|False : else : false (t1,t2) : false -defn u() -> UIntType : UIntType(UnknownWidth()) -defn s() -> SIntType : SIntType(UnknownWidth()) +defn u () -> UIntType : UIntType(UnknownWidth()) +defn s () -> SIntType : SIntType(UnknownWidth()) ;----------------- Check Types Pass --------------------- public defn check-types (c:Circuit) -> Circuit : - val errors = Vector() - defn check-types-e (info:FileInfo,e:Expression) -> Expression - match(map(check-types-e{info,_},s)) : + val errors = Vector() + defn check-types-e (info:FileInfo,e:Expression) -> Expression : + match(map(check-types-e{info,_},e)) : (e:WRef) : e (e:WSubfield) : match(type(exp(e))) : (t:BundleType) : - val ft = for p in fields(v) find : name(p) == s + val ft = for p in fields(t) find : name(p) == s if ft == false : add(errors,SubfieldNotInBundle(info,name(e))) (t) : add(errors,SubfieldOnNonBundle(info,name(e))) (e:WIndex) : @@ -344,7 +385,7 @@ public defn check-types (c:Circuit) -> Circuit : (t:VectorType) : if value(e) >= size(t) : add(errors,IndexTooLarge(info,value(e))) (t) : add(errors,IndexOnNonVector(info)) - (e:DoPrim) : check-types-primop(e) + (e:DoPrim) : false ;check-types-primop(e) (e:ReadPort|WritePort) : if type(index(e)) != u() : add(errors,IndexNotUInt(info)) if type(enable(e)) != u() : add(errors,EnableNotUInt(info)) @@ -357,13 +398,14 @@ public defn check-types (c:Circuit) -> Circuit : e defn check-types-s (s:Stmt) -> Stmt : map{check-types-s,_} $ - match(map(check-types-e,s)) : + match(map(check-types-e{info!(s),_},s)) : (s:Connect|OnReset) : if type(loc(s)) == type(exp(s)) : add(errors,InvalidConnect(info!(s))) + s (s:Conditionally) : - if type(pred(s)) != u() : add(errors,PredNotUInt(info)) - (s) : false - s + if type(pred(s)) != u() : add(errors,PredNotUInt(info!(s))) + s + (s) : s for m in modules(c) do : check-types-s(body(m)) diff --git a/src/main/stanza/passes.stanza b/src/main/stanza/passes.stanza index 8e15f0e6..00f158d9 100644 --- a/src/main/stanza/passes.stanza +++ b/src/main/stanza/passes.stanza @@ -18,18 +18,17 @@ public defn PassExceptions (xs:Streamable) : PassException(string-join(xs, "\n")) ;=============== WORKING IR ================================ -definterface Kind -defstruct WireKind <: Kind -defstruct RegKind <: Kind -defstruct InstanceKind <: Kind -defstruct ReadAccessorKind <: Kind -defstruct WriteAccessorKind <: Kind -defstruct PortKind <: Kind -defstruct NodeKind <: Kind ; All elems except structural memory, wires - -defstruct MemKind <: Kind -defstruct ModuleKind <: Kind -defstruct AccessorKind <: Kind +public definterface Kind +public defstruct WireKind <: Kind +public defstruct RegKind <: Kind +public defstruct InstanceKind <: Kind +public defstruct ReadAccessorKind <: Kind +public defstruct WriteAccessorKind <: Kind +public defstruct PortKind <: Kind +public defstruct NodeKind <: Kind ; All elems except structural memory, wires +public defstruct MemKind <: Kind +public defstruct ModuleKind <: Kind +public defstruct AccessorKind <: Kind public definterface Gender public val MALE = new Gender @@ -37,25 +36,25 @@ public val FEMALE = new Gender public val UNKNOWN-GENDER = new Gender public val BI-GENDER = new Gender -defstruct WRef <: Expression : +public defstruct WRef <: Expression : name: Symbol type: Type with: (as-method => true) kind: Kind gender: Gender with: (as-method => true) -defstruct WSubfield <: Expression : +public defstruct WSubfield <: Expression : exp: Expression name: Symbol type: Type with: (as-method => true) gender: Gender with: (as-method => true) -defstruct WIndex <: Expression : +public defstruct WIndex <: Expression : exp: Expression value: Int type: Type with: (as-method => true) gender: Gender with: (as-method => true) -defstruct WDefAccessor <: Stmt : +public defstruct WDefAccessor <: Stmt : name: Symbol source: Expression index: Expression @@ -719,18 +718,18 @@ defn expand-expr (e:Expression) -> List : for x in generate-entry(name(e),type(e)) map : EF(WRef(name(x),type(x),kind(e),gender(e)), flip(x)) (e:WSubfield) : + val f = {_ as Field} $ + for f in fields(type(exp(e)) as BundleType) find : name(f) == name(e) if inst?(exp(e)) : - val i = exp(e) - val f = {_ as Field} $ - for f in fields(type(i) as BundleType) find : name(f) == name(e) + println-all(["here with " exp(e)]) for x in generate-entry(name(f),type(f)) map : - EF(WSubfield(i,name(x),type(x),gender(e)),flip(x)) + EF(WSubfield(exp(e),name(x),type(x),gender(e)),flip(x)) else : val exps = expand-expr(exp(e)) val begin = index-of-elem(type(exp(e)) as BundleType,name(e)) val len = num-elems(type(e)) val ret = headn(tailn(exps,begin),len) - for r in ret map : EF(exp(r),DEFAULT) + for r in ret map : EF(exp(r),flip(r) * flip(f)) (e:WIndex) : val exps = expand-expr(exp(e)) val len = num-elems(type(e)) diff --git a/test/chisel3/Memory.fir b/test/chisel3/Memory.fir new file mode 100644 index 00000000..67f0a7cf --- /dev/null +++ b/test/chisel3/Memory.fir @@ -0,0 +1,204 @@ +; RUN: firrtl -i %s -o %s.flo -x X -p c | tee %s.out | FileCheck %s +; CHECK: Done! + +circuit Memory : + module Queue : + output count : UInt<3> + input enq : {valid : UInt<1>, flip ready : UInt<1>, bits : {mask : UInt<4>, rw : UInt<1>, tag : UInt<5>, addr : UInt<32>}} + output deq : {valid : UInt<1>, flip ready : UInt<1>, bits : {mask : UInt<4>, rw : UInt<1>, tag : UInt<5>, addr : UInt<32>}} + + mem ram : {mask : UInt<4>, rw : UInt<1>, tag : UInt<5>, addr : UInt<32>}[4] + reg T_292 : UInt<2> + on-reset T_292 := UInt<2>(0) + reg T_293 : UInt<2> + on-reset T_293 := UInt<2>(0) + reg maybe_full : UInt<1> + on-reset maybe_full := UInt<1>(0) + node ptr_match = eq(T_292, T_293) + node T_294 = bit-not(maybe_full) + node empty = bit-and(ptr_match, T_294) + node full = bit-and(ptr_match, maybe_full) + node maybe_flow = bit-and(UInt<1>(0), empty) + node do_flow = bit-and(maybe_flow, deq.ready) + node T_295 = bit-and(enq.ready, enq.valid) + node T_296 = bit-not(do_flow) + node do_enq = bit-and(T_295, T_296) + node T_297 = bit-and(deq.ready, deq.valid) + node T_298 = bit-not(do_flow) + node do_deq = bit-and(T_297, T_298) + when do_enq : + accessor T_299 = ram[T_292] + T_299 := enq.bits + node T_300 = eq(T_292, UInt<2>(3)) + node T_301 = bit-and(UInt<1>(0), T_300) + node T_302 = add-wrap(T_292, UInt<2>(1)) + node T_303 = mux(T_301, UInt<2>(0), T_302) + T_292 := T_303 + when do_deq : + node T_304 = eq(T_293, UInt<2>(3)) + node T_305 = bit-and(UInt<1>(0), T_304) + node T_306 = add-wrap(T_293, UInt<2>(1)) + node T_307 = mux(T_305, UInt<2>(0), T_306) + T_293 := T_307 + node T_308 = neq(do_enq, do_deq) + when T_308 : maybe_full := do_enq + node T_309 = bit-not(empty) + node T_310 = bit-and(UInt<1>(0), enq.valid) + node T_311 = bit-or(T_309, T_310) + deq.valid := T_311 + node T_312 = bit-not(full) + node T_313 = bit-and(UInt<1>(0), deq.ready) + node T_314 = bit-or(T_312, T_313) + enq.ready := T_314 + accessor T_315 = ram[T_293] + wire T_316 : {mask : UInt<4>, rw : UInt<1>, tag : UInt<5>, addr : UInt<32>} + node T_317 = mux(maybe_flow, enq.bits.mask, T_315.mask) + T_316.mask := T_317 + node T_318 = mux(maybe_flow, enq.bits.rw, T_315.rw) + T_316.rw := T_318 + node T_319 = mux(maybe_flow, enq.bits.tag, T_315.tag) + T_316.tag := T_319 + node T_320 = mux(maybe_flow, enq.bits.addr, T_315.addr) + T_316.addr := T_320 + deq.bits := T_316 + node ptr_diff = sub-wrap(T_292, T_293) + node T_321 = bit-and(maybe_full, ptr_match) + node T_322 = cat(T_321, ptr_diff) + count := Pad(T_322,3) + module Queue_228 : + output count : UInt<3> + input enq : {valid : UInt<1>, flip ready : UInt<1>, bits : {data : UInt<32>}} + output deq : {valid : UInt<1>, flip ready : UInt<1>, bits : {data : UInt<32>}} + + mem ram : {data : UInt<32>}[4] + reg T_323 : UInt<2> + on-reset T_323 := UInt<2>(0) + reg T_324 : UInt<2> + on-reset T_324 := UInt<2>(0) + reg maybe_full : UInt<1> + on-reset maybe_full := UInt<1>(0) + node ptr_match = eq(T_323, T_324) + node T_325 = bit-not(maybe_full) + node empty = bit-and(ptr_match, T_325) + node full = bit-and(ptr_match, maybe_full) + node maybe_flow = bit-and(UInt<1>(0), empty) + node do_flow = bit-and(maybe_flow, deq.ready) + node T_326 = bit-and(enq.ready, enq.valid) + node T_327 = bit-not(do_flow) + node do_enq = bit-and(T_326, T_327) + node T_328 = bit-and(deq.ready, deq.valid) + node T_329 = bit-not(do_flow) + node do_deq = bit-and(T_328, T_329) + when do_enq : + accessor T_330 = ram[T_323] + T_330 := enq.bits + node T_331 = eq(T_323, UInt<2>(3)) + node T_332 = bit-and(UInt<1>(0), T_331) + node T_333 = add-wrap(T_323, UInt<2>(1)) + node T_334 = mux(T_332, UInt<2>(0), T_333) + T_323 := T_334 + when do_deq : + node T_335 = eq(T_324, UInt<2>(3)) + node T_336 = bit-and(UInt<1>(0), T_335) + node T_337 = add-wrap(T_324, UInt<2>(1)) + node T_338 = mux(T_336, UInt<2>(0), T_337) + T_324 := T_338 + node T_339 = neq(do_enq, do_deq) + when T_339 : maybe_full := do_enq + node T_340 = bit-not(empty) + node T_341 = bit-and(UInt<1>(0), enq.valid) + node T_342 = bit-or(T_340, T_341) + deq.valid := T_342 + node T_343 = bit-not(full) + node T_344 = bit-and(UInt<1>(0), deq.ready) + node T_345 = bit-or(T_343, T_344) + enq.ready := T_345 + accessor T_346 = ram[T_324] + wire T_347 : {data : UInt<32>} + node T_348 = mux(maybe_flow, enq.bits.data, T_346.data) + T_347.data := T_348 + deq.bits := T_347 + node ptr_diff = sub-wrap(T_323, T_324) + node T_349 = bit-and(maybe_full, ptr_match) + node T_350 = cat(T_349, ptr_diff) + count := Pad(T_350,3) + module Memory : + output stall : UInt<1> + output memory : {flip resp : {valid : UInt<1>, flip ready : UInt<1>, bits : {data : UInt<32>, tag : UInt<5>}}, req_data : {valid : UInt<1>, flip ready : UInt<1>, bits : {data : UInt<32>}}, req_cmd : {valid : UInt<1>, flip ready : UInt<1>, bits : {mask : UInt<4>, rw : UInt<1>, tag : UInt<5>, addr : UInt<32>}}} + input icache : {re : UInt<1>, addr : UInt<32>, din : UInt<32>, flip dout : UInt<32>, we : UInt<4>} + input dcache : {re : UInt<1>, addr : UInt<32>, din : UInt<32>, flip dout : UInt<32>, we : UInt<4>} + + inst memReqCmdQueue of Queue + inst memReqDataQueue of Queue_228 + reg state : UInt<1> + on-reset state := UInt<1>(0) + reg tag : UInt<5> + on-reset tag := UInt<5>(0) + node T_351 = eq(state, UInt<1>(0)) + node T_352 = bit-or(icache.re, dcache.re) + node T_353 = eq(dcache.we, UInt<4>(0)) + node T_354 = bit-not(T_353) + node T_355 = bit-or(T_352, T_354) + node cpuReq = bit-and(T_351, T_355) + node T_356 = bits(icache.addr, 31, 2) + node iaddr = cat(T_356, UInt<2>(0)) + node T_357 = bits(dcache.addr, 31, 2) + node daddr = cat(T_357, UInt<2>(0)) + reg idata : UInt + reg ddata : UInt + reg ire : UInt<1> + reg dre : UInt<1> + icache.dout := Pad(idata,?) + dcache.dout := Pad(ddata,?) + memReqCmdQueue.deq := memory.req_cmd + memReqDataQueue.deq := memory.req_data + memory.resp.ready := UInt<1>(0) + node T_358 = eq(state, UInt<1>(1)) + node T_359 = bit-not(memReqCmdQueue.enq.ready) + node T_360 = bit-or(T_358, T_359) + node T_361 = bit-not(memReqDataQueue.enq.ready) + node T_362 = bit-or(T_360, T_361) + stall := T_362 + node T_363 = eq(dcache.we, UInt<4>(0)) + node T_364 = bit-not(T_363) + memReqCmdQueue.enq.bits.rw := T_364 + memReqCmdQueue.enq.bits.tag := tag + node T_365 = eq(dcache.we, UInt<4>(0)) + node T_366 = bit-not(T_365) + node T_367 = bit-not(icache.re) + node T_368 = bit-or(T_366, T_367) + node T_369 = mux(T_368, daddr, iaddr) + memReqCmdQueue.enq.bits.addr := T_369 + memReqCmdQueue.enq.bits.mask := dcache.we + node T_370 = bit-and(memReqDataQueue.enq.ready, cpuReq) + memReqCmdQueue.enq.valid := T_370 + memReqDataQueue.enq.bits.data := dcache.din + node T_371 = bit-and(memReqCmdQueue.enq.ready, cpuReq) + node T_372 = eq(dcache.we, UInt<4>(0)) + node T_373 = bit-not(T_372) + node T_374 = bit-and(T_371, T_373) + memReqDataQueue.enq.valid := T_374 + node T_375 = eq(UInt<1>(0), state) + when T_375 : + node T_376 = bit-or(icache.re, dcache.re) + node T_377 = eq(dcache.we, UInt<4>(0)) + node T_378 = bit-not(T_377) + node T_379 = bit-not(T_378) + node T_380 = bit-and(T_376, T_379) + node T_381 = bit-and(T_380, memReqCmdQueue.enq.ready) + when T_381 : + ire := icache.re + dre := dcache.re + state := UInt<1>(1) + node T_382 = eq(UInt<1>(1), state) + when T_382 : + memory.resp.ready := UInt<1>(1) + node T_383 = eq(memory.resp.bits.tag, tag) + node T_384 = bit-and(memory.resp.valid, T_383) + when T_384 : + state := UInt<1>(0) + node T_385 = add-wrap(tag, UInt<5>(1)) + tag := T_385 + memory.resp.ready := UInt<1>(0) + when ire : idata := Pad(memory.resp.bits.data,?) + when dre : ddata := Pad(memory.resp.bits.data,?) diff --git a/test/passes/expand-whens/scoped-reg.fir b/test/passes/expand-whens/scoped-reg.fir new file mode 100644 index 00000000..20c91386 --- /dev/null +++ b/test/passes/expand-whens/scoped-reg.fir @@ -0,0 +1,12 @@ +; RUN: firrtl -i %s -o %s.flo -x abcdefghijk -p c | tee %s.out | FileCheck %s +; CHECK: Expand Whens +circuit top : + module A : + wire p : UInt + when p : + reg r : UInt + on-reset r := UInt(10) + r := UInt(20) +; CHECK: r := Register(mux-uu(reset, UInt(10), UInt(20)), mux-uu(reset, UInt(1), p)) +; CHECK: Finished Expand Whens + diff --git a/test/passes/lower-to-ground/test.fir b/test/passes/lower-to-ground/test.fir new file mode 100644 index 00000000..fb951bff --- /dev/null +++ b/test/passes/lower-to-ground/test.fir @@ -0,0 +1,13 @@ +; RUN: firrtl -i %s -o %s.flo -x X -p cd | tee %s.out | FileCheck %s +; CHECK: Done! + +circuit Top : + module Queue : + output out : {valid : UInt<1>, flip ready : UInt<1>} + module Top : + output this : {out : {valid : UInt<1>, flip ready : UInt<1>}} + inst queue of Queue + this.out := queue.out + wire w : { x : UInt, flip y : UInt} + wire a : UInt + w.y := a -- cgit v1.2.3