fixed instruction length issue
authorJustin Wind <justin.wind@gmail.com>
Fri, 13 Apr 2012 19:14:27 +0000 (12:14 -0700)
committerJustin Wind <justin.wind@gmail.com>
Fri, 13 Apr 2012 19:14:27 +0000 (12:14 -0700)
dcpu16.c: fixed instruction length issues
dcpu16.c: fixed and cleaned up disassembly function
vm-dcpu16.c: fixed argument handling for some commands

Makefile
as-dcpu16.c
dcpu16.c
dcpu16.h
vm-dcpu16.c

index ad94a65a6dcd3f1aadad04f7c551a78a69564b47..1a931a1c8f709724d37f398aabfaea17c30c6534 100644 (file)
--- 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
index c61884232c573a3469890df36c251f2f7d154b53..798bf7ece0d8061a01c50e66b258cc64bd710be2 100644 (file)
@@ -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$";
index e43c09103b74d0d92c9d10e8af3238f064306437..b21f0f9cda33298895f365c982ad7b09c1125871 100644 (file)
--- 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) {
index af964e7e46c561f1923e5f49ff8dc5f8768623e8..a96bd417ba1d8760a64be1817770ec452b68ebaa 100644 (file)
--- 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));
index 522682a6732e871ff50157323a227b85e619e76e..17effb6a558db14d11698cfceaf56d452c202252 100644 (file)
@@ -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;
 }