Esempio n. 1
0
    def __init__(self, program, hardware_config, output_file_name):
        '''
        '''
        self.memory_size = 4096 # bytes
        self.insns = [] # instructions.
        self.builder = Translator(self.memory_size, self.insns)
        self.zero_register = 0
        self.sp_register = 62 # register that contains stack pointer value
        self.pc_return_register = 61 # pc to return to after its done.
        self.hp_register_no = 63 # address of heap pointer.
        self.function_begin = {}  # which insn # does function begin?
        self.function_calls = []  # which function is being called where?
        self.output_file_name = output_file_name
        self.program = program

        # some special instructions.

        # set register 0 to zero pointer
        self.builder.set_int(self.zero_register, 0)
        # set stack pointer to memory size
        self.builder.set_int(self.sp_register, self.memory_size)
        # set pc return register
        self.builder.set_int(self.pc_return_register, 0)

        hp_index = len(self.insns)
        self.builder.set_int(self.hp_register_no, 0)
        for function in program.functions:
            self.function_begin[function.name] = len(self.insns)
            self.spit_function(function)

        for index, name in self.function_calls:
            self.builder.jump_and_link_set(index, immediate=self.function_begin[name]*4)

        # heap begins right after end of insns.
        self.builder.set_int_set(hp_index, register_no=None, value=len(self.insns)*4)
        # now convert all insns into
        self.write_insns(output_file_name)
