Added Etienne's error messages to the vm, which give the name of the
[picobit/chj.git] / picobit-vm.c
blobfe3241a390c5901504d11d2565b243e4ac14ba34
1 /* file: "picobit-vm.c" */
3 /*
4 * Copyright 2004 by Marc Feeley, All Rights Reserved.
6 * History:
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
13 #define DEBUG_not
14 #define DEBUG_GC_not
16 /*---------------------------------------------------------------------------*/
18 typedef char int8;
19 typedef short int16;
20 typedef long int32;
21 typedef unsigned char uint8;
22 typedef unsigned short uint16;
23 typedef unsigned long uint32;
25 /*---------------------------------------------------------------------------*/
28 #ifdef PICOBOARD2
29 #define ROBOT
30 #endif
32 #ifdef HI_TECH_C
33 #define ROBOT
34 #endif
36 #ifndef ROBOT
37 #define WORKSTATION
38 #endif
41 #ifdef HI_TECH_C
43 #include <pic18.h>
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;
56 #endif
59 #ifdef WORKSTATION
61 #include <stdio.h>
62 #include <stdlib.h>
64 #ifdef _WIN32
65 #include <sys/types.h>
66 #include <sys/timeb.h>
67 #include <conio.h>
68 #else
69 #include <sys/time.h>
70 #endif
72 #endif
75 /*---------------------------------------------------------------------------*/
77 #define WORD_BITS 8
79 #define CODE_START 0x5000
81 #ifdef DEBUG
82 #define IF_TRACE(x) x
83 #define IF_GC_TRACE(x) x
84 #else
85 #define IF_TRACE(x)
86 #define IF_GC_TRACE(x)
87 #endif
89 /*---------------------------------------------------------------------------*/
92 #ifdef PICOBOARD2
94 #define ERROR(msg) halt_with_error()
95 #define TYPE_ERROR(prim, type) halt_with_error()
97 #endif
100 #ifdef WORKSTATION
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);
108 exit (1);
111 void type_error (char *prim, char *type)
113 printf ("ERROR: %s: An argument of type %s was expected\n", prim, type);
114 exit (1);
117 #endif
120 /*---------------------------------------------------------------------------*/
122 #if WORD_BITS <= 8
123 typedef uint8 word;
124 #else
125 typedef uint16 word;
126 #endif
128 typedef uint16 ram_addr;
129 typedef uint16 rom_addr;
131 typedef uint16 obj;
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
148 #if WORD_BITS == 8
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)))
153 #endif
155 #ifdef PICOBOARD2
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 ?
160 #endif
163 #ifdef WORKSTATION
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)
170 #endif
173 /*---------------------------------------------------------------------------*/
175 #ifdef PICOBOARD2
177 /* #if WORD_BITS == 8 */
178 /* #endif */ // TODO useless
180 uint8 rom_get (rom_addr a)
182 return *(rom uint8*)a;
185 #endif
188 #ifdef WORKSTATION
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] =
195 #define RED_GREEN
196 #define PUTCHAR_LIGHT_not
198 #ifdef RED_GREEN
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
210 , 0x51, 0x00, 0xFF
211 #endif
212 #ifdef PUTCHAR_LIGHT
213 0xFB, 0xD7, 0x00, 0x00, 0x80, 0x08, 0xFE, 0xE8
214 , 0x00, 0xF6, 0xF5, 0x90, 0x08
215 #endif
218 uint8 rom_get (rom_addr a)
220 return rom_mem[a-CODE_START];
223 #endif
225 /*---------------------------------------------------------------------------*/
228 OBJECT ENCODING:
230 #f 0
231 #t 1
232 () 2
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
246 a is car
247 d is cdr
248 gives an address space of 2^13 * 4 = 32k divided between simple objects,
249 rom, ram and vectors
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
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
283 the procedure:
285 n = 0 to 127 -> procedure has n parameters (no rest parameter)
286 n = -128 to -1 -> procedure has -n parameters, the last is
287 a rest parameter
290 #define OBJ_FALSE 0
291 #define OBJ_TRUE 1
292 #define OBJ_NULL 2
294 #define MIN_FIXNUM_ENCODING 3
295 #define MIN_FIXNUM 0
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 ?
303 #if WORD_BITS == 8
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))
307 #endif
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))
368 #if WORD_BITS == 8
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 ?
387 #endif
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
451 if (i & 1)
452 return ram_get_cdr (MIN_RAM_ENCODING + (i / 2));
453 else
454 return ram_get_car (MIN_RAM_ENCODING + (i / 2));
457 void set_global (uint8 i, obj o)
459 if (i & 1)
460 ram_set_cdr (MIN_RAM_ENCODING + (i / 2), o);
461 else
462 ram_set_car (MIN_RAM_ENCODING + (i / 2), o);
465 #ifdef WORKSTATION
466 void show_type (obj o) // for debugging purposes
468 printf("%x : ", o);
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");
473 else if (IN_RAM (o))
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");
483 else // ROM
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");
493 printf("\n");
495 #endif
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 */
524 obj arg2;
525 obj arg3;
526 obj arg4;
527 obj cont;
528 obj env;
530 uint8 na; /* interpreter variables */
531 rom_addr pc;
532 uint8 glovars;
533 rom_addr entry;
534 uint8 bytecode;
535 uint8 bytecode_hi4;
536 uint8 bytecode_lo4;
537 int32 a1;
538 int32 a2;
539 int32 a3;
541 void init_ram_heap (void)
543 uint8 i;
544 obj o = MAX_RAM_ENCODING;
546 free_list = 0;
548 while (o > (MIN_RAM_ENCODING + (glovars + 1) / 2))
549 // we don't want to add globals to the free list, and globals occupy the
550 // beginning of memory at the rate of 2 globals per word (car and cdr)
552 ram_set_gc_tags (o, GC_TAG_UNMARKED);
553 ram_set_car (o, free_list);
554 free_list = o;
555 o--;
558 free_list_vec = MIN_VEC_ENCODING;
559 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
560 // each node of the free list must know the free length that follows it
561 // this free length is stored in words, not in bytes
562 // if we did count in bytes, the number might need more than 13 bits
563 ram_set_cdr (free_list_vec, VEC_BYTES / 4);
564 // TODO so, at the start, we have only 1 node that says the whole space is free
566 for (i=0; i<glovars; i++)
567 set_global (i, OBJ_FALSE);
569 arg1 = OBJ_FALSE;
570 arg2 = OBJ_FALSE;
571 arg3 = OBJ_FALSE;
572 arg4 = OBJ_FALSE;
573 cont = OBJ_FALSE;
574 env = OBJ_NULL;
578 void mark (obj temp)
580 /* mark phase */
582 obj stack;
583 obj visit;
585 if (IN_RAM(temp))
587 visit = NIL;
589 push:
591 stack = visit;
592 visit = temp;
594 // 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
595 IF_GC_TRACE(printf ("push stack=%d visit=%d (tag=%d)\n", stack, visit, ram_get_gc_tags (visit)>>5));
597 if ((HAS_1_OBJECT_FIELD (visit) && ram_get_gc_tag0 (visit))
598 || (HAS_2_OBJECT_FIELDS (visit)
599 && (ram_get_gc_tags (visit) != GC_TAG_UNMARKED)))
600 // TODO ugly condition
601 IF_GC_TRACE(printf ("case 1\n"));
602 else
604 if (HAS_2_OBJECT_FIELDS(visit)) // pairs and continuations
606 IF_GC_TRACE(printf ("case 5\n"));
608 visit_field2:
610 temp = ram_get_cdr (visit);
612 if (IN_RAM(temp))
614 IF_GC_TRACE(printf ("case 6\n"));
615 ram_set_gc_tags (visit, GC_TAG_1_LEFT);
616 ram_set_cdr (visit, stack);
617 goto push;
620 IF_GC_TRACE(printf ("case 7\n"));
622 goto visit_field1;
625 if (HAS_1_OBJECT_FIELD(visit))
627 IF_GC_TRACE(printf ("case 8\n"));
629 visit_field1:
631 if (RAM_CLOSURE(visit)) // closures have the pointer in the cdr
632 temp = ram_get_cdr (visit);
633 else
634 temp = ram_get_car (visit);
636 if (IN_RAM(temp))
638 IF_GC_TRACE(printf ("case 9\n"));
639 ram_set_gc_tag0 (visit, GC_TAG_0_LEFT);
640 if (RAM_CLOSURE(visit))
641 ram_set_cdr (visit, stack);
642 else
643 ram_set_car (visit, stack);
645 goto push;
648 IF_GC_TRACE(printf ("case 10\n"));
650 else
651 IF_GC_TRACE(printf ("case 11\n"));
653 ram_set_gc_tag0 (visit, GC_TAG_0_LEFT);
656 pop:
658 /* 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)); */
659 // TODO, like for push, getting the gc tags of nil is not great
660 IF_GC_TRACE(printf ("pop stack=%d visit=%d (tag=%d)\n", stack, visit, ram_get_gc_tags (visit)>>6));
662 if (stack != NIL)
664 if (HAS_2_OBJECT_FIELDS(stack) && ram_get_gc_tag1 (stack))
666 IF_GC_TRACE(printf ("case 13\n"));
668 temp = ram_get_cdr (stack); /* pop through cdr */
669 ram_set_cdr (stack, visit);
670 visit = stack;
671 stack = temp;
673 ram_set_gc_tag1(visit, GC_TAG_UNMARKED);
674 // we unset the "1-left" bit
676 goto visit_field1;
679 if (RAM_CLOSURE(stack))
680 // closures have one object field, but it's in the cdr
682 IF_GC_TRACE(printf ("case 13.5\n")); // TODO renumber cases
684 temp = ram_get_cdr (stack); /* pop through cdr */
685 ram_set_cdr (stack, visit);
686 visit = stack;
687 stack = temp;
689 goto pop;
692 IF_GC_TRACE(printf ("case 14\n"));
694 temp = ram_get_car (stack); /* pop through car */
695 ram_set_car (stack, visit);
696 visit = stack;
697 stack = temp;
699 goto pop;
704 #ifdef DEBUG_GC
705 int max_live = 0;
706 #endif
708 void sweep (void)
710 /* sweep phase */
712 #ifdef DEBUG_GC
713 int n = 0;
714 #endif
716 obj visit = MAX_RAM_ENCODING;
718 free_list = 0;
720 while (visit >= (MIN_RAM_ENCODING + ((glovars + 1) / 2)))
721 // we don't want to sweep the global variables area
723 if ((RAM_COMPOSITE(visit)
724 && (ram_get_gc_tags (visit) == GC_TAG_UNMARKED)) // 2 mark bit
725 || !(ram_get_gc_tags (visit) & GC_TAG_0_LEFT)) // 1 mark bit
726 /* unmarked? */
728 if (RAM_VECTOR(visit))
729 // when we sweep a vector, we also have to sweep its contents
731 obj o = ram_get_cdr (visit);
732 uint16 i = ram_get_car (visit); // number of elements
733 ram_set_car (o, free_list_vec);
734 ram_set_cdr (o, (i + 3) / 4); // free length, in words
735 free_list_vec = o;
736 // 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
738 ram_set_car (visit, free_list);
739 free_list = visit;
741 else
743 if (RAM_COMPOSITE(visit))
744 ram_set_gc_tags (visit, GC_TAG_UNMARKED);
745 else // only 1 mark bit to unset
746 ram_set_gc_tag0 (visit, GC_TAG_UNMARKED);
747 #ifdef DEBUG_GC
748 n++;
749 #endif
751 visit--;
754 #ifdef DEBUG_GC
755 if (n > max_live)
757 max_live = n;
758 printf ("**************** memory needed = %d\n", max_live+1);
759 fflush (stdout);
761 #endif
764 void gc (void)
766 uint8 i;
768 IF_TRACE(printf("\nGC BEGINS\n"));
770 IF_GC_TRACE(printf("arg1\n"));
771 mark (arg1);
772 IF_GC_TRACE(printf("arg2\n"));
773 mark (arg2);
774 IF_GC_TRACE(printf("arg3\n"));
775 mark (arg3);
776 IF_GC_TRACE(printf("arg4\n"));
777 mark (arg4);
778 IF_GC_TRACE(printf("cont\n"));
779 mark (cont);
780 IF_GC_TRACE(printf("env\n"));
781 mark (env); // TODO do we mark the free list or do we rebuild it every time ? what about vectors ?
783 for (i=0; i<glovars; i++)
784 mark (get_global (i));
786 sweep ();
789 obj alloc_ram_cell (void)
791 obj o;
793 #ifdef DEBUG_GC
794 gc ();
795 #endif
797 if (free_list == 0)
799 #ifndef DEBUG_GC
800 gc ();
801 if (free_list == 0)
802 #endif
803 ERROR("memory is full");
806 o = free_list;
808 free_list = ram_get_car (o);
810 return o;
813 obj alloc_ram_cell_init (uint8 f0, uint8 f1, uint8 f2, uint8 f3)
815 obj o = alloc_ram_cell ();
817 ram_set_field0 (o, f0);
818 ram_set_field1 (o, f1);
819 ram_set_field2 (o, f2);
820 ram_set_field3 (o, f3);
822 return o;
825 obj alloc_vec_cell (uint16 n) // TODO add a init version ?
827 obj o = free_list_vec;
828 obj prec = 0;
829 uint8 gc_done = 0;
831 #ifdef DEBUG_GC
832 gc ();
833 gc_done = 1;
834 #endif
836 while ((ram_get_cdr (o) * 4) < n) // free space too small
837 { // 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
838 if (o == 0) // no free space, or none big enough
840 if (gc_done) // we gc'd, but no space is big enough for the vector
841 ERROR("no room for vector");
842 #ifndef DEBUG_GC
843 gc ();
844 gc_done = 1;
845 #endif
846 o = free_list_vec;
847 prec = 0;
848 continue;
849 } // TODO fuse adjacent free spaces, and maybe compact ? FOOBAR
850 prec = o;
851 o = ram_get_car (o);
854 // case 1 : the new vector fills every free word advertized, we remove the
855 // node from the free list
856 // TODO mettre le cdr de o dans une var temporaire ?
857 if ((n - (ram_get_cdr(o) * 4)) < 4) // TODO is there a better way ?
859 if (prec)
860 ram_set_car (prec, ram_get_car (o));
861 else
862 free_list_vec = ram_get_car (o);
864 // case 2 : there is still some space left in the free section, create a new
865 // node to represent this space
866 else
868 obj new_free = o + (n + 3)/4;
869 if (prec)
870 ram_set_car (prec, new_free);
871 else
872 free_list_vec = new_free;
873 ram_set_car (new_free, ram_get_car (o));
874 ram_set_cdr (new_free, ram_get_cdr (o) - (n + 3)/4); // TODO documenter structure de cette free list quelque part
877 return o;
880 /*---------------------------------------------------------------------------*/
882 int32 decode_int (obj o)
884 uint8 u;
885 uint8 h;
886 uint8 l;
888 if (o < MIN_FIXNUM_ENCODING)
889 TYPE_ERROR("decode_int", "integer");
891 if (o <= (MIN_FIXNUM_ENCODING + (MAX_FIXNUM - MIN_FIXNUM)))
892 return DECODE_FIXNUM(o);
894 if (IN_RAM(o))
896 if (!RAM_BIGNUM(o))
897 TYPE_ERROR("decode_int", "integer");
899 u = ram_get_field1 (o);
900 h = ram_get_field2 (o);
901 l = ram_get_field3 (o);
903 else if (IN_ROM(o))
905 if (!ROM_BIGNUM(o))
906 TYPE_ERROR("decode_int", "integer");
908 u = rom_get_field1 (o);
909 h = rom_get_field2 (o);
910 l = rom_get_field3 (o);
912 else
913 TYPE_ERROR("decode_int", "integer");
915 if (u >= 128)
916 return ((int32)((((int16)u - 256) << 8) + h) << 8) + l;
918 return ((int32)(((int16)u << 8) + h) << 8) + l;
921 obj encode_int (int32 n)
923 if (n >= MIN_FIXNUM && n <= MAX_FIXNUM)
924 return ENCODE_FIXNUM(n);
926 return alloc_ram_cell_init (BIGNUM_FIELD0, n >> 16, n >> 8, n);
929 /*---------------------------------------------------------------------------*/
931 #ifdef WORKSTATION
933 void show (obj o)
935 #if 0
936 printf ("[%d]", o);
937 #endif
939 if (o == OBJ_FALSE)
940 printf ("#f");
941 else if (o == OBJ_TRUE)
942 printf ("#t");
943 else if (o == OBJ_NULL)
944 printf ("()");
945 else if (o <= (MIN_FIXNUM_ENCODING + (MAX_FIXNUM - MIN_FIXNUM)))
946 printf ("%d", DECODE_FIXNUM(o));
947 else // TODO past here, everything is either in ram or in rom, until we add a 3rd space for vectors, that is
949 uint8 in_ram;
951 if (IN_RAM(o))
952 in_ram = 1;
953 else
954 in_ram = 0;
956 if ((in_ram && RAM_BIGNUM(o)) || (!in_ram && ROM_BIGNUM(o)))
957 printf ("%d", decode_int (o));
958 else if ((in_ram && RAM_COMPOSITE(o)) || (!in_ram && ROM_COMPOSITE(o)))
960 obj car;
961 obj cdr;
963 if ((in_ram && RAM_PAIR(o)) || (!in_ram && ROM_PAIR(o))) // TODO not exactly efficient, fix it
965 if (in_ram)
967 car = ram_get_car (o);
968 cdr = ram_get_cdr (o);
970 else
972 car = rom_get_car (o);
973 cdr = rom_get_cdr (o);
976 printf ("(");
978 loop:
980 show (car);
982 if (cdr == OBJ_NULL)
983 printf (")");
984 else if ((IN_RAM(cdr) && RAM_PAIR(cdr))
985 || (IN_ROM(cdr) && ROM_PAIR(cdr)))
987 if (IN_RAM(cdr))
989 car = ram_get_car (cdr);
990 cdr = ram_get_cdr (cdr);
992 else
994 car = rom_get_car (cdr);
995 cdr = rom_get_cdr (cdr);
998 printf (" ");
999 goto loop;
1001 else
1003 printf (" . ");
1004 show (cdr);
1005 printf (")");
1008 else if ((in_ram && RAM_SYMBOL(o)) || (!in_ram && ROM_SYMBOL(o)))
1009 printf ("#<symbol>");
1010 else if ((in_ram && RAM_STRING(o)) || (!in_ram && ROM_STRING(o)))
1011 printf ("#<string>");
1012 else if ((in_ram && RAM_VECTOR(o)) || (!in_ram && ROM_VECTOR(o)))
1013 printf ("#<vector %d>", o); // TODO do better DEBUG BREGG
1014 else
1016 printf ("(");
1017 car = ram_get_car (o);
1018 cdr = ram_get_cdr (o);
1019 goto loop; // TODO ugly hack, takes advantage of the fact that pairs and continuations have the same layout
1022 else // closure
1024 obj env;
1025 rom_addr pc;
1027 if (IN_RAM(o)) // TODO can closures be in rom ? I don't think so
1028 env = ram_get_cdr (o);
1029 else
1030 env = rom_get_cdr (o);
1032 if (IN_RAM(o))
1033 pc = ram_get_entry (o);
1034 else
1035 pc = rom_get_entry (o);
1037 printf ("{0x%04x ", pc);
1038 show (env);
1039 printf ("}");
1043 fflush (stdout);
1046 void show_state (rom_addr pc)
1048 printf("\n");
1049 printf ("pc=0x%04x bytecode=0x%02x env=", pc, rom_get (pc));
1050 show (env);
1051 printf (" cont=");
1052 show (cont);
1053 printf ("\n");
1054 fflush (stdout);
1057 void print (obj o)
1059 show (o);
1060 printf ("\n");
1061 fflush (stdout);
1064 #endif
1066 /*---------------------------------------------------------------------------*/
1068 /* Integer operations */
1070 #define encode_bool(x) ((obj)(x))
1072 void prim_numberp (void)
1074 if (arg1 >= MIN_FIXNUM_ENCODING
1075 && arg1 <= (MIN_FIXNUM_ENCODING + (MAX_FIXNUM - MIN_FIXNUM)))
1076 arg1 = OBJ_TRUE;
1077 else
1079 if (IN_RAM(arg1))
1080 arg1 = encode_bool (RAM_BIGNUM(arg1));
1081 else if (IN_ROM(arg1))
1082 arg1 = encode_bool (ROM_BIGNUM(arg1));
1083 else
1084 arg1 = OBJ_FALSE;
1088 void decode_2_int_args (void)
1090 a1 = decode_int (arg1);
1091 a2 = decode_int (arg2);
1094 void prim_add (void)
1096 decode_2_int_args ();
1097 arg1 = encode_int (a1 + a2);
1098 arg2 = OBJ_FALSE;
1101 void prim_sub (void)
1103 decode_2_int_args ();
1104 arg1 = encode_int (a1 - a2);
1105 arg2 = OBJ_FALSE;
1108 void prim_mul (void)
1110 decode_2_int_args ();
1111 arg1 = encode_int (a1 * a2);
1112 arg2 = OBJ_FALSE;
1115 void prim_div (void)
1117 decode_2_int_args ();
1118 if (a2 == 0)
1119 ERROR("divide by 0");
1120 arg1 = encode_int (a1 / a2);
1121 arg2 = OBJ_FALSE;
1124 void prim_rem (void)
1126 decode_2_int_args ();
1127 if (a2 == 0)
1128 ERROR("divide by 0");
1129 arg1 = encode_int (a1 % a2);
1130 arg2 = OBJ_FALSE;
1133 void prim_neg (void)
1135 a1 = decode_int (arg1);
1136 arg1 = encode_int (- a1);
1139 void prim_eq (void)
1141 decode_2_int_args ();
1142 arg1 = encode_bool (a1 == a2);
1143 arg2 = OBJ_FALSE;
1146 void prim_lt (void)
1148 decode_2_int_args ();
1149 arg1 = encode_bool (a1 < a2);
1150 arg2 = OBJ_FALSE;
1153 void prim_gt (void)
1155 decode_2_int_args ();
1156 arg1 = encode_bool (a1 > a2);
1157 arg2 = OBJ_FALSE;
1160 void prim_ior (void)
1162 a1 = decode_int (arg1);
1163 a2 = decode_int (arg2);
1164 arg1 = encode_int (a1 | a2);
1165 arg2 = OBJ_FALSE;
1168 void prim_xor (void)
1170 a1 = decode_int (arg1);
1171 a2 = decode_int (arg2);
1172 arg1 = encode_int (a1 ^ a2);
1173 arg2 = OBJ_FALSE;
1177 /*---------------------------------------------------------------------------*/
1179 /* List operations */
1181 void prim_pairp (void)
1183 if (IN_RAM(arg1))
1184 arg1 = encode_bool (RAM_PAIR(arg1));
1185 else if (IN_ROM(arg1))
1186 arg1 = encode_bool (ROM_PAIR(arg1));
1187 else
1188 arg1 = OBJ_FALSE;
1191 obj cons (obj car, obj cdr)
1193 return alloc_ram_cell_init (COMPOSITE_FIELD0 | (car >> 8), // TODO was ((car & 0x1f00) >> 8), probably redundant
1194 car & 0xff,
1195 PAIR_FIELD2 | (cdr >> 8), // TODO was ((cdr & 0x1f00) >> 8), probably redundant
1196 cdr & 0xff);
1199 void prim_cons (void)
1201 arg1 = cons (arg1, arg2);
1202 arg2 = OBJ_FALSE;
1205 void prim_car (void)
1207 if (IN_RAM(arg1))
1209 if (!RAM_PAIR(arg1))
1210 TYPE_ERROR("car", "pair");
1211 arg1 = ram_get_car (arg1);
1213 else if (IN_ROM(arg1))
1215 if (!ROM_PAIR(arg1))
1216 TYPE_ERROR("car", "pair");
1217 arg1 = rom_get_car (arg1);
1219 else
1221 TYPE_ERROR("car", "pair");
1225 void prim_cdr (void)
1227 if (IN_RAM(arg1))
1229 if (!RAM_PAIR(arg1))
1230 TYPE_ERROR("cdr", "pair");
1231 arg1 = ram_get_cdr (arg1);
1233 else if (IN_ROM(arg1))
1235 if (!ROM_PAIR(arg1))
1236 TYPE_ERROR("cdr", "pair");
1237 arg1 = rom_get_cdr (arg1);
1239 else
1241 TYPE_ERROR("cdr", "pair");
1245 void prim_set_car (void)
1247 if (IN_RAM(arg1))
1249 if (!RAM_PAIR(arg1))
1250 TYPE_ERROR("set-car!", "pair");
1252 ram_set_car (arg1, arg2);
1253 arg1 = OBJ_FALSE;
1254 arg2 = OBJ_FALSE;
1256 else
1258 TYPE_ERROR("set-car!", "pair");
1262 void prim_set_cdr (void)
1264 if (IN_RAM(arg1))
1266 if (!RAM_PAIR(arg1))
1267 TYPE_ERROR("set-cdr!", "pair");
1269 ram_set_cdr (arg1, arg2);
1270 arg1 = OBJ_FALSE;
1271 arg2 = OBJ_FALSE;
1273 else
1275 TYPE_ERROR("set-cdr!", "pair");
1279 void prim_nullp (void)
1281 arg1 = encode_bool (arg1 == OBJ_NULL);
1284 /*---------------------------------------------------------------------------*/
1286 /* Vector operations */
1288 void prim_u8vectorp (void)
1290 if (IN_RAM(arg1))
1291 arg1 = encode_bool (RAM_VECTOR(arg1));
1292 else if (IN_ROM(arg1))
1293 arg1 = encode_bool (ROM_VECTOR(arg1));
1294 else
1295 arg1 = OBJ_FALSE;
1298 void prim_make_u8vector (void)
1300 obj elems = alloc_vec_cell (arg1); // arg1 is length
1301 arg1 = alloc_ram_cell_init (COMPOSITE_FIELD0 | (arg1 >> 8),
1302 arg1 & 0xff,
1303 VECTOR_FIELD2 | (elems >> 8),
1304 elems & 0xff);
1305 // the contents of the vector are intentionally left as they were.
1306 // it is up to the library functions to set them accordingly
1309 void prim_u8vector_ref (void)
1310 { // TODO how do we deal with rom vectors ? as lists ? they're never all that long
1311 arg2 = decode_int (arg2);
1313 if (IN_RAM(arg1))
1315 if (!RAM_VECTOR(arg1))
1316 TYPE_ERROR("u8vector-ref", "vector");
1317 if (ram_get_car (arg1) < arg2)
1318 ERROR("vector index too large");
1319 arg1 = ram_get_cdr (arg1);
1321 else if (IN_ROM(arg1))
1323 if (!ROM_VECTOR(arg1))
1324 TYPE_ERROR("u8vector-ref", "vector");
1325 if (rom_get_car (arg1) < arg2)
1326 ERROR("vector index too large");
1327 arg1 = rom_get_cdr (arg1);
1329 else
1330 TYPE_ERROR("u8vector-ref", "vector");
1332 if (IN_VEC(arg1))
1334 arg1 += (arg2 / 4);
1335 arg2 %= 4;
1337 switch (arg2)
1339 case 0:
1340 arg1 = ram_get_field0 (arg1); break;
1341 case 1:
1342 arg1 = ram_get_field1 (arg1); break;
1343 case 2:
1344 arg1 = ram_get_field2 (arg1); break;
1345 case 3:
1346 arg1 = ram_get_field3 (arg1); break;
1349 arg1 = encode_int (arg1);
1351 else // rom vector, stored as a list
1352 { // 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)
1353 while (arg2--)
1354 arg1 = rom_get_cdr (arg1);
1356 arg1 = rom_get_car (arg1);
1359 arg2 = OBJ_FALSE;
1362 void prim_u8vector_set (void)
1363 { // TODO a lot in common with ref, abstract that
1364 arg2 = decode_int (arg2);
1365 arg3 = decode_int (arg3);
1367 if (arg3 > 255)
1368 ERROR("byte vectors can only contain bytes");
1370 if (IN_RAM(arg1))
1372 if (!RAM_VECTOR(arg1))
1373 TYPE_ERROR("u8vector-set!", "vector");
1374 if (ram_get_car (arg1) < arg2)
1375 ERROR("vector index too large");
1376 arg1 = ram_get_cdr (arg1);
1378 else
1379 TYPE_ERROR("u8vector-set!", "vector");
1381 arg1 += (arg2 / 4);
1382 arg2 %= 4;
1384 switch (arg2)
1386 case 0:
1387 ram_set_field0 (arg1, arg3); break;
1388 case 1:
1389 ram_set_field1 (arg1, arg3); break;
1390 case 2:
1391 ram_set_field2 (arg1, arg3); break;
1392 case 3:
1393 ram_set_field3 (arg1, arg3); break;
1396 arg1 = OBJ_FALSE;
1397 arg2 = OBJ_FALSE;
1398 arg3 = OBJ_FALSE;
1401 void prim_u8vector_length (void)
1403 if (IN_RAM(arg1))
1405 if (!RAM_VECTOR(arg1))
1406 TYPE_ERROR("u8vector-length", "vector");
1407 arg1 = encode_int (ram_get_car (arg1));
1409 else if (IN_ROM(arg1))
1411 if (!ROM_VECTOR(arg1))
1412 TYPE_ERROR("u8vector-length", "vector");
1413 arg1 = rom_get_car (arg1);
1415 else
1416 TYPE_ERROR("u8vector-length", "vector");
1419 /*---------------------------------------------------------------------------*/
1421 /* Miscellaneous operations */
1423 void prim_eqp (void)
1425 arg1 = encode_bool (arg1 == arg2);
1426 arg2 = OBJ_FALSE;
1429 void prim_not (void)
1431 arg1 = encode_bool (arg1 == OBJ_FALSE);
1434 void prim_symbolp (void)
1436 if (IN_RAM(arg1))
1437 arg1 = encode_bool (RAM_SYMBOL(arg1));
1438 else if (IN_ROM(arg1))
1439 arg1 = encode_bool (ROM_SYMBOL(arg1));
1440 else
1441 arg1 = OBJ_FALSE;
1444 void prim_stringp (void)
1446 if (IN_RAM(arg1))
1447 arg1 = encode_bool (RAM_STRING(arg1));
1448 else if (IN_ROM(arg1))
1449 arg1 = encode_bool (ROM_STRING(arg1));
1450 else
1451 arg1 = OBJ_FALSE;
1454 void prim_string2list (void)
1456 if (IN_RAM(arg1))
1458 if (!RAM_STRING(arg1))
1459 TYPE_ERROR("string->list", "string");
1461 arg1 = ram_get_car (arg1);
1463 else if (IN_ROM(arg1))
1465 if (!ROM_STRING(arg1))
1466 TYPE_ERROR("string->list", "string");
1468 arg1 = rom_get_car (arg1);
1470 else
1471 TYPE_ERROR("string->list", "string");
1474 void prim_list2string (void)
1476 arg1 = alloc_ram_cell_init (COMPOSITE_FIELD0 | ((arg1 & 0x1f00) >> 8),
1477 arg1 & 0xff,
1478 STRING_FIELD2,
1483 /*---------------------------------------------------------------------------*/
1485 /* Robot specific operations */
1488 void prim_print (void)
1490 #ifdef PICOBOARD2
1491 #endif
1493 #ifdef WORKSTATION
1495 print (arg1);
1497 #endif
1499 arg1 = OBJ_FALSE;
1503 int32 read_clock (void)
1505 int32 now = 0;
1507 #ifdef PICOBOARD2
1509 now = from_now( 0 );
1511 #endif
1513 #ifdef WORKSTATION
1515 #ifdef _WIN32
1517 static int32 start = 0;
1518 struct timeb tb;
1520 ftime (&tb);
1522 now = tb.time * 1000 + tb.millitm;
1523 if (start == 0)
1524 start = now;
1525 now -= start;
1527 #else
1529 static int32 start = 0;
1530 struct timeval tv;
1532 if (gettimeofday (&tv, NULL) == 0)
1534 now = tv.tv_sec * 1000 + tv.tv_usec / 1000;
1535 if (start == 0)
1536 start = now;
1537 now -= start;
1540 #endif
1542 #endif
1544 return now;
1548 void prim_clock (void)
1550 arg1 = encode_int (read_clock ());
1554 void prim_motor (void)
1556 decode_2_int_args ();
1558 if (a1 < 1 || a1 > 2 || a2 < -100 || a2 > 100)
1559 ERROR("argument out of range to procedure \"motor\"");
1561 #ifdef PICOBOARD2
1563 fw_motor ();
1565 #endif
1567 #ifdef WORKSTATION
1569 printf ("motor %d -> power=%d\n", a1, a2);
1570 fflush (stdout);
1572 #endif
1574 arg1 = OBJ_FALSE;
1575 arg2 = OBJ_FALSE;
1579 void prim_led (void)
1581 decode_2_int_args ();
1582 a3 = decode_int (arg3);
1584 if (a1 < 1 || a1 > 3 || a2 < 0 || a3 < 0)
1585 ERROR("argument out of range to procedure \"led\"");
1587 #ifdef PICOBOARD2
1589 LED_set( a1, a2, a3 );
1591 #endif
1593 #ifdef WORKSTATION
1595 printf ("led %d -> duty=%d period=%d\n", a1, a2, a3 );
1596 fflush (stdout);
1598 #endif
1600 arg1 = OBJ_FALSE;
1601 arg2 = OBJ_FALSE;
1602 arg3 = OBJ_FALSE;
1606 void prim_led2_color (void)
1608 a1 = decode_int (arg1);
1610 if (a1 < 0 || a1 > 1)
1611 ERROR("argument out of range to procedure \"led2-color\"");
1613 #ifdef PICOBOARD2
1615 LED2_color_set( a1 );
1617 #endif
1619 #ifdef WORKSTATION
1621 printf ("led2-color -> %s\n", (a1==0)?"green":"red");
1622 fflush (stdout);
1624 #endif
1626 arg1 = OBJ_FALSE;
1630 void prim_getchar_wait (void)
1632 decode_2_int_args();
1633 a1 = read_clock () + a1;
1635 if (a1 < 0 || a2 < 1 || a2 > 3)
1636 ERROR("argument out of range to procedure \"getchar-wait\"");
1638 #ifdef PICOBOARD2
1640 arg1 = OBJ_FALSE;
1643 serial_port_set ports;
1644 ports = serial_rx_wait_with_timeout( a2, a1 );
1645 if (ports != 0)
1646 arg1 = encode_int (serial_rx_read( ports ));
1649 #endif
1651 #ifdef WORKSTATION
1653 #ifdef _WIN32
1655 arg1 = OBJ_FALSE;
1659 if (_kbhit ())
1661 arg1 = encode_int (_getch ());
1662 break;
1664 } while (read_clock () < a1);
1667 #else
1669 arg1 = encode_int (getchar ());
1671 #endif
1673 #endif
1677 void prim_putchar (void)
1679 decode_2_int_args ();
1681 if (a1 < 0 || a1 > 255 || a2 < 1 || a2 > 3)
1682 ERROR("argument out of range to procedure \"putchar\"");
1684 #ifdef PICOBOARD2
1686 serial_tx_write( a2, a1 );
1688 #endif
1690 #ifdef WORKSTATION
1692 putchar (a1);
1693 fflush (stdout);
1695 #endif
1697 arg1 = OBJ_FALSE;
1698 arg2 = OBJ_FALSE;
1702 void prim_beep (void)
1704 decode_2_int_args ();
1706 if (a1 < 1 || a1 > 255 || a2 < 0)
1707 ERROR("argument out of range to procedure \"beep\"");
1709 #ifdef PICOBOARD2
1711 beep( a1, from_now( a2 ) );
1713 #endif
1715 #ifdef WORKSTATION
1717 printf ("beep -> freq-div=%d duration=%d\n", a1, a2 );
1718 fflush (stdout);
1720 #endif
1722 arg1 = OBJ_FALSE;
1723 arg2 = OBJ_FALSE;
1727 void prim_adc (void)
1729 short x;
1731 a1 = decode_int (arg1);
1733 if (a1 < 1 || a1 > 3)
1734 ERROR("argument out of range to procedure \"adc\"");
1736 #ifdef PICOBOARD2
1738 x = adc( a1 );
1740 #endif
1742 #ifdef WORKSTATION
1744 x = read_clock () & 255;
1746 if (x > 127) x = 256 - x;
1748 x += 200;
1750 #endif
1752 arg1 = encode_int (x);
1756 void prim_dac (void)
1758 a1 = decode_int (arg1);
1760 if (a1 < 0 || a1 > 255)
1761 ERROR("argument out of range to procedure \"dac\"");
1763 #ifdef PICOBOARD2
1765 dac( a1 );
1767 #endif
1769 #ifdef WORKSTATION
1771 printf ("dac -> %d\n", a1 );
1772 fflush (stdout);
1774 #endif
1776 arg1 = OBJ_FALSE;
1780 void prim_sernum (void)
1782 short x;
1784 #ifdef PICOBOARD2
1786 x = serial_num ();
1788 #endif
1790 #ifdef WORKSTATION
1792 x = 0;
1794 #endif
1796 arg1 = encode_int (x);
1800 /*---------------------------------------------------------------------------*/
1802 #ifdef WORKSTATION
1804 int hidden_fgetc (FILE *f)
1806 int c = fgetc (f);
1807 #if 0
1808 printf ("{%d}",c);
1809 fflush (stdout);
1810 #endif
1811 return c;
1814 #define fgetc(f) hidden_fgetc(f)
1816 void write_hex_nibble (int n)
1818 putchar ("0123456789ABCDEF"[n]);
1821 void write_hex (uint8 n)
1823 write_hex_nibble (n >> 4);
1824 write_hex_nibble (n & 0x0f);
1827 int hex (int c)
1829 if (c >= '0' && c <= '9')
1830 return (c - '0');
1832 if (c >= 'A' && c <= 'F')
1833 return (c - 'A' + 10);
1835 if (c >= 'a' && c <= 'f')
1836 return (c - 'a' + 10);
1838 return -1;
1841 int read_hex_byte (FILE *f)
1843 int h1 = hex (fgetc (f));
1844 int h2 = hex (fgetc (f));
1846 if (h1 >= 0 && h2 >= 0)
1847 return (h1<<4) + h2;
1849 return -1;
1852 int read_hex_file (char *filename)
1854 int c;
1855 FILE *f = fopen (filename, "r");
1856 int result = 0;
1857 int len;
1858 int a, a1, a2;
1859 int t;
1860 int b;
1861 int i;
1862 uint8 sum;
1863 int hi16 = 0;
1865 for (i=0; i<ROM_BYTES; i++)
1866 rom_mem[i] = 0xff;
1868 if (f != NULL)
1870 while ((c = fgetc (f)) != EOF)
1872 if ((c == '\r') || (c == '\n'))
1873 continue;
1875 if (c != ':' ||
1876 (len = read_hex_byte (f)) < 0 ||
1877 (a1 = read_hex_byte (f)) < 0 ||
1878 (a2 = read_hex_byte (f)) < 0 ||
1879 (t = read_hex_byte (f)) < 0)
1880 break;
1882 a = (a1 << 8) + a2;
1884 i = 0;
1885 sum = len + a1 + a2 + t;
1887 if (t == 0)
1889 next0:
1891 if (i < len)
1893 unsigned long adr = ((unsigned long)hi16 << 16) + a - CODE_START;
1895 if ((b = read_hex_byte (f)) < 0)
1896 break;
1898 if (adr >= 0 && adr < ROM_BYTES)
1899 rom_mem[adr] = b;
1901 a = (a + 1) & 0xffff;
1902 i++;
1903 sum += b;
1905 goto next0;
1908 else if (t == 1)
1910 if (len != 0)
1911 break;
1913 else if (t == 4)
1915 if (len != 2)
1916 break;
1918 if ((a1 = read_hex_byte (f)) < 0 ||
1919 (a2 = read_hex_byte (f)) < 0)
1920 break;
1922 sum += a1 + a2;
1924 hi16 = (a1<<8) + a2;
1926 else
1927 break;
1929 if ((b = read_hex_byte (f)) < 0)
1930 break;
1932 sum = -sum;
1934 if (sum != b)
1936 printf ("*** HEX file checksum error (expected 0x%02x)\n", sum);
1937 break;
1940 c = fgetc (f);
1942 if ((c != '\r') && (c != '\n'))
1943 break;
1945 if (t == 1)
1947 result = 1;
1948 break;
1952 if (result == 0)
1953 printf ("*** HEX file syntax error\n");
1955 fclose (f);
1958 return result;
1961 #endif
1963 /*---------------------------------------------------------------------------*/
1965 #define FETCH_NEXT_BYTECODE() bytecode = rom_get (pc++)
1967 #define BEGIN_DISPATCH() \
1968 dispatch: \
1969 IF_TRACE(show_state (pc)); \
1970 FETCH_NEXT_BYTECODE(); \
1971 bytecode_hi4 = bytecode & 0xf0; \
1972 bytecode_lo4 = bytecode & 0x0f; \
1973 switch (bytecode_hi4 >> 4) {
1975 #define END_DISPATCH() }
1977 #define CASE(opcode) case (opcode>>4):;
1979 #define DISPATCH(); goto dispatch;
1981 #if 0
1982 #define pc FSR1
1983 #define sp FSR2
1984 #define bytecode TABLAT
1985 #define bytecode_hi4 WREG
1986 #endif
1988 #define PUSH_CONSTANT1 0x00
1989 #define PUSH_CONSTANT2 0x10
1990 #define PUSH_STACK1 0x20
1991 #define PUSH_STACK2 0x30
1992 #define PUSH_GLOBAL 0x40
1993 #define SET_GLOBAL 0x50
1994 #define CALL 0x60
1995 #define JUMP 0x70
1996 #define LABEL_INSTR 0x80
1997 #define PUSH_CONSTANT_LONG 0x90
1999 // TODO these are free
2000 #define GOTO 0xa0
2001 #define GOTO_IF_FALSE 0xb0
2002 #define CLOSURE 0xc0
2004 #define PRIM1 0xd0
2005 #define PRIM2 0xe0
2006 #define PRIM3 0xf0
2008 #ifdef WORKSTATION
2010 char *prim_name[48] =
2012 "prim #%number?",
2013 "prim #%+",
2014 "prim #%-",
2015 "prim #%*",
2016 "prim #%quotient",
2017 "prim #%remainder",
2018 "prim #%neg",
2019 "prim #%=",
2020 "prim #%<",
2021 "prim #%ior",
2022 "prim #%>",
2023 "prim #%xor",
2024 "prim #%pair?",
2025 "prim #%cons",
2026 "prim #%car",
2027 "prim #%cdr",
2028 "prim #%set-car!",
2029 "prim #%set-cdr!",
2030 "prim #%null?",
2031 "prim #%eq?",
2032 "prim #%not",
2033 "prim #%get-cont",
2034 "prim #%graft-to-cont",
2035 "prim #%return-to-cont",
2036 "prim #%halt",
2037 "prim #%symbol?",
2038 "prim #%string?",
2039 "prim #%string->list",
2040 "prim #%list->string",
2041 "prim #%make-u8vector", // TODO was prim29
2042 "prim #%u8vector-ref", // TODO was prim30
2043 "prim #%u8vector-set!", // TODO was prim31
2044 "prim #%print",
2045 "prim #%clock",
2046 "prim #%motor",
2047 "prim #%led",
2048 "prim #%led2-color",
2049 "prim #%getchar-wait",
2050 "prim #%putchar",
2051 "prim #%beep",
2052 "prim #%adc",
2053 "prim #%u8vector?", // TODO was dac, but it's not plugged to anything
2054 "prim #%sernum",
2055 "prim #%u8vector-length", // TODO was prim43
2056 "push-constant [long]",
2057 "shift",
2058 "pop",
2059 "return",
2062 #endif
2064 #define PUSH_ARG1() push_arg1 ()
2065 #define POP() pop()
2067 void push_arg1 (void)
2069 env = cons (arg1, env);
2070 arg1 = OBJ_FALSE;
2073 obj pop (void)
2075 obj o = ram_get_car (env);
2076 env = ram_get_cdr (env);
2077 return o;
2080 void pop_procedure (void)
2082 arg1 = POP();
2084 if (IN_RAM(arg1))
2086 if (!RAM_CLOSURE(arg1))
2087 TYPE_ERROR("pop_procedure", "procedure");
2089 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
2091 else if (IN_ROM(arg1))
2093 if (!ROM_CLOSURE(arg1))
2094 TYPE_ERROR("pop_procedure", "procedure");
2096 entry = rom_get_entry (arg1) + CODE_START;
2098 else
2099 TYPE_ERROR("pop_procedure", "procedure");
2102 void handle_arity_and_rest_param (void)
2104 uint8 np;
2106 np = rom_get (entry++);
2108 if ((np & 0x80) == 0)
2110 if (na != np)
2111 ERROR("wrong number of arguments");
2113 else
2115 np = ~np;
2117 if (na < np)
2118 ERROR("wrong number of arguments");
2120 arg3 = OBJ_NULL;
2122 while (na > np)
2124 arg4 = POP();
2126 arg3 = cons (arg4, arg3);
2127 arg4 = OBJ_FALSE;
2129 na--;
2132 arg1 = cons (arg3, arg1);
2133 arg3 = OBJ_FALSE;
2137 void build_env (void)
2139 while (na != 0)
2141 arg3 = POP();
2143 arg1 = cons (arg3, arg1);
2145 na--;
2148 arg3 = OBJ_FALSE;
2151 void save_cont (void)
2153 // the second half is a closure
2154 arg3 = alloc_ram_cell_init (CLOSURE_FIELD0 | (pc >> 11),
2155 (pc >> 3) & 0xff,
2156 ((pc & 0x0007) << 5) | (env >> 8),
2157 env & 0xff);
2158 cont = alloc_ram_cell_init (COMPOSITE_FIELD0 | (cont >> 8),
2159 cont & 0xff,
2160 CONTINUATION_FIELD2 | (arg3 >> 8),
2161 arg3 & 0xff);
2162 arg3 = OBJ_FALSE;
2165 void interpreter (void)
2167 pc = (CODE_START + 4) + ((rom_addr)rom_get (CODE_START+2) << 2);
2169 glovars = rom_get (CODE_START+3); // number of global variables
2171 init_ram_heap ();
2173 BEGIN_DISPATCH();
2175 /***************************************************************************/
2176 CASE(PUSH_CONSTANT1);
2178 IF_TRACE(printf(" (push-constant "); show (bytecode_lo4); printf (")\n"));
2180 arg1 = bytecode_lo4;
2182 PUSH_ARG1();
2184 DISPATCH();
2186 /***************************************************************************/
2187 CASE(PUSH_CONSTANT2);
2189 IF_TRACE(printf(" (push-constant "); show (bytecode_lo4+16); printf (")\n"));
2190 arg1 = bytecode_lo4+16;
2192 PUSH_ARG1();
2194 DISPATCH();
2196 /***************************************************************************/
2197 CASE(PUSH_STACK1);
2199 IF_TRACE(printf(" (push-stack %d)\n", bytecode_lo4));
2201 arg1 = env;
2203 while (bytecode_lo4 != 0)
2205 arg1 = ram_get_cdr (arg1);
2206 bytecode_lo4--;
2209 arg1 = ram_get_car (arg1);
2211 PUSH_ARG1();
2213 DISPATCH();
2215 /***************************************************************************/
2216 CASE(PUSH_STACK2);
2218 IF_TRACE(printf(" (push-stack %d)\n", bytecode_lo4+16));
2219 // TODO does this ever happens ?
2220 bytecode_lo4 += 16;
2222 arg1 = env;
2224 while (bytecode_lo4 != 0)
2226 arg1 = ram_get_cdr (arg1);
2227 bytecode_lo4--;
2230 arg1 = ram_get_car (arg1);
2232 PUSH_ARG1();
2234 DISPATCH();
2236 /***************************************************************************/
2237 CASE(PUSH_GLOBAL);
2239 IF_TRACE(printf(" (push-global %d)\n", bytecode_lo4));
2241 arg1 = get_global (bytecode_lo4);
2243 PUSH_ARG1();
2245 DISPATCH();
2247 /***************************************************************************/
2248 CASE(SET_GLOBAL);
2250 IF_TRACE(printf(" (set-global %d)\n", bytecode_lo4));
2252 set_global (bytecode_lo4, POP()); // TODO debug
2254 DISPATCH();
2256 /***************************************************************************/
2257 CASE(CALL);
2259 IF_TRACE(printf(" (call %d)\n", bytecode_lo4));
2261 na = bytecode_lo4;
2263 pop_procedure ();
2264 handle_arity_and_rest_param ();
2265 build_env ();
2266 save_cont ();
2268 env = arg1;
2269 pc = entry;
2271 arg1 = OBJ_FALSE;
2273 DISPATCH();
2275 /***************************************************************************/
2276 CASE(JUMP);
2278 IF_TRACE(printf(" (jump %d)\n", bytecode_lo4));
2280 na = bytecode_lo4;
2282 pop_procedure ();
2283 handle_arity_and_rest_param ();
2284 build_env ();
2286 env = arg1;
2287 pc = entry;
2289 arg1 = OBJ_FALSE;
2291 DISPATCH();
2293 /***************************************************************************/
2294 CASE(LABEL_INSTR);
2296 switch (bytecode_lo4)
2298 case 0: // call-toplevel TODO put these in separate functions ?
2299 FETCH_NEXT_BYTECODE();
2300 arg2 = bytecode;
2302 FETCH_NEXT_BYTECODE();
2304 IF_TRACE(printf(" (call-toplevel 0x%04x)\n",
2305 ((arg2 << 8) | bytecode) + CODE_START));
2307 entry = (arg2 << 8) + bytecode + CODE_START;
2308 arg1 = OBJ_NULL;
2310 na = rom_get (entry++);
2312 build_env ();
2313 save_cont ();
2315 env = arg1;
2316 pc = entry;
2318 arg1 = OBJ_FALSE;
2319 arg2 = OBJ_FALSE;
2321 break;
2323 case 1: // jump-toplevel
2324 FETCH_NEXT_BYTECODE();
2325 arg2 = bytecode;
2327 FETCH_NEXT_BYTECODE();
2329 IF_TRACE(printf(" (jump-toplevel 0x%04x)\n",
2330 ((arg2 << 8) | bytecode) + CODE_START));
2332 entry = (arg2 << 8) + bytecode + CODE_START; // TODO this is a common pattern
2333 arg1 = OBJ_NULL;
2335 na = rom_get (entry++);
2337 build_env ();
2339 env = arg1;
2340 pc = entry;
2342 arg1 = OBJ_FALSE;
2343 arg2 = OBJ_FALSE;
2345 break;
2347 case 2: // goto
2348 FETCH_NEXT_BYTECODE();
2349 arg2 = bytecode;
2351 FETCH_NEXT_BYTECODE();
2353 IF_TRACE(printf(" (goto 0x%04x)\n",
2354 (arg2 << 8) + bytecode + CODE_START));
2356 pc = (arg2 << 8) + bytecode + CODE_START;
2358 break;
2360 case 3: // goto-if-false
2361 FETCH_NEXT_BYTECODE();
2362 arg2 = bytecode;
2364 FETCH_NEXT_BYTECODE();
2366 IF_TRACE(printf(" (goto-if-false 0x%04x)\n",
2367 (arg2 << 8) + bytecode + CODE_START));
2369 if (POP() == OBJ_FALSE)
2370 pc = (arg2 << 8) + bytecode + CODE_START;
2372 break;
2374 case 4: // closure
2375 FETCH_NEXT_BYTECODE();
2376 arg2 = bytecode;
2378 FETCH_NEXT_BYTECODE();
2380 IF_TRACE(printf(" (closure 0x%04x)\n", (arg2 << 8) | bytecode));
2382 arg3 = POP(); // env
2384 entry = (arg2 << 8) | bytecode;
2386 arg1 = alloc_ram_cell_init (CLOSURE_FIELD0 | (arg2 >> 3),
2387 ((arg2 & 0x07) << 5) | (bytecode >> 3),
2388 ((bytecode &0x07) <<5) |((arg3 &0x1f00) >>8),
2389 arg3 & 0xff);
2391 PUSH_ARG1();
2393 arg2 = OBJ_FALSE;
2394 arg3 = OBJ_FALSE;
2396 break;
2398 case 5: // call-toplevel-short
2399 FETCH_NEXT_BYTECODE(); // TODO the sort version have a lot in common with the long ones, abstract ?
2400 // TODO short instructions don't work at the moment
2401 IF_TRACE(printf(" (call-toplevel-short 0x%04x)\n",
2402 pc + bytecode + CODE_START));
2404 entry = pc + bytecode + CODE_START;
2405 arg1 = OBJ_NULL;
2407 na = rom_get (entry++);
2409 build_env ();
2410 save_cont ();
2412 env = arg1;
2413 pc = entry;
2415 arg1 = OBJ_FALSE;
2417 break;
2419 case 6: // jump-toplevel-short
2420 FETCH_NEXT_BYTECODE();
2422 IF_TRACE(printf(" (jump-toplevel-short 0x%04x)\n",
2423 pc + bytecode + CODE_START));
2425 entry = pc + bytecode + CODE_START;
2426 arg1 = OBJ_NULL;
2428 na = rom_get (entry++);
2430 build_env ();
2432 env = arg1;
2433 pc = entry;
2435 arg1 = OBJ_FALSE;
2437 break;
2439 case 7: // goto-short
2440 FETCH_NEXT_BYTECODE();
2442 IF_TRACE(printf(" (goto-short 0x%04x)\n", pc + bytecode + CODE_START));
2444 pc = pc + bytecode + CODE_START;
2446 break;
2448 case 8: // goto-if-false-short
2449 FETCH_NEXT_BYTECODE();
2451 IF_TRACE(printf(" (goto-if-false-short 0x%04x)\n",
2452 pc + bytecode + CODE_START));
2454 if (POP() == OBJ_FALSE)
2455 pc = pc + bytecode + CODE_START;
2457 break;
2459 case 9: // closure-short TODO I doubt these short instrs will have great effect, and this is the one I doubt the most about
2460 FETCH_NEXT_BYTECODE();
2462 IF_TRACE(printf(" (closure-short 0x%04x)\n", pc + bytecode));
2464 arg3 = POP(); // env
2466 entry = pc + bytecode; // TODO makes sense for a closure ?
2468 arg1 = alloc_ram_cell_init (CLOSURE_FIELD0 | (arg2 >> 3),
2469 ((arg2 & 0x07) << 5) | (bytecode >> 3),
2470 ((bytecode &0x07) <<5) |((arg3 &0x1f00) >>8),
2471 arg3 & 0xff);
2473 PUSH_ARG1();
2475 arg3 = OBJ_FALSE;
2477 break;
2479 #if 0
2480 case 10:
2481 break;
2482 case 11:
2483 break;
2484 case 12:
2485 break;
2486 case 13:
2487 break;
2488 #endif
2489 case 14: // push_global [long]
2490 FETCH_NEXT_BYTECODE();
2492 IF_TRACE(printf(" (push-global [long] %d)\n", bytecode));
2494 arg1 = get_global (bytecode);
2496 PUSH_ARG1();
2498 break;
2500 case 15: // set_global [long]
2501 FETCH_NEXT_BYTECODE();
2503 IF_TRACE(printf(" (set-global [long] %d)\n", bytecode));
2505 set_global (bytecode, POP());
2507 break;
2510 DISPATCH();
2512 /***************************************************************************/
2513 CASE(PUSH_CONSTANT_LONG);
2515 /* push-constant [long] */
2517 FETCH_NEXT_BYTECODE();
2519 IF_TRACE(printf(" (push [long] 0x%04x)\n", (bytecode_lo4 << 8) + bytecode));
2521 arg1 = (bytecode_lo4 << 8) | bytecode;
2522 PUSH_ARG1();
2524 DISPATCH();
2526 /***************************************************************************/
2527 CASE(GOTO); // BREGG move
2529 DISPATCH();
2531 /***************************************************************************/
2532 CASE(GOTO_IF_FALSE); // BREGG move
2534 DISPATCH();
2536 /***************************************************************************/
2537 CASE(CLOSURE); // BREGG move
2539 DISPATCH();
2541 /***************************************************************************/
2542 CASE(PRIM1);
2544 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4]));
2546 switch (bytecode_lo4)
2548 case 0:
2549 arg1 = POP(); prim_numberp (); PUSH_ARG1(); break;
2550 case 1:
2551 arg2 = POP(); arg1 = POP(); prim_add (); PUSH_ARG1(); break;
2552 case 2:
2553 arg2 = POP(); arg1 = POP(); prim_sub (); PUSH_ARG1(); break;
2554 case 3:
2555 arg2 = POP(); arg1 = POP(); prim_mul (); PUSH_ARG1(); break;
2556 case 4:
2557 arg2 = POP(); arg1 = POP(); prim_div (); PUSH_ARG1(); break;
2558 case 5:
2559 arg2 = POP(); arg1 = POP(); prim_rem (); PUSH_ARG1(); break;
2560 case 6:
2561 arg1 = POP(); prim_neg (); PUSH_ARG1(); break;
2562 case 7:
2563 arg2 = POP(); arg1 = POP(); prim_eq (); PUSH_ARG1(); break;
2564 case 8:
2565 arg2 = POP(); arg1 = POP(); prim_lt (); PUSH_ARG1(); break;
2566 case 9:
2567 arg2 = POP(); arg1 = POP(); prim_ior (); PUSH_ARG1(); break;
2568 case 10:
2569 arg2 = POP(); arg1 = POP(); prim_gt (); PUSH_ARG1(); break;
2570 case 11:
2571 arg2 = POP(); arg1 = POP(); prim_xor (); PUSH_ARG1(); break;
2572 case 12:
2573 arg1 = POP(); prim_pairp (); PUSH_ARG1(); break;
2574 case 13:
2575 arg2 = POP(); arg1 = POP(); prim_cons (); PUSH_ARG1(); break;
2576 case 14:
2577 arg1 = POP(); prim_car (); PUSH_ARG1(); break;
2578 case 15:
2579 arg1 = POP(); prim_cdr (); PUSH_ARG1(); break;
2582 DISPATCH();
2584 /***************************************************************************/
2585 CASE(PRIM2);
2587 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4+16]));
2589 switch (bytecode_lo4)
2591 case 0:
2592 arg2 = POP(); arg1 = POP(); prim_set_car (); break;
2593 case 1:
2594 arg2 = POP(); arg1 = POP(); prim_set_cdr (); break;
2595 case 2:
2596 arg1 = POP(); prim_nullp (); PUSH_ARG1(); break;
2597 case 3:
2598 arg2 = POP(); arg1 = POP(); prim_eqp (); PUSH_ARG1(); break;
2599 case 4:
2600 arg1 = POP(); prim_not (); PUSH_ARG1(); break;
2601 case 5:
2602 /* prim #%get-cont */
2603 arg1 = cont;
2604 PUSH_ARG1();
2605 break;
2606 case 6:
2607 /* prim #%graft-to-cont */
2609 arg1 = POP(); /* thunk to call */
2610 cont = POP(); /* continuation */
2612 PUSH_ARG1();
2614 na = 0;
2616 pop_procedure ();
2617 handle_arity_and_rest_param ();
2618 build_env ();
2620 env = arg1;
2621 pc = entry;
2623 arg1 = OBJ_FALSE;
2625 break;
2626 case 7:
2627 /* prim #%return-to-cont */
2629 arg1 = POP(); /* value to return */
2630 cont = POP(); /* continuation */
2632 arg2 = ram_get_cdr (cont);
2634 pc = ram_get_entry (arg2);
2636 env = ram_get_cdr (arg2);
2637 cont = ram_get_car (cont);
2639 PUSH_ARG1();
2640 arg2 = OBJ_FALSE;
2642 break;
2643 case 8:
2644 /* prim #%halt */
2645 return;
2646 case 9:
2647 /* prim #%symbol? */
2648 arg1 = POP(); prim_symbolp (); PUSH_ARG1(); break;
2649 case 10:
2650 /* prim #%string? */
2651 arg1 = POP(); prim_stringp (); PUSH_ARG1(); break;
2652 case 11:
2653 /* prim #%string->list */
2654 arg1 = POP(); prim_string2list (); PUSH_ARG1(); break;
2655 case 12:
2656 /* prim #%list->string */
2657 arg1 = POP(); prim_list2string (); PUSH_ARG1(); break;
2658 case 13:
2659 /* prim #%make-u8vector */
2660 arg1 = POP(); prim_make_u8vector (); PUSH_ARG1(); break;
2661 case 14:
2662 /* prim #%u8vector-ref */
2663 arg2 = POP(); arg1 = POP(); prim_u8vector_ref (); PUSH_ARG1(); break;
2664 case 15:
2665 /* prim #%u8vector-set! */
2666 arg3 = POP(); arg2 = POP(); arg1 = POP(); prim_u8vector_set (); break;
2669 DISPATCH();
2671 /***************************************************************************/
2672 CASE(PRIM3);
2674 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4+32]));
2676 switch (bytecode_lo4)
2678 case 0:
2679 /* prim #%print */
2680 arg1 = POP();
2681 prim_print ();
2682 break;
2683 case 1:
2684 /* prim #%clock */
2685 prim_clock (); PUSH_ARG1(); break;
2686 case 2:
2687 /* prim #%motor */
2688 arg2 = POP(); arg1 = POP(); prim_motor (); break;
2689 case 3:
2690 /* prim #%led */
2691 arg3 = POP(); arg2 = POP(); arg1 = POP(); prim_led (); ;break;
2692 case 4:
2693 /* prim #%led2-color */
2694 arg1 = POP(); prim_led2_color (); break;
2695 case 5:
2696 /* prim #%getchar-wait */
2697 arg2 = POP(); arg1 = POP(); prim_getchar_wait (); PUSH_ARG1(); break;
2698 case 6:
2699 /* prim #%putchar */
2700 arg2 = POP(); arg1 = POP(); prim_putchar (); break;
2701 case 7:
2702 /* prim #%beep */
2703 arg2 = POP(); arg1 = POP(); prim_beep (); break;
2704 case 8:
2705 /* prim #%adc */
2706 arg1 = POP(); prim_adc (); PUSH_ARG1(); break;
2707 case 9:
2708 /* prim #%u8vector? */
2709 arg1 = POP(); prim_u8vectorp (); PUSH_ARG1(); break;
2710 case 10:
2711 /* prim #%sernum */
2712 prim_sernum (); PUSH_ARG1(); break;
2713 case 11:
2714 /* prim #%u8vector-length */
2715 arg1 = POP(); prim_u8vector_length (); PUSH_ARG1(); break;
2716 case 12:
2717 // FREE find something to do with this
2718 break;
2719 case 13:
2720 /* shift */
2721 arg1 = POP();
2722 POP();
2723 PUSH_ARG1();
2724 break;
2725 case 14:
2726 /* pop */
2727 POP();
2728 break;
2729 case 15:
2730 /* return */
2731 arg1 = POP();
2732 arg2 = ram_get_cdr (cont);
2733 pc = ram_get_entry (arg2);
2734 env = ram_get_cdr (arg2);
2735 cont = ram_get_car (cont);
2736 PUSH_ARG1();
2737 arg2 = OBJ_FALSE;
2738 break;
2741 DISPATCH();
2743 /***************************************************************************/
2745 END_DISPATCH();
2748 /*---------------------------------------------------------------------------*/
2750 #ifdef WORKSTATION
2752 void usage (void)
2754 printf ("usage: sim file.hex\n");
2755 exit (1);
2758 int main (int argc, char *argv[])
2760 int errcode = 1;
2761 rom_addr rom_start_addr = 0;
2763 if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 's')
2765 int h1;
2766 int h2;
2767 int h3;
2768 int h4;
2770 if ((h1 = hex (argv[1][2])) < 0 ||
2771 (h2 = hex (argv[1][3])) < 0 ||
2772 (h3 = hex (argv[1][4])) != 0 ||
2773 (h4 = hex (argv[1][5])) != 0 ||
2774 argv[1][6] != '\0')
2775 usage ();
2777 rom_start_addr = (h1 << 12) | (h2 << 8) | (h3 << 4) | h4;
2779 argv++;
2780 argc--;
2783 #ifdef DEBUG
2784 printf ("Start address = 0x%04x\n", rom_start_addr); // TODO says 0, but should be CODE_START ?
2785 #endif
2787 if (argc != 2)
2788 usage ();
2790 if (!read_hex_file (argv[1]))
2791 printf ("*** Could not read hex file \"%s\"\n", argv[1]);
2792 else
2794 int i;
2796 if (rom_get (CODE_START+0) != 0xfb ||
2797 rom_get (CODE_START+1) != 0xd7)
2798 printf ("*** The hex file was not compiled with PICOBIT\n");
2799 else
2801 #if 0
2802 for (i=0; i<8192; i++) // TODO remove this ? and not the night address space, now 16 bits
2803 if (rom_get (i) != 0xff)
2804 printf ("rom_mem[0x%04x] = 0x%02x\n", i, rom_get (i));
2805 #endif
2807 interpreter ();
2809 #ifdef DEBUG_GC
2810 printf ("**************** memory needed = %d\n", max_live+1);
2811 #endif
2815 return errcode;
2818 #endif
2820 /*---------------------------------------------------------------------------*/