Tests added to the repository.
[picobit/chj.git] / picobit-vm.c
blobaa8cd6137b0864a7779cbd4635af84c0ce3aeb4b
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 what to do with the gc tags for the bignums ? will this work ?
274 ifndef INFINITE_PRECISION_BIGNUMS
275 bignum n 00000000 uuuuuuuu hhhhhhhh llllllll (24 bit signed integer)
277 pair 1GGaaaaa aaaaaaaa 000ddddd dddddddd
278 a is car
279 d is cdr
280 gives an address space of 2^13 * 4 = 32k divided between simple objects,
281 rom, ram and vectors
283 symbol 1GG00000 00000000 00100000 00000000
285 string 1GG***** *chars** 01000000 00000000
287 u8vector 1GGxxxxx xxxxxxxx 011yyyyy yyyyyyyy
288 x is length of the vector, in bytes (stored raw, not encoded as an object)
289 y is pointer to the elements themselves (stored in vector space)
291 closure 01Gaaaaa aaaaaaaa aaaxxxxx xxxxxxxx
292 0x5ff<a<0x4000 is entry
293 x is pointer to environment
294 the reason why the environment is on the cdr (and the entry is split on 3
295 bytes) is that, when looking for a variable, a closure is considered to be a
296 pair. The compiler adds an extra offset to any variable in the closure's
297 environment, so the car of the closure (which doesn't really exist) is never
298 checked, but the cdr is followed to find the other bindings
300 continuation 1GGxxxxx xxxxxxxx 100yyyyy yyyyyyyy
301 x is parent continuation
302 y is pointer to the second half, which is a closure (contains env and entry)
304 An environment is a list of objects built out of pairs. On entry to
305 a procedure the environment is the list of parameters to which is
306 added the environment of the closure being called.
308 The first byte at the entry point of a procedure gives the arity of
309 the procedure:
311 n = 0 to 127 -> procedure has n parameters (no rest parameter)
312 n = -128 to -1 -> procedure has -n parameters, the last is
313 a rest parameter
316 #define OBJ_FALSE 0
317 #define OBJ_TRUE 1
318 #define encode_bool(x) ((obj)(x))
320 #define OBJ_NULL 2
322 #define MIN_FIXNUM_ENCODING 3
323 // TODO change these ? were -5 and 40, with the new bignums, the needs for these might change
324 #define MIN_FIXNUM -1
325 #define MAX_FIXNUM 255
326 #define MIN_ROM_ENCODING (MIN_FIXNUM_ENCODING+MAX_FIXNUM-MIN_FIXNUM+1)
328 #define ENCODE_FIXNUM(n) ((obj)(n) + (MIN_FIXNUM_ENCODING - MIN_FIXNUM))
329 #define DECODE_FIXNUM(o) ((int32)(o) - (MIN_FIXNUM_ENCODING - MIN_FIXNUM))
331 // TODO why this ifdef ?
332 #if WORD_BITS == 8
333 #define IN_VEC(o) ((o) >= MIN_VEC_ENCODING)
334 #define IN_RAM(o) (!IN_VEC(o) && ((o) >= MIN_RAM_ENCODING))
335 #define IN_ROM(o) (!IN_VEC(o) && !IN_RAM(o) && ((o) >= MIN_ROM_ENCODING))
336 #endif
338 // bignum first byte : 00Gxxxxx
339 #define BIGNUM_FIELD0 0
340 #define RAM_BIGNUM(o) ((ram_get_field0 (o) & 0xc0) == BIGNUM_FIELD0)
341 #define ROM_BIGNUM(o) ((rom_get_field0 (o) & 0xc0) == BIGNUM_FIELD0)
343 // composite first byte : 1GGxxxxx
344 #define COMPOSITE_FIELD0 0x80
345 #define RAM_COMPOSITE(o) ((ram_get_field0 (o) & 0x80) == COMPOSITE_FIELD0)
346 #define ROM_COMPOSITE(o) ((rom_get_field0 (o) & 0x80) == COMPOSITE_FIELD0)
348 // pair third byte : 000xxxxx
349 #define PAIR_FIELD2 0
350 #define RAM_PAIR(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == PAIR_FIELD2))
351 #define ROM_PAIR(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == PAIR_FIELD2))
353 // symbol third byte : 001xxxxx
354 #define SYMBOL_FIELD2 0x20
355 #define RAM_SYMBOL(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == SYMBOL_FIELD2))
356 #define ROM_SYMBOL(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == SYMBOL_FIELD2))
358 // string third byte : 010xxxxx
359 #define STRING_FIELD2 0x40
360 #define RAM_STRING(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == STRING_FIELD2))
361 #define ROM_STRING(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == STRING_FIELD2))
363 // vector third byte : 011xxxxx
364 #define VECTOR_FIELD2 0x60
365 #define RAM_VECTOR(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == VECTOR_FIELD2))
366 #define ROM_VECTOR(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == VECTOR_FIELD2))
368 // continuation third byte : 100xxxxx
369 #define CONTINUATION_FIELD2 0x80
370 #define RAM_CONTINUATION(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == CONTINUATION_FIELD2))
371 #define ROM_CONTINUATION(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == CONTINUATION_FIELD2))
373 // closure first byte : 01Gxxxxx
374 #define CLOSURE_FIELD0 0x40
375 #define RAM_CLOSURE(o) ((ram_get_field0 (o) & 0xc0) == CLOSURE_FIELD0)
376 #define ROM_CLOSURE(o) ((rom_get_field0 (o) & 0xc0) == CLOSURE_FIELD0)
379 /*---------------------------------------------------------------------------*/
381 #define RAM_GET_FIELD0_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,0))
382 #define RAM_SET_FIELD0_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,0), val)
383 #define ROM_GET_FIELD0_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,0))
385 #define RAM_GET_GC_TAGS_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x60)
386 #define RAM_GET_GC_TAG0_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x20)
387 #define RAM_GET_GC_TAG1_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x40)
388 #define RAM_SET_GC_TAGS_MACRO(o,tags) \
389 (RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0x9f) | (tags)))
390 #define RAM_SET_GC_TAG0_MACRO(o,tag) \
391 RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0xdf) | (tag))
392 #define RAM_SET_GC_TAG1_MACRO(o,tag) \
393 RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0xbf) | (tag))
395 #if WORD_BITS == 8
396 #define RAM_GET_FIELD1_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,1))
397 #define RAM_GET_FIELD2_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,2))
398 #define RAM_GET_FIELD3_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,3))
399 #define RAM_SET_FIELD1_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,1), val)
400 #define RAM_SET_FIELD2_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,2), val)
401 #define RAM_SET_FIELD3_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,3), val)
402 #define ROM_GET_FIELD1_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,1))
403 #define ROM_GET_FIELD2_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,2))
404 #define ROM_GET_FIELD3_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,3))
405 #define VEC_GET_BYTE0_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,0))
406 #define VEC_GET_BYTE1_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,1))
407 #define VEC_GET_BYTE2_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,2))
408 #define VEC_GET_BYTE3_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,3))
409 #define VEC_SET_BYTE0_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,0), val)
410 #define VEC_SET_BYTE1_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,1), val)
411 #define VEC_SET_BYTE2_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,2), val)
412 #define VEC_SET_BYTE3_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,3), val)
413 #endif
415 uint8 ram_get_gc_tags (obj o) { return RAM_GET_GC_TAGS_MACRO(o); }
416 uint8 ram_get_gc_tag0 (obj o) { return RAM_GET_GC_TAG0_MACRO(o); }
417 uint8 ram_get_gc_tag1 (obj o) { return RAM_GET_GC_TAG1_MACRO(o); }
418 void ram_set_gc_tags (obj o, uint8 tags) { RAM_SET_GC_TAGS_MACRO(o, tags); }
419 void ram_set_gc_tag0 (obj o, uint8 tag) { RAM_SET_GC_TAG0_MACRO(o,tag); }
420 void ram_set_gc_tag1 (obj o, uint8 tag) { RAM_SET_GC_TAG1_MACRO(o,tag); }
421 uint8 ram_get_field0 (obj o) { return RAM_GET_FIELD0_MACRO(o); }
422 word ram_get_field1 (obj o) { return RAM_GET_FIELD1_MACRO(o); }
423 word ram_get_field2 (obj o) { return RAM_GET_FIELD2_MACRO(o); }
424 word ram_get_field3 (obj o) { return RAM_GET_FIELD3_MACRO(o); }
425 word ram_get_fieldn (obj o, uint8 n)
427 switch (n)
429 case 0: return ram_get_field0 (o);
430 case 1: return ram_get_field1 (o);
431 case 2: return ram_get_field2 (o);
432 case 3: return ram_get_field3 (o);
435 void ram_set_field0 (obj o, uint8 val) { RAM_SET_FIELD0_MACRO(o,val); }
436 void ram_set_field1 (obj o, word val) { RAM_SET_FIELD1_MACRO(o,val); }
437 void ram_set_field2 (obj o, word val) { RAM_SET_FIELD2_MACRO(o,val); }
438 void ram_set_field3 (obj o, word val) { RAM_SET_FIELD3_MACRO(o,val); }
439 void ram_set_fieldn (obj o, uint8 n, word val)
441 switch (n)
443 case 0: ram_set_field0 (o, val); break;
444 case 1: ram_set_field1 (o, val); break;
445 case 2: ram_set_field2 (o, val); break;
446 case 3: ram_set_field3 (o, val); break;
449 uint8 rom_get_field0 (obj o) { return ROM_GET_FIELD0_MACRO(o); }
450 word rom_get_field1 (obj o) { return ROM_GET_FIELD1_MACRO(o); }
451 word rom_get_field2 (obj o) { return ROM_GET_FIELD2_MACRO(o); }
452 word rom_get_field3 (obj o) { return ROM_GET_FIELD3_MACRO(o); }
453 /* word vec_get_byte0 (obj o) { return VEC_GET_BYTE0_MACRO(o); } */
454 /* word vec_get_byte1 (obj o) { return VEC_GET_BYTE1_MACRO(o); } */
455 /* word vec_get_byte2 (obj o) { return VEC_GET_BYTE2_MACRO(o); } */
456 /* word vec_get_byte3 (obj o) { return VEC_GET_BYTE3_MACRO(o); } */
457 /* word vec_set_byte0 (obj o, word val) { VEC_SET_BYTE0_MACRO(o,val); } */
458 /* word vec_set_byte1 (obj o, word val) { VEC_SET_BYTE1_MACRO(o,val); } */
459 /* word vec_set_byte2 (obj o, word val) { VEC_SET_BYTE2_MACRO(o,val); } */
460 /* word vec_set_byte3 (obj o, word val) { VEC_SET_BYTE3_MACRO(o,val); } */
462 obj get_field0 (obj o) // TODO these are not used yet, will they be useful at all ?
464 if (IN_RAM(o))
465 return ram_get_field0 (o);
466 else
467 return rom_get_field0 (o);
469 obj get_field1 (obj o)
471 if (IN_RAM(o))
472 return ram_get_field1 (o);
473 else
474 return rom_get_field1 (o);
476 obj get_field2 (obj o)
478 if (IN_RAM(o))
479 return ram_get_field2 (o);
480 else
481 return rom_get_field2 (o);
483 obj get_field3 (obj o)
485 if (IN_RAM(o))
486 return ram_get_field3 (o);
487 else
488 return rom_get_field3 (o);
492 obj ram_get_car (obj o)
493 { return ((ram_get_field0 (o) & 0x1f) << 8) | ram_get_field1 (o); }
494 obj rom_get_car (obj o)
495 { return ((rom_get_field0 (o) & 0x1f) << 8) | rom_get_field1 (o); }
496 obj ram_get_cdr (obj o)
497 { return ((ram_get_field2 (o) & 0x1f) << 8) | ram_get_field3 (o); }
498 obj rom_get_cdr (obj o)
499 { return ((rom_get_field2 (o) & 0x1f) << 8) | rom_get_field3 (o); }
500 obj get_car (obj o)
502 if (IN_RAM(o))
503 return ram_get_car (o);
504 else
505 return rom_get_car (o);
507 obj get_cdr (obj o)
509 if (IN_RAM(o))
510 return ram_get_cdr (o);
511 else
512 return rom_get_cdr (o);
515 void ram_set_car (obj o, obj val)
517 ram_set_field0 (o, (val >> 8) | (ram_get_field0 (o) & 0xe0));
518 ram_set_field1 (o, val & 0xff);
520 void ram_set_cdr (obj o, obj val)
522 ram_set_field2 (o, (val >> 8) | (ram_get_field2 (o) & 0xe0));
523 ram_set_field3 (o, val & 0xff);
526 obj ram_get_entry (obj o)
528 return (((ram_get_field0 (o) & 0x1f) << 11)
529 | (ram_get_field1 (o) << 3)
530 | (ram_get_field2 (o) >> 5));
532 obj rom_get_entry (obj o)
534 return (((rom_get_field0 (o) & 0x1f) << 11)
535 | (rom_get_field1 (o) << 3)
536 | (rom_get_field2 (o) >> 5));
538 obj get_entry (obj o)
540 if (IN_RAM(o))
541 return ram_get_entry (o);
542 else
543 return rom_get_entry (o);
547 obj get_global (uint8 i)
548 // globals occupy the beginning of ram, with 2 globals per word
550 if (i & 1)
551 return ram_get_cdr (MIN_RAM_ENCODING + (i / 2));
552 else
553 return ram_get_car (MIN_RAM_ENCODING + (i / 2));
556 void set_global (uint8 i, obj o)
558 if (i & 1)
559 ram_set_cdr (MIN_RAM_ENCODING + (i / 2), o);
560 else
561 ram_set_car (MIN_RAM_ENCODING + (i / 2), o);
564 #ifdef WORKSTATION
565 void show_type (obj o) // for debugging purposes
567 printf("%d : ", o);
568 if (o == OBJ_FALSE) printf("#f");
569 else if (o == OBJ_TRUE) printf("#t");
570 else if (o == OBJ_NULL) printf("()");
571 else if (o < MIN_ROM_ENCODING) printf("fixnum");
572 else if (IN_RAM (o))
574 if (RAM_BIGNUM(o)) printf("ram bignum");
575 else if (RAM_PAIR(o)) printf("ram pair");
576 else if (RAM_SYMBOL(o)) printf("ram symbol");
577 else if (RAM_STRING(o)) printf("ram string");
578 else if (RAM_VECTOR(o)) printf("ram vector");
579 else if (RAM_CONTINUATION(o)) printf("ram continuation");
580 else if (RAM_CLOSURE(o)) printf("ram closure");
582 else // ROM
584 if (ROM_BIGNUM(o)) printf("rom bignum");
585 else if (ROM_PAIR(o)) printf("rom pair");
586 else if (ROM_SYMBOL(o)) printf("rom symbol");
587 else if (ROM_STRING(o)) printf("rom string");
588 else if (ROM_VECTOR(o)) printf("rom vector");
589 else if (ROM_CONTINUATION(o)) printf("rom continuation");
590 else if (RAM_CLOSURE(o)) printf("rom closure");
592 printf("\n");
594 #endif
597 /*---------------------------------------------------------------------------*/
599 /* Interface to GC */
601 // TODO explain what each tag means, with 1-2 mark bits
602 #define GC_TAG_0_LEFT (1<<5)
603 #define GC_TAG_1_LEFT (2<<5)
604 #define GC_TAG_UNMARKED (0<<5)
606 /* Number of object fields of objects in ram */
607 #define HAS_2_OBJECT_FIELDS(visit) (RAM_PAIR(visit) || RAM_CONTINUATION(visit))
608 #ifdef INFINITE_PRECISION_BIGNUMS
609 #define HAS_1_OBJECT_FIELD(visit) (RAM_COMPOSITE(visit) \
610 || RAM_CLOSURE(visit) || RAM_BIGNUM(visit))
611 #else
612 #define HAS_1_OBJECT_FIELD(visit) (RAM_COMPOSITE(visit) || RAM_CLOSURE(visit))
613 #endif
614 // all composites except pairs and continuations have 1 object field
616 #define NIL OBJ_FALSE
618 /*---------------------------------------------------------------------------*/
620 /* Garbage collector */
622 obj free_list; /* list of unused cells */
623 obj free_list_vec; /* list of unused cells in vector space */
625 obj arg1; /* root set */
626 obj arg2;
627 obj arg3;
628 obj arg4;
629 obj arg5;
630 obj cont;
631 obj env;
633 uint8 na; /* interpreter variables */
634 rom_addr pc;
635 uint8 glovars;
636 rom_addr entry;
637 uint8 bytecode;
638 uint8 bytecode_hi4;
639 uint8 bytecode_lo4;
640 int32 a1;
641 int32 a2;
642 int32 a3;
644 void init_ram_heap (void)
646 uint8 i;
647 obj o = MAX_RAM_ENCODING;
649 free_list = 0;
651 while (o > (MIN_RAM_ENCODING + (glovars + 1) / 2))
652 // we don't want to add globals to the free list, and globals occupy the
653 // beginning of memory at the rate of 2 globals per word (car and cdr)
655 ram_set_gc_tags (o, GC_TAG_UNMARKED);
656 ram_set_car (o, free_list);
657 free_list = o;
658 o--;
661 free_list_vec = MIN_VEC_ENCODING;
662 ram_set_car (free_list_vec, 0);
663 // each node of the free list must know the free length that follows it
664 // this free length is stored in words, not in bytes
665 // if we did count in bytes, the number might need more than 13 bits
666 ram_set_cdr (free_list_vec, VEC_BYTES / 4);
668 for (i=0; i<glovars; i++)
669 set_global (i, OBJ_FALSE);
671 arg1 = OBJ_FALSE;
672 arg2 = OBJ_FALSE;
673 arg3 = OBJ_FALSE;
674 arg4 = OBJ_FALSE;
675 cont = OBJ_FALSE;
676 env = OBJ_NULL;
680 void mark (obj temp)
682 /* mark phase */
684 obj stack;
685 obj visit;
687 if (IN_RAM(temp))
689 visit = NIL;
691 push:
693 stack = visit;
694 visit = temp;
696 IF_GC_TRACE(printf ("push stack=%d visit=%d (tag=%d)\n", stack, visit, ram_get_gc_tags (visit)>>5));
698 if ((HAS_1_OBJECT_FIELD (visit) && ram_get_gc_tag0 (visit))
699 || (HAS_2_OBJECT_FIELDS (visit)
700 && (ram_get_gc_tags (visit) != GC_TAG_UNMARKED)))
701 IF_GC_TRACE(printf ("case 1\n"));
702 else
704 if (HAS_2_OBJECT_FIELDS(visit)) // pairs and continuations
706 IF_GC_TRACE(printf ("case 2\n"));
708 visit_field2:
710 temp = ram_get_cdr (visit);
712 if (IN_RAM(temp))
714 IF_GC_TRACE(printf ("case 3\n"));
715 ram_set_gc_tags (visit, GC_TAG_1_LEFT);
716 ram_set_cdr (visit, stack);
717 goto push;
720 IF_GC_TRACE(printf ("case 4\n"));
722 goto visit_field1;
725 if (HAS_1_OBJECT_FIELD(visit))
727 IF_GC_TRACE(printf ("case 5\n"));
729 visit_field1:
731 if (RAM_CLOSURE(visit)) // closures have the pointer in the cdr
732 temp = ram_get_cdr (visit);
733 else
734 temp = ram_get_car (visit);
736 if (IN_RAM(temp))
738 IF_GC_TRACE(printf ("case 6\n"));
739 ram_set_gc_tag0 (visit, GC_TAG_0_LEFT);
740 if (RAM_CLOSURE(visit))
741 ram_set_cdr (visit, stack);
742 else
743 ram_set_car (visit, stack);
745 goto push;
748 IF_GC_TRACE(printf ("case 7\n"));
750 else
751 IF_GC_TRACE(printf ("case 8\n"));
753 ram_set_gc_tag0 (visit, GC_TAG_0_LEFT);
756 pop:
758 IF_GC_TRACE(printf ("pop stack=%d visit=%d (tag=%d)\n", stack, visit, ram_get_gc_tags (visit)>>6));
760 if (stack != NIL)
762 if (HAS_2_OBJECT_FIELDS(stack) && ram_get_gc_tag1 (stack))
764 IF_GC_TRACE(printf ("case 9\n"));
766 temp = ram_get_cdr (stack); /* pop through cdr */
767 ram_set_cdr (stack, visit);
768 visit = stack;
769 stack = temp;
771 ram_set_gc_tag1(visit, GC_TAG_UNMARKED);
772 // we unset the "1-left" bit
774 goto visit_field1;
777 if (RAM_CLOSURE(stack))
778 // closures have one object field, but it's in the cdr
780 IF_GC_TRACE(printf ("case 10\n"));
782 temp = ram_get_cdr (stack); /* pop through cdr */
783 ram_set_cdr (stack, visit);
784 visit = stack;
785 stack = temp;
787 goto pop;
790 IF_GC_TRACE(printf ("case 11\n"));
792 temp = ram_get_car (stack); /* pop through car */
793 ram_set_car (stack, visit);
794 visit = stack;
795 stack = temp;
797 goto pop;
802 #ifdef DEBUG_GC
803 int max_live = 0;
804 #endif
806 void sweep (void)
808 /* sweep phase */
810 #ifdef DEBUG_GC
811 int n = 0;
812 #endif
814 obj visit = MAX_RAM_ENCODING;
816 free_list = 0;
818 while (visit >= (MIN_RAM_ENCODING + ((glovars + 1) / 2)))
819 // we don't want to sweep the global variables area
821 if ((RAM_COMPOSITE(visit)
822 && (ram_get_gc_tags (visit) == GC_TAG_UNMARKED)) // 2 mark bit
823 || !(ram_get_gc_tags (visit) & GC_TAG_0_LEFT)) // 1 mark bit
824 /* unmarked? */
826 if (RAM_VECTOR(visit))
827 // when we sweep a vector, we also have to sweep its contents
829 obj o = ram_get_cdr (visit);
830 uint16 i = ram_get_car (visit); // number of elements
831 ram_set_car (o, free_list_vec);
832 ram_set_cdr (o, (i + 3) / 4); // free length, in words
833 free_list_vec = o;
834 // TODO merge free spaces
836 ram_set_car (visit, free_list);
837 free_list = visit;
839 else
841 if (RAM_COMPOSITE(visit))
842 ram_set_gc_tags (visit, GC_TAG_UNMARKED);
843 else // only 1 mark bit to unset
844 ram_set_gc_tag0 (visit, GC_TAG_UNMARKED);
845 #ifdef DEBUG_GC
846 n++;
847 #endif
849 visit--;
852 #ifdef DEBUG_GC
853 if (n > max_live)
855 max_live = n;
856 printf ("**************** memory needed = %d\n", max_live+1);
857 fflush (stdout);
859 #endif
862 void gc (void)
864 uint8 i;
866 IF_TRACE(printf("\nGC BEGINS\n"));
868 IF_GC_TRACE(printf("arg1\n"));
869 mark (arg1);
870 IF_GC_TRACE(printf("arg2\n"));
871 mark (arg2);
872 IF_GC_TRACE(printf("arg3\n"));
873 mark (arg3);
874 IF_GC_TRACE(printf("arg4\n"));
875 mark (arg4);
876 IF_GC_TRACE(printf("arg5\n"));
877 mark (arg5);
878 IF_GC_TRACE(printf("cont\n"));
879 mark (cont);
880 IF_GC_TRACE(printf("env\n"));
881 mark (env);
883 IF_GC_TRACE(printf("globals\n"));
884 for (i=0; i<glovars; i++)
885 mark (get_global (i));
887 sweep ();
890 obj alloc_ram_cell (void)
892 obj o;
894 #ifdef DEBUG_GC
895 gc ();
896 #endif
898 if (free_list == 0)
900 #ifndef DEBUG_GC
901 gc ();
902 if (free_list == 0)
903 #endif
904 ERROR("alloc_ram_cell", "memory is full");
907 o = free_list;
909 free_list = ram_get_car (o);
911 return o;
914 obj alloc_ram_cell_init (uint8 f0, uint8 f1, uint8 f2, uint8 f3)
916 obj o = alloc_ram_cell ();
918 ram_set_field0 (o, f0);
919 ram_set_field1 (o, f1);
920 ram_set_field2 (o, f2);
921 ram_set_field3 (o, f3);
923 return o;
926 obj alloc_vec_cell (uint16 n)
928 obj o = free_list_vec;
929 obj prec = 0;
930 uint8 gc_done = 0;
932 #ifdef DEBUG_GC
933 gc ();
934 gc_done = 1;
935 #endif
937 while ((ram_get_cdr (o) * 4) < n) // free space too small
939 if (o == 0) // no free space, or none big enough
941 if (gc_done) // we gc'd, but no space is big enough for the vector
942 ERROR("alloc_vec_cell", "no room for vector");
943 #ifndef DEBUG_GC
944 gc ();
945 gc_done = 1;
946 #endif
947 o = free_list_vec;
948 prec = 0;
949 continue;
950 } // TODO merge adjacent free spaces, maybe compact ?
951 prec = o;
952 o = ram_get_car (o);
955 // case 1 : the new vector fills every free word advertized, we remove the
956 // node from the free list
957 if (((ram_get_cdr(o) * 4) - n) < 4)
959 if (prec)
960 ram_set_car (prec, ram_get_car (o));
961 else
962 free_list_vec = ram_get_car (o);
964 // case 2 : there is still some space left in the free section, create a new
965 // node to represent this space
966 else
968 obj new_free = o + (n + 3)/4;
969 if (prec)
970 ram_set_car (prec, new_free);
971 else
972 free_list_vec = new_free;
973 ram_set_car (new_free, ram_get_car (o));
974 ram_set_cdr (new_free, ram_get_cdr (o) - (n + 3)/4);
977 return o;
980 /*---------------------------------------------------------------------------*/
982 #ifdef INFINITE_PRECISION_BIGNUMS
984 int8 decode_int8 (obj o) // TODO never used except in decode_int, clean useless functions
985 { // TODO really fishy, to use only 8 bits this way...
986 int8 result;
987 if (o < MIN_FIXNUM_ENCODING)
988 TYPE_ERROR("decode_int8.0", "integer");
990 if (o <= (MIN_FIXNUM_ENCODING + (MAX_FIXNUM - MIN_FIXNUM)))
991 return DECODE_FIXNUM(o);
993 if (IN_RAM(o))
995 if (!RAM_BIGNUM(o))
996 TYPE_ERROR("decode_int8.1", "integer");
997 return ram_get_field3 (o);
999 else if (IN_ROM(o))
1001 if (!ROM_BIGNUM(o))
1002 TYPE_ERROR("decode_int8.2", "integer");
1003 return rom_get_field3 (o);
1005 else
1006 TYPE_ERROR("decode_int8.3", "integer");
1008 // TODO how could this possibly work ? it does not consider other fields, same for encoding, get to the bottom of this
1010 int32 decode_int (obj o)
1012 return decode_int8 (o); // TODO FOOBAR clearly wrong, is it used ?
1016 obj encode_int (int32 n) // TODO never used in the bignum code
1018 if (n >= MIN_FIXNUM && n <= MAX_FIXNUM){
1019 return ENCODE_FIXNUM(n);
1022 return alloc_ram_cell_init (BIGNUM_FIELD0, ENCODE_FIXNUM(0), n >> 8, n);
1025 #else
1027 int32 decode_int (obj o)
1029 uint8 u;
1030 uint8 h;
1031 uint8 l;
1033 if (o < MIN_FIXNUM_ENCODING)
1034 TYPE_ERROR("decode_int.0", "integer");
1036 if (o <= (MIN_FIXNUM_ENCODING + (MAX_FIXNUM - MIN_FIXNUM)))
1037 return DECODE_FIXNUM(o);
1039 if (IN_RAM(o))
1041 if (!RAM_BIGNUM(o))
1042 TYPE_ERROR("decode_int.1", "integer");
1044 u = ram_get_field1 (o);
1045 h = ram_get_field2 (o);
1046 l = ram_get_field3 (o);
1048 else if (IN_ROM(o))
1050 if (!ROM_BIGNUM(o))
1051 TYPE_ERROR("decode_int.2", "integer");
1053 u = rom_get_field1 (o);
1054 h = rom_get_field2 (o);
1055 l = rom_get_field3 (o);
1057 else
1058 TYPE_ERROR("decode_int.3", "integer");
1060 if (u >= 128) // negative
1061 return ((int32)((((int16)u - 256) << 8) + h) << 8) + l;
1063 return ((int32)(((int16)u << 8) + h) << 8) + l;
1066 obj encode_int (int32 n)
1068 if (n >= MIN_FIXNUM && n <= MAX_FIXNUM)
1069 return ENCODE_FIXNUM(n);
1071 return alloc_ram_cell_init (BIGNUM_FIELD0, n >> 16, n >> 8, n);
1074 #endif
1076 /*---------------------------------------------------------------------------*/
1078 #ifdef WORKSTATION
1080 void show (obj o)
1082 #if 0
1083 printf ("[%d]", o);
1084 #endif
1086 if (o == OBJ_FALSE)
1087 printf ("#f");
1088 else if (o == OBJ_TRUE)
1089 printf ("#t");
1090 else if (o == OBJ_NULL)
1091 printf ("()");
1092 else if (o <= (MIN_FIXNUM_ENCODING + (MAX_FIXNUM - MIN_FIXNUM)))
1093 printf ("%d", DECODE_FIXNUM(o));
1094 else
1096 uint8 in_ram;
1098 if (IN_RAM(o))
1099 in_ram = 1;
1100 else
1101 in_ram = 0;
1103 if ((in_ram && RAM_BIGNUM(o)) || (!in_ram && ROM_BIGNUM(o))) // TODO FIX for new bignums
1104 printf ("%d", decode_int (o));
1105 else if ((in_ram && RAM_COMPOSITE(o)) || (!in_ram && ROM_COMPOSITE(o)))
1107 obj car;
1108 obj cdr;
1110 if ((in_ram && RAM_PAIR(o)) || (!in_ram && ROM_PAIR(o)))
1112 if (in_ram)
1114 car = ram_get_car (o);
1115 cdr = ram_get_cdr (o);
1117 else
1119 car = rom_get_car (o);
1120 cdr = rom_get_cdr (o);
1123 printf ("(");
1125 loop:
1127 show (car);
1129 if (cdr == OBJ_NULL)
1130 printf (")");
1131 else if ((IN_RAM(cdr) && RAM_PAIR(cdr))
1132 || (IN_ROM(cdr) && ROM_PAIR(cdr)))
1134 if (IN_RAM(cdr))
1136 car = ram_get_car (cdr);
1137 cdr = ram_get_cdr (cdr);
1139 else
1141 car = rom_get_car (cdr);
1142 cdr = rom_get_cdr (cdr);
1145 printf (" ");
1146 goto loop;
1148 else
1150 printf (" . ");
1151 show (cdr);
1152 printf (")");
1155 else if ((in_ram && RAM_SYMBOL(o)) || (!in_ram && ROM_SYMBOL(o)))
1156 printf ("#<symbol>");
1157 else if ((in_ram && RAM_STRING(o)) || (!in_ram && ROM_STRING(o)))
1158 printf ("#<string>");
1159 else if ((in_ram && RAM_VECTOR(o)) || (!in_ram && ROM_VECTOR(o)))
1160 printf ("#<vector %d>", o);
1161 else
1163 printf ("(");
1164 car = ram_get_car (o);
1165 cdr = ram_get_cdr (o);
1166 // ugly hack, takes advantage of the fact that pairs and
1167 // continuations have the same layout
1168 goto loop;
1171 else // closure
1173 obj env;
1174 rom_addr pc;
1176 if (IN_RAM(o))
1177 env = ram_get_cdr (o);
1178 else
1179 env = rom_get_cdr (o);
1181 if (IN_RAM(o))
1182 pc = ram_get_entry (o);
1183 else
1184 pc = rom_get_entry (o);
1186 printf ("{0x%04x ", pc);
1187 show (env);
1188 printf ("}");
1192 fflush (stdout);
1195 void show_state (rom_addr pc)
1197 printf("\n");
1198 printf ("pc=0x%04x bytecode=0x%02x env=", pc, rom_get (pc));
1199 show (env);
1200 printf (" cont=");
1201 show (cont);
1202 printf ("\n");
1203 fflush (stdout);
1206 void print (obj o)
1208 show (o);
1209 printf ("\n");
1210 fflush (stdout);
1213 #endif
1215 /*---------------------------------------------------------------------------*/
1217 /* Integer operations */
1219 #ifdef INFINITE_PRECISION_BIGNUMS
1221 #define obj_eq(x,y) ((x) == (y))
1223 #define integer_hi_set(x,y) ram_set_car (x, y)
1224 // 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
1226 #define ZERO ENCODE_FIXNUM(0)
1227 #define NEG1 (ZERO-1)
1228 #define POS1 (ZERO+1)
1230 // TODO this integer type is a mess, it should be obj, for clarity
1231 integer make_integer (digit lo, integer hi) // TODO BAD, should use encode_int instead
1233 // TODO could this be fixed by a call to encode_int ?
1234 /* 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 ?
1235 /* return ENCODE_FIXNUM(lo); */
1236 // TODO won't work, and the bignum functions are unaware of fixnums
1237 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
1240 integer integer_hi (integer x) // TODO should be used for decoding
1242 if (IN_RAM(x))
1243 return ram_get_car (x);
1244 else if (IN_ROM(x))
1245 return rom_get_car (x);
1246 else if (x < (MIN_FIXNUM_ENCODING - MIN_FIXNUM))
1247 return NEG1; /* negative fixnum */
1248 else
1249 return ZERO; /* nonnegative fixnum */
1252 digit integer_lo (integer x)
1254 if (IN_RAM(x))
1255 return (((digit)ram_get_field2 (x)) << 8) + ram_get_field3 (x);
1256 else if (IN_ROM(x))
1257 return (((digit)rom_get_field2 (x)) << 8) + rom_get_field3 (x);
1258 else
1259 return DECODE_FIXNUM(x);
1262 integer norm (obj prefix, integer n)
1264 /* norm(prefix,n) returns a normalized integer whose value is the
1265 integer n prefixed with the digits in prefix (a list of digits) */
1267 while (prefix != NIL)
1269 digit d = integer_lo (prefix);
1270 obj temp = prefix;
1272 prefix = integer_hi (temp);
1274 if (obj_eq (n, ZERO))
1276 if (d <= MAX_FIXNUM)
1278 n = ENCODE_FIXNUM ((uint8)d);
1279 continue; // TODO with cast to unsigned, will it work for negative numbers ? or is it only handled in the next branch ?
1282 else if (obj_eq (n, NEG1))
1284 if (d >= (1<<digit_width) + MIN_FIXNUM)
1286 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 ?
1287 continue;
1291 integer_hi_set (temp, n);
1292 n = temp;
1295 return n;
1298 boolean negp (integer x)
1300 /* negp(x) returns true iff x is negative */
1304 x = integer_hi (x);
1305 if (obj_eq (x, ZERO)) return false;
1306 } while (!obj_eq (x, NEG1));
1308 return true;
1311 int8 cmp (integer x, integer y)
1313 /* cmp(x,y) return -1 when x<y, 1 when x>y, and 0 when x=y */
1315 int8 result = 0;
1316 digit xlo;
1317 digit ylo;
1319 for (;;)
1321 if (obj_eq (x, ZERO) || obj_eq (x, NEG1))
1323 if (!obj_eq (x, y))
1324 { if (negp (y)) result = 1; else result = -1; }
1325 break;
1328 if (obj_eq (y, ZERO) || obj_eq (y, NEG1))
1330 if (negp (x)) result = -1; else result = 1;
1331 break;
1334 xlo = integer_lo (x);
1335 ylo = integer_lo (y);
1336 x = integer_hi (x);
1337 y = integer_hi (y);
1338 if (xlo != ylo)
1339 { if (xlo < ylo) result = -1; else result = 1; }
1341 return result;
1344 uint16 integer_length (integer x)
1346 /* integer_length(x) returns the number of bits in the binary
1347 representation of the nonnegative integer x */
1349 uint16 result = 0;
1350 integer next;
1351 digit d;
1353 while (!obj_eq ((next = integer_hi (x)), ZERO)) // TODO what happens if it ends with -1 ?
1355 result += digit_width;
1356 x = next;
1359 d = integer_lo (x);
1361 while (d > 0)
1363 result++;
1364 d >>= 1;
1367 return result;
1370 integer shr (integer x)
1372 /* shr(x) returns the integer x shifted one bit to the right */
1374 obj result = NIL;
1375 digit d;
1377 for (;;)
1379 if (obj_eq (x, ZERO) || obj_eq (x, NEG1))
1381 result = norm (result, x);
1382 break;
1385 d = integer_lo (x);
1386 x = integer_hi (x);
1387 result = make_integer ((d >> 1) |
1388 ((integer_lo (x) & 1) ? (1<<(digit_width-1)) : 0),
1389 result);
1392 return result;
1395 integer negative_carry (integer carry)
1397 if (carry)
1398 return NEG1;
1399 else
1400 return ZERO;
1403 integer shl (integer x)
1405 /* shl(x) returns the integer x shifted one bit to the left */
1407 integer negc = ZERO; /* negative carry */
1408 integer temp;
1409 obj result = NIL;
1410 digit d;
1412 for (;;)
1414 if (obj_eq (x, negc))
1416 result = norm (result, x);
1417 break;
1420 d = integer_lo (x);
1421 x = integer_hi (x);
1422 temp = negc;
1423 negc = negative_carry (d & (1<<(digit_width-1))); // TODO right side is constant, and sixpic has no constant folding
1424 result = make_integer ((d << 1) | obj_eq (temp, NEG1), result);
1427 return result;
1430 integer shift_left (integer x, uint16 n) // TODO have the primitves been changed for this and right ?
1432 /* shift_left(x,n) returns the integer x shifted n bits to the left */
1434 if (obj_eq (x, ZERO))
1435 return x;
1437 while (n & (digit_width-1))
1439 x = shl (x);
1440 n--;
1443 while (n > 0)
1445 x = make_integer (0, x);
1446 n -= digit_width;
1449 return x;
1452 integer add (integer x, integer y)
1454 /* add(x,y) returns the sum of the integers x and y */
1456 integer negc = ZERO; /* negative carry */
1457 obj result = NIL; /* nil terminated for the norm function */
1458 digit dx;
1459 digit dy;
1461 for (;;)
1463 if (obj_eq (x, negc))
1465 result = norm (result, y);
1466 break;
1469 if (obj_eq (y, negc))
1471 result = norm (result, x);
1472 break;
1475 dx = integer_lo (x);
1476 dy = integer_lo (y);
1477 dx = dx + dy; /* may wrap around */
1479 if (obj_eq (negc, ZERO))
1480 negc = negative_carry (dx < dy);
1481 else
1483 dx++; /* may wrap around */
1484 negc = negative_carry (dx <= dy);
1487 x = integer_hi (x);
1488 y = integer_hi (y);
1490 result = make_integer (dx, result);
1493 return result;
1496 integer invert (integer x)
1498 if (obj_eq (x, ZERO))
1499 return NEG1;
1500 else
1501 return ZERO;
1504 integer sub (integer x, integer y)
1506 /* sub(x,y) returns the difference of the integers x and y */
1507 integer negc = NEG1; /* negative carry */
1508 obj result = NIL;
1509 digit dx;
1510 digit dy;
1512 for (;;)
1514 if (obj_eq (x, negc) && (obj_eq (y, ZERO) || obj_eq (y, NEG1)))
1516 result = norm (result, invert (y));
1517 break;
1520 if (obj_eq (y, invert (negc)))
1522 result = norm (result, x);
1523 break;
1526 dx = integer_lo (x);
1527 dy = ~integer_lo (y);
1528 dx = dx + dy; /* may wrap around */
1530 if (obj_eq (negc, ZERO))
1531 negc = negative_carry (dx < dy);
1532 else
1534 dx++; /* may wrap around */
1535 negc = negative_carry (dx <= dy);
1538 x = integer_hi (x);
1539 y = integer_hi (y);
1541 result = make_integer (dx, result);
1544 return result;
1547 integer neg (integer x)
1549 /* neg(x) returns the integer -x */
1551 return sub (ZERO, x);
1554 integer scale (digit n, integer x)
1556 /* scale(n,x) returns the integer n*x */
1558 obj result;
1559 digit carry;
1560 two_digit m;
1562 if ((n == 0) || obj_eq (x, ZERO))
1563 return ZERO;
1565 if (n == 1)
1566 return x;
1568 result = NIL;
1569 carry = 0;
1571 for (;;)
1573 if (obj_eq (x, ZERO))
1575 if (carry <= MAX_FIXNUM)
1576 result = norm (result, ENCODE_FIXNUM ((uint8)carry)); // TODO was fixnum, and int8 (signed)
1577 else
1578 result = norm (result, make_integer (carry, ZERO));
1579 break;
1582 if (obj_eq (x, NEG1))
1584 carry = carry - n;
1585 if (carry >= ((1<<digit_width) + MIN_FIXNUM))
1586 result = norm (result, ENCODE_FIXNUM ((uint8)carry)); // TODO was fixnum, and int8 (signed)
1587 else
1588 result = norm (result, make_integer (carry, NEG1));
1589 break;
1592 m = (two_digit)integer_lo (x) * n + carry;
1594 x = integer_hi (x);
1595 carry = m >> digit_width;
1596 result = make_integer ((digit)m, result);
1599 return result;
1602 integer mulnonneg (integer x, integer y)
1604 /* mulnonneg(x,y) returns the product of the integers x and y
1605 where x is nonnegative */
1607 obj result = NIL;
1608 integer s = scale (integer_lo (x), y);
1610 for (;;)
1612 result = make_integer (integer_lo (s), result);
1613 s = integer_hi (s);
1614 x = integer_hi (x);
1616 if (obj_eq (x, ZERO))
1617 break;
1619 s = add (s, scale (integer_lo (x), y));
1622 return norm (result, s);
1625 // TODO have functions mul and div that handle negative arguments ? currently, the logic is in prim_mul and prim_div
1626 integer divnonneg (integer x, integer y)
1628 /* divnonneg(x,y) returns the quotient and remainder of
1629 the integers x and y where x and y are nonnegative */
1631 integer result = ZERO;
1632 uint16 lx = integer_length (x);
1633 uint16 ly = integer_length (y);
1635 if (lx >= ly)
1637 lx = lx - ly;
1639 y = shift_left (y, lx);
1643 result = shl (result);
1644 if (cmp (x, y) >= 0)
1646 x = sub (x, y);
1647 result = add (POS1, result);
1649 y = shr (y);
1650 } while (lx-- != 0);
1653 return result;
1656 #ifdef WORKSTATION
1657 void p (integer n)
1659 long long x; // TODO long long is 32 bits here, what about on a 64 bit machine ?
1660 x = ((long long)integer_lo (integer_hi (integer_hi (integer_hi (n))))<<48)+
1661 ((long long)integer_lo (integer_hi (integer_hi (n)))<<32)+
1662 ((long long)integer_lo (integer_hi (n))<<16)+
1663 (long long)integer_lo (n);
1664 printf ("%lld ", x);
1665 // TODO test for hex output, to avoid signedness problems
1666 /* printf("%x %x %x %x\n", // TODO prob, if a lower part is 0, will show 0, not 0000 */
1667 /* integer_lo (integer_hi (integer_hi (integer_hi (n)))), */
1668 /* integer_lo (integer_hi (integer_hi (n))), */
1669 /* integer_lo (integer_hi (n)), */
1670 /* integer_lo (n)); */
1673 integer enc (long long n) // TODO used only for debugging
1675 integer result = NIL;
1677 while (n != 0 && n != -1)
1679 result = make_integer ((digit)n, result);
1680 n >>= digit_width;
1683 if (n < 0)
1684 return norm (result, NEG1);
1685 else
1686 return norm (result, ZERO);
1689 void test (void) // TODO still in use ? no, but useful for tests
1691 integer min2;
1692 integer min1;
1693 integer zero;
1694 integer one;
1695 integer two;
1696 integer three;
1697 integer four;
1699 zero = make_integer (0x0000, 0);
1700 min1 = make_integer (0xffff, 0);
1701 integer_hi_set (zero, ZERO);
1702 integer_hi_set (min1, NEG1);
1704 min2 = make_integer (0xfffe, NEG1);
1705 one = make_integer (0x0001, ZERO);
1706 two = make_integer (0x0002, ZERO);
1707 three= make_integer (0x0003, ZERO);
1708 four = make_integer (0x0004, ZERO);
1710 if (negp (ZERO)) printf ("zero is negp\n"); // should not show
1711 if (negp (NEG1)) printf ("min1 is negp\n");
1713 printf ("cmp(5,5) = %d\n",cmp (make_integer (5, ZERO), make_integer (5, ZERO)));
1714 printf ("cmp(2,5) = %d\n",cmp (make_integer (2, ZERO), make_integer (5, ZERO)));
1715 printf ("cmp(5,2) = %d\n",cmp (make_integer (5, ZERO), make_integer (2, ZERO)));
1717 printf ("cmp(-5,-5) = %d\n",cmp (make_integer (-5, NEG1), make_integer (-5, NEG1)));
1718 printf ("cmp(-2,-5) = %d\n",cmp (make_integer (-2, NEG1), make_integer (-5, NEG1)));
1719 printf ("cmp(-5,-2) = %d\n",cmp (make_integer (-5, NEG1), make_integer (-2, NEG1)));
1721 printf ("cmp(-5,65533) = %d\n",cmp (make_integer (-5, NEG1), make_integer (65533, ZERO)));
1722 printf ("cmp(-5,2) = %d\n",cmp (make_integer (-5, NEG1), make_integer (2, ZERO)));
1723 printf ("cmp(5,-65533) = %d\n",cmp (make_integer (5, ZERO), make_integer (-65533, NEG1)));
1724 printf ("cmp(5,-2) = %d\n",cmp (make_integer (5, ZERO), make_integer (-2, NEG1)));
1726 printf ("integer_length(0) = %d\n", integer_length (ZERO)); // these return the number of bits necessary to encode
1727 printf ("integer_length(1) = %d\n", integer_length (make_integer (1, ZERO)));
1728 printf ("integer_length(2) = %d\n", integer_length (make_integer (2, ZERO)));
1729 printf ("integer_length(3) = %d\n", integer_length (make_integer (3, ZERO)));
1730 printf ("integer_length(4) = %d\n", integer_length (make_integer (4, ZERO)));
1731 printf ("integer_length(65536 + 4) = %d\n", integer_length (make_integer (4, make_integer (1, ZERO))));
1734 printf ("1 = %d\n", one); // TODO these show the address, useful ?
1735 printf ("2 = %d\n", two);
1736 printf ("4 = %d\n", four);
1737 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
1738 printf ("norm(2) = %d\n", norm (make_integer (0, make_integer (2, NIL)), ZERO));
1739 printf ("norm(3) = %d\n", norm (make_integer (0, make_integer (3, NIL)), ZERO));
1740 printf ("norm(3) = %d\n", norm (make_integer (0, make_integer (3, NIL)), ZERO));
1742 printf ("shl(1) = %d\n", shl (one)); // TODO fixnums, again
1743 printf ("shl(2) = %d\n", shl (two));
1746 integer n = one;
1747 int i;
1748 // should show powers of 2 incerasing, then decreasing
1749 for (i=1; i<=34; i++)
1751 printf("\nloop-1 : i=%d len=%d ", i, integer_length(n));
1752 p (n);
1753 n = shl(n);
1755 for (i=1; i<=35; i++)
1757 printf("\nloop-2 : i=%d len=%d ", i, integer_length(n));
1758 p (n);
1759 n = shr(n);
1764 integer n = shift_left (four, 5);
1765 int i;
1767 for (i=0; i<=14; i++)
1769 printf("\nloop-3 : i=%d len=%d ", i);
1770 p (shift_left (n, i*4));
1774 printf("\n");
1775 p (add (enc (32768), enc (32768))); printf("\n"); // 65536
1776 p (add (enc (32768+(65536*65535LL)), enc (32768))); printf("\n"); // 4294967296
1778 p (sub (enc (32768), enc (-32768))); printf("\n"); // 65536
1779 p (sub (enc (32768+(65536*65535LL)), enc (-32768))); printf("\n"); // 4294967296
1781 p (sub (enc (32768), enc (32769))); printf("\n"); // -1
1782 p (sub (enc (32768), enc (132768))); printf("\n"); // -100000
1783 p (add(sub (enc (32768), enc (32769)), enc(1000))); printf("\n"); // 999
1785 // TODO mul was scrapped, logic is now in prim_mul
1786 /* p (mul (enc (123456789), enc (1000000000))); printf("\n"); // 123456789000000000 */
1787 /* p (mul (enc (123456789), enc (-1000000000))); printf("\n"); // -123456789000000000 */
1788 /* p (mul (enc (-123456789), enc (1000000000))); printf("\n"); // -123456789000000000 */
1789 /* p (mul (enc (-123456789), enc (-1000000000))); printf("\n"); // 123456789000000000 */
1790 /* p (mul (enc (-123456789), neg (enc (1000000000)))); printf("\n"); // 123456789000000000 */
1792 p (divnonneg (enc (10000000-1), enc (500000))); printf("\n"); // 19
1794 printf ("done\n");
1796 exit (0);
1798 #endif
1800 #endif
1803 void prim_numberp (void)
1805 if (arg1 >= MIN_FIXNUM_ENCODING
1806 && arg1 <= (MIN_FIXNUM_ENCODING + (MAX_FIXNUM - MIN_FIXNUM)))
1807 arg1 = OBJ_TRUE;
1808 else
1810 if (IN_RAM(arg1))
1811 arg1 = encode_bool (RAM_BIGNUM(arg1));
1812 else if (IN_ROM(arg1))
1813 arg1 = encode_bool (ROM_BIGNUM(arg1));
1814 else
1815 arg1 = OBJ_FALSE;
1819 void decode_2_int_args (void) // TODO fix for bignums ?
1821 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
1822 a2 = decode_int (arg2);
1825 void prim_add (void)
1827 #ifdef INFINITE_PRECISION_BIGNUMS
1828 arg1 = add (arg1, arg2);
1829 #else
1830 decode_2_int_args ();
1831 arg1 = encode_int (a1 + a2);
1832 #endif
1833 arg2 = OBJ_FALSE;
1836 void prim_sub (void)
1838 #ifdef INFINITE_PRECISION_BIGNUMS
1839 arg1 = sub (arg1, arg2);
1840 #else
1841 decode_2_int_args ();
1842 arg1 = encode_int (a1 - a2);
1843 #endif
1844 arg2 = OBJ_FALSE;
1847 void prim_mul (void)
1849 #ifdef INFINITE_PRECISION_BIGNUMS
1850 a1 = negp (arg1);
1851 a2 = negp (arg2); // -1 if negative
1852 arg1 = mulnonneg (a1 ? neg(arg1) : arg1,
1853 a2 ? neg(arg2) : arg2);
1854 if (a1 + a2 == 1) // only one of the 2 was negative
1855 arg1 = neg(arg1);
1856 #else
1857 decode_2_int_args ();
1858 arg1 = encode_int (a1 * a2);
1859 #endif
1860 arg2 = OBJ_FALSE;
1863 void prim_div (void)
1865 #ifdef INFINITE_PRECISION_BIGNUMS
1866 if (obj_eq(arg2, ZERO))
1867 ERROR("quotient", "divide by 0");
1868 a1 = negp (arg1);
1869 a2 = negp (arg2); // -1 if negative
1870 arg1 = divnonneg (a1 ? neg(arg1) : arg1,
1871 a2 ? neg(arg2) : arg2);
1872 if (a1 + a2 == 1) // only one of the 2 was negative
1873 arg1 = neg(arg1);
1874 #else
1875 decode_2_int_args ();
1876 if (a2 == 0)
1877 ERROR("quotient", "divide by 0");
1878 arg1 = encode_int (a1 / a2);
1879 #endif
1880 arg2 = OBJ_FALSE;
1883 void prim_rem (void)
1885 #ifdef INFINITE_PRECISION_BIGNUMS
1886 if (obj_eq(arg2, ZERO))
1887 ERROR("remainder", "divide by 0");
1888 if (negp(arg1) || negp(arg2))
1889 ERROR("remainder", "only positive numbers are supported");
1890 // TODO fix this to handle negatives
1891 // TODO logic quite similar to mul and div (likely, once we fix), abstract ?
1892 arg3 = divnonneg (arg1, arg2);
1893 arg4 = mulnonneg (arg2, arg3);
1894 arg1 = sub(arg1, arg4 );
1895 arg3 = OBJ_FALSE;
1896 arg4 = OBJ_FALSE;
1897 #else
1898 decode_2_int_args ();
1899 if (a2 == 0)
1900 ERROR("remainder", "divide by 0");
1901 arg1 = encode_int (a1 % a2);
1902 #endif
1903 arg2 = OBJ_FALSE;
1906 void prim_neg (void)
1908 #ifdef INFINITE_PRECISION_BIGNUMS
1909 arg1 = neg (arg1);
1910 #else
1911 a1 = decode_int (arg1);
1912 arg1 = encode_int (- a1);
1913 #endif
1916 void prim_eq (void)
1918 #ifdef INFINITE_PRECISION_BIGNUMS
1919 arg1 = encode_bool(cmp (arg1, arg2) == 0);
1920 #else
1921 decode_2_int_args ();
1922 arg1 = encode_bool(a1 == a2);
1923 #endif
1924 arg2 = OBJ_FALSE;
1927 void prim_lt (void)
1929 #ifdef INFINITE_PRECISION_BIGNUMS
1930 arg1 = encode_bool(cmp (arg1, arg2) < 0);
1931 #else
1932 decode_2_int_args ();
1933 arg1 = encode_bool(a1 < a2);
1934 #endif
1935 arg2 = OBJ_FALSE;
1938 void prim_gt (void)
1940 #ifdef INFINITE_PRECISION_BIGNUMS
1941 arg1 = encode_bool(cmp (arg1, arg2) > 0);
1942 #else
1943 decode_2_int_args ();
1944 arg1 = encode_bool(a1 > a2);
1945 #endif
1946 arg2 = OBJ_FALSE;
1949 void prim_ior (void) // TODO FOOBIGNUMS these have not been implemented with bignums, do it
1951 decode_2_int_args (); // TODO is the function call overhead worth it ?
1952 arg1 = encode_int (a1 | a2);
1953 arg2 = OBJ_FALSE;
1956 void prim_xor (void)
1958 decode_2_int_args (); // TODO is the function call overhead worth it ?
1959 arg1 = encode_int (a1 ^ a2);
1960 arg2 = OBJ_FALSE;
1964 /*---------------------------------------------------------------------------*/
1966 /* List operations */
1968 void prim_pairp (void)
1970 if (IN_RAM(arg1))
1971 arg1 = encode_bool (RAM_PAIR(arg1));
1972 else if (IN_ROM(arg1))
1973 arg1 = encode_bool (ROM_PAIR(arg1));
1974 else
1975 arg1 = OBJ_FALSE;
1978 obj cons (obj car, obj cdr)
1980 return alloc_ram_cell_init (COMPOSITE_FIELD0 | (car >> 8),
1981 car & 0xff,
1982 PAIR_FIELD2 | (cdr >> 8),
1983 cdr & 0xff);
1986 void prim_cons (void)
1988 arg1 = cons (arg1, arg2);
1989 arg2 = OBJ_FALSE;
1992 void prim_car (void)
1994 if (IN_RAM(arg1))
1996 if (!RAM_PAIR(arg1))
1997 TYPE_ERROR("car.0", "pair");
1998 arg1 = ram_get_car (arg1);
2000 else if (IN_ROM(arg1))
2002 if (!ROM_PAIR(arg1))
2003 TYPE_ERROR("car.1", "pair");
2004 arg1 = rom_get_car (arg1);
2006 else
2008 TYPE_ERROR("car.2", "pair");
2012 void prim_cdr (void)
2014 if (IN_RAM(arg1))
2016 if (!RAM_PAIR(arg1))
2017 TYPE_ERROR("cdr.0", "pair");
2018 arg1 = ram_get_cdr (arg1);
2020 else if (IN_ROM(arg1))
2022 if (!ROM_PAIR(arg1))
2023 TYPE_ERROR("cdr.1", "pair");
2024 arg1 = rom_get_cdr (arg1);
2026 else
2028 TYPE_ERROR("cdr.2", "pair");
2032 void prim_set_car (void)
2034 if (IN_RAM(arg1))
2036 if (!RAM_PAIR(arg1))
2037 TYPE_ERROR("set-car!.0", "pair");
2039 ram_set_car (arg1, arg2);
2040 arg1 = OBJ_FALSE;
2041 arg2 = OBJ_FALSE;
2043 else
2045 TYPE_ERROR("set-car!.1", "pair");
2049 void prim_set_cdr (void)
2051 if (IN_RAM(arg1))
2053 if (!RAM_PAIR(arg1))
2054 TYPE_ERROR("set-cdr!.0", "pair");
2056 ram_set_cdr (arg1, arg2);
2057 arg1 = OBJ_FALSE;
2058 arg2 = OBJ_FALSE;
2060 else
2062 TYPE_ERROR("set-cdr!.1", "pair");
2066 void prim_nullp (void)
2068 arg1 = encode_bool (arg1 == OBJ_NULL);
2071 /*---------------------------------------------------------------------------*/
2073 /* Vector operations */
2075 void prim_u8vectorp (void)
2077 if (IN_RAM(arg1))
2078 arg1 = encode_bool (RAM_VECTOR(arg1));
2079 else if (IN_ROM(arg1))
2080 arg1 = encode_bool (ROM_VECTOR(arg1));
2081 else
2082 arg1 = OBJ_FALSE;
2085 void prim_make_u8vector (void)
2087 decode_2_int_args (); // arg1 is length, arg2 is contents
2088 // TODO adapt for the new bignums
2089 if (a2 > 255)
2090 ERROR("make-u8vector", "byte vectors can only contain bytes");
2092 arg3 = alloc_vec_cell (a1);
2093 arg1 = alloc_ram_cell_init (COMPOSITE_FIELD0 | (a1 >> 8),
2094 a1 & 0xff,
2095 VECTOR_FIELD2 | (arg3 >> 8),
2096 arg3 & 0xff);
2098 a1 = (a1 + 3) / 4; // actual length, in words
2099 while (a1--)
2101 ram_set_field0 (arg3, a2);
2102 ram_set_field1 (arg3, a2);
2103 ram_set_field2 (arg3, a2);
2104 ram_set_field3 (arg3, a2);
2105 arg3++;
2109 void prim_u8vector_ref (void)
2111 a2 = decode_int (arg2);
2112 // TODO adapt for the new bignums
2113 if (IN_RAM(arg1))
2115 if (!RAM_VECTOR(arg1))
2116 TYPE_ERROR("u8vector-ref.0", "vector");
2117 if ((ram_get_car (arg1) <= a2) || (a2 < 0))
2118 ERROR("u8vector-ref.0", "vector index invalid");
2119 arg1 = ram_get_cdr (arg1);
2121 else if (IN_ROM(arg1))
2123 if (!ROM_VECTOR(arg1))
2124 TYPE_ERROR("u8vector-ref.1", "vector");
2125 if ((rom_get_car (arg1) <= a2) || (a2 < 0))
2126 ERROR("u8vector-ref.1", "vector index invalid");
2127 arg1 = rom_get_cdr (arg1);
2129 else
2130 TYPE_ERROR("u8vector-ref.2", "vector");
2132 if (IN_VEC(arg1))
2134 arg1 += (a2 / 4);
2135 a2 %= 4;
2137 arg1 = encode_int (ram_get_fieldn (arg1, a2));
2139 else // rom vector, stored as a list
2141 while (a2--)
2142 arg1 = rom_get_cdr (arg1);
2144 // the contents are already encoded as fixnums
2145 arg1 = rom_get_car (arg1);
2148 arg2 = OBJ_FALSE;
2149 arg3 = OBJ_FALSE;
2150 arg4 = OBJ_FALSE;
2153 void prim_u8vector_set (void)
2154 { // TODO a lot in common with ref, abstract that
2155 a2 = decode_int (arg2); // TODO adapt for bignums
2156 a3 = decode_int (arg3);
2158 if (a3 > 255)
2159 ERROR("u8vector-set!", "byte vectors can only contain bytes");
2161 if (IN_RAM(arg1))
2163 if (!RAM_VECTOR(arg1))
2164 TYPE_ERROR("u8vector-set!.0", "vector");
2165 if ((ram_get_car (arg1) <= a2) || (a2 < 0))
2166 ERROR("u8vector-set!", "vector index invalid");
2167 arg1 = ram_get_cdr (arg1);
2169 else
2170 TYPE_ERROR("u8vector-set!.1", "vector");
2172 arg1 += (a2 / 4);
2173 a2 %= 4;
2175 ram_set_fieldn (arg1, a2, a3);
2177 arg1 = OBJ_FALSE;
2178 arg2 = OBJ_FALSE;
2179 arg3 = OBJ_FALSE;
2182 void prim_u8vector_length (void)
2184 if (IN_RAM(arg1))
2186 if (!RAM_VECTOR(arg1))
2187 TYPE_ERROR("u8vector-length.0", "vector");
2188 arg1 = encode_int (ram_get_car (arg1));
2190 else if (IN_ROM(arg1))
2192 if (!ROM_VECTOR(arg1))
2193 TYPE_ERROR("u8vector-length.1", "vector");
2194 arg1 = encode_int (rom_get_car (arg1));
2196 else
2197 TYPE_ERROR("u8vector-length.2", "vector");
2200 void prim_u8vector_copy (void)
2202 // arg1 is source, arg2 is source-start, arg3 is target, arg4 is target-start
2203 // arg5 is number of bytes to copy
2205 a1 = decode_int (arg2); // TODO adapt for bignums
2206 a2 = decode_int (arg4);
2207 a3 = decode_int (arg5);
2209 // case 1 : ram to ram
2210 if (IN_RAM(arg1) && IN_RAM(arg3))
2212 if (!RAM_VECTOR(arg1) || !RAM_VECTOR(arg3))
2213 TYPE_ERROR("u8vector-copy!.0", "vector");
2214 if ((ram_get_car (arg1) < (a1 + a3)) || (a1 < 0) ||
2215 (ram_get_car (arg3) < (a2 + a3)) || (a2 < 0))
2216 ERROR("u8vector-copy!.0", "vector index invalid");
2218 // position to the start
2219 arg1 = ram_get_cdr (arg1);
2220 arg1 += (a1 / 4);
2221 a1 %= 4;
2222 arg3 = ram_get_cdr (arg3);
2223 arg3 += (a2 / 4);
2224 a2 %= 4;
2226 // copy
2227 while (a3--)
2229 ram_set_fieldn (arg3, a2, ram_get_fieldn (arg1, a1));
2231 a1++;
2232 arg1 += (a1 / 4);
2233 a1 %= 4; // TODO merge with the previous similar block ?
2234 a2++;
2235 arg3 += (a2 / 4);
2236 a2 %= 4;
2239 // case 2 : rom to ram
2240 else if (IN_ROM(arg1) && IN_RAM(arg3))
2242 if (!ROM_VECTOR(arg1) || !RAM_VECTOR(arg3))
2243 TYPE_ERROR("u8vector-copy!.1", "vector");
2244 if ((rom_get_car (arg1) < (a1 + a3)) || (a1 < 0) ||
2245 (ram_get_car (arg3) < (a2 + a3)) || (a2 < 0))
2246 ERROR("u8vector-copy!.1", "vector index invalid");
2248 arg1 = rom_get_cdr (arg1);
2249 while (a1--)
2250 arg1 = rom_get_cdr (arg1);
2252 arg3 = ram_get_cdr (arg3);
2253 arg3 += (a2 / 4);
2254 a2 %= 4;
2256 while (a3--)
2258 ram_set_fieldn (arg3, a2, decode_int (rom_get_car (arg1)));
2260 arg1 = rom_get_cdr (arg1);
2261 a2++;
2262 arg3 += (a2 / 4);
2263 a2 %= 4; // TODO very similar to the other case
2266 else
2267 TYPE_ERROR("u8vector-copy!.2", "vector");
2269 arg1 = OBJ_FALSE;
2270 arg2 = OBJ_FALSE;
2271 arg3 = OBJ_FALSE;
2272 arg4 = OBJ_FALSE;
2273 arg5 = OBJ_FALSE;
2276 /*---------------------------------------------------------------------------*/
2278 /* Miscellaneous operations */
2280 void prim_eqp (void)
2282 arg1 = encode_bool (arg1 == arg2);
2283 arg2 = OBJ_FALSE;
2286 void prim_not (void)
2288 arg1 = encode_bool (arg1 == OBJ_FALSE);
2291 void prim_symbolp (void)
2293 if (IN_RAM(arg1))
2294 arg1 = encode_bool (RAM_SYMBOL(arg1));
2295 else if (IN_ROM(arg1))
2296 arg1 = encode_bool (ROM_SYMBOL(arg1));
2297 else
2298 arg1 = OBJ_FALSE;
2301 void prim_stringp (void)
2303 if (IN_RAM(arg1))
2304 arg1 = encode_bool (RAM_STRING(arg1));
2305 else if (IN_ROM(arg1))
2306 arg1 = encode_bool (ROM_STRING(arg1));
2307 else
2308 arg1 = OBJ_FALSE;
2311 void prim_string2list (void)
2313 if (IN_RAM(arg1))
2315 if (!RAM_STRING(arg1))
2316 TYPE_ERROR("string->list.0", "string");
2318 arg1 = ram_get_car (arg1);
2320 else if (IN_ROM(arg1))
2322 if (!ROM_STRING(arg1))
2323 TYPE_ERROR("string->list.1", "string");
2325 arg1 = rom_get_car (arg1);
2327 else
2328 TYPE_ERROR("string->list.2", "string");
2331 void prim_list2string (void)
2333 arg1 = alloc_ram_cell_init (COMPOSITE_FIELD0 | ((arg1 & 0x1f00) >> 8),
2334 arg1 & 0xff,
2335 STRING_FIELD2,
2339 void prim_booleanp (void)
2341 arg1 = encode_bool (arg1 < 2);
2345 /*---------------------------------------------------------------------------*/
2347 /* Robot specific operations */
2350 void prim_print (void)
2352 #ifdef PICOBOARD2
2353 #endif
2355 #ifdef WORKSTATION
2357 print (arg1);
2359 #endif
2361 arg1 = OBJ_FALSE;
2365 int32 read_clock (void)
2367 int32 now = 0;
2369 #ifdef PICOBOARD2
2371 now = from_now( 0 );
2373 #endif
2375 #ifdef WORKSTATION
2377 #ifdef _WIN32
2379 static int32 start = 0;
2380 struct timeb tb;
2382 ftime (&tb);
2384 now = tb.time * 1000 + tb.millitm;
2385 if (start == 0)
2386 start = now;
2387 now -= start;
2389 #else
2391 static int32 start = 0;
2392 struct timeval tv;
2394 if (gettimeofday (&tv, NULL) == 0)
2396 now = tv.tv_sec * 1000 + tv.tv_usec / 1000;
2397 if (start == 0)
2398 start = now;
2399 now -= start;
2402 #endif
2404 #endif
2406 return now;
2410 void prim_clock (void)
2412 arg1 = encode_int (read_clock ());
2416 void prim_motor (void)
2418 decode_2_int_args (); // TODO fix for bignums
2420 if (a1 < 1 || a1 > 2 || a2 < -100 || a2 > 100)
2421 ERROR("motor", "argument out of range");
2423 #ifdef PICOBOARD2
2425 MOTOR_set( a1, a2 );
2427 #endif
2429 #ifdef WORKSTATION
2431 printf ("motor %d -> power=%d\n", a1, a2);
2432 fflush (stdout);
2434 #endif
2436 arg1 = OBJ_FALSE;
2437 arg2 = OBJ_FALSE;
2441 void prim_led (void)
2443 decode_2_int_args (); // TODO fix for bignums
2444 a3 = decode_int (arg3);
2446 if (a1 < 1 || a1 > 3 || a2 < 0 || a3 < 0)
2447 ERROR("led", "argument out of range");
2449 #ifdef PICOBOARD2
2451 LED_set( a1, a2, a3 );
2453 #endif
2455 #ifdef WORKSTATION
2457 printf ("led %d -> duty=%d period=%d\n", a1, a2, a3 );
2458 fflush (stdout);
2460 #endif
2462 arg1 = OBJ_FALSE;
2463 arg2 = OBJ_FALSE;
2464 arg3 = OBJ_FALSE;
2468 void prim_led2_color (void)
2470 a1 = decode_int (arg1); // TODO fix for bignums
2472 if (a1 < 0 || a1 > 1)
2473 ERROR("led2-colors", "argument out of range");
2475 #ifdef PICOBOARD2
2477 LED2_color_set( a1 );
2479 #endif
2481 #ifdef WORKSTATION
2483 printf ("led2-color -> %s\n", (a1==0)?"green":"red");
2484 fflush (stdout);
2486 #endif
2488 arg1 = OBJ_FALSE;
2492 void prim_getchar_wait (void)
2494 decode_2_int_args(); // TODO fix for bignums
2495 a1 = read_clock () + a1;
2497 if (a1 < 0 || a2 < 1 || a2 > 3)
2498 ERROR("getchar-wait", "argument out of range");
2500 #ifdef PICOBOARD2
2502 arg1 = OBJ_FALSE;
2505 serial_port_set ports;
2506 ports = serial_rx_wait_with_timeout( a2, a1 );
2507 if (ports != 0)
2508 arg1 = encode_int (serial_rx_read( ports ));
2511 #endif
2513 #ifdef WORKSTATION
2515 #ifdef _WIN32
2517 arg1 = OBJ_FALSE;
2521 if (_kbhit ())
2523 arg1 = encode_int (_getch ());
2524 break;
2526 } while (read_clock () < a1);
2529 #else
2531 arg1 = encode_int (getchar ());
2533 #endif
2535 #endif
2539 void prim_putchar (void)
2541 decode_2_int_args ();
2543 if (a1 < 0 || a1 > 255 || a2 < 1 || a2 > 3)
2544 ERROR("putchar", "argument out of range");
2546 #ifdef PICOBOARD2
2548 serial_tx_write( a2, a1 );
2550 #endif
2552 #ifdef WORKSTATION
2554 putchar (a1);
2555 fflush (stdout);
2557 #endif
2559 arg1 = OBJ_FALSE;
2560 arg2 = OBJ_FALSE;
2564 void prim_beep (void)
2566 decode_2_int_args (); // TODO fix for bignums
2568 if (a1 < 1 || a1 > 255 || a2 < 0)
2569 ERROR("beep", "argument out of range");
2571 #ifdef PICOBOARD2
2573 beep( a1, from_now( a2 ) );
2575 #endif
2577 #ifdef WORKSTATION
2579 printf ("beep -> freq-div=%d duration=%d\n", a1, a2 );
2580 fflush (stdout);
2582 #endif
2584 arg1 = OBJ_FALSE;
2585 arg2 = OBJ_FALSE;
2589 void prim_adc (void)
2591 short x;
2593 a1 = decode_int (arg1); // TODO fix for bignums
2595 if (a1 < 1 || a1 > 3)
2596 ERROR("adc", "argument out of range");
2598 #ifdef PICOBOARD2
2600 x = adc( a1 );
2602 #endif
2604 #ifdef WORKSTATION
2606 x = read_clock () & 255;
2608 if (x > 127) x = 256 - x;
2610 x += 200;
2612 #endif
2614 arg1 = encode_int (x);
2618 void prim_dac (void) // TODO not used
2620 a1 = decode_int (arg1); // TODO fix for bignums
2622 if (a1 < 0 || a1 > 255)
2623 ERROR("dac", "argument out of range");
2625 #ifdef PICOBOARD2
2627 dac( a1 );
2629 #endif
2631 #ifdef WORKSTATION
2633 printf ("dac -> %d\n", a1 );
2634 fflush (stdout);
2636 #endif
2638 arg1 = OBJ_FALSE;
2642 void prim_sernum (void)
2644 short x;
2646 #ifdef PICOBOARD2
2648 x = serial_num ();
2650 #endif
2652 #ifdef WORKSTATION
2654 x = 0;
2656 #endif
2658 arg1 = encode_int (x);
2662 /*---------------------------------------------------------------------------*/
2663 // networking, currently works only on workstations
2665 #ifdef WORKSTATION
2667 void prim_network_init (void)
2668 { // TODO maybe put in the initialization of the vm
2669 handle= pcap_open_live(INTERFACE, MAX_PACKET_SIZE, PROMISC, TO_MSEC, errbuf);
2670 if (handle == NULL)
2671 ERROR("network-init", "interface not responding");
2674 void prim_network_cleanup (void)
2675 { // TODO maybe put in halt ?
2676 pcap_close(handle);
2679 void prim_receive_packet_to_u8vector (void)
2681 // arg1 is the vector in which to put the received packet
2682 if (!RAM_VECTOR(arg1))
2683 TYPE_ERROR("receive-packet-to-u8vector", "vector");
2685 // receive the packet in the buffer
2686 struct pcap_pkthdr header;
2687 const u_char *packet;
2689 packet = pcap_next(handle, &header);
2691 if (packet == NULL)
2692 header.len = 0;
2694 if (ram_get_car (arg1) < header.len)
2695 ERROR("receive-packet-to-u8vector", "packet longer than vector");
2697 if (header.len > 0) // we have received a packet, write it in the vector
2699 arg2 = rom_get_cdr (arg1);
2700 arg1 = header.len; // we return the length of the received packet
2701 a1 = 0;
2703 while (a1 < arg1)
2705 ram_set_fieldn (arg2, a1 % 4, (char)packet[a1]);
2706 a1++;
2707 arg2 += (a1 % 4) ? 0 : 1;
2710 arg2 = OBJ_FALSE;
2712 else // no packet to be read
2713 arg1 = OBJ_FALSE;
2716 void prim_send_packet_from_u8vector (void)
2718 // arg1 is the vector which contains the packet to be sent
2719 // arg2 is the length of the packet
2720 // TODO only works with ram vectors for now
2721 if (!RAM_VECTOR(arg1))
2722 TYPE_ERROR("send-packet-from-vector!", "vector");
2723 a2 = decode_int (arg2); // TODO fix for bignums
2724 a1 = 0;
2726 // TODO test if the length of the packet is longer than the length of the vector
2727 if (ram_get_car (arg1) < a2)
2728 ERROR("send-packet-from-u8vector", "packet cannot be longer than vector");
2730 arg1 = ram_get_cdr (arg1);
2732 // copy the packet to the output buffer
2733 while (a1 < a2)
2734 buf[a1] = ram_get_fieldn (arg1, a1 % 4);
2735 // TODO maybe I could just give pcap the pointer to the memory BREGG
2737 if (pcap_sendpacket(handle, buf, a2) < 0) // TODO an error has occurred, can we reuse the interface ?
2738 arg1 = OBJ_FALSE;
2739 else
2740 arg1 = OBJ_TRUE;
2742 arg2 = OBJ_FALSE;
2745 #endif
2747 /*---------------------------------------------------------------------------*/
2749 #ifdef WORKSTATION
2751 int hidden_fgetc (FILE *f)
2753 int c = fgetc (f);
2754 #if 0
2755 printf ("{%d}",c);
2756 fflush (stdout);
2757 #endif
2758 return c;
2761 #define fgetc(f) hidden_fgetc(f)
2763 void write_hex_nibble (int n)
2765 putchar ("0123456789ABCDEF"[n]);
2768 void write_hex (uint8 n)
2770 write_hex_nibble (n >> 4);
2771 write_hex_nibble (n & 0x0f);
2774 int hex (int c)
2776 if (c >= '0' && c <= '9')
2777 return (c - '0');
2779 if (c >= 'A' && c <= 'F')
2780 return (c - 'A' + 10);
2782 if (c >= 'a' && c <= 'f')
2783 return (c - 'a' + 10);
2785 return -1;
2788 int read_hex_byte (FILE *f)
2790 int h1 = hex (fgetc (f));
2791 int h2 = hex (fgetc (f));
2793 if (h1 >= 0 && h2 >= 0)
2794 return (h1<<4) + h2;
2796 return -1;
2799 int read_hex_file (char *filename)
2801 int c;
2802 FILE *f = fopen (filename, "r");
2803 int result = 0;
2804 int len;
2805 int a, a1, a2;
2806 int t;
2807 int b;
2808 int i;
2809 uint8 sum;
2810 int hi16 = 0;
2812 for (i=0; i<ROM_BYTES; i++)
2813 rom_mem[i] = 0xff;
2815 if (f != NULL)
2817 while ((c = fgetc (f)) != EOF)
2819 if ((c == '\r') || (c == '\n'))
2820 continue;
2822 if (c != ':' ||
2823 (len = read_hex_byte (f)) < 0 ||
2824 (a1 = read_hex_byte (f)) < 0 ||
2825 (a2 = read_hex_byte (f)) < 0 ||
2826 (t = read_hex_byte (f)) < 0)
2827 break;
2829 a = (a1 << 8) + a2;
2831 i = 0;
2832 sum = len + a1 + a2 + t;
2834 if (t == 0)
2836 next0:
2838 if (i < len)
2840 unsigned long adr = ((unsigned long)hi16 << 16) + a - CODE_START;
2842 if ((b = read_hex_byte (f)) < 0)
2843 break;
2845 if (adr >= 0 && adr < ROM_BYTES)
2846 rom_mem[adr] = b;
2848 a = (a + 1) & 0xffff;
2849 i++;
2850 sum += b;
2852 goto next0;
2855 else if (t == 1)
2857 if (len != 0)
2858 break;
2860 else if (t == 4)
2862 if (len != 2)
2863 break;
2865 if ((a1 = read_hex_byte (f)) < 0 ||
2866 (a2 = read_hex_byte (f)) < 0)
2867 break;
2869 sum += a1 + a2;
2871 hi16 = (a1<<8) + a2;
2873 else
2874 break;
2876 if ((b = read_hex_byte (f)) < 0)
2877 break;
2879 sum = -sum;
2881 if (sum != b)
2883 printf ("*** HEX file checksum error (expected 0x%02x)\n", sum);
2884 break;
2887 c = fgetc (f);
2889 if ((c != '\r') && (c != '\n'))
2890 break;
2892 if (t == 1)
2894 result = 1;
2895 break;
2899 if (result == 0)
2900 printf ("*** HEX file syntax error\n");
2902 fclose (f);
2905 return result;
2908 #endif
2910 /*---------------------------------------------------------------------------*/
2912 #define FETCH_NEXT_BYTECODE() bytecode = rom_get (pc++)
2914 #define BEGIN_DISPATCH() \
2915 dispatch: \
2916 IF_TRACE(show_state (pc)); \
2917 FETCH_NEXT_BYTECODE(); \
2918 bytecode_hi4 = bytecode & 0xf0; \
2919 bytecode_lo4 = bytecode & 0x0f; \
2920 switch (bytecode_hi4 >> 4) {
2922 #define END_DISPATCH() }
2924 #define CASE(opcode) case (opcode>>4):;
2926 #define DISPATCH(); goto dispatch;
2928 #if 0
2929 #define pc FSR1
2930 #define sp FSR2
2931 #define bytecode TABLAT
2932 #define bytecode_hi4 WREG
2933 #endif
2935 #define PUSH_CONSTANT1 0x00
2936 #define PUSH_CONSTANT2 0x10
2937 #define PUSH_STACK1 0x20
2938 #define PUSH_STACK2 0x30
2939 #define PUSH_GLOBAL 0x40
2940 #define SET_GLOBAL 0x50
2941 #define CALL 0x60
2942 #define JUMP 0x70
2943 #define LABEL_INSTR 0x80
2944 #define PUSH_CONSTANT_LONG 0x90
2946 #define FREE1 0xa0
2947 #define FREE2 0xb0
2949 #define PRIM1 0xc0
2950 #define PRIM2 0xd0
2951 #define PRIM3 0xe0
2952 #define PRIM4 0xf0
2954 #ifdef WORKSTATION
2956 char *prim_name[64] =
2958 "prim #%number?",
2959 "prim #%+",
2960 "prim #%-",
2961 "prim #%*",
2962 "prim #%quotient",
2963 "prim #%remainder",
2964 "prim #%neg",
2965 "prim #%=",
2966 "prim #%<",
2967 "prim #%ior",
2968 "prim #%>",
2969 "prim #%xor",
2970 "prim #%pair?",
2971 "prim #%cons",
2972 "prim #%car",
2973 "prim #%cdr",
2974 "prim #%set-car!",
2975 "prim #%set-cdr!",
2976 "prim #%null?",
2977 "prim #%eq?",
2978 "prim #%not",
2979 "prim #%get-cont",
2980 "prim #%graft-to-cont",
2981 "prim #%return-to-cont",
2982 "prim #%halt",
2983 "prim #%symbol?",
2984 "prim #%string?",
2985 "prim #%string->list",
2986 "prim #%list->string",
2987 "prim #%make-u8vector",
2988 "prim #%u8vector-ref",
2989 "prim #%u8vector-set!",
2990 "prim #%print",
2991 "prim #%clock",
2992 "prim #%motor",
2993 "prim #%led",
2994 "prim #%led2-color",
2995 "prim #%getchar-wait",
2996 "prim #%putchar",
2997 "prim #%beep",
2998 "prim #%adc",
2999 "prim #%u8vector?",
3000 "prim #%sernum",
3001 "prim #%u8vector-length",
3002 "prim #%u8vector-copy!",
3003 "shift",
3004 "pop",
3005 "return",
3006 "prim #%boolean?",
3007 "prim #%network-init",
3008 "prim #%network-cleanup",
3009 "prim #%receive-packet-to-u8vector",
3010 "prim #%send-packet-from-u8vector",
3011 "prim 53",
3012 "prim 54",
3013 "prim 55",
3014 "prim 56",
3015 "prim 57",
3016 "prim 58",
3017 "prim 59",
3018 "prim 60",
3019 "prim 61",
3020 "prim 62",
3021 "prim 63"
3024 #endif
3026 #define PUSH_ARG1() push_arg1 ()
3027 #define POP() pop()
3029 void push_arg1 (void)
3031 env = cons (arg1, env);
3032 arg1 = OBJ_FALSE;
3035 obj pop (void)
3037 obj o = ram_get_car (env);
3038 env = ram_get_cdr (env);
3039 return o;
3042 void pop_procedure (void)
3044 arg1 = POP();
3046 if (IN_RAM(arg1))
3048 if (!RAM_CLOSURE(arg1))
3049 TYPE_ERROR("pop_procedure.0", "procedure");
3051 entry = ram_get_entry (arg1) + CODE_START;
3053 else if (IN_ROM(arg1))
3055 if (!ROM_CLOSURE(arg1))
3056 TYPE_ERROR("pop_procedure.1", "procedure");
3058 entry = rom_get_entry (arg1) + CODE_START;
3060 else
3061 TYPE_ERROR("pop_procedure.2", "procedure");
3064 void handle_arity_and_rest_param (void)
3066 uint8 np;
3068 np = rom_get (entry++);
3070 if ((np & 0x80) == 0)
3072 if (na != np)
3073 ERROR("handle_arity_and_rest_param.0", "wrong number of arguments");
3075 else
3077 np = ~np;
3079 if (na < np)
3080 ERROR("handle_arity_and_rest_param.1", "wrong number of arguments");
3082 arg3 = OBJ_NULL;
3084 while (na > np)
3086 arg4 = POP();
3088 arg3 = cons (arg4, arg3);
3089 arg4 = OBJ_FALSE;
3091 na--;
3094 arg1 = cons (arg3, arg1);
3095 arg3 = OBJ_FALSE;
3099 void build_env (void)
3101 while (na != 0)
3103 arg3 = POP();
3105 arg1 = cons (arg3, arg1);
3107 na--;
3110 arg3 = OBJ_FALSE;
3113 void save_cont (void)
3115 // the second half is a closure
3116 arg3 = alloc_ram_cell_init (CLOSURE_FIELD0 | (pc >> 11),
3117 (pc >> 3) & 0xff,
3118 ((pc & 0x0007) << 5) | (env >> 8),
3119 env & 0xff);
3120 cont = alloc_ram_cell_init (COMPOSITE_FIELD0 | (cont >> 8),
3121 cont & 0xff,
3122 CONTINUATION_FIELD2 | (arg3 >> 8),
3123 arg3 & 0xff);
3124 arg3 = OBJ_FALSE;
3127 void interpreter (void)
3129 pc = (CODE_START + 4) + ((rom_addr)rom_get (CODE_START+2) << 2);
3131 glovars = rom_get (CODE_START+3); // number of global variables
3133 init_ram_heap ();
3135 BEGIN_DISPATCH();
3137 /***************************************************************************/
3138 CASE(PUSH_CONSTANT1);
3140 IF_TRACE(printf(" (push-constant "); show (bytecode_lo4); printf (")\n"));
3142 arg1 = bytecode_lo4;
3144 PUSH_ARG1();
3146 DISPATCH();
3148 /***************************************************************************/
3149 CASE(PUSH_CONSTANT2);
3151 IF_TRACE(printf(" (push-constant "); show (bytecode_lo4+16); printf (")\n"));
3152 arg1 = bytecode_lo4+16;
3154 PUSH_ARG1();
3156 DISPATCH();
3158 /***************************************************************************/
3159 CASE(PUSH_STACK1);
3161 IF_TRACE(printf(" (push-stack %d)\n", bytecode_lo4));
3163 arg1 = env;
3165 while (bytecode_lo4 != 0)
3167 arg1 = ram_get_cdr (arg1);
3168 bytecode_lo4--;
3171 arg1 = ram_get_car (arg1);
3173 PUSH_ARG1();
3175 DISPATCH();
3177 /***************************************************************************/
3178 CASE(PUSH_STACK2);
3180 IF_TRACE(printf(" (push-stack %d)\n", bytecode_lo4+16));
3182 bytecode_lo4 += 16;
3184 arg1 = env;
3186 while (bytecode_lo4 != 0)
3188 arg1 = ram_get_cdr (arg1);
3189 bytecode_lo4--;
3192 arg1 = ram_get_car (arg1);
3194 PUSH_ARG1();
3196 DISPATCH();
3198 /***************************************************************************/
3199 CASE(PUSH_GLOBAL);
3201 IF_TRACE(printf(" (push-global %d)\n", bytecode_lo4));
3203 arg1 = get_global (bytecode_lo4);
3205 PUSH_ARG1();
3207 DISPATCH();
3209 /***************************************************************************/
3210 CASE(SET_GLOBAL);
3212 IF_TRACE(printf(" (set-global %d)\n", bytecode_lo4));
3214 set_global (bytecode_lo4, POP());
3216 DISPATCH();
3218 /***************************************************************************/
3219 CASE(CALL);
3221 IF_TRACE(printf(" (call %d)\n", bytecode_lo4));
3223 na = bytecode_lo4;
3225 pop_procedure ();
3226 handle_arity_and_rest_param ();
3227 build_env ();
3228 save_cont ();
3230 env = arg1;
3231 pc = entry;
3233 arg1 = OBJ_FALSE;
3235 DISPATCH();
3237 /***************************************************************************/
3238 CASE(JUMP);
3240 IF_TRACE(printf(" (jump %d)\n", bytecode_lo4));
3242 na = bytecode_lo4;
3244 pop_procedure ();
3245 handle_arity_and_rest_param ();
3246 build_env ();
3248 env = arg1;
3249 pc = entry;
3251 arg1 = OBJ_FALSE;
3253 DISPATCH();
3255 /***************************************************************************/
3256 CASE(LABEL_INSTR);
3258 switch (bytecode_lo4)
3260 case 0: // call-toplevel
3261 FETCH_NEXT_BYTECODE();
3262 arg2 = bytecode;
3264 FETCH_NEXT_BYTECODE();
3266 IF_TRACE(printf(" (call-toplevel 0x%04x)\n",
3267 ((arg2 << 8) | bytecode) + CODE_START));
3269 entry = (arg2 << 8) + bytecode + CODE_START;
3270 arg1 = OBJ_NULL;
3272 na = rom_get (entry++);
3274 build_env ();
3275 save_cont ();
3277 env = arg1;
3278 pc = entry;
3280 arg1 = OBJ_FALSE;
3281 arg2 = OBJ_FALSE;
3283 break;
3285 case 1: // jump-toplevel
3286 FETCH_NEXT_BYTECODE();
3287 arg2 = bytecode;
3289 FETCH_NEXT_BYTECODE();
3291 IF_TRACE(printf(" (jump-toplevel 0x%04x)\n",
3292 ((arg2 << 8) | bytecode) + CODE_START));
3294 entry = (arg2 << 8) + bytecode + CODE_START;
3295 arg1 = OBJ_NULL;
3297 na = rom_get (entry++);
3299 build_env ();
3301 env = arg1;
3302 pc = entry;
3304 arg1 = OBJ_FALSE;
3305 arg2 = OBJ_FALSE;
3307 break;
3309 case 2: // goto
3310 FETCH_NEXT_BYTECODE();
3311 arg2 = bytecode;
3313 FETCH_NEXT_BYTECODE();
3315 IF_TRACE(printf(" (goto 0x%04x)\n",
3316 (arg2 << 8) + bytecode + CODE_START));
3318 pc = (arg2 << 8) + bytecode + CODE_START;
3320 break;
3322 case 3: // goto-if-false
3323 FETCH_NEXT_BYTECODE();
3324 arg2 = bytecode;
3326 FETCH_NEXT_BYTECODE();
3328 IF_TRACE(printf(" (goto-if-false 0x%04x)\n",
3329 (arg2 << 8) + bytecode + CODE_START));
3331 if (POP() == OBJ_FALSE)
3332 pc = (arg2 << 8) + bytecode + CODE_START;
3334 break;
3336 case 4: // closure
3337 FETCH_NEXT_BYTECODE();
3338 arg2 = bytecode;
3340 FETCH_NEXT_BYTECODE();
3342 IF_TRACE(printf(" (closure 0x%04x)\n", (arg2 << 8) | bytecode));
3344 arg3 = POP(); // env
3346 entry = (arg2 << 8) | bytecode;
3348 arg1 = alloc_ram_cell_init (CLOSURE_FIELD0 | (arg2 >> 3),
3349 ((arg2 & 0x07) << 5) | (bytecode >> 3),
3350 ((bytecode &0x07) <<5) |((arg3 &0x1f00) >>8),
3351 arg3 & 0xff);
3353 PUSH_ARG1();
3355 arg2 = OBJ_FALSE;
3356 arg3 = OBJ_FALSE;
3358 break;
3360 case 5: // call-toplevel-short
3361 FETCH_NEXT_BYTECODE(); // TODO the short version have a lot in common with the long ones, abstract ?
3362 // TODO short instructions don't work at the moment
3363 IF_TRACE(printf(" (call-toplevel-short 0x%04x)\n",
3364 pc + bytecode + CODE_START));
3366 entry = pc + bytecode + CODE_START;
3367 arg1 = OBJ_NULL;
3369 na = rom_get (entry++);
3371 build_env ();
3372 save_cont ();
3374 env = arg1;
3375 pc = entry;
3377 arg1 = OBJ_FALSE;
3379 break;
3381 case 6: // jump-toplevel-short
3382 FETCH_NEXT_BYTECODE();
3384 IF_TRACE(printf(" (jump-toplevel-short 0x%04x)\n",
3385 pc + bytecode + CODE_START));
3387 entry = pc + bytecode + CODE_START;
3388 arg1 = OBJ_NULL;
3390 na = rom_get (entry++);
3392 build_env ();
3394 env = arg1;
3395 pc = entry;
3397 arg1 = OBJ_FALSE;
3399 break;
3401 case 7: // goto-short
3402 FETCH_NEXT_BYTECODE();
3404 IF_TRACE(printf(" (goto-short 0x%04x)\n", pc + bytecode + CODE_START));
3406 pc = pc + bytecode + CODE_START;
3408 break;
3410 case 8: // goto-if-false-short
3411 FETCH_NEXT_BYTECODE();
3413 IF_TRACE(printf(" (goto-if-false-short 0x%04x)\n",
3414 pc + bytecode + CODE_START));
3416 if (POP() == OBJ_FALSE)
3417 pc = pc + bytecode + CODE_START;
3419 break;
3421 case 9: // closure-short
3422 FETCH_NEXT_BYTECODE();
3424 IF_TRACE(printf(" (closure-short 0x%04x)\n", pc + bytecode));
3426 arg3 = POP(); // env
3428 entry = pc + bytecode;
3430 arg1 = alloc_ram_cell_init (CLOSURE_FIELD0 | (arg2 >> 3),
3431 ((arg2 & 0x07) << 5) | (bytecode >> 3),
3432 ((bytecode &0x07) <<5) |((arg3 &0x1f00) >>8),
3433 arg3 & 0xff);
3435 PUSH_ARG1();
3437 arg3 = OBJ_FALSE;
3439 break;
3441 #if 0
3442 case 10:
3443 break;
3444 case 11:
3445 break;
3446 case 12:
3447 break;
3448 case 13:
3449 break;
3450 #endif
3451 case 14: // push_global [long]
3452 FETCH_NEXT_BYTECODE();
3454 IF_TRACE(printf(" (push-global [long] %d)\n", bytecode));
3456 arg1 = get_global (bytecode);
3458 PUSH_ARG1();
3460 break;
3462 case 15: // set_global [long]
3463 FETCH_NEXT_BYTECODE();
3465 IF_TRACE(printf(" (set-global [long] %d)\n", bytecode));
3467 set_global (bytecode, POP());
3469 break;
3472 DISPATCH();
3474 /***************************************************************************/
3475 CASE(PUSH_CONSTANT_LONG);
3477 /* push-constant [long] */
3479 FETCH_NEXT_BYTECODE();
3481 IF_TRACE(printf(" (push [long] 0x%04x)\n", (bytecode_lo4 << 8) + bytecode));
3483 arg1 = (bytecode_lo4 << 8) | bytecode;
3484 PUSH_ARG1();
3486 DISPATCH();
3488 /***************************************************************************/
3489 CASE(FREE1); // FREE
3491 DISPATCH();
3493 /***************************************************************************/
3494 CASE(FREE2); // FREE
3496 DISPATCH();
3498 /***************************************************************************/
3499 CASE(PRIM1);
3501 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4]));
3503 switch (bytecode_lo4)
3505 case 0:
3506 arg1 = POP(); prim_numberp (); PUSH_ARG1(); break;
3507 case 1:
3508 arg2 = POP(); arg1 = POP(); prim_add (); PUSH_ARG1(); break;
3509 case 2:
3510 arg2 = POP(); arg1 = POP(); prim_sub (); PUSH_ARG1(); break;
3511 case 3:
3512 arg2 = POP(); arg1 = POP(); prim_mul (); PUSH_ARG1(); break;
3513 case 4:
3514 arg2 = POP(); arg1 = POP(); prim_div (); PUSH_ARG1(); break;
3515 case 5:
3516 arg2 = POP(); arg1 = POP(); prim_rem (); PUSH_ARG1(); break;
3517 case 6:
3518 arg1 = POP(); prim_neg (); PUSH_ARG1(); break;
3519 case 7:
3520 arg2 = POP(); arg1 = POP(); prim_eq (); PUSH_ARG1(); break;
3521 case 8:
3522 arg2 = POP(); arg1 = POP(); prim_lt (); PUSH_ARG1(); break;
3523 case 9:
3524 arg2 = POP(); arg1 = POP(); prim_ior (); PUSH_ARG1(); break;
3525 case 10:
3526 arg2 = POP(); arg1 = POP(); prim_gt (); PUSH_ARG1(); break;
3527 case 11:
3528 arg2 = POP(); arg1 = POP(); prim_xor (); PUSH_ARG1(); break;
3529 case 12:
3530 arg1 = POP(); prim_pairp (); PUSH_ARG1(); break;
3531 case 13:
3532 arg2 = POP(); arg1 = POP(); prim_cons (); PUSH_ARG1(); break;
3533 case 14:
3534 arg1 = POP(); prim_car (); PUSH_ARG1(); break;
3535 case 15:
3536 arg1 = POP(); prim_cdr (); PUSH_ARG1(); break;
3539 DISPATCH();
3541 /***************************************************************************/
3542 CASE(PRIM2);
3544 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4+16]));
3546 switch (bytecode_lo4)
3548 case 0:
3549 arg2 = POP(); arg1 = POP(); prim_set_car (); break;
3550 case 1:
3551 arg2 = POP(); arg1 = POP(); prim_set_cdr (); break;
3552 case 2:
3553 arg1 = POP(); prim_nullp (); PUSH_ARG1(); break;
3554 case 3:
3555 arg2 = POP(); arg1 = POP(); prim_eqp (); PUSH_ARG1(); break;
3556 case 4:
3557 arg1 = POP(); prim_not (); PUSH_ARG1(); break;
3558 case 5:
3559 /* prim #%get-cont */
3560 arg1 = cont;
3561 PUSH_ARG1();
3562 break;
3563 case 6:
3564 /* prim #%graft-to-cont */
3566 arg1 = POP(); /* thunk to call */
3567 cont = POP(); /* continuation */
3569 PUSH_ARG1();
3571 na = 0;
3573 pop_procedure ();
3574 handle_arity_and_rest_param ();
3575 build_env ();
3577 env = arg1;
3578 pc = entry;
3580 arg1 = OBJ_FALSE;
3582 break;
3583 case 7:
3584 /* prim #%return-to-cont */
3586 arg1 = POP(); /* value to return */
3587 cont = POP(); /* continuation */
3589 arg2 = ram_get_cdr (cont);
3591 pc = ram_get_entry (arg2);
3593 env = ram_get_cdr (arg2);
3594 cont = ram_get_car (cont);
3596 PUSH_ARG1();
3597 arg2 = OBJ_FALSE;
3599 break;
3600 case 8:
3601 /* prim #%halt */
3602 return;
3603 case 9:
3604 /* prim #%symbol? */
3605 arg1 = POP(); prim_symbolp (); PUSH_ARG1(); break;
3606 case 10:
3607 /* prim #%string? */
3608 arg1 = POP(); prim_stringp (); PUSH_ARG1(); break;
3609 case 11:
3610 /* prim #%string->list */
3611 arg1 = POP(); prim_string2list (); PUSH_ARG1(); break;
3612 case 12:
3613 /* prim #%list->string */
3614 arg1 = POP(); prim_list2string (); PUSH_ARG1(); break;
3615 case 13:
3616 /* prim #%make-u8vector */
3617 arg2 = POP(); arg1 = POP(); prim_make_u8vector (); PUSH_ARG1(); break;
3618 case 14:
3619 /* prim #%u8vector-ref */
3620 arg2 = POP(); arg1 = POP(); prim_u8vector_ref (); PUSH_ARG1(); break;
3621 case 15:
3622 /* prim #%u8vector-set! */
3623 arg3 = POP(); arg2 = POP(); arg1 = POP(); prim_u8vector_set (); break;
3626 DISPATCH();
3628 /***************************************************************************/
3629 CASE(PRIM3);
3631 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4+32]));
3633 switch (bytecode_lo4)
3635 case 0:
3636 /* prim #%print */
3637 arg1 = POP();
3638 prim_print ();
3639 break;
3640 case 1:
3641 /* prim #%clock */
3642 prim_clock (); PUSH_ARG1(); break;
3643 case 2:
3644 /* prim #%motor */
3645 arg2 = POP(); arg1 = POP(); prim_motor (); break;
3646 case 3:
3647 /* prim #%led */
3648 arg3 = POP(); arg2 = POP(); arg1 = POP(); prim_led (); ;break;
3649 case 4:
3650 /* prim #%led2-color */
3651 arg1 = POP(); prim_led2_color (); break;
3652 case 5:
3653 /* prim #%getchar-wait */
3654 arg2 = POP(); arg1 = POP(); prim_getchar_wait (); PUSH_ARG1(); break;
3655 case 6:
3656 /* prim #%putchar */
3657 arg2 = POP(); arg1 = POP(); prim_putchar (); break;
3658 case 7:
3659 /* prim #%beep */
3660 arg2 = POP(); arg1 = POP(); prim_beep (); break;
3661 case 8:
3662 /* prim #%adc */
3663 arg1 = POP(); prim_adc (); PUSH_ARG1(); break;
3664 case 9:
3665 /* prim #%u8vector? */
3666 arg1 = POP(); prim_u8vectorp (); PUSH_ARG1(); break;
3667 case 10:
3668 /* prim #%sernum */
3669 prim_sernum (); PUSH_ARG1(); break;
3670 case 11:
3671 /* prim #%u8vector-length */
3672 arg1 = POP(); prim_u8vector_length (); PUSH_ARG1(); break;
3673 case 12:
3674 /* prim #%u8vector-copy! */
3675 arg5 = POP(); arg4 = POP(); arg3 = POP(); arg2 = POP(); arg1 = POP();
3676 prim_u8vector_copy (); break;
3677 break;
3678 case 13:
3679 /* shift */
3680 arg1 = POP();
3681 POP();
3682 PUSH_ARG1();
3683 break;
3684 case 14:
3685 /* pop */
3686 POP();
3687 break;
3688 case 15:
3689 /* return */
3690 arg1 = POP();
3691 arg2 = ram_get_cdr (cont);
3692 pc = ram_get_entry (arg2);
3693 env = ram_get_cdr (arg2);
3694 cont = ram_get_car (cont);
3695 PUSH_ARG1();
3696 arg2 = OBJ_FALSE;
3697 break;
3700 DISPATCH();
3702 /***************************************************************************/
3704 CASE(PRIM4);
3706 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4]));
3708 switch (bytecode_lo4)
3710 case 0:
3711 /* prim #%boolean? */
3712 arg1 = POP(); prim_booleanp (); PUSH_ARG1(); break;
3713 case 1:
3714 /* prim #%network-init */
3715 prim_network_init (); break;
3716 case 2:
3717 /* prim #%network-cleanup */
3718 prim_network_cleanup (); break;
3719 case 3:
3720 /* prim #%receive-packet-to-u8vector */
3721 arg1 = POP(); prim_receive_packet_to_u8vector (); PUSH_ARG1(); break;
3722 case 4:
3723 /* prim #%send-packet-from-u8vector */
3724 arg2 = POP(); arg1 = POP(); prim_send_packet_from_u8vector ();
3725 PUSH_ARG1(); break;
3726 case 5:
3727 break;
3728 case 6:
3729 break;
3730 case 7:
3731 break;
3732 case 8:
3733 break;
3734 case 9:
3735 break;
3736 case 10:
3737 break;
3738 case 11:
3739 break;
3740 case 12:
3741 break;
3742 case 13:
3743 break;
3744 case 14:
3745 break;
3746 case 15:
3747 break;
3750 DISPATCH();
3752 /***************************************************************************/
3754 END_DISPATCH();
3757 /*---------------------------------------------------------------------------*/
3759 #ifdef WORKSTATION
3761 void usage (void)
3763 printf ("usage: sim file.hex\n");
3764 exit (1);
3767 int main (int argc, char *argv[])
3769 int errcode = 1;
3770 rom_addr rom_start_addr = 0;
3772 #ifdef TEST_BIGNUM
3773 test();
3774 #endif
3776 if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 's')
3778 int h1;
3779 int h2;
3780 int h3;
3781 int h4;
3783 if ((h1 = hex (argv[1][2])) < 0 ||
3784 (h2 = hex (argv[1][3])) < 0 ||
3785 (h3 = hex (argv[1][4])) != 0 ||
3786 (h4 = hex (argv[1][5])) != 0 ||
3787 argv[1][6] != '\0')
3788 usage ();
3790 rom_start_addr = (h1 << 12) | (h2 << 8) | (h3 << 4) | h4;
3792 argv++;
3793 argc--;
3796 #ifdef DEBUG
3797 printf ("Start address = 0x%04x\n", rom_start_addr + CODE_START);
3798 #endif
3800 if (argc != 2)
3801 usage ();
3803 if (!read_hex_file (argv[1]))
3804 printf ("*** Could not read hex file \"%s\"\n", argv[1]);
3805 else
3807 int i;
3809 if (rom_get (CODE_START+0) != 0xfb ||
3810 rom_get (CODE_START+1) != 0xd7)
3811 printf ("*** The hex file was not compiled with PICOBIT\n");
3812 else
3814 #if 0
3815 for (i=0; i<8192; i++)
3816 if (rom_get (i) != 0xff)
3817 printf ("rom_mem[0x%04x] = 0x%02x\n", i, rom_get (i));
3818 #endif
3820 interpreter ();
3822 #ifdef DEBUG_GC
3823 printf ("**************** memory needed = %d\n", max_live+1);
3824 #endif
3828 return errcode;
3831 #endif
3833 /*---------------------------------------------------------------------------*/