From df965ac8eeee9115d8f8c7e35e8a470b315d3fb4 Mon Sep 17 00:00:00 2001 From: Justin Wind Date: Fri, 13 Apr 2012 14:31:30 -0700 Subject: [PATCH] cleanup, simplified event callbacks, step now consumes branch-skipped instructions --- Makefile | 17 ++- dcpu16.c | 301 +++++++++++++++++++++++++++------------------------- dcpu16.h | 7 +- vm-dcpu16.c | 27 ++++- 4 files changed, 196 insertions(+), 156 deletions(-) diff --git a/Makefile b/Makefile index 1a931a1..a0745cf 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,30 @@ #!make # PROGRAMS = as-dcpu16 vm-dcpu16 +SOURCES = dcpu16.c as-dcpu16.c vm-dcpu16.c CFLAGS = -g -Wall -Wextra -pedantic -std=c99 LDFLAGS = -lreadline -HEADERS = dcpu16.h all: $(PROGRAMS) -%.o: %.c $(HEADERS) +depend: .depend -vm-dcpu16: vm-dcpu16.o dcpu16.o +.depend: $(SOURCES) + @rm -f ./.depend + $(CC) $(CFLAGS) -MM $^ >> ./.depend -as-dcpu16: as-dcpu16.o +include .depend + + +vm-dcpu16: vm-dcpu16.o dcpu16.o + +as-dcpu16: as-dcpu16.o dcpu16: dcpu16.o clean: - @rm -rf $(PROGRAMS) *.o *.dSYM + @rm -rf $(PROGRAMS) *.o *.dSYM .depend check: $(PROGRAMS) diff --git a/dcpu16.c b/dcpu16.c index b21f0f9..e231e5f 100644 --- a/dcpu16.c +++ b/dcpu16.c @@ -24,13 +24,15 @@ * 2012 04 12 - added basic callback support for address accesses * * TODO + * change api to print into buffers rather than stdio * drop checks for assigning to literals -- it won't affect anything anyhow - * debug short literal decoding + * refactor opcode functiontables into switch statements */ static const char * const src_id_ = "$Id$"; -#define WORD DCPU16_WORD +#define OPCODE_BASIC_BITS 4 +#define OPCODE_OPERAND_BITS 6 static const char regnames_[] = "ABCXYZIJ"; @@ -82,35 +84,6 @@ void dcpu16_trace_cb_set(void (*fn)(char *fmt, ...)) { } -/* dcpu16_acct_add - * Register callback fn to be triggered whenever event matching exactly mask_ev - * and additionally matching any of mask events occur. - */ -int dcpu16_acct_add(struct dcpu16 *vm, dcpu16_acct_event_ match_all, dcpu16_acct_event_ match_any, void (*fn)(dcpu16_acct_event_, DCPU16_WORD)) { - struct dcpu16_acct_cb cb; - - cb.match_all = match_all; - cb.match_any = match_any; - cb.fn = fn; - - /* add to vm->cb_table_, vm->cb_table_entries_, vm->cb_table_allocated_ */ - if (vm->cb_table_entries_ == vm->cb_table_allocated_) { - size_t new_entries = vm->cb_table_allocated_ + 32; - void *tmp_ptr = realloc(vm->cb_table_, new_entries * sizeof *(vm->cb_table_)); - if (tmp_ptr == NULL) { - fprintf(stderr, "%s():%s", "realloc", strerror(errno)); - return -1; - } - vm->cb_table_ = tmp_ptr; - vm->cb_table_allocated_ += 32; - } - - memcpy(vm->cb_table_ + vm->cb_table_entries_, &cb, sizeof cb); - vm->cb_table_entries_++; - - return 0; -} - /* acct_event_ * invokes callbacks for specified event */ @@ -120,27 +93,26 @@ void acct_event_(struct dcpu16 *vm, dcpu16_acct_event_ ev, DCPU16_WORD addr) { size_t i; for (i = 0; i < vm->cb_table_entries_; i++) { - if ( (cb[i].match_all & ev) == cb[i].match_all /* exact match on event flags */ - && (cb[i].match_any & ev) ) { /* any match on rest */ + if ( (cb[i].mask & ev) ) cb[i].fn(ev, addr); - } } } + /* value_decode_ * sets *v to be the destination of the value + * advances d->pc if necessary * workv is buffer to use to accumulate literal value before use, one exists for either potential instruction operand + * e_addr is for accounting callback * returns true if destination points to literal (id est *v should ignore writes) */ static -unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v, dcpu16_acct_event_ *e, WORD *e_addr) { - WORD nextword; +unsigned int value_decode_(struct dcpu16 *d, DCPU16_WORD value, DCPU16_WORD *work_v, DCPU16_WORD **v, DCPU16_WORD *e_addr) { + DCPU16_WORD nextword; unsigned int retval = 0; assert(value <= 0x3f); - *e = 0; - /* does this value indicate a literal */ if (value >= 0x1f) retval = 1; @@ -165,7 +137,6 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v, regnames_[value&0x07], d->reg[value&0x07], **v); - *e |= DCPU16_ACCT_RAM; *e_addr = d->reg[(value & 0x07)]; } else if (value <= 0x17) { /* [next word + register] */ @@ -177,7 +148,6 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v, nextword, d->reg[(value & 0x07)], **v); - *e |= DCPU16_ACCT_RAM; *e_addr = nextword + d->reg[(value & 0x07)]; } else switch (value) { @@ -186,7 +156,6 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v, TRACE(">> POP [0x%04x] (0x%04x)", d->sp - 1, **v); - *e |= DCPU16_ACCT_RAM; *e_addr = d->sp - 1; break; @@ -195,7 +164,6 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v, TRACE(">> PEEK [0x%04x] (0x%04x)", d->sp, **v); - *e |= DCPU16_ACCT_RAM; *e_addr = d->sp; break; @@ -204,7 +172,6 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v, TRACE(">> PUSH [0x%04x] (0x%04x)", d->sp + 1, **v); - *e |= DCPU16_ACCT_RAM; *e_addr = d->sp + 1; break; @@ -231,7 +198,6 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v, TRACE(">> [nextword] [0x%04x] (0x%04x)", nextword, **v); - *e |= DCPU16_ACCT_RAM; *e_addr = nextword; break; @@ -252,47 +218,37 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v, return retval; } -#define OPCODE_BASIC_BITS (4) -#define OPCODE_BASIC_SHIFT (0) - -#define OPCODE_NBI_BITS (6) -#define OPCODE_NBI_SHIFT (4) - -#define OPCODE_FUTURE_BITS (16) -#define OPCODE_FUTURE_SHIFT (10) #define OPCODE_NAME_LEN 16 struct opcode_entry { unsigned short value; char name[OPCODE_NAME_LEN]; - void (*impl)(struct dcpu16 *, WORD, WORD); + void (*impl)(struct dcpu16 *, DCPU16_WORD, DCPU16_WORD); }; /* messy boilerplate for opcode handlers */ -#define OP_IMPL(x) static void op_##x(struct dcpu16 *d, WORD val_a, WORD val_b) +#define OP_IMPL(x) static void op_##x(struct dcpu16 *d, DCPU16_WORD val_a, DCPU16_WORD val_b) -#define OP_NBI_ (void)val_b, (void)b, (void)ev_b, (void)ev_b_addr -#define OP_BASIC_ (void)value_decode(d, val_b, &d->reg_work_[0], &b, &ev_b, &ev_b_addr) -#define OP_TYPE(op_type) WORD *a, *b;\ +#define OP_TYPE(op_type) DCPU16_WORD *a, *b;\ unsigned int lit_a;\ - dcpu16_acct_event_ ev_a = 0, ev_b = 0;\ - WORD ev_a_addr = 0, ev_b_addr = 0;\ + DCPU16_WORD ev_a_addr = 0, ev_b_addr = 0;\ do {\ - lit_a = value_decode(d, val_a, &d->reg_work_[0], &a, &ev_a, &ev_a_addr);\ + lit_a = value_decode_(d, val_a, &d->reg_work_[0], &a, &ev_a_addr);\ op_type;\ - if (d->skip_) {\ - TRACE("++ SKIPPED");\ - d->skip_ = 0;\ - return;\ - }\ } while (0) +#define OP_NBI_ (void)val_b, (void)b, (void)ev_b_addr +#define OP_BASIC_ (void)value_decode_(d, val_b, &d->reg_work_[0], &b, &ev_b_addr) #define OP_BASIC(x) OP_TYPE(OP_BASIC_) #define OP_NBI(x) OP_TYPE(OP_NBI_) -/* accounting helpers */ -#define ACCT_R(ev) do { if (ev) { acct_event_(d, ev | DCPU16_ACCT_EV_READ, ev##_addr); } } while (0) -#define ACCT_W(ev) do { if (ev) { acct_event_(d, ev | DCPU16_ACCT_EV_WRITE, ev##_addr); } } while (0) +/* + accounting helpers, these fire off the related callbacks for memory reads, + memory writes, and execution of reserved instructions + */ +#define ACCT_R(addr) do { acct_event_(d, DCPU16_ACCT_EV_READ, addr); } while (0) +#define ACCT_W(addr) do { acct_event_(d, DCPU16_ACCT_EV_WRITE, addr); } while (0) +#define ACCT_ILL(addr) do { acct_event_(d, DCPU16_ACCT_EV_NOP, addr); } while (0) /* extended opcodes */ @@ -307,20 +263,24 @@ OP_IMPL(nbi__reserved_) { OP_NBI(nbi__reserved_); /* reserved for future expansion */ - WORD future_opcode = (d->ram[d->pc] >> OPCODE_FUTURE_SHIFT); + DCPU16_WORD future_opcode = (d->ram[d->pc] >> (OPCODE_BASIC_BITS + OPCODE_OPERAND_BITS)); WARN("reserved future opcode 0x%04x invoked", future_opcode); + + ACCT_ILL(d->pc); } OP_IMPL(nbi_jsr) { OP_NBI(nbi_jsr); /* pushes the address of the next instruction to the stack, then sets PC to a */ - ACCT_R(ev_a); + ACCT_R(ev_a_addr); d->ram[ --d->sp ] = d->pc; d->pc = *a; d->cycle += 2; + + ACCT_W(d->sp + 1); } OP_IMPL(nbi__reserved2_) { @@ -328,6 +288,8 @@ OP_IMPL(nbi__reserved2_) { /* reserved */ WARN("reserved nbi opcode invoked"); + + ACCT_ILL(d->pc); } static const struct opcode_entry opcode_nbi_entries[] = { @@ -350,7 +312,7 @@ OP_IMPL(_nbi_) { /* don't do normal value decoding here */ - WORD nbi_opcode = val_a; + DCPU16_WORD nbi_opcode = val_a; const struct opcode_entry *e = opcode_nbi_entries; e = opcode_nbi_entries + ( (nbi_opcode < OPCODE_NBI_MAX) ? nbi_opcode : (OPCODE_NBI_MAX - 1) ); @@ -365,8 +327,8 @@ OP_IMPL(set) { OP_BASIC(set); /* sets a to b */ - ACCT_R(ev_b); - ACCT_W(ev_a); + ACCT_R(ev_b_addr); + ACCT_W(ev_a_addr); /* only set non-literal target */ if (!lit_a) { @@ -381,8 +343,8 @@ OP_IMPL(add) { /* sets a to a+b, sets O to 0x0001 if there's an overflow, 0x0 otherwise */ unsigned int acc = *a + *b; - ACCT_R(ev_b); - ACCT_R(ev_a); + ACCT_R(ev_b_addr); + ACCT_R(ev_a_addr); if (!lit_a) { *a = acc; @@ -391,7 +353,7 @@ OP_IMPL(add) { d->cycle += 2; - ACCT_W(ev_a); + ACCT_W(ev_a_addr); } OP_IMPL(sub) { @@ -399,8 +361,8 @@ OP_IMPL(sub) { /* sets a to a-b, sets O to 0xffff if there's an underflow, 0x0 otherwise */ unsigned int acc = *a - *b; - ACCT_R(ev_b); - ACCT_R(ev_a); + ACCT_R(ev_b_addr); + ACCT_R(ev_a_addr); if (!lit_a) { *a = acc; @@ -408,7 +370,7 @@ OP_IMPL(sub) { d->o = (acc > 0xffff); d->cycle += 2; - ACCT_W(ev_a); + ACCT_W(ev_a_addr); } OP_IMPL(mul) { @@ -416,8 +378,8 @@ OP_IMPL(mul) { /* sets a to a*b, sets O to ((a*b)>>16)&0xffff */ unsigned int acc = *a * *b; - ACCT_R(ev_b); - ACCT_R(ev_a); + ACCT_R(ev_b_addr); + ACCT_R(ev_a_addr); if (!lit_a) { *a = acc; @@ -425,15 +387,15 @@ OP_IMPL(mul) { d->o = acc >> 16; d->cycle += 2; - ACCT_W(ev_a); + ACCT_W(ev_a_addr); } OP_IMPL(div) { OP_BASIC(div); /* sets a to a/b, sets O to ((a<<16)/b)&0xffff. if b==0, sets a and O to 0 instead. */ - ACCT_R(ev_b); - ACCT_R(ev_a); + ACCT_R(ev_b_addr); + ACCT_R(ev_a_addr); if (*b == 0) { if (!lit_a) { @@ -453,15 +415,15 @@ OP_IMPL(div) { d->cycle += 3; - ACCT_W(ev_a); + ACCT_W(ev_a_addr); } OP_IMPL(mod) { OP_BASIC(mod); /* sets a to a%b. if b==0, sets a to 0 instead. */ - ACCT_R(ev_b); - ACCT_R(ev_a); + ACCT_R(ev_b_addr); + ACCT_R(ev_a_addr); if (*b == 0) { if (!lit_a) { @@ -475,7 +437,7 @@ OP_IMPL(mod) { d->cycle += 3; - ACCT_W(ev_a); + ACCT_W(ev_a_addr); } OP_IMPL(shl) { @@ -483,8 +445,8 @@ OP_IMPL(shl) { /* sets a to a<>16)&0xffff */ unsigned int acc = *a << *b; - ACCT_R(ev_b); - ACCT_R(ev_a); + ACCT_R(ev_b_addr); + ACCT_R(ev_a_addr); if (!lit_a) { *a = acc; @@ -493,7 +455,7 @@ OP_IMPL(shl) { d->cycle += 2; - ACCT_W(ev_a); + ACCT_W(ev_a_addr); } OP_IMPL(shr) { @@ -501,8 +463,8 @@ OP_IMPL(shr) { /* sets a to a>>b, sets O to ((a<<16)>>b)&0xffff */ unsigned int acc = *a >> *b; - ACCT_R(ev_b); - ACCT_R(ev_a); + ACCT_R(ev_b_addr); + ACCT_R(ev_a_addr); if (!lit_a) { *a = acc; @@ -511,15 +473,15 @@ OP_IMPL(shr) { d->cycle += 2; - ACCT_W(ev_a); + ACCT_W(ev_a_addr); } OP_IMPL(and) { OP_BASIC(and); /* sets a to a&b */ - ACCT_R(ev_b); - ACCT_R(ev_a); + ACCT_R(ev_b_addr); + ACCT_R(ev_a_addr); if (!lit_a) { *a = *a & *b; @@ -527,15 +489,15 @@ OP_IMPL(and) { d->cycle += 1; - ACCT_W(ev_a); + ACCT_W(ev_a_addr); } OP_IMPL(bor) { OP_BASIC(bor); /* sets a to a|b */ - ACCT_R(ev_b); - ACCT_R(ev_a); + ACCT_R(ev_b_addr); + ACCT_R(ev_a_addr); if (!lit_a) { *a = *a | *b; @@ -543,21 +505,21 @@ OP_IMPL(bor) { d->cycle += 1; - ACCT_W(ev_a); + ACCT_W(ev_a_addr); } OP_IMPL(xor) { OP_BASIC(xor); /* sets a to a^b */ - ACCT_R(ev_b); - ACCT_R(ev_a); + ACCT_R(ev_b_addr); + ACCT_R(ev_a_addr); if (!lit_a) { *a = *a ^ *b; } - ACCT_W(ev_a); + ACCT_W(ev_a_addr); d->cycle += 1; } @@ -566,8 +528,8 @@ OP_IMPL(ife) { OP_BASIC(ife); /* performs next instruction only if a==b */ - ACCT_R(ev_b); - ACCT_R(ev_a); + ACCT_R(ev_b_addr); + ACCT_R(ev_a_addr); if (*a == *b) { /* */ @@ -583,8 +545,8 @@ OP_IMPL(ifn) { OP_BASIC(ifn); /* performs next instruction only if a!=b */ - ACCT_R(ev_b); - ACCT_R(ev_a); + ACCT_R(ev_b_addr); + ACCT_R(ev_a_addr); if (*a != *b) { /* */ @@ -600,8 +562,8 @@ OP_IMPL(ifg) { OP_BASIC(ifg); /* performs next instruction only if a>b */ - ACCT_R(ev_b); - ACCT_R(ev_a); + ACCT_R(ev_b_addr); + ACCT_R(ev_a_addr); if (*a > *b) { /* */ @@ -617,8 +579,8 @@ OP_IMPL(ifb) { OP_BASIC(ifb); /* performs next instruction only if (a&b)!=0 */ - ACCT_R(ev_b); - ACCT_R(ev_a); + ACCT_R(ev_b_addr); + ACCT_R(ev_a_addr); if ((*a & *b) != 0) { /* */ @@ -651,7 +613,7 @@ static const struct opcode_entry opcode_basic_entries[] = { }; static inline -void dump_operand_value_(WORD value, WORD nextword) { +void dump_operand_value_(DCPU16_WORD value, DCPU16_WORD nextword) { if (value <= 0x07) { printf(" %c", regnames_[value]); } else if (value <= 0x0f) { @@ -671,36 +633,37 @@ void dump_operand_value_(WORD value, WORD nextword) { } } + /* split a word into the parts of an instruction, and determine how many words it takes up in total */ static inline -void instruction_decode_(struct dcpu16 *d, WORD addr, WORD *opcode, WORD *a, WORD *b, unsigned int *instr_len) { +void instruction_decode_(struct dcpu16 *d, DCPU16_WORD addr, DCPU16_WORD *opcode, DCPU16_WORD *a, DCPU16_WORD *b, DCPU16_WORD *instr_len) { *opcode = d->ram[addr] & ((1 << OPCODE_BASIC_BITS) - 1); - *a = (d->ram[addr] >> OPCODE_BASIC_BITS) & ((1 << 6) - 1); - *b = (d->ram[addr] >> (OPCODE_BASIC_BITS + 6)) & ((1 << 6) - 1); - *instr_len = 1; - /* both basic and nbi opcodes use their b operand */ - if ( (*b >= 0x10 && *b <= 0x17) || *b == 0x1e || *b == 0x1f ) - *instr_len += 1; - /* but only basic uses a */ - if (*opcode - && ((*a >= 0x10 && *a <= 0x17) || *a == 0x1e || *a == 0x1f) ) + *a = (d->ram[addr] >> OPCODE_BASIC_BITS) & ((1 << OPCODE_OPERAND_BITS) - 1); + *b = (d->ram[addr] >> (OPCODE_BASIC_BITS + OPCODE_OPERAND_BITS)) & ((1 << OPCODE_OPERAND_BITS) - 1); + if (instr_len) { + *instr_len = 1; + /* both basic and nbi opcodes use their b operand */ + if ( (*b >= 0x10 && *b <= 0x17) || *b == 0x1e || *b == 0x1f ) *instr_len += 1; + /* but only basic uses a */ + if (*opcode + && ((*a >= 0x10 && *a <= 0x17) || *a == 0x1e || *a == 0x1f) ) + *instr_len += 1; + } } /* dcpu16_disassemble_print - print the words of the instruction at addr, followed by its assembly - 7c01 0030 ; SET A, - 7de1 1000 0020 ; SET [0x1000], 0x0020 - 7803 1000 ; SUB A, - c00d ; IFN A, + print the words of the instruction at addr, followed by its assembly representation + returns the length of the instruction in words */ -WORD dcpu16_disassemble_print(struct dcpu16 *d, WORD addr) { - WORD opcode, a, b; - unsigned int instr_len, i; +DCPU16_WORD dcpu16_disassemble_print(struct dcpu16 *d, DCPU16_WORD addr) { + DCPU16_WORD opcode, a, b, instr_len, i; const struct opcode_entry *e; unsigned int indent = 0; unsigned int partial = 0; + if (!d) return 0; + /* Check the previous instruction, to see if this one should be indented. This check isn't foolproof, as preceeding addresses @@ -753,31 +716,52 @@ WORD dcpu16_disassemble_print(struct dcpu16 *d, WORD addr) { return instr_len; } +/* execute the next instruction */ void dcpu16_step(struct dcpu16 *d) { - WORD opcode; - WORD val_a, val_b; + DCPU16_WORD opcode, a, b, instr_len; const struct opcode_entry *e; - /* decode opcode and invoke */ + if (!d) return; - opcode = (d->ram[ d->pc ] >> OPCODE_BASIC_SHIFT) & ((1 << OPCODE_BASIC_BITS) - 1); - val_a = (d->ram[d->pc] >> (OPCODE_BASIC_SHIFT + OPCODE_BASIC_BITS)) & ((1 << 6) - 1); - val_b = (d->ram[d->pc] >> (OPCODE_BASIC_SHIFT + OPCODE_BASIC_BITS + 6)) & ((1 << 6) - 1); + /* + PC is advanced while decoding the operands by the opcode functions. + Things like this could be organized a little better.. + */ + instruction_decode_(d, d->pc, &opcode, &a, &b, NULL); - d->pc++; + d->pc++; /* all instructions take at least one word */ for (e = opcode_basic_entries; e->impl; e++) { if (e->value == opcode) { - TRACE(">> %s 0x%04x, 0x%04x", e->name, val_a, val_b); - e->impl(d, val_a, val_b); + TRACE(">> %s 0x%04x, 0x%04x", e->name, a, b); + e->impl(d, a, b); break; } } + + /* and jump over next instr if needed */ + if (d->skip_) { + instruction_decode_(d, d->pc, &opcode, &a, &b, &instr_len); + d->pc += instr_len; + d->skip_ = 0; + TRACE("++ SKIPPED %x words", instr_len); + } } +/* + print the current state of the machine + shows current cycle count, registers, and next instruction +*/ void dcpu16_state_print(struct dcpu16 *d) { unsigned int i; + if (!d) return; + + printf(" "); + for (i = 0; i < 8; i++) + printf(" %c:0x%04x", regnames_[i], d->reg[i]); + printf("\n"); + printf("(0x%08llx) %2s:0x%04x %2s:0x%04x %2s:0x%04x [%2s]:", d->cycle, "O", d->o, @@ -786,20 +770,18 @@ void dcpu16_state_print(struct dcpu16 *d) { "PC"); dcpu16_disassemble_print(d, d->pc); - printf("\n "); - - for (i = 0; i < 8; i++) - printf(" %c:0x%04x", regnames_[i], d->reg[i]); printf("\n"); } /* dcpu16_dump_ram * print raw ram contents from start to stop */ -void dcpu16_dump_ram(struct dcpu16 *d, WORD start, WORD end) { +void dcpu16_dump_ram(struct dcpu16 *d, DCPU16_WORD start, DCPU16_WORD end) { unsigned int i, j; const unsigned int n = 8; /* words per line */ + if (!d) return; + for (i = start, j = 0; i <= end; i++, j++) { if (j % n == 0) printf("0x%04x:\t", i); @@ -809,10 +791,39 @@ void dcpu16_dump_ram(struct dcpu16 *d, WORD start, WORD end) { printf("\n"); } +/* dcpu16_acct_add + * 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)) { + struct dcpu16_acct_cb cb; + + cb.mask = mask; + cb.fn = fn; + + if (vm->cb_table_entries_ == vm->cb_table_allocated_) { + size_t new_entries = vm->cb_table_allocated_ + 32; + void *tmp_ptr = realloc(vm->cb_table_, new_entries * sizeof *(vm->cb_table_)); + if (tmp_ptr == NULL) { + fprintf(stderr, "%s():%s", "realloc", strerror(errno)); + return -1; + } + vm->cb_table_ = tmp_ptr; + vm->cb_table_allocated_ += 32; + } + + memcpy(vm->cb_table_ + vm->cb_table_entries_, &cb, sizeof cb); + vm->cb_table_entries_++; + + return 0; +} + /* dcpu16_reset * resets a dcpu16 instance to initial state */ void dcpu16_reset(struct dcpu16 *d) { + if (!d) return; + memset(d, 0, sizeof *d); } @@ -833,6 +844,8 @@ struct dcpu16 *dcpu16_new(void) { * release a dcpu16 instance */ void dcpu16_delete(struct dcpu16 **vm) { + if (!vm || !*vm) return; + free(*vm); *vm = NULL; } diff --git a/dcpu16.h b/dcpu16.h index a96bd41..005aad3 100644 --- a/dcpu16.h +++ b/dcpu16.h @@ -11,12 +11,11 @@ typedef unsigned short DCPU16_WORD; typedef unsigned int dcpu16_acct_event_; #define DCPU16_ACCT_EV_READ (1<<1) #define DCPU16_ACCT_EV_WRITE (1<<2) -#define DCPU16_ACCT_RAM (1<<3) +#define DCPU16_ACCT_EV_NOP (1<<3) struct dcpu16_acct_cb { void (*fn)(dcpu16_acct_event_ e, DCPU16_WORD addr); - dcpu16_acct_event_ match_all; - dcpu16_acct_event_ match_any; + dcpu16_acct_event_ mask; }; /* a self-contained dcpu16 core */ @@ -50,7 +49,7 @@ void dcpu16_dump_ram(struct dcpu16 *, DCPU16_WORD, DCPU16_WORD); DCPU16_WORD dcpu16_disassemble_print(struct dcpu16 *, DCPU16_WORD); /* register a callback for an accounting event */ -int dcpu16_acct_add(struct dcpu16 *, dcpu16_acct_event_ match_all, dcpu16_acct_event_ match_any, void (*fn)(dcpu16_acct_event_, DCPU16_WORD)); +int dcpu16_acct_add(struct dcpu16 *, dcpu16_acct_event_ mask, void (*fn)(dcpu16_acct_event_, DCPU16_WORD)); /* execute the next instruction */ void dcpu16_step(struct dcpu16 *); diff --git a/vm-dcpu16.c b/vm-dcpu16.c index 17effb6..df86455 100644 --- a/vm-dcpu16.c +++ b/vm-dcpu16.c @@ -43,7 +43,8 @@ void sigint_handler_(int sig) { #define VERBOSE_PRINTF(...) do { if (opt_.verbose) printf(__VA_ARGS__); } while (0) -static void usage_(char *prog, unsigned int full) { +static +void usage_(char *prog, unsigned int full) { FILE *f = full ? stdout : stderr; char *x = strrchr(prog, '/'); @@ -130,13 +131,17 @@ int buf_tok_vect_(char ***v, int *c, char *buf) { return 0; } -/* resets the instance and loads an image into ram starting at addr */ +/* + resets the vm if addr is zero then + loads an image from filename into ram starting at addr +*/ static int file_load_(struct dcpu16 *vm, char *filename, DCPU16_WORD addr) { FILE *f; size_t r; - dcpu16_reset(vm); + if (!addr) + dcpu16_reset(vm); f = fopen(filename, "rb"); if (f == NULL) { @@ -196,6 +201,21 @@ COMMAND_HELP(quit) { } +COMMAND_IMPL(reset) { + (void)arg_count, (void)arg_vector; + + dcpu16_reset(vm); + printf("initialized\n"); + return 0; +} +COMMAND_HELP(reset) { + fprintf(f, "\treset\n"); + if (summary) return; + + fprintf(f, "Clears and reinitializes emulator.\n"); +} + + COMMAND_IMPL(load) { int addr = 0; @@ -379,6 +399,7 @@ static struct command_ command_table_[] = { COMMAND_ENTRY(disassemble, 0, 2), COMMAND_ENTRY(step, 0, 1), COMMAND_ENTRY(run, 0, 0), + COMMAND_ENTRY(reset, 0, 0), { NULL, 0, 0, NULL, NULL } }; -- 2.43.2