]> git.ipfire.org Git - thirdparty/qemu.git/blame - target-sparc/translate.c
PowerPC fixes (Jocelyn Mayer)
[thirdparty/qemu.git] / target-sparc / translate.c
CommitLineData
7a3f1944
FB
1/*
2 SPARC translation
3
4 Copyright (C) 2003 Thomas M. Ogrisegg <tom@fnord.at>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21/*
22 SPARC has two pitfalls: Delay slots and (a)nullification.
23 This is currently solved as follows:
24
25 'call' instructions simply execute the delay slot before the actual
26 control transfer instructions.
27
28 'jmpl' instructions execute calculate the destination, then execute
29 the delay slot and then do the control transfer.
30
31 (conditional) branch instructions are the most difficult ones, as the
32 delay slot may be nullified (ie. not executed). This happens when a
33 conditional branch is not executed (thus no control transfer happens)
34 and the 'anull' bit in the branch instruction opcode is set. This is
35 currently solved by doing a jump after the delay slot instruction.
36
37 There is also one big (currently unsolved) bug in the branch code:
38 If a delay slot modifies the condition codes then the new condition
39 codes, instead of the old ones will be used.
40
41 TODO-list:
42
43 FPU-Instructions
44 Coprocessor-Instructions
45 Fix above bug
46 Check signedness issues
47 Privileged instructions
48 Register window overflow/underflow check
49 Optimize synthetic instructions
50 Optional alignment and privileged instruction check
51
52 -- TMO, 09/03/03
53 */
54
55#include <stdarg.h>
56#include <stdlib.h>
57#include <stdio.h>
58#include <string.h>
59#include <inttypes.h>
60
61#include "cpu.h"
62#include "exec-all.h"
63#include "disas.h"
64
65#define DEBUG_DISAS
66
67typedef struct DisasContext {
68 uint8_t *pc;
69 uint8_t *npc;
70 void (*branch) (struct DisasContext *, uint32_t, uint32_t);
71 unsigned int delay_slot:2;
72 uint32_t insn;
73 uint32_t target;
74 int is_br;
75 struct TranslationBlock *tb;
76} DisasContext;
77
78static uint16_t *gen_opc_ptr;
79static uint32_t *gen_opparam_ptr;
80extern FILE *logfile;
81extern int loglevel;
82
83enum {
84#define DEF(s,n,copy_size) INDEX_op_ ## s,
85#include "opc.h"
86#undef DEF
87 NB_OPS
88};
89
90#include "gen-op.h"
91
92#define GET_FIELD(X, FROM, TO) \
93 ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
94
95#define IS_IMM (insn & (1<<13))
96
97static void disas_sparc_insn (DisasContext *dc);
98
99typedef void (GenOpFunc)(void);
100typedef void (GenOpFunc1)(long);
101typedef void (GenOpFunc2)(long, long);
102typedef void (GenOpFunc3)(long, long, long);
103
104static GenOpFunc *gen_op_movl_TN_reg[2][32] = {
105 {
106 gen_op_movl_g0_T0,
107 gen_op_movl_g1_T0,
108 gen_op_movl_g2_T0,
109 gen_op_movl_g3_T0,
110 gen_op_movl_g4_T0,
111 gen_op_movl_g5_T0,
112 gen_op_movl_g6_T0,
113 gen_op_movl_g7_T0,
114 gen_op_movl_o0_T0,
115 gen_op_movl_o1_T0,
116 gen_op_movl_o2_T0,
117 gen_op_movl_o3_T0,
118 gen_op_movl_o4_T0,
119 gen_op_movl_o5_T0,
120 gen_op_movl_o6_T0,
121 gen_op_movl_o7_T0,
122 gen_op_movl_l0_T0,
123 gen_op_movl_l1_T0,
124 gen_op_movl_l2_T0,
125 gen_op_movl_l3_T0,
126 gen_op_movl_l4_T0,
127 gen_op_movl_l5_T0,
128 gen_op_movl_l6_T0,
129 gen_op_movl_l7_T0,
130 gen_op_movl_i0_T0,
131 gen_op_movl_i1_T0,
132 gen_op_movl_i2_T0,
133 gen_op_movl_i3_T0,
134 gen_op_movl_i4_T0,
135 gen_op_movl_i5_T0,
136 gen_op_movl_i6_T0,
137 gen_op_movl_i7_T0,
138 },
139 {
140 gen_op_movl_g0_T1,
141 gen_op_movl_g1_T1,
142 gen_op_movl_g2_T1,
143 gen_op_movl_g3_T1,
144 gen_op_movl_g4_T1,
145 gen_op_movl_g5_T1,
146 gen_op_movl_g6_T1,
147 gen_op_movl_g7_T1,
148 gen_op_movl_o0_T1,
149 gen_op_movl_o1_T1,
150 gen_op_movl_o2_T1,
151 gen_op_movl_o3_T1,
152 gen_op_movl_o4_T1,
153 gen_op_movl_o5_T1,
154 gen_op_movl_o6_T1,
155 gen_op_movl_o7_T1,
156 gen_op_movl_l0_T1,
157 gen_op_movl_l1_T1,
158 gen_op_movl_l2_T1,
159 gen_op_movl_l3_T1,
160 gen_op_movl_l4_T1,
161 gen_op_movl_l5_T1,
162 gen_op_movl_l6_T1,
163 gen_op_movl_l7_T1,
164 gen_op_movl_i0_T1,
165 gen_op_movl_i1_T1,
166 gen_op_movl_i2_T1,
167 gen_op_movl_i3_T1,
168 gen_op_movl_i4_T1,
169 gen_op_movl_i5_T1,
170 gen_op_movl_i6_T1,
171 gen_op_movl_i7_T1,
172 }
173};
174
175static GenOpFunc *gen_op_movl_reg_TN[3][32] = {
176 {
177 gen_op_movl_T0_g0,
178 gen_op_movl_T0_g1,
179 gen_op_movl_T0_g2,
180 gen_op_movl_T0_g3,
181 gen_op_movl_T0_g4,
182 gen_op_movl_T0_g5,
183 gen_op_movl_T0_g6,
184 gen_op_movl_T0_g7,
185 gen_op_movl_T0_o0,
186 gen_op_movl_T0_o1,
187 gen_op_movl_T0_o2,
188 gen_op_movl_T0_o3,
189 gen_op_movl_T0_o4,
190 gen_op_movl_T0_o5,
191 gen_op_movl_T0_o6,
192 gen_op_movl_T0_o7,
193 gen_op_movl_T0_l0,
194 gen_op_movl_T0_l1,
195 gen_op_movl_T0_l2,
196 gen_op_movl_T0_l3,
197 gen_op_movl_T0_l4,
198 gen_op_movl_T0_l5,
199 gen_op_movl_T0_l6,
200 gen_op_movl_T0_l7,
201 gen_op_movl_T0_i0,
202 gen_op_movl_T0_i1,
203 gen_op_movl_T0_i2,
204 gen_op_movl_T0_i3,
205 gen_op_movl_T0_i4,
206 gen_op_movl_T0_i5,
207 gen_op_movl_T0_i6,
208 gen_op_movl_T0_i7,
209 },
210 {
211 gen_op_movl_T1_g0,
212 gen_op_movl_T1_g1,
213 gen_op_movl_T1_g2,
214 gen_op_movl_T1_g3,
215 gen_op_movl_T1_g4,
216 gen_op_movl_T1_g5,
217 gen_op_movl_T1_g6,
218 gen_op_movl_T1_g7,
219 gen_op_movl_T1_o0,
220 gen_op_movl_T1_o1,
221 gen_op_movl_T1_o2,
222 gen_op_movl_T1_o3,
223 gen_op_movl_T1_o4,
224 gen_op_movl_T1_o5,
225 gen_op_movl_T1_o6,
226 gen_op_movl_T1_o7,
227 gen_op_movl_T1_l0,
228 gen_op_movl_T1_l1,
229 gen_op_movl_T1_l2,
230 gen_op_movl_T1_l3,
231 gen_op_movl_T1_l4,
232 gen_op_movl_T1_l5,
233 gen_op_movl_T1_l6,
234 gen_op_movl_T1_l7,
235 gen_op_movl_T1_i0,
236 gen_op_movl_T1_i1,
237 gen_op_movl_T1_i2,
238 gen_op_movl_T1_i3,
239 gen_op_movl_T1_i4,
240 gen_op_movl_T1_i5,
241 gen_op_movl_T1_i6,
242 gen_op_movl_T1_i7,
243 },
244 {
245 gen_op_movl_T2_g0,
246 gen_op_movl_T2_g1,
247 gen_op_movl_T2_g2,
248 gen_op_movl_T2_g3,
249 gen_op_movl_T2_g4,
250 gen_op_movl_T2_g5,
251 gen_op_movl_T2_g6,
252 gen_op_movl_T2_g7,
253 gen_op_movl_T2_o0,
254 gen_op_movl_T2_o1,
255 gen_op_movl_T2_o2,
256 gen_op_movl_T2_o3,
257 gen_op_movl_T2_o4,
258 gen_op_movl_T2_o5,
259 gen_op_movl_T2_o6,
260 gen_op_movl_T2_o7,
261 gen_op_movl_T2_l0,
262 gen_op_movl_T2_l1,
263 gen_op_movl_T2_l2,
264 gen_op_movl_T2_l3,
265 gen_op_movl_T2_l4,
266 gen_op_movl_T2_l5,
267 gen_op_movl_T2_l6,
268 gen_op_movl_T2_l7,
269 gen_op_movl_T2_i0,
270 gen_op_movl_T2_i1,
271 gen_op_movl_T2_i2,
272 gen_op_movl_T2_i3,
273 gen_op_movl_T2_i4,
274 gen_op_movl_T2_i5,
275 gen_op_movl_T2_i6,
276 gen_op_movl_T2_i7,
277 }
278};
279
280static GenOpFunc1 *gen_op_movl_TN_im[3] = {
281 gen_op_movl_T0_im,
282 gen_op_movl_T1_im,
283 gen_op_movl_T2_im
284};
285
286static inline void gen_movl_imm_TN (int reg, int imm)
287{
288 gen_op_movl_TN_im[reg](imm);
289}
290
291static inline void gen_movl_imm_T1 (int val)
292{
293 gen_movl_imm_TN (1, val);
294}
295
296static inline void gen_movl_imm_T0 (int val)
297{
298 gen_movl_imm_TN (0, val);
299}
300
301static inline void gen_movl_reg_TN (int reg, int t)
302{
303 if (reg) gen_op_movl_reg_TN[t][reg]();
304 else gen_movl_imm_TN (t, 0);
305}
306
307static inline void gen_movl_reg_T0 (int reg)
308{
309 gen_movl_reg_TN (reg, 0);
310}
311
312static inline void gen_movl_reg_T1 (int reg)
313{
314 gen_movl_reg_TN (reg, 1);
315}
316
317static inline void gen_movl_reg_T2 (int reg)
318{
319 gen_movl_reg_TN (reg, 2);
320}
321
322static inline void gen_movl_TN_reg (int reg, int t)
323{
324 if (reg) gen_op_movl_TN_reg[t][reg]();
325}
326
327static inline void gen_movl_T0_reg (int reg)
328{
329 gen_movl_TN_reg (reg, 0);
330}
331
332static inline void gen_movl_T1_reg (int reg)
333{
334 gen_movl_TN_reg (reg, 1);
335}
336
337static void do_branch (DisasContext *dc, uint32_t target, uint32_t insn)
338{
339 unsigned int cond = GET_FIELD (insn, 3, 6), a = (insn & (1<<29)), ib = 0;
340 target += (uint32_t) dc->pc-4;
341 if (!a) disas_sparc_insn (dc);
342 switch (cond) {
343 case 0x0: gen_op_movl_T0_0 (); break;
344 case 0x1: gen_op_eval_be (); break;
345 case 0x2: gen_op_eval_ble (); break;
346 case 0x3: gen_op_eval_bl (); break;
347 case 0x4: gen_op_eval_bleu (); break;
348 case 0x5: gen_op_eval_bcs (); break;
349 case 0x6: gen_op_eval_bneg (); break;
350 case 0x7: gen_op_eval_bvs (); break;
351 case 0x8: gen_op_movl_T0_1 (); break;
352 case 0x9: gen_op_eval_bne (); break;
353 case 0xa: gen_op_eval_bg (); break;
354 case 0xb: gen_op_eval_bge (); break;
355 case 0xc: gen_op_eval_bgu (); break;
356 case 0xd: gen_op_eval_bcc (); break;
357 case 0xe: gen_op_eval_bpos (); break;
358 case 0xf: gen_op_eval_bvc (); break;
359 }
360 if (a && ((cond|0x8) != 0x8)) {
361 gen_op_generic_branch_a ((uint32_t) dc->tb,
362 (uint32_t) dc->pc+4, target);
363 disas_sparc_insn (dc);
364 ib = 1;
365 }
366 else
367 if (cond && !a) {
368 gen_op_generic_branch ((uint32_t) dc->tb, (uint32_t) target,
369 (uint32_t) dc->pc);
370 ib = 1;
371 }
372 if (ib) dc->is_br = DISAS_JUMP;
373}
374
375/* target == 0x1 means CALL- else JMPL-instruction */
376static void do_jump (DisasContext *dc, uint32_t target, uint32_t rd)
377{
378 uint32_t orig_pc = (uint32_t) dc->pc-8;
379 if (target != 0x1)
380 gen_op_generic_jmp_1 (orig_pc, target);
381 else
382 gen_op_generic_jmp_2 (orig_pc);
383 gen_movl_T1_reg (rd);
384 dc->is_br = DISAS_JUMP;
385 gen_op_movl_T0_0 ();
386}
387
388#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), b-a)
389
390static int
391sign_extend (x, len)
392 int x, len;
393{
394 int signbit = (1 << (len - 1));
395 int mask = (signbit << 1) - 1;
396 return ((x & mask) ^ signbit) - signbit;
397}
398
399static void disas_sparc_insn (DisasContext *dc)
400{
401 unsigned int insn, opc, rs1, rs2, rd;
402
403 if (dc->delay_slot == 1) {
404 insn = dc->insn;
405 } else {
406 if (dc->delay_slot) dc->delay_slot--;
407 insn = htonl (*(unsigned int *) (dc->pc));
408 dc->pc += 4;
409 }
410
411 opc = GET_FIELD (insn, 0, 1);
412
413 rd = GET_FIELD (insn, 2, 6);
414 switch (opc) {
415 case 0: /* branches/sethi */
416 {
417 unsigned int xop = GET_FIELD (insn, 7, 9);
418 int target;
419 target = GET_FIELD (insn, 10, 31);
420 switch (xop) {
421 case 0x0: case 0x1: /* UNIMPL */
422 printf ("UNIMPLEMENTED: %p\n", dc->pc-4);
423 exit (23);
424 break;
425 case 0x2: /* BN+x */
426 {
427 target <<= 2;
428 target = sign_extend (target, 22);
429 do_branch (dc, target, insn);
430 break;
431 }
432 case 0x3: /* FBN+x */
433 break;
434 case 0x4: /* SETHI */
435 gen_movl_imm_T0 (target<<10);
436 gen_movl_T0_reg (rd);
437 break;
438 case 0x5: /*CBN+x*/
439 break;
440 }
441 break;
442 }
443 case 1: /*CALL*/
444 {
445 unsigned int target = GET_FIELDs (insn, 2, 31) << 2;
446 if (dc->delay_slot) {
447 do_jump (dc, target, 15);
448 dc->delay_slot = 0;
449 } else {
450 dc->insn = insn;
451 dc->delay_slot = 2;
452 }
453 break;
454 }
455 case 2: /* FPU & Logical Operations */
456 {
457 unsigned int xop = GET_FIELD (insn, 7, 12);
458 if (xop == 58) { /* generate trap */
459 dc->is_br = DISAS_JUMP;
460 gen_op_jmp_im ((uint32_t) dc->pc);
461 if (IS_IMM) gen_op_trap (GET_FIELD (insn, 25, 31));
462 /* else XXX*/
463 gen_op_movl_T0_0 ();
464 break;
465 }
466 if (xop == 0x34 || xop == 0x35) { /* FPU Operations */
467 exit (33);
468 }
469 rs1 = GET_FIELD (insn, 13, 17);
470 gen_movl_reg_T0 (rs1);
471 if (IS_IMM) { /* immediate */
472 rs2 = GET_FIELDs (insn, 20, 31);
473 gen_movl_imm_T1 (rs2);
474 } else { /* register */
475 rs2 = GET_FIELD (insn, 27, 31);
476 gen_movl_reg_T1 (rs2);
477 }
478 if (xop < 0x20) {
479 switch (xop &~ 0x10) {
480 case 0x0:
481 gen_op_add_T1_T0 ();
482 break;
483 case 0x1:
484 gen_op_and_T1_T0 ();
485 break;
486 case 0x2:
487 gen_op_or_T1_T0 ();
488 break;
489 case 0x3:
490 gen_op_xor_T1_T0 ();
491 break;
492 case 0x4:
493 gen_op_sub_T1_T0 ();
494 break;
495 case 0x5:
496 gen_op_andn_T1_T0 ();
497 break;
498 case 0x6:
499 gen_op_orn_T1_T0 ();
500 break;
501 case 0x7:
502 gen_op_xnor_T1_T0 ();
503 break;
504 case 0x8:
505 gen_op_addx_T1_T0 ();
506 break;
507 case 0xa:
508 gen_op_umul_T1_T0 ();
509 break;
510 case 0xb:
511 gen_op_smul_T1_T0 ();
512 break;
513 case 0xc:
514 gen_op_subx_T1_T0 ();
515 break;
516 case 0xe:
517 gen_op_udiv_T1_T0 ();
518 break;
519 case 0xf:
520 gen_op_sdiv_T1_T0 ();
521 break;
522 default:
523 exit (17);
524 break;
525 }
526 gen_movl_T0_reg (rd);
527 if (xop & 0x10) {
528 gen_op_set_flags ();
529 }
530 } else {
531 switch (xop) {
532 case 0x25: /* SLL */
533 gen_op_sll ();
534 break;
535 case 0x26:
536 gen_op_srl ();
537 break;
538 case 0x27:
539 gen_op_sra ();
540 break;
541 case 0x28: case 0x30:
542 {
543 unsigned int rdi = GET_FIELD (insn, 13, 17);
544 if (!rdi) (xop==0x28?gen_op_rdy ():gen_op_wry());
545 /* else gen_op_su_trap (); */
546 break;
547 }
548 /* Problem with jmpl: if restore is executed in the delay
549 slot, then the wrong registers are beeing used */
550 case 0x38: /* jmpl */
551 {
552 if (dc->delay_slot) {
553 gen_op_add_T1_T0 ();
554 do_jump (dc, 1, rd);
555 dc->delay_slot = 0;
556 } else {
557 gen_op_add_T1_T0 ();
558 gen_op_jmpl ();
559 dc->insn = insn;
560 dc->delay_slot = 2;
561 }
562 break;
563 }
564 case 0x3c: /* save */
565 gen_op_add_T1_T0 ();
566 gen_op_save ();
567 gen_movl_T0_reg (rd);
568 break;
569 case 0x3d: /* restore */
570 gen_op_add_T1_T0 ();
571 gen_op_restore ();
572 gen_movl_T0_reg (rd);
573 break;
574 }
575 }
576 break;
577 }
578 case 3: /* load/store instructions */
579 {
580 unsigned int xop = GET_FIELD (insn, 7, 12);
581 rs1 = GET_FIELD (insn, 13, 17);
582 gen_movl_reg_T0 (rs1);
583 if (IS_IMM) { /* immediate */
584 rs2 = GET_FIELDs (insn, 20, 31);
585 gen_movl_imm_T1 (rs2);
586 } else { /* register */
587 rs2 = GET_FIELD (insn, 27, 31);
588 gen_movl_reg_T1 (rs2);
589 }
590 gen_op_add_T1_T0 ();
591 if (xop < 4 || xop > 7) {
592 switch (xop) {
593 case 0x0: /* load word */
594 gen_op_ld ();
595 break;
596 case 0x1: /* load unsigned byte */
597 gen_op_ldub ();
598 break;
599 case 0x2: /* load unsigned halfword */
600 gen_op_lduh ();
601 break;
602 case 0x3: /* load double word */
603 gen_op_ldd ();
604 gen_movl_T0_reg (rd+1);
605 break;
606 case 0x9: /* load signed byte */
607 gen_op_ldsb ();
608 break;
609 case 0xa: /* load signed halfword */
610 gen_op_ldsh ();
611 break;
612 case 0xd: /* ldstub -- XXX: should be atomically */
613 gen_op_ldstub ();
614 break;
615 case 0x0f: /* swap register with memory. Also atomically */
616 gen_op_swap ();
617 break;
618 }
619 gen_movl_T1_reg (rd);
620 } else if (xop < 8) {
621 gen_movl_reg_T1 (rd);
622 switch (xop) {
623 case 0x4:
624 gen_op_st ();
625 break;
626 case 0x5:
627 gen_op_stb ();
628 break;
629 case 0x6:
630 gen_op_sth ();
631 break;
632 case 0x7:
633 gen_op_st ();
634 gen_movl_reg_T1 (rd+1);
635 gen_op_st ();
636 break;
637 }
638 }
639 }
640 }
641}
642
643static inline int gen_intermediate_code_internal (TranslationBlock *tb, int spc)
644{
645 uint8_t *pc_start = (uint8_t *) tb->pc;
646 uint16_t *gen_opc_end;
647 DisasContext dc;
648
649 memset (&dc, 0, sizeof (dc));
650 if (spc) {
651 printf ("SearchPC not yet supported\n");
652 exit (0);
653 }
654 dc.tb = tb;
655 dc.pc = pc_start;
656
657 gen_opc_ptr = gen_opc_buf;
658 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
659 gen_opparam_ptr = gen_opparam_buf;
660
661 do {
662 disas_sparc_insn (&dc);
663 } while (!dc.is_br && (gen_opc_ptr < gen_opc_end) &&
664 (dc.pc - pc_start) < (TARGET_PAGE_SIZE - 32));
665
666 switch (dc.is_br) {
667 case DISAS_JUMP:
668 case DISAS_TB_JUMP:
669 gen_op_exit_tb ();
670 break;
671 }
672
673 *gen_opc_ptr = INDEX_op_end;
674#ifdef DEBUG_DISAS
675 if (loglevel) {
676 fprintf (logfile, "--------------\n");
677 fprintf (logfile, "IN: %s\n", lookup_symbol (pc_start));
678 disas(logfile, pc_start, dc.pc - pc_start, 0, 0);
679 fprintf(logfile, "\n");
680 fprintf(logfile, "OP:\n");
681 dump_ops(gen_opc_buf, gen_opparam_buf);
682 fprintf(logfile, "\n");
683 }
684#endif
685
686 return 0;
687}
688
689int gen_intermediate_code (CPUSPARCState *env, TranslationBlock *tb)
690{
691 return gen_intermediate_code_internal(tb, 0);
692}
693
694int gen_intermediate_code_pc (CPUSPARCState *env, TranslationBlock *tb)
695{
696 return gen_intermediate_code_internal(tb, 1);
697}
698
699void *mycpu;
700
701CPUSPARCState *cpu_sparc_init (void)
702{
703 CPUSPARCState *env;
704
705 cpu_exec_init ();
706
707 if (!(env = malloc (sizeof(CPUSPARCState))))
708 return (NULL);
709 memset (env, 0, sizeof (*env));
710 if (!(env->regwptr = malloc (0x2000)))
711 return (NULL);
712 memset (env->regwptr, 0, 0x2000);
713 env->regwptr += 127;
714 env->user_mode_only = 1;
715 mycpu = env;
716 return (env);
717}
718
719#define GET_FLAG(a,b) ((env->psr & a)?b:'-')
720
721void cpu_sparc_dump_state (CPUSPARCState *env, FILE *f, int flags)
722{
723 int i, x;
724
725 fprintf (f, "@PC: %p\n", (void *) env->pc);
726 fprintf (f, "General Registers:\n");
727 for (i=0;i<4;i++)
728 fprintf (f, "%%g%c: %%%08x\t", i+'0', env->gregs[i]);
729 fprintf (f, "\n");
730 for (;i<8;i++)
731 fprintf (f, "%%g%c: %%%08x\t", i+'0', env->gregs[i]);
732 fprintf (f, "\nCurrent Register Window:\n");
733 for (x=0;x<3;x++) {
734 for (i=0;i<4;i++)
735 fprintf (f, "%%%c%d: %%%08x\t", (x==0?'o':(x==1?'l':'i')), i, env->regwptr[i+x*8]);
736 fprintf (f, "\n");
737 for (;i<8;i++)
738 fprintf (f, "%%%c%d: %%%08x\t", (x==0?'o':x==1?'l':'i'), i, env->regwptr[i+x*8]);
739 fprintf (f, "\n");
740 }
741 fprintf (f, "PSR: %x -> %c%c%c%c\n", env->psr,
742 GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'),
743 GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'));
744}