CIRCT

Circuit IR Compilers and Tools

'esi' Dialect

Operation definition

esi.decode.capnp (::circt::esi::CapnpDecodeOp)

Translate bits in Cap’nProto messages to HW typed data

Syntax:

operation ::= `esi.decode.capnp` $clk $valid $capnpBits attr-dict `:` qualified(type($capnpBits)) `->`
              qualified(type($decodedData))

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
clk1-bit signless integer
valid1-bit signless integer
capnpBitsan HW bit array

Results:

ResultDescription
decodedDataany type

esi.encode.capnp (::circt::esi::CapnpEncodeOp)

Translate HW typed data to Cap’nProto

Syntax:

operation ::= `esi.encode.capnp` $clk $valid $dataToEncode attr-dict `:` qualified(type($dataToEncode))
              `->` qualified(type($capnpBits))

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
clk1-bit signless integer
valid1-bit signless integer
dataToEncodeany type

Results:

ResultDescription
capnpBitsan HW bit array

esi.buffer (::circt::esi::ChannelBufferOp)

Control options for an ESI channel.

A channel buffer (buffer) is essentially a set of options on a channel. It always adds at least one cycle of latency (pipeline stage) to the channel, but this is configurable.

This operation is inserted on an ESI dataflow edge. It must exist previous to SystemVerilog emission but can be added in a lowering pass.

A stages attribute may be provided to specify a specific number of cycles (pipeline stages) to use on this channel. Must be greater than 0.

A name attribute may be provided to assigned a name to a buffered connection.

Example:

%esiChan = hw.instance "sender" @Sender () : () -> (!esi.channel<i1>)
// Allow automatic selection of options.
%bufferedChan = esi.buffer %esiChan : i1
hw.instance "recv" @Reciever (%bufferedChan) : (!esi.channel<i1>) -> ()

// Alternatively, specify the number of stages.
%fourStageBufferedChan = esi.buffer %esiChan { stages = 4 } : i1

Traits: AlwaysSpeculatableImplTrait

Interfaces: ChannelOpInterface, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
stages::mlir::IntegerAttr64-bit signless integer attribute whose minimum value is 1
name::mlir::StringAttrstring attribute

Operands:

OperandDescription
clk1-bit signless integer
rst1-bit signless integer
inputAn ESI-compatible channel port

Results:

ResultDescription
outputAn ESI-compatible channel port

esi.cosim (::circt::esi::CosimEndpointOp)

Co-simulation endpoint

Syntax:

operation ::= `esi.cosim` $clk `,` $rst `,` $send `,` $name attr-dict
              `:` qualified(type($send)) `->` qualified(type($recv))

A co-simulation endpoint is a connection from the simulation to some outside process, usually a software application responsible for driving the simulation (driver).

ESI uses a serialization protocol called Cap’n Proto (capnp for short). The advantage of capnp is the decoding overhead: for value types (ints, structs, etc.) there is none! This stands in contrast to Protocol Buffers and Bond as their messages contain metadata for each field which must be interpreted.

The advantage of using a well-supported serialization protocol is language support – driver applications can be written in any language supported by the specific protocol.

Attributes:

AttributeMLIR TypeDescription
name::mlir::StringAttrstring attribute

Operands:

OperandDescription
clk1-bit signless integer
rst1-bit signless integer
sendAn ESI-compatible channel port

Results:

ResultDescription
recvAn ESI-compatible channel port

esi.service.decl (::circt::esi::CustomServiceDeclOp)

An ESI service interface declaration

Syntax:

operation ::= `esi.service.decl` $sym_name $ports attr-dict

A declaration of an ESI service interface. Defines a contract between a service provider and its clients.

Example:

esi.service.decl @HostComms {
  esi.service.to_server send : !esi.channel<!esi.any>
  esi.service.to_client recieve : !esi.channel<i8>
}

Traits: HasParent<::mlir::ModuleOp>, NoTerminator, SingleBlock

Interfaces: ServiceDeclOpInterface, Symbol

Attributes:

AttributeMLIR TypeDescription
sym_name::mlir::StringAttrstring attribute

esi.null (::circt::esi::NullSourceOp)

An op which never produces messages.

Syntax:

operation ::= `esi.null` attr-dict `:` qualified(type($out))

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Results:

ResultDescription
outAn ESI-compatible channel port

esi.stage (::circt::esi::PipelineStageOp)

An elastic buffer stage.

An individual elastic pipeline register. Generally lowered to from a ChannelBuffer (‘buffer’), though can be inserted anywhere to add an additional pipeline stage. Adding individually could be useful for late-pass latency balancing.

Traits: AlwaysSpeculatableImplTrait

Interfaces: ChannelOpInterface, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
clk1-bit signless integer
rst1-bit signless integer
inputAn ESI-compatible channel port

Results:

ResultDescription
outputAn ESI-compatible channel port

esi.mem.ram (::circt::esi::RandomAccessMemoryDeclOp)

Random access memory service

Syntax:

