Skip to content

Understanding Firrtl Intermediate Representation

Chick Markley edited this page Sep 15, 2016 · 2 revisions

This page describes common FirrtlNodes found in firrtl/src/main/scala/firrtl/ir/IR.scala.

For more detail on components not mentioned here, please refer to The FIRRTL Specification.

Overview

The Firrtl datastructure is an AST (abstract syntax tree) describing a digital circuit, with a corresponding concrete syntax that is human-readable. The following examples show examples of concrete syntax parsed into the Firrtl AST.

Many Firrtl nodes contain an info: Info field, which the parser can either insert file information like line number and column number, or insert a NoInfo token. For clarity and simplicity, the following examples will all insert a NoInfo token.

Circuit

Circuit is the root node of any Firrtl datastructure. There is only ever one Circuit, and that Circuit contains a list of module definitions and the name of the top-level module.

FirrtlNode Declaration

Circuit(info: Info, modules: Seq[DefModule], main: String)

Concrete Syntax

circuit Adder:
  ... //List of modules

In-memory Representation

Circuit(NoInfo, Seq(...), "Adder")

Module

Modules are the unit of modularity within Firrtl and are never directly nested (declaring an instance of a module has its own concrete syntax and AST representation). Each Module has a name, and a list of ports, and a body containing its implementation.

FirrtlNode declaration

Module(info: Info, name: String, ports: Seq[Port], body: Stmt) extends DefModule

Concrete Syntax

module Adder:
  ... // list of ports
  ... // statements

In-memory representation

Module(NoInfo, "Adder", Seq(...), )

Port

A port defines part of a Module's io, and has a name, direction (input or output), and type.

FirrtlNode Declaration

class Port(info: Info, name: String, direction: Direction, tpe: Type)

Concrete Syntax

input x: UInt

In-memory representation

Port(NoInfo, "x", INPUT, UIntType(UnknownWidth))

Statement

A statement is used to describe the components within a module and how they interact. Below are some commonly used statements:

Block of Statements

A group of statements. Commonly used as the body field in a Module declaration.

Wire Declaration

A wire declaration, containing a name and type.

FirrtlNode declaration

DefWire(info: Info, name: String, tpe: Type)

Concrete syntax

wire w: UInt

In-memory Representation

DefWire(NoInfo, "w", UIntType(UnknownWidth))

Register Declaration

A register declaration, containing a name, type, clock signal, reset signal, and reset value.

FirrtlNode decalration

DefRegister(info: Info, name: String, tpe: Type, clock: Expression, reset: Expression, init: Expression)

DefMemory

DefNode

Connect

IsInvalid

EmptyStmt

Examples

Circuit(info: Info, modules: Seq[DefModule], main: String) Module(info: Info, name: String, ports: Seq[Port], body: Stmt) Port(info: Info, name: String, direction: Direction, tpe: Type) Block(stmts: Seq[Stmt]) Connect(info: Info, name: String, value: Expression) Ref(name: String, tpe: Type)

Circuit(NoInfo, Seq(Module(NoInfo, Seq(Port(NoInfo, )), "Adder")