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

Subversion Repositories marca

[/] [marca/] [trunk/] [spar/] [spar.l] - Rev 8

Compare with Previous | Blame | View Log

/* This file is part of the assembler "spar" for marca.
   Copyright (C) 2007 Wolfgang Puffitsch

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU Library General Public License as published
   by the Free Software Foundation; either version 2, 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA */

%option nounput

%{
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <getopt.h>

#include "spar.h"
#include "ui.h"
#include "checks.h"
#include "code.h"
#include "emit.h"
#include "expand.h"
#include "exprs.h"
#include "fixes.h"
#include "optab.h"
#include "output.h"
#include "segtab.h"
#include "symtab.h"

char *command = NULL;

int8_t  output_mode = DEFAULT_MODE;
FILE   *output_file = NULL;
FILE   *rom0_file = NULL;
FILE   *rom1_file = NULL;

uint32_t codesize = DEFAULT_CODESIZE;
uint32_t datasize = DEFAULT_DATASIZE;
uint32_t romsize  = DEFAULT_ROMSIZE;
uint16_t filler = DEFAULT_FILLER;

int nostart = 0;
int noend = 0;

uint32_t line_count = 1;
uint32_t file_count = 0;
uint32_t error_count = 0;

int      seen_op = 0;
int8_t   args_to_match = -1;

/***************** WHAT TO DO ****************/
int initialize(void);
int merge(void);
int postprocess(void);

/* this does not really fit anywhere */
void expand_mod(void);

/***************** SHORTCUT ****************/
#define MATCH_OP(X) \
do { \
  struct seg *seg = get_current_seg(); \
  adjust_segsize(seg, seg->pos+1); \
  set_op(seg, seg->pos, (X)); \
  trace_listing(seg, seg->pos, yytext); \
  trace_listing(seg, seg->pos, "\t"); \
  seen_op = 1; \
  args_to_match = get_arg_count(seg, seg->pos)*2 - 1; \
} while(0)

%}

REG  (r[0-9]+)
NUM  ((-?0[0-7]*)|(-?[1-9][0-9]*)|(-?0x[0-9a-fA-F]+))
BNUM (0b[0-1]+)
SYM  (\.?[_\.a-zA-Z0-9]+)
EXPR (([^ \t\r\n,;])|([^ \t\r\n,;][^,;\n]*[^ \t\r\n,;]))

%%

\.file[ \t]*\r?\n   file_count++;

\.text[ \t]*\r?\n   set_current_segnum(SEG_TEXT);
\.data[ \t]*\r?\n   set_current_segnum(SEG_DATA);
\.bss[ \t]*\r?\n    set_current_segnum(SEG_BSS);

\.align[ \t]{EXPR}\r?\n {
         struct seg *seg = get_current_seg();
         char *s = xstrdup(yytext+7);
         int32_t a = 1 << expr_nevaluate(s);

         while ((seg->pos % a) != 0)
           {
             if (get_current_segnum() == SEG_TEXT)
               {
                 emit_nop(seg);
               }
             else
               {
                 emit_zero(seg);
               }
           }
       }

\.comm[ \t]{SYM}[ \t]*,[ \t]*{EXPR}\r?\n {
         int32_t i;
         char *s = xstrdup(yytext+6);
         char *t = s;
         
         t = strpbrk(s, ",");
         *t++ = '\0';
         
         s = localize_string(s);
         check_sym_dup(s);
         push_sym(s, SEG_BSS, get_seg(SEG_BSS)->pos);
         trace_listing(get_seg(SEG_BSS), get_seg(SEG_BSS)->pos, s);
         trace_listing(get_seg(SEG_BSS), get_seg(SEG_BSS)->pos, ":\t");

         for (i=0; i < expr_nevaluate(t); i++)
           {
             emit_zero(get_seg(SEG_BSS));
           }
       }

