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

Subversion Repositories ssbcc

[/] [ssbcc/] [trunk/] [core/] [9x8/] [asmDef_9x8.py] - Blame information for rev 2

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

Line No. Rev Author Line
1 2 sinclairrf
################################################################################
2
#
3
# Copyright 2012, Sinclair R.F., Inc.
4
#
5
# Assembly language definitions for SSBCC 9x8.
6
#
7
################################################################################
8
 
9
import copy
10
import string
11
 
12
import asmDef
13
 
14
class asmDef_9x8:
15
  """
16
  Class for core-specific opcodes, macros, etc. for core/9x8.
17
  """
18
 
19
  ################################################################################
20
  #
21
  # External interface to the directives.
22
  #
23
  ################################################################################
24
 
25
  def IsDirective(self,name):
26
    """
27
    Indicate whether or not the string "name" is a directive.
28
    """
29
    return name in self.directives['list'];
30
 
31
  ################################################################################
32
  #
33
  # Record symbols
34
  #
35
  ################################################################################
36
 
37
  def AddSymbol(self,name,stype,body=None):
38
    """
39
    Add the named global symbol to the list of symbols including its mandatory
40
    type and an optional body.\n
41
    Note:  Symbols include memory names, variables, constants, functions,
42
           parameters, inports, outports, ...
43
    """
44
    if self.IsSymbol(name):
45
      raise Exception('Program Bug -- name "%s" already exists is symbols' % name);
46
    self.symbols['list'].append(name);
47
    self.symbols['type'].append(stype);
48
    self.symbols['body'].append(body);
49
 
50
  def IsSymbol(self,name):
51
    return name in self.symbols['list'];
52
 
53
  def SymbolDict(self):
54
    """
55
    Return a dict object usable by the eval function with the currently defines
56
    symbols for constants, variables, memory lengths, stack lengths, and signal
57
    lengths.
58
    """
59
    t = dict();
60
    for ixSymbol in range(len(self.symbols['list'])):
61
      name = self.symbols['list'][ixSymbol];
62
      stype = self.symbols['type'][ixSymbol];
63
      if stype == 'constant':
64
        t[name] = self.symbols['body'][ixSymbol][0];
65
      elif stype == 'variable':
66
        t[name] = self.symbols['body'][ixSymbol]['start'];
67
    sizes=dict();
68
    for name in self.memoryLength:
69
      sizes[name] = self.memoryLength[name];
70
    for name in self.stackLength:
71
      sizes[name] = self.stackLength[name];
72
    t['size'] = sizes;
73
    return t;
74
 
75
  ################################################################################
76
  #
77
  # Configure the class for identifying and processing macros.
78
  #
79
  ################################################################################
80
 
81
  def AddMacro(self,name,macroLength,args):
82
    """
83
    Add a macro to the list of recognized macros.
84
      name              string with the name of the macro
85
      macroLength       number of instructions the macro expands to
86
                        Note:  A negative value means that the macro has a
87
                               variable length (see MacroLength below)
88
      args              list of the arguments
89
                        each element of this list is an array of strings specifying the following:
90
                          1.  If the first element is the empty string, then
91
                              there is no default value for the argument,
92
                              otherwise the listed string is the default
93
                              value of the optional argument.
94
                          2.  The remaining elements of the list are the types
95
                              of arguments that can be accepted for the
96
                              required or optional arguments.
97
                        Note:  Only the last list in args is allowed to
98
                               indicate an optional value for that argument.
99
 
100
    Also record the allowed number of allowed arguments to the macro.
101
    """
102
    if name in self.macros['list']:
103
      raise Exception('Program Bug -- name "%s" has already been listed as a macro' % name);
104
    self.macros['list'].append(name);
105
    self.macros['length'].append(macroLength);
106
    self.macros['args'].append(args);
107
    # Compute the range of the number of allowed arguments by first counting
108
    # the number of required arguments and then determining whether or not
109
    # there is at most one optional argument.
110
    nRequired = 0;
111
    while (nRequired < len(args)) and (args[nRequired][0] == ''):
112
      nRequired = nRequired + 1;
113
    if nRequired < len(args)-1:
114
      raise Exception('Program Bug -- Only the last macro argument can be optional');
115
    self.macros['nArgs'].append(range(nRequired,len(args)+1));
116
 
117
  def IsMacro(self,name):
118
    """
119
    Indicate whether or not the string "name" is a recognized macro.
120
    """
121
    return name in self.macros['list'];
122
 
123
  def IsSingleMacro(self,name):
124
    """
125
    Indicate whether or not the macro is only one instruction long.
126
    """
127
    if name not in self.macros['list']:
128
      raise Exception('Program Bug -- name "%s" is not a macro' % name);
129
    ix = self.macros['list'].index(name);
130
    return (self.macros['length'][ix] == 1);
131
 
132
  def MacroArgTypes(self,name,ixArg):
133
    """
134
    Return the list of allowed types for the macro name for argument ixArg.
135
    """
136
    if name not in self.macros['list']:
137
      raise Exception('Program Bug -- name "%s" is not a macro' % name);
138
    ix = self.macros['list'].index(name);
139
    return self.macros['args'][ix][ixArg][1:];
140
 
141
  def MacroDefault(self,name,ixArg):
142
    """
143
    Return the default argument for the macro name for argument ixArg.
144
    """
145
    if name not in self.macros['list']:
146
      raise Exception('Program Bug -- name "%s" is not a macro' % name);
147
    ix = self.macros['list'].index(name);
148
    return self.macros['args'][ix][ixArg][0];
149
 
150
  def MacroLength(self,token):
151
    """
152
    Return the length of fixed-length macros or compute and return the length
153
    of variable-length macros.\n
154
    Note:  The only variable length macros recognized are fetchvector and
155
           storevector.
156
    """
157
    if token['value'] not in self.macros['list']:
158
      raise Exception('Program Bug -- name "%s" is not a macro' % token['value']);
159
    ix = self.macros['list'].index(token['value']);
160
    length = self.macros['length'][ix];
161
    if length >= 0:
162
      return length;
163
    if token['value'] == '.fetchvector':
164
      return int(token['argument'][1]['value']) + 1;
165
    if token['value'] == '.storevector':
166
      return int(token['argument'][1]['value']) + 2;
167
    raise Exception('Program Bug -- Unrecognized variable length macro "%s"' % token['value']);
168
 
169
  def MacroNumberArgs(self,name):
170
    """
171
    Return the range of the number of allowed arguments to the named macro.
172
    """
173
    if name not in self.macros['list']:
174
      raise Exception('Program bug -- name "%s" is not a macro' % name);
175
    ix = self.macros['list'].index(name);
176
    return self.macros['nArgs'][ix];
177
 
178
  ################################################################################
179
  #
180
  # Configure the class for processing instructions.
181
  #
182
  ################################################################################
183
 
184
  def AddInstruction(self,name,opcode):
185
    """
186
    Add an instruction to the list of recognized instructions.
187
    """
188
    self.instructions['list'].append(name);
189
    self.instructions['opcode'].append(opcode);
190
 
191
  def IsInstruction(self,name):
192
    """
193
    Indicate whether or not the argument is an instruction.
194
    """
195
    return name in self.instructions['list'];
196
 
197
  def InstructionOpcode(self,name):
198
    """
199
    Return the opcode for the specified instruction.
200
    """
201
    if not self.IsInstruction(name):
202
      raise Exception('Program Bug:  "%s" not in instruction list' % name);
203
    ix = self.instructions['list'].index(name);
204
    return self.instructions['opcode'][ix];
205
 
206
  ################################################################################
207
  #
208
  # Register input and output port names and addresses.
209
  #
210
  ################################################################################
211
 
212
  def IsConstant(self,name):
213
    """
214
    Indicate whether or not the named symbol is an inport.
215
    """
216
    if not self.IsSymbol(name):
217
      return False;
218
    ix = self.symbols['list'].index(name);
219
    return self.symbols['type'][ix] == 'constant';
220
 
221
  def IsInport(self,name):
222
    """
223
    Indicate whether or not the named symbol is an inport.
224
    """
225
    if not self.IsSymbol(name):
226
      return False;
227
    ix = self.symbols['list'].index(name);
