Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement OM C-API for Binder
Browse files Browse the repository at this point in the history
SpriteOvO committed Nov 13, 2023
1 parent 5d03a5c commit a3dbd29
Showing 14 changed files with 461 additions and 25 deletions.
6 changes: 3 additions & 3 deletions binder/includeConstants.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# enum FIRRTLPortDirection
FIRRTL_PORT_DIR_INPUT
FIRRTL_PORT_DIR_OUTPUT
# enum FIRRTLDirection
FIRRTL_DIRECTION_IN
FIRRTL_DIRECTION_OUT
# enum FIRRTLConvention
FIRRTL_CONVENTION_INTERNAL
FIRRTL_CONVENTION_SCALARIZED
76 changes: 76 additions & 0 deletions binder/includeFunctions.txt
Original file line number Diff line number Diff line change
@@ -19,7 +19,9 @@ mlirOperationStateGet
mlirNamedAttributeGet
mlirIntegerAttrGet
mlirFloatAttrDoubleGet
mlirBoolAttrGet
mlirStringAttrGet
mlirStringAttrGetValue
mlirArrayAttrGet
mlirTypeAttrGet
mlirArrayAttrGet
@@ -66,6 +68,15 @@ firrtlTypeGetAsyncReset
firrtlTypeGetAnalog
firrtlTypeGetVector
firrtlTypeGetBundle
firrtlTypeGetAnyRef
firrtlTypeGetInteger
firrtlTypeGetDouble
firrtlTypeGetString
firrtlTypeGetBoolean
firrtlTypeGetPath
firrtlTypeGetList
firrtlTypeGetMap
firrtlTypeGetClass

# FIRRTL Attribute
firrtlAttrGetPortDirs
@@ -172,3 +183,68 @@ firtoolPopulateHWToSV
firtoolPopulateExportVerilog
firtoolPopulateExportSplitVerilog
firtoolPopulateFinalizeIR

#
# OM C-API
#

