OpenCores
URL https://opencores.org/ocsvn/c16/c16/trunk

Subversion Repositories c16

[/] [c16/] [trunk/] [asm/] [assembler.bison] - Rev 28

Go to most recent revision | Compare with Previous | Blame | View Log


%{

#include <stdio.h>
#include <assert.h>

extern int yylex();
extern int yyparse();
extern int yyerror(const char *);
extern FILE * out;
extern FILE * list;
extern FILE * sym;
extern FILE * ihx;
static void write_intel_hex(FILE * out);

int PC          = 0;
int reloc_start = 0;   // first PC
int reloc_last  = 0;   // last PC
int reloc_end   = 0;   // end of reloc

char memory[0x10000];
unsigned int mem_idx = 0;

enum ExHow { EX_NAME, EX_NUMBER,
             EX_ADD, EX_SUB, EX_MULT, EX_DIV, EX_MOD };

class Expression
{

public:
   Expression(const char * n)
   : how(EX_NAME),
     ex(0),
     name(n),
     number(0)
     {};

   Expression(int n)
   : how(EX_NUMBER),
     ex(0),
     name(0),
     number(n)
     {};

   Expression(Expression * e, ExHow h, const char * n)
   : how(h),
     ex(e),
     name(n),
     number(0)
     {};

   Expression(Expression * e, ExHow h, int n)
   : how(h),
     ex(e),
     name(0),
     number(n)
     {};

   int GetValue() const;
   int ListBase() const;
   bool UsesName() const
      {
        if (how == EX_NAME)     return true;
        if (how == EX_NUMBER)   return false;
        assert(ex);
        return ex->UsesName();
      }


private:
   const ExHow  how;
   Expression * ex;
   const char * name;
   int          number;
};

enum OP_BASE
{
   EXPR,
   REG_RR, REG_RU, REG_RS, REG_R,
   REG_LL, REG_LU, REG_LS, REG_L,
   REG_SP,
   COND_Z,
   COND_NZ
};

enum OP_ATTR
{
   ATT_NONE,
   ATT_POSTINC,
   ATT_PREDEC,
   ATT_OFFSET,
   ATT_CONTENT,
   ATT_PORT,
   ATT_ADDR,
   ATT_IMM,
};

enum OP_HOW
{
   H_NONE     = 0, // unique opcode
   H_BYTE     = 1,
   H_PORT     = 2, //                       #byte
   H_WORD     = 3, //                                      #word
   H_sBW      = 4, // signed                #byte (01X) or #word (10X)
   H_uBW      = 5, // unsigned              #byte (01X) or #word (10X)
   H_sQBW     = 6, // signed quick       or #byte (01X) or #word (10X)
   H_uQBW     = 7, // unsigned quick     or #byte (01X) or #word (10X)
};

class Operand
{
public:
   Operand(OP_BASE b, const char * txt)
   : base(b), attr(ATT_NONE), expr(0), op_text(txt), offset(0) {};

   Operand(Expression * ex)
   : base(EXPR), attr(ATT_NONE), expr(ex), op_text(0), offset(0) {};

   Operand * PostInc()
      {
        assert(attr == ATT_NONE);
        attr = ATT_POSTINC;
        return this;
      };

   Operand * PreDec()
      {
        assert(attr == ATT_NONE);
        attr = ATT_PREDEC;
        return this;
      };

   Operand * Content()
      {
        assert(base == REG_RR || base == REG_LL);
        assert(attr == ATT_NONE);
        attr = ATT_CONTENT;
        return this;
      };

   Operand * Offset(Operand * offs)
      {
        assert(base != EXPR);
        assert(attr == ATT_NONE);
        attr = ATT_OFFSET;

        assert(offs->base == EXPR);
        assert(offs->attr == ATT_NONE);
        assert(offset == 0);
        offset = offs;
        return this;
      };

   Operand * Port()
      {
        assert(base == EXPR);
        assert(attr == ATT_NONE);
        attr = ATT_PORT;
        return this;
      };

   Operand * AbsAddr()
      {
        assert(base == EXPR);
        assert(attr == ATT_NONE);
        attr = ATT_ADDR;
        return this;
      };

   Operand * Immediate()
     {
        assert(base == EXPR);
        assert(attr == ATT_NONE);
        attr = ATT_IMM;
        return this;
     };

   int  GetLength(OP_HOW how);
   int  GetValue();
   int  ListHex(OP_HOW how);
   int  List(OP_HOW how);
   int  ListBase(OP_HOW how);

private:
   OP_BASE      base;
   OP_ATTR      attr;
   Operand    * offset;
   const char * op_text;   // scanned text
   Expression * expr;
};

class Opcode
{
public:
   Opcode(OP_HOW how, unsigned int opc, const char * txt,
          Operand * op1 = 0, Operand * op2 = 0)
   : op_how(how),
     op_code(opc),
     op_text(txt),
     op_1(op1),
     op_2(op2),
     reloc(reloc_end) {};

   int GetLength() const;
   int GetOpcode(int & len) const;
   int List(int pc);
   void Error() const;

private:
   OP_HOW        op_how;
   unsigned char op_code;
   const char  * op_text;   // opcode text
   Operand     * op_1;    // oerand 1
   Operand     * op_2;    // oerand 2
   bool          reloc;   // true if relocated
};

int Reloc(bool rloc, int value)
{
  if (!rloc)   return value;
   return value + reloc_end - reloc_last;
}

class Symbol
{
public:
   static void Add(const char * id, Expression * ex, bool lab, bool reloc);
   static void ListNonlabels();
   static int GetValue(const char * id);
   static void Reset()   { current = symbols; };
   static void PrintSymbols();
   static void Advance(int pc);

private:
   Symbol(const char * id, Expression * ex, bool lab, bool rloc)
   : identifier(id),
     expr(ex),
     label(lab),
     reloc(rloc),
     tail(0) {};

   const char * identifier;
   Expression * expr;
   Symbol     * tail;
   bool         label;   // true if label
   bool         reloc;   // true if relocated

   static Symbol * symbols;
   static Symbol * current;
};

class Line
{
public:
   static void Add(Opcode * opc);
   static void List();

private:
   Line(Opcode * opc)
   : opcode(opc),
     pc(PC),
     tail(0)
     {};

   int      pc;
   Opcode * opcode;
   Line   * tail;

   static Line * first;
   static Line * last;
};

%}

