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
            self.functionEvaluation['body'].append(self.symbols['body'][ixName]['tokens']);
725
            self.functionEvaluation['address'].append(nextStart);
726
            nextStart = nextStart + self.functionEvaluation['length'][-1];
727
      ix = ix + 1;
728
    # Within each function, compute the list of label addresses and then fill in
729
    # the address for all jumps and calls.
730
    for ix in range(len(self.functionEvaluation['list'])):
731
      startAddress = self.functionEvaluation['address'][ix];
732
      labelAddress = dict(list=list(), address=list());
733
      for token in self.functionEvaluation['body'][ix]:
734
        if token['type'] == 'label':
735
          labelAddress['list'].append(token['value']);
736
          labelAddress['address'].append(startAddress + token['offset']);
737
      for token in self.functionEvaluation['body'][ix]:
738
        if token['type'] != 'macro':
739
          continue;
740
        if token['value'] in ('.jump','.jumpc',):
741
          ix = labelAddress['list'].index(token['argument'][0]['value']);
742
          token['address'] = labelAddress['address'][ix];
743
        elif token['value'] in ('.call','.callc',):
744
          ix = self.functionEvaluation['list'].index(token['argument'][0]['value']);
745
          token['address'] = self.functionEvaluation['address'][ix];
746
    # Sanity checks for address range
747
    if self.functionEvaluation['address'][-1] + self.functionEvaluation['length'][-1] >= 2**13:
748
      raise asmDef.AsmException('Max address for program requires more than 13 bits');
749
 
750
  ################################################################################
751
  #
752
  # Emit the meta code for the memories.
753
  #
754
  ################################################################################
755
 
756
  def EmitMemories(self,fp):
757
    """
758
    Print the memories to the metacode file.\n
759
    The first line for each memory has the format
760
      :memory type mem_name bank length
761
    where
762
      type              is RAM or ROM
763
      mem_name          is the name of the memory
764
      bank              is the assigned bank address
765
      length            is the number of bytes used by the memory\n
766
    The subsequent lines are sequences of
767
      - variable_name
768
      value(s)
769
    where
770
      '-'               indicates a variable name is present
771
      variable_name     is the name of the variable
772
      values(s)         is one or more lines for the values with one byte per line
773
                        Note:  because the lines with variable names start with
774
                               '-', negative values are converted to unsigned
775
                               values\n
776
    """
777
    # Emit the individual memories.
778
    for ixMem in range(len(self.memories['list'])):
779
      fp.write(':memory %s %s %d %d\n' % (self.memories['type'][ixMem],self.memories['list'][ixMem],self.memories['bank'][ixMem],self.memories['length'][ixMem]));
780
      memName = self.memories['list'][ixMem];
781
      address = 0;
782
      for ixSymbol in range(len(self.symbols['list'])):
783
        if self.symbols['type'][ixSymbol] != 'variable':
784
          continue;
785
        vBody = self.symbols['body'][ixSymbol];
786
        if vBody['memory'] != memName:
787
          continue;
788
        fp.write('- %s\n' % self.symbols['list'][ixSymbol]);
789
        for v in vBody['value']:
790
          if not (-128 <=v < 256):
791
            raise Exception('Program Bug -- value not representable by a byte');
792
          fp.write('%02X\n' % (v % 0x100,));
793
      fp.write('\n');
794
 
795
  ################################################################################
796
  #
797
  # Emit the metacode for the program.
798
  #
799
  ################################################################################
800
 
801
  #
802
  # Utilities for building opcodes or the associated description strings.
803
  #
804
  # Note:  These utilities do not write to the metacode file.
805
  #
806
 
807
  def Emit_AddLabel(self,name):
808
    """
809
    Append the label to the labels associated with the current program address.
810
    """
811
    self.emitLabelList += ':' + name + ' ';
812
 
813
  def Emit_EvalSingleValue(self,token):
814
    """
815
    Evaluate the optional single-byte value for a macro.
816
    """
817
    if token['type'] == 'symbol':
818
      token = self.ExpandSymbol(token,singleValue=True);
819
    if token['type'] == 'constant':
