Add a line to KNOWN_BUGS about `let' inconsistently forcing values.
[proto.git] / src / kernel / proto.c
blobf02d4605e8c27aa6ee42dc459101cc1ce26f2d2f
1 /* ProtoKernel virtual machine
2 Copyright (C) 2005-2008, Jonathan Bachrach, Jacob Beal, and contributors
3 listed in the AUTHORS file in the MIT Proto distribution's top directory.
5 This file is part of MIT Proto, and is distributed under the terms of
6 the GNU General Public License, with a linking exception, as described
7 in the file LICENSE in the MIT Proto distribution's top directory. */
9 #include <stdlib.h>
10 #include <stdarg.h>
11 #include <math.h>
12 #include "proto.h"
13 #include "proto_vm.h"
15 extern void * lookup_op_by_code (int code, char **name);
17 int is_throttling = 0; // TODO: are_exports_serialized must be true right now
19 int depth;
21 #define MAX_NBR_TIMEOUT 11
22 #define TIMEOUT_BASE 1.6
24 // INLINE uint8_t* word_align(uint8_t *x) {
25 // return (uint8_t *)(((uint32_t)x + 3) & (~3));
26 // }
28 INLINE uint16_t word_align(uint16_t x) {
29 return IS_WORD_ALIGN ? ((x + 3) & (~3)) : x;
32 uint16_t machine_mem_size (MACHINE *m) {
33 // return ((uint32_t)m->memptr) - ((uint32_t)m->membuf);
34 return m->memptr;
37 uint8_t* PMALLOC(uint16_t sz) {
38 uint8_t *ptr;
39 MACHINE *m = machine;
40 ATOMIC {
41 if ((machine_mem_size(m)+sz) > m->memlen)
42 MEM_GROW(m);
43 // post("M%d MALLOCING %d\n", m->id, sz);
44 m->memptr = word_align(m->memptr);
45 ptr = &m->membuf[m->memptr];
46 m->memptr += sz;
48 return ptr;
51 void MARK_MEM (VOID) {
52 ATOMIC machine->saved_memptr = machine->memptr;
55 void FREE_MEM (VOID) {
56 ATOMIC machine->memptr = machine->saved_memptr;
59 INLINE BOOL is_tracing (MACHINE *m) {
60 return is_tracing_val && (debug_id == -1 || debug_id == m->id);
63 INLINE BOOL is_debugging (MACHINE *m) {
64 return is_debugging_val && (debug_id == -1 || debug_id == m->id);
67 INLINE BOOL is_script_debugging (MACHINE *m) {
68 return is_script_debug_val && (debug_id == -1 || debug_id == m->id);
71 uint16_t timeout_of (uint8_t timeout_pow) {
72 return (uint16_t)ceil(pow(TIMEOUT_BASE, timeout_pow));
75 int rnd (int min, int max) {
76 return (rand() % (max - min + 1)) + min;
79 NUM_VAL num_rnd (NUM_VAL min, NUM_VAL max) {
80 FLO val = (double)rand() / (double)RAND_MAX;
81 return (val * (max - min)) + min;
84 static DATA *new_num(NUM_VAL i) {
85 return init_num((DATA*)PMALLOC(sizeof(DATA)), i);
88 MAYBE_INLINE DATA* init_vec (DATA* x, int n, int cap, DATA *f) {
89 int i, len = sizeof(VEC_VAL)+cap*sizeof(DATA);
90 VEC_VAL *dat = (VEC_VAL*)PMALLOC(len);
91 dat->n = n;
92 dat->cap = cap;
93 for (i = 0; i < n; i++)
94 DATA_SET(&dat->elts[i], f);
95 x->val.v = dat;
96 x->is_dead = FALSE;
97 x->tag = VEC_TAG;
98 return x;
101 VEC_VAL *ensure_vec(DATA *dat, int n) {
102 VEC_VAL *v = VEC_GET(dat);
103 if (dat->tag != VEC_TAG) {
104 DATA val; init_num(&val, 0);
105 init_vec(dat, n, n, &val);
106 return VEC_GET(dat);
107 } else if (n < v->n) {
108 if (n <= v->cap) {
109 v->n = n;
110 } else {
111 DATA val; init_num(&val, 0);
112 init_vec(dat, n, n, &val);
114 return VEC_GET(dat);
115 } else
116 return v;
119 DATA *data_copy (DATA *dst, DATA *src) {
120 dst->is_dead = src->is_dead;
121 switch (src->tag) {
122 case NUM_TAG:
123 DATA_SET(dst, src++);
124 break;
125 case VEC_TAG: {
126 VEC_VAL *vs = VEC_GET(src);
127 int n = vs->n;
128 VEC_VAL *vd = ensure_vec(dst, n);
129 int i;
130 for (i = 0; i < n; i++)
131 data_copy(&vd->elts[i], &vs->elts[i]);
132 break; }
133 default:
134 uerror("M%d UNKNOWN TAG %d\n", machine->id, src->tag);
136 return src;
139 VEC_VAL* grow_vec(VEC_VAL *v, int cap) {
140 int i, len = sizeof(VEC_VAL)+cap*sizeof(DATA);
141 VEC_VAL *dat = (VEC_VAL*)PMALLOC(len);
142 dat->n = v->n;
143 dat->cap = cap;
144 for (i = 0; i < v->n; i++)
145 data_copy(&dat->elts[i], &v->elts[i]);
146 POST("M%d GROW VEC %lx %d\n", machine->id, v, v->n);
147 // FREE(v);
148 return dat;
151 MAYBE_INLINE void ensure_len(VEC_VAL *v, int n) {
152 if (v->n != n) {
153 if (n > v->cap)
154 uerror("TOO FEW ELEMENTS %d > %d\n", n, v->cap);
155 v->n = n;
159 static DATA *new_vec(int n, DATA *f) {
160 return init_vec((DATA*)PMALLOC(sizeof(DATA)), n, n, f);
163 DATA *new_tup(int n, DATA *f) {
164 return new_vec(n, f);
167 INLINE int vec_len (VEC_VAL *vec) {
168 return vec->n;
171 INLINE void vec_zap (VEC_VAL *vec) {
172 vec->n = 0;
175 MAYBE_INLINE VEC_VAL* vec_add (VEC_VAL *vec, DATA *val) {
176 data_copy(&vec->elts[vec->n++], val);
177 if (vec->n > vec->cap)
178 vec = grow_vec(vec, 2*vec->cap);
179 return vec;
182 MAYBE_INLINE DATA *vec_elt (VEC_VAL *vec, int i) {
183 if (i < 0 || i >= vec->n)
184 uerror("UNBOUND VEC ELT %d > %d\n", i, vec->n);
185 return &vec->elts[i];
188 INLINE void init_data (DATA *dat, TAG tag, DATA_VAL val) {
189 dat->is_dead = FALSE;
190 dat->tag = tag;
191 dat->val = val;
194 MACHINE *machine;
196 #define NBR_NULL -1
198 INLINE void nbr_invalid_set (NBR *nbr) {
199 nbr->stamp = NBR_NULL;
202 INLINE void nbr_valid_set (NBR *nbr) {
203 nbr->stamp = 0;
206 INLINE BOOL is_nbr_valid (NBR *nbr) {
207 return nbr->stamp != NBR_NULL;
210 void del_nbr (int k) {
211 int i;
212 MACHINE *m = machine;
213 nbr_invalid_set(m->hood[k]);
214 for (i = k; i < (m->n_hood-1); i++)
215 m->hood[i] = m->hood[i+1];
216 m->n_hood -= 1;
219 void ins_nbr (NBR *nbr, int k) {
220 MACHINE *m = machine;
221 int i;
222 for (i = m->n_hood; i > k; i--)
223 m->hood[i] = m->hood[i-1];
224 m->hood[k] = nbr;
225 m->n_hood += 1;
228 void post_nbrs (MACHINE *m) {
229 int i;
230 for (i = 0; i < m->n_hood; i++)
231 POST("M%d|%lx ", m->hood[i]->id, m->hood[i]);
234 NBR *add_nbr (uint16_t src_id) {
235 int i, j;
236 MACHINE *m = machine;
237 NBR *nbr;
238 for (i = 0; i < MAX_HOOD; i++) {
239 nbr = &m->hood_data[i];
240 if (!is_nbr_valid(nbr)) {
241 nbr->id = src_id;
242 nbr->stamp = m->ticks;
243 nbr->time = m->time;
244 for (j = 0; j < m->n_hood; j++)
245 if (src_id < m->hood[j]->id) {
246 break;
248 ins_nbr(nbr, j);
249 // POST("M%d ADDING NBR %d: ", m->id, src_id); post_nbrs(m); POST("\n");
250 return nbr;
253 return NULL;
256 MAYBE_INLINE NBR *find_nbr (uint16_t src_id) {
257 MACHINE *m = machine;
258 int left = 0;
259 int right = m->n_hood-1;
260 // POST("M%d LOOKING UP NBR %d N_HOOD %d: ", m->id, src_id, m->n_hood);
261 // post_nbrs(m); POST("\n");
262 while (left <= right) {
263 int mid = (left + right)>>1;
264 NBR *nbr = m->hood[mid];
265 // POST("M%d LOOKING AT %d M%d\n", m->id, mid, nbr->id);
266 if (nbr->id == src_id) {
267 // POST("M%d FOUND NBR AT %d\n", mid);
268 return nbr;
269 } else if (src_id < nbr->id)
270 right = mid - 1;
271 else
272 left = mid + 1;
274 // POST("M%d LOST NBR %d\n", m->id, src_id);
275 return NULL;
278 extern void link_script (MACHINE *m);
279 extern void install_script(MACHINE *m, uint8_t *script, uint8_t slot, uint16_t len, uint8_t version);
280 extern void install_script_pkt(MACHINE *m, uint8_t pkt_num, uint8_t *script_pkt, uint16_t len);
281 void clear_pkt_tracker(void);
282 uint8_t add_pkt(uint8_t pkt_num);
283 int is_script_complete(void);
285 #define TRICKLE_BASE_TIME 5
286 #define TRICKLE_MAX_WAIT 100
287 uint16_t trickle_wait_time = 0;
288 uint16_t trickle_passed_time = 0;
290 void reinit_machine (MACHINE *m) {
291 int i;
292 m->n_hood = 0;
293 for (i = 0; i < N_SENSORS; i++)
294 m->sensors[i] = 0;
295 for (i = 0; i < MAX_HOOD; i++)
296 nbr_invalid_set(&m->hood_data[i]);
297 reinitHardware();
300 MACHINE *init_machine
301 (MACHINE *m, int id, int16_t x, int16_t y, int16_t z,
302 TIME desired_period, uint8_t *script, uint16_t script_len) {
303 int i;
304 m->id = id;
305 m->cur_script = 0;
306 for (i = 0; i < MAX_SCRIPTS; i++) {
307 m->scripts[i].version = 0;
308 m->scripts[i].is_complete = FALSE;
310 install_script(m, script, m->cur_script, script_len, m->scripts[m->cur_script].version);
311 trickle_wait_time = TRICKLE_BASE_TIME/2 + (rand()% TRICKLE_BASE_TIME /2);
312 m->is_digest = 1;
313 m->radio_range = read_radio_range();
314 m->radio_range_sqr = m->radio_range * m->radio_range;
315 m->x = x;
316 m->y = y;
317 m->z = z;
318 m->ticks = 0;
319 m->time = 0;
320 m->last_time = 0;
321 m->send_ticks = 0;
322 m->timeout = 0;
323 m->period = m->desired_period = desired_period;
324 // m->next_id = 0;
325 reinit_machine(m);
326 return m;
329 DATA nul_tup_dat;
331 MACHINE *new_machine
332 (MACHINE *m, int id, int16_t x, int16_t y, int16_t z,
333 TIME desired_period, uint8_t *script, uint16_t script_len) {
334 // MACHINE *m = (MACHINE*)PMALLOC(sizeof(MACHINE));
335 machine = m;
336 init_vec(&nul_tup_dat, 0, 0, NULL);
337 m = init_machine(m, id, x, y, z, desired_period, script, script_len);
338 MARK_MEM();
339 return m;
342 INLINE DATA *STATE_GET (uint8_t i) {
343 // if (i >= machine->n_state) uerror("STATE OVERFLOW");
344 return &machine->state[i].data;
347 MAYBE_INLINE DATA *STATE_SET (uint8_t i, DATA *val) {
348 DATA_SET(&machine->state[i].data, val);
349 return val;
352 INLINE BOOL IS_EXEC (uint8_t i) {
353 return machine->state[i].is_exec;
356 INLINE BOOL IS_EXEC_SET (uint8_t i, BOOL val) {
357 return machine->state[i].is_exec = val;
360 INLINE BOOL IS_OPEN (uint8_t i) {
361 return machine->state[i].is_open;
364 INLINE BOOL IS_OPEN_SET (uint8_t i, BOOL val) {
365 return machine->state[i].is_open = val;
368 ////
369 //// VIRTUAL MACHINE
370 ////
372 // shared VM functions in proto_vm.h
374 extern DATA *eval(DATA *res, FUN_VAL fun);
376 MAYBE_INLINE DATA funcall0 (FUN_VAL fun) {
377 DATA res;
378 FUN_PUSH(machine->pc);
379 eval(&res, fun);
380 return res;
383 MAYBE_INLINE DATA funcall1 (FUN_VAL fun, DATA *arg) {
384 DATA res;
385 FUN_PUSH(machine->pc);
386 ENV_PUSH(arg);
387 eval(&res, fun);
388 ENV_POP(1);
389 return res;
392 MAYBE_INLINE DATA funcall2 (FUN_VAL fun, DATA *a1, DATA *a2) {
393 DATA res;
394 FUN_PUSH(machine->pc);
395 ENV_PUSH(a1); ENV_PUSH(a2);
396 eval(&res, fun);
397 ENV_POP(2);
398 return res;
401 void clear_actuators (VOID) {
402 MACHINE *m = machine;
403 int i;
404 for (i = 0; i < N_ACTUATORS; i++)
405 m->actuators[i] = 0;
408 void clear_exports (VOID) {
409 MACHINE *m = machine;
410 int i;
411 for (i = 0; i < m->n_hood_vals; i++)
412 m->hood_exports[i].is_dead = TRUE;
415 void maybe_hibernate_machine (VOID) {
416 int i;
417 for (i = 0; i < machine->n_state; i++) {
418 if (!IS_EXEC(i))
419 IS_OPEN_SET(i, 0);
420 IS_EXEC_SET(i, 0);
424 void clear_is_exec (VOID) {
425 int i;
426 for (i = 0; i < machine->n_state; i++) {
427 IS_EXEC_SET(i, 0);
431 void clear_is_open (VOID) {
432 int i;
433 for (i = 0; i < machine->n_state; i++) {
434 IS_OPEN_SET(i, 0);
438 void open_machine (VOID) {
439 //MACHINE *m = machine;
440 // m->n_hood = 0;
441 // m->next_id = 0;
442 // for (i = 0; i < N_SENSORS; i++)
443 // m->sensors[i] = 0;
444 clear_actuators();
445 clear_is_exec();
446 clear_is_open();
447 // POST("M%d HOOD VALUES %d\n", m->id, m->n_hood_vals);
450 void close_machine (VOID) {
451 MACHINE *m = machine;
452 m->n_hood_vals = 0;
455 typedef union {
456 float f;
457 uint32_t i;
458 } FLOint;
460 #if IS_COMPRESSED_COM_DATA
461 INLINE NUM_VAL NUM_DECODE_VAL (COM_DATA *src) {
462 FLOint fi;
463 fi.i = ((uint32_t)(ntohs(src->val.n))) << 16;
464 return fi.f;
466 INLINE uint16_t NUM_ENCODE_VAL (DATA *src) {
467 FLOint fi;
468 fi.f = src->val.n;
469 return htons(fi.i >> 16);
471 #else
472 INLINE NUM_VAL NUM_DECODE_VAL (COM_DATA *src) {
473 return src->val.n;
475 INLINE NUM_VAL NUM_ENCODE_VAL (DATA *src) {
476 return src->val.n;
478 #endif
480 INLINE void NUM_DECODE (DATA *dst, COM_DATA *src) {
481 dst->is_dead = src->is_dead;
482 dst->tag = src->tag;
483 dst->val.n = NUM_DECODE_VAL(src);
487 INLINE void NUM_ENCODE (COM_DATA *dst, DATA *src) {
488 dst->is_dead = src->is_dead;
489 dst->tag = src->tag;
490 dst->val.n = NUM_ENCODE_VAL(src);
493 COM_DATA *data_decode (DATA *dst, COM_DATA *src) {
494 switch (src->tag) {
495 case NUM_TAG:
496 NUM_DECODE(dst, src++);
497 break;
498 case VEC_TAG: {
499 int is_dead = src->is_dead;
500 int n = (int)NUM_DECODE_VAL(src++);
501 VEC_VAL *v = ensure_vec(dst, n);
502 int i;
503 for (i = 0; i < n; i++)
504 src = data_decode(&v->elts[i], src++);
505 dst->is_dead = is_dead;
506 break; }
507 default:
508 if (src->is_dead)
509 NUM_DECODE(dst, src++);
510 else
511 uerror("M%d UNKNOWN TAG %d\n", machine->id, src->tag);
513 return src;
516 COM_DATA *data_encode (COM_DATA *dst, DATA *src, int *len) {
517 *len += 1;
518 switch (src->tag) {
519 case NUM_TAG:
520 NUM_ENCODE(dst++, src);
521 break;
522 case VEC_TAG: {
523 VEC_VAL *v = src->val.v;
524 int n = v->n;
525 int i;
526 DATA dat;
527 dat.is_dead = src->is_dead;
528 dat.tag = VEC_TAG;
529 dat.val.n = n;
530 NUM_ENCODE(dst, &dat);
531 dst++;
532 for (i = 0; i < n; i++)
533 dst = data_encode(dst, &v->elts[i], len);
534 break; }
535 default:
536 if (src->is_dead)
537 NUM_ENCODE(dst++, src);
538 else
539 uerror("M%d UNKNOWN TAG %d\n", machine->id, src->tag);
541 return dst;
544 INLINE int ABS(int x) { return (x < 0) ? -x : x; }
546 #define NBR_TIMEOUT 10 // Number of missed messages before punting.
547 // #define NBR_TIMEOUT 100000
549 void prune_hood (MACHINE *dst) {
550 int i,x;
551 TICKS newest = 0;
552 // for (i = 0; i < dst->n_hood; i++)
553 // newest = MAX(newest, dst->hood[i]->stamp);
554 newest = dst->ticks;
555 for (i = 0; i < dst->n_hood; i++) {
556 NBR *nbr = dst->hood[i];
557 // Buggy way of doing it: would wait as long as 1.6^{MAX_NBR_TIMEOUT + NBR_TIMEOUT}
558 //uint16_t nbr_timeout
559 // = timeout_of(nbr->timeout + NBR_TIMEOUT) - timeout_of(nbr->timeout);
560 // Timeout = Sum_{x=t+1}^{t+NBR_TIMEOUT}(timeout_of(MIN(x,MAX_NBR_TIMEOUT))
561 uint16_t nbr_timeout = 0;
562 if (is_throttling)
563 for(x=1;x<=NBR_TIMEOUT;x++)
564 nbr_timeout += timeout_of(MIN(nbr->timeout+x,MAX_NBR_TIMEOUT));
565 else
566 nbr_timeout = NBR_TIMEOUT;
567 if ((newest - nbr->stamp) > nbr_timeout) {
568 // POST("M%d DEL NBR %d: ", dst->id, nbr->id); post_nbrs(dst); POST("\n");
569 del_nbr(i);
574 void radio_receive_export
575 (uint16_t src_id, uint8_t version, uint8_t timeout, flo x, flo y, flo z, uint8_t n, COM_DATA *buf) {
576 int i;
577 COM_DATA *bp = buf;
578 MACHINE *dst = machine;
579 int is_debug = is_debugging(dst);
581 if (version == dst->scripts[dst->cur_script].version &&
582 n == dst->n_hood_vals) {
583 NBR *nbr = find_nbr(src_id);
584 if (nbr == NULL) {
585 if (is_debug) POST("M%d ADDING NBR %d\n", dst->id, src_id);
586 nbr = add_nbr(src_id);
587 if (nbr == NULL) {
588 return; // TODO: LRU
589 } else {
590 if (is_debug) POST("M%d ADDED %d V%d\n", dst->id, src_id, version);
592 } // else
593 // if (is_debug) POST("M%d FOUND NBR %d\n", dst->id, src_id);
594 nbr->stamp = dst->ticks;
595 nbr->timeout = timeout;
596 nbr->time = dst->time;
597 nbr->x = x;
598 nbr->y = y;
599 nbr->z = z;
600 // if (n > 1) POST("M%d RCVEXP[%d](%d):", dst->id, src_id, n-1);
601 if (is_debug) POST("M%d<-M%d %d %d IMPORTS ", dst->id, nbr->id, n, dst->n_hood_vals);
602 if (are_exports_serialized) {
603 for (i = 0; i < n; i++) {
604 bp = data_decode(&nbr->imports[i], bp);
605 if (is_debug) { POST("/%d/", i); post_data(&nbr->imports[i]); POST(" "); }
606 // POST(" %d ", dst->hood_exports[i].tag); post_data(&nbr->imports[i]);
608 } else
609 nbr->imports = (DATA*)buf;
610 if (is_debug) POST("\n");
611 // if (n > 1) POST("\n");
612 // else
613 // POST("ERROR %d<-%d DIFF NUMBER HOOD VALS %d VS %d\n",
614 // dst->id, src_id, n, dst->n_hood_vals+1);
615 } else {
616 if (is_debug) { POST("BAD VERSION %d OR N %d N_HOOD_VALS %d\n", version, n, dst->n_hood_vals); }
620 void hood_send (MACHINE *m, COM_DATA *buf, int n, COM_DATA *bp) {
621 if (is_throttling) {
622 BOOL is_timeout = ((m->ticks - m->send_ticks) > timeout_of(m->timeout));
623 BOOL is_fresh = (memcmp(m->next_buf, m->buf, m->buflen) != 0);
624 if (is_timeout || is_fresh) {
625 radio_send_export(m->scripts[m->cur_script].version, m->timeout, n, bp-buf, buf);
626 memcpy(m->buf, m->next_buf, m->buflen);
627 if (is_fresh || !is_throttling)
628 m->timeout = 0;
629 else
630 m->timeout = MIN(m->timeout + 1, MAX_NBR_TIMEOUT);
631 m->send_ticks = m->ticks;
633 } else {
634 radio_send_export(m->scripts[m->cur_script].version, m->timeout, n, bp-buf, buf);
635 m->send_ticks = m->ticks;
639 void export_machine (VOID) {
640 MACHINE *m = machine;
641 COM_DATA *buf, *bp;
642 int n, len, is_debug;
643 if (are_exports_serialized) {
644 buf = m->next_buf;
645 bp = buf;
646 is_debug = is_debugging(m);
647 len = 0;
648 memset(buf, 0, m->buflen);
649 // POST("SETTING TICKS %d\n", k);
650 if (is_debug) POST("M%d EXPORTS ", m->id);
651 for (n = 0; n < m->n_hood_vals; n++) {
652 DATA *out = &m->hood_exports[n];
653 bp = data_encode(bp, out, &len);
654 if (is_debug) { POST("<"); post_data(out); POST("> "); }
655 // POST("EXPORTING[%d/%d/%d/%d] ", i, m->n_hood_vals, k, m->scripts[m->cur_script].version);
656 // post_data(&m->hood_exports[i]);
657 // POST(" ");
658 // post_data(&buf[k-1]);
659 // POST("\n");
662 if (is_debug) POST("\n");
663 // POST("M%d HV %d N %d\n", m->id, m->n_hood_vals, bp-buf);
664 // POST("EXPORT SIZE %d == %d\n", (bp-buf)*sizeof(DATA), m->buflen);
665 if (((bp-buf)*sizeof(DATA)) > (m->buflen)) {
666 POST("EXPORT SIZE TOO BIG %d x %d > %d\n", len, m->buflen, sizeof(DATA));
668 } else {
669 bp = buf = (COM_DATA*)m->hood_exports;
670 n = m->n_hood_vals;
672 hood_send(m, buf, n, bp);
675 MAYBE_INLINE uint16_t num_pkts (uint16_t len) {
676 return (uint16_t)ceil(len / (float)MAX_SCRIPT_PKT);
679 void dump_byte (uint8_t byte, uint16_t n_bits) {
680 int j;
681 for (j = 0; j < n_bits; j++)
682 POST("%d", (byte>>j)&1);
685 void dump_digest (uint8_t *digest, uint16_t len) {
686 uint8_t i;
687 uint8_t npkts = num_pkts(len);
688 uint8_t major = npkts / 8;
689 uint8_t minor = npkts % 8;
690 // POST("L%d/P%d/J%d/N%d-", len, npkts, major, minor);
691 for (i = 0; i < major; i++)
692 dump_byte(digest[i], 8);
693 dump_byte(digest[major], minor);
696 void needed_and_available_pkts
697 (uint8_t *needed, uint8_t *nbr_digest, uint8_t *digest, uint16_t len) {
698 uint8_t i;
699 uint8_t npkts = num_pkts(len);
700 uint8_t major = npkts / 8;
701 // uint8_t minor = npkts % 8;
702 // POST("LEN %d NPKTS %d MAJOR %d MINOR %d\n", len, npkts, major, minor);
703 for (i = 0; i < (major+1); i++) {
704 needed[i] |= ~nbr_digest[i] & digest[i];
708 void radio_receive_digest(uint8_t version, uint16_t script_len, uint8_t *digest) {
709 MACHINE *m = machine;
710 SCRIPT *cur_script = &m->scripts[m->cur_script];
711 SCRIPT *nxt_script = &m->scripts[(m->cur_script+1)%MAX_SCRIPTS];
712 if (version > cur_script->version) {
713 if (version > nxt_script->version) {
714 if (is_script_debugging(m))
715 POST("M%d NEW VERSION %d LEN %d---\n", m->id, version, script_len);
716 clear_pkt_tracker();
717 nxt_script->is_complete = FALSE;
718 nxt_script->version = version;
719 nxt_script->len = script_len;
722 needed_and_available_pkts(m->pkt_listner, digest, m->pkt_tracker, script_len);
723 if (is_script_debugging(m)) {
724 POST("---M%d HAS VERSION %d LEN %d---\n", m->id, version, script_len);
725 POST("NEEDED: "); dump_digest(m->pkt_listner, script_len); POST("\n");
726 POST("HEARD: "); dump_digest(digest, script_len); POST("\n");
727 POST("HAVE: "); dump_digest(m->pkt_tracker, script_len); POST("\n");
731 void radio_receive_script_pkt (uint8_t version, uint16_t n, uint8_t pkt_num, uint8_t *script_pkt) {
732 MACHINE *m = machine;
733 SCRIPT *cur_script = &m->scripts[m->cur_script];
734 SCRIPT *nxt_script = &m->scripts[(m->cur_script+1)%MAX_SCRIPTS];
737 if (is_script_debugging(m))
738 POST("M%d RCV PKT %d VER %d LEN %d CUR %d NXT %d DON %d\n",
739 m->id, pkt_num, version, n, cur_script->version, nxt_script->version, cur_script->is_complete);
740 if (version > cur_script->version || (MAX_SCRIPTS == 1 && !cur_script->is_complete)) {
741 if (version == nxt_script->version) {
742 if (is_script_debugging(m))
743 POST("M%d GOT PKT %d VER %d LEN %d\n", m->id, pkt_num, version, n);
744 install_script_pkt(m, pkt_num, script_pkt, n);
745 } else if (version > nxt_script->version) {
746 if (is_script_debugging(m)) {
747 POST("M%d NEW VERSION\n", m->id);
748 POST("M%d GOT PKT %d VER %d LEN %d\n", m->id, pkt_num, version, n);
750 clear_pkt_tracker();
751 nxt_script->version = version;
752 nxt_script->is_complete = FALSE;
753 install_script_pkt(m, pkt_num, script_pkt, n);
755 if (is_script_complete()) {
756 m->cur_script = (m->cur_script+1)%MAX_SCRIPTS;
757 if (is_script_debugging(m))
758 POST("M%d PACKET COMPLETE LEN %d\n", m->id, nxt_script->len);
759 m->scripts[m->cur_script].is_complete = TRUE;
760 // clear_pkt_tracker();
761 link_script(m);
763 ATOMIC {
764 FREE_MEM();
765 open_machine();
772 void export_script (VOID) {
773 MACHINE *m = machine;
774 uint8_t i;
775 // char OutputMsg[80];
777 /* ++trickle_passed_time; */
778 /* if(trickle_passed_time > trickle_wait_time){ */
779 /* trickle_passed_time = 0; */
780 /* trickle_wait_time = MAX(trickle_wait_time/2, TRICKLE_MAX_WAIT /2) */
781 /* + (rand()% MAX(trickle_wait_time/2, TRICKLE_MAX_WAIT /2)); */
782 /* } */
784 SCRIPT *nxt_script;
786 if (m->scripts[(m->cur_script+1)%MAX_SCRIPTS].version > m->scripts[m->cur_script].version)
787 nxt_script = &m->scripts[(m->cur_script+1)%MAX_SCRIPTS];
788 else
789 nxt_script = &m->scripts[m->cur_script];
791 for (i = 0; i < num_pkts(nxt_script->len); i++) {
792 uint8_t major = i / 8;
793 uint8_t minor = i % 8;
795 if (m->pkt_listner[major] & (1 << minor)) {
797 if (is_script_debugging(m))
798 POST("M%d SND PKT %d VER %d LEN %d\n",
799 m->id, i, m->scripts[m->cur_script].version, m->scripts[m->cur_script].len);
800 radio_send_script_pkt(nxt_script->version, nxt_script->len,
801 i, &nxt_script->bytes[i * MAX_SCRIPT_PKT]);
802 return;
805 if (is_script_debugging(m)) {
806 POST("M%d DIGEST: ", m->id); dump_digest(m->pkt_tracker, nxt_script->len); POST("\n");
808 radio_send_digest(nxt_script->version, nxt_script->len, m->pkt_tracker);
811 void script_pkt_callback(uint8_t pkt_num){
812 MACHINE *m = machine;
813 uint8_t major = pkt_num / 8;
814 uint8_t minor = pkt_num % 8;
815 ATOMIC m->pkt_listner[major] &= ~(1 << minor);
818 void exec_machine (TICKS ticks, TIME time) {
819 MACHINE *m = machine;
820 SCRIPT *s = &m->scripts[m->cur_script];
821 #ifdef IS_MOTE
822 m->last_time = m->time;
823 m->time = time;
824 m->ticks = ticks;
825 #endif
826 if (s->is_complete) {
827 #ifndef IS_MOTE
828 m->last_time = m->time;
829 m->time = time;
830 m->ticks = ticks;
831 #endif
832 if (is_debugging(m) || is_tracing(m)) {
833 depth = 0;
834 POST("M%d EXEC %f V%d\n", m->id, m->ticks, s->version);
836 clear_actuators();
837 clear_exports();
838 prune_hood(m);
839 m->res = funcall0(m->exec);
840 maybe_hibernate_machine();
844 INLINE uint8_t n_hood (VOID) {
845 return machine->n_hood;
848 INLINE NUM_VAL num_vec_elt (VEC_VAL *v, int i) { return NUM_GET(vec_elt(v, i)); }
849 INLINE NUM_VAL num_vec_elt_set (VEC_VAL *v, int i, NUM_VAL x) { return NUM_SET(vec_elt(v, i), x); }
852 // VECTOR OPERATIONS
855 //Create Tuples
856 INLINE void tup_exec (int n, int offset) {
857 int i;
858 DATA *data = GLO_GET(offset);
859 VEC_VAL *v = VEC_GET(data);
860 for (i = 0; i < n; i++)
861 DATA_SET(&v->elts[i], PEEK(n-i-1));
862 NPOP(n); PUSH(data);
865 //Access Elements of Vectors
866 INLINE void elt_exec (VOID) {
867 VEC_VAL *val = VEC_PEEK(1);
868 NUM_VAL k = NUM_PEEK(0);
869 NPOP(2); PUSH(vec_elt(val, (int)k));
872 //Hook for getting Length of Vectors
873 INLINE void len_exec(void) {
874 VEC_VAL *v1 = VEC_POP();
875 NUM_PUSH(v1->n);
878 //Vector addition: the shorter vector has elements padded with 0 to match len
879 void vadd_exec (int off) {
880 int i;
881 VEC_VAL *vr = VEC_GET(GLO_GET(off));
882 VEC_VAL *v0 = VEC_PEEK(1);
883 VEC_VAL *v1 = VEC_PEEK(0);
884 int n0 = v0->n;
885 int n1 = v1->n;
886 int nMin = MIN(n0,n1);
887 int nMax = MAX(n0,n1);
888 VEC_VAL *vlarger = (n0 == nMax) ? v0 : v1;
889 ensure_len(vr, nMax);
891 for (i = 0; i < nMin; i++) {
892 NUM_SET(vec_elt(vr,i), NUM_GET(vec_elt(v0,i)) + NUM_GET(vec_elt(v1, i)));
895 for (i = nMin; i < nMax; i++) {
896 NUM_SET(vec_elt(vr,i), NUM_GET(vec_elt(vlarger,i)));
899 NPOP(2); VEC_PUSH(vr);
902 void vsub_exec (int off) {
903 int i;
904 VEC_VAL *vr = VEC_GET(GLO_GET(off));
905 VEC_VAL *v0 = VEC_PEEK(1);
906 VEC_VAL *v1 = VEC_PEEK(0);
907 int n0 = v0->n;
908 int n1 = v1->n;
909 int nMin = MIN(n0, n1);
910 int nMax = MAX(n0, n1);
911 ensure_len(vr, nMax);
913 VEC_VAL *vlarger = (n0 == nMax) ? v0 : v1;
914 int sign = (n0 == nMax) ? 1 : -1; /*If v1 is longer than v0, padding means
915 that we're subtracting elts of v1 from "0". So -ve.
918 for (i = 0; i < nMin; i++) {
919 NUM_SET(vec_elt(vr, i), NUM_GET(vec_elt(v0, i)) - NUM_GET(vec_elt(v1, i)));
921 for (i = nMin; i < nMax; i++) {
922 NUM_SET(vec_elt(vr, i), sign * NUM_GET(vec_elt(vlarger,i)));
925 NPOP(2); VEC_PUSH(vr);
928 //Scalar Multiplication
929 void vmul_exec (int off) {
930 VEC_VAL *vr = VEC_GET(GLO_GET(off));
931 NUM_VAL n = NUM_PEEK(1);
932 VEC_VAL *v1 = VEC_PEEK(0);
933 int i;
934 int n1 = v1->n;
935 ensure_len(vr, n1);
937 for (i = 0; i < n1; i++)
938 NUM_SET(vec_elt(vr, i), n * NUM_GET(vec_elt(v1, i)));
940 NPOP(2); VEC_PUSH(vr);
943 void vdot_exec (VOID) {
944 NUM_VAL val = 0;
945 VEC_VAL *v0 = VEC_PEEK(1);
946 VEC_VAL *v1 = VEC_PEEK(0);
947 int i;
948 int n0 = vec_len(v0);
949 int n1 = vec_len(v1);
950 int nr = MIN(n0, n1);
951 for (i = 0; i < nr; i++)
952 val += NUM_GET(vec_elt(v0, i)) * NUM_GET(vec_elt(v1, i));
953 NPOP(2); NUM_PUSH(val);
957 Slicing is designed to work like in python.
959 void vslice_exec (int off) {
960 //TODO: When we have optional arguments, add "step" as optional argument
961 VEC_VAL *v1 = VEC_PEEK(0);
962 NUM_VAL len = vec_len(v1);
963 //Negative Indices are taken to mean len + index.
964 NUM_VAL start = NUM_PEEK(1) >= 0 ? NUM_PEEK(1): len + NUM_PEEK(1);
965 NUM_VAL stop = NUM_PEEK(2) >= 0 ? NUM_PEEK(2): len + NUM_PEEK(2);
966 //TODO: Check if stop index is greater than len
967 VEC_VAL *vr = VEC_GET(GLO_GET(off));
968 int ans_len = stop - start;
969 ensure_len(vr, ans_len);
970 int i;
972 for (i = 0; i < ans_len; i++)
973 NUM_SET(vec_elt(vr,i), NUM_GET(vec_elt(v1,start + i)));
974 NPOP(2); VEC_PUSH(vr);
978 /*Vector Comparison Operations.
979 If two vectors are of unequal length, the shorter one is padded with zeros.
980 i.e. The Comparison is lexicographical
981 Both LT and GT are defined to deal with infinities.
984 int vlt_op(VEC_VAL *v0, VEC_VAL *v1) {
985 int i;
987 int n0 = v0->n;
988 int n1 = v1->n;
989 int nMax = MAX(n0,n1);
991 for (i = 0; i < nMax; i++) {
992 NUM_VAL x0 = (i < n0) ? num_vec_elt(v0,i) : 0;
993 NUM_VAL x1 = (i < n1) ? num_vec_elt(v1,i) : 0;
994 if (x0 < x1) {
995 return 1;
996 } else if (x0 > x1) {
997 return 0;
1000 return 0;
1003 int vgt_op(VEC_VAL *v0, VEC_VAL *v1) {
1004 int i;
1006 int n0 = vec_len(v0);
1007 int n1 = vec_len(v1);
1008 int nMax = MAX(n0,n1);
1010 for (i = 0; i < nMax; i++) {
1011 NUM_VAL x0 = (i < n0) ? num_vec_elt(v0,i) : 0;
1012 NUM_VAL x1 = (i < n1) ? num_vec_elt(v1,i) : 0;
1013 if (x0 > x1) {
1014 return 1;
1015 } else if (x0 < x1) {
1016 return 0;
1019 return 0;
1022 int veq_op(VEC_VAL *v0, VEC_VAL *v1) {
1023 int i;
1025 int n0 = vec_len(v0);
1026 int n1 = vec_len(v1);
1027 int nMax = MAX(n0,n1);
1029 for (i = 0; i < nMax; i++) {
1030 NUM_VAL x0 = (i < n0) ? num_vec_elt(v0,i) : 0;
1031 NUM_VAL x1 = (i < n1) ? num_vec_elt(v1,i) : 0;
1032 if (x0 != x1) {
1033 return 0;
1036 return 1;
1039 void vlt_exec (VOID) {
1040 VEC_VAL *v0 = VEC_PEEK(1);
1041 VEC_VAL *v1 = VEC_PEEK(0);
1042 NPOP(2); NUM_PUSH(vlt_op(v0, v1));
1045 void vgt_exec (VOID) {
1046 VEC_VAL *v0 = VEC_PEEK(1);
1047 VEC_VAL *v1 = VEC_PEEK(0);
1048 NPOP(2); NUM_PUSH(vgt_op(v0, v1));
1051 void veq_exec (VOID) {
1052 VEC_VAL *v0 = VEC_PEEK(1);
1053 VEC_VAL *v1 = VEC_PEEK(0);
1054 NPOP(2); NUM_PUSH(veq_op(v0, v1));
1057 void vlte_exec (VOID) {
1058 VEC_VAL *v0 = VEC_PEEK(1);
1059 VEC_VAL *v1 = VEC_PEEK(0);
1060 NPOP(2); NUM_PUSH(vlt_op(v0, v1) || veq_op(v0, v1));
1063 void vgte_exec (VOID) {
1064 VEC_VAL *v0 = VEC_PEEK(1);
1065 VEC_VAL *v1 = VEC_PEEK(0);
1066 NPOP(2); NUM_PUSH(vgt_op(v0, v1) || veq_op(v0, v1));
1069 void vmin_exec (VOID) {
1070 VEC_VAL *v0 = VEC_PEEK(1);
1071 VEC_VAL *v1 = VEC_PEEK(0);
1072 int is_less = vlt_op(v0, v1);
1073 NPOP(2); VEC_PUSH(is_less ? v0 : v1);
1076 void vmax_exec (VOID) {
1077 VEC_VAL *v0 = VEC_PEEK(1);
1078 VEC_VAL *v1 = VEC_PEEK(0);
1079 int is_greater = vgt_op(v0, v1);
1080 NPOP(2); VEC_PUSH(is_greater ? v0 : v1);
1085 // Feedback & Neighbor Operations
1088 void init_feedback_exec (uint8_t state_off) {
1089 DATA res;
1090 // POST("M%d EXECING INIT-FEEDBACK %d %d\n", machine->id, machine->pc, state_off);
1091 if (!IS_OPEN(state_off)) {
1092 res = funcall0(FUN_PEEK(0));
1093 // POST("M%d RESETTING FEEDBACK %d -> ", machine->id, state_off);
1094 // post_data(&res); POST("\n");
1095 STATE_SET(state_off, &res);
1096 IS_OPEN_SET(state_off, 1);
1098 NPOP(1); PUSH(STATE_GET(state_off));
1101 void feedback_exec (uint8_t state_off) {
1102 DATA *res;
1103 // POST("M%d EXECING FEEDBACK %d %d\n", machine->id, machine->pc, state_off);
1104 IS_EXEC_SET(state_off, 1);
1105 res = PEEK(0);
1106 STATE_SET(state_off, res);
1107 NPOP(2); PUSH(res);
1110 INLINE NUM_VAL nbr_bearing (VOID) {
1111 MACHINE *m = machine;
1112 return atan2f(m->nbr_x , m->nbr_y);
1115 INLINE NUM_VAL nbr_lag (VOID) {
1116 MACHINE *m = machine;
1117 return m->nbr_lag;
1120 INLINE NUM_VAL nbr_range (VOID) {
1121 MACHINE *m = machine;
1122 return sqrt(m->nbr_x*m->nbr_x + m->nbr_y*m->nbr_y + m->nbr_z*m->nbr_z);
1125 #define NUM_AREA_BINS 16
1127 NUM_VAL machine_area (MACHINE *m) {
1128 int i;
1129 /* Deprecated for geometric incoherence
1130 // Note: this function assumes knowledge of neighbor relative X-Y position
1131 // and operates only in 2D. It should really be some smarter sort of
1132 // voronoi-ish calculation
1133 NUM_VAL radii[NUM_AREA_BINS];
1134 int counts[NUM_AREA_BINS];
1135 NUM_VAL radius, tot_radius, tot_count;
1136 for (i = 0; i < NUM_AREA_BINS; i++) {
1137 counts[i] = 0;
1138 radii[i] = m->radio_range;
1140 for (i = 0; i < m->n_hood; i++) {
1141 NBR *nbr = m->hood[i];
1142 flo angle = atan2f(nbr->y, nbr->x) + M_PI;
1143 flo range = sqrt(nbr->x*nbr->x + nbr->y*nbr->y); // once used 3D info badly
1144 int off = floor(NUM_AREA_BINS * angle / (2*M_PI));
1145 if (counts[off] == 0)
1146 radii[off] = 0;
1147 radii[off] += range;
1148 counts[off] += 1;
1150 tot_radius = tot_count = 0;
1151 for (i = 0; i < NUM_AREA_BINS; i++) {
1152 tot_radius += radii[i];
1153 tot_count += MAX(1, counts[i]);
1155 radius = (tot_radius / tot_count);
1158 // This is an estimate made with no neighbor location information
1159 // given neighbor X/Y or X/Y/Z information, a better estimate can be made
1160 NUM_VAL radius = m->radio_range;
1161 return radius*radius * M_PI / (m->n_hood + 1);
1164 INLINE void fold_one (FUN_VAL fuse, uint16_t id, DATA *res, DATA *src) {
1165 DATA val = funcall2(fuse, res, src);
1166 if (is_debugging(machine)) { POST("M%d ", id); /* POST("[%.1f %.1f]", nbr_range(), nbr_bearing()); */ POST("<"); post_data(res); POST(" "); post_data(src); POST(">=>"); post_data(&val); POST(" "); }
1167 data_copy(res, &val);
1170 void do_fold_hood_exec (DATA *res, int off) {
1171 MACHINE *m = machine;
1172 FUN_VAL fuse = FUN_PEEK(2);
1173 DATA *init = PEEK(1);
1174 DATA *expr = PEEK(0);
1175 int is_debug = is_debugging(m);
1176 int i;
1177 // char OutputMsg[32];
1178 data_copy(res, init);
1179 // if (off >= m->n_hood_vals) uerror("EXPORTS OVERFLOW");
1180 if (is_debug) { POST("M%d(%d,%d) ", m->id, m->n_hood, off); post_data(res); POST(" "); }
1181 m->nbr_x = m->nbr_y = m->nbr_z = 0;
1182 m->nbr_lag = m->time - m->last_time;
1183 fold_one(fuse, m->id, res, expr);
1184 DATA_SET(&m->hood_exports[off], expr);
1185 if (is_debug) { POST("{"); post_data(expr); POST("}"); }
1186 for (i = 0; i < m->n_hood; i++) {
1187 NBR *nbr = m->hood[i];
1188 DATA *import = &nbr->imports[off];
1189 if (!import->is_dead) {
1190 DATA imp;
1191 init_data(&imp, (TAG)expr->tag, import->val);
1192 m->nbr_x = nbr->x; m->nbr_y = nbr->y; m->nbr_z = nbr->z;
1193 m->nbr_lag = m->time - nbr->time;
1194 fold_one(fuse, m->hood[i]->id, res, &imp);
1195 } else if (is_debug)
1196 POST("M%d DEAD ", m->hood[i]->id);
1198 if (is_debug) { POST("=> "); post_data(res); POST("\n"); }
1199 NPOP(3); PUSH(res);
1202 INLINE void mold_fold_one (FUN_VAL mold, FUN_VAL fuse, uint16_t id, DATA *res, DATA *src) {
1203 DATA x = funcall1(mold, src);
1204 DATA val = funcall2(fuse, res, &x);
1205 if (is_debugging(machine)) { POST("M%d ", id); /* POST("[%.1f %.1f]", nbr_range(), nbr_bearing()); */ POST("<"); post_data(res); POST(" "); post_data(&x); POST(">=>"); post_data(&val); POST(" "); }
1206 data_copy(res, &val);
1209 void do_fold_hood_plus_exec (DATA *res, int off) {
1210 MACHINE *m = machine;
1211 FUN_VAL fuse = FUN_PEEK(2);
1212 FUN_VAL mold = FUN_PEEK(1);
1213 DATA *expr = PEEK(0);
1214 DATA val;
1215 int is_debug = is_debugging(m);
1216 int i;
1217 // char OutputMsg[32];
1218 // if (off >= m->n_hood_vals) uerror("EXPORTS OVERFLOW");
1219 if (is_debug) { POST("M%d(%d,%d) ", m->id, m->n_hood, off); post_data(res); POST(" "); }
1220 m->nbr_x = m->nbr_y = m->nbr_z = 0;
1221 m->nbr_lag = m->time - m->last_time;
1222 val = funcall1(mold, expr);
1223 data_copy(res, &val);
1224 DATA_SET(&m->hood_exports[off], expr);
1225 if (is_debug) { POST("{"); post_data(expr); POST("}"); }
1226 for (i = 0; i < m->n_hood; i++) {
1227 NBR *nbr = m->hood[i];
1228 DATA *import = &nbr->imports[off];
1229 if (!import->is_dead) {
1230 DATA imp;
1231 init_data(&imp, (TAG)expr->tag, import->val);
1232 m->nbr_x = nbr->x; m->nbr_y = nbr->y; m->nbr_z = nbr->z;
1233 m->nbr_lag = m->time - nbr->time;
1234 mold_fold_one(mold, fuse, m->hood[i]->id, res, &imp);
1235 } else if (is_debug)
1236 POST("M%d DEAD ", m->hood[i]->id);
1238 if (is_debug) { POST("=> "); post_data(res); POST("\n"); }
1239 NPOP(3); PUSH(res);
1242 void apply_exec (VOID) {
1243 FUN_VAL fun = FUN_PEEK(1);
1244 VEC_VAL *args = VEC_PEEK(0);
1245 DATA res;
1246 int n = vec_len(args);
1247 int i;
1249 FUN_PUSH(machine->pc);
1250 for (i = 0; i < n; i++)
1251 ENV_PUSH(vec_elt(args, i));
1252 eval(&res, fun);
1253 ENV_POP(n);
1254 NPOP(2); PUSH(&res);
1257 void map_exec (int off) {
1258 VEC_VAL *res = VEC_GET(GLO_GET(off));
1259 FUN_VAL fun = FUN_PEEK(1);
1260 VEC_VAL *vec = VEC_PEEK(0);
1261 int n = vec_len(vec);
1262 int i;
1263 vec_zap(res);
1264 for (i = 0; i < n; i++) {
1265 DATA val = funcall1(fun, vec_elt(vec, i));
1266 res = vec_add(res, &val);
1268 VEC_SET(GLO_GET(off), res);
1269 NPOP(2); VEC_PUSH(res);
1272 void do_fold_exec (DATA *res) {
1273 FUN_VAL fun = FUN_PEEK(2);
1274 DATA *init = PEEK(1);
1275 VEC_VAL *vec = VEC_PEEK(0);
1276 int n = vec_len(vec);
1277 int i;
1278 data_copy(res, init);
1279 for (i = 0; i < n; i++) {
1280 DATA val = funcall2(fun, res, vec_elt(vec, i));
1281 data_copy(res, &val);
1283 NPOP(3); PUSH(res);
1286 void fold_exec (VOID) {
1287 DATA res; do_fold_exec(&res);
1290 void vfold_exec (int roff) {
1291 DATA *res = GLO_GET(roff);
1292 do_fold_exec(res);
1295 static int max_stack_size = 0;
1297 INLINE void check_stack (MACHINE *m) {
1298 int delta = (m->sp - m->stack);
1299 max_stack_size = MAX(delta, max_stack_size);
1300 if (delta > m->n_stack)
1301 uerror("STACK OVERFLOW %d > %d\n", delta, m->n_stack);
1302 if (delta < 0)
1303 uerror("STACK UNDERFLOW\n");
1306 static int max_env_size = 0;
1308 INLINE void check_env (MACHINE *m) {
1309 int delta = (m->ep - m->env);
1310 max_env_size = MAX(delta, max_env_size);
1311 if (delta > m->n_env)
1312 uerror("ENV OVERFLOW %d > %d\n", delta, m->n_env);
1313 if (delta < 0)
1314 uerror("ENV UNDERFLOW\n");
1317 INLINE void dump_stack (MACHINE *m) {
1318 if (is_tracing(m)) {
1319 int i;
1320 int max_dump = 6; // 99
1321 POST("---\n");
1322 // POST("S[%d]E[%d]\n", max_stack_size, max_env_size);
1323 for (i = 0; i < MIN(m->sp - m->stack, max_dump); i++) {
1324 POST("->S[%d] ", i); post_data(PEEK(i)); POST("\n");
1326 for (i = 0; i < MIN(m->ep - m->env, max_dump); i++) {
1327 POST("->E[%d] ", i); post_data(ENV_PEEK(i)); POST("\n");
1332 typedef union {
1333 flo val;
1334 uint8_t bytes[4];
1335 uint32_t fourBytes;
1336 } FLO_BYTES;
1338 MAYBE_INLINE void def_fun_exec (MACHINE *m, uint16_t skip) {
1339 DATA res;
1340 FUN_SET(&res, m->pc);
1341 m->pc += skip;
1342 GLO_SET(m->n_globals++, &res);
1345 #define INF 1.0e12
1347 DATA *eval(DATA *res, FUN_VAL fun) {
1348 MACHINE *m = machine;
1349 SCRIPT *script = &m->scripts[m->cur_script];
1350 uint8_t op, i;
1351 int is_trace = is_tracing(m);
1352 // char msg[16];
1353 m->pc = fun;
1355 if (fun > script->len)
1356 uerror("BOGUS FUNCTION %d\n", fun);
1357 if (is_trace)
1358 POST("M%d EVAL AT %d\n", m->id, fun);
1359 dump_stack(m);
1360 for (i = 0;;i++) {
1361 // putstring(" PC:"); putnum_ud(m->pc);
1362 op = NXT_OP(m);
1363 if (is_trace) {
1364 char *name; lookup_op_by_code (op, &name);
1365 POST("%3d: OP %3d %s\n", m->pc-1, op, name);
1367 if(op < CORE_CMD_OPS) {
1368 switch (op) {
1369 case DEF_VM_OP: {
1370 int export_len = NXT_OP(m);
1371 int n_exports = NXT_OP(m);
1372 int n_globals = NXT_OP16(m);
1373 int n_state = NXT_OP(m);
1374 int n_stack = NXT_OP16(m);
1375 int n_env = NXT_OP(m);
1376 if (debug_id == m->id)
1377 POST("M%d MEM SIZE %d\n", m->id, machine_mem_size(m));
1378 if (debug_id == m->id)
1379 POST("EXPORT_LEN %d N_EXPORTS %d N_GLOBALS %d N_STATE %d N_STK %d N_ENV %d\n",
1380 export_len, n_exports, n_globals, n_state, n_stack, n_env);
1381 m->n_hood_vals = n_exports;
1382 m->max_globals = n_globals;
1383 m->n_state = n_state;
1384 // m->n_stack = n_stack;
1385 m->hood_exports = (DATA*)PMALLOC(n_exports * sizeof(DATA));
1386 m->buflen = export_len * sizeof(DATA);
1387 m->buf = (COM_DATA*)PMALLOC(m->buflen);
1388 memset(m->buf, 0, m->buflen);
1389 if (is_throttling) {
1390 m->next_buf = (COM_DATA*)PMALLOC(m->buflen);
1391 memset(m->next_buf, 0, m->buflen);
1392 } else
1393 m->next_buf = m->buf;
1394 if (are_exports_serialized) {
1395 for (i = 0; i < MAX_HOOD; i++)
1396 m->hood_data[i].imports = (DATA*)PMALLOC(n_exports * sizeof(DATA));
1398 m->state = (STATE*)PMALLOC(n_state * sizeof(STATE));
1399 m->globals = (DATA*)PMALLOC(n_globals * sizeof(DATA));
1400 m->n_stack = n_stack;
1401 m->stack = (DATA*)PMALLOC(n_stack * sizeof(DATA));
1402 m->n_env = n_env;
1403 m->env = (DATA*)PMALLOC(n_env * sizeof(DATA));
1404 if (debug_id == m->id)
1405 POST("M%d MEM SIZE %d\n", m->id, machine_mem_size(m));
1406 m->sp = m->stack;
1407 m->ep = m->env;
1408 // m->n_env = n_env;
1409 break; }
1410 case EXIT_OP:
1411 return res;
1412 case INF_OP:
1413 NUM_PUSH(INFINITY);
1414 break;
1415 case LIT8_OP:
1416 case LIT_0_OP: case LIT_1_OP: case LIT_2_OP: case LIT_3_OP: case LIT_4_OP: {
1417 int n = op == LIT8_OP ? NXT_OP(m) : op - LIT_0_OP;
1418 NUM_PUSH(n);
1419 break; }
1420 case LIT16_OP: {
1421 NUM_VAL val = NXT_OP16(m);
1422 NUM_PUSH(val);
1423 break; }
1424 case LIT_FLO_OP: {
1425 FLO_BYTES fb;
1426 fb.bytes[3] = NXT_OP(m); //
1427 fb.bytes[2] = NXT_OP(m); // Pack th' float in network
1428 fb.bytes[1] = NXT_OP(m); // byte order (big endian).
1429 fb.bytes[0] = NXT_OP(m); //
1430 fb.fourBytes = ntohl(fb.fourBytes); // Convert float into host byte order.
1431 NUM_PUSH(fb.val); // Load onto stack in float form.
1432 break; }
1433 case DEF_OP: {
1434 DATA data;
1435 GLO_SET(m->n_globals++, POP(&data));
1436 break; }
1437 case DEF_TUP_OP: case FAB_TUP_OP: {
1438 VEC_VAL *v;
1439 DATA data, num;
1440 int n = NXT_OP(m);
1441 init_vec(&data, n, n, init_num(&num, 0.0));
1442 v = VEC_GET(&data);
1443 for (i = 0; i < n; i++)
1444 DATA_SET(&v->elts[i], PEEK(n-i-1));
1445 NPOP(n);
1446 if (op == DEF_TUP_OP)
1447 GLO_SET(m->n_globals++, &data);
1448 else
1449 PUSH(&data);
1450 break; }
1451 case NUL_TUP_OP:
1452 PUSH(&nul_tup_dat);
1453 break;
1454 case DEF_NUM_VEC_OP: case DEF_NUM_VEC_1_OP: case DEF_NUM_VEC_2_OP: case DEF_NUM_VEC_3_OP:
1455 case FAB_NUM_VEC_OP: {
1456 DATA data, num;
1457 int n = (op == DEF_NUM_VEC_OP || op == FAB_NUM_VEC_OP) ? NXT_OP(m) : op - DEF_NUM_VEC_OP;
1458 init_vec(&data, n, n, init_num(&num, 0.0));
1459 if (op != FAB_NUM_VEC_OP)
1460 GLO_SET(m->n_globals++, &data);
1461 else
1462 PUSH(&data);
1463 break; }
1464 case DEF_VEC_OP: case FAB_VEC_OP: {
1465 VEC_VAL *v;
1466 DATA data, arg, num;
1467 int n = NXT_OP(m);
1468 init_vec(&data, n, n, init_num(&num, 0.0));
1469 v = VEC_GET(&data);
1470 POP(&arg);
1471 for (i = 1; i < n; i++)
1472 data_copy(&v->elts[i], &arg);
1473 if (op == DEF_VEC_OP)
1474 GLO_SET(m->n_globals++, &data);
1475 else
1476 PUSH(&data);
1477 break; }
1478 case LET_OP:
1479 case LET_1_OP: case LET_2_OP: case LET_3_OP: case LET_4_OP: {
1480 int n = op == LET_OP ? NXT_OP(m) : op - LET_OP;
1481 // if (is_trace) { POST("BEF LET N %d SP %lx ST %lx DELTA %d\n", n, m->sp, m->stack, (m->sp - m->stack)); }
1482 for (i = n; i > 0; i--)
1483 DATA_SET(m->ep++, (m->sp-i));
1484 // if (is_trace) { POST("MID LET N %d EDELTA %d SP %lx ST %lx DELTA %d\n", n, (m->ep - m->env), m->sp, m->stack, (m->sp - m->stack)); }
1485 m->sp -= n;
1486 // if (is_trace) { POST("AFT LET N %d SP %lx ST %lx DELTA %d\n", n, m->sp, m->stack, (m->sp - m->stack)); }
1487 break; }
1488 case REF_OP:
1489 case REF_0_OP: case REF_1_OP: case REF_2_OP: case REF_3_OP: {
1490 int off = op == REF_OP ? NXT_OP(m) : op - REF_0_OP;
1491 PUSH(m->ep-off-1);
1492 break; }
1493 case GLO_REF16_OP: {
1494 uint16_t off = NXT_OP16(m);
1495 PUSH(&m->globals[off]);
1496 break; }
1497 case GLO_REF_OP:
1498 case GLO_REF_0_OP: case GLO_REF_1_OP: case GLO_REF_2_OP: case GLO_REF_3_OP: {
1499 int off = op == GLO_REF_OP ? NXT_OP(m) : op - GLO_REF_0_OP;
1500 PUSH(&m->globals[off]);
1501 break; }
1502 case POP_LET_OP:
1503 case POP_LET_1_OP: case POP_LET_2_OP: case POP_LET_3_OP: case POP_LET_4_OP: {
1504 int n = op == POP_LET_OP ? NXT_OP(m) : op - POP_LET_OP;
1505 m->ep -= n;
1506 break; }
1507 case NO_OP:
1508 break;
1509 case MUX_OP: {
1510 DATA *reso = NUM_PEEK(2) ? PEEK(1) : PEEK(0); NPOP(3); PUSH(reso);
1511 break; }
1512 case VMUX_OP: {
1513 int roff = NXT_OP(m);
1514 DATA *res = GLO_GET(roff);
1515 if (NUM_PEEK(2))
1516 data_copy(res, PEEK(1));
1517 else
1518 data_copy(res, PEEK(0));
1519 NPOP(3); PUSH(res);
1520 break; }
1521 case IF_16_OP: {
1522 uint16_t else_off = NXT_OP16(m);
1523 NUM_VAL tst = NUM_POP();
1524 if (tst != 0)
1525 m->pc += else_off;
1526 break; }
1527 case IF_OP: {
1528 int else_off = NXT_OP(m);
1529 NUM_VAL tst = NUM_POP();
1530 if (tst != 0)
1531 m->pc += else_off;
1532 break; }
1533 case JMP_OP: {
1534 int off = NXT_OP(m);
1535 m->pc += off; break; }
1536 case JMP_16_OP: {
1537 m->pc += NXT_OP16(m);
1538 break; }
1539 case RET_OP: {
1540 POP(res);
1541 m->pc = FUN_POP();
1542 dump_stack(m);
1543 return res; }
1544 case DEF_FUN_2_OP: case DEF_FUN_3_OP: case DEF_FUN_4_OP:
1545 case DEF_FUN_5_OP: case DEF_FUN_6_OP: case DEF_FUN_7_OP:
1546 def_fun_exec(m, op - DEF_FUN_2_OP + 2); break;
1547 case DEF_FUN_OP:
1548 def_fun_exec(m, NXT_OP(m)); break;
1549 case DEF_FUN16_OP:
1550 def_fun_exec(m, NXT_OP16(m)); break;
1551 case SET_DT_OP:
1552 set_dt(NUM_PEEK(0)); break;
1553 case DT_OP:
1554 NUM_PUSH(machine->time - machine->last_time); break;
1555 case PROBE_OP: {
1556 DATA *val = PEEK(1);
1557 int k = (int)NUM_PEEK(0);
1558 set_probe(val, k);
1559 NPOP(2); PUSH(val);
1560 break; }
1561 case INFINITESIMAL_OP:
1562 NUM_PUSH(machine_area(m)); break;
1563 case NBR_RANGE_OP:
1564 NUM_PUSH(nbr_range()); break;
1565 case AREA_OP:
1566 NUM_PUSH(machine_area(m)); break;
1567 case NBR_BEARING_OP:
1568 NUM_PUSH(nbr_bearing()); break;
1569 case NBR_LAG_OP:
1570 NUM_PUSH(nbr_lag()); break;
1571 case NBR_VEC_OP: {
1572 VEC_VAL *vr = VEC_GET(GLO_GET(NXT_OP(m)));
1573 ensure_len(vr, 3);
1574 NUM_SET(vec_elt(vr, 0), m->nbr_x);
1575 NUM_SET(vec_elt(vr, 1), m->nbr_y);
1576 NUM_SET(vec_elt(vr, 2), m->nbr_z);
1577 VEC_PUSH(vr);
1578 break; }
1579 case BEARING_OP:
1580 NUM_PUSH(read_bearing()); break;
1581 case SPEED_OP:
1582 NUM_PUSH(read_speed()); break;
1583 case MOV_OP:
1584 mov(VEC_PEEK(0)); break;
1585 case RND_OP: {
1586 NUM_VAL val = num_rnd(NUM_PEEK(1), NUM_PEEK(0));
1587 NPOP(2); NUM_PUSH(val);
1588 break; }
1589 //Scalar Comparison Operations
1590 case GT_OP: {
1591 NUM_VAL val = NUM_PEEK(1) > NUM_PEEK(0); NPOP(2); NUM_PUSH(val); break; }
1592 case GTE_OP: {
1593 NUM_VAL val = NUM_PEEK(1) >= NUM_PEEK(0); NPOP(2); NUM_PUSH(val); break; }
1594 case LT_OP: {
1595 NUM_VAL val = NUM_PEEK(1) < NUM_PEEK(0); NPOP(2); NUM_PUSH(val); break; }
1596 case LTE_OP: {
1597 NUM_VAL val = NUM_PEEK(1) <= NUM_PEEK(0); NPOP(2); NUM_PUSH(val); break; }
1598 case EQ_OP: {
1599 NUM_VAL val = NUM_PEEK(1) == NUM_PEEK(0); NPOP(2); NUM_PUSH(val); break; }
1600 case MAX_OP: {
1601 NUM_VAL val = MAX(NUM_PEEK(1), NUM_PEEK(0)); NPOP(2); NUM_PUSH(val); break; }
1602 case MIN_OP: {
1603 NUM_VAL val = MIN(NUM_PEEK(1), NUM_PEEK(0)); NPOP(2); NUM_PUSH(val); break; }
1604 //Basic Mathematical Operations
1605 case ADD_OP: {
1606 NUM_VAL val = NUM_PEEK(1) + NUM_PEEK(0); NPOP(2); NUM_PUSH(val); break; }
1607 case MOD_OP: {
1608 NUM_VAL val = fmod(NUM_PEEK(1), NUM_PEEK(0)); NPOP(2); NUM_PUSH(val); break; }
1609 case DIV_OP: {
1610 NUM_VAL val = NUM_PEEK(1) / NUM_PEEK(0); NPOP(2); NUM_PUSH(val); break; }
1611 case MUL_OP: {
1612 NUM_VAL val = NUM_PEEK(1) * NUM_PEEK(0); NPOP(2); NUM_PUSH(val); break; }
1613 case SUB_OP: {
1614 NUM_VAL val = NUM_PEEK(1) - NUM_PEEK(0); NPOP(2); NUM_PUSH(val); break; }
1615 //Math Operations
1616 case ABS_OP:
1617 NUM_PUSH(fabs(NUM_POP())); break;
1618 case POW_OP: {
1619 NUM_VAL val = pow(NUM_PEEK(1), NUM_PEEK(0)); NPOP(2); NUM_PUSH(val); break; }
1620 case LOG_OP: {
1621 NUM_PUSH(log(NUM_POP())); break; }
1622 case SQRT_OP: {
1623 NUM_PUSH(sqrt(NUM_POP())); break; }
1624 case SIN_OP: {
1625 NUM_PUSH(sin(NUM_POP())); break; }
1626 case COS_OP: {
1627 NUM_PUSH(cos(NUM_POP())); break; }
1628 case TAN_OP: {
1629 NUM_PUSH(tan(NUM_POP())); break; }
1630 case SINH_OP: {
1631 NUM_PUSH(sinh(NUM_POP())); break; }
1632 case COSH_OP: {
1633 NUM_PUSH(cosh(NUM_POP())); break; }
1634 case TANH_OP: {
1635 NUM_PUSH(tanh(NUM_POP())); break; }
1636 case ASIN_OP: {
1637 NUM_PUSH(asin(NUM_POP())); break; }
1638 case ACOS_OP: {
1639 NUM_PUSH(acos(NUM_POP())); break; }
1640 case FLOOR_OP: {
1641 NUM_PUSH(floor(NUM_POP())); break; }
1642 case CEIL_OP: {
1643 NUM_PUSH(ceil(NUM_POP())); break; }
1644 case ATAN2_OP: {
1645 NUM_VAL val = atan2(NUM_PEEK(1), NUM_PEEK(0)); NPOP(2); NUM_PUSH(val); break; }
1647 //Basic Vector Operations
1648 case VADD_OP: {
1649 vadd_exec(NXT_OP(m)); break; }
1650 case VSUB_OP: {
1651 vsub_exec(NXT_OP(m)); break; }
1652 case VMUL_OP: {
1653 vmul_exec(NXT_OP(m)); break; }
1654 case VDOT_OP: {
1655 vdot_exec(); break; }
1656 case LEN_OP: {
1657 len_exec(); break; }
1658 case VSLICE_OP: {
1659 vslice_exec(NXT_OP(m)); break; }
1661 //Vector Comparison Operators
1662 case VGT_OP: {
1663 vgt_exec(); break; }
1664 case VGTE_OP: {
1665 vgte_exec(); break; }
1666 case VLT_OP: {
1667 vlt_exec(); break; }
1668 case VLTE_OP: {
1669 vlte_exec(); break; }
1670 case VEQ_OP: {
1671 veq_exec(); break; }
1672 case VMIN_OP: {
1673 vmin_exec(); break; }
1674 case VMAX_OP: {
1675 vmax_exec(); break; }
1676 //Feedback and Neighbor Operations
1677 case INIT_FEEDBACK_OP: init_feedback_exec(NXT_OP(m)); break;
1678 case FEEDBACK_OP: feedback_exec(NXT_OP(m)); break;
1679 case FOLD_HOOD_OP: {
1680 DATA reso; do_fold_hood_exec(&reso, NXT_OP(m)); break; }
1681 case VFOLD_HOOD_OP: {
1682 int roff = NXT_OP(m);
1683 int off = NXT_OP(m);
1684 do_fold_hood_exec(GLO_GET(roff), off); break; }
1685 case FOLD_HOOD_PLUS_OP: {
1686 DATA reso; do_fold_hood_plus_exec(&reso, NXT_OP(m)); break; }
1687 case VFOLD_HOOD_PLUS_OP: {
1688 int roff = NXT_OP(m);
1689 int off = NXT_OP(m);
1690 do_fold_hood_plus_exec(GLO_GET(roff), off); break; }
1691 case APPLY_OP:
1692 apply_exec(/* NXT_OP(m) */); break;
1693 case ALL_OP: {
1694 int n = NXT_OP(m); DATA val; POP(&val); NPOP(n-1); PUSH(&val); break; }
1696 case FOLD_OP:
1697 fold_exec(); break;
1698 case VFOLD_OP:
1699 vfold_exec(NXT_OP(m)); break;
1700 case MAP_OP:
1701 map_exec(NXT_OP(m)); break;
1702 case HOOD_RADIUS_OP:
1703 NUM_PUSH(read_radio_range()); break;
1704 case TUP_OP: {
1705 int off = NXT_OP(m);
1706 int n = NXT_OP(m);
1707 tup_exec(n, off); break; }
1708 case ELT_OP:
1709 elt_exec(); break;
1710 case MID_OP:
1711 NUM_PUSH(m->id); break;
1712 case FLEX_OP:
1713 flex(NUM_PEEK(0)); break;
1714 default:
1715 uerror("UNKNOWN OPCODE %d %d\n", op, MAX_CMD_OPS);
1717 } else {
1718 platform_operation(op); // call out to platform-specific code
1720 dump_stack(m);
1721 check_stack(m);
1722 check_env(m);
1726 void clear_pkt_tracker(){
1727 MACHINE *m = machine;
1728 uint8_t i;
1729 for(i = 0; i< NUM_SCRIPT_PKTS; i++){
1730 ATOMIC {
1731 m->pkt_tracker[i] = m->pkt_listner[i] = 0;
1737 //ret: 0-already have pkt, 1-added pkt
1738 uint8_t add_pkt(uint8_t pkt_num){
1739 MACHINE *m = machine;
1740 uint8_t major, minor;
1741 major = (int)floor((float)pkt_num / (float)8);
1742 minor = pkt_num % 8;
1744 if (((uint8_t)1 << minor) & m->pkt_tracker[major])
1745 return 0;
1746 m->pkt_tracker[major] = (1 << minor) | m->pkt_tracker[major];
1747 return 1;
1750 // true when the machine needs to request script or fill a neighbor's request
1751 int script_export_needed(VOID) {
1752 MACHINE *m = machine;
1753 if(!m->scripts[m->cur_script].is_complete) return 1;
1754 uint8_t i;
1755 SCRIPT *nxt_script;
1756 // code ripped from export_script
1757 if (m->scripts[(m->cur_script+1)%MAX_SCRIPTS].version > m->scripts[m->cur_script].version)
1758 nxt_script = &m->scripts[(m->cur_script+1)%MAX_SCRIPTS];
1759 else
1760 nxt_script = &m->scripts[m->cur_script];
1761 for (i = 0; i < num_pkts(nxt_script->len); i++) {
1762 uint8_t major = i / 8;
1763 uint8_t minor = i % 8;
1764 if (m->pkt_listner[major] & (1 << minor)) { return 1; }
1766 return 0;
1769 int is_script_complete(VOID) {
1770 MACHINE *m = machine;
1771 SCRIPT *script = &m->scripts[(m->cur_script+1)%MAX_SCRIPTS];
1772 uint8_t npkts = num_pkts(script->len);
1773 uint8_t i, major, minor;
1775 major = npkts / 8;
1776 minor = npkts % 8;
1777 for (i = 0; i < major; i++) {
1778 if (is_script_debugging(m))
1779 POST("MAJOR %d %x\n", i, m->pkt_tracker[i]);
1780 if (m->pkt_tracker[i] != 0xff)
1781 return 0;
1783 if (is_script_debugging(m))
1784 POST("MINOR %x\n", m->pkt_tracker[major]);
1785 if (minor > 0 && m->pkt_tracker[major] != ((1 << minor) - 1))
1786 return 0;
1787 return 1;
1790 void install_script_pkt(MACHINE *m, uint8_t pkt_num, uint8_t *script_pkt, uint16_t len) {
1791 SCRIPT *script = &m->scripts[(m->cur_script+1)%MAX_SCRIPTS];
1792 uint16_t pkt_len = MIN(len - pkt_num * MAX_SCRIPT_PKT, MAX_SCRIPT_PKT);
1794 // dump_code(len, script_pkt);
1795 memcpy(&script->bytes[pkt_num * MAX_SCRIPT_PKT], script_pkt, pkt_len);
1796 script->len = len;
1797 add_pkt(pkt_num);
1800 void link_script (MACHINE *m) {
1801 DATA res;
1802 SCRIPT *script = &m->scripts[m->cur_script];
1804 if (is_script_debugging(m))
1805 POST("M%d LINKING SCRIPT\n", m->id);
1806 m->script = script->bytes;
1807 m->n_state = 0;
1808 m->n_globals = 0;
1809 m->max_globals = 0;
1810 m->n_hood_vals = 0;
1811 m->sp = m->stack = NULL;
1812 m->ep = m->env = NULL;
1813 reinit_machine(m);
1814 // dump_code(script->len, script->bytes);
1815 eval(&res, 0);
1816 if (is_tracing(m))
1817 POST("M%d DONE LINKING\n", m->id);
1818 NUM_POP();
1819 m->exec = FUN_GET(GLO_GET(m->n_globals-1));
1822 void install_script(MACHINE *m, uint8_t *script, uint8_t slot, uint16_t len, uint8_t version) {
1823 SCRIPT *s = &m->scripts[slot];
1824 int i;
1825 if (len > MAX_SCRIPT_LEN)
1826 uerror("SCRIPT TOO BIG %d > %d -- INCREASE MAX_SCRIPT_LEN\n",
1827 len, MAX_SCRIPT_LEN);
1828 // post("SIZEOF DATA %d\n", sizeof(DATA));
1829 memcpy(s->bytes, script, len);
1830 s->is_complete = TRUE;
1831 s->len = len;
1832 s->version = version;
1833 clear_pkt_tracker();
1834 for(i = 0; i < num_pkts(len); i++)
1835 add_pkt(i);
1836 link_script(m);