1 /* MN10300 Misalignment fixup handler
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
11 #include <linux/module.h>
12 #include <linux/sched.h>
13 #include <linux/kernel.h>
14 #include <linux/string.h>
15 #include <linux/errno.h>
16 #include <linux/ptrace.h>
17 #include <linux/timer.h>
19 #include <linux/smp.h>
20 #include <linux/smp_lock.h>
21 #include <linux/init.h>
22 #include <linux/delay.h>
23 #include <linux/spinlock.h>
24 #include <linux/interrupt.h>
25 #include <linux/pci.h>
26 #include <asm/processor.h>
27 #include <asm/system.h>
28 #include <asm/uaccess.h>
30 #include <asm/atomic.h>
32 #include <asm/pgalloc.h>
33 #include <asm/cpu-regs.h>
34 #include <asm/busctl-regs.h>
36 #include <asm/gdb-stub.h>
37 #include <asm/asm-offsets.h>
40 #define kdebug(FMT, ...) printk(KERN_DEBUG FMT, ##__VA_ARGS__)
42 #define kdebug(FMT, ...) do {} while (0)
45 static int misalignment_addr(unsigned long *registers
, unsigned params
,
46 unsigned opcode
, unsigned disp
,
47 void **_address
, unsigned long **_postinc
);
49 static int misalignment_reg(unsigned long *registers
, unsigned params
,
50 unsigned opcode
, unsigned disp
,
51 unsigned long **_register
);
53 static inline unsigned int_log2(unsigned x
)
56 asm("bsch %1,%0" : "=r"(y
) : "r"(x
), "0"(0));
59 #define log2(x) int_log2(x)
61 static const unsigned Dreg_index
[] = {
62 REG_D0
>> 2, REG_D1
>> 2, REG_D2
>> 2, REG_D3
>> 2
65 static const unsigned Areg_index
[] = {
66 REG_A0
>> 2, REG_A1
>> 2, REG_A2
>> 2, REG_A3
>> 2
69 static const unsigned Rreg_index
[] = {
70 REG_E0
>> 2, REG_E1
>> 2, REG_E2
>> 2, REG_E3
>> 2,
71 REG_E4
>> 2, REG_E5
>> 2, REG_E6
>> 2, REG_E7
>> 2,
72 REG_A0
>> 2, REG_A1
>> 2, REG_A2
>> 2, REG_A3
>> 2,
73 REG_D0
>> 2, REG_D1
>> 2, REG_D2
>> 2, REG_D3
>> 2
92 u_int8_t opsz
, dispsz
;
100 [FMT_D2
] = { 16, 16 },
101 [FMT_D4
] = { 16, 32 },
102 [FMT_D6
] = { 24, 0 },
103 [FMT_D7
] = { 24, 8 },
104 [FMT_D8
] = { 24, 24 },
105 [FMT_D9
] = { 24, 32 },
109 DM0
, /* data reg in opcode in bits 0-1 */
110 DM1
, /* data reg in opcode in bits 2-3 */
111 DM2
, /* data reg in opcode in bits 4-5 */
112 AM0
, /* addr reg in opcode in bits 0-1 */
113 AM1
, /* addr reg in opcode in bits 2-3 */
114 AM2
, /* addr reg in opcode in bits 4-5 */
115 RM0
, /* reg in opcode in bits 0-3 */
116 RM1
, /* reg in opcode in bits 2-5 */
117 RM2
, /* reg in opcode in bits 4-7 */
118 RM4
, /* reg in opcode in bits 8-11 */
119 RM6
, /* reg in opcode in bits 12-15 */
121 RD0
, /* reg in displacement in bits 0-3 */
122 RD2
, /* reg in displacement in bits 4-7 */
124 SP
, /* stack pointer */
126 SD8
, /* 8-bit signed displacement */
127 SD16
, /* 16-bit signed displacement */
128 SD24
, /* 24-bit signed displacement */
129 SIMM4_2
, /* 4-bit signed displacement in opcode bits 4-7 */
130 SIMM8
, /* 8-bit signed immediate */
131 IMM24
, /* 24-bit unsigned immediate */
132 IMM32
, /* 32-bit unsigned immediate */
133 IMM32_HIGH8
, /* 32-bit unsigned immediate, high 8-bits in opcode */
151 struct mn10300_opcode
{
157 enum format_id format
;
163 #define MEM(ADDR) (0x80000000 | (ADDR))
164 #define MEM2(ADDR1, ADDR2) (0x80000000 | (ADDR1) << 8 | (ADDR2))
165 #define MEMINC(ADDR) (0x81000000 | (ADDR))
166 #define MEMINC2(ADDR, INC) (0x81000000 | (ADDR) << 8 | (INC))
169 /* LIBOPCODES EXCERPT
170 Assemble Matsushita MN10300 instructions.
171 Copyright 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
173 This program is free software; you can redistribute it and/or modify
174 it under the terms of the GNU General Public Licence as published by
175 the Free Software Foundation; either version 2 of the Licence, or
176 (at your option) any later version.
178 This program is distributed in the hope that it will be useful,
179 but WITHOUT ANY WARRANTY; without even the implied warranty of
180 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
181 GNU General Public Licence for more details.
183 You should have received a copy of the GNU General Public Licence
184 along with this program; if not, write to the Free Software
185 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
187 static const struct mn10300_opcode mn10300_opcodes
[] = {
188 { "mov", 0x60, 0xf0, 0, FMT_S0
, 0, {DM1
, MEM(AN0
)}},
189 { "mov", 0x70, 0xf0, 0, FMT_S0
, 0, {MEM(AM0
), DN1
}},
190 { "mov", 0xf000, 0xfff0, 0, FMT_D0
, 0, {MEM(AM0
), AN1
}},
191 { "mov", 0xf010, 0xfff0, 0, FMT_D0
, 0, {AM1
, MEM(AN0
)}},
192 { "mov", 0xf300, 0xffc0, 0, FMT_D0
, 0, {MEM2(DI
, AM0
), DN2
}},
193 { "mov", 0xf340, 0xffc0, 0, FMT_D0
, 0, {DM2
, MEM2(DI
, AN0
)}},
194 { "mov", 0xf380, 0xffc0, 0, FMT_D0
, 0, {MEM2(DI
, AM0
), AN2
}},
195 { "mov", 0xf3c0, 0xffc0, 0, FMT_D0
, 0, {AM2
, MEM2(DI
, AN0
)}},
196 { "mov", 0xf80000, 0xfff000, 0, FMT_D1
, 0, {MEM2(SD8
, AM0
), DN1
}},
197 { "mov", 0xf81000, 0xfff000, 0, FMT_D1
, 0, {DM1
, MEM2(SD8
, AN0
)}},
198 { "mov", 0xf82000, 0xfff000, 0, FMT_D1
, 0, {MEM2(SD8
,AM0
), AN1
}},
199 { "mov", 0xf83000, 0xfff000, 0, FMT_D1
, 0, {AM1
, MEM2(SD8
, AN0
)}},
200 { "mov", 0xf8f000, 0xfffc00, 0, FMT_D1
, AM33
, {MEM2(SD8
, AM0
), SP
}},
201 { "mov", 0xf8f400, 0xfffc00, 0, FMT_D1
, AM33
, {SP
, MEM2(SD8
, AN0
)}},
202 { "mov", 0xf90a00, 0xffff00, 0, FMT_D6
, AM33
, {MEM(RM0
), RN2
}},
203 { "mov", 0xf91a00, 0xffff00, 0, FMT_D6
, AM33
, {RM2
, MEM(RN0
)}},
204 { "mov", 0xf96a00, 0xffff00, 0x12, FMT_D6
, AM33
, {MEMINC(RM0
), RN2
}},
205 { "mov", 0xf97a00, 0xffff00, 0, FMT_D6
, AM33
, {RM2
, MEMINC(RN0
)}},
206 { "mov", 0xfa000000, 0xfff00000, 0, FMT_D2
, 0, {MEM2(SD16
, AM0
), DN1
}},
207 { "mov", 0xfa100000, 0xfff00000, 0, FMT_D2
, 0, {DM1
, MEM2(SD16
, AN0
)}},
208 { "mov", 0xfa200000, 0xfff00000, 0, FMT_D2
, 0, {MEM2(SD16
, AM0
), AN1
}},
209 { "mov", 0xfa300000, 0xfff00000, 0, FMT_D2
, 0, {AM1
, MEM2(SD16
, AN0
)}},
210 { "mov", 0xfb0a0000, 0xffff0000, 0, FMT_D7
, AM33
, {MEM2(SD8
, RM0
), RN2
}},
211 { "mov", 0xfb1a0000, 0xffff0000, 0, FMT_D7
, AM33
, {RM2
, MEM2(SD8
, RN0
)}},
212 { "mov", 0xfb6a0000, 0xffff0000, 0x22, FMT_D7
, AM33
, {MEMINC2 (RM0
, SIMM8
), RN2
}},
213 { "mov", 0xfb7a0000, 0xffff0000, 0, FMT_D7
, AM33
, {RM2
, MEMINC2 (RN0
, SIMM8
)}},
214 { "mov", 0xfb8e0000, 0xffff000f, 0, FMT_D7
, AM33
, {MEM2(RI
, RM0
), RD2
}},
215 { "mov", 0xfb9e0000, 0xffff000f, 0, FMT_D7
, AM33
, {RD2
, MEM2(RI
, RN0
)}},
216 { "mov", 0xfc000000, 0xfff00000, 0, FMT_D4
, 0, {MEM2(IMM32
,AM0
), DN1
}},
217 { "mov", 0xfc100000, 0xfff00000, 0, FMT_D4
, 0, {DM1
, MEM2(IMM32
,AN0
)}},
218 { "mov", 0xfc200000, 0xfff00000, 0, FMT_D4
, 0, {MEM2(IMM32
,AM0
), AN1
}},
219 { "mov", 0xfc300000, 0xfff00000, 0, FMT_D4
, 0, {AM1
, MEM2(IMM32
,AN0
)}},
220 { "mov", 0xfd0a0000, 0xffff0000, 0, FMT_D8
, AM33
, {MEM2(SD24
, RM0
), RN2
}},
221 { "mov", 0xfd1a0000, 0xffff0000, 0, FMT_D8
, AM33
, {RM2
, MEM2(SD24
, RN0
)}},
222 { "mov", 0xfd6a0000, 0xffff0000, 0x22, FMT_D8
, AM33
, {MEMINC2 (RM0
, IMM24
), RN2
}},
223 { "mov", 0xfd7a0000, 0xffff0000, 0, FMT_D8
, AM33
, {RM2
, MEMINC2 (RN0
, IMM24
)}},
224 { "mov", 0xfe0a0000, 0xffff0000, 0, FMT_D9
, AM33
, {MEM2(IMM32_HIGH8
,RM0
), RN2
}},
225 { "mov", 0xfe1a0000, 0xffff0000, 0, FMT_D9
, AM33
, {RM2
, MEM2(IMM32_HIGH8
, RN0
)}},
226 { "mov", 0xfe6a0000, 0xffff0000, 0x22, FMT_D9
, AM33
, {MEMINC2 (RM0
, IMM32_HIGH8
), RN2
}},
227 { "mov", 0xfe7a0000, 0xffff0000, 0, FMT_D9
, AM33
, {RN2
, MEMINC2 (RM0
, IMM32_HIGH8
)}},
229 { "movhu", 0xf060, 0xfff0, 0, FMT_D0
, 0, {MEM(AM0
), DN1
}},
230 { "movhu", 0xf070, 0xfff0, 0, FMT_D0
, 0, {DM1
, MEM(AN0
)}},
231 { "movhu", 0xf480, 0xffc0, 0, FMT_D0
, 0, {MEM2(DI
, AM0
), DN2
}},
232 { "movhu", 0xf4c0, 0xffc0, 0, FMT_D0
, 0, {DM2
, MEM2(DI
, AN0
)}},
233 { "movhu", 0xf86000, 0xfff000, 0, FMT_D1
, 0, {MEM2(SD8
, AM0
), DN1
}},
234 { "movhu", 0xf87000, 0xfff000, 0, FMT_D1
, 0, {DM1
, MEM2(SD8
, AN0
)}},
235 { "movhu", 0xf94a00, 0xffff00, 0, FMT_D6
, AM33
, {MEM(RM0
), RN2
}},
236 { "movhu", 0xf95a00, 0xffff00, 0, FMT_D6
, AM33
, {RM2
, MEM(RN0
)}},
237 { "movhu", 0xf9ea00, 0xffff00, 0x12, FMT_D6
, AM33
, {MEMINC(RM0
), RN2
}},
238 { "movhu", 0xf9fa00, 0xffff00, 0, FMT_D6
, AM33
, {RM2
, MEMINC(RN0
)}},
239 { "movhu", 0xfa600000, 0xfff00000, 0, FMT_D2
, 0, {MEM2(SD16
, AM0
), DN1
}},
240 { "movhu", 0xfa700000, 0xfff00000, 0, FMT_D2
, 0, {DM1
, MEM2(SD16
, AN0
)}},
241 { "movhu", 0xfb4a0000, 0xffff0000, 0, FMT_D7
, AM33
, {MEM2(SD8
, RM0
), RN2
}},
242 { "movhu", 0xfb5a0000, 0xffff0000, 0, FMT_D7
, AM33
, {RM2
, MEM2(SD8
, RN0
)}},
243 { "movhu", 0xfbce0000, 0xffff000f, 0, FMT_D7
, AM33
, {MEM2(RI
, RM0
), RD2
}},
244 { "movhu", 0xfbde0000, 0xffff000f, 0, FMT_D7
, AM33
, {RD2
, MEM2(RI
, RN0
)}},
245 { "movhu", 0xfbea0000, 0xffff0000, 0x22, FMT_D7
, AM33
, {MEMINC2 (RM0
, SIMM8
), RN2
}},
246 { "movhu", 0xfbfa0000, 0xffff0000, 0, FMT_D7
, AM33
, {RM2
, MEMINC2 (RN0
, SIMM8
)}},
247 { "movhu", 0xfc600000, 0xfff00000, 0, FMT_D4
, 0, {MEM2(IMM32
,AM0
), DN1
}},
248 { "movhu", 0xfc700000, 0xfff00000, 0, FMT_D4
, 0, {DM1
, MEM2(IMM32
,AN0
)}},
249 { "movhu", 0xfd4a0000, 0xffff0000, 0, FMT_D8
, AM33
, {MEM2(SD24
, RM0
), RN2
}},
250 { "movhu", 0xfd5a0000, 0xffff0000, 0, FMT_D8
, AM33
, {RM2
, MEM2(SD24
, RN0
)}},
251 { "movhu", 0xfdea0000, 0xffff0000, 0x22, FMT_D8
, AM33
, {MEMINC2 (RM0
, IMM24
), RN2
}},
252 { "movhu", 0xfdfa0000, 0xffff0000, 0, FMT_D8
, AM33
, {RM2
, MEMINC2 (RN0
, IMM24
)}},
253 { "movhu", 0xfe4a0000, 0xffff0000, 0, FMT_D9
, AM33
, {MEM2(IMM32_HIGH8
,RM0
), RN2
}},
254 { "movhu", 0xfe5a0000, 0xffff0000, 0, FMT_D9
, AM33
, {RM2
, MEM2(IMM32_HIGH8
, RN0
)}},
255 { "movhu", 0xfeea0000, 0xffff0000, 0x22, FMT_D9
, AM33
, {MEMINC2 (RM0
, IMM32_HIGH8
), RN2
}},
256 { "movhu", 0xfefa0000, 0xffff0000, 0, FMT_D9
, AM33
, {RN2
, MEMINC2 (RM0
, IMM32_HIGH8
)}},
257 { 0, 0, 0, 0, 0, 0, {0}},
261 * fix up misalignment problems where possible
263 asmlinkage
void misalignment(struct pt_regs
*regs
, enum exception_code code
)
265 const struct exception_table_entry
*fixup
;
266 const struct mn10300_opcode
*pop
;
267 unsigned long *registers
= (unsigned long *) regs
;
268 unsigned long data
, *store
, *postinc
;
271 uint32_t opcode
, disp
, noc
, xo
, xm
;
276 kdebug("MISALIGN at %lx\n", regs
->pc
);
279 die("Misalignment trap in interrupt context", regs
, code
);
281 if (regs
->epsw
& EPSW_IE
)
282 asm volatile("or %0,epsw" : : "i"(EPSW_IE
));
287 fixup
= search_exception_tables(regs
->pc
);
289 /* first thing to do is to match the opcode */
290 pc
= (u_int8_t
*) regs
->pc
;
292 if (__get_user(byte
, pc
) != 0)
297 for (pop
= mn10300_opcodes
; pop
->name
; pop
++) {
298 npop
= log2(pop
->opcode
| pop
->opmask
);
299 if (npop
<= 0 || npop
> 31)
301 npop
= (npop
+ 8) & ~7;
305 if ((opcode
& pop
->opmask
) == pop
->opcode
)
307 } else if (npop
> noc
) {
308 xo
= pop
->opcode
>> (npop
- noc
);
309 xm
= pop
->opmask
>> (npop
- noc
);
311 if ((opcode
& xm
) != xo
)
314 /* we've got a partial match (an exact match on the
315 * first N bytes), so we need to get some more data */
317 if (__get_user(byte
, pc
) != 0)
319 opcode
= opcode
<< 8 | byte
;
323 /* there's already been a partial match as long as the
324 * complete match we're now considering, so this one
330 /* didn't manage to find a fixup */
331 if (!user_mode(regs
))
332 printk(KERN_CRIT
"MISALIGN: %lx: unsupported instruction %x\n",
337 if (die_if_no_fixup("misalignment error", regs
, code
))
340 info
.si_signo
= SIGBUS
;
342 info
.si_code
= BUS_ADRALN
;
343 info
.si_addr
= (void *) regs
->pc
;
344 force_sig_info(SIGBUS
, &info
, current
);
347 /* error reading opcodes */
349 if (!user_mode(regs
))
351 "MISALIGN: %p: fault whilst reading instruction data\n",
356 if (!user_mode(regs
))
358 "MISALIGN: %lx: unsupported addressing mode %x\n",
363 if (!user_mode(regs
))
365 "MISALIGN: %lx: unsupported register mode %x\n",
369 unsupported_instruction
:
370 if (!user_mode(regs
))
372 "MISALIGN: %lx: unsupported instruction %x (%s)\n",
373 regs
->pc
, opcode
, pop
->name
);
379 regs
->pc
= fixup
->fixup
;
382 if (die_if_no_fixup("misalignment fixup", regs
, code
))
385 info
.si_signo
= SIGSEGV
;
388 info
.si_addr
= (void *) regs
->pc
;
389 force_sig_info(SIGSEGV
, &info
, current
);
392 /* we matched the opcode */
394 kdebug("MISALIGN: %lx: %x==%x { %x, %x }\n",
395 regs
->pc
, opcode
, pop
->opcode
, pop
->params
[0], pop
->params
[1]);
397 tmp
= format_tbl
[pop
->format
].opsz
;
399 BUG(); /* match was less complete than it ought to have been */
407 /* grab the extra displacement (note it's LSB first) */
409 tmp
= format_tbl
[pop
->format
].dispsz
>> 3;
415 if (__get_user(byte
, pc
) != 0)
421 if (fixup
|| regs
->epsw
& EPSW_nSL
)
424 tmp
= (pop
->params
[0] ^ pop
->params
[1]) & 0x80000000;
426 if (!user_mode(regs
))
429 " insn not move to/from memory %x\n",
434 if (pop
->params
[0] & 0x80000000) {
435 /* move memory to register */
436 if (!misalignment_addr(registers
, pop
->params
[0], opcode
, disp
,
440 if (!misalignment_reg(registers
, pop
->params
[1], opcode
, disp
,
444 if (strcmp(pop
->name
, "mov") == 0) {
445 kdebug("FIXUP: mov (%p),DARn\n", address
);
446 if (copy_from_user(&data
, (void *) address
, 4) != 0)
447 goto transfer_failed
;
448 if (pop
->params
[0] & 0x1000000)
450 } else if (strcmp(pop
->name
, "movhu") == 0) {
451 kdebug("FIXUP: movhu (%p),DARn\n", address
);
453 if (copy_from_user(&data
, (void *) address
, 2) != 0)
454 goto transfer_failed
;
455 if (pop
->params
[0] & 0x1000000)
458 goto unsupported_instruction
;
463 /* move register to memory */
464 if (!misalignment_reg(registers
, pop
->params
[0], opcode
, disp
,
468 if (!misalignment_addr(registers
, pop
->params
[1], opcode
, disp
,
474 if (strcmp(pop
->name
, "mov") == 0) {
475 kdebug("FIXUP: mov %lx,(%p)\n", data
, address
);
476 if (copy_to_user((void *) address
, &data
, 4) != 0)
477 goto transfer_failed
;
478 if (pop
->params
[1] & 0x1000000)
480 } else if (strcmp(pop
->name
, "movhu") == 0) {
481 kdebug("FIXUP: movhu %hx,(%p)\n",
482 (uint16_t) data
, address
);
483 if (copy_to_user((void *) address
, &data
, 2) != 0)
484 goto transfer_failed
;
485 if (pop
->params
[1] & 0x1000000)
488 goto unsupported_instruction
;
492 tmp
= format_tbl
[pop
->format
].opsz
+ format_tbl
[pop
->format
].dispsz
;
493 regs
->pc
+= tmp
>> 3;
500 * determine the address that was being accessed
502 static int misalignment_addr(unsigned long *registers
, unsigned params
,
503 unsigned opcode
, unsigned disp
,
504 void **_address
, unsigned long **_postinc
)
506 unsigned long *postinc
= NULL
, address
= 0, tmp
;
508 params
&= 0x7fffffff;
511 switch (params
& 0xff) {
513 postinc
= ®isters
[Dreg_index
[opcode
& 0x03]];
517 postinc
= ®isters
[Dreg_index
[opcode
>> 2 & 0x0c]];
521 postinc
= ®isters
[Dreg_index
[opcode
>> 4 & 0x30]];
525 postinc
= ®isters
[Areg_index
[opcode
& 0x03]];
529 postinc
= ®isters
[Areg_index
[opcode
>> 2 & 0x0c]];
533 postinc
= ®isters
[Areg_index
[opcode
>> 4 & 0x30]];
537 postinc
= ®isters
[Rreg_index
[opcode
& 0x0f]];
541 postinc
= ®isters
[Rreg_index
[opcode
>> 2 & 0x0f]];
545 postinc
= ®isters
[Rreg_index
[opcode
>> 4 & 0x0f]];
549 postinc
= ®isters
[Rreg_index
[opcode
>> 8 & 0x0f]];
553 postinc
= ®isters
[Rreg_index
[opcode
>> 12 & 0x0f]];
557 postinc
= ®isters
[Rreg_index
[disp
& 0x0f]];
561 postinc
= ®isters
[Rreg_index
[disp
>> 4 & 0x0f]];
567 address
+= (int32_t) (int8_t) (disp
& 0xff);
570 address
+= (int32_t) (int16_t) (disp
& 0xffff);
574 asm("asr 8,%0" : "=r"(tmp
) : "0"(tmp
));
578 tmp
= opcode
>> 4 & 0x0f;
580 asm("asr 28,%0" : "=r"(tmp
) : "0"(tmp
));
584 address
+= disp
& 0x00ffffff;
593 } while ((params
>>= 8));
595 *_address
= (void *) address
;
601 * determine the register that is acting as source/dest
603 static int misalignment_reg(unsigned long *registers
, unsigned params
,
604 unsigned opcode
, unsigned disp
,
605 unsigned long **_register
)
607 params
&= 0x7fffffff;
609 if (params
& 0xffffff00)
612 switch (params
& 0xff) {
614 *_register
= ®isters
[Dreg_index
[opcode
& 0x03]];
617 *_register
= ®isters
[Dreg_index
[opcode
>> 2 & 0x03]];
620 *_register
= ®isters
[Dreg_index
[opcode
>> 4 & 0x03]];
623 *_register
= ®isters
[Areg_index
[opcode
& 0x03]];
626 *_register
= ®isters
[Areg_index
[opcode
>> 2 & 0x03]];
629 *_register
= ®isters
[Areg_index
[opcode
>> 4 & 0x03]];
632 *_register
= ®isters
[Rreg_index
[opcode
& 0x0f]];
635 *_register
= ®isters
[Rreg_index
[opcode
>> 2 & 0x0f]];
638 *_register
= ®isters
[Rreg_index
[opcode
>> 4 & 0x0f]];
641 *_register
= ®isters
[Rreg_index
[opcode
>> 8 & 0x0f]];
644 *_register
= ®isters
[Rreg_index
[opcode
>> 12 & 0x0f]];
647 *_register
= ®isters
[Rreg_index
[disp
& 0x0f]];
650 *_register
= ®isters
[Rreg_index
[disp
>> 4 & 0x0f]];
653 *_register
= ®isters
[REG_SP
>> 2];