Example #1
0
def test_lui():
    imm = "00000000000010101010"
    rd = "0" * 5
    instruction = "$imm$rd0110111"
    instruction = instruction.replace("$imm", imm)
    instruction = instruction.replace("$rd", rd)
    exp = "10101010000000000000"

    instr = ISA().instruction_from_bin(instruction, 0)
    assert int(exp, 2) == instr.execute(None)
Example #2
0
def test_auipc():
    imm = "00000000000010101010"
    rd = "0" * 5
    instruction = "$imm$rd0010111"
    instruction = instruction.replace("$imm", imm)
    instruction = instruction.replace("$rd", rd)
    exp_par = "10101010000000000000"
    PC = 24
    exp = int(exp_par, 2) + PC

    instr = ISA().instruction_from_bin(instruction, 0)
    assert exp == instr.execute(PC)
def test_beq():
    rd = "0" * 5
    instruction = "0000000$rs2$rs1000100001100011"
    instruction = instruction.replace("$rs1", rd)
    instruction = instruction.replace("$rs2", rd)
    rs1 = 0b00000000000000000000000000001101  # 13
    rs2 = 0b00000000000000000000000000001011  # 11
    exp = 16

    instr = ISA().instruction_from_bin(instruction, 0)
    assert exp == instr.execute(rs1, rs1)

    assert 4 == instr.execute(rs1, rs2)
Example #4
0
def test_i_instruction_from_binary():
    instruction = "00000000110000011000001000010011"

    res = ISA().instruction_from_bin(instruction, 0)
    assert res.rd == 4
    assert res.rs == 3
    assert res.imm == 12
Example #5
0
def test_i_instruction_from_string():
    instruction = "addi r4, r3, 12"

    res = ISA().instruction_from_str(instruction, None, None)
    assert res.rd == 4
    assert res.rs == 3
    assert res.imm == 12
Example #6
0
def test_sym_reg_names():
    instruction = "add sp, ra, gp"

    res = ISA().instruction_from_str(instruction, None, None)
    assert res.rd == 2
    assert res.rs1 == 1
    assert res.rs2 == 3
Example #7
0
def test_r_instruction_from_binary():
    instruction = "00000000001000011001001000110011"

    res = ISA().instruction_from_bin(instruction, 0)
    assert res.rd == 4
    assert res.rs2 == 2
    assert res.rs1 == 3
Example #8
0
def test_r_instruction_from_string():
    instruction = "add r4, r3, r2"

    res = ISA().instruction_from_str(instruction, None, None)
    assert res.rd == 4
    assert res.rs1 == 3
    assert res.rs2 == 2
def test_MW_step():
    w = MainWindow()

    w.emulators[0].IFQ.put(ISA().instruction_from_str("mul x1, x0, x0", None, 0))
    s1 = w.emulators[0].emulator_instance.get_steps()
    w.emulator_step()

    assert w.emulators[0].emulator_instance.get_steps() > s1, "Emulator did not perform a step"
Example #10
0
    def create_tab_isa(self):
        isa = ISA().ISA
        toolbox = QtWidgets.QToolBox()

        # Lambdas do not preserve context when updating ISA from event signal
        def get_isa_updater(t, i, f):
            def _(v):
                print(t, i, f, v)
                isa[t][i][f] = v

            return _

        for type in isa.keys():
            for inst in isa[type]:
                f = QtWidgets.QFrame()
                f.setLayout(QtWidgets.QFormLayout())

                for inst in isa[type]:
                    f.layout().addRow(inst.upper(), None)

                    op_txt = QtWidgets.QLineEdit()
                    op_txt.setText(isa[type][inst]['exec'])
                    op_txt.textChanged.connect(
                        get_isa_updater(type, inst, 'exec'))
                    f.layout().addRow("Expression:", op_txt)

                    cyc = QtWidgets.QSpinBox()
                    cyc.setMinimum(1)
                    cyc.setValue(isa[type][inst]['clockNeeded'])
                    cyc.valueChanged.connect(
                        get_isa_updater(type, inst, 'clockNeeded'))
                    f.layout().addRow("Clock cycles:", cyc)

                    f.layout().addRow(" ", None)

                scroll = QtWidgets.QScrollArea()
                scroll.setWidgetResizable(True)
                scroll.setWidget(f)

            toolbox.addItem(f, type.upper())

        return toolbox
Example #11
0
    def __init__(self, DM):
        self.DM = DM
        self.ISA = ISA()

        self.syntax_errors = []  # Line numbers for text
        self.unknown_instructions = []  # Instruction indexes for ELF

        self.IM = []  # Instruction Memory
        self.sections = {'.text': 0}
        self.symbol_table = {}
        self.alignment = 4
        self.directives = {
            '.byte': 1,
            '.2byte': 2,
            '.4byte': 4,
            '.8byte': 8,
            '.half': 2,
            '.word': 4,
            '.dword': 8,
            # '.asciz': None,
            # '.string': None,
            # '.zero': None
        }