operation ::= `esi.mem.ram` $sym_name $innerType `x` $depth attr-dict

Declares a service which is backed by a memory of some sort. Allows random access of the inner elements.

Ports: read(address: clog2(depth)) -> data: innerType write({address: clog2(depth), data: innerType}) -> done: i0

Users can ensure R/W ordering by waiting for the write “done” message before issuing a potentially dependant read. Ordering of R/W messages in flight is undefined.

Traits: HasParent<::mlir::ModuleOp>, NoTerminator, SingleBlock

Interfaces: ServiceDeclOpInterface, Symbol

Attributes:

AttributeMLIR TypeDescription
sym_name::mlir::StringAttrstring attribute
innerType::mlir::TypeAttrany type attribute
depth::mlir::IntegerAttr64-bit signless integer attribute

esi.service.req.inout (::circt::esi::RequestInOutChannelOp)

Request a bidirectional channel

Syntax:

operation ::= `esi.service.req.inout` $toServer `->` $servicePort `(` $clientNamePath `)` attr-dict `:`
              qualified(type($toServer)) `->` qualified(type($toClient))

Interfaces: SymbolUserOpInterface

Attributes:

AttributeMLIR TypeDescription
servicePort::circt::hw::InnerRefAttrname reference attribute
clientNamePath::mlir::ArrayAttrstring array attribute

Operands:

OperandDescription
toServerAn ESI-compatible channel port

Results:

ResultDescription
toClientAn ESI-compatible channel port

esi.service.req.to_client (::circt::esi::RequestToClientConnectionOp)

Request a connection to receive data

Syntax:

operation ::= `esi.service.req.to_client` $servicePort `(` $clientNamePath `)`
              attr-dict `:` qualified(type($toClient))

Interfaces: SymbolUserOpInterface

Attributes:

AttributeMLIR TypeDescription
servicePort::circt::hw::InnerRefAttrname reference attribute
clientNamePath::mlir::ArrayAttrstring array attribute

Results:

ResultDescription
toClientAn ESI-compatible channel port

esi.service.req.to_server (::circt::esi::RequestToServerConnectionOp)

Request a connection to send data

Syntax:

operation ::= `esi.service.req.to_server` $toServer `->` $servicePort `(` $clientNamePath `)`
              attr-dict `:` qualified(type($toServer))

Interfaces: SymbolUserOpInterface

Attributes:

AttributeMLIR TypeDescription
servicePort::circt::hw::InnerRefAttrname reference attribute
clientNamePath::mlir::ArrayAttrstring array attribute

Operands:

OperandDescription
toServerAn ESI-compatible channel port

esi.service.inout (::circt::esi::ServiceDeclInOutOp)

An ESI service port which has both directions

Syntax:

operation ::= `esi.service.inout` $inner_sym attr-dict
              `:` qualified($toServerType) `->` qualified($toClientType)

Traits: HasParent<::circt::esi::CustomServiceDeclOp>

Attributes:

AttributeMLIR TypeDescription
inner_sym::mlir::StringAttrstring attribute
toServerType::mlir::TypeAttrany type attribute
toClientType::mlir::TypeAttrany type attribute

esi.service.hierarchy.metadata (::circt::esi::ServiceHierarchyMetadataOp)

Metadata about a service in the service hierarchy

Syntax:

operation ::= `esi.service.hierarchy.metadata` `path` $serverNamePath (`implementing` $service_symbol^)?
              `impl` `as` $impl_type (`opts` $impl_details^)?
              `clients` $clients attr-dict

Interfaces: SymbolUserOpInterface

Attributes:

AttributeMLIR TypeDescription
service_symbol::mlir::FlatSymbolRefAttrflat symbol reference attribute
serverNamePath::mlir::ArrayAttrarray attribute
impl_type::mlir::StringAttrstring attribute
impl_details::mlir::DictionaryAttrdictionary of named attribute values
clients::mlir::ArrayAttrarray attribute

esi.service.impl_req (::circt::esi::ServiceImplementReqOp)

Request for a service to be implemented

Syntax:

operation ::= `esi.service.impl_req` (`svc` $service_symbol^)? `impl` `as` $impl_type (`opts` $impl_opts^)?
              `(` $inputs `)` attr-dict `:` functional-type($inputs, results)
              $portReqs

The connect services pass replaces service.instances with this op. The portReqs region is the set of connection requests which need to be implemented for this service instance. Channels to/from the requests have been added to the operands/results of this op and consumers/producers have been redirected.

Some other pass or frontend is expected to replace this op with an actual implementation.

Traits: NoTerminator

Attributes:

AttributeMLIR TypeDescription
service_symbol::mlir::FlatSymbolRefAttrflat symbol reference attribute
impl_type::mlir::StringAttrstring attribute
impl_opts::mlir::DictionaryAttrdictionary of named attribute values

Operands:

OperandDescription
inputsany type

Results:

ResultDescription
outputsany type

esi.service.instance (::circt::esi::ServiceInstanceOp)

Instantiate a server module

