Mercurial > hg-old > index.cgi
changeset 151:427e268e876b
renamed src to lwasm to better reflect its purpose
author | lost |
---|---|
date | Fri, 30 Jan 2009 04:01:55 +0000 |
parents | f0881c115010 |
children | 6bd4755d224f |
files | Makefile.am configure.ac doc/Makefile.am doc/README lwasm/Makefile.am lwasm/expr.c lwasm/expr.h lwasm/insn_bitbit.c lwasm/insn_gen.c lwasm/insn_indexed.c lwasm/insn_inh.c lwasm/insn_logicmem.c lwasm/insn_rel.c lwasm/insn_rlist.c lwasm/insn_rtor.c lwasm/insn_tfm.c lwasm/instab.c lwasm/instab.h lwasm/list.c lwasm/lwasm.c lwasm/lwasm.h lwasm/lwval.c lwasm/lwval.h lwasm/macro.c lwasm/main.c lwasm/output.c lwasm/parse.c lwasm/pass1.c lwasm/pass2.c lwasm/pragma.c lwasm/pseudo.c lwasm/symbol.c lwasm/util.c lwasm/util.h src/Makefile.am src/insn_gen.c src/instab.c src/instab.h src/list.c src/lwasm.c src/lwasm.h src/macro.c src/main.c src/output.c src/pragma.c src/pseudo.c |
diffstat | 46 files changed, 6694 insertions(+), 3519 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile.am Fri Jan 30 02:55:30 2009 +0000 +++ b/Makefile.am Fri Jan 30 04:01:55 2009 +0000 @@ -1,2 +1,2 @@ -SUBDIRS = src lwlink -DIST_SUBDIRS = doc src lwlink +SUBDIRS = lwasm lwlink +DIST_SUBDIRS = doc lwasm lwlink
--- a/configure.ac Fri Jan 30 02:55:30 2009 +0000 +++ b/configure.ac Fri Jan 30 04:01:55 2009 +0000 @@ -4,7 +4,7 @@ AC_CONFIG_HEADERS([src/config.h]) AC_CONFIG_FILES([ Makefile - src/Makefile + lwasm/Makefile doc/Makefile lwlink/Makefile ])
--- a/doc/Makefile.am Fri Jan 30 02:55:30 2009 +0000 +++ b/doc/Makefile.am Fri Jan 30 04:01:55 2009 +0000 @@ -1,3 +1,3 @@ -EXTRA_DIST = lwasm.txt internals.txt pseudoops.txt objectfiles.txt scripts.txt lwlink.txt +EXTRA_DIST = lwasm.txt internals.txt manual.docbook.sgml manual.html manual
--- a/doc/README Fri Jan 30 02:55:30 2009 +0000 +++ b/doc/README Fri Jan 30 04:01:55 2009 +0000 @@ -9,5 +9,5 @@ or -docbook2html -u manual.docbook.sgml && mv manual.docbook.html manual.html +docbook2html -u manual.docbook.sgml && mv manual.docbook.html manual/manual.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/Makefile.am Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,3 @@ +bin_PROGRAMS = lwasm +lwasm_SOURCES = main.c expr.c pass1.c pass2.c util.c instab.c parse.c lwasm.c insn_inh.c insn_rtor.c insn_rlist.c insn_rel.c insn_tfm.c insn_bitbit.c insn_indexed.c insn_gen.c insn_logicmem.c list.c symbol.c output.c pseudo.c macro.c pragma.c +EXTRA_DIST = instab.h lwasm.h expr.h util.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/expr.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,893 @@ +/* +expr.c +Copyright © 2008 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +This file contains the actual expression evaluator +*/ + +#define __expr_c_seen__ + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +#include "expr.h" +#include "util.h" +#include "lwasm.h" + +lwasm_expr_stack_t *lwasm_expr_stack_create(void) +{ + lwasm_expr_stack_t *s; + + s = lwasm_alloc(sizeof(lwasm_expr_stack_t)); + s -> head = NULL; + s -> tail = NULL; + return s; +} + +void lwasm_expr_stack_free(lwasm_expr_stack_t *s) +{ + while (s -> head) + { + s -> tail = s -> head; + s -> head = s -> head -> next; + lwasm_expr_term_free(s -> tail -> term); + lwasm_free(s -> tail); + } + lwasm_free(s); +} + +void lwasm_expr_term_free(lwasm_expr_term_t *t) +{ + if (t) + { + if (t -> term_type == LWASM_TERM_SYM) + lwasm_free(t -> symbol); + lwasm_free(t); + } +} + +lwasm_expr_term_t *lwasm_expr_term_create_oper(int oper) +{ + lwasm_expr_term_t *t; + + debug_message(10, "Creating operator term: %d", oper); + + t = lwasm_alloc(sizeof(lwasm_expr_term_t)); + t -> term_type = LWASM_TERM_OPER; + t -> value = oper; + return t; +} + +lwasm_expr_term_t *lwasm_expr_term_create_int(int val) +{ + lwasm_expr_term_t *t; + debug_message(10, "Creating integer term: %d", val); + + t = lwasm_alloc(sizeof(lwasm_expr_term_t)); + t -> term_type = LWASM_TERM_INT; + t -> value = val; + return t; +} + +lwasm_expr_term_t *lwasm_expr_term_create_secbase(void) +{ + lwasm_expr_term_t *t; + debug_message(10, "Creating section base term"); + + t = lwasm_alloc(sizeof(lwasm_expr_term_t)); + t -> term_type = LWASM_TERM_SECBASE; + return t; +} + +lwasm_expr_term_t *lwasm_expr_term_create_sym(char *sym) +{ + lwasm_expr_term_t *t; + + debug_message(10, "Creating symbol term: %s", sym); + + t = lwasm_alloc(sizeof(lwasm_expr_term_t)); + t -> term_type = LWASM_TERM_SYM; + t -> symbol = lwasm_strdup(sym); + return t; +} + +lwasm_expr_term_t *lwasm_expr_term_dup(lwasm_expr_term_t *t) +{ + switch (t -> term_type) + { + case LWASM_TERM_INT: + return lwasm_expr_term_create_int(t -> value); + + case LWASM_TERM_OPER: + return lwasm_expr_term_create_oper(t -> value); + + case LWASM_TERM_SYM: + return lwasm_expr_term_create_sym(t -> symbol); + + case LWASM_TERM_SECBASE: + return lwasm_expr_term_create_secbase(); + + default: + debug_message(0, "lwasm_expr_term_dup(): invalid term type %d", t -> term_type); + exit(1); + } +// can't get here +} + +void lwasm_expr_stack_push(lwasm_expr_stack_t *s, lwasm_expr_term_t *t) +{ + lwasm_expr_stack_node_t *n; + + if (!s) + { + debug_message(0, "lwasm_expr_stack_push(): invalid stack pointer"); + exit(1); + } + + n = lwasm_alloc(sizeof(lwasm_expr_stack_node_t)); + n -> next = NULL; + n -> prev = s -> tail; + n -> term = lwasm_expr_term_dup(t); + + if (s -> head) + { + s -> tail -> next = n; + s -> tail = n; + } + else + { + s -> head = n; + s -> tail = n; + } +} + +lwasm_expr_term_t *lwasm_expr_stack_pop(lwasm_expr_stack_t *s) +{ + lwasm_expr_term_t *t; + lwasm_expr_stack_node_t *n; + + if (!(s -> tail)) + return NULL; + + n = s -> tail; + s -> tail = n -> prev; + if (!(n -> prev)) + { + s -> head = NULL; + } + + t = n -> term; + n -> term = NULL; + + lwasm_free(n); + + return t; +} + +// the following two functions are co-routines which actually parse +// an infix expression onto the expression stack, each returns -1 +// if an error is encountered + +/* +parse a term and push it onto the stack + +this function handles unary prefix operators (-, +, .not., .com.) +as well as () +*/ +int lwasm_expr_parse_term(lwasm_expr_stack_t *s, const char **p) +{ + lwasm_expr_term_t *t; + debug_message(2, "Expression string %s", *p); + +eval_next: + if (!**p || isspace(**p) || **p == ')' || **p == ']') + return -1; + if (**p == '(') + { + debug_message(3, "Starting paren"); + (*p)++; + lwasm_expr_parse_expr(s, p, 0); + if (**p != ')') + return -1; + (*p)++; + return 0; + } + + if (**p == '+') + { + debug_message(3, "Unary +"); + (*p)++; + goto eval_next; + } + + if (**p == '-') + { + // parse expression following "-" + (*p)++; + if (lwasm_expr_parse_expr(s, p, 200) < 0) + return -1; + t = lwasm_expr_term_create_oper(LWASM_OPER_NEG); + lwasm_expr_stack_push(s, t); + lwasm_expr_term_free(t); + return 0; + } + + if (**p == '^') + { + // parse expression following "^" + (*p)++; + if (lwasm_expr_parse_expr(s, p, 200) < 0) + return -1; + t = lwasm_expr_term_create_oper(LWASM_OPER_COM); + lwasm_expr_stack_push(s, t); + lwasm_expr_term_free(t); + return 0; + } + + /* + we have an actual term here so evaluate it + + it could be one of the following: + + 1. a decimal constant + 2. a hexadecimal constant + 3. an octal constant + 4. a binary constant + 5. a symbol reference + 6. the "current" instruction address (*) + 7. the "current" data address (.) + 8. a "back reference" (<) + 9. a "forward reference" (>) + + items 6 through 9 are stored as symbol references + + (a . followed by a . or a alpha char or number is a symbol) + */ + if (**p == '*' + || ( + **p == '.' + && (*p)[1] != '.' + && !((*p)[1] >= 'A' && (*p)[1] <= 'Z') + && !((*p)[1] >= 'a' && (*p)[1] <= 'z') + && !((*p)[1] >= '0' && (*p)[1] <= '9') + ) + || **p == '<' + || **p == '>') + { + char tstr[2]; + tstr[0] = **p; + tstr[1] = '\0'; + t = lwasm_expr_term_create_sym(tstr); + lwasm_expr_stack_push(s, t); + lwasm_expr_term_free(t); + (*p)++; + return 0; + } + + /* + - a symbol will be a string of characters introduced by a letter, ".", + "_" but NOT a number + - a decimal constant will consist of only digits, optionally prefixed + with "&" + - a binary constant will consist of only 0s and 1s either prefixed with % + or suffixed with "B" + - a hex constant will consist of 0-9A-F either prefixed with $ or + suffixed with "H"; a hex number starting with A-F must be prefixed + with $ or start with 0 and end with H + - an octal constant will consist of 0-7 either prefixed with @ or + suffixed with "O" or "Q" + - an ascii constant will be a single character prefixed with a ' + - a double ascii constant will be two characters prefixed with a " + + */ + if (**p == '"') + { + // double ascii constant + int val; + (*p)++; + if (!**p) + return -1; + if (!*((*p)+1)) + return -1; + val = **p << 8 | *((*p) + 1); + (*p) += 2; + t = lwasm_expr_term_create_int(val); + lwasm_expr_stack_push(s, t); + lwasm_expr_term_free(t); + return 0; + } + else if (**p == '\'') + { + // single ascii constant + int val; + (*p)++; + debug_message(3, "Single ascii character constant '%c'", **p); + if (!**p) + return -1; + val = **p; + (*p)++; + t = lwasm_expr_term_create_int(val); + lwasm_expr_stack_push(s, t); + lwasm_expr_term_free(t); + return 0; + } + else if (**p == '&') + { + // decimal constant + int val = 0; + + (*p)++; + while (**p && strchr("0123456789", **p)) + { + val = val * 10 + (**p - '0'); + (*p)++; + } + t = lwasm_expr_term_create_int(val); + lwasm_expr_stack_push(s, t); + lwasm_expr_term_free(t); + return 0; + } + else if (**p == '%') + { + // binary constant + int val = 0; + + (*p)++; + while (**p == '0' || **p == '1') + { + val = val * 2 + (**p - '0'); + (*p)++; + } + t = lwasm_expr_term_create_int(val); + lwasm_expr_stack_push(s, t); + lwasm_expr_term_free(t); + return 0; + } + else if (**p == '$') + { + // hexadecimal constant + int val = 0, val2; + + (*p)++; + debug_message(3, "Found prefix hex constant: %s", *p); + while (**p && strchr("0123456789ABCDEFabcdef", **p)) + { + val2 = toupper(**p) - '0'; + if (val2 > 9) + val2 -= 7; + debug_message(3, "Got char: %c (%d)", **p, val2); + val = val * 16 + val2; + (*p)++; + } + t = lwasm_expr_term_create_int(val); + lwasm_expr_stack_push(s, t); + lwasm_expr_term_free(t); + return 0; + } + // an @ followed by a digit is an octal number + // but if it's followed by anything else, it is a symbol + else if (**p == '@' && isdigit(*(*p + 1))) + { + // octal constant + int val = 0; + + (*p)++; + while (**p && strchr("01234567", **p)) + { + val = val * 8 + (**p - '0'); + (*p)++; + } + t = lwasm_expr_term_create_int(val); + lwasm_expr_stack_push(s, t); + lwasm_expr_term_free(t); + return 0; + } + + // symbol or bare decimal or suffix identified constant here + // all numbers will start with a digit at this point + if (**p < '0' || **p > '9') + { + int l = 0; + char *sb; + + // evaluate a symbol here + static const char *symchars = "_.$@?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + while ((*p)[l] && strchr(symchars, (*p)[l])) + l++; + + if (l == 0) + return -1; + + sb = lwasm_alloc(l + 1); + sb[l] = '\0'; + memcpy(sb, *p, l); + t = lwasm_expr_term_create_sym(sb); + lwasm_expr_stack_push(s, t); + lwasm_expr_term_free(t); + (*p) += l; + debug_message(3, "Symbol: '%s'; (%s)", sb, *p); + lwasm_free(sb); + return 0; + } + + if (!**p) + return -1; + + // evaluate a suffix based constant + { + int decval = 0, binval = 0, hexval = 0, octval = 0; + int valtype = 15; // 1 = bin, 2 = oct, 4 = dec, 8 = hex + int bindone = 0; + int val; + int dval; + + while (1) + { + if (!**p || !strchr("0123456789ABCDEFabcdefqhoQHO", **p)) + { + // we can legally have bin or decimal here + if (bindone) + { + // we just finished a binary value + val = binval; + break; + } + else if (valtype & 4) + { + // otherwise we must be decimal (if we're still allowed one) + val = decval; + debug_message(3, "End of decimal value"); + break; + } + else + { + // bad value + return -1; + } + } + + dval = toupper(**p); + (*p)++; + + if (bindone) + { + // any characters past "B" means it is not binary + bindone = 0; + valtype &= 14; + } + + switch (dval) + { + case 'Q': + case 'O': + if (valtype & 2) + { + val = octval; + valtype = -1; + break; + } + else + { + // not a valid octal value + return -1; + } + /* can't get here */ + + case 'H': + if (valtype & 8) + { + val = hexval; + valtype = -1; + break; + } + else + { + // not a valid hex number + return -1; + } + /* can't get here */ + + case 'B': + // this is a bit of a sticky one since B is a legit hex + // digit so this may or may not be the end of the number + // so we fall through to the digit case + + if (valtype & 1) + { + // could still be binary + bindone = 1; + valtype = 9; // hex and binary + } + /* fall through intentional */ + + default: + // digit + dval -= '0'; + if (dval > 9) + dval -= 7; + debug_message(3, "Got digit: %d", dval); +// if (dval > 1) +// valtype &= 14; +// if (dval > 7) +// valtype &= 12; +// if (dval > 9) +// valtype &= 8; + + if (valtype & 8) + { + hexval = hexval * 16 + dval; + } + if (valtype & 4) + { + if (dval > 9) + valtype &= 11; + else + decval = decval * 10 + dval; + } + if (valtype & 2) + { + if (dval > 7) + valtype &= 13; + else + octval = octval * 8 + dval; + } + if (valtype & 1) + { + if (dval > 1) + valtype &= 14; + else + binval = binval * 2 + dval; + } + } + // break out if we have a return value + if (valtype == -1) + break; + // return if no more valid possibilities! + if (valtype == 0) + return -1; + val = decval; // in case we fall through + } + + // we get here when we have a value to return + t = lwasm_expr_term_create_int(val); + lwasm_expr_stack_push(s, t); + lwasm_expr_term_free(t); + return 0; + } + /* can't get here */ +} + +// parse an expression and push the result onto the stack +// if an operator of lower precedence than the value of "prec" is found, +int lwasm_expr_parse_expr(lwasm_expr_stack_t *s, const char **p, int prec) +{ + static const struct operinfo + { + int opernum; + char *operstr; + int operprec; + } operators[] = + { + { LWASM_OPER_PLUS, "+", 100 }, + { LWASM_OPER_MINUS, "-", 100 }, + { LWASM_OPER_TIMES, "*", 150 }, + { LWASM_OPER_DIVIDE, "/", 150 }, + { LWASM_OPER_MOD, "%", 150 }, + { LWASM_OPER_INTDIV, "\\", 150 }, + + { LWASM_OPER_NONE, "", 0 } + }; + int opern, i; + lwasm_expr_term_t *operterm; + + // return if we are at the end of the expression or a subexpression + if (!**p || isspace(**p) || **p == ')' || **p == ',' || **p == ']') + return 0; + + if (lwasm_expr_parse_term(s, p) < 0) + return -1; + +eval_next: + if (!**p || isspace(**p) || **p == ')' || **p == ',' || **p == ']') + return 0; + + // expecting an operator here + for (opern = 0; operators[opern].opernum != LWASM_OPER_NONE; opern++) + { + for (i = 0; (*p)[i] && operators[opern].operstr[i] && (*p[i] == operators[opern].operstr[i]); i++) + /* do nothing */ ; + if (operators[opern].operstr[i] == '\0') + break; + } + if (operators[opern].opernum == LWASM_OPER_NONE) + { + // unrecognized operator + return -1; + } + + // the operator number in question is in opern; i is the length of the + // operator string + + // logic: + // if the precedence of this operation is <= to the "prec" flag, + // we simply return without advancing the input pointer; the operator + // will be evaluated again in the enclosing function call + if (operators[opern].operprec <= prec) + return 0; + + // logic: + // we have a higher precedence operator here so we will advance the + // input pointer to the next term and let the expression evaluator + // loose on it after which time we will push our operator onto the + // stack and then go on with the expression evaluation + (*p) += i; // advance input pointer + + // evaluate next expression(s) of higher precedence + if (lwasm_expr_parse_expr(s, p, operators[opern].operprec) < 0) + return -1; + + operterm = lwasm_expr_term_create_oper(operators[opern].opernum); + lwasm_expr_stack_push(s, operterm); + lwasm_expr_term_free(operterm); + + // return if we are at the end of the expression or a subexpression + if (!**p || isspace(**p) || **p == ')') + return 0; + + // continue evaluating + goto eval_next; +} + +/* +actually evaluate an expression + +This happens in two stages. The first stage merely parses the expression into +a lwasm_expr_stack_t * which is then evaluated as much as possible before the +result is returned. + +Returns NULL on a parse error or otherwise invalid expression. *outp will +contain the pointer to the next character after the expression if and only +if there is no error. In the case of an error, *outp is undefined. +*/ +lwasm_expr_stack_t *lwasm_expr_eval(const char *inp, const char **outp, lwasm_expr_stack_t *(*sfunc)(char *sym, void *state), void *state) +{ + lwasm_expr_stack_t *s; + const char *p; + int rval; + + // actually parse the expression + p = inp; + s = lwasm_expr_stack_create(); + + rval = lwasm_expr_parse_expr(s, &p, 0); + if (rval < 0) + goto cleanup_error; + + // save end of expression + if (outp) + (*outp) = p; + + // return potentially partial expression + if (lwasm_expr_reval(s, sfunc, state) < 0) + goto cleanup_error; + + if (lwasm_expr_is_constant(s)) + debug_message(3, "Constant expression evaluates to: %d", lwasm_expr_get_value(s)); + + return s; + +cleanup_error: + lwasm_expr_stack_free(s); + return NULL; +} + +/* +take an expression stack s and scan for operations that can be completed + +return -1 on error, 0 on no error + +possible errors are: division by zero or unknown operator + +theory of operation: + +scan the stack for an operator which has two constants preceding it (binary) +or 1 constant preceding it (unary) and if found, perform the calculation +and replace the operator and its operands with the result + +repeat the scan until no futher simplications are found or if there are no +further operators or only a single term remains + +*/ +int lwasm_expr_reval(lwasm_expr_stack_t *s, lwasm_expr_stack_t *(*sfunc)(char *sym, void *state), void *state) +{ + lwasm_expr_stack_node_t *n, *n2; + lwasm_expr_stack_t *ss; + int c; + +next_iter_sym: + // resolve symbols + // symbols that do not resolve to an expression are left alone + for (c = 0, n = s -> head; n; n = n -> next) + { + if (n -> term -> term_type == LWASM_TERM_SYM) + { + ss = sfunc(n -> term -> symbol, state); + if (ss) + { + c++; + // splice in the result stack + if (n -> prev) + { + n -> prev -> next = ss -> head; + } + else + { + s -> head = ss -> head; + } + ss -> head -> prev = n -> prev; + ss -> tail -> next = n -> next; + if (n -> next) + { + n -> next -> prev = ss -> tail; + } + else + { + s -> tail = ss -> tail; + } + lwasm_expr_term_free(n -> term); + lwasm_free(n); + n = ss -> tail; + + ss -> head = NULL; + ss -> tail = NULL; + lwasm_expr_stack_free(ss); + } + } + } + if (c) + goto next_iter_sym; + +next_iter: + // a single term + if (s -> head == s -> tail) + return 0; + + // search for an operator + for (n = s -> head; n; n = n -> next) + { + if (n -> term -> term_type == LWASM_TERM_OPER) + { + if (n -> term -> value == LWASM_OPER_NEG + || n -> term -> value == LWASM_OPER_COM + ) + { + // unary operator + if (n -> prev && n -> prev -> term -> term_type == LWASM_TERM_INT) + { + // a unary operator we can resolve + // we do the op then remove the term "n" is pointing at + if (n -> term -> value == LWASM_OPER_NEG) + { + n -> prev -> term -> value = -(n -> prev -> term -> value); + } + else if (n -> term -> value == LWASM_OPER_COM) + { + n -> prev -> term -> value = ~(n -> prev -> term -> value); + } + n -> prev -> next = n -> next; + if (n -> next) + n -> next -> prev = n -> prev; + else + s -> tail = n -> prev; + + lwasm_expr_term_free(n -> term); + lwasm_free(n); + break; + } + } + else + { + // binary operator + if (n -> prev && n -> prev -> prev && n -> prev -> term -> term_type == LWASM_TERM_INT && n -> prev -> prev -> term -> term_type == LWASM_TERM_INT) + { + // a binary operator we can resolve + switch (n -> term -> value) + { + case LWASM_OPER_PLUS: + n -> prev -> prev -> term -> value += n -> prev -> term -> value; + break; + + case LWASM_OPER_MINUS: + n -> prev -> prev -> term -> value -= n -> prev -> term -> value; + break; + + case LWASM_OPER_TIMES: + n -> prev -> prev -> term -> value *= n -> prev -> term -> value; + break; + + case LWASM_OPER_DIVIDE: + if (n -> prev -> term -> value == 0) + return -1; + n -> prev -> prev -> term -> value /= n -> prev -> term -> value; + break; + + case LWASM_OPER_MOD: + if (n -> prev -> term -> value == 0) + return -1; + n -> prev -> prev -> term -> value %= n -> prev -> term -> value; + break; + + case LWASM_OPER_INTDIV: + if (n -> prev -> term -> value == 0) + return -1; + n -> prev -> prev -> term -> value /= n -> prev -> term -> value; + break; + + case LWASM_OPER_BWAND: + n -> prev -> prev -> term -> value &= n -> prev -> term -> value; + break; + + case LWASM_OPER_BWOR: + n -> prev -> prev -> term -> value |= n -> prev -> term -> value; + break; + + case LWASM_OPER_BWXOR: + n -> prev -> prev -> term -> value ^= n -> prev -> term -> value; + break; + + case LWASM_OPER_AND: + n -> prev -> prev -> term -> value = (n -> prev -> term -> value && n -> prev -> prev -> term -> value) ? 1 : 0; + break; + + case LWASM_OPER_OR: + n -> prev -> prev -> term -> value = (n -> prev -> term -> value || n -> prev -> prev -> term -> value) ? 1 : 0; + break; + + default: + // return error if unknown operator! + return -1; + } + + // now remove the two unneeded entries from the stack + n -> prev -> prev -> next = n -> next; + if (n -> next) + n -> next -> prev = n -> prev -> prev; + else + s -> tail = n -> prev -> prev; + + lwasm_expr_term_free(n -> term); + lwasm_expr_term_free(n -> prev -> term); + lwasm_free(n -> prev); + lwasm_free(n); + break; + } + } + } + } + // note for the terminally confused about dynamic memory and pointers: + // n will not be NULL even after the lwasm_free calls above so + // this test will still work (n will be a dangling pointer) + // (n will only be NULL if we didn't find any operators to simplify) + if (n) + goto next_iter; + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/expr.h Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,119 @@ +/* +expr.h +Copyright © 2008 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +Definitions for expression evaluator +*/ + +#ifndef __expr_h_seen__ +#define __expr_h_seen__ + +#ifndef __expr_c_seen__ +#define __expr_E__ extern +#else +#define __expr_E__ +#endif + +// term types +#define LWASM_TERM_NONE 0 +#define LWASM_TERM_OPER 1 // an operator +#define LWASM_TERM_INT 2 // 32 bit signed integer +#define LWASM_TERM_SYM 3 // symbol reference +#define LWASM_TERM_SECBASE 4 // section base reference + +// operator types +#define LWASM_OPER_NONE 0 +#define LWASM_OPER_PLUS 1 // + +#define LWASM_OPER_MINUS 2 // - +#define LWASM_OPER_TIMES 3 // * +#define LWASM_OPER_DIVIDE 4 // / +#define LWASM_OPER_MOD 5 // % +#define LWASM_OPER_INTDIV 6 // \ (don't end line with \) +#define LWASM_OPER_BWAND 7 // bitwise AND +#define LWASM_OPER_BWOR 8 // bitwise OR +#define LWASM_OPER_BWXOR 9 // bitwise XOR +#define LWASM_OPER_AND 10 // boolean AND +#define LWASM_OPER_OR 11 // boolean OR +#define LWASM_OPER_NEG 12 // - unary negation (2's complement) +#define LWASM_OPER_COM 13 // ^ unary 1's complement + + +// term structure +typedef struct lwasm_expr_term_s +{ + int term_type; // type of term (see above) + char *symbol; // name of a symbol + int value; // value of the term (int) or operator number (OPER) +} lwasm_expr_term_t; + +// type for an expression evaluation stack +typedef struct lwasm_expr_stack_node_s lwasm_expr_stack_node_t; +struct lwasm_expr_stack_node_s +{ + lwasm_expr_term_t *term; + lwasm_expr_stack_node_t *prev; + lwasm_expr_stack_node_t *next; +}; + +typedef struct lwasm_expr_stack_s +{ + lwasm_expr_stack_node_t *head; + lwasm_expr_stack_node_t *tail; +} lwasm_expr_stack_t; + +__expr_E__ void lwasm_expr_term_free(lwasm_expr_term_t *t); +__expr_E__ lwasm_expr_term_t *lwasm_expr_term_create_oper(int oper); +__expr_E__ lwasm_expr_term_t *lwasm_expr_term_create_sym(char *sym); +__expr_E__ lwasm_expr_term_t *lwasm_expr_term_create_int(int val); +__expr_E__ lwasm_expr_term_t *lwasm_expr_term_create_secbase(void); +__expr_E__ lwasm_expr_term_t *lwasm_expr_term_dup(lwasm_expr_term_t *t); + +__expr_E__ void lwasm_expr_stack_free(lwasm_expr_stack_t *s); +__expr_E__ lwasm_expr_stack_t *lwasm_expr_stack_create(void); + +__expr_E__ void lwasm_expr_stack_push(lwasm_expr_stack_t *s, lwasm_expr_term_t *t); +__expr_E__ lwasm_expr_term_t *lwasm_expr_stack_pop(lwasm_expr_stack_t *s); + +/* +Evaluate an expression. The result is an lwasm_expr_stack_t pointer. If the +expression evaluates to a constant result, the stack will contain exactly one +value which will be a constant. Otherwise, the stack will contain the +expression with all operations that can be evaluated completely evaluated. +You must call lwasm_expr_stack_free() on the result when you are finished +with it. +*/ +__expr_E__ lwasm_expr_stack_t *lwasm_expr_eval(const char *inp, const char **outp, lwasm_expr_stack_t *(*sfunc)(char *sym, void *state), void *state); + +// simplify expression +__expr_E__ int lwasm_expr_reval(lwasm_expr_stack_t *s, lwasm_expr_stack_t *(*sfunc)(char *sym, void *state), void *state); + +// useful macros +// is the expression "simple" (one term)? +#define lwasm_expr_is_simple(s) ((s) -> head == (s) -> tail) + +// is the expression constant? +#define lwasm_expr_is_constant(s) (lwasm_expr_is_simple(s) && (!((s) -> head) || (s) -> head -> term -> term_type == LWASM_TERM_INT)) + +// get the constant value of an expression or 0 if not constant +#define lwasm_expr_get_value(s) (lwasm_expr_is_constant(s) ? ((s) -> head ? (s) -> head -> term -> value : 0) : 0) + +#undef __expr_E__ + +#endif // __expr_h_seen__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/insn_bitbit.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,137 @@ +/* +insn_bitbit.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +for handling inherent mode instructions +*/ + +#define __insn_bitbit_c_seen__ + +#include <stdlib.h> + +#include "lwasm.h" +#include "instab.h" +#include "expr.h" + +// these instructions cannot tolerate external references +OPFUNC(insn_bitbit) +{ + int r; + lwasm_expr_stack_t *s; + int v1; + int tv; + + lwasm_emitop(as, l, instab[opnum].ops[0]); + + r = toupper(*(*p)++); + if (r == 'A') + r = 1; + else if (r == 'B') + r = 2; + else if (r == 'C' && toupper(**p) == 'C') + { + r = 0; + (*p)++; + } + else + { + register_error(as, l, 1, "Bad register"); + return; + } + if (*(*p)++ != ',') + { + register_error(as, l, 1, "Bad operand"); + return; + } + s = lwasm_evaluate_expr(as, l, *p, NULL, 0); + if (!s) + { + register_error(as, l, 1, "Bad operand"); + return; + } + if (!lwasm_expr_is_constant(s)) + { + register_error(as, l, 2, "Incomplete reference"); + } + v1 = lwasm_expr_get_value(s); + lwasm_expr_stack_free(s); + if (v1 < 0 || v1 > 7) + { + register_error(as, l, 2, "Invalid bit number"); + v1 = 0; + } + if (*(*p)++ != ',') + { + register_error(as, l, 1, "Bad operand"); + return; + } + r = (r << 6) | (v1 << 3); + + s = lwasm_evaluate_expr(as, l, *p, NULL, 0); + if (!s) + { + register_error(as, l, 1, "Bad operand"); + return; + } + if (!lwasm_expr_is_constant(s)) + { + register_error(as, l, 1, "Incomplete reference"); + } + v1 = lwasm_expr_get_value(s); + lwasm_expr_stack_free(s); + if (v1 < 0 || v1 > 7) + { + register_error(as, l, 2, "Invalid bit number"); + v1 = 0; + } + if (*(*p)++ != ',') + { + register_error(as, l, 1, "Bad operand"); + return; + } + r |= v1; + + lwasm_emit(as, l, r); + + // ignore base page address modifier + if (**p == '<') + (*p)++; + + s = lwasm_evaluate_expr(as, l, *p, NULL, 0); + if (!s) + { + register_error(as, l, 1, "Bad operand"); + return; + } + if (!lwasm_expr_is_constant(s)) + { + register_error(as, l, 1, "Incomplete reference"); + } + v1 = lwasm_expr_get_value(s); + lwasm_expr_stack_free(s); + v1 &= 0xFFFF; + + tv = v1 - ((as -> dpval) << 8); + if (tv > 0xFF || tv < 0) + { + register_error(as, l, 2, "Byte overflow"); + } + lwasm_emit(as, l, tv & 0xff); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/insn_gen.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,228 @@ +/* +insn_gen.c, Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + +Contains code for parsing general addressing modes (IMM+DIR+EXT+IND) +*/ + +#include <ctype.h> +#include <stdlib.h> + +#include "lwasm.h" +#include "instab.h" +#include "expr.h" + +extern void insn_indexed_aux(asmstate_t *as, lwasm_line_t *l, const char **p, int *b1, int *b2, int *b3); + +// "extra" is required due to the way OIM, EIM, TIM, and AIM work +void insn_gen_aux(asmstate_t *as, lwasm_line_t *l, char **optr, int opnum, int extra) +{ + int b1 = -1, b2 = -1, b3 = -1; + + const char *optr2; + int v1, tv, rval; + lwasm_expr_stack_t *s; + int f8 = 0; + int f16 = 0; + int isdp = 0; + + optr2 = *optr; + while (*optr2 && !isspace(*optr2) && *optr2 != ',') optr2++ + /* do nothing */ ; + + if (*optr2 != ',' && **optr != '[') + { + // not indexed + if (l -> fsize == 1) + f8 = 1; + else if (l -> fsize == 2) + f16 = 1; + + if (**optr == '<') + { + (*optr)++; + f8 = 1; + } + else if (**optr == '>') + { + (*optr)++; + f16 = 1; + } + rval = lwasm_expr_result2(as, l, optr, 0, &v1, 0); + if (rval != 0) + { + f16 = 1; + v1 = 0; + l -> fsize = 2; + } + + if (((v1 >> 8) & 0xff) == (as -> dpval & 0xff)) + isdp = 1; + + // disallow non-explicit DP in obj target + if (as -> outformat == OUTPUT_OBJ && !f8) + f16 = 1; + + if (f8 || (!f16 && isdp)) + { + v1 = v1 & 0xffff; + tv = v1 - ((as -> dpval) << 8); + if (tv < 0 || tv > 0xff) + { + register_error(as, l, 2, "Byte overflow"); + } + v1 = v1 & 0xff; + lwasm_emitop(as, l, instab[opnum].ops[0]); + if (extra != -1) + lwasm_emit(as, l, extra); + lwasm_emit(as, l, v1 & 0xff); + return; + } + else + { + // everything else is 16 bit.... + lwasm_emitop(as, l, instab[opnum].ops[2]); + if (extra != -1) + lwasm_emit(as, l, extra); + l -> relocoff = as -> addr - l -> codeaddr; + lwasm_emit(as, l, v1 >> 8); + lwasm_emit(as, l, v1 & 0xff); + return; + } + } + + lwasm_emitop(as, l, instab[opnum].ops[1]); + if (extra != -1) + lwasm_emit(as, l, extra); + insn_indexed_aux(as, l, (const char **)optr, &b1, &b2, &b3); + if (b1 != -1) + lwasm_emit(as, l, b1); + if (b2 != -1) + lwasm_emit(as, l, b2); + if (b3 != -1) + lwasm_emit(as, l, b3); + return; +} + +// the various insn_gen? functions have an immediate mode of ? bits +OPFUNC(insn_gen0) +{ + if (**p == '#') + { + register_error(as, l, 1, "Immediate mode not allowed"); + return; + } + + // handle non-immediate + insn_gen_aux(as, l, p, opnum, -1); +} + +OPFUNC(insn_gen8) +{ + int rval; + int r; + + if (**p == '#') + { + lwasm_emitop(as, l, instab[opnum].ops[3]); + (*p)++; + r = lwasm_expr_result2(as, l, p, 0, &rval, 0); + if (r != 0) + rval = 0; + if (r == 1 && as -> passnum == 2) + register_error(as, l, 2, "Illegal external or intersegment reference"); + lwasm_emit(as, l, rval & 0xff); + return; + } + + insn_gen_aux(as, l, p, opnum, -1); +} + +OPFUNC(insn_gen16) +{ + int rval, r; + + if (**p == '#') + { + lwasm_emitop(as, l, instab[opnum].ops[3]); + (*p)++; + + r = lwasm_expr_result2(as, l, p, 0, &rval, 0); + if (r != 0) + rval = 0; + if (r == 1 && as -> passnum == 2) + { + l -> relocoff = as -> addr - l -> codeaddr; + } + lwasm_emit(as, l, (rval >> 8) & 0xff); + lwasm_emit(as, l, rval & 0xff); + return; + } + + insn_gen_aux(as, l, p, opnum, -1); +} + +OPFUNC(insn_gen32) +{ + int r, rval; + + if (**p == '#') + { + lwasm_emitop(as, l, instab[opnum].ops[3]); + (*p)++; + + r = lwasm_expr_result2(as, l, p, 0, &rval, 0); + if (r != 0) + rval = 0; + if (r == 1 && as -> passnum == 2) + { + register_error(as, l, 2, "Illegal external or intersegment reference"); + } + + lwasm_emit(as, l, (rval >> 24) & 0xff); + lwasm_emit(as, l, (rval >> 16) & 0xff); + lwasm_emit(as, l, (rval >> 8) & 0xff); + lwasm_emit(as, l, rval & 0xff); + return; + } + + insn_gen_aux(as, l, p, opnum, -1); +} + +OPFUNC(insn_imm8) +{ + int r, rval; + + if (**p == '#') + { + lwasm_emitop(as, l, instab[opnum].ops[0]); + (*p)++; + + r = lwasm_expr_result2(as, l, p, 0, &rval, 0); + if (r != 0) + rval = 0; + if (r == 1 && as -> passnum == 2) + register_error(as, l, 2, "Illegal external or intersegment reference"); + + if (rval < -128 || rval > 255) + register_error(as, l, 2, "Byte overflow"); + lwasm_emit(as, l, rval & 0xff); + return; + } + + register_error(as, l, 1, "Bad operand"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/insn_indexed.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,443 @@ +/* +insn_indexed.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +for handling indexed mode instructions +*/ + +#define __insn_indexed_c_seen__ + +#include <ctype.h> +#include <string.h> + +#include "lwasm.h" +#include "instab.h" +#include "expr.h" + +void insn_indexed_aux(asmstate_t *as, lwasm_line_t *l, const char **p, int *b1, int *b2, int *b3) +{ + static const char *regs = "X Y U S W PCRPC "; + static const struct { char *opstr; int pb; } simpleindex[] = + { + {",x", 0x84}, {",y", 0xa4}, {",u", 0xc4}, {",s", 0xe4}, + {",x+", 0x80}, {",y+", 0xa0}, {",u+", 0xc0}, {",s+", 0xe0}, + {",x++", 0x81}, {",y++", 0xa1}, {",u++", 0xc1}, {",s++", 0xe1}, + {",-x", 0x82}, {",-y", 0xa2}, {",-u", 0xc2}, {",-s", 0xe2}, + {",--x", 0x83}, {",--y", 0xa3}, {",--u", 0xc3}, {",--s", 0xe3}, + {"a,x", 0x86}, {"a,y", 0xa6}, {"a,u", 0xc6}, {"a,s", 0xe6}, + {"b,x", 0x85}, {"b,y", 0xa5}, {"b,u", 0xc5}, {"b,s", 0xe5}, + {"e,x", 0x87}, {"e,y", 0xa7}, {"e,u", 0xc7}, {"e,s", 0xe7}, + {"f,x", 0x8a}, {"f,y", 0xaa}, {"f,u", 0xca}, {"f,s", 0xea}, + {"d,x", 0x8b}, {"d,y", 0xab}, {"d,u", 0xcb}, {"d,s", 0xed}, + {"w,x", 0x8e}, {"w,y", 0xae}, {"w,u", 0xce}, {"w,s", 0xee}, + {",w", 0x8f}, {",w++", 0xcf}, {",--w", 0xef}, + + {"[,x]", 0x94}, {"[,y]", 0xb4}, {"[,u", 0xd4}, {"[,s]", 0xf4}, + {"[,x++]", 0x91}, {"[,y++]", 0xb1}, {"[,u++]", 0xd1}, {"[,s++]", 0xf1}, + {"[,--x]", 0x93}, {"[,--y]", 0xb3}, {"[,--u]", 0xd3}, {"[,--s]", 0xf3}, + {"[a,x]", 0x96}, {"[a,y]", 0xb6}, {"[a,u]", 0xd6}, {"[a,s]", 0xf6}, + {"[b,x]", 0x95}, {"[b,y]", 0xb5}, {"[b,u]", 0xd5}, {"[b,s]", 0xf5}, + {"[e,x]", 0x97}, {"[e,y]", 0xb7}, {"[e,u]", 0xd7}, {"[e,s]", 0xf7}, + {"[f,x]", 0x9a}, {"[f,y]", 0xba}, {"[f,u]", 0xda}, {"[f,s]", 0xfa}, + {"[d,x]", 0x9b}, {"[d,y]", 0xbb}, {"[d,u]", 0xdb}, {"[d,s]", 0xfd}, + {"[w,x]", 0x9e}, {"[w,y]", 0xbe}, {"[w,u]", 0xde}, {"[w,s]", 0xfe}, + {"[,w]", 0x90}, {"[,w++]", 0xd0}, {"[,--w]", 0xf0}, + + { "", -1 } + }; + char stbuf[25]; + int i, j, rn; + int f8 = 0, f16 = 0, f0 = 0; + int r, v; + int indir = 0; + int fs8 = 0, fs16 = 0; + + // initialize output bytes + *b1 = *b2 = *b3 = -1; + + // fetch out operand for lookup + for (i = 0; i < 24; i++) + { + if (*((*p) + i) && !isspace(*((*p) + i))) + stbuf[i] = *((*p) + i); + else + break; + } + stbuf[i] = '\0'; + + // now look up operand in "simple" table + if (!*((*p) + i) || isspace(*((*p) + i))) + { + // do simple lookup + for (j = 0; simpleindex[j].opstr[0]; j++) + { + if (!strcasecmp(stbuf, simpleindex[j].opstr)) + break; + } + if (simpleindex[j].opstr[0]) + { + *b1 = simpleindex[j].pb; + (*p) += i; + return; + } + } + + // now do the "hard" ones + + // is it indirect? + if (**p == '[') + { + indir = 1; + (*p)++; + } + + // look for a "," - all indexed modes have a "," except extended indir + rn = 0; + for (i = 0; (*p)[i] && !isspace((*p)[i]); i++) + { + if ((*p)[i] == ',') + { + rn = 1; + break; + } + } + + // if no "," and indirect, do extended indir + if (!rn && indir) + { + // extended indir + *b1 = 0x9f; + *b2 = 0; + *b3 = 0; + r = lwasm_expr_result2(as, l, (char **)p, 0, &v, 0); + if (r < 0) + { + return; + } + if (**p != ']') + { + register_error(as, l, 1, "Bad operand"); + return; + } + + (*p)++; + + if (r == 1 && as -> passnum == 2) + { + l -> relocoff = as -> addr - l -> codeaddr + 1; + } + + *b2 = (v >> 8) & 0xff; + *b3 = v & 0xff; + return; + } + + // if we've previously forced the offset size, make a note of it + if (l -> fsize == 1) + f8 = 1; + else if (l -> fsize == 2) + f16 = 1; + + if (**p == '<') + { + fs8 = 1; + (*p)++; + } + else if (**p == '>') + { + fs16 = 1; + (*p)++; + } + + if (**p == '0' && *(*p+1) == ',') + { + f0 = 1; + } + + // now we have to evaluate the expression + r = lwasm_expr_result2(as, l, (char **)p, 0, &v, 0); + if (r < 0) + { + return; + } + // now look for a comma; if not present, explode + if (*(*p)++ != ',') + { + // syntax error; force 0 bit + *b1 = 00; + l -> fsize = 0; + return; + } + + // now get the register + rn = lwasm_lookupreg3(regs, p); + if (rn < 0) + { + *b1 = 0; + l -> fsize = 0; + register_error(as, l, 1, "Bad register"); + return; + } + + if (indir) + { + if (**p != ']') + { + register_error(as, l, 1, "Bad operand"); + l -> fsize = 0; + *b1 = 0; + return; + } + else + (*p)++; + } + + // incomplete reference on pass 1 forces 16 bit + if (r == 1 && as -> passnum == 1) + { + f16 = 1; + l -> fsize = 2; + } + + // incomplete reference on pass 2 needs relocoff set + if (r == 1 && as -> passnum == 2) + { + l -> relocoff = as -> addr - l -> codeaddr + 1; + } + + // nnnn,W is only 16 bit (or 0 bit) + if (rn == 4) + { + if (f8) + { + register_error(as, l, 1, "n,W cannot be 8 bit"); + l -> fsize = 0; + *b1 = 0; + return; + } + // note: set f16 above for incomplete references + // also set reloc offset + if (!f16 && !f0 && !(as -> pragmas & PRAGMA_NOINDEX0TONONE) && v == 0) + { + if (indir) + *b1 = 0x90; + else + *b1 = 0x8f; + return; + } + + if (indir) + *b1 = 0xb0; + else + *b1 = 0xcf; + *b2 = (v >> 8) & 0xff; + *b3 = v & 0xff; + return; + } + + // set indir to correct bit value + if (indir) indir = 0x10; + + // PCR? then we have PC relative addressing (like B??, LB??) + if (rn == 5) + { + lwasm_expr_term_t *t; + // external references are handled exactly the same as for + // relative addressing modes + // on pass 1, adjust the expression for a subtraction of the + // current address + + // need to re-evaluate the expression with "SECTCONST"... + r = lwasm_expr_result2(as, l, (char **)p, EXPR_SECTCONST | EXPR_REEVAL, &v, 0); + if (r != 0) + v = 0; + if (as -> passnum == 1) + { + l -> fsize = 0; + } + f8 = f16 = 0; + if (r == 1 && as -> passnum == 1 && !fs8) + { + l -> fsize = 2; + f16 = 1; + } + if (fs8) + f8 = 1; + if (fs16) + f16 = 1; + if (l -> fsize == 2) + f16 = 1; + else if (l -> fsize == 1) + f8 = 1; + if (as -> passnum == 1) + v -= as -> addr; + + // we have a slight problem here + // PCR based on current insn loc is really + // -125 <= offset <= +130 (8 bit offset) + // NOTE: when we are called, we already have the opcode emitted + // so we only need to worry about the size of the operand + // hence the 2 and 3 magic numbers below instead of 3 and 4 + // (and that also avoids errors with two byte opcodes, etc) + if (f8 || (!f16 && v >= -125 && v <= 130)) + { + f8 = 1; + l -> fsize = 1; + *b1 = indir | 0x8C; + if (as -> passnum == 1) + v -= 2; + if (v < -128 || v > 127) + register_error(as, l, 2, "Byte overflow"); + *b2 = v & 0xff; + if (r != 0 && as -> passnum == 2) + { + register_error(as, l, 2, "Illegal incomplete reference"); + } + goto finpcr; + } + + // anything else is 16 bit offset + // need 16 bit + + l -> fsize = 2; + *b1 = indir | 0x8D; + if (as -> passnum == 1) + v -= 3; + *b2 = (v >> 8) & 0xff; + *b3 = v & 0xff; + if (as -> passnum == 2 && r == 1) + { + t = lwasm_expr_term_create_secbase(); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + } + + finpcr: + if (as -> passnum == 1) + { + // need to adjust the expression + if (l -> exprs[0]) + { + t = lwasm_expr_term_create_int(as -> addr + (f8 ? 2 : 3)); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + } + else + { + l -> exprvals[0] -= as -> addr + (f8 ? 2 : 3); + } + } + return; + } + if (fs16) + f16 = 1; + if (fs8) + f8 = 1; + + if (f8 && r != 0) + { + register_error(as, l, 2, "Illegal external or inter-section reference"); + r = 0; + v = 0; + } + + // constant offset from PC (using PC as regular register :) ) + // FIXME: handle external references intelligently + if (rn == 6) + { + if (f8 || (!f16 && v >= -128 && v <= 127)) + { + *b1 = indir | 0x8C; + if (v < -128 || v > 127) + register_error(as, l, 2, "Byte overflow"); + *b2 = v & 0xff; + return; + } + + // everything else must be 16 bit + // need 16 bit + *b1 = indir | 0x8D; + *b2 = (v >> 8) & 0xff; + *b3 = v & 0xff; + return; + } + + // we only have to deal with x,y,u,s here + if (!f8 && !f16 && v >= -16 && v <= 15) + { + // zero offset going to ,R? + if (v == 0 && !f0 && !(as -> pragmas & PRAGMA_NOINDEX0TONONE)) + { + *b1 = rn << 5 | indir | 0x80 | 0x04; + return; + } + + // no 5 bit on indirect + if (indir) + { + f8 = 1; + l -> fsize = 1; + goto no5bit; + } + + // 5 bit addressing + *b1 = rn << 5 | (v & 0x1F); + return; + } + +no5bit: + if (f16 || (!f8 && (v < -128 || v > 127))) + { + // must be a 16 bit offset here + *b1 = rn << 5 | indir | 0x80 | 0x09; + *b2 = (v >> 8) & 0xff; + *b3 = v & 0xff; + return; + } + + // if we're here, we have an 8 bit offset + // note: cannot get here if incomplete reference detected above + *b1 = rn << 5 | indir | 0x80 | 0x08; + if (v < -128 || v > 127) + register_error(as, l, 2, "Byte overflow"); + *b2 = v & 0xff; + return; +} + +OPFUNC(insn_indexed) +{ + int b1, b2, b3; + + lwasm_emitop(as, l, instab[opnum].ops[0]); + + insn_indexed_aux(as, l, (const char **)p, &b1, &b2, &b3); + if (b1 != -1) + lwasm_emit(as, l, b1); + if (b2 != -1) + lwasm_emit(as, l, b2); + if (b3 != -1) + lwasm_emit(as, l, b3); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/insn_inh.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,33 @@ +/* +insn_inh.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +for handling inherent mode instructions +*/ + +#define __insn_inh_c_seen__ + +#include "lwasm.h" +#include "instab.h" + +OPFUNC(insn_inh) +{ + lwasm_emitop(as, l, instab[opnum].ops[0]); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/insn_logicmem.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,63 @@ +/* +insn_logicmem.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + +Contains code for handling logic/mem instructions +*/ + +#include <ctype.h> +#include <stdio.h> +#include <string.h> + +#include "lwasm.h" +#include "instab.h" +#include "expr.h" + +extern void insn_gen_aux(asmstate_t *as, lwasm_line_t *l, char **optr, int opnum, int extra); + +// for aim, oim, eim, tim +// the immediate operand must be constant on pass 2 +OPFUNC(insn_logicmem) +{ + int rval, v1; + const char *p2; + lwasm_expr_stack_t *s; + + if (**p == '#') + (*p)++; + + rval = lwasm_expr_result2(as, l, p, 0, &v1, 1); + if (rval != 0) + v1 = 0; + if (rval == 1 && as -> passnum == 2) + register_error(as, l, 2, "Illegal external or intersegment reference"); + + if (v1 < -128 || v1 > 255) + register_error(as, l, 2, "Byte overflow"); + + if (**p != ',' && **p != ';') + { + register_error(as, l, 1, "Bad operand"); + return; + } + + (*p)++; + + // now we have a general addressing mode - call for it + insn_gen_aux(as, l, p, opnum, v1 & 0xff); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/insn_rel.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,123 @@ +/* +insn_rel.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +for handling relative mode instructions +*/ + +#define __insn_rel_c_seen__ + +#include <stdlib.h> + +#include "expr.h" +#include "lwasm.h" +#include "instab.h" + +OPFUNC(insn_rel8) +{ + int v; + lwasm_expr_term_t *t; + int r; + + lwasm_emitop(as, l, instab[opnum].ops[0]); + + if ((r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST, &v, 0)) < 0) + v = 0; + else + { + if (as -> passnum == 1) + { + // need to adjust the expression + if (l -> exprs[0]) + { + t = lwasm_expr_term_create_int(as -> addr + 1); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + } + else + { + l -> exprvals[0] -= as -> addr + 1; + } + } + } + if (r == 1 && as -> passnum == 2) + { + register_error(as, l, 2, "Illegal external or intersegment reference"); + } + if (v < -128 || v > 127) + register_error(as, l, 2, "Byte overflow"); + lwasm_emit(as, l, v & 0xff); +} + +/* +External and intersegment references are adjusted for the relative addressing mode +by adjusting the expression on pass 1 and then treated as absolute references later +*/ +OPFUNC(insn_rel16) +{ + int v; + int r; + lwasm_expr_term_t *t; + + lwasm_emitop(as, l, instab[opnum].ops[0]); + + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST, &v, 0); + if (r < 0) + v = 0; + else + { + if (as -> passnum == 1) + { + // need to adjust the expression + if (l -> exprs[0]) + { + t = lwasm_expr_term_create_int(as -> addr + 2); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + } + else + { + l -> exprvals[0] -= as -> addr + 2; + } + } + } + if (as -> passnum == 2 && r == 1) + { + // since we have a reference outside this section, add + // a subtract of the section base to get the right value + // upon linking + t = lwasm_expr_term_create_secbase(); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + + l -> relocoff = as -> addr - l -> codeaddr; + } + lwasm_emit(as, l, (v >> 8) & 0xff); + lwasm_emit(as, l, v & 0xff); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/insn_rlist.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,62 @@ +/* +insn_rlist.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +for handling inherent mode instructions +*/ + +#define __insn_rlist_c_seen__ + +#include "lwasm.h" +#include "instab.h" + +OPFUNC(insn_rlist) +{ + int rb = 0; + int rn; + static const char *regs = "CCA B DPX Y U PCD S "; + + lwasm_emitop(as, l, instab[opnum].ops[0]); + while (**p && !isspace(**p)) + { + rn = lwasm_lookupreg2(regs, p); + if (rn < 0) + { + register_error(as, l, 1, "Bad register '%s'", *p); + lwasm_emit(as, l, 0); + return; + } + if (**p && **p != ',' && !isspace(**p)) + { + register_error(as, l, 1, "Bad operand"); + lwasm_emit(as, l, 0); + } + if (**p == ',') + (*p)++; + if (rn == 8) + rn = 6; + else if (rn == 9) + rn = 0x40; + else + rn = 1 << rn; + rb |= rn; + } + lwasm_emit(as, l, rb); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/insn_rtor.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,56 @@ +/* +insn_rtor.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +for handling register to register mode instructions +*/ + +#define __insn_rtor_c_seen__ + +#include "lwasm.h" +#include "instab.h" + +OPFUNC(insn_rtor) +{ + int r0, r1; + static const char *regs = "D X Y U S PCW V A B CCDP0 0 E F "; + + lwasm_emitop(as, l, instab[opnum].ops[0]); + // register to register (r0,r1) + // registers are in order: + // D,X,Y,U,S,PC,W,V + // A,B,CC,DP,0,0,E,F + r0 = lwasm_lookupreg2(regs, p); + if (r0 < 0 || *(*p)++ != ',') + { + register_error(as, l, 1, "Bad operand"); + r0 = r1 = 0; + } + else + { + r1 = lwasm_lookupreg2(regs, p); + if (r1 < 0) + { + register_error(as, l, 1, "Bad operand"); + r0 = r1 = 0; + } + } + lwasm_emit(as, l, (r0 << 4) | r1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/insn_tfm.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,111 @@ +/* +insn_tfm.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +for handling inherent mode instructions +*/ + +#define __insn_tfm_c_seen__ + +#include <ctype.h> +#include <string.h> + +#include "lwasm.h" +#include "instab.h" + +OPFUNC(insn_tfm) +{ + static const char *reglist = "DXYUS AB 00EF"; + int r0, r1; + char *c; + int tfm = 0; + + c = strchr(reglist, toupper(*(*p)++)); + if (!c) + { + register_error(as, l, 1, "Unknown operation"); + return; + } + r0 = c - reglist; + if (**p == '+') + { + (*p)++; + tfm = 1; + } + else if (**p == '-') + { + (*p)++; + tfm = 2; + } + if (*(*p)++ != ',') + { + register_error(as, l, 1, "Unknown operation"); + return; + } + c = strchr(reglist, toupper(*(*p)++)); + if (!c) + { + register_error(as, l, 1, "Unknown operation"); + return; + } + r1 = c - reglist; + + if (**p == '+') + { + (*p)++; + tfm |= 4; + } + else if (**p == '-') + { + (*p)++; + tfm |= 8; + } + + if (**p && !isspace(**p)) + { + register_error(as, l, 1, "Bad operand"); + return; + } + + // valid values of tfm here are: + // 1: r0+,r1 (2) + // 4: r0,r1+ (3) + // 5: r0+,r1+ (0) + // 10: r0-,r1- (1) + switch (tfm) + { + case 5: //r0+,r1+ + lwasm_emitop(as, l, instab[opnum].ops[0]); + break; + case 10: //r0-,r1- + lwasm_emitop(as, l, instab[opnum].ops[1]); + break; + case 1: // r0+,r1 + lwasm_emitop(as, l, instab[opnum].ops[2]); + break; + case 4: // r0,r1+ + lwasm_emitop(as, l, instab[opnum].ops[3]); + break; + default: + register_error(as, l, 1, "Unknown operation"); + return; + } + lwasm_emit(as, l, (r0 << 4) | r1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/instab.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,389 @@ +/* +instab.c +Copyright © 2008 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + + +Contains the instruction table for assembling code +*/ + +#include <stdlib.h> + +#define __instab_c_seen__ +#include "instab.h" + +extern OPFUNC(insn_inh); +extern OPFUNC(insn_gen8); +extern OPFUNC(insn_gen16); +extern OPFUNC(insn_gen32); +extern OPFUNC(insn_gen0); +extern OPFUNC(insn_rtor); +extern OPFUNC(insn_imm8); +extern OPFUNC(insn_rel8); +extern OPFUNC(insn_rel16); +extern OPFUNC(insn_rlist); +extern OPFUNC(insn_bitbit); +extern OPFUNC(insn_logicmem); +extern OPFUNC(insn_tfm); +extern OPFUNC(insn_indexed); + +extern OPFUNC(pseudo_org); +extern OPFUNC(pseudo_equ); +extern OPFUNC(pseudo_rmb); +extern OPFUNC(pseudo_rmd); +extern OPFUNC(pseudo_rmq); +extern OPFUNC(pseudo_zmb); +extern OPFUNC(pseudo_zmd); +extern OPFUNC(pseudo_zmq); +extern OPFUNC(pseudo_include); +extern OPFUNC(pseudo_end); +extern OPFUNC(pseudo_align); +extern OPFUNC(pseudo_error); +extern OPFUNC(pseudo_fcc); +extern OPFUNC(pseudo_fcs); +extern OPFUNC(pseudo_fcn); +extern OPFUNC(pseudo_fcb); +extern OPFUNC(pseudo_fdb); +extern OPFUNC(pseudo_fqb); +extern OPFUNC(pseudo_ifne); +extern OPFUNC(pseudo_ifeq); +extern OPFUNC(pseudo_ifgt); +extern OPFUNC(pseudo_ifge); +extern OPFUNC(pseudo_iflt); +extern OPFUNC(pseudo_ifle); +extern OPFUNC(pseudo_else); +extern OPFUNC(pseudo_endc); +extern OPFUNC(pseudo_macro); +extern OPFUNC(pseudo_endm); +extern OPFUNC(pseudo_setdp); +extern OPFUNC(pseudo_set); +extern OPFUNC(pseudo_section); +extern OPFUNC(pseudo_endsection); +extern OPFUNC(pseudo_pragma); +extern OPFUNC(pseudo_starpragma); +extern OPFUNC(pseudo_extern); +extern OPFUNC(pseudo_export); +extern OPFUNC(pseudo_ifdef); +extern OPFUNC(pseudo_ifndef); + +instab_t instab[] = +{ + { "abx", { 0x3a, -0x1, -0x1, -0x1 }, insn_inh }, + { "adca", { 0x99, 0xa9, 0xb9, 0x89 }, insn_gen8 }, + { "adcb", { 0xd9, 0xe9, 0xf9, 0xc9 }, insn_gen8 }, + { "adcd", { 0x1099, 0x10a9, 0x10b9, 0x1089 }, insn_gen16 }, + { "adcr", { 0x1031, -0x1, -0x1, -0x1 }, insn_rtor }, + { "adda", { 0x9b, 0xab, 0xbb, 0x8b }, insn_gen8 }, + { "addb", { 0xdb, 0xeb, 0xfb, 0xcb }, insn_gen8 }, + { "addd", { 0xd3, 0xe3, 0xf3, 0xc3 }, insn_gen16 }, + { "adde", { 0x119b, 0x11ab, 0x11bb, 0x118b }, insn_gen8 }, + { "addf", { 0x11db, 0x11eb, 0x11fb, 0x11cb }, insn_gen8 }, + { "addr", { 0x1030, -0x1, -0x1, -0x1 }, insn_rtor }, + { "addw", { 0x109b, 0x10ab, 0x10bb, 0x108b }, insn_gen16 }, + { "aim", { 0x02, 0x62, 0x72, -0x1 }, insn_logicmem }, + { "anda", { 0x94, 0xa4, 0xb4, 0x84 }, insn_gen8 }, + { "andb", { 0xd4, 0xe4, 0xf4, 0xc4 }, insn_gen8 }, + { "andcc", { 0x1c, -0x1, -0x1, 0x1c }, insn_imm8 }, + { "andd", { 0x1094, 0x10a4, 0x10b4, 0x1084 }, insn_gen16 }, + { "andr", { 0x1034, -0x1, -0x1, -0x1 }, insn_rtor }, + { "asl", { 0x08, 0x68, 0x78, -0x1 }, insn_gen0 }, + { "asla", { 0x48, -0x1, -0x1, -0x1 }, insn_inh }, + { "aslb", { 0x58, -0x1, -0x1, -0x1 }, insn_inh }, + { "asld", { 0x1048, -0x1, -0x1, -0x1 }, insn_inh }, + { "asr", { 0x07, 0x67, 0x77, -0x1 }, insn_gen0 }, + { "asra", { 0x47, -0x1, -0x1, -0x1 }, insn_inh }, + { "asrb", { 0x57, -0x1, -0x1, -0x1 }, insn_inh }, + { "asrd", { 0x1047, -0x1, -0x1, -0x1 }, insn_inh }, + + { "band", { 0x1130, -0x1, -0x1, -0x1 }, insn_bitbit }, + { "bcc", { 0x24, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "bcs", { 0x25, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "beor", { 0x1134, -0x1, -0x1, -0x1 }, insn_bitbit }, + { "beq", { 0x27, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "bge", { 0x2c, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "bgt", { 0x2e, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "bhi", { 0x22, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "bhs", { 0x24, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "biand", { 0x1131, -0x1, -0x1, -0x1 }, insn_bitbit }, + { "bieor", { 0x1135, -0x1, -0x1, -0x1 }, insn_bitbit }, + { "bior", { 0x1133, -0x1, -0x1, -0x1 }, insn_bitbit }, + { "bita", { 0x95, 0xa5, 0xb5, 0x85 }, insn_gen8 }, + { "bitb", { 0xd5, 0xe5, 0xf5, 0xc5 }, insn_gen8 }, + { "bitd", { 0x1095, 0x10a5, 0x10b5, 0x1085 }, insn_gen16 }, + { "bitmd", { 0x113c, -0x1, -0x1, 0x113c }, insn_imm8 }, + { "ble", { 0x2f, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "blo", { 0x25, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "bls", { 0x23, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "blt", { 0x2d, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "bmi", { 0x2b, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "bne", { 0x26, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "bor", { 0x1132, -0x1, -0x1, -0x1 }, insn_bitbit }, + { "bpl", { 0x2a, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "bra", { 0x20, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "brn", { 0x21, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "bsr", { 0x8d, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "bvc", { 0x28, -0x1, -0x1, -0x1 }, insn_rel8 }, + { "bvs", { 0x29, -0x1, -0x1, -0x1 }, insn_rel8 }, + + { "clr", { 0x0f, 0x6f, 0x7f, -0x1 }, insn_gen0 }, + { "clra", { 0x4f, -0x1, -0x1, -0x1 }, insn_inh }, + { "clrb", { 0x5f, -0x1, -0x1, -0x1 }, insn_inh }, + { "clrd", { 0x104f, -0x1, -0x1, -0x1 }, insn_inh }, + { "clre", { 0x114f, -0x1, -0x1, -0x1 }, insn_inh }, + { "clrf", { 0x115f, -0x1, -0x1, -0x1 }, insn_inh }, + { "clrw", { 0x105f, -0x1, -0x1, -0x1 }, insn_inh }, + { "cmpa", { 0x91, 0xa1, 0xb1, 0x81 }, insn_gen8 }, + { "cmpb", { 0xd1, 0xe1, 0xf1, 0xc1 }, insn_gen8 }, + { "cmpd", { 0x1093, 0x10a3, 0x10b3, 0x1083 }, insn_gen16 }, + { "cmpe", { 0x1191, 0x11a1, 0x11b1, 0x1181 }, insn_gen8 }, + { "cmpf", { 0x11d1, 0x11e1, 0x11f1, 0x11c1 }, insn_gen8 }, + { "cmpr", { 0x1037, -0x1, -0x1, -0x1 }, insn_rtor }, + { "cmps", { 0x119c, 0x11ac, 0x11bc, 0x118c }, insn_gen16 }, + { "cmpu", { 0x1193, 0x11a3, 0x11b3, 0x1183 }, insn_gen16 }, + { "cmpw", { 0x1091, 0x10a1, 0x10b1, 0x1081 }, insn_gen16 }, + { "cmpx", { 0x9c, 0xac, 0xbc, 0x8c }, insn_gen16 }, + { "cmpy", { 0x109c, 0x10ac, 0x10bc, 0x108c }, insn_gen16 }, + { "com", { 0x03, 0x63, 0x73, -0x1 }, insn_gen0 }, + { "coma", { 0x43, -0x1, -0x1, -0x1 }, insn_inh }, + { "comb", { 0x53, -0x1, -0x1, -0x1 }, insn_inh }, + { "comd", { 0x1043, -0x1, -0x1, -0x1 }, insn_inh }, + { "come", { 0x1143, -0x1, -0x1, -0x1 }, insn_inh }, + { "comf", { 0x1153, -0x1, -0x1, -0x1 }, insn_inh }, + { "comw", { 0x1053, -0x1, -0x1, -0x1 }, insn_inh }, + { "cwai", { 0x3c, -0x1, -0x1, -0x1 }, insn_imm8 }, + + { "daa", { 0x19, -0x1, -0x1, -0x1 }, insn_inh }, + { "dec", { 0x0a, 0x6a, 0x7a, -0x1 }, insn_gen0 }, + { "deca", { 0x4a, -0x1, -0x1, -0x1 }, insn_inh }, + { "decb", { 0x5a, -0x1, -0x1, -0x1 }, insn_inh }, + { "decd", { 0x104a, -0x1, -0x1, -0x1 }, insn_inh }, + { "dece", { 0x114a, -0x1, -0x1, -0x1 }, insn_inh }, + { "decf", { 0x115a, -0x1, -0x1, -0x1 }, insn_inh }, + { "decw", { 0x105a, -0x1, -0x1, -0x1 }, insn_inh }, + { "divd", { 0x118d, 0x119d, 0x11ad, 0x11bd }, insn_gen8 }, + { "divq", { 0x118e, 0x119e, 0x11ae, 0x11be }, insn_gen16 }, + + { "eim", { 0x05, 0x65, 0x75, -0x1 }, insn_logicmem }, + { "eora", { 0x98, 0xa8, 0xb8, 0x88 }, insn_gen8 }, + { "eorb", { 0xd8, 0xe9, 0xf9, 0xc8 }, insn_gen8 }, + { "eord", { 0x1098, 0x10a8, 0x10b8, 0x1088 }, insn_gen16 }, + { "eorr", { 0x1036, -0x1, -0x1, -0x1 }, insn_rtor }, + { "exg", { 0x1e, -0x1, -0x1, -0x1 }, insn_rtor }, + + { "inc", { 0x0c, 0x6c, 0x7c, -0x1 }, insn_gen0 }, + { "inca", { 0x4c, -0x1, -0x1, -0x1 }, insn_inh }, + { "incb", { 0x5c, -0x1, -0x1, -0x1 }, insn_inh }, + { "incd", { 0x104c, -0x1, -0x1, -0x1 }, insn_inh }, + { "ince", { 0x114c, -0x1, -0x1, -0x1 }, insn_inh }, + { "incf", { 0x115c, -0x1, -0x1, -0x1 }, insn_inh }, + { "incw", { 0x105c, -0x1, -0x1, -0x1 }, insn_inh }, + + { "jmp", { 0x0e, 0x6e, 0x7e, -0x1 }, insn_gen0 }, + { "jsr", { 0x9d, 0xad, 0xbd, -0x1 }, insn_gen0 }, + + { "lbcc", { 0x1024, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbcs", { 0x1025, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbeq", { 0x1027, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbge", { 0x102c, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbgt", { 0x102e, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbhi", { 0x1022, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbhs", { 0x1024, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lble", { 0x102f, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lblo", { 0x1025, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbls", { 0x1023, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lblt", { 0x102d, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbmi", { 0x102b, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbne", { 0x1026, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbpl", { 0x102a, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbra", { 0x16, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbrn", { 0x1021, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbsr", { 0x17, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbvc", { 0x1028, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lbvs", { 0x1029, -0x1, -0x1, -0x1 }, insn_rel16 }, + { "lda", { 0x96, 0xa6, 0xb6, 0x86 }, insn_gen8 }, + { "ldb", { 0xd6, 0xe6, 0xf6, 0xc6 }, insn_gen8 }, + { "ldbt", { 0x1136, -0x1, -0x1, -0x1 }, insn_bitbit }, + { "ldd", { 0xdc, 0xec, 0xfc, 0xcc }, insn_gen16 }, + { "lde", { 0x1196, 0x11a6, 0x11b6, 0x1186 }, insn_gen8 }, + { "ldf", { 0x11d6, 0x11e6, 0x11f6, 0x11c6 }, insn_gen8 }, + { "ldq", { 0x10dc, 0x10ec, 0x10fc, 0xcd }, insn_gen32 }, + { "lds", { 0x10de, 0x10ee, 0x10fe, 0x10ce }, insn_gen16 }, + { "ldu", { 0xde, 0xee, 0xfe, 0xce }, insn_gen16 }, + { "ldw", { 0x1096, 0x10a6, 0x10b6, 0x1086 }, insn_gen16 }, + { "ldx", { 0x9e, 0xae, 0xbe, 0x8e }, insn_gen16 }, + { "ldy", { 0x109e, 0x10ae, 0x10be, 0x108e }, insn_gen16 }, + { "ldmd", { 0x113d, -0x1, -0x1, 0x113d }, insn_imm8 }, + { "leas", { 0x32, -0x1, -0x1, -0x1 }, insn_indexed }, + { "leau", { 0x33, -0x1, -0x1, -0x1 }, insn_indexed }, + { "leax", { 0x30, -0x1, -0x1, -0x1 }, insn_indexed }, + { "leay", { 0x31, -0x1, -0x1, -0x1 }, insn_indexed }, + { "lsl", { 0x08, 0x68, 0x78, -0x1 }, insn_gen0 }, + { "lsla", { 0x48, -0x1, -0x1, -0x1 }, insn_inh }, + { "lslb", { 0x58, -0x1, -0x1, -0x1 }, insn_inh }, + { "lsld", { 0x1048, -0x1, -0x1, -0x1 }, insn_inh }, + { "lsr", { 0x04, 0x64, 0x74, -0x1 }, insn_gen0 }, + { "lsra", { 0x44, -0x1, -0x1, -0x1 }, insn_inh }, + { "lsrb", { 0x54, -0x1, -0x1, -0x1 }, insn_inh }, + { "lsrd", { 0x1044, -0x1, -0x1, -0x1 }, insn_inh }, + { "lsrw", { 0x1054, -0x1, -0x1, -0x1 }, insn_inh }, + + { "mul", { 0x3d, -0x1, -0x1, -0x1 }, insn_inh }, + { "muld", { 0x118f, 0x119f, 0x11af, 0x11bf }, insn_gen16 }, + + { "neg", { 0x00, 0x60, 0x70, -0x1 }, insn_gen0 }, + { "nega", { 0x40, -0x1, -0x1, -0x1 }, insn_inh }, + { "negb", { 0x50, -0x1, -0x1, -0x1 }, insn_inh }, + { "negd", { 0x1040, -0x1, -0x1, -0x1 }, insn_inh }, + { "nop", { 0x12, -0x1, -0x1, -0x1 }, insn_inh }, + + { "oim", { 0x01, 0x61, 0x71, -0x1 }, insn_logicmem }, + { "ora", { 0x9a, 0xaa, 0xba, 0x8a }, insn_gen8 }, + { "orb", { 0xda, 0xea, 0xfa, 0xca }, insn_gen8 }, + { "orcc", { 0x1a, -0x1, -0x1, 0x1a }, insn_imm8 }, + { "ord", { 0x109a, 0x10aa, 0x10ba, 0x108a }, insn_gen16 }, + { "orr", { 0x1035, -0x1, -0x1, -0x1 }, insn_rtor }, + + { "pshs", { 0x34, -0x1, -0x1, -0x1 }, insn_rlist }, + { "pshsw", { 0x1038, -0x1, -0x1, -0x1 }, insn_inh }, + { "pshu", { 0x36, -0x1, -0x1, -0x1 }, insn_rlist }, + { "pshuw", { 0x103a, -0x1, -0x1, -0x1 }, insn_inh }, + { "puls", { 0x35, -0x1, -0x1, -0x1 }, insn_rlist }, + { "pulsw", { 0x1039, -0x1, -0x1, -0x1 }, insn_inh }, + { "pulu", { 0x37, -0x1, -0x1, -0x1 }, insn_rlist }, + { "puluw", { 0x103b, -0x1, -0x1, -0x1 }, insn_inh }, + + { "rol", { 0x09, 0x69, 0x79, -0x1 }, insn_gen0 }, + { "rola", { 0x49, -0x1, -0x1, -0x1 }, insn_inh }, + { "rolb", { 0x59, -0x1, -0x1, -0x1 }, insn_inh }, + { "rold", { 0x1049, -0x1, -0x1, -0x1 }, insn_inh }, + { "rolw", { 0x1059, -0x1, -0x1, -0x1 }, insn_inh }, + { "ror", { 0x06, 0x66, 0x76, -0x1 }, insn_gen0 }, + { "rora", { 0x46, -0x1, -0x1, -0x1 }, insn_inh }, + { "rorb", { 0x56, -0x1, -0x1, -0x1 }, insn_inh }, + { "rord", { 0x1046, -0x1, -0x1, -0x1 }, insn_inh }, + { "rorw", { 0x1056, -0x1, -0x1, -0x1 }, insn_inh }, + { "rti", { 0x3b, -0x1, -0x1, -0x1 }, insn_inh }, + { "rts", { 0x39, -0x1, -0x1, -0x1 }, insn_inh }, + + { "sbca", { 0x92, 0xa2, 0xb2, 0x82 }, insn_gen8 }, + { "sbcb", { 0xd2, 0xe2, 0xf2, 0xc2 }, insn_gen8 }, + { "sbcd", { 0x1092, 0x10a2, 0x10b2, 0x1082 }, insn_gen16 }, + { "sbcr", { 0x1033, -0x1, -0x1, -0x1 }, insn_rtor }, + { "sex", { 0x1d, -0x1, -0x1, -0x1 }, insn_inh }, + { "sexw", { 0x14, -0x1, -0x1, -0x1 }, insn_inh }, + { "sta", { 0x97, 0xa7, 0xb7, -0x1 }, insn_gen0 }, + { "stb", { 0xd7, 0xe7, 0xf7, -0x1 }, insn_gen0 }, + { "stbt", { 0x1137, -0x1, -0x1, -0x1 }, insn_bitbit }, + { "std", { 0xdd, 0xed, 0xfd, -0x1 }, insn_gen0 }, + { "ste", { 0x1197, 0x11a7, 0x11b7, -0x1 }, insn_gen0 }, + { "stf", { 0x11d7, 0x11e7, 0x11f7, -0x1 }, insn_gen0 }, + { "stq", { 0x10dd, 0x10ed, 0x10fd, -0x1 }, insn_gen0 }, + { "sts", { 0x10df, 0x10ef, 0x10ff, -0x1 }, insn_gen0 }, + { "stu", { 0xdf, 0xef, 0xff, -0x1 }, insn_gen0 }, + { "stw", { 0x1097, 0x10a7, 0x10b7, -0x1 }, insn_gen0 }, + { "stx", { 0x9f, 0xaf, 0xbf, -0x1 }, insn_gen0 }, + { "sty", { 0x109f, 0x10af, 0x10bf, -0x1 }, insn_gen0 }, + { "suba", { 0x90, 0xa0, 0xb0, 0x80 }, insn_gen8 }, + { "subb", { 0xd0, 0xe0, 0xf0, 0xc0 }, insn_gen8 }, + { "subd", { 0x93, 0xa3, 0xb3, 0x83 }, insn_gen16 }, + { "sube", { 0x1190, 0x11a0, 0x11b0, 0x1180 }, insn_gen8 }, + { "subf", { 0x11d0, 0x11e0, 0x11f0, 0x11c0 }, insn_gen8 }, + { "subr", { 0x1032, -0x1, -0x1, -0x1 }, insn_rtor }, + { "subw", { 0x1090, 0x10a0, 0x1090, 0x1080 }, insn_gen8 }, + { "swi", { 0x3f, -0x1, -0x1, -0x1 }, insn_inh }, + { "swi2", { 0x103f, -0x1, -0x1, -0x1 }, insn_inh }, + { "swi3", { 0x113f, -0x1, -0x1, -0x1 }, insn_inh }, + { "sync", { 0x13, -0x1, -0x1, -0x1 }, insn_inh }, + + // note: r+,r+ r-,r- r+,r r,r+ + { "tfm", { 0x1138, 0x1139, 0x113a, 0x113b }, insn_tfm }, + + { "tfr", { 0x1f, -0x1, -0x1, -0x1 }, insn_rtor }, + { "tim", { 0x0b, 0x6b, 0x7b, -0x1 }, insn_logicmem }, + { "tst", { 0x0d, 0x6d, 0x7d, -0x1 }, insn_gen0 }, + { "tsta", { 0x4d, -0x1, -0x1, -0x1 }, insn_inh }, + { "tstb", { 0x5d, -0x1, -0x1, -0x1 }, insn_inh }, + { "tstd", { 0x104d, -0x1, -0x1, -0x1 }, insn_inh }, + { "tste", { 0x114d, -0x1, -0x1, -0x1 }, insn_inh }, + { "tstf", { 0x115d, -0x1, -0x1, -0x1 }, insn_inh }, + { "tstw", { 0x105d, -0x1, -0x1, -0x1 }, insn_inh }, + + { "org", { -1, -1, -1, -1 }, pseudo_org }, + + { "equ", { -1, -1, -1, -1 }, pseudo_equ, 0, 0, 1 }, + { "=", { -1, -1, -1, -1 }, pseudo_equ, 0, 0, 1 }, + { "extern", { -1, -1, -1, -1 }, pseudo_extern, 0, 0, 1 }, + { "external", { -1, -1, -1, -1 }, pseudo_extern, 0, 0, 1 }, + { "import", { -1, -1, -1, -1 }, pseudo_extern, 0, 0, 1 }, + { "export", { -1, -1, -1, -1 }, pseudo_export, 0, 0, 1 }, + + + { "rmb", { -1, -1, -1, -1 }, pseudo_rmb }, + { "rmd", { -1, -1, -1, -1 }, pseudo_rmd }, + { "rmq", { -1, -1, -1, -1 }, pseudo_rmq }, + + { "zmb", { -1, -1, -1, -1 }, pseudo_zmb }, + { "zmd", { -1, -1, -1, -1 }, pseudo_zmd }, + { "zmq", { -1, -1, -1, -1 }, pseudo_zmq }, + + { "fcc", { -1, -1, -1, -1 }, pseudo_fcc }, + { "fcn", { -1, -1, -1, -1 }, pseudo_fcn }, + { "fcs", { -1, -1, -1, -1 }, pseudo_fcs }, + + { "fcb", { -1, -1, -1, -1 }, pseudo_fcb }, + { "fdb", { -1, -1, -1, -1 }, pseudo_fdb }, + { "fqb", { -1, -1, -1, -1 }, pseudo_fqb }, + + { "end", { -1, -1, -1, -1 }, pseudo_end }, + + { "include", { -1, -1, -1, -1 }, pseudo_include }, + + { "align", { -1, -1, -1, -1 }, pseudo_align }, + + { "error", { -1, -1, -1, -1}, pseudo_error }, + + { "ifeq", { -1, -1, -1, -1}, pseudo_ifeq, 1 }, + { "ifne", { -1, -1, -1, -1}, pseudo_ifne, 1 }, + { "if", { -1, -1, -1, -1}, pseudo_ifne, 1 }, + { "ifgt", { -1, -1, -1, -1}, pseudo_ifgt, 1 }, + { "ifge", { -1, -1, -1, -1}, pseudo_ifge, 1 }, + { "iflt", { -1, -1, -1, -1}, pseudo_iflt, 1 }, + { "ifle", { -1, -1, -1, -1}, pseudo_ifle, 1 }, + { "endc", { -1, -1, -1, -1}, pseudo_endc, 1 }, + { "else", { -1, -1, -1, -1}, pseudo_else, 1 }, + { "ifdef", { -1, -1, -1, -1}, pseudo_ifdef, 1}, + { "ifndef", { -1, -1, -1, -1}, pseudo_ifndef, 1}, + + { "macro", { -1, -1, -1, -1}, pseudo_macro, 1, 0, 1 }, + { "endm", { -1, -1, -1, -1}, pseudo_endm, 1, 1, 1 }, + + { "setdp", { -1, -1, -1, -1}, pseudo_setdp }, + { "set", { -1, -1, -1, -1}, pseudo_set, 0, 0, 1 }, + + { "section", { -1, -1, -1, -1}, pseudo_section }, + { "sect", { -1, -1, -1, -1}, pseudo_section }, + { "ends", { -1, -1, -1, -1}, pseudo_endsection }, + { "endsect", { -1, -1, -1, -1}, pseudo_endsection }, + { "endsection", { -1, -1, -1, -1}, pseudo_endsection }, + + { "pragma", { -1, -1, -1, -1}, pseudo_pragma }, + { "*pragma", { -1, -1, -1, -1}, pseudo_starpragma }, + + + /* flag end of table */ + { NULL, { -0x1, -0x1, -0x1, -0x1 }, insn_inh } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/instab.h Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,45 @@ +/* +instab.h +Copyright © 2008 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + + +Contains definitions for the instruction table +*/ + +#ifndef __instab_h_seen__ +#define __instab_h_seen__ + +#include "lwasm.h" + +typedef struct +{ + char *opcode; /* the mneumonic */ + int ops[4]; /* opcode values for up to four addr modes */ + void (*fn)(asmstate_t *as, lwasm_line_t *l, char **optr, int opnum); + int iscond; /* set if this should be dispatched even if skipping a condition/macro */ + int endm; /* end of macro? */ + int setsym; /* does this set a symbol address? EQU, SET */ +} instab_t; + +#define OPFUNC(fn) void (fn)(asmstate_t *as, lwasm_line_t *l, char **p, int opnum) + +#ifndef __instab_c_seen__ +extern instab_t instab[]; +#endif //__instab_c_seen__ + +#endif //__instab_h_seen__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/list.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,139 @@ +/* +list.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + +Contains code for displaying a program listings, etc. +*/ + +#define __list_c_seen__ + +#include <stdio.h> +#include <stdlib.h> + +#include "lwasm.h" + +void lwasm_show_errors(asmstate_t *as) +{ + lwasm_line_t *l; + lwasm_error_t *e; + + for (l = as -> lineshead; l; l = l -> next) + { + if (l -> err) + { + for (e = l -> err; e; e = e -> next) + { + fprintf(stderr, "ERROR: %s\n", e -> mess); + } + fprintf(stderr, "%s:%d: %s\n", l -> filename, l -> lineno, l -> text); + } + } +} + +void lwasm_list(asmstate_t *as) +{ + FILE *lf; + lwasm_line_t *l; + int c, c3; + char *p; + + if (!as -> listfile) + return; + if (as -> listfile[0] == '-' && as -> listfile[1] == '\0') + lf = stdout; + else + { + lf = fopen(as -> listfile, "w"); + if (!lf) + { + fprintf(stderr, "Unable to open list file '%s'. No listing will be generated: ", as -> listfile); + perror(""); + goto showerr; + } + } + + for (l = as -> lineshead; l; l = l -> next) + { + if (l -> addrset == 1 || l -> codelen > 0 || l -> nocodelen > 0) + { + fprintf(lf, "%04X ", l -> codeaddr); + } + else + { + fprintf(lf, " "); + } + + if (l -> addrset == 2) + { + fprintf(lf, "%04X ", l -> symaddr); + } + else + { + for (c = 0; c < l -> codelen && c < 5; c++) + { + fprintf(lf, "%02X", l -> bytes[c]); + } + while (c < 5) + { + fprintf(lf, " "); + c++; + } + } + fprintf(lf, " %20.20s:%05d ", l -> filename, l -> lineno); + + // print line here + for (c3 = 0, c = 0, p = l -> text; *p; c++, p++) + { + if (*p == '\t') + { + int c2; + c2 = 8 - (c3 % 8); + c3 += c2; + while (c2--) fputc(' ', lf); + } + else + { + c3++; + fputc(*p, lf); + } + } + fputc('\n', lf); + + if (l -> codelen > 5) + { + fprintf(lf, "%04X ", (l -> codeaddr + 5) & 0xFFFF); + for (c = 5; c < l -> codelen; c++) + { + if (!(c % 5) && c != 5) + { + fprintf(lf, "\n%04X ", (l -> codeaddr + c) & 0xFFFF); + } + fprintf(lf, "%02X", l -> bytes[c]); + } + fputc('\n', lf); + } + } + + lwasm_list_symbols(as, lf); + + if (lf != stdout) + fclose(lf); + +showerr: + lwasm_show_errors(as); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/lwasm.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,428 @@ +/* +lwasm.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + + +Contains random functions used by the assembler +*/ + +#define __lwasm_c_seen__ + +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> + +#include "lwasm.h" +#include "util.h" +#include "expr.h" + +int debug_level = 0; + +int register_error(asmstate_t *as, lwasm_line_t *l, int pass, const char *fmt, ...) +{ + lwasm_error_t *e; + va_list args; + char errbuff[1024]; + int r; + + if (!l) + return; + + if (as -> passnum != pass) + return; + + va_start(args, fmt); + + e = lwasm_alloc(sizeof(lwasm_error_t)); + + e -> next = l -> err; + l -> err = e; + + as -> errorcount++; + + r = vsnprintf(errbuff, 1024, fmt, args); + e -> mess = lwasm_strdup(errbuff); + + va_end(args); + + return r; +} + +void lwasm_emit(asmstate_t *as, lwasm_line_t *l, int b) +{ + as -> addr += 1; + as -> addr &= 0xffff; + + if (as -> outformat == OUTPUT_OBJ && !(as -> csect)) + { + register_error(as, l, 1, "Output not allowed outside sections with obj target"); + return; + } + if (as -> outformat == OUTPUT_OBJ && as -> csect -> flags & SECTION_BSS) + { + register_error(as, l, 1, "Output not allowed inside BSS sections"); + return; + } + if (as -> passnum == 1) + return; + + + if (l -> codelen >= l -> codesize) + { + l -> bytes = realloc(l -> bytes, l -> codesize + 16); + l -> codesize += 16; + } + l -> bytes[l -> codelen] = b & 0xff; + l -> codelen += 1; +} + +void lwasm_emitop(asmstate_t *as, lwasm_line_t *l, int o) +{ + if (o >= 0x100) + lwasm_emit(as, l, o >> 8); + lwasm_emit(as, l, o & 0xff); +} + +int lwasm_lookupreg2(const char *reglist, char **str) +{ + int rval = 0; + + while (*reglist) + { + if (toupper(**str) == *reglist) + { + // first char matches + if (reglist[1] == ' ' && !isalpha(*(*str + 1))) + break; + if (toupper(*(*str + 1)) == reglist[1]) + break; + } + reglist += 2; + rval++; + } + if (!*reglist) + return -1; + if (reglist[1] == ' ') + (*str)++; + else + (*str) += 2; + return rval; +} + +int lwasm_lookupreg3(const char *rlist, const char **str) +{ + int rval = 0; + int f = 0; + const char *reglist = rlist; + + while (*reglist) + { + if (toupper(**str) == *reglist) + { + // first char matches + if (reglist[1] == ' ') + { + f = 1; + break; + } + if (toupper(*(*str + 1)) == reglist[1]) + { + // second char matches + if (reglist[2] == ' ') + { + f = 1; + break; + } + if (toupper(*(*str + 2)) == reglist[2]) + { + f = 1; + break; + } + } + } + reglist += 3; + rval++; + } + if (f == 0) + return -1; + + + reglist = rval * 3 + rlist; + if (reglist[1] == ' ') + (*str) += 1; + else if (reglist[2] == ' ') + (*str) += 2; + else + (*str)+=3; + return rval; +} + +struct symstateinfo +{ + asmstate_t *as; + lwasm_line_t *l; + int flags; +}; + +lwasm_expr_stack_t *lwasm_expr_lookup_symbol(char *sym, void *state) +{ + lwasm_symbol_ent_t *se; + struct symstateinfo *st; + lwasm_expr_stack_t *rs; + lwasm_expr_term_t *t; + lwasm_expr_stack_node_t *n; + + int val; + + st = state; + debug_message(3, "lwasm_expr_lookup_symbol(): find '%s' (context=%d)", sym, st -> as -> context); + + // check for special symbols first... + if (sym[1] == '\0') + { + switch (sym[0]) + { + // current line address + case '*': + case '.': + val = st -> l -> codeaddr; + goto retconst; + + case '<': + // previous branch point + // not implemented + break; + case '>': + // next branch point + // not implemented + break; + } + } + + // look for local symbol first then global symbol + se = lwasm_find_symbol(st -> as, sym, st -> as -> context); + if (!se) + se = lwasm_find_symbol(st -> as, sym, -1); + debug_message(3, "lwasm_expr_lookup_symbol(): got '%p'", se); + if (!se) + { + register_error(st -> as, st -> l, 2, "Undefined symbol '%s'", sym); + return NULL; + } + // external reference - can not resolve it + if (se -> flags & SYMBOL_EXTERN) + { + return NULL; + } + if (st -> flags & EXPR_SECTCONST) + { + if (se -> sect == st -> l -> sect) + { + if (se -> expr) + goto retsym; + val = se -> value; + goto retconst; + } + } + if (st -> as -> outformat == OUTPUT_OBJ && se -> sect != NULL) + { + return NULL; + } + if (st -> as -> outformat != OUTPUT_OBJ || se -> sect == NULL) + { + // global symbol, intrasegment reference, or not an object target + val = se -> value; + goto retconst; + } + + // an intersegment reference will return as NULL (to be resolved at output/link time) + // if se -> expr is NULL, it has to be an intersegment reference here + if (se -> expr == NULL) + { + return NULL; + } + +retsym: + // duplicate the expression for return + rs = lwasm_expr_stack_create(); + for (n = se -> expr -> head; n; n = n -> next) + { + lwasm_expr_stack_push(rs, n -> term); + } + return rs; + +retconst: + rs = lwasm_expr_stack_create(); + t = lwasm_expr_term_create_int(val); + lwasm_expr_stack_push(rs, t); + lwasm_expr_term_free(t); + return rs; +} + +lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp, int flags) +{ + struct symstateinfo st; + + st.as = as; + st.l = l; + st.flags = flags; + + debug_message(2, "Evaluate expression: %s", inp); + + return(lwasm_expr_eval(inp, outp, lwasm_expr_lookup_symbol, &st)); +} + + +int lwasm_reevaluate_expr(asmstate_t *as, lwasm_line_t *l, lwasm_expr_stack_t *s, int flags) +{ + struct symstateinfo st; + + st.as = as; + st.l = l; + st.flags = flags; + return(lwasm_expr_reval(s, lwasm_expr_lookup_symbol, &st)); +} + +// return 1 if no undefined symbols (externals and incompletes are okay) +// return 0 if there are undefined symbols +int lwasm_expr_result_ckconst(asmstate_t *as, lwasm_expr_stack_t *s) +{ + lwasm_expr_stack_node_t *n; + lwasm_symbol_ent_t *se; + + if (as -> outformat != OUTPUT_OBJ) + { + if (lwasm_expr_is_constant(s)) + return 1; + else + return 0; + } + + for (n = s -> head; n; n = n -> next) + { + if (n -> term -> term_type == LWASM_TERM_SYM) + { + se = lwasm_find_symbol(as, n -> term -> symbol, as -> context); + if (!se) + se = lwasm_find_symbol(as, n -> term -> symbol, -1); + if (!se) + return 0; + } + } + return 1; +} + +/* +Evaluate an expression according to the flag value. Return 0 if a constant result was +obtained, 1 if an incomplete result was obtained, and -1 if an error was flagged. + +*/ +int lwasm_expr_result2(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val, int slot) +{ + lwasm_expr_stack_t *s = NULL; + const char *ep; + int rval; + + if ((as -> passnum == 1 && !(flag & EXPR_REEVAL)) || slot < 0) + { + s = lwasm_evaluate_expr(as, l, *inp, &ep, flag); + if (slot >= 0) + l -> exprs[slot] = s; + if (!s) + { + register_error(as, l, 1, "Bad expression"); + *val = 0; + return -1; + } + *inp = (char *)ep; + if (slot >= 0) + { + l -> exprends[slot] = (char *)ep; + l -> exprvals[slot] = lwasm_expr_get_value(s); + } + } + else if (l -> exprs[slot]) + { + s = l -> exprs[slot]; + lwasm_reevaluate_expr(as, l, s, flag); + l -> exprvals[slot] = lwasm_expr_get_value(s); + } + if (as -> passnum == 2 && slot >= 0) + *inp = l -> exprends[slot]; + + if (s && lwasm_expr_is_constant(s)) + { + *val = lwasm_expr_get_value(s); + lwasm_expr_stack_free(s); + l -> exprs[slot] = NULL; + s = NULL; + return 0; + } + + if (!s && slot >= 0) + { + *val = l -> exprvals[slot]; + return 0; + } + else if (!s) + { + *val = 0; + return 0; + } + + // was a constant result on pass 1 requested? + // that means we must have a constant on either pass + if (flag & EXPR_PASS1CONST) + { + *val = 0; + if (slot >= 0) + l -> exprvals[slot] = 0; + register_error(as, l, 1, "Illegal forward, external, or inter-section reference"); + lwasm_expr_stack_free(s); + if (slot >= 0) + l -> exprs[slot] = NULL; + return -1; + } + + return 1; +} + +void debug_message(int level, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + if (debug_level >= level) + { + if (level > 0) + fprintf(stderr, "DEBUG %d: ", level); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + } + va_end(args); +} + +int lwasm_next_context(asmstate_t *as) +{ + int r; + r = as -> nextcontext; + as -> nextcontext += 1; + debug_message(3, "lwasm_next_context(): %d (%d) pass %d", r, as -> nextcontext, as -> passnum); + return r; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/lwasm.h Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,234 @@ +/* +lwasm.h +Copyright © 2008 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + +Contains the main defs used by the assembler +*/ + + +#ifndef __lwasm_h_seen__ +#define __lwasm_h_seen__ + +#include <stdio.h> +#include "expr.h" + +#define OUTPUT_DECB 0 // DECB multirecord format +#define OUTPUT_RAW 1 // raw sequence of bytes +#define OUTPUT_OBJ 2 // proprietary object file format +#define OUTPUT_RAWREL 3 // raw bytes where ORG causes a SEEK in the file + +// structure for tracking sections +typedef struct section_reloc_list_s section_reloc_list_t; +struct section_reloc_list_s +{ + int offset; // offset into section + lwasm_expr_stack_t *expr; // value definition + int context; // symbol context (for local syms) + section_reloc_list_t *next; // next relocation +}; + +typedef struct export_list_s export_list_t; +struct export_list_s +{ + int offset; // offset of symbol + char *sym; // name of symbol + export_list_t *next; // next export +}; + +#define SECTION_BSS 1 // the section contains no actual code - just uninit vars +typedef struct sectiontab_s sectiontab_t; +struct sectiontab_s +{ + char *name; // name of the section + int offset; // current offset in the section + int flags; // section flags + sectiontab_t *next; // next section + // the following are used during code output + unsigned char *obytes; // output bytes + int oblen; // how many bytes output so far? + int obsize; // how big is output buffer so far? + section_reloc_list_t *rl; // relocation list + export_list_t *exports; // export list for the section +}; + +// structure for tracking macros +typedef struct macrotab_s macrotab_t; +struct macrotab_s +{ + char *name; + char **lines; + int numlines; + macrotab_t *next; +}; + +// structure for tracking errors +typedef struct lwasm_error_s lwasm_error_t; +struct lwasm_error_s +{ + char *mess; // the actual error message + lwasm_error_t *next; // ptr to next error +}; + +// structure for keeping track of lines +// it also as space for 4 expressions which is enough for all known +// instructions and addressing modes +// on pass 1, the expressions are parsed, on pass 2 they are re-evaluated +// to determine constancy +typedef struct lwasm_line_s lwasm_line_t; +struct lwasm_line_s { + char *text; // the actual text of the line + int lineno; // line number within the file + char *filename; // file name reference + lwasm_line_t *next; // next line + lwasm_line_t *prev; // previous line + lwasm_error_t *err; // error messages + int fsize; // forced size (0 = no forced size) + char *sym; // scratch area to record the presence of a symbol + unsigned char *bytes; // actual bytes emitted + int codelen; // number of bytes emitted + int codesize; // the size of the code buffer + int codeaddr; // address the code goes at + int nocodelen; // for "RMB" type instructions + int addrset; // set if this instruction sets the assembly address + int symaddr; // set if this instruction sets a symbol addr with EQU or the like + int badop; // bad operation - ignore it + int context; // the symbol context for this line + + // the following are used for obj format - for external references, inter-section + // references, and intrasection relocations + int relocoff; // offset into insn where relocation value goes + lwasm_expr_stack_t *exprs[4]; // non-constant expression values + int exprvals[4]; // constant expression values + char *exprends[4]; // pointer to character after end of expression + + sectiontab_t *sect; // which section is the line in? +}; + +// for keeping track of symbols +#define SYMBOL_SET 1 // the symbol was used for "SET" +#define SYMBOL_COMPLEX 2 // register symbol as a complex symbol (from l -> expr) +#define SYMBOL_FORCE 4 // force resetting the symbol value if it already exists on pass 2 +#define SYMBOL_NORM 0 // no flags +#define SYMBOL_EXTERN 8 // the symbol is an external reference +typedef struct lwasm_symbol_ent_s lwasm_symbol_ent_t; +struct lwasm_symbol_ent_s +{ + char *sym; // the symbol + int context; // the context number of the symbol (-1 for global) + int value; // the value of the symbol + int flags; // flags for the symbol + char *externalname; // for external references that are aliased locally + sectiontab_t *sect; // the section the symbol exists in; NULL for none + lwasm_expr_stack_t *expr; // expression for a symbol that is not constant NULL for const + lwasm_symbol_ent_t *next; // next symbol in the table + lwasm_symbol_ent_t *prev; // previous symbol in the table +}; + +// keep track of current assembler state +typedef struct { + int dpval; // current dp value (setdp) + int addr; // current address + int context; // context counter (for local symbols) + int errorcount; // error count + int passnum; // which pass are we on? + int execaddr; // execution address for the program (END ....) + int pragmas; // what pragmas are in effect? + + lwasm_line_t *lineshead; // first line of source code + lwasm_line_t *linestail; // last line of source code + + lwasm_symbol_ent_t *symhead; // first entry in symbol table + lwasm_symbol_ent_t *symtail; // last entry in symbol table + + macrotab_t *macros; // macro table + + const char *infile; // input file + const char *outfile; // output file + const char *listfile; // output listing file + int outformat; // output format type + char **filelist; // files that have been read + int filelistlen; // number of files in the list + + int endseen; // set to true if "end" has been seen + int skipcond; // skipping a condition? + int skipcount; // how many? + int skipmacro; // skipping a macro? + int inmacro; // are we currently in a macro? + int macroex; // current depth of macro expansion + int nextcontext; // next context number + int skiplines; // number of lines to skip + + // items used only for the "object" target + sectiontab_t *sections; // pointer to section table + sectiontab_t *csect; // current section - NULL if not in one +} asmstate_t; + +// do not rewrite XXX,r to ,r if XXX evaluates to 0 +#define PRAGMA_NOINDEX0TONONE 1 +// any undefined symbols are considered external +#define PRAGMA_UNDEFEXTERN 2 + +#ifndef __lwasm_c_seen__ +#define __lwasm_E__ extern +#else +#define __lwasm_E__ +#endif + +__lwasm_E__ int debug_level; + +__lwasm_E__ int register_error(asmstate_t *as, lwasm_line_t *l, int pass, const char *fmt, ...); +__lwasm_E__ void debug_message(int level, const char *fmt, ...); + +__lwasm_E__ void lwasm_emit(asmstate_t *as, lwasm_line_t *l, int b); +__lwasm_E__ void lwasm_emitop(asmstate_t *as, lwasm_line_t *l, int o); +__lwasm_E__ int lwasm_lookupreg2(const char *reglist, char **str); +__lwasm_E__ int lwasm_lookupreg3(const char *rlist, const char **str); + +__lwasm_E__ lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp, int flags); + + +// return next context number and update it +__lwasm_E__ int lwasm_next_context(asmstate_t *as); + +// also throw an error on expression eval failure +// return 0 on ok, -1 on error, 1 if a complex expression was returned +#define EXPR_NOFLAG 0 +#define EXPR_PASS1CONST 1 // no forward references on pass 1 +#define EXPR_SECTCONST 2 // resolve symbols local to section +#define EXPR_REEVAL 4 // re-evaluate the expression +__lwasm_E__ int lwasm_expr_result(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val); +__lwasm_E__ int lwasm_expr_result2(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val, int slot); + +#undef __lwasm_E__ + + +#ifndef __symbol_c_seen__ +#define __lwasm_E__ extern +#else +#define __lwasm_E__ +#endif + +__lwasm_E__ int lwasm_register_symbol(asmstate_t *as, lwasm_line_t *l, char *sym, int val, int flags); +__lwasm_E__ lwasm_symbol_ent_t *lwasm_find_symbol(asmstate_t *as, char *sym, int scontext); +__lwasm_E__ int lwasm_set_symbol(asmstate_t *as, char *sym, int scontext, int val); +__lwasm_E__ void lwasm_list_symbols(asmstate_t *as, FILE *f); +#undef __lwasm_E__ + + + +#endif //__lwasm_h_seen__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/lwval.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,210 @@ +/* +lwval.c +Copyright © 2008 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +This file contains implementations associated with the expression evaluator +used by LWASM. + +*/ + +#include <malloc.h> + +#define __lwval_c_seen__ +#include "lwval.h" + +LWVAL *lwval_construct_int(int value) +{ + LWVAL *v; + + v = malloc(sizeof(LWVAL)); + if (!v) + return NULL; + + v -> lwval_type = LWVAL_TYPE_INT; + v -> dt.lwval_int = value; + + return v; +} + +LWVAL *lwval_construct_err(int errno) +{ + LWVAL *v; + + v = malloc(sizeof(LWVAL)); + if (!v) + return NULL; + + v -> lwval_type = LWVAL_TYPE_ERR; + v -> dt.lwval_int = errno; + + return v; +} + +LWVAL *lwval_construct_nan(void) +{ + LWVAL *v; + + v = malloc(sizeof(LWVAL)); + if (!v) + return NULL; + + v -> lwval_type = LWVAL_TYPE_NAN; + + return v; +} + +LWVAL *lwval_construct_undef(void) +{ + LWVAL *v; + + v = malloc(sizeof(LWVAL)); + if (!v) + return NULL; + + v -> lwval_type = LWVAL_TYPE_UNDEF; + + return v; +} + +LWVAL *lwval_construct_expr(LWVAL *v1, LWVAL *v2, int op) +{ + LWVAL *v; + v = malloc(sizeof(LWVAL)); + if (!v) + return NULL; + + v -> lwval_type = LWVAL_TYPE_EXPR; + v -> dt.expr.v1 = v1; + v -> dt.expr.v2 = v2; + v -> dt.expr.op = op; + return v; +} + +void lwval_destroy(LWVAL *value) +{ + if (value) + { + lwval_clear(value); + free(value); + } +} + +// performs a deep copy of an LWVAL, including ALL referenced values +void lwval_dup(LWVAL *v1, LWVAL *v2) +{ + lwval_clear(v2); + + switch (v1 -> lwval_type) + { + case LWVAL_TYPE_INT: + case LWVAL_TYPE_ERR: + v2 -> dt.lwval_int = v1 -> dt.lwval_int; + break; + + case LWVAL_TYPE_EXPR: + v2 -> dt.expr.op = v1 -> dt.expr.op; + if (v1 -> dt.expr.v1) + { + v2 -> dt.expr.v1 = lwval_construct_undef(); + lwval_dup(v1 -> dt.expr.v1, v2 -> dt.expr.v1); + } + else + v2 -> dt.expr.v1 = NULL; + if (v1 -> dt.expr.v2) + { + v2 -> dt.expr.v2 = lwval_construct_undef(); + lwval_dup(v1 -> dt.expr.v2, v2 -> dt.expr.v2); + } + else + v2 -> dt.expr.v2 = NULL; + break; + } + + v2 -> lwval_type = v1 -> lwval_type; +} + +void lwval_clear(LWVAL *value) +{ + switch (value -> lwval_type) + { + case LWVAL_TYPE_EXPR: + lwval_destroy(value -> dt.expr.v1); + lwval_destroy(value -> dt.expr.v2); + break; + } + value -> lwval_type = LWVAL_TYPE_UNDEF; +} + +// for integer, simply negate value +// for expr, change to "-1 * (expr)" +// everything else: error +LWVAL *lwval_neg(LWVAL *v1) +{ + switch (v1 -> lwval_type) + { + case LWVAL_TYPE_INT: + v1 -> dt.lwval_int = -(v1 -> dt.lwval_int); + break; + + case LWVAL_TYPE_EXPR: + { + LWVAL *v, *v2; + v = lwval_construct_undef(); + lwval_dup(v1, v); + lwval_clear(v1); + v2 = lwval_construct_expr(lwval_construct_int(-1), v, '*'); + lwval_dup(v2, v1); + lwval_destroy(v2); + } + break; + + default: + lwval_clear(v1); + v1 -> lwval_type = LWVAL_TYPE_ERR; + v1 -> dt.lwval_int = 1; + } + + return v1; +} + +// v1 + v2 -> v1 +LWVAL *lwval_add(LWVAL *v1, LWVAL *v2) +{ +} + +// v1 - v2 -> v1 +LWVAL *lwval_sub(LWVAL *v1, LWVAL *v2) +{ +} + +// v1 * v2 -> v1 +LWVAL *lwval_mul(LWVAL *v1, LWVAL *v2) +{ +} + +// v1 / v2 -> v1 +LWVAL *lwval_div(LWVAL *v1, LWVAL *v2) +{ +} + +// v1 % v2 -> v1 +LWVAL *lwval_mod(LWVAL *v1, LWVAL *v2) +{ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/lwval.h Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,113 @@ +/* +lwval.h +Copyright © 2008 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +This file contains definitions associated with the expression evaluator used +by LWASM. + +The core of the entire expression handler is the opaque type LWVAL, pointers +to which are passed around to keep track of values. A value may be a simple +integer or it could be a more complex expression linked by operators or it +could be a polynomial expression. Simple integers are merely a degenerate +case of polynomials. + +The package understands the following operations: + +addition +subtraction +multiplication +division +modulus +parentheses +unary negation +unary "positive" +bitwise and +bitwise or +bitwise not (1's complement) +bitwise exclusive or + +Infix operators can be expressed as LWVAL <op> LWVAL. Thus, the order of +operations is only relevant when initially parsing the expression. The order +of evaluation is determined by what appears on either side of the <op> as +an LWVAL may be an expression. +*/ + +#ifndef __lwval_h_seen__ +#define __lwval_h_seen__ + +typedef struct lwval LWVAL; + +struct lwval_dt_expr +{ + LWVAL *v1; // first value + LWVAL *v2; // second value + int op; // operator +}; + +union lwval_dt +{ + int lwval_int; // integer type data + char *lwval_var; // pointer to variable name + struct lwval_dt_expr expr; // expression +}; + +enum +{ + LWVAL_TYPE_UNDEF, // undefined + LWVAL_TYPE_NAN, // not a number + LWVAL_TYPE_INT, // integer + LWVAL_TYPE_VAR, // variable (symbol) + LWVAL_TYPE_EXPR, // expression + LWVAL_TYPE_ERR // error +}; + +struct lwval +{ + int lwval_type; // data type + union lwval_dt dt; // type specific stuff +}; + +#ifndef __lwval_c_seen__ +#define __lwval_extern__ extern +#else +#define __lwval_extern__ +#endif + +__lwval_extern__ LWVAL *lwval_construct_int(int value); +__lwval_extern__ LWVAL *lwval_construct_err(int errno); +__lwval_extern__ LWVAL *lwval_construct_nan(void); +__lwval_extern__ LWVAL *lwval_construct_expr(LWVAL *v1, LWVAL *v2, int op); +__lwval_extern__ LWVAL *lwval_construct_undef(void); +__lwval_extern__ void lwval_clear(LWVAL *value); +__lwval_extern__ void lwval_destroy(LWVAL *value); +__lwval_extern__ void lwval_dup(LWVAL *v1, LWVAL *v2); + +// operators - operate on v1 and v2 in order, result goes into +// v1; return v1 +__lwval_extern__ LWVAL *lwval_add(LWVAL *v1, LWVAL *v2); +__lwval_extern__ LWVAL *lwval_sub(LWVAL *v1, LWVAL *v2); +__lwval_extern__ LWVAL *lwval_mul(LWVAL *v1, LWVAL *v2); +__lwval_extern__ LWVAL *lwval_div(LWVAL *v1, LWVAL *v2); +__lwval_extern__ LWVAL *lwval_mod(LWVAL *v1, LWVAL *v2); +__lwval_extern__ LWVAL *lwval_neg(LWVAL *v1); + +#undef __lwval_extern__ + +#endif //__lwval_h_seen__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/macro.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,340 @@ +/* +macro.c +Copyright © 2008 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + +Contains stuff associated with macro processing +*/ + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include "lwasm.h" +#include "instab.h" +#include "util.h" + +OPFUNC(pseudo_macro) +{ + macrotab_t *m; + + // if skipping a condition, flag in a macro + if (as -> skipcond) + { + as -> skipmacro = 1; + return; + } + + // actually define a macro + if (as -> inmacro) + { + register_error(as, l, 1, "Attempt to define a macro inside a macro"); + return; + } + + as -> inmacro = 1; + + // don't actually do anything if not pass 1 + if (as -> passnum != 1) + return; + + + if (!l -> sym) + { + register_error(as, l, 1, "Macro definition with no effect - no symbol"); + return; + } + + // search for macro by same name... + for (m = as -> macros; m; m = m -> next) + { + if (!strcmp(m -> name, l -> sym)) + break; + } + if (m) + { + register_error(as, l, 1, "Duplicate macro definition"); + return; + } + + m = lwasm_alloc(sizeof(macrotab_t)); + m -> name = lwasm_strdup(l -> sym); + m -> next = as -> macros; + m -> lines = NULL; + m -> numlines = 0; + as -> macros = m; + + while (**p && !isspace(**p)) + (*p)++; +} + +OPFUNC(pseudo_endm) +{ + if (as -> skipcond) + { + as -> skipmacro = 0; + return; + } + + if (!as -> inmacro) + { + register_error(as, l, 1, "ENDM without MACRO"); + return; + } + + as -> inmacro = 0; + + // a macro definition counts as a context break for local symbols + as -> context = lwasm_next_context(as); +} + +// the current macro will ALWAYS be the first one in the table +int add_macro_line(asmstate_t *as, char *optr) +{ + if (!as -> inmacro) + return 0; + + if (as -> passnum == 2) + return 1; + + as -> macros -> lines = lwasm_realloc(as -> macros -> lines, sizeof(char *) * (as -> macros -> numlines + 1)); + as -> macros -> lines[as -> macros -> numlines] = lwasm_strdup(optr); + as -> macros -> numlines += 1; + return 1; +} + +void macro_add_to_buff(char **buff, int *loc, int *len, char c) +{ + if (*loc == *len) + { + *buff = lwasm_realloc(*buff, *len + 32); + *len += 32; + } + (*buff)[(*loc)++] = c; +} + +// this is just like a regular operation function +/* +macro args are referenced by "\n" where 1 <= n <= 9 +or by "\{n}"; a \ can be included by writing \\ +a comma separates argument but one can be included with "\," +whitespace ends argument list but can be included with "\ " or the like + +In pass 1, actually add the lines to the system, in pass 2, do not +In pass 2, track the number of lines to skip because they already will be +processed by this function - this will be in as -> skiplines + +*/ +int expand_macro(asmstate_t *as, lwasm_line_t *l, char **p, char *opc) +{ + int lc; + lwasm_line_t *cl, *nl; + int oldcontext; + macrotab_t *m; + + char **args = NULL; // macro arguments + int nargs = 0; // number of arguments + + char *p2, *p3; + + int bloc, blen; + char *linebuff; + + for (m = as -> macros; m; m = m -> next) + { + if (!strcmp(opc, m -> name)) + break; + } + // signal no macro expansion + if (!m) + return -1; + + + // save current symbol context for after macro expansion + oldcontext = as -> context; + + cl = l; + + as -> context = lwasm_next_context(as); + + // step 1: parse arguments (pass 1 only) + if (as -> passnum == 1) + { + while (**p && !isspace(**p) && **p != ',') + { + p2 = *p; + while (*p2 && !isspace(*p2) && *p2 != ',') + { + if (*p2 == '\\') + { + if (p2[1]) + p2++; + } + p2++; + } + + // have arg here + args = lwasm_realloc(args, sizeof(char *) * (nargs + 1)); + args[nargs] = lwasm_alloc(p2 - *p + 1); + args[nargs][p2 - *p] = '\0'; + memcpy(args[nargs], *p, p2 - *p); + *p = p2; + + // now collapse out "\" characters + for (p3 = p2 = args[nargs]; *p2; p2++, p3++) + { + if (*p2 == '\\' && p2[1]) + { + p2++; + } + *p3 = *p2; + } + *p3 = '\0'; + + nargs++; + if (**p == ',') + (*p)++; + } + } + + { + int i; + for (i = 0; i < nargs; i++) + { + debug_message(10, "Macro (%s) arg %d: %s", m -> name, i + 1, args[i]); + } + } + + // step 2: iterate over the lines + if (as -> passnum == 2) + { + // pass 2 only - parse the lines and count them + for (lc = 0; lc < m -> numlines; lc++) + { + cl = cl -> next; + as -> skiplines++; + lwasm_parse_line(as, cl); + } + } + else + { + // pass 1 only - construct the lines and parse them + for (lc = 0; lc < m -> numlines; lc++) + { + nl = lwasm_alloc(sizeof(lwasm_line_t)); + nl -> lineno = lc + 1; + nl -> filename = m -> name; + nl -> next = NULL; + nl -> prev = as -> linestail; + nl -> err = NULL; + nl -> fsize = 0; + nl -> sym = NULL; + nl -> bytes = NULL; + nl -> codelen = 0; + nl -> codesize = 0; + nl -> nocodelen = 0; + nl -> addrset = 0; + nl -> symaddr = -1; + nl -> badop = 0; + nl -> relocoff = -1; + if (as -> linestail) + as -> linestail -> next = nl; + as -> linestail = nl; + if (!(as -> lineshead)) + as -> lineshead = nl; + + bloc = blen = 0; + linebuff = NULL; + for (p2 = m -> lines[lc]; *p2; p2++) + { + if (*p2 == '\\' && isdigit(p2[1])) + { + int n; + + p2++; + n = *p2 - '0'; + if (n == 0) + { + for (p3 = m -> name; *p3; p3++) + macro_add_to_buff(&linebuff, &bloc, &blen, *p3); + continue; + } + if (n < 1 || n > nargs) + continue; + for (p3 = args[n - 1]; *p3; p3++) + macro_add_to_buff(&linebuff, &bloc, &blen, *p3); + continue; + } + else if (*p2 == '{') + { + int n = 0, n2; + p2++; + while (*p2 && isdigit(*p2)) + { + n2 = *p2 - '0'; + if (n2 < 0 || n2 > 9) + n2 = 0; + n = n * 10 + n2; + p2++; + } + if (*p2 == '}') + p2++; + + if (n == 0) + { + for (p3 = m -> name; *p3; p3++) + macro_add_to_buff(&linebuff, &bloc, &blen, *p3); + continue; + } + if (n < 1 || n > nargs) + continue; + for (p3 = args[n - 1]; *p3; p3++) + macro_add_to_buff(&linebuff, &bloc, &blen, *p3); + continue; + } + else + { + macro_add_to_buff(&linebuff, &bloc, &blen, *p2); + } + } + + macro_add_to_buff(&linebuff, &bloc, &blen, 0); + + nl -> text = linebuff; + + lwasm_parse_line(as, nl); + if (as -> endseen) + break; + + } + } + + // restore context from before the macro was called + as -> context = oldcontext; + + // clean up + if (args) + { + while (nargs) + { + lwasm_free(args[--nargs]); + } + lwasm_free(args); + } + + // indicate a macro was expanded + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/main.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,199 @@ +/* +main.c +Copyright © 2008 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + + +Implements the program startup code + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <argp.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "lwasm.h" + +// external declarations +extern void lwasm_pass1(asmstate_t *as); +extern void lwasm_pass2(asmstate_t *as); +extern void lwasm_list(asmstate_t *as); +extern void lwasm_output(asmstate_t *as); +extern void pseudo_pragma_real(asmstate_t *as, lwasm_line_t *cl, char **optr, int error); + +// command line option handling +const char *argp_program_version = "LWASM from " PACKAGE_STRING; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + +static error_t parse_opts(int key, char *arg, struct argp_state *state) +{ + asmstate_t *as = state -> input; + char *p; + + switch (key) + { + case 'o': + // output + if (as -> outfile) + { + } + as -> outfile = arg; + break; + + case 'd': + // debug + debug_level++; + break; + + case 'l': + // list + if (arg) + as -> listfile = arg; + else + as -> listfile = "-"; + break; + + case 'b': + // decb output + as -> outformat = OUTPUT_DECB; + break; + + case 'r': + // raw binary output + as -> outformat = OUTPUT_RAW; + break; + + case 0x100: + // proprietary object format + as -> outformat = OUTPUT_OBJ; + break; + + case 'f': + // output format + if (!strcasecmp(arg, "decb")) + as -> outformat = OUTPUT_DECB; + else if (!strcasecmp(arg, "raw")) + as -> outformat = OUTPUT_RAW; + else if (!strcasecmp(arg, "obj")) + as -> outformat = OUTPUT_OBJ; + else + { + fprintf(stderr, "Invalid output format: %s\n", arg); + exit(1); + } + break; + + case 'p': + // pragmas + p = arg; + pseudo_pragma_real(as, NULL, &p, 2); + if (!p) + { + fprintf(stderr, "Invalid pragma string: %s\n", arg); + exit(1); + } + break; + + case ARGP_KEY_END: + // done; sanity check + if (!as -> outfile) + as -> outfile = "a.out"; + break; + + case ARGP_KEY_ARG: + // non-option arg + if (as -> infile) + argp_usage(state); + as -> infile = arg; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp_option options[] = +{ + { "output", 'o', "FILE", 0, + "Output to FILE"}, + { "debug", 'd', 0, 0, + "Set debug mode"}, + { "format", 'f', "TYPE", 0, + "Select output format: decb, raw, obj"}, + { "list", 'l', "FILE", OPTION_ARG_OPTIONAL, + "Generate list [to FILE]"}, + { "decb", 'b', 0, 0, + "Generate DECB .bin format output, equivalent of --format=decb"}, + { "raw", 'r', 0, 0, + "Generate raw binary format output, equivalent of --format=raw"}, + { "obj", 0x100, 0, 0, + "Generate proprietary object file format for later linking, equivalent of --format=obj" }, + { "pragma", 'p', "PRAGMA", 0, + "Set an assembler pragma to any value understood by the \"pragma\" pseudo op"}, + { 0 } +}; + +static struct argp argp = +{ + options, + parse_opts, + "<input file>", + "LWASM, a HD6309 and MC6809 cross-assembler" +}; + +// main function; parse command line, set up assembler state, and run the +// assembler on the first file +int main(int argc, char **argv) +{ + // assembler state + asmstate_t asmstate = { 0 }; + + argp_parse(&argp, argc, argv, 0, 0, &asmstate); + + if (!asmstate.infile) + { + fprintf(stderr, "No input files specified.\n"); + exit(1); + } + + /* pass 1 - collect the symbols and assign addresses where possible */ + /* pass 1 also resolves included files, etc. */ + /* that means files are read exactly once unless included multiple times */ + lwasm_pass1(&asmstate); + + // pass 2: actually generate the code; if any phasing errors appear + // at this stage, we have a bug + lwasm_pass2(&asmstate); + + // now make a pretty listing + lwasm_list(&asmstate); + + // now write the code out to the output file + lwasm_output(&asmstate); + + if (asmstate.errorcount > 0) + exit(1); + + exit(0); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/output.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,419 @@ +/* +output.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + + +Contains the code for actually outputting the assembled code +*/ + +//#include <ctype.h> +#include <errno.h> +#include <stdio.h> +//#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#define __output_c_seen__ +//#include "instab.h" +#include "lwasm.h" +#include "util.h" + +void write_code_raw(asmstate_t *as, FILE *of); +void write_code_decb(asmstate_t *as, FILE *of); +void write_code_rawrel(asmstate_t *as, FILE *of); +void write_code_obj(asmstate_t *as, FILE *of); + +// this prevents warnings about not using the return value of fwrite() +#define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); } while (0) + +void lwasm_output(asmstate_t *as) +{ + FILE *of; + + if (as -> errorcount > 0) + { + fprintf(stderr, "Not doing output due to assembly errors.\n"); + return; + } + + of = fopen(as -> outfile, "wb"); + if (!of) + { + fprintf(stderr, "Cannot open '%s' for output", as -> outfile); + perror(""); + return; + } + + switch (as -> outformat) + { + case OUTPUT_RAW: + write_code_raw(as, of); + break; + + case OUTPUT_DECB: + write_code_decb(as, of); + break; + + case OUTPUT_RAWREL: + write_code_rawrel(as, of); + break; + + case OUTPUT_OBJ: + write_code_obj(as, of); + break; + + default: + fprintf(stderr, "BUG: unrecognized output format when generating output file\n"); + fclose(of); + unlink(as -> outfile); + return; + } + + fclose(of); +} + +/* +rawrel output treats an ORG directive as an offset from the start of the +file. Undefined results will occur if an ORG directive moves the output +pointer backward. This particular implementation uses "fseek" to handle +ORG requests and to skip over RMBs. + +This simple brain damanged method simply does an fseek before outputting +each instruction. +*/ +void write_code_rawrel(asmstate_t *as, FILE *of) +{ + lwasm_line_t *cl; + + for (cl = as -> lineshead; cl; cl = cl -> next) + { + if (cl -> codelen == 0) + continue; + + fseek(of, cl -> codeaddr, SEEK_SET); + writebytes(cl -> bytes, cl -> codelen, 1, of); + } +} + +/* +raw merely writes all the bytes directly to the file as is. ORG is just a +reference for the assembler to handle absolute references. Multiple ORG +statements will produce mostly useless results +*/ +void write_code_raw(asmstate_t *as, FILE *of) +{ + lwasm_line_t *cl; + + for (cl = as -> lineshead; cl; cl = cl -> next) + { + if (cl -> nocodelen) + { + int i; + for (i = 0; i < cl -> nocodelen; i++) + writebytes("\0", 1, 1, of); + continue; + } + writebytes(cl -> bytes, cl -> codelen, 1, of); + } +} + +void write_code_decb(asmstate_t *as, FILE *of) +{ + long preambloc; + lwasm_line_t *cl; + int blocklen = -1; + int nextcalc = -1; + unsigned char outbuf[5]; + + for (cl = as -> lineshead; cl; cl = cl -> next) + { + if (cl -> nocodelen) + continue; + if (cl -> codeaddr != nextcalc && cl -> codelen > 0) + { + // need preamble here + if (blocklen > 0) + { + // update previous preamble if needed + fseek(of, preambloc, SEEK_SET); + outbuf[0] = (blocklen >> 8) & 0xFF; + outbuf[1] = blocklen & 0xFF; + writebytes(outbuf, 2, 1, of); + fseek(of, 0, SEEK_END); + } + blocklen = 0; + nextcalc = cl -> codeaddr; + outbuf[0] = 0x00; + outbuf[1] = 0x00; + outbuf[2] = 0x00; + outbuf[3] = (nextcalc >> 8) & 0xFF; + outbuf[4] = nextcalc & 0xFF; + preambloc = ftell(of) + 1; + writebytes(outbuf, 5, 1, of); + } + nextcalc += cl -> codelen; + writebytes(cl -> bytes, cl -> codelen, 1, of); + blocklen += cl -> codelen; + } + if (blocklen > 0) + { + fseek(of, preambloc, SEEK_SET); + outbuf[0] = (blocklen >> 8) & 0xFF; + outbuf[1] = blocklen & 0xFF; + writebytes(outbuf, 2, 1, of); + fseek(of, 0, SEEK_END); + } + + // now write postamble + outbuf[0] = 0xFF; + outbuf[1] = 0x00; + outbuf[2] = 0x00; + outbuf[3] = (as -> execaddr >> 8) & 0xFF; + outbuf[4] = (as -> execaddr) & 0xFF; + writebytes(outbuf, 5, 1, of); +} + +void write_code_obj_sbadd(sectiontab_t *s, unsigned char b) +{ + if (s -> oblen >= s -> obsize) + { + s -> obytes = lwasm_realloc(s -> obytes, s -> obsize + 128); + s -> obsize += 128; + } + s -> obytes[s -> oblen] = b; + s -> oblen += 1; +} + +void write_code_obj(asmstate_t *as, FILE *of) +{ + lwasm_line_t *l; + sectiontab_t *s; + lwasm_symbol_ent_t *se; + export_list_t *ex; + section_reloc_list_t *re; + lwasm_expr_stack_node_t *sn; + + int i; + unsigned char buf[16]; + + // output the magic number and file header + // the 8 is NOT an error + writebytes("LWOBJ16", 8, 1, of); + + // run through the entire system and build the byte streams for each + // section; at the same time, generate a list of "local" symbols to + // output for each section + // NOTE: for "local" symbols, we will append \x01 and the ascii string + // of the context identifier (so sym in context 1 would be "sym\x011" + // we can do this because the linker can handle symbols with any + // character other than NUL. + // also we will generate a list of incomplete references for each + // section along with the actual definition that will be output + + // once all this information is generated, we will output each section + // to the file + + // NOTE: we build everything in memory then output it because the + // assembler accepts multiple instances of the same section but the + // linker expects only one instance of each section in the object file + // so we need to collect all the various pieces of a section together + // (also, the assembler treated multiple instances of the same section + // as continuations of previous sections so we would need to collect + // them together anyway. + + for (l = as -> lineshead; l; l = l -> next) + { + if (l -> sect) + { + // we're in a section - need to output some bytes + for (i = 0; i < l -> codelen; i++) + write_code_obj_sbadd(l -> sect, l -> bytes[i]); + for (i = 0; i < l -> nocodelen; i++) + write_code_obj_sbadd(l -> sect, 0); + + // do we have a "relocation"? If so, add a reference to the + // relocation table + if (l -> relocoff >= 0) + { + // build the relocation reference for the linker + re = lwasm_alloc(sizeof(section_reloc_list_t)); + re -> next = l -> sect -> rl; + l -> sect -> rl = re; + + re -> offset = l -> codeaddr + l -> relocoff; + re -> expr = l -> exprs[0]; + re -> context = l -> context; + } + } + } + + // run through the sections + for (s = as -> sections; s; s = s -> next) + { + // write the name + writebytes(s -> name, strlen(s -> name) + 1, 1, of); + + // write the flags + if (s -> flags & SECTION_BSS) + writebytes("\x01", 1, 1, of); + + // indicate end of flags - the "" is NOT an error + writebytes("", 1, 1, of); + + + // now the local symbols + for (se = as -> symhead; se; se = se -> next) + { + // ignore symbols not in this section + if (se -> sect != s) + continue; + + if (se -> flags & SYMBOL_SET) + continue; + + if (se -> flags & SYMBOL_EXTERN) + continue; + + writebytes(se -> sym, strlen(se -> sym), 1, of); + if (se -> context >= 0) + { + writebytes("\x01", 1, 1, of); + sprintf(buf, "%d", se -> context); + writebytes(buf, strlen(buf), 1, of); + } + // the "" is NOT an error + writebytes("", 1, 1, of); + + // write the address + buf[0] = (se -> value >> 8) & 0xff; + buf[1] = se -> value & 0xff; + writebytes(buf, 2, 1, of); + } + // flag end of local symbol table - "" is NOT an error + writebytes("", 1, 1, of); + + // now the exports + for (ex = s -> exports; ex; ex = ex -> next) + { + writebytes(ex -> sym, strlen(ex -> sym) + 1, 1, of); + buf[0] = (ex -> offset >> 8) & 0xff; + buf[1] = ex -> offset & 0xff; + writebytes(buf, 2, 1, of); + } + + // flag end of exported symbols - "" is NOT an error + writebytes("", 1, 1, of); + + // now output the "incomplete references" + // this being the most complex bit + for (re = s -> rl; re; re = re -> next) + { + if (re -> expr == NULL) + { + // this is an error but we'll simply ignore it + // and not output this expression + continue; + } + + // work through each term in the expression and output + // the proper equivalent to the object file + for (sn = re -> expr -> head; sn; sn = sn -> next) + { + switch (sn -> term -> term_type) + { + case LWASM_TERM_OPER: + buf[0] = 0x04; + buf[1] = sn -> term -> value; + writebytes(buf, 2, 1, of); + break; + + case LWASM_TERM_INT: + buf[0] = 0x01; + buf[1] = (sn -> term -> value >> 8) & 0xff; + buf[2] = sn -> term -> value & 0xff; + writebytes(buf, 3, 1, of); + break; + + case LWASM_TERM_SECBASE: + writebytes("\x05", 1, 1, of); + break; + + case LWASM_TERM_SYM: + // now for the ugly part - resolve a symbol reference + // and determine whether it's internal, external, or + // a section base + se = lwasm_find_symbol(as, sn -> term -> symbol, re -> context); + if (!se) + se = lwasm_find_symbol(as, sn -> term -> symbol, -1); + if (!se || se -> flags & SYMBOL_EXTERN) + { + // not found - assume external reference + // found but flagged external - handle it + writebytes("\x02", 1, 1, of); + writebytes(se -> sym, strlen(se -> sym) + 1, 1, of); + break; + } + // a local symbol reference here + writebytes("\x03", 1, 1, of); + writebytes(se -> sym, strlen(se -> sym), 1, of); + if (se -> context >= 0) + { + writebytes("\x01", 1, 1, of); + sprintf(buf, "%d", se -> context); + writebytes(buf, strlen(buf), 1, of); + } + writebytes("", 1, 1, of); + break; + + default: + // unrecognized term type - replace with integer 0 + buf[0] = 0x01; + buf[1] = 0x00; + buf[2] = 0x00; + writebytes(buf, 3, 1, of); + break; + } + } + + // flag end of expressions + writebytes("", 1, 1, of); + + // write the offset + buf[0] = (re -> offset >> 8) & 0xff; + buf[1] = re -> offset & 0xff; + writebytes(buf, 2, 1, of); + } + // flag end of incomplete references list + writebytes("", 1, 1, of); + + // now blast out the code + + // length + buf[0] = s -> oblen >> 8 & 0xff; + buf[1] = s -> oblen & 0xff; + writebytes(buf, 2, 1, of); + + if (!(s -> flags & SECTION_BSS)) + { + writebytes(s -> obytes, s -> oblen, 1, of); + } + } + + // flag no more sections + // the "" is NOT an error + writebytes("", 1, 1, of); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/parse.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,196 @@ +/* +parse.c +Copyright © 2008 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +Contains the general parser +*/ + +#define __parse_c_seen__ + +#include <ctype.h> +#include <string.h> + +#include "lwasm.h" +#include "instab.h" +#include "util.h" + +// parse a line and despatch to the appropriate handlers for opcodes +int lwasm_parse_line(asmstate_t *as, lwasm_line_t *l) +{ + char *p, *p2; + char *opc; + int opnum; + char *sym = NULL; + + // if this was a bad op first pass (or otherwise a no-process line) + // ignore it + if (l -> badop) + return; + + p = l -> text; + l -> sect = as -> csect; + + // blank lines are a no brainer + if (!*p) + { + as -> context = lwasm_next_context(as); + return 0; + } + + // for output generation later but only on pass 1 + // also used by some pseudo ops on pass 2 + if (as -> passnum == 1) + l -> codeaddr = as -> addr; + + // if it's a comment, return (this doesn't cause a context change) + if (*p == '*' || *p == ';') + return; + + // if we start with a non-space character, it's a symbol + if (!isspace(*p)) + { + // we have a symbol specified here + // parse it out and record it for later use + for (p2 = p; *p2 && !isspace(*p2); p2++) + /* do nothing */ ; + + sym = lwasm_alloc((p2 - p) + 1); + sym[p2 - p] = '\0'; + memcpy(sym, p, p2 - p); + + p = p2; + } + l -> sym = sym; + + // now skip any whitespace to find the opcode + while (*p && isspace(*p)) + p++; + + // is the line blank? + if (!*p && !sym) + { + // nothing but white space *is* a context break + as -> context = lwasm_next_context(as); + return; + } + + // parse the opcode + for (p2 = p; *p2 && !isspace(*p2); p2++) + /* do nothing */ ; + + opc = lwasm_alloc((p2 - p) + 1); + memcpy(opc, p, p2 - p); + opc[p2 - p] = '\0'; + + debug_message(2, "Found operation code: '%s'", opc); + + // skip intervening whitespace if present + while (*p2 && isspace(*p2)) + p2++; + + // look up instruction in insn table + for (opnum = 0; instab[opnum].opcode; opnum++) + { + if (!strcasecmp(instab[opnum].opcode, opc)) + break; + } + + // if we found no operation, check if we had a comment + // the reason this check is here is to allow for "private" + // operation codes like "*pragma" which will be ignored by + // other assemblers + // also skip empty ops + if (!(instab[opnum].opcode)) + { + if (*opc == '*' || *opc == ';' || !*opc) + goto done_line; + } + + // now we have the opcode and the symbol, we can decide if we're + // actually going to do anything with this line + + // we will NOT call the function if any of the following are true: + + // - we are skipping a condition and the operation code is not a conditional + // - we are defining a macro and the operation code is not ENDM + + // we will call the function in any other circumstance + + // first condition above + if (as -> inmacro && instab[opnum].endm == 0) + { + add_macro_line(as, l -> text); + goto done_line; + } + + // second condition above + if (as -> skipcond && instab[opnum].iscond == 0) + goto done_line; + + // we've registered the symbol as needed + // now we need to check for a macro call IFF we don't collide with + // an operation code; otherwise, call the operation function + if (instab[opnum].opcode) + { + if (instab[opnum].fn) + { + (instab[opnum].fn)(as, l, &p2, opnum); + } + else + { + // carp about unimplemented operation + register_error(as, l, 1, "Unimplemented operation code: %s", opc); + } + } + else + { + if (expand_macro(as, l, &p2, opc) == 0) + goto done_line; + + // carp about an unknown operation code and note that fact for + // pass 2 in case a macro appears later with the same name! + register_error(as, l, 1, "Uknown operation code: %s", opc); + l -> badop = 1; + } + +done_line: + if (!(as -> skipcond || as -> inmacro)) + { + // register symbol if the operation didn't + if (sym && instab[opnum].setsym == 0) + { + if (as -> passnum == 1) + { + debug_message(1, "Registering symbol '%s' at %04X", sym, l -> codeaddr); + if (lwasm_register_symbol(as, l, sym, l -> codeaddr, SYMBOL_NORM) < 0) + l -> sym = NULL; + else + l -> addrset = 1; + } + } + } + + l -> sect = as -> csect; + l -> context = as -> context; + + lwasm_free(opc); + if (sym) + lwasm_free(sym); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/pass1.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,178 @@ +/* +pass1.c +Copyright © 2008 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + + +Handles first pass of assembly + +First pass involves the following: + +1. read all lines from the main source file, following all "include" + directives as appropriate +2. each operand is evaluated for syntax and futher for value if there are + multiple addressing sizes available; any undefined or not fully resolved + value will default to the largest addressing size available (16 bit) +3. addresses are assigned to every symbol defined in the assembly +4. macros are defined and expanded at this pass + +* note: the lines are re-evaluated on the second pass + +All source lines are read into memory with a record of the file name and +line number within the files. + +Lines are one of the following formats: + +<symbol> <opcode> <operand> <comment> +<symbol> <opcode> <comment> + <opcode> <operand> <comment> + <opcode> <comment> + +A "*" or ";" appearing anywhere on the line that is not otherwise interpreted +as part of an operation code or operand introduces a comment. + +Certain lwasm specific operations are prefixed with a "*" to aid in source +code portability (like *pragma). +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "lwasm.h" +#include "util.h" + + +extern int lwasm_parse_line(asmstate_t *as, lwasm_line_t *l); + +// we can't use standard line inputting functions here because we have to +// handle non-standard line terminations (CR, LF, CRLF, or LFCR) +int lwasm_read_file(asmstate_t *as, const char *filename) +{ + FILE *f; + int c, c2; + lwasm_line_t *nl; + int lineno = 1; + char *fnref; + + // ought to be long enough...we truncate longer lines + char linebuff[2049]; + int lbloc = 0; + int eol = 0; + + // add filename to list + as -> filelist = lwasm_realloc(as -> filelist, sizeof(char *) * (as -> filelistlen + 1)); + fnref = as -> filelist[as -> filelistlen] = lwasm_strdup(filename); + as -> filelistlen += 1; + + f = fopen(filename, "rb"); + if (!f) + return -1; + + for (;;) + { + c = fgetc(f); + if (c == EOF) + { + linebuff[lbloc] = '\0'; + eol = 1; + } + else if (c == '\r') + { + linebuff[lbloc] = '\0'; + eol = 1; + // check for '\n': + c2 = fgetc(f); + if (c2 == EOF) + c = EOF; + else if (c2 != '\n') + ungetc(c2, f); + } + else if (c == '\n') + { + linebuff[lbloc] = '\0'; + eol = 1; + // check for '\r': + c2 = fgetc(f); + if (c2 == EOF) + c = EOF; + else if (c2 != '\r') + ungetc(c2, f); + } + else + { + // silently ignore characters past 2K on a line... FIXME + if (lbloc < 2048) + linebuff[lbloc++] = c; + } + if (eol) + { + eol = 0; + lbloc = 0; + nl = lwasm_alloc(sizeof(lwasm_line_t)); + nl -> text = lwasm_strdup(linebuff); + nl -> lineno = lineno++; + nl -> filename = fnref; + nl -> next = NULL; + nl -> prev = as -> linestail; + nl -> err = NULL; + nl -> fsize = 0; + nl -> sym = NULL; + nl -> bytes = NULL; + nl -> codelen = 0; + nl -> codesize = 0; + nl -> nocodelen = 0; + nl -> addrset = 0; + nl -> symaddr = -1; + nl -> badop = 0; + nl -> relocoff = -1; + if (as -> linestail) + as -> linestail -> next = nl; + as -> linestail = nl; + if (!(as -> lineshead)) + as -> lineshead = nl; + lwasm_parse_line(as, nl); + if (as -> endseen) + break; + } + if (c == EOF) + break; + } + + fclose(f); + return 0; +} + +void lwasm_pass1(asmstate_t *as) +{ + as -> passnum = 1; + as -> addr = 0; + as -> nextcontext = 1; + + debug_message(1, "Entering pass 1"); + if (lwasm_read_file(as, as -> infile) < 0) + { + fprintf(stderr, "Error reading input file '%s'", as -> infile); + perror(""); + exit(1); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/pass2.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,61 @@ +/* +pass2.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + + +Handles second pass of assembly + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "lwasm.h" + +void lwasm_pass2(asmstate_t *as) +{ + lwasm_line_t *l; + sectiontab_t *st; + + debug_message(1, "Entering pass 2"); + as -> passnum = 2; + as -> addr = 0; + as -> context = 0; + as -> endseen = 0; + as -> skipcond = 0; + as -> skipcount = 0; + as -> skipmacro = 0; + as -> inmacro = 0; + as -> nextcontext = 1; + as -> skiplines = 0; + as -> dpval = 0; + + for (st = as -> sections; st; st = st -> next) + st -> offset = 0; + as -> csect = NULL; + + // iterate over all the lines and re-parse them + for (l = as -> lineshead; l && !(as -> endseen); l = l -> next) + { + if (as -> skiplines) + as -> skiplines--; + else + lwasm_parse_line(as, l); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/pragma.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,123 @@ +/* +pragma.c +Copyright © 2008 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + + +This file contains stuff associated with lwasm specific strangeness +*/ + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include "lwasm.h" +#include "instab.h" + +/* +A pragma is a means of controlling code generation. + +The pseudo op "*pragma" which will be treated as a comment by an assembler +that doesn't recognize it and thus will not cause assembly errors. This is +the preferred way of flagging a pragma if it will not cause incorrect +execution of the program. + +The pseudo op "pragma" which will cause an error on an assembler that does +not understand it. + +In the case of "*pragma", unrecognized pragmas MUST be silently ignored. In +the case of "pragma", unrecognized pragmas should raise an error. + +LWASM understands the following pragmas: + +index0tonone +noindex0tonone + +When set (index0tonone), an expression that evaluates to 0, other than a +bare constant, in a <offset>,r operand will cause the code for ",r" to be +emitted rather than "0,r". If not set (noindex0tonone), the "0,r" output +will be emitted. The default is to perform the optimization. + +This particular optimization will save a cycle for a direct operation. For +an indirect operation, however, it will save several cycles and a program byte +which may be very useful. +*/ + +void pseudo_pragma_real(asmstate_t *as, lwasm_line_t *cl, char **optr, int error) +{ + char pragma[128]; + int c = 0; + + while (isspace(**optr)) + (*optr)++; + + while (c < 127 && **optr && !isspace(**optr)) + { + pragma[c++] = **optr; + (*optr)++; + } + + if (c == 0 || (**optr && !isspace(**optr))) + { + if (error) + { + register_error(as, cl, 1, "Unrecognized pragma"); + } + if (error == 2) + { + *optr = NULL; + } + return; + } + pragma[c] = 0; + if (!strcasecmp(pragma, "noindex0tonone")) + { + as -> pragmas |= PRAGMA_NOINDEX0TONONE; + } + else if (!strcasecmp(pragma, "index0tonone")) + { + as -> pragmas &= ~PRAGMA_NOINDEX0TONONE; + } + else if (!strcasecmp(pragma, "undefextern")) + { + as -> pragmas |= PRAGMA_UNDEFEXTERN; + } + else if (!strcasecmp(pragma, "noundefextern")) + { + as -> pragmas &= ~PRAGMA_UNDEFEXTERN; + } + else + { + if (error) + { + register_error(as, cl, 1, "Unrecognized pragma"); + if (error == 2) + { + *optr = NULL; + } + } + } +} + +OPFUNC(pseudo_pragma) +{ + pseudo_pragma_real(as, l, p, 1); +} + +OPFUNC(pseudo_starpragma) +{ + pseudo_pragma_real(as, l, p, 0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/pseudo.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,967 @@ +/* +pseudo.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + + +This file implements the various pseudo operations. +*/ + +#include <stdlib.h> +#include <string.h> +#include "lwasm.h" +#include "instab.h" +#include "expr.h" +#include "util.h" + +extern int lwasm_read_file(asmstate_t *as, const char *filename); + +OPFUNC(pseudo_org) +{ + int v, r; + + if (as -> csect) + { + register_error(as, l, 1, "ORG not allowed within sections"); + return; + } + + if (as -> passnum != 1) + { + // org is not needed to be processed on pass 2 + // this will prevent phasing errors for forward references that + // resolve on the second pass + // we saved the org address in l -> codeaddr on pass 1 + as -> addr = l -> codeaddr; + return; + } + + if (l -> sym) + { + register_error(as, l, 1, "No symbol allowed with ORG"); + } + + r = lwasm_expr_result2(as, l, p, EXPR_PASS1CONST, &v, 0); + if (r != 0) + return; + l -> codeaddr = v; + l -> addrset = 1; + as -> addr = v; +} + +/* +The operand for include is a string optionally enclosed in " +*/ +OPFUNC(pseudo_include) +{ + int v1; + char *fn; + + // only include files on pass 1 + // but make sure local include context is right + // for the next line... + if (as -> passnum != 1) + { + as -> context = lwasm_next_context(as); + return; + } + + while (**p && isspace(**p)) + (*p)++; + + if (!**p) + { + register_error(as, l, 1, "Bad file name"); + return; + } + + if (**p == '"') + { + // search for ending " + (*p)++; + for (v1 = 0; *((*p)+v1) && *((*p)+v1) != '"'; v1++) + /* do nothing */ ; + if (*((*p)+v1) != '"') + { + register_error(as, l, 1, "Bad file name"); + return; + } + } + else + { + // search for a space type character + for (v1 = 0; *((*p)+v1) && !isspace(*((*p)+v1)); v1++) + ; + } + + fn = lwasm_alloc(v1 + 1); + memcpy(fn, *p, v1); + fn[v1] = '\0'; + + // end local label context on include + as -> context = lwasm_next_context(as); + if (lwasm_read_file(as, fn) < 0) + { + register_error(as, l, 1, "File include error (%s)", fn); + } + lwasm_free(fn); +} + +OPFUNC(pseudo_rmb) +{ + int r, v; + + if (as -> passnum == 2) + { + as -> addr += l -> nocodelen; + return; + } + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, -1); + if (r != 0) + return; + l -> nocodelen = v; + as -> addr += v; +} + +OPFUNC(pseudo_rmd) +{ + int r, v; + + if (as -> passnum == 2) + { + as -> addr += l -> nocodelen; + return; + } + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r != 0) + return; + v *= 2; + l -> nocodelen = v; + as -> addr += v; +} + +OPFUNC(pseudo_rmq) +{ + int r, v; + + if (as -> passnum == 2) + { + as -> addr += l -> nocodelen; + return; + } + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r != 0) + return; + v *= 4; + l -> nocodelen = v; + as -> addr += v; +} + +OPFUNC(pseudo_zmb) +{ + int r, v; + + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r != 0) + return; + while (v--) + lwasm_emit(as, l, 0); +} + +OPFUNC(pseudo_zmd) +{ + int r, v; + + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r != 0) + return; + v *= 2; + while (v--) + lwasm_emit(as, l, 0); +} + +OPFUNC(pseudo_zmq) +{ + int r, v; + + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r != 0) + return; + v *= 4; + while (v--) + lwasm_emit(as, l, 0); +} + +OPFUNC(pseudo_end) +{ + int r, v; + lwasm_expr_stack_t *s; + + + as -> endseen = 1; + + // address only matters for DECB output + if (as -> outformat != OUTPUT_DECB) + return; + + r = lwasm_expr_result2(as, l, p, 0, &v, 0); + if (r != 0) + { + register_error(as, l, 2, "Bad operand"); + } + + v = v & 0xffff; + if (as -> passnum == 2) + { + as -> execaddr = v; + l -> symaddr = v; + l -> addrset = 2; + } +} + + +OPFUNC(pseudo_align) +{ + int cn; + int r, v; + + if (as -> passnum == 2) + { + while (as -> addr < l -> symaddr) + lwasm_emit(as, l, 0); + return; + } + + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r != 0) + { + l -> symaddr = as -> addr; + return; + } + + if (v < 1) + { + register_error(as, l, 1, "Illegal alignment %d", v); + return; + } + + cn = l -> codeaddr % v; + if (cn) + cn = v - cn; + + while (cn--) + { + lwasm_emit(as, l, 0); + } + l -> symaddr = as -> addr; +} + +OPFUNC(pseudo_equ) +{ + int r, v; + + if (l -> sym == NULL) + { + register_error(as, l, 1, "No symbol specified"); + return; + } + + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r < 0) + v = 0; + + l -> symaddr = v & 0xFFFF; + l -> addrset = 2; + + // note: we need to do this because the symbol might have resolved + // to a constant! + lwasm_register_symbol(as, l, l -> sym, v, (r > 0 ? SYMBOL_COMPLEX: SYMBOL_NORM) | SYMBOL_FORCE); +} + +OPFUNC(pseudo_set) +{ + int r, v; + + // set MUST run on both passes as the symbol value changes! + + if (l -> sym == NULL) + { + register_error(as, l, 1, "No symbol specified"); + return; + } + + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r < 0) + v = 0; + + l -> symaddr = v & 0xFFFF; + l -> addrset = 2; + + lwasm_register_symbol(as, l, l -> sym, v, (r > 0 ? SYMBOL_COMPLEX: SYMBOL_NORM) | SYMBOL_SET); +} + +OPFUNC(pseudo_setdp) +{ + int r, v; + + if (as -> outformat == OUTPUT_OBJ) + { + register_error(as, l, 1, "SETDP not permitted with OBJ target"); + return; + } + + // setdp is needed on both passes; must resolve to a constant on pass 1 + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); + if (r != 0) + return; + + if (v < -127 || v > 255) + { + register_error(as, l, 1, "Byte overflow"); + return; + } + + l -> symaddr = v & 0xFF; + l -> addrset = 2; + + as -> dpval = v & 0xFF; +} + +OPFUNC(pseudo_fcc) +{ + int delim = 0; + + delim = **p; + if (!delim) + { + register_error(as, l, 1, "Bad operand"); + return; + } + *p += 1; + while (**p && **p != delim) + { + lwasm_emit(as, l, **p); + (*p)++; + } + if (**p) + (*p)++; +} + + +OPFUNC(pseudo_fcs) +{ + int delim = 0; + + delim = **p; + if (!delim) + { + register_error(as, l, 1, "Bad operand"); + return; + } + *p += 1; + while (**p && **p != delim) + { + if (!*((*p) + 1) || *((*p) + 1) == delim) + lwasm_emit(as, l, **p | 0x80); + else + lwasm_emit(as, l, **p); + (*p)++; + } + if (**p) + (*p)++; +} + +OPFUNC(pseudo_fcn) +{ + int delim = 0; + + delim = **p; + if (!delim) + { + register_error(as, l, 1, "Bad operand"); + return; + } + *p += 1; + while (**p && **p != delim) + { + lwasm_emit(as, l, **p); + (*p)++; + } + if (**p) + (*p)++; + lwasm_emit(as, l, 0); +} + +// FIXME: handle external, etc., references in a useful manner +OPFUNC(pseudo_fcb) +{ + int r, v; + +fcb_again: + r = lwasm_expr_result2(as, l, p, 0, &v, -1); + if (r < 0) + return; + + if (r > 0) + { + register_error(as, l, 2, "Illegal external or inter-segment reference"); + v = 0; + } + + if (v < -127 || v > 255) + { + register_error(as, l, 1, "Byte overflow"); + } + + lwasm_emit(as, l, v); + if (**p == ',') + { + (*p)++; + goto fcb_again; + } +} + +// FIXME: handle external references in an intelligent way +OPFUNC(pseudo_fdb) +{ + int r, v; + int extseen = 0; + char *p1; + +fdb_again: + p1 = *p; + r = lwasm_expr_result2(as, l, p, 0, &v, -1); + if (r < 0) + return; + + if (r > 0 && extseen == 1) + { + register_error(as, l, 2, "Illegal external or inter-segment reference (only 1 per FDB line)"); + v = 0; + } + else if (r > 0) + { + l -> relocoff = as -> addr - l -> codeaddr; + *p = p1; + r = lwasm_expr_result2(as, l, p, 0, &v, 0); + } + + lwasm_emit(as, l, v >> 8); + lwasm_emit(as, l, v & 0xff); + if (**p == ',') + { + (*p)++; + goto fdb_again; + } +} + +// FIXME: handle external references in a sensible way +OPFUNC(pseudo_fqb) +{ + int r, v; + +fqb_again: + r = lwasm_expr_result2(as, l, p, 0, &v, -1); + if (r < 0) + return; + + if (r > 0) + { + register_error(as, l, 2, "Illegal external or inter-segment reference"); + v = 0; + } + + lwasm_emit(as, l, v >> 24); + lwasm_emit(as, l, v >> 16); + lwasm_emit(as, l, v >> 8); + lwasm_emit(as, l, v & 0xff); + if (**p == ',') + { + (*p)++; + goto fqb_again; + } +} + +// don't need to do anything if we are executing one of these +OPFUNC(pseudo_endc) +{ + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount -= 1; + if (as -> skipcount <= 0) + { + as -> skipcond = 0; + } + } + return; +} + +// if "else" executes, we must be going into an "ignore" state +OPFUNC(pseudo_else) +{ + if (as -> skipmacro) + return; + + if (as -> skipcond) + { + if (as -> skipcount == 1) + { + as -> skipcount = 0; + as -> skipcond = 0; + } + return; + } + + as -> skipcond = 1; + as -> skipcount = 1; +} + +OPFUNC(pseudo_ifne) +{ + int v1; + int rval; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + return; + } + + rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); + if (rval != 0) + return; + if (!v1) + { + as -> skipcond = 1; + as -> skipcount = 1; + } +} + +OPFUNC(pseudo_ifdef) +{ + lwasm_symbol_ent_t *se; + char *sym; + char *p2; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + return; + } + + if (as -> passnum != 1) + { + if (!(l -> fsize)) + { + as -> skipcond = 1; + as -> skipcount = 1; + } + return; + } + + if (!**p) + { + register_error(as, l, 1, "Need symbol name"); + return; + } + + for (p2 = *p; *p2 && !isspace(*p2); p2++) + /* do nothing */ ; + + sym = lwasm_alloc(p2 - *p + 1); + memcpy(sym, *p, p2 - *p); + sym[p2 - *p] = '\0'; + + *p = p2; + + se = lwasm_find_symbol(as, sym, l -> context); + if (!se) + se = lwasm_find_symbol(as, sym, -1); + + lwasm_free(sym); + + if (!se) + { + as -> skipcond = 1; + as -> skipcount = 1; + l -> fsize = 0; + } + else + { + l -> fsize = 1; + } +} + +OPFUNC(pseudo_ifndef) +{ + lwasm_symbol_ent_t *se; + char *sym; + char *p2; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + return; + } + + if (as -> passnum != 1) + { + if (l -> fsize) + { + as -> skipcond = 1; + as -> skipcount = 1; + } + return; + } + + if (!**p) + { + register_error(as, l, 1, "Need symbol name"); + return; + } + + for (p2 = *p; *p2 && !isspace(*p2); p2++) + /* do nothing */ ; + + sym = lwasm_alloc(p2 - *p + 1); + memcpy(sym, *p, p2 - *p); + sym[p2 - *p] = '\0'; + + *p = p2; + + se = lwasm_find_symbol(as, sym, l -> context); + if (!se) + se = lwasm_find_symbol(as, sym, -1); + + lwasm_free(sym); + + if (se) + { + as -> skipcond = 1; + as -> skipcount = 1; + l -> fsize = 0; + } + else + { + l -> fsize = 1; + } +} + +OPFUNC(pseudo_ifeq) +{ + int v1; + int rval; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + return; + } + + rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); + if (rval != 0) + return; + if (v1) + { + as -> skipcond = 1; + as -> skipcount = 1; + } +} + +OPFUNC(pseudo_iflt) +{ + int v1; + int rval; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + return; + } + + rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); + if (rval != 0) + return; + if (v1 >= 0) + { + as -> skipcond = 1; + as -> skipcount = 1; + } +} + +OPFUNC(pseudo_ifle) +{ + int v1; + int rval; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + return; + } + + rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); + if (rval != 0) + return; + if (v1 > 0) + { + as -> skipcond = 1; + as -> skipcount = 1; + } +} + +OPFUNC(pseudo_ifgt) +{ + int v1; + int rval; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + return; + } + + rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); + if (rval != 0) + return; + if (v1 <= 0) + { + as -> skipcond = 1; + as -> skipcount = 1; + } +} + +OPFUNC(pseudo_ifge) +{ + int v1; + int rval; + + if (as -> skipcond && !(as -> skipmacro)) + { + as -> skipcount++; + return; + } + + rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); + if (rval != 0) + return; + if (v1 < 0) + { + as -> skipcond = 1; + as -> skipcount = 1; + } +} + +OPFUNC(pseudo_error) +{ + register_error(as, l, 1, "User error: %s", *p); +} + + +OPFUNC(pseudo_section) +{ + sectiontab_t *s; + char *p2; + char *sn; + char *opts; + + + if (as -> outformat != OUTPUT_OBJ) + { + register_error(as, l, 1, "Sections only supported for obj target"); + return; + } + + if (as -> csect) + { + as -> csect -> offset = as -> addr; + as -> csect = NULL; + } + + if (!**p) + { + register_error(as, l, 1, "Need section name"); + return; + } + + for (p2 = *p; *p2 && !isspace(*p2); p2++) + /* do nothing */ ; + + sn = lwasm_alloc(p2 - *p + 1); + memcpy(sn, *p, p2 - *p); + sn[p2 - *p] = '\0'; + + *p = p2; + + opts = strchr(sn, ','); + if (opts) + { + *opts++ = '\0'; + } + + // have we seen the section name already? + for (s = as -> sections; s; s = s -> next) + { + if (!strcmp(s -> name, sn)) + break; + } + + if (s && as -> passnum == 1) + { + lwasm_free(sn); + if (opts) + { + register_error(as, l, 1, "Section options can only be specified the first time"); + return; + } + } + else if (!s) + { + s = lwasm_alloc(sizeof(sectiontab_t)); + s -> name = sn; + s -> offset = 0; + s -> flags = 0; + s -> obytes = NULL; + s -> oblen = 0; + s -> obsize = 0; + s -> rl = NULL; + s -> exports = NULL; + // parse options; only one "bss" + if (opts && as -> passnum == 1) + { + if (!strcasecmp(opts, "bss")) + { + s -> flags = SECTION_BSS; + } + else + { + register_error(as, l, 1, "Unrecognized section option '%s'", opts); + lwasm_free(s -> name); + lwasm_free(s); + return; + } + } + + s -> next = as -> sections; + as -> sections = s; + } + as -> addr = s -> offset; + as -> csect = s; + as -> context = lwasm_next_context(as); +} + +OPFUNC(pseudo_endsection) +{ + if (as -> outformat != OUTPUT_OBJ) + { + register_error(as, l, 1, "Sections only supported for obj target"); + return; + } + + if (!(as -> csect)) + { + register_error(as, l, 1, "ENDSECTION when not in a section"); + return; + } + + as -> csect -> offset = as -> addr; + as -> addr = 0; + as -> csect = 0; + as -> context = lwasm_next_context(as); +} + +OPFUNC(pseudo_extern) +{ + if (as -> passnum != 1) + return; + + if (as -> outformat != OUTPUT_OBJ) + { + register_error(as, l, 1, "External references only supported for obj target"); + return; + } + + if (as -> csect) + { + register_error(as, l, 1, "Cannot declare external symbols within a section"); + return; + } + + lwasm_register_symbol(as, l, l -> sym, 0, SYMBOL_EXTERN); +} + +OPFUNC(pseudo_export) +{ + lwasm_symbol_ent_t *se; + export_list_t *ex; + + if (as -> outformat != OUTPUT_OBJ) + { + register_error(as, l, 1, "Symbol exports only supported for obj target"); + return; + } + + if (as -> passnum == 1) + return; + + // the symbol better be defined at this point (pass 2) + // local symbols cannot be exported nor can "global" symbols + se = lwasm_find_symbol(as, l -> sym, -1); + if (!se) + { + register_error(as, l, 2, "Exported symbols must be fully defined within a section"); + return; + } + if (se -> sect == NULL) + { + register_error(as, l, 2, "Only non-local symbols within a section can be exported"); + return; + } + + if (se -> flags & SYMBOL_SET) + { + register_error(as, l, 2, "You cannot export symbols defined with SET"); + return; + } + + // if the symbol is not already a simple value, re-evaluate it + // and see if it becomes simple + + + if (se -> flags & SYMBOL_COMPLEX) + { + register_error(as, l, 2, "Exported symbols must be fully resolved on pass 2"); + return; + } + + // search for existing export + for (ex = se -> sect -> exports; ex; ex = ex -> next) + if (!strcmp(l -> sym, ex -> sym)) + break; + if (ex) + { + register_error(as, l, 2, "Symbol %s already exported", l -> sym); + return; + } + + // add an external reference + ex = lwasm_alloc(sizeof(export_list_t)); + ex -> next = se -> sect -> exports; + se -> sect -> exports = ex; + ex -> offset = se -> value; + ex -> sym = lwasm_strdup(se -> sym); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/symbol.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,249 @@ +/* +symbol.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +for handling the symbol table +*/ + +#define __symbol_c_seen__ + +#include <string.h> + +#include "lwasm.h" +#include "util.h" +#include "expr.h" + +/* +Note that this function may accept symbols that the expression evaluator doesn't +recognize because the expression evaluator must avoid all ambiguity in order +to achieve predictable results. The checks here are simply a fuzz check. +*/ + +/* +NOTE: complex symbols always take their value from slot 0 on the expression placeholders +for a line! +*/ +int lwasm_register_symbol(asmstate_t *as, lwasm_line_t *l, char *sym, int val, int flags) +{ + lwasm_symbol_ent_t *se, *se2; + char *p; + + int scontext = -1; + + // if the symbol is constant, fall back to simple registration! + if (flags & SYMBOL_COMPLEX) + { + if (l -> exprs[0] == NULL) + { + val = l -> exprvals[0]; + flags &= ~SYMBOL_COMPLEX; + } + } + + // first check if the symbol is valid + // the following characters are allowed in a symbol: + // [a-zA-Z0-9._$?@] and any byte value larger than 0x7F + // although symbols should be restricted to the 7 bit range + // symbols must start with [a-zA-Z._] + if (!strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._@?", *sym)) + { + register_error(as, l, 1, "Bad symbol: %s", sym); + return -1; + } + + if (*sym == '@' && isdigit(sym[1])) + { + register_error(as, l, 1, "Bad symbol: %s", sym); + return -1; + } + + for (p = sym; *p; p++) + { + if (!strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._$?@0123456789", *sym)) + { + register_error(as, l, 1, "Bad symbol: %s", sym); + return -1; + } + // flag local symbols while we're at it... + if (*p == '?' || *p == '@') + scontext = as -> context; + } + + debug_message(3, "lwasm_register_symbol(): registering '%s' (%d) at %04X; flags=%d", sym, scontext, val, flags); + + // now look it for to see if it is a duplicate + se = lwasm_find_symbol(as, sym, scontext); + if (se) + { + if (flags & SYMBOL_FORCE && as -> passnum != 2) + { + register_error(as, l, 1, "Multiply defined symbol: %s", sym); + return -1; + } + if (!(flags & SYMBOL_SET) || (flags & SYMBOL_SET && !(se -> flags & SYMBOL_SET))) + { + register_error(as, l, 1, "Mulitply defined symbol: %s", sym); + return -1; + } + } + if (se) + { + se -> value = val; + if (flags & SYMBOL_COMPLEX) + { + se -> expr = l -> exprs[0]; + } + else + { + se -> expr = NULL; + } + return; + } + + // if not a duplicate, register it with the value + se = lwasm_alloc(sizeof(lwasm_symbol_ent_t)); + if (as -> symhead) + { + se -> prev = NULL; + se -> next = as -> symhead; + as -> symhead -> prev = se; + as -> symhead = se; + } + else + { + se -> next = NULL; + se -> prev = NULL; + as -> symhead = se; + as -> symtail = se; + } + se -> value = val; + if (flags & SYMBOL_COMPLEX) + se -> expr = l -> exprs[0]; + se -> sym = lwasm_strdup(sym); + se -> context = scontext; + + if (!(flags & SYMBOL_EXTERN)) + se -> sect = as -> csect; + else + se -> sect = NULL; + + se -> expr = NULL; + se -> flags = flags; + se -> externalname = NULL; + + return 0; +} + +lwasm_symbol_ent_t *lwasm_find_symbol(asmstate_t *as, char *sym, int scontext) +{ + lwasm_symbol_ent_t *se; + static int st = 0; + + for (se = as -> symhead; se; se = se -> next) + { + if (scontext == se -> context && !strcmp(sym, se -> sym)) + { + return se; + } + } + if (as -> passnum == 2 && st == 0 && scontext == -1 && as -> outformat == OUTPUT_OBJ && as -> pragmas & PRAGMA_UNDEFEXTERN) + { + // we want undefined symbols to be considered external + // we didn't find it on a lookup so register it as external + // but we only do so when looking up in global context + st = 1; + if (lwasm_register_symbol(as, NULL, sym, 0, SYMBOL_EXTERN)) + { + st = 0; + return NULL; + } + st = 0; + + // find the newly registered symbol and return it + for (se = as -> symhead; se; se = se -> next) + { + if (scontext == se -> context && !strcmp(sym, se -> sym)) + { + return se; + } + } + } + + return NULL; +} + +// reset the value of a symbol - should not be used normally +// it is intended for use by such operations as EQU +// returns -1 if the symbol is not registered +int lwasm_set_symbol(asmstate_t *as, char *sym, int scontext, int val) +{ + lwasm_symbol_ent_t *se; + + se = lwasm_find_symbol(as, sym, scontext); + if (!se) + return -1; + + se -> value = val; + return 0; +} + +void lwasm_list_symbols(asmstate_t *as, FILE *lf) +{ + lwasm_symbol_ent_t *se; + + for (se = as -> symhead; se; se = se -> next) + { + if (se -> expr) + { + fprintf(lf, "<incompl>"); + } + else if (se -> value > 0xffff || se -> value < -0x8000) + { + fprintf(lf, "%08X ", se -> value); + } + else + { + fprintf(lf, " %04X ", se -> value); + } + if (se -> context < 0) + fputc('G', lf); + else + fputc('L', lf); + + if (se -> flags & SYMBOL_SET) + fputc('S', lf); + else if (se -> flags & SYMBOL_EXTERN) + fputc('E', lf); + else + fputc(' ', lf); + + fprintf(lf, " %s", se -> sym); + + if (se -> context >= 0) + fprintf(lf, " (%d)", se -> context); + + if (se -> sect) + { + fprintf(lf, " [%s]", se -> sect -> name); + } + + fputc('\n', lf); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/util.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,84 @@ +/* +util.c +Copyright © 2008 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +Utility functions +*/ + +#define __util_c_seen__ + +#include <malloc.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "util.h" + +void *lwasm_alloc(int size) +{ + void *ptr; + + ptr = malloc(size); + if (!ptr) + { + // bail out; memory allocation error + fprintf(stderr, "Memory allocation error\n"); + exit(1); + } + return ptr; +} + +void *lwasm_realloc(void *optr, int size) +{ + void *ptr; + + if (size == 0) + { + lwasm_free(optr); + return; + } + + ptr = realloc(optr, size); + if (!ptr) + { + fprintf(stderr, "lwasm_realloc(): memory allocation error\n"); + exit(1); + } +} + +void lwasm_free(void *ptr) +{ + if (ptr) + free(ptr); +} + +char *lwasm_strdup(const char *s) +{ + char *d; + + d = strdup(s); + if (!d) + { + fprintf(stderr, "lwasm_strdup(): memory allocation error\n"); + exit(1); + } + + return d; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/util.h Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,44 @@ +/* +expr.h +Copyright © 2008 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +Utility functions +*/ + +#ifndef __util_h_seen__ +#define __util_h_seen__ + +#ifndef __util_c_seen__ +#define __util_E__ extern +#else +#define __util_E__ +#endif + +// allocate memory +__util_E__ void *lwasm_alloc(int size); +__util_E__ void lwasm_free(void *ptr); +__util_E__ void *lwasm_realloc(void *optr, int size); + +// string stuff +__util_E__ char *lwasm_strdup(const char *s); + +#undef __util_E__ + +#endif // __util_h_seen__
--- a/src/Makefile.am Fri Jan 30 02:55:30 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -bin_PROGRAMS = lwasm -lwasm_SOURCES = main.c expr.c pass1.c pass2.c util.c instab.c parse.c lwasm.c insn_inh.c insn_rtor.c insn_rlist.c insn_rel.c insn_tfm.c insn_bitbit.c insn_indexed.c insn_gen.c insn_logicmem.c list.c symbol.c output.c pseudo.c macro.c pragma.c -EXTRA_DIST = instab.h lwasm.h expr.h util.h
--- a/src/insn_gen.c Fri Jan 30 02:55:30 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,228 +0,0 @@ -/* -insn_gen.c, Copyright © 2009 William Astle - -This file is part of LWASM. - -LWASM is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - -Contains code for parsing general addressing modes (IMM+DIR+EXT+IND) -*/ - -#include <ctype.h> -#include <stdlib.h> - -#include "lwasm.h" -#include "instab.h" -#include "expr.h" - -extern void insn_indexed_aux(asmstate_t *as, lwasm_line_t *l, const char **p, int *b1, int *b2, int *b3); - -// "extra" is required due to the way OIM, EIM, TIM, and AIM work -void insn_gen_aux(asmstate_t *as, lwasm_line_t *l, char **optr, int opnum, int extra) -{ - int b1 = -1, b2 = -1, b3 = -1; - - const char *optr2; - int v1, tv, rval; - lwasm_expr_stack_t *s; - int f8 = 0; - int f16 = 0; - int isdp = 0; - - optr2 = *optr; - while (*optr2 && !isspace(*optr2) && *optr2 != ',') optr2++ - /* do nothing */ ; - - if (*optr2 != ',' && **optr != '[') - { - // not indexed - if (l -> fsize == 1) - f8 = 1; - else if (l -> fsize == 2) - f16 = 1; - - if (**optr == '<') - { - (*optr)++; - f8 = 1; - } - else if (**optr == '>') - { - (*optr)++; - f16 = 1; - } - rval = lwasm_expr_result2(as, l, optr, 0, &v1, 0); - if (rval != 0) - { - f16 = 1; - v1 = 0; - l -> fsize = 2; - } - - if (((v1 >> 8) & 0xff) == (as -> dpval & 0xff)) - isdp = 1; - - // disallow non-explicit DP in obj target - if (as -> outformat == OUTPUT_OBJ && !f8) - f16 = 1; - - if (f8 || (!f16 && isdp)) - { - v1 = v1 & 0xffff; - tv = v1 - ((as -> dpval) << 8); - if (tv < 0 || tv > 0xff) - { - register_error(as, l, 2, "Byte overflow"); - } - v1 = v1 & 0xff; - lwasm_emitop(as, l, instab[opnum].ops[0]); - if (extra != -1) - lwasm_emit(as, l, extra); - lwasm_emit(as, l, v1 & 0xff); - return; - } - else - { - // everything else is 16 bit.... - lwasm_emitop(as, l, instab[opnum].ops[2]); - if (extra != -1) - lwasm_emit(as, l, extra); - l -> relocoff = as -> addr - l -> codeaddr; - lwasm_emit(as, l, v1 >> 8); - lwasm_emit(as, l, v1 & 0xff); - return; - } - } - - lwasm_emitop(as, l, instab[opnum].ops[1]); - if (extra != -1) - lwasm_emit(as, l, extra); - insn_indexed_aux(as, l, (const char **)optr, &b1, &b2, &b3); - if (b1 != -1) - lwasm_emit(as, l, b1); - if (b2 != -1) - lwasm_emit(as, l, b2); - if (b3 != -1) - lwasm_emit(as, l, b3); - return; -} - -// the various insn_gen? functions have an immediate mode of ? bits -OPFUNC(insn_gen0) -{ - if (**p == '#') - { - register_error(as, l, 1, "Immediate mode not allowed"); - return; - } - - // handle non-immediate - insn_gen_aux(as, l, p, opnum, -1); -} - -OPFUNC(insn_gen8) -{ - int rval; - int r; - - if (**p == '#') - { - lwasm_emitop(as, l, instab[opnum].ops[3]); - (*p)++; - r = lwasm_expr_result2(as, l, p, 0, &rval, 0); - if (r != 0) - rval = 0; - if (r == 1 && as -> passnum == 2) - register_error(as, l, 2, "Illegal external or intersegment reference"); - lwasm_emit(as, l, rval & 0xff); - return; - } - - insn_gen_aux(as, l, p, opnum, -1); -} - -OPFUNC(insn_gen16) -{ - int rval, r; - - if (**p == '#') - { - lwasm_emitop(as, l, instab[opnum].ops[3]); - (*p)++; - - r = lwasm_expr_result2(as, l, p, 0, &rval, 0); - if (r != 0) - rval = 0; - if (r == 1 && as -> passnum == 2) - { - l -> relocoff = as -> addr - l -> codeaddr; - } - lwasm_emit(as, l, (rval >> 8) & 0xff); - lwasm_emit(as, l, rval & 0xff); - return; - } - - insn_gen_aux(as, l, p, opnum, -1); -} - -OPFUNC(insn_gen32) -{ - int r, rval; - - if (**p == '#') - { - lwasm_emitop(as, l, instab[opnum].ops[3]); - (*p)++; - - r = lwasm_expr_result2(as, l, p, 0, &rval, 0); - if (r != 0) - rval = 0; - if (r == 1 && as -> passnum == 2) - { - register_error(as, l, 2, "Illegal external or intersegment reference"); - } - - lwasm_emit(as, l, (rval >> 24) & 0xff); - lwasm_emit(as, l, (rval >> 16) & 0xff); - lwasm_emit(as, l, (rval >> 8) & 0xff); - lwasm_emit(as, l, rval & 0xff); - return; - } - - insn_gen_aux(as, l, p, opnum, -1); -} - -OPFUNC(insn_imm8) -{ - int r, rval; - - if (**p == '#') - { - lwasm_emitop(as, l, instab[opnum].ops[0]); - (*p)++; - - r = lwasm_expr_result2(as, l, p, 0, &rval, 0); - if (r != 0) - rval = 0; - if (r == 1 && as -> passnum == 2) - register_error(as, l, 2, "Illegal external or intersegment reference"); - - if (rval < -128 || rval > 255) - register_error(as, l, 2, "Byte overflow"); - lwasm_emit(as, l, rval & 0xff); - return; - } - - register_error(as, l, 1, "Bad operand"); -}
--- a/src/instab.c Fri Jan 30 02:55:30 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,389 +0,0 @@ -/* -instab.c -Copyright © 2008 William Astle - -This file is part of LWASM. - -LWASM is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - - -Contains the instruction table for assembling code -*/ - -#include <stdlib.h> - -#define __instab_c_seen__ -#include "instab.h" - -extern OPFUNC(insn_inh); -extern OPFUNC(insn_gen8); -extern OPFUNC(insn_gen16); -extern OPFUNC(insn_gen32); -extern OPFUNC(insn_gen0); -extern OPFUNC(insn_rtor); -extern OPFUNC(insn_imm8); -extern OPFUNC(insn_rel8); -extern OPFUNC(insn_rel16); -extern OPFUNC(insn_rlist); -extern OPFUNC(insn_bitbit); -extern OPFUNC(insn_logicmem); -extern OPFUNC(insn_tfm); -extern OPFUNC(insn_indexed); - -extern OPFUNC(pseudo_org); -extern OPFUNC(pseudo_equ); -extern OPFUNC(pseudo_rmb); -extern OPFUNC(pseudo_rmd); -extern OPFUNC(pseudo_rmq); -extern OPFUNC(pseudo_zmb); -extern OPFUNC(pseudo_zmd); -extern OPFUNC(pseudo_zmq); -extern OPFUNC(pseudo_include); -extern OPFUNC(pseudo_end); -extern OPFUNC(pseudo_align); -extern OPFUNC(pseudo_error); -extern OPFUNC(pseudo_fcc); -extern OPFUNC(pseudo_fcs); -extern OPFUNC(pseudo_fcn); -extern OPFUNC(pseudo_fcb); -extern OPFUNC(pseudo_fdb); -extern OPFUNC(pseudo_fqb); -extern OPFUNC(pseudo_ifne); -extern OPFUNC(pseudo_ifeq); -extern OPFUNC(pseudo_ifgt); -extern OPFUNC(pseudo_ifge); -extern OPFUNC(pseudo_iflt); -extern OPFUNC(pseudo_ifle); -extern OPFUNC(pseudo_else); -extern OPFUNC(pseudo_endc); -extern OPFUNC(pseudo_macro); -extern OPFUNC(pseudo_endm); -extern OPFUNC(pseudo_setdp); -extern OPFUNC(pseudo_set); -extern OPFUNC(pseudo_section); -extern OPFUNC(pseudo_endsection); -extern OPFUNC(pseudo_pragma); -extern OPFUNC(pseudo_starpragma); -extern OPFUNC(pseudo_extern); -extern OPFUNC(pseudo_export); -extern OPFUNC(pseudo_ifdef); -extern OPFUNC(pseudo_ifndef); - -instab_t instab[] = -{ - { "abx", { 0x3a, -0x1, -0x1, -0x1 }, insn_inh }, - { "adca", { 0x99, 0xa9, 0xb9, 0x89 }, insn_gen8 }, - { "adcb", { 0xd9, 0xe9, 0xf9, 0xc9 }, insn_gen8 }, - { "adcd", { 0x1099, 0x10a9, 0x10b9, 0x1089 }, insn_gen16 }, - { "adcr", { 0x1031, -0x1, -0x1, -0x1 }, insn_rtor }, - { "adda", { 0x9b, 0xab, 0xbb, 0x8b }, insn_gen8 }, - { "addb", { 0xdb, 0xeb, 0xfb, 0xcb }, insn_gen8 }, - { "addd", { 0xd3, 0xe3, 0xf3, 0xc3 }, insn_gen16 }, - { "adde", { 0x119b, 0x11ab, 0x11bb, 0x118b }, insn_gen8 }, - { "addf", { 0x11db, 0x11eb, 0x11fb, 0x11cb }, insn_gen8 }, - { "addr", { 0x1030, -0x1, -0x1, -0x1 }, insn_rtor }, - { "addw", { 0x109b, 0x10ab, 0x10bb, 0x108b }, insn_gen16 }, - { "aim", { 0x02, 0x62, 0x72, -0x1 }, insn_logicmem }, - { "anda", { 0x94, 0xa4, 0xb4, 0x84 }, insn_gen8 }, - { "andb", { 0xd4, 0xe4, 0xf4, 0xc4 }, insn_gen8 }, - { "andcc", { 0x1c, -0x1, -0x1, 0x1c }, insn_imm8 }, - { "andd", { 0x1094, 0x10a4, 0x10b4, 0x1084 }, insn_gen16 }, - { "andr", { 0x1034, -0x1, -0x1, -0x1 }, insn_rtor }, - { "asl", { 0x08, 0x68, 0x78, -0x1 }, insn_gen0 }, - { "asla", { 0x48, -0x1, -0x1, -0x1 }, insn_inh }, - { "aslb", { 0x58, -0x1, -0x1, -0x1 }, insn_inh }, - { "asld", { 0x1048, -0x1, -0x1, -0x1 }, insn_inh }, - { "asr", { 0x07, 0x67, 0x77, -0x1 }, insn_gen0 }, - { "asra", { 0x47, -0x1, -0x1, -0x1 }, insn_inh }, - { "asrb", { 0x57, -0x1, -0x1, -0x1 }, insn_inh }, - { "asrd", { 0x1047, -0x1, -0x1, -0x1 }, insn_inh }, - - { "band", { 0x1130, -0x1, -0x1, -0x1 }, insn_bitbit }, - { "bcc", { 0x24, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "bcs", { 0x25, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "beor", { 0x1134, -0x1, -0x1, -0x1 }, insn_bitbit }, - { "beq", { 0x27, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "bge", { 0x2c, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "bgt", { 0x2e, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "bhi", { 0x22, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "bhs", { 0x24, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "biand", { 0x1131, -0x1, -0x1, -0x1 }, insn_bitbit }, - { "bieor", { 0x1135, -0x1, -0x1, -0x1 }, insn_bitbit }, - { "bior", { 0x1133, -0x1, -0x1, -0x1 }, insn_bitbit }, - { "bita", { 0x95, 0xa5, 0xb5, 0x85 }, insn_gen8 }, - { "bitb", { 0xd5, 0xe5, 0xf5, 0xc5 }, insn_gen8 }, - { "bitd", { 0x1095, 0x10a5, 0x10b5, 0x1085 }, insn_gen16 }, - { "bitmd", { 0x113c, -0x1, -0x1, 0x113c }, insn_imm8 }, - { "ble", { 0x2f, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "blo", { 0x25, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "bls", { 0x23, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "blt", { 0x2d, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "bmi", { 0x2b, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "bne", { 0x26, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "bor", { 0x1132, -0x1, -0x1, -0x1 }, insn_bitbit }, - { "bpl", { 0x2a, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "bra", { 0x20, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "brn", { 0x21, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "bsr", { 0x8d, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "bvc", { 0x28, -0x1, -0x1, -0x1 }, insn_rel8 }, - { "bvs", { 0x29, -0x1, -0x1, -0x1 }, insn_rel8 }, - - { "clr", { 0x0f, 0x6f, 0x7f, -0x1 }, insn_gen0 }, - { "clra", { 0x4f, -0x1, -0x1, -0x1 }, insn_inh }, - { "clrb", { 0x5f, -0x1, -0x1, -0x1 }, insn_inh }, - { "clrd", { 0x104f, -0x1, -0x1, -0x1 }, insn_inh }, - { "clre", { 0x114f, -0x1, -0x1, -0x1 }, insn_inh }, - { "clrf", { 0x115f, -0x1, -0x1, -0x1 }, insn_inh }, - { "clrw", { 0x105f, -0x1, -0x1, -0x1 }, insn_inh }, - { "cmpa", { 0x91, 0xa1, 0xb1, 0x81 }, insn_gen8 }, - { "cmpb", { 0xd1, 0xe1, 0xf1, 0xc1 }, insn_gen8 }, - { "cmpd", { 0x1093, 0x10a3, 0x10b3, 0x1083 }, insn_gen16 }, - { "cmpe", { 0x1191, 0x11a1, 0x11b1, 0x1181 }, insn_gen8 }, - { "cmpf", { 0x11d1, 0x11e1, 0x11f1, 0x11c1 }, insn_gen8 }, - { "cmpr", { 0x1037, -0x1, -0x1, -0x1 }, insn_rtor }, - { "cmps", { 0x119c, 0x11ac, 0x11bc, 0x118c }, insn_gen16 }, - { "cmpu", { 0x1193, 0x11a3, 0x11b3, 0x1183 }, insn_gen16 }, - { "cmpw", { 0x1091, 0x10a1, 0x10b1, 0x1081 }, insn_gen16 }, - { "cmpx", { 0x9c, 0xac, 0xbc, 0x8c }, insn_gen16 }, - { "cmpy", { 0x109c, 0x10ac, 0x10bc, 0x108c }, insn_gen16 }, - { "com", { 0x03, 0x63, 0x73, -0x1 }, insn_gen0 }, - { "coma", { 0x43, -0x1, -0x1, -0x1 }, insn_inh }, - { "comb", { 0x53, -0x1, -0x1, -0x1 }, insn_inh }, - { "comd", { 0x1043, -0x1, -0x1, -0x1 }, insn_inh }, - { "come", { 0x1143, -0x1, -0x1, -0x1 }, insn_inh }, - { "comf", { 0x1153, -0x1, -0x1, -0x1 }, insn_inh }, - { "comw", { 0x1053, -0x1, -0x1, -0x1 }, insn_inh }, - { "cwai", { 0x3c, -0x1, -0x1, -0x1 }, insn_imm8 }, - - { "daa", { 0x19, -0x1, -0x1, -0x1 }, insn_inh }, - { "dec", { 0x0a, 0x6a, 0x7a, -0x1 }, insn_gen0 }, - { "deca", { 0x4a, -0x1, -0x1, -0x1 }, insn_inh }, - { "decb", { 0x5a, -0x1, -0x1, -0x1 }, insn_inh }, - { "decd", { 0x104a, -0x1, -0x1, -0x1 }, insn_inh }, - { "dece", { 0x114a, -0x1, -0x1, -0x1 }, insn_inh }, - { "decf", { 0x115a, -0x1, -0x1, -0x1 }, insn_inh }, - { "decw", { 0x105a, -0x1, -0x1, -0x1 }, insn_inh }, - { "divd", { 0x118d, 0x119d, 0x11ad, 0x11bd }, insn_gen8 }, - { "divq", { 0x118e, 0x119e, 0x11ae, 0x11be }, insn_gen16 }, - - { "eim", { 0x05, 0x65, 0x75, -0x1 }, insn_logicmem }, - { "eora", { 0x98, 0xa8, 0xb8, 0x88 }, insn_gen8 }, - { "eorb", { 0xd8, 0xe9, 0xf9, 0xc8 }, insn_gen8 }, - { "eord", { 0x1098, 0x10a8, 0x10b8, 0x1088 }, insn_gen16 }, - { "eorr", { 0x1036, -0x1, -0x1, -0x1 }, insn_rtor }, - { "exg", { 0x1e, -0x1, -0x1, -0x1 }, insn_rtor }, - - { "inc", { 0x0c, 0x6c, 0x7c, -0x1 }, insn_gen0 }, - { "inca", { 0x4c, -0x1, -0x1, -0x1 }, insn_inh }, - { "incb", { 0x5c, -0x1, -0x1, -0x1 }, insn_inh }, - { "incd", { 0x104c, -0x1, -0x1, -0x1 }, insn_inh }, - { "ince", { 0x114c, -0x1, -0x1, -0x1 }, insn_inh }, - { "incf", { 0x115c, -0x1, -0x1, -0x1 }, insn_inh }, - { "incw", { 0x105c, -0x1, -0x1, -0x1 }, insn_inh }, - - { "jmp", { 0x0e, 0x6e, 0x7e, -0x1 }, insn_gen0 }, - { "jsr", { 0x9d, 0xad, 0xbd, -0x1 }, insn_gen0 }, - - { "lbcc", { 0x1024, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbcs", { 0x1025, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbeq", { 0x1027, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbge", { 0x102c, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbgt", { 0x102e, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbhi", { 0x1022, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbhs", { 0x1024, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lble", { 0x102f, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lblo", { 0x1025, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbls", { 0x1023, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lblt", { 0x102d, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbmi", { 0x102b, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbne", { 0x1026, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbpl", { 0x102a, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbra", { 0x16, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbrn", { 0x1021, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbsr", { 0x17, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbvc", { 0x1028, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lbvs", { 0x1029, -0x1, -0x1, -0x1 }, insn_rel16 }, - { "lda", { 0x96, 0xa6, 0xb6, 0x86 }, insn_gen8 }, - { "ldb", { 0xd6, 0xe6, 0xf6, 0xc6 }, insn_gen8 }, - { "ldbt", { 0x1136, -0x1, -0x1, -0x1 }, insn_bitbit }, - { "ldd", { 0xdc, 0xec, 0xfc, 0xcc }, insn_gen16 }, - { "lde", { 0x1196, 0x11a6, 0x11b6, 0x1186 }, insn_gen8 }, - { "ldf", { 0x11d6, 0x11e6, 0x11f6, 0x11c6 }, insn_gen8 }, - { "ldq", { 0x10dc, 0x10ec, 0x10fc, 0xcd }, insn_gen32 }, - { "lds", { 0x10de, 0x10ee, 0x10fe, 0x10ce }, insn_gen16 }, - { "ldu", { 0xde, 0xee, 0xfe, 0xce }, insn_gen16 }, - { "ldw", { 0x1096, 0x10a6, 0x10b6, 0x1086 }, insn_gen16 }, - { "ldx", { 0x9e, 0xae, 0xbe, 0x8e }, insn_gen16 }, - { "ldy", { 0x109e, 0x10ae, 0x10be, 0x108e }, insn_gen16 }, - { "ldmd", { 0x113d, -0x1, -0x1, 0x113d }, insn_imm8 }, - { "leas", { 0x32, -0x1, -0x1, -0x1 }, insn_indexed }, - { "leau", { 0x33, -0x1, -0x1, -0x1 }, insn_indexed }, - { "leax", { 0x30, -0x1, -0x1, -0x1 }, insn_indexed }, - { "leay", { 0x31, -0x1, -0x1, -0x1 }, insn_indexed }, - { "lsl", { 0x08, 0x68, 0x78, -0x1 }, insn_gen0 }, - { "lsla", { 0x48, -0x1, -0x1, -0x1 }, insn_inh }, - { "lslb", { 0x58, -0x1, -0x1, -0x1 }, insn_inh }, - { "lsld", { 0x1048, -0x1, -0x1, -0x1 }, insn_inh }, - { "lsr", { 0x04, 0x64, 0x74, -0x1 }, insn_gen0 }, - { "lsra", { 0x44, -0x1, -0x1, -0x1 }, insn_inh }, - { "lsrb", { 0x54, -0x1, -0x1, -0x1 }, insn_inh }, - { "lsrd", { 0x1044, -0x1, -0x1, -0x1 }, insn_inh }, - { "lsrw", { 0x1054, -0x1, -0x1, -0x1 }, insn_inh }, - - { "mul", { 0x3d, -0x1, -0x1, -0x1 }, insn_inh }, - { "muld", { 0x118f, 0x119f, 0x11af, 0x11bf }, insn_gen16 }, - - { "neg", { 0x00, 0x60, 0x70, -0x1 }, insn_gen0 }, - { "nega", { 0x40, -0x1, -0x1, -0x1 }, insn_inh }, - { "negb", { 0x50, -0x1, -0x1, -0x1 }, insn_inh }, - { "negd", { 0x1040, -0x1, -0x1, -0x1 }, insn_inh }, - { "nop", { 0x12, -0x1, -0x1, -0x1 }, insn_inh }, - - { "oim", { 0x01, 0x61, 0x71, -0x1 }, insn_logicmem }, - { "ora", { 0x9a, 0xaa, 0xba, 0x8a }, insn_gen8 }, - { "orb", { 0xda, 0xea, 0xfa, 0xca }, insn_gen8 }, - { "orcc", { 0x1a, -0x1, -0x1, 0x1a }, insn_imm8 }, - { "ord", { 0x109a, 0x10aa, 0x10ba, 0x108a }, insn_gen16 }, - { "orr", { 0x1035, -0x1, -0x1, -0x1 }, insn_rtor }, - - { "pshs", { 0x34, -0x1, -0x1, -0x1 }, insn_rlist }, - { "pshsw", { 0x1038, -0x1, -0x1, -0x1 }, insn_inh }, - { "pshu", { 0x36, -0x1, -0x1, -0x1 }, insn_rlist }, - { "pshuw", { 0x103a, -0x1, -0x1, -0x1 }, insn_inh }, - { "puls", { 0x35, -0x1, -0x1, -0x1 }, insn_rlist }, - { "pulsw", { 0x1039, -0x1, -0x1, -0x1 }, insn_inh }, - { "pulu", { 0x37, -0x1, -0x1, -0x1 }, insn_rlist }, - { "puluw", { 0x103b, -0x1, -0x1, -0x1 }, insn_inh }, - - { "rol", { 0x09, 0x69, 0x79, -0x1 }, insn_gen0 }, - { "rola", { 0x49, -0x1, -0x1, -0x1 }, insn_inh }, - { "rolb", { 0x59, -0x1, -0x1, -0x1 }, insn_inh }, - { "rold", { 0x1049, -0x1, -0x1, -0x1 }, insn_inh }, - { "rolw", { 0x1059, -0x1, -0x1, -0x1 }, insn_inh }, - { "ror", { 0x06, 0x66, 0x76, -0x1 }, insn_gen0 }, - { "rora", { 0x46, -0x1, -0x1, -0x1 }, insn_inh }, - { "rorb", { 0x56, -0x1, -0x1, -0x1 }, insn_inh }, - { "rord", { 0x1046, -0x1, -0x1, -0x1 }, insn_inh }, - { "rorw", { 0x1056, -0x1, -0x1, -0x1 }, insn_inh }, - { "rti", { 0x3b, -0x1, -0x1, -0x1 }, insn_inh }, - { "rts", { 0x39, -0x1, -0x1, -0x1 }, insn_inh }, - - { "sbca", { 0x92, 0xa2, 0xb2, 0x82 }, insn_gen8 }, - { "sbcb", { 0xd2, 0xe2, 0xf2, 0xc2 }, insn_gen8 }, - { "sbcd", { 0x1092, 0x10a2, 0x10b2, 0x1082 }, insn_gen16 }, - { "sbcr", { 0x1033, -0x1, -0x1, -0x1 }, insn_rtor }, - { "sex", { 0x1d, -0x1, -0x1, -0x1 }, insn_inh }, - { "sexw", { 0x14, -0x1, -0x1, -0x1 }, insn_inh }, - { "sta", { 0x97, 0xa7, 0xb7, -0x1 }, insn_gen0 }, - { "stb", { 0xd7, 0xe7, 0xf7, -0x1 }, insn_gen0 }, - { "stbt", { 0x1137, -0x1, -0x1, -0x1 }, insn_bitbit }, - { "std", { 0xdd, 0xed, 0xfd, -0x1 }, insn_gen0 }, - { "ste", { 0x1197, 0x11a7, 0x11b7, -0x1 }, insn_gen0 }, - { "stf", { 0x11d7, 0x11e7, 0x11f7, -0x1 }, insn_gen0 }, - { "stq", { 0x10dd, 0x10ed, 0x10fd, -0x1 }, insn_gen0 }, - { "sts", { 0x10df, 0x10ef, 0x10ff, -0x1 }, insn_gen0 }, - { "stu", { 0xdf, 0xef, 0xff, -0x1 }, insn_gen0 }, - { "stw", { 0x1097, 0x10a7, 0x10b7, -0x1 }, insn_gen0 }, - { "stx", { 0x9f, 0xaf, 0xbf, -0x1 }, insn_gen0 }, - { "sty", { 0x109f, 0x10af, 0x10bf, -0x1 }, insn_gen0 }, - { "suba", { 0x90, 0xa0, 0xb0, 0x80 }, insn_gen8 }, - { "subb", { 0xd0, 0xe0, 0xf0, 0xc0 }, insn_gen8 }, - { "subd", { 0x93, 0xa3, 0xb3, 0x83 }, insn_gen16 }, - { "sube", { 0x1190, 0x11a0, 0x11b0, 0x1180 }, insn_gen8 }, - { "subf", { 0x11d0, 0x11e0, 0x11f0, 0x11c0 }, insn_gen8 }, - { "subr", { 0x1032, -0x1, -0x1, -0x1 }, insn_rtor }, - { "subw", { 0x1090, 0x10a0, 0x1090, 0x1080 }, insn_gen8 }, - { "swi", { 0x3f, -0x1, -0x1, -0x1 }, insn_inh }, - { "swi2", { 0x103f, -0x1, -0x1, -0x1 }, insn_inh }, - { "swi3", { 0x113f, -0x1, -0x1, -0x1 }, insn_inh }, - { "sync", { 0x13, -0x1, -0x1, -0x1 }, insn_inh }, - - // note: r+,r+ r-,r- r+,r r,r+ - { "tfm", { 0x1138, 0x1139, 0x113a, 0x113b }, insn_tfm }, - - { "tfr", { 0x1f, -0x1, -0x1, -0x1 }, insn_rtor }, - { "tim", { 0x0b, 0x6b, 0x7b, -0x1 }, insn_logicmem }, - { "tst", { 0x0d, 0x6d, 0x7d, -0x1 }, insn_gen0 }, - { "tsta", { 0x4d, -0x1, -0x1, -0x1 }, insn_inh }, - { "tstb", { 0x5d, -0x1, -0x1, -0x1 }, insn_inh }, - { "tstd", { 0x104d, -0x1, -0x1, -0x1 }, insn_inh }, - { "tste", { 0x114d, -0x1, -0x1, -0x1 }, insn_inh }, - { "tstf", { 0x115d, -0x1, -0x1, -0x1 }, insn_inh }, - { "tstw", { 0x105d, -0x1, -0x1, -0x1 }, insn_inh }, - - { "org", { -1, -1, -1, -1 }, pseudo_org }, - - { "equ", { -1, -1, -1, -1 }, pseudo_equ, 0, 0, 1 }, - { "=", { -1, -1, -1, -1 }, pseudo_equ, 0, 0, 1 }, - { "extern", { -1, -1, -1, -1 }, pseudo_extern, 0, 0, 1 }, - { "external", { -1, -1, -1, -1 }, pseudo_extern, 0, 0, 1 }, - { "import", { -1, -1, -1, -1 }, pseudo_extern, 0, 0, 1 }, - { "export", { -1, -1, -1, -1 }, pseudo_export, 0, 0, 1 }, - - - { "rmb", { -1, -1, -1, -1 }, pseudo_rmb }, - { "rmd", { -1, -1, -1, -1 }, pseudo_rmd }, - { "rmq", { -1, -1, -1, -1 }, pseudo_rmq }, - - { "zmb", { -1, -1, -1, -1 }, pseudo_zmb }, - { "zmd", { -1, -1, -1, -1 }, pseudo_zmd }, - { "zmq", { -1, -1, -1, -1 }, pseudo_zmq }, - - { "fcc", { -1, -1, -1, -1 }, pseudo_fcc }, - { "fcn", { -1, -1, -1, -1 }, pseudo_fcn }, - { "fcs", { -1, -1, -1, -1 }, pseudo_fcs }, - - { "fcb", { -1, -1, -1, -1 }, pseudo_fcb }, - { "fdb", { -1, -1, -1, -1 }, pseudo_fdb }, - { "fqb", { -1, -1, -1, -1 }, pseudo_fqb }, - - { "end", { -1, -1, -1, -1 }, pseudo_end }, - - { "include", { -1, -1, -1, -1 }, pseudo_include }, - - { "align", { -1, -1, -1, -1 }, pseudo_align }, - - { "error", { -1, -1, -1, -1}, pseudo_error }, - - { "ifeq", { -1, -1, -1, -1}, pseudo_ifeq, 1 }, - { "ifne", { -1, -1, -1, -1}, pseudo_ifne, 1 }, - { "if", { -1, -1, -1, -1}, pseudo_ifne, 1 }, - { "ifgt", { -1, -1, -1, -1}, pseudo_ifgt, 1 }, - { "ifge", { -1, -1, -1, -1}, pseudo_ifge, 1 }, - { "iflt", { -1, -1, -1, -1}, pseudo_iflt, 1 }, - { "ifle", { -1, -1, -1, -1}, pseudo_ifle, 1 }, - { "endc", { -1, -1, -1, -1}, pseudo_endc, 1 }, - { "else", { -1, -1, -1, -1}, pseudo_else, 1 }, - { "ifdef", { -1, -1, -1, -1}, pseudo_ifdef, 1}, - { "ifndef", { -1, -1, -1, -1}, pseudo_ifndef, 1}, - - { "macro", { -1, -1, -1, -1}, pseudo_macro, 1, 0, 1 }, - { "endm", { -1, -1, -1, -1}, pseudo_endm, 1, 1, 1 }, - - { "setdp", { -1, -1, -1, -1}, pseudo_setdp }, - { "set", { -1, -1, -1, -1}, pseudo_set, 0, 0, 1 }, - - { "section", { -1, -1, -1, -1}, pseudo_section }, - { "sect", { -1, -1, -1, -1}, pseudo_section }, - { "ends", { -1, -1, -1, -1}, pseudo_endsection }, - { "endsect", { -1, -1, -1, -1}, pseudo_endsection }, - { "endsection", { -1, -1, -1, -1}, pseudo_endsection }, - - { "pragma", { -1, -1, -1, -1}, pseudo_pragma }, - { "*pragma", { -1, -1, -1, -1}, pseudo_starpragma }, - - - /* flag end of table */ - { NULL, { -0x1, -0x1, -0x1, -0x1 }, insn_inh } -};
--- a/src/instab.h Fri Jan 30 02:55:30 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* -instab.h -Copyright © 2008 William Astle - -This file is part of LWASM. - -LWASM is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - - -Contains definitions for the instruction table -*/ - -#ifndef __instab_h_seen__ -#define __instab_h_seen__ - -#include "lwasm.h" - -typedef struct -{ - char *opcode; /* the mneumonic */ - int ops[4]; /* opcode values for up to four addr modes */ - void (*fn)(asmstate_t *as, lwasm_line_t *l, char **optr, int opnum); - int iscond; /* set if this should be dispatched even if skipping a condition/macro */ - int endm; /* end of macro? */ - int setsym; /* does this set a symbol address? EQU, SET */ -} instab_t; - -#define OPFUNC(fn) void (fn)(asmstate_t *as, lwasm_line_t *l, char **p, int opnum) - -#ifndef __instab_c_seen__ -extern instab_t instab[]; -#endif //__instab_c_seen__ - -#endif //__instab_h_seen__
--- a/src/list.c Fri Jan 30 02:55:30 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -/* -list.c -Copyright © 2009 William Astle - -This file is part of LWASM. - -LWASM is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - -Contains code for displaying a program listings, etc. -*/ - -#define __list_c_seen__ - -#include <stdio.h> -#include <stdlib.h> - -#include "lwasm.h" - -void lwasm_show_errors(asmstate_t *as) -{ - lwasm_line_t *l; - lwasm_error_t *e; - - for (l = as -> lineshead; l; l = l -> next) - { - if (l -> err) - { - for (e = l -> err; e; e = e -> next) - { - fprintf(stderr, "ERROR: %s\n", e -> mess); - } - fprintf(stderr, "%s:%d: %s\n", l -> filename, l -> lineno, l -> text); - } - } -} - -void lwasm_list(asmstate_t *as) -{ - FILE *lf; - lwasm_line_t *l; - int c, c3; - char *p; - - if (!as -> listfile) - return; - if (as -> listfile[0] == '-' && as -> listfile[1] == '\0') - lf = stdout; - else - { - lf = fopen(as -> listfile, "w"); - if (!lf) - { - fprintf(stderr, "Unable to open list file '%s'. No listing will be generated: ", as -> listfile); - perror(""); - goto showerr; - } - } - - for (l = as -> lineshead; l; l = l -> next) - { - if (l -> addrset == 1 || l -> codelen > 0 || l -> nocodelen > 0) - { - fprintf(lf, "%04X ", l -> codeaddr); - } - else - { - fprintf(lf, " "); - } - - if (l -> addrset == 2) - { - fprintf(lf, "%04X ", l -> symaddr); - } - else - { - for (c = 0; c < l -> codelen && c < 5; c++) - { - fprintf(lf, "%02X", l -> bytes[c]); - } - while (c < 5) - { - fprintf(lf, " "); - c++; - } - } - fprintf(lf, " %20.20s:%05d ", l -> filename, l -> lineno); - - // print line here - for (c3 = 0, c = 0, p = l -> text; *p; c++, p++) - { - if (*p == '\t') - { - int c2; - c2 = 8 - (c3 % 8); - c3 += c2; - while (c2--) fputc(' ', lf); - } - else - { - c3++; - fputc(*p, lf); - } - } - fputc('\n', lf); - - if (l -> codelen > 5) - { - fprintf(lf, "%04X ", (l -> codeaddr + 5) & 0xFFFF); - for (c = 5; c < l -> codelen; c++) - { - if (!(c % 5) && c != 5) - { - fprintf(lf, "\n%04X ", (l -> codeaddr + c) & 0xFFFF); - } - fprintf(lf, "%02X", l -> bytes[c]); - } - fputc('\n', lf); - } - } - - lwasm_list_symbols(as, lf); - - if (lf != stdout) - fclose(lf); - -showerr: - lwasm_show_errors(as); -}
--- a/src/lwasm.c Fri Jan 30 02:55:30 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,428 +0,0 @@ -/* -lwasm.c -Copyright © 2009 William Astle - -This file is part of LWASM. - -LWASM is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - - -Contains random functions used by the assembler -*/ - -#define __lwasm_c_seen__ - -#include <stdarg.h> -#include <stdlib.h> -#include <stdio.h> - -#include "lwasm.h" -#include "util.h" -#include "expr.h" - -int debug_level = 0; - -int register_error(asmstate_t *as, lwasm_line_t *l, int pass, const char *fmt, ...) -{ - lwasm_error_t *e; - va_list args; - char errbuff[1024]; - int r; - - if (!l) - return; - - if (as -> passnum != pass) - return; - - va_start(args, fmt); - - e = lwasm_alloc(sizeof(lwasm_error_t)); - - e -> next = l -> err; - l -> err = e; - - as -> errorcount++; - - r = vsnprintf(errbuff, 1024, fmt, args); - e -> mess = lwasm_strdup(errbuff); - - va_end(args); - - return r; -} - -void lwasm_emit(asmstate_t *as, lwasm_line_t *l, int b) -{ - as -> addr += 1; - as -> addr &= 0xffff; - - if (as -> outformat == OUTPUT_OBJ && !(as -> csect)) - { - register_error(as, l, 1, "Output not allowed outside sections with obj target"); - return; - } - if (as -> outformat == OUTPUT_OBJ && as -> csect -> flags & SECTION_BSS) - { - register_error(as, l, 1, "Output not allowed inside BSS sections"); - return; - } - if (as -> passnum == 1) - return; - - - if (l -> codelen >= l -> codesize) - { - l -> bytes = realloc(l -> bytes, l -> codesize + 16); - l -> codesize += 16; - } - l -> bytes[l -> codelen] = b & 0xff; - l -> codelen += 1; -} - -void lwasm_emitop(asmstate_t *as, lwasm_line_t *l, int o) -{ - if (o >= 0x100) - lwasm_emit(as, l, o >> 8); - lwasm_emit(as, l, o & 0xff); -} - -int lwasm_lookupreg2(const char *reglist, char **str) -{ - int rval = 0; - - while (*reglist) - { - if (toupper(**str) == *reglist) - { - // first char matches - if (reglist[1] == ' ' && !isalpha(*(*str + 1))) - break; - if (toupper(*(*str + 1)) == reglist[1]) - break; - } - reglist += 2; - rval++; - } - if (!*reglist) - return -1; - if (reglist[1] == ' ') - (*str)++; - else - (*str) += 2; - return rval; -} - -int lwasm_lookupreg3(const char *rlist, const char **str) -{ - int rval = 0; - int f = 0; - const char *reglist = rlist; - - while (*reglist) - { - if (toupper(**str) == *reglist) - { - // first char matches - if (reglist[1] == ' ') - { - f = 1; - break; - } - if (toupper(*(*str + 1)) == reglist[1]) - { - // second char matches - if (reglist[2] == ' ') - { - f = 1; - break; - } - if (toupper(*(*str + 2)) == reglist[2]) - { - f = 1; - break; - } - } - } - reglist += 3; - rval++; - } - if (f == 0) - return -1; - - - reglist = rval * 3 + rlist; - if (reglist[1] == ' ') - (*str) += 1; - else if (reglist[2] == ' ') - (*str) += 2; - else - (*str)+=3; - return rval; -} - -struct symstateinfo -{ - asmstate_t *as; - lwasm_line_t *l; - int flags; -}; - -lwasm_expr_stack_t *lwasm_expr_lookup_symbol(char *sym, void *state) -{ - lwasm_symbol_ent_t *se; - struct symstateinfo *st; - lwasm_expr_stack_t *rs; - lwasm_expr_term_t *t; - lwasm_expr_stack_node_t *n; - - int val; - - st = state; - debug_message(3, "lwasm_expr_lookup_symbol(): find '%s' (context=%d)", sym, st -> as -> context); - - // check for special symbols first... - if (sym[1] == '\0') - { - switch (sym[0]) - { - // current line address - case '*': - case '.': - val = st -> l -> codeaddr; - goto retconst; - - case '<': - // previous branch point - // not implemented - break; - case '>': - // next branch point - // not implemented - break; - } - } - - // look for local symbol first then global symbol - se = lwasm_find_symbol(st -> as, sym, st -> as -> context); - if (!se) - se = lwasm_find_symbol(st -> as, sym, -1); - debug_message(3, "lwasm_expr_lookup_symbol(): got '%p'", se); - if (!se) - { - register_error(st -> as, st -> l, 2, "Undefined symbol '%s'", sym); - return NULL; - } - // external reference - can not resolve it - if (se -> flags & SYMBOL_EXTERN) - { - return NULL; - } - if (st -> flags & EXPR_SECTCONST) - { - if (se -> sect == st -> l -> sect) - { - if (se -> expr) - goto retsym; - val = se -> value; - goto retconst; - } - } - if (st -> as -> outformat == OUTPUT_OBJ && se -> sect != NULL) - { - return NULL; - } - if (st -> as -> outformat != OUTPUT_OBJ || se -> sect == NULL) - { - // global symbol, intrasegment reference, or not an object target - val = se -> value; - goto retconst; - } - - // an intersegment reference will return as NULL (to be resolved at output/link time) - // if se -> expr is NULL, it has to be an intersegment reference here - if (se -> expr == NULL) - { - return NULL; - } - -retsym: - // duplicate the expression for return - rs = lwasm_expr_stack_create(); - for (n = se -> expr -> head; n; n = n -> next) - { - lwasm_expr_stack_push(rs, n -> term); - } - return rs; - -retconst: - rs = lwasm_expr_stack_create(); - t = lwasm_expr_term_create_int(val); - lwasm_expr_stack_push(rs, t); - lwasm_expr_term_free(t); - return rs; -} - -lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp, int flags) -{ - struct symstateinfo st; - - st.as = as; - st.l = l; - st.flags = flags; - - debug_message(2, "Evaluate expression: %s", inp); - - return(lwasm_expr_eval(inp, outp, lwasm_expr_lookup_symbol, &st)); -} - - -int lwasm_reevaluate_expr(asmstate_t *as, lwasm_line_t *l, lwasm_expr_stack_t *s, int flags) -{ - struct symstateinfo st; - - st.as = as; - st.l = l; - st.flags = flags; - return(lwasm_expr_reval(s, lwasm_expr_lookup_symbol, &st)); -} - -// return 1 if no undefined symbols (externals and incompletes are okay) -// return 0 if there are undefined symbols -int lwasm_expr_result_ckconst(asmstate_t *as, lwasm_expr_stack_t *s) -{ - lwasm_expr_stack_node_t *n; - lwasm_symbol_ent_t *se; - - if (as -> outformat != OUTPUT_OBJ) - { - if (lwasm_expr_is_constant(s)) - return 1; - else - return 0; - } - - for (n = s -> head; n; n = n -> next) - { - if (n -> term -> term_type == LWASM_TERM_SYM) - { - se = lwasm_find_symbol(as, n -> term -> symbol, as -> context); - if (!se) - se = lwasm_find_symbol(as, n -> term -> symbol, -1); - if (!se) - return 0; - } - } - return 1; -} - -/* -Evaluate an expression according to the flag value. Return 0 if a constant result was -obtained, 1 if an incomplete result was obtained, and -1 if an error was flagged. - -*/ -int lwasm_expr_result2(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val, int slot) -{ - lwasm_expr_stack_t *s = NULL; - const char *ep; - int rval; - - if ((as -> passnum == 1 && !(flag & EXPR_REEVAL)) || slot < 0) - { - s = lwasm_evaluate_expr(as, l, *inp, &ep, flag); - if (slot >= 0) - l -> exprs[slot] = s; - if (!s) - { - register_error(as, l, 1, "Bad expression"); - *val = 0; - return -1; - } - *inp = (char *)ep; - if (slot >= 0) - { - l -> exprends[slot] = (char *)ep; - l -> exprvals[slot] = lwasm_expr_get_value(s); - } - } - else if (l -> exprs[slot]) - { - s = l -> exprs[slot]; - lwasm_reevaluate_expr(as, l, s, flag); - l -> exprvals[slot] = lwasm_expr_get_value(s); - } - if (as -> passnum == 2 && slot >= 0) - *inp = l -> exprends[slot]; - - if (s && lwasm_expr_is_constant(s)) - { - *val = lwasm_expr_get_value(s); - lwasm_expr_stack_free(s); - l -> exprs[slot] = NULL; - s = NULL; - return 0; - } - - if (!s && slot >= 0) - { - *val = l -> exprvals[slot]; - return 0; - } - else if (!s) - { - *val = 0; - return 0; - } - - // was a constant result on pass 1 requested? - // that means we must have a constant on either pass - if (flag & EXPR_PASS1CONST) - { - *val = 0; - if (slot >= 0) - l -> exprvals[slot] = 0; - register_error(as, l, 1, "Illegal forward, external, or inter-section reference"); - lwasm_expr_stack_free(s); - if (slot >= 0) - l -> exprs[slot] = NULL; - return -1; - } - - return 1; -} - -void debug_message(int level, const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - if (debug_level >= level) - { - if (level > 0) - fprintf(stderr, "DEBUG %d: ", level); - vfprintf(stderr, fmt, args); - fputc('\n', stderr); - } - va_end(args); -} - -int lwasm_next_context(asmstate_t *as) -{ - int r; - r = as -> nextcontext; - as -> nextcontext += 1; - debug_message(3, "lwasm_next_context(): %d (%d) pass %d", r, as -> nextcontext, as -> passnum); - return r; -} -
--- a/src/lwasm.h Fri Jan 30 02:55:30 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,234 +0,0 @@ -/* -lwasm.h -Copyright © 2008 William Astle - -This file is part of LWASM. - -LWASM is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - -Contains the main defs used by the assembler -*/ - - -#ifndef __lwasm_h_seen__ -#define __lwasm_h_seen__ - -#include <stdio.h> -#include "expr.h" - -#define OUTPUT_DECB 0 // DECB multirecord format -#define OUTPUT_RAW 1 // raw sequence of bytes -#define OUTPUT_OBJ 2 // proprietary object file format -#define OUTPUT_RAWREL 3 // raw bytes where ORG causes a SEEK in the file - -// structure for tracking sections -typedef struct section_reloc_list_s section_reloc_list_t; -struct section_reloc_list_s -{ - int offset; // offset into section - lwasm_expr_stack_t *expr; // value definition - int context; // symbol context (for local syms) - section_reloc_list_t *next; // next relocation -}; - -typedef struct export_list_s export_list_t; -struct export_list_s -{ - int offset; // offset of symbol - char *sym; // name of symbol - export_list_t *next; // next export -}; - -#define SECTION_BSS 1 // the section contains no actual code - just uninit vars -typedef struct sectiontab_s sectiontab_t; -struct sectiontab_s -{ - char *name; // name of the section - int offset; // current offset in the section - int flags; // section flags - sectiontab_t *next; // next section - // the following are used during code output - unsigned char *obytes; // output bytes - int oblen; // how many bytes output so far? - int obsize; // how big is output buffer so far? - section_reloc_list_t *rl; // relocation list - export_list_t *exports; // export list for the section -}; - -// structure for tracking macros -typedef struct macrotab_s macrotab_t; -struct macrotab_s -{ - char *name; - char **lines; - int numlines; - macrotab_t *next; -}; - -// structure for tracking errors -typedef struct lwasm_error_s lwasm_error_t; -struct lwasm_error_s -{ - char *mess; // the actual error message - lwasm_error_t *next; // ptr to next error -}; - -// structure for keeping track of lines -// it also as space for 4 expressions which is enough for all known -// instructions and addressing modes -// on pass 1, the expressions are parsed, on pass 2 they are re-evaluated -// to determine constancy -typedef struct lwasm_line_s lwasm_line_t; -struct lwasm_line_s { - char *text; // the actual text of the line - int lineno; // line number within the file - char *filename; // file name reference - lwasm_line_t *next; // next line - lwasm_line_t *prev; // previous line - lwasm_error_t *err; // error messages - int fsize; // forced size (0 = no forced size) - char *sym; // scratch area to record the presence of a symbol - unsigned char *bytes; // actual bytes emitted - int codelen; // number of bytes emitted - int codesize; // the size of the code buffer - int codeaddr; // address the code goes at - int nocodelen; // for "RMB" type instructions - int addrset; // set if this instruction sets the assembly address - int symaddr; // set if this instruction sets a symbol addr with EQU or the like - int badop; // bad operation - ignore it - int context; // the symbol context for this line - - // the following are used for obj format - for external references, inter-section - // references, and intrasection relocations - int relocoff; // offset into insn where relocation value goes - lwasm_expr_stack_t *exprs[4]; // non-constant expression values - int exprvals[4]; // constant expression values - char *exprends[4]; // pointer to character after end of expression - - sectiontab_t *sect; // which section is the line in? -}; - -// for keeping track of symbols -#define SYMBOL_SET 1 // the symbol was used for "SET" -#define SYMBOL_COMPLEX 2 // register symbol as a complex symbol (from l -> expr) -#define SYMBOL_FORCE 4 // force resetting the symbol value if it already exists on pass 2 -#define SYMBOL_NORM 0 // no flags -#define SYMBOL_EXTERN 8 // the symbol is an external reference -typedef struct lwasm_symbol_ent_s lwasm_symbol_ent_t; -struct lwasm_symbol_ent_s -{ - char *sym; // the symbol - int context; // the context number of the symbol (-1 for global) - int value; // the value of the symbol - int flags; // flags for the symbol - char *externalname; // for external references that are aliased locally - sectiontab_t *sect; // the section the symbol exists in; NULL for none - lwasm_expr_stack_t *expr; // expression for a symbol that is not constant NULL for const - lwasm_symbol_ent_t *next; // next symbol in the table - lwasm_symbol_ent_t *prev; // previous symbol in the table -}; - -// keep track of current assembler state -typedef struct { - int dpval; // current dp value (setdp) - int addr; // current address - int context; // context counter (for local symbols) - int errorcount; // error count - int passnum; // which pass are we on? - int execaddr; // execution address for the program (END ....) - int pragmas; // what pragmas are in effect? - - lwasm_line_t *lineshead; // first line of source code - lwasm_line_t *linestail; // last line of source code - - lwasm_symbol_ent_t *symhead; // first entry in symbol table - lwasm_symbol_ent_t *symtail; // last entry in symbol table - - macrotab_t *macros; // macro table - - const char *infile; // input file - const char *outfile; // output file - const char *listfile; // output listing file - int outformat; // output format type - char **filelist; // files that have been read - int filelistlen; // number of files in the list - - int endseen; // set to true if "end" has been seen - int skipcond; // skipping a condition? - int skipcount; // how many? - int skipmacro; // skipping a macro? - int inmacro; // are we currently in a macro? - int macroex; // current depth of macro expansion - int nextcontext; // next context number - int skiplines; // number of lines to skip - - // items used only for the "object" target - sectiontab_t *sections; // pointer to section table - sectiontab_t *csect; // current section - NULL if not in one -} asmstate_t; - -// do not rewrite XXX,r to ,r if XXX evaluates to 0 -#define PRAGMA_NOINDEX0TONONE 1 -// any undefined symbols are considered external -#define PRAGMA_UNDEFEXTERN 2 - -#ifndef __lwasm_c_seen__ -#define __lwasm_E__ extern -#else -#define __lwasm_E__ -#endif - -__lwasm_E__ int debug_level; - -__lwasm_E__ int register_error(asmstate_t *as, lwasm_line_t *l, int pass, const char *fmt, ...); -__lwasm_E__ void debug_message(int level, const char *fmt, ...); - -__lwasm_E__ void lwasm_emit(asmstate_t *as, lwasm_line_t *l, int b); -__lwasm_E__ void lwasm_emitop(asmstate_t *as, lwasm_line_t *l, int o); -__lwasm_E__ int lwasm_lookupreg2(const char *reglist, char **str); -__lwasm_E__ int lwasm_lookupreg3(const char *rlist, const char **str); - -__lwasm_E__ lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp, int flags); - - -// return next context number and update it -__lwasm_E__ int lwasm_next_context(asmstate_t *as); - -// also throw an error on expression eval failure -// return 0 on ok, -1 on error, 1 if a complex expression was returned -#define EXPR_NOFLAG 0 -#define EXPR_PASS1CONST 1 // no forward references on pass 1 -#define EXPR_SECTCONST 2 // resolve symbols local to section -#define EXPR_REEVAL 4 // re-evaluate the expression -__lwasm_E__ int lwasm_expr_result(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val); -__lwasm_E__ int lwasm_expr_result2(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val, int slot); - -#undef __lwasm_E__ - - -#ifndef __symbol_c_seen__ -#define __lwasm_E__ extern -#else -#define __lwasm_E__ -#endif - -__lwasm_E__ int lwasm_register_symbol(asmstate_t *as, lwasm_line_t *l, char *sym, int val, int flags); -__lwasm_E__ lwasm_symbol_ent_t *lwasm_find_symbol(asmstate_t *as, char *sym, int scontext); -__lwasm_E__ int lwasm_set_symbol(asmstate_t *as, char *sym, int scontext, int val); -__lwasm_E__ void lwasm_list_symbols(asmstate_t *as, FILE *f); -#undef __lwasm_E__ - - - -#endif //__lwasm_h_seen__
--- a/src/macro.c Fri Jan 30 02:55:30 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,340 +0,0 @@ -/* -macro.c -Copyright © 2008 William Astle - -This file is part of LWASM. - -LWASM is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - -Contains stuff associated with macro processing -*/ - -#include <ctype.h> -#include <stdlib.h> -#include <string.h> -#include "lwasm.h" -#include "instab.h" -#include "util.h" - -OPFUNC(pseudo_macro) -{ - macrotab_t *m; - - // if skipping a condition, flag in a macro - if (as -> skipcond) - { - as -> skipmacro = 1; - return; - } - - // actually define a macro - if (as -> inmacro) - { - register_error(as, l, 1, "Attempt to define a macro inside a macro"); - return; - } - - as -> inmacro = 1; - - // don't actually do anything if not pass 1 - if (as -> passnum != 1) - return; - - - if (!l -> sym) - { - register_error(as, l, 1, "Macro definition with no effect - no symbol"); - return; - } - - // search for macro by same name... - for (m = as -> macros; m; m = m -> next) - { - if (!strcmp(m -> name, l -> sym)) - break; - } - if (m) - { - register_error(as, l, 1, "Duplicate macro definition"); - return; - } - - m = lwasm_alloc(sizeof(macrotab_t)); - m -> name = lwasm_strdup(l -> sym); - m -> next = as -> macros; - m -> lines = NULL; - m -> numlines = 0; - as -> macros = m; - - while (**p && !isspace(**p)) - (*p)++; -} - -OPFUNC(pseudo_endm) -{ - if (as -> skipcond) - { - as -> skipmacro = 0; - return; - } - - if (!as -> inmacro) - { - register_error(as, l, 1, "ENDM without MACRO"); - return; - } - - as -> inmacro = 0; - - // a macro definition counts as a context break for local symbols - as -> context = lwasm_next_context(as); -} - -// the current macro will ALWAYS be the first one in the table -int add_macro_line(asmstate_t *as, char *optr) -{ - if (!as -> inmacro) - return 0; - - if (as -> passnum == 2) - return 1; - - as -> macros -> lines = lwasm_realloc(as -> macros -> lines, sizeof(char *) * (as -> macros -> numlines + 1)); - as -> macros -> lines[as -> macros -> numlines] = lwasm_strdup(optr); - as -> macros -> numlines += 1; - return 1; -} - -void macro_add_to_buff(char **buff, int *loc, int *len, char c) -{ - if (*loc == *len) - { - *buff = lwasm_realloc(*buff, *len + 32); - *len += 32; - } - (*buff)[(*loc)++] = c; -} - -// this is just like a regular operation function -/* -macro args are referenced by "\n" where 1 <= n <= 9 -or by "\{n}"; a \ can be included by writing \\ -a comma separates argument but one can be included with "\," -whitespace ends argument list but can be included with "\ " or the like - -In pass 1, actually add the lines to the system, in pass 2, do not -In pass 2, track the number of lines to skip because they already will be -processed by this function - this will be in as -> skiplines - -*/ -int expand_macro(asmstate_t *as, lwasm_line_t *l, char **p, char *opc) -{ - int lc; - lwasm_line_t *cl, *nl; - int oldcontext; - macrotab_t *m; - - char **args = NULL; // macro arguments - int nargs = 0; // number of arguments - - char *p2, *p3; - - int bloc, blen; - char *linebuff; - - for (m = as -> macros; m; m = m -> next) - { - if (!strcmp(opc, m -> name)) - break; - } - // signal no macro expansion - if (!m) - return -1; - - - // save current symbol context for after macro expansion - oldcontext = as -> context; - - cl = l; - - as -> context = lwasm_next_context(as); - - // step 1: parse arguments (pass 1 only) - if (as -> passnum == 1) - { - while (**p && !isspace(**p) && **p != ',') - { - p2 = *p; - while (*p2 && !isspace(*p2) && *p2 != ',') - { - if (*p2 == '\\') - { - if (p2[1]) - p2++; - } - p2++; - } - - // have arg here - args = lwasm_realloc(args, sizeof(char *) * (nargs + 1)); - args[nargs] = lwasm_alloc(p2 - *p + 1); - args[nargs][p2 - *p] = '\0'; - memcpy(args[nargs], *p, p2 - *p); - *p = p2; - - // now collapse out "\" characters - for (p3 = p2 = args[nargs]; *p2; p2++, p3++) - { - if (*p2 == '\\' && p2[1]) - { - p2++; - } - *p3 = *p2; - } - *p3 = '\0'; - - nargs++; - if (**p == ',') - (*p)++; - } - } - - { - int i; - for (i = 0; i < nargs; i++) - { - debug_message(10, "Macro (%s) arg %d: %s", m -> name, i + 1, args[i]); - } - } - - // step 2: iterate over the lines - if (as -> passnum == 2) - { - // pass 2 only - parse the lines and count them - for (lc = 0; lc < m -> numlines; lc++) - { - cl = cl -> next; - as -> skiplines++; - lwasm_parse_line(as, cl); - } - } - else - { - // pass 1 only - construct the lines and parse them - for (lc = 0; lc < m -> numlines; lc++) - { - nl = lwasm_alloc(sizeof(lwasm_line_t)); - nl -> lineno = lc + 1; - nl -> filename = m -> name; - nl -> next = NULL; - nl -> prev = as -> linestail; - nl -> err = NULL; - nl -> fsize = 0; - nl -> sym = NULL; - nl -> bytes = NULL; - nl -> codelen = 0; - nl -> codesize = 0; - nl -> nocodelen = 0; - nl -> addrset = 0; - nl -> symaddr = -1; - nl -> badop = 0; - nl -> relocoff = -1; - if (as -> linestail) - as -> linestail -> next = nl; - as -> linestail = nl; - if (!(as -> lineshead)) - as -> lineshead = nl; - - bloc = blen = 0; - linebuff = NULL; - for (p2 = m -> lines[lc]; *p2; p2++) - { - if (*p2 == '\\' && isdigit(p2[1])) - { - int n; - - p2++; - n = *p2 - '0'; - if (n == 0) - { - for (p3 = m -> name; *p3; p3++) - macro_add_to_buff(&linebuff, &bloc, &blen, *p3); - continue; - } - if (n < 1 || n > nargs) - continue; - for (p3 = args[n - 1]; *p3; p3++) - macro_add_to_buff(&linebuff, &bloc, &blen, *p3); - continue; - } - else if (*p2 == '{') - { - int n = 0, n2; - p2++; - while (*p2 && isdigit(*p2)) - { - n2 = *p2 - '0'; - if (n2 < 0 || n2 > 9) - n2 = 0; - n = n * 10 + n2; - p2++; - } - if (*p2 == '}') - p2++; - - if (n == 0) - { - for (p3 = m -> name; *p3; p3++) - macro_add_to_buff(&linebuff, &bloc, &blen, *p3); - continue; - } - if (n < 1 || n > nargs) - continue; - for (p3 = args[n - 1]; *p3; p3++) - macro_add_to_buff(&linebuff, &bloc, &blen, *p3); - continue; - } - else - { - macro_add_to_buff(&linebuff, &bloc, &blen, *p2); - } - } - - macro_add_to_buff(&linebuff, &bloc, &blen, 0); - - nl -> text = linebuff; - - lwasm_parse_line(as, nl); - if (as -> endseen) - break; - - } - } - - // restore context from before the macro was called - as -> context = oldcontext; - - // clean up - if (args) - { - while (nargs) - { - lwasm_free(args[--nargs]); - } - lwasm_free(args); - } - - // indicate a macro was expanded - return 0; -}
--- a/src/main.c Fri Jan 30 02:55:30 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,199 +0,0 @@ -/* -main.c -Copyright © 2008 William Astle - -This file is part of LWASM. - -LWASM is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - - -Implements the program startup code - -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <argp.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> - -#include "lwasm.h" - -// external declarations -extern void lwasm_pass1(asmstate_t *as); -extern void lwasm_pass2(asmstate_t *as); -extern void lwasm_list(asmstate_t *as); -extern void lwasm_output(asmstate_t *as); -extern void pseudo_pragma_real(asmstate_t *as, lwasm_line_t *cl, char **optr, int error); - -// command line option handling -const char *argp_program_version = "LWASM from " PACKAGE_STRING; -const char *argp_program_bug_address = PACKAGE_BUGREPORT; - -static error_t parse_opts(int key, char *arg, struct argp_state *state) -{ - asmstate_t *as = state -> input; - char *p; - - switch (key) - { - case 'o': - // output - if (as -> outfile) - { - } - as -> outfile = arg; - break; - - case 'd': - // debug - debug_level++; - break; - - case 'l': - // list - if (arg) - as -> listfile = arg; - else - as -> listfile = "-"; - break; - - case 'b': - // decb output - as -> outformat = OUTPUT_DECB; - break; - - case 'r': - // raw binary output - as -> outformat = OUTPUT_RAW; - break; - - case 0x100: - // proprietary object format - as -> outformat = OUTPUT_OBJ; - break; - - case 'f': - // output format - if (!strcasecmp(arg, "decb")) - as -> outformat = OUTPUT_DECB; - else if (!strcasecmp(arg, "raw")) - as -> outformat = OUTPUT_RAW; - else if (!strcasecmp(arg, "obj")) - as -> outformat = OUTPUT_OBJ; - else - { - fprintf(stderr, "Invalid output format: %s\n", arg); - exit(1); - } - break; - - case 'p': - // pragmas - p = arg; - pseudo_pragma_real(as, NULL, &p, 2); - if (!p) - { - fprintf(stderr, "Invalid pragma string: %s\n", arg); - exit(1); - } - break; - - case ARGP_KEY_END: - // done; sanity check - if (!as -> outfile) - as -> outfile = "a.out"; - break; - - case ARGP_KEY_ARG: - // non-option arg - if (as -> infile) - argp_usage(state); - as -> infile = arg; - break; - - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - -static struct argp_option options[] = -{ - { "output", 'o', "FILE", 0, - "Output to FILE"}, - { "debug", 'd', 0, 0, - "Set debug mode"}, - { "format", 'f', "TYPE", 0, - "Select output format: decb, raw, obj"}, - { "list", 'l', "FILE", OPTION_ARG_OPTIONAL, - "Generate list [to FILE]"}, - { "decb", 'b', 0, 0, - "Generate DECB .bin format output, equivalent of --format=decb"}, - { "raw", 'r', 0, 0, - "Generate raw binary format output, equivalent of --format=raw"}, - { "obj", 0x100, 0, 0, - "Generate proprietary object file format for later linking, equivalent of --format=obj" }, - { "pragma", 'p', "PRAGMA", 0, - "Set an assembler pragma to any value understood by the \"pragma\" pseudo op"}, - { 0 } -}; - -static struct argp argp = -{ - options, - parse_opts, - "<input file>", - "LWASM, a HD6309 and MC6809 cross-assembler" -}; - -// main function; parse command line, set up assembler state, and run the -// assembler on the first file -int main(int argc, char **argv) -{ - // assembler state - asmstate_t asmstate = { 0 }; - - argp_parse(&argp, argc, argv, 0, 0, &asmstate); - - if (!asmstate.infile) - { - fprintf(stderr, "No input files specified.\n"); - exit(1); - } - - /* pass 1 - collect the symbols and assign addresses where possible */ - /* pass 1 also resolves included files, etc. */ - /* that means files are read exactly once unless included multiple times */ - lwasm_pass1(&asmstate); - - // pass 2: actually generate the code; if any phasing errors appear - // at this stage, we have a bug - lwasm_pass2(&asmstate); - - // now make a pretty listing - lwasm_list(&asmstate); - - // now write the code out to the output file - lwasm_output(&asmstate); - - if (asmstate.errorcount > 0) - exit(1); - - exit(0); -} -
--- a/src/output.c Fri Jan 30 02:55:30 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,419 +0,0 @@ -/* -output.c -Copyright © 2009 William Astle - -This file is part of LWASM. - -LWASM is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - - -Contains the code for actually outputting the assembled code -*/ - -//#include <ctype.h> -#include <errno.h> -#include <stdio.h> -//#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#define __output_c_seen__ -//#include "instab.h" -#include "lwasm.h" -#include "util.h" - -void write_code_raw(asmstate_t *as, FILE *of); -void write_code_decb(asmstate_t *as, FILE *of); -void write_code_rawrel(asmstate_t *as, FILE *of); -void write_code_obj(asmstate_t *as, FILE *of); - -// this prevents warnings about not using the return value of fwrite() -#define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); } while (0) - -void lwasm_output(asmstate_t *as) -{ - FILE *of; - - if (as -> errorcount > 0) - { - fprintf(stderr, "Not doing output due to assembly errors.\n"); - return; - } - - of = fopen(as -> outfile, "wb"); - if (!of) - { - fprintf(stderr, "Cannot open '%s' for output", as -> outfile); - perror(""); - return; - } - - switch (as -> outformat) - { - case OUTPUT_RAW: - write_code_raw(as, of); - break; - - case OUTPUT_DECB: - write_code_decb(as, of); - break; - - case OUTPUT_RAWREL: - write_code_rawrel(as, of); - break; - - case OUTPUT_OBJ: - write_code_obj(as, of); - break; - - default: - fprintf(stderr, "BUG: unrecognized output format when generating output file\n"); - fclose(of); - unlink(as -> outfile); - return; - } - - fclose(of); -} - -/* -rawrel output treats an ORG directive as an offset from the start of the -file. Undefined results will occur if an ORG directive moves the output -pointer backward. This particular implementation uses "fseek" to handle -ORG requests and to skip over RMBs. - -This simple brain damanged method simply does an fseek before outputting -each instruction. -*/ -void write_code_rawrel(asmstate_t *as, FILE *of) -{ - lwasm_line_t *cl; - - for (cl = as -> lineshead; cl; cl = cl -> next) - { - if (cl -> codelen == 0) - continue; - - fseek(of, cl -> codeaddr, SEEK_SET); - writebytes(cl -> bytes, cl -> codelen, 1, of); - } -} - -/* -raw merely writes all the bytes directly to the file as is. ORG is just a -reference for the assembler to handle absolute references. Multiple ORG -statements will produce mostly useless results -*/ -void write_code_raw(asmstate_t *as, FILE *of) -{ - lwasm_line_t *cl; - - for (cl = as -> lineshead; cl; cl = cl -> next) - { - if (cl -> nocodelen) - { - int i; - for (i = 0; i < cl -> nocodelen; i++) - writebytes("\0", 1, 1, of); - continue; - } - writebytes(cl -> bytes, cl -> codelen, 1, of); - } -} - -void write_code_decb(asmstate_t *as, FILE *of) -{ - long preambloc; - lwasm_line_t *cl; - int blocklen = -1; - int nextcalc = -1; - unsigned char outbuf[5]; - - for (cl = as -> lineshead; cl; cl = cl -> next) - { - if (cl -> nocodelen) - continue; - if (cl -> codeaddr != nextcalc && cl -> codelen > 0) - { - // need preamble here - if (blocklen > 0) - { - // update previous preamble if needed - fseek(of, preambloc, SEEK_SET); - outbuf[0] = (blocklen >> 8) & 0xFF; - outbuf[1] = blocklen & 0xFF; - writebytes(outbuf, 2, 1, of); - fseek(of, 0, SEEK_END); - } - blocklen = 0; - nextcalc = cl -> codeaddr; - outbuf[0] = 0x00; - outbuf[1] = 0x00; - outbuf[2] = 0x00; - outbuf[3] = (nextcalc >> 8) & 0xFF; - outbuf[4] = nextcalc & 0xFF; - preambloc = ftell(of) + 1; - writebytes(outbuf, 5, 1, of); - } - nextcalc += cl -> codelen; - writebytes(cl -> bytes, cl -> codelen, 1, of); - blocklen += cl -> codelen; - } - if (blocklen > 0) - { - fseek(of, preambloc, SEEK_SET); - outbuf[0] = (blocklen >> 8) & 0xFF; - outbuf[1] = blocklen & 0xFF; - writebytes(outbuf, 2, 1, of); - fseek(of, 0, SEEK_END); - } - - // now write postamble - outbuf[0] = 0xFF; - outbuf[1] = 0x00; - outbuf[2] = 0x00; - outbuf[3] = (as -> execaddr >> 8) & 0xFF; - outbuf[4] = (as -> execaddr) & 0xFF; - writebytes(outbuf, 5, 1, of); -} - -void write_code_obj_sbadd(sectiontab_t *s, unsigned char b) -{ - if (s -> oblen >= s -> obsize) - { - s -> obytes = lwasm_realloc(s -> obytes, s -> obsize + 128); - s -> obsize += 128; - } - s -> obytes[s -> oblen] = b; - s -> oblen += 1; -} - -void write_code_obj(asmstate_t *as, FILE *of) -{ - lwasm_line_t *l; - sectiontab_t *s; - lwasm_symbol_ent_t *se; - export_list_t *ex; - section_reloc_list_t *re; - lwasm_expr_stack_node_t *sn; - - int i; - unsigned char buf[16]; - - // output the magic number and file header - // the 8 is NOT an error - writebytes("LWOBJ16", 8, 1, of); - - // run through the entire system and build the byte streams for each - // section; at the same time, generate a list of "local" symbols to - // output for each section - // NOTE: for "local" symbols, we will append \x01 and the ascii string - // of the context identifier (so sym in context 1 would be "sym\x011" - // we can do this because the linker can handle symbols with any - // character other than NUL. - // also we will generate a list of incomplete references for each - // section along with the actual definition that will be output - - // once all this information is generated, we will output each section - // to the file - - // NOTE: we build everything in memory then output it because the - // assembler accepts multiple instances of the same section but the - // linker expects only one instance of each section in the object file - // so we need to collect all the various pieces of a section together - // (also, the assembler treated multiple instances of the same section - // as continuations of previous sections so we would need to collect - // them together anyway. - - for (l = as -> lineshead; l; l = l -> next) - { - if (l -> sect) - { - // we're in a section - need to output some bytes - for (i = 0; i < l -> codelen; i++) - write_code_obj_sbadd(l -> sect, l -> bytes[i]); - for (i = 0; i < l -> nocodelen; i++) - write_code_obj_sbadd(l -> sect, 0); - - // do we have a "relocation"? If so, add a reference to the - // relocation table - if (l -> relocoff >= 0) - { - // build the relocation reference for the linker - re = lwasm_alloc(sizeof(section_reloc_list_t)); - re -> next = l -> sect -> rl; - l -> sect -> rl = re; - - re -> offset = l -> codeaddr + l -> relocoff; - re -> expr = l -> exprs[0]; - re -> context = l -> context; - } - } - } - - // run through the sections - for (s = as -> sections; s; s = s -> next) - { - // write the name - writebytes(s -> name, strlen(s -> name) + 1, 1, of); - - // write the flags - if (s -> flags & SECTION_BSS) - writebytes("\x01", 1, 1, of); - - // indicate end of flags - the "" is NOT an error - writebytes("", 1, 1, of); - - - // now the local symbols - for (se = as -> symhead; se; se = se -> next) - { - // ignore symbols not in this section - if (se -> sect != s) - continue; - - if (se -> flags & SYMBOL_SET) - continue; - - if (se -> flags & SYMBOL_EXTERN) - continue; - - writebytes(se -> sym, strlen(se -> sym), 1, of); - if (se -> context >= 0) - { - writebytes("\x01", 1, 1, of); - sprintf(buf, "%d", se -> context); - writebytes(buf, strlen(buf), 1, of); - } - // the "" is NOT an error - writebytes("", 1, 1, of); - - // write the address - buf[0] = (se -> value >> 8) & 0xff; - buf[1] = se -> value & 0xff; - writebytes(buf, 2, 1, of); - } - // flag end of local symbol table - "" is NOT an error - writebytes("", 1, 1, of); - - // now the exports - for (ex = s -> exports; ex; ex = ex -> next) - { - writebytes(ex -> sym, strlen(ex -> sym) + 1, 1, of); - buf[0] = (ex -> offset >> 8) & 0xff; - buf[1] = ex -> offset & 0xff; - writebytes(buf, 2, 1, of); - } - - // flag end of exported symbols - "" is NOT an error - writebytes("", 1, 1, of); - - // now output the "incomplete references" - // this being the most complex bit - for (re = s -> rl; re; re = re -> next) - { - if (re -> expr == NULL) - { - // this is an error but we'll simply ignore it - // and not output this expression - continue; - } - - // work through each term in the expression and output - // the proper equivalent to the object file - for (sn = re -> expr -> head; sn; sn = sn -> next) - { - switch (sn -> term -> term_type) - { - case LWASM_TERM_OPER: - buf[0] = 0x04; - buf[1] = sn -> term -> value; - writebytes(buf, 2, 1, of); - break; - - case LWASM_TERM_INT: - buf[0] = 0x01; - buf[1] = (sn -> term -> value >> 8) & 0xff; - buf[2] = sn -> term -> value & 0xff; - writebytes(buf, 3, 1, of); - break; - - case LWASM_TERM_SECBASE: - writebytes("\x05", 1, 1, of); - break; - - case LWASM_TERM_SYM: - // now for the ugly part - resolve a symbol reference - // and determine whether it's internal, external, or - // a section base - se = lwasm_find_symbol(as, sn -> term -> symbol, re -> context); - if (!se) - se = lwasm_find_symbol(as, sn -> term -> symbol, -1); - if (!se || se -> flags & SYMBOL_EXTERN) - { - // not found - assume external reference - // found but flagged external - handle it - writebytes("\x02", 1, 1, of); - writebytes(se -> sym, strlen(se -> sym) + 1, 1, of); - break; - } - // a local symbol reference here - writebytes("\x03", 1, 1, of); - writebytes(se -> sym, strlen(se -> sym), 1, of); - if (se -> context >= 0) - { - writebytes("\x01", 1, 1, of); - sprintf(buf, "%d", se -> context); - writebytes(buf, strlen(buf), 1, of); - } - writebytes("", 1, 1, of); - break; - - default: - // unrecognized term type - replace with integer 0 - buf[0] = 0x01; - buf[1] = 0x00; - buf[2] = 0x00; - writebytes(buf, 3, 1, of); - break; - } - } - - // flag end of expressions - writebytes("", 1, 1, of); - - // write the offset - buf[0] = (re -> offset >> 8) & 0xff; - buf[1] = re -> offset & 0xff; - writebytes(buf, 2, 1, of); - } - // flag end of incomplete references list - writebytes("", 1, 1, of); - - // now blast out the code - - // length - buf[0] = s -> oblen >> 8 & 0xff; - buf[1] = s -> oblen & 0xff; - writebytes(buf, 2, 1, of); - - if (!(s -> flags & SECTION_BSS)) - { - writebytes(s -> obytes, s -> oblen, 1, of); - } - } - - // flag no more sections - // the "" is NOT an error - writebytes("", 1, 1, of); -}
--- a/src/pragma.c Fri Jan 30 02:55:30 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* -pragma.c -Copyright © 2008 William Astle - -This file is part of LWASM. - -LWASM is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - - -This file contains stuff associated with lwasm specific strangeness -*/ - -#include <ctype.h> -#include <stdlib.h> -#include <string.h> -#include "lwasm.h" -#include "instab.h" - -/* -A pragma is a means of controlling code generation. - -The pseudo op "*pragma" which will be treated as a comment by an assembler -that doesn't recognize it and thus will not cause assembly errors. This is -the preferred way of flagging a pragma if it will not cause incorrect -execution of the program. - -The pseudo op "pragma" which will cause an error on an assembler that does -not understand it. - -In the case of "*pragma", unrecognized pragmas MUST be silently ignored. In -the case of "pragma", unrecognized pragmas should raise an error. - -LWASM understands the following pragmas: - -index0tonone -noindex0tonone - -When set (index0tonone), an expression that evaluates to 0, other than a -bare constant, in a <offset>,r operand will cause the code for ",r" to be -emitted rather than "0,r". If not set (noindex0tonone), the "0,r" output -will be emitted. The default is to perform the optimization. - -This particular optimization will save a cycle for a direct operation. For -an indirect operation, however, it will save several cycles and a program byte -which may be very useful. -*/ - -void pseudo_pragma_real(asmstate_t *as, lwasm_line_t *cl, char **optr, int error) -{ - char pragma[128]; - int c = 0; - - while (isspace(**optr)) - (*optr)++; - - while (c < 127 && **optr && !isspace(**optr)) - { - pragma[c++] = **optr; - (*optr)++; - } - - if (c == 0 || (**optr && !isspace(**optr))) - { - if (error) - { - register_error(as, cl, 1, "Unrecognized pragma"); - } - if (error == 2) - { - *optr = NULL; - } - return; - } - pragma[c] = 0; - if (!strcasecmp(pragma, "noindex0tonone")) - { - as -> pragmas |= PRAGMA_NOINDEX0TONONE; - } - else if (!strcasecmp(pragma, "index0tonone")) - { - as -> pragmas &= ~PRAGMA_NOINDEX0TONONE; - } - else if (!strcasecmp(pragma, "undefextern")) - { - as -> pragmas |= PRAGMA_UNDEFEXTERN; - } - else if (!strcasecmp(pragma, "noundefextern")) - { - as -> pragmas &= ~PRAGMA_UNDEFEXTERN; - } - else - { - if (error) - { - register_error(as, cl, 1, "Unrecognized pragma"); - if (error == 2) - { - *optr = NULL; - } - } - } -} - -OPFUNC(pseudo_pragma) -{ - pseudo_pragma_real(as, l, p, 1); -} - -OPFUNC(pseudo_starpragma) -{ - pseudo_pragma_real(as, l, p, 0); -}
--- a/src/pseudo.c Fri Jan 30 02:55:30 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,967 +0,0 @@ -/* -pseudo.c -Copyright © 2009 William Astle - -This file is part of LWASM. - -LWASM is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see <http://www.gnu.org/licenses/>. - - -This file implements the various pseudo operations. -*/ - -#include <stdlib.h> -#include <string.h> -#include "lwasm.h" -#include "instab.h" -#include "expr.h" -#include "util.h" - -extern int lwasm_read_file(asmstate_t *as, const char *filename); - -OPFUNC(pseudo_org) -{ - int v, r; - - if (as -> csect) - { - register_error(as, l, 1, "ORG not allowed within sections"); - return; - } - - if (as -> passnum != 1) - { - // org is not needed to be processed on pass 2 - // this will prevent phasing errors for forward references that - // resolve on the second pass - // we saved the org address in l -> codeaddr on pass 1 - as -> addr = l -> codeaddr; - return; - } - - if (l -> sym) - { - register_error(as, l, 1, "No symbol allowed with ORG"); - } - - r = lwasm_expr_result2(as, l, p, EXPR_PASS1CONST, &v, 0); - if (r != 0) - return; - l -> codeaddr = v; - l -> addrset = 1; - as -> addr = v; -} - -/* -The operand for include is a string optionally enclosed in " -*/ -OPFUNC(pseudo_include) -{ - int v1; - char *fn; - - // only include files on pass 1 - // but make sure local include context is right - // for the next line... - if (as -> passnum != 1) - { - as -> context = lwasm_next_context(as); - return; - } - - while (**p && isspace(**p)) - (*p)++; - - if (!**p) - { - register_error(as, l, 1, "Bad file name"); - return; - } - - if (**p == '"') - { - // search for ending " - (*p)++; - for (v1 = 0; *((*p)+v1) && *((*p)+v1) != '"'; v1++) - /* do nothing */ ; - if (*((*p)+v1) != '"') - { - register_error(as, l, 1, "Bad file name"); - return; - } - } - else - { - // search for a space type character - for (v1 = 0; *((*p)+v1) && !isspace(*((*p)+v1)); v1++) - ; - } - - fn = lwasm_alloc(v1 + 1); - memcpy(fn, *p, v1); - fn[v1] = '\0'; - - // end local label context on include - as -> context = lwasm_next_context(as); - if (lwasm_read_file(as, fn) < 0) - { - register_error(as, l, 1, "File include error (%s)", fn); - } - lwasm_free(fn); -} - -OPFUNC(pseudo_rmb) -{ - int r, v; - - if (as -> passnum == 2) - { - as -> addr += l -> nocodelen; - return; - } - r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, -1); - if (r != 0) - return; - l -> nocodelen = v; - as -> addr += v; -} - -OPFUNC(pseudo_rmd) -{ - int r, v; - - if (as -> passnum == 2) - { - as -> addr += l -> nocodelen; - return; - } - r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); - if (r != 0) - return; - v *= 2; - l -> nocodelen = v; - as -> addr += v; -} - -OPFUNC(pseudo_rmq) -{ - int r, v; - - if (as -> passnum == 2) - { - as -> addr += l -> nocodelen; - return; - } - r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); - if (r != 0) - return; - v *= 4; - l -> nocodelen = v; - as -> addr += v; -} - -OPFUNC(pseudo_zmb) -{ - int r, v; - - r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); - if (r != 0) - return; - while (v--) - lwasm_emit(as, l, 0); -} - -OPFUNC(pseudo_zmd) -{ - int r, v; - - r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); - if (r != 0) - return; - v *= 2; - while (v--) - lwasm_emit(as, l, 0); -} - -OPFUNC(pseudo_zmq) -{ - int r, v; - - r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); - if (r != 0) - return; - v *= 4; - while (v--) - lwasm_emit(as, l, 0); -} - -OPFUNC(pseudo_end) -{ - int r, v; - lwasm_expr_stack_t *s; - - - as -> endseen = 1; - - // address only matters for DECB output - if (as -> outformat != OUTPUT_DECB) - return; - - r = lwasm_expr_result2(as, l, p, 0, &v, 0); - if (r != 0) - { - register_error(as, l, 2, "Bad operand"); - } - - v = v & 0xffff; - if (as -> passnum == 2) - { - as -> execaddr = v; - l -> symaddr = v; - l -> addrset = 2; - } -} - - -OPFUNC(pseudo_align) -{ - int cn; - int r, v; - - if (as -> passnum == 2) - { - while (as -> addr < l -> symaddr) - lwasm_emit(as, l, 0); - return; - } - - r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); - if (r != 0) - { - l -> symaddr = as -> addr; - return; - } - - if (v < 1) - { - register_error(as, l, 1, "Illegal alignment %d", v); - return; - } - - cn = l -> codeaddr % v; - if (cn) - cn = v - cn; - - while (cn--) - { - lwasm_emit(as, l, 0); - } - l -> symaddr = as -> addr; -} - -OPFUNC(pseudo_equ) -{ - int r, v; - - if (l -> sym == NULL) - { - register_error(as, l, 1, "No symbol specified"); - return; - } - - r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); - if (r < 0) - v = 0; - - l -> symaddr = v & 0xFFFF; - l -> addrset = 2; - - // note: we need to do this because the symbol might have resolved - // to a constant! - lwasm_register_symbol(as, l, l -> sym, v, (r > 0 ? SYMBOL_COMPLEX: SYMBOL_NORM) | SYMBOL_FORCE); -} - -OPFUNC(pseudo_set) -{ - int r, v; - - // set MUST run on both passes as the symbol value changes! - - if (l -> sym == NULL) - { - register_error(as, l, 1, "No symbol specified"); - return; - } - - r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); - if (r < 0) - v = 0; - - l -> symaddr = v & 0xFFFF; - l -> addrset = 2; - - lwasm_register_symbol(as, l, l -> sym, v, (r > 0 ? SYMBOL_COMPLEX: SYMBOL_NORM) | SYMBOL_SET); -} - -OPFUNC(pseudo_setdp) -{ - int r, v; - - if (as -> outformat == OUTPUT_OBJ) - { - register_error(as, l, 1, "SETDP not permitted with OBJ target"); - return; - } - - // setdp is needed on both passes; must resolve to a constant on pass 1 - r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0); - if (r != 0) - return; - - if (v < -127 || v > 255) - { - register_error(as, l, 1, "Byte overflow"); - return; - } - - l -> symaddr = v & 0xFF; - l -> addrset = 2; - - as -> dpval = v & 0xFF; -} - -OPFUNC(pseudo_fcc) -{ - int delim = 0; - - delim = **p; - if (!delim) - { - register_error(as, l, 1, "Bad operand"); - return; - } - *p += 1; - while (**p && **p != delim) - { - lwasm_emit(as, l, **p); - (*p)++; - } - if (**p) - (*p)++; -} - - -OPFUNC(pseudo_fcs) -{ - int delim = 0; - - delim = **p; - if (!delim) - { - register_error(as, l, 1, "Bad operand"); - return; - } - *p += 1; - while (**p && **p != delim) - { - if (!*((*p) + 1) || *((*p) + 1) == delim) - lwasm_emit(as, l, **p | 0x80); - else - lwasm_emit(as, l, **p); - (*p)++; - } - if (**p) - (*p)++; -} - -OPFUNC(pseudo_fcn) -{ - int delim = 0; - - delim = **p; - if (!delim) - { - register_error(as, l, 1, "Bad operand"); - return; - } - *p += 1; - while (**p && **p != delim) - { - lwasm_emit(as, l, **p); - (*p)++; - } - if (**p) - (*p)++; - lwasm_emit(as, l, 0); -} - -// FIXME: handle external, etc., references in a useful manner -OPFUNC(pseudo_fcb) -{ - int r, v; - -fcb_again: - r = lwasm_expr_result2(as, l, p, 0, &v, -1); - if (r < 0) - return; - - if (r > 0) - { - register_error(as, l, 2, "Illegal external or inter-segment reference"); - v = 0; - } - - if (v < -127 || v > 255) - { - register_error(as, l, 1, "Byte overflow"); - } - - lwasm_emit(as, l, v); - if (**p == ',') - { - (*p)++; - goto fcb_again; - } -} - -// FIXME: handle external references in an intelligent way -OPFUNC(pseudo_fdb) -{ - int r, v; - int extseen = 0; - char *p1; - -fdb_again: - p1 = *p; - r = lwasm_expr_result2(as, l, p, 0, &v, -1); - if (r < 0) - return; - - if (r > 0 && extseen == 1) - { - register_error(as, l, 2, "Illegal external or inter-segment reference (only 1 per FDB line)"); - v = 0; - } - else if (r > 0) - { - l -> relocoff = as -> addr - l -> codeaddr; - *p = p1; - r = lwasm_expr_result2(as, l, p, 0, &v, 0); - } - - lwasm_emit(as, l, v >> 8); - lwasm_emit(as, l, v & 0xff); - if (**p == ',') - { - (*p)++; - goto fdb_again; - } -} - -// FIXME: handle external references in a sensible way -OPFUNC(pseudo_fqb) -{ - int r, v; - -fqb_again: - r = lwasm_expr_result2(as, l, p, 0, &v, -1); - if (r < 0) - return; - - if (r > 0) - { - register_error(as, l, 2, "Illegal external or inter-segment reference"); - v = 0; - } - - lwasm_emit(as, l, v >> 24); - lwasm_emit(as, l, v >> 16); - lwasm_emit(as, l, v >> 8); - lwasm_emit(as, l, v & 0xff); - if (**p == ',') - { - (*p)++; - goto fqb_again; - } -} - -// don't need to do anything if we are executing one of these -OPFUNC(pseudo_endc) -{ - if (as -> skipcond && !(as -> skipmacro)) - { - as -> skipcount -= 1; - if (as -> skipcount <= 0) - { - as -> skipcond = 0; - } - } - return; -} - -// if "else" executes, we must be going into an "ignore" state -OPFUNC(pseudo_else) -{ - if (as -> skipmacro) - return; - - if (as -> skipcond) - { - if (as -> skipcount == 1) - { - as -> skipcount = 0; - as -> skipcond = 0; - } - return; - } - - as -> skipcond = 1; - as -> skipcount = 1; -} - -OPFUNC(pseudo_ifne) -{ - int v1; - int rval; - - if (as -> skipcond && !(as -> skipmacro)) - { - as -> skipcount++; - return; - } - - rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); - if (rval != 0) - return; - if (!v1) - { - as -> skipcond = 1; - as -> skipcount = 1; - } -} - -OPFUNC(pseudo_ifdef) -{ - lwasm_symbol_ent_t *se; - char *sym; - char *p2; - - if (as -> skipcond && !(as -> skipmacro)) - { - as -> skipcount++; - return; - } - - if (as -> passnum != 1) - { - if (!(l -> fsize)) - { - as -> skipcond = 1; - as -> skipcount = 1; - } - return; - } - - if (!**p) - { - register_error(as, l, 1, "Need symbol name"); - return; - } - - for (p2 = *p; *p2 && !isspace(*p2); p2++) - /* do nothing */ ; - - sym = lwasm_alloc(p2 - *p + 1); - memcpy(sym, *p, p2 - *p); - sym[p2 - *p] = '\0'; - - *p = p2; - - se = lwasm_find_symbol(as, sym, l -> context); - if (!se) - se = lwasm_find_symbol(as, sym, -1); - - lwasm_free(sym); - - if (!se) - { - as -> skipcond = 1; - as -> skipcount = 1; - l -> fsize = 0; - } - else - { - l -> fsize = 1; - } -} - -OPFUNC(pseudo_ifndef) -{ - lwasm_symbol_ent_t *se; - char *sym; - char *p2; - - if (as -> skipcond && !(as -> skipmacro)) - { - as -> skipcount++; - return; - } - - if (as -> passnum != 1) - { - if (l -> fsize) - { - as -> skipcond = 1; - as -> skipcount = 1; - } - return; - } - - if (!**p) - { - register_error(as, l, 1, "Need symbol name"); - return; - } - - for (p2 = *p; *p2 && !isspace(*p2); p2++) - /* do nothing */ ; - - sym = lwasm_alloc(p2 - *p + 1); - memcpy(sym, *p, p2 - *p); - sym[p2 - *p] = '\0'; - - *p = p2; - - se = lwasm_find_symbol(as, sym, l -> context); - if (!se) - se = lwasm_find_symbol(as, sym, -1); - - lwasm_free(sym); - - if (se) - { - as -> skipcond = 1; - as -> skipcount = 1; - l -> fsize = 0; - } - else - { - l -> fsize = 1; - } -} - -OPFUNC(pseudo_ifeq) -{ - int v1; - int rval; - - if (as -> skipcond && !(as -> skipmacro)) - { - as -> skipcount++; - return; - } - - rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); - if (rval != 0) - return; - if (v1) - { - as -> skipcond = 1; - as -> skipcount = 1; - } -} - -OPFUNC(pseudo_iflt) -{ - int v1; - int rval; - - if (as -> skipcond && !(as -> skipmacro)) - { - as -> skipcount++; - return; - } - - rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); - if (rval != 0) - return; - if (v1 >= 0) - { - as -> skipcond = 1; - as -> skipcount = 1; - } -} - -OPFUNC(pseudo_ifle) -{ - int v1; - int rval; - - if (as -> skipcond && !(as -> skipmacro)) - { - as -> skipcount++; - return; - } - - rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); - if (rval != 0) - return; - if (v1 > 0) - { - as -> skipcond = 1; - as -> skipcount = 1; - } -} - -OPFUNC(pseudo_ifgt) -{ - int v1; - int rval; - - if (as -> skipcond && !(as -> skipmacro)) - { - as -> skipcount++; - return; - } - - rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); - if (rval != 0) - return; - if (v1 <= 0) - { - as -> skipcond = 1; - as -> skipcount = 1; - } -} - -OPFUNC(pseudo_ifge) -{ - int v1; - int rval; - - if (as -> skipcond && !(as -> skipmacro)) - { - as -> skipcount++; - return; - } - - rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0); - if (rval != 0) - return; - if (v1 < 0) - { - as -> skipcond = 1; - as -> skipcount = 1; - } -} - -OPFUNC(pseudo_error) -{ - register_error(as, l, 1, "User error: %s", *p); -} - - -OPFUNC(pseudo_section) -{ - sectiontab_t *s; - char *p2; - char *sn; - char *opts; - - - if (as -> outformat != OUTPUT_OBJ) - { - register_error(as, l, 1, "Sections only supported for obj target"); - return; - } - - if (as -> csect) - { - as -> csect -> offset = as -> addr; - as -> csect = NULL; - } - - if (!**p) - { - register_error(as, l, 1, "Need section name"); - return; - } - - for (p2 = *p; *p2 && !isspace(*p2); p2++) - /* do nothing */ ; - - sn = lwasm_alloc(p2 - *p + 1); - memcpy(sn, *p, p2 - *p); - sn[p2 - *p] = '\0'; - - *p = p2; - - opts = strchr(sn, ','); - if (opts) - { - *opts++ = '\0'; - } - - // have we seen the section name already? - for (s = as -> sections; s; s = s -> next) - { - if (!strcmp(s -> name, sn)) - break; - } - - if (s && as -> passnum == 1) - { - lwasm_free(sn); - if (opts) - { - register_error(as, l, 1, "Section options can only be specified the first time"); - return; - } - } - else if (!s) - { - s = lwasm_alloc(sizeof(sectiontab_t)); - s -> name = sn; - s -> offset = 0; - s -> flags = 0; - s -> obytes = NULL; - s -> oblen = 0; - s -> obsize = 0; - s -> rl = NULL; - s -> exports = NULL; - // parse options; only one "bss" - if (opts && as -> passnum == 1) - { - if (!strcasecmp(opts, "bss")) - { - s -> flags = SECTION_BSS; - } - else - { - register_error(as, l, 1, "Unrecognized section option '%s'", opts); - lwasm_free(s -> name); - lwasm_free(s); - return; - } - } - - s -> next = as -> sections; - as -> sections = s; - } - as -> addr = s -> offset; - as -> csect = s; - as -> context = lwasm_next_context(as); -} - -OPFUNC(pseudo_endsection) -{ - if (as -> outformat != OUTPUT_OBJ) - { - register_error(as, l, 1, "Sections only supported for obj target"); - return; - } - - if (!(as -> csect)) - { - register_error(as, l, 1, "ENDSECTION when not in a section"); - return; - } - - as -> csect -> offset = as -> addr; - as -> addr = 0; - as -> csect = 0; - as -> context = lwasm_next_context(as); -} - -OPFUNC(pseudo_extern) -{ - if (as -> passnum != 1) - return; - - if (as -> outformat != OUTPUT_OBJ) - { - register_error(as, l, 1, "External references only supported for obj target"); - return; - } - - if (as -> csect) - { - register_error(as, l, 1, "Cannot declare external symbols within a section"); - return; - } - - lwasm_register_symbol(as, l, l -> sym, 0, SYMBOL_EXTERN); -} - -OPFUNC(pseudo_export) -{ - lwasm_symbol_ent_t *se; - export_list_t *ex; - - if (as -> outformat != OUTPUT_OBJ) - { - register_error(as, l, 1, "Symbol exports only supported for obj target"); - return; - } - - if (as -> passnum == 1) - return; - - // the symbol better be defined at this point (pass 2) - // local symbols cannot be exported nor can "global" symbols - se = lwasm_find_symbol(as, l -> sym, -1); - if (!se) - { - register_error(as, l, 2, "Exported symbols must be fully defined within a section"); - return; - } - if (se -> sect == NULL) - { - register_error(as, l, 2, "Only non-local symbols within a section can be exported"); - return; - } - - if (se -> flags & SYMBOL_SET) - { - register_error(as, l, 2, "You cannot export symbols defined with SET"); - return; - } - - // if the symbol is not already a simple value, re-evaluate it - // and see if it becomes simple - - - if (se -> flags & SYMBOL_COMPLEX) - { - register_error(as, l, 2, "Exported symbols must be fully resolved on pass 2"); - return; - } - - // search for existing export - for (ex = se -> sect -> exports; ex; ex = ex -> next) - if (!strcmp(l -> sym, ex -> sym)) - break; - if (ex) - { - register_error(as, l, 2, "Symbol %s already exported", l -> sym); - return; - } - - // add an external reference - ex = lwasm_alloc(sizeof(export_list_t)); - ex -> next = se -> sect -> exports; - se -> sect -> exports = ex; - ex -> offset = se -> value; - ex -> sym = lwasm_strdup(se -> sym); -}