initial sh2 interpreter
This commit is contained in:
commit
6eba0cdb9e
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
__pycache__
|
||||
*.o
|
||||
*.elf
|
||||
*.bin
|
||||
*.pyc
|
30
compare.py
Normal file
30
compare.py
Normal file
@ -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))
|
21
decode.py
Normal file
21
decode.py
Normal file
@ -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
|
||||
]
|
28
disassemble.py
Normal file
28
disassemble.py
Normal file
@ -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("<unknown instruction>", hex(n))
|
||||
else:
|
||||
variables = decode_variables(n, ins)
|
||||
print_instruction(ins, variables)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
46
effective_address.py
Normal file
46
effective_address.py
Normal file
@ -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
|
82
elf.py
Normal file
82
elf.py
Normal file
@ -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
|
47
execute.py
Normal file
47
execute.py
Normal file
@ -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
|
5
gdb.script
Normal file
5
gdb.script
Normal file
@ -0,0 +1,5 @@
|
||||
target extended-remote localhost:1236
|
||||
tui enable
|
||||
tui layout regs
|
||||
tui focus cmd
|
||||
tui reg all
|
88
generate.py
Normal file
88
generate.py
Normal file
@ -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()
|
47
instruction_properties.py
Normal file
47
instruction_properties.py
Normal file
@ -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
|
235
instruction_table.py
Normal file
235
instruction_table.py
Normal file
@ -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)
|
10
log.py
Normal file
10
log.py
Normal file
@ -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
|
48
mem.py
Normal file
48
mem.py
Normal file
@ -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
|
94
operations.py
Normal file
94
operations.py
Normal file
@ -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)
|
31
sh2-vs-sh4.txt
Normal file
31
sh2-vs-sh4.txt
Normal file
@ -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:
|
89
sh2.py
Normal file
89
sh2.py
Normal file
@ -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)
|
170
sh2.txt
Normal file
170
sh2.txt
Normal file
@ -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 —
|
254
sh4.txt
Normal file
254
sh4.txt
Normal file
@ -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 — —
|
354
simulate.py
Normal file
354
simulate.py
Normal file
@ -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)
|
311
test_impl.py
Normal file
311
test_impl.py
Normal file
@ -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()
|
6
tests/add.s
Normal file
6
tests/add.s
Normal file
@ -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
|
5
tests/addc.s
Normal file
5
tests/addc.s
Normal file
@ -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
|
4
tests/addv.s
Normal file
4
tests/addv.s
Normal file
@ -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
|
6
tests/and.s
Normal file
6
tests/and.s
Normal file
@ -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
|
8
tests/bf.s
Normal file
8
tests/bf.s
Normal file
@ -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
|
8
tests/bfs.s
Normal file
8
tests/bfs.s
Normal file
@ -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
|
5
tests/bra.s
Normal file
5
tests/bra.s
Normal file
@ -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
|
8
tests/braf.s
Normal file
8
tests/braf.s
Normal file
@ -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
|
9
tests/bsr.s
Normal file
9
tests/bsr.s
Normal file
@ -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
|
12
tests/bsrf.s
Normal file
12
tests/bsrf.s
Normal file
@ -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
|
7
tests/bt.s
Normal file
7
tests/bt.s
Normal file
@ -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
|
8
tests/bts.s
Normal file
8
tests/bts.s
Normal file
@ -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
|
25
tests/dmuls.s
Normal file
25
tests/dmuls.s
Normal file
@ -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
|
25
tests/dmulu.s
Normal file
25
tests/dmulu.s
Normal file
@ -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
|
17
tests/macl.s
Normal file
17
tests/macl.s
Normal file
@ -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
|
1
tests/macl_saturation.s
Symbolic link
1
tests/macl_saturation.s
Symbolic link
@ -0,0 +1 @@
|
||||
/home/bilbo/dreamcast/example/macl_saturation.s
|
25
tests/macw.s
Normal file
25
tests/macw.s
Normal file
@ -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
|
1
tests/macw_saturation.s
Symbolic link
1
tests/macw_saturation.s
Symbolic link
@ -0,0 +1 @@
|
||||
/home/bilbo/dreamcast/example/macw_saturation.s
|
7
tests/mova.s
Normal file
7
tests/mova.s
Normal file
@ -0,0 +1,7 @@
|
||||
.long 0
|
||||
.word 0
|
||||
mova foo,r0
|
||||
.word 0
|
||||
.word 0
|
||||
foo:
|
||||
.long 0x12345678
|
18
tests/mull.s
Normal file
18
tests/mull.s
Normal file
@ -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
|
25
tests/muls.s
Normal file
25
tests/muls.s
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user