228
    return self.symbols['type'][ix] == 'inport';
229
 
230
  def IsOutport(self,name):
231
    """
232
    Indicate whether or not the named symbol is an outport.
233
    """
234
    if not self.IsSymbol(name):
235
      return False;
236
    ix = self.symbols['list'].index(name);
237
    return self.symbols['type'][ix] == 'outport';
238
 
239
  def IsOutstrobe(self,name):
240
    """
241
    Indicate whether or not the named symbol is a strobe-only outport.
242
    """
243
    if not self.IsSymbol(name):
244
      return False;
245
    ix = self.symbols['list'].index(name);
246
    return self.symbols['type'][ix] == 'outstrobe';
247
 
248
  def IsParameter(self,name):
249
    """
250
    Indicate whether or not the named symbol is a parameter.
251
    """
252
    if not self.IsSymbol(name):
253
      return False;
254
    ix = self.symbols['list'].index(name);
255
    return self.symbols['type'][ix] == 'parameter';
256
 
257
  def InportAddress(self,name):
258
    """
259
    Return the address of the named inport.
260
    """
261
    if not self.IsInport(name):
262
      raise Exception('Program Bug -- "%s" is not an inport' % name);
263
    ix = self.symbols['list'].index(name);
264
    return self.symbols['body'][ix];
265
 
266
  def OutportAddress(self,name):
267
    """
268
    Return the address of the named outport.
269
    """
270
    if not self.IsOutport(name) and not self.IsOutstrobe(name):
271
      raise Exception('Program Bug -- "%s" is not an outport' % name);
272
    ix = self.symbols['list'].index(name);
273
    return self.symbols['body'][ix];
274
 
275
  def RegisterInport(self,name,address):
276
    """
277
    Add the named inport to the list of recognized symbols and record its
278
    address as the body of the inport.
279
    """
280
    if self.IsSymbol(name):
281
      raise Exception('Program Bug -- repeated symbol name "%s"' % name);
282
    self.AddSymbol(name,'inport',address);
283
 
284
  def RegisterOutport(self,name,address):
285
    """
286
    Add the named outport to the list of recognized symbols and record its
287
    address as the body of the outport.
288
    """
289
    if self.IsSymbol(name):
290
      raise Exception('Program Bug -- repeated symbol name "%s"' % name);
291
    self.AddSymbol(name,'outport',address);
292
 
293
  def RegisterOutstrobe(self,name,address):
294
    """
295
    Add the named outport to the list of recognized symbols and record its
296
    address as the body of the strobe-only outports.
297
    """
298
    if self.IsSymbol(name):
299
      raise Exception('Program Bug -- repeated symbol name "%s"' % name);
300
    self.AddSymbol(name,'outstrobe',address);
301
 
302
  def RegisterParameterName(self,name):
303
    """
304
    Add the named parameter to the list of regognized symbols.\n
305
    Note:  Parameters do not have a body.
306
    """
307
    if self.IsSymbol(name):
308
      raise Exception('Program Bug -- repeated symbol name "%s"' % name);
309
    self.AddSymbol(name,'parameter');
310
 
311
  def RegisterMemoryLength(self,name,length):
312
    """
313
    Record the length of the specified memory.\n
314
    Note:  This is used to evaluate "size[name]" in "${...}" expressions.
315
    """
316
    self.memoryLength[name] = length;
317
 
318
  def RegisterStackLength(self,name,length):
319
    """
320
    Record the length of the specified stack.\n
321
    Note:  This is used to evaluate "size[name]" in "${...}" expressions.
322
    """
323
    self.stackLength[name] = length;
324
 
325
  ################################################################################
326
  #
327
  # Check a list of raw tokens to ensure their proper format.
328
  #
329
  ################################################################################
330
 
331
  def CheckSymbolToken(self,name,allowableTypes,loc):
332
    """
333
    Syntax check for symbols, either by themselves or as a macro argument.\n
334
    Note:  This is used by CheckRawTokens.
335
    """
336
    if not self.IsSymbol(name):
337
      raise asmDef.AsmException('Undefined symbol "%s" at %s' % (name,loc));
