Commit 823029f909b3666660418387d48ea6a207f23f26

Authored by ths
1 parent a36e69dd

SH4 delay slot code update, by Magnus Damm.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3761 c046a42c-6fe2-441c-8c8c-71466251a162
cpu-exec.c
... ... @@ -202,8 +202,8 @@ static inline TranslationBlock *tb_find_fast(void)
202 202 cs_base = 0;
203 203 pc = env->pc;
204 204 #elif defined(TARGET_SH4)
205   - flags = env->sr & (SR_MD | SR_RB);
206   - cs_base = 0; /* XXXXX */
  205 + flags = env->flags;
  206 + cs_base = 0;
207 207 pc = env->pc;
208 208 #elif defined(TARGET_ALPHA)
209 209 flags = env->ps;
... ...
target-sh4/cpu.h
... ... @@ -46,16 +46,16 @@
46 46 #define FPSCR_SZ (1 << 20)
47 47 #define FPSCR_PR (1 << 19)
48 48 #define FPSCR_DN (1 << 18)
49   -
50   -#define DELAY_SLOT (1 << 0) /* Must be the same as SR_T. */
51   -/* This flag is set if the next insn is a delay slot for a conditional jump.
52   - The dynamic value of the DELAY_SLOT determines whether the jup is taken. */
  49 +#define DELAY_SLOT (1 << 0)
53 50 #define DELAY_SLOT_CONDITIONAL (1 << 1)
54   -/* Those are used in contexts only */
55   -#define BRANCH (1 << 2)
56   -#define BRANCH_CONDITIONAL (1 << 3)
57   -#define MODE_CHANGE (1 << 4) /* Potential MD|RB change */
58   -#define BRANCH_EXCEPTION (1 << 5) /* Branch after exception */
  51 +#define DELAY_SLOT_TRUE (1 << 2)
  52 +#define DELAY_SLOT_CLEARME (1 << 3)
  53 +/* The dynamic value of the DELAY_SLOT_TRUE flag determines whether the jump
  54 + * after the delay slot should be taken or not. It is calculated from SR_T.
  55 + *
  56 + * It is unclear if it is permitted to modify the SR_T flag in a delay slot.
  57 + * The use of DELAY_SLOT_TRUE flag makes us accept such SR_T modification.
  58 + */
