12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282 |
- /* rx.c --- opcode semantics for stand-alone RX simulator.
- Copyright (C) 2008-2022 Free Software Foundation, Inc.
- Contributed by Red Hat, Inc.
- This file is part of the GNU simulators.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- /* This must come before any other includes. */
- #include "defs.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <signal.h>
- #include "libiberty.h"
- #include "opcode/rx.h"
- #include "cpu.h"
- #include "mem.h"
- #include "syscalls.h"
- #include "fpu.h"
- #include "err.h"
- #include "misc.h"
- #ifdef WITH_PROFILE
- static const char * id_names[] = {
- "RXO_unknown",
- "RXO_mov", /* d = s (signed) */
- "RXO_movbi", /* d = [s,s2] (signed) */
- "RXO_movbir", /* [s,s2] = d (signed) */
- "RXO_pushm", /* s..s2 */
- "RXO_popm", /* s..s2 */
- "RXO_xchg", /* s <-> d */
- "RXO_stcc", /* d = s if cond(s2) */
- "RXO_rtsd", /* rtsd, 1=imm, 2-0 = reg if reg type */
- /* These are all either d OP= s or, if s2 is set, d = s OP s2. Note
- that d may be "None". */
- "RXO_and",
- "RXO_or",
- "RXO_xor",
- "RXO_add",
- "RXO_sub",
- "RXO_mul",
- "RXO_div",
- "RXO_divu",
- "RXO_shll",
- "RXO_shar",
- "RXO_shlr",
- "RXO_adc", /* d = d + s + carry */
- "RXO_sbb", /* d = d - s - ~carry */
- "RXO_abs", /* d = |s| */
- "RXO_max", /* d = max(d,s) */
- "RXO_min", /* d = min(d,s) */
- "RXO_emul", /* d:64 = d:32 * s */
- "RXO_emulu", /* d:64 = d:32 * s (unsigned) */
- "RXO_rolc", /* d <<= 1 through carry */
- "RXO_rorc", /* d >>= 1 through carry*/
- "RXO_rotl", /* d <<= #s without carry */
- "RXO_rotr", /* d >>= #s without carry*/
- "RXO_revw", /* d = revw(s) */
- "RXO_revl", /* d = revl(s) */
- "RXO_branch", /* pc = d if cond(s) */
- "RXO_branchrel",/* pc += d if cond(s) */
- "RXO_jsr", /* pc = d */
- "RXO_jsrrel", /* pc += d */
- "RXO_rts",
- "RXO_nop",
- "RXO_nop2",
- "RXO_nop3",
- "RXO_nop4",
- "RXO_nop5",
- "RXO_nop6",
- "RXO_nop7",
- "RXO_scmpu",
- "RXO_smovu",
- "RXO_smovb",
- "RXO_suntil",
- "RXO_swhile",
- "RXO_smovf",
- "RXO_sstr",
- "RXO_rmpa",
- "RXO_mulhi",
- "RXO_mullo",
- "RXO_machi",
- "RXO_maclo",
- "RXO_mvtachi",
- "RXO_mvtaclo",
- "RXO_mvfachi",
- "RXO_mvfacmi",
- "RXO_mvfaclo",
- "RXO_racw",
- "RXO_sat", /* sat(d) */
- "RXO_satr",
- "RXO_fadd", /* d op= s */
- "RXO_fcmp",
- "RXO_fsub",
- "RXO_ftoi",
- "RXO_fmul",
- "RXO_fdiv",
- "RXO_round",
- "RXO_itof",
- "RXO_bset", /* d |= (1<<s) */
- "RXO_bclr", /* d &= ~(1<<s) */
- "RXO_btst", /* s & (1<<s2) */
- "RXO_bnot", /* d ^= (1<<s) */
- "RXO_bmcc", /* d<s> = cond(s2) */
- "RXO_clrpsw", /* flag index in d */
- "RXO_setpsw", /* flag index in d */
- "RXO_mvtipl", /* new IPL in s */
- "RXO_rtfi",
- "RXO_rte",
- "RXO_rtd", /* undocumented */
- "RXO_brk",
- "RXO_dbt", /* undocumented */
- "RXO_int", /* vector id in s */
- "RXO_stop",
- "RXO_wait",
- "RXO_sccnd", /* d = cond(s) ? 1 : 0 */
- };
- static const char * optype_names[] = {
- " - ",
- "#Imm", /* #addend */
- " Rn ", /* Rn */
- "[Rn]", /* [Rn + addend] */
- "Ps++", /* [Rn+] */
- "--Pr", /* [-Rn] */
- " cc ", /* eq, gtu, etc */
- "Flag", /* [UIOSZC] */
- "RbRi" /* [Rb + scale * Ri] */
- };
- #define N_RXO ARRAY_SIZE (id_names)
- #define N_RXT ARRAY_SIZE (optype_names)
- #define N_MAP 90
- static unsigned long long benchmark_start_cycle;
- static unsigned long long benchmark_end_cycle;
- static int op_cache[N_RXT][N_RXT][N_RXT];
- static int op_cache_rev[N_MAP];
- static int op_cache_idx = 0;
- static int
- op_lookup (int a, int b, int c)
- {
- if (op_cache[a][b][c])
- return op_cache[a][b][c];
- op_cache_idx ++;
- if (op_cache_idx >= N_MAP)
- {
- printf("op_cache_idx exceeds %d\n", N_MAP);
- exit(1);
- }
- op_cache[a][b][c] = op_cache_idx;
- op_cache_rev[op_cache_idx] = (a<<8) | (b<<4) | c;
- return op_cache_idx;
- }
- static char *
- op_cache_string (int map)
- {
- static int ci;
- static char cb[5][20];
- int a, b, c;
- map = op_cache_rev[map];
- a = (map >> 8) & 15;
- b = (map >> 4) & 15;
- c = (map >> 0) & 15;
- ci = (ci + 1) % 5;
- sprintf(cb[ci], "%s %s %s", optype_names[a], optype_names[b], optype_names[c]);
- return cb[ci];
- }
- static unsigned long long cycles_per_id[N_RXO][N_MAP];
- static unsigned long long times_per_id[N_RXO][N_MAP];
- static unsigned long long memory_stalls;
- static unsigned long long register_stalls;
- static unsigned long long branch_stalls;
- static unsigned long long branch_alignment_stalls;
- static unsigned long long fast_returns;
- static unsigned long times_per_pair[N_RXO][N_MAP][N_RXO][N_MAP];
- static int prev_opcode_id = RXO_unknown;
- static int po0;
- #define STATS(x) x
- #else
- #define STATS(x)
- #endif /* WITH_PROFILE */
- #ifdef CYCLE_ACCURATE
- static int new_rt = -1;
- /* Number of cycles to add if an insn spans an 8-byte boundary. */
- static int branch_alignment_penalty = 0;
- #endif
- static int running_benchmark = 1;
- #define tprintf if (trace && running_benchmark) printf
- jmp_buf decode_jmp_buf;
- unsigned int rx_cycles = 0;
- #ifdef CYCLE_ACCURATE
- /* If nonzero, memory was read at some point and cycle latency might
- take effect. */
- static int memory_source = 0;
- /* If nonzero, memory was written and extra cycles might be
- needed. */
- static int memory_dest = 0;
- static void
- cycles (int throughput)
- {
- tprintf("%d cycles\n", throughput);
- regs.cycle_count += throughput;
- }
- /* Number of execution (E) cycles the op uses. For memory sources, we
- include the load micro-op stall as two extra E cycles. */
- #define E(c) cycles (memory_source ? c + 2 : c)
- #define E1 cycles (1)
- #define E2 cycles (2)
- #define EBIT cycles (memory_source ? 2 : 1)
- /* Check to see if a read latency must be applied for a given register. */
- #define RL(r) \
- if (regs.rt == r ) \
- { \
- tprintf("register %d load stall\n", r); \
- regs.cycle_count ++; \
- STATS(register_stalls ++); \
- regs.rt = -1; \
- }
- #define RLD(r) \
- if (memory_source) \
- { \
- tprintf ("Rt now %d\n", r); \
- new_rt = r; \
- }
- static int
- lsb_count (unsigned long v, int is_signed)
- {
- int i, lsb;
- if (is_signed && (v & 0x80000000U))
- v = (unsigned long)(long)(-v);
- for (i=31; i>=0; i--)
- if (v & (1 << i))
- {
- /* v is 0..31, we want 1=1-2, 2=3-4, 3=5-6, etc. */
- lsb = (i + 2) / 2;
- return lsb;
- }
- return 0;
- }
- static int
- divu_cycles(unsigned long num, unsigned long den)
- {
- int nb = lsb_count (num, 0);
- int db = lsb_count (den, 0);
- int rv;
- if (nb < db)
- rv = 2;
- else
- rv = 3 + nb - db;
- E (rv);
- return rv;
- }
- static int
- div_cycles(long num, long den)
- {
- int nb = lsb_count ((unsigned long)num, 1);
- int db = lsb_count ((unsigned long)den, 1);
- int rv;
- if (nb < db)
- rv = 3;
- else
- rv = 5 + nb - db;
- E (rv);
- return rv;
- }
- #else /* !CYCLE_ACCURATE */
- #define cycles(t)
- #define E(c)
- #define E1
- #define E2
- #define EBIT
- #define RL(r)
- #define RLD(r)
- #define divu_cycles(n,d)
- #define div_cycles(n,d)
- #endif /* else CYCLE_ACCURATE */
- static int size2bytes[] = {
- 4, 1, 1, 1, 2, 2, 2, 3, 4
- };
- typedef struct {
- unsigned long dpc;
- } RX_Data;
- #define rx_abort() _rx_abort(__FILE__, __LINE__)
- static void
- _rx_abort (const char *file, int line)
- {
- if (strrchr (file, '/'))
- file = strrchr (file, '/') + 1;
- fprintf(stderr, "abort at %s:%d\n", file, line);
- abort();
- }
- static unsigned char *get_byte_base;
- static RX_Opcode_Decoded **decode_cache_base;
- static SI get_byte_page;
- void
- reset_decoder (void)
- {
- get_byte_base = 0;
- decode_cache_base = 0;
- get_byte_page = 0;
- }
- static inline void
- maybe_get_mem_page (SI tpc)
- {
- if (((tpc ^ get_byte_page) & NONPAGE_MASK) || enable_counting)
- {
- get_byte_page = tpc & NONPAGE_MASK;
- get_byte_base = rx_mem_ptr (get_byte_page, MPA_READING) - get_byte_page;
- decode_cache_base = rx_mem_decode_cache (get_byte_page) - get_byte_page;
- }
- }
- /* This gets called a *lot* so optimize it. */
- static int
- rx_get_byte (void *vdata)
- {
- RX_Data *rx_data = (RX_Data *)vdata;
- SI tpc = rx_data->dpc;
- /* See load.c for an explanation of this. */
- if (rx_big_endian)
- tpc ^= 3;
- maybe_get_mem_page (tpc);
- rx_data->dpc ++;
- return get_byte_base [tpc];
- }
- static int
- get_op (const RX_Opcode_Decoded *rd, int i)
- {
- const RX_Opcode_Operand *o = rd->op + i;
- int addr, rv = 0;
- switch (o->type)
- {
- case RX_Operand_None:
- rx_abort ();
- case RX_Operand_Immediate: /* #addend */
- return o->addend;
- case RX_Operand_Register: /* Rn */
- RL (o->reg);
- rv = get_reg (o->reg);
- break;
- case RX_Operand_Predec: /* [-Rn] */
- put_reg (o->reg, get_reg (o->reg) - size2bytes[o->size]);
- /* fall through */
- case RX_Operand_Postinc: /* [Rn+] */
- case RX_Operand_Zero_Indirect: /* [Rn + 0] */
- case RX_Operand_Indirect: /* [Rn + addend] */
- case RX_Operand_TwoReg: /* [Rn + scale * R2] */
- #ifdef CYCLE_ACCURATE
- RL (o->reg);
- if (o->type == RX_Operand_TwoReg)
- RL (rd->op[2].reg);
- regs.rt = -1;
- if (regs.m2m == M2M_BOTH)
- {
- tprintf("src memory stall\n");
- #ifdef WITH_PROFILE
- memory_stalls ++;
- #endif
- regs.cycle_count ++;
- regs.m2m = 0;
- }
- memory_source = 1;
- #endif
- if (o->type == RX_Operand_TwoReg)
- addr = get_reg (o->reg) * size2bytes[rd->size] + get_reg (rd->op[2].reg);
- else
- addr = get_reg (o->reg) + o->addend;
- switch (o->size)
- {
- default:
- case RX_AnySize:
- rx_abort ();
- case RX_Byte: /* undefined extension */
- case RX_UByte:
- case RX_SByte:
- rv = mem_get_qi (addr);
- break;
- case RX_Word: /* undefined extension */
- case RX_UWord:
- case RX_SWord:
- rv = mem_get_hi (addr);
- break;
- case RX_3Byte:
- rv = mem_get_psi (addr);
- break;
- case RX_Long:
- rv = mem_get_si (addr);
- break;
- }
- if (o->type == RX_Operand_Postinc)
- put_reg (o->reg, get_reg (o->reg) + size2bytes[o->size]);
- break;
- case RX_Operand_Condition: /* eq, gtu, etc */
- return condition_true (o->reg);
- case RX_Operand_Flag: /* [UIOSZC] */
- return (regs.r_psw & (1 << o->reg)) ? 1 : 0;
- }
- /* if we've gotten here, we need to clip/extend the value according
- to the size. */
- switch (o->size)
- {
- default:
- case RX_AnySize:
- rx_abort ();
- case RX_Byte: /* undefined extension */
- rv |= 0xdeadbe00; /* keep them honest */
- break;
- case RX_UByte:
- rv &= 0xff;
- break;
- case RX_SByte:
- rv = sign_ext (rv, 8);
- break;
- case RX_Word: /* undefined extension */
- rv |= 0xdead0000; /* keep them honest */
- break;
- case RX_UWord:
- rv &= 0xffff;
- break;
- case RX_SWord:
- rv = sign_ext (rv, 16);
- break;
- case RX_3Byte:
- rv &= 0xffffff;
- break;
- case RX_Long:
- break;
- }
- return rv;
- }
- static void
- put_op (const RX_Opcode_Decoded *rd, int i, int v)
- {
- const RX_Opcode_Operand *o = rd->op + i;
- int addr;
- switch (o->size)
- {
- default:
- case RX_AnySize:
- if (o->type != RX_Operand_Register)
- rx_abort ();
- break;
- case RX_Byte: /* undefined extension */
- v |= 0xdeadbe00; /* keep them honest */
- break;
- case RX_UByte:
- v &= 0xff;
- break;
- case RX_SByte:
- v = sign_ext (v, 8);
- break;
- case RX_Word: /* undefined extension */
- v |= 0xdead0000; /* keep them honest */
- break;
- case RX_UWord:
- v &= 0xffff;
- break;
- case RX_SWord:
- v = sign_ext (v, 16);
- break;
- case RX_3Byte:
- v &= 0xffffff;
- break;
- case RX_Long:
- break;
- }
- switch (o->type)
- {
- case RX_Operand_None:
- /* Opcodes like TST and CMP use this. */
- break;
- case RX_Operand_Immediate: /* #addend */
- case RX_Operand_Condition: /* eq, gtu, etc */
- rx_abort ();
- case RX_Operand_Register: /* Rn */
- put_reg (o->reg, v);
- RLD (o->reg);
- break;
- case RX_Operand_Predec: /* [-Rn] */
- put_reg (o->reg, get_reg (o->reg) - size2bytes[o->size]);
- /* fall through */
- case RX_Operand_Postinc: /* [Rn+] */
- case RX_Operand_Zero_Indirect: /* [Rn + 0] */
- case RX_Operand_Indirect: /* [Rn + addend] */
- case RX_Operand_TwoReg: /* [Rn + scale * R2] */
- #ifdef CYCLE_ACCURATE
- if (regs.m2m == M2M_BOTH)
- {
- tprintf("dst memory stall\n");
- regs.cycle_count ++;
- #ifdef WITH_PROFILE
- memory_stalls ++;
- #endif
- regs.m2m = 0;
- }
- memory_dest = 1;
- #endif
- if (o->type == RX_Operand_TwoReg)
- addr = get_reg (o->reg) * size2bytes[rd->size] + get_reg (rd->op[2].reg);
- else
- addr = get_reg (o->reg) + o->addend;
- switch (o->size)
- {
- default:
- case RX_AnySize:
- rx_abort ();
- case RX_Byte: /* undefined extension */
- case RX_UByte:
- case RX_SByte:
- mem_put_qi (addr, v);
- break;
- case RX_Word: /* undefined extension */
- case RX_UWord:
- case RX_SWord:
- mem_put_hi (addr, v);
- break;
- case RX_3Byte:
- mem_put_psi (addr, v);
- break;
- case RX_Long:
- mem_put_si (addr, v);
- break;
- }
- if (o->type == RX_Operand_Postinc)
- put_reg (o->reg, get_reg (o->reg) + size2bytes[o->size]);
- break;
- case RX_Operand_Flag: /* [UIOSZC] */
- if (v)
- regs.r_psw |= (1 << o->reg);
- else
- regs.r_psw &= ~(1 << o->reg);
- break;
- }
- }
- #define PD(x) put_op (opcode, 0, x)
- #define PS(x) put_op (opcode, 1, x)
- #define PS2(x) put_op (opcode, 2, x)
- #define GD() get_op (opcode, 0)
- #define GS() get_op (opcode, 1)
- #define GS2() get_op (opcode, 2)
- #define DSZ() size2bytes[opcode->op[0].size]
- #define SSZ() size2bytes[opcode->op[0].size]
- #define S2SZ() size2bytes[opcode->op[0].size]
- /* "Universal" sources. */
- #define US1() ((opcode->op[2].type == RX_Operand_None) ? GD() : GS())
- #define US2() ((opcode->op[2].type == RX_Operand_None) ? GS() : GS2())
- static void
- push(int val)
- {
- int rsp = get_reg (sp);
- rsp -= 4;
- put_reg (sp, rsp);
- mem_put_si (rsp, val);
- }
- /* Just like the above, but tag the memory as "pushed pc" so if anyone
- tries to write to it, it will cause an error. */
- static void
- pushpc(int val)
- {
- int rsp = get_reg (sp);
- rsp -= 4;
- put_reg (sp, rsp);
- mem_put_si (rsp, val);
- mem_set_content_range (rsp, rsp+3, MC_PUSHED_PC);
- }
- static int
- pop (void)
- {
- int rv;
- int rsp = get_reg (sp);
- rv = mem_get_si (rsp);
- rsp += 4;
- put_reg (sp, rsp);
- return rv;
- }
- static int
- poppc (void)
- {
- int rv;
- int rsp = get_reg (sp);
- if (mem_get_content_type (rsp) != MC_PUSHED_PC)
- execution_error (SIM_ERR_CORRUPT_STACK, rsp);
- rv = mem_get_si (rsp);
- mem_set_content_range (rsp, rsp+3, MC_UNINIT);
- rsp += 4;
- put_reg (sp, rsp);
- return rv;
- }
- #define MATH_OP(vop,c) \
- { \
- umb = US2(); \
- uma = US1(); \
- ll = (unsigned long long) uma vop (unsigned long long) umb vop c; \
- tprintf ("0x%x " #vop " 0x%x " #vop " 0x%x = 0x%llx\n", uma, umb, c, ll); \
- ma = sign_ext (uma, DSZ() * 8); \
- mb = sign_ext (umb, DSZ() * 8); \
- sll = (long long) ma vop (long long) mb vop c; \
- tprintf ("%d " #vop " %d " #vop " %d = %lld\n", ma, mb, c, sll); \
- set_oszc (sll, DSZ(), (long long) ll > ((1 vop 1) ? (long long) b2mask[DSZ()] : (long long) -1)); \
- PD (sll); \
- E (1); \
- }
- #define LOGIC_OP(vop) \
- { \
- mb = US2(); \
- ma = US1(); \
- v = ma vop mb; \
- tprintf("0x%x " #vop " 0x%x = 0x%x\n", ma, mb, v); \
- set_sz (v, DSZ()); \
- PD(v); \
- E (1); \
- }
- #define SHIFT_OP(val, type, count, OP, carry_mask) \
- { \
- int i, c=0; \
- count = US2(); \
- val = (type)US1(); \
- tprintf("%lld " #OP " %d\n", val, count); \
- for (i = 0; i < count; i ++) \
- { \
- c = val & carry_mask; \
- val OP 1; \
- } \
- set_oszc (val, 4, c); \
- PD (val); \
- }
- typedef union {
- int i;
- float f;
- } FloatInt;
- static inline int
- float2int (float f)
- {
- FloatInt fi;
- fi.f = f;
- return fi.i;
- }
- static inline float
- int2float (int i)
- {
- FloatInt fi;
- fi.i = i;
- return fi.f;
- }
- static int
- fop_fadd (fp_t s1, fp_t s2, fp_t *d)
- {
- *d = rxfp_add (s1, s2);
- return 1;
- }
- static int
- fop_fmul (fp_t s1, fp_t s2, fp_t *d)
- {
- *d = rxfp_mul (s1, s2);
- return 1;
- }
- static int
- fop_fdiv (fp_t s1, fp_t s2, fp_t *d)
- {
- *d = rxfp_div (s1, s2);
- return 1;
- }
- static int
- fop_fsub (fp_t s1, fp_t s2, fp_t *d)
- {
- *d = rxfp_sub (s1, s2);
- return 1;
- }
- #define FPPENDING() (regs.r_fpsw & (FPSWBITS_CE | (FPSWBITS_FMASK & (regs.r_fpsw << FPSW_EFSH))))
- #define FPCLEAR() regs.r_fpsw &= FPSWBITS_CLEAR
- #define FPCHECK() \
- if (FPPENDING()) \
- return do_fp_exception (opcode_pc)
- #define FLOAT_OP(func) \
- { \
- int do_store; \
- fp_t fa, fb, fc; \
- FPCLEAR(); \
- fb = GS (); \
- fa = GD (); \
- do_store = fop_##func (fa, fb, &fc); \
- tprintf("%g " #func " %g = %g %08x\n", int2float(fa), int2float(fb), int2float(fc), fc); \
- FPCHECK(); \
- if (do_store) \
- PD (fc); \
- mb = 0; \
- if ((fc & 0x80000000UL) != 0) \
- mb |= FLAGBIT_S; \
- if ((fc & 0x7fffffffUL) == 0) \
- mb |= FLAGBIT_Z; \
- set_flags (FLAGBIT_S | FLAGBIT_Z, mb); \
- }
- #define carry (FLAG_C ? 1 : 0)
- static struct {
- unsigned long vaddr;
- const char *str;
- int signal;
- } exception_info[] = {
- { 0xFFFFFFD0UL, "priviledged opcode", SIGILL },
- { 0xFFFFFFD4UL, "access violation", SIGSEGV },
- { 0xFFFFFFDCUL, "undefined opcode", SIGILL },
- { 0xFFFFFFE4UL, "floating point", SIGFPE }
- };
- #define EX_PRIVILEDGED 0
- #define EX_ACCESS 1
- #define EX_UNDEFINED 2
- #define EX_FLOATING 3
- #define EXCEPTION(n) \
- return generate_exception (n, opcode_pc)
- #define PRIVILEDGED() \
- if (FLAG_PM) \
- EXCEPTION (EX_PRIVILEDGED)
- static int
- generate_exception (unsigned long type, SI opcode_pc)
- {
- SI old_psw, old_pc, new_pc;
- new_pc = mem_get_si (exception_info[type].vaddr);
- /* 0x00020000 is the value used to initialise the known
- exception vectors (see rx.ld), but it is a reserved
- area of memory so do not try to access it, and if the
- value has not been changed by the program then the
- vector has not been installed. */
- if (new_pc == 0 || new_pc == 0x00020000)
- {
- if (rx_in_gdb)
- return RX_MAKE_STOPPED (exception_info[type].signal);
- fprintf(stderr, "Unhandled %s exception at pc = %#lx\n",
- exception_info[type].str, (unsigned long) opcode_pc);
- if (type == EX_FLOATING)
- {
- int mask = FPPENDING ();
- fprintf (stderr, "Pending FP exceptions:");
- if (mask & FPSWBITS_FV)
- fprintf(stderr, " Invalid");
- if (mask & FPSWBITS_FO)
- fprintf(stderr, " Overflow");
- if (mask & FPSWBITS_FZ)
- fprintf(stderr, " Division-by-zero");
- if (mask & FPSWBITS_FU)
- fprintf(stderr, " Underflow");
- if (mask & FPSWBITS_FX)
- fprintf(stderr, " Inexact");
- if (mask & FPSWBITS_CE)
- fprintf(stderr, " Unimplemented");
- fprintf(stderr, "\n");
- }
- return RX_MAKE_EXITED (1);
- }
- tprintf ("Triggering %s exception\n", exception_info[type].str);
- old_psw = regs.r_psw;
- regs.r_psw &= ~ (FLAGBIT_I | FLAGBIT_U | FLAGBIT_PM);
- old_pc = opcode_pc;
- regs.r_pc = new_pc;
- pushpc (old_psw);
- pushpc (old_pc);
- return RX_MAKE_STEPPED ();
- }
- void
- generate_access_exception (void)
- {
- int rv;
- rv = generate_exception (EX_ACCESS, regs.r_pc);
- if (RX_EXITED (rv))
- longjmp (decode_jmp_buf, rv);
- }
- static int
- do_fp_exception (unsigned long opcode_pc)
- {
- while (FPPENDING())
- EXCEPTION (EX_FLOATING);
- return RX_MAKE_STEPPED ();
- }
- static int
- op_is_memory (const RX_Opcode_Decoded *rd, int i)
- {
- switch (rd->op[i].type)
- {
- case RX_Operand_Predec:
- case RX_Operand_Postinc:
- case RX_Operand_Indirect:
- return 1;
- default:
- return 0;
- }
- }
- #define OM(i) op_is_memory (opcode, i)
- #define DO_RETURN(x) { longjmp (decode_jmp_buf, x); }
- int
- decode_opcode (void)
- {
- unsigned int uma=0, umb=0;
- int ma=0, mb=0;
- int opcode_size, v;
- unsigned long long ll;
- long long sll;
- unsigned long opcode_pc;
- RX_Data rx_data;
- const RX_Opcode_Decoded *opcode;
- #ifdef WITH_PROFILE
- unsigned long long prev_cycle_count;
- #endif
- #ifdef CYCLE_ACCURATE
- unsigned int tx;
- #endif
- #ifdef WITH_PROFILE
- prev_cycle_count = regs.cycle_count;
- #endif
- #ifdef CYCLE_ACCURATE
- memory_source = 0;
- memory_dest = 0;
- #endif
- rx_cycles ++;
- maybe_get_mem_page (regs.r_pc);
- opcode_pc = regs.r_pc;
- /* Note that we don't word-swap this point, there's no point. */
- if (decode_cache_base[opcode_pc] == NULL)
- {
- RX_Opcode_Decoded *opcode_w;
- rx_data.dpc = opcode_pc;
- opcode_w = decode_cache_base[opcode_pc] = calloc (1, sizeof (RX_Opcode_Decoded));
- opcode_size = rx_decode_opcode (opcode_pc, opcode_w,
- rx_get_byte, &rx_data);
- opcode = opcode_w;
- }
- else
- {
- opcode = decode_cache_base[opcode_pc];
- opcode_size = opcode->n_bytes;
- }
- #ifdef CYCLE_ACCURATE
- if (branch_alignment_penalty)
- {
- if ((regs.r_pc ^ (regs.r_pc + opcode_size - 1)) & ~7)
- {
- tprintf("1 cycle branch alignment penalty\n");
- cycles (branch_alignment_penalty);
- #ifdef WITH_PROFILE
- branch_alignment_stalls ++;
- #endif
- }
- branch_alignment_penalty = 0;
- }
- #endif
- regs.r_pc += opcode_size;
- rx_flagmask = opcode->flags_s;
- rx_flagand = ~(int)opcode->flags_0;
- rx_flagor = opcode->flags_1;
- switch (opcode->id)
- {
- case RXO_abs:
- sll = GS ();
- tprintf("|%lld| = ", sll);
- if (sll < 0)
- sll = -sll;
- tprintf("%lld\n", sll);
- PD (sll);
- set_osz (sll, 4);
- E (1);
- break;
- case RXO_adc:
- MATH_OP (+,carry);
- break;
- case RXO_add:
- MATH_OP (+,0);
- break;
- case RXO_and:
- LOGIC_OP (&);
- break;
- case RXO_bclr:
- ma = GD ();
- mb = GS ();
- if (opcode->op[0].type == RX_Operand_Register)
- mb &= 0x1f;
- else
- mb &= 0x07;
- ma &= ~(1 << mb);
- PD (ma);
- EBIT;
- break;
- case RXO_bmcc:
- ma = GD ();
- mb = GS ();
- if (opcode->op[0].type == RX_Operand_Register)
- mb &= 0x1f;
- else
- mb &= 0x07;
- if (GS2 ())
- ma |= (1 << mb);
- else
- ma &= ~(1 << mb);
- PD (ma);
- EBIT;
- break;
- case RXO_bnot:
- ma = GD ();
- mb = GS ();
- if (opcode->op[0].type == RX_Operand_Register)
- mb &= 0x1f;
- else
- mb &= 0x07;
- ma ^= (1 << mb);
- PD (ma);
- EBIT;
- break;
- case RXO_branch:
- if (opcode->op[1].type == RX_Operand_None || GS())
- {
- #ifdef CYCLE_ACCURATE
- SI old_pc = regs.r_pc;
- int delta;
- #endif
- regs.r_pc = GD();
- #ifdef CYCLE_ACCURATE
- delta = regs.r_pc - old_pc;
- if (delta >= 0 && delta < 16
- && opcode_size > 1)
- {
- tprintf("near forward branch bonus\n");
- cycles (2);
- }
- else
- {
- cycles (3);
- branch_alignment_penalty = 1;
- }
- #ifdef WITH_PROFILE
- branch_stalls ++;
- #endif
- #endif
- }
- #ifdef CYCLE_ACCURATE
- else
- cycles (1);
- #endif
- break;
- case RXO_branchrel:
- if (opcode->op[1].type == RX_Operand_None || GS())
- {
- int delta = GD();
- regs.r_pc = opcode_pc + delta;
- #ifdef CYCLE_ACCURATE
- /* Note: specs say 3, chip says 2. */
- if (delta >= 0 && delta < 16
- && opcode_size > 1)
- {
- tprintf("near forward branch bonus\n");
- cycles (2);
- }
- else
- {
- cycles (3);
- branch_alignment_penalty = 1;
- }
- #ifdef WITH_PROFILE
- branch_stalls ++;
- #endif
- #endif
- }
- #ifdef CYCLE_ACCURATE
- else
- cycles (1);
- #endif
- break;
- case RXO_brk:
- {
- int old_psw = regs.r_psw;
- if (rx_in_gdb)
- DO_RETURN (RX_MAKE_HIT_BREAK ());
- if (regs.r_intb == 0)
- {
- tprintf("BREAK hit, no vector table.\n");
- DO_RETURN (RX_MAKE_EXITED(1));
- }
- regs.r_psw &= ~(FLAGBIT_I | FLAGBIT_U | FLAGBIT_PM);
- pushpc (old_psw);
- pushpc (regs.r_pc);
- regs.r_pc = mem_get_si (regs.r_intb);
- cycles(6);
- }
- break;
- case RXO_bset:
- ma = GD ();
- mb = GS ();
- if (opcode->op[0].type == RX_Operand_Register)
- mb &= 0x1f;
- else
- mb &= 0x07;
- ma |= (1 << mb);
- PD (ma);
- EBIT;
- break;
- case RXO_btst:
- ma = GS ();
- mb = GS2 ();
- if (opcode->op[1].type == RX_Operand_Register)
- mb &= 0x1f;
- else
- mb &= 0x07;
- umb = ma & (1 << mb);
- set_zc (! umb, umb);
- EBIT;
- break;
- case RXO_clrpsw:
- v = 1 << opcode->op[0].reg;
- if (FLAG_PM
- && (v == FLAGBIT_I
- || v == FLAGBIT_U))
- break;
- regs.r_psw &= ~v;
- cycles (1);
- break;
- case RXO_div: /* d = d / s */
- ma = GS();
- mb = GD();
- tprintf("%d / %d = ", mb, ma);
- if (ma == 0 || (ma == -1 && (unsigned int) mb == 0x80000000))
- {
- tprintf("#NAN\n");
- set_flags (FLAGBIT_O, FLAGBIT_O);
- cycles (3);
- }
- else
- {
- v = mb/ma;
- tprintf("%d\n", v);
- set_flags (FLAGBIT_O, 0);
- PD (v);
- div_cycles (mb, ma);
- }
- break;
- case RXO_divu: /* d = d / s */
- uma = GS();
- umb = GD();
- tprintf("%u / %u = ", umb, uma);
- if (uma == 0)
- {
- tprintf("#NAN\n");
- set_flags (FLAGBIT_O, FLAGBIT_O);
- cycles (2);
- }
- else
- {
- v = umb / uma;
- tprintf("%u\n", v);
- set_flags (FLAGBIT_O, 0);
- PD (v);
- divu_cycles (umb, uma);
- }
- break;
- case RXO_emul:
- ma = GD ();
- mb = GS ();
- sll = (long long)ma * (long long)mb;
- tprintf("%d * %d = %lld\n", ma, mb, sll);
- put_reg (opcode->op[0].reg, sll);
- put_reg (opcode->op[0].reg + 1, sll >> 32);
- E2;
- break;
- case RXO_emulu:
- uma = GD ();
- umb = GS ();
- ll = (long long)uma * (long long)umb;
- tprintf("%#x * %#x = %#llx\n", uma, umb, ll);
- put_reg (opcode->op[0].reg, ll);
- put_reg (opcode->op[0].reg + 1, ll >> 32);
- E2;
- break;
- case RXO_fadd:
- FLOAT_OP (fadd);
- E (4);
- break;
- case RXO_fcmp:
- ma = GD();
- mb = GS();
- FPCLEAR ();
- rxfp_cmp (ma, mb);
- FPCHECK ();
- E (1);
- break;
- case RXO_fdiv:
- FLOAT_OP (fdiv);
- E (16);
- break;
- case RXO_fmul:
- FLOAT_OP (fmul);
- E (3);
- break;
- case RXO_rtfi:
- PRIVILEDGED ();
- regs.r_psw = regs.r_bpsw;
- regs.r_pc = regs.r_bpc;
- #ifdef CYCLE_ACCURATE
- regs.fast_return = 0;
- cycles(3);
- #endif
- break;
- case RXO_fsub:
- FLOAT_OP (fsub);
- E (4);
- break;
- case RXO_ftoi:
- ma = GS ();
- FPCLEAR ();
- mb = rxfp_ftoi (ma, FPRM_ZERO);
- FPCHECK ();
- PD (mb);
- tprintf("(int) %g = %d\n", int2float(ma), mb);
- set_sz (mb, 4);
- E (2);
- break;
- case RXO_int:
- v = GS ();
- if (v == 255)
- {
- int rc = rx_syscall (regs.r[5]);
- if (! RX_STEPPED (rc))
- DO_RETURN (rc);
- }
- else
- {
- int old_psw = regs.r_psw;
- regs.r_psw &= ~(FLAGBIT_I | FLAGBIT_U | FLAGBIT_PM);
- pushpc (old_psw);
- pushpc (regs.r_pc);
- regs.r_pc = mem_get_si (regs.r_intb + 4 * v);
- }
- cycles (6);
- break;
- case RXO_itof:
- ma = GS ();
- FPCLEAR ();
- mb = rxfp_itof (ma, regs.r_fpsw);
- FPCHECK ();
- tprintf("(float) %d = %x\n", ma, mb);
- PD (mb);
- set_sz (ma, 4);
- E (2);
- break;
- case RXO_jsr:
- case RXO_jsrrel:
- {
- #ifdef CYCLE_ACCURATE
- int delta;
- regs.m2m = 0;
- #endif
- v = GD ();
- #ifdef CYCLE_ACCURATE
- regs.link_register = regs.r_pc;
- #endif
- pushpc (get_reg (pc));
- if (opcode->id == RXO_jsrrel)
- v += regs.r_pc;
- #ifdef CYCLE_ACCURATE
- delta = v - regs.r_pc;
- #endif
- put_reg (pc, v);
- #ifdef CYCLE_ACCURATE
- /* Note: docs say 3, chip says 2 */
- if (delta >= 0 && delta < 16)
- {
- tprintf ("near forward jsr bonus\n");
- cycles (2);
- }
- else
- {
- branch_alignment_penalty = 1;
- cycles (3);
- }
- regs.fast_return = 1;
- #endif
- }
- break;
- case RXO_machi:
- ll = (long long)(signed short)(GS() >> 16) * (long long)(signed short)(GS2 () >> 16);
- ll <<= 16;
- put_reg64 (acc64, ll + regs.r_acc);
- E1;
- break;
- case RXO_maclo:
- ll = (long long)(signed short)(GS()) * (long long)(signed short)(GS2 ());
- ll <<= 16;
- put_reg64 (acc64, ll + regs.r_acc);
- E1;
- break;
- case RXO_max:
- mb = GS();
- ma = GD();
- if (ma > mb)
- PD (ma);
- else
- PD (mb);
- E (1);
- break;
- case RXO_min:
- mb = GS();
- ma = GD();
- if (ma < mb)
- PD (ma);
- else
- PD (mb);
- E (1);
- break;
- case RXO_mov:
- v = GS ();
- if (opcode->op[1].type == RX_Operand_Register
- && opcode->op[1].reg == 17 /* PC */)
- {
- /* Special case. We want the address of the insn, not the
- address of the next insn. */
- v = opcode_pc;
- }
- if (opcode->op[0].type == RX_Operand_Register
- && opcode->op[0].reg == 16 /* PSW */)
- {
- /* Special case, LDC and POPC can't ever modify PM. */
- int pm = regs.r_psw & FLAGBIT_PM;
- v &= ~ FLAGBIT_PM;
- v |= pm;
- if (pm)
- {
- v &= ~ (FLAGBIT_I | FLAGBIT_U | FLAGBITS_IPL);
- v |= pm;
- }
- }
- if (FLAG_PM)
- {
- /* various things can't be changed in user mode. */
- if (opcode->op[0].type == RX_Operand_Register)
- if (opcode->op[0].reg == 32)
- {
- v &= ~ (FLAGBIT_I | FLAGBIT_U | FLAGBITS_IPL);
- v |= regs.r_psw & (FLAGBIT_I | FLAGBIT_U | FLAGBITS_IPL);
- }
- if (opcode->op[0].reg == 34 /* ISP */
- || opcode->op[0].reg == 37 /* BPSW */
- || opcode->op[0].reg == 39 /* INTB */
- || opcode->op[0].reg == 38 /* VCT */)
- /* These are ignored. */
- break;
- }
- if (OM(0) && OM(1))
- cycles (2);
- else
- cycles (1);
- PD (v);
- #ifdef CYCLE_ACCURATE
- if ((opcode->op[0].type == RX_Operand_Predec
- && opcode->op[1].type == RX_Operand_Register)
- || (opcode->op[0].type == RX_Operand_Postinc
- && opcode->op[1].type == RX_Operand_Register))
- {
- /* Special case: push reg doesn't cause a memory stall. */
- memory_dest = 0;
- tprintf("push special case\n");
- }
- #endif
- set_sz (v, DSZ());
- break;
- case RXO_movbi:
- PD (GS ());
- cycles (1);
- break;
- case RXO_movbir:
- PS (GD ());
- cycles (1);
- break;
- case RXO_mul:
- v = US2 ();
- ll = (unsigned long long) US1() * (unsigned long long) v;
- PD(ll);
- E (1);
- break;
- case RXO_mulhi:
- v = GS2 ();
- ll = (long long)(signed short)(GS() >> 16) * (long long)(signed short)(v >> 16);
- ll <<= 16;
- put_reg64 (acc64, ll);
- E1;
- break;
- case RXO_mullo:
- v = GS2 ();
- ll = (long long)(signed short)(GS()) * (long long)(signed short)(v);
- ll <<= 16;
- put_reg64 (acc64, ll);
- E1;
- break;
- case RXO_mvfachi:
- PD (get_reg (acchi));
- E1;
- break;
- case RXO_mvfaclo:
- PD (get_reg (acclo));
- E1;
- break;
- case RXO_mvfacmi:
- PD (get_reg (accmi));
- E1;
- break;
- case RXO_mvtachi:
- put_reg (acchi, GS ());
- E1;
- break;
- case RXO_mvtaclo:
- put_reg (acclo, GS ());
- E1;
- break;
- case RXO_mvtipl:
- regs.r_psw &= ~ FLAGBITS_IPL;
- regs.r_psw |= (GS () << FLAGSHIFT_IPL) & FLAGBITS_IPL;
- E1;
- break;
- case RXO_nop:
- case RXO_nop2:
- case RXO_nop3:
- case RXO_nop4:
- case RXO_nop5:
- case RXO_nop6:
- case RXO_nop7:
- E1;
- break;
- case RXO_or:
- LOGIC_OP (|);
- break;
- case RXO_popm:
- /* POPM cannot pop R0 (sp). */
- if (opcode->op[1].reg == 0 || opcode->op[2].reg == 0)
- EXCEPTION (EX_UNDEFINED);
- if (opcode->op[1].reg >= opcode->op[2].reg)
- {
- regs.r_pc = opcode_pc;
- DO_RETURN (RX_MAKE_STOPPED (SIGILL));
- }
- for (v = opcode->op[1].reg; v <= opcode->op[2].reg; v++)
- {
- cycles (1);
- RLD (v);
- put_reg (v, pop ());
- }
- break;
- case RXO_pushm:
- /* PUSHM cannot push R0 (sp). */
- if (opcode->op[1].reg == 0 || opcode->op[2].reg == 0)
- EXCEPTION (EX_UNDEFINED);
- if (opcode->op[1].reg >= opcode->op[2].reg)
- {
- regs.r_pc = opcode_pc;
- return RX_MAKE_STOPPED (SIGILL);
- }
- for (v = opcode->op[2].reg; v >= opcode->op[1].reg; v--)
- {
- RL (v);
- push (get_reg (v));
- }
- cycles (opcode->op[2].reg - opcode->op[1].reg + 1);
- break;
- case RXO_racw:
- ll = get_reg64 (acc64) << GS ();
- ll += 0x80000000ULL;
- if ((signed long long)ll > (signed long long)0x00007fff00000000ULL)
- ll = 0x00007fff00000000ULL;
- else if ((signed long long)ll < (signed long long)0xffff800000000000ULL)
- ll = 0xffff800000000000ULL;
- else
- ll &= 0xffffffff00000000ULL;
- put_reg64 (acc64, ll);
- E1;
- break;
- case RXO_rte:
- PRIVILEDGED ();
- regs.r_pc = poppc ();
- regs.r_psw = poppc ();
- if (FLAG_PM)
- regs.r_psw |= FLAGBIT_U;
- #ifdef CYCLE_ACCURATE
- regs.fast_return = 0;
- cycles (6);
- #endif
- break;
- case RXO_revl:
- uma = GS ();
- umb = (((uma >> 24) & 0xff)
- | ((uma >> 8) & 0xff00)
- | ((uma << 8) & 0xff0000)
- | ((uma << 24) & 0xff000000UL));
- PD (umb);
- E1;
- break;
- case RXO_revw:
- uma = GS ();
- umb = (((uma >> 8) & 0x00ff00ff)
- | ((uma << 8) & 0xff00ff00UL));
- PD (umb);
- E1;
- break;
- case RXO_rmpa:
- RL(4);
- RL(5);
- #ifdef CYCLE_ACCURATE
- tx = regs.r[3];
- #endif
- while (regs.r[3] != 0)
- {
- long long tmp;
- switch (opcode->size)
- {
- case RX_Long:
- ma = mem_get_si (regs.r[1]);
- mb = mem_get_si (regs.r[2]);
- regs.r[1] += 4;
- regs.r[2] += 4;
- break;
- case RX_Word:
- ma = sign_ext (mem_get_hi (regs.r[1]), 16);
- mb = sign_ext (mem_get_hi (regs.r[2]), 16);
- regs.r[1] += 2;
- regs.r[2] += 2;
- break;
- case RX_Byte:
- ma = sign_ext (mem_get_qi (regs.r[1]), 8);
- mb = sign_ext (mem_get_qi (regs.r[2]), 8);
- regs.r[1] += 1;
- regs.r[2] += 1;
- break;
- default:
- abort ();
- }
- /* We do the multiply as a signed value. */
- sll = (long long)ma * (long long)mb;
- tprintf(" %016llx = %d * %d\n", sll, ma, mb);
- /* but we do the sum as unsigned, while sign extending the operands. */
- tmp = regs.r[4] + (sll & 0xffffffffUL);
- regs.r[4] = tmp & 0xffffffffUL;
- tmp >>= 32;
- sll >>= 32;
- tmp += regs.r[5] + (sll & 0xffffffffUL);
- regs.r[5] = tmp & 0xffffffffUL;
- tmp >>= 32;
- sll >>= 32;
- tmp += regs.r[6] + (sll & 0xffffffffUL);
- regs.r[6] = tmp & 0xffffffffUL;
- tprintf("%08lx\033[36m%08lx\033[0m%08lx\n",
- (unsigned long) regs.r[6],
- (unsigned long) regs.r[5],
- (unsigned long) regs.r[4]);
- regs.r[3] --;
- }
- if (regs.r[6] & 0x00008000)
- regs.r[6] |= 0xffff0000UL;
- else
- regs.r[6] &= 0x0000ffff;
- ma = (regs.r[6] & 0x80000000UL) ? FLAGBIT_S : 0;
- if (regs.r[6] != 0 && regs.r[6] != 0xffffffffUL)
- set_flags (FLAGBIT_O|FLAGBIT_S, ma | FLAGBIT_O);
- else
- set_flags (FLAGBIT_O|FLAGBIT_S, ma);
- #ifdef CYCLE_ACCURATE
- switch (opcode->size)
- {
- case RX_Long:
- cycles (6 + 4 * tx);
- break;
- case RX_Word:
- cycles (6 + 5 * (tx / 2) + 4 * (tx % 2));
- break;
- case RX_Byte:
- cycles (6 + 7 * (tx / 4) + 4 * (tx % 4));
- break;
- default:
- abort ();
- }
- #endif
- break;
- case RXO_rolc:
- v = GD ();
- ma = v & 0x80000000UL;
- v <<= 1;
- v |= carry;
- set_szc (v, 4, ma);
- PD (v);
- E1;
- break;
- case RXO_rorc:
- uma = GD ();
- mb = uma & 1;
- uma >>= 1;
- uma |= (carry ? 0x80000000UL : 0);
- set_szc (uma, 4, mb);
- PD (uma);
- E1;
- break;
- case RXO_rotl:
- mb = GS ();
- uma = GD ();
- if (mb)
- {
- uma = (uma << mb) | (uma >> (32-mb));
- mb = uma & 1;
- }
- set_szc (uma, 4, mb);
- PD (uma);
- E1;
- break;
- case RXO_rotr:
- mb = GS ();
- uma = GD ();
- if (mb)
- {
- uma = (uma >> mb) | (uma << (32-mb));
- mb = uma & 0x80000000;
- }
- set_szc (uma, 4, mb);
- PD (uma);
- E1;
- break;
- case RXO_round:
- ma = GS ();
- FPCLEAR ();
- mb = rxfp_ftoi (ma, regs.r_fpsw);
- FPCHECK ();
- PD (mb);
- tprintf("(int) %g = %d\n", int2float(ma), mb);
- set_sz (mb, 4);
- E (2);
- break;
- case RXO_rts:
- {
- #ifdef CYCLE_ACCURATE
- int cyc = 5;
- #endif
- regs.r_pc = poppc ();
- #ifdef CYCLE_ACCURATE
- /* Note: specs say 5, chip says 3. */
- if (regs.fast_return && regs.link_register == regs.r_pc)
- {
- #ifdef WITH_PROFILE
- fast_returns ++;
- #endif
- tprintf("fast return bonus\n");
- cyc -= 2;
- }
- cycles (cyc);
- regs.fast_return = 0;
- branch_alignment_penalty = 1;
- #endif
- }
- break;
- case RXO_rtsd:
- if (opcode->op[2].type == RX_Operand_Register)
- {
- int i;
- /* RTSD cannot pop R0 (sp). */
- put_reg (0, get_reg (0) + GS() - (opcode->op[0].reg-opcode->op[2].reg+1)*4);
- if (opcode->op[2].reg == 0)
- EXCEPTION (EX_UNDEFINED);
- #ifdef CYCLE_ACCURATE
- tx = opcode->op[0].reg - opcode->op[2].reg + 1;
- #endif
- for (i = opcode->op[2].reg; i <= opcode->op[0].reg; i ++)
- {
- RLD (i);
- put_reg (i, pop ());
- }
- }
- else
- {
- #ifdef CYCLE_ACCURATE
- tx = 0;
- #endif
- put_reg (0, get_reg (0) + GS());
- }
- put_reg (pc, poppc());
- #ifdef CYCLE_ACCURATE
- if (regs.fast_return && regs.link_register == regs.r_pc)
- {
- tprintf("fast return bonus\n");
- #ifdef WITH_PROFILE
- fast_returns ++;
- #endif
- cycles (tx < 3 ? 3 : tx + 1);
- }
- else
- {
- cycles (tx < 5 ? 5 : tx + 1);
- }
- regs.fast_return = 0;
- branch_alignment_penalty = 1;
- #endif
- break;
- case RXO_sat:
- if (FLAG_O && FLAG_S)
- PD (0x7fffffffUL);
- else if (FLAG_O && ! FLAG_S)
- PD (0x80000000UL);
- E1;
- break;
- case RXO_satr:
- if (FLAG_O && ! FLAG_S)
- {
- put_reg (6, 0x0);
- put_reg (5, 0x7fffffff);
- put_reg (4, 0xffffffff);
- }
- else if (FLAG_O && FLAG_S)
- {
- put_reg (6, 0xffffffff);
- put_reg (5, 0x80000000);
- put_reg (4, 0x0);
- }
- E1;
- break;
-
- case RXO_sbb:
- MATH_OP (-, ! carry);
- break;
- case RXO_sccnd:
- if (GS())
- PD (1);
- else
- PD (0);
- E1;
- break;
- case RXO_scmpu:
- #ifdef CYCLE_ACCURATE
- tx = regs.r[3];
- #endif
- while (regs.r[3] != 0)
- {
- uma = mem_get_qi (regs.r[1] ++);
- umb = mem_get_qi (regs.r[2] ++);
- regs.r[3] --;
- if (uma != umb || uma == 0)
- break;
- }
- if (uma == umb)
- set_zc (1, 1);
- else
- set_zc (0, ((int)uma - (int)umb) >= 0);
- cycles (2 + 4 * (tx / 4) + 4 * (tx % 4));
- break;
- case RXO_setpsw:
- v = 1 << opcode->op[0].reg;
- if (FLAG_PM
- && (v == FLAGBIT_I
- || v == FLAGBIT_U))
- break;
- regs.r_psw |= v;
- cycles (1);
- break;
- case RXO_smovb:
- RL (3);
- #ifdef CYCLE_ACCURATE
- tx = regs.r[3];
- #endif
- while (regs.r[3])
- {
- uma = mem_get_qi (regs.r[2] --);
- mem_put_qi (regs.r[1]--, uma);
- regs.r[3] --;
- }
- #ifdef CYCLE_ACCURATE
- if (tx > 3)
- cycles (6 + 3 * (tx / 4) + 3 * (tx % 4));
- else
- cycles (2 + 3 * (tx % 4));
- #endif
- break;
- case RXO_smovf:
- RL (3);
- #ifdef CYCLE_ACCURATE
- tx = regs.r[3];
- #endif
- while (regs.r[3])
- {
- uma = mem_get_qi (regs.r[2] ++);
- mem_put_qi (regs.r[1]++, uma);
- regs.r[3] --;
- }
- cycles (2 + 3 * (int)(tx / 4) + 3 * (tx % 4));
- break;
- case RXO_smovu:
- #ifdef CYCLE_ACCURATE
- tx = regs.r[3];
- #endif
- while (regs.r[3] != 0)
- {
- uma = mem_get_qi (regs.r[2] ++);
- mem_put_qi (regs.r[1]++, uma);
- regs.r[3] --;
- if (uma == 0)
- break;
- }
- cycles (2 + 3 * (int)(tx / 4) + 3 * (tx % 4));
- break;
- case RXO_shar: /* d = ma >> mb */
- SHIFT_OP (sll, int, mb, >>=, 1);
- E (1);
- break;
- case RXO_shll: /* d = ma << mb */
- SHIFT_OP (ll, int, mb, <<=, 0x80000000UL);
- E (1);
- break;
- case RXO_shlr: /* d = ma >> mb */
- SHIFT_OP (ll, unsigned int, mb, >>=, 1);
- E (1);
- break;
- case RXO_sstr:
- RL (3);
- #ifdef CYCLE_ACCURATE
- tx = regs.r[3];
- #endif
- switch (opcode->size)
- {
- case RX_Long:
- while (regs.r[3] != 0)
- {
- mem_put_si (regs.r[1], regs.r[2]);
- regs.r[1] += 4;
- regs.r[3] --;
- }
- cycles (2 + tx);
- break;
- case RX_Word:
- while (regs.r[3] != 0)
- {
- mem_put_hi (regs.r[1], regs.r[2]);
- regs.r[1] += 2;
- regs.r[3] --;
- }
- cycles (2 + (int)(tx / 2) + tx % 2);
- break;
- case RX_Byte:
- while (regs.r[3] != 0)
- {
- mem_put_qi (regs.r[1], regs.r[2]);
- regs.r[1] ++;
- regs.r[3] --;
- }
- cycles (2 + (int)(tx / 4) + tx % 4);
- break;
- default:
- abort ();
- }
- break;
- case RXO_stcc:
- if (GS2())
- PD (GS ());
- E1;
- break;
- case RXO_stop:
- PRIVILEDGED ();
- regs.r_psw |= FLAGBIT_I;
- DO_RETURN (RX_MAKE_STOPPED(0));
- case RXO_sub:
- MATH_OP (-, 0);
- break;
- case RXO_suntil:
- RL(3);
- #ifdef CYCLE_ACCURATE
- tx = 0;
- #endif
- if (regs.r[3] == 0)
- {
- cycles (3);
- break;
- }
- switch (opcode->size)
- {
- case RX_Long:
- uma = get_reg (2);
- while (regs.r[3] != 0)
- {
- regs.r[3] --;
- umb = mem_get_si (get_reg (1));
- regs.r[1] += 4;
- #ifdef CYCLE_ACCURATE
- tx ++;
- #endif
- if (umb == uma)
- break;
- }
- #ifdef CYCLE_ACCURATE
- cycles (3 + 3 * tx);
- #endif
- break;
- case RX_Word:
- uma = get_reg (2) & 0xffff;
- while (regs.r[3] != 0)
- {
- regs.r[3] --;
- umb = mem_get_hi (get_reg (1));
- regs.r[1] += 2;
- #ifdef CYCLE_ACCURATE
- tx ++;
- #endif
- if (umb == uma)
- break;
- }
- #ifdef CYCLE_ACCURATE
- cycles (3 + 3 * (tx / 2) + 3 * (tx % 2));
- #endif
- break;
- case RX_Byte:
- uma = get_reg (2) & 0xff;
- while (regs.r[3] != 0)
- {
- regs.r[3] --;
- umb = mem_get_qi (regs.r[1]);
- regs.r[1] += 1;
- #ifdef CYCLE_ACCURATE
- tx ++;
- #endif
- if (umb == uma)
- break;
- }
- #ifdef CYCLE_ACCURATE
- cycles (3 + 3 * (tx / 4) + 3 * (tx % 4));
- #endif
- break;
- default:
- abort();
- }
- if (uma == umb)
- set_zc (1, 1);
- else
- set_zc (0, ((int)uma - (int)umb) >= 0);
- break;
- case RXO_swhile:
- RL(3);
- #ifdef CYCLE_ACCURATE
- tx = 0;
- #endif
- if (regs.r[3] == 0)
- break;
- switch (opcode->size)
- {
- case RX_Long:
- uma = get_reg (2);
- while (regs.r[3] != 0)
- {
- regs.r[3] --;
- umb = mem_get_si (get_reg (1));
- regs.r[1] += 4;
- #ifdef CYCLE_ACCURATE
- tx ++;
- #endif
- if (umb != uma)
- break;
- }
- #ifdef CYCLE_ACCURATE
- cycles (3 + 3 * tx);
- #endif
- break;
- case RX_Word:
- uma = get_reg (2) & 0xffff;
- while (regs.r[3] != 0)
- {
- regs.r[3] --;
- umb = mem_get_hi (get_reg (1));
- regs.r[1] += 2;
- #ifdef CYCLE_ACCURATE
- tx ++;
- #endif
- if (umb != uma)
- break;
- }
- #ifdef CYCLE_ACCURATE
- cycles (3 + 3 * (tx / 2) + 3 * (tx % 2));
- #endif
- break;
- case RX_Byte:
- uma = get_reg (2) & 0xff;
- while (regs.r[3] != 0)
- {
- regs.r[3] --;
- umb = mem_get_qi (regs.r[1]);
- regs.r[1] += 1;
- #ifdef CYCLE_ACCURATE
- tx ++;
- #endif
- if (umb != uma)
- break;
- }
- #ifdef CYCLE_ACCURATE
- cycles (3 + 3 * (tx / 4) + 3 * (tx % 4));
- #endif
- break;
- default:
- abort();
- }
- if (uma == umb)
- set_zc (1, 1);
- else
- set_zc (0, ((int)uma - (int)umb) >= 0);
- break;
- case RXO_wait:
- PRIVILEDGED ();
- regs.r_psw |= FLAGBIT_I;
- DO_RETURN (RX_MAKE_STOPPED(0));
- case RXO_xchg:
- #ifdef CYCLE_ACCURATE
- regs.m2m = 0;
- #endif
- v = GS (); /* This is the memory operand, if any. */
- PS (GD ()); /* and this may change the address register. */
- PD (v);
- E2;
- #ifdef CYCLE_ACCURATE
- /* all M cycles happen during xchg's cycles. */
- memory_dest = 0;
- memory_source = 0;
- #endif
- break;
- case RXO_xor:
- LOGIC_OP (^);
- break;
- default:
- EXCEPTION (EX_UNDEFINED);
- }
- #ifdef CYCLE_ACCURATE
- regs.m2m = 0;
- if (memory_source)
- regs.m2m |= M2M_SRC;
- if (memory_dest)
- regs.m2m |= M2M_DST;
- regs.rt = new_rt;
- new_rt = -1;
- #endif
- #ifdef WITH_PROFILE
- if (prev_cycle_count == regs.cycle_count)
- {
- printf("Cycle count not updated! id %s\n", id_names[opcode->id]);
- abort ();
- }
- #endif
- #ifdef WITH_PROFILE
- if (running_benchmark)
- {
- int omap = op_lookup (opcode->op[0].type, opcode->op[1].type, opcode->op[2].type);
- cycles_per_id[opcode->id][omap] += regs.cycle_count - prev_cycle_count;
- times_per_id[opcode->id][omap] ++;
- times_per_pair[prev_opcode_id][po0][opcode->id][omap] ++;
- prev_opcode_id = opcode->id;
- po0 = omap;
- }
- #endif
- return RX_MAKE_STEPPED ();
- }
- #ifdef WITH_PROFILE
- void
- reset_pipeline_stats (void)
- {
- memset (cycles_per_id, 0, sizeof(cycles_per_id));
- memset (times_per_id, 0, sizeof(times_per_id));
- memory_stalls = 0;
- register_stalls = 0;
- branch_stalls = 0;
- branch_alignment_stalls = 0;
- fast_returns = 0;
- memset (times_per_pair, 0, sizeof(times_per_pair));
- running_benchmark = 1;
- benchmark_start_cycle = regs.cycle_count;
- }
- void
- halt_pipeline_stats (void)
- {
- running_benchmark = 0;
- benchmark_end_cycle = regs.cycle_count;
- }
- #endif
- void
- pipeline_stats (void)
- {
- #ifdef WITH_PROFILE
- int i, o1;
- int p, p1;
- #endif
- #ifdef CYCLE_ACCURATE
- if (verbose == 1)
- {
- printf ("cycles: %llu\n", regs.cycle_count);
- return;
- }
- printf ("cycles: %13s\n", comma (regs.cycle_count));
- #endif
- #ifdef WITH_PROFILE
- if (benchmark_start_cycle)
- printf ("bmark: %13s\n", comma (benchmark_end_cycle - benchmark_start_cycle));
- printf("\n");
- for (i = 0; i < N_RXO; i++)
- for (o1 = 0; o1 < N_MAP; o1 ++)
- if (times_per_id[i][o1])
- printf("%13s %13s %7.2f %s %s\n",
- comma (cycles_per_id[i][o1]),
- comma (times_per_id[i][o1]),
- (double)cycles_per_id[i][o1] / times_per_id[i][o1],
- op_cache_string(o1),
- id_names[i]+4);
- printf("\n");
- for (p = 0; p < N_RXO; p ++)
- for (p1 = 0; p1 < N_MAP; p1 ++)
- for (i = 0; i < N_RXO; i ++)
- for (o1 = 0; o1 < N_MAP; o1 ++)
- if (times_per_pair[p][p1][i][o1])
- {
- printf("%13s %s %-9s -> %s %s\n",
- comma (times_per_pair[p][p1][i][o1]),
- op_cache_string(p1),
- id_names[p]+4,
- op_cache_string(o1),
- id_names[i]+4);
- }
- printf("\n");
- printf("%13s memory stalls\n", comma (memory_stalls));
- printf("%13s register stalls\n", comma (register_stalls));
- printf("%13s branches taken (non-return)\n", comma (branch_stalls));
- printf("%13s branch alignment stalls\n", comma (branch_alignment_stalls));
- printf("%13s fast returns\n", comma (fast_returns));
- #endif
- }
|