Esempio n. 2
0
class Converter(object):
    '''
    Read objects and spit out bytecode.

    '''
    def __init__(self, program, hardware_config, output_file_name):
        '''
        '''
        self.memory_size = 4096 # bytes
        self.insns = [] # instructions.
        self.builder = Translator(self.memory_size, self.insns)
        self.zero_register = 0
        self.sp_register = 62 # register that contains stack pointer value
        self.pc_return_register = 61 # pc to return to after its done.
        self.hp_register_no = 63 # address of heap pointer.
        self.function_begin = {}  # which insn # does function begin?
        self.function_calls = []  # which function is being called where?
        self.output_file_name = output_file_name
        self.program = program

        # some special instructions.

        # set register 0 to zero pointer
        self.builder.set_int(self.zero_register, 0)
        # set stack pointer to memory size
        self.builder.set_int(self.sp_register, self.memory_size)
        # set pc return register
        self.builder.set_int(self.pc_return_register, 0)

        hp_index = len(self.insns)
        self.builder.set_int(self.hp_register_no, 0)
        for function in program.functions:
            self.function_begin[function.name] = len(self.insns)
            self.spit_function(function)

        for index, name in self.function_calls:
            self.builder.jump_and_link_set(index, immediate=self.function_begin[name]*4)

        # heap begins right after end of insns.
        self.builder.set_int_set(hp_index, register_no=None, value=len(self.insns)*4)
        # now convert all insns into
        self.write_insns(output_file_name)


    def write_insns(self, output_file_name):
        def function_key(item):
            return item[0]
        functions = [(number, name) for name, number in self.function_begin.iteritems()]
        functions.sort(key=function_key)

        current_no, current_name = functions.pop(0)
        assf = open(output_file_name + '.ass', 'w')
        binf = open(output_file_name + '.bin', 'w')
        for index, insn in enumerate(self.insns):
            binf.write(write_insn(insn))
            if index == current_no:
                text = current_name + ": "
                if len(functions) > 0:
                    current_no, current_name = functions.pop(0)
            else:
                text = ""
            assf.write(text + write_ass(insn))
        binf.close()
        assf.close()


    def spit_function(self, function):
        '''
        stack contains:
        1. outputs
        2. inputs
        3. return address
        '''
        logging.debug("spitting function: {0}".format(function.name))
        # print a single function
        builder = self.builder
        block_stack = BlockStack()
        inputs = function.inputs
        outputs = function.outputs
        local_vars = function.local_variables

        return_pc = Variable(get_type('int'), 'return_pc')
        for input in outputs+inputs+[return_pc]+local_vars:
            block_stack.new_variable(input)


        # write code now
        self.write_code_block(block_stack, function)

        # return to some address.
        #offset = block.variables['return_pc']['offset']
        #self.set_offset_address(4, offset, 3)
        builder.jump(self.pc_return_register)
        logging.debug("spitting function done: {0}".format(function.name))

    def write_code_block(self, block_stack, code_block):
        for chunk in code_block.code:
            if isinstance(chunk, Expression):
                self.spit_expression(block_stack, chunk)
            elif isinstance(chunk, Statement):
                self.spit_statement(block_stack, chunk)
            elif isinstance(chunk, While):
                self.spit_while(block_stack, chunk)
            elif isinstance(chunk, If):
                self.spit_if(block_stack, chunk)
            elif isinstance(chunk, ElIf):
                self.spit_elif(block_stack, chunk)
            elif isinstance(chunk, Else):
                self.spit_else(block_stack, chunk)
            else:
                raise Exception("Don't know what to do with: ", chunk)



    def spit_expression(self, block_stack, expression):
        '''
        Allocates space for return types.
        Perform the operation. at the end,
        block offset will be returned to what it was.
        After finish,
        The "return value" starts just below the block offset.
        '''
        # perform operation and store in temporary variable
        #self.builder.store_short(vars[exp.dest], exp.ex
        # 1 level expression
        logging.debug("spitting expression: {0}".format(expression))
        return_types = expression.get_types()
        builder = self.builder
        return_vars = {}
        block_begin_offset = block_stack.offset

        for count, return_type in enumerate(return_types):
            # make room for return value
            block_stack.offset -= POINTER_SIZE
            return_var = {
                'variable': Variable(return_type, count),
                'offset': block_stack.offset
            }
            return_vars[count] = return_var

        data = expression.data
        if isinstance(data, Constant):
            # setting to constant or variable
            dest_offset = return_vars[0]['offset']
            self.set_offset_address(4, dest_offset, 3) # 4 has addr of dest+offset
            builder.store_int(4, self.hp_register_no)  # store address on hp_register_no to dest.
            # constant. store to 4 (destination)
            # create a location for 4.
            # TODO: currently only handle integers
            builder.store_inti(self.hp_register_no, data.value, 5)
            builder.add_inti(self.hp_register_no, self.hp_register_no, data.type.size, 6)

        elif isinstance(data, DottedName):
            # first get the source address
            temp_reg = 6
            variable_dict = block_stack.get_variable(data)
            variable_offset = variable_dict['offset']

            self.set_offset_address(5, variable_offset, 3)
            #builder.load_int(7,5)  # reg 7 has pointer value.
            get_offset(data.tokens, variable_dict['variable'].type, 5, temp_reg, 7, builder)

            # now get destination offset
            dest_offset = return_vars[0]['offset']
            self.set_offset_address(4, dest_offset, 3) # 4 has addr of dest+offset
            # copy from 5 to 4.
            builder.copy(4, 5, POINTER_SIZE, 7)

        elif isinstance(data, str):
            # has children.
            # if necessary, allocate additional space for intermediary.
            # so run them first.
            children = expression.children
            for child in children:
                self.spit_expression(block_stack, child)
                # need to save the child somewhere.
                child_return_types = child.get_types()
                for child_type in child_return_types:
                    block_stack.offset -= child_type.size

            # operator or string
            if data in OPERATORS:
                if len(return_vars) != 1:
                    raise Exception("operation returns 1 value, but returns: {0}".format(len(return_vars)))
                # operators return only one thing. assume 2 return values.
                dest_offset = return_vars[0]['offset']
                self.set_offset_address(4, dest_offset, 3) # 4 has addr of dest_offset
                self.set_offset_address(5, dest_offset-POINTER_SIZE, 3) # 5 has address of operand one
                self.set_offset_address(6, dest_offset - 2*(POINTER_SIZE), 3) # 6 has address of operand two

                builder.load_int(10, 5)
                builder.load_int(8, 10)
                builder.load_int(11, 6)
                builder.load_int(9, 11)
                if data == '+':
                    builder.add_int(7, 8, 9)
                elif data == '-':
                    builder.subtract_int(7,8,9)
                elif data == '!=':
                    builder.set_on_ne(7,8,9, 10, 11)
                elif data == '==':
                    builder.set_on_e(7,8,9, 10, 11)
                else:
                    raise Exception("Unknown operator: ", data)
                builder.store_int(4, self.hp_register_no) # store result in 4
                builder.store_int(self.hp_register_no, 7) # store result in heap
                var_size = return_vars[0]['variable'].type.size
                builder.add_inti(self.hp_register_no, self.hp_register_no, var_size, 12)


            elif self.program.get_struct(data) is not None:

                # a struct constructor. then we don't need to do anything
                size = self.program.get_struct(data).size
                dest_offset = return_vars[0]['offset']
                self.set_offset_address(4, dest_offset, 3) # 4 has addr of dest_offset
                builder.add_inti(self.hp_register_no, self.hp_register_no, size, 6)


            else:
                # call function. Note we already allocated space for the 
                # output (return_vars) and input (child_return_types).
                # save return register on stack, because the child is going to use it now.
                dotted_name= DottedName(['return_pc'])
                return_pc_offset = block_stack.get_variable(dotted_name)['offset']
                self.set_offset_address(3, return_pc_offset, 4)
                builder.store_int(3, self.pc_return_register)

                # set stack pointer to offset
                builder.subtract_inti(self.sp_register, self.sp_register, block_begin_offset *-1, 3)

                self.call_function(data)

                # call function changed the stack pointer, so change it back
                builder.add_inti(self.sp_register, self.sp_register, block_begin_offset * -1, 4)
                # set return address back to return register
                self.set_offset_address(3, return_pc_offset, 4)
                builder.load_int(self.pc_return_register, 3)


        block_stack.offset = block_begin_offset
        logging.debug("spitting expression done")

    def set_offset_address(self, register, offset, worker_register):
        '''
        set worker_register to offset.
        set register = sp - worker_register
        Offset is always <= 0.
        Convert to positive number and subtract.

        '''
        assert offset <= 0
        self.builder.set_int(worker_register, offset*-1)
        self.builder.subtract_int(register, self.sp_register, worker_register)


    def call_function(self, function_name):
        builder = self.builder
        function = self.program.get_function(function_name)
        if not function:
            raise Exception("Unknown function name: {0}".format(function_name))

        self.function_calls.append((len(self.insns), function_name))
        # need to give return pc and jump
        builder.jump_and_link(0, self.pc_return_register, 5)

        # variable setting and calling:
        # stack pointer is at top of function stack. 
        # keep a map of variable name to offset.
        # then add offset to sp and store in register ADDR.
        # set some value to another register VAL.
        # store VAL ADDR. 

    def spit_statement(self, block_stack, statement):
        '''
        Destinations should already be in the stack, so does not
        allocate additional memory (but expressions inside
        probably will use the stack).
        After expression is done, memory is copied from the 
        return values to the destinations.
        '''
        logging.debug("spitting statement: {0}".format(statement))
        builder = self.builder
        destinations = statement.destinations
        expression = statement.expression

        # find the destinations
        for dest in destinations:
            variable = block_stack.get_variable(dest)['variable']
            if not variable:
                raise Exception("didn't find variable %s" % dest)

        self.spit_expression(block_stack, expression)
        return_start = block_stack.offset
        # copy addrs to destinations
        for dest in destinations:
            variable_dict = block_stack.get_variable(dest)
            variable = variable_dict['variable']
            variable_offset = variable_dict['offset']
            self.set_offset_address(8, variable_offset, 9)  # 8 has address of variable on stack.
            get_offset(dest.tokens, variable.type, 8, 10, 11, builder)  # if variable is dotted.
            logging.debug("var_offset: {}".format(variable_offset))
            return_start -= POINTER_SIZE

            self.set_offset_address(5, return_start,6)
            #copy. 8 is the destination. 5 is the source.
            builder.copy(8, 5, POINTER_SIZE, 7)

        logging.debug("spitting statement done. block.offset: %s" % block_stack.offset)

    def _load_condition_result(self, block_stack):
        offset = block_stack.offset - POINTER_SIZE
        addr_reg = 3
        self.set_offset_address(addr_reg, offset, 4) # addr_reg has addr of pointer.
        self.builder.load_int(6, addr_reg) # 6 has value of return value.
        value_reg = 5
        self.builder.load_byte(value_reg, 6)

    def spit_while(self, block_stack, while_cond):
        # if condition met, enter loop, else exit.
        # must clear any unused variables after its done.
        logging.debug("spitting while: {0}".format(while_cond.condition))
        loop_start = len(self.builder.insns)
        self.spit_expression(block_stack, while_cond.condition)

        self._load_condition_result(block_stack)
        loop_end_index = len(self.builder.insns)

        # if condition doesn't hold, exit.
        self.builder.branch_on_z_imm(5, 0, 6)  # temporarily set to 0, later to loop_end

        self.write_code_block(block_stack, while_cond)

        # end loop
        self.builder.jumpi(loop_start*4, 6)
        loop_end = len(self.builder.insns)
        # loop conclusion
        self.builder.branch_on_z_imm_set(loop_end_index, value_reg=None, immediate=loop_end*4, free_reg=None)
        #self.builder.insns[loop_end_index].branch_to = loop_end
        logging.debug("spitting while done")

    def spit_if(self, block_stack, if_cond):
        for variable in if_cond.variables:
            block_stack.new_variable(variable)

        self.spit_expression(block_stack, if_cond.condition)

        # load result of expression into reg 5
        self._load_condition_result(block_stack)

        # branch to next guy
        branch_index = len(self.builder.insns)
        self.builder.branch_on_z_imm(5, 0, 6)

        self.write_code_block(block_stack, if_cond)
        block_end = len(self.builder.insns)
        self.builder.branch_on_z_imm_set(branch_index, value_reg=None, immediate=block_end*4, free_reg=None)

        # pop stack
        for _ in if_cond.variables:
            block_stack.pop_variable()

    def spit_elif(self, block_stack, elif_cond):
        self.spit_if(block_stack, elif_cond)

    def spit_else(self, block_stack, else_cond):
        for variable in else_cond.variables:
            block_stack.new_variable(variable)
        self.write_code_block(block_stack, else_cond)
        for _ in else_cond.variables:
            block_stack.pop_variable()