\.lcomm[ \t]{SYM}[ \t]*,[ \t]*{EXPR}\r?\n {
         int32_t i;
         char *s = xstrdup(yytext+7);
         char *t = s;
         
         t = strpbrk(s, ",");
         *t++ = '\0';
         
         s = localize_string(s);
         check_sym_dup(s);
         push_sym(s, SEG_BSS, get_seg(SEG_BSS)->pos);
         trace_listing(get_seg(SEG_BSS), get_seg(SEG_BSS)->pos, s);
         trace_listing(get_seg(SEG_BSS), get_seg(SEG_BSS)->pos, ":\t");

         for (i=0; i < expr_nevaluate(t); i++)
           {
             emit_zero(get_seg(SEG_BSS));
           }
       }

\.org[ \t]{EXPR}\r?\n {
         struct seg *seg = get_current_seg();
         char *s = xstrdup(yytext+6);
         int32_t o = expr_nevaluate(s);

         check_org_advances(seg, o);

         while (seg->pos < o)
           {
             if (get_current_segnum() == SEG_TEXT)
               {
                 emit_nop(seg);
               }
             else
               {
                 emit_zero(seg);
               }
           }
       }

\.skip[ \t]{EXPR}\r?\n {
         struct seg *seg = get_current_seg();
         char *s = xstrdup(yytext+6);
         int32_t i;

         for (i = 0; i < expr_nevaluate(s); i++)
           {
             if (get_current_segnum() == SEG_TEXT)
               {
                 emit_nop(seg);
               }
             else
               {
                 emit_zero(seg);
               }
           }
       }

{SYM}: {
         char *s;
         struct seg *seg = get_current_seg();
         s = xstrdup(yytext);
         s[yyleng-1] = '\0';
         s = localize_string(s);
         check_sym_dup(s);
         push_sym(s, get_current_segnum(), seg->pos);
         trace_listing(seg, seg->pos, s);
         trace_listing(seg, seg->pos, ":\t");
       }  

data     MATCH_OP(DATA);
add      MATCH_OP(ADD);
addc     MATCH_OP(ADDC);
sub      MATCH_OP(SUB);
subc     MATCH_OP(SUBC);
and      MATCH_OP(AND);
or       MATCH_OP(OR);
xor      MATCH_OP(XOR);
mul      MATCH_OP(MUL);
div      MATCH_OP(DIV);
udiv     MATCH_OP(UDIV);
ldil     MATCH_OP(LDIL);
ldih     MATCH_OP(LDIH);
ldib     MATCH_OP(LDIB);
mov      MATCH_OP(MOV);
not      MATCH_OP(NOT);
neg      MATCH_OP(NEG);
cmp      MATCH_OP(CMP);
addi     MATCH_OP(ADDI);
cmpi     MATCH_OP(CMPI);
shl      MATCH_OP(SHL);
shr      MATCH_OP(SHR);
sar      MATCH_OP(SAR);
mod      MATCH_OP(MOD);
umod     MATCH_OP(UMOD);
rolc     MATCH_OP(ROLC);
rorc     MATCH_OP(RORC);
bset     MATCH_OP(BSET);
bclr     MATCH_OP(BCLR);
btest    MATCH_OP(BTEST);
load     MATCH_OP(LOAD);
store    MATCH_OP(STORE);
loadl    MATCH_OP(LOADL);
loadh    MATCH_OP(LOADH);
loadb    MATCH_OP(LOADB);
storel   MATCH_OP(STOREL);
storeh   MATCH_OP(STOREH);
call     MATCH_OP(CALL);

br       MATCH_OP(BR);
brz      MATCH_OP(BRZ);
brnz     MATCH_OP(BRNZ);
brle     MATCH_OP(BRLE);
brlt     MATCH_OP(BRLT);
brge     MATCH_OP(BRGE);
brgt     MATCH_OP(BRGT);
brule    MATCH_OP(BRULE);
brult    MATCH_OP(BRULT);
bruge    MATCH_OP(BRUGE);
brugt    MATCH_OP(BRUGT);
sext     MATCH_OP(SEXT);
ldvec    MATCH_OP(LDVEC);
stvec    MATCH_OP(STVEC);

