A couple of fixes for numerical operations without bignums.
[picobit.git] / picobit-vm.c
blobd7ba1f502ec7849f89c2d5232c2977af2e9a6429
1 /* file: "picobit-vm.c" */
3 /*
4 * Copyright 2004-2009 by Marc Feeley and Vincent St-Amour, All Rights Reserved.
6 * History:
8 * 15/08/2004 Release of version 1
9 * 06/07/2008 Modified for PICOBOARD2_R3
10 * 18/07/2008 Modified to use new object representation
11 * 17/12/2008 Release of version 2
14 #include "picobit-vm.h"
16 /*---------------------------------------------------------------------------*/
18 // error handling
20 #ifdef WORKSTATION
21 void error (char *prim, char *msg) {
22 printf ("ERROR: %s: %s\n", prim, msg);
23 exit (1);
26 void type_error (char *prim, char *type) {
27 printf ("ERROR: %s: An argument of type %s was expected\n", prim, type);
28 exit (1);
30 #endif
32 #ifdef SIXPIC
33 void halt_with_error () {
34 uart_write(101); // e
35 uart_write(114); // r
36 uart_write(114); // r
37 uart_write(13);
38 uart_write(10);
39 exit();
41 #endif
43 /*---------------------------------------------------------------------------*/
45 // memory access
47 word ram_get_fieldn (obj o, word n) {
48 switch (n) {
49 case 0: return ram_get_field0 (o);
50 case 1: return ram_get_field1 (o);
51 case 2: return ram_get_field2 (o);
52 case 3: return ram_get_field3 (o);
55 void ram_set_fieldn (obj o, uint8 n, word val) { // TODO have as a macro ?
56 switch (n) {
57 case 0: ram_set_field0 (o, val); break;
58 case 1: ram_set_field1 (o, val); break;
59 case 2: ram_set_field2 (o, val); break;
60 case 3: ram_set_field3 (o, val); break;
64 // these temporary variables are necessary with SIXPIC, or else the shift
65 // results will be 8 bits values, which is wrong
66 obj ram_get_car (obj o) {
67 uint16 tmp = ram_get_field0 (o) & 0x1f;
68 return (tmp << 8) | ram_get_field1 (o);
70 obj rom_get_car (obj o) {
71 uint16 tmp = rom_get_field0 (o) & 0x1f;
72 return (tmp << 8) | rom_get_field1 (o);
74 obj ram_get_cdr (obj o) {
75 uint16 tmp = ram_get_field2 (o) & 0x1f;
76 return (tmp << 8) | ram_get_field3 (o);
78 obj rom_get_cdr (obj o) {
79 uint16 tmp = rom_get_field2 (o) & 0x1f;
80 return (tmp << 8) | rom_get_field3 (o);
83 void ram_set_car (obj o, obj val) {
84 ram_set_field0 (o, (val >> 8) | (ram_get_field0 (o) & 0xe0));
85 ram_set_field1 (o, val & 0xff);
87 void ram_set_cdr (obj o, obj val) {
88 ram_set_field2 (o, (val >> 8) | (ram_get_field2 (o) & 0xe0));
89 ram_set_field3 (o, val & 0xff);
92 // function entry point
93 // the temporary variables are necessary with SIXPIC, see above
94 obj ram_get_entry (obj o) {
95 uint16 tmp = ram_get_field0 (o) & 0x1f;
96 uint16 tmp2 = ram_get_field1 (o);
97 return ((tmp << 11) | (tmp2 << 3) | (ram_get_field2 (o) >> 5));
99 obj rom_get_entry (obj o){
100 uint16 tmp = rom_get_field0 (o) & 0x1f;
101 uint16 tmp2 = rom_get_field1 (o);
102 return ((tmp << 11) | (tmp2 << 3) | (rom_get_field2 (o) >> 5));
105 obj get_global (uint8 i) {
106 // globals occupy the beginning of ram, with 2 globals per word
107 if (i & 1)
108 return ram_get_cdr (MIN_RAM_ENCODING + (i >> 1));
109 else
110 return ram_get_car (MIN_RAM_ENCODING + (i >> 1));
112 void set_global (uint8 i, obj o) {
113 if (i & 1)
114 ram_set_cdr (MIN_RAM_ENCODING + (i >> 1), o);
115 else
116 ram_set_car (MIN_RAM_ENCODING + (i >> 1), o);
119 // TODO generic functions (get_field0, get_car, etc) that work for both rom and ram were not used, are in garbage
121 /*---------------------------------------------------------------------------*/
123 #ifdef WORKSTATION
125 int hidden_fgetc (FILE *f)
127 int c = fgetc (f);
128 #if 0
129 printf ("{%d}",c);
130 fflush (stdout);
131 #endif
132 return c;
135 #define fgetc(f) hidden_fgetc(f)
137 void write_hex_nibble (int n)
139 putchar ("0123456789ABCDEF"[n]);
142 void write_hex (uint8 n)
144 write_hex_nibble (n >> 4);
145 write_hex_nibble (n & 0x0f);
148 int hex (int c)
150 if (c >= '0' && c <= '9')
151 return (c - '0');
153 if (c >= 'A' && c <= 'F')
154 return (c - 'A' + 10);
156 if (c >= 'a' && c <= 'f')
157 return (c - 'a' + 10);
159 return -1;
162 int read_hex_byte (FILE *f)
164 int h1 = hex (fgetc (f));
165 int h2 = hex (fgetc (f));
167 if (h1 >= 0 && h2 >= 0)
168 return (h1<<4) + h2;
170 return -1;
173 int read_hex_file (char *filename)
175 int c;
176 FILE *f = fopen (filename, "r");
177 int result = 0;
178 int len;
179 int a, a1, a2;
180 int t;
181 int b;
182 int i;
183 uint8 sum;
184 int hi16 = 0;
186 for (i=0; i<ROM_BYTES; i++)
187 rom_mem[i] = 0xff;
189 if (f != NULL)
191 while ((c = fgetc (f)) != EOF)
193 if ((c == '\r') || (c == '\n'))
194 continue;
196 if (c != ':' ||
197 (len = read_hex_byte (f)) < 0 ||
198 (a1 = read_hex_byte (f)) < 0 ||
199 (a2 = read_hex_byte (f)) < 0 ||
200 (t = read_hex_byte (f)) < 0)
201 break;
203 a = (a1 << 8) + a2;
205 i = 0;
206 sum = len + a1 + a2 + t;
208 if (t == 0)
210 next0:
212 if (i < len)
214 unsigned long adr = ((unsigned long)hi16 << 16) + a - CODE_START;
216 if ((b = read_hex_byte (f)) < 0)
217 break;
219 if (adr >= 0 && adr < ROM_BYTES)
220 rom_mem[adr] = b;
222 a = (a + 1) & 0xffff;
223 i++;
224 sum += b;
226 goto next0;
229 else if (t == 1)
231 if (len != 0)
232 break;
234 else if (t == 4)
236 if (len != 2)
237 break;
239 if ((a1 = read_hex_byte (f)) < 0 ||
240 (a2 = read_hex_byte (f)) < 0)
241 break;
243 sum += a1 + a2;
245 hi16 = (a1<<8) + a2;
247 else
248 break;
250 if ((b = read_hex_byte (f)) < 0)
251 break;
253 sum = -sum;
255 if (sum != b)
257 printf ("*** HEX file checksum error (expected 0x%02x)\n", sum);
258 break;
261 c = fgetc (f);
263 if ((c != '\r') && (c != '\n'))
264 break;
266 if (t == 1)
268 result = 1;
269 break;
273 if (result == 0)
274 printf ("*** HEX file syntax error\n");
276 fclose (f);
279 return result;
282 #endif
284 /*---------------------------------------------------------------------------*/
286 /* #ifdef ROBOT */
287 // TODO since picobit-vm.h can now contain code (with LESS_MACROS), including
288 // the header in each results in multiple definitions of these functions.
289 // no separate compilation
290 #include "debug.c"
291 #include "gc.c"
292 #include "bignums.c"
293 #include "primitives.c"
294 #include "dispatch.c"
295 /* #endif */
297 /*---------------------------------------------------------------------------*/
299 #ifdef WORKSTATION
301 void usage ()
303 printf ("usage: sim file.hex\n");
304 exit (1);
307 int main (int argc, char *argv[])
309 int errcode = 0;
310 rom_addr rom_start_addr = 0;
312 #ifdef TEST_BIGNUM
313 test();
314 #endif
316 if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 's')
318 int h1;
319 int h2;
320 int h3;
321 int h4;
323 if ((h1 = hex (argv[1][2])) < 0 ||
324 (h2 = hex (argv[1][3])) < 0 ||
325 (h3 = hex (argv[1][4])) != 0 ||
326 (h4 = hex (argv[1][5])) != 0 ||
327 argv[1][6] != '\0')
328 usage ();
330 rom_start_addr = (h1 << 12) | (h2 << 8) | (h3 << 4) | h4;
332 argv++;
333 argc--;
336 #ifdef DEBUG
337 printf ("Start address = 0x%04x\n", rom_start_addr + CODE_START);
338 #endif
340 if (argc != 2)
341 usage ();
343 if (!read_hex_file (argv[1]))
344 printf ("*** Could not read hex file \"%s\"\n", argv[1]);
345 else
347 int i;
349 if (rom_get (CODE_START+0) != 0xfb ||
350 rom_get (CODE_START+1) != 0xd7)
351 printf ("*** The hex file was not compiled with PICOBIT\n");
352 else
354 #if 0
355 for (i=0; i<8192; i++)
356 if (rom_get (i) != 0xff)
357 printf ("rom_mem[0x%04x] = 0x%02x\n", i, rom_get (i));
358 #endif
360 interpreter ();
362 #ifdef DEBUG_GC
363 printf ("**************** memory needed = %d\n", max_live+1);
364 #endif
368 return errcode;
371 #endif
373 #ifdef SIXPIC
374 interpreter();
375 #endif
377 #ifdef HI_TECH_C
378 void main () {
379 interpreter();
381 #endif