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

Subversion Repositories eco32

[/] [eco32/] [trunk/] [binutils/] [as/] [as.c] - Blame information for rev 42

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

Line No. Rev Author Line
1 7 hellwig
/*
2
 * as.c -- ECO32 assembler
3
 */
4
 
5
 
6
#include <stdio.h>
7
#include <stdlib.h>
8
#include <string.h>
9
#include <stdarg.h>
10
#include <ctype.h>
11
#include <unistd.h>
12
 
13
#include "../include/a.out.h"
14
 
15
 
16
/**************************************************************/
17
 
18
 
19
#define NUM_REGS        32
20
#define AUX_REG         1
21
 
22
#define LINE_SIZE       200
23
 
24
#define TOK_EOL         0
25
#define TOK_LABEL       1
26
#define TOK_IDENT       2
27
#define TOK_STRING      3
28
#define TOK_NUMBER      4
29
#define TOK_REGISTER    5
30
#define TOK_PLUS        6
31
#define TOK_MINUS       7
32
#define TOK_STAR        8
33
#define TOK_SLASH       9
34
#define TOK_PERCENT     10
35
#define TOK_LSHIFT      11
36
#define TOK_RSHIFT      12
37
#define TOK_LPAREN      13
38
#define TOK_RPAREN      14
39
#define TOK_COMMA       15
40
#define TOK_TILDE       16
41
#define TOK_AMPER       17
42
#define TOK_BAR         18
43
#define TOK_CARET       19
44
 
45
#define STATUS_UNKNOWN  0        /* symbol is not yet defined */
46
#define STATUS_DEFINED  1       /* symbol is defined */
47
#define STATUS_GLOBREF  2       /* local entry refers to a global one */
48
 
49
#define GLOBAL_TABLE    0        /* global symbol table identifier */
50
#define LOCAL_TABLE     1       /* local symbol table identifier */
51
 
52
#define MSB     ((unsigned int) 1 << (sizeof(unsigned int) * 8 - 1))
53
 
54
 
55
/**************************************************************/
56
 
57
 
58
#define OP_ADD          0x00
59
#define OP_ADDI         0x01
60
#define OP_SUB          0x02
61
#define OP_SUBI         0x03
62
 
63
#define OP_MUL          0x04
64
#define OP_MULI         0x05
65
#define OP_MULU         0x06
66
#define OP_MULUI        0x07
67
#define OP_DIV          0x08
68
#define OP_DIVI         0x09
69
#define OP_DIVU         0x0A
70
#define OP_DIVUI        0x0B
71
#define OP_REM          0x0C
72
#define OP_REMI         0x0D
73
#define OP_REMU         0x0E
74
#define OP_REMUI        0x0F
75
 
76
#define OP_AND          0x10
77
#define OP_ANDI         0x11
78
#define OP_OR           0x12
79
#define OP_ORI          0x13
80
#define OP_XOR          0x14
81
#define OP_XORI         0x15
82
#define OP_XNOR         0x16
83
#define OP_XNORI        0x17
84
 
85
#define OP_SLL          0x18
86
#define OP_SLLI         0x19
87
#define OP_SLR          0x1A
88
#define OP_SLRI         0x1B
89
#define OP_SAR          0x1C
90
#define OP_SARI         0x1D
91
 
92
#define OP_LDHI         0x1F
93
 
94
#define OP_BEQ          0x20
95
#define OP_BNE          0x21
96
#define OP_BLE          0x22
97
#define OP_BLEU         0x23
98
#define OP_BLT          0x24
99
#define OP_BLTU         0x25
100
#define OP_BGE          0x26
101
#define OP_BGEU         0x27
102
#define OP_BGT          0x28
103
#define OP_BGTU         0x29
104
 
105
#define OP_J            0x2A
106
#define OP_JR           0x2B
107
#define OP_JAL          0x2C
108
#define OP_JALR         0x2D
109
 
110
#define OP_TRAP         0x2E
111
#define OP_RFX          0x2F
112
 
113
#define OP_LDW          0x30
114
#define OP_LDH          0x31
115
#define OP_LDHU         0x32
116
#define OP_LDB          0x33
117
#define OP_LDBU         0x34
118
 
119
#define OP_STW          0x35
120
#define OP_STH          0x36
121
#define OP_STB          0x37
122
 
123
#define OP_MVFS         0x38
124
#define OP_MVTS         0x39
125
#define OP_TBS          0x3A
126
#define OP_TBWR         0x3B
127
#define OP_TBRI         0x3C
128
#define OP_TBWI         0x3D
129
 
130
 
131
/**************************************************************/
132
 
133
 
134
int debugToken = 0;
135
int debugCode = 0;
136
int debugFixup = 0;
137
 
138
char codeName[L_tmpnam];
139
char dataName[L_tmpnam];
140
char *outName = NULL;
141
char *inName = NULL;
142
 
143
FILE *codeFile = NULL;
144
FILE *dataFile = NULL;
145
FILE *outFile = NULL;
146
FILE *inFile = NULL;
147
 
148
char line[LINE_SIZE];
149
char *lineptr;
150
int lineno;
151
 
152
int token;
153
int tokenvalNumber;
154
char tokenvalString[LINE_SIZE];
155
 
156
int allowSyn = 1;
157
int currSeg = SEGMENT_CODE;
158
unsigned int segPtr[4] = { 0, 0, 0, 0 };
159
char *segName[4] = { "ABS", "CODE", "DATA", "BSS" };
160
char *methodName[5] = { "H16", "L16", "R16", "R26", "W32" };
161
 
162
 
163
typedef struct fixup {
164
  int segment;                  /* in which segment */
165
  unsigned int offset;          /* at which offset */
166
  int method;                   /* what kind of coding method is to be used */
167
  int value;                    /* known part of value */
168
  int base;                     /* segment which this ref is relative to */
169
                                /* valid only when used for relocation */
170
  struct fixup *next;           /* next fixup */
171
} Fixup;
172
 
173
 
174
typedef struct symbol {
175
  char *name;                   /* name of symbol */
176
  int status;                   /* status of symbol */
177
  int segment;                  /* the symbol's segment */
178
  int value;                    /* the symbol's value */
179
  Fixup *fixups;                /* list of locations to fix */
180
  struct symbol *globref;       /* set if this local refers to a global */
181
  struct symbol *left;          /* left son in binary search tree */
182
  struct symbol *right;         /* right son in binary search tree */
183
  int skip;                     /* this symbol is not defined here nor is */
184
                                /* it used here: don't write to object file */
185
} Symbol;
186
 
187
 
188
/**************************************************************/
189
 
190
 
191
void error(char *fmt, ...) {
192
  va_list ap;
193
 
194
  va_start(ap, fmt);
195
  fprintf(stderr, "Error: ");
196
  vfprintf(stderr, fmt, ap);
197
  fprintf(stderr, "\n");
198
  va_end(ap);
199
  if (codeFile != NULL) {
200
    fclose(codeFile);
201
    codeFile = NULL;
202
  }
203
  if (dataFile != NULL) {
204
    fclose(dataFile);
205
    dataFile = NULL;
206
  }
207
  if (outFile != NULL) {
208
    fclose(outFile);
209
    outFile = NULL;
210
  }
211
  if (inFile != NULL) {
212
    fclose(inFile);
213
    inFile = NULL;
214
  }
215
  if (codeName != NULL) {
216
    unlink(codeName);
217
  }
218
  if (dataName != NULL) {
219
    unlink(dataName);
220
  }
221
  if (outName != NULL) {
222
    unlink(outName);
223
  }
224
  exit(1);
225
}
226
 
227
 
228
void *allocateMemory(unsigned int size) {
229
  void *p;
230
 
231
  p = malloc(size);
232
  if (p == NULL) {
233
    error("out of memory");
234
  }
235
  return p;
236
}
237
 
238
 
239
void freeMemory(void *p) {
240
  free(p);
241
}
242
 
243
 
244
/**************************************************************/
245
 
246
 
