Beispiel #1
0
def DefineDehydrate(cirb: CoreIRBackend, T: Kind):
    """
    Convert a nested type to a flat array of bits
    Aetherling Type: {1, T} -> {1, Bit[width(T)]}
    This returns a circuit definition.

    Args:
        cirb: The CoreIR backend currently be used
        T: The type to dehydrate

    Returns:
        A module with the following ports:
        I : In(T)
        out : Out(Array(width(T), Bit))

        The module also has the following data:
        size: width(T)
    """
    cirType = cirb.get_type(T, True)
    name = "dehydrate_t{}".format(cleanName(str(T)))
    defToReturn = DefineCircuitFromGeneratorWrapper(
        cirb, "aetherlinglib", "dehydrate", name,
        ["commonlib", "mantle", "coreir", "global"], {"hydratedType": cirType})
    defToReturn.size = cirType.size
    return defToReturn
Beispiel #2
0
def DefineMapParallel(numInputs: int,
                      op: DefineCircuitKind) -> DefineCircuitKind:
    """
    Map an operation over numInputs inputs in one clock cycle
    Aetherling Type: {1, T[numInputs]} -> {1, S[numInputs]}
    This returns a circuit definition.

    :param cirb: The CoreIR backend currently be used
    :param numInputs: The number of input elements
    :param op: The operator (the magma circuit) to map over the elements. It should have type T -> S
    :return: A module with all the ports of op, except that they will be converted to arrays
     of original type, with each array of length numInputs. For example, if op has
     one input port I and one output O, the ports will be:
    I : In(Array[numInputs, T])
    O : Out(Array[numInputs, S])
    """
    cirb = GetCoreIRBackend()
    if hasattr(op, 'is_instance'
               ) and op.is_instance and op.defn.instances.__contains__(op):
        op.defn.instances.remove(op)
    name = "MapParallel_n{}_op{}".format(str(numInputs), cleanName(str(op)))
    definitionToReturn = DefineCircuitFromGeneratorWrapper(
        cirb, "aetherlinglib", "mapParallel", name,
        ["commonlib", "mantle", "coreir", "global"], {
            "numInputs": numInputs,
            "operator": GetCoreIRModule(cirb, op)
        })
    return definitionToReturn
Beispiel #3
0
def DefineMapSequential(numInputs: int,
                        op: DefineCircuitKind) -> DefineCircuitKind:
    """
    Map an operation over numInputs inputs over numInputs cycles.
    Note: the entire inputs must be delivered on the first cycle.
    There is no point in implementing the streaming version of this operation
    as that is just the module op.
    Aetherling Type: {1, T[numInputs]} -> {1, S[numInputs]}
    This returns a circuit definition.

    :param cirb: The CoreIR backend currently be used
    :param numInputs: The number of input elements
    :param op: The operator (the coreir module) to map over the elements. It should
    s.t. Op : T -> S
    :return: A module with all the ports of op, except that they will be converted to arrays
     of original type, with each array of length numInputs. For example, if op has
     one input port I and one output O, the ports will be:
     I : In(Array[numInputs, T]
     O : Out(Array[numInputs, S])
    """
    cirb = GetCoreIRBackend()
    if op.is_instance and op.defn.instances.__contains__(op):
        op.defn.instances.remove(op)
    name = "MapSequential_n{}_op{}".format(str(numInputs), cleanName(str(op)))
    definitionToReturn = DefineCircuitFromGeneratorWrapper(
        cirb, "aetherlinglib", "mapSequential", name,
        ["commonlib", "mantle", "coreir", "global"], {
            "numInputs": numInputs,
            "operator": GetCoreIRModule(cirb, op)
        })
    return definitionToReturn
Beispiel #4
0
def DefineReduceParallelWithIdentity(numInputs: int, op: Circuit) -> Circuit:
    """
    Reduce multiple numInputs into one in one clock cycle.
    This uses a reduction tree but can handle numInputs that aren't powers of 2.
    It does this using the identity element to fill in inputs to the tree that aren't used.
    Aetherling Type: ({1, T[numInputs]} -> {1, T}, 1)

    :param cirb: The CoreIR backend currently be used
    :param numInputs: The number of input elements
    :param op: The operator (the magma circuit) to map over the elements. It should have type T -> T -> T,
    with input ports in0 and in1.
    :return: A module with ports:
    I: In({
        data: Array[numInputs, T],
        identity: T
    })
    out: Out(T)
    """
    cirb = GetCoreIRBackend()
    if op.is_instance and op.defn.instances.__contains__(op):
        op.defn.instances.remove(op)
    name = "ReduceParallel_n{}_op{}".format(str(numInputs), cleanName(str(op)))
    moduleToReturn = DefineCircuitFromGeneratorWrapper(cirb, "aetherlinglib", "reduceParallel", name,
                                                         ["commonlib", "mantle", "coreir", "global"],
                                                         {"numInputs": numInputs,
                                                          "operator": GetCoreIRModule(cirb, op)})
    return moduleToReturn
