pollex/arm32/instruction_codec/
decode_thumb.rs

1// Copyright 2024 Gabriel Bjørnager Jensen.
2//
3// This file is part of Pollex.
4//
5// Pollex is free software: you can redistribute it
6// and/or modify it under the terms of the GNU Af-
7// fero General Public License as published by the
8// Free Software Foundation, either version 3 of
9// the License, or (at your option) any later ver-
10// sion.
11//
12// Pollex is distributed in the hope that it will
13// be useful, but WITHOUT ANY WARRANTY; without
14// even the implied warranty of MERCHANTABILITY or
15// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// Affero General Public License for more details.
17//
18// You should have received a copy of the GNU Af-
19// fero General Public License along with Pollex.
20// If not, see <https://www.gnu.org/licenses/>.
21
22use crate::Result;
23use crate::arm32::{
24	Instruction,
25	InstructionCodec,
26	Predicate,
27	Register,
28	Sflag,
29	Shifter,
30	ThumbOpcode,
31};
32
33use core::num::Wrapping;
34
35impl InstructionCodec {
36	/// Decodes the given Thumb opcode.
37	///
38	/// # Errors
39	///
40	/// If the provided opcode is invalid (i.e. does not match any known pattern), an [InvalidOpcode](crate::Error::InvalidOpcode) error is returned.
41	pub fn decode_thumb(&mut self, opcode: ThumbOpcode) -> Result<Instruction> {
42		use Instruction::*;
43
44		let opcode = opcode.to_u16();
45
46		macro_rules! match_bits {
47			($mask:expr) => {{
48				opcode & $mask == $mask
49			}};
50		}
51
52		let instruction = if match_bits!(0b11010000_00000000) {
53			let predicate = (opcode & 0b00001111_00000000).wrapping_shr(0x8) as u8;
54			let immediate = u32::from(opcode & 0b00000000_11111111);
55
56			if predicate == 0b1111 {
57				SoftwareInterrupt {
58					predicate: Predicate::Always,
59					immediate,
60				}
61			} else {
62				let predicate = Predicate::from_u8(predicate).unwrap();
63
64				let mut immediate = (immediate.wrapping_shl(0x18) as i32).wrapping_shl(0x17) as u32;
65				immediate = immediate.wrapping_add(self.address.0).wrapping_add(0x4);
66
67				Branch {
68					predicate,
69					immediate,
70				}
71			}
72		} else if match_bits!(0b00011000_00000000) {
73			let destination = Register::from_u8((opcode & 0b00000000_00000111) as u8).unwrap();
74			let base        = Register::from_u8((opcode & 0b00000000_00111000).wrapping_shr(0x3) as u8).unwrap();
75
76			let subtract = opcode & 0b00000010_00000000 != 0x0;
77
78			let immediate_source = opcode & 0b00000100_00000000 != 0x0;
79			if immediate_source {
80				let source = u32::from((opcode & 0b00000001_11000000).wrapping_shr(0x6));
81
82				if subtract {
83					Subtract {
84						predicate:   Predicate::Always,
85						destination,
86						base,
87						source:      Shifter::Immediate(source),
88						s:           Sflag::On,
89					}
90				} else {
91					Add {
92						predicate:   Predicate::Always,
93						destination,
94						base,
95						source:      Shifter::Immediate(source),
96						s:           Sflag::On,
97					}
98				}
99			} else {
100				// register source
101
102				let source = Register::from_u8((opcode & 0b00000001_11000000).wrapping_shr(0x6) as u8).unwrap();
103
104				if subtract {
105					Subtract {
106						predicate:   Predicate::Always,
107						destination,
108						base,
109						source:      Shifter::from_register(source),
110						s:           Sflag::On,
111					}
112				} else {
113					Add {
114						predicate:   Predicate::Always,
115						destination,
116						base,
117						source:      Shifter::from_register(source),
118						s:           Sflag::On,
119					}
120				}
121			}
122		} else if match_bits!(0b01000111_00000000) {
123			let source = Register::from_u8((opcode & 0b00000000_01111000).wrapping_shr(0x3) as u8).unwrap();
124			let l      = opcode & 0b00000000_10000000 != 0x0;
125
126			if l {
127				BranchLinkExchange {
128					predicate: Predicate::Always,
129					source:    Shifter::from_register(source),
130				}
131			} else {
132				BranchExchange {
133					predicate: Predicate::Always,
134					source,
135				}
136			}
137		} else {
138			let _code = (opcode & 0b00011000_00000000).wrapping_shr(0xB) as u8;
139
140			todo!();
141		};
142
143		self.address += Wrapping(ThumbOpcode::SIZE);
144		Ok(instruction)
145	}
146}