drc: arm: use movw/movt
[picodrive.git] / cpu / sh2 / compiler.c
CommitLineData
e898de13 1/*
cff531af 2 * SH2 recompiler
228ee974 3 * (C) notaz, 2009,2010,2013
cff531af 4 *
5 * This work is licensed under the terms of MAME license.
6 * See COPYING file in the top-level directory.
44e6452e 7 *
8 * notes:
9 * - tcache, block descriptor, link buffer overflows result in sh2_translate()
10 * failure, followed by full tcache invalidation for that region
00a725a8 11 * - jumps between blocks are tracked for SMC handling (in block_entry->links),
9bb5d91c 12 * except jumps between different tcaches
13 *
14 * implemented:
15 * - static register allocation
16 * - remaining register caching and tracking in temporaries
17 * - block-local branch linking
18 * - block linking (except between tcaches)
23686515 19 * - some constant propagation
9bb5d91c 20 *
21 * TODO:
23686515 22 * - better constant propagation
9bb5d91c 23 * - stack caching?
24 * - bug fixing
e898de13 25 */
f0d7b1fa 26#include <stddef.h>
679af8a3 27#include <stdio.h>
28#include <stdlib.h>
29#include <assert.h>
41397701 30
f4bb5d6b 31#include "../../pico/pico_int.h"
98a3d79b 32#include "../../pico/arm_features.h"
679af8a3 33#include "sh2.h"
34#include "compiler.h"
35#include "../drc/cmn.h"
5686d931 36#include "../debug.h"
679af8a3 37
23686515 38// features
39#define PROPAGATE_CONSTANTS 1
40#define LINK_BRANCHES 1
41
04092e32 42// limits (per block)
e1553677 43#define MAX_BLOCK_SIZE (BLOCK_INSN_LIMIT * 6 * 6)
04092e32 44
23686515 45// max literal offset from the block end
46#define MAX_LITERAL_OFFSET 32*2
e1553677 47#define MAX_LITERALS (BLOCK_INSN_LIMIT / 4)
04092e32 48#define MAX_LOCAL_BRANCHES 32
23686515 49
00faec9c 50// debug stuff
d602fd4f 51// 01 - warnings/errors
52// 02 - block info/smc
53// 04 - asm
54// 08 - runtime block entry log
55// 10 - smc self-check
00faec9c 56// {
e898de13 57#ifndef DRC_DEBUG
58#define DRC_DEBUG 0
59#endif
60
553c3eaa 61#if DRC_DEBUG
f4bb5d6b 62#define dbg(l,...) { \
63 if ((l) & DRC_DEBUG) \
64 elprintf(EL_STATUS, ##__VA_ARGS__); \
65}
e898de13 66#include "mame/sh2dasm.h"
009ef50c 67#include <platform/libpicofe/linux/host_dasm.h>
e898de13 68static int insns_compiled, hash_collisions, host_insn_count;
553c3eaa 69#define COUNT_OP \
70 host_insn_count++
71#else // !DRC_DEBUG
72#define COUNT_OP
73#define dbg(...)
e898de13 74#endif
553c3eaa 75
bf092a36 76///
77#define FETCH_OP(pc) \
78 dr_pc_base[(pc) / 2]
79
80#define FETCH32(a) \
81 ((dr_pc_base[(a) / 2] << 16) | dr_pc_base[(a) / 2 + 1])
82
83#define CHECK_UNHANDLED_BITS(mask, label) { \
84 if ((op & (mask)) != 0) \
85 goto label; \
86}
87
88#define GET_Fx() \
89 ((op >> 4) & 0x0f)
90
91#define GET_Rm GET_Fx
92
93#define GET_Rn() \
94 ((op >> 8) & 0x0f)
95
96#define BITMASK1(v0) (1 << (v0))
97#define BITMASK2(v0,v1) ((1 << (v0)) | (1 << (v1)))
98#define BITMASK3(v0,v1,v2) (BITMASK2(v0,v1) | (1 << (v2)))
99#define BITMASK4(v0,v1,v2,v3) (BITMASK3(v0,v1,v2) | (1 << (v3)))
100#define BITMASK5(v0,v1,v2,v3,v4) (BITMASK4(v0,v1,v2,v3) | (1 << (v4)))
101
102#define SHR_T SHR_SR // might make them separate someday
103
104static struct op_data {
105 u8 op;
106 u8 cycles;
107 u8 size; // 0, 1, 2 - byte, word, long
108 s8 rm; // branch or load/store data reg
109 u32 source; // bitmask of src regs
110 u32 dest; // bitmask of dest regs
111 u32 imm; // immediate/io address/branch target
112 // (for literal - address, not value)
113} ops[BLOCK_INSN_LIMIT];
114
115enum op_types {
116 OP_UNHANDLED = 0,
117 OP_BRANCH,
118 OP_BRANCH_CT, // conditional, branch if T set
119 OP_BRANCH_CF, // conditional, branch if T clear
120 OP_BRANCH_R, // indirect
121 OP_BRANCH_RF, // indirect far (PC + Rm)
122 OP_SETCLRT, // T flag set/clear
123 OP_MOVE, // register move
fa841b44 124 OP_LOAD_POOL, // literal pool load, imm is address
125 OP_MOVA,
bf092a36 126 OP_SLEEP,
127 OP_RTE,
128};
129
130#ifdef DRC_SH2
131
405dfdd7 132static int literal_disabled_frames;
133
fcdefcf6 134#if (DRC_DEBUG & 4)
f4bb5d6b 135static u8 *tcache_dsm_ptrs[3];
e898de13 136static char sh2dasm_buff[64];
f4bb5d6b 137#define do_host_disasm(tcid) \
138 host_dasm(tcache_dsm_ptrs[tcid], tcache_ptr - tcache_dsm_ptrs[tcid]); \
139 tcache_dsm_ptrs[tcid] = tcache_ptr
140#else
141#define do_host_disasm(x)
e898de13 142#endif
e05b81fc 143
fcdefcf6 144#if (DRC_DEBUG & 8) || defined(PDB)
5686d931 145static void REGPARM(3) *sh2_drc_log_entry(void *block, SH2 *sh2, u32 sr)
e05b81fc 146{
5686d931 147 if (block != NULL) {
fcdefcf6 148 dbg(8, "= %csh2 enter %08x %p, c=%d", sh2->is_slave ? 's' : 'm',
e05b81fc 149 sh2->pc, block, (signed int)sr >> 12);
5686d931 150 pdb_step(sh2, sh2->pc);
151 }
e05b81fc 152 return block;
153}
154#endif
8796b7ee 155// } debug
e898de13 156
44e6452e 157#define TCACHE_BUFFERS 3
f4bb5d6b 158
159// we have 3 translation cache buffers, split from one drc/cmn buffer.
160// BIOS shares tcache with data array because it's only used for init
161// and can be discarded early
8796b7ee 162// XXX: need to tune sizes
44e6452e 163static const int tcache_sizes[TCACHE_BUFFERS] = {
4943816b 164 DRC_TCACHE_SIZE * 6 / 8, // ROM (rarely used), DRAM
f4bb5d6b 165 DRC_TCACHE_SIZE / 8, // BIOS, data array in master sh2
166 DRC_TCACHE_SIZE / 8, // ... slave
167};
679af8a3 168
44e6452e 169static u8 *tcache_bases[TCACHE_BUFFERS];
170static u8 *tcache_ptrs[TCACHE_BUFFERS];
f4bb5d6b 171
172// ptr for code emiters
173static u8 *tcache_ptr;
e898de13 174
228ee974 175#define MAX_BLOCK_ENTRIES (BLOCK_INSN_LIMIT / 8)
176
00a725a8 177struct block_link {
178 u32 target_pc;
179 void *jump; // insn address
180 struct block_link *next; // either in block_entry->links or
181};
182
228ee974 183struct block_entry {
184 u32 pc;
44e6452e 185 void *tcache_ptr; // translated block for above PC
228ee974 186 struct block_entry *next; // next block in hash_table with same pc hash
00a725a8 187 struct block_link *links; // links to this entry
228ee974 188#if (DRC_DEBUG & 2)
189 struct block_desc *block;
190#endif
191};
192
193struct block_desc {
194 u32 addr; // block start SH2 PC address
51d86e55 195 u16 size; // ..of recompiled insns+lit. pool
196 u16 size_nolit; // same without literals
fcdefcf6 197#if (DRC_DEBUG & 2)
44e6452e 198 int refcount;
199#endif
228ee974 200 int entry_count;
201 struct block_entry entryp[MAX_BLOCK_ENTRIES];
e1553677 202};
44e6452e 203
44e6452e 204static const int block_max_counts[TCACHE_BUFFERS] = {
205 4*1024,
206 256,
207 256,
208};
e1553677 209static struct block_desc *block_tables[TCACHE_BUFFERS];
44e6452e 210static int block_counts[TCACHE_BUFFERS];
228ee974 211
00a725a8 212// we have block_link_pool to avoid using mallocs
213static const int block_link_pool_max_counts[TCACHE_BUFFERS] = {
228ee974 214 4*1024,
215 256,
216 256,
217};
00a725a8 218static struct block_link *block_link_pool[TCACHE_BUFFERS];
219static int block_link_pool_counts[TCACHE_BUFFERS];
220static struct block_link *unresolved_links[TCACHE_BUFFERS];
44e6452e 221
4943816b 222// used for invalidation
223static const int ram_sizes[TCACHE_BUFFERS] = {
224 0x40000,
225 0x1000,
226 0x1000,
227};
51d86e55 228#define INVAL_PAGE_SIZE 0x100
4943816b 229
230struct block_list {
e1553677 231 struct block_desc *block;
4943816b 232 struct block_list *next;
233};
234
235// array of pointers to block_lists for RAM and 2 data arrays
51d86e55 236// each array has len: sizeof(mem) / INVAL_PAGE_SIZE
4943816b 237static struct block_list **inval_lookup[TCACHE_BUFFERS];
569420b0 238
228ee974 239static const int hash_table_sizes[TCACHE_BUFFERS] = {
240 0x1000,
241 0x100,
242 0x100,
243};
244static struct block_entry **hash_tables[TCACHE_BUFFERS];
245
246#define HASH_FUNC(hash_tab, addr, mask) \
247 (hash_tab)[(((addr) >> 20) ^ ((addr) >> 2)) & (mask)]
248
c18edb34 249// host register tracking
250enum {
251 HR_FREE,
252 HR_CACHED, // 'val' has sh2_reg_e
23686515 253// HR_CONST, // 'val' has a constant
c18edb34 254 HR_TEMP, // reg used for temp storage
255};
256
23686515 257enum {
258 HRF_DIRTY = 1 << 0, // reg has "dirty" value to be written to ctx
259 HRF_LOCKED = 1 << 1, // HR_CACHED can't be evicted
260};
261
c18edb34 262typedef struct {
23686515 263 u32 hreg:5; // "host" reg
264 u32 greg:5; // "guest" reg
265 u32 type:3;
266 u32 flags:3;
267 u32 stamp:16; // kind of a timestamp
c18edb34 268} temp_reg_t;
269
80599a42 270// note: reg_temp[] must have at least the amount of
3863edbd 271// registers used by handlers in worst case (currently 4)
d4d62665 272#ifdef __arm__
65c75cb0 273#include "../drc/emit_arm.c"
274
2dbc96b1 275#ifndef __MACH__
276
65c75cb0 277static const int reg_map_g2h[] = {
8b4f38f4 278 4, 5, 6, 7,
279 8, -1, -1, -1,
c18edb34 280 -1, -1, -1, -1,
65514d85 281 -1, -1, -1, 9, // r12 .. sp
282 -1, -1, -1, 10, // SHR_PC, SHR_PPC, SHR_PR, SHR_SR,
283 -1, -1, -1, -1, // SHR_GBR, SHR_VBR, SHR_MACH, SHR_MACL,
c18edb34 284};
285
2dbc96b1 286#else
287
288// no r9..
289static const int reg_map_g2h[] = {
290 4, 5, 6, 7,
291 -1, -1, -1, -1,
292 -1, -1, -1, -1,
293 -1, -1, -1, 8, // r12 .. sp
294 -1, -1, -1, 10, // SHR_PC, SHR_PPC, SHR_PR, SHR_SR,
295 -1, -1, -1, -1, // SHR_GBR, SHR_VBR, SHR_MACH, SHR_MACL,
296};
297
298#endif
299
c18edb34 300static temp_reg_t reg_temp[] = {
301 { 0, },
302 { 1, },
303 { 12, },
304 { 14, },
305 { 2, },
306 { 3, },
65c75cb0 307};
308
e05b81fc 309#elif defined(__i386__)
e898de13 310#include "../drc/emit_x86.c"
311
65c75cb0 312static const int reg_map_g2h[] = {
8b4f38f4 313 xSI,-1, -1, -1,
c18edb34 314 -1, -1, -1, -1,
315 -1, -1, -1, -1,
316 -1, -1, -1, -1,
8b4f38f4 317 -1, -1, -1, xDI,
c18edb34 318 -1, -1, -1, -1,
319};
320
3863edbd 321// ax, cx, dx are usually temporaries by convention
c18edb34 322static temp_reg_t reg_temp[] = {
323 { xAX, },
3863edbd 324 { xBX, },
c18edb34 325 { xCX, },
326 { xDX, },
65c75cb0 327};
328
e05b81fc 329#else
330#error unsupported arch
65c75cb0 331#endif
332
80599a42 333#define T 0x00000001
334#define S 0x00000002
335#define I 0x000000f0
336#define Q 0x00000100
337#define M 0x00000200
18b94127 338#define T_save 0x00000800
80599a42 339
e05b81fc 340#define I_SHIFT 4
f0d7b1fa 341#define Q_SHIFT 8
342#define M_SHIFT 9
343
e05b81fc 344static void REGPARM(1) (*sh2_drc_entry)(SH2 *sh2);
345static void (*sh2_drc_dispatcher)(void);
346static void (*sh2_drc_exit)(void);
347static void (*sh2_drc_test_irq)(void);
5686d931 348
349static u32 REGPARM(2) (*sh2_drc_read8)(u32 a, SH2 *sh2);
350static u32 REGPARM(2) (*sh2_drc_read16)(u32 a, SH2 *sh2);
351static u32 REGPARM(2) (*sh2_drc_read32)(u32 a, SH2 *sh2);
e05b81fc 352static void REGPARM(2) (*sh2_drc_write8)(u32 a, u32 d);
e05b81fc 353static void REGPARM(2) (*sh2_drc_write16)(u32 a, u32 d);
f81107f5 354static void REGPARM(3) (*sh2_drc_write32)(u32 a, u32 d, SH2 *sh2);
679af8a3 355
a2b8c5a5 356// address space stuff
a2b8c5a5 357static int dr_ctx_get_mem_ptr(u32 a, u32 *mask)
358{
359 int poffs = -1;
360
361 if ((a & ~0x7ff) == 0) {
362 // BIOS
363 poffs = offsetof(SH2, p_bios);
364 *mask = 0x7ff;
365 }
366 else if ((a & 0xfffff000) == 0xc0000000) {
367 // data array
f81107f5 368 // FIXME: access sh2->data_array instead
a2b8c5a5 369 poffs = offsetof(SH2, p_da);
370 *mask = 0xfff;
371 }
372 else if ((a & 0xc6000000) == 0x06000000) {
373 // SDRAM
374 poffs = offsetof(SH2, p_sdram);
375 *mask = 0x03ffff;
376 }
377 else if ((a & 0xc6000000) == 0x02000000) {
378 // ROM
379 poffs = offsetof(SH2, p_rom);
380 *mask = 0x3fffff;
381 }
382
383 return poffs;
384}
385
228ee974 386static struct block_entry *dr_get_entry(u32 pc, int is_slave, int *tcache_id)
a2b8c5a5 387{
228ee974 388 struct block_entry *be;
389 u32 tcid = 0, mask;
a2b8c5a5 390
228ee974 391 // data arrays have their own caches
392 if ((pc & 0xe0000000) == 0xc0000000 || (pc & ~0xfff) == 0)
393 tcid = 1 + is_slave;
394
395 *tcache_id = tcid;
396
397 mask = hash_table_sizes[tcid] - 1;
398 be = HASH_FUNC(hash_tables[tcid], pc, mask);
399 for (; be != NULL; be = be->next)
400 if (be->pc == pc)
401 return be;
a2b8c5a5 402
403 return NULL;
404}
405
406// ---------------------------------------------------------------
407
408// block management
e1553677 409static void add_to_block_list(struct block_list **blist, struct block_desc *block)
4943816b 410{
411 struct block_list *added = malloc(sizeof(*added));
412 if (!added) {
413 elprintf(EL_ANOMALY, "drc OOM (1)");
414 return;
415 }
416 added->block = block;
417 added->next = *blist;
418 *blist = added;
419}
420
e1553677 421static void rm_from_block_list(struct block_list **blist, struct block_desc *block)
4943816b 422{
423 struct block_list *prev = NULL, *current = *blist;
f0ed9e38 424 for (; current != NULL; current = current->next) {
4943816b 425 if (current->block == block) {
426 if (prev == NULL)
427 *blist = current->next;
428 else
429 prev->next = current->next;
430 free(current);
431 return;
432 }
f0ed9e38 433 prev = current;
4943816b 434 }
435 dbg(1, "can't rm block %p (%08x-%08x)",
51d86e55 436 block, block->addr, block->addr + block->size);
4943816b 437}
438
439static void rm_block_list(struct block_list **blist)
440{
441 struct block_list *tmp, *current = *blist;
442 while (current != NULL) {
443 tmp = current;
444 current = current->next;
445 free(tmp);
446 }
447 *blist = NULL;
448}
449
a2b8c5a5 450static void REGPARM(1) flush_tcache(int tcid)
f4bb5d6b 451{
4943816b 452 int i;
453
553c3eaa 454 dbg(1, "tcache #%d flush! (%d/%d, bds %d/%d)", tcid,
f4bb5d6b 455 tcache_ptrs[tcid] - tcache_bases[tcid], tcache_sizes[tcid],
456 block_counts[tcid], block_max_counts[tcid]);
457
458 block_counts[tcid] = 0;
00a725a8 459 block_link_pool_counts[tcid] = 0;
460 unresolved_links[tcid] = NULL;
228ee974 461 memset(hash_tables[tcid], 0, sizeof(*hash_tables[0]) * hash_table_sizes[tcid]);
f4bb5d6b 462 tcache_ptrs[tcid] = tcache_bases[tcid];
228ee974 463 if (Pico32xMem != NULL) {
464 if (tcid == 0) // ROM, RAM
465 memset(Pico32xMem->drcblk_ram, 0,
466 sizeof(Pico32xMem->drcblk_ram));
467 else
468 memset(Pico32xMem->drcblk_da[tcid - 1], 0,
469 sizeof(Pico32xMem->drcblk_da[0]));
f4bb5d6b 470 }
fcdefcf6 471#if (DRC_DEBUG & 4)
f4bb5d6b 472 tcache_dsm_ptrs[tcid] = tcache_bases[tcid];
473#endif
4943816b 474
51d86e55 475 for (i = 0; i < ram_sizes[tcid] / INVAL_PAGE_SIZE; i++)
4943816b 476 rm_block_list(&inval_lookup[tcid][i]);
f4bb5d6b 477}
478
228ee974 479static void add_to_hashlist(struct block_entry *be, int tcache_id)
480{
481 u32 tcmask = hash_table_sizes[tcache_id] - 1;
482
483 be->next = HASH_FUNC(hash_tables[tcache_id], be->pc, tcmask);
484 HASH_FUNC(hash_tables[tcache_id], be->pc, tcmask) = be;
485
486#if (DRC_DEBUG & 2)
487 if (be->next != NULL) {
488 printf(" %08x: hash collision with %08x\n",
489 be->pc, be->next->pc);
490 hash_collisions++;
491 }
492#endif
493}
494
495static void rm_from_hashlist(struct block_entry *be, int tcache_id)
496{
497 u32 tcmask = hash_table_sizes[tcache_id] - 1;
498 struct block_entry *cur, *prev;
499
500 cur = HASH_FUNC(hash_tables[tcache_id], be->pc, tcmask);
501 if (cur == NULL)
502 goto missing;
503
504 if (be == cur) { // first
505 HASH_FUNC(hash_tables[tcache_id], be->pc, tcmask) = be->next;
506 return;
507 }
508
509 for (prev = cur, cur = cur->next; cur != NULL; cur = cur->next) {
510 if (cur == be) {
511 prev->next = cur->next;
512 return;
513 }
514 }
515
516missing:
517 dbg(1, "rm_from_hashlist: be %p %08x missing?", be, be->pc);
518}
519
f0ed9e38 520static void unregister_links(struct block_entry *be, int tcache_id)
521{
522 struct block_link *bl_unresolved = unresolved_links[tcache_id];
523 struct block_link *bl, *bl_next;
524
525 for (bl = be->links; bl != NULL; ) {
526 bl_next = bl->next;
527 bl->next = bl_unresolved;
528 bl_unresolved = bl;
529 bl = bl_next;
530 }
531 be->links = NULL;
532 unresolved_links[tcache_id] = bl_unresolved;
533}
534
535// unlike sh2_smc_rm_block, the block stays and can still be accessed
536// by other already directly linked blocks, just not preferred
537static void kill_block_entry(struct block_entry *be, int tcache_id)
538{
539 rm_from_hashlist(be, tcache_id);
540 unregister_links(be, tcache_id);
541}
542
51d86e55 543static struct block_desc *dr_add_block(u32 addr, u16 size_lit,
544 u16 size_nolit, int is_slave, int *blk_id)
679af8a3 545{
228ee974 546 struct block_entry *be;
e1553677 547 struct block_desc *bd;
a2b8c5a5 548 int tcache_id;
549 int *bcount;
550
228ee974 551 // do a lookup to get tcache_id and override check
552 be = dr_get_entry(addr, is_slave, &tcache_id);
f0ed9e38 553 if (be != NULL) {
554 dbg(1, "block override for %08x, was %p", addr, be->tcache_ptr);
555 kill_block_entry(be, tcache_id);
556 }
679af8a3 557
a2b8c5a5 558 bcount = &block_counts[tcache_id];
44e6452e 559 if (*bcount >= block_max_counts[tcache_id]) {
fcdefcf6 560 dbg(1, "bd overflow for tcache %d", tcache_id);
f4bb5d6b 561 return NULL;
44e6452e 562 }
679af8a3 563
f4bb5d6b 564 bd = &block_tables[tcache_id][*bcount];
679af8a3 565 bd->addr = addr;
51d86e55 566 bd->size = size_lit;
567 bd->size_nolit = size_nolit;
679af8a3 568
228ee974 569 bd->entry_count = 1;
570 bd->entryp[0].pc = addr;
571 bd->entryp[0].tcache_ptr = tcache_ptr;
00a725a8 572 bd->entryp[0].links = NULL;
fcdefcf6 573#if (DRC_DEBUG & 2)
228ee974 574 bd->entryp[0].block = bd;
575 bd->refcount = 0;
18b94127 576#endif
228ee974 577 add_to_hashlist(&bd->entryp[0], tcache_id);
578
579 *blk_id = *bcount;
580 (*bcount)++;
18b94127 581
679af8a3 582 return bd;
583}
584
a2b8c5a5 585static void REGPARM(3) *dr_lookup_block(u32 pc, int is_slave, int *tcache_id)
586{
228ee974 587 struct block_entry *be = NULL;
a2b8c5a5 588 void *block = NULL;
589
228ee974 590 be = dr_get_entry(pc, is_slave, tcache_id);
591 if (be != NULL)
592 block = be->tcache_ptr;
a2b8c5a5 593
fcdefcf6 594#if (DRC_DEBUG & 2)
228ee974 595 if (be != NULL)
596 be->block->refcount++;
a2b8c5a5 597#endif
598 return block;
599}
600
c25d78ee 601static void *dr_failure(void)
602{
603 lprintf("recompilation failed\n");
604 exit(1);
605}
606
00a725a8 607static void *dr_prepare_ext_branch(u32 pc, int is_slave, int tcache_id)
a2b8c5a5 608{
609#if LINK_BRANCHES
00a725a8 610 struct block_link *bl = block_link_pool[tcache_id];
611 int cnt = block_link_pool_counts[tcache_id];
612 struct block_entry *be = NULL;
a2b8c5a5 613 int target_tcache_id;
00a725a8 614 int i;
615
616 be = dr_get_entry(pc, is_slave, &target_tcache_id);
617 if (target_tcache_id != tcache_id)
618 return sh2_drc_dispatcher;
619
620 // if pool has been freed, reuse
621 for (i = cnt - 1; i >= 0; i--)
622 if (bl[i].target_pc != 0)
623 break;
624 cnt = i + 1;
625 if (cnt >= block_link_pool_max_counts[tcache_id]) {
6d797957 626 dbg(1, "bl overflow for tcache %d", tcache_id);
00a725a8 627 return NULL;
a2b8c5a5 628 }
00a725a8 629 bl += cnt;
630 block_link_pool_counts[tcache_id]++;
a2b8c5a5 631
00a725a8 632 bl->target_pc = pc;
633 bl->jump = tcache_ptr;
634
635 if (be != NULL) {
636 dbg(2, "- early link from %p to pc %08x", bl->jump, pc);
637 bl->next = be->links;
638 be->links = bl;
639 return be->tcache_ptr;
640 }
641 else {
642 bl->next = unresolved_links[tcache_id];
643 unresolved_links[tcache_id] = bl;
644 return sh2_drc_dispatcher;
645 }
a2b8c5a5 646#else
647 return sh2_drc_dispatcher;
648#endif
649}
650
00a725a8 651static void dr_link_blocks(struct block_entry *be, int tcache_id)
a2b8c5a5 652{
00a725a8 653#if LINK_BRANCHES
654 struct block_link *first = unresolved_links[tcache_id];
655 struct block_link *bl, *prev, *tmp;
656 u32 pc = be->pc;
657
658 for (bl = prev = first; bl != NULL; ) {
659 if (bl->target_pc == pc) {
660 dbg(2, "- link from %p to pc %08x", bl->jump, pc);
661 emith_jump_patch(bl->jump, tcache_ptr);
662
663 // move bl from unresolved_links to block_entry
664 tmp = bl->next;
665 bl->next = be->links;
666 be->links = bl;
667
668 if (bl == first)
669 first = prev = bl = tmp;
670 else
671 prev->next = bl = tmp;
672 continue;
a2b8c5a5 673 }
00a725a8 674 prev = bl;
675 bl = bl->next;
a2b8c5a5 676 }
00a725a8 677 unresolved_links[tcache_id] = first;
678
679 // could sync arm caches here, but that's unnecessary
a2b8c5a5 680#endif
681}
682
44e6452e 683#define ADD_TO_ARRAY(array, count, item, failcode) \
44e6452e 684 if (count >= ARRAY_SIZE(array)) { \
fcdefcf6 685 dbg(1, "warning: " #array " overflow"); \
44e6452e 686 failcode; \
fa841b44 687 } \
688 array[count++] = item;
44e6452e 689
a2b8c5a5 690static int find_in_array(u32 *array, size_t size, u32 what)
18b94127 691{
692 size_t i;
693 for (i = 0; i < size; i++)
694 if (what == array[i])
695 return i;
696
697 return -1;
698}
679af8a3 699
700// ---------------------------------------------------------------
701
a2b8c5a5 702// register cache / constant propagation stuff
23686515 703typedef enum {
704 RC_GR_READ,
705 RC_GR_WRITE,
706 RC_GR_RMW,
707} rc_gr_mode;
708
709static int rcache_get_reg_(sh2_reg_e r, rc_gr_mode mode, int do_locking);
710
711// guest regs with constants
712static u32 dr_gcregs[24];
713// a mask of constant/dirty regs
714static u32 dr_gcregs_mask;
715static u32 dr_gcregs_dirty;
716
a2b8c5a5 717#if PROPAGATE_CONSTANTS
23686515 718static void gconst_new(sh2_reg_e r, u32 val)
719{
23686515 720 int i;
721
722 dr_gcregs_mask |= 1 << r;
723 dr_gcregs_dirty |= 1 << r;
724 dr_gcregs[r] = val;
725
726 // throw away old r that we might have cached
727 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
728 if ((reg_temp[i].type == HR_CACHED) &&
729 reg_temp[i].greg == r) {
730 reg_temp[i].type = HR_FREE;
731 reg_temp[i].flags = 0;
732 }
733 }
23686515 734}
a2b8c5a5 735#endif
23686515 736
737static int gconst_get(sh2_reg_e r, u32 *val)
738{
739 if (dr_gcregs_mask & (1 << r)) {
740 *val = dr_gcregs[r];
741 return 1;
742 }
743 return 0;
744}
745
746static int gconst_check(sh2_reg_e r)
747{
748 if ((dr_gcregs_mask | dr_gcregs_dirty) & (1 << r))
749 return 1;
750 return 0;
751}
752
753// update hr if dirty, else do nothing
754static int gconst_try_read(int hr, sh2_reg_e r)
755{
756 if (dr_gcregs_dirty & (1 << r)) {
757 emith_move_r_imm(hr, dr_gcregs[r]);
758 dr_gcregs_dirty &= ~(1 << r);
759 return 1;
760 }
761 return 0;
762}
763
764static void gconst_check_evict(sh2_reg_e r)
765{
766 if (dr_gcregs_mask & (1 << r))
767 // no longer cached in reg, make dirty again
768 dr_gcregs_dirty |= 1 << r;
769}
770
771static void gconst_kill(sh2_reg_e r)
772{
773 dr_gcregs_mask &= ~(1 << r);
774 dr_gcregs_dirty &= ~(1 << r);
775}
776
777static void gconst_clean(void)
778{
779 int i;
780
781 for (i = 0; i < ARRAY_SIZE(dr_gcregs); i++)
782 if (dr_gcregs_dirty & (1 << i)) {
783 // using RC_GR_READ here: it will call gconst_try_read,
784 // cache the reg and mark it dirty.
785 rcache_get_reg_(i, RC_GR_READ, 0);
786 }
787}
788
789static void gconst_invalidate(void)
790{
791 dr_gcregs_mask = dr_gcregs_dirty = 0;
792}
793
c18edb34 794static u16 rcache_counter;
795
796static temp_reg_t *rcache_evict(void)
41397701 797{
c18edb34 798 // evict reg with oldest stamp
799 int i, oldest = -1;
800 u16 min_stamp = (u16)-1;
801
802 for (i = 0; i < ARRAY_SIZE(reg_temp); i++) {
23686515 803 if (reg_temp[i].type == HR_CACHED && !(reg_temp[i].flags & HRF_LOCKED) &&
804 reg_temp[i].stamp <= min_stamp) {
805 min_stamp = reg_temp[i].stamp;
806 oldest = i;
807 }
c18edb34 808 }
809
810 if (oldest == -1) {
80599a42 811 printf("no registers to evict, aborting\n");
c18edb34 812 exit(1);
813 }
814
815 i = oldest;
23686515 816 if (reg_temp[i].type == HR_CACHED) {
817 if (reg_temp[i].flags & HRF_DIRTY)
818 // writeback
819 emith_ctx_write(reg_temp[i].hreg, reg_temp[i].greg * 4);
820 gconst_check_evict(reg_temp[i].greg);
c18edb34 821 }
822
23686515 823 reg_temp[i].type = HR_FREE;
824 reg_temp[i].flags = 0;
c18edb34 825 return &reg_temp[i];
679af8a3 826}
827
23686515 828static int get_reg_static(sh2_reg_e r, rc_gr_mode mode)
829{
830 int i = reg_map_g2h[r];
831 if (i != -1) {
832 if (mode != RC_GR_WRITE)
833 gconst_try_read(i, r);
834 }
835 return i;
836}
c18edb34 837
80599a42 838// note: must not be called when doing conditional code
23686515 839static int rcache_get_reg_(sh2_reg_e r, rc_gr_mode mode, int do_locking)
679af8a3 840{
c18edb34 841 temp_reg_t *tr;
23686515 842 int i, ret;
c18edb34 843
23686515 844 // maybe statically mapped?
845 ret = get_reg_static(r, mode);
846 if (ret != -1)
847 goto end;
679af8a3 848
c18edb34 849 rcache_counter++;
850
851 // maybe already cached?
23686515 852 // if so, prefer against gconst (they must be in sync)
c18edb34 853 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
23686515 854 if (reg_temp[i].type == HR_CACHED && reg_temp[i].greg == r) {
c18edb34 855 reg_temp[i].stamp = rcache_counter;
856 if (mode != RC_GR_READ)
23686515 857 reg_temp[i].flags |= HRF_DIRTY;
858 ret = reg_temp[i].hreg;
859 goto end;
c18edb34 860 }
679af8a3 861 }
862
c18edb34 863 // use any free reg
864 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
23686515 865 if (reg_temp[i].type == HR_FREE) {
c18edb34 866 tr = &reg_temp[i];
867 goto do_alloc;
868 }
869 }
870
871 tr = rcache_evict();
872
873do_alloc:
23686515 874 tr->type = HR_CACHED;
875 if (do_locking)
876 tr->flags |= HRF_LOCKED;
877 if (mode != RC_GR_READ)
878 tr->flags |= HRF_DIRTY;
879 tr->greg = r;
c18edb34 880 tr->stamp = rcache_counter;
23686515 881 ret = tr->hreg;
882
883 if (mode != RC_GR_WRITE) {
884 if (gconst_check(r)) {
885 if (gconst_try_read(ret, r))
886 tr->flags |= HRF_DIRTY;
887 }
888 else
889 emith_ctx_read(tr->hreg, r * 4);
890 }
891
892end:
893 if (mode != RC_GR_READ)
894 gconst_kill(r);
895
896 return ret;
897}
898
899static int rcache_get_reg(sh2_reg_e r, rc_gr_mode mode)
900{
901 return rcache_get_reg_(r, mode, 1);
679af8a3 902}
903
c18edb34 904static int rcache_get_tmp(void)
679af8a3 905{
c18edb34 906 temp_reg_t *tr;
907 int i;
908
909 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
23686515 910 if (reg_temp[i].type == HR_FREE) {
c18edb34 911 tr = &reg_temp[i];
912 goto do_alloc;
913 }
914
915 tr = rcache_evict();
916
917do_alloc:
918 tr->type = HR_TEMP;
23686515 919 return tr->hreg;
c18edb34 920}
921
80599a42 922static int rcache_get_arg_id(int arg)
923{
924 int i, r = 0;
925 host_arg2reg(r, arg);
926
927 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
23686515 928 if (reg_temp[i].hreg == r)
80599a42 929 break;
930
04092e32 931 if (i == ARRAY_SIZE(reg_temp)) // can't happen
932 exit(1);
80599a42 933
23686515 934 if (reg_temp[i].type == HR_CACHED) {
80599a42 935 // writeback
23686515 936 if (reg_temp[i].flags & HRF_DIRTY)
937 emith_ctx_write(reg_temp[i].hreg, reg_temp[i].greg * 4);
938 gconst_check_evict(reg_temp[i].greg);
80599a42 939 }
940 else if (reg_temp[i].type == HR_TEMP) {
941 printf("arg %d reg %d already used, aborting\n", arg, r);
942 exit(1);
943 }
944
23686515 945 reg_temp[i].type = HR_FREE;
946 reg_temp[i].flags = 0;
947
80599a42 948 return i;
949}
950
951// get a reg to be used as function arg
80599a42 952static int rcache_get_tmp_arg(int arg)
953{
954 int id = rcache_get_arg_id(arg);
955 reg_temp[id].type = HR_TEMP;
956
23686515 957 return reg_temp[id].hreg;
80599a42 958}
959
23686515 960// same but caches a reg. RC_GR_READ only.
80599a42 961static int rcache_get_reg_arg(int arg, sh2_reg_e r)
962{
963 int i, srcr, dstr, dstid;
04092e32 964 int dirty = 0, src_dirty = 0;
80599a42 965
966 dstid = rcache_get_arg_id(arg);
23686515 967 dstr = reg_temp[dstid].hreg;
80599a42 968
969 // maybe already statically mapped?
23686515 970 srcr = get_reg_static(r, RC_GR_READ);
80599a42 971 if (srcr != -1)
972 goto do_cache;
973
974 // maybe already cached?
975 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
23686515 976 if ((reg_temp[i].type == HR_CACHED) &&
977 reg_temp[i].greg == r)
80599a42 978 {
23686515 979 srcr = reg_temp[i].hreg;
04092e32 980 if (reg_temp[i].flags & HRF_DIRTY)
981 src_dirty = 1;
80599a42 982 goto do_cache;
983 }
984 }
985
986 // must read
987 srcr = dstr;
23686515 988 if (gconst_check(r)) {
989 if (gconst_try_read(srcr, r))
990 dirty = 1;
991 }
992 else
993 emith_ctx_read(srcr, r * 4);
80599a42 994
995do_cache:
23686515 996 if (dstr != srcr)
80599a42 997 emith_move_r_r(dstr, srcr);
04092e32 998#if 1
999 else
1000 dirty |= src_dirty;
1001
1002 if (dirty)
1003 // must clean, callers might want to modify the arg before call
1004 emith_ctx_write(dstr, r * 4);
1005#else
1006 if (dirty)
1007 reg_temp[dstid].flags |= HRF_DIRTY;
1008#endif
80599a42 1009
1010 reg_temp[dstid].stamp = ++rcache_counter;
1011 reg_temp[dstid].type = HR_CACHED;
23686515 1012 reg_temp[dstid].greg = r;
1013 reg_temp[dstid].flags |= HRF_LOCKED;
80599a42 1014 return dstr;
1015}
1016
c18edb34 1017static void rcache_free_tmp(int hr)
1018{
1019 int i;
1020 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
23686515 1021 if (reg_temp[i].hreg == hr)
c18edb34 1022 break;
1023
80599a42 1024 if (i == ARRAY_SIZE(reg_temp) || reg_temp[i].type != HR_TEMP) {
c18edb34 1025 printf("rcache_free_tmp fail: #%i hr %d, type %d\n", i, hr, reg_temp[i].type);
80599a42 1026 return;
1027 }
1028
1029 reg_temp[i].type = HR_FREE;
23686515 1030 reg_temp[i].flags = 0;
1031}
1032
1033static void rcache_unlock(int hr)
1034{
1035 int i;
1036 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
1037 if (reg_temp[i].type == HR_CACHED && reg_temp[i].hreg == hr)
1038 reg_temp[i].flags &= ~HRF_LOCKED;
1039}
1040
1041static void rcache_unlock_all(void)
1042{
1043 int i;
1044 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
1045 reg_temp[i].flags &= ~HRF_LOCKED;
c18edb34 1046}
1047
759c9d38 1048#ifdef DRC_CMP
e9a11abb 1049static u32 rcache_used_hreg_mask(void)
6d797957 1050{
1051 u32 mask = 0;
1052 int i;
1053
1054 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
1055 if (reg_temp[i].type != HR_FREE)
1056 mask |= 1 << reg_temp[i].hreg;
1057
1058 return mask;
1059}
759c9d38 1060#endif
6d797957 1061
80599a42 1062static void rcache_clean(void)
c18edb34 1063{
1064 int i;
23686515 1065 gconst_clean();
1066
80599a42 1067 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
23686515 1068 if (reg_temp[i].type == HR_CACHED && (reg_temp[i].flags & HRF_DIRTY)) {
c18edb34 1069 // writeback
23686515 1070 emith_ctx_write(reg_temp[i].hreg, reg_temp[i].greg * 4);
1071 reg_temp[i].flags &= ~HRF_DIRTY;
c18edb34 1072 }
80599a42 1073}
1074
1075static void rcache_invalidate(void)
1076{
1077 int i;
23686515 1078 for (i = 0; i < ARRAY_SIZE(reg_temp); i++) {
c18edb34 1079 reg_temp[i].type = HR_FREE;
23686515 1080 reg_temp[i].flags = 0;
1081 }
c18edb34 1082 rcache_counter = 0;
23686515 1083
1084 gconst_invalidate();
c18edb34 1085}
1086
80599a42 1087static void rcache_flush(void)
1088{
1089 rcache_clean();
1090 rcache_invalidate();
1091}
1092
c18edb34 1093// ---------------------------------------------------------------
1094
23686515 1095static int emit_get_rbase_and_offs(u32 a, u32 *offs)
1096{
23686515 1097 u32 mask = 0;
a2b8c5a5 1098 int poffs;
23686515 1099 int hr;
1100
a2b8c5a5 1101 poffs = dr_ctx_get_mem_ptr(a, &mask);
23686515 1102 if (poffs == -1)
1103 return -1;
1104
a2b8c5a5 1105 // XXX: could use some related reg
23686515 1106 hr = rcache_get_tmp();
1107 emith_ctx_read(hr, poffs);
1108 emith_add_r_imm(hr, a & mask & ~0xff);
1109 *offs = a & 0xff; // XXX: ARM oriented..
1110 return hr;
1111}
1112
c18edb34 1113static void emit_move_r_imm32(sh2_reg_e dst, u32 imm)
1114{
23686515 1115#if PROPAGATE_CONSTANTS
1116 gconst_new(dst, imm);
1117#else
c18edb34 1118 int hr = rcache_get_reg(dst, RC_GR_WRITE);
1119 emith_move_r_imm(hr, imm);
23686515 1120#endif
c18edb34 1121}
1122
1123static void emit_move_r_r(sh2_reg_e dst, sh2_reg_e src)
1124{
1125 int hr_d = rcache_get_reg(dst, RC_GR_WRITE);
1126 int hr_s = rcache_get_reg(src, RC_GR_READ);
1127
1128 emith_move_r_r(hr_d, hr_s);
679af8a3 1129}
1130
52d759c3 1131// T must be clear, and comparison done just before this
1132static void emit_or_t_if_eq(int srr)
1133{
1134 EMITH_SJMP_START(DCOND_NE);
1135 emith_or_r_imm_c(DCOND_EQ, srr, T);
1136 EMITH_SJMP_END(DCOND_NE);
1137}
1138
80599a42 1139// arguments must be ready
1140// reg cache must be clean before call
23686515 1141static int emit_memhandler_read_(int size, int ram_check)
679af8a3 1142{
895d1512 1143 int arg1;
1144#if 0
1145 int arg0;
b081408f 1146 host_arg2reg(arg0, 0);
895d1512 1147#endif
b081408f 1148
23686515 1149 rcache_clean();
1150
b081408f 1151 // must writeback cycles for poll detection stuff
23686515 1152 // FIXME: rm
b081408f 1153 if (reg_map_g2h[SHR_SR] != -1)
1154 emith_ctx_write(reg_map_g2h[SHR_SR], SHR_SR * 4);
23686515 1155
b081408f 1156 arg1 = rcache_get_tmp_arg(1);
1157 emith_move_r_r(arg1, CONTEXT_REG);
1158
fa841b44 1159#if 0 // can't do this because of unmapped reads
1160 // ndef PDB_NET
23686515 1161 if (ram_check && Pico.rom == (void *)0x02000000 && Pico32xMem->sdram == (void *)0x06000000) {
b081408f 1162 int tmp = rcache_get_tmp();
1163 emith_and_r_r_imm(tmp, arg0, 0xfb000000);
1164 emith_cmp_r_imm(tmp, 0x02000000);
1165 switch (size) {
1166 case 0: // 8
1167 EMITH_SJMP3_START(DCOND_NE);
1168 emith_eor_r_imm_c(DCOND_EQ, arg0, 1);
1169 emith_read8_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
1170 EMITH_SJMP3_MID(DCOND_NE);
5686d931 1171 emith_call_cond(DCOND_NE, sh2_drc_read8);
b081408f 1172 EMITH_SJMP3_END();
1173 break;
1174 case 1: // 16
1175 EMITH_SJMP3_START(DCOND_NE);
1176 emith_read16_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
1177 EMITH_SJMP3_MID(DCOND_NE);
5686d931 1178 emith_call_cond(DCOND_NE, sh2_drc_read16);
b081408f 1179 EMITH_SJMP3_END();
1180 break;
1181 case 2: // 32
1182 EMITH_SJMP3_START(DCOND_NE);
1183 emith_read_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
1184 emith_ror_c(DCOND_EQ, arg0, arg0, 16);
1185 EMITH_SJMP3_MID(DCOND_NE);
5686d931 1186 emith_call_cond(DCOND_NE, sh2_drc_read32);
b081408f 1187 EMITH_SJMP3_END();
1188 break;
1189 }
1190 }
1191 else
1192#endif
1193 {
1194 switch (size) {
1195 case 0: // 8
5686d931 1196 emith_call(sh2_drc_read8);
b081408f 1197 break;
1198 case 1: // 16
5686d931 1199 emith_call(sh2_drc_read16);
b081408f 1200 break;
1201 case 2: // 32
5686d931 1202 emith_call(sh2_drc_read32);
b081408f 1203 break;
1204 }
679af8a3 1205 }
80599a42 1206 rcache_invalidate();
97e95a29 1207
1208 if (reg_map_g2h[SHR_SR] != -1)
1209 emith_ctx_read(reg_map_g2h[SHR_SR], SHR_SR * 4);
1210
80599a42 1211 // assuming arg0 and retval reg matches
1212 return rcache_get_tmp_arg(0);
1213}
679af8a3 1214
23686515 1215static int emit_memhandler_read(int size)
1216{
1217 return emit_memhandler_read_(size, 1);
1218}
1219
1220static int emit_memhandler_read_rr(sh2_reg_e rd, sh2_reg_e rs, u32 offs, int size)
1221{
1222 int hr, hr2, ram_check = 1;
1223 u32 val, offs2;
1224
1225 if (gconst_get(rs, &val)) {
1226 hr = emit_get_rbase_and_offs(val + offs, &offs2);
1227 if (hr != -1) {
1228 hr2 = rcache_get_reg(rd, RC_GR_WRITE);
1229 switch (size) {
1230 case 0: // 8
1231 emith_read8_r_r_offs(hr2, hr, offs2 ^ 1);
1232 emith_sext(hr2, hr2, 8);
1233 break;
1234 case 1: // 16
1235 emith_read16_r_r_offs(hr2, hr, offs2);
1236 emith_sext(hr2, hr2, 16);
1237 break;
1238 case 2: // 32
1239 emith_read_r_r_offs(hr2, hr, offs2);
1240 emith_ror(hr2, hr2, 16);
1241 break;
1242 }
1243 rcache_free_tmp(hr);
1244 return hr2;
1245 }
1246
1247 ram_check = 0;
1248 }
1249
1250 hr = rcache_get_reg_arg(0, rs);
1251 if (offs != 0)
1252 emith_add_r_imm(hr, offs);
1253 hr = emit_memhandler_read_(size, ram_check);
1254 hr2 = rcache_get_reg(rd, RC_GR_WRITE);
1255 if (size != 2) {
1256 emith_sext(hr2, hr, (size == 1) ? 16 : 8);
1257 } else
1258 emith_move_r_r(hr2, hr);
1259 rcache_free_tmp(hr);
1260
1261 return hr2;
1262}
1263
001f73a0 1264static void emit_memhandler_write(int size)
80599a42 1265{
1266 int ctxr;
1267 host_arg2reg(ctxr, 2);
97e95a29 1268 if (reg_map_g2h[SHR_SR] != -1)
1269 emith_ctx_write(reg_map_g2h[SHR_SR], SHR_SR * 4);
1270
6976a547 1271 rcache_clean();
1272
80599a42 1273 switch (size) {
1274 case 0: // 8
e05b81fc 1275 // XXX: consider inlining sh2_drc_write8
d056bef8 1276 emith_call(sh2_drc_write8);
80599a42 1277 break;
1278 case 1: // 16
d056bef8 1279 emith_call(sh2_drc_write16);
80599a42 1280 break;
1281 case 2: // 32
e05b81fc 1282 emith_move_r_r(ctxr, CONTEXT_REG);
5686d931 1283 emith_call(sh2_drc_write32);
80599a42 1284 break;
1285 }
97e95a29 1286
d056bef8 1287 rcache_invalidate();
97e95a29 1288 if (reg_map_g2h[SHR_SR] != -1)
1289 emith_ctx_read(reg_map_g2h[SHR_SR], SHR_SR * 4);
679af8a3 1290}
80599a42 1291
52d759c3 1292// @(Rx,Ry)
1293static int emit_indirect_indexed_read(int rx, int ry, int size)
1294{
1295 int a0, t;
52d759c3 1296 a0 = rcache_get_reg_arg(0, rx);
1297 t = rcache_get_reg(ry, RC_GR_READ);
1298 emith_add_r_r(a0, t);
1299 return emit_memhandler_read(size);
1300}
1301
f0d7b1fa 1302// read @Rn, @rm
1303static void emit_indirect_read_double(u32 *rnr, u32 *rmr, int rn, int rm, int size)
1304{
1305 int tmp;
1306
f0d7b1fa 1307 rcache_get_reg_arg(0, rn);
1308 tmp = emit_memhandler_read(size);
1309 emith_ctx_write(tmp, offsetof(SH2, drc_tmp));
1310 rcache_free_tmp(tmp);
1311 tmp = rcache_get_reg(rn, RC_GR_RMW);
1312 emith_add_r_imm(tmp, 1 << size);
23686515 1313 rcache_unlock(tmp);
f0d7b1fa 1314
f0d7b1fa 1315 rcache_get_reg_arg(0, rm);
1316 *rmr = emit_memhandler_read(size);
1317 *rnr = rcache_get_tmp();
1318 emith_ctx_read(*rnr, offsetof(SH2, drc_tmp));
1319 tmp = rcache_get_reg(rm, RC_GR_RMW);
1320 emith_add_r_imm(tmp, 1 << size);
23686515 1321 rcache_unlock(tmp);
f0d7b1fa 1322}
1323
8796b7ee 1324static void emit_do_static_regs(int is_write, int tmpr)
f0d7b1fa 1325{
8796b7ee 1326 int i, r, count;
1327
1328 for (i = 0; i < ARRAY_SIZE(reg_map_g2h); i++) {
1329 r = reg_map_g2h[i];
1330 if (r == -1)
1331 continue;
1332
1333 for (count = 1; i < ARRAY_SIZE(reg_map_g2h) - 1; i++, r++) {
1334 if (reg_map_g2h[i + 1] != r + 1)
1335 break;
1336 count++;
1337 }
1338
1339 if (count > 1) {
1340 // i, r point to last item
1341 if (is_write)
1342 emith_ctx_write_multiple(r - count + 1, (i - count + 1) * 4, count, tmpr);
1343 else
1344 emith_ctx_read_multiple(r - count + 1, (i - count + 1) * 4, count, tmpr);
1345 } else {
1346 if (is_write)
1347 emith_ctx_write(r, i * 4);
1348 else
1349 emith_ctx_read(r, i * 4);
1350 }
f0d7b1fa 1351 }
1352}
1353
e05b81fc 1354static void emit_block_entry(void)
f0d7b1fa 1355{
c25d78ee 1356 int arg0;
8796b7ee 1357
e05b81fc 1358 host_arg2reg(arg0, 0);
c25d78ee 1359
1360#if (DRC_DEBUG & 8) || defined(PDB)
1361 int arg1, arg2;
e05b81fc 1362 host_arg2reg(arg1, 1);
1363 host_arg2reg(arg2, 2);
8796b7ee 1364
5686d931 1365 emit_do_static_regs(1, arg2);
e05b81fc 1366 emith_move_r_r(arg1, CONTEXT_REG);
1367 emith_move_r_r(arg2, rcache_get_reg(SHR_SR, RC_GR_READ));
5686d931 1368 emith_call(sh2_drc_log_entry);
e05b81fc 1369 rcache_invalidate();
1370#endif
1371 emith_tst_r_r(arg0, arg0);
1372 EMITH_SJMP_START(DCOND_EQ);
1373 emith_jump_reg_c(DCOND_NE, arg0);
1374 EMITH_SJMP_END(DCOND_EQ);
1375}
8796b7ee 1376
18b94127 1377#define DELAY_SAVE_T(sr) { \
1378 emith_bic_r_imm(sr, T_save); \
1379 emith_tst_r_imm(sr, T); \
1380 EMITH_SJMP_START(DCOND_EQ); \
1381 emith_or_r_imm_c(DCOND_NE, sr, T_save); \
1382 EMITH_SJMP_END(DCOND_EQ); \
18b94127 1383}
e898de13 1384
e05b81fc 1385#define FLUSH_CYCLES(sr) \
1386 if (cycles > 0) { \
1387 emith_sub_r_imm(sr, cycles << 12); \
1388 cycles = 0; \
1389 }
1390
00faec9c 1391static void *dr_get_pc_base(u32 pc, int is_slave);
18b94127 1392
e05b81fc 1393static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
679af8a3 1394{
18b94127 1395 u32 branch_target_pc[MAX_LOCAL_BRANCHES];
a2b8c5a5 1396 void *branch_target_ptr[MAX_LOCAL_BRANCHES];
18b94127 1397 int branch_target_count = 0;
1398 void *branch_patch_ptr[MAX_LOCAL_BRANCHES];
1399 u32 branch_patch_pc[MAX_LOCAL_BRANCHES];
1400 int branch_patch_count = 0;
04092e32 1401 u32 literal_addr[MAX_LITERALS];
1402 int literal_addr_count = 0;
e1553677 1403 u8 op_flags[BLOCK_INSN_LIMIT];
18b94127 1404 struct {
18b94127 1405 u32 test_irq:1;
bf092a36 1406 u32 pending_branch_direct:1;
1407 u32 pending_branch_indirect:1;
51d86e55 1408 u32 literals_disabled:1;
18b94127 1409 } drcf = { 0, };
1410
bf092a36 1411 // PC of current, first, last SH2 insn
1412 u32 pc, base_pc, end_pc;
1413 u32 end_literals;
228ee974 1414 void *block_entry_ptr;
1415 struct block_desc *block;
23686515 1416 u16 *dr_pc_base;
bf092a36 1417 struct op_data *opd;
18b94127 1418 int blkid_main = 0;
23686515 1419 int skip_op = 0;
18b94127 1420 u32 tmp, tmp2;
1421 int cycles;
228ee974 1422 int i, v;
18b94127 1423 int op;
18b94127 1424
1425 base_pc = sh2->pc;
51d86e55 1426 drcf.literals_disabled = literal_disabled_frames != 0;
679af8a3 1427
23686515 1428 // get base/validate PC
1429 dr_pc_base = dr_get_pc_base(base_pc, sh2->is_slave);
1430 if (dr_pc_base == (void *)-1) {
18b94127 1431 printf("invalid PC, aborting: %08x\n", base_pc);
f4bb5d6b 1432 // FIXME: be less destructive
1433 exit(1);
1434 }
1435
f4bb5d6b 1436 tcache_ptr = tcache_ptrs[tcache_id];
f4bb5d6b 1437
18b94127 1438 // predict tcache overflow
f4bb5d6b 1439 tmp = tcache_ptr - tcache_bases[tcache_id];
44e6452e 1440 if (tmp > tcache_sizes[tcache_id] - MAX_BLOCK_SIZE) {
fcdefcf6 1441 dbg(1, "tcache %d overflow", tcache_id);
18b94127 1442 return NULL;
44e6452e 1443 }
18b94127 1444
bf092a36 1445 // initial passes to disassemble and analyze the block
1446 scan_block(base_pc, sh2->is_slave, op_flags, &end_pc, &end_literals);
569420b0 1447
51d86e55 1448 if (drcf.literals_disabled)
1449 end_literals = end_pc;
1450
1451 block = dr_add_block(base_pc, end_literals - base_pc,
1452 end_pc - base_pc, sh2->is_slave, &blkid_main);
228ee974 1453 if (block == NULL)
569420b0 1454 return NULL;
1455
228ee974 1456 block_entry_ptr = tcache_ptr;
4943816b 1457 dbg(2, "== %csh2 block #%d,%d %08x-%08x -> %p", sh2->is_slave ? 's' : 'm',
228ee974 1458 tcache_id, blkid_main, base_pc, end_pc, block_entry_ptr);
18b94127 1459
00a725a8 1460 dr_link_blocks(&block->entryp[0], tcache_id);
44e6452e 1461
00faec9c 1462 // collect branch_targets that don't land on delay slots
bf092a36 1463 for (pc = base_pc, i = 0; pc < end_pc; i++, pc += 2) {
1464 if (!(op_flags[i] & OF_BTARGET))
00faec9c 1465 continue;
bf092a36 1466 if (op_flags[i] & OF_DELAY_OP) {
1467 op_flags[i] &= ~OF_BTARGET;
18b94127 1468 continue;
1469 }
00faec9c 1470 ADD_TO_ARRAY(branch_target_pc, branch_target_count, pc, break);
e898de13 1471 }
c25d78ee 1472
c25d78ee 1473 if (branch_target_count > 0) {
1474 memset(branch_target_ptr, 0, sizeof(branch_target_ptr[0]) * branch_target_count);
c25d78ee 1475 }
679af8a3 1476
6976a547 1477 // clear stale state after compile errors
1478 rcache_invalidate();
1479
18b94127 1480 // -------------------------------------------------
bf092a36 1481 // 3rd pass: actual compilation
18b94127 1482 pc = base_pc;
bf092a36 1483 cycles = 0;
1484 for (i = 0; pc < end_pc; i++)
679af8a3 1485 {
bf092a36 1486 u32 delay_dep_fw = 0, delay_dep_bk = 0;
18b94127 1487 u32 tmp3, tmp4, sr;
1488
bf092a36 1489 opd = &ops[i];
23686515 1490 op = FETCH_OP(pc);
1491
bf092a36 1492#if (DRC_DEBUG & 2)
1493 insns_compiled++;
1494#endif
1495#if (DRC_DEBUG & 4)
1496 DasmSH2(sh2dasm_buff, pc, op);
1497 printf("%c%08x %04x %s\n", (op_flags[i] & OF_BTARGET) ? '*' : ' ',
1498 pc, op, sh2dasm_buff);
1499#endif
1500
1501 if ((op_flags[i] & OF_BTARGET) || pc == base_pc)
18b94127 1502 {
a2b8c5a5 1503 if (pc != base_pc)
18b94127 1504 {
18b94127 1505 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
e05b81fc 1506 FLUSH_CYCLES(sr);
bf092a36 1507 rcache_flush();
18b94127 1508
bf092a36 1509 // make block entry
228ee974 1510 v = block->entry_count;
f0ed9e38 1511 if (v < ARRAY_SIZE(block->entryp))
1512 {
1513 struct block_entry *be_old;
1514
228ee974 1515 block->entryp[v].pc = pc;
1516 block->entryp[v].tcache_ptr = tcache_ptr;
00a725a8 1517 block->entryp[v].links = NULL;
228ee974 1518#if (DRC_DEBUG & 2)
1519 block->entryp[v].block = block;
1520#endif
f0ed9e38 1521 be_old = dr_get_entry(pc, sh2->is_slave, &tcache_id);
1522 if (be_old != NULL) {
1523 dbg(1, "entry override for %08x, was %p", pc, be_old->tcache_ptr);
1524 kill_block_entry(be_old, tcache_id);
1525 }
1526
228ee974 1527 add_to_hashlist(&block->entryp[v], tcache_id);
1528 block->entry_count++;
04092e32 1529
bf092a36 1530 dbg(2, "-- %csh2 block #%d,%d entry %08x -> %p",
1531 sh2->is_slave ? 's' : 'm', tcache_id, blkid_main,
1532 pc, tcache_ptr);
18b94127 1533
00a725a8 1534 // since we made a block entry, link any other blocks
1535 // that jump to current pc
1536 dr_link_blocks(&block->entryp[v], tcache_id);
228ee974 1537 }
1538 else {
1539 dbg(1, "too many entryp for block #%d,%d pc=%08x",
1540 tcache_id, blkid_main, pc);
1541 }
bf092a36 1542
1543 do_host_disasm(tcache_id);
18b94127 1544 }
bf092a36 1545
1546 v = find_in_array(branch_target_pc, branch_target_count, pc);
1547 if (v >= 0)
1548 branch_target_ptr[v] = tcache_ptr;
18b94127 1549
1550 // must update PC
1551 emit_move_r_imm32(SHR_PC, pc);
1552 rcache_clean();
1553
d602fd4f 1554#if (DRC_DEBUG & 0x10)
1555 rcache_get_reg_arg(0, SHR_PC);
1556 tmp = emit_memhandler_read(2);
1557 tmp2 = rcache_get_tmp();
1558 tmp3 = rcache_get_tmp();
1559 emith_move_r_imm(tmp2, FETCH32(pc));
1560 emith_move_r_imm(tmp3, 0);
1561 emith_cmp_r_r(tmp, tmp2);
1562 EMITH_SJMP_START(DCOND_EQ);
1563 emith_read_r_r_offs_c(DCOND_NE, tmp3, tmp3, 0); // crash
1564 EMITH_SJMP_END(DCOND_EQ);
1565 rcache_free_tmp(tmp);
1566 rcache_free_tmp(tmp2);
1567 rcache_free_tmp(tmp3);
1568#endif
1569
18b94127 1570 // check cycles
1571 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
1572 emith_cmp_r_imm(sr, 0);
1573 emith_jump_cond(DCOND_LE, sh2_drc_exit);
23686515 1574 do_host_disasm(tcache_id);
04092e32 1575 rcache_unlock_all();
18b94127 1576 }
e898de13 1577
00faec9c 1578#ifdef DRC_CMP
bf092a36 1579 if (!(op_flags[i] & OF_DELAY_OP)) {
00faec9c 1580 emit_move_r_imm32(SHR_PC, pc);
1581 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1582 FLUSH_CYCLES(sr);
6d797957 1583 rcache_clean();
1584
1585 tmp = rcache_used_hreg_mask();
1586 emith_save_caller_regs(tmp);
00faec9c 1587 emit_do_static_regs(1, 0);
1588 emith_pass_arg_r(0, CONTEXT_REG);
1589 emith_call(do_sh2_cmp);
6d797957 1590 emith_restore_caller_regs(tmp);
00faec9c 1591 }
679af8a3 1592#endif
679af8a3 1593
1594 pc += 2;
679af8a3 1595
23686515 1596 if (skip_op > 0) {
1597 skip_op--;
1598 continue;
1599 }
1600
bf092a36 1601 if (op_flags[i] & OF_DELAY_OP)
1602 {
1603 // handle delay slot dependencies
1604 delay_dep_fw = opd->dest & ops[i-1].source;
1605 delay_dep_bk = opd->source & ops[i-1].dest;
1606 if (delay_dep_fw & BITMASK1(SHR_T)) {
1607 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1608 DELAY_SAVE_T(sr);
1609 }
fa841b44 1610 if (delay_dep_bk & BITMASK1(SHR_PC)) {
1611 if (opd->op != OP_LOAD_POOL && opd->op != OP_MOVA) {
1612 // can only be those 2 really..
f8675e28 1613 elprintf_sh2(sh2, EL_ANOMALY,
1614 "drc: illegal slot insn %04x @ %08x?", op, pc - 2);
fa841b44 1615 }
1616 if (opd->imm != 0)
1617 ; // addr already resolved somehow
1618 else {
1619 switch (ops[i-1].op) {
1620 case OP_BRANCH:
1621 emit_move_r_imm32(SHR_PC, ops[i-1].imm);
1622 break;
1623 case OP_BRANCH_CT:
1624 case OP_BRANCH_CF:
1625 tmp = rcache_get_reg(SHR_PC, RC_GR_WRITE);
1626 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
1627 emith_move_r_imm(tmp, pc);
1628 emith_tst_r_imm(sr, T);
1629 tmp2 = ops[i-1].op == OP_BRANCH_CT ? DCOND_NE : DCOND_EQ;
1630 emith_move_r_imm_c(tmp2, tmp, ops[i-1].imm);
1631 break;
1632 // case OP_BRANCH_R OP_BRANCH_RF - PC already loaded
1633 }
1634 }
1635 }
1636 //if (delay_dep_fw & ~BITMASK1(SHR_T))
1637 // dbg(1, "unhandled delay_dep_fw: %x", delay_dep_fw & ~BITMASK1(SHR_T));
1638 if (delay_dep_bk & ~BITMASK2(SHR_PC, SHR_PR))
bf092a36 1639 dbg(1, "unhandled delay_dep_bk: %x", delay_dep_bk);
1640 }
1641
1642 switch (opd->op)
1643 {
1644 case OP_BRANCH:
1645 case OP_BRANCH_CT:
1646 case OP_BRANCH_CF:
1647 if (opd->dest & BITMASK1(SHR_PR))
1648 emit_move_r_imm32(SHR_PR, pc + 2);
1649 drcf.pending_branch_direct = 1;
1650 goto end_op;
1651
1652 case OP_BRANCH_R:
1653 if (opd->dest & BITMASK1(SHR_PR))
1654 emit_move_r_imm32(SHR_PR, pc + 2);
1655 emit_move_r_r(SHR_PC, opd->rm);
1656 drcf.pending_branch_indirect = 1;
1657 goto end_op;
1658
1659 case OP_BRANCH_RF:
1660 tmp = rcache_get_reg(SHR_PC, RC_GR_WRITE);
1661 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1662 if (opd->dest & BITMASK1(SHR_PR)) {
1663 tmp3 = rcache_get_reg(SHR_PR, RC_GR_WRITE);
1664 emith_move_r_imm(tmp3, pc + 2);
1665 emith_add_r_r_r(tmp, tmp2, tmp3);
1666 }
1667 else {
1668 emith_move_r_r(tmp, tmp2);
1669 emith_add_r_imm(tmp, pc + 2);
1670 }
1671 drcf.pending_branch_indirect = 1;
1672 goto end_op;
1673
1674 case OP_SLEEP:
1675 printf("TODO sleep\n");
1676 goto end_op;
1677
1678 case OP_RTE:
1679 // pop PC
1680 emit_memhandler_read_rr(SHR_PC, SHR_SP, 0, 2);
1681 // pop SR
1682 tmp = rcache_get_reg_arg(0, SHR_SP);
1683 emith_add_r_imm(tmp, 4);
1684 tmp = emit_memhandler_read(2);
1685 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1686 emith_write_sr(sr, tmp);
1687 rcache_free_tmp(tmp);
1688 tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
1689 emith_add_r_imm(tmp, 4*2);
1690 drcf.test_irq = 1;
1691 drcf.pending_branch_indirect = 1;
fa841b44 1692 goto end_op;
1693
1694 case OP_LOAD_POOL:
1695#if PROPAGATE_CONSTANTS
51d86e55 1696 if (opd->imm != 0 && opd->imm < end_literals
fa841b44 1697 && literal_addr_count < MAX_LITERALS)
1698 {
1699 ADD_TO_ARRAY(literal_addr, literal_addr_count, opd->imm,);
1700 if (opd->size == 2)
1701 tmp = FETCH32(opd->imm);
1702 else
1703 tmp = (u32)(int)(signed short)FETCH_OP(opd->imm);
1704 gconst_new(GET_Rn(), tmp);
1705 }
1706 else
1707#endif
1708 {
1709 tmp = rcache_get_tmp_arg(0);
1710 if (opd->imm != 0)
1711 emith_move_r_imm(tmp, opd->imm);
1712 else {
1713 // have to calculate read addr from PC
1714 tmp2 = rcache_get_reg(SHR_PC, RC_GR_READ);
1715 if (opd->size == 2) {
1716 emith_add_r_r_imm(tmp, tmp2, 2 + (op & 0xff) * 4);
1717 emith_bic_r_imm(tmp, 3);
1718 }
1719 else
1720 emith_add_r_r_imm(tmp, tmp2, 2 + (op & 0xff) * 2);
1721 }
1722 tmp2 = emit_memhandler_read(opd->size);
1723 tmp3 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1724 if (opd->size == 2)
1725 emith_move_r_r(tmp3, tmp2);
1726 else
1727 emith_sext(tmp3, tmp2, 16);
1728 rcache_free_tmp(tmp2);
1729 }
1730 goto end_op;
1731
1732 case OP_MOVA:
1733 if (opd->imm != 0)
1734 emit_move_r_imm32(SHR_R0, opd->imm);
1735 else {
1736 tmp = rcache_get_reg(SHR_R0, RC_GR_WRITE);
1737 tmp2 = rcache_get_reg(SHR_PC, RC_GR_READ);
1738 emith_add_r_r_imm(tmp, tmp2, 2 + (op & 0xff) * 4);
1739 emith_bic_r_imm(tmp, 3);
1740 }
1741 goto end_op;
bf092a36 1742 }
1743
679af8a3 1744 switch ((op >> 12) & 0x0f)
1745 {
3863edbd 1746 /////////////////////////////////////////////
679af8a3 1747 case 0x00:
80599a42 1748 switch (op & 0x0f)
1749 {
1750 case 0x02:
1751 tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1752 switch (GET_Fx())
1753 {
1754 case 0: // STC SR,Rn 0000nnnn00000010
1755 tmp2 = SHR_SR;
1756 break;
1757 case 1: // STC GBR,Rn 0000nnnn00010010
1758 tmp2 = SHR_GBR;
1759 break;
1760 case 2: // STC VBR,Rn 0000nnnn00100010
1761 tmp2 = SHR_VBR;
1762 break;
1763 default:
1764 goto default_;
1765 }
ed8cf79b 1766 tmp3 = rcache_get_reg(tmp2, RC_GR_READ);
1767 emith_move_r_r(tmp, tmp3);
1768 if (tmp2 == SHR_SR)
18b94127 1769 emith_clear_msb(tmp, tmp, 22); // reserved bits defined by ISA as 0
80599a42 1770 goto end_op;
80599a42 1771 case 0x04: // MOV.B Rm,@(R0,Rn) 0000nnnnmmmm0100
1772 case 0x05: // MOV.W Rm,@(R0,Rn) 0000nnnnmmmm0101
1773 case 0x06: // MOV.L Rm,@(R0,Rn) 0000nnnnmmmm0110
e05b81fc 1774 rcache_clean();
1775 tmp = rcache_get_reg_arg(1, GET_Rm());
1776 tmp2 = rcache_get_reg_arg(0, SHR_R0);
1777 tmp3 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1778 emith_add_r_r(tmp2, tmp3);
001f73a0 1779 emit_memhandler_write(op & 3);
80599a42 1780 goto end_op;
1781 case 0x07:
1782 // MUL.L Rm,Rn 0000nnnnmmmm0111
1783 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
1784 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1785 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
1786 emith_mul(tmp3, tmp2, tmp);
80599a42 1787 goto end_op;
1788 case 0x08:
80599a42 1789 switch (GET_Fx())
1790 {
1791 case 0: // CLRT 0000000000001000
8796b7ee 1792 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1793 emith_bic_r_imm(sr, T);
80599a42 1794 break;
1795 case 1: // SETT 0000000000011000
8796b7ee 1796 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1797 emith_or_r_imm(sr, T);
80599a42 1798 break;
1799 case 2: // CLRMAC 0000000000101000
23686515 1800 emit_move_r_imm32(SHR_MACL, 0);
1801 emit_move_r_imm32(SHR_MACH, 0);
80599a42 1802 break;
1803 default:
1804 goto default_;
1805 }
1806 goto end_op;
e898de13 1807 case 0x09:
80599a42 1808 switch (GET_Fx())
1809 {
1810 case 0: // NOP 0000000000001001
80599a42 1811 break;
1812 case 1: // DIV0U 0000000000011001
8796b7ee 1813 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1814 emith_bic_r_imm(sr, M|Q|T);
80599a42 1815 break;
1816 case 2: // MOVT Rn 0000nnnn00101001
8796b7ee 1817 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
80599a42 1818 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
8796b7ee 1819 emith_clear_msb(tmp2, sr, 31);
80599a42 1820 break;
1821 default:
1822 goto default_;
1823 }
1824 goto end_op;
1825 case 0x0a:
1826 tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1827 switch (GET_Fx())
1828 {
1829 case 0: // STS MACH,Rn 0000nnnn00001010
ed8cf79b 1830 tmp2 = SHR_MACH;
80599a42 1831 break;
1832 case 1: // STS MACL,Rn 0000nnnn00011010
ed8cf79b 1833 tmp2 = SHR_MACL;
80599a42 1834 break;
1835 case 2: // STS PR,Rn 0000nnnn00101010
ed8cf79b 1836 tmp2 = SHR_PR;
80599a42 1837 break;
1838 default:
1839 goto default_;
1840 }
ed8cf79b 1841 tmp2 = rcache_get_reg(tmp2, RC_GR_READ);
80599a42 1842 emith_move_r_r(tmp, tmp2);
e898de13 1843 goto end_op;
80599a42 1844 case 0x0c: // MOV.B @(R0,Rm),Rn 0000nnnnmmmm1100
1845 case 0x0d: // MOV.W @(R0,Rm),Rn 0000nnnnmmmm1101
1846 case 0x0e: // MOV.L @(R0,Rm),Rn 0000nnnnmmmm1110
52d759c3 1847 tmp = emit_indirect_indexed_read(SHR_R0, GET_Rm(), op & 3);
80599a42 1848 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
80599a42 1849 if ((op & 3) != 2) {
1850 emith_sext(tmp2, tmp, (op & 1) ? 16 : 8);
1851 } else
1852 emith_move_r_r(tmp2, tmp);
52d759c3 1853 rcache_free_tmp(tmp);
80599a42 1854 goto end_op;
1855 case 0x0f: // MAC.L @Rm+,@Rn+ 0000nnnnmmmm1111
f0d7b1fa 1856 emit_indirect_read_double(&tmp, &tmp2, GET_Rn(), GET_Rm(), 2);
f0d7b1fa 1857 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_RMW);
1858 /* MS 16 MAC bits unused if saturated */
23686515 1859 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
8796b7ee 1860 emith_tst_r_imm(sr, S);
f0d7b1fa 1861 EMITH_SJMP_START(DCOND_EQ);
1862 emith_clear_msb_c(DCOND_NE, tmp4, tmp4, 16);
1863 EMITH_SJMP_END(DCOND_EQ);
23686515 1864 rcache_unlock(sr);
f0d7b1fa 1865 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_RMW); // might evict SR
1866 emith_mula_s64(tmp3, tmp4, tmp, tmp2);
f0d7b1fa 1867 rcache_free_tmp(tmp2);
8796b7ee 1868 sr = rcache_get_reg(SHR_SR, RC_GR_READ); // reget just in case
1869 emith_tst_r_imm(sr, S);
1870
1871 EMITH_JMP_START(DCOND_EQ);
1872 emith_asr(tmp, tmp4, 15);
1873 emith_cmp_r_imm(tmp, -1); // negative overflow (0x80000000..0xffff7fff)
1874 EMITH_SJMP_START(DCOND_GE);
1875 emith_move_r_imm_c(DCOND_LT, tmp4, 0x8000);
1876 emith_move_r_imm_c(DCOND_LT, tmp3, 0x0000);
1877 EMITH_SJMP_END(DCOND_GE);
1878 emith_cmp_r_imm(tmp, 0); // positive overflow (0x00008000..0x7fffffff)
1879 EMITH_SJMP_START(DCOND_LE);
1880 emith_move_r_imm_c(DCOND_GT, tmp4, 0x00007fff);
1881 emith_move_r_imm_c(DCOND_GT, tmp3, 0xffffffff);
1882 EMITH_SJMP_END(DCOND_LE);
1883 EMITH_JMP_END(DCOND_EQ);
1884
1885 rcache_free_tmp(tmp);
f0d7b1fa 1886 goto end_op;
80599a42 1887 }
1888 goto default_;
1889
3863edbd 1890 /////////////////////////////////////////////
80599a42 1891 case 0x01:
1892 // MOV.L Rm,@(disp,Rn) 0001nnnnmmmmdddd
1893 rcache_clean();
1894 tmp = rcache_get_reg_arg(0, GET_Rn());
1895 tmp2 = rcache_get_reg_arg(1, GET_Rm());
23686515 1896 if (op & 0x0f)
1897 emith_add_r_imm(tmp, (op & 0x0f) * 4);
001f73a0 1898 emit_memhandler_write(2);
80599a42 1899 goto end_op;
1900
1901 case 0x02:
1902 switch (op & 0x0f)
1903 {
1904 case 0x00: // MOV.B Rm,@Rn 0010nnnnmmmm0000
1905 case 0x01: // MOV.W Rm,@Rn 0010nnnnmmmm0001
1906 case 0x02: // MOV.L Rm,@Rn 0010nnnnmmmm0010
1907 rcache_clean();
1908 rcache_get_reg_arg(0, GET_Rn());
1909 rcache_get_reg_arg(1, GET_Rm());
001f73a0 1910 emit_memhandler_write(op & 3);
80599a42 1911 goto end_op;
f2dde871 1912 case 0x04: // MOV.B Rm,@-Rn 0010nnnnmmmm0100
1913 case 0x05: // MOV.W Rm,@-Rn 0010nnnnmmmm0101
1914 case 0x06: // MOV.L Rm,@-Rn 0010nnnnmmmm0110
fa841b44 1915 rcache_get_reg_arg(1, GET_Rm()); // for Rm == Rn
80599a42 1916 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1917 emith_sub_r_imm(tmp, (1 << (op & 3)));
1918 rcache_clean();
1919 rcache_get_reg_arg(0, GET_Rn());
001f73a0 1920 emit_memhandler_write(op & 3);
80599a42 1921 goto end_op;
1922 case 0x07: // DIV0S Rm,Rn 0010nnnnmmmm0111
8796b7ee 1923 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
80599a42 1924 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1925 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
8796b7ee 1926 emith_bic_r_imm(sr, M|Q|T);
80599a42 1927 emith_tst_r_imm(tmp2, (1<<31));
1928 EMITH_SJMP_START(DCOND_EQ);
8796b7ee 1929 emith_or_r_imm_c(DCOND_NE, sr, Q);
80599a42 1930 EMITH_SJMP_END(DCOND_EQ);
1931 emith_tst_r_imm(tmp3, (1<<31));
1932 EMITH_SJMP_START(DCOND_EQ);
8796b7ee 1933 emith_or_r_imm_c(DCOND_NE, sr, M);
80599a42 1934 EMITH_SJMP_END(DCOND_EQ);
1935 emith_teq_r_r(tmp2, tmp3);
1936 EMITH_SJMP_START(DCOND_PL);
8796b7ee 1937 emith_or_r_imm_c(DCOND_MI, sr, T);
80599a42 1938 EMITH_SJMP_END(DCOND_PL);
1939 goto end_op;
3863edbd 1940 case 0x08: // TST Rm,Rn 0010nnnnmmmm1000
8796b7ee 1941 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
3863edbd 1942 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1943 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
8796b7ee 1944 emith_bic_r_imm(sr, T);
3863edbd 1945 emith_tst_r_r(tmp2, tmp3);
8796b7ee 1946 emit_or_t_if_eq(sr);
3863edbd 1947 goto end_op;
1948 case 0x09: // AND Rm,Rn 0010nnnnmmmm1001
1949 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1950 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1951 emith_and_r_r(tmp, tmp2);
1952 goto end_op;
1953 case 0x0a: // XOR Rm,Rn 0010nnnnmmmm1010
1954 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1955 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1956 emith_eor_r_r(tmp, tmp2);
1957 goto end_op;
1958 case 0x0b: // OR Rm,Rn 0010nnnnmmmm1011
1959 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1960 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1961 emith_or_r_r(tmp, tmp2);
1962 goto end_op;
1963 case 0x0c: // CMP/STR Rm,Rn 0010nnnnmmmm1100
1964 tmp = rcache_get_tmp();
1965 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1966 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1967 emith_eor_r_r_r(tmp, tmp2, tmp3);
8796b7ee 1968 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1969 emith_bic_r_imm(sr, T);
3863edbd 1970 emith_tst_r_imm(tmp, 0x000000ff);
fa841b44 1971 emit_or_t_if_eq(sr);
3863edbd 1972 emith_tst_r_imm(tmp, 0x0000ff00);
fa841b44 1973 emit_or_t_if_eq(sr);
3863edbd 1974 emith_tst_r_imm(tmp, 0x00ff0000);
fa841b44 1975 emit_or_t_if_eq(sr);
3863edbd 1976 emith_tst_r_imm(tmp, 0xff000000);
fa841b44 1977 emit_or_t_if_eq(sr);
3863edbd 1978 rcache_free_tmp(tmp);
1979 goto end_op;
1980 case 0x0d: // XTRCT Rm,Rn 0010nnnnmmmm1101
1981 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1982 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1983 emith_lsr(tmp, tmp, 16);
f0d7b1fa 1984 emith_or_r_r_lsl(tmp, tmp2, 16);
3863edbd 1985 goto end_op;
1986 case 0x0e: // MULU.W Rm,Rn 0010nnnnmmmm1110
1987 case 0x0f: // MULS.W Rm,Rn 0010nnnnmmmm1111
1988 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1989 tmp = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
1990 if (op & 1) {
1991 emith_sext(tmp, tmp2, 16);
1992 } else
1993 emith_clear_msb(tmp, tmp2, 16);
1994 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1995 tmp2 = rcache_get_tmp();
1996 if (op & 1) {
1997 emith_sext(tmp2, tmp3, 16);
1998 } else
1999 emith_clear_msb(tmp2, tmp3, 16);
2000 emith_mul(tmp, tmp, tmp2);
2001 rcache_free_tmp(tmp2);
3863edbd 2002 goto end_op;
679af8a3 2003 }
2004 goto default_;
2005
3863edbd 2006 /////////////////////////////////////////////
2007 case 0x03:
2008 switch (op & 0x0f)
2009 {
2010 case 0x00: // CMP/EQ Rm,Rn 0011nnnnmmmm0000
2011 case 0x02: // CMP/HS Rm,Rn 0011nnnnmmmm0010
2012 case 0x03: // CMP/GE Rm,Rn 0011nnnnmmmm0011
2013 case 0x06: // CMP/HI Rm,Rn 0011nnnnmmmm0110
2014 case 0x07: // CMP/GT Rm,Rn 0011nnnnmmmm0111
8796b7ee 2015 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
3863edbd 2016 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
2017 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
8796b7ee 2018 emith_bic_r_imm(sr, T);
3863edbd 2019 emith_cmp_r_r(tmp2, tmp3);
2020 switch (op & 0x07)
2021 {
2022 case 0x00: // CMP/EQ
8796b7ee 2023 emit_or_t_if_eq(sr);
3863edbd 2024 break;
2025 case 0x02: // CMP/HS
2026 EMITH_SJMP_START(DCOND_LO);
8796b7ee 2027 emith_or_r_imm_c(DCOND_HS, sr, T);
3863edbd 2028 EMITH_SJMP_END(DCOND_LO);
2029 break;
2030 case 0x03: // CMP/GE
2031 EMITH_SJMP_START(DCOND_LT);
8796b7ee 2032 emith_or_r_imm_c(DCOND_GE, sr, T);
3863edbd 2033 EMITH_SJMP_END(DCOND_LT);
2034 break;
2035 case 0x06: // CMP/HI
2036 EMITH_SJMP_START(DCOND_LS);
8796b7ee 2037 emith_or_r_imm_c(DCOND_HI, sr, T);
3863edbd 2038 EMITH_SJMP_END(DCOND_LS);
2039 break;
2040 case 0x07: // CMP/GT
2041 EMITH_SJMP_START(DCOND_LE);
8796b7ee 2042 emith_or_r_imm_c(DCOND_GT, sr, T);
3863edbd 2043 EMITH_SJMP_END(DCOND_LE);
2044 break;
2045 }
2046 goto end_op;
2047 case 0x04: // DIV1 Rm,Rn 0011nnnnmmmm0100
f0d7b1fa 2048 // Q1 = carry(Rn = (Rn << 1) | T)
2049 // if Q ^ M
2050 // Q2 = carry(Rn += Rm)
2051 // else
2052 // Q2 = carry(Rn -= Rm)
2053 // Q = M ^ Q1 ^ Q2
2054 // T = (Q == M) = !(Q ^ M) = !(Q1 ^ Q2)
2055 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2056 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
2057 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
8b4f38f4 2058 emith_tpop_carry(sr, 0);
f0d7b1fa 2059 emith_adcf_r_r(tmp2, tmp2);
8b4f38f4 2060 emith_tpush_carry(sr, 0); // keep Q1 in T for now
f0d7b1fa 2061 tmp4 = rcache_get_tmp();
2062 emith_and_r_r_imm(tmp4, sr, M);
2063 emith_eor_r_r_lsr(sr, tmp4, M_SHIFT - Q_SHIFT); // Q ^= M
2064 rcache_free_tmp(tmp4);
2065 // add or sub, invert T if carry to get Q1 ^ Q2
2066 // in: (Q ^ M) passed in Q, Q1 in T
2067 emith_sh2_div1_step(tmp2, tmp3, sr);
18b94127 2068 emith_bic_r_imm(sr, Q);
2069 emith_tst_r_imm(sr, M);
2070 EMITH_SJMP_START(DCOND_EQ);
2071 emith_or_r_imm_c(DCOND_NE, sr, Q); // Q = M
2072 EMITH_SJMP_END(DCOND_EQ);
2073 emith_tst_r_imm(sr, T);
2074 EMITH_SJMP_START(DCOND_EQ);
2075 emith_eor_r_imm_c(DCOND_NE, sr, Q); // Q = M ^ Q1 ^ Q2
2076 EMITH_SJMP_END(DCOND_EQ);
2077 emith_eor_r_imm(sr, T); // T = !(Q1 ^ Q2)
f0d7b1fa 2078 goto end_op;
3863edbd 2079 case 0x05: // DMULU.L Rm,Rn 0011nnnnmmmm0101
2080 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
2081 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
2082 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
2083 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
2084 emith_mul_u64(tmp3, tmp4, tmp, tmp2);
2085 goto end_op;
2086 case 0x08: // SUB Rm,Rn 0011nnnnmmmm1000
2087 case 0x0c: // ADD Rm,Rn 0011nnnnmmmm1100
2088 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2089 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
2090 if (op & 4) {
2091 emith_add_r_r(tmp, tmp2);
2092 } else
2093 emith_sub_r_r(tmp, tmp2);
2094 goto end_op;
2095 case 0x0a: // SUBC Rm,Rn 0011nnnnmmmm1010
2096 case 0x0e: // ADDC Rm,Rn 0011nnnnmmmm1110
2097 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2098 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
8796b7ee 2099 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
3863edbd 2100 if (op & 4) { // adc
8b4f38f4 2101 emith_tpop_carry(sr, 0);
3863edbd 2102 emith_adcf_r_r(tmp, tmp2);
8b4f38f4 2103 emith_tpush_carry(sr, 0);
3863edbd 2104 } else {
8b4f38f4 2105 emith_tpop_carry(sr, 1);
3863edbd 2106 emith_sbcf_r_r(tmp, tmp2);
8b4f38f4 2107 emith_tpush_carry(sr, 1);
3863edbd 2108 }
3863edbd 2109 goto end_op;
2110 case 0x0b: // SUBV Rm,Rn 0011nnnnmmmm1011
2111 case 0x0f: // ADDV Rm,Rn 0011nnnnmmmm1111
2112 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2113 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
8796b7ee 2114 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2115 emith_bic_r_imm(sr, T);
3863edbd 2116 if (op & 4) {
2117 emith_addf_r_r(tmp, tmp2);
2118 } else
2119 emith_subf_r_r(tmp, tmp2);
2120 EMITH_SJMP_START(DCOND_VC);
8796b7ee 2121 emith_or_r_imm_c(DCOND_VS, sr, T);
3863edbd 2122 EMITH_SJMP_END(DCOND_VC);
2123 goto end_op;
2124 case 0x0d: // DMULS.L Rm,Rn 0011nnnnmmmm1101
2125 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
2126 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
2127 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
2128 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
2129 emith_mul_s64(tmp3, tmp4, tmp, tmp2);
2130 goto end_op;
2131 }
2132 goto default_;
2133
2134 /////////////////////////////////////////////
679af8a3 2135 case 0x04:
3863edbd 2136 switch (op & 0x0f)
2137 {
c18edb34 2138 case 0x00:
3863edbd 2139 switch (GET_Fx())
2140 {
2141 case 0: // SHLL Rn 0100nnnn00000000
2142 case 2: // SHAL Rn 0100nnnn00100000
8796b7ee 2143 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2144 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
8b4f38f4 2145 emith_tpop_carry(sr, 0); // dummy
3863edbd 2146 emith_lslf(tmp, tmp, 1);
8b4f38f4 2147 emith_tpush_carry(sr, 0);
3863edbd 2148 goto end_op;
2149 case 1: // DT Rn 0100nnnn00010000
8796b7ee 2150 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
fa841b44 2151#if 0 // scheduling needs tuning
23686515 2152 if (FETCH_OP(pc) == 0x8bfd) { // BF #-2
2153 if (gconst_get(GET_Rn(), &tmp)) {
2154 // XXX: limit burned cycles
2155 emit_move_r_imm32(GET_Rn(), 0);
2156 emith_or_r_imm(sr, T);
a2b8c5a5 2157 cycles += tmp * 4 + 1; // +1 syncs with noconst version, not sure why
23686515 2158 skip_op = 1;
2159 }
2160 else
2161 emith_sh2_dtbf_loop();
2162 goto end_op;
2163 }
00faec9c 2164#endif
23686515 2165 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
8796b7ee 2166 emith_bic_r_imm(sr, T);
3863edbd 2167 emith_subf_r_imm(tmp, 1);
8796b7ee 2168 emit_or_t_if_eq(sr);
80599a42 2169 goto end_op;
2170 }
3863edbd 2171 goto default_;
ed8cf79b 2172 case 0x01:
2173 switch (GET_Fx())
2174 {
2175 case 0: // SHLR Rn 0100nnnn00000001
2176 case 2: // SHAR Rn 0100nnnn00100001
8796b7ee 2177 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2178 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
8b4f38f4 2179 emith_tpop_carry(sr, 0); // dummy
ed8cf79b 2180 if (op & 0x20) {
2181 emith_asrf(tmp, tmp, 1);
2182 } else
2183 emith_lsrf(tmp, tmp, 1);
8b4f38f4 2184 emith_tpush_carry(sr, 0);
ed8cf79b 2185 goto end_op;
2186 case 1: // CMP/PZ Rn 0100nnnn00010001
bf092a36 2187 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
8796b7ee 2188 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2189 emith_bic_r_imm(sr, T);
ed8cf79b 2190 emith_cmp_r_imm(tmp, 0);
2191 EMITH_SJMP_START(DCOND_LT);
8796b7ee 2192 emith_or_r_imm_c(DCOND_GE, sr, T);
ed8cf79b 2193 EMITH_SJMP_END(DCOND_LT);
2194 goto end_op;
2195 }
2196 goto default_;
2197 case 0x02:
2198 case 0x03:
2199 switch (op & 0x3f)
2200 {
f2dde871 2201 case 0x02: // STS.L MACH,@-Rn 0100nnnn00000010
ed8cf79b 2202 tmp = SHR_MACH;
2203 break;
f2dde871 2204 case 0x12: // STS.L MACL,@-Rn 0100nnnn00010010
ed8cf79b 2205 tmp = SHR_MACL;
2206 break;
f2dde871 2207 case 0x22: // STS.L PR,@-Rn 0100nnnn00100010
ed8cf79b 2208 tmp = SHR_PR;
2209 break;
f2dde871 2210 case 0x03: // STC.L SR,@-Rn 0100nnnn00000011
ed8cf79b 2211 tmp = SHR_SR;
2212 break;
f2dde871 2213 case 0x13: // STC.L GBR,@-Rn 0100nnnn00010011
ed8cf79b 2214 tmp = SHR_GBR;
2215 break;
f2dde871 2216 case 0x23: // STC.L VBR,@-Rn 0100nnnn00100011
ed8cf79b 2217 tmp = SHR_VBR;
2218 break;
2219 default:
e898de13 2220 goto default_;
ed8cf79b 2221 }
2222 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2223 emith_sub_r_imm(tmp2, 4);
2224 rcache_clean();
2225 rcache_get_reg_arg(0, GET_Rn());
2226 tmp3 = rcache_get_reg_arg(1, tmp);
2227 if (tmp == SHR_SR)
e05b81fc 2228 emith_clear_msb(tmp3, tmp3, 22); // reserved bits defined by ISA as 0
001f73a0 2229 emit_memhandler_write(2);
ed8cf79b 2230 goto end_op;
2231 case 0x04:
2232 case 0x05:
2233 switch (op & 0x3f)
2234 {
2235 case 0x04: // ROTL Rn 0100nnnn00000100
2236 case 0x05: // ROTR Rn 0100nnnn00000101
8796b7ee 2237 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2238 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
8b4f38f4 2239 emith_tpop_carry(sr, 0); // dummy
ed8cf79b 2240 if (op & 1) {
2241 emith_rorf(tmp, tmp, 1);
2242 } else
2243 emith_rolf(tmp, tmp, 1);
8b4f38f4 2244 emith_tpush_carry(sr, 0);
ed8cf79b 2245 goto end_op;
2246 case 0x24: // ROTCL Rn 0100nnnn00100100
2247 case 0x25: // ROTCR Rn 0100nnnn00100101
8796b7ee 2248 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2249 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
8b4f38f4 2250 emith_tpop_carry(sr, 0);
ed8cf79b 2251 if (op & 1) {
2252 emith_rorcf(tmp);
2253 } else
2254 emith_rolcf(tmp);
8b4f38f4 2255 emith_tpush_carry(sr, 0);
ed8cf79b 2256 goto end_op;
2257 case 0x15: // CMP/PL Rn 0100nnnn00010101
8796b7ee 2258 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2259 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2260 emith_bic_r_imm(sr, T);
ed8cf79b 2261 emith_cmp_r_imm(tmp, 0);
2262 EMITH_SJMP_START(DCOND_LE);
8796b7ee 2263 emith_or_r_imm_c(DCOND_GT, sr, T);
ed8cf79b 2264 EMITH_SJMP_END(DCOND_LE);
2265 goto end_op;
2266 }
e898de13 2267 goto default_;
ed8cf79b 2268 case 0x06:
2269 case 0x07:
2270 switch (op & 0x3f)
2271 {
2272 case 0x06: // LDS.L @Rm+,MACH 0100mmmm00000110
2273 tmp = SHR_MACH;
2274 break;
2275 case 0x16: // LDS.L @Rm+,MACL 0100mmmm00010110
2276 tmp = SHR_MACL;
2277 break;
2278 case 0x26: // LDS.L @Rm+,PR 0100mmmm00100110
2279 tmp = SHR_PR;
2280 break;
2281 case 0x07: // LDC.L @Rm+,SR 0100mmmm00000111
2282 tmp = SHR_SR;
2283 break;
2284 case 0x17: // LDC.L @Rm+,GBR 0100mmmm00010111
2285 tmp = SHR_GBR;
2286 break;
2287 case 0x27: // LDC.L @Rm+,VBR 0100mmmm00100111
2288 tmp = SHR_VBR;
2289 break;
2290 default:
2291 goto default_;
2292 }
ed8cf79b 2293 rcache_get_reg_arg(0, GET_Rn());
2294 tmp2 = emit_memhandler_read(2);
2295 if (tmp == SHR_SR) {
18b94127 2296 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 2297 emith_write_sr(sr, tmp2);
2298 drcf.test_irq = 1;
ed8cf79b 2299 } else {
2300 tmp = rcache_get_reg(tmp, RC_GR_WRITE);
2301 emith_move_r_r(tmp, tmp2);
2302 }
2303 rcache_free_tmp(tmp2);
2304 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2305 emith_add_r_imm(tmp, 4);
2306 goto end_op;
52d759c3 2307 case 0x08:
2308 case 0x09:
2309 switch (GET_Fx())
2310 {
2311 case 0:
2312 // SHLL2 Rn 0100nnnn00001000
2313 // SHLR2 Rn 0100nnnn00001001
2314 tmp = 2;
2315 break;
2316 case 1:
2317 // SHLL8 Rn 0100nnnn00011000
2318 // SHLR8 Rn 0100nnnn00011001
2319 tmp = 8;
2320 break;
2321 case 2:
2322 // SHLL16 Rn 0100nnnn00101000
2323 // SHLR16 Rn 0100nnnn00101001
2324 tmp = 16;
2325 break;
2326 default:
2327 goto default_;
2328 }
2329 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2330 if (op & 1) {
2331 emith_lsr(tmp2, tmp2, tmp);
2332 } else
2333 emith_lsl(tmp2, tmp2, tmp);
2334 goto end_op;
2335 case 0x0a:
2336 switch (GET_Fx())
2337 {
2338 case 0: // LDS Rm,MACH 0100mmmm00001010
2339 tmp2 = SHR_MACH;
2340 break;
2341 case 1: // LDS Rm,MACL 0100mmmm00011010
2342 tmp2 = SHR_MACL;
2343 break;
2344 case 2: // LDS Rm,PR 0100mmmm00101010
2345 tmp2 = SHR_PR;
2346 break;
2347 default:
2348 goto default_;
2349 }
2350 emit_move_r_r(tmp2, GET_Rn());
2351 goto end_op;
e898de13 2352 case 0x0b:
52d759c3 2353 switch (GET_Fx())
2354 {
52d759c3 2355 case 1: // TAS.B @Rn 0100nnnn00011011
2356 // XXX: is TAS working on 32X?
52d759c3 2357 rcache_get_reg_arg(0, GET_Rn());
8796b7ee 2358 tmp = emit_memhandler_read(0);
2359 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2360 emith_bic_r_imm(sr, T);
52d759c3 2361 emith_cmp_r_imm(tmp, 0);
8796b7ee 2362 emit_or_t_if_eq(sr);
52d759c3 2363 rcache_clean();
2364 emith_or_r_imm(tmp, 0x80);
2365 tmp2 = rcache_get_tmp_arg(1); // assuming it differs to tmp
2366 emith_move_r_r(tmp2, tmp);
2367 rcache_free_tmp(tmp);
2368 rcache_get_reg_arg(0, GET_Rn());
001f73a0 2369 emit_memhandler_write(0);
52d759c3 2370 break;
2371 default:
e898de13 2372 goto default_;
52d759c3 2373 }
e898de13 2374 goto end_op;
2375 case 0x0e:
52d759c3 2376 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
2377 switch (GET_Fx())
2378 {
2379 case 0: // LDC Rm,SR 0100mmmm00001110
2380 tmp2 = SHR_SR;
2381 break;
2382 case 1: // LDC Rm,GBR 0100mmmm00011110
2383 tmp2 = SHR_GBR;
2384 break;
2385 case 2: // LDC Rm,VBR 0100mmmm00101110
2386 tmp2 = SHR_VBR;
2387 break;
2388 default:
e898de13 2389 goto default_;
52d759c3 2390 }
2391 if (tmp2 == SHR_SR) {
18b94127 2392 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 2393 emith_write_sr(sr, tmp);
2394 drcf.test_irq = 1;
52d759c3 2395 } else {
2396 tmp2 = rcache_get_reg(tmp2, RC_GR_WRITE);
2397 emith_move_r_r(tmp2, tmp);
2398 }
2399 goto end_op;
2400 case 0x0f:
23686515 2401 // MAC.W @Rm+,@Rn+ 0100nnnnmmmm1111
f0d7b1fa 2402 emit_indirect_read_double(&tmp, &tmp2, GET_Rn(), GET_Rm(), 1);
2403 emith_sext(tmp, tmp, 16);
2404 emith_sext(tmp2, tmp2, 16);
2405 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_RMW);
2406 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_RMW);
2407 emith_mula_s64(tmp3, tmp4, tmp, tmp2);
f0d7b1fa 2408 rcache_free_tmp(tmp2);
f0d7b1fa 2409 // XXX: MACH should be untouched when S is set?
8796b7ee 2410 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
2411 emith_tst_r_imm(sr, S);
2412 EMITH_JMP_START(DCOND_EQ);
2413
2414 emith_asr(tmp, tmp3, 31);
2415 emith_eorf_r_r(tmp, tmp4); // tmp = ((signed)macl >> 31) ^ mach
2416 EMITH_JMP_START(DCOND_EQ);
2417 emith_move_r_imm(tmp3, 0x80000000);
2418 emith_tst_r_r(tmp4, tmp4);
2419 EMITH_SJMP_START(DCOND_MI);
2420 emith_sub_r_imm_c(DCOND_PL, tmp3, 1); // positive
2421 EMITH_SJMP_END(DCOND_MI);
2422 EMITH_JMP_END(DCOND_EQ);
2423
2424 EMITH_JMP_END(DCOND_EQ);
2425 rcache_free_tmp(tmp);
f0d7b1fa 2426 goto end_op;
679af8a3 2427 }
2428 goto default_;
2429
52d759c3 2430 /////////////////////////////////////////////
2431 case 0x05:
2432 // MOV.L @(disp,Rm),Rn 0101nnnnmmmmdddd
23686515 2433 emit_memhandler_read_rr(GET_Rn(), GET_Rm(), (op & 0x0f) * 4, 2);
52d759c3 2434 goto end_op;
2435
2436 /////////////////////////////////////////////
2437 case 0x06:
2438 switch (op & 0x0f)
2439 {
2440 case 0x00: // MOV.B @Rm,Rn 0110nnnnmmmm0000
2441 case 0x01: // MOV.W @Rm,Rn 0110nnnnmmmm0001
2442 case 0x02: // MOV.L @Rm,Rn 0110nnnnmmmm0010
2443 case 0x04: // MOV.B @Rm+,Rn 0110nnnnmmmm0100
2444 case 0x05: // MOV.W @Rm+,Rn 0110nnnnmmmm0101
2445 case 0x06: // MOV.L @Rm+,Rn 0110nnnnmmmm0110
23686515 2446 emit_memhandler_read_rr(GET_Rn(), GET_Rm(), 0, op & 3);
52d759c3 2447 if ((op & 7) >= 4 && GET_Rn() != GET_Rm()) {
2448 tmp = rcache_get_reg(GET_Rm(), RC_GR_RMW);
2449 emith_add_r_imm(tmp, (1 << (op & 3)));
2450 }
2451 goto end_op;
2452 case 0x03:
2453 case 0x07 ... 0x0f:
2454 tmp = rcache_get_reg(GET_Rm(), RC_GR_READ);
2455 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
2456 switch (op & 0x0f)
2457 {
2458 case 0x03: // MOV Rm,Rn 0110nnnnmmmm0011
2459 emith_move_r_r(tmp2, tmp);
2460 break;
2461 case 0x07: // NOT Rm,Rn 0110nnnnmmmm0111
2462 emith_mvn_r_r(tmp2, tmp);
2463 break;
2464 case 0x08: // SWAP.B Rm,Rn 0110nnnnmmmm1000
2465 tmp3 = tmp2;
2466 if (tmp == tmp2)
2467 tmp3 = rcache_get_tmp();
2468 tmp4 = rcache_get_tmp();
2469 emith_lsr(tmp3, tmp, 16);
f0d7b1fa 2470 emith_or_r_r_lsl(tmp3, tmp, 24);
52d759c3 2471 emith_and_r_r_imm(tmp4, tmp, 0xff00);
f0d7b1fa 2472 emith_or_r_r_lsl(tmp3, tmp4, 8);
52d759c3 2473 emith_rol(tmp2, tmp3, 16);
2474 rcache_free_tmp(tmp4);
2475 if (tmp == tmp2)
2476 rcache_free_tmp(tmp3);
2477 break;
2478 case 0x09: // SWAP.W Rm,Rn 0110nnnnmmmm1001
2479 emith_rol(tmp2, tmp, 16);
2480 break;
2481 case 0x0a: // NEGC Rm,Rn 0110nnnnmmmm1010
8796b7ee 2482 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
8b4f38f4 2483 emith_tpop_carry(sr, 1);
52d759c3 2484 emith_negcf_r_r(tmp2, tmp);
8b4f38f4 2485 emith_tpush_carry(sr, 1);
52d759c3 2486 break;
2487 case 0x0b: // NEG Rm,Rn 0110nnnnmmmm1011
2488 emith_neg_r_r(tmp2, tmp);
2489 break;
2490 case 0x0c: // EXTU.B Rm,Rn 0110nnnnmmmm1100
2491 emith_clear_msb(tmp2, tmp, 24);
2492 break;
2493 case 0x0d: // EXTU.W Rm,Rn 0110nnnnmmmm1101
2494 emith_clear_msb(tmp2, tmp, 16);
2495 break;
2496 case 0x0e: // EXTS.B Rm,Rn 0110nnnnmmmm1110
2497 emith_sext(tmp2, tmp, 8);
2498 break;
2499 case 0x0f: // EXTS.W Rm,Rn 0110nnnnmmmm1111
2500 emith_sext(tmp2, tmp, 16);
2501 break;
2502 }
2503 goto end_op;
2504 }
2505 goto default_;
2506
2507 /////////////////////////////////////////////
2508 case 0x07:
2509 // ADD #imm,Rn 0111nnnniiiiiiii
2510 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2511 if (op & 0x80) { // adding negative
2512 emith_sub_r_imm(tmp, -op & 0xff);
2513 } else
2514 emith_add_r_imm(tmp, op & 0xff);
2515 goto end_op;
2516
3863edbd 2517 /////////////////////////////////////////////
e898de13 2518 case 0x08:
52d759c3 2519 switch (op & 0x0f00)
2520 {
2521 case 0x0000: // MOV.B R0,@(disp,Rn) 10000000nnnndddd
2522 case 0x0100: // MOV.W R0,@(disp,Rn) 10000001nnnndddd
2523 rcache_clean();
2524 tmp = rcache_get_reg_arg(0, GET_Rm());
2525 tmp2 = rcache_get_reg_arg(1, SHR_R0);
2526 tmp3 = (op & 0x100) >> 8;
23686515 2527 if (op & 0x0f)
2528 emith_add_r_imm(tmp, (op & 0x0f) << tmp3);
001f73a0 2529 emit_memhandler_write(tmp3);
52d759c3 2530 goto end_op;
2531 case 0x0400: // MOV.B @(disp,Rm),R0 10000100mmmmdddd
2532 case 0x0500: // MOV.W @(disp,Rm),R0 10000101mmmmdddd
23686515 2533 tmp = (op & 0x100) >> 8;
2534 emit_memhandler_read_rr(SHR_R0, GET_Rm(), (op & 0x0f) << tmp, tmp);
52d759c3 2535 goto end_op;
2536 case 0x0800: // CMP/EQ #imm,R0 10001000iiiiiiii
2537 // XXX: could use cmn
2538 tmp = rcache_get_tmp();
2539 tmp2 = rcache_get_reg(0, RC_GR_READ);
8796b7ee 2540 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
52d759c3 2541 emith_move_r_imm_s8(tmp, op & 0xff);
8796b7ee 2542 emith_bic_r_imm(sr, T);
52d759c3 2543 emith_cmp_r_r(tmp2, tmp);
8796b7ee 2544 emit_or_t_if_eq(sr);
52d759c3 2545 rcache_free_tmp(tmp);
2546 goto end_op;
44e6452e 2547 }
679af8a3 2548 goto default_;
679af8a3 2549
52d759c3 2550 /////////////////////////////////////////////
2551 case 0x0c:
2552 switch (op & 0x0f00)
2553 {
2554 case 0x0000: // MOV.B R0,@(disp,GBR) 11000000dddddddd
2555 case 0x0100: // MOV.W R0,@(disp,GBR) 11000001dddddddd
2556 case 0x0200: // MOV.L R0,@(disp,GBR) 11000010dddddddd
2557 rcache_clean();
2558 tmp = rcache_get_reg_arg(0, SHR_GBR);
2559 tmp2 = rcache_get_reg_arg(1, SHR_R0);
2560 tmp3 = (op & 0x300) >> 8;
2561 emith_add_r_imm(tmp, (op & 0xff) << tmp3);
001f73a0 2562 emit_memhandler_write(tmp3);
52d759c3 2563 goto end_op;
2564 case 0x0400: // MOV.B @(disp,GBR),R0 11000100dddddddd
2565 case 0x0500: // MOV.W @(disp,GBR),R0 11000101dddddddd
2566 case 0x0600: // MOV.L @(disp,GBR),R0 11000110dddddddd
23686515 2567 tmp = (op & 0x300) >> 8;
2568 emit_memhandler_read_rr(SHR_R0, SHR_GBR, (op & 0xff) << tmp, tmp);
52d759c3 2569 goto end_op;
2570 case 0x0300: // TRAPA #imm 11000011iiiiiiii
2571 tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
2572 emith_sub_r_imm(tmp, 4*2);
52d759c3 2573 // push SR
2574 tmp = rcache_get_reg_arg(0, SHR_SP);
2575 emith_add_r_imm(tmp, 4);
2576 tmp = rcache_get_reg_arg(1, SHR_SR);
18b94127 2577 emith_clear_msb(tmp, tmp, 22);
001f73a0 2578 emit_memhandler_write(2);
52d759c3 2579 // push PC
2580 rcache_get_reg_arg(0, SHR_SP);
2581 tmp = rcache_get_tmp_arg(1);
2582 emith_move_r_imm(tmp, pc);
001f73a0 2583 emit_memhandler_write(2);
52d759c3 2584 // obtain new PC
23686515 2585 emit_memhandler_read_rr(SHR_PC, SHR_VBR, (op & 0xff) * 4, 2);
bf092a36 2586 // indirect jump -> back to dispatcher
6976a547 2587 rcache_flush();
bf092a36 2588 emith_jump(sh2_drc_dispatcher);
44e6452e 2589 goto end_op;
52d759c3 2590 case 0x0800: // TST #imm,R0 11001000iiiiiiii
8796b7ee 2591 tmp = rcache_get_reg(SHR_R0, RC_GR_READ);
2592 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2593 emith_bic_r_imm(sr, T);
52d759c3 2594 emith_tst_r_imm(tmp, op & 0xff);
8796b7ee 2595 emit_or_t_if_eq(sr);
52d759c3 2596 goto end_op;
2597 case 0x0900: // AND #imm,R0 11001001iiiiiiii
2598 tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
2599 emith_and_r_imm(tmp, op & 0xff);
2600 goto end_op;
2601 case 0x0a00: // XOR #imm,R0 11001010iiiiiiii
2602 tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
2603 emith_eor_r_imm(tmp, op & 0xff);
2604 goto end_op;
2605 case 0x0b00: // OR #imm,R0 11001011iiiiiiii
2606 tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
2607 emith_or_r_imm(tmp, op & 0xff);
2608 goto end_op;
2609 case 0x0c00: // TST.B #imm,@(R0,GBR) 11001100iiiiiiii
8796b7ee 2610 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
2611 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2612 emith_bic_r_imm(sr, T);
52d759c3 2613 emith_tst_r_imm(tmp, op & 0xff);
8796b7ee 2614 emit_or_t_if_eq(sr);
52d759c3 2615 rcache_free_tmp(tmp);
52d759c3 2616 goto end_op;
2617 case 0x0d00: // AND.B #imm,@(R0,GBR) 11001101iiiiiiii
2618 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
2619 emith_and_r_imm(tmp, op & 0xff);
8796b7ee 2620 goto end_rmw_op;
52d759c3 2621 case 0x0e00: // XOR.B #imm,@(R0,GBR) 11001110iiiiiiii
2622 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
2623 emith_eor_r_imm(tmp, op & 0xff);
8796b7ee 2624 goto end_rmw_op;
52d759c3 2625 case 0x0f00: // OR.B #imm,@(R0,GBR) 11001111iiiiiiii
2626 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
2627 emith_or_r_imm(tmp, op & 0xff);
8796b7ee 2628 end_rmw_op:
2629 tmp2 = rcache_get_tmp_arg(1);
2630 emith_move_r_r(tmp2, tmp);
2631 rcache_free_tmp(tmp);
2632 tmp3 = rcache_get_reg_arg(0, SHR_GBR);
2633 tmp4 = rcache_get_reg(SHR_R0, RC_GR_READ);
2634 emith_add_r_r(tmp3, tmp4);
001f73a0 2635 emit_memhandler_write(0);
52d759c3 2636 goto end_op;
2637 }
2638 goto default_;
2639
52d759c3 2640 /////////////////////////////////////////////
2641 case 0x0e:
2642 // MOV #imm,Rn 1110nnnniiiiiiii
23686515 2643 emit_move_r_imm32(GET_Rn(), (u32)(signed int)(signed char)op);
52d759c3 2644 goto end_op;
2645
679af8a3 2646 default:
2647 default_:
6a5b1b36 2648 if (!(op_flags[i] & OF_B_IN_DS))
2649 elprintf_sh2(sh2, EL_ANOMALY,
2650 "drc: illegal op %04x @ %08x", op, pc - 2);
001f73a0 2651
2652 tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
2653 emith_sub_r_imm(tmp, 4*2);
2654 // push SR
2655 tmp = rcache_get_reg_arg(0, SHR_SP);
2656 emith_add_r_imm(tmp, 4);
2657 tmp = rcache_get_reg_arg(1, SHR_SR);
2658 emith_clear_msb(tmp, tmp, 22);
2659 emit_memhandler_write(2);
2660 // push PC
2661 rcache_get_reg_arg(0, SHR_SP);
2662 tmp = rcache_get_tmp_arg(1);
6a5b1b36 2663 if (drcf.pending_branch_indirect) {
2664 tmp2 = rcache_get_reg(SHR_PC, RC_GR_READ);
2665 emith_move_r_r(tmp, tmp2);
2666 }
2667 else
2668 emith_move_r_imm(tmp, pc - 2);
001f73a0 2669 emit_memhandler_write(2);
2670 // obtain new PC
6a5b1b36 2671 v = (op_flags[i] & OF_B_IN_DS) ? 6 : 4;
2672 emit_memhandler_read_rr(SHR_PC, SHR_VBR, v * 4, 2);
001f73a0 2673 // indirect jump -> back to dispatcher
2674 rcache_flush();
2675 emith_jump(sh2_drc_dispatcher);
679af8a3 2676 break;
2677 }
2678
e898de13 2679end_op:
23686515 2680 rcache_unlock_all();
2681
6d797957 2682 cycles += opd->cycles;
2683
bf092a36 2684 if (op_flags[i+1] & OF_DELAY_OP) {
2685 do_host_disasm(tcache_id);
2686 continue;
2687 }
2688
2689 // test irq?
2690 if (drcf.test_irq && !drcf.pending_branch_direct) {
2691 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2692 FLUSH_CYCLES(sr);
fa841b44 2693 if (!drcf.pending_branch_indirect)
2694 emit_move_r_imm32(SHR_PC, pc);
bf092a36 2695 rcache_flush();
2696 emith_call(sh2_drc_test_irq);
2697 drcf.test_irq = 0;
2698 }
2699
2700 // branch handling (with/without delay)
2701 if (drcf.pending_branch_direct)
44e6452e 2702 {
bf092a36 2703 struct op_data *opd_b =
2704 (op_flags[i] & OF_DELAY_OP) ? &ops[i-1] : opd;
2705 u32 target_pc = opd_b->imm;
2706 int cond = -1;
2707 void *target = NULL;
44e6452e 2708
18b94127 2709 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
e05b81fc 2710 FLUSH_CYCLES(sr);
18b94127 2711
bf092a36 2712 if (opd_b->op != OP_BRANCH)
2713 cond = (opd_b->op == OP_BRANCH_CF) ? DCOND_EQ : DCOND_NE;
2714 if (cond != -1) {
2715 int ctaken = (op_flags[i] & OF_DELAY_OP) ? 1 : 2;
2716
2717 if (delay_dep_fw & BITMASK1(SHR_T))
2718 emith_tst_r_imm(sr, T_save);
2719 else
2720 emith_tst_r_imm(sr, T);
2721
2722 emith_sub_r_imm_c(cond, sr, ctaken<<12);
2723 }
5f0ca48f 2724 rcache_clean();
2725
5686d931 2726#if LINK_BRANCHES
bf092a36 2727 if (find_in_array(branch_target_pc, branch_target_count, target_pc) >= 0)
2728 {
44e6452e 2729 // local branch
2730 // XXX: jumps back can be linked already
bf092a36 2731 if (branch_patch_count < MAX_LOCAL_BRANCHES) {
2732 target = tcache_ptr;
2733 branch_patch_pc[branch_patch_count] = target_pc;
2734 branch_patch_ptr[branch_patch_count] = target;
2735 branch_patch_count++;
44e6452e 2736 }
bf092a36 2737 else
2738 dbg(1, "warning: too many local branches");
44e6452e 2739 }
bf092a36 2740
2741 if (target == NULL)
5686d931 2742#endif
2743 {
44e6452e 2744 // can't resolve branch locally, make a block exit
2745 emit_move_r_imm32(SHR_PC, target_pc);
2746 rcache_clean();
2747
00a725a8 2748 target = dr_prepare_ext_branch(target_pc, sh2->is_slave, tcache_id);
44e6452e 2749 if (target == NULL)
2750 return NULL;
18b94127 2751 }
44e6452e 2752
bf092a36 2753 if (cond != -1)
2754 emith_jump_cond_patchable(cond, target);
6976a547 2755 else {
bf092a36 2756 emith_jump_patchable(target);
6976a547 2757 rcache_invalidate();
2758 }
44e6452e 2759
bf092a36 2760 drcf.pending_branch_direct = 0;
2761 }
2762 else if (drcf.pending_branch_indirect) {
e05b81fc 2763 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2764 FLUSH_CYCLES(sr);
2765 rcache_flush();
bf092a36 2766 emith_jump(sh2_drc_dispatcher);
2767 drcf.pending_branch_indirect = 0;
e05b81fc 2768 }
e898de13 2769
f4bb5d6b 2770 do_host_disasm(tcache_id);
44e6452e 2771 }
f4bb5d6b 2772
18b94127 2773 tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
e05b81fc 2774 FLUSH_CYCLES(tmp);
18b94127 2775 rcache_flush();
44e6452e 2776
bf092a36 2777 // check the last op
2778 if (op_flags[i-1] & OF_DELAY_OP)
2779 opd = &ops[i-2];
2780 else
2781 opd = &ops[i-1];
2782
2783 if (opd->op != OP_BRANCH && opd->op != OP_BRANCH_R
2784 && opd->op != OP_BRANCH_RF && opd->op != OP_RTE)
2785 {
44e6452e 2786 void *target;
bf092a36 2787
2788 emit_move_r_imm32(SHR_PC, pc);
44e6452e 2789 rcache_flush();
2790
bf092a36 2791 target = dr_prepare_ext_branch(pc, sh2->is_slave, tcache_id);
44e6452e 2792 if (target == NULL)
2793 return NULL;
2794 emith_jump_patchable(target);
2795 }
18b94127 2796
2797 // link local branches
2798 for (i = 0; i < branch_patch_count; i++) {
2799 void *target;
2800 int t;
18b94127 2801 t = find_in_array(branch_target_pc, branch_target_count, branch_patch_pc[i]);
44e6452e 2802 target = branch_target_ptr[t];
2803 if (target == NULL) {
fcdefcf6 2804 // flush pc and go back to dispatcher (this should no longer happen)
2805 dbg(1, "stray branch to %08x %p", branch_patch_pc[i], tcache_ptr);
18b94127 2806 target = tcache_ptr;
2807 emit_move_r_imm32(SHR_PC, branch_patch_pc[i]);
2808 rcache_flush();
e05b81fc 2809 emith_jump(sh2_drc_dispatcher);
18b94127 2810 }
2811 emith_jump_patch(branch_patch_ptr[i], target);
2812 }
2813
f4bb5d6b 2814 // mark memory blocks as containing compiled code
a2b8c5a5 2815 // override any overlay blocks as they become unreachable anyway
fa841b44 2816 if ((block->addr & 0xc7fc0000) == 0x06000000
2817 || (block->addr & 0xfffff000) == 0xc0000000)
a2b8c5a5 2818 {
228ee974 2819 u16 *drc_ram_blk = NULL;
4943816b 2820 u32 addr, mask = 0, shift = 0;
a2b8c5a5 2821
2822 if (tcache_id != 0) {
2823 // data array, BIOS
2824 drc_ram_blk = Pico32xMem->drcblk_da[sh2->is_slave];
2825 shift = SH2_DRCBLK_DA_SHIFT;
4943816b 2826 mask = 0xfff;
f4bb5d6b 2827 }
fa841b44 2828 else {
a2b8c5a5 2829 // SDRAM
2830 drc_ram_blk = Pico32xMem->drcblk_ram;
2831 shift = SH2_DRCBLK_RAM_SHIFT;
4943816b 2832 mask = 0x3ffff;
f4bb5d6b 2833 }
a2b8c5a5 2834
228ee974 2835 // mark recompiled insns
2836 drc_ram_blk[(base_pc & mask) >> shift] = 1;
2837 for (pc = base_pc; pc < end_pc; pc += 2)
2838 drc_ram_blk[(pc & mask) >> shift] = 1;
04092e32 2839
2840 // mark literals
2841 for (i = 0; i < literal_addr_count; i++) {
2842 tmp = literal_addr[i];
228ee974 2843 drc_ram_blk[(tmp & mask) >> shift] = 1;
04092e32 2844 }
4943816b 2845
2846 // add to invalidation lookup lists
51d86e55 2847 addr = base_pc & ~(INVAL_PAGE_SIZE - 1);
2848 for (; addr < end_literals; addr += INVAL_PAGE_SIZE) {
2849 i = (addr & mask) / INVAL_PAGE_SIZE;
228ee974 2850 add_to_block_list(&inval_lookup[tcache_id][i], block);
4943816b 2851 }
679af8a3 2852 }
2853
f4bb5d6b 2854 tcache_ptrs[tcache_id] = tcache_ptr;
2855
228ee974 2856 host_instructions_updated(block_entry_ptr, tcache_ptr);
553c3eaa 2857
f4bb5d6b 2858 do_host_disasm(tcache_id);
51d86e55 2859
2860 if (drcf.literals_disabled && literal_addr_count)
2861 dbg(1, "literals_disabled && literal_addr_count?");
fcdefcf6 2862 dbg(2, " block #%d,%d tcache %d/%d, insns %d -> %d %.3f",
4943816b 2863 tcache_id, blkid_main,
f4bb5d6b 2864 tcache_ptr - tcache_bases[tcache_id], tcache_sizes[tcache_id],
4943816b 2865 insns_compiled, host_insn_count, (float)host_insn_count / insns_compiled);
f4bb5d6b 2866 if ((sh2->pc & 0xc6000000) == 0x02000000) // ROM
fcdefcf6 2867 dbg(2, " hash collisions %d/%d", hash_collisions, block_counts[tcache_id]);
18b94127 2868/*
2869 printf("~~~\n");
228ee974 2870 tcache_dsm_ptrs[tcache_id] = block_entry_ptr;
18b94127 2871 do_host_disasm(tcache_id);
2872 printf("~~~\n");
2873*/
2874
fcdefcf6 2875#if (DRC_DEBUG & 4)
553c3eaa 2876 fflush(stdout);
2877#endif
2878
228ee974 2879 return block_entry_ptr;
679af8a3 2880}
2881
e05b81fc 2882static void sh2_generate_utils(void)
679af8a3 2883{
e05b81fc 2884 int arg0, arg1, arg2, sr, tmp;
52d759c3 2885
5686d931 2886 sh2_drc_write32 = p32x_sh2_write32;
2887 sh2_drc_read8 = p32x_sh2_read8;
2888 sh2_drc_read16 = p32x_sh2_read16;
2889 sh2_drc_read32 = p32x_sh2_read32;
2890
e05b81fc 2891 host_arg2reg(arg0, 0);
2892 host_arg2reg(arg1, 1);
2893 host_arg2reg(arg2, 2);
2894 emith_move_r_r(arg0, arg0); // nop
679af8a3 2895
e05b81fc 2896 // sh2_drc_exit(void)
2897 sh2_drc_exit = (void *)tcache_ptr;
2898 emit_do_static_regs(1, arg2);
2899 emith_sh2_drc_exit();
679af8a3 2900
e05b81fc 2901 // sh2_drc_dispatcher(void)
2902 sh2_drc_dispatcher = (void *)tcache_ptr;
2903 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
2904 emith_cmp_r_imm(sr, 0);
2905 emith_jump_cond(DCOND_LT, sh2_drc_exit);
2906 rcache_invalidate();
2907 emith_ctx_read(arg0, SHR_PC * 4);
2908 emith_ctx_read(arg1, offsetof(SH2, is_slave));
2909 emith_add_r_r_imm(arg2, CONTEXT_REG, offsetof(SH2, drc_tmp));
a2b8c5a5 2910 emith_call(dr_lookup_block);
e05b81fc 2911 emit_block_entry();
2912 // lookup failed, call sh2_translate()
2913 emith_move_r_r(arg0, CONTEXT_REG);
2914 emith_ctx_read(arg1, offsetof(SH2, drc_tmp)); // tcache_id
2915 emith_call(sh2_translate);
2916 emit_block_entry();
2917 // sh2_translate() failed, flush cache and retry
2918 emith_ctx_read(arg0, offsetof(SH2, drc_tmp));
2919 emith_call(flush_tcache);
2920 emith_move_r_r(arg0, CONTEXT_REG);
2921 emith_ctx_read(arg1, offsetof(SH2, drc_tmp));
2922 emith_call(sh2_translate);
2923 emit_block_entry();
2924 // XXX: can't translate, fail
c25d78ee 2925 emith_call(dr_failure);
e05b81fc 2926
2927 // sh2_drc_test_irq(void)
2928 // assumes it's called from main function (may jump to dispatcher)
2929 sh2_drc_test_irq = (void *)tcache_ptr;
2930 emith_ctx_read(arg1, offsetof(SH2, pending_level));
2931 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
2932 emith_lsr(arg0, sr, I_SHIFT);
2933 emith_and_r_imm(arg0, 0x0f);
2934 emith_cmp_r_r(arg1, arg0); // pending_level > ((sr >> 4) & 0x0f)?
2935 EMITH_SJMP_START(DCOND_GT);
2936 emith_ret_c(DCOND_LE); // nope, return
2937 EMITH_SJMP_END(DCOND_GT);
2938 // adjust SP
2939 tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
2940 emith_sub_r_imm(tmp, 4*2);
2941 rcache_clean();
2942 // push SR
2943 tmp = rcache_get_reg_arg(0, SHR_SP);
2944 emith_add_r_imm(tmp, 4);
2945 tmp = rcache_get_reg_arg(1, SHR_SR);
2946 emith_clear_msb(tmp, tmp, 22);
2947 emith_move_r_r(arg2, CONTEXT_REG);
5686d931 2948 emith_call(p32x_sh2_write32); // XXX: use sh2_drc_write32?
e05b81fc 2949 rcache_invalidate();
2950 // push PC
2951 rcache_get_reg_arg(0, SHR_SP);
2952 emith_ctx_read(arg1, SHR_PC * 4);
2953 emith_move_r_r(arg2, CONTEXT_REG);
2954 emith_call(p32x_sh2_write32);
2955 rcache_invalidate();
2956 // update I, cycles, do callback
2957 emith_ctx_read(arg1, offsetof(SH2, pending_level));
2958 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2959 emith_bic_r_imm(sr, I);
2960 emith_or_r_r_lsl(sr, arg1, I_SHIFT);
2961 emith_sub_r_imm(sr, 13 << 12); // at least 13 cycles
2962 rcache_flush();
2963 emith_move_r_r(arg0, CONTEXT_REG);
2964 emith_call_ctx(offsetof(SH2, irq_callback)); // vector = sh2->irq_callback(sh2, level);
2965 // obtain new PC
2966 emith_lsl(arg0, arg0, 2);
2967 emith_ctx_read(arg1, SHR_VBR * 4);
2968 emith_add_r_r(arg0, arg1);
2969 emit_memhandler_read(2);
2970 emith_ctx_write(arg0, SHR_PC * 4);
2971#ifdef __i386__
2972 emith_add_r_imm(xSP, 4); // fix stack
2973#endif
2974 emith_jump(sh2_drc_dispatcher);
2975 rcache_invalidate();
2976
2977 // sh2_drc_entry(SH2 *sh2)
2978 sh2_drc_entry = (void *)tcache_ptr;
2979 emith_sh2_drc_entry();
2980 emith_move_r_r(CONTEXT_REG, arg0); // move ctx, arg0
2981 emit_do_static_regs(0, arg2);
2982 emith_call(sh2_drc_test_irq);
2983 emith_jump(sh2_drc_dispatcher);
2984
e05b81fc 2985 // sh2_drc_write8(u32 a, u32 d)
2986 sh2_drc_write8 = (void *)tcache_ptr;
e05b81fc 2987 emith_ctx_read(arg2, offsetof(SH2, write8_tab));
d056bef8 2988 emith_sh2_wcall(arg0, arg2);
e05b81fc 2989
2990 // sh2_drc_write16(u32 a, u32 d)
2991 sh2_drc_write16 = (void *)tcache_ptr;
e05b81fc 2992 emith_ctx_read(arg2, offsetof(SH2, write16_tab));
d056bef8 2993 emith_sh2_wcall(arg0, arg2);
e05b81fc 2994
5686d931 2995#ifdef PDB_NET
2996 // debug
2997 #define MAKE_READ_WRAPPER(func) { \
2998 void *tmp = (void *)tcache_ptr; \
a2b8c5a5 2999 emith_push_ret(); \
5686d931 3000 emith_call(func); \
3001 emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[0])); \
3002 emith_addf_r_r(arg2, arg0); \
3003 emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[0])); \
3004 emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[1])); \
3005 emith_adc_r_imm(arg2, 0x01000000); \
3006 emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[1])); \
a2b8c5a5 3007 emith_pop_and_ret(); \
5686d931 3008 func = tmp; \
3009 }
3010 #define MAKE_WRITE_WRAPPER(func) { \
3011 void *tmp = (void *)tcache_ptr; \
3012 emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[0])); \
3013 emith_addf_r_r(arg2, arg1); \
3014 emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[0])); \
3015 emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[1])); \
3016 emith_adc_r_imm(arg2, 0x01000000); \
3017 emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[1])); \
3018 emith_move_r_r(arg2, CONTEXT_REG); \
3019 emith_jump(func); \
3020 func = tmp; \
3021 }
3022
3023 MAKE_READ_WRAPPER(sh2_drc_read8);
3024 MAKE_READ_WRAPPER(sh2_drc_read16);
3025 MAKE_READ_WRAPPER(sh2_drc_read32);
3026 MAKE_WRITE_WRAPPER(sh2_drc_write8);
5686d931 3027 MAKE_WRITE_WRAPPER(sh2_drc_write16);
5686d931 3028 MAKE_WRITE_WRAPPER(sh2_drc_write32);
fcdefcf6 3029#if (DRC_DEBUG & 4)
5686d931 3030 host_dasm_new_symbol(sh2_drc_read8);
3031 host_dasm_new_symbol(sh2_drc_read16);
3032 host_dasm_new_symbol(sh2_drc_read32);
3033 host_dasm_new_symbol(sh2_drc_write32);
3034#endif
3035#endif
3036
e05b81fc 3037 rcache_invalidate();
fcdefcf6 3038#if (DRC_DEBUG & 4)
e05b81fc 3039 host_dasm_new_symbol(sh2_drc_entry);
3040 host_dasm_new_symbol(sh2_drc_dispatcher);
3041 host_dasm_new_symbol(sh2_drc_exit);
3042 host_dasm_new_symbol(sh2_drc_test_irq);
e05b81fc 3043 host_dasm_new_symbol(sh2_drc_write8);
e05b81fc 3044 host_dasm_new_symbol(sh2_drc_write16);
679af8a3 3045#endif
679af8a3 3046}
3047
f0ed9e38 3048static void sh2_smc_rm_block(struct block_desc *bd, int tcache_id, u32 ram_mask)
f4bb5d6b 3049{
51d86e55 3050 u32 i, addr, end_addr;
04092e32 3051 void *tmp;
3052
f0ed9e38 3053 dbg(2, " killing block %08x-%08x-%08x, blkid %d,%d",
51d86e55 3054 bd->addr, bd->addr + bd->size_nolit, bd->addr + bd->size,
3055 tcache_id, bd - block_tables[tcache_id]);
228ee974 3056 if (bd->addr == 0 || bd->entry_count == 0) {
fcdefcf6 3057 dbg(1, " killing dead block!? %08x", bd->addr);
569420b0 3058 return;
04092e32 3059 }
3060
4943816b 3061 // remove from inval_lookup
51d86e55 3062 addr = bd->addr & ~(INVAL_PAGE_SIZE - 1);
3063 end_addr = bd->addr + bd->size;
3064 for (; addr < end_addr; addr += INVAL_PAGE_SIZE) {
3065 i = (addr & ram_mask) / INVAL_PAGE_SIZE;
4943816b 3066 rm_from_block_list(&inval_lookup[tcache_id][i], bd);
3067 }
3068
04092e32 3069 tmp = tcache_ptr;
569420b0 3070
00a725a8 3071 // remove from hash table, make incoming links unresolved
3072 // XXX: maybe patch branches w/flush instead?
228ee974 3073 for (i = 0; i < bd->entry_count; i++) {
3074 rm_from_hashlist(&bd->entryp[i], tcache_id);
3075
3076 // since we never reuse tcache space of dead blocks,
3077 // insert jump to dispatcher for blocks that are linked to this
3078 tcache_ptr = bd->entryp[i].tcache_ptr;
fa841b44 3079 emit_move_r_imm32(SHR_PC, bd->entryp[i].pc);
228ee974 3080 rcache_flush();
3081 emith_jump(sh2_drc_dispatcher);
3082
3083 host_instructions_updated(bd->entryp[i].tcache_ptr, tcache_ptr);
00a725a8 3084
f0ed9e38 3085 unregister_links(&bd->entryp[i], tcache_id);
228ee974 3086 }
3087
04092e32 3088 tcache_ptr = tmp;
3089
51d86e55 3090 bd->addr = bd->size = bd->size_nolit = 0;
228ee974 3091 bd->entry_count = 0;
a2b8c5a5 3092}
f4bb5d6b 3093
d602fd4f 3094/*
309504205:243: == msh2 block #0,200 060017a8-060017f0 -> 0x27cb9c
3096 060017a8 d11c MOV.L @($70,PC),R1 ; @$0600181c
3097
309804230:261: msh2 xsh w32 [260017a8] d225e304
309904230:261: msh2 smc check @260017a8
310004239:226: = ssh2 enter 060017a8 0x27cb9c, c=173
3101*/
f0ed9e38 3102static void sh2_smc_rm_blocks(u32 a, u16 *drc_ram_blk, int tcache_id, u32 shift, u32 mask)
a2b8c5a5 3103{
4943816b 3104 struct block_list **blist = NULL, *entry;
e1553677 3105 struct block_desc *block;
d602fd4f 3106 u32 start_addr, end_addr, taddr, i;
3107 u32 from = ~0, to = 0;
3108
3109 // ignore cache-through
3110 a &= ~0x20000000;
4943816b 3111
51d86e55 3112 blist = &inval_lookup[tcache_id][(a & mask) / INVAL_PAGE_SIZE];
4943816b 3113 entry = *blist;
3114 while (entry != NULL) {
3115 block = entry->block;
d602fd4f 3116 start_addr = block->addr & ~0x20000000;
3117 end_addr = start_addr + block->size;
3118 if (start_addr <= a && a < end_addr) {
51d86e55 3119 // get addr range that includes all removed blocks
d602fd4f 3120 if (from > start_addr)
3121 from = start_addr;
51d86e55 3122 if (to < end_addr)
3123 to = end_addr;
4943816b 3124
d602fd4f 3125 if (a >= start_addr + block->size_nolit)
51d86e55 3126 literal_disabled_frames = 3;
00468b0a 3127 sh2_smc_rm_block(block, tcache_id, mask);
4943816b 3128
3129 // entry lost, restart search
3130 entry = *blist;
569420b0 3131 continue;
3132 }
4943816b 3133 entry = entry->next;
04092e32 3134 }
3135
51d86e55 3136 if (from >= to)
3137 return;
3138
3139 // update range around a to match latest state
3140 from &= ~(INVAL_PAGE_SIZE - 1);
3141 to |= (INVAL_PAGE_SIZE - 1);
3142 for (taddr = from; taddr < to; taddr += INVAL_PAGE_SIZE) {
3143 i = (taddr & mask) / INVAL_PAGE_SIZE;
3144 entry = inval_lookup[tcache_id][i];
3145
3146 for (; entry != NULL; entry = entry->next) {
3147 block = entry->block;
3148
d602fd4f 3149 start_addr = block->addr & ~0x20000000;
3150 if (start_addr > a) {
3151 if (to > start_addr)
3152 to = start_addr;
51d86e55 3153 }
3154 else {
d602fd4f 3155 end_addr = start_addr + block->size;
51d86e55 3156 if (from < end_addr)
3157 from = end_addr;
3158 }
6976a547 3159 }
3160 }
3161
3162 // clear code marks
4943816b 3163 if (from < to) {
3164 u16 *p = drc_ram_blk + ((from & mask) >> shift);
3165 memset(p, 0, (to - from) >> (shift - 1));
f4bb5d6b 3166 }
f4bb5d6b 3167}
3168
3169void sh2_drc_wcheck_ram(unsigned int a, int val, int cpuid)
3170{
fcdefcf6 3171 dbg(2, "%csh2 smc check @%08x", cpuid ? 's' : 'm', a);
f0ed9e38 3172 sh2_smc_rm_blocks(a, Pico32xMem->drcblk_ram, 0, SH2_DRCBLK_RAM_SHIFT, 0x3ffff);
f4bb5d6b 3173}
3174
3175void sh2_drc_wcheck_da(unsigned int a, int val, int cpuid)
3176{
fcdefcf6 3177 dbg(2, "%csh2 smc check @%08x", cpuid ? 's' : 'm', a);
f0ed9e38 3178 sh2_smc_rm_blocks(a, Pico32xMem->drcblk_da[cpuid],
a2b8c5a5 3179 1 + cpuid, SH2_DRCBLK_DA_SHIFT, 0xfff);
f4bb5d6b 3180}
3181
0185b677 3182int sh2_execute_drc(SH2 *sh2c, int cycles)
679af8a3 3183{
e05b81fc 3184 int ret_cycles;
52d759c3 3185
679af8a3 3186 // cycles are kept in SHR_SR unused bits (upper 20)
65514d85 3187 // bit11 contains T saved for delay slot
18b94127 3188 // others are usual SH2 flags
52d759c3 3189 sh2c->sr &= 0x3f3;
3190 sh2c->sr |= cycles << 12;
e05b81fc 3191 sh2_drc_entry(sh2c);
679af8a3 3192
e05b81fc 3193 // TODO: irq cycles
3194 ret_cycles = (signed int)sh2c->sr >> 12;
3195 if (ret_cycles > 0)
fcdefcf6 3196 dbg(1, "warning: drc returned with cycles: %d", ret_cycles);
679af8a3 3197
0219d379 3198 sh2c->sr &= 0x3f3;
0185b677 3199 return ret_cycles;
679af8a3 3200}
3201
fcdefcf6 3202#if (DRC_DEBUG & 2)
9bb5d91c 3203void block_stats(void)
f4bb5d6b 3204{
3205 int c, b, i, total = 0;
3206
9bb5d91c 3207 printf("block stats:\n");
f4bb5d6b 3208 for (b = 0; b < ARRAY_SIZE(block_tables); b++)
3209 for (i = 0; i < block_counts[b]; i++)
3210 if (block_tables[b][i].addr != 0)
3211 total += block_tables[b][i].refcount;
3212
3213 for (c = 0; c < 10; c++) {
e1553677 3214 struct block_desc *blk, *maxb = NULL;
f4bb5d6b 3215 int max = 0;
3216 for (b = 0; b < ARRAY_SIZE(block_tables); b++) {
3217 for (i = 0; i < block_counts[b]; i++) {
3218 blk = &block_tables[b][i];
3219 if (blk->addr != 0 && blk->refcount > max) {
3220 max = blk->refcount;
3221 maxb = blk;
3222 }
3223 }
3224 }
3225 if (maxb == NULL)
3226 break;
3227 printf("%08x %9d %2.3f%%\n", maxb->addr, maxb->refcount,
3228 (double)maxb->refcount / total * 100.0);
3229 maxb->refcount = 0;
3230 }
553c3eaa 3231
3232 for (b = 0; b < ARRAY_SIZE(block_tables); b++)
3233 for (i = 0; i < block_counts[b]; i++)
3234 block_tables[b][i].refcount = 0;
f4bb5d6b 3235}
553c3eaa 3236#else
3237#define block_stats()
f4bb5d6b 3238#endif
3239
553c3eaa 3240void sh2_drc_flush_all(void)
3241{
3242 block_stats();
3243 flush_tcache(0);
3244 flush_tcache(1);
3245 flush_tcache(2);
3246}
3247
23686515 3248void sh2_drc_mem_setup(SH2 *sh2)
3249{
3250 // fill the convenience pointers
895d1512 3251 sh2->p_bios = sh2->is_slave ? Pico32xMem->sh2_rom_s.w : Pico32xMem->sh2_rom_m.w;
f81107f5 3252 sh2->p_da = sh2->data_array;
23686515 3253 sh2->p_sdram = Pico32xMem->sdram;
3254 sh2->p_rom = Pico.rom;
3255}
3256
51d86e55 3257void sh2_drc_frame(void)
3258{
3259 if (literal_disabled_frames > 0)
3260 literal_disabled_frames--;
3261}
3262
679af8a3 3263int sh2_drc_init(SH2 *sh2)
3264{
44e6452e 3265 int i;
7f5a3fc1 3266
44e6452e 3267 if (block_tables[0] == NULL)
3268 {
3269 for (i = 0; i < TCACHE_BUFFERS; i++) {
3270 block_tables[i] = calloc(block_max_counts[i], sizeof(*block_tables[0]));
3271 if (block_tables[i] == NULL)
3272 goto fail;
3273 // max 2 block links (exits) per block
00a725a8 3274 block_link_pool[i] = calloc(block_link_pool_max_counts[i],
3275 sizeof(*block_link_pool[0]));
3276 if (block_link_pool[i] == NULL)
44e6452e 3277 goto fail;
4943816b 3278
51d86e55 3279 inval_lookup[i] = calloc(ram_sizes[i] / INVAL_PAGE_SIZE,
4943816b 3280 sizeof(inval_lookup[0]));
3281 if (inval_lookup[i] == NULL)
3282 goto fail;
228ee974 3283
3284 hash_tables[i] = calloc(hash_table_sizes[i], sizeof(*hash_tables[0]));
3285 if (hash_tables[i] == NULL)
3286 goto fail;
44e6452e 3287 }
3288 memset(block_counts, 0, sizeof(block_counts));
00a725a8 3289 memset(block_link_pool_counts, 0, sizeof(block_link_pool_counts));
e898de13 3290
44e6452e 3291 drc_cmn_init();
8796b7ee 3292 tcache_ptr = tcache;
3293 sh2_generate_utils();
a2b8c5a5 3294 host_instructions_updated(tcache, tcache_ptr);
8796b7ee 3295
8796b7ee 3296 tcache_bases[0] = tcache_ptrs[0] = tcache_ptr;
44e6452e 3297 for (i = 1; i < ARRAY_SIZE(tcache_bases); i++)
f4bb5d6b 3298 tcache_bases[i] = tcache_ptrs[i] = tcache_bases[i - 1] + tcache_sizes[i - 1];
f4bb5d6b 3299
fcdefcf6 3300#if (DRC_DEBUG & 4)
f4bb5d6b 3301 for (i = 0; i < ARRAY_SIZE(block_tables); i++)
3302 tcache_dsm_ptrs[i] = tcache_bases[i];
8796b7ee 3303 // disasm the utils
3304 tcache_dsm_ptrs[0] = tcache;
3305 do_host_disasm(0);
f4bb5d6b 3306#endif
e898de13 3307#if (DRC_DEBUG & 1)
3308 hash_collisions = 0;
3309#endif
679af8a3 3310 }
3311
679af8a3 3312 return 0;
44e6452e 3313
3314fail:
3315 sh2_drc_finish(sh2);
3316 return -1;
41397701 3317}
3318
e898de13 3319void sh2_drc_finish(SH2 *sh2)
3320{
44e6452e 3321 int i;
3322
228ee974 3323 if (block_tables[0] == NULL)
3324 return;
4943816b 3325
228ee974 3326 sh2_drc_flush_all();
44e6452e 3327
228ee974 3328 for (i = 0; i < TCACHE_BUFFERS; i++) {
fcdefcf6 3329#if (DRC_DEBUG & 4)
228ee974 3330 printf("~~~ tcache %d\n", i);
3331 tcache_dsm_ptrs[i] = tcache_bases[i];
3332 tcache_ptr = tcache_ptrs[i];
3333 do_host_disasm(i);
44e6452e 3334#endif
3335
228ee974 3336 if (block_tables[i] != NULL)
3337 free(block_tables[i]);
3338 block_tables[i] = NULL;
00a725a8 3339 if (block_link_pool[i] == NULL)
3340 free(block_link_pool[i]);
3341 block_link_pool[i] = NULL;
4943816b 3342
228ee974 3343 if (inval_lookup[i] == NULL)
3344 free(inval_lookup[i]);
3345 inval_lookup[i] = NULL;
7f5a3fc1 3346
228ee974 3347 if (hash_tables[i] != NULL) {
3348 free(hash_tables[i]);
3349 hash_tables[i] = NULL;
3350 }
e898de13 3351 }
3352
228ee974 3353 drc_cmn_cleanup();
e898de13 3354}
cff531af 3355
00faec9c 3356#endif /* DRC_SH2 */
3357
3358static void *dr_get_pc_base(u32 pc, int is_slave)
3359{
3360 void *ret = NULL;
3361 u32 mask = 0;
3362
3363 if ((pc & ~0x7ff) == 0) {
3364 // BIOS
895d1512 3365 ret = is_slave ? Pico32xMem->sh2_rom_s.w : Pico32xMem->sh2_rom_m.w;
00faec9c 3366 mask = 0x7ff;
3367 }
3368 else if ((pc & 0xfffff000) == 0xc0000000) {
3369 // data array
f81107f5 3370 ret = sh2s[is_slave].data_array;
00faec9c 3371 mask = 0xfff;
3372 }
3373 else if ((pc & 0xc6000000) == 0x06000000) {
3374 // SDRAM
3375 ret = Pico32xMem->sdram;
3376 mask = 0x03ffff;
3377 }
3378 else if ((pc & 0xc6000000) == 0x02000000) {
3379 // ROM
eb35ce15 3380 if ((pc & 0x3fffff) < Pico.romsize)
3381 ret = Pico.rom;
00faec9c 3382 mask = 0x3fffff;
3383 }
3384
3385 if (ret == NULL)
3386 return (void *)-1; // NULL is valid value
3387
3388 return (char *)ret - (pc & ~mask);
3389}
3390
bf092a36 3391void scan_block(u32 base_pc, int is_slave, u8 *op_flags, u32 *end_pc_out,
3392 u32 *end_literals_out)
00faec9c 3393{
3394 u16 *dr_pc_base;
bf092a36 3395 u32 pc, op, tmp;
3396 u32 end_pc, end_literals = 0;
ee5f7e99 3397 u32 lowest_mova = 0;
bf092a36 3398 struct op_data *opd;
3399 int next_is_delay = 0;
3400 int end_block = 0;
3401 int i, i_end;
00faec9c 3402
e1553677 3403 memset(op_flags, 0, BLOCK_INSN_LIMIT);
00faec9c 3404
3405 dr_pc_base = dr_get_pc_base(base_pc, is_slave);
3406
bf092a36 3407 // 1st pass: disassemble
3408 for (i = 0, pc = base_pc; ; i++, pc += 2) {
3409 // we need an ops[] entry after the last one initialized,
3410 // so do it before end_block checks
3411 opd = &ops[i];
3412 opd->op = OP_UNHANDLED;
3413 opd->rm = -1;
3414 opd->source = opd->dest = 0;
3415 opd->cycles = 1;
3416 opd->imm = 0;
3417
3418 if (next_is_delay) {
3419 op_flags[i] |= OF_DELAY_OP;
3420 next_is_delay = 0;
00faec9c 3421 }
bf092a36 3422 else if (end_block || i >= BLOCK_INSN_LIMIT - 2)
3423 break;
3424
3425 op = FETCH_OP(pc);
3426 switch ((op & 0xf000) >> 12)
3427 {
3428 /////////////////////////////////////////////
3429 case 0x00:
3430 switch (op & 0x0f)
3431 {
3432 case 0x02:
3433 switch (GET_Fx())
3434 {
3435 case 0: // STC SR,Rn 0000nnnn00000010
3436 tmp = SHR_SR;
3437 break;
3438 case 1: // STC GBR,Rn 0000nnnn00010010
3439 tmp = SHR_GBR;
3440 break;
3441 case 2: // STC VBR,Rn 0000nnnn00100010
3442 tmp = SHR_VBR;
3443 break;
3444 default:
3445 goto undefined;
3446 }
3447 opd->op = OP_MOVE;
3448 opd->source = BITMASK1(tmp);
3449 opd->dest = BITMASK1(GET_Rn());
00faec9c 3450 break;
bf092a36 3451 case 0x03:
3452 CHECK_UNHANDLED_BITS(0xd0, undefined);
3453 // BRAF Rm 0000mmmm00100011
3454 // BSRF Rm 0000mmmm00000011
3455 opd->op = OP_BRANCH_RF;
3456 opd->rm = GET_Rn();
3457 opd->source = BITMASK1(opd->rm);
3458 opd->dest = BITMASK1(SHR_PC);
3459 if (!(op & 0x20))
3460 opd->dest |= BITMASK1(SHR_PR);
3461 opd->cycles = 2;
3462 next_is_delay = 1;
3463 end_block = 1;
00faec9c 3464 break;
bf092a36 3465 case 0x04: // MOV.B Rm,@(R0,Rn) 0000nnnnmmmm0100
3466 case 0x05: // MOV.W Rm,@(R0,Rn) 0000nnnnmmmm0101
3467 case 0x06: // MOV.L Rm,@(R0,Rn) 0000nnnnmmmm0110
3468 opd->source = BITMASK3(GET_Rm(), SHR_R0, GET_Rn());
3469 break;
3470 case 0x07:
3471 // MUL.L Rm,Rn 0000nnnnmmmm0111
3472 opd->source = BITMASK2(GET_Rm(), GET_Rn());
3473 opd->dest = BITMASK1(SHR_MACL);
3474 opd->cycles = 2;
3475 break;
3476 case 0x08:
3477 CHECK_UNHANDLED_BITS(0xf00, undefined);
3478 switch (GET_Fx())
3479 {
3480 case 0: // CLRT 0000000000001000
3481 opd->op = OP_SETCLRT;
3482 opd->dest = BITMASK1(SHR_T);
3483 opd->imm = 0;
3484 break;
3485 case 1: // SETT 0000000000011000
3486 opd->op = OP_SETCLRT;
3487 opd->dest = BITMASK1(SHR_T);
3488 opd->imm = 1;
3489 break;
3490 case 2: // CLRMAC 0000000000101000
3491 opd->dest = BITMASK3(SHR_T, SHR_MACL, SHR_MACH);
3492 break;
3493 default:
3494 goto undefined;
3495 }
3496 break;
3497 case 0x09:
3498 switch (GET_Fx())
3499 {
3500 case 0: // NOP 0000000000001001
3501 CHECK_UNHANDLED_BITS(0xf00, undefined);
3502 break;
3503 case 1: // DIV0U 0000000000011001
3504 CHECK_UNHANDLED_BITS(0xf00, undefined);
3505 opd->dest = BITMASK2(SHR_SR, SHR_T);
3506 break;
3507 case 2: // MOVT Rn 0000nnnn00101001
3508 opd->source = BITMASK1(SHR_T);
3509 opd->dest = BITMASK1(GET_Rn());
3510 break;
3511 default:
3512 goto undefined;
3513 }
3514 break;
3515 case 0x0a:
3516 switch (GET_Fx())
3517 {
3518 case 0: // STS MACH,Rn 0000nnnn00001010
3519 tmp = SHR_MACH;
3520 break;
3521 case 1: // STS MACL,Rn 0000nnnn00011010
3522 tmp = SHR_MACL;
3523 break;
3524 case 2: // STS PR,Rn 0000nnnn00101010
3525 tmp = SHR_PR;
3526 break;
3527 default:
3528 goto undefined;
3529 }
3530 opd->op = OP_MOVE;
3531 opd->source = BITMASK1(tmp);
3532 opd->dest = BITMASK1(GET_Rn());
3533 break;
3534 case 0x0b:
3535 CHECK_UNHANDLED_BITS(0xf00, undefined);
3536 switch (GET_Fx())
3537 {
3538 case 0: // RTS 0000000000001011
3539 opd->op = OP_BRANCH_R;
3540 opd->rm = SHR_PR;
3541 opd->source = BITMASK1(opd->rm);
3542 opd->dest = BITMASK1(SHR_PC);
3543 opd->cycles = 2;
3544 next_is_delay = 1;
3545 end_block = 1;
3546 break;
3547 case 1: // SLEEP 0000000000011011
3548 opd->op = OP_SLEEP;
3549 end_block = 1;
3550 break;
3551 case 2: // RTE 0000000000101011
3552 opd->op = OP_RTE;
3553 opd->source = BITMASK1(SHR_SP);
3554 opd->dest = BITMASK2(SHR_SR, SHR_PC);
3555 opd->cycles = 4;
3556 next_is_delay = 1;
3557 end_block = 1;
3558 break;
3559 default:
3560 goto undefined;
3561 }
3562 break;
3563 case 0x0c: // MOV.B @(R0,Rm),Rn 0000nnnnmmmm1100
3564 case 0x0d: // MOV.W @(R0,Rm),Rn 0000nnnnmmmm1101
3565 case 0x0e: // MOV.L @(R0,Rm),Rn 0000nnnnmmmm1110
3566 opd->source = BITMASK2(GET_Rm(), SHR_R0);
3567 opd->dest = BITMASK1(GET_Rn());
3568 break;
3569 case 0x0f: // MAC.L @Rm+,@Rn+ 0000nnnnmmmm1111
3570 opd->source = BITMASK5(GET_Rm(), GET_Rn(), SHR_SR, SHR_MACL, SHR_MACH);
3571 opd->dest = BITMASK4(GET_Rm(), GET_Rn(), SHR_MACL, SHR_MACH);
3572 opd->cycles = 3;
3573 break;
3574 default:
3575 goto undefined;
3576 }
3577 break;
3578
3579 /////////////////////////////////////////////
3580 case 0x01:
3581 // MOV.L Rm,@(disp,Rn) 0001nnnnmmmmdddd
3582 opd->source = BITMASK1(GET_Rm());
3583 opd->source = BITMASK1(GET_Rn());
3584 opd->imm = (op & 0x0f) * 4;
3585 break;
3586
3587 /////////////////////////////////////////////
3588 case 0x02:
3589 switch (op & 0x0f)
3590 {
3591 case 0x00: // MOV.B Rm,@Rn 0010nnnnmmmm0000
3592 case 0x01: // MOV.W Rm,@Rn 0010nnnnmmmm0001
3593 case 0x02: // MOV.L Rm,@Rn 0010nnnnmmmm0010
3594 opd->source = BITMASK1(GET_Rm());
3595 opd->source = BITMASK1(GET_Rn());
3596 break;
f2dde871 3597 case 0x04: // MOV.B Rm,@-Rn 0010nnnnmmmm0100
3598 case 0x05: // MOV.W Rm,@-Rn 0010nnnnmmmm0101
3599 case 0x06: // MOV.L Rm,@-Rn 0010nnnnmmmm0110
bf092a36 3600 opd->source = BITMASK2(GET_Rm(), GET_Rn());
3601 opd->dest = BITMASK1(GET_Rn());
3602 break;
3603 case 0x07: // DIV0S Rm,Rn 0010nnnnmmmm0111
3604 opd->source = BITMASK2(GET_Rm(), GET_Rn());
3605 opd->dest = BITMASK1(SHR_SR);
3606 break;
3607 case 0x08: // TST Rm,Rn 0010nnnnmmmm1000
3608 opd->source = BITMASK2(GET_Rm(), GET_Rn());
3609 opd->dest = BITMASK1(SHR_T);
3610 break;
3611 case 0x09: // AND Rm,Rn 0010nnnnmmmm1001
3612 case 0x0a: // XOR Rm,Rn 0010nnnnmmmm1010
3613 case 0x0b: // OR Rm,Rn 0010nnnnmmmm1011
3614 opd->source = BITMASK2(GET_Rm(), GET_Rn());
3615 opd->dest = BITMASK1(GET_Rn());
3616 break;
3617 case 0x0c: // CMP/STR Rm,Rn 0010nnnnmmmm1100
3618 opd->source = BITMASK2(GET_Rm(), GET_Rn());
3619 opd->dest = BITMASK1(SHR_T);
3620 break;
3621 case 0x0d: // XTRCT Rm,Rn 0010nnnnmmmm1101
3622 opd->source = BITMASK2(GET_Rm(), GET_Rn());
3623 opd->dest = BITMASK1(GET_Rn());
3624 break;
3625 case 0x0e: // MULU.W Rm,Rn 0010nnnnmmmm1110
3626 case 0x0f: // MULS.W Rm,Rn 0010nnnnmmmm1111
3627 opd->source = BITMASK2(GET_Rm(), GET_Rn());
3628 opd->dest = BITMASK1(SHR_MACL);
3629 break;
3630 default:
3631 goto undefined;
3632 }
3633 break;
3634
3635 /////////////////////////////////////////////
3636 case 0x03:
3637 switch (op & 0x0f)
3638 {
3639 case 0x00: // CMP/EQ Rm,Rn 0011nnnnmmmm0000
3640 case 0x02: // CMP/HS Rm,Rn 0011nnnnmmmm0010
3641 case 0x03: // CMP/GE Rm,Rn 0011nnnnmmmm0011
3642 case 0x06: // CMP/HI Rm,Rn 0011nnnnmmmm0110
3643 case 0x07: // CMP/GT Rm,Rn 0011nnnnmmmm0111
3644 opd->source = BITMASK2(GET_Rm(), GET_Rn());
3645 opd->dest = BITMASK1(SHR_T);
3646 break;
3647 case 0x04: // DIV1 Rm,Rn 0011nnnnmmmm0100
3648 opd->source = BITMASK3(GET_Rm(), GET_Rn(), SHR_SR);
3649 opd->dest = BITMASK2(GET_Rn(), SHR_SR);
3650 break;
3651 case 0x05: // DMULU.L Rm,Rn 0011nnnnmmmm0101
3652 case 0x0d: // DMULS.L Rm,Rn 0011nnnnmmmm1101
3653 opd->source = BITMASK2(GET_Rm(), GET_Rn());
3654 opd->dest = BITMASK2(SHR_MACL, SHR_MACH);
3655 opd->cycles = 2;
3656 break;
3657 case 0x08: // SUB Rm,Rn 0011nnnnmmmm1000
3658 case 0x0c: // ADD Rm,Rn 0011nnnnmmmm1100
3659 opd->source = BITMASK2(GET_Rm(), GET_Rn());
3660 opd->dest = BITMASK1(GET_Rn());
3661 break;
3662 case 0x0a: // SUBC Rm,Rn 0011nnnnmmmm1010
3663 case 0x0e: // ADDC Rm,Rn 0011nnnnmmmm1110
3664 opd->source = BITMASK3(GET_Rm(), GET_Rn(), SHR_T);
3665 opd->dest = BITMASK2(GET_Rn(), SHR_T);
3666 break;
3667 case 0x0b: // SUBV Rm,Rn 0011nnnnmmmm1011
3668 case 0x0f: // ADDV Rm,Rn 0011nnnnmmmm1111
3669 opd->source = BITMASK2(GET_Rm(), GET_Rn());
3670 opd->dest = BITMASK2(GET_Rn(), SHR_T);
3671 break;
3672 default:
3673 goto undefined;
3674 }
3675 break;
3676
3677 /////////////////////////////////////////////
3678 case 0x04:
3679 switch (op & 0x0f)
3680 {
3681 case 0x00:
3682 switch (GET_Fx())
3683 {
3684 case 0: // SHLL Rn 0100nnnn00000000
3685 case 2: // SHAL Rn 0100nnnn00100000
3686 opd->source = BITMASK1(GET_Rn());
3687 opd->dest = BITMASK2(GET_Rn(), SHR_T);
3688 break;
3689 case 1: // DT Rn 0100nnnn00010000
3690 opd->source = BITMASK1(GET_Rn());
3691 opd->dest = BITMASK2(GET_Rn(), SHR_T);
3692 break;
3693 default:
3694 goto undefined;
3695 }
3696 break;
3697 case 0x01:
3698 switch (GET_Fx())
3699 {
3700 case 0: // SHLR Rn 0100nnnn00000001
3701 case 2: // SHAR Rn 0100nnnn00100001
3702 opd->source = BITMASK1(GET_Rn());
3703 opd->dest = BITMASK2(GET_Rn(), SHR_T);
3704 break;
3705 case 1: // CMP/PZ Rn 0100nnnn00010001
3706 opd->source = BITMASK1(GET_Rn());
3707 opd->dest = BITMASK1(SHR_T);
3708 break;
3709 default:
3710 goto undefined;
3711 }
3712 break;
3713 case 0x02:
3714 case 0x03:
3715 switch (op & 0x3f)
3716 {
f2dde871 3717 case 0x02: // STS.L MACH,@-Rn 0100nnnn00000010
bf092a36 3718 tmp = SHR_MACH;
3719 break;
f2dde871 3720 case 0x12: // STS.L MACL,@-Rn 0100nnnn00010010
bf092a36 3721 tmp = SHR_MACL;
3722 break;
f2dde871 3723 case 0x22: // STS.L PR,@-Rn 0100nnnn00100010
bf092a36 3724 tmp = SHR_PR;
3725 break;
f2dde871 3726 case 0x03: // STC.L SR,@-Rn 0100nnnn00000011
bf092a36 3727 tmp = SHR_SR;
3728 opd->cycles = 2;
3729 break;
f2dde871 3730 case 0x13: // STC.L GBR,@-Rn 0100nnnn00010011
bf092a36 3731 tmp = SHR_GBR;
3732 opd->cycles = 2;
3733 break;
f2dde871 3734 case 0x23: // STC.L VBR,@-Rn 0100nnnn00100011
bf092a36 3735 tmp = SHR_VBR;
3736 opd->cycles = 2;
3737 break;
3738 default:
3739 goto undefined;
3740 }
3741 opd->source = BITMASK2(GET_Rn(), tmp);
3742 opd->dest = BITMASK1(GET_Rn());
3743 break;
3744 case 0x04:
3745 case 0x05:
3746 switch (op & 0x3f)
3747 {
3748 case 0x04: // ROTL Rn 0100nnnn00000100
3749 case 0x05: // ROTR Rn 0100nnnn00000101
3750 opd->source = BITMASK1(GET_Rn());
3751 opd->dest = BITMASK2(GET_Rn(), SHR_T);
3752 break;
3753 case 0x24: // ROTCL Rn 0100nnnn00100100
3754 case 0x25: // ROTCR Rn 0100nnnn00100101
3755 opd->source = BITMASK2(GET_Rn(), SHR_T);
3756 opd->dest = BITMASK2(GET_Rn(), SHR_T);
3757 break;
3758 case 0x15: // CMP/PL Rn 0100nnnn00010101
3759 opd->source = BITMASK1(GET_Rn());
3760 opd->dest = BITMASK1(SHR_T);
3761 break;
3762 default:
3763 goto undefined;
3764 }
3765 break;
3766 case 0x06:
3767 case 0x07:
3768 switch (op & 0x3f)
3769 {
3770 case 0x06: // LDS.L @Rm+,MACH 0100mmmm00000110
3771 tmp = SHR_MACH;
3772 break;
3773 case 0x16: // LDS.L @Rm+,MACL 0100mmmm00010110
3774 tmp = SHR_MACL;
3775 break;
3776 case 0x26: // LDS.L @Rm+,PR 0100mmmm00100110
3777 tmp = SHR_PR;
3778 break;
3779 case 0x07: // LDC.L @Rm+,SR 0100mmmm00000111
3780 tmp = SHR_SR;
3781 opd->cycles = 3;
3782 break;
3783 case 0x17: // LDC.L @Rm+,GBR 0100mmmm00010111
3784 tmp = SHR_GBR;
3785 opd->cycles = 3;
3786 break;
3787 case 0x27: // LDC.L @Rm+,VBR 0100mmmm00100111
3788 tmp = SHR_VBR;
3789 opd->cycles = 3;
3790 break;
3791 default:
3792 goto undefined;
3793 }
3794 opd->source = BITMASK1(GET_Rn());
3795 opd->dest = BITMASK2(GET_Rn(), tmp);
3796 break;
3797 case 0x08:
3798 case 0x09:
3799 switch (GET_Fx())
3800 {
3801 case 0:
3802 // SHLL2 Rn 0100nnnn00001000
3803 // SHLR2 Rn 0100nnnn00001001
3804 break;
3805 case 1:
3806 // SHLL8 Rn 0100nnnn00011000
3807 // SHLR8 Rn 0100nnnn00011001
3808 break;
3809 case 2:
3810 // SHLL16 Rn 0100nnnn00101000
3811 // SHLR16 Rn 0100nnnn00101001
3812 break;
3813 default:
3814 goto undefined;
3815 }
3816 opd->source = BITMASK1(GET_Rn());
3817 opd->dest = BITMASK1(GET_Rn());
3818 break;
3819 case 0x0a:
3820 switch (GET_Fx())
3821 {
3822 case 0: // LDS Rm,MACH 0100mmmm00001010
3823 tmp = SHR_MACH;
3824 break;
3825 case 1: // LDS Rm,MACL 0100mmmm00011010
3826 tmp = SHR_MACL;
3827 break;
3828 case 2: // LDS Rm,PR 0100mmmm00101010
3829 tmp = SHR_PR;
3830 break;
3831 default:
3832 goto undefined;
3833 }
3834 opd->op = OP_MOVE;
3835 opd->source = BITMASK1(GET_Rn());
3836 opd->dest = BITMASK1(tmp);
3837 break;
3838 case 0x0b:
3839 switch (GET_Fx())
3840 {
3841 case 0: // JSR @Rm 0100mmmm00001011
3842 opd->dest = BITMASK1(SHR_PR);
3843 case 2: // JMP @Rm 0100mmmm00101011
3844 opd->op = OP_BRANCH_R;
3845 opd->rm = GET_Rn();
3846 opd->source = BITMASK1(opd->rm);
3847 opd->dest |= BITMASK1(SHR_PC);
3848 opd->cycles = 2;
3849 next_is_delay = 1;
3850 end_block = 1;
3851 break;
3852 case 1: // TAS.B @Rn 0100nnnn00011011
3853 opd->source = BITMASK1(GET_Rn());
3854 opd->dest = BITMASK1(SHR_T);
3855 opd->cycles = 4;
3856 break;
3857 default:
3858 goto undefined;
3859 }
3860 break;
3861 case 0x0e:
3862 switch (GET_Fx())
3863 {
3864 case 0: // LDC Rm,SR 0100mmmm00001110
3865 tmp = SHR_SR;
3866 break;
3867 case 1: // LDC Rm,GBR 0100mmmm00011110
3868 tmp = SHR_GBR;
3869 break;
3870 case 2: // LDC Rm,VBR 0100mmmm00101110
3871 tmp = SHR_VBR;
3872 break;
3873 default:
3874 goto undefined;
3875 }
3876 opd->op = OP_MOVE;
3877 opd->source = BITMASK1(GET_Rn());
3878 opd->dest = BITMASK1(tmp);
3879 break;
3880 case 0x0f:
3881 // MAC.W @Rm+,@Rn+ 0100nnnnmmmm1111
3882 opd->source = BITMASK5(GET_Rm(), GET_Rn(), SHR_SR, SHR_MACL, SHR_MACH);
3883 opd->dest = BITMASK4(GET_Rm(), GET_Rn(), SHR_MACL, SHR_MACH);
3884 opd->cycles = 3;
3885 break;
3886 default:
3887 goto undefined;
3888 }
3889 break;
3890
3891 /////////////////////////////////////////////
3892 case 0x05:
3893 // MOV.L @(disp,Rm),Rn 0101nnnnmmmmdddd
3894 opd->source = BITMASK1(GET_Rm());
3895 opd->dest = BITMASK1(GET_Rn());
3896 opd->imm = (op & 0x0f) * 4;
3897 break;
3898
3899 /////////////////////////////////////////////
3900 case 0x06:
3901 switch (op & 0x0f)
3902 {
3903 case 0x04: // MOV.B @Rm+,Rn 0110nnnnmmmm0100
3904 case 0x05: // MOV.W @Rm+,Rn 0110nnnnmmmm0101
3905 case 0x06: // MOV.L @Rm+,Rn 0110nnnnmmmm0110
3906 opd->dest = BITMASK1(GET_Rm());
3907 case 0x00: // MOV.B @Rm,Rn 0110nnnnmmmm0000
3908 case 0x01: // MOV.W @Rm,Rn 0110nnnnmmmm0001
3909 case 0x02: // MOV.L @Rm,Rn 0110nnnnmmmm0010
3910 opd->source = BITMASK1(GET_Rm());
3911 opd->dest |= BITMASK1(GET_Rn());
3912 break;
fa841b44 3913 case 0x0a: // NEGC Rm,Rn 0110nnnnmmmm1010
3914 opd->source = BITMASK2(GET_Rm(), SHR_T);
3915 opd->dest = BITMASK2(GET_Rn(), SHR_T);
3916 break;
bf092a36 3917 case 0x03: // MOV Rm,Rn 0110nnnnmmmm0011
3918 opd->op = OP_MOVE;
3919 goto arith_rmrn;
3920 case 0x07: // NOT Rm,Rn 0110nnnnmmmm0111
3921 case 0x08: // SWAP.B Rm,Rn 0110nnnnmmmm1000
3922 case 0x09: // SWAP.W Rm,Rn 0110nnnnmmmm1001
bf092a36 3923 case 0x0b: // NEG Rm,Rn 0110nnnnmmmm1011
3924 case 0x0c: // EXTU.B Rm,Rn 0110nnnnmmmm1100
3925 case 0x0d: // EXTU.W Rm,Rn 0110nnnnmmmm1101
3926 case 0x0e: // EXTS.B Rm,Rn 0110nnnnmmmm1110
3927 case 0x0f: // EXTS.W Rm,Rn 0110nnnnmmmm1111
3928 arith_rmrn:
3929 opd->source = BITMASK1(GET_Rm());
3930 opd->dest = BITMASK1(GET_Rn());
3931 break;
3932 }
3933 break;
3934
3935 /////////////////////////////////////////////
3936 case 0x07:
3937 // ADD #imm,Rn 0111nnnniiiiiiii
3938 opd->source = opd->dest = BITMASK1(GET_Rn());
3939 opd->imm = (int)(signed char)op;
3940 break;
3941
3942 /////////////////////////////////////////////
3943 case 0x08:
3944 switch (op & 0x0f00)
3945 {
3946 case 0x0000: // MOV.B R0,@(disp,Rn) 10000000nnnndddd
3947 opd->source = BITMASK2(GET_Rm(), SHR_R0);
3948 opd->imm = (op & 0x0f);
3949 break;
3950 case 0x0100: // MOV.W R0,@(disp,Rn) 10000001nnnndddd
3951 opd->source = BITMASK2(GET_Rm(), SHR_R0);
3952 opd->imm = (op & 0x0f) * 2;
3953 break;
3954 case 0x0400: // MOV.B @(disp,Rm),R0 10000100mmmmdddd
3955 opd->source = BITMASK1(GET_Rm());
3956 opd->dest = BITMASK1(SHR_R0);
3957 opd->imm = (op & 0x0f);
3958 break;
3959 case 0x0500: // MOV.W @(disp,Rm),R0 10000101mmmmdddd
3960 opd->source = BITMASK1(GET_Rm());
3961 opd->dest = BITMASK1(SHR_R0);
3962 opd->imm = (op & 0x0f) * 2;
3963 break;
3964 case 0x0800: // CMP/EQ #imm,R0 10001000iiiiiiii
3965 opd->source = BITMASK1(SHR_R0);
3966 opd->dest = BITMASK1(SHR_T);
3967 opd->imm = (int)(signed char)op;
3968 break;
3969 case 0x0d00: // BT/S label 10001101dddddddd
3970 case 0x0f00: // BF/S label 10001111dddddddd
3971 next_is_delay = 1;
3972 // fallthrough
3973 case 0x0900: // BT label 10001001dddddddd
3974 case 0x0b00: // BF label 10001011dddddddd
3975 opd->op = (op & 0x0200) ? OP_BRANCH_CF : OP_BRANCH_CT;
3976 opd->source = BITMASK1(SHR_T);
3977 opd->dest = BITMASK1(SHR_PC);
3978 opd->imm = ((signed int)(op << 24) >> 23);
3979 opd->imm += pc + 4;
3980 if (base_pc <= opd->imm && opd->imm < base_pc + BLOCK_INSN_LIMIT * 2)
3981 op_flags[(opd->imm - base_pc) / 2] |= OF_BTARGET;
3982 break;
3983 default:
3984 goto undefined;
3985 }
3986 break;
3987
3988 /////////////////////////////////////////////
3989 case 0x09:
3990 // MOV.W @(disp,PC),Rn 1001nnnndddddddd
3991 opd->op = OP_LOAD_POOL;
fa841b44 3992 tmp = pc + 2;
3993 if (op_flags[i] & OF_DELAY_OP) {
3994 if (ops[i-1].op == OP_BRANCH)
3995 tmp = ops[i-1].imm;
3996 else
3997 tmp = 0;
3998 }
bf092a36 3999 opd->source = BITMASK1(SHR_PC);
4000 opd->dest = BITMASK1(GET_Rn());
fa841b44 4001 if (tmp)
4002 opd->imm = tmp + 2 + (op & 0xff) * 2;
bf092a36 4003 opd->size = 1;
4004 break;
4005
4006 /////////////////////////////////////////////
4007 case 0x0b:
4008 // BSR label 1011dddddddddddd
4009 opd->dest = BITMASK1(SHR_PR);
4010 case 0x0a:
4011 // BRA label 1010dddddddddddd
4012 opd->op = OP_BRANCH;
4013 opd->dest |= BITMASK1(SHR_PC);
4014 opd->imm = ((signed int)(op << 20) >> 19);
4015 opd->imm += pc + 4;
4016 opd->cycles = 2;
4017 next_is_delay = 1;
4018 end_block = 1;
4019 if (base_pc <= opd->imm && opd->imm < base_pc + BLOCK_INSN_LIMIT * 2)
4020 op_flags[(opd->imm - base_pc) / 2] |= OF_BTARGET;
4021 break;
4022
4023 /////////////////////////////////////////////
4024 case 0x0c:
4025 switch (op & 0x0f00)
4026 {
4027 case 0x0000: // MOV.B R0,@(disp,GBR) 11000000dddddddd
4028 case 0x0100: // MOV.W R0,@(disp,GBR) 11000001dddddddd
4029 case 0x0200: // MOV.L R0,@(disp,GBR) 11000010dddddddd
4030 opd->source = BITMASK2(SHR_GBR, SHR_R0);
4031 opd->size = (op & 0x300) >> 8;
4032 opd->imm = (op & 0xff) << opd->size;
4033 break;
4034 case 0x0400: // MOV.B @(disp,GBR),R0 11000100dddddddd
4035 case 0x0500: // MOV.W @(disp,GBR),R0 11000101dddddddd
4036 case 0x0600: // MOV.L @(disp,GBR),R0 11000110dddddddd
4037 opd->source = BITMASK1(SHR_GBR);
4038 opd->dest = BITMASK1(SHR_R0);
4039 opd->size = (op & 0x300) >> 8;
4040 opd->imm = (op & 0xff) << opd->size;
4041 break;
4042 case 0x0300: // TRAPA #imm 11000011iiiiiiii
4043 opd->source = BITMASK2(SHR_PC, SHR_SR);
4044 opd->dest = BITMASK1(SHR_PC);
4045 opd->imm = (op & 0xff) * 4;
4046 opd->cycles = 8;
4047 end_block = 1; // FIXME
4048 break;
4049 case 0x0700: // MOVA @(disp,PC),R0 11000111dddddddd
fa841b44 4050 opd->op = OP_MOVA;
4051 tmp = pc + 2;
4052 if (op_flags[i] & OF_DELAY_OP) {
4053 if (ops[i-1].op == OP_BRANCH)
4054 tmp = ops[i-1].imm;
4055 else
4056 tmp = 0;
4057 }
bf092a36 4058 opd->dest = BITMASK1(SHR_R0);
ee5f7e99 4059 if (tmp) {
fa841b44 4060 opd->imm = (tmp + 2 + (op & 0xff) * 4) & ~3;
ee5f7e99 4061 if (opd->imm >= base_pc) {
4062 if (lowest_mova == 0 || opd->imm < lowest_mova)
4063 lowest_mova = opd->imm;
4064 }
4065 }
bf092a36 4066 break;
4067 case 0x0800: // TST #imm,R0 11001000iiiiiiii
4068 opd->source = BITMASK1(SHR_R0);
4069 opd->dest = BITMASK1(SHR_T);
4070 opd->imm = op & 0xff;
4071 break;
4072 case 0x0900: // AND #imm,R0 11001001iiiiiiii
4073 opd->source = opd->dest = BITMASK1(SHR_R0);
4074 opd->imm = op & 0xff;
4075 break;
4076 case 0x0a00: // XOR #imm,R0 11001010iiiiiiii
4077 opd->source = opd->dest = BITMASK1(SHR_R0);
4078 opd->imm = op & 0xff;
4079 break;
4080 case 0x0b00: // OR #imm,R0 11001011iiiiiiii
4081 opd->source = opd->dest = BITMASK1(SHR_R0);
4082 opd->imm = op & 0xff;
4083 break;
4084 case 0x0c00: // TST.B #imm,@(R0,GBR) 11001100iiiiiiii
4085 opd->source = BITMASK2(SHR_GBR, SHR_R0);
4086 opd->dest = BITMASK1(SHR_T);
4087 opd->imm = op & 0xff;
4088 opd->cycles = 3;
4089 break;
4090 case 0x0d00: // AND.B #imm,@(R0,GBR) 11001101iiiiiiii
4091 case 0x0e00: // XOR.B #imm,@(R0,GBR) 11001110iiiiiiii
4092 case 0x0f00: // OR.B #imm,@(R0,GBR) 11001111iiiiiiii
4093 opd->source = BITMASK2(SHR_GBR, SHR_R0);
4094 opd->imm = op & 0xff;
4095 opd->cycles = 3;
4096 break;
4097 default:
4098 goto undefined;
4099 }
4100 break;
4101
4102 /////////////////////////////////////////////
4103 case 0x0d:
4104 // MOV.L @(disp,PC),Rn 1101nnnndddddddd
4105 opd->op = OP_LOAD_POOL;
fa841b44 4106 tmp = pc + 2;
4107 if (op_flags[i] & OF_DELAY_OP) {
4108 if (ops[i-1].op == OP_BRANCH)
4109 tmp = ops[i-1].imm;
4110 else
4111 tmp = 0;
4112 }
bf092a36 4113 opd->source = BITMASK1(SHR_PC);
4114 opd->dest = BITMASK1(GET_Rn());
fa841b44 4115 if (tmp)
4116 opd->imm = (tmp + 2 + (op & 0xff) * 4) & ~3;
bf092a36 4117 opd->size = 2;
4118 break;
4119
4120 /////////////////////////////////////////////
4121 case 0x0e:
4122 // MOV #imm,Rn 1110nnnniiiiiiii
4123 opd->dest = BITMASK1(GET_Rn());
4124 opd->imm = (u32)(signed int)(signed char)op;
4125 break;
4126
4127 default:
4128 undefined:
4129 elprintf(EL_ANOMALY, "%csh2 drc: unhandled op %04x @ %08x",
4130 is_slave ? 's' : 'm', op, pc);
4131 break;
4132 }
6a5b1b36 4133
4134 if (op_flags[i] & OF_DELAY_OP) {
4135 switch (opd->op) {
4136 case OP_BRANCH:
4137 case OP_BRANCH_CT:
4138 case OP_BRANCH_CF:
4139 case OP_BRANCH_R:
4140 case OP_BRANCH_RF:
4141 elprintf(EL_ANOMALY, "%csh2 drc: branch in DS @ %08x",
4142 is_slave ? 's' : 'm', pc);
4143 opd->op = OP_UNHANDLED;
4144 op_flags[i] |= OF_B_IN_DS;
4145 next_is_delay = 0;
4146 break;
4147 }
4148 }
bf092a36 4149 }
4150 i_end = i;
4151 end_pc = pc;
4152
4153 // 2nd pass: some analysis
4154 for (i = 0; i < i_end; i++) {
4155 opd = &ops[i];
4156
4157 // propagate T (TODO: DIV0U)
4158 if ((opd->op == OP_SETCLRT && !opd->imm) || opd->op == OP_BRANCH_CT)
4159 op_flags[i + 1] |= OF_T_CLEAR;
4160 else if ((opd->op == OP_SETCLRT && opd->imm) || opd->op == OP_BRANCH_CF)
4161 op_flags[i + 1] |= OF_T_SET;
4162
4163 if ((op_flags[i] & OF_BTARGET) || (opd->dest & BITMASK1(SHR_T)))
4164 op_flags[i] &= ~(OF_T_SET | OF_T_CLEAR);
4165 else
4166 op_flags[i + 1] |= op_flags[i] & (OF_T_SET | OF_T_CLEAR);
4167
4168 if ((opd->op == OP_BRANCH_CT && (op_flags[i] & OF_T_SET))
4169 || (opd->op == OP_BRANCH_CF && (op_flags[i] & OF_T_CLEAR)))
4170 {
4171 opd->op = OP_BRANCH;
4172 opd->cycles = 3;
4173 i_end = i + 1;
4174 if (op_flags[i + 1] & OF_DELAY_OP) {
4175 opd->cycles = 2;
4176 i_end++;
4177 }
4178 }
4179 else if (opd->op == OP_LOAD_POOL)
4180 {
4181 if (opd->imm < end_pc + MAX_LITERAL_OFFSET) {
4182 if (end_literals < opd->imm + opd->size * 2)
4183 end_literals = opd->imm + opd->size * 2;
4184 }
4185 }
4186 }
4187 end_pc = base_pc + i_end * 2;
4188 if (end_literals < end_pc)
4189 end_literals = end_pc;
4190
ee5f7e99 4191 // end_literals is used to decide to inline a literal or not
4192 // XXX: need better detection if this actually is used in write
4193 if (lowest_mova >= base_pc) {
4194 if (lowest_mova < end_literals) {
4195 dbg(1, "mova for %08x, block %08x", lowest_mova, base_pc);
4196 end_literals = end_pc;
4197 }
4198 if (lowest_mova < end_pc) {
4199 dbg(1, "warning: mova inside of blk for %08x, block %08x",
4200 lowest_mova, base_pc);
4201 end_literals = end_pc;
4202 }
4203 }
4204
bf092a36 4205 *end_pc_out = end_pc;
4206 if (end_literals_out != NULL)
4207 *end_literals_out = end_literals;
00faec9c 4208}
4209
5f0ca48f 4210// vim:shiftwidth=2:ts=2:expandtab