Created
May 18, 2019 08:32
-
-
Save murachue/2e63f7f2d03d79ba92b5e67b1e1499a4 to your computer and use it in GitHub Desktop.
INCOMPLETE SH-2 Ghidra processor module
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<compiler_spec> | |
<global> | |
<range space="RAM"/> | |
</global> | |
<stackpointer register="r15" space="RAM" growth="negative"/> | |
<returnaddress> | |
<register name="pr"/> | |
</returnaddress> | |
<default_proto> | |
<prototype name="__stdcall" extrapop="0" stackshift="0" strategy="register"> | |
<input> | |
<pentry minsize="1" maxsize="4"> | |
<register name="r4"/> | |
</pentry> | |
<pentry minsize="1" maxsize="4"> | |
<register name="r5"/> | |
</pentry> | |
<pentry minsize="1" maxsize="4"> | |
<register name="r6"/> | |
</pentry> | |
<pentry minsize="1" maxsize="4"> | |
<register name="r7"/> | |
</pentry> | |
<pentry minsize="1" maxsize="500" align="4"> | |
<addr offset="0" space="stack"/> | |
</pentry> | |
</input> | |
<output> | |
<pentry minsize="1" maxsize="4"> | |
<register name="r0"/> | |
</pentry> | |
</output> | |
<unaffected> | |
<register name="r8"/> | |
<register name="r9"/> | |
<register name="r10"/> | |
<register name="r11"/> | |
<register name="r12"/> | |
<register name="r13"/> | |
<register name="r14"/> | |
<register name="r15"/> <!-- sp --> | |
</unaffected> | |
</prototype> | |
</default_proto> | |
</compiler_spec> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<language_definitions> | |
<language processor="SH-2" | |
endian="big" | |
size="32" | |
variant="default" | |
version="1.0" | |
slafile="sh2.sla" | |
processorspec="sh2.pspec" | |
id="SH2:BE:32:default"> | |
<description>SH-2 Family</description> | |
<compiler name="default" spec="sh2.cspec" id="default"/> | |
<external_name tool="IDA-PRO" name="sh2"/> | |
</language> | |
</language_definitions> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<processor_spec> | |
<programcounter register="pc"/> | |
</processor_spec> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# INCOMPLETE sleigh specification file for Hitachi SH-2 | |
# just for learning SLEIGH | |
# you should use https://github.com/VGKintsugi/Ghidra-SegaSaturn-Processor | |
define endian=big; | |
define alignment=2; | |
define space RAM type=ram_space size=4 default; | |
define space register type=register_space size=4; | |
define register offset=0x00 size=4 [ r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 ]; | |
define register offset=0x40 size=4 [ sr GBR VBR TBR ]; # ctlreg | |
define register offset=0x80 size=4 [ mach macl pr pc ]; # sysreg | |
#define bitrange | |
# BO=sr[14,1] | |
# CS=sr[13,1] | |
# M=sr[9,1] | |
# Q=sr[8,1] | |
# I=sr[4,4] | |
# S=sr[1,1] | |
# T=sr[0,1]; | |
# "define bitrange" produces wrong sla output... use macro. | |
@define SR_BO "sr[14,1]" | |
@define SR_CS "sr[13,1]" | |
@define SR_M "sr[9,1]" | |
@define SR_Q "sr[8,1]" | |
@define SR_I "sr[4,1]" | |
@define SR_S "sr[1,1]" | |
@define SR_T "sr[0,1]" | |
# TODO: ... or emulate sr on ldc/sdc and define those bits as individual registers. | |
# TODO: floating points | |
define token insn (16) | |
op16 = (0,15) | |
op = (12,15) | |
n = (8,11) | |
op8 = (8,15) | |
m = (4,7) | |
mc = (4,7) | |
ms = (4,7) | |
d4u = (0,3) | |
d8 = (0,7) signed # for branch | |
d8u = (0,7) | |
d12 = (0,11) signed | |
i = (0,7) signed | |
iu = (0,7) | |
opl = (0,3) | |
opl8 = (0,7) | |
; | |
attach variables [n m] [r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15]; | |
attach variables [mc] [sr GBR VBR _ _ _ _ _ _ _ _ _ _ _ _ _]; | |
attach variables [ms] [mach macl pr _ _ _ _ _ _ _ _ _ _ _ _ _]; | |
Rel12: addr is d12 [ addr = inst_start + 4 + d12 * 2; ] { export *:4 addr; } | |
# FIXME: 20190408 I don't know why sleigh-compiler crash when write in a line but not if Rel8+b* | |
Rel8: addr is d8 [ addr = inst_start + 4 + d8 * 2; ] { export *:4 addr; } | |
:stc mc,n is op=0 & n & mc & opl=2 { n = mc; } | |
:bsrf n is op=0 & n & opl8=0x03 { pr = inst_start + 4; npc = inst_start + 4 + n; delayslot(1); call [npc]; } # reusing n as m | |
:braf n is op=0 & n & opl8=0x23 { npc = inst_start + 4 + n; delayslot(1); goto [npc]; } # XXX: reusing n as m | |
:mov.b m,@(r0,n) is op=0 & n & m & opl=4 & r0 { *:1 (r0 + n) = m:1; } | |
:mov.w m,@(r0,n) is op=0 & n & m & opl=5 & r0 { *:2 (r0 + n) = m:2; } | |
:mov.l m,@(r0,n) is op=0 & n & m & opl=6 & r0 { *:4 (r0 + n) = m; } | |
:mul.l m,n is op=0 & n & m & opl=7 { macl = n * m; } # no mach change | |
:nop is op16=0x0009 { } | |
:div0u is op16=0x0019 { $(SR_M) = 0; $(SR_Q) = 0; $(SR_T) = 0; } | |
:movt n is op=0 & n & opl8=0x29 { n = zext($(SR_T)); } | |
:sts ms,n is op=0 & n & ms & opl=10 { n = ms; } | |
:rts is op16=0x000B { npc = pr; delayslot(1); return [npc]; } | |
:rte is op16=0x002B { npc = *:4 r15; r15 = r15 + 4; sr = *:4 r15 & 0x000063F3; r15 = r15 + 4; delayslot(1); goto [npc]; } | |
:mov.b @(r0,m),n is op=0 & n & m & opl=12 & r0 { n = sext(*:1 (r0 + m)); } | |
:mov.w @(r0,m),n is op=0 & n & m & opl=13 & r0 { n = sext(*:2 (r0 + m)); } | |
:mov.l @(r0,m),n is op=0 & n & m & opl=14 & r0 { n = *:4 (r0 + m); } | |
:mov.l m,@(d4ul2,n) is op=1 & n & m & d4u [ d4ul2 = d4u * 4; ] { *:4 (n + d4ul2) = m:4; } | |
:mov.b m,@n is op=2 & m & n & opl=0 { *:1 n = m:1; } | |
:mov.w m,@n is op=2 & m & n & opl=1 { *:2 n = m:2; } | |
:mov.l m,@n is op=2 & m & n & opl=2 { *:4 n = m; } | |
:mov.b m,@-n is op=2 & m & n & opl=4 { n = n - 4; *:1 n = m:1; } | |
:mov.w m,@-n is op=2 & m & n & opl=5 { n = n - 4; *:2 n = m:2; } | |
:mov.l m,@-n is op=2 & m & n & opl=6 { n = n - 4; *:4 n = m; } | |
:div0s m,n is op=2 & n & m & opl=7 { $(SR_Q) = ((n & 0x80000000) != 0); $(SR_M) = ((m & 0x80000000) != 0); $(SR_T) = $(SR_M) ^ $(SR_Q); } | |
:tst m,n is op=2 & n & m & opl=8 { $(SR_T) = ((n & m) == 0); } | |
:and m,n is op=2 & n & m & opl=9 { n = n & m; } | |
:xor m,n is op=2 & n & m & opl=10 { n = n ^ m; } | |
:or m,n is op=2 & n & m & opl=11 { n = n | m; } | |
:cmp/"str" m,n is op=2 & n & m & opl=12 { | |
t = n ^ m; | |
hh = (((t >> 24) & 255) == 0); | |
hl = (((t >> 16) & 255) == 0); | |
lh = (((t >> 8) & 255) == 0); | |
ll = ((t & 255) == 0); | |
$(SR_T) = (hh || hl || lh || ll); # T=1 if some byte(s) are matched | |
} | |
:xtrct m,n is op=2 & n & m & opl=13 { n = ((m & 0xFFFF) << 16) | (n >> 16); } | |
:mulu.w m,n is op=2 & n & m & opl=14 { macl = zext(n:2) * zext(m:2); } | |
:muls.w m,n is op=2 & n & m & opl=15 { macl = sext(n:2) * sext(m:2); } | |
:cmp/"eq" m,n is op=3 & n & m & opl=0 { $(SR_T) = (n == m); } | |
:cmp/"hs" m,n is op=3 & n & m & opl=2 { $(SR_T) = (n >= m); } # high-or-same? | |
:cmp/"ge" m,n is op=3 & n & m & opl=3 { $(SR_T) = (n s>= m); } | |
:div1 m,n is op=3 & n & m & opl=4 { | |
oldq = $(SR_Q); | |
$(SR_Q) = ((n & 0x80000000) != 0); | |
n = (n << 1) | zext($(SR_T)); | |
negater:4 = 1 - (sext(oldq != $(SR_M)) * 2); # sext or zext. | |
oldn = n; | |
# if oldq==M then {n-=m;c=n>oldn} else {n+=m;c=n<oldn} | |
n = n - (m * negater); | |
c = (n * negater) > (oldn * negater); | |
# if M==Q then Q=c; else Q=(c==0); | |
$(SR_Q) = c ^ ($(SR_M) != $(SR_Q)); | |
$(SR_T) = ($(SR_Q) == $(SR_M)); | |
} | |
:dmulu.l m,n is op=3 & n & m & opl=5 { t:8 = zext(m) * zext(n); mach = t(4); macl = t:4; } | |
:cmp/"hi" m,n is op=3 & n & m & opl=6 { $(SR_T) = (n > m); } | |
:cmp/"gt" m,n is op=3 & n & m & opl=7 { $(SR_T) = (n s> m); } | |
:sub m,n is op=3 & n & m & opl=8 { n = n - m; } | |
:subc m,n is op=3 & n & m & opl=10 { on = n; r = n - m; n = r - zext($(SR_T)); $(SR_T) = (on < r) | (r < n); } | |
:add m,n is op=3 & n & m & opl=12 { n = n + m; } | |
:dmuls.l m,n is op=3 & n & m & opl=13 { t:8 = sext(m) * sext(n); mach = t(4); macl = t:4; } | |
# users manual style # or using carry() style (seems produce same decompile) | |
:addc m,n is op=3 & n & m & opl=14 { tmp1 = n + m; tmp0 = n; n = tmp1 + zext($(SR_T)); $(SR_T) = ((tmp0 > tmp1) | (tmp1 > n)); } # { c1 = carry(n, m); n = n + m; c2 = carry(n, zext($(SR_T))); n = n + zext($(SR_T)); $(SR_T) = (c1 | c2); } | |
:shll n is op=4 & n & opl8=0x00 { $(SR_T) = ((n & 0x80000000) != 0); n = n << 1; } | |
:dt n is op=4 & n & opl8=0x10 { n = n - 1; $(SR_T) = (n == 0); } | |
:shal n is op=4 & n & opl8=0x20 { $(SR_T) = ((n & 0x80000000) != 0); n = n << 1; } # same as shll. | |
:shlr n is op=4 & n & opl8=0x01 { $(SR_T) = ((n & 1) != 0); n = n >> 1; } | |
:cmp/"pz" n is op=4 & n & opl8=0x11 { $(SR_T) = (n s>= 0); } | |
:shar n is op=4 & n & opl8=0x21 { $(SR_T) = ((n & 1) != 0); n = n s>> 1; } | |
:sts.l ms,@-n is op=4 & n & ms & opl=2 { n = n - 4; *n = ms; } | |
:stc.l mc,@-n is op=4 & n & mc & opl=3 { n = n - 4; *n = mc; } | |
:rotl n is op=4 & n & opl8=0x04 { $(SR_T) = ((n & 0x80000000) != 0); n = (n << 1) | (n >> 31); } | |
:rotcl n is op=4 & n & opl8=0x24 { ot = $(SR_T); $(SR_T) = ((n & 0x80000000) != 0); n = (n << 1) | zext(ot); } | |
:rotr n is op=4 & n & opl8=0x05 { $(SR_T) = ((n & 1) != 0); n = (n >> 1) | (n << 31); } | |
:cmp/"pl" n is op=4 & n & opl8=0x15 { $(SR_T) = (n s> 0); } | |
:rotcr n is op=4 & n & opl8=0x25 { ot = $(SR_T); $(SR_T) = ((n & 1) != 0); n = (zext(ot) << 31) | (n >> 1); } | |
:lds.l @n+,ms is op=4 & n & ms & opl=6 { ms = *n; n = n + 4; } | |
:ldc.l @n+,mc is op=4 & n & mc & opl=7 { mc = *n; n = n + 4; } | |
:shll2 n is op=4 & n & opl8=0x08 { n = n << 2; } | |
:shll8 n is op=4 & n & opl8=0x18 { n = n << 8; } | |
:shll16 n is op=4 & n & opl8=0x28 { n = n << 16; } | |
:shlr2 n is op=4 & n & opl8=0x09 { n = n >> 2; } | |
:shlr8 n is op=4 & n & opl8=0x19 { n = n >> 8; } | |
:shlr16 n is op=4 & n & opl8=0x29 { n = n >> 16; } | |
:lds n,ms is op=4 & ms & n & opl=10 { ms = n; } | |
:jsr @n is op=4 & n & opl8=0x0B { pr = inst_start + 4; npc = n; delayslot(1); call [npc]; } # XXX: reusing n as m | |
:jmp @n is op=4 & n & opl8=0x2B { npc = n; delayslot(1); goto [npc]; } | |
# XXX: "m" and "n(c)" naming is reversed to reuse fields... | |
:ldc n,mc is op=4 & n & mc & opl=14 { mc = n; } | |
:mov.l @(d4ul2,m),n is op=5 & n & m & d4u [ d4ul2 = d4u * 4; ] { n = *:4 (m + d4ul2); } | |
:mov.b @m,n is op=6 & n & m & opl=0 { n = sext(*:1 m); } | |
:mov.w @m,n is op=6 & n & m & opl=1 { n = sext(*:2 m); } | |
:mov.l @m,n is op=6 & n & m & opl=2 { n = *:4 m; } | |
:mov m,n is op=6 & m & n & opl=3 { n = m; } | |
:mov.b @m+,n is op=6 & m & n & opl=4 { n = sext(*:1 m); m = m + 4; } | |
:mov.w @m+,n is op=6 & m & n & opl=5 { n = sext(*:2 m); m = m + 4; } | |
:mov.l @m+,n is op=6 & m & n & opl=6 { n = *:4 m; m = m + 4; } | |
:not m,n is op=6 & n & m & opl=7 { n = ~m; } | |
:neg m,n is op=6 & n & m & opl=11 { n = -m; } | |
:extu.b m,n is op=6 & n & m & opl=12 { n = zext(m:1); } | |
:extu.w m,n is op=6 & n & m & opl=13 { n = zext(m:2); } | |
:exts.b m,n is op=6 & n & m & opl=14 { n = sext(m:1); } | |
:exts.w m,n is op=6 & n & m & opl=15 { n = sext(m:2); } | |
:add #i,n is op=7 & n & i { n = n + i; } | |
:mov.b r0,@(d4u,m) is op8=0x80 & m & d4u & r0 { *:1 (m + d4u ) = r0:1; } # XXX: reusing m as n | |
:mov.w r0,@(d4ul1,m) is op8=0x81 & m & d4u & r0 [ d4ul1 = d4u * 2; ] { *:2 (m + d4ul1) = r0:2; } # XXX: reusing m as n | |
:mov.b @(d4u,m),r0 is op8=0x84 & m & d4u & r0 { r0 = sext(*:1 (m + d4u )); } | |
:mov.w @(d4ul1,m),r0 is op8=0x85 & m & d4u & r0 [ d4ul1 = d4u * 2; ] { r0 = sext(*:2 (m + d4ul1)); } | |
:cmp/"eq" #i,"r0" is op8=0x88 & i { $(SR_T) = (r0 == sext(i:1)); } # XXX: sleigh-compiler can't know i is 1byte?? | |
#:bt pcrel8 is op8=0x89 & d8 [ pcrel8 = inst_start + 4 + (d8 << 1); ] { if($(SR_T)) goto *:4(inst_start + 4 + sext(d8 << 1)); } | |
:bt Rel8 is op8=0x89 & Rel8 { if($(SR_T)) goto Rel8; } | |
#:bf pcrel8 is op8=0x8B & d8 [ pcrel8 = inst_start + 4 + (d8 << 1); ] { if(!$(SR_T)) goto (inst_start + 4 + sext(d8 << 1)); } | |
:bf Rel8 is op8=0x8B & Rel8 { if(!$(SR_T)) goto Rel8; } | |
# NOTE: SR_T must be kept while delayslot() because it will rewrite T. | |
#:bt/"s" pcrel8 is op8=0x8D & d8 [ pcrel8 = inst_start + 4 + (d8 << 1); ] { tt = $(SR_T); delayslot(1); if(tt) goto (inst_start + 4 + sext(d8 << 1)); } | |
:bt/"s" Rel8 is op8=0x8D & Rel8 { tt = $(SR_T); delayslot(1); if(tt) goto Rel8; } | |
#:bf/"s" pcrel8 is op8=0x8F & d8 [ pcrel8 = inst_start + 4 + (d8 << 1); ] { tt = $(SR_T); delayslot(1); if(!tt) goto (inst_start + 4 + sext(d8 << 1)); } | |
:bf/"s" Rel8 is op8=0x8F & Rel8 { tt = $(SR_T); delayslot(1); if(!tt) goto Rel8; } | |
#:mov.w @(d8ul1,pc),n is op=9 & n & d8u & pc [ d8ul1 = d8u * 2; ] { pval:4 = inst_start + 4 + d8ul1; n = sext(*:2 pval); } | |
:mov.w @(rel),n is op=9 & n & d8u [ rel = inst_start + 4 + d8u * 2; ] { tmp:4 = rel; n = sext(*:2 tmp); } # XXX: WTF unknown size!? must use tmp to specify size. | |
#:bra rel is op=10 & d12 [ rel = inst_start + 4 + d12 * 2; ] { delayslot(1); goto [rel:4]; } # this does not resolve operand as label. | |
:bra Rel12 is op=10 & Rel12 { delayslot(1); goto Rel12; } | |
:bsr Rel12 is op=11 & Rel12 { pr = inst_start + 4; delayslot(1); call Rel12; } | |
#:mova @(d8ul2,pc),r0 is op8=0xC7 & d8u & pc & r0 [ d8ul2 = d8u << 2; ] { r0 = ((inst_start + 4) & ~3) + d8ul2; } | |
:mova rel,r0 is op8=0xC7 & d8u & r0 [ rel = ((inst_start + 4) & ~3) + d8u * 4; ] { r0 = rel; } | |
:tst #iu,r0 is op8=0xC8 & iu & r0 { $(SR_T) = ((r0 & iu) == 0); } | |
:and #iu,r0 is op8=0xC9 & iu & r0 { r0 = r0 & iu; } | |
:xor #iu,r0 is op8=0xCA & iu & r0 { r0 = r0 ^ iu; } | |
:or #iu,r0 is op8=0xCB & iu & r0 { r0 = r0 | iu; } | |
# TODO: tst #iu,@(r0,GBR) is op8=0xCC and iu | |
# TODO: and #iu,@(r0,GBR) is op8=0xCD and iu | |
# TODO: xor #iu,@(r0,GBR) is op8=0xCE and iu | |
# TODO: or #iu,@(r0,GBR) is op8=0xCF and iu | |
#pcrlc: #c is d8u { b:4 = (inst_start + 4) & ~3; p:4 = b + zext(d8u); c = *:4 p; export c; } | |
#:mov.l pcrlc,n is op=13 & n & pcrlc { n = pcrlc; } | |
#:mov.l @(d8ul2,pc),n is op=13 & n & d8u & pc [ d8ul2 = d8u << 2; ] { pval:4 = ((inst_start + 4) & ~3) + (d8u << 2); n = *pval; } | |
#:mov.l @(rel),n is op=13 & n & d8u [ rel = ((inst_start + 4) & ~3) + d8u * 4; ] { n = *:4 rel; } | |
:mov.l @(rel),n is op=13 & n & d8u [ rel = ((inst_start + 4) & ~3) + d8u * 4; ] { rela:4 = ((inst_start + 4) & ~3) + d8u * 4; n = *:4 rela; } # WTF unknown size!? | |
:mov #i,n is op=14 & n & i { n = i; } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment