/* By: Daniel Bertrand Date: Nov 6th, 2000 Description: A software implementation of creatives LOG and EXP instructions found in the emu10k1 processor. (Patent: WO 9901814 (A1)) I'm not sure if this is even legal, being a software implementation of a patented hardware instruction, so I'm releasing it into the public domain (no license, no copyright). Compiling: exp: gcc explog.c -o exp usage: ./exp log: gcc explog.c -DLOG -o log usage: ./log -- log converts linear to logarithmic exp converts logarithmic to linear Logarithmic representation: | 31 |30 29-25|28-24 0| |sign| exponent | Mantissa | exponent size varies between 2 and 5 bits, is specified in actual value, thus 3 bits is =7 max_exp_size can be anyvalue between 2 and 31. */ #include #include __u32 log(__s32 lin_data,__u32 Max_Exp,__u32 sign_ctrl) { __u8 sign; int Exp=(int)Max_Exp+1; int Max_Exp_tmp=Max_Exp; int count=0; __u32 result; //FIX ME: mask inputs (i think this is what it does, haven't checked it yet): sign_ctrl= 0x3 & sign_ctrl; if(Max_Exp=(0x1f & Max_Exp) <2) Max_Exp==2; if( (sign = (lin_data>>31)) !=0 ) lin_data= ~lin_data; while( lin_data>0 ){ lin_data=lin_data<<1; Exp--; if(Exp==0) goto build_result; } lin_data=lin_data<<1; build_result: result=(__u32)lin_data; if (Max_Exp & 0x10) result=(( result>>7 ) | ( Exp<<25 )) ; else if(Max_Exp & 0x8) result=(( result>>6 ) | ( Exp<<26 )) ; else if(Max_Exp & 0x4) result=(( result>>5 ) | ( Exp<<27 )); else result=(( result>>4 ) | ( Exp<<28 )) ; /* Sign control ------------ the result is complemented depending on the following conditions |----------------|----------|---------| | Sign Control | sign=0 | sign=1 | |----------------|----------|---------| | 00 | R | ~R | |----------------|----------|---------| | 01 | R | R | |----------------|----------|---------| | 10 | ~R | ~R | |----------------|----------|---------| | 11 | ~R | R | |----------------|----------|---------| */ switch( sign_ctrl){ case 0: if(sign!=0) result= ~result; return result; case 1: return result; case 2: return ~result; case 3: if(sign==0) result= ~result; return result; } //All that was one instruction, hardware rules :-) } __s32 exp(__u32 log_data,__u32 Max_Exp,__u32 sign_ctrl) { __u8 sign; __u32 result; int num_shifts; __u32 Exp; //FIX ME: mask inputs (i think this is what it does, haven't checked it yet): Max_Exp=0x1f&Max_Exp; sign_ctrl=0x3&sign_ctrl; if(Max_Exp<2) Max_Exp==2; if( (sign=log_data>>31) !=0 ) log_data=~log_data; //seperate mantissa and exponent if(Max_Exp&16){ Exp=log_data>>26; log_data=log_data<<5; } else if(Max_Exp&8){ Exp=log_data>>27; log_data=log_data<<4; } else if(Max_Exp&4){ Exp= log_data>>28; log_data=log_data<<3; } else{ Exp= log_data>>29 ; log_data=log_data<<2; } //put back the implicit 1 if(Exp!=0){ log_data=log_data|0x80000000; Exp--; } //shift mantissa back down result=log_data>>(Max_Exp-Exp); //handle sign switch( sign_ctrl){ case 0: if(sign!=0) result= ~result; return result; case 1: return result; case 2: return ~result; case 3: if(sign==0) result= ~result; return result; } } int main (int argc, char *argv[]) { if(argc!=4){ printf("usage: log "); return -1; } #ifdef LOG printf("0x%08x\n",log(strtoul(argv[1],NULL,16),strtoul(argv[2],NULL,16),strtoul(argv[3],NULL,16) )); #else printf("0x%08x\n",exp(strtoul(argv[1],NULL,16),strtoul(argv[2],NULL,16),strtoul(argv[3],NULL,16) )); #endif return 0; }