diff --git a/.gitignore b/.gitignore index 5f2652fa880..f3ad0d9f518 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ test_run_dir *~ \#*\# .\#* +.vscode .metals .bloop .scala-build diff --git a/binder/includeFunctions.txt b/binder/includeFunctions.txt index bb4bcdfa25a..a7a9535f8f6 100644 --- a/binder/includeFunctions.txt +++ b/binder/includeFunctions.txt @@ -19,7 +19,9 @@ mlirOperationStateGet mlirNamedAttributeGet mlirIntegerAttrGet mlirFloatAttrDoubleGet +mlirBoolAttrGet mlirStringAttrGet +mlirStringAttrGetValue mlirArrayAttrGet mlirTypeAttrGet mlirArrayAttrGet @@ -66,6 +68,14 @@ firrtlTypeGetAsyncReset firrtlTypeGetAnalog firrtlTypeGetVector firrtlTypeGetBundle +firrtlTypeGetAnyRef +firrtlTypeGetInteger +firrtlTypeGetDouble +firrtlTypeGetString +firrtlTypeGetBoolean +firrtlTypeGetPath +firrtlTypeGetList +firrtlTypeGetClass # FIRRTL Attribute firrtlAttrGetPortDirs @@ -132,3 +142,68 @@ circtFirtoolPopulateHWToSV circtFirtoolPopulateExportVerilog circtFirtoolPopulateExportSplitVerilog circtFirtoolPopulateFinalizeIR + +# +# 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 diff --git a/binder/includeStructs.txt b/binder/includeStructs.txt index 9fb5d8dabbd..0ced725de47 100644 --- a/binder/includeStructs.txt +++ b/binder/includeStructs.txt @@ -17,4 +17,7 @@ MlirOpPassManager MlirPass MlirLogicalResult FIRRTLBundleField +FIRRTLClassElement CirctFirtoolFirtoolOptions +OMEvaluator +OMEvaluatorValue diff --git a/binder/jextract-headers.h b/binder/jextract-headers.h index 81bcaa2ae26..9df367caff8 100644 --- a/binder/jextract-headers.h +++ b/binder/jextract-headers.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/binder/linkLibraries.txt b/binder/linkLibraries.txt index 3b17d2b8925..cc3826af9ff 100644 --- a/binder/linkLibraries.txt +++ b/binder/linkLibraries.txt @@ -4,6 +4,7 @@ CIRCTCAPICHIRRTL CIRCTCAPIHW CIRCTCAPISV CIRCTCAPISeq +CIRCTCAPIOM CIRCTCAPIFirtool CIRCTCAPIExportFIRRTL CIRCTCAPIExportVerilog diff --git a/binder/src/main/scala/PanamaCIRCT.scala b/binder/src/main/scala/PanamaCIRCT.scala index eb70f996c6b..58d4d340999 100644 --- a/binder/src/main/scala/PanamaCIRCT.scala +++ b/binder/src/main/scala/PanamaCIRCT.scala @@ -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( @@ -344,6 +351,9 @@ class PanamaCIRCT { CAPI.circtFirtoolPopulateExportSplitVerilog(arena, pm.get, options.get, newString(directory).get) ) + def circtFirtoolPopulateFinalizeIR(pm: MlirPassManager, options: CirctFirtoolFirtoolOptions) = + MlirLogicalResult(CAPI.circtFirtoolPopulateFinalizeIR(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 @@ -376,6 +386,32 @@ class PanamaCIRCT { MlirType(CAPI.firrtlTypeGetBundle(arena, mlirCtx, fields.length, buffer)) } + 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 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)) @@ -402,6 +438,101 @@ 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) + ) } // @@ -559,6 +690,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 CirctFirtoolFirtoolOptions(ptr: MemorySegment) extends ForeignType[MemorySegment] { private[circt] def get = ptr private[circt] val sizeof = circt.CirctFirtoolFirtoolOptions.sizeof().toInt @@ -567,6 +700,22 @@ object CirctFirtoolFirtoolOptions { private[circt] def apply(ptr: MemorySegment) = new CirctFirtoolFirtoolOptions(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 // diff --git a/binder/src/main/scala/PanamaCIRCTConverter.scala b/binder/src/main/scala/PanamaCIRCTConverter.scala index 668b77a4c12..2f660f4a4ed 100644 --- a/binder/src/main/scala/PanamaCIRCTConverter.scala +++ b/binder/src/main/scala/PanamaCIRCTConverter.scala @@ -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._ @@ -166,6 +167,18 @@ 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? */ + ) } } @@ -439,7 +452,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,11 +466,52 @@ 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 unhandled => throw new Exception(s"unhandled arg type to be reference: $unhandled") + case propLit: PropertyLit[_, _] => referToNewProperty(propLit) + case unhandled => throw new Exception(s"unhandled arg type to be reference: $unhandled") } } @@ -504,6 +558,9 @@ class PanamaCIRCTConverter extends CIRCTConverter { } } + 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 +1242,28 @@ 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 +1315,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 +1398,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) + } } diff --git a/binder/src/main/scala/PanamaCIRCTOM.scala b/binder/src/main/scala/PanamaCIRCTOM.scala new file mode 100644 index 00000000000..ee3d8db8f70 --- /dev/null +++ b/binder/src/main/scala/PanamaCIRCTOM.scala @@ -0,0 +1,89 @@ +// 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)) +} diff --git a/binder/src/main/scala/PanamaCIRCTPassManager.scala b/binder/src/main/scala/PanamaCIRCTPassManager.scala new file mode 100644 index 00000000000..bbb1f2baa7d --- /dev/null +++ b/binder/src/main/scala/PanamaCIRCTPassManager.scala @@ -0,0 +1,28 @@ +// 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.circtFirtoolOptionsCreateDefault() // TODO: Make it configurable from CIRCTPassManager + + private def isSuccess(result: MlirLogicalResult): Boolean = circt.mlirLogicalResultIsSuccess(result) + + def populatePreprocessTransforms(): Boolean = isSuccess(circt.circtFirtoolPopulatePreprocessTransforms(pm, options)) + def populateCHIRRTLToLowFIRRTL(): Boolean = isSuccess( + circt.circtFirtoolPopulateCHIRRTLToLowFIRRTL(pm, options, mlirModule, "-") + ) + def populateLowFIRRTLToHW(): Boolean = isSuccess(circt.circtFirtoolPopulateLowFIRRTLToHW(pm, options)) + def populateLowHWToSV(): Boolean = isSuccess(circt.circtFirtoolPopulateHWToSV(pm, options)) + def populateExportVerilog(callback: String => Unit): Boolean = isSuccess( + circt.circtFirtoolPopulateExportVerilog(pm, options, callback) + ) + def populateExportSplitVerilog(directory: String): Boolean = isSuccess( + circt.circtFirtoolPopulateExportSplitVerilog(pm, options, directory) + ) + def populateFinalizeIR(): Boolean = isSuccess(circt.circtFirtoolPopulateFinalizeIR(pm, options)) + + def run(): Boolean = isSuccess(circt.mlirPassManagerRunOnOp(pm, circt.mlirModuleGetOperation(mlirModule))) +} diff --git a/binder/src/test/scala/BinderSpec.scala b/binder/src/test/scala/BinderSpec.scala index e1ccae93437..543a78ce06f 100644 --- a/binder/src/test/scala/BinderSpec.scala +++ b/binder/src/test/scala/BinderSpec.scala @@ -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,28 @@ 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, %1 : !om.frozenpath") + .and(include("om.class.field @a, %3 : !om.list>")) + .and(include("om.class.field @b, %3 : !om.list>")) } } diff --git a/core/src/main/scala/chisel3/internal/CIRCTConverter.scala b/core/src/main/scala/chisel3/internal/CIRCTConverter.scala index e0019036ffc..ba94c5576f3 100644 --- a/core/src/main/scala/chisel3/internal/CIRCTConverter.scala +++ b/core/src/main/scala/chisel3/internal/CIRCTConverter.scala @@ -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 } diff --git a/core/src/main/scala/chisel3/internal/CIRCTOM.scala b/core/src/main/scala/chisel3/internal/CIRCTOM.scala new file mode 100644 index 00000000000..c9b910d7095 --- /dev/null +++ b/core/src/main/scala/chisel3/internal/CIRCTOM.scala @@ -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 +} diff --git a/core/src/main/scala/chisel3/internal/CIRCTPassManager.scala b/core/src/main/scala/chisel3/internal/CIRCTPassManager.scala new file mode 100644 index 00000000000..a1b1969f02a --- /dev/null +++ b/core/src/main/scala/chisel3/internal/CIRCTPassManager.scala @@ -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; +}