Esempio n. 1
0
    def _compile(self) -> Memory:
        """
        Fills .bytecode field of IRElements in self._intermediate,
        returns memory block with whole source bytecode
        """
        curr_ip = 0  # instruction pointer value at the point of running current op
        mem = ExtendableMemory(self._char_bit)

        for line in self._intermediate:
            try:
                logging.debug('compile: %s', line.source)
                if not line.statement:
                    continue

                prev_ip = curr_ip

                if isinstance(line.statement, Data):
                    for value in line.statement.values:
                        mem.append(self._resolve_expression(value),
                                   line.statement.datatype, Endianness.Big)
                elif isinstance(line.statement, Instruction):
                    op = line.statement.operation
                    curr_ip = len(mem) + op.size_bytes

                    mem.append(op.opcode, DataType.from_fmt('b'),
                               Endianness.Little)

                    if len(line.statement.args.arguments) != len(op.arg_def):
                        raise SyntaxError(
                            'invalid number of arguments for operation %s: expected %d, got %d'
                            % (op.mnemonic, len(op.arg_def),
                               len(line.statement.args.arguments)))

                    for idx, arg in enumerate(line.statement.args.arguments):
                        arg_datatype = DataType.from_fmt(op.arg_def[idx])

                        if isinstance(arg, Register):
                            mem.append(arg.value, arg_datatype,
                                       op.args_endianness)
                        else:
                            val = self._resolve_expression(arg)
                            mem.append(self._resolve_expression(arg),
                                       arg_datatype, op.args_endianness)
                else:
                    raise AssertionError('unhandled IR type: %s' %
                                         type(line.statement).__name__)

                curr_ip = len(mem)
                line.bytecode[:] = mem[prev_ip:]
            except Exception as err:
                raise Exception('could not assemble line: %s' %
                                (line.source, )) from err

        return mem
Esempio n. 2
0
    def _resolve_expression(self,
                            expr: Expression,
                            already_resolved: Set[str] = None) -> int:
        logging.debug('%s = ?' % (expr, ))
        if not already_resolved:
            already_resolved = set()

        if isinstance(expr, NumericExpression):
            logging.debug('NumericExpression: %d' % expr.value)
            return expr.value
        elif isinstance(expr, CharacterExpression):
            logging.debug('CharacterExpression: %d' % ord(expr.value))
            return ord(expr.value)
        elif isinstance(expr, ConstantExpression):
            if expr.name in already_resolved:
                raise ValueError('circular constant definition: %s' %
                                 expr.name)
            val = self._constants[expr.name]
            if not isinstance(val, int):
                val = self._resolve_expression(
                    self._constants[expr.name],
                    already_resolved | set(expr.name))
                self._constants[expr.name] = val
            else:
                logging.debug('alredy resolved: %s = %s' % (expr.name, val))
            logging.debug('ConstantExpression %s' % (val, ))
            return val
        elif isinstance(expr, UnaryExpression):
            logging.debug('UnaryExpression: %s' % (expr, ))
            if expr.operator == 'sizeof':
                assert isinstance(expr.operand, ConstantExpression)
                try:
                    return DataType.from_fmt(expr.operand.name).size_bytes
                except KeyError:
                    return CPU.OPERATIONS_BY_MNEMONIC[
                        expr.operand.name].size_bytes
            elif expr.operator == 'alignof':
                assert isinstance(expr.operand, ConstantExpression)
                return DataType.from_fmt(expr.operand.name).alignment
            else:
                return eval(expr.operator +
                            str(self._resolve_expression(expr.operand)))
        elif isinstance(expr, BinaryExpression):
            logging.debug('BinaryExpression: %s' % (expr, ))
            return eval(
                str(self._resolve_expression(expr.lhs)) +
                expr.operator.replace('/',
                                      '//')  # TODO: hack for integer division
                + str(self._resolve_expression(expr.rhs)))
        else:
            raise AssertionError('unknown expression type: %r' % (expr, ))
Esempio n. 3
0
class Data(NamedTuple, Statement):
    """ db/a/w ARGUMENT_LIST """
    datatype: DataType
    values: ArgumentList

    DATATYPES = {
        'db': DataType.from_fmt('b'),
        'da': DataType.from_fmt('a'),
        'dw': DataType.from_fmt('w'),
    }

    @staticmethod
    def build(tokens: List[str]):
        return Data(Data.DATATYPES[tokens[0]],
                    ExpressionList.build(tokens[1:]))
