32x: drc: handlers wip
[picodrive.git] / cpu / sh2 / compiler.c
... / ...
CommitLineData
1/*
2 * vim:shiftwidth=2:expandtab
3 */
4#include <stdio.h>
5#include <stdlib.h>
6#include <assert.h>
7
8#include "../../pico/pico_int.h"
9#include "sh2.h"
10#include "compiler.h"
11#include "../drc/cmn.h"
12
13#ifndef DRC_DEBUG
14#define DRC_DEBUG 0
15#endif
16
17#if DRC_DEBUG
18#define dbg(l,...) { \
19 if ((l) & DRC_DEBUG) \
20 elprintf(EL_STATUS, ##__VA_ARGS__); \
21}
22
23#include "mame/sh2dasm.h"
24#include <platform/linux/host_dasm.h>
25static int insns_compiled, hash_collisions, host_insn_count;
26#define COUNT_OP \
27 host_insn_count++
28#else // !DRC_DEBUG
29#define COUNT_OP
30#define dbg(...)
31#endif
32
33#if (DRC_DEBUG & 2)
34static u8 *tcache_dsm_ptrs[3];
35static char sh2dasm_buff[64];
36#define do_host_disasm(tcid) \
37 host_dasm(tcache_dsm_ptrs[tcid], tcache_ptr - tcache_dsm_ptrs[tcid]); \
38 tcache_dsm_ptrs[tcid] = tcache_ptr
39#else
40#define do_host_disasm(x)
41#endif
42
43#define BLOCK_CYCLE_LIMIT 100
44#define MAX_BLOCK_SIZE (BLOCK_CYCLE_LIMIT * 6 * 6)
45
46// we have 3 translation cache buffers, split from one drc/cmn buffer.
47// BIOS shares tcache with data array because it's only used for init
48// and can be discarded early
49static const int tcache_sizes[3] = {
50 DRC_TCACHE_SIZE * 6 / 8, // ROM, DRAM
51 DRC_TCACHE_SIZE / 8, // BIOS, data array in master sh2
52 DRC_TCACHE_SIZE / 8, // ... slave
53};
54
55static u8 *tcache_bases[3];
56static u8 *tcache_ptrs[3];
57
58// ptr for code emiters
59static u8 *tcache_ptr;
60
61// host register tracking
62enum {
63 HR_FREE,
64 HR_CACHED, // 'val' has sh2_reg_e
65 HR_CACHED_DIRTY,
66 HR_CONST, // 'val' has constant
67 HR_TEMP, // reg used for temp storage
68};
69
70typedef struct {
71 u8 reg;
72 u8 type;
73 u16 stamp; // kind of a timestamp
74 u32 val;
75} temp_reg_t;
76
77// note: reg_temp[] must have at least the amount of
78// registers used by handlers in worst case (currently 3?)
79#ifdef ARM
80#include "../drc/emit_arm.c"
81
82static const int reg_map_g2h[] = {
83 -1, -1, -1, -1,
84 -1, -1, -1, -1,
85 -1, -1, -1, -1,
86 -1, -1, -1, -1,
87 -1, -1, -1, -1,
88 -1, -1, -1, -1,
89};
90
91static temp_reg_t reg_temp[] = {
92 { 0, },
93 { 1, },
94 { 12, },
95 { 14, },
96 { 2, },
97 { 3, },
98};
99
100#else
101#include "../drc/emit_x86.c"
102
103static const int reg_map_g2h[] = {
104 -1, -1, -1, -1,
105 -1, -1, -1, -1,
106 -1, -1, -1, -1,
107 -1, -1, -1, -1,
108 -1, -1, -1, -1,
109 -1, -1, -1, -1,
110};
111
112// ax, cx, dx are usually temporaries
113static temp_reg_t reg_temp[] = {
114 { xAX, },
115 { xCX, },
116 { xDX, },
117};
118
119#endif
120
121#define T 0x00000001
122#define S 0x00000002
123#define I 0x000000f0
124#define Q 0x00000100
125#define M 0x00000200
126
127typedef enum {
128 SHR_R0 = 0, SHR_R15 = 15,
129 SHR_PC, SHR_PPC, SHR_PR, SHR_SR,
130 SHR_GBR, SHR_VBR, SHR_MACH, SHR_MACL,
131} sh2_reg_e;
132
133typedef struct block_desc_ {
134 u32 addr; // SH2 PC address
135 u32 end_addr; // TODO rm?
136 void *tcache_ptr; // translated block for above PC
137 struct block_desc_ *next; // next block with the same PC hash
138#if (DRC_DEBUG & 1)
139 int refcount;
140#endif
141} block_desc;
142
143static const int block_max_counts[3] = {
144 4*1024,
145 256,
146 256,
147};
148static block_desc *block_tables[3];
149static int block_counts[3];
150
151// ROM hash table
152#define MAX_HASH_ENTRIES 1024
153#define HASH_MASK (MAX_HASH_ENTRIES - 1)
154static void **hash_table;
155
156extern void sh2_drc_entry(SH2 *sh2, void *block);
157extern void sh2_drc_exit(void);
158
159// tmp
160extern void REGPARM(2) sh2_do_op(SH2 *sh2, int opcode);
161static void REGPARM(1) sh2_test_irq(SH2 *sh2);
162
163static void flush_tcache(int tcid)
164{
165 dbg(1, "tcache #%d flush! (%d/%d, bds %d/%d)", tcid,
166 tcache_ptrs[tcid] - tcache_bases[tcid], tcache_sizes[tcid],
167 block_counts[tcid], block_max_counts[tcid]);
168
169 block_counts[tcid] = 0;
170 tcache_ptrs[tcid] = tcache_bases[tcid];
171 if (tcid == 0) { // ROM, RAM
172 memset(hash_table, 0, sizeof(hash_table[0]) * MAX_HASH_ENTRIES);
173 memset(Pico32xMem->drcblk_ram, 0, sizeof(Pico32xMem->drcblk_ram));
174 }
175 else
176 memset(Pico32xMem->drcblk_da[tcid - 1], 0, sizeof(Pico32xMem->drcblk_da[0]));
177#if (DRC_DEBUG & 2)
178 tcache_dsm_ptrs[tcid] = tcache_bases[tcid];
179#endif
180}
181
182static void *dr_find_block(block_desc *tab, u32 addr)
183{
184 for (tab = tab->next; tab != NULL; tab = tab->next)
185 if (tab->addr == addr)
186 break;
187
188 if (tab != NULL)
189 return tab->tcache_ptr;
190
191 printf("block miss for %08x\n", addr);
192 return NULL;
193}
194
195static block_desc *dr_add_block(u32 addr, int tcache_id, int *blk_id)
196{
197 int *bcount = &block_counts[tcache_id];
198 block_desc *bd;
199
200 if (*bcount >= block_max_counts[tcache_id])
201 return NULL;
202
203 bd = &block_tables[tcache_id][*bcount];
204 bd->addr = addr;
205 bd->tcache_ptr = tcache_ptr;
206 *blk_id = *bcount;
207 (*bcount)++;
208
209 return bd;
210}
211
212#define HASH_FUNC(hash_tab, addr) \
213 ((block_desc **)(hash_tab))[(addr) & HASH_MASK]
214
215// ---------------------------------------------------------------
216
217// register chache
218static u16 rcache_counter;
219
220static temp_reg_t *rcache_evict(void)
221{
222 // evict reg with oldest stamp
223 int i, oldest = -1;
224 u16 min_stamp = (u16)-1;
225
226 for (i = 0; i < ARRAY_SIZE(reg_temp); i++) {
227 if (reg_temp[i].type == HR_CACHED || reg_temp[i].type == HR_CACHED_DIRTY)
228 if (reg_temp[i].stamp <= min_stamp) {
229 min_stamp = reg_temp[i].stamp;
230 oldest = i;
231 }
232 }
233
234 if (oldest == -1) {
235 printf("no registers to evict, aborting\n");
236 exit(1);
237 }
238
239 i = oldest;
240 if (reg_temp[i].type == HR_CACHED_DIRTY) {
241 // writeback
242 emith_ctx_write(reg_temp[i].reg, reg_temp[i].val * 4);
243 }
244
245 return &reg_temp[i];
246}
247
248typedef enum {
249 RC_GR_READ,
250 RC_GR_WRITE,
251 RC_GR_RMW,
252} rc_gr_mode;
253
254// note: must not be called when doing conditional code
255static int rcache_get_reg(sh2_reg_e r, rc_gr_mode mode)
256{
257 temp_reg_t *tr;
258 int i;
259
260 // maybe already statically mapped?
261 i = reg_map_g2h[r];
262 if (i != -1)
263 return i;
264
265 rcache_counter++;
266
267 // maybe already cached?
268 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
269 if ((reg_temp[i].type == HR_CACHED || reg_temp[i].type == HR_CACHED_DIRTY) &&
270 reg_temp[i].val == r)
271 {
272 reg_temp[i].stamp = rcache_counter;
273 if (mode != RC_GR_READ)
274 reg_temp[i].type = HR_CACHED_DIRTY;
275 return reg_temp[i].reg;
276 }
277 }
278
279 // use any free reg
280 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
281 if (reg_temp[i].type == HR_FREE || reg_temp[i].type == HR_CONST) {
282 tr = &reg_temp[i];
283 goto do_alloc;
284 }
285 }
286
287 tr = rcache_evict();
288
289do_alloc:
290 if (mode != RC_GR_WRITE)
291 emith_ctx_read(tr->reg, r * 4);
292
293 tr->type = mode != RC_GR_READ ? HR_CACHED_DIRTY : HR_CACHED;
294 tr->val = r;
295 tr->stamp = rcache_counter;
296 return tr->reg;
297}
298
299static int rcache_get_tmp(void)
300{
301 temp_reg_t *tr;
302 int i;
303
304 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
305 if (reg_temp[i].type == HR_FREE || reg_temp[i].type == HR_CONST) {
306 tr = &reg_temp[i];
307 goto do_alloc;
308 }
309
310 tr = rcache_evict();
311
312do_alloc:
313 tr->type = HR_TEMP;
314 return tr->reg;
315}
316
317static int rcache_get_arg_id(int arg)
318{
319 int i, r = 0;
320 host_arg2reg(r, arg);
321
322 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
323 if (reg_temp[i].reg == r)
324 break;
325
326 if (i == ARRAY_SIZE(reg_temp))
327 // let's just say it's untracked arg reg
328 return r;
329
330 if (reg_temp[i].type == HR_CACHED_DIRTY) {
331 // writeback
332 emith_ctx_write(reg_temp[i].reg, reg_temp[i].val * 4);
333 }
334 else if (reg_temp[i].type == HR_TEMP) {
335 printf("arg %d reg %d already used, aborting\n", arg, r);
336 exit(1);
337 }
338
339 return i;
340}
341
342// get a reg to be used as function arg
343// it's assumed that regs are cleaned before call
344static int rcache_get_tmp_arg(int arg)
345{
346 int id = rcache_get_arg_id(arg);
347 reg_temp[id].type = HR_TEMP;
348
349 return reg_temp[id].reg;
350}
351
352// same but caches reg. RC_GR_READ only.
353static int rcache_get_reg_arg(int arg, sh2_reg_e r)
354{
355 int i, srcr, dstr, dstid;
356
357 dstid = rcache_get_arg_id(arg);
358 dstr = reg_temp[dstid].reg;
359
360 // maybe already statically mapped?
361 srcr = reg_map_g2h[r];
362 if (srcr != -1)
363 goto do_cache;
364
365 // maybe already cached?
366 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
367 if ((reg_temp[i].type == HR_CACHED || reg_temp[i].type == HR_CACHED_DIRTY) &&
368 reg_temp[i].val == r)
369 {
370 srcr = reg_temp[i].reg;
371 goto do_cache;
372 }
373 }
374
375 // must read
376 srcr = dstr;
377 emith_ctx_read(srcr, r * 4);
378
379do_cache:
380 if (srcr != dstr)
381 emith_move_r_r(dstr, srcr);
382
383 reg_temp[dstid].stamp = ++rcache_counter;
384 reg_temp[dstid].type = HR_CACHED;
385 reg_temp[dstid].val = r;
386 return dstr;
387}
388
389static void rcache_free_tmp(int hr)
390{
391 int i;
392 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
393 if (reg_temp[i].reg == hr)
394 break;
395
396 if (i == ARRAY_SIZE(reg_temp) || reg_temp[i].type != HR_TEMP) {
397 printf("rcache_free_tmp fail: #%i hr %d, type %d\n", i, hr, reg_temp[i].type);
398 return;
399 }
400
401 reg_temp[i].type = HR_FREE;
402}
403
404static void rcache_clean(void)
405{
406 int i;
407 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
408 if (reg_temp[i].type == HR_CACHED_DIRTY) {
409 // writeback
410 emith_ctx_write(reg_temp[i].reg, reg_temp[i].val * 4);
411 reg_temp[i].type = HR_CACHED;
412 }
413}
414
415static void rcache_invalidate(void)
416{
417 int i;
418 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
419 reg_temp[i].type = HR_FREE;
420 rcache_counter = 0;
421}
422
423static void rcache_flush(void)
424{
425 rcache_clean();
426 rcache_invalidate();
427}
428
429// ---------------------------------------------------------------
430
431static void emit_move_r_imm32(sh2_reg_e dst, u32 imm)
432{
433 int hr = rcache_get_reg(dst, RC_GR_WRITE);
434 emith_move_r_imm(hr, imm);
435}
436
437static void emit_move_r_r(sh2_reg_e dst, sh2_reg_e src)
438{
439 int hr_d = rcache_get_reg(dst, RC_GR_WRITE);
440 int hr_s = rcache_get_reg(src, RC_GR_READ);
441
442 emith_move_r_r(hr_d, hr_s);
443}
444
445// arguments must be ready
446// reg cache must be clean before call
447static int emit_memhandler_read(int size)
448{
449 int ctxr;
450 host_arg2reg(ctxr, 1);
451 emith_move_r_r(ctxr, CONTEXT_REG);
452 switch (size) {
453 case 0: // 8
454 emith_call(p32x_sh2_read8);
455 break;
456 case 1: // 16
457 emith_call(p32x_sh2_read16);
458 break;
459 case 2: // 32
460 emith_call(p32x_sh2_read32);
461 break;
462 }
463 rcache_invalidate();
464 // assuming arg0 and retval reg matches
465 return rcache_get_tmp_arg(0);
466}
467
468static void emit_memhandler_write(int size)
469{
470 int ctxr;
471 host_arg2reg(ctxr, 2);
472 emith_move_r_r(ctxr, CONTEXT_REG);
473 switch (size) {
474 case 0: // 8
475 emith_call(p32x_sh2_write8);
476 break;
477 case 1: // 16
478 emith_call(p32x_sh2_write16);
479 break;
480 case 2: // 32
481 emith_call(p32x_sh2_write32);
482 break;
483 }
484 rcache_invalidate();
485}
486
487/*
488MOV #imm,Rn 1110nnnniiiiiiii
489MOV.W @(disp,PC),Rn 1001nnnndddddddd
490MOV.L @(disp,PC),Rn 1101nnnndddddddd
491MOV Rm,Rn 0110nnnnmmmm0011
492MOV.B @Rm,Rn 0110nnnnmmmm0000
493MOV.W @Rm,Rn 0110nnnnmmmm0001
494MOV.L @Rm,Rn 0110nnnnmmmm0010
495MOV.B @Rm+,Rn 0110nnnnmmmm0100
496MOV.W @Rm+,Rn 0110nnnnmmmm0101
497MOV.L @Rm+,Rn 0110nnnnmmmm0110
498MOV.B R0,@(disp,Rn) 10000000nnnndddd
499MOV.W R0,@(disp,Rn) 10000001nnnndddd
500MOV.B @(disp,Rm),R0 10000100mmmmdddd
501MOV.W @(disp,Rm),R0 10000101mmmmdddd
502MOV.L @(disp,Rm),Rn 0101nnnnmmmmdddd
503MOV.B R0,@(disp,GBR) 11000000dddddddd
504MOV.W R0,@(disp,GBR) 11000001dddddddd
505MOV.L R0,@(disp,GBR) 11000010dddddddd
506MOV.B @(disp,GBR),R0 11000100dddddddd
507MOV.W @(disp,GBR),R0 11000101dddddddd
508MOV.L @(disp,GBR),R0 11000110dddddddd
509MOVA @(disp,PC),R0 11000111dddddddd
510SWAP.B Rm,Rn 0110nnnnmmmm1000
511SWAP.W Rm,Rn 0110nnnnmmmm1001
512XTRCT Rm,Rn 0010nnnnmmmm1101
513ADD Rm,Rn 0011nnnnmmmm1100
514ADD #imm,Rn 0111nnnniiiiiiii
515ADDC Rm,Rn 0011nnnnmmmm1110
516ADDV Rm,Rn 0011nnnnmmmm1111
517CMP/EQ #imm,R0 10001000iiiiiiii
518CMP/EQ Rm,Rn 0011nnnnmmmm0000
519CMP/HS Rm,Rn 0011nnnnmmmm0010
520CMP/GE Rm,Rn 0011nnnnmmmm0011
521CMP/HI Rm,Rn 0011nnnnmmmm0110
522CMP/GT Rm,Rn 0011nnnnmmmm0111
523CMP/PZ Rn 0100nnnn00010001
524CMP/PL Rn 0100nnnn00010101
525CMP/ST Rm,Rn 0010nnnnmmmm1100
526DIV1 Rm,Rn 0011nnnnmmmm0100
527DMULS. Rm,Rn 0011nnnnmmmm1101
528DMULU.L Rm,Rn 0011nnnnmmmm0101
529EXTS.B Rm,Rn 0110nnnnmmmm1110
530EXTS.W Rm,Rn 0110nnnnmmmm1111
531EXTU.B Rm,Rn 0110nnnnmmmm1100
532EXTU.W Rm,Rn 0110nnnnmmmm1101
533MAC @Rm+,@Rn+ 0100nnnnmmmm1111
534MULS.W Rm,Rn 0010nnnnmmmm1111
535MULU.W Rm,Rn 0010nnnnmmmm1110
536NEG Rm,Rn 0110nnnnmmmm1011
537NEGC Rm,Rn 0110nnnnmmmm1010
538SUB Rm,Rn 0011nnnnmmmm1000
539SUBC Rm,Rn 0011nnnnmmmm1010
540SUBV Rm,Rn 0011nnnnmmmm1011
541AND Rm,Rn 0010nnnnmmmm1001
542AND #imm,R0 11001001iiiiiiii
543AND.B #imm,@(R0,GBR) 11001101iiiiiiii
544NOT Rm,Rn 0110nnnnmmmm0111
545OR Rm,Rn 0010nnnnmmmm1011
546OR #imm,R0 11001011iiiiiiii
547OR.B #imm,@(R0,GBR) 11001111iiiiiiii
548TAS.B @Rn 0100nnnn00011011
549TST Rm,Rn 0010nnnnmmmm1000
550TST #imm,R0 11001000iiiiiiii
551TST.B #imm,@(R0,GBR) 11001100iiiiiiii
552XOR Rm,Rn 0010nnnnmmmm1010
553XOR #imm,R0 11001010iiiiiiii
554XOR.B #imm,@(R0,GBR) 11001110iiiiiiii
555ROTL Rn 0100nnnn00000100
556ROTR Rn 0100nnnn00000101
557ROTCL Rn 0100nnnn00100100
558ROTCR Rn 0100nnnn00100101
559SHAL Rn 0100nnnn00100000
560SHAR Rn 0100nnnn00100001
561SHLL Rn 0100nnnn00000000
562SHLR Rn 0100nnnn00000001
563SHLL2 Rn 0100nnnn00001000
564SHLR2 Rn 0100nnnn00001001
565SHLL8 Rn 0100nnnn00011000
566SHLR8 Rn 0100nnnn00011001
567SHLL16 Rn 0100nnnn00101000
568SHLR16 Rn 0100nnnn00101001
569LDC Rm,GBR 0100mmmm00011110
570LDC Rm,VBR 0100mmmm00101110
571LDC.L @Rm+,GBR 0100mmmm00010111
572LDC.L @Rm+,VBR 0100mmmm00100111
573LDS Rm,MACH 0100mmmm00001010
574LDS Rm,MACL 0100mmmm00011010
575LDS Rm,PR 0100mmmm00101010
576LDS.L @Rm+,MACH 0100mmmm00000110
577LDS.L @Rm+,MACL 0100mmmm00010110
578LDS.L @Rm+,PR 0100mmmm00100110
579STC.L SR,@–Rn 0100nnnn00000011
580STC.L GBR,@–Rn 0100nnnn00010011
581STC.L VBR,@–Rn 0100nnnn00100011
582STS.L MACH,@–Rn 0100nnnn00000010
583STS.L MACL,@–Rn 0100nnnn00010010
584STS.L PR,@–Rn 0100nnnn00100010
585TRAPA #imm 11000011iiiiiiii
586*/
587
588#define DELAYED_OP \
589 delayed_op = 2
590
591#define CHECK_UNHANDLED_BITS(mask) { \
592 if ((op & (mask)) != 0) \
593 goto default_; \
594}
595
596#define GET_Fx() \
597 ((op >> 4) & 0x0f)
598
599#define GET_Rm GET_Fx
600
601#define GET_Rn() \
602 ((op >> 8) & 0x0f)
603
604#define CHECK_FX_GT_3() \
605 if (GET_Fx() > 3) \
606 goto default_
607
608static void *sh2_translate(SH2 *sh2, block_desc *other_block)
609{
610 void *block_entry;
611 block_desc *this_block;
612 unsigned int pc = sh2->pc;
613 int op, delayed_op = 0, test_irq = 0;
614 int tcache_id = 0, blkid = 0;
615 int cycles = 0;
616 u32 tmp, tmp2, tmp3;
617
618 // validate PC
619 tmp = sh2->pc >> 29;
620 if ((tmp != 0 && tmp != 1 && tmp != 6) || sh2->pc == 0) {
621 printf("invalid PC, aborting: %08x\n", sh2->pc);
622 // FIXME: be less destructive
623 exit(1);
624 }
625
626 if ((sh2->pc & 0xe0000000) == 0xc0000000 || (sh2->pc & ~0xfff) == 0) {
627 // data_array, BIOS have separate tcache (shared)
628 tcache_id = 1 + sh2->is_slave;
629 }
630
631 tcache_ptr = tcache_ptrs[tcache_id];
632 this_block = dr_add_block(pc, tcache_id, &blkid);
633
634 tmp = tcache_ptr - tcache_bases[tcache_id];
635 if (tmp > tcache_sizes[tcache_id] - MAX_BLOCK_SIZE || this_block == NULL) {
636 flush_tcache(tcache_id);
637 tcache_ptr = tcache_ptrs[tcache_id];
638 other_block = NULL; // also gone too due to flush
639 this_block = dr_add_block(pc, tcache_id, &blkid);
640 }
641
642 this_block->next = other_block;
643 if ((sh2->pc & 0xc6000000) == 0x02000000) // ROM
644 HASH_FUNC(hash_table, pc) = this_block;
645
646 block_entry = tcache_ptr;
647#if (DRC_DEBUG & 1)
648 printf("== %csh2 block #%d,%d %08x -> %p\n", sh2->is_slave ? 's' : 'm',
649 tcache_id, block_counts[tcache_id], pc, block_entry);
650 if (other_block != NULL) {
651 printf(" hash collision with %08x\n", other_block->addr);
652 hash_collisions++;
653 }
654#endif
655
656 while (cycles < BLOCK_CYCLE_LIMIT || delayed_op)
657 {
658 if (delayed_op > 0)
659 delayed_op--;
660
661 op = p32x_sh2_read16(pc, sh2);
662
663#if (DRC_DEBUG & 3)
664 insns_compiled++;
665#if (DRC_DEBUG & 2)
666 DasmSH2(sh2dasm_buff, pc, op);
667 printf("%08x %04x %s\n", pc, op, sh2dasm_buff);
668#endif
669#endif
670
671 pc += 2;
672 cycles++;
673
674 switch ((op >> 12) & 0x0f)
675 {
676 case 0x00:
677 switch (op & 0x0f)
678 {
679 case 0x02:
680 tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
681 switch (GET_Fx())
682 {
683 case 0: // STC SR,Rn 0000nnnn00000010
684 tmp2 = SHR_SR;
685 break;
686 case 1: // STC GBR,Rn 0000nnnn00010010
687 tmp2 = SHR_GBR;
688 break;
689 case 2: // STC VBR,Rn 0000nnnn00100010
690 tmp2 = SHR_VBR;
691 break;
692 default:
693 goto default_;
694 }
695 tmp2 = rcache_get_reg(tmp2, RC_GR_READ);
696 emith_move_r_r(tmp, tmp2);
697 goto end_op;
698 case 0x03:
699 CHECK_UNHANDLED_BITS(0xd0);
700 // BRAF Rm 0000mmmm00100011
701 // BSRF Rm 0000mmmm00000011
702 DELAYED_OP;
703 if (!(op & 0x20))
704 emit_move_r_imm32(SHR_PR, pc + 2);
705 tmp = rcache_get_reg(SHR_PPC, RC_GR_WRITE);
706 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
707 emith_move_r_r(tmp, tmp2);
708 emith_add_r_imm(tmp, pc + 2);
709 cycles++;
710 goto end_op;
711 case 0x04: // MOV.B Rm,@(R0,Rn) 0000nnnnmmmm0100
712 case 0x05: // MOV.W Rm,@(R0,Rn) 0000nnnnmmmm0101
713 case 0x06: // MOV.L Rm,@(R0,Rn) 0000nnnnmmmm0110
714 rcache_clean();
715 tmp = rcache_get_reg_arg(0, SHR_R0);
716 tmp2 = rcache_get_reg_arg(1, GET_Rm());
717 tmp3 = rcache_get_reg(GET_Rn(), RC_GR_READ);
718 emith_add_r_r(tmp, tmp3);
719 emit_memhandler_write(op & 3);
720 goto end_op;
721 case 0x07:
722 // MUL.L Rm,Rn 0000nnnnmmmm0111
723 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
724 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
725 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
726 emith_mul(tmp3, tmp2, tmp);
727 cycles++;
728 goto end_op;
729 case 0x08:
730 CHECK_UNHANDLED_BITS(0xf00);
731 switch (GET_Fx())
732 {
733 case 0: // CLRT 0000000000001000
734 tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
735 emith_bic_r_imm(tmp, T);
736 break;
737 case 1: // SETT 0000000000011000
738 tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
739 emith_or_r_imm(tmp, T);
740 break;
741 case 2: // CLRMAC 0000000000101000
742 tmp = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
743 emith_move_r_imm(tmp, 0);
744 tmp = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
745 emith_move_r_imm(tmp, 0);
746 break;
747 default:
748 goto default_;
749 }
750 goto end_op;
751 case 0x09:
752 switch (GET_Fx())
753 {
754 case 0: // NOP 0000000000001001
755 CHECK_UNHANDLED_BITS(0xf00);
756 break;
757 case 1: // DIV0U 0000000000011001
758 CHECK_UNHANDLED_BITS(0xf00);
759 tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
760 emith_bic_r_imm(tmp, M|Q|T);
761 break;
762 case 2: // MOVT Rn 0000nnnn00101001
763 tmp = rcache_get_reg(SHR_SR, RC_GR_READ);
764 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
765 emith_clear_msb(tmp2, tmp, 31);
766 break;
767 default:
768 goto default_;
769 }
770 goto end_op;
771 case 0x0a:
772 tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
773 switch (GET_Fx())
774 {
775 case 0: // STS MACH,Rn 0000nnnn00001010
776 tmp2 = rcache_get_reg(SHR_MACH, RC_GR_READ);
777 break;
778 case 1: // STS MACL,Rn 0000nnnn00011010
779 tmp2 = rcache_get_reg(SHR_MACL, RC_GR_READ);
780 break;
781 case 2: // STS PR,Rn 0000nnnn00101010
782 tmp2 = rcache_get_reg(SHR_PR, RC_GR_READ);
783 break;
784 default:
785 goto default_;
786 }
787 emith_move_r_r(tmp, tmp2);
788 goto end_op;
789 case 0x0b:
790 CHECK_UNHANDLED_BITS(0xf00);
791 switch (GET_Fx())
792 {
793 case 0: // RTS 0000000000001011
794 DELAYED_OP;
795 emit_move_r_r(SHR_PPC, SHR_PR);
796 cycles++;
797 break;
798 case 1: // SLEEP 0000000000011011
799 emit_move_r_imm32(SHR_PC, pc - 2);
800 tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
801 emith_clear_msb(tmp, tmp, 20); // clear cycles
802 test_irq = 1;
803 cycles = 1;
804 break;
805 case 2: // RTE 0000000000101011
806 //emit_move_r_r(SHR_PC, SHR_PR);
807 emit_move_r_imm32(SHR_PC, pc - 2);
808 rcache_flush();
809 emith_pass_arg_r(0, CONTEXT_REG);
810 emith_pass_arg_imm(1, op);
811 emith_call(sh2_do_op);
812 emit_move_r_r(SHR_PPC, SHR_PC);
813 test_irq = 1;
814 cycles += 3;
815 break;
816 default:
817 goto default_;
818 }
819 goto end_op;
820 case 0x0c: // MOV.B @(R0,Rm),Rn 0000nnnnmmmm1100
821 case 0x0d: // MOV.W @(R0,Rm),Rn 0000nnnnmmmm1101
822 case 0x0e: // MOV.L @(R0,Rm),Rn 0000nnnnmmmm1110
823 rcache_clean();
824 tmp = rcache_get_reg_arg(0, SHR_R0);
825 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
826 emith_add_r_r(tmp, tmp2);
827 tmp = emit_memhandler_read(op & 3);
828 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
829 rcache_free_tmp(tmp);
830 if ((op & 3) != 2) {
831 emith_sext(tmp2, tmp, (op & 1) ? 16 : 8);
832 } else
833 emith_move_r_r(tmp2, tmp);
834 goto end_op;
835 case 0x0f: // MAC.L @Rm+,@Rn+ 0000nnnnmmmm1111
836 // TODO
837 break;
838 }
839 goto default_;
840
841 case 0x01:
842 // MOV.L Rm,@(disp,Rn) 0001nnnnmmmmdddd
843 rcache_clean();
844 tmp = rcache_get_reg_arg(0, GET_Rn());
845 tmp2 = rcache_get_reg_arg(1, GET_Rm());
846 emith_add_r_imm(tmp, (op & 0x0f) * 4);
847 emit_memhandler_write(2);
848 goto end_op;
849
850 case 0x02:
851 switch (op & 0x0f)
852 {
853 case 0x00: // MOV.B Rm,@Rn 0010nnnnmmmm0000
854 case 0x01: // MOV.W Rm,@Rn 0010nnnnmmmm0001
855 case 0x02: // MOV.L Rm,@Rn 0010nnnnmmmm0010
856 rcache_clean();
857 rcache_get_reg_arg(0, GET_Rn());
858 rcache_get_reg_arg(1, GET_Rm());
859 emit_memhandler_write(op & 3);
860 goto end_op;
861 case 0x04: // MOV.B Rm,@–Rn 0010nnnnmmmm0100
862 case 0x05: // MOV.W Rm,@–Rn 0010nnnnmmmm0101
863 case 0x06: // MOV.L Rm,@–Rn 0010nnnnmmmm0110
864 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
865 emith_sub_r_imm(tmp, (1 << (op & 3)));
866 rcache_clean();
867 rcache_get_reg_arg(0, GET_Rn());
868 rcache_get_reg_arg(1, GET_Rm());
869 emit_memhandler_write(op & 3);
870 goto end_op;
871 case 0x07: // DIV0S Rm,Rn 0010nnnnmmmm0111
872 tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
873 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
874 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
875 emith_bic_r_imm(tmp, M|Q|T);
876 emith_tst_r_imm(tmp2, (1<<31));
877 EMITH_SJMP_START(DCOND_EQ);
878 emith_or_r_imm_c(DCOND_NE, tmp, Q);
879 EMITH_SJMP_END(DCOND_EQ);
880 emith_tst_r_imm(tmp3, (1<<31));
881 EMITH_SJMP_START(DCOND_EQ);
882 emith_or_r_imm_c(DCOND_NE, tmp, M);
883 EMITH_SJMP_END(DCOND_EQ);
884 emith_teq_r_r(tmp2, tmp3);
885 EMITH_SJMP_START(DCOND_PL);
886 emith_or_r_imm_c(DCOND_MI, tmp, T);
887 EMITH_SJMP_END(DCOND_PL);
888 goto end_op;
889 }
890 goto default_;
891
892 case 0x04:
893 switch (op & 0x0f) {
894 case 0x00:
895 if ((op & 0xf0) != 0x10)
896 goto default_;
897 // DT Rn 0100nnnn00010000
898 if (p32x_sh2_read16(pc, sh2) == 0x8bfd) { // BF #-2
899 emith_sh2_dtbf_loop();
900 goto end_op;
901 }
902 tmp = rcache_get_reg((op >> 8) & 0x0f, RC_GR_RMW);
903 tmp2 = rcache_get_reg(SHR_SR, RC_GR_RMW);
904 emith_bic_r_imm(tmp2, T);
905 emith_subf_r_imm(tmp, 1);
906 EMITH_SJMP_START(DCOND_NE);
907 emith_or_r_imm_c(DCOND_EQ, tmp2, T);
908 EMITH_SJMP_END(DCOND_NE);
909 goto end_op;
910 case 0x07:
911 if ((op & 0xf0) != 0)
912 goto default_;
913 // LDC.L @Rm+,SR 0100mmmm00000111
914 test_irq = 1;
915 goto default_;
916 case 0x0b:
917 if ((op & 0xd0) != 0)
918 goto default_;
919 // JMP @Rm 0100mmmm00101011
920 // JSR @Rm 0100mmmm00001011
921 DELAYED_OP;
922 if (!(op & 0x20))
923 emit_move_r_imm32(SHR_PR, pc + 2);
924 emit_move_r_r(SHR_PPC, (op >> 8) & 0x0f);
925 cycles++;
926 goto end_op;
927 case 0x0e:
928 if ((op & 0xf0) != 0)
929 goto default_;
930 // LDC Rm,SR 0100mmmm00001110
931 test_irq = 1;
932 goto default_;
933 }
934 goto default_;
935
936 case 0x08:
937 switch (op & 0x0f00) {
938 // BT/S label 10001101dddddddd
939 case 0x0d00:
940 // BF/S label 10001111dddddddd
941 case 0x0f00:
942 DELAYED_OP;
943 cycles--;
944 // fallthrough
945 // BT label 10001001dddddddd
946 case 0x0900:
947 // BF label 10001011dddddddd
948 case 0x0b00: {
949 // jmp_cond ~ cond when guest doesn't jump
950 int jmp_cond = (op & 0x0200) ? DCOND_NE : DCOND_EQ;
951 int insn_cond = (op & 0x0200) ? DCOND_EQ : DCOND_NE;
952 signed int offs = ((signed int)(op << 24) >> 23);
953 tmp = rcache_get_reg(delayed_op ? SHR_PPC : SHR_PC, RC_GR_WRITE);
954 emith_move_r_imm(tmp, pc + (delayed_op ? 2 : 0));
955 emith_sh2_test_t();
956 EMITH_SJMP_START(jmp_cond);
957 if (!delayed_op)
958 offs += 2;
959 if (offs < 0) {
960 emith_sub_r_imm_c(insn_cond, tmp, -offs);
961 } else
962 emith_add_r_imm_c(insn_cond, tmp, offs);
963 EMITH_SJMP_END(jmp_cond);
964 cycles += 2;
965 if (!delayed_op)
966 goto end_block;
967 goto end_op;
968 }}
969 goto default_;
970
971 case 0x0a:
972 // BRA label 1010dddddddddddd
973 DELAYED_OP;
974 do_bra:
975 tmp = ((signed int)(op << 20) >> 19);
976 emit_move_r_imm32(SHR_PPC, pc + tmp + 2);
977 cycles++;
978 break;
979
980 case 0x0b:
981 // BSR label 1011dddddddddddd
982 DELAYED_OP;
983 emit_move_r_imm32(SHR_PR, pc + 2);
984 goto do_bra;
985
986 default:
987 default_:
988 emit_move_r_imm32(SHR_PC, pc - 2);
989 rcache_flush();
990 emith_pass_arg_r(0, CONTEXT_REG);
991 emith_pass_arg_imm(1, op);
992 emith_call(sh2_do_op);
993 break;
994 }
995
996end_op:
997 if (delayed_op == 1)
998 emit_move_r_r(SHR_PC, SHR_PPC);
999
1000 if (test_irq && delayed_op != 2) {
1001 rcache_flush();
1002 emith_pass_arg_r(0, CONTEXT_REG);
1003 emith_call(sh2_test_irq);
1004 break;
1005 }
1006 if (delayed_op == 1)
1007 break;
1008
1009 do_host_disasm(tcache_id);
1010 }
1011
1012end_block:
1013 this_block->end_addr = pc;
1014
1015 // mark memory blocks as containing compiled code
1016 if ((sh2->pc & 0xe0000000) == 0xc0000000 || (sh2->pc & ~0xfff) == 0) {
1017 // data array, BIOS
1018 u16 *drcblk = Pico32xMem->drcblk_da[sh2->is_slave];
1019 tmp = (this_block->addr & 0xfff) >> SH2_DRCBLK_DA_SHIFT;
1020 tmp2 = (this_block->end_addr & 0xfff) >> SH2_DRCBLK_DA_SHIFT;
1021 Pico32xMem->drcblk_da[sh2->is_slave][tmp] = (blkid << 1) | 1;
1022 for (++tmp; tmp < tmp2; tmp++) {
1023 if (drcblk[tmp])
1024 break; // dont overwrite overlay block
1025 drcblk[tmp] = blkid << 1;
1026 }
1027 }
1028 else if ((this_block->addr & 0xc7fc0000) == 0x06000000) { // DRAM
1029 tmp = (this_block->addr & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
1030 tmp2 = (this_block->end_addr & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
1031 Pico32xMem->drcblk_ram[tmp] = (blkid << 1) | 1;
1032 for (++tmp; tmp < tmp2; tmp++) {
1033 if (Pico32xMem->drcblk_ram[tmp])
1034 break;
1035 Pico32xMem->drcblk_ram[tmp] = blkid << 1;
1036 }
1037 }
1038
1039 tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
1040 emith_sub_r_imm(tmp, cycles << 12);
1041 rcache_flush();
1042 emith_jump(sh2_drc_exit);
1043 tcache_ptrs[tcache_id] = tcache_ptr;
1044
1045#ifdef ARM
1046 cache_flush_d_inval_i(block_entry, tcache_ptr);
1047#endif
1048
1049 do_host_disasm(tcache_id);
1050 dbg(1, " block #%d,%d tcache %d/%d, insns %d -> %d %.3f",
1051 tcache_id, block_counts[tcache_id],
1052 tcache_ptr - tcache_bases[tcache_id], tcache_sizes[tcache_id],
1053 insns_compiled, host_insn_count, (double)host_insn_count / insns_compiled);
1054 if ((sh2->pc & 0xc6000000) == 0x02000000) // ROM
1055 dbg(1, " hash collisions %d/%d", hash_collisions, block_counts[tcache_id]);
1056#if (DRC_DEBUG & 2)
1057 fflush(stdout);
1058#endif
1059
1060 return block_entry;
1061/*
1062unimplemented:
1063 // last op
1064 do_host_disasm(tcache_id);
1065 exit(1);
1066*/
1067}
1068
1069void __attribute__((noinline)) sh2_drc_dispatcher(SH2 *sh2)
1070{
1071 while (((signed int)sh2->sr >> 12) > 0)
1072 {
1073 void *block = NULL;
1074 block_desc *bd = NULL;
1075
1076 // FIXME: must avoid doing it so often..
1077 sh2_test_irq(sh2);
1078
1079 // we have full block id tables for data_array and RAM
1080 // BIOS goes to data_array table too
1081 if ((sh2->pc & 0xff000000) == 0xc0000000 || (sh2->pc & ~0xfff) == 0) {
1082 int blkid = Pico32xMem->drcblk_da[sh2->is_slave][(sh2->pc & 0xfff) >> SH2_DRCBLK_DA_SHIFT];
1083 if (blkid & 1) {
1084 bd = &block_tables[1 + sh2->is_slave][blkid >> 1];
1085 block = bd->tcache_ptr;
1086 }
1087 }
1088 // RAM
1089 else if ((sh2->pc & 0xc6000000) == 0x06000000) {
1090 int blkid = Pico32xMem->drcblk_ram[(sh2->pc & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT];
1091 if (blkid & 1) {
1092 bd = &block_tables[0][blkid >> 1];
1093 block = bd->tcache_ptr;
1094 }
1095 }
1096 // ROM
1097 else if ((sh2->pc & 0xc6000000) == 0x02000000) {
1098 bd = HASH_FUNC(hash_table, sh2->pc);
1099
1100 if (bd != NULL) {
1101 if (bd->addr == sh2->pc)
1102 block = bd->tcache_ptr;
1103 else
1104 block = dr_find_block(bd, sh2->pc);
1105 }
1106 }
1107
1108 if (block == NULL)
1109 block = sh2_translate(sh2, bd);
1110
1111 dbg(4, "= %csh2 enter %08x %p, c=%d", sh2->is_slave ? 's' : 'm',
1112 sh2->pc, block, (signed int)sh2->sr >> 12);
1113#if (DRC_DEBUG & 1)
1114 if (bd != NULL)
1115 bd->refcount++;
1116#endif
1117 sh2_drc_entry(sh2, block);
1118 }
1119}
1120
1121static void sh2_smc_rm_block(u16 *drcblk, u16 *p, block_desc *btab, u32 a)
1122{
1123 u16 id = *p >> 1;
1124 block_desc *bd = btab + id;
1125
1126 dbg(1, " killing block %08x", bd->addr);
1127 bd->addr = bd->end_addr = 0;
1128
1129 while (p > drcblk && (p[-1] >> 1) == id)
1130 p--;
1131
1132 // check for possible overlay block
1133 if (p > 0 && p[-1] != 0) {
1134 bd = btab + (p[-1] >> 1);
1135 if (bd->addr <= a && a < bd->end_addr)
1136 sh2_smc_rm_block(drcblk, p - 1, btab, a);
1137 }
1138
1139 do {
1140 *p++ = 0;
1141 }
1142 while ((*p >> 1) == id);
1143}
1144
1145void sh2_drc_wcheck_ram(unsigned int a, int val, int cpuid)
1146{
1147 u16 *drcblk = Pico32xMem->drcblk_ram;
1148 u16 *p = drcblk + ((a & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT);
1149
1150 dbg(1, "%csh2 smc check @%08x", cpuid ? 's' : 'm', a);
1151 sh2_smc_rm_block(drcblk, p, block_tables[0], a);
1152}
1153
1154void sh2_drc_wcheck_da(unsigned int a, int val, int cpuid)
1155{
1156 u16 *drcblk = Pico32xMem->drcblk_da[cpuid];
1157 u16 *p = drcblk + ((a & 0xfff) >> SH2_DRCBLK_DA_SHIFT);
1158
1159 dbg(1, "%csh2 smc check @%08x", cpuid ? 's' : 'm', a);
1160 sh2_smc_rm_block(drcblk, p, block_tables[1 + cpuid], a);
1161}
1162
1163void sh2_execute(SH2 *sh2, int cycles)
1164{
1165 sh2->cycles_aim += cycles;
1166 cycles = sh2->cycles_aim - sh2->cycles_done;
1167
1168 // cycles are kept in SHR_SR unused bits (upper 20)
1169 sh2->sr &= 0x3f3;
1170 sh2->sr |= cycles << 12;
1171 sh2_drc_dispatcher(sh2);
1172
1173 sh2->cycles_done += cycles - ((signed int)sh2->sr >> 12);
1174}
1175
1176static void REGPARM(1) sh2_test_irq(SH2 *sh2)
1177{
1178 if (sh2->pending_level > ((sh2->sr >> 4) & 0x0f))
1179 {
1180 if (sh2->pending_irl > sh2->pending_int_irq)
1181 sh2_do_irq(sh2, sh2->pending_irl, 64 + sh2->pending_irl/2);
1182 else {
1183 sh2_do_irq(sh2, sh2->pending_int_irq, sh2->pending_int_vector);
1184 sh2->pending_int_irq = 0; // auto-clear
1185 sh2->pending_level = sh2->pending_irl;
1186 }
1187 }
1188}
1189
1190#if (DRC_DEBUG & 1)
1191static void block_stats(void)
1192{
1193 int c, b, i, total = 0;
1194
1195 for (b = 0; b < ARRAY_SIZE(block_tables); b++)
1196 for (i = 0; i < block_counts[b]; i++)
1197 if (block_tables[b][i].addr != 0)
1198 total += block_tables[b][i].refcount;
1199
1200 for (c = 0; c < 10; c++) {
1201 block_desc *blk, *maxb = NULL;
1202 int max = 0;
1203 for (b = 0; b < ARRAY_SIZE(block_tables); b++) {
1204 for (i = 0; i < block_counts[b]; i++) {
1205 blk = &block_tables[b][i];
1206 if (blk->addr != 0 && blk->refcount > max) {
1207 max = blk->refcount;
1208 maxb = blk;
1209 }
1210 }
1211 }
1212 if (maxb == NULL)
1213 break;
1214 printf("%08x %9d %2.3f%%\n", maxb->addr, maxb->refcount,
1215 (double)maxb->refcount / total * 100.0);
1216 maxb->refcount = 0;
1217 }
1218
1219 for (b = 0; b < ARRAY_SIZE(block_tables); b++)
1220 for (i = 0; i < block_counts[b]; i++)
1221 block_tables[b][i].refcount = 0;
1222}
1223#else
1224#define block_stats()
1225#endif
1226
1227void sh2_drc_flush_all(void)
1228{
1229 block_stats();
1230 flush_tcache(0);
1231 flush_tcache(1);
1232 flush_tcache(2);
1233}
1234
1235int sh2_drc_init(SH2 *sh2)
1236{
1237 if (block_tables[0] == NULL) {
1238 int i, cnt;
1239
1240 drc_cmn_init();
1241
1242 cnt = block_max_counts[0] + block_max_counts[1] + block_max_counts[2];
1243 block_tables[0] = calloc(cnt, sizeof(*block_tables[0]));
1244 if (block_tables[0] == NULL)
1245 return -1;
1246
1247 memset(block_counts, 0, sizeof(block_counts));
1248 tcache_bases[0] = tcache_ptrs[0] = tcache;
1249
1250 for (i = 1; i < ARRAY_SIZE(block_tables); i++) {
1251 block_tables[i] = block_tables[i - 1] + block_max_counts[i - 1];
1252 tcache_bases[i] = tcache_ptrs[i] = tcache_bases[i - 1] + tcache_sizes[i - 1];
1253 }
1254
1255 // tmp
1256 PicoOpt |= POPT_DIS_VDP_FIFO;
1257
1258#if (DRC_DEBUG & 2)
1259 for (i = 0; i < ARRAY_SIZE(block_tables); i++)
1260 tcache_dsm_ptrs[i] = tcache_bases[i];
1261#endif
1262#if (DRC_DEBUG & 1)
1263 hash_collisions = 0;
1264#endif
1265 }
1266
1267 if (hash_table == NULL) {
1268 hash_table = calloc(sizeof(hash_table[0]), MAX_HASH_ENTRIES);
1269 if (hash_table == NULL)
1270 return -1;
1271 }
1272
1273 return 0;
1274}
1275
1276void sh2_drc_finish(SH2 *sh2)
1277{
1278 if (block_tables[0] != NULL) {
1279 block_stats();
1280 free(block_tables[0]);
1281 memset(block_tables, 0, sizeof(block_tables));
1282
1283 drc_cmn_cleanup();
1284 }
1285
1286 if (hash_table != NULL) {
1287 free(hash_table);
1288 hash_table = NULL;
1289 }
1290}