%token  _BYTE   _WORD   _OFFSET INT     IDENT   EOL     EOFILE  ERROR
        _LL     _L      _LS     _LU     _RR     _R      _RS     _RU
        _RRZ    _RRNZ   _SP     _EXTERN _STATIC

        ADD     AND     ASR     CALL    CLRB    CLRW    DI      DIV_IS
        DIV_IU  EI      HALT    IN      JMP     LNOT    LEA     LSL
        LSR     MOVE    MD_STP  MD_FIN  MOD_FIN MUL_IS  MUL_IU  NEG
        NOP     NOT     OUT     OR      RET     RETI    SEQ     SGE
        SGT     SLE     SLT     SNE     SHS     SHI     SLS     SLO
        SUB     XOR

%start  all

%union  {       int          _num;
                const char * _txt;
                Opcode     * _opcode;
                Operand    * _operand;
                Expression * _expression;
        }

%type   <_num>  INT
%type   <_txt>
        IDENT   _BYTE   _WORD
        _LL     _LU     _LS     _L      _RR     _RU     _RS     _R
        _RRZ    _RRNZ   _SP

        ADD     AND     ASR     CALL    CLRB    CLRW    DI      DIV_IS
        DIV_IU  EI      HALT    IN      JMP     LNOT    LEA     LSL
        LSR     MOVE    MD_STP  MD_FIN  MOD_FIN MUL_IS  MUL_IU  NEG
        NOP     NOT     OUT     OR      RET     RETI    SEQ     SGE
        SGT     SLE     SLT     SNE     SHS     SHI     SLS     SLO
        SUB     XOR

%type   <_opcode>       opcode  rest    line
%type   <_expression>   expr
%type   <_operand>
        value
        imm
        cRR RR RU RS R dRR RRi
        cLL LL LU LS L dLL LLi
        SP dSP SPi oSP
        RRZ RRNZ
        port addr

%%

all     : lines EOFILE
          {
            reloc_last = PC;
            Symbol::ListNonlabels();
            Line::List();
            Symbol::PrintSymbols();
            fwrite(memory, 1, mem_idx, out);
            write_intel_hex(ihx);
            return 0;
          }
        ;

lines
        : line                  { if ($1)   Line::Add($1); }
        | lines line            { if ($2)   Line::Add($2); }
        ;

line
        :            EOL        { $$ =  0; }
        | label      EOL        { $$ =  0; }
        |       rest EOL        { $$ = $1; }
        | label rest EOL        { $$ = $2; }
        ;

label   : IDENT ':'
          { Symbol::Add($1, new Expression(PC), true, reloc_end); }
        ;

rest
        : IDENT '='  expr       { $$ = 0;   Symbol::Add($1, $3, false, false); }
        | _EXTERN IDENT         { $$ = 0;   }
        | _STATIC IDENT         { $$ = 0;   }
        | _OFFSET    expr       { $$ = 0;   reloc_end = $2->GetValue();
                                  reloc_start = PC;  }
        | opcode                { $$ = $1 }
        ;

expr
        : INT                   { $$ = new Expression($1);               }
        | IDENT                 { $$ = new Expression($1);               }
        | expr '+' INT          { $$ = new Expression($1, EX_ADD,  $3);  }
        | expr '-' INT          { $$ = new Expression($1, EX_SUB,  $3);  }
        | expr '*' INT          { $$ = new Expression($1, EX_MULT, $3);  }
        | expr '/' INT          { $$ = new Expression($1, EX_DIV,  $3);  }
        | expr '%' INT          { $$ = new Expression($1, EX_MOD,  $3);  }
        | expr '+' IDENT        { $$ = new Expression($1, EX_ADD,  $3);  }
        | expr '-' IDENT        { $$ = new Expression($1, EX_SUB,  $3);  }
        | expr '*' IDENT        { $$ = new Expression($1, EX_MULT, $3); }
        | expr '/' IDENT        { $$ = new Expression($1, EX_DIV,  $3);  }
        | expr '%' IDENT        { $$ = new Expression($1, EX_MOD,  $3);  }
        ;

value
        : expr                  { $$ = new Operand($1); }
        ;

imm
        :  '#' value            { $$ = $2->Immediate(); }
        ;

RR      : _RR                   { $$ = new Operand(REG_RR, $1); }       ;
RU      : _RU                   { $$ = new Operand(REG_RU, $1); }       ;
RS      : _RS                   { $$ = new Operand(REG_RS, $1); }       ;
R       : _R                    { $$ = new Operand(REG_R,  $1); }       ;
cRR     : '(' RR ')'            { $$ = $2->Content();           }       ;
RRZ     : _RRZ                  { $$ = new Operand(COND_Z, $1); }       ;
RRNZ    : _RRNZ                 { $$ = new Operand(COND_NZ, $1); }      ;

LL      : _LL                   { $$ = new Operand(REG_LL, $1); }       ;
LU      : _LU                   { $$ = new Operand(REG_LU, $1); }       ;
LS      : _LS                   { $$ = new Operand(REG_LS, $1); }       ;
L       : _L                    { $$ = new Operand(REG_L,  $1); }       ;
cLL     : '(' LL ')'            { $$ = $2->Content();           }       ;

SP      : _SP                   { $$ = new Operand(REG_SP,  $1); }      ;

dRR     : '-' '(' RR ')'        { $$ = $3->PreDec();             }      ;
dLL     : '-' '(' LL ')'        { $$ = $3->PreDec();             }      ;
dSP     : '-' '(' SP ')'        { $$ = $3->PreDec();             }      ;
RRi     : '(' RR ')' '+'        { $$ = $2->PostInc();            }      ;
LLi     : '(' LL ')' '+'        { $$ = $2->PostInc();            }      ;
SPi     : '(' SP ')' '+'        { $$ = $2->PostInc();            }      ;
oSP     : value '(' SP ')'      { $$ = $3->Offset($1);           }      ;
port    : '(' value ')'         { $$ = $2->Port();               }      ;
addr    : '(' value ')'         { $$ = $2->AbsAddr();            }      ;

/////////////////////////////////////////////////////////////////////////

opcode
: _BYTE value           { $$ = new Opcode(H_BYTE, 0x00, $1, $2);       }
| _WORD value           { $$ = new Opcode(H_WORD, 0x00, $1, $2);       }

| HALT                  { $$ = new Opcode(H_NONE,   0x00, $1);         }
| NOP                   { $$ = new Opcode(H_NONE,   0x01, $1);         }
| JMP  value            { $$ = new Opcode(H_WORD,   0x02, $1, $2);     }
| JMP  RRNZ ',' value   { $$ = new Opcode(H_WORD,   0x03, $1, $2, $4); }
| JMP  RRZ  ',' value   { $$ = new Opcode(H_WORD,   0x04, $1, $2, $4); }
| CALL value            { $$ = new Opcode(H_WORD,   0x05, $1, $2);     }
| CALL '(' RR ')'       { $$ = new Opcode(H_NONE,   0x06, $1, $3);     }
| RET                   { $$ = new Opcode(H_NONE,   0x07, $1);         }
| MOVE SPi  ',' RR      { $$ = new Opcode(H_NONE,   0x08, $1, $2, $4); }
| MOVE SPi  ',' RS      { $$ = new Opcode(H_NONE,   0x09, $1, $2, $4); }
| MOVE SPi  ',' RU      { $$ = new Opcode(H_NONE,   0x0A, $1, $2, $4); }
| MOVE SPi  ',' LL      { $$ = new Opcode(H_NONE,   0x0B, $1, $2, $4); }
| MOVE SPi  ',' LS      { $$ = new Opcode(H_NONE,   0x0C, $1, $2, $4); }
| MOVE SPi  ',' LU      { $$ = new Opcode(H_NONE,   0x0D, $1, $2, $4); }
| MOVE RR   ',' dSP     { $$ = new Opcode(H_NONE,   0x0E, $1, $2, $4); }
| MOVE R    ',' dSP     { $$ = new Opcode(H_NONE,   0x0F, $1, $2, $4); }

