Jak jsem si nabehnul aneb double v pacalu na AVR

Jan Waclawek konfera na efton.sk
Úterý Červenec 22 07:19:02 CEST 2014


> Skoro uz jsem chtel udelat test 
> rychlosti ale zrovna jsem nemel po ruce AVR... 

Na to predsa nepotrebujete AVR, staci (ba dokonca je lepsi) simulator.

Vid dole.

Ta celociselna varianta je asi 4060 cyklov, ta s double asi 27000 s
WinAVR20100110 (t.j. avr-gcc 4.3.3). A to som sa prilis nenamahal
optimalizovat... ;-)

Schvalne som nepouzival type punning, aby sa to dalo 1:1 prepisat do
Pascalu - pri volaniach treba pouzit referencie miesto pointrov, ->
nahradit ^., poupravovat definicie, nemalo by to dat privela roboty.

Na druhej strane som v tej variante s double, co som vykopiroval z appnote,
musel upravit dva riadky, inak to vracia dvojnasobny vysledok - nechapem
preco to tak napisal ten co to napisal.

Mozete skusit ten ARM, ked uz ho mate poruke :-)

wek



#include <stdint.h>

#define SHR >>
#define SHL <<
#define OR  |
#define AND &

// #define DEBUG
#ifdef DEBUG
typedef union {
  struct __attribute__((packed)) {
    uint16_t h0;
    uint16_t h1;
    uint16_t h2;
    uint16_t h3;
  };
  uint64_t f;
} h64_t;
#else
typedef struct __attribute__((packed)) {
  uint16_t h0;
  uint16_t h1;
  uint16_t h2;
  uint16_t h3;
} h64_t;
#endif

void umul16_32(h64_t * c, uint16_t b, uint32_t a) {
  uint32_t t;
  t = (a AND 0xFFFF) * b;
  c->h0 = t AND 0xFFFF;
  c->h1 = t SHR 16;
  t = (a SHR 16) * b;
  c->h2 = t SHR 16;
  t = (t AND 0xFFFF) + c->h1;
  c->h1 = t AND 0xFFFF;
  t = (t SHR 16) + c->h2;
  c->h2 = t AND 0xFFFF;
  c->h3 = t SHR 16; // this is always 0 anyway...
}

void umul32_64(h64_t * c, uint32_t b, h64_t * a) {
  h64_t t;
  uint32_t tl;
  
  umul16_32(&t, a->h0, b);
  c->h0 = t.h0; c->h1 = t.h1; c->h2 = t.h2; c->h3 = t.h3;
  umul16_32(&t, a->h1, b);
  tl = (uint32_t)c->h1 + t.h0;
  c->h1 = tl AND 0xFFFF;
  tl = (tl SHR 16) + c->h2 + t.h1;
  c->h2 = tl AND 0xFFFF;
  tl = (tl SHR 16) + c->h3 + t.h2;
  c->h3 = tl AND 0xFFFF;
  umul16_32(&t, a->h2, b);
  tl = (uint32_t)c->h2 + t.h0;
  c->h2 = tl AND 0xFFFF;
  tl = (tl SHR 16) + c->h3 + t.h1;
  c->h3 = tl AND 0xFFFF;
  umul16_32(&t, a->h2, b);
  tl = (uint32_t)c->h3 + t.h0;
  c->h3 = tl AND 0xFFFF;  
}

void shr64(h64_t * c, uint8_t s) {
  if (s < 16) {
    c->h0 = (c->h0 SHR s) OR (c->h1 SHL (16 - s));
    c->h1 = (c->h1 SHR s) OR (c->h2 SHL (16 - s));
    c->h2 = (c->h2 SHR s) OR (c->h3 SHL (16 - s));
    c->h3 = (c->h3 SHR s);
  } else {  // we won't need s = 16 nor s > 32
    s = s - 16;
    c->h0 = (c->h1 SHR s) OR (c->h2 SHL (16 - s));
    c->h1 = (c->h2 SHR s) OR (c->h3 SHL (16 - s));
    c->h2 = (c->h3 SHR s);
	c->h3 = 0;
  }
}