820
      name = token['value'];
821
      if not self.IsSymbol(name):
822
        raise Exception('Program Bug');
823
      ix = self.symbols['list'].index(name);
824
      if len(self.symbols['body'][ix]) != 1:
825
        raise asmDef.AsmException('Optional constant can only be one byte at %s' % token['loc']);
826
      return self.symbols['body'][ix][0]
827
    elif token['type'] == 'value':
828
      return token['value']
829
    else:
830
      raise asmDef.AsmException('Unrecognized optional argument "%s"' % token['value']);
831
 
832
  def Emit_GetAddrAndBank(self,name):
833
    """
834
    For the specified variable, return an ordered tuple of the memory address
835
    within its bank, the corresponding bank index, and the corresponding bank
836
    name.\n
837
    Note:  This is used for the .fetchvector and .storevector macro generation.
838
    """
839
    if not self.IsSymbol(name):
840
      raise asmDef.AsmException('"%s" is not a recognized symbol' % name);
841
    ixName = self.symbols['list'].index(name);
842
    if self.symbols['type'][ixName] != 'variable':
843
      raise asmDef.AsmException('"%s" is not a variable' % name);
844
    body = self.symbols['body'][ixName];
845
    bankName = body['memory'];
846
    ixMem = self.memories['list'].index(bankName);
847
    return (body['start'],self.memories['bank'][ixMem],bankName,);
848
 
849
  def Emit_GetBank(self,name):
850
    """
851
    For the specified variable, return the memory bank index.\n
852
    Note:  This is used for the .fetch, .fetch+, .fetch-, .store, .store+, and
853
           .store- macros.
854
    """
855
    if name not in self.memories['list']:
856
      raise asmDef.AsmException('"%s" not a memory' % name);
857
    ixMem = self.memories['list'].index(name);
858
    return self.memories['bank'][ixMem];
859
 
860
  def Emit_String(self,name=''):
861
    """
862
    Append the specified string to the list of labels for the current
863
    instruction, restart the list of labels, and return the composite string.
864
    """
865
    name = self.emitLabelList + name;
866
    self.emitLabelList = '';
867
    return name;
868
 
869
  #
870
  # Utilities to write single instructions to the metacode file.
871
  #
872
  # Note:  Other than the program header and the function names, these
873
  #        utilities write the function bodies.
874
  #
875
 
876
  def EmitOpcode(self,fp,opcode,name):
877
    """
878
    Write the specified opcode and the associated comment string.\n
879
    The leading bit for an opcode is always a '0'.
880
    """
881
    if not (0 <= opcode < 256):
882
      raise Exception('Program Bug -- opcode "0x%X" out of range');
883
    fp.write('0%02X %s\n' % (opcode,self.Emit_String(name)));
884
 
885
  def EmitParameter(self,fp,token):
886
    """
887
    Write the name (and range) of the specified parameter and the optional
888
    associated comment string.\n
889
    The string 'p' specifies that the parameter is to be inserted into the
890
    instruction body.\n
891
    Note:  The comment string may be the empty string if there were no labels
892
           immediately preceding the parameter.
893
    """
894
    name = token['value'];
895
    if not self.IsParameter(name):
896
      raise Exception('Program Bug');
897
    commentString = self.Emit_String();
898
    if commentString:
899
      fp.write('p %s%s %s\n' % (name,token['range'],commentString,));
900
    else:
901
      fp.write('p %s%s\n' % (name,token['range'],));
902
 
903
  def EmitPush(self,fp,value,name=None,tokenLoc=None):
904
    """
905
    Write the opcode to push a value onto the data stack.  Include the comment
906
    string including either the optionally provided symbol name or a printable
907
    representation of the value being pushed onto the stack.\n
908
    Note:  The printable value is included when a name is not provided so that
909
           the contents of single characters or of strings being pushed onto
910
           the stack can be read.\n
911
    Note:  The token location is an optional input required when the range of
912
           the provided value may not have been previously ensured to fit in
913
           one byte.
914
    """
915
    if not (-128 <= value < 256):
916
      if tokenLoc == None:
917
        raise Exception('Program Bug -- untrapped out-of-range token "%s"' % value);
918
      else:
919
        raise asmDef.AsmException('Value not representable by a byte at "%s"' % tokenLoc);
920
    if value < 0:
921
      value = value + 256;
922
    if type(name) == str:
923
      fp.write('1%02X %s\n' % ((value % 0x100),self.Emit_String(name)));
924
    elif (chr(value) in string.printable) and (chr(value) not in string.whitespace):
925
      fp.write('1%02X %s\n' % ((value % 0x100),self.Emit_String('%02X \'%c\'' % (value,value,))));
926
    else:
927
      fp.write('1%02X %s\n' % ((value % 0x100),self.Emit_String('0x%02X' % value)));
928
 
929
  def EmitVariable(self,fp,name):
930
    """
931
    Use the EmitPush method to push the address of a variable onto the data
932
    stack.
933
    """
934
    if not self.IsSymbol(name):
935
      raise asmDef.AsmException('Variable "%s" not recognized' % name);
936
    ixName = self.symbols['list'].index(name);
937
    if self.symbols['type'][ixName] != 'variable':
938
      raise asmDef.AsmException('"%s" is not a variable' % name);
939
    self.EmitPush(fp,self.symbols['body'][ixName]['start'],name);
940
 
941
  #
942
  # EmitOpcode, EmitMacro, and EmitProgram emit composite or more complicated
943
  # bodies.
944
  #
945
 
946
  def EmitOptArg(self,fp,token):
947
    """
948
    Write the metacode for optional arguments to macros.\n
949
    These must be single-instruction arguments.
950
    """
951
    # Symbols encountered in macros are expanded here instead of the
952
    # ExpandTokens method -- the code is much simpler this way even though the
953
    # associated error detection was deferred in the processing.  The symbol
954
    # must expand to a single value.
955
    if token['type'] == 'symbol':
956
      token = self.ExpandSymbol(token,singleValue=True);
957
    if token['type'] == 'constant':
958
      name = token['value'];
959
      if not self.IsSymbol(name):
960
        raise Exception('Program Bug');
961
      ix = self.symbols['list'].index(name);
962
      if len(self.symbols['body'][ix]) != 1:
963
        raise asmDef.AsmException('Optional constant can only be one byte at %s' % token['loc']);
964
      self.EmitPush(fp,self.symbols['body'][ix][0],self.Emit_String(name),tokenLoc=token['loc']);
965
    elif token['type'] in ('inport','outport','outstrobe'):
966
      name = token['value'];
967
      if not self.IsSymbol(name):
968
        raise Exception('Program Bug -- unrecognized inport/outport name "%s"');
969
      ix = self.symbols['list'].index(name);
970
      self.EmitPush(fp,self.symbols['body'][ix],self.Emit_String(name));
971
    elif token['type'] == 'instruction':
972
      self.EmitOpcode(fp,self.InstructionOpcode(token['value']),token['value']);
973
    elif token['type'] == 'parameter':
974
      self.EmitParameter(fp,token);
975
    elif token['type'] == 'value':
976
      self.EmitPush(fp,token['value'],tokenLoc=token['loc']);
977
    elif token['type'] == 'variable':
978
      self.EmitVariable(fp,token['value']);
979
    elif token['type'] == 'macro':
980
      self.EmitMacro(fp,token);
981
    else:
982
      raise asmDef.AsmException('Unrecognized optional argument "%s"' % token['value']);
983
 
984
  def EmitMacro(self,fp,token):
985
    """
986
    Write the metacode for a macro.
987
    """
988
    # .call
989
    if token['value'] == '.call':
990
      self.EmitPush(fp,token['address'] & 0xFF,'');
991
      self.EmitOpcode(fp,self.specialInstructions['call'] | (token['address'] >> 8),'call '+token['argument'][0]['value']);
992
      self.EmitOptArg(fp,token['argument'][1]);
993
    # .callc
994
    elif token['value'] == '.callc':
995
      self.EmitPush(fp,token['address'] & 0xFF,'');
996
      self.EmitOpcode(fp,self.specialInstructions['callc'] | (token['address'] >> 8),'callc '+token['argument'][0]['value']);
997
      self.EmitOptArg(fp,token['argument'][1]);
998
    # .fetch
999
    elif token['value'] == '.fetch':
1000
      name = token['argument'][0]['value'];
1001
      ixBank = self.Emit_GetBank(name);
1002
      self.EmitOpcode(fp,self.specialInstructions['fetch'] | ixBank,'fetch '+name);
1003
    # .fetch+
1004
    elif token['value'] == '.fetch+':
1005
      name = token['argument'][0]['value'];
1006
      ixBank = self.Emit_GetBank(name);
1007
      self.EmitOpcode(fp,self.specialInstructions['fetch+'] | ixBank,'fetch+('+name+')');
1008
    # .fetch-
1009
    elif token['value'] == '.fetch-':
1010
      name = token['argument'][0]['value'];
1011
      ixBank = self.Emit_GetBank(name);
1012
      self.EmitOpcode(fp,self.specialInstructions['fetch-'] | ixBank,'fetch-('+name+')');
1013
    # .fetchindexed
1014
    elif token['value'] == '.fetchindexed':
1015
      name = token['argument'][0]['value'];
1016
      (addr,ixBank,bankName) = self.Emit_GetAddrAndBank(name);
1017
      self.EmitPush(fp,addr,self.Emit_String(name),token['loc']);
1018
      self.EmitOpcode(fp,self.InstructionOpcode('+'),'+');
1019
      self.EmitOpcode(fp,self.specialInstructions['fetch'] | ixBank,'fetch '+bankName);
1020
    # .fetchoffset
1021
    elif token['value'] == '.fetchoffset':
1022
      name = token['argument'][0]['value'];
1023
      (addr,ixBank,bankName) = self.Emit_GetAddrAndBank(name);
1024
      offset = self.Emit_EvalSingleValue(token['argument'][1]);
1025
      self.EmitPush(fp,addr+offset,self.Emit_String('%s+%s' % (name,offset,)),token['loc']);
1026
      self.EmitOpcode(fp,self.specialInstructions['fetch'] | ixBank,'fetch '+bankName);
1027
    # .fetchvalue
1028
    elif token['value'] == '.fetchvalue':
1029
      name = token['argument'][0]['value'];
1030
      (addr,ixBank,bankName) = self.Emit_GetAddrAndBank(name);
1031
      self.EmitPush(fp,addr,self.Emit_String(name),token['loc']);
1032
      self.EmitOpcode(fp,self.specialInstructions['fetch'] | ixBank,'fetch '+bankName);
1033
    # .fetchvector
1034
    elif token['value'] == '.fetchvector':
1035
      name = token['argument'][0]['value'];
1036
      (addr,ixBank,bankName) = self.Emit_GetAddrAndBank(name);
1037
      N = int(token['argument'][1]['value']);
1038
      self.EmitPush(fp,addr+N-1,'%s+%d' % (name,N-1));
1039
      for dummy in range(N-1):
1040
        self.EmitOpcode(fp,self.specialInstructions['fetch-'] | ixBank,'fetch- '+bankName);
1041
      self.EmitOpcode(fp,self.specialInstructions['fetch'] | ixBank,'fetch '+bankName);
1042
    # .inport
1043
    elif token['value'] == '.inport':
1044
      name = token['argument'][0]['value'];
1045
      self.EmitPush(fp,self.InportAddress(name) & 0xFF,name);
1046
      self.EmitOpcode(fp,self.InstructionOpcode('inport'),'inport');
1047
    # .jump
1048
    elif token['value'] == '.jump':
1049
      self.EmitPush(fp,token['address'] & 0xFF,'');
1050
      self.EmitOpcode(fp,self.specialInstructions['jump'] | (token['address'] >> 8),'jump '+token['argument'][0]['value']);
1051
      self.EmitOptArg(fp,token['argument'][1]);
1052
    # .jumpc
1053
    elif token['value'] == '.jumpc':
1054
      self.EmitPush(fp,token['address'] & 0xFF,'');