| AND  RR   ',' imm     { $$ = new Opcode(H_uBW,    0x10, $1, $2, $4); }
| OR   RR   ',' imm     { $$ = new Opcode(H_uBW,    0x12, $1, $2, $4); }
| XOR  RR   ',' imm     { $$ = new Opcode(H_uBW,    0x14, $1, $2, $4); }
| SEQ  RR   ',' imm     { $$ = new Opcode(H_sBW,    0x16, $1, $2, $4); }
| SNE  RR   ',' imm     { $$ = new Opcode(H_sBW,    0x18, $1, $2, $4); }
| SGE  RR   ',' imm     { $$ = new Opcode(H_sBW,    0x1A, $1, $2, $4); }
| SGT  RR   ',' imm     { $$ = new Opcode(H_sBW,    0x1C, $1, $2, $4); }
| SLE  RR   ',' imm     { $$ = new Opcode(H_sBW,    0x1E, $1, $2, $4); }
| SLT  RR   ',' imm     { $$ = new Opcode(H_sBW,    0x20, $1, $2, $4); }
| SHS  RR   ',' imm     { $$ = new Opcode(H_uBW,    0x22, $1, $2, $4); }
| SHI  RR   ',' imm     { $$ = new Opcode(H_uBW,    0x24, $1, $2, $4); }
| SLS  RR   ',' imm     { $$ = new Opcode(H_uBW,    0x26, $1, $2, $4); }
| SLO  RR   ',' imm     { $$ = new Opcode(H_uBW,    0x28, $1, $2, $4); }
| ADD  SP   ',' imm     { $$ = new Opcode(H_uBW,    0x2A, $1, $2, $4); }
| CLRW dSP              { $$ = new Opcode(H_NONE,   0x2C, $1, $2);     }
| CLRB dSP              { $$ = new Opcode(H_NONE,   0x2D, $1, $2);     }
| IN   port ',' RU      { $$ = new Opcode(H_PORT,   0x2E, $1, $2, $4); }
| OUT  R    ',' port    { $$ = new Opcode(H_PORT,   0x2F, $1, $2, $4); }

| AND  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x30, $1, $2, $4); }
| OR   LL   ',' RR      { $$ = new Opcode(H_NONE,   0x31, $1, $2, $4); }
| XOR  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x32, $1, $2, $4); }
| SEQ  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x33, $1, $2, $4); }
| SNE  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x34, $1, $2, $4); }
| SGE  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x35, $1, $2, $4); }
| SGT  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x36, $1, $2, $4); }
| SLE  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x37, $1, $2, $4); }
| SLT  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x38, $1, $2, $4); }
| SHS  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x39, $1, $2, $4); }
| SHI  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x3A, $1, $2, $4); }
| SLS  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x3B, $1, $2, $4); }
| SLO  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x3C, $1, $2, $4); }
| LNOT RR               { $$ = new Opcode(H_NONE,   0x3D, $1, $2);     }
| NEG  RR               { $$ = new Opcode(H_NONE,   0x3E, $1, $2);     }
| NOT  RR               { $$ = new Opcode(H_NONE,   0x3F, $1, $2);     }