Beispiel #5
0
def DefineLinebuffer(cirb: CoreIRBackend,
                     inType: ArrayKind,
                     outType: ArrayKind,
                     imgType: ArrayKind,
                     has_valid=False):
    """
    Implements a linebuffer for image pipelines. inType is an array of how many pixels
    are inputted per clock. outType is an array of how many pixels are emitted per clock.
    imgType is the size of the total image.

    inType and outType are nested arrays of elementType if doing linebuffer over a 2d (or higher dimension)
    image. Their nesting should match number of dimensions.

    inType, outType, and imgType must be arrays of elementType

    Args:
        cirb: The CoreIR backend currently be used
        inType: The type of the input every clock
        outType: The type of the output every clock following warmup
        imgType: The type of the complete image
        elementType: The elements of the image, typically this is a pixel
        has_valid: Whether this module should have an output port denoting if output data
        is valid this clock

    Returns:
        A module with the following ports:
        I : In(inType)
        out : Out(outType)
        wen : In(Bit) -- this is a clock enable port. TODO: wrap this module and call it CE

        AND IF VALID SET
        valid : Out(Bit)
        valid_chain : Out(Bit) (this is an internal property that is being
        exposed on linebuffer's external interface. always send it to a term)
    """
    # Reason for weird False/True settings in get_type
    # get_type does some funky things, False means not input, and since
    # looking from inside module, output port is an input as it receives input
    # But, linebuffer wants these ports from perspective of outside,
    # so need inverse, inputs are BitIns and outputs are Bits
    cirInType = cirb.get_type(inType, False)
    cirOutType = cirb.get_type(outType, True)
    cirImgType = cirb.get_type(imgType, False)
    strForValid = "_Valid" if has_valid else ""
    name = "linebuffer_in{}_out{}_img{}{}".format(cleanName(str(inType)),
                                                  cleanName(str(outType)),
                                                  cleanName(str(imgType)),
                                                  strForValid)
    # this is the linebuffer with the outputs as a flat array, unsplit
    defToReturn = DefineCircuitFromGeneratorWrapper(
        cirb, "commonlib", "linebuffer", "unioned_" + name,
        ["mantle", "coreir", "global"], {
            "input_type": cirInType,
            "output_type": cirOutType,
            "image_type": cirImgType,
            "has_valid": has_valid
        })

    return defToReturn
def DefineTerm(width: int):
    """
    Take in an array of wires and connect it to nothing so that you don't get an unconnected
    Returns a circuit definition.

    :param cirb: The CoreIR backend currently be used
    :param width: The width of the element to absorb
    :return:
    """
    return DefineCircuitFromGeneratorWrapper(GetCoreIRBackend(), "coreir",
                                             "term", "term_w" + str(width),
                                             ["global"], {"width": width})
Beispiel #7
0
def DefineCommonlibMuxN(cirb: CoreIRBackend, N: int, width: int):
    """
    Get a Mux that handles any number of inputs

    :param N: The number of inputs to select between
    :param width: The number of bits per input
    :return: A circuit with the following ports:
    I : {
        data: In(Array(N, Array(width, Bit)))
        sel: In(Array(getRAMAddrWidth(N), Bit))
    }
    out : Out(Array(width, Bit))
    Note: even though this isn't a RAM, the AddrWidth computation is the same.
    """
    name = "CommonlibMuxN_n{}_w{}".format(str(N), str(width))
    return DefineCircuitFromGeneratorWrapper(cirb, "commonlib", "muxn", name,
                                             ["mantle", "coreir", "global"], {
                                                 "N": N,
                                                 "width": width
                                             })
Beispiel #8
0
        def definition(cls):
            lb = Linebuffer(cirb, Array(pxPerClock, elementType),
                            Array(stencilWidth + pxPerClock - 1, elementType),
                            imgType)
            overlapPartition = DefineCircuitFromGeneratorWrapper(
                cirb, "aetherlinglib", "overlapPartition",
                "overlapPartition_" + cls.name,
                ["commonlib", "mantle", "coreir", "global"], {
                    "elementType": cls.cirElementType,
                    "numOverlapped": pxPerClock,
                    "arrayLen": stencilWidth
                })()

            wire(cls.I, lb.I)
            wire(lb.out, overlapPartition.I)
            wire(overlapPartition.out, cls.O)
            wire(lb.wen, cls.CE)

            if (has_valid):
                cls.wire(lb.valid, cls.valid)
                validChainTerm = Term(cirb, 1)
                wire(lb.valid_chain, validChainTerm.I[0])