diff options
Diffstat (limited to 'src/instruction')
-rw-r--r-- | src/instruction/decode_arm.rs | 201 | ||||
-rw-r--r-- | src/instruction/decode_thumb.rs | 267 |
2 files changed, 468 insertions, 0 deletions
diff --git a/src/instruction/decode_arm.rs b/src/instruction/decode_arm.rs new file mode 100644 index 0000000..9efe859 --- /dev/null +++ b/src/instruction/decode_arm.rs @@ -0,0 +1,201 @@ +/* + Copyright 2021-2023 Gabriel Jensen. + + This file is part of Luma. + + Luma is free software: you can redistribute it + and/or modify it under the terms of the GNU + Affero General Public License as published by + the Free Software Foundation, either version 3 + of the License, or (at your option) any later + version. + + Luma is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU + Affero General Public License along with Luma. + If not, see <https://www.gnu.org/licenses/>. +*/ + +use crate::instruction::Instruction; +use crate::predicate::Predicate; +use crate::shifter::Shifter; + +use std::hint::unreachable_unchecked; + +impl Instruction { + #[must_use] + pub fn decode_arm(opcode: u32) -> (Self, Predicate) { + use Instruction::*; + use Predicate::*; + + let predicate = (opcode & 0b11110000000000000000000000000000).wrapping_shr(0x1C) as u8; + let predicate = Predicate::from_raw(predicate); + + return match (opcode & 0b00001110000000000000000000000000).wrapping_shr(0x19) { + 0b000 => { + match (opcode & 0b00000000000000000000000000010000).wrapping_shr(0x4) { + 0b0 => { + let rd = (opcode & 0b00000000000000001111000000000000).wrapping_shr(0xC) as u8; + let rn = (opcode & 0b00000000000011110000000000000000).wrapping_shr(0x10) as u8; + let s = opcode & 0b00000000000100000000000000000000 != 0x0; + + let shifter = Shifter::extract(opcode); + + match (opcode & 0b00000001111000000000000000000000).wrapping_shr(0x15) { + 0b0000 => (And(rd, rn, shifter, s), predicate), + 0b0001 => (Eor(rd, rn, shifter, s), predicate), + 0b0010 => (Sub(rd, rn, shifter,s), predicate), + 0b0011 => (Rsb(rd, rn, shifter, s), predicate), + 0b0100 => (Add(rd, rn, shifter, s), predicate), + 0b0101 => (Adc(rd, rn, shifter, s), predicate), + 0b0110 => (Sbc(rd, rn, shifter, s), predicate), + 0b0111 => (Rsc(rd, rn, shifter, s), predicate), + 0b1000 => (Tst(rd, shifter), predicate), + 0b1001 => (Teq(rd, shifter), predicate), + 0b1010 => (Cmp(rd, shifter), predicate), + 0b1011 => (Cmn(rd, shifter), predicate), + 0b1100 => (Orr(rd, rn, shifter, s), predicate), + 0b1101 => (Mov(rd, shifter, s), predicate), + 0b1110 => (Bic(rd, rn, shifter, s), predicate), + 0b1111 => (Mvn(rd, shifter, s), predicate), + + _ => unsafe { unreachable_unchecked() }, + } + }, + + 0b1 => { + match (opcode & 0b00000000000000000000000010000000).wrapping_shr(0x7) { + 0b0 => { + match opcode & 0b00000001100100000000000000000000 { + 0b00000001000000000000000000000000 => { + let rm = (opcode & 0b00000000000000000000000000001111) as u8; + + match (opcode & 0b00000000011000000000000000000000).wrapping_shr(0x13) | (opcode & 0b00000000000000000000000001100000).wrapping_shr(0x5) { + 0b0000 => (Undefined, Al), + 0b0001 => (Undefined, Al), + 0b0010 => (Undefined, Al), + 0b0011 => (Undefined, Al), + 0b0100 => (Bx(rm), predicate), + 0b0101 => (Undefined, Al), + 0b0110 => (Undefined, Al), + 0b0111 => (Undefined, Al), + 0b1000 => (Undefined, Al), + 0b1001 => (Undefined, Al), + 0b1010 => (Undefined, Al), + 0b1011 => (Undefined, Al), + 0b1100 => (Undefined, Al), + 0b1101 => (Undefined, Al), + 0b1110 => (Undefined, Al), + 0b1111 => (Undefined, Al), + + _ => unsafe { unreachable_unchecked() }, + } + }, + + _ => (Undefined, Al), + } + }, + + 0b1 => (Undefined, Al), + + _ => unsafe { unreachable_unchecked() }, + } + }, + + _ => unsafe { unreachable_unchecked() }, + } + }, + + 0b001 => { + let rd = (opcode & 0b00000000000000001111000000000000).wrapping_shr(0xC) as u8; + let rn = (opcode & 0b00000000000011110000000000000000).wrapping_shr(0x10) as u8; + let s = opcode & 0b00000000000100000000000000000000 != 0x0; + + let shifter = Shifter::extract(opcode); + + match (opcode & 0b00000001111000000000000000000000).wrapping_shr(0x15) { + 0b0000 => (And(rd, rn, shifter, s), predicate), + 0b0001 => (Eor(rd, rn, shifter, s), predicate), + 0b0010 => (Sub(rd, rn, shifter, s), predicate), + 0b0011 => (Rsb(rd, rn, shifter, s), predicate), + 0b0100 => (Add(rd, rn, shifter, s), predicate), + 0b0101 => (Adc(rd, rn, shifter, s), predicate), + 0b0110 => (Sbc(rd, rn, shifter, s), predicate), + 0b0111 => (Rsc(rd, rn, shifter, s), predicate), + 0b1000 => (Tst(rn, shifter), predicate), + 0b1001 => (Teq(rn, shifter), predicate), + 0b1010 => (Cmp(rn, shifter), predicate), + 0b1011 => (Cmn(rn, shifter), predicate), + 0b1100 => (Orr(rd, rn, shifter, s), predicate), + 0b1101 => (Mov(rd, shifter, s), predicate), + 0b1110 => (Bic(rd, rn, shifter, s), predicate), + 0b1111 => (Mvn(rd, shifter, s), predicate), + + _ => unsafe { unreachable_unchecked() }, + } + }, + + 0b010 => { + let imm = (opcode & 0b00000000000000000000111111111111) as u16; + + let register = (opcode & 0b00000000000000001111000000000000).wrapping_shr(0xC) as u8; + + let base = (opcode & 0b00000000000011110000000000000000).wrapping_shr(0x10) as u8; + + let l = opcode & 0b00000000000100000000000000000000 != 0x0; + let _w = opcode & 0b00000000001000000000000000000000 != 0x0; + let _b = opcode & 0b00000000010000000000000000000000 != 0x0; + let u = opcode & 0b00000000100000000000000000000000 != 0x0; + let _p = opcode & 0b00000001000000000000000000000000 != 0x0; + + let imm = match u { + false => 0x0 - imm as i16, + true => imm as i16, + }; + + match l { + false => (StoreImmediateOffset(register, base, imm), predicate), + true => (LoadImmediateOffset( register, base, imm), predicate), + } + }, + + 0b011 => (Undefined, Al), + + 0b100 => (Undefined, Al), + + 0b101 => { + let offset = opcode & 0b00000000111111111111111111111111; + let offset = (offset << 0x8) as i32 >> 0x6; + + let l = opcode & 0b00000001000000000000000000000000 != 0x0; + + match l { + false => (B(offset), predicate), + true => (Bl(offset), predicate), + } + }, + + 0b110 => (Undefined, Al), + + 0b111 => { + match (opcode & 0b00000001000000000000000000000000).wrapping_shr(0x18) { + 0b0 => (Undefined, Al), + + 0b1 => { + let imm = opcode & 0b00000000111111111111111111111111; + (Swi(imm), predicate) + }, + + _ => unsafe { unreachable_unchecked() }, + } + }, + + _ => unsafe { unreachable_unchecked() }, + }; + } +} diff --git a/src/instruction/decode_thumb.rs b/src/instruction/decode_thumb.rs new file mode 100644 index 0000000..5735367 --- /dev/null +++ b/src/instruction/decode_thumb.rs @@ -0,0 +1,267 @@ +/* + Copyright 2021-2023 Gabriel Jensen. + + This file is part of Luma. + + Luma is free software: you can redistribute it + and/or modify it under the terms of the GNU + Affero General Public License as published by + the Free Software Foundation, either version 3 + of the License, or (at your option) any later + version. + + Luma is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU + Affero General Public License along with Luma. + If not, see <https://www.gnu.org/licenses/>. +*/ + +use crate::instruction::Instruction; +use crate::predicate::Predicate; +use crate::shifter::Shifter; + +use std::hint::unreachable_unchecked; + +impl Instruction { + pub fn decode_thumb(opcode: u16) -> (Self, Predicate) { + use Instruction::*; + use Predicate::*; + use Shifter::*; + + return match (opcode & 0b1110000000000000).wrapping_shr(0xD) { + 0b000 => { + match (opcode & 0b0001100000000000).wrapping_shr(0xB) { + 0b11 => { + match (opcode & 0b0000010000000000).wrapping_shr(0xA) { + 0b0 => { + let rd = (opcode & 0b0000000000000111) as u8; + let rn = ((opcode & 0b0000000000111000).wrapping_shr(0x3)) as u8; + let rm = ((opcode & 0b0000000111000000).wrapping_shr(0x6)) as u8; + + match (opcode & 0b0000001000000000).wrapping_shr(0x9) { + 0b0 => (Add(rd, rn, Shifter::from_register(rm), true), Al), + 0b1 => (Sub(rd, rn, Shifter::from_register(rm), true), Al), + + _ => unsafe { unreachable_unchecked() }, + } + }, + + 0b1 => (Undefined, Al), + + _ => unsafe { unreachable_unchecked() }, + } + }, + + pattern => { + let rd = (opcode & 0b0000000000000111) as u8; + let rm = ((opcode & 0b0000000000111000).wrapping_shr(0x3)) as u8; + let imm = ((opcode & 0b0000011111000000).wrapping_shr(0x6)) as u8; + + match pattern { + 0b00 => (Mov(rd, LogicalShiftLeftImmediate(rm, imm), true), Al), + 0b01 => (Mov(rd, LogicalShiftRightImmediate(rm, imm), true), Al), + 0b10 => (Mov(rd, ArithmeticShiftRightImmediate(rm, imm), true), Al), + + _ => unsafe { unreachable_unchecked() }, + } + }, + } + }, + + 0b001 => { + let imm = (opcode & 0b0000000011111111) as u8; + let rd = ((opcode & 0b0000111100000000).wrapping_shr(0x8)) as u8; + + match (opcode & 0b0001100000000000).wrapping_shr(0xB) { + 0b00 => (Mov(rd, Immediate(imm, 0x0), true), Al), + 0b01 => (Cmp(rd, Immediate(imm, 0x0)), Al), + 0b10 => (Add(rd, rd, Immediate(imm, 0x0), true), Al), + 0b11 => (Sub(rd, rd, Immediate(imm, 0x0), true), Al), + + _ => unsafe { unreachable_unchecked() }, + } + }, + + 0b010 => { + match (opcode & 0b0001000000000000).wrapping_shr(0xC) { + 0b0 => { + match (opcode & 0b0000100000000000).wrapping_shr(0xB) { + 0b0 => { + match (opcode & 0b0000010000000000).wrapping_shr(0xA) { + 0b0 => { + let rd = (opcode & 0b0000000000000111) as u8; + let rm = (opcode & 0b0000000000111000).wrapping_shr(0x3) as u8; + + match (opcode & 0b0000001111000000).wrapping_shr(0x6) { + 0b0000 => (And(rd, rd, Shifter::from_register(rm), true), Al), + 0b0001 => (Eor(rd, rd, Shifter::from_register(rm), true), Al), + 0b0010 => (Mov(rd, LogicalShiftLeftRegister(rd, rm), true), Al), + 0b0011 => (Mov(rd, LogicalShiftRightRegister(rd, rm), true), Al), + 0b0100 => (Mov(rd, ArithmeticShiftRightRegister(rd, rm), true), Al), + 0b0101 => (Adc(rd, rd, Shifter::from_register(rm), true), Al), + 0b0110 => (Sbc(rd, rd, Shifter::from_register(rm), true), Al), + 0b0111 => (Mov(rd, RotateRightRegister(rd, rm), true), Al), + 0b1000 => (Tst(rd, Shifter::from_register(rm)), Al), + 0b1001 => (Rsb(rd, rm, Immediate(0x0, 0x0), true), Al), + 0b1010 => (Cmp(rd, Shifter::from_register(rm)), Al), + 0b1011 => (Cmn(rd, Shifter::from_register(rm)), Al), + 0b1100 => (Orr(rd, rd, Shifter::from_register(rm), true), Al), + 0b1101 => (Mul(rd, rd, Shifter::from_register(rm), true), Al), + 0b1110 => (Bic(rd, rd, Shifter::from_register(rm), true), Al), + 0b1111 => (Mvn(rd, Shifter::from_register(rm), true), Al), + + _ => unsafe { unreachable_unchecked() }, + } + }, + + 0b1 => { + let h0 = opcode & 0b0000000010000000 != 0x0; + let h1 = opcode & 0b0000000001000000 != 0x0; + + let rd = (opcode & 0b0000000000000111) as u8 | (h0 as u8) << 0x3; + let rm = ((opcode & 0b0000000000111000).wrapping_shr(0x3)) as u8 | (h1 as u8) << 0x3; + + match (opcode & 0b0000001100000000).wrapping_shr(0x8) { + 0b00 => (Undefined, Al), + + // Unpredictable if rd is pc or if both rd and rm + // are low registers. + 0b01 => (Cmp(rd, Shifter::from_register(rm)), Al), + 0b10 => (Mov(rd, Shifter::from_register(rm), true), Al), + // Unpredictable if h0 is true or if rd is non- + // zero. + 0b11 => (Bx(rm), Al), + + _ => unsafe { unreachable_unchecked() }, + } + }, + + _ => unsafe { unreachable_unchecked() }, + } + }, + + 0b1 => { + let imm = (opcode & 0b0000000011111111) as u8; + let rd = ((opcode & 0b0000011100000000).wrapping_shr(0x8)) as u8; + + let imm = (imm as u16).wrapping_mul(0x4); + + (LoadPc(rd, imm), Al) + }, + + _ => unsafe { unreachable_unchecked() }, + } + }, + + 0b1 => (Undefined, Al), + + _ => unsafe { unreachable_unchecked() }, + } + }, + + 0b011 => { + let rd = (opcode & 0b0000000000000111) as u8; + let rn = ((opcode & 0b0000000000111000).wrapping_shr(0x3)) as u8; + let imm = (opcode & 0b0000011111000000).wrapping_shr(0x6); + let l = opcode & 0b0000100000000000 != 0x0; + let b = opcode & 0b0001000000000000 != 0x0; + + let imm = imm.wrapping_shl(0x2) as i16; + + match l { + false => match b { + false => (StoreImmediateOffset( rd, rn, imm), Al), + true => (StoreByteImmediateOffset(rd, rn, imm), Al), + }, + + true => match b { + false => (LoadImmediateOffset( rd, rn, imm), Al), + true => (StoreByteImmediateOffset(rd, rn, imm), Al), // TODO + }, + } + }, + + 0b100 => { + match (opcode & 0b0001000000000000).wrapping_shr(0xC) { + 0b0 => { + let rd = (opcode & 0b0000000000000111) as u8; + let rn = ((opcode & 0b0000000000111000).wrapping_shr(0x3)) as u8; + let imm = (opcode & 0b0000011111000000).wrapping_shr(0x6) as u8; + let l = opcode & 0b0000010000000000 != 0x0; + + let imm = imm.wrapping_shl(0x1) as i16; + + match l { + false => (StoreHalfword(rd, rn, imm), Al), + true => (LoadHalfword( rd, rn, imm), Al), + } + }, + + 0b1 => (Undefined, Al), + + _ => unsafe { unreachable_unchecked() }, + } + }, + + 0b101 => (Undefined, Al), + + 0b110 => { + match (opcode & 0b0001000000000000).wrapping_shr(0xC) { + 0b0 => (Undefined, Al), + + 0b1 => { + let predicate = ((opcode & 0b0000111100000000).wrapping_shr(0x8)) as u8; + + let imm = opcode & 0b0000000011111111; + + match predicate { + 0b1111 => (Swi(imm as u32), Al), + + _ => { + let predicate = Predicate::from_raw(predicate); + let imm = ((imm as u32) << 0x18) as i32 >> 0x17; + + (B(imm), predicate) + }, + } + }, + + _ => unsafe { unreachable_unchecked() }, + } + }, + + 0b111 => { + let imm = (opcode & 0b0000011111111111) as u32; + + match (opcode & 0b0001100000000000).wrapping_shr(0xB) { + 0b00 => { + let imm = imm.wrapping_shl(0x15) as i32 >> 0x14; + (B(imm), Al) + }, + + // Undefined in ARMv4 (later blx suffix). + 0b01 => (Undefined, Al), + + 0b10 => { + let imm = imm.wrapping_shl(0x15) as i32 >> 0x9; + (Bl0(imm), Al) + }, + + 0b11 => { + let imm = imm.wrapping_shl(0x1) as i32; + (Bl1(imm), Al) + }, + + _ => unsafe { unreachable_unchecked() }, + } + }, + + _ => unsafe { unreachable_unchecked() }, + }; + } +} |