Added ARC4 CPU support

This commit is contained in:
Dan Genin 2024-03-21 19:30:49 -04:00
parent 568ebd45ef
commit 5e299be862
29 changed files with 1428 additions and 0 deletions

View File

@ -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.

View File

View File

@ -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

View File

@ -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

View File

@ -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')
}

View File

@ -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

View File

@ -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|

View File

@ -0,0 +1,74 @@
<!-- Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC
Authors: Dan Genin and Tommy Johnson
-->
<?xml version="1.0" encoding="UTF-8"?>
<compiler_spec>
<global>
<range space="ram"/>
</global>
<stackpointer register="sp" space="ram"/>
<default_proto>
<prototype name="__stdcall" extrapop="0" stackshift="0">
<input>
<pentry minsize="1" maxsize="4">
<register name="r0"/>
</pentry>
<pentry minsize="1" maxsize="4">
<register name="r1"/>
</pentry>
<pentry minsize="1" maxsize="4">
<register name="r2"/>
</pentry>
<pentry minsize="1" maxsize="4">
<register name="r3"/>
</pentry>
<!--pentry minsize="1" maxsize="4">
<register name="r4"/>
</pentry-->
<pentry minsize="1" maxsize="500" align="4">
<addr offset="0" space="stack"/>
</pentry>
</input>
<output>
<pentry minsize="1" maxsize="4">
<register name="r0"/>
</pentry>
</output>
<unaffected>
<varnode space="ram" offset="0" size="4"/>
<register name="sp"/>
<register name="fp"/>
<register name="blink"/>
<register name="r13"/>
<register name="r14"/>
<register name="r15"/>
<register name="r16"/>
<register name="r17"/>
<register name="r18"/>
<register name="r19"/>
<register name="r20"/>
</unaffected>
</prototype>
</default_proto>
<!-- <prototype name="__stackcall" extrapop="unknown" stackshift="4">
<input pointermax="16">
<pentry minsize="1" maxsize="500" align="4">
<addr offset="0" space="stack"/>
</pentry>
</input>
<output>
<pentry minsize="1" maxsize="4">
<register name="r0"/>
</pentry>
</output>
<unaffected>
<varnode space="ram" offset="0" size="4"/>
<register name="sp"/>
<register name="blink"/>
</unaffected>
</prototype>
-->
</compiler_spec>

View File

@ -0,0 +1,18 @@
<!-- Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC
Authors: Dan Genin and Tommy Johnson
-->
<?xml version="1.0" encoding="UTF-8"?>
<language_definitions>
<language processor="ARC4"
endian="little"
size="32"
variant="default"
version="1.0"
slafile="ARC4_le.sla"
processorspec="ARC4.pspec"
id="ARC4:BE:32:default">
<description>ARC4 32 bit little-endian</description>
<compiler name="default" spec="ARC4.cspec" id="default"/>
</language>
</language_definitions>

View File

@ -0,0 +1,9 @@
<!-- Copyright 2023 The Johns Hopkins University Applied Physics Laboratory LLC
Authors: Dan Genin and Tommy Johnson
-->
<?xml version="1.0" encoding="UTF-8"?>
<processor_spec>
<programcounter register="pc"/>
</processor_spec>

View File

@ -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)
;

View File

@ -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
# <sign bit> ? -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 <skip>; goto [lp_addr]; <skip> }
# 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 <skip>; delayslot(1); <skip> } # 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 <skip>;
# 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 <skip>;
# otherwise return to the start of the loop
goto [lp_start];
<skip>
}
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 <skip>;
tmp = 0xFFFFFFFF << (32 - opC);
<skip>
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];
}

View File

@ -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"

View File

@ -0,0 +1,11 @@
<patternlist>
<patternpairs totalbits="32" postbits="16">
<prepatterns>
<data>......00 0x10 0x6e 0x0b</data>
</prepatterns>
<postpatterns>
<data>0x04 0x3e 0x0e 0x10</data>
<funcstart/>
</postpatterns>
</patternpairs>
</patternlist>

View File

@ -0,0 +1,11 @@
<patternlist>
<patternpairs totalbits="32" postbits="16">
<prepatterns>
<data>......00 0x10 0x6e 0x0b</data>
</prepatterns>
<postpatterns>
<data>0x04 0x3e 0x0e 0x10</data>
<funcstart/>
</postpatterns>
</patternpairs>
</patternlist>

View File

@ -0,0 +1,5 @@
<patternconstraints>
<language id="ARC4:LE:32:*">
<patternfile>ARC4_LE_patterns.xml</patternfile>
</language>
</patternconstraints>

View File

@ -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

View File

@ -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 <short immediate>
jl_test:
nop
nop
nop

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,2 @@
#!/bin/sh
~/other_projects/KodakP720/usr/local/arc/bin/arc-elf32-objdump -D $1

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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

BIN
Ghidra/Processors/ARC4/test Executable file

Binary file not shown.

View File

@ -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