247
int getNextToken(void) {
248
  char *p;
249
  int base;
250
  int digit;
251
 
252
  while (*lineptr == ' ' || *lineptr == '\t') {
253
    lineptr++;
254
  }
255
  if (*lineptr == '\n' || *lineptr == '\0' || *lineptr == ';') {
256
    return TOK_EOL;
257
  }
258
  if (isalpha((int) *lineptr) || *lineptr == '_' || *lineptr == '.') {
259
    p = tokenvalString;
260
    while (isalnum((int) *lineptr) || *lineptr == '_' || *lineptr == '.') {
261
      *p++ = *lineptr++;
262
    }
263
    *p = '\0';
264
    if (*lineptr == ':') {
265
      lineptr++;
266
      return TOK_LABEL;
267
    } else {
268
      return TOK_IDENT;
269
    }
270
  }
271
  if (isdigit((int) *lineptr)) {
272
    base = 10;
273
    tokenvalNumber = 0;
274
    if (*lineptr == '0') {
275
      lineptr++;
276
      if (*lineptr == 'x' || *lineptr == 'X') {
277
        base = 16;
278
        lineptr++;
279
      } else
280
      if (isdigit((int) *lineptr)) {
281
        base = 8;
282
      } else {
283
        return TOK_NUMBER;
284
      }
285
    }
286
    while (isxdigit((int) *lineptr)) {
287
      digit = *lineptr++ - '0';
288
      if (digit >= 'A' - '0') {
289
        if (digit >= 'a' - '0') {
290
          digit += '0' - 'a' + 10;
291
        } else {
292
          digit += '0' - 'A' + 10;
293
        }
294
      }
295
      if (digit >= base) {
296
        error("illegal digit value %d in line %d", digit, lineno);
297
      }
298
      tokenvalNumber *= base;
299
      tokenvalNumber += digit;
300
    }
301
    return TOK_NUMBER;
302
  }
303
  if (*lineptr == '\'') {
304
    lineptr++;
305
    if (!isprint((int) *lineptr)) {
306
      error("cannot quote character 0x%02X in line %d", *lineptr, lineno);
307
    }
308
    tokenvalNumber = *lineptr;
309
    lineptr++;
310
    if (*lineptr != '\'') {
311
      error("unbalanced quote in line %d", lineno);
312
    }
313
    lineptr++;
314
    return TOK_NUMBER;
315
  }
316
  if (*lineptr == '\"') {
317
    lineptr++;
318
    p = tokenvalString;
319
    while (1) {
320
      if (*lineptr == '\n' || *lineptr == '\0') {
321
        error("unterminated string constant in line %d", lineno);
322
      }
323
      if (!isprint((int) *lineptr)) {
324
        error("string contains illegal character 0x%02X in line %d",
325
              *lineptr, lineno);
326
      }
327
      if (*lineptr == '\"') {
328
        break;
329
      }
330
      *p++ = *lineptr++;
331
    }
332
    lineptr++;
333
    *p = '\0';
334
    return TOK_STRING;
335
  }
336
  if (*lineptr == '$') {
337
    lineptr++;
338
    if (!isdigit((int) *lineptr)) {
339
      error("register number expected after '$' in line %d", lineno);
340
    }
341
    tokenvalNumber = 0;
342
    while (isdigit((int) *lineptr)) {
343
      digit = *lineptr++ - '0';
344
      tokenvalNumber *= 10;
345
      tokenvalNumber += digit;
346
    }
347
    if (tokenvalNumber < 0 || tokenvalNumber >= NUM_REGS) {
348
      error("illegal register number %d in line %d", tokenvalNumber, lineno);
349
    }
350
    return TOK_REGISTER;
351
  }
352
  if (*lineptr == '+') {
353
    lineptr++;
354
    return TOK_PLUS;
355
  }
356
  if (*lineptr == '-') {
357
    lineptr++;
358
    return TOK_MINUS;
359
  }
360
  if (*lineptr == '*') {
361
    lineptr++;
362
    return TOK_STAR;
363
  }
364
  if (*lineptr == '/') {
365
    lineptr++;
366
    return TOK_SLASH;
367
  }
368
  if (*lineptr == '%') {
369
    lineptr++;
370
    return TOK_PERCENT;
371
  }
372
  if (*lineptr == '<' && *(lineptr + 1) == '<') {
373
    lineptr += 2;
374
    return TOK_LSHIFT;
375
  }
376
  if (*lineptr == '>' && *(lineptr + 1) == '>') {
377
    lineptr += 2;
378
    return TOK_RSHIFT;
379
  }
380
  if (*lineptr == '(') {
381
    lineptr++;
382
    return TOK_LPAREN;
383
  }
384
  if (*lineptr == ')') {
385
    lineptr++;
386
    return TOK_RPAREN;
387
  }
388
  if (*lineptr == ',') {
389
    lineptr++;
390
    return TOK_COMMA;
391
  }
392
  if (*lineptr == '~') {
393
    lineptr++;
394
    return TOK_TILDE;
395
  }
396
  if (*lineptr == '&') {
397
    lineptr++;
398
    return TOK_AMPER;
399
  }
400
  if (*lineptr == '|') {
401
    lineptr++;
402
    return TOK_BAR;
403
  }
404
  if (*lineptr == '^') {
405
    lineptr++;
406
    return TOK_CARET;
407
  }
408
  error("illegal character 0x%02X in line %d", *lineptr, lineno);
409
  return 0;
410
}
411
 
412
 
413
void showToken(void) {
414
  printf("DEBUG: ");
415
  switch (token) {
416
    case TOK_EOL:
417
      printf("token = TOK_EOL\n");
418
      break;
419
    case TOK_LABEL:
420
      printf("token = TOK_LABEL, value = %s\n", tokenvalString);
421
      break;
422
    case TOK_IDENT:
423
      printf("token = TOK_IDENT, value = %s\n", tokenvalString);
424
      break;
425
    case TOK_STRING:
426
      printf("token = TOK_STRING, value = %s\n", tokenvalString);
427
      break;
428
    case TOK_NUMBER:
429
      printf("token = TOK_NUMBER, value = 0x%x\n", tokenvalNumber);
430
      break;
431
    case TOK_REGISTER:
432
      printf("token = TOK_REGISTER, value = %d\n", tokenvalNumber);
433
      break;
434
    case TOK_PLUS:
435
      printf("token = TOK_PLUS\n");
436
      break;
437
    case TOK_MINUS:
438
      printf("token = TOK_MINUS\n");
439
      break;
440
    case TOK_STAR:
441
      printf("token = TOK_STAR\n");
442
      break;
443
    case TOK_SLASH:
444
      printf("token = TOK_SLASH\n");
445
      break;
446
    case TOK_PERCENT:
447
      printf("token = TOK_PERCENT\n");
448
      break;
449
    case TOK_LSHIFT:
450
      printf("token = TOK_LSHIFT\n");
451
      break;
452
    case TOK_RSHIFT:
453
      printf("token = TOK_RSHIFT\n");
454
      break;
455
    case TOK_LPAREN:
456
      printf("token = TOK_LPAREN\n");
457
      break;
458
    case TOK_RPAREN:
459
      printf("token = TOK_RPAREN\n");
460
      break;
461
    case TOK_COMMA:
462
      printf("token = TOK_COMMA\n");
463
      break;
464
    case TOK_TILDE:
465
      printf("token = TOK_TILDE\n");
466
      break;
467
    case TOK_AMPER:
468
      printf("token = TOK_AMPER\n");
469
      break;
470
    case TOK_BAR:
471
      printf("token = TOK_BAR\n");
472
      break;
473
    case TOK_CARET:
474
      printf("token = TOK_CARET\n");
475
      break;
476
    default:
477
      error("illegal token %d in showToken()", token);
478
  }
479
}
480
 
481
 
482
void getToken(void) {
483
  token = getNextToken();
484
  if (debugToken) {
485
    showToken();
486
  }
487
}
488
 
489
 
490
static char *tok2str[] = {
491
  "end-of-line",
492
  "label",
493
  "identifier",
494
  "string",
495
  "number",
496
  "register",
497
  "+",
498
  "-",
499
  "*",
500
  "/",
501
  "%",
502
  "<<",
503
  ">>",
504
  "(",
505
  ")",
506
  ",",
507
  "~",
508
  "&",
509
  "|",
510
  "^"
511
};
512
 
513
 
514
void expect(int expected) {
515
  if (token != expected) {
516
    error("'%s' expected, got '%s' in line %d",
517
          tok2str[expected], tok2str[token], lineno);
518
  }
519
}
520
 
521
 
522
/**************************************************************/
523
 
524
 
525
Fixup *fixupList = NULL;
526
 
527
 
528
Fixup *newFixup(int segment, unsigned int offset, int method, int value) {
529
  Fixup *f;
530
 
531
  f = allocateMemory(sizeof(Fixup));
532
  f->segment = segment;
533
  f->offset = offset;
534
  f->method = method;
535
  f->value = value;
536
  f->base = 0;
537
  f->next = NULL;
538
  return f;
539
}
540
 
541
 
542
void addFixup(Symbol *s,
543
              int segment, unsigned int offset, int method, int value) {
544
  Fixup *f;
545
 
546
  if (debugFixup) {
547
    printf("DEBUG: fixup (s:%s, o:%08X, m:%s, v:%08X) added to '%s'\n",
548
           segName[segment], offset, methodName[method], value, s->name);
549
  }
550
  f = newFixup(segment, offset, method, value);
551
  f->next = s->fixups;
552
  s->fixups = f;
553
}
554
 
555
 
556
/**************************************************************/
557
 
558
 
559
Symbol *globalTable = NULL;
560
Symbol *localTable = NULL;
561
 
562
 
563
Symbol *deref(Symbol *s) {
564
  if (s->status == STATUS_GLOBREF) {
565
    return s->globref;
566
  } else {
567
    return s;
568
  }
569
}
570
 
571
 
572
Symbol *newSymbol(char *name) {
573
  Symbol *p;
574
 
575
  p = allocateMemory(sizeof(Symbol));
576
  p->name = allocateMemory(strlen(name) + 1);
577
  strcpy(p->name, name);
578
  p->status = STATUS_UNKNOWN;
579
  p->segment = 0;
580
  p->value = 0;
581
  p->fixups = NULL;
582
  p->globref = NULL;
583
  p->left = NULL;
584
  p->right = NULL;
585
  return p;
586
}
587
 
