Example #1
0
def build_false_pum(cp, instruction):
    """
    Build the integer representation of the false predicate update mask.

    :param cp: CoreParameters instance for the target architecture
    :param instruction: Instruction instance
    :return: integer representation of the false half of pum
    """

    # OR in the predicates.
    false_pum = 0
    for predicate, boolean in zip(instruction.predicate_update_indices,
                                  instruction.predicate_update_values):
        if predicate > cp.num_predicates:
            exception_string = f"Predicate {predicate} is out of range on the target architecture with " \
                               + f"{cp.num_predicates} predicates."
            raise AssemblyException(exception_string)
        if not boolean:
            false_pum |= 1 << predicate

    # Check sizing, and return the integer.
    false_pum = int(false_pum)
    if false_pum.bit_length() > cp.false_pum_width:
        raise AssemblyException("False pum exceeds its allotted bit width.")
    return false_pum
Example #2
0
def build_ictb(cp, instruction):
    """
    Build the integer representation of the input channel tag Booleans.

    :param cp: CoreParameters instance for the target architecture
    :param instruction: Instruction instance
    :return: integer representation of the ictb
    """

    # Check sizing.
    if len(instruction.trigger.input_channel_tag_booleans
           ) > cp.max_num_input_channels_to_check:
        exception_string = f"The {len(instruction.trigger.input_channel_tag_booleans)} input channel tags to check " \
                           + f"exceed the architecture's specified maximum of {cp.max_num_input_channels_to_check}."
        raise AssemblyException(exception_string)

    # Concatenate the Booleans together.
    ictb = 0
    for i, boolean in enumerate(
            reversed(instruction.trigger.input_channel_tag_booleans)):
        ictb |= boolean
        if i != len(instruction.trigger.input_channels) - 1:
            ictb <<= 1

    # Append empty slots.
    num_null_slots = cp.max_num_input_channels_to_check - len(
        instruction.trigger.input_channels)
    ictb <<= num_null_slots

    # Check sizing, and return the integer.
    ictb = int(ictb)
    if ictb.bit_length() > cp.ictb_width:
        raise AssemblyException("ictb exceeds its allotted bit width.")
    return ictb
Example #3
0
def build_ictv(cp, instruction):
    """
    Build the integer representation of the input channel tag values.

    :param cp: CoreParameters instance for the target architecture
    :param instruction: Instruction instance
    :return: integer representation of the ictv
    """

    # Check sizing.
    if len(instruction.trigger.input_channel_tags
           ) > cp.max_num_input_channels_to_check:
        exception_string = f"The {len(instruction.trigger.input_channel_tags)} input channel tags to check exceed " \
                           + f"the architecture's specified maximum of {cp.max_num_input_channels_to_check}."
        raise AssemblyException(exception_string)

    # Concatenate the values together.
    ictv = 0
    for i, tag_value in enumerate(
            reversed(instruction.trigger.input_channel_tags)):
        ictv |= tag_value
        if i != len(instruction.trigger.input_channel_tags) - 1:
            ictv <<= cp.tag_width

    # Append empty slots.
    num_null_slots = cp.max_num_input_channels_to_check - len(
        instruction.trigger.input_channel_tags)
    ictv <<= num_null_slots * cp.tag_width

    # Check sizing, and return the integer.
    ictv = int(ictv)
    if ictv.bit_length() > cp.ictv_width:
        raise AssemblyException("ictv exceeds its allotted bit width.")
    return ictv
Example #4
0
def build_ici(cp, instruction):
    """
    Build the integer representation of the input channel indices.

    :param cp: CoreParameters instance for the target architecture
    :param instruction: Instruction instance
    :return: integer representation of the ici
    """
    # Check sizing.
    if len(instruction.trigger.input_channels
           ) > cp.max_num_input_channels_to_check:
        exception_string = f"The {len(instruction.trigger.input_channels)} input channels to check exceed the " \
                           + f"architecture's specified maximum of {cp.max_num_input_channels_to_check}."
        raise AssemblyException(exception_string)

    # Concatenate the indices together.
    ici = 0
    for i, input_channel in enumerate(
            reversed(instruction.trigger.input_channels)):
        ici |= input_channel + 1  # Recall that a zero-filled ici slot implies a null value.
        if i != len(instruction.trigger.input_channels) - 1:
            ici <<= cp.single_ici_width

    # Append empty slots.
    num_null_slots = cp.max_num_input_channels_to_check - len(
        instruction.trigger.input_channels)
    ici <<= num_null_slots * cp.single_ici_width

    # Check sizing and return the integer.
    ici = int(ici)
    if ici.bit_length() > cp.ici_width:
        raise AssemblyException("ici exceeds its allotted bit width.")
    return ici
