Example #1
0
    def branchAbsolute(self, args, instruction_decoded, **named_args):
        """Sets the instruction pointer to a new memory address.

        Values:
            a = int
           [b = int]

           Takes an optional second argument which can be used
           to simulate a jump return offset amongst other things.

        Returns True
        """
        self.log.buffer('branchAbsolute called', level.FINER)
        a = int(instruction_decoded[args[0]], 2)
        self.log.buffer('args 0:{:}'.format(a), level.FINEST)
        # add branch delay
        if len(args) > 1:
            b = int(self._register.get_value(args[1]))
            self.log.buffer('args 1:{:}'.format(b), level.FINEST)
            word_space = self._memory.get_word_spacing()
            b = b * word_space
            a = a + b
        pc=self._register.get_pc()
        self._register.set_value(pc, a)
        return True
Example #2
0
    def subRegisters(self, args, instruction_decoded, **named_args):
        """args:list -> True

        Subtracts two registers and stores the result in a third.

        Args:
            Each argument should be the number of a register.
            args[0]:int (register)
            args[1]:int (register)
            args[2]:int (register)

        State changed:
            register[a]['value'] <-
                register[b]['value'] - register[c]['value']

        Returns:
            Always returns True

        Raises:
            RegisterReferenceException
        """
        self.log.buffer('subRegisters called', level.FINER)
        a = int(instruction_decoded[args[0]], 2)
        b = int(instruction_decoded[args[1]], 2)
        c = int(instruction_decoded[args[2]], 2)
        self.log.buffer('args 0:{0}, 1:{1}, 2:{2}'.format(a,b,c), level.FINEST)
        for operand in [a, b, c]:
            if operand not in self._register.keys():
                raise RegisterReferenceException
        result = self._register.get_value(b) - self._register.get_value(c)
        self._register.set_value(a, result)
        return True
Example #3
0
    def setRegister(self, args, instruction_decoded, **named_args):
        """args:list -> True

        Sets the value of a register.

        Args:
            Either argument can be a register or immediate value.
            args[0]:int (target)
            args[1]:int (value)

        State changed:
            register[a]['value'] <- b:int

        Returns:
            Always returns True
        """
        self.log.buffer('setRegister called', level.FINER)
        if args[0] in instruction_decoded.keys():
            a = int(instruction_decoded[args[0]], 2)
        else:
            a = args[0]
        if args[1] in instruction_decoded.keys():
            b = int(instruction_decoded[args[1]], 2)
        else:
            b = args[1]
        self.log.buffer('args 0:{0}, 1:{1}'.format(a,b), level.FINEST)
        self._register.set_value(a, b)
        return True
Example #4
0
    def mulRegisters(self, args, instruction_decoded, **named_args):
        """args:list -> True

        Multiplies two registers and stores the product in hi and lo
        registers.

        Args:
            Each argument should be the number of a register.
            args[0]:int (high result register)
            args[1]:int (low result register)
            args[2]:int (operand)
            args[3]:int (operand)

        Returns:
            Always returns True

        Raises:
            RegisterReferenceException
        """
        self.log.buffer('mulRegisters called', level.FINER)
        try:
            a = int(instruction_decoded[args[0]], 2)
        except:
            a = args[0]
        b = int(instruction_decoded[args[1]], 2)
        c = int(instruction_decoded[args[2]], 2)
        self.log.buffer('args 0:{:}, 1:{:}, 2:{:}'.format(a,b,c), level.FINEST)
        for operand in [b, c]:
            if operand not in self._register.keys():
                raise RegisterReferenceException
        result = self._register.get_value(b) * self._register.get_value(c)
        self._register.set_value(a, result)
        return True
Example #5
0
    def testGreaterOrEqual(self, args, instruction_decoded, **named_args):
        """args:list -> bool

        Returns true if a >= b.
        """
        self.log.buffer('testGreaterOrEqual called', level.FINER)
        a = int(instruction_decoded[args[0]], 2)
        b = int(instruction_decoded[args[1]], 2)
        self.log.buffer('args 0:{0}, 1:{1}'.format(a,b), level.FINEST)
        self.log.buffer('returning {0}'.format(self._register.get_value(a) >= self._register.get_value(b)),
                        level.FINEST)
        return self._register.get_value(a) >= self._register.get_value(b)