338
    ixName = self.symbols['list'].index(name);
339
    if self.symbols['type'][ixName] not in allowableTypes:
340
      raise asmDef.AsmException('Illegal symbol at %s' % loc);
341
 
342
  def CheckRawTokens(self,rawTokens):
343
    """
344
    Syntax check for directive bodies.\n
345
    Note:  This core-specific method is called by the top-level assembler after
346
           the RawTokens method.
347
    """
348
    # Ensure the first token is a directive.
349
    firstToken = rawTokens[0];
350
    if firstToken['type'] != 'directive':
351
      raise Exception('Program Bug triggered at %s' % firstToken['loc']);
352
    # Ensure the directive bodies are not too short.
353
    if (firstToken['value'] in ('.main','.interrupt',)) and not (len(rawTokens) > 1):
354
      raise asmDef.AsmException('"%s" missing body at %s' % (firstToken['value'],firstToken['loc'],));
355
    if (firstToken['value'] in ('.constant','.function','.memory','.variable',)) and not (len(rawTokens) >= 3):
356
      raise asmDef.AsmException('body for "%s" directive too short at %s' % (firstToken['value'],firstToken['loc'],));
357
    # Ensure the main body ends in a ".jump".
358
    lastToken = rawTokens[-1];
359
    if firstToken['value'] == '.main':
360
      if (lastToken['type'] != 'macro') or (lastToken['value'] != '.jump'):
361
        raise asmDef.AsmException('.main body does not end in ".jump" at %s' % lastToken['loc']);
362
    # Ensure functions and interrupts end in a ".jump" or ".return".
363
    if firstToken['value'] in ('.function','.interrupt',):
364
      if (lastToken['type'] != 'macro') or (lastToken['value'] not in ('.jump','.return',)):
365
        raise asmDef.AsmException('Last entry in ".function" or ".interrupt" must be a ".jump" or ".return" at %s' % lastToken['loc']);
366
    # Ensure no macros and no instructions in non-"functions".
367
    # Byproduct:  No labels allowed in non-"functions".
368
    if firstToken['value'] not in ('.function','.interrupt','.main',):
369
      for token in rawTokens[2:]:
370
        if (token['type'] == 'macro'):
371
          raise asmDef.AsmException('Macro not allowed in directive at %s' % token['loc']);
372
        if token['type'] == 'instruction':
373
          raise asmDef.AsmException('Instruction not allowed in directive at %s' % token['loc']);
374
    # Ensure local labels are defined and used.
375
    labelDefs = list();
376
    for token in rawTokens:
377
      if token['type'] == 'label':
378
        name = token['value'];
379
        if name in labelDefs:
380
          raise asmDef.AsmException('Repeated label definition "%s" at %s' % (name,token['loc'],));
381
        labelDefs.append(name);
382
    labelsUsed = list();
383
    for token in rawTokens:
384
      if (token['type'] == 'macro') and (token['value'] in ('.jump','.jumpc',)):
385
        target = token['argument'][0]['value'];
386
        if target not in labelDefs:
387
          raise asmDef.AsmException('label definition for target missing at %s' % token['loc']);
388
        labelsUsed.append(target);
389
    labelsUnused = set(labelDefs) - set(labelsUsed);
390
    if labelsUnused:
391
      raise asmDef.AsmException('Unused label(s) %s in body %s' % (labelsUnused,firstToken['loc']));
392
    # Ensure symbols referenced by ".input", ".outport", and ".outstrobe" are defined.
393
    for token in rawTokens:
394
      if (token['type'] == 'macro') and (token['value'] == '.inport'):
395
        if not self.IsInport(token['argument'][0]['value']):
396
          raise asmDef.AsmException('Symbol "%s is not an input port at %s' % (token['argument'][0]['value'],token['loc']));
397
      if (token['type'] == 'macro') and (token['value'] == '.outport'):
398
        if not self.IsOutport(token['argument'][0]['value']):
399
          raise asmDef.AsmException('Symbol "%s" is either not an output port or is a strobe-only outport at %s' % (token['argument'][0]['value'],token['loc']));
400
      if (token['type'] == 'macro') and (token['value'] == '.outstrobe'):
