commit
4abfa88af8
|
@ -0,0 +1,4 @@
|
|||
[submodule "gzdoom"]
|
||||
path = Projects/Android/jni/gzdoom-g3.3mgw_mobile
|
||||
url = https://github.com/emawind84/gzdoom.git
|
||||
branch = questzdoom
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.drbeef.questzdoom"
|
||||
android:versionCode="28"
|
||||
android:versionName="1.2.3" android:installLocation="auto" >
|
||||
android:versionCode="29"
|
||||
android:versionName="1.3.0" android:installLocation="auto" >
|
||||
|
||||
<!-- Tell the system this app requires OpenGL ES 3.1. -->
|
||||
<uses-feature android:glEsVersion="0x00030001" android:required="true"/>
|
||||
|
@ -19,6 +19,7 @@
|
|||
<application android:allowBackup="false" android:icon="@drawable/ic_qquest" android:label="@string/qzdoom">
|
||||
<meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
|
||||
<meta-data android:name="com.oculus.supportedDevices" android:value="quest|quest2"/>
|
||||
<meta-data android:name="com.oculus.ossplash" android:value="true"/>
|
||||
<!-- The activity is the built-in NativeActivity framework class. -->
|
||||
<!-- launchMode is set to singleTask because there should never be multiple copies of the app running. -->
|
||||
<!-- Theme.Black.NoTitleBar.Fullscreen gives solid black instead of a (bad stereoscopic) gradient on app transition. -->
|
||||
|
|
|
@ -701,7 +701,7 @@ void ovrRenderer_Create( int width, int height, ovrRenderer * renderer, const ov
|
|||
renderer->NumBuffers = VRAPI_FRAME_LAYER_EYE_MAX;
|
||||
|
||||
//Now using a symmetrical render target, based on the horizontal FOV
|
||||
QzDoom_GetFOV();
|
||||
//QzDoom_GetFOV();
|
||||
|
||||
// Create the render Textures.
|
||||
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
|
||||
|
@ -1335,6 +1335,29 @@ int QzDoom_GetRefresh()
|
|||
return vrapi_GetSystemPropertyInt(&gAppState.Java, VRAPI_SYS_PROP_DISPLAY_REFRESH_RATE);
|
||||
}
|
||||
|
||||
int QzDoom_SetRefreshRate(int refreshRate)
|
||||
{
|
||||
return vrapi_SetDisplayRefreshRate(gAppState.Ovr, (float)refreshRate);
|
||||
}
|
||||
|
||||
bool QzDoom_IsRefreshSupported(int refreshRate)
|
||||
{
|
||||
int size = vrapi_GetSystemPropertyInt(&gAppState.Java, VRAPI_SYS_PROP_NUM_SUPPORTED_DISPLAY_REFRESH_RATES);
|
||||
float supported_rates[size];
|
||||
int elements = vrapi_GetSystemPropertyFloatArray(&gAppState.Java,
|
||||
VRAPI_SYS_PROP_SUPPORTED_DISPLAY_REFRESH_RATES,
|
||||
supported_rates, size);
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (refreshRate == (int)supported_rates[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ALOGV("Refresh rate not supported: %dHz", refreshRate);
|
||||
return false;
|
||||
}
|
||||
|
||||
float QzDoom_GetFOV()
|
||||
{
|
||||
vrFOV = vrapi_GetSystemPropertyInt(&gAppState.Java, VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_Y);
|
||||
|
@ -1499,6 +1522,10 @@ void * AppThreadFunction(void * parm ) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (QzDoom_IsRefreshSupported(DISPLAY_REFRESH)) {
|
||||
QzDoom_SetRefreshRate(DISPLAY_REFRESH);
|
||||
}
|
||||
|
||||
// Create the scene if not yet created.
|
||||
ovrScene_Create( m_width, m_height, &gAppState.Scene, &java );
|
||||
|
||||
|
@ -1530,11 +1557,6 @@ void QzDoom_FrameSetup()
|
|||
{
|
||||
//Use floor based tracking space
|
||||
vrapi_SetTrackingSpace(gAppState.Ovr, VRAPI_TRACKING_SPACE_LOCAL_FLOOR);
|
||||
|
||||
//Set the screen refresh - repeat this every frame so VrApi doesn't try changing it on us
|
||||
if (DISPLAY_REFRESH != -1) {
|
||||
vrapi_SetDisplayRefreshRate(gAppState.Ovr, DISPLAY_REFRESH);
|
||||
}
|
||||
}
|
||||
|
||||
void QzDoom_processHaptics() {//Handle haptics
|
||||
|
@ -1866,7 +1888,7 @@ JNIEXPORT jlong JNICALL Java_com_drbeef_questzdoom_GLES3JNILib_onCreate( JNIEnv
|
|||
gpu = arg_int0("g", "gpu", "<int>", "GPU perf index 1-4 (default: 3)"),
|
||||
msaa = arg_int0("m", "msaa", "<int>", "MSAA 1-4 (default: 1)"),
|
||||
ffr = arg_int0("f", "ffr", "<int>", "FFR 0-4 (default: 0)"),
|
||||
refresh = arg_int0("r", "refresh", "<int>", "Display Refresh 60 or 72 (default: 72)"),
|
||||
refresh = arg_int0("r", "refresh", "<int>", "Display Refresh 60, 72 or 90 (default: 72)"),
|
||||
end = arg_end(20)
|
||||
};
|
||||
|
||||
|
@ -1918,7 +1940,7 @@ JNIEXPORT jlong JNICALL Java_com_drbeef_questzdoom_GLES3JNILib_onCreate( JNIEnv
|
|||
FFR = ffr->ival[0];
|
||||
}
|
||||
|
||||
if (refresh->count > 0 && (refresh->ival[0] == 60 || refresh->ival[0] == 72))
|
||||
if (refresh->count > 0 && (refresh->ival[0] == 60 || refresh->ival[0] == 72 || refresh->ival[0] == 90 || refresh->ival[0] == 120))
|
||||
{
|
||||
DISPLAY_REFRESH = refresh->ival[0];
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@ void QzDoom_setUseScreenLayer(bool use);
|
|||
void QzDoom_processHaptics();
|
||||
void QzDoom_getHMDOrientation(ovrTracking2 *tracking);
|
||||
void QzDoom_getTrackedRemotesOrientation(int vr_control_scheme);
|
||||
int QzDoom_SetRefreshRate(int refreshRate);
|
||||
|
||||
void QzDoom_HapticEvent(const char* event, int position, int intensity, float angle, float yHeight );
|
||||
void QzDoom_HapticEnable();
|
||||
|
|
|
@ -33,21 +33,6 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
|
|||
handleTrackedControllerButton(&leftTrackedRemoteState_new, &leftTrackedRemoteState_old, ovrButton_Enter, KEY_ESCAPE);
|
||||
handleTrackedControllerButton(&rightTrackedRemoteState_new, &rightTrackedRemoteState_old, ovrButton_Enter, KEY_ESCAPE); // For users who have switched the buttons
|
||||
|
||||
if (getGameState() != 0 || getMenuState() == 1) // If getMenuState returns 2, then we are waiting for a key mapping input, so send normal keymappings, don't send these
|
||||
{
|
||||
Joy_GenerateButtonEvents((pOffTrackedRemoteOld->Joystick.x > 0.7f ? 1 : 0), (pOffTrackedRemoteNew->Joystick.x > 0.7f ? 1 : 0), 1, KEY_PAD_DPAD_RIGHT);
|
||||
Joy_GenerateButtonEvents((pDominantTrackedRemoteOld->Joystick.x > 0.7f ? 1 : 0), (pDominantTrackedRemoteNew->Joystick.x > 0.7f ? 1 : 0), 1, KEY_PAD_DPAD_RIGHT);
|
||||
|
||||
Joy_GenerateButtonEvents((pOffTrackedRemoteOld->Joystick.x < -0.7f ? 1 : 0), (pOffTrackedRemoteNew->Joystick.x < -0.7f ? 1 : 0), 1, KEY_PAD_DPAD_LEFT);
|
||||
Joy_GenerateButtonEvents((pDominantTrackedRemoteOld->Joystick.x < -0.7f ? 1 : 0), (pDominantTrackedRemoteNew->Joystick.x < -0.7f ? 1 : 0), 1, KEY_PAD_DPAD_LEFT);
|
||||
|
||||
Joy_GenerateButtonEvents((pOffTrackedRemoteOld->Joystick.y < -0.7f ? 1 : 0), (pOffTrackedRemoteNew->Joystick.y < -0.7f ? 1 : 0), 1, KEY_PAD_DPAD_DOWN);
|
||||
Joy_GenerateButtonEvents((pDominantTrackedRemoteOld->Joystick.y < -0.7f ? 1 : 0), (pDominantTrackedRemoteNew->Joystick.y < -0.7f ? 1 : 0), 1, KEY_PAD_DPAD_DOWN);
|
||||
|
||||
Joy_GenerateButtonEvents((pOffTrackedRemoteOld->Joystick.y > 0.7f ? 1 : 0), (pOffTrackedRemoteNew->Joystick.y > 0.7f ? 1 : 0), 1, KEY_PAD_DPAD_UP);
|
||||
Joy_GenerateButtonEvents((pDominantTrackedRemoteOld->Joystick.y > 0.7f ? 1 : 0), (pDominantTrackedRemoteNew->Joystick.y > 0.7f ? 1 : 0), 1, KEY_PAD_DPAD_UP);
|
||||
}
|
||||
|
||||
//Dominant Grip works like a shift key
|
||||
bool dominantGripPushedOld = vr_secondarybuttonmappings ?
|
||||
(pDominantTrackedRemoteOld->Buttons & ovrButton_GripTrigger) != 0 : false;
|
||||
|
@ -105,6 +90,18 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
|
|||
secondaryButton2 = offButton2;
|
||||
}
|
||||
|
||||
Joy_GenerateButtonEvents((pSecondaryTrackedRemoteOld->Joystick.x > 0.7f ? 1 : 0), (pSecondaryTrackedRemoteNew->Joystick.x > 0.7f ? 1 : 0), 1, KEY_JOYAXIS1PLUS);
|
||||
Joy_GenerateButtonEvents((pSecondaryTrackedRemoteOld->Joystick.x < -0.7f ? 1 : 0), (pSecondaryTrackedRemoteNew->Joystick.x < -0.7f ? 1 : 0), 1, KEY_JOYAXIS1MINUS);
|
||||
|
||||
Joy_GenerateButtonEvents((pPrimaryTrackedRemoteOld->Joystick.x > 0.7f ? 1 : 0), (pPrimaryTrackedRemoteNew->Joystick.x > 0.7f ? 1 : 0), 1, KEY_JOYAXIS3PLUS);
|
||||
Joy_GenerateButtonEvents((pPrimaryTrackedRemoteOld->Joystick.x < -0.7f ? 1 : 0), (pPrimaryTrackedRemoteNew->Joystick.x < -0.7f ? 1 : 0), 1, KEY_JOYAXIS3MINUS);
|
||||
|
||||
Joy_GenerateButtonEvents((pSecondaryTrackedRemoteOld->Joystick.y < -0.7f ? 1 : 0), (pSecondaryTrackedRemoteNew->Joystick.y < -0.7f ? 1 : 0), 1, KEY_JOYAXIS2MINUS);
|
||||
Joy_GenerateButtonEvents((pSecondaryTrackedRemoteOld->Joystick.y > 0.7f ? 1 : 0), (pSecondaryTrackedRemoteNew->Joystick.y > 0.7f ? 1 : 0), 1, KEY_JOYAXIS2PLUS);
|
||||
|
||||
Joy_GenerateButtonEvents((pPrimaryTrackedRemoteOld->Joystick.y < -0.7f ? 1 : 0), (pPrimaryTrackedRemoteNew->Joystick.y < -0.7f ? 1 : 0), 1, KEY_JOYAXIS4MINUS);
|
||||
Joy_GenerateButtonEvents((pPrimaryTrackedRemoteOld->Joystick.y > 0.7f ? 1 : 0), (pPrimaryTrackedRemoteNew->Joystick.y > 0.7f ? 1 : 0), 1, KEY_JOYAXIS4PLUS);
|
||||
|
||||
//In cinema mode, right-stick controls mouse
|
||||
const float mouseSpeed = 3.0f;
|
||||
if (cinemamode)
|
||||
|
@ -148,15 +145,11 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
|
|||
weaponoffset[1] = pDominantTracking->HeadPose.Pose.Position.y - hmdPosition[1];
|
||||
weaponoffset[2] = pDominantTracking->HeadPose.Pose.Position.z - hmdPosition[2];
|
||||
|
||||
{
|
||||
vec2_t v;
|
||||
float yawRotation = cinemamode ? getViewpointYaw() - hmdorientation[YAW] :
|
||||
doomYaw - hmdorientation[YAW];
|
||||
rotateAboutOrigin(weaponoffset[0], weaponoffset[2],
|
||||
-yawRotation, v);
|
||||
weaponoffset[0] = v[1];
|
||||
weaponoffset[2] = v[0];
|
||||
}
|
||||
vec2_t v;
|
||||
float yawRotation = getViewpointYaw() - hmdorientation[YAW];
|
||||
rotateAboutOrigin(weaponoffset[0], weaponoffset[2], -yawRotation, v);
|
||||
weaponoffset[0] = v[1];
|
||||
weaponoffset[2] = v[0];
|
||||
|
||||
//Set gun angles
|
||||
const ovrQuatf quatRemote = pDominantTracking->HeadPose.Pose.Orientation;
|
||||
|
@ -190,15 +183,15 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
|
|||
offhandoffset[2] = pOffTracking->HeadPose.Pose.Position.z - hmdPosition[2];
|
||||
|
||||
vec2_t v;
|
||||
rotateAboutOrigin(offhandoffset[0], offhandoffset[2], -(doomYaw - hmdorientation[YAW]),
|
||||
v);
|
||||
float yawRotation = getViewpointYaw() - hmdorientation[YAW];
|
||||
rotateAboutOrigin(offhandoffset[0], offhandoffset[2], -yawRotation, v);
|
||||
offhandoffset[0] = v[1];
|
||||
offhandoffset[2] = v[0];
|
||||
|
||||
vec3_t rotation = {0};
|
||||
QuatToYawPitchRoll(pOffTracking->HeadPose.Pose.Orientation, rotation, offhandangles);
|
||||
|
||||
if (vr_moveuseoffhand != 0) {
|
||||
if (vr_moveuseoffhand) {
|
||||
controllerYawHeading = offhandangles[YAW] - hmdorientation[YAW];
|
||||
} else {
|
||||
controllerYawHeading = 0.0f;
|
||||
|
@ -318,18 +311,18 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
|
|||
between(-1.0f, pPrimaryTrackedRemoteNew->Joystick.y, -0.8f))) {
|
||||
if (itemSwitched == 0) {
|
||||
if (between(0.8f, pPrimaryTrackedRemoteNew->Joystick.y, 1.0f)) {
|
||||
Joy_GenerateButtonEvents(0, 1, 1, KEY_MWHEELDOWN);
|
||||
Joy_GenerateButtonEvents(0, 1, 1, KEY_MWHEELUP);
|
||||
itemSwitched = 1;
|
||||
} else {
|
||||
Joy_GenerateButtonEvents(0, 1, 1, KEY_MWHEELUP);
|
||||
Joy_GenerateButtonEvents(0, 1, 1, KEY_MWHEELDOWN);
|
||||
itemSwitched = 2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (itemSwitched == 1) {
|
||||
Joy_GenerateButtonEvents(1, 0, 1, KEY_MWHEELDOWN);
|
||||
} else if (itemSwitched == 2) {
|
||||
Joy_GenerateButtonEvents(1, 0, 1, KEY_MWHEELUP);
|
||||
} else if (itemSwitched == 2) {
|
||||
Joy_GenerateButtonEvents(1, 0, 1, KEY_MWHEELDOWN);
|
||||
}
|
||||
itemSwitched = 0;
|
||||
}
|
||||
|
@ -385,7 +378,10 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
|
|||
((pDominantTrackedRemoteNew->Buttons & ovrButton_Joystick) != 0) && !dominantGripPushedNew ? 1 : 0,
|
||||
1, KEY_ENTER);
|
||||
|
||||
|
||||
//No Default Binding
|
||||
Joy_GenerateButtonEvents(((pDominantTrackedRemoteOld->Touches & ovrTouch_ThumbRest) != 0) && !dominantGripPushedOld ? 1 : 0,
|
||||
((pDominantTrackedRemoteNew->Touches & ovrTouch_ThumbRest) != 0) && !dominantGripPushedNew ? 1 : 0,
|
||||
1, KEY_JOY5);
|
||||
|
||||
if (vr_secondarybuttonmappings) {
|
||||
//Dominant Hand - Secondary keys (grip pushed)
|
||||
|
@ -418,6 +414,13 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
|
|||
((pDominantTrackedRemoteNew->Buttons & ovrButton_Joystick) != 0) &&
|
||||
dominantGripPushedNew ? 1 : 0,
|
||||
1, KEY_TAB);
|
||||
|
||||
//No Default Binding
|
||||
Joy_GenerateButtonEvents(
|
||||
((pDominantTrackedRemoteOld->Touches & ovrTouch_ThumbRest) != 0) && dominantGripPushedOld ? 1 : 0,
|
||||
((pDominantTrackedRemoteNew->Touches & ovrTouch_ThumbRest) != 0) && dominantGripPushedNew ? 1 : 0,
|
||||
1, KEY_JOY6);
|
||||
|
||||
} else {
|
||||
//Use grip as an extra button
|
||||
//Alt-Fire
|
||||
|
@ -451,6 +454,11 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
|
|||
((pOffTrackedRemoteNew->Buttons & ovrButton_Joystick) != 0) && !dominantGripPushedNew ? 1 : 0,
|
||||
1, KEY_SPACE);
|
||||
|
||||
//No Default Binding
|
||||
Joy_GenerateButtonEvents(((pOffTrackedRemoteOld->Touches & ovrTouch_ThumbRest) != 0) && !dominantGripPushedOld ? 1 : 0,
|
||||
((pOffTrackedRemoteNew->Touches & ovrTouch_ThumbRest) != 0) && !dominantGripPushedNew ? 1 : 0,
|
||||
1, KEY_JOY7);
|
||||
|
||||
if (!vr_twohandedweapons)
|
||||
{
|
||||
Joy_GenerateButtonEvents(
|
||||
|
@ -496,6 +504,12 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
|
|||
dominantGripPushedNew ? 1 : 0,
|
||||
1, KEY_HOME);
|
||||
|
||||
//No Default Binding
|
||||
Joy_GenerateButtonEvents(
|
||||
((pOffTrackedRemoteOld->Touches & ovrTouch_ThumbRest) != 0) && dominantGripPushedOld ? 1 : 0,
|
||||
((pOffTrackedRemoteNew->Touches & ovrTouch_ThumbRest) != 0) && dominantGripPushedNew ? 1 : 0,
|
||||
1, KEY_JOY8);
|
||||
|
||||
if (!vr_twohandedweapons)
|
||||
{
|
||||
Joy_GenerateButtonEvents(
|
||||
|
|
|
@ -195,7 +195,88 @@
|
|||
#define KEY_JOY4AXIS8PLUS 0x222
|
||||
#define KEY_JOY4AXIS8MINUS 0x223
|
||||
|
||||
#define NUM_KEYS 0x224
|
||||
#define KEY_PAD2_LTHUMB_RIGHT 0x224
|
||||
#define KEY_PAD2_LTHUMB_LEFT 0x225
|
||||
#define KEY_PAD2_LTHUMB_DOWN 0x226
|
||||
#define KEY_PAD2_LTHUMB_UP 0x227
|
||||
|
||||
#define KEY_PAD2_RTHUMB_RIGHT 0x228
|
||||
#define KEY_PAD2_RTHUMB_LEFT 0x229
|
||||
#define KEY_PAD2_RTHUMB_DOWN 0x22A
|
||||
#define KEY_PAD2_RTHUMB_UP 0x22B
|
||||
|
||||
#define KEY_PAD2_DPAD_UP 0x22C
|
||||
#define KEY_PAD2_DPAD_DOWN 0x22D
|
||||
#define KEY_PAD2_DPAD_LEFT 0x22E
|
||||
#define KEY_PAD2_DPAD_RIGHT 0x22F
|
||||
#define KEY_PAD2_START 0x230
|
||||
#define KEY_PAD2_BACK 0x231
|
||||
#define KEY_PAD2_LTHUMB 0x232
|
||||
#define KEY_PAD2_RTHUMB 0x233
|
||||
#define KEY_PAD2_LSHOULDER 0x234
|
||||
#define KEY_PAD2_RSHOULDER 0x235
|
||||
#define KEY_PAD2_LTRIGGER 0x236
|
||||
#define KEY_PAD2_RTRIGGER 0x237
|
||||
#define KEY_PAD2_A 0x238
|
||||
#define KEY_PAD2_B 0x239
|
||||
#define KEY_PAD2_X 0x23A
|
||||
#define KEY_PAD2_Y 0x23B
|
||||
|
||||
#define KEY_PAD3_LTHUMB_RIGHT 0x23C
|
||||
#define KEY_PAD3_LTHUMB_LEFT 0x23D
|
||||
#define KEY_PAD3_LTHUMB_DOWN 0x23E
|
||||
#define KEY_PAD3_LTHUMB_UP 0x23F
|
||||
|
||||
#define KEY_PAD3_RTHUMB_RIGHT 0x240
|
||||
#define KEY_PAD3_RTHUMB_LEFT 0x241
|
||||
#define KEY_PAD3_RTHUMB_DOWN 0x242
|
||||
#define KEY_PAD3_RTHUMB_UP 0x243
|
||||
|
||||
#define KEY_PAD3_DPAD_UP 0x244
|
||||
#define KEY_PAD3_DPAD_DOWN 0x245
|
||||
#define KEY_PAD3_DPAD_LEFT 0x246
|
||||
#define KEY_PAD3_DPAD_RIGHT 0x247
|
||||
#define KEY_PAD3_START 0x248
|
||||
#define KEY_PAD3_BACK 0x249
|
||||
#define KEY_PAD3_LTHUMB 0x24A
|
||||
#define KEY_PAD3_RTHUMB 0x24B
|
||||
#define KEY_PAD3_LSHOULDER 0x24C
|
||||
#define KEY_PAD3_RSHOULDER 0x24D
|
||||
#define KEY_PAD3_LTRIGGER 0x24E
|
||||
#define KEY_PAD3_RTRIGGER 0x24F
|
||||
#define KEY_PAD3_A 0x250
|
||||
#define KEY_PAD3_B 0x251
|
||||
#define KEY_PAD3_X 0x252
|
||||
#define KEY_PAD3_Y 0x253
|
||||
|
||||
#define KEY_PAD4_LTHUMB_RIGHT 0x254
|
||||
#define KEY_PAD4_LTHUMB_LEFT 0x255
|
||||
#define KEY_PAD4_LTHUMB_DOWN 0x256
|
||||
#define KEY_PAD4_LTHUMB_UP 0x257
|
||||
|
||||
#define KEY_PAD4_RTHUMB_RIGHT 0x258
|
||||
#define KEY_PAD4_RTHUMB_LEFT 0x259
|
||||
#define KEY_PAD4_RTHUMB_DOWN 0x25A
|
||||
#define KEY_PAD4_RTHUMB_UP 0x25B
|
||||
|
||||
#define KEY_PAD4_DPAD_UP 0x25C
|
||||
#define KEY_PAD4_DPAD_DOWN 0x25D
|
||||
#define KEY_PAD4_DPAD_LEFT 0x25E
|
||||
#define KEY_PAD4_DPAD_RIGHT 0x25F
|
||||
#define KEY_PAD4_START 0x260
|
||||
#define KEY_PAD4_BACK 0x261
|
||||
#define KEY_PAD4_LTHUMB 0x262
|
||||
#define KEY_PAD4_RTHUMB 0x263
|
||||
#define KEY_PAD4_LSHOULDER 0x264
|
||||
#define KEY_PAD4_RSHOULDER 0x265
|
||||
#define KEY_PAD4_LTRIGGER 0x266
|
||||
#define KEY_PAD4_RTRIGGER 0x267
|
||||
#define KEY_PAD4_A 0x268
|
||||
#define KEY_PAD4_B 0x269
|
||||
#define KEY_PAD4_X 0x26A
|
||||
#define KEY_PAD4_Y 0x26B
|
||||
|
||||
#define NUM_KEYS 0x26C
|
||||
|
||||
|
||||
#endif //QZDOOM_DOOMKEYS_H
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 9155ab78b52e490213659a570fccce3c4a65f224
|
|
@ -1,54 +0,0 @@
|
|||
version: "{build}"
|
||||
|
||||
branches:
|
||||
except:
|
||||
- /^travis.*$/
|
||||
|
||||
clone_depth: 10
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- GENERATOR: "Visual Studio 14 2015"
|
||||
ARCH: Win32
|
||||
CONFIGURATION: Release
|
||||
TOOLSET: v140_xp
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2015"
|
||||
- GENERATOR: "Visual Studio 15 2017"
|
||||
ARCH: x64
|
||||
CONFIGURATION: Release
|
||||
TOOLSET: v141
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2017"
|
||||
- GENERATOR: "Visual Studio 16 2019"
|
||||
ARCH: Win32
|
||||
CONFIGURATION: Release
|
||||
TOOLSET: v142
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2019"
|
||||
- GENERATOR: "Visual Studio 16 2019"
|
||||
ARCH: x64
|
||||
CONFIGURATION: Release
|
||||
TOOLSET: v142
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2019"
|
||||
- GENERATOR: "Visual Studio 16 2019"
|
||||
ARCH: x64
|
||||
CONFIGURATION: Debug
|
||||
TOOLSET: v142
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2019"
|
||||
|
||||
build_script:
|
||||
- md build
|
||||
- cd build
|
||||
- cmake -G "%GENERATOR%" -A %ARCH% -T "%TOOLSET%" -DPK3_QUIET_ZIPDIR=YES ..
|
||||
- cmake --build . --config "%CONFIGURATION%" -- -maxcpucount -verbosity:minimal
|
||||
|
||||
after_build:
|
||||
- set OUTPUT_DIR=%APPVEYOR_BUILD_FOLDER%\build\%CONFIGURATION%\
|
||||
- 7z a ..\lzdoom.zip "%OUTPUT_DIR%lzdoom.exe" "%OUTPUT_DIR%*.pk3"
|
||||
|
||||
artifacts:
|
||||
- path: lzdoom.zip
|
||||
|
||||
notifications:
|
||||
- provider: Email
|
||||
on_build_success: false
|
||||
on_build_failure: false
|
||||
on_build_status_changed: false
|
|
@ -1,27 +0,0 @@
|
|||
* text=auto
|
||||
|
||||
*.h text
|
||||
*.c text
|
||||
*.cc text
|
||||
*.cpp text
|
||||
*.mm text
|
||||
*.lemon text
|
||||
*.y text
|
||||
*.re text
|
||||
*.i text
|
||||
*.asm text
|
||||
*.S text
|
||||
|
||||
*.vcproj text eol=crlf
|
||||
*.sln text eol=crlf
|
||||
*.bat text eol=crlf
|
||||
*.rc text eol=crlf
|
||||
|
||||
*.txt text
|
||||
language.* text
|
||||
|
||||
*.png binary
|
||||
*.imgz binary
|
||||
*.lmp binary
|
||||
*.flac binary
|
||||
*.dat binary
|
|
@ -1,57 +0,0 @@
|
|||
/Debug
|
||||
*.ncb
|
||||
*.suo
|
||||
*.pdb
|
||||
*.ilk
|
||||
*.aps
|
||||
/fmodapi*/
|
||||
/Release
|
||||
/wadsrc_wad
|
||||
*.user
|
||||
/build
|
||||
/debug
|
||||
/release
|
||||
*/debug
|
||||
*/release
|
||||
/release_gcc
|
||||
/dumb/vc6/dumb_static/release
|
||||
/dumb/vc6/dumb_static/debug
|
||||
/dumb/vc6/dumb_static/x64
|
||||
/DOOMSTATS.TXT
|
||||
/src/gitinfo.h
|
||||
/src/sc_man_scanner.h
|
||||
/src/xlat/xlat_parser.c
|
||||
/src/xlat/xlat_parser.h
|
||||
/src/xlat/xlat_parser.out
|
||||
/src/zscript/zcc-parse.c
|
||||
/src/zscript/zcc-parse.h
|
||||
/src/zscript/zcc-parse.out
|
||||
/tools/*/debug
|
||||
/tools/*/release
|
||||
/tools/*/*.exe
|
||||
/tools/lemon/build
|
||||
/tools/re2c/build
|
||||
/tools/updaterevision/x64/
|
||||
/tools/zipdir/x64
|
||||
/wadsrc/*.pk3
|
||||
/build_vc2013
|
||||
/bzip2/x64/
|
||||
/disasm.txt
|
||||
/game-music-emu/x64/
|
||||
/gdtoa/x64/
|
||||
/jpeg-6b/x64/
|
||||
/lzma/x64/
|
||||
/zlib/x64/
|
||||
/build_vc2013_64bit
|
||||
/build_vc2015
|
||||
/build_vc2015-32
|
||||
/build_vc2015-64
|
||||
/build_vc2017-64
|
||||
/build
|
||||
/llvm
|
||||
/src/r_drawersasm.obj
|
||||
/src/r_drawersasm.o
|
||||
.vs
|
||||
/src/gl/unused
|
||||
/mapfiles_release/*.map
|
||||
.DS_Store
|
|
@ -1,152 +0,0 @@
|
|||
language: cpp
|
||||
dist: xenial
|
||||
|
||||
branches:
|
||||
except:
|
||||
- /^appveyor.*$/
|
||||
|
||||
git:
|
||||
depth: 10
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
env:
|
||||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Debug -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9"
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode10.3
|
||||
env:
|
||||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9"
|
||||
|
||||
- os: windows
|
||||
env:
|
||||
- CMAKE_OPTIONS="-A Win32"
|
||||
|
||||
- os: windows
|
||||
env:
|
||||
- CMAKE_OPTIONS="-A x64"
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
- GCC_VERSION=4.9
|
||||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=-Wno-maybe-uninitialized"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-4.9
|
||||
- libsdl2-dev
|
||||
- libgtk2.0-dev
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
- GCC_VERSION=5
|
||||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=-Wno-maybe-uninitialized"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-5
|
||||
- libsdl2-dev
|
||||
- libgtk-3-dev
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
- GCC_VERSION=6
|
||||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_CXX_FLAGS=-Wno-maybe-uninitialized"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-6
|
||||
- libsdl2-dev
|
||||
- libgtk2.0-dev
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
- GCC_VERSION=7
|
||||
- CMAKE_OPTIONS="-DCMAKE_CXX_FLAGS=-Wno-implicit-fallthrough"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-7
|
||||
- libsdl2-dev
|
||||
- libgtk-3-dev
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
- GCC_VERSION=8
|
||||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_CXX_FLAGS=-Wno-implicit-fallthrough"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-8
|
||||
- libsdl2-dev
|
||||
- libgtk-3-dev
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env:
|
||||
- GCC_VERSION=9
|
||||
- CMAKE_OPTIONS="-DCMAKE_CXX_FLAGS=-Wno-implicit-fallthrough"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-9
|
||||
- libsdl2-dev
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env:
|
||||
- CLANG_VERSION=8
|
||||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=MinSizeRel -DDYN_OPENAL=NO -DDYN_SNDFILE=NO -DDYN_MPG123=NO -DDYN_FLUIDSYNTH=NO"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-xenial-8
|
||||
packages:
|
||||
- clang-8
|
||||
- libsdl2-dev
|
||||
- libgme-dev
|
||||
- libopenal-dev
|
||||
- libmpg123-dev
|
||||
- libsndfile-dev
|
||||
- libfluidsynth-dev
|
||||
- libgtk-3-dev
|
||||
|
||||
before_install:
|
||||
- if [ -n "$GCC_VERSION" ]; then export CC="gcc-${GCC_VERSION}" CXX="g++-${GCC_VERSION}"; fi
|
||||
- if [ -n "$CLANG_VERSION" ]; then export CC="clang-${CLANG_VERSION}" CXX="clang++-${CLANG_VERSION}"; fi
|
||||
- $CC --version
|
||||
- $CXX --version
|
||||
|
||||
script:
|
||||
- echo ${TRAVIS_BUILD_DIR}
|
||||
- mkdir build
|
||||
- cd build
|
||||
- >
|
||||
cmake ${CMAKE_OPTIONS} \
|
||||
-DFORCE_INTERNAL_ZLIB=YES \
|
||||
-DFORCE_INTERNAL_JPEG=YES \
|
||||
-DFORCE_INTERNAL_BZIP2=YES \
|
||||
-DFORCE_INTERNAL_GME=YES \
|
||||
-DPK3_QUIET_ZIPDIR=YES \
|
||||
..
|
||||
- if [[ $TRAVIS_OS_NAME == 'windows' ]]; then cmake --build . --config Release -- -maxcpucount -verbosity:minimal; fi
|
||||
- if [[ $TRAVIS_OS_NAME != 'windows' ]]; then cmake --build . -- --jobs=2 --keep-going; fi
|
||||
|
||||
notifications:
|
||||
email: false
|
|
@ -1,415 +0,0 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
project(LZDoom)
|
||||
|
||||
if( COMMAND cmake_policy )
|
||||
if( POLICY CMP0011 )
|
||||
cmake_policy( SET CMP0011 NEW )
|
||||
endif()
|
||||
if( POLICY CMP0054 )
|
||||
cmake_policy( SET CMP0054 NEW )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list( APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake )
|
||||
include( FindPackageHandleStandardArgs )
|
||||
|
||||
# Produce a warning if XP support will be missing when building a 32 bit target for MSVC.
|
||||
if( MSVC )
|
||||
if(NOT "${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
|
||||
|
||||
list( APPEND WINXP_TOOLSETS v140_xp v141_xp)
|
||||
list( FIND WINXP_TOOLSETS "${CMAKE_GENERATOR_TOOLSET}" HAVE_WINXP_SUPPORT)
|
||||
|
||||
if( HAVE_WINXP_SUPPORT EQUAL -1 )
|
||||
string( REPLACE ";" " or " WINXP_TOOLSETS_STR "${WINXP_TOOLSETS}" )
|
||||
message( WARNING "This project supports Windows XP but you must set the optional toolset to ${WINXP_TOOLSETS_STR} manually to have it in your build!\n"
|
||||
"Assign toolset's name to CMAKE_GENERATOR_TOOLSET variable or use -T <toolset> from the command prompt." )
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Support cross compiling
|
||||
option( FORCE_CROSSCOMPILE "Turn on cross compiling." NO )
|
||||
if( FORCE_CROSSCOMPILE )
|
||||
set( CMAKE_CROSSCOMPILING TRUE )
|
||||
endif()
|
||||
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
set(IMPORT_EXECUTABLES "IMPORTFILE-NOTFOUND" CACHE FILEPATH "Export file from native build.")
|
||||
include(${IMPORT_EXECUTABLES})
|
||||
endif()
|
||||
|
||||
# Recursive function to place PK3 archive source files into a hierarchy of source file in the IDE
|
||||
function( assort_pk3_source_folder FOLDER_NAME PK3_DIR )
|
||||
# Assort source files into folders in the IDE
|
||||
file(GLOB PK3_SRCS ${PK3_DIR}/*) # Create list of all files in this folder
|
||||
foreach(PK3_SRC ${PK3_SRCS})
|
||||
# If there are subfolders, recurse into them
|
||||
if(IS_DIRECTORY ${PK3_SRC})
|
||||
get_filename_component(DIRNAME ${PK3_SRC} NAME)
|
||||
# Exclude folder from list of source files
|
||||
list(REMOVE_ITEM PK3_SRCS ${PK3_SRC})
|
||||
# Recurse deeper into the filesystem folder tree
|
||||
assort_pk3_source_folder( ${FOLDER_NAME}\\${DIRNAME} ${PK3_SRC} )
|
||||
endif()
|
||||
# Assign IDE group for current top-level source files
|
||||
source_group(${FOLDER_NAME} FILES ${PK3_SRCS})
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
option( PK3_QUIET_ZIPDIR "Do not list files processed by zipdir" NO )
|
||||
if( PK3_QUIET_ZIPDIR )
|
||||
set( PK3_ZIPDIR_OPTIONS "-q" )
|
||||
endif()
|
||||
|
||||
# Simplify pk3 building, add_pk3(filename srcdirectory)
|
||||
function( add_pk3 PK3_NAME PK3_DIR )
|
||||
# Generate target name. Just use "pk3" for main pk3 target.
|
||||
string( REPLACE "." "_" PK3_TARGET ${PK3_NAME} )
|
||||
|
||||
if( NOT ZDOOM_OUTPUT_OLDSTYLE )
|
||||
add_custom_command( OUTPUT ${ZDOOM_OUTPUT_DIR}/${PK3_NAME}
|
||||
COMMAND zipdir -udf ${PK3_ZIPDIR_OPTIONS} ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} ${PK3_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} $<TARGET_FILE_DIR:zdoom>/${PK3_NAME}
|
||||
DEPENDS zipdir )
|
||||
else()
|
||||
add_custom_command( OUTPUT ${ZDOOM_OUTPUT_DIR}/${PK3_NAME}
|
||||
COMMAND zipdir -udf ${PK3_ZIPDIR_OPTIONS} ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} ${PK3_DIR}
|
||||
DEPENDS zipdir )
|
||||
endif()
|
||||
# Create a list of source files for this PK3, for use in the IDE
|
||||
# Phase 1: Create a list of all source files for this PK3 archive, except
|
||||
# for a couple of strife image file names that confuse CMake.
|
||||
file(GLOB_RECURSE PK3_SRCS ${PK3_DIR}/*)
|
||||
# Exclude from the source list some gzdoom .png files with brackets in the
|
||||
# file names here, because they confuse CMake.
|
||||
# This only affects the list of source files shown in the IDE.
|
||||
# It does not actually remove the files from the PK3 archive.
|
||||
# First replace that toxic bracket character with something we can handle
|
||||
string(REPLACE "[" confusing_bracket PK3_SRCS "${PK3_SRCS}")
|
||||
string(REPLACE "]" confusing_bracket PK3_SRCS "${PK3_SRCS}")
|
||||
foreach(PK3_SRC ${PK3_SRCS}) # All source files at all levels
|
||||
# Exclude those quarantined source file source file names that once had a bracket
|
||||
if(${PK3_SRC} MATCHES confusing_bracket)
|
||||
# message(STATUS "Ignoring PK3 file name containing brackets "${PK3_SRC})
|
||||
list(REMOVE_ITEM PK3_SRCS ${PK3_SRC})
|
||||
endif()
|
||||
endforeach()
|
||||
# Phase 2: Create the PK3 build rule, including the source file list for the IDE
|
||||
# Touch the zipdir executable here so that the pk3s are forced to
|
||||
# rebuild each time since their dependency has "changed."
|
||||
add_custom_target( ${PK3_TARGET} ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E touch $<TARGET_FILE:zipdir>
|
||||
DEPENDS ${ZDOOM_OUTPUT_DIR}/${PK3_NAME}
|
||||
SOURCES ${PK3_SRCS})
|
||||
# Phase 3: Assign source files to a nice folder structure in the IDE
|
||||
assort_pk3_source_folder("Source Files" ${PK3_DIR})
|
||||
# Phase 4: Add the resulting PK3 to the install target.
|
||||
if( WIN32 )
|
||||
set( INSTALL_PK3_PATH . CACHE STRING "Directory where zdoom.pk3 will be placed during install." )
|
||||
else()
|
||||
set( INSTALL_PK3_PATH share/games/doom CACHE STRING "Directory where zdoom.pk3 will be placed during install." )
|
||||
endif()
|
||||
install(FILES "${PROJECT_BINARY_DIR}/${PK3_NAME}"
|
||||
DESTINATION ${INSTALL_PK3_PATH}
|
||||
COMPONENT "Game resources")
|
||||
endfunction()
|
||||
|
||||
# Macro for building libraries without debugging information
|
||||
macro( make_release_only )
|
||||
set( CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_RELEASE} )
|
||||
set( CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELEASE} )
|
||||
string( REPLACE "/MT " "/MTd " CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_RELEASE} )
|
||||
set( CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_RELEASE} )
|
||||
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELEASE} )
|
||||
string( REPLACE "/MT " "/MTd " CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_RELEASE} )
|
||||
endmacro()
|
||||
|
||||
IF( NOT CMAKE_BUILD_TYPE )
|
||||
SET( CMAKE_BUILD_TYPE Debug CACHE STRING
|
||||
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
|
||||
FORCE )
|
||||
ENDIF()
|
||||
|
||||
set( ZDOOM_OUTPUT_DIR ${CMAKE_BINARY_DIR} CACHE PATH "Directory where zdoom.pk3 and the executable will be created." )
|
||||
set( ZDOOM_EXE_NAME "lzdoom" CACHE FILEPATH "Name of the executable to create" )
|
||||
if( MSVC )
|
||||
# Allow the user to use ZDOOM_OUTPUT_DIR as a single release point.
|
||||
# Use zdoom, zdoomd, zdoom64, and zdoomd64 for the binary names
|
||||
option( ZDOOM_OUTPUT_OLDSTYLE "Don't use Release/Debug directories." OFF )
|
||||
else()
|
||||
set( ZDOOM_OUTPUT_OLDSTYLE OFF )
|
||||
endif()
|
||||
|
||||
# Replacement variables for a possible long list of C/C++ compilers compatible with GCC
|
||||
if( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" )
|
||||
set( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE TRUE )
|
||||
else()
|
||||
set( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE FALSE )
|
||||
endif()
|
||||
|
||||
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
set( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE TRUE )
|
||||
else()
|
||||
set( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE FALSE )
|
||||
endif()
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
set( PROFILE 0 CACHE BOOL "Enable profiling with gprof for Debug and RelWithDebInfo build types." )
|
||||
endif()
|
||||
|
||||
option( NO_OPENAL "Disable OpenAL sound support" OFF )
|
||||
|
||||
find_package( BZip2 )
|
||||
find_package( JPEG )
|
||||
find_package( ZLIB )
|
||||
|
||||
include( TargetArch )
|
||||
|
||||
target_architecture(ZDOOM_TARGET_ARCH)
|
||||
|
||||
if( ${ZDOOM_TARGET_ARCH} MATCHES "x86_64" )
|
||||
set( HAVE_VM_JIT ON )
|
||||
endif()
|
||||
|
||||
# no, we're not using external asmjit for now, we made too many modifications to our's.
|
||||
# if the asmjit author uses our changes then we'll update this.
|
||||
|
||||
#if( ${HAVE_VM_JIT} )
|
||||
# find_package( asmjit )
|
||||
#endif()
|
||||
|
||||
# GME
|
||||
#find_path( GME_INCLUDE_DIR gme/gme.h )
|
||||
#find_library( GME_LIBRARIES gme )
|
||||
#mark_as_advanced( GME_INCLUDE_DIR GME_LIBRARIES )
|
||||
#FIND_PACKAGE_HANDLE_STANDARD_ARGS( GME
|
||||
# REQUIRED_VARS GME_LIBRARIES GME_INCLUDE_DIR
|
||||
#)
|
||||
|
||||
if( MSVC )
|
||||
# Eliminate unreferenced functions and data
|
||||
# Perform identical COMDAT folding
|
||||
set( REL_LINKER_FLAGS "/opt:ref /opt:icf /nodefaultlib:msvcrt /TSAWARE /LARGEADDRESSAWARE" )
|
||||
|
||||
# String pooling
|
||||
# Function-level linking
|
||||
# Disable run-time type information
|
||||
set( ALL_C_FLAGS "/GF /Gy /GR-" )
|
||||
|
||||
# Use SSE 2 as minimum always as the true color drawers needs it for __vectorcall
|
||||
#set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2") # This is already the default
|
||||
|
||||
|
||||
# if( CMAKE_SIZEOF_VOID_P MATCHES "4")
|
||||
# # SSE2 option (to allow x87 in 32 bit and disallow extended feature sets which have not yet been checked for precision)
|
||||
# option (ZDOOM_USE_SSE2 "Use SSE2 instruction set")
|
||||
# if (ZDOOM_USE_SSE2)
|
||||
# set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2")
|
||||
# else ()
|
||||
# if (MSVC_VERSION GREATER 1699)
|
||||
# # On Visual C++ 2012 and later SSE2 is the default, so we need to switch it off explicitly
|
||||
# set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:IA32")
|
||||
# endif ()
|
||||
# endif ()
|
||||
# else()
|
||||
# set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2")
|
||||
# endif()
|
||||
|
||||
# Avoid CRT DLL dependancies in release builds, optionally generate assembly output for checking crash locations.
|
||||
option( ZDOOM_GENERATE_ASM "Generate assembly output." OFF )
|
||||
if( ZDOOM_GENERATE_ASM )
|
||||
set( REL_C_FLAGS "/MT /Oy /Oi /FAcs" )
|
||||
else()
|
||||
set( REL_C_FLAGS "/MT /Oy /Oi" )
|
||||
endif()
|
||||
|
||||
|
||||
# Debug allocations in debug builds
|
||||
set( DEB_C_FLAGS "/D _CRTDBG_MAP_ALLOC /MTd" )
|
||||
|
||||
# Disable warnings for unsecure CRT functions from VC8+
|
||||
set( ALL_C_FLAGS "${ALL_C_FLAGS} /wd4996 /DUNICODE /D_UNICODE" )
|
||||
|
||||
# The CMake configurations set /GR and /MD by default, which conflict with our settings.
|
||||
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} )
|
||||
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL} )
|
||||
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} )
|
||||
string(REPLACE "/Ob1 " "/Ob2 " CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} )
|
||||
string(REPLACE "/MDd " " " CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG} )
|
||||
string(REPLACE "/MD " " " CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} )
|
||||
string(REPLACE "/MD " " " CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_MINSIZEREL} )
|
||||
string(REPLACE "/MD " " " CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO} )
|
||||
string(REPLACE "/MDd " " " CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG} )
|
||||
string(REPLACE " /GR" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} )
|
||||
else()
|
||||
set( REL_LINKER_FLAGS "" )
|
||||
set( ALL_C_FLAGS "-ffp-contract=off" )
|
||||
|
||||
if ( UNIX )
|
||||
include(CheckSymbolExists)
|
||||
check_symbol_exists( "fts_set" "fts.h" HAVE_FTS )
|
||||
if ( NOT HAVE_FTS )
|
||||
include ( FindPkgConfig )
|
||||
pkg_check_modules( MUSL_FTS musl-fts )
|
||||
if ( MUSL_FTS_FOUND )
|
||||
set ( ALL_C_FLAGS "${ALL_C_FLAGS} ${MUSL_FTS_LDFLAGS}" )
|
||||
else ( MUSL_FTS_FOUND )
|
||||
message (ERROR "fts_* functions not found in the system" )
|
||||
endif ( MUSL_FTS_FOUND )
|
||||
endif ( NOT HAVE_FTS )
|
||||
endif ( UNIX )
|
||||
|
||||
set( REL_C_FLAGS "" )
|
||||
set( DEB_C_FLAGS "" )
|
||||
|
||||
|
||||
if( APPLE )
|
||||
if( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" )
|
||||
# With standard Apple tools -stdlib=libc++ needs to be specified in order to get
|
||||
# C++11 support using SDKs 10.7 and 10.8.
|
||||
set( CMAKE_CXX_FLAGS "-stdlib=libc++ ${CMAKE_CXX_FLAGS}" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS "-stdlib=libc++ ${CMAKE_EXE_LINKER_FLAGS}" )
|
||||
elseif( CMAKE_CXX_COMPILER_ID STREQUAL "GNU" )
|
||||
# If we're compiling with a custom GCC on the Mac (which we know since g++-4.2 doesn't support C++11) statically link libgcc.
|
||||
set( ALL_C_FLAGS "-static-libgcc" )
|
||||
endif()
|
||||
elseif( NOT MINGW )
|
||||
# Generic GCC/Clang requires position independent executable to be enabled explicitly
|
||||
set( ALL_C_FLAGS "${ALL_C_FLAGS} -fPIE" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie" )
|
||||
endif( APPLE )
|
||||
endif()
|
||||
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${REL_LINKER_FLAGS}" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} ${REL_LINKER_FLAGS}" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} ${REL_LINKER_FLAGS}" )
|
||||
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ALL_C_FLAGS}" )
|
||||
set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${REL_C_FLAGS}" )
|
||||
set( CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" )
|
||||
set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" )
|
||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
|
||||
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ALL_C_FLAGS}" )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${REL_C_FLAGS}" )
|
||||
set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" )
|
||||
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" )
|
||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
|
||||
|
||||
option(FORCE_INTERNAL_ZLIB "Use internal zlib")
|
||||
option(FORCE_INTERNAL_JPEG "Use internal jpeg")
|
||||
option(FORCE_INTERNAL_BZIP2 "Use internal bzip2")
|
||||
option(FORCE_INTERNAL_GME "Use internal gme" ON)
|
||||
mark_as_advanced( FORCE_INTERNAL_GME )
|
||||
option(FORCE_INTERNAL_ASMJIT "Use internal asmjit" ON)
|
||||
mark_as_advanced( FORCE_INTERNAL_ASMJIT )
|
||||
|
||||
# Fast math flags, required by some subprojects
|
||||
set( ZD_FASTMATH_FLAG "" )
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
set( ZD_FASTMATH_FLAG "-ffast-math -ffp-contract=fast" )
|
||||
elseif( MSVC )
|
||||
set( ZD_FASTMATH_FLAG "/fp:fast" )
|
||||
endif()
|
||||
|
||||
if( ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB )
|
||||
message( STATUS "Using system zlib, includes found at ${ZLIB_INCLUDE_DIR}" )
|
||||
else()
|
||||
message( STATUS "Using internal zlib" )
|
||||
set( SKIP_INSTALL_ALL TRUE ) # Avoid installing zlib alongside zdoom
|
||||
add_subdirectory( zlib )
|
||||
set( ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/zlib )
|
||||
set( ZLIB_LIBRARIES z )
|
||||
set( ZLIB_LIBRARY z )
|
||||
endif()
|
||||
|
||||
if( HAVE_VM_JIT AND UNIX )
|
||||
check_symbol_exists( "backtrace" "execinfo.h" HAVE_BACKTRACE )
|
||||
if( NOT HAVE_BACKTRACE )
|
||||
set( CMAKE_REQUIRED_FLAGS "-lexecinfo" )
|
||||
check_symbol_exists( "backtrace" "execinfo.h" HAVE_LIBEXECINFO )
|
||||
if( HAVE_LIBEXECINFO )
|
||||
set( ALL_C_FLAGS "${ALL_C_FLAGS} -lexecinfo" )
|
||||
else( HAVE_LIBEXECINFO )
|
||||
set( HAVE_VM_JIT NO )
|
||||
endif( HAVE_LIBEXECINFO )
|
||||
endif( NOT HAVE_BACKTRACE )
|
||||
endif( HAVE_VM_JIT AND UNIX )
|
||||
|
||||
if( ${HAVE_VM_JIT} )
|
||||
if( ASMJIT_FOUND AND NOT FORCE_INTERNAL_ASMJIT )
|
||||
message( STATUS "Using system asmjit, includes found at ${ASMJIT_INCLUDE_DIR}" )
|
||||
else()
|
||||
message( STATUS "Using internal asmjit" )
|
||||
set( SKIP_INSTALL_ALL TRUE ) # Avoid installing asmjit alongside zdoom
|
||||
add_subdirectory( asmjit )
|
||||
set( ASMJIT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/asmjit )
|
||||
set( ASMJIT_LIBRARIES asmjit )
|
||||
set( ASMJIT_LIBRARY asmjit )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if( JPEG_FOUND AND NOT FORCE_INTERNAL_JPEG )
|
||||
message( STATUS "Using system jpeg library, includes found at ${JPEG_INCLUDE_DIR}" )
|
||||
else()
|
||||
message( STATUS "Using internal jpeg library" )
|
||||
add_subdirectory( jpeg )
|
||||
set( JPEG_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/jpeg )
|
||||
set( JPEG_LIBRARIES jpeg )
|
||||
set( JPEG_LIBRARY jpeg )
|
||||
endif()
|
||||
|
||||
if( BZIP2_FOUND AND NOT FORCE_INTERNAL_BZIP2 )
|
||||
message( STATUS "Using system bzip2 library, includes found at ${BZIP2_INCLUDE_DIR}" )
|
||||
else()
|
||||
message( STATUS "Using internal bzip2 library" )
|
||||
add_subdirectory( bzip2 )
|
||||
set( BZIP2_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/bzip2" )
|
||||
set( BZIP2_LIBRARIES bz2 )
|
||||
set( BZIP2_LIBRARY bz2 )
|
||||
endif()
|
||||
|
||||
if( GME_FOUND AND NOT FORCE_INTERNAL_GME )
|
||||
message( STATUS "Using system gme library, includes found at ${GME_INCLUDE_DIR}" )
|
||||
else()
|
||||
message( STATUS "Using internal gme library" )
|
||||
# Use MAME as it's balanced emulator: well-accurate, but doesn't eats lot of CPU
|
||||
# Nuked OPN2 is very accurate emulator, but it eats too much CPU for the workflow
|
||||
set( GME_YM2612_EMU "MAME" )
|
||||
add_subdirectory( game-music-emu )
|
||||
set( GME_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/game-music-emu" )
|
||||
set( GME_LIBRARIES gme )
|
||||
endif()
|
||||
|
||||
set( LZMA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lzma/C" )
|
||||
|
||||
if( NOT CMAKE_CROSSCOMPILING )
|
||||
if( NOT CROSS_EXPORTS )
|
||||
set( CROSS_EXPORTS "" )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Install the entire docs directory in the distributed zip package
|
||||
if( WIN32 )
|
||||
set( INSTALL_DOCS_PATH docs CACHE STRING "Directory where the documentation will be placed during install." )
|
||||
else()
|
||||
set( INSTALL_DOCS_PATH share/doc/${ZDOOM_EXE_NAME} CACHE STRING "Directory where the zdoom documentation will be placed during install." )
|
||||
endif()
|
||||
install(DIRECTORY docs/
|
||||
DESTINATION ${INSTALL_DOCS_PATH}
|
||||
COMPONENT "Documentation")
|
||||
|
||||
add_subdirectory( lzma )
|
||||
add_subdirectory( tools )
|
||||
add_subdirectory( dumb )
|
||||
add_subdirectory( gdtoa )
|
||||
add_subdirectory( wadsrc )
|
||||
add_subdirectory( wadsrc_bm )
|
||||
add_subdirectory( wadsrc_lights )
|
||||
add_subdirectory( wadsrc_extra )
|
||||
add_subdirectory( src )
|
||||
|
||||
if( NOT CMAKE_CROSSCOMPILING )
|
||||
export(TARGETS ${CROSS_EXPORTS} FILE "${CMAKE_BINARY_DIR}/ImportExecutables.cmake" )
|
||||
endif()
|
|
@ -1,28 +0,0 @@
|
|||
# Welcome to LZDoom!
|
||||
|
||||
[![Build Status](https://ci.appveyor.com/api/projects/status/github/drfrag666/gzdoom?branch=g3.3mgw&svg=true)](https://ci.appveyor.com/project/drfrag666/gzdoom) [![Build Status](https://travis-ci.org/drfrag666/gzdoom.svg?branch=g3.3mgw)](https://travis-ci.org/drfrag666/gzdoom)
|
||||
|
||||
## LZDoom is a fork of GZDoom 3.3 compiling with MinGW and running on older non SSE2 cpus while keeping the DDRAW and D3D backends for compatibility.
|
||||
|
||||
Copyright (c) 1998-2019 ZDoom + GZDoom teams, and contributors
|
||||
|
||||
Doom Source (c) 1997 id Software, Raven Software, and contributors
|
||||
|
||||
Please see license files for individual contributor licenses
|
||||
|
||||
Special thanks to Coraline of the 3DGE team for allowing us to use her README.md as a template for this one.
|
||||
|
||||
### Licensed under the GPL v3
|
||||
##### https://www.gnu.org/licenses/quick-guide-gplv3.en.html
|
||||
---
|
||||
|
||||
## How to build GZDoom
|
||||
|
||||
To build GZDoom, please see the [wiki](https://zdoom.org/wiki/) and see the "Programmer's Corner" on the bottom-right corner of the page to build for your platform.
|
||||
|
||||
GZDoom repo: https://github.com/coelckers/gzdoom
|
||||
|
||||
## Other forks/branches
|
||||
|
||||
- legacy: Official GZDoom vintage build for GL 2 hardware. - gzdoom32: ZDoom32. - gzdoomle: ZDoom LE (Legacy Edition).
|
||||
For more info see old README.md: https://github.com/drfrag666/gzdoom/blob/gzdoom32/README.md
|
|
@ -1,23 +0,0 @@
|
|||
# - Find fluidsynth
|
||||
# Find the native fluidsynth includes and library
|
||||
#
|
||||
# FLUIDSYNTH_INCLUDE_DIR - where to find fluidsynth.h
|
||||
# FLUIDSYNTH_LIBRARIES - List of libraries when using fluidsynth.
|
||||
# FLUIDSYNTH_FOUND - True if fluidsynth found.
|
||||
|
||||
|
||||
IF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES)
|
||||
# Already in cache, be silent
|
||||
SET(FluidSynth_FIND_QUIETLY TRUE)
|
||||
ENDIF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES)
|
||||
|
||||
FIND_PATH(FLUIDSYNTH_INCLUDE_DIR fluidsynth.h)
|
||||
|
||||
FIND_LIBRARY(FLUIDSYNTH_LIBRARIES NAMES fluidsynth )
|
||||
MARK_AS_ADVANCED( FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR )
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set FLUIDSYNTH_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(FluidSynth DEFAULT_MSG FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR)
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
# - Find mpg123
|
||||
# Find the native mpg123 includes and library
|
||||
#
|
||||
# MPG123_INCLUDE_DIR - where to find mpg123.h
|
||||
# MPG123_LIBRARIES - List of libraries when using mpg123.
|
||||
# MPG123_FOUND - True if mpg123 found.
|
||||
|
||||
IF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES)
|
||||
# Already in cache, be silent
|
||||
SET(MPG123_FIND_QUIETLY TRUE)
|
||||
ENDIF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES)
|
||||
|
||||
FIND_PATH(MPG123_INCLUDE_DIR mpg123.h
|
||||
PATHS "${MPG123_DIR}"
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
FIND_LIBRARY(MPG123_LIBRARIES NAMES mpg123 mpg123-0
|
||||
PATHS "${MPG123_DIR}"
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
# MARK_AS_ADVANCED(MPG123_LIBRARIES MPG123_INCLUDE_DIR)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set MPG123_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(MPG123 DEFAULT_MSG MPG123_LIBRARIES MPG123_INCLUDE_DIR)
|
|
@ -1,182 +0,0 @@
|
|||
# Locate SDL2 library
|
||||
# This module defines
|
||||
# SDL2_LIBRARY, the name of the library to link against
|
||||
# SDL2_FOUND, if false, do not try to link to SDL2
|
||||
# SDL2_INCLUDE_DIR, where to find SDL.h
|
||||
#
|
||||
# This module responds to the the flag:
|
||||
# SDL2_BUILDING_LIBRARY
|
||||
# If this is defined, then no SDL2_main will be linked in because
|
||||
# only applications need main().
|
||||
# Otherwise, it is assumed you are building an application and this
|
||||
# module will attempt to locate and set the the proper link flags
|
||||
# as part of the returned SDL2_LIBRARY variable.
|
||||
#
|
||||
# Don't forget to include SDL2main.h and SDL2main.m your project for the
|
||||
# OS X framework based version. (Other versions link to -lSDL2main which
|
||||
# this module will try to find on your behalf.) Also for OS X, this
|
||||
# module will automatically add the -framework Cocoa on your behalf.
|
||||
#
|
||||
#
|
||||
# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
|
||||
# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
|
||||
# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
|
||||
# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
|
||||
# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
|
||||
# as appropriate. These values are used to generate the final SDL2_LIBRARY
|
||||
# variable, but when these values are unset, SDL2_LIBRARY does not get created.
|
||||
#
|
||||
#
|
||||
# $SDL2DIR is an environment variable that would
|
||||
# correspond to the ./configure --prefix=$SDL2DIR
|
||||
# used in building SDL2.
|
||||
# l.e.galup 9-20-02
|
||||
#
|
||||
# Modified by Eric Wing.
|
||||
# Added code to assist with automated building by using environmental variables
|
||||
# and providing a more controlled/consistent search behavior.
|
||||
# Added new modifications to recognize OS X frameworks and
|
||||
# additional Unix paths (FreeBSD, etc).
|
||||
# Also corrected the header search path to follow "proper" SDL2 guidelines.
|
||||
# Added a search for SDL2main which is needed by some platforms.
|
||||
# Added a search for threads which is needed by some platforms.
|
||||
# Added needed compile switches for MinGW.
|
||||
#
|
||||
# On OSX, this will prefer the Framework version (if found) over others.
|
||||
# People will have to manually change the cache values of
|
||||
# SDL2_LIBRARY to override this selection or set the CMake environment
|
||||
# CMAKE_INCLUDE_PATH to modify the search paths.
|
||||
#
|
||||
# Note that the header path has changed from SDL2/SDL.h to just SDL.h
|
||||
# This needed to change because "proper" SDL2 convention
|
||||
# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
|
||||
# reasons because not all systems place things in SDL2/ (see FreeBSD).
|
||||
#
|
||||
# Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake
|
||||
# module with the minor edit of changing "SDL" to "SDL2" where necessary. This
|
||||
# was not created for redistribution, and exists temporarily pending official
|
||||
# SDL2 CMake modules.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2003-2009 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
FIND_PATH(SDL2_INCLUDE_DIR SDL.h
|
||||
HINTS
|
||||
$ENV{SDL2DIR}
|
||||
PATH_SUFFIXES include/SDL2 include
|
||||
PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local/include/SDL2
|
||||
/usr/include/SDL2
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/csw # Blastwave
|
||||
/opt
|
||||
/boot/system/develop/headers/SDL2 #Hiaku OS
|
||||
)
|
||||
#MESSAGE("SDL2_INCLUDE_DIR is ${SDL2_INCLUDE_DIR}")
|
||||
|
||||
FIND_LIBRARY(SDL2_LIBRARY_TEMP
|
||||
NAMES SDL2
|
||||
HINTS
|
||||
$ENV{SDL2DIR}
|
||||
PATH_SUFFIXES lib64 lib
|
||||
PATHS
|
||||
/sw
|
||||
/opt/local
|
||||
/opt/csw
|
||||
/opt
|
||||
/system/lib #Hiaku OS
|
||||
)
|
||||
|
||||
#MESSAGE("SDL2_LIBRARY_TEMP is ${SDL2_LIBRARY_TEMP}")
|
||||
|
||||
IF(NOT SDL2_BUILDING_LIBRARY)
|
||||
IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
|
||||
# Non-OS X framework versions expect you to also dynamically link to
|
||||
# SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
|
||||
# seem to provide SDL2main for compatibility even though they don't
|
||||
# necessarily need it.
|
||||
FIND_LIBRARY(SDL2MAIN_LIBRARY
|
||||
NAMES SDL2main
|
||||
HINTS
|
||||
$ENV{SDL2DIR}
|
||||
PATH_SUFFIXES lib64 lib
|
||||
PATHS
|
||||
/sw
|
||||
/opt/local
|
||||
/opt/csw
|
||||
/opt
|
||||
)
|
||||
ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
|
||||
ENDIF(NOT SDL2_BUILDING_LIBRARY)
|
||||
|
||||
# SDL2 may require threads on your system.
|
||||
# The Apple build may not need an explicit flag because one of the
|
||||
# frameworks may already provide it.
|
||||
# But for non-OSX systems, I will use the CMake Threads package.
|
||||
IF(NOT APPLE)
|
||||
FIND_PACKAGE(Threads)
|
||||
ENDIF(NOT APPLE)
|
||||
|
||||
# MinGW needs an additional library, mwindows
|
||||
# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows
|
||||
# (Actually on second look, I think it only needs one of the m* libraries.)
|
||||
IF(MINGW)
|
||||
SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
|
||||
ENDIF(MINGW)
|
||||
|
||||
SET(SDL2_FOUND "NO")
|
||||
IF(SDL2_LIBRARY_TEMP)
|
||||
# For SDL2main
|
||||
IF(NOT SDL2_BUILDING_LIBRARY)
|
||||
IF(SDL2MAIN_LIBRARY)
|
||||
SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
|
||||
ENDIF(SDL2MAIN_LIBRARY)
|
||||
ENDIF(NOT SDL2_BUILDING_LIBRARY)
|
||||
|
||||
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
|
||||
# CMake doesn't display the -framework Cocoa string in the UI even
|
||||
# though it actually is there if I modify a pre-used variable.
|
||||
# I think it has something to do with the CACHE STRING.
|
||||
# So I use a temporary variable until the end so I can set the
|
||||
# "real" variable in one-shot.
|
||||
IF(APPLE)
|
||||
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
|
||||
ENDIF(APPLE)
|
||||
|
||||
# For threads, as mentioned Apple doesn't need this.
|
||||
# In fact, there seems to be a problem if I used the Threads package
|
||||
# and try using this line, so I'm just skipping it entirely for OS X.
|
||||
IF(NOT APPLE)
|
||||
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
|
||||
ENDIF(NOT APPLE)
|
||||
|
||||
# For MinGW library
|
||||
IF(MINGW)
|
||||
SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
|
||||
ENDIF(MINGW)
|
||||
|
||||
# Set the final string here so the GUI reflects the final state.
|
||||
SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
|
||||
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
|
||||
SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
|
||||
|
||||
SET(SDL2_FOUND "YES")
|
||||
ENDIF(SDL2_LIBRARY_TEMP)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2
|
||||
REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)
|
|
@ -1,29 +0,0 @@
|
|||
# - Try to find SndFile
|
||||
# Once done this will define
|
||||
#
|
||||
# SNDFILE_FOUND - system has SndFile
|
||||
# SNDFILE_INCLUDE_DIRS - the SndFile include directory
|
||||
# SNDFILE_LIBRARIES - Link these to use SndFile
|
||||
#
|
||||
# Copyright © 2006 Wengo
|
||||
# Copyright © 2009 Guillaume Martres
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
find_path(SNDFILE_INCLUDE_DIR NAMES sndfile.h)
|
||||
|
||||
find_library(SNDFILE_LIBRARY NAMES sndfile sndfile-1)
|
||||
|
||||
set(SNDFILE_INCLUDE_DIRS ${SNDFILE_INCLUDE_DIR})
|
||||
set(SNDFILE_LIBRARIES ${SNDFILE_LIBRARY})
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
# handle the QUIETLY and REQUIRED arguments and set SNDFILE_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SndFile DEFAULT_MSG SNDFILE_LIBRARY SNDFILE_INCLUDE_DIR)
|
||||
|
||||
# show the SNDFILE_INCLUDE_DIRS and SNDFILE_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(SNDFILE_INCLUDE_DIRS SNDFILE_LIBRARIES)
|
|
@ -1,157 +0,0 @@
|
|||
|
||||
# Copyright (c) 2012 Petroules Corporation. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation and/or
|
||||
# other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
|
||||
# Based on the Qt 5 processor detection code, so should be very accurate
|
||||
# https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h
|
||||
# Currently handles arm (v5, v6, v7), x86 (32/64), ia64, and ppc (32/64)
|
||||
|
||||
# Regarding POWER/PowerPC, just as is noted in the Qt source,
|
||||
# "There are many more known variants/revisions that we do not handle/detect."
|
||||
|
||||
set(archdetect_c_code "
|
||||
#if defined(__arm__) || defined(__TARGET_ARCH_ARM)
|
||||
#if defined(__ARM_ARCH_7__) \\
|
||||
|| defined(__ARM_ARCH_7A__) \\
|
||||
|| defined(__ARM_ARCH_7R__) \\
|
||||
|| defined(__ARM_ARCH_7M__) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7)
|
||||
#error cmake_ARCH armv7
|
||||
#elif defined(__ARM_ARCH_6__) \\
|
||||
|| defined(__ARM_ARCH_6J__) \\
|
||||
|| defined(__ARM_ARCH_6T2__) \\
|
||||
|| defined(__ARM_ARCH_6Z__) \\
|
||||
|| defined(__ARM_ARCH_6K__) \\
|
||||
|| defined(__ARM_ARCH_6ZK__) \\
|
||||
|| defined(__ARM_ARCH_6M__) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6)
|
||||
#error cmake_ARCH armv6
|
||||
#elif defined(__ARM_ARCH_5TEJ__) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5)
|
||||
#error cmake_ARCH armv5
|
||||
#else
|
||||
#error cmake_ARCH arm
|
||||
#endif
|
||||
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
|
||||
#error cmake_ARCH i386
|
||||
#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
|
||||
#error cmake_ARCH x86_64
|
||||
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
|
||||
#error cmake_ARCH ia64
|
||||
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\
|
||||
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\
|
||||
|| defined(_M_MPPC) || defined(_M_PPC)
|
||||
#if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
|
||||
#error cmake_ARCH ppc64
|
||||
#else
|
||||
#error cmake_ARCH ppc
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#error cmake_ARCH unknown
|
||||
")
|
||||
|
||||
# Set ppc_support to TRUE before including this file or ppc and ppc64
|
||||
# will be treated as invalid architectures since they are no longer supported by Apple
|
||||
|
||||
function(target_architecture output_var)
|
||||
if(APPLE AND CMAKE_OSX_ARCHITECTURES)
|
||||
# On OS X we use CMAKE_OSX_ARCHITECTURES *if* it was set
|
||||
# First let's normalize the order of the values
|
||||
|
||||
# Note that it's not possible to compile PowerPC applications if you are using
|
||||
# the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we
|
||||
# disable it by default
|
||||
# See this page for more information:
|
||||
# http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4
|
||||
|
||||
# Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime.
|
||||
# On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise.
|
||||
|
||||
foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
|
||||
if("${osx_arch}" STREQUAL "ppc" AND ppc_support)
|
||||
set(osx_arch_ppc TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "i386")
|
||||
set(osx_arch_i386 TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "x86_64")
|
||||
set(osx_arch_x86_64 TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support)
|
||||
set(osx_arch_ppc64 TRUE)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Now add all the architectures in our normalized order
|
||||
if(osx_arch_ppc)
|
||||
list(APPEND ARCH ppc)
|
||||
endif()
|
||||
|
||||
if(osx_arch_i386)
|
||||
list(APPEND ARCH i386)
|
||||
endif()
|
||||
|
||||
if(osx_arch_x86_64)
|
||||
list(APPEND ARCH x86_64)
|
||||
endif()
|
||||
|
||||
if(osx_arch_ppc64)
|
||||
list(APPEND ARCH ppc64)
|
||||
endif()
|
||||
else()
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}")
|
||||
|
||||
enable_language(C)
|
||||
|
||||
# Detect the architecture in a rather creative way...
|
||||
# This compiles a small C program which is a series of ifdefs that selects a
|
||||
# particular #error preprocessor directive whose message string contains the
|
||||
# target architecture. The program will always fail to compile (both because
|
||||
# file is not a valid C program, and obviously because of the presence of the
|
||||
# #error preprocessor directives... but by exploiting the preprocessor in this
|
||||
# way, we can detect the correct target architecture even when cross-compiling,
|
||||
# since the program itself never needs to be run (only the compiler/preprocessor)
|
||||
try_run(
|
||||
run_result_unused
|
||||
compile_result_unused
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
"${CMAKE_BINARY_DIR}/arch.c"
|
||||
COMPILE_OUTPUT_VARIABLE ARCH
|
||||
CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
|
||||
)
|
||||
|
||||
# Parse the architecture name from the compiler output
|
||||
string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}")
|
||||
|
||||
# Get rid of the value marker leaving just the architecture name
|
||||
string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}")
|
||||
|
||||
# If we are compiling with an unknown architecture this variable should
|
||||
# already be set to "unknown" but in the case that it's empty (i.e. due
|
||||
# to a typo in the code), then set it to unknown
|
||||
if (NOT ARCH)
|
||||
set(ARCH unknown)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(${output_var} "${ARCH}" PARENT_SCOPE)
|
||||
endfunction()
|
|
@ -1,45 +0,0 @@
|
|||
#
|
||||
# Christoph Heindl 2010
|
||||
# Precompiled Headers Demo
|
||||
# http://cheind.wordpress.com
|
||||
#
|
||||
|
||||
# Instructs the MSVC toolset to use the precompiled header PRECOMPILED_HEADER
|
||||
# for each source file given in the collection named by SOURCE_VARIABLE_NAME.
|
||||
function(enable_precompiled_headers PRECOMPILED_HEADER SOURCE_VARIABLE_NAME)
|
||||
if(MSVC)
|
||||
set(files ${${SOURCE_VARIABLE_NAME}})
|
||||
|
||||
# Generate precompiled header translation unit
|
||||
get_filename_component(pch_basename ${PRECOMPILED_HEADER} NAME_WE)
|
||||
set(pch_abs ${CMAKE_CURRENT_SOURCE_DIR}/${PRECOMPILED_HEADER})
|
||||
set(pch_unity ${CMAKE_CURRENT_BINARY_DIR}/${pch_basename}.cpp)
|
||||
set(pch_content "// Precompiled header unity generated by CMake\n#include <${pch_abs}>\n")
|
||||
# Read .cpp if exists
|
||||
if(EXISTS ${pch_unity})
|
||||
file(READ ${pch_unity} pch_content_prev)
|
||||
endif()
|
||||
# Compare existing .cpp content with the actual one
|
||||
if (pch_content_prev AND pch_content STREQUAL pch_content_prev)
|
||||
unset(pch_content)
|
||||
endif()
|
||||
# Write .cpp if it's out-of-date
|
||||
if (pch_content)
|
||||
FILE(WRITE ${pch_unity} "${pch_content}")
|
||||
endif()
|
||||
set_source_files_properties(${pch_unity} PROPERTIES COMPILE_FLAGS "/Yc\"${pch_abs}\"")
|
||||
|
||||
# Update properties of source files to use the precompiled header.
|
||||
# Additionally, force the inclusion of the precompiled header at beginning of each source file.
|
||||
foreach(source_file ${files} )
|
||||
set_source_files_properties(
|
||||
${source_file}
|
||||
PROPERTIES COMPILE_FLAGS
|
||||
"/Yu\"${pch_abs}\" /FI\"${pch_abs}\""
|
||||
)
|
||||
endforeach(source_file)
|
||||
|
||||
# Finally, update the source file collection to contain the precompiled header translation unit
|
||||
set(${SOURCE_VARIABLE_NAME} ${${SOURCE_VARIABLE_NAME}} ${pch_unity} PARENT_SCOPE)
|
||||
endif(MSVC)
|
||||
endfunction(enable_precompiled_headers)
|
|
@ -1,162 +0,0 @@
|
|||
DT
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
DD
|
||||
{
|
||||
margin-bottom: 1em;
|
||||
margin-left: 1.5em;
|
||||
margin-right: 1.5em;
|
||||
}
|
||||
TH
|
||||
{
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
padding-right: 2em;
|
||||
vertical-align: top;
|
||||
}
|
||||
TD
|
||||
{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* Command Descriptions */
|
||||
DIV.c
|
||||
{
|
||||
border-right: 2px solid;
|
||||
padding-right: 0.4em;
|
||||
border-top: 1px solid;
|
||||
margin-top: 1em;
|
||||
padding-left: 0.4em;
|
||||
font-weight: bold;
|
||||
padding-bottom: 0.2em;
|
||||
border-left: 1px solid;
|
||||
padding-top: 0.2em;
|
||||
border-bottom: 1px solid;
|
||||
background-color: rgb(152,251,152);
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
DIV.b
|
||||
{
|
||||
border-right: 2px solid;
|
||||
padding-right: 1.2em;
|
||||
border-top: 1px;
|
||||
padding-left: 1.2em;
|
||||
padding-bottom: 0.5em;
|
||||
border-left: 1px solid;
|
||||
padding-top: 0.5em;
|
||||
border-bottom: 2px solid;
|
||||
background-color: rgb(240,255,240);
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
/* Variable Descriptions */
|
||||
DIV.v, DIV.vf
|
||||
{
|
||||
border-right: 2px solid;
|
||||
padding-right: 0.4em;
|
||||
border-top: 1px solid;
|
||||
margin-top: 1em;
|
||||
padding-left: 0.4em;
|
||||
font-weight: bold;
|
||||
padding-bottom: 0.2em;
|
||||
border-left: 1px solid;
|
||||
padding-top: 0.2em;
|
||||
border-bottom: 1px solid;
|
||||
background-color: rgb(175,238,238);
|
||||
}
|
||||
DIV.vf
|
||||
{
|
||||
background-color: rgb(175,200,238);
|
||||
}
|
||||
DIV.t, DIV.tf
|
||||
{
|
||||
border-right: 2px solid;
|
||||
padding-right: 1.2em;
|
||||
border-top: 1px;
|
||||
padding-left: 0.9em;
|
||||
padding-bottom: 0.2em;
|
||||
border-left: 1px solid;
|
||||
padding-top: 0.2em;
|
||||
border-bottom: 1px solid;
|
||||
background-color: rgb(224,255,255);
|
||||
}
|
||||
DIV.tf
|
||||
{
|
||||
background-color: rgb(224,238,255);
|
||||
}
|
||||
DIV.d, DIV.df
|
||||
{
|
||||
border-right: 2px solid;
|
||||
padding-right: 1.2em;
|
||||
border-top: 2px;
|
||||
padding-left: 1.2em;
|
||||
padding-bottom: 0.5em;
|
||||
border-left: 1px solid;
|
||||
padding-top: 0.5em;
|
||||
border-bottom: 2px solid;
|
||||
background-color: rgb(240,255,255);
|
||||
}
|
||||
DIV.df
|
||||
{
|
||||
background-color: rgb(240,248,255);
|
||||
}
|
||||
P
|
||||
{
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
A
|
||||
{
|
||||
color: Blue;
|
||||
text-decoration: none;
|
||||
}
|
||||
A:hover
|
||||
{
|
||||
text-decoration: underline;
|
||||
}
|
||||
H1, H2
|
||||
{
|
||||
font-weight: bold;
|
||||
left: -0.8em;
|
||||
font-family: Verdana, Arial, Helvetica, Sans-Serif;
|
||||
position: relative;
|
||||
}
|
||||
H3, H4
|
||||
{
|
||||
font-weight: bold;
|
||||
font-family: Verdana, Arial, Helvetica, Sans-Serif;
|
||||
left: 0em;
|
||||
}
|
||||
BODY
|
||||
{
|
||||
margin: 2em 2em 2em 2em;
|
||||
background-color: white;
|
||||
}
|
||||
PRE
|
||||
{
|
||||
border: ridge 2px;
|
||||
background-color: rgb(210,210,210);
|
||||
padding: 1em 1em 1em 1em;
|
||||
}
|
||||
DIV.index
|
||||
{
|
||||
padding-right: 0.8em;
|
||||
padding-left: 0.8em;
|
||||
left: 0px;
|
||||
float: left;
|
||||
padding-bottom: 1em;
|
||||
overflow: auto;
|
||||
clip: rect(auto,auto,auto,auto);
|
||||
padding-top: 0.5em;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
background-color: #ffffcc;
|
||||
border-right: solid 1px #808080;
|
||||
border-bottom: solid 1px #808080;
|
||||
}
|
||||
DIV.main
|
||||
{
|
||||
margin-left: 11em;
|
||||
height: 50%;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,34 +0,0 @@
|
|||
The original Doom source code was released by id Software under the
|
||||
GPL v2, but has been relicensed under the GPL v3 for GZDoom.
|
||||
See gpl.txt
|
||||
|
||||
Parts of the voxel code in the software renderer use code from the
|
||||
BUILD engine by Ken Silverman and are used under the terms of the
|
||||
GPL v3 with permission.
|
||||
|
||||
The majority of original code uses a BSD-like lincese. See bsd.txt.
|
||||
|
||||
The OpenGL renderer is released under the LGPL v3, except some bits
|
||||
of code that were inherited fro ZDoomGL.
|
||||
|
||||
Some code was taken from the Eternity Engine.
|
||||
Copyright (c) James Haley, Stephen McGranahan, et al.
|
||||
|
||||
This software is based in part on the work of the Independent JPEG Group.
|
||||
|
||||
This software uses the 'zlib' general purpose compression library by
|
||||
Jean-loup Gailly and Mark Adler.
|
||||
|
||||
This software uses the gdtoa package, see gdtoa.txt.
|
||||
|
||||
This software uses the game_music_emu library, which is covered by the GNU Lesser
|
||||
General Public License. See lgpl.txt.
|
||||
|
||||
This software uses the "Dynamic Universal Music Bibliotheque" library for
|
||||
MOD music playback. See dumb.txt for original license. The version used,
|
||||
however, has been heavily modified from its original form and is the same
|
||||
version used by the foobar2000 component foo_dumb as of mid-2008, found at
|
||||
http://kode54.foobar2000.org/.
|
||||
|
||||
All script code in gzdoom.pk3 is licensed under the GPL v3 unless noted
|
||||
otherwise.
|
|
@ -1,27 +0,0 @@
|
|||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2009 Randy Heit, Christoph Oelckers, et al.
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
|
@ -1,42 +0,0 @@
|
|||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
This program, "bzip2", the associated library "libbzip2", and all
|
||||
documentation, are copyright (C) 1996-2010 Julian R Seward. All
|
||||
rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
3. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Julian Seward, jseward@bzip.org
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
|
||||
--------------------------------------------------------------------------
|
|
@ -1,54 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* licence.txt - Conditions for use of DUMB. / / \ \
|
||||
* | < / \_
|
||||
* If you do not agree to these terms, please | \/ /\ /
|
||||
* do not use DUMB. \_ / > /
|
||||
* | \ / /
|
||||
* Information in [brackets] is provided to aid | ' /
|
||||
* interpretation of the licence. \__/
|
||||
*/
|
||||
|
||||
|
||||
Dynamic Universal Music Bibliotheque
|
||||
|
||||
Copyright (C) 2001-2003 Ben Davis, Robert J Ohannessian and Julien Cugniere
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event shall the authors be held liable for any damages arising from the
|
||||
use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim
|
||||
that you wrote the original software. If you use this software in a
|
||||
product, you are requested to acknowledge its use in the product
|
||||
documentation, along with details on where to get an unmodified version of
|
||||
this software, but this is not a strict requirement.
|
||||
|
||||
[Note that the above point asks for a link to DUMB, not just a mention.
|
||||
Googling for DUMB doesn't help much! The URL is "http://dumb.sf.net/".]
|
||||
|
||||
[The only reason why the link is not strictly required is that such a
|
||||
requirement prevents DUMB from being used in projects with certain other
|
||||
licences, notably the GPL. See http://www.gnu.org/philosophy/bsd.html .]
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed from or altered in any source distribution.
|
||||
|
||||
4. If you are using the Program in someone else's bedroom at any Monday
|
||||
3:05 PM, you are not allowed to modify the Program for ten minutes. [This
|
||||
clause provided by Inphernic; every licence should contain at least one
|
||||
clause, the reasoning behind which is far from obvious.]
|
|
@ -1,33 +0,0 @@
|
|||
//----------------------------------------------------------------------------------
|
||||
// File: es3-kepler\FXAA/FXAA3_11.h
|
||||
// SDK Version: v3.00
|
||||
// Email: gameworks@nvidia.com
|
||||
// Site: http://developer.nvidia.com/
|
||||
//
|
||||
// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//----------------------------------------------------------------------------------
|
|
@ -1,27 +0,0 @@
|
|||
/****************************************************************
|
||||
|
||||
The author of this software is David M. Gay.
|
||||
|
||||
Copyright (C) 1998 by Lucent Technologies
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and
|
||||
its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of Lucent or any of its entities
|
||||
not be used in advertising or publicity pertaining to
|
||||
distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
|
||||
****************************************************************/
|
|
@ -1,674 +0,0 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
@ -1,841 +0,0 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 240 KiB |
|
@ -1,23 +0,0 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
|
||||
make_release_only()
|
||||
use_fast_math()
|
||||
|
||||
add_definitions(-DADLMIDI_DISABLE_MIDI_SEQUENCER)
|
||||
|
||||
add_library( adl STATIC
|
||||
adldata.cpp
|
||||
adlmidi.cpp
|
||||
adlmidi_load.cpp
|
||||
adlmidi_midiplay.cpp
|
||||
adlmidi_opl3.cpp
|
||||
adlmidi_private.cpp
|
||||
chips/dosbox/dbopl.cpp
|
||||
chips/dosbox_opl3.cpp
|
||||
chips/nuked/nukedopl3_174.c
|
||||
chips/nuked/nukedopl3.c
|
||||
chips/nuked_opl3.cpp
|
||||
chips/nuked_opl3_v174.cpp
|
||||
wopl/wopl_file.c
|
||||
)
|
||||
target_link_libraries( adl )
|
File diff suppressed because it is too large
Load Diff
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
|
||||
*
|
||||
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2016 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
|
||||
* http://iki.fi/bisqwit/source/adlmidi.html
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ADLDATA_H
|
||||
#define ADLDATA_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <cstring>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
#define ADLDATA_BYTE_COMPARABLE(T) \
|
||||
inline bool operator==(const T &a, const T &b) \
|
||||
{ return !memcmp(&a, &b, sizeof(T)); } \
|
||||
inline bool operator!=(const T &a, const T &b) \
|
||||
{ return !operator==(a, b); }
|
||||
|
||||
struct adldata
|
||||
{
|
||||
uint32_t modulator_E862, carrier_E862; // See below
|
||||
uint8_t modulator_40, carrier_40; // KSL/attenuation settings
|
||||
uint8_t feedconn; // Feedback/connection bits for the channel
|
||||
|
||||
int8_t finetune;
|
||||
};
|
||||
ADLDATA_BYTE_COMPARABLE(struct adldata)
|
||||
|
||||
struct adlinsdata
|
||||
{
|
||||
enum { Flag_Pseudo4op = 0x01, Flag_NoSound = 0x02, Flag_Real4op = 0x04 };
|
||||
|
||||
enum { Flag_RM_BassDrum = 0x08, Flag_RM_Snare = 0x10, Flag_RM_TomTom = 0x18,
|
||||
Flag_RM_Cymbal = 0x20, Flag_RM_HiHat = 0x28, Mask_RhythmMode = 0x38 };
|
||||
|
||||
uint16_t adlno1, adlno2;
|
||||
uint8_t tone;
|
||||
uint8_t flags;
|
||||
uint16_t ms_sound_kon; // Number of milliseconds it produces sound;
|
||||
uint16_t ms_sound_koff;
|
||||
int8_t midi_velocity_offset;
|
||||
double voice2_fine_tune;
|
||||
};
|
||||
ADLDATA_BYTE_COMPARABLE(struct adlinsdata)
|
||||
|
||||
enum { adlNoteOnMaxTime = 40000 };
|
||||
|
||||
/**
|
||||
* @brief Instrument data with operators included
|
||||
*/
|
||||
struct adlinsdata2
|
||||
{
|
||||
adldata adl[2];
|
||||
uint8_t tone;
|
||||
uint8_t flags;
|
||||
uint16_t ms_sound_kon; // Number of milliseconds it produces sound;
|
||||
uint16_t ms_sound_koff;
|
||||
int8_t midi_velocity_offset;
|
||||
double voice2_fine_tune;
|
||||
static adlinsdata2 from_adldata(const adlinsdata &d);
|
||||
};
|
||||
ADLDATA_BYTE_COMPARABLE(struct adlinsdata2)
|
||||
|
||||
#undef ADLDATA_BYTE_COMPARABLE
|
||||
#pragma pack(pop)
|
||||
|
||||
/**
|
||||
* @brief Bank global setup
|
||||
*/
|
||||
struct AdlBankSetup
|
||||
{
|
||||
int volumeModel;
|
||||
bool deepTremolo;
|
||||
bool deepVibrato;
|
||||
bool adLibPercussions;
|
||||
bool scaleModulators;
|
||||
};
|
||||
|
||||
#ifndef DISABLE_EMBEDDED_BANKS
|
||||
int maxAdlBanks();
|
||||
extern const adldata adl[];
|
||||
extern const adlinsdata adlins[];
|
||||
extern const unsigned short banks[][256];
|
||||
extern const char* const banknames[];
|
||||
extern const AdlBankSetup adlbanksetup[];
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Conversion of storage formats
|
||||
*/
|
||||
inline adlinsdata2 adlinsdata2::from_adldata(const adlinsdata &d)
|
||||
{
|
||||
adlinsdata2 ins;
|
||||
ins.tone = d.tone;
|
||||
ins.flags = d.flags;
|
||||
ins.ms_sound_kon = d.ms_sound_kon;
|
||||
ins.ms_sound_koff = d.ms_sound_koff;
|
||||
ins.midi_velocity_offset = d.midi_velocity_offset;
|
||||
ins.voice2_fine_tune = d.voice2_fine_tune;
|
||||
#ifdef DISABLE_EMBEDDED_BANKS
|
||||
std::memset(ins.adl, 0, sizeof(adldata) * 2);
|
||||
#else
|
||||
ins.adl[0] = ::adl[d.adlno1];
|
||||
ins.adl[1] = ::adl[d.adlno2];
|
||||
#endif
|
||||
return ins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert external instrument to internal instrument
|
||||
*/
|
||||
void cvt_ADLI_to_FMIns(adlinsdata2 &dst, const struct ADL_Instrument &src);
|
||||
|
||||
/**
|
||||
* @brief Convert internal instrument to external instrument
|
||||
*/
|
||||
void cvt_FMIns_to_ADLI(struct ADL_Instrument &dst, const adlinsdata2 &src);
|
||||
|
||||
#endif //ADLDATA_H
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
|
||||
*
|
||||
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
|
||||
* http://iki.fi/bisqwit/source/adlmidi.html
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ADLMIDI_HPP
|
||||
#define ADLMIDI_HPP
|
||||
|
||||
#include "adlmidi.h"
|
||||
|
||||
struct ADL_MIDIPlayer;
|
||||
|
||||
class ADLMIDI_DECLSPEC AdlInstrumentTester
|
||||
{
|
||||
struct Impl;
|
||||
Impl *P;
|
||||
|
||||
public:
|
||||
explicit AdlInstrumentTester(ADL_MIDIPlayer *device);
|
||||
virtual ~AdlInstrumentTester();
|
||||
|
||||
// Find list of adlib instruments that supposedly implement this GM
|
||||
void FindAdlList();
|
||||
void Touch(unsigned c, unsigned volume);
|
||||
void DoNote(int note);
|
||||
void NextGM(int offset);
|
||||
void NextAdl(int offset);
|
||||
bool HandleInputChar(char ch);
|
||||
|
||||
private:
|
||||
AdlInstrumentTester(const AdlInstrumentTester &);
|
||||
AdlInstrumentTester &operator=(const AdlInstrumentTester &);
|
||||
};
|
||||
|
||||
#endif //ADLMIDI_HPP
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
|
||||
*
|
||||
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
|
||||
* http://iki.fi/bisqwit/source/adlmidi.html
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ADLMIDI_BANKMAP_H
|
||||
#define ADLMIDI_BANKMAP_H
|
||||
|
||||
#include <list>
|
||||
#include <utility>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "adlmidi_ptr.hpp"
|
||||
|
||||
/**
|
||||
* A simple hash map which accepts bank numbers as keys, can be reserved to a
|
||||
* fixed size, offers O(1) search and insertion, has a hash function to
|
||||
* optimize for the worst case, and has some good cache locality properties.
|
||||
*/
|
||||
template <class T>
|
||||
class BasicBankMap
|
||||
{
|
||||
public:
|
||||
typedef size_t key_type; /* the bank identifier */
|
||||
typedef T mapped_type;
|
||||
typedef std::pair<key_type, T> value_type;
|
||||
|
||||
BasicBankMap();
|
||||
void reserve(size_t capacity);
|
||||
|
||||
size_t size() const
|
||||
{ return m_size; }
|
||||
size_t capacity() const
|
||||
{ return m_capacity; }
|
||||
bool empty() const
|
||||
{ return m_size == 0; }
|
||||
|
||||
class iterator;
|
||||
iterator begin() const;
|
||||
iterator end() const;
|
||||
|
||||
struct do_not_expand_t {};
|
||||
|
||||
iterator find(key_type key);
|
||||
void erase(iterator it);
|
||||
std::pair<iterator, bool> insert(const value_type &value);
|
||||
std::pair<iterator, bool> insert(const value_type &value, do_not_expand_t);
|
||||
void clear();
|
||||
|
||||
T &operator[](key_type key);
|
||||
|
||||
private:
|
||||
struct Slot;
|
||||
enum { minimum_allocation = 4 };
|
||||
enum
|
||||
{
|
||||
hash_bits = 8, /* worst case # of collisions: 128^2/2^hash_bits */
|
||||
hash_buckets = 1 << hash_bits
|
||||
};
|
||||
|
||||
public:
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
iterator();
|
||||
value_type &operator*() const { return slot->value; }
|
||||
value_type *operator->() const { return &slot->value; }
|
||||
iterator &operator++();
|
||||
bool operator==(const iterator &o) const;
|
||||
bool operator!=(const iterator &o) const;
|
||||
void to_ptrs(void *ptrs[3]);
|
||||
static iterator from_ptrs(void *const ptrs[3]);
|
||||
private:
|
||||
Slot **buckets;
|
||||
Slot *slot;
|
||||
size_t index;
|
||||
iterator(Slot **buckets, Slot *slot, size_t index);
|
||||
#ifdef _MSC_VER
|
||||
template<class _T>
|
||||
friend class BasicBankMap;
|
||||
#else
|
||||
friend class BasicBankMap<T>;
|
||||
#endif
|
||||
};
|
||||
|
||||
private:
|
||||
struct Slot {
|
||||
Slot *next, *prev;
|
||||
value_type value;
|
||||
Slot() : next(NULL), prev(NULL) {}
|
||||
};
|
||||
AdlMIDI_SPtrArray<Slot *> m_buckets;
|
||||
std::list< AdlMIDI_SPtrArray<Slot> > m_allocations;
|
||||
Slot *m_freeslots;
|
||||
size_t m_size;
|
||||
size_t m_capacity;
|
||||
static size_t hash(key_type key);
|
||||
Slot *allocate_slot();
|
||||
Slot *ensure_allocate_slot();
|
||||
void free_slot(Slot *slot);
|
||||
Slot *bucket_find(size_t index, key_type key);
|
||||
void bucket_add(size_t index, Slot *slot);
|
||||
void bucket_remove(size_t index, Slot *slot);
|
||||
};
|
||||
|
||||
#include "adlmidi_bankmap.tcc"
|
||||
|
||||
#endif // ADLMIDI_BANKMAP_H
|
|
@ -1,283 +0,0 @@
|
|||
/*
|
||||
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
|
||||
*
|
||||
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
|
||||
* http://iki.fi/bisqwit/source/adlmidi.html
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "adlmidi_bankmap.h"
|
||||
#include <cassert>
|
||||
|
||||
template <class T>
|
||||
inline BasicBankMap<T>::BasicBankMap()
|
||||
: m_freeslots(NULL),
|
||||
m_size(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
m_buckets.reset(new Slot *[hash_buckets]());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline size_t BasicBankMap<T>::hash(key_type key)
|
||||
{
|
||||
// disregard the 0 high bit in LSB
|
||||
key = key_type(key & 127) | key_type((key >> 8) << 7);
|
||||
// take low part as hash value
|
||||
return key & (hash_buckets - 1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::reserve(size_t capacity)
|
||||
{
|
||||
if(m_capacity >= capacity)
|
||||
return;
|
||||
|
||||
size_t need = capacity - m_capacity;
|
||||
const size_t minalloc = static_cast<size_t>(minimum_allocation);
|
||||
need = (need < minalloc) ? minalloc : need;
|
||||
|
||||
AdlMIDI_SPtrArray<Slot> slotz;
|
||||
slotz.reset(new Slot[need]);
|
||||
m_allocations.push_back(slotz);
|
||||
m_capacity += need;
|
||||
|
||||
for(size_t i = need; i-- > 0;)
|
||||
free_slot(&slotz[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::iterator
|
||||
BasicBankMap<T>::begin() const
|
||||
{
|
||||
iterator it(m_buckets.get(), NULL, 0);
|
||||
while(it.index < hash_buckets && !(it.slot = m_buckets[it.index]))
|
||||
++it.index;
|
||||
return it;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::iterator
|
||||
BasicBankMap<T>::end() const
|
||||
{
|
||||
iterator it(m_buckets.get(), NULL, hash_buckets);
|
||||
return it;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::iterator BasicBankMap<T>::find(key_type key)
|
||||
{
|
||||
size_t index = hash(key);
|
||||
Slot *slot = bucket_find(index, key);
|
||||
if(!slot)
|
||||
return end();
|
||||
return iterator(m_buckets.get(), slot, index);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::erase(iterator it)
|
||||
{
|
||||
bucket_remove(it.index, it.slot);
|
||||
free_slot(it.slot);
|
||||
--m_size;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline BasicBankMap<T>::iterator::iterator()
|
||||
: buckets(NULL), slot(NULL), index(0)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline BasicBankMap<T>::iterator::iterator(Slot **buckets, Slot *slot, size_t index)
|
||||
: buckets(buckets), slot(slot), index(index)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::iterator &
|
||||
BasicBankMap<T>::iterator::operator++()
|
||||
{
|
||||
if(slot->next)
|
||||
slot = slot->next;
|
||||
else {
|
||||
Slot *slot = NULL;
|
||||
++index;
|
||||
while(index < hash_buckets && !(slot = buckets[index]))
|
||||
++index;
|
||||
this->slot = slot;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool BasicBankMap<T>::iterator::operator==(const iterator &o) const
|
||||
{
|
||||
return buckets == o.buckets && slot == o.slot && index == o.index;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool BasicBankMap<T>::iterator::operator!=(const iterator &o) const
|
||||
{
|
||||
return !operator==(o);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::iterator::to_ptrs(void *ptrs[3])
|
||||
{
|
||||
ptrs[0] = buckets;
|
||||
ptrs[1] = slot;
|
||||
ptrs[2] = (void *)index;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::iterator
|
||||
BasicBankMap<T>::iterator::from_ptrs(void *const ptrs[3])
|
||||
{
|
||||
iterator it;
|
||||
it.buckets = (Slot **)ptrs[0];
|
||||
it.slot = (Slot *)ptrs[1];
|
||||
it.index = (size_t)ptrs[2];
|
||||
return it;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::pair<typename BasicBankMap<T>::iterator, bool>
|
||||
BasicBankMap<T>::insert(const value_type &value)
|
||||
{
|
||||
size_t index = hash(value.first);
|
||||
Slot *slot = bucket_find(index, value.first);
|
||||
if(slot)
|
||||
return std::make_pair(iterator(m_buckets.get(), slot, index), false);
|
||||
slot = allocate_slot();
|
||||
if(!slot) {
|
||||
reserve(m_capacity + minimum_allocation);
|
||||
slot = ensure_allocate_slot();
|
||||
}
|
||||
slot->value = value;
|
||||
bucket_add(index, slot);
|
||||
++m_size;
|
||||
return std::make_pair(iterator(m_buckets.get(), slot, index), true);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::pair<typename BasicBankMap<T>::iterator, bool>
|
||||
BasicBankMap<T>::insert(const value_type &value, do_not_expand_t)
|
||||
{
|
||||
size_t index = hash(value.first);
|
||||
Slot *slot = bucket_find(index, value.first);
|
||||
if(slot)
|
||||
return std::make_pair(iterator(m_buckets.get(), slot, index), false);
|
||||
slot = allocate_slot();
|
||||
if(!slot)
|
||||
return std::make_pair(end(), false);
|
||||
slot->value = value;
|
||||
bucket_add(index, slot);
|
||||
++m_size;
|
||||
return std::make_pair(iterator(m_buckets.get(), slot, index), true);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::clear()
|
||||
{
|
||||
for(size_t i = 0; i < hash_buckets; ++i) {
|
||||
Slot *slot = m_buckets[i];
|
||||
while (Slot *cur = slot) {
|
||||
slot = slot->next;
|
||||
free_slot(cur);
|
||||
}
|
||||
m_buckets[i] = NULL;
|
||||
}
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T &BasicBankMap<T>::operator[](key_type key)
|
||||
{
|
||||
return insert(value_type(key, T())).first->second;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::Slot *
|
||||
BasicBankMap<T>::allocate_slot()
|
||||
{
|
||||
Slot *slot = m_freeslots;
|
||||
if(!slot)
|
||||
return NULL;
|
||||
Slot *next = slot->next;
|
||||
if(next)
|
||||
next->prev = NULL;
|
||||
m_freeslots = next;
|
||||
return slot;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename BasicBankMap<T>::Slot *
|
||||
BasicBankMap<T>::ensure_allocate_slot()
|
||||
{
|
||||
Slot *slot = allocate_slot();
|
||||
assert(slot);
|
||||
return slot;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::free_slot(Slot *slot)
|
||||
{
|
||||
Slot *next = m_freeslots;
|
||||
if(next)
|
||||
next->prev = slot;
|
||||
slot->prev = NULL;
|
||||
slot->next = next;
|
||||
m_freeslots = slot;
|
||||
m_freeslots->value.second = T();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::Slot *
|
||||
BasicBankMap<T>::bucket_find(size_t index, key_type key)
|
||||
{
|
||||
Slot *slot = m_buckets[index];
|
||||
while(slot && slot->value.first != key)
|
||||
slot = slot->next;
|
||||
return slot;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::bucket_add(size_t index, Slot *slot)
|
||||
{
|
||||
assert(slot);
|
||||
Slot *next = m_buckets[index];
|
||||
if(next)
|
||||
next->prev = slot;
|
||||
slot->next = next;
|
||||
m_buckets[index] = slot;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::bucket_remove(size_t index, Slot *slot)
|
||||
{
|
||||
assert(slot);
|
||||
Slot *prev = slot->prev;
|
||||
Slot *next = slot->next;
|
||||
if(!prev)
|
||||
m_buckets[index] = next;
|
||||
else
|
||||
prev->next = next;
|
||||
if(next)
|
||||
next->prev = prev;
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
|
||||
*
|
||||
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
|
||||
* http://iki.fi/bisqwit/source/adlmidi.html
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "adldata.hh"
|
||||
#include "wopl/wopl_file.h"
|
||||
#include <cmath>
|
||||
|
||||
template <class WOPLI>
|
||||
static void cvt_generic_to_FMIns(adlinsdata2 &ins, const WOPLI &in)
|
||||
{
|
||||
ins.voice2_fine_tune = 0.0;
|
||||
int8_t voice2_fine_tune = in.second_voice_detune;
|
||||
if(voice2_fine_tune != 0)
|
||||
{
|
||||
if(voice2_fine_tune == 1)
|
||||
ins.voice2_fine_tune = 0.000025;
|
||||
else if(voice2_fine_tune == -1)
|
||||
ins.voice2_fine_tune = -0.000025;
|
||||
else
|
||||
ins.voice2_fine_tune = voice2_fine_tune * (15.625 / 1000.0);
|
||||
}
|
||||
|
||||
ins.midi_velocity_offset = in.midi_velocity_offset;
|
||||
ins.tone = in.percussion_key_number;
|
||||
ins.flags = (in.inst_flags & WOPL_Ins_4op) && (in.inst_flags & WOPL_Ins_Pseudo4op) ? adlinsdata::Flag_Pseudo4op : 0;
|
||||
ins.flags|= (in.inst_flags & WOPL_Ins_4op) && ((in.inst_flags & WOPL_Ins_Pseudo4op) == 0) ? adlinsdata::Flag_Real4op : 0;
|
||||
ins.flags|= (in.inst_flags & WOPL_Ins_IsBlank) ? adlinsdata::Flag_NoSound : 0;
|
||||
ins.flags|= in.inst_flags & WOPL_RhythmModeMask;
|
||||
|
||||
for(size_t op = 0, slt = 0; op < 4; op++, slt++)
|
||||
{
|
||||
ins.adl[slt].carrier_E862 =
|
||||
((static_cast<uint32_t>(in.operators[op].waveform_E0) << 24) & 0xFF000000) //WaveForm
|
||||
| ((static_cast<uint32_t>(in.operators[op].susrel_80) << 16) & 0x00FF0000) //SusRel
|
||||
| ((static_cast<uint32_t>(in.operators[op].atdec_60) << 8) & 0x0000FF00) //AtDec
|
||||
| ((static_cast<uint32_t>(in.operators[op].avekf_20) << 0) & 0x000000FF); //AVEKM
|
||||
ins.adl[slt].carrier_40 = in.operators[op].ksl_l_40;//KSLL
|
||||
|
||||
op++;
|
||||
ins.adl[slt].modulator_E862 =
|
||||
((static_cast<uint32_t>(in.operators[op].waveform_E0) << 24) & 0xFF000000) //WaveForm
|
||||
| ((static_cast<uint32_t>(in.operators[op].susrel_80) << 16) & 0x00FF0000) //SusRel
|
||||
| ((static_cast<uint32_t>(in.operators[op].atdec_60) << 8) & 0x0000FF00) //AtDec
|
||||
| ((static_cast<uint32_t>(in.operators[op].avekf_20) << 0) & 0x000000FF); //AVEKM
|
||||
ins.adl[slt].modulator_40 = in.operators[op].ksl_l_40;//KSLL
|
||||
}
|
||||
|
||||
ins.adl[0].finetune = static_cast<int8_t>(in.note_offset1);
|
||||
ins.adl[0].feedconn = in.fb_conn1_C0;
|
||||
ins.adl[1].finetune = static_cast<int8_t>(in.note_offset2);
|
||||
ins.adl[1].feedconn = in.fb_conn2_C0;
|
||||
|
||||
ins.ms_sound_kon = in.delay_on_ms;
|
||||
ins.ms_sound_koff = in.delay_off_ms;
|
||||
}
|
||||
|
||||
template <class WOPLI>
|
||||
static void cvt_FMIns_to_generic(WOPLI &ins, const adlinsdata2 &in)
|
||||
{
|
||||
ins.second_voice_detune = 0;
|
||||
double voice2_fine_tune = in.voice2_fine_tune;
|
||||
if(voice2_fine_tune != 0)
|
||||
{
|
||||
if(voice2_fine_tune > 0 && voice2_fine_tune <= 0.000025)
|
||||
ins.second_voice_detune = 1;
|
||||
else if(voice2_fine_tune < 0 && voice2_fine_tune >= -0.000025)
|
||||
ins.second_voice_detune = -1;
|
||||
else
|
||||
{
|
||||
long value = static_cast<long>(round(voice2_fine_tune * (1000.0 / 15.625)));
|
||||
value = (value < -128) ? -128 : value;
|
||||
value = (value > +127) ? +127 : value;
|
||||
ins.second_voice_detune = static_cast<int8_t>(value);
|
||||
}
|
||||
}
|
||||
|
||||
ins.midi_velocity_offset = in.midi_velocity_offset;
|
||||
ins.percussion_key_number = in.tone;
|
||||
ins.inst_flags = (in.flags & (adlinsdata::Flag_Pseudo4op|adlinsdata::Flag_Real4op)) ? WOPL_Ins_4op : 0;
|
||||
ins.inst_flags|= (in.flags & adlinsdata::Flag_Pseudo4op) ? WOPL_Ins_Pseudo4op : 0;
|
||||
ins.inst_flags|= (in.flags & adlinsdata::Flag_NoSound) ? WOPL_Ins_IsBlank : 0;
|
||||
ins.inst_flags |= in.flags & adlinsdata::Mask_RhythmMode;
|
||||
|
||||
for(size_t op = 0; op < 4; op++)
|
||||
{
|
||||
const adldata &in2op = in.adl[(op < 2) ? 0 : 1];
|
||||
uint32_t regE862 = ((op & 1) == 0) ? in2op.carrier_E862 : in2op.modulator_E862;
|
||||
uint8_t reg40 = ((op & 1) == 0) ? in2op.carrier_40 : in2op.modulator_40;
|
||||
|
||||
ins.operators[op].waveform_E0 = static_cast<uint8_t>(regE862 >> 24);
|
||||
ins.operators[op].susrel_80 = static_cast<uint8_t>(regE862 >> 16);
|
||||
ins.operators[op].atdec_60 = static_cast<uint8_t>(regE862 >> 8);
|
||||
ins.operators[op].avekf_20 = static_cast<uint8_t>(regE862 >> 0);
|
||||
ins.operators[op].ksl_l_40 = reg40;
|
||||
}
|
||||
|
||||
ins.note_offset1 = in.adl[0].finetune;
|
||||
ins.fb_conn1_C0 = in.adl[0].feedconn;
|
||||
ins.note_offset2 = in.adl[1].finetune;
|
||||
ins.fb_conn2_C0 = in.adl[1].feedconn;
|
||||
|
||||
ins.delay_on_ms = in.ms_sound_kon;
|
||||
ins.delay_off_ms = in.ms_sound_koff;
|
||||
}
|
|
@ -1,287 +0,0 @@
|
|||
/*
|
||||
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
|
||||
*
|
||||
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
|
||||
* http://iki.fi/bisqwit/source/adlmidi.html
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "adlmidi_private.hpp"
|
||||
#include "adlmidi_cvt.hpp"
|
||||
#include "wopl/wopl_file.h"
|
||||
|
||||
bool MIDIplay::LoadBank(const std::string &filename)
|
||||
{
|
||||
FileAndMemReader file;
|
||||
file.openFile(filename.c_str());
|
||||
return LoadBank(file);
|
||||
}
|
||||
|
||||
bool MIDIplay::LoadBank(const void *data, size_t size)
|
||||
{
|
||||
FileAndMemReader file;
|
||||
file.openData(data, size);
|
||||
return LoadBank(file);
|
||||
}
|
||||
|
||||
void cvt_ADLI_to_FMIns(adlinsdata2 &ins, const ADL_Instrument &in)
|
||||
{
|
||||
return cvt_generic_to_FMIns(ins, in);
|
||||
}
|
||||
|
||||
void cvt_FMIns_to_ADLI(ADL_Instrument &ins, const adlinsdata2 &in)
|
||||
{
|
||||
cvt_FMIns_to_generic(ins, in);
|
||||
}
|
||||
|
||||
bool MIDIplay::LoadBank(FileAndMemReader &fr)
|
||||
{
|
||||
int err = 0;
|
||||
WOPLFile *wopl = NULL;
|
||||
char *raw_file_data = NULL;
|
||||
size_t fsize;
|
||||
if(!fr.isValid())
|
||||
{
|
||||
errorStringOut = "Custom bank: Invalid data stream!";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read complete bank file into the memory
|
||||
fsize = fr.fileSize();
|
||||
fr.seek(0, FileAndMemReader::SET);
|
||||
// Allocate necessary memory block
|
||||
raw_file_data = (char*)malloc(fsize);
|
||||
if(!raw_file_data)
|
||||
{
|
||||
errorStringOut = "Custom bank: Out of memory before of read!";
|
||||
return false;
|
||||
}
|
||||
fr.read(raw_file_data, 1, fsize);
|
||||
|
||||
// Parse bank file from the memory
|
||||
wopl = WOPL_LoadBankFromMem((void*)raw_file_data, fsize, &err);
|
||||
//Free the buffer no more needed
|
||||
free(raw_file_data);
|
||||
|
||||
// Check for any erros
|
||||
if(!wopl)
|
||||
{
|
||||
switch(err)
|
||||
{
|
||||
case WOPL_ERR_BAD_MAGIC:
|
||||
errorStringOut = "Custom bank: Invalid magic!";
|
||||
return false;
|
||||
case WOPL_ERR_UNEXPECTED_ENDING:
|
||||
errorStringOut = "Custom bank: Unexpected ending!";
|
||||
return false;
|
||||
case WOPL_ERR_INVALID_BANKS_COUNT:
|
||||
errorStringOut = "Custom bank: Invalid banks count!";
|
||||
return false;
|
||||
case WOPL_ERR_NEWER_VERSION:
|
||||
errorStringOut = "Custom bank: Version is newer than supported by this library!";
|
||||
return false;
|
||||
case WOPL_ERR_OUT_OF_MEMORY:
|
||||
errorStringOut = "Custom bank: Out of memory!";
|
||||
return false;
|
||||
default:
|
||||
errorStringOut = "Custom bank: Unknown error!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_synth.m_insBankSetup.adLibPercussions = false;
|
||||
m_synth.m_insBankSetup.scaleModulators = false;
|
||||
m_synth.m_insBankSetup.deepTremolo = (wopl->opl_flags & WOPL_FLAG_DEEP_TREMOLO) != 0;
|
||||
m_synth.m_insBankSetup.deepVibrato = (wopl->opl_flags & WOPL_FLAG_DEEP_VIBRATO) != 0;
|
||||
m_synth.m_insBankSetup.volumeModel = wopl->volume_model;
|
||||
m_setup.deepTremoloMode = -1;
|
||||
m_setup.deepVibratoMode = -1;
|
||||
m_setup.volumeScaleModel = ADLMIDI_VolumeModel_AUTO;
|
||||
|
||||
m_synth.setEmbeddedBank(m_setup.bankId);
|
||||
|
||||
uint16_t slots_counts[2] = {wopl->banks_count_melodic, wopl->banks_count_percussion};
|
||||
WOPLBank *slots_src_ins[2] = { wopl->banks_melodic, wopl->banks_percussive };
|
||||
|
||||
for(size_t ss = 0; ss < 2; ss++)
|
||||
{
|
||||
for(size_t i = 0; i < slots_counts[ss]; i++)
|
||||
{
|
||||
size_t bankno = (slots_src_ins[ss][i].bank_midi_msb * 256) +
|
||||
(slots_src_ins[ss][i].bank_midi_lsb) +
|
||||
(ss ? size_t(OPL3::PercussionTag) : 0);
|
||||
OPL3::Bank &bank = m_synth.m_insBanks[bankno];
|
||||
for(int j = 0; j < 128; j++)
|
||||
{
|
||||
adlinsdata2 &ins = bank.ins[j];
|
||||
std::memset(&ins, 0, sizeof(adlinsdata2));
|
||||
WOPLInstrument &inIns = slots_src_ins[ss][i].ins[j];
|
||||
cvt_generic_to_FMIns(ins, inIns);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_synth.m_embeddedBank = OPL3::CustomBankTag; // Use dynamic banks!
|
||||
//Percussion offset is count of instruments multipled to count of melodic banks
|
||||
applySetup();
|
||||
|
||||
WOPL_Free(wopl);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
|
||||
|
||||
bool MIDIplay::LoadMIDI_pre()
|
||||
{
|
||||
#ifdef DISABLE_EMBEDDED_BANKS
|
||||
if((m_synth.m_embeddedBank != OPL3::CustomBankTag) || m_synth.m_insBanks.empty())
|
||||
{
|
||||
errorStringOut = "Bank is not set! Please load any instruments bank by using of adl_openBankFile() or adl_openBankData() functions!";
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
/**** Set all properties BEFORE starting of actial file reading! ****/
|
||||
resetMIDI();
|
||||
applySetup();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MIDIplay::LoadMIDI_post()
|
||||
{
|
||||
MidiSequencer::FileFormat format = m_sequencer.getFormat();
|
||||
if(format == MidiSequencer::Format_CMF)
|
||||
{
|
||||
const std::vector<MidiSequencer::CmfInstrument> &instruments = m_sequencer.getRawCmfInstruments();
|
||||
m_synth.m_insBanks.clear();//Clean up old banks
|
||||
|
||||
uint16_t ins_count = static_cast<uint16_t>(instruments.size());
|
||||
for(uint16_t i = 0; i < ins_count; ++i)
|
||||
{
|
||||
const uint8_t *InsData = instruments[i].data;
|
||||
size_t bank = i / 256;
|
||||
bank = ((bank & 127) + ((bank >> 7) << 8));
|
||||
if(bank > 127 + (127 << 8))
|
||||
break;
|
||||
bank += (i % 256 < 128) ? 0 : size_t(OPL3::PercussionTag);
|
||||
|
||||
/*std::printf("Ins %3u: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
||||
i, InsData[0],InsData[1],InsData[2],InsData[3], InsData[4],InsData[5],InsData[6],InsData[7],
|
||||
InsData[8],InsData[9],InsData[10],InsData[11], InsData[12],InsData[13],InsData[14],InsData[15]);*/
|
||||
adlinsdata2 &adlins = m_synth.m_insBanks[bank].ins[i % 128];
|
||||
adldata adl;
|
||||
adl.modulator_E862 =
|
||||
((static_cast<uint32_t>(InsData[8] & 0x07) << 24) & 0xFF000000) //WaveForm
|
||||
| ((static_cast<uint32_t>(InsData[6]) << 16) & 0x00FF0000) //Sustain/Release
|
||||
| ((static_cast<uint32_t>(InsData[4]) << 8) & 0x0000FF00) //Attack/Decay
|
||||
| ((static_cast<uint32_t>(InsData[0]) << 0) & 0x000000FF); //MultKEVA
|
||||
adl.carrier_E862 =
|
||||
((static_cast<uint32_t>(InsData[9] & 0x07) << 24) & 0xFF000000) //WaveForm
|
||||
| ((static_cast<uint32_t>(InsData[7]) << 16) & 0x00FF0000) //Sustain/Release
|
||||
| ((static_cast<uint32_t>(InsData[5]) << 8) & 0x0000FF00) //Attack/Decay
|
||||
| ((static_cast<uint32_t>(InsData[1]) << 0) & 0x000000FF); //MultKEVA
|
||||
adl.modulator_40 = InsData[2];
|
||||
adl.carrier_40 = InsData[3];
|
||||
adl.feedconn = InsData[10] & 0x0F;
|
||||
adl.finetune = 0;
|
||||
adlins.adl[0] = adl;
|
||||
adlins.adl[1] = adl;
|
||||
adlins.ms_sound_kon = 1000;
|
||||
adlins.ms_sound_koff = 500;
|
||||
adlins.tone = 0;
|
||||
adlins.flags = 0;
|
||||
adlins.voice2_fine_tune = 0.0;
|
||||
}
|
||||
|
||||
m_synth.m_embeddedBank = OPL3::CustomBankTag; // Ignore AdlBank number, use dynamic banks instead
|
||||
//std::printf("CMF deltas %u ticks %u, basictempo = %u\n", deltas, ticks, basictempo);
|
||||
m_synth.m_rhythmMode = true;
|
||||
m_synth.m_musicMode = OPL3::MODE_CMF;
|
||||
m_synth.m_volumeScale = OPL3::VOLUME_NATIVE;
|
||||
|
||||
m_synth.m_numChips = 1;
|
||||
m_synth.m_numFourOps = 0;
|
||||
}
|
||||
else if(format == MidiSequencer::Format_RSXX)
|
||||
{
|
||||
//opl.CartoonersVolumes = true;
|
||||
m_synth.m_musicMode = OPL3::MODE_RSXX;
|
||||
m_synth.m_volumeScale = OPL3::VOLUME_NATIVE;
|
||||
|
||||
m_synth.m_numChips = 1;
|
||||
m_synth.m_numFourOps = 0;
|
||||
}
|
||||
else if(format == MidiSequencer::Format_IMF)
|
||||
{
|
||||
//std::fprintf(stderr, "Done reading IMF file\n");
|
||||
m_synth.m_numFourOps = 0; //Don't use 4-operator channels for IMF playing!
|
||||
m_synth.m_musicMode = OPL3::MODE_IMF;
|
||||
|
||||
m_synth.m_numChips = 1;
|
||||
m_synth.m_numFourOps = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_synth.m_numChips = m_setup.numChips;
|
||||
if(m_setup.numFourOps < 0)
|
||||
adlCalculateFourOpChannels(this, true);
|
||||
}
|
||||
|
||||
m_setup.tick_skip_samples_delay = 0;
|
||||
m_synth.reset(m_setup.emulator, m_setup.PCM_RATE, this); // Reset OPL3 chip
|
||||
//opl.Reset(); // ...twice (just in case someone misprogrammed OPL3 previously)
|
||||
m_chipChannels.clear();
|
||||
m_chipChannels.resize(m_synth.m_numChannels);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MIDIplay::LoadMIDI(const std::string &filename)
|
||||
{
|
||||
FileAndMemReader file;
|
||||
file.openFile(filename.c_str());
|
||||
if(!LoadMIDI_pre())
|
||||
return false;
|
||||
if(!m_sequencer.loadMIDI(file))
|
||||
{
|
||||
errorStringOut = m_sequencer.getErrorString();
|
||||
return false;
|
||||
}
|
||||
if(!LoadMIDI_post())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MIDIplay::LoadMIDI(const void *data, size_t size)
|
||||
{
|
||||
FileAndMemReader file;
|
||||
file.openData(data, size);
|
||||
if(!LoadMIDI_pre())
|
||||
return false;
|
||||
if(!m_sequencer.loadMIDI(file))
|
||||
{
|
||||
errorStringOut = m_sequencer.getErrorString();
|
||||
return false;
|
||||
}
|
||||
if(!LoadMIDI_post())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* ADLMIDI_DISABLE_MIDI_SEQUENCER */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,753 +0,0 @@
|
|||
/*
|
||||
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
|
||||
*
|
||||
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
|
||||
* http://iki.fi/bisqwit/source/adlmidi.html
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "adlmidi_private.hpp"
|
||||
#include <stdlib.h>
|
||||
#include <cassert>
|
||||
|
||||
#ifdef ADLMIDI_HW_OPL
|
||||
static const unsigned OPLBase = 0x388;
|
||||
#else
|
||||
# if defined(ADLMIDI_DISABLE_NUKED_EMULATOR) && defined(ADLMIDI_DISABLE_DOSBOX_EMULATOR)
|
||||
# error "No emulators enabled. You must enable at least one emulator to use this library!"
|
||||
# endif
|
||||
|
||||
// Nuked OPL3 emulator, Most accurate, but requires the powerful CPU
|
||||
# ifndef ADLMIDI_DISABLE_NUKED_EMULATOR
|
||||
# include "chips/nuked_opl3.h"
|
||||
# include "chips/nuked_opl3_v174.h"
|
||||
# endif
|
||||
|
||||
// DosBox 0.74 OPL3 emulator, Well-accurate and fast
|
||||
# ifndef ADLMIDI_DISABLE_DOSBOX_EMULATOR
|
||||
# include "chips/dosbox_opl3.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static const unsigned adl_emulatorSupport = 0
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
# ifndef ADLMIDI_DISABLE_NUKED_EMULATOR
|
||||
| (1u << ADLMIDI_EMU_NUKED) | (1u << ADLMIDI_EMU_NUKED_174)
|
||||
# endif
|
||||
|
||||
# ifndef ADLMIDI_DISABLE_DOSBOX_EMULATOR
|
||||
| (1u << ADLMIDI_EMU_DOSBOX)
|
||||
# endif
|
||||
#endif
|
||||
;
|
||||
|
||||
//! Check emulator availability
|
||||
bool adl_isEmulatorAvailable(int emulator)
|
||||
{
|
||||
return (adl_emulatorSupport & (1u << (unsigned)emulator)) != 0;
|
||||
}
|
||||
|
||||
//! Find highest emulator
|
||||
int adl_getHighestEmulator()
|
||||
{
|
||||
int emu = -1;
|
||||
for(unsigned m = adl_emulatorSupport; m > 0; m >>= 1)
|
||||
++emu;
|
||||
return emu;
|
||||
}
|
||||
|
||||
//! Find lowest emulator
|
||||
int adl_getLowestEmulator()
|
||||
{
|
||||
int emu = -1;
|
||||
unsigned m = adl_emulatorSupport;
|
||||
if(m > 0)
|
||||
{
|
||||
for(emu = 0; (m & 1) == 0; m >>= 1)
|
||||
++emu;
|
||||
}
|
||||
return emu;
|
||||
}
|
||||
|
||||
//! Per-channel and per-operator registers map
|
||||
static const uint16_t g_operatorsMap[23 * 2] =
|
||||
{
|
||||
// Channels 0-2
|
||||
0x000, 0x003, 0x001, 0x004, 0x002, 0x005, // operators 0, 3, 1, 4, 2, 5
|
||||
// Channels 3-5
|
||||
0x008, 0x00B, 0x009, 0x00C, 0x00A, 0x00D, // operators 6, 9, 7,10, 8,11
|
||||
// Channels 6-8
|
||||
0x010, 0x013, 0x011, 0x014, 0x012, 0x015, // operators 12,15, 13,16, 14,17
|
||||
// Same for second card
|
||||
0x100, 0x103, 0x101, 0x104, 0x102, 0x105, // operators 18,21, 19,22, 20,23
|
||||
0x108, 0x10B, 0x109, 0x10C, 0x10A, 0x10D, // operators 24,27, 25,28, 26,29
|
||||
0x110, 0x113, 0x111, 0x114, 0x112, 0x115, // operators 30,33, 31,34, 32,35
|
||||
// Channel 18
|
||||
0x010, 0x013, // operators 12,15
|
||||
// Channel 19
|
||||
0x014, 0xFFF, // operator 16
|
||||
// Channel 19
|
||||
0x012, 0xFFF, // operator 14
|
||||
// Channel 19
|
||||
0x015, 0xFFF, // operator 17
|
||||
// Channel 19
|
||||
0x011, 0xFFF
|
||||
}; // operator 13
|
||||
|
||||
//! Channel map to regoster offsets
|
||||
static const uint16_t g_channelsMap[23] =
|
||||
{
|
||||
0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, // 0..8
|
||||
0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, // 9..17 (secondary set)
|
||||
0x006, 0x007, 0x008, 0xFFF, 0xFFF
|
||||
}; // <- hw percussions, 0xFFF = no support for pitch/pan
|
||||
|
||||
/*
|
||||
In OPL3 mode:
|
||||
0 1 2 6 7 8 9 10 11 16 17 18
|
||||
op0 op1 op2 op12 op13 op14 op18 op19 op20 op30 op31 op32
|
||||
op3 op4 op5 op15 op16 op17 op21 op22 op23 op33 op34 op35
|
||||
3 4 5 13 14 15
|
||||
op6 op7 op8 op24 op25 op26
|
||||
op9 op10 op11 op27 op28 op29
|
||||
Ports:
|
||||
+0 +1 +2 +10 +11 +12 +100 +101 +102 +110 +111 +112
|
||||
+3 +4 +5 +13 +14 +15 +103 +104 +105 +113 +114 +115
|
||||
+8 +9 +A +108 +109 +10A
|
||||
+B +C +D +10B +10C +10D
|
||||
|
||||
Percussion:
|
||||
bassdrum = op(0): 0xBD bit 0x10, operators 12 (0x10) and 15 (0x13) / channels 6, 6b
|
||||
snare = op(3): 0xBD bit 0x08, operators 16 (0x14) / channels 7b
|
||||
tomtom = op(4): 0xBD bit 0x04, operators 14 (0x12) / channels 8
|
||||
cym = op(5): 0xBD bit 0x02, operators 17 (0x17) / channels 8b
|
||||
hihat = op(2): 0xBD bit 0x01, operators 13 (0x11) / channels 7
|
||||
|
||||
|
||||
In OPTi mode ("extended FM" in 82C924, 82C925, 82C931 chips):
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
||||
op0 op4 op6 op10 op12 op16 op18 op22 op24 op28 op30 op34 op36 op38 op40 op42 op44 op46
|
||||
op1 op5 op7 op11 op13 op17 op19 op23 op25 op29 op31 op35 op37 op39 op41 op43 op45 op47
|
||||
op2 op8 op14 op20 op26 op32
|
||||
op3 op9 op15 op21 op27 op33 for a total of 6 quad + 12 dual
|
||||
Ports: ???
|
||||
*/
|
||||
|
||||
static adlinsdata2 makeEmptyInstrument()
|
||||
{
|
||||
adlinsdata2 ins;
|
||||
memset(&ins, 0, sizeof(adlinsdata2));
|
||||
ins.flags = adlinsdata::Flag_NoSound;
|
||||
return ins;
|
||||
}
|
||||
|
||||
const adlinsdata2 OPL3::m_emptyInstrument = makeEmptyInstrument();
|
||||
|
||||
OPL3::OPL3() :
|
||||
m_numChips(1),
|
||||
m_numFourOps(0),
|
||||
m_deepTremoloMode(false),
|
||||
m_deepVibratoMode(false),
|
||||
m_rhythmMode(false),
|
||||
m_softPanning(false),
|
||||
m_musicMode(MODE_MIDI),
|
||||
m_volumeScale(VOLUME_Generic)
|
||||
{
|
||||
m_insBankSetup.volumeModel = OPL3::VOLUME_Generic;
|
||||
m_insBankSetup.deepTremolo = false;
|
||||
m_insBankSetup.deepVibrato = false;
|
||||
m_insBankSetup.adLibPercussions = false;
|
||||
m_insBankSetup.scaleModulators = false;
|
||||
|
||||
#ifdef DISABLE_EMBEDDED_BANKS
|
||||
m_embeddedBank = CustomBankTag;
|
||||
#else
|
||||
setEmbeddedBank(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool OPL3::setupLocked()
|
||||
{
|
||||
return (m_musicMode == MODE_CMF ||
|
||||
m_musicMode == MODE_IMF ||
|
||||
m_musicMode == MODE_RSXX);
|
||||
}
|
||||
|
||||
void OPL3::setEmbeddedBank(uint32_t bank)
|
||||
{
|
||||
#ifndef DISABLE_EMBEDDED_BANKS
|
||||
m_embeddedBank = bank;
|
||||
//Embedded banks are supports 128:128 GM set only
|
||||
m_insBanks.clear();
|
||||
|
||||
if(bank >= static_cast<unsigned int>(maxAdlBanks()))
|
||||
return;
|
||||
|
||||
Bank *bank_pair[2] =
|
||||
{
|
||||
&m_insBanks[0],
|
||||
&m_insBanks[PercussionTag]
|
||||
};
|
||||
|
||||
for(unsigned i = 0; i < 256; ++i)
|
||||
{
|
||||
size_t meta = banks[bank][i];
|
||||
adlinsdata2 &ins = bank_pair[i / 128]->ins[i % 128];
|
||||
ins = adlinsdata2::from_adldata(::adlins[meta]);
|
||||
}
|
||||
#else
|
||||
ADL_UNUSED(bank);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OPL3::writeReg(size_t chip, uint16_t address, uint8_t value)
|
||||
{
|
||||
#ifdef ADLMIDI_HW_OPL
|
||||
ADL_UNUSED(chip);
|
||||
unsigned o = address >> 8;
|
||||
unsigned port = OPLBase + o * 2;
|
||||
|
||||
#ifdef __DJGPP__
|
||||
outportb(port, address);
|
||||
for(unsigned c = 0; c < 6; ++c) inportb(port);
|
||||
outportb(port + 1, value);
|
||||
for(unsigned c = 0; c < 35; ++c) inportb(port);
|
||||
#endif
|
||||
|
||||
#ifdef __WATCOMC__
|
||||
outp(port, address);
|
||||
for(uint16_t c = 0; c < 6; ++c) inp(port);
|
||||
outp(port + 1, value);
|
||||
for(uint16_t c = 0; c < 35; ++c) inp(port);
|
||||
#endif//__WATCOMC__
|
||||
|
||||
#else//ADLMIDI_HW_OPL
|
||||
m_chips[chip]->writeReg(address, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OPL3::writeRegI(size_t chip, uint32_t address, uint32_t value)
|
||||
{
|
||||
#ifdef ADLMIDI_HW_OPL
|
||||
writeReg(chip, static_cast<uint16_t>(address), static_cast<uint8_t>(value));
|
||||
#else//ADLMIDI_HW_OPL
|
||||
m_chips[chip]->writeReg(static_cast<uint16_t>(address), static_cast<uint8_t>(value));
|
||||
#endif
|
||||
}
|
||||
|
||||
void OPL3::writePan(size_t chip, uint32_t address, uint32_t value)
|
||||
{
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
m_chips[chip]->writePan(static_cast<uint16_t>(address), static_cast<uint8_t>(value));
|
||||
#else
|
||||
ADL_UNUSED(chip);
|
||||
ADL_UNUSED(address);
|
||||
ADL_UNUSED(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void OPL3::noteOff(size_t c)
|
||||
{
|
||||
size_t chip = c / 23, cc = c % 23;
|
||||
|
||||
if(cc >= 18)
|
||||
{
|
||||
m_regBD[chip] &= ~(0x10 >> (cc - 18));
|
||||
writeRegI(chip, 0xBD, m_regBD[chip]);
|
||||
return;
|
||||
}
|
||||
|
||||
writeRegI(chip, 0xB0 + g_channelsMap[cc], m_keyBlockFNumCache[c] & 0xDF);
|
||||
}
|
||||
|
||||
void OPL3::noteOn(size_t c1, size_t c2, double hertz) // Hertz range: 0..131071
|
||||
{
|
||||
size_t chip = c1 / 23, cc1 = c1 % 23, cc2 = c2 % 23;
|
||||
uint32_t octave = 0, ftone = 0, mul_offset = 0;
|
||||
|
||||
if(hertz < 0)
|
||||
return;
|
||||
|
||||
//Basic range until max of octaves reaching
|
||||
while((hertz >= 1023.5) && (octave < 0x1C00))
|
||||
{
|
||||
hertz /= 2.0; // Calculate octave
|
||||
octave += 0x400;
|
||||
}
|
||||
//Extended range, rely on frequency multiplication increment
|
||||
while(hertz >= 1022.75)
|
||||
{
|
||||
hertz /= 2.0; // Calculate octave
|
||||
mul_offset++;
|
||||
}
|
||||
|
||||
ftone = octave + static_cast<uint32_t>(hertz + 0.5);
|
||||
uint32_t chn = g_channelsMap[cc1];
|
||||
const adldata &patch1 = m_insCache[c1];
|
||||
const adldata &patch2 = m_insCache[c2 < m_insCache.size() ? c2 : 0];
|
||||
|
||||
if(cc1 < 18)
|
||||
{
|
||||
ftone += 0x2000u; /* Key-ON [KON] */
|
||||
|
||||
const bool natural_4op = (m_channelCategory[c1] == ChanCat_4op_Master);
|
||||
const size_t opsCount = natural_4op ? 4 : 2;
|
||||
const uint16_t op_addr[4] =
|
||||
{
|
||||
g_operatorsMap[cc1 * 2 + 0], g_operatorsMap[cc1 * 2 + 1],
|
||||
g_operatorsMap[cc2 * 2 + 0], g_operatorsMap[cc2 * 2 + 1]
|
||||
};
|
||||
const uint32_t ops[4] =
|
||||
{
|
||||
patch1.modulator_E862 & 0xFF,
|
||||
patch1.carrier_E862 & 0xFF,
|
||||
patch2.modulator_E862 & 0xFF,
|
||||
patch2.carrier_E862 & 0xFF
|
||||
};
|
||||
|
||||
for(size_t op = 0; op < opsCount; op++)
|
||||
{
|
||||
if((op > 0) && (op_addr[op] == 0xFFF))
|
||||
break;
|
||||
if(mul_offset > 0)
|
||||
{
|
||||
uint32_t dt = ops[op] & 0xF0;
|
||||
uint32_t mul = ops[op] & 0x0F;
|
||||
if((mul + mul_offset) > 0x0F)
|
||||
{
|
||||
mul_offset = 0;
|
||||
mul = 0x0F;
|
||||
}
|
||||
writeRegI(chip, 0x20 + op_addr[op], (dt | (mul + mul_offset)) & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeRegI(chip, 0x20 + op_addr[op], ops[op] & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(chn != 0xFFF)
|
||||
{
|
||||
writeRegI(chip , 0xA0 + chn, (ftone & 0xFF));
|
||||
writeRegI(chip , 0xB0 + chn, (ftone >> 8));
|
||||
m_keyBlockFNumCache[c1] = (ftone >> 8);
|
||||
}
|
||||
|
||||
if(cc1 >= 18)
|
||||
{
|
||||
m_regBD[chip ] |= (0x10 >> (cc1 - 18));
|
||||
writeRegI(chip , 0x0BD, m_regBD[chip ]);
|
||||
//x |= 0x800; // for test
|
||||
}
|
||||
}
|
||||
|
||||
void OPL3::touchNote(size_t c, uint8_t volume, uint8_t brightness)
|
||||
{
|
||||
if(volume > 63)
|
||||
volume = 63;
|
||||
|
||||
size_t chip = c / 23, cc = c % 23;
|
||||
const adldata &adli = m_insCache[c];
|
||||
uint16_t o1 = g_operatorsMap[cc * 2 + 0];
|
||||
uint16_t o2 = g_operatorsMap[cc * 2 + 1];
|
||||
uint8_t x = adli.modulator_40, y = adli.carrier_40;
|
||||
uint32_t mode = 1; // 2-op AM
|
||||
|
||||
if(m_channelCategory[c] == ChanCat_Regular ||
|
||||
m_channelCategory[c] == ChanCat_Rhythm_Bass)
|
||||
{
|
||||
mode = adli.feedconn & 1; // 2-op FM or 2-op AM
|
||||
}
|
||||
else if(m_channelCategory[c] == ChanCat_4op_Master ||
|
||||
m_channelCategory[c] == ChanCat_4op_Slave)
|
||||
{
|
||||
const adldata *i0, *i1;
|
||||
|
||||
if(m_channelCategory[c] == ChanCat_4op_Master)
|
||||
{
|
||||
i0 = &adli;
|
||||
i1 = &m_insCache[c + 3];
|
||||
mode = 2; // 4-op xx-xx ops 1&2
|
||||
}
|
||||
else
|
||||
{
|
||||
i0 = &m_insCache[c - 3];
|
||||
i1 = &adli;
|
||||
mode = 6; // 4-op xx-xx ops 3&4
|
||||
}
|
||||
|
||||
mode += (i0->feedconn & 1) + (i1->feedconn & 1) * 2;
|
||||
}
|
||||
|
||||
static const bool do_ops[10][2] =
|
||||
{
|
||||
{ false, true }, /* 2 op FM */
|
||||
{ true, true }, /* 2 op AM */
|
||||
{ false, false }, /* 4 op FM-FM ops 1&2 */
|
||||
{ true, false }, /* 4 op AM-FM ops 1&2 */
|
||||
{ false, true }, /* 4 op FM-AM ops 1&2 */
|
||||
{ true, false }, /* 4 op AM-AM ops 1&2 */
|
||||
{ false, true }, /* 4 op FM-FM ops 3&4 */
|
||||
{ false, true }, /* 4 op AM-FM ops 3&4 */
|
||||
{ false, true }, /* 4 op FM-AM ops 3&4 */
|
||||
{ true, true } /* 4 op AM-AM ops 3&4 */
|
||||
};
|
||||
|
||||
if(m_musicMode == MODE_RSXX)
|
||||
{
|
||||
writeRegI(chip, 0x40 + o1, x);
|
||||
if(o2 != 0xFFF)
|
||||
writeRegI(chip, 0x40 + o2, y - volume / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool do_modulator = do_ops[ mode ][ 0 ] || m_scaleModulators;
|
||||
bool do_carrier = do_ops[ mode ][ 1 ] || m_scaleModulators;
|
||||
|
||||
uint32_t modulator = do_modulator ? (x | 63) - volume + volume * (x & 63) / 63 : x;
|
||||
uint32_t carrier = do_carrier ? (y | 63) - volume + volume * (y & 63) / 63 : y;
|
||||
|
||||
if(brightness != 127)
|
||||
{
|
||||
brightness = static_cast<uint8_t>(::round(127.0 * ::sqrt((static_cast<double>(brightness)) * (1.0 / 127.0))) / 2.0);
|
||||
if(!do_modulator)
|
||||
modulator = (modulator | 63) - brightness + brightness * (modulator & 63) / 63;
|
||||
if(!do_carrier)
|
||||
carrier = (carrier | 63) - brightness + brightness * (carrier & 63) / 63;
|
||||
}
|
||||
|
||||
writeRegI(chip, 0x40 + o1, modulator);
|
||||
if(o2 != 0xFFF)
|
||||
writeRegI(chip, 0x40 + o2, carrier);
|
||||
}
|
||||
|
||||
// Correct formula (ST3, AdPlug):
|
||||
// 63-((63-(instrvol))/63)*chanvol
|
||||
// Reduces to (tested identical):
|
||||
// 63 - chanvol + chanvol*instrvol/63
|
||||
// Also (slower, floats):
|
||||
// 63 + chanvol * (instrvol / 63.0 - 1)
|
||||
}
|
||||
|
||||
/*
|
||||
void OPL3::Touch(unsigned c, unsigned volume) // Volume maxes at 127*127*127
|
||||
{
|
||||
if(LogarithmicVolumes)
|
||||
Touch_Real(c, volume * 127 / (127 * 127 * 127) / 2);
|
||||
else
|
||||
{
|
||||
// The formula below: SOLVE(V=127^3 * 2^( (A-63.49999) / 8), A)
|
||||
Touch_Real(c, volume > 8725 ? static_cast<unsigned int>(std::log(volume) * 11.541561 + (0.5 - 104.22845)) : 0);
|
||||
// The incorrect formula below: SOLVE(V=127^3 * (2^(A/63)-1), A)
|
||||
//Touch_Real(c, volume>11210 ? 91.61112 * std::log(4.8819E-7*volume + 1.0)+0.5 : 0);
|
||||
}
|
||||
}*/
|
||||
|
||||
void OPL3::setPatch(size_t c, const adldata &instrument)
|
||||
{
|
||||
size_t chip = c / 23, cc = c % 23;
|
||||
static const uint8_t data[4] = {0x20, 0x60, 0x80, 0xE0};
|
||||
m_insCache[c] = instrument;
|
||||
uint16_t o1 = g_operatorsMap[cc * 2 + 0];
|
||||
uint16_t o2 = g_operatorsMap[cc * 2 + 1];
|
||||
unsigned x = instrument.modulator_E862, y = instrument.carrier_E862;
|
||||
|
||||
for(size_t a = 0; a < 4; ++a, x >>= 8, y >>= 8)
|
||||
{
|
||||
writeRegI(chip, data[a] + o1, x & 0xFF);
|
||||
if(o2 != 0xFFF)
|
||||
writeRegI(chip, data[a] + o2, y & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
void OPL3::setPan(size_t c, uint8_t value)
|
||||
{
|
||||
size_t chip = c / 23, cc = c % 23;
|
||||
if(g_channelsMap[cc] != 0xFFF)
|
||||
{
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
if (m_softPanning)
|
||||
{
|
||||
writePan(chip, g_channelsMap[cc], value);
|
||||
writeRegI(chip, 0xC0 + g_channelsMap[cc], m_insCache[c].feedconn | OPL_PANNING_BOTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
int panning = 0;
|
||||
if(value < 64 + 32) panning |= OPL_PANNING_LEFT;
|
||||
if(value >= 64 - 32) panning |= OPL_PANNING_RIGHT;
|
||||
writePan(chip, g_channelsMap[cc], 64);
|
||||
writeRegI(chip, 0xC0 + g_channelsMap[cc], m_insCache[c].feedconn | panning);
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void OPL3::silenceAll() // Silence all OPL channels.
|
||||
{
|
||||
for(size_t c = 0; c < m_numChannels; ++c)
|
||||
{
|
||||
noteOff(c);
|
||||
touchNote(c, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void OPL3::updateChannelCategories()
|
||||
{
|
||||
const uint32_t fours = m_numFourOps;
|
||||
|
||||
for(uint32_t chip = 0, fours_left = fours; chip < m_numChips; ++chip)
|
||||
{
|
||||
m_regBD[chip] = (m_deepTremoloMode * 0x80 + m_deepVibratoMode * 0x40 + m_rhythmMode * 0x20);
|
||||
writeRegI(chip, 0x0BD, m_regBD[chip]);
|
||||
uint32_t fours_this_chip = std::min(fours_left, static_cast<uint32_t>(6u));
|
||||
writeRegI(chip, 0x104, (1 << fours_this_chip) - 1);
|
||||
fours_left -= fours_this_chip;
|
||||
}
|
||||
|
||||
if(!m_rhythmMode)
|
||||
{
|
||||
for(size_t a = 0, n = m_numChips; a < n; ++a)
|
||||
{
|
||||
for(size_t b = 0; b < 23; ++b)
|
||||
{
|
||||
m_channelCategory[a * 23 + b] =
|
||||
(b >= 18) ? ChanCat_Rhythm_Slave : ChanCat_Regular;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(size_t a = 0, n = m_numChips; a < n; ++a)
|
||||
{
|
||||
for(size_t b = 0; b < 23; ++b)
|
||||
{
|
||||
m_channelCategory[a * 23 + b] =
|
||||
(b >= 18) ? static_cast<ChanCat>(ChanCat_Rhythm_Bass + (b - 18)) :
|
||||
(b >= 6 && b < 9) ? ChanCat_Rhythm_Slave : ChanCat_Regular;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t nextfour = 0;
|
||||
for(uint32_t a = 0; a < fours; ++a)
|
||||
{
|
||||
m_channelCategory[nextfour] = ChanCat_4op_Master;
|
||||
m_channelCategory[nextfour + 3] = ChanCat_4op_Slave;
|
||||
|
||||
switch(a % 6)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
nextfour += 1;
|
||||
break;
|
||||
case 2:
|
||||
nextfour += 9 - 2;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
nextfour += 1;
|
||||
break;
|
||||
case 5:
|
||||
nextfour += 23 - 9 - 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**/
|
||||
/*
|
||||
In two-op mode, channels 0..8 go as follows:
|
||||
Op1[port] Op2[port]
|
||||
Channel 0: 00 00 03 03
|
||||
Channel 1: 01 01 04 04
|
||||
Channel 2: 02 02 05 05
|
||||
Channel 3: 06 08 09 0B
|
||||
Channel 4: 07 09 10 0C
|
||||
Channel 5: 08 0A 11 0D
|
||||
Channel 6: 12 10 15 13
|
||||
Channel 7: 13 11 16 14
|
||||
Channel 8: 14 12 17 15
|
||||
In four-op mode, channels 0..8 go as follows:
|
||||
Op1[port] Op2[port] Op3[port] Op4[port]
|
||||
Channel 0: 00 00 03 03 06 08 09 0B
|
||||
Channel 1: 01 01 04 04 07 09 10 0C
|
||||
Channel 2: 02 02 05 05 08 0A 11 0D
|
||||
Channel 3: CHANNEL 0 SLAVE
|
||||
Channel 4: CHANNEL 1 SLAVE
|
||||
Channel 5: CHANNEL 2 SLAVE
|
||||
Channel 6: 12 10 15 13
|
||||
Channel 7: 13 11 16 14
|
||||
Channel 8: 14 12 17 15
|
||||
Same goes principally for channels 9-17 respectively.
|
||||
*/
|
||||
}
|
||||
|
||||
void OPL3::commitDeepFlags()
|
||||
{
|
||||
for(size_t chip = 0; chip < m_numChips; ++chip)
|
||||
{
|
||||
m_regBD[chip] = (m_deepTremoloMode * 0x80 + m_deepVibratoMode * 0x40 + m_rhythmMode * 0x20);
|
||||
writeRegI(chip, 0x0BD, m_regBD[chip]);
|
||||
}
|
||||
}
|
||||
|
||||
void OPL3::setVolumeScaleModel(ADLMIDI_VolumeModels volumeModel)
|
||||
{
|
||||
switch(volumeModel)
|
||||
{
|
||||
case ADLMIDI_VolumeModel_AUTO://Do nothing until restart playing
|
||||
break;
|
||||
|
||||
case ADLMIDI_VolumeModel_Generic:
|
||||
m_volumeScale = OPL3::VOLUME_Generic;
|
||||
break;
|
||||
|
||||
case ADLMIDI_VolumeModel_NativeOPL3:
|
||||
m_volumeScale = OPL3::VOLUME_NATIVE;
|
||||
break;
|
||||
|
||||
case ADLMIDI_VolumeModel_DMX:
|
||||
m_volumeScale = OPL3::VOLUME_DMX;
|
||||
break;
|
||||
|
||||
case ADLMIDI_VolumeModel_APOGEE:
|
||||
m_volumeScale = OPL3::VOLUME_APOGEE;
|
||||
break;
|
||||
|
||||
case ADLMIDI_VolumeModel_9X:
|
||||
m_volumeScale = OPL3::VOLUME_9X;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ADLMIDI_VolumeModels OPL3::getVolumeScaleModel()
|
||||
{
|
||||
switch(m_volumeScale)
|
||||
{
|
||||
default:
|
||||
case OPL3::VOLUME_Generic:
|
||||
return ADLMIDI_VolumeModel_Generic;
|
||||
case OPL3::VOLUME_NATIVE:
|
||||
return ADLMIDI_VolumeModel_NativeOPL3;
|
||||
case OPL3::VOLUME_DMX:
|
||||
return ADLMIDI_VolumeModel_DMX;
|
||||
case OPL3::VOLUME_APOGEE:
|
||||
return ADLMIDI_VolumeModel_APOGEE;
|
||||
case OPL3::VOLUME_9X:
|
||||
return ADLMIDI_VolumeModel_9X;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
void OPL3::clearChips()
|
||||
{
|
||||
for(size_t i = 0; i < m_chips.size(); i++)
|
||||
m_chips[i].reset(NULL);
|
||||
m_chips.clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
void OPL3::reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler)
|
||||
{
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
clearChips();
|
||||
#else
|
||||
(void)emulator;
|
||||
(void)PCM_RATE;
|
||||
#endif
|
||||
#if !defined(ADLMIDI_AUDIO_TICK_HANDLER)
|
||||
(void)audioTickHandler;
|
||||
#endif
|
||||
m_insCache.clear();
|
||||
m_keyBlockFNumCache.clear();
|
||||
m_regBD.clear();
|
||||
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
m_chips.resize(m_numChips, AdlMIDI_SPtr<OPLChipBase>());
|
||||
#endif
|
||||
|
||||
const struct adldata defaultInsCache = { 0x1557403,0x005B381, 0x49,0x80, 0x4, +0 };
|
||||
m_numChannels = m_numChips * 23;
|
||||
m_insCache.resize(m_numChannels, defaultInsCache);
|
||||
m_keyBlockFNumCache.resize(m_numChannels, 0);
|
||||
m_regBD.resize(m_numChips, 0);
|
||||
m_channelCategory.resize(m_numChannels, 0);
|
||||
|
||||
for(size_t p = 0, a = 0; a < m_numChips; ++a)
|
||||
{
|
||||
for(size_t b = 0; b < 18; ++b)
|
||||
m_channelCategory[p++] = 0;
|
||||
for(size_t b = 0; b < 5; ++b)
|
||||
m_channelCategory[p++] = ChanCat_Rhythm_Slave;
|
||||
}
|
||||
|
||||
static const uint16_t data[] =
|
||||
{
|
||||
0x004, 96, 0x004, 128, // Pulse timer
|
||||
0x105, 0, 0x105, 1, 0x105, 0, // Pulse OPL3 enable
|
||||
0x001, 32, 0x105, 1 // Enable wave, OPL3 extensions
|
||||
};
|
||||
// size_t fours = m_numFourOps;
|
||||
|
||||
for(size_t i = 0; i < m_numChips; ++i)
|
||||
{
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
OPLChipBase *chip;
|
||||
switch(emulator)
|
||||
{
|
||||
default:
|
||||
assert(false);
|
||||
abort();
|
||||
#ifndef ADLMIDI_DISABLE_NUKED_EMULATOR
|
||||
case ADLMIDI_EMU_NUKED: /* Latest Nuked OPL3 */
|
||||
chip = new NukedOPL3;
|
||||
break;
|
||||
case ADLMIDI_EMU_NUKED_174: /* Old Nuked OPL3 1.4.7 modified and optimized */
|
||||
chip = new NukedOPL3v174;
|
||||
break;
|
||||
#endif
|
||||
#ifndef ADLMIDI_DISABLE_DOSBOX_EMULATOR
|
||||
case ADLMIDI_EMU_DOSBOX:
|
||||
chip = new DosBoxOPL3;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
m_chips[i].reset(chip);
|
||||
chip->setChipId((uint32_t)i);
|
||||
chip->setRate((uint32_t)PCM_RATE);
|
||||
if(m_runAtPcmRate)
|
||||
chip->setRunningAtPcmRate(true);
|
||||
# if defined(ADLMIDI_AUDIO_TICK_HANDLER)
|
||||
chip->setAudioTickHandlerInstance(audioTickHandler);
|
||||
# endif
|
||||
#endif // ADLMIDI_HW_OPL
|
||||
|
||||
/* Clean-up channels from any playing junk sounds */
|
||||
for(size_t a = 0; a < 18; ++a)
|
||||
writeRegI(i, 0xB0 + g_channelsMap[a], 0x00);
|
||||
for(size_t a = 0; a < sizeof(data) / sizeof(*data); a += 2)
|
||||
writeRegI(i, data[a], (data[a + 1]));
|
||||
}
|
||||
|
||||
updateChannelCategories();
|
||||
silenceAll();
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
|
||||
*
|
||||
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
|
||||
* http://iki.fi/bisqwit/source/adlmidi.html
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "adlmidi_private.hpp"
|
||||
|
||||
std::string ADLMIDI_ErrorString;
|
||||
|
||||
// Generator callback on audio rate ticks
|
||||
|
||||
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
|
||||
void adl_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate)
|
||||
{
|
||||
reinterpret_cast<MIDIplay *>(instance)->AudioTick(chipId, rate);
|
||||
}
|
||||
#endif
|
||||
|
||||
int adlCalculateFourOpChannels(MIDIplay *play, bool silent)
|
||||
{
|
||||
size_t n_fourop[2] = {0, 0}, n_total[2] = {0, 0};
|
||||
|
||||
//Automatically calculate how much 4-operator channels is necessary
|
||||
#ifndef DISABLE_EMBEDDED_BANKS
|
||||
if(play->m_synth.m_embeddedBank == OPL3::CustomBankTag)
|
||||
#endif
|
||||
{
|
||||
//For custom bank
|
||||
OPL3::BankMap::iterator it = play->m_synth.m_insBanks.begin();
|
||||
OPL3::BankMap::iterator end = play->m_synth.m_insBanks.end();
|
||||
for(; it != end; ++it)
|
||||
{
|
||||
size_t bank = it->first;
|
||||
size_t div = (bank & OPL3::PercussionTag) ? 1 : 0;
|
||||
for(size_t i = 0; i < 128; ++i)
|
||||
{
|
||||
adlinsdata2 &ins = it->second.ins[i];
|
||||
if(ins.flags & adlinsdata::Flag_NoSound)
|
||||
continue;
|
||||
if((ins.flags & adlinsdata::Flag_Real4op) != 0)
|
||||
++n_fourop[div];
|
||||
++n_total[div];
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef DISABLE_EMBEDDED_BANKS
|
||||
else
|
||||
{
|
||||
//For embedded bank
|
||||
for(size_t a = 0; a < 256; ++a)
|
||||
{
|
||||
size_t insno = banks[play->m_setup.bankId][a];
|
||||
if(insno == 198)
|
||||
continue;
|
||||
++n_total[a / 128];
|
||||
adlinsdata2 ins = adlinsdata2::from_adldata(::adlins[insno]);
|
||||
if((ins.flags & adlinsdata::Flag_Real4op) != 0)
|
||||
++n_fourop[a / 128];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t numFourOps = 0;
|
||||
|
||||
// All 2ops (no 4ops)
|
||||
if((n_fourop[0] == 0) && (n_fourop[1] == 0))
|
||||
numFourOps = 0;
|
||||
// All 2op melodics and Some (or All) 4op drums
|
||||
else if((n_fourop[0] == 0) && (n_fourop[1] > 0))
|
||||
numFourOps = 2;
|
||||
// Many 4op melodics
|
||||
else if((n_fourop[0] >= (n_total[0] * 7) / 8))
|
||||
numFourOps = 6;
|
||||
// Few 4op melodics
|
||||
else if(n_fourop[0] > 0)
|
||||
numFourOps = 4;
|
||||
|
||||
/* //Old formula
|
||||
unsigned NumFourOps = ((n_fourop[0] == 0) && (n_fourop[1] == 0)) ? 0
|
||||
: (n_fourop[0] >= (n_total[0] * 7) / 8) ? play->m_setup.NumCards * 6
|
||||
: (play->m_setup.NumCards == 1 ? 1 : play->m_setup.NumCards * 4);
|
||||
*/
|
||||
|
||||
play->m_synth.m_numFourOps = static_cast<unsigned>(numFourOps * play->m_synth.m_numChips);
|
||||
// Update channel categories and set up four-operator channels
|
||||
if(!silent)
|
||||
play->m_synth.updateChannelCategories();
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,217 +0,0 @@
|
|||
/*
|
||||
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
|
||||
*
|
||||
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
|
||||
* http://iki.fi/bisqwit/source/adlmidi.html
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ADLMIDI_PTR_HPP_THING
|
||||
#define ADLMIDI_PTR_HPP_THING
|
||||
|
||||
#include <algorithm> // swap
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
Generic deleters for smart pointers
|
||||
*/
|
||||
template <class T>
|
||||
struct ADLMIDI_DefaultDelete
|
||||
{
|
||||
void operator()(T *x) { delete x; }
|
||||
};
|
||||
template <class T>
|
||||
struct ADLMIDI_DefaultArrayDelete
|
||||
{
|
||||
void operator()(T *x) { delete[] x; }
|
||||
};
|
||||
struct ADLMIDI_CDelete
|
||||
{
|
||||
void operator()(void *x) { free(x); }
|
||||
};
|
||||
|
||||
/*
|
||||
Safe unique pointer for C++98, non-copyable but swappable.
|
||||
*/
|
||||
template< class T, class Deleter = ADLMIDI_DefaultDelete<T> >
|
||||
class AdlMIDI_UPtr
|
||||
{
|
||||
T *m_p;
|
||||
public:
|
||||
explicit AdlMIDI_UPtr(T *p)
|
||||
: m_p(p) {}
|
||||
~AdlMIDI_UPtr()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset(T *p = NULL)
|
||||
{
|
||||
if(p != m_p) {
|
||||
if(m_p) {
|
||||
Deleter del;
|
||||
del(m_p);
|
||||
}
|
||||
m_p = p;
|
||||
}
|
||||
}
|
||||
|
||||
void swap(AdlMIDI_UPtr &other)
|
||||
{
|
||||
std::swap(m_p, other.m_p);
|
||||
}
|
||||
|
||||
T *get() const
|
||||
{
|
||||
return m_p;
|
||||
}
|
||||
T &operator*() const
|
||||
{
|
||||
return *m_p;
|
||||
}
|
||||
T *operator->() const
|
||||
{
|
||||
return m_p;
|
||||
}
|
||||
T &operator[](size_t index) const
|
||||
{
|
||||
return m_p[index];
|
||||
}
|
||||
private:
|
||||
AdlMIDI_UPtr(const AdlMIDI_UPtr &);
|
||||
AdlMIDI_UPtr &operator=(const AdlMIDI_UPtr &);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void swap(AdlMIDI_UPtr<T> &a, AdlMIDI_UPtr<T> &b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
/**
|
||||
Unique pointer for arrays.
|
||||
*/
|
||||
template<class T>
|
||||
class AdlMIDI_UPtrArray :
|
||||
public AdlMIDI_UPtr< T, ADLMIDI_DefaultArrayDelete<T> >
|
||||
{
|
||||
public:
|
||||
explicit AdlMIDI_UPtrArray(T *p = NULL)
|
||||
: AdlMIDI_UPtr< T, ADLMIDI_DefaultArrayDelete<T> >(p) {}
|
||||
};
|
||||
|
||||
/**
|
||||
Unique pointer for C memory.
|
||||
*/
|
||||
template<class T>
|
||||
class AdlMIDI_CPtr :
|
||||
public AdlMIDI_UPtr< T, ADLMIDI_CDelete >
|
||||
{
|
||||
public:
|
||||
explicit AdlMIDI_CPtr(T *p = NULL)
|
||||
: AdlMIDI_UPtr< T, ADLMIDI_CDelete >(p) {}
|
||||
};
|
||||
|
||||
/*
|
||||
Shared pointer with non-atomic counter
|
||||
FAQ: Why not std::shared_ptr? Because of Android NDK now doesn't supports it
|
||||
*/
|
||||
template< class T, class Deleter = ADLMIDI_DefaultDelete<T> >
|
||||
class AdlMIDI_SPtr
|
||||
{
|
||||
T *m_p;
|
||||
size_t *m_counter;
|
||||
public:
|
||||
explicit AdlMIDI_SPtr(T *p = NULL)
|
||||
: m_p(p), m_counter(p ? new size_t(1) : NULL) {}
|
||||
~AdlMIDI_SPtr()
|
||||
{
|
||||
reset(NULL);
|
||||
}
|
||||
|
||||
AdlMIDI_SPtr(const AdlMIDI_SPtr &other)
|
||||
: m_p(other.m_p), m_counter(other.m_counter)
|
||||
{
|
||||
if(m_counter)
|
||||
++*m_counter;
|
||||
}
|
||||
|
||||
AdlMIDI_SPtr &operator=(const AdlMIDI_SPtr &other)
|
||||
{
|
||||
if(this == &other)
|
||||
return *this;
|
||||
reset();
|
||||
m_p = other.m_p;
|
||||
m_counter = other.m_counter;
|
||||
if(m_counter)
|
||||
++*m_counter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset(T *p = NULL)
|
||||
{
|
||||
if(p != m_p) {
|
||||
if(m_p && --*m_counter == 0) {
|
||||
Deleter del;
|
||||
del(m_p);
|
||||
if(!p) {
|
||||
delete m_counter;
|
||||
m_counter = NULL;
|
||||
}
|
||||
}
|
||||
m_p = p;
|
||||
if(p) {
|
||||
if(!m_counter)
|
||||
m_counter = new size_t;
|
||||
*m_counter = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
T *get() const
|
||||
{
|
||||
return m_p;
|
||||
}
|
||||
T &operator*() const
|
||||
{
|
||||
return *m_p;
|
||||
}
|
||||
T *operator->() const
|
||||
{
|
||||
return m_p;
|
||||
}
|
||||
T &operator[](size_t index) const
|
||||
{
|
||||
return m_p[index];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Shared pointer for arrays.
|
||||
*/
|
||||
template<class T>
|
||||
class AdlMIDI_SPtrArray :
|
||||
public AdlMIDI_SPtr< T, ADLMIDI_DefaultArrayDelete<T> >
|
||||
{
|
||||
public:
|
||||
explicit AdlMIDI_SPtrArray(T *p = NULL)
|
||||
: AdlMIDI_SPtr< T, ADLMIDI_DefaultArrayDelete<T> >(p) {}
|
||||
};
|
||||
|
||||
#endif //ADLMIDI_PTR_HPP_THING
|
File diff suppressed because it is too large
Load Diff
|
@ -1,290 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2002-2018 The DOSBox Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(__GNUC__) && defined(__i386__)
|
||||
#define DB_FASTCALL __attribute__((fastcall))
|
||||
#elif defined(_MSC_VER)
|
||||
#define DB_FASTCALL __fastcall
|
||||
#else
|
||||
#define DB_FASTCALL
|
||||
#endif
|
||||
|
||||
typedef uintptr_t Bitu;
|
||||
typedef intptr_t Bits;
|
||||
typedef uint64_t Bit64u;
|
||||
typedef int64_t Bit64s;
|
||||
typedef uint32_t Bit32u;
|
||||
typedef int32_t Bit32s;
|
||||
typedef uint16_t Bit16u;
|
||||
typedef int16_t Bit16s;
|
||||
typedef uint8_t Bit8u;
|
||||
typedef int8_t Bit8s;
|
||||
|
||||
//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume
|
||||
#define WAVE_HANDLER 10
|
||||
//Use a logarithmic wavetable with an exponential table for volume
|
||||
#define WAVE_TABLELOG 11
|
||||
//Use a linear wavetable with a multiply table for volume
|
||||
#define WAVE_TABLEMUL 12
|
||||
|
||||
//Select the type of wave generator routine
|
||||
#define DBOPL_WAVE WAVE_TABLEMUL
|
||||
|
||||
namespace DBOPL {
|
||||
|
||||
struct Chip;
|
||||
struct Operator;
|
||||
struct Channel;
|
||||
|
||||
#if (DBOPL_WAVE == WAVE_HANDLER)
|
||||
typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume );
|
||||
#endif
|
||||
|
||||
typedef Bits ( DBOPL::Operator::*VolumeHandler) ( );
|
||||
typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output );
|
||||
|
||||
//Different synth modes that can generate blocks of data
|
||||
typedef enum {
|
||||
sm2AM,
|
||||
sm2FM,
|
||||
sm3AM,
|
||||
sm3FM,
|
||||
sm4Start,
|
||||
sm3FMFM,
|
||||
sm3AMFM,
|
||||
sm3FMAM,
|
||||
sm3AMAM,
|
||||
sm6Start,
|
||||
sm2Percussion,
|
||||
sm3Percussion
|
||||
} SynthMode;
|
||||
|
||||
//Shifts for the values contained in chandata variable
|
||||
enum {
|
||||
SHIFT_KSLBASE = 16,
|
||||
SHIFT_KEYCODE = 24
|
||||
};
|
||||
|
||||
struct Operator {
|
||||
public:
|
||||
//Masks for operator 20 values
|
||||
enum {
|
||||
MASK_KSR = 0x10,
|
||||
MASK_SUSTAIN = 0x20,
|
||||
MASK_VIBRATO = 0x40,
|
||||
MASK_TREMOLO = 0x80
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
OFF,
|
||||
RELEASE,
|
||||
SUSTAIN,
|
||||
DECAY,
|
||||
ATTACK
|
||||
} State;
|
||||
|
||||
VolumeHandler volHandler;
|
||||
|
||||
#if (DBOPL_WAVE == WAVE_HANDLER)
|
||||
WaveHandler waveHandler; //Routine that generate a wave
|
||||
#else
|
||||
Bit16s* waveBase;
|
||||
Bit32u waveMask;
|
||||
Bit32u waveStart;
|
||||
#endif
|
||||
Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index
|
||||
Bit32u waveAdd; //The base frequency without vibrato
|
||||
Bit32u waveCurrent; //waveAdd + vibratao
|
||||
|
||||
Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this
|
||||
Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove?
|
||||
Bit32u vibrato; //Scaled up vibrato strength
|
||||
Bit32s sustainLevel; //When stopping at sustain level stop here
|
||||
Bit32s totalLevel; //totalLevel is added to every generated volume
|
||||
Bit32u currentLevel; //totalLevel + tremolo
|
||||
Bit32s volume; //The currently active volume
|
||||
|
||||
Bit32u attackAdd; //Timers for the different states of the envelope
|
||||
Bit32u decayAdd;
|
||||
Bit32u releaseAdd;
|
||||
Bit32u rateIndex; //Current position of the evenlope
|
||||
|
||||
Bit8u rateZero; //Bits for the different states of the envelope having no changes
|
||||
Bit8u keyOn; //Bitmask of different values that can generate keyon
|
||||
//Registers, also used to check for changes
|
||||
Bit8u reg20, reg40, reg60, reg80, regE0;
|
||||
//Active part of the envelope we're in
|
||||
Bit8u state;
|
||||
//0xff when tremolo is enabled
|
||||
Bit8u tremoloMask;
|
||||
//Strength of the vibrato
|
||||
Bit8u vibStrength;
|
||||
//Keep track of the calculated KSR so we can check for changes
|
||||
Bit8u ksr;
|
||||
private:
|
||||
void SetState( Bit8u s );
|
||||
void UpdateAttack( const Chip* chip );
|
||||
void UpdateRelease( const Chip* chip );
|
||||
void UpdateDecay( const Chip* chip );
|
||||
public:
|
||||
void UpdateAttenuation();
|
||||
void UpdateRates( const Chip* chip );
|
||||
void UpdateFrequency( );
|
||||
|
||||
void Write20( const Chip* chip, Bit8u val );
|
||||
void Write40( const Chip* chip, Bit8u val );
|
||||
void Write60( const Chip* chip, Bit8u val );
|
||||
void Write80( const Chip* chip, Bit8u val );
|
||||
void WriteE0( const Chip* chip, Bit8u val );
|
||||
|
||||
bool Silent() const;
|
||||
void Prepare( const Chip* chip );
|
||||
|
||||
void KeyOn( Bit8u mask);
|
||||
void KeyOff( Bit8u mask);
|
||||
|
||||
template< State state>
|
||||
Bits TemplateVolume( );
|
||||
|
||||
Bit32s RateForward( Bit32u add );
|
||||
Bitu ForwardWave();
|
||||
Bitu ForwardVolume();
|
||||
|
||||
Bits GetSample( Bits modulation );
|
||||
Bits GetWave( Bitu index, Bitu vol );
|
||||
public:
|
||||
Operator();
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
Operator op[2];
|
||||
inline Operator* Op( Bitu index ) {
|
||||
return &( ( this + (index >> 1) )->op[ index & 1 ]);
|
||||
}
|
||||
SynthHandler synthHandler;
|
||||
Bit32u chanData; //Frequency/octave and derived values
|
||||
Bit32s old[2]; //Old data for feedback
|
||||
|
||||
Bit8u feedback; //Feedback shift
|
||||
Bit8u regB0; //Register values to check for changes
|
||||
Bit8u regC0;
|
||||
//This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel
|
||||
Bit8u fourMask;
|
||||
Bit8s maskLeft; //Sign extended values for both channel's panning
|
||||
Bit8s maskRight;
|
||||
|
||||
Bit16u panLeft; // Extended behavior, scale values for soft panning
|
||||
Bit16u panRight;
|
||||
|
||||
//Forward the channel data to the operators of the channel
|
||||
void SetChanData( const Chip* chip, Bit32u data );
|
||||
//Change in the chandata, check for new values and if we have to forward to operators
|
||||
void UpdateFrequency( const Chip* chip, Bit8u fourOp );
|
||||
void UpdateSynth(const Chip* chip);
|
||||
void WriteA0( const Chip* chip, Bit8u val );
|
||||
void WriteB0( const Chip* chip, Bit8u val );
|
||||
void WriteC0( const Chip* chip, Bit8u val );
|
||||
|
||||
void WritePan( Bit8u val );
|
||||
|
||||
//call this for the first channel
|
||||
template< bool opl3Mode >
|
||||
void GeneratePercussion( Chip* chip, Bit32s* output );
|
||||
|
||||
//Generate blocks of data in specific modes
|
||||
template<SynthMode mode>
|
||||
Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output );
|
||||
Channel();
|
||||
};
|
||||
|
||||
struct Chip {
|
||||
//This is used as the base counter for vibrato and tremolo
|
||||
Bit32u lfoCounter;
|
||||
Bit32u lfoAdd;
|
||||
|
||||
|
||||
Bit32u noiseCounter;
|
||||
Bit32u noiseAdd;
|
||||
Bit32u noiseValue;
|
||||
|
||||
//Frequency scales for the different multiplications
|
||||
const Bit32u *freqMul/*[16]*/;
|
||||
//Rates for decay and release for rate of this chip
|
||||
const Bit32u *linearRates/*[76]*/;
|
||||
//Best match attack rates for the rate of this chip
|
||||
const Bit32u *attackRates/*[76]*/;
|
||||
|
||||
//18 channels with 2 operators each
|
||||
Channel chan[18];
|
||||
|
||||
Bit8u reg104;
|
||||
Bit8u reg08;
|
||||
Bit8u reg04;
|
||||
Bit8u regBD;
|
||||
Bit8u vibratoIndex;
|
||||
Bit8u tremoloIndex;
|
||||
Bit8s vibratoSign;
|
||||
Bit8u vibratoShift;
|
||||
Bit8u tremoloValue;
|
||||
Bit8u vibratoStrength;
|
||||
Bit8u tremoloStrength;
|
||||
//Mask for allowed wave forms
|
||||
Bit8u waveFormMask;
|
||||
//0 or -1 when enabled
|
||||
Bit8s opl3Active;
|
||||
|
||||
//Return the maximum amount of samples before and LFO change
|
||||
Bit32u ForwardLFO( Bit32u samples );
|
||||
Bit32u ForwardNoise();
|
||||
|
||||
void WriteBD( Bit8u val );
|
||||
void WriteReg(Bit32u reg, Bit8u val );
|
||||
|
||||
Bit32u WriteAddr( Bit32u port, Bit8u val );
|
||||
|
||||
void GenerateBlock2( Bitu samples, Bit32s* output );
|
||||
void GenerateBlock2_Mix( Bitu samples, Bit32s* output );
|
||||
void GenerateBlock3( Bitu samples, Bit32s* output );
|
||||
void GenerateBlock3_Mix( Bitu samples, Bit32s* output );
|
||||
|
||||
//Update the synth handlers in all channels
|
||||
void UpdateSynths();
|
||||
void Generate( Bit32u samples );
|
||||
void Setup( Bit32u r );
|
||||
|
||||
Chip();
|
||||
};
|
||||
|
||||
struct Handler {
|
||||
DBOPL::Chip chip;
|
||||
void WritePan( Bit32u port, Bit8u val );
|
||||
Bit32u WriteAddr( Bit32u port, Bit8u val );
|
||||
void WriteReg( Bit32u addr, Bit8u val );
|
||||
void GenerateArr(Bit32s *out, Bitu *samples);
|
||||
void GenerateArr(Bit16s *out, Bitu *samples);
|
||||
void GenerateArrMix(Bit32s *out, Bitu *samples);
|
||||
void GenerateArrMix(Bit16s *out, Bitu *samples);
|
||||
void Init( Bitu rate );
|
||||
};
|
||||
|
||||
|
||||
} //Namespace
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
|
||||
*
|
||||
* Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "dosbox_opl3.h"
|
||||
#include "dosbox/dbopl.h"
|
||||
#include <new>
|
||||
#include <cstdlib>
|
||||
#include <assert.h>
|
||||
|
||||
DosBoxOPL3::DosBoxOPL3() :
|
||||
OPLChipBaseBufferedT(),
|
||||
m_chip(new DBOPL::Handler)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
DosBoxOPL3::~DosBoxOPL3()
|
||||
{
|
||||
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
|
||||
delete chip_r;
|
||||
}
|
||||
|
||||
void DosBoxOPL3::setRate(uint32_t rate)
|
||||
{
|
||||
OPLChipBaseBufferedT::setRate(rate);
|
||||
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
|
||||
chip_r->~Handler();
|
||||
new(chip_r) DBOPL::Handler;
|
||||
chip_r->Init(effectiveRate());
|
||||
}
|
||||
|
||||
void DosBoxOPL3::reset()
|
||||
{
|
||||
OPLChipBaseBufferedT::reset();
|
||||
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
|
||||
chip_r->~Handler();
|
||||
new(chip_r) DBOPL::Handler;
|
||||
chip_r->Init(effectiveRate());
|
||||
}
|
||||
|
||||
void DosBoxOPL3::writeReg(uint16_t addr, uint8_t data)
|
||||
{
|
||||
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
|
||||
chip_r->WriteReg(static_cast<Bit32u>(addr), data);
|
||||
}
|
||||
|
||||
void DosBoxOPL3::writePan(uint16_t addr, uint8_t data)
|
||||
{
|
||||
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
|
||||
chip_r->WritePan(static_cast<Bit32u>(addr), data);
|
||||
}
|
||||
|
||||
void DosBoxOPL3::nativeGenerateN(int16_t *output, size_t frames)
|
||||
{
|
||||
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
|
||||
Bitu frames_i = frames;
|
||||
chip_r->GenerateArr(output, &frames_i);
|
||||
}
|
||||
|
||||
const char *DosBoxOPL3::emulatorName()
|
||||
{
|
||||
return "DOSBox 0.74-r4111 OPL3";
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
|
||||
*
|
||||
* Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef DOSBOX_OPL3_H
|
||||
#define DOSBOX_OPL3_H
|
||||
|
||||
#include "opl_chip_base.h"
|
||||
|
||||
class DosBoxOPL3 final : public OPLChipBaseBufferedT<DosBoxOPL3>
|
||||
{
|
||||
void *m_chip;
|
||||
public:
|
||||
DosBoxOPL3();
|
||||
~DosBoxOPL3() override;
|
||||
|
||||
bool canRunAtPcmRate() const override { return true; }
|
||||
void setRate(uint32_t rate) override;
|
||||
void reset() override;
|
||||
void writeReg(uint16_t addr, uint8_t data) override;
|
||||
void writePan(uint16_t addr, uint8_t data) override;
|
||||
void nativePreGenerate() override {}
|
||||
void nativePostGenerate() override {}
|
||||
void nativeGenerateN(int16_t *output, size_t frames) override;
|
||||
const char *emulatorName() override;
|
||||
};
|
||||
|
||||
#endif // DOSBOX_OPL3_H
|
File diff suppressed because it is too large
Load Diff
|
@ -1,165 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2018 Alexey Khokholov (Nuke.YKT)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Nuked OPL3 emulator.
|
||||
* Thanks:
|
||||
* MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh):
|
||||
* Feedback and Rhythm part calculation information.
|
||||
* forums.submarine.org.uk(carbon14, opl3):
|
||||
* Tremolo and phase generator calculation information.
|
||||
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
|
||||
* OPL2 ROMs.
|
||||
* siliconpr0n.org(John McMaster, digshadow):
|
||||
* YMF262 and VRC VII decaps and die shots.
|
||||
*
|
||||
* version: 1.8
|
||||
*/
|
||||
|
||||
#ifndef OPL_OPL3_H
|
||||
#define OPL_OPL3_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define OPL_WRITEBUF_SIZE 1024
|
||||
#define OPL_WRITEBUF_DELAY 2
|
||||
|
||||
typedef uintptr_t Bitu;
|
||||
typedef intptr_t Bits;
|
||||
typedef uint64_t Bit64u;
|
||||
typedef int64_t Bit64s;
|
||||
typedef uint32_t Bit32u;
|
||||
typedef int32_t Bit32s;
|
||||
typedef uint16_t Bit16u;
|
||||
typedef int16_t Bit16s;
|
||||
typedef uint8_t Bit8u;
|
||||
typedef int8_t Bit8s;
|
||||
|
||||
typedef struct _opl3_slot opl3_slot;
|
||||
typedef struct _opl3_channel opl3_channel;
|
||||
typedef struct _opl3_chip opl3_chip;
|
||||
|
||||
struct _opl3_slot {
|
||||
opl3_channel *channel;
|
||||
opl3_chip *chip;
|
||||
Bit16s out;
|
||||
Bit16s fbmod;
|
||||
Bit16s *mod;
|
||||
Bit16s prout;
|
||||
Bit16s eg_rout;
|
||||
Bit16s eg_out;
|
||||
Bit8u eg_inc;
|
||||
Bit8u eg_gen;
|
||||
Bit8u eg_rate;
|
||||
Bit8u eg_ksl;
|
||||
Bit8u *trem;
|
||||
Bit8u reg_vib;
|
||||
Bit8u reg_type;
|
||||
Bit8u reg_ksr;
|
||||
Bit8u reg_mult;
|
||||
Bit8u reg_ksl;
|
||||
Bit8u reg_tl;
|
||||
Bit8u reg_ar;
|
||||
Bit8u reg_dr;
|
||||
Bit8u reg_sl;
|
||||
Bit8u reg_rr;
|
||||
Bit8u reg_wf;
|
||||
Bit8u key;
|
||||
Bit32u pg_reset;
|
||||
Bit32u pg_phase;
|
||||
Bit16u pg_phase_out;
|
||||
Bit8u slot_num;
|
||||
};
|
||||
|
||||
struct _opl3_channel {
|
||||
opl3_slot *slotz[2];/*Don't use "slots" keyword to avoid conflict with Qt applications*/
|
||||
opl3_channel *pair;
|
||||
opl3_chip *chip;
|
||||
Bit16s *out[4];
|
||||
Bit8u chtype;
|
||||
Bit16u f_num;
|
||||
Bit8u block;
|
||||
Bit8u fb;
|
||||
Bit8u con;
|
||||
Bit8u alg;
|
||||
Bit8u ksv;
|
||||
Bit16u cha, chb;
|
||||
Bit16u chl, chr;
|
||||
Bit8u ch_num;
|
||||
};
|
||||
|
||||
typedef struct _opl3_writebuf {
|
||||
Bit64u time;
|
||||
Bit16u reg;
|
||||
Bit8u data;
|
||||
} opl3_writebuf;
|
||||
|
||||
struct _opl3_chip {
|
||||
opl3_channel channel[18];
|
||||
opl3_slot slot[36];
|
||||
Bit16u timer;
|
||||
Bit64u eg_timer;
|
||||
Bit8u eg_timerrem;
|
||||
Bit8u eg_state;
|
||||
Bit8u eg_add;
|
||||
Bit8u newm;
|
||||
Bit8u nts;
|
||||
Bit8u rhy;
|
||||
Bit8u vibpos;
|
||||
Bit8u vibshift;
|
||||
Bit8u tremolo;
|
||||
Bit8u tremolopos;
|
||||
Bit8u tremoloshift;
|
||||
Bit32u noise;
|
||||
Bit16s zeromod;
|
||||
Bit32s mixbuff[2];
|
||||
Bit8u rm_hh_bit2;
|
||||
Bit8u rm_hh_bit3;
|
||||
Bit8u rm_hh_bit7;
|
||||
Bit8u rm_hh_bit8;
|
||||
Bit8u rm_tc_bit3;
|
||||
Bit8u rm_tc_bit5;
|
||||
/* OPL3L */
|
||||
Bit32s rateratio;
|
||||
Bit32s samplecnt;
|
||||
Bit16s oldsamples[2];
|
||||
Bit16s samples[2];
|
||||
|
||||
Bit64u writebuf_samplecnt;
|
||||
Bit32u writebuf_cur;
|
||||
Bit32u writebuf_last;
|
||||
Bit64u writebuf_lasttime;
|
||||
opl3_writebuf writebuf[OPL_WRITEBUF_SIZE];
|
||||
};
|
||||
|
||||
void OPL3_Generate(opl3_chip *chip, Bit16s *buf);
|
||||
void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf);
|
||||
void OPL3_Reset(opl3_chip *chip, Bit32u samplerate);
|
||||
void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v);
|
||||
void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v);
|
||||
void OPL3_WritePan(opl3_chip *chip, Bit16u reg, Bit8u v);
|
||||
void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples);
|
||||
void OPL3_GenerateStreamMix(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,156 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2016 Alexey Khokholov (Nuke.YKT)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Nuked OPL3 emulator.
|
||||
* Thanks:
|
||||
* MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh):
|
||||
* Feedback and Rhythm part calculation information.
|
||||
* forums.submarine.org.uk(carbon14, opl3):
|
||||
* Tremolo and phase generator calculation information.
|
||||
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
|
||||
* OPL2 ROMs.
|
||||
*
|
||||
* version: 1.7.4
|
||||
*/
|
||||
|
||||
#ifndef OPL_OPL3_H
|
||||
#define OPL_OPL3_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define OPL_WRITEBUF_SIZE 1024
|
||||
#define OPL_WRITEBUF_DELAY 2
|
||||
|
||||
typedef uintptr_t Bitu;
|
||||
typedef intptr_t Bits;
|
||||
typedef uint64_t Bit64u;
|
||||
typedef int64_t Bit64s;
|
||||
typedef uint32_t Bit32u;
|
||||
typedef int32_t Bit32s;
|
||||
typedef uint16_t Bit16u;
|
||||
typedef int16_t Bit16s;
|
||||
typedef uint8_t Bit8u;
|
||||
typedef int8_t Bit8s;
|
||||
|
||||
typedef struct _opl3_slot opl3_slot;
|
||||
typedef struct _opl3_channel opl3_channel;
|
||||
typedef struct _opl3_chip opl3_chip;
|
||||
|
||||
struct _opl3_slot {
|
||||
opl3_channel *channel;
|
||||
opl3_chip *chip;
|
||||
Bit16s out;
|
||||
Bit16s fbmod;
|
||||
Bit16s *mod;
|
||||
Bit16s prout;
|
||||
Bit16s eg_rout;
|
||||
Bit16s eg_out;
|
||||
Bit8u eg_inc;
|
||||
Bit8u eg_gen;
|
||||
Bit8u eg_rate;
|
||||
Bit8u eg_ksl;
|
||||
Bit8u *trem;
|
||||
Bit8u reg_vib;
|
||||
Bit8u reg_type;
|
||||
Bit8u reg_ksr;
|
||||
Bit8u reg_mult;
|
||||
Bit8u reg_ksl;
|
||||
Bit8u reg_tl;
|
||||
Bit8u reg_ar;
|
||||
Bit8u reg_dr;
|
||||
Bit8u reg_sl;
|
||||
Bit8u reg_rr;
|
||||
Bit8u reg_wf;
|
||||
Bit8u key;
|
||||
Bit32u pg_phase;
|
||||
Bit32u timer;
|
||||
|
||||
Bit16u maskzero;
|
||||
Bit8u signpos;
|
||||
Bit8u phaseshift;
|
||||
};
|
||||
|
||||
struct _opl3_channel {
|
||||
opl3_slot *slotz[2];/*Don't use "slots" keyword to avoid conflict with Qt applications*/
|
||||
opl3_channel *pair;
|
||||
opl3_chip *chip;
|
||||
Bit16s *out[4];
|
||||
Bit8u chtype;
|
||||
Bit16u f_num;
|
||||
Bit8u block;
|
||||
Bit8u fb;
|
||||
Bit8u con;
|
||||
Bit8u alg;
|
||||
Bit8u ksv;
|
||||
Bit16u cha, chb;
|
||||
Bit16u chl, chr;
|
||||
};
|
||||
|
||||
typedef struct _opl3_writebuf {
|
||||
Bit64u time;
|
||||
Bit16u reg;
|
||||
Bit8u data;
|
||||
} opl3_writebuf;
|
||||
|
||||
struct _opl3_chip {
|
||||
opl3_channel channel[18];
|
||||
opl3_slot chipslot[36];
|
||||
Bit16u timer;
|
||||
Bit8u newm;
|
||||
Bit8u nts;
|
||||
Bit8u rhy;
|
||||
Bit8u vibpos;
|
||||
Bit8u vibshift;
|
||||
Bit8u tremolo;
|
||||
Bit8u tremolopos;
|
||||
Bit8u tremoloshift;
|
||||
Bit32u noise;
|
||||
Bit16s zeromod;
|
||||
Bit32s mixbuff[2];
|
||||
/* OPL3L */
|
||||
Bit32s rateratio;
|
||||
Bit32s samplecnt;
|
||||
Bit16s oldsamples[2];
|
||||
Bit16s samples[2];
|
||||
|
||||
Bit64u writebuf_samplecnt;
|
||||
Bit32u writebuf_cur;
|
||||
Bit32u writebuf_last;
|
||||
Bit64u writebuf_lasttime;
|
||||
opl3_writebuf writebuf[OPL_WRITEBUF_SIZE];
|
||||
};
|
||||
|
||||
void OPL3v17_Generate(opl3_chip *chip, Bit16s *buf);
|
||||
void OPL3v17_GenerateResampled(opl3_chip *chip, Bit16s *buf);
|
||||
void OPL3v17_Reset(opl3_chip *chip, Bit32u samplerate);
|
||||
void OPL3v17_WritePan(opl3_chip *chip, Bit16u reg, Bit8u v);
|
||||
void OPL3v17_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v);
|
||||
void OPL3v17_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v);
|
||||
void OPL3v17_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples);
|
||||
void OPL3v17_GenerateStreamMix(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
|
||||
*
|
||||
* Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "nuked_opl3.h"
|
||||
#include "nuked/nukedopl3.h"
|
||||
#include <cstring>
|
||||
|
||||
NukedOPL3::NukedOPL3() :
|
||||
OPLChipBaseT()
|
||||
{
|
||||
m_chip = new opl3_chip;
|
||||
setRate(m_rate);
|
||||
}
|
||||
|
||||
NukedOPL3::~NukedOPL3()
|
||||
{
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
delete chip_r;
|
||||
}
|
||||
|
||||
void NukedOPL3::setRate(uint32_t rate)
|
||||
{
|
||||
OPLChipBaseT::setRate(rate);
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
std::memset(chip_r, 0, sizeof(opl3_chip));
|
||||
OPL3_Reset(chip_r, rate);
|
||||
}
|
||||
|
||||
void NukedOPL3::reset()
|
||||
{
|
||||
OPLChipBaseT::reset();
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
std::memset(chip_r, 0, sizeof(opl3_chip));
|
||||
OPL3_Reset(chip_r, m_rate);
|
||||
}
|
||||
|
||||
void NukedOPL3::writeReg(uint16_t addr, uint8_t data)
|
||||
{
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
OPL3_WriteRegBuffered(chip_r, addr, data);
|
||||
}
|
||||
|
||||
void NukedOPL3::writePan(uint16_t addr, uint8_t data)
|
||||
{
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
OPL3_WritePan(chip_r, addr, data);
|
||||
}
|
||||
|
||||
void NukedOPL3::nativeGenerate(int16_t *frame)
|
||||
{
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
OPL3_Generate(chip_r, frame);
|
||||
}
|
||||
|
||||
const char *NukedOPL3::emulatorName()
|
||||
{
|
||||
return "Nuked OPL3 (v 1.8)";
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
|
||||
*
|
||||
* Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef NUKED_OPL3_H
|
||||
#define NUKED_OPL3_H
|
||||
|
||||
#include "opl_chip_base.h"
|
||||
|
||||
class NukedOPL3 final : public OPLChipBaseT<NukedOPL3>
|
||||
{
|
||||
void *m_chip;
|
||||
public:
|
||||
NukedOPL3();
|
||||
~NukedOPL3() override;
|
||||
|
||||
bool canRunAtPcmRate() const override { return false; }
|
||||
void setRate(uint32_t rate) override;
|
||||
void reset() override;
|
||||
void writeReg(uint16_t addr, uint8_t data) override;
|
||||
void writePan(uint16_t addr, uint8_t data) override;
|
||||
void nativePreGenerate() override {}
|
||||
void nativePostGenerate() override {}
|
||||
void nativeGenerate(int16_t *frame) override;
|
||||
const char *emulatorName() override;
|
||||
};
|
||||
|
||||
#endif // NUKED_OPL3_H
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
|
||||
*
|
||||
* Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "nuked_opl3_v174.h"
|
||||
#include "nuked/nukedopl3_174.h"
|
||||
#include <cstring>
|
||||
|
||||
NukedOPL3v174::NukedOPL3v174() :
|
||||
OPLChipBaseT()
|
||||
{
|
||||
m_chip = new opl3_chip;
|
||||
setRate(m_rate);
|
||||
}
|
||||
|
||||
NukedOPL3v174::~NukedOPL3v174()
|
||||
{
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
delete chip_r;
|
||||
}
|
||||
|
||||
void NukedOPL3v174::setRate(uint32_t rate)
|
||||
{
|
||||
OPLChipBaseT::setRate(rate);
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
std::memset(chip_r, 0, sizeof(opl3_chip));
|
||||
OPL3v17_Reset(chip_r, rate);
|
||||
}
|
||||
|
||||
void NukedOPL3v174::reset()
|
||||
{
|
||||
OPLChipBaseT::reset();
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
std::memset(chip_r, 0, sizeof(opl3_chip));
|
||||
OPL3v17_Reset(chip_r, m_rate);
|
||||
}
|
||||
|
||||
void NukedOPL3v174::writeReg(uint16_t addr, uint8_t data)
|
||||
{
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
OPL3v17_WriteReg(chip_r, addr, data);
|
||||
}
|
||||
|
||||
void NukedOPL3v174::writePan(uint16_t addr, uint8_t data)
|
||||
{
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
OPL3v17_WritePan(chip_r, addr, data);
|
||||
}
|
||||
|
||||
void NukedOPL3v174::nativeGenerate(int16_t *frame)
|
||||
{
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
OPL3v17_Generate(chip_r, frame);
|
||||
}
|
||||
|
||||
const char *NukedOPL3v174::emulatorName()
|
||||
{
|
||||
return "Nuked OPL3 (v 1.7.4)";
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
|
||||
*
|
||||
* Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef NUKED_OPL3174_H
|
||||
#define NUKED_OPL3174_H
|
||||
|
||||
#include "opl_chip_base.h"
|
||||
|
||||
class NukedOPL3v174 final : public OPLChipBaseT<NukedOPL3v174>
|
||||
{
|
||||
void *m_chip;
|
||||
public:
|
||||
NukedOPL3v174();
|
||||
~NukedOPL3v174() override;
|
||||
|
||||
bool canRunAtPcmRate() const override { return false; }
|
||||
void setRate(uint32_t rate) override;
|
||||
void reset() override;
|
||||
void writeReg(uint16_t addr, uint8_t data) override;
|
||||
void writePan(uint16_t addr, uint8_t data) override;
|
||||
void nativePreGenerate() override {}
|
||||
void nativePostGenerate() override {}
|
||||
void nativeGenerate(int16_t *frame) override;
|
||||
const char *emulatorName() override;
|
||||
};
|
||||
|
||||
#endif // NUKED_OPL3174_H
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ONP_CHIP_BASE_H
|
||||
#define ONP_CHIP_BASE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if !defined(_MSC_VER) && (__cplusplus <= 199711L)
|
||||
#define final
|
||||
#define override
|
||||
#endif
|
||||
|
||||
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
|
||||
class VResampler;
|
||||
#endif
|
||||
|
||||
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
|
||||
extern void adl_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate);
|
||||
#endif
|
||||
|
||||
class OPLChipBase
|
||||
{
|
||||
public:
|
||||
enum { nativeRate = 49716 };
|
||||
protected:
|
||||
uint32_t m_id;
|
||||
uint32_t m_rate;
|
||||
public:
|
||||
OPLChipBase();
|
||||
virtual ~OPLChipBase();
|
||||
|
||||
uint32_t chipId() const { return m_id; }
|
||||
void setChipId(uint32_t id) { m_id = id; }
|
||||
|
||||
virtual bool canRunAtPcmRate() const = 0;
|
||||
virtual bool isRunningAtPcmRate() const = 0;
|
||||
virtual bool setRunningAtPcmRate(bool r) = 0;
|
||||
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
|
||||
virtual void setAudioTickHandlerInstance(void *instance) = 0;
|
||||
#endif
|
||||
|
||||
virtual void setRate(uint32_t rate) = 0;
|
||||
virtual uint32_t effectiveRate() const = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual void writeReg(uint16_t addr, uint8_t data) = 0;
|
||||
|
||||
// extended
|
||||
virtual void writePan(uint16_t addr, uint8_t data) { (void)addr; (void)data; }
|
||||
|
||||
virtual void nativePreGenerate() = 0;
|
||||
virtual void nativePostGenerate() = 0;
|
||||
virtual void nativeGenerate(int16_t *frame) = 0;
|
||||
|
||||
virtual void generate(int16_t *output, size_t frames) = 0;
|
||||
virtual void generateAndMix(int16_t *output, size_t frames) = 0;
|
||||
virtual void generate32(int32_t *output, size_t frames) = 0;
|
||||
virtual void generateAndMix32(int32_t *output, size_t frames) = 0;
|
||||
|
||||
virtual const char* emulatorName() = 0;
|
||||
private:
|
||||
OPLChipBase(const OPLChipBase &c);
|
||||
OPLChipBase &operator=(const OPLChipBase &c);
|
||||
};
|
||||
|
||||
// A base class providing F-bounded generic and efficient implementations,
|
||||
// supporting resampling of chip outputs
|
||||
template <class T>
|
||||
class OPLChipBaseT : public OPLChipBase
|
||||
{
|
||||
public:
|
||||
OPLChipBaseT();
|
||||
virtual ~OPLChipBaseT();
|
||||
|
||||
bool isRunningAtPcmRate() const override;
|
||||
bool setRunningAtPcmRate(bool r) override;
|
||||
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
|
||||
void setAudioTickHandlerInstance(void *instance);
|
||||
#endif
|
||||
|
||||
virtual void setRate(uint32_t rate) override;
|
||||
uint32_t effectiveRate() const override;
|
||||
virtual void reset() override;
|
||||
void generate(int16_t *output, size_t frames) override;
|
||||
void generateAndMix(int16_t *output, size_t frames) override;
|
||||
void generate32(int32_t *output, size_t frames) override;
|
||||
void generateAndMix32(int32_t *output, size_t frames) override;
|
||||
private:
|
||||
bool m_runningAtPcmRate;
|
||||
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
|
||||
void *m_audioTickHandlerInstance;
|
||||
#endif
|
||||
void nativeTick(int16_t *frame);
|
||||
void setupResampler(uint32_t rate);
|
||||
void resetResampler();
|
||||
void resampledGenerate(int32_t *output);
|
||||
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
|
||||
VResampler *m_resampler;
|
||||
#else
|
||||
int32_t m_oldsamples[2];
|
||||
int32_t m_samples[2];
|
||||
int32_t m_samplecnt;
|
||||
int32_t m_rateratio;
|
||||
enum { rsm_frac = 10 };
|
||||
#endif
|
||||
// amplitude scale factors in and out of resampler, varying for chips;
|
||||
// values are OK to "redefine", the static polymorphism will accept it.
|
||||
enum { resamplerPreAmplify = 1, resamplerPostAttenuate = 1 };
|
||||
};
|
||||
|
||||
// A base class which provides frame-by-frame interfaces on emulations which
|
||||
// don't have a routine for it. It produces outputs in fixed size buffers.
|
||||
// Fast register updates will suffer some latency because of buffering.
|
||||
template <class T, unsigned Buffer = 256>
|
||||
class OPLChipBaseBufferedT : public OPLChipBaseT<T>
|
||||
{
|
||||
public:
|
||||
OPLChipBaseBufferedT()
|
||||
: OPLChipBaseT<T>(), m_bufferIndex(0) {}
|
||||
virtual ~OPLChipBaseBufferedT()
|
||||
{}
|
||||
public:
|
||||
void reset() override;
|
||||
void nativeGenerate(int16_t *frame) override;
|
||||
protected:
|
||||
virtual void nativeGenerateN(int16_t *output, size_t frames) = 0;
|
||||
private:
|
||||
unsigned m_bufferIndex;
|
||||
int16_t m_buffer[2 * Buffer];
|
||||
};
|
||||
|
||||
#include "opl_chip_base.tcc"
|
||||
|
||||
#endif // ONP_CHIP_BASE_H
|
|
@ -1,294 +0,0 @@
|
|||
#include "opl_chip_base.h"
|
||||
#include <cmath>
|
||||
|
||||
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
|
||||
#include <zita-resampler/vresampler.h>
|
||||
#endif
|
||||
|
||||
#if !defined(LIKELY) && defined(__GNUC__)
|
||||
#define LIKELY(x) __builtin_expect((x), 1)
|
||||
#elif !defined(LIKELY)
|
||||
#define LIKELY(x) (x)
|
||||
#endif
|
||||
|
||||
#if !defined(UNLIKELY) && defined(__GNUC__)
|
||||
#define UNLIKELY(x) __builtin_expect((x), 0)
|
||||
#elif !defined(UNLIKELY)
|
||||
#define UNLIKELY(x) (x)
|
||||
#endif
|
||||
|
||||
/* OPLChipBase */
|
||||
|
||||
inline OPLChipBase::OPLChipBase() :
|
||||
m_id(0),
|
||||
m_rate(44100)
|
||||
{
|
||||
}
|
||||
|
||||
inline OPLChipBase::~OPLChipBase()
|
||||
{
|
||||
}
|
||||
|
||||
/* OPLChipBaseT */
|
||||
|
||||
template <class T>
|
||||
OPLChipBaseT<T>::OPLChipBaseT()
|
||||
: OPLChipBase(),
|
||||
m_runningAtPcmRate(false)
|
||||
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
|
||||
,
|
||||
m_audioTickHandlerInstance(NULL)
|
||||
#endif
|
||||
{
|
||||
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
|
||||
m_resampler = new VResampler;
|
||||
#endif
|
||||
setupResampler(m_rate);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
OPLChipBaseT<T>::~OPLChipBaseT()
|
||||
{
|
||||
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
|
||||
delete m_resampler;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool OPLChipBaseT<T>::isRunningAtPcmRate() const
|
||||
{
|
||||
return m_runningAtPcmRate;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool OPLChipBaseT<T>::setRunningAtPcmRate(bool r)
|
||||
{
|
||||
if(r != m_runningAtPcmRate)
|
||||
{
|
||||
if(r && !static_cast<T *>(this)->canRunAtPcmRate())
|
||||
return false;
|
||||
m_runningAtPcmRate = r;
|
||||
static_cast<T *>(this)->setRate(m_rate);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::setAudioTickHandlerInstance(void *instance)
|
||||
{
|
||||
m_audioTickHandlerInstance = instance;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::setRate(uint32_t rate)
|
||||
{
|
||||
uint32_t oldRate = m_rate;
|
||||
m_rate = rate;
|
||||
if(rate != oldRate)
|
||||
setupResampler(rate);
|
||||
else
|
||||
resetResampler();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
uint32_t OPLChipBaseT<T>::effectiveRate() const
|
||||
{
|
||||
return m_runningAtPcmRate ? m_rate : (uint32_t)nativeRate;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::reset()
|
||||
{
|
||||
resetResampler();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::generate(int16_t *output, size_t frames)
|
||||
{
|
||||
static_cast<T *>(this)->nativePreGenerate();
|
||||
for(size_t i = 0; i < frames; ++i)
|
||||
{
|
||||
int32_t frame[2];
|
||||
static_cast<T *>(this)->resampledGenerate(frame);
|
||||
for (unsigned c = 0; c < 2; ++c) {
|
||||
int32_t temp = frame[c];
|
||||
temp = (temp > -32768) ? temp : -32768;
|
||||
temp = (temp < 32767) ? temp : 32767;
|
||||
output[c] = (int16_t)temp;
|
||||
}
|
||||
output += 2;
|
||||
}
|
||||
static_cast<T *>(this)->nativePostGenerate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::generateAndMix(int16_t *output, size_t frames)
|
||||
{
|
||||
static_cast<T *>(this)->nativePreGenerate();
|
||||
for(size_t i = 0; i < frames; ++i)
|
||||
{
|
||||
int32_t frame[2];
|
||||
static_cast<T *>(this)->resampledGenerate(frame);
|
||||
for (unsigned c = 0; c < 2; ++c) {
|
||||
int32_t temp = (int32_t)output[c] + frame[c];
|
||||
temp = (temp > -32768) ? temp : -32768;
|
||||
temp = (temp < 32767) ? temp : 32767;
|
||||
output[c] = (int16_t)temp;
|
||||
}
|
||||
output += 2;
|
||||
}
|
||||
static_cast<T *>(this)->nativePostGenerate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::generate32(int32_t *output, size_t frames)
|
||||
{
|
||||
static_cast<T *>(this)->nativePreGenerate();
|
||||
for(size_t i = 0; i < frames; ++i)
|
||||
{
|
||||
static_cast<T *>(this)->resampledGenerate(output);
|
||||
output += 2;
|
||||
}
|
||||
static_cast<T *>(this)->nativePostGenerate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::generateAndMix32(int32_t *output, size_t frames)
|
||||
{
|
||||
static_cast<T *>(this)->nativePreGenerate();
|
||||
for(size_t i = 0; i < frames; ++i)
|
||||
{
|
||||
int32_t frame[2];
|
||||
static_cast<T *>(this)->resampledGenerate(frame);
|
||||
output[0] += frame[0];
|
||||
output[1] += frame[1];
|
||||
output += 2;
|
||||
}
|
||||
static_cast<T *>(this)->nativePostGenerate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::nativeTick(int16_t *frame)
|
||||
{
|
||||
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
|
||||
adl_audioTickHandler(m_audioTickHandlerInstance, m_id, effectiveRate());
|
||||
#endif
|
||||
static_cast<T *>(this)->nativeGenerate(frame);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::setupResampler(uint32_t rate)
|
||||
{
|
||||
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
|
||||
m_resampler->setup(rate * (1.0 / 49716), 2, 48);
|
||||
#else
|
||||
m_oldsamples[0] = m_oldsamples[1] = 0;
|
||||
m_samples[0] = m_samples[1] = 0;
|
||||
m_samplecnt = 0;
|
||||
m_rateratio = (int32_t)((rate << rsm_frac) / 49716);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::resetResampler()
|
||||
{
|
||||
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
|
||||
m_resampler->reset();
|
||||
#else
|
||||
m_oldsamples[0] = m_oldsamples[1] = 0;
|
||||
m_samples[0] = m_samples[1] = 0;
|
||||
m_samplecnt = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::resampledGenerate(int32_t *output)
|
||||
{
|
||||
if(UNLIKELY(m_runningAtPcmRate))
|
||||
{
|
||||
int16_t in[2];
|
||||
static_cast<T *>(this)->nativeTick(in);
|
||||
output[0] = (int32_t)in[0] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
|
||||
output[1] = (int32_t)in[1] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
|
||||
return;
|
||||
}
|
||||
|
||||
VResampler *rsm = m_resampler;
|
||||
float scale = (float)T::resamplerPreAmplify /
|
||||
(float)T::resamplerPostAttenuate;
|
||||
float f_in[2];
|
||||
float f_out[2];
|
||||
rsm->inp_count = 0;
|
||||
rsm->inp_data = f_in;
|
||||
rsm->out_count = 1;
|
||||
rsm->out_data = f_out;
|
||||
while(rsm->process(), rsm->out_count != 0)
|
||||
{
|
||||
int16_t in[2];
|
||||
static_cast<T *>(this)->nativeTick(in);
|
||||
f_in[0] = scale * (float)in[0];
|
||||
f_in[1] = scale * (float)in[1];
|
||||
rsm->inp_count = 1;
|
||||
rsm->inp_data = f_in;
|
||||
rsm->out_count = 1;
|
||||
rsm->out_data = f_out;
|
||||
}
|
||||
output[0] = static_cast<int32_t>(std::lround(f_out[0]));
|
||||
output[1] = static_cast<int32_t>(std::lround(f_out[1]));
|
||||
}
|
||||
#else
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::resampledGenerate(int32_t *output)
|
||||
{
|
||||
if(UNLIKELY(m_runningAtPcmRate))
|
||||
{
|
||||
int16_t in[2];
|
||||
static_cast<T *>(this)->nativeTick(in);
|
||||
output[0] = (int32_t)in[0] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
|
||||
output[1] = (int32_t)in[1] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t samplecnt = m_samplecnt;
|
||||
const int32_t rateratio = m_rateratio;
|
||||
while(samplecnt >= rateratio)
|
||||
{
|
||||
m_oldsamples[0] = m_samples[0];
|
||||
m_oldsamples[1] = m_samples[1];
|
||||
int16_t buffer[2];
|
||||
static_cast<T *>(this)->nativeTick(buffer);
|
||||
m_samples[0] = buffer[0] * T::resamplerPreAmplify;
|
||||
m_samples[1] = buffer[1] * T::resamplerPreAmplify;
|
||||
samplecnt -= rateratio;
|
||||
}
|
||||
output[0] = (int32_t)(((m_oldsamples[0] * (rateratio - samplecnt)
|
||||
+ m_samples[0] * samplecnt) / rateratio)/T::resamplerPostAttenuate);
|
||||
output[1] = (int32_t)(((m_oldsamples[1] * (rateratio - samplecnt)
|
||||
+ m_samples[1] * samplecnt) / rateratio)/T::resamplerPostAttenuate);
|
||||
m_samplecnt = samplecnt + (1 << rsm_frac);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* OPLChipBaseBufferedT */
|
||||
|
||||
template <class T, unsigned Buffer>
|
||||
void OPLChipBaseBufferedT<T, Buffer>::reset()
|
||||
{
|
||||
OPLChipBaseT<T>::reset();
|
||||
m_bufferIndex = 0;
|
||||
}
|
||||
|
||||
template <class T, unsigned Buffer>
|
||||
void OPLChipBaseBufferedT<T, Buffer>::nativeGenerate(int16_t *frame)
|
||||
{
|
||||
unsigned bufferIndex = m_bufferIndex;
|
||||
if(bufferIndex == 0)
|
||||
static_cast<T *>(this)->nativeGenerateN(m_buffer, Buffer);
|
||||
frame[0] = m_buffer[2 * bufferIndex];
|
||||
frame[1] = m_buffer[2 * bufferIndex + 1];
|
||||
bufferIndex = (bufferIndex + 1 < Buffer) ? (bufferIndex + 1) : 0;
|
||||
m_bufferIndex = bufferIndex;
|
||||
}
|
|
@ -1,300 +0,0 @@
|
|||
/*
|
||||
* FileAndMemoryReader - a tiny helper to utify file reading from a disk and memory block
|
||||
*
|
||||
* Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef FILE_AND_MEM_READER_HHHH
|
||||
#define FILE_AND_MEM_READER_HHHH
|
||||
|
||||
#include <string> // std::string
|
||||
#include <cstdio> // std::fopen, std::fread, std::fseek, std::ftell, std::fclose, std::feof
|
||||
#include <stdint.h> // uint*_t
|
||||
#include <stddef.h> // size_t and friends
|
||||
#ifdef _WIN32
|
||||
#define NOMINMAX 1
|
||||
#include <cstring> // std::strlen
|
||||
#include <windows.h> // MultiByteToWideChar
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief A little class gives able to read filedata from disk and also from a memory segment
|
||||
*/
|
||||
class FileAndMemReader
|
||||
{
|
||||
//! Currently loaded filename (empty for a memory blocks)
|
||||
std::string m_file_name;
|
||||
//! File reader descriptor
|
||||
std::FILE *m_fp;
|
||||
|
||||
//! Memory pointer descriptor
|
||||
const void *m_mp;
|
||||
//! Size of memory block
|
||||
size_t m_mp_size;
|
||||
//! Cursor position in the memory block
|
||||
size_t m_mp_tell;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Relation direction
|
||||
*/
|
||||
enum relTo
|
||||
{
|
||||
//! At begin position
|
||||
SET = SEEK_SET,
|
||||
//! At current position
|
||||
CUR = SEEK_CUR,
|
||||
//! At end position
|
||||
END = SEEK_END
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief C.O.: It's a constructor!
|
||||
*/
|
||||
FileAndMemReader() :
|
||||
m_fp(NULL),
|
||||
m_mp(NULL),
|
||||
m_mp_size(0),
|
||||
m_mp_tell(0)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief C.O.: It's a destructor!
|
||||
*/
|
||||
~FileAndMemReader()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Open file from a disk
|
||||
* @param path Path to the file in UTF-8 (even on Windows!)
|
||||
*/
|
||||
void openFile(const char *path)
|
||||
{
|
||||
if(m_fp)
|
||||
this->close();//Close previously opened file first!
|
||||
#if !defined(_WIN32) || defined(__WATCOMC__)
|
||||
m_fp = std::fopen(path, "rb");
|
||||
#else
|
||||
wchar_t widePath[MAX_PATH];
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, path, static_cast<int>(std::strlen(path)), widePath, MAX_PATH);
|
||||
widePath[size] = '\0';
|
||||
m_fp = _wfopen(widePath, L"rb");
|
||||
#endif
|
||||
m_file_name = path;
|
||||
m_mp = NULL;
|
||||
m_mp_size = 0;
|
||||
m_mp_tell = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Open file from memory block
|
||||
* @param mem Pointer to the memory block
|
||||
* @param lenght Size of given block
|
||||
*/
|
||||
void openData(const void *mem, size_t lenght)
|
||||
{
|
||||
if(m_fp)
|
||||
this->close();//Close previously opened file first!
|
||||
m_fp = NULL;
|
||||
m_mp = mem;
|
||||
m_mp_size = lenght;
|
||||
m_mp_tell = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Seek to given position
|
||||
* @param pos Offset or position
|
||||
* @param rel_to Relation (at begin, at current, or at end)
|
||||
*/
|
||||
void seek(long pos, int rel_to)
|
||||
{
|
||||
if(!this->isValid())
|
||||
return;
|
||||
|
||||
if(m_fp)//If a file
|
||||
{
|
||||
std::fseek(m_fp, pos, rel_to);
|
||||
}
|
||||
else//If a memory block
|
||||
{
|
||||
switch(rel_to)
|
||||
{
|
||||
case SET:
|
||||
m_mp_tell = static_cast<size_t>(pos);
|
||||
break;
|
||||
|
||||
case END:
|
||||
m_mp_tell = m_mp_size - static_cast<size_t>(pos);
|
||||
break;
|
||||
|
||||
case CUR:
|
||||
m_mp_tell = m_mp_tell + static_cast<size_t>(pos);
|
||||
break;
|
||||
}
|
||||
|
||||
if(m_mp_tell > m_mp_size)
|
||||
m_mp_tell = m_mp_size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Seek to given position (unsigned integer 64 as relation. Negative values not supported)
|
||||
* @param pos Offset or position
|
||||
* @param rel_to Relation (at begin, at current, or at end)
|
||||
*/
|
||||
inline void seeku(uint64_t pos, int rel_to)
|
||||
{
|
||||
this->seek(static_cast<long>(pos), rel_to);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the buffer from a file
|
||||
* @param buf Pointer to the destination memory block
|
||||
* @param num Number of elements
|
||||
* @param size Size of one element
|
||||
* @return Size
|
||||
*/
|
||||
size_t read(void *buf, size_t num, size_t size)
|
||||
{
|
||||
if(!this->isValid())
|
||||
return 0;
|
||||
if(m_fp)
|
||||
return std::fread(buf, num, size, m_fp);
|
||||
else
|
||||
{
|
||||
size_t pos = 0;
|
||||
size_t maxSize = static_cast<size_t>(size * num);
|
||||
|
||||
while((pos < maxSize) && (m_mp_tell < m_mp_size))
|
||||
{
|
||||
reinterpret_cast<uint8_t *>(buf)[pos] = reinterpret_cast<const uint8_t *>(m_mp)[m_mp_tell];
|
||||
m_mp_tell++;
|
||||
pos++;
|
||||
}
|
||||
|
||||
return pos / num;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get one byte and seek forward
|
||||
* @return Readed byte or EOF (a.k.a. -1)
|
||||
*/
|
||||
int getc()
|
||||
{
|
||||
if(!this->isValid())
|
||||
return -1;
|
||||
if(m_fp)//If a file
|
||||
{
|
||||
return std::getc(m_fp);
|
||||
}
|
||||
else //If a memory block
|
||||
{
|
||||
if(m_mp_tell >= m_mp_size)
|
||||
return -1;
|
||||
int x = reinterpret_cast<const uint8_t *>(m_mp)[m_mp_tell];
|
||||
m_mp_tell++;
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns current offset of cursor in a file
|
||||
* @return Offset position
|
||||
*/
|
||||
size_t tell()
|
||||
{
|
||||
if(!this->isValid())
|
||||
return 0;
|
||||
if(m_fp)//If a file
|
||||
return static_cast<size_t>(std::ftell(m_fp));
|
||||
else//If a memory block
|
||||
return m_mp_tell;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Close the file
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
if(m_fp)
|
||||
std::fclose(m_fp);
|
||||
|
||||
m_fp = NULL;
|
||||
m_mp = NULL;
|
||||
m_mp_size = 0;
|
||||
m_mp_tell = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Is file instance valid
|
||||
* @return true if vaild
|
||||
*/
|
||||
bool isValid()
|
||||
{
|
||||
return (m_fp) || (m_mp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Is End Of File?
|
||||
* @return true if end of file was reached
|
||||
*/
|
||||
bool eof()
|
||||
{
|
||||
if(!this->isValid())
|
||||
return true;
|
||||
if(m_fp)
|
||||
return (std::feof(m_fp) != 0);
|
||||
else
|
||||
return m_mp_tell >= m_mp_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a current file name
|
||||
* @return File name of currently loaded file
|
||||
*/
|
||||
const std::string &fileName()
|
||||
{
|
||||
return m_file_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieve file size
|
||||
* @return Size of file in bytes
|
||||
*/
|
||||
size_t fileSize()
|
||||
{
|
||||
if(!this->isValid())
|
||||
return 0;
|
||||
if(!m_fp)
|
||||
return m_mp_size; //Size of memory block is well known
|
||||
size_t old_pos = this->tell();
|
||||
seek(0l, FileAndMemReader::END);
|
||||
size_t file_size = this->tell();
|
||||
seek(static_cast<long>(old_pos), FileAndMemReader::SET);
|
||||
return file_size;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FILE_AND_MEM_READER_HHHH */
|
|
@ -1,588 +0,0 @@
|
|||
/*
|
||||
* Wohlstand's OPL3 Bank File - a bank format to store OPL3 timbre data and setup
|
||||
*
|
||||
* Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "wopl_file.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const char *wopl3_magic = "WOPL3-BANK\0";
|
||||
static const char *wopli_magic = "WOPL3-INST\0";
|
||||
|
||||
static const uint16_t wopl_latest_version = 3;
|
||||
|
||||
#define WOPL_INST_SIZE_V2 62
|
||||
#define WOPL_INST_SIZE_V3 66
|
||||
|
||||
static uint16_t toUint16LE(const uint8_t *arr)
|
||||
{
|
||||
uint16_t num = arr[0];
|
||||
num |= ((arr[1] << 8) & 0xFF00);
|
||||
return num;
|
||||
}
|
||||
|
||||
static uint16_t toUint16BE(const uint8_t *arr)
|
||||
{
|
||||
uint16_t num = arr[1];
|
||||
num |= ((arr[0] << 8) & 0xFF00);
|
||||
return num;
|
||||
}
|
||||
|
||||
static int16_t toSint16BE(const uint8_t *arr)
|
||||
{
|
||||
int16_t num = *(const int8_t *)(&arr[0]);
|
||||
num *= 1 << 8;
|
||||
num |= arr[1];
|
||||
return num;
|
||||
}
|
||||
|
||||
static void fromUint16LE(uint16_t in, uint8_t *arr)
|
||||
{
|
||||
arr[0] = in & 0x00FF;
|
||||
arr[1] = (in >> 8) & 0x00FF;
|
||||
}
|
||||
|
||||
static void fromUint16BE(uint16_t in, uint8_t *arr)
|
||||
{
|
||||
arr[1] = in & 0x00FF;
|
||||
arr[0] = (in >> 8) & 0x00FF;
|
||||
}
|
||||
|
||||
static void fromSint16BE(int16_t in, uint8_t *arr)
|
||||
{
|
||||
arr[1] = in & 0x00FF;
|
||||
arr[0] = ((uint16_t)in >> 8) & 0x00FF;
|
||||
}
|
||||
|
||||
|
||||
WOPLFile *WOPL_Init(uint16_t melodic_banks, uint16_t percussive_banks)
|
||||
{
|
||||
WOPLFile *file = NULL;
|
||||
if(melodic_banks == 0)
|
||||
return NULL;
|
||||
if(percussive_banks == 0)
|
||||
return NULL;
|
||||
file = (WOPLFile*)calloc(1, sizeof(WOPLFile));
|
||||
if(!file)
|
||||
return NULL;
|
||||
file->banks_count_melodic = melodic_banks;
|
||||
file->banks_count_percussion = percussive_banks;
|
||||
file->banks_melodic = (WOPLBank*)calloc(1, sizeof(WOPLBank) * melodic_banks );
|
||||
file->banks_percussive = (WOPLBank*)calloc(1, sizeof(WOPLBank) * percussive_banks );
|
||||
return file;
|
||||
}
|
||||
|
||||
void WOPL_Free(WOPLFile *file)
|
||||
{
|
||||
if(file)
|
||||
{
|
||||
if(file->banks_melodic)
|
||||
free(file->banks_melodic);
|
||||
if(file->banks_percussive)
|
||||
free(file->banks_percussive);
|
||||
free(file);
|
||||
}
|
||||
}
|
||||
|
||||
int WOPL_BanksCmp(const WOPLFile *bank1, const WOPLFile *bank2)
|
||||
{
|
||||
int res = 1;
|
||||
|
||||
res &= (bank1->version == bank2->version);
|
||||
res &= (bank1->opl_flags == bank2->opl_flags);
|
||||
res &= (bank1->volume_model == bank2->volume_model);
|
||||
res &= (bank1->banks_count_melodic == bank2->banks_count_melodic);
|
||||
res &= (bank1->banks_count_percussion == bank2->banks_count_percussion);
|
||||
|
||||
if(res)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < bank1->banks_count_melodic; i++)
|
||||
res &= (memcmp(&bank1->banks_melodic[i], &bank2->banks_melodic[i], sizeof(WOPLBank)) == 0);
|
||||
if(res)
|
||||
{
|
||||
for(i = 0; i < bank1->banks_count_percussion; i++)
|
||||
res &= (memcmp(&bank1->banks_percussive[i], &bank2->banks_percussive[i], sizeof(WOPLBank)) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void WOPL_parseInstrument(WOPLInstrument *ins, uint8_t *cursor, uint16_t version, uint8_t has_sounding_delays)
|
||||
{
|
||||
int l;
|
||||
strncpy(ins->inst_name, (const char*)cursor, 32);
|
||||
ins->inst_name[32] = '\0';
|
||||
ins->note_offset1 = toSint16BE(cursor + 32);
|
||||
ins->note_offset2 = toSint16BE(cursor + 34);
|
||||
ins->midi_velocity_offset = (int8_t)cursor[36];
|
||||
ins->second_voice_detune = (int8_t)cursor[37];
|
||||
ins->percussion_key_number = cursor[38];
|
||||
ins->inst_flags = cursor[39];
|
||||
ins->fb_conn1_C0 = cursor[40];
|
||||
ins->fb_conn2_C0 = cursor[41];
|
||||
for(l = 0; l < 4; l++)
|
||||
{
|
||||
size_t off = 42 + (size_t)(l) * 5;
|
||||
ins->operators[l].avekf_20 = cursor[off + 0];
|
||||
ins->operators[l].ksl_l_40 = cursor[off + 1];
|
||||
ins->operators[l].atdec_60 = cursor[off + 2];
|
||||
ins->operators[l].susrel_80 = cursor[off + 3];
|
||||
ins->operators[l].waveform_E0 = cursor[off + 4];
|
||||
}
|
||||
if((version >= 3) && has_sounding_delays)
|
||||
{
|
||||
ins->delay_on_ms = toUint16BE(cursor + 62);
|
||||
ins->delay_off_ms = toUint16BE(cursor + 64);
|
||||
}
|
||||
}
|
||||
|
||||
static void WOPL_writeInstrument(WOPLInstrument *ins, uint8_t *cursor, uint16_t version, uint8_t has_sounding_delays)
|
||||
{
|
||||
int l;
|
||||
strncpy((char*)cursor, ins->inst_name, 32);
|
||||
fromSint16BE(ins->note_offset1, cursor + 32);
|
||||
fromSint16BE(ins->note_offset2, cursor + 34);
|
||||
cursor[36] = (uint8_t)ins->midi_velocity_offset;
|
||||
cursor[37] = (uint8_t)ins->second_voice_detune;
|
||||
cursor[38] = ins->percussion_key_number;
|
||||
cursor[39] = ins->inst_flags;
|
||||
cursor[40] = ins->fb_conn1_C0;
|
||||
cursor[41] = ins->fb_conn2_C0;
|
||||
for(l = 0; l < 4; l++)
|
||||
{
|
||||
size_t off = 42 + (size_t)(l) * 5;
|
||||
cursor[off + 0] = ins->operators[l].avekf_20;
|
||||
cursor[off + 1] = ins->operators[l].ksl_l_40;
|
||||
cursor[off + 2] = ins->operators[l].atdec_60;
|
||||
cursor[off + 3] = ins->operators[l].susrel_80;
|
||||
cursor[off + 4] = ins->operators[l].waveform_E0;
|
||||
}
|
||||
if((version >= 3) && has_sounding_delays)
|
||||
{
|
||||
fromUint16BE(ins->delay_on_ms, cursor + 62);
|
||||
fromUint16BE(ins->delay_off_ms, cursor + 64);
|
||||
}
|
||||
}
|
||||
|
||||
WOPLFile *WOPL_LoadBankFromMem(void *mem, size_t length, int *error)
|
||||
{
|
||||
WOPLFile *outFile = NULL;
|
||||
uint16_t i = 0, j = 0, k = 0;
|
||||
uint16_t version = 0;
|
||||
uint16_t count_melodic_banks = 1;
|
||||
uint16_t count_percusive_banks = 1;
|
||||
uint8_t *cursor = (uint8_t *)mem;
|
||||
|
||||
WOPLBank *bankslots[2];
|
||||
uint16_t bankslots_sizes[2];
|
||||
|
||||
#define SET_ERROR(err) \
|
||||
{\
|
||||
WOPL_Free(outFile);\
|
||||
if(error)\
|
||||
{\
|
||||
*error = err;\
|
||||
}\
|
||||
}
|
||||
|
||||
#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; }
|
||||
|
||||
if(!cursor)
|
||||
{
|
||||
SET_ERROR(WOPL_ERR_NULL_POINTER);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
{/* Magic number */
|
||||
if(length < 11)
|
||||
{
|
||||
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
|
||||
return NULL;
|
||||
}
|
||||
if(memcmp(cursor, wopl3_magic, 11) != 0)
|
||||
{
|
||||
SET_ERROR(WOPL_ERR_BAD_MAGIC);
|
||||
return NULL;
|
||||
}
|
||||
GO_FORWARD(11);
|
||||
}
|
||||
|
||||
{/* Version code */
|
||||
if(length < 2)
|
||||
{
|
||||
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
|
||||
return NULL;
|
||||
}
|
||||
version = toUint16LE(cursor);
|
||||
if(version > wopl_latest_version)
|
||||
{
|
||||
SET_ERROR(WOPL_ERR_NEWER_VERSION);
|
||||
return NULL;
|
||||
}
|
||||
GO_FORWARD(2);
|
||||
}
|
||||
|
||||
{/* Header of WOPL */
|
||||
uint8_t head[6];
|
||||
if(length < 6)
|
||||
{
|
||||
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(head, cursor, 6);
|
||||
count_melodic_banks = toUint16BE(head);
|
||||
count_percusive_banks = toUint16BE(head + 2);
|
||||
GO_FORWARD(6);
|
||||
|
||||
outFile = WOPL_Init(count_melodic_banks, count_percusive_banks);
|
||||
if(!outFile)
|
||||
{
|
||||
SET_ERROR(WOPL_ERR_OUT_OF_MEMORY);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
outFile->version = version;
|
||||
outFile->opl_flags = head[4];
|
||||
outFile->volume_model = head[5];
|
||||
}
|
||||
|
||||
bankslots_sizes[0] = count_melodic_banks;
|
||||
bankslots[0] = outFile->banks_melodic;
|
||||
bankslots_sizes[1] = count_percusive_banks;
|
||||
bankslots[1] = outFile->banks_percussive;
|
||||
|
||||
if(version >= 2) /* Bank names and LSB/MSB titles */
|
||||
{
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
for(j = 0; j < bankslots_sizes[i]; j++)
|
||||
{
|
||||
if(length < 34)
|
||||
{
|
||||
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
|
||||
return NULL;
|
||||
}
|
||||
strncpy(bankslots[i][j].bank_name, (const char*)cursor, 32);
|
||||
bankslots[i][j].bank_name[32] = '\0';
|
||||
bankslots[i][j].bank_midi_lsb = cursor[32];
|
||||
bankslots[i][j].bank_midi_msb = cursor[33];
|
||||
GO_FORWARD(34);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{/* Read instruments data */
|
||||
uint16_t insSize = 0;
|
||||
if(version > 2)
|
||||
insSize = WOPL_INST_SIZE_V3;
|
||||
else
|
||||
insSize = WOPL_INST_SIZE_V2;
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
if(length < (insSize * 128) * (size_t)bankslots_sizes[i])
|
||||
{
|
||||
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(j = 0; j < bankslots_sizes[i]; j++)
|
||||
{
|
||||
for(k = 0; k < 128; k++)
|
||||
{
|
||||
WOPLInstrument *ins = &bankslots[i][j].ins[k];
|
||||
WOPL_parseInstrument(ins, cursor, version, 1);
|
||||
GO_FORWARD(insSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef GO_FORWARD
|
||||
#undef SET_ERROR
|
||||
|
||||
return outFile;
|
||||
}
|
||||
|
||||
int WOPL_LoadInstFromMem(WOPIFile *file, void *mem, size_t length)
|
||||
{
|
||||
uint16_t version = 0;
|
||||
uint8_t *cursor = (uint8_t *)mem;
|
||||
uint16_t ins_size;
|
||||
|
||||
if(!cursor)
|
||||
return WOPL_ERR_NULL_POINTER;
|
||||
|
||||
#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; }
|
||||
|
||||
{/* Magic number */
|
||||
if(length < 11)
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
if(memcmp(cursor, wopli_magic, 11) != 0)
|
||||
return WOPL_ERR_BAD_MAGIC;
|
||||
GO_FORWARD(11);
|
||||
}
|
||||
|
||||
{/* Version code */
|
||||
if(length < 2)
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
version = toUint16LE(cursor);
|
||||
if(version > wopl_latest_version)
|
||||
return WOPL_ERR_NEWER_VERSION;
|
||||
GO_FORWARD(2);
|
||||
}
|
||||
|
||||
file->version = version;
|
||||
|
||||
{/* is drum flag */
|
||||
if(length < 1)
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
file->is_drum = *cursor;
|
||||
GO_FORWARD(1);
|
||||
}
|
||||
|
||||
if(version > 2)
|
||||
/* Skip sounding delays are not part of single-instrument file
|
||||
* two sizes of uint16_t will be subtracted */
|
||||
ins_size = WOPL_INST_SIZE_V3 - (sizeof(uint16_t) * 2);
|
||||
else
|
||||
ins_size = WOPL_INST_SIZE_V2;
|
||||
|
||||
if(length < ins_size)
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
|
||||
WOPL_parseInstrument(&file->inst, cursor, version, 0);
|
||||
GO_FORWARD(ins_size);
|
||||
|
||||
return WOPL_ERR_OK;
|
||||
#undef GO_FORWARD
|
||||
}
|
||||
|
||||
size_t WOPL_CalculateBankFileSize(WOPLFile *file, uint16_t version)
|
||||
{
|
||||
size_t final_size = 0;
|
||||
size_t ins_size = 0;
|
||||
|
||||
if(version == 0)
|
||||
version = wopl_latest_version;
|
||||
|
||||
if(!file)
|
||||
return 0;
|
||||
final_size += 11 + 2 + 2 + 2 + 1 + 1;
|
||||
/*
|
||||
* Magic number,
|
||||
* Version,
|
||||
* Count of melodic banks,
|
||||
* Count of percussive banks,
|
||||
* Chip specific flags
|
||||
* Volume Model
|
||||
*/
|
||||
|
||||
if(version >= 2)
|
||||
{
|
||||
/* Melodic banks meta-data */
|
||||
final_size += (32 + 1 + 1) * file->banks_count_melodic;
|
||||
/* Percussive banks meta-data */
|
||||
final_size += (32 + 1 + 1) * file->banks_count_percussion;
|
||||
}
|
||||
|
||||
if(version >= 3)
|
||||
ins_size = WOPL_INST_SIZE_V3;
|
||||
else
|
||||
ins_size = WOPL_INST_SIZE_V2;
|
||||
/* Melodic instruments */
|
||||
final_size += (ins_size * 128) * file->banks_count_melodic;
|
||||
/* Percusive instruments */
|
||||
final_size += (ins_size * 128) * file->banks_count_percussion;
|
||||
|
||||
return final_size;
|
||||
}
|
||||
|
||||
size_t WOPL_CalculateInstFileSize(WOPIFile *file, uint16_t version)
|
||||
{
|
||||
size_t final_size = 0;
|
||||
size_t ins_size = 0;
|
||||
|
||||
if(version == 0)
|
||||
version = wopl_latest_version;
|
||||
|
||||
if(!file)
|
||||
return 0;
|
||||
final_size += 11 + 2 + 1;
|
||||
/*
|
||||
* Magic number,
|
||||
* version,
|
||||
* is percussive instrument
|
||||
*/
|
||||
|
||||
if(version > 2)
|
||||
/* Skip sounding delays are not part of single-instrument file
|
||||
* two sizes of uint16_t will be subtracted */
|
||||
ins_size = WOPL_INST_SIZE_V3 - (sizeof(uint16_t) * 2);
|
||||
else
|
||||
ins_size = WOPL_INST_SIZE_V2;
|
||||
final_size += ins_size;
|
||||
|
||||
return final_size;
|
||||
}
|
||||
|
||||
int WOPL_SaveBankToMem(WOPLFile *file, void *dest_mem, size_t length, uint16_t version, uint16_t force_gm)
|
||||
{
|
||||
uint8_t *cursor = (uint8_t *)dest_mem;
|
||||
uint16_t ins_size = 0;
|
||||
uint16_t i, j, k;
|
||||
uint16_t banks_melodic = force_gm ? 1 : file->banks_count_melodic;
|
||||
uint16_t banks_percusive = force_gm ? 1 : file->banks_count_percussion;
|
||||
|
||||
WOPLBank *bankslots[2];
|
||||
uint16_t bankslots_sizes[2];
|
||||
|
||||
if(version == 0)
|
||||
version = wopl_latest_version;
|
||||
|
||||
#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; }
|
||||
|
||||
if(length < 11)
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
memcpy(cursor, wopl3_magic, 11);
|
||||
GO_FORWARD(11);
|
||||
|
||||
if(length < 2)
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
fromUint16LE(version, cursor);
|
||||
GO_FORWARD(2);
|
||||
|
||||
if(length < 2)
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
fromUint16BE(banks_melodic, cursor);
|
||||
GO_FORWARD(2);
|
||||
|
||||
if(length < 2)
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
fromUint16BE(banks_percusive, cursor);
|
||||
GO_FORWARD(2);
|
||||
|
||||
if(length < 2)
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
cursor[0] = file->opl_flags;
|
||||
cursor[1] = file->volume_model;
|
||||
GO_FORWARD(2);
|
||||
|
||||
bankslots[0] = file->banks_melodic;
|
||||
bankslots_sizes[0] = banks_melodic;
|
||||
bankslots[1] = file->banks_percussive;
|
||||
bankslots_sizes[1] = banks_percusive;
|
||||
|
||||
if(version >= 2)
|
||||
{
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
for(j = 0; j < bankslots_sizes[i]; j++)
|
||||
{
|
||||
if(length < 34)
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
strncpy((char*)cursor, bankslots[i][j].bank_name, 32);
|
||||
cursor[32] = bankslots[i][j].bank_midi_lsb;
|
||||
cursor[33] = bankslots[i][j].bank_midi_msb;
|
||||
GO_FORWARD(34);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{/* Write instruments data */
|
||||
if(version >= 3)
|
||||
ins_size = WOPL_INST_SIZE_V3;
|
||||
else
|
||||
ins_size = WOPL_INST_SIZE_V2;
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
if(length < (ins_size * 128) * (size_t)bankslots_sizes[i])
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
|
||||
for(j = 0; j < bankslots_sizes[i]; j++)
|
||||
{
|
||||
for(k = 0; k < 128; k++)
|
||||
{
|
||||
WOPLInstrument *ins = &bankslots[i][j].ins[k];
|
||||
WOPL_writeInstrument(ins, cursor, version, 1);
|
||||
GO_FORWARD(ins_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return WOPL_ERR_OK;
|
||||
#undef GO_FORWARD
|
||||
}
|
||||
|
||||
int WOPL_SaveInstToMem(WOPIFile *file, void *dest_mem, size_t length, uint16_t version)
|
||||
{
|
||||
uint8_t *cursor = (uint8_t *)dest_mem;
|
||||
uint16_t ins_size;
|
||||
|
||||
if(!cursor)
|
||||
return WOPL_ERR_NULL_POINTER;
|
||||
|
||||
if(version == 0)
|
||||
version = wopl_latest_version;
|
||||
|
||||
#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; }
|
||||
|
||||
{/* Magic number */
|
||||
if(length < 11)
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
memcpy(cursor, wopli_magic, 11);
|
||||
GO_FORWARD(11);
|
||||
}
|
||||
|
||||
{/* Version code */
|
||||
if(length < 2)
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
fromUint16LE(version, cursor);
|
||||
GO_FORWARD(2);
|
||||
}
|
||||
|
||||
{/* is drum flag */
|
||||
if(length < 1)
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
*cursor = file->is_drum;
|
||||
GO_FORWARD(1);
|
||||
}
|
||||
|
||||
if(version > 2)
|
||||
/* Skip sounding delays are not part of single-instrument file
|
||||
* two sizes of uint16_t will be subtracted */
|
||||
ins_size = WOPL_INST_SIZE_V3 - (sizeof(uint16_t) * 2);
|
||||
else
|
||||
ins_size = WOPL_INST_SIZE_V2;
|
||||
|
||||
if(length < ins_size)
|
||||
return WOPL_ERR_UNEXPECTED_ENDING;
|
||||
|
||||
WOPL_writeInstrument(&file->inst, cursor, version, 0);
|
||||
GO_FORWARD(ins_size);
|
||||
|
||||
return WOPL_ERR_OK;
|
||||
#undef GO_FORWARD
|
||||
}
|
|
@ -1,293 +0,0 @@
|
|||
/*
|
||||
* Wohlstand's OPL3 Bank File - a bank format to store OPL3 timbre data and setup
|
||||
*
|
||||
* Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef WOPL_FILE_H
|
||||
#define WOPL_FILE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !defined(__STDC_VERSION__) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ < 199901L)) \
|
||||
|| defined(__STRICT_ANSI__) || !defined(__cplusplus)
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed short int int16_t;
|
||||
typedef unsigned short int uint16_t;
|
||||
#endif
|
||||
|
||||
/* Global OPL flags */
|
||||
typedef enum WOPLFileFlags
|
||||
{
|
||||
/* Enable Deep-Tremolo flag */
|
||||
WOPL_FLAG_DEEP_TREMOLO = 0x01,
|
||||
/* Enable Deep-Vibrato flag */
|
||||
WOPL_FLAG_DEEP_VIBRATO = 0x02
|
||||
} WOPLFileFlags;
|
||||
|
||||
/* Volume scaling model implemented in the libADLMIDI */
|
||||
typedef enum WOPL_VolumeModel
|
||||
{
|
||||
WOPL_VM_Generic = 0,
|
||||
WOPL_VM_Native,
|
||||
WOPL_VM_DMX,
|
||||
WOPL_VM_Apogee,
|
||||
WOPL_VM_Win9x
|
||||
} WOPL_VolumeModel;
|
||||
|
||||
typedef enum WOPL_InstrumentFlags
|
||||
{
|
||||
/* Is two-operator single-voice instrument (no flags) */
|
||||
WOPL_Ins_2op = 0x00,
|
||||
/* Is true four-operator instrument */
|
||||
WOPL_Ins_4op = 0x01,
|
||||
/* Is pseudo four-operator (two 2-operator voices) instrument */
|
||||
WOPL_Ins_Pseudo4op = 0x02,
|
||||
/* Is a blank instrument entry */
|
||||
WOPL_Ins_IsBlank = 0x04,
|
||||
|
||||
/* RythmMode flags mask */
|
||||
WOPL_RhythmModeMask = 0x38,
|
||||
|
||||
/* Mask of the flags range */
|
||||
WOPL_Ins_ALL_MASK = 0x07
|
||||
} WOPL_InstrumentFlags;
|
||||
|
||||
typedef enum WOPL_RhythmMode
|
||||
{
|
||||
/* RythmMode: BassDrum */
|
||||
WOPL_RM_BassDrum = 0x08,
|
||||
/* RythmMode: Snare */
|
||||
WOPL_RM_Snare = 0x10,
|
||||
/* RythmMode: TomTom */
|
||||
WOPL_RM_TomTom = 0x18,
|
||||
/* RythmMode: Cymbell */
|
||||
WOPL_RM_Cymbal = 0x20,
|
||||
/* RythmMode: HiHat */
|
||||
WOPL_RM_HiHat = 0x28
|
||||
} WOPL_RhythmMode;
|
||||
|
||||
/* DEPRECATED: It has typo. Don't use it! */
|
||||
typedef WOPL_RhythmMode WOPL_RythmMode;
|
||||
|
||||
/* Error codes */
|
||||
typedef enum WOPL_ErrorCodes
|
||||
{
|
||||
WOPL_ERR_OK = 0,
|
||||
/* Magic number is not maching */
|
||||
WOPL_ERR_BAD_MAGIC,
|
||||
/* Too short file */
|
||||
WOPL_ERR_UNEXPECTED_ENDING,
|
||||
/* Zero banks count */
|
||||
WOPL_ERR_INVALID_BANKS_COUNT,
|
||||
/* Version of file is newer than supported by current version of library */
|
||||
WOPL_ERR_NEWER_VERSION,
|
||||
/* Out of memory */
|
||||
WOPL_ERR_OUT_OF_MEMORY,
|
||||
/* Given null pointer memory data */
|
||||
WOPL_ERR_NULL_POINTER
|
||||
} WOPL_ErrorCodes;
|
||||
|
||||
/* Operator indeces inside of Instrument Entry */
|
||||
#define WOPL_OP_CARRIER1 0
|
||||
#define WOPL_OP_MODULATOR1 1
|
||||
#define WOPL_OP_CARRIER2 2
|
||||
#define WOPL_OP_MODULATOR2 3
|
||||
|
||||
/* OPL3 Oerators data */
|
||||
typedef struct WOPLOperator
|
||||
{
|
||||
/* AM/Vib/Env/Ksr/FMult characteristics */
|
||||
uint8_t avekf_20;
|
||||
/* Key Scale Level / Total level register data */
|
||||
uint8_t ksl_l_40;
|
||||
/* Attack / Decay */
|
||||
uint8_t atdec_60;
|
||||
/* Systain and Release register data */
|
||||
uint8_t susrel_80;
|
||||
/* Wave form */
|
||||
uint8_t waveform_E0;
|
||||
} WOPLOperator;
|
||||
|
||||
/* Instrument entry */
|
||||
typedef struct WOPLInstrument
|
||||
{
|
||||
/* Title of the instrument */
|
||||
char inst_name[34];
|
||||
/* MIDI note key (half-tone) offset for an instrument (or a first voice in pseudo-4-op mode) */
|
||||
int16_t note_offset1;
|
||||
/* MIDI note key (half-tone) offset for a second voice in pseudo-4-op mode */
|
||||
int16_t note_offset2;
|
||||
/* MIDI note velocity offset (taken from Apogee TMB format) */
|
||||
int8_t midi_velocity_offset;
|
||||
/* Second voice detune level (taken from DMX OP2) */
|
||||
int8_t second_voice_detune;
|
||||
/* Percussion MIDI base tone number at which this drum will be played */
|
||||
uint8_t percussion_key_number;
|
||||
/* Enum WOPL_InstrumentFlags */
|
||||
uint8_t inst_flags;
|
||||
/* Feedback&Connection register for first and second operators */
|
||||
uint8_t fb_conn1_C0;
|
||||
/* Feedback&Connection register for third and fourth operators */
|
||||
uint8_t fb_conn2_C0;
|
||||
/* Operators register data */
|
||||
WOPLOperator operators[4];
|
||||
/* Millisecond delay of sounding while key is on */
|
||||
uint16_t delay_on_ms;
|
||||
/* Millisecond delay of sounding after key off */
|
||||
uint16_t delay_off_ms;
|
||||
} WOPLInstrument;
|
||||
|
||||
/* Bank entry */
|
||||
typedef struct WOPLBank
|
||||
{
|
||||
/* Name of bank */
|
||||
char bank_name[33];
|
||||
/* MIDI Bank LSB code */
|
||||
uint8_t bank_midi_lsb;
|
||||
/* MIDI Bank MSB code */
|
||||
uint8_t bank_midi_msb;
|
||||
/* Instruments data of this bank */
|
||||
WOPLInstrument ins[128];
|
||||
} WOPLBank;
|
||||
|
||||
/* Instrument data file */
|
||||
typedef struct WOPIFile
|
||||
{
|
||||
/* Version of instrument file */
|
||||
uint16_t version;
|
||||
/* Is this a percussion instrument */
|
||||
uint8_t is_drum;
|
||||
/* Instrument data */
|
||||
WOPLInstrument inst;
|
||||
} WOPIFile;
|
||||
|
||||
/* Bank data file */
|
||||
typedef struct WOPLFile
|
||||
{
|
||||
/* Version of bank file */
|
||||
uint16_t version;
|
||||
/* Count of melodic banks in this file */
|
||||
uint16_t banks_count_melodic;
|
||||
/* Count of percussion banks in this file */
|
||||
uint16_t banks_count_percussion;
|
||||
/* Enum WOPLFileFlags */
|
||||
uint8_t opl_flags;
|
||||
/* Enum WOPL_VolumeModel */
|
||||
uint8_t volume_model;
|
||||
/* dynamically allocated data Melodic banks array */
|
||||
WOPLBank *banks_melodic;
|
||||
/* dynamically allocated data Percussive banks array */
|
||||
WOPLBank *banks_percussive;
|
||||
} WOPLFile;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize blank WOPL data structure with allocated bank data
|
||||
* @param melodic_banks Count of melodic banks
|
||||
* @param percussive_banks Count of percussive banks
|
||||
* @return pointer to heap-allocated WOPL data structure or NULL when out of memory or incorrectly given banks counts
|
||||
*/
|
||||
extern WOPLFile *WOPL_Init(uint16_t melodic_banks, uint16_t percussive_banks);
|
||||
|
||||
/**
|
||||
* @brief Clean up WOPL data file (all allocated bank arrays will be fried too)
|
||||
* @param file pointer to heap-allocated WOPL data structure
|
||||
*/
|
||||
extern void WOPL_Free(WOPLFile *file);
|
||||
|
||||
/**
|
||||
* @brief Compare two bank entries
|
||||
* @param bank1 First bank
|
||||
* @param bank2 Second bank
|
||||
* @return 1 if banks are equal or 0 if there are different
|
||||
*/
|
||||
extern int WOPL_BanksCmp(const WOPLFile *bank1, const WOPLFile *bank2);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Load WOPL bank file from the memory.
|
||||
* WOPL data structure will be allocated. (don't forget to clear it with WOPL_Free() after use!)
|
||||
* @param mem Pointer to memory block contains raw WOPL bank file data
|
||||
* @param length Length of given memory block
|
||||
* @param error pointer to integer to return an error code. Pass NULL if you don't want to use error codes.
|
||||
* @return Heap-allocated WOPL file data structure or NULL if any error has occouped
|
||||
*/
|
||||
extern WOPLFile *WOPL_LoadBankFromMem(void *mem, size_t length, int *error);
|
||||
|
||||
/**
|
||||
* @brief Load WOPI instrument file from the memory.
|
||||
* You must allocate WOPIFile structure by yourself and give the pointer to it.
|
||||
* @param file Pointer to destinition WOPIFile structure to fill it with parsed data.
|
||||
* @param mem Pointer to memory block contains raw WOPI instrument file data
|
||||
* @param length Length of given memory block
|
||||
* @return 0 if no errors occouped, or an error code of WOPL_ErrorCodes enumeration
|
||||
*/
|
||||
extern int WOPL_LoadInstFromMem(WOPIFile *file, void *mem, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Calculate the size of the output memory block
|
||||
* @param file Heap-allocated WOPL file data structure
|
||||
* @param version Destinition version of the file
|
||||
* @return Size of the raw WOPL file data
|
||||
*/
|
||||
extern size_t WOPL_CalculateBankFileSize(WOPLFile *file, uint16_t version);
|
||||
|
||||
/**
|
||||
* @brief Calculate the size of the output memory block
|
||||
* @param file Pointer to WOPI file data structure
|
||||
* @param version Destinition version of the file
|
||||
* @return Size of the raw WOPI file data
|
||||
*/
|
||||
extern size_t WOPL_CalculateInstFileSize(WOPIFile *file, uint16_t version);
|
||||
|
||||
/**
|
||||
* @brief Write raw WOPL into given memory block
|
||||
* @param file Heap-allocated WOPL file data structure
|
||||
* @param dest_mem Destinition memory block pointer
|
||||
* @param length Length of destinition memory block
|
||||
* @param version Wanted WOPL version
|
||||
* @param force_gm Force GM set in saved bank file
|
||||
* @return Error code or 0 on success
|
||||
*/
|
||||
extern int WOPL_SaveBankToMem(WOPLFile *file, void *dest_mem, size_t length, uint16_t version, uint16_t force_gm);
|
||||
|
||||
/**
|
||||
* @brief Write raw WOPI into given memory block
|
||||
* @param file Pointer to WOPI file data structure
|
||||
* @param dest_mem Destinition memory block pointer
|
||||
* @param length Length of destinition memory block
|
||||
* @param version Wanted WOPI version
|
||||
* @return Error code or 0 on success
|
||||
*/
|
||||
extern int WOPL_SaveInstToMem(WOPIFile *file, void *dest_mem, size_t length, uint16_t version);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WOPL_FILE_H */
|
|
@ -1,112 +0,0 @@
|
|||
cmake_minimum_required(VERSION 2.8.7)
|
||||
|
||||
#make_release_only()
|
||||
|
||||
project(asmjit C)
|
||||
|
||||
set(ASMJITNAME asmjit)
|
||||
|
||||
add_definitions(-DASMJIT_BUILD_EMBED)
|
||||
add_definitions(-DASMJIT_STATIC)
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_DEBUG_POSTFIX "d")
|
||||
add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
# Suppress stdlib.h:334:6: warning: pointer is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)
|
||||
add_definitions(-Wno-nullability-completeness)
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
set(ASMJIT_PUBLIC_HDRS
|
||||
asmjit/arm.h
|
||||
asmjit/asmjit.h
|
||||
asmjit/asmjit_apibegin.h
|
||||
asmjit/asmjit_apiend.h
|
||||
asmjit/asmjit_build.h
|
||||
asmjit/base.h
|
||||
asmjit/base/arch.h
|
||||
asmjit/base/assembler.h
|
||||
asmjit/base/codebuilder.h
|
||||
asmjit/base/codecompiler.h
|
||||
asmjit/base/codeemitter.h
|
||||
asmjit/base/codeholder.h
|
||||
asmjit/base/constpool.h
|
||||
asmjit/base/cpuinfo.h
|
||||
asmjit/base/func.h
|
||||
asmjit/base/globals.h
|
||||
asmjit/base/inst.h
|
||||
asmjit/base/logging.h
|
||||
asmjit/base/misc_p.h
|
||||
asmjit/base/operand.h
|
||||
asmjit/base/osutils.h
|
||||
asmjit/base/regalloc_p.h
|
||||
asmjit/base/runtime.h
|
||||
asmjit/base/simdtypes.h
|
||||
asmjit/base/string.h
|
||||
asmjit/base/utils.h
|
||||
asmjit/base/vmem.h
|
||||
asmjit/base/zone.h
|
||||
asmjit/x86.h
|
||||
asmjit/x86/x86assembler.h
|
||||
asmjit/x86/x86builder.h
|
||||
asmjit/x86/x86compiler.h
|
||||
asmjit/x86/x86emitter.h
|
||||
asmjit/x86/x86globals.h
|
||||
asmjit/x86/x86inst.h
|
||||
asmjit/x86/x86instimpl_p.h
|
||||
asmjit/x86/x86internal_p.h
|
||||
asmjit/x86/x86logging_p.h
|
||||
asmjit/x86/x86misc.h
|
||||
asmjit/x86/x86operand.h
|
||||
asmjit/x86/x86regalloc_p.h
|
||||
)
|
||||
set(ASMJIT_SRCS
|
||||
asmjit/base/arch.cpp
|
||||
asmjit/base/assembler.cpp
|
||||
asmjit/base/codebuilder.cpp
|
||||
asmjit/base/codecompiler.cpp
|
||||
asmjit/base/codeemitter.cpp
|
||||
asmjit/base/codeholder.cpp
|
||||
asmjit/base/constpool.cpp
|
||||
asmjit/base/cpuinfo.cpp
|
||||
asmjit/base/func.cpp
|
||||
asmjit/base/globals.cpp
|
||||
asmjit/base/inst.cpp
|
||||
asmjit/base/logging.cpp
|
||||
asmjit/base/operand.cpp
|
||||
asmjit/base/osutils.cpp
|
||||
asmjit/base/regalloc.cpp
|
||||
asmjit/base/runtime.cpp
|
||||
asmjit/base/string.cpp
|
||||
asmjit/base/utils.cpp
|
||||
asmjit/base/vmem.cpp
|
||||
asmjit/base/zone.cpp
|
||||
asmjit/x86/x86assembler.cpp
|
||||
asmjit/x86/x86builder.cpp
|
||||
asmjit/x86/x86compiler.cpp
|
||||
asmjit/x86/x86inst.cpp
|
||||
asmjit/x86/x86instimpl.cpp
|
||||
asmjit/x86/x86internal.cpp
|
||||
asmjit/x86/x86logging.cpp
|
||||
asmjit/x86/x86operand.cpp
|
||||
asmjit/x86/x86operand_regs.cpp
|
||||
asmjit/x86/x86regalloc.cpp
|
||||
)
|
||||
|
||||
add_library(${ASMJITNAME} STATIC ${ASMJIT_SRCS} ${ASMJIT_PUBLIC_HDRS})
|
||||
|
||||
set_target_properties(${ASMJITNAME} PROPERTIES OUTPUT_NAME asmjit)
|
||||
|
||||
if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL )
|
||||
install(TARGETS ${ASMJITNAME}
|
||||
RUNTIME DESTINATION bin
|
||||
ARCHIVE DESTINATION lib
|
||||
LIBRARY DESTINATION lib )
|
||||
endif()
|
||||
if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL )
|
||||
install(FILES ${ASMJIT_PUBLIC_HDRS} DESTINATION include)
|
||||
endif()
|
|
@ -1,21 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_ARM_H
|
||||
#define _ASMJIT_ARM_H
|
||||
|
||||
// [Dependencies]
|
||||
#include "./base.h"
|
||||
|
||||
#include "./arm/armassembler.h"
|
||||
#include "./arm/armbuilder.h"
|
||||
#include "./arm/armcompiler.h"
|
||||
#include "./arm/arminst.h"
|
||||
#include "./arm/armoperand.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_ARM_H
|
|
@ -1,47 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_ASMJIT_H
|
||||
#define _ASMJIT_ASMJIT_H
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit_mainpage]
|
||||
// ============================================================================
|
||||
|
||||
//! \mainpage
|
||||
//!
|
||||
//! AsmJit - Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//!
|
||||
//! Introduction provided by the project page at https://github.com/asmjit/asmjit.
|
||||
|
||||
//! \defgroup asmjit_base AsmJit Base API (architecture independent)
|
||||
//!
|
||||
//! \brief Backend Neutral API.
|
||||
|
||||
//! \defgroup asmjit_x86 AsmJit X86/X64 API
|
||||
//!
|
||||
//! \brief X86/X64 Backend API.
|
||||
|
||||
//! \defgroup asmjit_arm AsmJit ARM32/ARM64 API
|
||||
//!
|
||||
//! \brief ARM32/ARM64 Backend API.
|
||||
|
||||
// [Dependencies]
|
||||
#include "./base.h"
|
||||
|
||||
// [X86/X64]
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
#include "./x86.h"
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
// [ARM32/ARM64]
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
#include "./arm.h"
|
||||
#endif // ASMJIT_BUILD_ARM
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_ASMJIT_H
|
|
@ -1,117 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Dependencies]
|
||||
#if !defined(_ASMJIT_BUILD_H)
|
||||
# include "./build.h"
|
||||
#endif // !_ASMJIT_BUILD_H
|
||||
|
||||
// [Guard]
|
||||
#if !defined(ASMJIT_API_SCOPE)
|
||||
# define ASMJIT_API_SCOPE
|
||||
#else
|
||||
# error "[asmjit] api-scope is already active, previous scope not closed by asmjit_apiend.h?"
|
||||
#endif // ASMJIT_API_SCOPE
|
||||
|
||||
// ============================================================================
|
||||
// [C++ Support]
|
||||
// ============================================================================
|
||||
|
||||
// [NoExcept]
|
||||
#if !ASMJIT_CC_HAS_NOEXCEPT && !defined(noexcept)
|
||||
# define noexcept ASMJIT_NOEXCEPT
|
||||
# define ASMJIT_UNDEF_NOEXCEPT
|
||||
#endif // !ASMJIT_CC_HAS_NOEXCEPT && !noexcept
|
||||
|
||||
// [NullPtr]
|
||||
#if !ASMJIT_CC_HAS_NULLPTR && !defined(nullptr)
|
||||
# define nullptr NULL
|
||||
# define ASMJIT_UNDEF_NULLPTR
|
||||
#endif // !ASMJIT_CC_HAS_NULLPTR && !nullptr
|
||||
|
||||
// [Override]
|
||||
#if !ASMJIT_CC_HAS_OVERRIDE && !defined(override)
|
||||
# define override
|
||||
# define ASMJIT_UNDEF_OVERRIDE
|
||||
#endif // !ASMJIT_CC_HAS_OVERRIDE && !override
|
||||
|
||||
// ============================================================================
|
||||
// [Compiler Support]
|
||||
// ============================================================================
|
||||
|
||||
// [Clang]
|
||||
#if ASMJIT_CC_CLANG
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wc++11-extensions"
|
||||
# pragma clang diagnostic ignored "-Wconstant-logical-operand"
|
||||
# pragma clang diagnostic ignored "-Wunnamed-type-template-args"
|
||||
#endif // ASMJIT_CC_CLANG
|
||||
|
||||
// [GCC]
|
||||
#if ASMJIT_CC_GCC
|
||||
# pragma GCC diagnostic push
|
||||
#endif // ASMJIT_CC_GCC
|
||||
|
||||
// [MSC]
|
||||
#if ASMJIT_CC_MSC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4127) // conditional expression is constant
|
||||
# pragma warning(disable: 4201) // nameless struct/union
|
||||
# pragma warning(disable: 4244) // '+=' : conversion from 'int' to 'x', possible loss of data
|
||||
# pragma warning(disable: 4251) // struct needs to have dll-interface to be used by clients of struct ...
|
||||
# pragma warning(disable: 4275) // non dll-interface struct ... used as base for dll-interface struct
|
||||
# pragma warning(disable: 4355) // this used in base member initializer list
|
||||
# pragma warning(disable: 4480) // specifying underlying type for enum
|
||||
# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false'
|
||||
# if _MSC_VER < 1900
|
||||
# if !defined(vsnprintf)
|
||||
# define ASMJIT_UNDEF_VSNPRINTF
|
||||
# define vsnprintf _vsnprintf
|
||||
# endif // !vsnprintf
|
||||
# if !defined(snprintf)
|
||||
# define ASMJIT_UNDEF_SNPRINTF
|
||||
# define snprintf _snprintf
|
||||
# endif // !snprintf
|
||||
# endif
|
||||
#endif // ASMJIT_CC_MSC
|
||||
|
||||
// ============================================================================
|
||||
// [Custom Macros]
|
||||
// ============================================================================
|
||||
|
||||
// [ASMJIT_NON...]
|
||||
#if ASMJIT_CC_HAS_DELETE_FUNCTION
|
||||
#define ASMJIT_NONCONSTRUCTIBLE(...) \
|
||||
private: \
|
||||
__VA_ARGS__() = delete; \
|
||||
__VA_ARGS__(const __VA_ARGS__& other) = delete; \
|
||||
__VA_ARGS__& operator=(const __VA_ARGS__& other) = delete; \
|
||||
public:
|
||||
#define ASMJIT_NONCOPYABLE(...) \
|
||||
private: \
|
||||
__VA_ARGS__(const __VA_ARGS__& other) = delete; \
|
||||
__VA_ARGS__& operator=(const __VA_ARGS__& other) = delete; \
|
||||
public:
|
||||
#else
|
||||
#define ASMJIT_NONCONSTRUCTIBLE(...) \
|
||||
private: \
|
||||
inline __VA_ARGS__(); \
|
||||
inline __VA_ARGS__(const __VA_ARGS__& other); \
|
||||
inline __VA_ARGS__& operator=(const __VA_ARGS__& other); \
|
||||
public:
|
||||
#define ASMJIT_NONCOPYABLE(...) \
|
||||
private: \
|
||||
inline __VA_ARGS__(const __VA_ARGS__& other); \
|
||||
inline __VA_ARGS__& operator=(const __VA_ARGS__& other); \
|
||||
public:
|
||||
#endif // ASMJIT_CC_HAS_DELETE_FUNCTION
|
||||
|
||||
// [ASMJIT_ENUM]
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
# define ASMJIT_ENUM(NAME) enum NAME : uint32_t
|
||||
#else
|
||||
# define ASMJIT_ENUM(NAME) enum NAME
|
||||
#endif
|
|
@ -1,74 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#if defined(ASMJIT_API_SCOPE)
|
||||
# undef ASMJIT_API_SCOPE
|
||||
#else
|
||||
# error "[asmjit] api-scope not active, forgot to include asmjit_apibegin.h?"
|
||||
#endif // ASMJIT_API_SCOPE
|
||||
|
||||
// ============================================================================
|
||||
// [C++ Support]
|
||||
// ============================================================================
|
||||
|
||||
// [NoExcept]
|
||||
#if defined(ASMJIT_UNDEF_NOEXCEPT)
|
||||
# undef noexcept
|
||||
# undef ASMJIT_UNDEF_NOEXCEPT
|
||||
#endif // ASMJIT_UNDEF_NOEXCEPT
|
||||
|
||||
// [NullPtr]
|
||||
#if defined(ASMJIT_UNDEF_NULLPTR)
|
||||
# undef nullptr
|
||||
# undef ASMJIT_UNDEF_NULLPTR
|
||||
#endif // ASMJIT_UNDEF_NULLPTR
|
||||
|
||||
// [Override]
|
||||
#if defined(ASMJIT_UNDEF_OVERRIDE)
|
||||
# undef override
|
||||
# undef ASMJIT_UNDEF_OVERRIDE
|
||||
#endif // ASMJIT_UNDEF_OVERRIDE
|
||||
|
||||
// ============================================================================
|
||||
// [Compiler Support]
|
||||
// ============================================================================
|
||||
|
||||
// [Clang]
|
||||
#if ASMJIT_CC_CLANG
|
||||
# pragma clang diagnostic pop
|
||||
#endif // ASMJIT_CC_CLANG
|
||||
|
||||
// [GCC]
|
||||
#if ASMJIT_CC_GCC
|
||||
# pragma GCC diagnostic pop
|
||||
#endif // ASMJIT_CC_GCC
|
||||
|
||||
// [MSC]
|
||||
#if ASMJIT_CC_MSC
|
||||
# pragma warning(pop)
|
||||
# if _MSC_VER < 1900
|
||||
# if defined(ASMJIT_UNDEF_VSNPRINTF)
|
||||
# undef vsnprintf
|
||||
# undef ASMJIT_UNDEF_VSNPRINTF
|
||||
# endif // ASMJIT_UNDEF_VSNPRINTF
|
||||
# if defined(ASMJIT_UNDEF_SNPRINTF)
|
||||
# undef snprintf
|
||||
# undef ASMJIT_UNDEF_SNPRINTF
|
||||
# endif // ASMJIT_UNDEF_SNPRINTF
|
||||
# endif
|
||||
#endif // ASMJIT_CC_MSC
|
||||
|
||||
// ============================================================================
|
||||
// [Custom Macros]
|
||||
// ============================================================================
|
||||
|
||||
// [ASMJIT_NON...]
|
||||
#undef ASMJIT_NONCONSTRUCTIBLE
|
||||
#undef ASMJIT_NONCOPYABLE
|
||||
|
||||
// [ASMJIT_ENUM]
|
||||
#undef ASMJIT_ENUM
|
|
@ -1,949 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BUILD_H
|
||||
#define _ASMJIT_BUILD_H
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Build - Configuration]
|
||||
// ============================================================================
|
||||
|
||||
// AsmJit is by default compiled only for a host processor for the purpose of
|
||||
// JIT code generation. Both Assembler and CodeCompiler emitters are compiled
|
||||
// by default. Preprocessor macros can be used to change the default behavior.
|
||||
|
||||
// External Config File
|
||||
// --------------------
|
||||
//
|
||||
// Define in case your configuration is generated in an external file to be
|
||||
// included.
|
||||
|
||||
#if defined(ASMJIT_CONFIG_FILE)
|
||||
# include ASMJIT_CONFIG_FILE
|
||||
#endif // ASMJIT_CONFIG_FILE
|
||||
|
||||
// AsmJit Static Builds and Embedding
|
||||
// ----------------------------------
|
||||
//
|
||||
// These definitions can be used to enable static library build. Embed is used
|
||||
// when AsmJit's source code is embedded directly in another project, implies
|
||||
// static build as well.
|
||||
//
|
||||
// #define ASMJIT_EMBED // Asmjit is embedded (implies ASMJIT_STATIC).
|
||||
// #define ASMJIT_STATIC // Define to enable static-library build.
|
||||
|
||||
// AsmJit Build Modes
|
||||
// ------------------
|
||||
//
|
||||
// These definitions control the build mode and tracing support. The build mode
|
||||
// should be auto-detected at compile time, but it's possible to override it in
|
||||
// case that the auto-detection fails.
|
||||
//
|
||||
// Tracing is a feature that is never compiled by default and it's only used to
|
||||
// debug AsmJit itself.
|
||||
//
|
||||
// #define ASMJIT_DEBUG // Define to enable debug-mode.
|
||||
// #define ASMJIT_RELEASE // Define to enable release-mode.
|
||||
|
||||
// AsmJit Build Backends
|
||||
// ---------------------
|
||||
//
|
||||
// These definitions control which backends to compile. If none of these is
|
||||
// defined AsmJit will use host architecture by default (for JIT code generation).
|
||||
//
|
||||
// #define ASMJIT_BUILD_X86 // Define to enable X86 and X64 code-generation.
|
||||
// #define ASMJIT_BUILD_ARM // Define to enable ARM32 and ARM64 code-generation.
|
||||
// #define ASMJIT_BUILD_HOST // Define to enable host instruction set.
|
||||
|
||||
// AsmJit Build Features
|
||||
// ---------------------
|
||||
//
|
||||
// Flags can be defined to disable standard features. These are handy especially
|
||||
// when building AsmJit statically and some features are not needed or unwanted
|
||||
// (like CodeCompiler).
|
||||
//
|
||||
// AsmJit features are enabled by default.
|
||||
// #define ASMJIT_DISABLE_COMPILER // Disable CodeCompiler (completely).
|
||||
// #define ASMJIT_DISABLE_LOGGING // Disable logging and formatting (completely).
|
||||
// #define ASMJIT_DISABLE_TEXT // Disable everything that contains text
|
||||
// // representation (instructions, errors, ...).
|
||||
// #define ASMJIT_DISABLE_VALIDATION // Disable Validation (completely).
|
||||
|
||||
// Prevent compile-time errors caused by misconfiguration.
|
||||
#if defined(ASMJIT_DISABLE_TEXT) && !defined(ASMJIT_DISABLE_LOGGING)
|
||||
# error "[asmjit] ASMJIT_DISABLE_TEXT requires ASMJIT_DISABLE_LOGGING to be defined."
|
||||
#endif // ASMJIT_DISABLE_TEXT && !ASMJIT_DISABLE_LOGGING
|
||||
|
||||
// Detect ASMJIT_DEBUG and ASMJIT_RELEASE if not forced from outside.
|
||||
#if !defined(ASMJIT_DEBUG) && !defined(ASMJIT_RELEASE)
|
||||
# if !defined(NDEBUG)
|
||||
# define ASMJIT_DEBUG
|
||||
# else
|
||||
# define ASMJIT_RELEASE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// ASMJIT_EMBED implies ASMJIT_STATIC.
|
||||
#if defined(ASMJIT_EMBED) && !defined(ASMJIT_STATIC)
|
||||
# define ASMJIT_STATIC
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Build - VERSION]
|
||||
// ============================================================================
|
||||
|
||||
// [@VERSION{@]
|
||||
#define ASMJIT_VERSION_MAJOR 1
|
||||
#define ASMJIT_VERSION_MINOR 0
|
||||
#define ASMJIT_VERSION_PATCH 0
|
||||
#define ASMJIT_VERSION_STRING "1.0.0"
|
||||
// [@VERSION}@]
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Build - WIN32]
|
||||
// ============================================================================
|
||||
|
||||
// [@WIN32_CRT_NO_DEPRECATE{@]
|
||||
#if defined(_MSC_VER) && defined(ASMJIT_EXPORTS)
|
||||
# if !defined(_CRT_SECURE_NO_DEPRECATE)
|
||||
# define _CRT_SECURE_NO_DEPRECATE
|
||||
# endif
|
||||
# if !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
# endif
|
||||
#endif
|
||||
// [@WIN32_CRT_NO_DEPRECATE}@]
|
||||
|
||||
// [@WIN32_LEAN_AND_MEAN{@]
|
||||
#if (defined(_WIN32) || defined(_WINDOWS)) && !defined(_WINDOWS_)
|
||||
# if !defined(WIN32_LEAN_AND_MEAN)
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# if !defined(NOMINMAX)
|
||||
# define NOMINMAX
|
||||
# define ASMJIT_UNDEF_NOMINMAX
|
||||
# endif
|
||||
# include <windows.h>
|
||||
# if defined(ASMJIT_UNDEF_NOMINMAX)
|
||||
# undef NOMINMAX
|
||||
# undef ASMJIT_UNDEF_NOMINMAX
|
||||
# endif
|
||||
# if defined(ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN)
|
||||
# undef WIN32_LEAN_AND_MEAN
|
||||
# undef ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
#endif
|
||||
// [@WIN32_LEAN_AND_MEAN}@]
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Build - OS]
|
||||
// ============================================================================
|
||||
|
||||
// [@OS{@]
|
||||
#if defined(_WIN32) || defined(_WINDOWS)
|
||||
#define ASMJIT_OS_WINDOWS (1)
|
||||
#else
|
||||
#define ASMJIT_OS_WINDOWS (0)
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <TargetConditionals.h>
|
||||
# define ASMJIT_OS_MAC (TARGET_OS_MAC)
|
||||
# define ASMJIT_OS_IOS (TARGET_OS_IPHONE)
|
||||
#else
|
||||
# define ASMJIT_OS_MAC (0)
|
||||
# define ASMJIT_OS_IOS (0)
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
# define ASMJIT_OS_ANDROID (1)
|
||||
#else
|
||||
# define ASMJIT_OS_ANDROID (0)
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__ANDROID__)
|
||||
# define ASMJIT_OS_LINUX (1)
|
||||
#else
|
||||
# define ASMJIT_OS_LINUX (0)
|
||||
#endif
|
||||
|
||||
#if defined(__DragonFly__)
|
||||
# define ASMJIT_OS_DRAGONFLYBSD (1)
|
||||
#else
|
||||
# define ASMJIT_OS_DRAGONFLYBSD (0)
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
# define ASMJIT_OS_FREEBSD (1)
|
||||
#else
|
||||
# define ASMJIT_OS_FREEBSD (0)
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
# define ASMJIT_OS_NETBSD (1)
|
||||
#else
|
||||
# define ASMJIT_OS_NETBSD (0)
|
||||
#endif
|
||||
|
||||
#if defined(__OpenBSD__)
|
||||
# define ASMJIT_OS_OPENBSD (1)
|
||||
#else
|
||||
# define ASMJIT_OS_OPENBSD (0)
|
||||
#endif
|
||||
|
||||
#if defined(__QNXNTO__)
|
||||
# define ASMJIT_OS_QNX (1)
|
||||
#else
|
||||
# define ASMJIT_OS_QNX (0)
|
||||
#endif
|
||||
|
||||
#if defined(__sun)
|
||||
# define ASMJIT_OS_SOLARIS (1)
|
||||
#else
|
||||
# define ASMJIT_OS_SOLARIS (0)
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
# define ASMJIT_OS_CYGWIN (1)
|
||||
#else
|
||||
# define ASMJIT_OS_CYGWIN (0)
|
||||
#endif
|
||||
|
||||
#define ASMJIT_OS_BSD ( \
|
||||
ASMJIT_OS_FREEBSD || \
|
||||
ASMJIT_OS_DRAGONFLYBSD || \
|
||||
ASMJIT_OS_NETBSD || \
|
||||
ASMJIT_OS_OPENBSD || \
|
||||
ASMJIT_OS_MAC)
|
||||
#define ASMJIT_OS_POSIX (!ASMJIT_OS_WINDOWS)
|
||||
// [@OS}@]
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Build - ARCH]
|
||||
// ============================================================================
|
||||
|
||||
// [@ARCH{@]
|
||||
// \def ASMJIT_ARCH_ARM32
|
||||
// True if the target architecture is a 32-bit ARM.
|
||||
//
|
||||
// \def ASMJIT_ARCH_ARM64
|
||||
// True if the target architecture is a 64-bit ARM.
|
||||
//
|
||||
// \def ASMJIT_ARCH_X86
|
||||
// True if the target architecture is a 32-bit X86/IA32
|
||||
//
|
||||
// \def ASMJIT_ARCH_X64
|
||||
// True if the target architecture is a 64-bit X64/AMD64
|
||||
//
|
||||
// \def ASMJIT_ARCH_LE
|
||||
// True if the target architecture is little endian.
|
||||
//
|
||||
// \def ASMJIT_ARCH_BE
|
||||
// True if the target architecture is big endian.
|
||||
//
|
||||
// \def ASMJIT_ARCH_64BIT
|
||||
// True if the target architecture is 64-bit.
|
||||
|
||||
#if (defined(_M_X64 ) || defined(__x86_64) || defined(__x86_64__) || \
|
||||
defined(_M_AMD64) || defined(__amd64 ) || defined(__amd64__ ))
|
||||
# define ASMJIT_ARCH_X64 1
|
||||
#else
|
||||
# define ASMJIT_ARCH_X64 0
|
||||
#endif
|
||||
|
||||
#if (defined(_M_IX86 ) || defined(__X86__ ) || defined(__i386 ) || \
|
||||
defined(__IA32__) || defined(__I86__ ) || defined(__i386__) || \
|
||||
defined(__i486__) || defined(__i586__) || defined(__i686__))
|
||||
# define ASMJIT_ARCH_X86 (!ASMJIT_ARCH_X64)
|
||||
#else
|
||||
# define ASMJIT_ARCH_X86 0
|
||||
#endif
|
||||
|
||||
#if defined(__aarch64__)
|
||||
# define ASMJIT_ARCH_ARM64 1
|
||||
#else
|
||||
# define ASMJIT_ARCH_ARM64 0
|
||||
#endif
|
||||
|
||||
#if (defined(_M_ARM ) || defined(__arm ) || defined(__thumb__ ) || \
|
||||
defined(_M_ARMT ) || defined(__arm__ ) || defined(__thumb2__))
|
||||
# define ASMJIT_ARCH_ARM32 (!ASMJIT_ARCH_ARM64)
|
||||
#else
|
||||
# define ASMJIT_ARCH_ARM32 0
|
||||
#endif
|
||||
|
||||
#define ASMJIT_ARCH_LE ( \
|
||||
ASMJIT_ARCH_X86 || \
|
||||
ASMJIT_ARCH_X64 || \
|
||||
ASMJIT_ARCH_ARM32 || \
|
||||
ASMJIT_ARCH_ARM64 )
|
||||
#define ASMJIT_ARCH_BE (!(ASMJIT_ARCH_LE))
|
||||
#define ASMJIT_ARCH_64BIT (ASMJIT_ARCH_X64 || ASMJIT_ARCH_ARM64)
|
||||
// [@ARCH}@]
|
||||
|
||||
// [@ARCH_UNALIGNED_RW{@]
|
||||
// \def ASMJIT_ARCH_UNALIGNED_16
|
||||
// True if the target architecture allows unaligned 16-bit reads and writes.
|
||||
//
|
||||
// \def ASMJIT_ARCH_UNALIGNED_32
|
||||
// True if the target architecture allows unaligned 32-bit reads and writes.
|
||||
//
|
||||
// \def ASMJIT_ARCH_UNALIGNED_64
|
||||
// True if the target architecture allows unaligned 64-bit reads and writes.
|
||||
|
||||
#define ASMJIT_ARCH_UNALIGNED_16 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64)
|
||||
#define ASMJIT_ARCH_UNALIGNED_32 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64)
|
||||
#define ASMJIT_ARCH_UNALIGNED_64 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64)
|
||||
// [@ARCH_UNALIGNED_RW}@]
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Build - CC]
|
||||
// ============================================================================
|
||||
|
||||
// [@CC{@]
|
||||
// \def ASMJIT_CC_CLANG
|
||||
// Non-zero if the detected C++ compiler is CLANG (contains normalized CLANG version).
|
||||
//
|
||||
// \def ASMJIT_CC_CODEGEAR
|
||||
// Non-zero if the detected C++ compiler is CODEGEAR or BORLAND (version not normalized).
|
||||
//
|
||||
// \def ASMJIT_CC_INTEL
|
||||
// Non-zero if the detected C++ compiler is INTEL (version not normalized).
|
||||
//
|
||||
// \def ASMJIT_CC_GCC
|
||||
// Non-zero if the detected C++ compiler is GCC (contains normalized GCC version).
|
||||
//
|
||||
// \def ASMJIT_CC_MSC
|
||||
// Non-zero if the detected C++ compiler is MSC (contains normalized MSC version).
|
||||
//
|
||||
// \def ASMJIT_CC_MINGW
|
||||
// Non-zero if the detected C++ compiler is MINGW32 (set to 32) or MINGW64 (set to 64).
|
||||
|
||||
#define ASMJIT_CC_CLANG 0
|
||||
#define ASMJIT_CC_CODEGEAR 0
|
||||
#define ASMJIT_CC_GCC 0
|
||||
#define ASMJIT_CC_INTEL 0
|
||||
#define ASMJIT_CC_MSC 0
|
||||
|
||||
// Intel masquerades as GCC, so check for it first.
|
||||
#if defined(__INTEL_COMPILER)
|
||||
# undef ASMJIT_CC_INTEL
|
||||
# define ASMJIT_CC_INTEL __INTEL_COMPILER
|
||||
#elif defined(__CODEGEARC__)
|
||||
# undef ASMJIT_CC_CODEGEAR
|
||||
# define ASMJIT_CC_CODEGEAR (__CODEGEARC__)
|
||||
#elif defined(__BORLANDC__)
|
||||
# undef ASMJIT_CC_CODEGEAR
|
||||
# define ASMJIT_CC_CODEGEAR (__BORLANDC__)
|
||||
#elif defined(__clang__) && defined(__clang_minor__)
|
||||
# undef ASMJIT_CC_CLANG
|
||||
# define ASMJIT_CC_CLANG (__clang_major__ * 10000000 + __clang_minor__ * 100000 + __clang_patchlevel__)
|
||||
#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
|
||||
# undef ASMJIT_CC_GCC
|
||||
# define ASMJIT_CC_GCC (__GNUC__ * 10000000 + __GNUC_MINOR__ * 100000 + __GNUC_PATCHLEVEL__)
|
||||
#elif defined(_MSC_VER) && defined(_MSC_FULL_VER)
|
||||
# undef ASMJIT_CC_MSC
|
||||
# if _MSC_VER == _MSC_FULL_VER / 10000
|
||||
# define ASMJIT_CC_MSC (_MSC_VER * 100000 + (_MSC_FULL_VER % 10000))
|
||||
# else
|
||||
# define ASMJIT_CC_MSC (_MSC_VER * 100000 + (_MSC_FULL_VER % 100000))
|
||||
# endif
|
||||
#else
|
||||
# error "[asmjit] Unable to detect the C/C++ compiler."
|
||||
#endif
|
||||
|
||||
#if ASMJIT_CC_INTEL && (defined(__GNUC__) || defined(__clang__))
|
||||
# define ASMJIT_CC_INTEL_COMPAT_MODE 1
|
||||
# else
|
||||
# define ASMJIT_CC_INTEL_COMPAT_MODE 0
|
||||
#endif
|
||||
|
||||
#define ASMJIT_CC_CODEGEAR_EQ(x, y) (ASMJIT_CC_CODEGEAR == (((x) << 8) + (y)))
|
||||
#define ASMJIT_CC_CODEGEAR_GE(x, y) (ASMJIT_CC_CODEGEAR >= (((x) << 8) + (y)))
|
||||
|
||||
#define ASMJIT_CC_CLANG_EQ(x, y, z) (ASMJIT_CC_CLANG == ((x) * 10000000 + (y) * 100000 + (z)))
|
||||
#define ASMJIT_CC_CLANG_GE(x, y, z) (ASMJIT_CC_CLANG >= ((x) * 10000000 + (y) * 100000 + (z)))
|
||||
|
||||
#define ASMJIT_CC_GCC_EQ(x, y, z) (ASMJIT_CC_GCC == ((x) * 10000000 + (y) * 100000 + (z)))
|
||||
#define ASMJIT_CC_GCC_GE(x, y, z) (ASMJIT_CC_GCC >= ((x) * 10000000 + (y) * 100000 + (z)))
|
||||
|
||||
#define ASMJIT_CC_INTEL_EQ(x, y) (ASMJIT_CC_INTEL == (((x) * 100) + (y)))
|
||||
#define ASMJIT_CC_INTEL_GE(x, y) (ASMJIT_CC_INTEL >= (((x) * 100) + (y)))
|
||||
|
||||
#define ASMJIT_CC_MSC_EQ(x, y, z) (ASMJIT_CC_MSC == ((x) * 10000000 + (y) * 100000 + (z)))
|
||||
#define ASMJIT_CC_MSC_GE(x, y, z) (ASMJIT_CC_MSC >= ((x) * 10000000 + (y) * 100000 + (z)))
|
||||
|
||||
#if defined(__MINGW64__)
|
||||
# define ASMJIT_CC_MINGW 64
|
||||
#elif defined(__MINGW32__)
|
||||
# define ASMJIT_CC_MINGW 32
|
||||
#else
|
||||
# define ASMJIT_CC_MINGW 0
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
# if __cplusplus >= 201103L
|
||||
# define ASMJIT_CC_CXX_VERSION __cplusplus
|
||||
# elif defined(__GXX_EXPERIMENTAL_CXX0X__) || ASMJIT_CC_MSC_GE(18, 0, 0) || ASMJIT_CC_INTEL_GE(14, 0)
|
||||
# define ASMJIT_CC_CXX_VERSION 201103L
|
||||
# else
|
||||
# define ASMJIT_CC_CXX_VERSION 199711L
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(ASMJIT_CC_CXX_VERSION)
|
||||
# define ASMJIT_CC_CXX_VERSION 0
|
||||
#endif
|
||||
// [@CC}@]
|
||||
|
||||
// [@CC_FEATURES{@]
|
||||
#if ASMJIT_CC_CLANG
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE (1)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (__has_attribute(__aligned__))
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (__has_attribute(__always_inline__))
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (__has_attribute(__noinline__))
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (__has_attribute(__noreturn__))
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (__has_attribute(__optimize__))
|
||||
# define ASMJIT_CC_HAS_BUILTIN_ASSUME (__has_builtin(__builtin_assume))
|
||||
# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (__has_builtin(__builtin_assume_aligned))
|
||||
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (__has_builtin(__builtin_expect))
|
||||
# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (__has_builtin(__builtin_unreachable))
|
||||
# define ASMJIT_CC_HAS_ALIGNAS (__has_extension(__cxx_alignas__))
|
||||
# define ASMJIT_CC_HAS_ALIGNOF (__has_extension(__cxx_alignof__))
|
||||
# define ASMJIT_CC_HAS_CONSTEXPR (__has_extension(__cxx_constexpr__))
|
||||
# define ASMJIT_CC_HAS_DECLTYPE (__has_extension(__cxx_decltype__))
|
||||
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (__has_extension(__cxx_defaulted_functions__))
|
||||
# define ASMJIT_CC_HAS_DELETE_FUNCTION (__has_extension(__cxx_deleted_functions__))
|
||||
# define ASMJIT_CC_HAS_FINAL (__has_extension(__cxx_override_control__))
|
||||
# define ASMJIT_CC_HAS_INITIALIZER_LIST (__has_extension(__cxx_generalized_initializers__))
|
||||
# define ASMJIT_CC_HAS_LAMBDA (__has_extension(__cxx_lambdas__))
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
|
||||
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (__has_extension(__cxx_unicode_literals__))
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (__has_extension(__cxx_unicode_literals__))
|
||||
# define ASMJIT_CC_HAS_NOEXCEPT (__has_extension(__cxx_noexcept__))
|
||||
# define ASMJIT_CC_HAS_NULLPTR (__has_extension(__cxx_nullptr__))
|
||||
# define ASMJIT_CC_HAS_OVERRIDE (__has_extension(__cxx_override_control__))
|
||||
# define ASMJIT_CC_HAS_RVALUE (__has_extension(__cxx_rvalue_references__))
|
||||
# define ASMJIT_CC_HAS_STATIC_ASSERT (__has_extension(__cxx_static_assert__))
|
||||
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (__has_extension(__cxx_variadic_templates__))
|
||||
#endif
|
||||
|
||||
#if ASMJIT_CC_CODEGEAR
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (ASMJIT_CC_CODEGEAR >= 0x0610)
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (0)
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (0)
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (ASMJIT_CC_CODEGEAR >= 0x0610)
|
||||
# define ASMJIT_CC_HAS_ALIGNAS (0)
|
||||
# define ASMJIT_CC_HAS_ALIGNOF (0)
|
||||
# define ASMJIT_CC_HAS_CONSTEXPR (0)
|
||||
# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_CODEGEAR >= 0x0610)
|
||||
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (0)
|
||||
# define ASMJIT_CC_HAS_DELETE_FUNCTION (0)
|
||||
# define ASMJIT_CC_HAS_FINAL (0)
|
||||
# define ASMJIT_CC_HAS_INITIALIZER_LIST (0)
|
||||
# define ASMJIT_CC_HAS_LAMBDA (0)
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
|
||||
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (0)
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (0)
|
||||
# define ASMJIT_CC_HAS_NOEXCEPT (0)
|
||||
# define ASMJIT_CC_HAS_NULLPTR (0)
|
||||
# define ASMJIT_CC_HAS_OVERRIDE (0)
|
||||
# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_CODEGEAR >= 0x0610)
|
||||
# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_CODEGEAR >= 0x0610)
|
||||
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (0)
|
||||
#endif
|
||||
|
||||
#if ASMJIT_CC_GCC
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE (1)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (ASMJIT_CC_GCC_GE(2, 7, 0))
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (ASMJIT_CC_GCC_GE(4, 4, 0) && !ASMJIT_CC_MINGW)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (ASMJIT_CC_GCC_GE(3, 4, 0) && !ASMJIT_CC_MINGW)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (ASMJIT_CC_GCC_GE(2, 5, 0))
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (ASMJIT_CC_GCC_GE(4, 4, 0))
|
||||
# define ASMJIT_CC_HAS_BUILTIN_ASSUME (0)
|
||||
# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (ASMJIT_CC_GCC_GE(4, 7, 0))
|
||||
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (1)
|
||||
# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_GCC_GE(4, 7, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
|
||||
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_GCC_GE(4, 7, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
|
||||
#endif
|
||||
|
||||
#if ASMJIT_CC_INTEL
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE (ASMJIT_CC_INTEL_COMPAT_MODE)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (ASMJIT_CC_INTEL_COMPAT_MODE)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (ASMJIT_CC_INTEL_COMPAT_MODE)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (ASMJIT_CC_INTEL_COMPAT_MODE)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (ASMJIT_CC_INTEL_COMPAT_MODE)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (ASMJIT_CC_INTEL_COMPAT_MODE)
|
||||
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (ASMJIT_CC_INTEL_COMPAT_MODE)
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (ASMJIT_CC_INTEL_COMPAT_MODE == 0)
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (ASMJIT_CC_INTEL_COMPAT_MODE == 0)
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (ASMJIT_CC_INTEL_COMPAT_MODE == 0)
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (ASMJIT_CC_INTEL_COMPAT_MODE == 0)
|
||||
# define ASMJIT_CC_HAS_ASSUME (1)
|
||||
# define ASMJIT_CC_HAS_ASSUME_ALIGNED (1)
|
||||
# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_INTEL >= 1500)
|
||||
# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_INTEL >= 1500)
|
||||
# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_INTEL >= 1400)
|
||||
# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_INTEL >= 1200)
|
||||
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_INTEL >= 1200)
|
||||
# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_INTEL >= 1200)
|
||||
# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_INTEL >= 1400)
|
||||
# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_INTEL >= 1400)
|
||||
# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_INTEL >= 1200)
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
|
||||
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_INTEL >= 1400 || (ASMJIT_CC_INTEL_COMPAT_MODE > 0 && ASMJIT_CC_INTEL >= 1206))
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_INTEL >= 1400 || (ASMJIT_CC_INTEL_COMPAT_MODE > 0 && ASMJIT_CC_INTEL >= 1206))
|
||||
# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_INTEL >= 1400)
|
||||
# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_INTEL >= 1206)
|
||||
# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_INTEL >= 1400)
|
||||
# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_INTEL >= 1110)
|
||||
# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_INTEL >= 1110)
|
||||
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_INTEL >= 1206)
|
||||
#endif
|
||||
|
||||
#if ASMJIT_CC_MSC
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (1)
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (1)
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (1)
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (1)
|
||||
# define ASMJIT_CC_HAS_ASSUME (1)
|
||||
# define ASMJIT_CC_HAS_ASSUME_ALIGNED (0)
|
||||
# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_MSC_GE(19, 0, 0))
|
||||
# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_MSC_GE(19, 0, 0))
|
||||
# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_MSC_GE(19, 0, 0))
|
||||
# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_MSC_GE(16, 0, 0))
|
||||
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_MSC_GE(18, 0, 0))
|
||||
# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_MSC_GE(18, 0, 0))
|
||||
# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_MSC_GE(14, 0, 0))
|
||||
# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_MSC_GE(18, 0, 0))
|
||||
# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_MSC_GE(16, 0, 0))
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
|
||||
# if defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
|
||||
# else
|
||||
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (0)
|
||||
# endif
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_MSC_GE(19, 0, 0))
|
||||
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_MSC_GE(19, 0, 0))
|
||||
# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_MSC_GE(19, 0, 0))
|
||||
# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_MSC_GE(16, 0, 0))
|
||||
# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_MSC_GE(14, 0, 0))
|
||||
# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_MSC_GE(16, 0, 0))
|
||||
# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_MSC_GE(16, 0, 0))
|
||||
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_MSC_GE(18, 0, 0))
|
||||
#endif
|
||||
|
||||
// Fixup some vendor specific keywords.
|
||||
#if !defined(ASMJIT_CC_HAS_ASSUME)
|
||||
# define ASMJIT_CC_HAS_ASSUME (0)
|
||||
#endif
|
||||
#if !defined(ASMJIT_CC_HAS_ASSUME_ALIGNED)
|
||||
# define ASMJIT_CC_HAS_ASSUME_ALIGNED (0)
|
||||
#endif
|
||||
|
||||
// Fixup compilers that don't support '__attribute__'.
|
||||
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE (0)
|
||||
#endif
|
||||
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (0)
|
||||
#endif
|
||||
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (0)
|
||||
#endif
|
||||
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (0)
|
||||
#endif
|
||||
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_NORETURN)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (0)
|
||||
#endif
|
||||
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE)
|
||||
# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (0)
|
||||
#endif
|
||||
|
||||
// Fixup compilers that don't support '__builtin?'.
|
||||
#if !defined(ASMJIT_CC_HAS_BUILTIN_ASSUME)
|
||||
# define ASMJIT_CC_HAS_BUILTIN_ASSUME (0)
|
||||
#endif
|
||||
#if !defined(ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED)
|
||||
# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (0)
|
||||
#endif
|
||||
#if !defined(ASMJIT_CC_HAS_BUILTIN_EXPECT)
|
||||
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (0)
|
||||
#endif
|
||||
#if !defined(ASMJIT_CC_HAS_BUILTIN_UNREACHABLE)
|
||||
# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (0)
|
||||
#endif
|
||||
|
||||
// Fixup compilers that don't support 'declspec'.
|
||||
#if !defined(ASMJIT_CC_HAS_DECLSPEC_ALIGN)
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (0)
|
||||
#endif
|
||||
#if !defined(ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE)
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (0)
|
||||
#endif
|
||||
#if !defined(ASMJIT_CC_HAS_DECLSPEC_NOINLINE)
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (0)
|
||||
#endif
|
||||
#if !defined(ASMJIT_CC_HAS_DECLSPEC_NORETURN)
|
||||
# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (0)
|
||||
#endif
|
||||
// [@CC_FEATURES}@]
|
||||
|
||||
// [@CC_API{@]
|
||||
// \def ASMJIT_API
|
||||
// The decorated function is asmjit API and should be exported.
|
||||
#if !defined(ASMJIT_API)
|
||||
# if defined(ASMJIT_STATIC)
|
||||
# define ASMJIT_API
|
||||
# elif ASMJIT_OS_WINDOWS
|
||||
# if (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && !ASMJIT_CC_MINGW
|
||||
# if defined(ASMJIT_EXPORTS)
|
||||
# define ASMJIT_API __attribute__((__dllexport__))
|
||||
# else
|
||||
# define ASMJIT_API __attribute__((__dllimport__))
|
||||
# endif
|
||||
# else
|
||||
# if defined(ASMJIT_EXPORTS)
|
||||
# define ASMJIT_API __declspec(dllexport)
|
||||
# else
|
||||
# define ASMJIT_API __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
# else
|
||||
# if ASMJIT_CC_CLANG || ASMJIT_CC_GCC_GE(4, 0, 0) || ASMJIT_CC_INTEL
|
||||
# define ASMJIT_API __attribute__((__visibility__("default")))
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
// [@CC_API}@]
|
||||
|
||||
// [@CC_VARAPI{@]
|
||||
// \def ASMJIT_VARAPI
|
||||
// The decorated variable is part of asmjit API and is exported.
|
||||
#if !defined(ASMJIT_VARAPI)
|
||||
# define ASMJIT_VARAPI extern ASMJIT_API
|
||||
#endif
|
||||
// [@CC_VARAPI}@]
|
||||
|
||||
// [@CC_VIRTAPI{@]
|
||||
// \def ASMJIT_VIRTAPI
|
||||
// The decorated class has a virtual table and is part of asmjit API.
|
||||
//
|
||||
// This is basically a workaround. When using MSVC and marking class as DLL
|
||||
// export everything gets exported, which is unwanted in most projects. MSVC
|
||||
// automatically exports typeinfo and vtable if at least one symbol of the
|
||||
// class is exported. However, GCC has some strange behavior that even if
|
||||
// one or more symbol is exported it doesn't export typeinfo unless the
|
||||
// class itself is decorated with "visibility(default)" (i.e. asmjit_API).
|
||||
#if (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && !ASMJIT_OS_WINDOWS
|
||||
# define ASMJIT_VIRTAPI ASMJIT_API
|
||||
#else
|
||||
# define ASMJIT_VIRTAPI
|
||||
#endif
|
||||
// [@CC_VIRTAPI}@]
|
||||
|
||||
// [@CC_INLINE{@]
|
||||
// \def ASMJIT_INLINE
|
||||
// Always inline the decorated function.
|
||||
#if ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE
|
||||
# define ASMJIT_INLINE inline __attribute__((__always_inline__))
|
||||
#elif ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE
|
||||
# define ASMJIT_INLINE __forceinline
|
||||
#else
|
||||
# define ASMJIT_INLINE inline
|
||||
#endif
|
||||
// [@CC_INLINE}@]
|
||||
|
||||
// [@CC_NOINLINE{@]
|
||||
// \def ASMJIT_NOINLINE
|
||||
// Never inline the decorated function.
|
||||
#if ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE
|
||||
# define ASMJIT_NOINLINE __attribute__((__noinline__))
|
||||
#elif ASMJIT_CC_HAS_DECLSPEC_NOINLINE
|
||||
# define ASMJIT_NOINLINE __declspec(noinline)
|
||||
#else
|
||||
# define ASMJIT_NOINLINE
|
||||
#endif
|
||||
// [@CC_NOINLINE}@]
|
||||
|
||||
// [@CC_NORETURN{@]
|
||||
// \def ASMJIT_NORETURN
|
||||
// The decorated function never returns (exit, assertion failure, etc...).
|
||||
#if ASMJIT_CC_HAS_ATTRIBUTE_NORETURN
|
||||
# define ASMJIT_NORETURN __attribute__((__noreturn__))
|
||||
#elif ASMJIT_CC_HAS_DECLSPEC_NORETURN
|
||||
# define ASMJIT_NORETURN __declspec(noreturn)
|
||||
#else
|
||||
# define ASMJIT_NORETURN
|
||||
#endif
|
||||
// [@CC_NORETURN}@]
|
||||
|
||||
// [@CC_CDECL{@]
|
||||
// \def ASMJIT_CDECL
|
||||
// Standard C function calling convention decorator (__cdecl).
|
||||
#if ASMJIT_ARCH_X86
|
||||
# if ASMJIT_CC_HAS_ATTRIBUTE
|
||||
# define ASMJIT_CDECL __attribute__((__cdecl__))
|
||||
# else
|
||||
# define ASMJIT_CDECL __cdecl
|
||||
# endif
|
||||
#else
|
||||
# define ASMJIT_CDECL
|
||||
#endif
|
||||
// [@CC_CDECL}@]
|
||||
|
||||
// [@CC_STDCALL{@]
|
||||
// \def ASMJIT_STDCALL
|
||||
// StdCall function calling convention decorator (__stdcall).
|
||||
#if ASMJIT_ARCH_X86
|
||||
# if ASMJIT_CC_HAS_ATTRIBUTE
|
||||
# define ASMJIT_STDCALL __attribute__((__stdcall__))
|
||||
# else
|
||||
# define ASMJIT_STDCALL __stdcall
|
||||
# endif
|
||||
#else
|
||||
# define ASMJIT_STDCALL
|
||||
#endif
|
||||
// [@CC_STDCALL}@]
|
||||
|
||||
// [@CC_FASTCALL{@]
|
||||
// \def ASMJIT_FASTCALL
|
||||
// FastCall function calling convention decorator (__fastcall).
|
||||
#if ASMJIT_ARCH_X86
|
||||
# if ASMJIT_CC_HAS_ATTRIBUTE
|
||||
# define ASMJIT_FASTCALL __attribute__((__fastcall__))
|
||||
# else
|
||||
# define ASMJIT_FASTCALL __fastcall
|
||||
# endif
|
||||
#else
|
||||
# define ASMJIT_FASTCALL
|
||||
#endif
|
||||
// [@CC_FASTCALL}@]
|
||||
|
||||
// [@CC_REGPARM{@]
|
||||
// \def ASMJIT_REGPARM(n)
|
||||
// A custom calling convention which passes n arguments in registers.
|
||||
#if ASMJIT_ARCH_X86 && ASMJIT_CC_HAS_ATTRIBUTE
|
||||
# define ASMJIT_REGPARM(n) __attribute__((__regparm__(n)))
|
||||
#else
|
||||
# define ASMJIT_REGPARM(n)
|
||||
#endif
|
||||
// [@CC_REGPARM}@]
|
||||
|
||||
// [@CC_NOEXCEPT{@]
|
||||
// \def ASMJIT_NOEXCEPT
|
||||
// The decorated function never throws an exception (noexcept).
|
||||
#if ASMJIT_CC_HAS_NOEXCEPT
|
||||
# define ASMJIT_NOEXCEPT noexcept
|
||||
#else
|
||||
# define ASMJIT_NOEXCEPT
|
||||
#endif
|
||||
// [@CC_NOEXCEPT}@]
|
||||
|
||||
// [@CC_NOP{@]
|
||||
// \def ASMJIT_NOP
|
||||
// No operation.
|
||||
#if !defined(ASMJIT_NOP)
|
||||
# define ASMJIT_NOP ((void)0)
|
||||
#endif
|
||||
// [@CC_NOP}@]
|
||||
|
||||
// [@CC_ASSUME{@]
|
||||
// \def ASMJIT_ASSUME(exp)
|
||||
// Assume that the expression exp is always true.
|
||||
#if ASMJIT_CC_HAS_ASSUME
|
||||
# define ASMJIT_ASSUME(exp) __assume(exp)
|
||||
#elif ASMJIT_CC_HAS_BUILTIN_ASSUME
|
||||
# define ASMJIT_ASSUME(exp) __builtin_assume(exp)
|
||||
#elif ASMJIT_CC_HAS_BUILTIN_UNREACHABLE
|
||||
# define ASMJIT_ASSUME(exp) do { if (!(exp)) __builtin_unreachable(); } while (0)
|
||||
#else
|
||||
# define ASMJIT_ASSUME(exp) ((void)0)
|
||||
#endif
|
||||
// [@CC_ASSUME}@]
|
||||
|
||||
// [@CC_ASSUME_ALIGNED{@]
|
||||
// \def ASMJIT_ASSUME_ALIGNED(p, alignment)
|
||||
// Assume that the pointer 'p' is aligned to at least 'alignment' bytes.
|
||||
#if ASMJIT_CC_HAS_ASSUME_ALIGNED
|
||||
# define ASMJIT_ASSUME_ALIGNED(p, alignment) __assume_aligned(p, alignment)
|
||||
#elif ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED
|
||||
# define ASMJIT_ASSUME_ALIGNED(p, alignment) p = __builtin_assume_aligned(p, alignment)
|
||||
#else
|
||||
# define ASMJIT_ASSUME_ALIGNED(p, alignment) ((void)0)
|
||||
#endif
|
||||
// [@CC_ASSUME_ALIGNED}@]
|
||||
|
||||
// [@CC_EXPECT{@]
|
||||
// \def ASMJIT_LIKELY(exp)
|
||||
// Expression exp is likely to be true.
|
||||
//
|
||||
// \def ASMJIT_UNLIKELY(exp)
|
||||
// Expression exp is likely to be false.
|
||||
#if ASMJIT_CC_HAS_BUILTIN_EXPECT
|
||||
# define ASMJIT_LIKELY(exp) __builtin_expect(!!(exp), 1)
|
||||
# define ASMJIT_UNLIKELY(exp) __builtin_expect(!!(exp), 0)
|
||||
#else
|
||||
# define ASMJIT_LIKELY(exp) (exp)
|
||||
# define ASMJIT_UNLIKELY(exp) (exp)
|
||||
#endif
|
||||
// [@CC_EXPECT}@]
|
||||
|
||||
// [@CC_FALLTHROUGH{@]
|
||||
// \def ASMJIT_FALLTHROUGH
|
||||
// The code falls through annotation (switch / case).
|
||||
#if ASMJIT_CC_CLANG && __cplusplus >= 201103L
|
||||
# define ASMJIT_FALLTHROUGH [[clang::fallthrough]]
|
||||
#else
|
||||
# define ASMJIT_FALLTHROUGH (void)0
|
||||
#endif
|
||||
// [@CC_FALLTHROUGH}@]
|
||||
|
||||
// [@CC_UNUSED{@]
|
||||
// \def ASMJIT_UNUSED(x)
|
||||
// Mark a variable x as unused.
|
||||
#define ASMJIT_UNUSED(x) (void)(x)
|
||||
// [@CC_UNUSED}@]
|
||||
|
||||
// [@CC_OFFSET_OF{@]
|
||||
// \def ASMJIT_OFFSET_OF(x, y).
|
||||
// Get the offset of a member y of a struct x at compile-time.
|
||||
#define ASMJIT_OFFSET_OF(x, y) ((int)(intptr_t)((const char*)&((const x*)0x1)->y) - 1)
|
||||
// [@CC_OFFSET_OF}@]
|
||||
|
||||
// [@CC_ARRAY_SIZE{@]
|
||||
// \def ASMJIT_ARRAY_SIZE(x)
|
||||
// Get the array size of x at compile-time.
|
||||
#define ASMJIT_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
// [@CC_ARRAY_SIZE}@]
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Build - STDTYPES]
|
||||
// ============================================================================
|
||||
|
||||
// [@STDTYPES{@]
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1600)
|
||||
# include <limits.h>
|
||||
# if !defined(ASMJIT_SUPPRESS_STD_TYPES)
|
||||
# if (_MSC_VER < 1300)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
# else
|
||||
typedef __int8 int8_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
# endif
|
||||
# endif
|
||||
#else
|
||||
# include <stdint.h>
|
||||
# include <limits.h>
|
||||
#endif
|
||||
// [@STDTYPES}@]
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Build - Dependencies]
|
||||
// ============================================================================
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <new>
|
||||
|
||||
#if ASMJIT_OS_POSIX
|
||||
# include <pthread.h>
|
||||
#endif // ASMJIT_OS_POSIX
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Build - Additional]
|
||||
// ============================================================================
|
||||
|
||||
// Build host architecture if no architecture is selected.
|
||||
#if !defined(ASMJIT_BUILD_HOST) && \
|
||||
!defined(ASMJIT_BUILD_X86) && \
|
||||
!defined(ASMJIT_BUILD_ARM)
|
||||
# define ASMJIT_BUILD_HOST
|
||||
#endif
|
||||
|
||||
// Detect host architecture if building only for host.
|
||||
#if defined(ASMJIT_BUILD_HOST)
|
||||
# if (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && !defined(ASMJIT_BUILD_X86)
|
||||
# define ASMJIT_BUILD_X86
|
||||
# endif // ASMJIT_ARCH_X86
|
||||
#endif // ASMJIT_BUILD_HOST
|
||||
|
||||
#if ASMJIT_CC_MSC
|
||||
# define ASMJIT_UINT64_C(x) x##ui64
|
||||
#else
|
||||
# define ASMJIT_UINT64_C(x) x##ull
|
||||
#endif
|
||||
|
||||
#if ASMJIT_ARCH_LE
|
||||
# define ASMJIT_PACK32_4x8(A, B, C, D) ((A) + ((B) << 8) + ((C) << 16) + ((D) << 24))
|
||||
#else
|
||||
# define ASMJIT_PACK32_4x8(A, B, C, D) ((D) + ((C) << 8) + ((B) << 16) + ((A) << 24))
|
||||
#endif
|
||||
|
||||
// Internal macros that are only used when building AsmJit itself.
|
||||
#if defined(ASMJIT_EXPORTS)
|
||||
# if !defined(ASMJIT_DEBUG) && ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE
|
||||
# define ASMJIT_FAVOR_SIZE __attribute__((__optimize__("Os")))
|
||||
# else
|
||||
# define ASMJIT_FAVOR_SIZE
|
||||
# endif
|
||||
#endif // ASMJIT_EXPORTS
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Build - Test]
|
||||
// ============================================================================
|
||||
|
||||
// Include a unit testing package if this is a `asmjit_test` build.
|
||||
#if defined(ASMJIT_TEST)
|
||||
# include "../../test/broken.h"
|
||||
#endif // ASMJIT_TEST
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BUILD_H
|
|
@ -1,34 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_H
|
||||
#define _ASMJIT_BASE_H
|
||||
|
||||
// [Dependencies]
|
||||
#include "./base/arch.h"
|
||||
#include "./base/assembler.h"
|
||||
#include "./base/codebuilder.h"
|
||||
#include "./base/codecompiler.h"
|
||||
#include "./base/codeemitter.h"
|
||||
#include "./base/codeholder.h"
|
||||
#include "./base/constpool.h"
|
||||
#include "./base/cpuinfo.h"
|
||||
#include "./base/func.h"
|
||||
#include "./base/globals.h"
|
||||
#include "./base/inst.h"
|
||||
#include "./base/logging.h"
|
||||
#include "./base/operand.h"
|
||||
#include "./base/osutils.h"
|
||||
#include "./base/runtime.h"
|
||||
#include "./base/simdtypes.h"
|
||||
#include "./base/string.h"
|
||||
#include "./base/utils.h"
|
||||
#include "./base/vmem.h"
|
||||
#include "./base/zone.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_H
|
|
@ -1,161 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/arch.h"
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
#include "../x86/x86operand.h"
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ArchInfo]
|
||||
// ============================================================================
|
||||
|
||||
static const uint32_t archInfoTable[] = {
|
||||
// <-------------+---------------------+-----------------------+-------+
|
||||
// | Type | SubType | GPInfo|
|
||||
// <-------------+---------------------+-----------------------+-------+
|
||||
ASMJIT_PACK32_4x8(ArchInfo::kTypeNone , ArchInfo::kSubTypeNone, 0, 0),
|
||||
ASMJIT_PACK32_4x8(ArchInfo::kTypeX86 , ArchInfo::kSubTypeNone, 4, 8),
|
||||
ASMJIT_PACK32_4x8(ArchInfo::kTypeX64 , ArchInfo::kSubTypeNone, 8, 16),
|
||||
ASMJIT_PACK32_4x8(ArchInfo::kTypeX32 , ArchInfo::kSubTypeNone, 8, 16),
|
||||
ASMJIT_PACK32_4x8(ArchInfo::kTypeA32 , ArchInfo::kSubTypeNone, 4, 16),
|
||||
ASMJIT_PACK32_4x8(ArchInfo::kTypeA64 , ArchInfo::kSubTypeNone, 8, 32)
|
||||
};
|
||||
|
||||
ASMJIT_FAVOR_SIZE void ArchInfo::init(uint32_t type, uint32_t subType) noexcept {
|
||||
uint32_t index = type < ASMJIT_ARRAY_SIZE(archInfoTable) ? type : uint32_t(0);
|
||||
|
||||
// Make sure the `archInfoTable` array is correctly indexed.
|
||||
_signature = archInfoTable[index];
|
||||
ASMJIT_ASSERT(_type == index);
|
||||
|
||||
// Even if the architecture is not known we setup its type and sub-type,
|
||||
// however, such architecture is not really useful.
|
||||
_type = type;
|
||||
_subType = subType;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ArchUtils]
|
||||
// ============================================================================
|
||||
|
||||
ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegInfo(uint32_t archType, uint32_t& typeIdInOut, RegInfo& regInfo) noexcept {
|
||||
uint32_t typeId = typeIdInOut;
|
||||
|
||||
// Zero the signature so it's clear in case that typeId is not invalid.
|
||||
regInfo._signature = 0;
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
if (ArchInfo::isX86Family(archType)) {
|
||||
// Passed RegType instead of TypeId?
|
||||
if (typeId <= Reg::kRegMax)
|
||||
typeId = x86OpData.archRegs.regTypeToTypeId[typeId];
|
||||
|
||||
if (ASMJIT_UNLIKELY(!TypeId::isValid(typeId)))
|
||||
return DebugUtils::errored(kErrorInvalidTypeId);
|
||||
|
||||
// First normalize architecture dependent types.
|
||||
if (TypeId::isAbstract(typeId)) {
|
||||
if (typeId == TypeId::kIntPtr)
|
||||
typeId = (archType == ArchInfo::kTypeX86) ? TypeId::kI32 : TypeId::kI64;
|
||||
else
|
||||
typeId = (archType == ArchInfo::kTypeX86) ? TypeId::kU32 : TypeId::kU64;
|
||||
}
|
||||
|
||||
// Type size helps to construct all kinds of registers. If the size is zero
|
||||
// then the TypeId is invalid.
|
||||
uint32_t size = TypeId::sizeOf(typeId);
|
||||
if (ASMJIT_UNLIKELY(!size))
|
||||
return DebugUtils::errored(kErrorInvalidTypeId);
|
||||
|
||||
if (ASMJIT_UNLIKELY(typeId == TypeId::kF80))
|
||||
return DebugUtils::errored(kErrorInvalidUseOfF80);
|
||||
|
||||
uint32_t regType = 0;
|
||||
|
||||
switch (typeId) {
|
||||
case TypeId::kI8:
|
||||
case TypeId::kU8:
|
||||
regType = X86Reg::kRegGpbLo;
|
||||
break;
|
||||
|
||||
case TypeId::kI16:
|
||||
case TypeId::kU16:
|
||||
regType = X86Reg::kRegGpw;
|
||||
break;
|
||||
|
||||
case TypeId::kI32:
|
||||
case TypeId::kU32:
|
||||
regType = X86Reg::kRegGpd;
|
||||
break;
|
||||
|
||||
case TypeId::kI64:
|
||||
case TypeId::kU64:
|
||||
if (archType == ArchInfo::kTypeX86)
|
||||
return DebugUtils::errored(kErrorInvalidUseOfGpq);
|
||||
|
||||
regType = X86Reg::kRegGpq;
|
||||
break;
|
||||
|
||||
// F32 and F64 are always promoted to use vector registers.
|
||||
case TypeId::kF32:
|
||||
typeId = TypeId::kF32x1;
|
||||
regType = X86Reg::kRegXmm;
|
||||
break;
|
||||
|
||||
case TypeId::kF64:
|
||||
typeId = TypeId::kF64x1;
|
||||
regType = X86Reg::kRegXmm;
|
||||
break;
|
||||
|
||||
// Mask registers {k}.
|
||||
case TypeId::kMask8:
|
||||
case TypeId::kMask16:
|
||||
case TypeId::kMask32:
|
||||
case TypeId::kMask64:
|
||||
regType = X86Reg::kRegK;
|
||||
break;
|
||||
|
||||
// MMX registers.
|
||||
case TypeId::kMmx32:
|
||||
case TypeId::kMmx64:
|
||||
regType = X86Reg::kRegMm;
|
||||
break;
|
||||
|
||||
// XMM|YMM|ZMM registers.
|
||||
default:
|
||||
if (size <= 16)
|
||||
regType = X86Reg::kRegXmm;
|
||||
else if (size == 32)
|
||||
regType = X86Reg::kRegYmm;
|
||||
else
|
||||
regType = X86Reg::kRegZmm;
|
||||
break;
|
||||
}
|
||||
|
||||
typeIdInOut = typeId;
|
||||
regInfo._signature = x86OpData.archRegs.regInfo[regType].getSignature();
|
||||
return kErrorOk;
|
||||
}
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
return DebugUtils::errored(kErrorInvalidArch);
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
|
@ -1,199 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_ARCH_H
|
||||
#define _ASMJIT_BASE_ARCH_H
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/globals.h"
|
||||
#include "../base/operand.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! \addtogroup asmjit_base
|
||||
//! \{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ArchInfo]
|
||||
// ============================================================================
|
||||
|
||||
class ArchInfo {
|
||||
public:
|
||||
//! Architecture type.
|
||||
ASMJIT_ENUM(Type) {
|
||||
kTypeNone = 0, //!< No/Unknown architecture.
|
||||
|
||||
// X86 architectures.
|
||||
kTypeX86 = 1, //!< X86 architecture (32-bit).
|
||||
kTypeX64 = 2, //!< X64 architecture (64-bit) (AMD64).
|
||||
kTypeX32 = 3, //!< X32 architecture (DEAD-END).
|
||||
|
||||
// ARM architectures.
|
||||
kTypeA32 = 4, //!< ARM 32-bit architecture (AArch32/ARM/THUMB).
|
||||
kTypeA64 = 5, //!< ARM 64-bit architecture (AArch64).
|
||||
|
||||
//! Architecture detected at compile-time (architecture of the host).
|
||||
kTypeHost = ASMJIT_ARCH_X86 ? kTypeX86 :
|
||||
ASMJIT_ARCH_X64 ? kTypeX64 :
|
||||
ASMJIT_ARCH_ARM32 ? kTypeA32 :
|
||||
ASMJIT_ARCH_ARM64 ? kTypeA64 : kTypeNone
|
||||
};
|
||||
|
||||
//! Architecture sub-type or execution mode.
|
||||
ASMJIT_ENUM(SubType) {
|
||||
kSubTypeNone = 0, //!< Default mode (or no specific mode).
|
||||
|
||||
// X86 sub-types.
|
||||
kSubTypeX86_AVX = 1, //!< Code generation uses AVX by default (VEC instructions).
|
||||
kSubTypeX86_AVX2 = 2, //!< Code generation uses AVX2 by default (VEC instructions).
|
||||
kSubTypeX86_AVX512 = 3, //!< Code generation uses AVX-512F by default (+32 vector regs).
|
||||
kSubTypeX86_AVX512VL = 4, //!< Code generation uses AVX-512F-VL by default (+VL extensions).
|
||||
|
||||
// ARM sub-types.
|
||||
kSubTypeA32_Thumb = 8, //!< THUMB|THUMB2 sub-type (only ARM in 32-bit mode).
|
||||
|
||||
#if (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX512VL__)
|
||||
kSubTypeHost = kSubTypeX86_AVX512VL
|
||||
#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX512F__)
|
||||
kSubTypeHost = kSubTypeX86_AVX512
|
||||
#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX2__)
|
||||
kSubTypeHost = kSubTypeX86_AVX2
|
||||
#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX__)
|
||||
kSubTypeHost = kSubTypeX86_AVX
|
||||
#elif (ASMJIT_ARCH_ARM32) && (defined(_M_ARMT) || defined(__thumb__) || defined(__thumb2__))
|
||||
kSubTypeHost = kSubTypeA32_Thumb
|
||||
#else
|
||||
kSubTypeHost = 0
|
||||
#endif
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Utilities]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
static ASMJIT_INLINE bool isX86Family(uint32_t archType) noexcept { return archType >= kTypeX86 && archType <= kTypeX32; }
|
||||
static ASMJIT_INLINE bool isArmFamily(uint32_t archType) noexcept { return archType >= kTypeA32 && archType <= kTypeA64; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE ArchInfo() noexcept : _signature(0) {}
|
||||
ASMJIT_INLINE ArchInfo(const ArchInfo& other) noexcept : _signature(other._signature) {}
|
||||
explicit ASMJIT_INLINE ArchInfo(uint32_t type, uint32_t subType = kSubTypeNone) noexcept { init(type, subType); }
|
||||
|
||||
ASMJIT_INLINE static ArchInfo host() noexcept { return ArchInfo(kTypeHost, kSubTypeHost); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Init / Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE bool isInitialized() const noexcept { return _type != kTypeNone; }
|
||||
|
||||
ASMJIT_API void init(uint32_t type, uint32_t subType = kSubTypeNone) noexcept;
|
||||
ASMJIT_INLINE void reset() noexcept { _signature = 0; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get if the architecture is 32-bit.
|
||||
ASMJIT_INLINE bool is32Bit() const noexcept { return _gpSize == 4; }
|
||||
//! Get if the architecture is 64-bit.
|
||||
ASMJIT_INLINE bool is64Bit() const noexcept { return _gpSize == 8; }
|
||||
|
||||
//! Get architecture type, see \ref Type.
|
||||
ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
|
||||
|
||||
//! Get architecture sub-type, see \ref SubType.
|
||||
//!
|
||||
//! X86 & X64
|
||||
//! ---------
|
||||
//!
|
||||
//! Architecture subtype describe the highest instruction-set level that can
|
||||
//! be used.
|
||||
//!
|
||||
//! ARM32
|
||||
//! -----
|
||||
//!
|
||||
//! Architecture mode means the instruction encoding to be used when generating
|
||||
//! machine code, thus mode can be used to force generation of THUMB and THUMB2
|
||||
//! encoding or regular ARM encoding.
|
||||
//!
|
||||
//! ARM64
|
||||
//! -----
|
||||
//!
|
||||
//! No meaning yet.
|
||||
ASMJIT_INLINE uint32_t getSubType() const noexcept { return _subType; }
|
||||
|
||||
//! Get if the architecture is X86, X64, or X32.
|
||||
ASMJIT_INLINE bool isX86Family() const noexcept { return isX86Family(_type); }
|
||||
//! Get if the architecture is ARM32 or ARM64.
|
||||
ASMJIT_INLINE bool isArmFamily() const noexcept { return isArmFamily(_type); }
|
||||
|
||||
//! Get a size of a general-purpose register.
|
||||
ASMJIT_INLINE uint32_t getGpSize() const noexcept { return _gpSize; }
|
||||
//! Get number of general-purpose registers.
|
||||
ASMJIT_INLINE uint32_t getGpCount() const noexcept { return _gpCount; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Operator Overload]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE const ArchInfo& operator=(const ArchInfo& other) noexcept { _signature = other._signature; return *this; }
|
||||
ASMJIT_INLINE bool operator==(const ArchInfo& other) const noexcept { return _signature == other._signature; }
|
||||
ASMJIT_INLINE bool operator!=(const ArchInfo& other) const noexcept { return _signature != other._signature; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint8_t _type; //!< Architecture type.
|
||||
uint8_t _subType; //!< Architecture sub-type.
|
||||
uint8_t _gpSize; //!< Default size of a general purpose register.
|
||||
uint8_t _gpCount; //!< Count of all general purpose registers.
|
||||
};
|
||||
uint32_t _signature; //!< Architecture signature (32-bit int).
|
||||
};
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ArchRegs]
|
||||
// ============================================================================
|
||||
|
||||
//! Information about all architecture registers.
|
||||
struct ArchRegs {
|
||||
//! Register information and signatures indexed by \ref Reg::Type.
|
||||
RegInfo regInfo[Reg::kRegMax + 1];
|
||||
//! Count (maximum) of registers per \ref Reg::Type.
|
||||
uint8_t regCount[Reg::kRegMax + 1];
|
||||
//! Converts RegType to TypeId, see \ref TypeId::Id.
|
||||
uint8_t regTypeToTypeId[Reg::kRegMax + 1];
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ArchUtils]
|
||||
// ============================================================================
|
||||
|
||||
struct ArchUtils {
|
||||
ASMJIT_API static Error typeIdToRegInfo(uint32_t archType, uint32_t& typeIdInOut, RegInfo& regInfo) noexcept;
|
||||
};
|
||||
|
||||
//! \}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_ARCH_H
|
|
@ -1,447 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/assembler.h"
|
||||
#include "../base/constpool.h"
|
||||
#include "../base/utils.h"
|
||||
#include "../base/vmem.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Assembler - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
Assembler::Assembler() noexcept
|
||||
: CodeEmitter(kTypeAssembler),
|
||||
_section(nullptr),
|
||||
_bufferData(nullptr),
|
||||
_bufferEnd(nullptr),
|
||||
_bufferPtr(nullptr),
|
||||
_op4(),
|
||||
_op5() {}
|
||||
|
||||
Assembler::~Assembler() noexcept {
|
||||
if (_code) sync();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Assembler - Events]
|
||||
// ============================================================================
|
||||
|
||||
Error Assembler::onAttach(CodeHolder* code) noexcept {
|
||||
// Attach to the end of the .text section.
|
||||
_section = code->_sections[0];
|
||||
uint8_t* p = _section->_buffer._data;
|
||||
|
||||
_bufferData = p;
|
||||
_bufferEnd = p + _section->_buffer._capacity;
|
||||
_bufferPtr = p + _section->_buffer._length;
|
||||
|
||||
_op4.reset();
|
||||
_op5.reset();
|
||||
|
||||
return Base::onAttach(code);
|
||||
}
|
||||
|
||||
Error Assembler::onDetach(CodeHolder* code) noexcept {
|
||||
_section = nullptr;
|
||||
_bufferData = nullptr;
|
||||
_bufferEnd = nullptr;
|
||||
_bufferPtr = nullptr;
|
||||
|
||||
_op4.reset();
|
||||
_op5.reset();
|
||||
|
||||
return Base::onDetach(code);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Assembler - Code-Generation]
|
||||
// ============================================================================
|
||||
|
||||
Error Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) {
|
||||
_op4 = o4;
|
||||
_op5 = o5;
|
||||
_options |= kOptionOp4Op5Used;
|
||||
return _emit(instId, o0, o1, o2, o3);
|
||||
}
|
||||
|
||||
Error Assembler::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
|
||||
const Operand_* op = opArray;
|
||||
switch (opCount) {
|
||||
case 0: return _emit(instId, _none, _none, _none, _none);
|
||||
case 1: return _emit(instId, op[0], _none, _none, _none);
|
||||
case 2: return _emit(instId, op[0], op[1], _none, _none);
|
||||
case 3: return _emit(instId, op[0], op[1], op[2], _none);
|
||||
case 4: return _emit(instId, op[0], op[1], op[2], op[3]);
|
||||
|
||||
case 5:
|
||||
_op4 = op[4];
|
||||
_op5.reset();
|
||||
_options |= kOptionOp4Op5Used;
|
||||
return _emit(instId, op[0], op[1], op[2], op[3]);
|
||||
|
||||
case 6:
|
||||
_op4 = op[4];
|
||||
_op5 = op[5];
|
||||
_options |= kOptionOp4Op5Used;
|
||||
return _emit(instId, op[0], op[1], op[2], op[3]);
|
||||
|
||||
default:
|
||||
return DebugUtils::errored(kErrorInvalidArgument);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Assembler - Sync]
|
||||
// ============================================================================
|
||||
|
||||
void Assembler::sync() noexcept {
|
||||
ASMJIT_ASSERT(_code != nullptr); // Only called by CodeHolder, so we must be attached.
|
||||
ASMJIT_ASSERT(_section != nullptr); // One section must always be active, no matter what.
|
||||
ASMJIT_ASSERT(_bufferData == _section->_buffer._data); // `_bufferStart` is a shortcut to `_section->buffer.data`.
|
||||
|
||||
// Update only if the current offset is greater than the section length.
|
||||
size_t offset = (size_t)(_bufferPtr - _bufferData);
|
||||
if (_section->getBuffer().getLength() < offset)
|
||||
_section->_buffer._length = offset;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Assembler - Code-Buffer]
|
||||
// ============================================================================
|
||||
|
||||
Error Assembler::setOffset(size_t offset) {
|
||||
if (_lastError) return _lastError;
|
||||
|
||||
size_t length = std::max(_section->getBuffer().getLength(), getOffset());
|
||||
if (ASMJIT_UNLIKELY(offset > length))
|
||||
return setLastError(DebugUtils::errored(kErrorInvalidArgument));
|
||||
|
||||
// If the `Assembler` generated any code the `_bufferPtr` may be higher than
|
||||
// the section length stored in `CodeHolder` as it doesn't update it each
|
||||
// time it generates machine code. This is the same as calling `sync()`.
|
||||
if (_section->_buffer._length < length)
|
||||
_section->_buffer._length = length;
|
||||
|
||||
_bufferPtr = _bufferData + offset;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Assembler - Comment]
|
||||
// ============================================================================
|
||||
|
||||
Error Assembler::comment(const char* s, size_t len) {
|
||||
if (_lastError) return _lastError;
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
if (_globalOptions & kOptionLoggingEnabled) {
|
||||
Logger* logger = _code->getLogger();
|
||||
logger->log(s, len);
|
||||
logger->log("\n", 1);
|
||||
return kErrorOk;
|
||||
}
|
||||
#else
|
||||
ASMJIT_UNUSED(s);
|
||||
ASMJIT_UNUSED(len);
|
||||
#endif
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Assembler - Building Blocks]
|
||||
// ============================================================================
|
||||
|
||||
Label Assembler::newLabel() {
|
||||
uint32_t id = 0;
|
||||
if (!_lastError) {
|
||||
ASMJIT_ASSERT(_code != nullptr);
|
||||
Error err = _code->newLabelId(id);
|
||||
if (ASMJIT_UNLIKELY(err)) setLastError(err);
|
||||
}
|
||||
return Label(id);
|
||||
}
|
||||
|
||||
Label Assembler::newNamedLabel(const char* name, size_t nameLength, uint32_t type, uint32_t parentId) {
|
||||
uint32_t id = 0;
|
||||
if (!_lastError) {
|
||||
ASMJIT_ASSERT(_code != nullptr);
|
||||
Error err = _code->newNamedLabelId(id, name, nameLength, type, parentId);
|
||||
if (ASMJIT_UNLIKELY(err)) setLastError(err);
|
||||
}
|
||||
return Label(id);
|
||||
}
|
||||
|
||||
Error Assembler::bind(const Label& label) {
|
||||
if (_lastError) return _lastError;
|
||||
ASMJIT_ASSERT(_code != nullptr);
|
||||
|
||||
LabelEntry* le = _code->getLabelEntry(label);
|
||||
if (ASMJIT_UNLIKELY(!le))
|
||||
return setLastError(DebugUtils::errored(kErrorInvalidLabel));
|
||||
|
||||
// Label can be bound only once.
|
||||
if (ASMJIT_UNLIKELY(le->isBound()))
|
||||
return setLastError(DebugUtils::errored(kErrorLabelAlreadyBound));
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
if (_globalOptions & kOptionLoggingEnabled) {
|
||||
StringBuilderTmp<256> sb;
|
||||
if (le->hasName())
|
||||
sb.setFormat("%s:", le->getName());
|
||||
else
|
||||
sb.setFormat("L%u:", Operand::unpackId(label.getId()));
|
||||
|
||||
size_t binSize = 0;
|
||||
if (!_code->_logger->hasOption(Logger::kOptionBinaryForm))
|
||||
binSize = Globals::kInvalidIndex;
|
||||
|
||||
Logging::formatLine(sb, nullptr, binSize, 0, 0, getInlineComment());
|
||||
_code->_logger->log(sb.getData(), sb.getLength());
|
||||
}
|
||||
#endif // !ASMJIT_DISABLE_LOGGING
|
||||
|
||||
Error err = kErrorOk;
|
||||
size_t pos = getOffset();
|
||||
|
||||
LabelLink* link = le->_links;
|
||||
LabelLink* prev = nullptr;
|
||||
|
||||
while (link) {
|
||||
intptr_t offset = link->offset;
|
||||
uint32_t relocId = link->relocId;
|
||||
|
||||
if (relocId != RelocEntry::kInvalidId) {
|
||||
// Adjust relocation data.
|
||||
RelocEntry* re = _code->_relocations[relocId];
|
||||
re->_data += static_cast<uint64_t>(pos);
|
||||
}
|
||||
else {
|
||||
// Not using relocId, this means that we are overwriting a real
|
||||
// displacement in the CodeBuffer.
|
||||
int32_t patchedValue = static_cast<int32_t>(
|
||||
static_cast<intptr_t>(pos) - offset + link->rel);
|
||||
|
||||
// Size of the value we are going to patch. Only BYTE/DWORD is allowed.
|
||||
uint32_t size = _bufferData[offset];
|
||||
if (size == 4)
|
||||
Utils::writeI32u(_bufferData + offset, static_cast<int32_t>(patchedValue));
|
||||
else if (size == 1 && Utils::isInt8(patchedValue))
|
||||
_bufferData[offset] = static_cast<uint8_t>(patchedValue & 0xFF);
|
||||
else
|
||||
err = DebugUtils::errored(kErrorInvalidDisplacement);
|
||||
}
|
||||
|
||||
prev = link->prev;
|
||||
_code->_unresolvedLabelsCount--;
|
||||
_code->_baseHeap.release(link, sizeof(LabelLink));
|
||||
|
||||
link = prev;
|
||||
}
|
||||
|
||||
// Set as bound.
|
||||
le->_sectionId = _section->getId();
|
||||
le->_offset = pos;
|
||||
le->_links = nullptr;
|
||||
resetInlineComment();
|
||||
|
||||
if (err != kErrorOk)
|
||||
return setLastError(err);
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error Assembler::embed(const void* data, uint32_t size) {
|
||||
if (_lastError) return _lastError;
|
||||
|
||||
if (getRemainingSpace() < size) {
|
||||
Error err = _code->growBuffer(&_section->_buffer, size);
|
||||
if (ASMJIT_UNLIKELY(err != kErrorOk)) return setLastError(err);
|
||||
}
|
||||
|
||||
::memcpy(_bufferPtr, data, size);
|
||||
_bufferPtr += size;
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
if (_globalOptions & kOptionLoggingEnabled)
|
||||
_code->_logger->logBinary(data, size);
|
||||
#endif // !ASMJIT_DISABLE_LOGGING
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error Assembler::embedLabel(const Label& label) {
|
||||
if (_lastError) return _lastError;
|
||||
ASMJIT_ASSERT(_code != nullptr);
|
||||
|
||||
RelocEntry* re;
|
||||
LabelEntry* le = _code->getLabelEntry(label);
|
||||
|
||||
if (ASMJIT_UNLIKELY(!le))
|
||||
return setLastError(DebugUtils::errored(kErrorInvalidLabel));
|
||||
|
||||
Error err;
|
||||
uint32_t gpSize = getGpSize();
|
||||
|
||||
if (getRemainingSpace() < gpSize) {
|
||||
err = _code->growBuffer(&_section->_buffer, gpSize);
|
||||
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
|
||||
}
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
if (_globalOptions & kOptionLoggingEnabled)
|
||||
_code->_logger->logf(gpSize == 4 ? ".dd L%u\n" : ".dq L%u\n", Operand::unpackId(label.getId()));
|
||||
#endif // !ASMJIT_DISABLE_LOGGING
|
||||
|
||||
err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs, gpSize);
|
||||
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
|
||||
|
||||
re->_sourceSectionId = _section->getId();
|
||||
re->_sourceOffset = static_cast<uint64_t>(getOffset());
|
||||
|
||||
if (le->isBound()) {
|
||||
re->_targetSectionId = le->getSectionId();
|
||||
re->_data = static_cast<uint64_t>(static_cast<int64_t>(le->getOffset()));
|
||||
}
|
||||
else {
|
||||
LabelLink* link = _code->newLabelLink(le, _section->getId(), getOffset(), 0);
|
||||
if (ASMJIT_UNLIKELY(!link))
|
||||
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
link->relocId = re->getId();
|
||||
}
|
||||
|
||||
// Emit dummy DWORD/QWORD depending on the address size.
|
||||
::memset(_bufferPtr, 0, gpSize);
|
||||
_bufferPtr += gpSize;
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error Assembler::embedConstPool(const Label& label, const ConstPool& pool) {
|
||||
if (_lastError) return _lastError;
|
||||
|
||||
if (!isLabelValid(label))
|
||||
return DebugUtils::errored(kErrorInvalidLabel);
|
||||
|
||||
ASMJIT_PROPAGATE(align(kAlignData, static_cast<uint32_t>(pool.getAlignment())));
|
||||
ASMJIT_PROPAGATE(bind(label));
|
||||
|
||||
size_t size = pool.getSize();
|
||||
if (getRemainingSpace() < size) {
|
||||
Error err = _code->growBuffer(&_section->_buffer, size);
|
||||
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
|
||||
}
|
||||
|
||||
uint8_t* p = _bufferPtr;
|
||||
pool.fill(p);
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
if (_globalOptions & kOptionLoggingEnabled)
|
||||
_code->_logger->logBinary(p, size);
|
||||
#endif // !ASMJIT_DISABLE_LOGGING
|
||||
|
||||
_bufferPtr += size;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Assembler - Emit-Helpers]
|
||||
// ============================================================================
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
void Assembler::_emitLog(
|
||||
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3,
|
||||
uint32_t relSize, uint32_t imLen, uint8_t* afterCursor) {
|
||||
|
||||
Logger* logger = _code->getLogger();
|
||||
ASMJIT_ASSERT(logger != nullptr);
|
||||
ASMJIT_ASSERT(options & CodeEmitter::kOptionLoggingEnabled);
|
||||
|
||||
StringBuilderTmp<256> sb;
|
||||
uint32_t logOptions = logger->getOptions();
|
||||
|
||||
uint8_t* beforeCursor = _bufferPtr;
|
||||
intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor);
|
||||
|
||||
sb.appendString(logger->getIndentation());
|
||||
|
||||
Operand_ opArray[6];
|
||||
opArray[0].copyFrom(o0);
|
||||
opArray[1].copyFrom(o1);
|
||||
opArray[2].copyFrom(o2);
|
||||
opArray[3].copyFrom(o3);
|
||||
|
||||
if (options & kOptionOp4Op5Used) {
|
||||
opArray[4].copyFrom(_op4);
|
||||
opArray[5].copyFrom(_op5);
|
||||
}
|
||||
else {
|
||||
opArray[4].reset();
|
||||
opArray[5].reset();
|
||||
}
|
||||
|
||||
Logging::formatInstruction(
|
||||
sb, logOptions,
|
||||
this, getArchType(),
|
||||
Inst::Detail(instId, options, _extraReg), opArray, 6);
|
||||
|
||||
if ((logOptions & Logger::kOptionBinaryForm) != 0)
|
||||
Logging::formatLine(sb, _bufferPtr, emittedSize, relSize, imLen, getInlineComment());
|
||||
else
|
||||
Logging::formatLine(sb, nullptr, Globals::kInvalidIndex, 0, 0, getInlineComment());
|
||||
|
||||
logger->log(sb.getData(), sb.getLength());
|
||||
}
|
||||
|
||||
Error Assembler::_emitFailed(
|
||||
Error err,
|
||||
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
|
||||
|
||||
StringBuilderTmp<256> sb;
|
||||
sb.appendString(DebugUtils::errorAsString(err));
|
||||
sb.appendString(": ");
|
||||
|
||||
Operand_ opArray[6];
|
||||
opArray[0].copyFrom(o0);
|
||||
opArray[1].copyFrom(o1);
|
||||
opArray[2].copyFrom(o2);
|
||||
opArray[3].copyFrom(o3);
|
||||
|
||||
if (options & kOptionOp4Op5Used) {
|
||||
opArray[4].copyFrom(_op4);
|
||||
opArray[5].copyFrom(_op5);
|
||||
}
|
||||
else {
|
||||
opArray[4].reset();
|
||||
opArray[5].reset();
|
||||
}
|
||||
|
||||
Logging::formatInstruction(
|
||||
sb, 0,
|
||||
this, getArchType(),
|
||||
Inst::Detail(instId, options, _extraReg), opArray, 6);
|
||||
|
||||
resetOptions();
|
||||
resetExtraReg();
|
||||
resetInlineComment();
|
||||
return setLastError(err, sb.getData());
|
||||
}
|
||||
#endif
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
|
@ -1,154 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_ASSEMBLER_H
|
||||
#define _ASMJIT_BASE_ASSEMBLER_H
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/codeemitter.h"
|
||||
#include "../base/codeholder.h"
|
||||
#include "../base/operand.h"
|
||||
#include "../base/simdtypes.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! \addtogroup asmjit_base
|
||||
//! \{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Assembler]
|
||||
// ============================================================================
|
||||
|
||||
//! Base assembler.
|
||||
//!
|
||||
//! This class implements a base interface that is used by architecture
|
||||
//! specific assemblers.
|
||||
//!
|
||||
//! \sa CodeCompiler.
|
||||
class ASMJIT_VIRTAPI Assembler : public CodeEmitter {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(Assembler)
|
||||
typedef CodeEmitter Base;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `Assembler` instance.
|
||||
ASMJIT_API Assembler() noexcept;
|
||||
//! Destroy the `Assembler` instance.
|
||||
ASMJIT_API virtual ~Assembler() noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Events]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
|
||||
ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Code-Generation]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
using CodeEmitter::_emit;
|
||||
|
||||
ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) override;
|
||||
ASMJIT_API Error _emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) override;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Code-Buffer]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Called by \ref CodeHolder::sync().
|
||||
ASMJIT_API virtual void sync() noexcept;
|
||||
|
||||
//! Get the capacity of the current CodeBuffer.
|
||||
ASMJIT_INLINE size_t getBufferCapacity() const noexcept { return (size_t)(_bufferEnd - _bufferData); }
|
||||
//! Get the number of remaining bytes in the current CodeBuffer.
|
||||
ASMJIT_INLINE size_t getRemainingSpace() const noexcept { return (size_t)(_bufferEnd - _bufferPtr); }
|
||||
|
||||
//! Get the current position in the CodeBuffer.
|
||||
ASMJIT_INLINE size_t getOffset() const noexcept { return (size_t)(_bufferPtr - _bufferData); }
|
||||
//! Set the current position in the CodeBuffer to `offset`.
|
||||
//!
|
||||
//! NOTE: The `offset` cannot be outside of the buffer length (even if it's
|
||||
//! within buffer's capacity).
|
||||
ASMJIT_API Error setOffset(size_t offset);
|
||||
|
||||
//! Get start of the CodeBuffer of the current section.
|
||||
ASMJIT_INLINE uint8_t* getBufferData() const noexcept { return _bufferData; }
|
||||
//! Get end (first invalid byte) of the current section.
|
||||
ASMJIT_INLINE uint8_t* getBufferEnd() const noexcept { return _bufferEnd; }
|
||||
//! Get pointer in the CodeBuffer of the current section.
|
||||
ASMJIT_INLINE uint8_t* getBufferPtr() const noexcept { return _bufferPtr; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Code-Generation]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API Label newLabel() override;
|
||||
ASMJIT_API Label newNamedLabel(
|
||||
const char* name,
|
||||
size_t nameLength = Globals::kInvalidIndex,
|
||||
uint32_t type = Label::kTypeGlobal,
|
||||
uint32_t parentId = 0) override;
|
||||
ASMJIT_API Error bind(const Label& label) override;
|
||||
ASMJIT_API Error embed(const void* data, uint32_t size) override;
|
||||
ASMJIT_API Error embedLabel(const Label& label) override;
|
||||
ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override;
|
||||
ASMJIT_API Error comment(const char* s, size_t len = Globals::kInvalidIndex) override;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Emit-Helpers]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
protected:
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
void _emitLog(
|
||||
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3,
|
||||
uint32_t relSize, uint32_t imLen, uint8_t* afterCursor);
|
||||
|
||||
Error _emitFailed(
|
||||
Error err,
|
||||
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3);
|
||||
#else
|
||||
ASMJIT_INLINE Error _emitFailed(
|
||||
uint32_t err,
|
||||
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
|
||||
|
||||
resetOptions();
|
||||
resetInlineComment();
|
||||
return setLastError(err);
|
||||
}
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
SectionEntry* _section; //!< Current section where the assembling happens.
|
||||
uint8_t* _bufferData; //!< Start of the CodeBuffer of the current section.
|
||||
uint8_t* _bufferEnd; //!< End (first invalid byte) of the current section.
|
||||
uint8_t* _bufferPtr; //!< Pointer in the CodeBuffer of the current section.
|
||||
|
||||
Operand_ _op4; //!< 5th operand data, used only temporarily.
|
||||
Operand_ _op5; //!< 6th operand data, used only temporarily.
|
||||
};
|
||||
|
||||
//! \}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_ASSEMBLER_H
|
|
@ -1,584 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Guard]
|
||||
#include "../asmjit_build.h"
|
||||
#if !defined(ASMJIT_DISABLE_BUILDER)
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/codebuilder.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeBuilder - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
CodeBuilder::CodeBuilder() noexcept
|
||||
: CodeEmitter(kTypeBuilder),
|
||||
_cbBaseZone(32768 - Zone::kZoneOverhead),
|
||||
_cbDataZone(16384 - Zone::kZoneOverhead),
|
||||
_cbPassZone(32768 - Zone::kZoneOverhead),
|
||||
_cbHeap(&_cbBaseZone),
|
||||
_cbPasses(),
|
||||
_cbLabels(),
|
||||
_firstNode(nullptr),
|
||||
_lastNode(nullptr),
|
||||
_cursor(nullptr),
|
||||
_position(0),
|
||||
_nodeFlags(0) {}
|
||||
CodeBuilder::~CodeBuilder() noexcept {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeBuilder - Events]
|
||||
// ============================================================================
|
||||
|
||||
Error CodeBuilder::onAttach(CodeHolder* code) noexcept {
|
||||
return Base::onAttach(code);
|
||||
}
|
||||
|
||||
Error CodeBuilder::onDetach(CodeHolder* code) noexcept {
|
||||
_cbPasses.reset();
|
||||
_cbLabels.reset();
|
||||
_cbHeap.reset(&_cbBaseZone);
|
||||
|
||||
_cbBaseZone.reset(false);
|
||||
_cbDataZone.reset(false);
|
||||
_cbPassZone.reset(false);
|
||||
|
||||
_position = 0;
|
||||
_nodeFlags = 0;
|
||||
|
||||
_firstNode = nullptr;
|
||||
_lastNode = nullptr;
|
||||
_cursor = nullptr;
|
||||
|
||||
return Base::onDetach(code);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeBuilder - Node-Factory]
|
||||
// ============================================================================
|
||||
|
||||
Error CodeBuilder::getCBLabel(CBLabel** pOut, uint32_t id) noexcept {
|
||||
if (_lastError) return _lastError;
|
||||
ASMJIT_ASSERT(_code != nullptr);
|
||||
|
||||
size_t index = Operand::unpackId(id);
|
||||
if (ASMJIT_UNLIKELY(index >= _code->getLabelsCount()))
|
||||
return DebugUtils::errored(kErrorInvalidLabel);
|
||||
|
||||
if (index >= _cbLabels.getLength())
|
||||
ASMJIT_PROPAGATE(_cbLabels.resize(&_cbHeap, index + 1));
|
||||
|
||||
CBLabel* node = _cbLabels[index];
|
||||
if (!node) {
|
||||
node = newNodeT<CBLabel>(id);
|
||||
if (ASMJIT_UNLIKELY(!node))
|
||||
return DebugUtils::errored(kErrorNoHeapMemory);
|
||||
_cbLabels[index] = node;
|
||||
}
|
||||
|
||||
*pOut = node;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error CodeBuilder::registerLabelNode(CBLabel* node) noexcept {
|
||||
if (_lastError) return _lastError;
|
||||
ASMJIT_ASSERT(_code != nullptr);
|
||||
|
||||
// Don't call setLastError() from here, we are noexcept and we are called
|
||||
// by `newLabelNode()` and `newFuncNode()`, which are noexcept as well.
|
||||
uint32_t id;
|
||||
ASMJIT_PROPAGATE(_code->newLabelId(id));
|
||||
size_t index = Operand::unpackId(id);
|
||||
|
||||
// We just added one label so it must be true.
|
||||
ASMJIT_ASSERT(_cbLabels.getLength() < index + 1);
|
||||
ASMJIT_PROPAGATE(_cbLabels.resize(&_cbHeap, index + 1));
|
||||
|
||||
_cbLabels[index] = node;
|
||||
node->_id = id;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
CBLabel* CodeBuilder::newLabelNode() noexcept {
|
||||
CBLabel* node = newNodeT<CBLabel>();
|
||||
if (!node || registerLabelNode(node) != kErrorOk)
|
||||
return nullptr;
|
||||
return node;
|
||||
}
|
||||
|
||||
CBAlign* CodeBuilder::newAlignNode(uint32_t mode, uint32_t alignment) noexcept {
|
||||
return newNodeT<CBAlign>(mode, alignment);
|
||||
}
|
||||
|
||||
CBData* CodeBuilder::newDataNode(const void* data, uint32_t size) noexcept {
|
||||
if (size > CBData::kInlineBufferSize) {
|
||||
void* cloned = _cbDataZone.alloc(size);
|
||||
if (!cloned) return nullptr;
|
||||
|
||||
if (data) ::memcpy(cloned, data, size);
|
||||
data = cloned;
|
||||
}
|
||||
|
||||
return newNodeT<CBData>(const_cast<void*>(data), size);
|
||||
}
|
||||
|
||||
CBConstPool* CodeBuilder::newConstPool() noexcept {
|
||||
CBConstPool* node = newNodeT<CBConstPool>();
|
||||
if (!node || registerLabelNode(node) != kErrorOk)
|
||||
return nullptr;
|
||||
return node;
|
||||
}
|
||||
|
||||
CBComment* CodeBuilder::newCommentNode(const char* s, size_t len) noexcept {
|
||||
if (s) {
|
||||
if (len == Globals::kInvalidIndex) len = ::strlen(s);
|
||||
if (len > 0) {
|
||||
s = static_cast<char*>(_cbDataZone.dup(s, len, true));
|
||||
if (!s) return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return newNodeT<CBComment>(s);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeBuilder - Code-Emitter]
|
||||
// ============================================================================
|
||||
|
||||
Label CodeBuilder::newLabel() {
|
||||
uint32_t id = kInvalidValue;
|
||||
|
||||
if (!_lastError) {
|
||||
CBLabel* node = newNodeT<CBLabel>(id);
|
||||
if (ASMJIT_UNLIKELY(!node)) {
|
||||
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
}
|
||||
else {
|
||||
Error err = registerLabelNode(node);
|
||||
if (ASMJIT_UNLIKELY(err))
|
||||
setLastError(err);
|
||||
else
|
||||
id = node->getId();
|
||||
}
|
||||
}
|
||||
|
||||
return Label(id);
|
||||
}
|
||||
|
||||
Label CodeBuilder::newNamedLabel(const char* name, size_t nameLength, uint32_t type, uint32_t parentId) {
|
||||
uint32_t id = kInvalidValue;
|
||||
|
||||
if (!_lastError) {
|
||||
CBLabel* node = newNodeT<CBLabel>(id);
|
||||
if (ASMJIT_UNLIKELY(!node)) {
|
||||
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
}
|
||||
else {
|
||||
Error err = _code->newNamedLabelId(id, name, nameLength, type, parentId);
|
||||
if (ASMJIT_UNLIKELY(err))
|
||||
setLastError(err);
|
||||
else
|
||||
id = node->getId();
|
||||
}
|
||||
}
|
||||
|
||||
return Label(id);
|
||||
}
|
||||
|
||||
Error CodeBuilder::bind(const Label& label) {
|
||||
if (_lastError) return _lastError;
|
||||
|
||||
CBLabel* node;
|
||||
Error err = getCBLabel(&node, label);
|
||||
if (ASMJIT_UNLIKELY(err))
|
||||
return setLastError(err);
|
||||
|
||||
addNode(node);
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error CodeBuilder::align(uint32_t mode, uint32_t alignment) {
|
||||
if (_lastError) return _lastError;
|
||||
|
||||
CBAlign* node = newAlignNode(mode, alignment);
|
||||
if (ASMJIT_UNLIKELY(!node))
|
||||
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
|
||||
addNode(node);
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error CodeBuilder::embed(const void* data, uint32_t size) {
|
||||
if (_lastError) return _lastError;
|
||||
|
||||
CBData* node = newDataNode(data, size);
|
||||
if (ASMJIT_UNLIKELY(!node))
|
||||
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
|
||||
addNode(node);
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error CodeBuilder::embedLabel(const Label& label) {
|
||||
if (_lastError) return _lastError;
|
||||
|
||||
CBLabelData* node = newNodeT<CBLabelData>(label.getId());
|
||||
if (ASMJIT_UNLIKELY(!node))
|
||||
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
|
||||
addNode(node);
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error CodeBuilder::embedConstPool(const Label& label, const ConstPool& pool) {
|
||||
if (_lastError) return _lastError;
|
||||
|
||||
if (!isLabelValid(label))
|
||||
return setLastError(DebugUtils::errored(kErrorInvalidLabel));
|
||||
|
||||
ASMJIT_PROPAGATE(align(kAlignData, static_cast<uint32_t>(pool.getAlignment())));
|
||||
ASMJIT_PROPAGATE(bind(label));
|
||||
|
||||
CBData* node = newDataNode(nullptr, static_cast<uint32_t>(pool.getSize()));
|
||||
if (ASMJIT_UNLIKELY(!node))
|
||||
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
|
||||
pool.fill(node->getData());
|
||||
addNode(node);
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error CodeBuilder::comment(const char* s, size_t len) {
|
||||
if (_lastError) return _lastError;
|
||||
|
||||
CBComment* node = newCommentNode(s, len);
|
||||
if (ASMJIT_UNLIKELY(!node))
|
||||
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
|
||||
addNode(node);
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeBuilder - Node-Management]
|
||||
// ============================================================================
|
||||
|
||||
CBNode* CodeBuilder::addNode(CBNode* node) noexcept {
|
||||
ASMJIT_ASSERT(node);
|
||||
ASMJIT_ASSERT(node->_prev == nullptr);
|
||||
ASMJIT_ASSERT(node->_next == nullptr);
|
||||
|
||||
if (!_cursor) {
|
||||
if (!_firstNode) {
|
||||
_firstNode = node;
|
||||
_lastNode = node;
|
||||
}
|
||||
else {
|
||||
node->_next = _firstNode;
|
||||
_firstNode->_prev = node;
|
||||
_firstNode = node;
|
||||
}
|
||||
}
|
||||
else {
|
||||
CBNode* prev = _cursor;
|
||||
CBNode* next = _cursor->_next;
|
||||
|
||||
node->_prev = prev;
|
||||
node->_next = next;
|
||||
|
||||
prev->_next = node;
|
||||
if (next)
|
||||
next->_prev = node;
|
||||
else
|
||||
_lastNode = node;
|
||||
}
|
||||
|
||||
_cursor = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
CBNode* CodeBuilder::addAfter(CBNode* node, CBNode* ref) noexcept {
|
||||
ASMJIT_ASSERT(node);
|
||||
ASMJIT_ASSERT(ref);
|
||||
|
||||
ASMJIT_ASSERT(node->_prev == nullptr);
|
||||
ASMJIT_ASSERT(node->_next == nullptr);
|
||||
|
||||
CBNode* prev = ref;
|
||||
CBNode* next = ref->_next;
|
||||
|
||||
node->_prev = prev;
|
||||
node->_next = next;
|
||||
|
||||
prev->_next = node;
|
||||
if (next)
|
||||
next->_prev = node;
|
||||
else
|
||||
_lastNode = node;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
CBNode* CodeBuilder::addBefore(CBNode* node, CBNode* ref) noexcept {
|
||||
ASMJIT_ASSERT(node != nullptr);
|
||||
ASMJIT_ASSERT(node->_prev == nullptr);
|
||||
ASMJIT_ASSERT(node->_next == nullptr);
|
||||
ASMJIT_ASSERT(ref != nullptr);
|
||||
|
||||
CBNode* prev = ref->_prev;
|
||||
CBNode* next = ref;
|
||||
|
||||
node->_prev = prev;
|
||||
node->_next = next;
|
||||
|
||||
next->_prev = node;
|
||||
if (prev)
|
||||
prev->_next = node;
|
||||
else
|
||||
_firstNode = node;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE void CodeBuilder_nodeRemoved(CodeBuilder* self, CBNode* node_) noexcept {
|
||||
if (node_->isJmpOrJcc()) {
|
||||
CBJump* node = static_cast<CBJump*>(node_);
|
||||
CBLabel* label = node->getTarget();
|
||||
|
||||
if (label) {
|
||||
// Disconnect.
|
||||
CBJump** pPrev = &label->_from;
|
||||
for (;;) {
|
||||
ASMJIT_ASSERT(*pPrev != nullptr);
|
||||
|
||||
CBJump* current = *pPrev;
|
||||
if (!current) break;
|
||||
|
||||
if (current == node) {
|
||||
*pPrev = node->_jumpNext;
|
||||
break;
|
||||
}
|
||||
|
||||
pPrev = ¤t->_jumpNext;
|
||||
}
|
||||
|
||||
label->subNumRefs();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CBNode* CodeBuilder::removeNode(CBNode* node) noexcept {
|
||||
CBNode* prev = node->_prev;
|
||||
CBNode* next = node->_next;
|
||||
|
||||
if (_firstNode == node)
|
||||
_firstNode = next;
|
||||
else
|
||||
prev->_next = next;
|
||||
|
||||
if (_lastNode == node)
|
||||
_lastNode = prev;
|
||||
else
|
||||
next->_prev = prev;
|
||||
|
||||
node->_prev = nullptr;
|
||||
node->_next = nullptr;
|
||||
|
||||
if (_cursor == node)
|
||||
_cursor = prev;
|
||||
CodeBuilder_nodeRemoved(this, node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void CodeBuilder::removeNodes(CBNode* first, CBNode* last) noexcept {
|
||||
if (first == last) {
|
||||
removeNode(first);
|
||||
return;
|
||||
}
|
||||
|
||||
CBNode* prev = first->_prev;
|
||||
CBNode* next = last->_next;
|
||||
|
||||
if (_firstNode == first)
|
||||
_firstNode = next;
|
||||
else
|
||||
prev->_next = next;
|
||||
|
||||
if (_lastNode == last)
|
||||
_lastNode = prev;
|
||||
else
|
||||
next->_prev = prev;
|
||||
|
||||
CBNode* node = first;
|
||||
for (;;) {
|
||||
CBNode* next = node->getNext();
|
||||
ASMJIT_ASSERT(next != nullptr);
|
||||
|
||||
node->_prev = nullptr;
|
||||
node->_next = nullptr;
|
||||
|
||||
if (_cursor == node)
|
||||
_cursor = prev;
|
||||
CodeBuilder_nodeRemoved(this, node);
|
||||
|
||||
if (node == last)
|
||||
break;
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
|
||||
CBNode* CodeBuilder::setCursor(CBNode* node) noexcept {
|
||||
CBNode* old = _cursor;
|
||||
_cursor = node;
|
||||
return old;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeBuilder - Passes]
|
||||
// ============================================================================
|
||||
|
||||
ASMJIT_FAVOR_SIZE CBPass* CodeBuilder::getPassByName(const char* name) const noexcept {
|
||||
for (size_t i = 0, len = _cbPasses.getLength(); i < len; i++) {
|
||||
CBPass* pass = _cbPasses[i];
|
||||
if (::strcmp(pass->getName(), name) == 0)
|
||||
return pass;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ASMJIT_FAVOR_SIZE Error CodeBuilder::addPass(CBPass* pass) noexcept {
|
||||
if (ASMJIT_UNLIKELY(pass == nullptr)) {
|
||||
// Since this is directly called by `addPassT()` we treat `null` argument
|
||||
// as out-of-memory condition. Otherwise it would be API misuse.
|
||||
return DebugUtils::errored(kErrorNoHeapMemory);
|
||||
}
|
||||
else if (ASMJIT_UNLIKELY(pass->_cb)) {
|
||||
// Kind of weird, but okay...
|
||||
if (pass->_cb == this)
|
||||
return kErrorOk;
|
||||
return DebugUtils::errored(kErrorInvalidState);
|
||||
}
|
||||
|
||||
ASMJIT_PROPAGATE(_cbPasses.append(&_cbHeap, pass));
|
||||
pass->_cb = this;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
ASMJIT_FAVOR_SIZE Error CodeBuilder::deletePass(CBPass* pass) noexcept {
|
||||
if (ASMJIT_UNLIKELY(pass == nullptr))
|
||||
return DebugUtils::errored(kErrorInvalidArgument);
|
||||
|
||||
if (pass->_cb != nullptr) {
|
||||
if (pass->_cb != this)
|
||||
return DebugUtils::errored(kErrorInvalidState);
|
||||
|
||||
size_t index = _cbPasses.indexOf(pass);
|
||||
ASMJIT_ASSERT(index != Globals::kInvalidIndex);
|
||||
|
||||
pass->_cb = nullptr;
|
||||
_cbPasses.removeAt(index);
|
||||
}
|
||||
|
||||
pass->~CBPass();
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeBuilder - Serialization]
|
||||
// ============================================================================
|
||||
|
||||
Error CodeBuilder::serialize(CodeEmitter* dst) {
|
||||
Error err = kErrorOk;
|
||||
CBNode* node_ = getFirstNode();
|
||||
|
||||
do {
|
||||
dst->setInlineComment(node_->getInlineComment());
|
||||
|
||||
switch (node_->getType()) {
|
||||
case CBNode::kNodeAlign: {
|
||||
CBAlign* node = static_cast<CBAlign*>(node_);
|
||||
err = dst->align(node->getMode(), node->getAlignment());
|
||||
break;
|
||||
}
|
||||
|
||||
case CBNode::kNodeData: {
|
||||
CBData* node = static_cast<CBData*>(node_);
|
||||
err = dst->embed(node->getData(), node->getSize());
|
||||
break;
|
||||
}
|
||||
|
||||
case CBNode::kNodeFunc:
|
||||
case CBNode::kNodeLabel: {
|
||||
CBLabel* node = static_cast<CBLabel*>(node_);
|
||||
err = dst->bind(node->getLabel());
|
||||
break;
|
||||
}
|
||||
|
||||
case CBNode::kNodeLabelData: {
|
||||
CBLabelData* node = static_cast<CBLabelData*>(node_);
|
||||
err = dst->embedLabel(node->getLabel());
|
||||
break;
|
||||
}
|
||||
|
||||
case CBNode::kNodeConstPool: {
|
||||
CBConstPool* node = static_cast<CBConstPool*>(node_);
|
||||
err = dst->embedConstPool(node->getLabel(), node->getConstPool());
|
||||
break;
|
||||
}
|
||||
|
||||
case CBNode::kNodeInst:
|
||||
case CBNode::kNodeFuncCall: {
|
||||
CBInst* node = node_->as<CBInst>();
|
||||
dst->setOptions(node->getOptions());
|
||||
dst->setExtraReg(node->getExtraReg());
|
||||
err = dst->emitOpArray(node->getInstId(), node->getOpArray(), node->getOpCount());
|
||||
break;
|
||||
}
|
||||
|
||||
case CBNode::kNodeComment: {
|
||||
CBComment* node = static_cast<CBComment*>(node_);
|
||||
err = dst->comment(node->getInlineComment());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (err) break;
|
||||
node_ = node_->getNext();
|
||||
} while (node_);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CBPass]
|
||||
// ============================================================================
|
||||
|
||||
CBPass::CBPass(const char* name) noexcept
|
||||
: _cb(nullptr),
|
||||
_name(name) {}
|
||||
CBPass::~CBPass() noexcept {}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // !ASMJIT_DISABLE_BUILDER
|
|
@ -1,915 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_CODEBUILDER_H
|
||||
#define _ASMJIT_BASE_CODEBUILDER_H
|
||||
|
||||
#include "../asmjit_build.h"
|
||||
#if !defined(ASMJIT_DISABLE_BUILDER)
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/assembler.h"
|
||||
#include "../base/codeholder.h"
|
||||
#include "../base/constpool.h"
|
||||
#include "../base/inst.h"
|
||||
#include "../base/operand.h"
|
||||
#include "../base/utils.h"
|
||||
#include "../base/zone.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [Forward Declarations]
|
||||
// ============================================================================
|
||||
|
||||
class CBNode;
|
||||
class CBPass;
|
||||
|
||||
class CBAlign;
|
||||
class CBComment;
|
||||
class CBConstPool;
|
||||
class CBData;
|
||||
class CBInst;
|
||||
class CBJump;
|
||||
class CBLabel;
|
||||
class CBLabelData;
|
||||
class CBSentinel;
|
||||
|
||||
//! \addtogroup asmjit_base
|
||||
//! \{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeBuilder]
|
||||
// ============================================================================
|
||||
|
||||
class ASMJIT_VIRTAPI CodeBuilder : public CodeEmitter {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CodeBuilder)
|
||||
typedef CodeEmitter Base;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CodeBuilder` instance.
|
||||
ASMJIT_API CodeBuilder() noexcept;
|
||||
//! Destroy the `CodeBuilder` instance.
|
||||
ASMJIT_API virtual ~CodeBuilder() noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Events]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API virtual Error onAttach(CodeHolder* code) noexcept override;
|
||||
ASMJIT_API virtual Error onDetach(CodeHolder* code) noexcept override;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get a vector of CBPass objects that will be executed by `process()`.
|
||||
ASMJIT_INLINE const ZoneVector<CBPass*>& getPasses() const noexcept { return _cbPasses; }
|
||||
|
||||
//! Get a vector of CBLabel nodes.
|
||||
//!
|
||||
//! NOTE: If a label of some index is not associated with `CodeBuilder` it
|
||||
//! would be null, so always check for nulls if you iterate over the vector.
|
||||
ASMJIT_INLINE const ZoneVector<CBLabel*>& getLabels() const noexcept { return _cbLabels; }
|
||||
|
||||
//! Get the first node.
|
||||
ASMJIT_INLINE CBNode* getFirstNode() const noexcept { return _firstNode; }
|
||||
//! Get the last node.
|
||||
ASMJIT_INLINE CBNode* getLastNode() const noexcept { return _lastNode; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Node-Management]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! \internal
|
||||
template<typename T>
|
||||
ASMJIT_INLINE T* newNodeT() noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this); }
|
||||
|
||||
//! \internal
|
||||
template<typename T, typename P0>
|
||||
ASMJIT_INLINE T* newNodeT(P0 p0) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0); }
|
||||
|
||||
//! \internal
|
||||
template<typename T, typename P0, typename P1>
|
||||
ASMJIT_INLINE T* newNodeT(P0 p0, P1 p1) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0, p1); }
|
||||
|
||||
//! \internal
|
||||
template<typename T, typename P0, typename P1, typename P2>
|
||||
ASMJIT_INLINE T* newNodeT(P0 p0, P1 p1, P2 p2) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0, p1, p2); }
|
||||
|
||||
ASMJIT_API Error registerLabelNode(CBLabel* node) noexcept;
|
||||
//! Get `CBLabel` by `id`.
|
||||
ASMJIT_API Error getCBLabel(CBLabel** pOut, uint32_t id) noexcept;
|
||||
//! Get `CBLabel` by `label`.
|
||||
ASMJIT_INLINE Error getCBLabel(CBLabel** pOut, const Label& label) noexcept { return getCBLabel(pOut, label.getId()); }
|
||||
|
||||
//! Create a new \ref CBLabel node.
|
||||
ASMJIT_API CBLabel* newLabelNode() noexcept;
|
||||
//! Create a new \ref CBAlign node.
|
||||
ASMJIT_API CBAlign* newAlignNode(uint32_t mode, uint32_t alignment) noexcept;
|
||||
//! Create a new \ref CBData node.
|
||||
ASMJIT_API CBData* newDataNode(const void* data, uint32_t size) noexcept;
|
||||
//! Create a new \ref CBConstPool node.
|
||||
ASMJIT_API CBConstPool* newConstPool() noexcept;
|
||||
//! Create a new \ref CBComment node.
|
||||
ASMJIT_API CBComment* newCommentNode(const char* s, size_t len) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Code-Emitter]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API virtual Label newLabel() override;
|
||||
ASMJIT_API virtual Label newNamedLabel(const char* name, size_t nameLength = Globals::kInvalidIndex, uint32_t type = Label::kTypeGlobal, uint32_t parentId = kInvalidValue) override;
|
||||
ASMJIT_API virtual Error bind(const Label& label) override;
|
||||
ASMJIT_API virtual Error align(uint32_t mode, uint32_t alignment) override;
|
||||
ASMJIT_API virtual Error embed(const void* data, uint32_t size) override;
|
||||
ASMJIT_API virtual Error embedLabel(const Label& label) override;
|
||||
ASMJIT_API virtual Error embedConstPool(const Label& label, const ConstPool& pool) override;
|
||||
ASMJIT_API virtual Error comment(const char* s, size_t len = Globals::kInvalidIndex) override;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Node-Management]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Add `node` after the current and set current to `node`.
|
||||
ASMJIT_API CBNode* addNode(CBNode* node) noexcept;
|
||||
//! Insert `node` after `ref`.
|
||||
ASMJIT_API CBNode* addAfter(CBNode* node, CBNode* ref) noexcept;
|
||||
//! Insert `node` before `ref`.
|
||||
ASMJIT_API CBNode* addBefore(CBNode* node, CBNode* ref) noexcept;
|
||||
//! Remove `node`.
|
||||
ASMJIT_API CBNode* removeNode(CBNode* node) noexcept;
|
||||
//! Remove multiple nodes.
|
||||
ASMJIT_API void removeNodes(CBNode* first, CBNode* last) noexcept;
|
||||
|
||||
//! Get current node.
|
||||
//!
|
||||
//! \note If this method returns null it means that nothing has been
|
||||
//! emitted yet.
|
||||
ASMJIT_INLINE CBNode* getCursor() const noexcept { return _cursor; }
|
||||
//! Set the current node without returning the previous node.
|
||||
ASMJIT_INLINE void _setCursor(CBNode* node) noexcept { _cursor = node; }
|
||||
//! Set the current node to `node` and return the previous one.
|
||||
ASMJIT_API CBNode* setCursor(CBNode* node) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Passes]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
ASMJIT_INLINE T* newPassT() noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(); }
|
||||
template<typename T, typename P0>
|
||||
ASMJIT_INLINE T* newPassT(P0 p0) noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(p0); }
|
||||
template<typename T, typename P0, typename P1>
|
||||
ASMJIT_INLINE T* newPassT(P0 p0, P1 p1) noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(p0, p1); }
|
||||
|
||||
template<typename T>
|
||||
ASMJIT_INLINE Error addPassT() noexcept { return addPass(newPassT<T>()); }
|
||||
template<typename T, typename P0>
|
||||
ASMJIT_INLINE Error addPassT(P0 p0) noexcept { return addPass(newPassT<P0>(p0)); }
|
||||
template<typename T, typename P0, typename P1>
|
||||
ASMJIT_INLINE Error addPassT(P0 p0, P1 p1) noexcept { return addPass(newPassT<P0, P1>(p0, p1)); }
|
||||
|
||||
//! Get a `CBPass` by name.
|
||||
ASMJIT_API CBPass* getPassByName(const char* name) const noexcept;
|
||||
//! Add `pass` to the list of passes.
|
||||
ASMJIT_API Error addPass(CBPass* pass) noexcept;
|
||||
//! Remove `pass` from the list of passes and delete it.
|
||||
ASMJIT_API Error deletePass(CBPass* pass) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Serialization]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API virtual Error serialize(CodeEmitter* dst);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
Zone _cbBaseZone; //!< Base zone used to allocate nodes and `CBPass`.
|
||||
Zone _cbDataZone; //!< Data zone used to allocate data and names.
|
||||
Zone _cbPassZone; //!< Zone passed to `CBPass::process()`.
|
||||
ZoneHeap _cbHeap; //!< ZoneHeap that uses `_cbBaseZone`.
|
||||
|
||||
ZoneVector<CBPass*> _cbPasses; //!< Array of `CBPass` objects.
|
||||
ZoneVector<CBLabel*> _cbLabels; //!< Maps label indexes to `CBLabel` nodes.
|
||||
|
||||
CBNode* _firstNode; //!< First node of the current section.
|
||||
CBNode* _lastNode; //!< Last node of the current section.
|
||||
CBNode* _cursor; //!< Current node (cursor).
|
||||
|
||||
uint32_t _position; //!< Flow-id assigned to each new node.
|
||||
uint32_t _nodeFlags; //!< Flags assigned to each new node.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CBPass]
|
||||
// ============================================================================
|
||||
|
||||
//! `CodeBuilder` pass used to code transformations, analysis, and lowering.
|
||||
class ASMJIT_VIRTAPI CBPass {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CBPass);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API CBPass(const char* name) noexcept;
|
||||
ASMJIT_API virtual ~CBPass() noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Interface]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Process the code stored in CodeBuffer `cb`.
|
||||
//!
|
||||
//! This is the only function that is called by the `CodeBuilder` to process
|
||||
//! the code. It passes the CodeBuilder itself (`cb`) and also a zone memory
|
||||
//! allocator `zone`, which will be reset after the `process()` returns. The
|
||||
//! allocator should be used for all allocations as it's fast and everything
|
||||
//! it allocates will be released at once when `process()` returns.
|
||||
virtual Error process(Zone* zone) noexcept = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE const CodeBuilder* cb() const noexcept { return _cb; }
|
||||
ASMJIT_INLINE const char* getName() const noexcept { return _name; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
CodeBuilder* _cb; //!< CodeBuilder this pass is assigned to.
|
||||
const char* _name; //!< Name of the pass.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CBNode]
|
||||
// ============================================================================
|
||||
|
||||
//! Node (CodeBuilder).
|
||||
//!
|
||||
//! Every node represents a building-block used by \ref CodeBuilder. It can be
|
||||
//! instruction, data, label, comment, directive, or any other high-level
|
||||
//! representation that can be transformed to the building blocks mentioned.
|
||||
//! Every class that inherits \ref CodeBuilder can define its own nodes that it
|
||||
//! can lower to basic nodes.
|
||||
class CBNode {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CBNode)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Type]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Type of \ref CBNode.
|
||||
ASMJIT_ENUM(NodeType) {
|
||||
kNodeNone = 0, //!< Invalid node (internal, don't use).
|
||||
|
||||
// [CodeBuilder]
|
||||
kNodeInst = 1, //!< Node is \ref CBInst or \ref CBJump.
|
||||
kNodeData = 2, //!< Node is \ref CBData.
|
||||
kNodeAlign = 3, //!< Node is \ref CBAlign.
|
||||
kNodeLabel = 4, //!< Node is \ref CBLabel.
|
||||
kNodeLabelData = 5, //!< Node is \ref CBLabelData.
|
||||
kNodeConstPool = 6, //!< Node is \ref CBConstPool.
|
||||
kNodeComment = 7, //!< Node is \ref CBComment.
|
||||
kNodeSentinel = 8, //!< Node is \ref CBSentinel.
|
||||
|
||||
// [CodeCompiler]
|
||||
kNodeFunc = 16, //!< Node is \ref CCFunc (considered as \ref CBLabel by \ref CodeBuilder).
|
||||
kNodeFuncExit = 17, //!< Node is \ref CCFuncRet.
|
||||
kNodeFuncCall = 18, //!< Node is \ref CCFuncCall.
|
||||
kNodePushArg = 19, //!< Node is \ref CCPushArg.
|
||||
kNodeHint = 20, //!< Node is \ref CCHint.
|
||||
|
||||
// [UserDefined]
|
||||
kNodeUser = 32 //!< First id of a user-defined node.
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Flags]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_ENUM(Flags) {
|
||||
//! The node has been translated by the CodeCompiler.
|
||||
kFlagIsTranslated = 0x0001,
|
||||
//! If the node can be safely removed (has no effect).
|
||||
kFlagIsRemovable = 0x0004,
|
||||
//! If the node is informative only and can be safely removed.
|
||||
kFlagIsInformative = 0x0008,
|
||||
|
||||
//! If the `CBInst` is a jump.
|
||||
kFlagIsJmp = 0x0010,
|
||||
//! If the `CBInst` is a conditional jump.
|
||||
kFlagIsJcc = 0x0020,
|
||||
|
||||
//! If the `CBInst` is an unconditional jump or conditional jump that is
|
||||
//! likely to be taken.
|
||||
kFlagIsTaken = 0x0040,
|
||||
|
||||
//! If the `CBNode` will return from a function.
|
||||
//!
|
||||
//! This flag is used by both `CBSentinel` and `CCFuncRet`.
|
||||
kFlagIsRet = 0x0080,
|
||||
|
||||
//! Whether the instruction is special.
|
||||
kFlagIsSpecial = 0x0100,
|
||||
|
||||
//! Whether the instruction is an FPU instruction.
|
||||
kFlagIsFp = 0x0200
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new \ref CBNode - always use \ref CodeBuilder to allocate nodes.
|
||||
ASMJIT_INLINE CBNode(CodeBuilder* cb, uint32_t type) noexcept {
|
||||
_prev = nullptr;
|
||||
_next = nullptr;
|
||||
_type = static_cast<uint8_t>(type);
|
||||
_opCount = 0;
|
||||
_flags = static_cast<uint16_t>(cb->_nodeFlags);
|
||||
_position = cb->_position;
|
||||
_inlineComment = nullptr;
|
||||
_passData = nullptr;
|
||||
}
|
||||
//! Destroy the `CBNode` instance (NEVER CALLED).
|
||||
ASMJIT_INLINE ~CBNode() noexcept {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
ASMJIT_INLINE T* as() noexcept { return static_cast<T*>(this); }
|
||||
template<typename T>
|
||||
ASMJIT_INLINE const T* as() const noexcept { return static_cast<const T*>(this); }
|
||||
|
||||
//! Get previous node in the compiler stream.
|
||||
ASMJIT_INLINE CBNode* getPrev() const noexcept { return _prev; }
|
||||
//! Get next node in the compiler stream.
|
||||
ASMJIT_INLINE CBNode* getNext() const noexcept { return _next; }
|
||||
|
||||
//! Get the node type, see \ref Type.
|
||||
ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
|
||||
//! Get the node flags.
|
||||
ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; }
|
||||
|
||||
//! Get whether the instruction has flag `flag`.
|
||||
ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (static_cast<uint32_t>(_flags) & flag) != 0; }
|
||||
//! Set node flags to `flags`.
|
||||
ASMJIT_INLINE void setFlags(uint32_t flags) noexcept { _flags = static_cast<uint16_t>(flags); }
|
||||
//! Add instruction `flags`.
|
||||
ASMJIT_INLINE void orFlags(uint32_t flags) noexcept { _flags |= static_cast<uint16_t>(flags); }
|
||||
//! And instruction `flags`.
|
||||
ASMJIT_INLINE void andFlags(uint32_t flags) noexcept { _flags &= static_cast<uint16_t>(flags); }
|
||||
//! Clear instruction `flags`.
|
||||
ASMJIT_INLINE void andNotFlags(uint32_t flags) noexcept { _flags &= ~static_cast<uint16_t>(flags); }
|
||||
|
||||
//! Get whether the node has been translated.
|
||||
ASMJIT_INLINE bool isTranslated() const noexcept { return hasFlag(kFlagIsTranslated); }
|
||||
|
||||
//! Get whether the node is removable if it's in unreachable code block.
|
||||
ASMJIT_INLINE bool isRemovable() const noexcept { return hasFlag(kFlagIsRemovable); }
|
||||
//! Get whether the node is informative only (comment, hint).
|
||||
ASMJIT_INLINE bool isInformative() const noexcept { return hasFlag(kFlagIsInformative); }
|
||||
|
||||
//! Whether the node is `CBLabel`.
|
||||
ASMJIT_INLINE bool isLabel() const noexcept { return _type == kNodeLabel; }
|
||||
//! Whether the `CBInst` node is an unconditional jump.
|
||||
ASMJIT_INLINE bool isJmp() const noexcept { return hasFlag(kFlagIsJmp); }
|
||||
//! Whether the `CBInst` node is a conditional jump.
|
||||
ASMJIT_INLINE bool isJcc() const noexcept { return hasFlag(kFlagIsJcc); }
|
||||
//! Whether the `CBInst` node is a conditional/unconditional jump.
|
||||
ASMJIT_INLINE bool isJmpOrJcc() const noexcept { return hasFlag(kFlagIsJmp | kFlagIsJcc); }
|
||||
//! Whether the `CBInst` node is a return.
|
||||
ASMJIT_INLINE bool isRet() const noexcept { return hasFlag(kFlagIsRet); }
|
||||
|
||||
//! Get whether the node is `CBInst` and the instruction is special.
|
||||
ASMJIT_INLINE bool isSpecial() const noexcept { return hasFlag(kFlagIsSpecial); }
|
||||
//! Get whether the node is `CBInst` and the instruction uses x87-FPU.
|
||||
ASMJIT_INLINE bool isFp() const noexcept { return hasFlag(kFlagIsFp); }
|
||||
|
||||
ASMJIT_INLINE bool hasPosition() const noexcept { return _position != 0; }
|
||||
//! Get flow index.
|
||||
ASMJIT_INLINE uint32_t getPosition() const noexcept { return _position; }
|
||||
//! Set flow index.
|
||||
ASMJIT_INLINE void setPosition(uint32_t position) noexcept { _position = position; }
|
||||
|
||||
//! Get if the node has an inline comment.
|
||||
ASMJIT_INLINE bool hasInlineComment() const noexcept { return _inlineComment != nullptr; }
|
||||
//! Get an inline comment string.
|
||||
ASMJIT_INLINE const char* getInlineComment() const noexcept { return _inlineComment; }
|
||||
//! Set an inline comment string to `s`.
|
||||
ASMJIT_INLINE void setInlineComment(const char* s) noexcept { _inlineComment = s; }
|
||||
//! Set an inline comment string to null.
|
||||
ASMJIT_INLINE void resetInlineComment() noexcept { _inlineComment = nullptr; }
|
||||
|
||||
//! Get if the node has associated work-data.
|
||||
ASMJIT_INLINE bool hasPassData() const noexcept { return _passData != nullptr; }
|
||||
//! Get work-data - data used during processing & transformations.
|
||||
template<typename T>
|
||||
ASMJIT_INLINE T* getPassData() const noexcept { return (T*)_passData; }
|
||||
//! Set work-data to `data`.
|
||||
template<typename T>
|
||||
ASMJIT_INLINE void setPassData(T* data) noexcept { _passData = (void*)data; }
|
||||
//! Reset work-data to null.
|
||||
ASMJIT_INLINE void resetPassData() noexcept { _passData = nullptr; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
CBNode* _prev; //!< Previous node.
|
||||
CBNode* _next; //!< Next node.
|
||||
|
||||
uint8_t _type; //!< Node type, see \ref NodeType.
|
||||
uint8_t _opCount; //!< Count of operands or zero.
|
||||
uint16_t _flags; //!< Flags, different meaning for every type of the node.
|
||||
uint32_t _position; //!< Flow index.
|
||||
|
||||
const char* _inlineComment; //!< Inline comment or null if not used.
|
||||
void* _passData; //!< Data used exclusively by the current `CBPass`.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CBInst]
|
||||
// ============================================================================
|
||||
|
||||
//! Instruction (CodeBuilder).
|
||||
//!
|
||||
//! Wraps an instruction with its options and operands.
|
||||
class CBInst : public CBNode {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CBInst)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CBInst` instance.
|
||||
ASMJIT_INLINE CBInst(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept
|
||||
: CBNode(cb, kNodeInst) {
|
||||
|
||||
orFlags(kFlagIsRemovable);
|
||||
_instDetail.instId = static_cast<uint16_t>(instId);
|
||||
_instDetail.options = options;
|
||||
|
||||
_opCount = static_cast<uint8_t>(opCount);
|
||||
_opArray = opArray;
|
||||
|
||||
_updateMemOp();
|
||||
}
|
||||
|
||||
//! Destroy the `CBInst` instance (NEVER CALLED).
|
||||
ASMJIT_INLINE ~CBInst() noexcept {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE Inst::Detail& getInstDetail() noexcept { return _instDetail; }
|
||||
ASMJIT_INLINE const Inst::Detail& getInstDetail() const noexcept { return _instDetail; }
|
||||
|
||||
//! Get the instruction id, see \ref Inst::Id.
|
||||
ASMJIT_INLINE uint32_t getInstId() const noexcept { return _instDetail.instId; }
|
||||
//! Set the instruction id to `instId`, see \ref Inst::Id.
|
||||
ASMJIT_INLINE void setInstId(uint32_t instId) noexcept { _instDetail.instId = instId; }
|
||||
|
||||
//! Whether the instruction is either a jump or a conditional jump likely to be taken.
|
||||
ASMJIT_INLINE bool isTaken() const noexcept { return hasFlag(kFlagIsTaken); }
|
||||
|
||||
//! Get emit options.
|
||||
ASMJIT_INLINE uint32_t getOptions() const noexcept { return _instDetail.options; }
|
||||
//! Set emit options.
|
||||
ASMJIT_INLINE void setOptions(uint32_t options) noexcept { _instDetail.options = options; }
|
||||
//! Add emit options.
|
||||
ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _instDetail.options |= options; }
|
||||
//! Mask emit options.
|
||||
ASMJIT_INLINE void andOptions(uint32_t options) noexcept { _instDetail.options &= options; }
|
||||
//! Clear emit options.
|
||||
ASMJIT_INLINE void delOptions(uint32_t options) noexcept { _instDetail.options &= ~options; }
|
||||
|
||||
//! Get if the node has an extra register operand.
|
||||
ASMJIT_INLINE bool hasExtraReg() const noexcept { return _instDetail.hasExtraReg(); }
|
||||
//! Get extra register operand.
|
||||
ASMJIT_INLINE RegOnly& getExtraReg() noexcept { return _instDetail.extraReg; }
|
||||
//! \overload
|
||||
ASMJIT_INLINE const RegOnly& getExtraReg() const noexcept { return _instDetail.extraReg; }
|
||||
//! Set extra register operand to `reg`.
|
||||
ASMJIT_INLINE void setExtraReg(const Reg& reg) noexcept { _instDetail.extraReg.init(reg); }
|
||||
//! Set extra register operand to `reg`.
|
||||
ASMJIT_INLINE void setExtraReg(const RegOnly& reg) noexcept { _instDetail.extraReg.init(reg); }
|
||||
//! Reset extra register operand.
|
||||
ASMJIT_INLINE void resetExtraReg() noexcept { _instDetail.extraReg.reset(); }
|
||||
|
||||
//! Get operands count.
|
||||
ASMJIT_INLINE uint32_t getOpCount() const noexcept { return _opCount; }
|
||||
//! Get operands list.
|
||||
ASMJIT_INLINE Operand* getOpArray() noexcept { return _opArray; }
|
||||
//! \overload
|
||||
ASMJIT_INLINE const Operand* getOpArray() const noexcept { return _opArray; }
|
||||
|
||||
//! Get whether the instruction contains a memory operand.
|
||||
ASMJIT_INLINE bool hasMemOp() const noexcept { return _memOpIndex != 0xFF; }
|
||||
//! Get memory operand.
|
||||
//!
|
||||
//! NOTE: Can only be called if the instruction has such operand,
|
||||
//! see `hasMemOp()`.
|
||||
ASMJIT_INLINE Mem* getMemOp() const noexcept {
|
||||
ASMJIT_ASSERT(hasMemOp());
|
||||
return static_cast<Mem*>(&_opArray[_memOpIndex]);
|
||||
}
|
||||
//! \overload
|
||||
template<typename T>
|
||||
ASMJIT_INLINE T* getMemOp() const noexcept {
|
||||
ASMJIT_ASSERT(hasMemOp());
|
||||
return static_cast<T*>(&_opArray[_memOpIndex]);
|
||||
}
|
||||
|
||||
//! Set memory operand index, `0xFF` means no memory operand.
|
||||
ASMJIT_INLINE void setMemOpIndex(uint32_t index) noexcept { _memOpIndex = static_cast<uint8_t>(index); }
|
||||
//! Reset memory operand index to `0xFF` (no operand).
|
||||
ASMJIT_INLINE void resetMemOpIndex() noexcept { _memOpIndex = 0xFF; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Utils]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE void _updateMemOp() noexcept {
|
||||
Operand* opArray = getOpArray();
|
||||
uint32_t opCount = getOpCount();
|
||||
|
||||
uint32_t i;
|
||||
for (i = 0; i < opCount; i++)
|
||||
if (opArray[i].isMem())
|
||||
goto Update;
|
||||
i = 0xFF;
|
||||
|
||||
Update:
|
||||
setMemOpIndex(i);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
Inst::Detail _instDetail; //!< Instruction id, options, and extra register.
|
||||
uint8_t _memOpIndex; //!< \internal
|
||||
uint8_t _reserved[7]; //!< \internal
|
||||
Operand* _opArray; //!< Instruction operands.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CBInstEx]
|
||||
// ============================================================================
|
||||
|
||||
struct CBInstEx : public CBInst {
|
||||
Operand _op4;
|
||||
Operand _op5;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CBJump]
|
||||
// ============================================================================
|
||||
|
||||
//! Asm jump (conditional or direct).
|
||||
//!
|
||||
//! Extension of `CBInst` node, which stores more information about the jump.
|
||||
class CBJump : public CBInst {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CBJump)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE CBJump(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept
|
||||
: CBInst(cb, instId, options, opArray, opCount),
|
||||
_target(nullptr),
|
||||
_jumpNext(nullptr) {}
|
||||
ASMJIT_INLINE ~CBJump() noexcept {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE CBLabel* getTarget() const noexcept { return _target; }
|
||||
ASMJIT_INLINE CBJump* getJumpNext() const noexcept { return _jumpNext; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
CBLabel* _target; //!< Target node.
|
||||
CBJump* _jumpNext; //!< Next jump to the same target in a single linked-list.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CBData]
|
||||
// ============================================================================
|
||||
|
||||
//! Asm data (CodeBuilder).
|
||||
//!
|
||||
//! Wraps `.data` directive. The node contains data that will be placed at the
|
||||
//! node's position in the assembler stream. The data is considered to be RAW;
|
||||
//! no analysis nor byte-order conversion is performed on RAW data.
|
||||
class CBData : public CBNode {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CBData)
|
||||
enum { kInlineBufferSize = static_cast<int>(64 - sizeof(CBNode) - 4) };
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CBData` instance.
|
||||
ASMJIT_INLINE CBData(CodeBuilder* cb, void* data, uint32_t size) noexcept : CBNode(cb, kNodeData) {
|
||||
if (size <= kInlineBufferSize) {
|
||||
if (data) ::memcpy(_buf, data, size);
|
||||
}
|
||||
else {
|
||||
_externalPtr = static_cast<uint8_t*>(data);
|
||||
}
|
||||
_size = size;
|
||||
}
|
||||
|
||||
//! Destroy the `CBData` instance (NEVER CALLED).
|
||||
ASMJIT_INLINE ~CBData() noexcept {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get size of the data.
|
||||
uint32_t getSize() const noexcept { return _size; }
|
||||
//! Get pointer to the data.
|
||||
uint8_t* getData() const noexcept { return _size <= kInlineBufferSize ? const_cast<uint8_t*>(_buf) : _externalPtr; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint8_t _buf[kInlineBufferSize]; //!< Embedded data buffer.
|
||||
uint32_t _size; //!< Size of the data.
|
||||
};
|
||||
struct {
|
||||
uint8_t* _externalPtr; //!< Pointer to external data.
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CBAlign]
|
||||
// ============================================================================
|
||||
|
||||
//! Align directive (CodeBuilder).
|
||||
//!
|
||||
//! Wraps `.align` directive.
|
||||
class CBAlign : public CBNode {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CBAlign)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CBAlign` instance.
|
||||
ASMJIT_INLINE CBAlign(CodeBuilder* cb, uint32_t mode, uint32_t alignment) noexcept
|
||||
: CBNode(cb, kNodeAlign),
|
||||
_mode(mode),
|
||||
_alignment(alignment) {}
|
||||
//! Destroy the `CBAlign` instance (NEVER CALLED).
|
||||
ASMJIT_INLINE ~CBAlign() noexcept {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get align mode.
|
||||
ASMJIT_INLINE uint32_t getMode() const noexcept { return _mode; }
|
||||
//! Set align mode.
|
||||
ASMJIT_INLINE void setMode(uint32_t mode) noexcept { _mode = mode; }
|
||||
|
||||
//! Get align offset in bytes.
|
||||
ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; }
|
||||
//! Set align offset in bytes to `offset`.
|
||||
ASMJIT_INLINE void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
uint32_t _mode; //!< Align mode, see \ref AlignMode.
|
||||
uint32_t _alignment; //!< Alignment (in bytes).
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CBLabel]
|
||||
// ============================================================================
|
||||
|
||||
//! Label (CodeBuilder).
|
||||
class CBLabel : public CBNode {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CBLabel)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CBLabel` instance.
|
||||
ASMJIT_INLINE CBLabel(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept
|
||||
: CBNode(cb, kNodeLabel),
|
||||
_id(id),
|
||||
_numRefs(0),
|
||||
_from(nullptr) {}
|
||||
//! Destroy the `CBLabel` instance (NEVER CALLED).
|
||||
ASMJIT_INLINE ~CBLabel() noexcept {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get the label id.
|
||||
ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
|
||||
//! Get the label as `Label` operand.
|
||||
ASMJIT_INLINE Label getLabel() const noexcept { return Label(_id); }
|
||||
|
||||
//! Get first jmp instruction.
|
||||
ASMJIT_INLINE CBJump* getFrom() const noexcept { return _from; }
|
||||
|
||||
//! Get number of jumps to this target.
|
||||
ASMJIT_INLINE uint32_t getNumRefs() const noexcept { return _numRefs; }
|
||||
//! Set number of jumps to this target.
|
||||
ASMJIT_INLINE void setNumRefs(uint32_t i) noexcept { _numRefs = i; }
|
||||
|
||||
//! Add number of jumps to this target.
|
||||
ASMJIT_INLINE void addNumRefs(uint32_t i = 1) noexcept { _numRefs += i; }
|
||||
//! Subtract number of jumps to this target.
|
||||
ASMJIT_INLINE void subNumRefs(uint32_t i = 1) noexcept { _numRefs -= i; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
uint32_t _id; //!< Label id.
|
||||
uint32_t _numRefs; //!< Count of jumps here.
|
||||
CBJump* _from; //!< Linked-list of nodes that can jump here.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CBLabelData]
|
||||
// ============================================================================
|
||||
|
||||
class CBLabelData : public CBNode {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CBLabelData)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CBLabelData` instance.
|
||||
ASMJIT_INLINE CBLabelData(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept
|
||||
: CBNode(cb, kNodeLabelData),
|
||||
_id(id) {}
|
||||
|
||||
//! Destroy the `CBLabelData` instance (NEVER CALLED).
|
||||
ASMJIT_INLINE ~CBLabelData() noexcept {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Interface]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get the label id.
|
||||
ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
|
||||
//! Get the label as `Label` operand.
|
||||
ASMJIT_INLINE Label getLabel() const noexcept { return Label(_id); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
uint32_t _id;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CBConstPool]
|
||||
// ============================================================================
|
||||
|
||||
class CBConstPool : public CBLabel {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CBConstPool)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CBConstPool` instance.
|
||||
ASMJIT_INLINE CBConstPool(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept
|
||||
: CBLabel(cb, id),
|
||||
_constPool(&cb->_cbBaseZone) { _type = kNodeConstPool; }
|
||||
|
||||
//! Destroy the `CBConstPool` instance (NEVER CALLED).
|
||||
ASMJIT_INLINE ~CBConstPool() noexcept {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Interface]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE ConstPool& getConstPool() noexcept { return _constPool; }
|
||||
ASMJIT_INLINE const ConstPool& getConstPool() const noexcept { return _constPool; }
|
||||
|
||||
//! Get whether the constant-pool is empty.
|
||||
ASMJIT_INLINE bool isEmpty() const noexcept { return _constPool.isEmpty(); }
|
||||
//! Get the size of the constant-pool in bytes.
|
||||
ASMJIT_INLINE size_t getSize() const noexcept { return _constPool.getSize(); }
|
||||
//! Get minimum alignment.
|
||||
ASMJIT_INLINE size_t getAlignment() const noexcept { return _constPool.getAlignment(); }
|
||||
|
||||
//! See \ref ConstPool::add().
|
||||
ASMJIT_INLINE Error add(const void* data, size_t size, size_t& dstOffset) noexcept {
|
||||
return _constPool.add(data, size, dstOffset);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ConstPool _constPool;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CBComment]
|
||||
// ============================================================================
|
||||
|
||||
//! Comment (CodeBuilder).
|
||||
class CBComment : public CBNode {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CBComment)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CBComment` instance.
|
||||
ASMJIT_INLINE CBComment(CodeBuilder* cb, const char* comment) noexcept : CBNode(cb, kNodeComment) {
|
||||
orFlags(kFlagIsRemovable | kFlagIsInformative);
|
||||
_inlineComment = comment;
|
||||
}
|
||||
|
||||
//! Destroy the `CBComment` instance (NEVER CALLED).
|
||||
ASMJIT_INLINE ~CBComment() noexcept {}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CBSentinel]
|
||||
// ============================================================================
|
||||
|
||||
//! Sentinel (CodeBuilder).
|
||||
//!
|
||||
//! Sentinel is a marker that is completely ignored by the code builder. It's
|
||||
//! used to remember a position in a code as it never gets removed by any pass.
|
||||
class CBSentinel : public CBNode {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CBSentinel)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CBSentinel` instance.
|
||||
ASMJIT_INLINE CBSentinel(CodeBuilder* cb) noexcept : CBNode(cb, kNodeSentinel) {}
|
||||
//! Destroy the `CBSentinel` instance (NEVER CALLED).
|
||||
ASMJIT_INLINE ~CBSentinel() noexcept {}
|
||||
};
|
||||
|
||||
//! \}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // !ASMJIT_DISABLE_BUILDER
|
||||
#endif // _ASMJIT_BASE_CODEBUILDER_H
|
|
@ -1,573 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Guard]
|
||||
#include "../asmjit_build.h"
|
||||
#if !defined(ASMJIT_DISABLE_COMPILER)
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/assembler.h"
|
||||
#include "../base/codecompiler.h"
|
||||
#include "../base/cpuinfo.h"
|
||||
#include "../base/logging.h"
|
||||
#include "../base/regalloc_p.h"
|
||||
#include "../base/utils.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [Constants]
|
||||
// ============================================================================
|
||||
|
||||
static const char noName[1] = { '\0' };
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CCFuncCall - Arg / Ret]
|
||||
// ============================================================================
|
||||
|
||||
bool CCFuncCall::_setArg(uint32_t i, const Operand_& op) noexcept {
|
||||
if ((i & ~kFuncArgHi) >= _funcDetail.getArgCount())
|
||||
return false;
|
||||
|
||||
_args[i] = op;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCFuncCall::_setRet(uint32_t i, const Operand_& op) noexcept {
|
||||
if (i >= 2)
|
||||
return false;
|
||||
|
||||
_ret[i] = op;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeCompiler - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
CodeCompiler::CodeCompiler() noexcept
|
||||
: CodeBuilder(),
|
||||
_func(nullptr),
|
||||
_vRegZone(4096 - Zone::kZoneOverhead),
|
||||
_vRegArray(),
|
||||
_localConstPool(nullptr),
|
||||
_globalConstPool(nullptr) {
|
||||
|
||||
_type = kTypeCompiler;
|
||||
}
|
||||
CodeCompiler::~CodeCompiler() noexcept {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeCompiler - Events]
|
||||
// ============================================================================
|
||||
|
||||
Error CodeCompiler::onAttach(CodeHolder* code) noexcept {
|
||||
return Base::onAttach(code);
|
||||
}
|
||||
|
||||
Error CodeCompiler::onDetach(CodeHolder* code) noexcept {
|
||||
_func = nullptr;
|
||||
|
||||
_localConstPool = nullptr;
|
||||
_globalConstPool = nullptr;
|
||||
|
||||
_vRegArray.reset();
|
||||
_vRegZone.reset(false);
|
||||
|
||||
return Base::onDetach(code);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeCompiler - Node-Factory]
|
||||
// ============================================================================
|
||||
|
||||
CCHint* CodeCompiler::newHintNode(Reg& r, uint32_t hint, uint32_t value) noexcept {
|
||||
if (!r.isVirtReg()) return nullptr;
|
||||
|
||||
VirtReg* vr = getVirtReg(r);
|
||||
return newNodeT<CCHint>(vr, hint, value);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeCompiler - Func]
|
||||
// ============================================================================
|
||||
|
||||
CCFunc* CodeCompiler::newFunc(const FuncSignature& sign) noexcept {
|
||||
Error err;
|
||||
|
||||
CCFunc* func = newNodeT<CCFunc>();
|
||||
if (!func) goto _NoMemory;
|
||||
|
||||
err = registerLabelNode(func);
|
||||
if (ASMJIT_UNLIKELY(err)) {
|
||||
// TODO: Calls setLastError, maybe rethink noexcept?
|
||||
setLastError(err);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create helper nodes.
|
||||
func->_exitNode = newLabelNode();
|
||||
func->_end = newNodeT<CBSentinel>();
|
||||
|
||||
if (!func->_exitNode || !func->_end)
|
||||
goto _NoMemory;
|
||||
|
||||
// Function prototype.
|
||||
err = func->getDetail().init(sign);
|
||||
if (err != kErrorOk) {
|
||||
setLastError(err);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If the CodeInfo guarantees higher alignment honor it.
|
||||
if (_codeInfo.getStackAlignment() > func->_funcDetail._callConv.getNaturalStackAlignment())
|
||||
func->_funcDetail._callConv.setNaturalStackAlignment(_codeInfo.getStackAlignment());
|
||||
|
||||
// Allocate space for function arguments.
|
||||
func->_args = nullptr;
|
||||
if (func->getArgCount() != 0) {
|
||||
func->_args = _cbHeap.allocT<VirtReg*>(func->getArgCount() * sizeof(VirtReg*));
|
||||
if (!func->_args) goto _NoMemory;
|
||||
|
||||
::memset(func->_args, 0, func->getArgCount() * sizeof(VirtReg*));
|
||||
}
|
||||
|
||||
return func;
|
||||
|
||||
_NoMemory:
|
||||
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CCFunc* CodeCompiler::addFunc(CCFunc* func) {
|
||||
ASMJIT_ASSERT(_func == nullptr);
|
||||
_func = func;
|
||||
|
||||
addNode(func); // Function node.
|
||||
CBNode* cursor = getCursor(); // {CURSOR}.
|
||||
addNode(func->getExitNode()); // Function exit label.
|
||||
addNode(func->getEnd()); // Function end marker.
|
||||
|
||||
_setCursor(cursor);
|
||||
return func;
|
||||
}
|
||||
|
||||
CCFunc* CodeCompiler::addFunc(const FuncSignature& sign) {
|
||||
CCFunc* func = newFunc(sign);
|
||||
|
||||
if (!func) {
|
||||
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return addFunc(func);
|
||||
}
|
||||
|
||||
CBSentinel* CodeCompiler::endFunc() {
|
||||
CCFunc* func = getFunc();
|
||||
if (!func) {
|
||||
// TODO:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Add the local constant pool at the end of the function (if exists).
|
||||
if (_localConstPool) {
|
||||
setCursor(func->getEnd()->getPrev());
|
||||
addNode(_localConstPool);
|
||||
_localConstPool = nullptr;
|
||||
}
|
||||
|
||||
// Mark as finished.
|
||||
func->_isFinished = true;
|
||||
_func = nullptr;
|
||||
|
||||
CBSentinel* end = func->getEnd();
|
||||
setCursor(end);
|
||||
return end;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeCompiler - Ret]
|
||||
// ============================================================================
|
||||
|
||||
CCFuncRet* CodeCompiler::newRet(const Operand_& o0, const Operand_& o1) noexcept {
|
||||
CCFuncRet* node = newNodeT<CCFuncRet>(o0, o1);
|
||||
if (!node) {
|
||||
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
return nullptr;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
CCFuncRet* CodeCompiler::addRet(const Operand_& o0, const Operand_& o1) noexcept {
|
||||
CCFuncRet* node = newRet(o0, o1);
|
||||
if (!node) return nullptr;
|
||||
return static_cast<CCFuncRet*>(addNode(node));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeCompiler - Call]
|
||||
// ============================================================================
|
||||
|
||||
CCFuncCall* CodeCompiler::newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept {
|
||||
Error err;
|
||||
uint32_t nArgs;
|
||||
|
||||
CCFuncCall* node = _cbHeap.allocT<CCFuncCall>(sizeof(CCFuncCall) + sizeof(Operand));
|
||||
Operand* opArray = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(node) + sizeof(CCFuncCall));
|
||||
|
||||
if (ASMJIT_UNLIKELY(!node))
|
||||
goto _NoMemory;
|
||||
|
||||
opArray[0].copyFrom(o0);
|
||||
new (node) CCFuncCall(this, instId, 0, opArray, 1);
|
||||
|
||||
if ((err = node->getDetail().init(sign)) != kErrorOk) {
|
||||
setLastError(err);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If there are no arguments skip the allocation.
|
||||
if ((nArgs = sign.getArgCount()) == 0)
|
||||
return node;
|
||||
|
||||
node->_args = static_cast<Operand*>(_cbHeap.alloc(nArgs * sizeof(Operand)));
|
||||
if (!node->_args) goto _NoMemory;
|
||||
|
||||
::memset(node->_args, 0, nArgs * sizeof(Operand));
|
||||
return node;
|
||||
|
||||
_NoMemory:
|
||||
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CCFuncCall* CodeCompiler::addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept {
|
||||
CCFuncCall* node = newCall(instId, o0, sign);
|
||||
if (!node) return nullptr;
|
||||
return static_cast<CCFuncCall*>(addNode(node));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeCompiler - Vars]
|
||||
// ============================================================================
|
||||
|
||||
Error CodeCompiler::setArg(uint32_t argIndex, const Reg& r) {
|
||||
CCFunc* func = getFunc();
|
||||
|
||||
if (!func)
|
||||
return setLastError(DebugUtils::errored(kErrorInvalidState));
|
||||
|
||||
if (!isVirtRegValid(r))
|
||||
return setLastError(DebugUtils::errored(kErrorInvalidVirtId));
|
||||
|
||||
VirtReg* vr = getVirtReg(r);
|
||||
func->setArg(argIndex, vr);
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeCompiler - Hint]
|
||||
// ============================================================================
|
||||
|
||||
Error CodeCompiler::_hint(Reg& r, uint32_t hint, uint32_t value) {
|
||||
if (!r.isVirtReg()) return kErrorOk;
|
||||
|
||||
CCHint* node = newHintNode(r, hint, value);
|
||||
if (!node) return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
|
||||
addNode(node);
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeCompiler - Vars]
|
||||
// ============================================================================
|
||||
|
||||
VirtReg* CodeCompiler::newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept {
|
||||
size_t index = _vRegArray.getLength();
|
||||
if (ASMJIT_UNLIKELY(index > Operand::kPackedIdCount))
|
||||
return nullptr;
|
||||
|
||||
VirtReg* vreg;
|
||||
if (_vRegArray.willGrow(&_cbHeap, 1) != kErrorOk || !(vreg = _vRegZone.allocZeroedT<VirtReg>()))
|
||||
return nullptr;
|
||||
|
||||
vreg->_id = Operand::packId(static_cast<uint32_t>(index));
|
||||
vreg->_regInfo._signature = signature;
|
||||
vreg->_name = noName;
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
if (name && name[0] != '\0')
|
||||
vreg->_name = static_cast<char*>(_cbDataZone.dup(name, ::strlen(name), true));
|
||||
#endif // !ASMJIT_DISABLE_LOGGING
|
||||
|
||||
vreg->_size = TypeId::sizeOf(typeId);
|
||||
vreg->_typeId = typeId;
|
||||
vreg->_alignment = static_cast<uint8_t>(std::min<uint32_t>(vreg->_size, 64));
|
||||
vreg->_priority = 10;
|
||||
|
||||
// The following are only used by `RAPass`.
|
||||
vreg->_raId = kInvalidValue;
|
||||
vreg->_state = VirtReg::kStateNone;
|
||||
vreg->_physId = Globals::kInvalidRegId;
|
||||
|
||||
_vRegArray.appendUnsafe(vreg);
|
||||
return vreg;
|
||||
}
|
||||
|
||||
Error CodeCompiler::_newReg(Reg& out, uint32_t typeId, const char* name) {
|
||||
RegInfo regInfo;
|
||||
|
||||
Error err = ArchUtils::typeIdToRegInfo(getArchType(), typeId, regInfo);
|
||||
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
|
||||
|
||||
VirtReg* vReg = newVirtReg(typeId, regInfo.getSignature(), name);
|
||||
if (ASMJIT_UNLIKELY(!vReg)) {
|
||||
out.reset();
|
||||
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
}
|
||||
|
||||
out._initReg(regInfo.getSignature(), vReg->getId());
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error CodeCompiler::_newReg(Reg& out, uint32_t typeId, const char* nameFmt, va_list ap) {
|
||||
StringBuilderTmp<256> sb;
|
||||
sb.appendFormatVA(nameFmt, ap);
|
||||
return _newReg(out, typeId, sb.getData());
|
||||
}
|
||||
|
||||
Error CodeCompiler::_newReg(Reg& out, const Reg& ref, const char* name) {
|
||||
RegInfo regInfo;
|
||||
uint32_t typeId;
|
||||
|
||||
if (isVirtRegValid(ref)) {
|
||||
VirtReg* vRef = getVirtReg(ref);
|
||||
typeId = vRef->getTypeId();
|
||||
|
||||
// NOTE: It's possible to cast one register type to another if it's the
|
||||
// same register kind. However, VirtReg always contains the TypeId that
|
||||
// was used to create the register. This means that in some cases we may
|
||||
// end up having different size of `ref` and `vRef`. In such case we
|
||||
// adjust the TypeId to match the `ref` register type instead of the
|
||||
// original register type, which should be the expected behavior.
|
||||
uint32_t typeSize = TypeId::sizeOf(typeId);
|
||||
uint32_t refSize = ref.getSize();
|
||||
|
||||
if (typeSize != refSize) {
|
||||
if (TypeId::isInt(typeId)) {
|
||||
// GP register - change TypeId to match `ref`, but keep sign of `vRef`.
|
||||
switch (refSize) {
|
||||
case 1: typeId = TypeId::kI8 | (typeId & 1); break;
|
||||
case 2: typeId = TypeId::kI16 | (typeId & 1); break;
|
||||
case 4: typeId = TypeId::kI32 | (typeId & 1); break;
|
||||
case 8: typeId = TypeId::kI64 | (typeId & 1); break;
|
||||
default: typeId = TypeId::kVoid; break;
|
||||
}
|
||||
}
|
||||
else if (TypeId::isMmx(typeId)) {
|
||||
// MMX register - always use 64-bit.
|
||||
typeId = TypeId::kMmx64;
|
||||
}
|
||||
else if (TypeId::isMask(typeId)) {
|
||||
// Mask register - change TypeId to match `ref` size.
|
||||
switch (refSize) {
|
||||
case 1: typeId = TypeId::kMask8; break;
|
||||
case 2: typeId = TypeId::kMask16; break;
|
||||
case 4: typeId = TypeId::kMask32; break;
|
||||
case 8: typeId = TypeId::kMask64; break;
|
||||
default: typeId = TypeId::kVoid; break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// VEC register - change TypeId to match `ref` size, keep vector metadata.
|
||||
uint32_t elementTypeId = TypeId::elementOf(typeId);
|
||||
|
||||
switch (refSize) {
|
||||
case 16: typeId = TypeId::_kVec128Start + (elementTypeId - TypeId::kI8); break;
|
||||
case 32: typeId = TypeId::_kVec256Start + (elementTypeId - TypeId::kI8); break;
|
||||
case 64: typeId = TypeId::_kVec512Start + (elementTypeId - TypeId::kI8); break;
|
||||
default: typeId = TypeId::kVoid; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeId == TypeId::kVoid)
|
||||
return setLastError(DebugUtils::errored(kErrorInvalidState));
|
||||
}
|
||||
}
|
||||
else {
|
||||
typeId = ref.getType();
|
||||
}
|
||||
|
||||
Error err = ArchUtils::typeIdToRegInfo(getArchType(), typeId, regInfo);
|
||||
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
|
||||
|
||||
VirtReg* vReg = newVirtReg(typeId, regInfo.getSignature(), name);
|
||||
if (ASMJIT_UNLIKELY(!vReg)) {
|
||||
out.reset();
|
||||
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
}
|
||||
|
||||
out._initReg(regInfo.getSignature(), vReg->getId());
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error CodeCompiler::_newReg(Reg& out, const Reg& ref, const char* nameFmt, va_list ap) {
|
||||
StringBuilderTmp<256> sb;
|
||||
sb.appendFormatVA(nameFmt, ap);
|
||||
return _newReg(out, ref, sb.getData());
|
||||
}
|
||||
|
||||
Error CodeCompiler::_newStack(Mem& out, uint32_t size, uint32_t alignment, const char* name) {
|
||||
if (size == 0)
|
||||
return setLastError(DebugUtils::errored(kErrorInvalidArgument));
|
||||
|
||||
if (alignment == 0) alignment = 1;
|
||||
if (!Utils::isPowerOf2(alignment))
|
||||
return setLastError(DebugUtils::errored(kErrorInvalidArgument));
|
||||
|
||||
if (alignment > 64) alignment = 64;
|
||||
|
||||
VirtReg* vReg = newVirtReg(0, 0, name);
|
||||
if (ASMJIT_UNLIKELY(!vReg)) {
|
||||
out.reset();
|
||||
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
}
|
||||
|
||||
vReg->_size = size;
|
||||
vReg->_isStack = true;
|
||||
vReg->_alignment = static_cast<uint8_t>(alignment);
|
||||
|
||||
// Set the memory operand to GPD/GPQ and its id to VirtReg.
|
||||
out = Mem(Init, _nativeGpReg.getType(), vReg->getId(), Reg::kRegNone, kInvalidValue, 0, 0, Mem::kSignatureMemRegHomeFlag);
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error CodeCompiler::_newConst(Mem& out, uint32_t scope, const void* data, size_t size) {
|
||||
CBConstPool** pPool;
|
||||
if (scope == kConstScopeLocal)
|
||||
pPool = &_localConstPool;
|
||||
else if (scope == kConstScopeGlobal)
|
||||
pPool = &_globalConstPool;
|
||||
else
|
||||
return setLastError(DebugUtils::errored(kErrorInvalidArgument));
|
||||
|
||||
if (!*pPool && !(*pPool = newConstPool()))
|
||||
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
|
||||
|
||||
CBConstPool* pool = *pPool;
|
||||
size_t off;
|
||||
|
||||
Error err = pool->add(data, size, off);
|
||||
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
|
||||
|
||||
out = Mem(Init,
|
||||
Label::kLabelTag, // Base type.
|
||||
pool->getId(), // Base id.
|
||||
0, // Index type.
|
||||
kInvalidValue, // Index id.
|
||||
static_cast<int32_t>(off), // Offset.
|
||||
static_cast<uint32_t>(size), // Size.
|
||||
0); // Flags.
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error CodeCompiler::alloc(Reg& reg) {
|
||||
if (!reg.isVirtReg()) return kErrorOk;
|
||||
return _hint(reg, CCHint::kHintAlloc, kInvalidValue);
|
||||
}
|
||||
|
||||
Error CodeCompiler::alloc(Reg& reg, uint32_t physId) {
|
||||
if (!reg.isVirtReg()) return kErrorOk;
|
||||
return _hint(reg, CCHint::kHintAlloc, physId);
|
||||
}
|
||||
|
||||
Error CodeCompiler::alloc(Reg& reg, const Reg& physReg) {
|
||||
if (!reg.isVirtReg()) return kErrorOk;
|
||||
return _hint(reg, CCHint::kHintAlloc, physReg.getId());
|
||||
}
|
||||
|
||||
Error CodeCompiler::save(Reg& reg) {
|
||||
if (!reg.isVirtReg()) return kErrorOk;
|
||||
return _hint(reg, CCHint::kHintSave, kInvalidValue);
|
||||
}
|
||||
|
||||
Error CodeCompiler::spill(Reg& reg) {
|
||||
if (!reg.isVirtReg()) return kErrorOk;
|
||||
return _hint(reg, CCHint::kHintSpill, kInvalidValue);
|
||||
}
|
||||
|
||||
Error CodeCompiler::unuse(Reg& reg) {
|
||||
if (!reg.isVirtReg()) return kErrorOk;
|
||||
return _hint(reg, CCHint::kHintUnuse, kInvalidValue);
|
||||
}
|
||||
|
||||
uint32_t CodeCompiler::getPriority(Reg& reg) const {
|
||||
if (!reg.isVirtReg()) return 0;
|
||||
return getVirtRegById(reg.getId())->getPriority();
|
||||
}
|
||||
|
||||
void CodeCompiler::setPriority(Reg& reg, uint32_t priority) {
|
||||
if (!reg.isVirtReg()) return;
|
||||
if (priority > 255) priority = 255;
|
||||
|
||||
VirtReg* vreg = getVirtRegById(reg.getId());
|
||||
if (vreg) vreg->_priority = static_cast<uint8_t>(priority);
|
||||
}
|
||||
|
||||
bool CodeCompiler::getSaveOnUnuse(Reg& reg) const {
|
||||
if (!reg.isVirtReg()) return false;
|
||||
|
||||
VirtReg* vreg = getVirtRegById(reg.getId());
|
||||
return static_cast<bool>(vreg->_saveOnUnuse);
|
||||
}
|
||||
|
||||
void CodeCompiler::setSaveOnUnuse(Reg& reg, bool value) {
|
||||
if (!reg.isVirtReg()) return;
|
||||
|
||||
VirtReg* vreg = getVirtRegById(reg.getId());
|
||||
if (!vreg) return;
|
||||
|
||||
vreg->_saveOnUnuse = value;
|
||||
}
|
||||
|
||||
void CodeCompiler::rename(Reg& reg, const char* fmt, ...) {
|
||||
if (!reg.isVirtReg()) return;
|
||||
|
||||
VirtReg* vreg = getVirtRegById(reg.getId());
|
||||
if (!vreg) return;
|
||||
|
||||
vreg->_name = noName;
|
||||
if (fmt && fmt[0] != '\0') {
|
||||
char buf[64];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap);
|
||||
buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0';
|
||||
|
||||
vreg->_name = static_cast<char*>(_cbDataZone.dup(buf, ::strlen(buf), true));
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // !ASMJIT_DISABLE_COMPILER
|
|
@ -1,738 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_CODECOMPILER_H
|
||||
#define _ASMJIT_BASE_CODECOMPILER_H
|
||||
|
||||
#include "../asmjit_build.h"
|
||||
#if !defined(ASMJIT_DISABLE_COMPILER)
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/assembler.h"
|
||||
#include "../base/codebuilder.h"
|
||||
#include "../base/constpool.h"
|
||||
#include "../base/func.h"
|
||||
#include "../base/operand.h"
|
||||
#include "../base/utils.h"
|
||||
#include "../base/zone.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [Forward Declarations]
|
||||
// ============================================================================
|
||||
|
||||
struct VirtReg;
|
||||
struct TiedReg;
|
||||
struct RAState;
|
||||
struct RACell;
|
||||
|
||||
//! \addtogroup asmjit_base
|
||||
//! \{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ConstScope]
|
||||
// ============================================================================
|
||||
|
||||
//! Scope of the constant.
|
||||
ASMJIT_ENUM(ConstScope) {
|
||||
//! Local constant, always embedded right after the current function.
|
||||
kConstScopeLocal = 0,
|
||||
//! Global constant, embedded at the end of the currently compiled code.
|
||||
kConstScopeGlobal = 1
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::VirtReg]
|
||||
// ============================================================================
|
||||
|
||||
//! Virtual register data (CodeCompiler).
|
||||
struct VirtReg {
|
||||
//! A state of a virtual register (used during register allocation).
|
||||
ASMJIT_ENUM(State) {
|
||||
kStateNone = 0, //!< Not allocated, not used.
|
||||
kStateReg = 1, //!< Allocated in register.
|
||||
kStateMem = 2 //!< Allocated in memory or spilled.
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get the virtual-register id.
|
||||
ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
|
||||
//! Get virtual-register's name.
|
||||
ASMJIT_INLINE const char* getName() const noexcept { return _name; }
|
||||
|
||||
//! Get a physical register type.
|
||||
ASMJIT_INLINE uint32_t getType() const noexcept { return _regInfo.getType(); }
|
||||
//! Get a physical register kind.
|
||||
ASMJIT_INLINE uint32_t getKind() const noexcept { return _regInfo.getKind(); }
|
||||
//! Get a physical register size.
|
||||
ASMJIT_INLINE uint32_t getRegSize() const noexcept { return _regInfo.getSize(); }
|
||||
//! Get a register signature of this virtual register.
|
||||
ASMJIT_INLINE uint32_t getSignature() const noexcept { return _regInfo.getSignature(); }
|
||||
|
||||
//! Get a register's type-id, see \ref TypeId.
|
||||
ASMJIT_INLINE uint32_t getTypeId() const noexcept { return _typeId; }
|
||||
|
||||
//! Get virtual-register's size.
|
||||
ASMJIT_INLINE uint32_t getSize() const noexcept { return _size; }
|
||||
//! Get virtual-register's alignment.
|
||||
ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; }
|
||||
|
||||
//! Get the virtual-register priority, used by compiler to decide which variable to spill.
|
||||
ASMJIT_INLINE uint32_t getPriority() const noexcept { return _priority; }
|
||||
//! Set the virtual-register priority.
|
||||
ASMJIT_INLINE void setPriority(uint32_t priority) noexcept {
|
||||
ASMJIT_ASSERT(priority <= 0xFF);
|
||||
_priority = static_cast<uint8_t>(priority);
|
||||
}
|
||||
|
||||
//! Get variable state, only used by `RAPass`.
|
||||
ASMJIT_INLINE uint32_t getState() const noexcept { return _state; }
|
||||
//! Set variable state, only used by `RAPass`.
|
||||
ASMJIT_INLINE void setState(uint32_t state) {
|
||||
ASMJIT_ASSERT(state <= 0xFF);
|
||||
_state = static_cast<uint8_t>(state);
|
||||
}
|
||||
|
||||
//! Get register index.
|
||||
ASMJIT_INLINE uint32_t getPhysId() const noexcept { return _physId; }
|
||||
//! Set register index.
|
||||
ASMJIT_INLINE void setPhysId(uint32_t physId) {
|
||||
ASMJIT_ASSERT(physId <= Globals::kInvalidRegId);
|
||||
_physId = static_cast<uint8_t>(physId);
|
||||
}
|
||||
//! Reset register index.
|
||||
ASMJIT_INLINE void resetPhysId() {
|
||||
_physId = static_cast<uint8_t>(Globals::kInvalidRegId);
|
||||
}
|
||||
|
||||
//! Get home registers mask.
|
||||
ASMJIT_INLINE uint32_t getHomeMask() const { return _homeMask; }
|
||||
//! Add a home register index to the home registers mask.
|
||||
ASMJIT_INLINE void addHomeId(uint32_t physId) { _homeMask |= Utils::mask(physId); }
|
||||
|
||||
ASMJIT_INLINE bool isFixed() const noexcept { return static_cast<bool>(_isFixed); }
|
||||
|
||||
//! Get whether the VirtReg is only memory allocated on the stack.
|
||||
ASMJIT_INLINE bool isStack() const noexcept { return static_cast<bool>(_isStack); }
|
||||
|
||||
//! Get whether to save variable when it's unused (spill).
|
||||
ASMJIT_INLINE bool saveOnUnuse() const noexcept { return static_cast<bool>(_saveOnUnuse); }
|
||||
|
||||
//! Get whether the variable was changed.
|
||||
ASMJIT_INLINE bool isModified() const noexcept { return static_cast<bool>(_modified); }
|
||||
//! Set whether the variable was changed.
|
||||
ASMJIT_INLINE void setModified(bool modified) noexcept { _modified = modified; }
|
||||
|
||||
//! Get home memory offset.
|
||||
ASMJIT_INLINE int32_t getMemOffset() const noexcept { return _memOffset; }
|
||||
//! Set home memory offset.
|
||||
ASMJIT_INLINE void setMemOffset(int32_t offset) noexcept { _memOffset = offset; }
|
||||
|
||||
//! Get home memory cell.
|
||||
ASMJIT_INLINE RACell* getMemCell() const noexcept { return _memCell; }
|
||||
//! Set home memory cell.
|
||||
ASMJIT_INLINE void setMemCell(RACell* cell) noexcept { _memCell = cell; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
uint32_t _id; //!< Virtual register id.
|
||||
RegInfo _regInfo; //!< Physical register info & signature.
|
||||
const char* _name; //!< Virtual name (user provided).
|
||||
uint32_t _size; //!< Virtual size (can be smaller than `regInfo._size`).
|
||||
uint8_t _typeId; //!< Type-id.
|
||||
uint8_t _alignment; //!< Register's natural alignment (for spilling).
|
||||
uint8_t _priority; //!< Allocation priority (hint for RAPass that can be ignored).
|
||||
uint8_t _isFixed : 1; //!< True if this is a fixed register, never reallocated.
|
||||
uint8_t _isStack : 1; //!< True if the virtual register is only used as a stack.
|
||||
uint8_t _isMaterialized : 1; //!< Register is constant that is easily created by a single instruction.
|
||||
uint8_t _saveOnUnuse : 1; //!< Save on unuse (at end of the variable scope).
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// The following members are used exclusively by RAPass. They are initialized
|
||||
// when the VirtReg is created and then changed during RAPass.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
uint32_t _raId; //!< Register allocator work-id (used by RAPass).
|
||||
int32_t _memOffset; //!< Home memory offset.
|
||||
uint32_t _homeMask; //!< Mask of all registers variable has been allocated to.
|
||||
|
||||
uint8_t _state; //!< Variable state (connected with actual `RAState)`.
|
||||
uint8_t _physId; //!< Actual register index (only used by `RAPass)`, during translate.
|
||||
uint8_t _modified; //!< Whether variable was changed (connected with actual `RAState)`.
|
||||
|
||||
RACell* _memCell; //!< Home memory cell, used by `RAPass` (initially nullptr).
|
||||
|
||||
//! Temporary link to TiedReg* used by the `RAPass` used in
|
||||
//! various phases, but always set back to nullptr when finished.
|
||||
//!
|
||||
//! This temporary data is designed to be used by algorithms that need to
|
||||
//! store some data into variables themselves during compilation. But it's
|
||||
//! expected that after variable is compiled & translated the data is set
|
||||
//! back to zero/null. Initial value is nullptr.
|
||||
TiedReg* _tied;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CCHint]
|
||||
// ============================================================================
|
||||
|
||||
//! Hint for register allocator (CodeCompiler).
|
||||
class CCHint : public CBNode {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CCHint)
|
||||
|
||||
//! Hint type.
|
||||
ASMJIT_ENUM(Hint) {
|
||||
//! Alloc to physical reg.
|
||||
kHintAlloc = 0,
|
||||
//! Spill to memory.
|
||||
kHintSpill = 1,
|
||||
//! Save if modified.
|
||||
kHintSave = 2,
|
||||
//! Save if modified and mark it as unused.
|
||||
kHintSaveAndUnuse = 3,
|
||||
//! Mark as unused.
|
||||
kHintUnuse = 4
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CCHint` instance.
|
||||
ASMJIT_INLINE CCHint(CodeBuilder* cb, VirtReg* vreg, uint32_t hint, uint32_t value) noexcept : CBNode(cb, kNodeHint) {
|
||||
orFlags(kFlagIsRemovable | kFlagIsInformative);
|
||||
_vreg = vreg;
|
||||
_hint = hint;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
//! Destroy the `CCHint` instance (NEVER CALLED).
|
||||
ASMJIT_INLINE ~CCHint() noexcept {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get variable.
|
||||
ASMJIT_INLINE VirtReg* getVReg() const noexcept { return _vreg; }
|
||||
|
||||
//! Get hint it, see \ref Hint.
|
||||
ASMJIT_INLINE uint32_t getHint() const noexcept { return _hint; }
|
||||
//! Set hint it, see \ref Hint.
|
||||
ASMJIT_INLINE void setHint(uint32_t hint) noexcept { _hint = hint; }
|
||||
|
||||
//! Get hint value.
|
||||
ASMJIT_INLINE uint32_t getValue() const noexcept { return _value; }
|
||||
//! Set hint value.
|
||||
ASMJIT_INLINE void setValue(uint32_t value) noexcept { _value = value; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Variable.
|
||||
VirtReg* _vreg;
|
||||
//! Hint id.
|
||||
uint32_t _hint;
|
||||
//! Value.
|
||||
uint32_t _value;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CCFunc]
|
||||
// ============================================================================
|
||||
|
||||
//! Function entry (CodeCompiler).
|
||||
class CCFunc : public CBLabel {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CCFunc)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CCFunc` instance.
|
||||
//!
|
||||
//! Always use `CodeCompiler::addFunc()` to create \ref CCFunc.
|
||||
ASMJIT_INLINE CCFunc(CodeBuilder* cb) noexcept
|
||||
: CBLabel(cb),
|
||||
_funcDetail(),
|
||||
_frameInfo(),
|
||||
_exitNode(nullptr),
|
||||
_end(nullptr),
|
||||
_args(nullptr),
|
||||
_isFinished(false) {
|
||||
|
||||
_type = kNodeFunc;
|
||||
}
|
||||
|
||||
//! Destroy the `CCFunc` instance (NEVER CALLED).
|
||||
ASMJIT_INLINE ~CCFunc() noexcept {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get function exit `CBLabel`.
|
||||
ASMJIT_INLINE CBLabel* getExitNode() const noexcept { return _exitNode; }
|
||||
//! Get function exit label.
|
||||
ASMJIT_INLINE Label getExitLabel() const noexcept { return _exitNode->getLabel(); }
|
||||
|
||||
//! Get "End of Func" sentinel.
|
||||
ASMJIT_INLINE CBSentinel* getEnd() const noexcept { return _end; }
|
||||
|
||||
//! Get function declaration.
|
||||
ASMJIT_INLINE FuncDetail& getDetail() noexcept { return _funcDetail; }
|
||||
//! Get function declaration.
|
||||
ASMJIT_INLINE const FuncDetail& getDetail() const noexcept { return _funcDetail; }
|
||||
|
||||
//! Get function declaration.
|
||||
ASMJIT_INLINE FuncFrameInfo& getFrameInfo() noexcept { return _frameInfo; }
|
||||
//! Get function declaration.
|
||||
ASMJIT_INLINE const FuncFrameInfo& getFrameInfo() const noexcept { return _frameInfo; }
|
||||
|
||||
//! Get arguments count.
|
||||
ASMJIT_INLINE uint32_t getArgCount() const noexcept { return _funcDetail.getArgCount(); }
|
||||
//! Get returns count.
|
||||
ASMJIT_INLINE uint32_t getRetCount() const noexcept { return _funcDetail.getRetCount(); }
|
||||
|
||||
//! Get arguments list.
|
||||
ASMJIT_INLINE VirtReg** getArgs() const noexcept { return _args; }
|
||||
|
||||
//! Get argument at `i`.
|
||||
ASMJIT_INLINE VirtReg* getArg(uint32_t i) const noexcept {
|
||||
ASMJIT_ASSERT(i < getArgCount());
|
||||
return _args[i];
|
||||
}
|
||||
|
||||
//! Set argument at `i`.
|
||||
ASMJIT_INLINE void setArg(uint32_t i, VirtReg* vreg) noexcept {
|
||||
ASMJIT_ASSERT(i < getArgCount());
|
||||
_args[i] = vreg;
|
||||
}
|
||||
|
||||
//! Reset argument at `i`.
|
||||
ASMJIT_INLINE void resetArg(uint32_t i) noexcept {
|
||||
ASMJIT_ASSERT(i < getArgCount());
|
||||
_args[i] = nullptr;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE uint32_t getAttributes() const noexcept { return _frameInfo.getAttributes(); }
|
||||
ASMJIT_INLINE void addAttributes(uint32_t attrs) noexcept { _frameInfo.addAttributes(attrs); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
FuncDetail _funcDetail; //!< Function detail.
|
||||
FuncFrameInfo _frameInfo; //!< Function frame information.
|
||||
|
||||
CBLabel* _exitNode; //!< Function exit.
|
||||
CBSentinel* _end; //!< Function end.
|
||||
|
||||
VirtReg** _args; //!< Arguments array as `VirtReg`.
|
||||
|
||||
//! Function was finished by `Compiler::endFunc()`.
|
||||
uint8_t _isFinished;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CCFuncRet]
|
||||
// ============================================================================
|
||||
|
||||
//! Function return (CodeCompiler).
|
||||
class CCFuncRet : public CBNode {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CCFuncRet)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CCFuncRet` instance.
|
||||
ASMJIT_INLINE CCFuncRet(CodeBuilder* cb, const Operand_& o0, const Operand_& o1) noexcept : CBNode(cb, kNodeFuncExit) {
|
||||
orFlags(kFlagIsRet);
|
||||
_ret[0].copyFrom(o0);
|
||||
_ret[1].copyFrom(o1);
|
||||
}
|
||||
|
||||
//! Destroy the `CCFuncRet` instance (NEVER CALLED).
|
||||
ASMJIT_INLINE ~CCFuncRet() noexcept {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get the first return operand.
|
||||
ASMJIT_INLINE Operand& getFirst() noexcept { return static_cast<Operand&>(_ret[0]); }
|
||||
//! \overload
|
||||
ASMJIT_INLINE const Operand& getFirst() const noexcept { return static_cast<const Operand&>(_ret[0]); }
|
||||
|
||||
//! Get the second return operand.
|
||||
ASMJIT_INLINE Operand& getSecond() noexcept { return static_cast<Operand&>(_ret[1]); }
|
||||
//! \overload
|
||||
ASMJIT_INLINE const Operand& getSecond() const noexcept { return static_cast<const Operand&>(_ret[1]); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Return operands.
|
||||
Operand_ _ret[2];
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CCFuncCall]
|
||||
// ============================================================================
|
||||
|
||||
//! Function call (CodeCompiler).
|
||||
class CCFuncCall : public CBInst {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CCFuncCall)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CCFuncCall` instance.
|
||||
ASMJIT_INLINE CCFuncCall(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept
|
||||
: CBInst(cb, instId, options, opArray, opCount),
|
||||
_funcDetail(),
|
||||
_args(nullptr) {
|
||||
|
||||
_type = kNodeFuncCall;
|
||||
_ret[0].reset();
|
||||
_ret[1].reset();
|
||||
orFlags(kFlagIsRemovable);
|
||||
}
|
||||
|
||||
//! Destroy the `CCFuncCall` instance (NEVER CALLED).
|
||||
ASMJIT_INLINE ~CCFuncCall() noexcept {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Signature]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Set function signature.
|
||||
ASMJIT_INLINE Error setSignature(const FuncSignature& sign) noexcept {
|
||||
return _funcDetail.init(sign);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get function declaration.
|
||||
ASMJIT_INLINE FuncDetail& getDetail() noexcept { return _funcDetail; }
|
||||
//! Get function declaration.
|
||||
ASMJIT_INLINE const FuncDetail& getDetail() const noexcept { return _funcDetail; }
|
||||
|
||||
//! Get target operand.
|
||||
ASMJIT_INLINE Operand& getTarget() noexcept { return static_cast<Operand&>(_opArray[0]); }
|
||||
//! \overload
|
||||
ASMJIT_INLINE const Operand& getTarget() const noexcept { return static_cast<const Operand&>(_opArray[0]); }
|
||||
|
||||
//! Get return at `i`.
|
||||
ASMJIT_INLINE Operand& getRet(uint32_t i = 0) noexcept {
|
||||
ASMJIT_ASSERT(i < 2);
|
||||
return static_cast<Operand&>(_ret[i]);
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE const Operand& getRet(uint32_t i = 0) const noexcept {
|
||||
ASMJIT_ASSERT(i < 2);
|
||||
return static_cast<const Operand&>(_ret[i]);
|
||||
}
|
||||
|
||||
//! Get argument at `i`.
|
||||
ASMJIT_INLINE Operand& getArg(uint32_t i) noexcept {
|
||||
ASMJIT_ASSERT(i < kFuncArgCountLoHi);
|
||||
return static_cast<Operand&>(_args[i]);
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE const Operand& getArg(uint32_t i) const noexcept {
|
||||
ASMJIT_ASSERT(i < kFuncArgCountLoHi);
|
||||
return static_cast<const Operand&>(_args[i]);
|
||||
}
|
||||
|
||||
//! Set argument at `i` to `op`.
|
||||
ASMJIT_API bool _setArg(uint32_t i, const Operand_& op) noexcept;
|
||||
//! Set return at `i` to `op`.
|
||||
ASMJIT_API bool _setRet(uint32_t i, const Operand_& op) noexcept;
|
||||
|
||||
//! Set argument at `i` to `reg`.
|
||||
ASMJIT_INLINE bool setArg(uint32_t i, const Reg& reg) noexcept { return _setArg(i, reg); }
|
||||
//! Set argument at `i` to `imm`.
|
||||
ASMJIT_INLINE bool setArg(uint32_t i, const Imm& imm) noexcept { return _setArg(i, imm); }
|
||||
|
||||
//! Set return at `i` to `var`.
|
||||
ASMJIT_INLINE bool setRet(uint32_t i, const Reg& reg) noexcept { return _setRet(i, reg); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
FuncDetail _funcDetail; //!< Function detail.
|
||||
Operand_ _ret[2]; //!< Return.
|
||||
Operand_* _args; //!< Arguments.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CCPushArg]
|
||||
// ============================================================================
|
||||
|
||||
//! Push argument before a function call (CodeCompiler).
|
||||
class CCPushArg : public CBNode {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CCPushArg)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CCPushArg` instance.
|
||||
ASMJIT_INLINE CCPushArg(CodeBuilder* cb, CCFuncCall* call, VirtReg* src, VirtReg* cvt) noexcept
|
||||
: CBNode(cb, kNodePushArg),
|
||||
_call(call),
|
||||
_src(src),
|
||||
_cvt(cvt),
|
||||
_args(0) {
|
||||
orFlags(kFlagIsRemovable);
|
||||
}
|
||||
|
||||
//! Destroy the `CCPushArg` instance.
|
||||
ASMJIT_INLINE ~CCPushArg() noexcept {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get the associated function-call.
|
||||
ASMJIT_INLINE CCFuncCall* getCall() const noexcept { return _call; }
|
||||
//! Get source variable.
|
||||
ASMJIT_INLINE VirtReg* getSrcReg() const noexcept { return _src; }
|
||||
//! Get conversion variable.
|
||||
ASMJIT_INLINE VirtReg* getCvtReg() const noexcept { return _cvt; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
CCFuncCall* _call; //!< Associated `CCFuncCall`.
|
||||
VirtReg* _src; //!< Source variable.
|
||||
VirtReg* _cvt; //!< Temporary variable used for conversion (or null).
|
||||
uint32_t _args; //!< Affected arguments bit-array.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeCompiler]
|
||||
// ============================================================================
|
||||
|
||||
//! Code emitter that uses virtual registers and performs register allocation.
|
||||
//!
|
||||
//! Compiler is a high-level code-generation tool that provides register
|
||||
//! allocation and automatic handling of function calling conventions. It was
|
||||
//! primarily designed for merging multiple parts of code into a function
|
||||
//! without worrying about registers and function calling conventions.
|
||||
//!
|
||||
//! CodeCompiler can be used, with a minimum effort, to handle 32-bit and 64-bit
|
||||
//! code at the same time.
|
||||
//!
|
||||
//! CodeCompiler is based on CodeBuilder and contains all the features it
|
||||
//! provides. It means that the code it stores can be modified (removed, added,
|
||||
//! injected) and analyzed. When the code is finalized the compiler can emit
|
||||
//! the code into an Assembler to translate the abstract representation into a
|
||||
//! machine code.
|
||||
class ASMJIT_VIRTAPI CodeCompiler : public CodeBuilder {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CodeCompiler)
|
||||
typedef CodeBuilder Base;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CodeCompiler` instance.
|
||||
ASMJIT_API CodeCompiler() noexcept;
|
||||
//! Destroy the `CodeCompiler` instance.
|
||||
ASMJIT_API virtual ~CodeCompiler() noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Events]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API virtual Error onAttach(CodeHolder* code) noexcept override;
|
||||
ASMJIT_API virtual Error onDetach(CodeHolder* code) noexcept override;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Node-Factory]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! Create a new `CCHint`.
|
||||
ASMJIT_API CCHint* newHintNode(Reg& reg, uint32_t hint, uint32_t value) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Func]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get the current function.
|
||||
ASMJIT_INLINE CCFunc* getFunc() const noexcept { return _func; }
|
||||
|
||||
//! Create a new `CCFunc`.
|
||||
ASMJIT_API CCFunc* newFunc(const FuncSignature& sign) noexcept;
|
||||
//! Add a function `node` to the stream.
|
||||
ASMJIT_API CCFunc* addFunc(CCFunc* func);
|
||||
//! Add a new function.
|
||||
ASMJIT_API CCFunc* addFunc(const FuncSignature& sign);
|
||||
//! Emit a sentinel that marks the end of the current function.
|
||||
ASMJIT_API CBSentinel* endFunc();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Ret]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CCFuncRet`.
|
||||
ASMJIT_API CCFuncRet* newRet(const Operand_& o0, const Operand_& o1) noexcept;
|
||||
//! Add a new `CCFuncRet`.
|
||||
ASMJIT_API CCFuncRet* addRet(const Operand_& o0, const Operand_& o1) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Call]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `CCFuncCall`.
|
||||
ASMJIT_API CCFuncCall* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept;
|
||||
//! Add a new `CCFuncCall`.
|
||||
ASMJIT_API CCFuncCall* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Args]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Set a function argument at `argIndex` to `reg`.
|
||||
ASMJIT_API Error setArg(uint32_t argIndex, const Reg& reg);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Hint]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Emit a new hint (purely informational node).
|
||||
ASMJIT_API Error _hint(Reg& reg, uint32_t hint, uint32_t value);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [VirtReg / Stack]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new virtual register representing the given `vti` and `signature`.
|
||||
//!
|
||||
//! This function accepts either register type representing a machine-specific
|
||||
//! register, like `X86Reg`, or RegTag representation, which represents
|
||||
//! machine independent register, and from the machine-specific register
|
||||
//! is deduced.
|
||||
ASMJIT_API VirtReg* newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept;
|
||||
|
||||
ASMJIT_API Error _newReg(Reg& out, uint32_t typeId, const char* name);
|
||||
ASMJIT_API Error _newReg(Reg& out, uint32_t typeId, const char* nameFmt, va_list ap);
|
||||
|
||||
ASMJIT_API Error _newReg(Reg& out, const Reg& ref, const char* name);
|
||||
ASMJIT_API Error _newReg(Reg& out, const Reg& ref, const char* nameFmt, va_list ap);
|
||||
|
||||
ASMJIT_API Error _newStack(Mem& out, uint32_t size, uint32_t alignment, const char* name);
|
||||
ASMJIT_API Error _newConst(Mem& out, uint32_t scope, const void* data, size_t size);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [VirtReg]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get whether the virtual register `r` is valid.
|
||||
ASMJIT_INLINE bool isVirtRegValid(const Reg& reg) const noexcept {
|
||||
return isVirtRegValid(reg.getId());
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE bool isVirtRegValid(uint32_t id) const noexcept {
|
||||
size_t index = Operand::unpackId(id);
|
||||
return index < _vRegArray.getLength();
|
||||
}
|
||||
|
||||
//! Get \ref VirtReg associated with the given `r`.
|
||||
ASMJIT_INLINE VirtReg* getVirtReg(const Reg& reg) const noexcept {
|
||||
return getVirtRegById(reg.getId());
|
||||
}
|
||||
//! Get \ref VirtReg associated with the given `id`.
|
||||
ASMJIT_INLINE VirtReg* getVirtRegById(uint32_t id) const noexcept {
|
||||
ASMJIT_ASSERT(id != kInvalidValue);
|
||||
size_t index = Operand::unpackId(id);
|
||||
|
||||
ASMJIT_ASSERT(index < _vRegArray.getLength());
|
||||
return _vRegArray[index];
|
||||
}
|
||||
|
||||
//! Get an array of all virtual registers managed by CodeCompiler.
|
||||
ASMJIT_INLINE const ZoneVector<VirtReg*>& getVirtRegArray() const noexcept { return _vRegArray; }
|
||||
|
||||
//! Alloc a virtual register `reg`.
|
||||
ASMJIT_API Error alloc(Reg& reg);
|
||||
//! Alloc a virtual register `reg` using `physId` as a register id.
|
||||
ASMJIT_API Error alloc(Reg& reg, uint32_t physId);
|
||||
//! Alloc a virtual register `reg` using `ref` as a register operand.
|
||||
ASMJIT_API Error alloc(Reg& reg, const Reg& ref);
|
||||
//! Spill a virtual register `reg`.
|
||||
ASMJIT_API Error spill(Reg& reg);
|
||||
//! Save a virtual register `reg` if the status is `modified` at this point.
|
||||
ASMJIT_API Error save(Reg& reg);
|
||||
//! Unuse a virtual register `reg`.
|
||||
ASMJIT_API Error unuse(Reg& reg);
|
||||
|
||||
//! Get priority of a virtual register `reg`.
|
||||
ASMJIT_API uint32_t getPriority(Reg& reg) const;
|
||||
//! Set priority of variable `reg` to `priority`.
|
||||
ASMJIT_API void setPriority(Reg& reg, uint32_t priority);
|
||||
|
||||
//! Get save-on-unuse `reg` property.
|
||||
ASMJIT_API bool getSaveOnUnuse(Reg& reg) const;
|
||||
//! Set save-on-unuse `reg` property to `value`.
|
||||
ASMJIT_API void setSaveOnUnuse(Reg& reg, bool value);
|
||||
|
||||
//! Rename variable `reg` to `name`.
|
||||
//!
|
||||
//! NOTE: Only new name will appear in the logger.
|
||||
ASMJIT_API void rename(Reg& reg, const char* fmt, ...);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
CCFunc* _func; //!< Current function.
|
||||
|
||||
Zone _vRegZone; //!< Allocates \ref VirtReg objects.
|
||||
ZoneVector<VirtReg*> _vRegArray; //!< Stores array of \ref VirtReg pointers.
|
||||
|
||||
CBConstPool* _localConstPool; //!< Local constant pool, flushed at the end of each function.
|
||||
CBConstPool* _globalConstPool; //!< Global constant pool, flushed at the end of the compilation.
|
||||
};
|
||||
|
||||
//! \}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // !ASMJIT_DISABLE_COMPILER
|
||||
#endif // _ASMJIT_BASE_CODECOMPILER_H
|
|
@ -1,236 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/assembler.h"
|
||||
#include "../base/utils.h"
|
||||
#include "../base/vmem.h"
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
#include "../x86/x86inst.h"
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
#include "../arm/arminst.h"
|
||||
#endif // ASMJIT_BUILD_ARM
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeEmitter - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
CodeEmitter::CodeEmitter(uint32_t type) noexcept
|
||||
: _codeInfo(),
|
||||
_code(nullptr),
|
||||
_nextEmitter(nullptr),
|
||||
_type(static_cast<uint8_t>(type)),
|
||||
_destroyed(false),
|
||||
_finalized(false),
|
||||
_reserved(false),
|
||||
_lastError(kErrorNotInitialized),
|
||||
_privateData(0),
|
||||
_globalHints(0),
|
||||
_globalOptions(kOptionMaybeFailureCase),
|
||||
_options(0),
|
||||
_extraReg(),
|
||||
_inlineComment(nullptr),
|
||||
_none(),
|
||||
_nativeGpReg(),
|
||||
_nativeGpArray(nullptr) {}
|
||||
|
||||
CodeEmitter::~CodeEmitter() noexcept {
|
||||
if (_code) {
|
||||
_destroyed = true;
|
||||
_code->detach(this);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeEmitter - Events]
|
||||
// ============================================================================
|
||||
|
||||
Error CodeEmitter::onAttach(CodeHolder* code) noexcept {
|
||||
_codeInfo = code->getCodeInfo();
|
||||
_lastError = kErrorOk;
|
||||
|
||||
_globalHints = code->getGlobalHints();
|
||||
_globalOptions = code->getGlobalOptions();
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error CodeEmitter::onDetach(CodeHolder* code) noexcept {
|
||||
_codeInfo.reset();
|
||||
_finalized = false;
|
||||
_lastError = kErrorNotInitialized;
|
||||
|
||||
_privateData = 0;
|
||||
_globalHints = 0;
|
||||
_globalOptions = kOptionMaybeFailureCase;
|
||||
|
||||
_options = 0;
|
||||
_extraReg.reset();
|
||||
_inlineComment = nullptr;
|
||||
|
||||
_nativeGpReg.reset();
|
||||
_nativeGpArray = nullptr;
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeEmitter - Code-Generation]
|
||||
// ============================================================================
|
||||
|
||||
Error CodeEmitter::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
|
||||
const Operand_* op = opArray;
|
||||
switch (opCount) {
|
||||
case 0: return _emit(instId, _none, _none, _none, _none);
|
||||
case 1: return _emit(instId, op[0], _none, _none, _none);
|
||||
case 2: return _emit(instId, op[0], op[1], _none, _none);
|
||||
case 3: return _emit(instId, op[0], op[1], op[2], _none);
|
||||
case 4: return _emit(instId, op[0], op[1], op[2], op[3]);
|
||||
case 5: return _emit(instId, op[0], op[1], op[2], op[3], op[4], _none);
|
||||
case 6: return _emit(instId, op[0], op[1], op[2], op[3], op[4], op[5]);
|
||||
|
||||
default:
|
||||
return DebugUtils::errored(kErrorInvalidArgument);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeEmitter - Finalize]
|
||||
// ============================================================================
|
||||
|
||||
Label CodeEmitter::getLabelByName(const char* name, size_t nameLength, uint32_t parentId) noexcept {
|
||||
return Label(_code ? _code->getLabelIdByName(name, nameLength, parentId) : static_cast<uint32_t>(0));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeEmitter - Finalize]
|
||||
// ============================================================================
|
||||
|
||||
Error CodeEmitter::finalize() {
|
||||
// Finalization does nothing by default, overridden by `CodeBuilder`.
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeEmitter - Error Handling]
|
||||
// ============================================================================
|
||||
|
||||
Error CodeEmitter::setLastError(Error error, const char* message) {
|
||||
// This is fatal, CodeEmitter can't set error without being attached to `CodeHolder`.
|
||||
ASMJIT_ASSERT(_code != nullptr);
|
||||
|
||||
// Special case used to reset the last error.
|
||||
if (error == kErrorOk) {
|
||||
_lastError = kErrorOk;
|
||||
_globalOptions &= ~kOptionMaybeFailureCase;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
if (!message)
|
||||
message = DebugUtils::errorAsString(error);
|
||||
|
||||
// Logging is skipped if the error is handled by `ErrorHandler`.
|
||||
ErrorHandler* handler = _code->_errorHandler;
|
||||
if (handler && handler->handleError(error, message, this))
|
||||
return error;
|
||||
|
||||
// The handler->handleError() function may throw an exception or longjmp()
|
||||
// to terminate the execution of `setLastError()`. This is the reason why
|
||||
// we have delayed changing the `_error` member until now.
|
||||
_lastError = error;
|
||||
_globalOptions |= kOptionMaybeFailureCase;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeEmitter - Helpers]
|
||||
// ============================================================================
|
||||
|
||||
bool CodeEmitter::isLabelValid(uint32_t id) const noexcept {
|
||||
size_t index = Operand::unpackId(id);
|
||||
return _code && index < _code->_labels.getLength();
|
||||
}
|
||||
|
||||
Error CodeEmitter::commentf(const char* fmt, ...) {
|
||||
Error err = _lastError;
|
||||
if (err) return err;
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
if (_globalOptions & kOptionLoggingEnabled) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
err = _code->_logger->logv(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
#else
|
||||
ASMJIT_UNUSED(fmt);
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
Error CodeEmitter::commentv(const char* fmt, va_list ap) {
|
||||
Error err = _lastError;
|
||||
if (err) return err;
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
if (_globalOptions & kOptionLoggingEnabled)
|
||||
err = _code->_logger->logv(fmt, ap);
|
||||
#else
|
||||
ASMJIT_UNUSED(fmt);
|
||||
ASMJIT_UNUSED(ap);
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeEmitter - Emit]
|
||||
// ============================================================================
|
||||
|
||||
#define OP const Operand_&
|
||||
|
||||
Error CodeEmitter::emit(uint32_t instId) { return _emit(instId, _none, _none, _none, _none); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0) { return _emit(instId, o0, _none, _none, _none); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1) { return _emit(instId, o0, o1, _none, _none); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2) { return _emit(instId, o0, o1, o2, _none); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3) { return _emit(instId, o0, o1, o2, o3); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4) { return _emit(instId, o0, o1, o2, o3, o4, _none); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, OP o5) { return _emit(instId, o0, o1, o2, o3, o4, o5); }
|
||||
|
||||
Error CodeEmitter::emit(uint32_t instId, int o0) { return _emit(instId, Imm(o0), _none, _none, _none); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, int o1) { return _emit(instId, o0, Imm(o1), _none, _none); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int o2) { return _emit(instId, o0, o1, Imm(o2), _none); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, int o3) { return _emit(instId, o0, o1, o2, Imm(o3)); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), _none); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); }
|
||||
|
||||
Error CodeEmitter::emit(uint32_t instId, int64_t o0) { return _emit(instId, Imm(o0), _none, _none, _none); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, int64_t o1) { return _emit(instId, o0, Imm(o1), _none, _none); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int64_t o2) { return _emit(instId, o0, o1, Imm(o2), _none); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, int64_t o3) { return _emit(instId, o0, o1, o2, Imm(o3)); }
|
||||
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int64_t o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), _none); }
|
||||
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int64_t o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); }
|
||||
|
||||
#undef OP
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
|
@ -1,499 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_CODEEMITTER_H
|
||||
#define _ASMJIT_BASE_CODEEMITTER_H
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/arch.h"
|
||||
#include "../base/codeholder.h"
|
||||
#include "../base/operand.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! \addtogroup asmjit_base
|
||||
//! \{
|
||||
|
||||
// ============================================================================
|
||||
// [Forward Declarations]
|
||||
// ============================================================================
|
||||
|
||||
class ConstPool;
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeEmitter]
|
||||
// ============================================================================
|
||||
|
||||
//! Provides a base foundation to emit code - specialized by \ref Assembler and
|
||||
//! \ref CodeBuilder.
|
||||
class ASMJIT_VIRTAPI CodeEmitter {
|
||||
public:
|
||||
//! CodeEmitter type.
|
||||
ASMJIT_ENUM(Type) {
|
||||
kTypeNone = 0,
|
||||
kTypeAssembler = 1,
|
||||
kTypeBuilder = 2,
|
||||
kTypeCompiler = 3,
|
||||
kTypeCount = 4
|
||||
};
|
||||
|
||||
//! CodeEmitter hints - global settings that affect machine-code generation.
|
||||
ASMJIT_ENUM(Hints) {
|
||||
//! Emit optimized code-alignment sequences.
|
||||
//!
|
||||
//! Default `true`.
|
||||
//!
|
||||
//! X86/X64 Specific
|
||||
//! ----------------
|
||||
//!
|
||||
//! Default align sequence used by X86/X64 architecture is one-byte (0x90)
|
||||
//! opcode that is often shown by disassemblers as nop. However there are
|
||||
//! more optimized align sequences for 2-11 bytes that may execute faster.
|
||||
//! If this feature is enabled AsmJit will generate specialized sequences
|
||||
//! for alignment between 2 to 11 bytes.
|
||||
kHintOptimizedAlign = 0x00000001U,
|
||||
|
||||
//! Emit jump-prediction hints.
|
||||
//!
|
||||
//! Default `false`.
|
||||
//!
|
||||
//! X86/X64 Specific
|
||||
//! ----------------
|
||||
//!
|
||||
//! Jump prediction is usually based on the direction of the jump. If the
|
||||
//! jump is backward it is usually predicted as taken; and if the jump is
|
||||
//! forward it is usually predicted as not-taken. The reason is that loops
|
||||
//! generally use backward jumps and conditions usually use forward jumps.
|
||||
//! However this behavior can be overridden by using instruction prefixes.
|
||||
//! If this option is enabled these hints will be emitted.
|
||||
//!
|
||||
//! This feature is disabled by default, because the only processor that
|
||||
//! used to take into consideration prediction hints was P4. Newer processors
|
||||
//! implement heuristics for branch prediction that ignores any static hints.
|
||||
kHintPredictedJumps = 0x00000002U
|
||||
};
|
||||
|
||||
//! CodeEmitter options that are merged with instruction options.
|
||||
ASMJIT_ENUM(Options) {
|
||||
//! Reserved, used to check for errors in `Assembler::_emit()`. In addition,
|
||||
//! if an emitter is in error state it will have `kOptionMaybeFailureCase`
|
||||
//! set
|
||||
kOptionMaybeFailureCase = 0x00000001U,
|
||||
|
||||
//! Perform a strict validation before the instruction is emitted.
|
||||
kOptionStrictValidation = 0x00000002U,
|
||||
|
||||
//! Logging is enabled and `CodeHolder::getLogger()` should return a valid
|
||||
//! \ref Logger pointer.
|
||||
kOptionLoggingEnabled = 0x00000004U,
|
||||
|
||||
//! Mask of all internal options that are not used to represent instruction
|
||||
//! options, but are used to instrument Assembler and CodeBuilder. These
|
||||
//! options are internal and should not be used outside of AsmJit itself.
|
||||
//!
|
||||
//! NOTE: Reserved options should never appear in `CBInst` options.
|
||||
kOptionReservedMask = 0x00000007U,
|
||||
|
||||
//! Used only by Assembler to mark `_op4` and `_op5` are used.
|
||||
kOptionOp4Op5Used = 0x00000008U,
|
||||
|
||||
//! Prevents following a jump during compilation (CodeCompiler).
|
||||
kOptionUnfollow = 0x00000010U,
|
||||
|
||||
//! Overwrite the destination operand (CodeCompiler).
|
||||
//!
|
||||
//! Hint that is important for register liveness analysis. It tells the
|
||||
//! compiler that the destination operand will be overwritten now or by
|
||||
//! adjacent instructions. CodeCompiler knows when a register is completely
|
||||
//! overwritten by a single instruction, for example you don't have to
|
||||
//! mark "movaps" or "pxor x, x", however, if a pair of instructions is
|
||||
//! used and the first of them doesn't completely overwrite the content
|
||||
//! of the destination, CodeCompiler fails to mark that register as dead.
|
||||
//!
|
||||
//! X86/X64 Specific
|
||||
//! ----------------
|
||||
//!
|
||||
//! - All instructions that always overwrite at least the size of the
|
||||
//! register the virtual-register uses , for example "mov", "movq",
|
||||
//! "movaps" don't need the overwrite option to be used - conversion,
|
||||
//! shuffle, and other miscellaneous instructions included.
|
||||
//!
|
||||
//! - All instructions that clear the destination register if all operands
|
||||
//! are the same, for example "xor x, x", "pcmpeqb x x", etc...
|
||||
//!
|
||||
//! - Consecutive instructions that partially overwrite the variable until
|
||||
//! there is no old content require the `overwrite()` to be used. Some
|
||||
//! examples (not always the best use cases thought):
|
||||
//!
|
||||
//! - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa
|
||||
//! - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa
|
||||
//! - `mov al, ?` followed by `and ax, 0xFF`
|
||||
//! - `mov al, ?` followed by `mov ah, al`
|
||||
//! - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1`
|
||||
//!
|
||||
//! - If allocated variable is used temporarily for scalar operations. For
|
||||
//! example if you allocate a full vector like `X86Compiler::newXmm()`
|
||||
//! and then use that vector for scalar operations you should use
|
||||
//! `overwrite()` directive:
|
||||
//!
|
||||
//! - `sqrtss x, y` - only LO element of `x` is changed, if you don't use
|
||||
//! HI elements, use `X86Compiler.overwrite().sqrtss(x, y)`.
|
||||
kOptionOverwrite = 0x00000020U
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API CodeEmitter(uint32_t type) noexcept;
|
||||
ASMJIT_API virtual ~CodeEmitter() noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Events]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Called after the \ref CodeEmitter was attached to the \ref CodeHolder.
|
||||
virtual Error onAttach(CodeHolder* code) noexcept = 0;
|
||||
//! Called after the \ref CodeEmitter was detached from the \ref CodeHolder.
|
||||
virtual Error onDetach(CodeHolder* code) noexcept = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Code-Generation]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Emit instruction having max 4 operands.
|
||||
virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) = 0;
|
||||
//! Emit instruction having max 6 operands.
|
||||
virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) = 0;
|
||||
//! Emit instruction having operands stored in array.
|
||||
virtual Error _emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount);
|
||||
|
||||
//! Create a new label.
|
||||
virtual Label newLabel() = 0;
|
||||
//! Create a new named label.
|
||||
virtual Label newNamedLabel(
|
||||
const char* name,
|
||||
size_t nameLength = Globals::kInvalidIndex,
|
||||
uint32_t type = Label::kTypeGlobal,
|
||||
uint32_t parentId = 0) = 0;
|
||||
|
||||
//! Get a label by name.
|
||||
//!
|
||||
//! Returns invalid Label in case that the name is invalid or label was not found.
|
||||
//!
|
||||
//! NOTE: This function doesn't trigger ErrorHandler in case the name is
|
||||
//! invalid or no such label exist. You must always check the validity of the
|
||||
//! \ref Label returned.
|
||||
ASMJIT_API Label getLabelByName(
|
||||
const char* name,
|
||||
size_t nameLength = Globals::kInvalidIndex,
|
||||
uint32_t parentId = 0) noexcept;
|
||||
|
||||
//! Bind the `label` to the current position of the current section.
|
||||
//!
|
||||
//! NOTE: Attempt to bind the same label multiple times will return an error.
|
||||
virtual Error bind(const Label& label) = 0;
|
||||
|
||||
//! Align to the `alignment` specified.
|
||||
//!
|
||||
//! The sequence that is used to fill the gap between the aligned location
|
||||
//! and the current location depends on the align `mode`, see \ref AlignMode.
|
||||
virtual Error align(uint32_t mode, uint32_t alignment) = 0;
|
||||
|
||||
//! Embed raw data into the code-buffer.
|
||||
virtual Error embed(const void* data, uint32_t size) = 0;
|
||||
|
||||
//! Embed absolute label address as data (4 or 8 bytes).
|
||||
virtual Error embedLabel(const Label& label) = 0;
|
||||
|
||||
//! Embed a constant pool into the code-buffer in the following steps:
|
||||
//! 1. Align by using kAlignData to the minimum `pool` alignment.
|
||||
//! 2. Bind `label` so it's bound to an aligned location.
|
||||
//! 3. Emit constant pool data.
|
||||
virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0;
|
||||
|
||||
//! Emit a comment string `s` with an optional `len` parameter.
|
||||
virtual Error comment(const char* s, size_t len = Globals::kInvalidIndex) = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Code-Generation Status]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get if the CodeEmitter is initialized (i.e. attached to a \ref CodeHolder).
|
||||
ASMJIT_INLINE bool isInitialized() const noexcept { return _code != nullptr; }
|
||||
|
||||
ASMJIT_API virtual Error finalize();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Code Information]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get information about the code, see \ref CodeInfo.
|
||||
ASMJIT_INLINE const CodeInfo& getCodeInfo() const noexcept { return _codeInfo; }
|
||||
//! Get \ref CodeHolder this CodeEmitter is attached to.
|
||||
ASMJIT_INLINE CodeHolder* getCode() const noexcept { return _code; }
|
||||
|
||||
//! Get information about the architecture, see \ref ArchInfo.
|
||||
ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _codeInfo.getArchInfo(); }
|
||||
|
||||
//! Get if the target architecture is 32-bit.
|
||||
ASMJIT_INLINE bool is32Bit() const noexcept { return getArchInfo().is32Bit(); }
|
||||
//! Get if the target architecture is 64-bit.
|
||||
ASMJIT_INLINE bool is64Bit() const noexcept { return getArchInfo().is64Bit(); }
|
||||
|
||||
//! Get the target architecture type.
|
||||
ASMJIT_INLINE uint32_t getArchType() const noexcept { return getArchInfo().getType(); }
|
||||
//! Get the target architecture sub-type.
|
||||
ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return getArchInfo().getSubType(); }
|
||||
//! Get the target architecture's GP register size (4 or 8 bytes).
|
||||
ASMJIT_INLINE uint32_t getGpSize() const noexcept { return getArchInfo().getGpSize(); }
|
||||
//! Get the number of target GP registers.
|
||||
ASMJIT_INLINE uint32_t getGpCount() const noexcept { return getArchInfo().getGpCount(); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Code-Emitter Type]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get the type of this CodeEmitter, see \ref Type.
|
||||
ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
|
||||
|
||||
ASMJIT_INLINE bool isAssembler() const noexcept { return _type == kTypeAssembler; }
|
||||
ASMJIT_INLINE bool isCodeBuilder() const noexcept { return _type == kTypeBuilder; }
|
||||
ASMJIT_INLINE bool isCodeCompiler() const noexcept { return _type == kTypeCompiler; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Global Information]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get global hints.
|
||||
ASMJIT_INLINE uint32_t getGlobalHints() const noexcept { return _globalHints; }
|
||||
|
||||
//! Get global options.
|
||||
//!
|
||||
//! Global options are merged with instruction options before the instruction
|
||||
//! is encoded. These options have some bits reserved that are used for error
|
||||
//! checking, logging, and strict validation. Other options are globals that
|
||||
//! affect each instruction, for example if VEX3 is set globally, it will all
|
||||
//! instructions, even those that don't have such option set.
|
||||
ASMJIT_INLINE uint32_t getGlobalOptions() const noexcept { return _globalOptions; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Error Handling]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get if the object is in error state.
|
||||
//!
|
||||
//! Error state means that it does not consume anything unless the error
|
||||
//! state is reset by calling `resetLastError()`. Use `getLastError()` to
|
||||
//! get the last error that put the object into the error state.
|
||||
ASMJIT_INLINE bool isInErrorState() const noexcept { return _lastError != kErrorOk; }
|
||||
|
||||
//! Get the last error code.
|
||||
ASMJIT_INLINE Error getLastError() const noexcept { return _lastError; }
|
||||
//! Set the last error code and propagate it through the error handler.
|
||||
ASMJIT_API Error setLastError(Error error, const char* message = nullptr);
|
||||
//! Clear the last error code and return `kErrorOk`.
|
||||
ASMJIT_INLINE Error resetLastError() noexcept { return setLastError(kErrorOk); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors That Affect the Next Instruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get options of the next instruction.
|
||||
ASMJIT_INLINE uint32_t getOptions() const noexcept { return _options; }
|
||||
//! Set options of the next instruction.
|
||||
ASMJIT_INLINE void setOptions(uint32_t options) noexcept { _options = options; }
|
||||
//! Add options of the next instruction.
|
||||
ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _options |= options; }
|
||||
//! Reset options of the next instruction.
|
||||
ASMJIT_INLINE void resetOptions() noexcept { _options = 0; }
|
||||
|
||||
//! Get if the extra register operand is valid.
|
||||
ASMJIT_INLINE bool hasExtraReg() const noexcept { return _extraReg.isValid(); }
|
||||
//! Get an extra operand that will be used by the next instruction (architecture specific).
|
||||
ASMJIT_INLINE const RegOnly& getExtraReg() const noexcept { return _extraReg; }
|
||||
//! Set an extra operand that will be used by the next instruction (architecture specific).
|
||||
ASMJIT_INLINE void setExtraReg(const Reg& reg) noexcept { _extraReg.init(reg); }
|
||||
//! Set an extra operand that will be used by the next instruction (architecture specific).
|
||||
ASMJIT_INLINE void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); }
|
||||
//! Reset an extra operand that will be used by the next instruction (architecture specific).
|
||||
ASMJIT_INLINE void resetExtraReg() noexcept { _extraReg.reset(); }
|
||||
|
||||
//! Get annotation of the next instruction.
|
||||
ASMJIT_INLINE const char* getInlineComment() const noexcept { return _inlineComment; }
|
||||
//! Set annotation of the next instruction.
|
||||
//!
|
||||
//! NOTE: This string is set back to null by `_emit()`, but until that it has
|
||||
//! to remain valid as `CodeEmitter` is not required to make a copy of it (and
|
||||
//! it would be slow to do that for each instruction).
|
||||
ASMJIT_INLINE void setInlineComment(const char* s) noexcept { _inlineComment = s; }
|
||||
//! Reset annotation of the next instruction to null.
|
||||
ASMJIT_INLINE void resetInlineComment() noexcept { _inlineComment = nullptr; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Helpers]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get if the `label` is valid (i.e. registered).
|
||||
ASMJIT_INLINE bool isLabelValid(const Label& label) const noexcept {
|
||||
return isLabelValid(label.getId());
|
||||
}
|
||||
|
||||
//! Get if the label `id` is valid (i.e. registered).
|
||||
ASMJIT_API bool isLabelValid(uint32_t id) const noexcept;
|
||||
|
||||
//! Emit a formatted string `fmt`.
|
||||
ASMJIT_API Error commentf(const char* fmt, ...);
|
||||
//! Emit a formatted string `fmt` (va_list version).
|
||||
ASMJIT_API Error commentv(const char* fmt, va_list ap);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Emit]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// NOTE: These `emit()` helpers are designed to address a code-bloat generated
|
||||
// by C++ compilers to call a function having many arguments. Each parameter to
|
||||
// `_emit()` requires code to pass it, which means that if we default to 4
|
||||
// operand parameters in `_emit()` and instId the C++ compiler would have to
|
||||
// generate a virtual function call having 5 parameters, which is quite a lot.
|
||||
// Since by default asm instructions have 2 to 3 operands it's better to
|
||||
// introduce helpers that pass those and fill all the remaining with `_none`.
|
||||
|
||||
//! Emit an instruction.
|
||||
ASMJIT_API Error emit(uint32_t instId);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5);
|
||||
|
||||
//! Emit an instruction that has a 32-bit signed immediate operand.
|
||||
ASMJIT_API Error emit(uint32_t instId, int o0);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, int o1);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, int o2);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, int o3);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, int o4);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, int o5);
|
||||
|
||||
//! Emit an instruction that has a 64-bit signed immediate operand.
|
||||
ASMJIT_API Error emit(uint32_t instId, int64_t o0);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, int64_t o1);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, int64_t o2);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, int64_t o3);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, int64_t o4);
|
||||
//! \overload
|
||||
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, int64_t o5);
|
||||
|
||||
//! \overload
|
||||
ASMJIT_INLINE Error emit(uint32_t instId, unsigned int o0) {
|
||||
return emit(instId, static_cast<int64_t>(o0));
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, unsigned int o1) {
|
||||
return emit(instId, o0, static_cast<int64_t>(o1));
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, unsigned int o2) {
|
||||
return emit(instId, o0, o1, static_cast<int64_t>(o2));
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, unsigned int o3) {
|
||||
return emit(instId, o0, o1, o2, static_cast<int64_t>(o3));
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, unsigned int o4) {
|
||||
return emit(instId, o0, o1, o2, o3, static_cast<int64_t>(o4));
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, unsigned int o5) {
|
||||
return emit(instId, o0, o1, o2, o3, o4, static_cast<int64_t>(o5));
|
||||
}
|
||||
|
||||
//! \overload
|
||||
ASMJIT_INLINE Error emit(uint32_t instId, uint64_t o0) {
|
||||
return emit(instId, static_cast<int64_t>(o0));
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, uint64_t o1) {
|
||||
return emit(instId, o0, static_cast<int64_t>(o1));
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, uint64_t o2) {
|
||||
return emit(instId, o0, o1, static_cast<int64_t>(o2));
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, uint64_t o3) {
|
||||
return emit(instId, o0, o1, o2, static_cast<int64_t>(o3));
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, uint64_t o4) {
|
||||
return emit(instId, o0, o1, o2, o3, static_cast<int64_t>(o4));
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, uint64_t o5) {
|
||||
return emit(instId, o0, o1, o2, o3, o4, static_cast<int64_t>(o5));
|
||||
}
|
||||
|
||||
ASMJIT_INLINE Error emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
|
||||
return _emitOpArray(instId, opArray, opCount);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
CodeInfo _codeInfo; //!< Basic information about the code (matches CodeHolder::_codeInfo).
|
||||
CodeHolder* _code; //!< CodeHolder the CodeEmitter is attached to.
|
||||
CodeEmitter* _nextEmitter; //!< Linked list of `CodeEmitter`s attached to the same \ref CodeHolder.
|
||||
|
||||
uint8_t _type; //!< See CodeEmitter::Type.
|
||||
uint8_t _destroyed; //!< Set by ~CodeEmitter() before calling `_code->detach()`.
|
||||
uint8_t _finalized; //!< True if the CodeEmitter is finalized (CodeBuilder & CodeCompiler).
|
||||
uint8_t _reserved; //!< \internal
|
||||
Error _lastError; //!< Last error code.
|
||||
|
||||
uint32_t _privateData; //!< Internal private data used freely by any CodeEmitter.
|
||||
uint32_t _globalHints; //!< Global hints, always in sync with CodeHolder.
|
||||
uint32_t _globalOptions; //!< Global options, combined with `_options` before used by each instruction.
|
||||
|
||||
uint32_t _options; //!< Used to pass instruction options (affects the next instruction).
|
||||
RegOnly _extraReg; //!< Extra register (op-mask {k} on AVX-512) (affects the next instruction).
|
||||
const char* _inlineComment; //!< Inline comment of the next instruction (affects the next instruction).
|
||||
|
||||
Operand_ _none; //!< Used to pass unused operands to `_emit()` instead of passing null.
|
||||
Reg _nativeGpReg; //!< Native GP register with zero id.
|
||||
const Reg* _nativeGpArray; //!< Array of native registers indexed from zero.
|
||||
};
|
||||
|
||||
//! \}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_CODEEMITTER_H
|
|
@ -1,696 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/assembler.h"
|
||||
#include "../base/utils.h"
|
||||
#include "../base/vmem.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ErrorHandler]
|
||||
// ============================================================================
|
||||
|
||||
ErrorHandler::ErrorHandler() noexcept {}
|
||||
ErrorHandler::~ErrorHandler() noexcept {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeHolder - Utilities]
|
||||
// ============================================================================
|
||||
|
||||
static void CodeHolder_setGlobalOption(CodeHolder* self, uint32_t clear, uint32_t add) noexcept {
|
||||
// Modify global options of `CodeHolder` itself.
|
||||
self->_globalOptions = (self->_globalOptions & ~clear) | add;
|
||||
|
||||
// Modify all global options of all `CodeEmitter`s attached.
|
||||
CodeEmitter* emitter = self->_emitters;
|
||||
while (emitter) {
|
||||
emitter->_globalOptions = (emitter->_globalOptions & ~clear) | add;
|
||||
emitter = emitter->_nextEmitter;
|
||||
}
|
||||
}
|
||||
|
||||
static void CodeHolder_resetInternal(CodeHolder* self, bool releaseMemory) noexcept {
|
||||
// Detach all `CodeEmitter`s.
|
||||
while (self->_emitters)
|
||||
self->detach(self->_emitters);
|
||||
|
||||
// Reset everything into its construction state.
|
||||
self->_codeInfo.reset();
|
||||
self->_globalHints = 0;
|
||||
self->_globalOptions = 0;
|
||||
self->_logger = nullptr;
|
||||
self->_errorHandler = nullptr;
|
||||
|
||||
self->_unresolvedLabelsCount = 0;
|
||||
self->_trampolinesSize = 0;
|
||||
|
||||
// Reset all sections.
|
||||
size_t numSections = self->_sections.getLength();
|
||||
for (size_t i = 0; i < numSections; i++) {
|
||||
SectionEntry* section = self->_sections[i];
|
||||
if (section->_buffer.hasData() && !section->_buffer.isExternal())
|
||||
Internal::releaseMemory(section->_buffer._data);
|
||||
section->_buffer._data = nullptr;
|
||||
section->_buffer._capacity = 0;
|
||||
}
|
||||
|
||||
// Reset zone allocator and all containers using it.
|
||||
ZoneHeap* heap = &self->_baseHeap;
|
||||
|
||||
self->_namedLabels.reset(heap);
|
||||
self->_relocations.reset();
|
||||
self->_labels.reset();
|
||||
self->_sections.reset();
|
||||
|
||||
heap->reset(&self->_baseZone);
|
||||
self->_baseZone.reset(releaseMemory);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeHolder - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
CodeHolder::CodeHolder() noexcept
|
||||
: _codeInfo(),
|
||||
_globalHints(0),
|
||||
_globalOptions(0),
|
||||
_emitters(nullptr),
|
||||
_cgAsm(nullptr),
|
||||
_logger(nullptr),
|
||||
_errorHandler(nullptr),
|
||||
_unresolvedLabelsCount(0),
|
||||
_trampolinesSize(0),
|
||||
_baseZone(16384 - Zone::kZoneOverhead),
|
||||
_dataZone(16384 - Zone::kZoneOverhead),
|
||||
_baseHeap(&_baseZone),
|
||||
_namedLabels(&_baseHeap) {}
|
||||
|
||||
CodeHolder::~CodeHolder() noexcept {
|
||||
CodeHolder_resetInternal(this, true);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeHolder - Init / Reset]
|
||||
// ============================================================================
|
||||
|
||||
Error CodeHolder::init(const CodeInfo& info) noexcept {
|
||||
// Cannot reinitialize if it's locked or there is one or more CodeEmitter
|
||||
// attached.
|
||||
if (isInitialized())
|
||||
return DebugUtils::errored(kErrorAlreadyInitialized);
|
||||
|
||||
// If we are just initializing there should be no emitters attached).
|
||||
ASMJIT_ASSERT(_emitters == nullptr);
|
||||
|
||||
// Create the default section and insert it to the `_sections` array.
|
||||
Error err = _sections.willGrow(&_baseHeap);
|
||||
if (err == kErrorOk) {
|
||||
SectionEntry* se = _baseZone.allocZeroedT<SectionEntry>();
|
||||
if (ASMJIT_LIKELY(se)) {
|
||||
se->_flags = SectionEntry::kFlagExec | SectionEntry::kFlagConst;
|
||||
se->_setDefaultName('.', 't', 'e', 'x', 't');
|
||||
_sections.appendUnsafe(se);
|
||||
}
|
||||
else {
|
||||
err = DebugUtils::errored(kErrorNoHeapMemory);
|
||||
}
|
||||
}
|
||||
|
||||
if (ASMJIT_UNLIKELY(err)) {
|
||||
_baseZone.reset(false);
|
||||
return err;
|
||||
}
|
||||
else {
|
||||
_codeInfo = info;
|
||||
return kErrorOk;
|
||||
}
|
||||
}
|
||||
|
||||
void CodeHolder::reset(bool releaseMemory) noexcept {
|
||||
CodeHolder_resetInternal(this, releaseMemory);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeHolder - Attach / Detach]
|
||||
// ============================================================================
|
||||
|
||||
Error CodeHolder::attach(CodeEmitter* emitter) noexcept {
|
||||
// Catch a possible misuse of the API.
|
||||
if (!emitter)
|
||||
return DebugUtils::errored(kErrorInvalidArgument);
|
||||
|
||||
uint32_t type = emitter->getType();
|
||||
if (type == CodeEmitter::kTypeNone || type >= CodeEmitter::kTypeCount)
|
||||
return DebugUtils::errored(kErrorInvalidState);
|
||||
|
||||
// This is suspicious, but don't fail if `emitter` matches.
|
||||
if (emitter->_code != nullptr) {
|
||||
if (emitter->_code == this) return kErrorOk;
|
||||
return DebugUtils::errored(kErrorInvalidState);
|
||||
}
|
||||
|
||||
// Special case - attach `Assembler`.
|
||||
CodeEmitter** pSlot = nullptr;
|
||||
if (type == CodeEmitter::kTypeAssembler) {
|
||||
if (_cgAsm)
|
||||
return DebugUtils::errored(kErrorSlotOccupied);
|
||||
pSlot = reinterpret_cast<CodeEmitter**>(&_cgAsm);
|
||||
}
|
||||
|
||||
Error err = emitter->onAttach(this);
|
||||
if (err != kErrorOk) return err;
|
||||
|
||||
// Add to a single-linked list of `CodeEmitter`s.
|
||||
emitter->_nextEmitter = _emitters;
|
||||
_emitters = emitter;
|
||||
if (pSlot) *pSlot = emitter;
|
||||
|
||||
// Establish the connection.
|
||||
emitter->_code = this;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error CodeHolder::detach(CodeEmitter* emitter) noexcept {
|
||||
if (!emitter)
|
||||
return DebugUtils::errored(kErrorInvalidArgument);
|
||||
|
||||
if (emitter->_code != this)
|
||||
return DebugUtils::errored(kErrorInvalidState);
|
||||
|
||||
uint32_t type = emitter->getType();
|
||||
Error err = kErrorOk;
|
||||
|
||||
// NOTE: We always detach if we were asked to, if error happens during
|
||||
// `emitter->onDetach()` we just propagate it, but the CodeEmitter will
|
||||
// be detached.
|
||||
if (!emitter->_destroyed) {
|
||||
if (type == CodeEmitter::kTypeAssembler)
|
||||
static_cast<Assembler*>(emitter)->sync();
|
||||
err = emitter->onDetach(this);
|
||||
}
|
||||
|
||||
// Special case - detach `Assembler`.
|
||||
if (type == CodeEmitter::kTypeAssembler)
|
||||
_cgAsm = nullptr;
|
||||
|
||||
// Remove from a single-linked list of `CodeEmitter`s.
|
||||
CodeEmitter** pPrev = &_emitters;
|
||||
for (;;) {
|
||||
ASMJIT_ASSERT(*pPrev != nullptr);
|
||||
CodeEmitter* cur = *pPrev;
|
||||
|
||||
if (cur == emitter) {
|
||||
*pPrev = emitter->_nextEmitter;
|
||||
break;
|
||||
}
|
||||
|
||||
pPrev = &cur->_nextEmitter;
|
||||
}
|
||||
|
||||
emitter->_code = nullptr;
|
||||
emitter->_nextEmitter = nullptr;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeHolder - Sync]
|
||||
// ============================================================================
|
||||
|
||||
void CodeHolder::sync() noexcept {
|
||||
if (_cgAsm) _cgAsm->sync();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeHolder - Result Information]
|
||||
// ============================================================================
|
||||
|
||||
size_t CodeHolder::getCodeSize() const noexcept {
|
||||
// Reflect all changes first.
|
||||
const_cast<CodeHolder*>(this)->sync();
|
||||
|
||||
// TODO: Support sections.
|
||||
return _sections[0]->_buffer._length + getTrampolinesSize();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeHolder - Logging & Error Handling]
|
||||
// ============================================================================
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
void CodeHolder::setLogger(Logger* logger) noexcept {
|
||||
uint32_t opt = 0;
|
||||
if (logger) opt = CodeEmitter::kOptionLoggingEnabled;
|
||||
|
||||
_logger = logger;
|
||||
CodeHolder_setGlobalOption(this, CodeEmitter::kOptionLoggingEnabled, opt);
|
||||
}
|
||||
#endif // !ASMJIT_DISABLE_LOGGING
|
||||
|
||||
Error CodeHolder::setErrorHandler(ErrorHandler* handler) noexcept {
|
||||
_errorHandler = handler;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeHolder - Sections]
|
||||
// ============================================================================
|
||||
|
||||
static Error CodeHolder_reserveInternal(CodeHolder* self, CodeBuffer* cb, size_t n) noexcept {
|
||||
uint8_t* oldData = cb->_data;
|
||||
uint8_t* newData;
|
||||
|
||||
if (oldData && !cb->isExternal())
|
||||
newData = static_cast<uint8_t*>(Internal::reallocMemory(oldData, n));
|
||||
else
|
||||
newData = static_cast<uint8_t*>(Internal::allocMemory(n));
|
||||
|
||||
if (ASMJIT_UNLIKELY(!newData))
|
||||
return DebugUtils::errored(kErrorNoHeapMemory);
|
||||
|
||||
cb->_data = newData;
|
||||
cb->_capacity = n;
|
||||
|
||||
// Update the `Assembler` pointers if attached. Maybe we should introduce an
|
||||
// event for this, but since only one Assembler can be attached at a time it
|
||||
// should not matter how these pointers are updated.
|
||||
Assembler* a = self->_cgAsm;
|
||||
if (a && &a->_section->_buffer == cb) {
|
||||
size_t offset = a->getOffset();
|
||||
|
||||
a->_bufferData = newData;
|
||||
a->_bufferEnd = newData + n;
|
||||
a->_bufferPtr = newData + offset;
|
||||
}
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error CodeHolder::growBuffer(CodeBuffer* cb, size_t n) noexcept {
|
||||
// This is most likely called by `Assembler` so `sync()` shouldn't be needed,
|
||||
// however, if this is called by the user and the currently attached Assembler
|
||||
// did generate some code we could lose that, so sync now and make sure the
|
||||
// section length is updated.
|
||||
if (_cgAsm) _cgAsm->sync();
|
||||
|
||||
// Now the length of the section must be valid.
|
||||
size_t length = cb->getLength();
|
||||
if (ASMJIT_UNLIKELY(n > IntTraits<uintptr_t>::maxValue() - length))
|
||||
return DebugUtils::errored(kErrorNoHeapMemory);
|
||||
|
||||
// We can now check if growing the buffer is really necessary. It's unlikely
|
||||
// that this function is called while there is still room for `n` bytes.
|
||||
size_t capacity = cb->getCapacity();
|
||||
size_t required = cb->getLength() + n;
|
||||
if (ASMJIT_UNLIKELY(required <= capacity)) return kErrorOk;
|
||||
|
||||
if (cb->isFixedSize())
|
||||
return DebugUtils::errored(kErrorCodeTooLarge);
|
||||
|
||||
if (capacity < 8096)
|
||||
capacity = 8096;
|
||||
else
|
||||
capacity += Globals::kAllocOverhead;
|
||||
|
||||
do {
|
||||
size_t old = capacity;
|
||||
if (capacity < Globals::kAllocThreshold)
|
||||
capacity *= 2;
|
||||
else
|
||||
capacity += Globals::kAllocThreshold;
|
||||
|
||||
if (capacity < Globals::kAllocThreshold)
|
||||
capacity *= 2;
|
||||
else
|
||||
capacity += Globals::kAllocThreshold;
|
||||
|
||||
// Overflow.
|
||||
if (ASMJIT_UNLIKELY(old > capacity))
|
||||
return DebugUtils::errored(kErrorNoHeapMemory);
|
||||
} while (capacity - Globals::kAllocOverhead < required);
|
||||
|
||||
return CodeHolder_reserveInternal(this, cb, capacity - Globals::kAllocOverhead);
|
||||
}
|
||||
|
||||
Error CodeHolder::reserveBuffer(CodeBuffer* cb, size_t n) noexcept {
|
||||
size_t capacity = cb->getCapacity();
|
||||
if (n <= capacity) return kErrorOk;
|
||||
|
||||
if (cb->isFixedSize())
|
||||
return DebugUtils::errored(kErrorCodeTooLarge);
|
||||
|
||||
// We must sync, as mentioned in `growBuffer()` as well.
|
||||
if (_cgAsm) _cgAsm->sync();
|
||||
|
||||
return CodeHolder_reserveInternal(this, cb, n);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeHolder - Labels & Symbols]
|
||||
// ============================================================================
|
||||
|
||||
namespace {
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! Only used to lookup a label from `_namedLabels`.
|
||||
class LabelByName {
|
||||
public:
|
||||
ASMJIT_INLINE LabelByName(const char* name, size_t nameLength, uint32_t hVal) noexcept
|
||||
: name(name),
|
||||
nameLength(static_cast<uint32_t>(nameLength)) {}
|
||||
|
||||
ASMJIT_INLINE bool matches(const LabelEntry* entry) const noexcept {
|
||||
return static_cast<uint32_t>(entry->getNameLength()) == nameLength &&
|
||||
::memcmp(entry->getName(), name, nameLength) == 0;
|
||||
}
|
||||
|
||||
const char* name;
|
||||
uint32_t nameLength;
|
||||
uint32_t hVal;
|
||||
};
|
||||
|
||||
// Returns a hash of `name` and fixes `nameLength` if it's `Globals::kInvalidIndex`.
|
||||
static uint32_t CodeHolder_hashNameAndFixLen(const char* name, size_t& nameLength) noexcept {
|
||||
uint32_t hVal = 0;
|
||||
if (nameLength == Globals::kInvalidIndex) {
|
||||
size_t i = 0;
|
||||
for (;;) {
|
||||
uint8_t c = static_cast<uint8_t>(name[i]);
|
||||
if (!c) break;
|
||||
hVal = Utils::hashRound(hVal, c);
|
||||
i++;
|
||||
}
|
||||
nameLength = i;
|
||||
}
|
||||
else {
|
||||
for (size_t i = 0; i < nameLength; i++) {
|
||||
uint8_t c = static_cast<uint8_t>(name[i]);
|
||||
if (ASMJIT_UNLIKELY(!c)) return DebugUtils::errored(kErrorInvalidLabelName);
|
||||
hVal = Utils::hashRound(hVal, c);
|
||||
}
|
||||
}
|
||||
return hVal;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
LabelLink* CodeHolder::newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel) noexcept {
|
||||
LabelLink* link = _baseHeap.allocT<LabelLink>();
|
||||
if (ASMJIT_UNLIKELY(!link)) return nullptr;
|
||||
|
||||
link->prev = le->_links;
|
||||
le->_links = link;
|
||||
|
||||
link->sectionId = sectionId;
|
||||
link->relocId = RelocEntry::kInvalidId;
|
||||
link->offset = offset;
|
||||
link->rel = rel;
|
||||
|
||||
_unresolvedLabelsCount++;
|
||||
return link;
|
||||
}
|
||||
|
||||
Error CodeHolder::newLabelId(uint32_t& idOut) noexcept {
|
||||
idOut = 0;
|
||||
|
||||
size_t index = _labels.getLength();
|
||||
if (ASMJIT_LIKELY(index >= Operand::kPackedIdCount))
|
||||
return DebugUtils::errored(kErrorLabelIndexOverflow);
|
||||
|
||||
ASMJIT_PROPAGATE(_labels.willGrow(&_baseHeap));
|
||||
LabelEntry* le = _baseHeap.allocZeroedT<LabelEntry>();
|
||||
|
||||
if (ASMJIT_UNLIKELY(!le))
|
||||
return DebugUtils::errored(kErrorNoHeapMemory);;
|
||||
|
||||
uint32_t id = Operand::packId(static_cast<uint32_t>(index));
|
||||
le->_setId(id);
|
||||
le->_parentId = 0;
|
||||
le->_sectionId = SectionEntry::kInvalidId;
|
||||
le->_offset = 0;
|
||||
|
||||
_labels.appendUnsafe(le);
|
||||
idOut = id;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error CodeHolder::newNamedLabelId(uint32_t& idOut, const char* name, size_t nameLength, uint32_t type, uint32_t parentId) noexcept {
|
||||
idOut = 0;
|
||||
uint32_t hVal = CodeHolder_hashNameAndFixLen(name, nameLength);
|
||||
|
||||
if (ASMJIT_UNLIKELY(nameLength == 0))
|
||||
return DebugUtils::errored(kErrorInvalidLabelName);
|
||||
|
||||
if (ASMJIT_UNLIKELY(nameLength > Globals::kMaxLabelLength))
|
||||
return DebugUtils::errored(kErrorLabelNameTooLong);
|
||||
|
||||
switch (type) {
|
||||
case Label::kTypeLocal:
|
||||
if (ASMJIT_UNLIKELY(Operand::unpackId(parentId) >= _labels.getLength()))
|
||||
return DebugUtils::errored(kErrorInvalidParentLabel);
|
||||
|
||||
hVal ^= parentId;
|
||||
break;
|
||||
|
||||
case Label::kTypeGlobal:
|
||||
if (ASMJIT_UNLIKELY(parentId != 0))
|
||||
return DebugUtils::errored(kErrorNonLocalLabelCantHaveParent);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return DebugUtils::errored(kErrorInvalidArgument);
|
||||
}
|
||||
|
||||
// Don't allow to insert duplicates. Local labels allow duplicates that have
|
||||
// different id, this is already accomplished by having a different hashes
|
||||
// between the same label names having different parent labels.
|
||||
LabelEntry* le = _namedLabels.get(LabelByName(name, nameLength, hVal));
|
||||
if (ASMJIT_UNLIKELY(le))
|
||||
return DebugUtils::errored(kErrorLabelAlreadyDefined);
|
||||
|
||||
Error err = kErrorOk;
|
||||
size_t index = _labels.getLength();
|
||||
|
||||
if (ASMJIT_UNLIKELY(index >= Operand::kPackedIdCount))
|
||||
return DebugUtils::errored(kErrorLabelIndexOverflow);
|
||||
|
||||
ASMJIT_PROPAGATE(_labels.willGrow(&_baseHeap));
|
||||
le = _baseHeap.allocZeroedT<LabelEntry>();
|
||||
|
||||
if (ASMJIT_UNLIKELY(!le))
|
||||
return DebugUtils::errored(kErrorNoHeapMemory);
|
||||
|
||||
uint32_t id = Operand::packId(static_cast<uint32_t>(index));
|
||||
le->_hVal = hVal;
|
||||
le->_setId(id);
|
||||
le->_type = static_cast<uint8_t>(type);
|
||||
le->_parentId = 0;
|
||||
le->_sectionId = SectionEntry::kInvalidId;
|
||||
le->_offset = 0;
|
||||
|
||||
if (le->_name.mustEmbed(nameLength)) {
|
||||
le->_name.setEmbedded(name, nameLength);
|
||||
}
|
||||
else {
|
||||
char* nameExternal = static_cast<char*>(_dataZone.dup(name, nameLength, true));
|
||||
if (ASMJIT_UNLIKELY(!nameExternal))
|
||||
return DebugUtils::errored(kErrorNoHeapMemory);
|
||||
le->_name.setExternal(nameExternal, nameLength);
|
||||
}
|
||||
|
||||
_labels.appendUnsafe(le);
|
||||
_namedLabels.put(le);
|
||||
|
||||
idOut = id;
|
||||
return err;
|
||||
}
|
||||
|
||||
uint32_t CodeHolder::getLabelIdByName(const char* name, size_t nameLength, uint32_t parentId) noexcept {
|
||||
uint32_t hVal = CodeHolder_hashNameAndFixLen(name, nameLength);
|
||||
if (ASMJIT_UNLIKELY(!nameLength)) return 0;
|
||||
|
||||
LabelEntry* le = _namedLabels.get(LabelByName(name, nameLength, hVal));
|
||||
return le ? le->getId() : static_cast<uint32_t>(0);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeEmitter - Relocations]
|
||||
// ============================================================================
|
||||
|
||||
//! Encode MOD byte.
|
||||
static ASMJIT_INLINE uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) noexcept {
|
||||
return (m << 6) | (o << 3) | rm;
|
||||
}
|
||||
|
||||
Error CodeHolder::newRelocEntry(RelocEntry** dst, uint32_t type, uint32_t size) noexcept {
|
||||
ASMJIT_PROPAGATE(_relocations.willGrow(&_baseHeap));
|
||||
|
||||
size_t index = _relocations.getLength();
|
||||
if (ASMJIT_UNLIKELY(index > size_t(0xFFFFFFFFU)))
|
||||
return DebugUtils::errored(kErrorRelocIndexOverflow);
|
||||
|
||||
RelocEntry* re = _baseHeap.allocZeroedT<RelocEntry>();
|
||||
if (ASMJIT_UNLIKELY(!re))
|
||||
return DebugUtils::errored(kErrorNoHeapMemory);
|
||||
|
||||
re->_id = static_cast<uint32_t>(index);
|
||||
re->_type = static_cast<uint8_t>(type);
|
||||
re->_size = static_cast<uint8_t>(size);
|
||||
re->_sourceSectionId = SectionEntry::kInvalidId;
|
||||
re->_targetSectionId = SectionEntry::kInvalidId;
|
||||
_relocations.appendUnsafe(re);
|
||||
|
||||
*dst = re;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// TODO: Support multiple sections, this only relocates the first.
|
||||
// TODO: This should go to Runtime as it's responsible for relocating the
|
||||
// code, CodeHolder should just hold it.
|
||||
size_t CodeHolder::relocate(void* _dst, uint64_t baseAddress) const noexcept {
|
||||
SectionEntry* section = _sections[0];
|
||||
ASMJIT_ASSERT(section != nullptr);
|
||||
|
||||
uint8_t* dst = static_cast<uint8_t*>(_dst);
|
||||
if (baseAddress == Globals::kNoBaseAddress)
|
||||
baseAddress = static_cast<uint64_t>((uintptr_t)dst);
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
Logger* logger = getLogger();
|
||||
#endif // ASMJIT_DISABLE_LOGGING
|
||||
|
||||
size_t minCodeSize = section->getBuffer().getLength(); // Minimum code size.
|
||||
size_t maxCodeSize = getCodeSize(); // Includes all possible trampolines.
|
||||
|
||||
// We will copy the exact size of the generated code. Extra code for trampolines
|
||||
// is generated on-the-fly by the relocator (this code doesn't exist at the moment).
|
||||
::memcpy(dst, section->_buffer._data, minCodeSize);
|
||||
|
||||
// Trampoline offset from the beginning of dst/baseAddress.
|
||||
size_t trampOffset = minCodeSize;
|
||||
|
||||
// Relocate all recorded locations.
|
||||
size_t numRelocs = _relocations.getLength();
|
||||
const RelocEntry* const* reArray = _relocations.getData();
|
||||
|
||||
for (size_t i = 0; i < numRelocs; i++) {
|
||||
const RelocEntry* re = reArray[i];
|
||||
|
||||
// Possibly deleted or optimized out relocation entry.
|
||||
if (re->getType() == RelocEntry::kTypeNone)
|
||||
continue;
|
||||
|
||||
uint64_t ptr = re->getData();
|
||||
size_t codeOffset = static_cast<size_t>(re->getSourceOffset());
|
||||
|
||||
// Make sure that the `RelocEntry` is correct, we don't want to write
|
||||
// out of bounds in `dst`.
|
||||
if (ASMJIT_UNLIKELY(codeOffset + re->getSize() > maxCodeSize))
|
||||
return DebugUtils::errored(kErrorInvalidRelocEntry);
|
||||
|
||||
// Whether to use trampoline, can be only used if relocation type is `kRelocTrampoline`.
|
||||
bool useTrampoline = false;
|
||||
|
||||
switch (re->getType()) {
|
||||
case RelocEntry::kTypeAbsToAbs: {
|
||||
break;
|
||||
}
|
||||
|
||||
case RelocEntry::kTypeRelToAbs: {
|
||||
ptr += baseAddress;
|
||||
break;
|
||||
}
|
||||
|
||||
case RelocEntry::kTypeAbsToRel: {
|
||||
ptr -= baseAddress + re->getSourceOffset() + re->getSize();
|
||||
break;
|
||||
}
|
||||
|
||||
case RelocEntry::kTypeTrampoline: {
|
||||
if (re->getSize() != 4)
|
||||
return DebugUtils::errored(kErrorInvalidRelocEntry);
|
||||
|
||||
ptr -= baseAddress + re->getSourceOffset() + re->getSize();
|
||||
if (!Utils::isInt32(static_cast<int64_t>(ptr))) {
|
||||
ptr = (uint64_t)trampOffset - re->getSourceOffset() - re->getSize();
|
||||
useTrampoline = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return DebugUtils::errored(kErrorInvalidRelocEntry);
|
||||
}
|
||||
|
||||
switch (re->getSize()) {
|
||||
case 1:
|
||||
Utils::writeU8(dst + codeOffset, static_cast<uint32_t>(ptr & 0xFFU));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
Utils::writeU32u(dst + codeOffset, static_cast<uint32_t>(ptr & 0xFFFFFFFFU));
|
||||
break;
|
||||
|
||||
case 8:
|
||||
Utils::writeU64u(dst + codeOffset, ptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
return DebugUtils::errored(kErrorInvalidRelocEntry);
|
||||
}
|
||||
|
||||
// Handle the trampoline case.
|
||||
if (useTrampoline) {
|
||||
// Bytes that replace [REX, OPCODE] bytes.
|
||||
uint32_t byte0 = 0xFF;
|
||||
uint32_t byte1 = dst[codeOffset - 1];
|
||||
|
||||
if (byte1 == 0xE8) {
|
||||
// Patch CALL/MOD byte to FF/2 (-> 0x15).
|
||||
byte1 = x86EncodeMod(0, 2, 5);
|
||||
}
|
||||
else if (byte1 == 0xE9) {
|
||||
// Patch JMP/MOD byte to FF/4 (-> 0x25).
|
||||
byte1 = x86EncodeMod(0, 4, 5);
|
||||
}
|
||||
else {
|
||||
return DebugUtils::errored(kErrorInvalidRelocEntry);
|
||||
}
|
||||
|
||||
// Patch `jmp/call` instruction.
|
||||
ASMJIT_ASSERT(codeOffset >= 2);
|
||||
dst[codeOffset - 2] = static_cast<uint8_t>(byte0);
|
||||
dst[codeOffset - 1] = static_cast<uint8_t>(byte1);
|
||||
|
||||
// Store absolute address and advance the trampoline pointer.
|
||||
Utils::writeU64u(dst + trampOffset, re->getData());
|
||||
trampOffset += 8;
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
if (logger)
|
||||
logger->logf("[reloc] dq 0x%016llX ; Trampoline\n", re->getData());
|
||||
#endif // !ASMJIT_DISABLE_LOGGING
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no trampolines this is the same as `minCodeSize`.
|
||||
return trampOffset;
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
|
@ -1,748 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_CODEHOLDER_H
|
||||
#define _ASMJIT_BASE_CODEHOLDER_H
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/arch.h"
|
||||
#include "../base/func.h"
|
||||
#include "../base/logging.h"
|
||||
#include "../base/operand.h"
|
||||
#include "../base/simdtypes.h"
|
||||
#include "../base/utils.h"
|
||||
#include "../base/zone.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! \addtogroup asmjit_base
|
||||
//! \{
|
||||
|
||||
// ============================================================================
|
||||
// [Forward Declarations]
|
||||
// ============================================================================
|
||||
|
||||
class Assembler;
|
||||
class CodeEmitter;
|
||||
class CodeHolder;
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::AlignMode]
|
||||
// ============================================================================
|
||||
|
||||
//! Align mode.
|
||||
ASMJIT_ENUM(AlignMode) {
|
||||
kAlignCode = 0, //!< Align executable code.
|
||||
kAlignData = 1, //!< Align non-executable code.
|
||||
kAlignZero = 2, //!< Align by a sequence of zeros.
|
||||
kAlignCount //!< Count of alignment modes.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ErrorHandler]
|
||||
// ============================================================================
|
||||
|
||||
//! Error handler can be used to override the default behavior of error handling
|
||||
//! available to all classes that inherit \ref CodeEmitter. See \ref handleError().
|
||||
class ASMJIT_VIRTAPI ErrorHandler {
|
||||
public:
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `ErrorHandler` instance.
|
||||
ASMJIT_API ErrorHandler() noexcept;
|
||||
//! Destroy the `ErrorHandler` instance.
|
||||
ASMJIT_API virtual ~ErrorHandler() noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Handle Error]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Error handler (abstract).
|
||||
//!
|
||||
//! Error handler is called after an error happened and before it's propagated
|
||||
//! to the caller. There are multiple ways how the error handler can be used:
|
||||
//!
|
||||
//! 1. Returning `true` or `false` from `handleError()`. If `true` is returned
|
||||
//! it means that the error was reported and AsmJit can continue execution.
|
||||
//! The reported error still be propagated to the caller, but won't put the
|
||||
//! CodeEmitter into an error state (it won't set last-error). However,
|
||||
//! returning `false` means that the error cannot be handled - in such case
|
||||
//! it stores the error, which can be then retrieved by using `getLastError()`.
|
||||
//! Returning `false` is the default behavior when no error handler is present.
|
||||
//! To put the assembler into a non-error state again a `resetLastError()` must
|
||||
//! be called.
|
||||
//!
|
||||
//! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely
|
||||
//! exception-safe, but you can throw exception from your error handler if
|
||||
//! this way is the preferred way of handling errors in your project. Throwing
|
||||
//! an exception acts virtually as returning `true` as AsmJit won't be able
|
||||
//! to store the error because the exception changes execution path.
|
||||
//!
|
||||
//! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts
|
||||
//! `CodeEmitter` to a consistent state before calling the `handleError()`
|
||||
//! so `longjmp()` can be used without any issues to cancel the code
|
||||
//! generation if an error occurred. There is no difference between
|
||||
//! exceptions and longjmp() from AsmJit's perspective.
|
||||
virtual bool handleError(Error err, const char* message, CodeEmitter* origin) = 0;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeInfo]
|
||||
// ============================================================================
|
||||
|
||||
//! Basic information about a code (or target). It describes its architecture,
|
||||
//! code generation mode (or optimization level), and base address.
|
||||
class CodeInfo {
|
||||
public:
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE CodeInfo() noexcept
|
||||
: _archInfo(),
|
||||
_stackAlignment(0),
|
||||
_cdeclCallConv(CallConv::kIdNone),
|
||||
_stdCallConv(CallConv::kIdNone),
|
||||
_fastCallConv(CallConv::kIdNone),
|
||||
_baseAddress(Globals::kNoBaseAddress) {}
|
||||
ASMJIT_INLINE CodeInfo(const CodeInfo& other) noexcept { init(other); }
|
||||
|
||||
explicit ASMJIT_INLINE CodeInfo(uint32_t archType, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept
|
||||
: _archInfo(archType, archMode),
|
||||
_packedMiscInfo(0),
|
||||
_baseAddress(baseAddress) {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Init / Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE bool isInitialized() const noexcept {
|
||||
return _archInfo._type != ArchInfo::kTypeNone;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE void init(const CodeInfo& other) noexcept {
|
||||
_archInfo = other._archInfo;
|
||||
_packedMiscInfo = other._packedMiscInfo;
|
||||
_baseAddress = other._baseAddress;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE void init(uint32_t archType, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept {
|
||||
_archInfo.init(archType, archMode);
|
||||
_packedMiscInfo = 0;
|
||||
_baseAddress = baseAddress;
|
||||
}
|
||||
|
||||
ASMJIT_INLINE void reset() noexcept {
|
||||
_archInfo.reset();
|
||||
_stackAlignment = 0;
|
||||
_cdeclCallConv = CallConv::kIdNone;
|
||||
_stdCallConv = CallConv::kIdNone;
|
||||
_fastCallConv = CallConv::kIdNone;
|
||||
_baseAddress = Globals::kNoBaseAddress;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Architecture Information]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get architecture information, see \ref ArchInfo.
|
||||
ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _archInfo; }
|
||||
|
||||
//! Get architecture type, see \ref ArchInfo::Type.
|
||||
ASMJIT_INLINE uint32_t getArchType() const noexcept { return _archInfo.getType(); }
|
||||
//! Get architecture sub-type, see \ref ArchInfo::SubType.
|
||||
ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return _archInfo.getSubType(); }
|
||||
//! Get a size of a GP register of the architecture the code is using.
|
||||
ASMJIT_INLINE uint32_t getGpSize() const noexcept { return _archInfo.getGpSize(); }
|
||||
//! Get number of GP registers available of the architecture the code is using.
|
||||
ASMJIT_INLINE uint32_t getGpCount() const noexcept { return _archInfo.getGpCount(); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [High-Level Information]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get a natural stack alignment that must be honored (or 0 if not known).
|
||||
ASMJIT_INLINE uint32_t getStackAlignment() const noexcept { return _stackAlignment; }
|
||||
//! Set a natural stack alignment that must be honored.
|
||||
ASMJIT_INLINE void setStackAlignment(uint8_t sa) noexcept { _stackAlignment = static_cast<uint8_t>(sa); }
|
||||
|
||||
ASMJIT_INLINE uint32_t getCdeclCallConv() const noexcept { return _cdeclCallConv; }
|
||||
ASMJIT_INLINE void setCdeclCallConv(uint32_t cc) noexcept { _cdeclCallConv = static_cast<uint8_t>(cc); }
|
||||
|
||||
ASMJIT_INLINE uint32_t getStdCallConv() const noexcept { return _stdCallConv; }
|
||||
ASMJIT_INLINE void setStdCallConv(uint32_t cc) noexcept { _stdCallConv = static_cast<uint8_t>(cc); }
|
||||
|
||||
ASMJIT_INLINE uint32_t getFastCallConv() const noexcept { return _fastCallConv; }
|
||||
ASMJIT_INLINE void setFastCallConv(uint32_t cc) noexcept { _fastCallConv = static_cast<uint8_t>(cc); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Addressing Information]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; }
|
||||
ASMJIT_INLINE uint64_t getBaseAddress() const noexcept { return _baseAddress; }
|
||||
ASMJIT_INLINE void setBaseAddress(uint64_t p) noexcept { _baseAddress = p; }
|
||||
ASMJIT_INLINE void resetBaseAddress() noexcept { _baseAddress = Globals::kNoBaseAddress; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Operator Overload]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE CodeInfo& operator=(const CodeInfo& other) noexcept { init(other); return *this; }
|
||||
ASMJIT_INLINE bool operator==(const CodeInfo& other) const noexcept { return ::memcmp(this, &other, sizeof(*this)) == 0; }
|
||||
ASMJIT_INLINE bool operator!=(const CodeInfo& other) const noexcept { return ::memcmp(this, &other, sizeof(*this)) != 0; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ArchInfo _archInfo; //!< Architecture information.
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint8_t _stackAlignment; //!< Natural stack alignment (ARCH+OS).
|
||||
uint8_t _cdeclCallConv; //!< Default CDECL calling convention.
|
||||
uint8_t _stdCallConv; //!< Default STDCALL calling convention.
|
||||
uint8_t _fastCallConv; //!< Default FASTCALL calling convention.
|
||||
};
|
||||
uint32_t _packedMiscInfo; //!< \internal
|
||||
};
|
||||
|
||||
uint64_t _baseAddress; //!< Base address.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeBuffer]
|
||||
// ============================================================================
|
||||
|
||||
//! Code or data buffer.
|
||||
struct CodeBuffer {
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE bool hasData() const noexcept { return _data != nullptr; }
|
||||
ASMJIT_INLINE uint8_t* getData() noexcept { return _data; }
|
||||
ASMJIT_INLINE const uint8_t* getData() const noexcept { return _data; }
|
||||
|
||||
ASMJIT_INLINE size_t getLength() const noexcept { return _length; }
|
||||
ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; }
|
||||
|
||||
ASMJIT_INLINE bool isExternal() const noexcept { return _isExternal; }
|
||||
ASMJIT_INLINE bool isFixedSize() const noexcept { return _isFixedSize; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
uint8_t* _data; //!< The content of the buffer (data).
|
||||
size_t _length; //!< Number of bytes of `data` used.
|
||||
size_t _capacity; //!< Buffer capacity (in bytes).
|
||||
bool _isExternal; //!< True if this is external buffer.
|
||||
bool _isFixedSize; //!< True if this buffer cannot grow.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::SectionEntry]
|
||||
// ============================================================================
|
||||
|
||||
//! Section entry.
|
||||
class SectionEntry {
|
||||
public:
|
||||
ASMJIT_ENUM(Id) {
|
||||
kInvalidId = 0xFFFFFFFFU //!< Invalid section id.
|
||||
};
|
||||
|
||||
//! Section flags.
|
||||
ASMJIT_ENUM(Flags) {
|
||||
kFlagExec = 0x00000001U, //!< Executable (.text sections).
|
||||
kFlagConst = 0x00000002U, //!< Read-only (.text and .data sections).
|
||||
kFlagZero = 0x00000004U, //!< Zero initialized by the loader (BSS).
|
||||
kFlagInfo = 0x00000008U, //!< Info / comment flag.
|
||||
kFlagImplicit = 0x80000000U //!< Section created implicitly (can be deleted by the Runtime).
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
|
||||
ASMJIT_INLINE const char* getName() const noexcept { return _name; }
|
||||
|
||||
ASMJIT_INLINE void _setDefaultName(
|
||||
char c0 = 0, char c1 = 0, char c2 = 0, char c3 = 0,
|
||||
char c4 = 0, char c5 = 0, char c6 = 0, char c7 = 0) noexcept {
|
||||
_nameAsU32[0] = Utils::pack32_4x8(c0, c1, c2, c3);
|
||||
_nameAsU32[1] = Utils::pack32_4x8(c4, c5, c6, c7);
|
||||
}
|
||||
|
||||
ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; }
|
||||
ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; }
|
||||
ASMJIT_INLINE void addFlags(uint32_t flags) noexcept { _flags |= flags; }
|
||||
ASMJIT_INLINE void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; }
|
||||
|
||||
ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; }
|
||||
ASMJIT_INLINE void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; }
|
||||
|
||||
ASMJIT_INLINE size_t getPhysicalSize() const noexcept { return _buffer.getLength(); }
|
||||
|
||||
ASMJIT_INLINE size_t getVirtualSize() const noexcept { return _virtualSize; }
|
||||
ASMJIT_INLINE void setVirtualSize(uint32_t size) noexcept { _virtualSize = size; }
|
||||
|
||||
ASMJIT_INLINE CodeBuffer& getBuffer() noexcept { return _buffer; }
|
||||
ASMJIT_INLINE const CodeBuffer& getBuffer() const noexcept { return _buffer; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
uint32_t _id; //!< Section id.
|
||||
uint32_t _flags; //!< Section flags.
|
||||
uint32_t _alignment; //!< Section alignment requirements (0 if no requirements).
|
||||
uint32_t _virtualSize; //!< Virtual size of the section (zero initialized mostly).
|
||||
union {
|
||||
char _name[36]; //!< Section name (max 35 characters, PE allows max 8).
|
||||
uint32_t _nameAsU32[36 / 4]; //!< Section name as `uint32_t[]` (only optimization).
|
||||
};
|
||||
CodeBuffer _buffer; //!< Code or data buffer.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::LabelLink]
|
||||
// ============================================================================
|
||||
|
||||
//! Data structure used to link labels.
|
||||
struct LabelLink {
|
||||
LabelLink* prev; //!< Previous link (single-linked list).
|
||||
uint32_t sectionId; //!< Section id.
|
||||
uint32_t relocId; //!< Relocation id or RelocEntry::kInvalidId.
|
||||
size_t offset; //!< Label offset relative to the start of the section.
|
||||
intptr_t rel; //!< Inlined rel8/rel32.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::LabelEntry]
|
||||
// ============================================================================
|
||||
|
||||
//! Label entry.
|
||||
//!
|
||||
//! Contains the following properties:
|
||||
//! * Label id - This is the only thing that is set to the `Label` operand.
|
||||
//! * Label name - Optional, used mostly to create executables and libraries.
|
||||
//! * Label type - Type of the label, default `Label::kTypeAnonymous`.
|
||||
//! * Label parent id - Derived from many assemblers that allow to define a
|
||||
//! local label that falls under a global label. This allows to define
|
||||
//! many labels of the same name that have different parent (global) label.
|
||||
//! * Offset - offset of the label bound by `Assembler`.
|
||||
//! * Links - single-linked list that contains locations of code that has
|
||||
//! to be patched when the label gets bound. Every use of unbound label
|
||||
//! adds one link to `_links` list.
|
||||
//! * HVal - Hash value of label's name and optionally parentId.
|
||||
//! * HashNext - Hash-table implementation detail.
|
||||
class LabelEntry : public ZoneHashNode {
|
||||
public:
|
||||
// NOTE: Label id is stored in `_customData`, which is provided by ZoneHashNode
|
||||
// to fill a padding that a C++ compiler targeting 64-bit CPU will add to align
|
||||
// the structure to 64-bits.
|
||||
|
||||
//! Get label id.
|
||||
ASMJIT_INLINE uint32_t getId() const noexcept { return _customData; }
|
||||
//! Set label id (internal, used only by \ref CodeHolder).
|
||||
ASMJIT_INLINE void _setId(uint32_t id) noexcept { _customData = id; }
|
||||
|
||||
//! Get label type, see \ref Label::Type.
|
||||
ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
|
||||
//! Get label flags, returns 0 at the moment.
|
||||
ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; }
|
||||
|
||||
ASMJIT_INLINE bool hasParent() const noexcept { return _parentId != 0; }
|
||||
//! Get label's parent id.
|
||||
ASMJIT_INLINE uint32_t getParentId() const noexcept { return _parentId; }
|
||||
|
||||
//! Get label's section id where it's bound to (or `SectionEntry::kInvalidId` if it's not bound yet).
|
||||
ASMJIT_INLINE uint32_t getSectionId() const noexcept { return _sectionId; }
|
||||
|
||||
//! Get if the label has name.
|
||||
ASMJIT_INLINE bool hasName() const noexcept { return !_name.isEmpty(); }
|
||||
|
||||
//! Get the label's name.
|
||||
//!
|
||||
//! NOTE: Local labels will return their local name without their parent
|
||||
//! part, for example ".L1".
|
||||
ASMJIT_INLINE const char* getName() const noexcept { return _name.getData(); }
|
||||
|
||||
//! Get length of label's name.
|
||||
//!
|
||||
//! NOTE: Label name is always null terminated, so you can use `strlen()` to
|
||||
//! get it, however, it's also cached in `LabelEntry`, so if you want to know
|
||||
//! the length the easiest way is to use `LabelEntry::getNameLength()`.
|
||||
ASMJIT_INLINE size_t getNameLength() const noexcept { return _name.getLength(); }
|
||||
|
||||
//! Get if the label is bound.
|
||||
ASMJIT_INLINE bool isBound() const noexcept { return _sectionId != SectionEntry::kInvalidId; }
|
||||
//! Get the label offset (only useful if the label is bound).
|
||||
ASMJIT_INLINE intptr_t getOffset() const noexcept { return _offset; }
|
||||
|
||||
//! Get the hash-value of label's name and its parent label (if any).
|
||||
//!
|
||||
//! Label hash is calculated as `HASH(Name) ^ ParentId`. The hash function
|
||||
//! is implemented in `Utils::hashString()` and `Utils::hashRound()`.
|
||||
ASMJIT_INLINE uint32_t getHVal() const noexcept { return _hVal; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Let's round the size of `LabelEntry` to 64 bytes (as ZoneHeap has 32
|
||||
// bytes granularity anyway). This gives `_name` the remaining space, which
|
||||
// is roughly 16 bytes on 64-bit and 28 bytes on 32-bit architectures.
|
||||
enum { kNameBytes = 64 - (sizeof(ZoneHashNode) + 16 + sizeof(intptr_t) + sizeof(LabelLink*)) };
|
||||
|
||||
uint8_t _type; //!< Label type, see Label::Type.
|
||||
uint8_t _flags; //!< Must be zero.
|
||||
uint16_t _reserved16; //!< Reserved.
|
||||
uint32_t _parentId; //!< Label parent id or zero.
|
||||
uint32_t _sectionId; //!< Section id or `SectionEntry::kInvalidId`.
|
||||
uint32_t _reserved32; //!< Reserved.
|
||||
intptr_t _offset; //!< Label offset.
|
||||
LabelLink* _links; //!< Label links.
|
||||
SmallString<kNameBytes> _name; //!< Label name.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::RelocEntry]
|
||||
// ============================================================================
|
||||
|
||||
//! Relocation entry.
|
||||
struct RelocEntry {
|
||||
ASMJIT_ENUM(Id) {
|
||||
kInvalidId = 0xFFFFFFFFU //!< Invalid relocation id.
|
||||
};
|
||||
|
||||
//! Relocation type.
|
||||
ASMJIT_ENUM(Type) {
|
||||
kTypeNone = 0, //!< Deleted entry (no relocation).
|
||||
kTypeAbsToAbs = 1, //!< Relocate absolute to absolute.
|
||||
kTypeRelToAbs = 2, //!< Relocate relative to absolute.
|
||||
kTypeAbsToRel = 3, //!< Relocate absolute to relative.
|
||||
kTypeTrampoline = 4 //!< Relocate absolute to relative or use trampoline.
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
|
||||
|
||||
ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
|
||||
ASMJIT_INLINE uint32_t getSize() const noexcept { return _size; }
|
||||
|
||||
ASMJIT_INLINE uint32_t getSourceSectionId() const noexcept { return _sourceSectionId; }
|
||||
ASMJIT_INLINE uint32_t getTargetSectionId() const noexcept { return _targetSectionId; }
|
||||
|
||||
ASMJIT_INLINE uint64_t getSourceOffset() const noexcept { return _sourceOffset; }
|
||||
ASMJIT_INLINE uint64_t getData() const noexcept { return _data; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
uint32_t _id; //!< Relocation id.
|
||||
uint8_t _type; //!< Type of the relocation.
|
||||
uint8_t _size; //!< Size of the relocation (1, 2, 4 or 8 bytes).
|
||||
uint8_t _reserved[2]; //!< Reserved.
|
||||
uint32_t _sourceSectionId; //!< Source section id.
|
||||
uint32_t _targetSectionId; //!< Destination section id.
|
||||
uint64_t _sourceOffset; //!< Source offset (relative to start of the section).
|
||||
uint64_t _data; //!< Relocation data (target offset, target address, etc).
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CodeHolder]
|
||||
// ============================================================================
|
||||
|
||||
//! Contains basic information about the target architecture plus its settings,
|
||||
//! and holds code & data (including sections, labels, and relocation information).
|
||||
//! CodeHolder can store both binary and intermediate representation of assembly,
|
||||
//! which can be generated by \ref Assembler and/or \ref CodeBuilder.
|
||||
//!
|
||||
//! NOTE: CodeHolder has ability to attach an \ref ErrorHandler, however, this
|
||||
//! error handler is not triggered by CodeHolder itself, it's only used by the
|
||||
//! attached code generators.
|
||||
class CodeHolder {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(CodeHolder)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create an uninitialized CodeHolder (you must init() it before it can be used).
|
||||
ASMJIT_API CodeHolder() noexcept;
|
||||
//! Destroy the CodeHolder.
|
||||
ASMJIT_API ~CodeHolder() noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Init / Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE bool isInitialized() const noexcept { return _codeInfo.isInitialized(); }
|
||||
|
||||
//! Initialize to CodeHolder to hold code described by `codeInfo`.
|
||||
ASMJIT_API Error init(const CodeInfo& info) noexcept;
|
||||
//! Detach all code-generators attached and reset the \ref CodeHolder.
|
||||
ASMJIT_API void reset(bool releaseMemory = false) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Attach / Detach]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Attach a \ref CodeEmitter to this \ref CodeHolder.
|
||||
ASMJIT_API Error attach(CodeEmitter* emitter) noexcept;
|
||||
//! Detach a \ref CodeEmitter from this \ref CodeHolder.
|
||||
ASMJIT_API Error detach(CodeEmitter* emitter) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Sync]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Synchronize all states of all `CodeEmitter`s associated with the CodeHolder.
|
||||
//! This is required as some code generators don't sync every time they do
|
||||
//! something - for example \ref Assembler generally syncs when it needs to
|
||||
//! reallocate the \ref CodeBuffer, but not each time it encodes instruction
|
||||
//! or directive.
|
||||
ASMJIT_API void sync() noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Code-Information]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get code/target information, see \ref CodeInfo.
|
||||
ASMJIT_INLINE const CodeInfo& getCodeInfo() const noexcept { return _codeInfo; }
|
||||
//! Get architecture information, see \ref ArchInfo.
|
||||
ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _codeInfo.getArchInfo(); }
|
||||
|
||||
//! Get the target's architecture type.
|
||||
ASMJIT_INLINE uint32_t getArchType() const noexcept { return getArchInfo().getType(); }
|
||||
//! Get the target's architecture sub-type.
|
||||
ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return getArchInfo().getSubType(); }
|
||||
|
||||
//! Get if a static base-address is set.
|
||||
ASMJIT_INLINE bool hasBaseAddress() const noexcept { return _codeInfo.hasBaseAddress(); }
|
||||
//! Get a static base-address (uint64_t).
|
||||
ASMJIT_INLINE uint64_t getBaseAddress() const noexcept { return _codeInfo.getBaseAddress(); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Global Information]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get global hints, internally propagated to all `CodeEmitter`s attached.
|
||||
ASMJIT_INLINE uint32_t getGlobalHints() const noexcept { return _globalHints; }
|
||||
//! Get global options, internally propagated to all `CodeEmitter`s attached.
|
||||
ASMJIT_INLINE uint32_t getGlobalOptions() const noexcept { return _globalOptions; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Result Information]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get the size code & data of all sections.
|
||||
ASMJIT_API size_t getCodeSize() const noexcept;
|
||||
|
||||
//! Get size of all possible trampolines.
|
||||
//!
|
||||
//! Trampolines are needed to successfully generate relative jumps to absolute
|
||||
//! addresses. This value is only non-zero if jmp of call instructions were
|
||||
//! used with immediate operand (this means jumping or calling an absolute
|
||||
//! address directly).
|
||||
ASMJIT_INLINE size_t getTrampolinesSize() const noexcept { return _trampolinesSize; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Logging & Error Handling]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
//! Get if a logger attached.
|
||||
ASMJIT_INLINE bool hasLogger() const noexcept { return _logger != nullptr; }
|
||||
//! Get the attached logger.
|
||||
ASMJIT_INLINE Logger* getLogger() const noexcept { return _logger; }
|
||||
//! Attach a `logger` to CodeHolder and propagate it to all attached `CodeEmitter`s.
|
||||
ASMJIT_API void setLogger(Logger* logger) noexcept;
|
||||
//! Reset the logger (does nothing if not attached).
|
||||
ASMJIT_INLINE void resetLogger() noexcept { setLogger(nullptr); }
|
||||
#endif // !ASMJIT_DISABLE_LOGGING
|
||||
|
||||
//! Get if error-handler is attached.
|
||||
ASMJIT_INLINE bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; }
|
||||
//! Get the error-handler.
|
||||
ASMJIT_INLINE ErrorHandler* getErrorHandler() const noexcept { return _errorHandler; }
|
||||
//! Set the error handler, will affect all attached `CodeEmitter`s.
|
||||
ASMJIT_API Error setErrorHandler(ErrorHandler* handler) noexcept;
|
||||
//! Reset the error handler (does nothing if not attached).
|
||||
ASMJIT_INLINE void resetErrorHandler() noexcept { setErrorHandler(nullptr); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Sections]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get array of `SectionEntry*` records.
|
||||
ASMJIT_INLINE const ZoneVector<SectionEntry*>& getSections() const noexcept { return _sections; }
|
||||
|
||||
//! Get a section entry of the given index.
|
||||
ASMJIT_INLINE SectionEntry* getSectionEntry(size_t index) const noexcept { return _sections[index]; }
|
||||
|
||||
ASMJIT_API Error growBuffer(CodeBuffer* cb, size_t n) noexcept;
|
||||
ASMJIT_API Error reserveBuffer(CodeBuffer* cb, size_t n) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Labels & Symbols]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new anonymous label and return its id in `idOut`.
|
||||
//!
|
||||
//! Returns `Error`, does not report error to \ref ErrorHandler.
|
||||
ASMJIT_API Error newLabelId(uint32_t& idOut) noexcept;
|
||||
|
||||
//! Create a new named label label-type `type`.
|
||||
//!
|
||||
//! Returns `Error`, does not report error to \ref ErrorHandler.
|
||||
ASMJIT_API Error newNamedLabelId(uint32_t& idOut, const char* name, size_t nameLength, uint32_t type, uint32_t parentId) noexcept;
|
||||
|
||||
//! Get a label id by name.
|
||||
ASMJIT_API uint32_t getLabelIdByName(const char* name, size_t nameLength = Globals::kInvalidIndex, uint32_t parentId = 0) noexcept;
|
||||
|
||||
//! Create a new label-link used to store information about yet unbound labels.
|
||||
//!
|
||||
//! Returns `null` if the allocation failed.
|
||||
ASMJIT_API LabelLink* newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel) noexcept;
|
||||
|
||||
//! Get array of `LabelEntry*` records.
|
||||
ASMJIT_INLINE const ZoneVector<LabelEntry*>& getLabelEntries() const noexcept { return _labels; }
|
||||
|
||||
//! Get number of labels created.
|
||||
ASMJIT_INLINE size_t getLabelsCount() const noexcept { return _labels.getLength(); }
|
||||
|
||||
//! Get number of label references, which are unresolved at the moment.
|
||||
ASMJIT_INLINE size_t getUnresolvedLabelsCount() const noexcept { return _unresolvedLabelsCount; }
|
||||
|
||||
//! Get if the `label` is valid (i.e. created by `newLabelId()`).
|
||||
ASMJIT_INLINE bool isLabelValid(const Label& label) const noexcept {
|
||||
return isLabelValid(label.getId());
|
||||
}
|
||||
//! Get if the label having `id` is valid (i.e. created by `newLabelId()`).
|
||||
ASMJIT_INLINE bool isLabelValid(uint32_t labelId) const noexcept {
|
||||
size_t index = Operand::unpackId(labelId);
|
||||
return index < _labels.getLength();
|
||||
}
|
||||
|
||||
//! Get if the `label` is already bound.
|
||||
//!
|
||||
//! Returns `false` if the `label` is not valid.
|
||||
ASMJIT_INLINE bool isLabelBound(const Label& label) const noexcept {
|
||||
return isLabelBound(label.getId());
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE bool isLabelBound(uint32_t id) const noexcept {
|
||||
size_t index = Operand::unpackId(id);
|
||||
return index < _labels.getLength() && _labels[index]->isBound();
|
||||
}
|
||||
|
||||
//! Get a `label` offset or -1 if the label is not yet bound.
|
||||
ASMJIT_INLINE intptr_t getLabelOffset(const Label& label) const noexcept {
|
||||
return getLabelOffset(label.getId());
|
||||
}
|
||||
//! \overload
|
||||
ASMJIT_INLINE intptr_t getLabelOffset(uint32_t id) const noexcept {
|
||||
ASMJIT_ASSERT(isLabelValid(id));
|
||||
return _labels[Operand::unpackId(id)]->getOffset();
|
||||
}
|
||||
|
||||
//! Get information about the given `label`.
|
||||
ASMJIT_INLINE LabelEntry* getLabelEntry(const Label& label) const noexcept {
|
||||
return getLabelEntry(label.getId());
|
||||
}
|
||||
//! Get information about a label having the given `id`.
|
||||
ASMJIT_INLINE LabelEntry* getLabelEntry(uint32_t id) const noexcept {
|
||||
size_t index = static_cast<size_t>(Operand::unpackId(id));
|
||||
return index < _labels.getLength() ? _labels[index] : static_cast<LabelEntry*>(nullptr);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Relocations]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new relocation entry of type `type` and size `size`.
|
||||
//!
|
||||
//! Additional fields can be set after the relocation entry was created.
|
||||
ASMJIT_API Error newRelocEntry(RelocEntry** dst, uint32_t type, uint32_t size) noexcept;
|
||||
|
||||
//! Get if the code contains relocations.
|
||||
ASMJIT_INLINE bool hasRelocations() const noexcept { return !_relocations.isEmpty(); }
|
||||
//! Get array of `RelocEntry*` records.
|
||||
ASMJIT_INLINE const ZoneVector<RelocEntry*>& getRelocEntries() const noexcept { return _relocations; }
|
||||
|
||||
ASMJIT_INLINE RelocEntry* getRelocEntry(uint32_t id) const noexcept { return _relocations[id]; }
|
||||
|
||||
//! Relocate the code to `baseAddress` and copy it to `dst`.
|
||||
//!
|
||||
//! \param dst Contains the location where the relocated code should be
|
||||
//! copied. The pointer can be address returned by virtual memory allocator
|
||||
//! or any other address that has sufficient space.
|
||||
//!
|
||||
//! \param baseAddress Base address used for relocation. `JitRuntime` always
|
||||
//! sets the `baseAddress` to be the same as `dst`.
|
||||
//!
|
||||
//! \return The number bytes actually used. If the code emitter reserved
|
||||
//! space for possible trampolines, but didn't use it, the number of bytes
|
||||
//! used can actually be less than the expected worst case. Virtual memory
|
||||
//! allocator can shrink the memory it allocated initially.
|
||||
//!
|
||||
//! A given buffer will be overwritten, to get the number of bytes required,
|
||||
//! use `getCodeSize()`.
|
||||
ASMJIT_API size_t relocate(void* dst, uint64_t baseAddress = Globals::kNoBaseAddress) const noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
CodeInfo _codeInfo; //!< Basic information about the code (architecture and other info).
|
||||
|
||||
uint32_t _globalHints; //!< Global hints, propagated to all `CodeEmitter`s.
|
||||
uint32_t _globalOptions; //!< Global options, propagated to all `CodeEmitter`s.
|
||||
|
||||
CodeEmitter* _emitters; //!< Linked-list of all attached `CodeEmitter`s.
|
||||
Assembler* _cgAsm; //!< Attached \ref Assembler (only one at a time).
|
||||
|
||||
Logger* _logger; //!< Attached \ref Logger, used by all consumers.
|
||||
ErrorHandler* _errorHandler; //!< Attached \ref ErrorHandler.
|
||||
|
||||
uint32_t _unresolvedLabelsCount; //!< Count of label references which were not resolved.
|
||||
uint32_t _trampolinesSize; //!< Size of all possible trampolines.
|
||||
|
||||
Zone _baseZone; //!< Base zone (used to allocate core structures).
|
||||
Zone _dataZone; //!< Data zone (used to allocate extra data like label names).
|
||||
ZoneHeap _baseHeap; //!< Zone allocator, used to manage internal containers.
|
||||
|
||||
ZoneVector<SectionEntry*> _sections; //!< Section entries.
|
||||
ZoneVector<LabelEntry*> _labels; //!< Label entries (each label is stored here).
|
||||
ZoneVector<RelocEntry*> _relocations; //!< Relocation entries.
|
||||
ZoneHash<LabelEntry> _namedLabels; //!< Label name -> LabelEntry (only named labels).
|
||||
};
|
||||
|
||||
//! \}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_CODEHOLDER_H
|
|
@ -1,511 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/constpool.h"
|
||||
#include "../base/utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// Binary tree code is based on Julienne Walker's "Andersson Binary Trees"
|
||||
// article and implementation. However, only three operations are implemented -
|
||||
// get, insert and traverse.
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ConstPool::Tree - Ops]
|
||||
// ============================================================================
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! Remove left horizontal links.
|
||||
static ASMJIT_INLINE ConstPool::Node* ConstPoolTree_skewNode(ConstPool::Node* node) noexcept {
|
||||
ConstPool::Node* link = node->_link[0];
|
||||
uint32_t level = node->_level;
|
||||
|
||||
if (level != 0 && link && link->_level == level) {
|
||||
node->_link[0] = link->_link[1];
|
||||
link->_link[1] = node;
|
||||
|
||||
node = link;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! Remove consecutive horizontal links.
|
||||
static ASMJIT_INLINE ConstPool::Node* ConstPoolTree_splitNode(ConstPool::Node* node) noexcept {
|
||||
ConstPool::Node* link = node->_link[1];
|
||||
uint32_t level = node->_level;
|
||||
|
||||
if (level != 0 && link && link->_link[1] && link->_link[1]->_level == level) {
|
||||
node->_link[1] = link->_link[0];
|
||||
link->_link[0] = node;
|
||||
|
||||
node = link;
|
||||
node->_level++;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
ConstPool::Node* ConstPool::Tree::get(const void* data) noexcept {
|
||||
ConstPool::Node* node = _root;
|
||||
size_t dataSize = _dataSize;
|
||||
|
||||
while (node) {
|
||||
int c = ::memcmp(node->getData(), data, dataSize);
|
||||
if (c == 0)
|
||||
return node;
|
||||
node = node->_link[c < 0];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ConstPool::Tree::put(ConstPool::Node* newNode) noexcept {
|
||||
size_t dataSize = _dataSize;
|
||||
_length++;
|
||||
|
||||
if (!_root) {
|
||||
_root = newNode;
|
||||
return;
|
||||
}
|
||||
|
||||
ConstPool::Node* node = _root;
|
||||
ConstPool::Node* stack[kHeightLimit];
|
||||
|
||||
unsigned int top = 0;
|
||||
unsigned int dir;
|
||||
|
||||
// Find a spot and save the stack.
|
||||
for (;;) {
|
||||
stack[top++] = node;
|
||||
dir = ::memcmp(node->getData(), newNode->getData(), dataSize) < 0;
|
||||
|
||||
ConstPool::Node* link = node->_link[dir];
|
||||
if (!link) break;
|
||||
|
||||
node = link;
|
||||
}
|
||||
|
||||
// Link and rebalance.
|
||||
node->_link[dir] = newNode;
|
||||
|
||||
while (top > 0) {
|
||||
// Which child?
|
||||
node = stack[--top];
|
||||
|
||||
if (top != 0) {
|
||||
dir = stack[top - 1]->_link[1] == node;
|
||||
}
|
||||
|
||||
node = ConstPoolTree_skewNode(node);
|
||||
node = ConstPoolTree_splitNode(node);
|
||||
|
||||
// Fix the parent.
|
||||
if (top != 0)
|
||||
stack[top - 1]->_link[dir] = node;
|
||||
else
|
||||
_root = node;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ConstPool - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
ConstPool::ConstPool(Zone* zone) noexcept { reset(zone); }
|
||||
ConstPool::~ConstPool() noexcept {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ConstPool - Reset]
|
||||
// ============================================================================
|
||||
|
||||
void ConstPool::reset(Zone* zone) noexcept {
|
||||
_zone = zone;
|
||||
|
||||
size_t dataSize = 1;
|
||||
for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) {
|
||||
_tree[i].reset();
|
||||
_tree[i].setDataSize(dataSize);
|
||||
_gaps[i] = nullptr;
|
||||
dataSize <<= 1;
|
||||
}
|
||||
|
||||
_gapPool = nullptr;
|
||||
_size = 0;
|
||||
_alignment = 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ConstPool - Ops]
|
||||
// ============================================================================
|
||||
|
||||
static ASMJIT_INLINE ConstPool::Gap* ConstPool_allocGap(ConstPool* self) noexcept {
|
||||
ConstPool::Gap* gap = self->_gapPool;
|
||||
if (!gap) return self->_zone->allocT<ConstPool::Gap>();
|
||||
|
||||
self->_gapPool = gap->_next;
|
||||
return gap;
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE void ConstPool_freeGap(ConstPool* self, ConstPool::Gap* gap) noexcept {
|
||||
gap->_next = self->_gapPool;
|
||||
self->_gapPool = gap;
|
||||
}
|
||||
|
||||
static void ConstPool_addGap(ConstPool* self, size_t offset, size_t length) noexcept {
|
||||
ASMJIT_ASSERT(length > 0);
|
||||
|
||||
while (length > 0) {
|
||||
size_t gapIndex;
|
||||
size_t gapLength;
|
||||
|
||||
gapIndex = ConstPool::kIndex16;
|
||||
if (length >= 16 && Utils::isAligned<size_t>(offset, 16)) {
|
||||
gapLength = 16;
|
||||
}
|
||||
else if (length >= 8 && Utils::isAligned<size_t>(offset, 8)) {
|
||||
gapIndex = ConstPool::kIndex8;
|
||||
gapLength = 8;
|
||||
}
|
||||
else if (length >= 4 && Utils::isAligned<size_t>(offset, 4)) {
|
||||
gapIndex = ConstPool::kIndex4;
|
||||
gapLength = 4;
|
||||
}
|
||||
else if (length >= 2 && Utils::isAligned<size_t>(offset, 2)) {
|
||||
gapIndex = ConstPool::kIndex2;
|
||||
gapLength = 2;
|
||||
}
|
||||
else {
|
||||
gapIndex = ConstPool::kIndex1;
|
||||
gapLength = 1;
|
||||
}
|
||||
|
||||
// We don't have to check for errors here, if this failed nothing really
|
||||
// happened (just the gap won't be visible) and it will fail again at
|
||||
// place where checking will cause kErrorNoHeapMemory.
|
||||
ConstPool::Gap* gap = ConstPool_allocGap(self);
|
||||
if (!gap) return;
|
||||
|
||||
gap->_next = self->_gaps[gapIndex];
|
||||
self->_gaps[gapIndex] = gap;
|
||||
|
||||
gap->_offset = offset;
|
||||
gap->_length = gapLength;
|
||||
|
||||
offset += gapLength;
|
||||
length -= gapLength;
|
||||
}
|
||||
}
|
||||
|
||||
Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept {
|
||||
size_t treeIndex;
|
||||
|
||||
if (size == 32)
|
||||
treeIndex = kIndex32;
|
||||
else if (size == 16)
|
||||
treeIndex = kIndex16;
|
||||
else if (size == 8)
|
||||
treeIndex = kIndex8;
|
||||
else if (size == 4)
|
||||
treeIndex = kIndex4;
|
||||
else if (size == 2)
|
||||
treeIndex = kIndex2;
|
||||
else if (size == 1)
|
||||
treeIndex = kIndex1;
|
||||
else
|
||||
return DebugUtils::errored(kErrorInvalidArgument);
|
||||
|
||||
ConstPool::Node* node = _tree[treeIndex].get(data);
|
||||
if (node) {
|
||||
dstOffset = node->_offset;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// Before incrementing the current offset try if there is a gap that can
|
||||
// be used for the requested data.
|
||||
size_t offset = ~static_cast<size_t>(0);
|
||||
size_t gapIndex = treeIndex;
|
||||
|
||||
while (gapIndex != kIndexCount - 1) {
|
||||
ConstPool::Gap* gap = _gaps[treeIndex];
|
||||
|
||||
// Check if there is a gap.
|
||||
if (gap) {
|
||||
size_t gapOffset = gap->_offset;
|
||||
size_t gapLength = gap->_length;
|
||||
|
||||
// Destroy the gap for now.
|
||||
_gaps[treeIndex] = gap->_next;
|
||||
ConstPool_freeGap(this, gap);
|
||||
|
||||
offset = gapOffset;
|
||||
ASMJIT_ASSERT(Utils::isAligned<size_t>(offset, size));
|
||||
|
||||
gapLength -= size;
|
||||
if (gapLength > 0)
|
||||
ConstPool_addGap(this, gapOffset, gapLength);
|
||||
}
|
||||
|
||||
gapIndex++;
|
||||
}
|
||||
|
||||
if (offset == ~static_cast<size_t>(0)) {
|
||||
// Get how many bytes have to be skipped so the address is aligned accordingly
|
||||
// to the 'size'.
|
||||
size_t diff = Utils::alignDiff<size_t>(_size, size);
|
||||
|
||||
if (diff != 0) {
|
||||
ConstPool_addGap(this, _size, diff);
|
||||
_size += diff;
|
||||
}
|
||||
|
||||
offset = _size;
|
||||
_size += size;
|
||||
}
|
||||
|
||||
// Add the initial node to the right index.
|
||||
node = ConstPool::Tree::_newNode(_zone, data, size, offset, false);
|
||||
if (!node) return DebugUtils::errored(kErrorNoHeapMemory);
|
||||
|
||||
_tree[treeIndex].put(node);
|
||||
_alignment = std::max<size_t>(_alignment, size);
|
||||
|
||||
dstOffset = offset;
|
||||
|
||||
// Now create a bunch of shared constants that are based on the data pattern.
|
||||
// We stop at size 4, it probably doesn't make sense to split constants down
|
||||
// to 1 byte.
|
||||
size_t pCount = 1;
|
||||
while (size > 4) {
|
||||
size >>= 1;
|
||||
pCount <<= 1;
|
||||
|
||||
ASMJIT_ASSERT(treeIndex != 0);
|
||||
treeIndex--;
|
||||
|
||||
const uint8_t* pData = static_cast<const uint8_t*>(data);
|
||||
for (size_t i = 0; i < pCount; i++, pData += size) {
|
||||
node = _tree[treeIndex].get(pData);
|
||||
if (node) continue;
|
||||
|
||||
node = ConstPool::Tree::_newNode(_zone, pData, size, offset + (i * size), true);
|
||||
_tree[treeIndex].put(node);
|
||||
}
|
||||
}
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ConstPool - Reset]
|
||||
// ============================================================================
|
||||
|
||||
struct ConstPoolFill {
|
||||
ASMJIT_INLINE ConstPoolFill(uint8_t* dst, size_t dataSize) noexcept :
|
||||
_dst(dst),
|
||||
_dataSize(dataSize) {}
|
||||
|
||||
ASMJIT_INLINE void visit(const ConstPool::Node* node) noexcept {
|
||||
if (!node->_shared)
|
||||
::memcpy(_dst + node->_offset, node->getData(), _dataSize);
|
||||
}
|
||||
|
||||
uint8_t* _dst;
|
||||
size_t _dataSize;
|
||||
};
|
||||
|
||||
void ConstPool::fill(void* dst) const noexcept {
|
||||
// Clears possible gaps, asmjit should never emit garbage to the output.
|
||||
::memset(dst, 0, _size);
|
||||
|
||||
ConstPoolFill filler(static_cast<uint8_t*>(dst), 1);
|
||||
for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) {
|
||||
_tree[i].iterate(filler);
|
||||
filler._dataSize <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ConstPool - Test]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(ASMJIT_TEST)
|
||||
UNIT(base_constpool) {
|
||||
Zone zone(32384 - Zone::kZoneOverhead);
|
||||
ConstPool pool(&zone);
|
||||
|
||||
uint32_t i;
|
||||
uint32_t kCount = 1000000;
|
||||
|
||||
INFO("Adding %u constants to the pool.", kCount);
|
||||
{
|
||||
size_t prevOffset;
|
||||
size_t curOffset;
|
||||
uint64_t c = ASMJIT_UINT64_C(0x0101010101010101);
|
||||
|
||||
EXPECT(pool.add(&c, 8, prevOffset) == kErrorOk,
|
||||
"pool.add() - Returned error");
|
||||
EXPECT(prevOffset == 0,
|
||||
"pool.add() - First constant should have zero offset");
|
||||
|
||||
for (i = 1; i < kCount; i++) {
|
||||
c++;
|
||||
EXPECT(pool.add(&c, 8, curOffset) == kErrorOk,
|
||||
"pool.add() - Returned error");
|
||||
EXPECT(prevOffset + 8 == curOffset,
|
||||
"pool.add() - Returned incorrect curOffset");
|
||||
EXPECT(pool.getSize() == (i + 1) * 8,
|
||||
"pool.getSize() - Reported incorrect size");
|
||||
prevOffset = curOffset;
|
||||
}
|
||||
|
||||
EXPECT(pool.getAlignment() == 8,
|
||||
"pool.getAlignment() - Expected 8-byte alignment");
|
||||
}
|
||||
|
||||
INFO("Retrieving %u constants from the pool.", kCount);
|
||||
{
|
||||
uint64_t c = ASMJIT_UINT64_C(0x0101010101010101);
|
||||
|
||||
for (i = 0; i < kCount; i++) {
|
||||
size_t offset;
|
||||
EXPECT(pool.add(&c, 8, offset) == kErrorOk,
|
||||
"pool.add() - Returned error");
|
||||
EXPECT(offset == i * 8,
|
||||
"pool.add() - Should have reused constant");
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
INFO("Checking if the constants were split into 4-byte patterns");
|
||||
{
|
||||
uint32_t c = 0x01010101;
|
||||
for (i = 0; i < kCount; i++) {
|
||||
size_t offset;
|
||||
EXPECT(pool.add(&c, 4, offset) == kErrorOk,
|
||||
"pool.add() - Returned error");
|
||||
EXPECT(offset == i * 8,
|
||||
"pool.add() - Should reuse existing constant");
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
INFO("Adding 2 byte constant to misalign the current offset");
|
||||
{
|
||||
uint16_t c = 0xFFFF;
|
||||
size_t offset;
|
||||
|
||||
EXPECT(pool.add(&c, 2, offset) == kErrorOk,
|
||||
"pool.add() - Returned error");
|
||||
EXPECT(offset == kCount * 8,
|
||||
"pool.add() - Didn't return expected position");
|
||||
EXPECT(pool.getAlignment() == 8,
|
||||
"pool.getAlignment() - Expected 8-byte alignment");
|
||||
}
|
||||
|
||||
INFO("Adding 8 byte constant to check if pool gets aligned again");
|
||||
{
|
||||
uint64_t c = ASMJIT_UINT64_C(0xFFFFFFFFFFFFFFFF);
|
||||
size_t offset;
|
||||
|
||||
EXPECT(pool.add(&c, 8, offset) == kErrorOk,
|
||||
"pool.add() - Returned error");
|
||||
EXPECT(offset == kCount * 8 + 8,
|
||||
"pool.add() - Didn't return aligned offset");
|
||||
}
|
||||
|
||||
INFO("Adding 2 byte constant to verify the gap is filled");
|
||||
{
|
||||
uint16_t c = 0xFFFE;
|
||||
size_t offset;
|
||||
|
||||
EXPECT(pool.add(&c, 2, offset) == kErrorOk,
|
||||
"pool.add() - Returned error");
|
||||
EXPECT(offset == kCount * 8 + 2,
|
||||
"pool.add() - Didn't fill the gap");
|
||||
EXPECT(pool.getAlignment() == 8,
|
||||
"pool.getAlignment() - Expected 8-byte alignment");
|
||||
}
|
||||
|
||||
INFO("Checking reset functionality");
|
||||
{
|
||||
pool.reset(&zone);
|
||||
zone.reset();
|
||||
|
||||
EXPECT(pool.getSize() == 0,
|
||||
"pool.getSize() - Expected pool size to be zero");
|
||||
EXPECT(pool.getAlignment() == 0,
|
||||
"pool.getSize() - Expected pool alignment to be zero");
|
||||
}
|
||||
|
||||
INFO("Checking pool alignment when combined constants are added");
|
||||
{
|
||||
uint8_t bytes[32] = { 0 };
|
||||
size_t offset;
|
||||
|
||||
pool.add(bytes, 1, offset);
|
||||
|
||||
EXPECT(pool.getSize() == 1,
|
||||
"pool.getSize() - Expected pool size to be 1 byte");
|
||||
EXPECT(pool.getAlignment() == 1,
|
||||
"pool.getSize() - Expected pool alignment to be 1 byte");
|
||||
EXPECT(offset == 0,
|
||||
"pool.getSize() - Expected offset returned to be zero");
|
||||
|
||||
pool.add(bytes, 2, offset);
|
||||
|
||||
EXPECT(pool.getSize() == 4,
|
||||
"pool.getSize() - Expected pool size to be 4 bytes");
|
||||
EXPECT(pool.getAlignment() == 2,
|
||||
"pool.getSize() - Expected pool alignment to be 2 bytes");
|
||||
EXPECT(offset == 2,
|
||||
"pool.getSize() - Expected offset returned to be 2");
|
||||
|
||||
pool.add(bytes, 4, offset);
|
||||
|
||||
EXPECT(pool.getSize() == 8,
|
||||
"pool.getSize() - Expected pool size to be 8 bytes");
|
||||
EXPECT(pool.getAlignment() == 4,
|
||||
"pool.getSize() - Expected pool alignment to be 4 bytes");
|
||||
EXPECT(offset == 4,
|
||||
"pool.getSize() - Expected offset returned to be 4");
|
||||
|
||||
pool.add(bytes, 4, offset);
|
||||
|
||||
EXPECT(pool.getSize() == 8,
|
||||
"pool.getSize() - Expected pool size to be 8 bytes");
|
||||
EXPECT(pool.getAlignment() == 4,
|
||||
"pool.getSize() - Expected pool alignment to be 4 bytes");
|
||||
EXPECT(offset == 4,
|
||||
"pool.getSize() - Expected offset returned to be 8");
|
||||
|
||||
pool.add(bytes, 32, offset);
|
||||
EXPECT(pool.getSize() == 64,
|
||||
"pool.getSize() - Expected pool size to be 64 bytes");
|
||||
EXPECT(pool.getAlignment() == 32,
|
||||
"pool.getSize() - Expected pool alignment to be 32 bytes");
|
||||
EXPECT(offset == 32,
|
||||
"pool.getSize() - Expected offset returned to be 32");
|
||||
}
|
||||
}
|
||||
#endif // ASMJIT_TEST
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
|
@ -1,257 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_CONSTPOOL_H
|
||||
#define _ASMJIT_BASE_CONSTPOOL_H
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/zone.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! \addtogroup asmjit_base
|
||||
//! \{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::ConstPool]
|
||||
// ============================================================================
|
||||
|
||||
//! Constant pool.
|
||||
class ConstPool {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(ConstPool)
|
||||
|
||||
enum {
|
||||
kIndex1 = 0,
|
||||
kIndex2 = 1,
|
||||
kIndex4 = 2,
|
||||
kIndex8 = 3,
|
||||
kIndex16 = 4,
|
||||
kIndex32 = 5,
|
||||
kIndexCount = 6
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Gap]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! Zone-allocated const-pool gap.
|
||||
struct Gap {
|
||||
Gap* _next; //!< Pointer to the next gap
|
||||
size_t _offset; //!< Offset of the gap.
|
||||
size_t _length; //!< Remaining bytes of the gap (basically a gap size).
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Node]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! Zone-allocated const-pool node.
|
||||
struct Node {
|
||||
ASMJIT_INLINE void* getData() const noexcept {
|
||||
return static_cast<void*>(const_cast<ConstPool::Node*>(this) + 1);
|
||||
}
|
||||
|
||||
Node* _link[2]; //!< Left/Right nodes.
|
||||
uint32_t _level : 31; //!< Horizontal level for balance.
|
||||
uint32_t _shared : 1; //!< If this constant is shared with another.
|
||||
uint32_t _offset; //!< Data offset from the beginning of the pool.
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Tree]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! Zone-allocated const-pool tree.
|
||||
struct Tree {
|
||||
enum {
|
||||
//! Maximum tree height == log2(1 << 64).
|
||||
kHeightLimit = 64
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE Tree(size_t dataSize = 0) noexcept
|
||||
: _root(nullptr),
|
||||
_length(0),
|
||||
_dataSize(dataSize) {}
|
||||
ASMJIT_INLINE ~Tree() {}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE void reset() noexcept {
|
||||
_root = nullptr;
|
||||
_length = 0;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; }
|
||||
ASMJIT_INLINE size_t getLength() const noexcept { return _length; }
|
||||
|
||||
ASMJIT_INLINE void setDataSize(size_t dataSize) noexcept {
|
||||
ASMJIT_ASSERT(isEmpty());
|
||||
_dataSize = dataSize;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Ops]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API Node* get(const void* data) noexcept;
|
||||
ASMJIT_API void put(Node* node) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Iterate]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
template<typename Visitor>
|
||||
ASMJIT_INLINE void iterate(Visitor& visitor) const noexcept {
|
||||
Node* node = const_cast<Node*>(_root);
|
||||
if (!node) return;
|
||||
|
||||
Node* stack[kHeightLimit];
|
||||
size_t top = 0;
|
||||
|
||||
for (;;) {
|
||||
Node* left = node->_link[0];
|
||||
if (left != nullptr) {
|
||||
ASMJIT_ASSERT(top != kHeightLimit);
|
||||
stack[top++] = node;
|
||||
|
||||
node = left;
|
||||
continue;
|
||||
}
|
||||
|
||||
Visit:
|
||||
visitor.visit(node);
|
||||
node = node->_link[1];
|
||||
if (node != nullptr)
|
||||
continue;
|
||||
|
||||
if (top == 0)
|
||||
return;
|
||||
|
||||
node = stack[--top];
|
||||
goto Visit;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Helpers]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
static ASMJIT_INLINE Node* _newNode(Zone* zone, const void* data, size_t size, size_t offset, bool shared) noexcept {
|
||||
Node* node = zone->allocT<Node>(sizeof(Node) + size);
|
||||
if (ASMJIT_UNLIKELY(!node)) return nullptr;
|
||||
|
||||
node->_link[0] = nullptr;
|
||||
node->_link[1] = nullptr;
|
||||
node->_level = 1;
|
||||
node->_shared = shared;
|
||||
node->_offset = static_cast<uint32_t>(offset);
|
||||
|
||||
::memcpy(node->getData(), data, size);
|
||||
return node;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
Node* _root; //!< Root of the tree
|
||||
size_t _length; //!< Length of the tree (count of nodes).
|
||||
size_t _dataSize; //!< Size of the data.
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API ConstPool(Zone* zone) noexcept;
|
||||
ASMJIT_API ~ConstPool() noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API void reset(Zone* zone) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Ops]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get whether the constant-pool is empty.
|
||||
ASMJIT_INLINE bool isEmpty() const noexcept { return _size == 0; }
|
||||
//! Get the size of the constant-pool in bytes.
|
||||
ASMJIT_INLINE size_t getSize() const noexcept { return _size; }
|
||||
//! Get minimum alignment.
|
||||
ASMJIT_INLINE size_t getAlignment() const noexcept { return _alignment; }
|
||||
|
||||
//! Add a constant to the constant pool.
|
||||
//!
|
||||
//! The constant must have known size, which is 1, 2, 4, 8, 16 or 32 bytes.
|
||||
//! The constant is added to the pool only if it doesn't not exist, otherwise
|
||||
//! cached value is returned.
|
||||
//!
|
||||
//! AsmJit is able to subdivide added constants, so for example if you add
|
||||
//! 8-byte constant 0x1122334455667788 it will create the following slots:
|
||||
//!
|
||||
//! 8-byte: 0x1122334455667788
|
||||
//! 4-byte: 0x11223344, 0x55667788
|
||||
//!
|
||||
//! The reason is that when combining MMX/SSE/AVX code some patterns are used
|
||||
//! frequently. However, AsmJit is not able to reallocate a constant that has
|
||||
//! been already added. For example if you try to add 4-byte constant and then
|
||||
//! 8-byte constant having the same 4-byte pattern as the previous one, two
|
||||
//! independent slots will be generated by the pool.
|
||||
ASMJIT_API Error add(const void* data, size_t size, size_t& dstOffset) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Fill]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Fill the destination with the constants from the pool.
|
||||
ASMJIT_API void fill(void* dst) const noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
Zone* _zone; //!< Zone allocator.
|
||||
Tree _tree[kIndexCount]; //!< Tree per size.
|
||||
Gap* _gaps[kIndexCount]; //!< Gaps per size.
|
||||
Gap* _gapPool; //!< Gaps pool
|
||||
|
||||
size_t _size; //!< Size of the pool (in bytes).
|
||||
size_t _alignment; //!< Required pool alignment.
|
||||
};
|
||||
|
||||
//! \}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_CONSTPOOL_H
|
|
@ -1,674 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/cpuinfo.h"
|
||||
#include "../base/utils.h"
|
||||
|
||||
#if ASMJIT_OS_POSIX
|
||||
# include <errno.h>
|
||||
# include <sys/utsname.h>
|
||||
# include <unistd.h>
|
||||
#endif // ASMJIT_OS_POSIX
|
||||
|
||||
#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
|
||||
# if ASMJIT_CC_MSC_GE(14, 0, 0)
|
||||
# include <intrin.h> // Required by `__cpuid()` and `_xgetbv()`.
|
||||
# endif // _MSC_VER >= 1400
|
||||
#endif
|
||||
|
||||
#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
|
||||
# if ASMJIT_OS_LINUX
|
||||
# include <sys/auxv.h> // Required by `getauxval()`.
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CpuInfo - Detect ARM]
|
||||
// ============================================================================
|
||||
|
||||
// ARM information has to be retrieved by the OS (this is how ARM was designed).
|
||||
#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
|
||||
|
||||
#if ASMJIT_ARCH_ARM32
|
||||
static ASMJIT_INLINE void armPopulateBaselineA32Features(CpuInfo* cpuInfo) noexcept {
|
||||
cpuInfo->_archInfo.init(ArchInfo::kTypeA32);
|
||||
}
|
||||
#endif // ASMJIT_ARCH_ARM32
|
||||
|
||||
#if ASMJIT_ARCH_ARM64
|
||||
static ASMJIT_INLINE void armPopulateBaselineA64Features(CpuInfo* cpuInfo) noexcept {
|
||||
cpuInfo->_archInfo.init(ArchInfo::kTypeA64);
|
||||
|
||||
// Thumb (including all variations) is supported on A64 (but not accessible from A64).
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB);
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB2);
|
||||
|
||||
// A64 is based on ARMv8 and newer.
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureV6);
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureV7);
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureV8);
|
||||
|
||||
// A64 comes with these features by default.
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv2);
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv3);
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv4);
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureEDSP);
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureASIMD);
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureIDIVA);
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureIDIVT);
|
||||
}
|
||||
#endif // ASMJIT_ARCH_ARM64
|
||||
|
||||
#if ASMJIT_OS_WINDOWS
|
||||
//! \internal
|
||||
//!
|
||||
//! Detect ARM CPU features on Windows.
|
||||
//!
|
||||
//! The detection is based on `IsProcessorFeaturePresent()` API call.
|
||||
static ASMJIT_INLINE void armDetectCpuInfoOnWindows(CpuInfo* cpuInfo) noexcept {
|
||||
#if ASMJIT_ARCH_ARM32
|
||||
armPopulateBaselineA32Features(cpuInfo);
|
||||
|
||||
// Windows for ARM requires at least ARMv7 with DSP extensions.
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureV6);
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureV7);
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureEDSP);
|
||||
|
||||
// Windows for ARM requires VFPv3.
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv2);
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv3);
|
||||
|
||||
// Windows for ARM requires and uses THUMB2.
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB);
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB2);
|
||||
#else
|
||||
armPopulateBaselineA64Features(cpuInfo);
|
||||
#endif
|
||||
|
||||
// Windows for ARM requires ASIMD.
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureASIMD);
|
||||
|
||||
// Detect additional CPU features by calling `IsProcessorFeaturePresent()`.
|
||||
struct WinPFPMapping {
|
||||
uint32_t pfpId;
|
||||
uint32_t featureId;
|
||||
};
|
||||
|
||||
static const WinPFPMapping mapping[] = {
|
||||
{ PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE , CpuInfo::kArmFeatureVFPv4 },
|
||||
{ PF_ARM_VFP_32_REGISTERS_AVAILABLE , CpuInfo::kArmFeatureVFP_D32 },
|
||||
{ PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE, CpuInfo::kArmFeatureIDIVT },
|
||||
{ PF_ARM_64BIT_LOADSTORE_ATOMIC , CpuInfo::kArmFeatureAtomics64 }
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(mapping); i++)
|
||||
if (::IsProcessorFeaturePresent(mapping[i].pfpId))
|
||||
cpuInfo->addFeature(mapping[i].featureId);
|
||||
}
|
||||
#endif // ASMJIT_OS_WINDOWS
|
||||
|
||||
#if ASMJIT_OS_LINUX
|
||||
struct LinuxHWCapMapping {
|
||||
uint32_t hwcapMask;
|
||||
uint32_t featureId;
|
||||
};
|
||||
|
||||
static void armDetectHWCaps(CpuInfo* cpuInfo, unsigned long type, const LinuxHWCapMapping* mapping, size_t length) noexcept {
|
||||
unsigned long mask = getauxval(type);
|
||||
|
||||
for (size_t i = 0; i < length; i++)
|
||||
if ((mask & mapping[i].hwcapMask) == mapping[i].hwcapMask)
|
||||
cpuInfo->addFeature(mapping[i].featureId);
|
||||
}
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! Detect ARM CPU features on Linux.
|
||||
//!
|
||||
//! The detection is based on `getauxval()`.
|
||||
ASMJIT_FAVOR_SIZE static void armDetectCpuInfoOnLinux(CpuInfo* cpuInfo) noexcept {
|
||||
#if ASMJIT_ARCH_ARM32
|
||||
armPopulateBaselineA32Features(cpuInfo);
|
||||
|
||||
// `AT_HWCAP` provides ARMv7 (and less) related flags.
|
||||
static const LinuxHWCapMapping hwCapMapping[] = {
|
||||
{ /* HWCAP_VFP */ (1 << 6), CpuInfo::kArmFeatureVFPv2 },
|
||||
{ /* HWCAP_EDSP */ (1 << 7), CpuInfo::kArmFeatureEDSP },
|
||||
{ /* HWCAP_NEON */ (1 << 12), CpuInfo::kArmFeatureASIMD },
|
||||
{ /* HWCAP_VFPv3 */ (1 << 13), CpuInfo::kArmFeatureVFPv3 },
|
||||
{ /* HWCAP_VFPv4 */ (1 << 16), CpuInfo::kArmFeatureVFPv4 },
|
||||
{ /* HWCAP_IDIVA */ (1 << 17), CpuInfo::kArmFeatureIDIVA },
|
||||
{ /* HWCAP_IDIVT */ (1 << 18), CpuInfo::kArmFeatureIDIVT },
|
||||
{ /* HWCAP_VFPD32 */ (1 << 19), CpuInfo::kArmFeatureVFP_D32 }
|
||||
};
|
||||
armDetectHWCaps(cpuInfo, AT_HWCAP, hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping));
|
||||
|
||||
// VFPv3 implies VFPv2.
|
||||
if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFPv3)) {
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv2);
|
||||
}
|
||||
|
||||
// VFPv2 implies ARMv6.
|
||||
if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFPv2)) {
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureV6);
|
||||
}
|
||||
|
||||
// VFPv3 or ASIMD implies ARMv7.
|
||||
if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFPv3) ||
|
||||
cpuInfo->hasFeature(CpuInfo::kArmFeatureASIMD)) {
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureV7);
|
||||
}
|
||||
|
||||
// `AT_HWCAP2` provides ARMv8+ related flags.
|
||||
static const LinuxHWCapMapping hwCap2Mapping[] = {
|
||||
{ /* HWCAP2_AES */ (1 << 0), CpuInfo::kArmFeatureAES },
|
||||
{ /* HWCAP2_PMULL */ (1 << 1), CpuInfo::kArmFeaturePMULL },
|
||||
{ /* HWCAP2_SHA1 */ (1 << 2), CpuInfo::kArmFeatureSHA1 },
|
||||
{ /* HWCAP2_SHA2 */ (1 << 3), CpuInfo::kArmFeatureSHA256 },
|
||||
{ /* HWCAP2_CRC32 */ (1 << 4), CpuInfo::kArmFeatureCRC32 }
|
||||
};
|
||||
armDetectHWCaps(cpuInfo, AT_HWCAP2, hwCap2Mapping, ASMJIT_ARRAY_SIZE(hwCap2Mapping));
|
||||
|
||||
if (cpuInfo->hasFeature(CpuInfo::kArmFeatureAES ) ||
|
||||
cpuInfo->hasFeature(CpuInfo::kArmFeatureCRC32 ) ||
|
||||
cpuInfo->hasFeature(CpuInfo::kArmFeaturePMULL ) ||
|
||||
cpuInfo->hasFeature(CpuInfo::kArmFeatureSHA1 ) ||
|
||||
cpuInfo->hasFeature(CpuInfo::kArmFeatureSHA256)) {
|
||||
cpuInfo->addFeature(CpuInfo::kArmFeatureV8);
|
||||
}
|
||||
#else
|
||||
armPopulateBaselineA64Features(cpuInfo);
|
||||
|
||||
// `AT_HWCAP` provides ARMv8+ related flags.
|
||||
static const LinuxHWCapMapping hwCapMapping[] = {
|
||||
{ /* HWCAP_ASIMD */ (1 << 1), CpuInfo::kArmFeatureASIMD },
|
||||
{ /* HWCAP_AES */ (1 << 3), CpuInfo::kArmFeatureAES },
|
||||
{ /* HWCAP_CRC32 */ (1 << 7), CpuInfo::kArmFeatureCRC32 },
|
||||
{ /* HWCAP_PMULL */ (1 << 4), CpuInfo::kArmFeaturePMULL },
|
||||
{ /* HWCAP_SHA1 */ (1 << 5), CpuInfo::kArmFeatureSHA1 },
|
||||
{ /* HWCAP_SHA2 */ (1 << 6), CpuInfo::kArmFeatureSHA256 },
|
||||
{ /* HWCAP_ATOMICS */ (1 << 8), CpuInfo::kArmFeatureAtomics64 }
|
||||
};
|
||||
armDetectHWCaps(cpuInfo, AT_HWCAP, hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping));
|
||||
|
||||
// `AT_HWCAP2` is not used at the moment.
|
||||
#endif
|
||||
}
|
||||
#endif // ASMJIT_OS_LINUX
|
||||
|
||||
ASMJIT_FAVOR_SIZE static void armDetectCpuInfo(CpuInfo* cpuInfo) noexcept {
|
||||
#if ASMJIT_OS_WINDOWS
|
||||
armDetectCpuInfoOnWindows(cpuInfo);
|
||||
#elif ASMJIT_OS_LINUX
|
||||
armDetectCpuInfoOnLinux(cpuInfo);
|
||||
#else
|
||||
# error "[asmjit] armDetectCpuInfo() - Unsupported OS."
|
||||
#endif
|
||||
}
|
||||
#endif // ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CpuInfo - Detect X86]
|
||||
// ============================================================================
|
||||
|
||||
#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! X86 CPUID result.
|
||||
struct CpuIdResult {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
};
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! Content of XCR register, result of XGETBV instruction.
|
||||
struct XGetBVResult {
|
||||
uint32_t eax, edx;
|
||||
};
|
||||
|
||||
#if ASMJIT_CC_MSC && !ASMJIT_CC_MSC_GE(15, 0, 30729) && ASMJIT_ARCH_X64
|
||||
//! \internal
|
||||
//!
|
||||
//! HACK: VS2008 or less, 64-bit mode - `__cpuidex` doesn't exist! However,
|
||||
//! 64-bit calling convention specifies the first parameter to be passed by
|
||||
//! ECX, so we may be lucky if compiler doesn't move the register, otherwise
|
||||
//! the result would be wrong.
|
||||
static void ASMJIT_NOINLINE void x86CallCpuIdWorkaround(uint32_t inEcx, uint32_t inEax, CpuIdResult* result) noexcept {
|
||||
__cpuid(reinterpret_cast<int*>(result), inEax);
|
||||
}
|
||||
#endif
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! Wrapper to call `cpuid` instruction.
|
||||
static void ASMJIT_INLINE x86CallCpuId(CpuIdResult* result, uint32_t inEax, uint32_t inEcx = 0) noexcept {
|
||||
#if ASMJIT_CC_MSC && ASMJIT_CC_MSC_GE(15, 0, 30729)
|
||||
__cpuidex(reinterpret_cast<int*>(result), inEax, inEcx);
|
||||
#elif ASMJIT_CC_MSC && ASMJIT_ARCH_X64
|
||||
x86CallCpuIdWorkaround(inEcx, inEax, result);
|
||||
#elif ASMJIT_CC_MSC && ASMJIT_ARCH_X86
|
||||
uint32_t paramEax = inEax;
|
||||
uint32_t paramEcx = inEcx;
|
||||
uint32_t* out = reinterpret_cast<uint32_t*>(result);
|
||||
|
||||
__asm {
|
||||
mov eax, paramEax
|
||||
mov ecx, paramEcx
|
||||
mov edi, out
|
||||
cpuid
|
||||
mov dword ptr[edi + 0], eax
|
||||
mov dword ptr[edi + 4], ebx
|
||||
mov dword ptr[edi + 8], ecx
|
||||
mov dword ptr[edi + 12], edx
|
||||
}
|
||||
#elif (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && ASMJIT_ARCH_X86
|
||||
__asm__ __volatile__(
|
||||
"mov %%ebx, %%edi\n"
|
||||
"cpuid\n"
|
||||
"xchg %%edi, %%ebx\n"
|
||||
: "=a"(result->eax),
|
||||
"=D"(result->ebx),
|
||||
"=c"(result->ecx),
|
||||
"=d"(result->edx)
|
||||
: "a"(inEax),
|
||||
"c"(inEcx));
|
||||
#elif (ASMJIT_CC_GCC || ASMJIT_CC_CLANG || ASMJIT_CC_INTEL) && ASMJIT_ARCH_X64
|
||||
__asm__ __volatile__(
|
||||
"mov %%rbx, %%rdi\n"
|
||||
"cpuid\n"
|
||||
"xchg %%rdi, %%rbx\n"
|
||||
: "=a"(result->eax),
|
||||
"=D"(result->ebx),
|
||||
"=c"(result->ecx),
|
||||
"=d"(result->edx)
|
||||
: "a"(inEax),
|
||||
"c"(inEcx));
|
||||
#else
|
||||
# error "[asmjit] x86CallCpuid() - Unsupported compiler."
|
||||
#endif
|
||||
}
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! Wrapper to call `xgetbv` instruction.
|
||||
static ASMJIT_INLINE void x86CallXGetBV(XGetBVResult* result, uint32_t inEcx) noexcept {
|
||||
#if ASMJIT_CC_MSC_GE(16, 0, 40219) // 2010SP1+
|
||||
uint64_t value = _xgetbv(inEcx);
|
||||
result->eax = static_cast<uint32_t>(value & 0xFFFFFFFFU);
|
||||
result->edx = static_cast<uint32_t>(value >> 32);
|
||||
#elif ASMJIT_CC_GCC || ASMJIT_CC_CLANG
|
||||
uint32_t outEax;
|
||||
uint32_t outEdx;
|
||||
|
||||
// Replaced, because the world is not perfect:
|
||||
// __asm__ __volatile__("xgetbv" : "=a"(outEax), "=d"(outEdx) : "c"(inEcx));
|
||||
__asm__ __volatile__(".byte 0x0F, 0x01, 0xd0" : "=a"(outEax), "=d"(outEdx) : "c"(inEcx));
|
||||
|
||||
result->eax = outEax;
|
||||
result->edx = outEdx;
|
||||
#else
|
||||
result->eax = 0;
|
||||
result->edx = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! Map a 12-byte vendor string returned by `cpuid` into a `CpuInfo::Vendor` ID.
|
||||
static ASMJIT_INLINE uint32_t x86GetCpuVendorID(const char* vendorString) noexcept {
|
||||
struct VendorData {
|
||||
uint32_t id;
|
||||
char text[12];
|
||||
};
|
||||
|
||||
static const VendorData vendorList[] = {
|
||||
{ CpuInfo::kVendorIntel , { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l' } },
|
||||
{ CpuInfo::kVendorAMD , { 'A', 'u', 't', 'h', 'e', 'n', 't', 'i', 'c', 'A', 'M', 'D' } },
|
||||
{ CpuInfo::kVendorVIA , { 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 } },
|
||||
{ CpuInfo::kVendorVIA , { 'C', 'e', 'n', 't', 'a', 'u', 'r', 'H', 'a', 'u', 'l', 's' } }
|
||||
};
|
||||
|
||||
uint32_t dw0 = reinterpret_cast<const uint32_t*>(vendorString)[0];
|
||||
uint32_t dw1 = reinterpret_cast<const uint32_t*>(vendorString)[1];
|
||||
uint32_t dw2 = reinterpret_cast<const uint32_t*>(vendorString)[2];
|
||||
|
||||
for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(vendorList); i++) {
|
||||
if (dw0 == reinterpret_cast<const uint32_t*>(vendorList[i].text)[0] &&
|
||||
dw1 == reinterpret_cast<const uint32_t*>(vendorList[i].text)[1] &&
|
||||
dw2 == reinterpret_cast<const uint32_t*>(vendorList[i].text)[2])
|
||||
return vendorList[i].id;
|
||||
}
|
||||
|
||||
return CpuInfo::kVendorNone;
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE void x86SimplifyBrandString(char* s) noexcept {
|
||||
// Used to always clear the current character to ensure that the result
|
||||
// doesn't contain garbage after the new zero terminator.
|
||||
char* d = s;
|
||||
|
||||
char prev = 0;
|
||||
char curr = s[0];
|
||||
s[0] = '\0';
|
||||
|
||||
for (;;) {
|
||||
if (curr == 0)
|
||||
break;
|
||||
|
||||
if (curr == ' ') {
|
||||
if (prev == '@' || s[1] == ' ' || s[1] == '@')
|
||||
goto L_Skip;
|
||||
}
|
||||
|
||||
d[0] = curr;
|
||||
d++;
|
||||
prev = curr;
|
||||
|
||||
L_Skip:
|
||||
curr = *++s;
|
||||
s[0] = '\0';
|
||||
}
|
||||
|
||||
d[0] = '\0';
|
||||
}
|
||||
|
||||
ASMJIT_FAVOR_SIZE static void x86DetectCpuInfo(CpuInfo* cpuInfo) noexcept {
|
||||
uint32_t i, maxId;
|
||||
|
||||
CpuIdResult regs;
|
||||
XGetBVResult xcr0 = { 0, 0 };
|
||||
|
||||
cpuInfo->_archInfo.init(ArchInfo::kTypeHost);
|
||||
cpuInfo->addFeature(CpuInfo::kX86FeatureI486);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [CPUID EAX=0x0]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Get vendor string/id.
|
||||
x86CallCpuId(®s, 0x0);
|
||||
|
||||
maxId = regs.eax;
|
||||
::memcpy(cpuInfo->_vendorString + 0, ®s.ebx, 4);
|
||||
::memcpy(cpuInfo->_vendorString + 4, ®s.edx, 4);
|
||||
::memcpy(cpuInfo->_vendorString + 8, ®s.ecx, 4);
|
||||
cpuInfo->_vendorId = x86GetCpuVendorID(cpuInfo->_vendorString);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [CPUID EAX=0x1]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
if (maxId >= 0x1) {
|
||||
// Get feature flags in ECX/EDX and family/model in EAX.
|
||||
x86CallCpuId(®s, 0x1);
|
||||
|
||||
// Fill family and model fields.
|
||||
cpuInfo->_family = (regs.eax >> 8) & 0x0F;
|
||||
cpuInfo->_model = (regs.eax >> 4) & 0x0F;
|
||||
cpuInfo->_stepping = (regs.eax ) & 0x0F;
|
||||
|
||||
// Use extended family and model fields.
|
||||
if (cpuInfo->_family == 0x0F) {
|
||||
cpuInfo->_family += ((regs.eax >> 20) & 0xFF);
|
||||
cpuInfo->_model += ((regs.eax >> 16) & 0x0F) << 4;
|
||||
}
|
||||
|
||||
cpuInfo->_x86Data._processorType = ((regs.eax >> 12) & 0x03);
|
||||
cpuInfo->_x86Data._brandIndex = ((regs.ebx ) & 0xFF);
|
||||
cpuInfo->_x86Data._flushCacheLineSize = ((regs.ebx >> 8) & 0xFF) * 8;
|
||||
cpuInfo->_x86Data._maxLogicalProcessors = ((regs.ebx >> 16) & 0xFF);
|
||||
|
||||
if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE3);
|
||||
if (regs.ecx & 0x00000002U) cpuInfo->addFeature(CpuInfo::kX86FeaturePCLMULQDQ);
|
||||
if (regs.ecx & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureMONITOR);
|
||||
if (regs.ecx & 0x00000200U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSSE3);
|
||||
if (regs.ecx & 0x00002000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMPXCHG16B);
|
||||
if (regs.ecx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4_1);
|
||||
if (regs.ecx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4_2);
|
||||
if (regs.ecx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMOVBE);
|
||||
if (regs.ecx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeaturePOPCNT);
|
||||
if (regs.ecx & 0x02000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAESNI);
|
||||
if (regs.ecx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVE);
|
||||
if (regs.ecx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureOSXSAVE);
|
||||
if (regs.ecx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDRAND);
|
||||
if (regs.edx & 0x00000010U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDTSC);
|
||||
if (regs.edx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureMSR);
|
||||
if (regs.edx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMPXCHG8B);
|
||||
if (regs.edx & 0x00008000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMOV);
|
||||
if (regs.edx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLFLUSH);
|
||||
if (regs.edx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMMX);
|
||||
if (regs.edx & 0x01000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFXSR);
|
||||
if (regs.edx & 0x02000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE)
|
||||
.addFeature(CpuInfo::kX86FeatureMMX2);
|
||||
if (regs.edx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE)
|
||||
.addFeature(CpuInfo::kX86FeatureSSE2);
|
||||
if (regs.edx & 0x10000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMT);
|
||||
|
||||
// Get the content of XCR0 if supported by CPU and enabled by OS.
|
||||
if ((regs.ecx & 0x0C000000U) == 0x0C000000U) {
|
||||
x86CallXGetBV(&xcr0, 0);
|
||||
}
|
||||
|
||||
// Detect AVX+.
|
||||
if (regs.ecx & 0x10000000U) {
|
||||
// - XCR0[2:1] == 11b
|
||||
// XMM & YMM states need to be enabled by OS.
|
||||
if ((xcr0.eax & 0x00000006U) == 0x00000006U) {
|
||||
cpuInfo->addFeature(CpuInfo::kX86FeatureAVX);
|
||||
|
||||
if (regs.ecx & 0x00001000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFMA);
|
||||
if (regs.ecx & 0x20000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureF16C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [CPUID EAX=0x7]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Detect new features if the processor supports CPUID-07.
|
||||
bool maybeMPX = false;
|
||||
|
||||
if (maxId >= 0x7) {
|
||||
x86CallCpuId(®s, 0x7);
|
||||
|
||||
if (regs.ebx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureFSGSBASE);
|
||||
if (regs.ebx & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureBMI);
|
||||
if (regs.ebx & 0x00000010U) cpuInfo->addFeature(CpuInfo::kX86FeatureHLE);
|
||||
if (regs.ebx & 0x00000080U) cpuInfo->addFeature(CpuInfo::kX86FeatureSMEP);
|
||||
if (regs.ebx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeatureBMI2);
|
||||
if (regs.ebx & 0x00000200U) cpuInfo->addFeature(CpuInfo::kX86FeatureERMS);
|
||||
if (regs.ebx & 0x00000800U) cpuInfo->addFeature(CpuInfo::kX86FeatureRTM);
|
||||
if (regs.ebx & 0x00004000U) maybeMPX = true;
|
||||
if (regs.ebx & 0x00040000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDSEED);
|
||||
if (regs.ebx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureADX);
|
||||
if (regs.ebx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSMAP);
|
||||
if (regs.ebx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeaturePCOMMIT);
|
||||
if (regs.ebx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLFLUSHOPT);
|
||||
if (regs.ebx & 0x01000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLWB);
|
||||
if (regs.ebx & 0x20000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSHA);
|
||||
if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeaturePREFETCHWT1);
|
||||
|
||||
// TSX is supported if at least one of `HLE` and `RTM` is supported.
|
||||
if (regs.ebx & 0x00000810U) cpuInfo->addFeature(CpuInfo::kX86FeatureTSX);
|
||||
|
||||
// Detect AVX2.
|
||||
if (cpuInfo->hasFeature(CpuInfo::kX86FeatureAVX)) {
|
||||
if (regs.ebx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX2);
|
||||
}
|
||||
|
||||
// Detect AVX-512+.
|
||||
if (regs.ebx & 0x00010000U) {
|
||||
// - XCR0[2:1] == 11b
|
||||
// XMM/YMM states need to be enabled by OS.
|
||||
// - XCR0[7:5] == 111b
|
||||
// Upper 256-bit of ZMM0-XMM15 and ZMM16-ZMM31 need to be enabled by the OS.
|
||||
if ((xcr0.eax & 0x000000E6U) == 0x000000E6U) {
|
||||
cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_F);
|
||||
|
||||
if (regs.ebx & 0x00020000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_DQ);
|
||||
if (regs.ebx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_IFMA);
|
||||
if (regs.ebx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_PFI);
|
||||
if (regs.ebx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_ERI);
|
||||
if (regs.ebx & 0x10000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_CDI);
|
||||
if (regs.ebx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_BW);
|
||||
if (regs.ebx & 0x80000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_VL);
|
||||
if (regs.ecx & 0x00000002U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_VBMI);
|
||||
if (regs.ecx & 0x00004000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_VPOPCNTDQ);
|
||||
if (regs.edx & 0x00000004U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_4VNNIW);
|
||||
if (regs.edx & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_4FMAPS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [CPUID EAX=0xD]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
if (maxId >= 0xD) {
|
||||
x86CallCpuId(®s, 0xD, 0);
|
||||
|
||||
// Both CPUID result and XCR0 has to be enabled to have support for MPX.
|
||||
if (((regs.eax & xcr0.eax) & 0x00000018U) == 0x00000018U && maybeMPX)
|
||||
cpuInfo->addFeature(CpuInfo::kX86FeatureMPX);
|
||||
|
||||
x86CallCpuId(®s, 0xD, 1);
|
||||
if (regs.eax & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVEOPT);
|
||||
if (regs.eax & 0x00000002U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVEC);
|
||||
if (regs.eax & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVES);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [CPUID EAX=0x80000000...maxId]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// The highest EAX that we understand.
|
||||
uint32_t kHighestProcessedEAX = 0x80000008U;
|
||||
|
||||
// Several CPUID calls are required to get the whole branc string. It's easy
|
||||
// to copy one DWORD at a time instead of performing a byte copy.
|
||||
uint32_t* brand = reinterpret_cast<uint32_t*>(cpuInfo->_brandString);
|
||||
|
||||
i = maxId = 0x80000000U;
|
||||
do {
|
||||
x86CallCpuId(®s, i);
|
||||
switch (i) {
|
||||
case 0x80000000U:
|
||||
maxId = std::min<uint32_t>(regs.eax, kHighestProcessedEAX);
|
||||
break;
|
||||
|
||||
case 0x80000001U:
|
||||
if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureLAHFSAHF);
|
||||
if (regs.ecx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureLZCNT);
|
||||
if (regs.ecx & 0x00000040U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4A);
|
||||
if (regs.ecx & 0x00000080U) cpuInfo->addFeature(CpuInfo::kX86FeatureMSSE);
|
||||
if (regs.ecx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeaturePREFETCHW);
|
||||
if (regs.ecx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureTBM);
|
||||
if (regs.edx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureNX);
|
||||
if (regs.edx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFXSROPT);
|
||||
if (regs.edx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMMX2);
|
||||
if (regs.edx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDTSCP);
|
||||
if (regs.edx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86Feature3DNOW2)
|
||||
.addFeature(CpuInfo::kX86FeatureMMX2);
|
||||
if (regs.edx & 0x80000000U) cpuInfo->addFeature(CpuInfo::kX86Feature3DNOW);
|
||||
|
||||
if (cpuInfo->hasFeature(CpuInfo::kX86FeatureAVX)) {
|
||||
if (regs.ecx & 0x00000800U) cpuInfo->addFeature(CpuInfo::kX86FeatureXOP);
|
||||
if (regs.ecx & 0x00010000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFMA4);
|
||||
}
|
||||
|
||||
// These seem to be only supported by AMD.
|
||||
if (cpuInfo->getVendorId() == CpuInfo::kVendorAMD) {
|
||||
if (regs.ecx & 0x00000010U) cpuInfo->addFeature(CpuInfo::kX86FeatureALTMOVCR8);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x80000002U:
|
||||
case 0x80000003U:
|
||||
case 0x80000004U:
|
||||
*brand++ = regs.eax;
|
||||
*brand++ = regs.ebx;
|
||||
*brand++ = regs.ecx;
|
||||
*brand++ = regs.edx;
|
||||
|
||||
// Go directly to the last one.
|
||||
if (i == 0x80000004U) i = 0x80000008U - 1;
|
||||
break;
|
||||
|
||||
case 0x80000008U:
|
||||
if (regs.ebx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLZERO);
|
||||
break;
|
||||
}
|
||||
} while (++i <= maxId);
|
||||
|
||||
// Simplify CPU brand string by removing unnecessary spaces.
|
||||
x86SimplifyBrandString(cpuInfo->_brandString);
|
||||
}
|
||||
#endif // ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CpuInfo - Detect - HWThreadsCount]
|
||||
// ============================================================================
|
||||
|
||||
static ASMJIT_INLINE uint32_t cpuDetectHWThreadsCount() noexcept {
|
||||
#if ASMJIT_OS_WINDOWS
|
||||
SYSTEM_INFO info;
|
||||
::GetSystemInfo(&info);
|
||||
return info.dwNumberOfProcessors;
|
||||
#elif ASMJIT_OS_POSIX && defined(_SC_NPROCESSORS_ONLN)
|
||||
long res = ::sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (res <= 0) return 1;
|
||||
return static_cast<uint32_t>(res);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CpuInfo - Detect]
|
||||
// ============================================================================
|
||||
|
||||
ASMJIT_FAVOR_SIZE void CpuInfo::detect() noexcept {
|
||||
reset();
|
||||
|
||||
#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
|
||||
armDetectCpuInfo(this);
|
||||
#endif // ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
|
||||
|
||||
#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
|
||||
x86DetectCpuInfo(this);
|
||||
#endif // ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
|
||||
|
||||
_hwThreadsCount = cpuDetectHWThreadsCount();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CpuInfo - GetHost]
|
||||
// ============================================================================
|
||||
|
||||
struct HostCpuInfo : public CpuInfo {
|
||||
ASMJIT_INLINE HostCpuInfo() noexcept : CpuInfo() { detect(); }
|
||||
};
|
||||
|
||||
const CpuInfo& CpuInfo::getHost() noexcept {
|
||||
static HostCpuInfo host;
|
||||
return host;
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
|
@ -1,373 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_CPUINFO_H
|
||||
#define _ASMJIT_BASE_CPUINFO_H
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/arch.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! \addtogroup asmjit_base
|
||||
//! \{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CpuFeatures]
|
||||
// ============================================================================
|
||||
|
||||
class CpuFeatures {
|
||||
public:
|
||||
typedef uintptr_t BitWord;
|
||||
|
||||
enum {
|
||||
kMaxFeatures = 128,
|
||||
kBitWordSize = static_cast<int>(sizeof(BitWord)) * 8,
|
||||
kNumBitWords = kMaxFeatures / kBitWordSize
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE CpuFeatures() noexcept { reset(); }
|
||||
ASMJIT_INLINE CpuFeatures(const CpuFeatures& other) noexcept { init(other); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Init / Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE void init(const CpuFeatures& other) noexcept { ::memcpy(this, &other, sizeof(*this)); }
|
||||
ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Ops]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get all features as `BitWord` array.
|
||||
ASMJIT_INLINE BitWord* getBits() noexcept { return _bits; }
|
||||
//! Get all features as `BitWord` array (const).
|
||||
ASMJIT_INLINE const BitWord* getBits() const noexcept { return _bits; }
|
||||
|
||||
//! Get if feature `feature` is present.
|
||||
ASMJIT_INLINE bool has(uint32_t feature) const noexcept {
|
||||
ASMJIT_ASSERT(feature < kMaxFeatures);
|
||||
|
||||
uint32_t idx = feature / kBitWordSize;
|
||||
uint32_t bit = feature % kBitWordSize;
|
||||
|
||||
return static_cast<bool>((_bits[idx] >> bit) & 0x1);
|
||||
}
|
||||
|
||||
//! Get if all features as defined by `other` are present.
|
||||
ASMJIT_INLINE bool hasAll(const CpuFeatures& other) const noexcept {
|
||||
for (uint32_t i = 0; i < kNumBitWords; i++)
|
||||
if ((_bits[i] & other._bits[i]) != other._bits[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Add a CPU `feature`.
|
||||
ASMJIT_INLINE CpuFeatures& add(uint32_t feature) noexcept {
|
||||
ASMJIT_ASSERT(feature < kMaxFeatures);
|
||||
|
||||
uint32_t idx = feature / kBitWordSize;
|
||||
uint32_t bit = feature % kBitWordSize;
|
||||
|
||||
_bits[idx] |= static_cast<BitWord>(1) << bit;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Remove a CPU `feature`.
|
||||
ASMJIT_INLINE CpuFeatures& remove(uint32_t feature) noexcept {
|
||||
ASMJIT_ASSERT(feature < kMaxFeatures);
|
||||
|
||||
uint32_t idx = feature / kBitWordSize;
|
||||
uint32_t bit = feature % kBitWordSize;
|
||||
|
||||
_bits[idx] &= ~(static_cast<BitWord>(1) << bit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
BitWord _bits[kNumBitWords];
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CpuInfo]
|
||||
// ============================================================================
|
||||
|
||||
//! CPU information.
|
||||
class CpuInfo {
|
||||
public:
|
||||
//! CPU vendor ID.
|
||||
ASMJIT_ENUM(Vendor) {
|
||||
kVendorNone = 0, //!< Generic or unknown.
|
||||
kVendorIntel = 1, //!< Intel vendor.
|
||||
kVendorAMD = 2, //!< AMD vendor.
|
||||
kVendorVIA = 3 //!< VIA vendor.
|
||||
};
|
||||
|
||||
//! ARM/ARM64 CPU features.
|
||||
ASMJIT_ENUM(ArmFeatures) {
|
||||
kArmFeatureV6 = 1, //!< ARMv6 instruction set.
|
||||
kArmFeatureV7, //!< ARMv7 instruction set.
|
||||
kArmFeatureV8, //!< ARMv8 instruction set.
|
||||
kArmFeatureTHUMB, //!< CPU provides THUMB v1 instruction set (THUMB mode).
|
||||
kArmFeatureTHUMB2, //!< CPU provides THUMB v2 instruction set (THUMB mode).
|
||||
kArmFeatureVFPv2, //!< CPU provides VFPv2 instruction set.
|
||||
kArmFeatureVFPv3, //!< CPU provides VFPv3 instruction set.
|
||||
kArmFeatureVFPv4, //!< CPU provides VFPv4 instruction set.
|
||||
kArmFeatureVFP_D32, //!< CPU provides 32 VFP-D (64-bit) registers.
|
||||
kArmFeatureEDSP, //!< CPU provides EDSP extensions.
|
||||
kArmFeatureASIMD, //!< CPU provides 'Advanced SIMD'.
|
||||
kArmFeatureIDIVA, //!< CPU provides hardware SDIV and UDIV (ARM mode).
|
||||
kArmFeatureIDIVT, //!< CPU provides hardware SDIV and UDIV (THUMB mode).
|
||||
kArmFeatureAES, //!< CPU provides AES instructions (ARM64 only).
|
||||
kArmFeatureCRC32, //!< CPU provides CRC32 instructions.
|
||||
kArmFeaturePMULL, //!< CPU provides PMULL instructions (ARM64 only).
|
||||
kArmFeatureSHA1, //!< CPU provides SHA1 instructions.
|
||||
kArmFeatureSHA256, //!< CPU provides SHA256 instructions.
|
||||
kArmFeatureAtomics64, //!< CPU provides 64-bit load/store atomics (ARM64 only).
|
||||
|
||||
kArmFeaturesCount //!< Count of ARM/ARM64 CPU features.
|
||||
};
|
||||
|
||||
//! X86/X64 CPU features.
|
||||
ASMJIT_ENUM(X86Features) {
|
||||
kX86FeatureI486 = 1, //!< CPU is at least I486.
|
||||
kX86FeatureNX, //!< CPU has Not-Execute-Bit.
|
||||
kX86FeatureMT, //!< CPU has multi-threading.
|
||||
kX86FeatureALTMOVCR8, //!< CPU supports `LOCK MOV CR8` (AMD CPUs).
|
||||
kX86FeatureCMOV, //!< CPU has CMOV.
|
||||
kX86FeatureCMPXCHG8B, //!< CPU has CMPXCHG8B.
|
||||
kX86FeatureCMPXCHG16B, //!< CPU has CMPXCHG16B (x64).
|
||||
kX86FeatureMSR, //!< CPU has RDMSR/WRMSR.
|
||||
kX86FeatureRDTSC, //!< CPU has RDTSC.
|
||||
kX86FeatureRDTSCP, //!< CPU has RDTSCP.
|
||||
kX86FeatureCLFLUSH, //!< CPU has CLFUSH.
|
||||
kX86FeatureCLFLUSHOPT, //!< CPU has CLFUSHOPT.
|
||||
kX86FeatureCLWB, //!< CPU has CLWB.
|
||||
kX86FeatureCLZERO, //!< CPU has CLZERO.
|
||||
kX86FeaturePCOMMIT, //!< CPU has PCOMMIT.
|
||||
kX86FeaturePREFETCHW, //!< CPU has PREFETCHW.
|
||||
kX86FeaturePREFETCHWT1, //!< CPU has PREFETCHWT1.
|
||||
kX86FeatureLAHFSAHF, //!< CPU has LAHF/SAHF.
|
||||
kX86FeatureFXSR, //!< CPU has FXSAVE/FXRSTOR.
|
||||
kX86FeatureFXSROPT, //!< CPU has FXSAVE/FXRSTOR (optimized).
|
||||
kX86FeatureMMX, //!< CPU has MMX.
|
||||
kX86FeatureMMX2, //!< CPU has extended MMX.
|
||||
kX86Feature3DNOW, //!< CPU has 3DNOW.
|
||||
kX86Feature3DNOW2, //!< CPU has 3DNOW2 (enhanced).
|
||||
kX86FeatureGEODE, //!< CPU has GEODE extensions (few additions to 3DNOW).
|
||||
kX86FeatureSSE, //!< CPU has SSE.
|
||||
kX86FeatureSSE2, //!< CPU has SSE2.
|
||||
kX86FeatureSSE3, //!< CPU has SSE3.
|
||||
kX86FeatureSSSE3, //!< CPU has SSSE3.
|
||||
kX86FeatureSSE4A, //!< CPU has SSE4.A.
|
||||
kX86FeatureSSE4_1, //!< CPU has SSE4.1.
|
||||
kX86FeatureSSE4_2, //!< CPU has SSE4.2.
|
||||
kX86FeatureMSSE, //!< CPU has Misaligned SSE (MSSE).
|
||||
kX86FeatureMONITOR, //!< CPU has MONITOR and MWAIT.
|
||||
kX86FeatureMOVBE, //!< CPU has MOVBE.
|
||||
kX86FeaturePOPCNT, //!< CPU has POPCNT.
|
||||
kX86FeatureLZCNT, //!< CPU has LZCNT.
|
||||
kX86FeatureAESNI, //!< CPU has AESNI.
|
||||
kX86FeaturePCLMULQDQ, //!< CPU has PCLMULQDQ.
|
||||
kX86FeatureRDRAND, //!< CPU has RDRAND.
|
||||
kX86FeatureRDSEED, //!< CPU has RDSEED.
|
||||
kX86FeatureSMAP, //!< CPU has SMAP (supervisor-mode access prevention).
|
||||
kX86FeatureSMEP, //!< CPU has SMEP (supervisor-mode execution prevention).
|
||||
kX86FeatureSHA, //!< CPU has SHA-1 and SHA-256.
|
||||
kX86FeatureXSAVE, //!< CPU has XSAVE support (XSAVE/XRSTOR, XSETBV/XGETBV, and XCR).
|
||||
kX86FeatureXSAVEC, //!< CPU has XSAVEC support (XSAVEC).
|
||||
kX86FeatureXSAVES, //!< CPU has XSAVES support (XSAVES/XRSTORS).
|
||||
kX86FeatureXSAVEOPT, //!< CPU has XSAVEOPT support (XSAVEOPT/XSAVEOPT64).
|
||||
kX86FeatureOSXSAVE, //!< CPU has XSAVE enabled by OS.
|
||||
kX86FeatureAVX, //!< CPU has AVX.
|
||||
kX86FeatureAVX2, //!< CPU has AVX2.
|
||||
kX86FeatureF16C, //!< CPU has F16C.
|
||||
kX86FeatureFMA, //!< CPU has FMA.
|
||||
kX86FeatureFMA4, //!< CPU has FMA4.
|
||||
kX86FeatureXOP, //!< CPU has XOP.
|
||||
kX86FeatureBMI, //!< CPU has BMI (bit manipulation instructions #1).
|
||||
kX86FeatureBMI2, //!< CPU has BMI2 (bit manipulation instructions #2).
|
||||
kX86FeatureADX, //!< CPU has ADX (multi-precision add-carry instruction extensions).
|
||||
kX86FeatureTBM, //!< CPU has TBM (trailing bit manipulation).
|
||||
kX86FeatureMPX, //!< CPU has MPX (memory protection extensions).
|
||||
kX86FeatureHLE, //!< CPU has HLE.
|
||||
kX86FeatureRTM, //!< CPU has RTM.
|
||||
kX86FeatureTSX, //!< CPU has TSX.
|
||||
kX86FeatureERMS, //!< CPU has ERMS (enhanced REP MOVSB/STOSB).
|
||||
kX86FeatureFSGSBASE, //!< CPU has FSGSBASE.
|
||||
kX86FeatureAVX512_F, //!< CPU has AVX512-F (foundation).
|
||||
kX86FeatureAVX512_CDI, //!< CPU has AVX512-CDI (conflict detection).
|
||||
kX86FeatureAVX512_PFI, //!< CPU has AVX512-PFI (prefetch instructions).
|
||||
kX86FeatureAVX512_ERI, //!< CPU has AVX512-ERI (exponential and reciprocal).
|
||||
kX86FeatureAVX512_DQ, //!< CPU has AVX512-DQ (DWORD/QWORD).
|
||||
kX86FeatureAVX512_BW, //!< CPU has AVX512-BW (BYTE/WORD).
|
||||
kX86FeatureAVX512_VL, //!< CPU has AVX512-VL (vector length extensions).
|
||||
kX86FeatureAVX512_IFMA, //!< CPU has AVX512-IFMA (integer fused-multiply-add using 52-bit precision).
|
||||
kX86FeatureAVX512_VBMI, //!< CPU has AVX512-VBMI (vector byte manipulation).
|
||||
kX86FeatureAVX512_VPOPCNTDQ, //!< CPU has AVX512-VPOPCNTDQ (VPOPCNT[D|Q] instructions).
|
||||
kX86FeatureAVX512_4VNNIW, //!< CPU has AVX512-VNNIW (vector NN instructions word variable precision).
|
||||
kX86FeatureAVX512_4FMAPS, //!< CPU has AVX512-FMAPS (FMA packed single).
|
||||
|
||||
kX86FeaturesCount //!< Count of X86/X64 CPU features.
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [ArmInfo]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
struct ArmData {
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [X86Info]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
struct X86Data {
|
||||
uint32_t _processorType; //!< Processor type.
|
||||
uint32_t _brandIndex; //!< Brand index.
|
||||
uint32_t _flushCacheLineSize; //!< Flush cache line size (in bytes).
|
||||
uint32_t _maxLogicalProcessors; //!< Maximum number of addressable IDs for logical processors.
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE CpuInfo() noexcept { reset(); }
|
||||
ASMJIT_INLINE CpuInfo(const CpuInfo& other) noexcept { init(other); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Init / Reset]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Initialize CpuInfo to the given architecture, see \ArchInfo.
|
||||
ASMJIT_INLINE void initArch(uint32_t archType, uint32_t archMode = 0) noexcept {
|
||||
_archInfo.init(archType, archMode);
|
||||
}
|
||||
|
||||
ASMJIT_INLINE void init(const CpuInfo& other) noexcept { ::memcpy(this, &other, sizeof(*this)); }
|
||||
ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Detect]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API void detect() noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get generic architecture information.
|
||||
ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _archInfo; }
|
||||
//! Get CPU architecture type, see \ArchInfo::Type.
|
||||
ASMJIT_INLINE uint32_t getArchType() const noexcept { return _archInfo.getType(); }
|
||||
//! Get CPU architecture sub-type, see \ArchInfo::SubType.
|
||||
ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return _archInfo.getSubType(); }
|
||||
|
||||
//! Get CPU vendor ID.
|
||||
ASMJIT_INLINE uint32_t getVendorId() const noexcept { return _vendorId; }
|
||||
//! Get CPU family ID.
|
||||
ASMJIT_INLINE uint32_t getFamily() const noexcept { return _family; }
|
||||
//! Get CPU model ID.
|
||||
ASMJIT_INLINE uint32_t getModel() const noexcept { return _model; }
|
||||
//! Get CPU stepping.
|
||||
ASMJIT_INLINE uint32_t getStepping() const noexcept { return _stepping; }
|
||||
|
||||
//! Get number of hardware threads available.
|
||||
ASMJIT_INLINE uint32_t getHwThreadsCount() const noexcept {
|
||||
return _hwThreadsCount;
|
||||
}
|
||||
|
||||
//! Get all CPU features.
|
||||
ASMJIT_INLINE const CpuFeatures& getFeatures() const noexcept { return _features; }
|
||||
//! Get whether CPU has a `feature`.
|
||||
ASMJIT_INLINE bool hasFeature(uint32_t feature) const noexcept { return _features.has(feature); }
|
||||
//! Add a CPU `feature`.
|
||||
ASMJIT_INLINE CpuInfo& addFeature(uint32_t feature) noexcept { _features.add(feature); return *this; }
|
||||
|
||||
//! Get CPU vendor string.
|
||||
ASMJIT_INLINE const char* getVendorString() const noexcept { return _vendorString; }
|
||||
//! Get CPU brand string.
|
||||
ASMJIT_INLINE const char* getBrandString() const noexcept { return _brandString; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors - ARM]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors - X86]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get processor type.
|
||||
ASMJIT_INLINE uint32_t getX86ProcessorType() const noexcept {
|
||||
return _x86Data._processorType;
|
||||
}
|
||||
|
||||
//! Get brand index.
|
||||
ASMJIT_INLINE uint32_t getX86BrandIndex() const noexcept {
|
||||
return _x86Data._brandIndex;
|
||||
}
|
||||
|
||||
//! Get flush cache line size.
|
||||
ASMJIT_INLINE uint32_t getX86FlushCacheLineSize() const noexcept {
|
||||
return _x86Data._flushCacheLineSize;
|
||||
}
|
||||
|
||||
//! Get maximum logical processors count.
|
||||
ASMJIT_INLINE uint32_t getX86MaxLogicalProcessors() const noexcept {
|
||||
return _x86Data._maxLogicalProcessors;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Statics]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get the host CPU information.
|
||||
ASMJIT_API static const CpuInfo& getHost() noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ArchInfo _archInfo; //!< CPU architecture information.
|
||||
uint32_t _vendorId; //!< CPU vendor id, see \ref Vendor.
|
||||
uint32_t _family; //!< CPU family ID.
|
||||
uint32_t _model; //!< CPU model ID.
|
||||
uint32_t _stepping; //!< CPU stepping.
|
||||
uint32_t _hwThreadsCount; //!< Number of hardware threads.
|
||||
CpuFeatures _features; //!< CPU features.
|
||||
char _vendorString[16]; //!< CPU vendor string.
|
||||
char _brandString[64]; //!< CPU brand string.
|
||||
|
||||
// Architecture specific data.
|
||||
union {
|
||||
ArmData _armData;
|
||||
X86Data _x86Data;
|
||||
};
|
||||
};
|
||||
|
||||
//! \}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_CPUINFO_H
|
|
@ -1,186 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/arch.h"
|
||||
#include "../base/func.h"
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
#include "../x86/x86internal_p.h"
|
||||
#include "../x86/x86operand.h"
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
#include "../arm/arminternal_p.h"
|
||||
#include "../arm/armoperand.h"
|
||||
#endif // ASMJIT_BUILD_ARM
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::CallConv - Init / Reset]
|
||||
// ============================================================================
|
||||
|
||||
ASMJIT_FAVOR_SIZE Error CallConv::init(uint32_t ccId) noexcept {
|
||||
reset();
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
if (CallConv::isX86Family(ccId))
|
||||
return X86Internal::initCallConv(*this, ccId);
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
if (CallConv::isArmFamily(ccId))
|
||||
return ArmInternal::initCallConv(*this, ccId);
|
||||
#endif // ASMJIT_BUILD_ARM
|
||||
|
||||
return DebugUtils::errored(kErrorInvalidArgument);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FuncDetail - Init / Reset]
|
||||
// ============================================================================
|
||||
|
||||
ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& sign) {
|
||||
uint32_t ccId = sign.getCallConv();
|
||||
CallConv& cc = _callConv;
|
||||
|
||||
uint32_t argCount = sign.getArgCount();
|
||||
if (ASMJIT_UNLIKELY(argCount > kFuncArgCount))
|
||||
return DebugUtils::errored(kErrorInvalidArgument);
|
||||
|
||||
ASMJIT_PROPAGATE(cc.init(ccId));
|
||||
|
||||
uint32_t gpSize = (cc.getArchType() == ArchInfo::kTypeX86) ? 4 : 8;
|
||||
uint32_t deabstractDelta = TypeId::deabstractDeltaOfSize(gpSize);
|
||||
|
||||
const uint8_t* args = sign.getArgs();
|
||||
for (uint32_t i = 0; i < argCount; i++) {
|
||||
Value& arg = _args[i];
|
||||
arg.initTypeId(TypeId::deabstract(args[i], deabstractDelta));
|
||||
}
|
||||
_argCount = static_cast<uint8_t>(argCount);
|
||||
|
||||
uint32_t ret = sign.getRet();
|
||||
if (ret != TypeId::kVoid) {
|
||||
_rets[0].initTypeId(TypeId::deabstract(ret, deabstractDelta));
|
||||
_retCount = 1;
|
||||
}
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
if (CallConv::isX86Family(ccId))
|
||||
return X86Internal::initFuncDetail(*this, sign, gpSize);
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
if (CallConv::isArmFamily(ccId))
|
||||
return ArmInternal::initFuncDetail(*this, sign, gpSize);
|
||||
#endif // ASMJIT_BUILD_ARM
|
||||
|
||||
// We should never bubble here as if `cc.init()` succeeded then there has to
|
||||
// be an implementation for the current architecture. However, stay safe.
|
||||
return DebugUtils::errored(kErrorInvalidArgument);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FuncFrameLayout - Init / Reset]
|
||||
// ============================================================================
|
||||
|
||||
ASMJIT_FAVOR_SIZE Error FuncFrameLayout::init(const FuncDetail& func, const FuncFrameInfo& ffi) noexcept {
|
||||
uint32_t ccId = func.getCallConv().getId();
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
if (CallConv::isX86Family(ccId))
|
||||
return X86Internal::initFrameLayout(*this, func, ffi);
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
if (CallConv::isArmFamily(ccId))
|
||||
return ArmInternal::initFrameLayout(*this, func, ffi);
|
||||
#endif // ASMJIT_BUILD_ARM
|
||||
|
||||
return DebugUtils::errored(kErrorInvalidArgument);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FuncArgsMapper]
|
||||
// ============================================================================
|
||||
|
||||
ASMJIT_FAVOR_SIZE Error FuncArgsMapper::updateFrameInfo(FuncFrameInfo& ffi) const noexcept {
|
||||
const FuncDetail* func = getFuncDetail();
|
||||
if (!func) return DebugUtils::errored(kErrorInvalidState);
|
||||
|
||||
uint32_t ccId = func->getCallConv().getId();
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
if (CallConv::isX86Family(ccId))
|
||||
return X86Internal::argsToFrameInfo(*this, ffi);
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
if (CallConv::isArmFamily(ccId))
|
||||
return ArmInternal::argsToFrameInfo(*this, ffi);
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
return DebugUtils::errored(kErrorInvalidArch);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FuncUtils]
|
||||
// ============================================================================
|
||||
|
||||
ASMJIT_FAVOR_SIZE Error FuncUtils::emitProlog(CodeEmitter* emitter, const FuncFrameLayout& layout) {
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
if (emitter->getArchInfo().isX86Family())
|
||||
return X86Internal::emitProlog(static_cast<X86Emitter*>(emitter), layout);
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
if (emitter->getArchInfo().isArmFamily())
|
||||
return ArmInternal::emitProlog(static_cast<ArmEmitter*>(emitter), layout);
|
||||
#endif // ASMJIT_BUILD_ARM
|
||||
|
||||
return DebugUtils::errored(kErrorInvalidArch);
|
||||
}
|
||||
|
||||
ASMJIT_FAVOR_SIZE Error FuncUtils::emitEpilog(CodeEmitter* emitter, const FuncFrameLayout& layout) {
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
if (emitter->getArchInfo().isX86Family())
|
||||
return X86Internal::emitEpilog(static_cast<X86Emitter*>(emitter), layout);
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
if (emitter->getArchInfo().isArmFamily())
|
||||
return ArmInternal::emitEpilog(static_cast<ArmEmitter*>(emitter), layout);
|
||||
#endif // ASMJIT_BUILD_ARM
|
||||
|
||||
return DebugUtils::errored(kErrorInvalidArch);
|
||||
}
|
||||
|
||||
ASMJIT_FAVOR_SIZE Error FuncUtils::allocArgs(CodeEmitter* emitter, const FuncFrameLayout& layout, const FuncArgsMapper& args) {
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
if (emitter->getArchInfo().isX86Family())
|
||||
return X86Internal::allocArgs(static_cast<X86Emitter*>(emitter), layout, args);
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
if (emitter->getArchInfo().isArmFamily())
|
||||
return ArmInternal::allocArgs(static_cast<ArmEmitter*>(emitter), layout, args);
|
||||
#endif // ASMJIT_BUILD_ARM
|
||||
|
||||
return DebugUtils::errored(kErrorInvalidArch);
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
File diff suppressed because it is too large
Load Diff
|
@ -1,118 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/globals.h"
|
||||
#include "../base/utils.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::DebugUtils]
|
||||
// ============================================================================
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_TEXT)
|
||||
static const char errorMessages[] =
|
||||
"Ok\0"
|
||||
"No heap memory\0"
|
||||
"No virtual memory\0"
|
||||
"Invalid argument\0"
|
||||
"Invalid state\0"
|
||||
"Invalid architecture\0"
|
||||
"Not initialized\0"
|
||||
"Already initialized\0"
|
||||
"Feature not enabled\0"
|
||||
"Slot occupied\0"
|
||||
"No code generated\0"
|
||||
"Code too large\0"
|
||||
"Invalid label\0"
|
||||
"Label index overflow\0"
|
||||
"Label already bound\0"
|
||||
"Label already defined\0"
|
||||
"Label name too long\0"
|
||||
"Invalid label name\0"
|
||||
"Invalid parent label\0"
|
||||
"Non-local label can't have parent\0"
|
||||
"Relocation index overflow\0"
|
||||
"Invalid relocation entry\0"
|
||||
"Invalid instruction\0"
|
||||
"Invalid register type\0"
|
||||
"Invalid register kind\0"
|
||||
"Invalid register's physical id\0"
|
||||
"Invalid register's virtual id\0"
|
||||
"Invalid prefix combination\0"
|
||||
"Invalid lock prefix\0"
|
||||
"Invalid xacquire prefix\0"
|
||||
"Invalid xrelease prefix\0"
|
||||
"Invalid rep prefix\0"
|
||||
"Invalid rex prefix\0"
|
||||
"Invalid mask, expected {k}\0"
|
||||
"Invalid use of {k}\0"
|
||||
"Invalid use of {k}{z}\0"
|
||||
"Invalid broadcast {1tox}\0"
|
||||
"Invalid {er} or {sae} option\0"
|
||||
"Invalid address\0"
|
||||
"Invalid address index\0"
|
||||
"Invalid address scale\0"
|
||||
"Invalid use of 64-bit address\0"
|
||||
"Invalid displacement\0"
|
||||
"Invalid segment\0"
|
||||
"Invalid immediate value\0"
|
||||
"Invalid operand size\0"
|
||||
"Ambiguous operand size\0"
|
||||
"Operand size mismatch\0"
|
||||
"Invalid type-info\0"
|
||||
"Invalid use of a low 8-bit GPB register\0"
|
||||
"Invalid use of a 64-bit GPQ register in 32-bit mode\0"
|
||||
"Invalid use of an 80-bit float\0"
|
||||
"Not consecutive registers\0"
|
||||
"No more physical registers\0"
|
||||
"Overlapped registers\0"
|
||||
"Overlapping register and arguments base-address register\0"
|
||||
"Unknown error\0";
|
||||
#endif // ASMJIT_DISABLE_TEXT
|
||||
|
||||
ASMJIT_FAVOR_SIZE const char* DebugUtils::errorAsString(Error err) noexcept {
|
||||
#if !defined(ASMJIT_DISABLE_TEXT)
|
||||
return Utils::findPackedString(errorMessages, std::min<Error>(err, kErrorCount));
|
||||
#else
|
||||
static const char noMessage[] = "";
|
||||
return noMessage;
|
||||
#endif
|
||||
}
|
||||
|
||||
ASMJIT_FAVOR_SIZE void DebugUtils::debugOutput(const char* str) noexcept {
|
||||
#if ASMJIT_OS_WINDOWS
|
||||
::OutputDebugStringA(str);
|
||||
#else
|
||||
::fputs(str, stderr);
|
||||
#endif
|
||||
}
|
||||
|
||||
ASMJIT_FAVOR_SIZE void DebugUtils::assertionFailed(const char* file, int line, const char* msg) noexcept {
|
||||
char str[1024];
|
||||
|
||||
snprintf(str, 1024,
|
||||
"[asmjit] Assertion failed at %s (line %d):\n"
|
||||
"[asmjit] %s\n", file, line, msg);
|
||||
|
||||
// Support buggy `snprintf` implementations.
|
||||
str[1023] = '\0';
|
||||
|
||||
debugOutput(str);
|
||||
::abort();
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
|
@ -1,341 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_GLOBALS_H
|
||||
#define _ASMJIT_BASE_GLOBALS_H
|
||||
|
||||
// [Dependencies]
|
||||
#include "../asmjit_build.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! \addtogroup asmjit_base
|
||||
//! \{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Globals]
|
||||
// ============================================================================
|
||||
|
||||
enum { kInvalidValue = 0xFFFFFFFFU };
|
||||
|
||||
//! AsmJit globals.
|
||||
namespace Globals {
|
||||
|
||||
//! Invalid index
|
||||
//!
|
||||
//! Invalid index is the last possible index that is never used in practice. In
|
||||
//! AsmJit it is used exclusively with strings to indicate the the length of the
|
||||
//! string is not known and has to be determined.
|
||||
static const size_t kInvalidIndex = ~static_cast<size_t>(0);
|
||||
|
||||
//! Invalid base address.
|
||||
static const uint64_t kNoBaseAddress = ~static_cast<uint64_t>(0);
|
||||
|
||||
//! Global definitions.
|
||||
ASMJIT_ENUM(Defs) {
|
||||
//! Invalid register id.
|
||||
kInvalidRegId = 0xFF,
|
||||
|
||||
//! Host memory allocator overhead.
|
||||
kAllocOverhead = static_cast<int>(sizeof(intptr_t) * 4),
|
||||
//! Aggressive growing strategy threshold.
|
||||
kAllocThreshold = 8192 * 1024
|
||||
};
|
||||
|
||||
ASMJIT_ENUM(Limits) {
|
||||
//! Count of register kinds that are important to Function API and CodeCompiler.
|
||||
//! The target architecture can define more register kinds for special registers,
|
||||
//! but these will never map to virtual registers and will never be used to pass
|
||||
//! and return function arguments and function return values, respectively.
|
||||
kMaxVRegKinds = 4,
|
||||
|
||||
//! Maximum number of physical registers of all kinds of all supported
|
||||
//! architectures. This is only important for \ref CodeCompiler and its
|
||||
//! \ref RAPass (register allocator pass).
|
||||
//!
|
||||
//! NOTE: The distribution of these registers is architecture specific.
|
||||
kMaxPhysRegs = 64,
|
||||
|
||||
//! Maximum alignment.
|
||||
kMaxAlignment = 64,
|
||||
|
||||
//! Maximum label or symbol length in bytes (take into consideration that a
|
||||
//! single UTF-8 character can take more than single byte to encode it).
|
||||
kMaxLabelLength = 2048
|
||||
};
|
||||
|
||||
} // Globals namespace
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Error]
|
||||
// ============================================================================
|
||||
|
||||
//! AsmJit error type (uint32_t).
|
||||
typedef uint32_t Error;
|
||||
|
||||
//! AsmJit error codes.
|
||||
ASMJIT_ENUM(ErrorCode) {
|
||||
//! No error (success).
|
||||
//!
|
||||
//! This is default state and state you want.
|
||||
kErrorOk = 0,
|
||||
|
||||
//! Heap memory allocation failed.
|
||||
kErrorNoHeapMemory,
|
||||
|
||||
//! Virtual memory allocation failed.
|
||||
kErrorNoVirtualMemory,
|
||||
|
||||
//! Invalid argument.
|
||||
kErrorInvalidArgument,
|
||||
|
||||
//! Invalid state.
|
||||
//!
|
||||
//! If this error is returned it means that either you are doing something
|
||||
//! wrong or AsmJit caught itself by doing something wrong. This error should
|
||||
//! not be underestimated.
|
||||
kErrorInvalidState,
|
||||
|
||||
//! Invalid or incompatible architecture.
|
||||
kErrorInvalidArch,
|
||||
|
||||
//! The object is not initialized.
|
||||
kErrorNotInitialized,
|
||||
//! The object is already initialized.
|
||||
kErrorAlreadyInitialized,
|
||||
|
||||
//! Built-in feature was disabled at compile time and it's not available.
|
||||
kErrorFeatureNotEnabled,
|
||||
|
||||
//! CodeHolder can't have attached more than one \ref Assembler at a time.
|
||||
kErrorSlotOccupied,
|
||||
|
||||
//! No code generated.
|
||||
//!
|
||||
//! Returned by runtime if the \ref CodeHolder contains no code.
|
||||
kErrorNoCodeGenerated,
|
||||
//! Code generated is larger than allowed.
|
||||
kErrorCodeTooLarge,
|
||||
|
||||
//! Attempt to use uninitialized label.
|
||||
kErrorInvalidLabel,
|
||||
//! Label index overflow - a single `Assembler` instance can hold more than
|
||||
//! 2 billion labels (2147483391 to be exact). If there is an attempt to
|
||||
//! create more labels this error is returned.
|
||||
kErrorLabelIndexOverflow,
|
||||
//! Label is already bound.
|
||||
kErrorLabelAlreadyBound,
|
||||
//! Label is already defined (named labels).
|
||||
kErrorLabelAlreadyDefined,
|
||||
//! Label name is too long.
|
||||
kErrorLabelNameTooLong,
|
||||
//! Label must always be local if it's anonymous (without a name).
|
||||
kErrorInvalidLabelName,
|
||||
//! Parent id passed to `CodeHolder::newNamedLabelId()` was invalid.
|
||||
kErrorInvalidParentLabel,
|
||||
//! Parent id specified for a non-local (global) label.
|
||||
kErrorNonLocalLabelCantHaveParent,
|
||||
|
||||
//! Relocation index overflow.
|
||||
kErrorRelocIndexOverflow,
|
||||
//! Invalid relocation entry.
|
||||
kErrorInvalidRelocEntry,
|
||||
|
||||
//! Invalid instruction.
|
||||
kErrorInvalidInstruction,
|
||||
//! Invalid register type.
|
||||
kErrorInvalidRegType,
|
||||
//! Invalid register kind.
|
||||
kErrorInvalidRegKind,
|
||||
//! Invalid register's physical id.
|
||||
kErrorInvalidPhysId,
|
||||
//! Invalid register's virtual id.
|
||||
kErrorInvalidVirtId,
|
||||
//! Invalid prefix combination.
|
||||
kErrorInvalidPrefixCombination,
|
||||
//! Invalid LOCK prefix.
|
||||
kErrorInvalidLockPrefix,
|
||||
//! Invalid XACQUIRE prefix.
|
||||
kErrorInvalidXAcquirePrefix,
|
||||
//! Invalid XACQUIRE prefix.
|
||||
kErrorInvalidXReleasePrefix,
|
||||
//! Invalid REP prefix.
|
||||
kErrorInvalidRepPrefix,
|
||||
//! Invalid REX prefix.
|
||||
kErrorInvalidRexPrefix,
|
||||
//! Invalid mask register (not 'k').
|
||||
kErrorInvalidKMaskReg,
|
||||
//! Invalid {k} use (not supported by the instruction).
|
||||
kErrorInvalidKMaskUse,
|
||||
//! Invalid {k}{z} use (not supported by the instruction).
|
||||
kErrorInvalidKZeroUse,
|
||||
//! Invalid broadcast - Currently only related to invalid use of AVX-512 {1tox}.
|
||||
kErrorInvalidBroadcast,
|
||||
//! Invalid 'embedded-rounding' {er} or 'suppress-all-exceptions' {sae} (AVX-512).
|
||||
kErrorInvalidEROrSAE,
|
||||
//! Invalid address used (not encodable).
|
||||
kErrorInvalidAddress,
|
||||
//! Invalid index register used in memory address (not encodable).
|
||||
kErrorInvalidAddressIndex,
|
||||
//! Invalid address scale (not encodable).
|
||||
kErrorInvalidAddressScale,
|
||||
//! Invalid use of 64-bit address.
|
||||
kErrorInvalidAddress64Bit,
|
||||
//! Invalid displacement (not encodable).
|
||||
kErrorInvalidDisplacement,
|
||||
//! Invalid segment (X86).
|
||||
kErrorInvalidSegment,
|
||||
|
||||
//! Invalid immediate (out of bounds on X86 and invalid pattern on ARM).
|
||||
kErrorInvalidImmediate,
|
||||
|
||||
//! Invalid operand size.
|
||||
kErrorInvalidOperandSize,
|
||||
//! Ambiguous operand size (memory has zero size while it's required to determine the operation type.
|
||||
kErrorAmbiguousOperandSize,
|
||||
//! Mismatching operand size (size of multiple operands doesn't match the operation size).
|
||||
kErrorOperandSizeMismatch,
|
||||
|
||||
//! Invalid TypeId.
|
||||
kErrorInvalidTypeId,
|
||||
//! Invalid use of a 8-bit GPB-HIGH register.
|
||||
kErrorInvalidUseOfGpbHi,
|
||||
//! Invalid use of a 64-bit GPQ register in 32-bit mode.
|
||||
kErrorInvalidUseOfGpq,
|
||||
//! Invalid use of an 80-bit float (TypeId::kF80).
|
||||
kErrorInvalidUseOfF80,
|
||||
//! Some registers in the instruction muse be consecutive (some ARM and AVX512 neural-net instructions).
|
||||
kErrorNotConsecutiveRegs,
|
||||
|
||||
//! AsmJit requires a physical register, but no one is available.
|
||||
kErrorNoMorePhysRegs,
|
||||
//! A variable has been assigned more than once to a function argument (CodeCompiler).
|
||||
kErrorOverlappedRegs,
|
||||
//! Invalid register to hold stack arguments offset.
|
||||
kErrorOverlappingStackRegWithRegArg,
|
||||
|
||||
//! Count of AsmJit error codes.
|
||||
kErrorCount
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Internal]
|
||||
// ============================================================================
|
||||
|
||||
namespace Internal {
|
||||
|
||||
#if defined(ASMJIT_CUSTOM_ALLOC) && \
|
||||
defined(ASMJIT_CUSTOM_REALLOC) && \
|
||||
defined(ASMJIT_CUSTOM_FREE)
|
||||
static ASMJIT_INLINE void* allocMemory(size_t size) noexcept { return ASMJIT_CUSTOM_ALLOC(size); }
|
||||
static ASMJIT_INLINE void* reallocMemory(void* p, size_t size) noexcept { return ASMJIT_CUSTOM_REALLOC(p, size); }
|
||||
static ASMJIT_INLINE void releaseMemory(void* p) noexcept { ASMJIT_CUSTOM_FREE(p); }
|
||||
#elif !defined(ASMJIT_CUSTOM_ALLOC) && \
|
||||
!defined(ASMJIT_CUSTOM_REALLOC) && \
|
||||
!defined(ASMJIT_CUSTOM_FREE)
|
||||
static ASMJIT_INLINE void* allocMemory(size_t size) noexcept { return ::malloc(size); }
|
||||
static ASMJIT_INLINE void* reallocMemory(void* p, size_t size) noexcept { return ::realloc(p, size); }
|
||||
static ASMJIT_INLINE void releaseMemory(void* p) noexcept { ::free(p); }
|
||||
#else
|
||||
# error "[asmjit] You must provide either none or all of ASMJIT_CUSTOM_[ALLOC|REALLOC|FREE]"
|
||||
#endif
|
||||
|
||||
//! Cast designed to cast between function and void* pointers.
|
||||
template<typename Dst, typename Src>
|
||||
static ASMJIT_INLINE Dst ptr_cast(Src p) noexcept { return (Dst)p; }
|
||||
|
||||
} // Internal namespace
|
||||
|
||||
template<typename Func>
|
||||
static ASMJIT_INLINE Func ptr_as_func(void* func) noexcept { return Internal::ptr_cast<Func, void*>(func); }
|
||||
|
||||
template<typename Func>
|
||||
static ASMJIT_INLINE void* func_as_ptr(Func func) noexcept { return Internal::ptr_cast<void*, Func>(func); }
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::DebugUtils]
|
||||
// ============================================================================
|
||||
|
||||
namespace DebugUtils {
|
||||
|
||||
//! Returns the error `err` passed.
|
||||
//!
|
||||
//! Provided for debugging purposes. Putting a breakpoint inside `errored` can
|
||||
//! help with tracing the origin of any error reported / returned by AsmJit.
|
||||
static ASMJIT_INLINE Error errored(Error err) noexcept { return err; }
|
||||
|
||||
//! Get a printable version of `asmjit::Error` code.
|
||||
ASMJIT_API const char* errorAsString(Error err) noexcept;
|
||||
|
||||
//! Called to output debugging message(s).
|
||||
ASMJIT_API void debugOutput(const char* str) noexcept;
|
||||
|
||||
//! Called on assertion failure.
|
||||
//!
|
||||
//! \param file Source file name where it happened.
|
||||
//! \param line Line in the source file.
|
||||
//! \param msg Message to display.
|
||||
//!
|
||||
//! If you have problems with assertions put a breakpoint at assertionFailed()
|
||||
//! function (asmjit/base/globals.cpp) and check the call stack to locate the
|
||||
//! failing code.
|
||||
ASMJIT_API void ASMJIT_NORETURN assertionFailed(const char* file, int line, const char* msg) noexcept;
|
||||
|
||||
#if defined(ASMJIT_DEBUG)
|
||||
# define ASMJIT_ASSERT(exp) \
|
||||
do { \
|
||||
if (ASMJIT_LIKELY(exp)) \
|
||||
break; \
|
||||
::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, #exp); \
|
||||
} while (0)
|
||||
# define ASMJIT_NOT_REACHED() \
|
||||
do { \
|
||||
::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, \
|
||||
"ASMJIT_NOT_REACHED has been reached"); \
|
||||
ASMJIT_ASSUME(0); \
|
||||
} while (0)
|
||||
#else
|
||||
# define ASMJIT_ASSERT(exp) ASMJIT_NOP
|
||||
# define ASMJIT_NOT_REACHED() ASMJIT_ASSUME(0)
|
||||
#endif // DEBUG
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! Used by AsmJit to propagate a possible `Error` produced by `...` to the caller.
|
||||
#define ASMJIT_PROPAGATE(...) \
|
||||
do { \
|
||||
::asmjit::Error _err = __VA_ARGS__; \
|
||||
if (ASMJIT_UNLIKELY(_err)) \
|
||||
return _err; \
|
||||
} while (0)
|
||||
|
||||
} // DebugUtils namespace
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Init / NoInit]
|
||||
// ============================================================================
|
||||
|
||||
#if !defined(ASMJIT_DOCGEN)
|
||||
struct _Init {};
|
||||
static const _Init Init = {};
|
||||
|
||||
struct _NoInit {};
|
||||
static const _NoInit NoInit = {};
|
||||
#endif // !ASMJIT_DOCGEN
|
||||
|
||||
//! \}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_GLOBALS_H
|
|
@ -1,77 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Guard]
|
||||
#include "../asmjit_build.h"
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/arch.h"
|
||||
#include "../base/inst.h"
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
# include "../x86/x86instimpl_p.h"
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
# include "../arm/arminstimpl_p.h"
|
||||
#endif // ASMJIT_BUILD_ARM
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Inst - Validate]
|
||||
// ============================================================================
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_VALIDATION)
|
||||
Error Inst::validate(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count) noexcept {
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
if (ArchInfo::isX86Family(archType))
|
||||
return X86InstImpl::validate(archType, detail, operands, count);
|
||||
#endif
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
if (ArchInfo::isArmFamily(archType))
|
||||
return ArmInstImpl::validate(archType, detail, operands, count);
|
||||
#endif
|
||||
|
||||
return DebugUtils::errored(kErrorInvalidArch);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Inst - CheckFeatures]
|
||||
// ============================================================================
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_EXTENSIONS)
|
||||
Error Inst::checkFeatures(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count, CpuFeatures& out) noexcept {
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
if (ArchInfo::isX86Family(archType))
|
||||
return X86InstImpl::checkFeatures(archType, detail, operands, count, out);
|
||||
#endif
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
if (ArchInfo::isArmFamily(archType))
|
||||
return ArmInstImpl::checkFeatures(archType, detail, operands, count, out);
|
||||
#endif
|
||||
|
||||
return DebugUtils::errored(kErrorInvalidArch);
|
||||
}
|
||||
#endif // !defined(ASMJIT_DISABLE_EXTENSIONS)
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // ASMJIT_BUILD_X86
|
|
@ -1,108 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_INST_H
|
||||
#define _ASMJIT_BASE_INST_H
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/cpuinfo.h"
|
||||
#include "../base/operand.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! \addtogroup asmjit_base
|
||||
//! \{
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Inst]
|
||||
// ============================================================================
|
||||
|
||||
//! Definitions and utilities related to instructions used by all architectures.
|
||||
struct Inst {
|
||||
ASMJIT_ENUM(Id) {
|
||||
kIdNone = 0 //!< Invalid or uninitialized instruction id.
|
||||
};
|
||||
|
||||
//! Describes an instruction's jump type, if any.
|
||||
ASMJIT_ENUM(JumpType) {
|
||||
kJumpTypeNone = 0, //!< Instruction doesn't jump (regular instruction).
|
||||
kJumpTypeDirect = 1, //!< Instruction is a unconditional (direct) jump.
|
||||
kJumpTypeConditional = 2, //!< Instruction is a conditional jump.
|
||||
kJumpTypeCall = 3, //!< Instruction is a function call.
|
||||
kJumpTypeReturn = 4 //!< Instruction is a function return.
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Detail]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Instruction id, options, and extraReg packed in a single structure. This
|
||||
//! structure exists to simplify analysis and validation API that requires a
|
||||
//! lot of information about the instruction to be processed.
|
||||
class Detail {
|
||||
public:
|
||||
ASMJIT_INLINE Detail() noexcept
|
||||
: instId(0),
|
||||
options(0),
|
||||
extraReg() {}
|
||||
|
||||
explicit ASMJIT_INLINE Detail(uint32_t instId, uint32_t options = 0) noexcept
|
||||
: instId(instId),
|
||||
options(options),
|
||||
extraReg() {}
|
||||
|
||||
ASMJIT_INLINE Detail(uint32_t instId, uint32_t options, const RegOnly& reg) noexcept
|
||||
: instId(instId),
|
||||
options(options),
|
||||
extraReg(reg) {}
|
||||
|
||||
ASMJIT_INLINE Detail(uint32_t instId, uint32_t options, const Reg& reg) noexcept
|
||||
: instId(instId),
|
||||
options(options) { extraReg.init(reg); }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_INLINE bool hasExtraReg() const noexcept { return extraReg.isValid(); }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
uint32_t instId;
|
||||
uint32_t options;
|
||||
RegOnly extraReg;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [API]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_VALIDATION)
|
||||
//! Validate the given instruction.
|
||||
ASMJIT_API static Error validate(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count) noexcept;
|
||||
#endif // !ASMJIT_DISABLE_VALIDATION
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_EXTENSIONS)
|
||||
//! Check CPU features required to execute the given instruction.
|
||||
ASMJIT_API static Error checkFeatures(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count, CpuFeatures& out) noexcept;
|
||||
#endif // !defined(ASMJIT_DISABLE_EXTENSIONS)
|
||||
};
|
||||
|
||||
//! \}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_INST_H
|
|
@ -1,497 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Guard]
|
||||
#include "../asmjit_build.h"
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/codeholder.h"
|
||||
#include "../base/codeemitter.h"
|
||||
#include "../base/logging.h"
|
||||
#include "../base/utils.h"
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_BUILDER)
|
||||
# include "../base/codebuilder.h"
|
||||
#endif // !ASMJIT_DISABLE_BUILDER
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_COMPILER)
|
||||
# include "../base/codecompiler.h"
|
||||
#else
|
||||
namespace asmjit { class VirtReg; }
|
||||
#endif // !ASMJIT_DISABLE_COMPILER
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
# include "../x86/x86logging_p.h"
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
# include "../arm/armlogging_p.h"
|
||||
#endif // ASMJIT_BUILD_ARM
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Logger - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
Logger::Logger() noexcept {
|
||||
_options = 0;
|
||||
::memset(_indentation, 0, ASMJIT_ARRAY_SIZE(_indentation));
|
||||
}
|
||||
Logger::~Logger() noexcept {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Logger - Logging]
|
||||
// ============================================================================
|
||||
|
||||
Error Logger::logf(const char* fmt, ...) noexcept {
|
||||
Error err;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
err = logv(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
Error Logger::logv(const char* fmt, va_list ap) noexcept {
|
||||
char buf[1024];
|
||||
size_t len = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
|
||||
if (len >= sizeof(buf))
|
||||
len = sizeof(buf) - 1;
|
||||
return log(buf, len);
|
||||
}
|
||||
|
||||
Error Logger::logBinary(const void* data, size_t size) noexcept {
|
||||
static const char prefix[] = ".data ";
|
||||
static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
|
||||
const uint8_t* s = static_cast<const uint8_t*>(data);
|
||||
size_t i = size;
|
||||
|
||||
char buffer[128];
|
||||
::memcpy(buffer, prefix, ASMJIT_ARRAY_SIZE(prefix) - 1);
|
||||
|
||||
while (i) {
|
||||
uint32_t n = static_cast<uint32_t>(std::min<size_t>(i, 16));
|
||||
char* p = buffer + ASMJIT_ARRAY_SIZE(prefix) - 1;
|
||||
|
||||
i -= n;
|
||||
do {
|
||||
uint32_t c = s[0];
|
||||
|
||||
p[0] = hex[c >> 4];
|
||||
p[1] = hex[c & 15];
|
||||
|
||||
p += 2;
|
||||
s += 1;
|
||||
} while (--n);
|
||||
|
||||
*p++ = '\n';
|
||||
ASMJIT_PROPAGATE(log(buffer, (size_t)(p - buffer)));
|
||||
}
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Logger - Indentation]
|
||||
// ============================================================================
|
||||
|
||||
void Logger::setIndentation(const char* indentation) noexcept {
|
||||
::memset(_indentation, 0, ASMJIT_ARRAY_SIZE(_indentation));
|
||||
if (!indentation)
|
||||
return;
|
||||
|
||||
size_t length = Utils::strLen(indentation, ASMJIT_ARRAY_SIZE(_indentation) - 1);
|
||||
::memcpy(_indentation, indentation, length);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FileLogger - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
FileLogger::FileLogger(FILE* stream) noexcept : _stream(nullptr) { setStream(stream); }
|
||||
FileLogger::~FileLogger() noexcept {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FileLogger - Logging]
|
||||
// ============================================================================
|
||||
|
||||
Error FileLogger::_log(const char* buf, size_t len) noexcept {
|
||||
if (!_stream)
|
||||
return kErrorOk;
|
||||
|
||||
if (len == Globals::kInvalidIndex)
|
||||
len = strlen(buf);
|
||||
|
||||
fwrite(buf, 1, len, _stream);
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::StringLogger - Construction / Destruction]
|
||||
// ============================================================================
|
||||
|
||||
StringLogger::StringLogger() noexcept {}
|
||||
StringLogger::~StringLogger() noexcept {}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::StringLogger - Logging]
|
||||
// ============================================================================
|
||||
|
||||
Error StringLogger::_log(const char* buf, size_t len) noexcept {
|
||||
return _stringBuilder.appendString(buf, len);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Logging]
|
||||
// ============================================================================
|
||||
|
||||
Error Logging::formatLabel(
|
||||
StringBuilder& sb,
|
||||
uint32_t logOptions,
|
||||
const CodeEmitter* emitter,
|
||||
uint32_t labelId) noexcept {
|
||||
|
||||
const LabelEntry* le = emitter->getCode()->getLabelEntry(labelId);
|
||||
if (ASMJIT_UNLIKELY(!le))
|
||||
return sb.appendFormat("InvalidLabel[Id=%u]", static_cast<unsigned int>(labelId));
|
||||
|
||||
if (le->hasName()) {
|
||||
if (le->hasParent()) {
|
||||
uint32_t parentId = le->getParentId();
|
||||
const LabelEntry* pe = emitter->getCode()->getLabelEntry(parentId);
|
||||
|
||||
if (ASMJIT_UNLIKELY(!pe))
|
||||
ASMJIT_PROPAGATE(sb.appendFormat("InvalidLabel[Id=%u]", static_cast<unsigned int>(labelId)));
|
||||
else if (ASMJIT_UNLIKELY(!pe->hasName()))
|
||||
ASMJIT_PROPAGATE(sb.appendFormat("L%u", Operand::unpackId(parentId)));
|
||||
else
|
||||
ASMJIT_PROPAGATE(sb.appendString(pe->getName()));
|
||||
|
||||
ASMJIT_PROPAGATE(sb.appendChar('.'));
|
||||
}
|
||||
return sb.appendString(le->getName());
|
||||
}
|
||||
else {
|
||||
return sb.appendFormat("L%u", Operand::unpackId(labelId));
|
||||
}
|
||||
}
|
||||
|
||||
Error Logging::formatRegister(
|
||||
StringBuilder& sb,
|
||||
uint32_t logOptions,
|
||||
const CodeEmitter* emitter,
|
||||
uint32_t archType,
|
||||
uint32_t regType,
|
||||
uint32_t regId) noexcept {
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
return X86Logging::formatRegister(sb, logOptions, emitter, archType, regType, regId);
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
return ArmLogging::formatRegister(sb, logOptions, emitter, archType, regType, regId);
|
||||
#endif // ASMJIT_BUILD_ARM
|
||||
|
||||
return kErrorInvalidArch;
|
||||
}
|
||||
|
||||
Error Logging::formatOperand(
|
||||
StringBuilder& sb,
|
||||
uint32_t logOptions,
|
||||
const CodeEmitter* emitter,
|
||||
uint32_t archType,
|
||||
const Operand_& op) noexcept {
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
return X86Logging::formatOperand(sb, logOptions, emitter, archType, op);
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
return ArmLogging::formatOperand(sb, logOptions, emitter, archType, op);
|
||||
#endif // ASMJIT_BUILD_ARM
|
||||
|
||||
return kErrorInvalidArch;
|
||||
}
|
||||
|
||||
Error Logging::formatInstruction(
|
||||
StringBuilder& sb,
|
||||
uint32_t logOptions,
|
||||
const CodeEmitter* emitter,
|
||||
uint32_t archType,
|
||||
const Inst::Detail& detail, const Operand_* opArray, uint32_t opCount) noexcept {
|
||||
|
||||
#if defined(ASMJIT_BUILD_X86)
|
||||
return X86Logging::formatInstruction(sb, logOptions, emitter, archType, detail, opArray, opCount);
|
||||
#endif // ASMJIT_BUILD_X86
|
||||
|
||||
#if defined(ASMJIT_BUILD_ARM)
|
||||
return ArmLogging::formatInstruction(sb, logOptions, emitter, archType, detail, opArray, opCount);
|
||||
#endif // ASMJIT_BUILD_ARM
|
||||
|
||||
return kErrorInvalidArch;
|
||||
}
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_BUILDER)
|
||||
static Error formatTypeId(StringBuilder& sb, uint32_t typeId) noexcept {
|
||||
if (typeId == TypeId::kVoid)
|
||||
return sb.appendString("void");
|
||||
|
||||
if (!TypeId::isValid(typeId))
|
||||
return sb.appendString("unknown");
|
||||
|
||||
const char* typeName = "unknown";
|
||||
uint32_t typeSize = TypeId::sizeOf(typeId);
|
||||
|
||||
uint32_t elementId = TypeId::elementOf(typeId);
|
||||
switch (elementId) {
|
||||
case TypeId::kIntPtr : typeName = "intptr" ; break;
|
||||
case TypeId::kUIntPtr: typeName = "uintptr"; break;
|
||||
case TypeId::kI8 : typeName = "i8" ; break;
|
||||
case TypeId::kU8 : typeName = "u8" ; break;
|
||||
case TypeId::kI16 : typeName = "i16" ; break;
|
||||
case TypeId::kU16 : typeName = "u16" ; break;
|
||||
case TypeId::kI32 : typeName = "i32" ; break;
|
||||
case TypeId::kU32 : typeName = "u32" ; break;
|
||||
case TypeId::kI64 : typeName = "i64" ; break;
|
||||
case TypeId::kU64 : typeName = "u64" ; break;
|
||||
case TypeId::kF32 : typeName = "f32" ; break;
|
||||
case TypeId::kF64 : typeName = "f64" ; break;
|
||||
case TypeId::kF80 : typeName = "f80" ; break;
|
||||
case TypeId::kMask8 : typeName = "mask8" ; break;
|
||||
case TypeId::kMask16 : typeName = "mask16" ; break;
|
||||
case TypeId::kMask32 : typeName = "mask32" ; break;
|
||||
case TypeId::kMask64 : typeName = "mask64" ; break;
|
||||
case TypeId::kMmx32 : typeName = "mmx32" ; break;
|
||||
case TypeId::kMmx64 : typeName = "mmx64" ; break;
|
||||
}
|
||||
|
||||
uint32_t elementSize = TypeId::sizeOf(elementId);
|
||||
if (typeSize > elementSize) {
|
||||
unsigned int numElements = typeSize / elementSize;
|
||||
return sb.appendFormat("%sx%u", typeName, numElements);
|
||||
}
|
||||
else {
|
||||
return sb.appendString(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
static Error formatFuncDetailValue(
|
||||
StringBuilder& sb,
|
||||
uint32_t logOptions,
|
||||
const CodeEmitter* emitter,
|
||||
FuncDetail::Value value) noexcept {
|
||||
|
||||
uint32_t typeId = value.getTypeId();
|
||||
ASMJIT_PROPAGATE(formatTypeId(sb, typeId));
|
||||
|
||||
if (value.byReg()) {
|
||||
ASMJIT_PROPAGATE(sb.appendChar(':'));
|
||||
ASMJIT_PROPAGATE(Logging::formatRegister(sb, logOptions, emitter, emitter->getArchType(), value.getRegType(), value.getRegId()));
|
||||
}
|
||||
|
||||
if (value.byStack()) {
|
||||
ASMJIT_PROPAGATE(sb.appendFormat(":[%d]", static_cast<int>(value.getStackOffset())));
|
||||
}
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
static Error formatFuncRets(
|
||||
StringBuilder& sb,
|
||||
uint32_t logOptions,
|
||||
const CodeEmitter* emitter,
|
||||
const FuncDetail& fd,
|
||||
VirtReg* const* vRegs) noexcept {
|
||||
|
||||
if (!fd.hasRet())
|
||||
return sb.appendString("void");
|
||||
|
||||
for (uint32_t i = 0; i < fd.getRetCount(); i++) {
|
||||
if (i) ASMJIT_PROPAGATE(sb.appendString(", "));
|
||||
ASMJIT_PROPAGATE(formatFuncDetailValue(sb, logOptions, emitter, fd.getRet(i)));
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_COMPILER)
|
||||
if (vRegs)
|
||||
ASMJIT_PROPAGATE(sb.appendFormat(" {%s}", vRegs[i]->getName()));
|
||||
#endif // !ASMJIT_DISABLE_COMPILER
|
||||
}
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
static Error formatFuncArgs(
|
||||
StringBuilder& sb,
|
||||
uint32_t logOptions,
|
||||
const CodeEmitter* emitter,
|
||||
const FuncDetail& fd,
|
||||
VirtReg* const* vRegs) noexcept {
|
||||
|
||||
for (uint32_t i = 0; i < fd.getArgCount(); i++) {
|
||||
if (i) ASMJIT_PROPAGATE(sb.appendString(", "));
|
||||
ASMJIT_PROPAGATE(formatFuncDetailValue(sb, logOptions, emitter, fd.getArg(i)));
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_COMPILER)
|
||||
if (vRegs)
|
||||
ASMJIT_PROPAGATE(sb.appendFormat(" {%s}", vRegs[i]->getName()));
|
||||
#endif // !ASMJIT_DISABLE_COMPILER
|
||||
}
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error Logging::formatNode(
|
||||
StringBuilder& sb,
|
||||
uint32_t logOptions,
|
||||
const CodeBuilder* cb,
|
||||
const CBNode* node_) noexcept {
|
||||
|
||||
if (node_->hasPosition())
|
||||
ASMJIT_PROPAGATE(sb.appendFormat("<%04u> ", node_->getPosition()));
|
||||
|
||||
switch (node_->getType()) {
|
||||
case CBNode::kNodeInst: {
|
||||
const CBInst* node = node_->as<CBInst>();
|
||||
ASMJIT_PROPAGATE(
|
||||
Logging::formatInstruction(sb, logOptions, cb,
|
||||
cb->getArchType(),
|
||||
node->getInstDetail(), node->getOpArray(), node->getOpCount()));
|
||||
break;
|
||||
}
|
||||
|
||||
case CBNode::kNodeLabel: {
|
||||
const CBLabel* node = node_->as<CBLabel>();
|
||||
ASMJIT_PROPAGATE(sb.appendFormat("L%u:", Operand::unpackId(node->getId())));
|
||||
break;
|
||||
}
|
||||
|
||||
case CBNode::kNodeData: {
|
||||
const CBData* node = node_->as<CBData>();
|
||||
ASMJIT_PROPAGATE(sb.appendFormat(".embed (%u bytes)", node->getSize()));
|
||||
break;
|
||||
}
|
||||
|
||||
case CBNode::kNodeAlign: {
|
||||
const CBAlign* node = node_->as<CBAlign>();
|
||||
ASMJIT_PROPAGATE(
|
||||
sb.appendFormat(".align %u (%s)",
|
||||
node->getAlignment(),
|
||||
node->getMode() == kAlignCode ? "code" : "data"));
|
||||
break;
|
||||
}
|
||||
|
||||
case CBNode::kNodeComment: {
|
||||
const CBComment* node = node_->as<CBComment>();
|
||||
ASMJIT_PROPAGATE(sb.appendFormat("; %s", node->getInlineComment()));
|
||||
break;
|
||||
}
|
||||
|
||||
case CBNode::kNodeSentinel: {
|
||||
ASMJIT_PROPAGATE(sb.appendString("[sentinel]"));
|
||||
break;
|
||||
}
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_COMPILER)
|
||||
case CBNode::kNodeFunc: {
|
||||
const CCFunc* node = node_->as<CCFunc>();
|
||||
ASMJIT_PROPAGATE(formatLabel(sb, logOptions, cb, node->getId()));
|
||||
|
||||
ASMJIT_PROPAGATE(sb.appendString(": ["));
|
||||
ASMJIT_PROPAGATE(formatFuncRets(sb, logOptions, cb, node->getDetail(), nullptr));
|
||||
ASMJIT_PROPAGATE(sb.appendString("]"));
|
||||
|
||||
ASMJIT_PROPAGATE(sb.appendString("("));
|
||||
ASMJIT_PROPAGATE(formatFuncArgs(sb, logOptions, cb, node->getDetail(), node->getArgs()));
|
||||
ASMJIT_PROPAGATE(sb.appendString(")"));
|
||||
break;
|
||||
}
|
||||
|
||||
case CBNode::kNodeFuncExit: {
|
||||
ASMJIT_PROPAGATE(sb.appendString("[ret]"));
|
||||
break;
|
||||
}
|
||||
|
||||
case CBNode::kNodeFuncCall: {
|
||||
const CCFuncCall* node = node_->as<CCFuncCall>();
|
||||
ASMJIT_PROPAGATE(
|
||||
Logging::formatInstruction(sb, logOptions, cb,
|
||||
cb->getArchType(),
|
||||
node->getInstDetail(), node->getOpArray(), node->getOpCount()));
|
||||
break;
|
||||
}
|
||||
#endif // !ASMJIT_DISABLE_COMPILER
|
||||
|
||||
default: {
|
||||
ASMJIT_PROPAGATE(sb.appendFormat("[unknown (type=%u)]", node_->getType()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
#endif // !ASMJIT_DISABLE_BUILDER
|
||||
|
||||
Error Logging::formatLine(StringBuilder& sb, const uint8_t* binData, size_t binLen, size_t dispLen, size_t imLen, const char* comment) noexcept {
|
||||
size_t currentLen = sb.getLength();
|
||||
size_t commentLen = comment ? Utils::strLen(comment, kMaxCommentLength) : 0;
|
||||
|
||||
ASMJIT_ASSERT(binLen >= dispLen);
|
||||
|
||||
if ((binLen != 0 && binLen != Globals::kInvalidIndex) || commentLen) {
|
||||
size_t align = kMaxInstLength;
|
||||
char sep = ';';
|
||||
|
||||
for (size_t i = (binLen == Globals::kInvalidIndex); i < 2; i++) {
|
||||
size_t begin = sb.getLength();
|
||||
|
||||
// Append align.
|
||||
if (currentLen < align)
|
||||
ASMJIT_PROPAGATE(sb.appendChars(' ', align - currentLen));
|
||||
|
||||
// Append separator.
|
||||
if (sep) {
|
||||
ASMJIT_PROPAGATE(sb.appendChar(sep));
|
||||
ASMJIT_PROPAGATE(sb.appendChar(' '));
|
||||
}
|
||||
|
||||
// Append binary data or comment.
|
||||
if (i == 0) {
|
||||
ASMJIT_PROPAGATE(sb.appendHex(binData, binLen - dispLen - imLen));
|
||||
ASMJIT_PROPAGATE(sb.appendChars('.', dispLen * 2));
|
||||
ASMJIT_PROPAGATE(sb.appendHex(binData + binLen - imLen, imLen));
|
||||
if (commentLen == 0) break;
|
||||
}
|
||||
else {
|
||||
ASMJIT_PROPAGATE(sb.appendString(comment, commentLen));
|
||||
}
|
||||
|
||||
currentLen += sb.getLength() - begin;
|
||||
align += kMaxBinaryLength;
|
||||
sep = '|';
|
||||
}
|
||||
}
|
||||
|
||||
return sb.appendChar('\n');
|
||||
}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // !ASMJIT_DISABLE_LOGGING
|
|
@ -1,288 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_LOGGING_H
|
||||
#define _ASMJIT_BASE_LOGGING_H
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/inst.h"
|
||||
#include "../base/string.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! \addtogroup asmjit_base
|
||||
//! \{
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_LOGGING)
|
||||
|
||||
// ============================================================================
|
||||
// [Forward Declarations]
|
||||
// ============================================================================
|
||||
|
||||
class CodeEmitter;
|
||||
class Reg;
|
||||
struct Operand_;
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_BUILDER)
|
||||
class CodeBuilder;
|
||||
class CBNode;
|
||||
#endif // !ASMJIT_DISABLE_BUILDER
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Logger]
|
||||
// ============================================================================
|
||||
|
||||
//! Abstract logging interface and helpers.
|
||||
//!
|
||||
//! This class can be inherited and reimplemented to fit into your logging
|
||||
//! subsystem. When reimplementing use `Logger::_log()` method to log into
|
||||
//! a custom stream.
|
||||
//!
|
||||
//! There are two \ref Logger implementations offered by AsmJit:
|
||||
//! - \ref FileLogger - allows to log into a `FILE*` stream.
|
||||
//! - \ref StringLogger - logs into a \ref StringBuilder.
|
||||
class ASMJIT_VIRTAPI Logger {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(Logger)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Options]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Logger options.
|
||||
ASMJIT_ENUM(Options) {
|
||||
kOptionBinaryForm = 0x00000001, //! Output instructions also in binary form.
|
||||
kOptionImmExtended = 0x00000002, //! Output a meaning of some immediates.
|
||||
kOptionHexImmediate = 0x00000004, //! Output constants in hexadecimal form.
|
||||
kOptionHexDisplacement = 0x00000008 //! Output displacements in hexadecimal form.
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a `Logger` instance.
|
||||
ASMJIT_API Logger() noexcept;
|
||||
//! Destroy the `Logger` instance.
|
||||
ASMJIT_API virtual ~Logger() noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Logging]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Log `str` - must be reimplemented.
|
||||
virtual Error _log(const char* str, size_t len) noexcept = 0;
|
||||
|
||||
//! Log a string `str`, which is either null terminated or having `len` length.
|
||||
ASMJIT_INLINE Error log(const char* str, size_t len = Globals::kInvalidIndex) noexcept { return _log(str, len); }
|
||||
//! Log a content of a `StringBuilder` `str`.
|
||||
ASMJIT_INLINE Error log(const StringBuilder& str) noexcept { return _log(str.getData(), str.getLength()); }
|
||||
|
||||
//! Format the message by using `sprintf()` and then send to `log()`.
|
||||
ASMJIT_API Error logf(const char* fmt, ...) noexcept;
|
||||
//! Format the message by using `vsprintf()` and then send to `log()`.
|
||||
ASMJIT_API Error logv(const char* fmt, va_list ap) noexcept;
|
||||
//! Log binary data.
|
||||
ASMJIT_API Error logBinary(const void* data, size_t size) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Options]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get all logger options as a single integer.
|
||||
ASMJIT_INLINE uint32_t getOptions() const noexcept { return _options; }
|
||||
//! Get the given logger option.
|
||||
ASMJIT_INLINE bool hasOption(uint32_t option) const noexcept { return (_options & option) != 0; }
|
||||
ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _options |= options; }
|
||||
ASMJIT_INLINE void clearOptions(uint32_t options) noexcept { _options &= ~options; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Indentation]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get indentation.
|
||||
ASMJIT_INLINE const char* getIndentation() const noexcept { return _indentation; }
|
||||
//! Set indentation.
|
||||
ASMJIT_API void setIndentation(const char* indentation) noexcept;
|
||||
//! Reset indentation.
|
||||
ASMJIT_INLINE void resetIndentation() noexcept { setIndentation(nullptr); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Options, see \ref LoggerOption.
|
||||
uint32_t _options;
|
||||
|
||||
//! Indentation.
|
||||
char _indentation[12];
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::FileLogger]
|
||||
// ============================================================================
|
||||
|
||||
//! Logger that can log to a `FILE*` stream.
|
||||
class ASMJIT_VIRTAPI FileLogger : public Logger {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(FileLogger)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create a new `FileLogger` that logs to a `FILE` stream.
|
||||
ASMJIT_API FileLogger(FILE* stream = nullptr) noexcept;
|
||||
//! Destroy the `FileLogger`.
|
||||
ASMJIT_API virtual ~FileLogger() noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get the logging out put stream or null.
|
||||
ASMJIT_INLINE FILE* getStream() const noexcept { return _stream; }
|
||||
|
||||
//! Set the logging output stream to `stream` or null.
|
||||
//!
|
||||
//! NOTE: If the `stream` is null it will disable logging, but it won't
|
||||
//! stop calling `log()` unless the logger is detached from the
|
||||
//! \ref Assembler.
|
||||
ASMJIT_INLINE void setStream(FILE* stream) noexcept { _stream = stream; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Logging]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API Error _log(const char* buf, size_t len = Globals::kInvalidIndex) noexcept override;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! C file stream.
|
||||
FILE* _stream;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::StringLogger]
|
||||
// ============================================================================
|
||||
|
||||
//! Logger that stores everything in an internal string buffer.
|
||||
class ASMJIT_VIRTAPI StringLogger : public Logger {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(StringLogger)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Construction / Destruction]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Create new `StringLogger`.
|
||||
ASMJIT_API StringLogger() noexcept;
|
||||
//! Destroy the `StringLogger`.
|
||||
ASMJIT_API virtual ~StringLogger() noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Accessors]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Get `char*` pointer which represents the resulting string.
|
||||
//!
|
||||
//! The pointer is owned by `StringLogger`, it can't be modified or freed.
|
||||
ASMJIT_INLINE const char* getString() const noexcept { return _stringBuilder.getData(); }
|
||||
//! Clear the resulting string.
|
||||
ASMJIT_INLINE void clearString() noexcept { _stringBuilder.clear(); }
|
||||
|
||||
//! Get the length of the string returned by `getString()`.
|
||||
ASMJIT_INLINE size_t getLength() const noexcept { return _stringBuilder.getLength(); }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Logging]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
ASMJIT_API Error _log(const char* buf, size_t len = Globals::kInvalidIndex) noexcept override;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Members]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
//! Output string.
|
||||
StringBuilder _stringBuilder;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Logging]
|
||||
// ============================================================================
|
||||
|
||||
struct Logging {
|
||||
ASMJIT_API static Error formatRegister(
|
||||
StringBuilder& sb,
|
||||
uint32_t logOptions,
|
||||
const CodeEmitter* emitter,
|
||||
uint32_t archType,
|
||||
uint32_t regType,
|
||||
uint32_t regId) noexcept;
|
||||
|
||||
ASMJIT_API static Error formatLabel(
|
||||
StringBuilder& sb,
|
||||
uint32_t logOptions,
|
||||
const CodeEmitter* emitter,
|
||||
uint32_t labelId) noexcept;
|
||||
|
||||
ASMJIT_API static Error formatOperand(
|
||||
StringBuilder& sb,
|
||||
uint32_t logOptions,
|
||||
const CodeEmitter* emitter,
|
||||
uint32_t archType,
|
||||
const Operand_& op) noexcept;
|
||||
|
||||
ASMJIT_API static Error formatInstruction(
|
||||
StringBuilder& sb,
|
||||
uint32_t logOptions,
|
||||
const CodeEmitter* emitter,
|
||||
uint32_t archType,
|
||||
const Inst::Detail& detail, const Operand_* opArray, uint32_t opCount) noexcept;
|
||||
|
||||
#if !defined(ASMJIT_DISABLE_BUILDER)
|
||||
ASMJIT_API static Error formatNode(
|
||||
StringBuilder& sb,
|
||||
uint32_t logOptions,
|
||||
const CodeBuilder* cb,
|
||||
const CBNode* node_) noexcept;
|
||||
#endif // !ASMJIT_DISABLE_BUILDER
|
||||
|
||||
// Only used by AsmJit internals, not available to users.
|
||||
#if defined(ASMJIT_EXPORTS)
|
||||
enum {
|
||||
// Has to be big to be able to hold all metadata compiler can assign to a
|
||||
// single instruction.
|
||||
kMaxCommentLength = 512,
|
||||
kMaxInstLength = 40,
|
||||
kMaxBinaryLength = 26
|
||||
};
|
||||
|
||||
static Error formatLine(
|
||||
StringBuilder& sb,
|
||||
const uint8_t* binData, size_t binLen, size_t dispLen, size_t imLen, const char* comment) noexcept;
|
||||
#endif // ASMJIT_EXPORTS
|
||||
};
|
||||
#else
|
||||
class Logger;
|
||||
#endif // !ASMJIT_DISABLE_LOGGING
|
||||
|
||||
//! \}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_LOGGER_H
|
|
@ -1,74 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Guard]
|
||||
#ifndef _ASMJIT_BASE_MISC_P_H
|
||||
#define _ASMJIT_BASE_MISC_P_H
|
||||
|
||||
// [Dependencies]
|
||||
#include "../asmjit_build.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
//! \addtogroup asmjit_base
|
||||
//! \{
|
||||
|
||||
//! \internal
|
||||
//!
|
||||
//! Macro used to populate a table with 16 elements starting at `I`.
|
||||
#define ASMJIT_TABLE_16(DEF, I) DEF(I + 0), DEF(I + 1), DEF(I + 2), DEF(I + 3), \
|
||||
DEF(I + 4), DEF(I + 5), DEF(I + 6), DEF(I + 7), \
|
||||
DEF(I + 8), DEF(I + 9), DEF(I + 10), DEF(I + 11), \
|
||||
DEF(I + 12), DEF(I + 13), DEF(I + 14), DEF(I + 15)
|
||||
|
||||
#define ASMJIT_TABLE_T_8(TABLE, VALUE, I) \
|
||||
TABLE< I + 0 >::VALUE, TABLE< I + 1 >::VALUE, \
|
||||
TABLE< I + 2 >::VALUE, TABLE< I + 3 >::VALUE, \
|
||||
TABLE< I + 4 >::VALUE, TABLE< I + 5 >::VALUE, \
|
||||
TABLE< I + 6 >::VALUE, TABLE< I + 7 >::VALUE
|
||||
|
||||
#define ASMJIT_TABLE_T_16(TABLE, VALUE, I) \
|
||||
ASMJIT_TABLE_T_8(TABLE, VALUE, I), \
|
||||
ASMJIT_TABLE_T_8(TABLE, VALUE, I + 8)
|
||||
|
||||
#define ASMJIT_TABLE_T_32(TABLE, VALUE, I) \
|
||||
ASMJIT_TABLE_T_16(TABLE, VALUE, I), \
|
||||
ASMJIT_TABLE_T_16(TABLE, VALUE, I + 16)
|
||||
|
||||
#define ASMJIT_TABLE_T_64(TABLE, VALUE, I) \
|
||||
ASMJIT_TABLE_T_32(TABLE, VALUE, I), \
|
||||
ASMJIT_TABLE_T_32(TABLE, VALUE, I + 32)
|
||||
|
||||
#define ASMJIT_TABLE_T_128(TABLE, VALUE, I) \
|
||||
ASMJIT_TABLE_T_64(TABLE, VALUE, I), \
|
||||
ASMJIT_TABLE_T_64(TABLE, VALUE, I + 64)
|
||||
|
||||
#define ASMJIT_TABLE_T_256(TABLE, VALUE, I) \
|
||||
ASMJIT_TABLE_T_128(TABLE, VALUE, I), \
|
||||
ASMJIT_TABLE_T_128(TABLE, VALUE, I + 128)
|
||||
|
||||
#define ASMJIT_TABLE_T_512(TABLE, VALUE, I) \
|
||||
ASMJIT_TABLE_T_256(TABLE, VALUE, I), \
|
||||
ASMJIT_TABLE_T_256(TABLE, VALUE, I + 256)
|
||||
|
||||
#define ASMJIT_TABLE_T_1024(TABLE, VALUE, I) \
|
||||
ASMJIT_TABLE_T_512(TABLE, VALUE, I), \
|
||||
ASMJIT_TABLE_T_512(TABLE, VALUE, I + 512)
|
||||
|
||||
//! \}
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
//! \}
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
||||
|
||||
// [Guard]
|
||||
#endif // _ASMJIT_BASE_MISC_P_H
|
|
@ -1,209 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/operand.h"
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::TypeId]
|
||||
// ============================================================================
|
||||
|
||||
template<int ID>
|
||||
struct TypeIdSizeOf_T {
|
||||
enum {
|
||||
kValue = (ID == TypeId::kI8 ) ? 1 :
|
||||
(ID == TypeId::kU8 ) ? 1 :
|
||||
(ID == TypeId::kI16 ) ? 2 :
|
||||
(ID == TypeId::kU16 ) ? 2 :
|
||||
(ID == TypeId::kI32 ) ? 4 :
|
||||
(ID == TypeId::kU32 ) ? 4 :
|
||||
(ID == TypeId::kI64 ) ? 8 :
|
||||
(ID == TypeId::kU64 ) ? 8 :
|
||||
(ID == TypeId::kF32 ) ? 4 :
|
||||
(ID == TypeId::kF64 ) ? 8 :
|
||||
(ID == TypeId::kF80 ) ? 10 :
|
||||
(ID == TypeId::kMask8 ) ? 1 :
|
||||
(ID == TypeId::kMask16) ? 2 :
|
||||
(ID == TypeId::kMask32) ? 4 :
|
||||
(ID == TypeId::kMask64) ? 8 :
|
||||
(ID == TypeId::kMmx32 ) ? 4 :
|
||||
(ID == TypeId::kMmx64 ) ? 8 :
|
||||
(ID >= TypeId::_kVec32Start && ID <= TypeId::_kVec32End ) ? 4 :
|
||||
(ID >= TypeId::_kVec64Start && ID <= TypeId::_kVec64End ) ? 8 :
|
||||
(ID >= TypeId::_kVec128Start && ID <= TypeId::_kVec128End) ? 16 :
|
||||
(ID >= TypeId::_kVec256Start && ID <= TypeId::_kVec256End) ? 32 :
|
||||
(ID >= TypeId::_kVec512Start && ID <= TypeId::_kVec512End) ? 64 : 0
|
||||
};
|
||||
};
|
||||
|
||||
template<int ID>
|
||||
struct TypeIdElementOf_T {
|
||||
enum {
|
||||
kValue = (ID == TypeId::kMask8 ) ? TypeId::kU8 :
|
||||
(ID == TypeId::kMask16) ? TypeId::kU16 :
|
||||
(ID == TypeId::kMask32) ? TypeId::kU32 :
|
||||
(ID == TypeId::kMask64) ? TypeId::kU64 :
|
||||
(ID == TypeId::kMmx32 ) ? TypeId::kI32 :
|
||||
(ID == TypeId::kMmx64 ) ? TypeId::kI64 :
|
||||
(ID >= TypeId::kI8 && ID <= TypeId::kF80 ) ? ID :
|
||||
(ID >= TypeId::_kVec32Start && ID <= TypeId::_kVec32End ) ? ID - TypeId::_kVec32Start + TypeId::kI8 :
|
||||
(ID >= TypeId::_kVec64Start && ID <= TypeId::_kVec64End ) ? ID - TypeId::_kVec64Start + TypeId::kI8 :
|
||||
(ID >= TypeId::_kVec128Start && ID <= TypeId::_kVec128End) ? ID - TypeId::_kVec128Start + TypeId::kI8 :
|
||||
(ID >= TypeId::_kVec256Start && ID <= TypeId::_kVec256End) ? ID - TypeId::_kVec256Start + TypeId::kI8 :
|
||||
(ID >= TypeId::_kVec512Start && ID <= TypeId::_kVec512End) ? ID - TypeId::_kVec512Start + TypeId::kI8 : 0
|
||||
};
|
||||
};
|
||||
|
||||
#define R(TMPL, I) TMPL<I + 0>::kValue, TMPL<I + 1>::kValue, \
|
||||
TMPL<I + 2>::kValue, TMPL<I + 3>::kValue, \
|
||||
TMPL<I + 4>::kValue, TMPL<I + 5>::kValue, \
|
||||
TMPL<I + 6>::kValue, TMPL<I + 7>::kValue, \
|
||||
TMPL<I + 8>::kValue, TMPL<I + 9>::kValue, \
|
||||
TMPL<I + 10>::kValue, TMPL<I + 11>::kValue, \
|
||||
TMPL<I + 12>::kValue, TMPL<I + 13>::kValue, \
|
||||
TMPL<I + 14>::kValue, TMPL<I + 15>::kValue
|
||||
ASMJIT_API const TypeId::Info TypeId::_info = {
|
||||
// SizeOf[128]
|
||||
{
|
||||
R(TypeIdSizeOf_T, 0), R(TypeIdSizeOf_T, 16),
|
||||
R(TypeIdSizeOf_T, 32), R(TypeIdSizeOf_T, 48),
|
||||
R(TypeIdSizeOf_T, 64), R(TypeIdSizeOf_T, 80),
|
||||
R(TypeIdSizeOf_T, 96), R(TypeIdSizeOf_T, 112)
|
||||
},
|
||||
|
||||
// ElementOf[128]
|
||||
{
|
||||
R(TypeIdElementOf_T, 0), R(TypeIdElementOf_T, 16),
|
||||
R(TypeIdElementOf_T, 32), R(TypeIdElementOf_T, 48),
|
||||
R(TypeIdElementOf_T, 64), R(TypeIdElementOf_T, 80),
|
||||
R(TypeIdElementOf_T, 96), R(TypeIdElementOf_T, 112)
|
||||
}
|
||||
};
|
||||
#undef R
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::Operand - Test]
|
||||
// ============================================================================
|
||||
|
||||
#if defined(ASMJIT_TEST)
|
||||
UNIT(base_operand) {
|
||||
INFO("Checking operand sizes");
|
||||
EXPECT(sizeof(Operand) == 16);
|
||||
EXPECT(sizeof(Reg) == 16);
|
||||
EXPECT(sizeof(Mem) == 16);
|
||||
EXPECT(sizeof(Imm) == 16);
|
||||
EXPECT(sizeof(Label) == 16);
|
||||
|
||||
INFO("Checking basic functionality of Operand");
|
||||
Operand a, b;
|
||||
Operand dummy;
|
||||
|
||||
EXPECT(a.isNone() == true);
|
||||
EXPECT(a.isReg() == false);
|
||||
EXPECT(a.isMem() == false);
|
||||
EXPECT(a.isImm() == false);
|
||||
EXPECT(a.isLabel() == false);
|
||||
EXPECT(a == b);
|
||||
|
||||
EXPECT(a._any.reserved8_4 == 0, "Default constructed Operand should zero its 'reserved8_4' field");
|
||||
EXPECT(a._any.reserved12_4 == 0, "Default constructed Operand should zero its 'reserved12_4' field");
|
||||
|
||||
INFO("Checking basic functionality of Label");
|
||||
Label label;
|
||||
EXPECT(label.isValid() == false);
|
||||
EXPECT(label.getId() == 0);
|
||||
|
||||
INFO("Checking basic functionality of Reg");
|
||||
EXPECT(Reg().isValid() == false,
|
||||
"Default constructed Reg() should not be valid");
|
||||
EXPECT(Reg()._any.reserved8_4 == 0,
|
||||
"A default constructed Reg() should zero its 'reserved8_4' field");
|
||||
EXPECT(Reg()._any.reserved12_4 == 0,
|
||||
"A default constructed Reg() should zero its 'reserved12_4' field");
|
||||
|
||||
EXPECT(Reg().isReg() == false,
|
||||
"Default constructed register should not isReg()");
|
||||
EXPECT(dummy.as<Reg>().isValid() == false,
|
||||
"Default constructed Operand casted to Reg should not be valid");
|
||||
|
||||
// Create some register (not specific to any architecture).
|
||||
uint32_t rSig = Operand::kOpReg | (1 << Operand::kSignatureRegTypeShift) |
|
||||
(2 << Operand::kSignatureRegKindShift) |
|
||||
(8 << Operand::kSignatureSizeShift ) ;
|
||||
Reg r1(Reg::fromSignature(rSig, 5));
|
||||
|
||||
EXPECT(r1.isValid() == true);
|
||||
EXPECT(r1.isReg() == true);
|
||||
EXPECT(r1.isReg(1) == true);
|
||||
EXPECT(r1.isPhysReg() == true);
|
||||
EXPECT(r1.isVirtReg() == false);
|
||||
EXPECT(r1.getSignature() == rSig);
|
||||
EXPECT(r1.getType() == 1);
|
||||
EXPECT(r1.getKind() == 2);
|
||||
EXPECT(r1.getSize() == 8);
|
||||
EXPECT(r1.getId() == 5);
|
||||
EXPECT(r1.isReg(1, 5) == true); // RegType and Id.
|
||||
|
||||
EXPECT(r1._any.reserved8_4 == 0, "Reg should have 'reserved8_4' zero");
|
||||
EXPECT(r1._any.reserved12_4 == 0, "Reg should have 'reserved12_4' zero");
|
||||
|
||||
// The same type of register having different id.
|
||||
Reg r2(r1, 6);
|
||||
EXPECT(r2.isValid() == true);
|
||||
EXPECT(r2.isReg() == true);
|
||||
EXPECT(r2.isReg(1) == true);
|
||||
EXPECT(r2.isPhysReg() == true);
|
||||
EXPECT(r2.isVirtReg() == false);
|
||||
EXPECT(r2.getSignature() == rSig);
|
||||
EXPECT(r2.getType() == r1.getType());
|
||||
EXPECT(r2.getKind() == r1.getKind());
|
||||
EXPECT(r2.getSize() == r1.getSize());
|
||||
EXPECT(r2.getId() == 6);
|
||||
EXPECT(r2.isReg(1, 6) == true);
|
||||
|
||||
r1.reset();
|
||||
EXPECT(!r1.isValid(),
|
||||
"Reset register should not be valid");
|
||||
EXPECT(!r1.isReg(),
|
||||
"Reset register should not isReg()");
|
||||
|
||||
INFO("Checking basic functionality of Mem");
|
||||
Mem m;
|
||||
EXPECT(m.isMem() , "Default constructed Mem() should isMem()");
|
||||
EXPECT(m == Mem() , "Two default constructed Mem() operands should be equal");
|
||||
EXPECT(m.hasBase() == false , "Default constructed Mem() should not have base specified");
|
||||
EXPECT(m.hasIndex() == false , "Default constructed Mem() should not have index specified");
|
||||
EXPECT(m.has64BitOffset() == true , "Default constructed Mem() should report 64-bit offset");
|
||||
EXPECT(m.getOffset() == 0 , "Default constructed Mem() should have be zero offset / address");
|
||||
|
||||
m.setOffset(-1);
|
||||
EXPECT(m.getOffsetLo32() == -1 , "Memory operand must hold a 32-bit offset");
|
||||
EXPECT(m.getOffset() == -1 , "32-bit offset must be sign extended to 64 bits");
|
||||
|
||||
int64_t x = int64_t(ASMJIT_UINT64_C(0xFF00FF0000000001));
|
||||
m.setOffset(x);
|
||||
EXPECT(m.getOffset() == x , "Memory operand must hold a 64-bit offset");
|
||||
EXPECT(m.getOffsetLo32() == 1 , "Memory operand must return correct low offset DWORD");
|
||||
EXPECT(m.getOffsetHi32() == 0xFF00FF00, "Memory operand must return correct high offset DWORD");
|
||||
|
||||
INFO("Checking basic functionality of Imm");
|
||||
EXPECT(Imm(-1).getInt64() == int64_t(-1),
|
||||
"Immediate values should by default sign-extend to 64-bits");
|
||||
}
|
||||
#endif // ASMJIT_TEST
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
File diff suppressed because it is too large
Load Diff
|
@ -1,228 +0,0 @@
|
|||
// [AsmJit]
|
||||
// Complete x86/x64 JIT and Remote Assembler for C++.
|
||||
//
|
||||
// [License]
|
||||
// Zlib - See LICENSE.md file in the package.
|
||||
|
||||
// [Export]
|
||||
#define ASMJIT_EXPORTS
|
||||
|
||||
// [Dependencies]
|
||||
#include "../base/osutils.h"
|
||||
#include "../base/utils.h"
|
||||
|
||||
#if ASMJIT_OS_POSIX
|
||||
# include <sys/types.h>
|
||||
# include <sys/mman.h>
|
||||
# include <time.h>
|
||||
# include <unistd.h>
|
||||
#endif // ASMJIT_OS_POSIX
|
||||
|
||||
#if ASMJIT_OS_MAC
|
||||
# include <mach/mach_time.h>
|
||||
#endif // ASMJIT_OS_MAC
|
||||
|
||||
#if ASMJIT_OS_WINDOWS
|
||||
# if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
# include <intrin.h>
|
||||
# else
|
||||
# define _InterlockedCompareExchange InterlockedCompareExchange
|
||||
# endif // _MSC_VER
|
||||
#endif // ASMJIT_OS_WINDOWS
|
||||
|
||||
// [Api-Begin]
|
||||
#include "../asmjit_apibegin.h"
|
||||
|
||||
namespace asmjit {
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::OSUtils - Virtual Memory]
|
||||
// ============================================================================
|
||||
|
||||
// Windows specific implementation using `VirtualAllocEx` and `VirtualFree`.
|
||||
#if ASMJIT_OS_WINDOWS
|
||||
static ASMJIT_NOINLINE const VMemInfo& OSUtils_GetVMemInfo() noexcept {
|
||||
static VMemInfo vmi;
|
||||
|
||||
if (ASMJIT_UNLIKELY(!vmi.hCurrentProcess)) {
|
||||
SYSTEM_INFO info;
|
||||
::GetSystemInfo(&info);
|
||||
|
||||
vmi.pageSize = Utils::alignToPowerOf2<uint32_t>(info.dwPageSize);
|
||||
vmi.pageGranularity = info.dwAllocationGranularity;
|
||||
vmi.hCurrentProcess = ::GetCurrentProcess();
|
||||
}
|
||||
|
||||
return vmi;
|
||||
};
|
||||
|
||||
VMemInfo OSUtils::getVirtualMemoryInfo() noexcept { return OSUtils_GetVMemInfo(); }
|
||||
|
||||
void* OSUtils::allocVirtualMemory(size_t size, size_t* allocated, uint32_t flags) noexcept {
|
||||
return allocProcessMemory(static_cast<HANDLE>(0), size, allocated, flags);
|
||||
}
|
||||
|
||||
Error OSUtils::releaseVirtualMemory(void* p, size_t size) noexcept {
|
||||
return releaseProcessMemory(static_cast<HANDLE>(0), p, size);
|
||||
}
|
||||
|
||||
void* OSUtils::allocProcessMemory(HANDLE hProcess, size_t size, size_t* allocated, uint32_t flags) noexcept {
|
||||
if (size == 0)
|
||||
return nullptr;
|
||||
|
||||
const VMemInfo& vmi = OSUtils_GetVMemInfo();
|
||||
if (!hProcess) hProcess = vmi.hCurrentProcess;
|
||||
|
||||
// VirtualAllocEx rounds the allocated size to a page size automatically,
|
||||
// but we need the `alignedSize` so we can store the real allocated size
|
||||
// into `allocated` output.
|
||||
size_t alignedSize = Utils::alignTo(size, vmi.pageSize);
|
||||
|
||||
// Windows XP SP2 / Vista+ allow data-execution-prevention (DEP).
|
||||
DWORD protectFlags = 0;
|
||||
|
||||
if (flags & kVMExecutable)
|
||||
protectFlags |= (flags & kVMWritable) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
|
||||
else
|
||||
protectFlags |= (flags & kVMWritable) ? PAGE_READWRITE : PAGE_READONLY;
|
||||
|
||||
LPVOID mBase = ::VirtualAllocEx(hProcess, nullptr, alignedSize, MEM_COMMIT | MEM_RESERVE, protectFlags);
|
||||
if (ASMJIT_UNLIKELY(!mBase)) return nullptr;
|
||||
|
||||
ASMJIT_ASSERT(Utils::isAligned<size_t>(reinterpret_cast<size_t>(mBase), vmi.pageSize));
|
||||
if (allocated) *allocated = alignedSize;
|
||||
return mBase;
|
||||
}
|
||||
|
||||
Error OSUtils::releaseProcessMemory(HANDLE hProcess, void* p, size_t size) noexcept {
|
||||
const VMemInfo& vmi = OSUtils_GetVMemInfo();
|
||||
if (!hProcess) hProcess = vmi.hCurrentProcess;
|
||||
|
||||
if (ASMJIT_UNLIKELY(!::VirtualFreeEx(hProcess, p, 0, MEM_RELEASE)))
|
||||
return DebugUtils::errored(kErrorInvalidState);
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
#endif // ASMJIT_OS_WINDOWS
|
||||
|
||||
// Posix specific implementation using `mmap()` and `munmap()`.
|
||||
#if ASMJIT_OS_POSIX
|
||||
|
||||
// Mac uses MAP_ANON instead of MAP_ANONYMOUS.
|
||||
#if !defined(MAP_ANONYMOUS)
|
||||
# define MAP_ANONYMOUS MAP_ANON
|
||||
#endif // MAP_ANONYMOUS
|
||||
|
||||
static const VMemInfo& OSUtils_GetVMemInfo() noexcept {
|
||||
static VMemInfo vmi;
|
||||
if (ASMJIT_UNLIKELY(!vmi.pageSize)) {
|
||||
size_t pageSize = ::getpagesize();
|
||||
vmi.pageSize = pageSize;
|
||||
vmi.pageGranularity = std::max<size_t>(pageSize, 65536);
|
||||
}
|
||||
return vmi;
|
||||
};
|
||||
|
||||
VMemInfo OSUtils::getVirtualMemoryInfo() noexcept { return OSUtils_GetVMemInfo(); }
|
||||
|
||||
void* OSUtils::allocVirtualMemory(size_t size, size_t* allocated, uint32_t flags) noexcept {
|
||||
const VMemInfo& vmi = OSUtils_GetVMemInfo();
|
||||
|
||||
size_t alignedSize = Utils::alignTo<size_t>(size, vmi.pageSize);
|
||||
int protection = PROT_READ;
|
||||
|
||||
if (flags & kVMWritable ) protection |= PROT_WRITE;
|
||||
if (flags & kVMExecutable) protection |= PROT_EXEC;
|
||||
|
||||
void* mbase = ::mmap(nullptr, alignedSize, protection, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (ASMJIT_UNLIKELY(mbase == MAP_FAILED)) return nullptr;
|
||||
|
||||
if (allocated) *allocated = alignedSize;
|
||||
return mbase;
|
||||
}
|
||||
|
||||
Error OSUtils::releaseVirtualMemory(void* p, size_t size) noexcept {
|
||||
if (ASMJIT_UNLIKELY(::munmap(p, size) != 0))
|
||||
return DebugUtils::errored(kErrorInvalidState);
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
#endif // ASMJIT_OS_POSIX
|
||||
|
||||
// ============================================================================
|
||||
// [asmjit::OSUtils - GetTickCount]
|
||||
// ============================================================================
|
||||
|
||||
#if ASMJIT_OS_WINDOWS
|
||||
static ASMJIT_INLINE uint32_t OSUtils_calcHiRes(const LARGE_INTEGER& now, double freq) noexcept {
|
||||
return static_cast<uint32_t>(
|
||||
(int64_t)(double(now.QuadPart) / freq) & 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
uint32_t OSUtils::getTickCount() noexcept {
|
||||
static volatile uint32_t _hiResTicks;
|
||||
static volatile double _hiResFreq;
|
||||
|
||||
do {
|
||||
uint32_t hiResOk = _hiResTicks;
|
||||
LARGE_INTEGER qpf, now;
|
||||
|
||||
// If for whatever reason this fails, bail to `GetTickCount()`.
|
||||
if (!::QueryPerformanceCounter(&now)) break;
|
||||
|
||||
// Expected - if we ran through this at least once `hiResTicks` will be
|
||||
// either 1 or 0xFFFFFFFF. If it's '1' then the Hi-Res counter is available
|
||||
// and `QueryPerformanceCounter()` can be used.
|
||||
if (hiResOk == 1) return OSUtils_calcHiRes(now, _hiResFreq);
|
||||
|
||||
// Hi-Res counter is not available, bail to `GetTickCount()`.
|
||||
if (hiResOk != 0) break;
|
||||
|
||||
// Detect availability of Hi-Res counter, if not available, bail to `GetTickCount()`.
|
||||
if (!::QueryPerformanceFrequency(&qpf)) {
|
||||
_InterlockedCompareExchange((LONG*)&_hiResTicks, 0xFFFFFFFF, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
double freq = double(qpf.QuadPart) / 1000.0;
|
||||
_hiResFreq = freq;
|
||||
|
||||
_InterlockedCompareExchange((LONG*)&_hiResTicks, 1, 0);
|
||||
return OSUtils_calcHiRes(now, freq);
|
||||
} while (0);
|
||||
|
||||
return ::GetTickCount();
|
||||
}
|
||||
#elif ASMJIT_OS_MAC
|
||||
uint32_t OSUtils::getTickCount() noexcept {
|
||||
static mach_timebase_info_data_t _machTime;
|
||||
|
||||
// See Apple's QA1398.
|
||||
if (ASMJIT_UNLIKELY(_machTime.denom == 0) || mach_timebase_info(&_machTime) != KERN_SUCCESS)
|
||||
return 0;
|
||||
|
||||
// `mach_absolute_time()` returns nanoseconds, we want milliseconds.
|
||||
uint64_t t = mach_absolute_time() / 1000000;
|
||||
|
||||
t = t * _machTime.numer / _machTime.denom;
|
||||
return static_cast<uint32_t>(t & 0xFFFFFFFFU);
|
||||
}
|
||||
#elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
|
||||
uint32_t OSUtils::getTickCount() noexcept {
|
||||
struct timespec ts;
|
||||
|
||||
if (ASMJIT_UNLIKELY(clock_gettime(CLOCK_MONOTONIC, &ts) != 0))
|
||||
return 0;
|
||||
|
||||
uint64_t t = (uint64_t(ts.tv_sec ) * 1000) + (uint64_t(ts.tv_nsec) / 1000000);
|
||||
return static_cast<uint32_t>(t & 0xFFFFFFFFU);
|
||||
}
|
||||
#else
|
||||
#error "[asmjit] OSUtils::getTickCount() is not implemented for your target OS."
|
||||
uint32_t OSUtils::getTickCount() noexcept { return 0; }
|
||||
#endif
|
||||
|
||||
} // asmjit namespace
|
||||
|
||||
// [Api-End]
|
||||
#include "../asmjit_apiend.h"
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue