1 Star 0 Fork 0

木××木/tinycc

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
c67-gen.c 69.32 KB
一键复制 编辑 原始数据 按行查看 历史
grischka 提交于 2020-05-05 14:47 . tccgen.c: cleanup debug support
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537
/*
* TMS320C67xx code generator for TCC
*
* Copyright (c) 2001, 2002 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef TARGET_DEFS_ONLY
/* #define ASSEMBLY_LISTING_C67 */
/* number of available registers */
#define NB_REGS 24
/* a register can belong to several classes. The classes must be
sorted from more general to more precise (see gv2() code which does
assumptions on it). */
#define RC_INT 0x0001 /* generic integer register */
#define RC_FLOAT 0x0002 /* generic float register */
#define RC_EAX 0x0004
#define RC_ST0 0x0008
#define RC_ECX 0x0010
#define RC_EDX 0x0020
#define RC_INT_BSIDE 0x00000040 /* generic integer register on b side */
#define RC_C67_A4 0x00000100
#define RC_C67_A5 0x00000200
#define RC_C67_B4 0x00000400
#define RC_C67_B5 0x00000800
#define RC_C67_A6 0x00001000
#define RC_C67_A7 0x00002000
#define RC_C67_B6 0x00004000
#define RC_C67_B7 0x00008000
#define RC_C67_A8 0x00010000
#define RC_C67_A9 0x00020000
#define RC_C67_B8 0x00040000
#define RC_C67_B9 0x00080000
#define RC_C67_A10 0x00100000
#define RC_C67_A11 0x00200000
#define RC_C67_B10 0x00400000
#define RC_C67_B11 0x00800000
#define RC_C67_A12 0x01000000
#define RC_C67_A13 0x02000000
#define RC_C67_B12 0x04000000
#define RC_C67_B13 0x08000000
#define RC_IRET RC_C67_A4 /* function return: integer register */
#define RC_IRE2 RC_C67_A5 /* function return: second integer register */
#define RC_FRET RC_C67_A4 /* function return: float register */
/* pretty names for the registers */
enum {
TREG_EAX = 0, // really A2
TREG_ECX, // really A3
TREG_EDX, // really B0
TREG_ST0, // really B1
TREG_C67_A4,
TREG_C67_A5,
TREG_C67_B4,
TREG_C67_B5,
TREG_C67_A6,
TREG_C67_A7,
TREG_C67_B6,
TREG_C67_B7,
TREG_C67_A8,
TREG_C67_A9,
TREG_C67_B8,
TREG_C67_B9,
TREG_C67_A10,
TREG_C67_A11,
TREG_C67_B10,
TREG_C67_B11,
TREG_C67_A12,
TREG_C67_A13,
TREG_C67_B12,
TREG_C67_B13,
};
/* return registers for function */
#define REG_IRET TREG_C67_A4 /* single word int return register */
#define REG_IRE2 TREG_C67_A5 /* second word return register (for long long) */
#define REG_FRET TREG_C67_A4 /* float return register */
/* defined if function parameters must be evaluated in reverse order */
/* #define INVERT_FUNC_PARAMS */
/* defined if structures are passed as pointers. Otherwise structures
are directly pushed on stack. */
/* #define FUNC_STRUCT_PARAM_AS_PTR */
/* pointer size, in bytes */
#define PTR_SIZE 4
/* long double size and alignment, in bytes */
#define LDOUBLE_SIZE 12
#define LDOUBLE_ALIGN 4
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 8
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
#define USING_GLOBALS
#include "tcc.h"
ST_DATA const int reg_classes[NB_REGS] = {
/* eax */ RC_INT | RC_FLOAT | RC_EAX,
// only allow even regs for floats (allow for doubles)
/* ecx */ RC_INT | RC_ECX,
/* edx */ RC_INT | RC_INT_BSIDE | RC_FLOAT | RC_EDX,
// only allow even regs for floats (allow for doubles)
/* st0 */ RC_INT | RC_INT_BSIDE | RC_ST0,
/* A4 */ RC_C67_A4,
/* A5 */ RC_C67_A5,
/* B4 */ RC_C67_B4,
/* B5 */ RC_C67_B5,
/* A6 */ RC_C67_A6,
/* A7 */ RC_C67_A7,
/* B6 */ RC_C67_B6,
/* B7 */ RC_C67_B7,
/* A8 */ RC_C67_A8,
/* A9 */ RC_C67_A9,
/* B8 */ RC_C67_B8,
/* B9 */ RC_C67_B9,
/* A10 */ RC_C67_A10,
/* A11 */ RC_C67_A11,
/* B10 */ RC_C67_B10,
/* B11 */ RC_C67_B11,
/* A12 */ RC_C67_A10,
/* A13 */ RC_C67_A11,
/* B12 */ RC_C67_B10,
/* B13 */ RC_C67_B11
};
// although tcc thinks it is passing parameters on the stack,
// the C67 really passes up to the first 10 params in special
// regs or regs pairs (for 64 bit params). So keep track of
// the stack offsets so we can translate to the appropriate
// reg (pair)
#define NoCallArgsPassedOnStack 10
int NoOfCurFuncArgs;
int TranslateStackToReg[NoCallArgsPassedOnStack];
int ParamLocOnStack[NoCallArgsPassedOnStack];
int TotalBytesPushedOnStack;
#ifndef FALSE
# define FALSE 0
# define TRUE 1
#endif
#undef BOOL
#define BOOL int
#define ALWAYS_ASSERT(x) \
do {\
if (!(x))\
tcc_error("internal compiler error file at %s:%d", __FILE__, __LINE__);\
} while (0)
/******************************************************/
static unsigned long func_sub_sp_offset;
static int func_ret_sub;
static BOOL C67_invert_test;
static int C67_compare_reg;
#ifdef ASSEMBLY_LISTING_C67
FILE *f = NULL;
#endif
void C67_g(int c)
{
int ind1;
if (nocode_wanted)
return;
#ifdef ASSEMBLY_LISTING_C67
fprintf(f, " %08X", c);
#endif
ind1 = ind + 4;
if (ind1 > (int) cur_text_section->data_allocated)
section_realloc(cur_text_section, ind1);
cur_text_section->data[ind] = c & 0xff;
cur_text_section->data[ind + 1] = (c >> 8) & 0xff;
cur_text_section->data[ind + 2] = (c >> 16) & 0xff;
cur_text_section->data[ind + 3] = (c >> 24) & 0xff;
ind = ind1;
}
/* output a symbol and patch all calls to it */
void gsym_addr(int t, int a)
{
int n, *ptr;
while (t) {
ptr = (int *) (cur_text_section->data + t);
{
Sym *sym;
// extract 32 bit address from MVKH/MVKL
n = ((*ptr >> 7) & 0xffff);
n |= ((*(ptr + 1) >> 7) & 0xffff) << 16;
// define a label that will be relocated
sym = get_sym_ref(&char_pointer_type, cur_text_section, a, 0);
greloc(cur_text_section, sym, t, R_C60LO16);
greloc(cur_text_section, sym, t + 4, R_C60HI16);
// clear out where the pointer was
*ptr &= ~(0xffff << 7);
*(ptr + 1) &= ~(0xffff << 7);
}
t = n;
}
}
// these are regs that tcc doesn't really know about,
// but assign them unique values so the mapping routines
// can distinguish them
#define C67_A0 105
#define C67_SP 106
#define C67_B3 107
#define C67_FP 108
#define C67_B2 109
#define C67_CREG_ZERO -1 /* Special code for no condition reg test */
int ConvertRegToRegClass(int r)
{
// only works for A4-B13
return RC_C67_A4 << (r - TREG_C67_A4);
}
// map TCC reg to C67 reg number
int C67_map_regn(int r)
{
if (r == 0) // normal tcc regs
return 0x2; // A2
else if (r == 1) // normal tcc regs
return 3; // A3
else if (r == 2) // normal tcc regs
return 0; // B0
else if (r == 3) // normal tcc regs
return 1; // B1
else if (r >= TREG_C67_A4 && r <= TREG_C67_B13) // these form a pattern of alt pairs
return (((r & 0xfffffffc) >> 1) | (r & 1)) + 2;
else if (r == C67_A0)
return 0; // set to A0 (offset reg)
else if (r == C67_B2)
return 2; // set to B2 (offset reg)
else if (r == C67_B3)
return 3; // set to B3 (return address reg)
else if (r == C67_SP)
return 15; // set to SP (B15) (offset reg)
else if (r == C67_FP)
return 15; // set to FP (A15) (offset reg)
else if (r == C67_CREG_ZERO)
return 0; // Special code for no condition reg test
else
ALWAYS_ASSERT(FALSE);
return 0;
}
// mapping from tcc reg number to
// C67 register to condition code field
//
// valid condition code regs are:
//
// tcc reg 2 ->B0 -> 1
// tcc reg 3 ->B1 -> 2
// tcc reg 0 -> A2 -> 5
// tcc reg 1 -> A3 -> X
// tcc reg B2 -> 3
int C67_map_regc(int r)
{
if (r == 0) // normal tcc regs
return 0x5;
else if (r == 2) // normal tcc regs
return 0x1;
else if (r == 3) // normal tcc regs
return 0x2;
else if (r == C67_B2) // normal tcc regs
return 0x3;
else if (r == C67_CREG_ZERO)
return 0; // Special code for no condition reg test
else
ALWAYS_ASSERT(FALSE);
return 0;
}
// map TCC reg to C67 reg side A or B
int C67_map_regs(int r)
{
if (r == 0) // normal tcc regs
return 0x0;
else if (r == 1) // normal tcc regs
return 0x0;
else if (r == 2) // normal tcc regs
return 0x1;
else if (r == 3) // normal tcc regs
return 0x1;
else if (r >= TREG_C67_A4 && r <= TREG_C67_B13) // these form a pattern of alt pairs
return (r & 2) >> 1;
else if (r == C67_A0)
return 0; // set to A side
else if (r == C67_B2)
return 1; // set to B side
else if (r == C67_B3)
return 1; // set to B side
else if (r == C67_SP)
return 0x1; // set to SP (B15) B side
else if (r == C67_FP)
return 0x0; // set to FP (A15) A side
else
ALWAYS_ASSERT(FALSE);
return 0;
}
int C67_map_S12(char *s)
{
if (strstr(s, ".S1") != NULL)
return 0;
else if (strcmp(s, ".S2"))
return 1;
else
ALWAYS_ASSERT(FALSE);
return 0;
}
int C67_map_D12(char *s)
{
if (strstr(s, ".D1") != NULL)
return 0;
else if (strcmp(s, ".D2"))
return 1;
else
ALWAYS_ASSERT(FALSE);
return 0;
}
void C67_asm(char *s, int a, int b, int c)
{
BOOL xpath;
#ifdef ASSEMBLY_LISTING_C67
if (!f) {
f = fopen("TCC67_out.txt", "wt");
}
fprintf(f, "%04X ", ind);
#endif
if (strstr(s, "MVKL") == s) {
C67_g((C67_map_regn(b) << 23) |
((a & 0xffff) << 7) | (0x0a << 2) | (C67_map_regs(b) << 1));
} else if (strstr(s, "MVKH") == s) {
C67_g((C67_map_regn(b) << 23) |
(((a >> 16) & 0xffff) << 7) |
(0x1a << 2) | (C67_map_regs(b) << 1));
} else if (strstr(s, "STW.D SP POST DEC") == s) {
C67_g((C67_map_regn(a) << 23) | //src
(15 << 18) | //SP B15
(2 << 13) | //ucst5 (must keep 8 byte boundary !!)
(0xa << 9) | //mode a = post dec ucst
(0 << 8) | //r (LDDW bit 0)
(1 << 7) | //y D1/D2 use B side
(7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of src
(0 << 0)); //parallel
} else if (strstr(s, "STB.D *+SP[A0]") == s) {
C67_g((C67_map_regn(a) << 23) | //src
(15 << 18) | //base reg A15
(0 << 13) | //offset reg A0
(5 << 9) | //mode 5 = pos offset, base reg + off reg
(0 << 8) | //r (LDDW bit 0)
(0 << 7) | //y D1/D2 A side
(3 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of src
(0 << 0)); //parallel
} else if (strstr(s, "STH.D *+SP[A0]") == s) {
C67_g((C67_map_regn(a) << 23) | //src
(15 << 18) | //base reg A15
(0 << 13) | //offset reg A0
(5 << 9) | //mode 5 = pos offset, base reg + off reg
(0 << 8) | //r (LDDW bit 0)
(0 << 7) | //y D1/D2 A side
(5 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of src
(0 << 0)); //parallel
} else if (strstr(s, "STB.D *+SP[A0]") == s) {
C67_g((C67_map_regn(a) << 23) | //src
(15 << 18) | //base reg A15
(0 << 13) | //offset reg A0
(5 << 9) | //mode 5 = pos offset, base reg + off reg
(0 << 8) | //r (LDDW bit 0)
(0 << 7) | //y D1/D2 A side
(3 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of src
(0 << 0)); //parallel
} else if (strstr(s, "STH.D *+SP[A0]") == s) {
C67_g((C67_map_regn(a) << 23) | //src
(15 << 18) | //base reg A15
(0 << 13) | //offset reg A0
(5 << 9) | //mode 5 = pos offset, base reg + off reg
(0 << 8) | //r (LDDW bit 0)
(0 << 7) | //y D1/D2 A side
(5 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of src
(0 << 0)); //parallel
} else if (strstr(s, "STW.D *+SP[A0]") == s) {
C67_g((C67_map_regn(a) << 23) | //src
(15 << 18) | //base reg A15
(0 << 13) | //offset reg A0
(5 << 9) | //mode 5 = pos offset, base reg + off reg
(0 << 8) | //r (LDDW bit 0)
(0 << 7) | //y D1/D2 A side
(7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of src
(0 << 0)); //parallel
} else if (strstr(s, "STW.D *") == s) {
C67_g((C67_map_regn(a) << 23) | //src
(C67_map_regn(b) << 18) | //base reg A0
(0 << 13) | //cst5
(1 << 9) | //mode 1 = pos cst offset
(0 << 8) | //r (LDDW bit 0)
(C67_map_regs(b) << 7) | //y D1/D2 base reg side
(7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of src
(0 << 0)); //parallel
} else if (strstr(s, "STH.D *") == s) {
C67_g((C67_map_regn(a) << 23) | //src
(C67_map_regn(b) << 18) | //base reg A0
(0 << 13) | //cst5
(1 << 9) | //mode 1 = pos cst offset
(0 << 8) | //r (LDDW bit 0)
(C67_map_regs(b) << 7) | //y D1/D2 base reg side
(5 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of src
(0 << 0)); //parallel
} else if (strstr(s, "STB.D *") == s) {
C67_g((C67_map_regn(a) << 23) | //src
(C67_map_regn(b) << 18) | //base reg A0
(0 << 13) | //cst5
(1 << 9) | //mode 1 = pos cst offset
(0 << 8) | //r (LDDW bit 0)
(C67_map_regs(b) << 7) | //y D1/D2 base reg side
(3 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of src
(0 << 0)); //parallel
} else if (strstr(s, "STW.D +*") == s) {
ALWAYS_ASSERT(c < 32);
C67_g((C67_map_regn(a) << 23) | //src
(C67_map_regn(b) << 18) | //base reg A0
(c << 13) | //cst5
(1 << 9) | //mode 1 = pos cst offset
(0 << 8) | //r (LDDW bit 0)
(C67_map_regs(b) << 7) | //y D1/D2 base reg side
(7 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of src
(0 << 0)); //parallel
} else if (strstr(s, "LDW.D SP PRE INC") == s) {
C67_g((C67_map_regn(a) << 23) | //dst
(15 << 18) | //base reg B15
(2 << 13) | //ucst5 (must keep 8 byte boundary)
(9 << 9) | //mode 9 = pre inc ucst5
(0 << 8) | //r (LDDW bit 0)
(1 << 7) | //y D1/D2 B side
(6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "LDDW.D SP PRE INC") == s) {
C67_g((C67_map_regn(a) << 23) | //dst
(15 << 18) | //base reg B15
(1 << 13) | //ucst5 (must keep 8 byte boundary)
(9 << 9) | //mode 9 = pre inc ucst5
(1 << 8) | //r (LDDW bit 1)
(1 << 7) | //y D1/D2 B side
(6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "LDW.D *+SP[A0]") == s) {
C67_g((C67_map_regn(a) << 23) | //dst
(15 << 18) | //base reg A15
(0 << 13) | //offset reg A0
(5 << 9) | //mode 5 = pos offset, base reg + off reg
(0 << 8) | //r (LDDW bit 0)
(0 << 7) | //y D1/D2 A side
(6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "LDDW.D *+SP[A0]") == s) {
C67_g((C67_map_regn(a) << 23) | //dst
(15 << 18) | //base reg A15
(0 << 13) | //offset reg A0
(5 << 9) | //mode 5 = pos offset, base reg + off reg
(1 << 8) | //r (LDDW bit 1)
(0 << 7) | //y D1/D2 A side
(6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "LDH.D *+SP[A0]") == s) {
C67_g((C67_map_regn(a) << 23) | //dst
(15 << 18) | //base reg A15
(0 << 13) | //offset reg A0
(5 << 9) | //mode 5 = pos offset, base reg + off reg
(0 << 8) | //r (LDDW bit 0)
(0 << 7) | //y D1/D2 A side
(4 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "LDB.D *+SP[A0]") == s) {
C67_g((C67_map_regn(a) << 23) | //dst
(15 << 18) | //base reg A15
(0 << 13) | //offset reg A0
(5 << 9) | //mode 5 = pos offset, base reg + off reg
(0 << 8) | //r (LDDW bit 0)
(0 << 7) | //y D1/D2 A side
(2 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "LDHU.D *+SP[A0]") == s) {
C67_g((C67_map_regn(a) << 23) | //dst
(15 << 18) | //base reg A15
(0 << 13) | //offset reg A0
(5 << 9) | //mode 5 = pos offset, base reg + off reg
(0 << 8) | //r (LDDW bit 0)
(0 << 7) | //y D1/D2 A side
(0 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "LDBU.D *+SP[A0]") == s) {
C67_g((C67_map_regn(a) << 23) | //dst
(15 << 18) | //base reg A15
(0 << 13) | //offset reg A0
(5 << 9) | //mode 5 = pos offset, base reg + off reg
(0 << 8) | //r (LDDW bit 0)
(0 << 7) | //y D1/D2 A side
(1 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(a) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "LDW.D *") == s) {
C67_g((C67_map_regn(b) << 23) | //dst
(C67_map_regn(a) << 18) | //base reg A15
(0 << 13) | //cst5
(1 << 9) | //mode 1 = pos cst offset
(0 << 8) | //r (LDDW bit 0)
(C67_map_regs(a) << 7) | //y D1/D2 src side
(6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(b) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "LDDW.D *") == s) {
C67_g((C67_map_regn(b) << 23) | //dst
(C67_map_regn(a) << 18) | //base reg A15
(0 << 13) | //cst5
(1 << 9) | //mode 1 = pos cst offset
(1 << 8) | //r (LDDW bit 1)
(C67_map_regs(a) << 7) | //y D1/D2 src side
(6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(b) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "LDH.D *") == s) {
C67_g((C67_map_regn(b) << 23) | //dst
(C67_map_regn(a) << 18) | //base reg A15
(0 << 13) | //cst5
(1 << 9) | //mode 1 = pos cst offset
(0 << 8) | //r (LDDW bit 0)
(C67_map_regs(a) << 7) | //y D1/D2 src side
(4 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(b) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "LDB.D *") == s) {
C67_g((C67_map_regn(b) << 23) | //dst
(C67_map_regn(a) << 18) | //base reg A15
(0 << 13) | //cst5
(1 << 9) | //mode 1 = pos cst offset
(0 << 8) | //r (LDDW bit 0)
(C67_map_regs(a) << 7) | //y D1/D2 src side
(2 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(b) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "LDHU.D *") == s) {
C67_g((C67_map_regn(b) << 23) | //dst
(C67_map_regn(a) << 18) | //base reg A15
(0 << 13) | //cst5
(1 << 9) | //mode 1 = pos cst offset
(0 << 8) | //r (LDDW bit 0)
(C67_map_regs(a) << 7) | //y D1/D2 src side
(0 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(b) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "LDBU.D *") == s) {
C67_g((C67_map_regn(b) << 23) | //dst
(C67_map_regn(a) << 18) | //base reg A15
(0 << 13) | //cst5
(1 << 9) | //mode 1 = pos cst offset
(0 << 8) | //r (LDDW bit 0)
(C67_map_regs(a) << 7) | //y D1/D2 src side
(1 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(b) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "LDW.D +*") == s) {
C67_g((C67_map_regn(b) << 23) | //dst
(C67_map_regn(a) << 18) | //base reg A15
(1 << 13) | //cst5
(1 << 9) | //mode 1 = pos cst offset
(0 << 8) | //r (LDDW bit 0)
(C67_map_regs(a) << 7) | //y D1/D2 src side
(6 << 4) | //ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
(1 << 2) | //opcode
(C67_map_regs(b) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "CMPLTSP") == s) {
xpath = C67_map_regs(a) ^ C67_map_regs(b);
ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
C67_g((C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x use cross path for src2
(0x3a << 6) | //opcode
(0x8 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side for reg c
(0 << 0)); //parallel
} else if (strstr(s, "CMPGTSP") == s) {
xpath = C67_map_regs(a) ^ C67_map_regs(b);
ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
C67_g((C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x use cross path for src2
(0x39 << 6) | //opcode
(0x8 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side for reg c
(0 << 0)); //parallel
} else if (strstr(s, "CMPEQSP") == s) {
xpath = C67_map_regs(a) ^ C67_map_regs(b);
ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
C67_g((C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x use cross path for src2
(0x38 << 6) | //opcode
(0x8 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side for reg c
(0 << 0)); //parallel
}
else if (strstr(s, "CMPLTDP") == s) {
xpath = C67_map_regs(a) ^ C67_map_regs(b);
ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
C67_g((C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x use cross path for src2
(0x2a << 6) | //opcode
(0x8 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side for reg c
(0 << 0)); //parallel
} else if (strstr(s, "CMPGTDP") == s) {
xpath = C67_map_regs(a) ^ C67_map_regs(b);
ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
C67_g((C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x use cross path for src2
(0x29 << 6) | //opcode
(0x8 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side for reg c
(0 << 0)); //parallel
} else if (strstr(s, "CMPEQDP") == s) {
xpath = C67_map_regs(a) ^ C67_map_regs(b);
ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
C67_g((C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x use cross path for src2
(0x28 << 6) | //opcode
(0x8 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side for reg c
(0 << 0)); //parallel
} else if (strstr(s, "CMPLT") == s) {
xpath = C67_map_regs(a) ^ C67_map_regs(b);
ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
C67_g((C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x use cross path for src2
(0x57 << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side for reg c
(0 << 0)); //parallel
} else if (strstr(s, "CMPGT") == s) {
xpath = C67_map_regs(a) ^ C67_map_regs(b);
ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
C67_g((C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x use cross path for src2
(0x47 << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side for reg c
(0 << 0)); //parallel
} else if (strstr(s, "CMPEQ") == s) {
xpath = C67_map_regs(a) ^ C67_map_regs(b);
ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
C67_g((C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x use cross path for src2
(0x53 << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side for reg c
(0 << 0)); //parallel
} else if (strstr(s, "CMPLTU") == s) {
xpath = C67_map_regs(a) ^ C67_map_regs(b);
ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
C67_g((C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x use cross path for src2
(0x5f << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side for reg c
(0 << 0)); //parallel
} else if (strstr(s, "CMPGTU") == s) {
xpath = C67_map_regs(a) ^ C67_map_regs(b);
ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
C67_g((C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x use cross path for src2
(0x4f << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side for reg c
(0 << 0)); //parallel
} else if (strstr(s, "B DISP") == s) {
C67_g((0 << 29) | //creg
(0 << 28) | //z
(a << 7) | //cnst
(0x4 << 2) | //opcode fixed
(0 << 1) | //S0/S1
(0 << 0)); //parallel
} else if (strstr(s, "B.") == s) {
xpath = C67_map_regs(c) ^ 1;
C67_g((C67_map_regc(b) << 29) | //creg
(a << 28) | //inv
(0 << 23) | //dst
(C67_map_regn(c) << 18) | //src2
(0 << 13) | //
(xpath << 12) | //x cross path if !B side
(0xd << 6) | //opcode
(0x8 << 2) | //opcode fixed
(1 << 1) | //must be S2
(0 << 0)); //parallel
} else if (strstr(s, "MV.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(0 << 13) | //src1 (cst5)
(xpath << 12) | //x cross path if opposite sides
(0x2 << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "SPTRUNC.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(0 << 13) | //src1 NA
(xpath << 12) | //x cross path if opposite sides
(0xb << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "DPTRUNC.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
((C67_map_regn(b) + 1) << 18) | //src2 WEIRD CPU must specify odd reg for some reason
(0 << 13) | //src1 NA
(xpath << 12) | //x cross path if opposite sides
(0x1 << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "INTSP.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(0 << 13) | //src1 NA
(xpath << 12) | //x cross path if opposite sides
(0x4a << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "INTSPU.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(0 << 13) | //src1 NA
(xpath << 12) | //x cross path if opposite sides
(0x49 << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "INTDP.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(0 << 13) | //src1 NA
(xpath << 12) | //x cross path if opposite sides
(0x39 << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "INTDPU.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
((C67_map_regn(b) + 1) << 18) | //src2 WEIRD CPU must specify odd reg for some reason
(0 << 13) | //src1 NA
(xpath << 12) | //x cross path if opposite sides
(0x3b << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "SPDP.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(0 << 13) | //src1 NA
(xpath << 12) | //x cross path if opposite sides
(0x2 << 6) | //opcode
(0x8 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "DPSP.L") == s) {
ALWAYS_ASSERT(C67_map_regs(b) == C67_map_regs(c));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
((C67_map_regn(b) + 1) << 18) | //src2 WEIRD CPU must specify odd reg for some reason
(0 << 13) | //src1 NA
(0 << 12) | //x cross path if opposite sides
(0x9 << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "ADD.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2 (possible x path)
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x cross path if opposite sides
(0x3 << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "SUB.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2 (possible x path)
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x cross path if opposite sides
(0x7 << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "OR.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2 (possible x path)
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x cross path if opposite sides
(0x7f << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "AND.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2 (possible x path)
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x cross path if opposite sides
(0x7b << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "XOR.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2 (possible x path)
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x cross path if opposite sides
(0x6f << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "ADDSP.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2 (possible x path)
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x cross path if opposite sides
(0x10 << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "ADDDP.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2 (possible x path)
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x cross path if opposite sides
(0x18 << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "SUBSP.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2 (possible x path)
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x cross path if opposite sides
(0x11 << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "SUBDP.L") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2 (possible x path)
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x cross path if opposite sides
(0x19 << 5) | //opcode
(0x6 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "MPYSP.M") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2 (possible x path)
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x cross path if opposite sides
(0x1c << 7) | //opcode
(0x0 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "MPYDP.M") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2 (possible x path)
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x cross path if opposite sides
(0x0e << 7) | //opcode
(0x0 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "MPYI.M") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1 (cst5)
(xpath << 12) | //x cross path if opposite sides
(0x4 << 7) | //opcode
(0x0 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "SHR.S") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x cross path if opposite sides
(0x37 << 6) | //opcode
(0x8 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "SHRU.S") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x cross path if opposite sides
(0x27 << 6) | //opcode
(0x8 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "SHL.S") == s) {
xpath = C67_map_regs(b) ^ C67_map_regs(c);
ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(c) << 23) | //dst
(C67_map_regn(b) << 18) | //src2
(C67_map_regn(a) << 13) | //src1
(xpath << 12) | //x cross path if opposite sides
(0x33 << 6) | //opcode
(0x8 << 2) | //opcode fixed
(C67_map_regs(c) << 1) | //side of dest
(0 << 0)); //parallel
} else if (strstr(s, "||ADDK") == s) {
xpath = 0; // no xpath required just use the side of the src/dst
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(b) << 23) | //dst
(a << 07) | //scst16
(0x14 << 2) | //opcode fixed
(C67_map_regs(b) << 1) | //side of dst
(1 << 0)); //parallel
} else if (strstr(s, "ADDK") == s) {
xpath = 0; // no xpath required just use the side of the src/dst
C67_g((0 << 29) | //creg
(0 << 28) | //inv
(C67_map_regn(b) << 23) | //dst
(a << 07) | //scst16
(0x14 << 2) | //opcode fixed
(C67_map_regs(b) << 1) | //side of dst
(0 << 0)); //parallel
} else if (strstr(s, "NOP") == s) {
C67_g(((a - 1) << 13) | //no of cycles
(0 << 0)); //parallel
} else
ALWAYS_ASSERT(FALSE);
#ifdef ASSEMBLY_LISTING_C67
fprintf(f, " %s %d %d %d\n", s, a, b, c);
#endif
}
//r=reg to load, fr=from reg, symbol for relocation, constant
void C67_MVKL(int r, int fc)
{
C67_asm("MVKL.", fc, r, 0);
}
void C67_MVKH(int r, int fc)
{
C67_asm("MVKH.", fc, r, 0);
}
void C67_STB_SP_A0(int r)
{
C67_asm("STB.D *+SP[A0]", r, 0, 0); // STB r,*+SP[A0]
}
void C67_STH_SP_A0(int r)
{
C67_asm("STH.D *+SP[A0]", r, 0, 0); // STH r,*+SP[A0]
}
void C67_STW_SP_A0(int r)
{
C67_asm("STW.D *+SP[A0]", r, 0, 0); // STW r,*+SP[A0]
}
void C67_STB_PTR(int r, int r2)
{
C67_asm("STB.D *", r, r2, 0); // STB r, *r2
}
void C67_STH_PTR(int r, int r2)
{
C67_asm("STH.D *", r, r2, 0); // STH r, *r2
}
void C67_STW_PTR(int r, int r2)
{
C67_asm("STW.D *", r, r2, 0); // STW r, *r2
}
void C67_STW_PTR_PRE_INC(int r, int r2, int n)
{
C67_asm("STW.D +*", r, r2, n); // STW r, *+r2
}
void C67_PUSH(int r)
{
C67_asm("STW.D SP POST DEC", r, 0, 0); // STW r,*SP--
}
void C67_LDW_SP_A0(int r)
{
C67_asm("LDW.D *+SP[A0]", r, 0, 0); // LDW *+SP[A0],r
}
void C67_LDDW_SP_A0(int r)
{
C67_asm("LDDW.D *+SP[A0]", r, 0, 0); // LDDW *+SP[A0],r
}
void C67_LDH_SP_A0(int r)
{
C67_asm("LDH.D *+SP[A0]", r, 0, 0); // LDH *+SP[A0],r
}
void C67_LDB_SP_A0(int r)
{
C67_asm("LDB.D *+SP[A0]", r, 0, 0); // LDB *+SP[A0],r
}
void C67_LDHU_SP_A0(int r)
{
C67_asm("LDHU.D *+SP[A0]", r, 0, 0); // LDHU *+SP[A0],r
}
void C67_LDBU_SP_A0(int r)
{
C67_asm("LDBU.D *+SP[A0]", r, 0, 0); // LDBU *+SP[A0],r
}
void C67_LDW_PTR(int r, int r2)
{
C67_asm("LDW.D *", r, r2, 0); // LDW *r,r2
}
void C67_LDDW_PTR(int r, int r2)
{
C67_asm("LDDW.D *", r, r2, 0); // LDDW *r,r2
}
void C67_LDH_PTR(int r, int r2)
{
C67_asm("LDH.D *", r, r2, 0); // LDH *r,r2
}
void C67_LDB_PTR(int r, int r2)
{
C67_asm("LDB.D *", r, r2, 0); // LDB *r,r2
}
void C67_LDHU_PTR(int r, int r2)
{
C67_asm("LDHU.D *", r, r2, 0); // LDHU *r,r2
}
void C67_LDBU_PTR(int r, int r2)
{
C67_asm("LDBU.D *", r, r2, 0); // LDBU *r,r2
}
void C67_LDW_PTR_PRE_INC(int r, int r2)
{
C67_asm("LDW.D +*", r, r2, 0); // LDW *+r,r2
}
void C67_POP(int r)
{
C67_asm("LDW.D SP PRE INC", r, 0, 0); // LDW *++SP,r
}
void C67_POP_DW(int r)
{
C67_asm("LDDW.D SP PRE INC", r, 0, 0); // LDDW *++SP,r
}
void C67_CMPLT(int s1, int s2, int dst)
{
C67_asm("CMPLT.L1", s1, s2, dst);
}
void C67_CMPGT(int s1, int s2, int dst)
{
C67_asm("CMPGT.L1", s1, s2, dst);
}
void C67_CMPEQ(int s1, int s2, int dst)
{
C67_asm("CMPEQ.L1", s1, s2, dst);
}
void C67_CMPLTU(int s1, int s2, int dst)
{
C67_asm("CMPLTU.L1", s1, s2, dst);
}
void C67_CMPGTU(int s1, int s2, int dst)
{
C67_asm("CMPGTU.L1", s1, s2, dst);
}
void C67_CMPLTSP(int s1, int s2, int dst)
{
C67_asm("CMPLTSP.S1", s1, s2, dst);
}
void C67_CMPGTSP(int s1, int s2, int dst)
{
C67_asm("CMPGTSP.S1", s1, s2, dst);
}
void C67_CMPEQSP(int s1, int s2, int dst)
{
C67_asm("CMPEQSP.S1", s1, s2, dst);
}
void C67_CMPLTDP(int s1, int s2, int dst)
{
C67_asm("CMPLTDP.S1", s1, s2, dst);
}
void C67_CMPGTDP(int s1, int s2, int dst)
{
C67_asm("CMPGTDP.S1", s1, s2, dst);
}
void C67_CMPEQDP(int s1, int s2, int dst)
{
C67_asm("CMPEQDP.S1", s1, s2, dst);
}
void C67_IREG_B_REG(int inv, int r1, int r2) // [!R] B r2
{
C67_asm("B.S2", inv, r1, r2);
}
// call with how many 32 bit words to skip
// (0 would branch to the branch instruction)
void C67_B_DISP(int disp) // B +2 Branch with constant displacement
{
// Branch point is relative to the 8 word fetch packet
//
// we will assume the text section always starts on an 8 word (32 byte boundary)
//
// so add in how many words into the fetch packet the branch is
C67_asm("B DISP", disp + ((ind & 31) >> 2), 0, 0);
}
void C67_NOP(int n)
{
C67_asm("NOP", n, 0, 0);
}
void C67_ADDK(int n, int r)
{
ALWAYS_ASSERT(abs(n) < 32767);
C67_asm("ADDK", n, r, 0);
}
void C67_ADDK_PARALLEL(int n, int r)
{
ALWAYS_ASSERT(abs(n) < 32767);
C67_asm("||ADDK", n, r, 0);
}
void C67_Adjust_ADDK(int *inst, int n)
{
ALWAYS_ASSERT(abs(n) < 32767);
*inst = (*inst & (~(0xffff << 7))) | ((n & 0xffff) << 7);
}
void C67_MV(int r, int v)
{
C67_asm("MV.L", 0, r, v);
}
void C67_DPTRUNC(int r, int v)
{
C67_asm("DPTRUNC.L", 0, r, v);
}
void C67_SPTRUNC(int r, int v)
{
C67_asm("SPTRUNC.L", 0, r, v);
}
void C67_INTSP(int r, int v)
{
C67_asm("INTSP.L", 0, r, v);
}
void C67_INTDP(int r, int v)
{
C67_asm("INTDP.L", 0, r, v);
}
void C67_INTSPU(int r, int v)
{
C67_asm("INTSPU.L", 0, r, v);
}
void C67_INTDPU(int r, int v)
{
C67_asm("INTDPU.L", 0, r, v);
}
void C67_SPDP(int r, int v)
{
C67_asm("SPDP.L", 0, r, v);
}
void C67_DPSP(int r, int v) // note regs must be on the same side
{
C67_asm("DPSP.L", 0, r, v);
}
void C67_ADD(int r, int v)
{
C67_asm("ADD.L", v, r, v);
}
void C67_SUB(int r, int v)
{
C67_asm("SUB.L", v, r, v);
}
void C67_AND(int r, int v)
{
C67_asm("AND.L", v, r, v);
}
void C67_OR(int r, int v)
{
C67_asm("OR.L", v, r, v);
}
void C67_XOR(int r, int v)
{
C67_asm("XOR.L", v, r, v);
}
void C67_ADDSP(int r, int v)
{
C67_asm("ADDSP.L", v, r, v);
}
void C67_SUBSP(int r, int v)
{
C67_asm("SUBSP.L", v, r, v);
}
void C67_MPYSP(int r, int v)
{
C67_asm("MPYSP.M", v, r, v);
}
void C67_ADDDP(int r, int v)
{
C67_asm("ADDDP.L", v, r, v);
}
void C67_SUBDP(int r, int v)
{
C67_asm("SUBDP.L", v, r, v);
}
void C67_MPYDP(int r, int v)
{
C67_asm("MPYDP.M", v, r, v);
}
void C67_MPYI(int r, int v)
{
C67_asm("MPYI.M", v, r, v);
}
void C67_SHL(int r, int v)
{
C67_asm("SHL.S", r, v, v);
}
void C67_SHRU(int r, int v)
{
C67_asm("SHRU.S", r, v, v);
}
void C67_SHR(int r, int v)
{
C67_asm("SHR.S", r, v, v);
}
/* load 'r' from value 'sv' */
void load(int r, SValue * sv)
{
int v, t, ft, fc, fr, size = 0, element;
BOOL Unsigned = FALSE;
SValue v1;
fr = sv->r;
ft = sv->type.t;
fc = sv->c.i;
v = fr & VT_VALMASK;
if (fr & VT_LVAL) {
if (v == VT_LLOCAL) {
v1.type.t = VT_INT;
v1.r = VT_LOCAL | VT_LVAL;
v1.c.i = fc;
load(r, &v1);
fr = r;
} else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
tcc_error("long double not supported");
} else if ((ft & VT_TYPE) == VT_BYTE) {
size = 1;
} else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
size = 1;
Unsigned = TRUE;
} else if ((ft & VT_TYPE) == VT_SHORT) {
size = 2;
} else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
size = 2;
Unsigned = TRUE;
} else if ((ft & VT_BTYPE) == VT_DOUBLE) {
size = 8;
} else {
size = 4;
}
// check if fc is a positive reference on the stack,
// if it is tcc is referencing what it thinks is a parameter
// on the stack, so check if it is really in a register.
if (v == VT_LOCAL && fc > 0) {
int stack_pos = 8;
for (t = 0; t < NoCallArgsPassedOnStack; t++) {
if (fc == stack_pos)
break;
stack_pos += TranslateStackToReg[t];
}
// param has been pushed on stack, get it like a local var
fc = ParamLocOnStack[t] - 8;
}
if ((fr & VT_VALMASK) < VT_CONST) // check for pure indirect
{
if (size == 1) {
if (Unsigned)
C67_LDBU_PTR(v, r); // LDBU *v,r
else
C67_LDB_PTR(v, r); // LDB *v,r
} else if (size == 2) {
if (Unsigned)
C67_LDHU_PTR(v, r); // LDHU *v,r
else
C67_LDH_PTR(v, r); // LDH *v,r
} else if (size == 4) {
C67_LDW_PTR(v, r); // LDW *v,r
} else if (size == 8) {
C67_LDDW_PTR(v, r); // LDDW *v,r
}
C67_NOP(4); // NOP 4
return;
} else if (fr & VT_SYM) {
greloc(cur_text_section, sv->sym, ind, R_C60LO16); // rem the inst need to be patched
greloc(cur_text_section, sv->sym, ind + 4, R_C60HI16);
C67_MVKL(C67_A0, fc); //r=reg to load, constant
C67_MVKH(C67_A0, fc); //r=reg to load, constant
if (size == 1) {
if (Unsigned)
C67_LDBU_PTR(C67_A0, r); // LDBU *A0,r
else
C67_LDB_PTR(C67_A0, r); // LDB *A0,r
} else if (size == 2) {
if (Unsigned)
C67_LDHU_PTR(C67_A0, r); // LDHU *A0,r
else
C67_LDH_PTR(C67_A0, r); // LDH *A0,r
} else if (size == 4) {
C67_LDW_PTR(C67_A0, r); // LDW *A0,r
} else if (size == 8) {
C67_LDDW_PTR(C67_A0, r); // LDDW *A0,r
}
C67_NOP(4); // NOP 4
return;
} else {
element = size;
// divide offset in bytes to create element index
C67_MVKL(C67_A0, (fc / element) + 8 / element); //r=reg to load, constant
C67_MVKH(C67_A0, (fc / element) + 8 / element); //r=reg to load, constant
if (size == 1) {
if (Unsigned)
C67_LDBU_SP_A0(r); // LDBU r, SP[A0]
else
C67_LDB_SP_A0(r); // LDB r, SP[A0]
} else if (size == 2) {
if (Unsigned)
C67_LDHU_SP_A0(r); // LDHU r, SP[A0]
else
C67_LDH_SP_A0(r); // LDH r, SP[A0]
} else if (size == 4) {
C67_LDW_SP_A0(r); // LDW r, SP[A0]
} else if (size == 8) {
C67_LDDW_SP_A0(r); // LDDW r, SP[A0]
}
C67_NOP(4); // NOP 4
return;
}
} else {
if (v == VT_CONST) {
if (fr & VT_SYM) {
greloc(cur_text_section, sv->sym, ind, R_C60LO16); // rem the inst need to be patched
greloc(cur_text_section, sv->sym, ind + 4, R_C60HI16);
}
C67_MVKL(r, fc); //r=reg to load, constant
C67_MVKH(r, fc); //r=reg to load, constant
} else if (v == VT_LOCAL) {
C67_MVKL(r, fc + 8); //r=reg to load, constant C67 stack points to next free
C67_MVKH(r, fc + 8); //r=reg to load, constant
C67_ADD(C67_FP, r); // MV v,r v -> r
} else if (v == VT_CMP) {
C67_MV(C67_compare_reg, r); // MV v,r v -> r
} else if (v == VT_JMP || v == VT_JMPI) {
t = v & 1;
C67_B_DISP(4); // Branch with constant displacement, skip over this branch, load, nop, load
C67_MVKL(r, t); // r=reg to load, 0 or 1 (do this while branching)
C67_NOP(4); // NOP 4
gsym(fc); // modifies other branches to branch here
C67_MVKL(r, t ^ 1); // r=reg to load, 0 or 1
} else if (v != r) {
C67_MV(v, r); // MV v,r v -> r
if ((ft & VT_BTYPE) == VT_DOUBLE)
C67_MV(v + 1, r + 1); // MV v,r v -> r
}
}
}
/* store register 'r' in lvalue 'v' */
void store(int r, SValue * v)
{
int fr, bt, ft, fc, size, t, element;
ft = v->type.t;
fc = v->c.i;
fr = v->r & VT_VALMASK;
bt = ft & VT_BTYPE;
/* XXX: incorrect if float reg to reg */
if (bt == VT_LDOUBLE) {
tcc_error("long double not supported");
} else {
if (bt == VT_SHORT)
size = 2;
else if (bt == VT_BYTE)
size = 1;
else if (bt == VT_DOUBLE)
size = 8;
else
size = 4;
if ((v->r & VT_VALMASK) == VT_CONST) {
/* constant memory reference */
if (v->r & VT_SYM) {
greloc(cur_text_section, v->sym, ind, R_C60LO16); // rem the inst need to be patched
greloc(cur_text_section, v->sym, ind + 4, R_C60HI16);
}
C67_MVKL(C67_A0, fc); //r=reg to load, constant
C67_MVKH(C67_A0, fc); //r=reg to load, constant
if (size == 1)
C67_STB_PTR(r, C67_A0); // STB r, *A0
else if (size == 2)
C67_STH_PTR(r, C67_A0); // STH r, *A0
else if (size == 4 || size == 8)
C67_STW_PTR(r, C67_A0); // STW r, *A0
if (size == 8)
C67_STW_PTR_PRE_INC(r + 1, C67_A0, 1); // STW r, *+A0[1]
} else if ((v->r & VT_VALMASK) == VT_LOCAL) {
// check case of storing to passed argument that
// tcc thinks is on the stack but for C67 is
// passed as a reg. However it may have been
// saved to the stack, if that reg was required
// for a call to a child function
if (fc > 0) // argument ??
{
// walk through sizes and figure which param
int stack_pos = 8;
for (t = 0; t < NoCallArgsPassedOnStack; t++) {
if (fc == stack_pos)
break;
stack_pos += TranslateStackToReg[t];
}
// param has been pushed on stack, get it like a local var
fc = ParamLocOnStack[t] - 8;
}
if (size == 8)
element = 4;
else
element = size;
// divide offset in bytes to create word index
C67_MVKL(C67_A0, (fc / element) + 8 / element); //r=reg to load, constant
C67_MVKH(C67_A0, (fc / element) + 8 / element); //r=reg to load, constant
if (size == 1)
C67_STB_SP_A0(r); // STB r, SP[A0]
else if (size == 2)
C67_STH_SP_A0(r); // STH r, SP[A0]
else if (size == 4 || size == 8)
C67_STW_SP_A0(r); // STW r, SP[A0]
if (size == 8) {
C67_ADDK(1, C67_A0); // ADDK 1,A0
C67_STW_SP_A0(r + 1); // STW r, SP[A0]
}
} else {
if (size == 1)
C67_STB_PTR(r, fr); // STB r, *fr
else if (size == 2)
C67_STH_PTR(r, fr); // STH r, *fr
else if (size == 4 || size == 8)
C67_STW_PTR(r, fr); // STW r, *fr
if (size == 8) {
C67_STW_PTR_PRE_INC(r + 1, fr, 1); // STW r, *+fr[1]
}
}
}
}
/* 'is_jmp' is '1' if it is a jump */
static void gcall_or_jmp(int is_jmp)
{
int r;
Sym *sym;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
/* constant case */
if (vtop->r & VT_SYM) {
/* relocation case */
// get add into A0, then start the jump B3
greloc(cur_text_section, vtop->sym, ind, R_C60LO16); // rem the inst need to be patched
greloc(cur_text_section, vtop->sym, ind + 4, R_C60HI16);
C67_MVKL(C67_A0, 0); //r=reg to load, constant
C67_MVKH(C67_A0, 0); //r=reg to load, constant
C67_IREG_B_REG(0, C67_CREG_ZERO, C67_A0); // B.S2x A0
if (is_jmp) {
C67_NOP(5); // simple jump, just put NOP
} else {
// Call, must load return address into B3 during delay slots
sym = get_sym_ref(&char_pointer_type, cur_text_section, ind + 12, 0); // symbol for return address
greloc(cur_text_section, sym, ind, R_C60LO16); // rem the inst need to be patched
greloc(cur_text_section, sym, ind + 4, R_C60HI16);
C67_MVKL(C67_B3, 0); //r=reg to load, constant
C67_MVKH(C67_B3, 0); //r=reg to load, constant
C67_NOP(3); // put remaining NOPs
}
} else {
/* put an empty PC32 relocation */
ALWAYS_ASSERT(FALSE);
}
} else {
/* otherwise, indirect call */
r = gv(RC_INT);
C67_IREG_B_REG(0, C67_CREG_ZERO, r); // B.S2x r
if (is_jmp) {
C67_NOP(5); // simple jump, just put NOP
} else {
// Call, must load return address into B3 during delay slots
sym = get_sym_ref(&char_pointer_type, cur_text_section, ind + 12, 0); // symbol for return address
greloc(cur_text_section, sym, ind, R_C60LO16); // rem the inst need to be patched
greloc(cur_text_section, sym, ind + 4, R_C60HI16);
C67_MVKL(C67_B3, 0); //r=reg to load, constant
C67_MVKH(C67_B3, 0); //r=reg to load, constant
C67_NOP(3); // put remaining NOPs
}
}
}
/* Return the number of registers needed to return the struct, or 0 if
returning via struct pointer. */
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) {
*ret_align = 1; // Never have to re-align return values for x86-64
return 0;
}
/* generate function call with address in (vtop->t, vtop->c) and free function
context. Stack entry is popped */
void gfunc_call(int nb_args)
{
int i, r, size = 0;
int args_sizes[NoCallArgsPassedOnStack];
if (nb_args > NoCallArgsPassedOnStack) {
tcc_error("more than 10 function params not currently supported");
// handle more than 10, put some on the stack
}
for (i = 0; i < nb_args; i++) {
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
ALWAYS_ASSERT(FALSE);
} else {
/* simple type (currently always same size) */
/* XXX: implicit cast ? */
if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
tcc_error("long long not supported");
} else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
tcc_error("long double not supported");
} else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) {
size = 8;
} else {
size = 4;
}
// put the parameter into the corresponding reg (pair)
r = gv(RC_C67_A4 << (2 * i));
// must put on stack because with 1 pass compiler , no way to tell
// if an up coming nested call might overwrite these regs
C67_PUSH(r);
if (size == 8) {
C67_STW_PTR_PRE_INC(r + 1, C67_SP, 3); // STW r, *+SP[3] (go back and put the other)
}
args_sizes[i] = size;
}
vtop--;
}
// POP all the params on the stack into registers for the
// immediate call (in reverse order)
for (i = nb_args - 1; i >= 0; i--) {
if (args_sizes[i] == 8)
C67_POP_DW(TREG_C67_A4 + i * 2);
else
C67_POP(TREG_C67_A4 + i * 2);
}
gcall_or_jmp(0);
vtop--;
}
// to be compatible with Code Composer for the C67
// the first 10 parameters must be passed in registers
// (pairs for 64 bits) starting wit; A4:A5, then B4:B5 and
// ending with B12:B13.
//
// When a call is made, if the caller has its parameters
// in regs A4-B13 these must be saved before/as the call
// parameters are loaded and restored upon return (or if/when needed).
/* generate function prolog of type 't' */
void gfunc_prolog(Sym *func_sym)
{
CType *func_type = &func_sym->type;
int addr, align, size, func_call, i;
Sym *sym;
CType *type;
sym = func_type->ref;
func_call = sym->f.func_call;
addr = 8;
/* if the function returns a structure, then add an
implicit pointer parameter */
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
func_vc = addr;
addr += 4;
}
NoOfCurFuncArgs = 0;
/* define parameters */
while ((sym = sym->next) != NULL) {
type = &sym->type;
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
size = type_size(type, &align);
size = (size + 3) & ~3;
// keep track of size of arguments so
// we can translate where tcc thinks they
// are on the stack into the appropriate reg
TranslateStackToReg[NoOfCurFuncArgs] = size;
NoOfCurFuncArgs++;
#ifdef FUNC_STRUCT_PARAM_AS_PTR
/* structs are passed as pointer */
if ((type->t & VT_BTYPE) == VT_STRUCT) {
size = 4;
}
#endif
addr += size;
}
func_ret_sub = 0;
/* pascal type call ? */
if (func_call == FUNC_STDCALL)
func_ret_sub = addr - 8;
C67_MV(C67_FP, C67_A0); // move FP -> A0
C67_MV(C67_SP, C67_FP); // move SP -> FP
// place all the args passed in regs onto the stack
loc = 0;
for (i = 0; i < NoOfCurFuncArgs; i++) {
ParamLocOnStack[i] = loc; // remember where the param is
loc += -8;
C67_PUSH(TREG_C67_A4 + i * 2);
if (TranslateStackToReg[i] == 8) {
C67_STW_PTR_PRE_INC(TREG_C67_A4 + i * 2 + 1, C67_SP, 3); // STW r, *+SP[1] (go back and put the other)
}
}
TotalBytesPushedOnStack = -loc;
func_sub_sp_offset = ind; // remember where we put the stack instruction
C67_ADDK(0, C67_SP); // ADDK.L2 loc,SP (just put zero temporarily)
C67_PUSH(C67_A0);
C67_PUSH(C67_B3);
}
/* generate function epilog */
void gfunc_epilog(void)
{
{
int local = (-loc + 7) & -8; // stack must stay aligned to 8 bytes for LDDW instr
C67_POP(C67_B3);
C67_NOP(4); // NOP wait for load
C67_IREG_B_REG(0, C67_CREG_ZERO, C67_B3); // B.S2 B3
C67_POP(C67_FP);
C67_ADDK(local, C67_SP); // ADDK.L2 loc,SP
C67_Adjust_ADDK((int *) (cur_text_section->data +
func_sub_sp_offset),
-local + TotalBytesPushedOnStack);
C67_NOP(3); // NOP
}
}
ST_FUNC void gen_fill_nops(int bytes)
{
if ((bytes & 3))
tcc_error("alignment of code section not multiple of 4");
while (bytes > 0) {
C67_NOP(4);
bytes -= 4;
}
}
/* generate a jump to a label */
int gjmp(int t)
{
int ind1 = ind;
if (nocode_wanted)
return t;
C67_MVKL(C67_A0, t); //r=reg to load, constant
C67_MVKH(C67_A0, t); //r=reg to load, constant
C67_IREG_B_REG(0, C67_CREG_ZERO, C67_A0); // [!R] B.S2x A0
C67_NOP(5);
return ind1;
}
/* generate a jump to a fixed address */
void gjmp_addr(int a)
{
Sym *sym;
// I guess this routine is used for relative short
// local jumps, for now just handle it as the general
// case
// define a label that will be relocated
sym = get_sym_ref(&char_pointer_type, cur_text_section, a, 0);
greloc(cur_text_section, sym, ind, R_C60LO16);
greloc(cur_text_section, sym, ind + 4, R_C60HI16);
gjmp(0); // place a zero there later the symbol will be added to it
}
/* generate a test. set 'inv' to invert test. Stack entry is popped */
ST_FUNC int gjmp_cond(int op, int t)
{
int ind1;
int inv = op & 1;
if (nocode_wanted)
return t;
/* fast case : can jump directly since flags are set */
// C67 uses B2 sort of as flags register
ind1 = ind;
C67_MVKL(C67_A0, t); //r=reg to load, constant
C67_MVKH(C67_A0, t); //r=reg to load, constant
if (C67_compare_reg != TREG_EAX && // check if not already in a conditional test reg
C67_compare_reg != TREG_EDX &&
C67_compare_reg != TREG_ST0 && C67_compare_reg != C67_B2) {
C67_MV(C67_compare_reg, C67_B2);
C67_compare_reg = C67_B2;
}
C67_IREG_B_REG(C67_invert_test ^ inv, C67_compare_reg, C67_A0); // [!R] B.S2x A0
C67_NOP(5);
t = ind1; //return where we need to patch
return t;
}
ST_FUNC int gjmp_append(int n0, int t)
{
if (n0) {
int n = n0, *p;
/* insert vtop->c jump list in t */
// I guess the idea is to traverse to the
// null at the end of the list and store t
// there
while (n != 0) {
p = (int *) (cur_text_section->data + n);
// extract 32 bit address from MVKH/MVKL
n = ((*p >> 7) & 0xffff);
n |= ((*(p + 1) >> 7) & 0xffff) << 16;
}
*p |= (t & 0xffff) << 7;
*(p + 1) |= ((t >> 16) & 0xffff) << 7;
t = n0;
}
return t;
}
/* generate an integer binary operation */
void gen_opi(int op)
{
int r, fr, opc, t;
switch (op) {
case '+':
case TOK_ADDC1: /* add with carry generation */
opc = 0;
gen_op8:
// C67 can't do const compares, must load into a reg
// so just go to gv2 directly - tktk
if (op >= TOK_ULT && op <= TOK_GT)
gv2(RC_INT_BSIDE, RC_INT); // make sure r (src1) is on the B Side of CPU
else
gv2(RC_INT, RC_INT);
r = vtop[-1].r;
fr = vtop[0].r;
C67_compare_reg = C67_B2;
if (op == TOK_LT) {
C67_CMPLT(r, fr, C67_B2);
C67_invert_test = FALSE;
} else if (op == TOK_GE) {
C67_CMPLT(r, fr, C67_B2);
C67_invert_test = TRUE;
} else if (op == TOK_GT) {
C67_CMPGT(r, fr, C67_B2);
C67_invert_test = FALSE;
} else if (op == TOK_LE) {
C67_CMPGT(r, fr, C67_B2);
C67_invert_test = TRUE;
} else if (op == TOK_EQ) {
C67_CMPEQ(r, fr, C67_B2);
C67_invert_test = FALSE;
} else if (op == TOK_NE) {
C67_CMPEQ(r, fr, C67_B2);
C67_invert_test = TRUE;
} else if (op == TOK_ULT) {
C67_CMPLTU(r, fr, C67_B2);
C67_invert_test = FALSE;
} else if (op == TOK_UGE) {
C67_CMPLTU(r, fr, C67_B2);
C67_invert_test = TRUE;
} else if (op == TOK_UGT) {
C67_CMPGTU(r, fr, C67_B2);
C67_invert_test = FALSE;
} else if (op == TOK_ULE) {
C67_CMPGTU(r, fr, C67_B2);
C67_invert_test = TRUE;
} else if (op == '+')
C67_ADD(fr, r); // ADD r,fr,r
else if (op == '-')
C67_SUB(fr, r); // SUB r,fr,r
else if (op == '&')
C67_AND(fr, r); // AND r,fr,r
else if (op == '|')
C67_OR(fr, r); // OR r,fr,r
else if (op == '^')
C67_XOR(fr, r); // XOR r,fr,r
else
ALWAYS_ASSERT(FALSE);
vtop--;
if (op >= TOK_ULT && op <= TOK_GT)
vset_VT_CMP(0x80);
break;
case '-':
case TOK_SUBC1: /* sub with carry generation */
opc = 5;
goto gen_op8;
case TOK_ADDC2: /* add with carry use */
opc = 2;
goto gen_op8;
case TOK_SUBC2: /* sub with carry use */
opc = 3;
goto gen_op8;
case '&':
opc = 4;
goto gen_op8;
case '^':
opc = 6;
goto gen_op8;
case '|':
opc = 1;
goto gen_op8;
case '*':
case TOK_UMULL:
gv2(RC_INT, RC_INT);
r = vtop[-1].r;
fr = vtop[0].r;
vtop--;
C67_MPYI(fr, r); // 32 bit multiply fr,r,fr
C67_NOP(8); // NOP 8 for worst case
break;
case TOK_SHL:
gv2(RC_INT_BSIDE, RC_INT_BSIDE); // shift amount must be on same side as dst
r = vtop[-1].r;
fr = vtop[0].r;
vtop--;
C67_SHL(fr, r); // arithmetic/logical shift
break;
case TOK_SHR:
gv2(RC_INT_BSIDE, RC_INT_BSIDE); // shift amount must be on same side as dst
r = vtop[-1].r;
fr = vtop[0].r;
vtop--;
C67_SHRU(fr, r); // logical shift
break;
case TOK_SAR:
gv2(RC_INT_BSIDE, RC_INT_BSIDE); // shift amount must be on same side as dst
r = vtop[-1].r;
fr = vtop[0].r;
vtop--;
C67_SHR(fr, r); // arithmetic shift
break;
case '/':
t = TOK__divi;
call_func:
vswap();
/* call generic idiv function */
vpush_global_sym(&func_old_type, t);
vrott(3);
gfunc_call(2);
vpushi(0);
vtop->r = REG_IRET;
vtop->r2 = VT_CONST;
break;
case TOK_UDIV:
case TOK_PDIV:
t = TOK__divu;
goto call_func;
case '%':
t = TOK__remi;
goto call_func;
case TOK_UMOD:
t = TOK__remu;
goto call_func;
default:
opc = 7;
goto gen_op8;
}
}
/* generate a floating point operation 'v = t1 op t2' instruction. The
two operands are guaranteed to have the same floating point type */
/* XXX: need to use ST1 too */
void gen_opf(int op)
{
int ft, fc, fr, r;
if (op >= TOK_ULT && op <= TOK_GT)
gv2(RC_EDX, RC_EAX); // make sure src2 is on b side
else
gv2(RC_FLOAT, RC_FLOAT); // make sure src2 is on b side
ft = vtop->type.t;
fc = vtop->c.i;
r = vtop->r;
fr = vtop[-1].r;
if ((ft & VT_BTYPE) == VT_LDOUBLE)
tcc_error("long doubles not supported");
if (op >= TOK_ULT && op <= TOK_GT) {
r = vtop[-1].r;
fr = vtop[0].r;
C67_compare_reg = C67_B2;
if (op == TOK_LT) {
if ((ft & VT_BTYPE) == VT_DOUBLE)
C67_CMPLTDP(r, fr, C67_B2);
else
C67_CMPLTSP(r, fr, C67_B2);
C67_invert_test = FALSE;
} else if (op == TOK_GE) {
if ((ft & VT_BTYPE) == VT_DOUBLE)
C67_CMPLTDP(r, fr, C67_B2);
else
C67_CMPLTSP(r, fr, C67_B2);
C67_invert_test = TRUE;
} else if (op == TOK_GT) {
if ((ft & VT_BTYPE) == VT_DOUBLE)
C67_CMPGTDP(r, fr, C67_B2);
else
C67_CMPGTSP(r, fr, C67_B2);
C67_invert_test = FALSE;
} else if (op == TOK_LE) {
if ((ft & VT_BTYPE) == VT_DOUBLE)
C67_CMPGTDP(r, fr, C67_B2);
else
C67_CMPGTSP(r, fr, C67_B2);
C67_invert_test = TRUE;
} else if (op == TOK_EQ) {
if ((ft & VT_BTYPE) == VT_DOUBLE)
C67_CMPEQDP(r, fr, C67_B2);
else
C67_CMPEQSP(r, fr, C67_B2);
C67_invert_test = FALSE;
} else if (op == TOK_NE) {
if ((ft & VT_BTYPE) == VT_DOUBLE)
C67_CMPEQDP(r, fr, C67_B2);
else
C67_CMPEQSP(r, fr, C67_B2);
C67_invert_test = TRUE;
} else {
ALWAYS_ASSERT(FALSE);
}
vset_VT_CMP(0x80);
} else {
if (op == '+') {
if ((ft & VT_BTYPE) == VT_DOUBLE) {
C67_ADDDP(r, fr); // ADD fr,r,fr
C67_NOP(6);
} else {
C67_ADDSP(r, fr); // ADD fr,r,fr
C67_NOP(3);
}
vtop--;
} else if (op == '-') {
if ((ft & VT_BTYPE) == VT_DOUBLE) {
C67_SUBDP(r, fr); // SUB fr,r,fr
C67_NOP(6);
} else {
C67_SUBSP(r, fr); // SUB fr,r,fr
C67_NOP(3);
}
vtop--;
} else if (op == '*') {
if ((ft & VT_BTYPE) == VT_DOUBLE) {
C67_MPYDP(r, fr); // MPY fr,r,fr
C67_NOP(9);
} else {
C67_MPYSP(r, fr); // MPY fr,r,fr
C67_NOP(3);
}
vtop--;
} else if (op == '/') {
if ((ft & VT_BTYPE) == VT_DOUBLE) {
// must call intrinsic DP floating point divide
vswap();
/* call generic idiv function */
vpush_global_sym(&func_old_type, TOK__divd);
vrott(3);
gfunc_call(2);
vpushi(0);
vtop->r = REG_FRET;
vtop->r2 = REG_IRE2;
} else {
// must call intrinsic SP floating point divide
vswap();
/* call generic idiv function */
vpush_global_sym(&func_old_type, TOK__divf);
vrott(3);
gfunc_call(2);
vpushi(0);
vtop->r = REG_FRET;
vtop->r2 = VT_CONST;
}
} else
ALWAYS_ASSERT(FALSE);
}
}
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
and 'long long' cases. */
void gen_cvt_itof(int t)
{
int r;
gv(RC_INT);
r = vtop->r;
if ((t & VT_BTYPE) == VT_DOUBLE) {
if (t & VT_UNSIGNED)
C67_INTDPU(r, r);
else
C67_INTDP(r, r);
C67_NOP(4);
vtop->type.t = VT_DOUBLE;
} else {
if (t & VT_UNSIGNED)
C67_INTSPU(r, r);
else
C67_INTSP(r, r);
C67_NOP(3);
vtop->type.t = VT_FLOAT;
}
}
/* convert fp to int 't' type */
/* XXX: handle long long case */
void gen_cvt_ftoi(int t)
{
int r;
gv(RC_FLOAT);
r = vtop->r;
if (t != VT_INT)
tcc_error("long long not supported");
else {
if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) {
C67_DPTRUNC(r, r);
C67_NOP(3);
} else {
C67_SPTRUNC(r, r);
C67_NOP(3);
}
vtop->type.t = VT_INT;
}
}
/* convert from one floating point type to another */
void gen_cvt_ftof(int t)
{
int r, r2;
if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE &&
(t & VT_BTYPE) == VT_FLOAT) {
// convert double to float
gv(RC_FLOAT); // get it in a register pair
r = vtop->r;
C67_DPSP(r, r); // convert it to SP same register
C67_NOP(3);
vtop->type.t = VT_FLOAT;
vtop->r2 = VT_CONST; // set this as unused
} else if ((vtop->type.t & VT_BTYPE) == VT_FLOAT &&
(t & VT_BTYPE) == VT_DOUBLE) {
// convert float to double
gv(RC_FLOAT); // get it in a register
r = vtop->r;
if (r == TREG_EAX) { // make sure the paired reg is avail
r2 = get_reg(RC_ECX);
} else if (r == TREG_EDX) {
r2 = get_reg(RC_ST0);
} else {
ALWAYS_ASSERT(FALSE);
r2 = 0; /* avoid warning */
}
C67_SPDP(r, r); // convert it to DP same register
C67_NOP(1);
vtop->type.t = VT_DOUBLE;
vtop->r2 = r2; // set this as unused
} else {
ALWAYS_ASSERT(FALSE);
}
}
/* computed goto support */
void ggoto(void)
{
gcall_or_jmp(1);
vtop--;
}
/* Save the stack pointer onto the stack and return the location of its address */
ST_FUNC void gen_vla_sp_save(int addr) {
tcc_error("variable length arrays unsupported for this target");
}
/* Restore the SP from a location on the stack */
ST_FUNC void gen_vla_sp_restore(int addr) {
tcc_error("variable length arrays unsupported for this target");
}
/* Subtract from the stack pointer, and push the resulting value onto the stack */
ST_FUNC void gen_vla_alloc(CType *type, int align) {
tcc_error("variable length arrays unsupported for this target");
}
/* end of C67 code generator */
/*************************************************************/
#endif
/*************************************************************/
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/ioesync/tinycc.git
git@gitee.com:ioesync/tinycc.git
ioesync
tinycc
tinycc
dev

搜索帮助