| MOVE LL   ',' RR      { $$ = new Opcode(H_NONE,   0x40, $1, $2, $4); }
| MOVE LL   ',' cRR     { $$ = new Opcode(H_NONE,   0x41, $1, $2, $4); }
| MOVE L    ',' cRR     { $$ = new Opcode(H_NONE,   0x42, $1, $2, $4); }
| MOVE RR   ',' LL      { $$ = new Opcode(H_NONE,   0x43, $1, $2, $4); }
| MOVE RR   ',' cLL     { $$ = new Opcode(H_NONE,   0x44, $1, $2, $4); }
| MOVE R    ',' cLL     { $$ = new Opcode(H_NONE,   0x45, $1, $2, $4); }
| MOVE cRR  ',' RR      { $$ = new Opcode(H_NONE,   0x46, $1, $2, $4); }
| MOVE cRR  ',' RS      { $$ = new Opcode(H_NONE,   0x47, $1, $2, $4); }
| MOVE cRR  ',' RU      { $$ = new Opcode(H_NONE,   0x48, $1, $2, $4); }
| MOVE addr ',' RR      { $$ = new Opcode(H_WORD,   0x49, $1, $2, $4); }
| MOVE addr ',' RS      { $$ = new Opcode(H_WORD,   0x4A, $1, $2, $4); }
| MOVE addr ',' RU      { $$ = new Opcode(H_WORD,   0x4B, $1, $2, $4); }
| MOVE addr ',' LL      { $$ = new Opcode(H_WORD,   0x4C, $1, $2, $4); }
| MOVE addr ',' LS      { $$ = new Opcode(H_WORD,   0x4D, $1, $2, $4); }
| MOVE addr ',' LU      { $$ = new Opcode(H_WORD,   0x4E, $1, $2, $4); }
| MOVE RR   ',' SP      { $$ = new Opcode(H_NONE,   0x4F, $1, $2, $4); }

| LSL  RR   ',' imm     { $$ = new Opcode(H_BYTE,   0x52, $1, $2, $4); }
| ASR  RR   ',' imm     { $$ = new Opcode(H_BYTE,   0x53, $1, $2, $4); }
| LSR  RR   ',' imm     { $$ = new Opcode(H_BYTE,   0x54, $1, $2, $4); }
| LSL  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x55, $1, $2, $4); }
| ASR  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x56, $1, $2, $4); }
| LSR  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x57, $1, $2, $4); }
| ADD  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x58, $1, $2, $4); }
| SUB  LL   ',' RR      { $$ = new Opcode(H_NONE,   0x59, $1, $2, $4); }
| MOVE RR   ',' addr    { $$ = new Opcode(H_WORD,   0x5A, $1, $2, $4); }
| MOVE R    ',' addr    { $$ = new Opcode(H_WORD,   0x5B, $1, $2, $4); }
| MOVE RR   ',' oSP     { $$ = new Opcode(H_uBW,    0x5C, $1, $2, $4); }
| MOVE R    ',' oSP     { $$ = new Opcode(H_uBW,    0x5E, $1, $2, $4); }

| MOVE oSP  ',' RR      { $$ = new Opcode(H_uBW,    0x60, $1, $2, $4); }
| MOVE oSP  ',' RS      { $$ = new Opcode(H_uBW,    0x62, $1, $2, $4); }
| MOVE oSP  ',' RU      { $$ = new Opcode(H_uBW,    0x64, $1, $2, $4); }
| MOVE oSP  ',' LL      { $$ = new Opcode(H_uBW,    0x66, $1, $2, $4); }
| MOVE oSP  ',' LS      { $$ = new Opcode(H_uBW,    0x68, $1, $2, $4); }
| MOVE oSP  ',' LU      { $$ = new Opcode(H_uBW,    0x6A, $1, $2, $4); }
| LEA  oSP  ',' RR      { $$ = new Opcode(H_uBW,    0x6C, $1, $2, $4); }
| MOVE dRR  ',' dLL     { $$ = new Opcode(H_NONE,   0x6E, $1, $2, $4); }
| MOVE RRi  ',' LLi     { $$ = new Opcode(H_NONE,   0x6F, $1, $2, $4); }

| MUL_IS                { $$ = new Opcode(H_NONE,   0x70, $1);         }
| MUL_IU                { $$ = new Opcode(H_NONE,   0x71, $1);         }
| DIV_IS                { $$ = new Opcode(H_NONE,   0x72, $1);         }
| DIV_IU                { $$ = new Opcode(H_NONE,   0x73, $1);         }
| MD_STP                { $$ = new Opcode(H_NONE,   0x74, $1);         }
| MD_FIN                { $$ = new Opcode(H_NONE,   0x75, $1);         }
| MOD_FIN               { $$ = new Opcode(H_NONE,   0x76, $1);         }
| EI                    { $$ = new Opcode(H_NONE,   0x77, $1);         }
| RETI                  { $$ = new Opcode(H_NONE,   0x78, $1);         }
| DI                    { $$ = new Opcode(H_NONE,   0x79, $1);         }

