Removed code that dealt with ROM closure, since these don't exist.
[picobit.git] / dispatch.c
blob23d325c43bbfa76f72f6a5502469db9d8c03378c
1 /* file: "dispatch.c" */
3 /*
4 * Copyright 2004-2009 by Marc Feeley and Vincent St-Amour, All Rights Reserved.
5 */
7 #include "picobit-vm.h"
9 void push_arg1 () {
10 env = cons (arg1, env);
11 arg1 = OBJ_FALSE;
14 obj pop () {
15 obj o = ram_get_car (env);
16 env = ram_get_cdr (env);
17 return o;
20 void pop_procedure () {
21 arg1 = pop();
23 if (IN_RAM(arg1)) {
24 if (!RAM_CLOSURE(arg1))
25 TYPE_ERROR("pop_procedure.0", "procedure");
27 entry = ram_get_entry (arg1) + CODE_START;
29 else
30 TYPE_ERROR("pop_procedure.1", "procedure");
33 uint8 handle_arity_and_rest_param (uint8 na) {
34 uint8 np;
36 np = rom_get (entry++);
38 if (arg1 != OBJ_NULL)
39 arg1 = ram_get_car(arg1); // closed environment
41 if ((np & 0x80) == 0) {
42 if (na != np)
43 ERROR("handle_arity_and_rest_param.0", "wrong number of arguments");
45 else {
46 np = ~np;
48 if (na < np)
49 ERROR("handle_arity_and_rest_param.1", "wrong number of arguments");
51 arg3 = OBJ_NULL;
53 while (na > np) {
54 arg4 = pop();
56 arg3 = cons (arg4, arg3);
57 arg4 = OBJ_FALSE;
59 na--;
62 arg1 = cons (arg3, arg1);
63 arg3 = OBJ_FALSE;
66 return na;
69 uint8 build_env (uint8 na) {
70 while (na != 0) {
71 arg3 = pop();
73 arg1 = cons (arg3, arg1);
75 na--;
78 arg3 = OBJ_FALSE;
81 void save_cont () {
82 // the second half is a closure
83 arg3 = alloc_ram_cell_init (CLOSURE_FIELD0 | (env >> 8),
84 env & 0xff,
85 (pc >> 8),
86 (pc & 0xff));
87 cont = alloc_ram_cell_init (COMPOSITE_FIELD0 | (cont >> 8),
88 cont & 0xff,
89 CONTINUATION_FIELD2 | (arg3 >> 8),
90 arg3 & 0xff);
91 arg3 = OBJ_FALSE;
94 void interpreter () {
95 pc = rom_get (CODE_START+2);
96 pc = (CODE_START + 4) + (pc << 2);
98 glovars = rom_get (CODE_START+3); // number of global variables
100 init_ram_heap ();
102 dispatch:
103 IF_TRACE(show_state (pc));
104 FETCH_NEXT_BYTECODE();
105 bytecode_hi4 = bytecode & 0xf0;
106 bytecode_lo4 = bytecode & 0x0f;
108 switch (bytecode_hi4 >> 4) {
110 /*************************************************************************/
111 case PUSH_CONSTANT1 :
113 IF_TRACE(printf(" (push-constant "); show (bytecode_lo4); printf (")\n"));
115 arg1 = bytecode_lo4;
117 push_arg1();
119 goto dispatch;
121 /*************************************************************************/
122 case PUSH_CONSTANT2 :
124 IF_TRACE(printf(" (push-constant "); show (bytecode_lo4+16); printf (")\n"));
125 arg1 = bytecode_lo4+16;
127 push_arg1();
129 goto dispatch;
131 /*************************************************************************/
132 case PUSH_STACK1 :
134 IF_TRACE(printf(" (push-stack %d)\n", bytecode_lo4));
136 arg1 = env;
138 while (bytecode_lo4 != 0) {
139 arg1 = ram_get_cdr (arg1);
140 bytecode_lo4--;
143 arg1 = ram_get_car (arg1);
145 push_arg1();
147 goto dispatch;
149 /*************************************************************************/
150 case PUSH_STACK2 :
152 IF_TRACE(printf(" (push-stack %d)\n", bytecode_lo4+16));
154 bytecode_lo4 += 16;
156 arg1 = env;
158 while (bytecode_lo4 != 0) {
159 arg1 = ram_get_cdr (arg1);
160 bytecode_lo4--;
163 arg1 = ram_get_car (arg1);
165 push_arg1();
167 goto dispatch;
169 /*************************************************************************/
170 case PUSH_GLOBAL :
172 IF_TRACE(printf(" (push-global %d)\n", bytecode_lo4));
174 arg1 = get_global (bytecode_lo4);
176 push_arg1();
178 goto dispatch;
180 /*************************************************************************/
181 case SET_GLOBAL :
183 IF_TRACE(printf(" (set-global %d)\n", bytecode_lo4));
185 set_global (bytecode_lo4, pop());
187 goto dispatch;
189 /*************************************************************************/
190 case CALL :
192 IF_TRACE(printf(" (call %d)\n", bytecode_lo4));
194 pop_procedure ();
195 build_env (handle_arity_and_rest_param (bytecode_lo4));
196 save_cont ();
198 env = arg1;
199 pc = entry;
201 arg1 = OBJ_FALSE;
203 goto dispatch;
205 /*************************************************************************/
206 case JUMP :
208 IF_TRACE(printf(" (jump %d)\n", bytecode_lo4));
210 pop_procedure ();
211 build_env (handle_arity_and_rest_param (bytecode_lo4));
213 env = arg1;
214 pc = entry;
216 arg1 = OBJ_FALSE;
218 goto dispatch;
220 /*************************************************************************/
221 case LABEL_INSTR :
223 switch (bytecode_lo4) {
224 case 0: // call-toplevel
225 FETCH_NEXT_BYTECODE();
226 arg2 = bytecode;
228 FETCH_NEXT_BYTECODE();
230 IF_TRACE(printf(" (call-toplevel 0x%04x)\n",
231 ((arg2 << 8) | bytecode) + CODE_START));
233 entry = (arg2 << 8) + bytecode + CODE_START;
234 arg1 = OBJ_NULL;
236 build_env (rom_get (entry++));
237 save_cont ();
239 env = arg1;
240 pc = entry;
242 arg1 = OBJ_FALSE;
243 arg2 = OBJ_FALSE;
245 break;
247 case 1: // jump-toplevel
248 FETCH_NEXT_BYTECODE();
249 arg2 = bytecode;
251 FETCH_NEXT_BYTECODE();
253 IF_TRACE(printf(" (jump-toplevel 0x%04x)\n",
254 ((arg2 << 8) | bytecode) + CODE_START));
256 entry = (arg2 << 8) + bytecode + CODE_START;
257 arg1 = OBJ_NULL;
259 build_env (rom_get (entry++));
261 env = arg1;
262 pc = entry;
264 arg1 = OBJ_FALSE;
265 arg2 = OBJ_FALSE;
267 break;
269 case 2: // goto
270 FETCH_NEXT_BYTECODE();
271 arg2 = bytecode;
273 FETCH_NEXT_BYTECODE();
275 IF_TRACE(printf(" (goto 0x%04x)\n",
276 (arg2 << 8) + bytecode + CODE_START));
278 pc = (arg2 << 8) + bytecode + CODE_START;
280 break;
282 case 3: // goto-if-false
283 FETCH_NEXT_BYTECODE();
284 arg2 = bytecode;
286 FETCH_NEXT_BYTECODE();
288 IF_TRACE(printf(" (goto-if-false 0x%04x)\n",
289 (arg2 << 8) + bytecode + CODE_START));
291 if (pop() == OBJ_FALSE)
292 pc = (arg2 << 8) + bytecode + CODE_START;
294 break;
296 case 4: // closure
297 FETCH_NEXT_BYTECODE();
298 arg2 = bytecode;
300 FETCH_NEXT_BYTECODE();
302 entry = (arg2 << 8) | bytecode;
304 IF_TRACE(printf(" (closure 0x%04x)\n", entry));
306 arg3 = pop(); // env
308 arg1 = alloc_ram_cell_init (CLOSURE_FIELD0 | (arg3 >> 8),
309 arg3 & 0xff,
310 entry >> 8,
311 (entry & 0xff));
313 push_arg1();
315 arg2 = OBJ_FALSE;
316 arg3 = OBJ_FALSE;
318 break;
320 #if 1
321 case 5: // call-toplevel-rel8
322 FETCH_NEXT_BYTECODE(); // TODO the short version have a lot in common with the long ones, abstract ?
324 IF_TRACE(printf(" (call-toplevel-rel8 0x%04x)\n", pc + bytecode - 128));
326 entry = pc + bytecode - 128;
327 arg1 = OBJ_NULL;
329 build_env (rom_get (entry++));
330 save_cont ();
332 env = arg1;
333 pc = entry;
335 arg1 = OBJ_FALSE;
337 break;
339 case 6: // jump-toplevel-rel8
340 FETCH_NEXT_BYTECODE();
342 IF_TRACE(printf(" (jump-toplevel-rel8 0x%04x)\n", pc + bytecode - 128));
344 entry = pc + bytecode - 128;
345 arg1 = OBJ_NULL;
347 build_env (rom_get (entry++));
349 env = arg1;
350 pc = entry;
352 arg1 = OBJ_FALSE;
354 break;
356 case 7: // goto-rel8
357 FETCH_NEXT_BYTECODE();
359 IF_TRACE(printf(" (goto-rel8 0x%04x)\n", pc + bytecode - 128));
361 pc = pc + bytecode - 128;
363 break;
365 case 8: // goto-if-false-rel8
366 FETCH_NEXT_BYTECODE();
368 IF_TRACE(printf(" (goto-if-false-rel8 0x%04x)\n", pc + bytecode - 128));
370 if (pop() == OBJ_FALSE)
371 pc = pc + bytecode - 128;
373 break;
375 // TODO why does this not work? don't worry about it now, as it is disabled in the compiler
377 case 9: // closure-rel8
378 FETCH_NEXT_BYTECODE();
380 entry = pc + bytecode - 128;
382 IF_TRACE(printf(" (closure-rel8 0x%04x)\n", entry));
384 arg3 = pop(); // env
386 arg1 = alloc_ram_cell_init (CLOSURE_FIELD0 | (entry >> 11),
387 entry >> 3,
388 ((entry & 0x07) << 5) | ((arg3 >> 8) & 0x1f),
389 arg3 & 0xff);
391 push_arg1();
393 arg3 = OBJ_FALSE;
395 break;
396 #endif
398 #if 0
399 case 10: // FREE
400 break;
401 case 11:
402 break;
403 case 12:
404 break;
405 case 13:
406 break;
407 #endif
408 case 14: // push_global [long]
409 FETCH_NEXT_BYTECODE();
411 IF_TRACE(printf(" (push-global [long] %d)\n", bytecode));
413 arg1 = get_global (bytecode);
415 push_arg1();
417 break;
419 case 15: // set_global [long]
420 FETCH_NEXT_BYTECODE();
422 IF_TRACE(printf(" (set-global [long] %d)\n", bytecode));
424 set_global (bytecode, pop());
426 break;
429 goto dispatch;
431 /*************************************************************************/
432 case PUSH_CONSTANT_LONG :
434 /* push-constant [long] */
436 FETCH_NEXT_BYTECODE();
438 IF_TRACE(printf(" (push [long] 0x%04x)\n", (bytecode_lo4 << 8) + bytecode));
440 // necessary since SIXPIC would have kept the result of the shift at 8 bits
441 arg1 = bytecode_lo4;
442 arg1 = (arg1 << 8) | bytecode;
443 push_arg1();
445 goto dispatch;
447 /*************************************************************************/
449 case JUMP_TOPLEVEL_REL4 :
451 IF_TRACE(printf(" (jump-toplevel-rel4 0x%04x)\n", pc + (bytecode & 0x0f)));
453 entry = pc + (bytecode & 0x0f);
454 arg1 = OBJ_NULL;
456 build_env (rom_get (entry++));
458 env = arg1;
459 pc = entry;
461 arg1 = OBJ_FALSE;
463 goto dispatch;
465 /*************************************************************************/
467 case GOTO_IF_FALSE_REL4 :
469 IF_TRACE(printf(" (goto-if-false-rel4 0x%04x)\n", pc + (bytecode & 0x0f)));
471 if (pop() == OBJ_FALSE)
472 pc = pc + (bytecode & 0x0f);
474 goto dispatch;
476 /*************************************************************************/
477 case PRIM1 :
479 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4]));
481 switch (bytecode_lo4) {
482 case 0:
483 arg1 = pop(); prim_numberp (); push_arg1(); break;
484 case 1:
485 arg2 = pop(); arg1 = pop(); prim_add (); push_arg1(); break;
486 case 2:
487 arg2 = pop(); arg1 = pop(); prim_sub (); push_arg1(); break;
488 case 3:
489 arg2 = pop(); arg1 = pop(); prim_mul_non_neg (); push_arg1(); break;
490 case 4:
491 arg2 = pop(); arg1 = pop(); prim_div_non_neg (); push_arg1(); break;
492 case 5:
493 arg2 = pop(); arg1 = pop(); prim_rem (); push_arg1(); break;
494 #if 0
495 case 6: // FREE
496 break;
497 #endif
498 case 7:
499 arg2 = pop(); arg1 = pop(); prim_eq (); push_arg1(); break;
500 case 8:
501 arg2 = pop(); arg1 = pop(); prim_lt (); push_arg1(); break;
502 #if 0
503 case 9:
504 break; // FREE
505 #endif
506 case 10:
507 arg2 = pop(); arg1 = pop(); prim_gt (); push_arg1(); break;
508 #if 0
509 case 11:
510 break; // FREE
511 #endif
512 case 12:
513 arg1 = pop(); prim_pairp (); push_arg1(); break;
514 case 13:
515 arg2 = pop(); arg1 = pop(); prim_cons (); push_arg1(); break;
516 case 14:
517 arg1 = pop(); prim_car (); push_arg1(); break;
518 case 15:
519 arg1 = pop(); prim_cdr (); push_arg1(); break;
522 goto dispatch;
524 /*************************************************************************/
525 case PRIM2 :
527 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4+16]));
529 switch (bytecode_lo4) {
530 case 0:
531 arg2 = pop(); arg1 = pop(); prim_set_car (); break;
532 case 1:
533 arg2 = pop(); arg1 = pop(); prim_set_cdr (); break;
534 case 2:
535 arg1 = pop(); prim_nullp (); push_arg1(); break;
536 case 3:
537 arg2 = pop(); arg1 = pop(); prim_eqp (); push_arg1(); break;
538 case 4:
539 arg1 = pop(); prim_not (); push_arg1(); break;
540 case 5:
541 /* prim #%get-cont */
542 arg1 = cont;
543 push_arg1();
544 break;
545 case 6:
546 /* prim #%graft-to-cont */
548 arg1 = pop(); /* thunk to call */
549 cont = pop(); /* continuation */
551 push_arg1();
553 pop_procedure ();
554 build_env (handle_arity_and_rest_param (0));
556 env = arg1;
557 pc = entry;
559 arg1 = OBJ_FALSE;
561 break;
562 case 7:
563 /* prim #%return-to-cont */
565 arg1 = pop(); /* value to return */
566 cont = pop(); /* continuation */
568 arg2 = ram_get_cdr (cont);
570 pc = ram_get_entry (arg2);
572 env = ram_get_car (arg2);
573 cont = ram_get_car (cont);
575 push_arg1();
576 arg2 = OBJ_FALSE;
578 break;
579 case 8:
580 /* prim #%halt */
581 return;
582 case 9:
583 /* prim #%symbol? */
584 arg1 = pop(); prim_symbolp (); push_arg1(); break;
585 case 10:
586 /* prim #%string? */
587 arg1 = pop(); prim_stringp (); push_arg1(); break;
588 case 11:
589 /* prim #%string->list */
590 arg1 = pop(); prim_string2list (); push_arg1(); break;
591 case 12:
592 /* prim #%list->string */
593 arg1 = pop(); prim_list2string (); push_arg1(); break;
594 case 13:
595 /* prim #%make-u8vector */
596 // not exactly like the standard Scheme function.
597 // only takes one argument, and does not fill the vector
598 arg1 = pop(); prim_make_u8vector (); push_arg1(); break;
599 case 14:
600 /* prim #%u8vector-ref */
601 arg2 = pop(); arg1 = pop(); prim_u8vector_ref (); push_arg1(); break;
602 case 15:
603 /* prim #%u8vector-set! */
604 arg3 = pop(); arg2 = pop(); arg1 = pop(); prim_u8vector_set (); break;
607 goto dispatch;
609 /*************************************************************************/
610 case PRIM3 :
612 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4+32]));
614 switch (bytecode_lo4) {
615 case 0:
616 /* prim #%print */
617 arg1 = pop();
618 prim_print ();
619 break;
620 case 1:
621 /* prim #%clock */
622 prim_clock (); push_arg1(); break;
623 case 2:
624 /* prim #%motor */
625 arg2 = pop(); arg1 = pop(); prim_motor (); break;
626 case 3:
627 /* prim #%led */
628 arg3 = pop(); arg2 = pop(); arg1 = pop(); prim_led (); ;break;
629 case 4:
630 /* prim #%led2-color */
631 arg1 = pop(); prim_led2_color (); break;
632 case 5:
633 /* prim #%getchar-wait */
634 arg2 = pop(); arg1 = pop(); prim_getchar_wait (); push_arg1(); break;
635 case 6:
636 /* prim #%putchar */
637 arg2 = pop(); arg1 = pop(); prim_putchar (); break;
638 case 7:
639 /* prim #%beep */
640 arg2 = pop(); arg1 = pop(); prim_beep (); break;
641 case 8:
642 /* prim #%adc */
643 arg1 = pop(); prim_adc (); push_arg1(); break;
644 case 9:
645 /* prim #%u8vector? */
646 arg1 = pop(); prim_u8vectorp (); push_arg1(); break;
647 case 10:
648 /* prim #%sernum */
649 prim_sernum (); push_arg1(); break;
650 case 11:
651 /* prim #%u8vector-length */
652 arg1 = pop(); prim_u8vector_length (); push_arg1(); break;
653 case 12:
654 // FREE
655 break;
656 case 13:
657 /* shift */
658 arg1 = pop();
659 pop();
660 push_arg1();
661 break;
662 case 14:
663 /* pop */
664 pop();
665 break;
666 case 15:
667 /* return */
668 arg1 = pop();
669 arg2 = ram_get_cdr (cont);
670 pc = ram_get_entry (arg2);
671 env = ram_get_car (arg2);
672 cont = ram_get_car (cont);
673 push_arg1();
674 arg2 = OBJ_FALSE;
675 break;
678 goto dispatch;
680 /*************************************************************************/
682 case PRIM4 :
684 IF_TRACE(printf(" (%s)\n", prim_name[bytecode_lo4]));
686 switch (bytecode_lo4) {
687 case 0:
688 /* prim #%boolean? */
689 arg1 = pop(); prim_booleanp (); push_arg1(); break;
690 #ifdef NETWORKING
691 case 1:
692 /* prim #%network-init */
693 prim_network_init (); break;
694 case 2:
695 /* prim #%network-cleanup */
696 prim_network_cleanup (); break;
697 case 3:
698 /* prim #%receive-packet-to-u8vector */
699 arg1 = pop(); prim_receive_packet_to_u8vector (); push_arg1(); break;
700 case 4:
701 /* prim #%send-packet-from-u8vector */
702 arg2 = pop(); arg1 = pop(); prim_send_packet_from_u8vector ();
703 push_arg1(); break;
704 #endif
705 case 5:
706 arg2 = pop(); arg1 = pop(); prim_ior (); push_arg1(); break;
707 break;
708 case 6:
709 arg2 = pop(); arg1 = pop(); prim_xor (); push_arg1(); break;
710 break;
711 #if 0
712 case 7: // FREE
713 break;
714 case 8:
715 break;
716 case 9:
717 break;
718 case 10:
719 break;
720 case 11:
721 break;
722 case 12:
723 break;
724 case 13:
725 break;
726 case 14:
727 break;
728 case 15:
729 break;
730 #endif
733 goto dispatch;
735 /*************************************************************************/