Click here to Skip to main content
15,895,777 members
Articles / Programming Languages / C#

SFMT in Action: Part II – Object oriented implementation of SIMD-oriented Fast Mersenne Twister (SFMT) in C#

Rate me:
Please Sign up or sign in to vote.
4.71/5 (5 votes)
31 Oct 2009CPOL18 min read 47K   620   9  
The new SIMD-oriented Fast Mersenne Twister (SFMT) library was developed using object oriented technologies such as UML, composition, aggregation, generalization, multiplicity, and Design Patterns.
#include <windows.h>
#include "cpuid.h"


// These are the bit flags that get set on calling cpuid
// with register eax set to 1
#define _MMX_FEATURE_BIT        0x00800000
#define _SSE_FEATURE_BIT        0x02000000
#define _SSE2_FEATURE_BIT       0x04000000

// This bit is set when cpuid is called with
// register set to 80000001h (only applicable to AMD)
#define _3DNOW_FEATURE_BIT      0x80000000

// These are the names of the various processors
#define PROC_AMD_AM486          "AMD Am486"
#define PROC_AMD_K5             "AMD K5"
#define PROC_AMD_K6             "AMD K6"
#define PROC_AMD_K6_2           "AMD K6-2"
#define PROC_AMD_K6_3           "AMD K6-3"
#define PROC_AMD_ATHLON         "AMD Athlon"
#define PROC_INTEL_486DX        "INTEL 486DX"
#define PROC_INTEL_486SX        "INTEL 486SX"
#define PROC_INTEL_486DX2       "INTEL 486DX2"
#define PROC_INTEL_486SL        "INTEL 486SL"
#define PROC_INTEL_486SX2       "INTEL 486SX2"
#define PROC_INTEL_486DX2E      "INTEL 486DX2E"
#define PROC_INTEL_486DX4       "INTEL 486DX4"
#define PROC_INTEL_PENTIUM      "INTEL Pentium"
#define PROC_INTEL_PENTIUM_MMX  "INTEL Pentium-MMX"
#define PROC_INTEL_PENTIUM_PRO  "INTEL Pentium-Pro"
#define PROC_INTEL_PENTIUM_II   "INTEL Pentium-II"
#define PROC_INTEL_CELERON      "INTEL Celeron"
#define PROC_INTEL_PENTIUM_III  "INTEL Pentium-III"
#define PROC_INTEL_PENTIUM_4    "INTEL Pentium-4"
#define PROC_CYRIX              "Cyrix"
#define PROC_CENTAUR            "Centaur"
#define PROC_UNKNOWN            "Unknown"

// This is the maximum length of the vendor name
#define MAX_VNAME_LENGTH        12
	
int IsCPUID()
{
    __try {
        _asm {
            xor eax, eax
            cpuid
        }
    }
	#pragma warning (suppress: 6320)
    __except (EXCEPTION_EXECUTE_HANDLER) {
        return 0;
    }
    return 1;
}


/***
* int _os_support(int feature)
*   - Checks if OS Supports the capablity or not
*
* Entry:
*   feature: the feature we want to check if OS supports it.
*
* Exit:
*   Returns 1 if OS support exist and 0 when OS doesn't support it.
*
****************************************************************/

int _os_support(int feature)
{
    __try {
        switch (feature) {
        case _CPU_FEATURE_SSE:
            __asm {
                xorps xmm0, xmm0        // executing SSE instruction
            }
            break;
        case _CPU_FEATURE_SSE2:
            __asm {
                xorpd xmm0, xmm0        // executing SSE2 instruction
            }
            break;
        case _CPU_FEATURE_3DNOW:
            __asm {
                pfrcp mm0, mm0          // executing 3DNow! instruction
                emms
            }
            break;
        case _CPU_FEATURE_MMX:
            __asm {
                pxor mm0, mm0           // executing MMX instruction
                emms
            }
            break;
        }
    }
	#pragma warning (suppress: 6320)
    __except (EXCEPTION_EXECUTE_HANDLER) {
        if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION) {
            return 0;
        }
        return 0;
    }
    return 1;
}


/***
*
* void map_mname(int, int, const char *, char *)
*   - Maps family and model to processor name
*
****************************************************/


