libmicroemu 0.2.0
ARM Microcontroller Emulator Library
Loading...
Searching...
No Matches
alu.h
1#pragma once
2#include "libmicroemu/internal/logic/imm_shift_results.h"
3#include "libmicroemu/internal/utils/bit_manip.h"
4#include "libmicroemu/internal/utils/traits.h"
5#include "libmicroemu/types.h"
6#include <assert.h>
7#include <cstddef>
8#include <cstdint>
9#include <limits>
10
11namespace libmicroemu::internal {
12
13// Alias zur einfacheren Verwendung
14template <typename T> using next_bigger_type_t = typename next_bigger_type<T>::type;
15
16template <typename T> class Alu {
17 // clang-format off
18 static_assert(
19 std::is_same<T, u32>::value ||
20 std::is_same<T, u16>::value ||
21 std::is_same<T, u8>::value,
22 "Alu only works for u32, u16 and u8");
23 // clang-format on
24public:
25 // Structure to hold the result of addition with carry
27 T value; // The result of the addition
28 bool carry_out; // True if there was an unsigned carry out of the most significant bit
29 bool overflow; // True if there was a signed overflow during addition
30 };
31
32 // AddWithCarry function that performs addition with a carry-in, and handles both unsigned carry
33 // and signed overflow
34 static AddWithCarryResult AddWithCarry(const T &x, const T &y, const bool carry_in) {
35 // Ensure that the type T is one of the unsigned integer types: u32, u16, or u8
36 static_assert(std::is_same<T, u32>::value || std::is_same<T, u16>::value ||
37 std::is_same<T, u8>::value,
38 "AddWithCarry only works for u32, u16, and u8");
39
40 // Define types for signed equivalent of T and the next bigger unsigned and signed types
41 using U =
42 next_bigger_type_t<T>; // Next bigger unsigned type that can hold the result of T + T + 1
43
44 // Perform unsigned addition using the larger type U, including carry_in
45 U unsigned_sum = static_cast<U>(x) + static_cast<U>(y) + static_cast<U>(carry_in);
46
47 // Convert the result back to the original type T
48 T result = static_cast<T>(unsigned_sum);
49
50 // Calculate carry_out: if any bit beyond the most significant bit of T is set, carry occurred
51 bool carry_out = unsigned_sum > std::numeric_limits<T>::max();
52
53 // Calculate overflow: check if sign bits differ (using two's complement arithmetic rules)
54 bool overflow = (((x ^ result) & (y ^ result)) >> (sizeof(T) * 8 - 1)) & 1;
55
56 // Return the result, along with the carry out and overflow flags
57 return AddWithCarryResult{result, carry_out, overflow};
58 }
59
60 static constexpr T OR(const T &x, const T &y) { return x | y; }
61 static constexpr T EOR(const T &x, const T &y) { return x ^ y; }
62 static constexpr T AND(const T &x, const T &y) { return x & y; }
63 static T LSR(const T &x, u32 shift) {
64 // see Armv7-M Architecture Reference Manual Issue E.e p.26
65 assert(shift >= 0);
66 return x >> shift;
67 }
68 //------------------------
69
70 static T ASR(const T &x, i32 shift) {
71 // see Armv7-M Architecture Reference Manual Issue E.e p.26
72 assert(shift >= 0);
73 return static_cast<T>(static_cast<make_signed_type<T>>(x) >> shift);
74 }
75
77 T result;
78 bool carry_out;
79 };
80
81 static ASR_C_Results ASR_C(const T &x, i32 shift) {
82 // see Armv7-M Architecture Reference Manual Issue E.e p.26
83 assert(shift > 0);
84 using Ts = make_signed_type_t<T>;
85
86 const Ts extended_x = static_cast<Ts>(x);
87 const T result = static_cast<T>(extended_x >> shift);
88
89 const bool carry_out = ((extended_x >> (shift - 1U)) & 0x1U) == 1U;
90 return ASR_C_Results{result, carry_out};
91 }
92
93 //-------------------------
94 static T LSL(const T &x, i32 shift) {
95 // see Armv7-M Architecture Reference Manual Issue E.e p.26
96 assert(shift >= 0);
97 return x << shift;
98 }
99
101 T result;
102 bool carry_out;
103 };
104
105 static LSR_C_Results LSR_C(const T &x, i32 shift) {
106 // see Armv7-M Architecture Reference Manual Issue E.e p.26
107 assert(shift > 0);
108
109 using U = next_bigger_type_t<T>;
110 const U extended_x = (static_cast<U>(x) << no_of_bits<T>::N) >> shift;
111
112 const T result = static_cast<T>(
113 BitManip<U>::template ExtractBits1R<no_of_bits<U>::N - 1U, no_of_bits<T>::N>(extended_x));
114
115 const bool carry_out =
116 BitManip<U>::template ExtractBits1R<no_of_bits<T>::N - 1, no_of_bits<T>::N - 1>(
117 extended_x) == 1U;
118
119 return LSR_C_Results{result, carry_out};
120 }
121
123 T result;
124 bool carry_out;
125 };
126
127 static LSL_C_Results LSL_C(const T &x, i32 shift) {
128 // see Armv7-M Architecture Reference Manual Issue E.e p.26
129 assert(shift > 0);
130
131 using U = next_bigger_type_t<T>;
132 const U extended_x = (static_cast<U>(x) << shift);
133 const T result =
134 static_cast<T>(BitManip<U>::template ExtractBits1R<no_of_bits<T>::N - 1U, 0>(extended_x));
135
136 const bool carry_out =
137 BitManip<U>::template ExtractBits1R<no_of_bits<T>::N, no_of_bits<T>::N>(extended_x) == 1U;
138
139 return LSL_C_Results{result, carry_out};
140 }
141
142 static T ROR(const T &x, i32 shift) {
143 if (shift == 0) {
144 return x;
145 } else {
146 return ROR_C(x, shift).result;
147 }
148 }
149
151 T result;
152 bool carry_out;
153 };
154
155 static ROR_C_Results ROR_C(const T &x, i32 shift) {
156 // see Armv7-M Architecture Reference Manual Issue E.e p.26
157 assert(shift != 0U);
158 constexpr auto N = no_of_bits<T>::N;
159 const auto m = shift % N;
160 const T result = LSR(x, m) | LSL(x, N - m);
161 const auto carry_out = BitManip<T>::template ExtractBits1R<N - 1U, N - 1U>(result);
162 return ROR_C_Results{result, carry_out == 0x1U};
163 }
164
166 T result;
167 bool carry_out;
168 };
169
170 static RXR_C_Results RXR_C(const T &x, bool carry_in) {
171 // see Armv7-M Architecture Reference Manual Issue E.e p.27
172 const u32 N = no_of_bits<T>::N;
173 const auto carry_out = BitManip<T>::template ExtractBits1R<0, 0>(x) == 0x1U;
174 const T carry_in_t = carry_in ? static_cast<T>(0x1U) : static_cast<T>(0x0U);
175 const T result = (x >> 1U) | (carry_in_t << (N - 1U));
176
177 return RXR_C_Results{result, carry_out};
178 }
179
180 static T RXR(const T &x, bool carry_in) { return RXR_C(x, carry_in).result; }
181 static ImmShiftResults DecodeImmShift(uint8_t type, uint8_t imm5) {
182 switch (type & 0x3U) {
183 case 0b00U: {
184 return ImmShiftResults{SRType::SRType_LSL, imm5};
185 }
186 case 0b01U: {
187 if (imm5 == 0x0U) {
188 return ImmShiftResults{SRType::SRType_LSR, 32U};
189 } else {
190 return ImmShiftResults{SRType::SRType_LSR, imm5};
191 }
192 }
193 case 0b10U: {
194 if (imm5 == 0x0U) {
195 return ImmShiftResults{SRType::SRType_ASR, 32U};
196 } else {
197 return ImmShiftResults{SRType::SRType_ASR, imm5};
198 }
199 }
200 case 0b11U: {
201 if (imm5 == 0x0U) {
202 return ImmShiftResults{SRType::SRType_RRX, 1U};
203 } else {
204 return ImmShiftResults{SRType::SRType_ROR, imm5};
205 }
206 default: {
207 assert(false);
208 // should not happen
209 }
210 }
211 }
212 return ImmShiftResults{SRType::SRType_None, 0U};
213 }
214 static T Shift(T value, SRType type, T amount, bool carry_in) {
215 const auto result = Shift_C(value, type, amount, carry_in);
216 return result.result;
217 }
218 struct ShiftCRes {
219 T result;
220 bool carry_out;
221 };
222 static ShiftCRes Shift_C(T value, SRType type, T amount, bool carry_in) {
223 // see Armv7-M Architecture Reference Manual Issue E.e p.183
224 if (amount == 0U) {
225 return ShiftCRes{value, carry_in};
226 }
227 switch (type) {
228 case SRType::SRType_LSL: {
229 const auto res = LSL_C(value, amount);
230 return ShiftCRes{res.result, res.carry_out};
231 }
232 case SRType::SRType_LSR: {
233 const auto res = LSR_C(value, amount);
234 return ShiftCRes{res.result, res.carry_out};
235 }
236 case SRType::SRType_ASR: {
237 const auto res = ASR_C(value, amount);
238 return ShiftCRes{res.result, res.carry_out};
239 }
240 case SRType::SRType_ROR: {
241 const auto res = ROR_C(value, amount);
242 return ShiftCRes{res.result, res.carry_out};
243 }
244 case SRType::SRType_RRX: {
245 const auto res = RXR_C(value, carry_in);
246 return ShiftCRes{res.result, res.carry_out};
247 break;
248 }
249 default: {
250 // should not happen
251 assert(false);
252 break;
253 }
254 }
255 return ShiftCRes{value, carry_in}; // // should not happen
256 }
257
258private:
262 Alu() = delete;
263
267 ~Alu() = delete;
268
273 Alu(const Alu &r_src) = delete;
274
279 Alu &operator=(const Alu &r_src) = delete;
280
285 Alu(Alu &&r_src) = delete;
286
291 Alu &operator=(Alu &&r_src) = delete;
292}; // namespace libmicroemu
293
294using Alu8 = Alu<u8>;
295using Alu16 = Alu<u16>;
296using Alu32 = Alu<u32>;
297
298} // namespace libmicroemu::internal
Definition alu.h:16
Definition bit_manip.h:11
The libmicroemu::internal namespace contains all classes and functions of libmicroemu which are priva...
Definition bkpt_flags.h:6
Definition traits.h:31