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
85 #define IF_GC_TRACE(x) x
88 #define IF_GC_TRACE(x)
91 /*---------------------------------------------------------------------------*/
96 #define ERROR(msg) halt_with_error()
97 #define TYPE_ERROR(type) halt_with_error()
104 #define ERROR(msg) error (msg)
105 #define TYPE_ERROR(type) type_error (type)
107 void error (char *msg
)
109 printf ("ERROR: %s\n", msg
);
113 void type_error (char *type
)
115 printf ("ERROR: An argument of type %s was expected\n", type
);
122 /*---------------------------------------------------------------------------*/
130 typedef uint16 ram_addr
;
131 typedef uint16 rom_addr
;
135 /*---------------------------------------------------------------------------*/
137 #define MAX_VEC_ENCODING 8191
138 #define MIN_VEC_ENCODING 4096
139 #define VEC_BYTES ((MAX_VEC_ENCODING - MIN_VEC_ENCODING + 1)*4)
140 // TODO this is new. if the pic has less than 8k of memory, start this lower
141 // TODO max was 8192 for ram, would have been 1 too much (watch out, master branch still has that), now corrected
142 // TODO the pic actually has 2k, so change these FOOBAR
143 // 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
145 #define MAX_RAM_ENCODING 4095
146 #define MIN_RAM_ENCODING 512
147 #define RAM_BYTES ((MAX_RAM_ENCODING - MIN_RAM_ENCODING + 1)*4)
148 // TODO watch out if we address more than what the PIC actually has
151 // TODO subtracts min_ram since vectors are actually in ram
152 #define OBJ_TO_VEC_ADDR(o,f) (((ram_addr)((uint16)(o) - MIN_RAM_ENCODING) << 2) + (f))
153 #define OBJ_TO_RAM_ADDR(o,f) (((ram_addr)((uint16)(o) - MIN_RAM_ENCODING) << 2) + (f))
154 #define OBJ_TO_ROM_ADDR(o,f) (((rom_addr)((uint16)(o) - MIN_ROM_ENCODING) << 2) + (CODE_START + 4 + (f)))
159 #define ram_get(a) *(uint8*)(a+0x200)
160 #define ram_set(a,x) *(uint8*)(a+0x200) = (x)
161 // TODO change these since we change proportion of ram and rom ?
167 uint8 ram_mem
[RAM_BYTES
+ VEC_BYTES
];
169 #define ram_get(a) ram_mem[a]
170 #define ram_set(a,x) ram_mem[a] = (x)
175 /*---------------------------------------------------------------------------*/
179 /* #if WORD_BITS == 8 */
180 /* #endif */ // TODO useless
182 uint8
rom_get (rom_addr a
)
184 return *(rom uint8
*)a
;
192 #define ROM_BYTES 8192
193 // TODO the new pics have 32k, change this ?
195 uint8 rom_mem
[ROM_BYTES
] =
198 #define PUTCHAR_LIGHT_not
201 0xFB, 0xD7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x32
202 , 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00
203 , 0x08, 0x50, 0x80, 0x16, 0xFE, 0xE8, 0x00, 0xFC
204 , 0x32, 0x80, 0x2D, 0xFE, 0xFC, 0x31, 0x80, 0x43
205 , 0xFE, 0xFC, 0x33, 0x80, 0x2D, 0xFE, 0xFC, 0x31
206 , 0x80, 0x43, 0xFE, 0x90, 0x16, 0x01, 0x20, 0xFC
207 , 0x32, 0xE3, 0xB0, 0x37, 0x09, 0xF3, 0xFF, 0x20
208 , 0xFC, 0x33, 0xE3, 0xB0, 0x40, 0x0A, 0xF3, 0xFF
209 , 0x08, 0xF3, 0xFF, 0x01, 0x40, 0x21, 0xD1, 0x00
210 , 0x02, 0xC0, 0x4C, 0x71, 0x01, 0x20, 0x50, 0x90
211 , 0x51, 0x00, 0xF1, 0x40, 0xD8, 0xB0, 0x59, 0x90
215 0xFB, 0xD7, 0x00, 0x00, 0x80, 0x08, 0xFE, 0xE8
216 , 0x00, 0xF6, 0xF5, 0x90, 0x08
220 uint8
rom_get (rom_addr a
)
222 return rom_mem
[a
-CODE_START
];
227 obj globals
[GLOVARS
];
229 /*---------------------------------------------------------------------------*/
237 fixnum n MIN_FIXNUM -> 3 ... MAX_FIXNUM -> 3 + (MAX_FIXNUM-MIN_FIXNUM)
238 rom object 4 + (MAX_FIXNUM-MIN_FIXNUM) ... MIN_RAM_ENCODING-1
239 ram object MIN_RAM_ENCODING ... MAX_RAM_ENCODING
240 vector MIN_VEC_ENCODING ... 8191
242 layout of memory allocated objects:
244 G's represent mark bits used by the gc
246 bignum n 00G00000 uuuuuuuu hhhhhhhh llllllll (24 bit signed integer)
247 TODO we could have 29-bit integers
249 pair 1GGaaaaa aaaaaaaa 000ddddd dddddddd
252 gives an address space of 2^13 * 4 = 32k divided between simple objects,
255 symbol 1GG00000 00000000 00100000 00000000
257 string 1GG***** *chars** 01000000 00000000
259 vector 1GG***** *elems** 01100000 00000000 TODO old
260 vector 1GGxxxxx xxxxxxxx 011yyyyy yyyyyyyy
261 x is length of the vector, in bytes
262 y is pointer to the elements themselves (stored in vector space)
263 TODO pointer could be shorter since it always points in vector space, same for length, will never be this long
264 TODO show how vectors are represented in vector space
265 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
266 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
267 TODO how to deal with gc ? mayeb when we sweep a vector header, go sweep its contents in vector space ?
269 closure 01Gaaaaa aaaaaaaa aaaxxxxx xxxxxxxx
270 0x5ff<a<0x4000 is entry
271 x is pointer to environment
272 the reason why the environment is on the cdr (and the entry is split on 3
273 bytes) is that, when looking for a variable, a closure is considered to be a
274 pair. The compiler adds an extra offset to any variable in the closure's
275 environment, so the car of the closure (which doesn't really exist) is never
276 checked, but the cdr is followed to find the other bindings
278 continuation 1GGxxxxx xxxxxxxx 100yyyyy yyyyyyyy
279 x is parent continuation
280 y is pointer to the second half, which is a closure (contains env and entry)
282 An environment is a list of objects built out of pairs. On entry to
283 a procedure the environment is the list of parameters to which is
284 added the environment of the closure being called.
286 The first byte at the entry point of a procedure gives the arity of
289 n = 0 to 127 -> procedure has n parameters (no rest parameter)
290 n = -128 to -1 -> procedure has -n parameters, the last is
298 #define MIN_FIXNUM_ENCODING 3
300 #define MAX_FIXNUM 255
301 #define MIN_ROM_ENCODING (MIN_FIXNUM_ENCODING+MAX_FIXNUM-MIN_FIXNUM+1)
303 #define ENCODE_FIXNUM(n) ((obj)(n) + (MIN_FIXNUM_ENCODING - MIN_FIXNUM))
304 #define DECODE_FIXNUM(o) ((int32)(o) - (MIN_FIXNUM_ENCODING - MIN_FIXNUM))
306 // TODO why this ifdef ?
308 #define IN_VEC(o) ((o) >= MIN_VEC_ENCODING)
309 #define IN_RAM(o) (!IN_VEC(o) && ((o) >= MIN_RAM_ENCODING))
310 #define IN_ROM(o) (!IN_VEC(o) && !IN_RAM(o) && ((o) >= MIN_ROM_ENCODING))
312 // TODO performance ?
314 // bignum first byte : 00G00000
315 #define BIGNUM_FIELD0 0
316 #define RAM_BIGNUM(o) ((ram_get_field0 (o) & 0xc0) == BIGNUM_FIELD0)
317 #define ROM_BIGNUM(o) ((rom_get_field0 (o) & 0xc0) == BIGNUM_FIELD0)
319 // composite first byte : 1GGxxxxx
320 #define COMPOSITE_FIELD0 0x80
321 #define RAM_COMPOSITE(o) ((ram_get_field0 (o) & 0x80) == COMPOSITE_FIELD0)
322 #define ROM_COMPOSITE(o) ((rom_get_field0 (o) & 0x80) == COMPOSITE_FIELD0)
324 // pair third byte : 000xxxxx
325 #define PAIR_FIELD2 0
326 #define RAM_PAIR(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == PAIR_FIELD2))
327 #define ROM_PAIR(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == PAIR_FIELD2))
329 // symbol third byte : 001xxxxx
330 #define SYMBOL_FIELD2 0x20
331 #define RAM_SYMBOL(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == SYMBOL_FIELD2))
332 #define ROM_SYMBOL(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == SYMBOL_FIELD2))
334 // string third byte : 010xxxxx
335 #define STRING_FIELD2 0x40
336 #define RAM_STRING(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == STRING_FIELD2))
337 #define ROM_STRING(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == STRING_FIELD2))
339 // vector third byte : 011xxxxx
340 #define VECTOR_FIELD2 0x60
341 #define RAM_VECTOR(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == VECTOR_FIELD2))
342 #define ROM_VECTOR(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == VECTOR_FIELD2))
343 // TODO this is only for headers
345 // continuation third byte : 100xxxxx
346 #define CONTINUATION_FIELD2 0x80
347 #define RAM_CONTINUATION(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == CONTINUATION_FIELD2))
348 #define ROM_CONTINUATION(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == CONTINUATION_FIELD2))
350 // closure first byte : 01Gxxxxx
351 #define CLOSURE_FIELD0 0x40
352 #define RAM_CLOSURE(o) ((ram_get_field0 (o) & 0xc0) == CLOSURE_FIELD0)
353 #define ROM_CLOSURE(o) ((rom_get_field0 (o) & 0xc0) == CLOSURE_FIELD0)
356 /*---------------------------------------------------------------------------*/
358 #define RAM_GET_FIELD0_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,0))
359 #define RAM_SET_FIELD0_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,0), val)
360 #define ROM_GET_FIELD0_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,0))
362 #define RAM_GET_GC_TAGS_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x60)
363 #define RAM_GET_GC_TAG0_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x20)
364 #define RAM_GET_GC_TAG1_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x40)
365 #define RAM_SET_GC_TAGS_MACRO(o,tags) \
366 (RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0x9f) | (tags)))
367 #define RAM_SET_GC_TAG0_MACRO(o,tag) \
368 RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0xdf) | (tag))
369 #define RAM_SET_GC_TAG1_MACRO(o,tag) \
370 RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0xbf) | (tag))
373 #define RAM_GET_FIELD1_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,1))
374 #define RAM_GET_FIELD2_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,2))
375 #define RAM_GET_FIELD3_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,3))
376 #define RAM_SET_FIELD1_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,1), val)
377 #define RAM_SET_FIELD2_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,2), val)
378 #define RAM_SET_FIELD3_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,3), val)
379 #define ROM_GET_FIELD1_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,1))
380 #define ROM_GET_FIELD2_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,2))
381 #define ROM_GET_FIELD3_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,3))
382 #define VEC_GET_BYTE0_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,0))
383 #define VEC_GET_BYTE1_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,1))
384 #define VEC_GET_BYTE2_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,2))
385 #define VEC_GET_BYTE3_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,3))
386 #define VEC_SET_BYTE0_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,0), val)
387 #define VEC_SET_BYTE1_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,1), val)
388 #define VEC_SET_BYTE2_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,2), val)
389 #define VEC_SET_BYTE3_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,3), val)
390 // 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 ?
393 uint8
ram_get_gc_tags (obj o
) { return RAM_GET_GC_TAGS_MACRO(o
); }
394 uint8
ram_get_gc_tag0 (obj o
) { return RAM_GET_GC_TAG0_MACRO(o
); }
395 uint8
ram_get_gc_tag1 (obj o
) { return RAM_GET_GC_TAG1_MACRO(o
); }
396 void ram_set_gc_tags (obj o
, uint8 tags
) { RAM_SET_GC_TAGS_MACRO(o
, tags
); }
397 void ram_set_gc_tag0 (obj o
, uint8 tag
) { RAM_SET_GC_TAG0_MACRO(o
,tag
); }
398 void ram_set_gc_tag1 (obj o
, uint8 tag
) { RAM_SET_GC_TAG1_MACRO(o
,tag
); }
399 uint8
ram_get_field0 (obj o
) { return RAM_GET_FIELD0_MACRO(o
); }
400 word
ram_get_field1 (obj o
) { return RAM_GET_FIELD1_MACRO(o
); }
401 word
ram_get_field2 (obj o
) { return RAM_GET_FIELD2_MACRO(o
); }
402 word
ram_get_field3 (obj o
) { return RAM_GET_FIELD3_MACRO(o
); }
403 void ram_set_field0 (obj o
, uint8 val
) { RAM_SET_FIELD0_MACRO(o
,val
); }
404 void ram_set_field1 (obj o
, word val
) { RAM_SET_FIELD1_MACRO(o
,val
); }
405 void ram_set_field2 (obj o
, word val
) { RAM_SET_FIELD2_MACRO(o
,val
); }
406 void ram_set_field3 (obj o
, word val
) { RAM_SET_FIELD3_MACRO(o
,val
); }
407 uint8
rom_get_field0 (obj o
) { return ROM_GET_FIELD0_MACRO(o
); }
408 word
rom_get_field1 (obj o
) { return ROM_GET_FIELD1_MACRO(o
); }
409 word
rom_get_field2 (obj o
) { return ROM_GET_FIELD2_MACRO(o
); }
410 word
rom_get_field3 (obj o
) { return ROM_GET_FIELD3_MACRO(o
); }
411 /* word vec_get_byte0 (obj o) { return VEC_GET_BYTE0_MACRO(o); } */
412 /* word vec_get_byte1 (obj o) { return VEC_GET_BYTE1_MACRO(o); } */
413 /* word vec_get_byte2 (obj o) { return VEC_GET_BYTE2_MACRO(o); } */
414 /* word vec_get_byte3 (obj o) { return VEC_GET_BYTE3_MACRO(o); } */
415 /* word vec_set_byte0 (obj o, word val) { VEC_SET_BYTE0_MACRO(o,val); } */
416 /* word vec_set_byte1 (obj o, word val) { VEC_SET_BYTE1_MACRO(o,val); } */
417 /* word vec_set_byte2 (obj o, word val) { VEC_SET_BYTE2_MACRO(o,val); } */
418 /* word vec_set_byte3 (obj o, word val) { VEC_SET_BYTE3_MACRO(o,val); } */
419 // TODO use the word field or byte ? actually the ram functions are used, since this is in ram anyways
421 obj
ram_get_car (obj o
)
422 { return ((ram_get_field0 (o
) & 0x1f) << 8) | ram_get_field1 (o
); }
423 obj
rom_get_car (obj o
)
424 { return ((rom_get_field0 (o
) & 0x1f) << 8) | rom_get_field1 (o
); }
425 obj
ram_get_cdr (obj o
)
426 { return ((ram_get_field2 (o
) & 0x1f) << 8) | ram_get_field3 (o
); }
427 obj
rom_get_cdr (obj o
)
428 { return ((rom_get_field2 (o
) & 0x1f) << 8) | rom_get_field3 (o
); }
429 void ram_set_car (obj o
, obj val
)
431 ram_set_field0 (o
, (val
>> 8) | (ram_get_field0 (o
) & 0xe0));
432 ram_set_field1 (o
, val
& 0xff);
434 void ram_set_cdr (obj o
, obj val
)
436 ram_set_field2 (o
, (val
>> 8) | (ram_get_field2 (o
) & 0xe0));
437 ram_set_field3 (o
, val
& 0xff);
439 obj
ram_get_entry (obj o
)
441 return (((ram_get_field0 (o
) & 0x1f) << 11)
442 | (ram_get_field1 (o
) << 3)
443 | (ram_get_field2 (o
) >> 5));
445 obj
rom_get_entry (obj o
)
447 return (((rom_get_field0 (o
) & 0x1f) << 11)
448 | (rom_get_field1 (o
) << 3)
449 | (rom_get_field2 (o
) >> 5));
452 obj
get_global (uint8 i
)
457 void set_global (uint8 i
, obj o
)
463 void show_type (obj o
) // for debugging purposes
466 if (o
== OBJ_FALSE
) printf("#f");
467 else if (o
== OBJ_TRUE
) printf("#t");
468 else if (o
== OBJ_NULL
) printf("()");
469 else if (o
< MIN_ROM_ENCODING
) printf("fixnum");
472 if (RAM_BIGNUM(o
)) printf("ram bignum");
473 else if (RAM_PAIR(o
)) printf("ram pair");
474 else if (RAM_SYMBOL(o
)) printf("ram symbol");
475 else if (RAM_STRING(o
)) printf("ram string");
476 else if (RAM_VECTOR(o
)) printf("ram vector");
477 else if (RAM_CONTINUATION(o
)) printf("ram continuation");
478 else if (RAM_CLOSURE(o
)) printf("ram closure");
482 if (ROM_BIGNUM(o
)) printf("rom bignum");
483 else if (ROM_PAIR(o
)) printf("rom pair");
484 else if (ROM_SYMBOL(o
)) printf("rom symbol");
485 else if (ROM_STRING(o
)) printf("rom string");
486 else if (ROM_VECTOR(o
)) printf("rom vector");
487 else if (ROM_CONTINUATION(o
)) printf("rom continuation");
488 else if (RAM_CLOSURE(o
)) printf("rom closure");
495 /*---------------------------------------------------------------------------*/
497 /* Interface to GC */
499 // TODO explain what each tag means, with 1-2 mark bits
500 #define GC_TAG_0_LEFT (1<<5)
501 // TODO was 3<<5, changed to play nice with procedures and bignums, but should actually set only this bit, not clear the other
502 #define GC_TAG_1_LEFT (2<<5)
503 #define GC_TAG_UNMARKED (0<<5)
505 /* Number of object fields of objects in ram */
506 #define HAS_2_OBJECT_FIELDS(visit) (RAM_PAIR(visit) || RAM_CONTINUATION(visit))
507 #define HAS_1_OBJECT_FIELD(visit) (RAM_COMPOSITE(visit) || RAM_CLOSURE(visit))
508 // all composites except pairs and continuations have 1 object field
509 // TODO if we ever have true bignums, bignums will have 1 object field
511 #define NIL OBJ_FALSE
513 /*---------------------------------------------------------------------------*/
515 /* Garbage collector */
517 obj free_list
; /* list of unused cells */
518 obj free_list_vec
; /* list of unused cells in vector space */
520 obj arg1
; /* root set */
527 uint8 na
; /* interpreter variables */
537 void init_ram_heap (void)
540 obj o
= MAX_RAM_ENCODING
;
544 while (o
>= MIN_RAM_ENCODING
)
546 ram_set_gc_tags (o
, GC_TAG_UNMARKED
);
547 ram_set_car (o
, free_list
);
552 free_list_vec
= MIN_VEC_ENCODING
;
553 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
554 // each node of the free list must know the free length that follows it
555 // this free length is stored in words, not in bytes
556 // if we did count in bytes, the number might need more than 13 bits
557 ram_set_cdr (free_list_vec
, VEC_BYTES
/ 4);
558 // TODO so, at the start, we have only 1 node that says the whole space is free
560 for (i
=0; i
<GLOVARS
; i
++)
561 set_global (i
, OBJ_FALSE
);
588 // 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
589 IF_GC_TRACE(printf ("push stack=%d visit=%d (tag=%d)\n", stack
, visit
, ram_get_gc_tags (visit
)>>5));
591 if ((HAS_1_OBJECT_FIELD (visit
) && ram_get_gc_tag0 (visit
))
592 || (HAS_2_OBJECT_FIELDS (visit
)
593 && (ram_get_gc_tags (visit
) != GC_TAG_UNMARKED
)))
594 // TODO ugly condition
595 IF_GC_TRACE(printf ("case 1\n"));
598 if (HAS_2_OBJECT_FIELDS(visit
)) // pairs and continuations
600 IF_GC_TRACE(printf ("case 5\n"));
604 temp
= ram_get_cdr (visit
);
608 IF_GC_TRACE(printf ("case 6\n"));
609 ram_set_gc_tags (visit
, GC_TAG_1_LEFT
);
610 ram_set_cdr (visit
, stack
);
614 IF_GC_TRACE(printf ("case 7\n"));
619 if (HAS_1_OBJECT_FIELD(visit
))
621 IF_GC_TRACE(printf ("case 8\n"));
625 if (RAM_CLOSURE(visit
)) // closures have the pointer in the cdr
626 temp
= ram_get_cdr (visit
);
628 temp
= ram_get_car (visit
);
632 IF_GC_TRACE(printf ("case 9\n"));
633 ram_set_gc_tag0 (visit
, GC_TAG_0_LEFT
);
634 if (RAM_CLOSURE(visit
))
635 ram_set_cdr (visit
, stack
);
637 ram_set_car (visit
, stack
);
642 IF_GC_TRACE(printf ("case 10\n"));
645 IF_GC_TRACE(printf ("case 11\n"));
647 ram_set_gc_tag0 (visit
, GC_TAG_0_LEFT
);
652 /* 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)); */
653 // TODO, like for push, getting the gc tags of nil is not great
654 IF_GC_TRACE(printf ("pop stack=%d visit=%d (tag=%d)\n", stack
, visit
, ram_get_gc_tags (visit
)>>6));
658 if (HAS_2_OBJECT_FIELDS(stack
) && ram_get_gc_tag1 (stack
))
660 IF_GC_TRACE(printf ("case 13\n"));
662 temp
= ram_get_cdr (stack
); /* pop through cdr */
663 ram_set_cdr (stack
, visit
);
667 ram_set_gc_tag1(visit
, GC_TAG_UNMARKED
);
668 // we unset the "1-left" bit
673 if (RAM_CLOSURE(stack
))
674 // closures have one object field, but it's in the cdr
676 IF_GC_TRACE(printf ("case 13.5\n")); // TODO renumber cases
678 temp
= ram_get_cdr (stack
); /* pop through cdr */
679 ram_set_cdr (stack
, visit
);
686 IF_GC_TRACE(printf ("case 14\n"));
688 temp
= ram_get_car (stack
); /* pop through car */
689 ram_set_car (stack
, visit
);
710 obj visit
= MAX_RAM_ENCODING
;
714 while (visit
>= MIN_RAM_ENCODING
)
716 if ((RAM_COMPOSITE(visit
)
717 && (ram_get_gc_tags (visit
) == GC_TAG_UNMARKED
)) // 2 mark bit
718 || !(ram_get_gc_tags (visit
) & GC_TAG_0_LEFT
)) // 1 mark bit
721 if (RAM_VECTOR(visit
))
722 // when we sweep a vector, we also have to sweep its contents
724 obj o
= ram_get_cdr (visit
);
725 uint16 i
= ram_get_car (visit
); // number of elements
726 ram_set_car (o
, free_list_vec
);
727 ram_set_cdr (o
, (i
+ 3) / 4); // free length, in words
729 // 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
731 ram_set_car (visit
, free_list
);
736 if (RAM_COMPOSITE(visit
))
737 ram_set_gc_tags (visit
, GC_TAG_UNMARKED
);
738 else // only 1 mark bit to unset
739 ram_set_gc_tag0 (visit
, GC_TAG_UNMARKED
);
751 printf ("**************** memory needed = %d\n", max_live
+1);
761 IF_GC_TRACE(printf("\nGC BEGINS\n"));
763 IF_GC_TRACE(printf("arg1\n"));
765 IF_GC_TRACE(printf("arg2\n"));
767 IF_GC_TRACE(printf("arg3\n"));
769 IF_GC_TRACE(printf("arg4\n"));
771 IF_GC_TRACE(printf("cont\n"));
773 IF_GC_TRACE(printf("env\n"));
774 mark (env
); // TODO do we mark the free list or do we rebuild it every time ? what about vectors ?
776 for (i
=0; i
<GLOVARS
; i
++)
777 mark (get_global (i
));
782 obj
alloc_ram_cell (void)
796 ERROR("memory is full");
801 free_list
= ram_get_car (o
);
806 obj
alloc_ram_cell_init (uint8 f0
, uint8 f1
, uint8 f2
, uint8 f3
)
808 obj o
= alloc_ram_cell ();
810 ram_set_field0 (o
, f0
);
811 ram_set_field1 (o
, f1
);
812 ram_set_field2 (o
, f2
);
813 ram_set_field3 (o
, f3
);
818 obj
alloc_vec_cell (uint16 n
) // TODO add a init version ?
820 obj o
= free_list_vec
;
829 while ((ram_get_cdr (o
) * 4) < n
) // free space too small
830 { // 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
831 if (o
== 0) // no free space, or none big enough
833 if (gc_done
) // we gc'd, but no space is big enough for the vector
834 ERROR("no room for vector");
842 } // TODO fuse adjacent free spaces, and maybe compact ? FOOBAR
847 // case 1 : the new vector fills every free word advertized, we remove the
848 // node from the free list
849 // TODO mettre le cdr de o dans une var temporaire ?
850 if ((n
- (ram_get_cdr(o
) * 4)) < 4) // TODO is there a better way ?
853 ram_set_car (prec
, ram_get_car (o
));
855 free_list_vec
= ram_get_car (o
);
857 // case 2 : there is still some space left in the free section, create a new
858 // node to represent this space
861 obj new_free
= o
+ (n
+ 3)/4;
863 ram_set_car (prec
, new_free
);
865 free_list_vec
= new_free
;
866 ram_set_car (new_free
, ram_get_car (o
));
867 ram_set_cdr (new_free
, ram_get_cdr (o
) - (n
+ 3)/4); // TODO documenter structure de cette free list quelque part
873 /*---------------------------------------------------------------------------*/
875 int32
decode_int (obj o
)
881 if (o
< MIN_FIXNUM_ENCODING
)
882 TYPE_ERROR("integer");
884 if (o
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
885 return DECODE_FIXNUM(o
);
890 TYPE_ERROR("integer");
892 u
= ram_get_field1 (o
);
893 h
= ram_get_field2 (o
);
894 l
= ram_get_field3 (o
);
899 TYPE_ERROR("integer");
901 u
= rom_get_field1 (o
);
902 h
= rom_get_field2 (o
);
903 l
= rom_get_field3 (o
);
906 TYPE_ERROR("integer");
909 return ((int32
)((((int16
)u
- 256) << 8) + h
) << 8) + l
;
911 return ((int32
)(((int16
)u
<< 8) + h
) << 8) + l
;
914 obj
encode_int (int32 n
)
916 if (n
>= MIN_FIXNUM
&& n
<= MAX_FIXNUM
)
917 return ENCODE_FIXNUM(n
);
919 return alloc_ram_cell_init (BIGNUM_FIELD0
, n
>> 16, n
>> 8, n
);
922 /*---------------------------------------------------------------------------*/
934 else if (o
== OBJ_TRUE
)
936 else if (o
== OBJ_NULL
)
938 else if (o
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
939 printf ("%d", DECODE_FIXNUM(o
));
940 else // TODO past here, everything is either in ram or in rom, until we add a 3rd space for vectors, that is
949 if ((in_ram
&& RAM_BIGNUM(o
)) || (!in_ram
&& ROM_BIGNUM(o
)))
950 printf ("%d", decode_int (o
));
951 else if ((in_ram
&& RAM_COMPOSITE(o
)) || (!in_ram
&& ROM_COMPOSITE(o
)))
956 if ((in_ram
&& RAM_PAIR(o
)) || (!in_ram
&& ROM_PAIR(o
))) // TODO not exactly efficient, fix it
960 car
= ram_get_car (o
);
961 cdr
= ram_get_cdr (o
);
965 car
= rom_get_car (o
);
966 cdr
= rom_get_cdr (o
);
977 else if ((IN_RAM(cdr
) && RAM_PAIR(cdr
))
978 || (IN_ROM(cdr
) && ROM_PAIR(cdr
)))
982 car
= ram_get_car (cdr
);
983 cdr
= ram_get_cdr (cdr
);
987 car
= rom_get_car (cdr
);
988 cdr
= rom_get_cdr (cdr
);
1001 else if ((in_ram
&& RAM_SYMBOL(o
)) || (!in_ram
&& ROM_SYMBOL(o
)))
1002 printf ("#<symbol>");
1003 else if ((in_ram
&& RAM_STRING(o
)) || (!in_ram
&& ROM_STRING(o
)))
1004 printf ("#<string>");
1005 else if ((in_ram
&& RAM_VECTOR(o
)) || (!in_ram
&& ROM_VECTOR(o
)))
1006 printf ("#<vector %d>", o
); // TODO do better DEBUG BREGG
1010 car
= ram_get_car (o
);
1011 cdr
= ram_get_cdr (o
);
1012 goto loop
; // TODO ugly hack, takes advantage of the fact that pairs and continuations have the same layout
1020 if (IN_RAM(o
)) // TODO can closures be in rom ? I don't think so
1021 env
= ram_get_cdr (o
);
1023 env
= rom_get_cdr (o
);
1026 pc
= ram_get_entry (o
);
1028 pc
= rom_get_entry (o
);
1030 printf ("{0x%04x ", pc
);
1039 void show_state (rom_addr pc
)
1042 printf ("pc=0x%04x bytecode=0x%02x env=", pc
, rom_get (pc
));
1059 /*---------------------------------------------------------------------------*/
1061 /* Integer operations */
1063 #define encode_bool(x) ((obj)(x))
1065 void prim_numberp (void)
1067 if (arg1
>= MIN_FIXNUM_ENCODING
1068 && arg1
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
1073 arg1
= encode_bool (RAM_BIGNUM(arg1
));
1074 else if (IN_ROM(arg1
))
1075 arg1
= encode_bool (ROM_BIGNUM(arg1
));
1081 void decode_2_int_args (void)
1083 a1
= decode_int (arg1
);
1084 a2
= decode_int (arg2
);
1087 void prim_add (void)
1089 decode_2_int_args ();
1090 arg1
= encode_int (a1
+ a2
);
1094 void prim_sub (void)
1096 decode_2_int_args ();
1097 arg1
= encode_int (a1
- a2
);
1101 void prim_mul (void)
1103 decode_2_int_args ();
1104 arg1
= encode_int (a1
* a2
);
1108 void prim_div (void)
1110 decode_2_int_args ();
1112 ERROR("divide by 0");
1113 arg1
= encode_int (a1
/ a2
);
1117 void prim_rem (void)
1119 decode_2_int_args ();
1121 ERROR("divide by 0");
1122 arg1
= encode_int (a1
% a2
);
1126 void prim_neg (void)
1128 a1
= decode_int (arg1
);
1129 arg1
= encode_int (- a1
);
1134 decode_2_int_args ();
1135 arg1
= encode_bool (a1
== a2
);
1141 decode_2_int_args ();
1142 arg1
= encode_bool (a1
< a2
);
1148 decode_2_int_args ();
1149 arg1
= encode_bool (a1
> a2
);
1153 void prim_ior (void)
1155 a1
= decode_int (arg1
);
1156 a2
= decode_int (arg2
);
1157 arg1
= encode_int (a1
| a2
);
1161 void prim_xor (void)
1163 a1
= decode_int (arg1
);
1164 a2
= decode_int (arg2
);
1165 arg1
= encode_int (a1
^ a2
);
1170 /*---------------------------------------------------------------------------*/
1172 /* List operations */
1174 void prim_pairp (void)
1177 arg1
= encode_bool (RAM_PAIR(arg1
));
1178 else if (IN_ROM(arg1
))
1179 arg1
= encode_bool (ROM_PAIR(arg1
));
1184 obj
cons (obj car
, obj cdr
)
1186 return alloc_ram_cell_init (COMPOSITE_FIELD0
| (car
>> 8), // TODO was ((car & 0x1f00) >> 8), probably redundant
1188 PAIR_FIELD2
| (cdr
>> 8), // TODO was ((cdr & 0x1f00) >> 8), probably redundant
1192 void prim_cons (void)
1194 arg1
= cons (arg1
, arg2
);
1198 void prim_car (void)
1202 if (!RAM_PAIR(arg1
))
1204 arg1
= ram_get_car (arg1
);
1206 else if (IN_ROM(arg1
))
1208 if (!ROM_PAIR(arg1
))
1210 arg1
= rom_get_car (arg1
);
1218 void prim_cdr (void)
1222 if (!RAM_PAIR(arg1
))
1224 arg1
= ram_get_cdr (arg1
);
1226 else if (IN_ROM(arg1
))
1228 if (!ROM_PAIR(arg1
))
1230 arg1
= rom_get_cdr (arg1
);
1238 void prim_set_car (void)
1242 if (!RAM_PAIR(arg1
))
1245 ram_set_car (arg1
, arg2
);
1255 void prim_set_cdr (void)
1259 if (!RAM_PAIR(arg1
))
1262 ram_set_cdr (arg1
, arg2
);
1272 void prim_nullp (void)
1274 arg1
= encode_bool (arg1
== OBJ_NULL
);
1277 /*---------------------------------------------------------------------------*/
1279 /* Vector operations */
1281 void prim_u8vectorp (void)
1284 arg1
= encode_bool (RAM_VECTOR(arg1
));
1285 else if (IN_ROM(arg1
))
1286 arg1
= encode_bool (ROM_VECTOR(arg1
));
1291 void prim_make_u8vector (void)
1293 obj elems
= alloc_vec_cell (arg1
); // arg1 is length
1294 arg1
= alloc_ram_cell_init (COMPOSITE_FIELD0
| (arg1
>> 8),
1296 VECTOR_FIELD2
| (elems
>> 8),
1298 // the contents of the vector are intentionally left as they were.
1299 // it is up to the library functions to set them accordingly
1302 void prim_u8vector_ref (void)
1303 { // TODO how do we deal with rom vectors ? as lists ? they're never all that long
1304 arg2
= decode_int (arg2
);
1308 if (!RAM_VECTOR(arg1
))
1309 TYPE_ERROR("vector");
1310 if (ram_get_car (arg1
) < arg2
)
1311 ERROR("vector index too large");
1312 arg1
= ram_get_cdr (arg1
);
1314 else if (IN_ROM(arg1
))
1316 if (!ROM_VECTOR(arg1
))
1317 TYPE_ERROR("vector");
1318 if (rom_get_car (arg1
) < arg2
)
1319 ERROR("vector index too large");
1320 arg1
= rom_get_cdr (arg1
);
1323 TYPE_ERROR("vector");
1333 arg1
= ram_get_field0 (arg1
); break;
1335 arg1
= ram_get_field1 (arg1
); break;
1337 arg1
= ram_get_field2 (arg1
); break;
1339 arg1
= ram_get_field3 (arg1
); break;
1342 arg1
= encode_int (arg1
);
1344 else // rom vector, stored as a list
1345 { // 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)
1347 arg1
= rom_get_cdr (arg1
);
1349 arg1
= rom_get_car (arg1
);
1355 void prim_u8vector_set (void)
1356 { // TODO a lot in common with ref, abstract that
1357 arg2
= decode_int (arg2
);
1358 arg3
= decode_int (arg3
);
1361 ERROR("byte vectors can only contain bytes");
1365 if (!RAM_VECTOR(arg1
))
1366 TYPE_ERROR("vector");
1367 if (ram_get_car (arg1
) < arg2
)
1368 ERROR("vector index too large");
1369 arg1
= ram_get_cdr (arg1
);
1371 // TODO no rom vector header can point to vector space, right ?
1373 TYPE_ERROR("vector");
1381 ram_set_field0 (arg1
, arg3
); break;
1383 ram_set_field1 (arg1
, arg3
); break;
1385 ram_set_field2 (arg1
, arg3
); break;
1387 ram_set_field3 (arg1
, arg3
); break;
1395 void prim_u8vector_length (void)
1399 if (!RAM_VECTOR(arg1
))
1400 TYPE_ERROR("vector");
1401 arg1
= encode_int (ram_get_car (arg1
));
1403 else if (IN_ROM(arg1
))
1405 if (!ROM_VECTOR(arg1
))
1406 TYPE_ERROR("vector");
1407 arg1
= rom_get_car (arg1
);
1410 TYPE_ERROR("vector");
1413 /*---------------------------------------------------------------------------*/
1415 /* Miscellaneous operations */
1417 void prim_eqp (void)
1419 arg1
= encode_bool (arg1
== arg2
);
1423 void prim_not (void)
1425 arg1
= encode_bool (arg1
== OBJ_FALSE
);
1428 void prim_symbolp (void)
1431 arg1
= encode_bool (RAM_SYMBOL(arg1
));
1432 else if (IN_ROM(arg1
))
1433 arg1
= encode_bool (ROM_SYMBOL(arg1
));
1438 void prim_stringp (void)
1441 arg1
= encode_bool (RAM_STRING(arg1
));
1442 else if (IN_ROM(arg1
))
1443 arg1
= encode_bool (ROM_STRING(arg1
));
1448 void prim_string2list (void)
1452 if (!RAM_STRING(arg1
))
1453 TYPE_ERROR("string");
1455 arg1
= ram_get_car (arg1
);
1457 else if (IN_ROM(arg1
))
1459 if (!ROM_STRING(arg1
))
1460 TYPE_ERROR("string");
1462 arg1
= rom_get_car (arg1
);
1465 TYPE_ERROR("string");
1468 void prim_list2string (void)
1470 arg1
= alloc_ram_cell_init (COMPOSITE_FIELD0
| ((arg1
& 0x1f00) >> 8),
1477 /*---------------------------------------------------------------------------*/
1479 /* Robot specific operations */
1482 void prim_print (void)
1497 int32
read_clock (void)
1503 now
= from_now( 0 );
1511 static int32 start
= 0;
1516 now
= tb
.time
* 1000 + tb
.millitm
;
1523 static int32 start
= 0;
1526 if (gettimeofday (&tv
, NULL
) == 0)
1528 now
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
1542 void prim_clock (void)
1544 arg1
= encode_int (read_clock ());
1548 void prim_motor (void)
1550 decode_2_int_args ();
1552 if (a1
< 1 || a1
> 2 || a2
< -100 || a2
> 100)
1553 ERROR("argument out of range to procedure \"motor\"");
1563 printf ("motor %d -> power=%d\n", a1
, a2
);
1573 void prim_led (void)
1575 decode_2_int_args ();
1576 a3
= decode_int (arg3
);
1578 if (a1
< 1 || a1
> 3 || a2
< 0 || a3
< 0)
1579 ERROR("argument out of range to procedure \"led\"");
1583 LED_set( a1
, a2
, a3
);
1589 printf ("led %d -> duty=%d period=%d\n", a1
, a2
, a3
);
1600 void prim_led2_color (void)
1602 a1
= decode_int (arg1
);
1604 if (a1
< 0 || a1
> 1)
1605 ERROR("argument out of range to procedure \"led2-color\"");
1609 LED2_color_set( a1
);
1615 printf ("led2-color -> %s\n", (a1
==0)?"green":"red");
1624 void prim_getchar_wait (void)
1626 decode_2_int_args();
1627 a1
= read_clock () + a1
;
1629 if (a1
< 0 || a2
< 1 || a2
> 3)
1630 ERROR("argument out of range to procedure \"getchar-wait\"");
1637 serial_port_set ports
;
1638 ports
= serial_rx_wait_with_timeout( a2
, a1
);
1640 arg1
= encode_int (serial_rx_read( ports
));
1655 arg1
= encode_int (_getch ());
1658 } while (read_clock () < a1
);
1663 arg1
= encode_int (getchar ());
1671 void prim_putchar (void)
1673 decode_2_int_args ();
1675 if (a1
< 0 || a1
> 255 || a2
< 1 || a2
> 3)
1676 ERROR("argument out of range to procedure \"putchar\"");
1680 serial_tx_write( a2
, a1
);
1696 void prim_beep (void)
1698 decode_2_int_args ();
1700 if (a1
< 1 || a1
> 255 || a2
< 0)
1701 ERROR("argument out of range to procedure \"beep\"");
1705 beep( a1
, from_now( a2
) );
1711 printf ("beep -> freq-div=%d duration=%d\n", a1
, a2
);
1721 void prim_adc (void)
1725 a1
= decode_int (arg1
);
1727 if (a1
< 1 || a1
> 3)
1728 ERROR("argument out of range to procedure \"adc\"");
1738 x
= read_clock () & 255;
1740 if (x
> 127) x
= 256 - x
;
1746 arg1
= encode_int (x
);
1750 void prim_dac (void)
1752 a1
= decode_int (arg1
);
1754 if (a1
< 0 || a1
> 255)
1755 ERROR("argument out of range to procedure \"dac\"");
1765 printf ("dac -> %d\n", a1
);
1774 void prim_sernum (void)
1790 arg1
= encode_int (x
);
1794 /*---------------------------------------------------------------------------*/
1798 int hidden_fgetc (FILE *f
)
1808 #define fgetc(f) hidden_fgetc(f)
1810 void write_hex_nibble (int n
)
1812 putchar ("0123456789ABCDEF"[n
]);
1815 void write_hex (uint8 n
)
1817 write_hex_nibble (n
>> 4);
1818 write_hex_nibble (n
& 0x0f);
1823 if (c
>= '0' && c
<= '9')
1826 if (c
>= 'A' && c
<= 'F')
1827 return (c
- 'A' + 10);
1829 if (c
>= 'a' && c
<= 'f')
1830 return (c
- 'a' + 10);
1835 int read_hex_byte (FILE *f
)
1837 int h1
= hex (fgetc (f
));
1838 int h2
= hex (fgetc (f
));
1840 if (h1
>= 0 && h2
>= 0)
1841 return (h1
<<4) + h2
;
1846 int read_hex_file (char *filename
)
1849 FILE *f
= fopen (filename
, "r");
1859 for (i
=0; i
<ROM_BYTES
; i
++)
1864 while ((c
= fgetc (f
)) != EOF
)
1866 if ((c
== '\r') || (c
== '\n'))
1870 (len
= read_hex_byte (f
)) < 0 ||
1871 (a1
= read_hex_byte (f
)) < 0 ||
1872 (a2
= read_hex_byte (f
)) < 0 ||
1873 (t
= read_hex_byte (f
)) < 0)
1879 sum
= len
+ a1
+ a2
+ t
;
1887 unsigned long adr
= ((unsigned long)hi16
<< 16) + a
- CODE_START
;
1889 if ((b
= read_hex_byte (f
)) < 0)
1892 if (adr
>= 0 && adr
< ROM_BYTES
)
1895 a
= (a
+ 1) & 0xffff;
1912 if ((a1
= read_hex_byte (f
)) < 0 ||
1913 (a2
= read_hex_byte (f
)) < 0)
1918 hi16
= (a1
<<8) + a2
;
1923 if ((b
= read_hex_byte (f
)) < 0)
1930 printf ("*** HEX file checksum error (expected 0x%02x)\n", sum
);
1936 if ((c
!= '\r') && (c
!= '\n'))
1947 printf ("*** HEX file syntax error\n");
1957 /*---------------------------------------------------------------------------*/
1959 #define FETCH_NEXT_BYTECODE() bytecode = rom_get (pc++)
1961 #define BEGIN_DISPATCH() \
1963 IF_TRACE(show_state (pc)); \
1964 FETCH_NEXT_BYTECODE(); \
1965 bytecode_hi4 = bytecode & 0xf0; \
1966 bytecode_lo4 = bytecode & 0x0f; \
1967 switch (bytecode_hi4 >> 4) {
1969 #define END_DISPATCH() }
1971 #define CASE(opcode) case (opcode>>4):;
1973 #define DISPATCH(); goto dispatch;
1978 #define bytecode TABLAT
1979 #define bytecode_hi4 WREG
1982 #define PUSH_CONSTANT1 0x00
1983 #define PUSH_CONSTANT2 0x10
1984 #define PUSH_STACK1 0x20
1985 #define PUSH_STACK2 0x30
1986 #define PUSH_GLOBAL 0x40
1987 #define SET_GLOBAL 0x50
1990 #define CALL_TOPLEVEL 0x80
1991 #define JUMP_TOPLEVEL 0x90
1993 #define GOTO_IF_FALSE 0xb0
1994 #define CLOSURE 0xc0
2001 char *prim_name
[48] =
2025 "prim #%graft-to-cont",
2026 "prim #%return-to-cont",
2030 "prim #%string->list",
2031 "prim #%list->string",
2032 "prim #%make-u8vector", // TODO was prim29
2033 "prim #%u8vector-ref", // TODO was prim30
2034 "prim #%u8vector-set!", // TODO was prim31
2039 "prim #%led2-color",
2040 "prim #%getchar-wait",
2044 "prim #%u8vector?", // TODO was dac, but it's not plugged to anything
2046 "prim #%u8vector-length", // TODO was prim43
2047 "push-constant [long]",
2055 #define PUSH_ARG1() push_arg1 ()
2058 void push_arg1 (void)
2060 env
= cons (arg1
, env
);
2066 obj o
= ram_get_car (env
);
2067 env
= ram_get_cdr (env
);
2071 void pop_procedure (void)
2077 if (!RAM_CLOSURE(arg1
))
2078 TYPE_ERROR("procedure");
2080 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
2082 else if (IN_ROM(arg1
))
2084 if (!ROM_CLOSURE(arg1
))
2085 TYPE_ERROR("procedure");
2087 entry
= rom_get_entry (arg1
) + CODE_START
;
2090 TYPE_ERROR("procedure");
2093 void handle_arity_and_rest_param (void)
2097 np
= rom_get (entry
++);
2099 if ((np
& 0x80) == 0)
2102 ERROR("wrong number of arguments");
2109 ERROR("wrong number of arguments");
2117 arg3
= cons (arg4
, arg3
);
2123 arg1
= cons (arg3
, arg1
);
2128 void build_env (void)
2134 arg1
= cons (arg3
, arg1
);
2142 void save_cont (void)
2144 // the second half is a closure
2145 arg3
= alloc_ram_cell_init (CLOSURE_FIELD0
| (pc
>> 11),
2147 ((pc
& 0x0007) << 5) | (env
>> 8),
2149 cont
= alloc_ram_cell_init (COMPOSITE_FIELD0
| (cont
>> 8),
2151 CONTINUATION_FIELD2
| (arg3
>> 8),
2156 void interpreter (void)
2160 pc
= (CODE_START
+ 4) + ((rom_addr
)rom_get (CODE_START
+2) << 2);
2164 /***************************************************************************/
2165 CASE(PUSH_CONSTANT1
);
2167 IF_TRACE(printf(" (push-constant "); show (bytecode_lo4
); printf (")\n"));
2169 arg1
= bytecode_lo4
;
2175 /***************************************************************************/
2176 CASE(PUSH_CONSTANT2
);
2178 IF_TRACE(printf(" (push-constant "); show (bytecode_lo4
+16); printf (")\n"));
2179 arg1
= bytecode_lo4
+16;
2185 /***************************************************************************/
2188 IF_TRACE(printf(" (push-stack %d)\n", bytecode_lo4
));
2192 while (bytecode_lo4
!= 0)
2194 arg1
= ram_get_cdr (arg1
);
2198 arg1
= ram_get_car (arg1
);
2204 /***************************************************************************/
2207 IF_TRACE(printf(" (push-stack %d)\n", bytecode_lo4
+16));
2213 while (bytecode_lo4
!= 0)
2215 arg1
= ram_get_cdr (arg1
);
2219 arg1
= ram_get_car (arg1
);
2225 /***************************************************************************/
2228 IF_TRACE(printf(" (push-global %d)\n", bytecode_lo4
));
2230 arg1
= get_global (bytecode_lo4
);
2236 /***************************************************************************/
2239 IF_TRACE(printf(" (set-global %d)\n", bytecode_lo4
));
2241 set_global (bytecode_lo4
, POP());
2245 /***************************************************************************/
2248 IF_TRACE(printf(" (call %d)\n", bytecode_lo4
));
2253 handle_arity_and_rest_param ();
2264 /***************************************************************************/
2267 IF_TRACE(printf(" (jump %d)\n", bytecode_lo4
));
2272 handle_arity_and_rest_param ();
2282 /***************************************************************************/
2283 CASE(CALL_TOPLEVEL
);
2285 FETCH_NEXT_BYTECODE();
2288 FETCH_NEXT_BYTECODE();
2290 IF_TRACE(printf(" (call-toplevel 0x%04x)\n", ((arg2
<< 8) | bytecode
) + CODE_START
));
2292 entry
= (arg2
<< 8) + bytecode
+ CODE_START
; // TODO FOOBAR we have the last 4 bits of the opcode free, to do pretty much anything
2295 na
= rom_get (entry
++);
2308 /***************************************************************************/
2309 CASE(JUMP_TOPLEVEL
);
2311 FETCH_NEXT_BYTECODE();
2314 FETCH_NEXT_BYTECODE();
2316 IF_TRACE(printf(" (jump-toplevel 0x%04x)\n", ((arg2
<< 8) | bytecode
) + CODE_START
));
2318 entry
= (arg2
<< 8) + bytecode
+ CODE_START
; // TODO this is a common pattern
2321 na
= rom_get (entry
++);
2333 /***************************************************************************/
2336 FETCH_NEXT_BYTECODE();
2339 FETCH_NEXT_BYTECODE();
2341 IF_TRACE(printf(" (goto 0x%04x)\n", (rom_addr
)((arg2
<< 8) + bytecode
+ CODE_START
)));
2343 pc
= (arg2
<< 8) + bytecode
+ CODE_START
;
2347 /***************************************************************************/
2348 CASE(GOTO_IF_FALSE
);
2350 FETCH_NEXT_BYTECODE();
2353 FETCH_NEXT_BYTECODE();
2355 IF_TRACE(printf(" (goto-if-false 0x%04x)\n", (rom_addr
)((arg2
<< 8) + bytecode
+ CODE_START
)));
2357 if (POP() == OBJ_FALSE
)
2358 pc
= (arg2
<< 8) + bytecode
+ CODE_START
;
2362 /***************************************************************************/
2365 FETCH_NEXT_BYTECODE();
2368 FETCH_NEXT_BYTECODE();
2370 IF_TRACE(printf(" (closure 0x%04x)\n", (arg2
<< 8) | bytecode
));
2372 arg3
= POP(); // env
2374 entry
= (arg2
<< 8) | bytecode
; // TODO original had no CODE_START, why ?
2376 arg1
= alloc_ram_cell_init (CLOSURE_FIELD0
| (arg2
>> 3),
2377 ((arg2
& 0x07) << 5) | (bytecode
>> 3),
2378 ((bytecode
& 0x07) << 5) |((arg3
& 0x1f00) >> 8),
2388 /***************************************************************************/
2391 IF_TRACE(printf(" (%s)\n", prim_name
[bytecode_lo4
]));
2393 switch (bytecode_lo4
)
2396 arg1
= POP(); prim_numberp (); PUSH_ARG1(); break;
2398 arg2
= POP(); arg1
= POP(); prim_add (); PUSH_ARG1(); break;
2400 arg2
= POP(); arg1
= POP(); prim_sub (); PUSH_ARG1(); break;
2402 arg2
= POP(); arg1
= POP(); prim_mul (); PUSH_ARG1(); break;
2404 arg2
= POP(); arg1
= POP(); prim_div (); PUSH_ARG1(); break;
2406 arg2
= POP(); arg1
= POP(); prim_rem (); PUSH_ARG1(); break;
2408 arg1
= POP(); prim_neg (); PUSH_ARG1(); break;
2410 arg2
= POP(); arg1
= POP(); prim_eq (); PUSH_ARG1(); break;
2412 arg2
= POP(); arg1
= POP(); prim_lt (); PUSH_ARG1(); break;
2414 arg2
= POP(); arg1
= POP(); prim_ior (); PUSH_ARG1(); break;
2416 arg2
= POP(); arg1
= POP(); prim_gt (); PUSH_ARG1(); break;
2418 arg2
= POP(); arg1
= POP(); prim_xor (); PUSH_ARG1(); break;
2420 arg1
= POP(); prim_pairp (); PUSH_ARG1(); break;
2422 arg2
= POP(); arg1
= POP(); prim_cons (); PUSH_ARG1(); break;
2424 arg1
= POP(); prim_car (); PUSH_ARG1(); break;
2426 arg1
= POP(); prim_cdr (); PUSH_ARG1(); break;
2431 /***************************************************************************/
2434 IF_TRACE(printf(" (%s)\n", prim_name
[bytecode_lo4
+16]));
2436 switch (bytecode_lo4
)
2439 arg2
= POP(); arg1
= POP(); prim_set_car (); break;
2441 arg2
= POP(); arg1
= POP(); prim_set_cdr (); break;
2443 arg1
= POP(); prim_nullp (); PUSH_ARG1(); break;
2445 arg2
= POP(); arg1
= POP(); prim_eqp (); PUSH_ARG1(); break;
2447 arg1
= POP(); prim_not (); PUSH_ARG1(); break;
2449 /* prim #%get-cont */
2454 /* prim #%graft-to-cont */
2456 arg1
= POP(); /* thunk to call */
2457 cont
= POP(); /* continuation */
2464 handle_arity_and_rest_param ();
2474 /* prim #%return-to-cont */
2476 arg1
= POP(); /* value to return */
2477 cont
= POP(); /* continuation */
2479 arg2
= ram_get_cdr (cont
);
2481 pc
= ram_get_entry (arg2
);
2483 env
= ram_get_cdr (arg2
);
2484 cont
= ram_get_car (cont
);
2494 /* prim #%symbol? */
2495 arg1
= POP(); prim_symbolp (); PUSH_ARG1(); break;
2497 /* prim #%string? */
2498 arg1
= POP(); prim_stringp (); PUSH_ARG1(); break;
2500 /* prim #%string->list */
2501 arg1
= POP(); prim_string2list (); PUSH_ARG1(); break;
2503 /* prim #%list->string */
2504 arg1
= POP(); prim_list2string (); PUSH_ARG1(); break;
2506 /* prim #%make-u8vector */
2507 arg1
= POP(); prim_make_u8vector (); PUSH_ARG1(); break;
2509 /* prim #%u8vector-ref */
2510 arg2
= POP(); arg1
= POP(); prim_u8vector_ref (); PUSH_ARG1(); break;
2512 /* prim #%u8vector-set! */
2513 arg3
= POP(); arg2
= POP(); arg1
= POP(); prim_u8vector_set (); break;
2518 /***************************************************************************/
2521 IF_TRACE(printf(" (%s)\n", prim_name
[bytecode_lo4
+32]));
2523 switch (bytecode_lo4
)
2532 prim_clock (); PUSH_ARG1(); break;
2535 arg2
= POP(); arg1
= POP(); prim_motor (); break;
2538 arg3
= POP(); arg2
= POP(); arg1
= POP(); prim_led (); ;break;
2540 /* prim #%led2-color */
2541 arg1
= POP(); prim_led2_color (); break;
2543 /* prim #%getchar-wait */
2544 arg2
= POP(); arg1
= POP(); prim_getchar_wait (); PUSH_ARG1(); break;
2546 /* prim #%putchar */
2547 arg2
= POP(); arg1
= POP(); prim_putchar (); break;
2550 arg2
= POP(); arg1
= POP(); prim_beep (); break;
2553 arg1
= POP(); prim_adc (); PUSH_ARG1(); break;
2555 /* prim #%u8vector? */
2556 arg1
= POP(); prim_u8vectorp (); PUSH_ARG1(); break;
2559 prim_sernum (); PUSH_ARG1(); break;
2561 /* prim #%u8vector-length */
2562 arg1
= POP(); prim_u8vector_length (); PUSH_ARG1(); break;
2564 /* push-constant [long] */
2565 FETCH_NEXT_BYTECODE(); // TODO BREGG this is a test, the compiler only knows what's in rom or lower, so we only need a byte, unless we change the number of rom addresses OOPS, 8 bits is not enough even for fixnums, we'd probably be ok with 12, though (actually 9, but that's harder to have and 12 gives us more room should we increase the number of rom addresses)
2567 FETCH_NEXT_BYTECODE();
2568 arg1
= (arg2
<< 8) | bytecode
;
2585 arg2
= ram_get_cdr (cont
);
2586 pc
= ram_get_entry (arg2
);
2587 env
= ram_get_cdr (arg2
);
2588 cont
= ram_get_car (cont
);
2596 /***************************************************************************/
2601 /*---------------------------------------------------------------------------*/
2607 printf ("usage: sim file.hex\n");
2611 int main (int argc
, char *argv
[])
2614 rom_addr rom_start_addr
= 0;
2616 if (argc
> 1 && argv
[1][0] == '-' && argv
[1][1] == 's')
2623 if ((h1
= hex (argv
[1][2])) < 0 ||
2624 (h2
= hex (argv
[1][3])) < 0 ||
2625 (h3
= hex (argv
[1][4])) != 0 ||
2626 (h4
= hex (argv
[1][5])) != 0 ||
2630 rom_start_addr
= (h1
<< 12) | (h2
<< 8) | (h3
<< 4) | h4
;
2637 printf ("Start address = 0x%04x\n", rom_start_addr
); // TODO says 0, but should be CODE_START ?
2643 if (!read_hex_file (argv
[1]))
2644 printf ("*** Could not read hex file \"%s\"\n", argv
[1]);
2649 if (rom_get (CODE_START
+0) != 0xfb ||
2650 rom_get (CODE_START
+1) != 0xd7)
2651 printf ("*** The hex file was not compiled with PICOBIT\n");
2655 for (i
=0; i
<8192; i
++)
2656 if (rom_get (i
) != 0xff)
2657 printf ("rom_mem[0x%04x] = 0x%02x\n", i
, rom_get (i
));
2663 printf ("**************** memory needed = %d\n", max_live
+1);
2673 /*---------------------------------------------------------------------------*/