59 59  
60 60 /* XXXXX The structure could be made more compact */
61 61 typedef struct tlb_t {
... ...
target-sh4/op.c
... ... @@ -19,16 +19,6 @@
19 19 */
20 20 #include "exec.h"
21 21  
22   -static inline void set_flag(uint32_t flag)
23   -{
24   - env->flags |= flag;
25   -}
26   -
27   -static inline void clr_flag(uint32_t flag)
28   -{
29   - env->flags &= ~flag;
30   -}
31   -
32 22 static inline void set_t(void)
33 23 {
34 24 env->sr |= SR_T;
... ... @@ -110,28 +100,37 @@ void OPPROTO op_not_T0(void)
110 100 void OPPROTO op_bf_s(void)
111 101 {
112 102 env->delayed_pc = PARAM1;
113   - set_flag(DELAY_SLOT_CONDITIONAL | ((~env->sr) & SR_T));
  103 + if (!(env->sr & SR_T)) {
  104 + env->flags |= DELAY_SLOT_TRUE;
  105 + }
114 106 RETURN();
115 107 }
116 108  
117 109 void OPPROTO op_bt_s(void)
118 110 {
119 111 env->delayed_pc = PARAM1;
120   - set_flag(DELAY_SLOT_CONDITIONAL | (env->sr & SR_T));
  112 + if (env->sr & SR_T) {
  113 + env->flags |= DELAY_SLOT_TRUE;
  114 + }
  115 + RETURN();
  116 +}
  117 +
  118 +void OPPROTO op_store_flags(void)
  119 +{
  120 + env->flags &= DELAY_SLOT_TRUE;
  121 + env->flags |= PARAM1;
121 122 RETURN();
122 123 }
123 124  
124 125 void OPPROTO op_bra(void)
125 126 {
126 127 env->delayed_pc = PARAM1;
127   - set_flag(DELAY_SLOT);
128 128 RETURN();
129 129 }
130 130  
131 131 void OPPROTO op_braf_T0(void)
132 132 {
133 133 env->delayed_pc = PARAM1 + T0;
134   - set_flag(DELAY_SLOT);
135 134 RETURN();
136 135 }
137 136  
... ... @@ -139,7 +138,6 @@ void OPPROTO op_bsr(void)
139 138 {
140 139 env->pr = PARAM1;
141 140 env->delayed_pc = PARAM2;
142   - set_flag(DELAY_SLOT);
143 141 RETURN();
144 142 }
145 143  
... ... @@ -147,7 +145,6 @@ void OPPROTO op_bsrf_T0(void)
147 145 {
148 146 env->pr = PARAM1;
149 147 env->delayed_pc = PARAM1 + T0;
150   - set_flag(DELAY_SLOT);
151 148 RETURN();
152 149 }
153 150  
... ... @@ -155,26 +152,12 @@ void OPPROTO op_jsr_T0(void)
155 152 {
156 153 env->pr = PARAM1;
157 154 env->delayed_pc = T0;
158   - set_flag(DELAY_SLOT);
159 155 RETURN();
160 156 }
161 157  
162 158 void OPPROTO op_rts(void)
163 159 {
164 160 env->delayed_pc = env->pr;
165   - set_flag(DELAY_SLOT);
166   - RETURN();
167   -}
168   -
169   -void OPPROTO op_clr_delay_slot(void)
170   -{
171   - clr_flag(DELAY_SLOT);
172   - RETURN();
173   -}
174   -
175   -void OPPROTO op_clr_delay_slot_conditional(void)
176   -{
177   - clr_flag(DELAY_SLOT_CONDITIONAL);
178 161 RETURN();
179 162 }
180 163  
... ... @@ -242,7 +225,6 @@ void OPPROTO op_rte(void)
242 225 {
243 226 env->sr = env->ssr;
244 227 env->delayed_pc = env->spc;
245   - set_flag(DELAY_SLOT);
246 228 RETURN();
247 229 }
248 230  
... ... @@ -458,7 +440,6 @@ void OPPROTO op_cmp_pz_T0(void)
458 440 void OPPROTO op_jmp_T0(void)
459 441 {
460 442 env->delayed_pc = T0;
461   - set_flag(DELAY_SLOT);
462 443 RETURN();
463 444 }
464 445  
... ... @@ -993,11 +974,10 @@ void OPPROTO op_jT(void)
993 974  
994 975 void OPPROTO op_jdelayed(void)
995 976 {
996   - uint32_t flags;
997   - flags = env->flags;
998   - env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
999   - if (flags & DELAY_SLOT)
1000   - GOTO_LABEL_PARAM(1);
  977 + if (env->flags & DELAY_SLOT_TRUE) {
  978 + env->flags &= ~DELAY_SLOT_TRUE;
  979 + GOTO_LABEL_PARAM(1);
  980 + }
1001 981 RETURN();
1002 982 }
1003 983  
... ...
target-sh4/translate.c
... ... @@ -57,11 +57,21 @@ typedef struct DisasContext {
57 57 uint32_t fpscr;
58 58 uint16_t opcode;
59 59 uint32_t flags;
  60 + int bstate;
60 61 int memidx;
61 62 uint32_t delayed_pc;
62 63 int singlestep_enabled;
63 64 } DisasContext;
64 65  
  66 +enum {
  67 + BS_NONE = 0, /* We go out of the TB without reaching a branch or an
  68 + * exception condition
  69 + */
  70 + BS_STOP = 1, /* We want to stop translation for any reason */
  71 + BS_BRANCH = 2, /* We reached a branch condition */
  72 + BS_EXCP = 3, /* We reached an exception condition */
  73 +};
  74 +
65 75 #ifdef CONFIG_USER_ONLY
66 76  
67 77 #define GEN_OP_LD(width, reg) \
... ... @@ -176,15 +186,6 @@ static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest)
176 186 gen_op_exit_tb();
177 187 }
178 188  
179   -/* Jump to pc after an exception */
180   -static void gen_jump_exception(DisasContext * ctx)
181   -{
182   - gen_op_movl_imm_T0(0);
183   - if (ctx->singlestep_enabled)
184   - gen_op_debug();
185   - gen_op_exit_tb();
186   -}
187   -
188 189 static void gen_jump(DisasContext * ctx)
189 190 {
190 191 if (ctx->delayed_pc == (uint32_t) - 1) {
... ... @@ -220,7 +221,7 @@ static void gen_delayed_conditional_jump(DisasContext * ctx)
220 221  
221 222 l1 = gen_new_label();
222 223 gen_op_jdelayed(l1);
223   - gen_goto_tb(ctx, 1, ctx->pc);
  224 + gen_goto_tb(ctx, 1, ctx->pc + 2);
224 225 gen_set_label(l1);
225 226 gen_jump(ctx);
226 227 }
... ... @@ -248,10 +249,10 @@ static void gen_delayed_conditional_jump(DisasContext * ctx)
248 249  
249 250 #define CHECK_NOT_DELAY_SLOT \
250 251 if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \
251   - {gen_op_raise_slot_illegal_instruction (); ctx->flags |= BRANCH_EXCEPTION; \
  252 + {gen_op_raise_slot_illegal_instruction (); ctx->bstate = BS_EXCP; \
252 253 return;}
253 254  
254   -void decode_opc(DisasContext * ctx)
  255 +void _decode_opc(DisasContext * ctx)
255 256 {
256 257 #if 0
257 258 fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode);
... ... @@ -290,11 +291,11 @@ void decode_opc(DisasContext * ctx)
290 291 return;
291 292 case 0xfbfb: /* frchg */
292 293 gen_op_frchg();
293   - ctx->flags |= MODE_CHANGE;
  294 + ctx->bstate = BS_STOP;
294 295 return;
295 296 case 0xf3fb: /* fschg */
296 297 gen_op_fschg();
297   - ctx->flags |= MODE_CHANGE;
  298 + ctx->bstate = BS_STOP;
298 299 return;
299 300 case 0x0009: /* nop */
300 301 return;
... ... @@ -805,7 +806,7 @@ void decode_opc(DisasContext * ctx)
805 806 CHECK_NOT_DELAY_SLOT
806 807 gen_conditional_jump(ctx, ctx->pc + 2,
807 808 ctx->pc + 4 + B7_0s * 2);
808   - ctx->flags |= BRANCH_CONDITIONAL;
  809 + ctx->bstate = BS_BRANCH;
809 810 return;
810 811 case 0x8f00: /* bf/s label */
811 812 CHECK_NOT_DELAY_SLOT
... ... @@ -816,7 +817,7 @@ void decode_opc(DisasContext * ctx)
816 817 CHECK_NOT_DELAY_SLOT
817 818 gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2,
818 819 ctx->pc + 2);
819   - ctx->flags |= BRANCH_CONDITIONAL;
  820 + ctx->bstate = BS_BRANCH;
820 821 return;
821 822 case 0x8d00: /* bt/s label */
822 823 CHECK_NOT_DELAY_SLOT
... ... @@ -908,7 +909,7 @@ void decode_opc(DisasContext * ctx)
908 909 case 0xc300: /* trapa #imm */
909 910 CHECK_NOT_DELAY_SLOT gen_op_movl_imm_PC(ctx->pc);
910 911 gen_op_trapa(B7_0);
911   - ctx->flags |= BRANCH;
  912 + ctx->bstate = BS_BRANCH;
912 913 return;
913 914 case 0xc800: /* tst #imm,R0 */
914 915 gen_op_tst_imm_rN(B7_0, REG(0));
... ... @@ -1012,8 +1013,8 @@ void decode_opc(DisasContext * ctx)
1012 1013 gen_op_movl_rN_T1 (REG(B11_8)); \
1013 1014 gen_op_stl_T0_T1 (ctx); \
1014 1015 return;
1015   - LDST(sr, 0x400e, 0x4007, ldc, 0x0002, 0x4003, stc, ctx->flags |=
1016   - MODE_CHANGE;)
  1016 + LDST(sr, 0x400e, 0x4007, ldc, 0x0002, 0x4003, stc, ctx->bstate =
  1017 + BS_STOP;)
1017 1018 LDST(gbr, 0x401e, 0x4017, ldc, 0x0012, 0x4013, stc,)
1018 1019 LDST(vbr, 0x402e, 0x4027, ldc, 0x0022, 0x4023, stc,)
1019 1020 LDST(ssr, 0x403e, 0x4037, ldc, 0x0032, 0x4033, stc,)
... ... @@ -1023,8 +1024,8 @@ void decode_opc(DisasContext * ctx)
1023 1024 LDST(macl, 0x401a, 0x4016, lds, 0x001a, 0x4012, sts,)
1024 1025 LDST(pr, 0x402a, 0x4026, lds, 0x002a, 0x4022, sts,)
1025 1026 LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x4052, sts,)
1026   - LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x4062, sts, ctx->flags |=
1027   - MODE_CHANGE;)
  1027 + LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x4062, sts, ctx->bstate =
  1028 + BS_STOP;)