jmp      MATCH_OP(JMP);
jmpz     MATCH_OP(JMPZ);
jmpnz    MATCH_OP(JMPNZ);
jmple    MATCH_OP(JMPLE);
jmplt    MATCH_OP(JMPLT);
jmpge    MATCH_OP(JMPGE);
jmpgt    MATCH_OP(JMPGT);
jmpule   MATCH_OP(JMPULE);
jmpult   MATCH_OP(JMPULT);
jmpuge   MATCH_OP(JMPUGE);
jmpugt   MATCH_OP(JMPUGT);
intr     MATCH_OP(INTR);
getira   MATCH_OP(GETIRA);
setira   MATCH_OP(SETIRA);
getfl    MATCH_OP(GETFL);
setfl    MATCH_OP(SETFL);
getshfl  MATCH_OP(GETSHFL);
setshfl  MATCH_OP(SETSHFL);

reti     MATCH_OP(RETI);
nop      MATCH_OP(NOP);
sei      MATCH_OP(SEI);
cli      MATCH_OP(CLI);
error    MATCH_OP(ERROR);

{REG} {
        struct seg *seg = get_current_seg();
        int arg_index = get_arg_count(seg, seg->pos) - (args_to_match+1)/2;

        if (check_arg_count() || check_arg_type(seg, seg->pos, arg_index, 'r'))
          YY_BREAK;

        set_regnum(seg, seg->pos, arg_index, strtol(yytext+1, NULL, 10));
        set_mode(seg, seg->pos, arg_index, 'r');
        trace_listing(seg, seg->pos, yytext);
        args_to_match--;
      }

{EXPR} {
        struct seg *seg = get_current_seg();
        int arg_index;

        if (!seen_op)
          {
            REJECT;
          }

        arg_index = get_arg_count(seg, seg->pos) - (args_to_match+1)/2; 

        if (check_arg_count() || check_arg_type(seg, seg->pos, arg_index, 'n'))
          YY_BREAK;

        set_expr(seg, seg->pos, arg_index, expr_localize(yytext));
        set_mode(seg, seg->pos, arg_index, 'n');
        trace_listing(seg, seg->pos, yytext);
        args_to_match--;
       }

,          {
             check_colon_ok();
             trace_listing(get_current_seg(), get_current_seg()->pos, ", ");
             args_to_match--;
           }

;.*        { /* ignore comments */ }

[ \t\r]+   { /* ignore whitespace */ }

\n+ {
      check_premature();
      expand_mod();
      if (seen_op)
        {
          get_current_seg()->pos++;
          seen_op = 0;
          args_to_match = -1;
        }
      line_count += yyleng;
    }

<<EOF>> {
      check_premature();
      expand_mod();
      if (seen_op)
        {
          get_current_seg()->pos++;
          seen_op = 0;
          args_to_match = -1;
        }
      yyterminate();
    }

. {
    fprintf(stderr, "invalid input `%c' in line %lu\n", yytext[0], line_count);
    error_count++;
  }

%%

int initialize(void)
{
  init_symtab();

  init_seg(SEG_DATA, SEG_INITSIZE/2);
  init_seg(SEG_BSS, SEG_INITSIZE/2);
  init_seg(SEG_TEXT, SEG_INITSIZE);

  set_current_segnum(SEG_TEXT);

  return 0;
}

