FPU fp32 Multiplier 알고리즘 검증코드

YumeIroVillain·2022년 9월 17일
0

졸프Project

목록 보기
5/9
/*
    FPU Multiplier
    M48 처리하는 새 알고리즘 적용
*/

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
// #define VERBOSE
#define RANDOM
#define ULL unsigned long long

int called = 0;

struct float16{ // 1 5 10
    union{
        struct{
            unsigned short sign : 1;
            unsigned short exponent : 5;
            unsigned short mantissa : 10;
        };
        unsigned short total;
    };
};

struct float32{ // 1 8 23
    union{
        struct{
            unsigned int mantissa : 23;
            unsigned short exponent : 8;
            unsigned short sign : 1;
        };
        float total;
        int total_int;
    };
};

/* When first call, put depth := 1
 * 
*/
void print_binary_rec(unsigned long long foo, unsigned long long depth)
{
    int ret;
    if(foo) {
        print_binary_rec((unsigned long long)foo>>1, depth+1);
        if(depth%4) printf("%llu",foo&1);
        else printf("_%llu",foo&1);
    }
}

void print_binary(unsigned long long foo)
{
    // printf("foo = %d %f\n", foo.total_int, foo.total);
    if(foo == 0)
        printf("0");
    else
        print_binary_rec(foo,1);
}

void float32_printer(struct float32 f32, char* name)
{
    printf("%s: %f\n",name, f32.total);
    printf("%s.sign: ", name);
    print_binary(f32.sign); printf("\n");
    printf("%s.exponent(%d): ", name, f32.exponent);
    print_binary(f32.exponent); printf("\n");
    printf("%s.mantissa: ", name);
    print_binary(f32.mantissa); printf("\n");
    printf("%s.total(%f): ", name, f32.total);
    print_binary(f32.total_int); printf("\n");
}

struct float32 norm;
struct float32 pos_infinity;
struct float32 neg_infinity;
struct float32 pos_not_a_number;
struct float32 neg_not_a_number;
struct float32 pos_zero;
struct float32 neg_zero;
struct float32 f32_arr[9];