Example #12
0
class Program:
    def __init__(self, DM):
        self.DM = DM
        self.ISA = ISA()

        self.syntax_errors = []  # Line numbers for text
        self.unknown_instructions = []  # Instruction indexes for ELF

        self.IM = []  # Instruction Memory
        self.sections = {'.text': 0}
        self.symbol_table = {}
        self.alignment = 4
        self.directives = {
            '.byte': 1,
            '.2byte': 2,
            '.4byte': 4,
            '.8byte': 8,
            '.half': 2,
            '.word': 4,
            '.dword': 8,
            # '.asciz': None,
            # '.string': None,
            # '.zero': None
        }

    def get_entry_point(self):
        if '_start' in self.symbol_table:
            return self.symbol_table['_start']['value']
        elif 'main' in self.symbol_table:
            return self.symbol_table['main']['value']
        else:
            return self.sections['.text']

    def load_text(self, text):
        pc = 0
        for l_n, line in enumerate(text.split('\n')):
            line = line.split(';')[0].strip()
            line = line.replace('\t', ' ')

            if line != '':
                if re.match(r'.+:', line):
                    # Label
                    label = re.match(r'.+:', line).group(0)
                    label = label[:-1].lower()
                    self.symbol_table[label] = {
                        'name': label,
                        'value': pc,
                        'size': 0,
                        'section': '.text'
                    }
                    self.last_symbol = label
                elif re.match(r'\.[a-zA-Z0-9]+', line):
                    # Directive
                    try:
                        pc = self.__parse_directive__(line, pc)
                    except SyntaxError as s:
                        self.syntax_errors.append((l_n, line, s))
                else:
                    # Instruction
                    try:
                        inst = self.ISA.instruction_from_str(
                            line, self.symbol_table, pc)
                        self.IM.append(inst)

                        # Load 32 bits into memory
                        for i in range(4):
                            self.DM.store(
                                pc + i,
                                int(inst.to_binary()[8 * i:(8 * i) + 8], 2))
                    except NotImplementedError:
                        self.syntax_errors.append(
                            (l_n, line, "Instruction not yet implemented"))
                    except SyntaxError:
                        self.syntax_errors.append(
                            (l_n, line, "Unknown instruction"))

                    pc += 4

    def __parse_directive__(self, line, pc):
        line = line.split(' ')

        sections = ['.text', '.data', '.rodata', '.bss']
        if line[0] in sections or (line[0] == '.section'
                                   and line[1]) in sections:
            section = line[0] if line[0] in sections else line[1]
            self.sections[section] = pc
        elif line[0] == '.align' or line[0] == '.p2align':
            self.alignment = 2**int(line[1])
        elif line[0] == '.balign':
            self.alignment = int(line[1])
        elif line[0] in self.directives:
            # TODO: store value byte per byte
            dir = self.directives[line[0]]
            val = line[1]

            for offset in range(self.alignment):
                self.DM.store(pc, val)
        elif line[0] == '.zero':
            addr = pc
            while addr < int(line[1]):
                self.DM.store(addr, 0)
                addr += 1
            pc += addr
        elif line[0] == '.string' or line[0] == '.asciz':
            s = line[1][1:-1]  # Remove quotes
            addr = pc

            for c in s:
                self.DM.store(addr, ord(c))
                addr += 1

            pc += addr
        else:
            raise SyntaxError("Unknown directive")

        return pc

    def __iter__(self):
        return iter(self.IM)

    def load_machine_code(self, filename):
        file = ELF(filename)
        file.load_program(self)
        self.unknown_instructions = file.unknown_instructions

    def to_code(self):
        lines = []
        done_sections = []

        for idx, inst in enumerate(self.IM):
            for s in self.sections:
                if self.sections[s] == idx * 4:
                    if s != '.text':  # If not the first line
                        lines.append('')
                    lines.append(s)
                    done_sections.append(s)
            for s in self.symbol_table:
                if self.symbol_table[s][
                        'value'] == idx * 4 and self.symbol_table[s][
                            'section'] == done_sections[-1]:
                    lines.append('')
                    lines.append(s + ':')
            lines.append('    ' + str(inst))

            if idx in self.unknown_instructions:
                self.syntax_errors.append(
                    (len(lines) - 1, str(inst), "Unknown Instruction"))

        for s in self.sections:
            if s not in done_sections:
                lines.append('')
                lines.append(s)
                for sym in self.symbol_table.values():
                    if sym['section'] == s:
                        lines.append(sym['name'] + ":")

                        if sym['size'] == 1:
                            dim = '.byte'
                        elif sym['size'] == 2:
                            dim = '.2byte'
                        elif sym['size'] == 4:
                            dim = '.4byte'
                        elif sym['size'] == 8:
                            dim = '.8byte'
                        else:
                            lines.append('    <no_info>')
                            continue

                        data = []
                        for i in range(sym['size']):
                            addr = self.sections[sym['section']] + sym['value']
                            data.append('{:x}'.format(self.DM.load(addr)))

                        lines.append("    {} 0x{}".format(dim, ''.join(data)))

        return '\n'.join(lines)
