'esi' Dialect
The Elastic Silicon Interconnect dialect aims to aid in accelerator system construction.
Application channels
The main component of ESI are point-to-point, typed channels that allow designers to connect modules to each other and software, then communicate by sending messages. Channels largely abstract away the details of message communication from the designer, though the designer can declaratively specify how to implement the channel.
Messages have types: ints, structs, arrays, unions, and variable-length lists. The width of a channel is not necessarily the same width as the message. ESI “windows” can be used to break up a message into a series of “frames”. IP blocks can emit / absorb “windowed” messages or full-sized messages, which can be automatically broken up to save wire area at the cost of bandwidth.
Any channel which is exposed to the host will have a platform-agnostic software API constructed for it based on the type of the channel. The software application merely has to connect to the accelerator then invoke a method to send or receive messages from the accelerator system.
ChannelBundleType
a group of related channels
Syntax:
!esi.bundle<
::llvm::ArrayRef<BundledChannel>, # channels
::mlir::UnitAttr # resettable
>
A channel bundle (sometimes referred to as just “bundle”) is a set of channels of associated signals, along with per-channel names and directions. The prototypical example for a bundle is a request-response channel pair.
The direction terminology is a bit confusing. Let us designate the module which is outputting the bundle as the “sender” module and a module which has a bundle as an input as the “receiver”. The directions “from” and “to” are from the senders perspective. So, the “to” direction means that channel is transmitting messages from the sender to the receiver. Then, “from” means that the sender is getting messages from the receiver (typically responses).
When requesting a bundle from a service, the client is always considered the sender. So the “to” direction is for the client to send messages to the service.
Parameters:
Parameter | C++ type | Description |
---|---|---|
channels | ::llvm::ArrayRef<BundledChannel> | |
resettable | ::mlir::UnitAttr | boolean flag |
ChannelType
An ESI-compatible channel port
Syntax:
!esi.channel<
Type, # inner
::circt::esi::ChannelSignaling # signaling
>
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:
Parameter | C++ type | Description |
---|---|---|
inner | Type | |
signaling | ::circt::esi::ChannelSignaling |
ClockType
A type for clock-carrying wires
Syntax: !seq.clock
The !seq.clock
type represents signals which can be used to drive the
clock input of sequential operations.
ListType
a runtime-variably sized list
Syntax:
!esi.list<
Type # elementType
>
In software, a chunk of memory with runtime-specified length. In hardware, a stream of runtime-specified amount of data transmitted over many cycles in compile-time specified specified windows (chunks).
Parameters:
Parameter | C++ type | Description |
---|---|---|
elementType | Type |
WindowType
a data window
Syntax:
!esi.window<
StringAttr, # name
mlir::Type, # into
::llvm::ArrayRef<WindowFrameType> # frames
>
A ‘data window’ allows designers to break up large messages into multiple frames (aka phits) spread across multiple cycles. Windows are specified in terms of a mapping of struct fields to frames. The width of a window is the maximum frame size + the union tag (log2(#frames)).
A data window does NOT imply an ESI channel.
Current restrictions:
- A field may only appear once.
- Fields may only be re-ordered (wrt the original message) within a frame.
- Array fields whose array length is not evenly divisible by ’numItems’ will have an implicit frame inserted directly after containing the leftover array items.
- Array fields with an array length MUST be in their own frame.
Parameters:
Parameter | C++ type | Description |
---|---|---|
name | StringAttr | |
into | mlir::Type | |
frames | ::llvm::ArrayRef<WindowFrameType> |
FirMemType
A FIRRTL-flavored memory
Syntax:
!seq.firmem<
uint64_t, # depth
uint32_t, # width
std::optional<uint32_t> # maskWidth
>
The !seq.firmem
type represents a FIRRTL-flavored memory declared by a
seq.firmem
operation. It captures the parameters of the memory that are
relevant to the read, write, and read-write ports, such as width and depth.
Parameters:
Parameter | C++ type | Description |
---|---|---|
depth | uint64_t | |
width | uint32_t | |
maskWidth | std::optional<uint32_t> |
HLMemType
Multi-dimensional memory type
Syntax:
hlmem-type ::== `hlmem` `<` dim-list element-type `>`
The HLMemType represents the type of an addressable memory structure. The type is inherently multidimensional. Dimensions must be known integer values.
Note: unidimensional memories are represented as <1x{element type}> - <{element type}> is illegal.
Parameters:
Parameter | C++ type | Description |
---|---|---|
shape | ::llvm::ArrayRef<int64_t> | |
elementType | Type |
WindowFieldType
a field-in-frame specifier
Syntax:
!esi.window.field<
StringAttr, # fieldName
uint64_t # numItems
>
Specify that a field should appear within the enclosing frame.
Parameters:
Parameter | C++ type | Description |
---|---|---|
fieldName | StringAttr | |
numItems | uint64_t | # of items in arrays or lists |
WindowFrameType
Declare a data window frame
Syntax:
!esi.window.frame<
StringAttr, # name
::llvm::ArrayRef<WindowFieldType> # members
>
A named list of fields which should appear in a given frame.
Parameters:
Parameter | C++ type | Description |
---|---|---|
name | StringAttr | |
members | ::llvm::ArrayRef<WindowFieldType> |
ListType
a runtime-variably sized list
Syntax:
!esi.list<
Type # elementType
>
In software, a chunk of memory with runtime-specified length. In hardware, a stream of runtime-specified amount of data transmitted over many cycles in compile-time specified specified windows (chunks).
Parameters:
Parameter | C++ type | Description |
---|---|---|
elementType | Type |
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:
Operand | Description |
---|---|
clk | A type for clock-carrying wires |
valid | 1-bit signless integer |
capnpBits | an HW bit array |
Results:
Result | Description |
---|---|
decodedData | any 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:
Operand | Description |
---|---|
clk | A type for clock-carrying wires |
valid | 1-bit signless integer |
dataToEncode | any type |
Results:
Result | Description |
---|---|
capnpBits | an 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:
Attribute | MLIR Type | Description |
---|---|---|
stages | ::mlir::IntegerAttr | 64-bit signless integer attribute whose minimum value is 1 |
name | ::mlir::StringAttr | string attribute |
Operands:
Operand | Description |
---|---|
clk | A type for clock-carrying wires |
rst | 1-bit signless integer |
input | an ESI channel |
Results:
Result | Description |
---|---|
output | an ESI channel |
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:
Attribute | MLIR Type | Description |
---|---|---|
name | ::mlir::StringAttr | string attribute |
Operands:
Operand | Description |
---|---|
clk | A type for clock-carrying wires |
rst | 1-bit signless integer |
send | an ESI channel |
Results:
Result | Description |
---|---|
recv | an ESI channel |
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:
Result | Description |
---|---|
out | an ESI channel |
esi.bundle.pack
(::circt::esi::PackBundleOp)
Pack channels into a bundle
Syntax:
operation ::= `esi.bundle.pack` $toChannels attr-dict `:` custom<UnPackBundleType>(
type($toChannels), type($fromChannels), type($bundle))
Interfaces: OpAsmOpInterface
Operands:
Operand | Description |
---|---|
toChannels | an ESI channel |
Results:
Result | Description |
---|---|
bundle | a group of related channels |
fromChannels | an ESI channel |
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:
Operand | Description |
---|---|
clk | A type for clock-carrying wires |
rst | 1-bit signless integer |
input | an ESI channel |
Results:
Result | Description |
---|---|
output | an ESI channel |
esi.bundle.unpack
(::circt::esi::UnpackBundleOp)
Unpack channels from a bundle
Syntax:
operation ::= `esi.bundle.unpack` $fromChannels `from` $bundle attr-dict `:` custom<UnPackBundleType>(
type($toChannels), type($fromChannels), type($bundle))
Interfaces: OpAsmOpInterface
Operands:
Operand | Description |
---|---|
bundle | a group of related channels |
fromChannels | an ESI channel |
Results:
Result | Description |
---|---|
toChannels | an ESI channel |
esi.unwrap.fifo
(::circt::esi::UnwrapFIFOOp)
Unwrap a value from an ESI port into a FIFO interface
Syntax:
operation ::= `esi.unwrap.fifo` $chanInput `,` $rden attr-dict `:` qualified(type($chanInput))
Interfaces: ChannelOpInterface, InferTypeOpInterface
Operands:
Operand | Description |
---|---|
chanInput | an ESI channel |
rden | 1-bit signless integer |
Results:
Result | Description |
---|---|
data | any type |
empty | 1-bit signless integer |
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:
Operand | Description |
---|---|
chanInput | an ESI channel |
interfaceSource | sv.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.
Interfaces: ChannelOpInterface
Operands:
Operand | Description |
---|---|
chanInput | an ESI channel |
ready | 1-bit signless integer |
Results:
Result | Description |
---|---|
rawOutput | any type |
valid | 1-bit signless integer |
esi.window.unwrap
(::circt::esi::UnwrapWindow)
Unwrap a data window into a union
Syntax:
operation ::= `esi.window.unwrap` $window attr-dict `:` qualified(type($window))
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands:
Operand | Description |
---|---|
window | a data window |
Results:
Result | Description |
---|---|
frame | a UnionType |
esi.wrap.fifo
(::circt::esi::WrapFIFOOp)
Wrap a value into an ESI port with FIFO signaling
Syntax:
operation ::= `esi.wrap.fifo` $data `,` $empty attr-dict `:`
custom<WrapFIFOType>(type($data), type($chanOutput))
Interfaces: ChannelOpInterface
Operands:
Operand | Description |
---|---|
data | any type |
empty | 1-bit signless integer |
Results:
Result | Description |
---|---|
chanOutput | an ESI channel |
rden | 1-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.
Interfaces: ChannelOpInterface
Operands:
Operand | Description |
---|---|
interfaceSink | sv.interface |
Results:
Result | Description |
---|---|
output | an ESI channel |
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.
Interfaces: ChannelOpInterface
Operands:
Operand | Description |
---|---|
rawInput | any type |
valid | 1-bit signless integer |
Results:
Result | Description |
---|---|
chanOutput | an ESI channel |
ready | 1-bit signless integer |
esi.window.wrap
(::circt::esi::WrapWindow)
Wrap a union into a data window
Syntax:
operation ::= `esi.window.wrap` $frame attr-dict `:` custom<InferWindowRet>(type($frame), type($window))
Traits: AlwaysSpeculatableImplTrait
Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)
Effects: MemoryEffects::Effect{}
Operands:
Operand | Description |
---|---|
frame | a UnionType |
Results:
Result | Description |
---|---|
window | a data window |
Services
ESI “services” provide device-wide connectivity and arbitration for shared resources, which can be requested from any IP block (service “client”). Standard services will include DRAM, clock/reset, statistical counter reporting, and debug.
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:
Attribute | MLIR Type | Description |
---|---|---|
sym_name | ::mlir::StringAttr | string 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: ServiceReqOpInterface, SymbolUserOpInterface
Attributes:
Attribute | MLIR Type | Description |
---|---|---|
servicePort | ::circt::hw::InnerRefAttr | Refer to a name inside a module |
clientNamePath | ::mlir::ArrayAttr | string array attribute |
Operands:
Operand | Description |
---|---|
toServer | an ESI channel |
Results:
Result | Description |
---|---|
toClient | an ESI channel |
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: ServiceReqOpInterface, SymbolUserOpInterface
Attributes:
Attribute | MLIR Type | Description |
---|---|---|
servicePort | ::circt::hw::InnerRefAttr | Refer to a name inside a module |
clientNamePath | ::mlir::ArrayAttr | string array attribute |
Results:
Result | Description |
---|---|
toClient | an ESI channel |
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: ServiceReqOpInterface, SymbolUserOpInterface
Attributes:
Attribute | MLIR Type | Description |
---|---|---|
servicePort | ::circt::hw::InnerRefAttr | Refer to a name inside a module |
clientNamePath | ::mlir::ArrayAttr | string array attribute |
Operands:
Operand | Description |
---|---|
toServer | an ESI channel |
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:
Attribute | MLIR Type | Description |
---|---|---|
inner_sym | ::mlir::StringAttr | string attribute |
toServerType | ::mlir::TypeAttr | any type attribute |
toClientType | ::mlir::TypeAttr | any 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:
Attribute | MLIR Type | Description |
---|---|---|
service_symbol | ::mlir::FlatSymbolRefAttr | flat symbol reference attribute |
serverNamePath | ::mlir::ArrayAttr | array attribute |
impl_type | ::mlir::StringAttr | string attribute |
impl_details | ::mlir::DictionaryAttr | dictionary of named attribute values |
clients | ::mlir::ArrayAttr | array 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.instance
s 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:
Attribute | MLIR Type | Description |
---|---|---|
service_symbol | ::mlir::FlatSymbolRefAttr | flat symbol reference attribute |
impl_type | ::mlir::StringAttr | string attribute |
impl_opts | ::mlir::DictionaryAttr | dictionary of named attribute values |
Operands:
Operand | Description |
---|---|
inputs | any type |
Results:
Result | Description |
---|---|
outputs | any 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:
Attribute | MLIR Type | Description |
---|---|---|
service_symbol | ::mlir::FlatSymbolRefAttr | flat symbol reference attribute |
impl_type | ::mlir::StringAttr | string attribute |
impl_opts | ::mlir::DictionaryAttr | dictionary of named attribute values |
Operands:
Operand | Description |
---|---|
inputs | any type |
Results:
Result | Description |
---|---|
«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:
Attribute | MLIR Type | Description |
---|---|---|
inner_sym | ::mlir::StringAttr | string attribute |
toClientType | ::mlir::TypeAttr | any 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:
Attribute | MLIR Type | Description |
---|---|---|
inner_sym | ::mlir::StringAttr | string attribute |
toServerType | ::mlir::TypeAttr | any type attribute |
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:
Attribute | MLIR Type | Description |
---|---|---|
sym_name | ::mlir::StringAttr | string attribute |
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:
Attribute | MLIR Type | Description |
---|---|---|
sym_name | ::mlir::StringAttr | string attribute |
innerType | ::mlir::TypeAttr | any type attribute |
depth | ::mlir::IntegerAttr | 64-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: ServiceReqOpInterface, SymbolUserOpInterface
Attributes:
Attribute | MLIR Type | Description |
---|---|---|
servicePort | ::circt::hw::InnerRefAttr | Refer to a name inside a module |
clientNamePath | ::mlir::ArrayAttr | string array attribute |
Operands:
Operand | Description |
---|---|
toServer | an ESI channel |
Results:
Result | Description |
---|---|
toClient | an ESI channel |
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: ServiceReqOpInterface, SymbolUserOpInterface
Attributes:
Attribute | MLIR Type | Description |
---|---|---|
servicePort | ::circt::hw::InnerRefAttr | Refer to a name inside a module |
clientNamePath | ::mlir::ArrayAttr | string array attribute |
Results:
Result | Description |
---|---|
toClient | an ESI channel |
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: ServiceReqOpInterface, SymbolUserOpInterface
Attributes:
Attribute | MLIR Type | Description |
---|---|---|
servicePort | ::circt::hw::InnerRefAttr | Refer to a name inside a module |
clientNamePath | ::mlir::ArrayAttr | string array attribute |
Operands:
Operand | Description |
---|---|
toServer | an ESI channel |
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:
Attribute | MLIR Type | Description |
---|---|---|
inner_sym | ::mlir::StringAttr | string attribute |
toServerType | ::mlir::TypeAttr | any type attribute |
toClientType | ::mlir::TypeAttr | any 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:
Attribute | MLIR Type | Description |
---|---|---|
service_symbol | ::mlir::FlatSymbolRefAttr | flat symbol reference attribute |
serverNamePath | ::mlir::ArrayAttr | array attribute |
impl_type | ::mlir::StringAttr | string attribute |
impl_details | ::mlir::DictionaryAttr | dictionary of named attribute values |
clients | ::mlir::ArrayAttr | array 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.instance
s 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:
Attribute | MLIR Type | Description |
---|---|---|
service_symbol | ::mlir::FlatSymbolRefAttr | flat symbol reference attribute |
impl_type | ::mlir::StringAttr | string attribute |
impl_opts | ::mlir::DictionaryAttr | dictionary of named attribute values |
Operands:
Operand | Description |
---|---|
inputs | any type |
Results:
Result | Description |
---|---|
outputs | any 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:
Attribute | MLIR Type | Description |
---|---|---|
service_symbol | ::mlir::FlatSymbolRefAttr | flat symbol reference attribute |
impl_type | ::mlir::StringAttr | string attribute |
impl_opts | ::mlir::DictionaryAttr | dictionary of named attribute values |
Operands:
Operand | Description |
---|---|
inputs | any type |
Results:
Result | Description |
---|---|
«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:
Attribute | MLIR Type | Description |
---|---|---|
inner_sym | ::mlir::StringAttr | string attribute |
toClientType | ::mlir::TypeAttr | any 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:
Attribute | MLIR Type | Description |
---|---|---|
inner_sym | ::mlir::StringAttr | string attribute |
toServerType | ::mlir::TypeAttr | any type attribute |
Structural
ESI has a special module which doesn’t expose ports. All external interactions are expected to be done through services.
esi.pure_module.input
(::circt::esi::ESIPureModuleInputOp)
Inputs become input ports when the module is lowered
Syntax:
operation ::= `esi.pure_module.input` $name attr-dict `:` type($value)
To create input ports when lowering a pure module op into an HWModuleOp, use this op. This op is typically created by a service implementation generator.
If two ‘input’ ops exist in the same block, the names match, and the type matches they’ll become one port during lowering. Two or more may not exist with the same name and different types. Useful for ‘clk’ and ‘rst’.
Traits: HasParent
Attributes:
Attribute | MLIR Type | Description |
---|---|---|
name | ::mlir::StringAttr | string attribute |
Results:
Result | Description |
---|---|
value | any type |
esi.pure_module
(::circt::esi::ESIPureModuleOp)
ESI pure module
Syntax:
operation ::= `esi.pure_module` $sym_name attr-dict-with-keyword $body
A module containing only ESI channels and modules with only ESI ports. All non-local connectivity is done through ESI services. If this module is the top level in the design, then the design’s actual top level ports are defined by a BSP.
Useful on its own for simulation and BSPs which don’t define a top-level.
Traits: HasParent mlir::ModuleOp, NoRegionArguments, NoTerminator, SingleBlock
Interfaces: HWModuleLike, InstanceGraphModuleOpInterface, PortList, RegionKindInterface, Symbol, SymboledPortList
Attributes:
Attribute | MLIR Type | Description |
---|---|---|
sym_name | ::mlir::StringAttr | string attribute |
esi.pure_module.output
(::circt::esi::ESIPureModuleOutputOp)
Outputs become output ports when the module is lowered
Syntax:
operation ::= `esi.pure_module.output` $name `,` $value attr-dict `:` type($value)
To create output ports when lowering a pure module op into an HWModuleOp, use this op. This op is typically created by a service implementation generator.
Two ‘output’ ops with the same name cannot exist in the same block.
Traits: HasParent
Attributes:
Attribute | MLIR Type | Description |
---|---|---|
name | ::mlir::StringAttr | string attribute |
Operands:
Operand | Description |
---|---|
value | any type |
esi.pure_module.param
(::circt::esi::ESIPureModuleParamOp)
Params become module parameters when the module is lowered
Syntax:
operation ::= `esi.pure_module.param` $name `:` $type attr-dict
Allows attaching parameters to modules which become HW module parameters when lowering. Currently, they are ignored. Some low-level BSPs instantiate modules with parameters. This allows the modules produced to accept parameters so those BSPs can instantiate them.
Traits: HasParent
Attributes:
Attribute | MLIR Type | Description |
---|---|---|
name | ::mlir::StringAttr | string attribute |
type | ::mlir::TypeAttr | any type attribute |
Interfaces
Misc CIRCT interfaces.
ChannelOpInterface (ChannelOpInterface
)
“An interface for operations which carries channel semantics.”
Methods:
channelType
circt::esi::ChannelType channelType();
“Returns the channel type of this operation.” NOTE: This method must be implemented by the user.
innerType
mlir::Type innerType();
“Returns the inner type of this channel. This will be the type of the data value of the channel, if the channel carries data semantics. Else, return NoneType.” NOTE: This method must be implemented by the user.
ServiceDeclOpInterface (ServiceDeclOpInterface
)
Any op which represents a service declaration should implement this interface.
Methods:
getPortList
void getPortList(llvm::SmallVectorImpl<ServicePortInfo>&ports);
Returns the list of interface ports for this service interface. NOTE: This method must be implemented by the user.
validateRequest
mlir::LogicalResult validateRequest(mlir::Operation*req);
Validate this service request against this service decl. NOTE: This method must be implemented by the user.
ServiceReqOpInterface (ServiceReqOpInterface
)
Any op which is requesting connection to a service’s port or has information pertaining to one of said requests.
Methods:
getServicePort
hw::InnerRefAttr getServicePort();
Returns the service port symbol. NOTE: This method must be implemented by the user.
getClientNamePath
ArrayAttr getClientNamePath();
Returns the client name path. NOTE: This method must be implemented by the user.
setClientNamePath
void setClientNamePath(ArrayAttr newClientNamePath);
Set the client name path. NOTE: This method must be implemented by the user.
getToClientType
Type getToClientType();
Returns the type headed to the client. Can be null.
getToClient
Value getToClient();
Returns the value headed to the client. Can be null. NOTE: This method must be implemented by the user.
getToServerType
Type getToServerType();
Returns the type headed to the server. Can be null.
getToServer
Value getToServer();
Returns the value headed to the server. Can be null. NOTE: This method must be implemented by the user.
setToServer
void setToServer(Value newValue);
Set the value headed to the server. Can assert(). NOTE: This method must be implemented by the user.