Example #6
0
    def branchRelative(self, args, instruction_decoded, **named_args):
        """Adds a computed offset to the instruction pointer.

        Values:
            a = int

        Returns True
        """
        self.log.buffer('branchRelative called', level.FINER)
        a = int(instruction_decoded[args[0]], 2, signed=True)
        self.log.buffer('args 0:{0}'.format(a), level.FINEST)
        # add branch delay
        if len(args) > 1:
            b=args[1]
            a = a + b
        pc = self._register.get_pc()
        pc_value = self._register.get_value(pc)
        self.log.buffer('pc is {:}'.format(hex(pc_value)), level.FINER)
        word_space = self._memory.get_word_spacing()
        self.log.buffer('word-space is {:}'.format(word_space), level.FINEST)
        index = named_args['branch_offset']
        a = a - index
        a = a * word_space
        self.log.buffer('increment is {:}'.format(a), level.FINEST)
        a = pc_value + a
        self._register.set_value(pc, a)
        return True
Example #7
0
 def __concatenate_instruction(self, part_0, part_1):
     part_0 = bin(part_0, self._size)
     part_1 = bin(part_1, self._size)
     self._log.buffer(self, "concatenating {:} and {:}"
                      .format(part_0[2:], part_1[2:]), level.FINEST)
     instruction = part_0[2:] + part_1[2:]
     return int(instruction, 2)
Example #8
0
 def copyRegister(self, args, instruction_decoded, **named_args):
     self.log.buffer('copyRegister called', level.FINER)
     if args[0] in instruction_decoded.keys():
         a = int(instruction_decoded[args[0]], 2)
     else:
         a = args[0]
     if args[1] in instruction_decoded.keys():
         b = int(instruction_decoded[args[1]], 2)
     else:
         b = args[1]
     #a = args[0]
     #b = instruction_decoded[args[1]]
     self.log.buffer('args 0:{:}, 1:{:}'.format(a, b), level.FINEST)
     value = self._register.get_value(a)
     self._register.set_value(b, value)
     return True
Example #9
0
 def _decode_register_reference(self, value, instruction_decoded):
     try:
         # Assume we are looking at an instruction that has
         # a register number encoded in some field at index
         value = int(instruction_decoded[value], 2)
     except: pass
     # Assume it is an integer value
     return value
Example #10
0
    def addImmediate(self, args, instruction_decoded, **named_args):
        """Adds a register to an immediate value and stores the
        result in a second register.

        addImmediate performs twos complement arithmetic, so
        the value stored as a result of -1 + -1 will be 0xfffffffe.

        For unsigned calculations, use addImmediateUnsigned.

        Arguments:
            Args 1 and 2 should be the numbers of registers.
            args[0]:int (register)
            args[1]:int (register)
            args[2]:int (immediate)

        State changed:
             register[a]['value'] <- register[b]['value'] + c:int

        Returns:
            Always returns True

        Raises:
            RegisterReferenceException
        """
        self.log.buffer('addImmediate called', level.FINER)
        a = self._decode_register_reference(args[0], instruction_decoded)
        b = self._decode_register_reference(args[1], instruction_decoded)
        # This will be a signed immediate value.
        c = int(instruction_decoded[args[2]], 2, signed=True)
        self.log.buffer('args 0:{0}, 1:{1}, 2:{2}'.format(a, b, c),
                        level.FINEST)
        for operand in [a, b]:
            if operand not in self._register.keys():
                raise RegisterReferenceException
        # Convert to binary to get the correct 2's comp value.
        b_size = self._register.get_size(b)
        bin_bvalue = bin(self._register.get_value(b), size=b_size)
        bvalue = int(bin_bvalue[2:], 2, signed=True)
        #result = int(bin(self._register.get_value(b))[2:], 2, signed=True)
        result = bvalue + c
        # Need size of a, the register to be written to, for correct sign.
        size = self._register.get_size(a)
        result = int(bin(result, size), 2)
        self.log.buffer('result is {0}'.format(result), level.FINEST)
        self._register.set_value(a, result)
        return True