Esempio n. 4
0
    def pop(cpu: 'CPU', reg: int):
        """
        pop - POP value from data stack into register

        reg = word ptr $RAM[SP]
        SP += sizeof_word
        """
        cpu.registers[Register(reg)] = cpu.ram.get_fmt('w', cpu.registers.SP)
        cpu.registers.SP += DataType.from_fmt('w').size_bytes
Esempio n. 5
0
    def push(cpu: 'CPU', reg: int):
        """
        push - PUSH register onto data stack

        SP -= sizeof_word
        word ptr $RAM[SP] = reg
        """
        cpu.registers.SP -= DataType.from_fmt('w').size_bytes
        cpu.ram.set_fmt('w', cpu.registers.SP, cpu.registers[Register(reg)])
Esempio n. 6
0
    def ret(cpu: 'CPU'):
        """
        ret - RETurn from subroutine

        IP = addr ptr $CALL_STACK[RP]
        RP += sizeof_addr
        """
        addr_size = DataType.calcsize('a')
        cpu.registers.IP = cpu.call_stack.get_fmt('a', cpu.registers.RP)
        cpu.registers.RP += addr_size
Esempio n. 7
0
 def __str__(self):
     return ('--- REGISTERS ---\n'
             '%s\n'
             '--- PROGRAM ---\n'
             '%s\n'
             '--- RAM ---\n'
             '%s\n'
             '--- CALL_STACK ---\n'
             '%s\n' %
             (self.registers, self.program, self.ram,
              self.call_stack.make_dump(DataType.from_fmt('a').alignment)))
Esempio n. 8
0
    def call_r(cpu: 'CPU', reg: int):
        """
        call.r addr - CALL subroutine, Register

        RP -= sizeof_addr
        addr ptr $CALL_STACK[RP] = IP
        IP = reg
        """
        addr_size = DataType.calcsize('a')
        cpu.registers.RP -= addr_size
        cpu.call_stack.set_fmt('a', cpu.registers.RP, cpu.registers.IP)
        cpu.registers.IP = cpu.registers[Register(reg)]
Esempio n. 9
0
    def call(cpu: 'CPU', addr: int):
        """
        call addr - CALL subroutine

        RP -= sizeof_addr
        addr ptr $CALL_STACK[RP] = IP
        IP = addr
        """
        addr_size = DataType.calcsize('a')
        cpu.registers.RP -= addr_size
        cpu.call_stack.set_fmt('a', cpu.registers.RP, cpu.registers.IP)
        cpu.registers.IP = addr
Esempio n. 10
0
    def rand(cpu: 'CPU'):
        """
        rand - put a random WORD in A

        A = random()
        """
        num_bytes = DataType.calcsize('w')
        value = 0
        for _ in range(num_bytes):
            value *= 2**cpu.ram.char_bit
            value += random.randint(0, 2**cpu.ram.char_bit)

        cpu.registers.A = value
        cpu._set_flags(cpu.registers.A)
Esempio n. 11
0
 def args_size(self) -> int:
     """ Size (in bytes) of this operation arguments, without the opcode """
     return DataType.calcsize(self.arg_def)
Esempio n. 12
0
    '-A',
    '--addr-alignment',
    type=int,
    default=None,
    help='Address memory alignment. By default, equal to address size.')
parser.add_argument(
    '-H',
    '--halt-after-instructions',
    type=int,
    default=None,
    help='Halts VM after executing specific number of instructions.')

args = parser.parse_args()

DataType._TYPES['w'] = DataType(name='w',
                                size_bytes=args.word_size,
                                alignment=(args.word_alignment
                                           or args.word_size))
DataType._TYPES['a'] = DataType(name='a',
                                size_bytes=args.addr_size,
                                alignment=(args.addr_alignment
                                           or args.addr_size))

with open(args.source[0]) as infile:
    asm = Assembler(char_bit=args.char_bit)
    if args.program_size is None:
        MEMORY_BLOCKS['program'] = asm.assemble_to_memory(infile.read())
    else:
        MEMORY_BLOCKS['program'] = Memory(char_bit=args.char_bit,
                                          value=asm.assemble(infile.read()),
                                          size=args.program_size)