Example #5
0
def build_si(cp, instruction):
    """
    Build the integer representation of the source indices.

    :param cp: CoreParameters instance for the target architecture
    :param instruction: Instruction instance
    :return: integer representation of si
    """

    # Check sizing.
    if len(instruction.source_indices) > 3:
        exception_string = f"The {len(instruction.source_indices)} sources exceed the architecture's specified " \
                           + f"maximum of 3."
        raise AssemblyException(exception_string)

    # Concatenate the values together.
    si = 0
    num_source_indices = len(instruction.source_indices)
    if num_source_indices > 2:
        if instruction.source_indices[2] != 0:
            si |= instruction.source_indices[2]
    si <<= cp.single_si_width
    if num_source_indices > 1:
        if instruction.source_indices[1] != 0:
            si |= instruction.source_indices[1]
    si <<= cp.single_si_width
    if num_source_indices > 0:
        if instruction.source_indices[0] != 0:
            si |= instruction.source_indices[0]

    # Check sizing, and return the integer.
    si = int(si)
    if si.bit_length() > cp.si_width:
        raise AssemblyException("si exceeds its allotted bit width.")
    return si
Example #6
0
    def convert_processing_element_instructions_string_to_instructions(
            processing_element_instructions_string):
        """
        Process an assembly string for an individual PE into a set of instructions.

        :param processing_element_instructions_string: multiline string containing an assembly program (instructions only)
        :return: the corresponding list of instructions
        """

        # Remove comments (MIPS-style comments).
        processing_element_instructions_string = re.sub(
            r"#.*", "", processing_element_instructions_string)

        # Break the program into instruction strings.
        program_string_lines = processing_element_instructions_string.split(
            '\n')
        instruction_strings = []
        i = 0
        while i < len(program_string_lines):
            line = program_string_lines[i].strip()
            if line == "":
                i += 1
            elif line.endswith(':'):
                instruction_strings.append(program_string_lines[i] +
                                           program_string_lines[i + 1])
                i += 2
            elif ':' in line:
                instruction_strings.append(program_string_lines[i])
                i += 1
            else:
                exception_string = f"Unexpected statement: {line} on source line {i}."
                raise AssemblyException(exception_string)

        # Build the list of instructions.
        instructions = []
        for i, instruction_string in enumerate(instruction_strings):
            try:
                instruction = Instruction.from_string(instruction_string)
                instruction.number = i
                instructions.append(instruction)
            except Exception as e:
                instruction_string = " ".join(
                    instruction_string.split()).strip()
                exception_string = f"Error encountered in assembling instruction {i}: {instruction_string} --> {str(e)}"
                raise AssemblyException(exception_string)

        # Return the completed list of instructions.
        return instructions
Example #7
0
def build_immediate(cp, instruction):
    """
    Build the integer representation of the immediate.

    :param cp: CoreParameters instance for the target architecture
    :param instruction: Instruction instance
    :return: the integer representation of the immediate.
    """

    # Make sure we actually have an immediate value, and if not, return zero.
    if instruction.immediate is None:
        return 0

    # Check sizing.
    if instruction.immediate.bit_length() > cp.immediate_width:
        raise AssemblyException(
            "The immediate exceeds its allotted bit width.")

    # Unsigned conversion and masking.
    unsigned = int(np.uint32(
        instruction.immediate))  # max immediate is 32 bits.
    mask = 0
    for i in range(cp.immediate_width):
        mask |= 1
        if i != cp.immediate_width - 1:
            mask <<= 1
    masked = unsigned & mask

    # Return the masked value.
    return masked
Example #8
0
def build_true_ptm(cp, instruction):
    """
    Build the integer representation of the true predicate trigger mask.

    :param cp: CoreParameters instance for the target architecture
    :param instruction: Instruction instance
    :return: integer representation of the true half of the ptm
    """

    # OR in the predicates.
    true_ptm = 0
    for predicate in reversed(instruction.trigger.true_predicates):
        if predicate > cp.num_predicates:
            exception_string = f"Predicate {predicate} is out of range on the target architecture with " \
                               + f"{cp.num_predicates} predicates."
            raise AssemblyException(exception_string)
        true_ptm |= 1 << predicate

    # Check sizing, and return the integer.
    true_ptm = int(true_ptm)
    if true_ptm.bit_length() > cp.true_ptm_width:
        raise AssemblyException("True ptm exceeds its allotted bit width.")
    return true_ptm
