This repository is private.
All pages are served over SSL and all pushing and pulling is done over SSH.
No one may fork, clone, or view it unless they are added as a member.
Every repository with this icon (
) is private.
Every repository with this icon (
This repository is public.
Anyone may fork, clone, or view it.
Every repository with this icon (
) is public.
Every repository with this icon (
ME (author)
Tue May 13 18:38:18 -0700 2008
gpsphone / cpu.c
| fc787e4d » | ME | 2008-05-13 | 1 | /* gameplaySP | |
| 2 | * | ||||
| 3 | * Copyright (C) 2006 Exophase <exophase@gmail.com> | ||||
| 4 | * | ||||
| 5 | * This program is free software; you can redistribute it and/or | ||||
| 6 | * modify it under the terms of the GNU General Public License as | ||||
| 7 | * published by the Free Software Foundation; either version 2 of | ||||
| 8 | * the License, or (at your option) any later version. | ||||
| 9 | * | ||||
| 10 | * This program is distributed in the hope that it will be useful, | ||||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
| 13 | * General Public License for more details. | ||||
| 14 | * | ||||
| 15 | * You should have received a copy of the GNU General Public License | ||||
| 16 | * along with this program; if not, write to the Free Software | ||||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| 18 | */ | ||||
| 19 | |||||
| 20 | // Important todo: | ||||
| 21 | // - stm reglist writeback when base is in the list needs adjustment | ||||
| 22 | // - block memory needs psr swapping and user mode reg swapping | ||||
| 23 | |||||
| 24 | #include <stdio.h> | ||||
| 25 | #include "common.h" | ||||
| 26 | |||||
| 27 | u32 memory_region_access_read_u8[16]; | ||||
| 28 | u32 memory_region_access_read_s8[16]; | ||||
| 29 | u32 memory_region_access_read_u16[16]; | ||||
| 30 | u32 memory_region_access_read_s16[16]; | ||||
| 31 | u32 memory_region_access_read_u32[16]; | ||||
| 32 | u32 memory_region_access_write_u8[16]; | ||||
| 33 | u32 memory_region_access_write_u16[16]; | ||||
| 34 | u32 memory_region_access_write_u32[16]; | ||||
| 35 | u32 memory_reads_u8; | ||||
| 36 | u32 memory_reads_s8; | ||||
| 37 | u32 memory_reads_u16; | ||||
| 38 | u32 memory_reads_s16; | ||||
| 39 | u32 memory_reads_u32; | ||||
| 40 | u32 memory_writes_u8; | ||||
| 41 | u32 memory_writes_u16; | ||||
| 42 | u32 memory_writes_u32; | ||||
| 43 | |||||
| 44 | static const u8 bit_count[256] = | ||||
| 45 | { | ||||
| 46 | 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, | ||||
| 47 | 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, | ||||
| 48 | 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, | ||||
| 49 | 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, | ||||
| 50 | 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, | ||||
| 51 | 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, | ||||
| 52 | 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, | ||||
| 53 | 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, | ||||
| 54 | 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, | ||||
| 55 | 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, | ||||
| 56 | 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, | ||||
| 57 | 7, 7, 8 | ||||
| 58 | }; | ||||
| 59 | |||||
| 60 | |||||
| 61 | #ifdef REGISTER_USAGE_ANALYZE | ||||
| 62 | |||||
| 63 | u64 instructions_total = 0; | ||||
| 64 | |||||
| 65 | u64 arm_reg_freq[16]; | ||||
| 66 | u64 arm_reg_access_total = 0; | ||||
| 67 | u64 arm_instructions_total = 0; | ||||
| 68 | |||||
| 69 | u64 thumb_reg_freq[16]; | ||||
| 70 | u64 thumb_reg_access_total = 0; | ||||
| 71 | u64 thumb_instructions_total = 0; | ||||
| 72 | |||||
| 73 | // mla/long mla's addition operand are not counted yet. | ||||
| 74 | |||||
| 75 | #define using_register(instruction_set, register, type) \ | ||||
| 76 | instruction_set##_reg_freq[register]++; \ | ||||
| 77 | instruction_set##_reg_access_total++ \ | ||||
| 78 | |||||
| 79 | #define using_register_list(instruction_set, rlist, count) \ | ||||
| 80 | { \ | ||||
| 81 | u32 i; \ | ||||
| 82 | for(i = 0; i < count; i++) \ | ||||
| 83 | { \ | ||||
| 84 | if((reg_list >> i) & 0x01) \ | ||||
| 85 | { \ | ||||
| 86 | using_register(instruction_set, i, memory_target); \ | ||||
| 87 | } \ | ||||
| 88 | } \ | ||||
| 89 | } \ | ||||
| 90 | |||||
| 91 | #define using_instruction(instruction_set) \ | ||||
| 92 | instruction_set##_instructions_total++; \ | ||||
| 93 | instructions_total++ \ | ||||
| 94 | |||||
| 95 | int sort_tagged_element(const void *_a, const void *_b) | ||||
| 96 | { | ||||
| 97 | const u64 *a = _a; | ||||
| 98 | const u64 *b = _b; | ||||
| 99 | |||||
| 100 | return (int)(b[1] - a[1]); | ||||
| 101 | } | ||||
| 102 | |||||
| 103 | void print_register_usage() | ||||
| 104 | { | ||||
| 105 | u32 i; | ||||
| 106 | u64 arm_reg_freq_tagged[32]; | ||||
| 107 | u64 thumb_reg_freq_tagged[32]; | ||||
| 108 | double percent; | ||||
| 109 | double percent_total = 0.0; | ||||
| 110 | |||||
| 111 | for(i = 0; i < 16; i++) | ||||
| 112 | { | ||||
| 113 | arm_reg_freq_tagged[i * 2] = i; | ||||
| 114 | arm_reg_freq_tagged[(i * 2) + 1] = arm_reg_freq[i]; | ||||
| 115 | thumb_reg_freq_tagged[i * 2] = i; | ||||
| 116 | thumb_reg_freq_tagged[(i * 2) + 1] = thumb_reg_freq[i]; | ||||
| 117 | } | ||||
| 118 | |||||
| 119 | qsort(arm_reg_freq_tagged, 16, sizeof(u64) * 2, sort_tagged_element); | ||||
| 120 | qsort(thumb_reg_freq_tagged, 16, sizeof(u64) * 2, sort_tagged_element); | ||||
| 121 | |||||
| 122 | printf("ARM register usage (%lf%% ARM instructions):\n", | ||||
| 123 | (arm_instructions_total * 100.0) / instructions_total); | ||||
| 124 | for(i = 0; i < 16; i++) | ||||
| 125 | { | ||||
| 126 | percent = (arm_reg_freq_tagged[(i * 2) + 1] * 100.0) / | ||||
| 127 | arm_reg_access_total; | ||||
| 128 | percent_total += percent; | ||||
| 129 | printf("r%02d: %lf%% (-- %lf%%)\n", | ||||
| 130 | (u32)arm_reg_freq_tagged[(i * 2)], percent, percent_total); | ||||
| 131 | } | ||||
| 132 | |||||
| 133 | percent_total = 0.0; | ||||
| 134 | |||||
| 135 | printf("\nThumb register usage (%lf%% Thumb instructions):\n", | ||||
| 136 | (thumb_instructions_total * 100.0) / instructions_total); | ||||
| 137 | for(i = 0; i < 16; i++) | ||||
| 138 | { | ||||
| 139 | percent = (thumb_reg_freq_tagged[(i * 2) + 1] * 100.0) / | ||||
| 140 | thumb_reg_access_total; | ||||
| 141 | percent_total += percent; | ||||
| 142 | printf("r%02d: %lf%% (-- %lf%%)\n", | ||||
| 143 | (u32)thumb_reg_freq_tagged[(i * 2)], percent, percent_total); | ||||
| 144 | } | ||||
| 145 | |||||
| 146 | memset(arm_reg_freq, 0, sizeof(u64) * 16); | ||||
| 147 | memset(thumb_reg_freq, 0, sizeof(u64) * 16); | ||||
| 148 | arm_reg_access_total = 0; | ||||
| 149 | thumb_reg_access_total = 0; | ||||
| 150 | } | ||||
| 151 | |||||
| 152 | #else | ||||
| 153 | |||||
| 154 | #define using_register(instruction_set, register, type) \ | ||||
| 155 | |||||
| 156 | #define using_register_list(instruction_set, rlist, count) \ | ||||
| 157 | |||||
| 158 | #define using_instruction(instruction_set) \ | ||||
| 159 | |||||
| 160 | #endif | ||||
| 161 | |||||
| 162 | |||||
| 163 | #define arm_decode_data_proc_reg() \ | ||||
| 164 | u32 rn = (opcode >> 16) & 0x0F; \ | ||||
| 165 | u32 rd = (opcode >> 12) & 0x0F; \ | ||||
| 166 | u32 rm = opcode & 0x0F; \ | ||||
| 167 | using_register(arm, rd, op_dest); \ | ||||
| 168 | using_register(arm, rn, op_src); \ | ||||
| 169 | using_register(arm, rm, op_src) \ | ||||
| 170 | |||||
| 171 | #define arm_decode_data_proc_imm() \ | ||||
| 172 | u32 rn = (opcode >> 16) & 0x0F; \ | ||||
| 173 | u32 rd = (opcode >> 12) & 0x0F; \ | ||||
| 174 | u32 imm; \ | ||||
| 175 | ror(imm, opcode & 0xFF, ((opcode >> 8) & 0x0F) * 2); \ | ||||
| 176 | using_register(arm, rd, op_dest); \ | ||||
| 177 | using_register(arm, rn, op_src) \ | ||||
| 178 | |||||
| 179 | #define arm_decode_psr_reg() \ | ||||
| 180 | u32 psr_field = (opcode >> 16) & 0x0F; \ | ||||
| 181 | u32 rd = (opcode >> 12) & 0x0F; \ | ||||
| 182 | u32 rm = opcode & 0x0F; \ | ||||
| 183 | using_register(arm, rd, op_dest); \ | ||||
| 184 | using_register(arm, rm, op_src) \ | ||||
| 185 | |||||
| 186 | #define arm_decode_psr_imm() \ | ||||
| 187 | u32 psr_field = (opcode >> 16) & 0x0F; \ | ||||
| 188 | u32 rd = (opcode >> 12) & 0x0F; \ | ||||
| 189 | u32 imm; \ | ||||
| 190 | ror(imm, opcode & 0xFF, ((opcode >> 8) & 0x0F) * 2); \ | ||||
| 191 | using_register(arm, rd, op_dest) \ | ||||
| 192 | |||||
| 193 | #define arm_decode_branchx() \ | ||||
| 194 | u32 rn = opcode & 0x0F; \ | ||||
| 195 | using_register(arm, rn, branch_target) \ | ||||
| 196 | |||||
| 197 | #define arm_decode_multiply() \ | ||||
| 198 | u32 rd = (opcode >> 16) & 0x0F; \ | ||||
| 199 | u32 rn = (opcode >> 12) & 0x0F; \ | ||||
| 200 | u32 rs = (opcode >> 8) & 0x0F; \ | ||||
| 201 | u32 rm = opcode & 0x0F; \ | ||||
| 202 | using_register(arm, rd, op_dest); \ | ||||
| 203 | using_register(arm, rn, op_src); \ | ||||
| 204 | using_register(arm, rm, op_src) \ | ||||
| 205 | |||||
| 206 | #define arm_decode_multiply_long() \ | ||||
| 207 | u32 rdhi = (opcode >> 16) & 0x0F; \ | ||||
| 208 | u32 rdlo = (opcode >> 12) & 0x0F; \ | ||||
| 209 | u32 rn = (opcode >> 8) & 0x0F; \ | ||||
| 210 | u32 rm = opcode & 0x0F; \ | ||||
| 211 | using_register(arm, rdhi, op_dest); \ | ||||
| 212 | using_register(arm, rdlo, op_dest); \ | ||||
| 213 | using_register(arm, rn, op_src); \ | ||||
| 214 | using_register(arm, rm, op_src) \ | ||||
| 215 | |||||
| 216 | #define arm_decode_swap() \ | ||||
| 217 | u32 rn = (opcode >> 16) & 0x0F; \ | ||||
| 218 | u32 rd = (opcode >> 12) & 0x0F; \ | ||||
| 219 | u32 rm = opcode & 0x0F; \ | ||||
| 220 | using_register(arm, rd, memory_target); \ | ||||
| 221 | using_register(arm, rn, memory_base); \ | ||||
| 222 | using_register(arm, rm, memory_target) \ | ||||
| 223 | |||||
| 224 | #define arm_decode_half_trans_r() \ | ||||
| 225 | u32 rn = (opcode >> 16) & 0x0F; \ | ||||
| 226 | u32 rd = (opcode >> 12) & 0x0F; \ | ||||
| 227 | u32 rm = opcode & 0x0F; \ | ||||
| 228 | using_register(arm, rd, memory_target); \ | ||||
| 229 | using_register(arm, rn, memory_base); \ | ||||
| 230 | using_register(arm, rm, memory_offset) \ | ||||
| 231 | |||||
| 232 | #define arm_decode_half_trans_of() \ | ||||
| 233 | u32 rn = (opcode >> 16) & 0x0F; \ | ||||
| 234 | u32 rd = (opcode >> 12) & 0x0F; \ | ||||
| 235 | u32 offset = ((opcode >> 4) & 0xF0) | (opcode & 0x0F); \ | ||||
| 236 | using_register(arm, rd, memory_target); \ | ||||
| 237 | using_register(arm, rn, memory_base) \ | ||||
| 238 | |||||
| 239 | #define arm_decode_data_trans_imm() \ | ||||
| 240 | u32 rn = (opcode >> 16) & 0x0F; \ | ||||
| 241 | u32 rd = (opcode >> 12) & 0x0F; \ | ||||
| 242 | u32 offset = opcode & 0x0FFF; \ | ||||
| 243 | using_register(arm, rd, memory_target); \ | ||||
| 244 | using_register(arm, rn, memory_base) \ | ||||
| 245 | |||||
| 246 | #define arm_decode_data_trans_reg() \ | ||||
| 247 | u32 rn = (opcode >> 16) & 0x0F; \ | ||||
| 248 | u32 rd = (opcode >> 12) & 0x0F; \ | ||||
| 249 | u32 rm = opcode & 0x0F; \ | ||||
| 250 | using_register(arm, rd, memory_target); \ | ||||
| 251 | using_register(arm, rn, memory_base); \ | ||||
| 252 | using_register(arm, rm, memory_offset) \ | ||||
| 253 | |||||
| 254 | #define arm_decode_block_trans() \ | ||||
| 255 | u32 rn = (opcode >> 16) & 0x0F; \ | ||||
| 256 | u32 reg_list = opcode & 0xFFFF; \ | ||||
| 257 | using_register(arm, rn, memory_base); \ | ||||
| 258 | using_register_list(arm, reg_list, 16) \ | ||||
| 259 | |||||
| 260 | #define arm_decode_branch() \ | ||||
| 261 | s32 offset = ((s32)(opcode & 0xFFFFFF) << 8) >> 6 \ | ||||
| 262 | |||||
| 263 | |||||
| 264 | #define thumb_decode_shift() \ | ||||
| 265 | u32 imm = (opcode >> 6) & 0x1F; \ | ||||
| 266 | u32 rs = (opcode >> 3) & 0x07; \ | ||||
| 267 | u32 rd = opcode & 0x07; \ | ||||
| 268 | using_register(thumb, rd, op_dest); \ | ||||
| 269 | using_register(thumb, rs, op_shift) \ | ||||
| 270 | |||||
| 271 | #define thumb_decode_add_sub() \ | ||||
| 272 | u32 rn = (opcode >> 6) & 0x07; \ | ||||
| 273 | u32 rs = (opcode >> 3) & 0x07; \ | ||||
| 274 | u32 rd = opcode & 0x07; \ | ||||
| 275 | using_register(thumb, rd, op_dest); \ | ||||
| 276 | using_register(thumb, rn, op_src); \ | ||||
| 277 | using_register(thumb, rn, op_src) \ | ||||
| 278 | |||||
| 279 | #define thumb_decode_add_sub_imm() \ | ||||
| 280 | u32 imm = (opcode >> 6) & 0x07; \ | ||||
| 281 | u32 rs = (opcode >> 3) & 0x07; \ | ||||
| 282 | u32 rd = opcode & 0x07; \ | ||||
| 283 | using_register(thumb, rd, op_src_dest); \ | ||||
| 284 | using_register(thumb, rs, op_src) \ | ||||
| 285 | |||||
| 286 | #define thumb_decode_imm() \ | ||||
| 287 | u32 imm = opcode & 0xFF; \ | ||||
| 288 | using_register(thumb, ((opcode >> 8) & 0x07), op_dest) \ | ||||
| 289 | |||||
| 290 | #define thumb_decode_alu_op() \ | ||||
| 291 | u32 rs = (opcode >> 3) & 0x07; \ | ||||
| 292 | u32 rd = opcode & 0x07; \ | ||||
| 293 | using_register(thumb, rd, op_src_dest); \ | ||||
| 294 | using_register(thumb, rs, op_src) \ | ||||
| 295 | |||||
| 296 | #define thumb_decode_hireg_op() \ | ||||
| 297 | u32 rs = (opcode >> 3) & 0x0F; \ | ||||
| 298 | u32 rd = ((opcode >> 4) & 0x08) | (opcode & 0x07); \ | ||||
| 299 | using_register(thumb, rd, op_src_dest); \ | ||||
| 300 | using_register(thumb, rs, op_src) \ | ||||
| 301 | |||||
| 302 | |||||
| 303 | #define thumb_decode_mem_reg() \ | ||||
| 304 | u32 ro = (opcode >> 6) & 0x07; \ | ||||
| 305 | u32 rb = (opcode >> 3) & 0x07; \ | ||||
| 306 | u32 rd = opcode & 0x07; \ | ||||
| 307 | using_register(thumb, rd, memory_target); \ | ||||
| 308 | using_register(thumb, rb, memory_base); \ | ||||
| 309 | using_register(thumb, ro, memory_offset) \ | ||||
| 310 | |||||
| 311 | |||||
| 312 | #define thumb_decode_mem_imm() \ | ||||
| 313 | u32 imm = (opcode >> 6) & 0x1F; \ | ||||
| 314 | u32 rb = (opcode >> 3) & 0x07; \ | ||||
| 315 | u32 rd = opcode & 0x07; \ | ||||
| 316 | using_register(thumb, rd, memory_target); \ | ||||
| 317 | using_register(thumb, rb, memory_base) \ | ||||
| 318 | |||||
| 319 | |||||
| 320 | #define thumb_decode_add_sp() \ | ||||
| 321 | u32 imm = opcode & 0x7F; \ | ||||
| 322 | using_register(thumb, REG_SP, op_dest) \ | ||||
| 323 | |||||
| 324 | #define thumb_decode_rlist() \ | ||||
| 325 | u32 reg_list = opcode & 0xFF; \ | ||||
| 326 | using_register_list(thumb, rlist, 8) \ | ||||
| 327 | |||||
| 328 | #define thumb_decode_branch_cond() \ | ||||
| 329 | s32 offset = (s8)(opcode & 0xFF) \ | ||||
| 330 | |||||
| 331 | #define thumb_decode_swi() \ | ||||
| 332 | u32 comment = opcode & 0xFF \ | ||||
| 333 | |||||
| 334 | #define thumb_decode_branch() \ | ||||
| 335 | u32 offset = opcode & 0x07FF \ | ||||
| 336 | |||||
| 337 | |||||
| 338 | #define get_shift_register(dest) \ | ||||
| 339 | u32 shift = reg[(opcode >> 8) & 0x0F]; \ | ||||
| 340 | using_register(arm, ((opcode >> 8) & 0x0F), op_shift); \ | ||||
| 341 | dest = reg[rm]; \ | ||||
| 342 | if(rm == 15) \ | ||||
| 343 | dest += 4 \ | ||||
| 344 | |||||
| 345 | |||||
| 346 | #define calculate_z_flag(dest) \ | ||||
| 347 | z_flag = (dest == 0) \ | ||||
| 348 | |||||
| 349 | #define calculate_n_flag(dest) \ | ||||
| 350 | n_flag = ((signed)dest < 0) \ | ||||
| 351 | |||||
| 352 | #define calculate_c_flag_sub(dest, src_a, src_b) \ | ||||
| 353 | c_flag = ((unsigned)src_b <= (unsigned)src_a) \ | ||||
| 354 | |||||
| 355 | #define calculate_v_flag_sub(dest, src_a, src_b) \ | ||||
| 356 | v_flag = ((signed)src_b > (signed)src_a) != ((signed)dest < 0) \ | ||||
| 357 | |||||
| 358 | #define calculate_c_flag_add(dest, src_a, src_b) \ | ||||
| 359 | c_flag = ((unsigned)dest < (unsigned)src_a) \ | ||||
| 360 | |||||
| 361 | #define calculate_v_flag_add(dest, src_a, src_b) \ | ||||
| 362 | v_flag = ((signed)dest < (signed)src_a) != ((signed)src_b < 0) \ | ||||
| 363 | |||||
| 364 | |||||
| 365 | #define calculate_reg_sh() \ | ||||
| 366 | u32 reg_sh; \ | ||||
| 367 | switch((opcode >> 4) & 0x07) \ | ||||
| 368 | { \ | ||||
| 369 | /* LSL imm */ \ | ||||
| 370 | case 0x0: \ | ||||
| 371 | { \ | ||||
| 372 | reg_sh = reg[rm] << ((opcode >> 7) & 0x1F); \ | ||||
| 373 | break; \ | ||||
| 374 | } \ | ||||
| 375 | \ | ||||
| 376 | /* LSL reg */ \ | ||||
| 377 | case 0x1: \ | ||||
| 378 | { \ | ||||
| 379 | get_shift_register(reg_sh); \ | ||||
| 380 | if(shift <= 31) \ | ||||
| 381 | reg_sh = reg_sh << shift; \ | ||||
| 382 | else \ | ||||
| 383 | reg_sh = 0; \ | ||||
| 384 | break; \ | ||||
| 385 | } \ | ||||
| 386 | \ | ||||
| 387 | /* LSR imm */ \ | ||||
| 388 | case 0x2: \ | ||||
| 389 | { \ | ||||
| 390 | u32 imm = (opcode >> 7) & 0x1F; \ | ||||
| 391 | if(imm == 0) \ | ||||
| 392 | reg_sh = 0; \ | ||||
| 393 | else \ | ||||
| 394 | reg_sh = reg[rm] >> imm; \ | ||||
| 395 | break; \ | ||||
| 396 | } \ | ||||
| 397 | \ | ||||
| 398 | /* LSR reg */ \ | ||||
| 399 | case 0x3: \ | ||||
| 400 | { \ | ||||
| 401 | get_shift_register(reg_sh); \ | ||||
| 402 | if(shift <= 31) \ | ||||
| 403 | reg_sh = reg_sh >> shift; \ | ||||
| 404 | else \ | ||||
| 405 | reg_sh = 0; \ | ||||
| 406 | break; \ | ||||
| 407 | } \ | ||||
| 408 | \ | ||||
| 409 | /* ASR imm */ \ | ||||
| 410 | case 0x4: \ | ||||
| 411 | { \ | ||||
| 412 | u32 imm = (opcode >> 7) & 0x1F; \ | ||||
| 413 | reg_sh = reg[rm]; \ | ||||
| 414 | \ | ||||
| 415 | if(imm == 0) \ | ||||
| 416 | reg_sh = (s32)reg_sh >> 31; \ | ||||
| 417 | else \ | ||||
| 418 | reg_sh = (s32)reg_sh >> imm; \ | ||||
| 419 | break; \ | ||||
| 420 | } \ | ||||
| 421 | \ | ||||
| 422 | /* ASR reg */ \ | ||||
| 423 | case 0x5: \ | ||||
| 424 | { \ | ||||
| 425 | get_shift_register(reg_sh); \ | ||||
| 426 | if(shift <= 31) \ | ||||
| 427 | reg_sh = (s32)reg_sh >> shift; \ | ||||
| 428 | else \ | ||||
| 429 | reg_sh = (s32)reg_sh >> 31; \ | ||||
| 430 | break; \ | ||||
| 431 | } \ | ||||
| 432 | \ | ||||
| 433 | /* ROR imm */ \ | ||||
| 434 | case 0x6: \ | ||||
| 435 | { \ | ||||
| 436 | u32 imm = (opcode >> 7) & 0x1F; \ | ||||
| 437 | \ | ||||
| 438 | if(imm == 0) \ | ||||
| 439 | reg_sh = (reg[rm] >> 1) | (c_flag << 31); \ | ||||
| 440 | else \ | ||||
| 441 | ror(reg_sh, reg[rm], imm); \ | ||||
| 442 | break; \ | ||||
| 443 | } \ | ||||
| 444 | \ | ||||
| 445 | /* ROR reg */ \ | ||||
| 446 | case 0x7: \ | ||||
| 447 | { \ | ||||
| 448 | get_shift_register(reg_sh); \ | ||||
| 449 | ror(reg_sh, reg_sh, shift); \ | ||||
| 450 | break; \ | ||||
| 451 | } \ | ||||
| 452 | } \ | ||||
| 453 | |||||
| 454 | #define calculate_reg_sh_flags() \ | ||||
| 455 | u32 reg_sh; \ | ||||
| 456 | switch((opcode >> 4) & 0x07) \ | ||||
| 457 | { \ | ||||
| 458 | /* LSL imm */ \ | ||||
| 459 | case 0x0: \ | ||||
| 460 | { \ | ||||
| 461 | u32 imm = (opcode >> 7) & 0x1F; \ | ||||
| 462 | reg_sh = reg[rm]; \ | ||||
| 463 | \ | ||||
| 464 | if(imm != 0) \ | ||||
| 465 | { \ | ||||
| 466 | c_flag = (reg_sh >> (32 - imm)) & 0x01; \ | ||||
| 467 | reg_sh <<= imm; \ | ||||
| 468 | } \ | ||||
| 469 | \ | ||||
| 470 | break; \ | ||||
| 471 | } \ | ||||
| 472 | \ | ||||
| 473 | /* LSL reg */ \ | ||||
| 474 | case 0x1: \ | ||||
| 475 | { \ | ||||
| 476 | get_shift_register(reg_sh); \ | ||||
| 477 | if(shift != 0) \ | ||||
| 478 | { \ | ||||
| 479 | if(shift > 31) \ | ||||
| 480 | { \ | ||||
| 481 | if(shift == 32) \ | ||||
| 482 | c_flag = reg_sh & 0x01; \ | ||||
| 483 | else \ | ||||
| 484 | c_flag = 0; \ | ||||
| 485 | reg_sh = 0; \ | ||||
| 486 | } \ | ||||
| 487 | else \ | ||||
| 488 | { \ | ||||
| 489 | c_flag = (reg_sh >> (32 - shift)) & 0x01; \ | ||||
| 490 | reg_sh <<= shift; \ | ||||
| 491 | } \ | ||||
| 492 | } \ | ||||
| 493 | break; \ | ||||
| 494 | } \ | ||||
| 495 | \ | ||||
| 496 | /* LSR imm */ \ | ||||
| 497 | case 0x2: \ | ||||
| 498 | { \ | ||||
| 499 | u32 imm = (opcode >> 7) & 0x1F; \ | ||||
| 500 | reg_sh = reg[rm]; \ | ||||
| 501 | if(imm == 0) \ | ||||
| 502 | { \ | ||||
| 503 | c_flag = reg_sh >> 31; \ | ||||
| 504 | reg_sh = 0; \ | ||||
| 505 | } \ | ||||
| 506 | else \ | ||||
| 507 | { \ | ||||
| 508 | c_flag = (reg_sh >> (imm - 1)) & 0x01; \ | ||||
| 509 | reg_sh >>= imm; \ | ||||
| 510 | } \ | ||||
| 511 | break; \ | ||||
| 512 | } \ | ||||
| 513 | \ | ||||
| 514 | /* LSR reg */ \ | ||||
| 515 | case 0x3: \ | ||||
| 516 | { \ | ||||
| 517 | get_shift_register(reg_sh); \ | ||||
| 518 | if(shift != 0) \ | ||||
| 519 | { \ | ||||
| 520 | if(shift > 31) \ | ||||
| 521 | { \ | ||||
| 522 | if(shift == 32) \ | ||||
| 523 | c_flag = (reg_sh >> 31) & 0x01; \ | ||||
| 524 | else \ | ||||
| 525 | c_flag = 0; \ | ||||
| 526 | reg_sh = 0; \ | ||||
| 527 | } \ | ||||
| 528 | else \ | ||||
| 529 | { \ | ||||
| 530 | c_flag = (reg_sh >> (shift - 1)) & 0x01; \ | ||||
| 531 | reg_sh >>= shift; \ | ||||
| 532 | } \ | ||||
| 533 | } \ | ||||
| 534 | break; \ | ||||
| 535 | } \ | ||||
| 536 | \ | ||||
| 537 | /* ASR imm */ \ | ||||
| 538 | case 0x4: \ | ||||
| 539 | { \ | ||||
| 540 | u32 imm = (opcode >> 7) & 0x1F; \ | ||||
| 541 | reg_sh = reg[rm]; \ | ||||
| 542 | if(imm == 0) \ | ||||
| 543 | { \ | ||||
| 544 | reg_sh = (s32)reg_sh >> 31; \ | ||||
| 545 | c_flag = reg_sh & 0x01; \ | ||||
| 546 | } \ | ||||
| 547 | else \ | ||||
| 548 | { \ | ||||
| 549 | c_flag = (reg_sh >> (imm - 1)) & 0x01; \ | ||||
| 550 | reg_sh = (s32)reg_sh >> imm; \ | ||||
| 551 | } \ | ||||
| 552 | break; \ | ||||
| 553 | } \ | ||||
| 554 | \ | ||||
| 555 | /* ASR reg */ \ | ||||
| 556 | case 0x5: \ | ||||
| 557 | { \ | ||||
| 558 | get_shift_register(reg_sh); \ | ||||
| 559 | if(shift != 0) \ | ||||
| 560 | { \ | ||||
| 561 | if(shift > 31) \ | ||||
| 562 | { \ | ||||
| 563 | reg_sh = (s32)reg_sh >> 31; \ | ||||
| 564 | c_flag = reg_sh & 0x01; \ | ||||
| 565 | } \ | ||||
| 566 | else \ | ||||
| 567 | { \ | ||||
| 568 | c_flag = (reg_sh >> (shift - 1)) & 0x01; \ | ||||
| 569 | reg_sh = (s32)reg_sh >> shift; \ | ||||
| 570 | } \ | ||||
| 571 | } \ | ||||
| 572 | break; \ | ||||
| 573 | } \ | ||||
| 574 | \ | ||||
| 575 | /* ROR imm */ \ | ||||
| 576 | case 0x6: \ | ||||
| 577 | { \ | ||||
| 578 | u32 imm = (opcode >> 7) & 0x1F; \ | ||||
| 579 | reg_sh = reg[rm]; \ | ||||
| 580 | if(imm == 0) \ | ||||
| 581 | { \ | ||||
| 582 | u32 old_c_flag = c_flag; \ | ||||
| 583 | c_flag = reg_sh & 0x01; \ | ||||
| 584 | reg_sh = (reg_sh >> 1) | (old_c_flag << 31); \ | ||||
| 585 | } \ | ||||
| 586 | else \ | ||||
| 587 | { \ | ||||
| 588 | c_flag = (reg_sh >> (imm - 1)) & 0x01; \ | ||||
| 589 | ror(reg_sh, reg_sh, imm); \ | ||||
| 590 | } \ | ||||
| 591 | break; \ | ||||
| 592 | } \ | ||||
| 593 | \ | ||||
| 594 | /* ROR reg */ \ | ||||
| 595 | case 0x7: \ | ||||
| 596 | { \ | ||||
| 597 | get_shift_register(reg_sh); \ | ||||
| 598 | if(shift != 0) \ | ||||
| 599 | { \ | ||||
| 600 | c_flag = (reg_sh >> (shift - 1)) & 0x01; \ | ||||
| 601 | ror(reg_sh, reg_sh, shift); \ | ||||
| 602 | } \ | ||||
| 603 | break; \ | ||||
| 604 | } \ | ||||
| 605 | } \ | ||||
| 606 | |||||
| 607 | #define calculate_reg_offset() \ | ||||
| 608 | u32 reg_offset; \ | ||||
| 609 | switch((opcode >> 5) & 0x03) \ | ||||
| 610 | { \ | ||||
| 611 | /* LSL imm */ \ | ||||
| 612 | case 0x0: \ | ||||
| 613 | { \ | ||||
| 614 | reg_offset = reg[rm] << ((opcode >> 7) & 0x1F); \ | ||||
| 615 | break; \ | ||||
| 616 | } \ | ||||
| 617 | \ | ||||
| 618 | /* LSR imm */ \ | ||||
| 619 | case 0x1: \ | ||||
| 620 | { \ | ||||
| 621 | u32 imm = (opcode >> 7) & 0x1F; \ | ||||
| 622 | if(imm == 0) \ | ||||
| 623 | reg_offset = 0; \ | ||||
| 624 | else \ | ||||
| 625 | reg_offset = reg[rm] >> imm; \ | ||||
| 626 | break; \ | ||||
| 627 | } \ | ||||
| 628 | \ | ||||
| 629 | /* ASR imm */ \ | ||||
| 630 | case 0x2: \ | ||||
| 631 | { \ | ||||
| 632 | u32 imm = (opcode >> 7) & 0x1F; \ | ||||
| 633 | if(imm == 0) \ | ||||
| 634 | reg_offset = (s32)reg[rm] >> 31; \ | ||||
| 635 | else \ | ||||
| 636 | reg_offset = (s32)reg[rm] >> imm; \ | ||||
| 637 | break; \ | ||||
| 638 | } \ | ||||
| 639 | \ | ||||
| 640 | /* ROR imm */ \ | ||||
| 641 | case 0x3: \ | ||||
| 642 | { \ | ||||
| 643 | u32 imm = (opcode >> 7) & 0x1F; \ | ||||
| 644 | if(imm == 0) \ | ||||
| 645 | reg_offset = (reg[rm] >> 1) | (c_flag << 31); \ | ||||
| 646 | else \ | ||||
| 647 | ror(reg_offset, reg[rm], imm); \ | ||||
| 648 | break; \ | ||||
| 649 | } \ | ||||
| 650 | } \ | ||||
| 651 | |||||
| 652 | #define calculate_flags_add(dest, src_a, src_b) \ | ||||
| 653 | calculate_z_flag(dest); \ | ||||
| 654 | calculate_n_flag(dest); \ | ||||
| 655 | calculate_c_flag_add(dest, src_a, src_b); \ | ||||
| 656 | calculate_v_flag_add(dest, src_a, src_b) \ | ||||
| 657 | |||||
| 658 | #define calculate_flags_sub(dest, src_a, src_b) \ | ||||
| 659 | calculate_z_flag(dest); \ | ||||
| 660 | calculate_n_flag(dest); \ | ||||
| 661 | calculate_c_flag_sub(dest, src_a, src_b); \ | ||||
| 662 | calculate_v_flag_sub(dest, src_a, src_b) \ | ||||
| 663 | |||||
| 664 | #define calculate_flags_logic(dest) \ | ||||
| 665 | calculate_z_flag(dest); \ | ||||
| 666 | calculate_n_flag(dest) \ | ||||
| 667 | |||||
| 668 | #define extract_flags() \ | ||||
| 669 | n_flag = reg[REG_CPSR] >> 31; \ | ||||
| 670 | z_flag = (reg[REG_CPSR] >> 30) & 0x01; \ | ||||
| 671 | c_flag = (reg[REG_CPSR] >> 29) & 0x01; \ | ||||
| 672 | v_flag = (reg[REG_CPSR] >> 28) & 0x01; \ | ||||
| 673 | |||||
| 674 | #define collapse_flags() \ | ||||
| 675 | reg[REG_CPSR] = (n_flag << 31) | (z_flag << 30) | (c_flag << 29) | \ | ||||
| 676 | (v_flag << 28) | (reg[REG_CPSR] & 0xFF) \ | ||||
| 677 | |||||
| 678 | #define memory_region(r_dest, l_dest, address) \ | ||||
| 679 | r_dest = memory_regions[address >> 24]; \ | ||||
| 680 | l_dest = memory_limits[address >> 24] \ | ||||
| 681 | |||||
| 682 | |||||
| 683 | #define pc_region() \ | ||||
| 684 | memory_region(pc_region, pc_limit, pc) \ | ||||
| 685 | |||||
| 686 | #define check_pc_region() \ | ||||
| 687 | new_pc_region = (pc >> 15); \ | ||||
| 688 | if(new_pc_region != pc_region) \ | ||||
| 689 | { \ | ||||
| 690 | pc_region = new_pc_region; \ | ||||
| 691 | pc_address_block = memory_map_read[new_pc_region]; \ | ||||
| 692 | \ | ||||
| 693 | if(pc_address_block == NULL) \ | ||||
| 694 | pc_address_block = load_gamepak_page(pc_region & 0x3FF); \ | ||||
| 695 | } \ | ||||
| 696 | |||||
| 697 | u32 branch_targets = 0; | ||||
| 698 | u32 high_frequency_branch_targets = 0; | ||||
| 699 | |||||
| 700 | #define BRANCH_ACTIVITY_THRESHOLD 50 | ||||
| 701 | |||||
| 702 | #define arm_update_pc() \ | ||||
| 703 | pc = reg[REG_PC] \ | ||||
| 704 | |||||
| 705 | #define arm_pc_offset(val) \ | ||||
| 706 | pc += val; \ | ||||
| 707 | reg[REG_PC] = pc \ | ||||
| 708 | |||||
| 709 | #define arm_pc_offset_update(val) \ | ||||
| 710 | pc += val; \ | ||||
| 711 | reg[REG_PC] = pc \ | ||||
| 712 | |||||
| 713 | #define arm_pc_offset_update_direct(val) \ | ||||
| 714 | pc = val; \ | ||||
| 715 | reg[REG_PC] = pc \ | ||||
| 716 | |||||
| 717 | |||||
| 718 | // It should be okay to still generate result flags, spsr will overwrite them. | ||||
| 719 | // This is pretty infrequent (returning from interrupt handlers, et al) so | ||||
| 720 | // probably not worth optimizing for. | ||||
| 721 | |||||
| 722 | #define check_for_interrupts() \ | ||||
| 723 | if((io_registers[REG_IE] & io_registers[REG_IF]) && \ | ||||
| 724 | io_registers[REG_IME] && ((reg[REG_CPSR] & 0x80) == 0)) \ | ||||
| 725 | { \ | ||||
| 726 | reg_mode[MODE_IRQ][6] = reg[REG_PC] + 4; \ | ||||
| 727 | spsr[MODE_IRQ] = reg[REG_CPSR]; \ | ||||
| 728 | reg[REG_CPSR] = 0xD2; \ | ||||
| 729 | reg[REG_PC] = 0x00000018; \ | ||||
| 730 | arm_update_pc(); \ | ||||
| 731 | set_cpu_mode(MODE_IRQ); \ | ||||
| 732 | goto arm_loop; \ | ||||
| 733 | } \ | ||||
| 734 | |||||
| 735 | #define arm_spsr_restore() \ | ||||
| 736 | if(rd == 15) \ | ||||
| 737 | { \ | ||||
| 738 | if(reg[CPU_MODE] != MODE_USER) \ | ||||
| 739 | { \ | ||||
| 740 | reg[REG_CPSR] = spsr[reg[CPU_MODE]]; \ | ||||
| 741 | extract_flags(); \ | ||||
| 742 | set_cpu_mode(cpu_modes[reg[REG_CPSR] & 0x1F]); \ | ||||
| 743 | check_for_interrupts(); \ | ||||
| 744 | } \ | ||||
| 745 | arm_update_pc(); \ | ||||
| 746 | \ | ||||
| 747 | if(reg[REG_CPSR] & 0x20) \ | ||||
| 748 | goto thumb_loop; \ | ||||
| 749 | } \ | ||||
| 750 | |||||
| 751 | #define arm_data_proc_flags_reg() \ | ||||
| 752 | arm_decode_data_proc_reg(); \ | ||||
| 753 | calculate_reg_sh_flags() \ | ||||
| 754 | |||||
| 755 | #define arm_data_proc_reg() \ | ||||
| 756 | arm_decode_data_proc_reg(); \ | ||||
| 757 | calculate_reg_sh() \ | ||||
| 758 | |||||
| 759 | #define arm_data_proc_flags_imm() \ | ||||
| 760 | arm_decode_data_proc_imm() \ | ||||
| 761 | |||||
| 762 | #define arm_data_proc_imm() \ | ||||
| 763 | arm_decode_data_proc_imm() \ | ||||
| 764 | |||||
| 765 | #define arm_data_proc(expr, type) \ | ||||
| 766 | { \ | ||||
| 767 | u32 dest; \ | ||||
| 768 | arm_pc_offset(8); \ | ||||
| 769 | arm_data_proc_##type(); \ | ||||
| 770 | dest = expr; \ | ||||
| 771 | arm_pc_offset(-4); \ | ||||
| 772 | reg[rd] = dest; \ | ||||
| 773 | \ | ||||
| 774 | if(rd == 15) \ | ||||
| 775 | { \ | ||||
| 776 | arm_update_pc(); \ | ||||
| 777 | } \ | ||||
| 778 | } \ | ||||
| 779 | |||||
| 780 | #define flags_vars(src_a, src_b) \ | ||||
| 781 | u32 dest; \ | ||||
| 782 | const u32 _sa = src_a; \ | ||||
| 783 | const u32 _sb = src_b \ | ||||
| 784 | |||||
| 785 | #define arm_data_proc_logic_flags(expr, type) \ | ||||
| 786 | { \ | ||||
| 787 | arm_pc_offset(8); \ | ||||
| 788 | arm_data_proc_flags_##type(); \ | ||||
| 789 | u32 dest = expr; \ | ||||
| 790 | calculate_flags_logic(dest); \ | ||||
| 791 | arm_pc_offset(-4); \ | ||||
| 792 | reg[rd] = dest; \ | ||||
| 793 | arm_spsr_restore(); \ | ||||
| 794 | } \ | ||||
| 795 | |||||
| 796 | #define arm_data_proc_add_flags(src_a, src_b, type) \ | ||||
| 797 | { \ | ||||
| 798 | arm_pc_offset(8); \ | ||||
| 799 | arm_data_proc_##type(); \ | ||||
| 800 | flags_vars(src_a, src_b); \ | ||||
| 801 | dest = _sa + _sb; \ | ||||
| 802 | calculate_flags_add(dest, _sa, _sb); \ | ||||
| 803 | arm_pc_offset(-4); \ | ||||
| 804 | reg[rd] = dest; \ | ||||
| 805 | arm_spsr_restore(); \ | ||||
| 806 | } | ||||
| 807 | |||||
| 808 | #define arm_data_proc_sub_flags(src_a, src_b, type) \ | ||||
| 809 | { \ | ||||
| 810 | arm_pc_offset(8); \ | ||||
| 811 | arm_data_proc_##type(); \ | ||||
| 812 | flags_vars(src_a, src_b); \ | ||||
| 813 | dest = _sa - _sb; \ | ||||
| 814 | calculate_flags_sub(dest, _sa, _sb); \ | ||||
| 815 | arm_pc_offset(-4); \ | ||||
| 816 | reg[rd] = dest; \ | ||||
| 817 | arm_spsr_restore(); \ | ||||
| 818 | } \ | ||||
| 819 | |||||
| 820 | #define arm_data_proc_test_logic(expr, type) \ | ||||
| 821 | { \ | ||||
| 822 | arm_pc_offset(8); \ | ||||
| 823 | arm_data_proc_flags_##type(); \ | ||||
| 824 | u32 dest = expr; \ | ||||
| 825 | calculate_flags_logic(dest); \ | ||||
| 826 | arm_pc_offset(-4); \ | ||||
| 827 | } \ | ||||
| 828 | |||||
| 829 | #define arm_data_proc_test_add(src_a, src_b, type) \ | ||||
| 830 | { \ | ||||
| 831 | arm_pc_offset(8); \ | ||||
| 832 | arm_data_proc_##type(); \ | ||||
| 833 | flags_vars(src_a, src_b); \ | ||||
| 834 | dest = _sa + _sb; \ | ||||
| 835 | calculate_flags_add(dest, _sa, _sb); \ | ||||
| 836 | arm_pc_offset(-4); \ | ||||
| 837 | } \ | ||||
| 838 | |||||
| 839 | #define arm_data_proc_test_sub(src_a, src_b, type) \ | ||||
| 840 | { \ | ||||
| 841 | arm_pc_offset(8); \ | ||||
| 842 | arm_data_proc_##type(); \ | ||||
| 843 | flags_vars(src_a, src_b); \ | ||||
| 844 | dest = _sa - _sb; \ | ||||
| 845 | calculate_flags_sub(dest, _sa, _sb); \ | ||||
| 846 | arm_pc_offset(-4); \ | ||||
| 847 | } \ | ||||
| 848 | |||||
| 849 | #define arm_multiply_flags_yes(_dest) \ | ||||
| 850 | calculate_z_flag(_dest); \ | ||||
| 851 | calculate_n_flag(_dest); \ | ||||
| 852 | |||||
| 853 | #define arm_multiply_flags_no(_dest) \ | ||||
| 854 | |||||
| 855 | #define arm_multiply_long_flags_yes(_dest_lo, _dest_hi) \ | ||||
| 856 | z_flag = (_dest_lo == 0) & (_dest_hi == 0); \ | ||||
| 857 | calculate_n_flag(_dest_hi) \ | ||||
| 858 | |||||
| 859 | #define arm_multiply_long_flags_no(_dest_lo, _dest_hi) \ | ||||
| 860 | |||||
| 861 | #define arm_multiply(add_op, flags) \ | ||||
| 862 | { \ | ||||
| 863 | u32 dest; \ | ||||
| 864 | arm_decode_multiply(); \ | ||||
| 865 | dest = (reg[rm] * reg[rs]) add_op; \ | ||||
| 866 | arm_multiply_flags_##flags(dest); \ | ||||
| 867 | reg[rd] = dest; \ | ||||
| 868 | arm_pc_offset(4); \ | ||||
| 869 | } \ | ||||
| 870 | |||||
| 871 | #define arm_multiply_long_addop(type) \ | ||||
| 872 | + ((type##64)((((type##64)reg[rdhi]) << 32) | reg[rdlo])); \ | ||||
| 873 | |||||
| 874 | #define arm_multiply_long(add_op, flags, type) \ | ||||
| 875 | { \ | ||||
| 876 | type##64 dest; \ | ||||
| 877 | u32 dest_lo; \ | ||||
| 878 | u32 dest_hi; \ | ||||
| 879 | arm_decode_multiply_long(); \ | ||||
| 880 | dest = ((type##64)((type##32)reg[rm]) * \ | ||||
| 881 | (type##64)((type##32)reg[rn])) add_op; \ | ||||
| 882 | dest_lo = (u32)dest; \ | ||||
| 883 | dest_hi = (u32)(dest >> 32); \ | ||||
| 884 | arm_multiply_long_flags_##flags(dest_lo, dest_hi); \ | ||||
| 885 | reg[rdlo] = dest_lo; \ | ||||
| 886 | reg[rdhi] = dest_hi; \ | ||||
| 887 | arm_pc_offset(4); \ | ||||
| 888 | } \ | ||||
| 889 | |||||
| 890 | const u32 psr_masks[16] = | ||||
| 891 | { | ||||
| 892 | 0x00000000, 0x000000FF, 0x0000FF00, 0x0000FFFF, 0x00FF0000, | ||||
| 893 | 0x00FF00FF, 0x00FFFF00, 0x00FFFFFF, 0xFF000000, 0xFF0000FF, | ||||
| 894 | 0xFF00FF00, 0xFF00FFFF, 0xFFFF0000, 0xFFFF00FF, 0xFFFFFF00, | ||||
| 895 | 0xFFFFFFFF | ||||
| 896 | }; | ||||
| 897 | |||||
| 898 | #define arm_psr_read(dummy, psr_reg) \ | ||||
| 899 | collapse_flags(); \ | ||||
| 900 | reg[rd] = psr_reg \ | ||||
| 901 | |||||
| 902 | #define arm_psr_store_cpsr(source) \ | ||||
| 903 | reg[REG_CPSR] = (source & store_mask) | (reg[REG_CPSR] & (~store_mask)); \ | ||||
| 904 | extract_flags(); \ | ||||
| 905 | if(store_mask & 0xFF) \ | ||||
| 906 | { \ | ||||
| 907 | set_cpu_mode(cpu_modes[reg[REG_CPSR] & 0x1F]); \ | ||||
| 908 | check_for_interrupts(); \ | ||||
| 909 | } \ | ||||
| 910 | |||||
| 911 | #define arm_psr_store_spsr(source) \ | ||||
| 912 | u32 _psr = spsr[reg[CPU_MODE]]; \ | ||||
| 913 | spsr[reg[CPU_MODE]] = (source & store_mask) | (_psr & (~store_mask)) \ | ||||
| 914 | |||||
| 915 | #define arm_psr_store(source, psr_reg) \ | ||||
| 916 | const u32 store_mask = psr_masks[psr_field]; \ | ||||
| 917 | arm_psr_store_##psr_reg(source) \ | ||||
| 918 | |||||
| 919 | #define arm_psr_src_reg reg[rm] | ||||
| 920 | |||||
| 921 | #define arm_psr_src_imm imm | ||||
| 922 | |||||
| 923 | #define arm_psr(op_type, transfer_type, psr_reg) \ | ||||
| 924 | { \ | ||||
| 925 | arm_decode_psr_##op_type(); \ | ||||
| 926 | arm_pc_offset(4); \ | ||||
| 927 | arm_psr_##transfer_type(arm_psr_src_##op_type, psr_reg); \ | ||||
| 928 | } \ | ||||
| 929 | |||||
| 930 | #define arm_data_trans_reg() \ | ||||
| 931 | arm_decode_data_trans_reg(); \ | ||||
| 932 | calculate_reg_offset() \ | ||||
| 933 | |||||
| 934 | #define arm_data_trans_imm() \ | ||||
| 935 | arm_decode_data_trans_imm() \ | ||||
| 936 | |||||
| 937 | #define arm_data_trans_half_reg() \ | ||||
| 938 | arm_decode_half_trans_r() \ | ||||
| 939 | |||||
| 940 | #define arm_data_trans_half_imm() \ | ||||
| 941 | arm_decode_half_trans_of() \ | ||||
| 942 | |||||
| 943 | #define aligned_address_mask8 0xF0000000 | ||||
| 944 | #define aligned_address_mask16 0xF0000001 | ||||
| 945 | #define aligned_address_mask32 0xF0000003 | ||||
| 946 | |||||
| 947 | #define fast_read_memory(size, type, address, dest) \ | ||||
| 948 | { \ | ||||
| 949 | u8 *map; \ | ||||
| 950 | u32 _address = address; \ | ||||
| 951 | \ | ||||
| 952 | if(_address < 0x10000000) \ | ||||
| 953 | { \ | ||||
| 954 | memory_region_access_read_##type[_address >> 24]++; \ | ||||
| 955 | memory_reads_##type++; \ | ||||
| 956 | } \ | ||||
| 957 | if(((_address >> 24) == 0) && (pc >= 0x4000)) \ | ||||
| 958 | { \ | ||||
| 959 | dest = *((type *)((u8 *)&bios_read_protect + (_address & 0x03))); \ | ||||
| 960 | } \ | ||||
| 961 | else \ | ||||
| 962 | \ | ||||
| 963 | if(((_address & aligned_address_mask##size) == 0) && \ | ||||
| 964 | (map = memory_map_read[address >> 15])) \ | ||||
| 965 | { \ | ||||
| 966 | dest = *((type *)((u8 *)map + (_address & 0x7FFF))); \ | ||||
| 967 | } \ | ||||
| 968 | else \ | ||||
| 969 | { \ | ||||
| 970 | dest = (type)read_memory##size(_address); \ | ||||
| 971 | } \ | ||||
| 972 | } \ | ||||
| 973 | |||||
| 974 | #define fast_read_memory_s16(address, dest) \ | ||||
| 975 | { \ | ||||
| 976 | u8 *map; \ | ||||
| 977 | u32 _address = address; \ | ||||
| 978 | if(_address < 0x10000000) \ | ||||
| 979 | { \ | ||||
| 980 | memory_region_access_read_s16[_address >> 24]++; \ | ||||
| 981 | memory_reads_s16++; \ | ||||
| 982 | } \ | ||||
| 983 | if(((_address & aligned_address_mask16) == 0) && \ | ||||
| 984 | (map = memory_map_read[_address >> 15])) \ | ||||
| 985 | { \ | ||||
| 986 | dest = *((s16 *)((u8 *)map + (_address & 0x7FFF))); \ | ||||
| 987 | } \ | ||||
| 988 | else \ | ||||
| 989 | { \ | ||||
| 990 | dest = (s16)read_memory16_signed(_address); \ | ||||
| 991 | } \ | ||||
| 992 | } \ | ||||
| 993 | |||||
| 994 | |||||
| 995 | #define fast_write_memory(size, type, address, value) \ | ||||
| 996 | { \ | ||||
| 997 | u8 *map; \ | ||||
| 998 | u32 _address = (address) & ~(aligned_address_mask##size & 0x03); \ | ||||
| 999 | if(_address < 0x10000000) \ | ||||
| 1000 | { \ | ||||
| 1001 | memory_region_access_write_##type[_address >> 24]++; \ | ||||
| 1002 | memory_writes_##type++; \ | ||||
| 1003 | } \ | ||||
| 1004 | \ | ||||
| 1005 | if(((_address & aligned_address_mask##size) == 0) && \ | ||||
| 1006 | (map = memory_map_write[_address >> 15])) \ | ||||
| 1007 | { \ | ||||
| 1008 | *((type *)((u8 *)map + (_address & 0x7FFF))) = value; \ | ||||
| 1009 | } \ | ||||
| 1010 | else \ | ||||
| 1011 | { \ | ||||
| 1012 | cpu_alert = write_memory##size(_address, value); \ | ||||
| 1013 | if(cpu_alert) \ | ||||
| 1014 | goto alert; \ | ||||
| 1015 | } \ | ||||
| 1016 | } \ | ||||
| 1017 | |||||
| 1018 | #define load_aligned32(address, dest) \ | ||||
| 1019 | { \ | ||||
| 1020 | u8 *map = memory_map_read[address >> 15]; \ | ||||
| 1021 | if(address < 0x10000000) \ | ||||
| 1022 | { \ | ||||
| 1023 | memory_region_access_read_u32[address >> 24]++; \ | ||||
| 1024 | memory_reads_u32++; \ | ||||
| 1025 | } \ | ||||
| 1026 | if(map) \ | ||||
| 1027 | { \ | ||||
| 1028 | dest = address32(map, address & 0x7FFF); \ | ||||
| 1029 | } \ | ||||
| 1030 | else \ | ||||
| 1031 | { \ | ||||
| 1032 | dest = read_memory32(address); \ | ||||
| 1033 | } \ | ||||
| 1034 | } \ | ||||
| 1035 | |||||
| 1036 | #define store_aligned32(address, value) \ | ||||
| 1037 | { \ | ||||
| 1038 | u8 *map = memory_map_write[address >> 15]; \ | ||||
| 1039 | if(address < 0x10000000) \ | ||||
| 1040 | { \ | ||||
| 1041 | memory_region_access_write_u32[address >> 24]++; \ | ||||
| 1042 | memory_writes_u32++; \ | ||||
| 1043 | } \ | ||||
| 1044 | if(map) \ | ||||
| 1045 | { \ | ||||
| 1046 | address32(map, address & 0x7FFF) = value; \ | ||||
| 1047 | } \ | ||||
| 1048 | else \ | ||||
| 1049 | { \ | ||||
| 1050 | cpu_alert = write_memory32(address, value); \ | ||||
| 1051 | if(cpu_alert) \ | ||||
| 1052 | goto alert; \ | ||||
| 1053 | } \ | ||||
| 1054 | } \ | ||||
| 1055 | |||||
| 1056 | #define load_memory_u8(address, dest) \ | ||||
| 1057 | fast_read_memory(8, u8, address, dest) \ | ||||
| 1058 | |||||
| 1059 | #define load_memory_u16(address, dest) \ | ||||
| 1060 | fast_read_memory(16, u16, address, dest) \ | ||||
| 1061 | |||||
| 1062 | #define load_memory_u32(address, dest) \ | ||||
| 1063 | fast_read_memory(32, u32, address, dest) \ | ||||
| 1064 | |||||
| 1065 | #define load_memory_s8(address, dest) \ | ||||
| 1066 | fast_read_memory(8, s8, address, dest) \ | ||||
| 1067 | |||||
| 1068 | #define load_memory_s16(address, dest) \ | ||||
| 1069 | fast_read_memory_s16(address, dest) \ | ||||
| 1070 | |||||
| 1071 | #define store_memory_u8(address, value) \ | ||||
| 1072 | fast_write_memory(8, u8, address, value) \ | ||||
| 1073 | |||||
| 1074 | #define store_memory_u16(address, value) \ | ||||
| 1075 | fast_write_memory(16, u16, address, value) \ | ||||
| 1076 | |||||
| 1077 | #define store_memory_u32(address, value) \ | ||||
| 1078 | fast_write_memory(32, u32, address, value) \ | ||||
| 1079 | |||||
| 1080 | #define no_op \ | ||||
| 1081 | |||||
| 1082 | #define arm_access_memory_writeback_yes(off_op) \ | ||||
| 1083 | reg[rn] = address off_op \ | ||||
| 1084 | |||||
| 1085 | #define arm_access_memory_writeback_no(off_op) \ | ||||
| 1086 | |||||
| 1087 | #define arm_access_memory_pc_preadjust_load() \ | ||||
| 1088 | |||||
| 1089 | #define arm_access_memory_pc_preadjust_store() \ | ||||
| 1090 | u32 reg_op = reg[rd]; \ | ||||
| 1091 | if(rd == 15) \ | ||||
| 1092 | reg_op += 4 \ | ||||
| 1093 | |||||
| 1094 | #define arm_access_memory_pc_postadjust_load() \ | ||||
| 1095 | arm_update_pc() \ | ||||
| 1096 | |||||
| 1097 | #define arm_access_memory_pc_postadjust_store() \ | ||||
| 1098 | |||||
| 1099 | #define load_reg_op reg[rd] \ | ||||
| 1100 | |||||
| 1101 | #define store_reg_op reg_op \ | ||||
| 1102 | |||||
| 1103 | #define arm_access_memory(access_type, off_op, off_type, mem_type, \ | ||||
| 1104 | wb, wb_off_op) \ | ||||
| 1105 | { \ | ||||
| 1106 | arm_pc_offset(8); \ | ||||
| 1107 | arm_data_trans_##off_type(); \ | ||||
| 1108 | u32 address = reg[rn] off_op; \ | ||||
| 1109 | arm_access_memory_pc_preadjust_##access_type(); \ | ||||
| 1110 | \ | ||||
| 1111 | arm_pc_offset(-4); \ | ||||
| 1112 | arm_access_memory_writeback_##wb(wb_off_op); \ | ||||
| 1113 | access_type##_memory_##mem_type(address, access_type##_reg_op); \ | ||||
| 1114 | arm_access_memory_pc_postadjust_##access_type(); \ | ||||
| 1115 | } \ | ||||
| 1116 | |||||
| 1117 | #define word_bit_count(word) \ | ||||
| 1118 | (bit_count[word >> 8] + bit_count[word & 0xFF]) \ | ||||
| 1119 | |||||
| 1120 | #define sprint_no(access_type, offset_type, writeback_type) \ | ||||
| 1121 | |||||
| 1122 | #define sprint_yes(access_type, offset_type, writeback_type) \ | ||||
| 1123 | printf("sbit on %s %s %s\n", #access_type, #offset_type, #writeback_type) \ | ||||
| 1124 | |||||
| 1125 | #define arm_block_writeback_load() \ | ||||
| 1126 | if(!((reg_list >> rn) & 0x01)) \ | ||||
| 1127 | { \ | ||||
| 1128 | reg[rn] = address; \ | ||||
| 1129 | } \ | ||||
| 1130 | |||||
| 1131 | #define arm_block_writeback_store() \ | ||||
| 1132 | reg[rn] = address \ | ||||
| 1133 | |||||
| 1134 | #define arm_block_writeback_yes(access_type) \ | ||||
| 1135 | arm_block_writeback_##access_type() \ | ||||
| 1136 | |||||
| 1137 | #define arm_block_writeback_no(access_type) \ | ||||
| 1138 | |||||
| 1139 | #define load_block_memory(address, dest) \ | ||||
| 1140 | dest = address32(address_region, (address + offset) & 0x7FFF) \ | ||||
| 1141 | |||||
| 1142 | #define store_block_memory(address, dest) \ | ||||
| 1143 | address32(address_region, (address + offset) & 0x7FFF) = dest \ | ||||
| 1144 | |||||
| 1145 | #define arm_block_memory_offset_down_a() \ | ||||
| 1146 | (base - (word_bit_count(reg_list) * 4) + 4) \ | ||||
| 1147 | |||||
| 1148 | #define arm_block_memory_offset_down_b() \ | ||||
| 1149 | (base - (word_bit_count(reg_list) * 4)) \ | ||||
| 1150 | |||||
| 1151 | #define arm_block_memory_offset_no() \ | ||||
| 1152 | (base) \ | ||||
| 1153 | |||||
| 1154 | #define arm_block_memory_offset_up() \ | ||||
| 1155 | (base + 4) \ | ||||
| 1156 | |||||
| 1157 | #define arm_block_memory_writeback_down() \ | ||||
| 1158 | reg[rn] = base - (word_bit_count(reg_list) * 4) \ | ||||
| 1159 | |||||
| 1160 | #define arm_block_memory_writeback_up() \ | ||||
| 1161 | reg[rn] = base + (word_bit_count(reg_list) * 4) \ | ||||
| 1162 | |||||
| 1163 | #define arm_block_memory_writeback_no() \ | ||||
| 1164 | |||||
| 1165 | #define arm_block_memory_load_pc() \ | ||||
| 1166 | load_aligned32(address, pc); \ | ||||
| 1167 | reg[REG_PC] = pc \ | ||||
| 1168 | |||||
| 1169 | #define arm_block_memory_store_pc() \ | ||||
| 1170 | store_aligned32(address, pc + 4) \ | ||||
| 1171 | |||||
| 1172 | #define arm_block_memory(access_type, offset_type, writeback_type, s_bit) \ | ||||
| 1173 | { \ | ||||
| 1174 | arm_decode_block_trans(); \ | ||||
| 1175 | u32 base = reg[rn]; \ | ||||
| 1176 | u32 address = arm_block_memory_offset_##offset_type() & 0xFFFFFFFC; \ | ||||
| 1177 | u32 i; \ | ||||
| 1178 | \ | ||||
| 1179 | arm_block_memory_writeback_##writeback_type(); \ | ||||
| 1180 | \ | ||||
| 1181 | for(i = 0; i < 15; i++) \ | ||||
| 1182 | { \ | ||||
| 1183 | if((reg_list >> i) & 0x01) \ | ||||
| 1184 | { \ | ||||
| 1185 | access_type##_aligned32(address, reg[i]); \ | ||||
| 1186 | address += 4; \ | ||||
| 1187 | } \ | ||||
| 1188 | } \ | ||||
| 1189 | \ | ||||
| 1190 | arm_pc_offset(4); \ | ||||
| 1191 | if(reg_list & 0x8000) \ | ||||
| 1192 | { \ | ||||
| 1193 | arm_block_memory_##access_type##_pc(); \ | ||||
| 1194 | } \ | ||||
| 1195 | } \ | ||||
| 1196 | |||||
| 1197 | #define arm_swap(type) \ | ||||
| 1198 | { \ | ||||
| 1199 | arm_decode_swap(); \ | ||||
| 1200 | u32 temp; \ | ||||
| 1201 | load_memory_##type(reg[rn], temp); \ | ||||
| 1202 | store_memory_##type(reg[rn], reg[rm]); \ | ||||
| 1203 | reg[rd] = temp; \ | ||||
| 1204 | arm_pc_offset(4); \ | ||||
| 1205 | } \ | ||||
| 1206 | |||||
| 1207 | #define arm_next_instruction() \ | ||||
| 1208 | { \ | ||||
| 1209 | arm_pc_offset(4); \ | ||||
| 1210 | goto skip_instruction; \ | ||||
| 1211 | } \ | ||||
| 1212 | |||||
| 1213 | #define thumb_update_pc() \ | ||||
| 1214 | pc = reg[REG_PC] \ | ||||
| 1215 | |||||
| 1216 | #define thumb_pc_offset(val) \ | ||||
| 1217 | pc += val; \ | ||||
| 1218 | reg[REG_PC] = pc \ | ||||
| 1219 | |||||
| 1220 | #define thumb_pc_offset_update(val) \ | ||||
| 1221 | pc += val; \ | ||||
| 1222 | reg[REG_PC] = pc \ | ||||
| 1223 | |||||
| 1224 | #define thumb_pc_offset_update_direct(val) \ | ||||
| 1225 | pc = val; \ | ||||
| 1226 | reg[REG_PC] = pc \ | ||||
| 1227 | |||||
| 1228 | // Types: add_sub, add_sub_imm, alu_op, imm | ||||
| 1229 | // Affects N/Z/C/V flags | ||||
| 1230 | |||||
| 1231 | #define thumb_add(type, dest_reg, src_a, src_b) \ | ||||
| 1232 | { \ | ||||
| 1233 | thumb_decode_##type(); \ | ||||
| 1234 | const u32 _sa = src_a; \ | ||||
| 1235 | const u32 _sb = src_b; \ | ||||
| 1236 | u32 dest = _sa + _sb; \ | ||||
| 1237 | calculate_flags_add(dest, src_a, src_b); \ | ||||
| 1238 | reg[dest_reg] = dest; \ | ||||
| 1239 | thumb_pc_offset(2); \ | ||||
| 1240 | } \ | ||||
| 1241 | |||||
| 1242 | #define thumb_add_noflags(type, dest_reg, src_a, src_b) \ | ||||
| 1243 | { \ | ||||
| 1244 | thumb_decode_##type(); \ | ||||
| 1245 | u32 dest = src_a + src_b; \ | ||||
| 1246 | reg[dest_reg] = dest; \ | ||||
| 1247 | thumb_pc_offset(2); \ | ||||
| 1248 | } \ | ||||
| 1249 | |||||
| 1250 | #define thumb_sub(type, dest_reg, src_a, src_b) \ | ||||
| 1251 | { \ | ||||
| 1252 | thumb_decode_##type(); \ | ||||
| 1253 | const u32 _sa = src_a; \ | ||||
| 1254 | const u32 _sb = src_b; \ | ||||
| 1255 | u32 dest = _sa - _sb; \ | ||||
| 1256 | calculate_flags_sub(dest, src_a, src_b); \ | ||||
| 1257 | reg[dest_reg] = dest; \ | ||||
| 1258 | thumb_pc_offset(2); \ | ||||
| 1259 | } \ | ||||
| 1260 | |||||
| 1261 | // Affects N/Z flags | ||||
| 1262 | |||||
| 1263 | #define thumb_logic(type, dest_reg, expr) \ | ||||
| 1264 | { \ | ||||
| 1265 | thumb_decode_##type(); \ | ||||
| 1266 | u32 dest = expr; \ | ||||
| 1267 | calculate_flags_logic(dest); \ | ||||
| 1268 | reg[dest_reg] = dest; \ | ||||
| 1269 | thumb_pc_offset(2); \ | ||||
| 1270 | } \ | ||||
| 1271 | |||||
| 1272 | // Decode types: shift, alu_op | ||||
| 1273 | // Operation types: lsl, lsr, asr, ror | ||||
| 1274 | // Affects N/Z/C flags | ||||
| 1275 | |||||
| 1276 | #define thumb_shift_lsl_reg() \ | ||||
| 1277 | u32 shift = reg[rs]; \ | ||||
| 1278 | u32 dest = reg[rd]; \ | ||||
| 1279 | if(shift != 0) \ | ||||
| 1280 | { \ | ||||
| 1281 | if(shift > 31) \ | ||||
| 1282 | { \ | ||||
| 1283 | if(shift == 32) \ | ||||
| 1284 | c_flag = dest & 0x01; \ | ||||
| 1285 | else \ | ||||
| 1286 | c_flag = 0; \ | ||||
| 1287 | dest = 0; \ | ||||
| 1288 | } \ | ||||
| 1289 | else \ | ||||
| 1290 | { \ | ||||
| 1291 | c_flag = (dest >> (32 - shift)) & 0x01; \ | ||||
| 1292 | dest <<= shift; \ | ||||
| 1293 | } \ | ||||
| 1294 | } \ | ||||
| 1295 | |||||
| 1296 | #define thumb_shift_lsr_reg() \ | ||||
| 1297 | u32 shift = reg[rs]; \ | ||||
| 1298 | u32 dest = reg[rd]; \ | ||||
| 1299 | if(shift != 0) \ | ||||
| 1300 | { \ | ||||
| 1301 | if(shift > 31) \ | ||||
| 1302 | { \ | ||||
| 1303 | if(shift == 32) \ | ||||
| 1304 | c_flag = dest >> 31; \ | ||||
| 1305 | else \ | ||||
| 1306 | c_flag = 0; \ | ||||
| 1307 | dest = 0; \ | ||||
| 1308 | } \ | ||||
| 1309 | else \ | ||||
| 1310 | { \ | ||||
| 1311 | c_flag = (dest >> (shift - 1)) & 0x01; \ | ||||
| 1312 | dest >>= shift; \ | ||||
| 1313 | } \ | ||||
| 1314 | } \ | ||||
| 1315 | |||||
| 1316 | #define thumb_shift_asr_reg() \ | ||||
| 1317 | u32 shift = reg[rs]; \ | ||||
| 1318 | u32 dest = reg[rd]; \ | ||||
| 1319 | if(shift != 0) \ | ||||
| 1320 | { \ | ||||
| 1321 | if(shift > 31) \ | ||||
| 1322 | { \ | ||||
| 1323 | dest = (s32)dest >> 31; \ | ||||
| 1324 | c_flag = dest & 0x01; \ | ||||
| 1325 | } \ | ||||
| 1326 | else \ | ||||
| 1327 | { \ | ||||
| 1328 | c_flag = (dest >> (shift - 1)) & 0x01; \ | ||||
| 1329 | dest = (s32)dest >> shift; \ | ||||
| 1330 | } \ | ||||
| 1331 | } \ | ||||
| 1332 | |||||
| 1333 | #define thumb_shift_ror_reg() \ | ||||
| 1334 | u32 shift = reg[rs]; \ | ||||
| 1335 | u32 dest = reg[rd]; \ | ||||
| 1336 | if(shift != 0) \ | ||||
| 1337 | { \ | ||||
| 1338 | c_flag = (dest >> (shift - 1)) & 0x01; \ | ||||
| 1339 | ror(dest, dest, shift); \ | ||||
| 1340 | } \ | ||||
| 1341 | |||||
| 1342 | #define thumb_shift_lsl_imm() \ | ||||
| 1343 | u32 dest = reg[rs]; \ | ||||
| 1344 | if(imm != 0) \ | ||||
| 1345 | { \ | ||||
| 1346 | c_flag = (dest >> (32 - imm)) & 0x01; \ | ||||
| 1347 | dest <<= imm; \ | ||||
| 1348 | } \ | ||||
| 1349 | |||||
| 1350 | #define thumb_shift_lsr_imm() \ | ||||
| 1351 | u32 dest; \ | ||||
| 1352 | if(imm == 0) \ | ||||
| 1353 | { \ | ||||
| 1354 | dest = 0; \ | ||||
| 1355 | c_flag = reg[rs] >> 31; \ | ||||
| 1356 | } \ | ||||
| 1357 | else \ | ||||
| 1358 | { \ | ||||
| 1359 | dest = reg[rs]; \ | ||||
| 1360 | c_flag = (dest >> (imm - 1)) & 0x01; \ | ||||
| 1361 | dest >>= imm; \ | ||||
| 1362 | } \ | ||||
| 1363 | |||||
| 1364 | #define thumb_shift_asr_imm() \ | ||||
| 1365 | u32 dest; \ | ||||
| 1366 | if(imm == 0) \ | ||||
| 1367 | { \ | ||||
| 1368 | dest = (s32)reg[rs] >> 31; \ | ||||
| 1369 | c_flag = dest & 0x01; \ | ||||
| 1370 | } \ | ||||
| 1371 | else \ | ||||
| 1372 | { \ | ||||
| 1373 | dest = reg[rs]; \ | ||||
| 1374 | c_flag = (dest >> (imm - 1)) & 0x01; \ | ||||
| 1375 | dest = (s32)dest >> imm; \ | ||||
| 1376 | } \ | ||||
| 1377 | |||||
| 1378 | #define thumb_shift_ror_imm() \ | ||||
| 1379 | u32 dest = reg[rs]; \ | ||||
| 1380 | if(imm == 0) \ | ||||
| 1381 | { \ | ||||
| 1382 | u32 old_c_flag = c_flag; \ | ||||
| 1383 | c_flag = dest & 0x01; \ | ||||
| 1384 | dest = (dest >> 1) | (old_c_flag << 31); \ | ||||
| 1385 | } \ | ||||
| 1386 | else \ | ||||
| 1387 | { \ | ||||
| 1388 | c_flag = (dest >> (imm - 1)) & 0x01; \ | ||||
| 1389 | ror(dest, dest, imm); \ | ||||
| 1390 | } \ | ||||
| 1391 | |||||
| 1392 | #define thumb_shift(decode_type, op_type, value_type) \ | ||||
| 1393 | { \ | ||||
| 1394 | thumb_decode_##decode_type(); \ | ||||
| 1395 | thumb_shift_##op_type##_##value_type(); \ | ||||
| 1396 | calculate_flags_logic(dest); \ | ||||
| 1397 | reg[rd] = dest; \ | ||||
| 1398 | thumb_pc_offset(2); \ | ||||
| 1399 | } \ | ||||
| 1400 | |||||
| 1401 | #define thumb_test_add(type, src_a, src_b) \ | ||||
| 1402 | { \ | ||||
| 1403 | thumb_decode_##type(); \ | ||||
| 1404 | const u32 _sa = src_a; \ | ||||
| 1405 | const u32 _sb = src_b; \ | ||||
| 1406 | u32 dest = _sa + _sb; \ | ||||
| 1407 | calculate_flags_add(dest, src_a, src_b); \ | ||||
| 1408 | thumb_pc_offset(2); \ | ||||
| 1409 | } \ | ||||
| 1410 | |||||
| 1411 | #define thumb_test_sub(type, src_a, src_b) \ | ||||
| 1412 | { \ | ||||
| 1413 | thumb_decode_##type(); \ | ||||
| 1414 | const u32 _sa = src_a; \ | ||||
| 1415 | const u32 _sb = src_b; \ | ||||
| 1416 | u32 dest = _sa - _sb; \ | ||||
| 1417 | calculate_flags_sub(dest, src_a, src_b); \ | ||||
| 1418 | thumb_pc_offset(2); \ | ||||
| 1419 | } \ | ||||
| 1420 | |||||
| 1421 | #define thumb_test_logic(type, expr) \ | ||||
| 1422 | { \ | ||||
| 1423 | thumb_decode_##type(); \ | ||||
| 1424 | u32 dest = expr; \ | ||||
| 1425 | calculate_flags_logic(dest); \ | ||||
| 1426 | thumb_pc_offset(2); \ | ||||
| 1427 | } | ||||
| 1428 | |||||
| 1429 | #define thumb_hireg_op(expr) \ | ||||
| 1430 | { \ | ||||
| 1431 | thumb_pc_offset(4); \ | ||||
| 1432 | thumb_decode_hireg_op(); \ | ||||
| 1433 | u32 dest = expr; \ | ||||
| 1434 | thumb_pc_offset(-2); \ | ||||
| 1435 | if(rd == 15) \ | ||||
| 1436 | { \ | ||||
| 1437 | reg[REG_PC] = dest & ~0x01; \ | ||||
| 1438 | thumb_update_pc(); \ | ||||
| 1439 | } \ | ||||
| 1440 | else \ | ||||
| 1441 | { \ | ||||
| 1442 | reg[rd] = dest; \ | ||||
| 1443 | } \ | ||||
| 1444 | } \ | ||||
| 1445 | |||||
| 1446 | // Operation types: imm, mem_reg, mem_imm | ||||
| 1447 | |||||
| 1448 | #define thumb_access_memory(access_type, op_type, address, reg_op, \ | ||||
| 1449 | mem_type) \ | ||||
| 1450 | { \ | ||||
| 1451 | thumb_decode_##op_type(); \ | ||||
| 1452 | access_type##_memory_##mem_type(address, reg_op); \ | ||||
| 1453 | thumb_pc_offset(2); \ | ||||
| 1454 | } \ | ||||
| 1455 | |||||
| 1456 | #define thumb_block_address_preadjust_no_op() \ | ||||
| 1457 | |||||
| 1458 | #define thumb_block_address_preadjust_up() \ | ||||
| 1459 | address += bit_count[reg_list] * 4 \ | ||||
| 1460 | |||||
| 1461 | #define thumb_block_address_preadjust_down() \ | ||||
| 1462 | address -= bit_count[reg_list] * 4 \ | ||||
| 1463 | |||||
| 1464 | #define thumb_block_address_preadjust_push_lr() \ | ||||
| 1465 | address -= (bit_count[reg_list] + 1) * 4 \ | ||||
| 1466 | |||||
| 1467 | #define thumb_block_address_postadjust_no_op() \ | ||||
| 1468 | |||||
| 1469 | #define thumb_block_address_postadjust_up() \ | ||||
| 1470 | address += offset \ | ||||
| 1471 | |||||
| 1472 | #define thumb_block_address_postadjust_down() \ | ||||
| 1473 | address -= offset \ | ||||
| 1474 | |||||
| 1475 | #define thumb_block_address_postadjust_pop_pc() \ | ||||
| 1476 | load_memory_u32(address + offset, pc); \ | ||||
| 1477 | pc &= ~0x01; \ | ||||
| 1478 | reg[REG_PC] = pc; \ | ||||
| 1479 | address += offset + 4 \ | ||||
| 1480 | |||||
| 1481 | #define thumb_block_address_postadjust_push_lr() \ | ||||
| 1482 | store_memory_u32(address + offset, reg[REG_LR]); \ | ||||
| 1483 | |||||
| 1484 | #define thumb_block_memory_wb_load(base_reg) \ | ||||
| 1485 | if(!((reg_list >> base_reg) & 0x01)) \ | ||||
| 1486 | { \ | ||||
| 1487 | reg[base_reg] = address; \ | ||||
| 1488 | } \ | ||||
| 1489 | |||||
| 1490 | #define thumb_block_memory_wb_store(base_reg) \ | ||||
| 1491 | reg[base_reg] = address \ | ||||
| 1492 | |||||
| 1493 | #define thumb_block_memory(access_type, pre_op, post_op, base_reg) \ | ||||
| 1494 | { \ | ||||
| 1495 | u32 i; \ | ||||
| 1496 | u32 offset = 0; \ | ||||
| 1497 | thumb_decode_rlist(); \ | ||||
| 1498 | using_register(thumb, base_reg, memory_base); \ | ||||
| 1499 | u32 address = reg[base_reg] & ~0x03; \ | ||||
| 1500 | thumb_block_address_preadjust_##pre_op(); \ | ||||
| 1501 | \ | ||||
| 1502 | for(i = 0; i < 8; i++) \ | ||||
| 1503 | { \ | ||||
| 1504 | if((reg_list >> i) & 1) \ | ||||
| 1505 | { \ | ||||
| 1506 | access_type##_aligned32(address + offset, reg[i]); \ | ||||
| 1507 | offset += 4; \ | ||||
| 1508 | } \ | ||||
| 1509 | } \ | ||||
| 1510 | \ | ||||
| 1511 | thumb_pc_offset(2); \ | ||||
| 1512 | \ | ||||
| 1513 | thumb_block_address_postadjust_##post_op(); \ | ||||
| 1514 | thumb_block_memory_wb_##access_type(base_reg); \ | ||||
| 1515 | } \ | ||||
| 1516 | |||||
| 1517 | #define thumb_conditional_branch(condition) \ | ||||
| 1518 | { \ | ||||
| 1519 | thumb_decode_branch_cond(); \ | ||||
| 1520 | if(condition) \ | ||||
| 1521 | { \ | ||||
| 1522 | thumb_pc_offset((offset * 2) + 4); \ | ||||
| 1523 | } \ | ||||
| 1524 | else \ | ||||
| 1525 | { \ | ||||
| 1526 | thumb_pc_offset(2); \ | ||||
| 1527 | } \ | ||||
| 1528 | } \ | ||||
| 1529 | |||||
| 1530 | // When a mode change occurs from non-FIQ to non-FIQ retire the current | ||||
| 1531 | // reg[13] and reg[14] into reg_mode[cpu_mode][5] and reg_mode[cpu_mode][6] | ||||
| 1532 | // respectively and load into reg[13] and reg[14] reg_mode[new_mode][5] and | ||||
| 1533 | // reg_mode[new_mode][6]. When swapping to/from FIQ retire/load reg[8] | ||||
| 1534 | // through reg[14] to/from reg_mode[MODE_FIQ][0] through reg_mode[MODE_FIQ][6]. | ||||
| 1535 | |||||
| 1536 | u32 reg_mode[7][7]; | ||||
| 1537 | |||||
| 1538 | u32 cpu_modes[32] = | ||||
| 1539 | { | ||||
| 1540 | MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID, | ||||
| 1541 | MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID, | ||||
| 1542 | MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID, | ||||
| 1543 | MODE_INVALID, MODE_USER, MODE_FIQ, MODE_IRQ, MODE_SUPERVISOR, MODE_INVALID, | ||||
| 1544 | MODE_INVALID, MODE_INVALID, MODE_ABORT, MODE_INVALID, MODE_INVALID, | ||||
| 1545 | MODE_INVALID, MODE_INVALID, MODE_UNDEFINED, MODE_INVALID, MODE_INVALID, | ||||
| 1546 | MODE_USER | ||||
| 1547 | }; | ||||
| 1548 | |||||
| 1549 | u32 cpu_modes_cpsr[7] = { 0x10, 0x11, 0x12, 0x13, 0x17, 0x1B, 0x1F }; | ||||
| 1550 | |||||
| 1551 | // When switching modes set spsr[new_mode] to cpsr. Modifying PC as the | ||||
| 1552 | // target of a data proc instruction will set cpsr to spsr[cpu_mode]. | ||||
| 1553 | |||||
| 1554 | u32 initial_reg[64]; | ||||
| 1555 | u32 *reg = initial_reg; | ||||
| 1556 | u32 spsr[6]; | ||||
| 1557 | |||||
| 1558 | // ARM/Thumb mode is stored in the flags directly, this is simpler than | ||||
| 1559 | // shadowing it since it has a constant 1bit represenation. | ||||
| 1560 | |||||
| 1561 | char *reg_names[16] = | ||||
| 1562 | { | ||||
| 1563 | " r0", " r1", " r2", " r3", " r4", " r5", " r6", " r7", | ||||
| 1564 | " r8", " r9", "r10", " fp", " ip", " sp", " lr", " pc" | ||||
| 1565 | }; | ||||
| 1566 | |||||
| 1567 | char *cpu_mode_names[] = | ||||
| 1568 | { | ||||
| 1569 | "user", "irq", "fiq", "svsr", "abrt", "undf", "invd" | ||||
| 1570 | }; | ||||
| 1571 | |||||
| 1572 | |||||
| 1573 | #define execute_arm_instruction() \ | ||||
| 1574 | using_instruction(arm); \ | ||||
| 1575 | check_pc_region(); \ | ||||
| 1576 | pc &= ~0x03; \ | ||||
| 1577 | opcode = address32(pc_address_block, (pc & 0x7FFF)); \ | ||||
| 1578 | condition = opcode >> 28; \ | ||||
| 1579 | \ | ||||
| 1580 | switch(condition) \ | ||||
| 1581 | { \ | ||||
| 1582 | case 0x0: \ | ||||
| 1583 | /* EQ */ \ | ||||
| 1584 | if(!z_flag) \ | ||||
| 1585 | arm_next_instruction(); \ | ||||
| 1586 | break; \ | ||||
| 1587 | \ | ||||
| 1588 | case 0x1: \ | ||||
| 1589 | /* NE */ \ | ||||
| 1590 | if(z_flag) \ | ||||
| 1591 | arm_next_instruction(); \ | ||||
| 1592 | break; \ | ||||
| 1593 | \ | ||||
| 1594 | case 0x2: \ | ||||
| 1595 | /* CS */ \ | ||||
| 1596 | if(!c_flag) \ | ||||
| 1597 | arm_next_instruction(); \ | ||||
| 1598 | break; \ | ||||
| 1599 | \ | ||||
| 1600 | case 0x3: \ | ||||
| 1601 | /* CC */ \ | ||||
| 1602 | if(c_flag) \ | ||||
| 1603 | arm_next_instruction(); \ | ||||
| 1604 | break; \ | ||||
| 1605 | \ | ||||
| 1606 | case 0x4: \ | ||||
| 1607 | /* MI */ \ | ||||
| 1608 | if(!n_flag) \ | ||||
| 1609 | arm_next_instruction(); \ | ||||
| 1610 | break; \ | ||||
| 1611 | \ | ||||
| 1612 | case 0x5: \ | ||||
| 1613 | /* PL */ \ | ||||
| 1614 | if(n_flag) \ | ||||
| 1615 | arm_next_instruction(); \ | ||||
| 1616 | break; \ | ||||
| 1617 | \ | ||||
| 1618 | case 0x6: \ | ||||
| 1619 | /* VS */ \ | ||||
| 1620 | if(!v_flag) \ | ||||
| 1621 | arm_next_instruction(); \ | ||||
| 1622 | break; \ | ||||
| 1623 | \ | ||||
| 1624 | case 0x7: \ | ||||
| 1625 | /* VC */ \ | ||||
| 1626 | if(v_flag) \ | ||||
| 1627 | arm_next_instruction(); \ | ||||
| 1628 | break; \ | ||||
| 1629 | \ | ||||
| 1630 | case 0x8: \ | ||||
| 1631 | /* HI */ \ | ||||
| 1632 | if((c_flag == 0) | z_flag) \ | ||||
| 1633 | arm_next_instruction(); \ | ||||
| 1634 | break; \ | ||||
| 1635 | \ | ||||
| 1636 | case 0x9: \ | ||||
| 1637 | /* LS */ \ | ||||
| 1638 | if(c_flag & (z_flag ^ 1)) \ | ||||
| 1639 | arm_next_instruction(); \ | ||||
| 1640 | break; \ | ||||
| 1641 | \ | ||||
| 1642 | case 0xA: \ | ||||
| 1643 | /* GE */ \ | ||||
| 1644 | if(n_flag != v_flag) \ | ||||
| 1645 | arm_next_instruction(); \ | ||||
| 1646 | break; \ | ||||
| 1647 | \ | ||||
| 1648 | case 0xB: \ | ||||
| 1649 | /* LT */ \ | ||||
| 1650 | if(n_flag == v_flag) \ | ||||
| 1651 | arm_next_instruction(); \ | ||||
| 1652 | break; \ | ||||
| 1653 | \ | ||||
| 1654 | case 0xC: \ | ||||
| 1655 | /* GT */ \ | ||||
| 1656 | if(z_flag | (n_flag != v_flag)) \ | ||||
| 1657 | arm_next_instruction(); \ | ||||
| 1658 | break; \ | ||||
| 1659 | \ | ||||
| 1660 | case 0xD: \ | ||||
| 1661 | /* LE */ \ | ||||
| 1662 | if((z_flag == 0) & (n_flag == v_flag)) \ | ||||
| 1663 | arm_next_instruction(); \ | ||||
| 1664 | break; \ | ||||
| 1665 | \ | ||||
| 1666 | case 0xE: \ | ||||
| 1667 | /* AL */ \ | ||||
| 1668 | break; \ | ||||
| 1669 | \ | ||||
| 1670 | case 0xF: \ | ||||
| 1671 | /* Reserved - treat as "never" */ \ | ||||
| 1672 | quit(); \ | ||||
| 1673 | arm_next_instruction(); \ | ||||
| 1674 | break; \ | ||||
| 1675 | } \ | ||||
| 1676 | \ | ||||
| 1677 | switch((opcode >> 20) & 0xFF) \ | ||||
| 1678 | { \ | ||||
| 1679 | case 0x00: \ | ||||
| 1680 | if((opcode & 0x90) == 0x90) \ | ||||
| 1681 | { \ | ||||
| 1682 | if(opcode & 0x20) \ | ||||
| 1683 | { \ | ||||
| 1684 | /* STRH rd, [rn], -rm */ \ | ||||
| 1685 | arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); \ | ||||
| 1686 | } \ | ||||
| 1687 | else \ | ||||
| 1688 | { \ | ||||
| 1689 | /* MUL rd, rm, rs */ \ | ||||
| 1690 | arm_multiply(no_op, no); \ | ||||
| 1691 | } \ | ||||
| 1692 | } \ | ||||
| 1693 | else \ | ||||
| 1694 | { \ | ||||
| 1695 | /* AND rd, rn, reg_op */ \ | ||||
| 1696 | arm_data_proc(reg[rn] & reg_sh, reg); \ | ||||
| 1697 | } \ | ||||
| 1698 | break; \ | ||||
| 1699 | \ | ||||
| 1700 | case 0x01: \ | ||||
| 1701 | if((opcode & 0x90) == 0x90) \ | ||||
| 1702 | { \ | ||||
| 1703 | switch((opcode >> 5) & 0x03) \ | ||||
| 1704 | { \ | ||||
| 1705 | case 0: \ | ||||
| 1706 | /* MULS rd, rm, rs */ \ | ||||
| 1707 | arm_multiply(no_op, yes); \ | ||||
| 1708 | break; \ | ||||
| 1709 | \ | ||||
| 1710 | case 1: \ | ||||
| 1711 | /* LDRH rd, [rn], -rm */ \ | ||||
| 1712 | arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); \ | ||||
| 1713 | break; \ | ||||
| 1714 | \ | ||||
| 1715 | case 2: \ | ||||
| 1716 | /* LDRSB rd, [rn], -rm */ \ | ||||
| 1717 | arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); \ | ||||
| 1718 | break; \ | ||||
| 1719 | \ | ||||
| 1720 | case 3: \ | ||||
| 1721 | /* LDRSH rd, [rn], -rm */ \ | ||||
| 1722 | arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); \ | ||||
| 1723 | break; \ | ||||
| 1724 | } \ | ||||
| 1725 | } \ | ||||
| 1726 | else \ | ||||
| 1727 | { \ | ||||
| 1728 | /* ANDS rd, rn, reg_op */ \ | ||||
| 1729 | arm_data_proc_logic_flags(reg[rn] & reg_sh, reg); \ | ||||
| 1730 | } \ | ||||
| 1731 | break; \ | ||||
| 1732 | \ | ||||
| 1733 | case 0x02: \ | ||||
| 1734 | if((opcode & 0x90) == 0x90) \ | ||||
| 1735 | { \ | ||||
| 1736 | if(opcode & 0x20) \ | ||||
| 1737 | { \ | ||||
| 1738 | /* STRH rd, [rn], -rm */ \ | ||||
| 1739 | arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); \ | ||||
| 1740 | } \ | ||||
| 1741 | else \ | ||||
| 1742 | { \ | ||||
| 1743 | /* MLA rd, rm, rs, rn */ \ | ||||
| 1744 | arm_multiply(+ reg[rn], no); \ | ||||
| 1745 | } \ | ||||
| 1746 | } \ | ||||
| 1747 | else \ | ||||
| 1748 | { \ | ||||
| 1749 | /* EOR rd, rn, reg_op */ \ | ||||
| 1750 | arm_data_proc(reg[rn] ^ reg_sh, reg); \ | ||||
| 1751 | } \ | ||||
| 1752 | break; \ | ||||
| 1753 | \ | ||||
| 1754 | case 0x03: \ | ||||
| 1755 | if((opcode & 0x90) == 0x90) \ | ||||
| 1756 | { \ | ||||
| 1757 | switch((opcode >> 5) & 0x03) \ | ||||
| 1758 | { \ | ||||
| 1759 | case 0: \ | ||||
| 1760 | /* MLAS rd, rm, rs, rn */ \ | ||||
| 1761 | arm_multiply(+ reg[rn], yes); \ | ||||
| 1762 | break; \ | ||||
| 1763 | \ | ||||
| 1764 | case 1: \ | ||||
| 1765 | /* LDRH rd, [rn], -rm */ \ | ||||
| 1766 | arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); \ | ||||
| 1767 | break; \ | ||||
| 1768 | \ | ||||
| 1769 | case 2: \ | ||||
| 1770 | /* LDRSB rd, [rn], -rm */ \ | ||||
| 1771 | arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); \ | ||||
| 1772 | break; \ | ||||
| 1773 | \ | ||||
| 1774 | case 3: \ | ||||
| 1775 | /* LDRSH rd, [rn], -rm */ \ | ||||
| 1776 | arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); \ | ||||
| 1777 | break; \ | ||||
| 1778 | } \ | ||||
| 1779 | } \ | ||||
| 1780 | else \ | ||||
| 1781 | { \ | ||||
| 1782 | /* EORS rd, rn, reg_op */ \ | ||||
| 1783 | arm_data_proc_logic_flags(reg[rn] ^ reg_sh, reg); \ | ||||
| 1784 | } \ | ||||
| 1785 | break; \ | ||||
| 1786 | \ | ||||
| 1787 | case 0x04: \ | ||||
| 1788 | if((opcode & 0x90) == 0x90) \ | ||||
| 1789 | { \ | ||||
| 1790 | /* STRH rd, [rn], -imm */ \ | ||||
| 1791 | arm_access_memory(store, no_op, half_imm, u16, yes, - offset); \ | ||||
| 1792 | } \ | ||||
| 1793 | else \ | ||||
| 1794 | { \ | ||||
| 1795 | /* SUB rd, rn, reg_op */ \ | ||||
| 1796 | arm_data_proc(reg[rn] - reg_sh, reg); \ | ||||
| 1797 | } \ | ||||
| 1798 | break; \ | ||||
| 1799 | \ | ||||
| 1800 | case 0x05: \ | ||||
| 1801 | if((opcode & 0x90) == 0x90) \ | ||||
| 1802 | { \ | ||||
| 1803 | switch((opcode >> 5) & 0x03) \ | ||||
| 1804 | { \ | ||||
| 1805 | case 1: \ | ||||
| 1806 | /* LDRH rd, [rn], -imm */ \ | ||||
| 1807 | arm_access_memory(load, no_op, half_imm, u16, yes, - offset); \ | ||||
| 1808 | break; \ | ||||
| 1809 | \ | ||||
| 1810 | case 2: \ | ||||
| 1811 | /* LDRSB rd, [rn], -imm */ \ | ||||
| 1812 | arm_access_memory(load, no_op, half_imm, s8, yes, - offset); \ | ||||
| 1813 | break; \ | ||||
| 1814 | \ | ||||
| 1815 | case 3: \ | ||||
| 1816 | /* LDRSH rd, [rn], -imm */ \ | ||||
| 1817 | arm_access_memory(load, no_op, half_imm, s16, yes, - offset); \ | ||||
| 1818 | break; \ | ||||
| 1819 | } \ | ||||
| 1820 | } \ | ||||
| 1821 | else \ | ||||
| 1822 | { \ | ||||
| 1823 | /* SUBS rd, rn, reg_op */ \ | ||||
| 1824 | arm_data_proc_sub_flags(reg[rn], reg_sh, reg); \ | ||||
| 1825 | } \ | ||||
| 1826 | break; \ | ||||
| 1827 | \ | ||||
| 1828 | case 0x06: \ | ||||
| 1829 | if((opcode & 0x90) == 0x90) \ | ||||
| 1830 | { \ | ||||
| 1831 | /* STRH rd, [rn], -imm */ \ | ||||
| 1832 | arm_access_memory(store, no_op, half_imm, u16, yes, - offset); \ | ||||
| 1833 | } \ | ||||
| 1834 | else \ | ||||
| 1835 | { \ | ||||
| 1836 | /* RSB rd, rn, reg_op */ \ | ||||
| 1837 | arm_data_proc(reg_sh - reg[rn], reg); \ | ||||
| 1838 | } \ | ||||
| 1839 | break; \ | ||||
| 1840 | \ | ||||
| 1841 | case 0x07: \ | ||||
| 1842 | if((opcode & 0x90) == 0x90) \ | ||||
| 1843 | { \ | ||||
| 1844 | switch((opcode >> 5) & 0x03) \ | ||||
| 1845 | { \ | ||||
| 1846 | case 1: \ | ||||
| 1847 | /* LDRH rd, [rn], -imm */ \ | ||||
| 1848 | arm_access_memory(load, no_op, half_imm, u16, yes, - offset); \ | ||||
| 1849 | break; \ | ||||
| 1850 | \ | ||||
| 1851 | case 2: \ | ||||
| 1852 | /* LDRSB rd, [rn], -imm */ \ | ||||
| 1853 | arm_access_memory(load, no_op, half_imm, s8, yes, - offset); \ | ||||
| 1854 | break; \ | ||||
| 1855 | \ | ||||
| 1856 | case 3: \ | ||||
| 1857 | /* LDRSH rd, [rn], -imm */ \ | ||||
| 1858 | arm_access_memory(load, no_op, half_imm, s16, yes, - offset); \ | ||||
| 1859 | break; \ | ||||
| 1860 | } \ | ||||
| 1861 | } \ | ||||
| 1862 | else \ | ||||
| 1863 | { \ | ||||
| 1864 | /* RSBS rd, rn, reg_op */ \ | ||||
| 1865 | arm_data_proc_sub_flags(reg_sh, reg[rn], reg); \ | ||||
| 1866 | } \ | ||||
| 1867 | break; \ | ||||
| 1868 | \ | ||||
| 1869 | case 0x08: \ | ||||
| 1870 | if((opcode & 0x90) == 0x90) \ | ||||
| 1871 | { \ | ||||
| 1872 | if(opcode & 0x20) \ | ||||
| 1873 | { \ | ||||
| 1874 | /* STRH rd, [rn], +rm */ \ | ||||
| 1875 | arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); \ | ||||
| 1876 | } \ | ||||
| 1877 | else \ | ||||
| 1878 | { \ | ||||
| 1879 | /* UMULL rd, rm, rs */ \ | ||||
| 1880 | arm_multiply_long(no_op, no, u); \ | ||||
| 1881 | } \ | ||||
| 1882 | } \ | ||||
| 1883 | else \ | ||||
| 1884 | { \ | ||||
| 1885 | /* ADD rd, rn, reg_op */ \ | ||||
| 1886 | arm_data_proc(reg[rn] + reg_sh, reg); \ | ||||
| 1887 | } \ | ||||
| 1888 | break; \ | ||||
| 1889 | \ | ||||
| 1890 | case 0x09: \ | ||||
| 1891 | if((opcode & 0x90) == 0x90) \ | ||||
| 1892 | { \ | ||||
| 1893 | switch((opcode >> 5) & 0x03) \ | ||||
| 1894 | { \ | ||||
| 1895 | case 0: \ | ||||
| 1896 | /* UMULLS rdlo, rdhi, rm, rs */ \ | ||||
| 1897 | arm_multiply_long(no_op, yes, u); \ | ||||
| 1898 | break; \ | ||||
| 1899 | \ | ||||
| 1900 | case 1: \ | ||||
| 1901 | /* LDRH rd, [rn], +rm */ \ | ||||
| 1902 | arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); \ | ||||
| 1903 | break; \ | ||||
| 1904 | \ | ||||
| 1905 | case 2: \ | ||||
| 1906 | /* LDRSB rd, [rn], +rm */ \ | ||||
| 1907 | arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); \ | ||||
| 1908 | break; \ | ||||
| 1909 | \ | ||||
| 1910 | case 3: \ | ||||
| 1911 | /* LDRSH rd, [rn], +rm */ \ | ||||
| 1912 | arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); \ | ||||
| 1913 | break; \ | ||||
| 1914 | } \ | ||||
| 1915 | } \ | ||||
| 1916 | else \ | ||||
| 1917 | { \ | ||||
| 1918 | /* ADDS rd, rn, reg_op */ \ | ||||
| 1919 | arm_data_proc_add_flags(reg[rn], reg_sh, reg); \ | ||||
| 1920 | } \ | ||||
| 1921 | break; \ | ||||
| 1922 | \ | ||||
| 1923 | case 0x0A: \ | ||||
| 1924 | if((opcode & 0x90) == 0x90) \ | ||||
| 1925 | { \ | ||||
| 1926 | if(opcode & 0x20) \ | ||||
| 1927 | { \ | ||||
| 1928 | /* STRH rd, [rn], +rm */ \ | ||||
| 1929 | arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); \ | ||||
| 1930 | } \ | ||||
| 1931 | else \ | ||||
| 1932 | { \ | ||||
| 1933 | /* UMLAL rd, rm, rs */ \ | ||||
| 1934 | arm_multiply_long(arm_multiply_long_addop(u), no, u); \ | ||||
| 1935 | } \ | ||||
| 1936 | } \ | ||||
| 1937 | else \ | ||||
| 1938 | { \ | ||||
| 1939 | /* ADC rd, rn, reg_op */ \ | ||||
| 1940 | arm_data_proc(reg[rn] + reg_sh + c_flag, reg); \ | ||||
| 1941 | } \ | ||||
| 1942 | break; \ | ||||
| 1943 | \ | ||||
| 1944 | case 0x0B: \ | ||||
| 1945 | if((opcode & 0x90) == 0x90) \ | ||||
| 1946 | { \ | ||||
| 1947 | switch((opcode >> 5) & 0x03) \ | ||||
| 1948 | { \ | ||||
| 1949 | case 0: \ | ||||
| 1950 | /* UMLALS rdlo, rdhi, rm, rs */ \ | ||||
| 1951 | arm_multiply_long(arm_multiply_long_addop(u), yes, u); \ | ||||
| 1952 | break; \ | ||||
| 1953 | \ | ||||
| 1954 | case 1: \ | ||||
| 1955 | /* LDRH rd, [rn], +rm */ \ | ||||
| 1956 | arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); \ | ||||
| 1957 | break; \ | ||||
| 1958 | \ | ||||
| 1959 | case 2: \ | ||||
| 1960 | /* LDRSB rd, [rn], +rm */ \ | ||||
| 1961 | arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); \ | ||||
| 1962 | break; \ | ||||
| 1963 | \ | ||||
| 1964 | case 3: \ | ||||
| 1965 | /* LDRSH rd, [rn], +rm */ \ | ||||
| 1966 | arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); \ | ||||
| 1967 | break; \ | ||||
| 1968 | } \ | ||||
| 1969 | } \ | ||||
| 1970 | else \ | ||||
| 1971 | { \ | ||||
| 1972 | /* ADCS rd, rn, reg_op */ \ | ||||
| 1973 | arm_data_proc_add_flags(reg[rn], reg_sh + c_flag, reg); \ | ||||
| 1974 | } \ | ||||
| 1975 | break; \ | ||||
| 1976 | \ | ||||
| 1977 | case 0x0C: \ | ||||
| 1978 | if((opcode & 0x90) == 0x90) \ | ||||
| 1979 | { \ | ||||
| 1980 | if(opcode & 0x20) \ | ||||
| 1981 | { \ | ||||
| 1982 | /* STRH rd, [rn], +imm */ \ | ||||
| 1983 | arm_access_memory(store, no_op, half_imm, u16, yes, + offset); \ | ||||
| 1984 | } \ | ||||
| 1985 | else \ | ||||
| 1986 | { \ | ||||
| 1987 | /* SMULL rd, rm, rs */ \ | ||||
| 1988 | arm_multiply_long(no_op, no, s); \ | ||||
| 1989 | } \ | ||||
| 1990 | } \ | ||||
| 1991 | else \ | ||||
| 1992 | { \ | ||||
| 1993 | /* SBC rd, rn, reg_op */ \ | ||||
| 1994 | arm_data_proc(reg[rn] - (reg_sh + (c_flag ^ 1)), reg); \ | ||||
| 1995 | } \ | ||||
| 1996 | break; \ | ||||
| 1997 | \ | ||||
| 1998 | case 0x0D: \ | ||||
| 1999 | if((opcode & 0x90) == 0x90) \ | ||||
| 2000 | { \ | ||||
| 2001 | switch((opcode >> 5) & 0x03) \ | ||||
| 2002 | { \ | ||||
| 2003 | case 0: \ | ||||
| 2004 | /* SMULLS rdlo, rdhi, rm, rs */ \ | ||||
| 2005 | arm_multiply_long(no_op, yes, s); \ | ||||
| 2006 | break; \ | ||||
| 2007 | \ | ||||
| 2008 | case 1: \ | ||||
| 2009 | /* LDRH rd, [rn], +imm */ \ | ||||
| 2010 | arm_access_memory(load, no_op, half_imm, u16, yes, + offset); \ | ||||
| 2011 | break; \ | ||||
| 2012 | \ | ||||
| 2013 | case 2: \ | ||||
| 2014 | /* LDRSB rd, [rn], +imm */ \ | ||||
| 2015 | arm_access_memory(load, no_op, half_imm, s8, yes, + offset); \ | ||||
| 2016 | break; \ | ||||
| 2017 | \ | ||||
| 2018 | case 3: \ | ||||
| 2019 | /* LDRSH rd, [rn], +imm */ \ | ||||
| 2020 | arm_access_memory(load, no_op, half_imm, s16, yes, + offset); \ | ||||
| 2021 | break; \ | ||||
| 2022 | } \ | ||||
| 2023 | } \ | ||||
| 2024 | else \ | ||||
| 2025 | { \ | ||||
| 2026 | /* SBCS rd, rn, reg_op */ \ | ||||
| 2027 | arm_data_proc_sub_flags(reg[rn], (reg_sh + (c_flag ^ 1)), reg); \ | ||||
| 2028 | } \ | ||||
| 2029 | break; \ | ||||
| 2030 | \ | ||||
| 2031 | case 0x0E: \ | ||||
| 2032 | if((opcode & 0x90) == 0x90) \ | ||||
| 2033 | { \ | ||||
| 2034 | if(opcode & 0x20) \ | ||||
| 2035 | { \ | ||||
| 2036 | /* STRH rd, [rn], +imm */ \ | ||||
| 2037 | arm_access_memory(store, no_op, half_imm, u16, yes, + offset); \ | ||||
| 2038 | } \ | ||||
| 2039 | else \ | ||||
| 2040 | { \ | ||||
| 2041 | /* SMLAL rd, rm, rs */ \ | ||||
| 2042 | arm_multiply_long(arm_multiply_long_addop(s), no, s); \ | ||||
| 2043 | } \ | ||||
| 2044 | } \ | ||||
| 2045 | else \ | ||||
| 2046 | { \ | ||||
| 2047 | /* RSC rd, rn, reg_op */ \ | ||||
| 2048 | arm_data_proc(reg_sh - reg[rn] + c_flag - 1, reg); \ | ||||
| 2049 | } \ | ||||
| 2050 | break; \ | ||||
| 2051 | \ | ||||
| 2052 | case 0x0F: \ | ||||
| 2053 | if((opcode & 0x90) == 0x90) \ | ||||
| 2054 | { \ | ||||
| 2055 | switch((opcode >> 5) & 0x03) \ | ||||
| 2056 | { \ | ||||
| 2057 | case 0: \ | ||||
| 2058 | /* SMLALS rdlo, rdhi, rm, rs */ \ | ||||
| 2059 | arm_multiply_long(arm_multiply_long_addop(s), yes, s); \ | ||||
| 2060 | break; \ | ||||
| 2061 | \ | ||||
| 2062 | case 1: \ | ||||
| 2063 | /* LDRH rd, [rn], +imm */ \ | ||||
| 2064 | arm_access_memory(load, no_op, half_imm, u16, yes, + offset); \ | ||||
| 2065 | break; \ | ||||
| 2066 | \ | ||||
| 2067 | case 2: \ | ||||
| 2068 | /* LDRSB rd, [rn], +imm */ \ | ||||
| 2069 | arm_access_memory(load, no_op, half_imm, s8, yes, + offset); \ | ||||
| 2070 | break; \ | ||||
| 2071 | \ | ||||
| 2072 | case 3: \ | ||||
| 2073 | /* LDRSH rd, [rn], +imm */ \ | ||||
| 2074 | arm_access_memory(load, no_op, half_imm, s16, yes, + offset); \ | ||||
| 2075 | break; \ | ||||
| 2076 | } \ | ||||
| 2077 | } \ | ||||
| 2078 | else \ | ||||
| 2079 | { \ | ||||
| 2080 | /* RSCS rd, rn, reg_op */ \ | ||||
| 2081 | arm_data_proc_sub_flags((reg_sh + c_flag - 1), reg[rn], reg); \ | ||||
| 2082 | } \ | ||||
| 2083 | break; \ | ||||
| 2084 | \ | ||||
| 2085 | case 0x10: \ | ||||
| 2086 | if((opcode & 0x90) == 0x90) \ | ||||
| 2087 | { \ | ||||
| 2088 | if(opcode & 0x20) \ | ||||
| 2089 | { \ | ||||
| 2090 | /* STRH rd, [rn - rm] */ \ | ||||
| 2091 | arm_access_memory(store, - reg[rm], half_reg, u16, no, no_op); \ | ||||
| 2092 | } \ | ||||
| 2093 | else \ | ||||
| 2094 | { \ | ||||
| 2095 | /* SWP rd, rm, [rn] */ \ | ||||
| 2096 | arm_swap(u32); \ | ||||
| 2097 | } \ | ||||
| 2098 | } \ | ||||
| 2099 | else \ | ||||
| 2100 | { \ | ||||
| 2101 | /* MRS rd, cpsr */ \ | ||||
| 2102 | arm_psr(reg, read, reg[REG_CPSR]); \ | ||||
| 2103 | } \ | ||||
| 2104 | break; \ | ||||
| 2105 | \ | ||||
| 2106 | case 0x11: \ | ||||
| 2107 | if((opcode & 0x90) == 0x90) \ | ||||
| 2108 | { \ | ||||
| 2109 | switch((opcode >> 5) & 0x03) \ | ||||
| 2110 | { \ | ||||
| 2111 | case 1: \ | ||||
| 2112 | /* LDRH rd, [rn - rm] */ \ | ||||
| 2113 | arm_access_memory(load, - reg[rm], half_reg, u16, no, no_op); \ | ||||
| 2114 | break; \ | ||||
| 2115 | \ | ||||
| 2116 | case 2: \ | ||||
| 2117 | /* LDRSB rd, [rn - rm] */ \ | ||||
| 2118 | arm_access_memory(load, - reg[rm], half_reg, s8, no, no_op); \ | ||||
| 2119 | break; \ | ||||
| 2120 | \ | ||||
| 2121 | case 3: \ | ||||
| 2122 | /* LDRSH rd, [rn - rm] */ \ | ||||
| 2123 | arm_access_memory(load, - reg[rm], half_reg, s16, no, no_op); \ | ||||
| 2124 | break; \ | ||||
| 2125 | } \ | ||||
| 2126 | } \ | ||||
| 2127 | else \ | ||||
| 2128 | { \ | ||||
| 2129 | /* TST rd, rn, reg_op */ \ | ||||
| 2130 | arm_data_proc_test_logic(reg[rn] & reg_sh, reg); \ | ||||
| 2131 | } \ | ||||
| 2132 | break; \ | ||||
| 2133 | \ | ||||
| 2134 | case 0x12: \ | ||||
| 2135 | if((opcode & 0x90) == 0x90) \ | ||||
| 2136 | { \ | ||||
| 2137 | /* STRH rd, [rn - rm]! */ \ | ||||
| 2138 | arm_access_memory(store, - reg[rm], half_reg, u16, yes, no_op); \ | ||||
| 2139 | } \ | ||||
| 2140 | else \ | ||||
| 2141 | { \ | ||||
| 2142 | if(opcode & 0x10) \ | ||||
| 2143 | { \ | ||||
| 2144 | /* BX rn */ \ | ||||
| 2145 | arm_decode_branchx(); \ | ||||
| 2146 | u32 src = reg[rn]; \ | ||||
| 2147 | if(src & 0x01) \ | ||||
| 2148 | { \ | ||||
| 2149 | src -= 1; \ | ||||
| 2150 | arm_pc_offset_update_direct(src); \ | ||||
| 2151 | reg[REG_CPSR] |= 0x20; \ | ||||
| 2152 | goto thumb_loop; \ | ||||
| 2153 | } \ | ||||
| 2154 | else \ | ||||
| 2155 | { \ | ||||
| 2156 | arm_pc_offset_update_direct(src); \ | ||||
| 2157 | } \ | ||||
| 2158 | } \ | ||||
| 2159 | else \ | ||||
| 2160 | { \ | ||||
| 2161 | /* MSR cpsr, rm */ \ | ||||
| 2162 | arm_psr(reg, store, cpsr); \ | ||||
| 2163 | } \ | ||||
| 2164 | } \ | ||||
| 2165 | break; \ | ||||
| 2166 | \ | ||||
| 2167 | case 0x13: \ | ||||
| 2168 | if((opcode & 0x90) == 0x90) \ | ||||
| 2169 | { \ | ||||
| 2170 | switch((opcode >> 5) & 0x03) \ | ||||
| 2171 | { \ | ||||
| 2172 | case 1: \ | ||||
| 2173 | /* LDRH rd, [rn - rm]! */ \ | ||||
| 2174 | arm_access_memory(load, - reg[rm], half_reg, u16, yes, no_op); \ | ||||
| 2175 | break; \ | ||||
| 2176 | \ | ||||
| 2177 | case 2: \ | ||||
| 2178 | /* LDRSB rd, [rn - rm]! */ \ | ||||
| 2179 | arm_access_memory(load, - reg[rm], half_reg, s8, yes, no_op); \ | ||||
| 2180 | break; \ | ||||
| 2181 | \ | ||||
| 2182 | case 3: \ | ||||
| 2183 | /* LDRSH rd, [rn - rm]! */ \ | ||||
| 2184 | arm_access_memory(load, - reg[rm], half_reg, s16, yes, no_op); \ | ||||
| 2185 | break; \ | ||||
| 2186 | } \ | ||||
| 2187 | } \ | ||||
| 2188 | else \ | ||||
| 2189 | { \ | ||||
| 2190 | /* TEQ rd, rn, reg_op */ \ | ||||
| 2191 | arm_data_proc_test_logic(reg[rn] ^ reg_sh, reg); \ | ||||
| 2192 | } \ | ||||
| 2193 | break; \ | ||||
| 2194 | \ | ||||
| 2195 | case 0x14: \ | ||||
| 2196 | if((opcode & 0x90) == 0x90) \ | ||||
| 2197 | { \ | ||||
| 2198 | if(opcode & 0x20) \ | ||||
| 2199 | { \ | ||||
| 2200 | /* STRH rd, [rn - imm] */ \ | ||||
| 2201 | arm_access_memory(store, - offset, half_imm, u16, no, no_op); \ | ||||
| 2202 | } \ | ||||
| 2203 | else \ | ||||
| 2204 | { \ | ||||
| 2205 | /* SWPB rd, rm, [rn] */ \ | ||||
| 2206 | arm_swap(u8); \ | ||||
| 2207 | } \ | ||||
| 2208 | } \ | ||||
| 2209 | else \ | ||||
| 2210 | { \ | ||||
| 2211 | /* MRS rd, spsr */ \ | ||||
| 2212 | arm_psr(reg, read, spsr[reg[CPU_MODE]]); \ | ||||
| 2213 | } \ | ||||
| 2214 | break; \ | ||||
| 2215 | \ | ||||
| 2216 | case 0x15: \ | ||||
| 2217 | if((opcode & 0x90) == 0x90) \ | ||||
| 2218 | { \ | ||||
| 2219 | switch((opcode >> 5) & 0x03) \ | ||||
| 2220 | { \ | ||||
| 2221 | case 1: \ | ||||
| 2222 | /* LDRH rd, [rn - imm] */ \ | ||||
| 2223 | arm_access_memory(load, - offset, half_imm, u16, no, no_op); \ | ||||
| 2224 | break; \ | ||||
| 2225 | \ | ||||
| 2226 | case 2: \ | ||||
| 2227 | /* LDRSB rd, [rn - imm] */ \ | ||||
| 2228 | arm_access_memory(load, - offset, half_imm, s8, no, no_op); \ | ||||
| 2229 | break; \ | ||||
| 2230 | \ | ||||
| 2231 | case 3: \ | ||||
| 2232 | /* LDRSH rd, [rn - imm] */ \ | ||||
| 2233 | arm_access_memory(load, - offset, half_imm, s16, no, no_op); \ | ||||
| 2234 | break; \ | ||||
| 2235 | } \ | ||||
| 2236 | } \ | ||||
| 2237 | else \ | ||||
| 2238 | { \ | ||||
| 2239 | /* CMP rn, reg_op */ \ | ||||
| 2240 | arm_data_proc_test_sub(reg[rn], reg_sh, reg); \ | ||||
| 2241 | } \ | ||||
| 2242 | break; \ | ||||
| 2243 | \ | ||||
| 2244 | case 0x16: \ | ||||
| 2245 | if((opcode & 0x90) == 0x90) \ | ||||
| 2246 | { \ | ||||
| 2247 | /* STRH rd, [rn - imm]! */ \ | ||||
| 2248 | arm_access_memory(store, - offset, half_imm, u16, yes, no_op); \ | ||||
| 2249 | } \ | ||||
| 2250 | else \ | ||||
| 2251 | { \ | ||||
| 2252 | /* MSR spsr, rm */ \ | ||||
| 2253 | arm_psr(reg, store, spsr); \ | ||||
| 2254 | } \ | ||||
| 2255 | break; \ | ||||
| 2256 | \ | ||||
| 2257 | case 0x17: \ | ||||
| 2258 | if((opcode & 0x90) == 0x90) \ | ||||
| 2259 | { \ | ||||
| 2260 | switch((opcode >> 5) & 0x03) \ | ||||
| 2261 | { \ | ||||
| 2262 | case 1: \ | ||||
| 2263 | /* LDRH rd, [rn - imm]! */ \ | ||||
| 2264 | arm_access_memory(load, - offset, half_imm, u16, yes, no_op); \ | ||||
| 2265 | break; \ | ||||
| 2266 | \ | ||||
| 2267 | case 2: \ | ||||
| 2268 | /* LDRSB rd, [rn - imm]! */ \ | ||||
| 2269 | arm_access_memory(load, - offset, half_imm, s8, yes, no_op); \ | ||||
| 2270 | break; \ | ||||
| 2271 | \ | ||||
| 2272 | case 3: \ | ||||
| 2273 | /* LDRSH rd, [rn - imm]! */ \ | ||||
| 2274 | arm_access_memory(load, - offset, half_imm, s16, yes, no_op); \ | ||||
| 2275 | break; \ | ||||
| 2276 | } \ | ||||
| 2277 | } \ | ||||
| 2278 | else \ | ||||
| 2279 | { \ | ||||
| 2280 | /* CMN rd, rn, reg_op */ \ | ||||
| 2281 | arm_data_proc_test_add(reg[rn], reg_sh, reg); \ | ||||
| 2282 | } \ | ||||
| 2283 | break; \ | ||||
| 2284 | \ | ||||
| 2285 | case 0x18: \ | ||||
| 2286 | if((opcode & 0x90) == 0x90) \ | ||||
| 2287 | { \ | ||||
| 2288 | /* STRH rd, [rn + rm] */ \ | ||||
| 2289 | arm_access_memory(store, + reg[rm], half_reg, u16, no, no_op); \ | ||||
| 2290 | } \ | ||||
| 2291 | else \ | ||||
| 2292 | { \ | ||||
| 2293 | /* ORR rd, rn, reg_op */ \ | ||||
| 2294 | arm_data_proc(reg[rn] | reg_sh, reg); \ | ||||
| 2295 | } \ | ||||
| 2296 | break; \ | ||||
| 2297 | \ | ||||
| 2298 | case 0x19: \ | ||||
| 2299 | if((opcode & 0x90) == 0x90) \ | ||||
| 2300 | { \ | ||||
| 2301 | switch((opcode >> 5) & 0x03) \ | ||||
| 2302 | { \ | ||||
| 2303 | case 1: \ | ||||
| 2304 | /* LDRH rd, [rn + rm] */ \ | ||||
| 2305 | arm_access_memory(load, + reg[rm], half_reg, u16, no, no_op); \ | ||||
| 2306 | break; \ | ||||
| 2307 | \ | ||||
| 2308 | case 2: \ | ||||
| 2309 | /* LDRSB rd, [rn + rm] */ \ | ||||
| 2310 | arm_access_memory(load, + reg[rm], half_reg, s8, no, no_op); \ | ||||
| 2311 | break; \ | ||||
| 2312 | \ | ||||
| 2313 | case 3: \ | ||||
| 2314 | /* LDRSH rd, [rn + rm] */ \ | ||||
| 2315 | arm_access_memory(load, + reg[rm], half_reg, s16, no, no_op); \ | ||||
| 2316 | break; \ | ||||
| 2317 | } \ | ||||
| 2318 | } \ | ||||
| 2319 | else \ | ||||
| 2320 | { \ | ||||
| 2321 | /* ORRS rd, rn, reg_op */ \ | ||||
| 2322 | arm_data_proc_logic_flags(reg[rn] | reg_sh, reg); \ | ||||
| 2323 | } \ | ||||
| 2324 | break; \ | ||||
| 2325 | \ | ||||
| 2326 | case 0x1A: \ | ||||
| 2327 | if((opcode & 0x90) == 0x90) \ | ||||
| 2328 | { \ | ||||
| 2329 | /* STRH rd, [rn + rm]! */ \ | ||||
| 2330 | arm_access_memory(store, + reg[rm], half_reg, u16, yes, no_op); \ | ||||
| 2331 | } \ | ||||
| 2332 | else \ | ||||
| 2333 | { \ | ||||
| 2334 | /* MOV rd, reg_op */ \ | ||||
| 2335 | arm_data_proc(reg_sh, reg); \ | ||||
| 2336 | } \ | ||||
| 2337 | break; \ | ||||
| 2338 | \ | ||||
| 2339 | case 0x1B: \ | ||||
| 2340 | if((opcode & 0x90) == 0x90) \ | ||||
| 2341 | { \ | ||||
| 2342 | switch((opcode >> 5) & 0x03) \ | ||||
| 2343 | { \ | ||||
| 2344 | case 1: \ | ||||
| 2345 | /* LDRH rd, [rn + rm]! */ \ | ||||
| 2346 | arm_access_memory(load, + reg[rm], half_reg, u16, yes, no_op); \ | ||||
| 2347 | break; \ | ||||
| 2348 | \ | ||||
| 2349 | case 2: \ | ||||
| 2350 | /* LDRSB rd, [rn + rm]! */ \ | ||||
| 2351 | arm_access_memory(load, + reg[rm], half_reg, s8, yes, no_op); \ | ||||
| 2352 | break; \ | ||||
| 2353 | \ | ||||
| 2354 | case 3: \ | ||||
| 2355 | /* LDRSH rd, [rn + rm]! */ \ | ||||
| 2356 | arm_access_memory(load, + reg[rm], half_reg, s16, yes, no_op); \ | ||||
| 2357 | break; \ | ||||
| 2358 | } \ | ||||
| 2359 | } \ | ||||
| 2360 | else \ | ||||
| 2361 | { \ | ||||
| 2362 | /* MOVS rd, reg_op */ \ | ||||
| 2363 | arm_data_proc_logic_flags(reg_sh, reg); \ | ||||
| 2364 | } \ | ||||
| 2365 | break; \ | ||||
| 2366 | \ | ||||
| 2367 | case 0x1C: \ | ||||
| 2368 | if((opcode & 0x90) == 0x90) \ | ||||
| 2369 | { \ | ||||
| 2370 | /* STRH rd, [rn + imm] */ \ | ||||
| 2371 | arm_access_memory(store, + offset, half_imm, u16, no, no_op); \ | ||||
| 2372 | } \ | ||||
| 2373 | else \ | ||||
| 2374 | { \ | ||||
| 2375 | /* BIC rd, rn, reg_op */ \ | ||||
| 2376 | arm_data_proc(reg[rn] & (~reg_sh), reg); \ | ||||
| 2377 | } \ | ||||
| 2378 | break; \ | ||||
| 2379 | \ | ||||
| 2380 | case 0x1D: \ | ||||
| 2381 | if((opcode & 0x90) == 0x90) \ | ||||
| 2382 | { \ | ||||
| 2383 | switch((opcode >> 5) & 0x03) \ | ||||
| 2384 | { \ | ||||
| 2385 | case 1: \ | ||||
| 2386 | /* LDRH rd, [rn + imm] */ \ | ||||
| 2387 | arm_access_memory(load, + offset, half_imm, u16, no, no_op); \ | ||||
| 2388 | break; \ | ||||
| 2389 | \ | ||||
| 2390 | case 2: \ | ||||
| 2391 | /* LDRSB rd, [rn + imm] */ \ | ||||
| 2392 | arm_access_memory(load, + offset, half_imm, s8, no, no_op); \ | ||||
| 2393 | break; \ | ||||
| 2394 | \ | ||||
| 2395 | case 3: \ | ||||
| 2396 | /* LDRSH rd, [rn + imm] */ \ | ||||
| 2397 | arm_access_memory(load, + offset, half_imm, s16, no, no_op); \ | ||||
| 2398 | break; \ | ||||
| 2399 | } \ | ||||
| 2400 | } \ | ||||
| 2401 | else \ | ||||
| 2402 | { \ | ||||
| 2403 | /* BICS rd, rn, reg_op */ \ | ||||
| 2404 | arm_data_proc_logic_flags(reg[rn] & (~reg_sh), reg); \ | ||||
| 2405 | } \ | ||||
| 2406 | break; \ | ||||
| 2407 | \ | ||||
| 2408 | case 0x1E: \ | ||||
| 2409 | if((opcode & 0x90) == 0x90) \ | ||||
| 2410 | { \ | ||||
| 2411 | /* STRH rd, [rn + imm]! */ \ | ||||
| 2412 | arm_access_memory(store, + offset, half_imm, u16, yes, no_op); \ | ||||
| 2413 | } \ | ||||
| 2414 | else \ | ||||
| 2415 | { \ | ||||
| 2416 | /* MVN rd, reg_op */ \ | ||||
| 2417 | arm_data_proc(~reg_sh, reg); \ | ||||
| 2418 | } \ | ||||
| 2419 | break; \ | ||||
| 2420 | \ | ||||
| 2421 | case 0x1F: \ | ||||
| 2422 | if((opcode & 0x90) == 0x90) \ | ||||
| 2423 | { \ | ||||
| 2424 | switch((opcode >> 5) & 0x03) \ | ||||
| 2425 | { \ | ||||
| 2426 | case 1: \ | ||||
| 2427 | /* LDRH rd, [rn + imm]! */ \ | ||||
| 2428 | arm_access_memory(load, + offset, half_imm, u16, yes, no_op); \ | ||||
| 2429 | break; \ | ||||
| 2430 | \ | ||||
| 2431 | case 2: \ | ||||
| 2432 | /* LDRSB rd, [rn + imm]! */ \ | ||||
| 2433 | arm_access_memory(load, + offset, half_imm, s8, yes, no_op); \ | ||||
| 2434 | break; \ | ||||
| 2435 | \ | ||||
| 2436 | case 3: \ | ||||
| 2437 | /* LDRSH rd, [rn + imm]! */ \ | ||||
| 2438 | arm_access_memory(load, + offset, half_imm, s16, yes, no_op); \ | ||||
| 2439 | break; \ | ||||
| 2440 | } \ | ||||
| 2441 | } \ | ||||
| 2442 | else \ | ||||
| 2443 | { \ | ||||
| 2444 | /* MVNS rd, rn, reg_op */ \ | ||||
| 2445 | arm_data_proc_logic_flags(~reg_sh, reg); \ | ||||
| 2446 | } \ | ||||
| 2447 | break; \ | ||||
| 2448 | \ | ||||
| 2449 | case 0x20: \ | ||||
| 2450 | /* AND rd, rn, imm */ \ | ||||
| 2451 | arm_data_proc(reg[rn] & imm, imm); \ | ||||
| 2452 | break; \ | ||||
| 2453 | \ | ||||
| 2454 | case 0x21: \ | ||||
| 2455 | /* ANDS rd, rn, imm */ \ | ||||
| 2456 | arm_data_proc_logic_flags(reg[rn] & imm, imm); \ | ||||
| 2457 | break; \ | ||||
| 2458 | \ | ||||
| 2459 | case 0x22: \ | ||||
| 2460 | /* EOR rd, rn, imm */ \ | ||||
| 2461 | arm_data_proc(reg[rn] ^ imm, imm); \ | ||||
| 2462 | break; \ | ||||
| 2463 | \ | ||||
| 2464 | case 0x23: \ | ||||
| 2465 | /* EORS rd, rn, imm */ \ | ||||
| 2466 | arm_data_proc_logic_flags(reg[rn] ^ imm, imm); \ | ||||
| 2467 | break; \ | ||||
| 2468 | \ | ||||
| 2469 | case 0x24: \ | ||||
| 2470 | /* SUB rd, rn, imm */ \ | ||||
| 2471 | arm_data_proc(reg[rn] - imm, imm); \ | ||||
| 2472 | break; \ | ||||
| 2473 | \ | ||||
| 2474 | case 0x25: \ | ||||
| 2475 | /* SUBS rd, rn, imm */ \ | ||||
| 2476 | arm_data_proc_sub_flags(reg[rn], imm, imm); \ | ||||
| 2477 | break; \ | ||||
| 2478 | \ | ||||
| 2479 | case 0x26: \ | ||||
| 2480 | /* RSB rd, rn, imm */ \ | ||||
| 2481 | arm_data_proc(imm - reg[rn], imm); \ | ||||
| 2482 | break; \ | ||||
| 2483 | \ | ||||
| 2484 | case 0x27: \ | ||||
| 2485 | /* RSBS rd, rn, imm */ \ | ||||
| 2486 | arm_data_proc_sub_flags(imm, reg[rn], imm); \ | ||||
| 2487 | break; \ | ||||
| 2488 | \ | ||||
| 2489 | case 0x28: \ | ||||
| 2490 | /* ADD rd, rn, imm */ \ | ||||
| 2491 | arm_data_proc(reg[rn] + imm, imm); \ | ||||
| 2492 | break; \ | ||||
| 2493 | \ | ||||
| 2494 | case 0x29: \ | ||||
| 2495 | /* ADDS rd, rn, imm */ \ | ||||
| 2496 | arm_data_proc_add_flags(reg[rn], imm, imm); \ | ||||
| 2497 | break; \ | ||||
| 2498 | \ | ||||
| 2499 | case 0x2A: \ | ||||
| 2500 | /* ADC rd, rn, imm */ \ | ||||
| 2501 | arm_data_proc(reg[rn] + imm + c_flag, imm); \ | ||||
| 2502 | break; \ | ||||
| 2503 | \ | ||||
| 2504 | case 0x2B: \ | ||||
| 2505 | /* ADCS rd, rn, imm */ \ | ||||
| 2506 | arm_data_proc_add_flags(reg[rn] + imm, c_flag, imm); \ | ||||
| 2507 | break; \ | ||||
| 2508 | \ | ||||
| 2509 | case 0x2C: \ | ||||
| 2510 | /* SBC rd, rn, imm */ \ | ||||
| 2511 | arm_data_proc(reg[rn] - imm + c_flag - 1, imm); \ | ||||
| 2512 | break; \ | ||||
| 2513 | \ | ||||
| 2514 | case 0x2D: \ | ||||
| 2515 | /* SBCS rd, rn, imm */ \ | ||||
| 2516 | arm_data_proc_sub_flags(reg[rn], (imm + (c_flag ^ 1)), imm); \ | ||||
| 2517 | break; \ | ||||
| 2518 | \ | ||||
| 2519 | case 0x2E: \ | ||||
| 2520 | /* RSC rd, rn, imm */ \ | ||||
| 2521 | arm_data_proc(imm - reg[rn] + c_flag - 1, imm); \ | ||||
| 2522 | break; \ | ||||
| 2523 | \ | ||||
| 2524 | case 0x2F: \ | ||||
| 2525 | /* RSCS rd, rn, imm */ \ | ||||
| 2526 | arm_data_proc_sub_flags((imm + c_flag - 1), reg[rn], imm); \ | ||||
| 2527 | break; \ | ||||
| 2528 | \ | ||||
| 2529 | case 0x30 ... 0x31: \ | ||||
| 2530 | /* TST rn, imm */ \ | ||||
| 2531 | arm_data_proc_test_logic(reg[rn] & imm, imm); \ | ||||
| 2532 | break; \ | ||||
| 2533 | \ | ||||
| 2534 | case 0x32: \ | ||||
| 2535 | /* MSR cpsr, imm */ \ | ||||
| 2536 | arm_psr(imm, store, cpsr); \ | ||||
| 2537 | break; \ | ||||
| 2538 | \ | ||||
| 2539 | case 0x33: \ | ||||
| 2540 | /* TEQ rn, imm */ \ | ||||
| 2541 | arm_data_proc_test_logic(reg[rn] ^ imm, imm); \ | ||||
| 2542 | break; \ | ||||
| 2543 | \ | ||||
| 2544 | case 0x34 ... 0x35: \ | ||||
| 2545 | /* CMP rn, imm */ \ | ||||
| 2546 | arm_data_proc_test_sub(reg[rn], imm, imm); \ | ||||
| 2547 | break; \ | ||||
| 2548 | \ | ||||
| 2549 | case 0x36: \ | ||||
| 2550 | /* MSR spsr, imm */ \ | ||||
| 2551 | arm_psr(imm, store, spsr); \ | ||||
| 2552 | break; \ | ||||
| 2553 | \ | ||||
| 2554 | case 0x37: \ | ||||
| 2555 | /* CMN rn, imm */ \ | ||||
| 2556 | arm_data_proc_test_add(reg[rn], imm, imm); \ | ||||
| 2557 | break; \ | ||||
| 2558 | \ | ||||
| 2559 | case 0x38: \ | ||||
| 2560 | /* ORR rd, rn, imm */ \ | ||||
| 2561 | arm_data_proc(reg[rn] | imm, imm); \ | ||||
| 2562 | break; \ | ||||
| 2563 | \ | ||||
| 2564 | case 0x39: \ | ||||
| 2565 | /* ORRS rd, rn, imm */ \ | ||||
| 2566 | arm_data_proc_logic_flags(reg[rn] | imm, imm); \ | ||||
| 2567 | break; \ | ||||
| 2568 | \ | ||||
| 2569 | case 0x3A: \ | ||||
| 2570 | /* MOV rd, imm */ \ | ||||
| 2571 | arm_data_proc(imm, imm); \ | ||||
| 2572 | break; \ | ||||
| 2573 | \ | ||||
| 2574 | case 0x3B: \ | ||||
| 2575 | /* MOVS rd, imm */ \ | ||||
| 2576 | arm_data_proc_logic_flags(imm, imm); \ | ||||
| 2577 | break; \ | ||||
| 2578 | \ | ||||
| 2579 | case 0x3C: \ | ||||
| 2580 | /* BIC rd, rn, imm */ \ | ||||
| 2581 | arm_data_proc(reg[rn] & (~imm), imm); \ | ||||
| 2582 | break; \ | ||||
| 2583 | \ | ||||
| 2584 | case 0x3D: \ | ||||
| 2585 | /* BICS rd, rn, imm */ \ | ||||
| 2586 | arm_data_proc_logic_flags(reg[rn] & (~imm), imm); \ | ||||
| 2587 | break; \ | ||||
| 2588 | \ | ||||
| 2589 | case 0x3E: \ | ||||
| 2590 | /* MVN rd, imm */ \ | ||||
| 2591 | arm_data_proc(~imm, imm); \ | ||||
| 2592 | break; \ | ||||
| 2593 | \ | ||||
| 2594 | case 0x3F: \ | ||||
| 2595 | /* MVNS rd, imm */ \ | ||||
| 2596 | arm_data_proc_logic_flags(~imm, imm); \ | ||||
| 2597 | break; \ | ||||
| 2598 | \ | ||||
| 2599 | case 0x40: \ | ||||
| 2600 | /* STR rd, [rn], -imm */ \ | ||||
| 2601 | arm_access_memory(store, no_op, imm, u32, yes, - offset); \ | ||||
| 2602 | break; \ | ||||
| 2603 | \ | ||||
| 2604 | case 0x41: \ | ||||
| 2605 | /* LDR rd, [rn], -imm */ \ | ||||
| 2606 | arm_access_memory(load, no_op, imm, u32, yes, - offset); \ | ||||
| 2607 | break; \ | ||||
| 2608 | \ | ||||
| 2609 | case 0x42: \ | ||||
| 2610 | /* STRT rd, [rn], -imm */ \ | ||||
| 2611 | arm_access_memory(store, no_op, imm, u32, yes, - offset); \ | ||||
| 2612 | break; \ | ||||
| 2613 | \ | ||||
| 2614 | case 0x43: \ | ||||
| 2615 | /* LDRT rd, [rn], -imm */ \ | ||||
| 2616 | arm_access_memory(load, no_op, imm, u32, yes, - offset); \ | ||||
| 2617 | break; \ | ||||
| 2618 | \ | ||||
| 2619 | case 0x44: \ | ||||
| 2620 | /* STRB rd, [rn], -imm */ \ | ||||
| 2621 | arm_access_memory(store, no_op, imm, u8, yes, - offset); \ | ||||
| 2622 | break; \ | ||||
| 2623 | \ | ||||
| 2624 | case 0x45: \ | ||||
| 2625 | /* LDRB rd, [rn], -imm */ \ | ||||
| 2626 | arm_access_memory(load, no_op, imm, u8, yes, - offset); \ | ||||
| 2627 | break; \ | ||||
| 2628 | \ | ||||
| 2629 | case 0x46: \ | ||||
| 2630 | /* STRBT rd, [rn], -imm */ \ | ||||
| 2631 | arm_access_memory(store, no_op, imm, u8, yes, - offset); \ | ||||
| 2632 | break; \ | ||||
| 2633 | \ | ||||
| 2634 | case 0x47: \ | ||||
| 2635 | /* LDRBT rd, [rn], -imm */ \ | ||||
| 2636 | arm_access_memory(load, no_op, imm, u8, yes, - offset); \ | ||||
| 2637 | break; \ | ||||
| 2638 | \ | ||||
| 2639 | case 0x48: \ | ||||
| 2640 | /* STR rd, [rn], +imm */ \ | ||||
| 2641 | arm_access_memory(store, no_op, imm, u32, yes, + offset); \ | ||||
| 2642 | break; \ | ||||
| 2643 | \ | ||||
| 2644 | case 0x49: \ | ||||
| 2645 | /* LDR rd, [rn], +imm */ \ | ||||
| 2646 | arm_access_memory(load, no_op, imm, u32, yes, + offset); \ | ||||
| 2647 | break; \ | ||||
| 2648 | \ | ||||
| 2649 | case 0x4A: \ | ||||
| 2650 | /* STRT rd, [rn], +imm */ \ | ||||
| 2651 | arm_access_memory(store, no_op, imm, u32, yes, + offset); \ | ||||
| 2652 | break; \ | ||||
| 2653 | \ | ||||
| 2654 | case 0x4B: \ | ||||
| 2655 | /* LDRT rd, [rn], +imm */ \ | ||||
| 2656 | arm_access_memory(load, no_op, imm, u32, yes, + offset); \ | ||||
| 2657 | break; \ | ||||
| 2658 | \ | ||||
| 2659 | case 0x4C: \ | ||||
| 2660 | /* STRB rd, [rn], +imm */ \ | ||||
| 2661 | arm_access_memory(store, no_op, imm, u8, yes, + offset); \ | ||||
| 2662 | break; \ | ||||
| 2663 | \ | ||||
| 2664 | case 0x4D: \ | ||||
| 2665 | /* LDRB rd, [rn], +imm */ \ | ||||
| 2666 | arm_access_memory(load, no_op, imm, u8, yes, + offset); \ | ||||
| 2667 | break; \ | ||||
| 2668 | \ | ||||
| 2669 | case 0x4E: \ | ||||
| 2670 | /* STRBT rd, [rn], +imm */ \ | ||||
| 2671 | arm_access_memory(store, no_op, imm, u8, yes, + offset); \ | ||||
| 2672 | break; \ | ||||
| 2673 | \ | ||||
| 2674 | case 0x4F: \ | ||||
| 2675 | /* LDRBT rd, [rn], +imm */ \ | ||||
| 2676 | arm_access_memory(load, no_op, imm, u8, yes, + offset); \ | ||||
| 2677 | break; \ | ||||
| 2678 | \ | ||||
| 2679 | case 0x50: \ | ||||
| 2680 | /* STR rd, [rn - imm] */ \ | ||||
| 2681 | arm_access_memory(store, - offset, imm, u32, no, no_op); \ | ||||
| 2682 | break; \ | ||||
| 2683 | \ | ||||
| 2684 | case 0x51: \ | ||||
| 2685 | /* LDR rd, [rn - imm] */ \ | ||||
| 2686 | arm_access_memory(load, - offset, imm, u32, no, no_op); \ | ||||
| 2687 | break; \ | ||||
| 2688 | \ | ||||
| 2689 | case 0x52: \ | ||||
| 2690 | /* STR rd, [rn - imm]! */ \ | ||||
| 2691 | arm_access_memory(store, - offset, imm, u32, yes, no_op); \ | ||||
| 2692 | break; \ | ||||
| 2693 | \ | ||||
| 2694 | case 0x53: \ | ||||
| 2695 | /* LDR rd, [rn - imm]! */ \ | ||||
| 2696 | arm_access_memory(load, - offset, imm, u32, yes, no_op); \ | ||||
| 2697 | break; \ | ||||
| 2698 | \ | ||||
| 2699 | case 0x54: \ | ||||
| 2700 | /* STRB rd, [rn - imm] */ \ | ||||
| 2701 | arm_access_memory(store, - offset, imm, u8, no, no_op); \ | ||||
| 2702 | break; \ | ||||
| 2703 | \ | ||||
| 2704 | case 0x55: \ | ||||
| 2705 | /* LDRB rd, [rn - imm] */ \ | ||||
| 2706 | arm_access_memory(load, - offset, imm, u8, no, no_op); \ | ||||
| 2707 | break; \ | ||||
| 2708 | \ | ||||
| 2709 | case 0x56: \ | ||||
| 2710 | /* STRB rd, [rn - imm]! */ \ | ||||
| 2711 | arm_access_memory(store, - offset, imm, u8, yes, no_op); \ | ||||
| 2712 | break; \ | ||||
| 2713 | \ | ||||
| 2714 | case 0x57: \ | ||||
| 2715 | /* LDRB rd, [rn - imm]! */ \ | ||||
| 2716 | arm_access_memory(load, - offset, imm, u8, yes, no_op); \ | ||||
| 2717 | break; \ | ||||
| 2718 | \ | ||||
| 2719 | case 0x58: \ | ||||
| 2720 | /* STR rd, [rn + imm] */ \ | ||||
| 2721 | arm_access_memory(store, + offset, imm, u32, no, no_op); \ | ||||
| 2722 | break; \ | ||||
| 2723 | \ | ||||
| 2724 | case 0x59: \ | ||||
| 2725 | /* LDR rd, [rn + imm] */ \ | ||||
| 2726 | arm_access_memory(load, + offset, imm, u32, no, no_op); \ | ||||
| 2727 | break; \ | ||||
| 2728 | \ | ||||
| 2729 | case 0x5A: \ | ||||
| 2730 | /* STR rd, [rn + imm]! */ \ | ||||
| 2731 | arm_access_memory(store, + offset, imm, u32, yes, no_op); \ | ||||
| 2732 | break; \ | ||||
| 2733 | \ | ||||
| 2734 | case 0x5B: \ | ||||
| 2735 | /* LDR rd, [rn + imm]! */ \ | ||||
| 2736 | arm_access_memory(load, + offset, imm, u32, yes, no_op); \ | ||||
| 2737 | break; \ | ||||
| 2738 | \ | ||||
| 2739 | case 0x5C: \ | ||||
| 2740 | /* STRB rd, [rn + imm] */ \ | ||||
| 2741 | arm_access_memory(store, + offset, imm, u8, no, no_op); \ | ||||
| 2742 | break; \ | ||||
| 2743 | \ | ||||
| 2744 | case 0x5D: \ | ||||
| 2745 | /* LDRB rd, [rn + imm] */ \ | ||||
| 2746 | arm_access_memory(load, + offset, imm, u8, no, no_op); \ | ||||
| 2747 | break; \ | ||||
| 2748 | \ | ||||
| 2749 | case 0x5E: \ | ||||
| 2750 | /* STRB rd, [rn + imm]! */ \ | ||||
| 2751 | arm_access_memory(store, + offset, imm, u8, yes, no_op); \ | ||||
| 2752 | break; \ | ||||
| 2753 | \ | ||||
| 2754 | case 0x5F: \ | ||||
| 2755 | /* LDRBT rd, [rn + imm]! */ \ | ||||
| 2756 | arm_access_memory(load, + offset, imm, u8, yes, no_op); \ | ||||
| 2757 | break; \ | ||||
| 2758 | \ | ||||
| 2759 | case 0x60: \ | ||||
| 2760 | /* STR rd, [rn], -reg_op */ \ | ||||
| 2761 | arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); \ | ||||
| 2762 | break; \ | ||||
| 2763 | \ | ||||
| 2764 | case 0x61: \ | ||||
| 2765 | /* LDR rd, [rn], -reg_op */ \ | ||||
| 2766 | arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); \ | ||||
| 2767 | break; \ | ||||
| 2768 | \ | ||||
| 2769 | case 0x62: \ | ||||
| 2770 | /* STRT rd, [rn], -reg_op */ \ | ||||
| 2771 | arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); \ | ||||
| 2772 | break; \ | ||||
| 2773 | \ | ||||
| 2774 | case 0x63: \ | ||||
| 2775 | /* LDRT rd, [rn], -reg_op */ \ | ||||
| 2776 | arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); \ | ||||
| 2777 | break; \ | ||||
| 2778 | \ | ||||
| 2779 | case 0x64: \ | ||||
| 2780 | /* STRB rd, [rn], -reg_op */ \ | ||||
| 2781 | arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); \ | ||||
| 2782 | break; \ | ||||
| 2783 | \ | ||||
| 2784 | case 0x65: \ | ||||
| 2785 | /* LDRB rd, [rn], -reg_op */ \ | ||||
| 2786 | arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); \ | ||||
| 2787 | break; \ | ||||
| 2788 | \ | ||||
| 2789 | case 0x66: \ | ||||
| 2790 | /* STRBT rd, [rn], -reg_op */ \ | ||||
| 2791 | arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); \ | ||||
| 2792 | break; \ | ||||
| 2793 | \ | ||||
| 2794 | case 0x67: \ | ||||
| 2795 | /* LDRBT rd, [rn], -reg_op */ \ | ||||
| 2796 | arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); \ | ||||
| 2797 | break; \ | ||||
| 2798 | \ | ||||
| 2799 | case 0x68: \ | ||||
| 2800 | /* STR rd, [rn], +reg_op */ \ | ||||
| 2801 | arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); \ | ||||
| 2802 | break; \ | ||||
| 2803 | \ | ||||
| 2804 | case 0x69: \ | ||||
| 2805 | /* LDR rd, [rn], +reg_op */ \ | ||||
| 2806 | arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); \ | ||||
| 2807 | break; \ | ||||
| 2808 | \ | ||||
| 2809 | case 0x6A: \ | ||||
| 2810 | /* STRT rd, [rn], +reg_op */ \ | ||||
| 2811 | arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); \ | ||||
| 2812 | break; \ | ||||
| 2813 | \ | ||||
| 2814 | case 0x6B: \ | ||||
| 2815 | /* LDRT rd, [rn], +reg_op */ \ | ||||
| 2816 | arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); \ | ||||
| 2817 | break; \ | ||||
| 2818 | \ | ||||
| 2819 | case 0x6C: \ | ||||
| 2820 | /* STRB rd, [rn], +reg_op */ \ | ||||
| 2821 | arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); \ | ||||
| 2822 | break; \ | ||||
| 2823 | \ | ||||
| 2824 | case 0x6D: \ | ||||
| 2825 | /* LDRB rd, [rn], +reg_op */ \ | ||||
| 2826 | arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); \ | ||||
| 2827 | break; \ | ||||
| 2828 | \ | ||||
| 2829 | case 0x6E: \ | ||||
| 2830 | /* STRBT rd, [rn], +reg_op */ \ | ||||
| 2831 | arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); \ | ||||
| 2832 | break; \ | ||||
| 2833 | \ | ||||
| 2834 | case 0x6F: \ | ||||
| 2835 | /* LDRBT rd, [rn], +reg_op */ \ | ||||
| 2836 | arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); \ | ||||
| 2837 | break; \ | ||||
| 2838 | \ | ||||
| 2839 | case 0x70: \ | ||||
| 2840 | /* STR rd, [rn - reg_op] */ \ | ||||
| 2841 | arm_access_memory(store, - reg_offset, reg, u32, no, no_op); \ | ||||
| 2842 | break; \ | ||||
| 2843 | \ | ||||
| 2844 | case 0x71: \ | ||||
| 2845 | /* LDR rd, [rn - reg_op] */ \ | ||||
| 2846 | arm_access_memory(load, - reg_offset, reg, u32, no, no_op); \ | ||||
| 2847 | break; \ | ||||
| 2848 | \ | ||||
| 2849 | case 0x72: \ | ||||
| 2850 | /* STR rd, [rn - reg_op]! */ \ | ||||
| 2851 | arm_access_memory(store, - reg_offset, reg, u32, yes, no_op); \ | ||||
| 2852 | break; \ | ||||
| 2853 | \ | ||||
| 2854 | case 0x73: \ | ||||
| 2855 | /* LDR rd, [rn - reg_op]! */ \ | ||||
| 2856 | arm_access_memory(load, - reg_offset, reg, u32, yes, no_op); \ | ||||
| 2857 | break; \ | ||||
| 2858 | \ | ||||
| 2859 | case 0x74: \ | ||||
| 2860 | /* STRB rd, [rn - reg_op] */ \ | ||||
| 2861 | arm_access_memory(store, - reg_offset, reg, u8, no, no_op); \ | ||||
| 2862 | break; \ | ||||
| 2863 | \ | ||||
| 2864 | case 0x75: \ | ||||
| 2865 | /* LDRB rd, [rn - reg_op] */ \ | ||||
| 2866 | arm_access_memory(load, - reg_offset, reg, u8, no, no_op); \ | ||||
| 2867 | break; \ | ||||
| 2868 | \ | ||||
| 2869 | case 0x76: \ | ||||
| 2870 | /* STRB rd, [rn - reg_op]! */ \ | ||||
| 2871 | arm_access_memory(store, - reg_offset, reg, u8, yes, no_op); \ | ||||
| 2872 | break; \ | ||||
| 2873 | \ | ||||
| 2874 | case 0x77: \ | ||||
| 2875 | /* LDRB rd, [rn - reg_op]! */ \ | ||||
| 2876 | arm_access_memory(load, - reg_offset, reg, u8, yes, no_op); \ | ||||
| 2877 | break; \ | ||||
| 2878 | \ | ||||
| 2879 | case 0x78: \ | ||||
| 2880 | /* STR rd, [rn + reg_op] */ \ | ||||
| 2881 | arm_access_memory(store, + reg_offset, reg, u32, no, no_op); \ | ||||
| 2882 | break; \ | ||||
| 2883 | \ | ||||
| 2884 | case 0x79: \ | ||||
| 2885 | /* LDR rd, [rn + reg_op] */ \ | ||||
| 2886 | arm_access_memory(load, + reg_offset, reg, u32, no, no_op); \ | ||||
| 2887 | break; \ | ||||
| 2888 | \ | ||||
| 2889 | case 0x7A: \ | ||||
| 2890 | /* STR rd, [rn + reg_op]! */ \ | ||||
| 2891 | arm_access_memory(store, + reg_offset, reg, u32, yes, no_op); \ | ||||
| 2892 | break; \ | ||||
| 2893 | \ | ||||
| 2894 | case 0x7B: \ | ||||
| 2895 | /* LDR rd, [rn + reg_op]! */ \ | ||||
| 2896 | arm_access_memory(load, + reg_offset, reg, u32, yes, no_op); \ | ||||
| 2897 | break; \ | ||||
| 2898 | \ | ||||
| 2899 | case 0x7C: \ | ||||
| 2900 | /* STRB rd, [rn + reg_op] */ \ | ||||
| 2901 | arm_access_memory(store, + reg_offset, reg, u8, no, no_op); \ | ||||
| 2902 | break; \ | ||||
| 2903 | \ | ||||
| 2904 | case 0x7D: \ | ||||
| 2905 | /* LDRB rd, [rn + reg_op] */ \ | ||||
| 2906 | arm_access_memory(load, + reg_offset, reg, u8, no, no_op); \ | ||||
| 2907 | break; \ | ||||
| 2908 | \ | ||||
| 2909 | case 0x7E: \ | ||||
| 2910 | /* STRB rd, [rn + reg_op]! */ \ | ||||
| 2911 | arm_access_memory(store, + reg_offset, reg, u8, yes, no_op); \ | ||||
| 2912 | break; \ | ||||
| 2913 | \ | ||||
| 2914 | case 0x7F: \ | ||||
| 2915 | /* LDRBT rd, [rn + reg_op]! */ \ | ||||
| 2916 | arm_access_memory(load, + reg_offset, reg, u8, yes, no_op); \ | ||||
| 2917 | break; \ | ||||
| 2918 | \ | ||||
| 2919 | case 0x80: \ | ||||
| 2920 | /* STMDA rn, rlist */ \ | ||||
| 2921 | arm_block_memory(store, down_a, no, no); \ | ||||
| 2922 | break; \ | ||||
| 2923 | \ | ||||
| 2924 | case 0x81: \ | ||||
| 2925 | /* LDMDA rn, rlist */ \ | ||||
| 2926 | arm_block_memory(load, down_a, no, no); \ | ||||
| 2927 | break; \ | ||||
| 2928 | \ | ||||
| 2929 | case 0x82: \ | ||||
| 2930 | /* STMDA rn!, rlist */ \ | ||||
| 2931 | arm_block_memory(store, down_a, down, no); \ | ||||
| 2932 | break; \ | ||||
| 2933 | \ | ||||
| 2934 | case 0x83: \ | ||||
| 2935 | /* LDMDA rn!, rlist */ \ | ||||
| 2936 | arm_block_memory(load, down_a, down, no); \ | ||||
| 2937 | break; \ | ||||
| 2938 | \ | ||||
| 2939 | case 0x84: \ | ||||
| 2940 | /* STMDA rn, rlist^ */ \ | ||||
| 2941 | arm_block_memory(store, down_a, no, yes); \ | ||||
| 2942 | break; \ | ||||
| 2943 | \ | ||||
| 2944 | case 0x85: \ | ||||
| 2945 | /* LDMDA rn, rlist^ */ \ | ||||
| 2946 | arm_block_memory(load, down_a, no, yes); \ | ||||
| 2947 | break; \ | ||||
| 2948 | \ | ||||
| 2949 | case 0x86: \ | ||||
| 2950 | /* STMDA rn!, rlist^ */ \ | ||||
| 2951 | arm_block_memory(store, down_a, down, yes); \ | ||||
| 2952 | break; \ | ||||
| 2953 | \ | ||||
| 2954 | case 0x87: \ | ||||
| 2955 | /* LDMDA rn!, rlist^ */ \ | ||||
| 2956 | arm_block_memory(load, down_a, down, yes); \ | ||||
| 2957 | break; \ | ||||
| 2958 | \ | ||||
| 2959 | case 0x88: \ | ||||
| 2960 | /* STMIA rn, rlist */ \ | ||||
| 2961 | arm_block_memory(store, no, no, no); \ | ||||
| 2962 | break; \ | ||||
| 2963 | \ | ||||
| 2964 | case 0x89: \ | ||||
| 2965 | /* LDMIA rn, rlist */ \ | ||||
| 2966 | arm_block_memory(load, no, no, no); \ | ||||
| 2967 | break; \ | ||||
| 2968 | \ | ||||
| 2969 | case 0x8A: \ | ||||
| 2970 | /* STMIA rn!, rlist */ \ | ||||
| 2971 | arm_block_memory(store, no, up, no); \ | ||||
| 2972 | break; \ | ||||
| 2973 | \ | ||||
| 2974 | case 0x8B: \ | ||||
| 2975 | /* LDMIA rn!, rlist */ \ | ||||
| 2976 | arm_block_memory(load, no, up, no); \ | ||||
| 2977 | break; \ | ||||
| 2978 | \ | ||||
| 2979 | case 0x8C: \ | ||||
| 2980 | /* STMIA rn, rlist^ */ \ | ||||
| 2981 | arm_block_memory(store, no, no, yes); \ | ||||
| 2982 | break; \ | ||||
| 2983 | \ | ||||
| 2984 | case 0x8D: \ | ||||
| 2985 | /* LDMIA rn, rlist^ */ \ | ||||
| 2986 | arm_block_memory(load, no, no, yes); \ | ||||
| 2987 | break; \ | ||||
| 2988 | \ | ||||
| 2989 | case 0x8E: \ | ||||
| 2990 | /* STMIA rn!, rlist^ */ \ | ||||
| 2991 | arm_block_memory(store, no, up, yes); \ | ||||
| 2992 | break; \ | ||||
| 2993 | \ | ||||
| 2994 | case 0x8F: \ | ||||
| 2995 | /* LDMIA rn!, rlist^ */ \ | ||||
| 2996 | arm_block_memory(load, no, up, yes); \ | ||||
| 2997 | break; \ | ||||
| 2998 | \ | ||||
| 2999 | case 0x90: \ | ||||
| 3000 | /* STMDB rn, rlist */ \ | ||||
| 3001 | arm_block_memory(store, down_b, no, no); \ | ||||
| 3002 | break; \ | ||||
| 3003 | \ | ||||
| 3004 | case 0x91: \ | ||||
| 3005 | /* LDMDB rn, rlist */ \ | ||||
| 3006 | arm_block_memory(load, down_b, no, no); \ | ||||
| 3007 | break; \ | ||||
| 3008 | \ | ||||
| 3009 | case 0x92: \ | ||||
| 3010 | /* STMDB rn!, rlist */ \ | ||||
| 3011 | arm_block_memory(store, down_b, down, no); \ | ||||
| 3012 | break; \ | ||||
| 3013 | \ | ||||
| 3014 | case 0x93: \ | ||||
| 3015 | /* LDMDB rn!, rlist */ \ | ||||
| 3016 | arm_block_memory(load, down_b, down, no); \ | ||||
| 3017 | break; \ | ||||
| 3018 | \ | ||||
| 3019 | case 0x94: \ | ||||
| 3020 | /* STMDB rn, rlist^ */ \ | ||||
| 3021 | arm_block_memory(store, down_b, no, yes); \ | ||||
| 3022 | break; \ | ||||
| 3023 | \ | ||||
| 3024 | case 0x95: \ | ||||
| 3025 | /* LDMDB rn, rlist^ */ | ||||