1055
      self.EmitOpcode(fp,self.specialInstructions['jumpc'] | (token['address'] >> 8),'jumpc '+token['argument'][0]['value']);
1056
      self.EmitOptArg(fp,token['argument'][1]);
1057
    # .outport
1058
    elif token['value'] == '.outport':
1059
      name = token['argument'][0]['value'];
1060
      self.EmitPush(fp,self.OutportAddress(name) & 0xFF,name);
1061
      self.EmitOpcode(fp,self.InstructionOpcode('outport'),'outport');
1062
      self.EmitOptArg(fp,token['argument'][1]);
1063
    # .outstrobe
1064
    elif token['value'] == '.outstrobe':
1065
      name = token['argument'][0]['value'];
1066
      self.EmitPush(fp,self.OutportAddress(name) & 0xFF,name);
1067
      self.EmitOpcode(fp,self.InstructionOpcode('outport'),'outport');
1068
    # .return
1069
    elif token['value'] == '.return':
1070
      self.EmitOpcode(fp,self.specialInstructions['return'],'return');
1071
      self.EmitOptArg(fp,token['argument'][0]);
1072
    # .store
1073
    elif token['value'] == '.store':
1074
      name = token['argument'][0]['value'];
1075
      ixBank = self.Emit_GetBank(name);
1076
      self.EmitOpcode(fp,self.specialInstructions['store'] | ixBank,'store '+name);
1077
    # .store+
1078
    elif token['value'] == '.store+':
1079
      name = token['argument'][0]['value'];
1080
      ixBank = self.Emit_GetBank(name);
1081
      self.EmitOpcode(fp,self.specialInstructions['store+'] | ixBank,'store+ '+name);
1082
    # .store-
1083
    elif token['value'] == '.store-':
1084
      name = token['argument'][0]['value'];
1085
      ixBank = self.Emit_GetBank(name);
1086
      self.EmitOpcode(fp,self.specialInstructions['store-'] | ixBank,'store- '+name);
1087
    # .storeindexed
1088
    elif token['value'] == '.storeindexed':
1089
      name = token['argument'][0]['value'];
1090
      (addr,ixBank,bankName) = self.Emit_GetAddrAndBank(name);
1091
      self.EmitPush(fp,addr,self.Emit_String(name),token['loc']);
1092
      self.EmitOpcode(fp,self.InstructionOpcode('+'),'+');
1093
      self.EmitOpcode(fp,self.specialInstructions['store'] | ixBank,'store '+bankName);
1094
      self.EmitOptArg(fp,token['argument'][1]);
1095
    # .storeoffset
1096
    elif token['value'] == '.storeoffset':
1097
      name = token['argument'][0]['value'];
1098
      (addr,ixBank,bankName) = self.Emit_GetAddrAndBank(name);
1099
      offset = self.Emit_EvalSingleValue(token['argument'][1]);
1100
      self.EmitPush(fp,addr+offset,self.Emit_String('%s+%s' % (name,offset,)),token['loc']);
1101
      self.EmitOpcode(fp,self.specialInstructions['store'] | ixBank,'store '+bankName);
1102
      self.EmitOptArg(fp,token['argument'][2]);
1103
    # .storevalue
1104
    elif token['value'] == '.storevalue':
1105
      name = token['argument'][0]['value'];
1106
      (addr,ixBank,bankName) = self.Emit_GetAddrAndBank(name);
1107
      self.EmitPush(fp,addr,self.Emit_String(name),token['loc']);
1108
      self.EmitOpcode(fp,self.specialInstructions['store'] | ixBank,'store '+bankName);
1109
      self.EmitOptArg(fp,token['argument'][1]);
1110
    # .storevector
1111
    elif token['value'] == '.storevector':
1112
      (addr,ixBank,bankName) = self.Emit_GetAddrAndBank(token['argument'][0]['value']);
1113
      N = int(token['argument'][1]['value']);
1114
      self.EmitPush(fp,addr,token['argument'][0]['value']);
1115
      for dummy in range(N):
1116
        self.EmitOpcode(fp,self.specialInstructions['store+'] | ixBank,'store+ '+bankName);
