1 /* file: "primitives.c" */
4 * Copyright 2004-2009 by Marc Feeley and Vincent St-Amour, All Rights Reserved.
7 #include "picobit-vm.h"
9 /*---------------------------------------------------------------------------*/
37 "prim #%graft-to-cont",
38 "prim #%return-to-cont",
42 "prim #%string->list",
43 "prim #%list->string",
44 "prim #%make-u8vector",
45 "prim #%u8vector-ref",
46 "prim #%u8vector-set!",
52 "prim #%getchar-wait",
58 "prim #%u8vector-length",
59 "prim #%u8vector-copy!",
64 "prim #%network-init",
65 "prim #%network-cleanup",
66 "prim #%receive-packet-to-u8vector",
67 "prim #%send-packet-from-u8vector",
83 /*---------------------------------------------------------------------------*/
85 // numerical primitives
87 void prim_numberp (void) {
88 if (arg1
>= MIN_FIXNUM_ENCODING
89 && arg1
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
93 arg1
= encode_bool (RAM_BIGNUM(arg1
));
94 else if (IN_ROM(arg1
))
95 arg1
= encode_bool (ROM_BIGNUM(arg1
));
101 void prim_add (void) {
102 #ifdef INFINITE_PRECISION_BIGNUMS
103 arg1
= add (arg1
, arg2
);
105 decode_2_int_args ();
106 arg1
= encode_int (a1
+ a2
);
111 void prim_sub (void) {
112 #ifdef INFINITE_PRECISION_BIGNUMS
113 arg1
= sub (arg1
, arg2
);
115 decode_2_int_args ();
116 arg1
= encode_int (a1
- a2
);
121 void prim_mul (void) {
122 #ifdef INFINITE_PRECISION_BIGNUMS
124 a2
= negp (arg2
); // -1 if negative
125 arg1
= mulnonneg (a1
? neg(arg1
) : arg1
,
126 a2
? neg(arg2
) : arg2
);
127 if (a1
+ a2
== 1) // only one of the 2 was negative
130 decode_2_int_args ();
131 arg1
= encode_int (a1
* a2
);
136 void prim_div (void) {
137 #ifdef INFINITE_PRECISION_BIGNUMS
138 if (obj_eq(arg2
, ZERO
))
139 ERROR("quotient", "divide by 0");
141 a2
= negp (arg2
); // -1 if negative
142 arg1
= divnonneg (a1
? neg(arg1
) : arg1
,
143 a2
? neg(arg2
) : arg2
);
144 if (a1
+ a2
== 1) // only one of the 2 was negative
147 decode_2_int_args ();
149 ERROR("quotient", "divide by 0");
150 arg1
= encode_int (a1
/ a2
);
155 void prim_rem (void) {
156 #ifdef INFINITE_PRECISION_BIGNUMS
157 if (obj_eq(arg2
, ZERO
))
158 ERROR("remainder", "divide by 0");
159 if (negp(arg1
) || negp(arg2
))
160 ERROR("remainder", "only positive numbers are supported");
161 // TODO fix this to handle negatives
162 // TODO logic quite similar to mul and div (likely, once we fix), abstract ?
163 arg3
= divnonneg (arg1
, arg2
);
164 arg4
= mulnonneg (arg2
, arg3
);
165 arg1
= sub(arg1
, arg4
);
169 decode_2_int_args ();
171 ERROR("remainder", "divide by 0");
172 arg1
= encode_int (a1
% a2
);
177 void prim_neg (void) {
178 #ifdef INFINITE_PRECISION_BIGNUMS
181 a1
= decode_int (arg1
);
182 arg1
= encode_int (- a1
);
186 void prim_eq (void) {
187 #ifdef INFINITE_PRECISION_BIGNUMS
188 arg1
= encode_bool(cmp (arg1
, arg2
) == 0);
190 decode_2_int_args ();
191 arg1
= encode_bool(a1
== a2
);
196 void prim_lt (void) {
197 #ifdef INFINITE_PRECISION_BIGNUMS
198 arg1
= encode_bool(cmp (arg1
, arg2
) < 0);
200 decode_2_int_args ();
201 arg1
= encode_bool(a1
< a2
);
206 void prim_gt (void) {
207 #ifdef INFINITE_PRECISION_BIGNUMS
208 arg1
= encode_bool(cmp (arg1
, arg2
) > 0);
210 decode_2_int_args ();
211 arg1
= encode_bool(a1
> a2
);
216 void prim_leq (void) { // TODO these 2 are useful, but they add to the code size, is it worth it ?
217 #ifdef INFINITE_PRECISION_BIGNUMS
218 arg1
= encode_bool(cmp (arg1
, arg2
) <= 0);
220 decode_2_int_args ();
221 arg1
= encode_bool(a1
<= a2
);
227 void prim_geq (void) {
228 #ifdef INFINITE_PRECISION_BIGNUMS
229 arg1
= encode_bool(cmp (arg1
, arg2
) >= 0);
231 decode_2_int_args ();
232 arg1
= encode_bool(a1
>= a2
);
237 void prim_ior (void) {
238 #ifdef INFINITE_PRECISION_BIGNUMS
239 arg1
= bitwise_ior(arg1
, arg2
);
241 decode_2_int_args (); // TODO is the function call overhead worth it ?
242 arg1
= encode_int (a1
| a2
);
247 void prim_xor (void) {
248 #ifdef INFINITE_PRECISION_BIGNUMS
249 arg1
= bitwise_xor(arg1
, arg2
);
251 decode_2_int_args (); // TODO is the function call overhead worth it ?
252 arg1
= encode_int (a1
^ a2
);
257 // TODO primitives de shift ?
259 /*---------------------------------------------------------------------------*/
263 void prim_pairp (void) {
265 arg1
= encode_bool (RAM_PAIR(arg1
));
266 else if (IN_ROM(arg1
))
267 arg1
= encode_bool (ROM_PAIR(arg1
));
272 obj
cons (obj car
, obj cdr
) {
273 return alloc_ram_cell_init (COMPOSITE_FIELD0
| (car
>> 8),
275 PAIR_FIELD2
| (cdr
>> 8),
279 void prim_cons (void) {
280 arg1
= cons (arg1
, arg2
);
284 void prim_car (void) {
287 TYPE_ERROR("car.0", "pair");
288 arg1
= ram_get_car (arg1
);
290 else if (IN_ROM(arg1
)) {
292 TYPE_ERROR("car.1", "pair");
293 arg1
= rom_get_car (arg1
);
296 TYPE_ERROR("car.2", "pair");
299 void prim_cdr (void) {
302 TYPE_ERROR("cdr.0", "pair");
303 arg1
= ram_get_cdr (arg1
);
305 else if (IN_ROM(arg1
)) {
307 TYPE_ERROR("cdr.1", "pair");
308 arg1
= rom_get_cdr (arg1
);
311 TYPE_ERROR("cdr.2", "pair");
314 void prim_set_car (void) {
317 TYPE_ERROR("set-car!.0", "pair");
319 ram_set_car (arg1
, arg2
);
324 TYPE_ERROR("set-car!.1", "pair");
327 void prim_set_cdr (void) {
330 TYPE_ERROR("set-cdr!.0", "pair");
332 ram_set_cdr (arg1
, arg2
);
337 TYPE_ERROR("set-cdr!.1", "pair");
340 void prim_nullp (void) {
341 arg1
= encode_bool (arg1
== OBJ_NULL
);
344 /*---------------------------------------------------------------------------*/
348 void prim_u8vectorp (void) {
350 arg1
= encode_bool (RAM_VECTOR(arg1
));
351 else if (IN_ROM(arg1
))
352 arg1
= encode_bool (ROM_VECTOR(arg1
));
357 void prim_make_u8vector (void) {
358 decode_2_int_args (); // arg1 is length, arg2 is contents
359 // TODO adapt for the new bignums
361 ERROR("make-u8vector", "byte vectors can only contain bytes");
363 arg3
= alloc_vec_cell (a1
);
364 arg1
= alloc_ram_cell_init (COMPOSITE_FIELD0
| (a1
>> 8),
366 VECTOR_FIELD2
| (arg3
>> 8),
369 a1
= (a1
+ 3) / 4; // actual length, in words
371 ram_set_field0 (arg3
, a2
);
372 ram_set_field1 (arg3
, a2
);
373 ram_set_field2 (arg3
, a2
);
374 ram_set_field3 (arg3
, a2
);
379 void prim_u8vector_ref (void) {
380 a2
= decode_int (arg2
);
381 // TODO adapt for the new bignums
383 if (!RAM_VECTOR(arg1
))
384 TYPE_ERROR("u8vector-ref.0", "vector");
385 if ((ram_get_car (arg1
) <= a2
) || (a2
< 0))
386 ERROR("u8vector-ref.0", "vector index invalid");
387 arg1
= ram_get_cdr (arg1
);
389 else if (IN_ROM(arg1
)) {
390 if (!ROM_VECTOR(arg1
))
391 TYPE_ERROR("u8vector-ref.1", "vector");
392 if ((rom_get_car (arg1
) <= a2
) || (a2
< 0))
393 ERROR("u8vector-ref.1", "vector index invalid");
394 arg1
= rom_get_cdr (arg1
);
397 TYPE_ERROR("u8vector-ref.2", "vector");
403 arg1
= encode_int (ram_get_fieldn (arg1
, a2
));
405 else { // rom vector, stored as a list
407 arg1
= rom_get_cdr (arg1
);
409 // the contents are already encoded as fixnums
410 arg1
= rom_get_car (arg1
);
418 void prim_u8vector_set (void) { // TODO a lot in common with ref, abstract that
419 a2
= decode_int (arg2
); // TODO adapt for bignums
420 a3
= decode_int (arg3
);
423 ERROR("u8vector-set!", "byte vectors can only contain bytes");
426 if (!RAM_VECTOR(arg1
))
427 TYPE_ERROR("u8vector-set!.0", "vector");
428 if ((ram_get_car (arg1
) <= a2
) || (a2
< 0))
429 ERROR("u8vector-set!", "vector index invalid");
430 arg1
= ram_get_cdr (arg1
);
433 TYPE_ERROR("u8vector-set!.1", "vector");
438 ram_set_fieldn (arg1
, a2
, a3
);
445 void prim_u8vector_length (void) {
447 if (!RAM_VECTOR(arg1
))
448 TYPE_ERROR("u8vector-length.0", "vector");
449 arg1
= encode_int (ram_get_car (arg1
));
451 else if (IN_ROM(arg1
)) {
452 if (!ROM_VECTOR(arg1
))
453 TYPE_ERROR("u8vector-length.1", "vector");
454 arg1
= encode_int (rom_get_car (arg1
));
457 TYPE_ERROR("u8vector-length.2", "vector");
460 void prim_u8vector_copy (void) {
461 // arg1 is source, arg2 is source-start, arg3 is target, arg4 is target-start
462 // arg5 is number of bytes to copy
464 a1
= decode_int (arg2
);
465 a2
= decode_int (arg4
);
466 a3
= decode_int (arg5
);
468 // case 1 : ram to ram
469 if (IN_RAM(arg1
) && IN_RAM(arg3
)) {
470 if (!RAM_VECTOR(arg1
) || !RAM_VECTOR(arg3
))
471 TYPE_ERROR("u8vector-copy!.0", "vector");
472 if ((ram_get_car (arg1
) < (a1
+ a3
)) || (a1
< 0) ||
473 (ram_get_car (arg3
) < (a2
+ a3
)) || (a2
< 0))
474 ERROR("u8vector-copy!.0", "vector index invalid");
476 // position to the start
477 arg1
= ram_get_cdr (arg1
);
480 arg3
= ram_get_cdr (arg3
);
486 ram_set_fieldn (arg3
, a2
, ram_get_fieldn (arg1
, a1
));
490 a1
%= 4; // TODO merge with the previous similar block ?
496 // case 2 : rom to ram
497 else if (IN_ROM(arg1
) && IN_RAM(arg3
)) {
498 if (!ROM_VECTOR(arg1
) || !RAM_VECTOR(arg3
))
499 TYPE_ERROR("u8vector-copy!.1", "vector");
500 if ((rom_get_car (arg1
) < (a1
+ a3
)) || (a1
< 0) ||
501 (ram_get_car (arg3
) < (a2
+ a3
)) || (a2
< 0))
502 ERROR("u8vector-copy!.1", "vector index invalid");
504 arg1
= rom_get_cdr (arg1
);
506 arg1
= rom_get_cdr (arg1
);
508 arg3
= ram_get_cdr (arg3
);
513 ram_set_fieldn (arg3
, a2
, decode_int (rom_get_car (arg1
)));
515 arg1
= rom_get_cdr (arg1
);
518 a2
%= 4; // TODO very similar to the other case
522 TYPE_ERROR("u8vector-copy!.2", "vector");
531 /*---------------------------------------------------------------------------*/
533 // miscellaneous primitives
535 void prim_eqp (void) {
536 arg1
= encode_bool (arg1
== arg2
);
540 void prim_not (void) {
541 arg1
= encode_bool (arg1
== OBJ_FALSE
);
544 void prim_symbolp (void) {
546 arg1
= encode_bool (RAM_SYMBOL(arg1
));
547 else if (IN_ROM(arg1
))
548 arg1
= encode_bool (ROM_SYMBOL(arg1
));
553 void prim_stringp (void) {
555 arg1
= encode_bool (RAM_STRING(arg1
));
556 else if (IN_ROM(arg1
))
557 arg1
= encode_bool (ROM_STRING(arg1
));
562 void prim_string2list (void) {
564 if (!RAM_STRING(arg1
))
565 TYPE_ERROR("string->list.0", "string");
567 arg1
= ram_get_car (arg1
);
569 else if (IN_ROM(arg1
)) {
570 if (!ROM_STRING(arg1
))
571 TYPE_ERROR("string->list.1", "string");
573 arg1
= rom_get_car (arg1
);
576 TYPE_ERROR("string->list.2", "string");
579 void prim_list2string (void) {
580 arg1
= alloc_ram_cell_init (COMPOSITE_FIELD0
| ((arg1
& 0x1f00) >> 8),
586 void prim_booleanp (void) {
587 arg1
= encode_bool (arg1
< 2);
590 /*---------------------------------------------------------------------------*/
592 // robot-specific primitives
603 else if (o
== OBJ_TRUE
)
605 else if (o
== OBJ_NULL
)
607 else if (o
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
608 printf ("%d", DECODE_FIXNUM(o
));
617 if ((in_ram
&& RAM_BIGNUM(o
)) || (!in_ram
&& ROM_BIGNUM(o
))) // TODO fix for new bignums
618 printf ("%d", decode_int (o
));
619 else if ((in_ram
&& RAM_COMPOSITE(o
)) || (!in_ram
&& ROM_COMPOSITE(o
))) {
623 if ((in_ram
&& RAM_PAIR(o
)) || (!in_ram
&& ROM_PAIR(o
))) {
625 car
= ram_get_car (o
);
626 cdr
= ram_get_cdr (o
);
629 car
= rom_get_car (o
);
630 cdr
= rom_get_cdr (o
);
641 else if ((IN_RAM(cdr
) && RAM_PAIR(cdr
))
642 || (IN_ROM(cdr
) && ROM_PAIR(cdr
))) {
644 car
= ram_get_car (cdr
);
645 cdr
= ram_get_cdr (cdr
);
648 car
= rom_get_car (cdr
);
649 cdr
= rom_get_cdr (cdr
);
661 else if ((in_ram
&& RAM_SYMBOL(o
)) || (!in_ram
&& ROM_SYMBOL(o
)))
662 printf ("#<symbol>");
663 else if ((in_ram
&& RAM_STRING(o
)) || (!in_ram
&& ROM_STRING(o
)))
664 printf ("#<string>");
665 else if ((in_ram
&& RAM_VECTOR(o
)) || (!in_ram
&& ROM_VECTOR(o
)))
666 printf ("#<vector %d>", o
);
669 car
= ram_get_car (o
);
670 cdr
= ram_get_cdr (o
);
671 // ugly hack, takes advantage of the fact that pairs and
672 // continuations have the same layout
681 env
= ram_get_cdr (o
);
683 env
= rom_get_cdr (o
);
686 pc
= ram_get_entry (o
);
688 pc
= rom_get_entry (o
);
690 printf ("{0x%04x ", pc
);
707 void prim_print (void) {
715 int32
read_clock (void) {
724 static int32 start
= 0;
727 now
= tb
.time
* 1000 + tb
.millitm
;
732 static int32 start
= 0;
734 if (gettimeofday (&tv
, NULL
) == 0) {
735 now
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
746 void prim_clock (void) {
747 arg1
= encode_int (read_clock ());
750 void prim_motor (void) {
751 decode_2_int_args ();
753 if (a1
< 1 || a1
> 2 || a2
< -100 || a2
> 100)
754 ERROR("motor", "argument out of range");
761 printf ("motor %d -> power=%d\n", a1
, a2
);
770 void prim_led (void) {
771 decode_2_int_args ();
772 a3
= decode_int (arg3
);
774 if (a1
< 1 || a1
> 3 || a2
< 0 || a3
< 0)
775 ERROR("led", "argument out of range");
778 LED_set( a1
, a2
, a3
);
782 printf ("led %d -> duty=%d period=%d\n", a1
, a2
, a3
);
792 void prim_led2_color (void) {
793 a1
= decode_int (arg1
);
795 if (a1
< 0 || a1
> 1)
796 ERROR("led2-colors", "argument out of range");
799 LED2_color_set( a1
);
803 printf ("led2-color -> %s\n", (a1
==0)?"green":"red");
811 void prim_getchar_wait (void) {
813 a1
= read_clock () + a1
;
815 if (a1
< 0 || a2
< 1 || a2
> 3)
816 ERROR("getchar-wait", "argument out of range");
821 serial_port_set ports
;
822 ports
= serial_rx_wait_with_timeout( a2
, a1
);
824 arg1
= encode_int (serial_rx_read( ports
));
833 arg1
= encode_int (_getch ());
836 } while (read_clock () < a1
);
838 arg1
= encode_int (getchar ());
844 void prim_putchar (void) {
845 decode_2_int_args ();
847 if (a1
< 0 || a1
> 255 || a2
< 1 || a2
> 3)
848 ERROR("putchar", "argument out of range");
851 serial_tx_write( a2
, a1
);
864 void prim_beep (void) {
865 decode_2_int_args ();
867 if (a1
< 1 || a1
> 255 || a2
< 0)
868 ERROR("beep", "argument out of range");
871 beep( a1
, from_now( a2
) );
875 printf ("beep -> freq-div=%d duration=%d\n", a1
, a2
);
884 void prim_adc (void) {
887 a1
= decode_int (arg1
);
889 if (a1
< 1 || a1
> 3)
890 ERROR("adc", "argument out of range");
897 x
= read_clock () & 255;
898 if (x
> 127) x
= 256 - x
;
902 arg1
= encode_int (x
);
905 void prim_sernum (void) {
916 arg1
= encode_int (x
);
919 /*---------------------------------------------------------------------------*/
921 // networking primitives
923 void prim_network_init (void) { // TODO maybe put in the initialization of the vm
925 handle
= pcap_open_live(INTERFACE
, MAX_PACKET_SIZE
, PROMISC
, TO_MSEC
, errbuf
);
927 ERROR("network-init", "interface not responding");
931 void prim_network_cleanup (void) { // TODO maybe put in halt ?
937 void prim_receive_packet_to_u8vector (void) {
938 // arg1 is the vector in which to put the received packet
939 if (!RAM_VECTOR(arg1
))
940 TYPE_ERROR("receive-packet-to-u8vector", "vector");
943 // receive the packet in the buffer
944 struct pcap_pkthdr header
;
945 const u_char
*packet
;
947 packet
= pcap_next(handle
, &header
);
952 if (ram_get_car (arg1
) < header
.len
)
953 ERROR("receive-packet-to-u8vector", "packet longer than vector");
955 if (header
.len
> 0) { // we have received a packet, write it in the vector
956 arg2
= rom_get_cdr (arg1
);
957 arg1
= header
.len
; // we return the length of the received packet
961 ram_set_fieldn (arg2
, a1
% 4, (char)packet
[a1
]);
963 arg2
+= (a1
% 4) ? 0 : 1;
968 else // no packet to be read
973 void prim_send_packet_from_u8vector (void) {
974 // arg1 is the vector which contains the packet to be sent
975 // arg2 is the length of the packet
976 // TODO only works with ram vectors for now
977 if (!RAM_VECTOR(arg1
))
978 TYPE_ERROR("send-packet-from-vector!", "vector");
980 a2
= decode_int (arg2
); // TODO fix for bignums
983 // TODO test if the length of the packet is longer than the length of the vector
984 if (ram_get_car (arg1
) < a2
)
985 ERROR("send-packet-from-u8vector", "packet cannot be longer than vector");
987 arg1
= ram_get_cdr (arg1
);
990 // copy the packet to the output buffer
992 buf
[a1
] = ram_get_fieldn (arg1
, a1
% 4);
993 // TODO maybe I could just give pcap the pointer to the memory
995 if (pcap_sendpacket(handle
, buf
, a2
) < 0) // TODO an error has occurred, can we reuse the interface ?