char *label; /* set if a label points here */
char *opcode; /* tokenized instruction text */
struct operand_ *operands; /* list of operands */
- unsigned int length; /* words */
unsigned int ready : 1; /* bytecode computed? */
+ unsigned int length; /* number of words of bytecode */
DCPU16_WORD instr_words[];
};
-enum operand_types_{
- OT_DIRECT, /* these operands simply render their contents into bytecode */
- OT_NEXT, /* these operands increase instruction length */
- OT_LABEL /* labels need to be computed then converted to other types */
-};
-
struct operand_ {
struct operand_ *next;
char *operand; /* tokenized operand text */
- enum operand_types_ type;
- union {
- DCPU16_WORD word_value;
- struct instruction_ *label_destination;
- } value;
};
};
-/* note label table holds its own structs, not pointers */
+/* note label table holds its own structs, not pointers like instruction list */
struct label_ {
char *label; /* name of label */
- struct instruction_ *instr;
+ struct instruction_ **instr; /* pointer into instruction list table */
+ unsigned int ready : 1; /* do we know where this label is yet? */
+ DCPU16_WORD addr;
};
#define LL_SIZE(entries) (((entries) * sizeof(struct label_ *)) + sizeof(struct label_list_))
* Justin Wind <justin.wind@gmail.com>
* 2012 04 05 - implementation started
* 2012 04 06 - first functionality achieved
+ * 2012 04 09 - minor cleanups
*
* TODO
* move cli driver to separate module
+ * drop checks for assigning to literals -- it won't affect anything anyhow
+ * debug short literal decoding
*/
static const char * const src_id_ = "$Id$";
WORD pc; /* program counter */
WORD sp; /* stack pointer */
WORD o; /* overflow */
- unsigned int skip_ : 1; /* */
+ unsigned int skip_ : 1; /* skip execution of next instruction */
WORD ram[RAM_SIZE]; /* memory */
};
-static unsigned int trace_mode_ = 0; /* turn on for overly verbose internals */
+static unsigned int trace_mode_ = 0; /* spew overly verbose internals */
-#define WARN(...) warn(__VA_ARGS__)
-static inline void warn(char *fmt, ...) __attribute__((format(printf, 1, 2)));
-static inline void warn(char *fmt, ...) {
+#define WARN(...) do { if (warn_cb_) warn_cb_(__VA_ARGS__); } while (0)
+static inline void warn_(char *fmt, ...) __attribute__((format(printf, 1, 2)));
+static inline
+void warn_(char *fmt, ...) {
va_list ap;
fprintf(stderr, "!!! ");
fprintf(stderr, "\n");
fflush(stderr);
}
+static void (*warn_cb_)(char *fmt, ...) = warn_;
+void dcpu16_warn_cb_set(void (*fn)(char *fmt, ...)) {
+ warn_cb_ = fn;
+}
-
-#define TRACE(...) do { if (trace_mode_) trace(__VA_ARGS__); } while (0)
-static inline void trace(char *fmt, ...) __attribute__((format(printf, 1, 2)));
+#define TRACE(...) do { if (trace_cb_ && trace_mode_) trace_cb_(__VA_ARGS__); } while (0)
+static inline void trace_(char *fmt, ...) __attribute__((format(printf, 1, 2)));
static inline
-void trace(char *fmt, ...) {
+void trace_(char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
fprintf(stdout, "\n");
fflush(stdout);
}
+static void (*trace_cb_)(char *fmt, ...) = trace_;
+void dcpu16_trace_cb_set(void (*fn)(char *fmt, ...)) {
+ trace_cb_ = fn;
+}
+
/* sets *v to be the destination of the value */
WORD nextword;
unsigned int retval = 0;
- assert(value >= 0x00 && value <= 0x3f);
+ assert(value <= 0x3f);
/* does this value indicate a literal */
if (value >= 0x1f)
#define OP_IMPL(x) static void op_##x(struct dcpu16 *d, WORD val_a, WORD val_b)
-#define OP_NBI_ (void)val_b
+#define OP_NBI_ (void)val_b, (void)b
#define OP_BASIC_ (void)value_decode(d, val_b, &d->reg_work_[0], &b)
#define OP_TYPE(op_type) WORD *a, *b;\
unsigned int lit_a;\
do {\
- assert(d != NULL);\
lit_a = value_decode(d, val_a, &d->reg_work_[0], &a);\
op_type;\
if (d->skip_) {\
return;\
}\
} while (0)
-
-
-#define OP_BASIC(x) WORD *a, *b;\
- unsigned int lit_a;\
- do {\
- assert(d != NULL);\
- lit_a = value_decode(d, val_a, &d->reg_work_[0], &a);\
- value_decode(d, val_b, &d->reg_work_[1], &b);\
- if (d->skip_) {\
- TRACE("++ SKIPPED");\
- d->skip_ = 0;\
- return;\
- }\
- } while(0)
-
-#define OP_NBI(x) WORD *a;\
- unsigned int lit_a;\
- do {\
- assert(d != NULL);\
- lit_a = value_decode(d, val_a, &d->reg_work_[0], &a);\
- (void)val_b;\
- if (d->skip_) {\
- TRACE("++ SKIPPED");\
- d->skip_ = 0;\
- return;\
- }\
- } while(0)
+#define OP_BASIC(x) OP_TYPE(OP_BASIC_)
+#define OP_NBI(x) OP_TYPE(OP_NBI_)
/* extended opcodes */
instructions only have one operand.
*/
OP_IMPL(_nbi_) {
- assert(d != NULL);
/* non-basic instruction */
/* don't do normal value decoding here */
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);
+ assert(opcode <= 0x0f);
+ assert(a <= 0x3f);
+ assert(b <= 0x3f);
- printf("next instr 0x%04x: %04x", addr, d->ram[addr]);
+ printf(" next instr 0x%04x: %04x", addr, d->ram[addr]);
if (opcode != 0)
{
e = opcode_basic_entries + opcode;
else
e = opcode_nbi_entries + ( (a < OPCODE_NBI_MAX) ? a : (OPCODE_NBI_MAX - 1) );
- printf("\n\t%s", e->name);
+
+ printf("%s%s ; %s",
+ instr_len < 3 ? " " : "",
+ instr_len < 2 ? " " : "",
+ e->name);
if (opcode != 0) {
dump_value(a, d->ram[addr + 1]);
if (a == 0x1e || a == 0x1f)
WORD val_a, val_b;
const struct opcode_entry *e;
- /* fetch next instruction */
- if (d->pc > RAM_SIZE) { /* currently impossible */
- WARN("%s beyond %u", "PC", RAM_SIZE);
- /* d->pc %= RAM_SIZE; */
- }
+ /* decode opcode and invoke */
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);
if (full) {
fprintf(f, "\nOptions:\n"
- "\t-h -- this screen\n");
+ "\t-h -- this screen\n"
+ "\t-t -- test mode, load demo program\n"
+ "\t-v -- verbose execution tracing\n");
fprintf(f, "\n%78s\n", src_id_);
}
void dump_cpu_state(struct dcpu16 *d) {
unsigned int i;
- printf("[--- cycle:0x%08llx %2s:0x%04x %2s:0x%04x %2s:0x%04x\n",
+ printf("---- cycle:0x%08llx %2s:0x%04x %2s:0x%04x %2s:0x%04x\n",
d->cycle,
"PC", d->pc,
"SP", d->sp,
exit(EX_OSERR);
}
- while ( (c = getopt(argc, argv, "ht")) != EOF )
+ while ( (c = getopt(argc, argv, "htv")) != EOF )
{
switch (c)
{
- case 't':
+ case 'v':
trace_mode_ = 1;
+ break;
+
+ case 't':
dump_ram(m, 0, 0x001f);
testprog_load(m);
dump_ram(m, 0, 0x001f);
}
dump_cpu_state(m);
+ dump_instruction(m, m->pc);
while (fgets(buf, sizeof buf, stdin)) {
dcpu16_execute_next_instruction(m);
dump_cpu_state(m);
- if (trace_mode_)
- dump_instruction(m, m->pc);
+ dump_instruction(m, m->pc);
}
free(m);