# HG changeset patch
# User lost
# Date 1233288115 0
# Node ID 427e268e876b70ebd18a8d96cc31e464220bb197
# Parent f0881c115010675464c24389423e60e269f049ee
renamed src to lwasm to better reflect its purpose
diff -r f0881c115010 -r 427e268e876b Makefile.am
--- 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
diff -r f0881c115010 -r 427e268e876b configure.ac
--- 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
])
diff -r f0881c115010 -r 427e268e876b doc/Makefile.am
--- 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
diff -r f0881c115010 -r 427e268e876b doc/README
--- 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
diff -r f0881c115010 -r 427e268e876b lwasm/Makefile.am
--- /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
diff -r f0881c115010 -r 427e268e876b lwasm/expr.c
--- /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 .
+*/
+
+/*
+This file contains the actual expression evaluator
+*/
+
+#define __expr_c_seen__
+
+#include
+#include
+#include
+
+#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;
+}
diff -r f0881c115010 -r 427e268e876b lwasm/expr.h
--- /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 .
+*/
+
+/*
+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__
diff -r f0881c115010 -r 427e268e876b lwasm/insn_bitbit.c
--- /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 .
+*/
+
+/*
+for handling inherent mode instructions
+*/
+
+#define __insn_bitbit_c_seen__
+
+#include
+
+#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);
+}
diff -r f0881c115010 -r 427e268e876b lwasm/insn_gen.c
--- /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 .
+
+Contains code for parsing general addressing modes (IMM+DIR+EXT+IND)
+*/
+
+#include
+#include
+
+#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");
+}
diff -r f0881c115010 -r 427e268e876b lwasm/insn_indexed.c
--- /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 .
+*/
+
+/*
+for handling indexed mode instructions
+*/
+
+#define __insn_indexed_c_seen__
+
+#include
+#include
+
+#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);
+}
diff -r f0881c115010 -r 427e268e876b lwasm/insn_inh.c
--- /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 .
+*/
+
+/*
+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]);
+}
diff -r f0881c115010 -r 427e268e876b lwasm/insn_logicmem.c
--- /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 .
+
+Contains code for handling logic/mem instructions
+*/
+
+#include
+#include
+#include
+
+#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);
+}
diff -r f0881c115010 -r 427e268e876b lwasm/insn_rel.c
--- /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 .
+*/
+
+/*
+for handling relative mode instructions
+*/
+
+#define __insn_rel_c_seen__
+
+#include
+
+#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);
+}
diff -r f0881c115010 -r 427e268e876b lwasm/insn_rlist.c
--- /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 .
+*/
+
+/*
+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);
+}
diff -r f0881c115010 -r 427e268e876b lwasm/insn_rtor.c
--- /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 .
+*/
+
+/*
+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);
+}
diff -r f0881c115010 -r 427e268e876b lwasm/insn_tfm.c
--- /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 .
+*/
+
+/*
+for handling inherent mode instructions
+*/
+
+#define __insn_tfm_c_seen__
+
+#include
+#include
+
+#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);
+}
diff -r f0881c115010 -r 427e268e876b lwasm/instab.c
--- /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 .
+
+
+Contains the instruction table for assembling code
+*/
+
+#include
+
+#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 }
+};
diff -r f0881c115010 -r 427e268e876b lwasm/instab.h
--- /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 .
+
+
+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__
diff -r f0881c115010 -r 427e268e876b lwasm/list.c
--- /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 .
+
+Contains code for displaying a program listings, etc.
+*/
+
+#define __list_c_seen__
+
+#include
+#include
+
+#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);
+}
diff -r f0881c115010 -r 427e268e876b lwasm/lwasm.c
--- /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 .
+
+
+Contains random functions used by the assembler
+*/
+
+#define __lwasm_c_seen__
+
+#include
+#include
+#include
+
+#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;
+}
+
diff -r f0881c115010 -r 427e268e876b lwasm/lwasm.h
--- /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 .
+
+Contains the main defs used by the assembler
+*/
+
+
+#ifndef __lwasm_h_seen__
+#define __lwasm_h_seen__
+
+#include
+#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__
diff -r f0881c115010 -r 427e268e876b lwasm/lwval.c
--- /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 .
+*/
+
+/*
+This file contains implementations associated with the expression evaluator
+used by LWASM.
+
+*/
+
+#include
+
+#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)
+{
+}
diff -r f0881c115010 -r 427e268e876b lwasm/lwval.h
--- /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 .
+*/
+
+/*
+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 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 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__
diff -r f0881c115010 -r 427e268e876b lwasm/macro.c
--- /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 .
+
+Contains stuff associated with macro processing
+*/
+
+#include
+#include
+#include
+#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;
+}
diff -r f0881c115010 -r 427e268e876b lwasm/main.c
--- /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 .
+
+
+Implements the program startup code
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+#include
+#include
+#include
+
+#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,
+ "",
+ "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);
+}
+
diff -r f0881c115010 -r 427e268e876b lwasm/output.c
--- /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 .
+
+
+Contains the code for actually outputting the assembled code
+*/
+
+//#include
+#include
+#include
+//#include
+#include
+#include
+#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);
+}
diff -r f0881c115010 -r 427e268e876b lwasm/parse.c
--- /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 .
+*/
+
+/*
+Contains the general parser
+*/
+
+#define __parse_c_seen__
+
+#include
+#include
+
+#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);
+}
diff -r f0881c115010 -r 427e268e876b lwasm/pass1.c
--- /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 .
+
+
+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:
+
+
+
+
+
+
+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
+#include
+#include
+
+#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);
+ }
+
+}
diff -r f0881c115010 -r 427e268e876b lwasm/pass2.c
--- /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 .
+
+
+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);
+ }
+}
diff -r f0881c115010 -r 427e268e876b lwasm/pragma.c
--- /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 .
+
+
+This file contains stuff associated with lwasm specific strangeness
+*/
+
+#include
+#include
+#include
+#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 ,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);
+}
diff -r f0881c115010 -r 427e268e876b lwasm/pseudo.c
--- /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 .
+
+
+This file implements the various pseudo operations.
+*/
+
+#include
+#include
+#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);
+}
diff -r f0881c115010 -r 427e268e876b lwasm/symbol.c
--- /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 .
+*/
+
+/*
+for handling the symbol table
+*/
+
+#define __symbol_c_seen__
+
+#include
+
+#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, "");
+ }
+ 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);
+ }
+}
diff -r f0881c115010 -r 427e268e876b lwasm/util.c
--- /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 .
+*/
+
+/*
+Utility functions
+*/
+
+#define __util_c_seen__
+
+#include
+#include
+#include
+#include
+
+#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;
+}
diff -r f0881c115010 -r 427e268e876b lwasm/util.h
--- /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 .
+*/
+
+/*
+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__
diff -r f0881c115010 -r 427e268e876b src/Makefile.am
--- 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
diff -r f0881c115010 -r 427e268e876b src/insn_gen.c
--- 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 .
-
-Contains code for parsing general addressing modes (IMM+DIR+EXT+IND)
-*/
-
-#include
-#include
-
-#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");
-}
diff -r f0881c115010 -r 427e268e876b src/instab.c
--- 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 .
-
-
-Contains the instruction table for assembling code
-*/
-
-#include
-
-#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 }
-};
diff -r f0881c115010 -r 427e268e876b src/instab.h
--- 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 .
-
-
-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__
diff -r f0881c115010 -r 427e268e876b src/list.c
--- 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 .
-
-Contains code for displaying a program listings, etc.
-*/
-
-#define __list_c_seen__
-
-#include
-#include
-
-#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);
-}
diff -r f0881c115010 -r 427e268e876b src/lwasm.c
--- 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 .
-
-
-Contains random functions used by the assembler
-*/
-
-#define __lwasm_c_seen__
-
-#include
-#include
-#include
-
-#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;
-}
-
diff -r f0881c115010 -r 427e268e876b src/lwasm.h
--- 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 .
-
-Contains the main defs used by the assembler
-*/
-
-
-#ifndef __lwasm_h_seen__
-#define __lwasm_h_seen__
-
-#include
-#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__
diff -r f0881c115010 -r 427e268e876b src/macro.c
--- 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 .
-
-Contains stuff associated with macro processing
-*/
-
-#include
-#include
-#include
-#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;
-}
diff -r f0881c115010 -r 427e268e876b src/main.c
--- 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 .
-
-
-Implements the program startup code
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include
-#include
-#include
-#include
-
-#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,
- "",
- "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);
-}
-
diff -r f0881c115010 -r 427e268e876b src/output.c
--- 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 .
-
-
-Contains the code for actually outputting the assembled code
-*/
-
-//#include
-#include
-#include
-//#include
-#include
-#include
-#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);
-}
diff -r f0881c115010 -r 427e268e876b src/pragma.c
--- 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 .
-
-
-This file contains stuff associated with lwasm specific strangeness
-*/
-
-#include
-#include
-#include
-#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 ,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);
-}
diff -r f0881c115010 -r 427e268e876b src/pseudo.c
--- 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 .
-
-
-This file implements the various pseudo operations.
-*/
-
-#include
-#include
-#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);
-}