void edge_test(int a, int b){
    struct float32 tmp;
    tmp.total = f32_arr[a].total + f32_arr[b].total;
    char name[20];
    sprintf(name, "result %d: %d >>> ", a, b);
    float32_printer(tmp, name);
    printf("\n");
    if(b==6){
        if(a==6){
            return;
        }
        else
            edge_test(a+1,0);
    }
    else
        edge_test(a,b+1);
}
void edge_setting(){
    struct float32 f32;
    f32.total = 0.75;

    float32_printer(f32, "f32");
    printf("\n");
    f32.exponent = f32.exponent - 1;
    float32_printer(f32, "f32");
    printf("\n");
    
    pos_infinity.sign = 0;
    pos_infinity.exponent = 0b11111111;
    pos_infinity.mantissa = 0;
    float32_printer(pos_infinity, "pos_infinity");
    printf("\n");
    
    neg_infinity.sign = 1;
    neg_infinity.exponent = 0b11111111;
    neg_infinity.mantissa = 0;
    float32_printer(neg_infinity, "neg_infinity");
    printf("\n");
    
    pos_not_a_number.sign = 0;
    pos_not_a_number.exponent = 0b11111111;
    pos_not_a_number.mantissa = 0b1111111111111111111;
    float32_printer(pos_not_a_number, "pos_not_a_number");
    printf("\n");
    
    neg_not_a_number.sign = 1;
    neg_not_a_number.exponent = 0b11111111;
    neg_not_a_number.mantissa = 0b1111111111111111111;
    float32_printer(neg_not_a_number, "neg_not_a_number");
    printf("\n");
    
    pos_zero.sign = 0;
    pos_zero.exponent = 0;
    pos_zero.mantissa = 0;
    float32_printer(pos_zero, "pos_zero");
    printf("\n");
    
    neg_zero.sign = 1;
    neg_zero.exponent = 0;
    neg_zero.mantissa = 0;
    float32_printer(neg_zero, "neg_zero");
    printf("\n");
    
    norm.total = 0.5;
    
    f32_arr[0] = norm;
    f32_arr[1] = pos_infinity;
    f32_arr[2] = neg_infinity;
    f32_arr[3] = pos_not_a_number;
    f32_arr[4] = neg_not_a_number;
    f32_arr[5] = pos_zero;
    f32_arr[6] = neg_zero;
}
int leading_1_detector(int tmp)
{
    if(tmp & 1<<23){
        return 0;   
    }else if(tmp & 1<<22){
        return 1;
    }else if(tmp & 1<<21){
        return 2;
    }else if(tmp & 1<<20){
        return 3;
    }else if(tmp & 0b00000000000010000000000000000000){
        return 4;
    }else if(tmp & 0b00000000000001000000000000000000){
        return 5;
    }else if(tmp & 0b00000000000000100000000000000000){
        return 6;
    }else if(tmp & 0b00000000000000010000000000000000){
        return 7;
    }else if(tmp & 0b00000000000000001000000000000000){
        return 8;
    }else if(tmp & 0b00000000000000000100000000000000){
        return 9;
    }else if(tmp & 0b00000000000000000010000000000000){
        return 10;
    }else if(tmp & 0b00000000000000000001000000000000){
        return 11;
    }else if(tmp & 0b00000000000000000000100000000000){
        return 12;
    }else if(tmp & 0b00000000000000000000010000000000){
        return 13;
    }else if(tmp & 0b00000000000000000000001000000000){
        return 14;
    }else if(tmp & 0b00000000000000000000000100000000){
        return 15;
    }else if(tmp & 0b00000000000000000000000010000000){
        return 16;
    }else if(tmp & 0b00000000000000000000000001000000){
        return 17;
    }else if(tmp & 0b00000000000000000000000000100000){
        return 18;
    }else if(tmp & 0b00000000000000000000000000010000){
        return 19;
    }else if(tmp & 0b00000000000000000000000000001000){
        return 20;
    }else if(tmp & 0b00000000000000000000000000000100){
        return 21;
    }else if(tmp & 0b00000000000000000000000000000010){
        return 22;
    }else if(tmp & 0b00000000000000000000000000000001){
        return 23;
    }else{
        return 0;
    }
}