Example #9
0
def build_dt(cp, instruction):
    """
    Build the integer representation of destination type.

    :param cp: CoreParameters instance for the target architecture
    :param instruction: Instruction instance
    :return: integer representation of dt
    """

    # Should already have the correct value.
    dt = instruction.destination_type

    # Check sizing, and return the integer.
    dt = int(dt)
    if dt.bit_length() > cp.di_width:
        raise AssemblyException("dt exceeds its allotted bit width.")
    return dt
Example #10
0
def build_op(cp, instruction):
    """
    Build the integer representation of a datapath operation.

    :param cp: CoreParameters instance for the target architecture
    :param instruction: Instruction instance
    :return: integer representation of op
    """

    # Should already have the correct value.
    op = instruction.op

    # Check sizing, and return the integer.
    op = int(op)
    if op.bit_length() > cp.op_width:
        raise AssemblyException("op exceeds its allotted bit width.")
    return op
Example #11
0
def build_pum(cp, instruction):
    """
    Build the integer representation of the concatenated predicate update mask.

    :param cp: CoreParameters instance for the target architecture
    :param instruction: Instruction instance
    :return: integer representation of the pum
    """

    # Concatenate the two pum halves.
    pum = build_true_pum(cp, instruction) << cp.false_ptm_width
    pum |= build_false_pum(cp, instruction)

    # Check sizing, and return the integer.
    pum = int(pum)
    if pum.bit_length() > cp.ptm_width:
        raise AssemblyException("pum exceeds its allotted bit width.")
    return pum
Example #12
0
    def extract_register_initialization_data_from_statement(statement):
        """
        Extract the register index and register data from an initialization statement.

        :param statement: "set %r5 = 0x1234;", for example
        :return: the index and data as integers
        """

        # Strip the statement of comments and whitespace.
        statement = re.sub(r"#.*", "", statement)
        statement = statement.strip()

        # Extract the register index.
        register_index_pattern = r"init\s*%r(\d+)\s*,.*"
        match = re.match(register_index_pattern, statement)
        if match is None:
            exception_string = f"Invalid register initialization statement: {statement}."
            raise AssemblyException(exception_string)
        try:
            register_index_string = match.group(1)
        except IndexError:
            exception_string = f"Invalid register initialization statement: {statement}."
            raise AssemblyException(exception_string)
        try:
            register_index = int(register_index_string)
        except ValueError:
            exception_string = f"Invalid register index in initialization statement: {statement}."
            raise AssemblyException(exception_string)

        # Extract the register data.
        register_data_pattern = r"init\s*%r\d+\s*,\s*\$(-*\d*|-*0x\d*);"
        match = re.match(register_data_pattern, statement)
        if match is None:
            exception_string = f"Invalid register initialization statement: {statement}."
            raise AssemblyException(exception_string)
        try:
            register_data_string = match.group(1)
        except IndexError:
            exception_string = f"Invalid register initialization statement: {statement}."
            raise AssemblyException(exception_string)
        if "0x" in register_data_string:
            base = 16
        else:
            base = 10
        try:
            register_data = int(register_data_string, base=base)
        except ValueError:
            exception_string = f"Invalid register data in initialization statement: {statement}."
            raise AssemblyException(exception_string)

        # Return the extracted information.
        return register_index, register_data
Example #13
0
def build_program_binary(cp, program):
    """
    Convert the program to a list of 32-bit words to be written out to disk or programmed into the hardware.
    :param cp: CoreParameters instance for the target architecture
    :param program: a ProcessingElementProgram instance
    :return: the register initialization settings and the instructions as two lists of 32-bit words
    """

    # Generate register initialization data as 32-bit words.
    register_words = []
    for register_value in program.register_values:
        unsigned = int(np.uint32(register_value))  # max word size is 32 bits.
        mask = 0
        for i in range(cp.device_word_width):
            mask |= 1
            if i != cp.device_word_width - 1:
                mask <<= 1
        masked = unsigned & mask
        register_words.append(np.uint32(masked))

    # Machine code instructions are sliced into individual 32-bit words.
    if cp.mm_instruction_width % 32 != 0:
        raise AssemblyException(
            "Memory-mapped instructions must be in multiples of 32-bit words.")
    mm_instruction_word_width = int(cp.mm_instruction_width / 32)
    assembled_instructions = [
        build_machine_code_instruction(cp, instruction)
        for instruction in program.instructions
    ]
    instruction_words = []
    for assembled_instruction in assembled_instructions:
        for i in range(mm_instruction_word_width):
            instruction_words.append((assembled_instruction >> i * 32)
                                     & 0xffffffff)

    # Append empty instructions to fill out remaining instruction memory.
    if len(assembled_instructions) < cp.num_instructions:
        num_empty_instructions = cp.num_instructions - len(
            assembled_instructions)
        for _ in range(num_empty_instructions):
            instruction_words += [0] * mm_instruction_word_width

    # Return the two lists.
    return register_words, instruction_words