401
        if not self.IsOutstrobe(token['argument'][0]['value']):
402
          raise asmDef.AsmException('Symbol "%s" is not a strobe-only output port at %s' % (token['argument'][0]['value'],token['loc']));
403
    # Ensure referenced symbols are already defined (other than labels and
404
    # function names for call and jump macros).
405
    checkBody = False;
406
    if (rawTokens[0]['type'] == 'directive') and (rawTokens[0]['value'] in ('.function','.interrupt','.main',)):
407
      checkBody = True;
408
    if checkBody:
409
      for token in rawTokens[2:]:
410
        if token['type'] == 'symbol':
411
          allowableTypes = ('constant','inport','macro','outport','outstrobe','parameter','variable',);
412
          self.CheckSymbolToken(token['value'],allowableTypes,token['loc']);
413
        elif token['type'] == 'macro':
414
          allowableTypes = ('RAM','ROM','constant','inport','outport','outstrobe','parameter','variable',);
415
          ixFirst = 1 if token['value'] in self.MacrosWithSpecialFirstSymbol else 0;
416
          for arg in  token['argument'][ixFirst:]:
417
            if arg['type'] == 'symbol':
418
              self.CheckSymbolToken(arg['value'],allowableTypes,arg['loc']);
419
 
420
  ################################################################################
421
  #
422
  # fill in symbols, etc. in the list of raw tokens.
423
  #
424
  ################################################################################
425
 
426
  def ByteList(self,rawTokens,limit=False):
427
    """
428
    Return either (1) a list comprised of a single token which may not be a
429
    byte or (2) a list comprised of multiple tokens, each of which is a single
430
    byte.\n
431
    Note:  This is called by FillRawTokens.
432
    """
433
    if len(rawTokens) > 1:
434
      limit = True;
435
    values = list();
436
    try:
437
      for token in rawTokens:
438
        if token['type'] == 'value':
439
          v = token['value'];
440
          if type(v) == int:
441
            if limit and not (-128 <= v < 256):
442
              raise Exception('Program Bug -- unexpected out-of-range value');
443
            values.append(v);
444
          else:
445
            for v in token['value']:
446
              if not (-128 <= v < 256):
447
                raise Exception('Program Bug -- unexpected out-of-range value');
448
              values.append(v);
449
        else:
450
          raise asmDef.AsmException('Illegal token "%s" at %s:%d:%d', (token['type'],token['loc']));
451
    except:
452
      raise asmDef.AsmException('Out-of-range token "%s" at %s:%d:%d', (token['type'],token['loc']));
453
    return values;
454
 
455
  def ExpandSymbol(self,token,singleValue):
456
    """
457
    Convert the token for a symbol into a token for its specific type.
458
    Optionally ensure constants expand to a single byte.  For parameters,
459
    ensure that a range is provided.\n
460
    Note:  Symbols must be defined before the directive bodies in which they
461
           are used.\n
462
    Note:  This is called in two spots.  The first is ExpandTokens, where
463
           isolated symbols are processed, for example to get the value of a
464
           constant.  The second is in EmitOptArg where symbols in arguments to
465
           macros are expanded (this allows the macro-specific processing to
466
           identify labels vs. symbols).
467
    """
468
    if not self.IsSymbol(token['value']):
469
      raise asmDef.AsmException('Symbol "%s" not in symbol list at %s' %(token['value'],token['loc'],));
470
    ix = self.symbols['list'].index(token['value']);
471
    symbolType = self.symbols['type'][ix];
472
    if symbolType == 'RAM':
473
      return dict(type='RAM', value=token['value'], loc=token['loc']);
474
    elif symbolType == 'ROM':
475
      return dict(type='ROM', value=token['value'], loc=token['loc']);
476
    elif symbolType == 'constant':
477
      if singleValue:
478
        thisBody = self.symbols['body'][ix];
479
        if len(thisBody) != 1:
480
          raise asmDef.AsmException('Constant "%s" must evaluate to a single byte at %s' % (token['value'],token['loc'],))
481
        thisBody = thisBody[0];
482
        if not (-128 <= thisBody < 256):