1117
      self.EmitOpcode(fp,self.InstructionOpcode('drop'),'drop');
1118
    # error
1119
    else:
1120
      raise Exception('Program Bug -- Unrecognized macro "%s"' % token['value']);
1121
 
1122
  def EmitProgram(self,fp):
1123
    """
1124
    Write the program to the metacode file.\n
1125
    The frist line for the program has the format
1126
      :program address_main address_interrupt
1127
    where
1128
      address_main      is the address of the .main function (this should be 0)
1129
      address_interrupt is either the address of the optional interrupt
1130
                        function if it was defined or the 2-character string
1131
                        '[]'\n
1132
    The subsequent lines are sequences of
1133
      - function_name   indicates the start of a new function body and the name
1134
                        of the function
1135
      instructions      is multiple lines, one for each instruction in the
1136
                        function\n
1137
    The formats of the instruction lines are as follows:
1138
      value string      value is the next instruction to store and string is an
1139
                        optional string describing the instruction
1140
                        Note:  "value" must be a 3-digit hex string
1141
                               representing a 9-bit value
1142
                        Note:  The only place string should be empty is when
1143
                               pushing the 8 lsb of an address onto the start
1144
                               prior to a call, callc, jump, or jumpc
1145
                               instruction
1146
      p name            the single 'p' means that the name of a parameter and
1147
                        its range are to be converted into an instruction
1148
    """
1149
    # Write the program marker, address of .main, address or "[]" of .interrupt,
1150
    # and the total program length.
1151
    fp.write(':program');
1152
    fp.write(' %d' % self.functionEvaluation['address'][0]);
1153
    if self.interrupt:
1154
      fp.write(' %d' % self.functionEvaluation['address'][1]);
1155
    else:
1156
      fp.write(' []');
1157
    fp.write(' %d' % (self.functionEvaluation['address'][-1] + self.functionEvaluation['length'][-1]));
1158
    fp.write('\n');
1159
    # Emit the bodies
1160
    for ix in range(len(self.functionEvaluation['list'])):
1161
      fp.write('- %s\n' % self.functionEvaluation['list'][ix]);
1162
      self.emitLabelList = '';
1163
      for token in self.functionEvaluation['body'][ix]:
1164
        if token['type'] == 'value':
1165
          self.EmitPush(fp,token['value'],tokenLoc=token['loc']);
1166
        elif token['type'] == 'label':
1167
          self.Emit_AddLabel(token['value']);
1168
        elif token['type'] == 'constant':
1169
          if not self.IsSymbol(token['value']):
1170
            raise Exception('Program Bug');
1171
          ix = self.symbols['list'].index(token['value']);
1172
          body = self.symbols['body'][ix];
1173
          self.EmitPush(fp,body[-1],token['value'],tokenLoc=token['loc']);
1174
          for v in body[-2::-1]:
1175
            self.EmitPush(fp,v,tokenLoc=token['loc']);
1176
        elif token['type'] in ('inport','outport','outstrobe',):
1177
          if not self.IsSymbol(token['value']):
1178
            raise Exception('Program Bug');
1179
          ix = self.symbols['list'].index(token['value']);
1180
          self.EmitPush(fp,self.symbols['body'][ix],token['value'],tokenLoc=token['loc']);
1181
        elif token['type'] == 'instruction':
1182
          self.EmitOpcode(fp,self.InstructionOpcode(token['value']),token['value']);
1183
        elif token['type'] == 'macro':
1184
          self.EmitMacro(fp,token);
1185
        elif token['type'] == 'parameter':
1186
          self.EmitParameter(fp,token);
1187
        elif token['type'] == 'symbol':
1188
          self.EmitPush(fp,token['value'],token['name'],tokenLoc=token['loc']);
1189
        elif token['type'] == 'variable':
1190
          self.EmitVariable(fp,token['value']);
1191
        else:
1192
          raise Exception('Program Bug:  Unrecognized type "%s"' % token['type']);
1193
 
1194
  ################################################################################
1195
  #
1196
  # Initialize the object.
1197
  #
1198
  ################################################################################
