X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=dcpu16.c;h=23ef53a41747da7aadb9a51baec085033d5e1bab;hb=4185a67f55fb99f34f013b939a8ef9e13454c1e5;hp=772aec84917cd407884f7a281a6e0ed3be547d29;hpb=76e24789b10f9165fa53b569c9ae33504d237ca6;p=dcpu16 diff --git a/dcpu16.c b/dcpu16.c index 772aec8..23ef53a 100644 --- a/dcpu16.c +++ b/dcpu16.c @@ -25,8 +25,9 @@ * * TODO * change api to print into buffers rather than stdio - * drop checks for assigning to literals -- it won't affect anything anyhow * refactor opcode functiontables into switch statements + * let callbacks determine whether to override events, or just observe + * sort init callbacks by base addr, to call in-order */ static const char * const src_id_ = "$Id$"; @@ -34,7 +35,7 @@ static const char * const src_id_ = "$Id$"; #define OPCODE_BASIC_BITS 4 #define OPCODE_OPERAND_BITS 6 -static const char regnames_[] = "ABCXYZIJ"; +static const char * const regnames_ = "ABCXYZIJ"; /* some default warning and debug reporting functions, which can be overridden by clients */ #define WARN(...) do { if (warn_cb_) warn_cb_(__VA_ARGS__); } while (0) @@ -88,13 +89,13 @@ void dcpu16_trace_cb_set(void (*fn)(char *fmt, ...)) { * invokes callbacks for specified event */ static inline -void acct_event_(struct dcpu16 *vm, dcpu16_acct_event_ ev, DCPU16_WORD addr) { +void acct_event_(struct dcpu16 *vm, dcpu16_acct_event ev, DCPU16_WORD addr) { struct dcpu16_acct_cb *cb = vm->cb_table_; size_t i; for (i = 0; i < vm->cb_table_entries_; i++) { if ( (cb[i].mask & ev) ) - cb[i].fn(ev, addr); + cb[i].fn(vm, ev, addr, cb[i].data); } } @@ -296,8 +297,8 @@ static const struct opcode_entry opcode_nbi_entries[] = { /* basic opcodes */ /* - N.B. the following function does not decode values, as the nbi - instructions only have one operand. + N.B. the following function does not decode values, (thus does not advance pc &c) + Decoding is handled by the opcode functions it calls. */ OP_IMPL(_nbi_) { /* non-basic instruction */ @@ -320,14 +321,16 @@ OP_IMPL(set) { /* sets a to b */ ACCT_R(ev_b_addr); - ACCT_W(ev_a_addr); - /* only set non-literal target */ - if (!lit_a) { - *a = *b; - } + /* + if a is a literal, it's aimed at a scratch register, + so it's fine to update, as it won't have any effect. + */ + *a = *b; d->cycle += 1; + + ACCT_W(ev_a_addr); } OP_IMPL(add) { @@ -338,9 +341,7 @@ OP_IMPL(add) { ACCT_R(ev_b_addr); ACCT_R(ev_a_addr); - if (!lit_a) { - *a = acc; - } + *a = acc; d->o = (acc > 0xffff); d->cycle += 2; @@ -356,10 +357,9 @@ OP_IMPL(sub) { ACCT_R(ev_b_addr); ACCT_R(ev_a_addr); - if (!lit_a) { - *a = acc; - } + *a = acc; d->o = (acc > 0xffff); + d->cycle += 2; ACCT_W(ev_a_addr); @@ -373,10 +373,9 @@ OP_IMPL(mul) { ACCT_R(ev_b_addr); ACCT_R(ev_a_addr); - if (!lit_a) { - *a = acc; - } + *a = acc; d->o = acc >> 16; + d->cycle += 2; ACCT_W(ev_a_addr); @@ -390,19 +389,11 @@ OP_IMPL(div) { ACCT_R(ev_a_addr); if (*b == 0) { - if (!lit_a) { - *a = 0; - } + *a = 0; d->o = 0; } else { - unsigned int acc = *a / *b; - - if (!lit_a) { - *a = acc; - } - - acc = (*a << 16) / *b; - d->o = acc; + *a = *a / *b; + d->o = (*a << 16) / *b; } d->cycle += 3; @@ -418,13 +409,9 @@ OP_IMPL(mod) { ACCT_R(ev_a_addr); if (*b == 0) { - if (!lit_a) { - *a = 0; - } + *a = 0; } else { - if (!lit_a) { - *a = *a % *b; - } + *a = *a % *b; } d->cycle += 3; @@ -440,9 +427,8 @@ OP_IMPL(shl) { ACCT_R(ev_b_addr); ACCT_R(ev_a_addr); - if (!lit_a) { - *a = acc; - } + *a = acc; + d->o = acc >> 16; d->cycle += 2; @@ -458,9 +444,7 @@ OP_IMPL(shr) { ACCT_R(ev_b_addr); ACCT_R(ev_a_addr); - if (!lit_a) { - *a = acc; - } + *a = acc; d->o = (*a << 16) >> *b; d->cycle += 2; @@ -475,9 +459,7 @@ OP_IMPL(and) { ACCT_R(ev_b_addr); ACCT_R(ev_a_addr); - if (!lit_a) { - *a = *a & *b; - } + *a = *a & *b; d->cycle += 1; @@ -491,9 +473,7 @@ OP_IMPL(bor) { ACCT_R(ev_b_addr); ACCT_R(ev_a_addr); - if (!lit_a) { - *a = *a | *b; - } + *a = *a | *b; d->cycle += 1; @@ -507,13 +487,11 @@ OP_IMPL(xor) { ACCT_R(ev_b_addr); ACCT_R(ev_a_addr); - if (!lit_a) { - *a = *a ^ *b; - } - - ACCT_W(ev_a_addr); + *a = *a ^ *b; d->cycle += 1; + + ACCT_W(ev_a_addr); } OP_IMPL(ife) { @@ -715,6 +693,8 @@ void dcpu16_step(struct dcpu16 *d) { if (!d) return; + acct_event_(d, DCPU16_ACCT_EV_CYCLE, d->pc); + /* PC is advanced while decoding the operands by the opcode functions. Things like this could be organized a little better.. @@ -787,11 +767,12 @@ void dcpu16_dump_ram(struct dcpu16 *d, DCPU16_WORD start, DCPU16_WORD end) { * Register callback fn to be triggered whenever event matching any events * in bitwise mask occur. */ -int dcpu16_acct_add(struct dcpu16 *vm, dcpu16_acct_event_ mask, void (*fn)(dcpu16_acct_event_, DCPU16_WORD)) { +int dcpu16_acct_add(struct dcpu16 *vm, dcpu16_acct_event mask, dcpu16_ev_cb_t *fn, void *data) { struct dcpu16_acct_cb cb; cb.mask = mask; cb.fn = fn; + cb.data = data; if (vm->cb_table_entries_ == vm->cb_table_allocated_) { size_t new_entries = vm->cb_table_allocated_ + 32; @@ -811,12 +792,20 @@ int dcpu16_acct_add(struct dcpu16 *vm, dcpu16_acct_event_ mask, void (*fn)(dcpu1 } /* dcpu16_reset - * resets a dcpu16 instance to initial state + * signals cpu to reset, clearing runstate and ram, then reload any init callbacks */ void dcpu16_reset(struct dcpu16 *d) { if (!d) return; - memset(d, 0, sizeof *d); + d->cycle = 0; + memset(d->reg, 0, sizeof d->reg); + d->pc = 0; + d->sp = 0; + d->o = 0; + d->skip_ = 0; + memset(d->ram, 0, sizeof d->ram); + + acct_event_(d, DCPU16_ACCT_EV_RESET, 0); } /* dcpu16_new