Example #11
0
 def incrementPc(self, args, instruction_decoded, **named_args):
     """args:list -> True"""
     self.log.buffer('incrementPc called', level.FINER)
     a = int(instruction_decoded[args[0]], 2)
     pc=self._register.get_pc()
     value=self._register.get_value(pc)+a
     self._register.set_value(pc, value)
     return True
Example #12
0
 def convert(self, lines):
     try:
         for i in range(len(lines)):
             lines[i] = int(lines[i], 2)
     except:
         raise DataConversionFromUnknownType(
             'Tried to convert from unknown type: {0} {1}'
             .format(lines[i], type(lines[i])))
     return lines
Example #13
0
    def setBitInRegister(self, args, instruction_decoded, **named_args):
        """Sets one bit in a register value to on or off.

        Description:
            (register:str, bit:int, value:int) -> return:bool

        Purpose:
            Can be used to alter registers which are commonly bit-stuffed,
            like the [E]FLAGS register of 808x ISAs.

            This call is not expected to read an instruction, so it is best
            used to generate the results of other operations, for example
            setting a carry flag as the result of an addition.

        Restrictions:
            If the register does not contain a bit_n, the result of this
            call is undefined. Registers are padded with zeros depending
            on their size specified in the ISA. This means a decimal value
            of 10 in an 0 bit register will be treated as 0b00001010.

            If the call does not contain a '0' or '1' value in the `value'
            field, the result of this call is undefined.

        Exceptions:
            This call has undefined behaviour and may not handle exceptions
            raised in the event of error.

        Returns:
            Always returns True
        """
        self.log.buffer('setBitInRegister called', level.FINER)
        a = args[0]
        b = int(args[1])
        c = str(args[2])
        self.log.buffer('args 0:{:}, 1:{:}, 2:{:}'.format(a, b, c), level.FINEST)

        a_size = self._register.get_size(a)

        value = list(bin(self._register.get_value(a), a_size)[2:])
        value[b] = c
        value = int(''.join(value), 2)
        self._register.set_value(a, value)

        return True
Example #14
0
    def addRegisters(self, args, instruction_decoded, **named_args):
        """Adds two registers and stores the result in a third.

        Args:
            Each argument should be the number of a register.
            args[0]:int (result)
            args[1]:int (operand)
            args[2]:int (operand)

        State changed:
            register[a]['value'] <-
                register[b]['value'] + register[c]['value']

        Returns:
            Always returns True

        Raises:
            RegisterReferenceException
        """
        self.log.buffer('addRegisters called', level.FINER)
        a = self._decode_register_reference(args[0], instruction_decoded)
        b = self._decode_register_reference(args[1], instruction_decoded)
        c = self._decode_register_reference(args[2], instruction_decoded)
        self.log.buffer('args 0:{0}, 1:{1}, 2:{2}'.format(a,b,c),
                        level.FINEST)
        for operand in [a, b, c]:
            if operand not in self._register.keys():
                raise RegisterReferenceException
        b_size = self._register.get_size(b)
        c_size = self._register.get_size(c)
        # We want 2's comp values for b and c...
        bin_bvalue = bin(self._register.get_value(b), size=b_size)
        bin_cvalue = bin(self._register.get_value(c), size=c_size)
        bvalue = int(bin_bvalue[2:], 2, signed=True)
        cvalue = int(bin_cvalue[2:], 2, signed=True)
        result = bvalue + cvalue
        # ... and we want to store the result as a signed number.
        a_size = self._register.get_size(a)
        # NB: we don't use signed arg to give correct 2's comp result
        result = int(bin(result, a_size), 2)
        self.log.buffer('result is {0}'.format(result), level.FINEST)
        self._register.set_value(a, result)
        return True