| ADD  RR   ',' imm     { $$ = new Opcode(H_uQBW,   0xA0, $1, $2, $4); }
| SUB  RR   ',' imm     { $$ = new Opcode(H_uQBW,   0xB0, $1, $2, $4); }
| MOVE imm  ',' RR      { $$ = new Opcode(H_sQBW,   0xC0, $1, $2, $4); }
| SEQ  LL   ',' imm     { $$ = new Opcode(H_sQBW,   0xD0, $1, $2, $4); }
| MOVE imm  ',' LL      { $$ = new Opcode(H_sQBW,   0xE0, $1, $2, $4); }
;

// Fx mapped from 8X..EX
%%

//-----------------------------------------------------------------------------
void Line::Add(Opcode * opc)
{
   assert(opc);
Line * l = new Line(opc);
   if (first == 0)
      {
        assert(last == 0);
        first = last = l;
      }
   else
      {
        assert(last->tail == 0);
        last->tail = l;
        last = l;
      }
   PC += opc->GetLength();
}
//-----------------------------------------------------------------------------
Symbol * Symbol::symbols = 0;
Symbol * Symbol::current = 0;

Line * Line::first = 0;
Line * Line::last  = 0;

void Symbol::Add(const char * id, Expression * expr, bool lab, bool reloc)
{
   for (Symbol * s = symbols; s; s = s->tail)
       {
         if (!strcmp(id, s->identifier))
            {
              fprintf(stderr, "Error: Symbol %s already defined\n", id);
              return;
            }

         if (s->tail == 0)
            {
              s->tail = new Symbol(id, expr, lab, reloc);
              return;
            }
       }

   symbols = new Symbol(id, expr, lab, reloc);
}