1028 1029 case 0x00c3: /* movca.l R0,@Rm */
1029 1030 gen_op_movl_rN_T0(REG(0));
1030 1031 gen_op_movl_rN_T1(REG(B11_8));
... ... @@ -1141,7 +1142,28 @@ void decode_opc(DisasContext * ctx)
1141 1142 fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n",
1142 1143 ctx->opcode, ctx->pc);
1143 1144 gen_op_raise_illegal_instruction();
1144   - ctx->flags |= BRANCH_EXCEPTION;
  1145 + ctx->bstate = BS_EXCP;
  1146 +}
  1147 +
  1148 +void decode_opc(DisasContext * ctx)
  1149 +{
  1150 + uint32_t old_flags = ctx->flags;
  1151 +
  1152 + _decode_opc(ctx);
  1153 +
  1154 + if (old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) {
  1155 + if (ctx->flags & DELAY_SLOT_CLEARME) {
  1156 + gen_op_store_flags(0);
  1157 + }
  1158 + ctx->flags = 0;
  1159 + ctx->bstate = BS_BRANCH;
  1160 + if (old_flags & DELAY_SLOT_CONDITIONAL) {
  1161 + gen_delayed_conditional_jump(ctx);
  1162 + } else if (old_flags & DELAY_SLOT) {
  1163 + gen_jump(ctx);
  1164 + }
  1165 +
  1166 + }
1145 1167 }
1146 1168  
1147 1169 static inline int
... ... @@ -1151,7 +1173,6 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
1151 1173 DisasContext ctx;
1152 1174 target_ulong pc_start;
1153 1175 static uint16_t *gen_opc_end;
1154   - uint32_t old_flags;
1155 1176 int i, ii;
1156 1177  
1157 1178 pc_start = tb->pc;
... ... @@ -1159,14 +1180,14 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
1159 1180 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
1160 1181 gen_opparam_ptr = gen_opparam_buf;
1161 1182 ctx.pc = pc_start;
1162   - ctx.flags = env->flags;
1163   - old_flags = 0;
  1183 + ctx.flags = (uint32_t)tb->flags;
  1184 + ctx.bstate = BS_NONE;
