commit 6eba0cdb9eecd9bf97f09abd80948e91e0ddf736 Author: Zack Buhman Date: Tue Apr 9 09:57:08 2024 +0800 initial sh2 interpreter diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e74cb7e --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +__pycache__ +*.o +*.elf +*.bin +*.pyc \ No newline at end of file diff --git a/compare.py b/compare.py new file mode 100644 index 0000000..1c8a487 --- /dev/null +++ b/compare.py @@ -0,0 +1,30 @@ +from pprint import pprint + +from instruction_table import untabulate_instructions_sh2 +from instruction_table import untabulate_instructions_sh4 + +sh2 = untabulate_instructions_sh2() +sh4 = untabulate_instructions_sh4() + +all_sh2 = set([(i.instruction, i.operands) for i in sh2]) +all_sh4 = set([(i.instruction, i.operands) for i in sh4]) + +max_instruction = max(len(i.instruction) for i in [*sh2, *sh4]) +max_operands = max(len(i.operands) for i in [*sh2, *sh4]) + +print("only in sh2:") +for i in sh2: + if (i.instruction, i.operands) not in all_sh4: + print(i.instruction, i.operands) + +print() +print("only in sh4:") +for i in sh4: + if (i.instruction, i.operands) not in all_sh2: + print(i.instruction.ljust(max_instruction + 1), + i.operands.ljust(max_operands + 1), i.operation) + +print() + +print("sh2", len(sh2)) +print("sh4", len(sh4)) diff --git a/decode.py b/decode.py new file mode 100644 index 0000000..3a12463 --- /dev/null +++ b/decode.py @@ -0,0 +1,21 @@ +from instruction_table import untabulate_instructions_sh2 + +instruction_table = untabulate_instructions_sh2() + +def match_instruction(n, ins): + return (n & ins.code.mask_bits) == ins.code.code_bits + +def decode_instruction(n): + global instruction_table + + for ins in instruction_table: + if match_instruction(n, ins): + return ins + return None + +def decode_variables(n, ins): + operands = ins.code.operands + return [ + (n >> operands[variable].lsb) & ((1 << operands[variable].length) - 1) + for variable in ins.variables + ] diff --git a/disassemble.py b/disassemble.py new file mode 100644 index 0000000..241f2a0 --- /dev/null +++ b/disassemble.py @@ -0,0 +1,28 @@ +import sys +import struct + +from decode import decode_instruction, decode_variables + +def print_instruction(ins, variables): + print(ins.instruction, ins.operands, variables) + +def next_instruction(ins): + pass + +def main(): + with open(sys.argv[1], 'rb') as f: + buf = f.read() + mem = memoryview(buf) + + for i in range(len(buf) // 2): + b = mem[(i+0)*2:(i+1)*2] + n, = struct.unpack(">H", b) + ins = decode_instruction(n) + if ins is None: + print("", hex(n)) + else: + variables = decode_variables(n, ins) + print_instruction(ins, variables) + +if __name__ == '__main__': + main() diff --git a/effective_address.py b/effective_address.py new file mode 100644 index 0000000..b4b8ada --- /dev/null +++ b/effective_address.py @@ -0,0 +1,46 @@ + def effective_address(self, + mode: str, + length: int, + *args): + if mode in {"Rm" , "Rn" }: + # the effective address is the register + assert False, mode + if mode in {"@Rm" , "@Rn" }: + n_m, = args + return self.reg[n_m] + if mode in {"@Rm+", "@Rn+"}: + n_m, = args + value = self.reg[n_m] + self.reg[n_m] += length + return value + if mode in {"@-Rm-", "@-Rn"}: + n_m, = args + self.reg[n_m] -= length + return self.reg[n_m] + if mode in {"@(disp,Rn)", "@(disp,Rm)"}: + disp, n_m = args + return self.reg[n_m] + (disp * length) + if mode in {"@(R0,Rn)" , "@(R0,Rm)" }: + n_m, = args + return self.reg[n_m] + self.reg[0] + if mode in {"@(disp,GBR)"}: + disp, = args + assert length in {1, 2, 4}, length + return self.gbr + (disp * length) + if mode in {"@(R0,GBR)"}: + assert args == [], args + return self.regs[0] + self.gbr + if mode in {"@(disp,PC)"}: + disp, = args + assert length in {2, 4}, length + mask = 0xffffffff & (~((2 ** length) - 1)) + return (self.pc & mask) + (disp * length) + if mode in {"label"}: + disp, = args + assert length == 2, length + return self.pc + (disp * length) + if mode in {"#imm"}: + # immediate should be calculated in another function + assert False, mode + # otherwise, assert False + assert False, mode diff --git a/elf.py b/elf.py new file mode 100644 index 0000000..88c32e5 --- /dev/null +++ b/elf.py @@ -0,0 +1,82 @@ +""" + #define EI_NIDENT 16 + + typedef struct { + unsigned char e_ident[EI_NIDENT]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + ElfN_Addr e_entry; + ElfN_Off e_phoff; + ElfN_Off e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; + } ElfN_Ehdr; +""" +@dataclass +class ElfEhdr: + e_ident: bytes + e_type: int + e_machine: int + e_version: int + e_entry: int + e_phoff: int + e_shoff: int + e_flags: int + e_ehsize: int + e_phentsize: int + e_phnum: int + e_shentsize: int + e_shnum: int + e_shstrndx: int + +ELFMAG0 = 0x7f +ELFMAG1 = ord('E') +ELFMAG2 = ord('L') +ELFMAG3 = ord('F') + +EI_NIDENT = 16 + +elf_ident_fields = [ + ("EI_MAG0", 0), + ("EI_MAG1", 1), + ("EI_MAG2", 2), + ("EI_MAG3", 3), + ("EI_CLASS", 4), + ("EI_DATA", 5), + ("EI_VERSION", 6), + ("EI_OSABI", 7), + ("EI_ABIVERSION", 8), + ("EI_PAD", 9), +] + +class ElfClass(IntEnum): + NONE = 0 + CLASS32 = 1 + CLASS64 = 2 + +class ElfData(IntEnum): + NONE = 0 + LSB = 1 + MSB = 2 + +class OsABI(IntEnum): + NONE = 0 + HPUX = 1 + NETBSD = 2 + GNU = 3 + SOLARIS = 6 + AIX = 7 + IRIX = 8 + FREEBSD = 9 + TRU64 = 10 + MODESTO = 11 + OPENBSD = 12 + ARM_AEABI = 64 + ARM = 97 + STANDALONE = 255 diff --git a/execute.py b/execute.py new file mode 100644 index 0000000..78a52fe --- /dev/null +++ b/execute.py @@ -0,0 +1,47 @@ +import instruction_properties +import impl2 +from operations import zero_extend32, sign_extend32 +from decode import decode_instruction, decode_variables + +def delay_slot_state(cpu, ins): + if instruction_properties.has_delay_slot(ins): + assert cpu.is_delay_slot == False + cpu.is_delay_slot = True + else: + cpu.is_delay_slot = False + +def step(cpu, mem): + # 3 Fetch the instruction bytes from the address in memory, as + # indicated by the current program counter, 2 bytes need to be + # fetched for each instruction. + address = zero_extend32(sign_extend32(cpu.pc)) + assert address & 0b1 == 0, address + instruction = mem.read16(address) + + # 4 Calculate the default values of PC’ and PR’. PC’ is set to the + # value of PC”, PR’ is set to the value of PR”. + cpu.pc1 = cpu.pc2 + cpu.pr1 = cpu.pr2 + + # 5 Calculate the default values of PC” and PR” assuming continued + # sequential execution without procedure call or mode switch: PC” + # is PC’+2, while PR” is unchanged. + cpu.pc2 = cpu.pc1 + 2 + cpu.pr2 = cpu.pr2 + + # 6 Decode and execute the instruction. This includes checks for + # synchronous events, such as exceptions and panics, and + # initiation of handling if required. Synchronous events are not + # accepted between a delayed branch and a delay slot. They are + # detected either before the delayed branch or after the delay + # slot. + ins = decode_instruction(instruction) + variables = decode_variables(instruction, ins) + func = impl2.lookup[(ins.instruction, ins.operands)] + func(cpu, mem, *variables) + delay_slot_state(cpu, ins) + + # 7 Set the current program counter (PC) to the value of the next + # program counter (PC’) and PR to the value of PR’. + cpu.pc = cpu.pc1 + cpu.pr = cpu.pr1 diff --git a/gdb.script b/gdb.script new file mode 100644 index 0000000..d28e99f --- /dev/null +++ b/gdb.script @@ -0,0 +1,5 @@ +target extended-remote localhost:1236 +tui enable +tui layout regs +tui focus cmd +tui reg all diff --git a/generate.py b/generate.py new file mode 100644 index 0000000..8f896f6 --- /dev/null +++ b/generate.py @@ -0,0 +1,88 @@ +from instruction_table import untabulate_instructions + +mode_name = { + '': 'no_operand', + 'Rn': 'destination_operand_only', + 'Rm': 'destination_operand_only', + 'Rm,Rn': 'source_and_destination_operands', + 'Rm,SR': 'transfer_to_sr', + 'Rm,GBR': 'transfer_to_gbr', + 'Rm,VBR': 'transfer_to_vbr', + 'Rm,MACH': 'transfer_to_mach', + 'Rm,MACL': 'transfer_to_macl', + 'Rm,PR': 'transfer_to_pr', + 'SR,Rn': 'transfer_from_sr', + 'GBR,Rn': 'transfer_from_gbr', + 'VBR,Rn': 'transfer_from_vbr', + 'MACH,Rn': 'transfer_from_mach', + 'MACL,Rn': 'transfer_from_macl', + 'PR,Rn': 'transfer_from_pr', + '@Rn': 'destination_operand_only', + 'Rm,@Rn': 'store_register_direct_data_transfer', + '@Rm,Rn': 'load_register_direct_data_transfer', + '@Rm+,@Rn+': 'multiply_and_accumulate_operation', + '@Rm+,Rn': 'load_direct_data_transfer_from_register', + '@Rm+,SR': 'load_to_sr', + '@Rm+,GBR': 'load_to_gbr', + '@Rm+,VBR': 'load_to_vbr', + '@Rm+,MACH': 'load_to_mach', + '@Rm+,MACL': 'load_to_macl', + '@Rm+,PR': 'load_to_pr', + 'Rm,@–Rn': 'store_direct_data_transfer_from_register', + 'SR,@–Rn': 'store_from_sr', + 'GBR,@–Rn': 'store_from_gbr', + 'VBR,@–Rn': 'store_from_vbr', + 'MACH,@–Rn': 'store_from_mach', + 'MACL,@–Rn': 'store_from_macl', + 'PR,@–Rn': 'store_from_pr', + 'R0,@(disp,Rn)': 'store_register_indirect_with_displacement', + 'Rm,@(disp,Rn)': 'store_register_indirect_with_displacement', + '@(disp,Rm),R0': 'load_register_indirect_with_displacement', + '@(disp,Rm),Rn': 'load_register_indirect_with_displacement', + 'Rm,@(R0,Rn)': 'store_indexed_register_indirect', + '@(R0,Rm),Rn': 'load_indexed_register_indirect', + 'R0,@(disp,GBR)': 'store_gbr_indirect_with_displacement', + '@(disp,GBR),R0': 'load_gbr_indirect_with_displacement', + '#imm,@(R0,GBR)': 'store_indexed_gbr_indirect', + '@(R0,GBR),#imm': 'load_indexed_gbr_indirect', + '@(disp,PC),Rn': 'pc_relative_with_displacement', + '@(disp,PC),R0': 'pc_relative_with_displacement', + 'label': 'pc_relative', + '#imm,Rn': 'immediate', + '#imm,R0': 'immediate', + '#imm': 'immediate', +} + +def sanitize_instruction(ins): + name = ins.instruction.replace('.', '_').replace('/', '_').lower() + assert ins.operands in mode_name, (ins.instruction, ins.operands) + mode = mode_name[ins.operands] + return '__'.join([name, mode]) + +def main(): + function_names = {} + instruction_table = untabulate_instructions() + for ins in instruction_table: + function_name = sanitize_instruction(ins) + instruction_operands = (ins.instruction, ins.operands) + assert function_name not in function_names, (instruction_operands, names[name]) + function_names[function_name] = instruction_operands + if ins.variables: + args = f', {", ".join(ins.variables)}' + else: + args = '' + print(f"def {function_name}(cpu, mem{args}):") + print(f" # {ins.instruction} {ins.operands}") + print(f" raise NotImplementedError()") + print() + + print("lookup = {") + for ins in instruction_table: + function_name = sanitize_instruction(ins) + i_space = ' ' * (len('CMP/STR') - len(ins.instruction)) + o_space = ' ' * (len('@(disp,GBR),R0') - len(ins.operands)) + print(f" ('{ins.instruction}'{i_space}, '{ins.operands}'{o_space}): {function_name},") + print("}") + +if __name__ == "__main__": + main() diff --git a/impl2.py b/impl2.py new file mode 100644 index 0000000..7bf8db4 --- /dev/null +++ b/impl2.py @@ -0,0 +1,1370 @@ +from operations import * +from log import log + +class ILLSLOT(Exception): + pass + +class TRAP(Exception): + pass + +def clrt__no_operand(cpu, mem): + # CLRT + t = 0 + cpu.sr.t = bit(t) + +def clrmac__no_operand(cpu, mem): + # CLRMAC + macl = 0 + mach = 0 + cpu.macl = zero_extend32(macl) + cpu.mach = zero_extend32(mach) + +def div0u__no_operand(cpu, mem): + # DIV0U + q = 0 + m = 0 + t = 0 + cpu.sr.q = bit(q) + cpu.sr.m = bit(m) + cpu.sr.t = bit(t) + +def nop__no_operand(cpu, mem): + # NOP + pass + +def rte__no_operand(cpu, mem): + # RTE + pc = sign_extend32(cpu.pc) + if cpu.is_delay_slot: + raise ILLSLOT() + target = pc + delayedpc = target & (~0x1) + cpu.pc2 = register(delayedpc) + +def rts__no_operand(cpu, mem): + # RTS + pr = sign_extend32(cpu.pr) + if cpu.is_delay_slot: + raise ILLSLOT() + target = pr + delayedpc = target & (~0x1) + cpu.pc2 = register(delayedpc) + +def sett__no_operand(cpu, mem): + # SETT + t = 1 + cpu.sr.t = bit(t) + +def sleep__no_operand(cpu, mem): + # SLEEP + raise NotImplementedError() + +def cmp_pl__destination_operand_only(cpu, mem, n): + # CMP/PL Rn + op1 = sign_extend32(cpu.reg[n]) + t = int(op1 > 0) + cpu.sr.t = bit(t) + +def cmp_pz__destination_operand_only(cpu, mem, n): + # CMP/PZ Rn + op1 = sign_extend32(cpu.reg[n]) + t = int(op1 >= 0) + cpu.sr.t = bit(t) + +def dt__destination_operand_only(cpu, mem, n): + # DT Rn + op1 = sign_extend32(cpu.reg[n]) + op1 = op1 - 1 + t = int(op1 == 0) + cpu.reg[n] = register(op1) + cpu.sr.t = bit(t) + +def movt__destination_operand_only(cpu, mem, n): + # MOVT Rn + t = zero_extend1(cpu.sr.t) + op1 = t + cpu.reg[n] = register(op1) + +def rotl__destination_operand_only(cpu, mem, n): + # ROTL Rn + op1 = zero_extend32(cpu.reg[n]) + t = (op1 >> 31) & 1 + op1 = (op1 << 1) | t + cpu.reg[n] = register(op1) + cpu.sr.t = bit(t) + +def rotr__destination_operand_only(cpu, mem, n): + # ROTR Rn + op1 = zero_extend32(cpu.reg[n]) + t = (op1 >> 0) & 1 + op1 = (op1 >> 1) | (t << 31) + cpu.reg[n] = register(op1) + cpu.sr.t = bit(t) + +def rotcl__destination_operand_only(cpu, mem, n): + # ROTCL Rn + t = zero_extend1(cpu.sr.t) + op1 = zero_extend32(cpu.reg[n]) + op1 = (op1 << 1) | t + t = (op1 >> 32) & 1 + cpu.reg[n] = register(op1) + cpu.sr.t = bit(t) + +def rotcr__destination_operand_only(cpu, mem, n): + # ROTCR Rn + t = zero_extend1(cpu.sr.t) + op1 = zero_extend32(cpu.reg[n]) + oldt = t + t = (op1 >> 0) & 1 + op1 = (op1 >> 1) | (oldt << 31) + cpu.reg[n] = register(op1) + cpu.sr.t = bit(t) + +def shal__destination_operand_only(cpu, mem, n): + # SHAL Rn + op1 = sign_extend32(cpu.reg[n]) + t = (op1 >> 31) & 1 + op1 = op1 << 1 + cpu.reg[n] = register(op1) + cpu.sr.t = bit(t) + +def shar__destination_operand_only(cpu, mem, n): + # SHAR Rn + op1 = sign_extend32(cpu.reg[n]) + t = (op1 >> 0) & 1 + op1 = op1 >> 1 + cpu.reg[n] = register(op1) + cpu.sr.t = bit(t) + +def shll__destination_operand_only(cpu, mem, n): + # SHLL Rn + op1 = zero_extend32(cpu.reg[n]) + t = (op1 >> 31) & 1 + op1 = op1 << 1 + cpu.reg[n] = register(op1) + cpu.sr.t = bit(t) + +def shlr__destination_operand_only(cpu, mem, n): + # SHLR Rn + op1 = zero_extend32(cpu.reg[n]) + t = (op1 >> 0) & 1 + op1 = op1 >> 1 + cpu.reg[n] = register(op1) + cpu.sr.t = bit(t) + +def shll2__destination_operand_only(cpu, mem, n): + # SHLL2 Rn + op1 = zero_extend32(cpu.reg[n]) + op1 = op1 << 2 + cpu.reg[n] = register(op1) + +def shlr2__destination_operand_only(cpu, mem, n): + # SHLR2 Rn + op1 = zero_extend32(cpu.reg[n]) + op1 = op1 >> 2 + cpu.reg[n] = register(op1) + +def shll8__destination_operand_only(cpu, mem, n): + # SHLL8 Rn + op1 = zero_extend32(cpu.reg[n]) + op1 = op1 << 8 + cpu.reg[n] = register(op1) + +def shlr8__destination_operand_only(cpu, mem, n): + # SHLR8 Rn + op1 = zero_extend32(cpu.reg[n]) + op1 = op1 >> 8 + cpu.reg[n] = register(op1) + +def shll16__destination_operand_only(cpu, mem, n): + # SHLL16 Rn + op1 = zero_extend32(cpu.reg[n]) + op1 = op1 << 16 + cpu.reg[n] = register(op1) + +def shlr16__destination_operand_only(cpu, mem, n): + # SHLR16 Rn + op1 = zero_extend32(cpu.reg[n]) + op1 = op1 >> 16 + cpu.reg[n] = register(op1) + +def add__source_and_destination_operands(cpu, mem, m, n): + # ADD Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + op2 = op2 + op1 + cpu.reg[n] = register(op2) + +def addc__source_and_destination_operands(cpu, mem, m, n): + # ADDC Rm,Rn + t = zero_extend1(cpu.sr.t) + op1 = zero_extend32(sign_extend32(cpu.reg[m])) + op2 = zero_extend32(sign_extend32(cpu.reg[n])) + op2 = (op2 + op1) + t + t = (op2 >> 32) & 1 + cpu.reg[n] = register(op2) + cpu.sr.t = bit(t) + +def addv__source_and_destination_operands(cpu, mem, m, n): + # ADDV Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + op2 = op2 + op1 + t = int((op2 < (-(2**31))) or (op2 >= (2**31))) + cpu.reg[n] = register(op2) + cpu.sr.t = bit(t) + +def and__source_and_destination_operands(cpu, mem, m, n): + # AND Rm,Rn + op1 = zero_extend32(cpu.reg[m]) + op2 = zero_extend32(cpu.reg[n]) + op2 = op2 & op1 + cpu.reg[n] = register(op2) + +def cmp_eq__source_and_destination_operands(cpu, mem, m, n): + # CMP/EQ Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + t = int(op2 == op1) + cpu.sr.t = bit(t) + +def cmp_hs__source_and_destination_operands(cpu, mem, m, n): + # CMP/HS Rm,Rn + op1 = zero_extend32(sign_extend32(cpu.reg[m])) + op2 = zero_extend32(sign_extend32(cpu.reg[n])) + t = int(op2 >= op1) + cpu.sr.t = bit(t) + +def cmp_ge__source_and_destination_operands(cpu, mem, m, n): + # CMP/GE Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + t = int(op2 >= op1) + cpu.sr.t = bit(t) + +def cmp_hi__source_and_destination_operands(cpu, mem, m, n): + # CMP/HI Rm,Rn + op1 = zero_extend32(sign_extend32(cpu.reg[m])) + op2 = zero_extend32(sign_extend32(cpu.reg[n])) + t = int(op2 > op1) + cpu.sr.t = bit(t) + +def cmp_gt__source_and_destination_operands(cpu, mem, m, n): + # CMP/GT Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + t = int(op2 > op1) + cpu.sr.t = bit(t) + +def cmp_str__source_and_destination_operands(cpu, mem, m, n): + # CMP/STR Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + temp = op1 ^ op2 + t = int(((temp >> 0 ) & 0xff) == 0) + t = int(((temp >> 8 ) & 0xff) == 0) | t + t = int(((temp >> 16) & 0xff) == 0) | t + t = int(((temp >> 24) & 0xff) == 0) | t + cpu.sr.t = bit(t) + +def div1__source_and_destination_operands(cpu, mem, m, n): + # DIV1 Rm,Rn + q = zero_extend1(cpu.sr.q) + m = zero_extend1(cpu.sr.m) + t = zero_extend1(cpu.sr.t) + op1 = zero_extend32(sign_extend32(cpu.reg[m])) + op2 = zero_extend32(sign_extend32(cpu.reg[n])) + oldq = q + q = (op2 >> 31) & 1 + op2 = zero_extend32(op2 << 1) | t + if oldq == m: + op2 = op2 - op1 + else: + op2 = op2 + op1 + q = (q ^ m) ^ (op2 >> 32) & 1 + t = 1 - (q ^ m) + cpu.reg[n] = register(op2) + cpu.sr.q = bit(q) + cpu.sr.t = bit(t) + +def div0s__source_and_destination_operands(cpu, mem, m, n): + # DIV0S Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + q = (op2 >> 31) & 1 + m = (op1 >> 31) & 1 + t = m ^ q + cpu.sr.q = bit(q) + cpu.sr.m = bit(m) + cpu.sr.t = bit(t) + +def dmuls_l__source_and_destination_operands(cpu, mem, m, n): + # DMULS.L Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + mac = op2 * op1 + macl = mac + mach = mac >> 32 + cpu.macl = zero_extend32(macl) + cpu.mach = zero_extend32(mach) + +def dmulu_l__source_and_destination_operands(cpu, mem, m, n): + # DMULU.L Rm,Rn + op1 = zero_extend32(sign_extend32(cpu.reg[m])) + op2 = zero_extend32(sign_extend32(cpu.reg[n])) + mac = op2 * op1 + macl = mac + mach = mac >> 32 + cpu.macl = zero_extend32(macl) + cpu.mach = zero_extend32(mach) + +def exts_b__source_and_destination_operands(cpu, mem, m, n): + # EXTS.B Rm,Rn + op1 = sign_extend8(cpu.reg[m]) + op2 = op1 + cpu.reg[n] = register(op2) + +def exts_w__source_and_destination_operands(cpu, mem, m, n): + # EXTS.W Rm,Rn + op1 = sign_extend16(cpu.reg[m]) + op2 = op1 + cpu.reg[n] = register(op2) + +def extu_b__source_and_destination_operands(cpu, mem, m, n): + # EXTU.B Rm,Rn + op1 = zero_extend8(cpu.reg[m]) + op2 = op1 + cpu.reg[n] = register(op2) + +def extu_w__source_and_destination_operands(cpu, mem, m, n): + # EXTU.W Rm,Rn + op1 = zero_extend16(cpu.reg[m]) + op2 = op1 + cpu.reg[n] = register(op2) + +def mov__source_and_destination_operands(cpu, mem, m, n): + # MOV Rm,Rn + op1 = zero_extend32(cpu.reg[m]) + op2 = op1 + cpu.reg[n] = register(op2) + +def mul_l__source_and_destination_operands(cpu, mem, m, n): + # MUL.L Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + macl = op2 * op1 + cpu.macl = zero_extend32(macl) + +def muls_w__source_and_destination_operands(cpu, mem, m, n): + # MULS.W Rm,Rn + op1 = sign_extend16(sign_extend32(cpu.reg[m])) + op2 = sign_extend16(sign_extend32(cpu.reg[n])) + macl = op2 * op1 + cpu.macl = zero_extend32(macl) + +def mulu_w__source_and_destination_operands(cpu, mem, m, n): + # MULU.W Rm,Rn + op1 = zero_extend16(sign_extend32(cpu.reg[m])) + op2 = zero_extend16(sign_extend32(cpu.reg[n])) + macl = op2 * op1 + cpu.macl = zero_extend32(macl) + +def neg__source_and_destination_operands(cpu, mem, m, n): + # NEG Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = (-op1) + cpu.reg[n] = register(op2) + +def negc__source_and_destination_operands(cpu, mem, m, n): + # NEGC Rm,Rn + t = zero_extend1(cpu.sr.t) + op1 = zero_extend32(cpu.reg[m]) + op2 = (-op1) - t + t = (op2 >> 32) & 1 + cpu.reg[n] = register(op2) + cpu.sr.t = bit(t) + +def not__source_and_destination_operands(cpu, mem, m, n): + # NOT Rm,Rn + op1 = zero_extend32(cpu.reg[m]) + op2 = (~op1) + cpu.reg[n] = register(op2) + +def or__source_and_destination_operands(cpu, mem, m, n): + # OR Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + op2 = op2 | op1 + cpu.reg[n] = register(op2) + +def sub__source_and_destination_operands(cpu, mem, m, n): + # SUB Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + op2 = op2 - op1 + cpu.reg[n] = register(op2) + +def subc__source_and_destination_operands(cpu, mem, m, n): + # SUBC Rm,Rn + t = zero_extend1(cpu.sr.t) + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + op2 = op2 - op1 - t + t = (op2 >> 32) & 1 + cpu.reg[n] = register(op2) + cpu.sr.t = bit(t) + +def subv__source_and_destination_operands(cpu, mem, m, n): + # SUBV Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + op2 = op2 - op1 + t = int((op2 < (-(2**31))) or (op2 >= (2**31))) + cpu.reg[n] = register(op2) + cpu.sr.t = bit(t) + +def swap_b__source_and_destination_operands(cpu, mem, m, n): + # SWAP.B Rm,Rn + op1 = zero_extend32(cpu.reg[m]) + op2 = ((((op1 >> 16) & 0xffff) << 16) + | (((op1 >> 0 ) & 0xff ) << 8 ) + | (((op1 >> 8 ) & 0xff ) << 0 )) + cpu.reg[n] = register(op2); + +def swap_w__source_and_destination_operands(cpu, mem, m, n): + # SWAP.W Rm,Rn + op1 = zero_extend32(cpu.reg[m]) + op2 = ((((op1 >> 0 ) & 0xffff) << 16) + | (((op1 >> 16) & 0xffff) << 0 )) + cpu.reg[n] = register(op2); + +def tst__source_and_destination_operands(cpu, mem, m, n): + # TST Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + t = int((op1 & op2) == 0) + cpu.sr.t = bit(t) + +def xor__source_and_destination_operands(cpu, mem, m, n): + # XOR Rm,Rn + op1 = zero_extend32(cpu.reg[m]) + op2 = zero_extend32(cpu.reg[n]) + op2 = op2 ^ op1 + cpu.reg[n] = register(op2) + +def xtrct__source_and_destination_operands(cpu, mem, m, n): + # XTRCT Rm,Rn + op1 = zero_extend32(cpu.reg[m]) + op2 = zero_extend32(cpu.reg[n]) + op2 = ((op2 >> 16) & 0xffff) | (((op1 >> 0) & 0xffff) << 16) + cpu.reg[n] = register(op2) + +def ldc__transfer_to_sr(cpu, mem, m): + # LDC Rm,SR + op1 = sign_extend32(cpu.reg[m]) + sr = op1 + cpu.sr.set_value(register(sr)) + +def ldc__transfer_to_gbr(cpu, mem, m): + # LDC Rm,GBR + op1 = sign_extend32(cpu.reg[m]) + gbr = op1 + cpu.gbr = register(gbr) + +def ldc__transfer_to_vbr(cpu, mem, m): + # LDC Rm,VBR + op1 = sign_extend32(cpu.reg[m]) + vbr = op1 + cpu.vbr = register(vbr) + +def lds__transfer_to_mach(cpu, mem, m): + # LDS Rm,MACH + op1 = sign_extend32(cpu.reg[m]) + mach = op1 + cpu.mach = register(mach) + +def lds__transfer_to_macl(cpu, mem, m): + # LDS Rm,MACL + op1 = sign_extend32(cpu.reg[m]) + macl = op1 + cpu.macl = register(macl) + +def lds__transfer_to_pr(cpu, mem, m): + # LDS Rm,PR + op1 = sign_extend32(cpu.reg[m]) + newpr = op1 + delayedpr = newpr + cpu.pr1 = register(newpr) + cpu.pr2 = register(delayedpr) + +def stc__transfer_from_sr(cpu, mem, n): + # STC SR,Rn + sr = sign_extend32(cpu.sr.get_value()) + op1 = sr + cpu.reg[n] = register(op1) + +def stc__transfer_from_gbr(cpu, mem, n): + # STC GBR,Rn + gbr = sign_extend32(cpu.gbr) + op1 = gbr + cpu.reg[n] = register(op1) + +def stc__transfer_from_vbr(cpu, mem, n): + # STC VBR,Rn + vbr = sign_extend32(cpu.vbr) + op1 = vbr + cpu.reg[n] = register(op1) + +def sts__transfer_from_mach(cpu, mem, n): + # STS MACH,Rn + mach = sign_extend32(cpu.mach) + op1 = mach + cpu.reg[n] = register(op1) + +def sts__transfer_from_macl(cpu, mem, n): + # STS MACL,Rn + macl = sign_extend32(cpu.macl) + op1 = macl + cpu.reg[n] = register(op1) + +def sts__transfer_from_pr(cpu, mem, n): + # STS PR,Rn + pr = sign_extend32(cpu.pr1) + op1 = pr + cpu.reg[n] = register(op1) + +def jmp__destination_operand_only(cpu, mem, n): + # JMP @Rn + op1 = sign_extend32(cpu.reg[n]) + if cpu.is_delay_slot: + raise ILLSLOT() + target = op1 + delayedpc = target & (~0x1) + cpu.pc2 = register(delayedpc) + +def jsr__destination_operand_only(cpu, mem, n): + # JSR @Rn + pc = sign_extend32(cpu.pc) + op1 = sign_extend32(cpu.reg[n]) + if cpu.is_delay_slot: + raise ILLSLOT() + delayedpr = pc + 4 + target = op1 + delayedpc = target & (~0x1) + cpu.pr2 = register(delayedpr) + cpu.pc2 = register(delayedpc) + +def tas_b__destination_operand_only(cpu, mem, n): + # TAS.B @Rn + op1 = sign_extend32(cpu.reg[n]) + address = zero_extend32(op1) + value = zero_extend8(mem.read8(address)) + t = int(value == 0) + value = value | (1 << 7) + mem.write8(address, value) + cpu.sr.t = bit(t) + +def mov_b__store_register_direct_data_transfer(cpu, mem, m, n): + # MOV.B Rm,@Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + address = zero_extend32(op2) + mem.write8(address, op1) + +def mov_w__store_register_direct_data_transfer(cpu, mem, m, n): + # MOV.W Rm,@Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + address = zero_extend32(op2) + mem.write16(address, op1) + +def mov_l__store_register_direct_data_transfer(cpu, mem, m, n): + # MOV.L Rm,@Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + address = zero_extend32(op2) + mem.write32(address, op1) + +def mov_b__load_register_direct_data_transfer(cpu, mem, m, n): + # MOV.B @Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(op1) + op2 = sign_extend8(mem.read8(address)) + cpu.reg[n] = register(op2) + +def mov_w__load_register_direct_data_transfer(cpu, mem, m, n): + # MOV.W @Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(op1) + op2 = sign_extend16(mem.read16(address)) + cpu.reg[n] = register(op2) + +def mov_l__load_register_direct_data_transfer(cpu, mem, m, n): + # MOV.L @Rm,Rn + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(op1) + op2 = sign_extend32(mem.read32(address)) + cpu.reg[n] = register(op2) + +def mac_l__multiply_and_accumulate_operation(cpu, mem, m, n): + # MAC.L @Rm+,@Rn+ + macl = zero_extend32(cpu.macl) + mach = zero_extend32(cpu.mach) + s = zero_extend1(cpu.sr.s) + m_field = zero_extend4(m) + n_field = zero_extend4(n) + m_address = sign_extend32(cpu.reg[m]) + n_address = sign_extend32(cpu.reg[n]) + value2 = sign_extend32(mem.read32(zero_extend32(n_address))) + n_address = n_address + 4 + if n_field == m_field: + m_address = m_address + 4 + n_address = n_address + 4 + value1 = sign_extend32(mem.read32(zero_extend32(m_address))) + m_address = m_address + 4 + mul = value2 * value1 + mac = sign_extend64((mach << 32) + macl) + # simulate 64-bit addition + result = (mac + mul) & 0xffff_ffff_ffff_ffff + if s == 1: + if (((result ^ mac) & (result ^ mul)) >> 63) & 1 == 1: + if (mac >> 63) & 1 == 0: + result = (2 ** 47) - 1 + else: + result = -(2 ** 47) + else: + result = signed_saturate48(result) + macl = result + mach = result >> 32 + cpu.reg[m] = register(m_address) + cpu.reg[n] = register(n_address) + cpu.macl = zero_extend32(macl) + cpu.mach = zero_extend32(mach) + +def mac_w__multiply_and_accumulate_operation(cpu, mem, m, n): + # MAC.W @Rm+,@Rn+ + macl = zero_extend32(cpu.macl) + mach = zero_extend32(cpu.mach) + s = zero_extend1(cpu.sr.s) + m_field = zero_extend4(m) + n_field = zero_extend4(n) + m_address = sign_extend32(cpu.reg[m]) + n_address = sign_extend32(cpu.reg[n]) + value2 = sign_extend16(mem.read16(zero_extend32(n_address))) + n_address = n_address + 2 + if n_field == m_field: + m_address = m_address + 2 + n_address = n_address + 2 + value1 = sign_extend16(mem.read16(zero_extend32(m_address))) + m_address = m_address + 2 + mul = value2 * value1 + if s == 1: + macl = sign_extend32(macl) + mul + temp = signed_saturate32(macl) + log(value1, value2, macl) + if macl == temp: + result = (mach << 32) | zero_extend32(macl) + else: + result = (1 << 32) | zero_extend32(temp) + else: + result = sign_extend64((mach << 32) + macl) + mul + macl = result + mach = result >> 32 + cpu.reg[m] = register(m_address) + cpu.reg[n] = register(n_address) + cpu.macl = zero_extend32(macl) + cpu.mach = zero_extend32(mach) + +def mov_b__load_direct_data_transfer_from_register(cpu, mem, m, n): + # MOV.B @Rm+,Rn + m_field = zero_extend4(m) + n_field = zero_extend4(n) + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(op1) + op2 = sign_extend8(mem.read8(address)) + if m_field == n_field: + op1 = op2 + else: + op1 = op1 + 1 + cpu.reg[m] = register(op1) + cpu.reg[n] = register(op2) + +def mov_w__load_direct_data_transfer_from_register(cpu, mem, m, n): + # MOV.W @Rm+,Rn + m_field = zero_extend4(m) + n_field = zero_extend4(n) + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(op1) + op2 = sign_extend16(mem.read16(address)) + if m_field == n_field: + op1 = op2 + else: + op1 = op1 + 2 + cpu.reg[m] = register(op1) + cpu.reg[n] = register(op2) + +def mov_l__load_direct_data_transfer_from_register(cpu, mem, m, n): + # MOV.L @Rm+,Rn + m_field = zero_extend4(m) + n_field = zero_extend4(n) + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(op1) + op2 = sign_extend32(mem.read32(address)) + if m_field == n_field: + op1 = op2 + else: + op1 = op1 + 4 + cpu.reg[m] = register(op1) + cpu.reg[n] = register(op2) + +def ldc_l__load_to_sr(cpu, mem, m): + # LDC.L @Rm+,SR + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(op1) + sr = sign_extend32(mem.read32(address)) + op1 = op1 + 4 + cpu.reg[m] = register(op1) + cpu.sr.set_value(register(sr)) + +def ldc_l__load_to_gbr(cpu, mem, m): + # LDC.L @Rm+,GBR + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(op1) + gbr = sign_extend32(mem.read32(address)) + op1 = op1 + 4 + cpu.reg[m] = register(op1) + cpu.gbr = register(gbr) + +def ldc_l__load_to_vbr(cpu, mem, m): + # LDC.L @Rm+,VBR + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(op1) + vbr = sign_extend32(mem.read32(address)) + op1 = op1 + 4 + cpu.reg[m] = register(op1) + cpu.vbr = register(vbr) + +def lds_l__load_to_mach(cpu, mem, m): + # LDS.L @Rm+,MACH + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(op1) + mach = sign_extend32(mem.read32(address)) + op1 = op1 + 4 + cpu.reg[m] = register(op1) + cpu.mach = zero_extend32(mach) + +def lds_l__load_to_macl(cpu, mem, m): + # LDS.L @Rm+,MACL + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(op1) + macl = sign_extend32(mem.read32(address)) + op1 = op1 + 4 + cpu.reg[m] = register(op1) + cpu.macl = zero_extend32(macl) + +def lds_l__load_to_pr(cpu, mem, m): + # LDS.L @Rm+,PR + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(op1) + newpr = sign_extend32(mem.read32(address)) + delayedpr = newpr + op1 = op1 + 4 + cpu.reg[m] = register(op1) + cpu.pr1 = register(newpr) + cpu.pr2 = register(delayedpr) + +def mov_b__store_direct_data_transfer_from_register(cpu, mem, m, n): + # MOV.B Rm,@-Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + address = zero_extend32(op2 - 1) + mem.write8(address, op1) + op2 = address + cpu.reg[n] = register(op2) + +def mov_w__store_direct_data_transfer_from_register(cpu, mem, m, n): + # MOV.W Rm,@-Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + address = zero_extend32(op2 - 2) + mem.write16(address, op1) + op2 = address + cpu.reg[n] = register(op2) + +def mov_l__store_direct_data_transfer_from_register(cpu, mem, m, n): + # MOV.L Rm,@-Rn + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + address = zero_extend32(op2 - 4) + mem.write32(address, op1) + op2 = address + cpu.reg[n] = register(op2) + +def stc_l__store_from_sr(cpu, mem, n): + # STC.L SR,@-Rn + sr = sign_extend32(cpu.sr.get_value()) + op1 = sign_extend32(cpu.reg[n]) + address = zero_extend32(op1 - 4) + mem.write32(address, sr) + op1 = address + cpu.reg[n] = register(op1) + +def stc_l__store_from_gbr(cpu, mem, n): + # STC.L GBR,@-Rn + gbr = sign_extend32(cpu.gbr) + op1 = sign_extend32(cpu.reg[n]) + address = zero_extend32(op1 - 4) + mem.write32(address, gbr) + op1 = address + cpu.reg[n] = register(op1) + +def stc_l__store_from_vbr(cpu, mem, n): + # STC.L VBR,@-Rn + vbr = sign_extend32(cpu.vbr) + op1 = sign_extend32(cpu.reg[n]) + address = zero_extend32(op1 - 4) + mem.write32(address, vbr) + op1 = address + cpu.reg[n] = register(op1) + +def sts_l__store_from_mach(cpu, mem, n): + # STS.L MACH,@-Rn + mach = sign_extend32(cpu.mach) + op1 = sign_extend32(cpu.reg[n]) + address = zero_extend32(op1 - 4) + mem.write32(address, mach) + op1 = address + cpu.reg[n] = register(op1) + +def sts_l__store_from_macl(cpu, mem, n): + # STS.L MACL,@-Rn + macl = sign_extend32(cpu.macl) + op1 = sign_extend32(cpu.reg[n]) + address = zero_extend32(op1 - 4) + mem.write32(address, macl) + op1 = address + cpu.reg[n] = register(op1) + +def sts_l__store_from_pr(cpu, mem, n): + # STS.L PR,@-Rn + pr = sign_extend32(cpu.pr1) + op1 = sign_extend32(cpu.reg[n]) + address = zero_extend32(op1 - 4) + mem.write32(address, pr) + op1 = address + cpu.reg[n] = register(op1) + +def mov_b__store_register_indirect_with_displacement(cpu, mem, d, n): + # MOV.B R0,@(disp,Rn) + r0 = sign_extend32(cpu.reg[0]) + disp = zero_extend4(d) + op2 = sign_extend32(cpu.reg[n]) + address = zero_extend32(disp + op2) + mem.write8(address, r0) + +def mov_w__store_register_indirect_with_displacement(cpu, mem, d, n): + # MOV.W R0,@(disp,Rn) + r0 = sign_extend32(cpu.reg[0]) + disp = zero_extend4(d) << 1 + op2 = sign_extend32(cpu.reg[n]) + address = zero_extend32(disp + op2) + mem.write16(address, r0) + +def mov_l__store_register_indirect_with_displacement(cpu, mem, m, d, n): + # MOV.L Rm,@(disp,Rn) + op1 = sign_extend32(cpu.reg[m]) + disp = zero_extend4(d) << 2 + op3 = sign_extend32(cpu.reg[n]) + address = zero_extend32(disp + op3) + mem.write32(address, op1) + +def mov_b__load_register_indirect_with_displacement(cpu, mem, d, m): + # MOV.B @(disp,Rm),R0 + disp = zero_extend4(d) + op2 = sign_extend32(cpu.reg[m]) + address = zero_extend32(disp + op2) + r0 = sign_extend8(mem.read8(address)) + cpu.reg[0] = register(r0) + +def mov_w__load_register_indirect_with_displacement(cpu, mem, d, m): + # MOV.W @(disp,Rm),R0 + disp = zero_extend4(d) << 1 + op2 = sign_extend32(cpu.reg[m]) + address = zero_extend32(disp + op2) + r0 = sign_extend16(mem.read16(address)) + cpu.reg[0] = register(r0) + +def mov_l__load_register_indirect_with_displacement(cpu, mem, d, m, n): + # MOV.L @(disp,Rm),Rn + disp = zero_extend4(d) << 2 + op2 = sign_extend32(cpu.reg[m]) + address = zero_extend32(disp + op2) + op3 = sign_extend16(mem.read16(address)) + cpu.reg[n] = register(op3) + +def mov_b__store_indexed_register_indirect(cpu, mem, m, n): + # MOV.B Rm,@(R0,Rn) + r0 = sign_extend32(cpu.reg[0]) + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + address = zero_extend32(r0 + op2) + mem.write8(address, op1) + +def mov_w__store_indexed_register_indirect(cpu, mem, m, n): + # MOV.W Rm,@(R0,Rn) + r0 = sign_extend32(cpu.reg[0]) + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + address = zero_extend32(r0 + op2) + mem.write16(address, op1) + +def mov_l__store_indexed_register_indirect(cpu, mem, m, n): + # MOV.L Rm,@(R0,Rn) + r0 = sign_extend32(cpu.reg[0]) + op1 = sign_extend32(cpu.reg[m]) + op2 = sign_extend32(cpu.reg[n]) + address = zero_extend32(r0 + op2) + mem.write32(address, op1) + +def mov_b__load_indexed_register_indirect(cpu, mem, m, n): + # MOV.B @(R0,Rm),Rn + r0 = sign_extend32(cpu.reg[0]) + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(r0 + op1) + op2 = sign_extend8(mem.read8(address)) + cpu.reg[n] = register(op2) + +def mov_w__load_indexed_register_indirect(cpu, mem, m, n): + # MOV.W @(R0,Rm),Rn + r0 = sign_extend32(cpu.reg[0]) + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(r0 + op1) + op2 = sign_extend16(mem.read16(address)) + cpu.reg[n] = register(op2) + +def mov_l__load_indexed_register_indirect(cpu, mem, m, n): + # MOV.L @(R0,Rm),Rn + r0 = sign_extend32(cpu.reg[0]) + op1 = sign_extend32(cpu.reg[m]) + address = zero_extend32(r0 + op1) + op2 = sign_extend32(mem.read32(address)) + cpu.reg[n] = register(op2) + +def mov_b__store_gbr_indirect_with_displacement(cpu, mem, d): + # MOV.B R0,@(disp,GBR) + gbr = sign_extend32(cpu.gbr) + r0 = sign_extend32(cpu.reg[0]) + disp = zero_extend8(d) + address = zero_extend32(disp + gbr) + mem.write8(address, r0) + +def mov_w__store_gbr_indirect_with_displacement(cpu, mem, d): + # MOV.W R0,@(disp,GBR) + gbr = sign_extend32(cpu.gbr) + r0 = sign_extend32(cpu.reg[0]) + disp = zero_extend8(d) << 1 + address = zero_extend32(disp + gbr) + mem.write16(address, r0) + +def mov_l__store_gbr_indirect_with_displacement(cpu, mem, d): + # MOV.L R0,@(disp,GBR) + gbr = sign_extend32(cpu.gbr) + r0 = sign_extend32(cpu.reg[0]) + disp = zero_extend8(d) << 2 + address = zero_extend32(disp + gbr) + mem.write32(address, r0) + +def mov_b__load_gbr_indirect_with_displacement(cpu, mem, d): + # MOV.B @(disp,GBR),R0 + gbr = sign_extend32(cpu.gbr) + disp = zero_extend8(d) + address = zero_extend32(disp + gbr) + r0 = sign_extend8(mem.read8(address)) + cpu.reg[0] = register(r0) + +def mov_w__load_gbr_indirect_with_displacement(cpu, mem, d): + # MOV.W @(disp,GBR),R0 + gbr = sign_extend32(cpu.gbr) + disp = zero_extend8(d) << 1 + address = zero_extend32(disp + gbr) + r0 = sign_extend16(mem.read16(address)) + cpu.reg[0] = register(r0) + +def mov_l__load_gbr_indirect_with_displacement(cpu, mem, d): + # MOV.L @(disp,GBR),R0 + gbr = sign_extend32(cpu.gbr) + disp = zero_extend8(d) << 2 + address = zero_extend32(disp + gbr) + r0 = sign_extend32(mem.read32(address)) + cpu.reg[0] = register(r0) + +def and_b__store_indexed_gbr_indirect(cpu, mem, i): + # AND.B #imm,@(R0,GBR) + r0 = sign_extend32(cpu.reg[0]) + gbr = sign_extend32(cpu.gbr) + imm = zero_extend8(i) + address = zero_extend32(r0 + gbr) + value = zero_extend8(mem.read8(address)) + value = value & imm + mem.write8(address, value) + +def or_b__store_indexed_gbr_indirect(cpu, mem, i): + # OR.B #imm,@(R0,GBR) + r0 = sign_extend32(cpu.reg[0]) + gbr = sign_extend32(cpu.gbr) + imm = zero_extend8(i) + address = zero_extend32(r0 + gbr) + value = zero_extend8(mem.read8(address)) + value = value | imm + mem.write8(address, value) + +def tst_b__store_indexed_gbr_indirect(cpu, mem, i): + # TST.B #imm,@(R0,GBR) + r0 = sign_extend32(cpu.reg[0]) + gbr = sign_extend32(cpu.gbr) + imm = zero_extend8(i) + address = zero_extend32(r0 + gbr) + value = zero_extend8(mem.read8(address)) + t = int((value & imm) == 0) + cpu.sr.t = bit(t) + +def xor_b__store_indexed_gbr_indirect(cpu, mem, i): + # XOR.B #imm,@(R0,GBR) + r0 = sign_extend32(cpu.reg[0]) + gbr = sign_extend32(cpu.gbr) + imm = zero_extend8(i) + address = zero_extend32(r0 + gbr) + value = zero_extend8(mem.read8(address)) + value = value ^ imm + mem.write8(address, value) + +def mov_w__pc_relative_with_displacement(cpu, mem, d, n): + # MOV.W @(disp,PC),Rn + pc = sign_extend32(cpu.pc) + disp = zero_extend8(d) << 1 + if cpu.is_delay_slot: + raise ILLSLOT() + address = zero_extend32(disp + (pc + 4)) + op2 = sign_extend16(mem.read16(address)) + cpu.reg[n] = register(op2) + +def mov_l__pc_relative_with_displacement(cpu, mem, d, n): + # MOV.L @(disp,PC),Rn + pc = sign_extend32(cpu.pc) + disp = zero_extend8(d) << 2 + if cpu.is_delay_slot: + raise ILLSLOT() + address = zero_extend32(disp + ((pc + 4) & (~0x3))) + op2 = sign_extend32(mem.read32(address)) + cpu.reg[n] = register(op2) + +def mova__pc_relative_with_displacement(cpu, mem, d): + # MOVA @(disp,PC),R0 + pc = sign_extend32(cpu.pc) + disp = zero_extend8(d) << 2 + if cpu.is_delay_slot: + raise ILLSLOT() + r0 = disp + ((pc + 4) & (~0x3)) + cpu.reg[0] = register(r0) + +def braf__destination_operand_only(cpu, mem, n): + # BRAF Rn + pc = sign_extend32(cpu.pc) + op1 = sign_extend32(cpu.reg[n]) + if cpu.is_delay_slot: + raise ILLSLOT() + target = zero_extend32(pc + 4 + op1) + delayedpc = target & (~0x1) + cpu.pc2 = register(delayedpc) + +def bsrf__destination_operand_only(cpu, mem, n): + # BSRF Rn + pc = sign_extend32(cpu.pc) + op1 = sign_extend32(cpu.reg[n]) + if cpu.is_delay_slot: + raise ILLSLOT() + delayedpr = pc + 4 + target = zero_extend32(pc + 4 + op1) + delayedpc = target & (~0x1) + cpu.pr2 = register(delayedpr) + cpu.pc2 = register(delayedpc) + +def bf__pc_relative(cpu, mem, d): + # BF label + t = zero_extend1(cpu.sr.t) + pc = sign_extend32(cpu.pc) + newpc = sign_extend32(cpu.pc1) + delayedpc = sign_extend32(cpu.pc2) + label = sign_extend8(d) << 1 + if cpu.is_delay_slot: + raise ILLSLOT() + if t == 0: + temp = zero_extend32(pc + 4 + label) + newpc = temp + delayedpc = temp + 2 + cpu.pc1 = register(newpc) + cpu.pc2 = register(delayedpc) + +def bf_s__pc_relative(cpu, mem, d): + # BF/S label + t = zero_extend1(cpu.sr.t) + pc = sign_extend32(cpu.pc) + delayedpc = sign_extend32(cpu.pc2) + label = sign_extend8(d) << 1 + if cpu.is_delay_slot: + raise ILLSLOT() + if t == 0: + temp = zero_extend32(pc + 4 + label) + delayedpc = temp + cpu.pc2 = register(delayedpc) + +def bt__pc_relative(cpu, mem, d): + # BT label + t = zero_extend1(cpu.sr.t) + pc = sign_extend32(cpu.pc) + newpc = sign_extend32(cpu.pc1) + delayedpc = sign_extend32(cpu.pc2) + label = sign_extend8(d) << 1 + if cpu.is_delay_slot: + raise ILLSLOT() + if t == 1: + temp = zero_extend32(pc + 4 + label) + newpc = temp + delayedpc = temp + 2 + cpu.pc1 = register(newpc) + cpu.pc2 = register(delayedpc) + +def bt_s__pc_relative(cpu, mem, d): + # BT/S label + t = zero_extend1(cpu.sr.t) + pc = sign_extend32(cpu.pc) + delayedpc = sign_extend32(cpu.pc2) + label = sign_extend8(d) << 1 + if cpu.is_delay_slot: + raise ILLSLOT() + if t == 1: + temp = zero_extend32(pc + 4 + label) + delayedpc = temp + cpu.pc2 = register(delayedpc) + +def bra__pc_relative(cpu, mem, d): + # BRA label + pc = sign_extend32(cpu.pc) + label = sign_extend12(d) << 1 + if cpu.is_delay_slot: + raise ILLSLOT() + temp = zero_extend32(pc + 4 + label) + delayedpc = temp + cpu.pc2 = register(delayedpc) + +def bsr__pc_relative(cpu, mem, d): + # BSR label + pc = sign_extend32(cpu.pc) + label = sign_extend12(d) << 1 + if cpu.is_delay_slot: + raise ILLSLOT() + delayedpr = pc + 4 + temp = zero_extend32(pc + 4 + label) + delayedpc = temp + cpu.pr2 = register(delayedpr) + cpu.pc2 = register(delayedpc) + +def add__immediate(cpu, mem, i, n): + # ADD #imm,Rn + imm = sign_extend8(i) + op2 = sign_extend32(cpu.reg[n]) + op2 = op2 + imm + cpu.reg[n] = register(op2) + +def and__immediate(cpu, mem, i): + # AND #imm,R0 + r0 = sign_extend32(cpu.reg[0]) + imm = sign_extend8(i) + r0 = r0 & imm + cpu.reg[0] = register(r0) + +def cmp_eq__immediate(cpu, mem, i): + # CMP/EQ #imm,R0 + r0 = sign_extend32(cpu.reg[0]) + imm = sign_extend8(i) + t = int(r0 == imm) + cpu.sr.t = bit(t) + +def mov__immediate(cpu, mem, i, n): + # MOV #imm,Rn + imm = sign_extend8(i) + op2 = imm + cpu.reg[n] = register(op2) + +def or__immediate(cpu, mem, i): + # OR #imm,R0 + r0 = sign_extend32(cpu.reg[0]) + imm = sign_extend8(i) + r0 = r0 | imm + cpu.reg[0] = register(r0) + +def tst__immediate(cpu, mem, i): + # TST #imm,R0 + r0 = sign_extend32(cpu.reg[0]) + imm = sign_extend8(i) + t = int((r0 & imm) == 0) + cpu.sr.t = bit(t) + +def xor__immediate(cpu, mem, i): + # XOR #imm,R0 + r0 = sign_extend32(cpu.reg[0]) + imm = sign_extend8(i) + r0 = r0 ^ imm + cpu.reg[0] = register(r0) + +def trapa__immediate(cpu, mem, i): + # TRAPA #imm + imm = zero_extend8(i) + if cpu.is_delay_slot: + raise ILLSLOT() + raise TRAP(imm) + +lookup = { + ('CLRT' , '' ): clrt__no_operand, + ('CLRMAC' , '' ): clrmac__no_operand, + ('DIV0U' , '' ): div0u__no_operand, + ('NOP' , '' ): nop__no_operand, + ('RTE' , '' ): rte__no_operand, + ('RTS' , '' ): rts__no_operand, + ('SETT' , '' ): sett__no_operand, + ('SLEEP' , '' ): sleep__no_operand, + ('CMP/PL' , 'Rn' ): cmp_pl__destination_operand_only, + ('CMP/PZ' , 'Rn' ): cmp_pz__destination_operand_only, + ('DT' , 'Rn' ): dt__destination_operand_only, + ('MOVT' , 'Rn' ): movt__destination_operand_only, + ('ROTL' , 'Rn' ): rotl__destination_operand_only, + ('ROTR' , 'Rn' ): rotr__destination_operand_only, + ('ROTCL' , 'Rn' ): rotcl__destination_operand_only, + ('ROTCR' , 'Rn' ): rotcr__destination_operand_only, + ('SHAL' , 'Rn' ): shal__destination_operand_only, + ('SHAR' , 'Rn' ): shar__destination_operand_only, + ('SHLL' , 'Rn' ): shll__destination_operand_only, + ('SHLR' , 'Rn' ): shlr__destination_operand_only, + ('SHLL2' , 'Rn' ): shll2__destination_operand_only, + ('SHLR2' , 'Rn' ): shlr2__destination_operand_only, + ('SHLL8' , 'Rn' ): shll8__destination_operand_only, + ('SHLR8' , 'Rn' ): shlr8__destination_operand_only, + ('SHLL16' , 'Rn' ): shll16__destination_operand_only, + ('SHLR16' , 'Rn' ): shlr16__destination_operand_only, + ('ADD' , 'Rm,Rn' ): add__source_and_destination_operands, + ('ADDC' , 'Rm,Rn' ): addc__source_and_destination_operands, + ('ADDV' , 'Rm,Rn' ): addv__source_and_destination_operands, + ('AND' , 'Rm,Rn' ): and__source_and_destination_operands, + ('CMP/EQ' , 'Rm,Rn' ): cmp_eq__source_and_destination_operands, + ('CMP/HS' , 'Rm,Rn' ): cmp_hs__source_and_destination_operands, + ('CMP/GE' , 'Rm,Rn' ): cmp_ge__source_and_destination_operands, + ('CMP/HI' , 'Rm,Rn' ): cmp_hi__source_and_destination_operands, + ('CMP/GT' , 'Rm,Rn' ): cmp_gt__source_and_destination_operands, + ('CMP/STR', 'Rm,Rn' ): cmp_str__source_and_destination_operands, + ('DIV1' , 'Rm,Rn' ): div1__source_and_destination_operands, + ('DIV0S' , 'Rm,Rn' ): div0s__source_and_destination_operands, + ('DMULS.L', 'Rm,Rn' ): dmuls_l__source_and_destination_operands, + ('DMULU.L', 'Rm,Rn' ): dmulu_l__source_and_destination_operands, + ('EXTS.B' , 'Rm,Rn' ): exts_b__source_and_destination_operands, + ('EXTS.W' , 'Rm,Rn' ): exts_w__source_and_destination_operands, + ('EXTU.B' , 'Rm,Rn' ): extu_b__source_and_destination_operands, + ('EXTU.W' , 'Rm,Rn' ): extu_w__source_and_destination_operands, + ('MOV' , 'Rm,Rn' ): mov__source_and_destination_operands, + ('MUL.L' , 'Rm,Rn' ): mul_l__source_and_destination_operands, + ('MULS.W' , 'Rm,Rn' ): muls_w__source_and_destination_operands, + ('MULU.W' , 'Rm,Rn' ): mulu_w__source_and_destination_operands, + ('NEG' , 'Rm,Rn' ): neg__source_and_destination_operands, + ('NEGC' , 'Rm,Rn' ): negc__source_and_destination_operands, + ('NOT' , 'Rm,Rn' ): not__source_and_destination_operands, + ('OR' , 'Rm,Rn' ): or__source_and_destination_operands, + ('SUB' , 'Rm,Rn' ): sub__source_and_destination_operands, + ('SUBC' , 'Rm,Rn' ): subc__source_and_destination_operands, + ('SUBV' , 'Rm,Rn' ): subv__source_and_destination_operands, + ('SWAP.B' , 'Rm,Rn' ): swap_b__source_and_destination_operands, + ('SWAP.W' , 'Rm,Rn' ): swap_w__source_and_destination_operands, + ('TST' , 'Rm,Rn' ): tst__source_and_destination_operands, + ('XOR' , 'Rm,Rn' ): xor__source_and_destination_operands, + ('XTRCT' , 'Rm,Rn' ): xtrct__source_and_destination_operands, + ('LDC' , 'Rm,SR' ): ldc__transfer_to_sr, + ('LDC' , 'Rm,GBR' ): ldc__transfer_to_gbr, + ('LDC' , 'Rm,VBR' ): ldc__transfer_to_vbr, + ('LDS' , 'Rm,MACH' ): lds__transfer_to_mach, + ('LDS' , 'Rm,MACL' ): lds__transfer_to_macl, + ('LDS' , 'Rm,PR' ): lds__transfer_to_pr, + ('STC' , 'SR,Rn' ): stc__transfer_from_sr, + ('STC' , 'GBR,Rn' ): stc__transfer_from_gbr, + ('STC' , 'VBR,Rn' ): stc__transfer_from_vbr, + ('STS' , 'MACH,Rn' ): sts__transfer_from_mach, + ('STS' , 'MACL,Rn' ): sts__transfer_from_macl, + ('STS' , 'PR,Rn' ): sts__transfer_from_pr, + ('JMP' , '@Rn' ): jmp__destination_operand_only, + ('JSR' , '@Rn' ): jsr__destination_operand_only, + ('TAS.B' , '@Rn' ): tas_b__destination_operand_only, + ('MOV.B' , 'Rm,@Rn' ): mov_b__store_register_direct_data_transfer, + ('MOV.W' , 'Rm,@Rn' ): mov_w__store_register_direct_data_transfer, + ('MOV.L' , 'Rm,@Rn' ): mov_l__store_register_direct_data_transfer, + ('MOV.B' , '@Rm,Rn' ): mov_b__load_register_direct_data_transfer, + ('MOV.W' , '@Rm,Rn' ): mov_w__load_register_direct_data_transfer, + ('MOV.L' , '@Rm,Rn' ): mov_l__load_register_direct_data_transfer, + ('MAC.L' , '@Rm+,@Rn+' ): mac_l__multiply_and_accumulate_operation, + ('MAC.W' , '@Rm+,@Rn+' ): mac_w__multiply_and_accumulate_operation, + ('MOV.B' , '@Rm+,Rn' ): mov_b__load_direct_data_transfer_from_register, + ('MOV.W' , '@Rm+,Rn' ): mov_w__load_direct_data_transfer_from_register, + ('MOV.L' , '@Rm+,Rn' ): mov_l__load_direct_data_transfer_from_register, + ('LDC.L' , '@Rm+,SR' ): ldc_l__load_to_sr, + ('LDC.L' , '@Rm+,GBR' ): ldc_l__load_to_gbr, + ('LDC.L' , '@Rm+,VBR' ): ldc_l__load_to_vbr, + ('LDS.L' , '@Rm+,MACH' ): lds_l__load_to_mach, + ('LDS.L' , '@Rm+,MACL' ): lds_l__load_to_macl, + ('LDS.L' , '@Rm+,PR' ): lds_l__load_to_pr, + ('MOV.B' , 'Rm,@-Rn' ): mov_b__store_direct_data_transfer_from_register, + ('MOV.W' , 'Rm,@-Rn' ): mov_w__store_direct_data_transfer_from_register, + ('MOV.L' , 'Rm,@-Rn' ): mov_l__store_direct_data_transfer_from_register, + ('STC.L' , 'SR,@-Rn' ): stc_l__store_from_sr, + ('STC.L' , 'GBR,@-Rn' ): stc_l__store_from_gbr, + ('STC.L' , 'VBR,@-Rn' ): stc_l__store_from_vbr, + ('STS.L' , 'MACH,@-Rn' ): sts_l__store_from_mach, + ('STS.L' , 'MACL,@-Rn' ): sts_l__store_from_macl, + ('STS.L' , 'PR,@-Rn' ): sts_l__store_from_pr, + ('MOV.B' , 'R0,@(disp,Rn)' ): mov_b__store_register_indirect_with_displacement, + ('MOV.W' , 'R0,@(disp,Rn)' ): mov_w__store_register_indirect_with_displacement, + ('MOV.L' , 'Rm,@(disp,Rn)' ): mov_l__store_register_indirect_with_displacement, + ('MOV.B' , '@(disp,Rm),R0' ): mov_b__load_register_indirect_with_displacement, + ('MOV.W' , '@(disp,Rm),R0' ): mov_w__load_register_indirect_with_displacement, + ('MOV.L' , '@(disp,Rm),Rn' ): mov_l__load_register_indirect_with_displacement, + ('MOV.B' , 'Rm,@(R0,Rn)' ): mov_b__store_indexed_register_indirect, + ('MOV.W' , 'Rm,@(R0,Rn)' ): mov_w__store_indexed_register_indirect, + ('MOV.L' , 'Rm,@(R0,Rn)' ): mov_l__store_indexed_register_indirect, + ('MOV.B' , '@(R0,Rm),Rn' ): mov_b__load_indexed_register_indirect, + ('MOV.W' , '@(R0,Rm),Rn' ): mov_w__load_indexed_register_indirect, + ('MOV.L' , '@(R0,Rm),Rn' ): mov_l__load_indexed_register_indirect, + ('MOV.B' , 'R0,@(disp,GBR)'): mov_b__store_gbr_indirect_with_displacement, + ('MOV.W' , 'R0,@(disp,GBR)'): mov_w__store_gbr_indirect_with_displacement, + ('MOV.L' , 'R0,@(disp,GBR)'): mov_l__store_gbr_indirect_with_displacement, + ('MOV.B' , '@(disp,GBR),R0'): mov_b__load_gbr_indirect_with_displacement, + ('MOV.W' , '@(disp,GBR),R0'): mov_w__load_gbr_indirect_with_displacement, + ('MOV.L' , '@(disp,GBR),R0'): mov_l__load_gbr_indirect_with_displacement, + ('AND.B' , '#imm,@(R0,GBR)'): and_b__store_indexed_gbr_indirect, + ('OR.B' , '#imm,@(R0,GBR)'): or_b__store_indexed_gbr_indirect, + ('TST.B' , '#imm,@(R0,GBR)'): tst_b__store_indexed_gbr_indirect, + ('XOR.B' , '#imm,@(R0,GBR)'): xor_b__store_indexed_gbr_indirect, + ('MOV.W' , '@(disp,PC),Rn' ): mov_w__pc_relative_with_displacement, + ('MOV.L' , '@(disp,PC),Rn' ): mov_l__pc_relative_with_displacement, + ('MOVA' , '@(disp,PC),R0' ): mova__pc_relative_with_displacement, + ('BRAF' , 'Rm' ): braf__destination_operand_only, + ('BSRF' , 'Rm' ): bsrf__destination_operand_only, + ('BF' , 'label' ): bf__pc_relative, + ('BF/S' , 'label' ): bf_s__pc_relative, + ('BT' , 'label' ): bt__pc_relative, + ('BT/S' , 'label' ): bt_s__pc_relative, + ('BRA' , 'label' ): bra__pc_relative, + ('BSR' , 'label' ): bsr__pc_relative, + ('ADD' , '#imm,Rn' ): add__immediate, + ('AND' , '#imm,R0' ): and__immediate, + ('CMP/EQ' , '#imm,R0' ): cmp_eq__immediate, + ('MOV' , '#imm,Rn' ): mov__immediate, + ('OR' , '#imm,R0' ): or__immediate, + ('TST' , '#imm,R0' ): tst__immediate, + ('XOR' , '#imm,R0' ): xor__immediate, + ('TRAPA' , '#imm' ): trapa__immediate, +} diff --git a/instruction_properties.py b/instruction_properties.py new file mode 100644 index 0000000..ce3fbe1 --- /dev/null +++ b/instruction_properties.py @@ -0,0 +1,47 @@ +def has_delay_slot(ins): + branches_with_delay_slots = { + "JMP", + "JSR", + "BRA", + "BRAF", + "BSR", + "BSRF", + "RTS", + "RTE", + "BT/S", + "BF/S" + } + return ins.instruction in branches_with_delay_slots + +def modifies_pc(ins): + modifies_pc = { + "JMP", + "JSR", + "BRA", + "BRAF", + "BSR", + "BSRF", + "RTS", + "RTE", + "BT", + "BF", + "BT/S", + "BF/S", + "TRAPA", + } + modifies_pc_with_operands = { + ("LDC" , "Rm,SR" ), + ("LDC.L", "@Rm+,SR"), + } + return ( + ins.instruction in modifies_pc + or (ins.instruction, ins.operands) in modifies_pc_with_operands + ) + +def is_pc_relative_mov_or_mova(ins): + pc_relative_mov_or_mova = { + ("MOV.W", "@(disp,PC),Rn"), + ("MOV.L", "@(disp,PC),Rn"), + ("MOVA" , "@(disp,PC),R0"), + } + return (ins.instruction, ins.operands) in pc_relative_mov_or_mova diff --git a/instruction_table.py b/instruction_table.py new file mode 100644 index 0000000..37f8fd4 --- /dev/null +++ b/instruction_table.py @@ -0,0 +1,235 @@ +from collections import defaultdict +from dataclasses import dataclass +from pprint import pprint +import os +import inspect + +@dataclass +class Instruction: + instruction: str + operands: str + variables: list[str] + code: str + operation: str + +_operands = { + "Rn", + "Rm", + "R0", + "GBR", + "SR", + "VBR", + "MACH", + "MACL", + "R0", +} + +def _b16_str(n): + for i in reversed(range(16)): + yield chr(ord('0') + ((n >> i) & 1)) + +def b16_str(n): + return ''.join(_b16_str(n)) + +@dataclass +class CodeOperand: + operand: str + lsb: int + length: int + +@dataclass +class Code: + code_bits: int + mask_bits: int + operands: list[CodeOperand] + +_operand_bits = { + 'i', + 'n', + 'm', + 'd', +} + +def assert_contiguous(bits): + assert len(bits) == len(set(bits)) + for i, bit in enumerate(bits[:-1]): + assert abs(bit - bits[i+1]) == 1 + return bits + +def parse_code(code): + operands_list = defaultdict(list) + code_bits_list = [] + mask_bits_list = [] + for i, digit in enumerate(reversed(code)): + if digit not in {'0','1'}: + assert digit in _operand_bits, (digit, code) + operands_list[digit].append(i) + mask_bits_list.append(i) + else: + code_bits_list.append((i, int(digit))) + + code_bits = 0 + for i, digit in code_bits_list: + code_bits |= (digit << i) + mask_bits = 0xffff + for i in mask_bits_list: + mask_bits &= ~(1 << i) + operands = { + operand: + CodeOperand( + operand=operand, + lsb=min(assert_contiguous(bits)), + length=len(bits) + ) + for operand, bits in operands_list.items() + } + return Code( + code_bits=code_bits, + mask_bits=mask_bits, + operands=operands + ) + +def get_variable(token): + variables = { + 'Rm': 'm', + 'Rn': 'n', + 'disp': 'd', + 'imm': 'i', + 'label': 'd', + # SH4 + "Rm_BANK": 'm', + "Rn_BANK": 'n', + # SH4 floating point + "FRm": 'm', + "FRn": 'n', + "DRm": 'm', + "DRn": 'n', + "XDm": 'm', + "XDn": 'n', + "FVm": 'm', + "FVn": 'n', + } + non_variables = { + "GBR", + "VBR", + "MACH", + "MACL", + "SR", + "PR", + "PC", + "R0", + # SH4 + "SSR", + "SPC", + "DBR", + "SGR", + # SH4 floating point + "FPUL", + "FR0", + "FPSCR", + "XMTRX", + } + if token in variables: + yield variables[token] + elif token in non_variables: + return + else: + assert False, token + +def parse_tokens(operands): + if operands == '': + return + span = 0 + i = 0 + while i != len(operands): + c = operands[i] + if c in {'(', '#', '@', '-'}: + span = i + 1 + elif c in {',', ')', '+'}: + if span != i: + yield operands[span:i] + span = i + 1 + i += 1 + assert operands[-1] != ',' + if span != len(operands): + yield operands[span:] + +def parse_variables(operands): + for token in parse_tokens(operands): + yield from get_variable(token) + + +def parse_instruction(*, instruction, operands, code, operation, **kwargs): + code = parse_code(code) + variables = tuple(parse_variables(operands)) + + return ( + instruction, + operands, + variables, + code, + operation, + ) + +def untabulate_instructions(filename, columns): + with open(filename, 'r') as f: + buf = f.read() + + instructions = [] + + for line in buf.split('\n'): + def column(s): + start, end = columns[s] + return line[start:end] + + if not line.strip(): + continue + assert '\t' not in line, line + if line and line[0] == ' ': + assert len(line.strip()) == len(column("operation").strip()) + instructions[-1].operation = " ".join([ + instructions[-1].operation, line.strip() + ]) + continue + instruction = Instruction(*parse_instruction(**dict([ + (name, line[start:end].strip()) + for name, (start, end) in columns.items() + ]))) + instructions.append(instruction) + + return instructions + +def column_bounds(columns): + for ix, (name, start) in enumerate(columns): + if ix == len(columns) - 1: + end = None + else: + end = columns[ix+1][1] + yield name, (start, end) + + +directory = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) + +def untabulate_instructions_sh2(): + columns = dict(column_bounds([ + ("instruction", 0 ), + ("operands" , 8 ), + ("code" , 23 ), + ("operation" , 42 ), + ("state" , 88 ), + ("t_bit" , 102) + ])) + + return untabulate_instructions(os.path.join(directory, "sh2.txt"), columns) + +def untabulate_instructions_sh4(): + columns = dict(column_bounds([ + ("instruction", 0 ), + ("operands" , 8 ), + ("operation" , 24 ), + ("code" , 80 ), + ("privileged" , 104), + ("t_bit" , 116) + ])) + + return untabulate_instructions(os.path.join(directory, "sh4.txt"), columns) diff --git a/log.py b/log.py new file mode 100644 index 0000000..68609a0 --- /dev/null +++ b/log.py @@ -0,0 +1,10 @@ +_log = [] + +def log(*args): + _log.append(" ".join(map(str, args))) + +def raw_log(*args): + _log.append(args) + +def get_log(): + return _log diff --git a/mem.py b/mem.py new file mode 100644 index 0000000..1820c48 --- /dev/null +++ b/mem.py @@ -0,0 +1,48 @@ +from collections import defaultdict + +class Memory: + def __init__(self): + self._mem = defaultdict(int) + + def read32(self, address): + assert (address & 0b11) == 0, address + a = self._mem[address + 0] + b = self._mem[address + 1] + c = self._mem[address + 2] + d = self._mem[address + 3] + return ( + (a << 24) + | (b << 16) + | (c << 8 ) + | (d << 0 ) + ) + + def read16(self, address): + assert (address & 0b1) == 0, address + a = self._mem[address + 0] + b = self._mem[address + 1] + return ( + (a << 8 ) + | (b << 0 ) + ) + + def read8(self, address): + return self._mem[address + 0] + + def write32(self, address, value): + assert type(value) is int + assert (address & 0b11) == 0, address + self._mem[address + 0] = (value >> 24) & 0xff + self._mem[address + 1] = (value >> 16) & 0xff + self._mem[address + 2] = (value >> 8 ) & 0xff + self._mem[address + 3] = (value >> 0 ) & 0xff + + def write16(self, address, value): + assert type(value) is int + assert (address & 0b1 ) == 0, address + self._mem[address + 0] = (value >> 8 ) & 0xff + self._mem[address + 1] = (value >> 0 ) & 0xff + + def write8(self, address, value): + assert type(value) is int + self._mem[address + 0] = (value >> 0 ) & 0xff diff --git a/operations.py b/operations.py new file mode 100644 index 0000000..ed9be68 --- /dev/null +++ b/operations.py @@ -0,0 +1,94 @@ +__all__ = [ + 'sign_extend64', + 'sign_extend32', + 'sign_extend16', + 'sign_extend12', + 'sign_extend8', + 'zero_extend32', + 'zero_extend16', + 'zero_extend8', + 'zero_extend4', + 'zero_extend1', + 'signed_saturate48', + 'signed_saturate32', + 'register', + 'bit', +] + +# +# sign_extend +# + +def sign_extend(x, b): + m = 1 << (b - 1) + x = x & ((1 << b) - 1) + r = (x ^ m) - m; + return r + +def sign_extend64(x): + return sign_extend(x, 64) + +def sign_extend32(x): + return sign_extend(x, 32) + +def sign_extend16(x): + return sign_extend(x, 16) + +def sign_extend12(x): + return sign_extend(x, 12) + +def sign_extend8(x): + return sign_extend(x, 8) + +# +# zero_extend +# + +def zero_extend(x, b): + x = x & ((1 << b) - 1) + return x + +def zero_extend32(x): + return zero_extend(x, 32) + +def zero_extend16(x): + return zero_extend(x, 16) + +def zero_extend8(x): + return zero_extend(x, 8) + +def zero_extend4(x): + return zero_extend(x, 4) + +def zero_extend1(x): + return zero_extend(x, 1) + +# +# signed_saturate +# + +def signed_saturate(x, b): + upper = (2 ** (b - 1)) - 1 + lower = -(2 ** (b - 1)) + if x > upper: + return upper + elif x < lower: + return lower + else: + return x + +def signed_saturate48(x): + return signed_saturate(x, 48) + +def signed_saturate32(x): + return signed_saturate(x, 32) + +# +# "convenience" functions +# + +def register(x): + return zero_extend(x, 32) + +def bit(x): + return zero_extend(x, 1) diff --git a/sh2-vs-sh4.txt b/sh2-vs-sh4.txt new file mode 100644 index 0000000..fa1bb8b --- /dev/null +++ b/sh2-vs-sh4.txt @@ -0,0 +1,31 @@ +only in sh2: + +only in sh4: (26 new instructions) +SHAD Rm,Rn When Rn ≥ 0, Rn << Rm → Rn When Rn < 0, Rn >> Rm → [MSB → Rn] +SHLD Rm,Rn When Rn ≥ 0, Rn << Rm → Rn When Rn < 0, Rn >> Rm → [0 → Rn] +LDC Rm,SSR Rm → SSR +LDC Rm,SPC Rm → SPC +LDC Rm,DBR Rm → DBR +LDC Rm,Rn_BANK Rm → Rn_BANK (n = 0 to 7) +LDC.L @Rm+,SSR (Rm) → SSR, Rm + 4 → Rm +LDC.L @Rm+,SPC (Rm) → SPC, Rm + 4 → Rm +LDC.L @Rm+,DBR (Rm) → DBR, Rm + 4 → Rm +LDC.L @Rm+,Rn_BANK (Rm) → Rn_BANK, Rm + 4 → Rm +LDTLB PTEH/PTEL → TLB +MOVCA.L R0,@Rn R0 → (Rn) (without fetching cache block) +OCBI @Rn Invalidates operand cache block +OCBP @Rn Writes back and invalidates operand cache block +OCBWB @Rn Writes back operand cache block +PREF @Rn (Rn) → operand cache +STC SSR,Rn SSR → Rn +STC SPC,Rn SPC → Rn +STC SGR,Rn SGR → Rn +STC DBR,Rn DBR → Rn +STC Rm_BANK,Rn Rm_BANK → Rn (m = 0 to 7) +STC.L SSR,@-Rn Rn – 4 → Rn, SSR → (Rn) +STC.L SPC,@-Rn Rn – 4 → Rn, SPC → (Rn) +STC.L SGR,@-Rn Rn – 4 → Rn, SGR → (Rn) +STC.L DBR,@-Rn Rn – 4 → Rn, DBR → (Rn) +STC.L Rm_BANK,@-Rn Rn – 4 → Rn, Rm_BANK → (Rn) (m = 0 to 7) + +floating point: diff --git a/sh2.py b/sh2.py new file mode 100644 index 0000000..ef429e0 --- /dev/null +++ b/sh2.py @@ -0,0 +1,89 @@ +import array +from dataclasses import dataclass + +from decode import decode_instruction + +class RegisterFile: + def __init__(self): + object.__setattr__(self, "_reg", [0] * 16) + + def __getitem__(self, key): + return self._reg[key] + + def __setitem__(self, key, value): + assert value >= 0 and value <= 0xffff_ffff, value + self._reg[key] = value + + def __setattr__(self, name, value): + raise AttributeError(name) + +class StatusRegister: + def __init__(self): + self.m = 0 + self.q = 0 + self.i = 0b1111 + self.s = 0 + self.t = 0 + + def get_value(self): + return (0 + | (self.m & 0b1 ) << 9 + | (self.q & 0b1 ) << 8 + | (self.i & 0b1111) << 4 + | (self.s & 0b1 ) << 1 + | (self.t & 0b1 ) << 0 + ) + + def set_value(self, value): + self.m = (value >> 9) & 0b1 + self.q = (value >> 8) & 0b1 + self.i = (value >> 4) & 0b1111 + self.s = (value >> 1) & 0b1 + self.t = (value >> 0) & 0b1 + + def __setattr__(self, name, value): + assert type(value) == int, (name, value) + if name in {'m', 'q', 's', 't'}: + assert value in {0, 1}, (name, value) + object.__setattr__(self, name, value) + elif name == 'i': + assert value >= 0 and value <= 15, (name, value) + object.__setattr__(self, name, value) + else: + raise AttributeError(name) + +@dataclass +class SH2: + def __init__(self): + self.reg = RegisterFile() + self.sr = StatusRegister() + self.gbr = 0 + self.vbr = 0 + self.mach = 0 + self.macl = 0 + self.pr = 0 + self.pr1 = 0 + self.pr2 = self.pr + self.pc = 0 + self.pc1 = 0 + self.pc2 = self.pc + 2 + self.is_delay_slot = False + + def __setattr__(self, name, value): + if name in {'gbr', 'vbr', 'mach', 'macl', + 'pr' , 'pr1', 'pr2', + 'pc' , 'pc1', 'pc2'}: + assert type(value) is int, value + assert value >= 0 and value <= 0xffff_ffff, value + object.__setattr__(self, name, value) + elif name == 'reg': + assert type(value) == RegisterFile + object.__setattr__(self, name, value) + elif name == 'sr': + assert type(value) == StatusRegister + object.__setattr__(self, name, value) + elif name == 'is_delay_slot': + assert type(value) == bool + object.__setattr__(self, name, value) + else: + raise AttributeError(name) diff --git a/sh2.txt b/sh2.txt new file mode 100644 index 0000000..2bf541a --- /dev/null +++ b/sh2.txt @@ -0,0 +1,170 @@ +CLRS 0000000001001000 0 → S 1 — +CLRT 0000000000001000 0 → T 1 0 +CLRMAC 0000000000101000 0 → MACH, MACL 1 — +DIV0U 0000000000011001 0 → M/Q/T 1 0 +NOP 0000000000001001 No operation 1 — +RTE 0000000000101011 Delayed branch, Stack area → PC/SR 4 LSB +RTS 0000000000001011 Delayed branch, PR → PC 2 — +SETS 0000000001011000 1 → S 1 — +SETT 0000000000011000 1 → T 1 1 +SLEEP 0000000000011011 Sleep 3 — + +CMP/PL Rn 0100nnnn00010101 Rn > 0, 1 → T 1 Comparison result +CMP/PZ Rn 0100nnnn00010001 Rn ≥ 0, 1 → T 1 Comparison result +DT Rn 0100nnnn00010000 Rn – 1 → Rn When Rn is 0, 1 → T, 1 Comparison result + when Rn is nonzero, 0 → T +MOVT Rn 0000nnnn00101001 T → Rn 1 — +ROTL Rn 0100nnnn00000100 T ← Rn ← MSB 1 MSB +ROTR Rn 0100nnnn00000101 LSB → Rn → T 1 LSB +ROTCL Rn 0100nnnn00100100 T ← Rn ← T 1 MSB +ROTCR Rn 0100nnnn00100101 T → Rn → T 1 LSB +SHAL Rn 0100nnnn00100000 T ← Rn ← 0 1 MSB +SHAR Rn 0100nnnn00100001 MSB → Rn → T 1 LSB +SHLL Rn 0100nnnn00000000 T ← Rn ← 0 1 MSB +SHLR Rn 0100nnnn00000001 0 → Rn → T 1 LSB +SHLL2 Rn 0100nnnn00001000 Rn<<2 → Rn 1 — +SHLR2 Rn 0100nnnn00001001 Rn>>2 → Rn 1 — +SHLL8 Rn 0100nnnn00011000 Rn<<8 → Rn 1 — +SHLR8 Rn 0100nnnn00011001 Rn>>8 → Rn 1 — +SHLL16 Rn 0100nnnn00101000 Rn<<16 → Rn 1 — +SHLR16 Rn 0100nnnn00101001 Rn>>16 → Rn 1 — + +ADD Rm,Rn 0011nnnnmmmm1100 Rn + Rm → Rn 1 — +ADDC Rm,Rn 0011nnnnmmmm1110 Rn + Rm + T → Rn, carry → T 1 Carry +ADDV Rm,Rn 0011nnnnmmmm1111 Rn + Rm → Rn, overflow → T 1 Overflow +AND Rm,Rn 0010nnnnmmmm1001 Rn & Rm → Rn 1 — +CMP/EQ Rm,Rn 0011nnnnmmmm0000 When Rn = Rm, 1 → T 1 Comparison result +CMP/HS Rm,Rn 0011nnnnmmmm0010 When unsigned and Rn ≥ Rm, 1 → T 1 Comparison result +CMP/GE Rm,Rn 0011nnnnmmmm0011 When signed and Rn ≥ Rm, 1 → T 1 Comparison result +CMP/HI Rm,Rn 0011nnnnmmmm0110 When unsigned and Rn > Rm, 1 → T 1 Comparison result +CMP/GT Rm,Rn 0011nnnnmmmm0111 When signed and Rn > Rm, 1 → T 1 Comparison result +CMP/STR Rm,Rn 0010nnnnmmmm1100 When a byte in Rn equals bytes in Rm, 1 → T 1 Comparison result +DIV1 Rm,Rn 0011nnnnmmmm0100 1–step division (Rn ÷ Rm) 1 Calculation result +DIV0S Rm,Rn 0010nnnnmmmm0111 MSB of Rn → Q, MSB of Rm → M, M ^ Q → T 1 Calculation result +DMULS.L Rm,Rn 0011nnnnmmmm1101 Signed, Rn × Rm → MACH, MACL 2 to 4 — +DMULU.L Rm,Rn 0011nnnnmmmm0101 Unsigned, Rn × Rm → MACH, MACL 2 to 4 — +EXTS.B Rm,Rn 0110nnnnmmmm1110 Sign – extends Rm from byte → Rn 1 — +EXTS.W Rm,Rn 0110nnnnmmmm1111 Sign – extends Rm from word → Rn 1 — +EXTU.B Rm,Rn 0110nnnnmmmm1100 Zero – extends Rm from byte → Rn 1 — +EXTU.W Rm,Rn 0110nnnnmmmm1101 Zero – extends Rm from word → Rn 1 — +MOV Rm,Rn 0110nnnnmmmm0011 Rm → Rn 1 — +MUL.L Rm,Rn 0000nnnnmmmm0111 Rn × Rm → MACL 2 to 4 — +MULS.W Rm,Rn 0010nnnnmmmm1111 Signed, Rn × Rm → MAC 1 to 3 — +MULU.W Rm,Rn 0010nnnnmmmm1110 Unsigned, Rn × Rm → MAC 1 to 3 — +NEG Rm,Rn 0110nnnnmmmm1011 0 – Rm → Rn 1 — +NEGC Rm,Rn 0110nnnnmmmm1010 0 – Rm – T → Rn, Borrow → T 1 Borrow + +NOT Rm,Rn 0110nnnnmmmm0111 ~Rm → Rn 1 — +OR Rm,Rn 0010nnnnmmmm1011 Rn | Rm → Rn 1 — +SUB Rm,Rn 0011nnnnmmmm1000 Rn – Rm → Rn 1 — +SUBC Rm,Rn 0011nnnnmmmm1010 Rn – Rm – T → Rn, Borrow → T 1 Borrow +SUBV Rm,Rn 0011nnnnmmmm1011 Rn – Rm → Rn, Underflow → T 1 Underflow +SWAP.B Rm,Rn 0110nnnnmmmm1000 Rm → Swap upper and lower halves of 1 — + lower 2 bytes → Rn +SWAP.W Rm,Rn 0110nnnnmmmm1001 Rm → Swap upper and lower word → Rn 1 — +TST Rm,Rn 0010nnnnmmmm1000 Rn & Rm, when result is 0, 1 → T 1 Test results +XOR Rm,Rn 0010nnnnmmmm1010 Rn ^ Rm → Rn 1 — +XTRCT Rm,Rn 0010nnnnmmmm1101 Center 32 bits of Rm and Rn → Rn 1 — + +LDC Rm,SR 0100mmmm00001110 Rm → SR 1 LSB +LDC Rm,GBR 0100mmmm00011110 Rm → GBR 1 — +LDC Rm,VBR 0100mmmm00101110 Rm → VBR 1 — +LDS Rm,MACH 0100mmmm00001010 Rm → MACH 1 — +LDS Rm,MACL 0100mmmm00011010 Rm → MACL 1 — +LDS Rm,PR 0100mmmm00101010 Rm → PR 1 — +STC SR,Rn 0000nnnn00000010 SR → Rn 1 — +STC GBR,Rn 0000nnnn00010010 GBR → Rn 1 — +STC VBR,Rn 0000nnnn00100010 VBR → Rn 1 — +STS MACH,Rn 0000nnnn00001010 MACH → Rn 1 — +STS MACL,Rn 0000nnnn00011010 MACL → Rn 1 — +STS PR,Rn 0000nnnn00101010 PR → Rn 1 — + +JMP @Rn 0100nnnn00101011 Delayed branch, Rn → PC 2 — +JSR @Rn 0100nnnn00001011 Delayed branch, PC → PR, Rn → PC 2 — +TAS.B @Rn 0100nnnn00011011 When (Rn) is 0, 1 → T, 1 → MSB of (Rn) 4 Test results + +MOV.B Rm,@Rn 0010nnnnmmmm0000 Rm → (Rn) 1 — +MOV.W Rm,@Rn 0010nnnnmmmm0001 Rm → (Rn) 1 — +MOV.L Rm,@Rn 0010nnnnmmmm0010 Rm → (Rn) 1 — +MOV.B @Rm,Rn 0110nnnnmmmm0000 (Rm) → sign extension → Rn 1 — +MOV.W @Rm,Rn 0110nnnnmmmm0001 (Rm) → sign extension → Rn 1 — +MOV.L @Rm,Rn 0110nnnnmmmm0010 (Rm) → Rn 1 — + +MAC.L @Rm+,@Rn+ 0000nnnnmmmm1111 Signed, (Rn) × (Rm) + MAC → MAC 3/(2 to 4) — +MAC.W @Rm+,@Rn+ 0100nnnnmmmm1111 Signed, (Rn) × (Rm) + MAC → MAC 3/(2) — + +MOV.B @Rm+,Rn 0110nnnnmmmm0100 (Rm) → sign extension → Rn, Rm + 1 → Rm 1 — +MOV.W @Rm+,Rn 0110nnnnmmmm0101 (Rm) → sign extension → Rn, Rm + 2 → Rm 1 — +MOV.L @Rm+,Rn 0110nnnnmmmm0110 (Rm) → Rn, Rm + 4 → Rm 1 — + +LDC.L @Rm+,SR 0100mmmm00000111 (Rm) → SR, Rm + 4 → Rm 3 LSB +LDC.L @Rm+,GBR 0100mmmm00010111 (Rm) → GBR, Rm + 4 → Rm 3 — +LDC.L @Rm+,VBR 0100mmmm00100111 (Rm) → VBR, Rm + 4 → Rm 3 — +LDS.L @Rm+,MACH 0100mmmm00000110 (Rm) → MACH, Rm + 4 → Rm 1 — +LDS.L @Rm+,MACL 0100mmmm00010110 (Rm) → MACL, Rm + 4 → Rm 1 — +LDS.L @Rm+,PR 0100mmmm00100110 (Rm) → PR, Rm + 4 → Rm 1 — + +MOV.B Rm,@-Rn 0010nnnnmmmm0100 Rn – 1 → Rn, Rm → (Rn) 1 — +MOV.W Rm,@-Rn 0010nnnnmmmm0101 Rn – 2 → Rn, Rm → (Rn) 1 — +MOV.L Rm,@-Rn 0010nnnnmmmm0110 Rn – 4 → Rn, Rm → (Rn) 1 — + +STC.L SR,@-Rn 0100nnnn00000011 Rn – 4 → Rn, SR → (Rn) 2 — +STC.L GBR,@-Rn 0100nnnn00010011 Rn – 4 → Rn, GBR → (Rn) 2 — +STC.L VBR,@-Rn 0100nnnn00100011 Rn – 4 → Rn, VBR → (Rn) 2 — +STS.L MACH,@-Rn 0100nnnn00000010 Rn – 4 → Rn, MACH → (Rn) 1 — +STS.L MACL,@-Rn 0100nnnn00010010 Rn – 4 → Rn, MACL → (Rn) 1 — +STS.L PR,@-Rn 0100nnnn00100010 Rn – 4 → Rn, PR → (Rn) 1 — + +MOV.B R0,@(disp,Rn) 10000000nnnndddd R0 → (disp + Rn) 1 — +MOV.W R0,@(disp,Rn) 10000001nnnndddd R0 → (disp × 2 + Rn) 1 — +MOV.L Rm,@(disp,Rn) 0001nnnnmmmmdddd Rm → (disp × 4 + Rn) 1 — +MOV.B @(disp,Rm),R0 10000100mmmmdddd (disp + Rm) → sign extension → R0 1 — +MOV.W @(disp,Rm),R0 10000101mmmmdddd (disp × 2 + Rm) → sign extension → R0 1 — +MOV.L @(disp,Rm),Rn 0101nnnnmmmmdddd (disp × 4 + Rm) → Rn 1 — + +MOV.B Rm,@(R0,Rn) 0000nnnnmmmm0100 Rm → (R0 + Rn) 1 — +MOV.W Rm,@(R0,Rn) 0000nnnnmmmm0101 Rm → (R0 + Rn) 1 — +MOV.L Rm,@(R0,Rn) 0000nnnnmmmm0110 Rm → (R0 + Rn) 1 — +MOV.B @(R0,Rm),Rn 0000nnnnmmmm1100 (R0 + Rm) → sign extension → Rn 1 — +MOV.W @(R0,Rm),Rn 0000nnnnmmmm1101 (R0 + Rm) → sign extension → Rn 1 — +MOV.L @(R0,Rm),Rn 0000nnnnmmmm1110 (R0 + Rm) → Rn 1 — + +MOV.B R0,@(disp,GBR) 11000000dddddddd R0 → (disp + GBR) 1 — +MOV.W R0,@(disp,GBR) 11000001dddddddd R0 → (disp × 2 + GBR) 1 — +MOV.L R0,@(disp,GBR) 11000010dddddddd R0 → (disp × 4 + GBR) 1 — +MOV.B @(disp,GBR),R0 11000100dddddddd (disp + GBR) → sign extension → R0 1 — +MOV.W @(disp,GBR),R0 11000101dddddddd (disp × 2 + GBR) → sign extension → R0 1 — +MOV.L @(disp,GBR),R0 11000110dddddddd (disp × 4 + GBR) → R0 1 — + +AND.B #imm,@(R0,GBR) 11001101iiiiiiii (R0 + GBR) & imm → (R0 + GBR) 3 — +OR.B #imm,@(R0,GBR) 11001111iiiiiiii (R0 + GBR) | imm → (R0 + GBR) 3 — +TST.B #imm,@(R0,GBR) 11001100iiiiiiii (R0 + GBR) & imm, when result is 0, 1 → T 3 Test results +XOR.B #imm,@(R0,GBR) 11001110iiiiiiii (R0 + GBR) ^ imm → (R0 + GBR) 3 — + +MOV.W @(disp,PC),Rn 1001nnnndddddddd (disp × 2 + PC) → sign extension → Rn 1 — +MOV.L @(disp,PC),Rn 1101nnnndddddddd (disp × 4 + PC) → Rn 1 — +MOVA @(disp,PC),R0 11000111dddddddd disp × 4 + PC → R0 1 — + +BRAF Rn 0000nnnn00100011 Delayed branch, Rn + PC → PC 2 — +BSRF Rn 0000nnnn00000011 Delayed branch, PC → PR, Rn + PC → PC 2 — + +BF label 10001011dddddddd When T = 0, disp × 2 + PC → PC; 3/1 — + When T = 1, nop +BF/S label 10001111dddddddd When T = 0, disp × 2 + PC → PC; 2/1 — + When T = 1, nop +BT label 10001001dddddddd When T = 1, disp × 2+ PC → PC; 3/1 — + When T = 0, nop +BT/S label 10001101dddddddd When T = 1, disp × 2 + PC → PC; 2/1 — + When T = 0, nop +BRA label 1010dddddddddddd Delayed branch, disp × 2 + PC → PC 2 — +BSR label 1011dddddddddddd Delayed branch, PC → PR, disp × 2 + PC → PC 2 — + +ADD #imm,Rn 0111nnnniiiiiiii Rn + imm → Rn 1 — +AND #imm,R0 11001001iiiiiiii R0 & imm → R0 1 — +CMP/EQ #imm,R0 10001000iiiiiiii When R0 = imm, 1 → T 1 Comparison result +MOV #imm,Rn 1110nnnniiiiiiii imm → sign extension → Rn 1 — +OR #imm,R0 11001011iiiiiiii R0 | imm → R0 1 — +TST #imm,R0 11001000iiiiiiii R0 & imm, when result is 0, 1 → T 1 Test results +XOR #imm,R0 11001010iiiiiiii R0 ^ imm → R0 1 — + +TRAPA #imm 11000011iiiiiiii PC/SR → Stack area, (imm × 4 + VBR) → PC 8 — diff --git a/sh4.txt b/sh4.txt new file mode 100644 index 0000000..a9981d0 --- /dev/null +++ b/sh4.txt @@ -0,0 +1,254 @@ +MOV #imm,Rn imm → sign extension → Rn 1110nnnniiiiiiii — — +MOV.W @(disp,PC),Rn (disp × 2 + PC + 4) → sign extension → Rn 1001nnnndddddddd — — +MOV.L @(disp,PC),Rn (disp × 4 + PC & 0xFFFFFFFC + 4) → Rn 1101nnnndddddddd — — +MOV Rm,Rn Rm → Rn 0110nnnnmmmm0011 — — +MOV.B Rm,@Rn Rm → (Rn) 0010nnnnmmmm0000 — — +MOV.W Rm,@Rn Rm → (Rn) 0010nnnnmmmm0001 — — +MOV.L Rm,@Rn Rm → (Rn) 0010nnnnmmmm0010 — — +MOV.B @Rm,Rn (Rm) → sign extension → Rn 0110nnnnmmmm0000 — — +MOV.W @Rm,Rn (Rm) → sign extension → Rn 0110nnnnmmmm0001 — — +MOV.L @Rm,Rn (Rm) → Rn 0110nnnnmmmm0010 — — +MOV.B Rm,@-Rn Rn-1 → Rn, Rm → (Rn) 0010nnnnmmmm0100 — — +MOV.W Rm,@-Rn Rn-2 → Rn, Rm → (Rn) 0010nnnnmmmm0101 — — +MOV.L Rm,@-Rn Rn-4 → Rn, Rm → (Rn) 0010nnnnmmmm0110 — — +MOV.B @Rm+,Rn (Rm)→ sign extension → Rn, Rm + 1 → Rm 0110nnnnmmmm0100 — — +MOV.W @Rm+,Rn (Rm) → sign extension → Rn, Rm + 2 → Rm 0110nnnnmmmm0101 — — +MOV.L @Rm+,Rn (Rm) → Rn, Rm + 4 → Rm 0110nnnnmmmm0110 — — +MOV.B R0,@(disp,Rn) R0 → (disp + Rn) 10000000nnnndddd — — +MOV.W R0,@(disp,Rn) R0 → (disp × 2 + Rn) 10000001nnnndddd — — +MOV.L Rm,@(disp,Rn) Rm → (disp × 4 + Rn) 0001nnnnmmmmdddd — — +MOV.B @(disp,Rm),R0 (disp + Rm) → sign extension → R0 10000100mmmmdddd — — +MOV.W @(disp,Rm),R0 (disp × 2 + Rm) → sign extension → R0 10000101mmmmdddd — — +MOV.L @(disp,Rm),Rn (disp × 4 + Rm) → Rn 0101nnnnmmmmdddd — — +MOV.B Rm,@(R0,Rn) Rm → (R0 + Rn) 0000nnnnmmmm0100 — — +MOV.W Rm,@(R0,Rn) Rm → (R0 + Rn) 0000nnnnmmmm0101 — — +MOV.L Rm,@(R0,Rn) Rm → (R0 + Rn) 0000nnnnmmmm0110 — — +MOV.B @(R0,Rm),Rn (R0 + Rm) → sign extension → Rn 0000nnnnmmmm1100 — — +MOV.W @(R0,Rm),Rn (R0 + Rm) → sign extension → Rn 0000nnnnmmmm1101 — — +MOV.L @(R0,Rm),Rn (R0 + Rm) → Rn 0000nnnnmmmm1110 — — +MOV.B R0,@(disp,GBR) R0 → (disp + GBR) 11000000dddddddd — — +MOV.W R0,@(disp,GBR) R0 → (disp × 2 + GBR) 11000001dddddddd — — +MOV.L R0,@(disp,GBR) R0 → (disp × 4 + GBR) 11000010dddddddd — — +MOV.B @(disp,GBR),R0 (disp + GBR) → sign extension → R0 11000100dddddddd — — +MOV.W @(disp,GBR),R0 (disp × 2 + GBR) → sign extension → R0 11000101dddddddd — — +MOV.L @(disp,GBR),R0 (disp × 4 + GBR) → R0 11000110dddddddd — — +MOVA @(disp,PC),R0 disp × 4 + PC & 0xFFFFFFFC + 4 → R0 11000111dddddddd — — +MOVT Rn T → Rn 0000nnnn00101001 — — +SWAP.B Rm,Rn Rm → swap lower 2 bytes → REG 0110nnnnmmmm1000 — — +SWAP.W Rm,Rn Rm → swap upper/lower words → Rn 0110nnnnmmmm1001 — — +XTRCT Rm,Rn Rm:Rn middle 32 bits → Rn 0010nnnnmmmm1101 — — + +ADD Rm,Rn Rn + Rm → Rn 0011nnnnmmmm1100 — — +ADD #imm,Rn Rn + imm → Rn 0111nnnniiiiiiii — — +ADDC Rm,Rn Rn + Rm + T → Rn, carry → T 0011nnnnmmmm1110 — Carry +ADDV Rm,Rn Rn + Rm → Rn, overflow → T 0011nnnnmmmm1111 — Overflow +CMP/EQ #imm,R0 When R0 = imm, 1 → T Otherwise, 0 → T 10001000iiiiiiii — Comparison result +CMP/EQ Rm,Rn When Rn = Rm, 1 → T Otherwise, 0 → T 0011nnnnmmmm0000 — Comparison result +CMP/HS Rm,Rn When Rn ≥ Rm (unsigned), 1 → T Otherwise, 0 → T 0011nnnnmmmm0010 — Comparison result +CMP/GE Rm,Rn When Rn ≥ Rm (signed), 1 → T Otherwise, 0 → T 0011nnnnmmmm0011 — Comparison result +CMP/HI Rm,Rn When Rn > Rm (unsigned), 1 → T Otherwise, 0 → T 0011nnnnmmmm0110 — Comparison result +CMP/GT Rm,Rn When Rn > Rm (signed), 1 → T Otherwise, 0 → T 0011nnnnmmmm0111 — Comparison result +CMP/PZ Rn When Rn ≥ 0, 1 → T Otherwise, 0 → T 0100nnnn00010001 — Comparison result +CMP/PL Rn When Rn > 0, 1 → T Otherwise, 0 → T 0100nnnn00010101 — Comparison result +CMP/STR Rm,Rn When any bytes are equal, 1 → T Otherwise, 0 → T 0010nnnnmmmm1100 — Comparison result +DIV1 Rm,Rn 1-step division (Rn ÷ Rm) 0011nnnnmmmm0100 — Calculation result +DIV0S Rm,Rn MSB of Rn → Q, MSB of Rm → M, M^Q → T 0010nnnnmmmm0111 — Calculation result +DIV0U 0 → M/Q/T 0000000000011001 — 0 +DMULS.L Rm,Rn Signed, Rn × Rm → MAC, 32 × 32 → 64 bits 0011nnnnmmmm1101 — — +DMULU.L Rm,Rn Unsigned, Rn × Rm → MAC, 32 × 32 → 64 bits 0011nnnnmmmm0101 — — +DT Rn Rn – 1 → Rn; when Rn = 0, 1 → T When Rn ≠ 0, 0 → T 0100nnnn00010000 — Comparison result +EXTS.B Rm,Rn Rm sign-extended from byte → Rn 0110nnnnmmmm1110 — — +EXTS.W Rm,Rn Rm sign-extended from word → Rn 0110nnnnmmmm1111 — — +EXTU.B Rm,Rn Rm zero-extended from byte → Rn 0110nnnnmmmm1100 — — +EXTU.W Rm,Rn Rm zero-extended from word → Rn 0110nnnnmmmm1101 — — +MAC.L @Rm+,@Rn+ Signed, (Rn) × (Rm) + MAC → MAC 0000nnnnmmmm1111 — — + Rn + 4 → Rn, Rm + 4 → Rm 32 × 32 + 64 → 64 bits +MAC.W @Rm+,@Rn+ Signed, (Rn) × (Rm) + MAC → MAC 0100nnnnmmmm1111 — — + Rn + 2 → Rn, Rm + 2 → Rm 16 × 16 + 64 → 64 bit +MUL.L Rm,Rn Rn × Rm → MACL 32 × 32 → 32 bits 0000nnnnmmmm0111 — — +MULS.W Rm,Rn Signed, Rn × Rm → MACL 16 × 16 → 32 bits 0010nnnnmmmm1111 — — +MULU.W Rm,Rn Unsigned, Rn × Rm → MACL 16 × 16 → 32 bits 0010nnnnmmmm1110 — — +NEG Rm,Rn 0 – Rm → Rn 0110nnnnmmmm1011 — — +NEGC Rm,Rn 0 – Rm – T → Rn, borrow → T 0110nnnnmmmm1010 — Borrow +SUB Rm,Rn Rn – Rm → Rn 0011nnnnmmmm1000 — — +SUBC Rm,Rn Rn – Rm – T → Rn, borrow → T 0011nnnnmmmm1010 — Borrow +SUBV Rm,Rn Rn – Rm → Rn, underflow → T 0011nnnnmmmm1011 — Underflow +AND Rm,Rn Rn & Rm → Rn 0010nnnnmmmm1001 — — +AND #imm,R0 R0 & imm → R0 11001001iiiiiiii — — +AND.B #imm,@(R0,GBR) (R0 + GBR) & imm → (R0 + GBR) 11001101iiiiiiii — — +NOT Rm,Rn ~Rm → Rn 0110nnnnmmmm0111 — — +OR Rm,Rn Rn | Rm → Rn 0010nnnnmmmm1011 — — +OR #imm,R0 R0 | imm → R0 11001011iiiiiiii — — +OR.B #imm,@(R0,GBR) (R0 + GBR) | imm → (R0 + GBR) 11001111iiiiiiii — — +TAS.B @Rn When (Rn) = 0, 1 → T Otherwise, 0 → T 0100nnnn00011011 — Test result + In both cases, 1 → MSB of (Rn +TST Rm,Rn Rn & Rm; when result = 0, 1 → T Otherwise, 0 → T 0010nnnnmmmm1000 — Test result +TST #imm,R0 R0 & imm; when result = 0, 1 → T Otherwise, 0 → T 11001000iiiiiiii — Test result +TST.B #imm,@(R0,GBR) (R0 + GBR) & imm; when result = 0, 1 → T 11001100iiiiiiii — Test result + Otherwise, 0 → +XOR Rm,Rn Rn ∧ Rm → Rn 0010nnnnmmmm1010 — — +XOR #imm,R0 R0 ∧ imm → R0 11001010iiiiiiii — — +XOR.B #imm,@(R0,GBR) (R0 + GBR) ∧ imm → (R0 + GBR) 11001110iiiiiiii — — +ROTL Rn T ← Rn ← MSB 0100nnnn00000100 — MSB +ROTR Rn LSB → Rn → T 0100nnnn00000101 — LSB +ROTCL Rn T ← Rn ← T 0100nnnn00100100 — MSB +ROTCR Rn T → Rn → T 0100nnnn00100101 — LSB +SHAD Rm,Rn When Rn ≥ 0, Rn << Rm → Rn 0100nnnnmmmm1100 — — + When Rn < 0, Rn >> Rm → [MSB → Rn] +SHAL Rn T ← Rn ← 0 0100nnnn00100000 — MSB +SHAR Rn MSB → Rn → T 0100nnnn00100001 — LSB +SHLD Rm,Rn When Rn ≥ 0, Rn << Rm → Rn 0100nnnnmmmm1101 — — + When Rn < 0, Rn >> Rm → [0 → Rn] +SHLL Rn T ← Rn ← 0 0100nnnn00000000 — MSB +SHLR Rn 0 → Rn → T 0100nnnn00000001 — LSB +SHLL2 Rn Rn << 2 → Rn 0100nnnn00001000 — — +SHLR2 Rn Rn >> 2 → Rn 0100nnnn00001001 — — +SHLL8 Rn Rn << 8 → Rn 0100nnnn00011000 — — +SHLR8 Rn Rn >> 8 → Rn 0100nnnn00011001 — — +SHLL16 Rn Rn << 16 → Rn 0100nnnn00101000 — — +SHLR16 Rn Rn >> 16 → Rn 0100nnnn00101001 — — +BF label When T = 0, disp × 2 + PC + 4 → PC 10001011dddddddd — — + When T = 1, no +BF/S label Delayed branch; when T = 0, disp × 2 + PC + 4 → PC 10001111dddddddd — — + When T = 1, no +BT label When T = 1, disp × 2 + PC + 4 → PC 10001001dddddddd — — + When T = 0, no +BT/S label Delayed branch; when T = 1, disp × 2 + PC + 4 → PC 10001101dddddddd — — + When T = 0, no +BRA label Delayed branch, disp × 2 + PC + 4 → PC 1010dddddddddddd — — +BRAF Rn Rn + PC + 4 → PC 0000nnnn00100011 — — +BSR label Delayed branch, PC + 4 → PR, disp × 2 + PC + 4 → PC 1011dddddddddddd — — +BSRF Rn Delayed branch, PC + 4 → PR, Rn + PC + 4 → PC 0000nnnn00000011 — — +JMP @Rn Delayed branch, Rn → PC 0100nnnn00101011 — — +JSR @Rn Delayed branch, PC + 4 → PR, Rn → PC 0100nnnn00001011 — — +RTS Delayed branch, PR → PC 0000000000001011 — — +CLRMAC 0 → MACH, MACL 0000000000101000 — — +CLRS 0 → S 0000000001001000 — — +CLRT 0 → T 0000000000001000 — 0 +LDC Rm,SR Rm → SR 0100mmmm00001110 Privileged LSB +LDC Rm,GBR Rm → GBR 0100mmmm00011110 — — +LDC Rm,VBR Rm → VBR 0100mmmm00101110 Privileged — +LDC Rm,SSR Rm → SSR 0100mmmm00111110 Privileged — +LDC Rm,SPC Rm → SPC 0100mmmm01001110 Privileged — +LDC Rm,DBR Rm → DBR 0100mmmm11111010 Privileged — +LDC Rm,Rn_BANK Rm → Rn_BANK (n = 0 to 7) 0100mmmm1nnn1110 Privileged — +LDC.L @Rm+,SR (Rm) → SR, Rm + 4 → Rm 0100mmmm00000111 Privileged LSB +LDC.L @Rm+,GBR (Rm) → GBR, Rm + 4 → Rm 0100mmmm00010111 — — +LDC.L @Rm+,VBR (Rm) → VBR, Rm + 4 → Rm 0100mmmm00100111 Privileged — +LDC.L @Rm+,SSR (Rm) → SSR, Rm + 4 → Rm 0100mmmm00110111 Privileged — +LDC.L @Rm+,SPC (Rm) → SPC, Rm + 4 → Rm 0100mmmm01000111 Privileged — +LDC.L @Rm+,DBR (Rm) → DBR, Rm + 4 → Rm 0100mmmm11110110 Privileged — +LDC.L @Rm+,Rn_BANK (Rm) → Rn_BANK, Rm + 4 → Rm 0100mmmm1nnn0111 Privileged — +LDS Rm,MACH Rm → MACH 0100mmmm00001010 — — +LDS Rm,MACL Rm → MACL 0100mmmm00011010 — — +LDS Rm,PR Rm → PR 0100mmmm00101010 — — +LDS.L @Rm+,MACH (Rm) → MACH, Rm + 4 → Rm 0100mmmm00000110 — — +LDS.L @Rm+,MACL (Rm) → MACL, Rm + 4 → Rm 0100mmmm00010110 — — +LDS.L @Rm+,PR (Rm) → PR, Rm + 4 → Rm 0100mmmm00100110 — — +LDTLB PTEH/PTEL → TLB 0000000000111000 Privileged — +MOVCA.L R0,@Rn R0 → (Rn) (without fetching cache block) 0000nnnn11000011 — — +NOP No operation 0000000000001001 — — +OCBI @Rn Invalidates operand cache block 0000nnnn10010011 — — +OCBP @Rn Writes back and invalidates operand cache block 0000nnnn10100011 — — +OCBWB @Rn Writes back operand cache block 0000nnnn10110011 — — +PREF @Rn (Rn) → operand cache 0000nnnn10000011 — — +RTE Delayed branch, SSR/SPC → SR/PC 0000000000101011 Privileged — +SETS 1 → S 0000000001011000 — — +SETT 1 → T 0000000000011000 — 1 +SLEEP Sleep or standby 0000000000011011 Privileged — +STC SR,Rn SR → Rn 0000nnnn00000010 Privileged — +STC GBR,Rn GBR → Rn 0000nnnn00010010 — — +STC VBR,Rn VBR → Rn 0000nnnn00100010 Privileged — +STC SSR,Rn SSR → Rn 0000nnnn00110010 Privileged — +STC SPC,Rn SPC → Rn 0000nnnn01000010 Privileged — +STC SGR,Rn SGR → Rn 0000nnnn00111010 Privileged — +STC DBR,Rn DBR → Rn 0000nnnn11111010 Privileged — +STC Rm_BANK,Rn Rm_BANK → Rn (m = 0 to 7) 0000nnnn1mmm0010 Privileged — +STC.L SR,@-Rn Rn – 4 → Rn, SR → (Rn) 0100nnnn00000011 Privileged — +STC.L GBR,@-Rn Rn – 4 → Rn, GBR → (Rn) 0100nnnn00010011 — — +STC.L VBR,@-Rn Rn – 4 → Rn, VBR → (Rn) 0100nnnn00100011 Privileged — +STC.L SSR,@-Rn Rn – 4 → Rn, SSR → (Rn) 0100nnnn00110011 Privileged — +STC.L SPC,@-Rn Rn – 4 → Rn, SPC → (Rn) 0100nnnn01000011 Privileged — +STC.L SGR,@-Rn Rn – 4 → Rn, SGR → (Rn) 0100nnnn00110010 Privileged — +STC.L DBR,@-Rn Rn – 4 → Rn, DBR → (Rn) 0100nnnn11110010 Privileged — +STC.L Rm_BANK,@-Rn Rn – 4 → Rn, Rm_BANK → (Rn) (m = 0 to 7) 0100nnnn1mmm0011 Privileged — +STS MACH,Rn MACH → Rn 0000nnnn00001010 — — +STS MACL,Rn MACL → Rn 0000nnnn00011010 — — +STS PR,Rn PR → Rn 0000nnnn00101010 — — +STS.L MACH,@-Rn Rn – 4 → Rn, MACH → (Rn) 0100nnnn00000010 — — +STS.L MACL,@-Rn Rn – 4 → Rn, MACL → (Rn) 0100nnnn00010010 — — +STS.L PR,@-Rn Rn – 4 → Rn, PR → (Rn) 0100nnnn00100010 — — +TRAPA #imm PC + 2 → SPC, SR → SSR, #imm << 2 → TRA, 11000011iiiiiiii — — + 0x160 → EXPEVT, VBR + 0x0100 → PC + +FLDI0 FRn 0x00000000 → FRn 1111nnnn10001101 — — +FLDI1 FRn 0x3F800000 → FRn 1111nnnn10011101 — — +FMOV FRm,FRn FRm → FRn 1111nnnnmmmm1100 — — +FMOV.S @Rm,FRn (Rm) → FRn 1111nnnnmmmm1000 — — +FMOV.S @(R0,Rm),FRn (R0 + Rm) → FRn 1111nnnnmmmm0110 — — +FMOV.S @Rm+,FRn (Rm) → FRn, Rm + 4 → Rm 1111nnnnmmmm1001 — — +FMOV.S FRm,@Rn FRm → (Rn) 1111nnnnmmmm1010 — — +FMOV.S FRm,@-Rn Rn-4 → Rn, FRm → (Rn) 1111nnnnmmmm1011 — — +FMOV.S FRm,@(R0,Rn) FRm → (R0 + Rn) 1111nnnnmmmm0111 — — +FMOV DRm,DRn DRm → DRn 1111nnn0mmm01100 — — +FMOV @Rm,DRn (Rm) → DRn 1111nnn0mmmm1000 — — +FMOV @(R0,Rm),DRn (R0 + Rm) → DRn 1111nnn0mmmm0110 — — +FMOV @Rm+,DRn (Rm) → DRn, Rm + 8 → Rm 1111nnn0mmmm1001 — — +FMOV DRm,@Rn DRm → (Rn) 1111nnnnmmm01010 — — +FMOV DRm,@-Rn Rn-8 → Rn, DRm → (Rn) 1111nnnnmmm01011 — — +FMOV DRm,@(R0,Rn) DRm → (R0 + Rn) 1111nnnnmmm00111 — — +FLDS FRm,FPUL FRm → FPUL 1111mmmm00011101 — — +FSTS FPUL,FRn FPUL → FRn 1111nnnn00001101 — — +FABS FRn FRn & 0x7FFF FFFF → FRn 1111nnnn01011101 — — +FADD FRm,FRn FRn + FRm → FRn 1111nnnnmmmm0000 — — +FCMP/EQ FRm,FRn When FRn = FRm, 1 → T Otherwise, 0 → T 1111nnnnmmmm0100 — Comparison result +FCMP/GT FRm,FRn When FRn > FRm, 1 → T Otherwise, 0 → T 1111nnnnmmmm0101 — Comparison result +FDIV FRm,FRn FRn/FRm → FRn 1111nnnnmmmm0011 — — +FLOAT FPUL,FRn (float) FPUL → FRn 1111nnnn00101101 — — +FMAC FR0,FRm,FRn FR0*FRm + FRn → FRn 1111nnnnmmmm1110 — — +FMUL FRm,FRn FRn*FRm → FRn 1111nnnnmmmm0010 — — +FNEG FRn FRn ∧ 0x80000000 → FRn 1111nnnn01001101 — — +FSQRT FRn √FRn → FRn 1111nnnn01101101 — — +FSUB FRm,FRn FRn – FRm → FRn 1111nnnnmmmm0001 — — +FTRC FRm,FPUL (long) FRm → FPUL 1111mmmm00111101 — — + + +FABS DRn DRn & 0x7FFF FFFF FFFF ; FFFF → DRn 1111nnn001011101 — — +FADD DRm,DRn DRn + DRm → DRn 1111nnn0mmm00000 — — +FCMP/EQ DRm,DRn When DRn = DRm, 1 → T Otherwise, 0 → T 1111nnn0mmm00100 — Comparison result +FCMP/GT DRm,DRn When DRn > DRm, 1 → T Otherwise, 0 → T 1111nnn0mmm00101 — Comparison result +FDIV DRm,DRn DRn /DRm → DRn 1111nnn0mmm00011 — — +FCNVDS DRm,FPUL double_to_ float[DRm] → FPUL 1111mmm010111101 — — +FCNVSD FPUL,DRn float_to_ double [FPUL] → DRn 1111nnn010101101 — — +FLOAT FPUL,DRn (float)FPUL → DRn 1111nnn000101101 — — +FMUL DRm,DRn DRn * DRm → DRn 1111nnn0mmm00010 — — +FNEG DRn DRn ^ 0x8000 0000 0000 0000 → DRn 1111nnn001001101 — — +FSQRT DRn √DRn → DRn 1111nnn001101101 — — +FSUB DRm,DRn DRn – DRm → DRn 1111nnn0mmm00001 — — +FTRC DRm,FPUL (long) DRm → FPUL 1111mmm000111101 — — + +LDS Rm,FPSCR Rm → FPSCR 0100mmmm01101010 — — +LDS Rm,FPUL Rm → FPUL 0100mmmm01011010 — — +LDS.L @Rm+,FPSCR (Rm) → FPSCR, Rm+4 → Rm 0100mmmm01100110 — — +LDS.L @Rm+,FPUL (Rm) → FPUL, Rm+4 → Rm 0100mmmm01010110 — — +STS FPSCR,Rn FPSCR → Rn 0000nnnn01101010 — — +STS FPUL,Rn FPUL → Rn 0000nnnn01011010 — — +STS.L FPSCR,@-Rn Rn – 4 → Rn, FPSCR → (Rn) 0100nnnn01100010 — — +STS.L FPUL,@-Rn Rn – 4 → Rn, FPUL → (Rn) 0100nnnn01010010 — — + +FMOV DRm,XDn DRm → XDn 1111nnn1mmm01100 — — +FMOV XDm,DRn XDm → DRn 1111nnn0mmm11100 — — +FMOV XDm,XDn XDm → XDn 1111nnn1mmm11100 — — +FMOV @Rm,XDn (Rm) → XDn 1111nnn1mmmm1000 — — +FMOV @Rm+,XDn (Rm) → XDn, Rm + 8 → Rm 1111nnn1mmmm1001 — — +FMOV @(R0,Rm),XDn (R0 + Rm) → XDn 1111nnn1mmmm0110 — — +FMOV XDm,@Rn XDm → (Rn) 1111nnnnmmm11010 — — +FMOV XDm,@-Rn Rn – 8 → Rn, XDm → (Rn) 1111nnnnmmm11011 — — +FMOV XDm,@(R0,Rn) XDm → (R0+Rn) 1111nnnnmmm10111 — — +FIPR FVm,FVn inner_product [FVm, FVn] → FR[n+3] 1111nnmm11101101 — — +FTRV XMTRX,FVn transform_vector [XMTRX, FVn] → FVn 1111nn0111111101 — — +FRCHG ~FPSCR.FR → SPFCR.FR 1111101111111101 — — +FSCHG ~FPSCR.SZ → SPFCR.SZ 1111001111111101 — — + +FCSA FPUL, DRn sin(FPUL) → FRn ; cos(FPUL) → FR[n+1] 1111nnn011111101 — — +FSRRA FRn 1/√FRn → FRn 1111nnnn01111101 — — diff --git a/simulate.py b/simulate.py new file mode 100644 index 0000000..51b25a3 --- /dev/null +++ b/simulate.py @@ -0,0 +1,354 @@ +import curses +import curses.panel +from curses.textpad import Textbox, rectangle +import time +from dataclasses import dataclass + +from sh2 import SH2 +from impl2 import ILLSLOT, TRAP +from mem import Memory +import sys +from execute import step +from decode import decode_instruction, decode_variables +from operations import sign_extend32 + +from log import get_log, log, raw_log + +last_seen1 = {} +last_seen = {} + +@dataclass +class C: + color: curses.color_pair + value: str + +def get_color(name, value, update): + global last_seen + global last_seen1 + + if not update: + seen = last_seen1 + else: + seen = last_seen + + if name not in seen or seen[name] != value: + color = curses.color_pair(5) + else: + color = curses.color_pair(0) + + if update: + if name in last_seen: + last_seen1[name] = last_seen[name] + last_seen[name] = value + + return color + +def render_registers(stdscr, cpu, simulator, update): + others = [ + 'sr', + 'gbr', + 'vbr', + 'mach', + 'macl', + 'pr', + 'pc', + ] + + def format_value(value): + if simulator.display_mode == "int": + return f"{sign_extend32(value)}" + if simulator.display_mode == "uint": + return f"{value}" + elif simulator.display_mode == "hex": + return f"0x{value:08x}" + else: + assert False, simulator.display_mode + + for i in range(8): + ra = i + rb = i+8 + stdscr.addstr(2 + i, 4 + 0 , f"r{ra}") + color = get_color(ra, cpu.reg[ra], update) + stdscr.addstr(2 + i, 4 + 5 , format_value(cpu.reg[ra]), color) + stdscr.addstr(2 + i, 4 + 20, f"r{rb}") + color = get_color(rb, cpu.reg[rb], update) + stdscr.addstr(2 + i, 4 + 25, format_value(cpu.reg[rb]), color) + + if i < len(others): + name = others[i] + if i == 0: + sr = cpu.sr + value = f"m:{sr.m} q:{sr.q} i:{sr.i} s:{sr.s} t:{sr.t}" + else: + value = getattr(cpu, name) + value = format_value(value) + + color = get_color(name, value, update) + stdscr.addstr(2 + i, 4 + 40, f"{name}") + stdscr.addstr(2 + i, 4 + 45, value, color) + +def format_variables(ins, variables): + s = ins.operands + for i, name in enumerate(ins.variables): + if 'disp' in s and name == 'd': + name = 'disp' + if 'imm' in s and name == 'i': + name = 'imm' + if 'label' in s and name == 'd': + name = 'label' + s = s.replace(name, str(variables[i])) + return s + +def render_instructions(stdscr, cpu, mem): + color0 = curses.color_pair(1) + color1 = curses.color_pair(2) + color2 = curses.color_pair(3) + + y = 12 + x = 4 + + history_length = 12 + address_offset = (cpu.pc + 4) - ((history_length // 2) * 2) + i = 0 + while i < history_length: + address = address_offset + (i * 2) + if address == cpu.pc: + stdscr.addstr(y+i, x+0 , f">") + if address >= 0: + stdscr.addstr(y+i, x+2 , f"{address:08x}") + instruction = mem.read16(address) + ins = decode_instruction(instruction) + label = f"0x{instruction:04x}" + if ins is None: + operation = "" + operands = "" + else: + variables = decode_variables(instruction, ins) + operation = ins.instruction + operands = format_variables(ins, variables) + + ins_len = len('CMP/STR ') + stdscr.addstr(y+i, x+12 + 0 , f"{label}", color0) + stdscr.addstr(y+i, x+12 + 8 , f"{operation}", color1) + stdscr.addstr(y+i, x+12 + 8 + ins_len , f"{operands}", color2) + i += 1 + +def render_log(stdscr): + _log = get_log() + + y, x = stdscr.getmaxyx() + log_length = max(3, ((y - 4) - 26)) + for i in range(log_length): + ix = (log_length - i) + if ix > len(_log): + continue + entry = _log[-ix] + if type(entry) is str: + stdscr.addstr(26 + i, 4 + 0, entry) + else: + assert type(entry) is tuple + x_offset = 0 + for e in entry: + if type(e) is C: + color, s = e.color, e.value + stdscr.addstr(26 + i, 4 + x_offset, s, color) + else: + s = e + stdscr.addstr(26 + i, 4 + x_offset, s) + x_offset += len(s) + 1 + +def render(stdscr, cpu, mem, simulator, update): + stdscr.clear() + + render_registers(stdscr, cpu, simulator, update) + render_instructions(stdscr, cpu, mem) + render_log(stdscr) + + y, x = stdscr.getmaxyx() + message = "backspace: Ctrl-H" + stdscr.addstr(y-4, x - (len(message) + 3), message, curses.color_pair(6)) + rectangle(stdscr, (y-3), 2, (y-3)+1+1, x - (2 + 1)) + + stdscr.refresh() + +def log_buf(buf, buf_start): + s = " ".join(f'{n:02x}' for n in buf) + address = f'{buf_start:08x}' + string = repr("".join(chr(n) for n in buf)) + raw_log( + address, + ':', + C(curses.color_pair(1), s), # green + ';', + C(curses.color_pair(4), string) # magenta + ) + +@dataclass +class Simulator: + break_points: list[int] + start_time: int + instructions: int + free_run: bool + display_mode: str + + def __init__(self): + self.break_points = [] + self.start_time = time.monotonic() + self.instructions = 0 + self.free_run = False + self.display_mode = "hex" + + def set_continue(self): + self.start_time = time.monotonic() + self.instructions = 0 + self.free_run = True + + def check_break_points(self, cpu): + if not self.free_run: + return + + for address in self.break_points: + if address != cpu.pc: + continue + + self.free_run = False + end = time.monotonic() + log("time", end - self.start_time) + log("instructions", self.instructions) + return + +def print_memory(mem, start, end): + i = start + buf = [] + buf_start = start + while True: + b = mem.read8(i) + buf.append(b) + if len(buf) >= 8: + log_buf(buf, buf_start) + buf = [] + buf_start = i + 1 + + if i == end: + break + i += 1 + if buf: + log_buf(buf, buf_start) + +def parse_registers(args): + regs = [] + for arg in args: + arg = arg.lower() + if not arg.startswith('@r'): + raise ValueError(arg) + n = int(arg.removeprefix('@r'), 10) + if n >= 0 and n <= 16: + regs.append(n) + else: + raise ValueError(arg) + return regs + +def handle_command(line, simulator, cpu, mem): + cmd, *args = line.split() + if cmd == "p" or cmd == "print" or cmd == "p/x": + if not args: + log("print: missing argument") + return + try: + if args[0].startswith('@'): + regs = parse_registers(args) + start = cpu.reg[regs[0]] + end = cpu.reg[regs[1]] if len(regs) >= 2 else start + else: + start = int(args[0], 16) + end = int(args[1], 16) if len(args) >= 2 else start + except ValueError: + log("print: invalid arguments", args) + return + print_memory(mem, start, end) + elif cmd == "b" or cmd == "break": + if not args: + log("break: missing argument") + return + address = int(args[0], 16) + if address % 2 != 0: + log("break: invalid address", f'{address:08x}') + else: + simulator.break_points.append(address) + log("break: added", f'{address:08x}') + elif cmd == "c" or cmd == "continue": + simulator.set_continue() + elif cmd == "hex": + simulator.display_mode = "hex" + elif cmd == "int": + simulator.display_mode = "int" + elif cmd == "uint": + simulator.display_mode = "uint" + else: + log("unknown command", repr(cmd), args) + + +def main(stdscr): + curses.start_color() + curses.use_default_colors() + curses.init_pair(1, curses.COLOR_GREEN, -1) + curses.init_pair(2, curses.COLOR_CYAN, -1) + curses.init_pair(3, curses.COLOR_RED, -1) + curses.init_pair(4, curses.COLOR_MAGENTA, -1) + curses.init_pair(5, curses.COLOR_YELLOW, -1) + curses.init_pair(6, 246, -1) # GREY + + with open(sys.argv[1], 'rb') as f: + _buf = f.read() + buf = memoryview(_buf) + + cpu = SH2() + mem = Memory() + simulator = Simulator() + + for address, b in enumerate(buf): + mem.write8(address, b) + + curses.curs_set(0) # invisible cursor + render(stdscr, cpu, mem, simulator, True) + + def new_inputbox(): + y, x = stdscr.getmaxyx() + nlines = 1 + ncols = x - (4 * 2 + 1) + editwin = curses.newwin(nlines, ncols, y-2, 4) + editwin.move(0, 0) + box = Textbox(editwin) + return box + + def next_input(): + box = new_inputbox() + curses.curs_set(1) + box.edit() + curses.curs_set(0) + command = box.gather().rstrip() + if command == '': + return True + else: + handle_command(command, simulator, cpu, mem) + return False + + while True: + update = False + + if simulator.free_run or next_input(): + try: + step(cpu, mem) + except TRAP as e: + simulator.free_run = 0 + log("trap", e.args[0]) + + simulator.instructions += 1 + update = True + + simulator.check_break_points(cpu) + + if not simulator.free_run or simulator.instructions % 100 == 0: + render(stdscr, cpu, mem, simulator, update) + +curses.wrapper(main) diff --git a/test_impl.py b/test_impl.py new file mode 100644 index 0000000..701cba6 --- /dev/null +++ b/test_impl.py @@ -0,0 +1,311 @@ +from sh2 import SH2 +from mem import Memory +from impl import * + +def test_addc(): + cpu = SH2() + mem = Memory() + + cpu.reg[0] = 0x0000_0000 + cpu.reg[1] = 0x0000_0001 + + cpu.reg[2] = 0x0000_0000 + cpu.reg[3] = 0xffff_ffff + + clrt(cpu, mem) + addc(cpu, mem, 3, 1) + assert cpu.reg[1] == 0x0000_0000 + assert cpu.sr.t == 1 + addc(cpu, mem, 2, 0) + assert cpu.reg[0] == 0x0000_0001 + assert cpu.sr.t == 0 + +def test_addv(): + cpu = SH2() + mem = Memory() + + cpu.reg[0] = 0x0000_0001 + cpu.reg[1] = 0x7fff_fffe + cpu.sr.t = 0 + addv(cpu, mem, 0, 1) + assert cpu.reg[1] == 0x7fff_ffff + assert cpu.sr.t == 0 + + cpu.reg[0] = 0x0000_0002 + cpu.reg[1] = 0x7fff_fffe + cpu.sr.t = 0 + addv(cpu, mem, 0, 1) + assert cpu.reg[1] == 0x8000_0000 + assert cpu.sr.t == 1 + +def test_dmuls(): + cpu = SH2() + mem = Memory() + + cpu.reg[0] = 0xffff_fffe + cpu.reg[1] = 0x0000_5555 + dmuls(cpu, mem, 0, 1) + assert cpu.mach == 0xffff_ffff, cpu.mach + assert cpu.macl == 0xffff_5556, cpu.macl + + cpu.reg[0] = 0x1234_abcd + cpu.reg[1] = 0x1234_abcd + dmuls(cpu, mem, 0, 1) + assert cpu.mach == 0x014b_72ff, hex(cpu.mach) + assert cpu.macl == 0x1293_8229, hex(cpu.macl) + + cpu.reg[0] = 0xedcb_5433 + cpu.reg[1] = 0x1234_abcd + dmuls(cpu, mem, 0, 1) + assert cpu.mach == 0xfeb4_8d00, hex(cpu.mach) + assert cpu.macl == 0xed6c_7dd7, hex(cpu.macl) + +def test_dmulu(): + cpu = SH2() + mem = Memory() + + cpu.reg[0] = 0xffff_fffe + cpu.reg[1] = 0x0000_5555 + dmulu(cpu, mem, 0, 1) + assert cpu.mach == 0x0000_5554, cpu.mach + assert cpu.macl == 0xffff_5556, hex(cpu.macl) + + cpu.reg[0] = 0x1234_abcd + cpu.reg[1] = 0x1234_abcd + dmulu(cpu, mem, 0, 1) + assert cpu.mach == 0x014b_72ff, hex(cpu.mach) + assert cpu.macl == 0x1293_8229, hex(cpu.macl) + + cpu.reg[0] = 0xedcb_5433 + cpu.reg[1] = 0x1234_abcd + dmulu(cpu, mem, 0, 1) + assert cpu.mach == 0x10e9_38cd, hex(cpu.mach) + assert cpu.macl == 0xed6c_7dd7, hex(cpu.macl) + +def test_extsb(): + cpu = SH2() + mem = Memory() + cpu.reg[0] = 0x0000_0080 + extsb(cpu, mem, 0, 1) + assert cpu.reg[1] == 0xffff_ff80 + +def test_extsw(): + cpu = SH2() + mem = Memory() + cpu.reg[0] = 0x0000_8000 + extsw(cpu, mem, 0, 1) + assert cpu.reg[1] == 0xffff_8000 + +def test_extub(): + cpu = SH2() + mem = Memory() + cpu.reg[0] = 0xffff_ff80 + extub(cpu, mem, 0, 1) + assert cpu.reg[1] == 0x0000_0080 + +def test_extuw(): + cpu = SH2() + mem = Memory() + cpu.reg[0] = 0xffff_8000 + extuw(cpu, mem, 0, 1) + assert cpu.reg[1] == 0x0000_8000 + +def test_mull(): + cpu = SH2() + mem = Memory() + cpu.reg[0] = 0xffff_fffe + cpu.reg[1] = 0x0000_5555 + mull(cpu, mem, 0, 1) + assert cpu.macl == 0xffff_5556, hex(cpu.macl) + cpu.reg[0] = 0xffff_0005 + cpu.reg[1] = 0x1234_5678 + mull(cpu, mem, 0, 1) + assert cpu.macl == 0x048d_b058, hex(cpu.macl) + +def test_muls(): + cpu = SH2() + mem = Memory() + cpu.reg[0] = 0xffff_fffe + cpu.reg[1] = 0x0000_5555 + muls(cpu, mem, 0, 1) + assert cpu.macl == 0xffff_5556, hex(cpu.macl) + cpu.reg[0] = 0xffff_0005 + cpu.reg[1] = 0x1234_5678 + muls(cpu, mem, 0, 1) + assert cpu.macl == 0x0001_b058, hex(cpu.macl) + cpu.reg[0] = 0xffff_f005 + cpu.reg[1] = 0x1234_5678 + muls(cpu, mem, 0, 1) + assert cpu.macl == 0xfa9a_3058, hex(cpu.macl) + +def test_mulu(): + cpu = SH2() + mem = Memory() + cpu.reg[0] = 0x0000_0002 + cpu.reg[1] = 0xffff_aaaa + mulu(cpu, mem, 0, 1) + assert cpu.macl == 0x0001_5554, hex(cpu.macl) + cpu.reg[0] = 0xffff_0005 + cpu.reg[1] = 0x1234_5678 + mulu(cpu, mem, 0, 1) + assert cpu.macl == 0x0001_b058, hex(cpu.macl) + cpu.reg[0] = 0xffff_f005 + cpu.reg[1] = 0x1234_5678 + mulu(cpu, mem, 0, 1) + assert cpu.macl == 0x5112_3058, hex(cpu.macl) + +def test_negc(): + cpu = SH2() + mem = Memory() + cpu.reg[1] = 0x0000_0001 + clrt(cpu, mem) + assert cpu.sr.t == 0 + negc(cpu, mem, 1, 1) + assert cpu.sr.t == 1 + assert cpu.reg[1] == 0xffff_ffff, hex(cpu.reg[1]) + cpu.reg[1] = 0x0000_0000 + negc(cpu, mem, 0, 0) + assert cpu.sr.t == 1 + assert cpu.reg[0] == 0xffff_ffff, hex(cpu.reg[0]) + +def test_subc(): + cpu = SH2() + mem = Memory() + cpu.reg[0] = 0x0000_0000 + cpu.reg[1] = 0x0000_0000 + cpu.reg[2] = 0x0000_0000 + cpu.reg[3] = 0x0000_0001 + + clrt(cpu, mem) + subc(cpu, mem, 3, 1) + subc(cpu, mem, 2, 0) + assert cpu.reg[0] == 0xffff_ffff + assert cpu.reg[1] == 0xffff_ffff + +def test_subv(): + cpu = SH2() + mem = Memory() + cpu.reg[0] = 0x0000_0002 + cpu.reg[1] = 0x8000_0001 + subv(cpu, mem, 0, 1) + assert cpu.sr.t == 1, cpu.sr.t + assert cpu.reg[1] == 0x7fff_ffff + + cpu.reg[2] = 0xffff_fffe + cpu.reg[3] = 0x7fff_fffe + subv(cpu, mem, 2, 3) + assert cpu.sr.t == 1 + assert cpu.reg[3] == 0x8000_0000 + +def test_swapb(): + cpu = SH2() + mem = Memory() + cpu.reg[0] = 0x12345678 + swapb(cpu, mem, 0, 1) + assert cpu.reg[1] == 0x12347856 + +def test_swapw(): + cpu = SH2() + mem = Memory() + cpu.reg[0] = 0x12345678 + swapw(cpu, mem, 0, 1) + assert cpu.reg[1] == 0x56781234 + +def test_xtrct(): + cpu = SH2() + mem = Memory() + cpu.reg[0] = 0x0123_4567 + cpu.reg[1] = 0x89ab_cdef + xtrct(cpu, mem, 0, 1) + assert cpu.reg[1] == 0x4567_89ab + +def test_macl(): + cpu = SH2() + mem = Memory() + + mem.write_long(0x1010, 0x1234abcd) # TBLM + mem.write_long(0x1014, 0x5678ef01) + mem.write_long(0x1018, 0x0123abcd) # TBLN + mem.write_long(0x101c, 0x4567def0) + + cpu.pc = 0x1000 + clrmac(cpu, mem) + mova(cpu, mem, 3) # TBLM + assert cpu.reg[0] == 0x0000_1010 + mov(cpu, mem, 0, 1) + mova(cpu, mem, 4) # TBLN + assert cpu.reg[0] == 0x0000_1018 + clrmac(cpu, mem) + macl(cpu, mem, 0, 1) + assert cpu.mach == 0x0014_be17, hex(cpu.mach) + assert cpu.macl == 0x0cf6_8229, hex(cpu.macl) + macl(cpu, mem, 0, 1) + assert cpu.mach == 0x1786_6c78, hex(cpu.mach) + assert cpu.macl == 0x6c00_7119, hex(cpu.macl) + +def test_macw(): + cpu = SH2() + mem = Memory() + + mem.write_word(0x1010, 0x1234) # TBLM + mem.write_word(0x1012, 0xabcd) + mem.write_word(0x1014, 0x5678) + mem.write_word(0x1016, 0xef01) + mem.write_word(0x1018, 0x0123) # TBLN + mem.write_word(0x101a, 0xabcd) + mem.write_word(0x101c, 0x4567) + mem.write_word(0x101e, 0xdef0) + + cpu.pc = 0x1000 + clrmac(cpu, mem) + mova(cpu, mem, 3) # TBLM + assert cpu.reg[0] == 0x0000_1010 + mov(cpu, mem, 0, 1) + mova(cpu, mem, 4) # TBLN + assert cpu.reg[0] == 0x0000_1018 + clrmac(cpu, mem) + + macw(cpu, mem, 0, 1) + assert cpu.mach == 0x0000_0000, hex(cpu.mach) + assert cpu.macl == 0x0014_b11c, hex(cpu.macl) + + macw(cpu, mem, 0, 1) + assert cpu.mach == 0x0000_0000, hex(cpu.mach) + assert cpu.macl == 0x1bc6_3345, hex(cpu.macl) + + macw(cpu, mem, 0, 1) + assert cpu.mach == 0x0000_0000, hex(cpu.mach) + assert cpu.macl == 0x3337_558d, hex(cpu.macl) + + macw(cpu, mem, 0, 1) + assert cpu.mach == 0x0000_0000, hex(cpu.mach) + assert cpu.macl == 0x3569_447d, hex(cpu.macl) + +def test_mova(): + cpu = SH2() + mem = Memory() + cpu.pc = 0x1006 + mova(cpu, mem, 1) + assert cpu.reg[0] == 0x100c + +test_addc() +test_addv() +test_dmuls() +test_dmulu() +test_extsb() +test_extsw() +test_extub() +test_extuw() +test_mull() +test_muls() +test_mulu() +test_negc() +test_subc() +test_subv() +test_swapb() +test_swapw() +test_xtrct() +test_macl() +test_macw() + +test_mova() diff --git a/tests/add.s b/tests/add.s new file mode 100644 index 0000000..217d3f5 --- /dev/null +++ b/tests/add.s @@ -0,0 +1,6 @@ + ADD R0,R1 ; Before execution R1 = H'7FFFFFFF, R1 = H'00000001 + ; After execution R1 = H'80000000 + ADD #H'01,R2 ; Before execution R2 = H'00000000 + ; After execution R3 = H'FFFFFFFF + ADD #H'FE,R3 ; Before execution R3 = H'00000001 + ; After execution R3 = H'FFFFFFFF diff --git a/tests/addc.s b/tests/addc.s new file mode 100644 index 0000000..e83e010 --- /dev/null +++ b/tests/addc.s @@ -0,0 +1,5 @@ + CLRT ; R0:R1 (64 bits) + R2:R3 (64 bits) = R0:R1 (64 bits) + ADDC R3,R1 ; Before execution T = 0, R1 = H'00000001, R3 = H'FFFFFFFF + ; After execution T = 1, R1 = H'0000000 + ADDC R2,R0 ; Before execution T = 1, R0 = H'00000000, R2 = H'00000000 + ; After execution T = 0, R0 = H'00000001 diff --git a/tests/addv.s b/tests/addv.s new file mode 100644 index 0000000..981b306 --- /dev/null +++ b/tests/addv.s @@ -0,0 +1,4 @@ + ADDV R0,R1 ; Before execution R0 = H'00000001, R1 = H'7FFFFFFE, T = 0 + ; After execution R1 = H'7FFFFFFF, T = 0 + ADDV R0,R1 ; Before execution R0 = H'00000002, R1 = H'7FFFFFFE, T = 0 + ; After execution R1 = H'80000000, T = 1 diff --git a/tests/and.s b/tests/and.s new file mode 100644 index 0000000..080bb3b --- /dev/null +++ b/tests/and.s @@ -0,0 +1,6 @@ + AND R0,R1 ; Before execution R0 = H'AAAAAAAA, R1 = H'55555555 + ; After execution R1 = H'00000000 + AND #H'0F,R0 ; Before execution R0 = H'FFFFFFFF + ; After execution R0 = H'0000000F + AND.B #H'80,@(R0,GBR) ; Before execution @(R0,GBR) = H'A5 + ; After execution @(R0,GBR) = H'80 diff --git a/tests/bf.s b/tests/bf.s new file mode 100644 index 0000000..f6af8f8 --- /dev/null +++ b/tests/bf.s @@ -0,0 +1,8 @@ + CLRT ; T is always cleared to 0 + BT TRGET_T ; Does not branch, because T = 0 + BF TRGET_F ; Branches to TRGET_F, because T = 0 + NOP + NOP ; ← The PC location is used to calculate the + ; branch destination address of the BF + ; instruction +TRGET_F: ; ← Branch destination of the BF instruction diff --git a/tests/bfs.s b/tests/bfs.s new file mode 100644 index 0000000..8dc091c --- /dev/null +++ b/tests/bfs.s @@ -0,0 +1,8 @@ + CLRT ; T is always 0 + BT/S TRGET_T ; Does not branch, because T = 0 + NOP + BF/S TRGET_F ; Branches to TRGET, because T = 0 + ADD R0,R1 ; Executed before branch + NOP ; ← The PC location is used to calculate the branch destination + ; address of the BF/S instruction +TRGET_F: ; ← Branch destination of the BF/S instruction diff --git a/tests/bra.s b/tests/bra.s new file mode 100644 index 0000000..25a7b41 --- /dev/null +++ b/tests/bra.s @@ -0,0 +1,5 @@ + BRA TRGET ; Branches to TRGET + ADD R0,R1 ; Executes ADD before branching + NOP ; ← The PC location is used to calculate the branch destination + ; address of the BRA instruction +TRGET: ; ← Branch destination of the BRA instruction diff --git a/tests/braf.s b/tests/braf.s new file mode 100644 index 0000000..728d0ef --- /dev/null +++ b/tests/braf.s @@ -0,0 +1,8 @@ + MOV.L #(TRGET-BSRF_PC),R0 ; Sets displacement + BRAF @R0 ; Branches to TRGET + ADD R0,R1 ; Executes ADD before branching +BRAF_PC: ; ← The PC location is used to calculate + ; the branch destination address of + ; the BRAF instruction + NOP +TRGET: ; ← Branch destination of the BRAF instruction diff --git a/tests/bsr.s b/tests/bsr.s new file mode 100644 index 0000000..b720c66 --- /dev/null +++ b/tests/bsr.s @@ -0,0 +1,9 @@ + BSR TRGET ; Branches to TRGET + MOV R3,R4 ; Executes the MOV instruction before branching + ADD R0,R1 ; ← The PC location is used to calculate the branch destination + ; address of the BSR instruction (return address for when the + ; subroutine procedure is completed (PR data)) +TRGET: ; ← Procedure entrance + MOV R2,R3 + RTS ; Returns to the above ADD instruction + MOV #1,R0 ; Executes MOV before branching diff --git a/tests/bsrf.s b/tests/bsrf.s new file mode 100644 index 0000000..e2aab4f --- /dev/null +++ b/tests/bsrf.s @@ -0,0 +1,12 @@ + MOV.L #(TRGET-BSRF_PC),R0 ; Sets displacement + BRSF @R0 ; Branches to TRGET + MOV R3,R4 ; Executes the MOV instruction before + ; branching +BSRF_PC: ; ← The PC location is used to + ; calculate the branch destination + ; with BSRF + ADD R0,R1 +TRGET: ; ← Procedure entrance + MOV R2,R3 + RTS ; Returns to the above ADD instruction + MOV #1,R0 ; Executes MOV before branching diff --git a/tests/bt.s b/tests/bt.s new file mode 100644 index 0000000..8d474ce --- /dev/null +++ b/tests/bt.s @@ -0,0 +1,7 @@ + SETT ; T is always 1 + BF TRGET_F ; Does not branch, because T = 1 + BT TRGET_T ; Branches to TRGET_T, because T = 1 + NOP + NOP ; ← The PC location is used to calculate the branch destination + ; address of the BT instruction +TRGET_T: ; ← Branch destination of the BT instruction diff --git a/tests/bts.s b/tests/bts.s new file mode 100644 index 0000000..86bf446 --- /dev/null +++ b/tests/bts.s @@ -0,0 +1,8 @@ + SETT ; T is always 1 + BF/S TRGET_F ; Does not branch, because T = 1 + NOP + BT/S TRGET_T ; Branches to TRGET, because T = 1 + ADD R0,R1 ; Executes before branching. + NOP ; ← The PC location is used to calculate the branch destination + ; address of the BT/S instruction +TRGET_T: ; ← Branch destination of the BT/S instruction diff --git a/tests/dmuls.s b/tests/dmuls.s new file mode 100644 index 0000000..2d0ece6 --- /dev/null +++ b/tests/dmuls.s @@ -0,0 +1,25 @@ + .global _start +_start: + mov.l .L0a,r0 + mov.l .L1a,r1 + dmuls.l r0,r1 /* mach 0xffffffff macl 0xffff5556 */ + mov.l .L0b,r0 + mov.l .L1b,r1 + dmuls.l r0,r1 /* mach 0x014b72ff macl 0x12938229 */ + mov.l .L0c,r0 + mov.l .L1c,r1 + dmuls.l r0,r1 /* mach 0xfeb48d00 macl 0xed6c7dd7 */ + + .align 4 +.L0a: + .long 0x00005555 +.L1a: + .long 0xfffffffe +.L0b: + .long 0x1234abcd +.L1b: + .long 0x1234abcd +.L0c: + .long 0xedcb5433 +.L1c: + .long 0x1234abcd diff --git a/tests/dmulu.s b/tests/dmulu.s new file mode 100644 index 0000000..044aafc --- /dev/null +++ b/tests/dmulu.s @@ -0,0 +1,25 @@ + .global _start +_start: + mov.l .L0a,r0 + mov.l .L1a,r1 + dmulu.l r0,r1 /* mach 0x00005554 macl 0xffff5556 */ + mov.l .L0b,r0 + mov.l .L1b,r1 + dmulu.l r0,r1 /* mach 0x014b72ff macl 0x12938229 */ + mov.l .L0c,r0 + mov.l .L1c,r1 + dmulu.l r0,r1 /* mach 0x10e938cd macl 0xed6c7dd7 */ + + .align 4 +.L0a: + .long 0x00005555 +.L1a: + .long 0xfffffffe +.L0b: + .long 0x1234abcd +.L1b: + .long 0x1234abcd +.L0c: + .long 0xedcb5433 +.L1c: + .long 0x1234abcd diff --git a/tests/macl.s b/tests/macl.s new file mode 100644 index 0000000..dbddfdd --- /dev/null +++ b/tests/macl.s @@ -0,0 +1,17 @@ + .global _start +_start: + mova tblm,r0 /* Get table address */ + mov r0,r1 + mova tbln,r0 /* Get table address */ + clrmac /* MAC register initialization */ + mac.l @r0+,@r1+ /* mach 0014_be17 + macl 0cf6_8229 */ + mac.l @r0+,@r1+ /* mach 1786_6c78 + macl 6c00_7119 */ + sts macl,r0 /* Get result in R0 */ + + .align 2 +tblm: .long 0x1234abcd + .long 0x5678ef01 +tbln: .long 0x0123abcd + .long 0x4567def0 diff --git a/tests/macl_saturation.s b/tests/macl_saturation.s new file mode 120000 index 0000000..0135dd9 --- /dev/null +++ b/tests/macl_saturation.s @@ -0,0 +1 @@ +/home/bilbo/dreamcast/example/macl_saturation.s \ No newline at end of file diff --git a/tests/macw.s b/tests/macw.s new file mode 100644 index 0000000..35b5a32 --- /dev/null +++ b/tests/macw.s @@ -0,0 +1,25 @@ + .global _start +_start: + mova tblm,r0 /* Get table address */ + mov r0,r1 + mova tbln,r0 /* Get table address */ + clrmac /* MAC register initialization */ + mac.w @r0+,@r1+ /* mach 0000_0000 + macl 0014_b11c */ + mac.w @r0+,@r1+ /* mach + macl */ + mac.w @r0+,@r1+ /* mach + macl */ + mac.w @r0+,@r1+ /* mach + macl */ + sts macl,r0 /* Get result in R0 */ + + .align 2 +tblm: .word 0x1234 + .word 0xabcd + .word 0x5678 + .word 0xef01 +tbln: .word 0x0123 + .word 0xabcd + .word 0x4567 + .word 0xdef0 diff --git a/tests/macw_saturation.s b/tests/macw_saturation.s new file mode 120000 index 0000000..475e879 --- /dev/null +++ b/tests/macw_saturation.s @@ -0,0 +1 @@ +/home/bilbo/dreamcast/example/macw_saturation.s \ No newline at end of file diff --git a/tests/mova.s b/tests/mova.s new file mode 100644 index 0000000..e7ae33c --- /dev/null +++ b/tests/mova.s @@ -0,0 +1,7 @@ + .long 0 + .word 0 + mova foo,r0 + .word 0 + .word 0 +foo: + .long 0x12345678 diff --git a/tests/mull.s b/tests/mull.s new file mode 100644 index 0000000..91a7150 --- /dev/null +++ b/tests/mull.s @@ -0,0 +1,18 @@ + .global _start +_start: + mov.l .L0a,r0 + mov.l .L1a,r1 + mul.l r0,r1 /* macl 0xffff5556 */ + mov.l .L0b,r0 + mov.l .L1b,r1 + mul.l r0,r1 /* macl 0x048db058 */ + + .align 4 +.L0a: + .long 0xfffffffe +.L1a: + .long 0x00005555 +.L0b: + .long 0xffff0005 +.L1b: + .long 0x12345678 diff --git a/tests/muls.s b/tests/muls.s new file mode 100644 index 0000000..3fa796d --- /dev/null +++ b/tests/muls.s @@ -0,0 +1,25 @@ + .global _start +_start: + mov.l .L0a,r0 + mov.l .L1a,r1 + muls.w r0,r1 /* macl 0xffff5556 */ + mov.l .L0b,r0 + mov.l .L1b,r1 + muls.w r0,r1 /* macl 0x0001b058 */ + mov.l .L0c,r0 + mov.l .L1c,r1 + muls.w r0,r1 /* macl 0xfa9a3058 */ + + .align 4 +.L0a: + .long 0xfffffffe +.L1a: + .long 0x00005555 +.L0b: + .long 0xffff0005 +.L1b: + .long 0x12345678 +.L0c: + .long 0xfffff005 +.L1c: + .long 0x12345678