Fixed a bug related to negative fixnum encoding (i.e. -1). -1 was
[picobit/chj.git] / picobit-vm.c
blobf7e91f51cbe2a4d918b923b3672e930ca13fd4e0
1 /* file: "picobit-vm.c" */
3 /*
4 * Copyright 2008 by Marc Feeley and Vincent St-Amour, All Rights Reserved.
6 * History:
8 * 15/08/2004 Release of version 1
9 * 06/07/2008 Modified for PICOBOARD2_R3
10 * 18/07/2008 Modified to use new object representation
11 * 17/12/2008 Release of version 2
14 #define DEBUG_not
15 #define DEBUG_GC_not
16 // TODO once this is stable, put as default
17 #define INFINITE_PRECISION_BIGNUMS_not
19 /*---------------------------------------------------------------------------*/
21 typedef char int8;
22 typedef short int16;
23 typedef long int32;
24 typedef unsigned char uint8;
25 typedef unsigned short uint16;
26 typedef unsigned long uint32;
28 #define true 1
29 #define false 0
31 typedef uint8 boolean;
32 // TODO was signed, preventive change
34 /*---------------------------------------------------------------------------*/
37 #ifdef PICOBOARD2
38 #define ROBOT
39 #endif
41 #ifdef HI_TECH_C
42 #define ROBOT
43 #endif
45 #ifndef ROBOT
46 #define WORKSTATION
47 #endif
50 #ifdef HI_TECH_C
52 #include <pic18.h>
54 static volatile near uint8 FW_VALUE_UP @ 0x33;
55 static volatile near uint8 FW_VALUE_HI @ 0x33;
56 static volatile near uint8 FW_VALUE_LO @ 0x33;
58 #define ACTIVITY_LED1_LAT LATB
59 #define ACTIVITY_LED1_BIT 5
60 #define ACTIVITY_LED2_LAT LATB
61 #define ACTIVITY_LED2_BIT 4
62 static volatile near bit ACTIVITY_LED1 @ ((unsigned)&ACTIVITY_LED1_LAT*8)+ACTIVITY_LED1_BIT;
63 static volatile near bit ACTIVITY_LED2 @ ((unsigned)&ACTIVITY_LED2_LAT*8)+ACTIVITY_LED2_BIT;
65 #endif
68 #ifdef WORKSTATION
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <pcap.h>
74 // for libpcap
76 #define MAX_PACKET_SIZE BUFSIZ
77 #define PROMISC 1
78 #define TO_MSEC 1
80 char errbuf[PCAP_ERRBUF_SIZE];
81 pcap_t *handle;
83 #define INTERFACE "eth0"
85 char buf [MAX_PACKET_SIZE]; // buffer for writing
88 #ifdef _WIN32
89 #include <sys/types.h>
90 #include <sys/timeb.h>
91 #include <conio.h>
92 #else
93 #include <sys/time.h>
94 #endif
96 #endif
99 /*---------------------------------------------------------------------------*/
101 #define WORD_BITS 8
103 #define CODE_START 0x5000
105 #ifdef DEBUG
106 #define IF_TRACE(x) x
107 #define IF_GC_TRACE(x) x
108 #else
109 #define IF_TRACE(x)
110 #define IF_GC_TRACE(x)
111 #endif
113 /*---------------------------------------------------------------------------*/
116 #ifdef PICOBOARD2
118 #define ERROR(prim, msg) halt_with_error()
119 #define TYPE_ERROR(prim, type) halt_with_error()
121 #endif
124 #ifdef WORKSTATION
126 #define ERROR(prim, msg) error (prim, msg)
127 #define TYPE_ERROR(prim, type) type_error (prim, type)
129 void error (char *prim, char *msg)
131 printf ("ERROR: %s: %s\n", prim, msg);
132 exit (1);
135 void type_error (char *prim, char *type)
137 printf ("ERROR: %s: An argument of type %s was expected\n", prim, type);
138 exit (1);
141 #endif
144 /*---------------------------------------------------------------------------*/
146 #if WORD_BITS <= 8
147 typedef uint8 word;
148 #else
149 typedef uint16 word;
150 #endif
152 typedef uint16 ram_addr;
153 typedef uint16 rom_addr;
155 typedef uint16 obj;
157 #ifdef INFINITE_PRECISION_BIGNUMS
159 #define digit_width 16
161 typedef obj integer;
162 typedef uint16 digit; // TODO why this ? adds to the confusion
163 typedef uint32 two_digit;
165 #endif
167 /*---------------------------------------------------------------------------*/
169 #define MAX_VEC_ENCODING 8191
170 #define MIN_VEC_ENCODING 4096
171 #define VEC_BYTES ((MAX_VEC_ENCODING - MIN_VEC_ENCODING + 1)*4)
172 // TODO this is new. if the pic has less than 8k of memory, start this lower
173 // TODO the pic actually has 2k, so change these
174 // TODO we'd only actually need 1024 or so for ram and vectors, since we can't address more. this gives us a lot of rom space
176 #define MAX_RAM_ENCODING 4095
177 #define MIN_RAM_ENCODING 512
178 #define RAM_BYTES ((MAX_RAM_ENCODING - MIN_RAM_ENCODING + 1)*4)
179 // TODO watch out if we address more than what the PIC actually has
181 #if WORD_BITS == 8
182 #define OBJ_TO_VEC_ADDR(o,f) (((ram_addr)((uint16)(o) - MIN_RAM_ENCODING) << 2) + (f))
183 #define OBJ_TO_RAM_ADDR(o,f) (((ram_addr)((uint16)(o) - MIN_RAM_ENCODING) << 2) + (f))
184 #define OBJ_TO_ROM_ADDR(o,f) (((rom_addr)((uint16)(o) - MIN_ROM_ENCODING) << 2) + (CODE_START + 4 + (f)))
185 #endif
187 #ifdef PICOBOARD2
189 #define ram_get(a) *(uint8*)(a+0x200)
190 #define ram_set(a,x) *(uint8*)(a+0x200) = (x)
191 #endif
194 #ifdef WORKSTATION
196 uint8 ram_mem[RAM_BYTES + VEC_BYTES];
198 #define ram_get(a) ram_mem[a]
199 #define ram_set(a,x) ram_mem[a] = (x)
201 #endif
204 /*---------------------------------------------------------------------------*/
206 #ifdef PICOBOARD2
208 uint8 rom_get (rom_addr a)
210 return *(rom uint8*)a;
213 #endif
216 #ifdef WORKSTATION
218 #define ROM_BYTES 8192
219 // TODO the new pics have 32k, change this ? minus the vm size, firmware ?
221 uint8 rom_mem[ROM_BYTES] =
223 #define RED_GREEN
224 #define PUTCHAR_LIGHT_not
226 #ifdef RED_GREEN
227 0xFB, 0xD7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x32
228 , 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00
229 , 0x08, 0x50, 0x80, 0x16, 0xFE, 0xE8, 0x00, 0xFC
230 , 0x32, 0x80, 0x2D, 0xFE, 0xFC, 0x31, 0x80, 0x43
231 , 0xFE, 0xFC, 0x33, 0x80, 0x2D, 0xFE, 0xFC, 0x31
232 , 0x80, 0x43, 0xFE, 0x90, 0x16, 0x01, 0x20, 0xFC
233 , 0x32, 0xE3, 0xB0, 0x37, 0x09, 0xF3, 0xFF, 0x20
234 , 0xFC, 0x33, 0xE3, 0xB0, 0x40, 0x0A, 0xF3, 0xFF
235 , 0x08, 0xF3, 0xFF, 0x01, 0x40, 0x21, 0xD1, 0x00
236 , 0x02, 0xC0, 0x4C, 0x71, 0x01, 0x20, 0x50, 0x90
237 , 0x51, 0x00, 0xF1, 0x40, 0xD8, 0xB0, 0x59, 0x90
238 , 0x51, 0x00, 0xFF
239 #endif
240 #ifdef PUTCHAR_LIGHT
241 0xFB, 0xD7, 0x00, 0x00, 0x80, 0x08, 0xFE, 0xE8
242 , 0x00, 0xF6, 0xF5, 0x90, 0x08
243 #endif
246 uint8 rom_get (rom_addr a)
248 return rom_mem[a-CODE_START];
251 #endif
253 /*---------------------------------------------------------------------------*/
256 OBJECT ENCODING:
258 #f 0
259 #t 1
260 () 2
261 fixnum n MIN_FIXNUM -> 3 ... MAX_FIXNUM -> 3 + (MAX_FIXNUM-MIN_FIXNUM)
262 rom object 4 + (MAX_FIXNUM-MIN_FIXNUM) ... MIN_RAM_ENCODING-1
263 ram object MIN_RAM_ENCODING ... MAX_RAM_ENCODING
264 u8vector MIN_VEC_ENCODING ... 8191
266 layout of memory allocated objects:
268 G's represent mark bits used by the gc
270 ifdef INFINITE_PRECISION_BIGNUMS
271 bignum n 0GG***** **next** hhhhhhhh llllllll (16 bit digit)
272 TODO make sure this works with the "new" object representation, that the first 3 bits are enough to spot bignums, quick check of the bignum predicate indicates this would work, now implement this pointer FOOBIGNUM
273 TODO what to do with the gc tags for the bignums ? will this work ?
275 ifndef INFINITE_PRECISION_BIGNUMS
276 bignum n 0000000 uuuuuuuu hhhhhhhh llllllll (24 bit signed integer)
278 pair 1GGaaaaa aaaaaaaa 000ddddd dddddddd
279 a is car
280 d is cdr
281 gives an address space of 2^13 * 4 = 32k divided between simple objects,
282 rom, ram and vectors
284 symbol 1GG00000 00000000 00100000 00000000
286 string 1GG***** *chars** 01000000 00000000
288 u8vector 1GGxxxxx xxxxxxxx 011yyyyy yyyyyyyy
289 x is length of the vector, in bytes (stored raw, not encoded as an object)
290 y is pointer to the elements themselves (stored in vector space)
292 closure 01Gaaaaa aaaaaaaa aaaxxxxx xxxxxxxx
293 0x5ff<a<0x4000 is entry
294 x is pointer to environment
295 the reason why the environment is on the cdr (and the entry is split on 3
296 bytes) is that, when looking for a variable, a closure is considered to be a
297 pair. The compiler adds an extra offset to any variable in the closure's
298 environment, so the car of the closure (which doesn't really exist) is never
299 checked, but the cdr is followed to find the other bindings
301 continuation 1GGxxxxx xxxxxxxx 100yyyyy yyyyyyyy
302 x is parent continuation
303 y is pointer to the second half, which is a closure (contains env and entry)
305 An environment is a list of objects built out of pairs. On entry to
306 a procedure the environment is the list of parameters to which is
307 added the environment of the closure being called.
309 The first byte at the entry point of a procedure gives the arity of
310 the procedure:
312 n = 0 to 127 -> procedure has n parameters (no rest parameter)
313 n = -128 to -1 -> procedure has -n parameters, the last is
314 a rest parameter
317 #define OBJ_FALSE 0
318 #define OBJ_TRUE 1
319 #define encode_bool(x) ((obj)(x))
321 #define OBJ_NULL 2
323 #define MIN_FIXNUM_ENCODING 3
324 // TODO change these ? were -5 and 40, with the new bignums, the needs for these might change
325 #define MIN_FIXNUM -1
326 // TODO FOOBIGNUMS, was 0, but -1 needed to be a fixnum for the algos to work
327 #define MAX_FIXNUM 255
328 #define MIN_ROM_ENCODING (MIN_FIXNUM_ENCODING+MAX_FIXNUM-MIN_FIXNUM+1)
330 #define ENCODE_FIXNUM(n) ((obj)(n) + (MIN_FIXNUM_ENCODING - MIN_FIXNUM))
331 #define DECODE_FIXNUM(o) ((int32)(o) - (MIN_FIXNUM_ENCODING - MIN_FIXNUM))
333 // TODO why this ifdef ?
334 #if WORD_BITS == 8
335 #define IN_VEC(o) ((o) >= MIN_VEC_ENCODING)
336 #define IN_RAM(o) (!IN_VEC(o) && ((o) >= MIN_RAM_ENCODING))
337 #define IN_ROM(o) (!IN_VEC(o) && !IN_RAM(o) && ((o) >= MIN_ROM_ENCODING))
338 #endif
340 // bignum first byte : 00Gxxxxx
341 #define BIGNUM_FIELD0 0
342 #define RAM_BIGNUM(o) ((ram_get_field0 (o) & 0xc0) == BIGNUM_FIELD0)
343 #define ROM_BIGNUM(o) ((rom_get_field0 (o) & 0xc0) == BIGNUM_FIELD0)
345 // composite first byte : 1GGxxxxx
346 #define COMPOSITE_FIELD0 0x80
347 #define RAM_COMPOSITE(o) ((ram_get_field0 (o) & 0x80) == COMPOSITE_FIELD0)
348 #define ROM_COMPOSITE(o) ((rom_get_field0 (o) & 0x80) == COMPOSITE_FIELD0)
350 // pair third byte : 000xxxxx
351 #define PAIR_FIELD2 0
352 #define RAM_PAIR(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == PAIR_FIELD2))
353 #define ROM_PAIR(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == PAIR_FIELD2))
355 // symbol third byte : 001xxxxx
356 #define SYMBOL_FIELD2 0x20
357 #define RAM_SYMBOL(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == SYMBOL_FIELD2))
358 #define ROM_SYMBOL(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == SYMBOL_FIELD2))
360 // string third byte : 010xxxxx
361 #define STRING_FIELD2 0x40
362 #define RAM_STRING(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == STRING_FIELD2))
363 #define ROM_STRING(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == STRING_FIELD2))
365 // vector third byte : 011xxxxx
366 #define VECTOR_FIELD2 0x60
367 #define RAM_VECTOR(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == VECTOR_FIELD2))
368 #define ROM_VECTOR(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == VECTOR_FIELD2))
370 // continuation third byte : 100xxxxx
371 #define CONTINUATION_FIELD2 0x80
372 #define RAM_CONTINUATION(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == CONTINUATION_FIELD2))
373 #define ROM_CONTINUATION(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == CONTINUATION_FIELD2))
375 // closure first byte : 01Gxxxxx
376 #define CLOSURE_FIELD0 0x40
377 #define RAM_CLOSURE(o) ((ram_get_field0 (o) & 0xc0) == CLOSURE_FIELD0)
378 #define ROM_CLOSURE(o) ((rom_get_field0 (o) & 0xc0) == CLOSURE_FIELD0)
381 /*---------------------------------------------------------------------------*/
383 #define RAM_GET_FIELD0_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,0))
384 #define RAM_SET_FIELD0_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,0), val)
385 #define ROM_GET_FIELD0_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,0))
387 #define RAM_GET_GC_TAGS_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x60)
388 #define RAM_GET_GC_TAG0_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x20)
389 #define RAM_GET_GC_TAG1_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x40)
390 #define RAM_SET_GC_TAGS_MACRO(o,tags) \
391 (RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0x9f) | (tags)))
392 #define RAM_SET_GC_TAG0_MACRO(o,tag) \
393 RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0xdf) | (tag))
394 #define RAM_SET_GC_TAG1_MACRO(o,tag) \
395 RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0xbf) | (tag))
397 #if WORD_BITS == 8
398 #define RAM_GET_FIELD1_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,1))
399 #define RAM_GET_FIELD2_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,2))
400 #define RAM_GET_FIELD3_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,3))
401 #define RAM_SET_FIELD1_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,1), val)
402 #define RAM_SET_FIELD2_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,2), val)
403 #define RAM_SET_FIELD3_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,3), val)
404 #define ROM_GET_FIELD1_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,1))
405 #define ROM_GET_FIELD2_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,2))
406 #define ROM_GET_FIELD3_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,3))
407 #define VEC_GET_BYTE0_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,0))
408 #define VEC_GET_BYTE1_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,1))
409 #define VEC_GET_BYTE2_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,2))
410 #define VEC_GET_BYTE3_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,3))
411 #define VEC_SET_BYTE0_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,0), val)
412 #define VEC_SET_BYTE1_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,1), val)
413 #define VEC_SET_BYTE2_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,2), val)
414 #define VEC_SET_BYTE3_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,3), val)
415 #endif
417 uint8 ram_get_gc_tags (obj o) { return RAM_GET_GC_TAGS_MACRO(o); }
418 uint8 ram_get_gc_tag0 (obj o) { return RAM_GET_GC_TAG0_MACRO(o); }
419 uint8 ram_get_gc_tag1 (obj o) { return RAM_GET_GC_TAG1_MACRO(o); }
420 void ram_set_gc_tags (obj o, uint8 tags) { RAM_SET_GC_TAGS_MACRO(o, tags); }
421 void ram_set_gc_tag0 (obj o, uint8 tag) { RAM_SET_GC_TAG0_MACRO(o,tag); }
422 void ram_set_gc_tag1 (obj o, uint8 tag) { RAM_SET_GC_TAG1_MACRO(o,tag); }
423 uint8 ram_get_field0 (obj o) { return RAM_GET_FIELD0_MACRO(o); }
424 word ram_get_field1 (obj o) { return RAM_GET_FIELD1_MACRO(o); }
425 word ram_get_field2 (obj o) { return RAM_GET_FIELD2_MACRO(o); }
426 word ram_get_field3 (obj o) { return RAM_GET_FIELD3_MACRO(o); }
427 word ram_get_fieldn (obj o, uint8 n)
429 switch (n)
431 case 0: return ram_get_field0 (o);
432 case 1: return ram_get_field1 (o);
433 case 2: return ram_get_field2 (o);
434 case 3: return ram_get_field3 (o);
437 void ram_set_field0 (obj o, uint8 val) { RAM_SET_FIELD0_MACRO(o,val); }
438 void ram_set_field1 (obj o, word val) { RAM_SET_FIELD1_MACRO(o,val); }
439 void ram_set_field2 (obj o, word val) { RAM_SET_FIELD2_MACRO(o,val); }
440 void ram_set_field3 (obj o, word val) { RAM_SET_FIELD3_MACRO(o,val); }
441 void ram_set_fieldn (obj o, uint8 n, word val)
443 switch (n)
445 case 0: ram_set_field0 (o, val); break;
446 case 1: ram_set_field1 (o, val); break;
447 case 2: ram_set_field2 (o, val); break;
448 case 3: ram_set_field3 (o, val); break;
451 uint8 rom_get_field0 (obj o) { return ROM_GET_FIELD0_MACRO(o); }
452 word rom_get_field1 (obj o) { return ROM_GET_FIELD1_MACRO(o); }
453 word rom_get_field2 (obj o) { return ROM_GET_FIELD2_MACRO(o); }
454 word rom_get_field3 (obj o) { return ROM_GET_FIELD3_MACRO(o); }
455 /* word vec_get_byte0 (obj o) { return VEC_GET_BYTE0_MACRO(o); } */
456 /* word vec_get_byte1 (obj o) { return VEC_GET_BYTE1_MACRO(o); } */
457 /* word vec_get_byte2 (obj o) { return VEC_GET_BYTE2_MACRO(o); } */
458 /* word vec_get_byte3 (obj o) { return VEC_GET_BYTE3_MACRO(o); } */
459 /* word vec_set_byte0 (obj o, word val) { VEC_SET_BYTE0_MACRO(o,val); } */
460 /* word vec_set_byte1 (obj o, word val) { VEC_SET_BYTE1_MACRO(o,val); } */
461 /* word vec_set_byte2 (obj o, word val) { VEC_SET_BYTE2_MACRO(o,val); } */
462 /* word vec_set_byte3 (obj o, word val) { VEC_SET_BYTE3_MACRO(o,val); } */
464 obj get_field0 (obj o) // TODO these are not used yet, will they be useful at all ?
466 if (IN_RAM(o))
467 return ram_get_field0 (o);
468 else
469 return rom_get_field0 (o);
471 obj get_field1 (obj o)
473 if (IN_RAM(o))
474 return ram_get_field1 (o);
475 else
476 return rom_get_field1 (o);
478 obj get_field2 (obj o)
480 if (IN_RAM(o))
481 return ram_get_field2 (o);
482 else
483 return rom_get_field2 (o);
485 obj get_field3 (obj o)
487 if (IN_RAM(o))
488 return ram_get_field3 (o);
489 else
490 return rom_get_field3 (o);
494 obj ram_get_car (obj o)
495 { return ((ram_get_field0 (o) & 0x1f) << 8) | ram_get_field1 (o); }
496 obj rom_get_car (obj o)
497 { return ((rom_get_field0 (o) & 0x1f) << 8) | rom_get_field1 (o); }
498 obj ram_get_cdr (obj o)
499 { return ((ram_get_field2 (o) & 0x1f) << 8) | ram_get_field3 (o); }
500 obj rom_get_cdr (obj o)
501 { return ((rom_get_field2 (o) & 0x1f) << 8) | rom_get_field3 (o); }
502 obj get_car (obj o)
504 if (IN_RAM(o))
505 return ram_get_car (o);
506 else
507 return rom_get_car (o);
509 obj get_cdr (obj o)
511 if (IN_RAM(o))
512 return ram_get_cdr (o);
513 else
514 return rom_get_cdr (o);
517 void ram_set_car (obj o, obj val)
519 ram_set_field0 (o, (val >> 8) | (ram_get_field0 (o) & 0xe0));
520 ram_set_field1 (o, val & 0xff);
522 void ram_set_cdr (obj o, obj val)
524 ram_set_field2 (o, (val >> 8) | (ram_get_field2 (o) & 0xe0));
525 ram_set_field3 (o, val & 0xff);
528 obj ram_get_entry (obj o)
530 return (((ram_get_field0 (o) & 0x1f) << 11)
531 | (ram_get_field1 (o) << 3)
532 | (ram_get_field2 (o) >> 5));
534 obj rom_get_entry (obj o)
536 return (((rom_get_field0 (o) & 0x1f) << 11)
537 | (rom_get_field1 (o) << 3)
538 | (rom_get_field2 (o) >> 5));
540 obj get_entry (obj o)
542 if (IN_RAM(o))
543 return ram_get_entry (o);
544 else
545 return rom_get_entry (o);
549 obj get_global (uint8 i)
550 // globals occupy the beginning of ram, with 2 globals per word
552 if (i & 1)
553 return ram_get_cdr (MIN_RAM_ENCODING + (i / 2));
554 else
555 return ram_get_car (MIN_RAM_ENCODING + (i / 2));
558 void set_global (uint8 i, obj o)
560 if (i & 1)
561 ram_set_cdr (MIN_RAM_ENCODING + (i / 2), o);
562 else
563 ram_set_car (MIN_RAM_ENCODING + (i / 2), o);
566 #ifdef WORKSTATION
567 void show_type (obj o) // for debugging purposes
569 printf("%d : ", o);
570 if (o == OBJ_FALSE) printf("#f");
571 else if (o == OBJ_TRUE) printf("#t");
572 else if (o == OBJ_NULL) printf("()");
573 else if (o < MIN_ROM_ENCODING) printf("fixnum");
574 else if (IN_RAM (o))
576 if (RAM_BIGNUM(o)) printf("ram bignum");
577 else if (RAM_PAIR(o)) printf("ram pair");
578 else if (RAM_SYMBOL(o)) printf("ram symbol");
579 else if (RAM_STRING(o)) printf("ram string");
580 else if (RAM_VECTOR(o)) printf("ram vector");
581 else if (RAM_CONTINUATION(o)) printf("ram continuation");
582 else if (RAM_CLOSURE(o)) printf("ram closure");
584 else // ROM
586 if (ROM_BIGNUM(o)) printf("rom bignum");
587 else if (ROM_PAIR(o)) printf("rom pair");
588 else if (ROM_SYMBOL(o)) printf("rom symbol");
589 else if (ROM_STRING(o)) printf("rom string");
590 else if (ROM_VECTOR(o)) printf("rom vector");
591 else if (ROM_CONTINUATION(o)) printf("rom continuation");
592 else if (RAM_CLOSURE(o)) printf("rom closure");
594 printf("\n");
596 #endif
599 /*---------------------------------------------------------------------------*/
601 /* Interface to GC */
603 // TODO explain what each tag means, with 1-2 mark bits
604 #define GC_TAG_0_LEFT (1<<5)
605 #define GC_TAG_1_LEFT (2<<5)
606 #define GC_TAG_UNMARKED (0<<5)
608 /* Number of object fields of objects in ram */
609 #define HAS_2_OBJECT_FIELDS(visit) (RAM_PAIR(visit) || RAM_CONTINUATION(visit))
610 #ifdef INFINITE_PRECISION_BIGNUMS
611 #define HAS_1_OBJECT_FIELD(visit) (RAM_COMPOSITE(visit) \
612 || RAM_CLOSURE(visit) || RAM_BIGNUM(visit))
613 #else
614 #define HAS_1_OBJECT_FIELD(visit) (RAM_COMPOSITE(visit) || RAM_CLOSURE(visit))
615 #endif
616 // all composites except pairs and continuations have 1 object field
618 #define NIL OBJ_FALSE
620 /*---------------------------------------------------------------------------*/
622 /* Garbage collector */
624 obj free_list; /* list of unused cells */
625 obj free_list_vec; /* list of unused cells in vector space */
627 obj arg1; /* root set */
628 obj arg2;
629 obj arg3;
630 obj arg4;
631 obj arg5;
632 obj cont;
633 obj env;
635 uint8 na; /* interpreter variables */
636 rom_addr pc;
637 uint8 glovars;
638 rom_addr entry;
639 uint8 bytecode;
640 uint8 bytecode_hi4;
641 uint8 bytecode_lo4;
642 int32 a1;
643 int32 a2;
644 int32 a3;
646 void init_ram_heap (void)
648 uint8 i;
649 obj o = MAX_RAM_ENCODING;
651 free_list = 0;
653 while (o > (MIN_RAM_ENCODING + (glovars + 1) / 2))
654 // we don't want to add globals to the free list, and globals occupy the
655 // beginning of memory at the rate of 2 globals per word (car and cdr)
657 ram_set_gc_tags (o, GC_TAG_UNMARKED);
658 ram_set_car (o, free_list);
659 free_list = o;
660 o--;
663 free_list_vec = MIN_VEC_ENCODING;
664 ram_set_car (free_list_vec, 0);
665 // each node of the free list must know the free length that follows it
666 // this free length is stored in words, not in bytes
667 // if we did count in bytes, the number might need more than 13 bits
668 ram_set_cdr (free_list_vec, VEC_BYTES / 4);
670 for (i=0; i<glovars; i++)
671 set_global (i, OBJ_FALSE);
673 arg1 = OBJ_FALSE;
674 arg2 = OBJ_FALSE;
675 arg3 = OBJ_FALSE;
676 arg4 = OBJ_FALSE;
677 cont = OBJ_FALSE;
678 env = OBJ_NULL;
682 void mark (obj temp)
684 /* mark phase */
686 obj stack;
687 obj visit;
689 if (IN_RAM(temp))
691 visit = NIL;
693 push:
695 stack = visit;
696 visit = temp;
698 IF_GC_TRACE(printf ("push stack=%d visit=%d (tag=%d)\n", stack, visit, ram_get_gc_tags (visit)>>5));
700 if ((HAS_1_OBJECT_FIELD (visit) && ram_get_gc_tag0 (visit))
701 || (HAS_2_OBJECT_FIELDS (visit)
702 && (ram_get_gc_tags (visit) != GC_TAG_UNMARKED)))
703 IF_GC_TRACE(printf ("case 1\n"));
704 else
706 if (HAS_2_OBJECT_FIELDS(visit)) // pairs and continuations
708 IF_GC_TRACE(printf ("case 2\n"));
710 visit_field2:
712 temp = ram_get_cdr (visit);
714 if (IN_RAM(temp))
716 IF_GC_TRACE(printf ("case 3\n"));
717 ram_set_gc_tags (visit, GC_TAG_1_LEFT);
718 ram_set_cdr (visit, stack);
719 goto push;
722 IF_GC_TRACE(printf ("case 4\n"));
724 goto visit_field1;
727 if (HAS_1_OBJECT_FIELD(visit))
729 IF_GC_TRACE(printf ("case 5\n"));
731 visit_field1:
733 if (RAM_CLOSURE(visit)) // closures have the pointer in the cdr
734 temp = ram_get_cdr (visit);
735 else
736 temp = ram_get_car (visit);
738 if (IN_RAM(temp))
740 IF_GC_TRACE(printf ("case 6\n"));
741 ram_set_gc_tag0 (visit, GC_TAG_0_LEFT);
742 if (RAM_CLOSURE(visit))
743 ram_set_cdr (visit, stack);
744 else
745 ram_set_car (visit, stack);
747 goto push;
750 IF_GC_TRACE(printf ("case 7\n"));
752 else
753 IF_GC_TRACE(printf ("case 8\n"));
755 ram_set_gc_tag0 (visit, GC_TAG_0_LEFT);
758 pop:
760 IF_GC_TRACE(printf ("pop stack=%d visit=%d (tag=%d)\n", stack, visit, ram_get_gc_tags (visit)>>6));
762 if (stack != NIL)
764 if (HAS_2_OBJECT_FIELDS(stack) && ram_get_gc_tag1 (stack))
766 IF_GC_TRACE(printf ("case 9\n"));
768 temp = ram_get_cdr (stack); /* pop through cdr */
769 ram_set_cdr (stack, visit);
770 visit = stack;
771 stack = temp;
773 ram_set_gc_tag1(visit, GC_TAG_UNMARKED);
774 // we unset the "1-left" bit
776 goto visit_field1;
779 if (RAM_CLOSURE(stack))
780 // closures have one object field, but it's in the cdr
782 IF_GC_TRACE(printf ("case 10\n"));
784 temp = ram_get_cdr (stack); /* pop through cdr */
785 ram_set_cdr (stack, visit);
786 visit = stack;
787 stack = temp;
789 goto pop;
792 IF_GC_TRACE(printf ("case 11\n"));
794 temp = ram_get_car (stack); /* pop through car */
795 ram_set_car (stack, visit);
796 visit = stack;
797 stack = temp;
799 goto pop;
804 #ifdef DEBUG_GC
805 int max_live = 0;
806 #endif
808 void sweep (void)
810 /* sweep phase */
812 #ifdef DEBUG_GC
813 int n = 0;
814 #endif
816 obj visit = MAX_RAM_ENCODING;
818 free_list = 0;
820 while (visit >= (MIN_RAM_ENCODING + ((glovars + 1) / 2)))
821 // we don't want to sweep the global variables area
823 if ((RAM_COMPOSITE(visit)
824 && (ram_get_gc_tags (visit) == GC_TAG_UNMARKED)) // 2 mark bit
825 || !(ram_get_gc_tags (visit) & GC_TAG_0_LEFT)) // 1 mark bit
826 /* unmarked? */
828 if (RAM_VECTOR(visit))
829 // when we sweep a vector, we also have to sweep its contents
831 obj o = ram_get_cdr (visit);
832 uint16 i = ram_get_car (visit); // number of elements
833 ram_set_car (o, free_list_vec);
834 ram_set_cdr (o, (i + 3) / 4); // free length, in words
835 free_list_vec = o;
836 // TODO merge free spaces
838 ram_set_car (visit, free_list);
839 free_list = visit;
841 else
843 if (RAM_COMPOSITE(visit))
844 ram_set_gc_tags (visit, GC_TAG_UNMARKED);
845 else // only 1 mark bit to unset
846 ram_set_gc_tag0 (visit, GC_TAG_UNMARKED);
847 #ifdef DEBUG_GC
848 n++;
849 #endif
851 visit--;
854 #ifdef DEBUG_GC
855 if (n > max_live)
857 max_live = n;
858 printf ("**************** memory needed = %d\n", max_live+1);
859 fflush (stdout);
861 #endif
864 void gc (void)
866 uint8 i;
868 IF_TRACE(printf("\nGC BEGINS\n"));
870 IF_GC_TRACE(printf("arg1\n"));
871 mark (arg1);
872 IF_GC_TRACE(printf("arg2\n"));
873 mark (arg2);
874 IF_GC_TRACE(printf("arg3\n"));
875 mark (arg3);
876 IF_GC_TRACE(printf("arg4\n"));
877 mark (arg4);
878 IF_GC_TRACE(printf("arg5\n"));
879 mark (arg5);
880 IF_GC_TRACE(printf("cont\n"));
881 mark (cont);
882 IF_GC_TRACE(printf("env\n"));
883 mark (env);
885 IF_GC_TRACE(printf("globals\n"));
886 for (i=0; i<glovars; i++)
887 mark (get_global (i));
889 sweep ();
892 obj alloc_ram_cell (void)
894 obj o;
896 #ifdef DEBUG_GC
897 gc ();
898 #endif
900 if (free_list == 0)
902 #ifndef DEBUG_GC
903 gc ();
904 if (free_list == 0)
905 #endif
906 ERROR("alloc_ram_cell", "memory is full");
909 o = free_list;
911 free_list = ram_get_car (o);
913 return o;
916 obj alloc_ram_cell_init (uint8 f0, uint8 f1, uint8 f2, uint8 f3)
918 obj o = alloc_ram_cell ();
920 ram_set_field0 (o, f0);
921 ram_set_field1 (o, f1);
922 ram_set_field2 (o, f2);
923 ram_set_field3 (o, f3);
925 return o;
928 obj alloc_vec_cell (uint16 n)
930 obj o = free_list_vec;
931 obj prec = 0;
932 uint8 gc_done = 0;
934 #ifdef DEBUG_GC
935 gc ();
936 gc_done = 1;
937 #endif
939 while ((ram_get_cdr (o) * 4) < n) // free space too small
941 if (o == 0) // no free space, or none big enough
943 if (gc_done) // we gc'd, but no space is big enough for the vector
944 ERROR("alloc_vec_cell", "no room for vector");
945 #ifndef DEBUG_GC
946 gc ();
947 gc_done = 1;
948 #endif
949 o = free_list_vec;
950 prec = 0;
951 continue;
952 } // TODO merge adjacent free spaces, maybe compact ?
953 prec = o;
954 o = ram_get_car (o);
957 // case 1 : the new vector fills every free word advertized, we remove the
958 // node from the free list
959 if (((ram_get_cdr(o) * 4) - n) < 4)
961 if (prec)
962 ram_set_car (prec, ram_get_car (o));
963 else
964 free_list_vec = ram_get_car (o);
966 // case 2 : there is still some space left in the free section, create a new
967 // node to represent this space
968 else
970 obj new_free = o + (n + 3)/4;
971 if (prec)
972 ram_set_car (prec, new_free);
973 else
974 free_list_vec = new_free;
975 ram_set_car (new_free, ram_get_car (o));
976 ram_set_cdr (new_free, ram_get_cdr (o) - (n + 3)/4);
979 return o;
982 /*---------------------------------------------------------------------------*/
984 #ifdef INFINITE_PRECISION_BIGNUMS
986 // TODO FOOBIGNUMS this was taken from the bignum code, see if it works
987 int8 decode_int8 (obj o) // TODO never used except in decode_int
988 { // TODO really fishy, to use only 8 bits this way...
989 int8 result;
990 if (o < MIN_FIXNUM_ENCODING)
991 TYPE_ERROR("decode_int8.0", "integer");
993 if (o <= (MIN_FIXNUM_ENCODING + (MAX_FIXNUM - MIN_FIXNUM)))
994 return DECODE_FIXNUM(o);
996 if (IN_RAM(o))
998 if (!RAM_BIGNUM(o))
999 TYPE_ERROR("decode_int8.1", "integer");
1000 return ram_get_field3 (o);
1002 else if (IN_ROM(o))
1004 if (!ROM_BIGNUM(o))
1005 TYPE_ERROR("decode_int8.2", "integer");
1006 return rom_get_field3 (o);
1008 else
1009 TYPE_ERROR("decode_int8.3", "integer");
1011 // TODO how could this possibly work ? it does not consider other fields, same for encoding, get to the bottom of this
1013 int32 decode_int (obj o)
1015 return decode_int8 (o); // TODO FOOBAR clearly wrong, is it used ?
1019 obj encode_int (int32 n) // TODO never used in the bignum code
1021 if (n >= MIN_FIXNUM && n <= MAX_FIXNUM){
1022 return ENCODE_FIXNUM(n);
1025 // TODO FOOBIGNUMS since we encode 0 here, and it's 00..0 we don't need to or with the 1st byte for the pointer, what happens with negative numbers, however ?
1026 return alloc_ram_cell_init (BIGNUM_FIELD0, ENCODE_FIXNUM(0), n >> 8, n);
1029 #else
1031 int32 decode_int (obj o)
1033 uint8 u;
1034 uint8 h;
1035 uint8 l;
1037 if (o < MIN_FIXNUM_ENCODING)
1038 TYPE_ERROR("decode_int.0", "integer");
1040 if (o <= (MIN_FIXNUM_ENCODING + (MAX_FIXNUM - MIN_FIXNUM)))
1041 return DECODE_FIXNUM(o);
1043 if (IN_RAM(o))
1045 if (!RAM_BIGNUM(o))
1046 TYPE_ERROR("decode_int.1", "integer");
1048 u = ram_get_field1 (o);
1049 h = ram_get_field2 (o);
1050 l = ram_get_field3 (o);
1052 else if (IN_ROM(o))
1054 if (!ROM_BIGNUM(o))
1055 TYPE_ERROR("decode_int.2", "integer");
1057 u = rom_get_field1 (o);
1058 h = rom_get_field2 (o);
1059 l = rom_get_field3 (o);
1061 else
1062 TYPE_ERROR("decode_int.3", "integer");
1064 if (u >= 128) // TODO FOOBIGNUMS uhh, what's that again ? is here since the beginning
1065 return ((int32)((((int16)u - 256) << 8) + h) << 8) + l;
1067 return ((int32)(((int16)u << 8) + h) << 8) + l;
1070 obj encode_int (int32 n)
1072 if (n >= MIN_FIXNUM && n <= MAX_FIXNUM)
1073 return ENCODE_FIXNUM(n);
1075 return alloc_ram_cell_init (BIGNUM_FIELD0, n >> 16, n >> 8, n);
1078 #endif
1080 /*---------------------------------------------------------------------------*/
1082 #ifdef WORKSTATION
1084 void show (obj o)
1086 #if 0
1087 printf ("[%d]", o);
1088 #endif
1090 if (o == OBJ_FALSE)
1091 printf ("#f");
1092 else if (o == OBJ_TRUE)
1093 printf ("#t");
1094 else if (o == OBJ_NULL)
1095 printf ("()");
1096 else if (o <= (MIN_FIXNUM_ENCODING + (MAX_FIXNUM - MIN_FIXNUM)))
1097 printf ("%d", DECODE_FIXNUM(o));
1098 else
1100 uint8 in_ram;
1102 if (IN_RAM(o))
1103 in_ram = 1;
1104 else
1105 in_ram = 0;
1107 if ((in_ram && RAM_BIGNUM(o)) || (!in_ram && ROM_BIGNUM(o))) // TODO FIX for new bignums
1108 printf ("%d", decode_int (o));
1109 else if ((in_ram && RAM_COMPOSITE(o)) || (!in_ram && ROM_COMPOSITE(o)))
1111 obj car;
1112 obj cdr;
1114 if ((in_ram && RAM_PAIR(o)) || (!in_ram && ROM_PAIR(o)))
1116 if (in_ram)
1118 car = ram_get_car (o);
1119 cdr = ram_get_cdr (o);
1121 else
1123 car = rom_get_car (o);
1124 cdr = rom_get_cdr (o);
1127 printf ("(");
1129 loop:
1131 show (car);
1133 if (cdr == OBJ_NULL)
1134 printf (")");
1135 else if ((IN_RAM(cdr) && RAM_PAIR(cdr))
1136 || (IN_ROM(cdr) && ROM_PAIR(cdr)))
1138 if (IN_RAM(cdr))
1140 car = ram_get_car (cdr);
1141 cdr = ram_get_cdr (cdr);
1143 else
1145 car = rom_get_car (cdr);
1146 cdr = rom_get_cdr (cdr);
1149 printf (" ");
1150 goto loop;
1152 else
1154 printf (" . ");
1155 show (cdr);
1156 printf (")");
1159 else if ((in_ram && RAM_SYMBOL(o)) || (!in_ram && ROM_SYMBOL(o)))
1160 printf ("#<symbol>");
1161 else if ((in_ram && RAM_STRING(o)) || (!in_ram && ROM_STRING(o)))
1162 printf ("#<string>");
1163 else if ((in_ram && RAM_VECTOR(o)) || (!in_ram && ROM_VECTOR(o)))
1164 printf ("#<vector %d>", o);
1165 else
1167 printf ("(");
1168 car = ram_get_car (o);
1169 cdr = ram_get_cdr (o);
1170 // ugly hack, takes advantage of the fact that pairs and
1171 // continuations have the same layout
1172 goto loop;
1175 else // closure
1177 obj env;
1178 rom_addr pc;
1180 if (IN_RAM(o))
1181 env = ram_get_cdr (o);
1182 else
1183 env = rom_get_cdr (o);
1185 if (IN_RAM(o))
1186 pc = ram_get_entry (o);
1187 else
1188 pc = rom_get_entry (o);
1190 printf ("{0x%04x ", pc);
1191 show (env);
1192 printf ("}");
1196 fflush (stdout);
1199 void show_state (rom_addr pc)
1201 printf("\n");
1202 printf ("pc=0x%04x bytecode=0x%02x env=", pc, rom_get (pc));
1203 show (env);
1204 printf (" cont=");
1205 show (cont);
1206 printf ("\n");
1207 fflush (stdout);
1210 void print (obj o)
1212 show (o);
1213 printf ("\n");
1214 fflush (stdout);
1217 #endif
1219 /*---------------------------------------------------------------------------*/
1221 /* Integer operations */
1223 // TODO FOOBIGNUMS big pasted and NOT CHECKED section here
1224 #ifdef INFINITE_PRECISION_BIGNUMS
1226 #define obj_eq(x,y) ((x) == (y))
1228 #define integer_hi_set(x,y) ram_set_car (x, y)
1229 // TODO FOOBIGNUMS won't work, I think, will erase next pointer (or set it only in part) ACTUALLY, this is probably supposed to change the pointer. changed field1, npw changes the whole car
1231 #define ZERO ENCODE_FIXNUM(0)
1232 #define NEG1 (ZERO-1)
1233 #define POS1 (ZERO+1)
1235 /* integer fixnum (uint8 n) // TODO this used to be a signed int, but broke everything. probably should be removed */
1236 /* { */
1237 /* return ENCODE_FIXNUM (n); */
1238 /* } */ // TODO if no ill effect is detected without this, remove it
1240 // TODO this integer type is a mess, it should be obj, for clarity
1241 integer make_integer (digit lo, integer hi) // TODO BAD, should use encode_int instead
1243 // TODO could this be fixed by a call to encode_int ?
1244 /* if(!hi && lo <= MAX_FIXNUM) // TODO dependent on the current fixnum range, which starts at 0, fix this */ // TODO would this even be useful ? don't the math routines already revert to fixnums if needed ? or norm does it ?
1245 /* return ENCODE_FIXNUM(lo); */
1246 // TODO won't work, and the bignum functions are unaware of fixnums
1247 return alloc_ram_cell_init (BIGNUM_FIELD0 | (hi >> 8), hi, lo >> 8, lo); // TODO hi should always be a 13-bit pointer, to avoid clobbering the bignum field
1250 integer integer_hi (integer x) // TODO should be used for decoding
1252 if (IN_RAM(x))
1253 return ram_get_car (x); // TODO was field1
1254 else if (IN_ROM(x))
1255 return rom_get_car (x); // TODO was field1
1256 else if (x < (MIN_FIXNUM_ENCODING - MIN_FIXNUM))
1257 return NEG1; /* negative fixnum */
1258 else
1259 return ZERO; /* nonnegative fixnum */
1262 digit integer_lo (integer x)
1264 if (IN_RAM(x))
1265 return (((digit)ram_get_field2 (x)) << 8) + ram_get_field3 (x);
1266 else if (IN_ROM(x))
1267 return (((digit)rom_get_field2 (x)) << 8) + rom_get_field3 (x);
1268 else
1269 return DECODE_FIXNUM(x);
1272 integer norm (obj prefix, integer n)
1274 /* norm(prefix,n) returns a normalized integer whose value is the
1275 integer n prefixed with the digits in prefix (a list of digits) */
1277 while (prefix != NIL)
1279 digit d = integer_lo (prefix);
1280 obj temp = prefix;
1282 prefix = integer_hi (temp);
1284 if (obj_eq (n, ZERO))
1286 if (d <= MAX_FIXNUM)
1288 n = ENCODE_FIXNUM ((uint8)d); // TODO is this cast needed at all ?
1289 continue; // TODO with cast to unsigned, will it work for negative numbers ? or is it only handled in the next branch ?
1292 else if (obj_eq (n, NEG1))
1294 if (d >= (1<<digit_width) + MIN_FIXNUM)
1296 n = ENCODE_FIXNUM (d - (1<<digit_width)); // TODO had a cast, origianlly to int8, changed to uint8 which didn't work (obviously, we use -1 here), is a cast necessary at all ?
1297 continue;
1301 integer_hi_set (temp, n);
1302 n = temp;
1305 return n;
1308 boolean negp (integer x)
1310 /* negp(x) returns true iff x is negative */
1314 x = integer_hi (x);
1315 if (obj_eq (x, ZERO)) return false;
1316 } while (!obj_eq (x, NEG1));
1318 return true;
1321 int8 cmp (integer x, integer y)
1323 /* cmp(x,y) return -1 when x<y, 1 when x>y, and 0 when x=y */
1325 int8 result = 0;
1326 digit xlo;
1327 digit ylo;
1329 for (;;)
1331 if (obj_eq (x, ZERO) || obj_eq (x, NEG1))
1333 if (!obj_eq (x, y))
1334 { if (negp (y)) result = 1; else result = -1; }
1335 break;
1338 if (obj_eq (y, ZERO) || obj_eq (y, NEG1))
1340 if (negp (x)) result = -1; else result = 1;
1341 break;
1344 xlo = integer_lo (x);
1345 ylo = integer_lo (y);
1346 x = integer_hi (x);
1347 y = integer_hi (y);
1348 if (xlo != ylo)
1349 { if (xlo < ylo) result = -1; else result = 1; }
1351 return result;
1354 uint16 integer_length (integer x)
1356 /* integer_length(x) returns the number of bits in the binary
1357 representation of the nonnegative integer x */
1359 uint16 result = 0;
1360 integer next;
1361 digit d;
1363 while (!obj_eq ((next = integer_hi (x)), ZERO)) // TODO what happens if it ends with -1 ?
1365 result += digit_width;
1366 x = next;
1369 d = integer_lo (x);
1371 while (d > 0)
1373 result++;
1374 d >>= 1;
1377 return result;
1380 integer shr (integer x)
1382 /* shr(x) returns the integer x shifted one bit to the right */
1384 obj result = NIL;
1385 digit d;
1387 for (;;)
1389 if (obj_eq (x, ZERO) || obj_eq (x, NEG1))
1391 result = norm (result, x);
1392 break;
1395 d = integer_lo (x);
1396 x = integer_hi (x);
1397 result = make_integer ((d >> 1) |
1398 ((integer_lo (x) & 1) ? (1<<(digit_width-1)) : 0),
1399 result);
1402 return result;
1405 integer negative_carry (integer carry)
1407 if (carry)
1408 return NEG1;
1409 else
1410 return ZERO;
1413 integer shl (integer x)
1415 /* shl(x) returns the integer x shifted one bit to the left */
1417 integer negc = ZERO; /* negative carry */
1418 integer temp;
1419 obj result = NIL;
1420 digit d;
1422 for (;;)
1424 if (obj_eq (x, negc))
1426 result = norm (result, x);
1427 break;
1430 d = integer_lo (x);
1431 x = integer_hi (x);
1432 temp = negc;
1433 negc = negative_carry (d & (1<<(digit_width-1))); // TODO right side is constant, and sixpic has no constant folding
1434 result = make_integer ((d << 1) | obj_eq (temp, NEG1), result);
1437 return result;
1440 integer shift_left (integer x, uint16 n) // TODO have the primitves been changed for this and right ?
1442 /* shift_left(x,n) returns the integer x shifted n bits to the left */
1444 if (obj_eq (x, ZERO))
1445 return x;
1447 while (n & (digit_width-1))
1449 x = shl (x);
1450 n--;
1453 while (n > 0)
1455 x = make_integer (0, x);
1456 n -= digit_width;
1459 return x;
1462 integer add (integer x, integer y)
1464 /* add(x,y) returns the sum of the integers x and y */
1466 integer negc = ZERO; /* negative carry */
1467 obj result = NIL; /* nil terminated for the norm function */
1468 digit dx;
1469 digit dy;
1471 for (;;)
1473 if (obj_eq (x, negc))
1475 result = norm (result, y);
1476 break;
1479 if (obj_eq (y, negc))
1481 result = norm (result, x);
1482 break;
1485 dx = integer_lo (x);
1486 dy = integer_lo (y);
1487 dx = dx + dy; /* may wrap around */
1489 if (obj_eq (negc, ZERO))
1490 negc = negative_carry (dx < dy);
1491 else
1493 dx++; /* may wrap around */
1494 negc = negative_carry (dx <= dy);
1497 x = integer_hi (x);
1498 y = integer_hi (y);
1500 result = make_integer (dx, result);
1503 return result;
1506 integer invert (integer x)
1508 if (obj_eq (x, ZERO))
1509 return NEG1;
1510 else
1511 return ZERO;
1514 integer sub (integer x, integer y)
1516 /* sub(x,y) returns the difference of the integers x and y */
1517 integer negc = NEG1; /* negative carry */
1518 obj result = NIL;
1519 digit dx;
1520 digit dy;
1522 for (;;)
1524 if (obj_eq (x, negc) && (obj_eq (y, ZERO) || obj_eq (y, NEG1)))
1526 result = norm (result, invert (y));
1527 break;
1530 if (obj_eq (y, invert (negc)))
1532 result = norm (result, x);
1533 break;
1536 dx = integer_lo (x);
1537 dy = ~integer_lo (y);
1538 dx = dx + dy; /* may wrap around */
1540 if (obj_eq (negc, ZERO))
1541 negc = negative_carry (dx < dy);
1542 else
1544 dx++; /* may wrap around */
1545 negc = negative_carry (dx <= dy);
1548 x = integer_hi (x);
1549 y = integer_hi (y);
1551 result = make_integer (dx, result);
1554 return result;
1557 integer neg (integer x)
1559 /* neg(x) returns the integer -x */
1561 return sub (ZERO, x);
1564 integer scale (digit n, integer x)
1566 /* scale(n,x) returns the integer n*x */
1568 obj result;
1569 digit carry;
1570 two_digit m;
1572 if ((n == 0) || obj_eq (x, ZERO))
1573 return ZERO;
1575 if (n == 1)
1576 return x;
1578 result = NIL;
1579 carry = 0;
1581 for (;;)
1583 if (obj_eq (x, ZERO))
1585 if (carry <= MAX_FIXNUM)
1586 result = norm (result, ENCODE_FIXNUM ((uint8)carry)); // TODO was fixnum, and int8 (signed)
1587 else
1588 result = norm (result, make_integer (carry, ZERO));
1589 break;
1592 if (obj_eq (x, NEG1))
1594 carry = carry - n;
1595 if (carry >= ((1<<digit_width) + MIN_FIXNUM))
1596 result = norm (result, ENCODE_FIXNUM ((uint8)carry)); // TODO was fixnum, and int8 (signed)
1597 else
1598 result = norm (result, make_integer (carry, NEG1));
1599 break;
1602 m = (two_digit)integer_lo (x) * n + carry;
1604 x = integer_hi (x);
1605 carry = m >> digit_width;
1606 result = make_integer ((digit)m, result);
1609 return result;
1612 integer mulnonneg (integer x, integer y)
1614 /* mulnonneg(x,y) returns the product of the integers x and y
1615 where x is nonnegative */
1617 obj result = NIL;
1618 integer s = scale (integer_lo (x), y);
1620 for (;;)
1622 result = make_integer (integer_lo (s), result);
1623 s = integer_hi (s);
1624 x = integer_hi (x);
1626 if (obj_eq (x, ZERO))
1627 break;
1629 s = add (s, scale (integer_lo (x), y));
1632 return norm (result, s);
1635 integer mul (integer x, integer y)
1637 /* mul(x,y) returns the product of the integers x and y */
1639 if (negp (x))
1640 return neg (mulnonneg (neg (x), y));
1641 else
1642 return mulnonneg (x, y);
1645 integer divnonneg (integer x, integer y)
1647 /* divnonneg(x,y) returns the quotient and remainder of
1648 the integers x and y where x and y are nonnegative */
1650 integer result = ZERO;
1651 uint16 lx = integer_length (x);
1652 uint16 ly = integer_length (y);
1654 if (lx >= ly)
1656 lx = lx - ly;
1658 y = shift_left (y, lx);
1662 result = shl (result);
1663 if (cmp (x, y) >= 0)
1665 x = sub (x, y);
1666 result = add (POS1, result);
1668 y = shr (y);
1669 } while (lx-- != 0);
1672 return result;
1675 #ifdef WORKSTATION
1676 void p (integer n)
1678 long long x; // TODO long long is 32 bits here, what about on a 64 bit machine ?
1679 x = ((long long)integer_lo (integer_hi (integer_hi (integer_hi (n))))<<48)+
1680 ((long long)integer_lo (integer_hi (integer_hi (n)))<<32)+
1681 ((long long)integer_lo (integer_hi (n))<<16)+
1682 (long long)integer_lo (n);
1683 printf ("%lld ", x);
1684 // TODO test for hex output, to avoid signedness problems
1685 /* printf("%x%x%x%x\n", // TODO prob, if a lower part is 0, will show 0, not 0000 */
1686 /* integer_lo (integer_hi (integer_hi (integer_hi (n)))), */
1687 /* integer_lo (integer_hi (integer_hi (n))), */
1688 /* integer_lo (integer_hi (n)), */
1689 /* integer_lo (n)); */
1692 integer enc (long long n) // TODO used only for debugging
1694 integer result = NIL;
1696 while (n != 0 && n != -1)
1698 result = make_integer ((digit)n, result);
1699 n >>= digit_width;
1702 if (n < 0)
1703 return norm (result, NEG1);
1704 else
1705 return norm (result, ZERO);
1708 void test (void) // TODO still in use ? no, but useful for tests
1710 integer min2;
1711 integer min1;
1712 integer zero;
1713 integer one;
1714 integer two;
1715 integer three;
1716 integer four;
1718 zero = make_integer (0x0000, 0);
1719 min1 = make_integer (0xffff, 0);
1720 integer_hi_set (zero, ZERO);
1721 integer_hi_set (min1, NEG1);
1723 min2 = make_integer (0xfffe, NEG1);
1724 one = make_integer (0x0001, ZERO);
1725 two = make_integer (0x0002, ZERO);
1726 three= make_integer (0x0003, ZERO);
1727 four = make_integer (0x0004, ZERO);
1729 if (negp (ZERO)) printf ("zero is negp\n"); // should not show
1730 if (negp (NEG1)) printf ("min1 is negp\n");
1732 printf ("cmp(5,5) = %d\n",cmp (make_integer (5, ZERO), make_integer (5, ZERO)));
1733 printf ("cmp(2,5) = %d\n",cmp (make_integer (2, ZERO), make_integer (5, ZERO)));
1734 printf ("cmp(5,2) = %d\n",cmp (make_integer (5, ZERO), make_integer (2, ZERO)));
1736 printf ("cmp(-5,-5) = %d\n",cmp (make_integer (-5, NEG1), make_integer (-5, NEG1)));
1737 printf ("cmp(-2,-5) = %d\n",cmp (make_integer (-2, NEG1), make_integer (-5, NEG1)));
1738 printf ("cmp(-5,-2) = %d\n",cmp (make_integer (-5, NEG1), make_integer (-2, NEG1)));
1740 printf ("cmp(-5,65533) = %d\n",cmp (make_integer (-5, NEG1), make_integer (65533, ZERO)));
1741 printf ("cmp(-5,2) = %d\n",cmp (make_integer (-5, NEG1), make_integer (2, ZERO)));
1742 printf ("cmp(5,-65533) = %d\n",cmp (make_integer (5, ZERO), make_integer (-65533, NEG1)));
1743 printf ("cmp(5,-2) = %d\n",cmp (make_integer (5, ZERO), make_integer (-2, NEG1)));
1745 printf ("integer_length(0) = %d\n", integer_length (ZERO)); // these return the number of bits necessary to encode
1746 printf ("integer_length(1) = %d\n", integer_length (make_integer (1, ZERO)));
1747 printf ("integer_length(2) = %d\n", integer_length (make_integer (2, ZERO)));
1748 printf ("integer_length(3) = %d\n", integer_length (make_integer (3, ZERO)));
1749 printf ("integer_length(4) = %d\n", integer_length (make_integer (4, ZERO)));
1750 printf ("integer_length(65536 + 4) = %d\n", integer_length (make_integer (4, make_integer (1, ZERO))));
1753 printf ("1 = %d\n", one); // TODO these show the address, useful ?
1754 printf ("2 = %d\n", two);
1755 printf ("4 = %d\n", four);
1756 printf ("norm(2) = %d\n", norm (make_integer (0, make_integer (2, NIL)), ZERO)); // TODO these show the fixnum address (6 and 7), so it seems to be working
1757 printf ("norm(2) = %d\n", norm (make_integer (0, make_integer (2, NIL)), ZERO));
1758 printf ("norm(3) = %d\n", norm (make_integer (0, make_integer (3, NIL)), ZERO));
1759 printf ("norm(3) = %d\n", norm (make_integer (0, make_integer (3, NIL)), ZERO));
1761 printf ("shl(1) = %d\n", shl (one)); // TODO fixnums, again
1762 printf ("shl(2) = %d\n", shl (two));
1765 integer n = one;
1766 int i;
1767 // should show powers of 2 incerasing, then decreasing
1768 for (i=1; i<=34; i++)
1770 printf("\nloop-1 : i=%d len=%d ", i, integer_length(n));
1771 p (n);
1772 n = shl(n);
1774 for (i=1; i<=35; i++)
1776 printf("\nloop-2 : i=%d len=%d ", i, integer_length(n));
1777 p (n);
1778 n = shr(n);
1783 integer n = shift_left (four, 5);
1784 int i;
1786 for (i=0; i<=14; i++)
1788 printf("\nloop-3 : i=%d len=%d ", i);
1789 p (shift_left (n, i*4));
1793 printf("\n");
1794 p (add (enc (32768), enc (32768))); printf("\n"); // 65536
1795 p (add (enc (32768+(65536*65535LL)), enc (32768))); printf("\n"); // 4294967296
1797 p (sub (enc (32768), enc (-32768))); printf("\n"); // 65536
1798 p (sub (enc (32768+(65536*65535LL)), enc (-32768))); printf("\n"); // 4294967296
1800 p (sub (enc (32768), enc (32769))); printf("\n"); // -1
1801 p (sub (enc (32768), enc (132768))); printf("\n"); // -100000
1802 p (add(sub (enc (32768), enc (32769)), enc(1000))); printf("\n"); // 999
1804 p (mul (enc (123456789), enc (1000000000))); printf("\n");
1805 p (mul (enc (123456789), enc (-1000000000))); printf("\n");
1806 p (mul (enc (-123456789), enc (1000000000))); printf("\n");
1807 p (mul (enc (-123456789), enc (-1000000000))); printf("\n");
1809 p (divnonneg (enc (10000000-1), enc (500000))); printf("\n");
1811 printf ("done\n");
1813 exit (0);
1815 #endif
1817 #endif
1820 void prim_numberp (void)
1822 if (arg1 >= MIN_FIXNUM_ENCODING
1823 && arg1 <= (MIN_FIXNUM_ENCODING + (MAX_FIXNUM - MIN_FIXNUM)))
1824 arg1 = OBJ_TRUE;
1825 else
1827 if (IN_RAM(arg1))
1828 arg1 = encode_bool (RAM_BIGNUM(arg1));
1829 else if (IN_ROM(arg1))
1830 arg1 = encode_bool (ROM_BIGNUM(arg1));
1831 else
1832 arg1 = OBJ_FALSE;
1836 void decode_2_int_args (void) // TODO fix for bignums ?
1838 a1 = decode_int (arg1); // TODO all math primitives call it, even for bignums, this is probably what causes problems, maybe not, since the primitives don't use a1 or a2, but rather arg1 and arg2
1839 a2 = decode_int (arg2);
1842 void prim_add (void)
1844 #ifdef INFINITE_PRECISION_BIGNUMS
1845 arg1 = add (arg1, arg2);
1846 #else
1847 decode_2_int_args ();
1848 arg1 = encode_int (a1 + a2);
1849 #endif
1850 arg2 = OBJ_FALSE;
1853 void prim_sub (void)
1855 #ifdef INFINITE_PRECISION_BIGNUMS
1856 arg1 = sub (arg1, arg2);
1857 #else
1858 decode_2_int_args ();
1859 arg1 = encode_int (a1 - a2);
1860 #endif
1861 arg2 = OBJ_FALSE;
1864 void prim_mul (void)
1866 #ifdef INFINITE_PRECISION_BIGNUMS
1867 arg1 = mul (arg1, arg2);
1868 #else
1869 decode_2_int_args ();
1870 arg1 = encode_int (a1 * a2);
1871 #endif
1872 arg2 = OBJ_FALSE;
1875 void prim_div (void)
1877 decode_2_int_args (); // TODO useless work in the case of bignums, move in the else, but make sure that an error message is written even with bignums
1878 if (a2 == 0)
1879 ERROR("quotient", "divide by 0");
1880 #ifdef INFINITE_PRECISION_BIGNUMS
1881 arg1 = ZERO;
1882 #else
1883 arg1 = encode_int (a1 / a2);
1884 #endif
1885 arg2 = OBJ_FALSE;
1888 void prim_rem (void)
1890 decode_2_int_args (); // TODO same as div
1891 if (a2 == 0)
1892 ERROR("remainder", "divide by 0");
1893 #ifdef INFINITE_PRECISION_BIGNUMS
1894 arg1 = ZERO;
1895 #else
1896 arg1 = encode_int (a1 % a2);
1897 #endif
1898 arg2 = OBJ_FALSE;
1901 void prim_neg (void)
1903 #ifdef INFINITE_PRECISION_BIGNUMS
1904 arg1 = neg (arg1);
1905 #else
1906 a1 = decode_int (arg1);
1907 arg1 = encode_int (- a1);
1908 #endif
1911 void prim_eq (void)
1913 #ifdef INFINITE_PRECISION_BIGNUMS
1914 arg1 = encode_bool(cmp (arg1, arg2) == 0);
1915 #else
1916 decode_2_int_args ();
1917 arg1 = encode_bool(a1 == a2);
1918 #endif
1919 arg2 = OBJ_FALSE;
1922 void prim_lt (void)
1924 #ifdef INFINITE_PRECISION_BIGNUMS
1925 arg1 = encode_bool(cmp (arg1, arg2) < 0);
1926 #else
1927 decode_2_int_args ();
1928 arg1 = encode_bool(a1 < a2);
1929 #endif
1930 arg2 = OBJ_FALSE;
1933 void prim_gt (void)
1935 #ifdef INFINITE_PRECISION_BIGNUMS
1936 arg1 = encode_bool(cmp (arg1, arg2) > 0);
1937 #else
1938 decode_2_int_args ();
1939 arg1 = encode_bool(a1 > a2);
1940 #endif
1941 arg2 = OBJ_FALSE;
1944 void prim_ior (void) // TODO FOOBIGNUMS these have not been implemented with bignums, do it
1946 decode_2_int_args (); // TODO is the function call overhead worth it ?
1947 arg1 = encode_int (a1 | a2);
1948 arg2 = OBJ_FALSE;
1951 void prim_xor (void)
1953 decode_2_int_args (); // TODO is the function call overhead worth it ?
1954 arg1 = encode_int (a1 ^ a2);
1955 arg2 = OBJ_FALSE;
1959 /*---------------------------------------------------------------------------*/
1961 /* List operations */
1963 void prim_pairp (void)
1965 if (IN_RAM(arg1))
1966 arg1 = encode_bool (RAM_PAIR(arg1));
1967 else if (IN_ROM(arg1))
1968 arg1 = encode_bool (ROM_PAIR(arg1));
1969 else
1970 arg1 = OBJ_FALSE;
1973 obj cons (obj car, obj cdr)
1975 return alloc_ram_cell_init (COMPOSITE_FIELD0 | (car >> 8),
1976 car & 0xff,
1977 PAIR_FIELD2 | (cdr >> 8),
1978 cdr & 0xff);
1981 void prim_cons (void)
1983 arg1 = cons (arg1, arg2);
1984 arg2 = OBJ_FALSE;
1987 void prim_car (void)
1989 if (IN_RAM(arg1))
1991 if (!RAM_PAIR(arg1))
1992 TYPE_ERROR("car.0", "pair");
1993 arg1 = ram_get_car (arg1);
1995 else if (IN_ROM(arg1))
1997 if (!ROM_PAIR(arg1))
1998 TYPE_ERROR("car.1", "pair");
1999 arg1 = rom_get_car (arg1);
2001 else
2003 TYPE_ERROR("car.2", "pair");
2007 void prim_cdr (void)
2009 if (IN_RAM(arg1))
2011 if (!RAM_PAIR(arg1))
2012 TYPE_ERROR("cdr.0", "pair");
2013 arg1 = ram_get_cdr (arg1);
2015 else if (IN_ROM(arg1))
2017 if (!ROM_PAIR(arg1))
2018 TYPE_ERROR("cdr.1", "pair");
2019 arg1 = rom_get_cdr (arg1);
2021 else
2023 TYPE_ERROR("cdr.2", "pair");
2027 void prim_set_car (void)
2029 if (IN_RAM(arg1))
2031 if (!RAM_PAIR(arg1))
2032 TYPE_ERROR("set-car!.0", "pair");
2034 ram_set_car (arg1, arg2);
2035 arg1 = OBJ_FALSE;
2036 arg2 = OBJ_FALSE;
2038 else
2040 TYPE_ERROR("set-car!.1", "pair");
2044 void prim_set_cdr (void)
2046 if (IN_RAM(arg1))
2048 if (!RAM_PAIR(arg1))
2049 TYPE_ERROR("set-cdr!.0", "pair");
2051 ram_set_cdr (arg1, arg2);
2052 arg1 = OBJ_FALSE;
2053 arg2 = OBJ_FALSE;
2055 else
2057 TYPE_ERROR("set-cdr!.1", "pair");
2061 void prim_nullp (void)
2063 arg1 = encode_bool (arg1 == OBJ_NULL);
2066 /*---------------------------------------------------------------------------*/
2068 /* Vector operations */
2070 void prim_u8vectorp (void)
2072 if (IN_RAM(arg1))
2073 arg1 = encode_bool (RAM_VECTOR(arg1));
2074 else if (IN_ROM(arg1))
2075 arg1 = encode_bool (ROM_VECTOR(arg1));
2076 else
2077 arg1 = OBJ_FALSE;
2080 void prim_make_u8vector (void)
2082 decode_2_int_args (); // arg1 is length, arg2 is contents
2083 // TODO adapt for the new bignums
2084 if (a2 > 255)
2085 ERROR("make-u8vector", "byte vectors can only contain bytes");
2087 arg3 = alloc_vec_cell (a1);
2088 arg1 = alloc_ram_cell_init (COMPOSITE_FIELD0 | (a1 >> 8),
2089 a1 & 0xff,
2090 VECTOR_FIELD2 | (arg3 >> 8),
2091 arg3 & 0xff);
2093 a1 = (a1 + 3) / 4; // actual length, in words
2094 while (a1--)
2096 ram_set_field0 (arg3, a2);
2097 ram_set_field1 (arg3, a2);
2098 ram_set_field2 (arg3, a2);
2099 ram_set_field3 (arg3, a2);
2100 arg3++;
2104 void prim_u8vector_ref (void)
2106 a2 = decode_int (arg2);
2107 // TODO adapt for the new bignums
2108 if (IN_RAM(arg1))
2110 if (!RAM_VECTOR(arg1))
2111 TYPE_ERROR("u8vector-ref.0", "vector");
2112 if ((ram_get_car (arg1) <= a2) || (a2 < 0))
2113 ERROR("u8vector-ref.0", "vector index invalid");
2114 arg1 = ram_get_cdr (arg1);
2116 else if (IN_ROM(arg1))
2118 if (!ROM_VECTOR(arg1))
2119 TYPE_ERROR("u8vector-ref.1", "vector");
2120 if ((rom_get_car (arg1) <= a2) || (a2 < 0))
2121 ERROR("u8vector-ref.1", "vector index invalid");
2122 arg1 = rom_get_cdr (arg1);
2124 else
2125 TYPE_ERROR("u8vector-ref.2", "vector");
2127 if (IN_VEC(arg1))
2129 arg1 += (a2 / 4);
2130 a2 %= 4;
2132 arg1 = encode_int (ram_get_fieldn (arg1, a2));
2134 else // rom vector, stored as a list
2136 while (a2--)
2137 arg1 = rom_get_cdr (arg1);
2139 // the contents are already encoded as fixnums
2140 arg1 = rom_get_car (arg1);
2143 arg2 = OBJ_FALSE;
2144 arg3 = OBJ_FALSE;
2145 arg4 = OBJ_FALSE;
2148 void prim_u8vector_set (void)
2149 { // TODO a lot in common with ref, abstract that
2150 a2 = decode_int (arg2); // TODO adapt for bignums
2151 a3 = decode_int (arg3);
2153 if (a3 > 255)
2154 ERROR("u8vector-set!", "byte vectors can only contain bytes");
2156 if (IN_RAM(arg1))
2158 if (!RAM_VECTOR(arg1))
2159 TYPE_ERROR("u8vector-set!.0", "vector");
2160 if ((ram_get_car (arg1) <= a2) || (a2 < 0))
2161 ERROR("u8vector-set!", "vector index invalid");
2162 arg1 = ram_get_cdr (arg1);
2164 else
2165 TYPE_ERROR("u8vector-set!.1", "vector");
2167 arg1 += (a2 / 4);
2168 a2 %= 4;
2170 ram_set_fieldn (arg1, a2, a3);
2172 arg1 = OBJ_FALSE;
2173 arg2 = OBJ_FALSE;
2174 arg3 = OBJ_FALSE;
2177 void prim_u8vector_length (void)
2179 if (IN_RAM(arg1))
2181 if (!RAM_VECTOR(arg1))
2182 TYPE_ERROR("u8vector-length.0", "vector");
2183 arg1 = encode_int (ram_get_car (arg1));
2185 else if (IN_ROM(arg1))
2187 if (!ROM_VECTOR(arg1))
2188 TYPE_ERROR("u8vector-length.1", "vector");
2189 arg1 = encode_int (rom_get_car (arg1));
2191 else
2192 TYPE_ERROR("u8vector-length.2", "vector");
2195 void prim_u8vector_copy (void)
2197 // arg1 is source, arg2 is source-start, arg3 is target, arg4 is target-start
2198 // arg5 is number of bytes to copy
2200 a1 = decode_int (arg2); // TODO adapt for bignums
2201 a2 = decode_int (arg4);
2202 a3 = decode_int (arg5);
2204 // case 1 : ram to ram
2205 if (IN_RAM(arg1) && IN_RAM(arg3))
2207 if (!RAM_VECTOR(arg1) || !RAM_VECTOR(arg3))
2208 TYPE_ERROR("u8vector-copy!.0", "vector");
2209 if ((ram_get_car (arg1) < (a1 + a3)) || (a1 < 0) ||
2210 (ram_get_car (arg3) < (a2 + a3)) || (a2 < 0))
2211 ERROR("u8vector-copy!.0", "vector index invalid");
2213 // position to the start
2214 arg1 = ram_get_cdr (arg1);
2215 arg1 += (a1 / 4);
2216 a1 %= 4;
2217 arg3 = ram_get_cdr (arg3);
2218 arg3 += (a2 / 4);
2219 a2 %= 4;
2221 // copy
2222 while (a3--)
2224 ram_set_fieldn (arg3, a2, ram_get_fieldn (arg1, a1));
2226 a1++;
2227 arg1 += (a1 / 4);
2228 a1 %= 4; // TODO merge with the previous similar block ?
2229 a2++;
2230 arg3 += (a2 / 4);
2231 a2 %= 4;
2234 // case 2 : rom to ram
2235 else if (IN_ROM(arg1) && IN_RAM(arg3))
2237 if (!ROM_VECTOR(arg1) || !RAM_VECTOR(arg3))
2238 TYPE_ERROR("u8vector-copy!.1", "vector");
2239 if ((rom_get_car (arg1) < (a1 + a3)) || (a1 < 0) ||
2240 (ram_get_car (arg3) < (a2 + a3)) || (a2 < 0))
2241 ERROR("u8vector-copy!.1", "vector index invalid");
2243 arg1 = rom_get_cdr (arg1);
2244 while (a1--)
2245 arg1 = rom_get_cdr (arg1);
2247 arg3 = ram_get_cdr (arg3);
2248 arg3 += (a2 / 4);
2249 a2 %= 4;
2251 while (a3--)
2253 ram_set_fieldn (arg3, a2, decode_int (rom_get_car (arg1)));
2255 arg1 = rom_get_cdr (arg1);
2256 a2++;
2257 arg3 += (a2 / 4);
2258 a2 %= 4; // TODO very similar to the other case
2261 else
2262 TYPE_ERROR("u8vector-copy!.2", "vector");
2264 arg1 = OBJ_FALSE;
2265 arg2 = OBJ_FALSE;
2266 arg3 = OBJ_FALSE;
2267 arg4 = OBJ_FALSE;
2268 arg5 = OBJ_FALSE;
2271 /*---------------------------------------------------------------------------*/
2273 /* Miscellaneous operations */
2275 void prim_eqp (void)
2277 arg1 = encode_bool (arg1 == arg2);
2278 arg2 = OBJ_FALSE;
2281 void prim_not (void)
2283 arg1 = encode_bool (arg1 == OBJ_FALSE);
2286 void prim_symbolp (void)
2288 if (IN_RAM(arg1))
2289 arg1 = encode_bool (RAM_SYMBOL(arg1));
2290 else if (IN_ROM(arg1))
2291 arg1 = encode_bool (ROM_SYMBOL(arg1));
2292 else
2293 arg1 = OBJ_FALSE;
2296 void prim_stringp (void)
2298 if (IN_RAM(arg1))
2299 arg1 = encode_bool (RAM_STRING(arg1));
2300 else if (IN_ROM(arg1))
2301 arg1 = encode_bool (ROM_STRING(arg1));
2302 else
2303 arg1 = OBJ_FALSE;
2306 void prim_string2list (void)
2308 if (IN_RAM(arg1))
2310 if (!RAM_STRING(arg1))
2311 TYPE_ERROR("string->list.0", "string");
2313 arg1 = ram_get_car (arg1);
2315 else if (IN_ROM(arg1))
2317 if (!ROM_STRING(arg1))
2318 TYPE_ERROR("string->list.1", "string");
2320 arg1 = rom_get_car (arg1);
2322 else
2323 TYPE_ERROR("string->list.2", "string");
2326 void prim_list2string (void)
2328 arg1 = alloc_ram_cell_init (COMPOSITE_FIELD0 | ((arg1 & 0x1f00) >> 8),
2329 arg1 & 0xff,
2330 STRING_FIELD2,
2334 void prim_booleanp (void)
2336 arg1 = encode_bool (arg1 < 2);
2340 /*---------------------------------------------------------------------------*/
2342 /* Robot specific operations */
2345 void prim_print (void)
2347 #ifdef PICOBOARD2
2348 #endif
2350 #ifdef WORKSTATION
2352 print (arg1);
2354 #endif
2356 arg1 = OBJ_FALSE;
2360 int32 read_clock (void)
2362 int32 now = 0;
2364 #ifdef PICOBOARD2
2366 now = from_now( 0 );
2368 #endif
2370 #ifdef WORKSTATION
2372 #ifdef _WIN32
2374 static int32 start = 0;
2375 struct timeb tb;
2377 ftime (&tb);
2379 now = tb.time * 1000 + tb.millitm;
2380 if (start == 0)
2381 start = now;
2382 now -= start;
2384 #else
2386 static int32 start = 0;
2387 struct timeval tv;
2389 if (gettimeofday (&tv, NULL) == 0)
2391 now = tv.tv_sec * 1000 + tv.tv_usec / 1000;
2392 if (start == 0)
2393 start = now;
2394 now -= start;
2397 #endif
2399 #endif
2401 return now;
2405 void prim_clock (void)
2407 arg1 = encode_int (read_clock ());
2411 void prim_motor (void)
2413 decode_2_int_args (); // TODO fix for bignums
2415 if (a1 < 1 || a1 > 2 || a2 < -100 || a2 > 100)
2416 ERROR("motor", "argument out of range");
2418 #ifdef PICOBOARD2
2420 MOTOR_set( a1, a2 );
2422 #endif
2424 #ifdef WORKSTATION
2426 printf ("motor %d -> power=%d\n", a1, a2);
2427 fflush (stdout);
2429 #endif
2431 arg1 = OBJ_FALSE;
2432 arg2 = OBJ_FALSE;
2436 void prim_led (void)
2438 decode_2_int_args (); // TODO fix for bignums
2439 a3 = decode_int (arg3);
2441 if (a1 < 1 || a1 > 3 || a2 < 0 || a3 < 0)
2442 ERROR("led", "argument out of range");
2444 #ifdef PICOBOARD2
2446 LED_set( a1, a2, a3 );
2448 #endif
2450 #ifdef WORKSTATION
2452 printf ("led %d -> duty=%d period=%d\n", a1, a2, a3 );
2453 fflush (stdout);
2455 #endif
2457 arg1 = OBJ_FALSE;
2458 arg2 = OBJ_FALSE;
2459 arg3 = OBJ_FALSE;
2463 void prim_led2_color (void)
2465 a1 = decode_int (arg1); // TODO fix for bignums
2467 if (a1 < 0 || a1 > 1)
2468 ERROR("led2-colors", "argument out of range");
2470 #ifdef PICOBOARD2
2472 LED2_color_set( a1 );
2474 #endif
2476 #ifdef WORKSTATION
2478 printf ("led2-color -> %s\n", (a1==0)?"green":"red");
2479 fflush (stdout);
2481 #endif
2483 arg1 = OBJ_FALSE;
2487 void prim_getchar_wait (void)
2489 decode_2_int_args(); // TODO fix for bignums
2490 a1 = read_clock () + a1;
2492 if (a1 < 0 || a2 < 1 || a2 > 3)
2493 ERROR("getchar-wait", "argument out of range");
2495 #ifdef PICOBOARD2
2497 arg1 = OBJ_FALSE;
2500 serial_port_set ports;
2501 ports = serial_rx_wait_with_timeout( a2, a1 );
2502 if (ports != 0)
2503 arg1 = encode_int (serial_rx_read( ports ));
2506 #endif
2508 #ifdef WORKSTATION
2510 #ifdef _WIN32
2512 arg1 = OBJ_FALSE;
2516 if (_kbhit ())
2518 arg1 = encode_int (_getch ());
2519 break;
2521 } while (read_clock () < a1);
2524 #else
2526 arg1 = encode_int (getchar ());
2528 #endif
2530 #endif
2534 void prim_putchar (void)
2536 decode_2_int_args ();
2538 if (a1 < 0 || a1 > 255 || a2 < 1 || a2 > 3)
2539 ERROR("putchar", "argument out of range");
2541 #ifdef PICOBOARD2
2543 serial_tx_write( a2, a1 );
2545 #endif
2547 #ifdef WORKSTATION
2549 putchar (a1);
2550 fflush (stdout);
2552 #endif
2554 arg1 = OBJ_FALSE;
2555 arg2 = OBJ_FALSE;
2559 void prim_beep (void)
2561 decode_2_int_args (); // TODO fix for bignums
2563 if (a1 < 1 || a1 > 255 || a2 < 0)
2564 ERROR("beep", "argument out of range");
2566 #ifdef PICOBOARD2
2568 beep( a1, from_now( a2 ) );
2570 #endif
2572 #ifdef WORKSTATION
2574 printf ("beep -> freq-div=%d duration=%d\n", a1, a2 );
2575 fflush (stdout);
2577 #endif
2579 arg1 = OBJ_FALSE;
2580 arg2 = OBJ_FALSE;
2584 void prim_adc (void)
2586 short x;
2588 a1 = decode_int (arg1); // TODO fix for bignums
2590 if (a1 < 1 || a1 > 3)
2591 ERROR("adc", "argument out of range");
2593 #ifdef PICOBOARD2
2595 x = adc( a1 );
2597 #endif
2599 #ifdef WORKSTATION
2601 x = read_clock () & 255;
2603 if (x > 127) x = 256 - x;
2605 x += 200;
2607 #endif
2609 arg1 = encode_int (x);
2613 void prim_dac (void) // TODO not used
2615 a1 = decode_int (arg1); // TODO fix for bignums
2617 if (a1 < 0 || a1 > 255)
2618 ERROR("dac", "argument out of range");
2620 #ifdef PICOBOARD2
2622 dac( a1 );
2624 #endif
2626 #ifdef WORKSTATION
2628 printf ("dac -> %d\n", a1 );
2629 fflush (stdout);
2631 #endif
2633 arg1 = OBJ_FALSE;
2637 void prim_sernum (void)
2639 short x;
2641 #ifdef PICOBOARD2
2643 x = serial_num ();
2645 #endif
2647 #ifdef WORKSTATION
2649 x = 0;
2651 #endif
2653 arg1 = encode_int (x);
2657 /*---------------------------------------------------------------------------*/
2658 // networking, currently works only on workstations
2660 #ifdef WORKSTATION
2662 void prim_network_init (void)
2663 { // TODO maybe put in the initialization of the vm
2664 handle= pcap_open_live(INTERFACE, MAX_PACKET_SIZE, PROMISC, TO_MSEC, errbuf);
2665 if (handle == NULL)
2666 ERROR("network-init", "interface not responding");
2669 void prim_network_cleanup (void)
2670 { // TODO maybe put in halt ?
2671 pcap_close(handle);
2674 void prim_receive_packet_to_u8vector (void)
2676 // arg1 is the vector in which to put the received packet
2677 if (!RAM_VECTOR(arg1))
2678 TYPE_ERROR("receive-packet-to-u8vector", "vector");
2680 // receive the packet in the buffer
2681 struct pcap_pkthdr header;
2682 const u_char *packet;
2684 packet = pcap_next(handle, &header);
2686 if (packet == NULL)
2687 header.len = 0;
2689 if (ram_get_car (arg1) < header.len)
2690 ERROR("receive-packet-to-u8vector", "packet longer than vector");
2692 if (header.len > 0) // we have received a packet, write it in the vector
2694 arg2 = rom_get_cdr (arg1);
2695 arg1 = header.len; // we return the length of the received packet
2696 a1 = 0;
2698 while (a1 < arg1)
2700 ram_set_fieldn (arg2, a1 % 4, (char)packet[a1]);
2701 a1++;
2702 arg2 += (a1 % 4) ? 0 : 1;
2705 arg2 = OBJ_FALSE;
2707 else // no packet to be read
2708 arg1 = OBJ_FALSE;
2711 void prim_send_packet_from_u8vector (void)
2713 // arg1 is the vector which contains the packet to be sent
2714 // arg2 is the length of the packet
2715 // TODO only works with ram vectors for now
2716 if (!RAM_VECTOR(arg1))
2717 TYPE_ERROR("send-packet-from-vector!", "vector");
2718 a2 = decode_int (arg2); // TODO fix for bignums
2719 a1 = 0;
2721 // TODO test if the length of the packet is longer than the length of the vector
2722 if (ram_get_car (arg1) < a2)
2723 ERROR("send-packet-from-u8vector", "packet cannot be longer than vector");
2725 arg1 = ram_get_cdr (arg1);
2727 // copy the packet to the output buffer
2728 while (a1 < a2)
2729 buf[a1] = ram_get_fieldn (arg1, a1 % 4);
2730 // TODO maybe I could just give pcap the pointer to the memory BREGG
2732 if (pcap_sendpacket(handle, buf, a2) < 0) // TODO an error has occurred, can we reuse the interface ?
2733 arg1 = OBJ_FALSE;
2734 else
2735 arg1 = OBJ_TRUE;
2737 arg2 = OBJ_FALSE;
2740 #endif
2742 /*---------------------------------------------------------------------------*/
2744 #ifdef WORKSTATION
2746 int hidden_fgetc (FILE *f)
2748 int c = fgetc (f);
2749 #if 0
2750 printf ("{%d}",c);
2751 fflush (stdout);
2752 #endif
2753 return c;
2756 #define fgetc(f) hidden_fgetc(f)
2758 void write_hex_nibble (int n)
2760 putchar ("0123456789ABCDEF"[n]);
2763 void write_hex (uint8 n)
2765 write_hex_nibble (n >> 4);
2766 write_hex_nibble (n & 0x0f);
2769 int hex (int c)
2771 if (c >= '0' && c <= '9')
2772 return (c - '0');
2774 if (c >= 'A' && c <= 'F')
2775 return (c - 'A' + 10);
2777 if (c >= 'a' && c <= 'f')
2778 return (c - 'a' + 10);
2780 return -1;
2783 int read_hex_byte (FILE *f)
2785 int h1 = hex (fgetc (f));
2786 int h2 = hex (fgetc (f));
2788 if (h1 >= 0 && h2 >= 0)
2789 return (h1<<4) + h2;
2791 return -1;
2794 int read_hex_file (char *filename)
2796 int c;
2797 FILE *f = fopen (filename, "r");
2798 int result = 0;
2799 int len;
2800 int a, a1, a2;
2801 int t;
2802 int b;
2803 int i;
2804 uint8 sum;
2805 int hi16 = 0;
2807 for (i=0; i<ROM_BYTES; i++)
2808 rom_mem[i] = 0xff;
2810 if (f != NULL)
2812 while ((c = fgetc (f)) != EOF)
2814 if ((c == '\r') || (c == '\n'))
2815 continue;
2817 if (c != ':' ||
2818 (len = read_hex_byte (f)) < 0 ||
2819 (a1 = read_hex_byte (f)) < 0 ||
2820 (a2 = read_hex_byte (f)) < 0 ||
2821 (t = read_hex_byte (f)) < 0)
2822 break;
2824 a = (a1 << 8) + a2;
2826 i = 0;
2827 sum = len + a1 + a2 + t;
2829 if (t == 0)
2831 next0:
2833 if (i < len)
2835 unsigned long adr = ((unsigned long)hi16 << 16) + a - CODE_START;
2837 if ((b = read_hex_byte (f)) < 0)
2838 break;
2840 if (adr >= 0 && adr < ROM_BYTES)
2841 rom_mem[adr] = b;
2843 a = (a + 1) & 0xffff;
2844 i++;
2845 sum += b;
2847 goto next0;
2850 else if (t == 1)
2852 if (len != 0)
2853 break;
2855 else if (t == 4)
2857 if (len != 2)
2858 break;
2860 if ((a1 = read_hex_byte (f)) < 0 ||
2861 (a2 = read_hex_byte (f)) < 0)
2862 break;
2864 sum += a1 + a2;
2866 hi16 = (a1<<8) + a2;
2868 else
2869 break;
2871 if ((b = read_hex_byte (f)) < 0)
2872 break;
2874 sum = -sum;
2876 if (sum != b)
2878 printf ("*** HEX file checksum error (expected 0x%02x)\n", sum);
2879 break;
2882 c = fgetc (f);
2884 if ((c != '\r') && (c != '\n'))
2885 break;
2887 if (t == 1)
2889 result = 1;
2890 break;
2894 if (result == 0)
2895 printf ("*** HEX file syntax error\n");
2897 fclose (f);
2900 return result;
2903 #endif
2905 /*---------------------------------------------------------------------------*/
2907 #define FETCH_NEXT_BYTECODE() bytecode = rom_get (pc++)
2909 #define BEGIN_DISPATCH() \
2910 dispatch: \
2911 IF_TRACE(show_state (pc)); \
2912 FETCH_NEXT_BYTECODE(); \
2913 bytecode_hi4 = bytecode & 0xf0; \
2914 bytecode_lo4 = bytecode & 0x0f; \
2915 switch (bytecode_hi4 >> 4) {
2917 #define END_DISPATCH() }
2919 #define CASE(opcode) case (opcode>>4):;
2921 #define DISPATCH(); goto dispatch;
2923 #if 0
2924 #define pc FSR1
2925 #define sp FSR2
2926 #define bytecode TABLAT
2927 #define bytecode_hi4 WREG
2928 #endif
2930 #define PUSH_CONSTANT1 0x00
2931 #define PUSH_CONSTANT2 0x10
2932 #define PUSH_STACK1 0x20
2933 #define PUSH_STACK2 0x30
2934 #define PUSH_GLOBAL 0x40
2935 #define SET_GLOBAL 0x50
2936 #define CALL 0x60
2937 #define JUMP 0x70
2938 #define LABEL_INSTR 0x80
2939 #define PUSH_CONSTANT_LONG 0x90
2941 #define FREE1 0xa0
2942 #define FREE2 0xb0
2944 #define PRIM1 0xc0
2945 #define PRIM2 0xd0
2946 #define PRIM3 0xe0
2947 #define PRIM4 0xf0
2949 #ifdef WORKSTATION
2951 char *prim_name[64] =
2953 "prim #%number?",
2954 "prim #%+",
2955 "prim #%-",
2956 "prim #%*",
2957 "prim #%quotient",
2958 "prim #%remainder",
2959 "prim #%neg",
2960 "prim #%=",
2961 "prim #%<",
2962 "prim #%ior",
2963 "prim #%>",
2964 "prim #%xor",
2965 "prim #%pair?",
2966 "prim #%cons",
2967 "prim #%car",
2968 "prim #%cdr",
2969 "prim #%set-car!",
2970 "prim #%set-cdr!",
2971 "prim #%null?",
2972 "prim #%eq?",
2973 "prim #%not",
2974 "prim #%get-cont",
2975 "prim #%graft-to-cont",
2976 "prim #%return-to-cont",
2977 "prim #%halt",
2978 "prim #%symbol?",
2979 "prim #%string?",
2980 "prim #%string->list",
2981 "prim #%list->string",
2982 "prim #%make-u8vector",
2983 "prim #%u8vector-ref",
2984 "prim #%u8vector-set!",
2985 "prim #%print",
2986 "prim #%clock",
2987 "prim #%motor",
2988 "prim #%led",
2989 "prim #%led2-color",
2990 "prim #%getchar-wait",
2991 "prim #%putchar",
2992 "prim #%beep",
2993 "prim #%adc",
2994 "prim #%u8vector?",
2995 "prim #%sernum",
2996 "prim #%u8vector-length",
2997 "prim #%u8vector-copy!",
2998 "shift",
2999 "pop",
3000 "return",
3001 "prim #%boolean?",
3002 "prim #%network-init",
3003 "prim #%network-cleanup",
3004 "prim #%receive-packet-to-u8vector",
3005 "prim #%send-packet-from-u8vector",
3006 "prim 53",
3007 "prim 54",
3008 "prim 55",
3009 "prim 56",
3010 "prim 57",
3011 "prim 58",
3012 "prim 59",
3013 "prim 60",
3014 "prim 61",
3015 "prim 62",
3016 "prim 63"
3019 #endif
3021 #define PUSH_ARG1() push_arg1 ()
3022 #define POP() pop()
3024 void push_arg1 (void)
3026 env = cons (arg1, env);
3027 arg1 = OBJ_FALSE;
3030 obj pop (void)
3032 obj o = ram_get_car (env);
3033 env = ram_get_cdr (env);
3034 return o;
3037 void pop_procedure (void)
3039 arg1 = POP();
3041 if (IN_RAM(arg1))
3043 if (!RAM_CLOSURE(arg1))
3044 TYPE_ERROR("pop_procedure.0", "procedure");
3046 entry = ram_get_entry (arg1) + CODE_START;
3048 else if (IN_ROM(arg1))
3050 if (!ROM_CLOSURE(arg1))
3051 TYPE_ERROR("pop_procedure.1", "procedure");
3053 entry = rom_get_entry (arg1) + CODE_START;
3055 else
3056 TYPE_ERROR("pop_procedure.2", "procedure");
3059 void handle_arity_and_rest_param (void)
3061 uint8 np;
3063 np = rom_get (entry++);
3065 if ((np & 0x80) == 0)
3067 if (na != np)
3068 ERROR("handle_arity_and_rest_param.0", "wrong number of arguments");
3070 else
3072 np = ~np;
3074 if (na < np)
3075 ERROR("handle_arity_and_rest_param.1", "wrong number of arguments");
3077 arg3 = OBJ_NULL;
3079 while (na > np)
3081 arg4 = POP();
3083 arg3 = cons (arg4, arg3);
3084 arg4 = OBJ_FALSE;
3086 na--;
3089 arg1 = cons (arg3, arg1);
3090 arg3 = OBJ_FALSE;
3094 void build_env (void)
3096 while (na != 0)
3098 arg3 = POP();
3100 arg1 = cons (arg3, arg1);
3102 na--;
3105 arg3 = OBJ_FALSE;
3108 void save_cont (void)
3110 // the second half is a closure
3111 arg3 = alloc_ram_cell_init (CLOSURE_FIELD0 | (pc >> 11),
3112 (pc >> 3) & 0xff,
3113 ((pc & 0x0007) << 5) | (env >> 8),
3114 env & 0xff);
3115 cont = alloc_ram_cell_init (COMPOSITE_FIELD0 | (cont >> 8),
3116 cont & 0xff,
3117 CONTINUATION_FIELD2 | (arg3 >> 8),
3118 arg3 & 0xff);
3119 arg3 = OBJ_FALSE;
3122 void interpreter (void)
3124 pc = (CODE_START + 4) + ((rom_addr)rom_get (CODE_START+2) << 2);
3126 glovars = rom_get (CODE_START+3); // number of global variables
3128 init_ram_heap ();
3130 BEGIN_DISPATCH();
3132 /***************************************************************************/
3133 CASE(PUSH_CONSTANT1);
3135 IF_TRACE(printf(" (push-constant "); show (bytecode_lo4); printf (")\n"));
3137 arg1 = bytecode_lo4;
3139 PUSH_ARG1();
3141 DISPATCH();
3143 /***************************************************************************/
3144 CASE(PUSH_CONSTANT2);
3146 IF_TRACE(printf(" (push-constant "); show (bytecode_lo4+16); printf (")\n"));
3147 arg1 = bytecode_lo4+16;
3149 PUSH_ARG1();
3151 DISPATCH();
3153 /***************************************************************************/
3154 CASE(PUSH_STACK1);
3156 IF_TRACE(printf(" (push-stack %d)\n", bytecode_lo4));
3158 arg1 = env;
3160 while (bytecode_lo4 != 0)
3162 arg1 = ram_get_cdr (arg1);
3163 bytecode_lo4--;
3166 arg1 = ram_get_car (arg1);
3168 PUSH_ARG1();
3170 DISPATCH();
3172 /***************************************************************************/
3173 CASE(PUSH_STACK2);
3175 IF_TRACE(printf(" (push-stack %d)\n", bytecode_lo4+16));
3177 bytecode_lo4 += 16;
3179 arg1 = env;
3181 while (bytecode_lo4 != 0)
3183 arg1 = ram_get_cdr (arg1);
3184 bytecode_lo4--;
3187 arg1 = ram_get_car (arg1);
3189 PUSH_ARG1();
3191 DISPATCH();
3193 /***************************************************************************/
3194 CASE(PUSH_GLOBAL);
3196 IF_TRACE(printf(" (push-global %d)\n", bytecode_lo4));
3198 arg1 = get_global (bytecode_lo4);
3200 PUSH_ARG1();
3202 DISPATCH();
3204 /***************************************************************************/
3205 CASE(SET_GLOBAL);
3207 IF_TRACE(printf(" (set-global %d)\n", bytecode_lo4));
3209 set_global (bytecode_lo4, POP());
3211 DISPATCH();
3213 /***************************************************************************/
3214 CASE(CALL);
3216 IF_TRACE(printf(" (call %d)\n", bytecode_lo4));
3218 na = bytecode_lo4;
3220 pop_procedure ();
3221 handle_arity_and_rest_param ();
3222 build_env ();
3223 save_cont ();
3225 env = arg1;
3226 pc = entry;
3228 arg1 = OBJ_FALSE;
3230 DISPATCH();
3232 /***************************************************************************/
3233 CASE(JUMP);
3235 IF_TRACE(printf(" (jump %d)\n", bytecode_lo4));
3237 na = bytecode_lo4;
3239 pop_procedure ();
3240 handle_arity_and_rest_param ();
3241 build_env ();
3243 env = arg1;
3244 pc = entry;
3246 arg1 = OBJ_FALSE;
3248 DISPATCH();
3250 /***************************************************************************/
3251 CASE(LABEL_INSTR);
3253 switch (bytecode_lo4)
3255 case 0: // call-toplevel
3256 FETCH_NEXT_BYTECODE();
3257 arg2 = bytecode;
3259 FETCH_NEXT_BYTECODE();
3261 IF_TRACE(printf(" (call-toplevel 0x%04x)\n",
3262 ((arg2 << 8) | bytecode) + CODE_START));
3264 entry = (arg2 << 8) + bytecode + CODE_START;
3265 arg1 = OBJ_NULL;
3267 na = rom_get (entry++);
3269 build_env ();
3270 save_cont ();
3272 env = arg1;
3273 pc = entry;
3275 arg1 = OBJ_FALSE;
3276 arg2 = OBJ_FALSE;
3278 break;
3280 case 1: // jump-toplevel
3281 FETCH_NEXT_BYTECODE();
3282 arg2 = bytecode;
3284 FETCH_NEXT_BYTECODE();
3286 IF_TRACE(printf(" (jump-toplevel 0x%04x)\n",
3287 ((arg2 << 8) | bytecode) + CODE_START));
3289 entry = (arg2 << 8) + bytecode + CODE_START;
3290 arg1 = OBJ_NULL;
3292 na = rom_get (entry++);
3294 build_env ();
3296 env = arg1;
3297 pc = entry;
3299 arg1 = OBJ_FALSE;
3300 arg2 = OBJ_FALSE;
3302 break;
3304 case 2: // goto
3305 FETCH_NEXT_BYTECODE();
3306 arg2 = bytecode;
3308 FETCH_NEXT_BYTECODE();
3310 IF_TRACE(printf(" (goto 0x%04x)\n",
3311 (arg2 << 8) + bytecode + CODE_START));
3313 pc = (arg2 << 8) + bytecode + CODE_START;
3315 break;
3317 case 3: // goto-if-false
3318 FETCH_NEXT_BYTECODE();
3319 arg2 = bytecode;
3321 FETCH_NEXT_BYTECODE();
3323 IF_TRACE(printf(" (goto-if-false 0x%04x)\n",
3324 (arg2 << 8) + bytecode + CODE_START));
3326 if (POP() == OBJ_FALSE)
3327 pc = (arg2 << 8) + bytecode + CODE_START;
3329 break;
3331 case 4: // closure
3332 FETCH_NEXT_BYTECODE();
3333 arg2 = bytecode;
3335 FETCH_NEXT_BYTECODE();
3337 IF_TRACE(printf(" (closure 0x%04x)\n", (arg2 << 8) | bytecode));
3339 arg3 = POP(); // env
3341 entry = (arg2 << 8) | bytecode;
3343 arg1 = alloc_ram_cell_init (CLOSURE_FIELD0 | (arg2 >> 3),
3344 ((arg2 & 0x07) << 5) | (bytecode >> 3),
3345 ((bytecode &0x07) <<5) |((arg3 &0x1f00) >>8),
3346 arg3 & 0xff);
3348 PUSH_ARG1();
3350 arg2 = OBJ_FALSE;
3351 arg3 = OBJ_FALSE;
3353 break;
3355 case 5: // call-toplevel-short
3356 FETCH_NEXT_BYTECODE(); // TODO the short version have a lot in common with the long ones, abstract ?
3357 // TODO short instructions don't work at the moment
3358 IF_TRACE(printf(" (call-toplevel-short 0x%04x)\n",
3359 pc + bytecode + CODE_START));
3361 entry = pc + bytecode + CODE_START;
3362 arg1 = OBJ_NULL;
3364 na = rom_get (entry++);
3366 build_env ();
3367 save_cont ();
3369 env = arg1;
3370 pc = entry;
3372 arg1 = OBJ_FALSE;
3374 break;
3376 case 6: // jump-toplevel-short
3377 FETCH_NEXT_BYTECODE();
3379 IF_TRACE(printf(" (jump-toplevel-short 0x%04x)\n",
3380 pc + bytecode + CODE_START));
3382 entry = pc + bytecode + CODE_START;
3383 arg1 = OBJ_NULL;
3385 na = rom_get (entry++);
3387 build_env ();
3389 env = arg1;
3390 pc = entry;
3392 arg1 = OBJ_FALSE;
3394 break;
3396 case 7: // goto-short
3397 FETCH_NEXT_BYTECODE();
3399 IF_TRACE(printf(" (goto-short 0x%04x)\n", pc + bytecode + CODE_START));
3401 pc = pc + bytecode + CODE_START;
3403 break;
3405 case 8: // goto-if-false-short
3406 FETCH_NEXT_BYTECODE();
3408 IF_TRACE(printf(" (goto-if-false-short 0x%04x)\n",
3409 pc + bytecode + CODE_START));
3411 if (POP() == OBJ_FALSE)
3412 pc = pc + bytecode + CODE_START;
3414 break;
3416 case 9: // closure-short
3417 FETCH_NEXT_BYTECODE();
3419 IF_TRACE(printf(" (closure-short 0x%04x)\n", pc + bytecode));
3421 arg3 = POP(); // env
3423 entry = pc + bytecode;
3425 arg1 = alloc_ram_cell_init (CLOSURE_FIELD0 | (arg2 >> 3),
3426 ((arg2 & 0x07) << 5) | (bytecode >> 3),
3427 ((bytecode &0x07) <<5) |((arg3 &0x1f00) >>8),
3428 arg3 & 0xff);
3430 PUSH_ARG1();
3432 arg3 = OBJ_FALSE;
3434 break;
3436 #if 0
3437 case 10:
3438 break;
3439 case 11:
3440 break;
3441 case 12:
3442 break;
3443 case 13:
3444 break;
3445 #endif
3446 case 14: // push_global [long]
3447 FETCH_NEXT_BYTECODE();
3449 IF_TRACE(printf(" (push-global [long] %d)\n", bytecode));
3451 arg1 = get_global (bytecode);
3453 PUSH_ARG1();
3455 break;
3457 case 15: // set_global [long]
3458 FETCH_NEXT_BYTECODE();
3460 IF_TRACE(printf(" (set-global [long] %d)\n", bytecode));
3462 set_global (bytecode, POP());
3464 break;
3467 DISPATCH();
3469 /***************************************************************************/
3470 CASE(PUSH_CONSTANT_LONG);
3472 /* push-constant [long] */
3474 FETCH_NEXT_BYTECODE();
3476 IF_TRACE(printf(" (push [long] 0x%04x)\n", (bytecode_lo4 << 8) + bytecode));
3478 arg1 = (bytecode_lo4 << 8) | bytecode;
3479 PUSH_ARG1();
3481 DISPATCH();
3483 /***************************************************************************/
3484 CASE(FREE1); // FREE
3486 DISPATCH();
3488 /***************************************************************************/
3489 CASE(FREE2); // FREE
3491 DISPATCH();
3493 /***************************************************************************/
3494 CASE(PRIM1);
3496 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4]));
3498 switch (bytecode_lo4)
3500 case 0:
3501 arg1 = POP(); prim_numberp (); PUSH_ARG1(); break;
3502 case 1:
3503 arg2 = POP(); arg1 = POP(); prim_add (); PUSH_ARG1(); break;
3504 case 2:
3505 arg2 = POP(); arg1 = POP(); prim_sub (); PUSH_ARG1(); break;
3506 case 3:
3507 arg2 = POP(); arg1 = POP(); prim_mul (); PUSH_ARG1(); break;
3508 case 4:
3509 arg2 = POP(); arg1 = POP(); prim_div (); PUSH_ARG1(); break;
3510 case 5:
3511 arg2 = POP(); arg1 = POP(); prim_rem (); PUSH_ARG1(); break;
3512 case 6:
3513 arg1 = POP(); prim_neg (); PUSH_ARG1(); break;
3514 case 7:
3515 arg2 = POP(); arg1 = POP(); prim_eq (); PUSH_ARG1(); break;
3516 case 8:
3517 arg2 = POP(); arg1 = POP(); prim_lt (); PUSH_ARG1(); break;
3518 case 9:
3519 arg2 = POP(); arg1 = POP(); prim_ior (); PUSH_ARG1(); break;
3520 case 10:
3521 arg2 = POP(); arg1 = POP(); prim_gt (); PUSH_ARG1(); break;
3522 case 11:
3523 arg2 = POP(); arg1 = POP(); prim_xor (); PUSH_ARG1(); break;
3524 case 12:
3525 arg1 = POP(); prim_pairp (); PUSH_ARG1(); break;
3526 case 13:
3527 arg2 = POP(); arg1 = POP(); prim_cons (); PUSH_ARG1(); break;
3528 case 14:
3529 arg1 = POP(); prim_car (); PUSH_ARG1(); break;
3530 case 15:
3531 arg1 = POP(); prim_cdr (); PUSH_ARG1(); break;
3534 DISPATCH();
3536 /***************************************************************************/
3537 CASE(PRIM2);
3539 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4+16]));
3541 switch (bytecode_lo4)
3543 case 0:
3544 arg2 = POP(); arg1 = POP(); prim_set_car (); break;
3545 case 1:
3546 arg2 = POP(); arg1 = POP(); prim_set_cdr (); break;
3547 case 2:
3548 arg1 = POP(); prim_nullp (); PUSH_ARG1(); break;
3549 case 3:
3550 arg2 = POP(); arg1 = POP(); prim_eqp (); PUSH_ARG1(); break;
3551 case 4:
3552 arg1 = POP(); prim_not (); PUSH_ARG1(); break;
3553 case 5:
3554 /* prim #%get-cont */
3555 arg1 = cont;
3556 PUSH_ARG1();
3557 break;
3558 case 6:
3559 /* prim #%graft-to-cont */
3561 arg1 = POP(); /* thunk to call */
3562 cont = POP(); /* continuation */
3564 PUSH_ARG1();
3566 na = 0;
3568 pop_procedure ();
3569 handle_arity_and_rest_param ();
3570 build_env ();
3572 env = arg1;
3573 pc = entry;
3575 arg1 = OBJ_FALSE;
3577 break;
3578 case 7:
3579 /* prim #%return-to-cont */
3581 arg1 = POP(); /* value to return */
3582 cont = POP(); /* continuation */
3584 arg2 = ram_get_cdr (cont);
3586 pc = ram_get_entry (arg2);
3588 env = ram_get_cdr (arg2);
3589 cont = ram_get_car (cont);
3591 PUSH_ARG1();
3592 arg2 = OBJ_FALSE;
3594 break;
3595 case 8:
3596 /* prim #%halt */
3597 return;
3598 case 9:
3599 /* prim #%symbol? */
3600 arg1 = POP(); prim_symbolp (); PUSH_ARG1(); break;
3601 case 10:
3602 /* prim #%string? */
3603 arg1 = POP(); prim_stringp (); PUSH_ARG1(); break;
3604 case 11:
3605 /* prim #%string->list */
3606 arg1 = POP(); prim_string2list (); PUSH_ARG1(); break;
3607 case 12:
3608 /* prim #%list->string */
3609 arg1 = POP(); prim_list2string (); PUSH_ARG1(); break;
3610 case 13:
3611 /* prim #%make-u8vector */
3612 arg2 = POP(); arg1 = POP(); prim_make_u8vector (); PUSH_ARG1(); break;
3613 case 14:
3614 /* prim #%u8vector-ref */
3615 arg2 = POP(); arg1 = POP(); prim_u8vector_ref (); PUSH_ARG1(); break;
3616 case 15:
3617 /* prim #%u8vector-set! */
3618 arg3 = POP(); arg2 = POP(); arg1 = POP(); prim_u8vector_set (); break;
3621 DISPATCH();
3623 /***************************************************************************/
3624 CASE(PRIM3);
3626 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4+32]));
3628 switch (bytecode_lo4)
3630 case 0:
3631 /* prim #%print */
3632 arg1 = POP();
3633 prim_print ();
3634 break;
3635 case 1:
3636 /* prim #%clock */
3637 prim_clock (); PUSH_ARG1(); break;
3638 case 2:
3639 /* prim #%motor */
3640 arg2 = POP(); arg1 = POP(); prim_motor (); break;
3641 case 3:
3642 /* prim #%led */
3643 arg3 = POP(); arg2 = POP(); arg1 = POP(); prim_led (); ;break;
3644 case 4:
3645 /* prim #%led2-color */
3646 arg1 = POP(); prim_led2_color (); break;
3647 case 5:
3648 /* prim #%getchar-wait */
3649 arg2 = POP(); arg1 = POP(); prim_getchar_wait (); PUSH_ARG1(); break;
3650 case 6:
3651 /* prim #%putchar */
3652 arg2 = POP(); arg1 = POP(); prim_putchar (); break;
3653 case 7:
3654 /* prim #%beep */
3655 arg2 = POP(); arg1 = POP(); prim_beep (); break;
3656 case 8:
3657 /* prim #%adc */
3658 arg1 = POP(); prim_adc (); PUSH_ARG1(); break;
3659 case 9:
3660 /* prim #%u8vector? */
3661 arg1 = POP(); prim_u8vectorp (); PUSH_ARG1(); break;
3662 case 10:
3663 /* prim #%sernum */
3664 prim_sernum (); PUSH_ARG1(); break;
3665 case 11:
3666 /* prim #%u8vector-length */
3667 arg1 = POP(); prim_u8vector_length (); PUSH_ARG1(); break;
3668 case 12:
3669 /* prim #%u8vector-copy! */
3670 arg5 = POP(); arg4 = POP(); arg3 = POP(); arg2 = POP(); arg1 = POP();
3671 prim_u8vector_copy (); break;
3672 break;
3673 case 13:
3674 /* shift */
3675 arg1 = POP();
3676 POP();
3677 PUSH_ARG1();
3678 break;
3679 case 14:
3680 /* pop */
3681 POP();
3682 break;
3683 case 15:
3684 /* return */
3685 arg1 = POP();
3686 arg2 = ram_get_cdr (cont);
3687 pc = ram_get_entry (arg2);
3688 env = ram_get_cdr (arg2);
3689 cont = ram_get_car (cont);
3690 PUSH_ARG1();
3691 arg2 = OBJ_FALSE;
3692 break;
3695 DISPATCH();
3697 /***************************************************************************/
3699 CASE(PRIM4);
3701 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4]));
3703 switch (bytecode_lo4)
3705 case 0:
3706 /* prim #%boolean? */
3707 arg1 = POP(); prim_booleanp (); PUSH_ARG1(); break;
3708 case 1:
3709 /* prim #%network-init */
3710 prim_network_init (); break;
3711 case 2:
3712 /* prim #%network-cleanup */
3713 prim_network_cleanup (); break;
3714 case 3:
3715 /* prim #%receive-packet-to-u8vector */
3716 arg1 = POP(); prim_receive_packet_to_u8vector (); PUSH_ARG1(); break;
3717 case 4:
3718 /* prim #%send-packet-from-u8vector */
3719 arg2 = POP(); arg1 = POP(); prim_send_packet_from_u8vector ();
3720 PUSH_ARG1(); break;
3721 case 5:
3722 break;
3723 case 6:
3724 break;
3725 case 7:
3726 break;
3727 case 8:
3728 break;
3729 case 9:
3730 break;
3731 case 10:
3732 break;
3733 case 11:
3734 break;
3735 case 12:
3736 break;
3737 case 13:
3738 break;
3739 case 14:
3740 break;
3741 case 15:
3742 break;
3745 DISPATCH();
3747 /***************************************************************************/
3749 END_DISPATCH();
3752 /*---------------------------------------------------------------------------*/
3754 #ifdef WORKSTATION
3756 void usage (void)
3758 printf ("usage: sim file.hex\n");
3759 exit (1);
3762 int main (int argc, char *argv[])
3764 int errcode = 1;
3765 rom_addr rom_start_addr = 0;
3767 test(); // TODO arithmetic test
3769 if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 's')
3771 int h1;
3772 int h2;
3773 int h3;
3774 int h4;
3776 if ((h1 = hex (argv[1][2])) < 0 ||
3777 (h2 = hex (argv[1][3])) < 0 ||
3778 (h3 = hex (argv[1][4])) != 0 ||
3779 (h4 = hex (argv[1][5])) != 0 ||
3780 argv[1][6] != '\0')
3781 usage ();
3783 rom_start_addr = (h1 << 12) | (h2 << 8) | (h3 << 4) | h4;
3785 argv++;
3786 argc--;
3789 #ifdef DEBUG
3790 printf ("Start address = 0x%04x\n", rom_start_addr + CODE_START);
3791 #endif
3793 if (argc != 2)
3794 usage ();
3796 if (!read_hex_file (argv[1]))
3797 printf ("*** Could not read hex file \"%s\"\n", argv[1]);
3798 else
3800 int i;
3802 if (rom_get (CODE_START+0) != 0xfb ||
3803 rom_get (CODE_START+1) != 0xd7)
3804 printf ("*** The hex file was not compiled with PICOBIT\n");
3805 else
3807 #if 0
3808 for (i=0; i<8192; i++)
3809 if (rom_get (i) != 0xff)
3810 printf ("rom_mem[0x%04x] = 0x%02x\n", i, rom_get (i));
3811 #endif
3813 interpreter ();
3815 #ifdef DEBUG_GC
3816 printf ("**************** memory needed = %d\n", max_live+1);
3817 #endif
3821 return errcode;
3824 #endif
3826 /*---------------------------------------------------------------------------*/