483
          raise asmDef.AsmException('Constant "%s" must be a byte value at %s' % (token['value'],token['loc'],));
484
      return dict(type='constant', value=token['value'], loc=token['loc']);
485
    elif symbolType == 'inport':
486
      return dict(type='inport', value=token['value'], loc=token['loc']);
487
    elif symbolType == 'outport':
488
      return dict(type='outport', value=token['value'], loc=token['loc']);
489
    elif symbolType == 'outstrobe':
490
      return dict(type='outstrobe', value=token['value'], loc=token['loc']);
491
    elif symbolType == 'parameter':
492
      if 'range' in token:
493
        trange = token['range'];
494
      else:
495
        trange = '[0+:8]';
496
      return dict(type='parameter', value=token['value'], range=trange, loc=token['loc']);
497
    elif symbolType == 'variable':
498
      return dict(type='variable', value=token['value'], loc=token['loc']);
499
    else:
500
      raise Exception('Program Bug -- unrecognized symbol type "%s"' % symbolType);
501
 
502
  def ExpandTokens(self,rawTokens):
503
    """
504
    Compute the relative addresses for tokens within function bodies.\n
505
    The return is a list of the tokens in the function body, each of which has
506
    a type, value, offset (relative address), and location within the source
507
    code.  Macro types also have the list of arguments provided to the macro.
508
    """
509
    tokens = list();
510
    offset = 0;
511
    for token in rawTokens:
512
      # insert labels
513
      if token['type'] == 'label':
514
        tokens.append(dict(type=token['type'], value=token['value'], offset=offset, loc=token['loc']));
515
        # labels don't change the offset
516
      # append instructions
517
      elif token['type'] == 'instruction':
518
        tokens.append(dict(type=token['type'], value=token['value'], offset=offset, loc=token['loc']));
519
        offset = offset + 1;
520
      # append values
521
      elif token['type'] == 'value':
522
        if type(token['value']) == int:
523
          tokens.append(dict(type=token['type'], value=token['value'], offset=offset, loc=token['loc']));
524
          offset = offset + 1;
525
        else:
526
          revTokens = copy.copy(token['value']);
527
          revTokens.reverse();
528
          for lToken in revTokens:
529
            tokens.append(dict(type=token['type'], value=lToken, offset=offset, loc=token['loc']));
530
            offset = offset + 1;
531
      # append macros
532
      elif token['type'] == 'macro':
533
        tokens.append(dict(type=token['type'], value=token['value'], offset=offset, argument=token['argument'], loc=token['loc']));
534
        offset = offset + self.MacroLength(token);
535
      # interpret and append symbols
536
      elif token['type'] == 'symbol':
537
        newToken = self.ExpandSymbol(token,singleValue=False);
538
        newToken['offset'] = offset;
539
        newToken['loc'] = token['loc'];
540
        tokens.append(newToken);
541
        if token['type'] == 'constant':
542
          ix = self.symbols['list'].index(newToken['value']);
543
          offset = offset + len(self.symbols['body'][ix]);
544
        else:
545
          offset = offset + 1;
546
      # anything else is a program bug
547
      else:
548
        raise Exception('Program bug:  unexpected token type "%s"' % token['type']);
549
    return dict(tokens=tokens, length=offset);
550
 
551
  def FillRawTokens(self,rawTokens):
552
    """
553
    Do one of the following as required for the specified directive:
554
      .constant         add the constant and its body to the list of symbols
555
      .function         add the function and its body, along with the relative
556
                        addresses, to the list of symbols
557
      .interrupt        record the function body and relative addresses
558
      .main             record the function body and relative addresses
559
      .memory           record the definition of the memory and make it current
560
                        for subsequent variable definitions.
561
      .variable         add the variable and its associated memory, length, and
562
                        initial values to the list of symbols
563
    """
564
    firstToken = rawTokens[0];
565
    secondToken = rawTokens[1];
566
    # Perform syntax check common to several directives.
567
    if firstToken['value'] in ('.constant','.function','.variable',):
568
      if secondToken['type'] != 'symbol':
569
        raise asmDef.AsmException('Expected symbol, not "%s", at %s' % (secondToken['value'],secondToken['loc'],));
