From: Justin Wind Date: Fri, 13 Apr 2012 19:14:27 +0000 (-0700) Subject: fixed instruction length issue X-Git-Url: http://git.squeep.com/?p=dcpu16;a=commitdiff_plain;h=e9cced1de1d6428996d255243b48513e82f233a5 fixed instruction length issue dcpu16.c: fixed instruction length issues dcpu16.c: fixed and cleaned up disassembly function vm-dcpu16.c: fixed argument handling for some commands --- diff --git a/Makefile b/Makefile index ad94a65..1a931a1 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,12 @@ PROGRAMS = as-dcpu16 vm-dcpu16 CFLAGS = -g -Wall -Wextra -pedantic -std=c99 LDFLAGS = -lreadline +HEADERS = dcpu16.h + all: $(PROGRAMS) +%.o: %.c $(HEADERS) + vm-dcpu16: vm-dcpu16.o dcpu16.o as-dcpu16: as-dcpu16.o diff --git a/as-dcpu16.c b/as-dcpu16.c index c618842..798bf7e 100644 --- a/as-dcpu16.c +++ b/as-dcpu16.c @@ -17,6 +17,7 @@ * * TODO * needs ability to specify location for code or data + * short labels not correctly computed */ static const char * const src_id_ = "$Id$"; diff --git a/dcpu16.c b/dcpu16.c index e43c091..b21f0f9 100644 --- a/dcpu16.c +++ b/dcpu16.c @@ -129,7 +129,7 @@ void acct_event_(struct dcpu16 *vm, dcpu16_acct_event_ ev, DCPU16_WORD addr) { /* value_decode_ * sets *v to be the destination of the value - * workv is buffer to use to accumulate literal value before use + * workv is buffer to use to accumulate literal value before use, one exists for either potential instruction operand * returns true if destination points to literal (id est *v should ignore writes) */ static @@ -148,7 +148,7 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v, /* if we're skipping this instruction, just advance the pc if needed */ if (d->skip_) { TRACE(">> SKIP decode"); - if (value == 0x1e || value == 0x1f) + if ((value >= 0x10 && value <= 0x17) || value == 0x1e || value == 0x1f) d->pc++; return retval; } @@ -369,7 +369,7 @@ OP_IMPL(set) { ACCT_W(ev_a); /* only set non-literal target */ - if (val_a < 0x1f) { + if (!lit_a) { *a = *b; } @@ -384,7 +384,7 @@ OP_IMPL(add) { ACCT_R(ev_b); ACCT_R(ev_a); - if (val_a < 0x1f) { + if (!lit_a) { *a = acc; } d->o = (acc > 0xffff); @@ -402,11 +402,10 @@ OP_IMPL(sub) { ACCT_R(ev_b); ACCT_R(ev_a); - if (val_a < 0x1f) { + if (!lit_a) { *a = acc; - d->o = (acc > 0xffff); - } + d->o = (acc > 0xffff); d->cycle += 2; ACCT_W(ev_a); @@ -420,7 +419,7 @@ OP_IMPL(mul) { ACCT_R(ev_b); ACCT_R(ev_a); - if (val_a < 0x1f) { + if (!lit_a) { *a = acc; } d->o = acc >> 16; @@ -437,14 +436,14 @@ OP_IMPL(div) { ACCT_R(ev_a); if (*b == 0) { - if (val_a < 0x1f) { + if (!lit_a) { *a = 0; } d->o = 0; } else { unsigned int acc = *a / *b; - if (val_a < 0x1f) { + if (!lit_a) { *a = acc; } @@ -465,11 +464,11 @@ OP_IMPL(mod) { ACCT_R(ev_a); if (*b == 0) { - if (val_a < 0x1f) { + if (!lit_a) { *a = 0; } } else { - if (val_a < 0x1f) { + if (!lit_a) { *a = *a % *b; } } @@ -487,7 +486,7 @@ OP_IMPL(shl) { ACCT_R(ev_b); ACCT_R(ev_a); - if (val_a < 0x1f) { + if (!lit_a) { *a = acc; } d->o = acc >> 16; @@ -505,7 +504,7 @@ OP_IMPL(shr) { ACCT_R(ev_b); ACCT_R(ev_a); - if (val_a < 0x1f) { + if (!lit_a) { *a = acc; } d->o = (*a << 16) >> *b; @@ -522,7 +521,7 @@ OP_IMPL(and) { ACCT_R(ev_b); ACCT_R(ev_a); - if (val_a < 0x1f) { + if (!lit_a) { *a = *a & *b; } @@ -538,7 +537,7 @@ OP_IMPL(bor) { ACCT_R(ev_b); ACCT_R(ev_a); - if (val_a < 0x1f) { + if (!lit_a) { *a = *a | *b; } @@ -554,7 +553,7 @@ OP_IMPL(xor) { ACCT_R(ev_b); ACCT_R(ev_a); - if (val_a < 0x1f) { + if (!lit_a) { *a = *a ^ *b; } @@ -651,12 +650,13 @@ static const struct opcode_entry opcode_basic_entries[] = { {0x0, "", NULL } }; -void dump_value(WORD value, WORD nextword) { - if (value < 0x07) { +static inline +void dump_operand_value_(WORD value, WORD nextword) { + if (value <= 0x07) { printf(" %c", regnames_[value]); - } else if (value < 0x0f) { + } else if (value <= 0x0f) { printf(" [%c]", regnames_[value & 0x07]); - } else if (value < 0x17) { + } else if (value <= 0x17) { printf(" [0x%04x + %c]", nextword, regnames_[value & 0x07]); } else switch (value) { case 0x18: printf(" POP"); break; @@ -671,50 +671,86 @@ void dump_value(WORD value, WORD nextword) { } } -void dcpu16_disassemble_print(struct dcpu16 *d, WORD addr) { +/* 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) { + *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) ) + *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, + */ +WORD dcpu16_disassemble_print(struct dcpu16 *d, WORD addr) { WORD opcode, a, b; - unsigned int instr_len = 1; + unsigned int instr_len, i; const struct opcode_entry *e; - - opcode = (d->ram[addr] >> OPCODE_BASIC_SHIFT) & ((1 << OPCODE_BASIC_BITS) - 1); - a = (d->ram[addr] >> (OPCODE_BASIC_SHIFT + OPCODE_BASIC_BITS)) & ((1 << 6) - 1); - b = (d->ram[addr] >> (OPCODE_BASIC_SHIFT + OPCODE_BASIC_BITS + 6)) & ((1 << 6) - 1); - - assert(opcode <= 0x0f); - assert(a <= 0x3f); - assert(b <= 0x3f); - - printf("%04x", d->ram[addr]); - - if (opcode != 0) - { - if (a == 0x1e || a == 0x1f) { - printf(" %04x", d->ram[addr + instr_len]); - instr_len++; + unsigned int indent = 0; + unsigned int partial = 0; + + /* + Check the previous instruction, to see if this one should be + indented. This check isn't foolproof, as preceeding addresses + could be data which happen to match instructions.. + */ + for (i = 3; i; i--) { + instruction_decode_(d, addr - i, &opcode, &a, &b, &instr_len); + if (instr_len > i) + partial++; + if (instr_len == i && opcode >= 0xc) { + indent++; + break; } } - if (b == 0x1e || b == 0x1f) { - printf(" %04x", d->ram[addr + instr_len]); - instr_len++; - } + + /* now get what we're really interested in */ + instruction_decode_(d, addr, &opcode, &a, &b, &instr_len); if (opcode) e = opcode_basic_entries + opcode; else e = opcode_nbi_entries + ( (a < OPCODE_NBI_MAX) ? a : (OPCODE_NBI_MAX - 1) ); - printf("%s%s ; %s", + /* show the raw words */ + printf("%04x", d->ram[addr]); + for (i = 1; i < instr_len; i++) { + printf(" %04x", d->ram[addr + i]); + } + + /* align things neatly, show the instruction */ + printf("%s%s ;%s%s%s", instr_len < 3 ? " " : "", instr_len < 2 ? " " : "", + partial ? "*" : " ", + indent ? " " : "", e->name); - if (opcode != 0) { - dump_value(a, d->ram[addr + 1]); - if (a == 0x1e || a == 0x1f) + + /* show the operands */ + i = 0; + if (opcode) { + dump_operand_value_(a, d->ram[addr + 1]); + if ((a >= 0x10 && a <= 0x17) || a == 0x1e || a == 0x1f) addr++; printf(","); } - dump_value(b, d->ram[addr + 1]); + if (opcode || a) + dump_operand_value_(b, d->ram[addr + 1]); + + return instr_len; } void dcpu16_step(struct dcpu16 *d) { diff --git a/dcpu16.h b/dcpu16.h index af964e7..a96bd41 100644 --- a/dcpu16.h +++ b/dcpu16.h @@ -46,8 +46,8 @@ void dcpu16_state_print(struct dcpu16 *); /* print the contents of ram from second to third argument */ void dcpu16_dump_ram(struct dcpu16 *, DCPU16_WORD, DCPU16_WORD); -/* print the instruction at the specified address */ -void dcpu16_disassemble_print(struct dcpu16 *, DCPU16_WORD); +/* print the instruction at the specified address, returns number of words consumed in decoding */ +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)); diff --git a/vm-dcpu16.c b/vm-dcpu16.c index 522682a..17effb6 100644 --- a/vm-dcpu16.c +++ b/vm-dcpu16.c @@ -230,8 +230,8 @@ COMMAND_IMPL(dump) { int i; for (i = 1; i < arg_count; i++) { - addr[i] = str_to_word_(arg_vector[i]); - if (addr[i] < 0) { + addr[i-1] = str_to_word_(arg_vector[i]); + if (addr[i-1] < 0) { fprintf(stderr, "address '%s' is not a valid word: %s\n", arg_vector[i], strerror(errno)); return 0; } @@ -261,8 +261,8 @@ COMMAND_IMPL(disassemble) { int i; for (i = 1; i < arg_count; i++) { - addr[i] = str_to_word_(arg_vector[i]); - if (addr[i] < 0) { + addr[i-1] = str_to_word_(arg_vector[i]); + if (addr[i-1] < 0) { fprintf(stderr, "address '%s' is not a valid word: %s\n", arg_vector[i], strerror(errno)); return 0; } @@ -275,8 +275,11 @@ COMMAND_IMPL(disassemble) { return 0; } - for (i = addr[0]; i <= addr[1]; i++) - dcpu16_disassemble_print(vm, i), printf("\n"); + for (i = addr[0]; i <= addr[1]; /* */ ) { + printf("0x%04x: ", i); + i += dcpu16_disassemble_print(vm, i); + printf("\n"); + } return 0; }