void map_mname(int family, int model, const char *v_name, char *m_name)
{
    // Default to name not known
    m_name[0] = '\0';

    if (!strncmp("AuthenticAMD", v_name, 12)) {
        switch (family) { // extract family code
        case 4: // Am486/AM5x86
            strcpy_s (m_name, sizeof(PROC_AMD_AM486), PROC_AMD_AM486);
            break;

        case 5: // K6
            switch (model) { // extract model code
            case 0:
            case 1:
            case 2:
            case 3:
                strcpy_s (m_name, sizeof(PROC_AMD_K5), PROC_AMD_K5);
                break;
            case 6:
            case 7:
                strcpy_s (m_name, sizeof(PROC_AMD_K6), PROC_AMD_K6);
                break;
            case 8:
                strcpy_s (m_name, sizeof(PROC_AMD_K6_2), PROC_AMD_K6_2);
                break;
            case 9:
            case 10:
            case 11:
            case 12:
            case 13:
            case 14:
            case 15:
                strcpy_s (m_name, sizeof(PROC_AMD_K6_3), PROC_AMD_K6_3);
                break;
            }
            break;

        case 6: // Athlon
            // No model numbers are currently defined
            strcpy_s (m_name, sizeof(PROC_AMD_ATHLON), PROC_AMD_ATHLON);
            break;
        }
    }
    else if (!strncmp("GenuineIntel", v_name, 12)) {
        switch (family) { // extract family code
        case 4:
            switch (model) { // extract model code
            case 0:
            case 1:
                strcpy_s (m_name, sizeof(PROC_INTEL_486DX), PROC_INTEL_486DX);
                break;
            case 2:
                strcpy_s (m_name, sizeof(PROC_INTEL_486SX), PROC_INTEL_486SX);
                break;
            case 3:
                strcpy_s (m_name, sizeof(PROC_INTEL_486DX2), PROC_INTEL_486DX2);
                break;
            case 4:
                strcpy_s (m_name, sizeof(PROC_INTEL_486SL), PROC_INTEL_486SL);
                break;
            case 5:
                strcpy_s (m_name, sizeof(PROC_INTEL_486SX2), PROC_INTEL_486SX2);
                break;
            case 7:
                strcpy_s (m_name, sizeof(PROC_INTEL_486DX2E), PROC_INTEL_486DX2E);
                break;
            case 8:
                strcpy_s (m_name, sizeof(PROC_INTEL_486DX4), PROC_INTEL_486DX4);
                break;
            }
            break;

        case 5:
            switch (model) { // extract model code
            case 1:
            case 2:
            case 3:
                strcpy_s (m_name, sizeof(PROC_INTEL_PENTIUM), PROC_INTEL_PENTIUM);
                break;
            case 4:
                strcpy_s (m_name, sizeof(PROC_INTEL_PENTIUM_MMX), PROC_INTEL_PENTIUM_MMX);
                break;
            }
            break;

        case 6:
            switch (model) { // extract model code
            case 1:
                strcpy_s (m_name, sizeof(PROC_INTEL_PENTIUM_PRO), PROC_INTEL_PENTIUM_PRO);
                break;
            case 3:
            case 5:
                strcpy_s (m_name, sizeof(PROC_INTEL_PENTIUM_II), PROC_INTEL_PENTIUM_II);
                break;  // actual differentiation depends on cache settings
            case 6:
                strcpy_s (m_name, sizeof(PROC_INTEL_CELERON), PROC_INTEL_CELERON);
                break;
            case 7:
            case 8:
            case 10:
                strcpy_s (m_name, sizeof(PROC_INTEL_PENTIUM_III), PROC_INTEL_PENTIUM_III);
                break;  // actual differentiation depends on cache settings
            }
            break;

        case 15 | (0x00 << 4): // family 15, extended family 0x00
            switch (model) {
            case 0:
                strcpy_s (m_name, sizeof(PROC_INTEL_PENTIUM_4), PROC_INTEL_PENTIUM_4);
                break;
            }
            break;
        }
    }
    else if (!strncmp("CyrixInstead", v_name, 12)) {
        strcpy_s (m_name, sizeof(PROC_CYRIX), PROC_CYRIX);
    }
    else if (!strncmp("CentaurHauls", v_name, 12)) {
        strcpy_s (m_name, sizeof(PROC_CENTAUR), PROC_CENTAUR);
    }

    if (!m_name[0]) {
        strcpy_s (m_name, sizeof(PROC_UNKNOWN), PROC_UNKNOWN);
    }
}


