1 /* file: "picobit-vm.c" */
4 * Copyright 2004 by Marc Feeley, All Rights Reserved.
8 * 15/08/2004 Release of version 1
9 * 06/07/2008 Modified for PICOBOARD2_R3
10 * 07/18/2008 Modified to use new object representation
16 /*---------------------------------------------------------------------------*/
21 typedef unsigned char uint8
;
22 typedef unsigned short uint16
;
23 typedef unsigned long uint32
;
25 /*---------------------------------------------------------------------------*/
45 static volatile near uint8 FW_VALUE_UP @
0x33;
46 static volatile near uint8 FW_VALUE_HI @
0x33;
47 static volatile near uint8 FW_VALUE_LO @
0x33;
49 #define ACTIVITY_LED1_LAT LATB
50 #define ACTIVITY_LED1_BIT 5
51 #define ACTIVITY_LED2_LAT LATB
52 #define ACTIVITY_LED2_BIT 4
53 static volatile near bit ACTIVITY_LED1 @
((unsigned)&ACTIVITY_LED1_LAT
*8)+ACTIVITY_LED1_BIT
;
54 static volatile near bit ACTIVITY_LED2 @
((unsigned)&ACTIVITY_LED2_LAT
*8)+ACTIVITY_LED2_BIT
;
65 #include <sys/types.h>
66 #include <sys/timeb.h>
75 /*---------------------------------------------------------------------------*/
79 #define CODE_START 0x5000
82 // TODO was 16, and might change
83 // TODO should this be read from the file like constants or statically allocated ? if read, it might cause problems because of dynamic allocation
87 #define IF_GC_TRACE(x) x
90 #define IF_GC_TRACE(x)
93 /*---------------------------------------------------------------------------*/
98 #define ERROR(msg) halt_with_error()
99 #define TYPE_ERROR(type) halt_with_error()
106 #define ERROR(msg) error (msg)
107 #define TYPE_ERROR(type) type_error (type)
109 void error (char *msg
)
111 printf ("ERROR: %s\n", msg
);
115 void type_error (char *type
)
117 printf ("ERROR: An argument of type %s was expected\n", type
);
124 /*---------------------------------------------------------------------------*/
132 typedef uint16 ram_addr
;
133 typedef uint16 rom_addr
;
137 /*---------------------------------------------------------------------------*/
139 #define MAX_VEC_ENCODING 8191
140 #define MIN_VEC_ENCODING 4096
141 #define VEC_BYTES ((MAX_VEC_ENCODING - MIN_VEC_ENCODING + 1)*4)
142 // TODO this is new. if the pic has less than 8k of memory, start this lower
143 // TODO max was 8192 for ram, would have been 1 too much (watch out, master branch still has that), now corrected
144 // TODO the pic actually has 2k, so change these FOOBAR
145 // 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
147 #define MAX_RAM_ENCODING 4095
148 #define MIN_RAM_ENCODING 512
149 #define RAM_BYTES ((MAX_RAM_ENCODING - MIN_RAM_ENCODING + 1)*4)
150 // TODO watch out if we address more than what the PIC actually has
153 // TODO subtracts min_ram since vectors are actually in ram
154 #define OBJ_TO_VEC_ADDR(o,f) (((ram_addr)((uint16)(o) - MIN_RAM_ENCODING) << 2) + (f))
155 #define OBJ_TO_RAM_ADDR(o,f) (((ram_addr)((uint16)(o) - MIN_RAM_ENCODING) << 2) + (f))
156 #define OBJ_TO_ROM_ADDR(o,f) (((rom_addr)((uint16)(o) - MIN_ROM_ENCODING) << 2) + (CODE_START + 4 + (f)))
161 #define ram_get(a) *(uint8*)(a+0x200)
162 #define ram_set(a,x) *(uint8*)(a+0x200) = (x)
163 // TODO change these since we change proportion of ram and rom ?
169 uint8 ram_mem
[RAM_BYTES
+ VEC_BYTES
];
171 #define ram_get(a) ram_mem[a]
172 #define ram_set(a,x) ram_mem[a] = (x)
177 /*---------------------------------------------------------------------------*/
181 /* #if WORD_BITS == 8 */
182 /* #endif */ // TODO useless
184 uint8
rom_get (rom_addr a
)
186 return *(rom uint8
*)a
;
194 #define ROM_BYTES 8192
195 // TODO the new pics have 32k, change this ? minus the vm size, firmware ?
197 uint8 rom_mem
[ROM_BYTES
] =
200 #define PUTCHAR_LIGHT_not
203 0xFB, 0xD7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x32
204 , 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00
205 , 0x08, 0x50, 0x80, 0x16, 0xFE, 0xE8, 0x00, 0xFC
206 , 0x32, 0x80, 0x2D, 0xFE, 0xFC, 0x31, 0x80, 0x43
207 , 0xFE, 0xFC, 0x33, 0x80, 0x2D, 0xFE, 0xFC, 0x31
208 , 0x80, 0x43, 0xFE, 0x90, 0x16, 0x01, 0x20, 0xFC
209 , 0x32, 0xE3, 0xB0, 0x37, 0x09, 0xF3, 0xFF, 0x20
210 , 0xFC, 0x33, 0xE3, 0xB0, 0x40, 0x0A, 0xF3, 0xFF
211 , 0x08, 0xF3, 0xFF, 0x01, 0x40, 0x21, 0xD1, 0x00
212 , 0x02, 0xC0, 0x4C, 0x71, 0x01, 0x20, 0x50, 0x90
213 , 0x51, 0x00, 0xF1, 0x40, 0xD8, 0xB0, 0x59, 0x90
217 0xFB, 0xD7, 0x00, 0x00, 0x80, 0x08, 0xFE, 0xE8
218 , 0x00, 0xF6, 0xF5, 0x90, 0x08
222 uint8
rom_get (rom_addr a
)
224 return rom_mem
[a
-CODE_START
];
229 obj globals
[GLOVARS
];
231 /*---------------------------------------------------------------------------*/
239 fixnum n MIN_FIXNUM -> 3 ... MAX_FIXNUM -> 3 + (MAX_FIXNUM-MIN_FIXNUM)
240 rom object 4 + (MAX_FIXNUM-MIN_FIXNUM) ... MIN_RAM_ENCODING-1
241 ram object MIN_RAM_ENCODING ... MAX_RAM_ENCODING
242 vector MIN_VEC_ENCODING ... 8191
244 layout of memory allocated objects:
246 G's represent mark bits used by the gc
248 bignum n 00G00000 uuuuuuuu hhhhhhhh llllllll (24 bit signed integer)
249 TODO we could have 29-bit integers
251 pair 1GGaaaaa aaaaaaaa 000ddddd dddddddd
254 gives an address space of 2^13 * 4 = 32k divided between simple objects,
257 symbol 1GG00000 00000000 00100000 00000000
259 string 1GG***** *chars** 01000000 00000000
261 vector 1GG***** *elems** 01100000 00000000 TODO old
262 vector 1GGxxxxx xxxxxxxx 011yyyyy yyyyyyyy
263 x is length of the vector, in bytes
264 y is pointer to the elements themselves (stored in vector space)
265 TODO pointer could be shorter since it always points in vector space, same for length, will never be this long
266 TODO show how vectors are represented in vector space
267 TODO what kind of gc to have for vectors ? if we have a copying gc (which we argues against in the paper), we might need a header in vector space to point to the ram header, so it can update the pointer when the vector is copied
268 TODO have a header with length here that points to vector space, or have the header in vector space, for now, header is in ordinary ram
269 TODO how to deal with gc ? mayeb when we sweep a vector header, go sweep its contents in vector space ?
271 closure 01Gaaaaa aaaaaaaa aaaxxxxx xxxxxxxx
272 0x5ff<a<0x4000 is entry
273 x is pointer to environment
274 the reason why the environment is on the cdr (and the entry is split on 3
275 bytes) is that, when looking for a variable, a closure is considered to be a
276 pair. The compiler adds an extra offset to any variable in the closure's
277 environment, so the car of the closure (which doesn't really exist) is never
278 checked, but the cdr is followed to find the other bindings
280 continuation 1GGxxxxx xxxxxxxx 100yyyyy yyyyyyyy
281 x is parent continuation
282 y is pointer to the second half, which is a closure (contains env and entry)
284 An environment is a list of objects built out of pairs. On entry to
285 a procedure the environment is the list of parameters to which is
286 added the environment of the closure being called.
288 The first byte at the entry point of a procedure gives the arity of
291 n = 0 to 127 -> procedure has n parameters (no rest parameter)
292 n = -128 to -1 -> procedure has -n parameters, the last is
300 #define MIN_FIXNUM_ENCODING 3
302 #define MAX_FIXNUM 255
303 #define MIN_ROM_ENCODING (MIN_FIXNUM_ENCODING+MAX_FIXNUM-MIN_FIXNUM+1)
305 #define ENCODE_FIXNUM(n) ((obj)(n) + (MIN_FIXNUM_ENCODING - MIN_FIXNUM))
306 #define DECODE_FIXNUM(o) ((int32)(o) - (MIN_FIXNUM_ENCODING - MIN_FIXNUM))
308 // TODO why this ifdef ?
310 #define IN_VEC(o) ((o) >= MIN_VEC_ENCODING)
311 #define IN_RAM(o) (!IN_VEC(o) && ((o) >= MIN_RAM_ENCODING))
312 #define IN_ROM(o) (!IN_VEC(o) && !IN_RAM(o) && ((o) >= MIN_ROM_ENCODING))
314 // TODO performance ?
316 // bignum first byte : 00G00000
317 #define BIGNUM_FIELD0 0
318 #define RAM_BIGNUM(o) ((ram_get_field0 (o) & 0xc0) == BIGNUM_FIELD0)
319 #define ROM_BIGNUM(o) ((rom_get_field0 (o) & 0xc0) == BIGNUM_FIELD0)
321 // composite first byte : 1GGxxxxx
322 #define COMPOSITE_FIELD0 0x80
323 #define RAM_COMPOSITE(o) ((ram_get_field0 (o) & 0x80) == COMPOSITE_FIELD0)
324 #define ROM_COMPOSITE(o) ((rom_get_field0 (o) & 0x80) == COMPOSITE_FIELD0)
326 // pair third byte : 000xxxxx
327 #define PAIR_FIELD2 0
328 #define RAM_PAIR(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == PAIR_FIELD2))
329 #define ROM_PAIR(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == PAIR_FIELD2))
331 // symbol third byte : 001xxxxx
332 #define SYMBOL_FIELD2 0x20
333 #define RAM_SYMBOL(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == SYMBOL_FIELD2))
334 #define ROM_SYMBOL(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == SYMBOL_FIELD2))
336 // string third byte : 010xxxxx
337 #define STRING_FIELD2 0x40
338 #define RAM_STRING(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == STRING_FIELD2))
339 #define ROM_STRING(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == STRING_FIELD2))
341 // vector third byte : 011xxxxx
342 #define VECTOR_FIELD2 0x60
343 #define RAM_VECTOR(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == VECTOR_FIELD2))
344 #define ROM_VECTOR(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == VECTOR_FIELD2))
345 // TODO this is only for headers
347 // continuation third byte : 100xxxxx
348 #define CONTINUATION_FIELD2 0x80
349 #define RAM_CONTINUATION(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == CONTINUATION_FIELD2))
350 #define ROM_CONTINUATION(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == CONTINUATION_FIELD2))
352 // closure first byte : 01Gxxxxx
353 #define CLOSURE_FIELD0 0x40
354 #define RAM_CLOSURE(o) ((ram_get_field0 (o) & 0xc0) == CLOSURE_FIELD0)
355 #define ROM_CLOSURE(o) ((rom_get_field0 (o) & 0xc0) == CLOSURE_FIELD0)
358 /*---------------------------------------------------------------------------*/
360 #define RAM_GET_FIELD0_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,0))
361 #define RAM_SET_FIELD0_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,0), val)
362 #define ROM_GET_FIELD0_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,0))
364 #define RAM_GET_GC_TAGS_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x60)
365 #define RAM_GET_GC_TAG0_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x20)
366 #define RAM_GET_GC_TAG1_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x40)
367 #define RAM_SET_GC_TAGS_MACRO(o,tags) \
368 (RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0x9f) | (tags)))
369 #define RAM_SET_GC_TAG0_MACRO(o,tag) \
370 RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0xdf) | (tag))
371 #define RAM_SET_GC_TAG1_MACRO(o,tag) \
372 RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0xbf) | (tag))
375 #define RAM_GET_FIELD1_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,1))
376 #define RAM_GET_FIELD2_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,2))
377 #define RAM_GET_FIELD3_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,3))
378 #define RAM_SET_FIELD1_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,1), val)
379 #define RAM_SET_FIELD2_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,2), val)
380 #define RAM_SET_FIELD3_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,3), val)
381 #define ROM_GET_FIELD1_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,1))
382 #define ROM_GET_FIELD2_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,2))
383 #define ROM_GET_FIELD3_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,3))
384 #define VEC_GET_BYTE0_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,0))
385 #define VEC_GET_BYTE1_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,1))
386 #define VEC_GET_BYTE2_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,2))
387 #define VEC_GET_BYTE3_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,3))
388 #define VEC_SET_BYTE0_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,0), val)
389 #define VEC_SET_BYTE1_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,1), val)
390 #define VEC_SET_BYTE2_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,2), val)
391 #define VEC_SET_BYTE3_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,3), val)
392 // TODO put these in the ifdef ? and is the ifdef necessary ? are the vec macros necessary ? use the word field instead of byte, for consistency ?
395 uint8
ram_get_gc_tags (obj o
) { return RAM_GET_GC_TAGS_MACRO(o
); }
396 uint8
ram_get_gc_tag0 (obj o
) { return RAM_GET_GC_TAG0_MACRO(o
); }
397 uint8
ram_get_gc_tag1 (obj o
) { return RAM_GET_GC_TAG1_MACRO(o
); }
398 void ram_set_gc_tags (obj o
, uint8 tags
) { RAM_SET_GC_TAGS_MACRO(o
, tags
); }
399 void ram_set_gc_tag0 (obj o
, uint8 tag
) { RAM_SET_GC_TAG0_MACRO(o
,tag
); }
400 void ram_set_gc_tag1 (obj o
, uint8 tag
) { RAM_SET_GC_TAG1_MACRO(o
,tag
); }
401 uint8
ram_get_field0 (obj o
) { return RAM_GET_FIELD0_MACRO(o
); }
402 word
ram_get_field1 (obj o
) { return RAM_GET_FIELD1_MACRO(o
); }
403 word
ram_get_field2 (obj o
) { return RAM_GET_FIELD2_MACRO(o
); }
404 word
ram_get_field3 (obj o
) { return RAM_GET_FIELD3_MACRO(o
); }
405 void ram_set_field0 (obj o
, uint8 val
) { RAM_SET_FIELD0_MACRO(o
,val
); }
406 void ram_set_field1 (obj o
, word val
) { RAM_SET_FIELD1_MACRO(o
,val
); }
407 void ram_set_field2 (obj o
, word val
) { RAM_SET_FIELD2_MACRO(o
,val
); }
408 void ram_set_field3 (obj o
, word val
) { RAM_SET_FIELD3_MACRO(o
,val
); }
409 uint8
rom_get_field0 (obj o
) { return ROM_GET_FIELD0_MACRO(o
); }
410 word
rom_get_field1 (obj o
) { return ROM_GET_FIELD1_MACRO(o
); }
411 word
rom_get_field2 (obj o
) { return ROM_GET_FIELD2_MACRO(o
); }
412 word
rom_get_field3 (obj o
) { return ROM_GET_FIELD3_MACRO(o
); }
413 /* word vec_get_byte0 (obj o) { return VEC_GET_BYTE0_MACRO(o); } */
414 /* word vec_get_byte1 (obj o) { return VEC_GET_BYTE1_MACRO(o); } */
415 /* word vec_get_byte2 (obj o) { return VEC_GET_BYTE2_MACRO(o); } */
416 /* word vec_get_byte3 (obj o) { return VEC_GET_BYTE3_MACRO(o); } */
417 /* word vec_set_byte0 (obj o, word val) { VEC_SET_BYTE0_MACRO(o,val); } */
418 /* word vec_set_byte1 (obj o, word val) { VEC_SET_BYTE1_MACRO(o,val); } */
419 /* word vec_set_byte2 (obj o, word val) { VEC_SET_BYTE2_MACRO(o,val); } */
420 /* word vec_set_byte3 (obj o, word val) { VEC_SET_BYTE3_MACRO(o,val); } */
421 // TODO use the word field or byte ? actually the ram functions are used, since this is in ram anyways
423 obj
ram_get_car (obj o
)
424 { return ((ram_get_field0 (o
) & 0x1f) << 8) | ram_get_field1 (o
); }
425 obj
rom_get_car (obj o
)
426 { return ((rom_get_field0 (o
) & 0x1f) << 8) | rom_get_field1 (o
); }
427 obj
ram_get_cdr (obj o
)
428 { return ((ram_get_field2 (o
) & 0x1f) << 8) | ram_get_field3 (o
); }
429 obj
rom_get_cdr (obj o
)
430 { return ((rom_get_field2 (o
) & 0x1f) << 8) | rom_get_field3 (o
); }
431 void ram_set_car (obj o
, obj val
)
433 ram_set_field0 (o
, (val
>> 8) | (ram_get_field0 (o
) & 0xe0));
434 ram_set_field1 (o
, val
& 0xff);
436 void ram_set_cdr (obj o
, obj val
)
438 ram_set_field2 (o
, (val
>> 8) | (ram_get_field2 (o
) & 0xe0));
439 ram_set_field3 (o
, val
& 0xff);
441 obj
ram_get_entry (obj o
)
443 return (((ram_get_field0 (o
) & 0x1f) << 11)
444 | (ram_get_field1 (o
) << 3)
445 | (ram_get_field2 (o
) >> 5));
447 obj
rom_get_entry (obj o
)
449 return (((rom_get_field0 (o
) & 0x1f) << 11)
450 | (rom_get_field1 (o
) << 3)
451 | (rom_get_field2 (o
) >> 5));
454 obj
get_global (uint8 i
)
459 void set_global (uint8 i
, obj o
)
465 void show_type (obj o
) // for debugging purposes
468 if (o
== OBJ_FALSE
) printf("#f");
469 else if (o
== OBJ_TRUE
) printf("#t");
470 else if (o
== OBJ_NULL
) printf("()");
471 else if (o
< MIN_ROM_ENCODING
) printf("fixnum");
474 if (RAM_BIGNUM(o
)) printf("ram bignum");
475 else if (RAM_PAIR(o
)) printf("ram pair");
476 else if (RAM_SYMBOL(o
)) printf("ram symbol");
477 else if (RAM_STRING(o
)) printf("ram string");
478 else if (RAM_VECTOR(o
)) printf("ram vector");
479 else if (RAM_CONTINUATION(o
)) printf("ram continuation");
480 else if (RAM_CLOSURE(o
)) printf("ram closure");
484 if (ROM_BIGNUM(o
)) printf("rom bignum");
485 else if (ROM_PAIR(o
)) printf("rom pair");
486 else if (ROM_SYMBOL(o
)) printf("rom symbol");
487 else if (ROM_STRING(o
)) printf("rom string");
488 else if (ROM_VECTOR(o
)) printf("rom vector");
489 else if (ROM_CONTINUATION(o
)) printf("rom continuation");
490 else if (RAM_CLOSURE(o
)) printf("rom closure");
497 /*---------------------------------------------------------------------------*/
499 /* Interface to GC */
501 // TODO explain what each tag means, with 1-2 mark bits
502 #define GC_TAG_0_LEFT (1<<5)
503 // TODO was 3<<5, changed to play nice with procedures and bignums, but should actually set only this bit, not clear the other
504 #define GC_TAG_1_LEFT (2<<5)
505 #define GC_TAG_UNMARKED (0<<5)
507 /* Number of object fields of objects in ram */
508 #define HAS_2_OBJECT_FIELDS(visit) (RAM_PAIR(visit) || RAM_CONTINUATION(visit))
509 #define HAS_1_OBJECT_FIELD(visit) (RAM_COMPOSITE(visit) || RAM_CLOSURE(visit))
510 // all composites except pairs and continuations have 1 object field
511 // TODO if we ever have true bignums, bignums will have 1 object field
513 #define NIL OBJ_FALSE
515 /*---------------------------------------------------------------------------*/
517 /* Garbage collector */
519 obj free_list
; /* list of unused cells */
520 obj free_list_vec
; /* list of unused cells in vector space */
522 obj arg1
; /* root set */
529 uint8 na
; /* interpreter variables */
539 void init_ram_heap (void)
542 obj o
= MAX_RAM_ENCODING
;
546 while (o
>= MIN_RAM_ENCODING
)
548 ram_set_gc_tags (o
, GC_TAG_UNMARKED
);
549 ram_set_car (o
, free_list
);
554 free_list_vec
= MIN_VEC_ENCODING
;
555 ram_set_car (free_list_vec
, 0); // TODO is ram_set_car appropriate ? now we have vector space objects that can either be a list or 4 bytes
556 // each node of the free list must know the free length that follows it
557 // this free length is stored in words, not in bytes
558 // if we did count in bytes, the number might need more than 13 bits
559 ram_set_cdr (free_list_vec
, VEC_BYTES
/ 4);
560 // TODO so, at the start, we have only 1 node that says the whole space is free
562 for (i
=0; i
<GLOVARS
; i
++)
563 set_global (i
, OBJ_FALSE
);
590 // IF_GC_TRACE(printf ("push stack=%d (tag=%d) visit=%d (tag=%d)\n", stack, ram_get_gc_tags (stack)>>5, visit, ram_get_gc_tags (visit)>>5)); // TODO error here, tried to get the tag of nil
591 IF_GC_TRACE(printf ("push stack=%d visit=%d (tag=%d)\n", stack
, visit
, ram_get_gc_tags (visit
)>>5));
593 if ((HAS_1_OBJECT_FIELD (visit
) && ram_get_gc_tag0 (visit
))
594 || (HAS_2_OBJECT_FIELDS (visit
)
595 && (ram_get_gc_tags (visit
) != GC_TAG_UNMARKED
)))
596 // TODO ugly condition
597 IF_GC_TRACE(printf ("case 1\n"));
600 if (HAS_2_OBJECT_FIELDS(visit
)) // pairs and continuations
602 IF_GC_TRACE(printf ("case 5\n"));
606 temp
= ram_get_cdr (visit
);
610 IF_GC_TRACE(printf ("case 6\n"));
611 ram_set_gc_tags (visit
, GC_TAG_1_LEFT
);
612 ram_set_cdr (visit
, stack
);
616 IF_GC_TRACE(printf ("case 7\n"));
621 if (HAS_1_OBJECT_FIELD(visit
))
623 IF_GC_TRACE(printf ("case 8\n"));
627 if (RAM_CLOSURE(visit
)) // closures have the pointer in the cdr
628 temp
= ram_get_cdr (visit
);
630 temp
= ram_get_car (visit
);
634 IF_GC_TRACE(printf ("case 9\n"));
635 ram_set_gc_tag0 (visit
, GC_TAG_0_LEFT
);
636 if (RAM_CLOSURE(visit
))
637 ram_set_cdr (visit
, stack
);
639 ram_set_car (visit
, stack
);
644 IF_GC_TRACE(printf ("case 10\n"));
647 IF_GC_TRACE(printf ("case 11\n"));
649 ram_set_gc_tag0 (visit
, GC_TAG_0_LEFT
);
654 /* IF_GC_TRACE(printf ("pop stack=%d (tag=%d) visit=%d (tag=%d)\n", stack, ram_get_gc_tags (stack)>>6, visit, ram_get_gc_tags (visit)>>6)); */
655 // TODO, like for push, getting the gc tags of nil is not great
656 IF_GC_TRACE(printf ("pop stack=%d visit=%d (tag=%d)\n", stack
, visit
, ram_get_gc_tags (visit
)>>6));
660 if (HAS_2_OBJECT_FIELDS(stack
) && ram_get_gc_tag1 (stack
))
662 IF_GC_TRACE(printf ("case 13\n"));
664 temp
= ram_get_cdr (stack
); /* pop through cdr */
665 ram_set_cdr (stack
, visit
);
669 ram_set_gc_tag1(visit
, GC_TAG_UNMARKED
);
670 // we unset the "1-left" bit
675 if (RAM_CLOSURE(stack
))
676 // closures have one object field, but it's in the cdr
678 IF_GC_TRACE(printf ("case 13.5\n")); // TODO renumber cases
680 temp
= ram_get_cdr (stack
); /* pop through cdr */
681 ram_set_cdr (stack
, visit
);
688 IF_GC_TRACE(printf ("case 14\n"));
690 temp
= ram_get_car (stack
); /* pop through car */
691 ram_set_car (stack
, visit
);
712 obj visit
= MAX_RAM_ENCODING
;
716 while (visit
>= MIN_RAM_ENCODING
)
718 if ((RAM_COMPOSITE(visit
)
719 && (ram_get_gc_tags (visit
) == GC_TAG_UNMARKED
)) // 2 mark bit
720 || !(ram_get_gc_tags (visit
) & GC_TAG_0_LEFT
)) // 1 mark bit
723 if (RAM_VECTOR(visit
))
724 // when we sweep a vector, we also have to sweep its contents
726 obj o
= ram_get_cdr (visit
);
727 uint16 i
= ram_get_car (visit
); // number of elements
728 ram_set_car (o
, free_list_vec
);
729 ram_set_cdr (o
, (i
+ 3) / 4); // free length, in words
731 // TODO fuse free spaces if needed ? would be a good idea FOOBAR or maybe just fuse when we call the gc ? actually, compacting might be a better idea, but would need a second header in vector space that would point to the header in ram
733 ram_set_car (visit
, free_list
);
738 if (RAM_COMPOSITE(visit
))
739 ram_set_gc_tags (visit
, GC_TAG_UNMARKED
);
740 else // only 1 mark bit to unset
741 ram_set_gc_tag0 (visit
, GC_TAG_UNMARKED
);
753 printf ("**************** memory needed = %d\n", max_live
+1);
763 IF_GC_TRACE(printf("\nGC BEGINS\n"));
765 IF_GC_TRACE(printf("arg1\n"));
767 IF_GC_TRACE(printf("arg2\n"));
769 IF_GC_TRACE(printf("arg3\n"));
771 IF_GC_TRACE(printf("arg4\n"));
773 IF_GC_TRACE(printf("cont\n"));
775 IF_GC_TRACE(printf("env\n"));
776 mark (env
); // TODO do we mark the free list or do we rebuild it every time ? what about vectors ?
778 for (i
=0; i
<GLOVARS
; i
++)
779 mark (get_global (i
));
784 obj
alloc_ram_cell (void)
798 ERROR("memory is full");
803 free_list
= ram_get_car (o
);
808 obj
alloc_ram_cell_init (uint8 f0
, uint8 f1
, uint8 f2
, uint8 f3
)
810 obj o
= alloc_ram_cell ();
812 ram_set_field0 (o
, f0
);
813 ram_set_field1 (o
, f1
);
814 ram_set_field2 (o
, f2
);
815 ram_set_field3 (o
, f3
);
820 obj
alloc_vec_cell (uint16 n
) // TODO add a init version ?
822 obj o
= free_list_vec
;
831 while ((ram_get_cdr (o
) * 4) < n
) // free space too small
832 { // TODO BREGG IMPORTANT : si on atteint le fond de la free list, 0, le get_cdr foire, et on meurt avant de pouvoir faire du gc
833 if (o
== 0) // no free space, or none big enough
835 if (gc_done
) // we gc'd, but no space is big enough for the vector
836 ERROR("no room for vector");
844 } // TODO fuse adjacent free spaces, and maybe compact ? FOOBAR
849 // case 1 : the new vector fills every free word advertized, we remove the
850 // node from the free list
851 // TODO mettre le cdr de o dans une var temporaire ?
852 if ((n
- (ram_get_cdr(o
) * 4)) < 4) // TODO is there a better way ?
855 ram_set_car (prec
, ram_get_car (o
));
857 free_list_vec
= ram_get_car (o
);
859 // case 2 : there is still some space left in the free section, create a new
860 // node to represent this space
863 obj new_free
= o
+ (n
+ 3)/4;
865 ram_set_car (prec
, new_free
);
867 free_list_vec
= new_free
;
868 ram_set_car (new_free
, ram_get_car (o
));
869 ram_set_cdr (new_free
, ram_get_cdr (o
) - (n
+ 3)/4); // TODO documenter structure de cette free list quelque part
875 /*---------------------------------------------------------------------------*/
877 int32
decode_int (obj o
)
883 if (o
< MIN_FIXNUM_ENCODING
)
884 TYPE_ERROR("integer");
886 if (o
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
887 return DECODE_FIXNUM(o
);
892 TYPE_ERROR("integer");
894 u
= ram_get_field1 (o
);
895 h
= ram_get_field2 (o
);
896 l
= ram_get_field3 (o
);
901 TYPE_ERROR("integer");
903 u
= rom_get_field1 (o
);
904 h
= rom_get_field2 (o
);
905 l
= rom_get_field3 (o
);
908 TYPE_ERROR("integer");
911 return ((int32
)((((int16
)u
- 256) << 8) + h
) << 8) + l
;
913 return ((int32
)(((int16
)u
<< 8) + h
) << 8) + l
;
916 obj
encode_int (int32 n
)
918 if (n
>= MIN_FIXNUM
&& n
<= MAX_FIXNUM
)
919 return ENCODE_FIXNUM(n
);
921 return alloc_ram_cell_init (BIGNUM_FIELD0
, n
>> 16, n
>> 8, n
);
924 /*---------------------------------------------------------------------------*/
936 else if (o
== OBJ_TRUE
)
938 else if (o
== OBJ_NULL
)
940 else if (o
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
941 printf ("%d", DECODE_FIXNUM(o
));
942 else // TODO past here, everything is either in ram or in rom, until we add a 3rd space for vectors, that is
951 if ((in_ram
&& RAM_BIGNUM(o
)) || (!in_ram
&& ROM_BIGNUM(o
)))
952 printf ("%d", decode_int (o
));
953 else if ((in_ram
&& RAM_COMPOSITE(o
)) || (!in_ram
&& ROM_COMPOSITE(o
)))
958 if ((in_ram
&& RAM_PAIR(o
)) || (!in_ram
&& ROM_PAIR(o
))) // TODO not exactly efficient, fix it
962 car
= ram_get_car (o
);
963 cdr
= ram_get_cdr (o
);
967 car
= rom_get_car (o
);
968 cdr
= rom_get_cdr (o
);
979 else if ((IN_RAM(cdr
) && RAM_PAIR(cdr
))
980 || (IN_ROM(cdr
) && ROM_PAIR(cdr
)))
984 car
= ram_get_car (cdr
);
985 cdr
= ram_get_cdr (cdr
);
989 car
= rom_get_car (cdr
);
990 cdr
= rom_get_cdr (cdr
);
1003 else if ((in_ram
&& RAM_SYMBOL(o
)) || (!in_ram
&& ROM_SYMBOL(o
)))
1004 printf ("#<symbol>");
1005 else if ((in_ram
&& RAM_STRING(o
)) || (!in_ram
&& ROM_STRING(o
)))
1006 printf ("#<string>");
1007 else if ((in_ram
&& RAM_VECTOR(o
)) || (!in_ram
&& ROM_VECTOR(o
)))
1008 printf ("#<vector %d>", o
); // TODO do better DEBUG BREGG
1012 car
= ram_get_car (o
);
1013 cdr
= ram_get_cdr (o
);
1014 goto loop
; // TODO ugly hack, takes advantage of the fact that pairs and continuations have the same layout
1022 if (IN_RAM(o
)) // TODO can closures be in rom ? I don't think so
1023 env
= ram_get_cdr (o
);
1025 env
= rom_get_cdr (o
);
1028 pc
= ram_get_entry (o
);
1030 pc
= rom_get_entry (o
);
1032 printf ("{0x%04x ", pc
);
1041 void show_state (rom_addr pc
)
1044 printf ("pc=0x%04x bytecode=0x%02x env=", pc
, rom_get (pc
));
1061 /*---------------------------------------------------------------------------*/
1063 /* Integer operations */
1065 #define encode_bool(x) ((obj)(x))
1067 void prim_numberp (void)
1069 if (arg1
>= MIN_FIXNUM_ENCODING
1070 && arg1
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
1075 arg1
= encode_bool (RAM_BIGNUM(arg1
));
1076 else if (IN_ROM(arg1
))
1077 arg1
= encode_bool (ROM_BIGNUM(arg1
));
1083 void decode_2_int_args (void)
1085 a1
= decode_int (arg1
);
1086 a2
= decode_int (arg2
);
1089 void prim_add (void)
1091 decode_2_int_args ();
1092 arg1
= encode_int (a1
+ a2
);
1096 void prim_sub (void)
1098 decode_2_int_args ();
1099 arg1
= encode_int (a1
- a2
);
1103 void prim_mul (void)
1105 decode_2_int_args ();
1106 arg1
= encode_int (a1
* a2
);
1110 void prim_div (void)
1112 decode_2_int_args ();
1114 ERROR("divide by 0");
1115 arg1
= encode_int (a1
/ a2
);
1119 void prim_rem (void)
1121 decode_2_int_args ();
1123 ERROR("divide by 0");
1124 arg1
= encode_int (a1
% a2
);
1128 void prim_neg (void)
1130 a1
= decode_int (arg1
);
1131 arg1
= encode_int (- a1
);
1136 decode_2_int_args ();
1137 arg1
= encode_bool (a1
== a2
);
1143 decode_2_int_args ();
1144 arg1
= encode_bool (a1
< a2
);
1150 decode_2_int_args ();
1151 arg1
= encode_bool (a1
> a2
);
1155 void prim_ior (void)
1157 a1
= decode_int (arg1
);
1158 a2
= decode_int (arg2
);
1159 arg1
= encode_int (a1
| a2
);
1163 void prim_xor (void)
1165 a1
= decode_int (arg1
);
1166 a2
= decode_int (arg2
);
1167 arg1
= encode_int (a1
^ a2
);
1172 /*---------------------------------------------------------------------------*/
1174 /* List operations */
1176 void prim_pairp (void)
1179 arg1
= encode_bool (RAM_PAIR(arg1
));
1180 else if (IN_ROM(arg1
))
1181 arg1
= encode_bool (ROM_PAIR(arg1
));
1186 obj
cons (obj car
, obj cdr
)
1188 return alloc_ram_cell_init (COMPOSITE_FIELD0
| (car
>> 8), // TODO was ((car & 0x1f00) >> 8), probably redundant
1190 PAIR_FIELD2
| (cdr
>> 8), // TODO was ((cdr & 0x1f00) >> 8), probably redundant
1194 void prim_cons (void)
1196 arg1
= cons (arg1
, arg2
);
1200 void prim_car (void)
1204 if (!RAM_PAIR(arg1
))
1206 arg1
= ram_get_car (arg1
);
1208 else if (IN_ROM(arg1
))
1210 if (!ROM_PAIR(arg1
))
1212 arg1
= rom_get_car (arg1
);
1220 void prim_cdr (void)
1224 if (!RAM_PAIR(arg1
))
1226 arg1
= ram_get_cdr (arg1
);
1228 else if (IN_ROM(arg1
))
1230 if (!ROM_PAIR(arg1
))
1232 arg1
= rom_get_cdr (arg1
);
1240 void prim_set_car (void)
1244 if (!RAM_PAIR(arg1
))
1247 ram_set_car (arg1
, arg2
);
1257 void prim_set_cdr (void)
1261 if (!RAM_PAIR(arg1
))
1264 ram_set_cdr (arg1
, arg2
);
1274 void prim_nullp (void)
1276 arg1
= encode_bool (arg1
== OBJ_NULL
);
1279 /*---------------------------------------------------------------------------*/
1281 /* Vector operations */
1283 void prim_u8vectorp (void)
1286 arg1
= encode_bool (RAM_VECTOR(arg1
));
1287 else if (IN_ROM(arg1
))
1288 arg1
= encode_bool (ROM_VECTOR(arg1
));
1293 void prim_make_u8vector (void)
1295 obj elems
= alloc_vec_cell (arg1
); // arg1 is length
1296 arg1
= alloc_ram_cell_init (COMPOSITE_FIELD0
| (arg1
>> 8),
1298 VECTOR_FIELD2
| (elems
>> 8),
1300 // the contents of the vector are intentionally left as they were.
1301 // it is up to the library functions to set them accordingly
1304 void prim_u8vector_ref (void)
1305 { // TODO how do we deal with rom vectors ? as lists ? they're never all that long
1306 arg2
= decode_int (arg2
);
1310 if (!RAM_VECTOR(arg1
))
1311 TYPE_ERROR("vector");
1312 if (ram_get_car (arg1
) < arg2
)
1313 ERROR("vector index too large");
1314 arg1
= ram_get_cdr (arg1
);
1316 else if (IN_ROM(arg1
))
1318 if (!ROM_VECTOR(arg1
))
1319 TYPE_ERROR("vector");
1320 if (rom_get_car (arg1
) < arg2
)
1321 ERROR("vector index too large");
1322 arg1
= rom_get_cdr (arg1
);
1325 TYPE_ERROR("vector");
1335 arg1
= ram_get_field0 (arg1
); break;
1337 arg1
= ram_get_field1 (arg1
); break;
1339 arg1
= ram_get_field2 (arg1
); break;
1341 arg1
= ram_get_field3 (arg1
); break;
1344 arg1
= encode_int (arg1
);
1346 else // rom vector, stored as a list
1347 { // TODO since these are stored as lists, nothing prevents us from having ordinary vectors, and not just byte vectors. in rom, both are lists so they are the same. in ram, byte vectors are in vector space, while ordinary vectors are still lists (the functions are already in the library)
1349 arg1
= rom_get_cdr (arg1
);
1351 arg1
= rom_get_car (arg1
);
1357 void prim_u8vector_set (void)
1358 { // TODO a lot in common with ref, abstract that
1359 arg2
= decode_int (arg2
);
1360 arg3
= decode_int (arg3
);
1363 ERROR("byte vectors can only contain bytes");
1367 if (!RAM_VECTOR(arg1
))
1368 TYPE_ERROR("vector");
1369 if (ram_get_car (arg1
) < arg2
)
1370 ERROR("vector index too large");
1371 arg1
= ram_get_cdr (arg1
);
1373 // TODO no rom vector header can point to vector space, right ?
1375 TYPE_ERROR("vector");
1383 ram_set_field0 (arg1
, arg3
); break;
1385 ram_set_field1 (arg1
, arg3
); break;
1387 ram_set_field2 (arg1
, arg3
); break;
1389 ram_set_field3 (arg1
, arg3
); break;
1397 void prim_u8vector_length (void)
1401 if (!RAM_VECTOR(arg1
))
1402 TYPE_ERROR("vector");
1403 arg1
= encode_int (ram_get_car (arg1
));
1405 else if (IN_ROM(arg1
))
1407 if (!ROM_VECTOR(arg1
))
1408 TYPE_ERROR("vector");
1409 arg1
= rom_get_car (arg1
);
1412 TYPE_ERROR("vector");
1415 /*---------------------------------------------------------------------------*/
1417 /* Miscellaneous operations */
1419 void prim_eqp (void)
1421 arg1
= encode_bool (arg1
== arg2
);
1425 void prim_not (void)
1427 arg1
= encode_bool (arg1
== OBJ_FALSE
);
1430 void prim_symbolp (void)
1433 arg1
= encode_bool (RAM_SYMBOL(arg1
));
1434 else if (IN_ROM(arg1
))
1435 arg1
= encode_bool (ROM_SYMBOL(arg1
));
1440 void prim_stringp (void)
1443 arg1
= encode_bool (RAM_STRING(arg1
));
1444 else if (IN_ROM(arg1
))
1445 arg1
= encode_bool (ROM_STRING(arg1
));
1450 void prim_string2list (void)
1454 if (!RAM_STRING(arg1
))
1455 TYPE_ERROR("string");
1457 arg1
= ram_get_car (arg1
);
1459 else if (IN_ROM(arg1
))
1461 if (!ROM_STRING(arg1
))
1462 TYPE_ERROR("string");
1464 arg1
= rom_get_car (arg1
);
1467 TYPE_ERROR("string");
1470 void prim_list2string (void)
1472 arg1
= alloc_ram_cell_init (COMPOSITE_FIELD0
| ((arg1
& 0x1f00) >> 8),
1479 /*---------------------------------------------------------------------------*/
1481 /* Robot specific operations */
1484 void prim_print (void)
1499 int32
read_clock (void)
1505 now
= from_now( 0 );
1513 static int32 start
= 0;
1518 now
= tb
.time
* 1000 + tb
.millitm
;
1525 static int32 start
= 0;
1528 if (gettimeofday (&tv
, NULL
) == 0)
1530 now
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
1544 void prim_clock (void)
1546 arg1
= encode_int (read_clock ());
1550 void prim_motor (void)
1552 decode_2_int_args ();
1554 if (a1
< 1 || a1
> 2 || a2
< -100 || a2
> 100)
1555 ERROR("argument out of range to procedure \"motor\"");
1565 printf ("motor %d -> power=%d\n", a1
, a2
);
1575 void prim_led (void)
1577 decode_2_int_args ();
1578 a3
= decode_int (arg3
);
1580 if (a1
< 1 || a1
> 3 || a2
< 0 || a3
< 0)
1581 ERROR("argument out of range to procedure \"led\"");
1585 LED_set( a1
, a2
, a3
);
1591 printf ("led %d -> duty=%d period=%d\n", a1
, a2
, a3
);
1602 void prim_led2_color (void)
1604 a1
= decode_int (arg1
);
1606 if (a1
< 0 || a1
> 1)
1607 ERROR("argument out of range to procedure \"led2-color\"");
1611 LED2_color_set( a1
);
1617 printf ("led2-color -> %s\n", (a1
==0)?"green":"red");
1626 void prim_getchar_wait (void)
1628 decode_2_int_args();
1629 a1
= read_clock () + a1
;
1631 if (a1
< 0 || a2
< 1 || a2
> 3)
1632 ERROR("argument out of range to procedure \"getchar-wait\"");
1639 serial_port_set ports
;
1640 ports
= serial_rx_wait_with_timeout( a2
, a1
);
1642 arg1
= encode_int (serial_rx_read( ports
));
1657 arg1
= encode_int (_getch ());
1660 } while (read_clock () < a1
);
1665 arg1
= encode_int (getchar ());
1673 void prim_putchar (void)
1675 decode_2_int_args ();
1677 if (a1
< 0 || a1
> 255 || a2
< 1 || a2
> 3)
1678 ERROR("argument out of range to procedure \"putchar\"");
1682 serial_tx_write( a2
, a1
);
1698 void prim_beep (void)
1700 decode_2_int_args ();
1702 if (a1
< 1 || a1
> 255 || a2
< 0)
1703 ERROR("argument out of range to procedure \"beep\"");
1707 beep( a1
, from_now( a2
) );
1713 printf ("beep -> freq-div=%d duration=%d\n", a1
, a2
);
1723 void prim_adc (void)
1727 a1
= decode_int (arg1
);
1729 if (a1
< 1 || a1
> 3)
1730 ERROR("argument out of range to procedure \"adc\"");
1740 x
= read_clock () & 255;
1742 if (x
> 127) x
= 256 - x
;
1748 arg1
= encode_int (x
);
1752 void prim_dac (void)
1754 a1
= decode_int (arg1
);
1756 if (a1
< 0 || a1
> 255)
1757 ERROR("argument out of range to procedure \"dac\"");
1767 printf ("dac -> %d\n", a1
);
1776 void prim_sernum (void)
1792 arg1
= encode_int (x
);
1796 /*---------------------------------------------------------------------------*/
1800 int hidden_fgetc (FILE *f
)
1810 #define fgetc(f) hidden_fgetc(f)
1812 void write_hex_nibble (int n
)
1814 putchar ("0123456789ABCDEF"[n
]);
1817 void write_hex (uint8 n
)
1819 write_hex_nibble (n
>> 4);
1820 write_hex_nibble (n
& 0x0f);
1825 if (c
>= '0' && c
<= '9')
1828 if (c
>= 'A' && c
<= 'F')
1829 return (c
- 'A' + 10);
1831 if (c
>= 'a' && c
<= 'f')
1832 return (c
- 'a' + 10);
1837 int read_hex_byte (FILE *f
)
1839 int h1
= hex (fgetc (f
));
1840 int h2
= hex (fgetc (f
));
1842 if (h1
>= 0 && h2
>= 0)
1843 return (h1
<<4) + h2
;
1848 int read_hex_file (char *filename
)
1851 FILE *f
= fopen (filename
, "r");
1861 for (i
=0; i
<ROM_BYTES
; i
++)
1866 while ((c
= fgetc (f
)) != EOF
)
1868 if ((c
== '\r') || (c
== '\n'))
1872 (len
= read_hex_byte (f
)) < 0 ||
1873 (a1
= read_hex_byte (f
)) < 0 ||
1874 (a2
= read_hex_byte (f
)) < 0 ||
1875 (t
= read_hex_byte (f
)) < 0)
1881 sum
= len
+ a1
+ a2
+ t
;
1889 unsigned long adr
= ((unsigned long)hi16
<< 16) + a
- CODE_START
;
1891 if ((b
= read_hex_byte (f
)) < 0)
1894 if (adr
>= 0 && adr
< ROM_BYTES
)
1897 a
= (a
+ 1) & 0xffff;
1914 if ((a1
= read_hex_byte (f
)) < 0 ||
1915 (a2
= read_hex_byte (f
)) < 0)
1920 hi16
= (a1
<<8) + a2
;
1925 if ((b
= read_hex_byte (f
)) < 0)
1932 printf ("*** HEX file checksum error (expected 0x%02x)\n", sum
);
1938 if ((c
!= '\r') && (c
!= '\n'))
1949 printf ("*** HEX file syntax error\n");
1959 /*---------------------------------------------------------------------------*/
1961 #define FETCH_NEXT_BYTECODE() bytecode = rom_get (pc++)
1963 #define BEGIN_DISPATCH() \
1965 IF_TRACE(show_state (pc)); \
1966 FETCH_NEXT_BYTECODE(); \
1967 bytecode_hi4 = bytecode & 0xf0; \
1968 bytecode_lo4 = bytecode & 0x0f; \
1969 switch (bytecode_hi4 >> 4) {
1971 #define END_DISPATCH() }
1973 #define CASE(opcode) case (opcode>>4):;
1975 #define DISPATCH(); goto dispatch;
1980 #define bytecode TABLAT
1981 #define bytecode_hi4 WREG
1984 #define PUSH_CONSTANT1 0x00
1985 #define PUSH_CONSTANT2 0x10
1986 #define PUSH_STACK1 0x20
1987 #define PUSH_STACK2 0x30
1988 #define PUSH_GLOBAL 0x40
1989 #define SET_GLOBAL 0x50
1992 #define LABEL_INSTR 0x80
1993 #define PUSH_CONSTANT_LONG 0x90
1995 // TODO these are free
1997 #define GOTO_IF_FALSE 0xb0
1998 #define CLOSURE 0xc0
2006 char *prim_name
[48] =
2030 "prim #%graft-to-cont",
2031 "prim #%return-to-cont",
2035 "prim #%string->list",
2036 "prim #%list->string",
2037 "prim #%make-u8vector", // TODO was prim29
2038 "prim #%u8vector-ref", // TODO was prim30
2039 "prim #%u8vector-set!", // TODO was prim31
2044 "prim #%led2-color",
2045 "prim #%getchar-wait",
2049 "prim #%u8vector?", // TODO was dac, but it's not plugged to anything
2051 "prim #%u8vector-length", // TODO was prim43
2052 "push-constant [long]",
2060 #define PUSH_ARG1() push_arg1 ()
2063 void push_arg1 (void)
2065 env
= cons (arg1
, env
);
2071 obj o
= ram_get_car (env
);
2072 env
= ram_get_cdr (env
);
2076 void pop_procedure (void)
2082 if (!RAM_CLOSURE(arg1
))
2083 TYPE_ERROR("procedure");
2085 entry
= ram_get_entry (arg1
) + CODE_START
; // FOO all addresses in the bytecode should be from 0, not from CODE_START, should be fixed everywhere, but might not be
2087 else if (IN_ROM(arg1
))
2089 if (!ROM_CLOSURE(arg1
))
2090 TYPE_ERROR("procedure");
2092 entry
= rom_get_entry (arg1
) + CODE_START
;
2095 TYPE_ERROR("procedure");
2098 void handle_arity_and_rest_param (void)
2102 np
= rom_get (entry
++);
2104 if ((np
& 0x80) == 0)
2107 ERROR("wrong number of arguments");
2114 ERROR("wrong number of arguments");
2122 arg3
= cons (arg4
, arg3
);
2128 arg1
= cons (arg3
, arg1
);
2133 void build_env (void)
2139 arg1
= cons (arg3
, arg1
);
2147 void save_cont (void)
2149 // the second half is a closure
2150 arg3
= alloc_ram_cell_init (CLOSURE_FIELD0
| (pc
>> 11),
2152 ((pc
& 0x0007) << 5) | (env
>> 8),
2154 cont
= alloc_ram_cell_init (COMPOSITE_FIELD0
| (cont
>> 8),
2156 CONTINUATION_FIELD2
| (arg3
>> 8),
2161 void interpreter (void)
2165 pc
= (CODE_START
+ 4) + ((rom_addr
)rom_get (CODE_START
+2) << 2);
2169 /***************************************************************************/
2170 CASE(PUSH_CONSTANT1
);
2172 IF_TRACE(printf(" (push-constant "); show (bytecode_lo4
); printf (")\n"));
2174 arg1
= bytecode_lo4
;
2180 /***************************************************************************/
2181 CASE(PUSH_CONSTANT2
);
2183 IF_TRACE(printf(" (push-constant "); show (bytecode_lo4
+16); printf (")\n"));
2184 arg1
= bytecode_lo4
+16;
2190 /***************************************************************************/
2193 IF_TRACE(printf(" (push-stack %d)\n", bytecode_lo4
));
2197 while (bytecode_lo4
!= 0)
2199 arg1
= ram_get_cdr (arg1
);
2203 arg1
= ram_get_car (arg1
);
2209 /***************************************************************************/
2212 IF_TRACE(printf(" (push-stack %d)\n", bytecode_lo4
+16));
2213 // TODO does this ever happens ?
2218 while (bytecode_lo4
!= 0)
2220 arg1
= ram_get_cdr (arg1
);
2224 arg1
= ram_get_car (arg1
);
2230 /***************************************************************************/
2233 IF_TRACE(printf(" (push-global %d)\n", bytecode_lo4
));
2235 arg1
= get_global (bytecode_lo4
);
2241 /***************************************************************************/
2244 IF_TRACE(printf(" (set-global %d)\n", bytecode_lo4
));
2246 set_global (bytecode_lo4
, POP());
2250 /***************************************************************************/
2253 IF_TRACE(printf(" (call %d)\n", bytecode_lo4
));
2258 handle_arity_and_rest_param ();
2269 /***************************************************************************/
2272 IF_TRACE(printf(" (jump %d)\n", bytecode_lo4
));
2277 handle_arity_and_rest_param ();
2287 /***************************************************************************/
2290 switch (bytecode_lo4
)
2292 case 0: // call-toplevel TODO put these in separate functions ?
2293 FETCH_NEXT_BYTECODE();
2296 FETCH_NEXT_BYTECODE();
2298 IF_TRACE(printf(" (call-toplevel 0x%04x)\n",
2299 ((arg2
<< 8) | bytecode
) + CODE_START
));
2301 entry
= (arg2
<< 8) + bytecode
+ CODE_START
;
2304 na
= rom_get (entry
++);
2317 case 1: // jump-toplevel
2318 FETCH_NEXT_BYTECODE();
2321 FETCH_NEXT_BYTECODE();
2323 IF_TRACE(printf(" (jump-toplevel 0x%04x)\n",
2324 ((arg2
<< 8) | bytecode
) + CODE_START
));
2326 entry
= (arg2
<< 8) + bytecode
+ CODE_START
; // TODO this is a common pattern
2329 na
= rom_get (entry
++);
2342 FETCH_NEXT_BYTECODE();
2345 FETCH_NEXT_BYTECODE();
2347 IF_TRACE(printf(" (goto 0x%04x)\n",
2348 (arg2
<< 8) + bytecode
+ CODE_START
));
2350 pc
= (arg2
<< 8) + bytecode
+ CODE_START
;
2354 case 3: // goto-if-false
2355 FETCH_NEXT_BYTECODE();
2358 FETCH_NEXT_BYTECODE();
2360 IF_TRACE(printf(" (goto-if-false 0x%04x)\n",
2361 (arg2
<< 8) + bytecode
+ CODE_START
));
2363 if (POP() == OBJ_FALSE
)
2364 pc
= (arg2
<< 8) + bytecode
+ CODE_START
;
2369 FETCH_NEXT_BYTECODE();
2372 FETCH_NEXT_BYTECODE();
2374 IF_TRACE(printf(" (closure 0x%04x)\n", (arg2
<< 8) | bytecode
));
2376 arg3
= POP(); // env
2378 entry
= (arg2
<< 8) | bytecode
;
2380 arg1
= alloc_ram_cell_init (CLOSURE_FIELD0
| (arg2
>> 3),
2381 ((arg2
& 0x07) << 5) | (bytecode
>> 3),
2382 ((bytecode
&0x07) <<5) |((arg3
&0x1f00) >>8),
2392 case 5: // call-toplevel-short
2393 FETCH_NEXT_BYTECODE(); // TODO the sort version have a lot in common with the long ones, abstract ?
2394 // TODO short instructions don't work at the moment
2395 IF_TRACE(printf(" (call-toplevel-short 0x%04x)\n",
2396 pc
+ bytecode
+ CODE_START
));
2398 entry
= pc
+ bytecode
+ CODE_START
;
2401 na
= rom_get (entry
++);
2413 case 6: // jump-toplevel-short
2414 FETCH_NEXT_BYTECODE();
2416 IF_TRACE(printf(" (jump-toplevel-short 0x%04x)\n",
2417 pc
+ bytecode
+ CODE_START
));
2419 entry
= pc
+ bytecode
+ CODE_START
;
2422 na
= rom_get (entry
++);
2433 case 7: // goto-short
2434 FETCH_NEXT_BYTECODE();
2436 IF_TRACE(printf(" (goto-short 0x%04x)\n", pc
+ bytecode
+ CODE_START
));
2438 pc
= pc
+ bytecode
+ CODE_START
;
2442 case 8: // goto-if-false-short
2443 FETCH_NEXT_BYTECODE();
2445 IF_TRACE(printf(" (goto-if-false-short 0x%04x)\n",
2446 pc
+ bytecode
+ CODE_START
));
2448 if (POP() == OBJ_FALSE
)
2449 pc
= pc
+ bytecode
+ CODE_START
;
2453 case 9: // closure-short TODO I doubt these short instrs will have great effect, and this is the one I doubt the most about
2454 FETCH_NEXT_BYTECODE();
2456 IF_TRACE(printf(" (closure-short 0x%04x)\n", pc
+ bytecode
));
2458 arg3
= POP(); // env
2460 entry
= pc
+ bytecode
; // TODO makes sense for a closure ?
2462 arg1
= alloc_ram_cell_init (CLOSURE_FIELD0
| (arg2
>> 3),
2463 ((arg2
& 0x07) << 5) | (bytecode
>> 3),
2464 ((bytecode
&0x07) <<5) |((arg3
&0x1f00) >>8),
2483 case 14: // push_global [long]
2484 FETCH_NEXT_BYTECODE(); // TODO doesn't work yet
2486 IF_TRACE(printf(" (push-global [long] %d)\n", bytecode
));
2488 arg1
= get_global (bytecode
);
2494 case 15: // set_global [long]
2495 FETCH_NEXT_BYTECODE();
2497 IF_TRACE(printf(" (set-global [long] %d)\n", bytecode
));
2499 set_global (bytecode
, POP());
2506 /***************************************************************************/
2507 CASE(PUSH_CONSTANT_LONG
);
2509 /* push-constant [long] */
2511 FETCH_NEXT_BYTECODE();
2513 IF_TRACE(printf(" (push [long] 0x%04x)\n", (bytecode_lo4
<< 8) + bytecode
));
2515 arg1
= (bytecode_lo4
<< 8) | bytecode
;
2520 /***************************************************************************/
2521 CASE(GOTO
); // BREGG move
2525 /***************************************************************************/
2526 CASE(GOTO_IF_FALSE
); // BREGG move
2530 /***************************************************************************/
2531 CASE(CLOSURE
); // BREGG move
2535 /***************************************************************************/
2538 IF_TRACE(printf(" (%s)\n", prim_name
[bytecode_lo4
]));
2540 switch (bytecode_lo4
)
2543 arg1
= POP(); prim_numberp (); PUSH_ARG1(); break;
2545 arg2
= POP(); arg1
= POP(); prim_add (); PUSH_ARG1(); break;
2547 arg2
= POP(); arg1
= POP(); prim_sub (); PUSH_ARG1(); break;
2549 arg2
= POP(); arg1
= POP(); prim_mul (); PUSH_ARG1(); break;
2551 arg2
= POP(); arg1
= POP(); prim_div (); PUSH_ARG1(); break;
2553 arg2
= POP(); arg1
= POP(); prim_rem (); PUSH_ARG1(); break;
2555 arg1
= POP(); prim_neg (); PUSH_ARG1(); break;
2557 arg2
= POP(); arg1
= POP(); prim_eq (); PUSH_ARG1(); break;
2559 arg2
= POP(); arg1
= POP(); prim_lt (); PUSH_ARG1(); break;
2561 arg2
= POP(); arg1
= POP(); prim_ior (); PUSH_ARG1(); break;
2563 arg2
= POP(); arg1
= POP(); prim_gt (); PUSH_ARG1(); break;
2565 arg2
= POP(); arg1
= POP(); prim_xor (); PUSH_ARG1(); break;
2567 arg1
= POP(); prim_pairp (); PUSH_ARG1(); break;
2569 arg2
= POP(); arg1
= POP(); prim_cons (); PUSH_ARG1(); break;
2571 arg1
= POP(); prim_car (); PUSH_ARG1(); break;
2573 arg1
= POP(); prim_cdr (); PUSH_ARG1(); break;
2578 /***************************************************************************/
2581 IF_TRACE(printf(" (%s)\n", prim_name
[bytecode_lo4
+16]));
2583 switch (bytecode_lo4
)
2586 arg2
= POP(); arg1
= POP(); prim_set_car (); break;
2588 arg2
= POP(); arg1
= POP(); prim_set_cdr (); break;
2590 arg1
= POP(); prim_nullp (); PUSH_ARG1(); break;
2592 arg2
= POP(); arg1
= POP(); prim_eqp (); PUSH_ARG1(); break;
2594 arg1
= POP(); prim_not (); PUSH_ARG1(); break;
2596 /* prim #%get-cont */
2601 /* prim #%graft-to-cont */
2603 arg1
= POP(); /* thunk to call */
2604 cont
= POP(); /* continuation */
2611 handle_arity_and_rest_param ();
2621 /* prim #%return-to-cont */
2623 arg1
= POP(); /* value to return */
2624 cont
= POP(); /* continuation */
2626 arg2
= ram_get_cdr (cont
);
2628 pc
= ram_get_entry (arg2
);
2630 env
= ram_get_cdr (arg2
);
2631 cont
= ram_get_car (cont
);
2641 /* prim #%symbol? */
2642 arg1
= POP(); prim_symbolp (); PUSH_ARG1(); break;
2644 /* prim #%string? */
2645 arg1
= POP(); prim_stringp (); PUSH_ARG1(); break;
2647 /* prim #%string->list */
2648 arg1
= POP(); prim_string2list (); PUSH_ARG1(); break;
2650 /* prim #%list->string */
2651 arg1
= POP(); prim_list2string (); PUSH_ARG1(); break;
2653 /* prim #%make-u8vector */
2654 arg1
= POP(); prim_make_u8vector (); PUSH_ARG1(); break;
2656 /* prim #%u8vector-ref */
2657 arg2
= POP(); arg1
= POP(); prim_u8vector_ref (); PUSH_ARG1(); break;
2659 /* prim #%u8vector-set! */
2660 arg3
= POP(); arg2
= POP(); arg1
= POP(); prim_u8vector_set (); break;
2665 /***************************************************************************/
2668 IF_TRACE(printf(" (%s)\n", prim_name
[bytecode_lo4
+32]));
2670 switch (bytecode_lo4
)
2679 prim_clock (); PUSH_ARG1(); break;
2682 arg2
= POP(); arg1
= POP(); prim_motor (); break;
2685 arg3
= POP(); arg2
= POP(); arg1
= POP(); prim_led (); ;break;
2687 /* prim #%led2-color */
2688 arg1
= POP(); prim_led2_color (); break;
2690 /* prim #%getchar-wait */
2691 arg2
= POP(); arg1
= POP(); prim_getchar_wait (); PUSH_ARG1(); break;
2693 /* prim #%putchar */
2694 arg2
= POP(); arg1
= POP(); prim_putchar (); break;
2697 arg2
= POP(); arg1
= POP(); prim_beep (); break;
2700 arg1
= POP(); prim_adc (); PUSH_ARG1(); break;
2702 /* prim #%u8vector? */
2703 arg1
= POP(); prim_u8vectorp (); PUSH_ARG1(); break;
2706 prim_sernum (); PUSH_ARG1(); break;
2708 /* prim #%u8vector-length */
2709 arg1
= POP(); prim_u8vector_length (); PUSH_ARG1(); break;
2711 // FREE find something to do with this
2726 arg2
= ram_get_cdr (cont
);
2727 pc
= ram_get_entry (arg2
);
2728 env
= ram_get_cdr (arg2
);
2729 cont
= ram_get_car (cont
);
2737 /***************************************************************************/
2742 /*---------------------------------------------------------------------------*/
2748 printf ("usage: sim file.hex\n");
2752 int main (int argc
, char *argv
[])
2755 rom_addr rom_start_addr
= 0;
2757 if (argc
> 1 && argv
[1][0] == '-' && argv
[1][1] == 's')
2764 if ((h1
= hex (argv
[1][2])) < 0 ||
2765 (h2
= hex (argv
[1][3])) < 0 ||
2766 (h3
= hex (argv
[1][4])) != 0 ||
2767 (h4
= hex (argv
[1][5])) != 0 ||
2771 rom_start_addr
= (h1
<< 12) | (h2
<< 8) | (h3
<< 4) | h4
;
2778 printf ("Start address = 0x%04x\n", rom_start_addr
); // TODO says 0, but should be CODE_START ?
2784 if (!read_hex_file (argv
[1]))
2785 printf ("*** Could not read hex file \"%s\"\n", argv
[1]);
2790 if (rom_get (CODE_START
+0) != 0xfb ||
2791 rom_get (CODE_START
+1) != 0xd7)
2792 printf ("*** The hex file was not compiled with PICOBIT\n");
2796 for (i
=0; i
<8192; i
++) // TODO remove this ? and not the night address space, now 16 bits
2797 if (rom_get (i
) != 0xff)
2798 printf ("rom_mem[0x%04x] = 0x%02x\n", i
, rom_get (i
));
2804 printf ("**************** memory needed = %d\n", max_live
+1);
2814 /*---------------------------------------------------------------------------*/