int merge(void)
{
  uint32_t pos;
  int retval = 0;

  init_seg(SEG_PILE, SEG_INITSIZE);

  /* align .data to word boundary */
  if ((get_seg(SEG_DATA)->pos % 2) != 0)
    {
      emit_zero(get_seg(SEG_DATA));
    }

  /* align .bss to word boundary */
  if ((get_seg(SEG_BSS)->pos % 2) != 0)
    {
      emit_zero(get_seg(SEG_BSS));
    }

  /* check .data */
  for (pos = 0; pos < get_seg(SEG_DATA)->pos; pos += 2)
    {
      if ((get_op(get_seg(SEG_DATA), pos) != DATA)
          || (get_op(get_seg(SEG_DATA), pos+1) != DATA))
        {
          fprintf(stderr, "cannot initialize anything but `data' in .data\n");
          error_count++;
          retval = 1;
        }
    }

  /* check .bss */
  for (pos = 0; pos < get_seg(SEG_BSS)->pos; pos++)
    {
      if ((get_op(get_seg(SEG_BSS), pos) != DATA)
          || (expr_symcount(get_expr(get_seg(SEG_BSS), pos, 0)) > 0)
          || (expr_evaluate(get_expr(get_seg(SEG_BSS), pos, 0)) != 0))
        {
          fprintf(stderr, "cannot put anything but `data 0' in .bss\n");
          error_count++;
          retval = 1;
        }
    }

  /* copy data from ROM */
  if (get_seg(SEG_DATA)->pos != 0)
    {
      emit_ldil(get_seg(SEG_PILE), 0,
                xsprintf("lo(%d)", get_seg(SEG_DATA)->pos));
      emit_ldih(get_seg(SEG_PILE), 0,
                xsprintf("hi(%d)", get_seg(SEG_DATA)->pos));

      emit_ldil(get_seg(SEG_PILE), 1,
                xsprintf("lo(%d)", datasize));
      emit_ldih(get_seg(SEG_PILE), 1,
                xsprintf("hi(%d)", datasize));

      emit_ldib(get_seg(SEG_PILE), 2, "0");
      push_sym("__init_data_loop__", SEG_PILE, get_seg(SEG_PILE)->pos);
      trace_listing(get_seg(SEG_PILE), get_seg(SEG_PILE)->pos,
                    "__init_data_loop__:\t");
      emit_load(get_seg(SEG_PILE), 3, 1);
      emit_store(get_seg(SEG_PILE), 3, 2);
      emit_addi(get_seg(SEG_PILE), 1, "2");
      emit_addi(get_seg(SEG_PILE), 2, "2");
      emit_cmp(get_seg(SEG_PILE), 0, 2);
      emit_brnz(get_seg(SEG_PILE), "__init_data_loop__");
    }

  /* clear .bss */
  if (get_seg(SEG_BSS)->pos != 0)
    {
      emit_ldil(get_seg(SEG_PILE), 0,
                xsprintf("lo(%d+%d)", get_seg(SEG_DATA)->pos,
                                      get_seg(SEG_BSS)->pos));
      emit_ldih(get_seg(SEG_PILE), 0,
                xsprintf("hi(%d+%d)", get_seg(SEG_DATA)->pos,
                                      get_seg(SEG_BSS)->pos));
      emit_ldib(get_seg(SEG_PILE), 3, "0");
      push_sym("__init_bss_loop__", SEG_PILE, get_seg(SEG_PILE)->pos);
      trace_listing(get_seg(SEG_PILE), get_seg(SEG_PILE)->pos,
                    "__init_bss_loop__:\t");
      emit_store(get_seg(SEG_PILE), 3, 2);
      emit_addi(get_seg(SEG_PILE), 2, "2");
      emit_cmp(get_seg(SEG_PILE), 0, 2);
      emit_brnz(get_seg(SEG_PILE), "__init_bss_loop__");      
    }

  reloc_syms(SEG_BSS, get_seg(SEG_DATA)->pos);
  reloc_syms(SEG_TEXT, get_seg(SEG_PILE)->pos);

  for(pos = 0; pos < get_seg(SEG_TEXT)->pos; pos++)
    {
      emit_op(get_seg(SEG_PILE), get_seg(SEG_TEXT)->code[pos]);
    }

  set_current_segnum(SEG_PILE);

  return retval;
}