588
 
589
Symbol *lookupEnter(char *name, int whichTable) {
590
  Symbol *p, *q, *r;
591
  int cmp;
592
 
593
  if (whichTable == GLOBAL_TABLE) {
594
    p = globalTable;
595
  } else {
596
    p = localTable;
597
  }
598
  if (p == NULL) {
599
    r = newSymbol(name);
600
    if (whichTable == GLOBAL_TABLE) {
601
      globalTable = r;
602
    } else {
603
      localTable = r;
604
    }
605
    return r;
606
  }
607
  while (1) {
608
    q = p;
609
    cmp = strcmp(name, q->name);
610
    if (cmp == 0) {
611
      return q;
612
    }
613
    if (cmp < 0) {
614
      p = q->left;
615
    } else {
616
      p = q->right;
617
    }
618
    if (p == NULL) {
619
      r = newSymbol(name);
620
      if (cmp < 0) {
621
        q->left = r;
622
      } else {
623
        q->right = r;
624
      }
625
      return r;
626
    }
627
  }
628
}
629
 
630
 
631
static void linkSymbol(Symbol *s) {
632
  Fixup *f;
633
 
634
  if (s->status == STATUS_UNKNOWN) {
635
    error("undefined symbol '%s'", s->name);
636
  }
637
  if (s->status == STATUS_GLOBREF) {
638
    if (s->fixups != NULL) {
639
      error("local fixups detected with global symbol '%s'", s->name);
640
    }
641
  } else {
642
    if (debugFixup) {
643
      printf("DEBUG: link '%s' (s:%s, v:%08X)\n",
644
             s->name, segName[s->segment], s->value);
645
    }
646
    while (s->fixups != NULL) {
647
      /* get next fixup record */
648
      f = s->fixups;
649
      s->fixups = f->next;
650
      /* add the symbol's value to the value in the record */
651
      /* and remember the symbol's segment */
652
      if (debugFixup) {
653
        printf("       (s:%s, o:%08X, m:%s, v:%08X --> %08X, b:%s)\n",
654
               segName[f->segment], f->offset, methodName[f->method],
655
               f->value, f->value + s->value, segName[s->segment]);
656
      }
657
      f->value += s->value;
658
      f->base = s->segment;
659
      /* transfer the record to the fixup list */
660
      f->next = fixupList;
661
      fixupList = f;
662
    }
663
  }
664
}
665
 
666
 
667
static void linkTree(Symbol *s) {
668
  if (s == NULL) {
669
    return;
670
  }
671
  linkTree(s->left);
672
  linkSymbol(s);
673
  linkTree(s->right);
674
  freeMemory(s->name);
675
  freeMemory(s);
676
}
677
 
678
 
679
void linkLocals(void) {
680
  linkTree(localTable);
681
  localTable = NULL;
682
  fseek(codeFile, 0, SEEK_END);
683
  fseek(dataFile, 0, SEEK_END);
684
}
685
 
686
 
687
/**************************************************************/
688
 
689
 
690
void emitByte(unsigned int byte) {
691
  byte &= 0x000000FF;
692
  if (debugCode) {
693
    printf("DEBUG: byte @ segment = %s, offset = %08X",
694
           segName[currSeg], segPtr[currSeg]);
695
    printf(", value = %02X\n", byte);
696
  }
697
  switch (currSeg) {
698
    case SEGMENT_ABS:
699
      error("illegal segment in emitByte()");
700
      break;
701
    case SEGMENT_CODE:
702
      fputc(byte, codeFile);
703
      break;
704
    case SEGMENT_DATA:
705
      fputc(byte, dataFile);
706
      break;
707
    case SEGMENT_BSS:
708
      break;
709
  }
710
  segPtr[currSeg] += 1;
711
}
712
 
713
 
714
void emitHalf(unsigned int half) {
715
  half &= 0x0000FFFF;
716
  if (debugCode) {
717
    printf("DEBUG: half @ segment = %s, offset = %08X",
718
           segName[currSeg], segPtr[currSeg]);
719
    printf(", value = %02X%02X\n",
720
           (half >> 8) & 0xFF, half & 0xFF);
721
  }
722
  switch (currSeg) {
723
    case SEGMENT_ABS:
724
      error("illegal segment in emitHalf()");
725
      break;
726
    case SEGMENT_CODE:
727
      fputc((half >> 8) & 0xFF, codeFile);
728
      fputc(half & 0xFF, codeFile);
729
      break;
730
    case SEGMENT_DATA:
731
      fputc((half >> 8) & 0xFF, dataFile);
732
      fputc(half & 0xFF, dataFile);
733
      break;
734
    case SEGMENT_BSS:
735
      break;
736
  }
737
  segPtr[currSeg] += 2;
738
}
739
 
740
 
741
void emitWord(unsigned int word) {
742
  if (debugCode) {
743
    printf("DEBUG: word @ segment = %s, offset = %08X",
744
           segName[currSeg], segPtr[currSeg]);
745
    printf(", value = %02X%02X%02X%02X\n",
746
           (word >> 24) & 0xFF, (word >> 16) & 0xFF,
747
           (word >> 8) & 0xFF, word & 0xFF);
748
  }
749
  switch (currSeg) {
750
    case SEGMENT_ABS:
751
      error("illegal segment in emitWord()");
752
      break;
753
    case SEGMENT_CODE:
754
      fputc((word >> 24) & 0xFF, codeFile);
755
      fputc((word >> 16) & 0xFF, codeFile);
756
      fputc((word >> 8) & 0xFF, codeFile);
757
      fputc(word & 0xFF, codeFile);
758
      break;
759
    case SEGMENT_DATA:
760
      fputc((word >> 24) & 0xFF, dataFile);
761
      fputc((word >> 16) & 0xFF, dataFile);
762
      fputc((word >> 8) & 0xFF, dataFile);
763
      fputc(word & 0xFF, dataFile);
764
      break;
765
    case SEGMENT_BSS:
766
      break;
767
  }
768
  segPtr[currSeg] += 4;
769
}
770
 
771
 
772
/**************************************************************/
773
 
774
 
775
typedef struct {
776
  int con;
777
  Symbol *sym;
778
} Value;
779
 
780
 
781
Value parseExpression(void);
782
 
783
 
784
Value parsePrimaryExpression(void) {
785
  Value v;
786
  Symbol *s;
787
 
788
  if (token == TOK_NUMBER) {
789
    v.con = tokenvalNumber;
790
    v.sym = NULL;
791
    getToken();
792
  } else
793
  if (token == TOK_IDENT) {
794
    s = deref(lookupEnter(tokenvalString, LOCAL_TABLE));
795
    if (s->status == STATUS_DEFINED && s->segment == SEGMENT_ABS) {
796
      v.con = s->value;
797
      v.sym = NULL;
798
    } else {
799
      v.con = 0;
800
      v.sym = s;
801
    }
802
    getToken();
803
  } else
804
  if (token == TOK_LPAREN) {
805
    getToken();
806
    v = parseExpression();
807
    expect(TOK_RPAREN);
808
    getToken();
809
  } else {
810
    error("illegal primary expression, line %d", lineno);
811
  }
812
  return v;
813
}
814
 
815
 
816
Value parseUnaryExpression(void) {
817
  Value v;
818
 
819
  if (token == TOK_PLUS) {
820
    getToken();
821
    v = parseUnaryExpression();
822
  } else
823
  if (token == TOK_MINUS) {
824
    getToken();
825
    v = parseUnaryExpression();
826
    if (v.sym != NULL) {
827
      error("cannot negate symbol '%s' in line %d", v.sym->name, lineno);
828
    }
829
    v.con = -v.con;
830
  } else
831
  if (token == TOK_TILDE) {
832
    getToken();
833
    v = parseUnaryExpression();
834
    if (v.sym != NULL) {
835
      error("cannot complement symbol '%s' in line %d", v.sym->name, lineno);
836
    }
837
    v.con = ~v.con;
838
  } else {
839
    v = parsePrimaryExpression();
840
  }
841
  return v;
842
}
843
 
844
 
845
Value parseMultiplicativeExpression(void) {
846
  Value v1, v2;
847
 
848
  v1 = parseUnaryExpression();
849
  while (token == TOK_STAR || token == TOK_SLASH || token == TOK_PERCENT) {
850
    if (token == TOK_STAR) {
851
      getToken();
852
      v2 = parseUnaryExpression();
853
      if (v1.sym != NULL || v2.sym != NULL) {
854
        error("multiplication of symbols not supported, line %d", lineno);
855
      }
856
      v1.con *= v2.con;
857
    } else
858
    if (token == TOK_SLASH) {
859
      getToken();
860
      v2 = parseUnaryExpression();
861
      if (v1.sym != NULL || v2.sym != NULL) {
862
        error("division of symbols not supported, line %d", lineno);
863
      }
864
      if (v2.con == 0) {
865
        error("division by zero, line %d", lineno);
866
      }
867
      v1.con /= v2.con;
868
    } else
869
    if (token == TOK_PERCENT) {
870
      getToken();
871
      v2 = parseUnaryExpression();
872
      if (v1.sym != NULL || v2.sym != NULL) {
873
        error("division of symbols not supported, line %d", lineno);
874
      }
875
      if (v2.con == 0) {
876
        error("division by zero, line %d", lineno);
877
      }
878
      v1.con %= v2.con;
879
    }
880
  }
881
  return v1;
882
}
883
 
