ghidra/Ghidra/Processors/Toy/data/languages/toyInstructions.sinc

225 lines
12 KiB
Plaintext

#### immediates
# 0iii dddd iiii iiii # imm rd, i load 11-bit unsigned int into rd
# 10nn dddd nnnn nnnn # simm rd, n load 10-bit signed int into rd
#
#### arithmetic
# 1100 0000 ssss tttt # add rs, rt rs = rs + rt
# 1100 0001 ssss tttt # sub rs, rt rs = rs - rt
# 1100 0010 ssss tttt # rsub rs, rt rs = rt - rs
# 1100 0011 ssss tttt # mul rs, rt rs = rs * rt
# 1100 0100 ssss tttt # div rs, rt rs = rs / rt
# 1100 0101 ssss tttt # mod rs, rt rs = rs % rt
# 1100 0110 ssss tttt # cmp rs, rt (set status only based on signed compare (rs - rt))
# 1100 0111 ssss tttt # ucmp rs, rt (set status only based on unsigned compare (rs - rt))
#
# 1100 1000 ssss nnnn # add rs, n rs = rs + n
# 1100 1001 ssss nnnn # sub rs, n rs = rs - n
# 1100 1010 ssss nnnn # rsub rs, n rs = n - rs
# 1100 1011 ssss nnnn # mul rs, n rs = rs * n
# 1100 1100 ssss nnnn # div rs, n rs = rs / n
# 1100 1101 ssss iiii # mod rs, i rs = rs % i
# 1100 1110 ssss nnnn # cmp rs, n (set status only based on signed compare (rs - n))
# 1100 1111 ssss iiii # ucmp rs, i (set status only based on unsigned compare (rs - i))
#
#### logic
# 1101 0000 ssss tttt # and rs, rt rs = rs & rt
# 1101 0001 ssss tttt # or rs, rt rs = rs | rt
# 1101 0010 ssss tttt # xor rs, rt rs = rs ^ rt
# 1101 0011 ssss tttt # lsr rs, rt rs = rs >> rt
# 1101 0100 ssss tttt # asr rs, rt rs = rs s>> rt
# 1101 0101 ssss tttt # lsl rs, rt rs = rs << rt
# 1101 1000 ssss tttt # saa rs, rt rs = (rs << 11) | rt
#
# 1101 1011 ssss iiii # lsr rs, i rs = rs >> i
# 1101 1100 ssss iiii # asr rs, i rs = rs s>> i
# 1101 1101 ssss iiii # lsl rs, i rs = rs << i
# 1101 1110 ssss 0000 # inv rs rs = ~rs
# 1101 1110 ssss 0001 # neg rs rs = -rs
#
#### memory
# 1101 0110 ssss tttt # load rs, [rt] rs = [rt]
# 1101 0111 ssss tttt # store [rs], rt [rs] = rt
# 1101 1111 ssss tttt # mov rs, rt rs = rt
#
#### flow
# 1110 nnnn nnnn 0ccc # brcc n if ccc goto pc + n
# 1110 nnnn nnnn 1ccc # brdscc n if ccc goto pc + n with delay slot
# 1111 0000 ssss 0ccc # brcc rs if ccc goto rs & ~1
# 1111 0001 ssss 0ccc # brdscc rs if ccc goto rs & ~1 with delay slot
# 1111 0010 ssss 0000 # push rs push rs
# 1111 0011 ssss 0000 # pop rs pop rs
# 1111 0100 0000 0000 # ret return
# 1111 0101 nnnn nnnn # callds n call n with delay slot
# 1111 0110 ssss 0000 # call rs call rs
# 1111 0110 ssss 1ccc # call rs if ccc call rs
# 1111 1nnn nnnn nnnn # call n call n
#
#### user-defined
# 1010 0010 ssss 0000 # user_one rs user_one rs
# 1010 0010 ssss 0000 # user_two rs user_two rs
# 1010 0011 0000 0000 # user_three user_three
# 1010 0100 ssss tttt # user_four rs rt user_four rs rt
# 1010 0101 nnnn nnnn # user_five n user_five n
# 1010 0110 ssss 0000 # user_six rs user_six rs
#
#### RESERVED
# 1101 1001 xxxx xxxx # RESERVED BANK
# 1101 1010 xxxx xxxx # RESERVED BANK
# 1111 0111 xxxx xxxx # RESERVED BANK
define token instr(16)
op1515 = (15, 15)
op1415 = (14, 15)
op1215 = (12, 15)
op1111 = (11, 11)
op0811 = (8, 11)
op0007 = (0, 7)
op0003 = (0, 3)
op0303 = (3, 3)
rd = (8, 11)
rs = (4, 7)
rt = (0, 3)
imm1214 = (12, 14)
imm0007 = (0, 7)
imm0003 = (0, 3)
simm1213 = (12, 13) signed
simm0010 = (0, 10) signed
simm0411 = (4, 11) signed
simm0007 = (0, 7) signed
simm0003 = (0, 3) signed
cc0911 = (9, 11)
cc0002 = (0, 2)
;
attach variables [ rd rs rt ] [
r0 r1 r2 r3 r4 r5 r6 r7
r8 r9 r10 r11 r12 sp lr pc
];
# addressing mode subs
Simm4: "#"^simm0003 is simm0003 { export *[const]:$(SIZE) simm0003; }
Simm10: "#"^computed is simm1213 & imm0007 [ computed = (simm1213 << 8) | imm0007; ] { export *[const]:$(SIZE) computed; }
Imm4: "#"^imm0003 is imm0003 { export *[const]:$(SIZE) imm0003; }
Imm11: "#"^computed is imm1214 & imm0007 [ computed = (imm1214 << 8) | imm0007; ] { export *[const]:$(SIZE) computed; }
Rel8: addr is simm0007 [ addr = inst_start + simm0007; ] { export *:$(SIZE) addr; }
Rel82: addr is simm0411 [ addr = inst_start + simm0411; ] { export *:$(SIZE) addr; }
Rel11: addr is simm0010 [ addr = inst_start + simm0010; ] { export *:$(SIZE) addr; }
RS: [rs] is rs { export *[ram]:$(SIZE) rs; }
RT: [rt] is rt { export *[ram]:$(SIZE) rt; }
CC: "eq" is cc0002=0x0 { export Z; }
CC: "ne" is cc0002=0x1 { tmp = !Z; export tmp; }
CC: "lt" is cc0002=0x2 { tmp = N != V; export tmp; }
CC: "le" is cc0002=0x3 { tmp = Z || (N != V); export tmp; }
CC: "lo" is cc0002=0x4 { export C; }
CC: "mi" is cc0002=0x5 { export N; }
CC: "vs" is cc0002=0x6 { export V; }
CC: "" is cc0002=0x7 { export 1:1; }
COND: CC is CC { if (!CC) goto inst_next; }
COND: CC is CC & cc0002=0x7 { } # unconditional
macro resultflags(result) {
N = result s< 0;
Z = result == 0;
}
macro addflags(a, b) {
C = carry(a, b);
V = scarry(a, b);
}
macro subflags(a, b) {
C = a s< b;
V = sborrow(a, b);
}
macro logicflags() {
C = 0;
V = 0;
}
define pcodeop pcodeop_one;
define pcodeop pcodeop_two;
define pcodeop pcodeop_three;
# operations
:imm rd, Imm11 is $(INSTR_PHASE) op1515=0x0 & rd & Imm11 { logicflags(); rd = Imm11; resultflags(rd); }
:simm rd, Simm10 is $(INSTR_PHASE) op1415=0x2 & rd & Simm10 { logicflags(); rd = Simm10; resultflags(rd); }
:add rs, rt is $(INSTR_PHASE) op1215=0xc & op0811=0x0 & rs & rt { addflags(rs, rt); rs = rs + rt; resultflags(rs); }
:sub rs, rt is $(INSTR_PHASE) op1215=0xc & op0811=0x1 & rs & rt { subflags(rs, rt); rs = rs - rt; resultflags(rs); }
:rsub rs, rt is $(INSTR_PHASE) op1215=0xc & op0811=0x2 & rs & rt { subflags(rt, rs); rs = rt - rs; resultflags(rs); }
:mul rs, rt is $(INSTR_PHASE) op1215=0xc & op0811=0x3 & rs & rt { rs = rs * rt; resultflags(rs); } # fix C & V
:div rs, rt is $(INSTR_PHASE) op1215=0xc & op0811=0x4 & rs & rt { rs = rs / rt; resultflags(rs); } # fix C & V
:mod rs, rt is $(INSTR_PHASE) op1215=0xc & op0811=0x5 & rs & rt { rs = rs % rt; resultflags(rs); } # fix C & V
:cmp rs, rt is $(INSTR_PHASE) op1215=0xc & op0811=0x6 & rs & rt { subflags(rs, rt); tmp:$(SIZE) = rs - rt; resultflags(tmp); }
:ucmp rs, rt is $(INSTR_PHASE) op1215=0xc & op0811=0x7 & rs & rt { logicflags(); N = rs < rt; Z = rs == rt; }
:add rs, Simm4 is $(INSTR_PHASE) op1215=0xc & op0811=0x8 & rs & Simm4 { addflags(rs, Simm4); rs = rs + Simm4; resultflags(rs); }
:sub rs, Simm4 is $(INSTR_PHASE) op1215=0xc & op0811=0x9 & rs & Simm4 { subflags(rs, Simm4); rs = rs - Simm4; resultflags(rs); }
:rsub rs, Simm4 is $(INSTR_PHASE) op1215=0xc & op0811=0xa & rs & Simm4 { subflags(Simm4, rs); rs = Simm4 - rs; resultflags(rs); }
:mul rs, Simm4 is $(INSTR_PHASE) op1215=0xc & op0811=0xb & rs & Simm4 { rs = rs * Simm4; resultflags(rs); } # fix C & V
:div rs, Simm4 is $(INSTR_PHASE) op1215=0xc & op0811=0xc & rs & Simm4 { rs = rs / Simm4; resultflags(rs); } # fix C & V
:mod rs, Imm4 is $(INSTR_PHASE) op1215=0xc & op0811=0xd & rs & Imm4 { rs = rs % Imm4; resultflags(rs); } # fix C & V
:cmp rs, Simm4 is $(INSTR_PHASE) op1215=0xc & op0811=0xe & rs & Simm4 { subflags(rs, Simm4); tmp:$(SIZE) = rs - Simm4; resultflags(tmp); }
:ucmp rs, Imm4 is $(INSTR_PHASE) op1215=0xc & op0811=0xf & rs & Imm4 { logicflags(); N = rs < Imm4; Z = rs == Imm4; }
:and rs, rt is $(INSTR_PHASE) op1215=0xd & op0811=0x0 & rs & rt { logicflags(); rs = rs & rt; resultflags(rs); }
:or rs, rt is $(INSTR_PHASE) op1215=0xd & op0811=0x1 & rs & rt { logicflags(); rs = rs | rt; resultflags(rs); }
:xor rs, rt is $(INSTR_PHASE) op1215=0xd & op0811=0x2 & rs & rt { logicflags(); rs = rs ^ rt; resultflags(rs); }
:lsr rs, rt is $(INSTR_PHASE) op1215=0xd & op0811=0x3 & rs & rt { logicflags(); rs = rs >> rt; resultflags(rs); }
:asr rs, rt is $(INSTR_PHASE) op1215=0xd & op0811=0x4 & rs & rt { logicflags(); rs = rs s>> rt; resultflags(rs); }
:lsl rs, rt is $(INSTR_PHASE) op1215=0xd & op0811=0x5 & rs & rt { logicflags(); rs = rs << rt; resultflags(rs); }
# saa == shift and accumulate; very useful for building up a 32 bit or 64 bit value in pieces, like:
# imm r12, #32b
# imm r11, #7d7
# saa r12, r11
# imm r11, #2be
# saa r12, r11
#
# now r12 contains '0xcafebabe' (decompiler reconstitutes the pieces seamlessly)
:saa rs, rt is $(INSTR_PHASE) op1215=0xd & op0811=0x8 & rs & rt { logicflags(); rs = (rs << 11) | rt; resultflags(rs); }
:lsr rs, Imm4 is $(INSTR_PHASE) op1215=0xd & op0811=0xb & rs & Imm4 { logicflags(); rs = rs >> Imm4; resultflags(rs); }
:asr rs, Imm4 is $(INSTR_PHASE) op1215=0xd & op0811=0xc & rs & Imm4 { logicflags(); rs = rs s>> Imm4; resultflags(rs); }
:lsl rs, Imm4 is $(INSTR_PHASE) op1215=0xd & op0811=0xd & rs & Imm4 { logicflags(); rs = rs << Imm4; resultflags(rs); } # fix C & V
:inv rs is $(INSTR_PHASE) op1215=0xd & op0811=0xe & rs & op0003=0x0 { logicflags(); rs = ~rs; resultflags(rs); }
:neg rs is $(INSTR_PHASE) op1215=0xd & op0811=0xe & rs & op0003=0x1 { logicflags(); rs = -rs; resultflags(rs); }
:load rs, RT is $(INSTR_PHASE) op1215=0xd & op0811=0x6 & rs & RT { rs = RT; logicflags(); resultflags(rs); }
:store RS, rt is $(INSTR_PHASE) op1215=0xd & op0811=0x7 & RS & rt { RS = rt; logicflags(); resultflags(rt); }
:mov rs, rt is $(INSTR_PHASE) op1215=0xd & op0811=0xf & rs & rt { rs = rt; logicflags(); resultflags(rs); }
:br^COND Rel82 is $(INSTR_PHASE) op1215=0xe & op0303=0x0 & COND & Rel82 { build COND; goto Rel82; }
:brds^COND Rel82 is $(INSTR_PHASE) op1215=0xe & op0303=0x1 & COND & Rel82 { build COND; delayslot(1); goto Rel82; }
:br^COND rs is $(INSTR_PHASE) op1215=0xf & op0811=0x0 & COND & rs & op0303=0x0 { build COND; goto [rs]; }
:brds^COND rs is $(INSTR_PHASE) op1215=0xf & op0811=0x1 & COND & rs & op0303=0x0 { build COND; delayslot(1); goto [rs]; }
@ifdef POS_STACK
:push rs is $(INSTR_PHASE) op1215=0xf & op0811=0x2 & rs & op0003=0x0 { *[ram]:$(SIZE) sp = rs; sp = sp + $(SIZE); logicflags(); resultflags(rs); }
:pop rs is $(INSTR_PHASE) op1215=0xf & op0811=0x3 & rs & op0003=0x0 { sp = sp - $(SIZE); rs = *[ram]:$(SIZE) sp; logicflags(); resultflags(rs); }
@else
:push rs is $(INSTR_PHASE) op1215=0xf & op0811=0x2 & rs & op0003=0x0 { *[ram]:$(SIZE) sp = rs; sp = sp - $(SIZE); logicflags(); resultflags(rs); }
:pop rs is $(INSTR_PHASE) op1215=0xf & op0811=0x3 & rs & op0003=0x0 { sp = sp + $(SIZE); rs = *[ram]:$(SIZE) sp; logicflags(); resultflags(rs); }
@endif
:ret is $(INSTR_PHASE) op1215=0xf & op0811=0x4 & op0007=0x0 { return [lr]; }
:callds Rel8 is $(INSTR_PHASE) op1215=0xf & op0811=0x5 & Rel8 { delayslot(1); lr = inst_next; call Rel8; }
:call rs is $(INSTR_PHASE) op1215=0xf & op0811=0x6 & rs & op0003=0x0 { lr = inst_next; call [rs]; }
:call Rel11 is $(INSTR_PHASE) op1215=0xf & op1111=0x1 & Rel11 { lr = inst_next; call Rel11; }
# 1111 0110 ssss 1ccc # call rs if ccc call rs
:call^COND rs is $(INSTR_PHASE) op1215=0xf & op0811=0x6 & rs & op0303=0x1 & COND { build COND; lr = inst_next; call [rs]; }
:user_one rs is $(INSTR_PHASE) op1215=0xa & op0811=0x01 & rs & op0003=0x0 { pcodeop_one(rs);}
:user_two rs is $(INSTR_PHASE) op1215=0xa & op0811=0x02 & rs & op0003=0x0 { pcodeop_two(rs); pcodeop_three();}
:user_three is $(INSTR_PHASE) op1215=0xa & op0811=0x03 & op0007=0x0 { pcodeop_three();}
:user_four rs rt is $(INSTR_PHASE) op1215=0xa & op0811=0x04 & rs & rt { pcodeop_one(rs); call [rt]; pcodeop_three();}
:user_five Rel8 is $(INSTR_PHASE) op1215=0xa & op0811=0x05 & Rel8 { lr = inst_next; call Rel8; pcodeop_three();}
:user_six rs is $(INSTR_PHASE) op1215=0xa & op0811=0x06 & rs & op0003=0x0 { r1 = pcodeop_one(rs); call [r1];}