Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
dfhdl.core.DFBoolOrBit.scala Maven / Gradle / Ivy
package dfhdl.core
import dfhdl.compiler.ir
import ir.DFVal.Func.Op as FuncOp
import dfhdl.internals.*
import annotation.{implicitNotFound, targetName}
type BitNum = 0 | 1
type BitOrBool = BitNum | Boolean
type DFBoolOrBit = DFType[ir.DFBoolOrBit, NoArgs]
object DFBoolOrBit:
type Data = Option[Boolean]
given DFBool = DFBool
given DFBit = DFBit
object Val:
@implicitNotFound(
"Argument of type ${R} is not a proper candidate for a DFBool or DFBit DFHDL value."
)
trait Candidate[R]:
type OutT <: DFBoolOrBit
type OutP
type Out = DFValTP[OutT, OutP]
def apply(arg: R)(using DFC): Out
object Candidate:
given fromBoolean[R <: Boolean]: Candidate[R] with
type OutT = DFBool
type OutP = CONST
def apply(arg: R)(using DFC): Out =
DFVal.Const(DFBool, Some(arg), named = true)
given fromBit[R <: BitNum]: Candidate[R] with
type OutT = DFBit
type OutP = CONST
def apply(arg: R)(using DFC): Out =
DFVal.Const(DFBit, Some(arg > 0), named = true)
given fromDFBoolOrBitVal[T <: DFBoolOrBit, P, R <: DFValTP[T, P]]: Candidate[R] with
type OutT = T
type OutP = P
def apply(arg: R)(using DFC): Out = arg
end Candidate
private def b2b[T <: DFBoolOrBit, R](dfType: T, arg: R)(using
ic: Candidate[R],
dfc: DFC
): DFValTP[T, ic.OutP] =
import Ops.{bit, bool}
val dfValArg = ic(arg)
val dfValOut = (dfType, dfValArg.dfType) match
case (DFBit, DFBool) => dfValArg.asValOf[DFBool].bit
case (DFBool, DFBit) => dfValArg.asValOf[DFBit].bool
case _ => dfValArg
dfValOut.asValTP[T, ic.OutP]
object TC:
import DFVal.TC
given DFBoolOrBitFromCandidate[T <: DFBoolOrBit, R, IC <: Candidate[R]](using
ic: IC
): TC[T, R] with
type OutP = ic.OutP
def conv(dfType: T, arg: R)(using DFC): Out = b2b(dfType, arg)
end TC
object Compare:
import DFVal.Compare
given DFBoolOrBitCompare[T <: DFBoolOrBit, R, IC <: Candidate[R], Op <: FuncOp, C <: Boolean](
using
ic: IC,
op: ValueOf[Op],
castling: ValueOf[C]
): Compare[T, R, Op, C] with
type OutP = ic.OutP
def conv(dfType: T, arg: R)(using DFC): Out =
b2b(dfType, arg)
object Ops:
extension [P](lhs: DFValTP[DFBoolOrBit, P])
def toScalaBoolean(using DFC, DFVal.ConstCheck[P]): Boolean =
lhs.toScalaValue
def toScalaBitNum(using DFC, DFVal.ConstCheck[P]): BitNum =
if (lhs.toScalaBoolean) 1 else 0
extension [P](lhs: DFValTP[DFBit, P])
def rising(using DFC): DFValOf[DFBool] = trydf {
DFVal.Func(DFBool, FuncOp.rising, List(lhs))
}
def falling(using DFC): DFValOf[DFBool] = trydf {
DFVal.Func(DFBool, FuncOp.falling, List(lhs))
}
def bool(using DFC): DFValTP[DFBool, P] = trydf {
DFVal.Alias.AsIs(DFBool, lhs)
}
@targetName("notOfDFBit")
def unary_!(using DFC): DFValTP[DFBit, P] = trydf {
DFVal.Func(DFBit, FuncOp.unary_!, List(lhs))
}
end extension
extension [P](lhs: DFValTP[DFBool, P])
def bit(using DFC): DFValTP[DFBit, P] = trydf {
DFVal.Alias.AsIs(DFBit, lhs)
}
@targetName("notOfDFBool")
def unary_!(using DFC): DFValTP[DFBool, P] = trydf {
DFVal.Func(DFBool, FuncOp.unary_!, List(lhs))
}
private def logicOp[T <: DFBoolOrBit, P, R](
dfVal: DFValTP[T, P],
arg: R,
op: FuncOp,
castle: Boolean
)(using dfc: DFC, ic: Candidate[R]): DFValTP[T, P | ic.OutP] =
val dfValArg = b2b(dfVal.dfType, arg)
val (lhs, rhs) = if (castle) (dfValArg, dfVal) else (dfVal, dfValArg)
DFVal.Func(lhs.dfType.asFE[T], op, List(lhs, rhs))
extension [T <: DFBoolOrBit, P](lhs: DFValTP[T, P])
def ||[R](rhs: Exact[R])(using dfc: DFC, ic: Candidate[R]): DFValTP[T, P | ic.OutP] =
trydf { logicOp[T, P, R](lhs, rhs, FuncOp.|, false) }
def &&[R](rhs: Exact[R])(using dfc: DFC, ic: Candidate[R]): DFValTP[T, P | ic.OutP] =
trydf { logicOp[T, P, R](lhs, rhs, FuncOp.&, false) }
def ^[R](rhs: Exact[R])(using dfc: DFC, ic: Candidate[R]): DFValTP[T, P | ic.OutP] =
trydf { logicOp[T, P, R](lhs, rhs, FuncOp.^, false) }
private def selForced[R <: DFTypeAny, OTP, OFP](
onTrue: DFValTP[R, OTP],
onFalse: DFValTP[R, OFP]
)(using dfc: DFC): DFValTP[R, P | OTP | OFP] =
val boolLHS = lhs.asIR.dfType match
case ir.DFBit => lhs.asValTP[DFBit, P].bool
case _ => lhs.asValTP[DFBool, P]
DFVal.Func(onTrue.dfType, FuncOp.sel, List(boolLHS, onTrue, onFalse))
def sel[R <: DFTypeAny, OTP, OF, OFP](onTrue: DFValTP[R, OTP], onFalse: Exact[OF])(using
dfc: DFC,
tcOF: DFVal.TC.Aux[R, OF, OFP]
): DFValTP[R, P | OTP | OFP] =
trydf { selForced(onTrue, tcOF(onTrue.dfType, onFalse)) }
def sel[R <: DFTypeAny, OT, OF, OTP, OFP](
outType: R
)(onTrue: Exact[OT], onFalse: Exact[OF])(using
dfc: DFC,
tcOT: DFVal.TC.Aux[R, OT, OTP],
tcOF: DFVal.TC.Aux[R, OF, OFP]
): DFValTP[R, P | OTP | OFP] =
trydf { selForced(tcOT(outType, onTrue), tcOF(outType, onFalse)) }
end extension
extension [L](lhs: L)
inline def ||[RT <: DFBoolOrBit, RP](
rhs: DFValTP[RT, RP]
)(using es: Exact.Summon[L, lhs.type])(using Candidate[es.Out]): Nothing =
compiletime.error(
"Unsupported Scala BitNum/Boolean primitive at the LHS of `||` with a DFHDL value.\nConsider switching positions of the arguments."
)
inline def &&[RT <: DFBoolOrBit, RP](
rhs: DFValTP[RT, RP]
)(using es: Exact.Summon[L, lhs.type])(using Candidate[es.Out]): Nothing =
compiletime.error(
"Unsupported Scala BitNum/Boolean primitive at the LHS of `&&` with a DFHDL value.\nConsider switching positions of the arguments."
)
inline def ^[RT <: DFBoolOrBit, RP](
rhs: DFValTP[RT, RP]
)(using es: Exact.Summon[L, lhs.type])(using Candidate[es.Out]): Nothing =
compiletime.error(
"Unsupported Scala BitNum/Boolean primitive at the LHS of `^` with a DFHDL value.\nConsider switching positions of the arguments."
)
end extension
end Ops
end Val
end DFBoolOrBit
type DFBool = DFType[ir.DFBool.type, NoArgs]
final lazy val DFBool = ir.DFBool.asFE[DFBool]
type DFBit = DFType[ir.DFBit.type, NoArgs]
final lazy val DFBit = ir.DFBit.asFE[DFBit]
given CanEqual[DFBoolOrBit, DFBoolOrBit] = CanEqual.derived
type DFConstBool = DFConstOf[DFBool]
type DFConstBit = DFConstOf[DFBit]