884
 
885
Value parseAdditiveExpression(void) {
886
  Value v1, v2;
887
 
888
  v1 = parseMultiplicativeExpression();
889
  while (token == TOK_PLUS || token == TOK_MINUS) {
890
    if (token == TOK_PLUS) {
891
      getToken();
892
      v2 = parseMultiplicativeExpression();
893
      if (v1.sym != NULL && v2.sym != NULL) {
894
        error("addition of symbols not supported, line %d", lineno);
895
      }
896
      if (v2.sym != NULL) {
897
        v1.sym = v2.sym;
898
      }
899
      v1.con += v2.con;
900
    } else
901
    if (token == TOK_MINUS) {
902
      getToken();
903
      v2 = parseMultiplicativeExpression();
904
      if (v2.sym != NULL) {
905
        error("subtraction of symbols not supported, line %d", lineno);
906
      }
907
      v1.con -= v2.con;
908
    }
909
  }
910
  return v1;
911
}
912
 
913
 
914
Value parseShiftExpression(void) {
915
  Value v1, v2;
916
 
917
  v1 = parseAdditiveExpression();
918
  while (token == TOK_LSHIFT || token == TOK_RSHIFT) {
919
    if (token == TOK_LSHIFT) {
920
      getToken();
921
      v2 = parseAdditiveExpression();
922
      if (v1.sym != NULL || v2.sym != NULL) {
923
        error("shifting of symbols not supported, line %d", lineno);
924
      }
925
      v1.con <<= v2.con;
926
    } else
927
    if (token == TOK_RSHIFT) {
928
      getToken();
929
      v2 = parseAdditiveExpression();
930
      if (v1.sym != NULL || v2.sym != NULL) {
931
        error("shifting of symbols not supported, line %d", lineno);
932
      }
933
      v1.con >>= v2.con;
934
    }
935
  }
936
  return v1;
937
}
938
 
939
 
940
Value parseAndExpression(void) {
941
  Value v1, v2;
942
 
943
  v1 = parseShiftExpression();
944
  while (token == TOK_AMPER) {
945
    getToken();
946
    v2 = parseShiftExpression();
947
    if (v2.sym != NULL) {
948
      error("bitwise 'and' of symbols not supported, line %d", lineno);
949
    }
950
    v1.con &= v2.con;
951
  }
952
  return v1;
953
}
954
 
955
 
956
Value parseExclusiveOrExpression(void) {
957
  Value v1, v2;
958
 
959
  v1 = parseAndExpression();
960
  while (token == TOK_CARET) {
961
    getToken();
962
    v2 = parseAndExpression();
963
    if (v2.sym != NULL) {
964
      error("bitwise 'xor' of symbols not supported, line %d", lineno);
965
    }
966
    v1.con ^= v2.con;
967
  }
968
  return v1;
969
}
970
 
971
 
972
Value parseInclusiveOrExpression(void) {
973
  Value v1, v2;
974
 
975
  v1 = parseExclusiveOrExpression();
976
  while (token == TOK_BAR) {
977
    getToken();
978
    v2 = parseExclusiveOrExpression();
979
    if (v2.sym != NULL) {
980
      error("bitwise 'or' of symbols not supported, line %d", lineno);
981
    }
982
    v1.con |= v2.con;
983
  }
984
  return v1;
985
}
986
 
987
 
988
Value parseExpression(void) {
989
  Value v;
990
 
991
  v = parseInclusiveOrExpression();
992
  return v;
993
}
994
 
995
 
996
/**************************************************************/
997
 
998
 
999
void dotSyn(unsigned int code) {
1000
  allowSyn = 1;
1001
}
1002
 
1003
 
1004
void dotNosyn(unsigned int code) {
1005
  allowSyn = 0;
1006
}
1007
 
1008
 
1009
void dotCode(unsigned int code) {
1010
  currSeg = SEGMENT_CODE;
1011
}
1012
 
1013
 
1014
void dotData(unsigned int code) {
1015
  currSeg = SEGMENT_DATA;
1016
}
1017
 
1018
 
1019
void dotBss(unsigned int code) {
1020
  currSeg = SEGMENT_BSS;
1021
}
1022
 
1023
 
1024
void dotExport(unsigned int code) {
1025
  Symbol *global;
1026
  Symbol *local;
1027
  Fixup *f;
1028
 
1029
  while (1) {
1030
    expect(TOK_IDENT);
1031
    global = lookupEnter(tokenvalString, GLOBAL_TABLE);
1032
    if (global->status != STATUS_UNKNOWN) {
1033
      error("exported symbol '%s' multiply defined in line %d",
1034
            global->name, lineno);
1035
    }
1036
    local = lookupEnter(tokenvalString, LOCAL_TABLE);
1037
    if (local->status == STATUS_GLOBREF) {
1038
      error("exported symbol '%s' multiply exported in line %d",
1039
            local->name, lineno);
1040
    }
1041
    global->status = local->status;
1042
    global->segment = local->segment;
1043
    global->value = local->value;
1044
    while (local->fixups != NULL) {
1045
      f = local->fixups;
1046
      local->fixups = f->next;
1047
      f->next = global->fixups;
1048
      global->fixups = f;
1049
    }
1050
    local->status = STATUS_GLOBREF;
1051
    local->globref = global;
1052
    getToken();
1053
    if (token != TOK_COMMA) {
1054
      break;
1055
    }
1056
    getToken();
1057
  }
1058
}
1059
 
1060
 
1061
void dotImport(unsigned int code) {
1062
  Symbol *global;
1063
  Symbol *local;
1064
  Fixup *f;
1065
 
1066
  while (1) {
1067
    expect(TOK_IDENT);
1068
    global = lookupEnter(tokenvalString, GLOBAL_TABLE);
1069
    local = lookupEnter(tokenvalString, LOCAL_TABLE);
1070
    if (local->status != STATUS_UNKNOWN) {
1071
      error("imported symbol '%s' multiply defined in line %d",
1072
            local->name, lineno);
1073
    }
1074
    while (local->fixups != NULL) {
1075
      f = local->fixups;
1076
      local->fixups = f->next;
1077
      f->next = global->fixups;
1078
      global->fixups = f;
1079
    }
1080
    local->status = STATUS_GLOBREF;
1081
    local->globref = global;
1082
    getToken();
1083
    if (token != TOK_COMMA) {
1084
      break;
1085
    }
1086
    getToken();
1087
  }
1088
}
1089
 
1090
 
1091
int countBits(unsigned int x) {
1092
  int n;
1093
 
1094
  n = 0;
1095
  while (x != 0) {
1096
    x &= x - 1;
1097
    n++;
1098
  }
1099
  return n;
1100
}
1101
 
1102
 
1103
void dotAlign(unsigned int code) {
1104
  Value v;
1105
  unsigned int mask;
1106
 
1107
  v = parseExpression();
1108
  if (v.sym != NULL) {
1109
    error("absolute expression expected in line %d", lineno);
1110
  }
1111
  if (countBits(v.con) != 1) {
1112
    error("argument must be a power of 2 in line %d", lineno);
1113
  }
1114
  mask = v.con - 1;
1115
  while ((segPtr[currSeg] & mask) != 0) {
1116
    emitByte(0);
1117
  }
1118
}
1119
 
1120
 
1121
void dotSpace(unsigned int code) {
1122
  Value v;
1123
  int i;
1124
 
1125
  v = parseExpression();
1126
  if (v.sym != NULL) {
1127
    error("absolute expression expected in line %d", lineno);
1128
  }
1129
  for (i = 0; i < v.con; i++) {
1130
    emitByte(0);
1131
  }
1132
}
1133
 
1134
 
1135
void dotLocate(unsigned int code) {
1136
  Value v;
1137
 
1138
  v = parseExpression();
1139
  if (v.sym != NULL) {
1140
    error("absolute expression expected in line %d", lineno);
1141
  }
1142
  while (segPtr[currSeg] != v.con) {
1143
    emitByte(0);
1144
  }
1145
}
1146
 
1147
 
1148
void dotByte(unsigned int code) {
1149
  Value v;
1150
  char *p;
1151
 
1152
  while (1) {
1153
    if (token == TOK_STRING) {
1154
      p = tokenvalString;
1155
      while (*p != '\0') {
1156
        emitByte(*p);
1157
        p++;
1158
      }
1159
      getToken();
1160
    } else {
1161
      v = parseExpression();
1162
      if (v.sym != NULL) {
1163
        error("absolute expression expected in line %d", lineno);
1164
      }
1165
      emitByte(v.con);
1166
    }
1167
    if (token != TOK_COMMA) {
1168
      break;
1169
    }
1170
    getToken();
1171
  }
1172
}
1173
 
1174
 
1175
void dotHalf(unsigned int code) {
1176
  Value v;
1177
 
1178
  while (1) {
1179
    v = parseExpression();
1180
    if (v.sym != NULL) {
1181
      error("absolute expression expected in line %d", lineno);
1182
    }
1183
    emitHalf(v.con);
1184
    if (token != TOK_COMMA) {
1185
      break;
1186
    }
1187
    getToken();
1188
  }
1189
}
1190
 