570
      if self.IsSymbol(secondToken['value']):
571
        raise asmDef.AsmException('Symbol "%s" already defined at %s' % (secondToken['value'],secondToken['loc'],));
572
    # Perform syntax-specific processing.
573
    if firstToken['value'] == '.constant':
574
      byteList = self.ByteList(rawTokens[2:]);
575
      self.AddSymbol(secondToken['value'],'constant',body=byteList);
576
    # Process ".function" definition.
577
    elif firstToken['value'] == '.function':
578
      self.AddSymbol(secondToken['value'],'function',self.ExpandTokens(rawTokens[2:]));
579
    # Process ".interrupt" definition.
580
    elif firstToken['value'] == '.interrupt':
581
      if self.interrupt:
582
        raise asmDef.AsmException('Second definition of ".interrupt" at %s' % firstToken['loc']);
583
      self.interrupt = self.ExpandTokens(rawTokens[1:]);
584
    # Process ".main" definition.
585
    elif firstToken['value'] == '.main':
586
      if self.main:
587
        raise asmDef.AsmException('Second definition of ".main" at %s' % firstToken['loc']);
588
      self.main = self.ExpandTokens(rawTokens[1:]);
589
    # Process ".memory" declaration.
590
    elif firstToken['value'] == '.memory':
591
      if len(rawTokens) != 3:
592
        raise asmDef.AsmException('".memory" directive requires exactly two arguments at %s' % firstToken['loc']);
593
      if (secondToken['type'] != 'symbol') or (secondToken['value'] not in ('RAM','ROM',)):
594
        raise asmDef.AsmException('First argument to ".memory" directive must be "RAM" or "RAM" at %s' % secondToken['loc']);
595
      thirdToken = rawTokens[2];
596
      if thirdToken['type'] != 'symbol':
597
        raise asmDef.AsmException('".memory" directive requires name for second argument at %s' % thirdToken['loc']);
598
      if self.IsSymbol(thirdToken['value']):
599
        ix = self.symbols['list'].index(thirdToken['value']);
600
        if self.symbols['type'] != secondToken['value']:
601
          raise asmDef.AsmException('Redefinition of ".memory %s %s" not allowed at %s' % (secondToken['value'],thirdToken['value'],firstToken['loc']));
602
      else:
603
        self.AddSymbol(thirdToken['value'],secondToken['value'],dict(length=0));
604
      self.currentMemory = thirdToken['value'];
605
    # Process ".variable" declaration.
606
    elif firstToken['value'] == '.variable':
607
      if not self.currentMemory:
608
        raise asmDef.AsmException('".memory" directive required before ".variable" directive at %s' % firstToken['line']);
609
      ixMem = self.symbols['list'].index(self.currentMemory);
610
      currentMemoryBody = self.symbols['body'][ixMem];
611
      byteList = self.ByteList(rawTokens[2:],limit=True);
612
      body = dict(memory=self.currentMemory, start=currentMemoryBody['length'], value=byteList);
613
      self.AddSymbol(secondToken['value'], 'variable', body=body);
614
      currentMemoryBody['length'] = currentMemoryBody['length'] + len(byteList);
615
      if currentMemoryBody['length'] > 256:
616
        raise asmDef.AsmException('Memory "%s" becomes too long at %s' % (self.currentMemory,firstToken['loc']));
617
    # Everything else is an error.
618
    else:
619
      raise Exception('Program Bug:  Unrecognized directive %s at %s' % (firstToken['value'],firstToken['loc']));
620
 
621
  def Main(self):
622
    """
623
    Return the body of the .main function.
624
    Note:  This is used by the top-level assembler to verify that the .main
625
           function has been defined.
626
    """
627
    return self.main;
628
 
629
  def Interrupt(self):
630
    """
631
    Return the body of the .interrupt function.
632
    Note:  This is used by the top-level assembler to verify that the .interrupt
633
           function has or has not been defined.
634
    """
635
    return self.interrupt;
636
 
637
  ################################################################################
638
  #
639
  # Compute the memory bank indices.
640
  #
641
  ################################################################################
642
 
643
  def EvaluateMemoryTree(self):
