From 34245ba6868f5d0580c3f16dbd68a4f973ef27f8 Mon Sep 17 00:00:00 2001 From: Justin Wind Date: Sun, 22 Apr 2012 13:20:10 -0700 Subject: [PATCH] fixes for assembler - label addrs and DAT statements Assembler now handles DATs correctly, fixed some issues with labels getting incorrect addresses. Assembler still does not correctly generate short-form addresses, though. Added README file. --- README | 16 +++++++++++++++ as-dcpu16.c | 59 +++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 README diff --git a/README b/README new file mode 100644 index 0000000..dedc1a5 --- /dev/null +++ b/README @@ -0,0 +1,16 @@ +A DCPU16 implementation, in late-model C. + Not the fastest, + nor the fanciest, + just another tree in the forest. + +This is an emulator system for an imaginary computing unit from 0x10c.com, based on initial specifications and speculations. + +Developed on Lion and targeting command-line operation, this ought work on most similar platforms, but portability has not been tested to any great degree. + +The processor-core emulator is complete and embeddable. The sparse API allows stepping the cpu, and a rudimentary callback system allows for watching system memory access, for doing all sorts of extra things, such as driving the included display driver, which can manage to splat some text glyphs into a tiny screen buffer, and render out make a PNM image of the current state. With a little more work, it could support such as loadable/pluggable modules, or something fancy like that. + +For support utilities, there's a simple shell for running and manipulating a complete emulated system, as well as a woefully inelegant brute-force assembler, which needs a few additional features to be really useful beyond proof-of-concept. + +Enjoy. + +Justin Wind diff --git a/as-dcpu16.c b/as-dcpu16.c index 820b837..f22e848 100644 --- a/as-dcpu16.c +++ b/as-dcpu16.c @@ -22,6 +22,7 @@ * needs ability to specify location for code or data * needs ability to specify label as relative to another label * short labels not correctly computed + * in label struct, store index of instruction rather than ptr, ptrs for iteration in addr calculation are ugly */ static const char * const src_id_ = "$Id$"; @@ -140,9 +141,14 @@ void label_addr_calculate_(struct dynamic_array *instructionps, struct dynamic_a l = (struct label_ *)DYNARRAY_ITEM(*labels, i); + DEBUG_PRINTFQ("%s: calculating address of label '%s'\n", __func__, l->label); + +#if 0 +force full resolution while debugging /* if it's already calculated, great. */ if (l->ready) continue; +#endif /* * starting at the instruction for this label, @@ -150,14 +156,24 @@ void label_addr_calculate_(struct dynamic_array *instructionps, struct dynamic_a * until we get to the start or a known prior label address. * update our label with the freshly calculated addr */ - for (instr = ((struct label_ *)DYNARRAY_ITEM(*labels, i))->instr; - instr >= (struct instruction_ **)DYNARRAY_ITEM(*instructionps, 0); - instr--) { - if ((*instr)->ready) - DEBUG_PRINTF("%s: instr not ready\n", __func__); + /* first fetch the instruction associated with the label we want to know about.. */ + /* the addr of this instruction will be whatever follows all the preceding instructions */ + /* so back up one before counting instruction lengths... */ + instr = ((struct label_ *)DYNARRAY_ITEM(*labels, i))->instr; + /* is it the first one? */ + if (instr == (struct instruction_ **)DYNARRAY_ITEM(*instructionps, 0)) + break; + + instr--; + + while (instr >= (struct instruction_ **)DYNARRAY_ITEM(*instructionps, 0)) { + if ((*instr)->ready == 0) + DEBUG_PRINTF("%s: instr '%s' not ready\n", __func__, (*instr)->opcode); word_count += (*instr)->length; + DEBUG_PRINTF("%s: instr '%s' takes '%u' bytes\n", __func__, (*instr)->opcode, (*instr)->length); + /* have we come across an instruction which a label points to? it should already be calculated, so just add that on and be done */ if ((*instr)->label @@ -174,6 +190,7 @@ void label_addr_calculate_(struct dynamic_array *instructionps, struct dynamic_a word_count += addr; break; } + instr--; } l->addr = word_count; l->ready = 1; @@ -373,6 +390,8 @@ int value_bits_(struct dynamic_array *labels, const char *operand_orig, DCPU16_W char *reg; char *constant; + DEBUG_PRINTFQ("is multipart.. "); + /* eat the plus */ *ep = '\0'; ep++; @@ -410,10 +429,13 @@ int value_bits_(struct dynamic_array *labels, const char *operand_orig, DCPU16_W *nextwordused += 1; DEBUG_PRINTFQ("is a dereferenced register (%c) + constant (%hu)\n", *reg, *nextword); return 0x10 | register_enumerate_(*reg); - } else if (errno) { + } else if (errno == ERANGE) { +#if 0 +oh, right, labels fall through DEBUG_PRINTFQ("is out of range\n"); fprintf(stderr, "trouble with operand '%s': %s\n", operand_orig, strerror(errno)); return -1; +#endif } /* what? still here? assume it's a label, I guess */ @@ -509,9 +531,9 @@ int instruction_print_(struct instruction_ *i, unsigned int with_label) { int r; if (with_label) - r = printf("%-16s %3s", i->label ? i->label : "", i->opcode); - else - r = printf("%3s", i->opcode); + r = printf("%-16s ", i->label ? i->label : ""); + + r = printf("%3s", i->opcode ? i->opcode : ""); for (o = i->operands; o; o = o->next) r += printf(" %s%s", o->operand, o->next ? "," : ""); @@ -523,6 +545,7 @@ int instruction_print_(struct instruction_ *i, unsigned int with_label) { * Parses a zero-terminated line of input into a newly-allocated struct instruction_. * [label] instruction [operand[,operand[,...]]] * Does no validation of contents of any of these tokens, as of yet. + * does not clean up after itself if a malloc fails */ static int tokenize_line_(char *line, struct instruction_ **next_instr) { @@ -594,6 +617,7 @@ int tokenize_line_(char *line, struct instruction_ **next_instr) { /* if we have an opcode, we'll need at least one word to compile instruction */ instr_words_needed++; + /* build a list of operands to hang off this instruction */ while ( (x = strqtok_r(NULL, ",", '\\', quotes, &qt, &st)) ) { struct operand_ *new_operand; char *y; @@ -688,13 +712,25 @@ int instr_assemble_(struct dynamic_array *labels, struct instruction_ *i, unsign if (opt_.verbose > 2) { printf("%s: assembling %p ", __func__, i); instruction_print_(i, 1); - printf("(line :%zu)\n", i->src_line); + printf("(line %zu)\n", i->src_line); } +#if 0 +while debugging, always reassemble if (i->ready) { /* already assembled, nothing to do */ return 0; } +#endif + + if (i->opcode == NULL) { + assert(i->label); + assert(i->operands == NULL); + /* just a label, move along */ + i->length = 0; + i->ready = 1; + return 0; + } /* special case DAT */ if (strncasecmp(i->opcode, "DAT", 3) == 0) { @@ -710,6 +746,7 @@ int instr_assemble_(struct dynamic_array *labels, struct instruction_ *i, unsign DEBUG_PRINTF("DAT operand:'%s' next:%p\n", o->operand, o->next); /* is this a string? */ + /* does it start with a quote, and end with the same quote? */ if ( (x = strchr("\"'`", o->operand[0])) ) { dat_len = strlen(o->operand) - 1; if (o->operand[dat_len] == *x) { @@ -746,7 +783,7 @@ int instr_assemble_(struct dynamic_array *labels, struct instruction_ *i, unsign /* otherwise assume it's a label, even if we don't know what it is */ if (label_addr_(labels, o->operand, &i->instr_words[i->length])) { - DEBUG_PRINTF("(deferred label resolution)\n"); + DEBUG_PRINTF("(deferred label '%s' resolution)\n", o->operand); incomplete = 1; } i->length++; -- 2.45.2