int leading_1_detector_48bit(unsigned long long tmp){
    if(tmp & (unsigned long long)1<<47){
        return 47; // "leading 1 is at 47th bit"
    }
    else if(tmp & (unsigned long long)1<<46){
        return 46;
    }
    else if(tmp & (unsigned long long)1<<45){
        return 45;
    }
    else if(tmp & (unsigned long long)1<<44){
        return 44;
    }
    else if(tmp & (unsigned long long)1<<43){
        return 43;
    }
    else if(tmp & (unsigned long long)1<<42){
        return 42;
    }
    else if(tmp & (unsigned long long)1<<41){
        return 41;
    }
    else if(tmp & (unsigned long long)1<<40){
        return 40;
    }
    else if(tmp & (unsigned long long)1<<39){
        return 39;
    }
    else if(tmp & (unsigned long long)1<<38){
        return 38;
    }
    else if(tmp & (unsigned long long)1<<37){
        return 37;
    }
    else if(tmp & (unsigned long long)1<<36){
        return 36;
    }
    else if(tmp & (unsigned long long)1<<35){
        return 35;
    }
    else if(tmp & (unsigned long long)1<<34){
        return 34;
    }
    else if(tmp & (unsigned long long)1<<33){
        return 33;
    }
    else if(tmp & (unsigned long long)1<<32){
        return 32;
    }
    else if(tmp & (unsigned long long)1<<31){
        return 31;
    }
    else if(tmp & (unsigned long long)1<<30){
        return 30;
    }
    else if(tmp & (unsigned long long)1<<29){
        return 29;
    }
    else if(tmp & (unsigned long long)1<<28){
        return 28;
    }
    else if(tmp & (unsigned long long)1<<27){
        return 27;
    }
    else if(tmp & (unsigned long long)1<<26){
        return 26;
    }
    else if(tmp & (unsigned long long)1<<25){
        return 25;
    }
    else if(tmp & (unsigned long long)1<<24){
        return 24;
    }
    else if(tmp & (unsigned long long)1<<23){
        return 23;
    }
    else if(tmp & (unsigned long long)1<<22){
        return 22;
    }
    else if(tmp & (unsigned long long)1<<21){
        return 21;
    }
    else if(tmp & (unsigned long long)1<<20){
        return 20;
    }
    else if(tmp & (unsigned long long)1<<19){
        return 19;
    }
    else if(tmp & (unsigned long long)1<<18){
        return 18;
    }
    else if(tmp & (unsigned long long)1<<17){
        return 17;
    }
    else if(tmp & (unsigned long long)1<<16){
        return 16;
    }
    else if(tmp & (unsigned long long)1<<15){
        return 15;
    }
    else if(tmp & (unsigned long long)1<<14){
        return 14;
    }
    else if(tmp & (unsigned long long)1<<13){
        return 13;
    }
    else if(tmp & (unsigned long long)1<<12){
        return 12;
    }
    else if(tmp & (unsigned long long)1<<11){
        return 11;
    }
    else if(tmp & (unsigned long long)1<<10){
        return 10;
    }
    else if(tmp & (unsigned long long)1<<9){
        return 9;
    }
    else if(tmp & (unsigned long long)1<<8){
        return 8;
    }
    else if(tmp & (unsigned long long)1<<7){
        return 7;
    }
    else if(tmp & (unsigned long long)1<<6){
        return 6;
    }
    else if(tmp & (unsigned long long)1<<5){
        return 5;
    }
    else if(tmp & (unsigned long long)1<<4){
        return 4;
    }
    else if(tmp & (unsigned long long)1<<3){
        return 3;
    }
    else if(tmp & (unsigned long long)1<<2){
        return 2;
    }
    else if(tmp & (unsigned long long)1<<1){
        return 1;
    }
    else if(tmp & (unsigned long long)1){
        return 0;
    }
    else{
        return -1; // NO leading 1
    }
}