1164 1185 ctx.sr = env->sr;
1165 1186 ctx.fpscr = env->fpscr;
1166 1187 ctx.memidx = (env->sr & SR_MD) ? 1 : 0;
1167 1188 /* We don't know if the delayed pc came from a dynamic or static branch,
1168 1189 so assume it is a dynamic branch. */
1169   - ctx.delayed_pc = -1;
  1190 + ctx.delayed_pc = -1; /* use delayed pc from env pointer */
1170 1191 ctx.tb = tb;
1171 1192 ctx.singlestep_enabled = env->singlestep_enabled;
1172 1193 nb_gen_labels = 0;
... ... @@ -1180,18 +1201,14 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
1180 1201 #endif
1181 1202  
1182 1203 ii = -1;
1183   - while ((old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) == 0 &&
1184   - (ctx.flags & (BRANCH | BRANCH_CONDITIONAL | MODE_CHANGE |
1185   - BRANCH_EXCEPTION)) == 0 &&
1186   - gen_opc_ptr < gen_opc_end && ctx.sr == env->sr) {
1187   - old_flags = ctx.flags;
  1204 + while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
1188 1205 if (env->nb_breakpoints > 0) {
1189 1206 for (i = 0; i < env->nb_breakpoints; i++) {
1190 1207 if (ctx.pc == env->breakpoints[i]) {
1191 1208 /* We have hit a breakpoint - make sure PC is up-to-date */
1192 1209 gen_op_movl_imm_PC(ctx.pc);
1193 1210 gen_op_debug();
1194   - ctx.flags |= BRANCH_EXCEPTION;
  1211 + ctx.bstate = BS_EXCP;
1195 1212 break;
1196 1213 }
1197 1214 }
... ... @@ -1204,6 +1221,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
1204 1221 gen_opc_instr_start[ii++] = 0;
1205 1222 }
1206 1223 gen_opc_pc[ii] = ctx.pc;
  1224 + gen_opc_hflags[ii] = ctx.flags;
1207 1225 gen_opc_instr_start[ii] = 1;
1208 1226 }
1209 1227 #if 0
... ... @@ -1221,21 +1239,30 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
1221 1239 break;
1222 1240 #endif
1223 1241 }
1224   -
1225   - if (old_flags & DELAY_SLOT_CONDITIONAL) {
1226   - gen_delayed_conditional_jump(&ctx);
1227   - } else if (old_flags & DELAY_SLOT) {
1228   - gen_op_clr_delay_slot();
1229   - gen_jump(&ctx);
1230   - } else if (ctx.flags & BRANCH_EXCEPTION) {
1231   - gen_jump_exception(&ctx);
1232   - } else if ((ctx.flags & (BRANCH | BRANCH_CONDITIONAL)) == 0) {
1233   - gen_goto_tb(&ctx, 0, ctx.pc);
1234   - }
1235   -
1236 1242 if (env->singlestep_enabled) {
1237   - gen_op_debug();
  1243 + gen_op_debug();
  1244 + } else {
  1245 + switch (ctx.bstate) {
  1246 + case BS_STOP:
  1247 + /* gen_op_interrupt_restart(); */
  1248 + /* fall through */
  1249 + case BS_NONE:
  1250 + if (ctx.flags) {
  1251 + gen_op_store_flags(ctx.flags | DELAY_SLOT_CLEARME);
  1252 + }
  1253 + gen_goto_tb(&ctx, 0, ctx.pc);
  1254 + break;
  1255 + case BS_EXCP:
  1256 + /* gen_op_interrupt_restart(); */
  1257 + gen_op_movl_imm_T0(0);
  1258 + gen_op_exit_tb();
  1259 + break;
  1260 + case BS_BRANCH:
  1261 + default:
  1262 + break;
  1263 + }
1238 1264 }
  1265 +
1239 1266 *gen_opc_ptr = INDEX_op_end;
1240 1267 if (search_pc) {
1241 1268 i = gen_opc_ptr - gen_opc_buf;
... ...
translate-all.c
... ... @@ -53,7 +53,7 @@ uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
53 53 #elif defined(TARGET_SPARC)
54 54 target_ulong gen_opc_npc[OPC_BUF_SIZE];
55 55 target_ulong gen_opc_jump_pc[2];
56   -#elif defined(TARGET_MIPS)
  56 +#elif defined(TARGET_MIPS) || defined(TARGET_SH4)
57 57 uint32_t gen_opc_hflags[OPC_BUF_SIZE];
58 58 #endif
59 59  
... ... @@ -298,6 +298,9 @@ int cpu_restore_state(TranslationBlock *tb,
298 298 env->hflags |= gen_opc_hflags[j];
299 299 #elif defined(TARGET_ALPHA)
300 300 env->pc = gen_opc_pc[j];
  301 +#elif defined(TARGET_SH4)
  302 + env->pc = gen_opc_pc[j];
  303 + env->flags = gen_opc_hflags[j];
301 304 #endif
302 305 return 0;
303 306 }
... ...