initial sh2 interpreter

This commit is contained in:
Zack Buhman 2024-04-09 09:57:08 +08:00
commit 6eba0cdb9e
42 changed files with 3595 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
__pycache__
*.o
*.elf
*.bin
*.pyc

30
compare.py Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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()

1370
impl2.py Normal file

File diff suppressed because it is too large Load Diff

47
instruction_properties.py Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1 @@
/home/bilbo/dreamcast/example/macl_saturation.s

25
tests/macw.s Normal file
View 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
View File

@ -0,0 +1 @@
/home/bilbo/dreamcast/example/macw_saturation.s

7
tests/mova.s Normal file
View 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
View 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
View 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