Example #14
0
    def validate(self):
        """
        Validate the register file values and instructions in a program against architectural parameters.
        """

        # Validate register values.
        for i, register_value in enumerate(self.register_values):
            if register_value < 0:
                effective_bit_length = register_value.bit_length() + 1
            else:
                effective_bit_length = register_value.bit_length()
            if effective_bit_length > self.cp.device_word_width:
                exception_string = f"In program {self.label}, register {i} initialized to too wide of a value for " \
                                   + f"this architecture: {register_value}"
                raise AssemblyException(exception_string)

        # Will raise an exception if needed.
        for instruction in self.instructions:
            instruction.validate(self.cp)
Example #15
0
def build_di(cp, instruction):
    """
    Build the integer representation of destination index.

    :param cp: CoreParameters instance for the target architecture
    :param instruction: Instruction instance
    :return: integer representation of di
    """

    # If it exists, again we have to increment it by one to show it is not void.
    if instruction.destination_index is not None:
        di = instruction.destination_index
    else:
        di = 0

    # Check sizing, and return the integer.
    di = int(di)
    if di.bit_length() > cp.di_width:
        raise AssemblyException("di exceeds its allotted bit width.")
    return di
Example #16
0
def build_oct(cp, instruction):
    """
    Build the integer representation of the destination tag.

    :param cp: CoreParameters instance for the target architecture
    :param instruction: Instruction instance
    :return: integer representation of oct
    """

    # If it exists, again we have to increment it by one to show it is not void.
    if instruction.output_channel_tag is not None:
        oct = instruction.output_channel_tag
    else:
        oct = 0

    # Check sizing, and return the integer.
    oct = int(oct)
    if oct.bit_length() > cp.oct_width:
        raise AssemblyException("oct exceeds its allotted bit width.")
    return oct
Example #17
0
def build_oci(cp, instruction):
    """
    Build the integer representation of the output channel indices array.

    :param cp: CoreParameters instance of the target architecture.
    :param instruction: Instruction instance
    :return: integer representation of oci
    """

    # OR in the output channels.
    oci = 0
    for output_channel in reversed(range(cp.num_output_channels)):
        if output_channel in instruction.output_channel_indices:
            oci |= 1
        if output_channel != 0:
            oci <<= 1

    # Check sizing, and return the integer.
    oci = int(oci)
    if oci.bit_length() > cp.oci_width:
        raise AssemblyException("oci exceeds its allotted bit width.")
    return oci
Example #18
0
def build_icd(cp, instruction):
    """
    Build the integer representation of the input channels to dequeue.

    :param cp: CoreParameters instance for the target architecture
    :param instruction: Instruction instance
    :return: integer representation of icd
    """

    # OR in the literal array of bits.
    icd = 0
    for input_channel in reversed(range(cp.num_input_channels)):
        if input_channel in instruction.input_channels_to_dequeue:
            icd |= 1
        if input_channel != 0:
            icd <<= 1

    # Check sizing, and return the integer.
    icd = int(icd)
    if icd.bit_length() > cp.icd_width:
        raise AssemblyException("icd exceeds its allotted bit width.")
    return icd
Example #19
0
    def from_label_and_string(cls, cp, label,
                              processing_element_program_string):
        """
        Build from a processing element label and register-file initialization/instruction string.

        :param cp: a CoreParameters instance
        :param label: processing element label
        :param processing_element_program_string: register setting statements and instructions
        :return: an initialized instance
        """

        # Build fields manually.
        try:
            register_string, instruction_string = \
                ProcessingElementProgram.split_into_register_and_instruction_strings(processing_element_program_string)
            register_values = \
                ProcessingElementProgram.convert_register_initialization_statements_to_register_values(cp, register_string)
            instructions = \
                ProcessingElementProgram.convert_processing_element_instructions_string_to_instructions(instruction_string)
        except AssemblyException as e:
            exception_string = f"Error parsing program {label}: {str(e)}"
            raise AssemblyException(exception_string)
        return cls(cp, label, register_values, instructions)