rm unused file
[picodrive.git] / cpu / sh2 / compiler.c
CommitLineData
679af8a3 1#include <stdio.h>
2#include <stdlib.h>
3#include <assert.h>
41397701 4
679af8a3 5#include "sh2.h"
6#include "compiler.h"
7#include "../drc/cmn.h"
8
9#define BLOCK_CYCLE_LIMIT 100
10
11typedef enum {
12 SHR_R0 = 0, SHR_R15 = 15,
13 SHR_PC, SHR_PPC, SHR_PR, SHR_SR,
14 SHR_GBR, SHR_VBR, SHR_MACH, SHR_MACL,
15} sh2_reg_e;
16
17typedef struct block_desc_ {
18 u32 addr; // SH2 PC address
19 void *tcache_ptr; // translated block for above PC
20 struct block_desc_ *next; // next block with the same PC hash
21} block_desc;
22
23#define MAX_BLOCK_COUNT 1024
24static block_desc *block_table;
25static int block_count;
26
27#define MAX_HASH_ENTRIES 1024
28#define HASH_MASK (MAX_HASH_ENTRIES - 1)
29
30#ifdef DRC_DEBUG
31#include "mame/sh2dasm.h"
32#include <platform/linux/host_dasm.h>
33static void *tcache_dsm_ptr = tcache;
34#endif
35
36static void *tcache_ptr;
37
38#include "../drc/emit_x86.c"
39
40extern void sh2_drc_entry(SH2 *sh2, void *block);
41extern void sh2_drc_exit(void);
42
43// tmp
44extern void __attribute__((regparm(2))) sh2_do_op(SH2 *sh2, int opcode);
45
46static void *dr_find_block(block_desc *tab, u32 addr)
47{
48 for (tab = tab->next; tab != NULL; tab = tab->next)
49 if (tab->addr == addr)
50 break;
51
52 if (tab != NULL)
53 return tab->tcache_ptr;
54
55 printf("block miss for %08x\n", addr);
56 return NULL;
57}
58
59static block_desc *dr_add_block(u32 addr, void *tcache_ptr)
60{
61 block_desc *bd;
62
63 if (block_count == MAX_BLOCK_COUNT) {
64 // FIXME: flush cache instead
65 printf("block descriptor overflow\n");
66 exit(1);
67 }
68
69 bd = &block_table[block_count];
70 bd->addr = addr;
71 bd->tcache_ptr = tcache_ptr;
72 block_count++;
73
74 return bd;
75}
76
77#define HASH_FUNC(hash_tab, addr) \
78 ((block_desc **)(hash_tab))[(addr) & HASH_MASK]
79
80// ---------------------------------------------------------------
81
82static void emit_move_r_imm32(sh2_reg_e dst, u32 imm)
41397701 83{
679af8a3 84 int host_dst = reg_map_g2h[dst];
85 int tmp = 0;
86
87 if (host_dst != -1)
88 tmp = host_dst;
89 emith_move_r_imm(tmp, imm);
90 if (host_dst == -1)
91 emith_ctx_write(tmp, dst * 4);
92}
93
94static void emit_move_r_r(sh2_reg_e dst, sh2_reg_e src)
95{
96 int host_dst = reg_map_g2h[dst], host_src = reg_map_g2h[src];
97 int tmp = 0;
98
99 if (host_dst != -1 && host_src != -1) {
100 emith_move_r_r(host_dst, host_src);
101 return;
102 }
103
104 if (host_src != -1)
105 tmp = host_src;
106 if (host_dst != -1)
107 tmp = host_dst;
108
109 if (host_src == -1)
110 emith_ctx_read(tmp, src * 4);
111 if (host_dst == -1)
112 emith_ctx_write(tmp, dst * 4);
113}
114
115static void emit_braf(sh2_reg_e reg, u32 pc)
116{
117 int host_reg = reg_map_g2h[reg];
118 if (host_reg == -1) {
119 emith_ctx_read(0, reg * 4);
120 } else
121 emith_move_r_r(0, host_reg);
122 emith_add_r_imm(0, pc);
123
124 emith_ctx_write(0, SHR_PC * 4);
125}
126
127// FIXME: this is broken, delayed insn shouldn't affect branch
128#define DELAYED_OP \
129 if (delayed_op < 0) { \
130 delayed_op = op; \
131 goto next_op; \
132 } \
133 delayed_op = -1; \
134 pc -= 2 /* adjust back */
135
136/*
137static int sh2_translate_op4(int op)
138{
139 switch (op & 0x000f)
140 {
141 case 0x0b:
142 default:
143 emith_pass_arg(2, sh2, op);
144 emith_call(sh2_do_op);
145 break;
146 }
147
148 return 0;
149}
150*/
151
152static void *sh2_translate(SH2 *sh2, block_desc *other_block)
153{
154 void *block_entry = tcache_ptr;
155 block_desc *this_block;
41397701 156 unsigned int pc = sh2->pc;
679af8a3 157 int op, delayed_op = -1;
158 int cycles = 0;
159 u32 tmp;
160
161 this_block = dr_add_block(pc, block_entry);
162 if (other_block != NULL) {
163 printf("hash collision between %08x and %08x\n", pc, other_block->addr);
164 this_block->next = other_block;
165 }
166 HASH_FUNC(sh2->pc_hashtab, pc) = this_block;
167
168#ifdef DRC_DEBUG
169 printf("== %csh2 block #%d %08x %p\n", sh2->is_slave ? 's' : 'm',
170 block_count, pc, block_entry);
171#endif
172
173 while (cycles < BLOCK_CYCLE_LIMIT)
174 {
175 if (delayed_op >= 0)
176 op = delayed_op;
177 else {
178next_op:
179 op = p32x_sh2_read16(pc, sh2->is_slave);
180
181#ifdef DRC_DEBUG
182 {
183 char buff[64];
184 DasmSH2(buff, pc, op);
185 printf("%08x %04x %s\n", pc, op, buff);
186 }
187#endif
188 }
189
190 pc += 2;
191 cycles++;
192
193 switch ((op >> 12) & 0x0f)
194 {
195 case 0x00:
196 // RTS 0000000000001011
197 if (op == 0x000b) {
198 DELAYED_OP;
199 emit_move_r_r(SHR_PC, SHR_PR);
200 cycles++;
201 goto end_block;
202 }
203 // RTE 0000000000101011
204 if (op == 0x002b) {
205 DELAYED_OP;
206 cycles++;
207 //emit_move_r_r(SHR_PC, SHR_PR);
208 emit_move_r_imm32(SHR_PC, pc - 4);
209 emith_pass_arg(2, sh2, op);
210 emith_call(sh2_do_op);
211 goto end_block;
212 }
213 // BRAF Rm 0000mmmm00100011
214 if (op == 0x0023) {
215 DELAYED_OP;
216 cycles++;
217 emit_braf((op >> 8) & 0x0f, pc);
218 goto end_block;
219 }
220 // BSRF Rm 0000mmmm00000011
221 if (op == 0x0003) {
222 DELAYED_OP;
223 emit_move_r_imm32(SHR_PR, pc);
224 emit_braf((op >> 8) & 0x0f, pc);
225 cycles++;
226 goto end_block;
227 }
228 goto default_;
229
230 case 0x04:
231 // JMP @Rm 0100mmmm00101011
232 if ((op & 0xff) == 0x2b) {
233 DELAYED_OP;
234 emit_move_r_r(SHR_PC, (op >> 8) & 0x0f);
235 cycles++;
236 goto end_block;
237 }
238 // JSR @Rm 0100mmmm00001011
239 if ((op & 0xff) == 0x0b) {
240 DELAYED_OP;
241 emit_move_r_imm32(SHR_PR, pc);
242 emit_move_r_r(SHR_PC, (op >> 8) & 0x0f);
243 cycles++;
244 goto end_block;
245 }
246 goto default_;
247
248 case 0x08: {
249 int adj = 2;
250 switch (op & 0x0f00) {
251 // BT/S label 10001101dddddddd
252 case 0x0d00:
253 // BF/S label 10001111dddddddd
254 case 0x0f00:
255 DELAYED_OP;
256 cycles--;
257 adj = 0;
258 // fallthrough
259 // BT label 10001001dddddddd
260 case 0x0900:
261 // BF label 10001011dddddddd
262 case 0x0b00:
263 cycles += 2;
264 emit_move_r_imm32(SHR_PC, pc);
265 emith_test_t();
266 tmp = ((signed int)(op << 24) >> 23);
267 EMIT_CONDITIONAL(emit_move_r_imm32(SHR_PC, pc + tmp + adj), (op & 0x0200) ? 1 : 0);
268 goto end_block;
269 }
270 goto default_;
271 }
272
273 case 0x0a:
274 // BRA label 1010dddddddddddd
275 DELAYED_OP;
276 do_bra:
277 tmp = ((signed int)(op << 20) >> 19);
278 emit_move_r_imm32(SHR_PC, pc + tmp);
279 cycles++;
280 goto end_block;
281
282 case 0x0b:
283 // BSR label 1011dddddddddddd
284 DELAYED_OP;
285 emit_move_r_imm32(SHR_PR, pc);
286 goto do_bra;
287
288 default:
289 default_:
290 emit_move_r_imm32(SHR_PC, pc - 2);
291 emith_pass_arg(2, sh2, op);
292 emith_call(sh2_do_op);
293 break;
294 }
295
296#ifdef DRC_DEBUG
297 host_dasm(tcache_dsm_ptr, (char *)tcache_ptr - (char *)tcache_dsm_ptr);
298 tcache_dsm_ptr = tcache_ptr;
299#endif
300 }
301
302end_block:
303 if ((char *)tcache_ptr - (char *)tcache > DRC_TCACHE_SIZE) {
304 printf("tcache overflow!\n");
305 fflush(stdout);
306 exit(1);
307 }
308
309 if (reg_map_g2h[SHR_SR] == -1) {
310 emith_ctx_sub(cycles << 12, SHR_SR * 4);
311 } else
312 emith_sub_r_imm(reg_map_g2h[SHR_SR], cycles << 12);
313 emith_jump(sh2_drc_exit);
314
315#ifdef DRC_DEBUG
316 host_dasm(tcache_dsm_ptr, (char *)tcache_ptr - (char *)tcache_dsm_ptr);
317 tcache_dsm_ptr = tcache_ptr;
318#endif
319 return block_entry;
320
321unimplemented:
322 // last op
323#ifdef DRC_DEBUG
324 host_dasm(tcache_dsm_ptr, (char *)tcache_ptr - (char *)tcache_dsm_ptr);
325 tcache_dsm_ptr = tcache_ptr;
326#endif
327 exit(1);
328}
329
330void __attribute__((noinline)) sh2_drc_dispatcher(SH2 *sh2)
331{
332 while (((signed int)sh2->sr >> 12) > 0)
333 {
334 block_desc *bd = HASH_FUNC(sh2->pc_hashtab, sh2->pc);
335 void *block = NULL;
336
337 if (bd != NULL) {
338 if (bd->addr == sh2->pc)
339 block = bd->tcache_ptr;
340 else
341 block = dr_find_block(bd, sh2->pc);
342 }
343
344 if (block == NULL)
345 block = sh2_translate(sh2, bd);
346
347#ifdef DRC_DEBUG
348 printf("= %csh2 enter %08x %p\n", sh2->is_slave ? 's' : 'm', sh2->pc, block);
349#endif
350 sh2_drc_entry(sh2, block);
351 }
352}
353
354void sh2_execute(SH2 *sh2, int cycles)
355{
356 sh2->cycles_aim += cycles;
357 cycles = sh2->cycles_aim - sh2->cycles_done;
358
359 // cycles are kept in SHR_SR unused bits (upper 20)
360 sh2->sr &= 0x3f3;
361 sh2->sr |= cycles << 12;
362 sh2_drc_dispatcher(sh2);
363
364 sh2->cycles_done += cycles - ((signed int)sh2->sr >> 12);
365}
366
367
368static int cmn_init_done;
369
370static int common_init(void)
371{
372 block_count = 0;
373 block_table = calloc(MAX_BLOCK_COUNT, sizeof(*block_table));
374 if (block_table == NULL)
375 return -1;
376
377 tcache_ptr = tcache;
378
379 cmn_init_done = 1;
380 return 0;
381}
382
383int sh2_drc_init(SH2 *sh2)
384{
385 if (!cmn_init_done) {
386 int ret = common_init();
387 if (ret)
388 return ret;
389 }
390
391 assert(sh2->pc_hashtab == NULL);
392 sh2->pc_hashtab = calloc(sizeof(sh2->pc_hashtab[0]), MAX_HASH_ENTRIES);
393 if (sh2->pc_hashtab == NULL)
394 return -1;
41397701 395
679af8a3 396 return 0;
41397701 397}
398