1191
 
1192
void dotWord(unsigned int code) {
1193
  Value v;
1194
 
1195
  while (1) {
1196
    v = parseExpression();
1197
    if (v.sym == NULL) {
1198
      emitWord(v.con);
1199
    } else {
1200
      addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_W32, v.con);
1201
      emitWord(0);
1202
    }
1203
    if (token != TOK_COMMA) {
1204
      break;
1205
    }
1206
    getToken();
1207
  }
1208
}
1209
 
1210
 
1211
void dotSet(unsigned int code) {
1212
  Value v;
1213
  Symbol *symbol;
1214
 
1215
  expect(TOK_IDENT);
1216
  symbol = deref(lookupEnter(tokenvalString, LOCAL_TABLE));
1217
  if (symbol->status != STATUS_UNKNOWN) {
1218
    error("symbol '%s' multiply defined in line %d",
1219
          symbol->name, lineno);
1220
  }
1221
  getToken();
1222
  expect(TOK_COMMA);
1223
  getToken();
1224
  v = parseExpression();
1225
  if (v.sym == NULL) {
1226
    symbol->status = STATUS_DEFINED;
1227
    symbol->segment = SEGMENT_ABS;
1228
    symbol->value = v.con;
1229
  } else {
1230
    error("illegal type of symbol '%s' in expression, line %d",
1231
          v.sym->name, lineno);
1232
  }
1233
}
1234
 
1235
 
1236
void formatN(unsigned int code) {
1237
  Value v;
1238
  unsigned int immed;
1239
 
1240
  /* opcode with no operands */
1241
  if (token != TOK_EOL) {
1242
    /* in exceptional cases (trap) there may be one constant operand */
1243
    v = parseExpression();
1244
    if (v.sym != NULL) {
1245
      error("operand must be a constant, line %d", lineno);
1246
    }
1247
    immed = v.con;
1248
  } else {
1249
    immed = 0;
1250
  }
1251
  emitWord(code << 26 | (immed & 0x03FFFFFF));
1252
}
1253
 
1254
 
1255
void formatRH(unsigned int code) {
1256
  int reg;
1257
  Value v;
1258
 
1259
  /* opcode with one register and a half operand */
1260
  expect(TOK_REGISTER);
1261
  reg = tokenvalNumber;
1262
  getToken();
1263
  expect(TOK_COMMA);
1264
  getToken();
1265
  v = parseExpression();
1266
  if (v.sym == NULL) {
1267
    emitHalf(code << 10 | reg);
1268
    emitHalf(v.con);
1269
  } else {
1270
    addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con);
1271
    emitHalf(code << 10 | reg);
1272
    emitHalf(0);
1273
  }
1274
}
1275
 
1276
 
1277
void formatRHH(unsigned int code) {
1278
  int reg;
1279
  Value v;
1280
 
1281
  /* opcode with one register and a half operand */
1282
  /* ATTENTION: high order 16 bits encoded in instruction */
1283
  expect(TOK_REGISTER);
1284
  reg = tokenvalNumber;
1285
  getToken();
1286
  expect(TOK_COMMA);
1287
  getToken();
1288
  v = parseExpression();
1289
  if (v.sym == NULL) {
1290
    emitHalf(code << 10 | reg);
1291
    emitHalf(v.con >> 16);
1292
  } else {
1293
    addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_H16, v.con);
1294
    emitHalf(code << 10 | reg);
1295
    emitHalf(0);
1296
  }
1297
}
1298
 
1299
 
1300
void formatRRH(unsigned int code) {
1301
  int dst, src;
1302
  Value v;
1303
 
1304
  /* opcode with two registers and a half operand */
1305
  expect(TOK_REGISTER);
1306
  dst = tokenvalNumber;
1307
  getToken();
1308
  expect(TOK_COMMA);
1309
  getToken();
1310
  expect(TOK_REGISTER);
1311
  src = tokenvalNumber;
1312
  getToken();
1313
  expect(TOK_COMMA);
1314
  getToken();
1315
  v = parseExpression();
1316
  if (allowSyn) {
1317
    if (v.sym == NULL) {
1318
      if ((v.con & 0xFFFF0000) == 0) {
1319
        /* code: op dst,src,con */
1320
        emitHalf(code << 10 | src << 5 | dst);
1321
        emitHalf(v.con);
1322
      } else {
1323
        /* code: ldhi $1,con; or $1,$1,con; add $1,$1,src; op dst,$1,0 */
1324
        emitHalf(OP_LDHI << 10 | AUX_REG);
1325
        emitHalf(v.con >> 16);
1326
        emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG);
1327
        emitHalf(v.con);
1328
        emitHalf(OP_ADD << 10 | AUX_REG << 5 | src);
1329
        emitHalf(AUX_REG << 11);
1330
        emitHalf(code << 10 | AUX_REG << 5 | dst);
1331
        emitHalf(0);
1332
      }
1333
    } else {
1334
      /* code: ldhi $1,con; or $1,$1,con; add $1,$1,src; op dst,$1,0 */
1335
      addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_H16, v.con);
1336
      emitHalf(OP_LDHI << 10 | AUX_REG);
1337
      emitHalf(0);
1338
      addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con);
1339
      emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG);
1340
      emitHalf(0);
1341
      emitHalf(OP_ADD << 10 | AUX_REG << 5 | src);
1342
      emitHalf(AUX_REG << 11);
1343
      emitHalf(code << 10 | AUX_REG << 5 | dst);
1344
      emitHalf(0);
1345
    }
1346
  } else {
1347
    if (v.sym == NULL) {
1348
      emitHalf(code << 10 | src << 5 | dst);
1349
      emitHalf(v.con);
1350
    } else {
1351
      addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con);
1352
      emitHalf(code << 10 | src << 5 | dst);
1353
      emitHalf(0);
1354
    }
1355
  }
1356
}
1357
 
1358
 
1359
void formatRRS(unsigned int code) {
1360
  int dst, src;
1361
  Value v;
1362
 
1363
  /* opcode with two registers and a signed half operand */
1364
  expect(TOK_REGISTER);
1365
  dst = tokenvalNumber;
1366
  getToken();
1367
  expect(TOK_COMMA);
1368
  getToken();
1369
  expect(TOK_REGISTER);
1370
  src = tokenvalNumber;
1371
  getToken();
1372
  expect(TOK_COMMA);
1373
  getToken();
1374
  v = parseExpression();
1375
  if (allowSyn) {
1376
    if (v.sym == NULL) {
1377
      if ((v.con & 0xFFFF8000) == 0x00000000 ||
1378
          (v.con & 0xFFFF8000) == 0xFFFF8000) {
1379
        /* code: op dst,src,con */
1380
        emitHalf(code << 10 | src << 5 | dst);
1381
        emitHalf(v.con);
1382
      } else {
1383
        /* code: ldhi $1,con; or $1,$1,con; add $1,$1,src; op dst,$1,0 */
1384
        emitHalf(OP_LDHI << 10 | AUX_REG);
1385
        emitHalf(v.con >> 16);
1386
        emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG);
1387
        emitHalf(v.con);
1388
        emitHalf(OP_ADD << 10 | AUX_REG << 5 | src);
1389
        emitHalf(AUX_REG << 11);
1390
        emitHalf(code << 10 | AUX_REG << 5 | dst);
1391
        emitHalf(0);
1392
      }
1393
    } else {
1394
      /* code: ldhi $1,con; or $1,$1,con; add $1,$1,src; op dst,$1,0 */
1395
      addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_H16, v.con);
1396
      emitHalf(OP_LDHI << 10 | AUX_REG);
1397
      emitHalf(0);
1398
      addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con);
1399
      emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG);
1400
      emitHalf(0);
1401
      emitHalf(OP_ADD << 10 | AUX_REG << 5 | src);
1402
      emitHalf(AUX_REG << 11);
1403
      emitHalf(code << 10 | AUX_REG << 5 | dst);
1404
      emitHalf(0);
1405
    }
1406
  } else {
1407
    if (v.sym == NULL) {
1408
      emitHalf(code << 10 | src << 5 | dst);
1409
      emitHalf(v.con);
1410
    } else {
1411
      addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con);
1412
      emitHalf(code << 10 | src << 5 | dst);
1413
      emitHalf(0);
1414
    }
1415
  }
1416
}
1417
 
1418
 
1419
void formatRRR(unsigned int code) {
1420
  int dst, src1, src2;
1421
 
1422
  /* opcode with three register operands */
1423
  expect(TOK_REGISTER);
1424
  dst = tokenvalNumber;
1425
  getToken();
1426
  expect(TOK_COMMA);
1427
  getToken();
1428
  expect(TOK_REGISTER);
1429
  src1 = tokenvalNumber;
1430
  getToken();
1431
  expect(TOK_COMMA);
1432
  getToken();
1433
  expect(TOK_REGISTER);
1434
  src2 = tokenvalNumber;
1435
  getToken();
1436
  emitHalf(code << 10 | src1 << 5 | src2);
1437
  emitHalf(dst << 11);
1438
}
1439
 