int postprocess(void)
{
  struct seg *seg;
  uint32_t pos;
  int retval = 0;

  if ((output_mode != MODE_DRYRUN)
      && (check_code_size()
          || check_data_size()))
    {
      retval = 1;
    }

  seg = get_seg(SEG_PILE);
  for (pos = 0; pos < seg->pos; pos++)
    {
      if (check_mnemonic(seg, pos))
        {
          retval = 1;
        }
      if ((output_mode != MODE_DRYRUN)
          && (fix_operands(seg, pos)
              || check_ranges(seg, pos)
              || fix_code(seg, pos)))
        {
          retval = 1;
        }
    }

  seg = get_seg(SEG_DATA);
  for (pos = 0; pos < seg->pos; pos++)
    {
      if (check_mnemonic(seg, pos))
        {
          retval = 1;
        }
      if ((output_mode != MODE_DRYRUN)
          && (fix_operands(seg, pos)
              || check_ranges(seg, pos)
              || fix_code(seg, pos)))
        {
          retval = 1;
        }
    }

  return retval;
}

/***************** LIB *****************/

void *xmalloc(size_t size)
{
  void *retval = malloc(size);
  if (retval == NULL)
    {
      fprintf(stderr, "run out of memory\n");
      exit(EXIT_FAILURE);
    }
  return retval;  
}

void *xrealloc(void *ptr, size_t size)
{
  void *retval = realloc(ptr, size);
  if (retval == NULL)
    {
      fprintf(stderr, "run out of memory\n");
      exit(EXIT_FAILURE);
    }
  return retval;  
}

char *xstrdup(const char *str)
{
  size_t len = strlen(str);
  void *retval = xmalloc(len+1);
  memcpy(retval, str, len+1);
  return retval;  
}

char *xsprintf(const char *fmt, ...)
{
  va_list ap;
  char *retval;

  va_start(ap, fmt);
  vasprintf(&retval, fmt, ap);
  va_end(ap);

  if (retval == NULL)
    {
      fprintf(stderr, "run out of memory\n");
      exit(EXIT_FAILURE);
    }

  return retval;
}

/***************** MAIN *****************/

int yywrap()
{
  return 1;
}