1199
 
1200
  def __init__(self):
1201
    """
1202
    Initialize the tables definining the following:
1203
      directly invokable instruction mnemonics and the associated opcodes
1204
      indirectly inivoked instruction mnemonics and the associated opcodes
1205
        Note:  These are accessed through macros since they require an argument
1206
               or are part of multi-instruction sequences.
1207
      directives (other than ".include")
1208
      macros with type restrictions for required arguments and defaults and
1209
        restrictions for optional arguments\n
1210
    Initialize lists and members to record memory attributes, stack lengths,
1211
    body of the .main function, body of the optional .interrupt function,
1212
    current memory for variable definitions, etc.
1213
    """
1214
 
1215
    #
1216
    # Configure the instructions.
1217
    #
1218
 
1219
    self.instructions = dict(list=list(), opcode=list());
1220
    self.AddInstruction('&',            0x050);
1221
    self.AddInstruction('+',            0x018);
1222
    self.AddInstruction('-',            0x01C);
1223
    self.AddInstruction('-1<>',         0x023);
1224
    self.AddInstruction('-1=',          0x022);
1225
    self.AddInstruction('0<>',          0x021);
1226
    self.AddInstruction('0=',           0x020);
1227
    self.AddInstruction('0>>',          0x004);
1228
    self.AddInstruction('1+',           0x058);
1229
    self.AddInstruction('1-',           0x05C);
1230
    self.AddInstruction('1>>',          0x005);
1231
    self.AddInstruction('<<0',          0x001);
1232
    self.AddInstruction('<<1',          0x002);
1233
    self.AddInstruction('<<msb',        0x003);
1234
    self.AddInstruction('>r',           0x040);
1235
    self.AddInstruction('^',            0x052);
1236
    #self.AddInstruction('dis',          0x01C);
1237
    self.AddInstruction('drop',         0x054);
1238
    self.AddInstruction('dup',          0x008);
1239
    #self.AddInstruction('ena',          0x019);
1240
    self.AddInstruction('inport',       0x030);
1241
    self.AddInstruction('lsb>>',        0x007);
1242
    self.AddInstruction('msb>>',        0x006);
1243
    self.AddInstruction('nip',          0x053);
1244
    self.AddInstruction('nop',          0x000);
1245
    self.AddInstruction('or',           0x051);
1246
    self.AddInstruction('outport',      0x038);
1247
    self.AddInstruction('over',         0x00A);
1248
    self.AddInstruction('r>',           0x049);
1249
    self.AddInstruction('r@',           0x009);
1250
    self.AddInstruction('swap',         0x012);
1251
 
1252
    self.specialInstructions = dict();
1253
    self.specialInstructions['call']    = 0x0C0;
1254
    self.specialInstructions['callc']   = 0x0E0;
1255
    self.specialInstructions['fetch']   = 0x068;
1256
    self.specialInstructions['fetch+']  = 0x078;
1257
    self.specialInstructions['fetch-']  = 0x07C;
1258
    self.specialInstructions['jump']    = 0x080;
1259
    self.specialInstructions['jumpc']   = 0x0A0;
1260
    self.specialInstructions['return']  = 0x028;
1261
    self.specialInstructions['store']   = 0x060;
1262
    self.specialInstructions['store+']  = 0x070;
1263
    self.specialInstructions['store-']  = 0x074;
1264
 
1265
    #
1266
    # Enumerate the directives
1267
    # Note:  The ".include" directive is handled within asmDef.FileBodyIterator.
1268
    #
1269
 
1270
    self.directives = dict();
1271
 
1272
    self.directives['list']= list();
1273
    self.directives['list'].append('.constant');
1274
    self.directives['list'].append('.function');
1275
    self.directives['list'].append('.interrupt');
1276
    self.directives['list'].append('.main');
1277
    self.directives['list'].append('.memory');
1278
    self.directives['list'].append('.variable');
1279
 
1280
    #
1281
    #
1282
    # Configure the pre-defined macros
1283
    # Note:  'symbol' is a catch-call for functions, labels, variables, etc.