1440
 
1441
void formatRRX(unsigned int code) {
1442
  int dst, src1, src2;
1443
  Value v;
1444
 
1445
  /* opcode with three register operands
1446
     or two registers and a half operand */
1447
  expect(TOK_REGISTER);
1448
  dst = tokenvalNumber;
1449
  getToken();
1450
  expect(TOK_COMMA);
1451
  getToken();
1452
  expect(TOK_REGISTER);
1453
  src1 = tokenvalNumber;
1454
  getToken();
1455
  expect(TOK_COMMA);
1456
  getToken();
1457
  if (token == TOK_REGISTER) {
1458
    src2 = tokenvalNumber;
1459
    getToken();
1460
    emitHalf(code << 10 | src1 << 5 | src2);
1461
    emitHalf(dst << 11);
1462
  } else {
1463
    v = parseExpression();
1464
    if (allowSyn) {
1465
      if (v.sym == NULL) {
1466
        if ((v.con & 0xFFFF0000) == 0) {
1467
          /* code: op dst,src,con */
1468
          emitHalf((code + 1) << 10 | src1 << 5 | dst);
1469
          emitHalf(v.con);
1470
        } else {
1471
          if ((v.con & 0x0000FFFF) == 0) {
1472
            /* code: ldhi $1,con; op dst,src,$1 */
1473
            emitHalf(OP_LDHI << 10 | AUX_REG);
1474
            emitHalf(v.con >> 16);
1475
            emitHalf(code << 10 | src1 << 5 | AUX_REG);
1476
            emitHalf(dst << 11);
1477
          } else {
1478
            /* code: ldhi $1,con; or $1,$1,con; op dst,src,$1 */
1479
            emitHalf(OP_LDHI << 10 | AUX_REG);
1480
            emitHalf(v.con >> 16);
1481
            emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG);
1482
            emitHalf(v.con);
1483
            emitHalf(code << 10 | src1 << 5 | AUX_REG);
1484
            emitHalf(dst << 11);
1485
          }
1486
        }
1487
      } else {
1488
        /* code: ldhi $1,con; or $1,$1,con; op dst,src,$1 */
1489
        addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_H16, v.con);
1490
        emitHalf(OP_LDHI << 10 | AUX_REG);
1491
        emitHalf(0);
1492
        addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con);
1493
        emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG);
1494
        emitHalf(0);
1495
        emitHalf(code << 10 | src1 << 5 | AUX_REG);
1496
        emitHalf(dst << 11);
1497
      }
1498
    } else {
1499
      if (v.sym == NULL) {
1500
        emitHalf((code + 1) << 10 | src1 << 5 | dst);
1501
        emitHalf(v.con);
1502
      } else {
1503
        addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con);
1504
        emitHalf((code + 1) << 10 | src1 << 5 | dst);
1505
        emitHalf(0);
1506
      }
1507
    }
1508
  }
1509
}
1510
 
1511
 
1512
void formatRRY(unsigned int code) {
1513
  int dst, src1, src2;
1514
  Value v;
1515
 
1516
  /* opcode with three register operands
1517
     or two registers and a signed half operand */
1518
  expect(TOK_REGISTER);
1519
  dst = tokenvalNumber;
1520
  getToken();
1521
  expect(TOK_COMMA);
1522
  getToken();
1523
  expect(TOK_REGISTER);
1524
  src1 = tokenvalNumber;
1525
  getToken();
1526
  expect(TOK_COMMA);
1527
  getToken();
1528
  if (token == TOK_REGISTER) {
1529
    src2 = tokenvalNumber;
1530
    getToken();
1531
    emitHalf(code << 10 | src1 << 5 | src2);
1532
    emitHalf(dst << 11);
1533
  } else {
1534
    v = parseExpression();
1535
    if (allowSyn) {
1536
      if (v.sym == NULL) {
1537
        if ((v.con & 0xFFFF8000) == 0x00000000 ||
1538
            (v.con & 0xFFFF8000) == 0xFFFF8000) {
1539
          /* code: op dst,src,con */
1540
          emitHalf((code + 1) << 10 | src1 << 5 | dst);
1541
          emitHalf(v.con);
1542
        } else {
1543
          if ((v.con & 0x0000FFFF) == 0) {
1544
            /* code: ldhi $1,con; op dst,src,$1 */
1545
            emitHalf(OP_LDHI << 10 | AUX_REG);
1546
            emitHalf(v.con >> 16);
1547
            emitHalf(code << 10 | src1 << 5 | AUX_REG);
1548
            emitHalf(dst << 11);
1549
          } else {
1550
            /* code: ldhi $1,con; or $1,$1,con; op dst,src,$1 */
1551
            emitHalf(OP_LDHI << 10 | AUX_REG);
1552
            emitHalf(v.con >> 16);
1553
            emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG);
1554
            emitHalf(v.con);
1555
            emitHalf(code << 10 | src1 << 5 | AUX_REG);
1556
            emitHalf(dst << 11);
1557
          }
1558
        }
1559
      } else {
1560
        /* code: ldhi $1,con; or $1,$1,con; op dst,src,$1 */
1561
        addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_H16, v.con);
1562
        emitHalf(OP_LDHI << 10 | AUX_REG);
1563
        emitHalf(0);
1564
        addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con);
1565
        emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG);
1566
        emitHalf(0);
1567
        emitHalf(code << 10 | src1 << 5 | AUX_REG);
1568
        emitHalf(dst << 11);
1569
      }
1570
    } else {
1571
      if (v.sym == NULL) {
1572
        emitHalf((code + 1) << 10 | src1 << 5 | dst);
1573
        emitHalf(v.con);
1574
      } else {
1575
        addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con);
1576
        emitHalf((code + 1) << 10 | src1 << 5 | dst);
1577
        emitHalf(0);
1578
      }
1579
    }
1580
  }
1581
}
1582
 
1583
 
1584
void formatRRB(unsigned int code) {
1585
  int src1, src2;
1586
  Value v;
1587
  unsigned int immed;
1588
 
1589
  /* opcode with two registers and a 16 bit signed offset operand */
1590
  expect(TOK_REGISTER);
1591
  src1 = tokenvalNumber;
1592
  getToken();
1593
  expect(TOK_COMMA);
1594
  getToken();
1595
  expect(TOK_REGISTER);
1596
  src2 = tokenvalNumber;
1597
  getToken();
1598
  expect(TOK_COMMA);
1599
  getToken();
1600
  v = parseExpression();
1601
  if (v.sym == NULL) {
1602
    immed = (v.con - ((signed) segPtr[currSeg] + 4)) / 4;
1603
  } else {
1604
    addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_R16, v.con);
1605
    immed = 0;
1606
  }
1607
  emitHalf(code << 10 | src1 << 5 | src2);
1608
  emitHalf(immed);
1609
}
1610
 
1611
 
1612
void formatJ(unsigned int code) {
1613
  Value v;
1614
  unsigned int immed;
1615
  int target;
1616
 
1617
  /* opcode with no registers and a 26 bit signed offset operand or
1618
     opcode with a single register */
1619
  if (token == TOK_REGISTER) {
1620
    target = tokenvalNumber;
1621
    getToken();
1622
    emitWord((code + 1) << 26 | target << 21);
1623
  } else {
1624
    v = parseExpression();
1625
    if (v.sym == NULL) {
1626
      immed = (v.con - ((signed) segPtr[currSeg] + 4)) / 4;
1627
    } else {
1628
      addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_R26, v.con);
1629
      immed = 0;
1630
    }
1631
    emitWord(code << 26 | (immed & 0x03FFFFFF));
1632
  }
1633
}
1634
 
1635
 
1636
void formatJR(unsigned int code) {
1637
  int target;
1638
 
1639
  /* opcode with one register operand */
1640
  expect(TOK_REGISTER);
1641
  target = tokenvalNumber;
1642
  getToken();
1643
  emitWord(code << 26 | target << 21);
1644
}
1645
 
1646
 
1647
typedef struct instr {
1648
  char *name;
1649
  void (*func)(unsigned int code);
1650
  unsigned int code;
1651
} Instr;
1652
 
1653
 