Example #15
0
    def loadWord32(self, args, instruction_decoded, **named_args):
        """args:list -> True

        Loads a word from memory.

        Args:
            args[0]:int (target)
            args[1]:int (memory offset)

        State changed:
            register[a]['value'] <- memory[b]

        Returns:
            Always returns True
        """
        self.log.buffer('loadWord32 called', level.FINER)
        a = int(instruction_decoded[args[0]], 2)
        b = int(instruction_decoded[args[1]], 2)
        c = int(instruction_decoded[args[2]], 2)
        self.log.buffer('args 0:{:}, 1:{:}, 2:{:}'.format(a,b,c), level.FINEST)
        offset=int(c)+self._register.get_value(int(b))
        word = self._memory.get_word(offset, 32)
        self._register.set_value(int(a), word)
        self.log.buffer('loading {:} into {:} from {:}'.format(word,a,offset),
                        level.FINEST)
        return True
Example #16
0
    def storeWord32(self, args, instruction_decoded, **named_args):
        """args:list -> True

        Loads a word from memory.

        Args:
            args[0]:int (register)
            args[1]:int (target)

        State changed:
            memory[b] <- register[a]['value']

        Returns:
            Always returns True
        """
        self.log.buffer('storeWord32 called', level.FINER)
        a = int(instruction_decoded[args[0]], 2)
        b = int(instruction_decoded[args[1]], 2)
        c = int(instruction_decoded[args[2]], 2)
        self.log.buffer('args 0:{:}, 1:{:}, 2:{:}'.format(a,b,c), level.FINEST)
        value=self._register.get_value(int(a))
        offset=int(c)+self._register.get_value(int(b))
        self._memory.set_word(offset, value, 32)
        self.log.buffer('storing {:} in {:}'.format(value, hex(offset)),
                        level.FINEST)
        return True
Example #17
0
    def remRegisters(self, args, instruction_decoded, **named_args):
        """args:list -> True

        Divides two registers and stores the remainder in a third.

        Args:
            Each argument should be the number of a register.
            args[0]:int (result)
            args[1]:int (operand)
            args[2]:int (operand)

        State changed:
            register[a]['value'] <-
                register[b]['value'] % register[c]['value']

        Returns:
            Always returns True

        Raises:
            ArithmeticError
            RegisterReferenceException
        """
        self.log.buffer('remRegisters called', level.FINER)
        try:
            a = int(instruction_decoded[args[0]], 2)
        except:
            a = args[0]
        b = int(instruction_decoded[args[1]], 2)
        c = int(instruction_decoded[args[2]], 2)
        self.log.buffer('args 0:{:}, 1:{:}, 2:{:}'.format(a,b,c), level.FINEST)
        if self._register.get_value(c) == 0:
            raise ArithmeticError
        for operand in [b, c]:
            if operand not in self._register.keys():
                raise RegisterReferenceException
        result = self._register.get_value(b) % self._register.get_value(c)
        self._register.set_value(a, result)
        return True
Example #18
0
 def systemCall(self, args, instruction_decoded, **named_args):
     """args:list -> True"""
     self.log.buffer('systemCall called', level.FINER)
     system_call = SystemCall()
     try:
         if args[0][:3] == 'DIR':
             a = int(args[0][3:], 16)
             result = a
     except:
         a = args[0]
         result = self._register.get_value(a)
     self.log.buffer('args 0:{0}'.format(a), level.FINEST)
     system_call.service(result)
     return True
Example #19
0
    def __decode(self, index):
        # Data required to decode instruction
        #Format-related data
        bit_ranges  = self._isa.get_format_bit_ranges()
        cycles      = self._isa.get_format_cycles()
        # Instruction-related data
        signatures  = self._isa.getSignatures()
        mappings    = self._isa.get_instruction_to_format_map()

        # Get the instruction to decode
        instruction = bin(self._pipeline[index][0],self._size)[2:]
        self._log.buffer(self, "decoding {0}".format(instruction), level.FINER)

        # The following block identifies the instruction being decoded.
        # It tells us the instruction's format, signature and the number
        # of parts it was broken into.
        test={}
        # Test each type of instruction
        for format_type in bit_ranges:
            # against each of the relevant signatures.
            for signature in signatures:
                # Do no work at all if the instruction is obviously
                # not a candidate.
                if format_type in mappings[signature]:
                    test.clear()

                    # We might have to deal with a multi-field signature.
                    for field in signatures[signature]:
                        start= bit_ranges[format_type][field][0]
                        end  = bit_ranges[format_type][field][1]+1
                        test[field]=int(instruction[start:end],2)

                    if test == signatures[signature]:
                        number_of_parts = cycles[format_type]
                        self._log.buffer(self, "decoded `{0}' type instruction, {1}"
                                         .format(format_type, signature),
                                         level.FINER)
                        return (format_type, signature, number_of_parts)