int my_multiplier(struct float32 alpha, struct float32 bravo)
{
    printf("alpha(0x%08llx %f) is ",(ULL)alpha.total_int, alpha.total); print_binary((ULL)alpha.total_int); printf("\n");
    printf("bravo(0x%08llx %f) is ",(ULL)bravo.total_int, bravo.total); print_binary((ULL)bravo.total_int); printf("\n");

    struct float32 charlie, delta; // charlie: Correct answer
    charlie.total = alpha.total * bravo.total;
    /**************** Get Larger Exponent ***************/
    int EA, EA0, EA1, EB, EB0, EB1, EA_minus_EB, EB_minus_EA;
    int Larger_E, Right_Shift;
    int E_LeftBig, E_RightBig, E_Equal;
    EA = alpha.exponent;
    EB = bravo.exponent;
    if (EA==0b00000000){
        EA0 = 1;
        EA1 = 0;
    } else if (EA==0b11111111){
        EA0 = 0;
        EA1 = 1;
    }else{
        EA0 = 0;
        EA1 = 0;
    }
    if (EB==0b00000000){
        EB0 = 1;
        EB1 = 0;
    } else if (EB==0b11111111){
        EB0 = 0;
        EB1 = 1;
    }else{
        EB0 = 0;
        EB1 = 0;
    }
    EA_minus_EB = EA - EB; // 9bit
    EB_minus_EA = EB - EA; // 9bit
    // E_RightBig = ((EA_minus_EB & 0b100000000) != 0);
    // E_LeftBig = ((EB_minus_EA & 0b100000000) != 0);
    E_RightBig = (EA < EB); // 일단 대소판별기는 임시로 이렇게 때운다. 만들면 되니까.
    E_LeftBig = (EA > EB);
    E_Equal = !(E_RightBig | E_LeftBig);
    Larger_E = ((E_LeftBig) ? EA : EB);
    Right_Shift = ((E_LeftBig) ? EA_minus_EB : EB_minus_EA);
    if(EA0 ^ EB0){ // 만약 하나의 E만 전부 0이면
        Right_Shift--;
    }
    /* 
    이걸 구현하려면 또 Carry Adder 만들어야하니, 앗싸리 EA 또는 EB가 0이면 1로 올려주는 방안을 고려할 필요가 있음.
    왜냐하면 어차피 denormalized number 의 E-127에서 E는 0이 아니라 1로 취급됨.
    */

    #ifdef VERBOSE
    printf(" \
    EA = %d \
    EA0 = %d \
    EA1 = %d \
    \n \
    EB = %d \
    EB0 = %d \
    EB1 = %d \
    \n \
    EA_minus_EB = %d \
    EB_minus_EA = %d \
    \n \
    E_LeftBig = %d \
    E_RightBig = %d \
    E_Equal = %d \
    \n \
    Larger_E = %d \
    Right_Shift = %d \
    \n", EA, EA0, EA1, EB, EB0, EB1, 
    EA_minus_EB, EB_minus_EA,
    E_LeftBig, E_RightBig, E_Equal,
    Larger_E, Right_Shift);
    #endif

    // 순서유의
    // 이 때, EA_minus_EB는 후에 다 EA0 봐가면서 보정이 되어있으므로 여기서 바꿔야함. 이보다 앞에서 바꿔버리면 꼬임.
    if(EA == 0) EA = 1; // denorm 의 exp는 -126취급.
    if(EB == 0) EB = 1;
    
    /*************************** ADD Exponent ***************************/
    int EA_plus_EB = EA + EB; // EA and EB is unsigined int
    int EA_plus_EB_minus_254 = EA_plus_EB - 254;

    #ifdef VERBOSE
    printf("ADD EXPONENT\n");
    printf("EA_plus_EB is %d\n",EA_plus_EB);
    printf("EA_plus_EB_minus_254 is %d\n",EA_plus_EB_minus_254);
    #endif
    
    /*************************** Get Sign ***************************/
    int SA, SB;
    SA = alpha.sign; SB = bravo.sign;
    int final_sign = SA ^ SB;

    /*********************** Setting up Multiply Mantissa ******************************/
    int MA, MB, isDenorm1, isDenorm2, isDenorm3, isDenorm4;
    int Denorm1, Denorm2;
    int M_RightBig, M_LeftBig, M_Equal, MA0, MB0;
    
    MA = alpha.mantissa; MB = bravo.mantissa;
    
    M_LeftBig = MA > MB;
    M_RightBig = MA < MB;
    M_Equal = (MA == MB);

    MA0 = ((MA==0) ? 1 : 0); MB0 = ((MB==0) ? 1 : 0);
    isDenorm1 = ((!EA0)<<23) | MA;
    isDenorm2 = MA;
    isDenorm3 = ((!EB0)<<23) | MB;
    isDenorm4 = MB;
    Denorm1 = ((EA0&&(!MA0)) ? isDenorm2 : isDenorm1);
    Denorm2 = ((EB0&&(!MB0)) ? isDenorm4 : isDenorm3);
    
    #ifdef VERBOSE
    printf(" \
    M_LeftBig = %d \
    M_RightBig = %d \
    M_Equal = %d \
    \n"
    , M_LeftBig, M_RightBig, M_Equal);
    #endif

    #ifdef VERBOSE
    printf("Denorm1(0x%x) is ",Denorm1); print_binary(Denorm1); printf("\n");
    printf("Denorm2(0x%x) is ",Denorm2); print_binary(Denorm2); printf("\n");
    #endif

    /******************************** Multiply Mantissa ******************************/
    unsigned long long M_48_Original = (unsigned long long) Denorm1 * (unsigned long long) Denorm2;

    int G, R, S;
    int leading_1_position = leading_1_detector_48bit(M_48_Original);
    #ifdef VERBOSE
    printf("M_48_Original == d1 * d2 = 0x%llx\n", M_48_Original);
    printf("leading_1_position %d\n", leading_1_position);
    #endif
    unsigned long long M_48 = M_48_Original;

    /*         Dealing with   M48             */
    int E = EA_plus_EB_minus_254;
    int Exp;
    int UDFL = 0;
    int OVFL = 0;
    if(E > -126){
        if(leading_1_position == 47){
            M_48>>=1;
            E++;
        }
        else if(leading_1_position == 46){
            // Do nothing
        }
        else{
            int Until_46th_Filled = 46 - leading_1_position;
            M_48 <<= Until_46th_Filled;
            E -= Until_46th_Filled;
        }
        Exp = E + 127;
        if(E > 127){
            OVFL = 1;
        }
    }// 둘다 elseif 가 아니라 if임에 유의
    leading_1_position = leading_1_detector_48bit(M_48);
    if(E < -126){
        int Until_126 = -126 - E;
        printf("E == %d\n",E);
        printf("Until_126 == %d\n",Until_126);
        if(Until_126 < 48) M_48>>=Until_126;
        else M_48 = 0;
        E += Until_126;
        printf("E == %d\n",E);
    }
    leading_1_position = leading_1_detector_48bit(M_48);
    if(E == -126){
        if(leading_1_position == 47){
            M_48>>=1;
            E = -125;
            Exp = 2;
        }
        else if(leading_1_position == 46){
            E = -126;
            Exp = 1;
        }
        else{
            E = -126;
            Exp = 0;
        }
    }
    #ifdef VERBOSE
    printf("mid(Before Hiding) M_48(0x%llx) is ", M_48); print_binary(M_48); printf("\n");
    printf("E is %d\n",E);
    printf("Exp is %d\n",Exp);
    #endif
    // Hide M48's 46th bit
    M_48 = M_48 & 0x3FFFFFFFFFFF;
    // Get G R S
    G = (M_48 & 0x800000) == 0 ? 0 : 1;
    R = (M_48 & 0x400000) == 0 ? 0 : 1;
    S = (M_48 & 0x3FFFFF) == 0 ? 0 : 1;
    // Get M_48[45:23]
    M_48 >>= 23;
    if((R==1 && S==1) || (G==1 && R==1 && S==0))
        M_48++;
    // rounding 고려시 추가 normalization 필요하지만, 일단 구현안함

    int NAN = 0;
    if((EA == 0xFF && MA != 0) || (EB == 0xFF && MB != 0))
        NAN = 1;

    delta.sign = final_sign;
    if(OVFL){ // INF
        Exp = 0xFF;
        M_48 = 0;
    }
    if(NAN){
        Exp = 0xFF;
        M_48 = 0xFFFFFF;
    }
    delta.exponent = Exp;
    delta.mantissa = M_48;


    #ifdef VERBOSE
    printf("final M_48(0x%llx) is ",M_48); print_binary(M_48); printf("\n");
    printf("G: %d\n", G);
    printf("R: %d\n", R);
    printf("S: %d\n", S);
    printf("OVFL: %d\t UDFL: %d\n",OVFL, UDFL);

    float32_printer(alpha, "alpha");
    float32_printer(bravo, "bravo");
    float32_printer(charlie, "charlie");
    float32_printer(delta, "delta");
    #endif

    printf("delta.total(%f) : 0b", delta.total); print_binary(delta.total_int); printf("\n");
    printf("charlie.total(%f) : 0b", charlie.total); print_binary(charlie.total_int); printf("\n");
    printf("charlie vs delta : %f vs %f\n", charlie.total, delta.total);
    if(charlie.total == delta.total) printf("SAME\n");
    else printf("ERROR!!!\n");

    called++;
    printf("my_multiplier: called = %dth\n", called);
    printf("*********************** %f * %f END*********************\n", alpha.total, bravo.total);
}

