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
83 #define IF_GC_TRACE(x) x
86 #define IF_GC_TRACE(x)
89 /*---------------------------------------------------------------------------*/
94 #define ERROR(msg) halt_with_error()
95 #define TYPE_ERROR(prim, type) halt_with_error()
102 #define ERROR(msg) error (msg)
103 #define TYPE_ERROR(prim, type) type_error (prim, type)
105 void error (char *msg
)
107 printf ("ERROR: %s\n", msg
);
111 void type_error (char *prim
, char *type
)
113 printf ("ERROR: %s: An argument of type %s was expected\n", prim
, type
);
120 /*---------------------------------------------------------------------------*/
128 typedef uint16 ram_addr
;
129 typedef uint16 rom_addr
;
133 /*---------------------------------------------------------------------------*/
135 #define MAX_VEC_ENCODING 8191
136 #define MIN_VEC_ENCODING 4096
137 #define VEC_BYTES ((MAX_VEC_ENCODING - MIN_VEC_ENCODING + 1)*4)
138 // TODO this is new. if the pic has less than 8k of memory, start this lower
139 // TODO max was 8192 for ram, would have been 1 too much (watch out, master branch still has that), now corrected
140 // TODO the pic actually has 2k, so change these FOOBAR
141 // 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
143 #define MAX_RAM_ENCODING 4095
144 #define MIN_RAM_ENCODING 512
145 #define RAM_BYTES ((MAX_RAM_ENCODING - MIN_RAM_ENCODING + 1)*4)
146 // TODO watch out if we address more than what the PIC actually has
149 // TODO subtracts min_ram since vectors are actually in ram
150 #define OBJ_TO_VEC_ADDR(o,f) (((ram_addr)((uint16)(o) - MIN_RAM_ENCODING) << 2) + (f))
151 #define OBJ_TO_RAM_ADDR(o,f) (((ram_addr)((uint16)(o) - MIN_RAM_ENCODING) << 2) + (f))
152 #define OBJ_TO_ROM_ADDR(o,f) (((rom_addr)((uint16)(o) - MIN_ROM_ENCODING) << 2) + (CODE_START + 4 + (f)))
157 #define ram_get(a) *(uint8*)(a+0x200)
158 #define ram_set(a,x) *(uint8*)(a+0x200) = (x)
159 // TODO change these since we change proportion of ram and rom ?
165 uint8 ram_mem
[RAM_BYTES
+ VEC_BYTES
];
167 #define ram_get(a) ram_mem[a]
168 #define ram_set(a,x) ram_mem[a] = (x)
173 /*---------------------------------------------------------------------------*/
177 /* #if WORD_BITS == 8 */
178 /* #endif */ // TODO useless
180 uint8
rom_get (rom_addr a
)
182 return *(rom uint8
*)a
;
190 #define ROM_BYTES 8192
191 // TODO the new pics have 32k, change this ? minus the vm size, firmware ?
193 uint8 rom_mem
[ROM_BYTES
] =
196 #define PUTCHAR_LIGHT_not
199 0xFB, 0xD7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x32
200 , 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00
201 , 0x08, 0x50, 0x80, 0x16, 0xFE, 0xE8, 0x00, 0xFC
202 , 0x32, 0x80, 0x2D, 0xFE, 0xFC, 0x31, 0x80, 0x43
203 , 0xFE, 0xFC, 0x33, 0x80, 0x2D, 0xFE, 0xFC, 0x31
204 , 0x80, 0x43, 0xFE, 0x90, 0x16, 0x01, 0x20, 0xFC
205 , 0x32, 0xE3, 0xB0, 0x37, 0x09, 0xF3, 0xFF, 0x20
206 , 0xFC, 0x33, 0xE3, 0xB0, 0x40, 0x0A, 0xF3, 0xFF
207 , 0x08, 0xF3, 0xFF, 0x01, 0x40, 0x21, 0xD1, 0x00
208 , 0x02, 0xC0, 0x4C, 0x71, 0x01, 0x20, 0x50, 0x90
209 , 0x51, 0x00, 0xF1, 0x40, 0xD8, 0xB0, 0x59, 0x90
213 0xFB, 0xD7, 0x00, 0x00, 0x80, 0x08, 0xFE, 0xE8
214 , 0x00, 0xF6, 0xF5, 0x90, 0x08
218 uint8
rom_get (rom_addr a
)
220 return rom_mem
[a
-CODE_START
];
225 /*---------------------------------------------------------------------------*/
233 fixnum n MIN_FIXNUM -> 3 ... MAX_FIXNUM -> 3 + (MAX_FIXNUM-MIN_FIXNUM)
234 rom object 4 + (MAX_FIXNUM-MIN_FIXNUM) ... MIN_RAM_ENCODING-1
235 ram object MIN_RAM_ENCODING ... MAX_RAM_ENCODING
236 vector MIN_VEC_ENCODING ... 8191
238 layout of memory allocated objects:
240 G's represent mark bits used by the gc
242 bignum n 00G00000 uuuuuuuu hhhhhhhh llllllll (24 bit signed integer)
243 TODO we could have 29-bit integers
245 pair 1GGaaaaa aaaaaaaa 000ddddd dddddddd
248 gives an address space of 2^13 * 4 = 32k divided between simple objects,
251 symbol 1GG00000 00000000 00100000 00000000
253 string 1GG***** *chars** 01000000 00000000
255 vector 1GG***** *elems** 01100000 00000000 TODO old
256 vector 1GGxxxxx xxxxxxxx 011yyyyy yyyyyyyy
257 x is length of the vector, in bytes (stored raw, not encoded as an object)
258 y is pointer to the elements themselves (stored in vector space)
259 TODO pointer could be shorter since it always points in vector space, same for length, will never be this long
260 TODO show how vectors are represented in vector space
261 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
262 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
263 TODO how to deal with gc ? mayeb when we sweep a vector header, go sweep its contents in vector space ?
265 closure 01Gaaaaa aaaaaaaa aaaxxxxx xxxxxxxx
266 0x5ff<a<0x4000 is entry
267 x is pointer to environment
268 the reason why the environment is on the cdr (and the entry is split on 3
269 bytes) is that, when looking for a variable, a closure is considered to be a
270 pair. The compiler adds an extra offset to any variable in the closure's
271 environment, so the car of the closure (which doesn't really exist) is never
272 checked, but the cdr is followed to find the other bindings
274 continuation 1GGxxxxx xxxxxxxx 100yyyyy yyyyyyyy
275 x is parent continuation
276 y is pointer to the second half, which is a closure (contains env and entry)
278 An environment is a list of objects built out of pairs. On entry to
279 a procedure the environment is the list of parameters to which is
280 added the environment of the closure being called.
282 The first byte at the entry point of a procedure gives the arity of
285 n = 0 to 127 -> procedure has n parameters (no rest parameter)
286 n = -128 to -1 -> procedure has -n parameters, the last is
294 #define MIN_FIXNUM_ENCODING 3
296 #define MAX_FIXNUM 255
297 #define MIN_ROM_ENCODING (MIN_FIXNUM_ENCODING+MAX_FIXNUM-MIN_FIXNUM+1)
299 #define ENCODE_FIXNUM(n) ((obj)(n) + (MIN_FIXNUM_ENCODING - MIN_FIXNUM))
300 #define DECODE_FIXNUM(o) ((int32)(o) - (MIN_FIXNUM_ENCODING - MIN_FIXNUM))
302 // TODO why this ifdef ?
304 #define IN_VEC(o) ((o) >= MIN_VEC_ENCODING)
305 #define IN_RAM(o) (!IN_VEC(o) && ((o) >= MIN_RAM_ENCODING))
306 #define IN_ROM(o) (!IN_VEC(o) && !IN_RAM(o) && ((o) >= MIN_ROM_ENCODING))
308 // TODO performance ?
310 // bignum first byte : 00G00000
311 #define BIGNUM_FIELD0 0
312 #define RAM_BIGNUM(o) ((ram_get_field0 (o) & 0xc0) == BIGNUM_FIELD0)
313 #define ROM_BIGNUM(o) ((rom_get_field0 (o) & 0xc0) == BIGNUM_FIELD0)
315 // composite first byte : 1GGxxxxx
316 #define COMPOSITE_FIELD0 0x80
317 #define RAM_COMPOSITE(o) ((ram_get_field0 (o) & 0x80) == COMPOSITE_FIELD0)
318 #define ROM_COMPOSITE(o) ((rom_get_field0 (o) & 0x80) == COMPOSITE_FIELD0)
320 // pair third byte : 000xxxxx
321 #define PAIR_FIELD2 0
322 #define RAM_PAIR(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == PAIR_FIELD2))
323 #define ROM_PAIR(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == PAIR_FIELD2))
325 // symbol third byte : 001xxxxx
326 #define SYMBOL_FIELD2 0x20
327 #define RAM_SYMBOL(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == SYMBOL_FIELD2))
328 #define ROM_SYMBOL(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == SYMBOL_FIELD2))
330 // string third byte : 010xxxxx
331 #define STRING_FIELD2 0x40
332 #define RAM_STRING(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == STRING_FIELD2))
333 #define ROM_STRING(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == STRING_FIELD2))
335 // vector third byte : 011xxxxx
336 #define VECTOR_FIELD2 0x60
337 #define RAM_VECTOR(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == VECTOR_FIELD2))
338 #define ROM_VECTOR(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == VECTOR_FIELD2))
339 // TODO this is only for headers
341 // continuation third byte : 100xxxxx
342 #define CONTINUATION_FIELD2 0x80
343 #define RAM_CONTINUATION(o) (RAM_COMPOSITE (o) && ((ram_get_field2 (o) & 0xe0) == CONTINUATION_FIELD2))
344 #define ROM_CONTINUATION(o) (ROM_COMPOSITE (o) && ((rom_get_field2 (o) & 0xe0) == CONTINUATION_FIELD2))
346 // closure first byte : 01Gxxxxx
347 #define CLOSURE_FIELD0 0x40
348 #define RAM_CLOSURE(o) ((ram_get_field0 (o) & 0xc0) == CLOSURE_FIELD0)
349 #define ROM_CLOSURE(o) ((rom_get_field0 (o) & 0xc0) == CLOSURE_FIELD0)
352 /*---------------------------------------------------------------------------*/
354 #define RAM_GET_FIELD0_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,0))
355 #define RAM_SET_FIELD0_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,0), val)
356 #define ROM_GET_FIELD0_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,0))
358 #define RAM_GET_GC_TAGS_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x60)
359 #define RAM_GET_GC_TAG0_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x20)
360 #define RAM_GET_GC_TAG1_MACRO(o) (RAM_GET_FIELD0_MACRO(o) & 0x40)
361 #define RAM_SET_GC_TAGS_MACRO(o,tags) \
362 (RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0x9f) | (tags)))
363 #define RAM_SET_GC_TAG0_MACRO(o,tag) \
364 RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0xdf) | (tag))
365 #define RAM_SET_GC_TAG1_MACRO(o,tag) \
366 RAM_SET_FIELD0_MACRO(o,(RAM_GET_FIELD0_MACRO(o) & 0xbf) | (tag))
369 #define RAM_GET_FIELD1_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,1))
370 #define RAM_GET_FIELD2_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,2))
371 #define RAM_GET_FIELD3_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,3))
372 #define RAM_SET_FIELD1_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,1), val)
373 #define RAM_SET_FIELD2_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,2), val)
374 #define RAM_SET_FIELD3_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,3), val)
375 #define ROM_GET_FIELD1_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,1))
376 #define ROM_GET_FIELD2_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,2))
377 #define ROM_GET_FIELD3_MACRO(o) rom_get (OBJ_TO_ROM_ADDR(o,3))
378 #define VEC_GET_BYTE0_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,0))
379 #define VEC_GET_BYTE1_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,1))
380 #define VEC_GET_BYTE2_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,2))
381 #define VEC_GET_BYTE3_MACRO(o) ram_get (OBJ_TO_RAM_ADDR(o,3))
382 #define VEC_SET_BYTE0_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,0), val)
383 #define VEC_SET_BYTE1_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,1), val)
384 #define VEC_SET_BYTE2_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,2), val)
385 #define VEC_SET_BYTE3_MACRO(o,val) ram_set (OBJ_TO_RAM_ADDR(o,3), val)
386 // 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 ?
389 uint8
ram_get_gc_tags (obj o
) { return RAM_GET_GC_TAGS_MACRO(o
); }
390 uint8
ram_get_gc_tag0 (obj o
) { return RAM_GET_GC_TAG0_MACRO(o
); }
391 uint8
ram_get_gc_tag1 (obj o
) { return RAM_GET_GC_TAG1_MACRO(o
); }
392 void ram_set_gc_tags (obj o
, uint8 tags
) { RAM_SET_GC_TAGS_MACRO(o
, tags
); }
393 void ram_set_gc_tag0 (obj o
, uint8 tag
) { RAM_SET_GC_TAG0_MACRO(o
,tag
); }
394 void ram_set_gc_tag1 (obj o
, uint8 tag
) { RAM_SET_GC_TAG1_MACRO(o
,tag
); }
395 uint8
ram_get_field0 (obj o
) { return RAM_GET_FIELD0_MACRO(o
); }
396 word
ram_get_field1 (obj o
) { return RAM_GET_FIELD1_MACRO(o
); }
397 word
ram_get_field2 (obj o
) { return RAM_GET_FIELD2_MACRO(o
); }
398 word
ram_get_field3 (obj o
) { return RAM_GET_FIELD3_MACRO(o
); }
399 void ram_set_field0 (obj o
, uint8 val
) { RAM_SET_FIELD0_MACRO(o
,val
); }
400 void ram_set_field1 (obj o
, word val
) { RAM_SET_FIELD1_MACRO(o
,val
); }
401 void ram_set_field2 (obj o
, word val
) { RAM_SET_FIELD2_MACRO(o
,val
); }
402 void ram_set_field3 (obj o
, word val
) { RAM_SET_FIELD3_MACRO(o
,val
); }
403 uint8
rom_get_field0 (obj o
) { return ROM_GET_FIELD0_MACRO(o
); }
404 word
rom_get_field1 (obj o
) { return ROM_GET_FIELD1_MACRO(o
); }
405 word
rom_get_field2 (obj o
) { return ROM_GET_FIELD2_MACRO(o
); }
406 word
rom_get_field3 (obj o
) { return ROM_GET_FIELD3_MACRO(o
); }
407 /* word vec_get_byte0 (obj o) { return VEC_GET_BYTE0_MACRO(o); } */
408 /* word vec_get_byte1 (obj o) { return VEC_GET_BYTE1_MACRO(o); } */
409 /* word vec_get_byte2 (obj o) { return VEC_GET_BYTE2_MACRO(o); } */
410 /* word vec_get_byte3 (obj o) { return VEC_GET_BYTE3_MACRO(o); } */
411 /* word vec_set_byte0 (obj o, word val) { VEC_SET_BYTE0_MACRO(o,val); } */
412 /* word vec_set_byte1 (obj o, word val) { VEC_SET_BYTE1_MACRO(o,val); } */
413 /* word vec_set_byte2 (obj o, word val) { VEC_SET_BYTE2_MACRO(o,val); } */
414 /* word vec_set_byte3 (obj o, word val) { VEC_SET_BYTE3_MACRO(o,val); } */
415 // TODO use the word field or byte ? actually the ram functions are used, since this is in ram anyways
417 obj
ram_get_car (obj o
)
418 { return ((ram_get_field0 (o
) & 0x1f) << 8) | ram_get_field1 (o
); }
419 obj
rom_get_car (obj o
)
420 { return ((rom_get_field0 (o
) & 0x1f) << 8) | rom_get_field1 (o
); }
421 obj
ram_get_cdr (obj o
)
422 { return ((ram_get_field2 (o
) & 0x1f) << 8) | ram_get_field3 (o
); }
423 obj
rom_get_cdr (obj o
)
424 { return ((rom_get_field2 (o
) & 0x1f) << 8) | rom_get_field3 (o
); }
425 void ram_set_car (obj o
, obj val
)
427 ram_set_field0 (o
, (val
>> 8) | (ram_get_field0 (o
) & 0xe0));
428 ram_set_field1 (o
, val
& 0xff);
430 void ram_set_cdr (obj o
, obj val
)
432 ram_set_field2 (o
, (val
>> 8) | (ram_get_field2 (o
) & 0xe0));
433 ram_set_field3 (o
, val
& 0xff);
435 obj
ram_get_entry (obj o
)
437 return (((ram_get_field0 (o
) & 0x1f) << 11)
438 | (ram_get_field1 (o
) << 3)
439 | (ram_get_field2 (o
) >> 5));
441 obj
rom_get_entry (obj o
)
443 return (((rom_get_field0 (o
) & 0x1f) << 11)
444 | (rom_get_field1 (o
) << 3)
445 | (rom_get_field2 (o
) >> 5));
448 obj
get_global (uint8 i
)
449 // globals occupy the beginning of ram, with 2 globals per word
452 return ram_get_cdr (MIN_RAM_ENCODING
+ (i
/ 2));
454 return ram_get_car (MIN_RAM_ENCODING
+ (i
/ 2));
457 void set_global (uint8 i
, obj o
)
460 ram_set_cdr (MIN_RAM_ENCODING
+ (i
/ 2), o
);
462 ram_set_car (MIN_RAM_ENCODING
+ (i
/ 2), o
);
466 void show_type (obj o
) // for debugging purposes
469 if (o
== OBJ_FALSE
) printf("#f");
470 else if (o
== OBJ_TRUE
) printf("#t");
471 else if (o
== OBJ_NULL
) printf("()");
472 else if (o
< MIN_ROM_ENCODING
) printf("fixnum");
475 if (RAM_BIGNUM(o
)) printf("ram bignum");
476 else if (RAM_PAIR(o
)) printf("ram pair");
477 else if (RAM_SYMBOL(o
)) printf("ram symbol");
478 else if (RAM_STRING(o
)) printf("ram string");
479 else if (RAM_VECTOR(o
)) printf("ram vector");
480 else if (RAM_CONTINUATION(o
)) printf("ram continuation");
481 else if (RAM_CLOSURE(o
)) printf("ram closure");
485 if (ROM_BIGNUM(o
)) printf("rom bignum");
486 else if (ROM_PAIR(o
)) printf("rom pair");
487 else if (ROM_SYMBOL(o
)) printf("rom symbol");
488 else if (ROM_STRING(o
)) printf("rom string");
489 else if (ROM_VECTOR(o
)) printf("rom vector");
490 else if (ROM_CONTINUATION(o
)) printf("rom continuation");
491 else if (RAM_CLOSURE(o
)) printf("rom closure");
498 /*---------------------------------------------------------------------------*/
500 /* Interface to GC */
502 // TODO explain what each tag means, with 1-2 mark bits
503 #define GC_TAG_0_LEFT (1<<5)
504 // TODO was 3<<5, changed to play nice with procedures and bignums, but should actually set only this bit, not clear the other
505 #define GC_TAG_1_LEFT (2<<5)
506 #define GC_TAG_UNMARKED (0<<5)
508 /* Number of object fields of objects in ram */
509 #define HAS_2_OBJECT_FIELDS(visit) (RAM_PAIR(visit) || RAM_CONTINUATION(visit))
510 #define HAS_1_OBJECT_FIELD(visit) (RAM_COMPOSITE(visit) || RAM_CLOSURE(visit))
511 // all composites except pairs and continuations have 1 object field
512 // TODO if we ever have true bignums, bignums will have 1 object field
514 #define NIL OBJ_FALSE
516 /*---------------------------------------------------------------------------*/
518 /* Garbage collector */
520 obj free_list
; /* list of unused cells */
521 obj free_list_vec
; /* list of unused cells in vector space */
523 obj arg1
; /* root set */
526 obj arg4
; // TODO only used once as a true arg, is swap space the rest of the time
527 obj arg5
; // OOPS we need that for u8vector-copy!
531 uint8 na
; /* interpreter variables */
542 void init_ram_heap (void)
545 obj o
= MAX_RAM_ENCODING
;
549 while (o
> (MIN_RAM_ENCODING
+ (glovars
+ 1) / 2))
550 // we don't want to add globals to the free list, and globals occupy the
551 // beginning of memory at the rate of 2 globals per word (car and cdr)
553 ram_set_gc_tags (o
, GC_TAG_UNMARKED
);
554 ram_set_car (o
, free_list
);
559 free_list_vec
= MIN_VEC_ENCODING
;
560 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
561 // each node of the free list must know the free length that follows it
562 // this free length is stored in words, not in bytes
563 // if we did count in bytes, the number might need more than 13 bits
564 ram_set_cdr (free_list_vec
, VEC_BYTES
/ 4);
565 // TODO so, at the start, we have only 1 node that says the whole space is free
567 for (i
=0; i
<glovars
; i
++)
568 set_global (i
, OBJ_FALSE
);
595 // 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
596 IF_GC_TRACE(printf ("push stack=%d visit=%d (tag=%d)\n", stack
, visit
, ram_get_gc_tags (visit
)>>5));
598 if ((HAS_1_OBJECT_FIELD (visit
) && ram_get_gc_tag0 (visit
))
599 || (HAS_2_OBJECT_FIELDS (visit
)
600 && (ram_get_gc_tags (visit
) != GC_TAG_UNMARKED
)))
601 // TODO ugly condition
602 IF_GC_TRACE(printf ("case 1\n"));
605 if (HAS_2_OBJECT_FIELDS(visit
)) // pairs and continuations
607 IF_GC_TRACE(printf ("case 5\n"));
611 temp
= ram_get_cdr (visit
);
615 IF_GC_TRACE(printf ("case 6\n"));
616 ram_set_gc_tags (visit
, GC_TAG_1_LEFT
);
617 ram_set_cdr (visit
, stack
);
621 IF_GC_TRACE(printf ("case 7\n"));
626 if (HAS_1_OBJECT_FIELD(visit
))
628 IF_GC_TRACE(printf ("case 8\n"));
632 if (RAM_CLOSURE(visit
)) // closures have the pointer in the cdr
633 temp
= ram_get_cdr (visit
);
635 temp
= ram_get_car (visit
);
639 IF_GC_TRACE(printf ("case 9\n"));
640 ram_set_gc_tag0 (visit
, GC_TAG_0_LEFT
);
641 if (RAM_CLOSURE(visit
))
642 ram_set_cdr (visit
, stack
);
644 ram_set_car (visit
, stack
);
649 IF_GC_TRACE(printf ("case 10\n"));
652 IF_GC_TRACE(printf ("case 11\n"));
654 ram_set_gc_tag0 (visit
, GC_TAG_0_LEFT
);
659 /* 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)); */
660 // TODO, like for push, getting the gc tags of nil is not great
661 IF_GC_TRACE(printf ("pop stack=%d visit=%d (tag=%d)\n", stack
, visit
, ram_get_gc_tags (visit
)>>6));
665 if (HAS_2_OBJECT_FIELDS(stack
) && ram_get_gc_tag1 (stack
))
667 IF_GC_TRACE(printf ("case 13\n"));
669 temp
= ram_get_cdr (stack
); /* pop through cdr */
670 ram_set_cdr (stack
, visit
);
674 ram_set_gc_tag1(visit
, GC_TAG_UNMARKED
);
675 // we unset the "1-left" bit
680 if (RAM_CLOSURE(stack
))
681 // closures have one object field, but it's in the cdr
683 IF_GC_TRACE(printf ("case 13.5\n")); // TODO renumber cases
685 temp
= ram_get_cdr (stack
); /* pop through cdr */
686 ram_set_cdr (stack
, visit
);
693 IF_GC_TRACE(printf ("case 14\n"));
695 temp
= ram_get_car (stack
); /* pop through car */
696 ram_set_car (stack
, visit
);
717 obj visit
= MAX_RAM_ENCODING
;
721 while (visit
>= (MIN_RAM_ENCODING
+ ((glovars
+ 1) / 2)))
722 // we don't want to sweep the global variables area
724 if ((RAM_COMPOSITE(visit
)
725 && (ram_get_gc_tags (visit
) == GC_TAG_UNMARKED
)) // 2 mark bit
726 || !(ram_get_gc_tags (visit
) & GC_TAG_0_LEFT
)) // 1 mark bit
729 if (RAM_VECTOR(visit
))
730 // when we sweep a vector, we also have to sweep its contents
732 obj o
= ram_get_cdr (visit
);
733 uint16 i
= ram_get_car (visit
); // number of elements
734 ram_set_car (o
, free_list_vec
);
735 ram_set_cdr (o
, (i
+ 3) / 4); // free length, in words
737 // 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
739 ram_set_car (visit
, free_list
);
744 if (RAM_COMPOSITE(visit
))
745 ram_set_gc_tags (visit
, GC_TAG_UNMARKED
);
746 else // only 1 mark bit to unset
747 ram_set_gc_tag0 (visit
, GC_TAG_UNMARKED
);
759 printf ("**************** memory needed = %d\n", max_live
+1);
769 IF_TRACE(printf("\nGC BEGINS\n"));
771 IF_GC_TRACE(printf("arg1\n"));
773 IF_GC_TRACE(printf("arg2\n"));
775 IF_GC_TRACE(printf("arg3\n"));
777 IF_GC_TRACE(printf("arg4\n"));
779 IF_GC_TRACE(printf("cont\n"));
781 IF_GC_TRACE(printf("env\n"));
782 mark (env
); // TODO do we mark the free list or do we rebuild it every time ? what about vectors ?
784 for (i
=0; i
<glovars
; i
++)
785 mark (get_global (i
));
790 obj
alloc_ram_cell (void)
804 ERROR("memory is full");
809 free_list
= ram_get_car (o
);
814 obj
alloc_ram_cell_init (uint8 f0
, uint8 f1
, uint8 f2
, uint8 f3
)
816 obj o
= alloc_ram_cell ();
818 ram_set_field0 (o
, f0
);
819 ram_set_field1 (o
, f1
);
820 ram_set_field2 (o
, f2
);
821 ram_set_field3 (o
, f3
);
826 obj
alloc_vec_cell (uint16 n
) // TODO add a init version ?
828 obj o
= free_list_vec
;
837 while ((ram_get_cdr (o
) * 4) < n
) // free space too small
838 { // 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
839 if (o
== 0) // no free space, or none big enough
841 if (gc_done
) // we gc'd, but no space is big enough for the vector
842 ERROR("no room for vector");
850 } // TODO fuse adjacent free spaces, and maybe compact ? FOOBAR
855 // case 1 : the new vector fills every free word advertized, we remove the
856 // node from the free list
857 // TODO mettre le cdr de o dans une var temporaire ?
858 if (((ram_get_cdr(o
) * 4) - n
) < 4) // TODO is there a better way ?
860 if (prec
) // TODO does this mean that the free list nodes are in the same order as they are in memory ?
861 ram_set_car (prec
, ram_get_car (o
));
863 free_list_vec
= ram_get_car (o
);
865 // case 2 : there is still some space left in the free section, create a new
866 // node to represent this space
869 obj new_free
= o
+ (n
+ 3)/4;
871 ram_set_car (prec
, new_free
);
873 free_list_vec
= new_free
;
874 ram_set_car (new_free
, ram_get_car (o
));
875 ram_set_cdr (new_free
, ram_get_cdr (o
) - (n
+ 3)/4); // TODO documenter structure de cette free list quelque part
881 /*---------------------------------------------------------------------------*/
883 int32
decode_int (obj o
)
889 if (o
< MIN_FIXNUM_ENCODING
)
890 TYPE_ERROR("decode_int", "integer");
892 if (o
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
893 return DECODE_FIXNUM(o
);
898 TYPE_ERROR("decode_int", "integer");
900 u
= ram_get_field1 (o
);
901 h
= ram_get_field2 (o
);
902 l
= ram_get_field3 (o
);
907 TYPE_ERROR("decode_int", "integer");
909 u
= rom_get_field1 (o
);
910 h
= rom_get_field2 (o
);
911 l
= rom_get_field3 (o
);
914 TYPE_ERROR("decode_int", "integer");
917 return ((int32
)((((int16
)u
- 256) << 8) + h
) << 8) + l
;
919 return ((int32
)(((int16
)u
<< 8) + h
) << 8) + l
;
922 obj
encode_int (int32 n
)
924 if (n
>= MIN_FIXNUM
&& n
<= MAX_FIXNUM
)
925 return ENCODE_FIXNUM(n
);
927 return alloc_ram_cell_init (BIGNUM_FIELD0
, n
>> 16, n
>> 8, n
);
930 /*---------------------------------------------------------------------------*/
942 else if (o
== OBJ_TRUE
)
944 else if (o
== OBJ_NULL
)
946 else if (o
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
947 printf ("%d", DECODE_FIXNUM(o
));
948 else // TODO past here, everything is either in ram or in rom, until we add a 3rd space for vectors, that is
957 if ((in_ram
&& RAM_BIGNUM(o
)) || (!in_ram
&& ROM_BIGNUM(o
)))
958 printf ("%d", decode_int (o
));
959 else if ((in_ram
&& RAM_COMPOSITE(o
)) || (!in_ram
&& ROM_COMPOSITE(o
)))
964 if ((in_ram
&& RAM_PAIR(o
)) || (!in_ram
&& ROM_PAIR(o
))) // TODO not exactly efficient, fix it
968 car
= ram_get_car (o
);
969 cdr
= ram_get_cdr (o
);
973 car
= rom_get_car (o
);
974 cdr
= rom_get_cdr (o
);
985 else if ((IN_RAM(cdr
) && RAM_PAIR(cdr
))
986 || (IN_ROM(cdr
) && ROM_PAIR(cdr
)))
990 car
= ram_get_car (cdr
);
991 cdr
= ram_get_cdr (cdr
);
995 car
= rom_get_car (cdr
);
996 cdr
= rom_get_cdr (cdr
);
1009 else if ((in_ram
&& RAM_SYMBOL(o
)) || (!in_ram
&& ROM_SYMBOL(o
)))
1010 printf ("#<symbol>");
1011 else if ((in_ram
&& RAM_STRING(o
)) || (!in_ram
&& ROM_STRING(o
)))
1012 printf ("#<string>");
1013 else if ((in_ram
&& RAM_VECTOR(o
)) || (!in_ram
&& ROM_VECTOR(o
)))
1014 printf ("#<vector %d>", o
); // TODO do better DEBUG BREGG
1018 car
= ram_get_car (o
);
1019 cdr
= ram_get_cdr (o
);
1020 goto loop
; // TODO ugly hack, takes advantage of the fact that pairs and continuations have the same layout
1028 if (IN_RAM(o
)) // TODO can closures be in rom ? I don't think so
1029 env
= ram_get_cdr (o
);
1031 env
= rom_get_cdr (o
);
1034 pc
= ram_get_entry (o
);
1036 pc
= rom_get_entry (o
);
1038 printf ("{0x%04x ", pc
);
1047 void show_state (rom_addr pc
)
1050 printf ("pc=0x%04x bytecode=0x%02x env=", pc
, rom_get (pc
));
1067 /*---------------------------------------------------------------------------*/
1069 /* Integer operations */
1071 #define encode_bool(x) ((obj)(x))
1073 void prim_numberp (void)
1075 if (arg1
>= MIN_FIXNUM_ENCODING
1076 && arg1
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
1081 arg1
= encode_bool (RAM_BIGNUM(arg1
));
1082 else if (IN_ROM(arg1
))
1083 arg1
= encode_bool (ROM_BIGNUM(arg1
));
1089 void decode_2_int_args (void)
1091 a1
= decode_int (arg1
);
1092 a2
= decode_int (arg2
);
1095 void prim_add (void)
1097 decode_2_int_args ();
1098 arg1
= encode_int (a1
+ a2
);
1102 void prim_sub (void)
1104 decode_2_int_args ();
1105 arg1
= encode_int (a1
- a2
);
1109 void prim_mul (void)
1111 decode_2_int_args ();
1112 arg1
= encode_int (a1
* a2
);
1116 void prim_div (void)
1118 decode_2_int_args ();
1120 ERROR("divide by 0");
1121 arg1
= encode_int (a1
/ a2
);
1125 void prim_rem (void)
1127 decode_2_int_args ();
1129 ERROR("divide by 0");
1130 arg1
= encode_int (a1
% a2
);
1134 void prim_neg (void)
1136 a1
= decode_int (arg1
);
1137 arg1
= encode_int (- a1
);
1142 decode_2_int_args ();
1143 arg1
= encode_bool (a1
== a2
);
1149 decode_2_int_args ();
1150 arg1
= encode_bool (a1
< a2
);
1156 decode_2_int_args ();
1157 arg1
= encode_bool (a1
> a2
);
1161 void prim_ior (void)
1163 a1
= decode_int (arg1
); // TODO use decode_2_int_args ? can't see why not
1164 a2
= decode_int (arg2
);
1165 arg1
= encode_int (a1
| a2
);
1169 void prim_xor (void)
1171 a1
= decode_int (arg1
);
1172 a2
= decode_int (arg2
);
1173 arg1
= encode_int (a1
^ a2
);
1178 /*---------------------------------------------------------------------------*/
1180 /* List operations */
1182 void prim_pairp (void)
1185 arg1
= encode_bool (RAM_PAIR(arg1
));
1186 else if (IN_ROM(arg1
))
1187 arg1
= encode_bool (ROM_PAIR(arg1
));
1192 obj
cons (obj car
, obj cdr
)
1194 return alloc_ram_cell_init (COMPOSITE_FIELD0
| (car
>> 8), // TODO was ((car & 0x1f00) >> 8), probably redundant
1196 PAIR_FIELD2
| (cdr
>> 8), // TODO was ((cdr & 0x1f00) >> 8), probably redundant
1200 void prim_cons (void)
1202 arg1
= cons (arg1
, arg2
);
1206 void prim_car (void)
1210 if (!RAM_PAIR(arg1
))
1211 TYPE_ERROR("car", "pair");
1212 arg1
= ram_get_car (arg1
);
1214 else if (IN_ROM(arg1
))
1216 if (!ROM_PAIR(arg1
))
1217 TYPE_ERROR("car", "pair");
1218 arg1
= rom_get_car (arg1
);
1222 TYPE_ERROR("car", "pair");
1226 void prim_cdr (void)
1230 if (!RAM_PAIR(arg1
))
1231 TYPE_ERROR("cdr", "pair");
1232 arg1
= ram_get_cdr (arg1
);
1234 else if (IN_ROM(arg1
))
1236 if (!ROM_PAIR(arg1
))
1237 TYPE_ERROR("cdr", "pair");
1238 arg1
= rom_get_cdr (arg1
);
1242 TYPE_ERROR("cdr", "pair");
1246 void prim_set_car (void)
1250 if (!RAM_PAIR(arg1
))
1251 TYPE_ERROR("set-car!", "pair");
1253 ram_set_car (arg1
, arg2
);
1259 TYPE_ERROR("set-car!", "pair");
1263 void prim_set_cdr (void)
1267 if (!RAM_PAIR(arg1
))
1268 TYPE_ERROR("set-cdr!", "pair");
1270 ram_set_cdr (arg1
, arg2
);
1276 TYPE_ERROR("set-cdr!", "pair");
1280 void prim_nullp (void)
1282 arg1
= encode_bool (arg1
== OBJ_NULL
);
1285 /*---------------------------------------------------------------------------*/
1287 /* Vector operations */
1289 void prim_u8vectorp (void)
1292 arg1
= encode_bool (RAM_VECTOR(arg1
));
1293 else if (IN_ROM(arg1
))
1294 arg1
= encode_bool (ROM_VECTOR(arg1
));
1299 void prim_make_u8vector (void)
1301 decode_2_int_args (); // arg1 is length, arg2 is contents
1304 ERROR("byte vectors can only contain bytes");
1306 arg3
= alloc_vec_cell (a1
);
1307 arg1
= alloc_ram_cell_init (COMPOSITE_FIELD0
| (a1
>> 8),
1309 VECTOR_FIELD2
| (arg3
>> 8),
1312 a1
= (a1
+ 3) / 4; // actual length, in words
1315 ram_set_field0 (arg3
, a2
);
1316 ram_set_field1 (arg3
, a2
);
1317 ram_set_field2 (arg3
, a2
);
1318 ram_set_field3 (arg3
, a2
);
1323 void prim_u8vector_ref (void)
1324 { // TODO how do we deal with rom vectors ? as lists ? they're never all that long
1325 a2
= decode_int (arg2
);
1329 if (!RAM_VECTOR(arg1
))
1330 TYPE_ERROR("u8vector-ref", "vector");
1331 if ((ram_get_car (arg1
) <= a2
) || (a2
< 0))
1332 ERROR("vector index invalid");
1333 arg1
= ram_get_cdr (arg1
);
1335 else if (IN_ROM(arg1
))
1337 if (!ROM_VECTOR(arg1
))
1338 TYPE_ERROR("u8vector-ref", "vector");
1339 if ((rom_get_car (arg1
) <= a2
) || (a2
< 0))
1340 ERROR("vector index invalid");
1341 arg1
= rom_get_cdr (arg1
);
1344 TYPE_ERROR("u8vector-ref", "vector");
1354 arg1
= ram_get_field0 (arg1
); break;
1356 arg1
= ram_get_field1 (arg1
); break;
1358 arg1
= ram_get_field2 (arg1
); break;
1360 arg1
= ram_get_field3 (arg1
); break;
1363 arg1
= encode_int (arg1
);
1365 else // rom vector, stored as a list
1366 { // 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)
1368 arg1
= rom_get_cdr (arg1
);
1370 // the contents are already encoded as fixnums
1371 arg1
= rom_get_car (arg1
);
1379 void prim_u8vector_set (void)
1380 { // TODO a lot in common with ref, abstract that
1381 a2
= decode_int (arg2
);
1382 a3
= decode_int (arg3
);
1385 ERROR("byte vectors can only contain bytes");
1389 if (!RAM_VECTOR(arg1
))
1390 TYPE_ERROR("u8vector-set!", "vector");
1391 if ((ram_get_car (arg1
) <= a2
) || (a2
< 0))
1392 ERROR("vector index invalid");
1393 arg1
= ram_get_cdr (arg1
);
1396 TYPE_ERROR("u8vector-set!", "vector");
1404 ram_set_field0 (arg1
, a3
); break;
1406 ram_set_field1 (arg1
, a3
); break;
1408 ram_set_field2 (arg1
, a3
); break;
1410 ram_set_field3 (arg1
, a3
); break;
1418 void prim_u8vector_length (void)
1422 if (!RAM_VECTOR(arg1
))
1423 TYPE_ERROR("u8vector-length", "vector");
1424 arg1
= encode_int (ram_get_car (arg1
));
1426 else if (IN_ROM(arg1
))
1428 if (!ROM_VECTOR(arg1
))
1429 TYPE_ERROR("u8vector-length", "vector");
1430 arg1
= encode_int (rom_get_car (arg1
));
1433 TYPE_ERROR("u8vector-length", "vector");
1436 void prim_u8vector_copy (void)
1438 // arg1 is source, arg2 is source-start, arg3 is target, arg4 is target-start
1439 // arg5 is number of bytes to copy
1441 a1
= decode_int (arg2
);
1442 a2
= decode_int (arg4
);
1443 a3
= decode_int (arg5
);
1445 // case 1 : ram to ram
1446 if (IN_RAM(arg1
) && IN_RAM(arg3
))
1448 if (!RAM_VECTOR(arg1
) || !RAM_VECTOR(arg3
))
1449 TYPE_ERROR("u8vector-copy!", "vector");
1450 if ((ram_get_car (arg1
) < (a1
+ a3
)) || (a1
< 0) ||
1451 (ram_get_car (arg3
) < (a2
+ a3
)) || (a2
< 0))
1452 ERROR("vector index invalid");
1454 // position to the start
1455 arg1
= ram_get_cdr (arg1
);
1458 arg3
= ram_get_cdr (arg3
);
1467 case 0: arg2
= ram_get_field0 (arg1
); break;
1468 case 1: arg2
= ram_get_field1 (arg1
); break;
1469 case 2: arg2
= ram_get_field2 (arg1
); break;
1470 case 3: arg2
= ram_get_field3 (arg1
); break;
1475 case 0: ram_set_field0 (arg3
, arg2
); break;
1476 case 1: ram_set_field1 (arg3
, arg2
); break;
1477 case 2: ram_set_field2 (arg3
, arg2
); break;
1478 case 3: ram_set_field3 (arg3
, arg2
); break;
1483 a1
%= 4; // TODO any way to merge with the previous similar block ?
1489 // case 2 : rom to ram
1490 else if (IN_ROM(arg1
) && IN_RAM(arg3
))
1492 if (!ROM_VECTOR(arg1
) || !RAM_VECTOR(arg3
))
1493 TYPE_ERROR("u8vector-copy!", "vector");
1494 if ((rom_get_car (arg1
) < (a1
+ a3
)) || (a1
< 0) ||
1495 (ram_get_car (arg3
) < (a2
+ a3
)) || (a2
< 0))
1496 ERROR("vector index invalid");
1498 arg1
= rom_get_cdr (arg1
);
1500 arg1
= rom_get_cdr (arg1
);
1502 arg3
= ram_get_cdr (arg3
);
1508 arg2
= decode_int (rom_get_car (arg1
));
1512 case 0: ram_set_field0 (arg3
, arg2
); break;
1513 case 1: ram_set_field1 (arg3
, arg2
); break;
1514 case 2: ram_set_field2 (arg3
, arg2
); break;
1515 case 3: ram_set_field3 (arg3
, arg2
); break;
1518 arg1
= rom_get_cdr (arg1
);
1521 a2
%= 4; // TODO very similar to the other case
1525 TYPE_ERROR("u8vector-copy!", "vector");
1534 /*---------------------------------------------------------------------------*/
1536 /* Miscellaneous operations */
1538 void prim_eqp (void)
1540 arg1
= encode_bool (arg1
== arg2
);
1544 void prim_not (void)
1546 arg1
= encode_bool (arg1
== OBJ_FALSE
);
1549 void prim_symbolp (void)
1552 arg1
= encode_bool (RAM_SYMBOL(arg1
));
1553 else if (IN_ROM(arg1
))
1554 arg1
= encode_bool (ROM_SYMBOL(arg1
));
1559 void prim_stringp (void)
1562 arg1
= encode_bool (RAM_STRING(arg1
));
1563 else if (IN_ROM(arg1
))
1564 arg1
= encode_bool (ROM_STRING(arg1
));
1569 void prim_string2list (void)
1573 if (!RAM_STRING(arg1
))
1574 TYPE_ERROR("string->list", "string");
1576 arg1
= ram_get_car (arg1
);
1578 else if (IN_ROM(arg1
))
1580 if (!ROM_STRING(arg1
))
1581 TYPE_ERROR("string->list", "string");
1583 arg1
= rom_get_car (arg1
);
1586 TYPE_ERROR("string->list", "string");
1589 void prim_list2string (void)
1591 arg1
= alloc_ram_cell_init (COMPOSITE_FIELD0
| ((arg1
& 0x1f00) >> 8),
1597 void prim_booleanp (void)
1599 arg1
= encode_bool (arg1
< 2);
1603 /*---------------------------------------------------------------------------*/
1605 /* Robot specific operations */
1608 void prim_print (void)
1623 int32
read_clock (void)
1629 now
= from_now( 0 );
1637 static int32 start
= 0;
1642 now
= tb
.time
* 1000 + tb
.millitm
;
1649 static int32 start
= 0;
1652 if (gettimeofday (&tv
, NULL
) == 0)
1654 now
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
1668 void prim_clock (void)
1670 arg1
= encode_int (read_clock ());
1674 void prim_motor (void)
1676 decode_2_int_args ();
1678 if (a1
< 1 || a1
> 2 || a2
< -100 || a2
> 100)
1679 ERROR("argument out of range to procedure \"motor\"");
1689 printf ("motor %d -> power=%d\n", a1
, a2
);
1699 void prim_led (void)
1701 decode_2_int_args ();
1702 a3
= decode_int (arg3
);
1704 if (a1
< 1 || a1
> 3 || a2
< 0 || a3
< 0)
1705 ERROR("argument out of range to procedure \"led\"");
1709 LED_set( a1
, a2
, a3
);
1715 printf ("led %d -> duty=%d period=%d\n", a1
, a2
, a3
);
1726 void prim_led2_color (void)
1728 a1
= decode_int (arg1
);
1730 if (a1
< 0 || a1
> 1)
1731 ERROR("argument out of range to procedure \"led2-color\"");
1735 LED2_color_set( a1
);
1741 printf ("led2-color -> %s\n", (a1
==0)?"green":"red");
1750 void prim_getchar_wait (void)
1752 decode_2_int_args();
1753 a1
= read_clock () + a1
;
1755 if (a1
< 0 || a2
< 1 || a2
> 3)
1756 ERROR("argument out of range to procedure \"getchar-wait\"");
1763 serial_port_set ports
;
1764 ports
= serial_rx_wait_with_timeout( a2
, a1
);
1766 arg1
= encode_int (serial_rx_read( ports
));
1781 arg1
= encode_int (_getch ());
1784 } while (read_clock () < a1
);
1789 arg1
= encode_int (getchar ());
1797 void prim_putchar (void)
1799 decode_2_int_args ();
1801 if (a1
< 0 || a1
> 255 || a2
< 1 || a2
> 3)
1802 ERROR("argument out of range to procedure \"putchar\"");
1806 serial_tx_write( a2
, a1
);
1822 void prim_beep (void)
1824 decode_2_int_args ();
1826 if (a1
< 1 || a1
> 255 || a2
< 0)
1827 ERROR("argument out of range to procedure \"beep\"");
1831 beep( a1
, from_now( a2
) );
1837 printf ("beep -> freq-div=%d duration=%d\n", a1
, a2
);
1847 void prim_adc (void)
1851 a1
= decode_int (arg1
);
1853 if (a1
< 1 || a1
> 3)
1854 ERROR("argument out of range to procedure \"adc\"");
1864 x
= read_clock () & 255;
1866 if (x
> 127) x
= 256 - x
;
1872 arg1
= encode_int (x
);
1876 void prim_dac (void)
1878 a1
= decode_int (arg1
);
1880 if (a1
< 0 || a1
> 255)
1881 ERROR("argument out of range to procedure \"dac\"");
1891 printf ("dac -> %d\n", a1
);
1900 void prim_sernum (void)
1916 arg1
= encode_int (x
);
1920 /*---------------------------------------------------------------------------*/
1924 int hidden_fgetc (FILE *f
)
1934 #define fgetc(f) hidden_fgetc(f)
1936 void write_hex_nibble (int n
)
1938 putchar ("0123456789ABCDEF"[n
]);
1941 void write_hex (uint8 n
)
1943 write_hex_nibble (n
>> 4);
1944 write_hex_nibble (n
& 0x0f);
1949 if (c
>= '0' && c
<= '9')
1952 if (c
>= 'A' && c
<= 'F')
1953 return (c
- 'A' + 10);
1955 if (c
>= 'a' && c
<= 'f')
1956 return (c
- 'a' + 10);
1961 int read_hex_byte (FILE *f
)
1963 int h1
= hex (fgetc (f
));
1964 int h2
= hex (fgetc (f
));
1966 if (h1
>= 0 && h2
>= 0)
1967 return (h1
<<4) + h2
;
1972 int read_hex_file (char *filename
)
1975 FILE *f
= fopen (filename
, "r");
1985 for (i
=0; i
<ROM_BYTES
; i
++)
1990 while ((c
= fgetc (f
)) != EOF
)
1992 if ((c
== '\r') || (c
== '\n'))
1996 (len
= read_hex_byte (f
)) < 0 ||
1997 (a1
= read_hex_byte (f
)) < 0 ||
1998 (a2
= read_hex_byte (f
)) < 0 ||
1999 (t
= read_hex_byte (f
)) < 0)
2005 sum
= len
+ a1
+ a2
+ t
;
2013 unsigned long adr
= ((unsigned long)hi16
<< 16) + a
- CODE_START
;
2015 if ((b
= read_hex_byte (f
)) < 0)
2018 if (adr
>= 0 && adr
< ROM_BYTES
)
2021 a
= (a
+ 1) & 0xffff;
2038 if ((a1
= read_hex_byte (f
)) < 0 ||
2039 (a2
= read_hex_byte (f
)) < 0)
2044 hi16
= (a1
<<8) + a2
;
2049 if ((b
= read_hex_byte (f
)) < 0)
2056 printf ("*** HEX file checksum error (expected 0x%02x)\n", sum
);
2062 if ((c
!= '\r') && (c
!= '\n'))
2073 printf ("*** HEX file syntax error\n");
2083 /*---------------------------------------------------------------------------*/
2085 #define FETCH_NEXT_BYTECODE() bytecode = rom_get (pc++)
2087 #define BEGIN_DISPATCH() \
2089 IF_TRACE(show_state (pc)); \
2090 FETCH_NEXT_BYTECODE(); \
2091 bytecode_hi4 = bytecode & 0xf0; \
2092 bytecode_lo4 = bytecode & 0x0f; \
2093 switch (bytecode_hi4 >> 4) {
2095 #define END_DISPATCH() }
2097 #define CASE(opcode) case (opcode>>4):;
2099 #define DISPATCH(); goto dispatch;
2104 #define bytecode TABLAT
2105 #define bytecode_hi4 WREG
2108 #define PUSH_CONSTANT1 0x00
2109 #define PUSH_CONSTANT2 0x10
2110 #define PUSH_STACK1 0x20
2111 #define PUSH_STACK2 0x30
2112 #define PUSH_GLOBAL 0x40
2113 #define SET_GLOBAL 0x50
2116 #define LABEL_INSTR 0x80
2117 #define PUSH_CONSTANT_LONG 0x90
2119 // TODO these are free
2121 #define GOTO_IF_FALSE 0xb0
2130 char *prim_name
[64] =
2154 "prim #%graft-to-cont",
2155 "prim #%return-to-cont",
2159 "prim #%string->list",
2160 "prim #%list->string",
2161 "prim #%make-u8vector",
2162 "prim #%u8vector-ref",
2163 "prim #%u8vector-set!",
2168 "prim #%led2-color",
2169 "prim #%getchar-wait",
2173 "prim #%u8vector?", // TODO was dac, but it's not plugged to anything
2175 "prim #%u8vector-length",
2176 "prim #%u8vector-copy!",
2200 #define PUSH_ARG1() push_arg1 ()
2203 void push_arg1 (void)
2205 env
= cons (arg1
, env
);
2211 obj o
= ram_get_car (env
);
2212 env
= ram_get_cdr (env
);
2216 void pop_procedure (void)
2222 if (!RAM_CLOSURE(arg1
))
2223 TYPE_ERROR("pop_procedure", "procedure");
2225 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
2227 else if (IN_ROM(arg1
))
2229 if (!ROM_CLOSURE(arg1
))
2230 TYPE_ERROR("pop_procedure", "procedure");
2232 entry
= rom_get_entry (arg1
) + CODE_START
;
2235 TYPE_ERROR("pop_procedure", "procedure");
2238 void handle_arity_and_rest_param (void)
2242 np
= rom_get (entry
++);
2244 if ((np
& 0x80) == 0)
2247 ERROR("wrong number of arguments");
2254 ERROR("wrong number of arguments");
2262 arg3
= cons (arg4
, arg3
);
2268 arg1
= cons (arg3
, arg1
);
2273 void build_env (void)
2279 arg1
= cons (arg3
, arg1
);
2287 void save_cont (void)
2289 // the second half is a closure
2290 arg3
= alloc_ram_cell_init (CLOSURE_FIELD0
| (pc
>> 11),
2292 ((pc
& 0x0007) << 5) | (env
>> 8),
2294 cont
= alloc_ram_cell_init (COMPOSITE_FIELD0
| (cont
>> 8),
2296 CONTINUATION_FIELD2
| (arg3
>> 8),
2301 void interpreter (void)
2303 pc
= (CODE_START
+ 4) + ((rom_addr
)rom_get (CODE_START
+2) << 2);
2305 glovars
= rom_get (CODE_START
+3); // number of global variables
2311 /***************************************************************************/
2312 CASE(PUSH_CONSTANT1
);
2314 IF_TRACE(printf(" (push-constant "); show (bytecode_lo4
); printf (")\n"));
2316 arg1
= bytecode_lo4
;
2322 /***************************************************************************/
2323 CASE(PUSH_CONSTANT2
);
2325 IF_TRACE(printf(" (push-constant "); show (bytecode_lo4
+16); printf (")\n"));
2326 arg1
= bytecode_lo4
+16;
2332 /***************************************************************************/
2335 IF_TRACE(printf(" (push-stack %d)\n", bytecode_lo4
));
2339 while (bytecode_lo4
!= 0)
2341 arg1
= ram_get_cdr (arg1
);
2345 arg1
= ram_get_car (arg1
);
2351 /***************************************************************************/
2354 IF_TRACE(printf(" (push-stack %d)\n", bytecode_lo4
+16));
2355 // TODO does this ever happens ?
2360 while (bytecode_lo4
!= 0)
2362 arg1
= ram_get_cdr (arg1
);
2366 arg1
= ram_get_car (arg1
);
2372 /***************************************************************************/
2375 IF_TRACE(printf(" (push-global %d)\n", bytecode_lo4
));
2377 arg1
= get_global (bytecode_lo4
);
2383 /***************************************************************************/
2386 IF_TRACE(printf(" (set-global %d)\n", bytecode_lo4
));
2388 set_global (bytecode_lo4
, POP());
2392 /***************************************************************************/
2395 IF_TRACE(printf(" (call %d)\n", bytecode_lo4
));
2400 handle_arity_and_rest_param ();
2411 /***************************************************************************/
2414 IF_TRACE(printf(" (jump %d)\n", bytecode_lo4
));
2419 handle_arity_and_rest_param ();
2429 /***************************************************************************/
2432 switch (bytecode_lo4
)
2434 case 0: // call-toplevel TODO put these in separate functions ?
2435 FETCH_NEXT_BYTECODE();
2438 FETCH_NEXT_BYTECODE();
2440 IF_TRACE(printf(" (call-toplevel 0x%04x)\n",
2441 ((arg2
<< 8) | bytecode
) + CODE_START
));
2443 entry
= (arg2
<< 8) + bytecode
+ CODE_START
;
2446 na
= rom_get (entry
++);
2459 case 1: // jump-toplevel
2460 FETCH_NEXT_BYTECODE();
2463 FETCH_NEXT_BYTECODE();
2465 IF_TRACE(printf(" (jump-toplevel 0x%04x)\n",
2466 ((arg2
<< 8) | bytecode
) + CODE_START
));
2468 entry
= (arg2
<< 8) + bytecode
+ CODE_START
; // TODO this is a common pattern
2471 na
= rom_get (entry
++);
2484 FETCH_NEXT_BYTECODE();
2487 FETCH_NEXT_BYTECODE();
2489 IF_TRACE(printf(" (goto 0x%04x)\n",
2490 (arg2
<< 8) + bytecode
+ CODE_START
));
2492 pc
= (arg2
<< 8) + bytecode
+ CODE_START
;
2496 case 3: // goto-if-false
2497 FETCH_NEXT_BYTECODE();
2500 FETCH_NEXT_BYTECODE();
2502 IF_TRACE(printf(" (goto-if-false 0x%04x)\n",
2503 (arg2
<< 8) + bytecode
+ CODE_START
));
2505 if (POP() == OBJ_FALSE
)
2506 pc
= (arg2
<< 8) + bytecode
+ CODE_START
;
2511 FETCH_NEXT_BYTECODE();
2514 FETCH_NEXT_BYTECODE();
2516 IF_TRACE(printf(" (closure 0x%04x)\n", (arg2
<< 8) | bytecode
));
2518 arg3
= POP(); // env
2520 entry
= (arg2
<< 8) | bytecode
;
2522 arg1
= alloc_ram_cell_init (CLOSURE_FIELD0
| (arg2
>> 3),
2523 ((arg2
& 0x07) << 5) | (bytecode
>> 3),
2524 ((bytecode
&0x07) <<5) |((arg3
&0x1f00) >>8),
2534 case 5: // call-toplevel-short
2535 FETCH_NEXT_BYTECODE(); // TODO the sort version have a lot in common with the long ones, abstract ?
2536 // TODO short instructions don't work at the moment
2537 IF_TRACE(printf(" (call-toplevel-short 0x%04x)\n",
2538 pc
+ bytecode
+ CODE_START
));
2540 entry
= pc
+ bytecode
+ CODE_START
;
2543 na
= rom_get (entry
++);
2555 case 6: // jump-toplevel-short
2556 FETCH_NEXT_BYTECODE();
2558 IF_TRACE(printf(" (jump-toplevel-short 0x%04x)\n",
2559 pc
+ bytecode
+ CODE_START
));
2561 entry
= pc
+ bytecode
+ CODE_START
;
2564 na
= rom_get (entry
++);
2575 case 7: // goto-short
2576 FETCH_NEXT_BYTECODE();
2578 IF_TRACE(printf(" (goto-short 0x%04x)\n", pc
+ bytecode
+ CODE_START
));
2580 pc
= pc
+ bytecode
+ CODE_START
;
2584 case 8: // goto-if-false-short
2585 FETCH_NEXT_BYTECODE();
2587 IF_TRACE(printf(" (goto-if-false-short 0x%04x)\n",
2588 pc
+ bytecode
+ CODE_START
));
2590 if (POP() == OBJ_FALSE
)
2591 pc
= pc
+ bytecode
+ CODE_START
;
2595 case 9: // closure-short TODO I doubt these short instrs will have great effect, and this is the one I doubt the most about
2596 FETCH_NEXT_BYTECODE();
2598 IF_TRACE(printf(" (closure-short 0x%04x)\n", pc
+ bytecode
));
2600 arg3
= POP(); // env
2602 entry
= pc
+ bytecode
; // TODO makes sense for a closure ?
2604 arg1
= alloc_ram_cell_init (CLOSURE_FIELD0
| (arg2
>> 3),
2605 ((arg2
& 0x07) << 5) | (bytecode
>> 3),
2606 ((bytecode
&0x07) <<5) |((arg3
&0x1f00) >>8),
2625 case 14: // push_global [long]
2626 FETCH_NEXT_BYTECODE();
2628 IF_TRACE(printf(" (push-global [long] %d)\n", bytecode
));
2630 arg1
= get_global (bytecode
);
2636 case 15: // set_global [long]
2637 FETCH_NEXT_BYTECODE();
2639 IF_TRACE(printf(" (set-global [long] %d)\n", bytecode
));
2641 set_global (bytecode
, POP());
2648 /***************************************************************************/
2649 CASE(PUSH_CONSTANT_LONG
);
2651 /* push-constant [long] */
2653 FETCH_NEXT_BYTECODE();
2655 IF_TRACE(printf(" (push [long] 0x%04x)\n", (bytecode_lo4
<< 8) + bytecode
));
2657 arg1
= (bytecode_lo4
<< 8) | bytecode
;
2662 /***************************************************************************/
2663 CASE(GOTO
); // BREGG move
2667 /***************************************************************************/
2668 CASE(GOTO_IF_FALSE
); // BREGG move
2672 /***************************************************************************/
2675 IF_TRACE(printf(" (%s)\n", prim_name
[bytecode_lo4
]));
2677 switch (bytecode_lo4
)
2680 arg1
= POP(); prim_numberp (); PUSH_ARG1(); break;
2682 arg2
= POP(); arg1
= POP(); prim_add (); PUSH_ARG1(); break;
2684 arg2
= POP(); arg1
= POP(); prim_sub (); PUSH_ARG1(); break;
2686 arg2
= POP(); arg1
= POP(); prim_mul (); PUSH_ARG1(); break;
2688 arg2
= POP(); arg1
= POP(); prim_div (); PUSH_ARG1(); break;
2690 arg2
= POP(); arg1
= POP(); prim_rem (); PUSH_ARG1(); break;
2692 arg1
= POP(); prim_neg (); PUSH_ARG1(); break;
2694 arg2
= POP(); arg1
= POP(); prim_eq (); PUSH_ARG1(); break;
2696 arg2
= POP(); arg1
= POP(); prim_lt (); PUSH_ARG1(); break;
2698 arg2
= POP(); arg1
= POP(); prim_ior (); PUSH_ARG1(); break;
2700 arg2
= POP(); arg1
= POP(); prim_gt (); PUSH_ARG1(); break;
2702 arg2
= POP(); arg1
= POP(); prim_xor (); PUSH_ARG1(); break;
2704 arg1
= POP(); prim_pairp (); PUSH_ARG1(); break;
2706 arg2
= POP(); arg1
= POP(); prim_cons (); PUSH_ARG1(); break;
2708 arg1
= POP(); prim_car (); PUSH_ARG1(); break;
2710 arg1
= POP(); prim_cdr (); PUSH_ARG1(); break;
2715 /***************************************************************************/
2718 IF_TRACE(printf(" (%s)\n", prim_name
[bytecode_lo4
+16]));
2720 switch (bytecode_lo4
)
2723 arg2
= POP(); arg1
= POP(); prim_set_car (); break;
2725 arg2
= POP(); arg1
= POP(); prim_set_cdr (); break;
2727 arg1
= POP(); prim_nullp (); PUSH_ARG1(); break;
2729 arg2
= POP(); arg1
= POP(); prim_eqp (); PUSH_ARG1(); break;
2731 arg1
= POP(); prim_not (); PUSH_ARG1(); break;
2733 /* prim #%get-cont */
2738 /* prim #%graft-to-cont */
2740 arg1
= POP(); /* thunk to call */
2741 cont
= POP(); /* continuation */
2748 handle_arity_and_rest_param ();
2758 /* prim #%return-to-cont */
2760 arg1
= POP(); /* value to return */
2761 cont
= POP(); /* continuation */
2763 arg2
= ram_get_cdr (cont
);
2765 pc
= ram_get_entry (arg2
);
2767 env
= ram_get_cdr (arg2
);
2768 cont
= ram_get_car (cont
);
2778 /* prim #%symbol? */
2779 arg1
= POP(); prim_symbolp (); PUSH_ARG1(); break;
2781 /* prim #%string? */
2782 arg1
= POP(); prim_stringp (); PUSH_ARG1(); break;
2784 /* prim #%string->list */
2785 arg1
= POP(); prim_string2list (); PUSH_ARG1(); break;
2787 /* prim #%list->string */
2788 arg1
= POP(); prim_list2string (); PUSH_ARG1(); break;
2790 /* prim #%make-u8vector */
2791 arg2
= POP(); arg1
= POP(); prim_make_u8vector (); PUSH_ARG1(); break;
2793 /* prim #%u8vector-ref */
2794 arg2
= POP(); arg1
= POP(); prim_u8vector_ref (); PUSH_ARG1(); break;
2796 /* prim #%u8vector-set! */
2797 arg3
= POP(); arg2
= POP(); arg1
= POP(); prim_u8vector_set (); break;
2802 /***************************************************************************/
2805 IF_TRACE(printf(" (%s)\n", prim_name
[bytecode_lo4
+32]));
2807 switch (bytecode_lo4
)
2816 prim_clock (); PUSH_ARG1(); break;
2819 arg2
= POP(); arg1
= POP(); prim_motor (); break;
2822 arg3
= POP(); arg2
= POP(); arg1
= POP(); prim_led (); ;break;
2824 /* prim #%led2-color */
2825 arg1
= POP(); prim_led2_color (); break;
2827 /* prim #%getchar-wait */
2828 arg2
= POP(); arg1
= POP(); prim_getchar_wait (); PUSH_ARG1(); break;
2830 /* prim #%putchar */
2831 arg2
= POP(); arg1
= POP(); prim_putchar (); break;
2834 arg2
= POP(); arg1
= POP(); prim_beep (); break;
2837 arg1
= POP(); prim_adc (); PUSH_ARG1(); break;
2839 /* prim #%u8vector? */
2840 arg1
= POP(); prim_u8vectorp (); PUSH_ARG1(); break;
2843 prim_sernum (); PUSH_ARG1(); break;
2845 /* prim #%u8vector-length */
2846 arg1
= POP(); prim_u8vector_length (); PUSH_ARG1(); break;
2848 /* prim #%u8vector-copy! */
2849 arg5
= POP(); arg4
= POP(); arg3
= POP(); arg2
= POP(); arg1
= POP();
2850 prim_u8vector_copy (); break;
2865 arg2
= ram_get_cdr (cont
);
2866 pc
= ram_get_entry (arg2
);
2867 env
= ram_get_cdr (arg2
);
2868 cont
= ram_get_car (cont
);
2876 /***************************************************************************/
2880 IF_TRACE(printf(" (%s)\n", prim_name
[bytecode_lo4
]));
2882 switch (bytecode_lo4
)
2885 /* prim #%boolean? */
2886 arg1
= POP(); prim_booleanp (); PUSH_ARG1(); break;
2922 /***************************************************************************/
2927 /*---------------------------------------------------------------------------*/
2933 printf ("usage: sim file.hex\n");
2937 int main (int argc
, char *argv
[])
2940 rom_addr rom_start_addr
= 0;
2942 if (argc
> 1 && argv
[1][0] == '-' && argv
[1][1] == 's')
2949 if ((h1
= hex (argv
[1][2])) < 0 ||
2950 (h2
= hex (argv
[1][3])) < 0 ||
2951 (h3
= hex (argv
[1][4])) != 0 ||
2952 (h4
= hex (argv
[1][5])) != 0 ||
2956 rom_start_addr
= (h1
<< 12) | (h2
<< 8) | (h3
<< 4) | h4
;
2963 printf ("Start address = 0x%04x\n", rom_start_addr
); // TODO says 0, but should be CODE_START ?
2969 if (!read_hex_file (argv
[1]))
2970 printf ("*** Could not read hex file \"%s\"\n", argv
[1]);
2975 if (rom_get (CODE_START
+0) != 0xfb ||
2976 rom_get (CODE_START
+1) != 0xd7)
2977 printf ("*** The hex file was not compiled with PICOBIT\n");
2981 for (i
=0; i
<8192; i
++) // TODO remove this ? and not the night address space, now 16 bits
2982 if (rom_get (i
) != 0xff)
2983 printf ("rom_mem[0x%04x] = 0x%02x\n", i
, rom_get (i
));
2989 printf ("**************** memory needed = %d\n", max_live
+1);
2999 /*---------------------------------------------------------------------------*/