644
    """
645
    Ensure defined memories are used.  Add the memory name, type, and length to
646
    the list of memories.  Compute the bank index ascending from 0 for RAMs and
647
    descending from 3 for ROMs and add that index to the memory attributes.
648
    Ensure that no more than 4 memories are listed.
649
    """
650
    self.memories = dict(list=list(), type=list(), length=list(), bank=list());
651
    ramBank = 0;
652
    romBank = 3;
653
    for ix in range(len(self.symbols['list'])):
654
      if self.symbols['type'][ix] in ('RAM','ROM',):
655
        memBody = self.symbols['body'][ix];
656
        if memBody['length'] == 0:
657
          raise asmDef.AsmException('Empty memory:  %s' % self.symbols['list'][ix]);
658
        self.memories['list'].append(self.symbols['list'][ix]);
659
        self.memories['type'].append(self.symbols['type'][ix]);
660
        self.memories['length'].append(memBody['length']);
661
        if self.symbols['type'][ix] == 'RAM':
662
          self.memories['bank'].append(ramBank);
663
          ramBank = ramBank + 1;
664
        else:
665
          self.memories['bank'].append(romBank);
666
          romBank = romBank - 1;
667
    if len(self.memories['list']) > 4:
668
      raise asmDef.AsmException('Too many memory banks');
669
 
670
  ################################################################################
671
  #
672
  # Generate the list of required functions from the ".main" and ".interrupt"
673
  # bodies.
674
  #
675
  # Look for function calls with the bodies of the required functions.  If the
676
  # function has not already been identified as a required function then (1)
677
  # ensure it exists and is a function and then (2) add it to the list of
678
  # required functions.
679
  #
680
  # Whenever a function is added to the list, set its start address and get its
681
  # length.
682
  #
683
  ################################################################################
684
 
685
  def EvaluateFunctionTree(self):
686
    """
687
    Create a list of the functions required by the program, starting with the
688
    required .main function and the optional .interrupt function.\n
689
    Record the length of each function, its body, and its start address and
690
    calculate the addresses of the labels within each function body.\n
691
    Finally, ensure the function address space does not exceed the absolute
692
    8192 address limit.
693
    """
694
    self.functionEvaluation = dict(list=list(), length=list(), body=list(), address=list());
695
    nextStart = 0;
696
    # ".main" is always required.
697
    self.functionEvaluation['list'].append('.main');
698
    self.functionEvaluation['length'].append(self.main['length']);
699
    self.functionEvaluation['body'].append(self.main['tokens']);
700
    self.functionEvaluation['address'].append(nextStart);
701
    nextStart = nextStart + self.functionEvaluation['length'][-1];
702
    # ".interrupt" is optionally required (and is sure to exist by this function
703
    # call if it is required).
704
    if self.interrupt:
705
      self.functionEvaluation['list'].append('.interrupt');
706
      self.functionEvaluation['length'].append(self.interrupt['length']);
707
      self.functionEvaluation['body'].append(self.interrupt['tokens']);
708
      self.functionEvaluation['address'].append(nextStart);
709
      nextStart = nextStart + self.functionEvaluation['length'][-1];
710
    # Loop through the required function bodies as they are identified.
711
    ix = 0;
712
    while ix < len(self.functionEvaluation['body']):
713
      for token in self.functionEvaluation['body'][ix]:
714
        if (token['type'] == 'macro') and (token['value'] in ('.call','.callc',)):
715
          callName = token['argument'][0]['value'];
716
          if callName not in self.functionEvaluation['list']:
717
            if not self.IsSymbol(callName):
718
              raise asmDef.AsmException('Function "%s" not defined for function "%s"' % (callName,self.functionEvaluation['list'][ix],));
719
            ixName = self.symbols['list'].index(callName);
720
            if self.symbols['type'][ixName] != 'function':
721
              raise asmDef.AsmException('Function "%s" called by "%s" is not a function', (callName, self.functionEvaluation['list'][ix],));
722
            self.functionEvaluation['list'].append(callName);
723
            self.functionEvaluation['length'].append(self.symbols['body'][ixName]['length']);
724
 

powered by: WebSVN 2.1.0

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