1654
Instr instrTable[] = {
1655
 
1656
  /* pseudo instructions */
1657
  { ".syn",    dotSyn,    0 },
1658
  { ".nosyn",  dotNosyn,  0 },
1659
  { ".code",   dotCode,   0 },
1660
  { ".data",   dotData,   0 },
1661
  { ".bss",    dotBss,    0 },
1662
  { ".export", dotExport, 0 },
1663
  { ".import", dotImport, 0 },
1664
  { ".align",  dotAlign,  0 },
1665
  { ".space",  dotSpace,  0 },
1666
  { ".locate", dotLocate, 0 },
1667
  { ".byte",   dotByte,   0 },
1668
  { ".half",   dotHalf,   0 },
1669
  { ".word",   dotWord,   0 },
1670
  { ".set",    dotSet,    0 },
1671
 
1672
  /* arithmetical instructions */
1673
  { "add",     formatRRY, OP_ADD  },
1674
  { "sub",     formatRRY, OP_SUB  },
1675
 
1676
  { "mul",     formatRRY, OP_MUL  },
1677
  { "mulu",    formatRRX, OP_MULU },
1678
  { "div",     formatRRY, OP_DIV  },
1679
  { "divu",    formatRRX, OP_DIVU },
1680
  { "rem",     formatRRY, OP_REM  },
1681
  { "remu",    formatRRX, OP_REMU },
1682
 
1683
  /* logical instructions */
1684
  { "and",     formatRRX, OP_AND  },
1685
  { "or",      formatRRX, OP_OR   },
1686
  { "xor",     formatRRX, OP_XOR  },
1687
  { "xnor",    formatRRX, OP_XNOR },
1688
 
1689
  /* shift instructions */
1690
  { "sll",     formatRRX, OP_SLL  },
1691
  { "slr",     formatRRX, OP_SLR  },
1692
  { "sar",     formatRRX, OP_SAR  },
1693
 
1694
  /* load immediate instructions */
1695
  { "ldhi",    formatRHH, OP_LDHI },
1696
 
1697
  /* branch instructions */
1698
  { "beq",     formatRRB, OP_BEQ  },
1699
  { "bne",     formatRRB, OP_BNE  },
1700
  { "ble",     formatRRB, OP_BLE  },
1701
  { "bleu",    formatRRB, OP_BLEU },
1702
  { "blt",     formatRRB, OP_BLT  },
1703
  { "bltu",    formatRRB, OP_BLTU },
1704
  { "bge",     formatRRB, OP_BGE  },
1705
  { "bgeu",    formatRRB, OP_BGEU },
1706
  { "bgt",     formatRRB, OP_BGT  },
1707
  { "bgtu",    formatRRB, OP_BGTU },
1708
 
1709
  /* jump, call & return instructions */
1710
  { "j",       formatJ,   OP_J    },
1711
  { "jr",      formatJR,  OP_JR   },
1712
  { "jal",     formatJ,   OP_JAL  },
1713
  { "jalr",    formatJR,  OP_JALR },
1714
 
1715
  /* interrupt related instructions */
1716
  { "trap",    formatN,   OP_TRAP },
1717
  { "rfx",     formatN,   OP_RFX  },
1718
 
1719
  /* load instructions */
1720
  { "ldw",     formatRRS, OP_LDW  },
1721
  { "ldh",     formatRRS, OP_LDH  },
1722
  { "ldhu",    formatRRS, OP_LDHU },
1723
  { "ldb",     formatRRS, OP_LDB  },
1724
  { "ldbu",    formatRRS, OP_LDBU },
1725
 
1726
  /* store instructions */
1727
  { "stw",     formatRRS, OP_STW  },
1728
  { "sth",     formatRRS, OP_STH  },
1729
  { "stb",     formatRRS, OP_STB  },
1730
 
1731
  /* processor control instructions */
1732
  { "mvfs",    formatRH,  OP_MVFS },
1733
  { "mvts",    formatRH,  OP_MVTS },
1734
  { "tbs",     formatN,   OP_TBS  },
1735
  { "tbwr",    formatN,   OP_TBWR },
1736
  { "tbri",    formatN,   OP_TBRI },
1737
  { "tbwi",    formatN,   OP_TBWI }
1738
 
1739
};
1740
 
1741
 
1742
static int cmpInstr(const void *instr1, const void *instr2) {
1743
  return strcmp(((Instr *) instr1)->name, ((Instr *) instr2)->name);
1744
}
1745
 
1746
 
1747
void sortInstrTable(void) {
1748
  qsort(instrTable, sizeof(instrTable)/sizeof(instrTable[0]),
1749
        sizeof(instrTable[0]), cmpInstr);
1750
}
1751
 
1752
 
1753
Instr *lookupInstr(char *name) {
1754
  int lo, hi, tst;
1755
  int res;
1756
 
1757
  lo = 0;
1758
  hi = sizeof(instrTable) / sizeof(instrTable[0]) - 1;
1759
  while (lo <= hi) {
1760
    tst = (lo + hi) / 2;
1761
    res = strcmp(instrTable[tst].name, name);
1762
    if (res == 0) {
1763
      return &instrTable[tst];
1764
    }
1765
    if (res < 0) {
1766
      lo = tst + 1;
1767
    } else {
1768
      hi = tst - 1;
1769
    }
1770
  }
1771
  return NULL;
1772
}
1773
 
1774
 
1775
/**************************************************************/
1776
 
1777
 
1778
void roundupSegments(void) {
1779
  while (segPtr[SEGMENT_CODE] & 3) {
1780
    fputc(0, codeFile);
1781
    segPtr[SEGMENT_CODE] += 1;
1782
  }
1783
  while (segPtr[SEGMENT_DATA] & 3) {
1784
    fputc(0, dataFile);
1785
    segPtr[SEGMENT_DATA] += 1;
1786
  }
1787
  while (segPtr[SEGMENT_BSS] & 3) {
1788
    segPtr[SEGMENT_BSS] += 1;
1789
  }
1790
}
1791
 
1792
 
1793
void asmModule(void) {
1794
  Symbol *label;
1795
  Instr *instr;
1796
 
1797
  allowSyn = 1;
1798
  currSeg = SEGMENT_CODE;
1799
  lineno = 0;
1800
  while (fgets(line, LINE_SIZE, inFile) != NULL) {
1801
    lineno++;
1802
    lineptr = line;
1803
    getToken();
1804
    while (token == TOK_LABEL) {
1805
      label = deref(lookupEnter(tokenvalString, LOCAL_TABLE));
1806
      if (label->status != STATUS_UNKNOWN) {
1807
        error("label '%s' multiply defined in line %d",
1808
              label->name, lineno);
1809
      }
1810
      label->status = STATUS_DEFINED;
1811
      label->segment = currSeg;
1812
      label->value = segPtr[currSeg];
1813
      getToken();
1814
    }
1815
    if (token == TOK_IDENT) {
1816
      instr = lookupInstr(tokenvalString);
1817
      if (instr == NULL) {
1818
        error("unknown instruction '%s' in line %d",
1819
              tokenvalString, lineno);
1820
      }
1821
      getToken();
1822
      (*instr->func)(instr->code);
1823
    }
1824
    if (token != TOK_EOL) {
1825
      error("garbage in line %d", lineno);
1826
    }
1827
  }
1828
  roundupSegments();
1829
}
1830
 
1831
 
1832
/**************************************************************/
1833
 
1834
 
1835
unsigned int read4FromEco(unsigned char *p) {
1836
  return (unsigned int) p[0] << 24 |
1837
         (unsigned int) p[1] << 16 |
1838
         (unsigned int) p[2] <<  8 |
1839
         (unsigned int) p[3] <<  0;
1840
}
1841
 
1842
 
1843
void write4ToEco(unsigned char *p, unsigned int data) {
1844
  p[0] = data >> 24;
1845
  p[1] = data >> 16;
1846
  p[2] = data >>  8;
1847
  p[3] = data >>  0;
1848
}
1849
 
1850
 
1851
void conv4FromEcoToNative(unsigned char *p) {
1852
  unsigned int data;
1853
 
1854
  data = read4FromEco(p);
1855
  * (unsigned int *) p = data;
1856
}
1857
 
1858
 
1859
void conv4FromNativeToEco(unsigned char *p) {
1860
  unsigned int data;
1861
 
1862
  data = * (unsigned int *) p;
1863
  write4ToEco(p, data);
1864
}
1865
 
1866
 
1867
/**************************************************************/
1868
 
1869
 
1870
static ExecHeader execHeader;
1871
static int numSymbols;
1872
static int crelSize;
1873
static int drelSize;
1874
static int symtblSize;
1875
static int stringSize;
1876
 
1877
 
1878
static void walkTree(Symbol *s, void (*fp)(Symbol *sp)) {
1879
  if (s == NULL) {
1880
    return;
1881
  }
1882
  walkTree(s->left, fp);
1883
  (*fp)(s);
1884
  walkTree(s->right, fp);
1885
}
1886
 
1887
 
1888
void writeDummyHeader(void) {
1889
  fwrite(&execHeader, sizeof(ExecHeader), 1, outFile);
1890
}
1891
 
1892
 
1893
void writeRealHeader(void) {
1894
  rewind(outFile);
1895
  execHeader.magic = EXEC_MAGIC;
1896
  execHeader.csize = segPtr[SEGMENT_CODE];
1897
  execHeader.dsize = segPtr[SEGMENT_DATA];
1898
  execHeader.bsize = segPtr[SEGMENT_BSS];
1899
  execHeader.crsize = crelSize;
1900
  execHeader.drsize = drelSize;
1901
  execHeader.symsize = symtblSize;
1902
  execHeader.strsize = stringSize;
1903
  conv4FromNativeToEco((unsigned char *) &execHeader.magic);
1904
  conv4FromNativeToEco((unsigned char *) &execHeader.csize);
1905
  conv4FromNativeToEco((unsigned char *) &execHeader.dsize);
1906
  conv4FromNativeToEco((unsigned char *) &execHeader.bsize);
1907
  conv4FromNativeToEco((unsigned char *) &execHeader.crsize);
1908
  conv4FromNativeToEco((unsigned char *) &execHeader.drsize);
1909
  conv4FromNativeToEco((unsigned char *) &execHeader.symsize);
1910
  conv4FromNativeToEco((unsigned char *) &execHeader.strsize);
1911
  fwrite(&execHeader, sizeof(ExecHeader), 1, outFile);
1912
}
1913
 
