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

Subversion Repositories ssbcc

[/] [ssbcc/] [trunk/] [core/] [9x8/] [asmDef_9x8.py] - Diff between revs 3 and 4

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 3 Rev 4
################################################################################
################################################################################
#
#
# Copyright 2012-2014, Sinclair R.F., Inc.
# Copyright 2012-2014, Sinclair R.F., Inc.
#
#
# Assembly language definitions for SSBCC 9x8.
# Assembly language definitions for SSBCC 9x8.
#
#
################################################################################
################################################################################
 
 
import copy
import copy
import os
import os
import re
import re
import string
import string
import sys
import sys
import types
import types
 
 
import asmDef
import asmDef
 
 
class asmDef_9x8:
class asmDef_9x8:
  """
  """
  Class for core-specific opcodes, macros, etc. for core/9x8.
  Class for core-specific opcodes, macros, etc. for core/9x8.
  """
  """
 
 
  ################################################################################
  ################################################################################
  #
  #
  # External interface to the directives.
  # External interface to the directives.
  #
  #
  ################################################################################
  ################################################################################
 
 
  def IsDirective(self,name):
  def IsDirective(self,name):
    """
    """
    Indicate whether or not the string "name" is a directive.
    Indicate whether or not the string "name" is a directive.
    """
    """
    return name in self.directives['list'];
    return name in self.directives['list'];
 
 
  ################################################################################
  ################################################################################
  #
  #
  # Record symbols
  # Record symbols
  #
  #
  ################################################################################
  ################################################################################
 
 
  def AddSymbol(self,name,stype,body=None):
  def AddSymbol(self,name,stype,body=None):
    """
    """
    Add the named global symbol to the list of symbols including its mandatory
    Add the named global symbol to the list of symbols including its mandatory
    type and an optional body.\n
    type and an optional body.\n
    Note:  Symbols include memory names, variables, constants, functions,
    Note:  Symbols include memory names, variables, constants, functions,
           parameters, inports, outports, ...
           parameters, inports, outports, ...
    """
    """
    if self.IsSymbol(name):
    if self.IsSymbol(name):
      raise Exception('Program Bug -- name "%s" already exists is symbols' % name);
      raise Exception('Program Bug -- name "%s" already exists is symbols' % name);
    self.symbols['list'].append(name);
    self.symbols['list'].append(name);
    self.symbols['type'].append(stype);
    self.symbols['type'].append(stype);
    self.symbols['body'].append(body);
    self.symbols['body'].append(body);
 
 
  def IsSymbol(self,name):
  def IsSymbol(self,name):
    return name in self.symbols['list'];
    return name in self.symbols['list'];
 
 
  def SymbolDict(self):
  def SymbolDict(self):
    """
    """
    Return a dict object usable by the eval function with the currently defines
    Return a dict object usable by the eval function with the currently defines
    symbols for constants, variables, memory lengths, stack lengths, and signal
    symbols for constants, variables, memory lengths, stack lengths, and signal
    lengths.
    lengths.
    """
    """
    t = dict();
    t = dict();
    for ixSymbol in range(len(self.symbols['list'])):
    for ixSymbol in range(len(self.symbols['list'])):
      name = self.symbols['list'][ixSymbol];
      name = self.symbols['list'][ixSymbol];
      stype = self.symbols['type'][ixSymbol];
      stype = self.symbols['type'][ixSymbol];
      if stype == 'constant':
      if stype == 'constant':
        t[name] = self.symbols['body'][ixSymbol][0];
        t[name] = self.symbols['body'][ixSymbol][0];
      elif stype == 'variable':
      elif stype == 'variable':
        t[name] = self.symbols['body'][ixSymbol]['start'];
        t[name] = self.symbols['body'][ixSymbol]['start'];
    sizes=dict();
    sizes=dict();
    for name in self.memoryLength:
    for name in self.memoryLength:
      sizes[name] = self.memoryLength[name];
      sizes[name] = self.memoryLength[name];
    for name in self.stackLength:
    for name in self.stackLength:
      sizes[name] = self.stackLength[name];
      sizes[name] = self.stackLength[name];
    t['size'] = sizes;
    t['size'] = sizes;
    return t;
    return t;
 
 
  ################################################################################
  ################################################################################
  #
  #
  # Configure the class for identifying and processing macros.
  # Configure the class for identifying and processing macros.
  #
  #
  ################################################################################
  ################################################################################
 
 
  def AddMacro(self,name,macroLength,args):
  def AddMacro(self,name,macroLength,args):
    """
    """
    Add a macro to the list of recognized macros.
    Add a macro to the list of recognized macros.
      name              string with the name of the macro
      name              string with the name of the macro
      macroLength       number of instructions the macro expands to
      macroLength       number of instructions the macro expands to
                        Note:  A negative value means that the macro has a
                        Note:  A negative value means that the macro has a
                               variable length (see MacroLength below)
                               variable length (see MacroLength below)
      args              list of the arguments
      args              list of the arguments
                        each element of this list is an array of strings specifying the following:
                        each element of this list is an array of strings specifying the following:
                          1.  If the first element is the empty string, then
                          1.  If the first element is the empty string, then
                              there is no default value for the argument,
                              there is no default value for the argument,
                              otherwise the listed string is the default
                              otherwise the listed string is the default
                              value of the optional argument.
                              value of the optional argument.
                          2.  The remaining elements of the list are the types
                          2.  The remaining elements of the list are the types
                              of arguments that can be accepted for the
                              of arguments that can be accepted for the
                              required or optional arguments.
                              required or optional arguments.
                        Note:  Only the last list in args is allowed to
                        Note:  Only the last list in args is allowed to
                               indicate an optional value for that argument.
                               indicate an optional value for that argument.
 
 
    Also record the allowed number of allowed arguments to the macro.
    Also record the allowed number of allowed arguments to the macro.
    """
    """
    if name in self.macros['list']:
    if name in self.macros['list']:
      raise Exception('Program Bug -- name "%s" has already been listed as a macro' % name);
      raise Exception('Program Bug -- name "%s" has already been listed as a macro' % name);
    self.macros['list'].append(name);
    self.macros['list'].append(name);
    self.macros['length'].append(macroLength);
    self.macros['length'].append(macroLength);
    self.macros['args'].append(args);
    self.macros['args'].append(args);
    # Compute the range of the number of allowed arguments by first counting
    # Compute the range of the number of allowed arguments by first counting
    # the number of required arguments and then determining whether or not
    # the number of required arguments and then determining whether or not
    # there is at most one optional argument.
    # there is at most one optional argument.
    nRequired = 0;
    nRequired = 0;
    while (nRequired < len(args)) and (args[nRequired][0] == ''):
    while (nRequired < len(args)) and (args[nRequired][0] == ''):
      nRequired = nRequired + 1;
      nRequired = nRequired + 1;
    if nRequired < len(args)-1:
    if nRequired < len(args)-1:
      raise Exception('Program Bug -- Only the last macro argument can be optional');
      raise Exception('Program Bug -- Only the last macro argument can be optional');
    self.macros['nArgs'].append(range(nRequired,len(args)+1));
    self.macros['nArgs'].append(range(nRequired,len(args)+1));
 
 
  def AddMacroSearchPath(self,path):
  def AddMacroSearchPath(self,path):
    self.macroSearchPaths.append(path);
    self.macroSearchPaths.append(path);
 
 
  def AddUserMacro(self,macroName,macroSearchPaths=None):
  def AddUserMacro(self,macroName,macroSearchPaths=None):
    """
    """
    Add a user-defined macro by processing the associated Python script.
    Add a user-defined macro by processing the associated Python script.
      macroName         name of the macro
      macroName         name of the macro
                        The associated Python script must be named
                        The associated Python script must be named
                        <macroName>.py and must be in the project directory, an
                        <macroName>.py and must be in the project directory, an
                        included directory, or must be one of the macros
                        included directory, or must be one of the macros
                        provided in "macros" subdirectory of this directory.
                        provided in "macros" subdirectory of this directory.
    """
    """
    if not macroSearchPaths:
    if not macroSearchPaths:
      macroSearchPaths = self.macroSearchPaths;
      macroSearchPaths = self.macroSearchPaths;
    for testPath in macroSearchPaths:
    for testPath in macroSearchPaths:
      fullMacro = os.path.join(testPath,'%s.py' % macroName);
      fullMacro = os.path.join(testPath,'%s.py' % macroName);
      if os.path.isfile(fullMacro):
      if os.path.isfile(fullMacro):
        break;
        break;
    else:
    else:
      raise asmDef.AsmException('Definition for macro "%s" not found' % macroName);
      raise asmDef.AsmException('Definition for macro "%s" not found' % macroName);
    execfile(fullMacro);
    execfile(fullMacro);
    exec('%s(self)' % macroName);
    exec('%s(self)' % macroName);
 
 
  def IsBuiltInMacro(self,name):
  def IsBuiltInMacro(self,name):
    """
    """
    Indicate if the macro is built-in to the assembler or is taken from the
    Indicate if the macro is built-in to the assembler or is taken from the
    ./macros directory.
    ./macros directory.
    """
    """
    return name in self.macros['builtIn'];
    return name in self.macros['builtIn'];
 
 
  def IsMacro(self,name):
  def IsMacro(self,name):
    """
    """
    Indicate whether or not the string "name" is a recognized macro.
    Indicate whether or not the string "name" is a recognized macro.
    """
    """
    return name in self.macros['list'];
    return name in self.macros['list'];
 
 
  def IsSingleMacro(self,name):
  def IsSingleMacro(self,name):
    """
    """
    Indicate whether or not the macro is only one instruction long.
    Indicate whether or not the macro is only one instruction long.
    """
    """
    if name not in self.macros['list']:
    if name not in self.macros['list']:
      raise Exception('Program Bug -- name "%s" is not a macro' % name);
      raise Exception('Program Bug -- name "%s" is not a macro' % name);
    ix = self.macros['list'].index(name);
    ix = self.macros['list'].index(name);
    return (self.macros['length'][ix] == 1);
    return (self.macros['length'][ix] == 1);
 
 
  def MacroArgTypes(self,name,ixArg):
  def MacroArgTypes(self,name,ixArg):
    """
    """
    Return the list of allowed types for the macro name for argument ixArg.
    Return the list of allowed types for the macro name for argument ixArg.
    """
    """
    if name not in self.macros['list']:
    if name not in self.macros['list']:
      raise Exception('Program Bug -- name "%s" is not a macro' % name);
      raise Exception('Program Bug -- name "%s" is not a macro' % name);
    ix = self.macros['list'].index(name);
    ix = self.macros['list'].index(name);
    return self.macros['args'][ix][ixArg][1:];
    return self.macros['args'][ix][ixArg][1:];
 
 
  def MacroDefault(self,name,ixArg):
  def MacroDefault(self,name,ixArg):
    """
    """
    Return the default argument for the macro name for argument ixArg.
    Return the default argument for the macro name for argument ixArg.
    """
    """
    if name not in self.macros['list']:
    if name not in self.macros['list']:
      raise Exception('Program Bug -- name "%s" is not a macro' % name);
      raise Exception('Program Bug -- name "%s" is not a macro' % name);
    ix = self.macros['list'].index(name);
    ix = self.macros['list'].index(name);
    return self.macros['args'][ix][ixArg][0];
    return self.macros['args'][ix][ixArg][0];
 
 
  def MacroLength(self,token):
  def MacroLength(self,token):
    """
    """
    Return the length of fixed-length macros or compute and return the length
    Return the length of fixed-length macros or compute and return the length
    of variable-length macros.
    of variable-length macros.
    """
    """
    if token['value'] not in self.macros['list']:
    if token['value'] not in self.macros['list']:
      raise Exception('Program Bug -- name "%s" is not a macro' % token['value']);
      raise Exception('Program Bug -- name "%s" is not a macro' % token['value']);
    ix = self.macros['list'].index(token['value']);
    ix = self.macros['list'].index(token['value']);
    length = self.macros['length'][ix];
    length = self.macros['length'][ix];
    if type(length) == int:
    if type(length) == int:
      return length;
      return length;
    elif type(length) == types.FunctionType:
    elif type(length) == types.FunctionType:
      return length(self,token['argument']);
      return length(self,token['argument']);
    else:
    else:
      raise Exception('Program Bug -- Unrecognized variable length macro "%s"' % token['value']);
      raise Exception('Program Bug -- Unrecognized variable length macro "%s"' % token['value']);
 
 
  def MacroNumberArgs(self,name):
  def MacroNumberArgs(self,name):
    """
    """
    Return the range of the number of allowed arguments to the named macro.
    Return the range of the number of allowed arguments to the named macro.
    """
    """
    if name not in self.macros['list']:
    if name not in self.macros['list']:
      raise Exception('Program bug -- name "%s" is not a macro' % name);
      raise Exception('Program bug -- name "%s" is not a macro' % name);
    ix = self.macros['list'].index(name);
    ix = self.macros['list'].index(name);
    return self.macros['nArgs'][ix];
    return self.macros['nArgs'][ix];
 
 
  ################################################################################
  ################################################################################
  #
  #
  # Configure the class for processing instructions.
  # Configure the class for processing instructions.
  #
  #
  ################################################################################
  ################################################################################
 
 
  def AddInstruction(self,name,opcode):
  def AddInstruction(self,name,opcode):
    """
    """
    Add an instruction to the list of recognized instructions.
    Add an instruction to the list of recognized instructions.
    """
    """
    self.instructions['list'].append(name);
    self.instructions['list'].append(name);
    self.instructions['opcode'].append(opcode);
    self.instructions['opcode'].append(opcode);
 
 
  def IsInstruction(self,name):
  def IsInstruction(self,name):
    """
    """
    Indicate whether or not the argument is an instruction.
    Indicate whether or not the argument is an instruction.
    """
    """
    return name in self.instructions['list'];
    return name in self.instructions['list'];
 
 
  def InstructionOpcode(self,name):
  def InstructionOpcode(self,name):
    """
    """
    Return the opcode for the specified instruction.
    Return the opcode for the specified instruction.
    """
    """
    if not self.IsInstruction(name):
    if not self.IsInstruction(name):
      raise Exception('Program Bug:  "%s" not in instruction list' % name);
      raise Exception('Program Bug:  "%s" not in instruction list' % name);
    ix = self.instructions['list'].index(name);
    ix = self.instructions['list'].index(name);
    return self.instructions['opcode'][ix];
    return self.instructions['opcode'][ix];
 
 
  ################################################################################
  ################################################################################
  #
  #
  # Register input and output port names and addresses.
  # Register input and output port names and addresses.
  #
  #
  ################################################################################
  ################################################################################
 
 
  def IsConstant(self,name):
  def IsConstant(self,name):
    """
    """
    Indicate whether or not the named symbol is an inport.
    Indicate whether or not the named symbol is an inport.
    """
    """
    if not self.IsSymbol(name):
    if not self.IsSymbol(name):
      return False;
      return False;
    ix = self.symbols['list'].index(name);
    ix = self.symbols['list'].index(name);
    return self.symbols['type'][ix] == 'constant';
    return self.symbols['type'][ix] == 'constant';
 
 
  def IsInport(self,name):
  def IsInport(self,name):
    """
    """
    Indicate whether or not the named symbol is an inport.
    Indicate whether or not the named symbol is an inport.
    """
    """
    if not self.IsSymbol(name):
    if not self.IsSymbol(name):
      return False;
      return False;
    ix = self.symbols['list'].index(name);
    ix = self.symbols['list'].index(name);
    return self.symbols['type'][ix] == 'inport';
    return self.symbols['type'][ix] == 'inport';
 
 
  def IsOutport(self,name):
  def IsOutport(self,name):
    """
    """
    Indicate whether or not the named symbol is an outport.
    Indicate whether or not the named symbol is an outport.
    """
    """
    if not self.IsSymbol(name):
    if not self.IsSymbol(name):
      return False;
      return False;
    ix = self.symbols['list'].index(name);
    ix = self.symbols['list'].index(name);
    return self.symbols['type'][ix] == 'outport';
    return self.symbols['type'][ix] == 'outport';
 
 
  def IsOutstrobe(self,name):
  def IsOutstrobe(self,name):
    """
    """
    Indicate whether or not the named symbol is a strobe-only outport.
    Indicate whether or not the named symbol is a strobe-only outport.
    """
    """
    if not self.IsSymbol(name):
    if not self.IsSymbol(name):
      return False;
      return False;
    ix = self.symbols['list'].index(name);
    ix = self.symbols['list'].index(name);
    return self.symbols['type'][ix] == 'outstrobe';
    return self.symbols['type'][ix] == 'outstrobe';
 
 
  def IsParameter(self,name):
  def IsParameter(self,name):
    """
    """
    Indicate whether or not the named symbol is a parameter.
    Indicate whether or not the named symbol is a parameter.
    """
    """
    if not self.IsSymbol(name):
    if not self.IsSymbol(name):
      return False;
      return False;
    ix = self.symbols['list'].index(name);
    ix = self.symbols['list'].index(name);
    return self.symbols['type'][ix] == 'parameter';
    return self.symbols['type'][ix] == 'parameter';
 
 
  def InportAddress(self,name):
  def InportAddress(self,name):
    """
    """
    Return the address of the named inport.
    Return the address of the named inport.
    """
    """
    if not self.IsInport(name):
    if not self.IsInport(name):
      raise Exception('Program Bug -- "%s" is not an inport' % name);
      raise Exception('Program Bug -- "%s" is not an inport' % name);
    ix = self.symbols['list'].index(name);
    ix = self.symbols['list'].index(name);
    return self.symbols['body'][ix];
    return self.symbols['body'][ix];
 
 
  def OutportAddress(self,name):
  def OutportAddress(self,name):
    """
    """
    Return the address of the named outport.
    Return the address of the named outport.
    """
    """
    if not self.IsOutport(name) and not self.IsOutstrobe(name):
    if not self.IsOutport(name) and not self.IsOutstrobe(name):
      raise Exception('Program Bug -- "%s" is not an outport' % name);
      raise Exception('Program Bug -- "%s" is not an outport' % name);
    ix = self.symbols['list'].index(name);
    ix = self.symbols['list'].index(name);
    return self.symbols['body'][ix];
    return self.symbols['body'][ix];
 
 
  def RegisterInport(self,name,address):
  def RegisterInport(self,name,address):
    """
    """
    Add the named inport to the list of recognized symbols and record its
    Add the named inport to the list of recognized symbols and record its
    address as the body of the inport.
    address as the body of the inport.
    """
    """
    if self.IsSymbol(name):
    if self.IsSymbol(name):
      raise Exception('Program Bug -- repeated symbol name "%s"' % name);
      raise Exception('Program Bug -- repeated symbol name "%s"' % name);
    self.AddSymbol(name,'inport',address);
    self.AddSymbol(name,'inport',address);
 
 
  def RegisterOutport(self,name,address):
  def RegisterOutport(self,name,address):
    """
    """
    Add the named outport to the list of recognized symbols and record its
    Add the named outport to the list of recognized symbols and record its
    address as the body of the outport.
    address as the body of the outport.
    """
    """
    if self.IsSymbol(name):
    if self.IsSymbol(name):
      raise Exception('Program Bug -- repeated symbol name "%s"' % name);
      raise Exception('Program Bug -- repeated symbol name "%s"' % name);
    self.AddSymbol(name,'outport',address);
    self.AddSymbol(name,'outport',address);
 
 
  def RegisterOutstrobe(self,name,address):
  def RegisterOutstrobe(self,name,address):
    """
    """
    Add the named outport to the list of recognized symbols and record its
    Add the named outport to the list of recognized symbols and record its
    address as the body of the strobe-only outports.
    address as the body of the strobe-only outports.
    """
    """
    if self.IsSymbol(name):
    if self.IsSymbol(name):
      raise Exception('Program Bug -- repeated symbol name "%s"' % name);
      raise Exception('Program Bug -- repeated symbol name "%s"' % name);
    self.AddSymbol(name,'outstrobe',address);
    self.AddSymbol(name,'outstrobe',address);
 
 
  def RegisterParameterName(self,name):
  def RegisterParameterName(self,name):
    """
    """
    Add the named parameter to the list of regognized symbols.\n
    Add the named parameter to the list of regognized symbols.\n
    Note:  Parameters do not have a body.
    Note:  Parameters do not have a body.
    """
    """
    if self.IsSymbol(name):
    if self.IsSymbol(name):
      raise Exception('Program Bug -- repeated symbol name "%s"' % name);
      raise Exception('Program Bug -- repeated symbol name "%s"' % name);
    self.AddSymbol(name,'parameter');
    self.AddSymbol(name,'parameter');
 
 
  def RegisterMemoryLength(self,name,length):
  def RegisterMemoryLength(self,name,length):
    """
    """
    Record the length of the specified memory.\n
    Record the length of the specified memory.\n
    Note:  This is used to evaluate "size[name]" in "${...}" expressions.
    Note:  This is used to evaluate "size[name]" in "${...}" expressions.
    """
    """
    self.memoryLength[name] = length;
    self.memoryLength[name] = length;
 
 
  def RegisterStackLength(self,name,length):
  def RegisterStackLength(self,name,length):
    """
    """
    Record the length of the specified stack.\n
    Record the length of the specified stack.\n
    Note:  This is used to evaluate "size[name]" in "${...}" expressions.
    Note:  This is used to evaluate "size[name]" in "${...}" expressions.
    """
    """
    self.stackLength[name] = length;
    self.stackLength[name] = length;
 
 
  ################################################################################
  ################################################################################
  #
  #
  # Check a list of raw tokens to ensure their proper format.
  # Check a list of raw tokens to ensure their proper format.
  #
  #
  ################################################################################
  ################################################################################
 
 
  def CheckSymbolToken(self,name,allowableTypes,loc):
  def CheckSymbolToken(self,name,allowableTypes,loc):
    """
    """
    Syntax check for symbols, either by themselves or as a macro argument.\n
    Syntax check for symbols, either by themselves or as a macro argument.\n
    Note:  This is used by CheckRawTokens.
    Note:  This is used by CheckRawTokens.
    """
    """
    if not self.IsSymbol(name):
    if not self.IsSymbol(name):
      raise asmDef.AsmException('Undefined symbol "%s" at %s' % (name,loc));
      raise asmDef.AsmException('Undefined symbol "%s" at %s' % (name,loc));
    ixName = self.symbols['list'].index(name);
    ixName = self.symbols['list'].index(name);
    if self.symbols['type'][ixName] not in allowableTypes:
    if self.symbols['type'][ixName] not in allowableTypes:
      raise asmDef.AsmException('Illegal symbol at %s' % loc);
      raise asmDef.AsmException('Illegal symbol at %s' % loc);
 
 
  def CheckRawTokens(self,rawTokens):
  def CheckRawTokens(self,rawTokens):
    """
    """
    Syntax check for directive bodies.\n
    Syntax check for directive bodies.\n
    Note:  This core-specific method is called by the top-level assembler after
    Note:  This core-specific method is called by the top-level assembler after
           the RawTokens method.
           the RawTokens method.
    """
    """
    # Ensure the first token is a directive.
    # Ensure the first token is a directive.
    firstToken = rawTokens[0];
    firstToken = rawTokens[0];
    if firstToken['type'] != 'directive':
    if firstToken['type'] != 'directive':
      raise Exception('Program Bug triggered at %s' % firstToken['loc']);
      raise Exception('Program Bug triggered at %s' % firstToken['loc']);
    # Ensure the directive bodies are not too short.
    # Ensure the directive bodies are not too short.
    if (firstToken['value'] in ('.main','.interrupt',)) and not (len(rawTokens) > 1):
    if (firstToken['value'] in ('.main','.interrupt',)) and not (len(rawTokens) > 1):
      raise asmDef.AsmException('"%s" missing body at %s' % (firstToken['value'],firstToken['loc'],));
      raise asmDef.AsmException('"%s" missing body at %s' % (firstToken['value'],firstToken['loc'],));
    if (firstToken['value'] in ('.macro',)) and not (len(rawTokens) == 2):
    if (firstToken['value'] in ('.macro',)) and not (len(rawTokens) == 2):
      raise asmDef.AsmException('body for "%s" directive must have exactly one argument at %s' % (firstToken['value'],firstToken['loc'],));
      raise asmDef.AsmException('body for "%s" directive must have exactly one argument at %s' % (firstToken['value'],firstToken['loc'],));
    if (firstToken['value'] in ('.constant','.function','.memory','.variable',)) and not (len(rawTokens) >= 3):
    if (firstToken['value'] in ('.constant','.function','.memory','.variable',)) and not (len(rawTokens) >= 3):
      raise asmDef.AsmException('body for "%s" directive too short at %s' % (firstToken['value'],firstToken['loc'],));
      raise asmDef.AsmException('body for "%s" directive too short at %s' % (firstToken['value'],firstToken['loc'],));
    # Ensure the main body ends in a ".jump".
    # Ensure the main body ends in a ".jump".
    lastToken = rawTokens[-1];
    lastToken = rawTokens[-1];
    if firstToken['value'] == '.main':
    if firstToken['value'] == '.main':
      if (lastToken['type'] != 'macro') or (lastToken['value'] != '.jump'):
      if (lastToken['type'] != 'macro') or (lastToken['value'] != '.jump'):
        raise asmDef.AsmException('.main body does not end in ".jump" at %s' % lastToken['loc']);
        raise asmDef.AsmException('.main body does not end in ".jump" at %s' % lastToken['loc']);
    # Ensure functions and interrupts end in a ".jump" or ".return".
    # Ensure functions and interrupts end in a ".jump" or ".return".
    if firstToken['value'] in ('.function','.interrupt',):
    if firstToken['value'] in ('.function','.interrupt',):
      if (lastToken['type'] != 'macro') or (lastToken['value'] not in ('.jump','.return',)):
      if (lastToken['type'] != 'macro') or (lastToken['value'] not in ('.jump','.return',)):
        raise asmDef.AsmException('Last entry in ".function" or ".interrupt" must be a ".jump" or ".return" at %s' % lastToken['loc']);
        raise asmDef.AsmException('Last entry in ".function" or ".interrupt" must be a ".jump" or ".return" at %s' % lastToken['loc']);
    # Ensure no macros and no instructions in non-"functions".
    # Ensure no macros and no instructions in non-"functions".
    # Byproduct:  No labels allowed in non-"functions".
    # Byproduct:  No labels allowed in non-"functions".
    if firstToken['value'] not in ('.function','.interrupt','.main',):
    if firstToken['value'] not in ('.function','.interrupt','.main',):
      for token in rawTokens[2:]:
      for token in rawTokens[2:]:
        if (token['type'] == 'macro'):
        if (token['type'] == 'macro'):
          raise asmDef.AsmException('Macro not allowed in directive at %s' % token['loc']);
          raise asmDef.AsmException('Macro not allowed in directive at %s' % token['loc']);
        if token['type'] == 'instruction':
        if token['type'] == 'instruction':
          raise asmDef.AsmException('Instruction not allowed in directive at %s' % token['loc']);
          raise asmDef.AsmException('Instruction not allowed in directive at %s' % token['loc']);
    # Ensure local labels are defined and used.
    # Ensure local labels are defined and used.
    labelDefs = list();
    labelDefs = list();
    for token in rawTokens:
    for token in rawTokens:
      if token['type'] == 'label':
      if token['type'] == 'label':
        name = token['value'];
        name = token['value'];
        if name in labelDefs:
        if name in labelDefs:
          raise asmDef.AsmException('Repeated label definition "%s" at %s' % (name,token['loc'],));
          raise asmDef.AsmException('Repeated label definition "%s" at %s' % (name,token['loc'],));
        labelDefs.append(name);
        labelDefs.append(name);
    labelsUsed = list();
    labelsUsed = list();
    for token in rawTokens:
    for token in rawTokens:
      if (token['type'] == 'macro') and (token['value'] in ('.jump','.jumpc',)):
      if (token['type'] == 'macro') and (token['value'] in ('.jump','.jumpc',)):
        target = token['argument'][0]['value'];
        target = token['argument'][0]['value'];
        if target not in labelDefs:
        if target not in labelDefs:
          raise asmDef.AsmException('label definition for target missing at %s' % token['loc']);
          raise asmDef.AsmException('label definition for target missing at %s' % token['loc']);
        labelsUsed.append(target);
        labelsUsed.append(target);
    labelsUnused = set(labelDefs) - set(labelsUsed);
    labelsUnused = set(labelDefs) - set(labelsUsed);
    if labelsUnused:
    if labelsUnused:
      raise asmDef.AsmException('Unused label(s) %s in body %s' % (labelsUnused,firstToken['loc']));
      raise asmDef.AsmException('Unused label(s) %s in body %s' % (labelsUnused,firstToken['loc']));
    # Ensure referenced symbols are already defined (other than labels and
    # Ensure referenced symbols are already defined (other than labels and
    # function names for call and jump macros).
    # function names for call and jump macros).
    checkBody = False;
    checkBody = False;
    if (rawTokens[0]['type'] == 'directive') and (rawTokens[0]['value'] in ('.function','.interrupt','.main',)):
    if (rawTokens[0]['type'] == 'directive') and (rawTokens[0]['value'] in ('.function','.interrupt','.main',)):
      checkBody = True;
      checkBody = True;
    if checkBody:
    if checkBody:
      for token in rawTokens[2:]:
      for token in rawTokens[2:]:
        if token['type'] == 'symbol':
        if token['type'] == 'symbol':
          allowableTypes = ('constant','inport','macro','outport','outstrobe','parameter','variable',);
          allowableTypes = ('constant','inport','macro','outport','outstrobe','parameter','variable',);
          self.CheckSymbolToken(token['value'],allowableTypes,token['loc']);
          self.CheckSymbolToken(token['value'],allowableTypes,token['loc']);
        elif token['type'] == 'macro':
        elif token['type'] == 'macro':
          allowableTypes = ('RAM','ROM','constant','inport','outport','outstrobe','parameter','variable',);
          allowableTypes = ('RAM','ROM','constant','inport','outport','outstrobe','parameter','variable',);
          ixFirst = 1 if token['value'] in self.MacrosWithSpecialFirstSymbol else 0;
          ixFirst = 1 if token['value'] in self.MacrosWithSpecialFirstSymbol else 0;
          for arg in  token['argument'][ixFirst:]:
          for arg in  token['argument'][ixFirst:]:
            if arg['type'] == 'symbol':
            if arg['type'] == 'symbol':
              self.CheckSymbolToken(arg['value'],allowableTypes,arg['loc']);
              self.CheckSymbolToken(arg['value'],allowableTypes,arg['loc']);
 
 
  ################################################################################
  ################################################################################
  #
  #
  # fill in symbols, etc. in the list of raw tokens.
  # fill in symbols, etc. in the list of raw tokens.
  #
  #
  ################################################################################
  ################################################################################
 
 
  def ByteList(self,rawTokens,limit=False):
  def ByteList(self,rawTokens,limit=False):
    """
    """
    Return either (1) a list comprised of a single token which may not be a
    Return either (1) a list comprised of a single token which may not be a
    byte or (2) a list comprised of multiple tokens, each of which is a single
    byte or (2) a list comprised of multiple tokens, each of which is a single
    byte.\n
    byte.\n
    Note:  This is called by FillRawTokens.
    Note:  This is called by FillRawTokens.
    """
    """
    if len(rawTokens) > 1:
    if len(rawTokens) > 1:
      limit = True;
      limit = True;
    values = list();
    values = list();
    try:
    try:
      for token in rawTokens:
      for token in rawTokens:
        if token['type'] == 'value':
        if token['type'] == 'value':
          v = token['value'];
          v = token['value'];
          if type(v) == int:
          if type(v) == int:
            if limit and not (-128 <= v < 256):
            if limit and not (-128 <= v < 256):
              raise Exception('Program Bug -- unexpected out-of-range value');
              raise Exception('Program Bug -- unexpected out-of-range value');
            values.append(v);
            values.append(v);
          else:
          else:
            for v in token['value']:
            for v in token['value']:
              if not (-128 <= v < 256):
              if not (-128 <= v < 256):
                raise Exception('Program Bug -- unexpected out-of-range value');
                raise Exception('Program Bug -- unexpected out-of-range value');
              values.append(v);
              values.append(v);
        else:
        else:
          raise asmDef.AsmException('Illegal token "%s" at %s:%d:%d', (token['type'],token['loc']));
          raise asmDef.AsmException('Illegal token "%s" at %s:%d:%d', (token['type'],token['loc']));
    except:
    except:
      raise asmDef.AsmException('Out-of-range token "%s" at %s:%d:%d', (token['type'],token['loc']));
      raise asmDef.AsmException('Out-of-range token "%s" at %s:%d:%d', (token['type'],token['loc']));
    return values;
    return values;
 
 
  def ExpandSymbol(self,token,singleValue):
  def ExpandSymbol(self,token,singleValue):
    """
    """
    Convert the token for a symbol into a token for its specific type.
    Convert the token for a symbol into a token for its specific type.
    Optionally ensure constants expand to a single byte.  For parameters,
    Optionally ensure constants expand to a single byte.  For parameters,
    ensure that a range is provided.\n
    ensure that a range is provided.\n
    Note:  Symbols must be defined before the directive bodies in which they
    Note:  Symbols must be defined before the directive bodies in which they
           are used.\n
           are used.\n
    Note:  This is called in two spots.  The first is ExpandTokens, where
    Note:  This is called in two spots.  The first is ExpandTokens, where
           isolated symbols are processed, for example to get the value of a
           isolated symbols are processed, for example to get the value of a
           constant.  The second is in EmitOptArg where symbols in arguments to
           constant.  The second is in EmitOptArg where symbols in arguments to
           macros are expanded (this allows the macro-specific processing to
           macros are expanded (this allows the macro-specific processing to
           identify labels vs. symbols).
           identify labels vs. symbols).
    """
    """
    if not self.IsSymbol(token['value']):
    if not self.IsSymbol(token['value']):
      raise asmDef.AsmException('Symbol "%s" not in symbol list at %s' %(token['value'],token['loc'],));
      raise asmDef.AsmException('Symbol "%s" not in symbol list at %s' %(token['value'],token['loc'],));
    ix = self.symbols['list'].index(token['value']);
    ix = self.symbols['list'].index(token['value']);
    symbolType = self.symbols['type'][ix];
    symbolType = self.symbols['type'][ix];
    if symbolType == 'RAM':
    if symbolType == 'RAM':
      return dict(type='RAM', value=token['value'], loc=token['loc']);
      return dict(type='RAM', value=token['value'], loc=token['loc']);
    elif symbolType == 'ROM':
    elif symbolType == 'ROM':
      return dict(type='ROM', value=token['value'], loc=token['loc']);
      return dict(type='ROM', value=token['value'], loc=token['loc']);
    elif symbolType == 'constant':
    elif symbolType == 'constant':
      if singleValue:
      if singleValue:
        thisBody = self.symbols['body'][ix];
        thisBody = self.symbols['body'][ix];
        if len(thisBody) != 1:
        if len(thisBody) != 1:
          raise asmDef.AsmException('Constant "%s" must evaluate to a single byte at %s' % (token['value'],token['loc'],))
          raise asmDef.AsmException('Constant "%s" must evaluate to a single byte at %s' % (token['value'],token['loc'],))
        thisBody = thisBody[0];
        thisBody = thisBody[0];
        if not (-128 <= thisBody < 256):
        if not (-128 <= thisBody < 256):
          raise asmDef.AsmException('Constant "%s" must be a byte value at %s' % (token['value'],token['loc'],));
          raise asmDef.AsmException('Constant "%s" must be a byte value at %s' % (token['value'],token['loc'],));
      return dict(type='constant', value=token['value'], loc=token['loc']);
      return dict(type='constant', value=token['value'], loc=token['loc']);
    elif symbolType == 'inport':
    elif symbolType == 'inport':
      return dict(type='inport', value=token['value'], loc=token['loc']);
      return dict(type='inport', value=token['value'], loc=token['loc']);
    elif symbolType == 'outport':
    elif symbolType == 'outport':
      return dict(type='outport', value=token['value'], loc=token['loc']);
      return dict(type='outport', value=token['value'], loc=token['loc']);
    elif symbolType == 'outstrobe':
    elif symbolType == 'outstrobe':
      return dict(type='outstrobe', value=token['value'], loc=token['loc']);
      return dict(type='outstrobe', value=token['value'], loc=token['loc']);
    elif symbolType == 'parameter':
    elif symbolType == 'parameter':
      if 'range' in token:
      if 'range' in token:
        trange = token['range'];
        trange = token['range'];
      else:
      else:
        trange = '[0+:8]';
        trange = '[0+:8]';
      return dict(type='parameter', value=token['value'], range=trange, loc=token['loc']);
      return dict(type='parameter', value=token['value'], range=trange, loc=token['loc']);
    elif symbolType == 'variable':
    elif symbolType == 'variable':
      return dict(type='variable', value=token['value'], loc=token['loc']);
      return dict(type='variable', value=token['value'], loc=token['loc']);
    else:
    else:
      raise Exception('Program Bug -- unrecognized symbol type "%s"' % symbolType);
      raise Exception('Program Bug -- unrecognized symbol type "%s"' % symbolType);
 
 
  def ExpandTokens(self,rawTokens):
  def ExpandTokens(self,rawTokens):
    """
    """
    Compute the relative addresses for tokens within function bodies.\n
    Compute the relative addresses for tokens within function bodies.\n
    The return is a list of the tokens in the function body, each of which has
    The return is a list of the tokens in the function body, each of which has
    a type, value, offset (relative address), and location within the source
    a type, value, offset (relative address), and location within the source
    code.  Macro types also have the list of arguments provided to the macro.
    code.  Macro types also have the list of arguments provided to the macro.
    """
    """
    tokens = list();
    tokens = list();
    offset = 0;
    offset = 0;
    for token in rawTokens:
    for token in rawTokens:
      # insert labels
      # insert labels
      if token['type'] == 'label':
      if token['type'] == 'label':
        tokens.append(dict(type=token['type'], value=token['value'], offset=offset, loc=token['loc']));
        tokens.append(dict(type=token['type'], value=token['value'], offset=offset, loc=token['loc']));
        # labels don't change the offset
        # labels don't change the offset
      # append instructions
      # append instructions
      elif token['type'] == 'instruction':
      elif token['type'] == 'instruction':
        tokens.append(dict(type=token['type'], value=token['value'], offset=offset, loc=token['loc']));
        tokens.append(dict(type=token['type'], value=token['value'], offset=offset, loc=token['loc']));
        offset = offset + 1;
        offset = offset + 1;
      # append values
      # append values
      elif token['type'] == 'value':
      elif token['type'] == 'value':
        if type(token['value']) == int:
        if type(token['value']) == int:
          tokens.append(dict(type=token['type'], value=token['value'], offset=offset, loc=token['loc']));
          tokens.append(dict(type=token['type'], value=token['value'], offset=offset, loc=token['loc']));
          offset = offset + 1;
          offset = offset + 1;
        else:
        else:
          revTokens = copy.copy(token['value']);
          revTokens = copy.copy(token['value']);
          revTokens.reverse();
          revTokens.reverse();
          for lToken in revTokens:
          for lToken in revTokens:
            tokens.append(dict(type=token['type'], value=lToken, offset=offset, loc=token['loc']));
            tokens.append(dict(type=token['type'], value=lToken, offset=offset, loc=token['loc']));
            offset = offset + 1;
            offset = offset + 1;
      # append macros
      # append macros
      elif token['type'] == 'macro':
      elif token['type'] == 'macro':
        tokens.append(dict(type=token['type'], value=token['value'], offset=offset, argument=token['argument'], loc=token['loc']));
        tokens.append(dict(type=token['type'], value=token['value'], offset=offset, argument=token['argument'], loc=token['loc']));
        offset = offset + self.MacroLength(token);
        offset = offset + self.MacroLength(token);
      # interpret and append symbols
      # interpret and append symbols
      elif token['type'] == 'symbol':
      elif token['type'] == 'symbol':
        newToken = self.ExpandSymbol(token,singleValue=False);
        newToken = self.ExpandSymbol(token,singleValue=False);
        newToken['offset'] = offset;
        newToken['offset'] = offset;
        newToken['loc'] = token['loc'];
        newToken['loc'] = token['loc'];
        tokens.append(newToken);
        tokens.append(newToken);
        if token['type'] == 'constant':
        if token['type'] == 'constant':
          ix = self.symbols['list'].index(newToken['value']);
          ix = self.symbols['list'].index(newToken['value']);
          offset = offset + len(self.symbols['body'][ix]);
          offset = offset + len(self.symbols['body'][ix]);
        else:
        else:
          offset = offset + 1;
          offset = offset + 1;
      # anything else is a program bug
      # anything else is a program bug
      else:
      else:
        raise Exception('Program bug:  unexpected token type "%s"' % token['type']);
        raise Exception('Program bug:  unexpected token type "%s"' % token['type']);
    return dict(tokens=tokens, length=offset);
    return dict(tokens=tokens, length=offset);
 
 
  def FillRawTokens(self,rawTokens):
  def FillRawTokens(self,rawTokens):
    """
    """
    Do one of the following as required for the specified directive:
    Do one of the following as required for the specified directive:
      .constant         add the constant and its body to the list of symbols
      .constant         add the constant and its body to the list of symbols
      .function         add the function and its body, along with the relative
      .function         add the function and its body, along with the relative
                        addresses, to the list of symbols
                        addresses, to the list of symbols
      .interrupt        record the function body and relative addresses
      .interrupt        record the function body and relative addresses
      .macro            register the user-defined macro
      .macro            register the user-defined macro
      .main             record the function body and relative addresses
      .main             record the function body and relative addresses
      .memory           record the definition of the memory and make it current
      .memory           record the definition of the memory and make it current
                        for subsequent variable definitions.
                        for subsequent variable definitions.
      .variable         add the variable and its associated memory, length, and
      .variable         add the variable and its associated memory, length, and
                        initial values to the list of symbols
                        initial values to the list of symbols
    """
    """
    firstToken = rawTokens[0];
    firstToken = rawTokens[0];
    secondToken = rawTokens[1];
    secondToken = rawTokens[1];
    # Perform syntax check common to several directives.
    # Perform syntax check common to several directives.
    if firstToken['value'] in ('.constant','.function','.variable',):
    if firstToken['value'] in ('.constant','.function','.variable',):
      if secondToken['type'] != 'symbol':
      if secondToken['type'] != 'symbol':
        raise asmDef.AsmException('Expected symbol, not "%s", at %s' % (secondToken['value'],secondToken['loc'],));
        raise asmDef.AsmException('Expected symbol, not "%s", at %s' % (secondToken['value'],secondToken['loc'],));
      if self.IsSymbol(secondToken['value']):
      if self.IsSymbol(secondToken['value']):
        raise asmDef.AsmException('Symbol "%s" already defined at %s' % (secondToken['value'],secondToken['loc'],));
        raise asmDef.AsmException('Symbol "%s" already defined at %s' % (secondToken['value'],secondToken['loc'],));
    # Perform syntax-specific processing.
    # Perform syntax-specific processing.
    if firstToken['value'] == '.constant':
    if firstToken['value'] == '.constant':
      byteList = self.ByteList(rawTokens[2:]);
      byteList = self.ByteList(rawTokens[2:]);
      self.AddSymbol(secondToken['value'],'constant',body=byteList);
      self.AddSymbol(secondToken['value'],'constant',body=byteList);
    # Process ".function" definition.
    # Process ".function" definition.
    elif firstToken['value'] == '.function':
    elif firstToken['value'] == '.function':
      self.AddSymbol(secondToken['value'],'function',self.ExpandTokens(rawTokens[2:]));
      self.AddSymbol(secondToken['value'],'function',self.ExpandTokens(rawTokens[2:]));
    # Process ".interrupt" definition.
    # Process ".interrupt" definition.
    elif firstToken['value'] == '.interrupt':
    elif firstToken['value'] == '.interrupt':
      if self.interrupt:
      if self.interrupt:
        raise asmDef.AsmException('Second definition of ".interrupt" at %s' % firstToken['loc']);
        raise asmDef.AsmException('Second definition of ".interrupt" at %s' % firstToken['loc']);
      self.interrupt = self.ExpandTokens(rawTokens[1:]);
      self.interrupt = self.ExpandTokens(rawTokens[1:]);
    # Process user-defined macros (the ".macro XXX" directive can be repeated for non-built-in macros).
    # Process user-defined macros (the ".macro XXX" directive can be repeated for non-built-in macros).
    elif firstToken['value'] == '.macro':
    elif firstToken['value'] == '.macro':
      macroName = secondToken['value'];
      macroName = secondToken['value'];
      fullMacroName = '.' + macroName;
      fullMacroName = '.' + macroName;
      if fullMacroName in self.directives:
      if fullMacroName in self.directives:
        raise asmDef.AsmException('Macro "%s" is a directive at %s' % (fullMacroName,secondToken['loc'],));
        raise asmDef.AsmException('Macro "%s" is a directive at %s' % (fullMacroName,secondToken['loc'],));
      if fullMacroName in self.instructions:
      if fullMacroName in self.instructions:
        raise asmDef.AsmException('Macro "%s" is an instruction at %s' % (fullMacroName,secondToken['loc'],));
        raise asmDef.AsmException('Macro "%s" is an instruction at %s' % (fullMacroName,secondToken['loc'],));
      if self.IsBuiltInMacro(fullMacroName):
      if self.IsBuiltInMacro(fullMacroName):
        raise asmDef.AsmException('Macro "%s" is a built-in macro at %s' % (fullMacroName,secondToken['loc'],));
        raise asmDef.AsmException('Macro "%s" is a built-in macro at %s' % (fullMacroName,secondToken['loc'],));
      if fullMacroName not in self.macros['list']:
      if fullMacroName not in self.macros['list']:
        self.AddUserMacro(macroName);
        self.AddUserMacro(macroName);
    # Process ".main" definition.
    # Process ".main" definition.
    elif firstToken['value'] == '.main':
    elif firstToken['value'] == '.main':
      if self.main:
      if self.main:
        raise asmDef.AsmException('Second definition of ".main" at %s' % firstToken['loc']);
        raise asmDef.AsmException('Second definition of ".main" at %s' % firstToken['loc']);
      self.main = self.ExpandTokens(rawTokens[1:]);
      self.main = self.ExpandTokens(rawTokens[1:]);
    # Process ".memory" declaration.
    # Process ".memory" declaration.
    elif firstToken['value'] == '.memory':
    elif firstToken['value'] == '.memory':
      if len(rawTokens) != 3:
      if len(rawTokens) != 3:
        raise asmDef.AsmException('".memory" directive requires exactly two arguments at %s' % firstToken['loc']);
        raise asmDef.AsmException('".memory" directive requires exactly two arguments at %s' % firstToken['loc']);
      if (secondToken['type'] != 'symbol') or (secondToken['value'] not in ('RAM','ROM',)):
      if (secondToken['type'] != 'symbol') or (secondToken['value'] not in ('RAM','ROM',)):
        raise asmDef.AsmException('First argument to ".memory" directive must be "RAM" or "RAM" at %s' % secondToken['loc']);
        raise asmDef.AsmException('First argument to ".memory" directive must be "RAM" or "RAM" at %s' % secondToken['loc']);
      thirdToken = rawTokens[2];
      thirdToken = rawTokens[2];
      if thirdToken['type'] != 'symbol':
      if thirdToken['type'] != 'symbol':
        raise asmDef.AsmException('".memory" directive requires name for second argument at %s' % thirdToken['loc']);
        raise asmDef.AsmException('".memory" directive requires name for second argument at %s' % thirdToken['loc']);
      if self.IsSymbol(thirdToken['value']):
      if self.IsSymbol(thirdToken['value']):
        ix = self.symbols['list'].index(thirdToken['value']);
        ix = self.symbols['list'].index(thirdToken['value']);
        if self.symbols['type'] != secondToken['value']:
        if self.symbols['type'] != secondToken['value']:
          raise asmDef.AsmException('Redefinition of ".memory %s %s" not allowed at %s' % (secondToken['value'],thirdToken['value'],firstToken['loc']));
          raise asmDef.AsmException('Redefinition of ".memory %s %s" not allowed at %s' % (secondToken['value'],thirdToken['value'],firstToken['loc']));
      else:
      else:
        self.AddSymbol(thirdToken['value'],secondToken['value'],dict(length=0));
        self.AddSymbol(thirdToken['value'],secondToken['value'],dict(length=0));
      self.currentMemory = thirdToken['value'];
      self.currentMemory = thirdToken['value'];
    # Process ".variable" declaration.
    # Process ".variable" declaration.
    elif firstToken['value'] == '.variable':
    elif firstToken['value'] == '.variable':
      if not self.currentMemory:
      if not self.currentMemory:
        raise asmDef.AsmException('".memory" directive required before ".variable" directive at %s' % firstToken['line']);
        raise asmDef.AsmException('".memory" directive required before ".variable" directive at %s' % firstToken['line']);
      ixMem = self.symbols['list'].index(self.currentMemory);
      ixMem = self.symbols['list'].index(self.currentMemory);
      currentMemoryBody = self.symbols['body'][ixMem];
      currentMemoryBody = self.symbols['body'][ixMem];
      byteList = self.ByteList(rawTokens[2:],limit=True);
      byteList = self.ByteList(rawTokens[2:],limit=True);
      body = dict(memory=self.currentMemory, start=currentMemoryBody['length'], value=byteList);
      body = dict(memory=self.currentMemory, start=currentMemoryBody['length'], value=byteList);
      self.AddSymbol(secondToken['value'], 'variable', body=body);
      self.AddSymbol(secondToken['value'], 'variable', body=body);
      currentMemoryBody['length'] = currentMemoryBody['length'] + len(byteList);
      currentMemoryBody['length'] = currentMemoryBody['length'] + len(byteList);
      if currentMemoryBody['length'] > 256:
      if currentMemoryBody['length'] > 256:
        raise asmDef.AsmException('Memory "%s" becomes too long at %s' % (self.currentMemory,firstToken['loc']));
        raise asmDef.AsmException('Memory "%s" becomes too long at %s' % (self.currentMemory,firstToken['loc']));
    # Everything else is an error.
    # Everything else is an error.
    else:
    else:
      raise Exception('Program Bug:  Unrecognized directive %s at %s' % (firstToken['value'],firstToken['loc']));
      raise Exception('Program Bug:  Unrecognized directive %s at %s' % (firstToken['value'],firstToken['loc']));
 
 
  def Main(self):
  def Main(self):
    """
    """
    Return the body of the .main function.
    Return the body of the .main function.
    Note:  This is used by the top-level assembler to verify that the .main
    Note:  This is used by the top-level assembler to verify that the .main
           function has been defined.
           function has been defined.
    """
    """
    return self.main;
    return self.main;
 
 
  def Interrupt(self):
  def Interrupt(self):
    """
    """
    Return the body of the .interrupt function.
    Return the body of the .interrupt function.
    Note:  This is used by the top-level assembler to verify that the .interrupt
    Note:  This is used by the top-level assembler to verify that the .interrupt
           function has or has not been defined.
           function has or has not been defined.
    """
    """
    return self.interrupt;
    return self.interrupt;
 
 
  ################################################################################
  ################################################################################
  #
  #
  # Compute the memory bank indices.
  # Compute the memory bank indices.
  #
  #
  ################################################################################
  ################################################################################
 
 
  def EvaluateMemoryTree(self):
  def EvaluateMemoryTree(self):
    """
    """
    Ensure defined memories are used.  Add the memory name, type, and length to
    Ensure defined memories are used.  Add the memory name, type, and length to
    the list of memories.  Compute the bank index ascending from 0 for RAMs and
    the list of memories.  Compute the bank index ascending from 0 for RAMs and
    descending from 3 for ROMs and add that index to the memory attributes.
    descending from 3 for ROMs and add that index to the memory attributes.
    Ensure that no more than 4 memories are listed.
    Ensure that no more than 4 memories are listed.
    """
    """
    self.memories = dict(list=list(), type=list(), length=list(), bank=list());
    self.memories = dict(list=list(), type=list(), length=list(), bank=list());
    ramBank = 0;
    ramBank = 0;
    romBank = 3;
    romBank = 3;
    for ix in range(len(self.symbols['list'])):
    for ix in range(len(self.symbols['list'])):
      if self.symbols['type'][ix] in ('RAM','ROM',):
      if self.symbols['type'][ix] in ('RAM','ROM',):
        memBody = self.symbols['body'][ix];
        memBody = self.symbols['body'][ix];
        if memBody['length'] == 0:
        if memBody['length'] == 0:
          raise asmDef.AsmException('Empty memory:  %s' % self.symbols['list'][ix]);
          raise asmDef.AsmException('Empty memory:  %s' % self.symbols['list'][ix]);
        self.memories['list'].append(self.symbols['list'][ix]);
        self.memories['list'].append(self.symbols['list'][ix]);
        self.memories['type'].append(self.symbols['type'][ix]);
        self.memories['type'].append(self.symbols['type'][ix]);
        self.memories['length'].append(memBody['length']);
        self.memories['length'].append(memBody['length']);
        if self.symbols['type'][ix] == 'RAM':
        if self.symbols['type'][ix] == 'RAM':
          self.memories['bank'].append(ramBank);
          self.memories['bank'].append(ramBank);
          ramBank = ramBank + 1;
          ramBank = ramBank + 1;
        else:
        else:
          self.memories['bank'].append(romBank);
          self.memories['bank'].append(romBank);
          romBank = romBank - 1;
          romBank = romBank - 1;
    if len(self.memories['list']) > 4:
    if len(self.memories['list']) > 4:
      raise asmDef.AsmException('Too many memory banks');
      raise asmDef.AsmException('Too many memory banks');
 
 
  ################################################################################
  ################################################################################
  #
  #
  # Generate the list of required functions from the ".main" and ".interrupt"
  # Generate the list of required functions from the ".main" and ".interrupt"
  # bodies.
  # bodies.
  #
  #
  # Look for function calls with the bodies of the required functions.  If the
  # Look for function calls with the bodies of the required functions.  If the
  # function has not already been identified as a required function then (1)
  # function has not already been identified as a required function then (1)
  # ensure it exists and is a function and then (2) add it to the list of
  # ensure it exists and is a function and then (2) add it to the list of
  # required functions.
  # required functions.
  #
  #
  # Whenever a function is added to the list, set its start address and get its
  # Whenever a function is added to the list, set its start address and get its
  # length.
  # length.
  #
  #
  ################################################################################
  ################################################################################
 
 
  def EvaluateFunctionTree(self):
  def EvaluateFunctionTree(self):
    """
    """
    Create a list of the functions required by the program, starting with the
    Create a list of the functions required by the program, starting with the
    required .main function and the optional .interrupt function.\n
    required .main function and the optional .interrupt function.\n
    Record the length of each function, its body, and its start address and
    Record the length of each function, its body, and its start address and
    calculate the addresses of the labels within each function body.\n
    calculate the addresses of the labels within each function body.\n
    Finally, ensure the function address space does not exceed the absolute
    Finally, ensure the function address space does not exceed the absolute
    8192 address limit.
    8192 address limit.
    """
    """
    self.functionEvaluation = dict(list=list(), length=list(), body=list(), address=list());
    self.functionEvaluation = dict(list=list(), length=list(), body=list(), address=list());
    nextStart = 0;
    nextStart = 0;
    # ".main" is always required.
    # ".main" is always required.
    self.functionEvaluation['list'].append('.main');
    self.functionEvaluation['list'].append('.main');
    self.functionEvaluation['length'].append(self.main['length']);
    self.functionEvaluation['length'].append(self.main['length']);
    self.functionEvaluation['body'].append(self.main['tokens']);
    self.functionEvaluation['body'].append(self.main['tokens']);
    self.functionEvaluation['address'].append(nextStart);
    self.functionEvaluation['address'].append(nextStart);
    nextStart = nextStart + self.functionEvaluation['length'][-1];
    nextStart = nextStart + self.functionEvaluation['length'][-1];
    # ".interrupt" is optionally required (and is sure to exist by this function
    # ".interrupt" is optionally required (and is sure to exist by this function
    # call if it is required).
    # call if it is required).
    if self.interrupt:
    if self.interrupt:
      self.functionEvaluation['list'].append('.interrupt');
      self.functionEvaluation['list'].append('.interrupt');
      self.functionEvaluation['length'].append(self.interrupt['length']);
      self.functionEvaluation['length'].append(self.interrupt['length']);
      self.functionEvaluation['body'].append(self.interrupt['tokens']);
      self.functionEvaluation['body'].append(self.interrupt['tokens']);
      self.functionEvaluation['address'].append(nextStart);
      self.functionEvaluation['address'].append(nextStart);
      nextStart = nextStart + self.functionEvaluation['length'][-1];
      nextStart = nextStart + self.functionEvaluation['length'][-1];
    # Loop through the required function bodies as they are identified.
    # Loop through the required function bodies as they are identified.
    ix = 0;
    ix = 0;
    while ix < len(self.functionEvaluation['body']):
    while ix < len(self.functionEvaluation['body']):
      for token in self.functionEvaluation['body'][ix]:
      for token in self.functionEvaluation['body'][ix]:
        if (token['type'] == 'macro') and (token['value'] in ('.call','.callc',)):
        if (token['type'] == 'macro') and (token['value'] in ('.call','.callc',)):
          callName = token['argument'][0]['value'];
          callName = token['argument'][0]['value'];
          if callName not in self.functionEvaluation['list']:
          if callName not in self.functionEvaluation['list']:
            if not self.IsSymbol(callName):
            if not self.IsSymbol(callName):
              raise asmDef.AsmException('Function "%s" not defined for function "%s"' % (callName,self.functionEvaluation['list'][ix],));
              raise asmDef.AsmException('Function "%s" not defined for function "%s"' % (callName,self.functionEvaluation['list'][ix],));
            ixName = self.symbols['list'].index(callName);
            ixName = self.symbols['list'].index(callName);
            if self.symbols['type'][ixName] != 'function':
            if self.symbols['type'][ixName] != 'function':
              raise asmDef.AsmException('Function "%s" called by "%s" is not a function', (callName, self.functionEvaluation['list'][ix],));
              raise asmDef.AsmException('Function "%s" called by "%s" is not a function', (callName, self.functionEvaluation['list'][ix],));
            self.functionEvaluation['list'].append(callName);
            self.functionEvaluation['list'].append(callName);
            self.functionEvaluation['length'].append(self.symbols['body'][ixName]['length']);
            self.functionEvaluation['length'].append(self.symbols['body'][ixName]['length']);
            self.functionEvaluation['body'].append(self.symbols['body'][ixName]['tokens']);
            self.functionEvaluation['body'].append(self.symbols['body'][ixName]['tokens']);
            self.functionEvaluation['address'].append(nextStart);
            self.functionEvaluation['address'].append(nextStart);
            nextStart = nextStart + self.functionEvaluation['length'][-1];
            nextStart = nextStart + self.functionEvaluation['length'][-1];
      ix = ix + 1;
      ix = ix + 1;
    # Within each function, compute the list of label addresses and then fill in
    # Within each function, compute the list of label addresses and then fill in
    # the address for all jumps and calls.
    # the address for all jumps and calls.
    for ix in range(len(self.functionEvaluation['list'])):
    for ix in range(len(self.functionEvaluation['list'])):
      startAddress = self.functionEvaluation['address'][ix];
      startAddress = self.functionEvaluation['address'][ix];
      labelAddress = dict(list=list(), address=list());
      labelAddress = dict(list=list(), address=list());
      for token in self.functionEvaluation['body'][ix]:
      for token in self.functionEvaluation['body'][ix]:
        if token['type'] == 'label':
        if token['type'] == 'label':
          labelAddress['list'].append(token['value']);
          labelAddress['list'].append(token['value']);
          labelAddress['address'].append(startAddress + token['offset']);
          labelAddress['address'].append(startAddress + token['offset']);
      for token in self.functionEvaluation['body'][ix]:
      for token in self.functionEvaluation['body'][ix]:
        if token['type'] != 'macro':
        if token['type'] != 'macro':
          continue;
          continue;
        if token['value'] in ('.jump','.jumpc',):
        if token['value'] in ('.jump','.jumpc',):
          ix = labelAddress['list'].index(token['argument'][0]['value']);
          ix = labelAddress['list'].index(token['argument'][0]['value']);
          token['address'] = labelAddress['address'][ix];
          token['address'] = labelAddress['address'][ix];
        elif token['value'] in ('.call','.callc',):
        elif token['value'] in ('.call','.callc',):
          ix = self.functionEvaluation['list'].index(token['argument'][0]['value']);
          ix = self.functionEvaluation['list'].index(token['argument'][0]['value']);
          token['address'] = self.functionEvaluation['address'][ix];
          token['address'] = self.functionEvaluation['address'][ix];
    # Sanity checks for address range
    # Sanity checks for address range
    if self.functionEvaluation['address'][-1] + self.functionEvaluation['length'][-1] >= 2**13:
    if self.functionEvaluation['address'][-1] + self.functionEvaluation['length'][-1] >= 2**13:
      raise asmDef.AsmException('Max address for program requires more than 13 bits');
      raise asmDef.AsmException('Max address for program requires more than 13 bits');
 
 
  ################################################################################
  ################################################################################
  #
  #
  # Emit the meta code for the memories.
  # Emit the meta code for the memories.
  #
  #
  ################################################################################
  ################################################################################
 
 
  def EmitMemories(self,fp):
  def EmitMemories(self,fp):
    """
    """
    Print the memories to the metacode file.\n
    Print the memories to the metacode file.\n
    The first line for each memory has the format
    The first line for each memory has the format
      :memory type mem_name bank length
      :memory type mem_name bank length
    where
    where
      type              is RAM or ROM
      type              is RAM or ROM
      mem_name          is the name of the memory
      mem_name          is the name of the memory
      bank              is the assigned bank address
      bank              is the assigned bank address
      length            is the number of bytes used by the memory\n
      length            is the number of bytes used by the memory\n
    The subsequent lines are sequences of
    The subsequent lines are sequences of
      - variable_name
      - variable_name
      value(s)
      value(s)
    where
    where
      '-'               indicates a variable name is present
      '-'               indicates a variable name is present
      variable_name     is the name of the variable
      variable_name     is the name of the variable
      values(s)         is one or more lines for the values with one byte per line
      values(s)         is one or more lines for the values with one byte per line
                        Note:  because the lines with variable names start with
                        Note:  because the lines with variable names start with
                               '-', negative values are converted to unsigned
                               '-', negative values are converted to unsigned
                               values\n
                               values\n
    """
    """
    # Emit the individual memories.
    # Emit the individual memories.
    for ixMem in range(len(self.memories['list'])):
    for ixMem in range(len(self.memories['list'])):
      fp.write(':memory %s %s %d %d\n' % (self.memories['type'][ixMem],self.memories['list'][ixMem],self.memories['bank'][ixMem],self.memories['length'][ixMem]));
      fp.write(':memory %s %s %d %d\n' % (self.memories['type'][ixMem],self.memories['list'][ixMem],self.memories['bank'][ixMem],self.memories['length'][ixMem]));
      memName = self.memories['list'][ixMem];
      memName = self.memories['list'][ixMem];
      address = 0;
      address = 0;
      for ixSymbol in range(len(self.symbols['list'])):
      for ixSymbol in range(len(self.symbols['list'])):
        if self.symbols['type'][ixSymbol] != 'variable':
        if self.symbols['type'][ixSymbol] != 'variable':
          continue;
          continue;
        vBody = self.symbols['body'][ixSymbol];
        vBody = self.symbols['body'][ixSymbol];
        if vBody['memory'] != memName:
        if vBody['memory'] != memName:
          continue;
          continue;
        fp.write('- %s\n' % self.symbols['list'][ixSymbol]);
        fp.write('- %s\n' % self.symbols['list'][ixSymbol]);
        for v in vBody['value']:
        for v in vBody['value']:
          if not (-128 <=v < 256):
          if not (-128 <=v < 256):
            raise Exception('Program Bug -- value not representable by a byte');
            raise Exception('Program Bug -- value not representable by a byte');
          fp.write('%02X\n' % (v % 0x100,));
          fp.write('%02X\n' % (v % 0x100,));
      fp.write('\n');
      fp.write('\n');
 
 
  ################################################################################
  ################################################################################
  #
  #
  # Emit the metacode for the program.
  # Emit the metacode for the program.
  #
  #
  ################################################################################
  ################################################################################
 
 
  #
  #
  # Utilities for building opcodes or the associated description strings.
  # Utilities for building opcodes or the associated description strings.
  #
  #
  # Note:  These utilities do not write to the metacode file.
  # Note:  These utilities do not write to the metacode file.
  #
  #
 
 
  def Emit_AddLabel(self,name):
  def Emit_AddLabel(self,name):
    """
    """
    Append the label to the labels associated with the current program address.
    Append the label to the labels associated with the current program address.
    """
    """
    self.emitLabelList += ':' + name + ' ';
    self.emitLabelList += ':' + name + ' ';
 
 
  def Emit_EvalSingleValue(self,token):
  def Emit_EvalSingleValue(self,token):
    """
    """
    Evaluate the optional single-byte value for a macro.
    Evaluate the optional single-byte value for a macro.
    """
    """
    if token['type'] == 'symbol':
    if token['type'] == 'symbol':
      token = self.ExpandSymbol(token,singleValue=True);
      token = self.ExpandSymbol(token,singleValue=True);
    if token['type'] == 'constant':
    if token['type'] == 'constant':
      name = token['value'];
      name = token['value'];
      if not self.IsSymbol(name):
      if not self.IsSymbol(name):
        raise Exception('Program Bug');
        raise Exception('Program Bug');
      ix = self.symbols['list'].index(name);
      ix = self.symbols['list'].index(name);
      if len(self.symbols['body'][ix]) != 1:
      if len(self.symbols['body'][ix]) != 1:
        raise asmDef.AsmException('Optional constant can only be one byte at %s' % token['loc']);
        raise asmDef.AsmException('Optional constant can only be one byte at %s' % token['loc']);
      return self.symbols['body'][ix][0]
      return self.symbols['body'][ix][0]
    elif token['type'] == 'value':
    elif token['type'] == 'value':
      return token['value']
      return token['value']
    else:
    else:
      raise asmDef.AsmException('Unrecognized optional argument "%s"' % token['value']);
      raise asmDef.AsmException('Unrecognized optional argument "%s"' % token['value']);
 
 
  def Emit_GetAddrAndBank(self,name):
  def Emit_GetAddrAndBank(self,name):
    """
    """
    For the specified variable, return an ordered tuple of the memory address
    For the specified variable, return an ordered tuple of the memory address
    within its bank, the corresponding bank index, and the corresponding bank
    within its bank, the corresponding bank index, and the corresponding bank
    name.\n
    name.\n
    Note:  This is used by several user-defined macros that fetch from or store
    Note:  This is used by several user-defined macros that fetch from or store
           to variables.
           to variables.
    """
    """
    if not self.IsSymbol(name):
    if not self.IsSymbol(name):
      raise asmDef.AsmException('"%s" is not a recognized symbol' % name);
      raise asmDef.AsmException('"%s" is not a recognized symbol' % name);
    ixName = self.symbols['list'].index(name);
    ixName = self.symbols['list'].index(name);
    if self.symbols['type'][ixName] != 'variable':
    if self.symbols['type'][ixName] != 'variable':
      raise asmDef.AsmException('"%s" is not a variable' % name);
      raise asmDef.AsmException('"%s" is not a variable' % name);
    body = self.symbols['body'][ixName];
    body = self.symbols['body'][ixName];
    bankName = body['memory'];
    bankName = body['memory'];
    ixMem = self.memories['list'].index(bankName);
    ixMem = self.memories['list'].index(bankName);
    return (body['start'],self.memories['bank'][ixMem],bankName,);
    return (body['start'],self.memories['bank'][ixMem],bankName,);
 
 
  def Emit_GetBank(self,name):
  def Emit_GetBank(self,name):
    """
    """
    For the specified variable, return the memory bank index.\n
    For the specified variable, return the memory bank index.\n
    Note:  This is used by the .fetch, .fetch+, .fetch-, .store, .store+, and
    Note:  This is used by the .fetch, .fetch+, .fetch-, .store, .store+, and
           .store- macros.
           .store- macros.
    """
    """
    if name not in self.memories['list']:
    if name not in self.memories['list']:
      raise asmDef.AsmException('"%s" not a memory' % name);
      raise asmDef.AsmException('"%s" not a memory' % name);
    ixMem = self.memories['list'].index(name);
    ixMem = self.memories['list'].index(name);
    return self.memories['bank'][ixMem];
    return self.memories['bank'][ixMem];
 
 
  def Emit_String(self,name=''):
  def Emit_String(self,name=''):
    """
    """
    Append the specified string to the list of labels for the current
    Append the specified string to the list of labels for the current
    instruction, restart the list of labels, and return the composite string.
    instruction, restart the list of labels, and return the composite string.
    """
    """
    name = self.emitLabelList + name;
    name = self.emitLabelList + name;
    self.emitLabelList = '';
    self.emitLabelList = '';
    return name;
    return name;
 
 
 
  def Emit_IntegerValue(self,token):
 
    """
 
    Return the integer value associated with a constant or a numeric expression.
 
    """
 
    if token['type'] == 'value':
 
      v = token['value'];
 
    elif token['type'] == 'symbol':
 
      name = token['value'];
 
      if not self.IsSymbol(name):
 
        raise asmDef.AsmException('Symbol "%s" not recognized at %s' % (token['value'],token['loc'],));
 
      ix = self.symbols['list'].index(name);
 
      v = self.symbols['body'][ix];
 
      if len(v) != 1:
 
        raise asmDef.AsmException('Argument can only be one value at %s' % token['loc']);
 
      v = v[0];
 
    else:
 
      raise asmDef.AsmException('Argument "%s" of type "%s" not recognized at %s' % (token['value'],token['type'],token['loc'],));
 
    if type(v) != int:
 
      raise Exception('Program Bug -- value should be an "int"');
 
    return v;
 
 
  #
  #
  # Utilities to write single instructions to the metacode file.
  # Utilities to write single instructions to the metacode file.
  #
  #
  # Note:  Other than the program header and the function names, these
  # Note:  Other than the program header and the function names, these
  #        utilities write the function bodies.
  #        utilities write the function bodies.
  #
  #
 
 
  def EmitOpcode(self,fp,opcode,name):
  def EmitOpcode(self,fp,opcode,name):
    """
    """
    Write the specified opcode and the associated comment string.\n
    Write the specified opcode and the associated comment string.\n
    The leading bit for an opcode is always a '0'.
    The leading bit for an opcode is always a '0'.
    """
    """
    if not (0 <= opcode < 256):
    if not (0 <= opcode < 256):
      raise Exception('Program Bug -- opcode "0x%X" out of range');
      raise Exception('Program Bug -- opcode "0x%X" out of range');
    fp.write('0%02X %s\n' % (opcode,self.Emit_String(name)));
    fp.write('0%02X %s\n' % (opcode,self.Emit_String(name)));
 
 
  def EmitParameter(self,fp,token):
  def EmitParameter(self,fp,token):
    """
    """
    Write the name (and range) of the specified parameter and the optional
    Write the name (and range) of the specified parameter and the optional
    associated comment string.\n
    associated comment string.\n
    The string 'p' specifies that the parameter is to be inserted into the
    The string 'p' specifies that the parameter is to be inserted into the
    instruction body.\n
    instruction body.\n
    Note:  The comment string may be the empty string if there were no labels
    Note:  The comment string may be the empty string if there were no labels
           immediately preceding the parameter.
           immediately preceding the parameter.
    """
    """
    name = token['value'];
    name = token['value'];
    if not self.IsParameter(name):
    if not self.IsParameter(name):
      raise Exception('Program Bug');
      raise Exception('Program Bug');
    commentString = self.Emit_String();
    commentString = self.Emit_String();
    if commentString:
    if commentString:
      fp.write('p %s%s %s\n' % (name,token['range'],commentString,));
      fp.write('p %s%s %s\n' % (name,token['range'],commentString,));
    else:
    else:
      fp.write('p %s%s\n' % (name,token['range'],));
      fp.write('p %s%s\n' % (name,token['range'],));
 
 
  def EmitPush(self,fp,value,name=None,tokenLoc=None):
  def EmitPush(self,fp,value,name=None,tokenLoc=None):
    """
    """
    Write the opcode to push a value onto the data stack.  Include the comment
    Write the opcode to push a value onto the data stack.  Include the comment
    string including either the optionally provided symbol name or a printable
    string including either the optionally provided symbol name or a printable
    representation of the value being pushed onto the stack.\n
    representation of the value being pushed onto the stack.\n
    Note:  The printable value is included when a name is not provided so that
    Note:  The printable value is included when a name is not provided so that
           the contents of single characters or of strings being pushed onto
           the contents of single characters or of strings being pushed onto
           the stack can be read.\n
           the stack can be read.\n
    Note:  The token location is an optional input required when the range of
    Note:  The token location is an optional input required when the range of
           the provided value may not have been previously ensured to fit in
           the provided value may not have been previously ensured to fit in
           one byte.
           one byte.
    """
    """
    if not (-128 <= value < 256):
    if not (-128 <= value < 256):
      if tokenLoc == None:
      if tokenLoc == None:
        raise Exception('Program Bug -- untrapped out-of-range token "%s"' % value);
        raise Exception('Program Bug -- untrapped out-of-range token "%s"' % value);
      else:
      else:
        raise asmDef.AsmException('Value not representable by a byte at "%s"' % tokenLoc);
        raise asmDef.AsmException('Value not representable by a byte at "%s"' % tokenLoc);
    if value < 0:
    if value < 0:
      value = value + 256;
      value = value + 256;
    if type(name) == str:
    if type(name) == str:
      fp.write('1%02X %s\n' % ((value % 0x100),self.Emit_String(name)));
      fp.write('1%02X %s\n' % ((value % 0x100),self.Emit_String(name)));
    elif (chr(value) in string.printable) and (chr(value) not in string.whitespace):
    elif (chr(value) in string.printable) and (chr(value) not in string.whitespace):
      fp.write('1%02X %s\n' % ((value % 0x100),self.Emit_String('%02X \'%c\'' % (value,value,))));
      fp.write('1%02X %s\n' % ((value % 0x100),self.Emit_String('%02X \'%c\'' % (value,value,))));
    else:
    else:
      fp.write('1%02X %s\n' % ((value % 0x100),self.Emit_String('0x%02X' % value)));
      fp.write('1%02X %s\n' % ((value % 0x100),self.Emit_String('0x%02X' % value)));
 
 
  def EmitVariable(self,fp,name):
  def EmitVariable(self,fp,name):
    """
    """
    Use the EmitPush method to push the address of a variable onto the data
    Use the EmitPush method to push the address of a variable onto the data
    stack.
    stack.
    """
    """
    if not self.IsSymbol(name):
    if not self.IsSymbol(name):
      raise asmDef.AsmException('Variable "%s" not recognized' % name);
      raise asmDef.AsmException('Variable "%s" not recognized' % name);
    ixName = self.symbols['list'].index(name);
    ixName = self.symbols['list'].index(name);
    if self.symbols['type'][ixName] != 'variable':
    if self.symbols['type'][ixName] != 'variable':
      raise asmDef.AsmException('"%s" is not a variable' % name);
      raise asmDef.AsmException('"%s" is not a variable' % name);
    self.EmitPush(fp,self.symbols['body'][ixName]['start'],name);
    self.EmitPush(fp,self.symbols['body'][ixName]['start'],name);
 
 
  #
  #
  # EmitOpcode, EmitMacro, and EmitProgram emit composite or more complicated
  # EmitOpcode, EmitMacro, and EmitProgram emit composite or more complicated
  # bodies.
  # bodies.
  #
  #
 
 
  def EmitOptArg(self,fp,token):
  def EmitOptArg(self,fp,token):
    """
    """
    Write the metacode for optional arguments to macros.\n
    Write the metacode for optional arguments to macros.\n
    These must be single-instruction arguments.
    These must be single-instruction arguments.
    """
    """
    # Symbols encountered in macros are expanded here instead of the
    # Symbols encountered in macros are expanded here instead of the
    # ExpandTokens method -- the code is much simpler this way even though the
    # ExpandTokens method -- the code is much simpler this way even though the
    # associated error detection was deferred in the processing.  The symbol
    # associated error detection was deferred in the processing.  The symbol
    # must expand to a single value.
    # must expand to a single value.
    if token['type'] == 'symbol':
    if token['type'] == 'symbol':
      token = self.ExpandSymbol(token,singleValue=True);
      token = self.ExpandSymbol(token,singleValue=True);
    if token['type'] == 'constant':
    if token['type'] == 'constant':
      name = token['value'];
      name = token['value'];
      if not self.IsSymbol(name):
      if not self.IsSymbol(name):
        raise Exception('Program Bug');
        raise Exception('Program Bug');
      ix = self.symbols['list'].index(name);
      ix = self.symbols['list'].index(name);
      if len(self.symbols['body'][ix]) != 1:
      if len(self.symbols['body'][ix]) != 1:
        raise asmDef.AsmException('Optional constant can only be one byte at %s' % token['loc']);
        raise asmDef.AsmException('Optional constant can only be one byte at %s' % token['loc']);
      self.EmitPush(fp,self.symbols['body'][ix][0],self.Emit_String(name),tokenLoc=token['loc']);
      self.EmitPush(fp,self.symbols['body'][ix][0],self.Emit_String(name),tokenLoc=token['loc']);
    elif token['type'] in ('inport','outport','outstrobe'):
    elif token['type'] in ('inport','outport','outstrobe'):
      name = token['value'];
      name = token['value'];
      if not self.IsSymbol(name):
      if not self.IsSymbol(name):
        raise Exception('Program Bug -- unrecognized inport/outport name "%s"');
        raise Exception('Program Bug -- unrecognized inport/outport name "%s"');
      ix = self.symbols['list'].index(name);
      ix = self.symbols['list'].index(name);
      self.EmitPush(fp,self.symbols['body'][ix],self.Emit_String(name));
      self.EmitPush(fp,self.symbols['body'][ix],self.Emit_String(name));
    elif token['type'] == 'instruction':
    elif token['type'] == 'instruction':
      self.EmitOpcode(fp,self.InstructionOpcode(token['value']),token['value']);
      self.EmitOpcode(fp,self.InstructionOpcode(token['value']),token['value']);
    elif token['type'] == 'parameter':
    elif token['type'] == 'parameter':
      self.EmitParameter(fp,token);
      self.EmitParameter(fp,token);
    elif token['type'] == 'value':
    elif token['type'] == 'value':
      self.EmitPush(fp,token['value'],tokenLoc=token['loc']);
      self.EmitPush(fp,token['value'],tokenLoc=token['loc']);
    elif token['type'] == 'variable':
    elif token['type'] == 'variable':
      self.EmitVariable(fp,token['value']);
      self.EmitVariable(fp,token['value']);
    elif token['type'] == 'macro':
    elif token['type'] == 'macro':
      self.EmitMacro(fp,token);
      self.EmitMacro(fp,token);
    else:
    else:
      raise asmDef.AsmException('Unrecognized optional argument "%s"' % token['value']);
      raise asmDef.AsmException('Unrecognized optional argument "%s"' % token['value']);
 
 
  def EmitMacro(self,fp,token):
  def EmitMacro(self,fp,token):
    """
    """
    Write the metacode for a macro.\n
    Write the metacode for a macro.\n
    The macros coded here are required to access intrinsics.
    The macros coded here are required to access intrinsics.
    """
    """
    # .call
    # .call
    if token['value'] == '.call':
    if token['value'] == '.call':
      self.EmitPush(fp,token['address'] & 0xFF,'');
      self.EmitPush(fp,token['address'] & 0xFF,'');
      self.EmitOpcode(fp,self.specialInstructions['call'] | (token['address'] >> 8),'call '+token['argument'][0]['value']);
      self.EmitOpcode(fp,self.specialInstructions['call'] | (token['address'] >> 8),'call '+token['argument'][0]['value']);
      self.EmitOptArg(fp,token['argument'][1]);
      self.EmitOptArg(fp,token['argument'][1]);
    # .callc
    # .callc
    elif token['value'] == '.callc':
    elif token['value'] == '.callc':
      self.EmitPush(fp,token['address'] & 0xFF,'');
      self.EmitPush(fp,token['address'] & 0xFF,'');
      self.EmitOpcode(fp,self.specialInstructions['callc'] | (token['address'] >> 8),'callc '+token['argument'][0]['value']);
      self.EmitOpcode(fp,self.specialInstructions['callc'] | (token['address'] >> 8),'callc '+token['argument'][0]['value']);
      self.EmitOptArg(fp,token['argument'][1]);
      self.EmitOptArg(fp,token['argument'][1]);
    # .fetch
    # .fetch
    elif token['value'] == '.fetch':
    elif token['value'] == '.fetch':
      name = token['argument'][0]['value'];
      name = token['argument'][0]['value'];
      ixBank = self.Emit_GetBank(name);
      ixBank = self.Emit_GetBank(name);
      self.EmitOpcode(fp,self.specialInstructions['fetch'] | ixBank,'fetch '+name);
      self.EmitOpcode(fp,self.specialInstructions['fetch'] | ixBank,'fetch '+name);
    # .fetch+
    # .fetch+
    elif token['value'] == '.fetch+':
    elif token['value'] == '.fetch+':
      name = token['argument'][0]['value'];
      name = token['argument'][0]['value'];
      ixBank = self.Emit_GetBank(name);
      ixBank = self.Emit_GetBank(name);
      self.EmitOpcode(fp,self.specialInstructions['fetch+'] | ixBank,'fetch+('+name+')');
      self.EmitOpcode(fp,self.specialInstructions['fetch+'] | ixBank,'fetch+('+name+')');
    # .fetch-
    # .fetch-
    elif token['value'] == '.fetch-':
    elif token['value'] == '.fetch-':
      name = token['argument'][0]['value'];
      name = token['argument'][0]['value'];
      ixBank = self.Emit_GetBank(name);
      ixBank = self.Emit_GetBank(name);
      self.EmitOpcode(fp,self.specialInstructions['fetch-'] | ixBank,'fetch-('+name+')');
      self.EmitOpcode(fp,self.specialInstructions['fetch-'] | ixBank,'fetch-('+name+')');
    # .jump
    # .jump
    elif token['value'] == '.jump':
    elif token['value'] == '.jump':
      self.EmitPush(fp,token['address'] & 0xFF,'');
      self.EmitPush(fp,token['address'] & 0xFF,'');
      self.EmitOpcode(fp,self.specialInstructions['jump'] | (token['address'] >> 8),'jump '+token['argument'][0]['value']);
      self.EmitOpcode(fp,self.specialInstructions['jump'] | (token['address'] >> 8),'jump '+token['argument'][0]['value']);
      self.EmitOptArg(fp,token['argument'][1]);
      self.EmitOptArg(fp,token['argument'][1]);
    # .jumpc
    # .jumpc
    elif token['value'] == '.jumpc':
    elif token['value'] == '.jumpc':
      self.EmitPush(fp,token['address'] & 0xFF,'');
      self.EmitPush(fp,token['address'] & 0xFF,'');
      self.EmitOpcode(fp,self.specialInstructions['jumpc'] | (token['address'] >> 8),'jumpc '+token['argument'][0]['value']);
      self.EmitOpcode(fp,self.specialInstructions['jumpc'] | (token['address'] >> 8),'jumpc '+token['argument'][0]['value']);
      self.EmitOptArg(fp,token['argument'][1]);
      self.EmitOptArg(fp,token['argument'][1]);
    # .return
    # .return
    elif token['value'] == '.return':
    elif token['value'] == '.return':
      self.EmitOpcode(fp,self.specialInstructions['return'],'return');
      self.EmitOpcode(fp,self.specialInstructions['return'],'return');
      self.EmitOptArg(fp,token['argument'][0]);
      self.EmitOptArg(fp,token['argument'][0]);
    # .store
    # .store
    elif token['value'] == '.store':
    elif token['value'] == '.store':
      name = token['argument'][0]['value'];
      name = token['argument'][0]['value'];
      ixBank = self.Emit_GetBank(name);
      ixBank = self.Emit_GetBank(name);
      self.EmitOpcode(fp,self.specialInstructions['store'] | ixBank,'store '+name);
      self.EmitOpcode(fp,self.specialInstructions['store'] | ixBank,'store '+name);
    # .store+
    # .store+
    elif token['value'] == '.store+':
    elif token['value'] == '.store+':
      name = token['argument'][0]['value'];
      name = token['argument'][0]['value'];
      ixBank = self.Emit_GetBank(name);
      ixBank = self.Emit_GetBank(name);
      self.EmitOpcode(fp,self.specialInstructions['store+'] | ixBank,'store+ '+name);
      self.EmitOpcode(fp,self.specialInstructions['store+'] | ixBank,'store+ '+name);
    # .store-
    # .store-
    elif token['value'] == '.store-':
    elif token['value'] == '.store-':
      name = token['argument'][0]['value'];
      name = token['argument'][0]['value'];
      ixBank = self.Emit_GetBank(name);
      ixBank = self.Emit_GetBank(name);
      self.EmitOpcode(fp,self.specialInstructions['store-'] | ixBank,'store- '+name);
      self.EmitOpcode(fp,self.specialInstructions['store-'] | ixBank,'store- '+name);
    # user-defined macro
    # user-defined macro
    elif token['value'] in self.EmitFunction:
    elif token['value'] in self.EmitFunction:
      self.EmitFunction[token['value']](self,fp,token['argument']);
      self.EmitFunction[token['value']](self,fp,token['argument']);
    # error
    # error
    else:
    else:
      raise Exception('Program Bug -- Unrecognized macro "%s"' % token['value']);
      raise Exception('Program Bug -- Unrecognized macro "%s"' % token['value']);
 
 
  def EmitProgram(self,fp):
  def EmitProgram(self,fp):
    """
    """
    Write the program to the metacode file.\n
    Write the program to the metacode file.\n
    The frist line for the program has the format
    The frist line for the program has the format
      :program address_main address_interrupt
      :program address_main address_interrupt
    where
    where
      address_main      is the address of the .main function (this should be 0)
      address_main      is the address of the .main function (this should be 0)
      address_interrupt is either the address of the optional interrupt
      address_interrupt is either the address of the optional interrupt
                        function if it was defined or the 2-character string
                        function if it was defined or the 2-character string
                        '[]'\n
                        '[]'\n
    The subsequent lines are sequences of
    The subsequent lines are sequences of
      - function_name   indicates the start of a new function body and the name
      - function_name   indicates the start of a new function body and the name
                        of the function
                        of the function
      instructions      is multiple lines, one for each instruction in the
      instructions      is multiple lines, one for each instruction in the
                        function\n
                        function\n
    The formats of the instruction lines are as follows:
    The formats of the instruction lines are as follows:
      value string      value is the next instruction to store and string is an
      value string      value is the next instruction to store and string is an
                        optional string describing the instruction
                        optional string describing the instruction
                        Note:  "value" must be a 3-digit hex string
                        Note:  "value" must be a 3-digit hex string
                               representing a 9-bit value
                               representing a 9-bit value
                        Note:  The only place string should be empty is when
                        Note:  The only place string should be empty is when
                               pushing the 8 lsb of an address onto the start
                               pushing the 8 lsb of an address onto the start
                               prior to a call, callc, jump, or jumpc
                               prior to a call, callc, jump, or jumpc
                               instruction
                               instruction
      p name            the single 'p' means that the name of a parameter and
      p name            the single 'p' means that the name of a parameter and
                        its range are to be converted into an instruction
                        its range are to be converted into an instruction
    """
    """
    # Write the program marker, address of .main, address or "[]" of .interrupt,
    # Write the program marker, address of .main, address or "[]" of .interrupt,
    # and the total program length.
    # and the total program length.
    fp.write(':program');
    fp.write(':program');
    fp.write(' %d' % self.functionEvaluation['address'][0]);
    fp.write(' %d' % self.functionEvaluation['address'][0]);
    if self.interrupt:
    if self.interrupt:
      fp.write(' %d' % self.functionEvaluation['address'][1]);
      fp.write(' %d' % self.functionEvaluation['address'][1]);
    else:
    else:
      fp.write(' []');
      fp.write(' []');
    fp.write(' %d' % (self.functionEvaluation['address'][-1] + self.functionEvaluation['length'][-1]));
    fp.write(' %d' % (self.functionEvaluation['address'][-1] + self.functionEvaluation['length'][-1]));
    fp.write('\n');
    fp.write('\n');
    # Emit the bodies
    # Emit the bodies
    for ix in range(len(self.functionEvaluation['list'])):
    for ix in range(len(self.functionEvaluation['list'])):
      fp.write('- %s\n' % self.functionEvaluation['list'][ix]);
      fp.write('- %s\n' % self.functionEvaluation['list'][ix]);
      self.emitLabelList = '';
      self.emitLabelList = '';
      for token in self.functionEvaluation['body'][ix]:
      for token in self.functionEvaluation['body'][ix]:
        if token['type'] == 'value':
        if token['type'] == 'value':
          self.EmitPush(fp,token['value'],tokenLoc=token['loc']);
          self.EmitPush(fp,token['value'],tokenLoc=token['loc']);
        elif token['type'] == 'label':
        elif token['type'] == 'label':
          self.Emit_AddLabel(token['value']);
          self.Emit_AddLabel(token['value']);
        elif token['type'] == 'constant':
        elif token['type'] == 'constant':
          if not self.IsSymbol(token['value']):
          if not self.IsSymbol(token['value']):
            raise Exception('Program Bug');
            raise Exception('Program Bug');
          ix = self.symbols['list'].index(token['value']);
          ix = self.symbols['list'].index(token['value']);
          body = self.symbols['body'][ix];
          body = self.symbols['body'][ix];
          self.EmitPush(fp,body[-1],token['value'],tokenLoc=token['loc']);
          self.EmitPush(fp,body[-1],token['value'],tokenLoc=token['loc']);
          for v in body[-2::-1]:
          for v in body[-2::-1]:
            self.EmitPush(fp,v,tokenLoc=token['loc']);
            self.EmitPush(fp,v,tokenLoc=token['loc']);
        elif token['type'] in ('inport','outport','outstrobe',):
        elif token['type'] in ('inport','outport','outstrobe',):
          if not self.IsSymbol(token['value']):
          if not self.IsSymbol(token['value']):
            raise Exception('Program Bug');
            raise Exception('Program Bug');
          ix = self.symbols['list'].index(token['value']);
          ix = self.symbols['list'].index(token['value']);
          self.EmitPush(fp,self.symbols['body'][ix],token['value'],tokenLoc=token['loc']);
          self.EmitPush(fp,self.symbols['body'][ix],token['value'],tokenLoc=token['loc']);
        elif token['type'] == 'instruction':
        elif token['type'] == 'instruction':
          self.EmitOpcode(fp,self.InstructionOpcode(token['value']),token['value']);
          self.EmitOpcode(fp,self.InstructionOpcode(token['value']),token['value']);
        elif token['type'] == 'macro':
        elif token['type'] == 'macro':
          self.EmitMacro(fp,token);
          self.EmitMacro(fp,token);
        elif token['type'] == 'parameter':
        elif token['type'] == 'parameter':
          self.EmitParameter(fp,token);
          self.EmitParameter(fp,token);
        elif token['type'] == 'symbol':
        elif token['type'] == 'symbol':
          self.EmitPush(fp,token['value'],token['name'],tokenLoc=token['loc']);
          self.EmitPush(fp,token['value'],token['name'],tokenLoc=token['loc']);
        elif token['type'] == 'variable':
        elif token['type'] == 'variable':
          self.EmitVariable(fp,token['value']);
          self.EmitVariable(fp,token['value']);
        else:
        else:
          raise Exception('Program Bug:  Unrecognized type "%s"' % token['type']);
          raise Exception('Program Bug:  Unrecognized type "%s"' % token['type']);
 
 
  ################################################################################
  ################################################################################
  #
  #
  # Initialize the object.
  # Initialize the object.
  #
  #
  ################################################################################
  ################################################################################
 
 
  def __init__(self):
  def __init__(self):
    """
    """
    Initialize the tables definining the following:
    Initialize the tables definining the following:
      directly invokable instruction mnemonics and the associated opcodes
      directly invokable instruction mnemonics and the associated opcodes
      indirectly inivoked instruction mnemonics and the associated opcodes
      indirectly inivoked instruction mnemonics and the associated opcodes
        Note:  These are accessed through macros since they require an argument
        Note:  These are accessed through macros since they require an argument
               or are part of multi-instruction sequences.
               or are part of multi-instruction sequences.
      directives (other than ".include")
      directives (other than ".include")
      macros with type restrictions for required arguments and defaults and
      macros with type restrictions for required arguments and defaults and
        restrictions for optional arguments\n
        restrictions for optional arguments\n
    Initialize lists and members to record memory attributes, stack lengths,
    Initialize lists and members to record memory attributes, stack lengths,
    body of the .main function, body of the optional .interrupt function,
    body of the .main function, body of the optional .interrupt function,
    current memory for variable definitions, etc.
    current memory for variable definitions, etc.
    """
    """
 
 
    #
    #
    # Enumerate the directives
    # Enumerate the directives
    # Note:  The ".include" directive is handled within asmDef.FileBodyIterator.
    # Note:  The ".include" directive is handled within asmDef.FileBodyIterator.
    #
    #
 
 
    self.directives = dict();
    self.directives = dict();
 
 
    self.directives['list']= list();
    self.directives['list']= list();
    self.directives['list'].append('.constant');
    self.directives['list'].append('.constant');
    self.directives['list'].append('.function');
    self.directives['list'].append('.function');
    self.directives['list'].append('.interrupt');
    self.directives['list'].append('.interrupt');
    self.directives['list'].append('.macro');
    self.directives['list'].append('.macro');
    self.directives['list'].append('.main');
    self.directives['list'].append('.main');
    self.directives['list'].append('.memory');
    self.directives['list'].append('.memory');
    self.directives['list'].append('.variable');
    self.directives['list'].append('.variable');
 
 
    #
    #
    # Configure the instructions.
    # Configure the instructions.
    #
    #
 
 
    self.instructions = dict(list=list(), opcode=list());
    self.instructions = dict(list=list(), opcode=list());
    self.AddInstruction('&',            0x050);
    self.AddInstruction('&',            0x050);
    self.AddInstruction('+',            0x018);
    self.AddInstruction('+',            0x018);
    self.AddInstruction('-',            0x01C);
    self.AddInstruction('-',            0x01C);
    self.AddInstruction('-1<>',         0x023);
    self.AddInstruction('-1<>',         0x023);
    self.AddInstruction('-1=',          0x022);
    self.AddInstruction('-1=',          0x022);
    self.AddInstruction('0<>',          0x021);
    self.AddInstruction('0<>',          0x021);
    self.AddInstruction('0=',           0x020);
    self.AddInstruction('0=',           0x020);
    self.AddInstruction('0>>',          0x004);
    self.AddInstruction('0>>',          0x004);
    self.AddInstruction('1+',           0x058);
    self.AddInstruction('1+',           0x058);
    self.AddInstruction('1-',           0x05C);
    self.AddInstruction('1-',           0x05C);
    self.AddInstruction('1>>',          0x005);
    self.AddInstruction('1>>',          0x005);
    self.AddInstruction('<<0',          0x001);
    self.AddInstruction('<<0',          0x001);
    self.AddInstruction('<<1',          0x002);
    self.AddInstruction('<<1',          0x002);
    self.AddInstruction('<<msb',        0x003);
    self.AddInstruction('<<msb',        0x003);
    self.AddInstruction('>r',           0x040);
    self.AddInstruction('>r',           0x040);
    self.AddInstruction('^',            0x052);
    self.AddInstruction('^',            0x052);
    #self.AddInstruction('dis',          0x01C);
    #self.AddInstruction('dis',          0x01C);
    self.AddInstruction('drop',         0x054);
    self.AddInstruction('drop',         0x054);
    self.AddInstruction('dup',          0x008);
    self.AddInstruction('dup',          0x008);
    #self.AddInstruction('ena',          0x019);
    #self.AddInstruction('ena',          0x019);
    self.AddInstruction('inport',       0x030);
    self.AddInstruction('inport',       0x030);
    self.AddInstruction('lsb>>',        0x007);
    self.AddInstruction('lsb>>',        0x007);
    self.AddInstruction('msb>>',        0x006);
    self.AddInstruction('msb>>',        0x006);
    self.AddInstruction('nip',          0x053);
    self.AddInstruction('nip',          0x053);
    self.AddInstruction('nop',          0x000);
    self.AddInstruction('nop',          0x000);
    self.AddInstruction('or',           0x051);
    self.AddInstruction('or',           0x051);
    self.AddInstruction('outport',      0x038);
    self.AddInstruction('outport',      0x038);
    self.AddInstruction('over',         0x00A);
    self.AddInstruction('over',         0x00A);
    self.AddInstruction('r>',           0x049);
    self.AddInstruction('r>',           0x049);
    self.AddInstruction('r@',           0x009);
    self.AddInstruction('r@',           0x009);
    self.AddInstruction('swap',         0x012);
    self.AddInstruction('swap',         0x012);
 
 
    self.specialInstructions = dict();
    self.specialInstructions = dict();
    self.specialInstructions['call']    = 0x0C0;
    self.specialInstructions['call']    = 0x0C0;
    self.specialInstructions['callc']   = 0x0E0;
    self.specialInstructions['callc']   = 0x0E0;
    self.specialInstructions['fetch']   = 0x068;
    self.specialInstructions['fetch']   = 0x068;
    self.specialInstructions['fetch+']  = 0x078;
    self.specialInstructions['fetch+']  = 0x078;
    self.specialInstructions['fetch-']  = 0x07C;
    self.specialInstructions['fetch-']  = 0x07C;
    self.specialInstructions['jump']    = 0x080;
    self.specialInstructions['jump']    = 0x080;
    self.specialInstructions['jumpc']   = 0x0A0;
    self.specialInstructions['jumpc']   = 0x0A0;
    self.specialInstructions['return']  = 0x028;
    self.specialInstructions['return']  = 0x028;
    self.specialInstructions['store']   = 0x060;
    self.specialInstructions['store']   = 0x060;
    self.specialInstructions['store+']  = 0x070;
    self.specialInstructions['store+']  = 0x070;
    self.specialInstructions['store-']  = 0x074;
    self.specialInstructions['store-']  = 0x074;
 
 
    #
    #
    # Configure the pre-defined macros
    # Configure the pre-defined macros
    # Note:  'symbol' is a catch-call for functions, labels, variables, etc.
    # Note:  'symbol' is a catch-call for functions, labels, variables, etc.
    #        These are restricted to the appropriate types when the macros are
    #        These are restricted to the appropriate types when the macros are
    #        expanded.
    #        expanded.
    #
    #
 
 
    self.macros = dict(list=list(), length=list(), args=list(), nArgs=list(), builtIn = list());
    self.macros = dict(list=list(), length=list(), args=list(), nArgs=list(), builtIn = list());
    self.EmitFunction = dict();
    self.EmitFunction = dict();
 
 
    # Macros built in to the assembler (to access primitives).
    # Macros built in to the assembler (to access primitives).
    self.AddMacro('.call',              3, [
    self.AddMacro('.call',              3, [
                                             ['','symbol'],
                                             ['','symbol'],
                                             ['nop','instruction','singlemacro','singlevalue','symbol']
                                             ['nop','instruction','singlemacro','singlevalue','symbol']
                                           ]);
                                           ]);
    self.AddMacro('.callc',             3, [
    self.AddMacro('.callc',             3, [
                                             ['','symbol'],
                                             ['','symbol'],
                                             ['drop','instruction','singlevalue','symbol']
                                             ['drop','instruction','singlevalue','symbol']
                                           ]);
                                           ]);
    self.AddMacro('.fetch',             1, [ ['','symbol'] ]);
    self.AddMacro('.fetch',             1, [ ['','symbol'] ]);
    self.AddMacro('.fetch+',            1, [ ['','symbol'] ]);
    self.AddMacro('.fetch+',            1, [ ['','symbol'] ]);
    self.AddMacro('.fetch-',            1, [ ['','symbol'] ]);
    self.AddMacro('.fetch-',            1, [ ['','symbol'] ]);
    self.AddMacro('.jump',              3, [
    self.AddMacro('.jump',              3, [
                                             ['','symbol'],
                                             ['','symbol'],
                                             ['nop','instruction','singlemacro','singlevalue','symbol']
                                             ['nop','instruction','singlemacro','singlevalue','symbol']
                                           ]);
                                           ]);
    self.AddMacro('.jumpc',             3, [
    self.AddMacro('.jumpc',             3, [
                                             ['','symbol'],
                                             ['','symbol'],
                                             ['drop','instruction','singlemacro','singlevalue','symbol']
                                             ['drop','instruction','singlemacro','singlevalue','symbol']
                                           ]);
                                           ]);
    self.AddMacro('.return',            2, [ ['nop','instruction','singlevalue','symbol'] ]);
    self.AddMacro('.return',            2, [ ['nop','instruction','singlemacro','singlevalue','symbol'] ]);
    self.AddMacro('.store',             1, [ ['','symbol'] ]);
    self.AddMacro('.store',             1, [ ['','symbol'] ]);
    self.AddMacro('.store+',            1, [ ['','symbol'] ]);
    self.AddMacro('.store+',            1, [ ['','symbol'] ]);
    self.AddMacro('.store-',            1, [ ['','symbol'] ]);
    self.AddMacro('.store-',            1, [ ['','symbol'] ]);
 
 
    # User-defined macros in ./macros that are "built in" to the assembler.
    # User-defined macros in ./macros that are "built in" to the assembler.
    macroSearchPath = os.path.join(sys.path[0],'macros');
    macroSearchPath = os.path.join(sys.path[0],'macros');
    for macroName in os.listdir(macroSearchPath):
    for macroName in os.listdir(macroSearchPath):
      if not re.match(r'.*\.py$',macroName):
      if not re.match(r'.*\.py$',macroName):
        continue;
        continue;
      self.AddUserMacro(macroName[:-3],macroSearchPaths=[macroSearchPath]);
      self.AddUserMacro(macroName[:-3],macroSearchPaths=[macroSearchPath]);
    for macroName in self.macros['list']:
    for macroName in self.macros['list']:
      self.macros['builtIn'].append(macroName);
      self.macros['builtIn'].append(macroName);
 
 
    #
    #
    # List the macros that have special symbols for their first argument.
    # List the macros that have special symbols for their first argument.
    #
    #
 
 
    self.MacrosWithSpecialFirstSymbol = ('.call','.callc','.jump','.jumpc',);
    self.MacrosWithSpecialFirstSymbol = ('.call','.callc','.jump','.jumpc',);
 
 
    #
    #
    # Externally defined parameters.
    # Externally defined parameters.
    #
    #
 
 
    self.memoryLength = dict();
    self.memoryLength = dict();
    self.stackLength = dict();
    self.stackLength = dict();
 
 
    #
    #
    # Configure the containers for the expanded main, interrupt, function,
    # Configure the containers for the expanded main, interrupt, function,
    # macro, etc. definitions.
    # macro, etc. definitions.
    #
    #
 
 
    self.currentMemory = None;
    self.currentMemory = None;
    self.interrupt = None;
    self.interrupt = None;
    self.main = None;
    self.main = None;
    self.macroSearchPaths = ['.','./macros'];
    self.macroSearchPaths = ['.','./macros'];
    self.symbols = dict(list=list(), type=list(), body=list());
    self.symbols = dict(list=list(), type=list(), body=list());
 
 

powered by: WebSVN 2.1.0

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