//-----------------------------------------------------------------------------
int Operand::GetLength(OP_HOW how)
{
   // how may apply to this or the other argument!
   //
   if (offset)   return offset->GetLength(how);

   if (base != EXPR)    return 0;
   assert(expr);

   switch(how)
      {
        case H_BYTE:
        case H_PORT: return 1;
        case H_WORD: return 2;
      }

   if (expr->UsesName())   return 2;   // not yet known

   if (GetValue() < 0)    switch(how)
      {
        case H_uBW:
        case H_uQBW:   return 2;

        case H_sBW:    if (GetValue() >= -128)   return 1;
                       return 2;

        case H_sQBW:   if (GetValue() >= -8)     return 0;
                       if (GetValue() >= -128)   return 1;
                       return 2;

        default:        fprintf(stderr, "HOW = %d\n", how);
                        assert(0 && "Bad how");
      }

   // here GetValue() >= 0
   switch(how)
      {
        case H_uBW:    if (GetValue() <= 255)   return 1;
                       return 2;

        case H_sBW:    if (GetValue() <= 127)   return 1;
                       return 2;

        case H_uQBW:   if (GetValue() <= 15)    return 0;
                       if (GetValue() <= 255)   return 1;
                       return 2;

        case H_sQBW:   if (GetValue() <= 7)     return 0;
                       if (GetValue() <= 127)   return 1;
                       return 2;

        default:        fprintf(stderr, "HOW = %d\n", how);
                        assert(0 && "Bad how");
      }
}
//-----------------------------------------------------------------------------
int Opcode::GetLength() const
{
int base_len = 1;

   assert(op_text);
   if (*op_text == '.')   base_len = 0;

int op1_len  = 0;
   if (op_1)   op1_len = op_1->GetLength(op_how);

int op2_len  = 0;
   if (op_2)   op2_len = op_2->GetLength(op_how);

   assert(!op1_len || !op2_len);
   return base_len + op1_len + op2_len;
}
//-----------------------------------------------------------------------------
void Line::List()
{
   PC = 0;
   Symbol::Reset();

   for (Line * l = first; l; l = l->tail)
       {
         Symbol::Advance(PC);
         assert(l->opcode);
         assert(l->pc == PC);
         PC += l->opcode->List(PC);
       }
   Symbol::Advance(PC);
   fprintf(stderr, "Bytes = %d (0x%X)\n", PC, PC);
}
//-----------------------------------------------------------------------------
void Symbol::ListNonlabels()
{
   for (Symbol * s = symbols; s; s = s->tail)
       {
         if (s->label)   continue;

         assert(s->identifier);
         fprintf(list, "%s\t= %d\n",
                 s->identifier, s->expr->GetValue() & 0xFFFF);
       }
   fprintf(list, "\n");
}
//-----------------------------------------------------------------------------
void Symbol::PrintSymbols()
{
   for (Symbol * s = symbols; s; s = s->tail)
       {
         if (!s->label)   continue;

         assert(s->identifier);
         fprintf(sym, "%4.4X %s\n",
                 s->expr->GetValue() & 0xFFFF, s->identifier);
       }
}
//-----------------------------------------------------------------------------
int Symbol::GetValue(const char * id)
{
   for (Symbol * s = symbols; s; s = s->tail)
       {
         assert(s->identifier);
         assert(s->expr);
         if (strcmp(id, s->identifier))   continue;
         return 0xFFFF & Reloc(s->reloc, s->expr->GetValue());
       }

   fprintf(stderr, "Symbol %s not defined\n", id);
   assert(0 && "Symbol Not Defined");
   return 0;
}
//-----------------------------------------------------------------------------
int Operand::GetValue()
{
   assert(expr);
   return expr->GetValue();
}
//-----------------------------------------------------------------------------
int Expression::ListBase() const
{
int ret = 0;

   if (ex)   ret += ex->ListBase();

   switch(how)
      {
        case EX_NAME:
             assert(name);
             assert(!ex);
             return fprintf(list, "%s", name);

        case EX_NUMBER:
             assert(!name);
             assert(!ex);
             return fprintf(list, "%d", 0xFFFF & number);

        case EX_ADD:
             assert(ex);
             ret += fprintf(list, " + ");
             break;

        case EX_SUB:
             assert(ex);
             ret += fprintf(list, " - ");
             break;

        case EX_MULT:
             assert(ex);
             ret += fprintf(list, " * ");
             break;

        case EX_DIV:
             assert(ex);
             ret += fprintf(list, " / ");
             break;

        case EX_MOD:
             assert(ex);
             ret += fprintf(list, " / ");
             break;

        default: assert(0);
      }

   if (name)   ret += fprintf(list, "%s", name);
   else        ret += fprintf(list, "%d", number);

   return ret;
}
//-----------------------------------------------------------------------------
int Expression::GetValue() const
{
int ret;

int my_val = number;
   if (name)   my_val = Symbol::GetValue(name);

   switch(how)
      {
        case EX_NAME:
             assert(name);
             assert(!ex);
             ret = 0xFFFF & my_val;
             break;

        case EX_NUMBER:
             assert(!name);
             assert(!ex);
             ret = 0xFFFF & my_val;
             break;

        case EX_ADD:
             assert(ex);
             ret = 0xFFFF & (ex->GetValue() + my_val);
             break;

        case EX_SUB:
             assert(ex);
             ret = 0xFFFF & (ex->GetValue() - my_val);
             break;

        case EX_MULT:
             assert(ex);
             ret = 0xFFFF & (ex->GetValue() * my_val);
             break;

        case EX_DIV:
             assert(ex);
             assert(0xFFFF & my_val);
             ret = 0xFFFF & (ex->GetValue() / my_val);
             break;

        case EX_MOD:
             assert(ex);
             assert(0xFFFF & my_val);
             ret = 0xFFFF & (ex->GetValue() % my_val);
             break;

        default: assert(0);
      }

   return ret;
}
//-----------------------------------------------------------------------------
void Symbol::Advance(int pc)
{
   for (; current; current = current->tail)
      {
        if (!current->label)   continue;

        assert(current->expr);
        int nxt = current->expr->GetValue();
        if (nxt > pc)   return;


        if (nxt == pc)
           {
             assert(current->identifier);
             fprintf(list, "%s:\n", current->identifier);
             continue;
           }

        assert(0);
      }
}
//-----------------------------------------------------------------------------
int Opcode::List(int pc)
{
int len = 0;
int ret = 0;
int real_opcode = GetOpcode(ret);

   len += fprintf(list, "   %4.4X: ", 0xFFFF & Reloc(reloc, pc));

   assert(op_text);
   if (*op_text != '.')
      {
       len += fprintf(list, "%2.2X ", real_opcode);
       memory[mem_idx++] = real_opcode;
      }

   if (op_1)   len += op_1->ListHex(op_how);
   if (op_2)   len += op_2->ListHex(op_how);

   while (len < 20)   len += fprintf(list, " ");

   len += fprintf(list, "%s ", op_text);

   while (len < 22)   len += fprintf(list, " ");

   if (op_1)   len += op_1->List(op_how);
   if (op_2)
      {
        len += fprintf(list, ", ");
        len += op_2->List(op_how);
      }

   fprintf(list, "\n");
   return ret;
}
//-----------------------------------------------------------------------------
int Operand::ListHex(OP_HOW how)
{
   if (offset)   return offset->ListHex(how);

   switch(GetLength(how))
      {
        case 0:   return 0;

        case 1:   memory[mem_idx++] = GetValue();
                  return fprintf(list, "%2.2X ", GetValue() & 0xFF);

        case 2:   memory[mem_idx++] = GetValue();
                  memory[mem_idx++] = GetValue() >> 8;
                  return fprintf(list, "%4.4X ", GetValue() & 0xFFFF);

        default:  assert(0);
      }
}
//-----------------------------------------------------------------------------
int Operand::List(OP_HOW how)
{
int len = 0;

   if (offset)   len += offset->List(how);

   switch(attr)
      {
        case ATT_NONE:
             return len + ListBase(how);

        case ATT_OFFSET:
             len += fprintf(list, "(");
             len += ListBase(how);
             return len + fprintf(list, ")");

        case ATT_POSTINC:
             len += fprintf(list, "(");
             len += ListBase(how);
             return len + fprintf(list, ")+");

        case ATT_PREDEC:
             len += fprintf(list, "-(");
             len += ListBase(how);
             return len + fprintf(list, ")");

        case ATT_CONTENT:
        case ATT_PORT:
        case ATT_ADDR:
             len += fprintf(list, "(");
             len += ListBase(how);
             return len + fprintf(list, ")");

        case ATT_IMM:
             len += fprintf(list, "#");
             return len + ListBase(how);

        default: assert(0);
      }
}
//-----------------------------------------------------------------------------
int Operand::ListBase(OP_HOW how)
{
   if (base != EXPR)
      {
        assert(op_text);
        return fprintf(list, op_text);
     }

   if (expr)   return expr->ListBase();

   switch(GetLength(how))
      {
        case 0:  // quick
        case 1:  return fprintf(list, "%2.2X", GetValue() & 0x0FF);
        case 2:  return fprintf(list, "%4.4X", GetValue() & 0x0FFFF);
      }

   assert(0);
}
//-----------------------------------------------------------------------------
int Opcode::GetOpcode(int & len) const
{
   len = GetLength();

   switch(op_how)
      {
        case H_BYTE:
        case H_WORD: return op_code;
        case H_NONE: if (len == 1)    return op_code;
                     if (len == 2)
                        {
                          assert(op_code & 0x0F1 == 0x61);
                          return op_code | 0x01;
                        }
                     if (len == 3)
                        {
                          assert(op_code & 0x0F1 == 0x60);
                          return op_code;
                        }

                     assert(0);
        case H_PORT: if (len == 2)    return op_code;
                     assert(0);

        case H_sBW:
        case H_uBW:  assert((op_code & 0x01) == 0);
                     if (len == 2)   return op_code | 0x01;
                     if (len == 3)   return op_code;
                     Error();
                     assert(0);

        case H_uQBW:
        case H_sQBW: assert(op_1);
                     assert(op_2);
                     assert((op_code & 0x0F) == 0);
                     if (len == 3)   return 0xF0 | op_code >> 3;
                     if (len == 2)   return 0xF1 | op_code >> 3;

                     assert(len == 1);
                     if (op_code == 0xC0)   // MOVE #, RR
                        return op_code | op_1->GetValue() & 0x0F;
                     if (op_code == 0xE0)   // MOVE #, LL
                        return op_code | op_1->GetValue() & 0x0F;

                     return op_code | op_2->GetValue() & 0x0F;

      }
   assert(0);
}
//-----------------------------------------------------------------------------
void Opcode::Error() const
{
   fprintf(stderr, "Error: ");
   if (op_text) fprintf(stderr, "%s ", op_text);
   fprintf(stderr, "%X", op_code);
   fprintf(stderr, "\n");
}
//-----------------------------------------------------------------------------
void write_intel_record(FILE * out, int adr, int len)
{
char checksum = 0;

   fprintf(out, ":");

   fprintf(out, "%2.2X", len & 0xFF);
   checksum += len;

   fprintf(out, "%4.4X", adr & 0xFFFF);
   checksum += adr >> 8;
   checksum += adr;

   if (len == 0)   { fprintf(out, "01");   checksum ++; }   // end of file
   else            { fprintf(out, "00");                }   // data

   for (int i = adr; i < adr + len; i++)
       {
         fprintf(out, "%2.2X", memory[i] & 0xFF);
         checksum += memory[i];
       }

   fprintf(out, "%2.2X", (-checksum) & 0xFF);
   fprintf(out, "\n");
}
//-----------------------------------------------------------------------------
void write_intel_hex(FILE * out)
{
   for (int i = 0; i < mem_idx; i += 16)
       {
         int len = mem_idx - i;
         if (len > 16)   len = 16;
         write_intel_record(out, i, len);
       }
   write_intel_record(out, 0, 0);
}
//-----------------------------------------------------------------------------

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.