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. */
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
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));
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);
37 uint8_t* PMALLOC(uint16_t sz
) {
41 if ((machine_mem_size(m
)+sz
) > m
->memlen
)
43 // post("M%d MALLOCING %d\n", m->id, sz);
44 m
->memptr
= word_align(m
->memptr
);
45 ptr
= &m
->membuf
[m
->memptr
];
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
);
93 for (i
= 0; i
< n
; i
++)
94 DATA_SET(&dat
->elts
[i
], f
);
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
);
107 } else if (n
< v
->n
) {
111 DATA val
; init_num(&val
, 0);
112 init_vec(dat
, n
, n
, &val
);
119 DATA
*data_copy (DATA
*dst
, DATA
*src
) {
120 dst
->is_dead
= src
->is_dead
;
123 DATA_SET(dst
, src
++);
126 VEC_VAL
*vs
= VEC_GET(src
);
128 VEC_VAL
*vd
= ensure_vec(dst
, n
);
130 for (i
= 0; i
< n
; i
++)
131 data_copy(&vd
->elts
[i
], &vs
->elts
[i
]);
134 uerror("M%d UNKNOWN TAG %d\n", machine
->id
, src
->tag
);
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
);
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
);
151 MAYBE_INLINE
void ensure_len(VEC_VAL
*v
, int n
) {
154 uerror("TOO FEW ELEMENTS %d > %d\n", n
, v
->cap
);
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
) {
171 INLINE
void vec_zap (VEC_VAL
*vec
) {
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
);
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
;
198 INLINE
void nbr_invalid_set (NBR
*nbr
) {
199 nbr
->stamp
= NBR_NULL
;
202 INLINE
void nbr_valid_set (NBR
*nbr
) {
206 INLINE BOOL
is_nbr_valid (NBR
*nbr
) {
207 return nbr
->stamp
!= NBR_NULL
;
210 void del_nbr (int k
) {
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];
219 void ins_nbr (NBR
*nbr
, int k
) {
220 MACHINE
*m
= machine
;
222 for (i
= m
->n_hood
; i
> k
; i
--)
223 m
->hood
[i
] = m
->hood
[i
-1];
228 void post_nbrs (MACHINE
*m
) {
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
) {
236 MACHINE
*m
= machine
;
238 for (i
= 0; i
< MAX_HOOD
; i
++) {
239 nbr
= &m
->hood_data
[i
];
240 if (!is_nbr_valid(nbr
)) {
242 nbr
->stamp
= m
->ticks
;
244 for (j
= 0; j
< m
->n_hood
; j
++)
245 if (src_id
< m
->hood
[j
]->id
) {
249 // POST("M%d ADDING NBR %d: ", m->id, src_id); post_nbrs(m); POST("\n");
256 MAYBE_INLINE NBR
*find_nbr (uint16_t src_id
) {
257 MACHINE
*m
= machine
;
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);
269 } else if (src_id
< nbr
->id
)
274 // POST("M%d LOST NBR %d\n", m->id, src_id);
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
) {
293 for (i
= 0; i
< N_SENSORS
; i
++)
295 for (i
= 0; i
< MAX_HOOD
; i
++)
296 nbr_invalid_set(&m
->hood_data
[i
]);
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
) {
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);
313 m
->radio_range
= read_radio_range();
314 m
->radio_range_sqr
= m
->radio_range
* m
->radio_range
;
323 m
->period
= m
->desired_period
= desired_period
;
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));
336 init_vec(&nul_tup_dat
, 0, 0, NULL
);
337 m
= init_machine(m
, id
, x
, y
, z
, desired_period
, script
, script_len
);
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
);
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
;
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
) {
378 FUN_PUSH(machine
->pc
);
383 MAYBE_INLINE DATA
funcall1 (FUN_VAL fun
, DATA
*arg
) {
385 FUN_PUSH(machine
->pc
);
392 MAYBE_INLINE DATA
funcall2 (FUN_VAL fun
, DATA
*a1
, DATA
*a2
) {
394 FUN_PUSH(machine
->pc
);
395 ENV_PUSH(a1
); ENV_PUSH(a2
);
401 void clear_actuators (VOID
) {
402 MACHINE
*m
= machine
;
404 for (i
= 0; i
< N_ACTUATORS
; i
++)
408 void clear_exports (VOID
) {
409 MACHINE
*m
= machine
;
411 for (i
= 0; i
< m
->n_hood_vals
; i
++)
412 m
->hood_exports
[i
].is_dead
= TRUE
;
415 void maybe_hibernate_machine (VOID
) {
417 for (i
= 0; i
< machine
->n_state
; i
++) {
424 void clear_is_exec (VOID
) {
426 for (i
= 0; i
< machine
->n_state
; i
++) {
431 void clear_is_open (VOID
) {
433 for (i
= 0; i
< machine
->n_state
; i
++) {
438 void open_machine (VOID
) {
439 //MACHINE *m = machine;
442 // for (i = 0; i < N_SENSORS; i++)
443 // m->sensors[i] = 0;
447 // POST("M%d HOOD VALUES %d\n", m->id, m->n_hood_vals);
450 void close_machine (VOID
) {
451 MACHINE
*m
= machine
;
460 #if IS_COMPRESSED_COM_DATA
461 INLINE NUM_VAL
NUM_DECODE_VAL (COM_DATA
*src
) {
463 fi
.i
= ((uint32_t)(ntohs(src
->val
.n
))) << 16;
466 INLINE
uint16_t NUM_ENCODE_VAL (DATA
*src
) {
469 return htons(fi
.i
>> 16);
472 INLINE NUM_VAL
NUM_DECODE_VAL (COM_DATA
*src
) {
475 INLINE NUM_VAL
NUM_ENCODE_VAL (DATA
*src
) {
480 INLINE
void NUM_DECODE (DATA
*dst
, COM_DATA
*src
) {
481 dst
->is_dead
= src
->is_dead
;
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
;
490 dst
->val
.n
= NUM_ENCODE_VAL(src
);
493 COM_DATA
*data_decode (DATA
*dst
, COM_DATA
*src
) {
496 NUM_DECODE(dst
, src
++);
499 int is_dead
= src
->is_dead
;
500 int n
= (int)NUM_DECODE_VAL(src
++);
501 VEC_VAL
*v
= ensure_vec(dst
, n
);
503 for (i
= 0; i
< n
; i
++)
504 src
= data_decode(&v
->elts
[i
], src
++);
505 dst
->is_dead
= is_dead
;
509 NUM_DECODE(dst
, src
++);
511 uerror("M%d UNKNOWN TAG %d\n", machine
->id
, src
->tag
);
516 COM_DATA
*data_encode (COM_DATA
*dst
, DATA
*src
, int *len
) {
520 NUM_ENCODE(dst
++, src
);
523 VEC_VAL
*v
= src
->val
.v
;
527 dat
.is_dead
= src
->is_dead
;
530 NUM_ENCODE(dst
, &dat
);
532 for (i
= 0; i
< n
; i
++)
533 dst
= data_encode(dst
, &v
->elts
[i
], len
);
537 NUM_ENCODE(dst
++, src
);
539 uerror("M%d UNKNOWN TAG %d\n", machine
->id
, src
->tag
);
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
) {
552 // for (i = 0; i < dst->n_hood; i++)
553 // newest = MAX(newest, dst->hood[i]->stamp);
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;
563 for(x
=1;x
<=NBR_TIMEOUT
;x
++)
564 nbr_timeout
+= timeout_of(MIN(nbr
->timeout
+x
,MAX_NBR_TIMEOUT
));
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");
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
) {
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
);
585 if (is_debug
) POST("M%d ADDING NBR %d\n", dst
->id
, src_id
);
586 nbr
= add_nbr(src_id
);
590 if (is_debug
) POST("M%d ADDED %d V%d\n", dst
->id
, src_id
, version
);
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
;
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]);
609 nbr
->imports
= (DATA
*)buf
;
610 if (is_debug
) POST("\n");
611 // if (n > 1) POST("\n");
613 // POST("ERROR %d<-%d DIFF NUMBER HOOD VALS %d VS %d\n",
614 // dst->id, src_id, n, dst->n_hood_vals+1);
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
) {
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
)
630 m
->timeout
= MIN(m
->timeout
+ 1, MAX_NBR_TIMEOUT
);
631 m
->send_ticks
= m
->ticks
;
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
;
642 int n
, len
, is_debug
;
643 if (are_exports_serialized
) {
646 is_debug
= is_debugging(m
);
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]);
658 // post_data(&buf[k-1]);
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
));
669 bp
= buf
= (COM_DATA
*)m
->hood_exports
;
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
) {
681 for (j
= 0; j
< n_bits
; j
++)
682 POST("%d", (byte
>>j
)&1);
685 void dump_digest (uint8_t *digest
, uint16_t len
) {
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
) {
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
);
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
);
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();
772 void export_script (VOID
) {
773 MACHINE
*m
= machine
;
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)); */
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
];
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
]);
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
];
822 m
->last_time
= m
->time
;
826 if (s
->is_complete
) {
828 m
->last_time
= m
->time
;
832 if (is_debugging(m
) || is_tracing(m
)) {
834 POST("M%d EXEC %f V%d\n", m
->id
, m
->ticks
, s
->version
);
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
); }
856 INLINE
void tup_exec (int n
, int offset
) {
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));
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();
878 //Vector addition: the shorter vector has elements padded with 0 to match len
879 void vadd_exec (int off
) {
881 VEC_VAL
*vr
= VEC_GET(GLO_GET(off
));
882 VEC_VAL
*v0
= VEC_PEEK(1);
883 VEC_VAL
*v1
= VEC_PEEK(0);
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
) {
904 VEC_VAL
*vr
= VEC_GET(GLO_GET(off
));
905 VEC_VAL
*v0
= VEC_PEEK(1);
906 VEC_VAL
*v1
= VEC_PEEK(0);
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);
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
) {
945 VEC_VAL
*v0
= VEC_PEEK(1);
946 VEC_VAL
*v1
= VEC_PEEK(0);
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
);
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
) {
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;
996 } else if (x0
> x1
) {
1003 int vgt_op(VEC_VAL
*v0
, VEC_VAL
*v1
) {
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;
1015 } else if (x0
< x1
) {
1022 int veq_op(VEC_VAL
*v0
, VEC_VAL
*v1
) {
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;
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
) {
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
) {
1103 // POST("M%d EXECING FEEDBACK %d %d\n", machine->id, machine->pc, state_off);
1104 IS_EXEC_SET(state_off
, 1);
1106 STATE_SET(state_off
, 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
;
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
) {
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++) {
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)
1147 radii[off] += range;
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
);
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
) {
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"); }
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);
1215 int is_debug
= is_debugging(m
);
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
) {
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"); }
1242 void apply_exec (VOID
) {
1243 FUN_VAL fun
= FUN_PEEK(1);
1244 VEC_VAL
*args
= VEC_PEEK(0);
1246 int n
= vec_len(args
);
1249 FUN_PUSH(machine
->pc
);
1250 for (i
= 0; i
< n
; i
++)
1251 ENV_PUSH(vec_elt(args
, i
));
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
);
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
);
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
);
1286 void fold_exec (VOID
) {
1287 DATA res
; do_fold_exec(&res
);
1290 void vfold_exec (int roff
) {
1291 DATA
*res
= GLO_GET(roff
);
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
);
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
);
1314 uerror("ENV UNDERFLOW\n");
1317 INLINE
void dump_stack (MACHINE
*m
) {
1318 if (is_tracing(m
)) {
1320 int max_dump
= 6; // 99
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");
1338 MAYBE_INLINE
void def_fun_exec (MACHINE
*m
, uint16_t skip
) {
1340 FUN_SET(&res
, m
->pc
);
1342 GLO_SET(m
->n_globals
++, &res
);
1347 DATA
*eval(DATA
*res
, FUN_VAL fun
) {
1348 MACHINE
*m
= machine
;
1349 SCRIPT
*script
= &m
->scripts
[m
->cur_script
];
1351 int is_trace
= is_tracing(m
);
1355 if (fun
> script
->len
)
1356 uerror("BOGUS FUNCTION %d\n", fun
);
1358 POST("M%d EVAL AT %d\n", m
->id
, fun
);
1361 // putstring(" PC:"); putnum_ud(m->pc);
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
) {
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
);
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
));
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
));
1408 // m->n_env = n_env;
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
;
1421 NUM_VAL val
= NXT_OP16(m
);
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.
1435 GLO_SET(m
->n_globals
++, POP(&data
));
1437 case DEF_TUP_OP
: case FAB_TUP_OP
: {
1441 init_vec(&data
, n
, n
, init_num(&num
, 0.0));
1443 for (i
= 0; i
< n
; i
++)
1444 DATA_SET(&v
->elts
[i
], PEEK(n
-i
-1));
1446 if (op
== DEF_TUP_OP
)
1447 GLO_SET(m
->n_globals
++, &data
);
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
: {
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
);
1464 case DEF_VEC_OP
: case FAB_VEC_OP
: {
1466 DATA data
, arg
, num
;
1468 init_vec(&data
, n
, n
, init_num(&num
, 0.0));
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
);
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)); }
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)); }
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
;
1493 case GLO_REF16_OP
: {
1494 uint16_t off
= NXT_OP16(m
);
1495 PUSH(&m
->globals
[off
]);
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
]);
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
;
1510 DATA
*reso
= NUM_PEEK(2) ? PEEK(1) : PEEK(0); NPOP(3); PUSH(reso
);
1513 int roff
= NXT_OP(m
);
1514 DATA
*res
= GLO_GET(roff
);
1516 data_copy(res
, PEEK(1));
1518 data_copy(res
, PEEK(0));
1522 uint16_t else_off
= NXT_OP16(m
);
1523 NUM_VAL tst
= NUM_POP();
1528 int else_off
= NXT_OP(m
);
1529 NUM_VAL tst
= NUM_POP();
1534 int off
= NXT_OP(m
);
1535 m
->pc
+= off
; break; }
1537 m
->pc
+= NXT_OP16(m
);
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;
1548 def_fun_exec(m
, NXT_OP(m
)); break;
1550 def_fun_exec(m
, NXT_OP16(m
)); break;
1552 set_dt(NUM_PEEK(0)); break;
1554 NUM_PUSH(machine
->time
- machine
->last_time
); break;
1556 DATA
*val
= PEEK(1);
1557 int k
= (int)NUM_PEEK(0);
1561 case INFINITESIMAL_OP
:
1562 NUM_PUSH(machine_area(m
)); break;
1564 NUM_PUSH(nbr_range()); break;
1566 NUM_PUSH(machine_area(m
)); break;
1567 case NBR_BEARING_OP
:
1568 NUM_PUSH(nbr_bearing()); break;
1570 NUM_PUSH(nbr_lag()); break;
1572 VEC_VAL
*vr
= VEC_GET(GLO_GET(NXT_OP(m
)));
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
);
1580 NUM_PUSH(read_bearing()); break;
1582 NUM_PUSH(read_speed()); break;
1584 mov(VEC_PEEK(0)); break;
1586 NUM_VAL val
= num_rnd(NUM_PEEK(1), NUM_PEEK(0));
1587 NPOP(2); NUM_PUSH(val
);
1589 //Scalar Comparison Operations
1591 NUM_VAL val
= NUM_PEEK(1) > NUM_PEEK(0); NPOP(2); NUM_PUSH(val
); break; }
1593 NUM_VAL val
= NUM_PEEK(1) >= NUM_PEEK(0); NPOP(2); NUM_PUSH(val
); break; }
1595 NUM_VAL val
= NUM_PEEK(1) < NUM_PEEK(0); NPOP(2); NUM_PUSH(val
); break; }
1597 NUM_VAL val
= NUM_PEEK(1) <= NUM_PEEK(0); NPOP(2); NUM_PUSH(val
); break; }
1599 NUM_VAL val
= NUM_PEEK(1) == NUM_PEEK(0); NPOP(2); NUM_PUSH(val
); break; }
1601 NUM_VAL val
= MAX(NUM_PEEK(1), NUM_PEEK(0)); NPOP(2); NUM_PUSH(val
); break; }
1603 NUM_VAL val
= MIN(NUM_PEEK(1), NUM_PEEK(0)); NPOP(2); NUM_PUSH(val
); break; }
1604 //Basic Mathematical Operations
1606 NUM_VAL val
= NUM_PEEK(1) + NUM_PEEK(0); NPOP(2); NUM_PUSH(val
); break; }
1608 NUM_VAL val
= fmod(NUM_PEEK(1), NUM_PEEK(0)); NPOP(2); NUM_PUSH(val
); break; }
1610 NUM_VAL val
= NUM_PEEK(1) / NUM_PEEK(0); NPOP(2); NUM_PUSH(val
); break; }
1612 NUM_VAL val
= NUM_PEEK(1) * NUM_PEEK(0); NPOP(2); NUM_PUSH(val
); break; }
1614 NUM_VAL val
= NUM_PEEK(1) - NUM_PEEK(0); NPOP(2); NUM_PUSH(val
); break; }
1617 NUM_PUSH(fabs(NUM_POP())); break;
1619 NUM_VAL val
= pow(NUM_PEEK(1), NUM_PEEK(0)); NPOP(2); NUM_PUSH(val
); break; }
1621 NUM_PUSH(log(NUM_POP())); break; }
1623 NUM_PUSH(sqrt(NUM_POP())); break; }
1625 NUM_PUSH(sin(NUM_POP())); break; }
1627 NUM_PUSH(cos(NUM_POP())); break; }
1629 NUM_PUSH(tan(NUM_POP())); break; }
1631 NUM_PUSH(sinh(NUM_POP())); break; }
1633 NUM_PUSH(cosh(NUM_POP())); break; }
1635 NUM_PUSH(tanh(NUM_POP())); break; }
1637 NUM_PUSH(asin(NUM_POP())); break; }
1639 NUM_PUSH(acos(NUM_POP())); break; }
1641 NUM_PUSH(floor(NUM_POP())); break; }
1643 NUM_PUSH(ceil(NUM_POP())); break; }
1645 NUM_VAL val
= atan2(NUM_PEEK(1), NUM_PEEK(0)); NPOP(2); NUM_PUSH(val
); break; }
1647 //Basic Vector Operations
1649 vadd_exec(NXT_OP(m
)); break; }
1651 vsub_exec(NXT_OP(m
)); break; }
1653 vmul_exec(NXT_OP(m
)); break; }
1655 vdot_exec(); break; }
1657 len_exec(); break; }
1659 vslice_exec(NXT_OP(m
)); break; }
1661 //Vector Comparison Operators
1663 vgt_exec(); break; }
1665 vgte_exec(); break; }
1667 vlt_exec(); break; }
1669 vlte_exec(); break; }
1671 veq_exec(); break; }
1673 vmin_exec(); break; }
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; }
1692 apply_exec(/* NXT_OP(m) */); break;
1694 int n
= NXT_OP(m
); DATA val
; POP(&val
); NPOP(n
-1); PUSH(&val
); break; }
1699 vfold_exec(NXT_OP(m
)); break;
1701 map_exec(NXT_OP(m
)); break;
1702 case HOOD_RADIUS_OP
:
1703 NUM_PUSH(read_radio_range()); break;
1705 int off
= NXT_OP(m
);
1707 tup_exec(n
, off
); break; }
1711 NUM_PUSH(m
->id
); break;
1713 flex(NUM_PEEK(0)); break;
1715 uerror("UNKNOWN OPCODE %d %d\n", op
, MAX_CMD_OPS
);
1718 platform_operation(op
); // call out to platform-specific code
1726 void clear_pkt_tracker(){
1727 MACHINE
*m
= machine
;
1729 for(i
= 0; i
< NUM_SCRIPT_PKTS
; i
++){
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
])
1746 m
->pkt_tracker
[major
] = (1 << minor
) | m
->pkt_tracker
[major
];
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;
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
];
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; }
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
;
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)
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))
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
);
1800 void link_script (MACHINE
*m
) {
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
;
1811 m
->sp
= m
->stack
= NULL
;
1812 m
->ep
= m
->env
= NULL
;
1814 // dump_code(script->len, script->bytes);
1817 POST("M%d DONE LINKING\n", m
->id
);
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
];
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
;
1832 s
->version
= version
;
1833 clear_pkt_tracker();
1834 for(i
= 0; i
< num_pkts(len
); i
++)