int main(int argc, char **argv)
{
  int opt;

  int opterr = 0;

  int hopt = 0;
  int vopt = 0;

  command = argv[0];

  while (optind < argc)
    {
      if (strcmp(argv[optind], "-") == 0 || (argv[optind][0] != '-'))
        {
          opt = -1;
        }
      else
        {
          opt = getopt_long(argc, argv, options, long_options, 0);
        }

      switch(opt)
        {
        case 'h': hopt++; break;
        case 'v': vopt++; break;
        case 'o': case '0': case '1':
        case 'c': case 'd': case 'r':
        case 'f': case 'i': case 'n': case 'l':
        case 'm': case 's': case 'e':
          break;
        case '?': opterr = 1; break;
        case -1: optind++; break;
        }
    }

  if (opterr)
    {
      printf("Usage:\n"
             "    %s [--intel|--nointel|--download|--dryrun]\n"
             "    [--codesize=*n*] [--datasize=*n*] [--romsize=*n*]\n"
             "    [--filler=*n*] [--output=file] [--rom0file=file] [--rom1file=file]\n"
             "    [--nostart] [--noend] file ...\n", command);
      return EXIT_FAILURE;
    }

  if (vopt)
    {
      printf("spar 0.2\n");
      return EXIT_SUCCESS;
    }

  if (hopt)
    {
      printf("Usage:\n"
             "    %s [--intel|--nointel|--download|--dryrun]\n"
             "    [--codesize=*n*] [--datasize=*n*] [--romsize=*n*]\n"
             "    [--filler=*n*] [--output=file] [--rom0file=file] [--rom1file=file]\n"
             "    [--nostart] [--noend] file ...\n", command);
      return EXIT_SUCCESS;
    }

  optind = 1;

  initialize();

  while (optind < argc)
    {
      if (strcmp(argv[optind], "-") == 0 || (argv[optind][0] != '-'))
        {
          opt = -1;
        }
      else
        {
          opt = getopt_long(argc, argv, options, long_options, 0);
        }

      switch (opt)
        {
        case 'h': case 'v':
          break;
        case 'o':
          if (strcmp(optarg, "-") == 0)
            {
              output_file = stdout;
            }
          else
            {
              output_file = fopen(optarg, "w");
              if (output_file == NULL)
                {
                  fprintf(stderr, "cannot open file %s\n", optarg);
                  return EXIT_FAILURE;            
                }
            }
          break;
        case '0':
          if (strcmp(optarg, "-") == 0)
            {
              rom0_file = stdout;
            }
          else
            {
              rom0_file = fopen(optarg, "w");
              if (rom0_file == NULL)
                {
                  fprintf(stderr, "cannot open file %s\n", optarg);
                  return EXIT_FAILURE;            
                }
            }
          break;
        case '1':
          if (strcmp(optarg, "-") == 0)
            {
              rom1_file = stdout;
            }
          else
            {
              rom1_file = fopen(optarg, "w");
              if (rom1_file == NULL)
                {
                  fprintf(stderr, "cannot open file %s\n", optarg);
                  return EXIT_FAILURE;            
                }
            }
          break;
        case 'c':
          {
            char * errptr = NULL;
            romsize = strtol(optarg, &errptr, 0);
            if (*errptr != '\0')
              {
                fprintf(stderr, "invalid codesize %s\n", optarg);
                return EXIT_FAILURE;              
              }
          }
          break;
        case 'd':
          {
            char * errptr = NULL;
            romsize = strtol(optarg, &errptr, 0);
            if (*errptr != '\0')
              {
                fprintf(stderr, "invalid datasize %s\n", optarg);
                return EXIT_FAILURE;              
              }
          }
          break;
        case 'r':
          {
            char * errptr = NULL;
            romsize = strtol(optarg, &errptr, 0);
            if (*errptr != '\0')
              {
                fprintf(stderr, "invalid romsize %s\n", optarg);
                return EXIT_FAILURE;              
              }
          }
          break;
        case 'f':
          {
            char * errptr = NULL;
            filler = strtol(optarg, &errptr, 0);
            if (*errptr != '\0')
              {
                fprintf(stderr, "invalid filler %s\n", optarg);
                return EXIT_FAILURE;              
              }
          }
          break;
        case 'i': output_mode = MODE_INTEL; break;
        case 'n': output_mode = MODE_DRYRUN; break;
        case 'l': output_mode = MODE_DOWNLOAD; break;
        case 'm': output_mode = MODE_MIF; break;
        case 's': nostart = 1; break;
        case 'e': noend = 1; break;
        case '?': break;
        case -1:
          if (argv[optind] == NULL)
            break;
          if (strcmp(argv[optind], "-") == 0)
            {
              yyin = stdin;
            }
          else
            {
              yyin = fopen(argv[optind], "r");
              if (yyin == NULL)
                {
                  fprintf(stderr, "cannot open file %s\n", argv[optind]);
                  return EXIT_FAILURE;            
                }
            }
          yylex();
          file_count++;

          optind++;
          break;
        }
    }

  if (output_file == NULL)
    {
      output_file = stdout;
    }
  if (rom0_file == NULL)
    {
      rom0_file = stdout;
    }
  if (rom1_file == NULL)
    {
      rom1_file = stdout;
    }

  if (file_count == 0)
    {
      yyin = stdin;
      yylex();
    }

  merge();

  postprocess();

  if (error_count != 0)
    {
      fprintf(stderr, "found %lu error(s)\n", error_count);
      return EXIT_FAILURE;
    }

  if (output_file == NULL)
    {
      output_file = stdout;
    }
  if (rom0_file == NULL)
    {
      rom0_file = stdout;
    }
  if (rom1_file == NULL)
    {
      rom1_file = stdout;
    }

  switch (output_mode)
    {
    case MODE_DRYRUN: break;
    case MODE_DOWNLOAD: print_download(output_file, rom0_file, rom1_file); break;
    case MODE_INTEL: print_intel(output_file, rom0_file, rom1_file); break;
    case MODE_MIF: print_mif(output_file, rom0_file, rom1_file); break;
    }

  if (output_file != stdout)
    {
      fclose(output_file);
    }
  if (rom0_file != stdout)
    {
      fclose(rom0_file);
    }
  if (rom1_file != stdout)
    {
      fclose(rom1_file);
    }

  return EXIT_SUCCESS;
}

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.