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.
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.
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
22 SPARC has two pitfalls: Delay slots and (a)nullification.
23 This is currently solved as follows:
25 'call' instructions simply execute the delay slot before the actual
26 control transfer instructions.
28 'jmpl' instructions execute calculate the destination, then execute
29 the delay slot and then do the control transfer.
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.
39 Register window overflow/underflow check
41 Coprocessor-Instructions
42 Check signedness issues
43 Privileged instructions
44 Optimize synthetic instructions
45 Optional alignment and privileged instruction check
62 typedef struct DisasContext {
63 uint8_t *pc; /* NULL means dynamic value */
64 uint8_t *npc; /* NULL means dynamic value */
66 struct TranslationBlock *tb;
69 static uint16_t *gen_opc_ptr;
70 static uint32_t *gen_opparam_ptr;
75 #define DEF(s,n,copy_size) INDEX_op_ ## s,
83 #define GET_FIELD(X, FROM, TO) \
84 ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
86 #define IS_IMM (insn & (1<<13))
88 static void disas_sparc_insn(DisasContext * dc);
90 typedef void (GenOpFunc) (void);
91 typedef void (GenOpFunc1) (long);
92 typedef void (GenOpFunc2) (long, long);
93 typedef void (GenOpFunc3) (long, long, long);
95 static GenOpFunc *gen_op_movl_TN_reg[2][32] = {
166 static GenOpFunc *gen_op_movl_reg_TN[3][32] = {
271 static GenOpFunc1 *gen_op_movl_TN_im[3] = {
277 static inline void gen_movl_imm_TN(int reg, int imm)
279 gen_op_movl_TN_im[reg] (imm);
282 static inline void gen_movl_imm_T1(int val)
284 gen_movl_imm_TN(1, val);
287 static inline void gen_movl_imm_T0(int val)
289 gen_movl_imm_TN(0, val);
292 static inline void gen_movl_reg_TN(int reg, int t)
295 gen_op_movl_reg_TN[t][reg] ();
297 gen_movl_imm_TN(t, 0);
300 static inline void gen_movl_reg_T0(int reg)
302 gen_movl_reg_TN(reg, 0);
305 static inline void gen_movl_reg_T1(int reg)
307 gen_movl_reg_TN(reg, 1);
310 static inline void gen_movl_reg_T2(int reg)
312 gen_movl_reg_TN(reg, 2);
315 static inline void gen_movl_TN_reg(int reg, int t)
318 gen_op_movl_TN_reg[t][reg] ();
321 static inline void gen_movl_T0_reg(int reg)
323 gen_movl_TN_reg(reg, 0);
326 static inline void gen_movl_T1_reg(int reg)
328 gen_movl_TN_reg(reg, 1);
331 static void gen_cond(int cond)
387 static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn)
389 unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29));
390 target += (uint32_t) dc->pc;
392 /* unconditional not taken */
394 dc->pc = dc->npc + 4;
395 dc->npc = dc->pc + 4;
398 dc->npc = dc->pc + 4;
400 } else if (cond == 0x8) {
401 /* unconditional taken */
403 dc->pc = (uint8_t *) target;
404 dc->npc = dc->pc + 4;
407 dc->npc = (uint8_t *) target;
412 gen_op_generic_branch_a((uint32_t) target,
413 (uint32_t) (dc->npc));
419 gen_op_generic_branch((uint32_t) target,
420 (uint32_t) (dc->npc + 4));
426 #define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1)
428 static int sign_extend(int x, int len)
431 return (x << len) >> len;
434 static inline void save_state(DisasContext * dc)
436 gen_op_jmp_im((uint32_t)dc->pc);
438 gen_op_movl_npc_im((long) dc->npc);
441 static void disas_sparc_insn(DisasContext * dc)
443 unsigned int insn, opc, rs1, rs2, rd;
445 insn = ldl_code(dc->pc);
446 opc = GET_FIELD(insn, 0, 1);
448 rd = GET_FIELD(insn, 2, 6);
450 case 0: /* branches/sethi */
452 unsigned int xop = GET_FIELD(insn, 7, 9);
454 target = GET_FIELD(insn, 10, 31);
457 case 0x1: /* UNIMPL */
462 target = sign_extend(target, 22);
463 do_branch(dc, target, insn);
466 case 0x3: /* FBN+x */
468 case 0x4: /* SETHI */
469 gen_movl_imm_T0(target << 10);
479 unsigned int target = GET_FIELDs(insn, 2, 31) << 2;
481 gen_op_movl_T0_im((long) (dc->pc));
483 target = (long) dc->pc + target;
485 dc->npc = (uint8_t *) target;
488 case 2: /* FPU & Logical Operations */
490 unsigned int xop = GET_FIELD(insn, 7, 12);
491 if (xop == 0x3a) { /* generate trap */
493 rs1 = GET_FIELD(insn, 13, 17);
494 gen_movl_reg_T0(rs1);
496 gen_movl_imm_T1(GET_FIELD(insn, 25, 31));
498 rs2 = GET_FIELD(insn, 27, 31);
499 gen_movl_reg_T1(rs2);
503 cond = GET_FIELD(insn, 3, 6);
511 } else if (xop == 0x28) {
512 rs1 = GET_FIELD(insn, 13, 17);
521 } else if (xop == 0x34 || xop == 0x35) { /* FPU Operations */
524 rs1 = GET_FIELD(insn, 13, 17);
525 gen_movl_reg_T0(rs1);
526 if (IS_IMM) { /* immediate */
527 rs2 = GET_FIELDs(insn, 19, 31);
528 gen_movl_imm_T1(rs2);
529 } else { /* register */
530 rs2 = GET_FIELD(insn, 27, 31);
531 gen_movl_reg_T1(rs2);
534 switch (xop & ~0x10) {
537 gen_op_add_T1_T0_cc();
544 gen_op_logic_T0_cc();
549 gen_op_logic_T0_cc();
554 gen_op_logic_T0_cc();
558 gen_op_sub_T1_T0_cc();
565 gen_op_logic_T0_cc();
570 gen_op_logic_T0_cc();
575 gen_op_logic_T0_cc();
585 gen_op_logic_T0_cc();
590 gen_op_logic_T0_cc();
613 case 0x24: /* mulscc */
614 gen_op_mulscc_T1_T0();
641 case 0x38: /* jmpl */
644 gen_op_movl_npc_T0();
646 gen_op_movl_T0_im((long) (dc->pc));
653 case 0x3b: /* flush */
656 case 0x3c: /* save */
662 case 0x3d: /* restore */
675 case 3: /* load/store instructions */
677 unsigned int xop = GET_FIELD(insn, 7, 12);
678 rs1 = GET_FIELD(insn, 13, 17);
679 gen_movl_reg_T0(rs1);
680 if (IS_IMM) { /* immediate */
681 rs2 = GET_FIELDs(insn, 19, 31);
682 gen_movl_imm_T1(rs2);
683 } else { /* register */
684 rs2 = GET_FIELD(insn, 27, 31);
685 gen_movl_reg_T1(rs2);
688 if (xop < 4 || xop > 7) {
690 case 0x0: /* load word */
693 case 0x1: /* load unsigned byte */
696 case 0x2: /* load unsigned halfword */
699 case 0x3: /* load double word */
701 gen_movl_T0_reg(rd + 1);
703 case 0x9: /* load signed byte */
706 case 0xa: /* load signed halfword */
709 case 0xd: /* ldstub -- XXX: should be atomically */
712 case 0x0f: /* swap register with memory. Also atomically */
717 } else if (xop < 8) {
730 gen_movl_reg_T2(rd + 1);
737 /* default case for non jump instructions */
738 if (dc->npc != NULL) {
740 dc->npc = dc->npc + 4;
748 gen_op_jmp_im((uint32_t)dc->pc);
750 gen_op_movl_npc_im((long) dc->npc);
751 gen_op_exception(TT_ILL_INSN);
755 static inline int gen_intermediate_code_internal(TranslationBlock * tb,
758 uint8_t *pc_start, *last_pc;
759 uint16_t *gen_opc_end;
760 DisasContext dc1, *dc = &dc1;
762 memset(dc, 0, sizeof(DisasContext));
764 printf("SearchPC not yet supported\n");
768 pc_start = (uint8_t *) tb->pc;
770 dc->npc = (uint8_t *) tb->cs_base;
772 gen_opc_ptr = gen_opc_buf;
773 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
774 gen_opparam_ptr = gen_opparam_buf;
778 disas_sparc_insn(dc);
781 /* if the next PC is different, we abort now */
782 if (dc->pc != (last_pc + 4))
784 } while ((gen_opc_ptr < gen_opc_end) &&
785 (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
787 gen_op_jmp_im((long) dc->pc);
789 gen_op_movl_npc_im((long) dc->npc);
793 *gen_opc_ptr = INDEX_op_end;
796 fprintf(logfile, "--------------\n");
797 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
798 disas(logfile, pc_start, last_pc + 4 - pc_start, 0, 0);
799 fprintf(logfile, "\n");
800 fprintf(logfile, "OP:\n");
801 dump_ops(gen_opc_buf, gen_opparam_buf);
802 fprintf(logfile, "\n");
809 int gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
811 return gen_intermediate_code_internal(tb, 0);
814 int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
816 return gen_intermediate_code_internal(tb, 1);
819 CPUSPARCState *cpu_sparc_init(void)
825 if (!(env = malloc(sizeof(CPUSPARCState))))
827 memset(env, 0, sizeof(*env));
830 env->regwptr = env->regbase + (env->cwp * 16);
831 env->user_mode_only = 1;
835 #define GET_FLAG(a,b) ((env->psr & a)?b:'-')
837 void cpu_sparc_dump_state(CPUSPARCState * env, FILE * f, int flags)
841 fprintf(f, "pc: 0x%08x npc: 0x%08x\n", (int) env->pc, (int) env->npc);
842 fprintf(f, "General Registers:\n");
843 for (i = 0; i < 4; i++)
844 fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]);
847 fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]);
848 fprintf(f, "\nCurrent Register Window:\n");
849 for (x = 0; x < 3; x++) {
850 for (i = 0; i < 4; i++)
851 fprintf(f, "%%%c%d: 0x%08x\t",
852 (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i,
853 env->regwptr[i + x * 8]);
856 fprintf(f, "%%%c%d: 0x%08x\t",
857 (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i,
858 env->regwptr[i + x * 8]);
861 fprintf(f, "psr: 0x%08x -> %c%c%c%c wim: 0x%08x\n", env->psr | env->cwp,
862 GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'),
863 GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'),