commit 9e34a2b211d377254d60018d58ef1b127fcf127e Author: Sebastian Schmidt Date: Sat Jun 22 15:04:45 2019 +0200 Initial commit diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4fb59c7 --- /dev/null +++ b/Makefile @@ -0,0 +1,54 @@ +# Assume we are in Ghidra/Processors/subdir +GHIDRA_DIR ?= $(shell readlink -f $(CURDIR)/../../..) +SLEIGH ?= $(GHIDRA_DIR)/support/sleigh +PERL ?= perl + +# -x turns on parser debugging (SleighCompile) +# -u print warnings for unnecessary pcode instructions (SleighCompile) +# -l report pattern conflicts (SleighCompile) +# -n print warnings for all NOP constructors (SleighCompile) +# -t print warnings for dead temporaries (SleighCompile) +# -e enforce use of 'local' keyword for temporaries (SleighCompile) +# -f print warnings for unused token fields (SleighCompile) +SLEIGH_ARGS := -x -u -l -n -t -e -f + +LANGDIR := data/languages + +# Must start with slaspec. +SLA_SRCS := $(LANGDIR)/xtensa.slaspec $(wildcard $(LANGDIR)/xtensa*.sinc) +SLA := $(LANGDIR)/xtensa.sla + +MANDIR := data/manuals +IDX := $(MANDIR)/xtensa.idx + +# Targets + +.PHONY: all +all: check-ghidra $(SLA) $(IDX) + +.PHONY: check-ghidra +check-ghidra: + @if [ ! -d $(GHIDRA_DIR)/Ghidra ]; then \ + echo "Your Ghidra installation directory could not be determined." >&2; \ + echo "Please re-run make with GHIDRA_DIR set to the root of your Ghidra installation." >&2; \ + exit 1; \ + fi + +$(SLA): $(SLA_SRCS) + $(SLEIGH) $(SLEIGH_ARGS) $< $@ + +$(IDX): $(SLA_SRCS) + mkdir -p $(MANDIR) + $(PERL) mkindex.pl $^ > $@ + +release.zip: clean all + mkdir -p release/Xtensa/$(LANGDIR) + cp -r $(LANGDIR)/xtensa* release/Xtensa/$(LANGDIR) + mkdir -p release/Xtensa/$(MANDIR) + cp -r $(MANDIR)/*.idx release/Xtensa/$(MANDIR) + cp Module.manifest release/Xtensa + cd release && zip -r ../$@ . + +.PHONY: clean +clean: + rm -rf $(SLA) $(IDX) release release.zip diff --git a/Module.manifest b/Module.manifest new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..31156c3 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# Tensilica Xtensa module for Ghidra + +![Screenshot](/screenshot.png?raw=true) + +# Installation + +``` +$ cd ghidra_9.0.X/Ghidra/Processors +$ git clone https://github.com/yath/ghidra-xtensa Xtensa +$ cd Xtensa +$ make +$ +``` + +Or download a pre-built release and unzip it to `Ghidra/Processors`. + +# Bugs + +* Some calculations are wrong, causing Ghidra to miscalculate a jump target. +* Probably a lot of others in instructions I did not yet happen to encouter. Pull requests + appreciated. + +# TODO + +* An `.opinion` file for autodetection +* Windowed Register Option +* MAC16 Option +* Loop Option +* ESP8266/ESP32 image loaders? diff --git a/data/languages/xtensa.cspec b/data/languages/xtensa.cspec new file mode 100644 index 0000000..4fd5967 --- /dev/null +++ b/data/languages/xtensa.cspec @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/languages/xtensa.ldefs b/data/languages/xtensa.ldefs new file mode 100644 index 0000000..4a4d460 --- /dev/null +++ b/data/languages/xtensa.ldefs @@ -0,0 +1,16 @@ + + + + + Tensilica Xtensa 32-bit little-endian + + + diff --git a/data/languages/xtensa.pspec b/data/languages/xtensa.pspec new file mode 100644 index 0000000..114b5c4 --- /dev/null +++ b/data/languages/xtensa.pspec @@ -0,0 +1,5 @@ + + + + + diff --git a/data/languages/xtensa.sinc b/data/languages/xtensa.sinc new file mode 100644 index 0000000..e225835 --- /dev/null +++ b/data/languages/xtensa.sinc @@ -0,0 +1,294 @@ +define endian=little; +define alignment=1; + +define space ram type=ram_space size=4 default; +define space register type=register_space size=4; + +# Address registers (AR). +define register offset=0x0000 size=4 [ + a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 +]; + +# Floating Point registers (FR + FCR (control) + FSR (status)). +# TODO: FCR and FSR seem unused? +define register offset=0x0100 size=4 [ + f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13 f14 f15 + fcr fsr +]; + +# Boolean registers (BR). +define register offset=0x0200 size=1 [ + b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 +]; + +# Program counter. +define register offset=0x1000 size=4 [ pc ]; + +# Shift amount register. (TODO: other special registers) +define register offset=0x2000 size=1 [ sar ]; + +# Regular 24-bit instruction. +define token insn(24) + # Named opcode/register fields. + op2 = (20,23) + ar = (12,15) + fr = (12,15) + br = (12,15) + as = (8,11) + fs = (8,11) + bs = (8,11) + at = (4,7) + ft = (4,7) + bt = (4,7) + op1 = (16,19) + op0 = (0,3) + + # Signed and unsigned immediates. Named [us]N_L.M, where u and s denote signedness, L and M the + # least and most significant bit of the immediate in the instruction word, and N the length + # (i.e. M-L+1). + u3_21.23 = (21,23) + u4_20.23 = (20,23) + s8_16.23 = (16,23) signed + u8_16.23 = (16,23) + u12_12.23 = (12,23) + s12_12.23 = (12,23) signed + u16_8.23 = (8,23) + s8_6.23 = (6,23) signed + u1_20 = (20,20) + u2_18.19 = (18,19) + u3_17.19 = (17,19) + u2_16.17 = (16,17) + u1_16 = (16,16) + u2_14.15 = (14,15) + u3_13.15 = (13,15) + u4_12.15 = (12,15) + u8_8.15 = (8,15) + u2_12.13 = (12,13) + u1_12 = (12,12) + u4_8.11 = (8,11) + u8_4.11 = (4,11) + # s4_8.11 = (8,11) signed + u2_6.7 = (6,7) + u3_5.7 = (5,7) + u4_4.7 = (4,7) + s4_4.7 = (4,7) + u2_4.5 = (4,5) + u1_4 = (4,4) +; + +# Narrow 16-bit instructions; fields are always prefixed with n_. +define token narrowinsn(16) + n_ar = (12,15) + n_as = (8,11) + n_at = (4,7) + n_op0 = (0, 3) + + n_u4_12.15 = (12,15) + n_s4_12.15 = (12,15) signed + n_u4_8.11 = (8,11) + n_u1_7 = (7,7) + n_u2_6.7 = (6,7) + n_u4_4.7 = (4,7) + n_s3_4.6 = (4,6) + n_u2_4.5 = (4,5) + +; + +attach variables [ ar as at n_ar n_as n_at ] [ + a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 +]; + +attach variables [ fr fs ft ] [ + f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13 f14 f15 +]; + +attach variables [ br bs bt ] [ + b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 +]; + +# Various 32-bit pointers relative to PC. Any operands that are split across non-consecutive +# bits are named foo_LL.LM_ML.MM, where LL is the least significant bits of the least +# singificant operand half, LM the most significant bits of the least significant operand half, etc. + +urel_16.23: rel is u8_16.23 [ rel = inst_start + u8_16.23 + 4; ] { export *:4 rel; } + +srel_16.23: rel is s8_16.23 [ rel = inst_start + s8_16.23 + 4; ] { export *:4 rel; } + +srel_12.23: rel is s12_12.23 [ rel = inst_start + s12_12.23 + 4; ] { export *:4 rel; } + +srel_6.23: rel is s8_6.23 [ rel = inst_start + s8_6.23 + 4; ] { export *:4 rel; } + +urel_12.15_4.5: rel is n_u2_4.5 & n_u4_12.15 [ + rel = inst_start + ((n_u2_4.5 << 4) | n_u4_12.15) + 4; +] { export *:4 rel; } + +srel_6.23_sb2: rel is s8_6.23 [ + rel = (inst_start & ~3) + ( s8_6.23 << 2 ) + 4; +] { export *:4 rel; } + +srel_8.23_oex_sb2: rel is u16_8.23 [ + rel = ((inst_start + 3) & ~3) + ((u16_8.23 | 0xffff0000) << 2); +] { export *:4 rel; } + +# Immediates split across the instruction. +u5_8.11_20: tmp is u1_20 & u4_8.11 [ tmp = (u1_20 << 4) | u4_8.11; ] { export *[const]:1 tmp; } +u5_4.7_20: tmp is u1_20 & u4_4.7 [ tmp = (u1_20 << 4) | u4_4.7; ] { export *[const]:1 tmp; } +u5_8.11_16: tmp is u1_16 & u4_8.11 [ tmp = (u1_16 << 4) | u4_8.11; ] { export *[const]:1 tmp; } +u5_4.7_12: tmp is u1_12 & u4_4.7 [ tmp = (u1_12 << 4) | u4_4.7; ] { export *[const]:1 tmp; } +u5_8.11_4: tmp is u1_4 & u4_8.11 [ tmp = (u1_4 << 4) | u4_8.11; ] { export *[const]:1 tmp; } + +# Signed 12-bit (extended to 16) immediate, used by MOVI. +s16_16.23_8.11: tmp is u4_8.11 & u8_16.23 [ + # FIXME: This table, and the fields used, should be signed, but using s4_8.11 and s8_16.23 + # somehow confuses Ghidra. + tmp = (0xf000 * (u4_8.11 >> 3)) | # Sign-extend. + (u4_8.11 << 8) | u8_16.23; +] { export *[const]:2 tmp; } + +# An “asymmetric” immediate from -32..95, used by MOVI.N. +n_s8_12.15_4.6_asymm: tmp is n_s3_4.6 & n_s4_12.15 [ + tmp = ((((n_s3_4.6 >> 2) & 1) & ((n_s3_4.6 >> 3) & 1)) << 7) | # sign + (n_s3_4.6 << 4) | n_s4_12.15; +] { export *[const]:1 tmp; } + +# Immediates shifted or with offset. +s16_16.23_sb8: tmp is s8_16.23 [ tmp = s8_16.23 << 8; ] { export *[const]:2 tmp; } +u15_12.23_sb3: tmp is u12_12.23 [ tmp = u12_12.23 << 3; ] { export *[const]:2 tmp; } +u10_16.23_sb2: tmp is u8_16.23 [ tmp = u8_16.23 << 2; ] { export *[const]:2 tmp; } +u9_16.23_sb1: tmp is u8_16.23 [ tmp = u8_16.23 << 1; ] { export *[const]:2 tmp; } +u5_20.23_plus1: tmp is u4_20.23 [ tmp = u4_20.23 + 1; ] { export *[const]:1 tmp; } +u8_20.23_sb4: tmp is u4_20.23 [ tmp = u4_20.23 << 4; ] { export *[const]:1 tmp; } +u5_4.7_plus7: tmp is u4_4.7 [ tmp = u4_4.7 + 7; ] { export *[const]:1 tmp; } + +n_u6_12.15_sb2: tmp is n_u4_12.15 [ tmp = n_u4_12.15 << 2; ] { export *[const]:1 tmp; } + +# One-extended. FIXME: Verify this. Only used by [LS]32E (window extension), which aren’t yet +# implemented. +s5_12.15_oex: tmp is u4_12.15 [ tmp = (2 << u4_12.15) * -1; ] { export *[const]:2 tmp; } + +# Some 4-bit immediates with mappings that can’t be (easily) expressed in a single disassembly action. +# FIXME: “foo: tmp is u4_foo [ tmp = u4_foo; ]” doesn’t work when a more special constructor exists. + +# n_u4_4.7 with 0 being -1, used by ADDI.N. +n_s4_4.7_nozero: tmp is n_u4_4.7 = 0 [ tmp = -1; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 1 [ tmp = 1; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 2 [ tmp = 2; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 3 [ tmp = 3; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 4 [ tmp = 4; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 5 [ tmp = 5; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 6 [ tmp = 6; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 7 [ tmp = 7; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 8 [ tmp = 8; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 9 [ tmp = 9; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 10 [ tmp = 10; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 11 [ tmp = 11; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 12 [ tmp = 12; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 13 [ tmp = 13; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 14 [ tmp = 14; ] { export *[const]:4 tmp; } +n_s4_4.7_nozero: tmp is n_u4_4.7 = 15 [ tmp = 15; ] { export *[const]:4 tmp; } + +# B4CONST(ar) (Branch Immediate) encodings, pg. 41 f. +r_b4const: tmp is ar = 0 [ tmp = 0xffffffff; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 1 [ tmp = 0x1; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 2 [ tmp = 0x2; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 3 [ tmp = 0x3; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 4 [ tmp = 0x4; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 5 [ tmp = 0x5; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 6 [ tmp = 0x6; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 7 [ tmp = 0x7; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 8 [ tmp = 0x8; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 9 [ tmp = 0xa; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 10 [ tmp = 0xc; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 11 [ tmp = 0x10; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 12 [ tmp = 0x20; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 13 [ tmp = 0x40; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 14 [ tmp = 0x80; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 15 [ tmp = 0x100; ] { export *[const]:4 tmp; } + +# B4CONSTU(ar) (Branch Unsigned Immediate) encodings, pg. 42. +r_b4constu: tmp is ar = 0 [ tmp = 0x8000; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 1 [ tmp = 0x1000; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 2 [ tmp = 0x2; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 3 [ tmp = 0x3; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 4 [ tmp = 0x4; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 5 [ tmp = 0x5; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 6 [ tmp = 0x6; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 7 [ tmp = 0x7; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 8 [ tmp = 0x8; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 9 [ tmp = 0xa; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 10 [ tmp = 0xc; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 11 [ tmp = 0x10; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 12 [ tmp = 0x20; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 13 [ tmp = 0x40; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 14 [ tmp = 0x80; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 15 [ tmp = 0x100; ] { export *[const]:4 tmp; } + +define pcodeop breakpoint; +define pcodeop dhi; +define pcodeop dhu; +define pcodeop dhwb; +define pcodeop dhwbi; +define pcodeop dii; +define pcodeop diu; +define pcodeop diwb; +define pcodeop diwbi; +define pcodeop dpfl; +define pcodeop dpfr; +define pcodeop dpfro; +define pcodeop dpfw; +define pcodeop dpfwo; +define pcodeop dsync; +define pcodeop esync; +define pcodeop excw; +define pcodeop extw; +define pcodeop idtlb; +define pcodeop ihi; +define pcodeop ihu; +define pcodeop iii; +define pcodeop iitlb; +define pcodeop iiu; +define pcodeop ill; +define pcodeop ipf; +define pcodeop ipfl; +define pcodeop isync; +define pcodeop acquire; +define pcodeop ldct; +define pcodeop lict; +define pcodeop licw; +define pcodeop memw; +define pcodeop nsa; +define pcodeop nsau; +define pcodeop pdtlb; +define pcodeop pitlb; +define pcodeop rdtlb0; +define pcodeop rdtlb1; +define pcodeop rer; +define pcodeop rfdd; +define pcodeop rfde; +define pcodeop rfdo; +define pcodeop rfe; +define pcodeop rfi; +define pcodeop rfme; +define pcodeop rfue; +define pcodeop rfwo; +define pcodeop rfwu; +define pcodeop ritlb0; +define pcodeop ritlb1; +define pcodeop rsil; +define pcodeop rsr; # TODO: Map known special registers. +define pcodeop rsync; +define pcodeop rur; +define pcodeop s32c1i; +define pcodeop release; +define pcodeop sdct; +define pcodeop sict; +define pcodeop sicw; +define pcodeop simcall; +define pcodeop syscall; +define pcodeop waiti; +define pcodeop wdtlb; +define pcodeop wer; +define pcodeop witlb; +define pcodeop wsr; # TODO: Map known special registers. +define pcodeop wur; +define pcodeop xsr; diff --git a/data/languages/xtensa.slaspec b/data/languages/xtensa.slaspec new file mode 100644 index 0000000..16a64f3 --- /dev/null +++ b/data/languages/xtensa.slaspec @@ -0,0 +1,3 @@ +@include "xtensa.sinc" +@include "xtensaInstructions.sinc" +@include "xtensaTodo.sinc" diff --git a/data/languages/xtensaInstructions.sinc b/data/languages/xtensaInstructions.sinc new file mode 100644 index 0000000..2f22a73 --- /dev/null +++ b/data/languages/xtensaInstructions.sinc @@ -0,0 +1,1283 @@ +# ABS - Absolute Value (RRR), pg. 246. +:abs ar, at is op2 = 0b0110 & op1 = 0 & ar & as = 0b0001 & at & op0 = 0 { + ar = at; + if (ar s> 0) + goto inst_next; + ar = -ar; +} + +# ABS.S - Absolute Single Value (RRR), pg. 247. +:abs.s fr, fs is op2 = 0b1111 & op1 = 0b1010 & fr & fs & at = 0b0001 & op0 = 0b0000 { + fr = abs(fs); +} + +# ADD - Add (RRR), pg. 248. +:add ar, as, at is op2 = 0b1000 & op1 = 0 & ar & as & at & op0 = 0 { + ar = as + at; +} + +# ADD.N - Narrow Add (RRRN), pg. 249. +:add.n n_ar, n_as, n_at is n_ar & n_as & n_at & n_op0 = 0b1010 { + n_ar = n_as + n_at; +} + +# ADD.S - Add Single (RRR), pg. 250. +:add.s fr, fs, ft is op2 = 0 & op1 = 0b1010 & fr & fs & ft & op0 = 0 { + fr = fs f+ ft; +} + +# ADDI - Add Immediate (RRI8), pg. 251. +:addi at, as, s8_16.23 is s8_16.23 & ar = 0b1100 & as & at & op0 = 0b0010 { + at = as + sext(s8_16.23:1); +} + +# ADDI.N - Narrow Add Immediate (RRRN), pg. 252. +:addi.n n_ar, n_as, n_s4_4.7_nozero is n_ar & n_as & n_s4_4.7_nozero & n_op0 = 0b1011 { + n_ar = n_as + n_s4_4.7_nozero; +} + +# ADDMI - Add Immediate with Shift by 8, pg. 253. +:addmi at, as, s16_16.23_sb8 is s16_16.23_sb8 & ar = 0b1101 & as & at & op0 = 0b0010 { + at = as + sext(s16_16.23_sb8); +} + +# ADDX2 - Add with Shift by 1, pg. 254. +:addx2 ar, as, at is op2 = 0b1001 & op1 = 0 & ar & as & at & op0 = 0 { + ar = (as << 1) + at; +} + +# ADDX4 - Add with Shift by 2, pg. 255. +:addx4 ar, as, at is op2 = 0b1010 & op1 = 0 & ar & as & at & op0 = 0 { + ar = (as << 2) + at; +} + +# ADDX8 - Add with Shift by 4, pg. 256. +:addx8 ar, as, at is op2 = 0b1011 & op1 = 0 & ar & as & at & op0 = 0 { + ar = (as << 3) + at; +} + +# ALL4 - All 4 Booleans True, pg. 257. +:all4 bt, bs is op2 = 0 & op1 = 0 & ar = 0b1001 & bs & bt & op0 = 0 { + local b = *[register]:1 &:4 bs+1; + local c = *[register]:1 &:4 bs+2; + local d = *[register]:1 &:4 bs+3; + bt = bs && b && c && d; +} + +# ALL8 - All 8 Booleans True, pg. 258. +:all8 bt, bs is op2 = 0 & op1 = 0 & ar = 0b1011 & bs & bt & op0 = 0 { + local b = *[register]:1 &:4 bs+1; + local c = *[register]:1 &:4 bs+2; + local d = *[register]:1 &:4 bs+3; + local e = *[register]:1 &:4 bs+4; + local f = *[register]:1 &:4 bs+5; + local g = *[register]:1 &:4 bs+6; + local h = *[register]:1 &:4 bs+7; + bt = bs && b && c && d && e && f && g && h; +} + +# AND - Bitwise Logical And, pg. 259. +:and ar, as, at is op2 = 0b0001 & op1 = 0 & ar & as & at & op0 = 0 { + ar = as & at; +} + +# ANDB - Boolean And, pg. 260. +:andb br, bs, bt is op2 = 0 & op1 = 0b0010 & br & bs & bt & op0 = 0 { + br = bs && bt; +} + +# ANDBC - Boolean And with Complement, pg. 261. +:andbc br, bs, bt is op2 = 0b0001 & op1 = 0b0010 & br & bs & bt & op0 = 0 { + br = bs && !bt; +} + +# ANY4 - Any 4 Booleans True, pg. 262. +:any4 bt, bs is op2 = 0 & op1 = 0 & ar = 0b1000 & bs & bt & op0 = 0 { + local b = *[register]:1 &:4 bs+1; + local c = *[register]:1 &:4 bs+2; + local d = *[register]:1 &:4 bs+3; + bt = bs || b || c || d; +} + +# ANY8 - Any 8 Booleans True, pg. 263. +:any8 bt, bs is op2 = 0 & op1 = 0 & ar = 0b1010 & bs & bt & op0 = 0 { + local b = *[register]:1 &:4 bs+1; + local c = *[register]:1 &:4 bs+2; + local d = *[register]:1 &:4 bs+3; + local e = *[register]:1 &:4 bs+4; + local f = *[register]:1 &:4 bs+5; + local g = *[register]:1 &:4 bs+6; + local h = *[register]:1 &:4 bs+7; + bt = bs || b || c || d || e || f || g || h; +} + +# BALL - Branch if All Bits Set, pg. 264. +:ball srel_16.23, as, at is srel_16.23 & ar = 0b0100 & as & at & op0 = 0b0111 { + if ((~as & at) == 0) + goto srel_16.23; +} + +# BANY - Branch if Any Bit Set, pg. 265. +:bany srel_16.23, as, at, is srel_16.23 & ar = 0b1000 & as & at & op0 = 0b0111 { + if ((as & at) != 0) + goto srel_16.23; +} + +macro extract_bit(val, bit, result) { + result = (val >> bit)&1; +} + +# BBC - Branch if Bit Clear, pg. 266. +:bbc as, at, srel_16.23 is srel_16.23 & ar = 0b0101 & as & at & op0 = 0b0111 { + local bval; + extract_bit(as, at[0,5], bval); + if (bval == 0) + goto srel_16.23; +} + +# BBCI - Branch if Bit Clear immediate, pg. 267 +:bbci as, u5_4.7_12, srel_16.23 is srel_16.23 & u3_13.15 = 0b011 & as & u5_4.7_12 & op0 = 0b0111 { + local bval; + extract_bit(as, u5_4.7_12, bval); + if (bval == 0) + goto srel_16.23; +} + +# BBS - Branch if Bit Set, pg. 269. +:bbs as, at, srel_16.23 is srel_16.23 & ar = 0b1101 & as & at & op0 = 0b0111 { + local bval; + extract_bit(as, at[0,5], bval); + if (bval != 0) + goto srel_16.23; +} + +# BBSI - Branch if Bit Set immediate, pg. 270. +:bbsi as, u5_4.7_12, srel_16.23 is srel_16.23 & u3_13.15 = 0b111 & as & u5_4.7_12 & op0 = 0b0111 { + local bval; + extract_bit(as, u5_4.7_12, bval); + if (bval == 0) + goto srel_16.23; +} + +# BEQ - Branch if Equal, pg. 272. +:beq as, at, srel_16.23 is srel_16.23 & ar = 0b0001 & as & at & op0 = 0b0111 { + if (as == at) + goto srel_16.23; +} + +# BEQI - Branch if Equal Immediate, pg. 273. +:beqi as, r_b4const, srel_16.23 is srel_16.23 & r_b4const & as & u2_6.7 = 0 & u2_4.5 = 0b10 & op0 = 0b0110 { + if (as == r_b4const) + goto srel_16.23; +} + +# BEQZ - Branch if Equal Zero, pg. 274. +:beqz as, srel_12.23 is srel_12.23 & as & u2_6.7 = 0 & u2_4.5 = 0b01 & op0 = 0b0110 { + if (as == 0) + goto srel_12.23; +} + +# BEQZ.N - Narrow Branch if Equal Zero, pg. 275. +:beqz.n n_as, urel_12.15_4.5 is urel_12.15_4.5 & n_as & n_u2_6.7 = 0b10 & n_op0 = 0b1100 { + if (n_as == 0) + goto urel_12.15_4.5; +} + +# BF - Branch if False, pg. 276. +:bf bs, srel_16.23 is srel_16.23 & ar = 0 & bs & at = 0b0111 & op0 = 0b0110 { + if (!bs) + goto srel_16.23; +} + +# BGE - Branch if Greater Than or Equal, pg. 277. +:bge as, at, srel_16.23 is srel_16.23 & ar = 0b1010 & as & at & op0 = 0b0111 { + if (as s>= at) + goto srel_16.23; +} + +# BGEI - Branch if Greater Than or Equal Immediate, pg. 278. +:bgei as, r_b4const, srel_16.23 is srel_16.23 & r_b4const & as & u2_6.7 = 0b11 & u2_4.5 = 0b10 & op0 = 0b0110 { + if (as s>= r_b4const) + goto srel_16.23; +} + +# BGEU - Branch if Greater Than or Equal Unsigned, pg. 279. +:bgeu as, at, srel_16.23 is srel_16.23 & ar = 0b1011 & as & at & op0 = 0b0111 { + if (as >= at) + goto srel_16.23; +} + +# BGEUI - Branch if Greater Than or Equal Unsigned Immediate, pg. 280. +:bgeui as, r_b4constu, srel_16.23 is srel_16.23 & r_b4constu & as & u2_6.7 = 0b11 & u2_4.5 = 0b11 & op0 = 0b0110 { + if (as >= r_b4constu) + goto srel_16.23; +} + +# BGEZ - Branch if Greater Than or Equal Zero, pg. 281. +:bgez as, srel_12.23 is srel_12.23 & as & u2_6.7 = 0b11 & u2_4.5 = 0b01 & op0 = 0b0110 { + if (as s>= 0) + goto srel_12.23; +} + +# BLT - Branch if Less Than, pg. 282. +:blt as, at, srel_16.23 is srel_16.23 & ar = 0b0010 & as & at & op0 = 0b0111 { + if (as s< at) + goto srel_16.23; +} + +# BLTI - Branch if Less Than Immediate, pg. 283. +:blti as, r_b4const, srel_16.23 is srel_16.23 & r_b4const & as & u2_6.7 = 0b10 & u2_4.5 = 0b10 & op0 = 0b0110 { + if (as s< r_b4const) + goto srel_16.23; +} + +# BLTU - Branch if Less Than Unsigned, pg. 284. +:bltu as, at, srel_16.23 is srel_16.23 & ar = 0b0011 & as & at & op0 = 0b0111 { + if (as < at) + goto srel_16.23; +} + +# BLTUI - Branch if Less Than Unsigned Immediate, pg. 285. +:bltui as, r_b4constu, srel_16.23 is srel_16.23 & r_b4constu & as & u2_6.7 = 0b10 & u2_4.5 = 0b11 & op0 = 0b0110 { + if (as < r_b4constu) + goto srel_16.23; +} + +# BLTZ - Branch if Less Than Zero, pg. 286. +:bltz as, srel_12.23 is srel_12.23 & as & u2_6.7 = 0b10 & u2_4.5 = 0b01 & op0 = 0b0110 { + if (as s< 0) + goto srel_12.23; +} + +# BNALL - Branch if Not-All Bits Set, pg. 287. +:bnall srel_16.23, as, at is srel_16.23 & ar = 0b1100 & as & at & op0 = 0b0111 { + if ((~as & at) != 0) + goto srel_16.23; +} + +# BNE - Branch if Not Equal, pg. 288. +:bne as, at, srel_16.23 is srel_16.23 & ar = 0b1001 & as & at & op0 = 0b0111 { + if (as != at) + goto srel_16.23; +} + +# BNEI - Branch if Not EquaL Immediate, pg. 289. +:bnei as, r_b4const, srel_16.23 is srel_16.23 & r_b4const & as & u2_6.7 = 0b01 & u2_4.5 = 0b10 & op0 = 0b0110 { + if (as != r_b4const) + goto srel_16.23; +} + +# BNEZ - Branch if Not Equal Zero, pg. 290. +:bnez as, srel_12.23 is srel_12.23 & as & u2_6.7 = 0b01 & u2_4.5 = 0b01 & op0 = 0b0110 { + if (as != 0) + goto srel_12.23; +} + +# BNEZ.N - Narrow Branch if Not Equal Zero, pg. 291. +:bnez.n n_as, urel_12.15_4.5 is urel_12.15_4.5 & n_as & n_u2_6.7 = 0b11 & n_op0 = 0b1100 { + if (n_as != 0) + goto urel_12.15_4.5; +} + +# BNONE - Branch if No Bit Set, pg. 292. +:bnone srel_16.23, as, at, is srel_16.23 & ar = 0 & as & at & op0 = 0b0111 { + if ((as & at) == 0) + goto srel_16.23; +} + +# BREAK - Breakpoint, pg. 293. +:break u4_8.11, u4_4.7 is op2 = 0 & op1 = 0 & ar = 0b0100 & u4_8.11 & u4_4.7 & op0 = 0 { + breakpoint(0x001000:4, u4_8.11:1, u4_4.7:1); +} + +# BREAK.N - Narrow Breakpoint, pg. 295. +:break.n n_u4_8.11 is n_ar = 0b1111 & n_u4_8.11 & n_at = 0b0010 & n_op0 = 0b1101 { + breakpoint(0x010000:4, n_u4_8.11:1, 0:1); +} + +# BT - Branch if True, pg. 296. +:bt bs, srel_16.23 is srel_16.23 & ar = 0b0001 & bs & at = 0b0111 & op0 = 0b0110 { + if (bs) + goto srel_16.23; +} + +# CALL0 - Non-windowed Call, pg. 297. +:call0 srel_6.23_sb2 is srel_6.23_sb2 & u2_4.5 = 0 & op0 = 0b0101 { + a0 = inst_start + 3; + call srel_6.23_sb2; +} + +# CALLX0 - Non-windowed Call Register, pg. 304. +:callx0 as is op2 = 0 & op1 = 0 & ar = 0 & as & u2_6.7 = 0b11 & u2_4.5 = 0 & op0 = 0 { + local dst = as; + a0 = inst_start + 3; + call [dst]; +} + +# CEIL.S - Ceiling Single to Fixed, pg. 311. +:ceil.s ar, fs, u4_4.7 is op2 = 0b1011 & op1 = 0b1010 & ar & fs & u4_4.7 & op0 = 0 { + local scale:4 = int2float(1:1 << u4_4.7:1); + ar = ceil(fs f* scale); +} + +# CLAMPS - Signed Clamp, pg. 312. +:clamps ar, as, u5_4.7_plus7 is op2 = 0b0011 & op1 = 0b0011 & ar & as & u5_4.7_plus7 & op0 = 0 { + # ar ← min(max(as, -2^{u5_4.7_plus7}), 2^{u5_4.7_plus7}-1) + local maxval:4 = (1 << u5_4.7_plus7) - 1; + local minval:4 = -(1 << u5_4.7_plus7); + if (as s< minval) + goto ; + if (as s> maxval) + goto ; + + ar = as; + goto inst_next; + + + ar = minval; + goto inst_next; + + + ar = maxval; + # fallthrough inst_next +} + +# DHI - Data Cache Hit Invalidate, pg. 313. +:dhi as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b0110 & op0 = 0b0010 { + dhi(as + zext(u10_16.23_sb2)); +} + +# DHU - Data Cache Hit Unlock, pg. 315. +:dhu as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0b0010 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 { + dhu(as + zext(u8_20.23_sb4)); +} + +# DHWB - Data Cache Hit Writeback, pg. 317. +:dhwb as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b0100 & op0 = 0b0010 { + dhwb(as + zext(u10_16.23_sb2)); +} + +# DHWBI - Data Cache Hit Writeback Invalidate, pg. 319. +:dhwbi as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b0101 & op0 = 0b0010 { + dhwbi(as + zext(u10_16.23_sb2)); +} + +# DII - Data Cache Index Invalidate, pg. 321. +:dii as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b0111 & op0 = 0b0010 { + dii(as + zext(u10_16.23_sb2)); +} + +# DIU - Data Cache Index Unlock, pg. 323. +:diu as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0b0011 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 { + diu(as + zext(u8_20.23_sb4)); +} + +# DIWB - Data Cache Index Write Back, pg. 325. +:diwb as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0b0100 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 { + diwb(as + zext(u8_20.23_sb4)); +} + +# DIWBI - Data Cache Index Write Back Invalidate, pg. 327. +:diwbi as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0b0101 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 { + diwbi(as + zext(u8_20.23_sb4)); +} + +# DPFL - Data Cache Prefetch and Lock, pg. 329. +:dpfl as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 { + dpfl(as + zext(u8_20.23_sb4)); +} + +# DPFR - Data Cache Prefetch for Read, pg. 331. +:dpfr as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0 & op0 = 0b0010 { + dpfr(as + zext(u10_16.23_sb2)); +} + +# DPFRO - Data Cache Prefetch for Read Once, pg. 333. +:dpfro as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b0010 & op0 = 0b0010 { + dpfro(as + zext(u10_16.23_sb2)); +} + +# DPFW - Data Cache Prefetch for Write, pg. 335. +:dpfw as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b0001 & op0 = 0b0010 { + dpfw(as + zext(u10_16.23_sb2)); +} + +# DPFWO - Data Cache Prefetch for Write Once, pg. 337. +:dpfwo as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b0011 & op0 = 0b0010 { + dpfwo(as + zext(u10_16.23_sb2)); +} + +# DSYNC - Load/Store Synchronize, pg. 339. +:dsync is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b0011 & op0 = 0 { + dsync(); +} + +# ESYNC - Execute Synchronize, pg. 342. +:esync is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b0010 & op0 = 0 { + esync(); +} + +# EXCW - Exception Wait, pg. 343. +:excw is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b1000 & op0 = 0 { + excw(); +} + +# EXTUI - Extract Unsigned Immediate, pg. 344. +:extui ar, at, u5_8.11_16, u5_20.23_plus1 is u5_20.23_plus1 & u3_17.19 = 0b010 & u5_8.11_16 & ar & at & op0 = 0 { + local shifted:4 = at >> u5_8.11_16; + local mask:4 = (1:4 << (u5_20.23_plus1))-1; + ar = shifted & mask; +} + +# EXTW - External Wait, pg. 345. +:extw is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b1101 & op0 = 0 { + extw(); +} + +# FLOAT.S - Convert Fixed to Single, pg. 346. +:float.s fr, as, u4_4.7 is op2 = 0b1100 & op1 = 0b1010 & fr & as & u4_4.7 & op0 = 0 { + local f = int2float(as); + local d = int2float(1:2 << u4_4.7:2); + fr = d f/ f; +} + +# FLOOR.S - Floor Single to Fixed, pg. 347. +:floor.s ar, fs, u4_4.7 is op2 = 0b1010 & op1 = 0b1010 & ar & fs & u4_4.7 & op0 = 0 { + local scale:4 = int2float(1:2 << u4_4.7:2); + ar = floor(fs f* scale); +} + +# IDTLB - Invalidate Data TLB Entry, pg. 348. +:idtlb as is op2 = 0b0101 & op1 = 0 & ar = 0b1100 & as & at = 0 & op0 = 0 { + idtlb(); +} + +# IHI - Instruction Cache Hit Invalidate, pg. 349. +:ihi as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b1110 & op0 = 0b0010 { + ihi(as + zext(u10_16.23_sb2)); +} + +# IHU - Instruction Cache Hit Unlock, pg. 351. +:ihu as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0b0010 & ar = 0b0111 & as & at = 0b1101 & op0 = 0b0010 { + ihu(as + zext(u8_20.23_sb4)); +} + +# III - Instruction Cache Index Invalidate, pg. 353. +:iii as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b1111 & op0 = 0b0010 { + iii(as + zext(u10_16.23_sb2)); +} + +# IITLB - Invalidate Instruction TLB Entry, pg. 355. +:iitlb as is op2 = 0b0101 & op1 = 0 & ar = 0b0100 & as & at = 0 & op0 = 0 { + iitlb(as); +} + +# IIU - Instruction Cache Index Unlock, pg. 356. +:iiu as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0b0011 & ar = 0b0111 & as & at = 0b1101 & op0 = 0b0010 { + iiu(as + zext(u8_20.23_sb4)); +} + +# ILL - Illegal Instruction, pg. 358. +:ill is op2 = 0 & op1 = 0 & ar = 0 & as = 0 & at = 0 & op0 = 0 { + ill(); +} + +# ILL.N - Narrow Illegal Instruction, pg. 359. +:ill.n is n_ar = 0b1111 & n_as = 0 & n_at = 0b0110 & n_op0 = 0b1101 { + ill(); +} + +# IPF - Instruction Cache Prefetch, pg. 360. +:ipf as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b1100 & op0 = 0b0010 { + ipf(as + zext(u10_16.23_sb2)); +} + +# IPFL - Instruction Cache Prefetch and Lock, pg. 362. +:ipfl as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0 & ar = 0b0111 & as & at = 0b1101 & op0 = 0b0010 { + ipfl(as + zext(u8_20.23_sb4)); +} + +# ISYNC - Instruction Fetch Synchronize, pg. 364. +:isync is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0 & op0 = 0 { + isync(); +} + +# J - Unconditional Jump, pg. 366. +:j srel_6.23 is srel_6.23 & u2_4.5 = 0 & op0 = 0b0110 { + goto srel_6.23; +} + +# J.L is a macro. + +# RET (JX A0) - Non-Windowed Return, pg. 478. +:ret is op2 = 0 & op1 = 0 & ar = 0 & as = 0 & u2_6.7 = 0b10 & u2_4.5 = 0b10 & op0 = 0 { + return [a0]; +} + +# The manual suggests that RET is equivalent to JX A0, yet RET has bit 5 unset, JX doesn’t. +:ret is op2 = 0 & op1 = 0 & ar = 0 & as = 0 & u2_6.7 = 0b10 & u2_4.5 = 0b00 & op0 = 0 { + return [a0]; +} + +# JX - Uncoditional Jump Register, pg. 368. +:jx as is op2 = 0 & op1 = 0 & ar = 0 & as & u2_6.7 = 0b10 & u2_4.5 = 0b10 & op0 = 0 { + goto as; +} + +# L8UI - Load 8-bit Unsigned, pg. 369. +:l8ui at, as, u8_16.23 is u8_16.23 & ar = 0 & as & at & op0 = 0b0010 { + local addr:4 = as + zext(u8_16.23:1); + at = zext(*:1 addr); +} + +# L16SI - Load 16-bit Signed, pg. 370. +:l16si at, as, u9_16.23_sb1 is u9_16.23_sb1 & ar = 0b1001 & as & at & op0 = 0b0010 { + local addr:4 = as + zext(u9_16.23_sb1); + at = sext(*:2 addr); +} + +# L16UI - Load 16-bit Unsigned, pg. 372. +:l16ui at, as, u9_16.23_sb1 is u9_16.23_sb1 & ar = 0b001 & as & at & op0 = 0b0010 { + local addr:4 = as + zext(u9_16.23_sb1); + at = zext(*:2 addr); +} + +# L32AI - Load 32-bit Acquire, pg. 374. +:l32ai at, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b1011 & as & at & op0 = 0b0010 { + local addr:4 = as + zext(u10_16.23_sb2); + at = *:4 addr; + acquire(addr); +} + +# L32I - Load 32-bit, pg. 378. +:l32i at, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0010 & as & at & op0 = 0b0010 { + local addr:4 = as + zext(u10_16.23_sb2); + at = *:4 addr; +} + +# L32I.N - Narrow Load 32-bit, pg. 380. +:l32i.n n_at, n_as, n_u6_12.15_sb2 is n_u6_12.15_sb2 & n_as & n_at & n_op0 = 0b1000 { + local addr:4 = n_as + zext(n_u6_12.15_sb2); + n_at = *:4 addr; +} + +# L32R - Load 32-bit PC-relative, pg. 382. +:l32r at, srel_8.23_oex_sb2 is srel_8.23_oex_sb2 & at & op0 = 0b0001 { + at = srel_8.23_oex_sb2; +} + +# LDCT - Load Data Cache Tag, pg. 384. +:ldct at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0b1000 & as & at & op0 = 0 { + at = ldct(as); +} + +# LICT - Load Instruction Cache Tag, pg. 388. +:lict at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0 & as & at & op0 = 0 { + at = lict(as); +} + +# LICW - Load Instruction Cache Word, pg. 390. +:licw at, as is op2 = 0b1111 & op1 = 0b0010 & ar = 0 & as & at & op0 = 0 { + at = licw(as); +} + +# LSI - Load Single Immediate, pg. 398. +:lsi ft, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0 & as & ft & op0 = 0b0011 { + local addr:4 = as + zext(u10_16.23_sb2); + ft = *:4 addr; +} + +# LSIU - Load Single Immediate with Update, pg. 400. +:lsiu ft, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b1000 & as & ft & op0 = 0b0011 { + local addr:4 = as + zext(u10_16.23_sb2); + ft = *:4 addr; + as = addr; +} + +# LSX - Load Single Indexed, pg. 402. +:lsx fr, as, at is op2 = 0 & op1 = 0b1000 & fr & as & at & op0 = 0 { + local addr:4 = as+at; + fr = *:4 addr; +} + +# LSXU - Load Single Indexed with Update, pg. 404. +:lsxu fr, as, at is op2 = 0b0001 & op1 = 0b1000 & fr & as & at & op0 = 0 { + local addr:4 = as+at; + fr = *:4 addr; + as = addr; +} + +# MADD.S - Multiply and Add Single, pg. 406. +:madd.s fr, fs, ft is op2 = 0b0100 & op1 = 0b1010 & fr & fs & ft & op0 = 0 { + fr = fr f+ (fs f* ft); +} + +# MAX - Maximum Value, pg. 407. +:max ar, as, at is op2 = 0b0101 & op1 = 0b0011 & ar & as & at & op0 = 0 { + if (as s> at) + goto ; + ar = at; + goto inst_next; + + ar = as; +} + +# MAXU - Maximum Value Unsigned, pg. 408. +:maxu ar, as, at is op2 = 0b0111 & op1 = 0b0011 & ar & as & at & op0 = 0 { + if (as > at) + goto ; + ar = at; + goto inst_next; + + ar = as; +} + +# MEMW - Memory Wait, pg. 409. +:memw is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b1100 & op0 = 0 { + memw(); +} + +# MIN - Minimum Value, pg. 410. +:min ar, as, at is op2 = 0b0100 & op1 = 0b0011 & ar & as & at & op0 = 0 { + if (as s< at) + goto ; + ar = at; + goto inst_next; + + ar = as; +} + +# MINU - Minimum Value Unsigned, pg. 411. +:minu ar, as, at is op2 = 0b0110 & op1 = 0b0011 & ar & as & at & op0 = 0 { + if (as < at) + goto ; + ar = at; + goto inst_next; + + ar = as; +} + +# MOV.N - Narrow Move, pg. 413. +:mov.n n_at, n_as is n_ar = 0 & n_as & n_at & n_op0 = 0b1101 { + n_at = n_as; +} + +# MOV.S - Move Single, pg. 414. +:mov.s fr, fs is op2 = 0b1111 & op1 = 0b1010 & fr & fs & at = 0 & op0 = 0 { + fr = fs; +} + +# MOVEQZ - Move if Equal to Zero, pg. 415. +:moveqz ar, as, at is op2 = 0b1000 & op1 = 0b0011 & ar & as & at & op0 = 0 { + if (at != 0) + goto inst_next; + ar = as; +} + +# MOVEQZ.S - Move Single if Equal to Zero, pg. 416. +:moveqz.s fr, fs, at is op2 = 0b1000 & op1 = 0b1011 & fr & fs & at & op0 = 0 { + if (at != 0) + goto inst_next; + fr = fs; +} + +# MOVF - Move if False, pg. 417. +:movf ar, as, bt is op2 = 0b1100 & op1 = 0b0011 & ar & as & bt & op0 = 0 { + if (bt) + goto inst_next; + ar = as; +} + +# MOVF.S - Move Single if False, pg. 418. +:movf.s fr, fs, bt is op2 = 0b1100 & op1 = 0b1011 & fr & fs & bt & op0 = 0 { + if (bt) + goto inst_next; + fr = fs; +} + +# MOVGEZ - Move if Greater Than or Equal to Zero, pg. 419. +:movgez ar, as, at is op2 = 0b1011 & op1 = 0b0011 & ar & as & at & op0 = 0 { + if (at s< 0) + goto inst_next; + ar = as; +} + +# MOVGEZ.S - Move Single if Greater Than or Equal to Zero, pg. 420. +:movgez.s fr, fs, at is op2 = 0b1011 & op1 = 0b1011 & fr & fs & at & op0 = 0 { + if (at s< 0) + goto inst_next; + fr = fs; +} + +# MOVI - Move Immediate, pg. 421. +:movi at, s16_16.23_8.11 is s16_16.23_8.11 & ar = 0b1010 & at & op0 = 0b0010 { + local val:4 = sext(s16_16.23_8.11); + at = val; +} + + +# MOVI.N - Narrow Move Immediate, pg. 422. +:movi.n n_as, n_s8_12.15_4.6_asymm is n_s8_12.15_4.6_asymm & n_as & n_u1_7 = 0 & n_op0 = 0b1100 { + local val:4 = sext(n_s8_12.15_4.6_asymm); + n_as = val; +} + +# MOVLTZ - Move if Less Than Zero, pg. 423. +:movltz ar, as, at is op2 = 0b1010 & op1 = 0b0011 & ar & as & at & op0 = 0 { + if (at s>= 0) + goto inst_next; + ar = as; +} + +# MOVLTZ.S - Move Single if Less Than Zero, pg. 424. +:movltz.s fr, fs, at is op2 = 0b1010 & op1 = 0b1011 & fr & fs & at & op0 = 0 { + if (at s>= 0) + goto inst_next; + fr = fs; +} + +# MOVNEZ - Move if Not Equal to Zero, pg. 425. +:movnez ar, as, at is op2 = 0b1001 & op1 = 0b0011 & ar & as & at & op0 = 0 { + if (at == 0) + goto inst_next; + ar = as; +} + +# MOVNEZ.S - Move Single if Not Equal to Zero, pg. 426. +:movnez.s fr, fs, at is op2 = 0b1001 & op1 = 0b1011 & fr & fs & at & op0 = 0 { + if (at == 0) + goto inst_next; + fr = fs; +} + +# MOVT - Move if True, pg. 428. +:movt ar, as, bt is op2 = 0b1101 & op1 = 0b0011 & ar & as & bt & op0 = 0 { + if (!bt) + goto inst_next; + ar = as; +} + +# MOVT.S - Move Single if True, pg. 429. +:movt.s fr, fs, bt is op2 = 0b1101 & op1 = 0b1011 & fr & fs & bt & op0 = 0 { + if (!bt) + goto inst_next; + fr = fs; +} + +# MSUB.S - Multiply and Subtract Single, pg. 430. +:msub.s fr, fs, ft is op2 = 0b0101 & op1 = 0b1010 & fr & fs & ft & op0 = 0 { + fr = fr f- (fs f* ft); +} + +# MUL.S - Multiply Single, pg. 435. +:mul.s fr, fs, ft is op2 = 0b0010 & op1 = 0b1010 & fr & fs & ft & op0 = 0 { + fr = fs f* ft; +} + +# MUL16S - Multiply 16-bit Signed, pg. 436. +:mul16s ar, as, at is op2 = 0b1101 & op1 = 0b0001 & ar & as & at & op0 = 0 { + ar = sext(as:2) * sext(at:2); +} + +# MUL16U - Multiply 16-bit Unsigned, pg. 437. +:mul16u ar, as, at is op2 = 0b1100 & op1 = 0b0001 & ar & as & at & op0 = 0 { + ar = zext(as:2) * zext(at:2); +} + +# MULL - Multiply Low, pg. 450. +:mull ar, as, at is op2 = 0b1000 & op1 = 0b0010 & ar & as & at & op0 = 0 { + ar = as * at; +} + +# MULSH - Multiply Signed High, pg. 455. +:mulsh ar, as, at is op2 = 0b1011 & op1 = 0b0010 & ar & as & at & op0 = 0 { + local s64:8 = sext(as); + local t64:8 = sext(at); + local p:8 = (s64 * t64); + ar = p(4); +} + +# MULUH - Multiply Unsigned High, pg. 456. +:muluh ar, as, at is op2 = 0b1010 & op1 = 0b0010 & ar & as & at & op0 = 0 { + local s64:8 = zext(as); + local t64:8 = zext(at); + local p:8 = (s64 * t64); + ar = p(4); +} + +# NEG - Negate, pg. 457. +:neg ar, at is op2 = 0b0110 & op1 = 0 & ar & as = 0 & at & op0 = 0 { + ar = -at; +} + +# NEG.S - Negate Single, pg. 458. +:neg.s fr, fs is op2 = 0b1111 & op1 = 0b1010 & fr & fs & at = 0b0110 & op0 = 0 { + fr = f- fs; +} + +# NOP - No Operation, pg. 459. +:nop is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b1111 & op0 = 0 { } + +# NOP.N - Narrow No Operation, pg. 460. +:nop.n is n_ar = 0b1111 & n_as = 0 & n_at = 0b0011 & n_op0 = 0b1101 { } + +# NSA - Normalization Shift Amount, pg. 461. +:nsa at, as is op2 = 0b0100 & op1 = 0 & ar = 0b1110 & as & at & op0 = 0 { + # https://stackoverflow.com/questions/54772520/normalizing-a-two-complement-number + at = nsa(as); +} + +# NSAU - Normalization Shift Amount Unsigned, pg. 462. (Count leading zeros) +:nsau at, as is op2 = 0b0100 & op1 = 0 & ar = 0b1111 & as & at & op0 = 0 { + at = nsau(as); +} + +# OEQ.S - Compare Single Equal, pg. 463. +:oeq.s br, fs, ft is op2 = 0b0010 & op1 = 0b1011 & br & fs & ft & op0 = 0 { + br = !nan(fs) && !nan(ft) && fs f== ft; +} + +# OLE.S - Compare Single Ordered and Less Than or Equal, pg. 464 +:ole.s br, fs, ft is op2 = 0b0110 & op1 = 0b1011 & br & fs & ft & op0 = 0 { + br = !nan(fs) && !nan(ft) && fs f<= ft; +} + +# OLT.S - Compare Single Ordered and Less Than, pg. 465. +:olt.s br, fs, ft is op2 = 0b0100 & op1 = 0b1011 & br & fs & ft & op0 = 0 { + br = !nan(fs) && !nan(ft) && fs f< ft; +} + +# MOV - Move, pg. 412. Special case of OR as, at, at. +:mov ar, as is op2 = 0b0010 & op1 = 0 & ar & as & as = at & op0 = 0 { + ar = as; +} + +# OR - Bitwise Logical Or, pg. 466. +:or ar, as, at is op2 = 0b0010 & op1 = 0 & ar & as & at & op0 = 0 { + ar = as | at; +} + +# ORB - Boolean Or, pg. 467. +:orb br, bs, bt is op2 = 0b0010 & op1 = 0b0010 & br & bs & bt & op0 = 0 { + br = bs || bt; +} + +# ORBC - Boolean Or with Complement, pg. 468. +:orbc br, bs, bt is op2 = 0b0011 & op1 = 0b0010 & br & bs & bt & op0 = 0 { + br = bs || !bt; +} + +# PDTLB - Probe Data TLB, pg. 469. +:pdtlb at, as is op2 = 0b0101 & op1 = 0 & ar = 0b1101 & as & at & op0 = 0 { + at = pdtlb(as); +} + +# PITLB - Probe Instruction TLB, pg. 470. +:pitlb at, as is op2 = 0b0101 & op1 = 0 & ar = 0b0101 & as & at & op0 = 0 { + at = pitlb(as); +} + +# QUOS - Quotient Signed, pg. 471. +:quos ar, as, at is op2 = 0b1101 & op1 = 0b0010 & ar & as & at & op0 = 0 { + ar = as s/ at; +} + +# QUOU - Quotient Unsigned, pg. 472. +:quou ar, as, at is op2 = 0b1100 & op1 = 0b0010 & ar & as & at & op0 = 0 { + ar = as / at; +} + +# RDTLB0 - Read Data TLB Virtual Entry, pg. 473. +:rdtlb0 at, as is op2 = 0b0101 & op1 = 0 & ar = 0b1011 & as & at & op0 = 0 { + at = rdtlb0(as); +} + +# RDTLB1 - Read Data TLB Entry Translation, pg. 474. +:rdtlb1 at, as is op2 = 0b0101 & op1 = 0 & ar = 0b1111 & as & at & op0 = 0 { + at = rdtlb1(as); +} + +# REMS - Remainder Signed, pg. 475. +:rems ar, as, at, is op2 = 0b1111 & op1 = 0b0010 & ar & as & at & op0 = 0 { + ar = as s% at; +} + +# REMU - Remainder Unsigned, pg. 476. +:remu ar, as, at, is op2 = 0b1110 & op1 = 0b0010 & ar & as & at & op0 = 0 { + ar = as % at; +} + +# RER - Read External Register, pg. 477. +:rer as, at is op2 = 0b0100 & op1 = 0 & ar = 0b0110 & as & at & op0 = 0 { + as = rer(at); +} + +# RET.N - Narrow Non-Windowed Return, pg. 479. +:ret.n is n_ar = 0b1111 & n_as = 0 & n_at = 0 & n_op0 = 0b1101 { + return [a0]; +} + +# RFDD - Return from Debug and Dispatch, pg. 484. +:rfdd is op2 = 0b1111 & op1 = 0b0001 & ar = 0b1110 & (as = 0b0000 | as = 0b0001) & at = 0b0001 & op0 = 0 { + rfdd(); +} + +# RFDE _ Return From Double Exception, pg. 485. +:rfde is op2 = 0 & op1 = 0 & ar = 0b0011 & as =0b0010 & at = 0 & op0 = 0 { + rfde(); +} + +# RFDO - Return from Debug Operation, pg. 486. +:rfdo is op2 = 0b1111 & op1 = 0b0001 & ar = 0b1110 & as = 0 & at = 0 & op0 = 0 { + rfdo(); +} + +# RFE - Return From Exception, pg. 487. +:rfe is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0 & at = 0 & op0 = 0 { + rfe(); +} + +# RFI - Return from High-Priority Interrupt, pg. 488. +:rfi u4_8.11 is op2 = 0 & op1 = 0 & ar = 0b0011 & u4_8.11 & at = 0b0001 & op0 = 0 { + rfi(u4_8.11:1); +} + +# RFME - Return from Memory Error, pg. 489. +:rfme is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0 & at = 0b0010 & op0 = 0 { + rfme(); +} + +# RFR - Move FR to AR, pg. 490. +:rfr ar, fs is op2 = 0b1111 & op1 = 0b1010 & ar & fs & at = 0b0100 & op0 = 0 { + ar = fs; +} + +# RFUE - Return from User-Mode Exception, pg. 491. +:rfue is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0b0001 & at = 0 & op0 = 0 { + rfue(); +} + +# RFWO - Return from Window Overflow, pg. 492. +:rfwo is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0b0100 & at = 0 & op0 = 0 { + rfwo(); +} + +# RFWU - Return from Window Underflow, pg. 493. +:rfwu is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0b0101 & at = 0 & op0 = 0 { + rfwu(); +} + +# RITLB0 - Read Instruction TLB Virtual Entry, pg. 494. +:ritlb0 at, as is op2 = 0b0101 & op1 = 0 & ar = 0b0011 & as & at & op0 = 0 { + at = ritlb0(as); +} + +# RITLB1 - Read Instruction TLB Entry Translation, pg. 495. +:ritlb1 at, as is op2 = 0b0101 & op1 = 0 & ar = 0b0111 & as & at & op0 = 0 { + at = ritlb1(as); +} + +# ROUND.S - Round Single to Fixed, pg. 497. +:round.s ar, fs, u4_4.7 is op2 = 0b1000 & op1 = 0b1010 & ar & fs & u4_4.7 & op0 = 0 { + local scale:4 = int2float(1:2 << u4_4.7:2); + ar = round(fs f* scale); +} + +# RSIL - Read and Set Interrupt Level, pg. 498. +:rsil at, u4_8.11 is op2 = 0 & op1 = 0 & ar = 0b0110 & u4_8.11 & at & op0 = 0 { + at = rsil(u4_8.11:1); +} + +# RSR - Read Special Register, pg. 500. +:rsr at, u8_8.15 is op0 = 0 & op1 = 0b0011 & u8_8.15 & at & op0 = 0 { + at = rsr(u8_8.15:1); +} + +# RSYNC - Register Read Synchronize, pg. 502. +:rsync is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b0001 & op0 = 0 { + rsync(); +} + +# RUR - Read User Register, pg. 503. +:rur ar, u8_4.11 is op2 = 0b1110 & op1 = 0b0011 & ar & u8_4.11 & op0 = 0 { + ar = rur(u8_4.11:1); +} + +# S8I - Store 8-bit, pg. 504. +:s8i at, as, u8_16.23 is u8_16.23 & ar = 0b0100 & as & at & op0 = 0b0010 { + local addr:4 = as + zext(u8_16.23:1); + *:1 addr = at:1; +} + +# S16I - Store 16-bit, pg. 505. +:s16i at, as, u9_16.23_sb1 is u9_16.23_sb1 & ar = 0b0101 & as & at & op0 = 0b0010 { + local addr:4 = as + zext(u9_16.23_sb1); + *:2 addr = at:2; +} + +# S32C1I - Store 32-bit Compare Conditional, pg. 506 +:s32c1i at, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b1110 & as & at & op0 = 0b0010 { + local addr:4 = as + zext(u10_16.23_sb2); + at = s32c1i(addr); +} + +# S32I - Store 32-bit, pg. 510. +:s32i at, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0110 & as & at & op0 = 0b0010 { + local addr:4 = as + zext(u10_16.23_sb2); + *:4 addr = at; +} + +# S32I.N - Narrow Store 32-bit, pg. 512. +:s32i.n n_at, n_as, n_u6_12.15_sb2 is n_u6_12.15_sb2 & n_as & n_at & n_op0 = 0b1001 { + local addr:4 = n_as + zext(n_u6_12.15_sb2); + *:4 addr = n_at; +} + +# S32RI - Store 32-bit Release, pg. 514. +:s32ri at, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b1111 & as & at & op0 = 0b0010 { + local addr:4 = as + zext(u10_16.23_sb2); + *:4 addr = at; + release(addr); +} + +# SDCT - Store Data Cache Tag, pg. 516. +:sdct at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0b1001 & as & at & op0 = 0 { + sdct(as, at); +} + +# SEXT - Sign Extend, pg. 518. +:sext ar, as, u5_4.7_plus7 is op2 = 0b0010 & op1 = 0b0011 & ar & as & u5_4.7_plus7 & op0 = 0 { + local shift:1 = 31:1 - u5_4.7_plus7; + local tmp:4 = as << shift; + ar = tmp s>> shift; +} + +# SICT - Store Instruction Cache Tag, pg. 519. +:sict at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0b0001 & as & at & op0 = 0 { + sict(as, at); +} + +# SICW - Store Instruction Cache word, pg. 521. +:sicw at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0b0011 & as & at & op0 = 0 { + sicw(as, at); +} + +# SIMCALL - Simulator Call, pg. 523. +:simcall is op2 = 0 & op1 = 0 & ar = 0b0101 & as = 0b0001 & at = 0 & op0 = 0 { + simcall(); +} + +# SLL - Shift Left Logical, pg. 524. +:sll ar, as is op2 = 0b1010 & op1 = 0b0001 & ar & as & at = 0 & op0 = 0 { + local sa:1 = 32 - (sar & 0xf); # XXX check this + ar = as << sa; +} + +# SLLI - Shift Left Logical Immediate, pg. 525. +:slli ar, as, u5_4.7_20 is u3_21.23 = 0 & u5_4.7_20 & op1 = 0b0001 & ar & as & op0 = 0 { + local sa:1 = 32 - u5_4.7_20; # XXX check this + ar = as << sa; +} + +# SRA - Shift Right Arithmetic, pg. 526. +:sra ar, at is op2 = 0b1011 & op1 = 0b0001 & ar & as = 0 & at & op0 = 0 { + ar = at s>> sar; +} + +# SRAI - Shift Right Arithmetic Immediate, pg. 527. +:srai ar, at, u5_8.11_20 is u3_21.23 = 0b001 & u5_8.11_20 & op1 = 0b0001 & ar & at & op0 = 0 { + ar = at s>> u5_8.11_20; +} + +# SRC - Shift Right Combined, pg. 528. +:src ar, as, at is op2 = 0b1000 & op1 = 0b0001 & ar & as & at & op0 = 0 { + local s64:8 = zext(as); + local t64:8 = zext(at); + local combined:8 = (s64 << 32) | t64; + local shifted:8 = combined >> sar; + ar = shifted:4; +} + +# SRL - Shift Right Logical, pg. 529. +:srl ar, at is op2 = 0b1001 & op1 = 0b0001 & ar & as = 0 & at & op0 = 0 { + ar = at >> sar; +} + +# SRLI - Shift Right Logical Immediate, pg. 530. +:srli ar, at, u4_8.11 is op2 = 0b0100 & op1 = 0b0001 & ar & u4_8.11 & at & op0 = 0 { + ar = at >> u4_8.11; +} + +# SSA8B - Set Shift Amount for BE Byte Shift, pg. 531. +:ssa8b as is op2 = 0b0100 & op1 = 0 & ar = 0b0011 & as & at = 0 & op0 = 0 { + local lsa:4 = (as&3)*8; + sar = 32 - lsa:1; +} + +# SSA8L - Set Shift Amount for LE Byte Shift, pg. 532. +:ssa8l as is op2 = 0b0100 & op1 = 0 & ar = 0b0010 & as & at = 0 & op0 = 0 { + local rsa:4 = (as&3)*8; + sar = rsa:1; +} + +# SSAI - Set Shift Amount Immediate, pg. 533. +:ssai u5_8.11_4 is op2 = 0b0100 & op1 = 0 & ar = 0b0100 & u5_8.11_4 & u3_5.7 = 0 & op0 = 0 { + sar = u5_8.11_4:1; +} + +# SSI - Store Single Immediate, pg. 534. +:ssi ft, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0100 & as & ft & op0 = 0b0011 { + local addr:4 = as + zext(u10_16.23_sb2); + *:4 addr = ft; +} + +# SSIU - Store Single Immediate with Update, pg. 536. +:ssiu ft, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b1100 & as & ft & op0 = 0b0011 { + local addr:4 = as + zext(u10_16.23_sb2); + *:4 addr = ft; + as = addr; +} + +# SSL - Set Shift Amount for Left Shift, pg. 538. +:ssl as is op2 = 0b0100 & op1 = 0 & ar = 0b0001 & as & at = 0 & op0 = 0 { + sar = 32 - (as:1 & 0xf); +} + +# SSR - Set Shift Amount for Right Shift, pg. 539. +:ssr as is op2 = 0b0100 & op1 = 0 & ar = 0 & as & at = 0 & op0 = 0 { + sar = (as:1 & 0xf); +} + +# SSX - Store Singe Indexed, pg. 540. +:ssx fr, as, at is op2 = 0b0100 & op1 = 0b1000 & fr & as & at & op0 = 0 { + local addr:4 = as+at; + *:4 addr = fr; +} + +# SSXU - Store Singe Indexed with Update, pg. 541. +:ssxu fr, as, at is op2 = 0b0101 & op1 = 0b1000 & fr & as & at & op0 = 0 { + local addr:4 = as+at; + *:4 addr = fr; + as = addr; +} + +# SUB - Subtract, pg. 542. +:sub ar, as, at is op2 = 0b1100 & op1 = 0 & ar & as & at & op0 = 0 { + ar = as - at; +} + +# SUB.S - Subtract Single, pg. 543. +:sub.s fr, fs, ft is op2 = 0b0001 & op1 = 0b1010 & fr & fs & ft & op0 = 0 { + fr = fs f- ft; +} + +# SUBX2 - Subtract with Shift by 1, pg. 544. +:subx2 ar, as, at is op2 = 0b1101 & op1 = 0 & ar & as & at & op0 = 0 { + ar = (as << 1) - at; +} + +# SUBX4 - Subtract with Shift by 2, pg. 545. +:subx4 ar, as, at is op2 = 0b1110 & op1 = 0 & ar & as & at & op0 = 0 { + ar = (as << 2) - at; +} + +# SUBX8 - Subtract with Shift by 3, pg. 546. +:subx8 ar, as, at is op2 = 0b1111 & op1 = 0 & ar & as & at & op0 = 0 { + ar = (as << 3) - at; +} + +# SYSCALL - System Call, pg. 547. +:syscall is op2 = 0 & op1 = 0 & ar = 0b0101 & as = 0 & at = 0 & op0 = 0 { + syscall(); +} + +# TRUNC.S - Truncate Single to Fixed, pg. 548 +:trunc.s ar, fs, u4_4.7 is op2 = 0b1001 & op1 = 0b1010 & ar & fs & u4_4.7 & op0 = 0 { + local scale:4 = int2float(1:2 << u4_4.7:2); + ar = trunc(fs f* scale); +} + +# UEQ.S - Compare Single Unordered or Equal, pg. 549. +:ueq.s br, fs, ft is op2 = 0b0011 & op1 = 0b1011 & br & fs & ft & op0 = 0 { + br = nan(fs) || nan(ft) || fs f== ft; +} + +# UFLOAT.S - Convert Unsigned Fixed to Single, pg. 550. XXX: How is this different from float.as? +:ufloat.s fr, as, u4_4.7 is op2 = 0b1101 & op1 = 0b1010 & fr & as & u4_4.7 & op0 = 0 { + local f = int2float(as); + local d = int2float(1:2 << u4_4.7:2); + fr = d f/ f; +} + +# ULE.S - Compare Single Unordered or Less Than or Equal, pg. 551. +:ule.s br, fs, ft is op2 = 0b0111 & op1 = 0b1011 & br & fs & ft & op0 = 0 { + br = nan(fs) || nan(ft) || fs f<= ft; +} + +# ULT.S - Compare Single Unordered or Less Than, pg. 552. +:ult.s br, fs, ft is op2 = 0b0101 & op1 = 0b1011 & br & fs & ft & op0 = 0 { + br = nan(fs) || nan(ft) || fs f< ft; +} + +# FIXME: UMUL.AA* + +# UN.S - Compare Single Unordered, pg. 554. +:un.s br, fs, ft is op2 = 0b0001 & op1 = 0b1011 & br & fs & ft & op0 = 0 { + br = nan(fs) || nan(ft); +} + +# UTRUNC.S - Truncate Single to Fixed Unsigned, pg. 555. FIXME: difference to trunc.s? +:utrunc.s ar, fs, u4_4.7 is op2 = 0b1110 & op1 = 0b1010 & ar & fs & u4_4.7 & op0 = 0 { + local scale:4 = int2float(1:2 << u4_4.7:2); + ar = trunc(fs f* scale); +} + +# WAITI - Wait Interrupt, pg. 556. +:waiti u4_8.11 is op2 = 0 & op1 = 0 & ar = 0b0111 & u4_8.11 & at = 0 & op0 = 0 { + waiti(u4_8.11:4); +} + +# WDTLB - Write Data TLB Entry, pg. 557. +:wdtlb at, as is op2 = 0b0101 & op1 = 0 & ar = 0b1110 & as & at & op0 = 0 { + wdtlb(as, at); +} + +# WER - Write External Register, pg. 558. +:wer as, at is op2 = 0b0100 & op1 = 0 & ar = 0b0111 & as & at & op0 = 0 { + wer(as, at); +} + +# WFR - Move AR to FR, pg. 559. +:wfr fr, as is op2 = 0b1111 & op1 = 0b1010 & fr & as & at = 0b0101 & op0 = 0 { + fr = as; +} + +# WITLB - Write Instruction TLB Entry, pg. 560. +:witlb at, as is op2 = 0b0101 & op1 = 0 & ar = 0b0110 & as & at & op0 = 0 { + witlb(as, at); +} + +# WSR - Write Special Register, pg. 561. +:wsr at, u8_8.15 is op2 = 0b0001 & op1 = 0b0011 & u8_8.15 & at & op0 = 0 { + wsr(u8_8.15:1, at); +} + +# WUR - Write User Register, pg. 563. +:wur at, u8_8.15 is op2 = 0b1111 & op1 = 0b0011 & u8_8.15 & at & op0 = 0 { + wur(u8_8.15:1, at); +} + +# XOR - Bitwise Exclusive Or, pg. 564. +:xor ar, as, at is op2 = 0b0011 & op1 = 0 & ar & as & at & op0 = 0 { + ar = as ^ at; +} + +# XORB - Boolean Exclusive Or, pg. 565. +:xorb br, bs, bt is op2 = 0b0100 & op1 = 0b0010 & br & bs & bt & op0 = 0 { + br = bs ^^ bt; +} + +# XSR - Exchange Special Register, pg. 566. +:xsr at, u8_8.15 is op2 = 0b1110 & op1 = 0b0001 & u8_8.15 & at & op0 = 0 { + at = xsr(u8_8.15:1, at); +} diff --git a/data/languages/xtensaTodo.sinc b/data/languages/xtensaTodo.sinc new file mode 100644 index 0000000..b89eea5 --- /dev/null +++ b/data/languages/xtensaTodo.sinc @@ -0,0 +1,66 @@ +## Windowed Register Option ## + +# CALL4 - Call PC-relative, Rotate Window by 4, pg. 298. +:call4 srel_6.23_sb2 is srel_6.23_sb2 & u2_4.5 = 0b01 & op0 = 0b0101 unimpl + +# CALL8 - Call PC-relative, Rotate Window by 8, pg. 300. +:call8 srel_6.23_sb2 is srel_6.23_sb2 & u2_4.5 = 0b10 & op0 = 0b0101 unimpl + +# CALL12 - Call PC-relative, Rotate Window by 12, pg. 302. +:call12 srel_6.23_sb2 is srel_6.23_sb2 & u2_4.5 = 0b11 & op0 = 0b0101 unimpl + +# CALLX4 - Call Register, Rotate Window by 4, pg. 305. +:callx4 as is op2 = 0 & op1 = 0 & ar = 0 & as & u2_6.7 = 0b11 & u2_4.5 = 0b01 & op0 = 0 unimpl + +# CALLX8 - Call Register, Rotate Window by 8, pg. 307. +:callx8 as is op2 = 0 & op1 = 0 & ar = 0 & as & u2_6.7 = 0b11 & u2_4.5 = 0b10 & op0 = 0 unimpl + +# CALLX12 - Call Register, Rotate Window by 12, pg. 308. +:callx12 as is op2 = 0 & op1 = 0 & ar = 0 & as & u2_6.7 = 0b11 & u2_4.5 = 0b11 & op0 = 0 unimpl + +# ENTRY - Subroutine Entry, pg. 340. +:entry as, u15_12.23_sb3 is u15_12.23_sb3 & as & u2_6.7 = 0b00 & u2_4.5 = 0b11 & op0 = 0b0110 unimpl + +# L32E - Load 32-bit for Window Exceptions, pg. 376. +:l32e at, as, s5_12.15_oex is op2 = 0 & op1 = 0b1001 & s5_12.15_oex & as & at & op0 = 0 unimpl + +# MOVSP - Move to Stack Pointer, pg. 427. +:movsp at, as is op2 = 0 & op1 = 0 & ar = 0b0001 & as & at & op0 = 0 unimpl + +# RETW - Windowed Return, pg. 480. +:retw is op2 = 0 & ar = 0 & as = 0 & at = 0 & u2_18.19 = 0b10 & u2_16.17 = 0b01 & op0 = 0 unimpl + +# RETW.N - Narrow Windowed Return, pg. 482. +:retw.n is n_ar = 0b1111 & n_as = 0 & n_at = 0b0001 & n_op0 = 0b1101 unimpl + +# ROTW - Rotate Window, pg. 496. +:rotw s4_4.7 is op2 = 0b0100 & op1 = 0 & ar = 0b1000 & as = 0 & s4_4.7 & op0 = 0 unimpl + +# S32E - Store 32-bit for Window Exceptions, pg. 508. +:s32e at, as, s5_12.15_oex is op2 = 0b0100 & op1 = 0b1001 & s5_12.15_oex & as & at & op0 = 0 unimpl + + +## MAC16 option ## + +# LDDEC - Load with Autodecrement, pg. 386. +:lddec "MAC16_REGS[" u2_12.13 "]", as is op2 = 0b1001 & op1 = 0 & u2_14.15 = 0 & u2_12.13 & as & at = 0 & op0 = 0b0100 unimpl + +# LDINC - Load with Autoincrement, pg. 387. +:ldinc "MAC16_REGS[" u2_12.13 "]", as is op2 = 0b1000 & op1 = 0 & u2_14.15 = 0 & u2_12.13 & as & at = 0 & op0 = 0b0100 unimpl + +# MULA.AA.* - Signed Multiply, pg. 431. +:mula.aa.* as, at is op2 = 0b0001 & u2_18.19 = 0b01 & ar = 0 & as & at & op0 = 0b0100 unimpl + +# FIXME: Add remaining MUL.* opcodes. + + +## Loop Option ## + +# LOOP - Loop, pg. 392. +:loop as, urel_16.23 is urel_16.23 & ar = 0b1000 & as & at = 0b0111 & op0 = 0b0110 unimpl + +# LOOPGTZ - Loop if Greater Than Zero, pg. 394. +:loopgtz as, urel_16.23 is urel_16.23 & ar = 0b1010 & as & at = 0b0111 & op0 = 0b0110 unimpl + +# LOOPNEZ - Loop if Not Equal Zero, pg. 396. +:loopnez as, urel_16.23 is urel_16.23 & ar = 0b1001 & as & at = 0b0111 & op0 = 0b0110 unimpl diff --git a/mkindex.pl b/mkindex.pl new file mode 100644 index 0000000..dfd24b2 --- /dev/null +++ b/mkindex.pl @@ -0,0 +1,20 @@ +use strict; +use warnings; + +use constant PAGEOFFSET => 24; + +print "\@xtensa.pdf[Xtensa® Instruction Set Architecture (ISA) Reference Manual, April 2010]\n\n"; + +my $last; + +while (<>) { + if (/^# (\S+) .*?pg\. (\d+)/) { + my ($o, $p) = (lc $1, $2+PAGEOFFSET); + print "$o, $p\n"; + $last = $o; + } + + if (/^:(\S+)/ && $last && $last ne $1) { + warn "Constructor for opcode $1 is preceded by comment for $last"; + } +} diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000..66806a9 Binary files /dev/null and b/screenshot.png differ