def test_to_bin():
    inst = ISA().instruction_from_str(
        'beq x5, x0, 4', None, 0)  # BType_Instruction(1100011, 5, '000', 1, 2)
    assert inst.to_binary() == '00000000010100000000010001100011'
Example #14
0
    def load_program(self, prog):
        print("\nLoading program into memory...")
        next_addr = 0  # If file is relocatable, need to store sections one after the other

        for s in self.sections.values():
            if s.sh_type == 0:  # SHT_NULL
                continue

            print("    {}:".format(s.sh_name))

            # Load in memory
            if s.sh_flags & 0x02 != 0x02:
                print("        ! SHF_ALLOC flag not set, skipping")
                continue
            if s.sh_addr == 0 and self.eheader['e_type'] != 1:  # Not ET_REL (relocatable)
                print("        ! sh_addr is set to 0 and file is not relocatable, skipping")
                continue
            if s.sh_addr == 0:
                s.sh_addr = next_addr
            if s.sh_type == 8:  # SHT_NOBITS, like .bss, doesn't have content
                print("        - sh_type is set to SHT_NOBITS, setting {} bytes to 0x00".format(s.sh_size))
                for offset in range(s.sh_size):
                    prog.DM.store(s.sh_addr + offset, 0x00)
            else:
                self.file.seek(s.sh_offset)
                s.content = self.file.read(s.sh_size)
                for offset, byte in enumerate(s.content):
                    prog.DM.store(s.sh_addr + offset, byte)

            print("        > Loaded {} bytes from {} to {} excluded. (Read from offset {})".format(
                s.sh_size, s.sh_addr, s.sh_addr + s.sh_size, s.sh_offset
            ))
            next_addr += s.sh_size

            # Insert start address in program's section array
            prog.sections[s.sh_name] = s.sh_addr

        # Dump DM
        print("\nData Memory dump (first 128 bytes):")
        bin, hex, ascii = [], [], []
        for addr, val in enumerate(prog.DM):
            if addr >= 128:
                break
            bin.append('{:08b}'.format(val))
            hex.append('{:02x}'.format(val))
            ascii.append(chr(val) if chr(val).isprintable() and chr(val) != '\n' else '.')

        bin_idx, hex_idx, ascii_idx = 0, 0, 0
        while bin_idx < len(bin):
            print('   ', ' '.join(bin[bin_idx:bin_idx+8]), end=' │ ')
            bin_idx += 8
            print(' '.join(hex[hex_idx:hex_idx+8]), end=' │ ')
            hex_idx += 8
            print(''.join(ascii[ascii_idx:ascii_idx+8]))
            ascii_idx += 8

        # Make relocation of symbols
        symbol_bindings = self.parse_rs()  # Relocation section

        # Fill program's symbol table
        for s in self.symbols:
            if s.st_shndx < len(self.ordered_sections):
                prog.symbol_table[s.st_name] = {
                    'name': s.st_name,
                    'value': s.st_value,
                    'size': s.st_size,
                    'section': self.ordered_sections[s.st_shndx].sh_name
                }

        # Parse .text section to instructions
        print("\nParsing .text section into ISA.Instruction objects...")
        isa = ISA()
        pc = prog.sections['.text']
        self.file.seek(self.sections['.text'].sh_offset)

        while self.file.tell() < self.sections['.text'].sh_offset + self.sections['.text'].sh_size:
            bin = ''.join(["{:08b}".format(b) for b in reversed(self.file.read(4))])

            try:
                inst = isa.instruction_from_bin(bin, pc)
            except NotImplementedError:
                inst = None

            if symbol_bindings is not None and len(prog.IM) in symbol_bindings:  # Relocate symbol in the instruction
                sym = symbol_bindings[len(prog.IM)]
                print("    (relocating a symbol: {})".format(sym))
                if isinstance(inst, (IType_Instruction, UType_Instruction, UJType_Instruction)):
                    inst.imm = sym

            print('   ', bin, '->', inst if inst is not None else "! [error]")
            prog.IM.append(inst)
            if inst is None:
                self.unknown_instructions.append(len(prog.IM)-1)

            pc += 4