struct pic_lib * pic_open_library(pic_state *pic, pic_value name) { struct pic_lib *lib; struct pic_senv *senv; struct pic_dict *exports; if ((lib = pic_find_library(pic, name)) != NULL) { #if DEBUG printf("* reopen library: "); pic_debug(pic, name); puts(""); #endif return lib; } senv = pic_null_syntactic_environment(pic); exports = pic_make_dict(pic); lib = (struct pic_lib *)pic_obj_alloc(pic, sizeof(struct pic_lib), PIC_TT_LIB); lib->name = name; lib->env = senv; lib->exports = exports; /* register! */ pic->libs = pic_acons(pic, name, pic_obj_value(lib), pic->libs); return lib; }
/* * Open device and perform command */ int main(int argc, char **argv) { char *execdup, *execname; int rc = EX_OK; /* Get exec name */ execdup = (char *)strdup(argv[0]); if (execdup == NULL) { printf("%s: fatal error: strdup failed\n", __func__); io_exit(EX_OSERR); /* Panic */ } execname = basename(execdup); if (execname == NULL) { printf("%s: fatal error: basename failed\n", __func__); io_exit(EX_OSERR); /* Panic */ } /* Get configuration */ getconf(); /* Open device */ if (io_open() < 0) { usage(execname, io_error()); } /* Raise priority */ setpriority(PRIO_PROCESS, 0, -20); /* Reset uid */ if (getuid() != geteuid()) { if (setuid(getuid()) < 0) { printf("%s: fatal error: setuid failed\n", __func__); io_exit(EX_OSERR); /* Panic */ } } /* Determine arch: 12 | 14 | 16 | 24 | 32 */ if (pic_arch(execname) == 0) usage_pickle(); /* Perform operation */ if (argc < 2) usage(execname, "Missing arg(s)"); /* Device selection */ int argv1 = tolower((int)argv[1][0]); if (argv1 == 's') { /* Select device */ if (argc < 3) { pic_selector(); io_exit(EX_OK); } if (mystrcasestr(argv[2], "dspic") == argv[2]) { strncpy(p.devicename, argv[2], STRLEN); } else if (mystrcasestr(argv[2], "pic") == argv[2]) { strncpy(p.devicename, argv[2], STRLEN); } else { int32_t temp = strtol(argv[2], NULL, 0); if (temp < 10 || temp > 33) { usage(execname, "Invalid arg [select]"); } if (temp == 30 || temp == 33) { strcpy(p.devicename, "dspic"); strncpy(&p.devicename[5], argv[2], STRLEN - 5); } else { strcpy(p.devicename, "pic"); strncpy(&p.devicename[3], argv[2], STRLEN - 3); } } argc -= 2; argv += 2; if (argc < 2) usage(execname, "Missing arg(s)"); } else if (p.pic->arch == ARCH12BIT) { usage(execname, "Missing select"); } /* Key entry */ argv1 = tolower((int)argv[1][0]); if (argv1 == 'l') { /* LVP 32-bit key entry */ if (p.pic->arch == ARCH12BIT) { usage(execname, "Invalid arg [lvp]"); } /* ARCH14BIT || ARCH16BIT || ARCH24BIT || ARCH32BIT */ p.key = LVPKEY; argc -= 1; argv += 1; if (argc < 2) usage(execname, "Missing arg(s)"); } else if (argv1 == 'h') { /* HVP 32-bit key entry */ if (p.pic->arch == ARCH12BIT || p.pic->arch == ARCH14BIT || p.pic->arch == ARCH32BIT) { usage(execname, "Invalid arg [hvp]"); } /* ARCH16BIT || ARCH24BIT */ p.key = HVPKEY; argc -= 1; argv += 1; if (argc < 2) usage(execname, "Missing arg(s)"); } else if (p.pic->arch == ARCH32BIT) { /* LVP 32-bit key entry */ /* ARCH32BIT */ p.key = LVPKEY; } else { /* No key entry */ /* ARCH12BIT || ARCH14BIT || ARCH16BIT || ARCH24BIT */ p.key = NOKEY; } /* Command */ argv1 = tolower((int)argv[1][0]); int argv11 = tolower((int)argv[1][1]); switch (argv1) { case 'b': if (argv11 == 'o') { /* BOOT */ uint32_t addr = UINT32_MAX, words = UINT32_MAX; if (argc > 4) usage(execname, "Too many args [boot]"); if (argc >= 3) { words = strtoul(argv[2], NULL, 0); if (words == 0) usage(execname, "Invalid arg [boot]"); } if (argc == 4) { addr = strtoul(argv[3], NULL, 0); } pic_dumpboot(addr, words); } else { /* BLANK */ int config = 1; if (argc > 3) usage(execname, "Too many args [blank]"); if (argc == 3) switch (argv[2][0]) { case 'n': case 'N': case '0': config = 0; break; case 'y': case 'Y': case '1': config = 1; break; default:usage(execname, "invalid arg [blank]"); break; } if (areyousure("Blank device")) { pic_blank(config); } } break; case 'c': if (argc > 3) usage(execname, "Too many args [config]"); if (argc == 2) pic_dumpconfig(); else pic_writebandgap(strtoul(argv[2], NULL, 0)); break; case 'd': if (argv11 == 'a') { /* DATA */ if (argc > 2) usage(execname, "Too many args [data]"); pic_dumpdata(); } else if (argv11 == 'e') { /* DEBUG */ pic_debug(); } else { /* DUMP */ if (argc > 2) usage(execname, "Too many args [dump]"); pic_dumpdevice(); } break; case 'e': if (argv11 == 'r') { /* ERASE FLASH | ID | ROW[NROWS] */ uint32_t row = 0, nrows = 1; char prompt[STRLEN] = {0}, *endptr = NULL; if (argc < 3) usage(execname, "Missing arg [erase]"); if (argc > 4) usage(execname, "Too many args [erase]"); int argv2 = tolower((int)argv[2][0]); switch (argv2) { case 'i': /* IDLOCATION */ case 'u': /* USERID/CONFIG */ row = PIC_ERASE_ID; strncpy(prompt, "Erase id", STRLEN); break; case 'c': /* CONFIG */ row = PIC_ERASE_CONFIG; strncpy(prompt, "Erase config", STRLEN); break; case 'e': /* EEPROM */ row = PIC_ERASE_EEPROM; strncpy(prompt, "Erase EEPROM", STRLEN); break; case 'f': /* FLASH */ nrows = UINT32_MAX; strncpy(prompt, "Erase program flash", STRLEN); break; default: /* FLASH ROW */ row = strtoul(argv[2], &endptr, 0); if (endptr == argv[2]) usage(execname, "Invalid arg [erase]"); if (argc == 4) { nrows = strtoul(argv[3], NULL, 0); if (nrows == 0) usage(execname, "Invalid arg [erase]"); } snprintf(prompt, STRLEN, "Erase %u row(s) at row %u", nrows, row); break; } if (areyousure(prompt)) pic_erase(row, nrows); } else if (argv11 == 'x') { /* EXECUTIVE */ uint32_t addr = UINT32_MAX, words = UINT32_MAX; if (argc > 4) usage(execname, "Too many args [executive]"); if (argc >= 3) { words = strtoul(argv[2], NULL, 0); if (words == 0) usage(execname, "Invalid arg [executive]"); } if (argc == 4) { addr = strtoul(argv[3], NULL, 0); } pic_dumpexec(addr, words); } else { /* EEPROM */ if (argc > 2) usage(execname, "Too many args [eeprom]"); pic_dumpdata(); } break; case 'f': { uint32_t words = UINT32_MAX, addr = UINT32_MAX; if (argc > 4) usage(execname, "Too many args [program flash]"); if (argc >= 3) { words = strtoul(argv[2], NULL, 0); if (words == 0) usage(execname, "Invalid arg [program flash]"); } if (argc == 4) { addr = strtoul(argv[3], NULL, 0); } pic_dumpprogram(addr, words); } break; case 'i': if (argc > 2) usage(execname, "Too many args [id]"); pic_dumpdeviceid(); break; case 'o': if (argc > 3) usage(execname, "Too many args [osccal]"); if (argc == 2) pic_dumposccal(); else pic_writeosccal(strtoul(argv[2], NULL, 0)); break; case 'p': { int blank = 1; if (argc > 4) usage(execname, "Too many args [program]"); if (argc == 4) switch (argv[3][0]) { case 'n': case 'N': case '0': blank = 0; break; case 'y': case 'Y': case '1': blank = 1; break; default:usage(execname, "invalid arg [program]"); break; } if (argc < 3) pic_program("-", 1); else pic_program(argv[2], blank); } break; case 'v': if (argv11 == 'i') { /* VIEW */ int raw = 0; if (argc > 4) usage(execname, "Too many args [view]"); if (argc == 4) switch (argv[3][0]) { case 'r': case 'R': raw = 1; break; default:usage(execname, "invalid arg [view]"); break; } if (argc < 3) pic_view("-", 0); else pic_view(argv[2], raw); } else { /* VERIFY */ if (argc > 3) usage(execname, "Too many args [verify]"); if (argc < 3) rc = 0 - pic_verify("-"); else rc = 0 - pic_verify(argv[2]); } break; #ifdef TTY case '/': if (strstr(argv[1], "/dev/tty") != argv[1]) { usage(execname, "Invalid device [TTY]"); } if (strstr(argv[1], p.device) != NULL) { usage(execname, "Device in use [TTY]"); } stk500v2_listen(argv[1], 0); break; case '8': stk500v2_listen("0.0.0.0", 8048); break; #endif default: usage(execname, "Unknown operation"); break; } free(execdup); io_exit(rc); }
pic_value pic_apply(pic_state *pic, struct pic_proc *proc, pic_value argv) { struct pic_code *pc, c; int ai = pic_gc_arena_preserve(pic); jmp_buf jmp; size_t argc, i; struct pic_code boot[2]; #if PIC_DIRECT_THREADED_VM static void *oplabels[] = { &&L_OP_POP, &&L_OP_PUSHNIL, &&L_OP_PUSHTRUE, &&L_OP_PUSHFALSE, &&L_OP_PUSHFLOAT, &&L_OP_PUSHINT, &&L_OP_PUSHCHAR, &&L_OP_PUSHCONST, &&L_OP_GREF, &&L_OP_GSET, &&L_OP_LREF, &&L_OP_LSET, &&L_OP_CREF, &&L_OP_CSET, &&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_CALL, &&L_OP_TAILCALL, &&L_OP_RET, &&L_OP_LAMBDA, &&L_OP_CONS, &&L_OP_CAR, &&L_OP_CDR, &&L_OP_NILP, &&L_OP_ADD, &&L_OP_SUB, &&L_OP_MUL, &&L_OP_DIV, &&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_STOP }; #endif if (setjmp(jmp) == 0) { pic->jmp = &jmp; } else { goto L_RAISE; } argc = pic_length(pic, argv) + 1; #if VM_DEBUG puts("== booting VM..."); printf(" proc = "); pic_debug(pic, pic_obj_value(proc)); puts(""); printf(" argv = "); pic_debug(pic, argv); puts(""); printf(" irep = "); print_irep(pic, proc->u.irep); puts("\nLet's go!"); #endif PUSH(pic_obj_value(proc)); for (i = 1; i < argc; ++i) { PUSH(pic_car(pic, argv)); argv = pic_cdr(pic, argv); } /* boot! */ boot[0].insn = OP_CALL; boot[0].u.i = argc; boot[1].insn = OP_STOP; pc = boot; c = *pc; goto L_CALL; VM_LOOP { CASE(OP_POP) { POPN(1); NEXT; } CASE(OP_PUSHNIL) { PUSH(pic_nil_value()); NEXT; } CASE(OP_PUSHTRUE) { PUSH(pic_true_value()); NEXT; } CASE(OP_PUSHFALSE) { PUSH(pic_false_value()); NEXT; } CASE(OP_PUSHFLOAT) { PUSH(pic_float_value(c.u.f)); NEXT; } CASE(OP_PUSHINT) { PUSH(pic_int_value(c.u.i)); NEXT; } CASE(OP_PUSHCHAR) { PUSH(pic_char_value(c.u.c)); NEXT; } CASE(OP_PUSHCONST) { PUSH(pic->pool[c.u.i]); NEXT; } CASE(OP_GREF) { PUSH(pic->globals[c.u.i]); NEXT; } CASE(OP_GSET) { pic->globals[c.u.i] = POP(); NEXT; } CASE(OP_LREF) { PUSH(pic->ci->fp[c.u.i]); NEXT; } CASE(OP_LSET) { pic->ci->fp[c.u.i] = POP(); NEXT; } CASE(OP_CREF) { int depth = c.u.r.depth; struct pic_env *env; env = pic->ci->env; while (depth--) { env = env->up; } PUSH(env->values[c.u.r.idx]); NEXT; } CASE(OP_CSET) { int depth = c.u.r.depth; struct pic_env *env; env = pic->ci->env; while (depth--) { env = env->up; } env->values[c.u.r.idx] = POP(); NEXT; } CASE(OP_JMP) { pc += c.u.i; JUMP; } CASE(OP_JMPIF) { pic_value v; v = POP(); if (! pic_false_p(v)) { pc += c.u.i; JUMP; } NEXT; } CASE(OP_CALL) { pic_value x, v; pic_callinfo *ci; struct pic_proc *proc; L_CALL: x = pic->sp[-c.u.i]; if (! pic_proc_p(x)) { pic->errmsg = "invalid application"; goto L_RAISE; } proc = pic_proc_ptr(x); ci = PUSHCI(); ci->argc = c.u.i; ci->pc = pc; ci->fp = pic->sp - c.u.i; ci->env = NULL; if (pic_proc_cfunc_p(x)) { v = proc->u.cfunc(pic); pic->sp = ci->fp; POPCI(); PUSH(v); pic_gc_arena_restore(pic, ai); NEXT; } else { int i; pic_value rest; if (ci->argc != proc->u.irep->argc) { if (! (proc->u.irep->varg && ci->argc >= proc->u.irep->argc)) { pic->errmsg = "wrong number of arguments"; goto L_RAISE; } } /* prepare rest args */ if (proc->u.irep->varg) { rest = pic_nil_value(); for (i = 0; i < ci->argc - proc->u.irep->argc; ++i) { pic_gc_protect(pic, v = POP()); rest = pic_cons(pic, v, rest); } PUSH(rest); } /* prepare env */ if (proc->u.irep->cv_num == 0) { ci->env = proc->env; } else { ci->env = (struct pic_env *)pic_obj_alloc(pic, sizeof(struct pic_env), PIC_TT_ENV); ci->env->up = proc->env; ci->env->valuec = proc->u.irep->cv_num; ci->env->values = (pic_value *)pic_calloc(pic, ci->env->valuec, sizeof(pic_value)); for (i = 0; i < ci->env->valuec; ++i) { ci->env->values[i] = ci->fp[proc->u.irep->cv_tbl[i]]; } } pc = proc->u.irep->code; pic_gc_arena_restore(pic, ai); JUMP; } } CASE(OP_TAILCALL) { int argc; pic_value *argv; argc = c.u.i; argv = pic->sp - argc; for (i = 0; i < argc; ++i) { pic->ci->fp[i] = argv[i]; } pic->sp = pic->ci->fp + argc; pc = POPCI()->pc; /* c is not changed */ goto L_CALL; } CASE(OP_RET) { pic_value v; pic_callinfo *ci; if (pic->errmsg) { L_RAISE: goto L_STOP; } else { v = POP(); ci = POPCI(); pc = ci->pc; pic->sp = ci->fp; PUSH(v); } NEXT; } CASE(OP_LAMBDA) { struct pic_proc *proc; proc = pic_proc_new(pic, pic->irep[c.u.i], pic->ci->env); PUSH(pic_obj_value(proc)); pic_gc_arena_restore(pic, ai); NEXT; } CASE(OP_CONS) { pic_value a, b; pic_gc_protect(pic, b = POP()); pic_gc_protect(pic, a = POP()); PUSH(pic_cons(pic, a, b)); pic_gc_arena_restore(pic, ai); NEXT; } CASE(OP_CAR) { pic_value p; p = POP(); PUSH(pic_car(pic, p)); NEXT; } CASE(OP_CDR) { pic_value p; p = POP(); PUSH(pic_cdr(pic, p)); NEXT; } CASE(OP_NILP) { pic_value p; p = POP(); PUSH(pic_bool_value(pic_nil_p(p))); NEXT; } #define DEFINE_ARITH_OP(opcode, op) \ CASE(opcode) { \ pic_value a, b; \ b = POP(); \ a = POP(); \ if (pic_int_p(a) && pic_int_p(b)) { \ double f = (double)pic_int(a) op (double)pic_int(b); \ if (INT_MIN <= f && f <= INT_MAX) { \ PUSH(pic_int_value((int)f)); \ } \ else { \ PUSH(pic_float_value(f)); \ } \ } \ else if (pic_float_p(a) && pic_float_p(b)) { \ PUSH(pic_float_value(pic_float(a) op pic_float(b))); \ } \ else if (pic_int_p(a) && pic_float_p(b)) { \ PUSH(pic_float_value(pic_int(a) op pic_float(b))); \ } \ else if (pic_float_p(a) && pic_int_p(b)) { \ PUSH(pic_float_value(pic_float(a) op pic_int(b))); \ } \ else { \ pic->errmsg = #op " got non-number operands"; \ goto L_RAISE; \ } \ NEXT; \ } DEFINE_ARITH_OP(OP_ADD, +); DEFINE_ARITH_OP(OP_SUB, -); DEFINE_ARITH_OP(OP_MUL, *); /* special care for (int / int) division */ CASE(OP_DIV) { pic_value a, b; b = POP(); a = POP(); if (pic_int_p(a) && pic_int_p(b)) { PUSH(pic_float_value((double)pic_int(a) / pic_int(b))); } else if (pic_float_p(a) && pic_float_p(b)) { PUSH(pic_float_value(pic_float(a) / pic_float(b))); } else if (pic_int_p(a) && pic_float_p(b)) { PUSH(pic_float_value(pic_int(a) / pic_float(b))); } else if (pic_float_p(a) && pic_int_p(b)) { PUSH(pic_float_value(pic_float(a) / pic_int(b))); } else { pic->errmsg = "/ got non-number operands"; goto L_RAISE; } NEXT; } #define DEFINE_COMP_OP(opcode, op) \ CASE(opcode) { \ pic_value a, b; \ b = POP(); \ a = POP(); \ if (pic_int_p(a) && pic_int_p(b)) { \ PUSH(pic_bool_value(pic_int(a) op pic_int(b))); \ } \ else if (pic_float_p(a) && pic_float_p(b)) { \ PUSH(pic_bool_value(pic_float(a) op pic_float(b))); \ } \ else if (pic_int_p(a) && pic_int_p(b)) { \ PUSH(pic_bool_value(pic_int(a) op pic_float(b))); \ } \ else if (pic_float_p(a) && pic_int_p(b)) { \ PUSH(pic_bool_value(pic_float(a) op pic_int(b))); \ } \ else { \ pic->errmsg = #op " got non-number operands"; \ goto L_RAISE; \ } \ NEXT; \ } DEFINE_COMP_OP(OP_EQ, ==); DEFINE_COMP_OP(OP_LT, <); DEFINE_COMP_OP(OP_LE, <=); CASE(OP_STOP) { pic_value val; L_STOP: val = POP(); pic->jmp = NULL; if (pic->errmsg) { return pic_undef_value(); } #if VM_DEBUG puts("**VM END STATE**"); printf("stbase\t= %p\nsp\t= %p\n", pic->stbase, pic->sp); printf("cibase\t= %p\nci\t= %p\n", pic->cibase, pic->ci); if (pic->stbase < pic->sp) { pic_value *sp; printf("* stack trace:"); for (sp = pic->stbase; pic->sp != sp; ++sp) { pic_debug(pic, *sp); puts(""); } } if (pic->stbase > pic->sp) { puts("*** stack underflow!"); } #endif pic_gc_protect(pic, val); return val; } } VM_LOOP_END; }