1 /* file: "primitives.c" */
4 * Copyright 2004-2009 by Marc Feeley and Vincent St-Amour, All Rights Reserved.
7 #include "picobit-vm.h"
9 /*---------------------------------------------------------------------------*/
36 "prim #%graft-to-cont",
37 "prim #%return-to-cont",
41 "prim #%string->list",
42 "prim #%list->string",
43 "prim #%make-u8vector",
44 "prim #%u8vector-ref",
45 "prim #%u8vector-set!",
51 "prim #%getchar-wait",
57 "prim #%u8vector-length",
63 "prim #%network-init",
64 "prim #%network-cleanup",
65 "prim #%receive-packet-to-u8vector",
66 "prim #%send-packet-from-u8vector",
81 /*---------------------------------------------------------------------------*/
83 // numerical primitives
85 void prim_numberp () {
86 if (arg1
>= MIN_FIXNUM_ENCODING
87 && arg1
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
91 arg1
= encode_bool (RAM_BIGNUM(arg1
));
92 else if (IN_ROM(arg1
))
93 arg1
= encode_bool (ROM_BIGNUM(arg1
));
100 #ifdef INFINITE_PRECISION_BIGNUMS
101 arg1
= add (arg1
, arg2
);
103 decode_2_int_args ();
104 arg1
= encode_int (a1
+ a2
);
110 #ifdef INFINITE_PRECISION_BIGNUMS
111 arg1
= sub (arg1
, arg2
);
113 decode_2_int_args ();
114 arg1
= encode_int (a1
- a2
);
119 void prim_mul_non_neg () {
120 #ifdef INFINITE_PRECISION_BIGNUMS
121 arg1
= mulnonneg (arg1
, arg2
);
123 decode_2_int_args ();
124 arg1
= encode_int (a1
* a2
);
129 void prim_div_non_neg () {
130 #ifdef INFINITE_PRECISION_BIGNUMS
131 if (obj_eq(arg2
, ZERO
))
132 ERROR("quotient", "divide by 0");
133 arg1
= divnonneg (arg1
, arg2
);
135 decode_2_int_args ();
137 ERROR("quotient", "divide by 0");
138 arg1
= encode_int (a1
/ a2
);
144 #ifdef INFINITE_PRECISION_BIGNUMS
145 if (obj_eq(arg2
, ZERO
))
146 ERROR("remainder", "divide by 0");
147 if (negp(arg1
) || negp(arg2
))
148 ERROR("remainder", "only positive numbers are supported");
149 // TODO fix this to handle negatives
150 // TODO logic quite similar to mul and div (likely, once we fix), abstract ?
151 arg3
= divnonneg (arg1
, arg2
);
152 arg4
= mulnonneg (arg2
, arg3
);
153 arg1
= sub(arg1
, arg4
);
157 decode_2_int_args ();
159 ERROR("remainder", "divide by 0");
160 arg1
= encode_int (a1
% a2
);
166 #ifdef INFINITE_PRECISION_BIGNUMS
167 arg1
= encode_bool(cmp (arg1
, arg2
) == 1);
169 decode_2_int_args ();
170 arg1
= encode_bool(a1
== a2
);
176 #ifdef INFINITE_PRECISION_BIGNUMS
177 arg1
= encode_bool(cmp (arg1
, arg2
) < 1);
179 decode_2_int_args ();
180 arg1
= encode_bool(a1
< a2
);
186 #ifdef INFINITE_PRECISION_BIGNUMS
187 arg1
= encode_bool(cmp (arg1
, arg2
) > 1);
189 decode_2_int_args ();
190 arg1
= encode_bool(a1
> a2
);
196 #ifdef INFINITE_PRECISION_BIGNUMS
197 arg1
= bitwise_ior(arg1
, arg2
);
199 decode_2_int_args ();
200 arg1
= encode_int (a1
| a2
);
206 #ifdef INFINITE_PRECISION_BIGNUMS
207 arg1
= bitwise_xor(arg1
, arg2
);
209 decode_2_int_args ();
210 arg1
= encode_int (a1
^ a2
);
215 // TODO primitives for shifting ?
217 /*---------------------------------------------------------------------------*/
223 arg1
= encode_bool (RAM_PAIR(arg1
));
224 else if (IN_ROM(arg1
))
225 arg1
= encode_bool (ROM_PAIR(arg1
));
230 obj
cons (obj car
, obj cdr
) {
231 return alloc_ram_cell_init (COMPOSITE_FIELD0
| (car
>> 8),
233 PAIR_FIELD2
| (cdr
>> 8),
238 arg1
= cons (arg1
, arg2
);
245 TYPE_ERROR("car.0", "pair");
246 arg1
= ram_get_car (arg1
);
248 else if (IN_ROM(arg1
)) {
250 TYPE_ERROR("car.1", "pair");
251 arg1
= rom_get_car (arg1
);
254 TYPE_ERROR("car.2", "pair");
260 TYPE_ERROR("cdr.0", "pair");
261 arg1
= ram_get_cdr (arg1
);
263 else if (IN_ROM(arg1
)) {
265 TYPE_ERROR("cdr.1", "pair");
266 arg1
= rom_get_cdr (arg1
);
269 TYPE_ERROR("cdr.2", "pair");
272 void prim_set_car () {
275 TYPE_ERROR("set-car!.0", "pair");
277 ram_set_car (arg1
, arg2
);
282 TYPE_ERROR("set-car!.1", "pair");
285 void prim_set_cdr () {
288 TYPE_ERROR("set-cdr!.0", "pair");
290 ram_set_cdr (arg1
, arg2
);
295 TYPE_ERROR("set-cdr!.1", "pair");
299 arg1
= encode_bool (arg1
== OBJ_NULL
);
302 /*---------------------------------------------------------------------------*/
306 void prim_u8vectorp () {
308 arg1
= encode_bool (RAM_VECTOR(arg1
));
309 else if (IN_ROM(arg1
))
310 arg1
= encode_bool (ROM_VECTOR(arg1
));
315 void prim_make_u8vector () {
316 a1
= decode_int (arg1
); // arg1 is length
317 // TODO adapt for the new bignums
319 arg2
= alloc_vec_cell (a1
);
320 arg1
= alloc_ram_cell_init (COMPOSITE_FIELD0
| (a1
>> 8),
322 VECTOR_FIELD2
| (arg2
>> 8),
327 void prim_u8vector_ref () {
328 a2
= decode_int (arg2
);
329 // TODO adapt for the new bignums
331 if (!RAM_VECTOR(arg1
))
332 TYPE_ERROR("u8vector-ref.0", "vector");
333 if (ram_get_car (arg1
) <= a2
)
334 ERROR("u8vector-ref.0", "vector index invalid");
335 arg1
= ram_get_cdr (arg1
);
337 else if (IN_ROM(arg1
)) {
338 if (!ROM_VECTOR(arg1
))
339 TYPE_ERROR("u8vector-ref.1", "vector");
340 if (rom_get_car (arg1
) <= a2
)
341 ERROR("u8vector-ref.1", "vector index invalid");
342 arg1
= rom_get_cdr (arg1
);
345 TYPE_ERROR("u8vector-ref.2", "vector");
351 arg1
= encode_int (ram_get_fieldn (arg1
, a2
));
353 else { // rom vector, stored as a list
355 arg1
= rom_get_cdr (arg1
);
357 // the contents are already encoded as fixnums
358 arg1
= rom_get_car (arg1
);
366 void prim_u8vector_set () { // TODO a lot in common with ref, abstract that
367 a2
= decode_int (arg2
); // TODO adapt for bignums
368 a3
= decode_int (arg3
);
371 ERROR("u8vector-set!", "byte vectors can only contain bytes");
374 if (!RAM_VECTOR(arg1
))
375 TYPE_ERROR("u8vector-set!.0", "vector");
376 if (ram_get_car (arg1
) <= a2
)
377 ERROR("u8vector-set!", "vector index invalid");
378 arg1
= ram_get_cdr (arg1
);
381 TYPE_ERROR("u8vector-set!.1", "vector");
386 ram_set_fieldn (arg1
, a2
, a3
);
393 void prim_u8vector_length () {
395 if (!RAM_VECTOR(arg1
))
396 TYPE_ERROR("u8vector-length.0", "vector");
397 arg1
= encode_int (ram_get_car (arg1
));
399 else if (IN_ROM(arg1
)) {
400 if (!ROM_VECTOR(arg1
))
401 TYPE_ERROR("u8vector-length.1", "vector");
402 arg1
= encode_int (rom_get_car (arg1
));
405 TYPE_ERROR("u8vector-length.2", "vector");
409 /*---------------------------------------------------------------------------*/
411 // miscellaneous primitives
414 arg1
= encode_bool (arg1
== arg2
);
419 arg1
= encode_bool (arg1
== OBJ_FALSE
);
422 void prim_symbolp () {
424 arg1
= encode_bool (RAM_SYMBOL(arg1
));
425 else if (IN_ROM(arg1
))
426 arg1
= encode_bool (ROM_SYMBOL(arg1
));
431 void prim_stringp () {
433 arg1
= encode_bool (RAM_STRING(arg1
));
434 else if (IN_ROM(arg1
))
435 arg1
= encode_bool (ROM_STRING(arg1
));
440 void prim_string2list () {
442 if (!RAM_STRING(arg1
))
443 TYPE_ERROR("string->list.0", "string");
445 arg1
= ram_get_car (arg1
);
447 else if (IN_ROM(arg1
)) {
448 if (!ROM_STRING(arg1
))
449 TYPE_ERROR("string->list.1", "string");
451 arg1
= rom_get_car (arg1
);
454 TYPE_ERROR("string->list.2", "string");
457 void prim_list2string () {
458 arg1
= alloc_ram_cell_init (COMPOSITE_FIELD0
| ((arg1
& 0x1f00) >> 8),
464 void prim_booleanp () {
465 arg1
= encode_bool (arg1
< 2);
468 /*---------------------------------------------------------------------------*/
470 // robot-specific primitives
481 else if (o
== OBJ_TRUE
)
483 else if (o
== OBJ_NULL
)
485 else if (o
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
486 printf ("%d", DECODE_FIXNUM(o
));
495 if ((in_ram
&& RAM_BIGNUM(o
)) || (!in_ram
&& ROM_BIGNUM(o
))) // TODO fix for new bignums, especially for the sign, a -5 is displayed as 251
496 printf ("%d", decode_int (o
));
497 else if ((in_ram
&& RAM_COMPOSITE(o
)) || (!in_ram
&& ROM_COMPOSITE(o
))) {
501 if ((in_ram
&& RAM_PAIR(o
)) || (!in_ram
&& ROM_PAIR(o
))) {
503 car
= ram_get_car (o
);
504 cdr
= ram_get_cdr (o
);
507 car
= rom_get_car (o
);
508 cdr
= rom_get_cdr (o
);
519 else if ((IN_RAM(cdr
) && RAM_PAIR(cdr
))
520 || (IN_ROM(cdr
) && ROM_PAIR(cdr
))) {
522 car
= ram_get_car (cdr
);
523 cdr
= ram_get_cdr (cdr
);
526 car
= rom_get_car (cdr
);
527 cdr
= rom_get_cdr (cdr
);
539 else if ((in_ram
&& RAM_SYMBOL(o
)) || (!in_ram
&& ROM_SYMBOL(o
)))
540 printf ("#<symbol>");
541 else if ((in_ram
&& RAM_STRING(o
)) || (!in_ram
&& ROM_STRING(o
)))
542 printf ("#<string>");
543 else if ((in_ram
&& RAM_VECTOR(o
)) || (!in_ram
&& ROM_VECTOR(o
)))
544 printf ("#<vector %d>", o
);
547 cdr
= ram_get_car (o
);
548 car
= ram_get_cdr (o
);
549 // ugly hack, takes advantage of the fact that pairs and
550 // continuations have the same layout
558 env
= ram_get_car (o
);
559 pc
= ram_get_entry (o
);
561 printf ("{0x%04x ", pc
);
586 uint32
read_clock () {
595 static int32 start
= 0;
598 now
= tb
.time
* 1000 + tb
.millitm
;
603 static int32 start
= 0;
605 if (gettimeofday (&tv
, NULL
) == 0) {
606 now
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
618 arg1
= encode_int (read_clock ());
622 decode_2_int_args ();
624 if (a1
< 1 || a1
> 2 || a2
< -100 || a2
> 100) // TODO since we now use undigned values, we can't go backwards anymore
625 ERROR("motor", "argument out of range");
632 printf ("motor %d -> power=%d\n", a1
, a2
);
642 decode_2_int_args ();
643 a3
= decode_int (arg3
);
645 if (a1
< 1 || a1
> 3)
646 ERROR("led", "argument out of range");
649 LED_set( a1
, a2
, a3
);
653 printf ("led %d -> duty=%d period=%d\n", a1
, a2
, a3
);
663 void prim_led2_color () {
664 a1
= decode_int (arg1
);
667 ERROR("led2-colors", "argument out of range");
670 LED2_color_set( a1
);
674 printf ("led2-color -> %s\n", (a1
==0)?"green":"red");
682 void prim_getchar_wait () {
684 a1
= read_clock () + a1
;
686 if (a2
< 1 || a2
> 3)
687 ERROR("getchar-wait", "argument out of range");
693 serial_port_set ports
;
694 ports
= serial_rx_wait_with_timeout( a2
, a1
);
696 arg1
= encode_int (serial_rx_read( ports
));
705 arg1
= encode_int (_getch ());
708 } while (read_clock () < a1
);
710 arg1
= encode_int (getchar ());
716 void prim_putchar () {
717 decode_2_int_args ();
719 if (a1
> 255 || a2
< 1 || a2
> 3)
720 ERROR("putchar", "argument out of range");
723 serial_tx_write( a2
, a1
);
740 decode_2_int_args ();
742 if (a1
< 1 || a1
> 255)
743 ERROR("beep", "argument out of range");
746 beep( a1
, from_now( a2
) );
750 printf ("beep -> freq-div=%d duration=%d\n", a1
, a2
);
762 a1
= decode_int (arg1
);
764 if (a1
< 1 || a1
> 3)
765 ERROR("adc", "argument out of range");
772 x
= read_clock () & 255;
773 if (x
> 127) x
= 256 - x
;
777 arg1
= encode_int (x
);
780 void prim_sernum () {
791 arg1
= encode_int (x
);
794 /*---------------------------------------------------------------------------*/
796 // networking primitives
798 void prim_network_init () { // TODO maybe put in the initialization of the vm
800 handle
= pcap_open_live(INTERFACE
, MAX_PACKET_SIZE
, PROMISC
, TO_MSEC
, errbuf
);
802 ERROR("network-init", "interface not responding");
806 void prim_network_cleanup () { // TODO maybe put in halt ?
812 void prim_receive_packet_to_u8vector () {
813 // arg1 is the vector in which to put the received packet
814 if (!RAM_VECTOR(arg1
))
815 TYPE_ERROR("receive-packet-to-u8vector", "vector");
818 // receive the packet in the buffer
819 struct pcap_pkthdr header
;
820 const u_char
*packet
;
822 packet
= pcap_next(handle
, &header
);
827 if (ram_get_car (arg1
) < header
.len
)
828 ERROR("receive-packet-to-u8vector", "packet longer than vector");
830 if (header
.len
> 0) { // we have received a packet, write it in the vector
831 arg2
= rom_get_cdr (arg1
);
832 arg1
= header
.len
; // we return the length of the received packet
836 ram_set_fieldn (arg2
, a1
% 4, (char)packet
[a1
]);
838 arg2
+= (a1
% 4) ? 0 : 1;
843 else // no packet to be read
848 void prim_send_packet_from_u8vector () {
849 // arg1 is the vector which contains the packet to be sent
850 // arg2 is the length of the packet
851 // TODO only works with ram vectors for now
852 if (!RAM_VECTOR(arg1
))
853 TYPE_ERROR("send-packet-from-vector!", "vector");
855 a2
= decode_int (arg2
); // TODO fix for bignums
858 // TODO test if the length of the packet is longer than the length of the vector
859 if (ram_get_car (arg1
) < a2
)
860 ERROR("send-packet-from-u8vector", "packet cannot be longer than vector");
862 arg1
= ram_get_cdr (arg1
);
865 // copy the packet to the output buffer
867 buf
[a1
] = ram_get_fieldn (arg1
, a1
% 4);
868 // TODO maybe I could just give pcap the pointer to the memory
870 if (pcap_sendpacket(handle
, buf
, a2
) < 0) // TODO an error has occurred, can we reuse the interface ?