Revision 9fddaa0c
b/cpu-all.h | ||
---|---|---|
627 | 627 |
if no page found. */ |
628 | 628 |
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr); |
629 | 629 |
|
630 |
#define CPU_LOG_TB_OUT_ASM (1 << 0)
|
|
631 |
#define CPU_LOG_TB_IN_ASM (1 << 1)
|
|
630 |
#define CPU_LOG_TB_OUT_ASM (1 << 0) |
|
631 |
#define CPU_LOG_TB_IN_ASM (1 << 1) |
|
632 | 632 |
#define CPU_LOG_TB_OP (1 << 2) |
633 | 633 |
#define CPU_LOG_TB_OP_OPT (1 << 3) |
634 | 634 |
#define CPU_LOG_INT (1 << 4) |
635 | 635 |
#define CPU_LOG_EXEC (1 << 5) |
636 | 636 |
#define CPU_LOG_PCALL (1 << 6) |
637 | 637 |
#define CPU_LOG_IOPORT (1 << 7) |
638 |
#define CPU_LOG_TB_CPU (1 << 8) |
|
638 | 639 |
|
639 | 640 |
/* define log items */ |
640 | 641 |
typedef struct CPULogItem { |
b/cpu-exec.c | ||
---|---|---|
241 | 241 |
#endif |
242 | 242 |
} |
243 | 243 |
#elif defined(TARGET_PPC) |
244 |
#if 0 |
|
245 |
if ((interrupt_request & CPU_INTERRUPT_RESET)) { |
|
246 |
cpu_ppc_reset(env); |
|
247 |
} |
|
248 |
#endif |
|
249 |
if (msr_ee != 0) { |
|
244 | 250 |
if ((interrupt_request & CPU_INTERRUPT_HARD)) { |
245 |
do_queue_exception(EXCP_EXTERNAL); |
|
246 |
if (check_exception_state(env)) |
|
251 |
/* Raise it */ |
|
252 |
env->exception_index = EXCP_EXTERNAL; |
|
253 |
env->error_code = 0; |
|
247 | 254 |
do_interrupt(env); |
248 | 255 |
env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
256 |
} else if ((interrupt_request & CPU_INTERRUPT_TIMER)) { |
|
257 |
/* Raise it */ |
|
258 |
env->exception_index = EXCP_DECR; |
|
259 |
env->error_code = 0; |
|
260 |
do_interrupt(env); |
|
261 |
env->interrupt_request &= ~CPU_INTERRUPT_TIMER; |
|
262 |
} |
|
249 | 263 |
} |
250 | 264 |
#endif |
251 | 265 |
if (interrupt_request & CPU_INTERRUPT_EXITTB) { |
... | ... | |
757 | 771 |
/* we restore the process signal mask as the sigreturn should |
758 | 772 |
do it (XXX: use sigsetjmp) */ |
759 | 773 |
sigprocmask(SIG_SETMASK, old_set, NULL); |
760 |
do_queue_exception_err(env->exception_index, env->error_code);
|
|
774 |
do_raise_exception_err(env->exception_index, env->error_code);
|
|
761 | 775 |
} else { |
762 | 776 |
/* activate soft MMU for this block */ |
763 | 777 |
cpu_resume_from_signal(env, puc); |
b/exec.c | ||
---|---|---|
1132 | 1132 |
"show interrupts/exceptions in short format" }, |
1133 | 1133 |
{ CPU_LOG_EXEC, "exec", |
1134 | 1134 |
"show trace before each executed TB (lots of logs)" }, |
1135 |
{ CPU_LOG_TB_CPU, "cpu", |
|
1136 |
"show CPU state before bloc translation" }, |
|
1135 | 1137 |
#ifdef TARGET_I386 |
1136 | 1138 |
{ CPU_LOG_PCALL, "pcall", |
1137 | 1139 |
"show protected mode far calls/returns/exceptions" }, |
b/hw/ppc.c | ||
---|---|---|
28 | 28 |
const char *kernel_filename, const char *kernel_cmdline, |
29 | 29 |
const char *initrd_filename); |
30 | 30 |
|
31 |
/*****************************************************************************/ |
|
32 |
/* PPC time base and decrementer emulation */ |
|
33 |
//#define DEBUG_TB |
|
34 |
|
|
35 |
struct ppc_tb_t { |
|
36 |
/* Time base management */ |
|
37 |
int64_t tb_offset; /* Compensation */ |
|
38 |
uint32_t tb_freq; /* TB frequency */ |
|
39 |
/* Decrementer management */ |
|
40 |
uint64_t decr_next; /* Tick for next decr interrupt */ |
|
41 |
struct QEMUTimer *decr_timer; |
|
42 |
}; |
|
43 |
|
|
44 |
static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env) |
|
45 |
{ |
|
46 |
/* TB time in tb periods */ |
|
47 |
return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset, |
|
48 |
tb_env->tb_freq, ticks_per_sec); |
|
49 |
} |
|
50 |
|
|
51 |
uint32_t cpu_ppc_load_tbl (CPUState *env) |
|
52 |
{ |
|
53 |
ppc_tb_t *tb_env = env->tb_env; |
|
54 |
uint64_t tb; |
|
55 |
|
|
56 |
tb = cpu_ppc_get_tb(tb_env); |
|
57 |
#ifdef DEBUG_TB |
|
58 |
{ |
|
59 |
static int last_time; |
|
60 |
int now; |
|
61 |
now = time(NULL); |
|
62 |
if (last_time != now) { |
|
63 |
last_time = now; |
|
64 |
printf("%s: tb=0x%016lx %d %08lx\n", |
|
65 |
__func__, tb, now, tb_env->tb_offset); |
|
66 |
} |
|
67 |
} |
|
68 |
#endif |
|
69 |
|
|
70 |
return tb & 0xFFFFFFFF; |
|
71 |
} |
|
72 |
|
|
73 |
uint32_t cpu_ppc_load_tbu (CPUState *env) |
|
74 |
{ |
|
75 |
ppc_tb_t *tb_env = env->tb_env; |
|
76 |
uint64_t tb; |
|
77 |
|
|
78 |
tb = cpu_ppc_get_tb(tb_env); |
|
79 |
#ifdef DEBUG_TB |
|
80 |
printf("%s: tb=0x%016lx\n", __func__, tb); |
|
81 |
#endif |
|
82 |
return tb >> 32; |
|
83 |
} |
|
84 |
|
|
85 |
static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value) |
|
86 |
{ |
|
87 |
tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq) |
|
88 |
- qemu_get_clock(vm_clock); |
|
89 |
#ifdef DEBUG_TB |
|
90 |
printf("%s: tb=0x%016lx offset=%08x\n", __func__, value); |
|
91 |
#endif |
|
92 |
} |
|
93 |
|
|
94 |
void cpu_ppc_store_tbu (CPUState *env, uint32_t value) |
|
95 |
{ |
|
96 |
ppc_tb_t *tb_env = env->tb_env; |
|
97 |
|
|
98 |
cpu_ppc_store_tb(tb_env, |
|
99 |
((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); |
|
100 |
} |
|
101 |
|
|
102 |
void cpu_ppc_store_tbl (CPUState *env, uint32_t value) |
|
103 |
{ |
|
104 |
ppc_tb_t *tb_env = env->tb_env; |
|
105 |
|
|
106 |
cpu_ppc_store_tb(tb_env, |
|
107 |
((uint64_t)cpu_ppc_load_tbu(env) << 32) | value); |
|
108 |
} |
|
109 |
|
|
110 |
uint32_t cpu_ppc_load_decr (CPUState *env) |
|
111 |
{ |
|
112 |
ppc_tb_t *tb_env = env->tb_env; |
|
113 |
uint32_t decr; |
|
114 |
|
|
115 |
decr = muldiv64(tb_env->decr_next - qemu_get_clock(vm_clock), |
|
116 |
tb_env->tb_freq, ticks_per_sec); |
|
117 |
#ifdef DEBUG_TB |
|
118 |
printf("%s: 0x%08x\n", __func__, decr); |
|
119 |
#endif |
|
120 |
|
|
121 |
return decr; |
|
122 |
} |
|
123 |
|
|
124 |
/* When decrementer expires, |
|
125 |
* all we need to do is generate or queue a CPU exception |
|
126 |
*/ |
|
127 |
static inline void cpu_ppc_decr_excp (CPUState *env) |
|
128 |
{ |
|
129 |
/* Raise it */ |
|
130 |
#ifdef DEBUG_TB |
|
131 |
printf("raise decrementer exception\n"); |
|
132 |
#endif |
|
133 |
cpu_interrupt(env, CPU_INTERRUPT_TIMER); |
|
134 |
} |
|
135 |
|
|
136 |
static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, |
|
137 |
uint32_t value, int is_excp) |
|
138 |
{ |
|
139 |
ppc_tb_t *tb_env = env->tb_env; |
|
140 |
uint64_t now, next; |
|
141 |
|
|
142 |
#ifdef DEBUG_TB |
|
143 |
printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value); |
|
144 |
#endif |
|
145 |
now = qemu_get_clock(vm_clock); |
|
146 |
next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq); |
|
147 |
if (is_excp) |
|
148 |
next += tb_env->decr_next - now; |
|
149 |
if (next == now) |
|
150 |
next++; |
|
151 |
tb_env->decr_next = next; |
|
152 |
/* Adjust timer */ |
|
153 |
qemu_mod_timer(tb_env->decr_timer, next); |
|
154 |
/* If we set a negative value and the decrementer was positive, |
|
155 |
* raise an exception. |
|
156 |
*/ |
|
157 |
if ((value & 0x80000000) && !(decr & 0x80000000)) |
|
158 |
cpu_ppc_decr_excp(env); |
|
159 |
} |
|
160 |
|
|
161 |
void cpu_ppc_store_decr (CPUState *env, uint32_t value) |
|
162 |
{ |
|
163 |
_cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0); |
|
164 |
} |
|
165 |
|
|
166 |
static void cpu_ppc_decr_cb (void *opaque) |
|
167 |
{ |
|
168 |
_cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1); |
|
169 |
} |
|
170 |
|
|
171 |
/* Set up (once) timebase frequency (in Hz) */ |
|
172 |
ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq) |
|
173 |
{ |
|
174 |
ppc_tb_t *tb_env; |
|
175 |
|
|
176 |
tb_env = qemu_mallocz(sizeof(ppc_tb_t)); |
|
177 |
if (tb_env == NULL) |
|
178 |
return NULL; |
|
179 |
env->tb_env = tb_env; |
|
180 |
if (tb_env->tb_freq == 0 || 1) { |
|
181 |
tb_env->tb_freq = freq; |
|
182 |
/* Create new timer */ |
|
183 |
tb_env->decr_timer = |
|
184 |
qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env); |
|
185 |
/* There is a bug in 2.4 kernels: |
|
186 |
* if a decrementer exception is pending when it enables msr_ee, |
|
187 |
* it's not ready to handle it... |
|
188 |
*/ |
|
189 |
_cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); |
|
190 |
} |
|
191 |
|
|
192 |
return tb_env; |
|
193 |
} |
|
194 |
|
|
195 |
#if 0 |
|
196 |
/*****************************************************************************/ |
|
197 |
/* Handle system reset (for now, just stop emulation) */ |
|
198 |
void cpu_ppc_reset (CPUState *env) |
|
199 |
{ |
|
200 |
printf("Reset asked... Stop emulation\n"); |
|
201 |
abort(); |
|
202 |
} |
|
203 |
#endif |
|
204 |
|
|
205 |
/*****************************************************************************/ |
|
31 | 206 |
void ppc_init (int ram_size, int vga_ram_size, int boot_device, |
32 | 207 |
DisplayState *ds, const char **fd_filename, int snapshot, |
33 | 208 |
const char *kernel_filename, const char *kernel_cmdline, |
b/hw/ppc_prep.c | ||
---|---|---|
24 | 24 |
#include "vl.h" |
25 | 25 |
#include "m48t59.h" |
26 | 26 |
|
27 |
/* XXX: move all TB related stuff in ppc_prep.c and suppress ppc.c ? */ |
|
28 |
ppc_tb_t *cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq); |
|
29 |
|
|
27 | 30 |
//#define HARD_DEBUG_PPC_IO |
28 | 31 |
//#define DEBUG_PPC_IO |
29 | 32 |
|
... | ... | |
663 | 666 |
static void VGA_init (void) |
664 | 667 |
{ |
665 | 668 |
/* Basic VGA init, inspired by plex86 VGAbios */ |
666 |
printf("Init VGA...\n"); |
|
667 | 669 |
#if 1 |
668 | 670 |
/* switch to color mode and enable CPU access 480 lines */ |
669 | 671 |
PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3); |
... | ... | |
725 | 727 |
* if a decrementer exception is pending when it enables msr_ee, |
726 | 728 |
* it's not ready to handle it... |
727 | 729 |
*/ |
728 |
env->decr = 0xFFFFFFFF; |
|
729 | 730 |
p = phys_ram_base + kernel_addr; |
730 | 731 |
#if !defined (USE_OPEN_FIRMWARE) |
731 | 732 |
/* Let's register the whole memory available only in supervisor mode */ |
... | ... | |
948 | 949 |
} |
949 | 950 |
} |
950 | 951 |
|
952 |
cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); |
|
953 |
|
|
951 | 954 |
/* init basic PC hardware */ |
952 | 955 |
vga_initialize(ds, phys_ram_base + ram_size, ram_size, |
953 | 956 |
vga_ram_size, 0); |
b/linux-user/main.c | ||
---|---|---|
504 | 504 |
#endif |
505 | 505 |
|
506 | 506 |
#ifdef TARGET_PPC |
507 |
|
|
508 |
static inline uint64_t cpu_ppc_get_tb (CPUState *env) |
|
509 |
{ |
|
510 |
/* TO FIX */ |
|
511 |
return 0; |
|
512 |
} |
|
513 |
|
|
514 |
uint32_t cpu_ppc_load_tbl (CPUState *env) |
|
515 |
{ |
|
516 |
return cpu_ppc_get_tb(env) & 0xFFFFFFFF; |
|
517 |
} |
|
518 |
|
|
519 |
uint32_t cpu_ppc_load_tbu (CPUState *env) |
|
520 |
{ |
|
521 |
return cpu_ppc_get_tb(env) >> 32; |
|
522 |
} |
|
523 |
|
|
524 |
static void cpu_ppc_store_tb (CPUState *env, uint64_t value) |
|
525 |
{ |
|
526 |
/* TO FIX */ |
|
527 |
} |
|
528 |
|
|
529 |
void cpu_ppc_store_tbu (CPUState *env, uint32_t value) |
|
530 |
{ |
|
531 |
cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); |
|
532 |
} |
|
533 |
|
|
534 |
void cpu_ppc_store_tbl (CPUState *env, uint32_t value) |
|
535 |
{ |
|
536 |
cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); |
|
537 |
} |
|
538 |
|
|
539 |
uint32_t cpu_ppc_load_decr (CPUState *env) |
|
540 |
{ |
|
541 |
/* TO FIX */ |
|
542 |
return -1; |
|
543 |
} |
|
544 |
|
|
545 |
void cpu_ppc_store_decr (CPUState *env, uint32_t value) |
|
546 |
{ |
|
547 |
/* TO FIX */ |
|
548 |
} |
|
549 |
|
|
507 | 550 |
void cpu_loop(CPUPPCState *env) |
508 | 551 |
{ |
509 | 552 |
target_siginfo_t info; |
... | ... | |
812 | 855 |
abort(); |
813 | 856 |
case EXCP_MTMSR: |
814 | 857 |
/* We reloaded the msr, just go on */ |
815 |
if (msr_pr) { |
|
858 |
if (msr_pr == 0) {
|
|
816 | 859 |
fprintf(stderr, "Tried to go into supervisor mode !\n"); |
817 | 860 |
if (loglevel) |
818 | 861 |
fprintf(logfile, "Tried to go into supervisor mode !\n"); |
... | ... | |
842 | 885 |
} |
843 | 886 |
abort(); |
844 | 887 |
} |
845 |
if (trapnr < EXCP_PPC_MAX) |
|
846 |
env->exceptions &= ~(1 << trapnr); |
|
847 | 888 |
process_pending_signals(env); |
848 |
if (env->exceptions != 0) { |
|
849 |
check_exception_state(env); |
|
850 |
} |
|
851 | 889 |
} |
852 | 890 |
} |
853 | 891 |
#endif |
b/monitor.c | ||
---|---|---|
589 | 589 |
(cpu_single_env->xer[XER_CA] << XER_CA) | |
590 | 590 |
(cpu_single_env->xer[XER_BC] << XER_BC); |
591 | 591 |
} |
592 |
|
|
593 |
uint32_t cpu_ppc_load_decr (CPUState *env); |
|
594 |
static int monitor_get_decr (struct MonitorDef *md) |
|
595 |
{ |
|
596 |
return cpu_ppc_load_decr(cpu_single_env); |
|
597 |
} |
|
598 |
|
|
599 |
uint32_t cpu_ppc_load_tbu (CPUState *env); |
|
600 |
static int monitor_get_tbu (struct MonitorDef *md) |
|
601 |
{ |
|
602 |
return cpu_ppc_load_tbu(cpu_single_env); |
|
603 |
} |
|
604 |
|
|
605 |
uint32_t cpu_ppc_load_tbl (CPUState *env); |
|
606 |
static int monitor_get_tbl (struct MonitorDef *md) |
|
607 |
{ |
|
608 |
return cpu_ppc_load_tbl(cpu_single_env); |
|
609 |
} |
|
592 | 610 |
#endif |
593 | 611 |
|
594 | 612 |
static MonitorDef monitor_defs[] = { |
... | ... | |
651 | 669 |
{ "nip|pc", offsetof(CPUState, nip) }, |
652 | 670 |
{ "lr", offsetof(CPUState, lr) }, |
653 | 671 |
{ "ctr", offsetof(CPUState, ctr) }, |
654 |
{ "decr", offsetof(CPUState, decr) },
|
|
672 |
{ "decr", 0, &monitor_get_decr, },
|
|
655 | 673 |
{ "ccr", 0, &monitor_get_ccr, }, |
656 | 674 |
{ "msr", 0, &monitor_get_msr, }, |
657 | 675 |
{ "xer", 0, &monitor_get_xer, }, |
658 |
{ "tbu", offsetof(CPUState, tb[0]) },
|
|
659 |
{ "tbl", offsetof(CPUState, tb[1]) },
|
|
676 |
{ "tbu", 0, &monitor_get_tbu, },
|
|
677 |
{ "tbl", 0, &monitor_get_tbl, },
|
|
660 | 678 |
{ "sdr1", offsetof(CPUState, sdr1) }, |
661 | 679 |
{ "sr0", offsetof(CPUState, sr[0]) }, |
662 | 680 |
{ "sr1", offsetof(CPUState, sr[1]) }, |
b/target-ppc/cpu.h | ||
---|---|---|
78 | 78 |
#define PPC_750 (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \ |
79 | 79 |
PPC_RES | PPC_CACHE | PPC_MISC | PPC_EXTERN | PPC_SEGMENT) |
80 | 80 |
|
81 |
typedef struct ppc_tb_t ppc_tb_t; |
|
82 |
|
|
81 | 83 |
/* Supervisor mode registers */ |
82 | 84 |
/* Machine state register */ |
83 | 85 |
#define MSR_POW 18 |
... | ... | |
134 | 136 |
/* special purpose registers */ |
135 | 137 |
uint32_t lr; |
136 | 138 |
uint32_t ctr; |
137 |
/* Time base */ |
|
138 |
uint32_t tb[2]; |
|
139 |
/* decrementer */ |
|
140 |
uint32_t decr; |
|
141 | 139 |
/* BATs */ |
142 | 140 |
uint32_t DBAT[2][8]; |
143 | 141 |
uint32_t IBAT[2][8]; |
... | ... | |
154 | 152 |
int error_code; |
155 | 153 |
int access_type; /* when a memory exception occurs, the access |
156 | 154 |
type is stored here */ |
157 |
#if 0 /* TODO */ |
|
158 |
uint32_t pending_exceptions; /* For external & decr exception, |
|
159 |
* that can be delayed */ |
|
160 |
#else |
|
161 |
uint32_t exceptions; /* exception queue */ |
|
162 |
uint32_t errors[32]; |
|
163 |
#endif |
|
164 | 155 |
int user_mode_only; /* user mode only simulation */ |
165 | 156 |
struct TranslationBlock *current_tb; /* currently executing TB */ |
166 | 157 |
/* soft mmu support */ |
... | ... | |
178 | 169 |
/* ice debug support */ |
179 | 170 |
uint32_t breakpoints[MAX_BREAKPOINTS]; |
180 | 171 |
int nb_breakpoints; |
181 |
int brkstate; |
|
182 |
int singlestep_enabled; |
|
172 |
int singlestep_enabled; /* XXX: should use CPU single step mode instead */ |
|
173 |
|
|
174 |
/* Time base and decrementer */ |
|
175 |
ppc_tb_t *tb_env; |
|
176 |
|
|
177 |
/* Power management */ |
|
178 |
int power_mode; |
|
183 | 179 |
|
184 | 180 |
/* user data */ |
185 | 181 |
void *opaque; |
... | ... | |
206 | 202 |
uint32_t _load_msr (CPUPPCState *env); |
207 | 203 |
void _store_msr (CPUPPCState *env, uint32_t value); |
208 | 204 |
|
209 |
void PPC_init_hw (uint32_t mem_size, |
|
210 |
uint32_t kernel_addr, uint32_t kernel_size, |
|
211 |
uint32_t stack_addr, int boot_device, |
|
212 |
const unsigned char *initrd_file); |
|
205 |
/* Time-base and decrementer management */ |
|
206 |
#ifndef NO_CPU_IO_DEFS |
|
207 |
uint32_t cpu_ppc_load_tbl (CPUPPCState *env); |
|
208 |
uint32_t cpu_ppc_load_tbu (CPUPPCState *env); |
|
209 |
void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value); |
|
210 |
void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value); |
|
211 |
uint32_t cpu_ppc_load_decr (CPUPPCState *env); |
|
212 |
void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); |
|
213 |
#endif |
|
213 | 214 |
|
214 | 215 |
#define TARGET_PAGE_BITS 12 |
215 | 216 |
#include "cpu-all.h" |
b/target-ppc/exec.h | ||
---|---|---|
119 | 119 |
|
120 | 120 |
#endif /* !defined(CONFIG_USER_ONLY) */ |
121 | 121 |
|
122 |
int check_exception_state (CPUState *env); |
|
123 |
|
|
124 |
void do_queue_exception_err (uint32_t exception, int error_code); |
|
125 |
void do_queue_exception (uint32_t exception); |
|
126 |
void do_process_exceptions (void); |
|
127 |
void do_check_exception_state (void); |
|
122 |
void do_raise_exception_err (uint32_t exception, int error_code); |
|
123 |
void do_raise_exception (uint32_t exception); |
|
128 | 124 |
|
129 | 125 |
void do_load_cr (void); |
130 | 126 |
void do_store_cr (uint32_t mask); |
b/target-ppc/helper.c | ||
---|---|---|
27 | 27 |
//#define DEBUG_BATS |
28 | 28 |
//#define DEBUG_EXCEPTIONS |
29 | 29 |
|
30 |
extern FILE *logfile, *stdout, *stderr; |
|
31 |
void exit (int); |
|
30 |
extern FILE *stdout, *stderr; |
|
32 | 31 |
void abort (void); |
33 | 32 |
|
34 |
void cpu_loop_exit(void) |
|
35 |
{ |
|
36 |
longjmp(env->jmp_env, 1); |
|
37 |
} |
|
38 |
|
|
39 |
void do_process_exceptions (void) |
|
40 |
{ |
|
41 |
cpu_loop_exit(); |
|
42 |
} |
|
43 |
|
|
44 |
int check_exception_state (CPUState *env) |
|
45 |
{ |
|
46 |
int i; |
|
47 |
|
|
48 |
/* Process PPC exceptions */ |
|
49 |
for (i = 1; i < EXCP_PPC_MAX; i++) { |
|
50 |
if (env->exceptions & (1 << i)) { |
|
51 |
switch (i) { |
|
52 |
case EXCP_EXTERNAL: |
|
53 |
case EXCP_DECR: |
|
54 |
if (msr_ee == 0) |
|
55 |
return 0; |
|
56 |
break; |
|
57 |
case EXCP_PROGRAM: |
|
58 |
if (env->errors[EXCP_PROGRAM] == EXCP_FP && |
|
59 |
msr_fe0 == 0 && msr_fe1 == 0) |
|
60 |
return 0; |
|
61 |
break; |
|
62 |
default: |
|
63 |
break; |
|
64 |
} |
|
65 |
env->exception_index = i; |
|
66 |
env->error_code = env->errors[i]; |
|
67 |
return 1; |
|
68 |
} |
|
69 |
} |
|
70 |
|
|
71 |
return 0; |
|
72 |
} |
|
33 |
/*****************************************************************************/ |
|
73 | 34 |
|
74 | 35 |
/*****************************************************************************/ |
75 | 36 |
/* PPC MMU emulation */ |
... | ... | |
500 | 461 |
cpu_restore_state(tb, env, pc, NULL); |
501 | 462 |
} |
502 | 463 |
} |
503 |
do_queue_exception_err(env->exception_index, env->error_code); |
|
504 |
do_process_exceptions(); |
|
464 |
do_raise_exception_err(env->exception_index, env->error_code); |
|
505 | 465 |
} |
506 | 466 |
{ |
507 | 467 |
unsigned long tlb_addrr, tlb_addrw; |
... | ... | |
701 | 661 |
uint32_t msr; |
702 | 662 |
int excp = env->exception_index; |
703 | 663 |
|
704 |
/* Dequeue PPC exceptions */ |
|
705 |
if (excp < EXCP_PPC_MAX) |
|
706 |
env->exceptions &= ~(1 << excp); |
|
707 | 664 |
msr = _load_msr(env); |
708 | 665 |
#if defined (DEBUG_EXCEPTIONS) |
709 | 666 |
if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) |
... | ... | |
812 | 769 |
} |
813 | 770 |
#endif |
814 | 771 |
/* Requeue it */ |
815 |
do_queue_exception(EXCP_EXTERNAL);
|
|
772 |
do_raise_exception(EXCP_EXTERNAL);
|
|
816 | 773 |
return; |
817 | 774 |
} |
818 | 775 |
goto store_next; |
... | ... | |
864 | 821 |
case EXCP_DECR: |
865 | 822 |
if (msr_ee == 0) { |
866 | 823 |
/* Requeue it */ |
867 |
do_queue_exception(EXCP_DECR);
|
|
824 |
do_raise_exception(EXCP_DECR);
|
|
868 | 825 |
return; |
869 | 826 |
} |
870 | 827 |
goto store_next; |
... | ... | |
937 | 894 |
T0 = 0; |
938 | 895 |
#endif |
939 | 896 |
#endif |
897 |
env->exception_index = -1; |
|
940 | 898 |
} |
b/target-ppc/op.c | ||
---|---|---|
208 | 208 |
} |
209 | 209 |
|
210 | 210 |
/* Generate exceptions */ |
211 |
PPC_OP(queue_exception_err)
|
|
211 |
PPC_OP(raise_exception_err)
|
|
212 | 212 |
{ |
213 |
do_queue_exception_err(PARAM(1), PARAM(2));
|
|
213 |
do_raise_exception_err(PARAM(1), PARAM(2));
|
|
214 | 214 |
} |
215 | 215 |
|
216 |
PPC_OP(queue_exception)
|
|
216 |
PPC_OP(raise_exception)
|
|
217 | 217 |
{ |
218 |
do_queue_exception(PARAM(1));
|
|
218 |
do_raise_exception(PARAM(1));
|
|
219 | 219 |
} |
220 | 220 |
|
221 |
PPC_OP(process_exceptions)
|
|
221 |
PPC_OP(update_nip)
|
|
222 | 222 |
{ |
223 | 223 |
env->nip = PARAM(1); |
224 |
if (env->exceptions != 0) { |
|
225 |
do_check_exception_state(); |
|
226 |
} |
|
227 | 224 |
} |
228 | 225 |
|
229 | 226 |
PPC_OP(debug) |
230 | 227 |
{ |
231 | 228 |
env->nip = PARAM(1); |
232 |
env->brkstate = 1; |
|
233 | 229 |
#if defined (DEBUG_OP) |
234 | 230 |
dump_state(); |
235 | 231 |
#endif |
236 |
do_queue_exception(EXCP_DEBUG);
|
|
232 |
do_raise_exception(EXCP_DEBUG);
|
|
237 | 233 |
RETURN(); |
238 | 234 |
} |
239 | 235 |
|
... | ... | |
364 | 360 |
RETURN(); |
365 | 361 |
} |
366 | 362 |
|
367 |
/* Update time base */ |
|
368 |
PPC_OP(update_tb) |
|
363 |
PPC_OP(load_tbl) |
|
369 | 364 |
{ |
370 |
T0 = regs->tb[0]; |
|
371 |
T1 = T0; |
|
372 |
T0 += PARAM(1); |
|
373 |
#if defined (DEBUG_OP) |
|
374 |
dump_update_tb(PARAM(1)); |
|
375 |
#endif |
|
376 |
if (T0 < T1) { |
|
377 |
T1 = regs->tb[1] + 1; |
|
378 |
regs->tb[1] = T1; |
|
379 |
} |
|
380 |
regs->tb[0] = T0; |
|
365 |
T0 = cpu_ppc_load_tbl(regs); |
|
381 | 366 |
RETURN(); |
382 | 367 |
} |
383 | 368 |
|
384 |
PPC_OP(load_tb) |
|
369 |
PPC_OP(load_tbu)
|
|
385 | 370 |
{ |
386 |
T0 = regs->tb[PARAM(1)];
|
|
371 |
T0 = cpu_ppc_load_tbu(regs);
|
|
387 | 372 |
RETURN(); |
388 | 373 |
} |
389 | 374 |
|
390 |
PPC_OP(store_tb) |
|
375 |
PPC_OP(store_tbl)
|
|
391 | 376 |
{ |
392 |
regs->tb[PARAM(1)] = T0; |
|
393 |
#if defined (DEBUG_OP) |
|
394 |
dump_store_tb(PARAM(1)); |
|
395 |
#endif |
|
377 |
cpu_ppc_store_tbl(regs, T0); |
|
396 | 378 |
RETURN(); |
397 | 379 |
} |
398 | 380 |
|
399 |
/* Update decrementer */ |
|
400 |
PPC_OP(update_decr) |
|
381 |
PPC_OP(store_tbu) |
|
401 | 382 |
{ |
402 |
T0 = regs->decr; |
|
403 |
T1 = T0; |
|
404 |
T0 -= PARAM(1); |
|
405 |
regs->decr = T0; |
|
406 |
if (PARAM(1) > T1) { |
|
407 |
do_queue_exception(EXCP_DECR); |
|
408 |
} |
|
383 |
cpu_ppc_store_tbu(regs, T0); |
|
409 | 384 |
RETURN(); |
410 | 385 |
} |
411 | 386 |
|
412 |
PPC_OP(store_decr)
|
|
387 |
PPC_OP(load_decr)
|
|
413 | 388 |
{ |
414 |
T1 = regs->decr; |
|
415 |
regs->decr = T0; |
|
416 |
if (Ts0 < 0 && Ts1 > 0) { |
|
417 |
do_queue_exception(EXCP_DECR); |
|
389 |
T0 = cpu_ppc_load_decr(regs); |
|
418 | 390 |
} |
391 |
|
|
392 |
PPC_OP(store_decr) |
|
393 |
{ |
|
394 |
cpu_ppc_store_decr(regs, T0); |
|
419 | 395 |
RETURN(); |
420 | 396 |
} |
421 | 397 |
|
... | ... | |
1471 | 1447 |
/* Return from interrupt */ |
1472 | 1448 |
PPC_OP(rfi) |
1473 | 1449 |
{ |
1450 |
regs->nip = regs->spr[SRR0] & ~0x00000003; |
|
1474 | 1451 |
T0 = regs->spr[SRR1] & ~0xFFFF0000; |
1475 | 1452 |
do_store_msr(); |
1476 |
do_tlbia(); |
|
1477 | 1453 |
#if defined (DEBUG_OP) |
1478 | 1454 |
dump_rfi(); |
1479 | 1455 |
#endif |
1480 |
regs->nip = regs->spr[SRR0] & ~0x00000003; |
|
1481 |
do_queue_exception(EXCP_RFI); |
|
1482 |
if (env->exceptions != 0) { |
|
1483 |
do_check_exception_state(); |
|
1484 |
} |
|
1456 |
// do_tlbia(); |
|
1457 |
do_raise_exception(EXCP_RFI); |
|
1485 | 1458 |
RETURN(); |
1486 | 1459 |
} |
1487 | 1460 |
|
... | ... | |
1493 | 1466 |
(Ts0 == Ts1 && (PARAM(1) & 0x04)) || |
1494 | 1467 |
(T0 < T1 && (PARAM(1) & 0x02)) || |
1495 | 1468 |
(T0 > T1 && (PARAM(1) & 0x01))) |
1496 |
do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP);
|
|
1469 |
do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
|
|
1497 | 1470 |
RETURN(); |
1498 | 1471 |
} |
1499 | 1472 |
|
... | ... | |
1504 | 1477 |
(Ts0 == SPARAM(1) && (PARAM(2) & 0x04)) || |
1505 | 1478 |
(T0 < (uint32_t)SPARAM(1) && (PARAM(2) & 0x02)) || |
1506 | 1479 |
(T0 > (uint32_t)SPARAM(1) && (PARAM(2) & 0x01))) |
1507 |
do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP);
|
|
1480 |
do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
|
|
1508 | 1481 |
RETURN(); |
1509 | 1482 |
} |
1510 | 1483 |
|
b/target-ppc/op_helper.c | ||
---|---|---|
31 | 31 |
|
32 | 32 |
/*****************************************************************************/ |
33 | 33 |
/* Exceptions processing helpers */ |
34 |
void do_queue_exception_err (uint32_t exception, int error_code)
|
|
34 |
void cpu_loop_exit(void)
|
|
35 | 35 |
{ |
36 |
/* Queue real PPC exceptions */ |
|
37 |
if (exception < EXCP_PPC_MAX) { |
|
38 |
env->exceptions |= 1 << exception; |
|
39 |
env->errors[exception] = error_code; |
|
40 |
} else { |
|
41 |
/* Preserve compatibility with qemu core */ |
|
42 |
env->exceptions |= 1; |
|
43 |
env->exception_index = exception; |
|
44 |
env->error_code = error_code; |
|
45 |
} |
|
36 |
longjmp(env->jmp_env, 1); |
|
46 | 37 |
} |
47 | 38 |
|
48 |
void do_queue_exception (uint32_t exception)
|
|
39 |
void do_raise_exception_err (uint32_t exception, int error_code)
|
|
49 | 40 |
{ |
50 |
do_queue_exception_err(exception, 0); |
|
51 |
} |
|
52 |
|
|
53 |
void do_check_exception_state (void) |
|
54 |
{ |
|
55 |
if ((env->exceptions & 1) == 1 || check_exception_state(env)) { |
|
56 |
env->exceptions &= ~1; |
|
41 |
#if 0 |
|
42 |
printf("Raise exception %3x code : %d\n", exception, error_code); |
|
43 |
#endif |
|
44 |
switch (exception) { |
|
45 |
case EXCP_EXTERNAL: |
|
46 |
case EXCP_DECR: |
|
47 |
printf("DECREMENTER & EXTERNAL exceptions should be hard interrupts !\n"); |
|
48 |
if (msr_ee == 0) |
|
49 |
return; |
|
50 |
break; |
|
51 |
case EXCP_PROGRAM: |
|
52 |
if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0) |
|
53 |
return; |
|
54 |
break; |
|
55 |
default: |
|
56 |
break; |
|
57 |
} |
|
58 |
env->exception_index = exception; |
|
59 |
env->error_code = error_code; |
|
57 | 60 |
cpu_loop_exit(); |
58 | 61 |
} |
62 |
|
|
63 |
void do_raise_exception (uint32_t exception) |
|
64 |
{ |
|
65 |
do_raise_exception_err(exception, 0); |
|
59 | 66 |
} |
60 | 67 |
|
61 | 68 |
/*****************************************************************************/ |
... | ... | |
125 | 132 |
/* Flush all tlb when changing translation mode or privilege level */ |
126 | 133 |
do_tlbia(); |
127 | 134 |
} |
128 |
#if 0 |
|
129 |
if ((T0 >> MSR_IP) & 0x01) { |
|
130 |
printf("Halting CPU. Stop emulation\n"); |
|
131 |
do_queue_exception(EXCP_HLT); |
|
132 |
cpu_loop_exit(); |
|
133 |
} |
|
134 |
#endif |
|
135 | 135 |
msr_pow = (T0 >> MSR_POW) & 0x03; |
136 | 136 |
msr_ile = (T0 >> MSR_ILE) & 0x01; |
137 | 137 |
msr_ee = (T0 >> MSR_EE) & 0x01; |
b/target-ppc/op_mem.h | ||
---|---|---|
97 | 97 |
if (T1 > 0) { |
98 | 98 |
if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) || |
99 | 99 |
(PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) { |
100 |
do_queue_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); |
|
101 |
do_process_exceptions(); |
|
100 |
do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); |
|
102 | 101 |
} else { |
103 | 102 |
glue(do_lsw, MEMSUFFIX)(PARAM(1)); |
104 | 103 |
} |
... | ... | |
138 | 137 |
PPC_OP(glue(lwarx, MEMSUFFIX)) |
139 | 138 |
{ |
140 | 139 |
if (T0 & 0x03) { |
141 |
do_queue_exception(EXCP_ALIGN); |
|
142 |
do_process_exceptions(); |
|
140 |
do_raise_exception(EXCP_ALIGN); |
|
143 | 141 |
} else { |
144 | 142 |
T1 = glue(ldl, MEMSUFFIX)((void *)T0); |
145 | 143 |
regs->reserve = T0; |
... | ... | |
151 | 149 |
PPC_OP(glue(stwcx, MEMSUFFIX)) |
152 | 150 |
{ |
153 | 151 |
if (T0 & 0x03) { |
154 |
do_queue_exception(EXCP_ALIGN); |
|
155 |
do_process_exceptions(); |
|
152 |
do_raise_exception(EXCP_ALIGN); |
|
156 | 153 |
} else { |
157 | 154 |
if (regs->reserve != T0) { |
158 | 155 |
env->crf[0] = xer_ov; |
b/target-ppc/translate.c | ||
---|---|---|
30 | 30 |
//#define DO_SINGLE_STEP |
31 | 31 |
//#define DO_STEP_FLUSH |
32 | 32 |
//#define DEBUG_DISAS |
33 |
//#define PPC_DEBUG_DISAS |
|
33 | 34 |
|
34 | 35 |
enum { |
35 | 36 |
#define DEF(s, n, copy_size) INDEX_op_ ## s, |
... | ... | |
135 | 136 |
uint32_t nip; |
136 | 137 |
uint32_t opcode; |
137 | 138 |
uint32_t exception; |
138 |
/* Time base offset */ |
|
139 |
uint32_t tb_offset; |
|
140 |
/* Decrementer offset */ |
|
141 |
uint32_t decr_offset; |
|
142 | 139 |
/* Execution mode */ |
143 | 140 |
#if !defined(CONFIG_USER_ONLY) |
144 | 141 |
int supervisor; |
... | ... | |
156 | 153 |
void (*handler)(DisasContext *ctx); |
157 | 154 |
} opc_handler_t; |
158 | 155 |
|
159 |
#define RET_EXCP(excp, error) \
|
|
156 |
#define RET_EXCP(ctx, excp, error) \
|
|
160 | 157 |
do { \ |
161 |
gen_op_queue_exception_err(excp, error); \ |
|
162 |
ctx->exception = excp; \ |
|
163 |
return; \ |
|
158 |
if ((ctx)->exception == EXCP_NONE) { \ |
|
159 |
gen_op_update_nip((ctx)->nip); \ |
|
160 |
} \ |
|
161 |
gen_op_raise_exception_err((excp), (error)); \ |
|
162 |
ctx->exception = (excp); \ |
|
164 | 163 |
} while (0) |
165 | 164 |
|
166 |
#define RET_INVAL() \ |
|
167 |
RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL) |
|
165 |
#define RET_INVAL(ctx) \ |
|
166 |
RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL) |
|
167 |
|
|
168 |
#define RET_PRIVOPC(ctx) \ |
|
169 |
RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC) |
|
168 | 170 |
|
169 |
#define RET_PRIVOPC() \
|
|
170 |
RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
|
|
171 |
#define RET_PRIVREG(ctx) \
|
|
172 |
RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
|
|
171 | 173 |
|
172 |
#define RET_PRIVREG() \
|
|
173 |
RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
|
|
174 |
#define RET_MTMSR(ctx) \
|
|
175 |
RET_EXCP((ctx), EXCP_MTMSR, 0)
|
|
174 | 176 |
|
175 | 177 |
#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ |
176 | 178 |
static void gen_##name (DisasContext *ctx); \ |
... | ... | |
312 | 314 |
/* Invalid instruction */ |
313 | 315 |
GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE) |
314 | 316 |
{ |
315 |
RET_INVAL(); |
|
317 |
RET_INVAL(ctx);
|
|
316 | 318 |
} |
317 | 319 |
|
318 | 320 |
/* Special opcode to stop emulation */ |
319 | 321 |
GEN_HANDLER(stop, 0x06, 0x00, 0xFF, 0x03FFFFC1, PPC_COMMON) |
320 | 322 |
{ |
321 |
gen_op_queue_exception(EXCP_HLT); |
|
322 |
ctx->exception = EXCP_HLT; |
|
323 |
RET_EXCP(ctx, EXCP_HLT, 0); |
|
323 | 324 |
} |
324 | 325 |
|
325 | 326 |
/* Special opcode to call open-firmware */ |
326 | 327 |
GEN_HANDLER(of_enter, 0x06, 0x01, 0xFF, 0x03FFFFC1, PPC_COMMON) |
327 | 328 |
{ |
328 |
gen_op_queue_exception(EXCP_OFCALL); |
|
329 |
ctx->exception = EXCP_OFCALL; |
|
329 |
RET_EXCP(ctx, EXCP_OFCALL, 0); |
|
330 | 330 |
} |
331 | 331 |
|
332 | 332 |
/* Special opcode to call RTAS */ |
333 | 333 |
GEN_HANDLER(rtas_enter, 0x06, 0x02, 0xFF, 0x03FFFFC1, PPC_COMMON) |
334 | 334 |
{ |
335 | 335 |
printf("RTAS entry point !\n"); |
336 |
gen_op_queue_exception(EXCP_RTASCALL); |
|
337 |
ctx->exception = EXCP_RTASCALL; |
|
336 |
RET_EXCP(ctx, EXCP_RTASCALL, 0); |
|
338 | 337 |
} |
339 | 338 |
|
340 | 339 |
static opc_handler_t invalid_handler = { |
... | ... | |
1010 | 1009 |
uint32_t simm = SIMM(ctx->opcode); \ |
1011 | 1010 |
if (rA(ctx->opcode) == 0 || \ |
1012 | 1011 |
rA(ctx->opcode) == rD(ctx->opcode)) { \ |
1013 |
RET_INVAL(); \ |
|
1012 |
RET_INVAL(ctx); \ |
|
1013 |
return; \ |
|
1014 | 1014 |
} \ |
1015 | 1015 |
gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
1016 | 1016 |
if (simm != 0) \ |
... | ... | |
1025 | 1025 |
{ \ |
1026 | 1026 |
if (rA(ctx->opcode) == 0 || \ |
1027 | 1027 |
rA(ctx->opcode) == rD(ctx->opcode)) { \ |
1028 |
RET_INVAL(); \ |
|
1028 |
RET_INVAL(ctx); \ |
|
1029 |
return; \ |
|
1029 | 1030 |
} \ |
1030 | 1031 |
gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
1031 | 1032 |
gen_op_load_gpr_T1(rB(ctx->opcode)); \ |
... | ... | |
1086 | 1087 |
{ \ |
1087 | 1088 |
uint32_t simm = SIMM(ctx->opcode); \ |
1088 | 1089 |
if (rA(ctx->opcode) == 0) { \ |
1089 |
RET_INVAL(); \ |
|
1090 |
RET_INVAL(ctx); \ |
|
1091 |
return; \ |
|
1090 | 1092 |
} \ |
1091 | 1093 |
gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
1092 | 1094 |
if (simm != 0) \ |
... | ... | |
1100 | 1102 |
GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ |
1101 | 1103 |
{ \ |
1102 | 1104 |
if (rA(ctx->opcode) == 0) { \ |
1103 |
RET_INVAL(); \ |
|
1105 |
RET_INVAL(ctx); \ |
|
1106 |
return; \ |
|
1104 | 1107 |
} \ |
1105 | 1108 |
gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
1106 | 1109 |
gen_op_load_gpr_T1(rB(ctx->opcode)); \ |
... | ... | |
1236 | 1239 |
nr = nb / 4; |
1237 | 1240 |
if (((start + nr) > 32 && start <= ra && (start + nr - 32) > ra) || |
1238 | 1241 |
((start + nr) <= 32 && start <= ra && (start + nr) > ra)) { |
1239 |
RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); |
|
1242 |
RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); |
|
1243 |
return; |
|
1240 | 1244 |
} |
1241 | 1245 |
if (ra == 0) { |
1242 | 1246 |
gen_op_set_T0(0); |
... | ... | |
1376 | 1380 |
uint32_t simm = SIMM(ctx->opcode); \ |
1377 | 1381 |
if (rA(ctx->opcode) == 0 || \ |
1378 | 1382 |
rA(ctx->opcode) == rD(ctx->opcode)) { \ |
1379 |
RET_INVAL(); \ |
|
1383 |
RET_INVAL(ctx); \ |
|
1384 |
return; \ |
|
1380 | 1385 |
} \ |
1381 | 1386 |
gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
1382 | 1387 |
if (simm != 0) \ |
... | ... | |
1391 | 1396 |
{ \ |
1392 | 1397 |
if (rA(ctx->opcode) == 0 || \ |
1393 | 1398 |
rA(ctx->opcode) == rD(ctx->opcode)) { \ |
1394 |
RET_INVAL(); \ |
|
1399 |
RET_INVAL(ctx); \ |
|
1400 |
return; \ |
|
1395 | 1401 |
} \ |
1396 | 1402 |
gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
1397 | 1403 |
gen_op_load_gpr_T1(rB(ctx->opcode)); \ |
... | ... | |
1448 | 1454 |
{ \ |
1449 | 1455 |
uint32_t simm = SIMM(ctx->opcode); \ |
1450 | 1456 |
if (rA(ctx->opcode) == 0) { \ |
1451 |
RET_INVAL(); \ |
|
1457 |
RET_INVAL(ctx); \ |
|
1458 |
return; \ |
|
1452 | 1459 |
} \ |
1453 | 1460 |
gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
1454 | 1461 |
if (simm != 0) \ |
... | ... | |
1462 | 1469 |
GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ |
1463 | 1470 |
{ \ |
1464 | 1471 |
if (rA(ctx->opcode) == 0) { \ |
1465 |
RET_INVAL(); \ |
|
1472 |
RET_INVAL(ctx); \ |
|
1473 |
return; \ |
|
1466 | 1474 |
} \ |
1467 | 1475 |
gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
1468 | 1476 |
gen_op_load_gpr_T1(rB(ctx->opcode)); \ |
... | ... | |
1502 | 1510 |
/* stfiwx */ |
1503 | 1511 |
GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) |
1504 | 1512 |
{ |
1505 |
RET_INVAL(); |
|
1513 |
RET_INVAL(ctx);
|
|
1506 | 1514 |
} |
1507 | 1515 |
|
1508 | 1516 |
/*** Branch ***/ |
... | ... | |
1512 | 1520 |
{ |
1513 | 1521 |
uint32_t li = s_ext24(LI(ctx->opcode)), target; |
1514 | 1522 |
|
1515 |
gen_op_update_tb(ctx->tb_offset); |
|
1516 |
gen_op_update_decr(ctx->decr_offset); |
|
1517 |
gen_op_process_exceptions(ctx->nip - 4); |
|
1518 | 1523 |
if (AA(ctx->opcode) == 0) |
1519 | 1524 |
target = ctx->nip + li - 4; |
1520 | 1525 |
else |
... | ... | |
1538 | 1543 |
uint32_t mask; |
1539 | 1544 |
uint32_t li; |
1540 | 1545 |
|
1541 |
gen_op_update_tb(ctx->tb_offset); |
|
1542 |
gen_op_update_decr(ctx->decr_offset); |
|
1543 |
gen_op_process_exceptions(ctx->nip - 4); |
|
1544 |
|
|
1545 | 1546 |
if ((bo & 0x4) == 0) |
1546 | 1547 |
gen_op_dec_ctr(); |
1547 | 1548 |
switch(type) { |
... | ... | |
1683 | 1684 |
GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW) |
1684 | 1685 |
{ |
1685 | 1686 |
#if defined(CONFIG_USER_ONLY) |
1686 |
RET_PRIVOPC(); |
|
1687 |
RET_PRIVOPC(ctx);
|
|
1687 | 1688 |
#else |
1688 | 1689 |
/* Restore CPU state */ |
1689 | 1690 |
if (!ctx->supervisor) { |
1690 |
RET_PRIVOPC(); |
|
1691 |
RET_PRIVOPC(ctx); |
|
1692 |
return; |
|
1691 | 1693 |
} |
1692 | 1694 |
gen_op_rfi(); |
1693 |
ctx->exception = EXCP_RFI;
|
|
1695 |
RET_EXCP(ctx, EXCP_RFI, 0);
|
|
1694 | 1696 |
#endif |
1695 | 1697 |
} |
1696 | 1698 |
|
... | ... | |
1698 | 1700 |
GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW) |
1699 | 1701 |
{ |
1700 | 1702 |
#if defined(CONFIG_USER_ONLY) |
1701 |
gen_op_queue_exception(EXCP_SYSCALL_USER);
|
|
1703 |
RET_EXCP(ctx, EXCP_SYSCALL_USER, 0);
|
|
1702 | 1704 |
#else |
1703 |
gen_op_queue_exception(EXCP_SYSCALL);
|
|
1705 |
RET_EXCP(ctx, EXCP_SYSCALL, 0);
|
|
1704 | 1706 |
#endif |
1705 |
ctx->exception = EXCP_SYSCALL; |
|
1706 | 1707 |
} |
1707 | 1708 |
|
1708 | 1709 |
/*** Trap ***/ |
... | ... | |
1770 | 1771 |
GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC) |
1771 | 1772 |
{ |
1772 | 1773 |
#if defined(CONFIG_USER_ONLY) |
1773 |
RET_PRIVREG(); |
|
1774 |
RET_PRIVREG(ctx);
|
|
1774 | 1775 |
#else |
1775 | 1776 |
if (!ctx->supervisor) { |
1776 |
RET_PRIVREG(); |
|
1777 |
RET_PRIVREG(ctx); |
|
1778 |
return; |
|
1777 | 1779 |
} |
1778 | 1780 |
gen_op_load_msr(); |
1779 | 1781 |
gen_op_store_T0_gpr(rD(ctx->opcode)); |
... | ... | |
1792 | 1794 |
#endif |
1793 | 1795 |
{ |
1794 | 1796 |
case -1: |
1795 |
RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); |
|
1796 |
break;
|
|
1797 |
RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
|
|
1798 |
return;
|
|
1797 | 1799 |
case 0: |
1798 |
RET_PRIVREG(); |
|
1799 |
break;
|
|
1800 |
RET_PRIVREG(ctx);
|
|
1801 |
return;
|
|
1800 | 1802 |
default: |
1801 | 1803 |
break; |
1802 | 1804 |
} |
... | ... | |
1910 | 1912 |
gen_op_load_sdr1(); |
1911 | 1913 |
break; |
1912 | 1914 |
case V_TBL: |
1913 |
gen_op_update_tb(ctx->tb_offset); |
|
1914 |
ctx->tb_offset = 0; |
|
1915 |
/* TBL is still in T0 */ |
|
1915 |
gen_op_load_tbl(); |
|
1916 | 1916 |
break; |
1917 | 1917 |
case V_TBU: |
1918 |
gen_op_update_tb(ctx->tb_offset); |
|
1919 |
ctx->tb_offset = 0; |
|
1920 |
gen_op_load_tb(1); |
|
1918 |
gen_op_load_tbu(); |
|
1921 | 1919 |
break; |
1922 | 1920 |
case DECR: |
1923 |
gen_op_update_decr(ctx->decr_offset); |
|
1924 |
ctx->decr_offset = 0; |
|
1925 |
/* decr is still in T0 */ |
|
1921 |
gen_op_load_decr(); |
|
1926 | 1922 |
break; |
1927 | 1923 |
default: |
1928 | 1924 |
gen_op_load_spr(sprn); |
... | ... | |
1939 | 1935 |
/* We need to update the time base before reading it */ |
1940 | 1936 |
switch (sprn) { |
1941 | 1937 |
case V_TBL: |
1942 |
gen_op_update_tb(ctx->tb_offset); |
|
1943 | 1938 |
/* TBL is still in T0 */ |
1939 |
gen_op_load_tbl(); |
|
1944 | 1940 |
break; |
1945 | 1941 |
case V_TBU: |
1946 |
gen_op_update_tb(ctx->tb_offset); |
|
1947 |
gen_op_load_tb(1); |
|
1942 |
gen_op_load_tbu(); |
|
1948 | 1943 |
break; |
1949 | 1944 |
default: |
1950 |
RET_INVAL(); |
|
1951 |
break;
|
|
1945 |
RET_INVAL(ctx);
|
|
1946 |
return;
|
|
1952 | 1947 |
} |
1953 |
ctx->tb_offset = 0; |
|
1954 | 1948 |
gen_op_store_T0_gpr(rD(ctx->opcode)); |
1955 | 1949 |
} |
1956 | 1950 |
|
... | ... | |
1965 | 1959 |
GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) |
1966 | 1960 |
{ |
1967 | 1961 |
#if defined(CONFIG_USER_ONLY) |
1968 |
RET_PRIVREG(); |
|
1962 |
RET_PRIVREG(ctx);
|
|
1969 | 1963 |
#else |
1970 | 1964 |
if (!ctx->supervisor) { |
1971 |
RET_PRIVREG(); |
|
1965 |
RET_PRIVREG(ctx); |
|
1966 |
return; |
|
1972 | 1967 |
} |
1973 | 1968 |
gen_op_load_gpr_T0(rS(ctx->opcode)); |
1974 | 1969 |
gen_op_store_msr(); |
1975 | 1970 |
/* Must stop the translation as machine state (may have) changed */ |
1976 |
ctx->exception = EXCP_MTMSR;
|
|
1971 |
RET_MTMSR(ctx);
|
|
1977 | 1972 |
#endif |
1978 | 1973 |
} |
1979 | 1974 |
|
... | ... | |
1995 | 1990 |
#endif |
1996 | 1991 |
{ |
1997 | 1992 |
case -1: |
1998 |
RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); |
|
1993 |
RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
|
|
1999 | 1994 |
break; |
2000 | 1995 |
case 0: |
2001 |
RET_PRIVREG(); |
|
1996 |
RET_PRIVREG(ctx);
|
|
2002 | 1997 |
break; |
2003 | 1998 |
default: |
2004 | 1999 |
break; |
... | ... | |
2147 | 2142 |
gen_op_tlbia(); |
2148 | 2143 |
break; |
2149 | 2144 |
case O_TBL: |
2150 |
gen_op_store_tb(0); |
|
2151 |
ctx->tb_offset = 0; |
|
2145 |
gen_op_store_tbl(); |
|
2152 | 2146 |
break; |
2153 | 2147 |
case O_TBU: |
2154 |
gen_op_store_tb(1); |
|
2155 |
ctx->tb_offset = 0; |
|
2148 |
gen_op_store_tbu(); |
|
2156 | 2149 |
break; |
2157 | 2150 |
case DECR: |
2158 | 2151 |
gen_op_store_decr(); |
2159 |
ctx->decr_offset = 0; |
|
2160 | 2152 |
break; |
2161 | 2153 |
default: |
2162 | 2154 |
gen_op_store_spr(sprn); |
... | ... | |
2186 | 2178 |
GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) |
2187 | 2179 |
{ |
2188 | 2180 |
#if defined(CONFIG_USER_ONLY) |
2189 |
RET_PRIVOPC(); |
|
2181 |
RET_PRIVOPC(ctx);
|
|
2190 | 2182 |
#else |
2191 | 2183 |
if (!ctx->supervisor) { |
2192 |
RET_PRIVOPC(); |
|
2184 |
RET_PRIVOPC(ctx); |
|
2185 |
return; |
|
2193 | 2186 |
} |
2194 | 2187 |
if (rA(ctx->opcode) == 0) { |
2195 | 2188 |
gen_op_load_gpr_T0(rB(ctx->opcode)); |
... | ... | |
2274 | 2267 |
GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT) |
2275 | 2268 |
{ |
2276 | 2269 |
#if defined(CONFIG_USER_ONLY) |
2277 |
RET_PRIVREG(); |
|
2270 |
RET_PRIVREG(ctx);
|
|
2278 | 2271 |
#else |
2279 | 2272 |
if (!ctx->supervisor) { |
2280 |
RET_PRIVREG(); |
|
2273 |
RET_PRIVREG(ctx); |
|
2274 |
return; |
|
2281 | 2275 |
} |
2282 | 2276 |
gen_op_load_sr(SR(ctx->opcode)); |
2283 | 2277 |
gen_op_store_T0_gpr(rD(ctx->opcode)); |
... | ... | |
2288 | 2282 |
GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT) |
2289 | 2283 |
{ |
2290 | 2284 |
#if defined(CONFIG_USER_ONLY) |
2291 |
RET_PRIVREG(); |
|
2285 |
RET_PRIVREG(ctx);
|
|
2292 | 2286 |
#else |
2293 | 2287 |
if (!ctx->supervisor) { |
2294 |
RET_PRIVREG(); |
|
2288 |
RET_PRIVREG(ctx); |
|
2289 |
return; |
|
2295 | 2290 |
} |
2296 | 2291 |
gen_op_load_gpr_T1(rB(ctx->opcode)); |
2297 | 2292 |
gen_op_load_srin(); |
... | ... | |
2303 | 2298 |
GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) |
2304 | 2299 |
{ |
2305 | 2300 |
#if defined(CONFIG_USER_ONLY) |
2306 |
RET_PRIVREG(); |
|
2301 |
RET_PRIVREG(ctx);
|
|
2307 | 2302 |
#else |
2308 | 2303 |
if (!ctx->supervisor) { |
2309 |
RET_PRIVREG(); |
|
2304 |
RET_PRIVREG(ctx); |
|
2305 |
return; |
|
2310 | 2306 |
} |
2311 | 2307 |
gen_op_load_gpr_T0(rS(ctx->opcode)); |
2312 | 2308 |
gen_op_store_sr(SR(ctx->opcode)); |
2309 |
#if 0 |
|
2313 | 2310 |
gen_op_tlbia(); |
2311 |
RET_MTMSR(ctx); |
|
2312 |
#endif |
|
2314 | 2313 |
#endif |
2315 | 2314 |
} |
2316 | 2315 |
|
... | ... | |
2318 | 2317 |
GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) |
2319 | 2318 |
{ |
2320 | 2319 |
#if defined(CONFIG_USER_ONLY) |
2321 |
RET_PRIVREG(); |
|
2320 |
RET_PRIVREG(ctx);
|
|
2322 | 2321 |
#else |
2323 | 2322 |
if (!ctx->supervisor) { |
2324 |
RET_PRIVREG(); |
|
2323 |
RET_PRIVREG(ctx); |
|
2324 |
return; |
|
2325 | 2325 |
} |
2326 | 2326 |
gen_op_load_gpr_T0(rS(ctx->opcode)); |
2327 | 2327 |
gen_op_load_gpr_T1(rB(ctx->opcode)); |
... | ... | |
2336 | 2336 |
GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT) |
2337 | 2337 |
{ |
2338 | 2338 |
#if defined(CONFIG_USER_ONLY) |
2339 |
RET_PRIVOPC(); |
|
2339 |
RET_PRIVOPC(ctx);
|
|
2340 | 2340 |
#else |
2341 | 2341 |
if (!ctx->supervisor) { |
2342 |
RET_PRIVOPC(); |
|
2342 |
if (loglevel) |
|
2343 |
fprintf(logfile, "%s: ! supervisor\n", __func__); |
|
2344 |
RET_PRIVOPC(ctx); |
|
2345 |
return; |
|
2343 | 2346 |
} |
2344 | 2347 |
gen_op_tlbia(); |
2345 | 2348 |
#endif |
... | ... | |
2349 | 2352 |
GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) |
2350 | 2353 |
{ |
2351 | 2354 |
#if defined(CONFIG_USER_ONLY) |
2352 |
RET_PRIVOPC(); |
|
2355 |
RET_PRIVOPC(ctx);
|
|
2353 | 2356 |
#else |
2354 | 2357 |
if (!ctx->supervisor) { |
2355 |
RET_PRIVOPC(); |
|
2358 |
RET_PRIVOPC(ctx); |
|
2359 |
return; |
|
2356 | 2360 |
} |
2357 | 2361 |
gen_op_load_gpr_T0(rB(ctx->opcode)); |
2358 | 2362 |
gen_op_tlbie(); |
... | ... | |
2363 | 2367 |
GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM) |
2364 | 2368 |
{ |
2365 | 2369 |
#if defined(CONFIG_USER_ONLY) |
2366 |
RET_PRIVOPC(); |
|
2370 |
RET_PRIVOPC(ctx);
|
|
2367 | 2371 |
#else |
2368 | 2372 |
if (!ctx->supervisor) { |
2369 |
RET_PRIVOPC(); |
|
2373 |
RET_PRIVOPC(ctx); |
|
2374 |
return; |
|
2370 | 2375 |
} |
2371 | 2376 |
/* This has no effect: it should ensure that all previous |
2372 | 2377 |
* tlbie have completed |
... | ... | |
2916 | 2921 |
fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); |
2917 | 2922 |
} |
2918 | 2923 |
fprintf(f, " ] "); |
2919 |
fprintf(f, "TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); |
|
2924 |
fprintf(f, "TB: 0x%08x %08x\n", cpu_ppc_load_tbu(env), |
|
2925 |
cpu_ppc_load_tbl(env)); |
|
2920 | 2926 |
for (i = 0; i < 16; i++) { |
2921 | 2927 |
if ((i & 3) == 0) |
2922 | 2928 |
fprintf(f, "FPR%02d:", i); |
... | ... | |
2924 | 2930 |
if ((i & 3) == 3) |
2925 | 2931 |
fprintf(f, "\n"); |
2926 | 2932 |
} |
2927 |
fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x excp:0x%08x\n",
|
|
2928 |
env->spr[SRR0], env->spr[SRR1], env->decr, env->exceptions);
|
|
2933 |
fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x\n", |
|
2934 |
env->spr[SRR0], env->spr[SRR1], cpu_ppc_load_decr(env));
|
|
2929 | 2935 |
fprintf(f, "reservation 0x%08x\n", env->reserve); |
2930 | 2936 |
fflush(f); |
2931 | 2937 |
} |
... | ... | |
2952 | 2958 |
// env->spr[PVR] = 0x00083100; /* MPC755 (G3 embedded) */ |
2953 | 2959 |
// env->spr[PVR] = 0x00070100; /* IBM 750FX */ |
2954 | 2960 |
#endif |
2955 |
env->decr = 0xFFFFFFFF; |
|
2956 | 2961 |
if (create_ppc_proc(ppc_opcodes, env->spr[PVR]) < 0) |
2957 | 2962 |
return NULL; |
2958 | 2963 |
init_spr_rights(env->spr[PVR]); |
... | ... | |
2976 | 2981 |
} |
2977 | 2982 |
|
2978 | 2983 |
/*****************************************************************************/ |
2979 |
void raise_exception_err (int exception_index, int error_code); |
|
2980 | 2984 |
int print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr, |
2981 | 2985 |
int dialect); |
2982 | 2986 |
|
2983 | 2987 |
int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, |
2984 | 2988 |
int search_pc) |
2985 | 2989 |
{ |
2986 |
DisasContext ctx; |
|
2990 |
DisasContext ctx, *ctxp = &ctx;
|
|
2987 | 2991 |
opc_handler_t **table, *handler; |
2988 | 2992 |
uint32_t pc_start; |
2989 | 2993 |
uint16_t *gen_opc_end; |
... | ... | |
2994 | 2998 |
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
2995 | 2999 |
gen_opparam_ptr = gen_opparam_buf; |
2996 | 3000 |
ctx.nip = pc_start; |
2997 |
ctx.tb_offset = 0; |
|
2998 |
ctx.decr_offset = 0; |
|
2999 | 3001 |
ctx.tb = tb; |
3000 | 3002 |
ctx.exception = EXCP_NONE; |
3001 | 3003 |
#if defined(CONFIG_USER_ONLY) |
... | ... | |
3023 | 3025 |
gen_opc_instr_start[lj] = 1; |
3024 | 3026 |
} |
3025 | 3027 |
} |
3026 |
#if defined DEBUG_DISAS |
|
3027 |
if (loglevel > 0) {
|
|
3028 |
#if defined PPC_DEBUG_DISAS
|
|
3029 |
if (loglevel & CPU_LOG_TB_IN_ASM) {
|
|
3028 | 3030 |
fprintf(logfile, "----------------\n"); |
3029 | 3031 |
fprintf(logfile, "nip=%08x super=%d ir=%d\n", |
3030 | 3032 |
ctx.nip, 1 - msr_pr, msr_ir); |
3031 | 3033 |
} |
3032 | 3034 |
#endif |
3033 | 3035 |
ctx.opcode = ldl_code((void *)ctx.nip); |
3034 |
#if defined DEBUG_DISAS |
|
3035 |
if (loglevel > 0) {
|
|
3036 |
#if defined PPC_DEBUG_DISAS
|
|
3037 |
if (loglevel & CPU_LOG_TB_IN_ASM) {
|
|
3036 | 3038 |
fprintf(logfile, "translate opcode %08x (%02x %02x %02x)\n", |
3037 | 3039 |
ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), |
3038 | 3040 |
opc3(ctx.opcode)); |
3039 | 3041 |
} |
3040 | 3042 |
#endif |
3041 | 3043 |
ctx.nip += 4; |
3042 |
ctx.tb_offset++; |
|
3043 |
/* Check decrementer exception */ |
|
3044 |
if (++ctx.decr_offset == env->decr + 1) |
|
3045 |
ctx.exception = EXCP_DECR; |
|
3046 | 3044 |
table = ppc_opcodes; |
3047 | 3045 |
handler = table[opc1(ctx.opcode)]; |
3048 | 3046 |
if (is_indirect_opcode(handler)) { |
... | ... | |
3098 | 3096 |
(ctx.nip & 0xFC) != 0x04) && |
3099 | 3097 |
ctx.exception != EXCP_SYSCALL && ctx.exception != EXCP_RFI && |
3100 | 3098 |
ctx.exception != EXCP_TRAP)) { |
3101 |
#if !defined(CONFIG_USER_ONLY) |
|
3102 |
gen_op_queue_exception(EXCP_TRACE); |
|
3103 |
#endif |
|
3104 |
if (ctx.exception == EXCP_NONE) { |
|
3105 |
ctx.exception = EXCP_TRACE; |
|
3106 |
} |
|
3099 |
RET_EXCP(ctxp, EXCP_TRACE, 0); |
|
3107 | 3100 |
} |
3108 | 3101 |
/* if we reach a page boundary, stop generation */ |
3109 | 3102 |
if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { |
3110 |
if (ctx.exception == EXCP_NONE) { |
|
3111 |
gen_op_b((long)ctx.tb, ctx.nip); |
|
3112 |
ctx.exception = EXCP_BRANCH; |
|
3113 |
} |
|
3103 |
RET_EXCP(ctxp, EXCP_BRANCH, 0); |
|
3114 | 3104 |
} |
3115 | 3105 |
} |
3116 |
/* In case of branch, this has already been done *BEFORE* the branch */ |
|
3117 |
if (ctx.exception != EXCP_BRANCH && ctx.exception != EXCP_RFI) { |
|
3118 |
gen_op_update_tb(ctx.tb_offset); |
|
3119 |
gen_op_update_decr(ctx.decr_offset); |
|
3120 |
gen_op_process_exceptions(ctx.nip); |
|
3106 |
if (ctx.exception == EXCP_NONE) { |
|
3107 |
gen_op_b((unsigned long)ctx.tb, ctx.nip); |
|
3108 |
} else if (ctx.exception != EXCP_BRANCH) { |
|
3109 |
gen_op_set_T0(0); |
|
3121 | 3110 |
} |
Also available in: Unified diff