123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048 |
- /*
- * vim:shiftwidth=2:expandtab
- *
- * notes:
- * - tcache, block descriptor, link buffer overflows result in sh2_translate()
- * failure, followed by full tcache invalidation for that region
- * - jumps between blocks are tracked for SMC handling (in block_links[]),
- * except jumps between different tcaches
- *
- * implemented:
- * - static register allocation
- * - remaining register caching and tracking in temporaries
- * - block-local branch linking
- * - block linking (except between tcaches)
- * - some constant propagation
- *
- * TODO:
- * - proper SMC handling
- * - better constant propagation
- * - stack caching?
- * - bug fixing
- */
- #include <stddef.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <assert.h>
- #include "../../pico/pico_int.h"
- #include "sh2.h"
- #include "compiler.h"
- #include "../drc/cmn.h"
- #include "../debug.h"
- // features
- #define PROPAGATE_CONSTANTS 1
- #define LINK_BRANCHES 1
- // max literal offset from the block end
- #define MAX_LITERAL_OFFSET 32*2
- // debug stuff {
- #ifndef DRC_DEBUG
- #define DRC_DEBUG 0
- #endif
- #if DRC_DEBUG
- #define dbg(l,...) { \
- if ((l) & DRC_DEBUG) \
- elprintf(EL_STATUS, ##__VA_ARGS__); \
- }
- #include "mame/sh2dasm.h"
- #include <platform/linux/host_dasm.h>
- static int insns_compiled, hash_collisions, host_insn_count;
- #define COUNT_OP \
- host_insn_count++
- #else // !DRC_DEBUG
- #define COUNT_OP
- #define dbg(...)
- #endif
- #if (DRC_DEBUG & 2)
- static u8 *tcache_dsm_ptrs[3];
- static char sh2dasm_buff[64];
- #define do_host_disasm(tcid) \
- host_dasm(tcache_dsm_ptrs[tcid], tcache_ptr - tcache_dsm_ptrs[tcid]); \
- tcache_dsm_ptrs[tcid] = tcache_ptr
- #else
- #define do_host_disasm(x)
- #endif
- #if (DRC_DEBUG & 4) || defined(PDB)
- static void REGPARM(3) *sh2_drc_log_entry(void *block, SH2 *sh2, u32 sr)
- {
- if (block != NULL) {
- dbg(4, "= %csh2 enter %08x %p, c=%d", sh2->is_slave ? 's' : 'm',
- sh2->pc, block, (signed int)sr >> 12);
- pdb_step(sh2, sh2->pc);
- }
- return block;
- }
- #endif
- // } debug
- #define BLOCK_CYCLE_LIMIT 100
- #define MAX_BLOCK_SIZE (BLOCK_CYCLE_LIMIT * 6 * 6)
- #define TCACHE_BUFFERS 3
- // we have 3 translation cache buffers, split from one drc/cmn buffer.
- // BIOS shares tcache with data array because it's only used for init
- // and can be discarded early
- // XXX: need to tune sizes
- static const int tcache_sizes[TCACHE_BUFFERS] = {
- DRC_TCACHE_SIZE * 6 / 8, // ROM, DRAM
- DRC_TCACHE_SIZE / 8, // BIOS, data array in master sh2
- DRC_TCACHE_SIZE / 8, // ... slave
- };
- static u8 *tcache_bases[TCACHE_BUFFERS];
- static u8 *tcache_ptrs[TCACHE_BUFFERS];
- // ptr for code emiters
- static u8 *tcache_ptr;
- typedef struct block_desc_ {
- u32 addr; // SH2 PC address
- u32 end_addr; // TODO rm?
- void *tcache_ptr; // translated block for above PC
- struct block_desc_ *next; // next block with the same PC hash
- #if (DRC_DEBUG & 1)
- int refcount;
- #endif
- } block_desc;
- typedef struct block_link_ {
- u32 target_pc;
- void *jump;
- // struct block_link_ *next;
- } block_link;
- static const int block_max_counts[TCACHE_BUFFERS] = {
- 4*1024,
- 256,
- 256,
- };
- static block_desc *block_tables[TCACHE_BUFFERS];
- static block_link *block_links[TCACHE_BUFFERS];
- static int block_counts[TCACHE_BUFFERS];
- static int block_link_counts[TCACHE_BUFFERS];
- // host register tracking
- enum {
- HR_FREE,
- HR_CACHED, // 'val' has sh2_reg_e
- // HR_CONST, // 'val' has a constant
- HR_TEMP, // reg used for temp storage
- };
- enum {
- HRF_DIRTY = 1 << 0, // reg has "dirty" value to be written to ctx
- HRF_LOCKED = 1 << 1, // HR_CACHED can't be evicted
- };
- typedef struct {
- u32 hreg:5; // "host" reg
- u32 greg:5; // "guest" reg
- u32 type:3;
- u32 flags:3;
- u32 stamp:16; // kind of a timestamp
- } temp_reg_t;
- // note: reg_temp[] must have at least the amount of
- // registers used by handlers in worst case (currently 4)
- #ifdef ARM
- #include "../drc/emit_arm.c"
- static const int reg_map_g2h[] = {
- 4, 5, 6, 7,
- 8, -1, -1, -1,
- -1, -1, -1, -1,
- -1, -1, -1, 9,
- -1, -1, -1, 10,
- -1, -1, -1, -1,
- };
- static temp_reg_t reg_temp[] = {
- { 0, },
- { 1, },
- { 12, },
- { 14, },
- { 2, },
- { 3, },
- };
- #elif defined(__i386__)
- #include "../drc/emit_x86.c"
- static const int reg_map_g2h[] = {
- xSI,-1, -1, -1,
- -1, -1, -1, -1,
- -1, -1, -1, -1,
- -1, -1, -1, -1,
- -1, -1, -1, xDI,
- -1, -1, -1, -1,
- };
- // ax, cx, dx are usually temporaries by convention
- static temp_reg_t reg_temp[] = {
- { xAX, },
- { xBX, },
- { xCX, },
- { xDX, },
- };
- #else
- #error unsupported arch
- #endif
- #define T 0x00000001
- #define S 0x00000002
- #define I 0x000000f0
- #define Q 0x00000100
- #define M 0x00000200
- #define T_save 0x00000800
- #define I_SHIFT 4
- #define Q_SHIFT 8
- #define M_SHIFT 9
- // ROM hash table
- #define MAX_HASH_ENTRIES 1024
- #define HASH_MASK (MAX_HASH_ENTRIES - 1)
- static void **hash_table;
- #define HASH_FUNC(hash_tab, addr) \
- ((block_desc **)(hash_tab))[(addr) & HASH_MASK]
- static void REGPARM(1) (*sh2_drc_entry)(SH2 *sh2);
- static void (*sh2_drc_dispatcher)(void);
- static void (*sh2_drc_exit)(void);
- static void (*sh2_drc_test_irq)(void);
- static u32 REGPARM(2) (*sh2_drc_read8)(u32 a, SH2 *sh2);
- static u32 REGPARM(2) (*sh2_drc_read16)(u32 a, SH2 *sh2);
- static u32 REGPARM(2) (*sh2_drc_read32)(u32 a, SH2 *sh2);
- static void REGPARM(2) (*sh2_drc_write8)(u32 a, u32 d);
- static void REGPARM(2) (*sh2_drc_write8_slot)(u32 a, u32 d);
- static void REGPARM(2) (*sh2_drc_write16)(u32 a, u32 d);
- static void REGPARM(2) (*sh2_drc_write16_slot)(u32 a, u32 d);
- static int REGPARM(3) (*sh2_drc_write32)(u32 a, u32 d, SH2 *sh2);
- extern void REGPARM(2) sh2_do_op(SH2 *sh2, int opcode);
- static void flush_tcache(int tcid)
- {
- dbg(1, "tcache #%d flush! (%d/%d, bds %d/%d)", tcid,
- tcache_ptrs[tcid] - tcache_bases[tcid], tcache_sizes[tcid],
- block_counts[tcid], block_max_counts[tcid]);
- block_counts[tcid] = 0;
- tcache_ptrs[tcid] = tcache_bases[tcid];
- if (tcid == 0) { // ROM, RAM
- memset(hash_table, 0, sizeof(hash_table[0]) * MAX_HASH_ENTRIES);
- memset(Pico32xMem->drcblk_ram, 0, sizeof(Pico32xMem->drcblk_ram));
- }
- else
- memset(Pico32xMem->drcblk_da[tcid - 1], 0, sizeof(Pico32xMem->drcblk_da[0]));
- #if (DRC_DEBUG & 2)
- tcache_dsm_ptrs[tcid] = tcache_bases[tcid];
- #endif
- }
- #if LINK_BRANCHES
- // add block links (tracked branches)
- static int dr_add_block_link(u32 target_pc, void *jump, int tcache_id)
- {
- block_link *bl = block_links[tcache_id];
- int cnt = block_link_counts[tcache_id];
- if (cnt >= block_max_counts[tcache_id] * 2) {
- printf("bl overflow for tcache %d\n", tcache_id);
- return -1;
- }
- bl[cnt].target_pc = target_pc;
- bl[cnt].jump = jump;
- block_link_counts[tcache_id]++;
- return 0;
- }
- #endif
- static void *dr_find_block(block_desc *tab, u32 addr)
- {
- for (tab = tab->next; tab != NULL; tab = tab->next)
- if (tab->addr == addr)
- break;
- if (tab != NULL)
- return tab->tcache_ptr;
- printf("block miss for %08x\n", addr);
- return NULL;
- }
- static block_desc *dr_add_block(u32 addr, int tcache_id, int *blk_id)
- {
- int *bcount = &block_counts[tcache_id];
- block_desc *bd;
- if (*bcount >= block_max_counts[tcache_id]) {
- printf("bd overflow for tcache %d\n", tcache_id);
- return NULL;
- }
- bd = &block_tables[tcache_id][*bcount];
- bd->addr = addr;
- bd->tcache_ptr = tcache_ptr;
- *blk_id = *bcount;
- (*bcount)++;
- if ((addr & 0xc6000000) == 0x02000000) { // ROM
- bd->next = HASH_FUNC(hash_table, addr);
- HASH_FUNC(hash_table, addr) = bd;
- #if (DRC_DEBUG & 1)
- if (bd->next != NULL) {
- printf(" hash collision with %08x\n", bd->next->addr);
- hash_collisions++;
- }
- #endif
- }
- return bd;
- }
- #define ADD_TO_ARRAY(array, count, item, failcode) \
- array[count++] = item; \
- if (count >= ARRAY_SIZE(array)) { \
- printf("warning: " #array " overflow\n"); \
- failcode; \
- }
- int find_in_array(u32 *array, size_t size, u32 what)
- {
- size_t i;
- for (i = 0; i < size; i++)
- if (what == array[i])
- return i;
- return -1;
- }
- // ---------------------------------------------------------------
- typedef enum {
- RC_GR_READ,
- RC_GR_WRITE,
- RC_GR_RMW,
- } rc_gr_mode;
- static int rcache_get_reg_(sh2_reg_e r, rc_gr_mode mode, int do_locking);
- // guest regs with constants
- static u32 dr_gcregs[24];
- // a mask of constant/dirty regs
- static u32 dr_gcregs_mask;
- static u32 dr_gcregs_dirty;
- static void gconst_new(sh2_reg_e r, u32 val)
- {
- #if PROPAGATE_CONSTANTS
- int i;
- dr_gcregs_mask |= 1 << r;
- dr_gcregs_dirty |= 1 << r;
- dr_gcregs[r] = val;
- // throw away old r that we might have cached
- for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
- if ((reg_temp[i].type == HR_CACHED) &&
- reg_temp[i].greg == r) {
- reg_temp[i].type = HR_FREE;
- reg_temp[i].flags = 0;
- }
- }
- #endif
- }
- static int gconst_get(sh2_reg_e r, u32 *val)
- {
- if (dr_gcregs_mask & (1 << r)) {
- *val = dr_gcregs[r];
- return 1;
- }
- return 0;
- }
- static int gconst_check(sh2_reg_e r)
- {
- if ((dr_gcregs_mask | dr_gcregs_dirty) & (1 << r))
- return 1;
- return 0;
- }
- // update hr if dirty, else do nothing
- static int gconst_try_read(int hr, sh2_reg_e r)
- {
- if (dr_gcregs_dirty & (1 << r)) {
- emith_move_r_imm(hr, dr_gcregs[r]);
- dr_gcregs_dirty &= ~(1 << r);
- return 1;
- }
- return 0;
- }
- static void gconst_check_evict(sh2_reg_e r)
- {
- if (dr_gcregs_mask & (1 << r))
- // no longer cached in reg, make dirty again
- dr_gcregs_dirty |= 1 << r;
- }
- static void gconst_kill(sh2_reg_e r)
- {
- dr_gcregs_mask &= ~(1 << r);
- dr_gcregs_dirty &= ~(1 << r);
- }
- static void gconst_clean(void)
- {
- int i;
- for (i = 0; i < ARRAY_SIZE(dr_gcregs); i++)
- if (dr_gcregs_dirty & (1 << i)) {
- // using RC_GR_READ here: it will call gconst_try_read,
- // cache the reg and mark it dirty.
- rcache_get_reg_(i, RC_GR_READ, 0);
- }
- }
- static void gconst_invalidate(void)
- {
- dr_gcregs_mask = dr_gcregs_dirty = 0;
- }
- // register chache
- static u16 rcache_counter;
- static temp_reg_t *rcache_evict(void)
- {
- // evict reg with oldest stamp
- int i, oldest = -1;
- u16 min_stamp = (u16)-1;
- for (i = 0; i < ARRAY_SIZE(reg_temp); i++) {
- if (reg_temp[i].type == HR_CACHED && !(reg_temp[i].flags & HRF_LOCKED) &&
- reg_temp[i].stamp <= min_stamp) {
- min_stamp = reg_temp[i].stamp;
- oldest = i;
- }
- }
- if (oldest == -1) {
- printf("no registers to evict, aborting\n");
- exit(1);
- }
- i = oldest;
- if (reg_temp[i].type == HR_CACHED) {
- if (reg_temp[i].flags & HRF_DIRTY)
- // writeback
- emith_ctx_write(reg_temp[i].hreg, reg_temp[i].greg * 4);
- gconst_check_evict(reg_temp[i].greg);
- }
- reg_temp[i].type = HR_FREE;
- reg_temp[i].flags = 0;
- return ®_temp[i];
- }
- static int get_reg_static(sh2_reg_e r, rc_gr_mode mode)
- {
- int i = reg_map_g2h[r];
- if (i != -1) {
- if (mode != RC_GR_WRITE)
- gconst_try_read(i, r);
- }
- return i;
- }
- // note: must not be called when doing conditional code
- static int rcache_get_reg_(sh2_reg_e r, rc_gr_mode mode, int do_locking)
- {
- temp_reg_t *tr;
- int i, ret;
- // maybe statically mapped?
- ret = get_reg_static(r, mode);
- if (ret != -1)
- goto end;
- rcache_counter++;
- // maybe already cached?
- // if so, prefer against gconst (they must be in sync)
- for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
- if (reg_temp[i].type == HR_CACHED && reg_temp[i].greg == r) {
- reg_temp[i].stamp = rcache_counter;
- if (mode != RC_GR_READ)
- reg_temp[i].flags |= HRF_DIRTY;
- ret = reg_temp[i].hreg;
- goto end;
- }
- }
- // use any free reg
- for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
- if (reg_temp[i].type == HR_FREE) {
- tr = ®_temp[i];
- goto do_alloc;
- }
- }
- tr = rcache_evict();
- do_alloc:
- tr->type = HR_CACHED;
- if (do_locking)
- tr->flags |= HRF_LOCKED;
- if (mode != RC_GR_READ)
- tr->flags |= HRF_DIRTY;
- tr->greg = r;
- tr->stamp = rcache_counter;
- ret = tr->hreg;
- if (mode != RC_GR_WRITE) {
- if (gconst_check(r)) {
- if (gconst_try_read(ret, r))
- tr->flags |= HRF_DIRTY;
- }
- else
- emith_ctx_read(tr->hreg, r * 4);
- }
- end:
- if (mode != RC_GR_READ)
- gconst_kill(r);
- return ret;
- }
- static int rcache_get_reg(sh2_reg_e r, rc_gr_mode mode)
- {
- return rcache_get_reg_(r, mode, 1);
- }
- static int rcache_get_tmp(void)
- {
- temp_reg_t *tr;
- int i;
- for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
- if (reg_temp[i].type == HR_FREE) {
- tr = ®_temp[i];
- goto do_alloc;
- }
- tr = rcache_evict();
- do_alloc:
- tr->type = HR_TEMP;
- return tr->hreg;
- }
- static int rcache_get_arg_id(int arg)
- {
- int i, r = 0;
- host_arg2reg(r, arg);
- for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
- if (reg_temp[i].hreg == r)
- break;
- if (i == ARRAY_SIZE(reg_temp))
- // let's just say it's untracked arg reg
- return r;
- if (reg_temp[i].type == HR_CACHED) {
- // writeback
- if (reg_temp[i].flags & HRF_DIRTY)
- emith_ctx_write(reg_temp[i].hreg, reg_temp[i].greg * 4);
- gconst_check_evict(reg_temp[i].greg);
- }
- else if (reg_temp[i].type == HR_TEMP) {
- printf("arg %d reg %d already used, aborting\n", arg, r);
- exit(1);
- }
- reg_temp[i].type = HR_FREE;
- reg_temp[i].flags = 0;
- return i;
- }
- // get a reg to be used as function arg
- static int rcache_get_tmp_arg(int arg)
- {
- int id = rcache_get_arg_id(arg);
- reg_temp[id].type = HR_TEMP;
- return reg_temp[id].hreg;
- }
- // same but caches a reg. RC_GR_READ only.
- static int rcache_get_reg_arg(int arg, sh2_reg_e r)
- {
- int i, srcr, dstr, dstid;
- int dirty = 0;
- dstid = rcache_get_arg_id(arg);
- dstr = reg_temp[dstid].hreg;
- // maybe already statically mapped?
- srcr = get_reg_static(r, RC_GR_READ);
- if (srcr != -1)
- goto do_cache;
- // maybe already cached?
- for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
- if ((reg_temp[i].type == HR_CACHED) &&
- reg_temp[i].greg == r)
- {
- srcr = reg_temp[i].hreg;
- goto do_cache;
- }
- }
- // must read
- srcr = dstr;
- if (gconst_check(r)) {
- if (gconst_try_read(srcr, r))
- dirty = 1;
- }
- else
- emith_ctx_read(srcr, r * 4);
- do_cache:
- if (dstr != srcr)
- emith_move_r_r(dstr, srcr);
- reg_temp[dstid].stamp = ++rcache_counter;
- reg_temp[dstid].type = HR_CACHED;
- reg_temp[dstid].greg = r;
- reg_temp[dstid].flags |= HRF_LOCKED;
- if (dirty)
- reg_temp[dstid].flags |= HRF_DIRTY;
- return dstr;
- }
- static void rcache_free_tmp(int hr)
- {
- int i;
- for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
- if (reg_temp[i].hreg == hr)
- break;
- if (i == ARRAY_SIZE(reg_temp) || reg_temp[i].type != HR_TEMP) {
- printf("rcache_free_tmp fail: #%i hr %d, type %d\n", i, hr, reg_temp[i].type);
- return;
- }
- reg_temp[i].type = HR_FREE;
- reg_temp[i].flags = 0;
- }
- static void rcache_unlock(int hr)
- {
- int i;
- for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
- if (reg_temp[i].type == HR_CACHED && reg_temp[i].hreg == hr)
- reg_temp[i].flags &= ~HRF_LOCKED;
- }
- static void rcache_unlock_all(void)
- {
- int i;
- for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
- reg_temp[i].flags &= ~HRF_LOCKED;
- }
- static void rcache_clean(void)
- {
- int i;
- gconst_clean();
- for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
- if (reg_temp[i].type == HR_CACHED && (reg_temp[i].flags & HRF_DIRTY)) {
- // writeback
- emith_ctx_write(reg_temp[i].hreg, reg_temp[i].greg * 4);
- reg_temp[i].flags &= ~HRF_DIRTY;
- }
- }
- static void rcache_invalidate(void)
- {
- int i;
- for (i = 0; i < ARRAY_SIZE(reg_temp); i++) {
- reg_temp[i].type = HR_FREE;
- reg_temp[i].flags = 0;
- }
- rcache_counter = 0;
- gconst_invalidate();
- }
- static void rcache_flush(void)
- {
- rcache_clean();
- rcache_invalidate();
- }
- // ---------------------------------------------------------------
- // address space stuff
- static void *dr_get_pc_base(u32 pc, int is_slave)
- {
- void *ret = NULL;
- u32 mask = 0;
- if ((pc & ~0x7ff) == 0) {
- // BIOS
- ret = is_slave ? Pico32xMem->sh2_rom_s : Pico32xMem->sh2_rom_m;
- mask = 0x7ff;
- }
- else if ((pc & 0xfffff000) == 0xc0000000) {
- // data array
- ret = Pico32xMem->data_array[is_slave];
- mask = 0xfff;
- }
- else if ((pc & 0xc6000000) == 0x06000000) {
- // SDRAM
- ret = Pico32xMem->sdram;
- mask = 0x03ffff;
- }
- else if ((pc & 0xc6000000) == 0x02000000) {
- // ROM
- ret = Pico.rom;
- mask = 0x3fffff;
- }
- if (ret == NULL)
- return (void *)-1; // NULL is valid value
- return (char *)ret - (pc & ~mask);
- }
- static int emit_get_rbase_and_offs(u32 a, u32 *offs)
- {
- int poffs = -1;
- u32 mask = 0;
- int hr;
- if ((a & ~0x7ff) == 0) {
- // BIOS
- poffs = offsetof(SH2, p_bios);
- mask = 0x7ff;
- }
- else if ((a & 0xfffff000) == 0xc0000000) {
- // data array
- poffs = offsetof(SH2, p_da);
- mask = 0xfff;
- }
- else if ((a & 0xc6000000) == 0x06000000) {
- // SDRAM
- poffs = offsetof(SH2, p_sdram);
- mask = 0x03ffff;
- }
- else if ((a & 0xc6000000) == 0x02000000) {
- // ROM
- poffs = offsetof(SH2, p_rom);
- mask = 0x3fffff;
- }
- if (poffs == -1)
- return -1;
- // XXX: could use related reg
- hr = rcache_get_tmp();
- emith_ctx_read(hr, poffs);
- emith_add_r_imm(hr, a & mask & ~0xff);
- *offs = a & 0xff; // XXX: ARM oriented..
- return hr;
- }
- static void REGPARM(3) *lookup_block(u32 pc, int is_slave, int *tcache_id)
- {
- block_desc *bd = NULL;
- void *block = NULL;
- *tcache_id = 0;
- // we have full block id tables for data_array and RAM
- // BIOS goes to data_array table too
- if ((pc & 0xe0000000) == 0xc0000000 || (pc & ~0xfff) == 0) {
- int blkid = Pico32xMem->drcblk_da[is_slave][(pc & 0xfff) >> SH2_DRCBLK_DA_SHIFT];
- *tcache_id = 1 + is_slave;
- if (blkid & 1) {
- bd = &block_tables[*tcache_id][blkid >> 1];
- block = bd->tcache_ptr;
- }
- }
- // RAM
- else if ((pc & 0xc6000000) == 0x06000000) {
- int blkid = Pico32xMem->drcblk_ram[(pc & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT];
- if (blkid & 1) {
- bd = &block_tables[0][blkid >> 1];
- block = bd->tcache_ptr;
- }
- }
- // ROM
- else if ((pc & 0xc6000000) == 0x02000000) {
- bd = HASH_FUNC(hash_table, pc);
- if (bd != NULL) {
- if (bd->addr == pc)
- block = bd->tcache_ptr;
- else
- block = dr_find_block(bd, pc);
- }
- }
- #if (DRC_DEBUG & 1)
- if (bd != NULL)
- bd->refcount++;
- #endif
- return block;
- }
- static void emit_move_r_imm32(sh2_reg_e dst, u32 imm)
- {
- #if PROPAGATE_CONSTANTS
- gconst_new(dst, imm);
- #else
- int hr = rcache_get_reg(dst, RC_GR_WRITE);
- emith_move_r_imm(hr, imm);
- #endif
- }
- static void emit_move_r_r(sh2_reg_e dst, sh2_reg_e src)
- {
- int hr_d = rcache_get_reg(dst, RC_GR_WRITE);
- int hr_s = rcache_get_reg(src, RC_GR_READ);
- emith_move_r_r(hr_d, hr_s);
- }
- // T must be clear, and comparison done just before this
- static void emit_or_t_if_eq(int srr)
- {
- EMITH_SJMP_START(DCOND_NE);
- emith_or_r_imm_c(DCOND_EQ, srr, T);
- EMITH_SJMP_END(DCOND_NE);
- }
- // arguments must be ready
- // reg cache must be clean before call
- static int emit_memhandler_read_(int size, int ram_check)
- {
- int arg0, arg1;
- host_arg2reg(arg0, 0);
- rcache_clean();
- // must writeback cycles for poll detection stuff
- // FIXME: rm
- if (reg_map_g2h[SHR_SR] != -1)
- emith_ctx_write(reg_map_g2h[SHR_SR], SHR_SR * 4);
- arg1 = rcache_get_tmp_arg(1);
- emith_move_r_r(arg1, CONTEXT_REG);
- #ifndef PDB_NET
- if (ram_check && Pico.rom == (void *)0x02000000 && Pico32xMem->sdram == (void *)0x06000000) {
- int tmp = rcache_get_tmp();
- emith_and_r_r_imm(tmp, arg0, 0xfb000000);
- emith_cmp_r_imm(tmp, 0x02000000);
- switch (size) {
- case 0: // 8
- EMITH_SJMP3_START(DCOND_NE);
- emith_eor_r_imm_c(DCOND_EQ, arg0, 1);
- emith_read8_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
- EMITH_SJMP3_MID(DCOND_NE);
- emith_call_cond(DCOND_NE, sh2_drc_read8);
- EMITH_SJMP3_END();
- break;
- case 1: // 16
- EMITH_SJMP3_START(DCOND_NE);
- emith_read16_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
- EMITH_SJMP3_MID(DCOND_NE);
- emith_call_cond(DCOND_NE, sh2_drc_read16);
- EMITH_SJMP3_END();
- break;
- case 2: // 32
- EMITH_SJMP3_START(DCOND_NE);
- emith_read_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
- emith_ror_c(DCOND_EQ, arg0, arg0, 16);
- EMITH_SJMP3_MID(DCOND_NE);
- emith_call_cond(DCOND_NE, sh2_drc_read32);
- EMITH_SJMP3_END();
- break;
- }
- }
- else
- #endif
- {
- switch (size) {
- case 0: // 8
- emith_call(sh2_drc_read8);
- break;
- case 1: // 16
- emith_call(sh2_drc_read16);
- break;
- case 2: // 32
- emith_call(sh2_drc_read32);
- break;
- }
- }
- rcache_invalidate();
- // assuming arg0 and retval reg matches
- return rcache_get_tmp_arg(0);
- }
- static int emit_memhandler_read(int size)
- {
- return emit_memhandler_read_(size, 1);
- }
- static int emit_memhandler_read_rr(sh2_reg_e rd, sh2_reg_e rs, u32 offs, int size)
- {
- int hr, hr2, ram_check = 1;
- u32 val, offs2;
- if (gconst_get(rs, &val)) {
- hr = emit_get_rbase_and_offs(val + offs, &offs2);
- if (hr != -1) {
- hr2 = rcache_get_reg(rd, RC_GR_WRITE);
- switch (size) {
- case 0: // 8
- emith_read8_r_r_offs(hr2, hr, offs2 ^ 1);
- emith_sext(hr2, hr2, 8);
- break;
- case 1: // 16
- emith_read16_r_r_offs(hr2, hr, offs2);
- emith_sext(hr2, hr2, 16);
- break;
- case 2: // 32
- emith_read_r_r_offs(hr2, hr, offs2);
- emith_ror(hr2, hr2, 16);
- break;
- }
- rcache_free_tmp(hr);
- return hr2;
- }
- ram_check = 0;
- }
- hr = rcache_get_reg_arg(0, rs);
- if (offs != 0)
- emith_add_r_imm(hr, offs);
- hr = emit_memhandler_read_(size, ram_check);
- hr2 = rcache_get_reg(rd, RC_GR_WRITE);
- if (size != 2) {
- emith_sext(hr2, hr, (size == 1) ? 16 : 8);
- } else
- emith_move_r_r(hr2, hr);
- rcache_free_tmp(hr);
- return hr2;
- }
- static void emit_memhandler_write(int size, u32 pc, int delay)
- {
- int ctxr;
- host_arg2reg(ctxr, 2);
- switch (size) {
- case 0: // 8
- // XXX: consider inlining sh2_drc_write8
- if (delay) {
- emith_call(sh2_drc_write8_slot);
- } else {
- emit_move_r_imm32(SHR_PC, pc);
- rcache_clean();
- emith_call(sh2_drc_write8);
- }
- break;
- case 1: // 16
- if (delay) {
- emith_call(sh2_drc_write16_slot);
- } else {
- emit_move_r_imm32(SHR_PC, pc);
- rcache_clean();
- emith_call(sh2_drc_write16);
- }
- break;
- case 2: // 32
- emith_move_r_r(ctxr, CONTEXT_REG);
- emith_call(sh2_drc_write32);
- break;
- }
- rcache_invalidate();
- }
- // @(Rx,Ry)
- static int emit_indirect_indexed_read(int rx, int ry, int size)
- {
- int a0, t;
- a0 = rcache_get_reg_arg(0, rx);
- t = rcache_get_reg(ry, RC_GR_READ);
- emith_add_r_r(a0, t);
- return emit_memhandler_read(size);
- }
- // read @Rn, @rm
- static void emit_indirect_read_double(u32 *rnr, u32 *rmr, int rn, int rm, int size)
- {
- int tmp;
- rcache_get_reg_arg(0, rn);
- tmp = emit_memhandler_read(size);
- emith_ctx_write(tmp, offsetof(SH2, drc_tmp));
- rcache_free_tmp(tmp);
- tmp = rcache_get_reg(rn, RC_GR_RMW);
- emith_add_r_imm(tmp, 1 << size);
- rcache_unlock(tmp);
- rcache_get_reg_arg(0, rm);
- *rmr = emit_memhandler_read(size);
- *rnr = rcache_get_tmp();
- emith_ctx_read(*rnr, offsetof(SH2, drc_tmp));
- tmp = rcache_get_reg(rm, RC_GR_RMW);
- emith_add_r_imm(tmp, 1 << size);
- rcache_unlock(tmp);
- }
-
- static void emit_do_static_regs(int is_write, int tmpr)
- {
- int i, r, count;
- for (i = 0; i < ARRAY_SIZE(reg_map_g2h); i++) {
- r = reg_map_g2h[i];
- if (r == -1)
- continue;
- for (count = 1; i < ARRAY_SIZE(reg_map_g2h) - 1; i++, r++) {
- if (reg_map_g2h[i + 1] != r + 1)
- break;
- count++;
- }
- if (count > 1) {
- // i, r point to last item
- if (is_write)
- emith_ctx_write_multiple(r - count + 1, (i - count + 1) * 4, count, tmpr);
- else
- emith_ctx_read_multiple(r - count + 1, (i - count + 1) * 4, count, tmpr);
- } else {
- if (is_write)
- emith_ctx_write(r, i * 4);
- else
- emith_ctx_read(r, i * 4);
- }
- }
- }
- static void emit_block_entry(void)
- {
- int arg0, arg1, arg2;
- host_arg2reg(arg0, 0);
- host_arg2reg(arg1, 1);
- host_arg2reg(arg2, 2);
- #if (DRC_DEBUG & 4) || defined(PDB)
- emit_do_static_regs(1, arg2);
- emith_move_r_r(arg1, CONTEXT_REG);
- emith_move_r_r(arg2, rcache_get_reg(SHR_SR, RC_GR_READ));
- emith_call(sh2_drc_log_entry);
- rcache_invalidate();
- #endif
- emith_tst_r_r(arg0, arg0);
- EMITH_SJMP_START(DCOND_EQ);
- emith_jump_reg_c(DCOND_NE, arg0);
- EMITH_SJMP_END(DCOND_EQ);
- }
- void dr_link_blocks(void *target, u32 pc, int tcache_id)
- {
- #if LINK_BRANCHES
- block_link *bl = block_links[tcache_id];
- int cnt = block_link_counts[tcache_id];
- int i;
- for (i = 0; i < cnt; i++) {
- if (bl[i].target_pc == pc) {
- dbg(1, "- link from %p", bl[i].jump);
- emith_jump_patch(bl[i].jump, target);
- // XXX: sync ARM caches (old jump should be fine)?
- }
- }
- #endif
- }
- void *dr_prepare_ext_branch(u32 pc, SH2 *sh2, int tcache_id)
- {
- #if LINK_BRANCHES
- int target_tcache_id;
- void *target;
- int ret;
- target = lookup_block(pc, sh2->is_slave, &target_tcache_id);
- if (target_tcache_id == tcache_id) {
- // allow linking blocks only from local cache
- ret = dr_add_block_link(pc, tcache_ptr, tcache_id);
- if (ret < 0)
- return NULL;
- }
- if (target == NULL || target_tcache_id != tcache_id)
- target = sh2_drc_dispatcher;
- return target;
- #else
- return sh2_drc_dispatcher;
- #endif
- }
- #define DELAYED_OP \
- drcf.delayed_op = 2
- #define DELAY_SAVE_T(sr) { \
- emith_bic_r_imm(sr, T_save); \
- emith_tst_r_imm(sr, T); \
- EMITH_SJMP_START(DCOND_EQ); \
- emith_or_r_imm_c(DCOND_NE, sr, T_save); \
- EMITH_SJMP_END(DCOND_EQ); \
- drcf.use_saved_t = 1; \
- }
- #define FLUSH_CYCLES(sr) \
- if (cycles > 0) { \
- emith_sub_r_imm(sr, cycles << 12); \
- cycles = 0; \
- }
- #define CHECK_UNHANDLED_BITS(mask) { \
- if ((op & (mask)) != 0) \
- goto default_; \
- }
- #define FETCH_OP(pc) \
- dr_pc_base[(pc) / 2]
- #define FETCH32(a) \
- ((dr_pc_base[(a) / 2] << 16) | dr_pc_base[(a) / 2 + 1])
- #define GET_Fx() \
- ((op >> 4) & 0x0f)
- #define GET_Rm GET_Fx
- #define GET_Rn() \
- ((op >> 8) & 0x0f)
- #define CHECK_FX_LT(n) \
- if (GET_Fx() >= n) \
- goto default_
- #define MAX_LOCAL_BRANCHES 32
- // op_flags: data from 1st pass
- #define OP_FLAGS(pc) op_flags[((pc) - base_pc) / 2]
- #define OF_DELAY_OP (1 << 0)
- static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
- {
- // XXX: maybe use structs instead?
- void *branch_target_ptr[MAX_LOCAL_BRANCHES];
- u32 branch_target_pc[MAX_LOCAL_BRANCHES];
- int branch_target_count = 0;
- void *branch_patch_ptr[MAX_LOCAL_BRANCHES];
- u32 branch_patch_pc[MAX_LOCAL_BRANCHES];
- int branch_patch_count = 0;
- int pending_branch_cond = -1;
- int pending_branch_pc = 0;
- u8 op_flags[BLOCK_CYCLE_LIMIT + 1];
- struct {
- u32 delayed_op:2;
- u32 test_irq:1;
- u32 use_saved_t:1; // delayed op modifies T
- } drcf = { 0, };
- // PC of current, first, last, last_target_blk SH2 insn
- u32 pc, base_pc, end_pc, out_pc;
- u32 last_inlined_literal = 0;
- void *block_entry;
- block_desc *this_block;
- u16 *dr_pc_base;
- int blkid_main = 0;
- int skip_op = 0;
- u32 tmp, tmp2;
- int cycles;
- int op;
- int i;
- base_pc = sh2->pc;
- // get base/validate PC
- dr_pc_base = dr_get_pc_base(base_pc, sh2->is_slave);
- if (dr_pc_base == (void *)-1) {
- printf("invalid PC, aborting: %08x\n", base_pc);
- // FIXME: be less destructive
- exit(1);
- }
- tcache_ptr = tcache_ptrs[tcache_id];
- this_block = dr_add_block(base_pc, tcache_id, &blkid_main);
- if (this_block == NULL)
- return NULL;
- // predict tcache overflow
- tmp = tcache_ptr - tcache_bases[tcache_id];
- if (tmp > tcache_sizes[tcache_id] - MAX_BLOCK_SIZE) {
- printf("tcache %d overflow\n", tcache_id);
- return NULL;
- }
- block_entry = tcache_ptr;
- dbg(1, "== %csh2 block #%d,%d %08x -> %p", sh2->is_slave ? 's' : 'm',
- tcache_id, blkid_main, base_pc, block_entry);
- dr_link_blocks(tcache_ptr, base_pc, tcache_id);
- // 1st pass: scan forward for local branches
- memset(op_flags, 0, sizeof(op_flags));
- for (cycles = 0, pc = base_pc; cycles < BLOCK_CYCLE_LIMIT; cycles++, pc += 2) {
- op = FETCH_OP(pc);
- if ((op & 0xf000) == 0xa000 || (op & 0xf000) == 0xb000) { // BRA, BSR
- signed int offs = ((signed int)(op << 20) >> 19);
- pc += 2;
- OP_FLAGS(pc) |= OF_DELAY_OP;
- ADD_TO_ARRAY(branch_target_pc, branch_target_count, pc + offs + 2,);
- break;
- }
- if ((op & 0xf000) == 0) {
- op &= 0xff;
- if (op == 0x1b) // SLEEP
- break;
- if (op == 0x23 || op == 0x03 || op == 0x0b || op == 0x2b) { // BRAF, BSRF, RTS, RTE
- pc += 2;
- OP_FLAGS(pc) |= OF_DELAY_OP;
- break;
- }
- continue;
- }
- if ((op & 0xf0df) == 0x400b) { // JMP, JSR
- pc += 2;
- OP_FLAGS(pc) |= OF_DELAY_OP;
- break;
- }
- if ((op & 0xf900) == 0x8900) { // BT(S), BF(S)
- signed int offs = ((signed int)(op << 24) >> 23);
- if (op & 0x0400)
- OP_FLAGS(pc + 2) |= OF_DELAY_OP;
- ADD_TO_ARRAY(branch_target_pc, branch_target_count, pc + offs + 4, break);
- }
- if ((op & 0xff00) == 0xc300) // TRAPA
- break;
- }
- end_pc = pc;
- // clean branch_targets that are not really local,
- // and that land on delay slots
- for (i = 0, tmp = 0; i < branch_target_count; i++) {
- pc = branch_target_pc[i];
- if (base_pc <= pc && pc <= end_pc && !(OP_FLAGS(pc) & OF_DELAY_OP))
- branch_target_pc[tmp++] = branch_target_pc[i];
- }
- branch_target_count = tmp;
- memset(branch_target_ptr, 0, sizeof(branch_target_ptr[0]) * branch_target_count);
- // -------------------------------------------------
- // 2nd pass: actual compilation
- out_pc = 0;
- pc = base_pc;
- for (cycles = 0; pc <= end_pc || drcf.delayed_op; )
- {
- u32 tmp3, tmp4, sr;
- if (drcf.delayed_op > 0)
- drcf.delayed_op--;
- op = FETCH_OP(pc);
- i = find_in_array(branch_target_pc, branch_target_count, pc);
- if (i >= 0)
- {
- if (pc != sh2->pc)
- {
- /* make "subblock" - just a mid-block entry */
- block_desc *subblock;
- u16 *drcblk;
- int blkid;
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- FLUSH_CYCLES(sr);
- // decide if to flush rcache
- if ((op & 0xf0ff) == 0x4010 && FETCH_OP(pc + 2) == 0x8bfd) // DT; BF #-2
- rcache_clean();
- else
- rcache_flush();
- do_host_disasm(tcache_id);
- subblock = dr_add_block(pc, tcache_id, &blkid);
- if (subblock == NULL)
- return NULL;
- subblock->end_addr = pc;
- if (tcache_id != 0) { // data array, BIOS
- drcblk = Pico32xMem->drcblk_da[sh2->is_slave];
- drcblk += (pc & 0x00fff) >> SH2_DRCBLK_DA_SHIFT;
- *drcblk = (blkid << 1) | 1;
- } else if ((this_block->addr & 0xc7fc0000) == 0x06000000) { // DRAM
- drcblk = Pico32xMem->drcblk_ram;
- drcblk += (pc & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
- *drcblk = (blkid << 1) | 1;
- }
- dbg(1, "-- %csh2 subblock #%d,%d %08x -> %p", sh2->is_slave ? 's' : 'm',
- tcache_id, blkid, pc, tcache_ptr);
- // since we made a block entry, link any other blocks that jump to current pc
- dr_link_blocks(tcache_ptr, pc, tcache_id);
- }
- branch_target_ptr[i] = tcache_ptr;
- // must update PC
- emit_move_r_imm32(SHR_PC, pc);
- rcache_clean();
- // check cycles
- sr = rcache_get_reg(SHR_SR, RC_GR_READ);
- emith_cmp_r_imm(sr, 0);
- emith_jump_cond(DCOND_LE, sh2_drc_exit);
- do_host_disasm(tcache_id);
- }
- #if (DRC_DEBUG & 3)
- insns_compiled++;
- #if (DRC_DEBUG & 2)
- DasmSH2(sh2dasm_buff, pc, op);
- printf("%08x %04x %s\n", pc, op, sh2dasm_buff);
- #endif
- #endif
- pc += 2;
- cycles++;
- if (skip_op > 0) {
- skip_op--;
- continue;
- }
- switch ((op >> 12) & 0x0f)
- {
- /////////////////////////////////////////////
- case 0x00:
- switch (op & 0x0f)
- {
- case 0x02:
- tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
- switch (GET_Fx())
- {
- case 0: // STC SR,Rn 0000nnnn00000010
- tmp2 = SHR_SR;
- break;
- case 1: // STC GBR,Rn 0000nnnn00010010
- tmp2 = SHR_GBR;
- break;
- case 2: // STC VBR,Rn 0000nnnn00100010
- tmp2 = SHR_VBR;
- break;
- default:
- goto default_;
- }
- tmp3 = rcache_get_reg(tmp2, RC_GR_READ);
- emith_move_r_r(tmp, tmp3);
- if (tmp2 == SHR_SR)
- emith_clear_msb(tmp, tmp, 22); // reserved bits defined by ISA as 0
- goto end_op;
- case 0x03:
- CHECK_UNHANDLED_BITS(0xd0);
- // BRAF Rm 0000mmmm00100011
- // BSRF Rm 0000mmmm00000011
- DELAYED_OP;
- tmp = rcache_get_reg(SHR_PC, RC_GR_WRITE);
- tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
- emith_move_r_r(tmp, tmp2);
- if (op & 0x20)
- emith_add_r_imm(tmp, pc + 2);
- else { // BSRF
- tmp3 = rcache_get_reg(SHR_PR, RC_GR_WRITE);
- emith_move_r_imm(tmp3, pc + 2);
- emith_add_r_r(tmp, tmp3);
- }
- out_pc = (u32)-1;
- cycles++;
- goto end_op;
- case 0x04: // MOV.B Rm,@(R0,Rn) 0000nnnnmmmm0100
- case 0x05: // MOV.W Rm,@(R0,Rn) 0000nnnnmmmm0101
- case 0x06: // MOV.L Rm,@(R0,Rn) 0000nnnnmmmm0110
- rcache_clean();
- tmp = rcache_get_reg_arg(1, GET_Rm());
- tmp2 = rcache_get_reg_arg(0, SHR_R0);
- tmp3 = rcache_get_reg(GET_Rn(), RC_GR_READ);
- emith_add_r_r(tmp2, tmp3);
- emit_memhandler_write(op & 3, pc, drcf.delayed_op);
- goto end_op;
- case 0x07:
- // MUL.L Rm,Rn 0000nnnnmmmm0111
- tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
- tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
- emith_mul(tmp3, tmp2, tmp);
- cycles++;
- goto end_op;
- case 0x08:
- CHECK_UNHANDLED_BITS(0xf00);
- switch (GET_Fx())
- {
- case 0: // CLRT 0000000000001000
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_bic_r_imm(sr, T);
- break;
- case 1: // SETT 0000000000011000
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_or_r_imm(sr, T);
- break;
- case 2: // CLRMAC 0000000000101000
- emit_move_r_imm32(SHR_MACL, 0);
- emit_move_r_imm32(SHR_MACH, 0);
- break;
- default:
- goto default_;
- }
- goto end_op;
- case 0x09:
- switch (GET_Fx())
- {
- case 0: // NOP 0000000000001001
- CHECK_UNHANDLED_BITS(0xf00);
- break;
- case 1: // DIV0U 0000000000011001
- CHECK_UNHANDLED_BITS(0xf00);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_bic_r_imm(sr, M|Q|T);
- break;
- case 2: // MOVT Rn 0000nnnn00101001
- sr = rcache_get_reg(SHR_SR, RC_GR_READ);
- tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
- emith_clear_msb(tmp2, sr, 31);
- break;
- default:
- goto default_;
- }
- goto end_op;
- case 0x0a:
- tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
- switch (GET_Fx())
- {
- case 0: // STS MACH,Rn 0000nnnn00001010
- tmp2 = SHR_MACH;
- break;
- case 1: // STS MACL,Rn 0000nnnn00011010
- tmp2 = SHR_MACL;
- break;
- case 2: // STS PR,Rn 0000nnnn00101010
- tmp2 = SHR_PR;
- break;
- default:
- goto default_;
- }
- tmp2 = rcache_get_reg(tmp2, RC_GR_READ);
- emith_move_r_r(tmp, tmp2);
- goto end_op;
- case 0x0b:
- CHECK_UNHANDLED_BITS(0xf00);
- switch (GET_Fx())
- {
- case 0: // RTS 0000000000001011
- DELAYED_OP;
- emit_move_r_r(SHR_PC, SHR_PR);
- out_pc = (u32)-1;
- cycles++;
- break;
- case 1: // SLEEP 0000000000011011
- tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
- emith_clear_msb(tmp, tmp, 20); // clear cycles
- out_pc = out_pc - 2;
- cycles = 1;
- goto end_op;
- case 2: // RTE 0000000000101011
- DELAYED_OP;
- // pop PC
- emit_memhandler_read_rr(SHR_PC, SHR_SP, 0, 2);
- // pop SR
- tmp = rcache_get_reg_arg(0, SHR_SP);
- emith_add_r_imm(tmp, 4);
- tmp = emit_memhandler_read(2);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- emith_write_sr(sr, tmp);
- rcache_free_tmp(tmp);
- tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
- emith_add_r_imm(tmp, 4*2);
- drcf.test_irq = 1;
- out_pc = (u32)-1;
- cycles += 3;
- break;
- default:
- goto default_;
- }
- goto end_op;
- case 0x0c: // MOV.B @(R0,Rm),Rn 0000nnnnmmmm1100
- case 0x0d: // MOV.W @(R0,Rm),Rn 0000nnnnmmmm1101
- case 0x0e: // MOV.L @(R0,Rm),Rn 0000nnnnmmmm1110
- tmp = emit_indirect_indexed_read(SHR_R0, GET_Rm(), op & 3);
- tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
- if ((op & 3) != 2) {
- emith_sext(tmp2, tmp, (op & 1) ? 16 : 8);
- } else
- emith_move_r_r(tmp2, tmp);
- rcache_free_tmp(tmp);
- goto end_op;
- case 0x0f: // MAC.L @Rm+,@Rn+ 0000nnnnmmmm1111
- emit_indirect_read_double(&tmp, &tmp2, GET_Rn(), GET_Rm(), 2);
- tmp4 = rcache_get_reg(SHR_MACH, RC_GR_RMW);
- /* MS 16 MAC bits unused if saturated */
- sr = rcache_get_reg(SHR_SR, RC_GR_READ);
- emith_tst_r_imm(sr, S);
- EMITH_SJMP_START(DCOND_EQ);
- emith_clear_msb_c(DCOND_NE, tmp4, tmp4, 16);
- EMITH_SJMP_END(DCOND_EQ);
- rcache_unlock(sr);
- tmp3 = rcache_get_reg(SHR_MACL, RC_GR_RMW); // might evict SR
- emith_mula_s64(tmp3, tmp4, tmp, tmp2);
- rcache_free_tmp(tmp2);
- sr = rcache_get_reg(SHR_SR, RC_GR_READ); // reget just in case
- emith_tst_r_imm(sr, S);
- EMITH_JMP_START(DCOND_EQ);
- emith_asr(tmp, tmp4, 15);
- emith_cmp_r_imm(tmp, -1); // negative overflow (0x80000000..0xffff7fff)
- EMITH_SJMP_START(DCOND_GE);
- emith_move_r_imm_c(DCOND_LT, tmp4, 0x8000);
- emith_move_r_imm_c(DCOND_LT, tmp3, 0x0000);
- EMITH_SJMP_END(DCOND_GE);
- emith_cmp_r_imm(tmp, 0); // positive overflow (0x00008000..0x7fffffff)
- EMITH_SJMP_START(DCOND_LE);
- emith_move_r_imm_c(DCOND_GT, tmp4, 0x00007fff);
- emith_move_r_imm_c(DCOND_GT, tmp3, 0xffffffff);
- EMITH_SJMP_END(DCOND_LE);
- EMITH_JMP_END(DCOND_EQ);
- rcache_free_tmp(tmp);
- cycles += 3;
- goto end_op;
- }
- goto default_;
- /////////////////////////////////////////////
- case 0x01:
- // MOV.L Rm,@(disp,Rn) 0001nnnnmmmmdddd
- rcache_clean();
- tmp = rcache_get_reg_arg(0, GET_Rn());
- tmp2 = rcache_get_reg_arg(1, GET_Rm());
- if (op & 0x0f)
- emith_add_r_imm(tmp, (op & 0x0f) * 4);
- emit_memhandler_write(2, pc, drcf.delayed_op);
- goto end_op;
- case 0x02:
- switch (op & 0x0f)
- {
- case 0x00: // MOV.B Rm,@Rn 0010nnnnmmmm0000
- case 0x01: // MOV.W Rm,@Rn 0010nnnnmmmm0001
- case 0x02: // MOV.L Rm,@Rn 0010nnnnmmmm0010
- rcache_clean();
- rcache_get_reg_arg(0, GET_Rn());
- rcache_get_reg_arg(1, GET_Rm());
- emit_memhandler_write(op & 3, pc, drcf.delayed_op);
- goto end_op;
- case 0x04: // MOV.B Rm,@–Rn 0010nnnnmmmm0100
- case 0x05: // MOV.W Rm,@–Rn 0010nnnnmmmm0101
- case 0x06: // MOV.L Rm,@–Rn 0010nnnnmmmm0110
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- emith_sub_r_imm(tmp, (1 << (op & 3)));
- rcache_clean();
- rcache_get_reg_arg(0, GET_Rn());
- rcache_get_reg_arg(1, GET_Rm());
- emit_memhandler_write(op & 3, pc, drcf.delayed_op);
- goto end_op;
- case 0x07: // DIV0S Rm,Rn 0010nnnnmmmm0111
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
- tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_bic_r_imm(sr, M|Q|T);
- emith_tst_r_imm(tmp2, (1<<31));
- EMITH_SJMP_START(DCOND_EQ);
- emith_or_r_imm_c(DCOND_NE, sr, Q);
- EMITH_SJMP_END(DCOND_EQ);
- emith_tst_r_imm(tmp3, (1<<31));
- EMITH_SJMP_START(DCOND_EQ);
- emith_or_r_imm_c(DCOND_NE, sr, M);
- EMITH_SJMP_END(DCOND_EQ);
- emith_teq_r_r(tmp2, tmp3);
- EMITH_SJMP_START(DCOND_PL);
- emith_or_r_imm_c(DCOND_MI, sr, T);
- EMITH_SJMP_END(DCOND_PL);
- goto end_op;
- case 0x08: // TST Rm,Rn 0010nnnnmmmm1000
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
- tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_bic_r_imm(sr, T);
- emith_tst_r_r(tmp2, tmp3);
- emit_or_t_if_eq(sr);
- goto end_op;
- case 0x09: // AND Rm,Rn 0010nnnnmmmm1001
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- emith_and_r_r(tmp, tmp2);
- goto end_op;
- case 0x0a: // XOR Rm,Rn 0010nnnnmmmm1010
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- emith_eor_r_r(tmp, tmp2);
- goto end_op;
- case 0x0b: // OR Rm,Rn 0010nnnnmmmm1011
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- emith_or_r_r(tmp, tmp2);
- goto end_op;
- case 0x0c: // CMP/STR Rm,Rn 0010nnnnmmmm1100
- tmp = rcache_get_tmp();
- tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
- tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- emith_eor_r_r_r(tmp, tmp2, tmp3);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_bic_r_imm(sr, T);
- emith_tst_r_imm(tmp, 0x000000ff);
- emit_or_t_if_eq(tmp);
- emith_tst_r_imm(tmp, 0x0000ff00);
- emit_or_t_if_eq(tmp);
- emith_tst_r_imm(tmp, 0x00ff0000);
- emit_or_t_if_eq(tmp);
- emith_tst_r_imm(tmp, 0xff000000);
- emit_or_t_if_eq(tmp);
- rcache_free_tmp(tmp);
- goto end_op;
- case 0x0d: // XTRCT Rm,Rn 0010nnnnmmmm1101
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- emith_lsr(tmp, tmp, 16);
- emith_or_r_r_lsl(tmp, tmp2, 16);
- goto end_op;
- case 0x0e: // MULU.W Rm,Rn 0010nnnnmmmm1110
- case 0x0f: // MULS.W Rm,Rn 0010nnnnmmmm1111
- tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
- tmp = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
- if (op & 1) {
- emith_sext(tmp, tmp2, 16);
- } else
- emith_clear_msb(tmp, tmp2, 16);
- tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- tmp2 = rcache_get_tmp();
- if (op & 1) {
- emith_sext(tmp2, tmp3, 16);
- } else
- emith_clear_msb(tmp2, tmp3, 16);
- emith_mul(tmp, tmp, tmp2);
- rcache_free_tmp(tmp2);
- // FIXME: causes timing issues in Doom?
- // cycles++;
- goto end_op;
- }
- goto default_;
- /////////////////////////////////////////////
- case 0x03:
- switch (op & 0x0f)
- {
- case 0x00: // CMP/EQ Rm,Rn 0011nnnnmmmm0000
- case 0x02: // CMP/HS Rm,Rn 0011nnnnmmmm0010
- case 0x03: // CMP/GE Rm,Rn 0011nnnnmmmm0011
- case 0x06: // CMP/HI Rm,Rn 0011nnnnmmmm0110
- case 0x07: // CMP/GT Rm,Rn 0011nnnnmmmm0111
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
- tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_bic_r_imm(sr, T);
- emith_cmp_r_r(tmp2, tmp3);
- switch (op & 0x07)
- {
- case 0x00: // CMP/EQ
- emit_or_t_if_eq(sr);
- break;
- case 0x02: // CMP/HS
- EMITH_SJMP_START(DCOND_LO);
- emith_or_r_imm_c(DCOND_HS, sr, T);
- EMITH_SJMP_END(DCOND_LO);
- break;
- case 0x03: // CMP/GE
- EMITH_SJMP_START(DCOND_LT);
- emith_or_r_imm_c(DCOND_GE, sr, T);
- EMITH_SJMP_END(DCOND_LT);
- break;
- case 0x06: // CMP/HI
- EMITH_SJMP_START(DCOND_LS);
- emith_or_r_imm_c(DCOND_HI, sr, T);
- EMITH_SJMP_END(DCOND_LS);
- break;
- case 0x07: // CMP/GT
- EMITH_SJMP_START(DCOND_LE);
- emith_or_r_imm_c(DCOND_GT, sr, T);
- EMITH_SJMP_END(DCOND_LE);
- break;
- }
- goto end_op;
- case 0x04: // DIV1 Rm,Rn 0011nnnnmmmm0100
- // Q1 = carry(Rn = (Rn << 1) | T)
- // if Q ^ M
- // Q2 = carry(Rn += Rm)
- // else
- // Q2 = carry(Rn -= Rm)
- // Q = M ^ Q1 ^ Q2
- // T = (Q == M) = !(Q ^ M) = !(Q1 ^ Q2)
- tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_tpop_carry(sr, 0);
- emith_adcf_r_r(tmp2, tmp2);
- emith_tpush_carry(sr, 0); // keep Q1 in T for now
- tmp4 = rcache_get_tmp();
- emith_and_r_r_imm(tmp4, sr, M);
- emith_eor_r_r_lsr(sr, tmp4, M_SHIFT - Q_SHIFT); // Q ^= M
- rcache_free_tmp(tmp4);
- // add or sub, invert T if carry to get Q1 ^ Q2
- // in: (Q ^ M) passed in Q, Q1 in T
- emith_sh2_div1_step(tmp2, tmp3, sr);
- emith_bic_r_imm(sr, Q);
- emith_tst_r_imm(sr, M);
- EMITH_SJMP_START(DCOND_EQ);
- emith_or_r_imm_c(DCOND_NE, sr, Q); // Q = M
- EMITH_SJMP_END(DCOND_EQ);
- emith_tst_r_imm(sr, T);
- EMITH_SJMP_START(DCOND_EQ);
- emith_eor_r_imm_c(DCOND_NE, sr, Q); // Q = M ^ Q1 ^ Q2
- EMITH_SJMP_END(DCOND_EQ);
- emith_eor_r_imm(sr, T); // T = !(Q1 ^ Q2)
- goto end_op;
- case 0x05: // DMULU.L Rm,Rn 0011nnnnmmmm0101
- tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
- tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
- tmp4 = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
- emith_mul_u64(tmp3, tmp4, tmp, tmp2);
- goto end_op;
- case 0x08: // SUB Rm,Rn 0011nnnnmmmm1000
- case 0x0c: // ADD Rm,Rn 0011nnnnmmmm1100
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- if (op & 4) {
- emith_add_r_r(tmp, tmp2);
- } else
- emith_sub_r_r(tmp, tmp2);
- goto end_op;
- case 0x0a: // SUBC Rm,Rn 0011nnnnmmmm1010
- case 0x0e: // ADDC Rm,Rn 0011nnnnmmmm1110
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- if (op & 4) { // adc
- emith_tpop_carry(sr, 0);
- emith_adcf_r_r(tmp, tmp2);
- emith_tpush_carry(sr, 0);
- } else {
- emith_tpop_carry(sr, 1);
- emith_sbcf_r_r(tmp, tmp2);
- emith_tpush_carry(sr, 1);
- }
- goto end_op;
- case 0x0b: // SUBV Rm,Rn 0011nnnnmmmm1011
- case 0x0f: // ADDV Rm,Rn 0011nnnnmmmm1111
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_bic_r_imm(sr, T);
- if (op & 4) {
- emith_addf_r_r(tmp, tmp2);
- } else
- emith_subf_r_r(tmp, tmp2);
- EMITH_SJMP_START(DCOND_VC);
- emith_or_r_imm_c(DCOND_VS, sr, T);
- EMITH_SJMP_END(DCOND_VC);
- goto end_op;
- case 0x0d: // DMULS.L Rm,Rn 0011nnnnmmmm1101
- tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
- tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
- tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
- tmp4 = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
- emith_mul_s64(tmp3, tmp4, tmp, tmp2);
- goto end_op;
- }
- goto default_;
- /////////////////////////////////////////////
- case 0x04:
- switch (op & 0x0f)
- {
- case 0x00:
- switch (GET_Fx())
- {
- case 0: // SHLL Rn 0100nnnn00000000
- case 2: // SHAL Rn 0100nnnn00100000
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_tpop_carry(sr, 0); // dummy
- emith_lslf(tmp, tmp, 1);
- emith_tpush_carry(sr, 0);
- goto end_op;
- case 1: // DT Rn 0100nnnn00010000
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- if (FETCH_OP(pc) == 0x8bfd) { // BF #-2
- if (gconst_get(GET_Rn(), &tmp)) {
- // XXX: limit burned cycles
- emit_move_r_imm32(GET_Rn(), 0);
- emith_or_r_imm(sr, T);
- cycles += tmp * 4;
- skip_op = 1;
- }
- else
- emith_sh2_dtbf_loop();
- goto end_op;
- }
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- emith_bic_r_imm(sr, T);
- emith_subf_r_imm(tmp, 1);
- emit_or_t_if_eq(sr);
- goto end_op;
- }
- goto default_;
- case 0x01:
- switch (GET_Fx())
- {
- case 0: // SHLR Rn 0100nnnn00000001
- case 2: // SHAR Rn 0100nnnn00100001
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_tpop_carry(sr, 0); // dummy
- if (op & 0x20) {
- emith_asrf(tmp, tmp, 1);
- } else
- emith_lsrf(tmp, tmp, 1);
- emith_tpush_carry(sr, 0);
- goto end_op;
- case 1: // CMP/PZ Rn 0100nnnn00010001
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_bic_r_imm(sr, T);
- emith_cmp_r_imm(tmp, 0);
- EMITH_SJMP_START(DCOND_LT);
- emith_or_r_imm_c(DCOND_GE, sr, T);
- EMITH_SJMP_END(DCOND_LT);
- goto end_op;
- }
- goto default_;
- case 0x02:
- case 0x03:
- switch (op & 0x3f)
- {
- case 0x02: // STS.L MACH,@–Rn 0100nnnn00000010
- tmp = SHR_MACH;
- break;
- case 0x12: // STS.L MACL,@–Rn 0100nnnn00010010
- tmp = SHR_MACL;
- break;
- case 0x22: // STS.L PR,@–Rn 0100nnnn00100010
- tmp = SHR_PR;
- break;
- case 0x03: // STC.L SR,@–Rn 0100nnnn00000011
- tmp = SHR_SR;
- break;
- case 0x13: // STC.L GBR,@–Rn 0100nnnn00010011
- tmp = SHR_GBR;
- break;
- case 0x23: // STC.L VBR,@–Rn 0100nnnn00100011
- tmp = SHR_VBR;
- break;
- default:
- goto default_;
- }
- tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- emith_sub_r_imm(tmp2, 4);
- rcache_clean();
- rcache_get_reg_arg(0, GET_Rn());
- tmp3 = rcache_get_reg_arg(1, tmp);
- if (tmp == SHR_SR)
- emith_clear_msb(tmp3, tmp3, 22); // reserved bits defined by ISA as 0
- emit_memhandler_write(2, pc, drcf.delayed_op);
- goto end_op;
- case 0x04:
- case 0x05:
- switch (op & 0x3f)
- {
- case 0x04: // ROTL Rn 0100nnnn00000100
- case 0x05: // ROTR Rn 0100nnnn00000101
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_tpop_carry(sr, 0); // dummy
- if (op & 1) {
- emith_rorf(tmp, tmp, 1);
- } else
- emith_rolf(tmp, tmp, 1);
- emith_tpush_carry(sr, 0);
- goto end_op;
- case 0x24: // ROTCL Rn 0100nnnn00100100
- case 0x25: // ROTCR Rn 0100nnnn00100101
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_tpop_carry(sr, 0);
- if (op & 1) {
- emith_rorcf(tmp);
- } else
- emith_rolcf(tmp);
- emith_tpush_carry(sr, 0);
- goto end_op;
- case 0x15: // CMP/PL Rn 0100nnnn00010101
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_bic_r_imm(sr, T);
- emith_cmp_r_imm(tmp, 0);
- EMITH_SJMP_START(DCOND_LE);
- emith_or_r_imm_c(DCOND_GT, sr, T);
- EMITH_SJMP_END(DCOND_LE);
- goto end_op;
- }
- goto default_;
- case 0x06:
- case 0x07:
- switch (op & 0x3f)
- {
- case 0x06: // LDS.L @Rm+,MACH 0100mmmm00000110
- tmp = SHR_MACH;
- break;
- case 0x16: // LDS.L @Rm+,MACL 0100mmmm00010110
- tmp = SHR_MACL;
- break;
- case 0x26: // LDS.L @Rm+,PR 0100mmmm00100110
- tmp = SHR_PR;
- break;
- case 0x07: // LDC.L @Rm+,SR 0100mmmm00000111
- tmp = SHR_SR;
- break;
- case 0x17: // LDC.L @Rm+,GBR 0100mmmm00010111
- tmp = SHR_GBR;
- break;
- case 0x27: // LDC.L @Rm+,VBR 0100mmmm00100111
- tmp = SHR_VBR;
- break;
- default:
- goto default_;
- }
- rcache_get_reg_arg(0, GET_Rn());
- tmp2 = emit_memhandler_read(2);
- if (tmp == SHR_SR) {
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_write_sr(sr, tmp2);
- drcf.test_irq = 1;
- } else {
- tmp = rcache_get_reg(tmp, RC_GR_WRITE);
- emith_move_r_r(tmp, tmp2);
- }
- rcache_free_tmp(tmp2);
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- emith_add_r_imm(tmp, 4);
- goto end_op;
- case 0x08:
- case 0x09:
- switch (GET_Fx())
- {
- case 0:
- // SHLL2 Rn 0100nnnn00001000
- // SHLR2 Rn 0100nnnn00001001
- tmp = 2;
- break;
- case 1:
- // SHLL8 Rn 0100nnnn00011000
- // SHLR8 Rn 0100nnnn00011001
- tmp = 8;
- break;
- case 2:
- // SHLL16 Rn 0100nnnn00101000
- // SHLR16 Rn 0100nnnn00101001
- tmp = 16;
- break;
- default:
- goto default_;
- }
- tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- if (op & 1) {
- emith_lsr(tmp2, tmp2, tmp);
- } else
- emith_lsl(tmp2, tmp2, tmp);
- goto end_op;
- case 0x0a:
- switch (GET_Fx())
- {
- case 0: // LDS Rm,MACH 0100mmmm00001010
- tmp2 = SHR_MACH;
- break;
- case 1: // LDS Rm,MACL 0100mmmm00011010
- tmp2 = SHR_MACL;
- break;
- case 2: // LDS Rm,PR 0100mmmm00101010
- tmp2 = SHR_PR;
- break;
- default:
- goto default_;
- }
- emit_move_r_r(tmp2, GET_Rn());
- goto end_op;
- case 0x0b:
- switch (GET_Fx())
- {
- case 0: // JSR @Rm 0100mmmm00001011
- case 2: // JMP @Rm 0100mmmm00101011
- DELAYED_OP;
- if (!(op & 0x20))
- emit_move_r_imm32(SHR_PR, pc + 2);
- emit_move_r_r(SHR_PC, (op >> 8) & 0x0f);
- out_pc = (u32)-1;
- cycles++;
- break;
- case 1: // TAS.B @Rn 0100nnnn00011011
- // XXX: is TAS working on 32X?
- rcache_get_reg_arg(0, GET_Rn());
- tmp = emit_memhandler_read(0);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_bic_r_imm(sr, T);
- emith_cmp_r_imm(tmp, 0);
- emit_or_t_if_eq(sr);
- rcache_clean();
- emith_or_r_imm(tmp, 0x80);
- tmp2 = rcache_get_tmp_arg(1); // assuming it differs to tmp
- emith_move_r_r(tmp2, tmp);
- rcache_free_tmp(tmp);
- rcache_get_reg_arg(0, GET_Rn());
- emit_memhandler_write(0, pc, drcf.delayed_op);
- cycles += 3;
- break;
- default:
- goto default_;
- }
- goto end_op;
- case 0x0e:
- tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
- switch (GET_Fx())
- {
- case 0: // LDC Rm,SR 0100mmmm00001110
- tmp2 = SHR_SR;
- break;
- case 1: // LDC Rm,GBR 0100mmmm00011110
- tmp2 = SHR_GBR;
- break;
- case 2: // LDC Rm,VBR 0100mmmm00101110
- tmp2 = SHR_VBR;
- break;
- default:
- goto default_;
- }
- if (tmp2 == SHR_SR) {
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_write_sr(sr, tmp);
- drcf.test_irq = 1;
- } else {
- tmp2 = rcache_get_reg(tmp2, RC_GR_WRITE);
- emith_move_r_r(tmp2, tmp);
- }
- goto end_op;
- case 0x0f:
- // MAC.W @Rm+,@Rn+ 0100nnnnmmmm1111
- emit_indirect_read_double(&tmp, &tmp2, GET_Rn(), GET_Rm(), 1);
- emith_sext(tmp, tmp, 16);
- emith_sext(tmp2, tmp2, 16);
- tmp3 = rcache_get_reg(SHR_MACL, RC_GR_RMW);
- tmp4 = rcache_get_reg(SHR_MACH, RC_GR_RMW);
- emith_mula_s64(tmp3, tmp4, tmp, tmp2);
- rcache_free_tmp(tmp2);
- // XXX: MACH should be untouched when S is set?
- sr = rcache_get_reg(SHR_SR, RC_GR_READ);
- emith_tst_r_imm(sr, S);
- EMITH_JMP_START(DCOND_EQ);
- emith_asr(tmp, tmp3, 31);
- emith_eorf_r_r(tmp, tmp4); // tmp = ((signed)macl >> 31) ^ mach
- EMITH_JMP_START(DCOND_EQ);
- emith_move_r_imm(tmp3, 0x80000000);
- emith_tst_r_r(tmp4, tmp4);
- EMITH_SJMP_START(DCOND_MI);
- emith_sub_r_imm_c(DCOND_PL, tmp3, 1); // positive
- EMITH_SJMP_END(DCOND_MI);
- EMITH_JMP_END(DCOND_EQ);
- EMITH_JMP_END(DCOND_EQ);
- rcache_free_tmp(tmp);
- cycles += 2;
- goto end_op;
- }
- goto default_;
- /////////////////////////////////////////////
- case 0x05:
- // MOV.L @(disp,Rm),Rn 0101nnnnmmmmdddd
- emit_memhandler_read_rr(GET_Rn(), GET_Rm(), (op & 0x0f) * 4, 2);
- goto end_op;
- /////////////////////////////////////////////
- case 0x06:
- switch (op & 0x0f)
- {
- case 0x00: // MOV.B @Rm,Rn 0110nnnnmmmm0000
- case 0x01: // MOV.W @Rm,Rn 0110nnnnmmmm0001
- case 0x02: // MOV.L @Rm,Rn 0110nnnnmmmm0010
- case 0x04: // MOV.B @Rm+,Rn 0110nnnnmmmm0100
- case 0x05: // MOV.W @Rm+,Rn 0110nnnnmmmm0101
- case 0x06: // MOV.L @Rm+,Rn 0110nnnnmmmm0110
- emit_memhandler_read_rr(GET_Rn(), GET_Rm(), 0, op & 3);
- if ((op & 7) >= 4 && GET_Rn() != GET_Rm()) {
- tmp = rcache_get_reg(GET_Rm(), RC_GR_RMW);
- emith_add_r_imm(tmp, (1 << (op & 3)));
- }
- goto end_op;
- case 0x03:
- case 0x07 ... 0x0f:
- tmp = rcache_get_reg(GET_Rm(), RC_GR_READ);
- tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
- switch (op & 0x0f)
- {
- case 0x03: // MOV Rm,Rn 0110nnnnmmmm0011
- emith_move_r_r(tmp2, tmp);
- break;
- case 0x07: // NOT Rm,Rn 0110nnnnmmmm0111
- emith_mvn_r_r(tmp2, tmp);
- break;
- case 0x08: // SWAP.B Rm,Rn 0110nnnnmmmm1000
- tmp3 = tmp2;
- if (tmp == tmp2)
- tmp3 = rcache_get_tmp();
- tmp4 = rcache_get_tmp();
- emith_lsr(tmp3, tmp, 16);
- emith_or_r_r_lsl(tmp3, tmp, 24);
- emith_and_r_r_imm(tmp4, tmp, 0xff00);
- emith_or_r_r_lsl(tmp3, tmp4, 8);
- emith_rol(tmp2, tmp3, 16);
- rcache_free_tmp(tmp4);
- if (tmp == tmp2)
- rcache_free_tmp(tmp3);
- break;
- case 0x09: // SWAP.W Rm,Rn 0110nnnnmmmm1001
- emith_rol(tmp2, tmp, 16);
- break;
- case 0x0a: // NEGC Rm,Rn 0110nnnnmmmm1010
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_tpop_carry(sr, 1);
- emith_negcf_r_r(tmp2, tmp);
- emith_tpush_carry(sr, 1);
- break;
- case 0x0b: // NEG Rm,Rn 0110nnnnmmmm1011
- emith_neg_r_r(tmp2, tmp);
- break;
- case 0x0c: // EXTU.B Rm,Rn 0110nnnnmmmm1100
- emith_clear_msb(tmp2, tmp, 24);
- break;
- case 0x0d: // EXTU.W Rm,Rn 0110nnnnmmmm1101
- emith_clear_msb(tmp2, tmp, 16);
- break;
- case 0x0e: // EXTS.B Rm,Rn 0110nnnnmmmm1110
- emith_sext(tmp2, tmp, 8);
- break;
- case 0x0f: // EXTS.W Rm,Rn 0110nnnnmmmm1111
- emith_sext(tmp2, tmp, 16);
- break;
- }
- goto end_op;
- }
- goto default_;
- /////////////////////////////////////////////
- case 0x07:
- // ADD #imm,Rn 0111nnnniiiiiiii
- tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
- if (op & 0x80) { // adding negative
- emith_sub_r_imm(tmp, -op & 0xff);
- } else
- emith_add_r_imm(tmp, op & 0xff);
- goto end_op;
- /////////////////////////////////////////////
- case 0x08:
- switch (op & 0x0f00)
- {
- case 0x0000: // MOV.B R0,@(disp,Rn) 10000000nnnndddd
- case 0x0100: // MOV.W R0,@(disp,Rn) 10000001nnnndddd
- rcache_clean();
- tmp = rcache_get_reg_arg(0, GET_Rm());
- tmp2 = rcache_get_reg_arg(1, SHR_R0);
- tmp3 = (op & 0x100) >> 8;
- if (op & 0x0f)
- emith_add_r_imm(tmp, (op & 0x0f) << tmp3);
- emit_memhandler_write(tmp3, pc, drcf.delayed_op);
- goto end_op;
- case 0x0400: // MOV.B @(disp,Rm),R0 10000100mmmmdddd
- case 0x0500: // MOV.W @(disp,Rm),R0 10000101mmmmdddd
- tmp = (op & 0x100) >> 8;
- emit_memhandler_read_rr(SHR_R0, GET_Rm(), (op & 0x0f) << tmp, tmp);
- goto end_op;
- case 0x0800: // CMP/EQ #imm,R0 10001000iiiiiiii
- // XXX: could use cmn
- tmp = rcache_get_tmp();
- tmp2 = rcache_get_reg(0, RC_GR_READ);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_move_r_imm_s8(tmp, op & 0xff);
- emith_bic_r_imm(sr, T);
- emith_cmp_r_r(tmp2, tmp);
- emit_or_t_if_eq(sr);
- rcache_free_tmp(tmp);
- goto end_op;
- case 0x0d00: // BT/S label 10001101dddddddd
- case 0x0f00: // BF/S label 10001111dddddddd
- DELAYED_OP;
- cycles--;
- // fallthrough
- case 0x0900: // BT label 10001001dddddddd
- case 0x0b00: // BF label 10001011dddddddd
- // will handle conditional branches later
- pending_branch_cond = (op & 0x0200) ? DCOND_EQ : DCOND_NE;
- i = ((signed int)(op << 24) >> 23);
- pending_branch_pc = pc + i + 2;
- cycles += 2;
- goto end_op;
- }
- goto default_;
- /////////////////////////////////////////////
- case 0x09:
- // MOV.W @(disp,PC),Rn 1001nnnndddddddd
- tmp = pc + (op & 0xff) * 2 + 2;
- #if PROPAGATE_CONSTANTS
- if (tmp < end_pc + MAX_LITERAL_OFFSET) {
- gconst_new(GET_Rn(), (u32)(int)(signed short)FETCH_OP(tmp));
- if (last_inlined_literal < tmp)
- last_inlined_literal = tmp;
- }
- else
- #endif
- {
- tmp2 = rcache_get_tmp_arg(0);
- emith_move_r_imm(tmp2, tmp);
- tmp2 = emit_memhandler_read(1);
- tmp3 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
- emith_sext(tmp3, tmp2, 16);
- rcache_free_tmp(tmp2);
- }
- goto end_op;
- /////////////////////////////////////////////
- case 0x0a:
- // BRA label 1010dddddddddddd
- DELAYED_OP;
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- tmp = ((signed int)(op << 20) >> 19);
- out_pc = pc + tmp + 2;
- if (tmp == (u32)-4)
- emith_clear_msb(sr, sr, 20); // burn cycles
- cycles++;
- break;
- /////////////////////////////////////////////
- case 0x0b:
- // BSR label 1011dddddddddddd
- DELAYED_OP;
- emit_move_r_imm32(SHR_PR, pc + 2);
- tmp = ((signed int)(op << 20) >> 19);
- out_pc = pc + tmp + 2;
- cycles++;
- break;
- /////////////////////////////////////////////
- case 0x0c:
- switch (op & 0x0f00)
- {
- case 0x0000: // MOV.B R0,@(disp,GBR) 11000000dddddddd
- case 0x0100: // MOV.W R0,@(disp,GBR) 11000001dddddddd
- case 0x0200: // MOV.L R0,@(disp,GBR) 11000010dddddddd
- rcache_clean();
- tmp = rcache_get_reg_arg(0, SHR_GBR);
- tmp2 = rcache_get_reg_arg(1, SHR_R0);
- tmp3 = (op & 0x300) >> 8;
- emith_add_r_imm(tmp, (op & 0xff) << tmp3);
- emit_memhandler_write(tmp3, pc, drcf.delayed_op);
- goto end_op;
- case 0x0400: // MOV.B @(disp,GBR),R0 11000100dddddddd
- case 0x0500: // MOV.W @(disp,GBR),R0 11000101dddddddd
- case 0x0600: // MOV.L @(disp,GBR),R0 11000110dddddddd
- tmp = (op & 0x300) >> 8;
- emit_memhandler_read_rr(SHR_R0, SHR_GBR, (op & 0xff) << tmp, tmp);
- goto end_op;
- case 0x0300: // TRAPA #imm 11000011iiiiiiii
- tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
- emith_sub_r_imm(tmp, 4*2);
- // push SR
- tmp = rcache_get_reg_arg(0, SHR_SP);
- emith_add_r_imm(tmp, 4);
- tmp = rcache_get_reg_arg(1, SHR_SR);
- emith_clear_msb(tmp, tmp, 22);
- emit_memhandler_write(2, pc, drcf.delayed_op);
- // push PC
- rcache_get_reg_arg(0, SHR_SP);
- tmp = rcache_get_tmp_arg(1);
- emith_move_r_imm(tmp, pc);
- emit_memhandler_write(2, pc, drcf.delayed_op);
- // obtain new PC
- emit_memhandler_read_rr(SHR_PC, SHR_VBR, (op & 0xff) * 4, 2);
- out_pc = (u32)-1;
- cycles += 7;
- goto end_op;
- case 0x0700: // MOVA @(disp,PC),R0 11000111dddddddd
- emit_move_r_imm32(SHR_R0, (pc + (op & 0xff) * 4 + 2) & ~3);
- goto end_op;
- case 0x0800: // TST #imm,R0 11001000iiiiiiii
- tmp = rcache_get_reg(SHR_R0, RC_GR_READ);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_bic_r_imm(sr, T);
- emith_tst_r_imm(tmp, op & 0xff);
- emit_or_t_if_eq(sr);
- goto end_op;
- case 0x0900: // AND #imm,R0 11001001iiiiiiii
- tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
- emith_and_r_imm(tmp, op & 0xff);
- goto end_op;
- case 0x0a00: // XOR #imm,R0 11001010iiiiiiii
- tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
- emith_eor_r_imm(tmp, op & 0xff);
- goto end_op;
- case 0x0b00: // OR #imm,R0 11001011iiiiiiii
- tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
- emith_or_r_imm(tmp, op & 0xff);
- goto end_op;
- case 0x0c00: // TST.B #imm,@(R0,GBR) 11001100iiiiiiii
- tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- if (drcf.delayed_op)
- DELAY_SAVE_T(sr);
- emith_bic_r_imm(sr, T);
- emith_tst_r_imm(tmp, op & 0xff);
- emit_or_t_if_eq(sr);
- rcache_free_tmp(tmp);
- cycles += 2;
- goto end_op;
- case 0x0d00: // AND.B #imm,@(R0,GBR) 11001101iiiiiiii
- tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
- emith_and_r_imm(tmp, op & 0xff);
- goto end_rmw_op;
- case 0x0e00: // XOR.B #imm,@(R0,GBR) 11001110iiiiiiii
- tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
- emith_eor_r_imm(tmp, op & 0xff);
- goto end_rmw_op;
- case 0x0f00: // OR.B #imm,@(R0,GBR) 11001111iiiiiiii
- tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
- emith_or_r_imm(tmp, op & 0xff);
- end_rmw_op:
- tmp2 = rcache_get_tmp_arg(1);
- emith_move_r_r(tmp2, tmp);
- rcache_free_tmp(tmp);
- tmp3 = rcache_get_reg_arg(0, SHR_GBR);
- tmp4 = rcache_get_reg(SHR_R0, RC_GR_READ);
- emith_add_r_r(tmp3, tmp4);
- emit_memhandler_write(0, pc, drcf.delayed_op);
- cycles += 2;
- goto end_op;
- }
- goto default_;
- /////////////////////////////////////////////
- case 0x0d:
- // MOV.L @(disp,PC),Rn 1101nnnndddddddd
- tmp = (pc + (op & 0xff) * 4 + 2) & ~3;
- #if PROPAGATE_CONSTANTS
- if (tmp < end_pc + MAX_LITERAL_OFFSET) {
- gconst_new(GET_Rn(), FETCH32(tmp));
- if (last_inlined_literal < tmp)
- last_inlined_literal = tmp;
- }
- else
- #endif
- {
- tmp2 = rcache_get_tmp_arg(0);
- emith_move_r_imm(tmp2, tmp);
- tmp2 = emit_memhandler_read(2);
- tmp3 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
- emith_move_r_r(tmp3, tmp2);
- rcache_free_tmp(tmp2);
- }
- goto end_op;
- /////////////////////////////////////////////
- case 0x0e:
- // MOV #imm,Rn 1110nnnniiiiiiii
- emit_move_r_imm32(GET_Rn(), (u32)(signed int)(signed char)op);
- goto end_op;
- default:
- default_:
- elprintf(EL_ANOMALY, "%csh2 drc: unhandled op %04x @ %08x",
- sh2->is_slave ? 's' : 'm', op, pc - 2);
- #ifdef DRC_DEBUG_INTERP
- emit_move_r_imm32(SHR_PC, pc - 2);
- rcache_flush();
- emith_pass_arg_r(0, CONTEXT_REG);
- emith_pass_arg_imm(1, op);
- emith_call(sh2_do_op);
- #endif
- break;
- }
- end_op:
- rcache_unlock_all();
- // conditional branch handling (with/without delay)
- if (pending_branch_cond != -1 && drcf.delayed_op != 2)
- {
- u32 target_pc = pending_branch_pc;
- void *target;
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- // handle cycles
- FLUSH_CYCLES(sr);
- rcache_clean();
- if (drcf.use_saved_t)
- emith_tst_r_imm(sr, T_save);
- else
- emith_tst_r_imm(sr, T);
- #if LINK_BRANCHES
- if (find_in_array(branch_target_pc, branch_target_count, target_pc) >= 0) {
- // local branch
- // XXX: jumps back can be linked already
- branch_patch_pc[branch_patch_count] = target_pc;
- branch_patch_ptr[branch_patch_count] = tcache_ptr;
- emith_jump_cond_patchable(pending_branch_cond, tcache_ptr);
- branch_patch_count++;
- if (branch_patch_count == MAX_LOCAL_BRANCHES) {
- printf("warning: too many local branches\n");
- break;
- }
- }
- else
- #endif
- {
- // can't resolve branch locally, make a block exit
- emit_move_r_imm32(SHR_PC, target_pc);
- rcache_clean();
- target = dr_prepare_ext_branch(target_pc, sh2, tcache_id);
- if (target == NULL)
- return NULL;
- emith_jump_cond_patchable(pending_branch_cond, target);
- }
- drcf.use_saved_t = 0;
- pending_branch_cond = -1;
- }
- // test irq?
- // XXX: delay slots..
- if (drcf.test_irq && drcf.delayed_op != 2) {
- if (!drcf.delayed_op)
- emit_move_r_imm32(SHR_PC, pc);
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- FLUSH_CYCLES(sr);
- rcache_flush();
- emith_call(sh2_drc_test_irq);
- drcf.test_irq = 0;
- }
- do_host_disasm(tcache_id);
- if (out_pc != 0 && drcf.delayed_op != 2)
- break;
- }
- tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
- FLUSH_CYCLES(tmp);
- rcache_flush();
- if (out_pc == (u32)-1) {
- // indirect jump -> back to dispatcher
- emith_jump(sh2_drc_dispatcher);
- } else {
- void *target;
- if (out_pc == 0)
- out_pc = pc;
- emit_move_r_imm32(SHR_PC, out_pc);
- rcache_flush();
- target = dr_prepare_ext_branch(out_pc, sh2, tcache_id);
- if (target == NULL)
- return NULL;
- emith_jump_patchable(target);
- }
- // link local branches
- for (i = 0; i < branch_patch_count; i++) {
- void *target;
- int t;
- t = find_in_array(branch_target_pc, branch_target_count, branch_patch_pc[i]);
- target = branch_target_ptr[t];
- if (target == NULL) {
- // flush pc and go back to dispatcher (should no longer happen)
- printf("stray branch to %08x %p\n", branch_patch_pc[i], tcache_ptr);
- target = tcache_ptr;
- emit_move_r_imm32(SHR_PC, branch_patch_pc[i]);
- rcache_flush();
- emith_jump(sh2_drc_dispatcher);
- }
- emith_jump_patch(branch_patch_ptr[i], target);
- }
- this_block->end_addr = pc;
- if (last_inlined_literal > pc)
- this_block->end_addr = last_inlined_literal + 4;
- // mark memory blocks as containing compiled code
- if (tcache_id != 0) {
- // data array, BIOS
- u16 *drcblk = Pico32xMem->drcblk_da[sh2->is_slave];
- tmp = (this_block->addr & 0xfff) >> SH2_DRCBLK_DA_SHIFT;
- tmp2 = (this_block->end_addr & 0xfff) >> SH2_DRCBLK_DA_SHIFT;
- drcblk[tmp] = (blkid_main << 1) | 1;
- for (++tmp; tmp < tmp2; tmp++) {
- if (drcblk[tmp])
- continue; // dont overwrite overlay block(s)
- drcblk[tmp] = blkid_main << 1;
- }
- }
- else if ((this_block->addr & 0xc7fc0000) == 0x06000000) { // DRAM
- tmp = (this_block->addr & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
- tmp2 = (this_block->end_addr & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
- Pico32xMem->drcblk_ram[tmp] = (blkid_main << 1) | 1;
- for (++tmp; tmp < tmp2; tmp++) {
- if (Pico32xMem->drcblk_ram[tmp])
- continue;
- Pico32xMem->drcblk_ram[tmp] = blkid_main << 1;
- }
- }
- tcache_ptrs[tcache_id] = tcache_ptr;
- #ifdef ARM
- cache_flush_d_inval_i(block_entry, tcache_ptr);
- #endif
- do_host_disasm(tcache_id);
- dbg(1, " block #%d,%d tcache %d/%d, insns %d -> %d %.3f",
- tcache_id, block_counts[tcache_id],
- tcache_ptr - tcache_bases[tcache_id], tcache_sizes[tcache_id],
- insns_compiled, host_insn_count, (double)host_insn_count / insns_compiled);
- if ((sh2->pc & 0xc6000000) == 0x02000000) // ROM
- dbg(1, " hash collisions %d/%d", hash_collisions, block_counts[tcache_id]);
- /*
- printf("~~~\n");
- tcache_dsm_ptrs[tcache_id] = block_entry;
- do_host_disasm(tcache_id);
- printf("~~~\n");
- */
- #if (DRC_DEBUG & 2)
- fflush(stdout);
- #endif
- return block_entry;
- }
- static void sh2_generate_utils(void)
- {
- int arg0, arg1, arg2, sr, tmp;
- void *sh2_drc_write_end, *sh2_drc_write_slot_end;
- sh2_drc_write32 = p32x_sh2_write32;
- sh2_drc_read8 = p32x_sh2_read8;
- sh2_drc_read16 = p32x_sh2_read16;
- sh2_drc_read32 = p32x_sh2_read32;
- host_arg2reg(arg0, 0);
- host_arg2reg(arg1, 1);
- host_arg2reg(arg2, 2);
- emith_move_r_r(arg0, arg0); // nop
- // sh2_drc_exit(void)
- sh2_drc_exit = (void *)tcache_ptr;
- emit_do_static_regs(1, arg2);
- emith_sh2_drc_exit();
- // sh2_drc_dispatcher(void)
- sh2_drc_dispatcher = (void *)tcache_ptr;
- sr = rcache_get_reg(SHR_SR, RC_GR_READ);
- emith_cmp_r_imm(sr, 0);
- emith_jump_cond(DCOND_LT, sh2_drc_exit);
- rcache_invalidate();
- emith_ctx_read(arg0, SHR_PC * 4);
- emith_ctx_read(arg1, offsetof(SH2, is_slave));
- emith_add_r_r_imm(arg2, CONTEXT_REG, offsetof(SH2, drc_tmp));
- emith_call(lookup_block);
- emit_block_entry();
- // lookup failed, call sh2_translate()
- emith_move_r_r(arg0, CONTEXT_REG);
- emith_ctx_read(arg1, offsetof(SH2, drc_tmp)); // tcache_id
- emith_call(sh2_translate);
- emit_block_entry();
- // sh2_translate() failed, flush cache and retry
- emith_ctx_read(arg0, offsetof(SH2, drc_tmp));
- emith_call(flush_tcache);
- emith_move_r_r(arg0, CONTEXT_REG);
- emith_ctx_read(arg1, offsetof(SH2, drc_tmp));
- emith_call(sh2_translate);
- emit_block_entry();
- // XXX: can't translate, fail
- emith_call(exit);
- // sh2_drc_test_irq(void)
- // assumes it's called from main function (may jump to dispatcher)
- sh2_drc_test_irq = (void *)tcache_ptr;
- emith_ctx_read(arg1, offsetof(SH2, pending_level));
- sr = rcache_get_reg(SHR_SR, RC_GR_READ);
- emith_lsr(arg0, sr, I_SHIFT);
- emith_and_r_imm(arg0, 0x0f);
- emith_cmp_r_r(arg1, arg0); // pending_level > ((sr >> 4) & 0x0f)?
- EMITH_SJMP_START(DCOND_GT);
- emith_ret_c(DCOND_LE); // nope, return
- EMITH_SJMP_END(DCOND_GT);
- // adjust SP
- tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
- emith_sub_r_imm(tmp, 4*2);
- rcache_clean();
- // push SR
- tmp = rcache_get_reg_arg(0, SHR_SP);
- emith_add_r_imm(tmp, 4);
- tmp = rcache_get_reg_arg(1, SHR_SR);
- emith_clear_msb(tmp, tmp, 22);
- emith_move_r_r(arg2, CONTEXT_REG);
- emith_call(p32x_sh2_write32); // XXX: use sh2_drc_write32?
- rcache_invalidate();
- // push PC
- rcache_get_reg_arg(0, SHR_SP);
- emith_ctx_read(arg1, SHR_PC * 4);
- emith_move_r_r(arg2, CONTEXT_REG);
- emith_call(p32x_sh2_write32);
- rcache_invalidate();
- // update I, cycles, do callback
- emith_ctx_read(arg1, offsetof(SH2, pending_level));
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- emith_bic_r_imm(sr, I);
- emith_or_r_r_lsl(sr, arg1, I_SHIFT);
- emith_sub_r_imm(sr, 13 << 12); // at least 13 cycles
- rcache_flush();
- emith_move_r_r(arg0, CONTEXT_REG);
- emith_call_ctx(offsetof(SH2, irq_callback)); // vector = sh2->irq_callback(sh2, level);
- // obtain new PC
- emith_lsl(arg0, arg0, 2);
- emith_ctx_read(arg1, SHR_VBR * 4);
- emith_add_r_r(arg0, arg1);
- emit_memhandler_read(2);
- emith_ctx_write(arg0, SHR_PC * 4);
- #ifdef __i386__
- emith_add_r_imm(xSP, 4); // fix stack
- #endif
- emith_jump(sh2_drc_dispatcher);
- rcache_invalidate();
- // sh2_drc_entry(SH2 *sh2)
- sh2_drc_entry = (void *)tcache_ptr;
- emith_sh2_drc_entry();
- emith_move_r_r(CONTEXT_REG, arg0); // move ctx, arg0
- emit_do_static_regs(0, arg2);
- emith_call(sh2_drc_test_irq);
- emith_jump(sh2_drc_dispatcher);
- // write-caused irq detection
- sh2_drc_write_end = tcache_ptr;
- emith_tst_r_r(arg0, arg0);
- EMITH_SJMP_START(DCOND_NE);
- emith_jump_ctx_c(DCOND_EQ, offsetof(SH2, drc_tmp)); // return
- EMITH_SJMP_END(DCOND_NE);
- emith_call(sh2_drc_test_irq);
- emith_jump_ctx(offsetof(SH2, drc_tmp));
- // write-caused irq detection for writes in delay slot
- sh2_drc_write_slot_end = tcache_ptr;
- emith_tst_r_r(arg0, arg0);
- EMITH_SJMP_START(DCOND_NE);
- emith_jump_ctx_c(DCOND_EQ, offsetof(SH2, drc_tmp));
- EMITH_SJMP_END(DCOND_NE);
- // just burn cycles to get back to dispatcher after branch is handled
- sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
- emith_ctx_write(sr, offsetof(SH2, irq_cycles));
- emith_clear_msb(sr, sr, 20); // clear cycles
- rcache_flush();
- emith_jump_ctx(offsetof(SH2, drc_tmp));
- // sh2_drc_write8(u32 a, u32 d)
- sh2_drc_write8 = (void *)tcache_ptr;
- emith_ret_to_ctx(offsetof(SH2, drc_tmp));
- emith_ctx_read(arg2, offsetof(SH2, write8_tab));
- emith_sh2_wcall(arg0, arg2, sh2_drc_write_end);
- // sh2_drc_write16(u32 a, u32 d)
- sh2_drc_write16 = (void *)tcache_ptr;
- emith_ret_to_ctx(offsetof(SH2, drc_tmp));
- emith_ctx_read(arg2, offsetof(SH2, write16_tab));
- emith_sh2_wcall(arg0, arg2, sh2_drc_write_end);
- // sh2_drc_write8_slot(u32 a, u32 d)
- sh2_drc_write8_slot = (void *)tcache_ptr;
- emith_ret_to_ctx(offsetof(SH2, drc_tmp));
- emith_ctx_read(arg2, offsetof(SH2, write8_tab));
- emith_sh2_wcall(arg0, arg2, sh2_drc_write_slot_end);
- // sh2_drc_write16_slot(u32 a, u32 d)
- sh2_drc_write16_slot = (void *)tcache_ptr;
- emith_ret_to_ctx(offsetof(SH2, drc_tmp));
- emith_ctx_read(arg2, offsetof(SH2, write16_tab));
- emith_sh2_wcall(arg0, arg2, sh2_drc_write_slot_end);
- #ifdef PDB_NET
- // debug
- #define MAKE_READ_WRAPPER(func) { \
- void *tmp = (void *)tcache_ptr; \
- emith_ret_to_ctx(offsetof(SH2, drc_tmp)); \
- emith_call(func); \
- emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[0])); \
- emith_addf_r_r(arg2, arg0); \
- emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[0])); \
- emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[1])); \
- emith_adc_r_imm(arg2, 0x01000000); \
- emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[1])); \
- emith_jump_ctx(offsetof(SH2, drc_tmp)); \
- func = tmp; \
- }
- #define MAKE_WRITE_WRAPPER(func) { \
- void *tmp = (void *)tcache_ptr; \
- emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[0])); \
- emith_addf_r_r(arg2, arg1); \
- emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[0])); \
- emith_ctx_read(arg2, offsetof(SH2, pdb_io_csum[1])); \
- emith_adc_r_imm(arg2, 0x01000000); \
- emith_ctx_write(arg2, offsetof(SH2, pdb_io_csum[1])); \
- emith_move_r_r(arg2, CONTEXT_REG); \
- emith_jump(func); \
- func = tmp; \
- }
- MAKE_READ_WRAPPER(sh2_drc_read8);
- MAKE_READ_WRAPPER(sh2_drc_read16);
- MAKE_READ_WRAPPER(sh2_drc_read32);
- MAKE_WRITE_WRAPPER(sh2_drc_write8);
- MAKE_WRITE_WRAPPER(sh2_drc_write8_slot);
- MAKE_WRITE_WRAPPER(sh2_drc_write16);
- MAKE_WRITE_WRAPPER(sh2_drc_write16_slot);
- MAKE_WRITE_WRAPPER(sh2_drc_write32);
- #if (DRC_DEBUG & 2)
- host_dasm_new_symbol(sh2_drc_read8);
- host_dasm_new_symbol(sh2_drc_read16);
- host_dasm_new_symbol(sh2_drc_read32);
- host_dasm_new_symbol(sh2_drc_write32);
- #endif
- #endif
- rcache_invalidate();
- #if (DRC_DEBUG & 2)
- host_dasm_new_symbol(sh2_drc_entry);
- host_dasm_new_symbol(sh2_drc_dispatcher);
- host_dasm_new_symbol(sh2_drc_exit);
- host_dasm_new_symbol(sh2_drc_test_irq);
- host_dasm_new_symbol(sh2_drc_write_end);
- host_dasm_new_symbol(sh2_drc_write_slot_end);
- host_dasm_new_symbol(sh2_drc_write8);
- host_dasm_new_symbol(sh2_drc_write8_slot);
- host_dasm_new_symbol(sh2_drc_write16);
- host_dasm_new_symbol(sh2_drc_write16_slot);
- #endif
- }
- static void sh2_smc_rm_block(u16 *drcblk, u16 *p, block_desc *btab, u32 a)
- {
- u16 id = *p >> 1;
- block_desc *bd = btab + id;
- // FIXME: skip subblocks; do both directions
- // FIXME: collect all branches
- dbg(1, " killing block %08x", bd->addr);
- bd->addr = bd->end_addr = 0;
- while (p > drcblk && (p[-1] >> 1) == id)
- p--;
- // check for possible overlay block
- if (p > 0 && p[-1] != 0) {
- bd = btab + (p[-1] >> 1);
- if (bd->addr <= a && a < bd->end_addr)
- sh2_smc_rm_block(drcblk, p - 1, btab, a);
- }
- do {
- *p++ = 0;
- }
- while ((*p >> 1) == id);
- }
- void sh2_drc_wcheck_ram(unsigned int a, int val, int cpuid)
- {
- u16 *drcblk = Pico32xMem->drcblk_ram;
- u16 *p = drcblk + ((a & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT);
- dbg(1, "%csh2 smc check @%08x", cpuid ? 's' : 'm', a);
- sh2_smc_rm_block(drcblk, p, block_tables[0], a);
- }
- void sh2_drc_wcheck_da(unsigned int a, int val, int cpuid)
- {
- u16 *drcblk = Pico32xMem->drcblk_da[cpuid];
- u16 *p = drcblk + ((a & 0xfff) >> SH2_DRCBLK_DA_SHIFT);
- dbg(1, "%csh2 smc check @%08x", cpuid ? 's' : 'm', a);
- sh2_smc_rm_block(drcblk, p, block_tables[1 + cpuid], a);
- }
- void sh2_execute(SH2 *sh2c, int cycles)
- {
- int ret_cycles;
- sh2 = sh2c; // XXX
- sh2c->cycles_aim += cycles;
- cycles = sh2c->cycles_aim - sh2c->cycles_done;
- // cycles are kept in SHR_SR unused bits (upper 20)
- // bit19 contains T saved for delay slot
- // others are usual SH2 flags
- sh2c->sr &= 0x3f3;
- sh2c->sr |= cycles << 12;
- sh2_drc_entry(sh2c);
- // TODO: irq cycles
- ret_cycles = (signed int)sh2c->sr >> 12;
- if (ret_cycles > 0)
- printf("warning: drc returned with cycles: %d\n", ret_cycles);
- sh2c->cycles_done += cycles - ret_cycles;
- }
- #if (DRC_DEBUG & 1)
- void block_stats(void)
- {
- int c, b, i, total = 0;
- printf("block stats:\n");
- for (b = 0; b < ARRAY_SIZE(block_tables); b++)
- for (i = 0; i < block_counts[b]; i++)
- if (block_tables[b][i].addr != 0)
- total += block_tables[b][i].refcount;
- for (c = 0; c < 10; c++) {
- block_desc *blk, *maxb = NULL;
- int max = 0;
- for (b = 0; b < ARRAY_SIZE(block_tables); b++) {
- for (i = 0; i < block_counts[b]; i++) {
- blk = &block_tables[b][i];
- if (blk->addr != 0 && blk->refcount > max) {
- max = blk->refcount;
- maxb = blk;
- }
- }
- }
- if (maxb == NULL)
- break;
- printf("%08x %9d %2.3f%%\n", maxb->addr, maxb->refcount,
- (double)maxb->refcount / total * 100.0);
- maxb->refcount = 0;
- }
- for (b = 0; b < ARRAY_SIZE(block_tables); b++)
- for (i = 0; i < block_counts[b]; i++)
- block_tables[b][i].refcount = 0;
- }
- #else
- #define block_stats()
- #endif
- void sh2_drc_flush_all(void)
- {
- block_stats();
- flush_tcache(0);
- flush_tcache(1);
- flush_tcache(2);
- }
- void sh2_drc_mem_setup(SH2 *sh2)
- {
- // fill the convenience pointers
- sh2->p_bios = sh2->is_slave ? Pico32xMem->sh2_rom_s : Pico32xMem->sh2_rom_m;
- sh2->p_da = Pico32xMem->data_array[sh2->is_slave];
- sh2->p_sdram = Pico32xMem->sdram;
- sh2->p_rom = Pico.rom;
- }
- int sh2_drc_init(SH2 *sh2)
- {
- int i;
- if (block_tables[0] == NULL)
- {
- for (i = 0; i < TCACHE_BUFFERS; i++) {
- block_tables[i] = calloc(block_max_counts[i], sizeof(*block_tables[0]));
- if (block_tables[i] == NULL)
- goto fail;
- // max 2 block links (exits) per block
- block_links[i] = calloc(block_max_counts[i] * 2, sizeof(*block_links[0]));
- if (block_links[i] == NULL)
- goto fail;
- }
- memset(block_counts, 0, sizeof(block_counts));
- memset(block_link_counts, 0, sizeof(block_link_counts));
- drc_cmn_init();
- tcache_ptr = tcache;
- sh2_generate_utils();
- #ifdef ARM
- cache_flush_d_inval_i(tcache, tcache_ptr);
- #endif
- tcache_bases[0] = tcache_ptrs[0] = tcache_ptr;
- for (i = 1; i < ARRAY_SIZE(tcache_bases); i++)
- tcache_bases[i] = tcache_ptrs[i] = tcache_bases[i - 1] + tcache_sizes[i - 1];
- // tmp
- PicoOpt |= POPT_DIS_VDP_FIFO;
- #if (DRC_DEBUG & 2)
- for (i = 0; i < ARRAY_SIZE(block_tables); i++)
- tcache_dsm_ptrs[i] = tcache_bases[i];
- // disasm the utils
- tcache_dsm_ptrs[0] = tcache;
- do_host_disasm(0);
- #endif
- #if (DRC_DEBUG & 1)
- hash_collisions = 0;
- #endif
- }
- if (hash_table == NULL) {
- hash_table = calloc(sizeof(hash_table[0]), MAX_HASH_ENTRIES);
- if (hash_table == NULL)
- goto fail;
- }
- return 0;
- fail:
- sh2_drc_finish(sh2);
- return -1;
- }
- void sh2_drc_finish(SH2 *sh2)
- {
- int i;
- if (block_tables[0] != NULL) {
- block_stats();
- for (i = 0; i < TCACHE_BUFFERS; i++) {
- #if (DRC_DEBUG & 2)
- printf("~~~ tcache %d\n", i);
- tcache_dsm_ptrs[i] = tcache_bases[i];
- tcache_ptr = tcache_ptrs[i];
- do_host_disasm(i);
- #endif
- if (block_tables[i] != NULL)
- free(block_tables[i]);
- block_tables[i] = NULL;
- if (block_links[i] == NULL)
- free(block_links[i]);
- block_links[i] = NULL;
- }
- drc_cmn_cleanup();
- }
- if (hash_table != NULL) {
- free(hash_table);
- hash_table = NULL;
- }
- }
|