$search
00001 /* 00002 Aseba - an event-based framework for distributed robot control 00003 Copyright (C) 2007--2011: 00004 Stephane Magnenat <stephane at magnenat dot net> 00005 (http://stephane.magnenat.net) 00006 and other contributors, see authors.txt for details 00007 00008 This program is free software: you can redistribute it and/or modify 00009 it under the terms of the GNU Lesser General Public License as published 00010 by the Free Software Foundation, version 3 of the License. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU Lesser General Public License for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 #include "../common/consts.h" 00022 #include "../common/types.h" 00023 #include "natives.h" 00024 #include <string.h> 00025 00026 #include <assert.h> 00027 00028 #if defined(__dsPIC30F__) 00029 #include <p30fxxxx.h> 00030 #define DSP_AVAILABLE 00031 #elif defined(__dsPIC33F__) 00032 #include <p33Fxxxx.h> 00033 #define DSP_AVAILABLE 00034 #elif defined(__PIC24H__) 00035 #include <p24Hxxxx.h> 00036 #endif 00037 00038 00039 00047 00048 // useful math functions used by below 00049 00050 // table is 20 bins (one for each bit of value) of 8 values each + one for infinity 00051 static const sint16 aseba_atan_table[20*8+1] = { 652, 735, 816, 896, 977, 1058, 1139, 1218, 1300, 1459, 1620, 1777, 1935, 2093, 2250, 2403, 2556, 2868, 3164, 3458, 3748, 4029, 4307, 4578, 4839, 5359, 5836, 6290, 6720, 7126, 7507, 7861, 8203, 8825, 9357, 9839, 10260, 10640, 10976, 11281, 11557, 12037, 12425, 12755, 13036, 13277, 13486, 13671, 13837, 14112, 14331, 14514, 14666, 14796, 14907, 15003, 15091, 15235, 15348, 15441, 15519, 15585, 15642, 15691, 15736, 15808, 15865, 15912, 15951, 15984, 16013, 16037, 16060, 16096, 16125, 16148, 16168, 16184, 16199, 16211, 16222, 16240, 16255, 16266, 16276, 16284, 16292, 16298, 16303, 16312, 16320, 16325, 16331, 16334, 16338, 16341, 16344, 16348, 16352, 16355, 16357, 16360, 16361, 16363, 16364, 16366, 16369, 16369, 16371, 16372, 16373, 16373, 16375, 16375, 16377, 16376, 16378, 16378, 16378, 16379, 16379, 16380, 16380, 16380, 16382, 16381, 16381, 16381, 16382, 16382, 16382, 16382, 16382, 16382, 16384, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16383, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384 }; 00052 /* Generation code: 00053 for (int i = 0; i < 20; i++) 00054 { 00055 double d = pow(2, (double)(i - 4)); 00056 double dd = d / 8; 00057 for (int j = 0; j < 8; j++) 00058 { 00059 double v = atan(d + dd * j); 00060 aseba_atan_table[i*8+j] = (int)(((32768.*v) / (M_PI))+0.5); 00061 } 00062 aseba_atan_table[20*8] = 16384 00063 } 00064 + optimisation 00065 */ 00066 00067 00068 // atan2, do y/x and return an "aseba" angle that spans the whole 16 bits range 00069 sint16 aseba_atan2(sint16 y, sint16 x) 00070 { 00071 if (y == 0) 00072 { 00073 if (x >= 0) // we return 0 on division by zero 00074 return 0; 00075 else if (x < 0) 00076 return -32768; 00077 } 00078 00079 { 00080 sint16 res; 00081 sint16 ax = abs(x); 00082 sint16 ay = abs(y); 00083 if (x == 0) 00084 { 00085 res = 16384; 00086 } 00087 else 00088 { 00089 #ifdef __C30__ 00090 unsigned int q2, rem1; 00091 unsigned long q1; 00092 q1 = __builtin_divmodud(ay, ax, &rem1); 00093 q2 = __builtin_divud(((unsigned long) rem1) << 16, ax); 00094 sint32 value = (q1 << 16) | q2; 00095 00096 sint16 fb1; 00097 00098 // find first bit at one 00099 // ASM optimisation for 16bits PIC 00100 // Find first bit from left (MSB) on 32 bits word 00101 asm ("ff1l %[word], %[b]" : [b] "=r" (fb1) : [word] "r" ((int) (value >> 16)) : "cc"); 00102 if(fb1) 00103 fb1 = 17 - fb1 + 16 - 1; // Bit 0 is "16", fbl = 0 mean no 1 found for ff1l 00104 else { 00105 asm ("ff1l %[word], %[b]" : [b] "=r" (fb1) : [word] "r" ((int) value) : "cc"); 00106 if(fb1) 00107 fb1 = 17 - fb1 - 1; // see above 00108 } 00109 { 00110 // we only keep 4 bits of precision below comma as atan(x) is like x near 0 00111 sint16 index = fb1 - 12; 00112 if (index < 0) 00113 { 00114 // value is smaller than 2e-4 00115 res = (value*aseba_atan_table[0]) >> 12; 00116 } 00117 else 00118 { 00119 sint32 subprecision_rest = value - (1L << fb1); 00120 sint16 to_shift = fb1 - 8; // fb1 >= 12 otherwise index would have been < 0 00121 sint16 subprecision_index = (sint16)(subprecision_rest >> to_shift); 00122 sint16 bin = subprecision_index >> 5; 00123 sint16 delta = subprecision_index & 0x1f; 00124 res = __builtin_divsd(__builtin_mulss(aseba_atan_table[index*8 + bin], 32 - delta) + __builtin_mulss(aseba_atan_table[index*8 + bin + 1], delta),32); 00125 } 00126 00127 #else 00128 sint32 value = (((sint32)ay << 16)/(sint32)(ax)); 00129 sint16 fb1 = 0; 00130 00131 sint16 fb1_counter; 00132 for (fb1_counter = 0; fb1_counter < 32; fb1_counter++) 00133 if ((value >> (sint32)fb1_counter) != 0) 00134 fb1 = fb1_counter; 00135 00136 { 00137 // we only keep 4 bits of precision below comma as atan(x) is like x near 0 00138 sint16 index = fb1 - 12; 00139 if (index < 0) 00140 { 00141 // value is smaller than 2e-4 00142 res = (sint16)(((sint32)aseba_atan_table[0] * value) >> 12); 00143 } 00144 else 00145 { 00146 sint32 subprecision_rest = value - (((sint32) 1) << fb1); 00147 sint16 to_shift = fb1 - 8; // fb1 >= 12 otherwise index would have been < 0 00148 sint16 subprecision_index = (sint16)(subprecision_rest >> to_shift); 00149 sint16 bin = subprecision_index >> 5; 00150 sint16 delta = subprecision_index & 0x1f; 00151 res = (sint16)(((sint32)aseba_atan_table[index*8 + bin] * (sint32)(32 - delta) + (sint32)aseba_atan_table[index*8 + bin + 1] * (sint32)delta) >> 5); 00152 } 00153 #endif 00154 // do pi - value if x negative 00155 if (x < 0) 00156 res = 32768 - res; 00157 } 00158 } 00159 00160 if (y > 0) 00161 return res; 00162 else 00163 return -res; 00164 } 00165 } 00166 00167 // 2 << 7 entries + 1, from 0 to 16384, being from 0 to PI 00168 static const sint16 aseba_sin_table[128+1] = {0, 403, 804, 1207, 1608, 2010, 2411, 2812, 3212, 3612, 4011, 4411, 4808, 5206, 5603, 5998, 6393, 6787, 7180, 7572, 7962, 8352, 8740, 9127, 9513, 9896, 10279, 10660, 11040, 11417, 11794, 12167, 12540, 12911, 13279, 13646, 14010, 14373, 14733, 15091, 15447, 15801, 16151, 16500, 16846, 17190, 17531, 17869, 18205, 18538, 18868, 19196, 19520, 19842, 20160, 20476, 20788, 21097, 21403, 21706, 22006, 22302, 22595, 22884, 23171, 23453, 23732, 24008, 24279, 24548, 24812, 25073, 25330, 25583, 25833, 26078, 26320, 26557, 26791, 27020, 27246, 27467, 27684, 27897, 28106, 28311, 28511, 28707, 28899, 29086, 29269, 29448, 29622, 29792, 29957, 30117, 30274, 30425, 30572, 30715, 30852, 30985, 31114, 31238, 31357, 31471, 31581, 31686, 31786, 31881, 31972, 32057, 32138, 32215, 32285, 32352, 32413, 32470, 32521, 32569, 32610, 32647, 32679, 32706, 32728, 32746, 32758, 32766, 32767, }; 00169 /* Generation code: 00170 int i; 00171 for (i = 0; i <= 128; i++) 00172 { 00173 sinTable[i] = (sint16)(32767. * sin( ((M_PI/2.)*(double)i)/128.) + 0.5); 00174 } 00175 + optimisation 00176 */ 00177 00178 00179 // do the sinus of an "aseba" angle that spans the whole 16 bits range, and return a 1.15 fixed point value 00180 sint16 aseba_sin(sint16 angle) 00181 { 00182 sint16 index; 00183 sint16 subIndex; 00184 sint16 invert; 00185 sint16 lookupAngle; 00186 if (angle < 0) 00187 { 00188 if (angle < -16384) 00189 lookupAngle = 32768 + angle; 00190 else if (angle > -16384) 00191 lookupAngle = -angle; 00192 else 00193 return -32767; 00194 invert = 1; 00195 } 00196 else 00197 { 00198 if (angle > 16384) 00199 lookupAngle = 32767 - angle + 1; 00200 else if (angle < 16484) 00201 lookupAngle = angle; 00202 else 00203 return 32767; 00204 invert = 0; 00205 } 00206 00207 index = lookupAngle >> 7; 00208 subIndex = lookupAngle & 0x7f; 00209 00210 { 00211 sint16 result = (sint16)(((sint32)aseba_sin_table[index] * (sint32)(128-subIndex) + (sint32)aseba_sin_table[index+1] * (sint32)(subIndex)) >> 7); 00212 00213 if (invert) 00214 return -result; 00215 else 00216 return result; 00217 } 00218 } 00219 00220 // do the cos of an "aseba" angle that spans the whole 16 bits range, and return a 1.15 fixed point value 00221 sint16 aseba_cos(sint16 angle) 00222 { 00223 return aseba_sin(16384 + angle); 00224 } 00225 00226 // Do integer square root ( from Wikipedia ) 00227 sint16 aseba_sqrt(sint16 num) 00228 { 00229 sint16 op = num; 00230 sint16 res = 0; 00231 sint16 one = 1 << 14; 00232 00233 while(one > op) 00234 one >>= 2; 00235 00236 while(one != 0) 00237 { 00238 if (op >= res + one) 00239 { 00240 op -= res + one; 00241 res = (res >> 1) + one; 00242 } 00243 else 00244 { 00245 res >>= 1; 00246 } 00247 one >>= 2; 00248 } 00249 return res; 00250 } 00251 00252 // comb sort ( from Wikipedia ) 00253 void aseba_comb_sort(sint16* input, uint16 size) 00254 { 00255 uint16 gap = size; 00256 uint16 swapped = 0; 00257 uint16 i; 00258 00259 while ((gap > 1) || swapped) 00260 { 00261 if (gap > 1) 00262 { 00263 #ifdef __C30__ 00264 gap = __builtin_divud(__builtin_muluu(gap,4),5); 00265 #else 00266 gap = (uint16)(((uint32)gap * 4) / 5); 00267 #endif 00268 } 00269 00270 swapped = 0; 00271 00272 for (i = 0; gap + i < size; i++) 00273 { 00274 if (input[i] - input[i + gap] > 0) 00275 { 00276 sint16 swap = input[i]; 00277 input[i] = input[i + gap]; 00278 input[i + gap] = swap; 00279 swapped = 1; 00280 } 00281 } 00282 } 00283 } 00284 00285 00286 // standard natives functions 00287 00288 void AsebaNative_veccopy(AsebaVMState *vm) 00289 { 00290 // variable pos 00291 uint16 dest = AsebaNativePopArg(vm); 00292 uint16 src = AsebaNativePopArg(vm); 00293 00294 // variable size 00295 uint16 length = AsebaNativePopArg(vm); 00296 00297 uint16 i; 00298 00299 for (i = 0; i < length; i++) 00300 { 00301 vm->variables[dest++] = vm->variables[src++]; 00302 } 00303 } 00304 00305 const AsebaNativeFunctionDescription AsebaNativeDescription_veccopy = 00306 { 00307 "math.copy", 00308 "copies src to dest element by element", 00309 { 00310 { -1, "dest" }, 00311 { -1, "src" }, 00312 { 0, 0 } 00313 } 00314 }; 00315 00316 00317 void AsebaNative_vecfill(AsebaVMState *vm) 00318 { 00319 // variable pos 00320 uint16 dest = AsebaNativePopArg(vm); 00321 uint16 value = AsebaNativePopArg(vm); 00322 00323 // variable size 00324 uint16 length = AsebaNativePopArg(vm); 00325 00326 uint16 i; 00327 00328 for (i = 0; i < length; i++) 00329 { 00330 vm->variables[dest++] = vm->variables[value]; 00331 } 00332 } 00333 00334 const AsebaNativeFunctionDescription AsebaNativeDescription_vecfill = 00335 { 00336 "math.fill", 00337 "fills dest with constant value", 00338 { 00339 { -1, "dest" }, 00340 { 1, "value" }, 00341 { 0, 0 } 00342 } 00343 }; 00344 00345 00346 void AsebaNative_vecaddscalar(AsebaVMState *vm) 00347 { 00348 // variable pos 00349 uint16 dest = AsebaNativePopArg(vm); 00350 uint16 src = AsebaNativePopArg(vm); 00351 uint16 scalar = AsebaNativePopArg(vm); 00352 00353 // variable size 00354 uint16 length = AsebaNativePopArg(vm); 00355 00356 const sint16 scalarValue = vm->variables[scalar]; 00357 uint16 i; 00358 for (i = 0; i < length; i++) 00359 { 00360 vm->variables[dest++] = vm->variables[src++] + scalarValue; 00361 } 00362 } 00363 00364 const AsebaNativeFunctionDescription AsebaNativeDescription_vecaddscalar = 00365 { 00366 "math.addscalar", 00367 "add scalar to each element of src and store result to dest", 00368 { 00369 { -1, "dest" }, 00370 { -1, "src" }, 00371 { 1, "scalar" }, 00372 { 0, 0 } 00373 } 00374 }; 00375 00376 00377 void AsebaNative_vecadd(AsebaVMState *vm) 00378 { 00379 // variable pos 00380 uint16 dest = AsebaNativePopArg(vm); 00381 uint16 src1 = AsebaNativePopArg(vm); 00382 uint16 src2 = AsebaNativePopArg(vm); 00383 00384 // variable size 00385 uint16 length = AsebaNativePopArg(vm); 00386 00387 uint16 i; 00388 for (i = 0; i < length; i++) 00389 { 00390 vm->variables[dest++] = vm->variables[src1++] + vm->variables[src2++]; 00391 } 00392 } 00393 00394 const AsebaNativeFunctionDescription AsebaNativeDescription_vecadd = 00395 { 00396 "math.add", 00397 "adds src1 and src2 to dest, element by element", 00398 { 00399 { -1, "dest" }, 00400 { -1, "src1" }, 00401 { -1, "src2" }, 00402 { 0, 0 } 00403 } 00404 }; 00405 00406 00407 void AsebaNative_vecsub(AsebaVMState *vm) 00408 { 00409 // variable pos 00410 uint16 dest = AsebaNativePopArg(vm); 00411 uint16 src1 = AsebaNativePopArg(vm); 00412 uint16 src2 = AsebaNativePopArg(vm); 00413 00414 // variable size 00415 uint16 length = AsebaNativePopArg(vm); 00416 00417 uint16 i; 00418 for (i = 0; i < length; i++) 00419 { 00420 vm->variables[dest++] = vm->variables[src1++] - vm->variables[src2++]; 00421 } 00422 } 00423 00424 const AsebaNativeFunctionDescription AsebaNativeDescription_vecsub = 00425 { 00426 "math.sub", 00427 "substracts src2 from src1 to dest, element by element", 00428 { 00429 { -1, "dest" }, 00430 { -1, "src1" }, 00431 { -1, "src2" }, 00432 { 0, 0 } 00433 } 00434 }; 00435 00436 00437 void AsebaNative_vecmul(AsebaVMState *vm) 00438 { 00439 // variable pos 00440 uint16 dest = AsebaNativePopArg(vm); 00441 uint16 src1 = AsebaNativePopArg(vm); 00442 uint16 src2 = AsebaNativePopArg(vm); 00443 00444 // variable size 00445 uint16 length = AsebaNativePopArg(vm); 00446 00447 uint16 i; 00448 for (i = 0; i < length; i++) 00449 { 00450 vm->variables[dest++] = vm->variables[src1++] * vm->variables[src2++]; 00451 } 00452 } 00453 00454 const AsebaNativeFunctionDescription AsebaNativeDescription_vecmul = 00455 { 00456 "math.mul", 00457 "multiplies src1 and src2 to dest, element by element", 00458 { 00459 { -1, "dest" }, 00460 { -1, "src1" }, 00461 { -1, "src2" }, 00462 { 0, 0 } 00463 } 00464 }; 00465 00466 00467 void AsebaNative_vecdiv(AsebaVMState *vm) 00468 { 00469 // variable pos 00470 uint16 dest = AsebaNativePopArg(vm); 00471 uint16 src1 = AsebaNativePopArg(vm); 00472 uint16 src2 = AsebaNativePopArg(vm); 00473 00474 // variable size 00475 uint16 length = AsebaNativePopArg(vm); 00476 00477 uint16 i; 00478 for (i = 0; i < length; i++) 00479 { 00480 sint32 dividend = (sint32)vm->variables[src1++]; 00481 sint32 divisor = (sint32)vm->variables[src2++]; 00482 00483 if (divisor != 0) 00484 { 00485 vm->variables[dest++] = (sint16)(dividend / divisor); 00486 } 00487 else 00488 { 00489 vm->flags = ASEBA_VM_STEP_BY_STEP_MASK; 00490 AsebaSendMessage(vm, ASEBA_MESSAGE_DIVISION_BY_ZERO, &(vm->pc), sizeof(vm->pc)); 00491 return; 00492 } 00493 } 00494 } 00495 00496 const AsebaNativeFunctionDescription AsebaNativeDescription_vecdiv = 00497 { 00498 "math.div", 00499 "divides src1 by src2 to dest, element by element", 00500 { 00501 { -1, "dest" }, 00502 { -1, "src1" }, 00503 { -1, "src2" }, 00504 { 0, 0 } 00505 } 00506 }; 00507 00508 00509 void AsebaNative_vecmin(AsebaVMState *vm) 00510 { 00511 // variable pos 00512 uint16 dest = AsebaNativePopArg(vm); 00513 uint16 src1 = AsebaNativePopArg(vm); 00514 uint16 src2 = AsebaNativePopArg(vm); 00515 00516 // variable size 00517 uint16 length = AsebaNativePopArg(vm); 00518 00519 uint16 i; 00520 for (i = 0; i < length; i++) 00521 { 00522 sint16 v1 = vm->variables[src1++]; 00523 sint16 v2 = vm->variables[src2++]; 00524 sint16 res = v1 < v2 ? v1 : v2; 00525 vm->variables[dest++] = res; 00526 } 00527 } 00528 00529 const AsebaNativeFunctionDescription AsebaNativeDescription_vecmin = 00530 { 00531 "math.min", 00532 "writes the minimum of src1 and src2 to dest, element by element", 00533 { 00534 { -1, "dest" }, 00535 { -1, "src1" }, 00536 { -1, "src2" }, 00537 { 0, 0 } 00538 } 00539 }; 00540 00541 00542 void AsebaNative_vecmax(AsebaVMState *vm) 00543 { 00544 // variable pos 00545 uint16 dest = AsebaNativePopArg(vm); 00546 uint16 src1 = AsebaNativePopArg(vm); 00547 uint16 src2 = AsebaNativePopArg(vm); 00548 00549 // variable size 00550 uint16 length = AsebaNativePopArg(vm); 00551 00552 uint16 i; 00553 for (i = 0; i < length; i++) 00554 { 00555 sint16 v1 = vm->variables[src1++]; 00556 sint16 v2 = vm->variables[src2++]; 00557 sint16 res = v1 > v2 ? v1 : v2; 00558 vm->variables[dest++] = res; 00559 } 00560 } 00561 00562 const AsebaNativeFunctionDescription AsebaNativeDescription_vecmax = 00563 { 00564 "math.max", 00565 "writes the maximum of src1 and src2 to dest, element by element", 00566 { 00567 { -1, "dest" }, 00568 { -1, "src1" }, 00569 { -1, "src2" }, 00570 { 0, 0 } 00571 } 00572 }; 00573 00574 00575 void AsebaNative_vecdot(AsebaVMState *vm) 00576 { 00577 // variable pos 00578 uint16 dest = AsebaNativePopArg(vm); 00579 uint16 src1 = AsebaNativePopArg(vm); 00580 uint16 src2 = AsebaNativePopArg(vm); 00581 sint16 shift = vm->variables[AsebaNativePopArg(vm)]; 00582 00583 // variable size 00584 uint16 length = AsebaNativePopArg(vm); 00585 sint32 res = 0; 00586 uint16 i; 00587 00588 if(shift > 32) { 00589 vm->variables[dest] = 0; 00590 return; 00591 } 00592 00593 #ifdef DSP_AVAILABLE 00594 length--; 00595 00596 CORCONbits.US = 0; // Signed mode 00597 CORCON |= 0b11110001; // 40 bits mode, saturation enable, integer mode. 00598 // Do NOT save the accumulator values, so do NOT USE THIS FUNCTION IN INTERRUPT ! 00599 asm __volatile__ ( 00600 "push %[ptr1] \r\n" 00601 "push %[ptr2] \r\n" 00602 "clr A\r\n" // A = 0 00603 "mov [%[ptr1]++], w4 \r\n" // Preload ptr 00604 "do %[loop_cnt], 1f \r\n" // Iterate loop_cnt time the two following instructions 00605 "mov [%[ptr2]++], w5 \r\n" // Load w5 00606 "1: mac w4*w5, A, [%[ptr1]]+=2, w4 \r\n" // A += w4 * w5, prefetch ptr1 into w4 00607 "pop %[ptr2] \r\n" 00608 "pop %[ptr1] \r\n" 00609 : /* No output */ 00610 : [loop_cnt] "r" (length), [ptr1] "x" (&vm->variables[src1]), [ptr2] "r" (&vm->variables[src2]) 00611 : "cc", "w4", "w5" ); 00612 00613 if(shift > 16) { 00614 shift -= 16; 00615 asm __volatile__ ("sftac A, #16\r\n" : /* No output */ : /* No input */ : "cc"); 00616 } 00617 00618 // Shift and get the output 00619 asm __volatile__ ("sftac A, %[sft]\r\n" : /* No output */ : [sft] "r" (shift) : "cc"); 00620 00621 vm->variables[dest] = ACCAL; // Get the Accumulator low word 00622 #elif defined(__C30__) 00623 for (i= 0; i < length; i++) 00624 res += __builtin_mulss(vm->variables[src1++], vm->variables[src2++]); 00625 res >>= shift; 00626 vm->variables[dest] = (sint16) res; 00627 #else 00628 for (i = 0; i < length; i++) 00629 { 00630 res += (sint32)vm->variables[src1++] * (sint32)vm->variables[src2++]; 00631 } 00632 res >>= shift; 00633 vm->variables[dest] = (sint16)res; 00634 #endif 00635 } 00636 00637 const AsebaNativeFunctionDescription AsebaNativeDescription_vecdot = 00638 { 00639 "math.dot", 00640 "writes the dot product of src1 and src2 to dest, after a shift", 00641 { 00642 { 1, "dest" }, 00643 { -1, "src1" }, 00644 { -1, "src2" }, 00645 { 1, "shift" }, 00646 { 0, 0 } 00647 } 00648 }; 00649 00650 00651 void AsebaNative_vecstat(AsebaVMState *vm) 00652 { 00653 // variable pos 00654 uint16 src = AsebaNativePopArg(vm); 00655 uint16 min = AsebaNativePopArg(vm); 00656 uint16 max = AsebaNativePopArg(vm); 00657 uint16 mean = AsebaNativePopArg(vm); 00658 00659 // variable size 00660 uint16 length = AsebaNativePopArg(vm); 00661 sint16 val; 00662 sint32 acc; 00663 uint16 i; 00664 00665 if (length) 00666 { 00667 val = vm->variables[src++]; 00668 acc = val; 00669 vm->variables[min] = val; 00670 vm->variables[max] = val; 00671 00672 for (i = 1; i < length; i++) 00673 { 00674 val = vm->variables[src++]; 00675 if (val < vm->variables[min]) 00676 vm->variables[min] = val; 00677 if (val > vm->variables[max]) 00678 vm->variables[max] = val; 00679 acc += (sint32)val; 00680 } 00681 00682 vm->variables[mean] = (sint16)(acc / (sint32)length); 00683 } 00684 } 00685 00686 const AsebaNativeFunctionDescription AsebaNativeDescription_vecstat = 00687 { 00688 "math.stat", 00689 "performs statistics on src", 00690 { 00691 { -1, "src" }, 00692 { 1, "min" }, 00693 { 1, "max" }, 00694 { 1, "mean" }, 00695 { 0, 0 } 00696 } 00697 }; 00698 00699 00700 void AsebaNative_vecargbounds(AsebaVMState *vm) 00701 { 00702 // variable pos 00703 uint16 src = AsebaNativePopArg(vm); 00704 uint16 argmin = AsebaNativePopArg(vm); 00705 uint16 argmax = AsebaNativePopArg(vm); 00706 00707 // variable size 00708 uint16 length = AsebaNativePopArg(vm); 00709 sint16 min = 32767; 00710 sint16 max = -32768; 00711 sint16 val; 00712 uint16 i; 00713 00714 if (length) 00715 { 00716 for (i = 0; i < length; i++) 00717 { 00718 val = vm->variables[src++]; 00719 if (val < min) 00720 { 00721 min = val; 00722 vm->variables[argmin] = i; 00723 } 00724 if (val > max) 00725 { 00726 max = val; 00727 vm->variables[argmax] = i; 00728 } 00729 } 00730 } 00731 } 00732 00733 const AsebaNativeFunctionDescription AsebaNativeDescription_vecargbounds = 00734 { 00735 "math.argbounds", 00736 "get the indices (argmin, argmax) of the (minimum, maximum) values of src", 00737 { 00738 { -1, "src" }, 00739 { 1, "argmin" }, 00740 { 1, "argmax" }, 00741 { 0, 0 } 00742 } 00743 }; 00744 00745 00746 void AsebaNative_vecsort(AsebaVMState *vm) 00747 { 00748 // variable pos 00749 uint16 src = AsebaNativePopArg(vm); 00750 00751 // variable size 00752 uint16 length = AsebaNativePopArg(vm); 00753 00754 aseba_comb_sort(&vm->variables[src], length); 00755 } 00756 00757 const AsebaNativeFunctionDescription AsebaNativeDescription_vecsort = 00758 { 00759 "math.sort", 00760 "sort array in place", 00761 { 00762 { -1, "array" }, 00763 { 0, 0 } 00764 } 00765 }; 00766 00767 00768 void AsebaNative_mathmuldiv(AsebaVMState *vm) 00769 { 00770 // variable pos 00771 uint16 destIndex = AsebaNativePopArg(vm); 00772 uint16 aIndex = AsebaNativePopArg(vm); 00773 uint16 bIndex = AsebaNativePopArg(vm); 00774 uint16 cIndex = AsebaNativePopArg(vm); 00775 00776 // variable size 00777 uint16 length = AsebaNativePopArg(vm); 00778 00779 uint16 i; 00780 for (i = 0; i < length; i++) 00781 { 00782 sint32 a = (sint32)vm->variables[aIndex++]; 00783 sint32 b = (sint32)vm->variables[bIndex++]; 00784 sint32 c = (sint32)vm->variables[cIndex++]; 00785 if (c != 0) 00786 { 00787 vm->variables[destIndex++] = (sint16)((a * b) / c); 00788 } 00789 else 00790 { 00791 vm->flags = ASEBA_VM_STEP_BY_STEP_MASK; 00792 AsebaSendMessage(vm, ASEBA_MESSAGE_DIVISION_BY_ZERO, &(vm->pc), sizeof(vm->pc)); 00793 return; 00794 } 00795 } 00796 } 00797 00798 const AsebaNativeFunctionDescription AsebaNativeDescription_mathmuldiv = 00799 { 00800 "math.muldiv", 00801 "performs dest = (a*b)/c in 32 bits element by element", 00802 { 00803 { -1, "dest" }, 00804 { -1, "a" }, 00805 { -1, "b" }, 00806 { -1, "c" }, 00807 { 0, 0 } 00808 } 00809 }; 00810 00811 void AsebaNative_mathatan2(AsebaVMState *vm) 00812 { 00813 // variable pos 00814 uint16 destIndex = AsebaNativePopArg(vm); 00815 sint16 yIndex = AsebaNativePopArg(vm); 00816 sint16 xIndex = AsebaNativePopArg(vm); 00817 00818 // variable size 00819 uint16 length = AsebaNativePopArg(vm); 00820 00821 uint16 i; 00822 for (i = 0; i < length; i++) 00823 { 00824 sint16 y = vm->variables[yIndex++]; 00825 sint16 x = vm->variables[xIndex++]; 00826 vm->variables[destIndex++] = aseba_atan2(y, x); 00827 } 00828 } 00829 00830 const AsebaNativeFunctionDescription AsebaNativeDescription_mathatan2 = 00831 { 00832 "math.atan2", 00833 "performs dest = atan2(y,x) element by element", 00834 { 00835 { -1, "dest" }, 00836 { -1, "y" }, 00837 { -1, "x" }, 00838 { 0, 0 } 00839 } 00840 }; 00841 00842 void AsebaNative_mathsin(AsebaVMState *vm) 00843 { 00844 // variable pos 00845 uint16 destIndex = AsebaNativePopArg(vm); 00846 sint16 xIndex = AsebaNativePopArg(vm); 00847 00848 // variable size 00849 uint16 length = AsebaNativePopArg(vm); 00850 00851 uint16 i; 00852 for (i = 0; i < length; i++) 00853 { 00854 sint16 x = vm->variables[xIndex++]; 00855 vm->variables[destIndex++] = aseba_sin(x); 00856 } 00857 } 00858 00859 const AsebaNativeFunctionDescription AsebaNativeDescription_mathsin = 00860 { 00861 "math.sin", 00862 "performs dest = sin(x) element by element", 00863 { 00864 { -1, "dest" }, 00865 { -1, "x" }, 00866 { 0, 0 } 00867 } 00868 }; 00869 00870 void AsebaNative_mathcos(AsebaVMState *vm) 00871 { 00872 // variable pos 00873 uint16 destIndex = AsebaNativePopArg(vm); 00874 sint16 xIndex = AsebaNativePopArg(vm); 00875 00876 // variable size 00877 uint16 length = AsebaNativePopArg(vm); 00878 00879 uint16 i; 00880 for (i = 0; i < length; i++) 00881 { 00882 sint16 x = vm->variables[xIndex++]; 00883 vm->variables[destIndex++] = aseba_cos(x); 00884 } 00885 } 00886 00887 const AsebaNativeFunctionDescription AsebaNativeDescription_mathcos = 00888 { 00889 "math.cos", 00890 "performs dest = cos(x) element by element", 00891 { 00892 { -1, "dest" }, 00893 { -1, "x" }, 00894 { 0, 0 } 00895 } 00896 }; 00897 00898 void AsebaNative_mathrot2(AsebaVMState *vm) 00899 { 00900 // variable pos 00901 uint16 vectOutIndex = AsebaNativePopArg(vm); 00902 uint16 vecInIndex = AsebaNativePopArg(vm); 00903 uint16 angleIndex = AsebaNativePopArg(vm); 00904 00905 // variables 00906 sint16 x = vm->variables[vecInIndex]; 00907 sint16 y = vm->variables[vecInIndex+1]; 00908 sint16 a = vm->variables[angleIndex]; 00909 00910 sint16 cos_a = aseba_cos(a); 00911 sint16 sin_a = aseba_sin(a); 00912 00913 sint16 xp = (sint16)(((sint32)cos_a * (sint32)x - (sint32)sin_a * (sint32)y) >> (sint32)15); 00914 sint16 yp = (sint16)(((sint32)cos_a * (sint32)y + (sint32)sin_a * (sint32)x) >> (sint32)15); 00915 00916 vm->variables[vectOutIndex] = xp; 00917 vm->variables[vectOutIndex+1] = yp; 00918 } 00919 00920 const AsebaNativeFunctionDescription AsebaNativeDescription_mathrot2 = 00921 { 00922 "math.rot2", 00923 "rotates v of angle a to dest", 00924 { 00925 { 2, "dest" }, 00926 { 2, "v" }, 00927 { 1, "a" }, 00928 { 0, 0 } 00929 } 00930 }; 00931 00932 void AsebaNative_mathsqrt(AsebaVMState *vm) 00933 { 00934 // variable pos 00935 uint16 destIndex = AsebaNativePopArg(vm); 00936 sint16 xIndex = AsebaNativePopArg(vm); 00937 00938 // variable size 00939 uint16 length = AsebaNativePopArg(vm); 00940 00941 uint16 i; 00942 for (i = 0; i < length; i++) 00943 { 00944 sint16 x = vm->variables[xIndex++]; 00945 vm->variables[destIndex++] = aseba_sqrt(x); 00946 } 00947 } 00948 00949 const AsebaNativeFunctionDescription AsebaNativeDescription_mathsqrt = 00950 { 00951 "math.sqrt", 00952 "performs dest = sqrt(x) element by element", 00953 { 00954 { -1, "dest" }, 00955 { -1, "x" }, 00956 { 0, 0 } 00957 } 00958 }; 00959 00960 void AsebaNative_vecnonzerosequence(AsebaVMState *vm) 00961 { 00962 // variable pos 00963 uint16 dest = AsebaNativePopArg(vm); // output value index 00964 uint16 src = AsebaNativePopArg(vm); // input vector index 00965 uint16 length = AsebaNativePopArg(vm); // length threshold index 00966 00967 // variable size 00968 uint16 inputLength = AsebaNativePopArg(vm); 00969 sint16 minLength = vm->variables[length]; // length threshold 00970 00971 // work variables 00972 uint16 nzFirstZero; 00973 sint16 index; 00974 sint16 seqIndex; 00975 sint16 bestSeqLength; 00976 sint16 bestSeqIndex; 00977 sint16 seqLength; 00978 00979 // search for a zero, then non-zero 00980 uint16 nzFirstIndex = 0; 00981 while (vm->variables[src + nzFirstIndex] != 0) 00982 { 00983 ++nzFirstIndex; 00984 if (nzFirstIndex > inputLength) 00985 { 00986 vm->variables[dest] = 0; 00987 return; 00988 } 00989 } 00990 nzFirstZero = nzFirstIndex; 00991 while (vm->variables[src + nzFirstIndex] == 0) 00992 { 00993 ++nzFirstIndex; 00994 if (nzFirstIndex > inputLength) 00995 { 00996 if (nzFirstZero == 0) 00997 { 00998 vm->variables[dest] = -1; 00999 } 01000 else 01001 { 01002 uint16 seqLength = nzFirstZero - 1; 01003 if (seqLength < minLength) 01004 vm->variables[dest] = -1; 01005 else 01006 vm->variables[dest] = (nzFirstZero - 1) / 2; 01007 } 01008 return; 01009 } 01010 } 01011 01012 index = 0; 01013 bestSeqLength = 0; 01014 bestSeqIndex = 0; 01015 01016 while (1) 01017 { 01018 // scan non-zero sequence 01019 seqIndex = index; 01020 while (vm->variables[src + (nzFirstIndex + index) % inputLength] != 0) 01021 { 01022 ++index; 01023 if (index >= inputLength) 01024 break; 01025 } 01026 // check size 01027 seqLength = index - seqIndex; 01028 if (seqLength > bestSeqLength) 01029 { 01030 bestSeqLength = seqLength; 01031 bestSeqIndex = (index + seqIndex) / 2; 01032 } 01033 if (index >= inputLength) 01034 break; 01035 01036 // scan zero sequence 01037 while (vm->variables[src + (nzFirstIndex + index) % inputLength] == 0) 01038 { 01039 ++index; 01040 if (index >= inputLength) 01041 goto doubleBreak; 01042 } 01043 } 01044 01045 doubleBreak: 01046 if (bestSeqLength < minLength) 01047 { 01048 vm->variables[dest] = -1; 01049 } 01050 else 01051 { 01052 vm->variables[dest] = (nzFirstIndex + bestSeqIndex) % inputLength; 01053 } 01054 } 01055 01056 01057 const AsebaNativeFunctionDescription AsebaNativeDescription_vecnonzerosequence = 01058 { 01059 "math.nzseq", 01060 "write to dest the middle index of the largest sequence of non-zero elements from src, -1 if not found or if smaller than minLength", 01061 { 01062 { 1, "dest" }, 01063 { -1, "src" }, 01064 { 1, "minLength" }, 01065 { 0, 0 } 01066 } 01067 }; 01068 01069 static uint16 rnd_state; 01070 01071 void AsebaSetRandomSeed(uint16 seed) 01072 { 01073 rnd_state = seed; 01074 } 01075 01076 uint16 AsebaGetRandom() 01077 { 01078 rnd_state = 25173 * rnd_state + 13849; 01079 return rnd_state; 01080 } 01081 01082 void AsebaNative_rand(AsebaVMState *vm) 01083 { 01084 // variable pos 01085 uint16 destIndex = AsebaNativePopArg(vm); 01086 01087 // variable size 01088 uint16 length = AsebaNativePopArg(vm); 01089 01090 uint16 i; 01091 for (i = 0; i < length; i++) 01092 { 01093 vm->variables[destIndex++] = (sint16)AsebaGetRandom(); 01094 } 01095 } 01096 01097 const AsebaNativeFunctionDescription AsebaNativeDescription_rand = 01098 { 01099 "math.rand", 01100 "fill array with random values", 01101 { 01102 { -1, "dest" }, 01103 { 0, 0 } 01104 } 01105 }; 01106 01107