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 0000000000..6ceb4a2a72
Binary files /dev/null and b/Ghidra/Processors/ARC4/test differ
diff --git a/Ghidra/Processors/ARC4/test.s b/Ghidra/Processors/ARC4/test.s
new file mode 100644
index 0000000000..2f01afaf62
--- /dev/null
+++ b/Ghidra/Processors/ARC4/test.s
@@ -0,0 +1,28 @@
+; Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC
+; Authors: Dan Genin and Tommy Johnson
+
+ .ORG 0x100
+ .include "add.s"
+ nop
+ .include "branch.s"
+ nop
+ .include "jump.s"
+ nop
+ .include "ext.s"
+ nop
+ .include "loop.s"
+ nop
+ .include "sr.s"
+ nop
+ .include "st.s"
+ nop
+ .include "ld.s"
+ nop
+ .include "ret.s"
+ nop
+ .include "add.s"
+ nop
+ .include "sub.s"
+ nop
+ .include "logic_ops.s"
+ nop