Example #20
0
    def _encode(self, lines):
        """Takes a list of assembly instructions (with decoded identifiers)
        and returns a list of binary machine instructions.

        Description:
            [lines:str]:list -> [lines:str]:list

            Once an assembly program has been through the linker and all
            the identifiers (label references) have been replaced with
            numerical values, the encoder can convert the instruction
            to binary using instruction and format data from the config.

        Purpose:
            Encodes assembly instructions as binary: the final step in
            converting an assembly program into machine code.

            Encoding gurantees that instruction syntax is correct and
            that identifiers and register references are valid.

        Restrictions:
            The result of processing identifiers which have not been
            converter is undefined.

        Exceptions:
            Raises:
                BadInstructionOrSyntax

        Returns:
            A list of binary manchine instructions.
        """

        self.log.buffer("entering encoder", level.FINER)
        # We will return output and use instruction_fields to build up
        # each instruction.
        output             = []
        instruction_fields = {}
        for line in lines:
            #
            # Here we will read the instruction on each line, try to fetch
            # a regular expression for it, and split it into groups.
            #
            instruction = line.split()[0]
            if instruction in self._format_mappings:
                syntax     = self._instruction_syntax[instruction]
                expression = '^' + syntax['expression'] + '$'
                self.log.buffer("matching `{0}' instruction"
                                .format(instruction), level.FINER)
                match = re.search(expression, line)
                if match:
                    # Here we are looping over fields in the instruction
                    # format and determining their values.
                    for i in range(len(match.groups())):
                        field = syntax['symbols'][i][0]
                        value = match.groups()[i]

                        # This block deals with the possibility that the
                        # symbol is a hex number.
                        if value not in self._registers:
                            try:
                                if value[:2] == '0x':
                                    value = int(value, 16)
                                elif value.endswith(self._hex_pattern):
                                    value = value.replace(self._hex_pattern, '')
                                    value = int(value, 16)
                                else:
                                    value=int(value)
                            except:
                                line = "`" + line + "'"
                                raise BadInstructionOrSyntax(
                                    "{:} on line {:}:Non-ref or digit.\n{:}"
                                    .format(BAD, i+1, lines[i]))
                        # We have identified the field. Log it...
                        self.log.buffer("`{0}' is {1}"
                                        .format(field, value), level.FINEST)
                        # ...and add it to the instruction.
                        instruction_fields[field] = value

                    # This block adds the preset field values.
                    values = self._instruction_values[instruction]
                    for field in values:
                        instruction_fields[field] = values[field]
                        self.log.buffer("`{0}' is {1}"
                                        .format(field, values[field]),
                                        level.FINEST)

                    #print("instruction: {:}".format(instruction_fields))


                    # Here we binary-encode the instruction.
                    format_name = self._format_mappings[instruction]
                    fetch_cycles = self._isa.get_format_cycles()[format_name]
                    instruction_length = self._isa_size * fetch_cycles
                    # Creates a list of 0s which we can edit to match the
                    # instruction.
                    instruction_raw = instruction_length * '0'.split()
                    for field in instruction_fields:
                        start = self._format_properties[format_name][field][0]
                        end   = self._format_properties[format_name][field][1]+1
                        # If the value is a register reference, encode the
                        # register number, otherwise encode literal.
                        if instruction_fields[field] in self._registers:
                            value = self._registers[instruction_fields[field]]
                        else:
                            value = instruction_fields[field]
                        # Now insert the encoded field into the instruction.
                        width = end - start
                        value = bin(value, size = width)[2:]
                        instruction_raw[start:end] = value
                        self.log.buffer("{:}:{:} is {:}"
                                        .format(start, end, value),
                                        level.FINEST)

                    # Finally convert the instruction from a list to a string.
                    instruction_raw = "".join(instruction_raw)
                    # Bon.
                    self.log.buffer("encoded {0}".format(instruction_raw),
                                    level.FINER)

                    # Split the instruction if it spans multiple words.
                    # eg. 8085 Direct Addressing uses three 8 bit parts
                    # despite being an 8 bit ISA.
                    self.log.buffer("splitting into {:}-bit chunks"
                                    .format(self._isa_size),
                                    level.FINER)
                    start = 0
                    end   = 1
                    for i in range(len(instruction_raw)):
                        if end % self._isa_size == 0:
                            part = instruction_raw[start:end]
                            # Log entry is indented for readability.
                            self.log.buffer(
                                "  split {:}".format(part),
                             level.FINER)
                            output.append(part)
                            start = end
                        end = end + 1
                    #output.append(instruction_raw)
                else:
                    raise BadInstructionOrSyntax(
                        "{:} on line {:}:\n{:}"
                        .format(BAD, i+1, lines[i]))
            # TODO: Keep this block under review. Probably kept for a reason.
            #(2011-08-18)
            #elif instruction in self._special_instructions:
                #
                #we aren't dealing with specials yet
                #this will probably come into play with assembler directives
                #
                #output.append(instruction)
                #pass
            else:
                raise BadInstructionOrSyntax(
                    "{:} on line {:}:\n{:}"
                    .format(BAD, i+1, lines[i]))
            instruction_fields.clear()
        self.log.buffer("leaving encoder", level.FINER)
        return output