int main()
{
    printf("Hello World\n");
    
    // float32_printer(cc, "cc");
    struct float32 aa, bb, cc;

    // 이하 통과시켜야함
    aa.total_int = 89489864; bb.total_int = 817591348; // exp 10 * exp 97 != zero(왜냐하면 생존 mantissa가 있다)
    my_multiplier(aa, bb);

    aa.total_int = 89489864; 
    bb.total_int = 817591348; bb.mantissa = 0; bb.exponent = 117; // exp == 0
    my_multiplier(aa, bb);

    aa.total_int = 0x007fffff; bb.total_int = 0x007fffff; // Maximum denorm mult ^ 2
    my_multiplier(aa, bb);
    
    // 이하 해결

    // 예시: https://stackoverflow.com/questions/51661257/binary-floating-point-addition-algorithm
    aa.total_int = 0b00001000111100110110010010011100; 
    bb.total_int = 0b00000000000011000111111010000100; 
    float32_printer(aa, "aa");
    float32_printer(bb, "bb");
    my_multiplier(aa, bb); // 뒈짓

    aa.total_int = 0x800000; bb.total_int = 0x800000; // Min norm ^ 2 == denorm???
    my_multiplier(aa, bb); // 뒈짓
    
    aa.total_int = 0x407FFFFF; bb.total_int = 0x407FFFFF; // Make 47th Mantissa 1, and result not INF
    my_multiplier(aa, bb);

    aa.total_int = 0x7f7fffff; bb.total_int = 0x007fffff; // Maximum norm mult * Maximum denorm mult
    my_multiplier(aa, bb);

    aa.total_int = 1656830887; bb.total_int = 1386443347;
    my_multiplier(aa, bb);


    
    aa.total_int = 1352740975; bb.total_int = 1207161653; // 터짐
    float32_printer(aa, "aa");
    float32_printer(bb, "bb");
    my_multiplier(aa, bb);

    aa.total_int = 1173666029; bb.total_int = 1167651708; // 아마 R==1 S==1이라서 mantissa++ 해줘야할듯?
    float32_printer(aa, "aa");
    float32_printer(bb, "bb");
    my_multiplier(aa, bb);

    aa.total_int = 977394179; bb.total_int = 961550550;
    float32_printer(aa, "aa");
    float32_printer(bb, "bb");
    my_multiplier(aa, bb);

    aa.total = 0.5; bb.total = 0.4375;
    my_multiplier(aa, bb); 

    aa.total = 0.5; bb.total = -0.4375;
    my_multiplier(aa, bb);
    aa.total = 0.5; bb.total = 0.75;
    my_multiplier(aa, bb);
    aa.total = -0.5; bb.total = 0.75;
    my_multiplier(aa, bb);
    aa.total = -0.5; bb.total = -0.75;  
    my_multiplier(aa, bb);
    // cc.total = aa.total + bb.total;

    aa.total_int = 551542477; bb.total_int = 1881522032;
    my_multiplier(aa, bb);
    // 여기까지 전부 통과



/*
    // 47th mantissa == 1
    aa.total_int = 89489864; 
    bb.total_int = 817591348; bb.exponent = 118; // exp == -126==1-127 +1(since mantissa 47th)
    my_multiplier(aa, bb);

    aa.total_int = 89489864; 
    bb.total_int = 817591348; bb.exponent = 117; // exp == 1 (since mantissa + 1)
    my_multiplier(aa, bb);

    aa.total_int = 89489864; 
    bb.total_int = 817591348; bb.exponent = 116; // exp == 0
    my_multiplier(aa, bb);
*/
    #ifdef RANDOM
    srand(time(NULL));
    for(int i=0;i<100000;i++){
        aa.total_int = rand();
        bb.total_int = rand();
        printf("aa.total_int: %d\n",aa.total_int);
        printf("bb.total_int: %d\n",bb.total_int);
        float32_printer(aa, "aa");
        float32_printer(bb, "bb");
        my_multiplier(aa, bb);
    }
    #endif
    
    return 0;
}

좀더단순히 할수있긴하다.
우선 저장한다.

profile
HW SW 둘다 공부하는 혼종의 넋두리 블로그 / SKKU SSE 17 / SWM 11th

0개의 댓글