1914
 
1915
void writeCode(void) {
1916
  int data;
1917
 
1918
  rewind(codeFile);
1919
  while (1) {
1920
    data = fgetc(codeFile);
1921
    if (data == EOF) {
1922
      break;
1923
    }
1924
    fputc(data, outFile);
1925
  }
1926
}
1927
 
1928
 
1929
void writeData(void) {
1930
  int data;
1931
 
1932
  rewind(dataFile);
1933
  while (1) {
1934
    data = fgetc(dataFile);
1935
    if (data == EOF) {
1936
      break;
1937
    }
1938
    fputc(data, outFile);
1939
  }
1940
}
1941
 
1942
 
1943
void transferFixupsForSymbol(Symbol *s) {
1944
  Fixup *f;
1945
 
1946
  if (s->status != STATUS_UNKNOWN && s->status != STATUS_DEFINED) {
1947
    /* this should never happen */
1948
    error("global symbol is neither unknown nor defined");
1949
  }
1950
  if (s->status == STATUS_UNKNOWN && s->fixups == NULL) {
1951
    /* this symbol is neither defined here nor referenced here: skip */
1952
    s->skip = 1;
1953
    return;
1954
  }
1955
  s->skip = 0;
1956
  while (s->fixups != NULL) {
1957
    /* get next fixup record */
1958
    f = s->fixups;
1959
    s->fixups = f->next;
1960
    /* use the 'base' component to store the current symbol number */
1961
    f->base = MSB | numSymbols;
1962
    /* transfer the record to the fixup list */
1963
    f->next = fixupList;
1964
    fixupList = f;
1965
  }
1966
  numSymbols++;
1967
}
1968
 
1969
 
1970
void transferFixups(void) {
1971
  numSymbols = 0;
1972
  walkTree(globalTable, transferFixupsForSymbol);
1973
}
1974
 
1975
 
1976
void writeCodeRelocs(void) {
1977
  Fixup *f;
1978
  RelocRecord relRec;
1979
 
1980
  crelSize = 0;
1981
  f = fixupList;
1982
  while (f != NULL) {
1983
    if (f->segment != SEGMENT_CODE && f->segment != SEGMENT_DATA) {
1984
      /* this should never happan */
1985
      error("fixup found in a segment other than code or data");
1986
    }
1987
    if (f->segment == SEGMENT_CODE) {
1988
      relRec.offset = f->offset;
1989
      relRec.method = f->method;
1990
      relRec.value = f->value;
1991
      relRec.base = f->base;
1992
      conv4FromNativeToEco((unsigned char *) &relRec.offset);
1993
      conv4FromNativeToEco((unsigned char *) &relRec.method);
1994
      conv4FromNativeToEco((unsigned char *) &relRec.value);
1995
      conv4FromNativeToEco((unsigned char *) &relRec.base);
1996
      fwrite(&relRec, sizeof(RelocRecord), 1, outFile);
1997
      crelSize += sizeof(RelocRecord);
1998
    }
1999
    f = f->next;
2000
  }
2001
}
2002
 
2003
 
2004
void writeDataRelocs(void) {
2005
  Fixup *f;
2006
  RelocRecord relRec;
2007
 
2008
  drelSize = 0;
2009
  f = fixupList;
2010
  while (f != NULL) {
2011
    if (f->segment != SEGMENT_CODE && f->segment != SEGMENT_DATA) {
2012
      /* this should never happan */
2013
      error("fixup found in a segment other than code or data");
2014
    }
2015
    if (f->segment == SEGMENT_DATA) {
2016
      relRec.offset = f->offset;
2017
      relRec.method = f->method;
2018
      relRec.value = f->value;
2019
      relRec.base = f->base;
2020
      conv4FromNativeToEco((unsigned char *) &relRec.offset);
2021
      conv4FromNativeToEco((unsigned char *) &relRec.method);
2022
      conv4FromNativeToEco((unsigned char *) &relRec.value);
2023
      conv4FromNativeToEco((unsigned char *) &relRec.base);
2024
      fwrite(&relRec, sizeof(RelocRecord), 1, outFile);
2025
      drelSize += sizeof(RelocRecord);
2026
    }
2027
    f = f->next;
2028
  }
2029
}
2030
 
2031
 
2032
void writeSymbol(Symbol *s) {
2033
  SymbolRecord symRec;
2034
 
2035
  if (s->skip) {
2036
    /* this symbol is neither defined here nor referenced here: skip */
2037
    return;
2038
  }
2039
  symRec.name = stringSize;
2040
  if (s->status == STATUS_UNKNOWN) {
2041
    symRec.type = MSB;
2042
    symRec.value = 0;
2043
  } else {
2044
    symRec.type = s->segment;
2045
    symRec.value = s->value;
2046
  }
2047
  conv4FromNativeToEco((unsigned char *) &symRec.name);
2048
  conv4FromNativeToEco((unsigned char *) &symRec.type);
2049
  conv4FromNativeToEco((unsigned char *) &symRec.value);
2050
  fwrite(&symRec, sizeof(SymbolRecord), 1, outFile);
2051
  symtblSize += sizeof(SymbolRecord);
2052
  stringSize += strlen(s->name) + 1;
2053
}
2054
 
2055
 
2056
void writeSymbols(void) {
2057
  symtblSize = 0;
2058
  stringSize = 0;
2059
  walkTree(globalTable, writeSymbol);
2060
}
2061
 
2062
 
2063
void writeString(Symbol *s) {
2064
  if (s->skip) {
2065
    /* this symbol is neither defined here nor referenced here: skip */
2066
    return;
2067
  }
2068
  fputs(s->name, outFile);
2069
  fputc('\0', outFile);
2070
}
2071
 
2072
 
2073
void writeStrings(void) {
2074
  walkTree(globalTable, writeString);
2075
}
2076
 
2077
 
2078
/**************************************************************/
2079
 
2080
 
2081
void usage(char *myself) {
2082
  fprintf(stderr, "Usage: %s\n", myself);
2083
  fprintf(stderr, "         [-o objfile]     set object file name\n");
2084
  fprintf(stderr, "         file             source file name\n");
2085
  fprintf(stderr, "         [files...]       additional source files\n");
2086
  exit(1);
2087
}
2088
 
2089
 
2090
int main(int argc, char *argv[]) {
2091
  int i;
2092
  char *argp;
2093
 
2094
  sortInstrTable();
2095
  tmpnam(codeName);
2096
  tmpnam(dataName);
2097
  outName = "a.out";
2098
  for (i = 1; i < argc; i++) {
2099
    argp = argv[i];
2100
    if (*argp != '-') {
2101
      break;
2102
    }
2103
    argp++;
2104
    switch (*argp) {
2105
      case 'o':
2106
        if (i == argc - 1) {
2107
          usage(argv[0]);
2108
        }
2109
        outName = argv[++i];
2110
        break;
2111
      default:
2112
        usage(argv[0]);
2113
    }
2114
  }
2115
  if (i == argc) {
2116
    usage(argv[0]);
2117
  }
2118
  codeFile = fopen(codeName, "w+b");
2119
  if (codeFile == NULL) {
2120
    error("cannot create temporary code file '%s'", codeName);
2121
  }
2122
  dataFile = fopen(dataName, "w+b");
2123
  if (dataFile == NULL) {
2124
    error("cannot create temporary data file '%s'", dataName);
2125
  }
2126
  outFile = fopen(outName, "wb");
2127
  if (outFile == NULL) {
2128
    error("cannot open output file '%s'", outName);
2129
  }
2130
  do {
2131
    inName = argv[i];
2132
    if (*inName == '-') {
2133
      usage(argv[0]);
2134
    }
2135
    inFile = fopen(inName, "rt");
2136
    if (inFile == NULL) {
2137
      error("cannot open input file '%s'", inName);
2138
    }
2139
    fprintf(stderr, "Assembling module '%s'...\n", inName);
2140
    asmModule();
2141
    if (inFile != NULL) {
2142
      fclose(inFile);
2143
      inFile = NULL;
2144
    }
2145
    linkLocals();
2146
  } while (++i < argc);
2147
  writeDummyHeader();
2148
  writeCode();
2149
  writeData();
2150
  transferFixups();
2151
  writeCodeRelocs();
2152
  writeDataRelocs();
2153
  writeSymbols();
2154
  writeStrings();
2155
  writeRealHeader();
2156
  if (codeFile != NULL) {
2157
    fclose(codeFile);
2158
    codeFile = NULL;
2159
  }
2160
  if (dataFile != NULL) {
2161
    fclose(dataFile);
2162
    dataFile = NULL;
2163
  }
2164
  if (outFile != NULL) {
2165
    fclose(outFile);
2166
    outFile = NULL;
2167
  }
2168
  if (codeName != NULL) {
2169
    unlink(codeName);
2170
  }
2171
  if (dataName != NULL) {
2172
    unlink(dataName);
2173
  }
2174
  return 0;
2175
}

powered by: WebSVN 2.1.0

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