DTYPE _sbi_getfval(uint8_t type, SBITHREAD* thread, sbi_runtime_t* rt) { DTYPE val = _getfch(); switch (type) { case _regid: case _varid: case _value8: break; case _value16: case _value32: val |= (DTYPE)_getfch() << 8; if (type==_value16) break; val |= (DTYPE)_getfch() << 16; val |= (DTYPE)_getfch() << 24; break; } return val; }
/* Executes the program */ unsigned int _sbi_run(void *rt) // Runs a SBI program // Returns: // 0: No errors // 1: Reached end (no exit found) // 2: Program exited // 3: Wrong instruction code // 4: Can't understand byte // 5: User error { if (!rt) return 5; RT(rt)->_exec = 1; byte rd = _getfch(); byte var1, var1t, var2, var2t, var3, var3t; unsigned int i; byte b[16]; switch (rd) { case _istr_assign: var1 = _getfch(); RT(rt)->_t[var1] = _getfch(); break; case _istr_move: var1 = _getfch(); RT(rt)->_t[var1] = RT(rt)->_t[_getfch()]; break; case _istr_add: var1t = _getfch(); var1 = _getfch(); var2t = _getfch(); var2 = _getfch(); RT(rt)->_t[_getfch()] = _getval(var1t, var1, rt) + _getval(var2t, var2, rt); break; case _istr_sub: var1t = _getfch(); var1 = _getfch(); var2t = _getfch(); var2 = _getfch(); RT(rt)->_t[_getfch()] = _getval(var1t, var1, rt) - _getval(var2t, var2, rt); break; case _istr_mul: var1t = _getfch(); var1 = _getfch(); var2t = _getfch(); var2 = _getfch(); RT(rt)->_t[_getfch()] = _getval(var1t, var1, rt) * _getval(var2t, var2, rt); break; case _istr_div: var1t = _getfch(); var1 = _getfch(); var2t = _getfch(); var2 = _getfch(); RT(rt)->_t[_getfch()] = _getval(var1t, var1, rt) / _getval(var2t, var2, rt); break; case _istr_incr: RT(rt)->_t[_getfch()]++; break; case _istr_decr: RT(rt)->_t[_getfch()]--; break; case _istr_inv: var1 = _getfch(); if (RT(rt)->_t[var1]==0) RT(rt)->_t[var1]=1; else RT(rt)->_t[var1]=0; break; case _istr_tob: var1 = _getfch(); if (RT(rt)->_t[var1]>0) RT(rt)->_t[var1]=1; else RT(rt)->_t[var1]=0; break; case _istr_cmp: var1t = _getfch(); var1 = _getfch(); var2t = _getfch(); var2 = _getfch(); if (_getval(var1t, var1, rt)==_getval(var2t, var2, rt)) RT(rt)->_t[_getfch()]=1; else RT(rt)->_t[_getfch()]=0; break; case _istr_high: var1t = _getfch(); var1 = _getfch(); var2t = _getfch(); var2 = _getfch(); if (_getval(var1t, var1, rt)>_getval(var2t, var2, rt)) RT(rt)->_t[_getfch()]=1; else RT(rt)->_t[_getfch()]=0; break; case _istr_low: var1t = _getfch(); var1 = _getfch(); var2t = _getfch(); var2 = _getfch(); if (_getval(var1t, var1, rt)<_getval(var2t, var2, rt)) RT(rt)->_t[_getfch()]=1; else RT(rt)->_t[_getfch()]=0; break; case _istr_jump: var1t = _getfch(); var1 = _getfch(); if (_getfch() > 0) { for (i=RETURNADDRESSESN-2; i>0; i--) RT(rt)->_returnaddresses[i+1] = RT(rt)->_returnaddresses[i]; RT(rt)->_returnaddresses[1] = RT(rt)->_returnaddresses[0]; RT(rt)->_returnaddresses[0] = _getfpos(); } _setfpos(RT(rt)->_labels[_getval(var1t, var1, rt)]); break; case _istr_cmpjump: var1t = _getfch(); var1 = _getfch(); var2t = _getfch(); var2 = _getfch(); var3t = _getfch(); var3 = _getfch(); if (_getfch() > 0) { for (i=RETURNADDRESSESN-2; i>0; i--) RT(rt)->_returnaddresses[i+1] = RT(rt)->_returnaddresses[i]; RT(rt)->_returnaddresses[1] = RT(rt)->_returnaddresses[0]; RT(rt)->_returnaddresses[0] = _getfpos(); } if (_getval(var1t, var1, rt)==_getval(var2t, var2, rt)) { _setfpos(RT(rt)->_labels[_getval(var3t, var3, rt)]); } break; case _istr_ret: _setfpos(RT(rt)->_returnaddresses[0]); for (i=1; i<RETURNADDRESSESN; i++) RT(rt)->_returnaddresses[i-1] = RT(rt)->_returnaddresses[i]; break; case _istr_debug: var1t = _getfch(); _debug(_getval(var1t, _getfch(), rt)); break; case _istr_error: var1t = _getfch(); _error(_getval(var1t, _getfch(), rt)); return 5; break; case _istr_sint: var1t = _getfch(); RT(rt)->_userfid=_getval(var1t, _getfch(), rt); break; case _istr_int: { for (i=0; i<16; i++) b[i] = _getfch(); RT(rt)->_userCtx->sbi_user_funcs[RT(rt)->_userfid](b,rt); } break; case _istr_exit: return 2; break; case FOOTER_0: if (_getfch()==FOOTER_1) return 1; else return 4; default: _error(0xB1); return 3; break; } RT(rt)->_exec = 0; if (RT(rt)->_intinqueue==1) _interrupt(RT(rt)->_queuedint, rt); // If there are interrupts in // in the queue, do it return 0; }
/* Begins program execution */ unsigned int _sbi_begin(void* rt) // Returns: // 0: No errors // 1: No function pointers for _getfch, // _setfpos and _getfpos // 2: Old version of executable format // 3: Invalid program file { // Check function pointers if (RT(rt)->_userCtx==0) return 1; if ((RT(rt)->_userCtx->getfch==0)||(RT(rt)->_userCtx->setfpos==0)||(RT(rt)->_userCtx->getfpos==0)) return 1; // Read head byte rd = _getfch(); if (rd!=HEADER_0) return 3; rd = _getfch(); if (rd!=HEADER_1) { if ((rd==0x1B)||(rd==0x2B)||(rd==0x3B)) return 2; else return 3; } // Getting labels if (_getfch()!=LABELSECTION) return 3; unsigned int ln = _getfch(); RT(rt)->_labels = (unsigned int*)malloc(ln * sizeof(int)); unsigned int c = 0; while (ln--) { RT(rt)->_labels[c] = _getfch() | (_getfch() << 8); c++; } if (_getfch()!=SEPARATOR) return 3; // Getting interrupts addresses if (_getfch()!=INTERRUPTSECTION) return 3; ln = _getfch(); RT(rt)->_interrupts = (unsigned int*)malloc(ln + ln); //ln * sizeof(unsigned int) -> ln * 2 -> ln+ln c = 0; while (ln--) { RT(rt)->_interrupts[c] = _getfch() | (_getfch() << 8); c++; } if (_getfch()!=SEPARATOR) return 3; // Done return 0; }
/* Steps the program of one instruction Returns: sbi_error_t */ sbi_error_t _sbi_step_internal(SBITHREAD* thread, sbi_runtime_t* rt) { uint8_t rd, var1t, var2t, var3t; DTYPE var1, var2, var3; int i; rd = _getfch(); _TRACE("Instruction code 0x%02x at pcount: 0x%02x thread %d\n", rd, CUR_PCOUNT-1, thread->threadid ); switch (rd) { case _istr_assign: var1t= _getfch(); var1 = _getfch(); _setval(var1t,var1,_getfval(_getfch()), thread); break; case _istr_move: var1t = _getfch(); var1 = _getfch(); var2t = _getfch(); var2 = _getfval(var2t); _setval ( var1t, var1, _getval(var2t,var2, thread), thread ); break; case _istr_add: case _istr_sub: case _istr_mul: case _istr_div: case _istr_cmp: case _istr_high: case _istr_low: case _istr_lte: case _istr_gte: { DTYPE v1, v2, val; var1t = _getfch(); var1 = _getfval(var1t); var2t = _getfch(); var2 = _getfval(var2t); var3t = _getfch(); var3 = _getfch(); v1=_getval(var1t,var1, thread); v2=_getval(var2t,var2, thread); val = rd == _istr_add ? v1+v2 : rd == _istr_sub ? v1-v2 : rd == _istr_mul ? v1*v2 : rd == _istr_div ? v1/v2 : rd == _istr_cmp ? (v1==v2?1:0) : rd == _istr_high ? (v1>v2?1:0) : rd == _istr_low ? (v1<v2?1:0) : rd == _istr_lte ? (v1<=v2?1:0) : rd == _istr_gte ? (v1>=v2?1:0) : 0; _setval( var3t, var3, val, thread ); } break; case _istr_push: if (thread->stackp>=STACK_SIZE-1) { _error(SBI_STACK_OVERFLOW); // TODO error codes (overflow) return SBI_PROG_ERROR; } var1t=_getfch(); var1 = _getfval(var1t); thread->stack[thread->stackp++] = _getval(var1t,var1,thread); break; case _istr_pop: { uint8_t n; if (thread->stackp==0) { _error(SBI_STACK_UNDERFLOW); // underflow return SBI_PROG_ERROR; } n = _getfch(); --thread->stackp; if (n) { DTYPE val = thread->stack[thread->stackp]; var1t=_getfch(); var1=_getfch(); _setval(var1t,var1,val,thread); } } break; case _istr_incr: case _istr_decr: case _istr_inv: case _istr_tob: { DTYPE val; var1t=_getfch(); var1=_getfch(); val = _getval( var1t, var1, thread); val = rd == _istr_incr ? val+1 : rd == _istr_decr ? val-1 : rd == _istr_inv ? !val : rd == _istr_tob ? (val?1:0) : 0; _setval(var1t,var1,val,thread); } break; case _istr_jump: var1t = _getfch(); var1 = _getfval(var1t); if (_getfch() > 0) { _RETADDRS[thread->raddr_cnt++] = CUR_PCOUNT; } CUR_PCOUNT = _LABELS[_getval(var1t, var1, thread)]; break; case _istr_cmpjump: var1t = _getfch(); var1 = _getfval(var1t); var2t = _getfch(); var2 = _getfval(var2t); var3t = _getfch(); var3 = _getfch(); i=_getfch(); // push ret if (_getval(var1t, var1, thread)==_getval(var2t, var2, thread)) { if (i > 0) { _RETADDRS[thread->raddr_cnt++] = CUR_PCOUNT; } CUR_PCOUNT = _LABELS[_getval(var3t, var3, thread)]; } break; case _istr_ret: if (thread->raddr_cnt>0) { CUR_PCOUNT = _RETADDRS[--thread->raddr_cnt]; } else { // thread exit return SBI_THREAD_EXIT; } break; case _istr_debug: var1t = _getfch(); var1 = _getfval(var1t); _debug(_getval(var1t, var1, thread)); break; case _istr_error: var1t = _getfch(); var1 = _getfval(var1t); _error(_getval(var1t, var1, thread)); return SBI_PROG_ERROR; break; case _istr_print: { uint16_t strLoc = _getfch(); strLoc |= _getfch()<<8; if (rt->ctx->print) { int slen, tmplen; char *tmp, cur; PCOUNT curp = CUR_PCOUNT; CUR_PCOUNT = strLoc; slen = 0; tmplen=0; tmp = NULL; cur; do { cur = _getfch(); if (tmplen==slen) { tmp = (char*) realloc ( tmp, slen+20 ); slen += 20; if (!tmp) return SBI_ALLOC_ERROR; } tmp[tmplen++] = cur; } while (cur != 0); _print(tmp); free(tmp); CUR_PCOUNT = curp; } } break; case _istr_sint: var1t = _getfch(); var1 = _getfval(var1t); thread->_userfid=_getval(var1t, var1, thread); break; case _istr_int: case _istr_intr: { uint8_t argc; DTYPE *pvals=NULL, r; // NOTE should parameters be pushed on the stack instead? if (rd==_istr_intr) { var1t=_getfch(); var1=_getfch(); } argc = _getfch(); if (argc>0) { pvals = malloc(sizeof(DTYPE)*(argc)); if (!pvals) return SBI_ALLOC_ERROR; } for (i=0;i<argc;++i) { var2t = _getfch(); var2 = _getfval(var2t); pvals[i] = _getval(var2t,var2,thread); } r = RT->ctx->sbi_user_funcs[thread->_userfid](argc,pvals); if (rd==_istr_intr) { _setval(var1t,var1,r,thread); } if (pvals) free(pvals); } break; case _istr_thread: { int ret; uint8_t tId; var1t = _getfch(); var1 = _getfch(); var2t = _getfch(); var2 = _getfch(); ret = _sbi_new_thread_at(_LABELS[_getval(var1t,var1,thread)], rt); tId = !ret ? rt->new_threadid : 0; _setval( var2t, var2, tId, thread ); if (ret) _error(ret); return ret; } break; case _istr_wait: { DTYPE tId; var1t = _getfch(); var1 = _getfch(); tId = _getval(var1t,var1,thread); for (i=0;i<rt->thread_cnt;++i) { if ( rt->_sbi_threads[i]->threadid == tId && rt->_sbi_threads[i]->status == RUNNING ) { CUR_PCOUNT-=3; // rerun wait break; } } } break; case _istr_alive: { DTYPE tId, val; var1t = _getfch(); var1 = _getfch(); var2t = _getfch(); var2 = _getfch(); tId = _getval(var1t,var1,thread); val = 0; // not running for (i=0;i<rt->thread_cnt;++i) { if (rt->_sbi_threads[i]->threadid == tId && rt->_sbi_threads[i]->status == RUNNING) { val=1; break; } } _setval(var2t,var2,val,thread); } break; case _istr_stop: { DTYPE tId; var1t = _getfch(); var1 = _getfch(); tId = _getval(var1t,var1,thread); for (i=0;i<rt->thread_cnt;++i) { if (rt->_sbi_threads[i]->threadid == tId) { rt->_sbi_threads[i]->status = STOPPED; break; } } } break; case _istr_exit: return SBI_PROG_EXIT; break; case FOOTER_0: if (_getfch()==FOOTER_1) return SBI_PROG_EOF; else return SBI_INSTR_ERROR; default: _error(SBI_INSTR_ERROR); _error(rd); _error(CUR_PCOUNT-1); _ERR("Instruction error 0x%02x at pcount: 0x%02x thread %d\n", rd, CUR_PCOUNT-1, thread->threadid ); return SBI_PROG_ERROR; break; } return SBI_NOERROR; }
/* * Starts the main thread */ sbi_error_t sbi_begin(void *rt) { SBITHREAD *thread; uint8_t rd; unsigned int ln, c; int ret; if (!rt) return SBI_INVALID_RT; // create the main thread thread = _sbi_createthread(0, (sbi_runtime_t*)rt); if (!thread) return SBI_ALLOC_ERROR; if (!RT->ctx->getfch) return SBI_CTX_ERROR; // Read head if (_getfch()!=HEADER_0) return SBI_HEADER_ERROR; rd = _getfch(); if (rd!=HEADER_1) { if ((rd==0x1B)||(rd==0x2B)||(rd==0x3B)) return SBI_HEADER_OLD; else return SBI_HEADER_ERROR; } // Getting labels if (_getfch()!=LABELSECTION) return SBI_HEADER_ERROR; ln = _getfch(); RT->_labels = malloc(ln * sizeof(LABEL)); c = 0; while (ln--) { RT->_labels[c] = _getfch() | (_getfch() << 8); c++; } if (_getfch()!=SEPARATOR) return SBI_HEADER_ERROR; // Getting interrupts addresses if (_getfch()!=INTERRUPTSECTION) return SBI_HEADER_ERROR; ln = _getfch(); RT->_interrupts = malloc(ln * sizeof(INTERRUPT)); c = 0; while (ln--) { RT->_interrupts[c] = _getfch() | (_getfch() << 8); c++; } if (_getfch()!=SEPARATOR) return SBI_HEADER_ERROR; ret = _sbi_loadthread(thread, RT); return ret; }