From 5e299be86277c03a010f53f3645fb3a197e6c17e Mon Sep 17 00:00:00 2001 From: Dan Genin Date: Thu, 21 Mar 2024 19:30:49 -0400 Subject: [PATCH] Added ARC4 CPU support --- Ghidra/Processors/ARC4/LICENSE.txt | 29 + Ghidra/Processors/ARC4/Module.manifest | 0 Ghidra/Processors/ARC4/add.s | 56 ++ Ghidra/Processors/ARC4/branch.s | 42 + Ghidra/Processors/ARC4/build.gradle | 11 + Ghidra/Processors/ARC4/build_test.sh | 4 + Ghidra/Processors/ARC4/certification.manifest | 32 + .../Processors/ARC4/data/languages/ARC4.cspec | 74 ++ .../Processors/ARC4/data/languages/ARC4.ldefs | 18 + .../Processors/ARC4/data/languages/ARC4.pspec | 9 + .../Processors/ARC4/data/languages/ARC4.sinc | 66 ++ .../ARC4/data/languages/ARC4Instructions.sinc | 791 ++++++++++++++++++ .../ARC4/data/languages/ARC4_le.slaspec | 9 + .../ARC4/data/patterns/ARC4_LE_patterns.xml | 11 + .../ARC4/data/patterns/ARC4_patterns.xml | 11 + .../ARC4/data/patterns/patternconstraints.xml | 5 + Ghidra/Processors/ARC4/data/sleighArgs.txt | 0 Ghidra/Processors/ARC4/ext.s | 36 + Ghidra/Processors/ARC4/jump.s | 13 + Ghidra/Processors/ARC4/ld.s | 23 + Ghidra/Processors/ARC4/logic_ops.s | 27 + Ghidra/Processors/ARC4/loop.s | 42 + Ghidra/Processors/ARC4/objdump.sh | 2 + Ghidra/Processors/ARC4/ret.s | 14 + Ghidra/Processors/ARC4/sr.s | 18 + Ghidra/Processors/ARC4/st.s | 13 + Ghidra/Processors/ARC4/sub.s | 44 + Ghidra/Processors/ARC4/test | Bin 0 -> 2442 bytes Ghidra/Processors/ARC4/test.s | 28 + 29 files changed, 1428 insertions(+) create mode 100644 Ghidra/Processors/ARC4/LICENSE.txt create mode 100644 Ghidra/Processors/ARC4/Module.manifest create mode 100644 Ghidra/Processors/ARC4/add.s create mode 100644 Ghidra/Processors/ARC4/branch.s create mode 100644 Ghidra/Processors/ARC4/build.gradle create mode 100755 Ghidra/Processors/ARC4/build_test.sh create mode 100644 Ghidra/Processors/ARC4/certification.manifest create mode 100644 Ghidra/Processors/ARC4/data/languages/ARC4.cspec create mode 100644 Ghidra/Processors/ARC4/data/languages/ARC4.ldefs create mode 100644 Ghidra/Processors/ARC4/data/languages/ARC4.pspec create mode 100644 Ghidra/Processors/ARC4/data/languages/ARC4.sinc create mode 100644 Ghidra/Processors/ARC4/data/languages/ARC4Instructions.sinc create mode 100644 Ghidra/Processors/ARC4/data/languages/ARC4_le.slaspec create mode 100644 Ghidra/Processors/ARC4/data/patterns/ARC4_LE_patterns.xml create mode 100644 Ghidra/Processors/ARC4/data/patterns/ARC4_patterns.xml create mode 100644 Ghidra/Processors/ARC4/data/patterns/patternconstraints.xml create mode 100644 Ghidra/Processors/ARC4/data/sleighArgs.txt create mode 100644 Ghidra/Processors/ARC4/ext.s create mode 100644 Ghidra/Processors/ARC4/jump.s create mode 100644 Ghidra/Processors/ARC4/ld.s create mode 100644 Ghidra/Processors/ARC4/logic_ops.s create mode 100644 Ghidra/Processors/ARC4/loop.s create mode 100755 Ghidra/Processors/ARC4/objdump.sh create mode 100644 Ghidra/Processors/ARC4/ret.s create mode 100644 Ghidra/Processors/ARC4/sr.s create mode 100644 Ghidra/Processors/ARC4/st.s create mode 100644 Ghidra/Processors/ARC4/sub.s create mode 100755 Ghidra/Processors/ARC4/test create mode 100644 Ghidra/Processors/ARC4/test.s diff --git a/Ghidra/Processors/ARC4/LICENSE.txt b/Ghidra/Processors/ARC4/LICENSE.txt new file mode 100644 index 0000000000..e5432dcf50 --- /dev/null +++ b/Ghidra/Processors/ARC4/LICENSE.txt @@ -0,0 +1,29 @@ +Copyright (c) 2023, Johns Hopkins University Applied Physics Laboratory +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Ghidra/Processors/ARC4/Module.manifest b/Ghidra/Processors/ARC4/Module.manifest new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Ghidra/Processors/ARC4/add.s b/Ghidra/Processors/ARC4/add.s new file mode 100644 index 0000000000..5786fc6840 --- /dev/null +++ b/Ghidra/Processors/ARC4/add.s @@ -0,0 +1,56 @@ +; Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC +; Authors: Dan Genin and Tommy Johnson + + add r2, 0, 0 + add r3, 1, 1 + add r4, 2, 2 + add r6, 3, 3 + add r0, r1, r5 + nop + add ilink1, 4, 4 + add blink, 5, 5 + add sp, 6, 6 + add r1,r2,32 + add r3,r4,32 + add r5,r6,32 + add r1,ilink1,32 + add r1,blink,32 + add r1,sp,32 + add fp,sp,sp + add sp,r1,sp + add r1,r1,32 + add r1,r1,32 + add r1,r1,0x1FFFFFFF + add 0x1FFFFFFF,r1,r2 + + ADD r1,r2,r3 + ADD.NZ r1,r2,r3 + ADD.F r1,r2,r3 + ADD.NZ.F r1,r2,r3 + ADD r1,r2,34 + ADD.F r1,r2,34 + ADD r1,34,r2 + ADD r1,255,255 + ADD.F 0,r1,r2 + ADD.F 0,r1,34 + ADD.F 0,34,r1 + ADD 0,0,0 + ADD r3,1,2 + ADD.F r3,1,2 + ;; A is shimmflags +.WORD 0x47c08500 + ;; A is limm +.WORD 0x47a08500 + ;; register register + ;; conditional + ;; setting flags + ;;conditional and conditionally set flags + ;;register immediate + ;;immediate register + ;;immediate immediate (shimms MUST match) + ;;test + ;;test with immediate + ;;test with immediate + ;;null instruction, NOP + + diff --git a/Ghidra/Processors/ARC4/branch.s b/Ghidra/Processors/ARC4/branch.s new file mode 100644 index 0000000000..204ae9bec8 --- /dev/null +++ b/Ghidra/Processors/ARC4/branch.s @@ -0,0 +1,42 @@ +; Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC +; Authors: Dan Genin and Tommy Johnson + +mov r0, 0 +mov r1, 1 + +# NOTE: Nested delay slot fails to disassemble in Ghidra but is permitted by the assembler (actual results TBD). +add r0,r1,r0 +b.d foo +b.d foo +add r0,r1,r0 ; not executed +foo: sub r0,r1,r0 ; executed twice? +add r0,r1,r0 +j blink + +sub.f 0,r1,r2 +bnz.jd bar +sub r0,r0,r0 +bar: + + +# inst 1 j.d r0 +# inst 2 j.d r1 <-- inst 1 delay slot +# inst 3 mov r1,0 <-- inst 2 delay slot + +# ... + +# r0: inst 10 mov r2,0 +# inst 11 j.d + +# ... + +# r1: inst 20 mov r3, 0 +# inst 21 j.d + +# t=0 t=1 t=2 t=3 +#j.d r0 fetch PC=r0 NOP NOP +#j.d r1 fetch PC=r1 NOP +#mov r2,0 fetch op fetch .. +#mov r3,0 fetch + + diff --git a/Ghidra/Processors/ARC4/build.gradle b/Ghidra/Processors/ARC4/build.gradle new file mode 100644 index 0000000000..2cf8db236d --- /dev/null +++ b/Ghidra/Processors/ARC4/build.gradle @@ -0,0 +1,11 @@ +apply from: "$rootProject.projectDir/gradle/javaProject.gradle" +apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle" +apply from: "$rootProject.projectDir/gradle/processorProject.gradle" +apply plugin: 'eclipse' +eclipse.project.name = 'Processors ARC4' + + +dependencies { + compile project(':Base') +} + diff --git a/Ghidra/Processors/ARC4/build_test.sh b/Ghidra/Processors/ARC4/build_test.sh new file mode 100755 index 0000000000..b449b80086 --- /dev/null +++ b/Ghidra/Processors/ARC4/build_test.sh @@ -0,0 +1,4 @@ +#!/bin/sh +~/other_projects/arc4-toolchain-20100305-x86/usr/local/arc/arc-elf32/bin/as test.s -o test.o +~/other_projects/arc4-toolchain-20100305-x86/usr/local/arc/arc-elf32/bin/ld test.o -o test + diff --git a/Ghidra/Processors/ARC4/certification.manifest b/Ghidra/Processors/ARC4/certification.manifest new file mode 100644 index 0000000000..ab0f15b05a --- /dev/null +++ b/Ghidra/Processors/ARC4/certification.manifest @@ -0,0 +1,32 @@ +##VERSION: 2.0 +Module.manifest||GHIDRA||||END| +build.gradle||GHIDRA||||END| +data/languages/old/ToyV00BE64.lang||GHIDRA||||END| +data/languages/old/ToyV0BE64.trans||GHIDRA||||END| +data/languages/old/ToyV0LE64.lang||GHIDRA||||END| +data/languages/old/ToyV0LE64.trans||GHIDRA||||END| +data/languages/old/v01stuff/toy.cspec||GHIDRA|exclude|||END| +data/languages/old/v01stuff/toy.ldefs_v01||GHIDRA|exclude|||END| +data/languages/old/v01stuff/toy.sinc||GHIDRA|exclude|||END| +data/languages/old/v01stuff/toy64.cspec||GHIDRA|exclude|||END| +data/languages/old/v01stuff/toyInstructions.sinc||GHIDRA|exclude|||END| +data/languages/old/v01stuff/toyPosStack.cspec||GHIDRA|exclude|||END| +data/languages/toy.cspec||GHIDRA||||END| +data/languages/toy.ldefs||GHIDRA||||END| +data/languages/toy.pspec||GHIDRA||reviewed||END| +data/languages/toy.sinc||GHIDRA||||END| +data/languages/toy64.cspec||GHIDRA||||END| +data/languages/toy64_be.slaspec||GHIDRA||reviewed||END| +data/languages/toy64_le.slaspec||GHIDRA||reviewed||END| +data/languages/toyInstructions.sinc||GHIDRA||||END| +data/languages/toyPosStack.cspec||GHIDRA||||END| +data/languages/toy_be.slaspec||GHIDRA||||END| +data/languages/toy_be_posStack.slaspec||GHIDRA||||END| +data/languages/toy_builder.sinc||GHIDRA||||END| +data/languages/toy_builder_be.slaspec||GHIDRA||||END| +data/languages/toy_builder_be_align2.slaspec||GHIDRA||reviewed||END| +data/languages/toy_builder_le.slaspec||GHIDRA||||END| +data/languages/toy_builder_le_align2.slaspec||GHIDRA||reviewed||END| +data/languages/toy_le.slaspec||GHIDRA||||END| +data/languages/toy_wsz_be.slaspec||GHIDRA||reviewed||END| +data/languages/toy_wsz_le.slaspec||GHIDRA||reviewed||END| diff --git a/Ghidra/Processors/ARC4/data/languages/ARC4.cspec b/Ghidra/Processors/ARC4/data/languages/ARC4.cspec new file mode 100644 index 0000000000..f5f57cae62 --- /dev/null +++ b/Ghidra/Processors/ARC4/data/languages/ARC4.cspec @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ghidra/Processors/ARC4/data/languages/ARC4.ldefs b/Ghidra/Processors/ARC4/data/languages/ARC4.ldefs new file mode 100644 index 0000000000..847a326a73 --- /dev/null +++ b/Ghidra/Processors/ARC4/data/languages/ARC4.ldefs @@ -0,0 +1,18 @@ + + + + + + ARC4 32 bit little-endian + + + diff --git a/Ghidra/Processors/ARC4/data/languages/ARC4.pspec b/Ghidra/Processors/ARC4/data/languages/ARC4.pspec new file mode 100644 index 0000000000..c66d58fa38 --- /dev/null +++ b/Ghidra/Processors/ARC4/data/languages/ARC4.pspec @@ -0,0 +1,9 @@ + + + + + + + diff --git a/Ghidra/Processors/ARC4/data/languages/ARC4.sinc b/Ghidra/Processors/ARC4/data/languages/ARC4.sinc new file mode 100644 index 0000000000..c4d773fd87 --- /dev/null +++ b/Ghidra/Processors/ARC4/data/languages/ARC4.sinc @@ -0,0 +1,66 @@ +# Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC +# Authors: Dan Genin and Tommy Johnson + +# Main slaspec must define endianess and alignment + +@ifndef WORDSIZE +@define WORDSIZE "1" +@endif + + +define space ram type=ram_space size=$(SIZE) wordsize=$(WORDSIZE) default; +define space register type=register_space size=2 wordsize=4; + +# shimmflags, limm and shimnoflags act as dummy registers for instructions +# with immediate value in destination register +define register offset=0x1000 size=$(SIZE) [ + + r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 + r15 r16 r17 r18 r19 r20 r21 r22 r23 r24 r25 r26 fp sp + ilink1 ilink2 blink pc + + ext0 ext1 ext2 ext3 ext4 ext5 ext6 ext7 ext8 ext9 ext10 ext11 ext12 ext13 ext14 + ext15 ext16 ext17 ext18 ext19 ext20 ext21 ext22 ext23 ext24 MLO MMID MHI lp_count + shimmflags limm shimmnoflags + +# r32-r59 reserved, lp_count is r60, MLO, MMID and MHI are only valid if the CPU has a 32x32 multiply extension. +]; + +# STATUS REGISTER MAP: (LOW) +# C - CARRY +# Z - ZERO +# N - NEGATIVE +# V - OVERFLOW +# tmp* are fake registers used to pass flags into FLAGS table +define register offset=0x1200 size=1 [ + Z N C V tmpZ tmpN tmpC tmpV +]; + +define register offset=0x1300 size=$(SIZE) [ + status semaphore lp_start lp_end identity debug + aux6 aux7 aux8 aux9 aux10 aux11 aux12 aux13 aux14 aux15 + aux16 aux17 aux18 aux19 aux20 aux21 aux22 aux23 aux24 aux25 + aux26 aux27 aux28 aux29 aux30 aux31 aux32 aux33 aux34 aux35 + aux36 aux37 aux38 aux39 aux40 aux41 aux42 aux43 aux44 aux45 + aux46 aux47 aux48 aux49 aux50 aux51 aux52 aux53 aux54 aux55 + aux56 aux57 aux58 aux59 aux60 aux61 aux62 aux63 +]; + +# Fake register used to pass loop address into LP_COND table +define register offset=0x1400 size=$(SIZE) [ + lp_addr +]; + +define register offset=0x1500 size=8 [ + lp_status +]; + +# NOTE: it appears that only one context register is allowed(?), so +# we are making them longer to accommodate address variables +# needed for computation in the action section of sr instruction +# to support manual loop initialization. + +define context lp_status + lp_in_use = (0,0) +# tmp1_1 = (32,63) + ; diff --git a/Ghidra/Processors/ARC4/data/languages/ARC4Instructions.sinc b/Ghidra/Processors/ARC4/data/languages/ARC4Instructions.sinc new file mode 100644 index 0000000000..b2ddf61384 --- /dev/null +++ b/Ghidra/Processors/ARC4/data/languages/ARC4Instructions.sinc @@ -0,0 +1,791 @@ +# Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC +# Authors: Dan Genin and Tommy Johnson + +define token instr(32) + iI = (27, 31) # opcode + iA = (21, 26) # destination reg + iBL_L = (7,26) signed # destination address divided by 4 + iST_Di= (26, 26) # direct (cache bypass) + iST_0 = (25, 25) + iST_A = (24, 24) # address write-back enable + iST_Z = (22, 23) # size field used by ST + iA_alias = (21, 26) # necessary because iA cannot occur as both parameter and constraint at once + iB = (15, 20) # op 1 address + iB_alias = (15, 20) + iSR_B = (15, 20) + iC = (9, 14) # op 2 address + iC_alias = (9, 14) + iLD0_R = (13, 13) # reserved should be 0 + iLD1_R = (6, 8) + iLD0_Di = (14, 14) # direct (cache bypass) + iLD1_Di = (5, 5) + iLD1_A = (12, 12) # address write-back enable (see ARC Ref. p. 99) + iLD1_Z = (1, 2) + iLD0_Z = (10, 11) # size field used by LD + iLD0_X = (9, 9) # sign extend field + iLD1_X = (0, 0) + iF = (8, 8) # flags set field + iR = (7, 7) # reserved, must be 0 + iN = (5, 6) # jump/call nullify instruction mode + iQ = (0, 4) # condition flags + iD = (0, 8) # short immediate data + iLD0_A = (3,3) # address write-back enable for instruction without short immediate (see ARC Ref. p.100) + iSR_D = (0, 5); # special register index for SR, note that this should + # actually be (0, 8) but this would require making + # the special register file 2^9 long. +define token limm_token(32) + limm32_field = (0,31); + +attach names iQ [ + AL EQ NE PL MI CS CC VS VC GT GE LT LE HI LS PNZ ex0 + ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 exA exB exC exD exE exF + ]; + +attach variables [ iA iB iC ] [ + r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 + r15 r16 r17 r18 r19 r20 r21 r22 r23 r24 r25 r26 fp sp + ilink1 ilink2 blink + ext0 ext1 ext2 ext3 ext4 ext5 ext6 ext7 ext8 ext9 ext10 ext11 ext12 ext13 ext14 + ext15 ext16 ext17 ext18 ext19 ext20 ext21 ext22 ext23 ext24 MLO MMID MHI lp_count + shimmflags limm shimmnoflags +]; + +attach variables [ iSR_D iSR_B ] [ + status semaphore lp_start lp_end identity debug + aux6 aux7 aux8 aux9 aux10 aux11 aux12 aux13 aux14 aux15 + aux16 aux17 aux18 aux19 aux20 aux21 aux22 aux23 aux24 aux25 + aux26 aux27 aux28 aux29 aux30 aux31 + aux32 aux33 aux34 aux35 aux36 aux37 aux38 aux39 aux40 aux41 + aux42 aux43 aux44 aux45 aux46 aux47 aux48 aux49 aux50 aux51 + aux52 aux53 aux54 aux55 aux56 aux57 aux58 aux59 aux60 aux61 + aux62 aux63 +]; + +# Short immediate arguments are sign extended to 32 bits. Ghidra sext() +# requires byte aligned data but short immediate arguments are 9 bits long. +# The work around is to sext(x)=(x<<23)s>>23. The combination of logical +# left shift and signed arithmetic right shift is equivalent to sext on +# the 9 bit short immediate value. +# +# The disassembly action section computes the 32 bit sign-extended operand +# value. The variables in this section are arbitrary precision signed ones +# complement. The expression in square brackets computes the correct signed +# value by extracting the sign bit and effectively implementing +# ? -iD : iD using arithmetic. +# opD: val is iD [ val = ((iD&0x100)>>8)*(iD-512)+(1-((iD&0x100)>>8))*iD; ] { local tmp:4 = ((iD<<23)s>>23); export tmp; } +opD: val is iD [ val = ((iD&0x100)>>8)*(iD-512)+(1-((iD&0x100)>>8))*iD; ] { local tmp:4 = ((iD&0x100)>>8)*(iD-512)+(1-((iD&0x100)>>8))*iD; export tmp; } + +# p.61 of ARC Ref. regs 61-63 reserved for encoding immediate data + +# 61 - Short immediate data indicator setting +# flags +# 62 - Long immediate data indicator +# 63 - Short immediate data indicator not setting +# flags + +opA: iA is iA_alias<61 & iA { export iA; } # normal register operand +opA: "0" is iA_alias=61 & iA { export iA; } # short immediate with flags set +opA: "0" is iA_alias>61 & iA { export iA; } # short immediate without flags set or long immediate flags? +# NOTEL: No long immediate for opA because it is the destination register. Short immediate for opA +# is used for setting flags only. + +opB: iB is iB_alias<61 & iB { export iB; } # normal register operand +opB: opD is iB=61 & opD { local tmp:4 = opD; export tmp; } # short immediate with flags set +opB: opD is iB=63 & opD { local tmp:4 = opD; export tmp; } # short immediate without flags set +opB: limm32_field is iB_alias=62 & iB_alias; limm32_field { export *[const]:$(SIZE) limm32_field; } # long immediate + +# SR instruction with implicit register specification, e.g., +# sr r1, [r2] +# results in decompiler code with a RAM memory write, e.g., +# *(int **)((uVar1 & 0x3f) + 0x1300) = piParm2; +# See discussion on SR for zero-overhead loop instruction below. +opSR_B: iSR_B is iB_alias<61 & iSR_B { export iSR_B; } # normal register operand +opSR_B: iSR_D is iSR_B=61 & iSR_D { export iSR_D; } # short immediate with flags set +opSR_B: iSR_D is iSR_B=63 & iSR_D { export iSR_D; } # short immediate without flags set +opSR_B: limm32_field is iB_alias=62 & iB_alias; limm32_field { export *[const]:$(SIZE) limm32_field; } # long immediate + +opC: iC is iC_alias<61 & iC { export iC; } # normal register operand +opC: opD is iC=61 & opD { local tmp:4 = opD; export tmp; } # short immediate with flags set +opC: opD is iC=63 & opD { local tmp:4 = opD; export tmp; } # short immediate without flags set +opC: limm32_field is iC=62; limm32_field { export *[const]:$(SIZE) limm32_field; } # long immediate + +cc: "" is iQ=0 { export 1:1; } #not displaying anything for always-execute +cc: ".eq" is iQ=1 { export Z; } +cc: ".ne" is iQ=2 { tmp:1 = !Z; export tmp; } +cc: ".pl" is iQ=3 { tmp:1 = !N; export tmp; } +cc: ".mi" is iQ=4 { export N; } +cc: ".cs" is iQ=5 { export C; } +cc: ".cc" is iQ=6 { tmp:1 = !C; export tmp; } +cc: ".vs" is iQ=7 { export V; } +cc: ".vc" is iQ=8 { tmp:1 = !V; export tmp; } +cc: ".gt" is iQ=9 { tmp:1 = (!Z) && (N==V); export tmp; } +cc: ".ge" is iQ=10 { tmp:1 = (N==V); export tmp; } +cc: ".lt" is iQ=11 { tmp:1 = (N!=V); export tmp; } +cc: ".le" is iQ=12 { tmp:1 = Z || (N!=V); export tmp; } +cc: ".hi" is iQ=13 { tmp:1 = C && (!Z); export tmp; } +cc: ".ls" is iQ=14 { tmp:1 = (!C) || Z; export tmp; } +cc: ".pnz" is iQ=15 { tmp:1 = (!Z) && (!N); export tmp; } + +COND: cc is cc & (iQ=0 & iC!=61 & iC!=63 & iB!=61 & iB!=63) { } +COND: cc is cc & (iC!=61 & iC!=63 & iB!=61 & iB!=63) { if (!cc) goto inst_next; } +# Always execute +COND: "" is ((iC > 60 & iC != 62) | (iB > 60 & iB != 62)) { } #(iC=61 | iC=63 | iB=61 | iB=63) { } + +B_COND: cc is cc & (iQ!=0) { if (!cc) goto inst_next; } +# This avoids inserting a conditional branch in the case where +# the jump is in fact unconditional. +B_COND: cc is cc & (iQ=0) { } + +# lp instruction does not use iA, iB, iC or iD fields but only iBL_L and iQ. +# So, LP_COND does not need to check instruction mode (long vs short immediate, register) +# the way COND does. +LP_COND: ".al" is (iQ=0) { } +LP_COND: cc is cc & (iQ!=0) { if (cc) goto ; goto [lp_addr]; } + + +# TODO: Try jumps with short immediate data which is not documented in the specification. +# Doesn't seem to be possible to force assembler to produce a jump with a short immediate +# JADDR: byte_addr is iB_alias<61 & iB { export iB; } # normal register operand +# JADDR: byte_addr is iB=61 & iD { export *[const]:$(SIZE) iD; } # short immediate with flags set +# JADDR: byte_addr is iB=63 & iD { export *[const]:$(SIZE) iD; } # short immediate without flags set +JADDR: byte_addr is iB_alias=62 & iB_alias; limm32_field [ byte_addr = (limm32_field & 0xFFFFFF) <<2; ] { export *[ram]:4 byte_addr; } # long immediate + + +ADDR: reloc is iBL_L [ reloc = inst_next + (4*iBL_L); ] { export *[ram]:4 reloc; } +LP_ADDR: reloc is iBL_L [ reloc = inst_next + (4*iBL_L); ] { export *[const]:$(SIZE) reloc; } +# Computes address of one instruction before the last instruction named the loop instruction +# to restrict loop branching p-code to only the final instruction in the loop. +# This avoids Ghidra complaining about unreachable blocks if end-of-loop testing +# p-code is inserted into every instruction, which is how hardware does it. +PREV_ADDR: reloc is iBL_L [ reloc = inst_next + (4*iBL_L) - 4; ] { export *[const]:$(SIZE) reloc; } + +PREV_opC: res is iC_alias<61 & iC [ res = (iC<<2) - 4; ] { export *[const]:$SIZE res; } # normal register operand +PREV_opC: res is iC=61 & iD [ res = (iD<<2) - 4; ] { export *[const]:$(SIZE) res; } # short immediate with flags set +PREV_opC: res is iC=63 & iD [ res = (iD<<2) - 4; ] { export *[const]:$(SIZE) res; } # short immediate without flags set +PREV_opC: res is iC=62; limm32_field [ res = (limm32_field<<2) - 4; ]{ export *[const]:$(SIZE) res; } # long immediate + +dd: ".nd" is iN=0 { } # Only execute next instruction when not jumping (Default) +dd: ".d" is iN=1 { delayslot(1); } # Always execute next instruction +dd: ".jd" is (iN=2)&cc { if (!cc) goto ; delayslot(1); } # Only execute next instruction when jumping (see p.88) + +# NOTE: This is used only for jl with long immediate address, which occupies +# the delay slot. According to the ARC4 spec .jd nullify mode must be +# used (p. 97). +jl_dd: ".jd" is iN=2 { } + +# p.36 ARC4 CPU manual +# Adds end-of-loop p-code test to the last instruction in the loop, +# which is the only instruction for which lp_in_use is 1. +LOOP: is (lp_in_use=0) {} +LOOP: is (lp_in_use=1) +{ + # if next instruction is not the end of the loop do nothing + if (inst_next!=lp_end) goto ; + # if next instruction is the end of the loop + # decrement lp_count + lp_count = lp_count - 1; + # if lp_count is 0 do nothing + if (lp_count==0) goto ; + # otherwise return to the start of the loop + goto [lp_start]; + +} + +macro resultflags(result) { + tmpN = result s< 0; + tmpZ = result == 0; +} + +macro addflags(op1,op2) { + tmpC = carry(op1,op2); + tmpV = scarry(op1,op2); +} + +# NOTE: unlike x86, carry flag is SET if there is NO borrow +macro subflags(op1,op2) { + tmpC = op2 <= op1; + tmpV = sborrow(op1,op2); +} + +FLAGS: ".f" is iF=1 & (iC!=61 & iC!=63 & iB!=61 & iB!=63) { C = tmpC; Z = tmpZ; N = tmpN; V = tmpV; } +FLAGS: "" is iF=0 & (iC!=61 & iC!=63 & iB!=61 & iB!=63) { } +FLAGS: ".f" is (iC<63 & iB<63) { C = tmpC; Z = tmpZ; N = tmpN; V = tmpV; } +FLAGS: "" is (iC=63 | iB=63) { } + +FLAGSNZ: ".f" is iF=1 & (iC!=opC61 & iC!=63 & iB!=61 & iB!=63) { N = tmpN; Z = tmpZ; } +FLAGSNZ: "" is iF=0 & (iC!=61 & iC!=63 & iB!=61 & iB!=63) { } +FLAGSNZ: ".f" is (iC<63 & iB<63) { N = tmpN; Z = tmpZ; } +FLAGSNZ: "" is (iC=63 | iB=63) { } + + +ADDRESS_WRITEBACK_LD0: ".a" is iLD0_A=1 ... & opB & opC { opB = opB + opC; export opB; } +ADDRESS_WRITEBACK_LD0: "" is iLD0_A=0 ... & opB & opC { local tmp = opB + opC; export tmp; } +ADDRESS_WRITEBACK_LD1: ".a" is iLD1_A=1 ... & opB & opD ... { opB = opB + opD; export opB; } +ADDRESS_WRITEBACK_LD1: "" is iLD1_A=0 ... & opB & opD ... { local tmp = opB + opD; export tmp; } +ADDRESS_WRITEBACK_ST0: ".a" is iST_A=1 ... & opB & opD ... { opB = opB + opD; export opB; } +ADDRESS_WRITEBACK_ST0: "" is iST_A=0 ... & opB & opD ... { local tmp = opB + opD; export tmp; } + +# p. 93 of ARC Ref +# TODO: implement cache bypass and sign extend +# NOTE: ld instruction family does not set status flags see p.100 +# LD instructions below use + +:ld^ADDRESS_WRITEBACK_LD0 opA, "["^opB, opC^"]" is LOOP & ADDRESS_WRITEBACK_LD0 & (iI=0x0 & iLD1_Z=0x0 & iLD1_R=0x0) ... & opA ... & opB & opC ... +{ + opA = *:4 ADDRESS_WRITEBACK_LD0; +} + +:ldb^ADDRESS_WRITEBACK_LD0 opA, "["^opB, opC^"]" is LOOP & ADDRESS_WRITEBACK_LD0 & (iI=0x0 & iLD1_Z=0x1 & iLD1_R=0x0) ... & opA ... & opB & opC ... +{ + local tmp = *:1 ADDRESS_WRITEBACK_LD0; + opA = zext(tmp); +} + +:ldw^ADDRESS_WRITEBACK_LD0 opA, "["^opB, opC^"]" is LOOP & ADDRESS_WRITEBACK_LD0 & (iI=0x0 & iLD1_Z=0x2 & iLD1_R=0x0) ... & opA ... & opB & opC ... +{ + local tmp = *:2 ADDRESS_WRITEBACK_LD0; + opA = zext(tmp); +} +# LD instructions below use short immediate addressing, e.g., ld r1,[r2,4] +:ld^ADDRESS_WRITEBACK_LD1 opA, "["^opB, opD^"]" is LOOP & ADDRESS_WRITEBACK_LD1 & (iI=0x1 & iLD0_Z=0x0 & iLD0_R=0) ... & opA ... & opB & opD ... +{ + opA = *:4 ADDRESS_WRITEBACK_LD1; +} + +:ldb^ADDRESS_WRITEBACK_LD1 opA, "["^opB, opD^"]" is LOOP & ADDRESS_WRITEBACK_LD1 & (iI=0x1 & iLD0_Z=0x1 & iLD0_R=0) ... & opA ... & opB & opD ... +{ + local tmp = *:1 ADDRESS_WRITEBACK_LD1; + opA = zext(tmp); +} + +:ldw^ADDRESS_WRITEBACK_LD1 opA, "["^opB, opD^"]" is LOOP & ADDRESS_WRITEBACK_LD1 & (iI=0x1 & iLD0_Z=0x2 & iLD0_R=0) ... & opA ... & opB & opD ... +{ + local tmp = *:2 ADDRESS_WRITEBACK_LD1; + opA = zext(tmp); +} + +:lr opA, "["^opB^"]" is LOOP & (iI=0x1 & iC=0x10) ... & opA ... & opB +{ + local addr = &:2 status + opB:2; + reg_val = *[register] addr; + opA = reg_val; +} + +:lr_but_reserved_bits_not_zero opA, "["^opB^"]" is LOOP & (iI=0x1 & iLD0_R=0x1 & iC!=0x10) ... & opA ... & opB & iD ... +{ + local addr = &:2 status + opB:2; + reg_val = *[register] addr; + opA = reg_val; +} + + +# lp_end = 3 +# NOTE: Zero-overhead loop setup with explicit stores to auxiliary registers cannot +# be made to work with existing implementation. The reason is that it requires +# constants propagation for the disassembler to be able to insert p-code +# jump at the correct instruction. The address of the loop end instruction +# must be computed from the corresponding label (using left shift?), which +# means it cannot be explicitly computed at compile time by assembler and +# therefore cannot be an immediate. So loop_end setup requires a register +# store, e.g., sr r1, [lp_end], where r1 holds the computed address of the +# end of the loop. +# The lp instruction circumvents this issue by using pc-relative addressing, +# so that the loop end instruction address can be computed by the disassembler. +# lp instruction therefore behaves like a branch instruction. +# +# Unrelated, the gcc ARC4 assembler appears to OR short immediates in auxiliary +# register store instructions, making it impossible to use code like +# sr 0x8e, [lp_end], which assembles into sr 0x8f, [0x8f]. It should have been +# assembled into an instruction using a short immediate and a long immediate, +# instead the two immediates are ORed into the short immediate field. Brilliant! +# +# NOTE: opC is not allowed in square brackets so we need to make +# equivalents of ADDR and PREV_ADDR to get the right values in to +# square brackets. +:sr opC, "["^opB^"]" is PREV_opC & LOOP & (iI=0x2 & iA=0x10 & (iB=61 | iB=63) & iD=0x3) ... & opC ... & opB ... & iD ... +[ + # Set lp_in_use context variable for the last + # instrution at the end of the loop so that + # the end-of-loop check is performed only + # in that instruction. + # NOTE: if lp_end is overwritten while the + # loop is running there will be sadness:'( + # lp_in_use=1; + # globalset(inst_next, lp_in_use); + # lp_in_use=0; + # This still results in unreachable branches because register value + # is not known at decompile time and lp_in_use ends up being set + # everywhere (see discussion on SR for zero-overhead loop). + lp_in_use=1; + globalset(PREV_opC, lp_in_use); + lp_in_use=0; + globalset(opC, lp_in_use); +] +{ + lp_end = opC<<2; +} + +:sr opC, "["^opB^"]" is LOOP & (iI=0x2 & iA=0x10 & iD!=0x3) ... & opC ... & opB ... & iD ... +{ + *[register] (&:2 status + opB:2) = opC; +} + +:st^ADDRESS_WRITEBACK_ST0 opC, "["^opB, opD^"]" is LOOP & ADDRESS_WRITEBACK_ST0 & (iI=0x2 & iST_Z=0x0 & iST_0=0) ... & opB ... & opC & opD ... +{ + *:4 ADDRESS_WRITEBACK_ST0 = opC:4; +} + +:stb^ADDRESS_WRITEBACK_ST0 opC, "["^opB, opD^"]" is LOOP & ADDRESS_WRITEBACK_ST0 & (iI=0x2 & iST_Z=0x1 & iST_0=0)... & opB ... & opC & opD ... +{ + *:1 ADDRESS_WRITEBACK_ST0 = opC:1; +} + +:stw^ADDRESS_WRITEBACK_ST0 opC, "["^opB, opD^"]" is LOOP & ADDRESS_WRITEBACK_ST0 & (iI=0x2 & iST_Z=0x2 & iST_0=0) ... & opB ... & opC & opD ... +{ + *:2 ADDRESS_WRITEBACK_ST0 = opC:2; +} + +:ext_unknown_instruction_3^COND^FLAGSNZ opA, opB is LOOP & COND ... & FLAGSNZ ... & (iI=0x3&iC=0x3f) ... & opA ... & opB ... +{ + build COND; +} + +# TODO: implement p-code +:norm^COND^FLAGSNZ opA, opB is LOOP & COND ... & FLAGSNZ ... & (iI=0x3&iC=10) ... & opA ... & opB ... +{ + build COND; +} + +# TODO: implement p-code +:swap^COND^FLAGSNZ opA, opB is LOOP & COND ... & FLAGSNZ ... & (iI=0x3&iC=9) ... & opA ... & opB ... +{ + build COND; +} + +:extw^COND^FLAGSNZ opA, opB is LOOP & COND ... & FLAGSNZ ... & (iI=0x3&iC=8) ... & opA ... & opB ... +{ + build COND; + opA = zext(opB:2); + resultflags(opA); + build FLAGSNZ; +} + +:extb^COND^FLAGSNZ opA, opB is LOOP & COND ... & FLAGSNZ ... & (iI=0x3&iC=7) ... & opA ... & opB ... +{ + build COND; + opA = zext(opB:1); + resultflags(opA); + build FLAGSNZ; +} + +:sexw^COND^FLAGSNZ opA, opB is LOOP & COND ... & FLAGSNZ ... & (iI=0x3&iC=6) ... & opA ... & opB ... +{ + build COND; + opA = sext(opB:2); + resultflags(opA); + build FLAGSNZ; +} + +:sexb^COND^FLAGSNZ opA, opB is LOOP & COND ... & FLAGSNZ ... & (iI=0x3&iC=5) ... & opA ... & opB ... +{ + build COND; + opA = sext(opB:1); + resultflags(opA); + build FLAGSNZ; +} + +:rrc^COND^FLAGS opA, opB is LOOP & COND ... & FLAGS ... & (iI=0x3&iC=4) ... & opA ... & opB ... +{ + build COND; + tmpC = opB[0,1]; + tmpV = V; + opA = (opB>>1)|(zext(C)<<31); + resultflags(opA); + build FLAGS; +} + +:ror^COND^FLAGSNZ opA, opB is LOOP & COND ... & FLAGSNZ ... & (iI=0x3&iC=3) ... & opA ... & opB ... +{ + build COND; + tmpC = opB[0,1]; + tmpV = V; + opA = (opB>>1)|(zext(tmpC)<<31); + resultflags(opA); + build FLAGSNZ; +} + +:lsr^COND^FLAGSNZ opA, opB is LOOP & COND ... & FLAGSNZ ... & (iI=0x3&iC=2) ... & opA ... & opB ... +{ + build COND; + tmpC = opB[0,1]; + tmpV = V; + opA = opB>>1; + resultflags(opA); + build FLAGSNZ; +} + +:asr^COND^FLAGS opA, opB is LOOP & COND ... & FLAGS ... & (iI=0x3&iC=1) ... & opA ... & opB ... +{ + build COND; + tmpC = opB[0,1]; + tmpV = V; + opA = (opB>>1)|(opB&0x80000000); + resultflags(opA); + build FLAGS; +} + +# NOTE: Effect of setting interrupt flag bits E1 (1), E2 (2) and the halt bit H (0) is not implemented. +# NOTE: Documentation specifies that the flag bit (8) must be cleared or the flag instruction will +# not set the flags. +:flag^COND opB is LOOP & COND ... & (iI=0x3&iA=0x3D&iC=0) ... & opA ... & opB ... +{ + build COND; + Z = opB[6,1]; + N = opB[5,1]; + C = opB[4,1]; + V = opB[3,1]; + # E2 = opB[2,1]; + # E1 = opB[1,1]; + # H = opB[0,1]; +} + +:flag_but_A_field_is_wrong^COND opB is LOOP & COND ... & (iI=0x3&iA!=0x3D&iC=0) ... & opA ... & opB ... +{ + build COND; + Z = opB[6,1]; + N = opB[5,1]; + C = opB[4,1]; + V = opB[3,1]; + # E2 = opB[2,1]; + # E1 = opB[1,1]; + # H = opB[0,1]; +} + +:b^B_COND^dd ADDR is LOOP & (iI=0x4) & B_COND & dd & ADDR +{ + build B_COND; + build ADDR; + goto ADDR; +} + +:bl^B_COND^dd ADDR is LOOP & (iI=0x5) & B_COND & dd & ADDR +{ + build B_COND; + build ADDR; + blink = inst_next; + call ADDR; +} + +:lp^LP_COND^dd LP_ADDR PREV_ADDR is PREV_ADDR & LOOP & (iI=0x6) & LP_COND & dd & LP_ADDR +[ + # Set lp_in_use context variable for the last + # instrution at the end of the loop so that + # the end-of-loop check is performed only + # in that instruction. + # NOTE: if lp_end is overwritten while the + # loop is running there will be sadness:'( + # NOTE: Order of disassembly matters. If the last + # instruction in the loop is disassembled before + # lp instruction that sets up the loop, the + # lp_in_use context register will not be set + # when lp is finally disassembled, and the loop + # will magically disappear (poof). + lp_in_use=1; + globalset(PREV_ADDR, lp_in_use); + lp_in_use=0; + globalset(LP_ADDR, lp_in_use); +] +{ + build LP_ADDR; + lp_addr = LP_ADDR; + build LP_COND; + lp_start = inst_next; + lp_end = LP_ADDR; +} + +# Special case for j blink +:j^COND^dd^FLAGS opB is LOOP & (COND & dd & FLAGS & iI=0x7 & iA=0 & iB=0x1F & iC=0) ... & opB +{ + build COND; + tmpZ = opB[31,1]; + tmpN = opB[30,1]; + tmpC = opB[29,1]; + tmpV = opB[28,1]; + build FLAGS; + return [blink]; +} + +:j^COND^dd^FLAGS JADDR is LOOP & COND ... & FLAGS ... & dd ... & (iI=0x7 & iA=0 & iB=62 & iC=0) ... & opB & JADDR +{ + build COND; + tmpZ = opB[31,1]; + tmpN = opB[30,1]; + tmpC = opB[29,1]; + tmpV = opB[28,1]; + build FLAGS; + goto JADDR; +} + +:j^COND^dd^FLAGS opB is LOOP & COND ... & FLAGS ... & dd ... & (iI=0x7 & iA=0 & iB<61 & iB!=0x1F & iC=0) ... & opB +{ + build COND; + local addr = (opB&0x0FFFFFF)<<2; + tmpZ = opB[31,1]; + tmpN = opB[30,1]; + tmpC = opB[29,1]; + tmpV = opB[28,1]; + build FLAGS; + goto [addr]; +} + +# iB==62 => long immediate +:jl^COND^jl_dd^FLAGS JADDR is LOOP & COND ... & FLAGS ... & jl_dd ... & (iI=0x7 & iA=0 & iB=62 & iC=1) ... & opB & JADDR +{ + build COND; + tmpZ = opB[31,1]; + tmpN = opB[30,1]; + tmpC = opB[29,1]; + tmpV = opB[28,1]; + build FLAGS; + blink = inst_next; + call JADDR; +} + +:jl^COND^dd^FLAGS opB is LOOP & COND ... & FLAGS ... & dd ... & (iI=0x7 & iA=0 & iB<61 & iC=1) ... & opB +{ + build COND; + local addr = (opB&0x0FFFFFF)<<2; + tmpZ = opB[31,1]; + tmpN = opB[30,1]; + tmpC = opB[29,1]; + tmpV = opB[28,1]; + build FLAGS; + blink = inst_next; + call [addr]; +} + +:add^COND^FLAGS opA, opB, opC is LOOP & COND ... & FLAGS ... & iI=0x8 ... & opA ... & opB & opC +{ + build COND; + opA = opB + opC; + local result = opA; + resultflags(result); + addflags(opB, opC); + # logicflags(); + build FLAGS; + build LOOP; +} + +:adc^COND^FLAGS opA, opB, opC is LOOP & COND ... & FLAGS ... & iI=0x9 ... & opA ... & opB & opC +{ + build COND; + opA = opB + opC + zext(C); + local result = opA; + resultflags(result); + addflags(opB, opC); + build FLAGS; +} + +:sub^COND^FLAGS opA, opB, opC is LOOP & COND ... & FLAGS ... & iI=0xA ... & opA ... & opB & opC +{ + build COND; + opA = opB - opC; + local result = opA; + resultflags(result); + subflags(opB, opC); + build FLAGS; +} + +:sbc^COND^FLAGS opA, opB, opC is LOOP & COND ... & FLAGS ... & iI=0xB ... & opA ... & opB & opC +{ + build COND; + opA = opB - opC - zext(C); + local result = opA; + resultflags(result); + subflags(opB, opC); + build FLAGS; +} + +:and^COND^FLAGSNZ opA, opB, opC is LOOP & COND ... & FLAGSNZ ... & iI=0xC ... & opA ... & opB & opC +{ + build COND; + opA = opB & opC; + local result = opA; + resultflags(result); + build FLAGSNZ; +} + +# with mov : iI = 0xC +# and reg, shimm, shimm +:mov^COND^FLAGSNZ opA, opB is LOOP & COND ... & FLAGSNZ ... & (iI=0xC & (iB=61 | iB=63) & (iC=61 | iC=63)) ... & opA ... & opB & opC +{ + build COND; + opA = opB; # & opC; + local result = opA; + resultflags(result); + build FLAGSNZ; +} + +# and reg, limm, limm +:mov^COND^FLAGSNZ opA, opB is LOOP & COND ... & FLAGSNZ ... & (iI=0xC & iB=62 & iC=62) ... & opA ... & opB & opC +{ + build COND; + opA = opB; # & opC; + local result = opA; + resultflags(result); + build FLAGSNZ; +} + +# and dst_reg, src_reg, src_reg +:mov^COND^FLAGSNZ opA, opB is LOOP & COND ... & FLAGSNZ ... & (iI=0xC & iB=iC & iB<61 & iC<61) ... & opA ... & opB& opC +{ + build COND; + opA = opB; # & opC; + local result = opA; + resultflags(result); + build FLAGSNZ; +} + +# and shimm, op1, op1 +:tst^COND^FLAGSNZ opB is LOOP & COND ... & FLAGSNZ ... & (iI=0xC & iA=63 & iB=iC & iB<61 & iC<61) ... & opA ... & opB & opC +{ + build COND; + opA = opB & opC; + local result = opA; + resultflags(result); + build FLAGSNZ; +} + +:or^COND^FLAGSNZ opA, opB, opC is LOOP & COND ... & FLAGSNZ ... & iI=0xD ... & opA ... & opB & opC +{ + build COND; + opA = opB | opC; + local result = opA; + resultflags(result); + build FLAGSNZ; +} + +:bic^COND^FLAGSNZ opA, opB, opC is LOOP & COND ... & FLAGSNZ ... & iI=0xE ... & opA ... & opB & opC +{ + build COND; + opA = opB & (~opC); + local result = opA; + resultflags(result); + build FLAGSNZ; +} + +:xor^COND^FLAGSNZ opA, opB, opC is LOOP & COND ... & FLAGSNZ ... & iI=0xF ... & opA ... & opB & opC +{ + build COND; + opA = opB ^ opC; + local result = opA; + resultflags(result); + build FLAGSNZ; +} + +# # ROR p.119 +# :ror^COND^FLAGS opA, opB is LOOP & COND ... & FLAGS ... & (iI=0x3&iC=3) ... & opA ... & opB +# { +# build COND; +# local tmp = (opB & 0x1); +# tmpC = tmp:1; +# opA = (opB >> 1) | (tmp << 31); +# local result = opA; +# resultflags(result); +# tmpV = V; +# build FLAGS; +# } + +# ROR multiple p.120 +:rorm^COND^FLAGS opA, opB, opC is LOOP & COND ... & FLAGS ... & iI=0x13 ... & opA ... & opB & opC +{ + build COND; + opA = (opB >> opC) | (opB << (32-opC)); + local result = opA; + resultflags(result); + tmpV = V; + tmpC = C; + build FLAGS; +} + +# ASL multiple p.84 +:asl^COND^FLAGSNZ opA, opB, opC is LOOP & COND ... & FLAGSNZ ... & iI=0x10 ... & opA ... & opB & opC +{ + build COND; + opA = opB << opC; + # TODO: Result is redundant. Pass opA directly to resultflags throughout. + local result = opA; + resultflags(result); + build FLAGSNZ; +} + + +# ASL p.8 3 +# NOTE: The specification has an _error_ where it claims that iI=0xC if there is no short immediate argument. +# This conflicts with the definition of ADD, which has the same op code and is also contradicted +# by the assembler. +:asl^COND^FLAGS opA, opB is LOOP & COND ... & FLAGS ... & iI=0x8 ... & iB=iC ... & opA ... & opB +{ + build COND; + local tmp = (opB & 0x80000000) >> 31; + tmpC = tmp:1; + opA = opB << 1; + local result = opA; + resultflags(result); + tmpV = (tmpN != N); + build FLAGS; +} + +:lsr^COND^FLAGS opA, opB, opC is LOOP & COND ... & FLAGS ... & iI=0x11 ... & opA ... & opB & opC +{ + build COND; + opA = opB >> opC; + resultflags(opA); + build FLAGS; +} + +:asr^COND^FLAGS opA, opB, opC is LOOP & COND ... & FLAGS ... & iI=0x12 ... & opA ... & opB & opC +{ + build COND; + local tmp = ((opB & 0x80000000) >> 31); + if (tmp[0,1]) goto ; + tmp = 0xFFFFFFFF << (32 - opC); + + opA = (opB >> opC) | tmp; + resultflags(opA); + build FLAGS; +} + +:nop^COND^FLAGS is LOOP & COND & FLAGS & iI=0xF & iA=63 & iB=63 & iC=63 & iD=0x1FF +{ +} + +# TODO: implement signed mul64 +# Idea: convert to unsigned, use unsigned multiplication on 31 bit unsigned operands, +# compute the correct sign for the product by xor-ing the sign bits of the operands, +# if it's negative convert the result to two's complement. +:mul64^COND opB, opC is LOOP & COND ... & iI=0x14 ... & iA=0x3F ... & opB & opC +{ + build COND; + local tmp_b:12 = 0; + tmp_b[0,31] = opB; + local tmp_c:12 = 0; + tmp_c[0,31] = opC; + local res:12 = tmp_b * tmp_c; + MLO = res[0,31]; + MMID = res[32,31]; + MHI = res[64,31]; +} + +:mulu64^COND opB, opC is LOOP & COND ... & iI=0x15 ... & iA=0x3F ... & opB & opC +{ + build COND; + local tmp_b:12 = 0; + tmp_b[0,31] = opB; + local tmp_c:12 = 0; + tmp_c[0,31] = opC; + local res:12 = tmp_b * tmp_c; + MLO = res[0,31]; + MMID = res[32,31]; + MHI = res[64,31]; +} \ No newline at end of file diff --git a/Ghidra/Processors/ARC4/data/languages/ARC4_le.slaspec b/Ghidra/Processors/ARC4/data/languages/ARC4_le.slaspec new file mode 100644 index 0000000000..fe1a0efbcf --- /dev/null +++ b/Ghidra/Processors/ARC4/data/languages/ARC4_le.slaspec @@ -0,0 +1,9 @@ +# Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC +# Authors: Dan Genin and Tommy Johnson + +define endian=little; + +@define SIZE "4" + +@include "ARC4.sinc" +@include "ARC4Instructions.sinc" diff --git a/Ghidra/Processors/ARC4/data/patterns/ARC4_LE_patterns.xml b/Ghidra/Processors/ARC4/data/patterns/ARC4_LE_patterns.xml new file mode 100644 index 0000000000..ff29338284 --- /dev/null +++ b/Ghidra/Processors/ARC4/data/patterns/ARC4_LE_patterns.xml @@ -0,0 +1,11 @@ + + + + ......00 0x10 0x6e 0x0b + + + 0x04 0x3e 0x0e 0x10 + + + + diff --git a/Ghidra/Processors/ARC4/data/patterns/ARC4_patterns.xml b/Ghidra/Processors/ARC4/data/patterns/ARC4_patterns.xml new file mode 100644 index 0000000000..ff29338284 --- /dev/null +++ b/Ghidra/Processors/ARC4/data/patterns/ARC4_patterns.xml @@ -0,0 +1,11 @@ + + + + ......00 0x10 0x6e 0x0b + + + 0x04 0x3e 0x0e 0x10 + + + + diff --git a/Ghidra/Processors/ARC4/data/patterns/patternconstraints.xml b/Ghidra/Processors/ARC4/data/patterns/patternconstraints.xml new file mode 100644 index 0000000000..71fcff2951 --- /dev/null +++ b/Ghidra/Processors/ARC4/data/patterns/patternconstraints.xml @@ -0,0 +1,5 @@ + + + ARC4_LE_patterns.xml + + diff --git a/Ghidra/Processors/ARC4/data/sleighArgs.txt b/Ghidra/Processors/ARC4/data/sleighArgs.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Ghidra/Processors/ARC4/ext.s b/Ghidra/Processors/ARC4/ext.s new file mode 100644 index 0000000000..14974b91f4 --- /dev/null +++ b/Ghidra/Processors/ARC4/ext.s @@ -0,0 +1,36 @@ +; Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC +; Authors: Dan Genin and Tommy Johnson + + extw r0,r0 + extw r1,r0 + extw r0,r1 + extw r1,r1 + extb r0,r0 + extb r1,r0 + extb r0,r1 + extb r1,r1 + nop + nop + sexw r0,r0 + sexb r0,r0 + flag r0 +.WORD 0x18000000|(0<<9) ; flag +.WORD 0x18000000|(1<<9) ; asr +.WORD 0x18000000|(2<<9) ; lsr +.WORD 0x18000000|(3<<9) ; ror +.WORD 0x18000000|(4<<9) ; rrc +.WORD 0x18000000|(5<<9) ; sexb +.WORD 0x18000000|(6<<9) ; sexw +.WORD 0x18000000|(7<<9) ; extb +.WORD 0x18000000|(8<<9) ; extw +;.WORD 0x18000000|(9<<9) ; illegal instruction +;.WORD 0x18000000|(10<<9) ; illegal instruction +;.WORD 0x18000000|(11<<9) ; illegal instruction +;.WORD 0x18000000|(12<<9) ; illegal instruction +;.WORD 0x18000000|(13<<9) ; illegal instruction +;.WORD 0x18000000|(14<<9) ; illegal instruction +;.WORD 0x18000000|(15<<9) ; illegal instruction +;.WORD 0x18000000|(16<<9) ; illegal instruction +;.WORD 0x18000000|(17<<9) ; illegal instruction +;.WORD 0x18000000|(18<<9) ; illegal instruction +;.WORD 0x18000000|(19<<9) ; illegal instruction diff --git a/Ghidra/Processors/ARC4/jump.s b/Ghidra/Processors/ARC4/jump.s new file mode 100644 index 0000000000..3e671a6ede --- /dev/null +++ b/Ghidra/Processors/ARC4/jump.s @@ -0,0 +1,13 @@ +; Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC +; Authors: Dan Genin and Tommy Johnson + + jl.jd 0xfffffff + jl blink + jl 42 + jl jl_test +.WORD 0x3963120f ; jlpnz [r6] +.WORD 0x381f8001 ; j 1 +jl_test: + nop + nop + nop \ No newline at end of file diff --git a/Ghidra/Processors/ARC4/ld.s b/Ghidra/Processors/ARC4/ld.s new file mode 100644 index 0000000000..2b78f7f9b6 --- /dev/null +++ b/Ghidra/Processors/ARC4/ld.s @@ -0,0 +1,23 @@ +; Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC +; Authors: Dan Genin and Tommy Johnson + + ld r0, [r1, 1] + ;; ld r0, [5,4] to (sic) many shimms in load + ld r0, [5,5] + ld r0, [5] + ld r0, [r3] + ld r0, [r3, r4] + ld r0, [r3, 0x0fffffff] + ld r0, [0x0fffffff] + ;; ld r0, [0x0fffffff, 0x12] ld operand error + ;; ld.a r0, [5] write-back not permitted + ld.a r0, [r1,5] + ld.a r0, [r1,-1] + ld.a r0, [r1,r2] + ld.x r0, [r1] + ldw.x r0, [r1] + ldb.x r0, [r1] + .WORD 0x081f000e ; ld r0, [0x1234, 0xe] + .WORD 0x1234 ; supported by objdump but not as + .WORD 0x0f126339 + diff --git a/Ghidra/Processors/ARC4/logic_ops.s b/Ghidra/Processors/ARC4/logic_ops.s new file mode 100644 index 0000000000..e1f23fafd9 --- /dev/null +++ b/Ghidra/Processors/ARC4/logic_ops.s @@ -0,0 +1,27 @@ +; Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC +; Authors: Dan Genin and Tommy Johnson + + asl r0,r1 + asl r0,42 + asl r0,0xffffff + nop + asl 0,r0 + asl 0,42 + asl 0,0xfffffff + nop + and r0,r1,r2 + and r0,r1,r1 + and r0,r1,42 + and r0,r1,0xffffffff + and r0,1,4 + and r0,0xffffffff,r1 + and r0,1,r1 + nop + and 0,r1,r2 + and 0,r1,r1 + and 0,r1,42 + and 0,r1,0xffffffff + and 0,1,4 + and 0,0xffffffff,r1 + and 0,1,r1 + diff --git a/Ghidra/Processors/ARC4/loop.s b/Ghidra/Processors/ARC4/loop.s new file mode 100644 index 0000000000..fe26df2379 --- /dev/null +++ b/Ghidra/Processors/ARC4/loop.s @@ -0,0 +1,42 @@ +; mov r2,r0 +; mov lp_count, 4 +; lp loop_end +;loop_in: +; ld r0,[r1] +; add r2,r2,r0 +; add r2,r2,r0 +;loop_end: +; mov r0,r2 +; j blink + + nop + nop + nop + mov lp_count, 10 + mov r2,0 + lp loop1_end +loop1_in: + ld r0,[r1] + add r2,r2,r0 + add r2,r2,r0 + nop + nop + nop + nop +loop1_end: + mov r0,r2 + j blink + + mov r2, 0 + mov lp_count, 5 + mov r3, loop2_in>>2 + add r4, r3, 1 + sr r3, [lp_start] + sr r4, [lp_end] + ;; sr 0x8e, [lp_end] + nop + nop +loop2_in: + add r2,r2,r0 + mov r0, r2 + j blink diff --git a/Ghidra/Processors/ARC4/objdump.sh b/Ghidra/Processors/ARC4/objdump.sh new file mode 100755 index 0000000000..c56a864771 --- /dev/null +++ b/Ghidra/Processors/ARC4/objdump.sh @@ -0,0 +1,2 @@ +#!/bin/sh +~/other_projects/KodakP720/usr/local/arc/bin/arc-elf32-objdump -D $1 diff --git a/Ghidra/Processors/ARC4/ret.s b/Ghidra/Processors/ARC4/ret.s new file mode 100644 index 0000000000..c1f3441ce6 --- /dev/null +++ b/Ghidra/Processors/ARC4/ret.s @@ -0,0 +1,14 @@ +; Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC +; Authors: Dan Genin and Tommy Johnson + + add r0, r1, r2 + j blink + nop + sub r0, r1, 10 + j 0xFFFF + j blink + nop + add r1, r1, 5 + sub r0, r1, 10 + jz 0x10120 + j blink diff --git a/Ghidra/Processors/ARC4/sr.s b/Ghidra/Processors/ARC4/sr.s new file mode 100644 index 0000000000..7e47f89eb2 --- /dev/null +++ b/Ghidra/Processors/ARC4/sr.s @@ -0,0 +1,18 @@ +; Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC +; Authors: Dan Genin and Tommy Johnson + + mov r2, 4 + sr r1,[r2] + sr r1,[42] + sr r1,[420000] + sr 430000,[43] + sr 44,[440000] + sr 45,[r2] + sr 450000,[r2] + sr r2, [lp_end] + sr r2, [4] + sr r2, [5] + sr r2, [7] + + lr r0, [r2] + j.nd blink diff --git a/Ghidra/Processors/ARC4/st.s b/Ghidra/Processors/ARC4/st.s new file mode 100644 index 0000000000..7211e16761 --- /dev/null +++ b/Ghidra/Processors/ARC4/st.s @@ -0,0 +1,13 @@ +; Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC +; Authors: Dan Genin and Tommy Johnson + + st r0, [r1, 1] + st r0, [5,5] + st r0, [5] + st r0, [r3] + st 3, [0x0fffffff] + st 3, [3] + st r0, [0x0fffffff] + st.a r0, [r1,5] + st.a r0, [r1,-1] + diff --git a/Ghidra/Processors/ARC4/sub.s b/Ghidra/Processors/ARC4/sub.s new file mode 100644 index 0000000000..a328bccd5a --- /dev/null +++ b/Ghidra/Processors/ARC4/sub.s @@ -0,0 +1,44 @@ +; Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC +; Authors: Dan Genin and Tommy Johnson + + sub r1,r2,32 + sub r3,r4,32 + sub r5,r6,32 + sub r1,ilink1,32 + sub r1,blink,32 + sub r1,sp,32 + sub fp,sp,sp + sub sp,r1,sp + sub r1,r1,32 + sub r1,r1,32 + sub r1,r1,0x1FFFFFFF + sub 0x1FFFFFFF,r1,r2 + + SUB r1,r2,r3 + SUB.NZ r1,r2,r3 + SUB.F r1,r2,r3 + SUB.NZ.F r1,r2,r3 + SUB r1,r2,34 + SUB.F r1,r2,34 + SUB r1,34,r2 + SUB r1,255,255 + SUB.F 0,r1,r2 + SUB.F 0,r1,34 + SUB.F 0,34,r1 + SUB 0,0,0 + SUB r3,1,2 + SUB.F r3,1,2 + + ;; register register + ;; conditional + ;; setting flags + ;;conditional and conditionally set flags + ;;register immediate + ;;immediate register + ;;immediate immediate (shimms MUST match) + ;;test + ;;test with immediate + ;;test with immediate + ;;null instruction, NOP + + diff --git a/Ghidra/Processors/ARC4/test b/Ghidra/Processors/ARC4/test new file mode 100755 index 0000000000000000000000000000000000000000..6ceb4a2a724eaaa8ea9df41f997ab28ad52b26d0 GIT binary patch literal 2442 zcmd^A&ue2<6#i~rl0J(xnFm6^#d|G+5^ZK2y2zl=Cqd)F#e*)gaPg9~G1ZxALYsw3 zNis1VhFOetFSIZlm#)N}ga3doXCvlc7;q)wKEHEcZW9Mlmx70U@7(j_p8NC59liU( zdrB!-$zU5|4Tv40lusi&2#~>RSjU=)r{47YGzSRy1Bx(l<9msI!bqfGN-_Sw7afO6 zkHU<;2p#=vh=&N1BpGG(54D_5YI%K83x=CvFl-Z#!$4Pv>ugs-RF7)-eq0N5Kwl7I z9!Osw(^(z)%`ih?jhfhEjjhj#>28?l-4JK9`quBnMAxB{x|(wiJPb7-8jZ6jb(~$+ zWiHTuQ|a9%#s~w2;1aw5Y!gwc3su%@{3w1Pl0IR^uTmENg5;8=V$P+FhG0BnstZDmMy{<31 z&~bC@;0EXK0`G(Z8@C!+#Wizn%*{!k(^2y$4yg3KFmvDcoCm&ll`AzC`Qpp64>HOt zPkav<-@81_N8#+F)YjACx= z8(^%8&d@K;xwnq?$soVToI-AlYsoz#&3Bn^zgI z4~hG5HyGdXfLr@sL26+t=bX-CUGuyl=f*w@Uyk=q{EGfS{yP?a?%99-UXxc5c||;q z$SdMH+m(pC+9R*_$SL}Qh`f?JExc-wR}py?kyjCU6_HmFc@>dY5qTAXJRq+cQz^q;-4{@3Z=j`4$c{a_mMw4kxHTRoY)=Iu0 zA16M2az3*zCbMo?&$>x6>#BLuO>>g2nk4iwr*iVy-9f8OJvdJFp=}L1pAJwtXboD7 zwogt_F`vUut1s!T{o5SyU&_nO;|(zX?eb;_4$MQq21Q~bn}oC-Lf!;f%{WQ?kM(Z;RUU7&6+3QqHLqjmXQRt?Tw|WB!HTS7*BaEehiJJ2R=!yS`gFcP zhdhCDUZTZbtyiMsm_94Ep0!uC?6ruq7}dVD&SK=HosO`yW%P7^MLX%sji+39YA+uB z)MT8KUlGUb{LVJwqOZH5hABx03q+a%ambArQtXJyYeJ+lVdOfsT$N1zGCk4)pHam6udb3BL*g^aO(J0A4