All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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]




© 2015 - 2024 Weber Informatics LLC | Privacy Policy