Syntax:

operation ::= `esi.service.instance` (`svc` $service_symbol^)? `impl` `as` $impl_type (`opts` $impl_opts^)?
              `(` $inputs `)` attr-dict `:` functional-type($inputs, results)

Instantiate a service adhering to a service declaration interface.

A pass collects all of the connection requests to the service this op implements from the containing modules’ descendants (in the instance hierarchy). It bubbles them all up to the module containing this op, creating the necessary ESI channel ports, groups them appropriately, then replaces this op with a service.impl_req.

If ‘service_symbol’ isn’t specified, this instance will be used to implement all of the service requests which get surfaced to here. This option is generally used at the top level to specify host connectivity.

Since implementing the server will usually need “normal” I/O, inputs and results act like normal hw.instance ports.

$identifier is used by frontends to specify or remember the type of implementation to use for this service.

Attributes:

AttributeMLIR TypeDescription
service_symbol::mlir::FlatSymbolRefAttrflat symbol reference attribute
impl_type::mlir::StringAttrstring attribute
impl_opts::mlir::DictionaryAttrdictionary of named attribute values

Operands:

OperandDescription
inputsany type

Results:

ResultDescription
«unnamed»any type

esi.service.to_client (::circt::esi::ToClientOp)

An ESI service port headed to a particular client

Syntax:

operation ::= `esi.service.to_client` $inner_sym  attr-dict `:` $toClientType

Traits: HasParent<::circt::esi::CustomServiceDeclOp>

Attributes:

AttributeMLIR TypeDescription
inner_sym::mlir::StringAttrstring attribute
toClientType::mlir::TypeAttrany type attribute

esi.service.to_server (::circt::esi::ToServerOp)

An ESI service port headed to the service

Syntax:

operation ::= `esi.service.to_server` $inner_sym attr-dict `:` $toServerType

Traits: HasParent<::circt::esi::CustomServiceDeclOp>

Attributes:

AttributeMLIR TypeDescription
inner_sym::mlir::StringAttrstring attribute
toServerType::mlir::TypeAttrany type attribute

esi.unwrap.iface (::circt::esi::UnwrapSVInterfaceOp)

Unwrap an SV interface from an ESI port

Syntax:

operation ::= `esi.unwrap.iface` $chanInput `into` $interfaceSource attr-dict `:` `(` qualified(type($chanInput)) `,` qualified(type($interfaceSource)) `)`

Unwrap an ESI channel into a SystemVerilog interface containing valid, ready, and data signals.

Interfaces: ChannelOpInterface

Operands:

OperandDescription
chanInputAn ESI-compatible channel port
interfaceSourcesv.interface

esi.unwrap.vr (::circt::esi::UnwrapValidReadyOp)

Unwrap a value from an ESI port

Unwrapping a value allows operations on the contained value. Unwrap the channel along with a ready signal that you generate. Result is the data along with a valid signal.

Traits: AlwaysSpeculatableImplTrait

Interfaces: ChannelOpInterface, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
chanInputAn ESI-compatible channel port
ready1-bit signless integer

Results:

ResultDescription
rawOutputany type
valid1-bit signless integer

esi.wrap.iface (::circt::esi::WrapSVInterfaceOp)

Wrap an SV interface into an ESI port

Syntax:

operation ::= `esi.wrap.iface` $interfaceSink attr-dict `:` qualified(type($interfaceSink)) `->` qualified(type($output))

Wrap a SystemVerilog interface into an ESI channel. Interface MUST look like an interface produced by ESI meaning it MUST contain valid, ready, and data signals. Any other signals will be discarded.

Traits: AlwaysSpeculatableImplTrait

Interfaces: ChannelOpInterface, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
interfaceSinksv.interface

Results:

ResultDescription
outputAn ESI-compatible channel port

esi.wrap.vr (::circt::esi::WrapValidReadyOp)

Wrap a value into an ESI port

Wrapping a value into an ESI port type allows modules to send values down an ESI port. Wrap data with valid bit, result is the ESI channel and the ready signal from the other end of the channel.

Traits: AlwaysSpeculatableImplTrait

Interfaces: ChannelOpInterface, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
rawInputany type
valid1-bit signless integer

Results:

ResultDescription
chanOutputAn ESI-compatible channel port
ready1-bit signless integer

Type definition

ChannelType

An ESI-compatible channel port

Syntax:

!esi.channel<
  Type   # inner
>

An ESI port kind which models a latency-insensitive, unidirectional, point-to-point data stream. Channels are typed (like all of ESI). Said type can be any MLIR type, but must be lowered to something a backend knows how to output (i.e. something emitVerilog knows about).

Example:

hw.module.extern @Sender() -> (%x: !esi.channel<i1>)
hw.module @Reciever(%a: !esi.channel<hw.array<5xi16>>) { }

Parameters:

ParameterC++ typeDescription
innerType

AnyType

any type

Syntax: !esi.any

Used to state that any type is accepted. The specific type will be determined later in compilation.

'esi' Dialect Docs