/***
*
* int _cpuid (_p_info *pinfo)
*
* Entry:
*
*   pinfo: pointer to _p_info.
*
* Exit:
*
*   Returns int with capablity bit set even if pinfo = NULL
*
****************************************************/


int _cpuid (_p_info *pinfo)
{
    DWORD dwStandard = 0;
    DWORD dwFeature = 0;
    DWORD dwMax = 0;
    DWORD dwExt = 0;
    int feature = 0;
    int os_support = 0;
    union {
		char cBuf[MAX_VNAME_LENGTH + 1]; // add one for the null terminator
        struct {
            DWORD dw0;
            DWORD dw1;
            DWORD dw2;
        } s;
    } Ident;

    if (!IsCPUID()) {
        return 0;
    }

    _asm {
        push ebx
        push ecx
        push edx

        // get the vendor string
        xor eax, eax
        cpuid
        mov dwMax, eax
        mov Ident.s.dw0, ebx
        mov Ident.s.dw1, edx
        mov Ident.s.dw2, ecx

        // get the Standard bits
        mov eax, 1
        cpuid
        mov dwStandard, eax
        mov dwFeature, edx

        // get AMD-specials
        mov eax, 80000000h
        cpuid
        cmp eax, 80000000h
        jc notamd
        mov eax, 80000001h
        cpuid
        mov dwExt, edx

notamd:
        pop ecx
        pop ebx
        pop edx
    }

    if (dwFeature & _MMX_FEATURE_BIT) {
        feature |= _CPU_FEATURE_MMX;
        if (_os_support(_CPU_FEATURE_MMX))
            os_support |= _CPU_FEATURE_MMX;
    }
    if (dwExt & _3DNOW_FEATURE_BIT) {
        feature |= _CPU_FEATURE_3DNOW;
        if (_os_support(_CPU_FEATURE_3DNOW))
            os_support |= _CPU_FEATURE_3DNOW;
    }
    if (dwFeature & _SSE_FEATURE_BIT) {
        feature |= _CPU_FEATURE_SSE;
        if (_os_support(_CPU_FEATURE_SSE))
            os_support |= _CPU_FEATURE_SSE;
    }
    if (dwFeature & _SSE2_FEATURE_BIT) {
        feature |= _CPU_FEATURE_SSE2;
        if (_os_support(_CPU_FEATURE_SSE2))
            os_support |= _CPU_FEATURE_SSE2;
    }

    if (pinfo) {
        memset(pinfo, 0, sizeof(_p_info));

        pinfo->os_support = os_support;
        pinfo->feature = feature;
        pinfo->family = (dwStandard >> 8) & 0xF; // retrieve family
        if (pinfo->family == 15) {               // retrieve extended family
            pinfo->family |= (dwStandard >> 16) & 0xFF0;
        }
        pinfo->model = (dwStandard >> 4) & 0xF;  // retrieve model
        if (pinfo->model == 15) {                // retrieve extended model
            pinfo->model |= (dwStandard >> 12) & 0xF;
        }
        pinfo->stepping = (dwStandard) & 0xF;    // retrieve stepping

        Ident.cBuf[MAX_VNAME_LENGTH] = 0;
        strcpy_s(pinfo->v_name, MAX_VNAME_LENGTH + 1, Ident.cBuf);

        map_mname(pinfo->family, 
                  pinfo->model,
                  pinfo->v_name,
                  pinfo->model_name);

        pinfo->checks = _CPU_FEATURE_MMX |
                        _CPU_FEATURE_SSE |
                        _CPU_FEATURE_SSE2 |
                        _CPU_FEATURE_3DNOW;
    }

    return feature;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder Parola Bilgi Teknolojileri Ltd.
Turkey Turkey
He was born in Bursa, Turkey in 1979, and still lives in this fascinating place.

He started programming with Fortran when he was at university and then has experienced with MS Visual Basic, Borland Delphi, Java, C++ and C#.

He developed database based several client-server and multi-tier applications using OO concepts and OOP. He worked with Oracle, MySQL, MSSQL and Firebird RDBMS.

In the past, he worked on freetime image processing projects using OpenGL, DirectX, SDL technologies. He's interested in encryption/decryption and compression/decompression algorithms, random number generators and computational algorithms such as Monte Carlo Methods.

In 2011, he founded Parola Information Technology Ltd.

http://www.markanabak.com.tr is serviced by Parola Information Technology Ltd. It's a SAAS model for Intellectual Property sector.

Comments and Discussions