1284
    #        These are restricted to the appropriate types when the macros are
1285
    #        expanded.
1286
    #
1287
 
1288
    self.macros = dict(list=list(), length=list(), args=list(), nArgs=list());
1289
    self.AddMacro('.call',              3, [
1290
                                             ['','symbol'],
1291
                                             ['nop','instruction','singlemacro','singlevalue','symbol']
1292
                                           ]);
1293
    self.AddMacro('.callc',             3, [
1294
                                             ['','symbol'],
1295
                                             ['drop','instruction','singlevalue','symbol']
1296
                                           ]);
1297
    self.AddMacro('.fetch',             1, [ ['','symbol'] ]);
1298
    self.AddMacro('.fetch+',            1, [ ['','symbol'] ]);
1299
    self.AddMacro('.fetch-',            1, [ ['','symbol'] ]);
1300
    self.AddMacro('.fetchindexed',      3, [ ['','symbol'] ]);
1301
    self.AddMacro('.fetchoffset',       2, [
1302
                                             ['','symbol'],
1303
                                             ['','singlevalue','symbol']
1304
                                           ]);
1305
    self.AddMacro('.fetchvalue',        2, [ ['','symbol'] ]);
1306
    self.AddMacro('.fetchvector',      -1, [
1307
                                             ['','symbol'],
1308
                                             ['','singlevalue','symbol']
1309
                                           ]);
1310
    self.AddMacro('.inport',            2, [ ['','symbol'] ]);
1311
    self.AddMacro('.jump',              3, [
1312
                                             ['','symbol'],
1313
                                             ['nop','instruction','singlemacro','singlevalue','symbol']
1314
                                           ]);
1315
    self.AddMacro('.jumpc',             3, [
1316
                                             ['','symbol'],
1317
                                             ['drop','instruction','singlemacro','singlevalue','symbol']
1318
                                           ]);
1319
    self.AddMacro('.outport',           3, [
1320
                                             ['','symbol'],
1321
                                             ['drop','instruction','singlemacro','singlevalue','symbol']
1322
                                           ]);
1323
    self.AddMacro('.outstrobe',         2, [ ['','symbol'] ]);
1324
    self.AddMacro('.return',            2, [ ['nop','instruction','singlevalue','symbol'] ]);
1325
    self.AddMacro('.store',             1, [ ['','symbol'] ]);
1326
    self.AddMacro('.store+',            1, [ ['','symbol'] ]);
1327
    self.AddMacro('.store-',            1, [ ['','symbol'] ]);
1328
    self.AddMacro('.storeindexed',      4, [
1329
                                             ['','symbol'],
1330
                                             ['drop','instruction','singlemacro','singlevalue','symbol']
1331
                                           ]);
1332
    self.AddMacro('.storeoffset',        3, [
1333
                                             ['','symbol'],
1334
                                             ['','singlevalue','symbol'],
1335
                                             ['drop','instruction','singlemacro','singlevalue','symbol']
1336
                                           ]);
1337
    self.AddMacro('.storevalue',        3, [
1338
                                             ['','symbol'],
1339
                                             ['drop','instruction','singlemacro','singlevalue','symbol']
1340
                                           ]);
1341
    self.AddMacro('.storevector',      -1, [
1342
                                             ['','symbol'],
1343
                                             ['','singlevalue','symbol'],
1344
                                           ]);
1345
 
1346
    #
1347
    # List the macros that have special symbols for their first argument.
1348
    #
1349
 
1350
    self.MacrosWithSpecialFirstSymbol = ('.call','.callc','.jump','.jumpc',);
1351
 
1352
    #
1353
    # Externally defined parameters.
1354
    #
1355
 
1356
    self.memoryLength = dict();
1357
    self.stackLength = dict();
1358
 
1359
    #
1360
    # Configure the containers for the expanded main, interrupt, function,
1361
    # macro, etc. definitions.
1362
    #
1363
 
1364
    self.interrupt = None;
1365
    self.main = None;
1366
    self.symbols = dict(list=list(), type=list(), body=list());
1367
    self.currentMemory = None;

powered by: WebSVN 2.1.0

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