1
0
mirror of https://github.com/mist-devel/mist-board.git synced 2026-01-25 11:26:47 +00:00
2014-01-31 12:21:39 +00:00

242 lines
3.8 KiB
C

/* vmath.c 96-bit integer and floating point routines for vasm */
/* (c) in 2002 by Frank Wille */
#include "vasm.h"
#include <math.h>
static int96 one = { 1,0,0,0,0,0,0,0,0,0,0,0 };
unsigned char *int96_assign32(unsigned char *x,int32_t val)
{
int i;
for (i=0; i<4; i++) {
x[i] = val & 0xff;
val >>= 8;
}
memset(&x[4],(x[3] & 0x80)?0xff:0,8);
return x;
}
unsigned char *int96_assign64(unsigned char *x,int64_t val)
{
int i;
for (i=0; i<8; i++) {
x[i] = val & 0xff;
val >>= 8;
}
memset(&x[8],(x[7] & 0x80)?0xff:0,4);
return x;
}
unsigned char *int96_add(unsigned char *x,unsigned char *y)
{
unsigned char s,v;
int i;
for (i=0,v=0; i<12; i++) {
s = x[i] + y[i] + v;
v = s<x[i] || s<y[i];
x[i] = s;
}
return x;
}
unsigned char *int96_add32(unsigned char *x,int32_t val)
{
int96 y;
return int96_add(x,int96_assign32(y,val));
}
unsigned char *int96_add64(unsigned char *x,int64_t val)
{
int96 y;
return int96_add(x,int96_assign64(y,val));
}
unsigned char *int96_negate(unsigned char *x)
{
int i;
for (i=0; i<12; i++)
x[i] = ~x[i];
return int96_add(x,one);
}
unsigned char *int96_lshleft(unsigned char *x,int cnt)
{
unsigned short old=0,new;
int i,sh;
while (cnt > 0) {
sh = (cnt > 8) ? 8 : cnt;
for (i=0; i<12; i++) {
new = (unsigned short)x[i] << sh;
x[i] = (new & 0xff) | ((old >> 8) & 0xff);
old = new;
}
cnt -= sh;
}
return x;
}
unsigned char *int96_lshright(unsigned char *x,int cnt)
{
unsigned short old=0,new;
int i,sh;
while (cnt > 0) {
sh = (cnt > 8) ? 8 : cnt;
for (i=11; i>=0; i--) {
new = ((unsigned short)x[i]<<8) >> sh;
x[i] = (old & 0xff) | ((new >> 8) & 0xff);
old = new;
}
cnt -= sh;
}
return x;
}
unsigned char *int96_ashright(unsigned char *x,int cnt)
{
unsigned short new;
unsigned short old = (x[11]>=0x80) ? 0xffff : 0;
int i,sh;
while (cnt > 0) {
sh = (cnt > 8) ? 8 : cnt;
for (i=11; i>=0; i--) {
new = ((unsigned short)x[i]<<8) >> sh;
x[i] = (old & 0xff) | ((new >> 8) & 0xff);
old = new;
}
cnt -= sh;
}
return x;
}
unsigned char *int96_mulu(unsigned char *x,unsigned char *y)
{
int i,j;
uint16_t m;
unsigned char p[13];
int96 sum;
memset(sum,0,12);
memset(p,0,13);
for (i=0; i<12; i++) {
for (j=0; j<(12-i); j++) {
m = (uint16_t)x[i] * (uint16_t)y[j];
p[i+j] = m & 0xff;
p[i+j+1] = (m >> 8) & 0xff;
int96_add(sum,p);
p[i+j] = p[i+j+1] = 0;
}
}
memcpy(x,sum,12);
return x;
}
unsigned char *int96_muls(unsigned char *x,unsigned char *y)
{
int neg = 0;
if (x[11] >= 0x80) {
neg = 1;
int96_negate(x);
}
if (y[11] >= 0x80) {
neg ^= 1;
int96_negate(y);
}
int96_mulu(x,y);
if (neg)
int96_negate(x);
return x;
}
long double int96_conv2longdouble(unsigned char *x)
{
long double f = 0.0;
long double m = 1.0;
int i,neg=0;
if (x[11] >= 0x80) {
neg = 1;
int96_negate(x);
}
for (i=0; i<12; i++) {
f += (long double)x[i] * m;
m *= 256.0;
}
return neg ? -f : f;
}
int int96_cntz(unsigned char *x)
{
int cnt = 0;
int i;
for (i=11; i>=0; i--) {
unsigned char v = x[i];
unsigned char m = 0x80;
for (m=0x80; m; m>>=1) {
if (v & m) {
i = -1;
break;
}
cnt++;
}
}
return cnt;
}
int int96_compare(unsigned char *x,unsigned char *y)
{
int96 cmp;
int i;
for (i=0; i<12; i++)
cmp[i] = ~y[i];
int96_add(cmp,one);
int96_add(cmp,x);
for (i=0; i<12; i++) {
if (cmp[i])
return cmp[11]>=0x80 ? -1 : 1;
}
return 0;
}
void int96_copybe(unsigned char *d,unsigned char *x,int len)
{
int i;
for (i=len-1; i>=0; i--)
*d++ = x[i];
}
void int96_copyle(unsigned char *d,unsigned char *x,int len)
{
memcpy(d,x,len);
}