void neg64(h64_t * c) {
  c->h0 = ~c->h0 + 1;
  c->h1 = ~c->h1;
  if (c->h0 == 0) c->h1++;
  c->h2 = ~c->h2;
  if (c->h1 == 0) c->h2++;
  c->h3 = ~c->h3;
  if (c->h2 == 0) c->h3++;
}

void add64(h64_t * c, h64_t * b, h64_t * a) {
  uint32_t t;
  t = a->h0 + b->h0;
  c->h0 = t AND 0xFFFF;
  t = (t SHR 16) + a->h1 + b->h1;
  c->h1 = t AND 0xFFFF;
  t = (t SHR 16) + a->h2 + b->h2;
  c->h2 = t AND 0xFFFF;
  t = (t SHR 16) + a->h3 + b->h3;
  c->h3 = t AND 0xFFFF;
}


uint32_t calcPressure(uint32_t d1, uint32_t d2, uint16_t c1, uint16_t c2,
uint16_t c3, uint16_t c4, uint16_t c5, uint16_t c6)
__attribute__((noinline));
uint32_t calcPressure(uint32_t d1, uint32_t d2, uint16_t c1, uint16_t c2,
uint16_t c3, uint16_t c4, uint16_t c5, uint16_t c6) {
  uint32_t temp32, dt;
  _Bool minus;
  h64_t temp64, off, sens, p;
  
  temp32 = (uint32_t)c5 SHL 8;
  minus = (temp32 > d2);
  if (minus) {
    dt = temp32 - d2;
  } else {
    dt = d2 - temp32;
  }
  
  umul16_32(&off, c4, dt);
  shr64(&off, 7);
  if (minus) {
    neg64(&off);
  }
  temp64.h0 = 0; temp64.h1 = c2; temp64.h2 = 0; temp64.h3 = 0;
  add64(&off, &off, &temp64);
   
  umul16_32(&sens, c3, dt);
  shr64(&sens, 8);
  if (minus) {
    neg64(&sens);
  }
  temp32 = (uint32_t)c1 SHL 15;
  temp64.h0 = temp32 AND 0xFFFF; temp64.h1 = temp32 SHR 16; temp64.h2 = 0;
temp64.h3 = 0;
  add64(&sens, &sens, &temp64);
  
  minus = ((sens.h3 AND 0x8000) != 0);
  if (minus) neg64(&sens);
  umul32_64(&p, d1, &sens);
  if (minus) neg64(&p);
  shr64(&p, 21);
  neg64(&off);
  add64(&p, &p, &off);
  shr64(&p,15);
  
  return ((uint32_t)p.h1 SHL 16) + p.h0;
}

#include <math.h>

double calcPressure2(uint32_t d1, uint32_t d2, uint16_t c1, uint16_t c2,
uint16_t c3, uint16_t c4, uint16_t c5, uint16_t c6)
__attribute__((noinline));
double calcPressure2(uint32_t d1, uint32_t d2, uint16_t c1, uint16_t c2,
uint16_t c3, uint16_t c4, uint16_t c5, uint16_t c6) {
  double P;  // compensated pressure value
//  double T; // compensated temperature value
  double dT;  // difference between actual and measured temperature
  double OFF;  // offset at actual temperature
  double SENS;  // sensitivity at actual temperature
  
  // calcualte 1st order pressure and temperature (MS5607 1st order
algorithm)
  dT=d2-c5*pow(2,8);
//  OFF=(double)c2*pow(2,17)+dT*c4/pow(2,6);
  OFF=(double)c2*pow(2,16)+dT*c4/pow(2,7);
//  SENS=c1*pow(2,16)+dT*c3/pow(2,7);
  SENS=c1*pow(2,15)+dT*c3/pow(2,8);
  // T=(2000+(dT*c6)/pow(2,23))/100;
  P=(((d1*SENS)/pow(2,21)-OFF)/pow(2,15))/100;
  return P;
}


volatile uint32_t p;
volatile double pp;
int main(void) {
  p = calcPressure(9085466, 8569150, 40127, 36924, 23317, 23282, 33464,
28312);
  __asm("nop");
  pp = calcPressure2(9085466, 8569150, 40127, 36924, 23317, 23282, 33464,
28312);
  __asm("nop");
  while(1);
}




Další informace o konferenci Hw-list