summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2009-10-03 12:31:59 +0000
committerTim Angus <tim@ngus.net>2013-01-03 00:16:03 +0000
commit304d4258d3a49488f570b8ad71931faa7e5d40ba (patch)
treebf9ec15bd9154305ff9fab2943b3daf25024f8a5 /src
parent6e90e4e7861f5cb354487d1fe0f1fd06c385308e (diff)
* Merge ioq3-r1498, by popular demand
Diffstat (limited to 'src')
-rw-r--r--src/client/cl_cgame.c8
-rw-r--r--src/client/cl_cin.c81
-rw-r--r--src/client/cl_console.c20
-rw-r--r--src/client/cl_curl.c2
-rw-r--r--src/client/cl_input.c2
-rw-r--r--src/client/cl_keys.c71
-rw-r--r--src/client/cl_main.c74
-rw-r--r--src/client/cl_ui.c8
-rw-r--r--src/client/snd_openal.c2
-rw-r--r--src/libspeex/config.h20
-rw-r--r--src/qcommon/cm_load.c19
-rw-r--r--src/qcommon/cm_trace.c5
-rw-r--r--src/qcommon/cmd.c76
-rw-r--r--src/qcommon/common.c98
-rw-r--r--src/qcommon/cvar.c22
-rw-r--r--src/qcommon/msg.c36
-rw-r--r--src/qcommon/net_ip.c40
-rw-r--r--src/qcommon/parse.c2
-rw-r--r--src/qcommon/q_math.c26
-rw-r--r--src/qcommon/q_shared.c188
-rw-r--r--src/qcommon/q_shared.h11
-rw-r--r--src/qcommon/qcommon.h24
-rw-r--r--src/qcommon/unzip.c6
-rw-r--r--src/qcommon/vm.c72
-rw-r--r--src/qcommon/vm_powerpc.c2170
-rw-r--r--src/qcommon/vm_powerpc_asm.c1009
-rw-r--r--src/qcommon/vm_powerpc_asm.h156
-rw-r--r--src/renderer/tr_bsp.c13
-rw-r--r--src/renderer/tr_image.c14
-rw-r--r--src/renderer/tr_image_bmp.c19
-rw-r--r--src/renderer/tr_image_jpg.c13
-rw-r--r--src/renderer/tr_image_pcx.c27
-rw-r--r--src/renderer/tr_image_png.c7
-rw-r--r--src/renderer/tr_image_tga.c15
-rw-r--r--src/renderer/tr_model.c27
-rw-r--r--src/sdl/sdl_input.c74
-rw-r--r--src/server/sv_ccmds.c13
-rw-r--r--src/server/sv_client.c1
-rw-r--r--src/server/sv_game.c11
-rw-r--r--src/server/sv_main.c7
-rw-r--r--src/sys/con_tty.c20
-rw-r--r--src/sys/sys_unix.c5
-rw-r--r--src/tools/lcc/src/bytecode.c14
-rw-r--r--src/tools/lcc/src/c.h6
44 files changed, 4036 insertions, 498 deletions
diff --git a/src/client/cl_cgame.c b/src/client/cl_cgame.c
index 6e436316..9a16d3bf 100644
--- a/src/client/cl_cgame.c
+++ b/src/client/cl_cgame.c
@@ -397,11 +397,9 @@ void CL_ShutdownCGame( void ) {
}
static int FloatAsInt( float f ) {
- int temp;
-
- *(float *)&temp = f;
-
- return temp;
+ floatint_t fi;
+ fi.f = f;
+ return fi.i;
}
/*
diff --git a/src/client/cl_cin.c b/src/client/cl_cin.c
index 1443937c..7690d627 100644
--- a/src/client/cl_cin.c
+++ b/src/client/cl_cin.c
@@ -621,7 +621,10 @@ static void decodeCodeBook( byte *input, unsigned short roq_flags )
unsigned short *aptr, *bptr, *cptr, *dptr;
long y0,y1,y2,y3,cr,cb;
byte *bbptr, *baptr, *bcptr, *bdptr;
- unsigned int *iaptr, *ibptr, *icptr, *idptr;
+ union {
+ unsigned int *i;
+ unsigned short *s;
+ } iaptr, ibptr, icptr, idptr;
if (!roq_flags) {
two = four = 256;
@@ -664,7 +667,7 @@ static void decodeCodeBook( byte *input, unsigned short roq_flags )
VQ2TO4(aptr,bptr,cptr,dptr);
}
} else if (cinTable[currentHandle].samplesPerPixel==4) {
- ibptr = (unsigned int *)bptr;
+ ibptr.s = bptr;
for(i=0;i<two;i++) {
y0 = (long)*input++;
y1 = (long)*input++;
@@ -672,20 +675,22 @@ static void decodeCodeBook( byte *input, unsigned short roq_flags )
y3 = (long)*input++;
cr = (long)*input++;
cb = (long)*input++;
- *ibptr++ = yuv_to_rgb24( y0, cr, cb );
- *ibptr++ = yuv_to_rgb24( y1, cr, cb );
- *ibptr++ = yuv_to_rgb24( y2, cr, cb );
- *ibptr++ = yuv_to_rgb24( y3, cr, cb );
+ *ibptr.i++ = yuv_to_rgb24( y0, cr, cb );
+ *ibptr.i++ = yuv_to_rgb24( y1, cr, cb );
+ *ibptr.i++ = yuv_to_rgb24( y2, cr, cb );
+ *ibptr.i++ = yuv_to_rgb24( y3, cr, cb );
}
- icptr = (unsigned int *)vq4;
- idptr = (unsigned int *)vq8;
+ icptr.s = vq4;
+ idptr.s = vq8;
for(i=0;i<four;i++) {
- iaptr = (unsigned int *)vq2 + (*input++)*4;
- ibptr = (unsigned int *)vq2 + (*input++)*4;
+ iaptr.s = vq2;
+ iaptr.i += (*input++)*4;
+ ibptr.s = vq2;
+ ibptr.i += (*input++)*4;
for(j=0;j<2;j++)
- VQ2TO4(iaptr, ibptr, icptr, idptr);
+ VQ2TO4(iaptr.i, ibptr.i, icptr.i, idptr.i);
}
} else if (cinTable[currentHandle].samplesPerPixel==1) {
bbptr = (byte *)bptr;
@@ -740,7 +745,7 @@ static void decodeCodeBook( byte *input, unsigned short roq_flags )
}
}
} else if (cinTable[currentHandle].samplesPerPixel==4) {
- ibptr = (unsigned int *)bptr;
+ ibptr.s = bptr;
for(i=0;i<two;i++) {
y0 = (long)*input++;
y1 = (long)*input++;
@@ -748,25 +753,27 @@ static void decodeCodeBook( byte *input, unsigned short roq_flags )
y3 = (long)*input++;
cr = (long)*input++;
cb = (long)*input++;
- *ibptr++ = yuv_to_rgb24( y0, cr, cb );
- *ibptr++ = yuv_to_rgb24( y1, cr, cb );
- *ibptr++ = yuv_to_rgb24( ((y0*3)+y2)/4, cr, cb );
- *ibptr++ = yuv_to_rgb24( ((y1*3)+y3)/4, cr, cb );
- *ibptr++ = yuv_to_rgb24( (y0+(y2*3))/4, cr, cb );
- *ibptr++ = yuv_to_rgb24( (y1+(y3*3))/4, cr, cb );
- *ibptr++ = yuv_to_rgb24( y2, cr, cb );
- *ibptr++ = yuv_to_rgb24( y3, cr, cb );
+ *ibptr.i++ = yuv_to_rgb24( y0, cr, cb );
+ *ibptr.i++ = yuv_to_rgb24( y1, cr, cb );
+ *ibptr.i++ = yuv_to_rgb24( ((y0*3)+y2)/4, cr, cb );
+ *ibptr.i++ = yuv_to_rgb24( ((y1*3)+y3)/4, cr, cb );
+ *ibptr.i++ = yuv_to_rgb24( (y0+(y2*3))/4, cr, cb );
+ *ibptr.i++ = yuv_to_rgb24( (y1+(y3*3))/4, cr, cb );
+ *ibptr.i++ = yuv_to_rgb24( y2, cr, cb );
+ *ibptr.i++ = yuv_to_rgb24( y3, cr, cb );
}
- icptr = (unsigned int *)vq4;
- idptr = (unsigned int *)vq8;
+ icptr.s = vq4;
+ idptr.s = vq8;
for(i=0;i<four;i++) {
- iaptr = (unsigned int *)vq2 + (*input++)*8;
- ibptr = (unsigned int *)vq2 + (*input++)*8;
+ iaptr.s = vq2;
+ iaptr.i += (*input++)*8;
+ ibptr.s = vq2;
+ ibptr.i += (*input++)*8;
for(j=0;j<2;j++) {
- VQ2TO4(iaptr, ibptr, icptr, idptr);
- VQ2TO4(iaptr, ibptr, icptr, idptr);
+ VQ2TO4(iaptr.i, ibptr.i, icptr.i, idptr.i);
+ VQ2TO4(iaptr.i, ibptr.i, icptr.i, idptr.i);
}
}
} else if (cinTable[currentHandle].samplesPerPixel==1) {
@@ -842,24 +849,26 @@ static void decodeCodeBook( byte *input, unsigned short roq_flags )
}
}
} else if (cinTable[currentHandle].samplesPerPixel == 4) {
- ibptr = (unsigned int *) bptr;
+ ibptr.s = bptr;
for(i=0;i<two;i++) {
y0 = (long)*input; input+=2;
y2 = (long)*input; input+=2;
cr = (long)*input++;
cb = (long)*input++;
- *ibptr++ = yuv_to_rgb24( y0, cr, cb );
- *ibptr++ = yuv_to_rgb24( y2, cr, cb );
+ *ibptr.i++ = yuv_to_rgb24( y0, cr, cb );
+ *ibptr.i++ = yuv_to_rgb24( y2, cr, cb );
}
- icptr = (unsigned int *)vq4;
- idptr = (unsigned int *)vq8;
+ icptr.s = vq4;
+ idptr.s = vq8;
for(i=0;i<four;i++) {
- iaptr = (unsigned int *)vq2 + (*input++)*2;
- ibptr = (unsigned int *)vq2 + (*input++)*2;
+ iaptr.s = vq2;
+ iaptr.i += (*input++)*2;
+ ibptr.s = vq2 + (*input++)*2;
+ ibptr.i += (*input++)*2;
for(j=0;j<2;j++) {
- VQ2TO2(iaptr,ibptr,icptr,idptr);
+ VQ2TO2(iaptr.i,ibptr.i,icptr.i,idptr.i);
}
}
}
@@ -1194,8 +1203,8 @@ redump:
cinTable[currentHandle].roq_id = framedata[0] + framedata[1]*256;
cinTable[currentHandle].RoQFrameSize = framedata[2] + framedata[3]*256 + framedata[4]*65536;
cinTable[currentHandle].roq_flags = framedata[6] + framedata[7]*256;
- cinTable[currentHandle].roqF0 = (char)framedata[7];
- cinTable[currentHandle].roqF1 = (char)framedata[6];
+ cinTable[currentHandle].roqF0 = (signed char)framedata[7];
+ cinTable[currentHandle].roqF1 = (signed char)framedata[6];
if (cinTable[currentHandle].RoQFrameSize>65536||cinTable[currentHandle].roq_id==0x1084) {
Com_DPrintf("roq_size>65536||roq_id==0x1084\n");
diff --git a/src/client/cl_console.c b/src/client/cl_console.c
index 0ad397b9..39f13028 100644
--- a/src/client/cl_console.c
+++ b/src/client/cl_console.c
@@ -233,6 +233,17 @@ void Con_CheckResize (void)
con.display = con.current;
}
+/*
+==================
+Cmd_CompleteTxtName
+==================
+*/
+void Cmd_CompleteTxtName( char *args, int argNum ) {
+ if( argNum == 2 ) {
+ Field_CompleteFilename( "", "txt", qfalse );
+ }
+}
+
/*
================
@@ -255,6 +266,7 @@ void Con_Init (void) {
Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
Cmd_AddCommand ("clear", Con_Clear_f);
Cmd_AddCommand ("condump", Con_Dump_f);
+ Cmd_SetCommandCompletionFunc( "condump", Cmd_CompleteTxtName );
}
@@ -431,7 +443,7 @@ void Con_DrawSolidConsole( float frac ) {
SCR_AdjustFrom640( &con.xadjust, NULL, NULL, NULL );
// draw the background
- y = frac * SCREEN_HEIGHT - 2;
+ y = frac * SCREEN_HEIGHT;
if ( y < 1 ) {
y = 0;
}
@@ -453,10 +465,8 @@ void Con_DrawSolidConsole( float frac ) {
i = strlen( Q3_VERSION );
for (x=0 ; x<i ; x++) {
-
- SCR_DrawSmallChar( cls.glconfig.vidWidth - ( i - x ) * SMALLCHAR_WIDTH,
- (lines-(SMALLCHAR_HEIGHT+SMALLCHAR_HEIGHT/2)), Q3_VERSION[x] );
-
+ SCR_DrawSmallChar( cls.glconfig.vidWidth - ( i - x + 1 ) * SMALLCHAR_WIDTH,
+ lines - SMALLCHAR_HEIGHT, Q3_VERSION[x] );
}
diff --git a/src/client/cl_curl.c b/src/client/cl_curl.c
index fb93aa2f..4c34667c 100644
--- a/src/client/cl_curl.c
+++ b/src/client/cl_curl.c
@@ -218,7 +218,7 @@ static int CL_cURL_CallbackProgress( void *dummy, double dltotal, double dlnow,
return 0;
}
-static int CL_cURL_CallbackWrite(void *buffer, size_t size, size_t nmemb,
+static size_t CL_cURL_CallbackWrite(void *buffer, size_t size, size_t nmemb,
void *stream)
{
FS_Write( buffer, size*nmemb, ((fileHandle_t*)stream)[0] );
diff --git a/src/client/cl_input.c b/src/client/cl_input.c
index cb95ce8c..dae244bb 100644
--- a/src/client/cl_input.c
+++ b/src/client/cl_input.c
@@ -782,8 +782,8 @@ void CL_WritePacket( void ) {
} else if (Q_stricmp(target, "none") == 0) {
clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0;
} else {
- clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0;
const char *ptr = target;
+ clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0;
do {
if ((*ptr == ',') || (*ptr == '\0')) {
const int val = atoi(target);
diff --git a/src/client/cl_keys.c b/src/client/cl_keys.c
index ee075ce5..10abefc2 100644
--- a/src/client/cl_keys.c
+++ b/src/client/cl_keys.c
@@ -728,7 +728,6 @@ qboolean Key_IsDown( int keynum ) {
return keys[keynum].down;
}
-
/*
===================
Key_StringToKeynum
@@ -753,28 +752,12 @@ int Key_StringToKeynum( char *str ) {
}
// check for hex code
- if ( str[0] == '0' && str[1] == 'x' && strlen( str ) == 4) {
- int n1, n2;
-
- n1 = str[2];
- if ( n1 >= '0' && n1 <= '9' ) {
- n1 -= '0';
- } else if ( n1 >= 'a' && n1 <= 'f' ) {
- n1 = n1 - 'a' + 10;
- } else {
- n1 = 0;
- }
+ if ( strlen( str ) == 4 ) {
+ int n = Com_HexStrToInt( str );
- n2 = str[3];
- if ( n2 >= '0' && n2 <= '9' ) {
- n2 -= '0';
- } else if ( n2 >= 'a' && n2 <= 'f' ) {
- n2 = n2 - 'a' + 10;
- } else {
- n2 = 0;
+ if ( n >= 0 ) {
+ return n;
}
-
- return n1 * 16 + n2;
}
// scan for a text match
@@ -1027,6 +1010,50 @@ void Key_KeynameCompletion( void(*callback)(const char *s) ) {
}
/*
+====================
+Key_CompleteUnbind
+====================
+*/
+static void Key_CompleteUnbind( char *args, int argNum )
+{
+ if( argNum == 2 )
+ {
+ // Skip "unbind "
+ char *p = Com_SkipTokens( args, 1, " " );
+
+ if( p > args )
+ Field_CompleteKeyname( );
+ }
+}
+
+/*
+====================
+Key_CompleteBind
+====================
+*/
+static void Key_CompleteBind( char *args, int argNum )
+{
+ char *p;
+
+ if( argNum == 2 )
+ {
+ // Skip "bind "
+ p = Com_SkipTokens( args, 1, " " );
+
+ if( p > args )
+ Field_CompleteKeyname( );
+ }
+ else if( argNum >= 3 )
+ {
+ // Skip "bind <key> "
+ p = Com_SkipTokens( args, 2, " " );
+
+ if( p > args )
+ Field_CompleteCommand( p, qtrue, qtrue );
+ }
+}
+
+/*
===================
CL_InitKeyCommands
===================
@@ -1034,7 +1061,9 @@ CL_InitKeyCommands
void CL_InitKeyCommands( void ) {
// register our functions
Cmd_AddCommand ("bind",Key_Bind_f);
+ Cmd_SetCommandCompletionFunc( "bind", Key_CompleteBind );
Cmd_AddCommand ("unbind",Key_Unbind_f);
+ Cmd_SetCommandCompletionFunc( "unbind", Key_CompleteUnbind );
Cmd_AddCommand ("unbindall",Key_Unbindall_f);
Cmd_AddCommand ("bindlist",Key_Bindlist_f);
}
diff --git a/src/client/cl_main.c b/src/client/cl_main.c
index f91c80b2..3551682f 100644
--- a/src/client/cl_main.c
+++ b/src/client/cl_main.c
@@ -868,6 +868,22 @@ static void CL_WalkDemoExt(char *arg, char *name, int *demofile)
/*
====================
+CL_CompleteDemoName
+====================
+*/
+static void CL_CompleteDemoName( char *args, int argNum )
+{
+ if( argNum == 2 )
+ {
+ char demoExt[ 16 ];
+
+ Com_sprintf( demoExt, sizeof( demoExt ), ".dm_%d", PROTOCOL_VERSION );
+ Field_CompleteFilename( "demos", demoExt, qtrue );
+ }
+}
+
+/*
+====================
CL_PlayDemo_f
demo <demoname>
@@ -1524,6 +1540,23 @@ void CL_Connect_f( void ) {
#define MAX_RCON_MESSAGE 1024
/*
+==================
+CL_CompleteRcon
+==================
+*/
+static void CL_CompleteRcon( char *args, int argNum )
+{
+ if( argNum == 2 )
+ {
+ // Skip "rcon "
+ char *p = Com_SkipTokens( args, 1, " " );
+
+ if( p > args )
+ Field_CompleteCommand( p, qtrue, qtrue );
+ }
+}
+
+/*
=====================
CL_Rcon_f
@@ -2126,7 +2159,7 @@ void CL_InitServerInfo( serverInfo_t *server, netadr_t *address ) {
CL_ServersResponsePacket
===================
*/
-void CL_ServersResponsePacket( netadr_t from, msg_t *msg ) {
+void CL_ServersResponsePacket( const netadr_t* from, msg_t *msg, qboolean extended ) {
int i, count, total;
netadr_t addresses[MAX_SERVERSPERPACKET];
int numservers;
@@ -2149,7 +2182,7 @@ void CL_ServersResponsePacket( netadr_t from, msg_t *msg ) {
// advance to initial token
do
{
- if(*buffptr == '\\' || *buffptr == '/')
+ if(*buffptr == '\\' || (extended && *buffptr == '/'))
break;
buffptr++;
@@ -2157,6 +2190,7 @@ void CL_ServersResponsePacket( netadr_t from, msg_t *msg ) {
while (buffptr + 1 < buffend)
{
+ // IPv4 address
if (*buffptr == '\\')
{
buffptr++;
@@ -2169,7 +2203,8 @@ void CL_ServersResponsePacket( netadr_t from, msg_t *msg ) {
addresses[numservers].type = NA_IP;
}
- else
+ // IPv6 address, if it's an extended response
+ else if (extended && *buffptr == '/')
{
buffptr++;
@@ -2180,7 +2215,11 @@ void CL_ServersResponsePacket( netadr_t from, msg_t *msg ) {
addresses[numservers].ip6[i] = *buffptr++;
addresses[numservers].type = NA_IP6;
+ addresses[numservers].scope_id = from->scope_id;
}
+ else
+ // syntax error!
+ break;
// parse out port
addresses[numservers].port = (*buffptr++) << 8;
@@ -2333,9 +2372,15 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
return;
}
- // echo request from server
+ // list of servers sent back by a master server (classic)
if ( !Q_strncmp(c, "getserversResponse", 18) ) {
- CL_ServersResponsePacket( from, msg );
+ CL_ServersResponsePacket( &from, msg, qfalse );
+ return;
+ }
+
+ // list of servers sent back by a master server (extended)
+ if ( !Q_strncmp(c, "getserversExtResponse", 21) ) {
+ CL_ServersResponsePacket( &from, msg, qtrue );
return;
}
@@ -3018,8 +3063,8 @@ void CL_Init( void ) {
cl_guidServerUniq = Cvar_Get ("cl_guidServerUniq", "1", CVAR_ARCHIVE);
- // 0x7e = ~ and 0x60 = `
- cl_consoleKeys = Cvar_Get( "cl_consoleKeys", "0x7e 0x60", CVAR_ARCHIVE);
+ // ~ and `, as keys and characters
+ cl_consoleKeys = Cvar_Get( "cl_consoleKeys", "~ ` 0x7e 0x60", CVAR_ARCHIVE);
// userinfo
Cvar_Get ("name", Sys_GetCurrentUser( ), CVAR_USERINFO | CVAR_ARCHIVE );
@@ -3081,6 +3126,7 @@ void CL_Init( void ) {
Cmd_AddCommand ("disconnect", CL_Disconnect_f);
Cmd_AddCommand ("record", CL_Record_f);
Cmd_AddCommand ("demo", CL_PlayDemo_f);
+ Cmd_SetCommandCompletionFunc( "demo", CL_CompleteDemoName );
Cmd_AddCommand ("cinematic", CL_PlayCinematic_f);
Cmd_AddCommand ("stoprecord", CL_StopRecord_f);
Cmd_AddCommand ("connect", CL_Connect_f);
@@ -3088,6 +3134,7 @@ void CL_Init( void ) {
Cmd_AddCommand ("localservers", CL_LocalServers_f);
Cmd_AddCommand ("globalservers", CL_GlobalServers_f);
Cmd_AddCommand ("rcon", CL_Rcon_f);
+ Cmd_SetCommandCompletionFunc( "rcon", CL_CompleteRcon );
Cmd_AddCommand ("setenv", CL_Setenv_f );
Cmd_AddCommand ("ping", CL_Ping_f );
Cmd_AddCommand ("serverstatus", CL_ServerStatus_f );
@@ -3557,6 +3604,7 @@ void CL_GlobalServers_f( void ) {
netadr_t to;
int count, i, masterNum;
char command[1024], *masteraddress;
+ char *cmdname;
if ((count = Cmd_Argc()) < 3 || (masterNum = atoi(Cmd_Argv(1))) < 0 || masterNum > 4)
{
@@ -3591,7 +3639,17 @@ void CL_GlobalServers_f( void ) {
cls.numglobalservers = -1;
cls.pingUpdateSource = AS_GLOBAL;
- Com_sprintf( command, sizeof(command), "getservers %s", Cmd_Argv(2) );
+ // Use the extended query for IPv6 masters
+ if (to.type == NA_IP6 || to.type == NA_MULTICAST6)
+ {
+ cmdname = "getserversExt " GAMENAME_FOR_MASTER;
+
+ // TODO: test if we only have an IPv6 connection. If it's the case,
+ // request IPv6 servers only by appending " ipv6" to the command
+ }
+ else
+ cmdname = "getservers";
+ Com_sprintf( command, sizeof(command), "%s %s", cmdname, Cmd_Argv(2) );
for (i=3; i < count; i++)
{
diff --git a/src/client/cl_ui.c b/src/client/cl_ui.c
index c0d4e729..49719824 100644
--- a/src/client/cl_ui.c
+++ b/src/client/cl_ui.c
@@ -631,11 +631,9 @@ FloatAsInt
====================
*/
static int FloatAsInt( float f ) {
- int temp;
-
- *(float *)&temp = f;
-
- return temp;
+ floatint_t fi;
+ fi.f = f;
+ return fi.i;
}
/*
diff --git a/src/client/snd_openal.c b/src/client/snd_openal.c
index 5421a7a0..912006d8 100644
--- a/src/client/snd_openal.c
+++ b/src/client/snd_openal.c
@@ -1921,7 +1921,7 @@ void S_AL_SoundInfo( void )
Com_Printf( " Version: %s\n", qalGetString( AL_VERSION ) );
Com_Printf( " Renderer: %s\n", qalGetString( AL_RENDERER ) );
Com_Printf( " AL Extensions: %s\n", qalGetString( AL_EXTENSIONS ) );
- Com_Printf( " ALC Extensions: %s\n", qalcGetString( NULL, ALC_EXTENSIONS ) );
+ Com_Printf( " ALC Extensions: %s\n", qalcGetString( alDevice, ALC_EXTENSIONS ) );
if(qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
{
Com_Printf(" Device: %s\n", qalcGetString(alDevice, ALC_DEVICE_SPECIFIER));
diff --git a/src/libspeex/config.h b/src/libspeex/config.h
new file mode 100644
index 00000000..abd35f09
--- /dev/null
+++ b/src/libspeex/config.h
@@ -0,0 +1,20 @@
+// Microsoft version of 'inline'
+#define inline __inline
+
+// Visual Studio support alloca(), but it always align variables to 16-bit
+// boundary, while SSE need 128-bit alignment. So we disable alloca() when
+// SSE is enabled.
+#ifndef _USE_SSE
+# define USE_ALLOCA
+#endif
+
+/* Default to floating point */
+#ifndef FIXED_POINT
+# define FLOATING_POINT
+# define USE_SMALLFT
+#else
+# define USE_KISS_FFT
+#endif
+
+/* We don't support visibility on Win32 */
+#define EXPORT
diff --git a/src/qcommon/cm_load.c b/src/qcommon/cm_load.c
index 06a037aa..6291f4d7 100644
--- a/src/qcommon/cm_load.c
+++ b/src/qcommon/cm_load.c
@@ -714,7 +714,10 @@ Loads in the map and all submodels
==================
*/
void CM_LoadMap( const char *name, qboolean clientload, int *checksum ) {
- int *buf;
+ union {
+ int *i;
+ void *v;
+ } buf;
int i;
dheader_t header;
int length;
@@ -753,19 +756,19 @@ void CM_LoadMap( const char *name, qboolean clientload, int *checksum ) {
// load the file
//
#ifndef BSPC
- length = FS_ReadFile( name, (void **)&buf );
+ length = FS_ReadFile( name, &buf.v );
#else
- length = LoadQuakeFile((quakefile_t *) name, (void **)&buf);
+ length = LoadQuakeFile((quakefile_t *) name, &buf.v);
#endif
- if ( !buf ) {
+ if ( !buf.i ) {
Com_Error (ERR_DROP, "Couldn't load %s", name);
}
- last_checksum = LittleLong (Com_BlockChecksum (buf, length));
+ last_checksum = LittleLong (Com_BlockChecksum (buf.i, length));
*checksum = last_checksum;
- header = *(dheader_t *)buf;
+ header = *(dheader_t *)buf.i;
for (i=0 ; i<sizeof(dheader_t)/4 ; i++) {
((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);
}
@@ -775,7 +778,7 @@ void CM_LoadMap( const char *name, qboolean clientload, int *checksum ) {
, name, header.version, BSP_VERSION );
}
- cmod_base = (byte *)buf;
+ cmod_base = (byte *)buf.i;
// load into heap
CMod_LoadShaders( &header.lumps[LUMP_SHADERS] );
@@ -794,7 +797,7 @@ void CM_LoadMap( const char *name, qboolean clientload, int *checksum ) {
CMod_CreateBrushSideWindings( );
// we are NOT freeing the file, because it is cached for the ref
- FS_FreeFile (buf);
+ FS_FreeFile (buf.v);
CM_InitBoxHull ();
diff --git a/src/qcommon/cm_trace.c b/src/qcommon/cm_trace.c
index 3be22d43..c48ee3b3 100644
--- a/src/qcommon/cm_trace.c
+++ b/src/qcommon/cm_trace.c
@@ -132,10 +132,7 @@ SquareRootFloat
================
*/
float SquareRootFloat(float number) {
- union {
- float f;
- int i;
- } t;
+ floatint_t t;
float x, y;
const float f = 1.5F;
diff --git a/src/qcommon/cmd.c b/src/qcommon/cmd.c
index 97687467..e04f314c 100644
--- a/src/qcommon/cmd.c
+++ b/src/qcommon/cmd.c
@@ -240,7 +240,10 @@ Cmd_Exec_f
===============
*/
void Cmd_Exec_f( void ) {
- char *f;
+ union {
+ char *c;
+ void *v;
+ } f;
int len;
char filename[MAX_QPATH];
@@ -250,17 +253,17 @@ void Cmd_Exec_f( void ) {
}
Q_strncpyz( filename, Cmd_Argv(1), sizeof( filename ) );
- COM_DefaultExtension( filename, sizeof( filename ), ".cfg" );
- len = FS_ReadFile( filename, (void **)&f);
- if (!f) {
+ COM_DefaultExtension( filename, sizeof( filename ), ".cfg" );
+ len = FS_ReadFile( filename, &f.v);
+ if (!f.c) {
Com_Printf ("couldn't exec %s\n",Cmd_Argv(1));
return;
}
Com_Printf ("execing %s\n",Cmd_Argv(1));
- Cbuf_InsertText (f);
+ Cbuf_InsertText (f.c);
- FS_FreeFile (f);
+ FS_FreeFile (f.v);
}
@@ -314,6 +317,7 @@ typedef struct cmd_function_s
struct cmd_function_s *next;
char *name;
xcommand_t function;
+ completionFunc_t complete;
} cmd_function_t;
@@ -468,6 +472,22 @@ char *Cmd_Cmd(void)
}
/*
+ Replace command separators with space to prevent interpretation
+ This is a hack to protect buggy qvms
+ https://bugzilla.icculus.org/show_bug.cgi?id=3593
+*/
+void Cmd_Args_Sanitize( void ) {
+ int i;
+ for ( i = 1 ; i < cmd.argc ; i++ ) {
+ char* c = cmd.argv[i];
+ while ((c = strpbrk(c, "\n\r;"))) {
+ *c = ' ';
+ ++c;
+ }
+ }
+}
+
+/*
============
Cmd_TokenizeString
@@ -623,12 +643,28 @@ void Cmd_AddCommand( const char *cmd_name, xcommand_t function ) {
cmd = S_Malloc (sizeof(cmd_function_t));
cmd->name = CopyString( cmd_name );
cmd->function = function;
+ cmd->complete = NULL;
cmd->next = cmd_functions;
cmd_functions = cmd;
}
/*
============
+Cmd_SetCommandCompletionFunc
+============
+*/
+void Cmd_SetCommandCompletionFunc( const char *command, completionFunc_t complete ) {
+ cmd_function_t *cmd;
+
+ for( cmd = cmd_functions; cmd; cmd = cmd->next ) {
+ if( !Q_stricmp( command, cmd->name ) ) {
+ cmd->complete = complete;
+ }
+ }
+}
+
+/*
+============
Cmd_RemoveCommand
============
*/
@@ -668,6 +704,21 @@ void Cmd_CommandCompletion( void(*callback)(const char *s) ) {
}
}
+/*
+============
+Cmd_CompleteArgument
+============
+*/
+void Cmd_CompleteArgument( const char *command, char *args, int argNum ) {
+ cmd_function_t *cmd;
+
+ for( cmd = cmd_functions; cmd; cmd = cmd->next ) {
+ if( !Q_stricmp( command, cmd->name ) && cmd->complete ) {
+ cmd->complete( args, argNum );
+ }
+ }
+}
+
/*
============
@@ -759,6 +810,17 @@ void Cmd_List_f (void)
}
/*
+==================
+Cmd_CompleteCfgName
+==================
+*/
+void Cmd_CompleteCfgName( char *args, int argNum ) {
+ if( argNum == 2 ) {
+ Field_CompleteFilename( "", "cfg", qfalse );
+ }
+}
+
+/*
============
Cmd_Init
============
@@ -766,7 +828,9 @@ Cmd_Init
void Cmd_Init (void) {
Cmd_AddCommand ("cmdlist",Cmd_List_f);
Cmd_AddCommand ("exec",Cmd_Exec_f);
+ Cmd_SetCommandCompletionFunc( "exec", Cmd_CompleteCfgName );
Cmd_AddCommand ("vstr",Cmd_Vstr_f);
+ Cmd_SetCommandCompletionFunc( "vstr", Cvar_CompleteCvarName );
Cmd_AddCommand ("echo",Cmd_Echo_f);
Cmd_AddCommand ("wait", Cmd_Wait_f);
}
diff --git a/src/qcommon/common.c b/src/qcommon/common.c
index 7c98d45e..ef9ee76a 100644
--- a/src/qcommon/common.c
+++ b/src/qcommon/common.c
@@ -2495,6 +2495,7 @@ void Com_Init( char *commandLine ) {
Cmd_AddCommand ("quit", Com_Quit_f);
Cmd_AddCommand ("changeVectors", MSG_ReportChangeVectors_f );
Cmd_AddCommand ("writeconfig", Com_WriteConfig_f );
+ Cmd_SetCommandCompletionFunc( "writeconfig", Cmd_CompleteCfgName );
s = va("%s %s %s", Q3_VERSION, PLATFORM_STRING, __DATE__ );
com_version = Cvar_Get ("version", s, CVAR_ROM | CVAR_SERVERINFO );
@@ -2993,7 +2994,7 @@ static qboolean Field_Complete( void )
int completionOffset;
if( matchCount == 0 )
- return qfalse;
+ return qtrue;
completionOffset = strlen( completionField->buffer ) - strlen( completionString );
@@ -3020,7 +3021,7 @@ static qboolean Field_Complete( void )
Field_CompleteKeyname
===============
*/
-static void Field_CompleteKeyname( void )
+void Field_CompleteKeyname( void )
{
matchCount = 0;
shortestMatch[ 0 ] = 0;
@@ -3037,7 +3038,7 @@ static void Field_CompleteKeyname( void )
Field_CompleteFilename
===============
*/
-static void Field_CompleteFilename( const char *dir,
+void Field_CompleteFilename( const char *dir,
const char *ext, qboolean stripExt )
{
matchCount = 0;
@@ -3054,11 +3055,10 @@ static void Field_CompleteFilename( const char *dir,
Field_CompleteCommand
===============
*/
-static void Field_CompleteCommand( char *cmd,
+void Field_CompleteCommand( char *cmd,
qboolean doCommands, qboolean doCvars )
{
int completionArgument = 0;
- char *p;
// Skip leading whitespace and quotes
cmd = Com_SkipCharset( cmd, " \"" );
@@ -3100,6 +3100,7 @@ static void Field_CompleteCommand( char *cmd,
if( completionArgument > 1 )
{
const char *baseCmd = Cmd_Argv( 0 );
+ char *p;
#ifndef DEDICATED
// This should always be true
@@ -3108,92 +3109,9 @@ static void Field_CompleteCommand( char *cmd,
#endif
if( ( p = Field_FindFirstSeparator( cmd ) ) )
- {
- // Compound command
- Field_CompleteCommand( p + 1, qtrue, qtrue );
- }
+ Field_CompleteCommand( p + 1, qtrue, qtrue ); // Compound command
else
- {
- // FIXME: all this junk should really be associated with the respective
- // commands, instead of being hard coded here
- if( ( !Q_stricmp( baseCmd, "map" ) ||
- !Q_stricmp( baseCmd, "devmap" ) ||
- !Q_stricmp( baseCmd, "spmap" ) ||
- !Q_stricmp( baseCmd, "spdevmap" ) ) &&
- completionArgument == 2 )
- {
- Field_CompleteFilename( "maps", "bsp", qtrue );
- }
- else if( ( !Q_stricmp( baseCmd, "exec" ) ||
- !Q_stricmp( baseCmd, "writeconfig" ) ) &&
- completionArgument == 2 )
- {
- Field_CompleteFilename( "", "cfg", qfalse );
- }
- else if( !Q_stricmp( baseCmd, "condump" ) &&
- completionArgument == 2 )
- {
- Field_CompleteFilename( "", "txt", qfalse );
- }
- else if( ( !Q_stricmp( baseCmd, "toggle" ) ||
- !Q_stricmp( baseCmd, "vstr" ) ||
- !Q_stricmp( baseCmd, "set" ) ||
- !Q_stricmp( baseCmd, "seta" ) ||
- !Q_stricmp( baseCmd, "setu" ) ||
- !Q_stricmp( baseCmd, "sets" ) ) &&
- completionArgument == 2 )
- {
- // Skip "<cmd> "
- p = Com_SkipTokens( cmd, 1, " " );
-
- if( p > cmd )
- Field_CompleteCommand( p, qfalse, qtrue );
- }
-#ifndef DEDICATED
- else if( !Q_stricmp( baseCmd, "demo" ) && completionArgument == 2 )
- {
- char demoExt[ 16 ];
-
- Com_sprintf( demoExt, sizeof( demoExt ), ".dm_%d", PROTOCOL_VERSION );
- Field_CompleteFilename( "demos", demoExt, qtrue );
- }
- else if( !Q_stricmp( baseCmd, "rcon" ) && completionArgument == 2 )
- {
- // Skip "rcon "
- p = Com_SkipTokens( cmd, 1, " " );
-
- if( p > cmd )
- Field_CompleteCommand( p, qtrue, qtrue );
- }
- else if( !Q_stricmp( baseCmd, "bind" ) )
- {
- if( completionArgument == 2 )
- {
- // Skip "bind "
- p = Com_SkipTokens( cmd, 1, " " );
-
- if( p > cmd )
- Field_CompleteKeyname( );
- }
- else if( completionArgument >= 3 )
- {
- // Skip "bind <key> "
- p = Com_SkipTokens( cmd, 2, " " );
-
- if( p > cmd )
- Field_CompleteCommand( p, qtrue, qtrue );
- }
- }
- else if( !Q_stricmp( baseCmd, "unbind" ) && completionArgument == 2 )
- {
- // Skip "unbind "
- p = Com_SkipTokens( cmd, 1, " " );
-
- if( p > cmd )
- Field_CompleteKeyname( );
- }
-#endif
- }
+ Cmd_CompleteArgument( baseCmd, cmd, completionArgument );
}
else
{
diff --git a/src/qcommon/cvar.c b/src/qcommon/cvar.c
index cb9f2634..c26ba543 100644
--- a/src/qcommon/cvar.c
+++ b/src/qcommon/cvar.c
@@ -1053,6 +1053,22 @@ void Cvar_Update( vmCvar_t *vmCvar ) {
vmCvar->integer = cv->integer;
}
+/*
+==================
+Cvar_CompleteCvarName
+==================
+*/
+void Cvar_CompleteCvarName( char *args, int argNum )
+{
+ if( argNum == 2 )
+ {
+ // Skip "<cmd> "
+ char *p = Com_SkipTokens( args, 1, " " );
+
+ if( p > args )
+ Field_CompleteCommand( p, qfalse, qtrue );
+ }
+}
/*
============
@@ -1066,11 +1082,17 @@ void Cvar_Init (void) {
Cmd_AddCommand ("print", Cvar_Print_f);
Cmd_AddCommand ("toggle", Cvar_Toggle_f);
+ Cmd_SetCommandCompletionFunc( "toggle", Cvar_CompleteCvarName );
Cmd_AddCommand ("set", Cvar_Set_f);
+ Cmd_SetCommandCompletionFunc( "set", Cvar_CompleteCvarName );
Cmd_AddCommand ("sets", Cvar_Set_f);
+ Cmd_SetCommandCompletionFunc( "sets", Cvar_CompleteCvarName );
Cmd_AddCommand ("setu", Cvar_Set_f);
+ Cmd_SetCommandCompletionFunc( "setu", Cvar_CompleteCvarName );
Cmd_AddCommand ("seta", Cvar_Set_f);
+ Cmd_SetCommandCompletionFunc( "seta", Cvar_CompleteCvarName );
Cmd_AddCommand ("reset", Cvar_Reset_f);
+ Cmd_SetCommandCompletionFunc( "reset", Cvar_CompleteCvarName );
Cmd_AddCommand ("cvarlist", Cvar_List_f);
Cmd_AddCommand ("cvar_restart", Cvar_Restart_f);
}
diff --git a/src/qcommon/msg.c b/src/qcommon/msg.c
index 8be19aca..34434d15 100644
--- a/src/qcommon/msg.c
+++ b/src/qcommon/msg.c
@@ -292,13 +292,9 @@ void MSG_WriteLong( msg_t *sb, int c ) {
}
void MSG_WriteFloat( msg_t *sb, float f ) {
- union {
- float f;
- int l;
- } dat;
-
+ floatint_t dat;
dat.f = f;
- MSG_WriteBits( sb, dat.l, 32 );
+ MSG_WriteBits( sb, dat.i, 32 );
}
void MSG_WriteString( msg_t *sb, const char *s ) {
@@ -424,13 +420,9 @@ int MSG_ReadLong( msg_t *msg ) {
}
float MSG_ReadFloat( msg_t *msg ) {
- union {
- byte b[4];
- float f;
- int l;
- } dat;
+ floatint_t dat;
- dat.l = MSG_ReadBits( msg, 32 );
+ dat.i = MSG_ReadBits( msg, 32 );
if ( msg->readcount > msg->cursize ) {
dat.f = -1;
}
@@ -552,20 +544,22 @@ int MSG_ReadDelta( msg_t *msg, int oldV, int bits ) {
}
void MSG_WriteDeltaFloat( msg_t *msg, float oldV, float newV ) {
+ floatint_t fi;
if ( oldV == newV ) {
MSG_WriteBits( msg, 0, 1 );
return;
}
+ fi.f = newV;
MSG_WriteBits( msg, 1, 1 );
- MSG_WriteBits( msg, *(int *)&newV, 32 );
+ MSG_WriteBits( msg, fi.i, 32 );
}
float MSG_ReadDeltaFloat( msg_t *msg, float oldV ) {
if ( MSG_ReadBits( msg, 1 ) ) {
- float newV;
+ floatint_t fi;
- *(int *)&newV = MSG_ReadBits( msg, 32 );
- return newV;
+ fi.i = MSG_ReadBits( msg, 32 );
+ return fi.f;
}
return oldV;
}
@@ -606,20 +600,22 @@ int MSG_ReadDeltaKey( msg_t *msg, int key, int oldV, int bits ) {
}
void MSG_WriteDeltaKeyFloat( msg_t *msg, int key, float oldV, float newV ) {
+ floatint_t fi;
if ( oldV == newV ) {
MSG_WriteBits( msg, 0, 1 );
return;
}
+ fi.f = newV;
MSG_WriteBits( msg, 1, 1 );
- MSG_WriteBits( msg, (*(int *)&newV) ^ key, 32 );
+ MSG_WriteBits( msg, fi.i ^ key, 32 );
}
float MSG_ReadDeltaKeyFloat( msg_t *msg, int key, float oldV ) {
if ( MSG_ReadBits( msg, 1 ) ) {
- float newV;
+ floatint_t fi;
- *(int *)&newV = MSG_ReadBits( msg, 32 ) ^ key;
- return newV;
+ fi.i = MSG_ReadBits( msg, 32 ) ^ key;
+ return fi.f;
}
return oldV;
}
diff --git a/src/qcommon/net_ip.c b/src/qcommon/net_ip.c
index baf70a17..e7a52996 100644
--- a/src/qcommon/net_ip.c
+++ b/src/qcommon/net_ip.c
@@ -227,6 +227,7 @@ static void NetadrToSockadr( netadr_t *a, struct sockaddr *s ) {
((struct sockaddr_in6 *)s)->sin6_family = AF_INET6;
((struct sockaddr_in6 *)s)->sin6_addr = * ((struct in6_addr *) &a->ip6);
((struct sockaddr_in6 *)s)->sin6_port = a->port;
+ ((struct sockaddr_in6 *)s)->sin6_scope_id = a->scope_id;
}
else if(a->type == NA_MULTICAST6)
{
@@ -248,6 +249,7 @@ static void SockadrToNetadr( struct sockaddr *s, netadr_t *a ) {
a->type = NA_IP6;
memcpy(a->ip6, &((struct sockaddr_in6 *)s)->sin6_addr, sizeof(a->ip6));
a->port = ((struct sockaddr_in6 *)s)->sin6_port;
+ a->scope_id = ((struct sockaddr_in6 *)s)->sin6_scope_id;
}
}
@@ -279,14 +281,11 @@ static qboolean Sys_StringToSockaddr(const char *s, struct sockaddr *sadr, int s
memset(sadr, '\0', sizeof(*sadr));
memset(&hints, '\0', sizeof(hints));
- // workaround for buggy MacOSX getaddrinfo implementation that doesn't handle AF_UNSPEC in hints correctly.
- if(family == AF_UNSPEC)
- hintsp = NULL;
- else
- {
- hintsp = &hints;
- hintsp->ai_family = family;
- }
+ hintsp = &hints;
+ hintsp->ai_family = family;
+ hintsp->ai_socktype = SOCK_DGRAM;
+ // FIXME: we should set "->ai_flags" to AI_PASSIVE if we intend
+ // to use this structure for a bind() - instead of a sendto()
retval = getaddrinfo(s, NULL, hintsp, &res);
@@ -340,8 +339,15 @@ static qboolean Sys_StringToSockaddr(const char *s, struct sockaddr *sadr, int s
Sys_SockaddrToString
=============
*/
-static void Sys_SockaddrToString(char *dest, int destlen, struct sockaddr *input, int inputlen)
+static void Sys_SockaddrToString(char *dest, int destlen, struct sockaddr *input)
{
+ socklen_t inputlen;
+
+ if (input->sa_family == AF_INET6)
+ inputlen = sizeof(struct sockaddr_in6);
+ else
+ inputlen = sizeof(struct sockaddr_in);
+
getnameinfo(input, inputlen, dest, destlen, NULL, 0, NI_NUMERICHOST);
}
@@ -399,7 +405,7 @@ qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
if (a.type == NA_IP6)
{
- if(!memcmp(a.ip6, b.ip6, sizeof(a.ip6)))
+ if(!memcmp(a.ip6, b.ip6, sizeof(a.ip6)) && a.scope_id == b.scope_id)
return qtrue;
return qfalse;
@@ -423,7 +429,7 @@ const char *NET_AdrToString (netadr_t a)
memset(&sadr, 0, sizeof(sadr));
NetadrToSockadr(&a, (struct sockaddr *) &sadr);
- Sys_SockaddrToString(s, sizeof(s), (struct sockaddr *) &sadr, sizeof(sadr));
+ Sys_SockaddrToString(s, sizeof(s), (struct sockaddr *) &sadr);
}
return s;
@@ -718,6 +724,8 @@ qboolean Sys_IsLANAddress( netadr_t adr ) {
}
else
{
+ // TODO? should we check the scope_id here?
+
compareip = (byte *) &((struct sockaddr_in6 *) &localIP[index].addr)->sin6_addr;
comparemask = (byte *) &((struct sockaddr_in6 *) &localIP[index].netmask)->sin6_addr;
compareadr = adr.ip6;
@@ -755,7 +763,7 @@ void Sys_ShowIP(void) {
for(i = 0; i < numIP; i++)
{
- Sys_SockaddrToString(addrbuf, sizeof(addrbuf), (struct sockaddr *) &localIP[i].addr, sizeof((*localIP).addr));
+ Sys_SockaddrToString(addrbuf, sizeof(addrbuf), (struct sockaddr *) &localIP[i].addr);
if(localIP[i].type == NA_IP)
Com_Printf( "IP: %s\n", addrbuf);
@@ -776,7 +784,7 @@ NET_IPSocket
int NET_IPSocket( char *net_interface, int port, int *err ) {
SOCKET newsocket;
struct sockaddr_in address;
- qboolean _true = qtrue;
+ u_long _true = 1;
int i = 1;
*err = 0;
@@ -794,7 +802,7 @@ int NET_IPSocket( char *net_interface, int port, int *err ) {
return newsocket;
}
// make it non-blocking
- if( ioctlsocket( newsocket, FIONBIO, (u_long *)&_true ) == SOCKET_ERROR ) {
+ if( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) {
Com_Printf( "WARNING: NET_IPSocket: ioctl FIONBIO: %s\n", NET_ErrorString() );
*err = socketError;
closesocket(newsocket);
@@ -847,7 +855,7 @@ NET_IP6Socket
int NET_IP6Socket( char *net_interface, int port, struct sockaddr_in6 *bindto, int *err ) {
SOCKET newsocket;
struct sockaddr_in6 address;
- qboolean _true = qtrue;
+ u_long _true = 1;
*err = 0;
@@ -869,7 +877,7 @@ int NET_IP6Socket( char *net_interface, int port, struct sockaddr_in6 *bindto, i
}
// make it non-blocking
- if( ioctlsocket( newsocket, FIONBIO, (u_long *)&_true ) == SOCKET_ERROR ) {
+ if( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) {
Com_Printf( "WARNING: NET_IP6Socket: ioctl FIONBIO: %s\n", NET_ErrorString() );
*err = socketError;
closesocket(newsocket);
diff --git a/src/qcommon/parse.c b/src/qcommon/parse.c
index 2156f75b..c3b6e0ce 100644
--- a/src/qcommon/parse.c
+++ b/src/qcommon/parse.c
@@ -2546,7 +2546,7 @@ static int Parse_Directive_include(source_t *source)
break;
}
if (token.type == TT_PUNCTUATION && *token.string == '>') break;
- strncat(path, token.string, MAX_QPATH);
+ strncat(path, token.string, MAX_QPATH - 1);
}
if (*token.string != '>')
{
diff --git a/src/qcommon/q_math.c b/src/qcommon/q_math.c
index a3a7b191..e7924073 100644
--- a/src/qcommon/q_math.c
+++ b/src/qcommon/q_math.c
@@ -550,10 +550,7 @@ void VectorRotate( vec3_t in, vec3_t matrix[3], vec3_t out )
*/
float Q_rsqrt( float number )
{
- union {
- float f;
- int i;
- } t;
+ floatint_t t;
float x2, y;
const float threehalfs = 1.5F;
@@ -568,9 +565,10 @@ float Q_rsqrt( float number )
}
float Q_fabs( float f ) {
- int tmp = * ( int * ) &f;
- tmp &= 0x7FFFFFFF;
- return * ( float * ) &tmp;
+ floatint_t fi;
+ fi.f = f;
+ fi.i &= 0x7FFFFFFF;
+ return fi.f;
}
#endif
@@ -1587,15 +1585,11 @@ Don't pass doubles to this
*/
int Q_isnan( float x )
{
- union
- {
- float f;
- unsigned int i;
- } t;
+ floatint_t fi;
- t.f = x;
- t.i &= 0x7FFFFFFF;
- t.i = 0x7F800000 - t.i;
+ fi.f = x;
+ fi.ui &= 0x7FFFFFFF;
+ fi.ui = 0x7F800000 - fi.ui;
- return (int)( (unsigned int)t.i >> 31 );
+ return (int)( (unsigned int)fi.ui >> 31 );
}
diff --git a/src/qcommon/q_shared.c b/src/qcommon/q_shared.c
index 81248644..fc259219 100644
--- a/src/qcommon/q_shared.c
+++ b/src/qcommon/q_shared.c
@@ -206,16 +206,11 @@ qint64 Long64NoSwap (qint64 ll)
return ll;
}
-typedef union {
- float f;
- unsigned int i;
-} _FloatByteUnion;
-
float FloatSwap (const float *f) {
- _FloatByteUnion out;
+ floatint_t out;
out.f = *f;
- out.i = LongSwap(out.i);
+ out.ui = LongSwap(out.ui);
return out.f;
}
@@ -362,48 +357,48 @@ int COM_Compress( char *data_p ) {
in++;
if ( *in )
in += 2;
- // record when we hit a newline
- } else if ( c == '\n' || c == '\r' ) {
- newline = qtrue;
- in++;
- // record when we hit whitespace
- } else if ( c == ' ' || c == '\t') {
- whitespace = qtrue;
- in++;
- // an actual token
+ // record when we hit a newline
+ } else if ( c == '\n' || c == '\r' ) {
+ newline = qtrue;
+ in++;
+ // record when we hit whitespace
+ } else if ( c == ' ' || c == '\t') {
+ whitespace = qtrue;
+ in++;
+ // an actual token
} else {
- // if we have a pending newline, emit it (and it counts as whitespace)
- if (newline) {
- *out++ = '\n';
- newline = qfalse;
- whitespace = qfalse;
- } if (whitespace) {
- *out++ = ' ';
- whitespace = qfalse;
- }
-
- // copy quoted strings unmolested
- if (c == '"') {
- *out++ = c;
- in++;
- while (1) {
- c = *in;
- if (c && c != '"') {
- *out++ = c;
- in++;
- } else {
- break;
- }
- }
- if (c == '"') {
- *out++ = c;
- in++;
- }
- } else {
- *out = c;
- out++;
- in++;
- }
+ // if we have a pending newline, emit it (and it counts as whitespace)
+ if (newline) {
+ *out++ = '\n';
+ newline = qfalse;
+ whitespace = qfalse;
+ } if (whitespace) {
+ *out++ = ' ';
+ whitespace = qfalse;
+ }
+
+ // copy quoted strings unmolested
+ if (c == '"') {
+ *out++ = c;
+ in++;
+ while (1) {
+ c = *in;
+ if (c && c != '"') {
+ *out++ = c;
+ in++;
+ } else {
+ break;
+ }
+ }
+ if (c == '"') {
+ *out++ = c;
+ in++;
+ }
+ } else {
+ *out = c;
+ out++;
+ in++;
+ }
}
}
}
@@ -513,62 +508,6 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
return com_token;
}
-
-#if 0
-// no longer used
-/*
-===============
-COM_ParseInfos
-===============
-*/
-int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] ) {
- char *token;
- int count;
- char key[MAX_TOKEN_CHARS];
-
- count = 0;
-
- while ( 1 ) {
- token = COM_Parse( &buf );
- if ( !token[0] ) {
- break;
- }
- if ( strcmp( token, "{" ) ) {
- Com_Printf( "Missing { in info file\n" );
- break;
- }
-
- if ( count == max ) {
- Com_Printf( "Max infos exceeded\n" );
- break;
- }
-
- infos[count][0] = 0;
- while ( 1 ) {
- token = COM_ParseExt( &buf, qtrue );
- if ( !token[0] ) {
- Com_Printf( "Unexpected end of info file\n" );
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
- Q_strncpyz( key, token, sizeof( key ) );
-
- token = COM_ParseExt( &buf, qfalse );
- if ( !token[0] ) {
- strcpy( token, "<NULL>" );
- }
- Info_SetValueForKey( infos[count], key, token );
- }
- count++;
- }
-
- return count;
-}
-#endif
-
-
/*
==================
COM_MatchToken
@@ -670,6 +609,44 @@ void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m) {
COM_MatchToken( buf_p, ")" );
}
+/*
+===================
+Com_HexStrToInt
+===================
+*/
+int Com_HexStrToInt( const char *str )
+{
+ if ( !str || !str[ 0 ] )
+ return -1;
+
+ // check for hex code
+ if( str[ 0 ] == '0' && str[ 1 ] == 'x' )
+ {
+ int i, n = 0;
+
+ for( i = 2; i < strlen( str ); i++ )
+ {
+ char digit;
+
+ n *= 16;
+
+ digit = tolower( str[ i ] );
+
+ if( digit >= '0' && digit <= '9' )
+ digit -= '0';
+ else if( digit >= 'a' && digit <= 'f' )
+ digit = digit - 'a' + 10;
+ else
+ return -1;
+
+ n += digit;
+ }
+
+ return n;
+ }
+
+ return -1;
+}
/*
============================================================================
@@ -734,11 +711,12 @@ qboolean Q_isanumber( const char *s )
return qfalse;
#else
char *p;
+ double d;
if( *s == '\0' )
return qfalse;
- strtod( s, &p );
+ d = strtod( s, &p );
return *p == '\0';
#endif
diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h
index 6eb636d6..c24fe292 100644
--- a/src/qcommon/q_shared.h
+++ b/src/qcommon/q_shared.h
@@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// q_shared.h -- included first by ALL program modules.
// A user mod should never modify this file
-#define PRODUCT_NAME "tremulous"
+#define PRODUCT_NAME "tremulous"
#ifdef _MSC_VER
# define PRODUCT_VERSION "1.1.0"
@@ -37,6 +37,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define CLIENT_WINDOW_MIN_TITLE "Tremulous"
#define Q3_VERSION PRODUCT_NAME " " PRODUCT_VERSION
+#define GAMENAME_FOR_MASTER "Tremulous"
+
#define MAX_TEAMNAME 32
#ifdef _MSC_VER
@@ -142,6 +144,12 @@ typedef unsigned char byte;
typedef enum {qfalse, qtrue} qboolean;
+typedef union {
+ float f;
+ int i;
+ unsigned int ui;
+} floatint_t;
+
typedef int qhandle_t;
typedef int sfxHandle_t;
typedef int fileHandle_t;
@@ -704,6 +712,7 @@ void SkipRestOfLine ( char **data );
void Parse1DMatrix (char **buf_p, int x, float *m);
void Parse2DMatrix (char **buf_p, int y, int x, float *m);
void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m);
+int Com_HexStrToInt( const char *str );
void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h
index d6f7ea03..e4234f54 100644
--- a/src/qcommon/qcommon.h
+++ b/src/qcommon/qcommon.h
@@ -153,6 +153,7 @@ typedef struct {
byte ip6[16];
unsigned short port;
+ unsigned long scope_id; // Needed for IPv6 link-local addresses
} netadr_t;
void NET_Init( void );
@@ -341,12 +342,9 @@ void *VM_ExplicitArgPtr( vm_t *vm, intptr_t intValue );
#define VMA(x) VM_ArgPtr(args[x])
static ID_INLINE float _vmf(intptr_t x)
{
- union {
- intptr_t l;
- float f;
- } t;
- t.l = x;
- return t.f;
+ floatint_t fi;
+ fi.i = (int) x;
+ return fi.f;
}
#define VMF(x) _vmf(args[x])
@@ -406,8 +404,14 @@ void Cmd_AddCommand( const char *cmd_name, xcommand_t function );
void Cmd_RemoveCommand( const char *cmd_name );
+typedef void (*completionFunc_t)( char *args, int argNum );
+
void Cmd_CommandCompletion( void(*callback)(const char *s) );
// callback with each valid string
+void Cmd_SetCommandCompletionFunc( const char *command,
+ completionFunc_t complete );
+void Cmd_CompleteArgument( const char *command, char *args, int argNum );
+void Cmd_CompleteCfgName( char *args, int argNum );
int Cmd_Argc (void);
char *Cmd_Argv (int arg);
@@ -417,6 +421,7 @@ char *Cmd_ArgsFrom( int arg );
void Cmd_ArgsBuffer( char *buffer, int bufferLength );
void Cmd_LiteralArgsBuffer( char *buffer, int bufferLength );
char *Cmd_Cmd (void);
+void Cmd_Args_Sanitize( void );
// The functions that execute commands get their parameters with these
// functions. Cmd_Argv () will return an empty string, not a NULL
// if arg > argc, so string operations are allways safe.
@@ -521,6 +526,8 @@ void Cvar_CheckRange( cvar_t *cv, float minVal, float maxVal, qboolean shouldBeI
void Cvar_Restart_f( void );
+void Cvar_CompleteCvarName( char *args, int argNum );
+
extern int cvar_modifiedFlags;
// whenever a cvar is modifed, its flags will be OR'd into this, so
// a single check can determine if any CVAR_USERINFO, CVAR_SERVERINFO,
@@ -702,6 +709,11 @@ typedef struct {
void Field_Clear( field_t *edit );
void Field_AutoComplete( field_t *edit );
+void Field_CompleteKeyname( void );
+void Field_CompleteFilename( const char *dir,
+ const char *ext, qboolean stripExt );
+void Field_CompleteCommand( char *cmd,
+ qboolean doCommands, qboolean doCvars );
/*
==============================================================
diff --git a/src/qcommon/unzip.c b/src/qcommon/unzip.c
index 90f5354d..7669aa95 100644
--- a/src/qcommon/unzip.c
+++ b/src/qcommon/unzip.c
@@ -1109,7 +1109,8 @@ static int unzlocal_getShort (FILE* fin, uLong *pX)
{
short v;
- fread( &v, sizeof(v), 1, fin );
+ size_t size;
+ size = fread( &v, sizeof(v), 1, fin );
*pX = LittleShort( v);
return UNZ_OK;
@@ -1138,7 +1139,8 @@ static int unzlocal_getLong (FILE *fin, uLong *pX)
{
int v;
- fread( &v, sizeof(v), 1, fin );
+ size_t size;
+ size = fread( &v, sizeof(v), 1, fin );
*pX = LittleLong( v);
return UNZ_OK;
diff --git a/src/qcommon/vm.c b/src/qcommon/vm.c
index 7a38b8db..c1a829a6 100644
--- a/src/qcommon/vm.c
+++ b/src/qcommon/vm.c
@@ -219,7 +219,11 @@ VM_LoadSymbols
*/
void VM_LoadSymbols( vm_t *vm ) {
int len;
- char *mapfile, *text_p, *token;
+ union {
+ char *c;
+ void *v;
+ } mapfile;
+ char *text_p, *token;
char name[MAX_QPATH];
char symbols[MAX_QPATH];
vmSymbol_t **prev, *sym;
@@ -236,8 +240,8 @@ void VM_LoadSymbols( vm_t *vm ) {
COM_StripExtension(vm->name, name, sizeof(name));
Com_sprintf( symbols, sizeof( symbols ), "vm/%s.map", name );
- len = FS_ReadFile( symbols, (void **)&mapfile );
- if ( !mapfile ) {
+ len = FS_ReadFile( symbols, &mapfile.v );
+ if ( !mapfile.c ) {
Com_Printf( "Couldn't load symbol file: %s\n", symbols );
return;
}
@@ -245,7 +249,7 @@ void VM_LoadSymbols( vm_t *vm ) {
numInstructions = vm->instructionPointersLength >> 2;
// parse the symbols
- text_p = mapfile;
+ text_p = mapfile.c;
prev = &vm->symbols;
count = 0;
@@ -292,7 +296,7 @@ void VM_LoadSymbols( vm_t *vm ) {
vm->numSymbols = count;
Com_Printf( "%i symbols parsed from %s\n", count, symbols );
- FS_FreeFile( mapfile );
+ FS_FreeFile( mapfile.v );
}
/*
@@ -365,47 +369,50 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
int dataLength;
int i;
char filename[MAX_QPATH];
- vmHeader_t *header;
+ union {
+ vmHeader_t *h;
+ void *v;
+ } header;
// load the image
Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name );
Com_Printf( "Loading vm file %s...\n", filename );
- length = FS_ReadFile( filename, (void **)&header );
- if ( !header ) {
+ length = FS_ReadFile( filename, &header.v );
+ if ( !header.h ) {
Com_Printf( "Failed.\n" );
VM_Free( vm );
return NULL;
}
- if( LittleLong( header->vmMagic ) == VM_MAGIC_VER2 ) {
+ if( LittleLong( header.h->vmMagic ) == VM_MAGIC_VER2 ) {
Com_Printf( "...which has vmMagic VM_MAGIC_VER2\n" );
// byte swap the header
for ( i = 0 ; i < sizeof( vmHeader_t ) / 4 ; i++ ) {
- ((int *)header)[i] = LittleLong( ((int *)header)[i] );
+ ((int *)header.h)[i] = LittleLong( ((int *)header.h)[i] );
}
// validate
- if ( header->jtrgLength < 0
- || header->bssLength < 0
- || header->dataLength < 0
- || header->litLength < 0
- || header->codeLength <= 0 ) {
+ if ( header.h->jtrgLength < 0
+ || header.h->bssLength < 0
+ || header.h->dataLength < 0
+ || header.h->litLength < 0
+ || header.h->codeLength <= 0 ) {
VM_Free( vm );
Com_Error( ERR_FATAL, "%s has bad header", filename );
}
- } else if( LittleLong( header->vmMagic ) == VM_MAGIC ) {
+ } else if( LittleLong( header.h->vmMagic ) == VM_MAGIC ) {
// byte swap the header
// sizeof( vmHeader_t ) - sizeof( int ) is the 1.32b vm header size
for ( i = 0 ; i < ( sizeof( vmHeader_t ) - sizeof( int ) ) / 4 ; i++ ) {
- ((int *)header)[i] = LittleLong( ((int *)header)[i] );
+ ((int *)header.h)[i] = LittleLong( ((int *)header.h)[i] );
}
// validate
- if ( header->bssLength < 0
- || header->dataLength < 0
- || header->litLength < 0
- || header->codeLength <= 0 ) {
+ if ( header.h->bssLength < 0
+ || header.h->dataLength < 0
+ || header.h->litLength < 0
+ || header.h->codeLength <= 0 ) {
VM_Free( vm );
Com_Error( ERR_FATAL, "%s has bad header", filename );
}
@@ -417,7 +424,7 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
// round up to next power of 2 so all data operations can
// be mask protected
- dataLength = header->dataLength + header->litLength + header->bssLength;
+ dataLength = header.h->dataLength + header.h->litLength + header.h->bssLength;
for ( i = 0 ; dataLength > ( 1 << i ) ; i++ ) {
}
dataLength = 1 << i;
@@ -432,33 +439,34 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
}
// copy the intialized data
- Com_Memcpy( vm->dataBase, (byte *)header + header->dataOffset, header->dataLength + header->litLength );
+ Com_Memcpy( vm->dataBase, (byte *)header.h + header.h->dataOffset,
+ header.h->dataLength + header.h->litLength );
// byte swap the longs
- for ( i = 0 ; i < header->dataLength ; i += 4 ) {
+ for ( i = 0 ; i < header.h->dataLength ; i += 4 ) {
*(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) );
}
- if( header->vmMagic == VM_MAGIC_VER2 ) {
- vm->numJumpTableTargets = header->jtrgLength >> 2;
+ if( header.h->vmMagic == VM_MAGIC_VER2 ) {
+ vm->numJumpTableTargets = header.h->jtrgLength >> 2;
Com_Printf( "Loading %d jump table targets\n", vm->numJumpTableTargets );
if( alloc ) {
- vm->jumpTableTargets = Hunk_Alloc( header->jtrgLength, h_high );
+ vm->jumpTableTargets = Hunk_Alloc( header.h->jtrgLength, h_high );
} else {
- Com_Memset( vm->jumpTableTargets, 0, header->jtrgLength );
+ Com_Memset( vm->jumpTableTargets, 0, header.h->jtrgLength );
}
- Com_Memcpy( vm->jumpTableTargets, (byte *)header + header->dataOffset +
- header->dataLength + header->litLength, header->jtrgLength );
+ Com_Memcpy( vm->jumpTableTargets, (byte *)header.h + header.h->dataOffset +
+ header.h->dataLength + header.h->litLength, header.h->jtrgLength );
// byte swap the longs
- for ( i = 0 ; i < header->jtrgLength ; i += 4 ) {
+ for ( i = 0 ; i < header.h->jtrgLength ; i += 4 ) {
*(int *)(vm->jumpTableTargets + i) = LittleLong( *(int *)(vm->jumpTableTargets + i ) );
}
}
- return header;
+ return header.h;
}
/*
diff --git a/src/qcommon/vm_powerpc.c b/src/qcommon/vm_powerpc.c
new file mode 100644
index 00000000..76bb984a
--- /dev/null
+++ b/src/qcommon/vm_powerpc.c
@@ -0,0 +1,2170 @@
+/*
+===========================================================================
+Copyright (C) 2008 Przemyslaw Iskra <sparky@pld-linux.org>
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include <sys/types.h> /* needed by sys/mman.h on OSX */
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stddef.h>
+
+#ifndef MAP_ANONYMOUS
+# define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#include "vm_local.h"
+#include "vm_powerpc_asm.h"
+
+/*
+ * VM_TIMES enables showing information about time spent inside
+ * and outside generated code
+ */
+//#define VM_TIMES
+#ifdef VM_TIMES
+#include <sys/times.h>
+static clock_t time_outside_vm = 0;
+static clock_t time_total_vm = 0;
+#endif
+
+/* exit() won't be called but use it because it is marked with noreturn */
+#define DIE( reason ) \
+ do { \
+ Com_Error(ERR_DROP, "vm_powerpc compiler error: " reason "\n"); \
+ exit(1); \
+ } while(0)
+
+/*
+ * vm_powerpc uses large quantities of memory during compilation,
+ * Z_Malloc memory may not be enough for some big qvm files
+ */
+
+//#define VM_SYSTEM_MALLOC
+#ifdef VM_SYSTEM_MALLOC
+static inline void *
+PPC_Malloc( size_t size )
+{
+ void *mem = malloc( size );
+ if ( ! mem )
+ DIE( "Not enough memory" );
+
+ return mem;
+}
+# define PPC_Free free
+#else
+# define PPC_Malloc Z_Malloc
+# define PPC_Free Z_Free
+#endif
+
+/*
+ * optimizations:
+ * - hole: bubble optimization (OP_CONST+instruction)
+ * - copy: inline OP_BLOCK_COPY for lengths under 16/32 bytes
+ * - mask: use rlwinm instruction as dataMask
+ */
+
+#ifdef __OPTIMIZE__
+# define OPTIMIZE_HOLE 1
+# define OPTIMIZE_COPY 1
+# define OPTIMIZE_MASK 1
+#else
+# define OPTIMIZE_HOLE 0
+# define OPTIMIZE_COPY 0
+# define OPTIMIZE_MASK 0
+#endif
+
+/*
+ * SUPPORTED TARGETS:
+ * - Linux 32 bits
+ * ( http://refspecs.freestandards.org/elf/elfspec_ppc.pdf )
+ * * LR at r0 + 4
+ * * Local variable space not needed
+ * -> store caller safe regs at 16+
+ *
+ * - Linux 64 bits (not fully conformant)
+ * ( http://www.ibm.com/developerworks/linux/library/l-powasm4.html )
+ * * needs "official procedure descriptors" (only first function has one)
+ * * LR at r0 + 16
+ * * local variable space required, min 64 bytes, starts at 48
+ * -> store caller safe regs at 128+
+ *
+ * - OS X 32 bits
+ * ( http://developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/Articles/32bitPowerPC.html )
+ * * LR at r0 + 8
+ * * local variable space required, min 32 bytes (?), starts at 24
+ * -> store caller safe regs at 64+
+ *
+ * - OS X 64 bits (completely untested)
+ * ( http://developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/Articles/64bitPowerPC.html )
+ * * LR at r0 + 16
+ * * local variable space required, min 64 bytes (?), starts at 48
+ * -> store caller safe regs at 128+
+ */
+
+/* Select Length - first value on 32 bits, second on 64 */
+#ifdef __PPC64__
+# define SL( a, b ) (b)
+#else
+# define SL( a, b ) (a)
+#endif
+
+/* Select ABI - first for ELF, second for OS X */
+#ifdef __ELF__
+# define SA( a, b ) (a)
+#else
+# define SA( a, b ) (b)
+#endif
+
+#define ELF32 SL( SA( 1, 0 ), 0 )
+#define ELF64 SL( 0, SA( 1, 0 ) )
+#define OSX32 SL( SA( 0, 1 ), 0 )
+#define OSX64 SL( 0, SA( 0, 1 ) )
+
+/* native length load/store instructions ( L stands for long ) */
+#define iSTLU SL( iSTWU, iSTDU )
+#define iSTL SL( iSTW, iSTD )
+#define iLL SL( iLWZ, iLD )
+#define iLLX SL( iLWZX, iLDX )
+
+/* register length */
+#define GPRLEN SL( 4, 8 )
+#define FPRLEN (8)
+/* shift that many bits to obtain value miltiplied by GPRLEN */
+#define GPRLEN_SHIFT SL( 2, 3 )
+
+/* Link register position */
+#define STACK_LR SL( SA( 4, 8 ), 16 )
+/* register save position */
+#define STACK_SAVE SL( SA( 16, 64 ), 128 )
+/* temporary space, for float<->int exchange */
+#define STACK_TEMP SL( SA( 8, 24 ), 48 )
+/* red zone temporary space, used instead of STACK_TEMP if stack isn't
+ * prepared properly */
+#define STACK_RTEMP (-16)
+
+#if ELF64
+/*
+ * Official Procedure Descriptor
+ * we need to prepare one for generated code if we want to call it
+ * as function
+ */
+typedef struct {
+ void *function;
+ void *toc;
+ void *env;
+} opd_t;
+#endif
+
+
+/*
+ * opcode information table:
+ * - length of immediate value
+ * - returned register type
+ * - required register(s) type
+ */
+#define opImm0 0x0000 /* no immediate */
+#define opImm1 0x0001 /* 1 byte immadiate value after opcode */
+#define opImm4 0x0002 /* 4 bytes immediate value after opcode */
+
+#define opRet0 0x0000 /* returns nothing */
+#define opRetI 0x0004 /* returns integer */
+#define opRetF 0x0008 /* returns float */
+#define opRetIF (opRetI | opRetF) /* returns integer or float */
+
+#define opArg0 0x0000 /* requires nothing */
+#define opArgI 0x0010 /* requires integer(s) */
+#define opArgF 0x0020 /* requires float(s) */
+#define opArgIF (opArgI | opArgF) /* requires integer or float */
+
+#define opArg2I 0x0040 /* requires second argument, integer */
+#define opArg2F 0x0080 /* requires second argument, float */
+#define opArg2IF (opArg2I | opArg2F) /* requires second argument, integer or float */
+
+static const unsigned char vm_opInfo[256] =
+{
+ [OP_UNDEF] = opImm0,
+ [OP_IGNORE] = opImm0,
+ [OP_BREAK] = opImm0,
+ [OP_ENTER] = opImm4,
+ /* OP_LEAVE has to accept floats, they will be converted to ints */
+ [OP_LEAVE] = opImm4 | opRet0 | opArgIF,
+ /* only STORE4 and POP use values from OP_CALL,
+ * no need to convert floats back */
+ [OP_CALL] = opImm0 | opRetI | opArgI,
+ [OP_PUSH] = opImm0 | opRetIF,
+ [OP_POP] = opImm0 | opRet0 | opArgIF,
+ [OP_CONST] = opImm4 | opRetIF,
+ [OP_LOCAL] = opImm4 | opRetI,
+ [OP_JUMP] = opImm0 | opRet0 | opArgI,
+
+ [OP_EQ] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_NE] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_LTI] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_LEI] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_GTI] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_GEI] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_LTU] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_LEU] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_GTU] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_GEU] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_EQF] = opImm4 | opRet0 | opArgF | opArg2F,
+ [OP_NEF] = opImm4 | opRet0 | opArgF | opArg2F,
+ [OP_LTF] = opImm4 | opRet0 | opArgF | opArg2F,
+ [OP_LEF] = opImm4 | opRet0 | opArgF | opArg2F,
+ [OP_GTF] = opImm4 | opRet0 | opArgF | opArg2F,
+ [OP_GEF] = opImm4 | opRet0 | opArgF | opArg2F,
+
+ [OP_LOAD1] = opImm0 | opRetI | opArgI,
+ [OP_LOAD2] = opImm0 | opRetI | opArgI,
+ [OP_LOAD4] = opImm0 | opRetIF| opArgI,
+ [OP_STORE1] = opImm0 | opRet0 | opArgI | opArg2I,
+ [OP_STORE2] = opImm0 | opRet0 | opArgI | opArg2I,
+ [OP_STORE4] = opImm0 | opRet0 | opArgIF| opArg2I,
+ [OP_ARG] = opImm1 | opRet0 | opArgIF,
+ [OP_BLOCK_COPY] = opImm4 | opRet0 | opArgI | opArg2I,
+
+ [OP_SEX8] = opImm0 | opRetI | opArgI,
+ [OP_SEX16] = opImm0 | opRetI | opArgI,
+ [OP_NEGI] = opImm0 | opRetI | opArgI,
+ [OP_ADD] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_SUB] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_DIVI] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_DIVU] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_MODI] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_MODU] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_MULI] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_MULU] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_BAND] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_BOR] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_BXOR] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_BCOM] = opImm0 | opRetI | opArgI,
+ [OP_LSH] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_RSHI] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_RSHU] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_NEGF] = opImm0 | opRetF | opArgF,
+ [OP_ADDF] = opImm0 | opRetF | opArgF | opArg2F,
+ [OP_SUBF] = opImm0 | opRetF | opArgF | opArg2F,
+ [OP_DIVF] = opImm0 | opRetF | opArgF | opArg2F,
+ [OP_MULF] = opImm0 | opRetF | opArgF | opArg2F,
+ [OP_CVIF] = opImm0 | opRetF | opArgI,
+ [OP_CVFI] = opImm0 | opRetI | opArgF,
+};
+
+/*
+ * source instruction data
+ */
+typedef struct source_instruction_s source_instruction_t;
+struct source_instruction_s {
+ // opcode
+ unsigned long int op;
+
+ // number of instruction
+ unsigned long int i_count;
+
+ // immediate value (if any)
+ union {
+ unsigned int i;
+ signed int si;
+ signed short ss[2];
+ unsigned short us[2];
+ unsigned char b;
+ } arg;
+
+ // required and returned registers
+ unsigned char regA1;
+ unsigned char regA2;
+ unsigned char regR;
+ unsigned char regPos;
+
+ // next instruction
+ source_instruction_t *next;
+};
+
+
+
+/*
+ * read-only data needed by the generated code
+ */
+typedef struct VM_Data {
+ // length of this struct + data
+ size_t dataLength;
+ // compiled code size (in bytes)
+ // it only is code size, without the data
+ size_t codeLength;
+
+ // function pointers, no use to waste registers for them
+ long int (* AsmCall)( int, int );
+ void (* BlockCopy )( unsigned int, unsigned int, unsigned int );
+
+ // instruction pointers, rarely used so don't waste register
+ ppc_instruction_t *iPointers;
+
+ // data mask for load and store, not used if optimized
+ unsigned int dataMask;
+
+ // fixed number used to convert from integer to float
+ unsigned int floatBase; // 0x59800004
+
+#if ELF64
+ // official procedure descriptor
+ opd_t opd;
+#endif
+
+ // additional constants, for floating point OP_CONST
+ // this data has dynamic length, thus '0' here
+ unsigned int data[0];
+} vm_data_t;
+
+#ifdef offsetof
+# define VM_Data_Offset( field ) offsetof( vm_data_t, field )
+#else
+# define OFFSET( structName, field ) \
+ ( (void *)&(((structName *)NULL)->field) - NULL )
+# define VM_Data_Offset( field ) OFFSET( vm_data_t, field )
+#endif
+
+
+/*
+ * functions used by generated code
+ */
+static long int
+VM_AsmCall( int callSyscallInvNum, int callProgramStack )
+{
+ vm_t *savedVM = currentVM;
+ long int i, ret;
+#ifdef VM_TIMES
+ struct tms start_time, stop_time;
+ clock_t saved_time = time_outside_vm;
+ times( &start_time );
+#endif
+
+ // save the stack to allow recursive VM entry
+ currentVM->programStack = callProgramStack - 4;
+
+ // we need to convert ints to longs on 64bit powerpcs
+ if ( sizeof( intptr_t ) == sizeof( int ) ) {
+ intptr_t *argPosition = (intptr_t *)((byte *)currentVM->dataBase + callProgramStack + 4);
+
+ // generated code does not invert syscall number
+ argPosition[ 0 ] = -1 - callSyscallInvNum;
+
+ ret = currentVM->systemCall( argPosition );
+ } else {
+ intptr_t args[11];
+
+ // generated code does not invert syscall number
+ args[0] = -1 - callSyscallInvNum;
+
+ int *argPosition = (int *)((byte *)currentVM->dataBase + callProgramStack + 4);
+ for( i = 1; i < 11; i++ )
+ args[ i ] = argPosition[ i ];
+
+ ret = currentVM->systemCall( args );
+ }
+
+ currentVM = savedVM;
+
+#ifdef VM_TIMES
+ times( &stop_time );
+ time_outside_vm = saved_time + ( stop_time.tms_utime - start_time.tms_utime );
+#endif
+
+ return ret;
+}
+
+static void
+VM_BlockCopy( unsigned int dest, unsigned int src, unsigned int count )
+{
+ unsigned dataMask = currentVM->dataMask;
+
+ if ( (dest & dataMask) != dest
+ || (src & dataMask) != src
+ || ((dest+count) & dataMask) != dest + count
+ || ((src+count) & dataMask) != src + count)
+ {
+ DIE( "OP_BLOCK_COPY out of range!");
+ }
+
+ memcpy( currentVM->dataBase+dest, currentVM->dataBase+src, count );
+}
+
+
+/*
+ * code-block descriptors
+ */
+typedef struct dest_instruction dest_instruction_t;
+typedef struct symbolic_jump symbolic_jump_t;
+
+struct symbolic_jump {
+ // number of source instruction it has to jump to
+ unsigned long int jump_to;
+
+ // jump condition true/false, (4*cr7+(eq|gt..))
+ long int bo, bi;
+
+ // extensions / modifiers (branch-link)
+ unsigned long ext;
+
+ // dest_instruction refering to this jump
+ dest_instruction_t *parent;
+
+ // next jump
+ symbolic_jump_t *nextJump;
+};
+
+struct dest_instruction {
+ // position in the output chain
+ unsigned long int count;
+
+ // source instruction number
+ unsigned long int i_count;
+
+ // exact (for instructins), or maximum (for jump) length
+ unsigned short length;
+
+ dest_instruction_t *next;
+
+ // if the instruction is a jump than jump will be non NULL
+ symbolic_jump_t *jump;
+
+ // if jump is NULL than all the instructions will be here
+ ppc_instruction_t code[0];
+};
+
+// first and last instruction,
+// di_first is a dummy instruction
+static dest_instruction_t *di_first = NULL, *di_last = NULL;
+// number of instructions
+static unsigned long int di_count = 0;
+// pointers needed to compute local jumps, those aren't pointers to
+// actual instructions, just used to check how long the jump is going
+// to be and whether it is positive or negative
+static dest_instruction_t **di_pointers = NULL;
+
+// output instructions which does not come from source code
+// use false i_count value
+#define FALSE_ICOUNT 0xffffffff
+
+
+/*
+ * append specified instructions at the end of instruction chain
+ */
+static void
+PPC_Append(
+ dest_instruction_t *di_now,
+ unsigned long int i_count
+ )
+{
+ di_now->count = di_count++;
+ di_now->i_count = i_count;
+ di_now->next = NULL;
+
+ di_last->next = di_now;
+ di_last = di_now;
+
+ if ( i_count != FALSE_ICOUNT ) {
+ if ( ! di_pointers[ i_count ] )
+ di_pointers[ i_count ] = di_now;
+ }
+}
+
+/*
+ * make space for instructions and append
+ */
+static void
+PPC_AppendInstructions(
+ unsigned long int i_count,
+ size_t num_instructions,
+ const ppc_instruction_t *is
+ )
+{
+ if ( num_instructions < 0 )
+ num_instructions = 0;
+ size_t iBytes = sizeof( ppc_instruction_t ) * num_instructions;
+ dest_instruction_t *di_now = PPC_Malloc( sizeof( dest_instruction_t ) + iBytes );
+
+ di_now->length = num_instructions;
+ di_now->jump = NULL;
+
+ if ( iBytes > 0 )
+ memcpy( &(di_now->code[0]), is, iBytes );
+
+ PPC_Append( di_now, i_count );
+}
+
+/*
+ * create symbolic jump and append
+ */
+static symbolic_jump_t *sj_first = NULL, *sj_last = NULL;
+static void
+PPC_PrepareJump(
+ unsigned long int i_count,
+ unsigned long int dest,
+ long int bo,
+ long int bi,
+ unsigned long int ext
+ )
+{
+ dest_instruction_t *di_now = PPC_Malloc( sizeof( dest_instruction_t ) );
+ symbolic_jump_t *sj = PPC_Malloc( sizeof( symbolic_jump_t ) );
+
+ sj->jump_to = dest;
+ sj->bo = bo;
+ sj->bi = bi;
+ sj->ext = ext;
+ sj->parent = di_now;
+ sj->nextJump = NULL;
+
+ sj_last->nextJump = sj;
+ sj_last = sj;
+
+ di_now->length = (bo == branchAlways ? 1 : 2);
+ di_now->jump = sj;
+
+ PPC_Append( di_now, i_count );
+}
+
+/*
+ * simplyfy instruction emission
+ */
+#define emitStart( i_cnt ) \
+ unsigned long int i_count = i_cnt; \
+ size_t num_instructions = 0; \
+ long int force_emit = 0; \
+ ppc_instruction_t instructions[50];
+
+#define pushIn( inst ) \
+ (instructions[ num_instructions++ ] = inst)
+#define in( inst, args... ) pushIn( IN( inst, args ) )
+
+#define emitEnd() \
+ do{ \
+ if ( num_instructions || force_emit ) \
+ PPC_AppendInstructions( i_count, num_instructions, instructions );\
+ num_instructions = 0; \
+ } while(0)
+
+#define emitJump( dest, bo, bi, ext ) \
+ do { \
+ emitEnd(); \
+ PPC_PrepareJump( i_count, dest, bo, bi, ext ); \
+ } while(0)
+
+
+/*
+ * definitions for creating .data section,
+ * used in cases where constant float is needed
+ */
+#define LOCAL_DATA_CHUNK 50
+typedef struct local_data_s local_data_t;
+struct local_data_s {
+ // number of data in this structure
+ long int count;
+
+ // data placeholder
+ unsigned int data[ LOCAL_DATA_CHUNK ];
+
+ // next chunk, if this one wasn't enough
+ local_data_t *next;
+};
+
+// first data chunk
+static local_data_t *data_first = NULL;
+// total number of data
+static long int data_acc = 0;
+
+/*
+ * append the data and return its offset
+ */
+static size_t
+PPC_PushData( unsigned int datum )
+{
+ local_data_t *d_now = data_first;
+ long int accumulated = 0;
+
+ // check whether we have this one already
+ do {
+ long int i;
+ for ( i = 0; i < d_now->count; i++ ) {
+ if ( d_now->data[ i ] == datum ) {
+ accumulated += i;
+ return VM_Data_Offset( data[ accumulated ] );
+ }
+ }
+ if ( !d_now->next )
+ break;
+
+ accumulated += d_now->count;
+ d_now = d_now->next;
+ } while (1);
+
+ // not found, need to append
+ accumulated += d_now->count;
+
+ // last chunk is full, create new one
+ if ( d_now->count >= LOCAL_DATA_CHUNK ) {
+ d_now->next = PPC_Malloc( sizeof( local_data_t ) );
+ d_now = d_now->next;
+ d_now->count = 0;
+ d_now->next = NULL;
+ }
+
+ d_now->data[ d_now->count ] = datum;
+ d_now->count += 1;
+
+ data_acc = accumulated + 1;
+
+ return VM_Data_Offset( data[ accumulated ] );
+}
+
+/*
+ * find leading zeros in dataMask to implement it with
+ * "rotate and mask" instruction
+ */
+static long int fastMaskHi = 0, fastMaskLo = 31;
+static void
+PPC_MakeFastMask( int mask )
+{
+#if defined( __GNUC__ ) && ( __GNUC__ >= 4 || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 4 ) )
+ /* count leading zeros */
+ fastMaskHi = __builtin_clz( mask );
+
+ /* count trailing zeros */
+ fastMaskLo = 31 - __builtin_ctz( mask );
+#else
+ fastMaskHi = 0;
+ while ( ( mask & ( 0x80000000 >> fastMaskHi ) ) == 0 )
+ fastMaskHi++;
+
+ fastMaskLo = 31;
+ while ( ( mask & ( 0x80000000 >> fastMaskLo ) ) == 0 )
+ fastMaskLo--;
+#endif
+}
+
+
+/*
+ * register definitions
+ */
+
+/* registers which are global for generated code */
+
+// pointer to VM_Data (constant)
+#define rVMDATA r14
+// vm->dataBase (constant)
+#define rDATABASE r15
+// programStack (variable)
+#define rPSTACK r16
+
+/*
+ * function local registers,
+ *
+ * normally only volatile registers are used, but if there aren't enough
+ * or function has to preserve some value while calling annother one
+ * then caller safe registers are used as well
+ */
+static const long int gpr_list[] = {
+ /* caller safe registers, normally only one is used */
+ r24, r23, r22, r21,
+ r20, r19, r18, r17,
+ /* volatile registers (preferred),
+ * normally no more than 5 is used */
+ r3, r4, r5, r6,
+ r7, r8, r9, r10,
+};
+static const long int gpr_vstart = 8; /* position of first volatile register */
+static const long int gpr_total = sizeof( gpr_list ) / sizeof( gpr_list[0] );
+
+static const long int fpr_list[] = {
+ /* static registers, normally none is used */
+ f20, f21, f19, f18,
+ f17, f16, f15, f14,
+ /* volatile registers (preferred),
+ * normally no more than 7 is used */
+ f0, f1, f2, f3,
+ f4, f5, f6, f7,
+ f8, f9, f10, f11,
+ f12, f13,
+};
+static const long int fpr_vstart = 8;
+static const long int fpr_total = sizeof( fpr_list ) / sizeof( fpr_list[0] );
+
+/*
+ * prepare some dummy structures and emit init code
+ */
+static void
+PPC_CompileInit( void )
+{
+ di_first = di_last = PPC_Malloc( sizeof( dest_instruction_t ) );
+ di_first->count = 0;
+ di_first->next = NULL;
+ di_first->jump = NULL;
+
+ sj_first = sj_last = PPC_Malloc( sizeof( symbolic_jump_t ) );
+ sj_first->nextJump = NULL;
+
+ data_first = PPC_Malloc( sizeof( local_data_t ) );
+ data_first->count = 0;
+ data_first->next = NULL;
+
+ /*
+ * init function:
+ * saves old values of global registers and sets our values
+ * function prototype is:
+ * int begin( void *data, int programStack, void *vm->dataBase )
+ */
+
+ /* first instruction must not be placed on instruction list */
+ emitStart( FALSE_ICOUNT );
+
+ long int stack = STACK_SAVE + 4 * GPRLEN;
+
+ in( iMFLR, r0 );
+ in( iSTLU, r1, -stack, r1 );
+ in( iSTL, rVMDATA, STACK_SAVE + 0 * GPRLEN, r1 );
+ in( iSTL, rPSTACK, STACK_SAVE + 1 * GPRLEN, r1 );
+ in( iSTL, rDATABASE, STACK_SAVE + 2 * GPRLEN, r1 );
+ in( iSTL, r0, stack + STACK_LR, r1 );
+ in( iMR, rVMDATA, r3 );
+ in( iMR, rPSTACK, r4 );
+ in( iMR, rDATABASE, r5 );
+ in( iBL, +4*8 ); // LINK JUMP: first generated instruction | XXX jump !
+ in( iLL, rVMDATA, STACK_SAVE + 0 * GPRLEN, r1 );
+ in( iLL, rPSTACK, STACK_SAVE + 1 * GPRLEN, r1 );
+ in( iLL, rDATABASE, STACK_SAVE + 2 * GPRLEN, r1 );
+ in( iLL, r0, stack + STACK_LR, r1 );
+ in( iMTLR, r0 );
+ in( iADDI, r1, r1, stack );
+ in( iBLR );
+
+ emitEnd();
+}
+
+// rFIRST is the copy of the top value on the opstack
+#define rFIRST (gpr_list[ gpr_pos - 1])
+// second value on the opstack
+#define rSECOND (gpr_list[ gpr_pos - 2 ])
+// temporary registers, not on the opstack
+#define rTEMP(x) (gpr_list[ gpr_pos + x ])
+#define rTMP rTEMP(0)
+
+#define fFIRST (fpr_list[ fpr_pos - 1 ])
+#define fSECOND (fpr_list[ fpr_pos - 2 ])
+#define fTEMP(x) (fpr_list[ fpr_pos + x ])
+#define fTMP fTEMP(0)
+
+// register types
+#define rTYPE_STATIC 0x01
+#define rTYPE_FLOAT 0x02
+
+// what type should this opcode return
+#define RET_INT ( !(i_now->regR & rTYPE_FLOAT) )
+#define RET_FLOAT ( i_now->regR & rTYPE_FLOAT )
+// what type should it accept
+#define ARG_INT ( ! i_now->regA1 )
+#define ARG_FLOAT ( i_now->regA1 )
+#define ARG2_INT ( ! i_now->regA2 )
+#define ARG2_FLOAT ( i_now->regA2 )
+
+/*
+ * emit OP_CONST, called if nothing has used the const value directly
+ */
+static void
+PPC_EmitConst( source_instruction_t * const i_const )
+{
+ emitStart( i_const->i_count );
+
+ if ( !(i_const->regR & rTYPE_FLOAT) ) {
+ // gpr_pos needed for "rFIRST" to work
+ long int gpr_pos = i_const->regPos;
+
+ if ( i_const->arg.si >= -0x8000 && i_const->arg.si < 0x8000 ) {
+ in( iLI, rFIRST, i_const->arg.si );
+ } else if ( i_const->arg.i < 0x10000 ) {
+ in( iLI, rFIRST, 0 );
+ in( iORI, rFIRST, rFIRST, i_const->arg.i );
+ } else {
+ in( iLIS, rFIRST, i_const->arg.ss[ 0 ] );
+ if ( i_const->arg.us[ 1 ] != 0 )
+ in( iORI, rFIRST, rFIRST, i_const->arg.us[ 1 ] );
+ }
+
+ } else {
+ // fpr_pos needed for "fFIRST" to work
+ long int fpr_pos = i_const->regPos;
+
+ // there's no good way to generate the data,
+ // just read it from data section
+ in( iLFS, fFIRST, PPC_PushData( i_const->arg.i ), rVMDATA );
+ }
+
+ emitEnd();
+}
+#define MAYBE_EMIT_CONST() if ( i_const ) PPC_EmitConst( i_const )
+
+/*
+ * emit empty instruction, just sets the needed pointers
+ */
+static inline void
+PPC_EmitNull( source_instruction_t * const i_null )
+{
+ PPC_AppendInstructions( i_null->i_count, 0, NULL );
+}
+#define EMIT_FALSE_CONST() PPC_EmitNull( i_const )
+
+
+/*
+ * analize function for register usage and whether it needs stack (r1) prepared
+ */
+static void
+VM_AnalyzeFunction(
+ source_instruction_t * const i_first,
+ long int *prepareStack,
+ long int *gpr_start_pos,
+ long int *fpr_start_pos
+ )
+{
+ source_instruction_t *i_now = i_first;
+
+ source_instruction_t *value_provider[20] = { NULL };
+ unsigned long int opstack_depth = 0;
+
+ /*
+ * first step:
+ * remember what codes returned some value and mark the value type
+ * when we get to know what it should be
+ */
+ while ( (i_now = i_now->next) ) {
+ unsigned long int op = i_now->op;
+ unsigned long int opi = vm_opInfo[ op ];
+
+ if ( opi & opArgIF ) {
+ assert( opstack_depth > 0 );
+
+ opstack_depth--;
+ source_instruction_t *vp = value_provider[ opstack_depth ];
+ unsigned long int vpopi = vm_opInfo[ vp->op ];
+
+ if ( (opi & opArgI) && (vpopi & opRetI) ) {
+ // instruction accepts integer, provider returns integer
+ //vp->regR |= rTYPE_INT;
+ //i_now->regA1 = rTYPE_INT;
+ } else if ( (opi & opArgF) && (vpopi & opRetF) ) {
+ // instruction accepts float, provider returns float
+ vp->regR |= rTYPE_FLOAT; // use OR here - could be marked as static
+ i_now->regA1 = rTYPE_FLOAT;
+ } else {
+ // instruction arg type does not agree with
+ // provider return type
+ DIE( "unrecognized instruction combination" );
+ }
+
+ }
+ if ( opi & opArg2IF ) {
+ assert( opstack_depth > 0 );
+
+ opstack_depth--;
+ source_instruction_t *vp = value_provider[ opstack_depth ];
+ unsigned long int vpopi = vm_opInfo[ vp->op ];
+
+ if ( (opi & opArg2I) && (vpopi & opRetI) ) {
+ // instruction accepts integer, provider returns integer
+ //vp->regR |= rTYPE_INT;
+ //i_now->regA2 = rTYPE_INT;
+ } else if ( (opi & opArg2F) && (vpopi & opRetF) ) {
+ // instruction accepts float, provider returns float
+ vp->regR |= rTYPE_FLOAT; // use OR here - could be marked as static
+ i_now->regA2 = rTYPE_FLOAT;
+ } else {
+ // instruction arg type does not agree with
+ // provider return type
+ DIE( "unrecognized instruction combination" );
+ }
+ }
+
+
+ if (
+ ( op == OP_CALL )
+ ||
+ ( op == OP_BLOCK_COPY && ( i_now->arg.i > SL( 16, 32 ) || !OPTIMIZE_COPY ) )
+ ) {
+ long int i;
+ *prepareStack = 1;
+ // force caller safe registers so we won't have to save them
+ for ( i = 0; i < opstack_depth; i++ ) {
+ source_instruction_t *vp = value_provider[ i ];
+ vp->regR |= rTYPE_STATIC;
+ }
+ }
+
+
+ if ( opi & opRetIF ) {
+ value_provider[ opstack_depth ] = i_now;
+ opstack_depth++;
+ }
+ }
+
+ /*
+ * second step:
+ * now that we know register types; compute exactly how many registers
+ * of each type we need
+ */
+
+ i_now = i_first;
+ long int needed_reg[4] = {0,0,0,0}, max_reg[4] = {0,0,0,0};
+ opstack_depth = 0;
+ while ( (i_now = i_now->next) ) {
+ unsigned long int op = i_now->op;
+ unsigned long int opi = vm_opInfo[ op ];
+
+ if ( opi & opArgIF ) {
+ assert( opstack_depth > 0 );
+ opstack_depth--;
+ source_instruction_t *vp = value_provider[ opstack_depth ];
+
+ needed_reg[ ( vp->regR & 2 ) ] -= 1;
+ if ( vp->regR & 1 ) // static
+ needed_reg[ ( vp->regR & 3 ) ] -= 1;
+ }
+ if ( opi & opArg2IF ) {
+ assert( opstack_depth > 0 );
+ opstack_depth--;
+ source_instruction_t *vp = value_provider[ opstack_depth ];
+
+ needed_reg[ ( vp->regR & 2 ) ] -= 1;
+ if ( vp->regR & 1 ) // static
+ needed_reg[ ( vp->regR & 3 ) ] -= 1;
+ }
+
+ if ( opi & opRetIF ) {
+ long int i;
+ value_provider[ opstack_depth ] = i_now;
+ opstack_depth++;
+
+ i = i_now->regR & 2;
+ needed_reg[ i ] += 1;
+ if ( max_reg[ i ] < needed_reg[ i ] )
+ max_reg[ i ] = needed_reg[ i ];
+
+ i = i_now->regR & 3;
+ if ( i & 1 ) {
+ needed_reg[ i ] += 1;
+ if ( max_reg[ i ] < needed_reg[ i ] )
+ max_reg[ i ] = needed_reg[ i ];
+ }
+ }
+ }
+
+ long int gpr_start = gpr_vstart;
+ const long int gpr_volatile = gpr_total - gpr_vstart;
+ if ( max_reg[ 1 ] > 0 || max_reg[ 0 ] > gpr_volatile ) {
+ // max_reg[ 0 ] - all gprs needed
+ // max_reg[ 1 ] - static gprs needed
+ long int max = max_reg[ 0 ] - gpr_volatile;
+ if ( max_reg[ 1 ] > max )
+ max = max_reg[ 1 ];
+ if ( max > gpr_vstart ) {
+ /* error */
+ DIE( "Need more GPRs" );
+ }
+
+ gpr_start -= max;
+
+ // need stack to save caller safe registers
+ *prepareStack = 1;
+ }
+ *gpr_start_pos = gpr_start;
+
+ long int fpr_start = fpr_vstart;
+ const long int fpr_volatile = fpr_total - fpr_vstart;
+ if ( max_reg[ 3 ] > 0 || max_reg[ 2 ] > fpr_volatile ) {
+ // max_reg[ 2 ] - all fprs needed
+ // max_reg[ 3 ] - static fprs needed
+ long int max = max_reg[ 2 ] - fpr_volatile;
+ if ( max_reg[ 3 ] > max )
+ max = max_reg[ 3 ];
+ if ( max > fpr_vstart ) {
+ /* error */
+ DIE( "Need more FPRs" );
+ }
+
+ fpr_start -= max;
+
+ // need stack to save caller safe registers
+ *prepareStack = 1;
+ }
+ *fpr_start_pos = fpr_start;
+}
+
+/*
+ * translate opcodes to ppc instructions,
+ * it works on functions, not on whole code at once
+ */
+static void
+VM_CompileFunction( source_instruction_t * const i_first )
+{
+ long int prepareStack = 0;
+ long int gpr_start_pos, fpr_start_pos;
+
+ VM_AnalyzeFunction( i_first, &prepareStack, &gpr_start_pos, &fpr_start_pos );
+
+ long int gpr_pos = gpr_start_pos, fpr_pos = fpr_start_pos;
+
+ // OP_CONST combines well with many opcodes so we treat it in a special way
+ source_instruction_t *i_const = NULL;
+ source_instruction_t *i_now = i_first;
+
+ // how big the stack has to be
+ long int save_space = STACK_SAVE;
+ {
+ if ( gpr_start_pos < gpr_vstart )
+ save_space += (gpr_vstart - gpr_start_pos) * GPRLEN;
+ save_space = ( save_space + 15 ) & ~0x0f;
+
+ if ( fpr_start_pos < fpr_vstart )
+ save_space += (fpr_vstart - fpr_start_pos) * FPRLEN;
+ save_space = ( save_space + 15 ) & ~0x0f;
+ }
+
+ long int stack_temp = prepareStack ? STACK_TEMP : STACK_RTEMP;
+
+ while ( (i_now = i_now->next) ) {
+ emitStart( i_now->i_count );
+
+ switch ( i_now->op )
+ {
+ default:
+ case OP_UNDEF:
+ case OP_IGNORE:
+ MAYBE_EMIT_CONST();
+ in( iNOP );
+ break;
+
+ case OP_BREAK:
+ MAYBE_EMIT_CONST();
+ // force SEGV
+ in( iLWZ, r0, 0, r0 );
+ break;
+
+ case OP_ENTER:
+ if ( i_const )
+ DIE( "Weird opcode order" );
+
+ // don't prepare stack if not needed
+ if ( prepareStack ) {
+ long int i, save_pos = STACK_SAVE;
+
+ in( iMFLR, r0 );
+ in( iSTLU, r1, -save_space, r1 );
+ in( iSTL, r0, save_space + STACK_LR, r1 );
+
+ /* save registers */
+ for ( i = gpr_start_pos; i < gpr_vstart; i++ ) {
+ in( iSTL, gpr_list[ i ], save_pos, r1 );
+ save_pos += GPRLEN;
+ }
+ save_pos = ( save_pos + 15 ) & ~0x0f;
+
+ for ( i = fpr_start_pos; i < fpr_vstart; i++ ) {
+ in( iSTFD, fpr_list[ i ], save_pos, r1 );
+ save_pos += FPRLEN;
+ }
+ prepareStack = 2;
+ }
+
+ in( iADDI, rPSTACK, rPSTACK, - i_now->arg.si );
+ break;
+
+ case OP_LEAVE:
+ if ( i_const ) {
+ EMIT_FALSE_CONST();
+
+ if ( i_const->regR & rTYPE_FLOAT)
+ DIE( "constant float in OP_LEAVE" );
+
+ if ( i_const->arg.si >= -0x8000 && i_const->arg.si < 0x8000 ) {
+ in( iLI, r3, i_const->arg.si );
+ } else if ( i_const->arg.i < 0x10000 ) {
+ in( iLI, r3, 0 );
+ in( iORI, r3, r3, i_const->arg.i );
+ } else {
+ in( iLIS, r3, i_const->arg.ss[ 0 ] );
+ if ( i_const->arg.us[ 1 ] != 0 )
+ in( iORI, r3, r3, i_const->arg.us[ 1 ] );
+ }
+ gpr_pos--;
+ } else {
+ MAYBE_EMIT_CONST();
+
+ /* place return value in r3 */
+ if ( ARG_INT ) {
+ if ( rFIRST != r3 )
+ in( iMR, r3, rFIRST );
+ gpr_pos--;
+ } else {
+ in( iSTFS, fFIRST, stack_temp, r1 );
+ in( iLWZ, r3, stack_temp, r1 );
+ fpr_pos--;
+ }
+ }
+
+ // don't undo stack if not prepared
+ if ( prepareStack >= 2 ) {
+ long int i, save_pos = STACK_SAVE;
+
+ in( iLL, r0, save_space + STACK_LR, r1 );
+
+
+ /* restore registers */
+ for ( i = gpr_start_pos; i < gpr_vstart; i++ ) {
+ in( iLL, gpr_list[ i ], save_pos, r1 );
+ save_pos += GPRLEN;
+ }
+ save_pos = ( save_pos + 15 ) & ~0x0f;
+ for ( i = fpr_start_pos; i < fpr_vstart; i++ ) {
+ in( iLFD, fpr_list[ i ], save_pos, r1 );
+ save_pos += FPRLEN;
+ }
+
+ in( iMTLR, r0 );
+ in( iADDI, r1, r1, save_space );
+ }
+ in( iADDI, rPSTACK, rPSTACK, i_now->arg.si);
+ in( iBLR );
+ assert( gpr_pos == gpr_start_pos );
+ assert( fpr_pos == fpr_start_pos );
+ break;
+
+ case OP_CALL:
+ if ( i_const ) {
+ EMIT_FALSE_CONST();
+
+ if ( i_const->arg.si >= 0 ) {
+ emitJump(
+ i_const->arg.i,
+ branchAlways, 0, branchExtLink
+ );
+ } else {
+ /* syscall */
+ in( iLL, r0, VM_Data_Offset( AsmCall ), rVMDATA );
+
+ in( iLI, r3, i_const->arg.si ); // negative value
+ in( iMR, r4, rPSTACK ); // push PSTACK on argument list
+
+ in( iMTCTR, r0 );
+ in( iBCTRL );
+ }
+ if ( rFIRST != r3 )
+ in( iMR, rFIRST, r3 );
+ } else {
+ MAYBE_EMIT_CONST();
+
+ in( iCMPWI, cr7, rFIRST, 0 );
+ in( iBLTm, cr7, +4*5 /* syscall */ ); // XXX jump !
+ /* instruction call */
+
+ // get instruction address
+ in( iLL, r0, VM_Data_Offset( iPointers ), rVMDATA );
+ in( iRLWINM, rFIRST, rFIRST, GPRLEN_SHIFT, 0, 31-GPRLEN_SHIFT ); // mul * GPRLEN
+ in( iLLX, r0, rFIRST, r0 ); // load pointer
+
+ in( iB, +4*(3 + (rFIRST != r3 ? 1 : 0) ) ); // XXX jump !
+
+ /* syscall */
+ in( iLL, r0, VM_Data_Offset( AsmCall ), rVMDATA ); // get asmCall pointer
+ /* rFIRST can be r3 or some static register */
+ if ( rFIRST != r3 )
+ in( iMR, r3, rFIRST ); // push OPSTACK top value on argument list
+ in( iMR, r4, rPSTACK ); // push PSTACK on argument list
+
+ /* common code */
+ in( iMTCTR, r0 );
+ in( iBCTRL );
+
+ if ( rFIRST != r3 )
+ in( iMR, rFIRST, r3 ); // push return value on the top of the opstack
+ }
+ break;
+
+ case OP_PUSH:
+ MAYBE_EMIT_CONST();
+ if ( RET_INT )
+ gpr_pos++;
+ else
+ fpr_pos++;
+ /* no instructions here */
+ force_emit = 1;
+ break;
+
+ case OP_POP:
+ MAYBE_EMIT_CONST();
+ if ( ARG_INT )
+ gpr_pos--;
+ else
+ fpr_pos--;
+ /* no instructions here */
+ force_emit = 1;
+ break;
+
+ case OP_CONST:
+ MAYBE_EMIT_CONST();
+ /* nothing here */
+ break;
+
+ case OP_LOCAL:
+ MAYBE_EMIT_CONST();
+ {
+ signed long int hi, lo;
+ hi = i_now->arg.ss[ 0 ];
+ lo = i_now->arg.ss[ 1 ];
+ if ( lo < 0 )
+ hi += 1;
+
+ gpr_pos++;
+ if ( hi == 0 ) {
+ in( iADDI, rFIRST, rPSTACK, lo );
+ } else {
+ in( iADDIS, rFIRST, rPSTACK, hi );
+ if ( lo != 0 )
+ in( iADDI, rFIRST, rFIRST, lo );
+ }
+ }
+ break;
+
+ case OP_JUMP:
+ if ( i_const ) {
+ EMIT_FALSE_CONST();
+
+ emitJump(
+ i_const->arg.i,
+ branchAlways, 0, 0
+ );
+ } else {
+ MAYBE_EMIT_CONST();
+
+ in( iLL, r0, VM_Data_Offset( iPointers ), rVMDATA );
+ in( iRLWINM, rFIRST, rFIRST, GPRLEN_SHIFT, 0, 31-GPRLEN_SHIFT ); // mul * GPRLEN
+ in( iLLX, r0, rFIRST, r0 ); // load pointer
+ in( iMTCTR, r0 );
+ in( iBCTR );
+ }
+ gpr_pos--;
+ break;
+
+ case OP_EQ:
+ case OP_NE:
+ if ( i_const && i_const->arg.si >= -0x8000 && i_const->arg.si < 0x10000 ) {
+ EMIT_FALSE_CONST();
+ if ( i_const->arg.si >= 0x8000 )
+ in( iCMPLWI, cr7, rSECOND, i_const->arg.i );
+ else
+ in( iCMPWI, cr7, rSECOND, i_const->arg.si );
+ } else {
+ MAYBE_EMIT_CONST();
+ in( iCMPW, cr7, rSECOND, rFIRST );
+ }
+ emitJump(
+ i_now->arg.i,
+ (i_now->op == OP_EQ ? branchTrue : branchFalse),
+ 4*cr7+eq, 0
+ );
+ gpr_pos -= 2;
+ break;
+
+ case OP_LTI:
+ case OP_GEI:
+ if ( i_const && i_const->arg.si >= -0x8000 && i_const->arg.si < 0x8000 ) {
+ EMIT_FALSE_CONST();
+ in( iCMPWI, cr7, rSECOND, i_const->arg.si );
+ } else {
+ MAYBE_EMIT_CONST();
+ in( iCMPW, cr7, rSECOND, rFIRST );
+ }
+ emitJump(
+ i_now->arg.i,
+ ( i_now->op == OP_LTI ? branchTrue : branchFalse ),
+ 4*cr7+lt, 0
+ );
+ gpr_pos -= 2;
+ break;
+
+ case OP_GTI:
+ case OP_LEI:
+ if ( i_const && i_const->arg.si >= -0x8000 && i_const->arg.si < 0x8000 ) {
+ EMIT_FALSE_CONST();
+ in( iCMPWI, cr7, rSECOND, i_const->arg.si );
+ } else {
+ MAYBE_EMIT_CONST();
+ in( iCMPW, cr7, rSECOND, rFIRST );
+ }
+ emitJump(
+ i_now->arg.i,
+ ( i_now->op == OP_GTI ? branchTrue : branchFalse ),
+ 4*cr7+gt, 0
+ );
+ gpr_pos -= 2;
+ break;
+
+ case OP_LTU:
+ case OP_GEU:
+ if ( i_const && i_const->arg.i < 0x10000 ) {
+ EMIT_FALSE_CONST();
+ in( iCMPLWI, cr7, rSECOND, i_const->arg.i );
+ } else {
+ MAYBE_EMIT_CONST();
+ in( iCMPLW, cr7, rSECOND, rFIRST );
+ }
+ emitJump(
+ i_now->arg.i,
+ ( i_now->op == OP_LTU ? branchTrue : branchFalse ),
+ 4*cr7+lt, 0
+ );
+ gpr_pos -= 2;
+ break;
+
+ case OP_GTU:
+ case OP_LEU:
+ if ( i_const && i_const->arg.i < 0x10000 ) {
+ EMIT_FALSE_CONST();
+ in( iCMPLWI, cr7, rSECOND, i_const->arg.i );
+ } else {
+ MAYBE_EMIT_CONST();
+ in( iCMPLW, cr7, rSECOND, rFIRST );
+ }
+ emitJump(
+ i_now->arg.i,
+ ( i_now->op == OP_GTU ? branchTrue : branchFalse ),
+ 4*cr7+gt, 0
+ );
+ gpr_pos -= 2;
+ break;
+
+ case OP_EQF:
+ case OP_NEF:
+ MAYBE_EMIT_CONST();
+ in( iFCMPU, cr7, fSECOND, fFIRST );
+ emitJump(
+ i_now->arg.i,
+ ( i_now->op == OP_EQF ? branchTrue : branchFalse ),
+ 4*cr7+eq, 0
+ );
+ fpr_pos -= 2;
+ break;
+
+ case OP_LTF:
+ case OP_GEF:
+ MAYBE_EMIT_CONST();
+ in( iFCMPU, cr7, fSECOND, fFIRST );
+ emitJump(
+ i_now->arg.i,
+ ( i_now->op == OP_LTF ? branchTrue : branchFalse ),
+ 4*cr7+lt, 0
+ );
+ fpr_pos -= 2;
+ break;
+
+ case OP_GTF:
+ case OP_LEF:
+ MAYBE_EMIT_CONST();
+ in( iFCMPU, cr7, fSECOND, fFIRST );
+ emitJump(
+ i_now->arg.i,
+ ( i_now->op == OP_GTF ? branchTrue : branchFalse ),
+ 4*cr7+gt, 0
+ );
+ fpr_pos -= 2;
+ break;
+
+ case OP_LOAD1:
+ MAYBE_EMIT_CONST();
+#if OPTIMIZE_MASK
+ in( iRLWINM, rFIRST, rFIRST, 0, fastMaskHi, fastMaskLo );
+#else
+ in( iLWZ, r0, VM_Data_Offset( dataMask ), rVMDATA );
+ in( iAND, rFIRST, rFIRST, r0 );
+#endif
+ in( iLBZX, rFIRST, rFIRST, rDATABASE );
+ break;
+
+ case OP_LOAD2:
+ MAYBE_EMIT_CONST();
+#if OPTIMIZE_MASK
+ in( iRLWINM, rFIRST, rFIRST, 0, fastMaskHi, fastMaskLo );
+#else
+ in( iLWZ, r0, VM_Data_Offset( dataMask ), rVMDATA );
+ in( iAND, rFIRST, rFIRST, r0 );
+#endif
+ in( iLHZX, rFIRST, rFIRST, rDATABASE );
+ break;
+
+ case OP_LOAD4:
+ MAYBE_EMIT_CONST();
+#if OPTIMIZE_MASK
+ in( iRLWINM, rFIRST, rFIRST, 0, fastMaskHi, fastMaskLo );
+#else
+ in( iLWZ, r0, VM_Data_Offset( dataMask ), rVMDATA );
+ in( iAND, rFIRST, rFIRST, r0 );
+#endif
+ if ( RET_INT ) {
+ in( iLWZX, rFIRST, rFIRST, rDATABASE );
+ } else {
+ fpr_pos++;
+ in( iLFSX, fFIRST, rFIRST, rDATABASE );
+ gpr_pos--;
+ }
+ break;
+
+ case OP_STORE1:
+ MAYBE_EMIT_CONST();
+#if OPTIMIZE_MASK
+ in( iRLWINM, rSECOND, rSECOND, 0, fastMaskHi, fastMaskLo );
+#else
+ in( iLWZ, r0, VM_Data_Offset( dataMask ), rVMDATA );
+ in( iAND, rSECOND, rSECOND, r0 );
+#endif
+ in( iSTBX, rFIRST, rSECOND, rDATABASE );
+ gpr_pos -= 2;
+ break;
+
+ case OP_STORE2:
+ MAYBE_EMIT_CONST();
+#if OPTIMIZE_MASK
+ in( iRLWINM, rSECOND, rSECOND, 0, fastMaskHi, fastMaskLo );
+#else
+ in( iLWZ, r0, VM_Data_Offset( dataMask ), rVMDATA );
+ in( iAND, rSECOND, rSECOND, r0 );
+#endif
+ in( iSTHX, rFIRST, rSECOND, rDATABASE );
+ gpr_pos -= 2;
+ break;
+
+ case OP_STORE4:
+ MAYBE_EMIT_CONST();
+ if ( ARG_INT ) {
+#if OPTIMIZE_MASK
+ in( iRLWINM, rSECOND, rSECOND, 0, fastMaskHi, fastMaskLo );
+#else
+ in( iLWZ, r0, VM_Data_Offset( dataMask ), rVMDATA );
+ in( iAND, rSECOND, rSECOND, r0 );
+#endif
+
+ in( iSTWX, rFIRST, rSECOND, rDATABASE );
+ gpr_pos--;
+ } else {
+#if OPTIMIZE_MASK
+ in( iRLWINM, rFIRST, rFIRST, 0, fastMaskHi, fastMaskLo );
+#else
+ in( iLWZ, r0, VM_Data_Offset( dataMask ), rVMDATA );
+ in( iAND, rFIRST, rFIRST, r0 );
+#endif
+
+ in( iSTFSX, fFIRST, rFIRST, rDATABASE );
+ fpr_pos--;
+ }
+ gpr_pos--;
+ break;
+
+ case OP_ARG:
+ MAYBE_EMIT_CONST();
+ in( iADDI, r0, rPSTACK, i_now->arg.b );
+ if ( ARG_INT ) {
+ in( iSTWX, rFIRST, rDATABASE, r0 );
+ gpr_pos--;
+ } else {
+ in( iSTFSX, fFIRST, rDATABASE, r0 );
+ fpr_pos--;
+ }
+ break;
+
+ case OP_BLOCK_COPY:
+ MAYBE_EMIT_CONST();
+#if OPTIMIZE_COPY
+ if ( i_now->arg.i <= SL( 16, 32 ) ) {
+ /* block is very short so copy it in-place */
+
+ unsigned int len = i_now->arg.i;
+ unsigned int copied = 0, left = len;
+
+ in( iADD, rFIRST, rFIRST, rDATABASE );
+ in( iADD, rSECOND, rSECOND, rDATABASE );
+
+ if ( len >= GPRLEN ) {
+ long int i, words = len / GPRLEN;
+ in( iLL, r0, 0, rFIRST );
+ for ( i = 1; i < words; i++ )
+ in( iLL, rTEMP( i - 1 ), GPRLEN * i, rFIRST );
+
+ in( iSTL, r0, 0, rSECOND );
+ for ( i = 1; i < words; i++ )
+ in( iSTL, rTEMP( i - 1 ), GPRLEN * i, rSECOND );
+
+ copied += words * GPRLEN;
+ left -= copied;
+ }
+
+ if ( SL( 0, left >= 4 ) ) {
+ in( iLWZ, r0, copied+0, rFIRST );
+ in( iSTW, r0, copied+0, rSECOND );
+ copied += 4;
+ left -= 4;
+ }
+ if ( left >= 4 ) {
+ DIE("Bug in OP_BLOCK_COPY");
+ }
+ if ( left == 3 ) {
+ in( iLHZ, r0, copied+0, rFIRST );
+ in( iLBZ, rTMP, copied+2, rFIRST );
+ in( iSTH, r0, copied+0, rSECOND );
+ in( iSTB, rTMP, copied+2, rSECOND );
+ } else if ( left == 2 ) {
+ in( iLHZ, r0, copied+0, rFIRST );
+ in( iSTH, r0, copied+0, rSECOND );
+ } else if ( left == 1 ) {
+ in( iLBZ, r0, copied+0, rFIRST );
+ in( iSTB, r0, copied+0, rSECOND );
+ }
+ } else
+#endif
+ {
+ unsigned long int r5_ori = 0;
+ if ( i_now->arg.si >= -0x8000 && i_now->arg.si < 0x8000 ) {
+ in( iLI, r5, i_now->arg.si );
+ } else if ( i_now->arg.i < 0x10000 ) {
+ in( iLI, r5, 0 );
+ r5_ori = i_now->arg.i;
+ } else {
+ in( iLIS, r5, i_now->arg.ss[ 0 ] );
+ r5_ori = i_now->arg.us[ 1 ];
+ }
+
+ in( iLL, r0, VM_Data_Offset( BlockCopy ), rVMDATA ); // get blockCopy pointer
+
+ if ( r5_ori )
+ in( iORI, r5, r5, r5_ori );
+
+ in( iMTCTR, r0 );
+
+ if ( rFIRST != r4 )
+ in( iMR, r4, rFIRST );
+ if ( rSECOND != r3 )
+ in( iMR, r3, rSECOND );
+
+ in( iBCTRL );
+ }
+
+ gpr_pos -= 2;
+ break;
+
+ case OP_SEX8:
+ MAYBE_EMIT_CONST();
+ in( iEXTSB, rFIRST, rFIRST );
+ break;
+
+ case OP_SEX16:
+ MAYBE_EMIT_CONST();
+ in( iEXTSH, rFIRST, rFIRST );
+ break;
+
+ case OP_NEGI:
+ MAYBE_EMIT_CONST();
+ in( iNEG, rFIRST, rFIRST );
+ break;
+
+ case OP_ADD:
+ if ( i_const ) {
+ EMIT_FALSE_CONST();
+
+ signed short int hi, lo;
+ hi = i_const->arg.ss[ 0 ];
+ lo = i_const->arg.ss[ 1 ];
+ if ( lo < 0 )
+ hi += 1;
+
+ if ( hi != 0 )
+ in( iADDIS, rSECOND, rSECOND, hi );
+ if ( lo != 0 )
+ in( iADDI, rSECOND, rSECOND, lo );
+
+ // if both are zero no instruction will be written
+ if ( hi == 0 && lo == 0 )
+ force_emit = 1;
+ } else {
+ MAYBE_EMIT_CONST();
+ in( iADD, rSECOND, rSECOND, rFIRST );
+ }
+ gpr_pos--;
+ break;
+
+ case OP_SUB:
+ MAYBE_EMIT_CONST();
+ in( iSUB, rSECOND, rSECOND, rFIRST );
+ gpr_pos--;
+ break;
+
+ case OP_DIVI:
+ MAYBE_EMIT_CONST();
+ in( iDIVW, rSECOND, rSECOND, rFIRST );
+ gpr_pos--;
+ break;
+
+ case OP_DIVU:
+ MAYBE_EMIT_CONST();
+ in( iDIVWU, rSECOND, rSECOND, rFIRST );
+ gpr_pos--;
+ break;
+
+ case OP_MODI:
+ MAYBE_EMIT_CONST();
+ in( iDIVW, r0, rSECOND, rFIRST );
+ in( iMULLW, r0, r0, rFIRST );
+ in( iSUB, rSECOND, rSECOND, r0 );
+ gpr_pos--;
+ break;
+
+ case OP_MODU:
+ MAYBE_EMIT_CONST();
+ in( iDIVWU, r0, rSECOND, rFIRST );
+ in( iMULLW, r0, r0, rFIRST );
+ in( iSUB, rSECOND, rSECOND, r0 );
+ gpr_pos--;
+ break;
+
+ case OP_MULI:
+ case OP_MULU:
+ MAYBE_EMIT_CONST();
+ in( iMULLW, rSECOND, rSECOND, rFIRST );
+ gpr_pos--;
+ break;
+
+ case OP_BAND:
+ MAYBE_EMIT_CONST();
+ in( iAND, rSECOND, rSECOND, rFIRST );
+ gpr_pos--;
+ break;
+
+ case OP_BOR:
+ MAYBE_EMIT_CONST();
+ in( iOR, rSECOND, rSECOND, rFIRST );
+ gpr_pos--;
+ break;
+
+ case OP_BXOR:
+ MAYBE_EMIT_CONST();
+ in( iXOR, rSECOND, rSECOND, rFIRST );
+ gpr_pos--;
+ break;
+
+ case OP_BCOM:
+ MAYBE_EMIT_CONST();
+ in( iNOT, rFIRST, rFIRST );
+ break;
+
+ case OP_LSH:
+ MAYBE_EMIT_CONST();
+ in( iSLW, rSECOND, rSECOND, rFIRST );
+ gpr_pos--;
+ break;
+
+ case OP_RSHI:
+ MAYBE_EMIT_CONST();
+ in( iSRAW, rSECOND, rSECOND, rFIRST );
+ gpr_pos--;
+ break;
+
+ case OP_RSHU:
+ MAYBE_EMIT_CONST();
+ in( iSRW, rSECOND, rSECOND, rFIRST );
+ gpr_pos--;
+ break;
+
+ case OP_NEGF:
+ MAYBE_EMIT_CONST();
+ in( iFNEG, fFIRST, fFIRST );
+ break;
+
+ case OP_ADDF:
+ MAYBE_EMIT_CONST();
+ in( iFADDS, fSECOND, fSECOND, fFIRST );
+ fpr_pos--;
+ break;
+
+ case OP_SUBF:
+ MAYBE_EMIT_CONST();
+ in( iFSUBS, fSECOND, fSECOND, fFIRST );
+ fpr_pos--;
+ break;
+
+ case OP_DIVF:
+ MAYBE_EMIT_CONST();
+ in( iFDIVS, fSECOND, fSECOND, fFIRST );
+ fpr_pos--;
+ break;
+
+ case OP_MULF:
+ MAYBE_EMIT_CONST();
+ in( iFMULS, fSECOND, fSECOND, fFIRST );
+ fpr_pos--;
+ break;
+
+ case OP_CVIF:
+ MAYBE_EMIT_CONST();
+ fpr_pos++;
+ in( iXORIS, rFIRST, rFIRST, 0x8000 );
+ in( iLIS, r0, 0x4330 );
+ in( iSTW, rFIRST, stack_temp + 4, r1 );
+ in( iSTW, r0, stack_temp, r1 );
+ in( iLFS, fTMP, VM_Data_Offset( floatBase ), rVMDATA );
+ in( iLFD, fFIRST, stack_temp, r1 );
+ in( iFSUB, fFIRST, fFIRST, fTMP );
+ in( iFRSP, fFIRST, fFIRST );
+ gpr_pos--;
+ break;
+
+ case OP_CVFI:
+ MAYBE_EMIT_CONST();
+ gpr_pos++;
+ in( iFCTIWZ, fFIRST, fFIRST );
+ in( iSTFD, fFIRST, stack_temp, r1 );
+ in( iLWZ, rFIRST, stack_temp + 4, r1 );
+ fpr_pos--;
+ break;
+ }
+
+ i_const = NULL;
+
+ if ( i_now->op != OP_CONST ) {
+ // emit the instructions if it isn't OP_CONST
+ emitEnd();
+ } else {
+ // mark in what register the value should be saved
+ if ( RET_INT )
+ i_now->regPos = ++gpr_pos;
+ else
+ i_now->regPos = ++fpr_pos;
+
+#if OPTIMIZE_HOLE
+ i_const = i_now;
+#else
+ PPC_EmitConst( i_now );
+#endif
+ }
+ }
+ if ( i_const )
+ DIE( "left (unused) OP_CONST" );
+
+ {
+ // free opcode information, don't free first dummy one
+ source_instruction_t *i_next = i_first->next;
+ while ( i_next ) {
+ i_now = i_next;
+ i_next = i_now->next;
+ PPC_Free( i_now );
+ }
+ }
+}
+
+
+/*
+ * check which jumps are short enough to use signed 16bit immediate branch
+ */
+static void
+PPC_ShrinkJumps( void )
+{
+ symbolic_jump_t *sj_now = sj_first;
+ while ( (sj_now = sj_now->nextJump) ) {
+ if ( sj_now->bo == branchAlways )
+ // non-conditional branch has 26bit immediate
+ sj_now->parent->length = 1;
+
+ else {
+ dest_instruction_t *di = di_pointers[ sj_now->jump_to ];
+ dest_instruction_t *ji = sj_now->parent;
+ long int jump_length = 0;
+ if ( ! di )
+ DIE( "No instruction to jump to" );
+ if ( ji->count > di->count ) {
+ do {
+ jump_length += di->length;
+ } while ( ( di = di->next ) != ji );
+ } else {
+ jump_length = 1;
+ while ( ( ji = ji->next ) != di )
+ jump_length += ji->length;
+ }
+ if ( jump_length < 0x2000 )
+ // jump is short, use normal instruction
+ sj_now->parent->length = 1;
+ }
+ }
+}
+
+/*
+ * puts all the data in one place, it consists of many different tasks
+ */
+static void
+PPC_ComputeCode( vm_t *vm )
+{
+ dest_instruction_t *di_now = di_first;
+
+ unsigned long int codeInstructions = 0;
+ // count total instruciton number
+ while ( (di_now = di_now->next ) )
+ codeInstructions += di_now->length;
+
+ size_t codeLength = sizeof( vm_data_t )
+ + sizeof( unsigned int ) * data_acc
+ + sizeof( ppc_instruction_t ) * codeInstructions;
+
+ // get the memory for the generated code, smarter ppcs need the
+ // mem to be marked as executable (whill change later)
+ unsigned char *dataAndCode = mmap( NULL, codeLength,
+ PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0 );
+
+ if ( ! dataAndCode )
+ DIE( "Not enough memory" );
+
+ ppc_instruction_t *codeNow, *codeBegin;
+ codeNow = codeBegin = (ppc_instruction_t *)( dataAndCode + VM_Data_Offset( data[ data_acc ] ) );
+
+ ppc_instruction_t nop = IN( iNOP );
+
+ // copy instructions to the destination
+ // fills the jump instructions with nops
+ // saves pointers of all instructions
+ di_now = di_first;
+ while ( (di_now = di_now->next ) ) {
+ unsigned long int i_count = di_now->i_count;
+ if ( i_count != FALSE_ICOUNT ) {
+ if ( ! di_pointers[ i_count ] )
+ di_pointers[ i_count ] = (void *) codeNow;
+ }
+
+ if ( di_now->jump == NULL ) {
+ memcpy( codeNow, &(di_now->code[0]), di_now->length * sizeof( ppc_instruction_t ) );
+ codeNow += di_now->length;
+ } else {
+ long int i;
+ symbolic_jump_t *sj;
+ for ( i = 0; i < di_now->length; i++ )
+ codeNow[ i ] = nop;
+ codeNow += di_now->length;
+
+ sj = di_now->jump;
+ // save position of jumping instruction
+ sj->parent = (void *)(codeNow - 1);
+ }
+ }
+
+ // compute the jumps and write corresponding instructions
+ symbolic_jump_t *sj_now = sj_first;
+ while ( (sj_now = sj_now->nextJump ) ) {
+ ppc_instruction_t *jumpFrom = (void *) sj_now->parent;
+ ppc_instruction_t *jumpTo = (void *) di_pointers[ sj_now->jump_to ];
+ signed long int jumpLength = jumpTo - jumpFrom;
+
+ // if jump is short, just write it
+ if ( jumpLength >= - 8192 && jumpLength < 8192 ) {
+ powerpc_iname_t branchConditional = sj_now->ext & branchExtLink ? iBCL : iBC;
+ *jumpFrom = IN( branchConditional, sj_now->bo, sj_now->bi, jumpLength * 4 );
+ continue;
+ }
+
+ // jump isn't short so write it as two instructions
+ //
+ // the letter one is a non-conditional branch instruction which
+ // accepts immediate values big enough (26 bits)
+ *jumpFrom = IN( (sj_now->ext & branchExtLink ? iBL : iB), jumpLength * 4 );
+ if ( sj_now->bo == branchAlways )
+ continue;
+
+ // there should have been additional space prepared for this case
+ if ( jumpFrom[ -1 ] != nop )
+ DIE( "additional space for long jump not prepared" );
+
+ // invert instruction condition
+ long int bo = 0;
+ switch ( sj_now->bo ) {
+ case branchTrue:
+ bo = branchFalse;
+ break;
+ case branchFalse:
+ bo = branchTrue;
+ break;
+ default:
+ DIE( "unrecognized branch type" );
+ break;
+ }
+
+ // the former instruction is an inverted conditional branch which
+ // jumps over the non-conditional one
+ jumpFrom[ -1 ] = IN( iBC, bo, sj_now->bi, +2*4 );
+ }
+
+ vm->codeBase = dataAndCode;
+ vm->codeLength = codeLength;
+
+ vm_data_t *data = (vm_data_t *)dataAndCode;
+
+#if ELF64
+ // prepare Official Procedure Descriptor for the generated code
+ // and retrieve real function pointer for helper functions
+
+ opd_t *ac = (void *)VM_AsmCall, *bc = (void *)VM_BlockCopy;
+ data->opd.function = codeBegin;
+ // trick it into using the same TOC
+ // this way we won't have to switch TOC before calling AsmCall or BlockCopy
+ data->opd.toc = ac->toc;
+ data->opd.env = ac->env;
+
+ data->AsmCall = ac->function;
+ data->BlockCopy = bc->function;
+#else
+ data->AsmCall = VM_AsmCall;
+ data->BlockCopy = VM_BlockCopy;
+#endif
+
+ data->dataMask = vm->dataMask;
+ data->iPointers = (ppc_instruction_t *)vm->instructionPointers;
+ data->dataLength = VM_Data_Offset( data[ data_acc ] );
+ data->codeLength = ( codeNow - codeBegin ) * sizeof( ppc_instruction_t );
+ data->floatBase = 0x59800004;
+
+
+ /* write dynamic data (float constants) */
+ {
+ local_data_t *d_next, *d_now = data_first;
+ long int accumulated = 0;
+
+ do {
+ long int i;
+ for ( i = 0; i < d_now->count; i++ )
+ data->data[ accumulated + i ] = d_now->data[ i ];
+
+ accumulated += d_now->count;
+ d_next = d_now->next;
+ PPC_Free( d_now );
+
+ if ( !d_next )
+ break;
+ d_now = d_next;
+ } while (1);
+ data_first = NULL;
+ }
+
+ /* free most of the compilation memory */
+ {
+ di_now = di_first->next;
+ PPC_Free( di_first );
+ PPC_Free( sj_first );
+
+ while ( di_now ) {
+ di_first = di_now->next;
+ if ( di_now->jump )
+ PPC_Free( di_now->jump );
+ PPC_Free( di_now );
+ di_now = di_first;
+ }
+ }
+
+ return;
+}
+
+static void
+VM_Destroy_Compiled( vm_t *self )
+{
+ if ( self->codeBase ) {
+ if ( munmap( self->codeBase, self->codeLength ) )
+ Com_Printf( S_COLOR_RED "Memory unmap failed, possible memory leak\n" );
+ }
+ self->codeBase = NULL;
+}
+
+void
+VM_Compile( vm_t *vm, vmHeader_t *header )
+{
+ long int pc = 0;
+ unsigned long int i_count;
+ char* code;
+ struct timeval tvstart = {0, 0};
+ source_instruction_t *i_first /* dummy */, *i_last = NULL, *i_now;
+
+ vm->compiled = qfalse;
+
+ gettimeofday(&tvstart, NULL);
+
+ PPC_MakeFastMask( vm->dataMask );
+
+ i_first = PPC_Malloc( sizeof( source_instruction_t ) );
+ i_first->next = NULL;
+
+ // realloc instructionPointers with correct size
+ // use Z_Malloc so vm.c will be able to free the memory
+ if ( sizeof( void * ) != sizeof( int ) ) {
+ Z_Free( vm->instructionPointers );
+ vm->instructionPointers = Z_Malloc( header->instructionCount * sizeof( void * ) );
+ }
+ di_pointers = (void *)vm->instructionPointers;
+ memset( di_pointers, 0, header->instructionCount * sizeof( void * ) );
+
+
+ PPC_CompileInit();
+
+ /*
+ * read the input program
+ * divide it into functions and send each function to compiler
+ */
+ code = (char *)header + header->codeOffset;
+ for ( i_count = 0; i_count < header->instructionCount; ++i_count )
+ {
+ unsigned char op = code[ pc++ ];
+
+ if ( op == OP_ENTER ) {
+ if ( i_first->next )
+ VM_CompileFunction( i_first );
+ i_first->next = NULL;
+ i_last = i_first;
+ }
+
+ i_now = PPC_Malloc( sizeof( source_instruction_t ) );
+ i_now->op = op;
+ i_now->i_count = i_count;
+ i_now->arg.i = 0;
+ i_now->regA1 = 0;
+ i_now->regA2 = 0;
+ i_now->regR = 0;
+ i_now->regPos = 0;
+ i_now->next = NULL;
+
+ if ( vm_opInfo[op] & opImm4 ) {
+ union {
+ unsigned char b[4];
+ unsigned int i;
+ } c = { { code[ pc + 3 ], code[ pc + 2 ], code[ pc + 1 ], code[ pc + 0 ] }, };
+
+ i_now->arg.i = c.i;
+ pc += 4;
+ } else if ( vm_opInfo[op] & opImm1 ) {
+ i_now->arg.b = code[ pc++ ];
+ }
+
+ i_last->next = i_now;
+ i_last = i_now;
+ }
+ VM_CompileFunction( i_first );
+ PPC_Free( i_first );
+
+ PPC_ShrinkJumps();
+ memset( di_pointers, 0, header->instructionCount * sizeof( void * ) );
+ PPC_ComputeCode( vm );
+
+ /* check for uninitialized pointers */
+#ifdef DEBUG_VM
+ long int i;
+ for ( i = 0; i < header->instructionCount; i++ )
+ if ( di_pointers[ i ] == 0 )
+ Com_Printf( S_COLOR_RED "Pointer %ld not initialized !\n", i );
+#endif
+
+ /* mark memory as executable and not writeable */
+ if ( mprotect( vm->codeBase, vm->codeLength, PROT_READ|PROT_EXEC ) ) {
+
+ // it has failed, make sure memory is unmapped before throwing the error
+ VM_Destroy_Compiled( vm );
+ DIE( "mprotect failed" );
+ }
+
+ vm->destroy = VM_Destroy_Compiled;
+ vm->compiled = qtrue;
+
+ {
+ struct timeval tvdone = {0, 0};
+ struct timeval dur = {0, 0};
+ Com_Printf( "VM file %s compiled to %i bytes of code (%p - %p)\n",
+ vm->name, vm->codeLength, vm->codeBase, vm->codeBase+vm->codeLength );
+
+ gettimeofday(&tvdone, NULL);
+ timersub(&tvdone, &tvstart, &dur);
+ Com_Printf( "compilation took %lu.%06lu seconds\n",
+ (long unsigned int)dur.tv_sec, (long unsigned int)dur.tv_usec );
+ }
+}
+
+int
+VM_CallCompiled( vm_t *vm, int *args )
+{
+ int retVal;
+ int *argPointer;
+
+ vm_data_t *vm_dataAndCode = (void *)( vm->codeBase );
+ int programStack = vm->programStack;
+ int stackOnEntry = programStack;
+
+ byte *image = vm->dataBase;
+
+ currentVM = vm;
+
+ vm->currentlyInterpreting = qtrue;
+
+ programStack -= 48;
+ argPointer = (int *)&image[ programStack + 8 ];
+ memcpy( argPointer, args, 4 * 9 );
+ argPointer[ -1 ] = 0;
+ argPointer[ -2 ] = -1;
+
+#ifdef VM_TIMES
+ struct tms start_time, stop_time;
+ clock_t time_diff;
+
+ times( &start_time );
+ time_outside_vm = 0;
+#endif
+
+ /* call generated code */
+ {
+ int ( *entry )( void *, int, void * );
+#ifdef __PPC64__
+ entry = (void *)&(vm_dataAndCode->opd);
+#else
+ entry = (void *)(vm->codeBase + vm_dataAndCode->dataLength);
+#endif
+ retVal = entry( vm->codeBase, programStack, vm->dataBase );
+ }
+
+#ifdef VM_TIMES
+ times( &stop_time );
+ time_diff = stop_time.tms_utime - start_time.tms_utime;
+ time_total_vm += time_diff - time_outside_vm;
+ if ( time_diff > 100 ) {
+ printf( "App clock: %ld, vm total: %ld, vm this: %ld, vm real: %ld, vm out: %ld\n"
+ "Inside VM %f%% of app time\n",
+ stop_time.tms_utime,
+ time_total_vm,
+ time_diff,
+ time_diff - time_outside_vm,
+ time_outside_vm,
+ (double)100 * time_total_vm / stop_time.tms_utime );
+ }
+#endif
+
+ vm->programStack = stackOnEntry;
+ vm->currentlyInterpreting = qfalse;
+
+ return retVal;
+}
diff --git a/src/qcommon/vm_powerpc_asm.c b/src/qcommon/vm_powerpc_asm.c
new file mode 100644
index 00000000..64c59771
--- /dev/null
+++ b/src/qcommon/vm_powerpc_asm.c
@@ -0,0 +1,1009 @@
+/*
+===========================================================================
+Copyright (C) 2008 Przemyslaw Iskra <sparky@pld-linux.org>
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+
+ * File includes code from GNU binutils, exactly:
+ * - include/opcode/ppc.h - licensed under GPL v1 or later
+ * - opcodes/ppc-opc.c - licensed under GPL v2 or later
+ *
+ * ppc.h -- Header file for PowerPC opcode table
+ * Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ * 2007 Free Software Foundation, Inc.
+ * Written by Ian Lance Taylor, Cygnus Suppor
+ *
+ * This file is part of GDB, GAS, and the GNU binutils.
+ *
+ * ppc-opc.c -- PowerPC opcode list
+ * Copyright 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004,
+ * 2005, 2006, 2007 Free Software Foundation, Inc.
+ * Written by Ian Lance Taylor, Cygnus Support
+ *
+ * This file is part of GDB, GAS, and the GNU binutils.
+ *
+ */
+
+#include "vm_powerpc_asm.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+/* return nop on error */
+#define ASM_ERROR_OPC (0x60000000)
+
+/*
+ * BEGIN OF ppc.h
+ */
+
+#define ppc_cpu_t int
+
+struct powerpc_opcode
+{
+ const char *name;
+ unsigned long opcode;
+ unsigned long mask;
+ ppc_cpu_t flags;
+ unsigned char operands[8];
+};
+
+static const struct powerpc_opcode powerpc_opcodes[];
+static const int powerpc_num_opcodes;
+
+#define PPC_OPCODE_PPC 1
+#define PPC_OPCODE_POWER 2
+#define PPC_OPCODE_POWER2 4
+#define PPC_OPCODE_32 8
+#define PPC_OPCODE_64 0x10
+#define PPC_OPCODE_601 0x20
+#define PPC_OPCODE_COMMON 0x40
+#define PPC_OPCODE_ANY 0x80
+#define PPC_OPCODE_64_BRIDGE 0x100
+#define PPC_OPCODE_ALTIVEC 0x200
+#define PPC_OPCODE_403 0x400
+#define PPC_OPCODE_BOOKE 0x800
+#define PPC_OPCODE_BOOKE64 0x1000
+#define PPC_OPCODE_440 0x2000
+#define PPC_OPCODE_POWER4 0x4000
+#define PPC_OPCODE_NOPOWER4 0x8000
+#define PPC_OPCODE_CLASSIC 0x10000
+#define PPC_OPCODE_SPE 0x20000
+#define PPC_OPCODE_ISEL 0x40000
+#define PPC_OPCODE_EFS 0x80000
+#define PPC_OPCODE_BRLOCK 0x100000
+#define PPC_OPCODE_PMR 0x200000
+#define PPC_OPCODE_CACHELCK 0x400000
+#define PPC_OPCODE_RFMCI 0x800000
+#define PPC_OPCODE_POWER5 0x1000000
+#define PPC_OPCODE_E300 0x2000000
+#define PPC_OPCODE_POWER6 0x4000000
+#define PPC_OPCODE_CELL 0x8000000
+#define PPC_OPCODE_PPCPS 0x10000000
+#define PPC_OPCODE_E500MC 0x20000000
+#define PPC_OPCODE_405 0x40000000
+#define PPC_OPCODE_VSX 0x80000000
+
+#define PPC_OP(i) (((i) >> 26) & 0x3f)
+
+struct powerpc_operand
+{
+ unsigned int bitm;
+ int shift;
+ unsigned long (*insert)
+ (unsigned long, long, int, const char **);
+ unsigned long flags;
+};
+
+static const struct powerpc_operand powerpc_operands[];
+static const unsigned int num_powerpc_operands;
+
+#define PPC_OPERAND_SIGNED (0x1)
+#define PPC_OPERAND_SIGNOPT (0x2)
+#define PPC_OPERAND_FAKE (0x4)
+#define PPC_OPERAND_PARENS (0x8)
+#define PPC_OPERAND_CR (0x10)
+#define PPC_OPERAND_GPR (0x20)
+#define PPC_OPERAND_GPR_0 (0x40)
+#define PPC_OPERAND_FPR (0x80)
+#define PPC_OPERAND_RELATIVE (0x100)
+#define PPC_OPERAND_ABSOLUTE (0x200)
+#define PPC_OPERAND_OPTIONAL (0x400)
+#define PPC_OPERAND_NEXT (0x800)
+#define PPC_OPERAND_NEGATIVE (0x1000)
+#define PPC_OPERAND_VR (0x2000)
+#define PPC_OPERAND_DS (0x4000)
+#define PPC_OPERAND_DQ (0x8000)
+#define PPC_OPERAND_PLUS1 (0x10000)
+#define PPC_OPERAND_FSL (0x20000)
+#define PPC_OPERAND_FCR (0x40000)
+#define PPC_OPERAND_UDI (0x80000)
+#define PPC_OPERAND_VSR (0x100000)
+
+/*
+ * END OF ppc.h
+ */
+
+#define PPC_DEST_ARCH PPC_OPCODE_PPC
+
+ppc_instruction_t
+asm_instruction( powerpc_iname_t sname, const int argc, const long int *argv )
+{
+ const char *errmsg = NULL;
+ const char *name;
+ unsigned long int ret;
+ const struct powerpc_opcode *opcode = NULL;
+ int argi, argj;
+
+ opcode = &powerpc_opcodes[ sname ];
+ name = opcode->name;
+
+ if ( ! opcode ) {
+ printf( "Can't find opcode %d\n", sname );
+ return ASM_ERROR_OPC;
+ }
+ if ( ( opcode->flags & PPC_DEST_ARCH ) != PPC_DEST_ARCH ) {
+ printf( "opcode %s not defined for this arch\n", name );
+ return ASM_ERROR_OPC;
+ }
+
+ ret = opcode->opcode;
+
+ argi = argj = 0;
+ while ( opcode->operands[ argi ] != 0 ) {
+ long int op = 0;
+ const struct powerpc_operand *operand = &powerpc_operands[ opcode->operands[ argi ] ];
+
+ if ( ! (operand->flags & PPC_OPERAND_FAKE) ) {
+ if ( argj >= argc ) {
+ printf( "Not enough arguments for %s, got %d\n", name, argc );
+ return ASM_ERROR_OPC;
+ }
+
+ op = argv[ argj++ ];
+ }
+
+ if ( operand->insert ) {
+ errmsg = NULL;
+ ret = operand->insert( ret, op, PPC_DEST_ARCH, &errmsg );
+ if ( errmsg ) {
+ printf( "%s: error while inserting operand %d (0x%.2lx): %s\n",
+ name, argi, op, errmsg );
+ }
+ } else {
+ unsigned long int opu = *(unsigned long int *)&op;
+ unsigned long int bitm = operand->bitm;
+ unsigned long int bitm_full = bitm | ( bitm & 1 ? 0 : 0xf );
+
+ if ( operand->flags & PPC_OPERAND_SIGNED ) {
+ bitm_full >>= 1;
+
+ if ( ( opu & ~bitm_full ) != 0 && ( opu | bitm_full ) != -1 )
+ printf( "%s: signed operand nr.%d to wide. op: %.8lx, mask: %.8lx\n",
+ name, argi, opu, bitm );
+ } else {
+ if ( ( opu & ~bitm_full ) != 0 )
+ printf( "%s: unsigned operand nr.%d to wide. op: %.8lx, mask: %.8lx\n",
+ name, argi, opu, bitm );
+ }
+ if ( (bitm & 1) == 0 ) {
+ if ( opu & 0xf & ~bitm )
+ printf( "%s: operand nr.%d not aligned correctly. op: %.8lx, mask: %.8lx\n",
+ name, argi, opu, bitm );
+ }
+
+ ret |= ( op & operand->bitm ) << operand->shift;
+ }
+ argi++;
+ }
+ if ( argc > argj ) {
+ printf( "Too many arguments for %s, got %d\n", name, argc );
+ return ASM_ERROR_OPC;
+ }
+
+ return ret;
+}
+
+
+/*
+ * BEGIN OF ppc-opc.c
+ */
+
+#define ATTRIBUTE_UNUSED
+#define _(x) (x)
+
+/* Local insertion and extraction functions. */
+
+static unsigned long insert_bdm (unsigned long, long, int, const char **);
+static unsigned long insert_bo (unsigned long, long, int, const char **);
+static unsigned long insert_ras (unsigned long, long, int, const char **);
+static unsigned long insert_rbs (unsigned long, long, int, const char **);
+
+/* The operands table.
+
+ The fields are bitm, shift, insert, extract, flags.
+ */
+
+static const struct powerpc_operand powerpc_operands[] =
+{
+ /* The zero index is used to indicate the end of the list of
+ operands. */
+#define UNUSED 0
+ { 0, 0, NULL, 0 },
+
+ /* The BA field in an XL form instruction. */
+#define BA UNUSED + 1
+ /* The BI field in a B form or XL form instruction. */
+#define BI BA
+#define BI_MASK (0x1f << 16)
+ { 0x1f, 16, NULL, PPC_OPERAND_CR },
+
+ /* The BD field in a B form instruction. The lower two bits are
+ forced to zero. */
+#define BD BA + 1
+ { 0xfffc, 0, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+ /* The BD field in a B form instruction when the - modifier is used.
+ This sets the y bit of the BO field appropriately. */
+#define BDM BD + 1
+ { 0xfffc, 0, insert_bdm,
+ PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+ /* The BF field in an X or XL form instruction. */
+#define BF BDM + 1
+ /* The CRFD field in an X form instruction. */
+#define CRFD BF
+ { 0x7, 23, NULL, PPC_OPERAND_CR },
+
+ /* An optional BF field. This is used for comparison instructions,
+ in which an omitted BF field is taken as zero. */
+#define OBF BF + 1
+ { 0x7, 23, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+
+ /* The BO field in a B form instruction. Certain values are
+ illegal. */
+#define BO OBF + 1
+#define BO_MASK (0x1f << 21)
+ { 0x1f, 21, insert_bo, 0 },
+
+ /* The condition register number portion of the BI field in a B form
+ or XL form instruction. This is used for the extended
+ conditional branch mnemonics, which set the lower two bits of the
+ BI field. This field is optional. */
+#define CR BO + 1
+ { 0x7, 18, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+
+ /* The D field in a D form instruction. This is a displacement off
+ a register, and implies that the next operand is a register in
+ parentheses. */
+#define D CR + 1
+ { 0xffff, 0, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+
+ /* The DS field in a DS form instruction. This is like D, but the
+ lower two bits are forced to zero. */
+#define DS D + 1
+ { 0xfffc, 0, NULL,
+ PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DS },
+
+ /* The FRA field in an X or A form instruction. */
+#define FRA DS + 1
+#define FRA_MASK (0x1f << 16)
+ { 0x1f, 16, NULL, PPC_OPERAND_FPR },
+
+ /* The FRB field in an X or A form instruction. */
+#define FRB FRA + 1
+#define FRB_MASK (0x1f << 11)
+ { 0x1f, 11, NULL, PPC_OPERAND_FPR },
+
+ /* The FRC field in an A form instruction. */
+#define FRC FRB + 1
+#define FRC_MASK (0x1f << 6)
+ { 0x1f, 6, NULL, PPC_OPERAND_FPR },
+
+ /* The FRS field in an X form instruction or the FRT field in a D, X
+ or A form instruction. */
+#define FRS FRC + 1
+#define FRT FRS
+ { 0x1f, 21, NULL, PPC_OPERAND_FPR },
+
+ /* The LI field in an I form instruction. The lower two bits are
+ forced to zero. */
+#define LI FRS + 1
+ { 0x3fffffc, 0, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+ /* The ME field in an M form instruction. */
+#define ME LI + 1
+#define ME_MASK (0x1f << 1)
+ { 0x1f, 1, NULL, 0 },
+
+ /* The MB and ME fields in an M form instruction expressed a single
+ operand which is a bitmask indicating which bits to select. This
+ is a two operand form using PPC_OPERAND_NEXT. See the
+ description in opcode/ppc.h for what this means. */
+#define MBE ME + 1
+ { 0x1f, 6, NULL, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT },
+
+ /* The RA field in an D, DS, DQ, X, XO, M, or MDS form instruction. */
+#define RA MBE + 1
+#define RA_MASK (0x1f << 16)
+ { 0x1f, 16, NULL, PPC_OPERAND_GPR },
+
+ /* As above, but 0 in the RA field means zero, not r0. */
+#define RA0 RA + 1
+ { 0x1f, 16, NULL, PPC_OPERAND_GPR_0 },
+
+ /* The RA field in a D or X form instruction which is an updating
+ store or an updating floating point load, which means that the RA
+ field may not be zero. */
+#define RAS RA0 + 1
+ { 0x1f, 16, insert_ras, PPC_OPERAND_GPR_0 },
+
+ /* The RB field in an X, XO, M, or MDS form instruction. */
+#define RB RAS + 1
+#define RB_MASK (0x1f << 11)
+ { 0x1f, 11, NULL, PPC_OPERAND_GPR },
+
+ /* The RB field in an X form instruction when it must be the same as
+ the RS field in the instruction. This is used for extended
+ mnemonics like mr. */
+#define RBS RB + 1
+ { 0x1f, 11, insert_rbs, PPC_OPERAND_FAKE },
+
+ /* The RS field in a D, DS, X, XFX, XS, M, MD or MDS form
+ instruction or the RT field in a D, DS, X, XFX or XO form
+ instruction. */
+#define RS RBS + 1
+#define RT RS
+#define RT_MASK (0x1f << 21)
+ { 0x1f, 21, NULL, PPC_OPERAND_GPR },
+
+ /* The SH field in an X or M form instruction. */
+#define SH RS + 1
+#define SH_MASK (0x1f << 11)
+ /* The other UIMM field in a EVX form instruction. */
+#define EVUIMM SH
+ { 0x1f, 11, NULL, 0 },
+
+ /* The SI field in a D form instruction. */
+#define SI SH + 1
+ { 0xffff, 0, NULL, PPC_OPERAND_SIGNED },
+
+ /* The UI field in a D form instruction. */
+#define UI SI + 1
+ { 0xffff, 0, NULL, 0 },
+
+};
+
+static const unsigned int num_powerpc_operands =
+ (sizeof (powerpc_operands) / sizeof (powerpc_operands[0]));
+
+/* The functions used to insert and extract complicated operands. */
+
+/* The BD field in a B form instruction when the - modifier is used.
+ This modifier means that the branch is not expected to be taken.
+ For chips built to versions of the architecture prior to version 2
+ (ie. not Power4 compatible), we set the y bit of the BO field to 1
+ if the offset is negative. When extracting, we require that the y
+ bit be 1 and that the offset be positive, since if the y bit is 0
+ we just want to print the normal form of the instruction.
+ Power4 compatible targets use two bits, "a", and "t", instead of
+ the "y" bit. "at" == 00 => no hint, "at" == 01 => unpredictable,
+ "at" == 10 => not taken, "at" == 11 => taken. The "t" bit is 00001
+ in BO field, the "a" bit is 00010 for branch on CR(BI) and 01000
+ for branch on CTR. We only handle the taken/not-taken hint here.
+ Note that we don't relax the conditions tested here when
+ disassembling with -Many because insns using extract_bdm and
+ extract_bdp always occur in pairs. One or the other will always
+ be valid. */
+
+static unsigned long
+insert_bdm (unsigned long insn,
+ long value,
+ int dialect,
+ const char **errmsg ATTRIBUTE_UNUSED)
+{
+ if ((dialect & PPC_OPCODE_POWER4) == 0)
+ {
+ if ((value & 0x8000) != 0)
+ insn |= 1 << 21;
+ }
+ else
+ {
+ if ((insn & (0x14 << 21)) == (0x04 << 21))
+ insn |= 0x02 << 21;
+ else if ((insn & (0x14 << 21)) == (0x10 << 21))
+ insn |= 0x08 << 21;
+ }
+ return insn | (value & 0xfffc);
+}
+
+
+/* Check for legal values of a BO field. */
+
+static int
+valid_bo (long value, int dialect, int extract)
+{
+ if ((dialect & PPC_OPCODE_POWER4) == 0)
+ {
+ int valid;
+ /* Certain encodings have bits that are required to be zero.
+ These are (z must be zero, y may be anything):
+ 001zy
+ 011zy
+ 1z00y
+ 1z01y
+ 1z1zz
+ */
+ switch (value & 0x14)
+ {
+ default:
+ case 0:
+ valid = 1;
+ break;
+ case 0x4:
+ valid = (value & 0x2) == 0;
+ break;
+ case 0x10:
+ valid = (value & 0x8) == 0;
+ break;
+ case 0x14:
+ valid = value == 0x14;
+ break;
+ }
+ /* When disassembling with -Many, accept power4 encodings too. */
+ if (valid
+ || (dialect & PPC_OPCODE_ANY) == 0
+ || !extract)
+ return valid;
+ }
+
+ /* Certain encodings have bits that are required to be zero.
+ These are (z must be zero, a & t may be anything):
+ 0000z
+ 0001z
+ 0100z
+ 0101z
+ 001at
+ 011at
+ 1a00t
+ 1a01t
+ 1z1zz
+ */
+ if ((value & 0x14) == 0)
+ return (value & 0x1) == 0;
+ else if ((value & 0x14) == 0x14)
+ return value == 0x14;
+ else
+ return 1;
+}
+
+/* The BO field in a B form instruction. Warn about attempts to set
+ the field to an illegal value. */
+
+static unsigned long
+insert_bo (unsigned long insn,
+ long value,
+ int dialect,
+ const char **errmsg)
+{
+ if (!valid_bo (value, dialect, 0))
+ *errmsg = _("invalid conditional option");
+ return insn | ((value & 0x1f) << 21);
+}
+
+/* The RA field in a D or X form instruction which is an updating
+ store or an updating floating point load, which means that the RA
+ field may not be zero. */
+
+static unsigned long
+insert_ras (unsigned long insn,
+ long value,
+ int dialect ATTRIBUTE_UNUSED,
+ const char **errmsg)
+{
+ if (value == 0)
+ *errmsg = _("invalid register operand when updating");
+ return insn | ((value & 0x1f) << 16);
+}
+
+/* The RB field in an X form instruction when it must be the same as
+ the RS field in the instruction. This is used for extended
+ mnemonics like mr. This operand is marked FAKE. The insertion
+ function just copies the BT field into the BA field, and the
+ extraction function just checks that the fields are the same. */
+
+static unsigned long
+insert_rbs (unsigned long insn,
+ long value ATTRIBUTE_UNUSED,
+ int dialect ATTRIBUTE_UNUSED,
+ const char **errmsg ATTRIBUTE_UNUSED)
+{
+ return insn | (((insn >> 21) & 0x1f) << 11);
+}
+
+
+/* Macros used to form opcodes. */
+
+/* The main opcode. */
+#define OP(x) ((((unsigned long)(x)) & 0x3f) << 26)
+#define OP_MASK OP (0x3f)
+
+/* The main opcode combined with a trap code in the TO field of a D
+ form instruction. Used for extended mnemonics for the trap
+ instructions. */
+#define OPTO(x,to) (OP (x) | ((((unsigned long)(to)) & 0x1f) << 21))
+#define OPTO_MASK (OP_MASK | TO_MASK)
+
+/* The main opcode combined with a comparison size bit in the L field
+ of a D form or X form instruction. Used for extended mnemonics for
+ the comparison instructions. */
+#define OPL(x,l) (OP (x) | ((((unsigned long)(l)) & 1) << 21))
+#define OPL_MASK OPL (0x3f,1)
+
+/* An A form instruction. */
+#define A(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1) | (((unsigned long)(rc)) & 1))
+#define A_MASK A (0x3f, 0x1f, 1)
+
+/* An A_MASK with the FRB field fixed. */
+#define AFRB_MASK (A_MASK | FRB_MASK)
+
+/* An A_MASK with the FRC field fixed. */
+#define AFRC_MASK (A_MASK | FRC_MASK)
+
+/* An A_MASK with the FRA and FRC fields fixed. */
+#define AFRAFRC_MASK (A_MASK | FRA_MASK | FRC_MASK)
+
+/* An AFRAFRC_MASK, but with L bit clear. */
+#define AFRALFRC_MASK (AFRAFRC_MASK & ~((unsigned long) 1 << 16))
+
+/* A B form instruction. */
+#define B(op, aa, lk) (OP (op) | ((((unsigned long)(aa)) & 1) << 1) | ((lk) & 1))
+#define B_MASK B (0x3f, 1, 1)
+
+/* A B form instruction setting the BO field. */
+#define BBO(op, bo, aa, lk) (B ((op), (aa), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21))
+#define BBO_MASK BBO (0x3f, 0x1f, 1, 1)
+
+/* A BBO_MASK with the y bit of the BO field removed. This permits
+ matching a conditional branch regardless of the setting of the y
+ bit. Similarly for the 'at' bits used for power4 branch hints. */
+#define Y_MASK (((unsigned long) 1) << 21)
+#define AT1_MASK (((unsigned long) 3) << 21)
+#define AT2_MASK (((unsigned long) 9) << 21)
+#define BBOY_MASK (BBO_MASK &~ Y_MASK)
+#define BBOAT_MASK (BBO_MASK &~ AT1_MASK)
+
+/* A B form instruction setting the BO field and the condition bits of
+ the BI field. */
+#define BBOCB(op, bo, cb, aa, lk) \
+ (BBO ((op), (bo), (aa), (lk)) | ((((unsigned long)(cb)) & 0x3) << 16))
+#define BBOCB_MASK BBOCB (0x3f, 0x1f, 0x3, 1, 1)
+
+/* A BBOCB_MASK with the y bit of the BO field removed. */
+#define BBOYCB_MASK (BBOCB_MASK &~ Y_MASK)
+#define BBOATCB_MASK (BBOCB_MASK &~ AT1_MASK)
+#define BBOAT2CB_MASK (BBOCB_MASK &~ AT2_MASK)
+
+/* A BBOYCB_MASK in which the BI field is fixed. */
+#define BBOYBI_MASK (BBOYCB_MASK | BI_MASK)
+#define BBOATBI_MASK (BBOAT2CB_MASK | BI_MASK)
+
+/* An Context form instruction. */
+#define CTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7))
+#define CTX_MASK CTX(0x3f, 0x7)
+
+/* An User Context form instruction. */
+#define UCTX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x1f))
+#define UCTX_MASK UCTX(0x3f, 0x1f)
+
+/* The main opcode mask with the RA field clear. */
+#define DRA_MASK (OP_MASK | RA_MASK)
+
+/* A DS form instruction. */
+#define DSO(op, xop) (OP (op) | ((xop) & 0x3))
+#define DS_MASK DSO (0x3f, 3)
+
+/* A DE form instruction. */
+#define DEO(op, xop) (OP (op) | ((xop) & 0xf))
+#define DE_MASK DEO (0x3e, 0xf)
+
+/* An EVSEL form instruction. */
+#define EVSEL(op, xop) (OP (op) | (((unsigned long)(xop)) & 0xff) << 3)
+#define EVSEL_MASK EVSEL(0x3f, 0xff)
+
+/* An M form instruction. */
+#define M(op, rc) (OP (op) | ((rc) & 1))
+#define M_MASK M (0x3f, 1)
+
+/* An M form instruction with the ME field specified. */
+#define MME(op, me, rc) (M ((op), (rc)) | ((((unsigned long)(me)) & 0x1f) << 1))
+
+/* An M_MASK with the MB and ME fields fixed. */
+#define MMBME_MASK (M_MASK | MB_MASK | ME_MASK)
+
+/* An M_MASK with the SH and ME fields fixed. */
+#define MSHME_MASK (M_MASK | SH_MASK | ME_MASK)
+
+/* An MD form instruction. */
+#define MD(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x7) << 2) | ((rc) & 1))
+#define MD_MASK MD (0x3f, 0x7, 1)
+
+/* An MD_MASK with the MB field fixed. */
+#define MDMB_MASK (MD_MASK | MB6_MASK)
+
+/* An MD_MASK with the SH field fixed. */
+#define MDSH_MASK (MD_MASK | SH6_MASK)
+
+/* An MDS form instruction. */
+#define MDS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0xf) << 1) | ((rc) & 1))
+#define MDS_MASK MDS (0x3f, 0xf, 1)
+
+/* An MDS_MASK with the MB field fixed. */
+#define MDSMB_MASK (MDS_MASK | MB6_MASK)
+
+/* An SC form instruction. */
+#define SC(op, sa, lk) (OP (op) | ((((unsigned long)(sa)) & 1) << 1) | ((lk) & 1))
+#define SC_MASK (OP_MASK | (((unsigned long)0x3ff) << 16) | (((unsigned long)1) << 1) | 1)
+
+/* An VX form instruction. */
+#define VX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7ff))
+
+/* The mask for an VX form instruction. */
+#define VX_MASK VX(0x3f, 0x7ff)
+
+/* An VA form instruction. */
+#define VXA(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x03f))
+
+/* The mask for an VA form instruction. */
+#define VXA_MASK VXA(0x3f, 0x3f)
+
+/* An VXR form instruction. */
+#define VXR(op, xop, rc) (OP (op) | (((rc) & 1) << 10) | (((unsigned long)(xop)) & 0x3ff))
+
+/* The mask for a VXR form instruction. */
+#define VXR_MASK VXR(0x3f, 0x3ff, 1)
+
+/* An X form instruction. */
+#define X(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1))
+
+/* A Z form instruction. */
+#define Z(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1))
+
+/* An X form instruction with the RC bit specified. */
+#define XRC(op, xop, rc) (X ((op), (xop)) | ((rc) & 1))
+
+/* A Z form instruction with the RC bit specified. */
+#define ZRC(op, xop, rc) (Z ((op), (xop)) | ((rc) & 1))
+
+/* The mask for an X form instruction. */
+#define X_MASK XRC (0x3f, 0x3ff, 1)
+
+/* The mask for a Z form instruction. */
+#define Z_MASK ZRC (0x3f, 0x1ff, 1)
+#define Z2_MASK ZRC (0x3f, 0xff, 1)
+
+/* An X_MASK with the RA field fixed. */
+#define XRA_MASK (X_MASK | RA_MASK)
+
+/* An XRA_MASK with the W field clear. */
+#define XWRA_MASK (XRA_MASK & ~((unsigned long) 1 << 16))
+
+/* An X_MASK with the RB field fixed. */
+#define XRB_MASK (X_MASK | RB_MASK)
+
+/* An X_MASK with the RT field fixed. */
+#define XRT_MASK (X_MASK | RT_MASK)
+
+/* An XRT_MASK mask with the L bits clear. */
+#define XLRT_MASK (XRT_MASK & ~((unsigned long) 0x3 << 21))
+
+/* An X_MASK with the RA and RB fields fixed. */
+#define XRARB_MASK (X_MASK | RA_MASK | RB_MASK)
+
+/* An XRARB_MASK, but with the L bit clear. */
+#define XRLARB_MASK (XRARB_MASK & ~((unsigned long) 1 << 16))
+
+/* An X_MASK with the RT and RA fields fixed. */
+#define XRTRA_MASK (X_MASK | RT_MASK | RA_MASK)
+
+/* An XRTRA_MASK, but with L bit clear. */
+#define XRTLRA_MASK (XRTRA_MASK & ~((unsigned long) 1 << 21))
+
+/* An X form instruction with the L bit specified. */
+#define XOPL(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 1) << 21))
+
+/* The mask for an X form comparison instruction. */
+#define XCMP_MASK (X_MASK | (((unsigned long)1) << 22))
+
+/* The mask for an X form comparison instruction with the L field
+ fixed. */
+#define XCMPL_MASK (XCMP_MASK | (((unsigned long)1) << 21))
+
+/* An X form trap instruction with the TO field specified. */
+#define XTO(op, xop, to) (X ((op), (xop)) | ((((unsigned long)(to)) & 0x1f) << 21))
+#define XTO_MASK (X_MASK | TO_MASK)
+
+/* An X form tlb instruction with the SH field specified. */
+#define XTLB(op, xop, sh) (X ((op), (xop)) | ((((unsigned long)(sh)) & 0x1f) << 11))
+#define XTLB_MASK (X_MASK | SH_MASK)
+
+/* An X form sync instruction. */
+#define XSYNC(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 3) << 21))
+
+/* An X form sync instruction with everything filled in except the LS field. */
+#define XSYNC_MASK (0xff9fffff)
+
+/* An X_MASK, but with the EH bit clear. */
+#define XEH_MASK (X_MASK & ~((unsigned long )1))
+
+/* An X form AltiVec dss instruction. */
+#define XDSS(op, xop, a) (X ((op), (xop)) | ((((unsigned long)(a)) & 1) << 25))
+#define XDSS_MASK XDSS(0x3f, 0x3ff, 1)
+
+/* An XFL form instruction. */
+#define XFL(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1) | (((unsigned long)(rc)) & 1))
+#define XFL_MASK XFL (0x3f, 0x3ff, 1)
+
+/* An X form isel instruction. */
+#define XISEL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1))
+#define XISEL_MASK XISEL(0x3f, 0x1f)
+
+/* An XL form instruction with the LK field set to 0. */
+#define XL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1))
+
+/* An XL form instruction which uses the LK field. */
+#define XLLK(op, xop, lk) (XL ((op), (xop)) | ((lk) & 1))
+
+/* The mask for an XL form instruction. */
+#define XL_MASK XLLK (0x3f, 0x3ff, 1)
+
+/* An XL form instruction which explicitly sets the BO field. */
+#define XLO(op, bo, xop, lk) \
+ (XLLK ((op), (xop), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21))
+#define XLO_MASK (XL_MASK | BO_MASK)
+
+/* An XL form instruction which explicitly sets the y bit of the BO
+ field. */
+#define XLYLK(op, xop, y, lk) (XLLK ((op), (xop), (lk)) | ((((unsigned long)(y)) & 1) << 21))
+#define XLYLK_MASK (XL_MASK | Y_MASK)
+
+/* An XL form instruction which sets the BO field and the condition
+ bits of the BI field. */
+#define XLOCB(op, bo, cb, xop, lk) \
+ (XLO ((op), (bo), (xop), (lk)) | ((((unsigned long)(cb)) & 3) << 16))
+#define XLOCB_MASK XLOCB (0x3f, 0x1f, 0x3, 0x3ff, 1)
+
+#define BB_MASK (0x1f << 11)
+/* An XL_MASK or XLYLK_MASK or XLOCB_MASK with the BB field fixed. */
+#define XLBB_MASK (XL_MASK | BB_MASK)
+#define XLYBB_MASK (XLYLK_MASK | BB_MASK)
+#define XLBOCBBB_MASK (XLOCB_MASK | BB_MASK)
+
+/* A mask for branch instructions using the BH field. */
+#define XLBH_MASK (XL_MASK | (0x1c << 11))
+
+/* An XL_MASK with the BO and BB fields fixed. */
+#define XLBOBB_MASK (XL_MASK | BO_MASK | BB_MASK)
+
+/* An XL_MASK with the BO, BI and BB fields fixed. */
+#define XLBOBIBB_MASK (XL_MASK | BO_MASK | BI_MASK | BB_MASK)
+
+/* An XO form instruction. */
+#define XO(op, xop, oe, rc) \
+ (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1) | ((((unsigned long)(oe)) & 1) << 10) | (((unsigned long)(rc)) & 1))
+#define XO_MASK XO (0x3f, 0x1ff, 1, 1)
+
+/* An XO_MASK with the RB field fixed. */
+#define XORB_MASK (XO_MASK | RB_MASK)
+
+/* An XS form instruction. */
+#define XS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 2) | (((unsigned long)(rc)) & 1))
+#define XS_MASK XS (0x3f, 0x1ff, 1)
+
+/* A mask for the FXM version of an XFX form instruction. */
+#define XFXFXM_MASK (X_MASK | (1 << 11) | (1 << 20))
+
+/* An XFX form instruction with the FXM field filled in. */
+#define XFXM(op, xop, fxm, p4) \
+ (X ((op), (xop)) | ((((unsigned long)(fxm)) & 0xff) << 12) \
+ | ((unsigned long)(p4) << 20))
+
+#define SPR_MASK (0x3ff << 11)
+/* An XFX form instruction with the SPR field filled in. */
+#define XSPR(op, xop, spr) \
+ (X ((op), (xop)) | ((((unsigned long)(spr)) & 0x1f) << 16) | ((((unsigned long)(spr)) & 0x3e0) << 6))
+#define XSPR_MASK (X_MASK | SPR_MASK)
+
+/* An XFX form instruction with the SPR field filled in except for the
+ SPRBAT field. */
+#define XSPRBAT_MASK (XSPR_MASK &~ SPRBAT_MASK)
+
+/* An XFX form instruction with the SPR field filled in except for the
+ SPRG field. */
+#define XSPRG_MASK (XSPR_MASK & ~(0x1f << 16))
+
+/* An X form instruction with everything filled in except the E field. */
+#define XE_MASK (0xffff7fff)
+
+/* An X form user context instruction. */
+#define XUC(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x1f))
+#define XUC_MASK XUC(0x3f, 0x1f)
+
+/* The BO encodings used in extended conditional branch mnemonics. */
+#define BODNZF (0x0)
+#define BODNZFP (0x1)
+#define BODZF (0x2)
+#define BODZFP (0x3)
+#define BODNZT (0x8)
+#define BODNZTP (0x9)
+#define BODZT (0xa)
+#define BODZTP (0xb)
+
+#define BOF (0x4)
+#define BOFP (0x5)
+#define BOFM4 (0x6)
+#define BOFP4 (0x7)
+#define BOT (0xc)
+#define BOTP (0xd)
+#define BOTM4 (0xe)
+#define BOTP4 (0xf)
+
+#define BODNZ (0x10)
+#define BODNZP (0x11)
+#define BODZ (0x12)
+#define BODZP (0x13)
+#define BODNZM4 (0x18)
+#define BODNZP4 (0x19)
+#define BODZM4 (0x1a)
+#define BODZP4 (0x1b)
+
+#define BOU (0x14)
+
+/* The BI condition bit encodings used in extended conditional branch
+ mnemonics. */
+#define CBLT (0)
+#define CBGT (1)
+#define CBEQ (2)
+#define CBSO (3)
+
+/* The TO encodings used in extended trap mnemonics. */
+#define TOLGT (0x1)
+#define TOLLT (0x2)
+#define TOEQ (0x4)
+#define TOLGE (0x5)
+#define TOLNL (0x5)
+#define TOLLE (0x6)
+#define TOLNG (0x6)
+#define TOGT (0x8)
+#define TOGE (0xc)
+#define TONL (0xc)
+#define TOLT (0x10)
+#define TOLE (0x14)
+#define TONG (0x14)
+#define TONE (0x18)
+#define TOU (0x1f)
+
+/* Smaller names for the flags so each entry in the opcodes table will
+ fit on a single line. */
+#undef PPC
+#define PPC PPC_OPCODE_PPC
+#define PPCCOM PPC_OPCODE_PPC | PPC_OPCODE_COMMON
+#define PPC64 PPC_OPCODE_64 | PPC_OPCODE_PPC
+#define COM PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON
+#define COM32 PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_32
+
+/* The opcode table.
+
+ The format of the opcode table is:
+
+ NAME OPCODE MASK FLAGS { OPERANDS }
+
+ NAME is the name of the instruction.
+ OPCODE is the instruction opcode.
+ MASK is the opcode mask; this is used to tell the disassembler
+ which bits in the actual opcode must match OPCODE.
+ FLAGS are flags indicated what processors support the instruction.
+ OPERANDS is the list of operands.
+
+ The disassembler reads the table in order and prints the first
+ instruction which matches, so this table is sorted to put more
+ specific instructions before more general instructions. It is also
+ sorted by major opcode. */
+
+static const struct powerpc_opcode powerpc_opcodes[] = {
+
+{ "cmplwi", OPL(10,0), OPL_MASK, PPCCOM, { OBF, RA, UI } },
+{ "cmpwi", OPL(11,0), OPL_MASK, PPCCOM, { OBF, RA, SI } },
+{ "cmpw", XOPL(31,0,0), XCMPL_MASK, PPCCOM, { OBF, RA, RB } },
+{ "cmplw", XOPL(31,32,0), XCMPL_MASK, PPCCOM, { OBF, RA, RB } },
+{ "fcmpu", X(63,0), X_MASK|(3<<21), COM, { BF, FRA, FRB } },
+
+{ "li", OP(14), DRA_MASK, PPCCOM, { RT, SI } },
+{ "lis", OP(15), DRA_MASK, PPCCOM, { RT, SI } },
+
+{ "addi", OP(14), OP_MASK, PPCCOM, { RT, RA0, SI } },
+{ "addis", OP(15), OP_MASK, PPCCOM, { RT,RA0,SI } },
+{ "blt-", BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, PPCCOM, { CR, BDM } },
+{ "bc", B(16,0,0), B_MASK, COM, { BO, BI, BD } },
+{ "bcl", B(16,0,1), B_MASK, COM, { BO, BI, BD } },
+{ "b", B(18,0,0), B_MASK, COM, { LI } },
+{ "bl", B(18,0,1), B_MASK, COM, { LI } },
+{ "blr", XLO(19,BOU,16,0), XLBOBIBB_MASK, PPCCOM, { 0 } },
+{ "bctr", XLO(19,BOU,528,0), XLBOBIBB_MASK, COM, { 0 } },
+{ "bctrl", XLO(19,BOU,528,1), XLBOBIBB_MASK, COM, { 0 } },
+
+{ "rlwinm", M(21,0), M_MASK, PPCCOM, { RA,RS,SH,MBE,ME } },
+{ "nop", OP(24), 0xffffffff, PPCCOM, { 0 } },
+{ "ori", OP(24), OP_MASK, PPCCOM, { RA, RS, UI } },
+{ "xoris", OP(27), OP_MASK, PPCCOM, { RA, RS, UI } },
+{ "ldx", X(31,21), X_MASK, PPC64, { RT, RA0, RB } },
+{ "lwzx", X(31,23), X_MASK, PPCCOM, { RT, RA0, RB } },
+{ "slw", XRC(31,24,0), X_MASK, PPCCOM, { RA, RS, RB } },
+{ "and", XRC(31,28,0), X_MASK, COM, { RA, RS, RB } },
+{ "sub", XO(31,40,0,0), XO_MASK, PPC, { RT, RB, RA } },
+{ "lbzx", X(31,87), X_MASK, COM, { RT, RA0, RB } },
+{ "neg", XO(31,104,0,0), XORB_MASK, COM, { RT, RA } },
+{ "not", XRC(31,124,0), X_MASK, COM, { RA, RS, RBS } },
+{ "stwx", X(31,151), X_MASK, PPCCOM, { RS, RA0, RB } },
+{ "stbx", X(31,215), X_MASK, COM, { RS, RA0, RB } },
+{ "mullw", XO(31,235,0,0), XO_MASK, PPCCOM, { RT, RA, RB } },
+{ "add", XO(31,266,0,0), XO_MASK, PPCCOM, { RT, RA, RB } },
+{ "lhzx", X(31,279), X_MASK, COM, { RT, RA0, RB } },
+{ "xor", XRC(31,316,0), X_MASK, COM, { RA, RS, RB } },
+{ "mflr", XSPR(31,339,8), XSPR_MASK, COM, { RT } },
+{ "sthx", X(31,407), X_MASK, COM, { RS, RA0, RB } },
+{ "mr", XRC(31,444,0), X_MASK, COM, { RA, RS, RBS } },
+{ "or", XRC(31,444,0), X_MASK, COM, { RA, RS, RB } },
+{ "divwu", XO(31,459,0,0), XO_MASK, PPC, { RT, RA, RB } },
+{ "mtlr", XSPR(31,467,8), XSPR_MASK, COM, { RS } },
+{ "mtctr", XSPR(31,467,9), XSPR_MASK, COM, { RS } },
+{ "divw", XO(31,491,0,0), XO_MASK, PPC, { RT, RA, RB } },
+{ "lfsx", X(31,535), X_MASK, COM, { FRT, RA0, RB } },
+{ "srw", XRC(31,536,0), X_MASK, PPCCOM, { RA, RS, RB } },
+{ "stfsx", X(31,663), X_MASK, COM, { FRS, RA0, RB } },
+{ "sraw", XRC(31,792,0), X_MASK, PPCCOM, { RA, RS, RB } },
+{ "extsh", XRC(31,922,0), XRB_MASK, PPCCOM, { RA, RS } },
+{ "extsb", XRC(31,954,0), XRB_MASK, PPC, { RA, RS} },
+
+{ "lwz", OP(32), OP_MASK, PPCCOM, { RT, D, RA0 } },
+{ "lbz", OP(34), OP_MASK, COM, { RT, D, RA0 } },
+{ "stw", OP(36), OP_MASK, PPCCOM, { RS, D, RA0 } },
+{ "stwu", OP(37), OP_MASK, PPCCOM, { RS, D, RAS } },
+{ "stb", OP(38), OP_MASK, COM, { RS, D, RA0 } },
+{ "lhz", OP(40), OP_MASK, COM, { RT, D, RA0 } },
+{ "sth", OP(44), OP_MASK, COM, { RS, D, RA0 } },
+{ "lfs", OP(48), OP_MASK, COM, { FRT, D, RA0 } },
+{ "lfd", OP(50), OP_MASK, COM, { FRT, D, RA0 } },
+{ "stfs", OP(52), OP_MASK, COM, { FRS, D, RA0 } },
+{ "stfd", OP(54), OP_MASK, COM, { FRS, D, RA0 } },
+{ "ld", DSO(58,0), DS_MASK, PPC64, { RT, DS, RA0 } },
+
+{ "fdivs", A(59,18,0), AFRC_MASK, PPC, { FRT, FRA, FRB } },
+{ "fsubs", A(59,20,0), AFRC_MASK, PPC, { FRT, FRA, FRB } },
+{ "fadds", A(59,21,0), AFRC_MASK, PPC, { FRT, FRA, FRB } },
+{ "fmuls", A(59,25,0), AFRB_MASK, PPC, { FRT, FRA, FRC } },
+{ "std", DSO(62,0), DS_MASK, PPC64, { RS, DS, RA0 } },
+{ "stdu", DSO(62,1), DS_MASK, PPC64, { RS, DS, RAS } },
+{ "frsp", XRC(63,12,0), XRA_MASK, COM, { FRT, FRB } },
+{ "fctiwz", XRC(63,15,0), XRA_MASK, PPCCOM, { FRT, FRB } },
+{ "fsub", A(63,20,0), AFRC_MASK, PPCCOM, { FRT, FRA, FRB } },
+{ "fneg", XRC(63,40,0), XRA_MASK, COM, { FRT, FRB } },
+};
+
+static const int powerpc_num_opcodes =
+ sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
diff --git a/src/qcommon/vm_powerpc_asm.h b/src/qcommon/vm_powerpc_asm.h
new file mode 100644
index 00000000..9bccf18a
--- /dev/null
+++ b/src/qcommon/vm_powerpc_asm.h
@@ -0,0 +1,156 @@
+/*
+===========================================================================
+Copyright (C) 2008 Przemyslaw Iskra <sparky@pld-linux.org>
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#ifndef VM_POWERPC_ASM_H
+#define VM_POWERPC_ASM_H
+
+/*
+ * Register information according to:
+ * http://refspecs.freestandards.org/elf/elfspec_ppc.pdf
+ */
+
+#define r0 0 // volatile
+#define r1 1 // caller safe ( stack pointer )
+#define r2 2 // reserved
+#define r3 3 // callee safe
+#define r4 4 // callee safe
+#define r5 5 // callee safe
+#define r6 6 // callee safe
+#define r7 7 // callee safe
+#define r8 8 // callee safe
+#define r9 9 // callee safe
+#define r10 10 // callee safe
+#define r11 11 // volatile
+#define r12 12 // volatile
+#define r13 13 // reserved ( small data area )
+#define r14 14 // caller safe
+#define r15 15 // caller safe
+#define r16 16 // caller safe
+#define r17 17 // caller safe
+#define r18 18 // caller safe
+#define r19 19 // caller safe
+#define r20 20 // caller safe
+#define r21 21 // caller safe
+#define r22 22 // caller safe
+#define r23 23 // caller safe
+#define r24 24 // caller safe
+#define r25 25 // caller safe
+#define r26 26 // caller safe
+#define r27 27 // caller safe
+#define r28 28 // caller safe
+#define r29 29 // caller safe
+#define r30 30 // caller safe
+#define r31 31 // caller safe ( environment pointers )
+
+#define f0 0 // callee safe
+#define f1 1 // callee safe
+#define f2 2 // callee safe
+#define f3 3 // callee safe
+#define f4 4 // callee safe
+#define f5 5 // callee safe
+#define f6 6 // callee safe
+#define f7 7 // callee safe
+#define f8 8 // callee safe
+#define f9 9 // callee safe
+#define f10 10 // callee safe
+#define f11 11 // callee safe
+#define f12 12 // callee safe
+#define f13 13 // callee safe
+#define f14 14 // caller safe
+#define f15 15 // caller safe
+#define f16 16 // caller safe
+#define f17 17 // caller safe
+#define f18 18 // caller safe
+#define f19 19 // caller safe
+#define f20 20 // caller safe
+#define f21 21 // caller safe
+#define f22 22 // caller safe
+#define f23 23 // caller safe
+#define f24 24 // caller safe
+#define f25 25 // caller safe
+#define f26 26 // caller safe
+#define f27 27 // caller safe
+#define f28 28 // caller safe
+#define f29 29 // caller safe
+#define f30 30 // caller safe
+#define f31 31 // caller safe
+
+#define cr0 0 // volatile
+#define cr1 1 // volatile
+#define cr2 2 // caller safe
+#define cr3 3 // caller safe
+#define cr4 4 // caller safe
+#define cr5 5 // volatile
+#define cr6 6 // volatile
+#define cr7 7 // volatile
+
+#define lt 0
+#define gt 1
+#define eq 2
+#define so 3
+
+// branch bo field values
+#define branchLikely 1
+#define branchFalse 4
+#define branchTrue 12
+#define branchAlways 20
+
+// branch extensions (change branch type)
+#define branchExtLink 0x0001
+
+
+/*
+ * This list must match exactly the powerpc_opcodes list from vm_powerpc_asm.c
+ * If you're changing the original list remember to regenerate this one. You
+ * may do so using this perl script:
+ perl -p -e 'BEGIN{%t=("-"=>m=>"+"=>p=>"."=>d=>);$l=""}$o=0 if/^}/;
+ if($o && s/^{ "(.*?)([\.+-])?".+/i\U$1\E$t{$2}/s){$_.="_" while$l{$_};
+ $l{$_}=1;if(length $l.$_ > 70){$s=$_;$_="\t$l\n";$l="$s,"}else
+ {$l.=" $_,";$_=undef}}else{$o=1 if/powerpc_opcodes.*=/;$_=undef};
+ END{print "\t$l\n"}' < vm_powerpc_asm.c
+ */
+
+typedef enum powerpc_iname {
+ iCMPLWI, iCMPWI, iCMPW, iCMPLW, iFCMPU, iLI, iLIS, iADDI, iADDIS,
+ iBLTm, iBC, iBCL, iB, iBL, iBLR, iBCTR, iBCTRL, iRLWINM, iNOP, iORI,
+ iXORIS, iLDX, iLWZX, iSLW, iAND, iSUB, iLBZX, iNEG, iNOT, iSTWX, iSTBX,
+ iMULLW, iADD, iLHZX, iXOR, iMFLR, iSTHX, iMR, iOR, iDIVWU, iMTLR,
+ iMTCTR, iDIVW, iLFSX, iSRW, iSTFSX, iSRAW, iEXTSH, iEXTSB, iLWZ, iLBZ,
+ iSTW, iSTWU, iSTB, iLHZ, iSTH, iLFS, iLFD, iSTFS, iSTFD, iLD, iFDIVS,
+ iFSUBS, iFADDS, iFMULS, iSTD, iSTDU, iFRSP, iFCTIWZ, iFSUB, iFNEG,
+} powerpc_iname_t;
+
+#include <stdint.h>
+
+typedef uint32_t ppc_instruction_t;
+
+extern ppc_instruction_t
+asm_instruction( powerpc_iname_t, const int, const long int * );
+
+#define IN( inst, args... ) \
+({\
+ const long int argv[] = { args };\
+ const int argc = sizeof( argv ) / sizeof( argv[0] ); \
+ asm_instruction( inst, argc, argv );\
+})
+
+#endif
diff --git a/src/renderer/tr_bsp.c b/src/renderer/tr_bsp.c
index fd1b64b6..83633c00 100644
--- a/src/renderer/tr_bsp.c
+++ b/src/renderer/tr_bsp.c
@@ -1796,7 +1796,10 @@ Called directly from cgame
void RE_LoadWorldMap( const char *name ) {
int i;
dheader_t *header;
- byte *buffer;
+ union {
+ byte *b;
+ void *v;
+ } buffer;
byte *startMarker;
if ( tr.worldMapLoaded ) {
@@ -1814,8 +1817,8 @@ void RE_LoadWorldMap( const char *name ) {
tr.worldMapLoaded = qtrue;
// load it
- ri.FS_ReadFile( name, (void **)&buffer );
- if ( !buffer ) {
+ ri.FS_ReadFile( name, &buffer.v );
+ if ( !buffer.b ) {
ri.Error (ERR_DROP, "RE_LoadWorldMap: %s not found", name);
}
@@ -1832,7 +1835,7 @@ void RE_LoadWorldMap( const char *name ) {
startMarker = ri.Hunk_Alloc(0, h_low);
c_gridVerts = 0;
- header = (dheader_t *)buffer;
+ header = (dheader_t *)buffer.b;
fileBase = (byte *)header;
i = LittleLong (header->version);
@@ -1864,6 +1867,6 @@ void RE_LoadWorldMap( const char *name ) {
// only set tr.world now that we know the entire level has loaded properly
tr.world = &s_worldData;
- ri.FS_FreeFile( buffer );
+ ri.FS_FreeFile( buffer.v );
}
diff --git a/src/renderer/tr_image.c b/src/renderer/tr_image.c
index 836433b5..5ed98450 100644
--- a/src/renderer/tr_image.c
+++ b/src/renderer/tr_image.c
@@ -1432,7 +1432,11 @@ qhandle_t RE_RegisterSkin( const char *name ) {
qhandle_t hSkin;
skin_t *skin;
skinSurface_t *surf;
- char *text, *text_p;
+ union {
+ char *c;
+ void *v;
+ } text;
+ char *text_p;
char *token;
char surfName[MAX_QPATH];
@@ -1481,12 +1485,12 @@ qhandle_t RE_RegisterSkin( const char *name ) {
}
// load and parse the skin file
- ri.FS_ReadFile( name, (void **)&text );
- if ( !text ) {
+ ri.FS_ReadFile( name, &text.v );
+ if ( !text.c ) {
return 0;
}
- text_p = text;
+ text_p = text.c;
while ( text_p && *text_p ) {
// get surface name
token = CommaParse( &text_p );
@@ -1515,7 +1519,7 @@ qhandle_t RE_RegisterSkin( const char *name ) {
skin->numSurfaces++;
}
- ri.FS_FreeFile( text );
+ ri.FS_FreeFile( text.v );
// never let a skin have 0 shaders
diff --git a/src/renderer/tr_image_bmp.c b/src/renderer/tr_image_bmp.c
index 190b878f..0b78abb8 100644
--- a/src/renderer/tr_image_bmp.c
+++ b/src/renderer/tr_image_bmp.c
@@ -50,7 +50,10 @@ void R_LoadBMP( const char *name, byte **pic, int *width, int *height )
int row, column;
byte *buf_p;
byte *end;
- byte *buffer = NULL;
+ union {
+ byte *b;
+ void *v;
+ } buffer;
int length;
BMPHeader_t bmpHeader;
byte *bmpRGBA;
@@ -66,8 +69,8 @@ void R_LoadBMP( const char *name, byte **pic, int *width, int *height )
//
// load the file
//
- length = ri.FS_ReadFile( ( char * ) name, (void **)&buffer);
- if (!buffer || length < 0) {
+ length = ri.FS_ReadFile( ( char * ) name, &buffer.v);
+ if (!buffer.b || length < 0) {
return;
}
@@ -76,8 +79,8 @@ void R_LoadBMP( const char *name, byte **pic, int *width, int *height )
ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name );
}
- buf_p = buffer;
- end = buffer + length;
+ buf_p = buffer.b;
+ end = buffer.b + length;
bmpHeader.id[0] = *buf_p++;
bmpHeader.id[1] = *buf_p++;
@@ -119,12 +122,12 @@ void R_LoadBMP( const char *name, byte **pic, int *width, int *height )
buf_p += sizeof(bmpHeader.palette);
}
- if (buffer + bmpHeader.bitmapDataOffset > end)
+ if (buffer.b + bmpHeader.bitmapDataOffset > end)
{
ri.Error( ERR_DROP, "LoadBMP: invalid offset value in header (%s)\n", name );
}
- buf_p = buffer + bmpHeader.bitmapDataOffset;
+ buf_p = buffer.b + bmpHeader.bitmapDataOffset;
if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' )
{
@@ -231,6 +234,6 @@ void R_LoadBMP( const char *name, byte **pic, int *width, int *height )
}
}
- ri.FS_FreeFile( buffer );
+ ri.FS_FreeFile( buffer.v );
}
diff --git a/src/renderer/tr_image_jpg.c b/src/renderer/tr_image_jpg.c
index fb4f2121..2e1a52a7 100644
--- a/src/renderer/tr_image_jpg.c
+++ b/src/renderer/tr_image_jpg.c
@@ -57,7 +57,10 @@ void R_LoadJPG( const char *filename, unsigned char **pic, int *width, int *heig
unsigned pixelcount, memcount;
unsigned char *out;
int len;
- byte *fbuffer;
+ union {
+ byte *b;
+ void *v;
+ } fbuffer;
byte *buf;
/* In this example we want to open the input file before doing anything else,
@@ -66,8 +69,8 @@ void R_LoadJPG( const char *filename, unsigned char **pic, int *width, int *heig
* requires it in order to read binary files.
*/
- len = ri.FS_ReadFile ( ( char * ) filename, (void **)&fbuffer);
- if (!fbuffer || len < 0) {
+ len = ri.FS_ReadFile ( ( char * ) filename, &fbuffer.v);
+ if (!fbuffer.b || len < 0) {
return;
}
@@ -85,7 +88,7 @@ void R_LoadJPG( const char *filename, unsigned char **pic, int *width, int *heig
/* Step 2: specify data source (eg, a file) */
- jpeg_mem_src(&cinfo, fbuffer, len);
+ jpeg_mem_src(&cinfo, fbuffer.b, len);
/* Step 3: read file parameters with jpeg_read_header() */
@@ -203,7 +206,7 @@ void R_LoadJPG( const char *filename, unsigned char **pic, int *width, int *heig
* so as to simplify the setjmp error logic above. (Actually, I don't
* think that jpeg_destroy can do an error exit, but why assume anything...)
*/
- ri.FS_FreeFile (fbuffer);
+ ri.FS_FreeFile (fbuffer.v);
/* At this point you may want to check to see whether any corrupt-data
* warnings occurred (test whether jerr.pub.num_warnings is nonzero).
diff --git a/src/renderer/tr_image_pcx.c b/src/renderer/tr_image_pcx.c
index db407dea..d1b1a5ee 100644
--- a/src/renderer/tr_image_pcx.c
+++ b/src/renderer/tr_image_pcx.c
@@ -50,7 +50,10 @@ typedef struct {
void R_LoadPCX ( const char *filename, byte **pic, int *width, int *height)
{
- byte *raw;
+ union {
+ byte *b;
+ void *v;
+ } raw;
byte *end;
pcx_t *pcx;
int len;
@@ -71,23 +74,23 @@ void R_LoadPCX ( const char *filename, byte **pic, int *width, int *height)
//
// load the file
//
- len = ri.FS_ReadFile( ( char * ) filename, (void **)&raw);
- if (!raw || len < 0) {
+ len = ri.FS_ReadFile( ( char * ) filename, &raw.v);
+ if (!raw.b || len < 0) {
return;
}
if((unsigned)len < sizeof(pcx_t))
{
ri.Printf (PRINT_ALL, "PCX truncated: %s\n", filename);
- ri.FS_FreeFile (raw);
+ ri.FS_FreeFile (raw.v);
return;
}
//
// parse the PCX file
//
- pcx = (pcx_t *)raw;
- end = raw+len;
+ pcx = (pcx_t *)raw.b;
+ end = raw.b+len;
w = LittleShort(pcx->xmax)+1;
h = LittleShort(pcx->ymax)+1;
@@ -107,7 +110,7 @@ void R_LoadPCX ( const char *filename, byte **pic, int *width, int *height)
pix = pic8 = ri.Malloc ( size );
- raw = pcx->data;
+ raw.b = pcx->data;
// FIXME: should use bytes_per_line but original q3 didn't do that either
while(pix < pic8+size)
{
@@ -117,16 +120,16 @@ void R_LoadPCX ( const char *filename, byte **pic, int *width, int *height)
continue;
}
- if(raw+1 > end)
+ if(raw.b+1 > end)
break;
- dataByte = *raw++;
+ dataByte = *raw.b++;
if((dataByte & 0xC0) == 0xC0)
{
- if(raw+1 > end)
+ if(raw.b+1 > end)
break;
runLength = dataByte & 0x3F;
- dataByte = *raw++;
+ dataByte = *raw.b++;
}
else
runLength = 1;
@@ -139,7 +142,7 @@ void R_LoadPCX ( const char *filename, byte **pic, int *width, int *height)
ri.Free (pic8);
}
- if (raw-(byte*)pcx >= end - (byte*)769 || end[-769] != 0x0c)
+ if (raw.b-(byte*)pcx >= end - (byte*)769 || end[-769] != 0x0c)
{
ri.Printf (PRINT_ALL, "PCX missing palette: %s\n", filename);
ri.FS_FreeFile (pcx);
diff --git a/src/renderer/tr_image_png.c b/src/renderer/tr_image_png.c
index e33ffffa..ef44c165 100644
--- a/src/renderer/tr_image_png.c
+++ b/src/renderer/tr_image_png.c
@@ -215,6 +215,10 @@ struct BufferedFile
static struct BufferedFile *ReadBufferedFile(const char *name)
{
struct BufferedFile *BF;
+ union {
+ byte *b;
+ void *v;
+ } buffer;
/*
* input verification
@@ -248,7 +252,8 @@ static struct BufferedFile *ReadBufferedFile(const char *name)
* Read the file.
*/
- BF->Length = ri.FS_ReadFile((char *) name, (void **) &BF->Buffer);
+ BF->Length = ri.FS_ReadFile((char *) name, &buffer.v);
+ BF->Buffer = buffer.b;
/*
* Did we get it? Is it big enough?
diff --git a/src/renderer/tr_image_tga.c b/src/renderer/tr_image_tga.c
index 2147acdc..e66e60de 100644
--- a/src/renderer/tr_image_tga.c
+++ b/src/renderer/tr_image_tga.c
@@ -45,7 +45,10 @@ void R_LoadTGA ( const char *name, byte **pic, int *width, int *height)
int row, column;
byte *buf_p;
byte *end;
- byte *buffer = NULL;
+ union {
+ byte *b;
+ void *v;
+ } buffer;
TargaHeader targa_header;
byte *targa_rgba;
int length;
@@ -60,8 +63,8 @@ void R_LoadTGA ( const char *name, byte **pic, int *width, int *height)
//
// load the file
//
- length = ri.FS_ReadFile ( ( char * ) name, (void **)&buffer);
- if (!buffer || length < 0) {
+ length = ri.FS_ReadFile ( ( char * ) name, &buffer.v);
+ if (!buffer.b || length < 0) {
return;
}
@@ -70,8 +73,8 @@ void R_LoadTGA ( const char *name, byte **pic, int *width, int *height)
ri.Error( ERR_DROP, "LoadTGA: header too short (%s)\n", name );
}
- buf_p = buffer;
- end = buffer + length;
+ buf_p = buffer.b;
+ end = buffer.b + length;
targa_header.id_length = buf_p[0];
targa_header.colormap_type = buf_p[1];
@@ -313,5 +316,5 @@ void R_LoadTGA ( const char *name, byte **pic, int *width, int *height)
*pic = targa_rgba;
- ri.FS_FreeFile (buffer);
+ ri.FS_FreeFile (buffer.v);
}
diff --git a/src/renderer/tr_model.c b/src/renderer/tr_model.c
index b4ca744f..8707d8a7 100644
--- a/src/renderer/tr_model.c
+++ b/src/renderer/tr_model.c
@@ -84,7 +84,10 @@ asked for again.
*/
qhandle_t RE_RegisterModel( const char *name ) {
model_t *mod;
- unsigned *buf;
+ union {
+ unsigned *u;
+ void *v;
+ } buf;
int lod;
int ident;
qboolean loaded = qfalse;
@@ -152,19 +155,19 @@ qhandle_t RE_RegisterModel( const char *name ) {
{
int filesize;
- filesize = ri.FS_ReadFile(name, (void **) &buf);
- if(!buf)
+ filesize = ri.FS_ReadFile(name, (void **) &buf.v);
+ if(!buf.u)
{
ri.Printf (PRINT_WARNING,"RE_RegisterModel: couldn't load %s\n", name);
mod->type = MOD_BAD;
return 0;
}
- ident = LittleLong(*(unsigned *)buf);
+ ident = LittleLong(*(unsigned *)buf.u);
if(ident == MDR_IDENT)
- loaded = R_LoadMDR(mod, buf, filesize, name);
+ loaded = R_LoadMDR(mod, buf.u, filesize, name);
- ri.FS_FreeFile (buf);
+ ri.FS_FreeFile (buf.v);
if(!loaded)
{
@@ -185,26 +188,26 @@ qhandle_t RE_RegisterModel( const char *name ) {
else
Com_sprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext);
- ri.FS_ReadFile( namebuf, (void **)&buf );
- if ( !buf ) {
+ ri.FS_ReadFile( namebuf, &buf.v );
+ if ( !buf.u ) {
continue;
}
loadmodel = mod;
- ident = LittleLong(*(unsigned *)buf);
+ ident = LittleLong(*(unsigned *)buf.u);
if ( ident == MD4_IDENT ) {
- loaded = R_LoadMD4( mod, buf, name );
+ loaded = R_LoadMD4( mod, buf.u, name );
} else {
if ( ident != MD3_IDENT ) {
ri.Printf (PRINT_WARNING,"RE_RegisterModel: unknown fileid for %s\n", name);
goto fail;
}
- loaded = R_LoadMD3( mod, lod, buf, name );
+ loaded = R_LoadMD3( mod, lod, buf.u, name );
}
- ri.FS_FreeFile (buf);
+ ri.FS_FreeFile (buf.v);
if ( !loaded ) {
if ( lod == 0 ) {
diff --git a/src/sdl/sdl_input.c b/src/sdl/sdl_input.c
index 98f8525a..3263932a 100644
--- a/src/sdl/sdl_input.c
+++ b/src/sdl/sdl_input.c
@@ -84,7 +84,7 @@ static void IN_PrintKey( const SDL_keysym *keysym, keyNum_t key, qboolean down )
else
Com_Printf( " " );
- Com_Printf( "0x%hx \"%s\"", keysym->scancode,
+ Com_Printf( "0x%02x \"%s\"", keysym->scancode,
SDL_GetKeyName( keysym->sym ) );
if( keysym->mod & KMOD_LSHIFT ) Com_Printf( " KMOD_LSHIFT" );
@@ -100,11 +100,11 @@ static void IN_PrintKey( const SDL_keysym *keysym, keyNum_t key, qboolean down )
if( keysym->mod & KMOD_MODE ) Com_Printf( " KMOD_MODE" );
if( keysym->mod & KMOD_RESERVED ) Com_Printf( " KMOD_RESERVED" );
- Com_Printf( " Q:%d(%s)", key, Key_KeynumToString( key ) );
+ Com_Printf( " Q:0x%02x(%s)", key, Key_KeynumToString( key ) );
if( keysym->unicode )
{
- Com_Printf( " U:%d", keysym->unicode );
+ Com_Printf( " U:0x%02x", keysym->unicode );
if( keysym->unicode > ' ' && keysym->unicode < '~' )
Com_Printf( "(%c)", (char)keysym->unicode );
@@ -120,7 +120,7 @@ static void IN_PrintKey( const SDL_keysym *keysym, keyNum_t key, qboolean down )
IN_IsConsoleKey
===============
*/
-static qboolean IN_IsConsoleKey( keyNum_t key, const char character )
+static qboolean IN_IsConsoleKey( keyNum_t key, const unsigned char character )
{
typedef struct consoleKey_s
{
@@ -133,7 +133,7 @@ static qboolean IN_IsConsoleKey( keyNum_t key, const char character )
union
{
keyNum_t key;
- char character;
+ unsigned char character;
} u;
} consoleKey_t;
@@ -153,34 +153,36 @@ static qboolean IN_IsConsoleKey( keyNum_t key, const char character )
while( numConsoleKeys < MAX_CONSOLE_KEYS )
{
consoleKey_t *c = &consoleKeys[ numConsoleKeys ];
- char *keyName;
+ int charCode = 0;
token = COM_Parse( &text_p );
if( !token[ 0 ] )
break;
- c->u.key = Key_StringToKeynum( token );
+ if( strlen( token ) == 4 )
+ charCode = Com_HexStrToInt( token );
- // 0 isn't a key
- if( c->u.key == 0 )
- continue;
-
- keyName = Key_KeynumToString( c->u.key );
-
- if( strlen( keyName ) == 1 )
+ if( charCode > 0 )
{
c->type = CHARACTER;
- c->u.character = *keyName;
+ c->u.character = (unsigned char)charCode;
}
else
+ {
c->type = KEY;
+ c->u.key = Key_StringToKeynum( token );
+
+ // 0 isn't a key
+ if( c->u.key <= 0 )
+ continue;
+ }
numConsoleKeys++;
}
}
- // Use the character in preference to the key name
- if( character != '\0' )
+ // If the character is the same as the key, prefer the character
+ if( key == character )
key = 0;
for( i = 0; i < numConsoleKeys; i++ )
@@ -212,7 +214,7 @@ IN_TranslateSDLToQ3Key
static const char *IN_TranslateSDLToQ3Key( SDL_keysym *keysym,
keyNum_t *key, qboolean down )
{
- static char buf[ 2 ] = { '\0', '\0' };
+ static unsigned char buf[ 2 ] = { '\0', '\0' };
*buf = '\0';
*key = 0;
@@ -311,9 +313,9 @@ static const char *IN_TranslateSDLToQ3Key( SDL_keysym *keysym,
}
}
- if( down && keysym->unicode && !( keysym->unicode & 0xFF80 ) )
+ if( down && keysym->unicode && !( keysym->unicode & 0xFF00 ) )
{
- char ch = (char)keysym->unicode & 0x7F;
+ unsigned char ch = (unsigned char)keysym->unicode & 0xFF;
switch( ch )
{
@@ -333,6 +335,17 @@ static const char *IN_TranslateSDLToQ3Key( SDL_keysym *keysym,
if( in_keyboardDebug->integer )
IN_PrintKey( keysym, *key, down );
+ // Keys that have ASCII names but produce no character are probably
+ // dead keys -- ignore them
+ if( down && strlen( Key_KeynumToString( *key ) ) == 1 &&
+ keysym->unicode == 0 )
+ {
+ if( in_keyboardDebug->integer )
+ Com_Printf( " Ignored dead key '%c'\n", *key );
+
+ *key = 0;
+ }
+
if( IN_IsConsoleKey( *key, *buf ) )
{
// Console keys can't be bound or generate characters
@@ -340,7 +353,11 @@ static const char *IN_TranslateSDLToQ3Key( SDL_keysym *keysym,
*buf = '\0';
}
- return buf;
+ // Don't allow extended ASCII to generate characters
+ if( *buf & 0x80 )
+ *buf = '\0';
+
+ return (char *)buf;
}
#ifdef MACOS_X_ACCELERATION_HACK
@@ -865,7 +882,7 @@ IN_ProcessEvents
static void IN_ProcessEvents( void )
{
SDL_Event e;
- const char *p = NULL;
+ const char *character = NULL;
keyNum_t key = 0;
if( !SDL_WasInit( SDL_INIT_VIDEO ) )
@@ -888,20 +905,19 @@ static void IN_ProcessEvents( void )
switch( e.type )
{
case SDL_KEYDOWN:
- p = IN_TranslateSDLToQ3Key( &e.key.keysym, &key, qtrue );
+ character = IN_TranslateSDLToQ3Key( &e.key.keysym, &key, qtrue );
if( key )
Com_QueueEvent( 0, SE_KEY, key, qtrue, 0, NULL );
- if( p )
- {
- while( *p )
- Com_QueueEvent( 0, SE_CHAR, *p++, 0, 0, NULL );
- }
+ if( character )
+ Com_QueueEvent( 0, SE_CHAR, *character, 0, 0, NULL );
break;
case SDL_KEYUP:
IN_TranslateSDLToQ3Key( &e.key.keysym, &key, qfalse );
- Com_QueueEvent( 0, SE_KEY, key, qfalse, 0, NULL );
+
+ if( key )
+ Com_QueueEvent( 0, SE_KEY, key, qfalse, 0, NULL );
break;
case SDL_MOUSEMOTION:
diff --git a/src/server/sv_ccmds.c b/src/server/sv_ccmds.c
index 367ca23d..1da5aaeb 100644
--- a/src/server/sv_ccmds.c
+++ b/src/server/sv_ccmds.c
@@ -259,6 +259,17 @@ static void SV_KillServer_f( void ) {
/*
==================
+SV_CompleteMapName
+==================
+*/
+static void SV_CompleteMapName( char *args, int argNum ) {
+ if( argNum == 2 ) {
+ Field_CompleteFilename( "maps", "bsp", qtrue );
+ }
+}
+
+/*
+==================
SV_AddOperatorCommands
==================
*/
@@ -276,7 +287,9 @@ void SV_AddOperatorCommands( void ) {
Cmd_AddCommand ("map_restart", SV_MapRestart_f);
Cmd_AddCommand ("sectorlist", SV_SectorList_f);
Cmd_AddCommand ("map", SV_Map_f);
+ Cmd_SetCommandCompletionFunc( "map", SV_CompleteMapName );
Cmd_AddCommand ("devmap", SV_Map_f);
+ Cmd_SetCommandCompletionFunc( "devmap", SV_CompleteMapName );
Cmd_AddCommand ("killserver", SV_KillServer_f);
}
diff --git a/src/server/sv_client.c b/src/server/sv_client.c
index 4fa0b24f..4b7b3bb6 100644
--- a/src/server/sv_client.c
+++ b/src/server/sv_client.c
@@ -1251,6 +1251,7 @@ void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK ) {
if (clientOK) {
// pass unknown strings to the game
if (!u->name && sv.state == SS_GAME) {
+ Cmd_Args_Sanitize();
VM_Call( gvm, GAME_CLIENT_COMMAND, cl - svs.clients );
}
}
diff --git a/src/server/sv_game.c b/src/server/sv_game.c
index df13500d..d375c095 100644
--- a/src/server/sv_game.c
+++ b/src/server/sv_game.c
@@ -285,14 +285,9 @@ void SV_GetUsercmd( int clientNum, usercmd_t *cmd ) {
//==============================================
static int FloatAsInt( float f ) {
- union
- {
- int i;
- float f;
- } temp;
-
- temp.f = f;
- return temp.i;
+ floatint_t fi;
+ fi.f = f;
+ return fi.i;
}
/*
diff --git a/src/server/sv_main.c b/src/server/sv_main.c
index 7b66aa6f..01da0f5d 100644
--- a/src/server/sv_main.c
+++ b/src/server/sv_main.c
@@ -225,6 +225,7 @@ but not on every player enter or exit.
void SV_MasterHeartbeat( void ) {
static netadr_t adr[MAX_MASTER_SERVERS];
int i;
+ int res;
// "dedicated 1" is for lan play, "dedicated 2" is for inet public play
if ( !com_dedicated || com_dedicated->integer != 2 ) {
@@ -251,11 +252,13 @@ void SV_MasterHeartbeat( void ) {
sv_master[i]->modified = qfalse;
Com_Printf( "Resolving %s\n", sv_master[i]->string );
- if ( !NET_StringToAdr( sv_master[i]->string, &adr[i], NA_UNSPEC ) ) {
+ res = NET_StringToAdr( sv_master[i]->string, &adr[i], NA_UNSPEC );
+ if ( !res ) {
Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string );
continue;
}
- if ( !strchr( sv_master[i]->string, ':' ) ) {
+ if ( res == 2 ) {
+ // if no port was specified, use the default master port
adr[i].port = BigShort( PORT_MASTER );
}
Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i]));
diff --git a/src/sys/con_tty.c b/src/sys/con_tty.c
index 687d1dd4..cdd686a1 100644
--- a/src/sys/con_tty.c
+++ b/src/sys/con_tty.c
@@ -87,12 +87,14 @@ send "\b \b"
static void CON_Back( void )
{
char key;
+ size_t size;
+
key = '\b';
- write(1, &key, 1);
+ size = write(1, &key, 1);
key = ' ';
- write(1, &key, 1);
+ size = write(1, &key, 1);
key = '\b';
- write(1, &key, 1);
+ size = write(1, &key, 1);
}
/*
@@ -143,12 +145,13 @@ static void CON_Show( void )
ttycon_hide--;
if (ttycon_hide == 0)
{
- write( 1, "]", 1 );
+ size_t size;
+ size = write( 1, "]", 1 );
if (TTY_con.cursor)
{
for (i=0; i<TTY_con.cursor; i++)
{
- write(1, TTY_con.buffer+i, 1);
+ size = write(1, TTY_con.buffer+i, 1);
}
}
}
@@ -308,6 +311,7 @@ char *CON_Input( void )
int avail;
char key;
field_t *history;
+ size_t size;
if( ttycon_on )
{
@@ -337,8 +341,8 @@ char *CON_Input( void )
strcpy(text, TTY_con.buffer);
Field_Clear(&TTY_con);
key = '\n';
- write(1, &key, 1);
- write( 1, "]", 1 );
+ size = write(1, &key, 1);
+ size = write( 1, "]", 1 );
return text;
}
if (key == '\t')
@@ -400,7 +404,7 @@ char *CON_Input( void )
TTY_con.buffer[TTY_con.cursor] = key;
TTY_con.cursor++;
// print the current line (this is differential)
- write(1, &key, 1);
+ size = write(1, &key, 1);
}
return NULL;
diff --git a/src/sys/sys_unix.c b/src/sys/sys_unix.c
index 760b6022..b55bbe6d 100644
--- a/src/sys/sys_unix.c
+++ b/src/sys/sys_unix.c
@@ -231,7 +231,10 @@ char *Sys_Cwd( void )
{
static char cwd[MAX_OSPATH];
- getcwd( cwd, sizeof( cwd ) - 1 );
+ char *result = getcwd( cwd, sizeof( cwd ) - 1 );
+ if( result != cwd )
+ return NULL;
+
cwd[MAX_OSPATH-1] = 0;
return cwd;
diff --git a/src/tools/lcc/src/bytecode.c b/src/tools/lcc/src/bytecode.c
index b267d6fa..e83429fc 100644
--- a/src/tools/lcc/src/bytecode.c
+++ b/src/tools/lcc/src/bytecode.c
@@ -40,8 +40,9 @@ static void I(defconst)(int suffix, int size, Value v) {
case P: print("byte %d %U\n", size, (unsigned long)v.p); return;
case F:
if (size == 4) {
- float f = v.d;
- print("byte 4 %u\n", *(unsigned *)&f);
+ floatint_t fi;
+ fi.f = v.d;
+ print("byte 4 %u\n", fi.ui);
} else {
unsigned *p = (unsigned *)&v.d;
print("byte 4 %u\n", p[swap]);
@@ -67,10 +68,10 @@ static void I(defsymbol)(Symbol p) {
case P: p->x.name = stringf("%U", p->u.c.v.p); break;
case F:
{ // JDC: added this to get inline floats
- unsigned temp;
+ floatint_t temp;
- *(float *)&temp = p->u.c.v.d;
- p->x.name = stringf("%U", temp );
+ temp.f = p->u.c.v.d;
+ p->x.name = stringf("%U", temp.ui );
}
break;// JDC: added this
default: assert(0);
@@ -260,7 +261,8 @@ static void LoadSourceFile( const char *filename ) {
length = filelength( f );
sourceFile = malloc( length + 1 );
if ( sourceFile ) {
- fread( sourceFile, length, 1, f );
+ size_t size;
+ size = fread( sourceFile, length, 1, f );
sourceFile[length] = 0;
}
diff --git a/src/tools/lcc/src/c.h b/src/tools/lcc/src/c.h
index e36380ef..68c8f629 100644
--- a/src/tools/lcc/src/c.h
+++ b/src/tools/lcc/src/c.h
@@ -98,6 +98,12 @@ typedef struct {
void *xt;
} Xtype;
+typedef union {
+ float f;
+ int i;
+ unsigned int ui;
+} floatint_t;
+
#include "config.h"
typedef struct metrics {
unsigned char size, align, outofline;