# Type
omTypeIsAClassType
omClassTypeGetTypeID
omClassTypeGetName
omTypeIsAFrozenBasePathType
omFrozenBasePathTypeGetTypeID
omTypeIsAFrozenPathType
omFrozenPathTypeGetTypeID
omTypeIsAMapType
omMapTypeGetKeyType
omTypeIsAStringType
# Evaluator
omEvaluatorNew
omEvaluatorInstantiate
omEvaluatorGetModule
# Object
omEvaluatorObjectIsNull
omEvaluatorObjectGetType
omEvaluatorObjectGetField
omEvaluatorObjectGetHash
omEvaluatorObjectIsEq
omEvaluatorObjectGetFieldNames
# EvaluatorValue
omEvaluatorValueGetContext
omEvaluatorValueGetLoc
omEvaluatorValueIsNull
omEvaluatorValueIsAObject
omEvaluatorValueIsAPrimitive
omEvaluatorValueGetPrimitive
omEvaluatorValueFromPrimitive
omEvaluatorValueIsAList
omEvaluatorListGetNumElements
omEvaluatorListGetElement
omEvaluatorValueIsATuple
omEvaluatorTupleGetNumElements
omEvaluatorTupleGetElement
omEvaluatorMapGetElement
omEvaluatorMapGetKeys
omEvaluatorValueIsAMap
omEvaluatorMapGetType
omEvaluatorValueIsABasePath
omEvaluatorBasePathGetEmpty
omEvaluatorValueIsAPath
omEvaluatorPathGetAsString
# ReferenceAttr API
omAttrIsAReferenceAttr
omReferenceAttrGetInnerRef
# IntegerAttr API
omAttrIsAIntegerAttr
omIntegerAttrGetInt
omIntegerAttrGet
# ListAttr API
omAttrIsAListAttr
omListAttrGetNumElements
omListAttrGetElement
# MapAttr API
omAttrIsAMapAttr
omMapAttrGetNumElements
omMapAttrGetElementKey
omMapAttrGetElementValue
3 changes: 3 additions & 0 deletions binder/includeStructs.txt
Original file line number Diff line number Diff line change
@@ -17,4 +17,7 @@ MlirOpPassManager
MlirPass
MlirLogicalResult
FIRRTLBundleField
FIRRTLClassElement
FirtoolOptions
OMEvaluator
OMEvaluatorValue
1 change: 1 addition & 0 deletions binder/jextract-headers.h
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
#include <circt-c/Dialect/HW.h>
#include <circt-c/Dialect/SV.h>
#include <circt-c/Dialect/Seq.h>
#include <circt-c/Dialect/OM.h>
#include <circt-c/Firtool/Firtool.h>
#include <circt-c/ExportFIRRTL.h>
#include <circt-c/ExportVerilog.h>
1 change: 1 addition & 0 deletions binder/linkLibraries.txt
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ CIRCTCAPICHIRRTL
CIRCTCAPIHW
CIRCTCAPISV
CIRCTCAPISeq
CIRCTCAPIOM
CIRCTCAPIFirtool
CIRCTCAPIExportFIRRTL
CIRCTCAPIExportVerilog
122 changes: 117 additions & 5 deletions binder/src/main/scala/PanamaCIRCT.scala
Original file line number Diff line number Diff line change
@@ -168,8 +168,15 @@ class PanamaCIRCT {

def mlirTypeAttrGet(tpe: MlirType) = MlirAttribute(CAPI.mlirTypeAttrGet(arena, tpe.get))

def mlirBoolAttrGet(value: Boolean) = MlirAttribute(CAPI.mlirBoolAttrGet(arena, mlirCtx, if (value) 1 else 0))

def mlirStringAttrGet(string: String) = MlirAttribute(CAPI.mlirStringAttrGet(arena, mlirCtx, newString(string).get))

def mlirStringAttrGetValue(attr: MlirAttribute): String = {
val string = CAPI.mlirStringAttrGetValue(arena, attr.get)
MlirStringRef(string).toString
}

def mlirIntegerAttrGet(tpe: MlirType, value: Int) = MlirAttribute(CAPI.mlirIntegerAttrGet(arena, tpe.get, value))

def mlirFloatAttrDoubleGet(tpe: MlirType, value: Double) = MlirAttribute(
@@ -412,6 +419,9 @@ class PanamaCIRCT {
CAPI.firtoolPopulateExportSplitVerilog(arena, pm.get, options.get, newString(directory).get)
)

def firtoolPopulateFinalizeIR(pm: MlirPassManager, options: FirtoolOptions) =
MlirLogicalResult(CAPI.firtoolPopulateFinalizeIR(arena, pm.get, options.get))

def mlirLogicalResultIsSuccess(res: MlirLogicalResult): Boolean = circt.MlirLogicalResult.value$get(res.get) != 0

def mlirLogicalResultIsFailure(res: MlirLogicalResult): Boolean = circt.MlirLogicalResult.value$get(res.get) == 0
@@ -444,7 +454,35 @@ class PanamaCIRCT {
MlirType(CAPI.firrtlTypeGetBundle(arena, mlirCtx, fields.length, buffer))
}

def firrtlAttrGetPortDirs(dirs: Seq[FIRRTLPortDir]): MlirAttribute = {
def firrtlTypeGetAnyRef() = MlirType(CAPI.firrtlTypeGetAnyRef(arena, mlirCtx))

def firrtlTypeGetInteger() = MlirType(CAPI.firrtlTypeGetInteger(arena, mlirCtx))

def firrtlTypeGetDouble() = MlirType(CAPI.firrtlTypeGetDouble(arena, mlirCtx))

def firrtlTypeGetString() = MlirType(CAPI.firrtlTypeGetString(arena, mlirCtx))

def firrtlTypeGetBoolean() = MlirType(CAPI.firrtlTypeGetBoolean(arena, mlirCtx))

def firrtlTypeGetPath() = MlirType(CAPI.firrtlTypeGetPath(arena, mlirCtx))

def firrtlTypeGetList(elementType: MlirType) = MlirType(CAPI.firrtlTypeGetList(arena, mlirCtx, elementType.get))

def firrtlTypeGetMap(keyType: MlirType, valueType: MlirType) = MlirType(CAPI.firrtlTypeGetMap(arena, mlirCtx, keyType.get, valueType.get))

def firrtlTypeGetClass(name: MlirAttribute /* FlatSymbolRefAttr */, elements: Seq[FIRRTLClassElement]): MlirType = {
val buffer = circt.FIRRTLClassElement.allocateArray(elements.length, arena)
elements.zipWithIndex.foreach {
case (element, i) =>
val elementBuffer = buffer.asSlice(circt.FIRRTLClassElement.sizeof() * i, circt.FIRRTLClassElement.sizeof())
circt.FIRRTLClassElement.name$slice(elementBuffer).copyFrom(mlirIdentifierGet(element.name).get)
circt.FIRRTLClassElement.type$slice(elementBuffer).copyFrom(element.tpe.get)
circt.FIRRTLClassElement.direction$set(elementBuffer, element.direction.get)
}
MlirType(CAPI.firrtlTypeGetClass(arena, mlirCtx, name.get, elements.length, buffer))
}

def firrtlAttrGetPortDirs(dirs: Seq[FIRRTLDirection]): MlirAttribute = {
val (ptr, length) = seqToArray(dirs)
MlirAttribute(CAPI.firrtlAttrGetPortDirs(arena, mlirCtx, length, ptr))
}
@@ -470,6 +508,62 @@ class PanamaCIRCT {
)

def chirrtlTypeGetCMemoryPort() = MlirType(CAPI.chirrtlTypeGetCMemoryPort(arena, mlirCtx))

//
// OM C-API
//

def omTypeIsAClassType(tpe: MlirType): Boolean = CAPI.omTypeIsAClassType(tpe.get)
def omClassTypeGetName(tpe: MlirType) = MlirIdentifier(CAPI.omClassTypeGetName(arena, tpe.get))
def omTypeIsAFrozenBasePathType(tpe: MlirType): Boolean = CAPI.omTypeIsAFrozenBasePathType(tpe.get)
def omTypeIsAFrozenPathType(tpe: MlirType): Boolean = CAPI.omTypeIsAFrozenPathType(tpe.get)
def omTypeIsAMapType(tpe: MlirType): Boolean = CAPI.omTypeIsAMapType(tpe.get)
def omMapTypeGetKeyType(tpe: MlirType) = MlirType(CAPI.omMapTypeGetKeyType(arena, tpe.get))
def omTypeIsAStringType(tpe: MlirType): Boolean = CAPI.omTypeIsAStringType(tpe.get)
def omEvaluatorNew(mod: MlirModule) = OMEvaluator(CAPI.omEvaluatorNew(arena, mod.get))
def omEvaluatorInstantiate(evaluator: OMEvaluator, className: String, actualParams: Seq[OMEvaluatorValue]) = {
val params = seqToArray(actualParams);
OMEvaluatorValue(CAPI.omEvaluatorInstantiate(arena, evaluator.get, mlirStringAttrGet(className).get, params._2, params._1))
}
def omEvaluatorGetModule(evaluator: OMEvaluator) = MlirModule(CAPI.omEvaluatorGetModule(arena, evaluator.get))
def omEvaluatorObjectIsNull(obj: OMEvaluatorValue): Boolean = CAPI.omEvaluatorObjectIsNull(obj.get)
def omEvaluatorObjectGetType(obj: OMEvaluatorValue) = MlirType(CAPI.omEvaluatorObjectGetType(arena, obj.get))
def omEvaluatorObjectGetField(obj: OMEvaluatorValue, name: String) = OMEvaluatorValue(CAPI.omEvaluatorObjectGetField(arena, obj.get, mlirStringAttrGet(name).get))
def omEvaluatorObjectGetHash(obj: OMEvaluatorValue): Int = CAPI.omEvaluatorObjectGetHash(obj.get)
def omEvaluatorObjectIsEq(obj: OMEvaluatorValue, other: OMEvaluatorValue): Boolean = CAPI.omEvaluatorObjectIsEq(obj.get, other.get)
def omEvaluatorObjectGetFieldNames(obj: OMEvaluatorValue) = MlirAttribute(CAPI.omEvaluatorObjectGetFieldNames(arena, obj.get))
def omEvaluatorValueGetLoc(evaluatorValue: OMEvaluatorValue) = MlirLocation(CAPI.omEvaluatorValueGetLoc(arena, evaluatorValue.get))
def omEvaluatorValueIsNull(evaluatorValue: OMEvaluatorValue): Boolean = CAPI.omEvaluatorValueIsNull(evaluatorValue.get)
def omEvaluatorValueIsAObject(evaluatorValue: OMEvaluatorValue): Boolean = CAPI.omEvaluatorValueIsAObject(evaluatorValue.get)
def omEvaluatorValueIsAPrimitive(evaluatorValue: OMEvaluatorValue): Boolean = CAPI.omEvaluatorValueIsAPrimitive(evaluatorValue.get)
def omEvaluatorValueGetPrimitive(evaluatorValue: OMEvaluatorValue) = MlirAttribute(CAPI.omEvaluatorValueGetPrimitive(arena, evaluatorValue.get))
def omEvaluatorValueFromPrimitive(primitive: MlirAttribute) = OMEvaluatorValue(CAPI.omEvaluatorValueFromPrimitive(arena, primitive.get))
def omEvaluatorValueIsAList(evaluatorValue: OMEvaluatorValue): Boolean = CAPI.omEvaluatorValueIsAList(evaluatorValue.get)
def omEvaluatorListGetNumElements(evaluatorValue: OMEvaluatorValue): Int = CAPI.omEvaluatorListGetNumElements(evaluatorValue.get).toInt
def omEvaluatorListGetElement(evaluatorValue: OMEvaluatorValue, pos: Int) = OMEvaluatorValue(CAPI.omEvaluatorListGetElement(arena, evaluatorValue.get, pos))
def omEvaluatorValueIsATuple(evaluatorValue: OMEvaluatorValue): Boolean = CAPI.omEvaluatorValueIsATuple(evaluatorValue.get)
def omEvaluatorTupleGetNumElements(evaluatorValue: OMEvaluatorValue): Int = CAPI.omEvaluatorTupleGetNumElements(evaluatorValue.get).toInt
def omEvaluatorTupleGetElement(evaluatorValue: OMEvaluatorValue, pos: Int) = OMEvaluatorValue(CAPI.omEvaluatorTupleGetElement(arena, evaluatorValue.get, pos))
def omEvaluatorMapGetElement(evaluatorValue: OMEvaluatorValue, attr: MlirAttribute) = OMEvaluatorValue(CAPI.omEvaluatorMapGetElement(arena, evaluatorValue.get, attr.get))
def omEvaluatorMapGetKeys(obj: OMEvaluatorValue) = MlirAttribute(CAPI.omEvaluatorMapGetKeys(arena, obj.get))
def omEvaluatorValueIsAMap(evaluatorValue: OMEvaluatorValue): Boolean = CAPI.omEvaluatorValueIsAMap(evaluatorValue.get)
def omEvaluatorMapGetType(evaluatorValue: OMEvaluatorValue): MlirType = MlirType(CAPI.omEvaluatorMapGetType(arena, evaluatorValue.get))
def omEvaluatorValueIsABasePath(evaluatorValue: OMEvaluatorValue): Boolean = CAPI.omEvaluatorValueIsABasePath(evaluatorValue.get)
def omEvaluatorBasePathGetEmpty() = OMEvaluatorValue(CAPI.omEvaluatorBasePathGetEmpty(arena, mlirCtx))
def omEvaluatorValueIsAPath(evaluatorValue: OMEvaluatorValue): Boolean = CAPI.omEvaluatorValueIsAPath(evaluatorValue.get)
def omEvaluatorPathGetAsString(evaluatorValue: OMEvaluatorValue): String = mlirStringAttrGetValue(MlirAttribute(CAPI.omEvaluatorPathGetAsString(arena, evaluatorValue.get)))
def omAttrIsAReferenceAttr(attr: MlirAttribute): Boolean = CAPI.omAttrIsAReferenceAttr(attr.get)
def omReferenceAttrGetInnerRef(attr: MlirAttribute) = MlirAttribute(CAPI.omReferenceAttrGetInnerRef(arena, attr.get))
def omAttrIsAIntegerAttr(attr: MlirAttribute): Boolean = CAPI.omAttrIsAIntegerAttr(attr.get)
def omIntegerAttrGetInt(attr: MlirAttribute) = MlirAttribute(CAPI.omIntegerAttrGetInt(arena, attr.get))
def omIntegerAttrGet(attr: MlirAttribute) = MlirAttribute(CAPI.omIntegerAttrGet(arena, attr.get))
def omAttrIsAListAttr(attr: MlirAttribute): Boolean = CAPI.omAttrIsAListAttr(attr.get)
def omListAttrGetNumElements(attr: MlirAttribute): Int = CAPI.omListAttrGetNumElements(attr.get).toInt
def omListAttrGetElement(attr: MlirAttribute, pos: Int) = MlirAttribute(CAPI.omListAttrGetElement(arena, attr.get, pos))
def omAttrIsAMapAttr(attr: MlirAttribute): Boolean = CAPI.omAttrIsAMapAttr(attr.get)
def omMapAttrGetNumElements(attr: MlirAttribute): Int = CAPI.omMapAttrGetNumElements(attr.get).toInt
def omMapAttrGetElementKey(attr: MlirAttribute, pos: Int) = MlirIdentifier(CAPI.omMapAttrGetElementKey(arena, attr.get, pos))
def omMapAttrGetElementValue(attr: MlirAttribute, pos: Int) = MlirAttribute(CAPI.omMapAttrGetElementValue(arena, attr.get, pos))
}

//
@@ -627,6 +721,8 @@ object MlirPass {

final case class FIRRTLBundleField(name: String, isFlip: Boolean, tpe: MlirType)

final case class FIRRTLClassElement(name: String, tpe: MlirType, direction: FIRRTLDirection)

final case class FirtoolOptions(ptr: MemorySegment) extends ForeignType[MemorySegment] {
private[circt] def get = ptr
private[circt] val sizeof = circt.FirtoolOptions.sizeof().toInt
@@ -635,6 +731,22 @@ object FirtoolOptions {
private[circt] def apply(ptr: MemorySegment) = new FirtoolOptions(ptr)
}

final case class OMEvaluator(ptr: MemorySegment) extends ForeignType[MemorySegment] {
private[circt] def get = ptr
private[circt] val sizeof = circt.OMEvaluator.sizeof().toInt
}
object OMEvaluator {
private[circt] def apply(ptr: MemorySegment) = new OMEvaluator(ptr)
}

final case class OMEvaluatorValue(ptr: MemorySegment) extends ForeignType[MemorySegment] {
private[circt] def get = ptr
private[circt] val sizeof = circt.OMEvaluatorValue.sizeof().toInt
}
object OMEvaluatorValue {
private[circt] def apply(ptr: MemorySegment) = new OMEvaluatorValue(ptr)
}

//
// MLIR & CIRCT Enums
//
@@ -657,13 +769,13 @@ object FIRRTLNameKind {
final case object InterestingName extends FIRRTLNameKind(value = CAPI.FIRRTL_NAME_KIND_INTERESTING_NAME())
}

sealed abstract class FIRRTLPortDir(val value: Int) extends ForeignType[Int] {
sealed abstract class FIRRTLDirection(val value: Int) extends ForeignType[Int] {
private[circt] def get = value
private[circt] val sizeof = 4 // FIXME: jextract doesn't export type for C enum
}
object FIRRTLPortDir {
final case object Input extends FIRRTLPortDir(value = CAPI.FIRRTL_PORT_DIR_INPUT())
final case object Output extends FIRRTLPortDir(value = CAPI.FIRRTL_PORT_DIR_OUTPUT())
object FIRRTLDirection {
final case object In extends FIRRTLDirection(value = CAPI.FIRRTL_DIRECTION_IN())
final case object Out extends FIRRTLDirection(value = CAPI.FIRRTL_DIRECTION_OUT())
}

sealed abstract class firrtlAttrGetRUW(val value: Int) extends ForeignType[Int] {
94 changes: 78 additions & 16 deletions binder/src/main/scala/PanamaCIRCTConverter.scala
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ import scala.math._
import firrtl.{ir => fir}
import firrtl.annotations.NoTargetAnnotation
import chisel3.{Data => ChiselData, _}
import chisel3.properties.PropertyType
import chisel3.experimental._
import chisel3.internal._
import chisel3.internal.firrtl._
@@ -33,7 +34,7 @@ case class Op(state: MlirOperationState, op: MlirOperation, regions: Seq[Region]

case class Ports(
types: Seq[MlirType],
dirs: Seq[FIRRTLPortDir],
dirs: Seq[FIRRTLDirection],
locs: Seq[MlirLocation],
names: Seq[String],
nameAttrs: Seq[MlirAttribute],
@@ -166,6 +167,14 @@ class PanamaCIRCTConverter extends CIRCTConverter {
)
)
)
case fir.AnyRefPropertyType => circt.firrtlTypeGetAnyRef()
case fir.IntegerPropertyType => circt.firrtlTypeGetInteger()
case fir.DoublePropertyType => circt.firrtlTypeGetDouble()
case fir.StringPropertyType => circt.firrtlTypeGetString()
case fir.BooleanPropertyType => circt.firrtlTypeGetBoolean()
case fir.PathPropertyType => circt.firrtlTypeGetPath()
case t: fir.SequencePropertyType => circt.firrtlTypeGetList(convert(t.tpe))
case t: fir.ClassPropertyType => circt.firrtlTypeGetClass(circt.mlirFlatSymbolRefAttrGet(t.name), Seq.empty /* TODO: where is the elements? */)
}
}

@@ -199,8 +208,8 @@ class PanamaCIRCTConverter extends CIRCTConverter {
Ports(
types = types,
dirs = irs.map(_.direction match {
case fir.Input => FIRRTLPortDir.Input
case fir.Output => FIRRTLPortDir.Output
case fir.Input => FIRRTLDirection.In
case fir.Output => FIRRTLDirection.Out
}),
locs = locs,
names = irs.map(_.name),
@@ -439,7 +448,7 @@ class PanamaCIRCTConverter extends CIRCTConverter {
}
}

def referTo(arg: Arg, loc: MlirLocation): Reference.Value = {
def referTo(arg: Arg, loc: MlirLocation, ctx: Option[(Component, SourceInfo)] = None): Reference.Value = {
def referToNewConstant(n: Int, w: Width, isSigned: Boolean): Reference.Value = {
val (firWidth, valWidth) = w match {
case _: UnknownWidth =>
@@ -453,10 +462,46 @@ class PanamaCIRCTConverter extends CIRCTConverter {
Reference.Value(util.newConstantValue(resultType, valueType, n.toInt, loc), resultType)
}

def referToNewProperty[T, U](propLit: PropertyLit[T, U]): Reference.Value = {
def rec(tpe: fir.PropertyType, exp: fir.Expression): MlirValue = {
val (opName, attrs, operands) = exp match {
case fir.IntegerPropertyLiteral(value) =>
val attrs = Seq(("value", circt.mlirIntegerAttrGet(circt.mlirIntegerTypeSignedGet(util.bitLength(value) + 1), value.toInt)))
("integer", attrs, Seq.empty)
case fir.DoublePropertyLiteral(value) =>
val attrs = Seq(("value", circt.mlirFloatAttrDoubleGet(circt.mlirF64TypeGet(), value)))
("double", attrs, Seq.empty)
case fir.StringPropertyLiteral(value) =>
val attrs = Seq(("value", circt.mlirStringAttrGet(value)))
("string", attrs, Seq.empty)
case fir.BooleanPropertyLiteral(value) =>
val attrs = Seq(("value", circt.mlirBoolAttrGet(value)))
("bool", attrs, Seq.empty)
case fir.PathPropertyLiteral(value) =>
val attrs = Seq(("target", circt.mlirStringAttrGet(value)))
("unresolved_path", attrs, Seq.empty)
case fir.SequencePropertyValue(elementTpe, values) =>
("list.create", Seq.empty, values.map(rec(elementTpe.asInstanceOf[fir.PropertyType], _)))
}
util
.OpBuilder(s"firrtl.$opName", firCtx.currentBlock, loc)
.withNamedAttrs(attrs)
.withOperands(operands)
.withResult(util.convert(tpe))
.build()
.results(0)
}

val tpe = propLit.propertyType.getPropertyType()
val exp = propLit.propertyType.convert(propLit.lit, ctx.get._1, ctx.get._2);
Reference.Value(rec(tpe, exp), tpe)
}

arg match {
case Node(id) => referTo(id, loc)
case ULit(value, width) => referToNewConstant(value.toInt, width, false)
case SLit(value, width) => referToNewConstant(value.toInt, width, true)
case propLit: PropertyLit[_, _] => referToNewProperty(propLit)
case unhandled => throw new Exception(s"unhandled arg type to be reference: $unhandled")
}
}
@@ -489,21 +534,19 @@ class PanamaCIRCTConverter extends CIRCTConverter {

val verilogStream = new Writable {
def writeBytesTo(out: OutputStream): Unit = {
def assertResult(result: MlirLogicalResult): Unit = {
assert(circt.mlirLogicalResultIsSuccess(result))
}

val pm = circt.mlirPassManagerCreate()
val options = circt.firtoolOptionsCreateDefault()
assertResult(circt.firtoolPopulatePreprocessTransforms(pm, options))
assertResult(circt.firtoolPopulateCHIRRTLToLowFIRRTL(pm, options, mlirRootModule, "-"))
assertResult(circt.firtoolPopulateLowFIRRTLToHW(pm, options))
assertResult(circt.firtoolPopulateHWToSV(pm, options))
assertResult(circt.firtoolPopulateExportVerilog(pm, options, message => out.write(message.getBytes)))
assertResult(circt.mlirPassManagerRunOnOp(pm, circt.mlirModuleGetOperation(mlirRootModule)))
val pm = passManager()
assert(pm.populatePreprocessTransforms())
assert(pm.populateCHIRRTLToLowFIRRTL())
assert(pm.populateLowFIRRTLToHW())
assert(pm.populateLowHWToSV())
assert(pm.populateExportVerilog(message => out.write(message.getBytes)))
assert(pm.run())
}
}

def passManager(): CIRCTPassManager = new PanamaCIRCTPassManager(circt, mlirRootModule)
def om(): CIRCTOM = new PanamaCIRCTOM(circt, mlirRootModule)

def visitCircuit(name: String): Unit = {
val firCircuit = util
.OpBuilder("firrtl.circuit", circt.mlirModuleGetBody(mlirRootModule), circt.unkLoc)
@@ -1185,6 +1228,21 @@ class PanamaCIRCTConverter extends CIRCTConverter {
// TODO: CIRCT emits `assert` for this, is it expected?
visitVerification(cover, "firrtl.cover", Seq.empty)
}

def visitPropAssign(parent: Component, propAssign: PropAssign): Unit = {
val loc = util.convert(propAssign.sourceInfo)

val dest = util.referTo(propAssign.loc.id, loc)
var src = util.referTo(Converter.getRef(propAssign.exp match {
case Node(id) => id
}, propAssign.sourceInfo), loc, Some((parent, propAssign.sourceInfo)))

util
.OpBuilder("firrtl.propassign", firCtx.currentBlock, loc)
.withOperand( /* dest */ dest.value)
.withOperand( /* src */ src.value)
.build()
}
}

private[chisel3] object PanamaCIRCTConverter {
@@ -1236,6 +1294,7 @@ private[chisel3] object PanamaCIRCTConverter {
case cover: Verification[VerifCover] => visitVerfiCover(cover)
case printf: Verification[VerifPrintf] => visitVerfiPrintf(printf)
case stop: Verification[VerifStop] => visitVerfiStop(stop)
case propAssign: PropAssign => visitPropAssign(defModule, propAssign)
case unhandled => throw new Exception(s"unhandled op: $unhandled")
}
}
@@ -1318,4 +1377,7 @@ private[chisel3] object PanamaCIRCTConverter {
// TODO: Not used anywhere?
throw new Exception("unimplemented")
}
def visitPropAssign(parent: Component, propAssign: PropAssign)(implicit cvt: CIRCTConverter): Unit = {
cvt.visitPropAssign(parent, propAssign)
}
}
78 changes: 78 additions & 0 deletions binder/src/main/scala/PanamaCIRCTOM.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: Apache-2.0

package chisel3.internal.panama.circt

import chisel3.internal._

class PanamaCIRCTOM private[chisel3](circt: PanamaCIRCT, mlirModule: MlirModule) extends CIRCTOM {
def evaluator(): CIRCTOMEvaluator = new PanamaCIRCTOMEvaluator(circt, mlirModule)

def newBasePathEmpty(): CIRCTOMEvaluatorValue = new PanamaCIRCTOMEvaluatorValueBasePath(circt, circt.omEvaluatorBasePathGetEmpty())
}

class PanamaCIRCTOMEvaluator private[chisel3](circt: PanamaCIRCT, mlirModule: MlirModule) extends CIRCTOMEvaluator {
val evaluator = circt.omEvaluatorNew(mlirModule)

def instantiate(className: String, actualParams: Seq[CIRCTOMEvaluatorValue]): CIRCTOMObject = {
val params = actualParams.map(_.asInstanceOf[PanamaCIRCTOMEvaluatorValue].value)

val value = circt.omEvaluatorInstantiate(evaluator, className, params)
assert(!circt.omEvaluatorObjectIsNull(value))
new PanamaCIRCTOMObject(circt, value)
}
}

abstract class PanamaCIRCTOMEvaluatorValue extends CIRCTOMEvaluatorValue {
val value: OMEvaluatorValue
}
object PanamaCIRCTOMEvaluatorValue {
def newValue(circt: PanamaCIRCT, value: OMEvaluatorValue): PanamaCIRCTOMEvaluatorValue = {
if (circt.omEvaluatorValueIsAObject(value)) {
throw new Exception("TODO")
} else if (circt.omEvaluatorValueIsAPrimitive(value)) {
new PanamaCIRCTOMEvaluatorValuePrimitive(circt, value)
} else if (circt.omEvaluatorValueIsAList(value)) {
new PanamaCIRCTOMEvaluatorValueList(circt, value)
} else if (circt.omEvaluatorValueIsATuple(value)) {
new PanamaCIRCTOMEvaluatorValueTuple(circt, value)
} else if (circt.omEvaluatorValueIsAMap(value)) {
new PanamaCIRCTOMEvaluatorValueMap(circt, value)
} else if (circt.omEvaluatorValueIsABasePath(value)) {
new PanamaCIRCTOMEvaluatorValueBasePath(circt, value)
} else if (circt.omEvaluatorValueIsAPath(value)) {
new PanamaCIRCTOMEvaluatorValuePath(circt, value)
} else {
throw new Exception("unknown OMEvaluatorValue type")
}
}
}

class PanamaCIRCTOMEvaluatorValueList private[chisel3](circt: PanamaCIRCT, val value: OMEvaluatorValue) extends PanamaCIRCTOMEvaluatorValue {
val numElements: Int = circt.omEvaluatorListGetNumElements(value)
def getElement(index: Int) = PanamaCIRCTOMEvaluatorValue.newValue(circt, circt.omEvaluatorListGetElement(value, index))
}

class PanamaCIRCTOMEvaluatorValueTuple private[chisel3](circt: PanamaCIRCT, val value: OMEvaluatorValue) extends PanamaCIRCTOMEvaluatorValue {
val numElements: Int = circt.omEvaluatorTupleGetNumElements(value)
def getElement(index: Int) = PanamaCIRCTOMEvaluatorValue.newValue(circt, circt.omEvaluatorTupleGetElement(value, index))
}

class PanamaCIRCTOMEvaluatorValueMap private[chisel3](circt: PanamaCIRCT, val value: OMEvaluatorValue) extends PanamaCIRCTOMEvaluatorValue {
val tpe: MlirType = circt.omEvaluatorMapGetType(value)
val keys: MlirAttribute = circt.omEvaluatorMapGetKeys(value)
def getElement(attr: MlirAttribute) = PanamaCIRCTOMEvaluatorValue.newValue(circt, circt.omEvaluatorMapGetElement(value, attr))
}

class PanamaCIRCTOMEvaluatorValueBasePath private[chisel3](circt: PanamaCIRCT, val value: OMEvaluatorValue) extends PanamaCIRCTOMEvaluatorValue {}

class PanamaCIRCTOMEvaluatorValuePath private[chisel3](circt: PanamaCIRCT, val value: OMEvaluatorValue) extends PanamaCIRCTOMEvaluatorValue {
def asString(): String = circt.omEvaluatorPathGetAsString(value)
}

class PanamaCIRCTOMEvaluatorValuePrimitive private[chisel3](circt: PanamaCIRCT, val value: OMEvaluatorValue) extends PanamaCIRCTOMEvaluatorValue {
val primitive: MlirAttribute = circt.omEvaluatorValueGetPrimitive(value)
}

class PanamaCIRCTOMObject private[chisel3](circt: PanamaCIRCT, value: OMEvaluatorValue) extends CIRCTOMObject {
def field(name: String): CIRCTOMEvaluatorValue = PanamaCIRCTOMEvaluatorValue.newValue(circt, circt.omEvaluatorObjectGetField(value, name))
}
22 changes: 22 additions & 0 deletions binder/src/main/scala/PanamaCIRCTPassManager.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: Apache-2.0

package chisel3.internal.panama.circt

import chisel3.internal._

class PanamaCIRCTPassManager private[chisel3](circt: PanamaCIRCT, mlirModule: MlirModule) extends CIRCTPassManager {
val pm = circt.mlirPassManagerCreate()
val options = circt.firtoolOptionsCreateDefault() // TODO: Make it configurable from CIRCTPassManager

private def isSuccess(result: MlirLogicalResult): Boolean = circt.mlirLogicalResultIsSuccess(result)

def populatePreprocessTransforms(): Boolean = isSuccess(circt.firtoolPopulatePreprocessTransforms(pm, options))
def populateCHIRRTLToLowFIRRTL(): Boolean = isSuccess(circt.firtoolPopulateCHIRRTLToLowFIRRTL(pm, options, mlirModule, "-"))
def populateLowFIRRTLToHW(): Boolean = isSuccess(circt.firtoolPopulateLowFIRRTLToHW(pm, options))
def populateLowHWToSV(): Boolean = isSuccess(circt.firtoolPopulateHWToSV(pm, options))
def populateExportVerilog(callback: String => Unit): Boolean = isSuccess(circt.firtoolPopulateExportVerilog(pm, options, callback))
def populateExportSplitVerilog(directory: String): Boolean = isSuccess(circt.firtoolPopulateExportSplitVerilog(pm, options, directory))
def populateFinalizeIR(): Boolean = isSuccess(circt.firtoolPopulateFinalizeIR(pm, options))

def run(): Boolean = isSuccess(circt.mlirPassManagerRunOnOp(pm, circt.mlirModuleGetOperation(mlirModule)))
}
37 changes: 36 additions & 1 deletion binder/src/test/scala/BinderSpec.scala
Original file line number Diff line number Diff line change
@@ -2,12 +2,15 @@

package chiselTests.util.random

import java.io.OutputStream
import geny.Writable
import scala.collection.immutable.SeqMap
import chisel3._
import chisel3.util._
import chisel3.experimental._
import chisel3.internal.CIRCTConverter
import chisel3.internal.panama.circt.PanamaCIRCTConverterAnnotation
import chisel3.internal.panama.circt._
import chisel3.properties._
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

@@ -38,6 +41,18 @@ class BitLengthOfNeg1Test extends RawModule {
a := -1.S.asUInt
}

class PropertyTest extends RawModule {
val i = IO(Input(UInt(8.W)))

val p = IO(Output(Property[Path]()))
p := Property(Path(i))

val a = IO(Output(Property[Seq[Seq[Property[Int]]]]()))
val b = IO(Output(Property[Seq[Property[Seq[Int]]]]()))
a := Property(Seq[Seq[Int]](Seq(123)))
b := Property(Seq[Seq[Int]](Seq(123)))
}

class BinderTest extends AnyFlatSpec with Matchers {

def streamString(module: => RawModule, stream: CIRCTConverter => Writable): String = Seq(
@@ -85,5 +100,25 @@ class BinderTest extends AnyFlatSpec with Matchers {
firrtlString(new TruncationTest) should include("connect dest, tail(src, 8)")

firrtlString(new BitLengthOfNeg1Test) should include("asUInt(SInt<1>(-1))")

streamString(new PropertyTest, (converter: CIRCTConverter) => {
val pm = converter.passManager()
assert(pm.populatePreprocessTransforms())
assert(pm.populateCHIRRTLToLowFIRRTL())
assert(pm.populateLowFIRRTLToHW())
assert(pm.populateFinalizeIR())
assert(pm.run())

val om = converter.om()
val evaluator = om.evaluator()
val obj = evaluator.instantiate("PropertyTest_Class", Seq(om.newBasePathEmpty))
val path = obj.field("p").asInstanceOf[PanamaCIRCTOMEvaluatorValuePath].asString

assert(path == "OMReferenceTarget:~PropertyTest|PropertyTest>i")

converter.mlirStream
}) should include("om.class.field @p")
.and(include("om.class.field @a, %3 : !om.list<!om.list<!om.integer>>"))
.and(include("om.class.field @b, %3 : !om.list<!om.list<!om.integer>>"))
}
}
6 changes: 6 additions & 0 deletions core/src/main/scala/chisel3/internal/CIRCTConverter.scala
Original file line number Diff line number Diff line change
@@ -10,9 +10,13 @@ import chisel3.cover.Cover
import chisel3.internal.firrtl._

abstract class CIRCTConverter {
val mlirStream: Writable
val firrtlStream: Writable
val verilogStream: Writable

def passManager(): CIRCTPassManager
def om(): CIRCTOM

def visitCircuit(name: String): Unit

def visitDefBlackBox(defBlackBox: DefBlackBox): Unit
@@ -60,4 +64,6 @@ abstract class CIRCTConverter {
def visitAssume(assume: Verification[Assume]): Unit

def visitCover(cover: Verification[Cover]): Unit

def visitPropAssign(parent: Component, propAssign: PropAssign): Unit
}
19 changes: 19 additions & 0 deletions core/src/main/scala/chisel3/internal/CIRCTOM.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: Apache-2.0

package chisel3.internal

abstract class CIRCTOM {
def evaluator(): CIRCTOMEvaluator

def newBasePathEmpty(): CIRCTOMEvaluatorValue
}

abstract class CIRCTOMEvaluator {
def instantiate(name: String, actualParams: Seq[CIRCTOMEvaluatorValue]): CIRCTOMObject
}

abstract class CIRCTOMEvaluatorValue {}

abstract class CIRCTOMObject {
def field(name: String): CIRCTOMEvaluatorValue
}
15 changes: 15 additions & 0 deletions core/src/main/scala/chisel3/internal/CIRCTPassManager.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Apache-2.0

package chisel3.internal

abstract class CIRCTPassManager {
def populatePreprocessTransforms(): Boolean
def populateCHIRRTLToLowFIRRTL(): Boolean
def populateLowFIRRTLToHW(): Boolean
def populateLowHWToSV(): Boolean
def populateExportVerilog(callback: String => Unit): Boolean
def populateExportSplitVerilog(directory: String): Boolean
def populateFinalizeIR(): Boolean

def run(): Boolean;
}
6 changes: 6 additions & 0 deletions overlay.nix
Original file line number Diff line number Diff line change
@@ -27,6 +27,12 @@ circtSrc: final: prev:
espresso = final.callPackage ./nix/espresso.nix { };
circt = prev.circt.overrideAttrs (old: rec {
version = circtSrc.shortRev;
patches = (old.patches or []) ++ [
(prev.fetchpatch {
url = "https://github.com/SpriteOvO/circt/commit/27ed25ea9c498ba2f589228a37421098a5e80a08.patch";
hash = "sha256-U8aCaFA3pPnmmt2SdmWdxPiIO+y+braKPswprQwEwTU=";
})
];
cmakeFlags = [
"-DBUILD_SHARED_LIBS=ON"
"-DLLVM_ENABLE_BINDINGS=OFF"

0 comments on commit a3dbd29

Please sign in to comment.