Example #21
0
    def __execute(self, index):
        # A dict to hold the encoded instruction parts.
        self._pipeline[index].append({})

        # Data on the instruction format so we can decode properly.
        format_sizes      = self._isa.get_format_sizes()
        format_properties = self._isa.get_format_bit_ranges()

        # Instruction data to operate on.
        instruction_type   = self._pipeline[index][1]
        instruction_name   = self._pipeline[index][2]

        # Particularly in the case of multi-part instructions, we need
        # to ensure the correct length binary is formed. We will use the
        # format size property to achieve this.
        size = format_sizes[instruction_type]
        self._log.buffer(self, "reading {:}b {:} instruction"
                         .format(size, instruction_name), level.FINER)

        # Finally, translate the instruction into a binary representation.
        instruction_binary = bin(self._pipeline[index][0], size)[2:]

        # Begin the execution by decoding each bit-field.
        for field in format_properties[instruction_type]:
            start = format_properties[instruction_type][field][0]
            end   = format_properties[instruction_type][field][1]+1
            self._pipeline[index][3][field] = instruction_binary[start:end]
            self._log.buffer(self, "`{:}' is {:} ({:})"
                             .format(field,
                                     instruction_binary[start:end],
                                     int(instruction_binary[start:end], 2)),
                             level.FINEST)

        self._log.buffer(self, "executing {:} ({:})"
                         .format(instruction_binary, instruction_name),
                         level.FINER)

        # This next step deals with the actual state change[s] by making
        # calls to the API.
        implementation = self._isa.getImplementation()
        name           = self._pipeline[index][2]
        # The branch offset is used to calculate the address of jump
        # instructions.
        branch_offset  = index

        if self.__special_flags['increment']:
            branch_offset = branch_offset + 1

        # We also need to consider the number of fetch cycles that have
        # passed and add them to the offset calculation.
        cycles = self._isa.get_format_cycles()[instruction_type] - 1
        if cycles:
            branch_offset = branch_offset + cycles
        # If an API call returns false, the sequential flag will block
        # the next call. This is used to evaluate tests.
        sequential = True
        for method in implementation[name]:
            if sequential:
                call = getattr(self._api, method[0])
                args = method[1]
                self._log.buffer(self, "calling {0} with {1}"
                                 .format(call.__name__, args), level.FINER)
                sequential = call(args,
                                  self._pipeline[index][3],
                                  branch_offset=branch_offset)
            else:
                self._log.buffer(self, 'skipping an API call', level.FINEST)
                sequential = True
        if 'EI' in self._pipeline_flags:
            self._registers.increment(self._pc, self._word_space)
            self.__special_flags['increment'] = True