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

Subversion Repositories ssbcc

[/] [ssbcc/] [trunk/] [ssbccConfig.py] - Diff between revs 9 and 10

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

Rev 9 Rev 10
################################################################################
################################################################################
#
#
# Copyright 2012-2013, Sinclair R.F., Inc.
# Copyright 2012-2013, Sinclair R.F., Inc.
#
#
# Utilities required by ssbcc
# Utilities required by ssbcc
#
#
################################################################################
################################################################################
 
 
import math
import math
import os
import os
import re
import re
import sys
import sys
 
 
from ssbccUtil import *
from ssbccUtil import *
 
 
class SSBCCconfig():
class SSBCCconfig():
  """
  """
  Container for ssbcc configuration commands, the associated parsing, and
  Container for ssbcc configuration commands, the associated parsing, and
  program generation.
  program generation.
  """
  """
 
 
  def __init__(self):
  def __init__(self):
    """
    """
    Initialize the empty dictionaries holding the processor configuration
    Initialize the empty dictionaries holding the processor configuration
    parameters.  Initialize the paths to search for peripherals.
    parameters.  Initialize the paths to search for peripherals.
    """
    """
    self.config         = dict();               # various settings, etc.
    self.config         = dict();               # various settings, etc.
    self.constants      = dict();               # CONSTANTs
    self.constants      = dict();               # CONSTANTs
    self.defines        = dict();               # defines
    self.defines        = dict();               # defines
    self.functions      = dict();               # list of functions to define
    self.functions      = dict();               # list of functions to define
    self.inports        = list();               # INPORT definitions
    self.inports        = list();               # INPORT definitions
    self.ios            = list();               # List of I/Os
    self.ios            = list();               # List of I/Os
    self.outports       = list();               # OUTPORT definitions (see AddOutport)
    self.outports       = list();               # OUTPORT definitions (see AddOutport)
    self.parameters     = list();               # PARAMETERs and LOCALPARAMs
    self.parameters     = list();               # PARAMETERs and LOCALPARAMs
    self.peripheral     = list();               # PERIPHERALs
    self.peripheral     = list();               # PERIPHERALs
    self.signals        = list();               # internal signals
    self.signals        = list();               # internal signals
    self.symbols        = list();               # constant, I/O, inport, etc.  names
    self.symbols        = list();               # constant, I/O, inport, etc.  names
 
 
    # list of memories
    # list of memories
    self.memories = dict(name=list(), type=list(), maxLength=list());
    self.memories = dict(name=list(), type=list(), maxLength=list());
 
 
    # list of how the memories will be instantiated
    # list of how the memories will be instantiated
    self.config['combine'] = list();
    self.config['combine'] = list();
 
 
    # initial search path for .INCLUDE configuration commands
    # initial search path for .INCLUDE configuration commands
    self.includepaths = list();
    self.includepaths = list();
    self.includepaths.append('.');
    self.includepaths.append('.');
 
 
    # initial search paths for peripherals
    # initial search paths for peripherals
    self.peripheralpaths = list();
    self.peripheralpaths = list();
    self.peripheralpaths.append('.');
    self.peripheralpaths.append('.');
    self.peripheralpaths.append('peripherals');
    self.peripheralpaths.append('peripherals');
    self.peripheralpaths.append(os.path.join(sys.path[0],'core/peripherals'));
    self.peripheralpaths.append(os.path.join(sys.path[0],'core/peripherals'));
 
 
  def AddConstant(self,name,value,loc):
  def AddConstant(self,name,value,loc):
    """
    """
    Add the constant for the "CONSTANT" configuration command to the "constants"
    Add the constant for the "CONSTANT" configuration command to the "constants"
    dictionary.\n
    dictionary.\n
    name        symbol for the constant
    name        symbol for the constant
    value       value of the constant
    value       value of the constant
    loc         file name and line number for error messages
    loc         file name and line number for error messages
    """
    """
    self.AddSymbol(name,loc);
    self.AddSymbol(name,loc);
    if name in self.constants:
    if name in self.constants:
      raise SSBCCException('CONSTANT "%s" already declared at %s' % (name,loc,));
      raise SSBCCException('CONSTANT "%s" already declared at %s' % (name,loc,));
    if not IsIntExpr(value):
    if not IsIntExpr(value):
      raise SSBCCException('Could not evaluate expression "%s" for constant at %s' % (value,loc,));
      raise SSBCCException('Could not evaluate expression "%s" for constant at %s' % (value,loc,));
    self.constants[name] = ParseIntExpr(value);
    self.constants[name] = ParseIntExpr(value);
 
 
  def AddDefine(self,name):
  def AddDefine(self,name):
    """
    """
    Add the defined symbol.\n
    Add the defined symbol.\n
    name        name for the symbol (must start with "D_")\n
    name        name for the symbol (must start with "D_")\n
    Note:  This is only invoked for the command line arguments so there is no
    Note:  This is only invoked for the command line arguments so there is no
           "loc" available.\n
           "loc" available.\n
    Note:  Defines can be declared more than once on the command line with no
    Note:  Defines can be declared more than once on the command line with no
           ill effects.
           ill effects.
    """
    """
    if not self.IsDefine(name):
    if not self.IsDefine(name):
      self.AddSymbol(name);
      self.AddSymbol(name);
      self.defines[name] = 1;
      self.defines[name] = 1;
 
 
  def AddIO(self,name,nBits,iotype,loc):
  def AddIO(self,name,nBits,iotype,loc):
    """
    """
    Add an I/O signal to the processor interface to the system.\n
    Add an I/O signal to the processor interface to the system.\n
    name        name of the I/O signal
    name        name of the I/O signal
    nBits       number of bits in the I/O signal
    nBits       number of bits in the I/O signal
    iotype      signal direction:  "input", "output", or "inout"
    iotype      signal direction:  "input", "output", or "inout"
    """
    """
    if iotype != 'comment':
    if iotype != 'comment':
      self.AddSymbol(name,loc);
      self.AddSymbol(name,loc);
    self.ios.append((name,nBits,iotype,));
    self.ios.append((name,nBits,iotype,));
 
 
  def AddInport(self,port,loc):
  def AddInport(self,port,loc):
    """
    """
    Add an INPORT symbol to the processor.\n
    Add an INPORT symbol to the processor.\n
    port        name of the INPORT symbol
    port        name of the INPORT symbol
    loc         file name and line number for error messages
    loc         file name and line number for error messages
    """
    """
    name = port[0];
    name = port[0];
    self.AddSymbol(name,loc);
    self.AddSymbol(name,loc);
    self.inports.append(port);
    self.inports.append(port);
 
 
  def AddMemory(self,cmd,loc):
  def AddMemory(self,cmd,loc):
    """
    """
    Add a memory to the list of memories.\n
    Add a memory to the list of memories.\n
    cmd         3-element list as follows:
    cmd         3-element list as follows:
                [0] ==> type:  "RAM" or "ROM"
                [0] ==> type:  "RAM" or "ROM"
                [1] ==> memory name
                [1] ==> memory name
                [2] ==> memory length (must be a power of 2)
                [2] ==> memory length (must be a power of 2)
    loc         file name and line number for error messages
    loc         file name and line number for error messages
    """
    """
    self.memories['type'].append(cmd[0]);
    self.memories['type'].append(cmd[0]);
    self.memories['name'].append(cmd[1]);
    self.memories['name'].append(cmd[1]);
    maxLength = eval(cmd[2]);
    maxLength = eval(cmd[2]);
    if not IsPowerOf2(maxLength):
    if not IsPowerOf2(maxLength):
      raise SSBCCException('Memory length must be a power of 2, not "%s", at %s' % (cmd[2],loc,));
      raise SSBCCException('Memory length must be a power of 2, not "%s", at %s' % (cmd[2],loc,));
    self.memories['maxLength'].append(eval(cmd[2]));
    self.memories['maxLength'].append(eval(cmd[2]));
 
 
  def AddOutport(self,port,loc):
  def AddOutport(self,port,loc):
    """
    """
    Add an OUTPORT symbol to the processor.\n
    Add an OUTPORT symbol to the processor.\n
    port        tuple as follows:
    port        tuple as follows:
                port[0] - name of the OUTPORT symbol
                port[0] - name of the OUTPORT symbol
                port[1] - True if the outport is a strobe-only outport, false
                port[1] - True if the outport is a strobe-only outport, false
                          otherwise
                          otherwise
                port[2:] - zero or more tuples as follows:
                port[2:] - zero or more tuples as follows:
                  (o_signal,width,type,[initialization],)
                  (o_signal,width,type,[initialization],)
                where
                where
                  o_signal is the name of the output signal
                  o_signal is the name of the output signal
                  width is the number of bits in the signal
                  width is the number of bits in the signal
                  type is 'data' or 'strobe'
                  type is 'data' or 'strobe'
                  initialization is an optional initial/reset value for the
                  initialization is an optional initial/reset value for the
                    output signal
                    output signal
    loc         file name and line number for error messages
    loc         file name and line number for error messages
    """
    """
    self.AddSymbol(port[0],loc);
    self.AddSymbol(port[0],loc);
    self.outports.append(port);
    self.outports.append(port);
 
 
  def AddParameter(self,name,value,loc):
  def AddParameter(self,name,value,loc):
    """
    """
    Add a PARAMETER to the processor.\n
    Add a PARAMETER to the processor.\n
    name        name of the PARAMETER
    name        name of the PARAMETER
    value       value of the PARAMETER
    value       value of the PARAMETER
    loc         file name and line number for error messages
    loc         file name and line number for error messages
    """
    """
    if not re.match(r'[LG]_\w+$',name):
    if not re.match(r'[LG]_\w+$',name):
      raise Exception('Program Bug -- bad parameter name at %s' % loc);
      raise Exception('Program Bug -- bad parameter name at %s' % loc);
    self.AddSymbol(name,loc);
    self.AddSymbol(name,loc);
    self.parameters.append((name,value,));
    self.parameters.append((name,value,));
 
 
  def AddSignal(self,name,nBits,loc):
  def AddSignal(self,name,nBits,loc):
    """
    """
    Add a signal without an initial value to the processor.\n
    Add a signal without an initial value to the processor.\n
    name        name of the signal
    name        name of the signal
    nBits       number of bits in the signal
    nBits       number of bits in the signal
    loc         file name and line number for error messages
    loc         file name and line number for error messages
    """
    """
    self.AddSymbol(name,loc);
    self.AddSymbol(name,loc);
    self.signals.append((name,nBits,));
    self.signals.append((name,nBits,));
 
 
  def AddSignalWithInit(self,name,nBits,init,loc):
  def AddSignalWithInit(self,name,nBits,init,loc):
    """
    """
    Add a signal with an initial/reset value to the processor.\n
    Add a signal with an initial/reset value to the processor.\n
    name        name of the signal
    name        name of the signal
    nBits       number of bits in the signal
    nBits       number of bits in the signal
    init        initial/reset value of the signal
    init        initial/reset value of the signal
    loc         file name and line number for error messages
    loc         file name and line number for error messages
    """
    """
    self.AddSymbol(name,loc);
    self.AddSymbol(name,loc);
    self.signals.append((name,nBits,init,));
    self.signals.append((name,nBits,init,));
 
 
  def AddSymbol(self,name,loc=None):
  def AddSymbol(self,name,loc=None):
    """
    """
    Add the specified name to the list of symbols.\n
    Add the specified name to the list of symbols.\n
    Note:  This symbol has no associated functionality and is only used for
    Note:  This symbol has no associated functionality and is only used for
           ".ifdef" conditionals.
           ".ifdef" conditionals.
    """
    """
    if name in self.symbols:
    if name in self.symbols:
      if loc == None:
      if loc == None:
        raise SSBCCException('Symbol "%s" already defined, no line number provided');
        raise SSBCCException('Symbol "%s" already defined, no line number provided');
      else:
      else:
        raise SSBCCException('Symbol "%s" already defined before %s' % (name,loc,));
        raise SSBCCException('Symbol "%s" already defined before %s' % (name,loc,));
    self.symbols.append(name);
    self.symbols.append(name);
 
 
  def AppendIncludePath(self,path):
  def AppendIncludePath(self,path):
    """
    """
    Add the specified path to the end of the paths to search for .INCLUDE
    Add the specified path to the end of the paths to search for .INCLUDE
    configuration commands.\n
    configuration commands.\n
    path        path to add to the list
    path        path to add to the list
    """
    """
    self.includepaths.insert(-1,path);
    self.includepaths.insert(-1,path);
 
 
  def CompleteCombines(self):
  def CompleteCombines(self):
    """
    """
    Ensure all memories are assigned addresses.\n
    Ensure all memories are assigned addresses.\n
    This modifies config['combine'] to include singleton entries for any
    This modifies config['combine'] to include singleton entries for any
    memories not subject to the COMBINE configuration command.  It then computes
    memories not subject to the COMBINE configuration command.  It then computes
    how the memories will be packed together as well as properites for the
    how the memories will be packed together as well as properites for the
    packed memories.  These properties are:
    packed memories.  These properties are:
      packing   how the memories will be packed as per PackCombinedMemory
      packing   how the memories will be packed as per PackCombinedMemory
      memName   HDL name of the memory
      memName   HDL name of the memory
      memLength number of words in the memory
      memLength number of words in the memory
      memWidth  bit width of the memory words
      memWidth  bit width of the memory words
    """
    """
    # Create singleton entries for memory types and memories that aren't already listed in 'combine'.
    # Create singleton entries for memory types and memories that aren't already listed in 'combine'.
    if not self.IsCombined('INSTRUCTION'):
    if not self.IsCombined('INSTRUCTION'):
      self.config['combine'].append({'mems':['INSTRUCTION',], 'memArch':'sync'});
      self.config['combine'].append({'mems':['INSTRUCTION',], 'memArch':'sync'});
    for memType in ('DATA_STACK','RETURN_STACK',):
    for memType in ('DATA_STACK','RETURN_STACK',):
      if not self.IsCombined(memType):
      if not self.IsCombined(memType):
        self.config['combine'].append({'mems':[memType,], 'memArch':'LUT'});
        self.config['combine'].append({'mems':[memType,], 'memArch':'LUT'});
    for memName in self.memories['name']:
    for memName in self.memories['name']:
      if not self.IsCombined(memName):
      if not self.IsCombined(memName):
        self.config['combine'].append({'mems':[memName,], 'memArch':'LUT'});
        self.config['combine'].append({'mems':[memName,], 'memArch':'LUT'});
    # Determine the HDL names for the memories.
    # Determine the HDL names for the memories.
    nRAMROMs = 0;
    nRAMROMs = 0;
    for combined in self.config['combine']:
    for combined in self.config['combine']:
      if combined['mems'][0] == 'INSTRUCTION':
      if combined['mems'][0] == 'INSTRUCTION':
        combined['memName'] = 's_opcodeMemory';
        combined['memName'] = 's_opcodeMemory';
      elif combined['mems'][0] == 'DATA_STACK':
      elif combined['mems'][0] == 'DATA_STACK':
        combined['memName'] = 's_data_stack';
        combined['memName'] = 's_data_stack';
      elif combined['mems'][0] == 'RETURN_STACK':
      elif combined['mems'][0] == 'RETURN_STACK':
        combined['memName'] = 's_R_stack';
        combined['memName'] = 's_R_stack';
      else:
      else:
        nRAMROMs += 1;
        nRAMROMs += 1;
    if nRAMROMs > 0:
    if nRAMROMs > 0:
      memNameFormat = 's_mem_%%0%dx' % ((CeilLog2(nRAMROMs)+3)/4);
      memNameFormat = 's_mem_%%0%dx' % ((CeilLog2(nRAMROMs)+3)/4);
    ixRAMROM = 0;
    ixRAMROM = 0;
    for combined in self.config['combine']:
    for combined in self.config['combine']:
      if 'memName' in combined:
      if 'memName' in combined:
        continue;
        continue;
      if nRAMROMs == 1:
      if nRAMROMs == 1:
        combined['memName'] = 's_mem';
        combined['memName'] = 's_mem';
      else:
      else:
        combined['memName'] = memNameFormat % ixRAMROM;
        combined['memName'] = memNameFormat % ixRAMROM;
        ixRAMROM += 1;
        ixRAMROM += 1;
    # Perform packing for all memories.
    # Perform packing for all memories.
    for combined in self.config['combine']:
    for combined in self.config['combine']:
      self.PackCombinedMemory(combined);
      self.PackCombinedMemory(combined);
 
 
  def Exists(self,name):
  def Exists(self,name):
    """
    """
    Return true if the requested attribute has been created in the ssbccConfig
    Return true if the requested attribute has been created in the ssbccConfig
    object.
    object.
    """
    """
    return name in self.config;
    return name in self.config;
 
 
  def Get(self,name):
  def Get(self,name):
    """
    """
    Return the requested attribute from the ssbccConfig object.
    Return the requested attribute from the ssbccConfig object.
    """
    """
    if not self.Exists(name):
    if not self.Exists(name):
      raise Exception('Program Bug:  "%s" not found in config' % name);
      raise Exception('Program Bug:  "%s" not found in config' % name);
    return self.config[name];
    return self.config[name];
 
 
  def GetMemoryByBank(self,ixBank):
  def GetMemoryByBank(self,ixBank):
    """
    """
    Return the parameters for a memory by its bank address.\n
    Return the parameters for a memory by its bank address.\n
    ixBank      index of the requested memory bank
    ixBank      index of the requested memory bank
    """
    """
    if not 'bank' in self.memories:
    if not 'bank' in self.memories:
      return None;
      return None;
    if ixBank not in self.memories['bank']:
    if ixBank not in self.memories['bank']:
      return None;
      return None;
    ixMem = self.memories['bank'].index(ixBank);
    ixMem = self.memories['bank'].index(ixBank);
    return self.GetMemoryParameters(ixMem);
    return self.GetMemoryParameters(ixMem);
 
 
  def GetMemoryByName(self,name):
  def GetMemoryByName(self,name):
    """
    """
    Return the parameters for a memory by its name.\n
    Return the parameters for a memory by its name.\n
    name        name of the requested memory
    name        name of the requested memory
    """
    """
    if not name in self.memories['name']:
    if not name in self.memories['name']:
      return None;
      return None;
    ixMem = self.memories['name'].index(name);
    ixMem = self.memories['name'].index(name);
    return self.GetMemoryParameters(ixMem);
    return self.GetMemoryParameters(ixMem);
 
 
  def GetMemoryParameters(self,rawIndex):
  def GetMemoryParameters(self,rawIndex):
    """
    """
    Return the parameters for a memory by its index in the list of memories.\n
    Return the parameters for a memory by its index in the list of memories.\n
    rawIndex    index within the list of memories
    rawIndex    index within the list of memories
    """
    """
    if type(rawIndex) == str:
    if type(rawIndex) == str:
      if not self.IsMemory(rawIndex):
      if not self.IsMemory(rawIndex):
        raise Exception('Program Bug:  reference to non-existent memory');
        raise Exception('Program Bug:  reference to non-existent memory');
      ix = self.memories['name'].index(rawIndex);
      ix = self.memories['name'].index(rawIndex);
    elif type(rawIndex) == int:
    elif type(rawIndex) == int:
      if (rawIndex < 0) or (rawIndex >= len(self.memories['name'])):
      if (rawIndex < 0) or (rawIndex >= len(self.memories['name'])):
        raise Exception('Program Bug:  bad memory index %d' % rawIndex);
        raise Exception('Program Bug:  bad memory index %d' % rawIndex);
      ix = rawIndex;
      ix = rawIndex;
    else:
    else:
      raise Exception('Program Bug:  unrecognized index type "%s"' % type(rawIndex));
      raise Exception('Program Bug:  unrecognized index type "%s"' % type(rawIndex));
    outvalue = dict();
    outvalue = dict();
    outvalue['index'] = ix;
    outvalue['index'] = ix;
    for field in self.memories:
    for field in self.memories:
      outvalue[field] = self.memories[field][ix];
      outvalue[field] = self.memories[field][ix];
    return outvalue;
    return outvalue;
 
 
  def GetPacking(self,name):
  def GetPacking(self,name):
    """
    """
    Get the memory packing for the provided memory.
    Get the memory packing for the provided memory.
    """
    """
    for combined in self.config['combine']:
    for combined in self.config['combine']:
      if name not in combined['mems']:
      if name not in combined['mems']:
        continue;
        continue;
      for port in combined['port']:
      for port in combined['port']:
        for packing in port['packing']:
        for packing in port['packing']:
          if packing['name'] == name:
          if packing['name'] == name:
            return (combined,port,packing,);
            return (combined,port,packing,);
    else:
    else:
      raise Exception('Program Bug -- %s not found in combined memories' % name);
      raise Exception('Program Bug -- %s not found in combined memories' % name);
 
 
  def GetParameterValue(self,name):
  def GetParameterValue(self,name):
    """
    """
    Get the value associated with the named parameter.
    Get the value associated with the named parameter.
    """
    """
    if name.find('[') != -1:
    if name.find('[') != -1:
      ix = name.index('[');
      ix = name.index('[');
      thisSlice = name[ix:];
      thisSlice = name[ix:];
      name = name[:ix];
      name = name[:ix];
    else:
    else:
      thisSlice = '[0+:8]';
      thisSlice = '[0+:8]';
    for ix in range(len(self.parameters)):
    for ix in range(len(self.parameters)):
      if self.parameters[ix][0] == name:
      if self.parameters[ix][0] == name:
        return ExtractBits(IntValue(self.parameters[ix][1]),thisSlice);
        return ExtractBits(IntValue(self.parameters[ix][1]),thisSlice);
    else:
    else:
      raise Exception('Program Bug:  Parameter "%s" not found' % name);
      raise Exception('Program Bug:  Parameter "%s" not found' % name);
 
 
  def InsertPeripheralPath(self,path):
  def InsertPeripheralPath(self,path):
    """
    """
    Add the specified path to the beginning of the paths to search for
    Add the specified path to the beginning of the paths to search for
    peripherals.\n
    peripherals.\n
    path        path to add to the list
    path        path to add to the list
    """
    """
    self.peripheralpaths.insert(-1,path);
    self.peripheralpaths.insert(-1,path);
 
 
  def IsCombined(self,name):
  def IsCombined(self,name):
    """
    """
    Indicate whether or not the specified memory type has already been listed
    Indicate whether or not the specified memory type has already been listed
    in a "COMBINE" configuration command.  The memory type should be one of
    in a "COMBINE" configuration command.  The memory type should be one of
    DATA_STACK, INSTRUCTION, or RETURN_STACK.\n
    DATA_STACK, INSTRUCTION, or RETURN_STACK.\n
    name        name of the specified memory type\n
    name        name of the specified memory type\n
    """
    """
    for combined in self.config['combine']:
    for combined in self.config['combine']:
      if name in combined['mems']:
      if name in combined['mems']:
        return True;
        return True;
    else:
    else:
      return False;
      return False;
 
 
  def IsConstant(self,name):
  def IsConstant(self,name):
    """
    """
    Indicate whether or not the specified symbol is a recognized constant.
    Indicate whether or not the specified symbol is a recognized constant.
    """
    """
    if re.match(r'C_\w+$',name) and name in self.constants:
    if re.match(r'C_\w+$',name) and name in self.constants:
      return True;
      return True;
    else:
    else:
      return False;
      return False;
 
 
  def IsDefine(self,name):
  def IsDefine(self,name):
    """
    """
    Indicate whether or not the specified symbol is a recognized define.
    Indicate whether or not the specified symbol is a recognized define.
    """
    """
    if re.match(r'D_\w+$',name) and name in self.defines:
    if re.match(r'D_\w+$',name) and name in self.defines:
      return True;
      return True;
    else:
    else:
      return False;
      return False;
 
 
  def IsMemory(self,name):
  def IsMemory(self,name):
    """
    """
    Indicate whether or not the specified symbol is the name of a memory.
    Indicate whether or not the specified symbol is the name of a memory.
    """
    """
    return (name in self.memories['name']);
    return (name in self.memories['name']);
 
 
  def IsParameter(self,name):
  def IsParameter(self,name):
    """
    """
    Indicate whether or not the specified symbol is the name of a parameter.
    Indicate whether or not the specified symbol is the name of a parameter.
    """
    """
    if re.match(r'[GL]_\w+$',name) and name in self.symbols:
    if re.match(r'[GL]_\w+$',name) and name in self.symbols:
      return True;
      return True;
    else:
    else:
      return False;
      return False;
 
 
  def IsRAM(self,name):
  def IsRAM(self,name):
    """
    """
    Indicate whether or not the specified symbol is the name of a RAM.
    Indicate whether or not the specified symbol is the name of a RAM.
    """
    """
    if name not in self.memories['name']:
    if name not in self.memories['name']:
      return False;
      return False;
    ix = self.memories['name'].index(name);
    ix = self.memories['name'].index(name);
    return self.memories['type'][ix] == 'RAM';
    return self.memories['type'][ix] == 'RAM';
 
 
  def IsROM(self,name):
  def IsROM(self,name):
    """
    """
    Indicate whether or not the specified symbol is the name of a RAM.
    Indicate whether or not the specified symbol is the name of a RAM.
    """
    """
    if name not in self.memories['name']:
    if name not in self.memories['name']:
      return False;
      return False;
    ix = self.memories['name'].index(name);
    ix = self.memories['name'].index(name);
    return self.memories['type'][ix] == 'ROM';
    return self.memories['type'][ix] == 'ROM';
 
 
  def IsStrobeOnlyOutport(self,outport):
  def IsStrobeOnlyOutport(self,outport):
    """
    """
    Indicate whether or not the specified outport symbol only has strobes
    Indicate whether or not the specified outport symbol only has strobes
    associated with it (i.e., it has no data signals).
    associated with it (i.e., it has no data signals).
    """
    """
    return outport[1];
    return outport[1];
 
 
  def IsSymbol(self,name):
  def IsSymbol(self,name):
    """
    """
    Indicate whether or not the specified name is a symbol.
    Indicate whether or not the specified name is a symbol.
    """
    """
    return (name in self.symbols);
    return (name in self.symbols);
 
 
  def MemoryNameLengthList(self):
  def MemoryNameLengthList(self):
    """
    """
    Return a list of tuples where each tuple is the name of a memory and its
    Return a list of tuples where each tuple is the name of a memory and its
    length.
    length.
    """
    """
    outlist = list();
    outlist = list();
    for ix in range(len(self.memories['name'])):
    for ix in range(len(self.memories['name'])):
      outlist.append((self.memories['name'][ix],self.memories['maxLength'][ix],));
      outlist.append((self.memories['name'][ix],self.memories['maxLength'][ix],));
    return outlist;
    return outlist;
 
 
  def NInports(self):
  def NInports(self):
    """
    """
    Return the number of INPORTS.
    Return the number of INPORTS.
    """
    """
    return len(self.inports);
    return len(self.inports);
 
 
  def NMemories(self):
  def NMemories(self):
    """
    """
    Return the number of memories.
    Return the number of memories.
    """
    """
    return len(self.memories['name']);
    return len(self.memories['name']);
 
 
  def NOutports(self):
  def NOutports(self):
    """
    """
    Return the number of OUTPORTS.
    Return the number of OUTPORTS.
    """
    """
    return len(self.outports);
    return len(self.outports);
 
 
  def OverrideParameter(self,name,value):
  def OverrideParameter(self,name,value):
    """
    """
    Change the value of the specified parameter (based on the command line
    Change the value of the specified parameter (based on the command line
    argument instead of the architecture file).\n
    argument instead of the architecture file).\n
    name        name of the parameter to change
    name        name of the parameter to change
    value       new value of the parameter
    value       new value of the parameter
    """
    """
    for ix in range(len(self.parameters)):
    for ix in range(len(self.parameters)):
      if self.parameters[ix][0] == name:
      if self.parameters[ix][0] == name:
        break;
        break;
    else:
    else:
      raise SSBCCException('Command-line parameter or localparam "%s" not specified in the architecture file' % name);
      raise SSBCCException('Command-line parameter or localparam "%s" not specified in the architecture file' % name);
    self.parameters[ix] = (name,value,);
    self.parameters[ix] = (name,value,);
 
 
  def PackCombinedMemory(self,combined):
  def PackCombinedMemory(self,combined):
    """
    """
    Utility function for CompleteCombines.\n
    Utility function for CompleteCombines.\n
    Determine packing strategy and resulting memory addresses and sizes.  This
    Determine packing strategy and resulting memory addresses and sizes.  This
    list has everything ssbccGenVerilog needs to construct the memory.\n
    list has everything ssbccGenVerilog needs to construct the memory.\n
    The dual port memories can be used to do the following:
    The dual port memories can be used to do the following:
      1.  pack a single memory, either single-port or dual-port
      1.  pack a single memory, either single-port or dual-port
      2.  pack two single-port memories sequentially, i.e., one at the start of
      2.  pack two single-port memories sequentially, i.e., one at the start of
          the RAM and one toward the end of the RAM
          the RAM and one toward the end of the RAM
      3.  pack one single-port memory at the start of the RAM and pack several
      3.  pack one single-port memory at the start of the RAM and pack several
          compatible single-port memories in parallel toward the end of the RAM.
          compatible single-port memories in parallel toward the end of the RAM.
          Note:  Compatible means that they have the same address.
          Note:  Compatible means that they have the same address.
      4.  pack several compatible dual-port memories in parallel.\n
      4.  pack several compatible dual-port memories in parallel.\n
    These single-port or dual-port single or parallel packed memories are
    These single-port or dual-port single or parallel packed memories are
    described in the 'port' list in combined.  Each entry in the port list has
    described in the 'port' list in combined.  Each entry in the port list has
    several parameters described below and a 'packing' list that describes the
    several parameters described below and a 'packing' list that describes the
    single or multiple memories attached to that port.\n
    single or multiple memories attached to that port.\n
    The parameters for each of port is as follows:
    The parameters for each of port is as follows:
      offset    start address of the memory in the packing
      offset    start address of the memory in the packing
      nWords    number of RAM words reserved for the memory
      nWords    number of RAM words reserved for the memory
                Note:  This can be larger than the aggregate number of words
                Note:  This can be larger than the aggregate number of words
                       required by the memory in order to align the memories to
                       required by the memory in order to align the memories to
                       power-of-2 address alignments.
                       power-of-2 address alignments.
      ratio     number of base memory entries for the memory
      ratio     number of base memory entries for the memory
                Note:  This must be a power of 2.\n
                Note:  This must be a power of 2.\n
    The contents of each entry in the packing are as follows:
    The contents of each entry in the packing are as follows:
      -- the following are from the memory declaration
      -- the following are from the memory declaration
      name      memory name
      name      memory name
      length    number of elements in the memory based on the declared memory
      length    number of elements in the memory based on the declared memory
                size
                size
                Note:  This is based on the number of addresses required for
                Note:  This is based on the number of addresses required for
                       each memory entry (see ratio).
                       each memory entry (see ratio).
      nbits     width of the memory type
      nbits     width of the memory type
      -- the following are derived for the packing
      -- the following are derived for the packing
      lane      start bit
      lane      start bit
                Note:  This is required in particular when memories are stacked
                Note:  This is required in particular when memories are stacked
                       in parallel.
                       in parallel.
      nWords    number of memory addresses allocated for the memory based on
      nWords    number of memory addresses allocated for the memory based on
                the packing
                the packing
                Note:  This will be larger than length when a small memory is
                Note:  This will be larger than length when a small memory is
                       packed in parallel with a larger memory.  I.e., when
                       packed in parallel with a larger memory.  I.e., when
                       ratio is not one.
                       ratio is not one.
      ratio     number of base memory entries required to extract a single word
      ratio     number of base memory entries required to extract a single word
                for the memory type
                for the memory type
                Note:  This allows return stack entries to occupy more than one
                Note:  This allows return stack entries to occupy more than one
                       memory address when the return stack is combined with
                       memory address when the return stack is combined with
                       other memory addresses.
                       other memory addresses.
                Note:  This must be a power of 2.\n
                Note:  This must be a power of 2.\n
    The following entries are also added to "combined":
    The following entries are also added to "combined":
      nWords    number of words in the memory
      nWords    number of words in the memory
      memWidth  bit width of the memory words\n
      memWidth  bit width of the memory words\n
    Note:  If memories are being combined with the instructions space, they are
    Note:  If memories are being combined with the instructions space, they are
           always packed at the end of the instruction space, so the
           always packed at the end of the instruction space, so the
           instruction space allocation is not included in the packing.
           instruction space allocation is not included in the packing.
    """
    """
    # Count how many memories of each type are being combined.
    # Count how many memories of each type are being combined.
    nSinglePort = 0;
    nSinglePort = 0;
    nRAMs = 0;
    nRAMs = 0;
    nROMs = 0;
    nROMs = 0;
    for memName in combined['mems']:
    for memName in combined['mems']:
      if memName in ('INSTRUCTION','DATA_STACK','RETURN_STACK',):
      if memName in ('INSTRUCTION','DATA_STACK','RETURN_STACK',):
        nSinglePort += 1;
        nSinglePort += 1;
      elif self.IsROM(memName):
      elif self.IsROM(memName):
        nROMs += 1;
        nROMs += 1;
      else:
      else:
        nRAMs += 1;
        nRAMs += 1;
    if nRAMs > 0:
    if nRAMs > 0:
      nRAMs += nROMs;
      nRAMs += nROMs;
      nROMs = 0;
      nROMs = 0;
    # Ensure the COMBINE configuration command is implementable in a dual-port RAM.
    # Ensure the COMBINE configuration command is implementable in a dual-port RAM.
    if nSinglePort > 0 and nRAMs > 0:
    if nSinglePort > 0 and nRAMs > 0:
      raise SSBCCException('Cannot combine RAMs with other memory types in COMBINE configuration command at %s' % combined['loc']);
      raise SSBCCException('Cannot combine RAMs with other memory types in COMBINE configuration command at %s' % combined['loc']);
    if nSinglePort > 2 or (nSinglePort > 1 and nROMs > 0):
    if nSinglePort > 2 or (nSinglePort > 1 and nROMs > 0):
      raise SSBCCException('Too many memory types in COMBINE configuration command at %s' % combined['loc']);
      raise SSBCCException('Too many memory types in COMBINE configuration command at %s' % combined['loc']);
    # Start splitting the listed memories into the one or two output lists and ensure that single-port memories are listed in the correct order.
    # Start splitting the listed memories into the one or two output lists and ensure that single-port memories are listed in the correct order.
    mems = combined['mems'];
    mems = combined['mems'];
    ixMem = 0;
    ixMem = 0;
    split = list();
    split = list();
    if 'INSTRUCTION' in mems:
    if 'INSTRUCTION' in mems:
      if mems[0] != 'INSTRUCTION':
      if mems[0] != 'INSTRUCTION':
        raise SSBCCException('INSTRUCTION must be the first memory listed in the COMBINE configuration command at %s' % combined['loc']);
        raise SSBCCException('INSTRUCTION must be the first memory listed in the COMBINE configuration command at %s' % combined['loc']);
      split.append(['INSTRUCTION']);
      split.append(['INSTRUCTION']);
      ixMem += 1;
      ixMem += 1;
    while len(mems[ixMem:]) > 0 and mems[ixMem] in ('DATA_STACK','RETURN_STACK',):
    while len(mems[ixMem:]) > 0 and mems[ixMem] in ('DATA_STACK','RETURN_STACK',):
      split.append([mems[ixMem]]);
      split.append([mems[ixMem]]);
      ixMem += 1;
      ixMem += 1;
    for memName in ('DATA_STACK','RETURN_STACK',):
    for memName in ('DATA_STACK','RETURN_STACK',):
      if memName in mems[ixMem:]:
      if memName in mems[ixMem:]:
        raise SSBCCException('Single-port memory %s must be listed before ROMs in COMBINE configuration command at %s' % combined['loc']);
        raise SSBCCException('Single-port memory %s must be listed before ROMs in COMBINE configuration command at %s' % combined['loc']);
    if mems[ixMem:]:
    if mems[ixMem:]:
      split.append(mems[ixMem:]);
      split.append(mems[ixMem:]);
    if not (1 <= len(split) <= 2):
    if not (1 <= len(split) <= 2):
      raise Exception('Program Bug -- bad COMBINE configuration command not caught');
      raise Exception('Program Bug -- bad COMBINE configuration command not caught');
    # Create the detailed packing information.
    # Create the detailed packing information.
    combined['port'] = list();
    combined['port'] = list();
    for thisSplit in split:
    for thisSplit in split:
      packing = list();
      packing = list();
      for memName in thisSplit:
      for memName in thisSplit:
        if memName == 'INSTRUCTION':
        if memName == 'INSTRUCTION':
          packing.append({'name':memName, 'length':self.Get('nInstructions')['length'], 'nbits':9});
          packing.append({'name':memName, 'length':self.Get('nInstructions')['length'], 'nbits':9});
        elif memName == 'DATA_STACK':
        elif memName == 'DATA_STACK':
          packing.append({'name':memName, 'length':self.Get('data_stack'), 'nbits':self.Get('data_width')});
          packing.append({'name':memName, 'length':self.Get('data_stack'), 'nbits':self.Get('data_width')});
        elif memName == 'RETURN_STACK':
        elif memName == 'RETURN_STACK':
          nbits = max(self.Get('data_width'),self.Get('nInstructions')['nbits']);
          nbits = max(self.Get('data_width'),self.Get('nInstructions')['nbits']);
          packing.append({'name':memName, 'length':self.Get('return_stack'), 'nbits':nbits});
          packing.append({'name':memName, 'length':self.Get('return_stack'), 'nbits':nbits});
        else:
        else:
          thisMemory = self.GetMemoryParameters(memName);
          thisMemory = self.GetMemoryParameters(memName);
          packing.append({'name':memName, 'length':CeilPow2(thisMemory['maxLength']), 'nbits':self.Get('data_width')});
          packing.append({'name':memName, 'length':CeilPow2(thisMemory['maxLength']), 'nbits':self.Get('data_width')});
      combined['port'].append({ 'packing':packing });
      combined['port'].append({ 'packing':packing });
    # Calculate the width of the base memory.
    # Calculate the width of the base memory.
    # Note:  This accommodates RETURN_STACK being an isolated memory.
    # Note:  This accommodates RETURN_STACK being an isolated memory.
    memWidth = combined['port'][0]['packing'][0]['nbits'] if len(combined['port']) == 1 else None;
    memWidth = combined['port'][0]['packing'][0]['nbits'] if len(combined['port']) == 1 else None;
    for port in combined['port']:
    for port in combined['port']:
      for packing in port['packing']:
      for packing in port['packing']:
        tempMemWidth = packing['nbits'];
        tempMemWidth = packing['nbits'];
        if tempMemWidth > self.Get('sram_width'):
        if tempMemWidth > self.Get('sram_width'):
          tempMemWidth = self.Get('sram_width');
          tempMemWidth = self.Get('sram_width');
        if not memWidth:
        if not memWidth:
          memWidth = tempMemWidth;
          memWidth = tempMemWidth;
        elif tempMemWidth > memWidth:
        elif tempMemWidth > memWidth:
          memWidth = tempMemWidth;
          memWidth = tempMemWidth;
    combined['memWidth'] = memWidth;
    combined['memWidth'] = memWidth;
    # Determine how the memories are packed.
    # Determine how the memories are packed.
    # Note:  "ratio" should be non-unity only for RETURN_STACK.
    # Note:  "ratio" should be non-unity only for RETURN_STACK.
    for port in combined['port']:
    for port in combined['port']:
      lane = 0;
      lane = 0;
      for packing in port['packing']:
      for packing in port['packing']:
        packing['lane'] = lane;
        packing['lane'] = lane;
        ratio = CeilPow2((packing['nbits']+memWidth-1)/memWidth);
        ratio = CeilPow2((packing['nbits']+memWidth-1)/memWidth);
        packing['ratio'] = ratio;
        packing['ratio'] = ratio;
        packing['nWords'] = ratio * packing['length'];
        packing['nWords'] = ratio * packing['length'];
        lane += ratio;
        lane += ratio;
    # Aggregate parameters each memory port.
    # Aggregate parameters each memory port.
    for port in combined['port']:
    for port in combined['port']:
      ratio = CeilPow2(sum(packing['ratio'] for packing in port['packing']));
      ratio = CeilPow2(sum(packing['ratio'] for packing in port['packing']));
      maxLength = max(packing['length'] for packing in port['packing']);
      maxLength = max(packing['length'] for packing in port['packing']);
      port['ratio'] = ratio;
      port['ratio'] = ratio;
      port['nWords'] = ratio * maxLength;
      port['nWords'] = ratio * maxLength;
    combined['port'][0]['offset'] = 0;
    combined['port'][0]['offset'] = 0;
    if len(combined['port']) > 1:
    if len(combined['port']) > 1:
      if combined['mems'][0] == 'INSTRUCTION':
      if combined['mems'][0] == 'INSTRUCTION':
        nWordsTail = combined['port'][1]['nWords'];
        nWordsTail = combined['port'][1]['nWords'];
        port0 = combined['port'][0];
        port0 = combined['port'][0];
        if port0['nWords'] <= nWordsTail:
        if port0['nWords'] <= nWordsTail:
          raise SSBCCException('INSTRUCTION length too small for "COMBINE INSTRUCTION,..." at %s' % combined['loc']);
          raise SSBCCException('INSTRUCTION length too small for "COMBINE INSTRUCTION,..." at %s' % combined['loc']);
        port0['nWords'] -= nWordsTail;
        port0['nWords'] -= nWordsTail;
        port0['packing'][0]['nWords'] -= nWordsTail;
        port0['packing'][0]['nWords'] -= nWordsTail;
        port0['packing'][0]['length'] -= nWordsTail;
        port0['packing'][0]['length'] -= nWordsTail;
      else:
      else:
        maxNWords = max(port['nWords'] for port in combined['port']);
        maxNWords = max(port['nWords'] for port in combined['port']);
        for port in combined['port']:
        for port in combined['port']:
          port['nWords'] = maxNWords;
          port['nWords'] = maxNWords;
      combined['port'][1]['offset'] = combined['port'][0]['nWords'];
      combined['port'][1]['offset'] = combined['port'][0]['nWords'];
    combined['nWords'] = sum(port['nWords'] for port in combined['port']);
    combined['nWords'] = sum(port['nWords'] for port in combined['port']);
 
 
  def ProcessCombine(self,loc,line):
  def ProcessCombine(self,loc,line):
    """
    """
    Parse the "COMBINE" configuration command as follows:\n
    Parse the "COMBINE" configuration command as follows:\n
    Validate the arguments to the "COMBINE" configuration command and append
    Validate the arguments to the "COMBINE" configuration command and append
    the list of combined memories and the associated arguments to "combine"
    the list of combined memories and the associated arguments to "combine"
    property.\n
    property.\n
    The argument consists of one of the following:
    The argument consists of one of the following:
      INSTRUCTION,{DATA_STACK,RETURN_STACK,rom_list}
      INSTRUCTION,{DATA_STACK,RETURN_STACK,rom_list}
      DATA_STACK
      DATA_STACK
      DATA_STACK,{RETURN_STACK,rom_list}
      DATA_STACK,{RETURN_STACK,rom_list}
      RETURN_STACK
      RETURN_STACK
      RETURN_STACK,{DATA_STACK,rom_list}
      RETURN_STACK,{DATA_STACK,rom_list}
      mem_list
      mem_list
    where rom_list is a comma separated list of one or more ROMs and mem_list is
    where rom_list is a comma separated list of one or more ROMs and mem_list is
    a list of one or more RAMs or ROMs.
    a list of one or more RAMs or ROMs.
    """
    """
    # Perform some syntax checking and get the list of memories to combine.
    # Perform some syntax checking and get the list of memories to combine.
    cmd = re.findall(r'\s*COMBINE\s+(\S+)\s*$',line);
    cmd = re.findall(r'\s*COMBINE\s+(\S+)\s*$',line);
    if not cmd:
    if not cmd:
      raise SSBCCException('Malformed COMBINE configuration command on %s' % loc);
      raise SSBCCException('Malformed COMBINE configuration command on %s' % loc);
    mems = re.split(r',',cmd[0]);
    mems = re.split(r',',cmd[0]);
    if (len(mems)==1) and ('INSTRUCTION' in mems):
    if (len(mems)==1) and ('INSTRUCTION' in mems):
      raise SSBCCException('"COMBINE INSTRUCTION" doesn\'t make sense at %s' % loc);
      raise SSBCCException('"COMBINE INSTRUCTION" doesn\'t make sense at %s' % loc);
    if ('INSTRUCTION' in mems) and (mems[0] != 'INSTRUCTION'):
    if ('INSTRUCTION' in mems) and (mems[0] != 'INSTRUCTION'):
      raise SSBCCException('"INSTRUCTION" must be listed first in COMBINE configuration command at %s' % loc);
      raise SSBCCException('"INSTRUCTION" must be listed first in COMBINE configuration command at %s' % loc);
    recognized = ['INSTRUCTION','DATA_STACK','RETURN_STACK'] + self.memories['name'];
    recognized = ['INSTRUCTION','DATA_STACK','RETURN_STACK'] + self.memories['name'];
    unrecognized = [memName for memName in mems if memName not in recognized];
    unrecognized = [memName for memName in mems if memName not in recognized];
    if unrecognized:
    if unrecognized:
      raise SSBCCException('"%s" not recognized in COMBINE configuration command at %s' % (unrecognized[0],loc,));
      raise SSBCCException('"%s" not recognized in COMBINE configuration command at %s' % (unrecognized[0],loc,));
    alreadyUsed = [memName for memName in mems if self.IsCombined(memName)];
    alreadyUsed = [memName for memName in mems if self.IsCombined(memName)];
    if alreadyUsed:
    if alreadyUsed:
      raise SSBCCException('"%s" already used in COMBINE configuration command before %s' % (alreadyUsed[0],loc,));
      raise SSBCCException('"%s" already used in COMBINE configuration command before %s' % (alreadyUsed[0],loc,));
    repeated = [mems[ix] for ix in range(len(mems)-1) if mems[ix] in mems[ix+1]];
    repeated = [mems[ix] for ix in range(len(mems)-1) if mems[ix] in mems[ix+1:]];
    if repeated:
    if repeated:
      raise SSBCCException('"%s" repeated in COMBINE configuration command on %s' % (repeated[0],loc,));
      raise SSBCCException('"%s" repeated in COMBINE configuration command on %s' % (repeated[0],loc,));
    # Count the number of the different memory types being combined and validate the combination.
    # Count the number of the different memory types being combined and validate the combination.
    nSinglePort = sum([thisMemName in ('INSTRUCTION','DATA_STACK','RETURN_STACK',) for thisMemName in mems]);
    nSinglePort = sum([thisMemName in ('INSTRUCTION','DATA_STACK','RETURN_STACK',) for thisMemName in mems]);
    nROM = len([thisMemName for thisMemName in mems if self.IsROM(thisMemName)]);
    nROM = len([thisMemName for thisMemName in mems if self.IsROM(thisMemName)]);
    nRAM = len([thisMemName for thisMemName in mems if self.IsRAM(thisMemName)]);
    nRAM = len([thisMemName for thisMemName in mems if self.IsRAM(thisMemName)]);
    if nRAM > 0:
    if nRAM > 0:
      nRAM += nROM;
      nRAM += nROM;
      nROM = 0;
      nROM = 0;
    if nROM > 0:
    if nROM > 0:
      nSinglePort += 1;
      nSinglePort += 1;
    nDualPort = 1 if nRAM > 0 else 0;
    nDualPort = 1 if nRAM > 0 else 0;
    if nSinglePort + 2*nDualPort > 2:
    if nSinglePort + 2*nDualPort > 2:
      raise SSBCCException('Too many ports required for COMBINE configuration command at %s' % loc);
      raise SSBCCException('Too many ports required for COMBINE configuration command at %s' % loc);
    # Append the listed memory types to the list of combined memories.
    # Append the listed memory types to the list of combined memories.
    self.config['combine'].append({'mems':mems, 'memArch':'sync', 'loc':loc});
    self.config['combine'].append({'mems':mems, 'memArch':'sync', 'loc':loc});
 
 
  def ProcessInport(self,loc,line):
  def ProcessInport(self,loc,line):
    """
    """
    Parse the "INPORT" configuration commands as follows:
    Parse the "INPORT" configuration commands as follows:
      The configuration command is well formatted.
      The configuration command is well formatted.
      The number of signals matches the corresponding list of signal declarations.
      The number of signals matches the corresponding list of signal declarations.
      The port name starts with 'I_'.
      The port name starts with 'I_'.
      The signal declarations are valid.
      The signal declarations are valid.
        n-bit where n is an integer
        n-bit where n is an integer
        set-reset
        set-reset
        strobe
        strobe
      That no other signals are specified in conjunction with a "set-reset" signal.
      That no other signals are specified in conjunction with a "set-reset" signal.
      The total input data with does not exceed the maximum data width.\n
      The total input data with does not exceed the maximum data width.\n
    The input port is appended to the list of inputs as a tuple.  The first
    The input port is appended to the list of inputs as a tuple.  The first
    entry in the tuple is the port name.  The subsequent entries are tuples
    entry in the tuple is the port name.  The subsequent entries are tuples
    consisting of the following:
    consisting of the following:
      signal name
      signal name
      signal width
      signal width
      signal type
      signal type
    """
    """
    cmd = re.findall(r'\s*INPORT\s+(\S+)\s+(\S+)\s+(I_\w+)\s*$',line);
    cmd = re.findall(r'\s*INPORT\s+(\S+)\s+(\S+)\s+(I_\w+)\s*$',line);
    if not cmd:
    if not cmd:
      raise SSBCCException('Malformed INPORT statement at %s: "%s"' % (loc,line[:-1],));
      raise SSBCCException('Malformed INPORT statement at %s: "%s"' % (loc,line[:-1],));
    modes = re.findall(r'([^,]+)',cmd[0][0]);
    modes = re.findall(r'([^,]+)',cmd[0][0]);
    names = re.findall(r'([^,]+)',cmd[0][1]);
    names = re.findall(r'([^,]+)',cmd[0][1]);
    portName = cmd[0][2];
    portName = cmd[0][2];
    if len(modes) != len(names):
    if len(modes) != len(names):
      raise SSBCCException('Malformed INPORT configuration command -- number of options don\'t match on %s: "%s"' % (loc,line[:-1],));
      raise SSBCCException('Malformed INPORT configuration command -- number of options don\'t match on %s: "%s"' % (loc,line[:-1],));
    # Append the input signal names, mode, and bit-width to the list of I/Os.
    # Append the input signal names, mode, and bit-width to the list of I/Os.
    has__set_reset = False;
    has__set_reset = False;
    nBits = 0;
    nBits = 0;
    thisPort = (portName,);
    thisPort = (portName,);
    for ix in range(len(names)):
    for ix in range(len(names)):
      if re.match(r'^\d+-bit$',modes[ix]):
      if re.match(r'^\d+-bit$',modes[ix]):
        thisNBits = int(modes[ix][0:-4]);
        thisNBits = int(modes[ix][0:-4]);
        self.AddIO(names[ix],thisNBits,'input',loc);
        self.AddIO(names[ix],thisNBits,'input',loc);
        thisPort += ((names[ix],thisNBits,'data',),);
        thisPort += ((names[ix],thisNBits,'data',),);
        nBits = nBits + thisNBits;
        nBits = nBits + thisNBits;
      elif modes[ix] == 'set-reset':
      elif modes[ix] == 'set-reset':
        has__set_reset = True;
        has__set_reset = True;
        self.AddIO(names[ix],1,'input',loc);
        self.AddIO(names[ix],1,'input',loc);
        thisPort += ((names[ix],1,'set-reset',),);
        thisPort += ((names[ix],1,'set-reset',),);
        self.AddSignal('s_SETRESET_%s' % names[ix],1,loc);
        self.AddSignal('s_SETRESET_%s' % names[ix],1,loc);
      elif modes[ix] == 'strobe':
      elif modes[ix] == 'strobe':
        self.AddIO(names[ix],1,'output',loc);
        self.AddIO(names[ix],1,'output',loc);
        thisPort += ((names[ix],1,'strobe',),);
        thisPort += ((names[ix],1,'strobe',),);
      else:
      else:
        raise SSBCCException('Unrecognized INPORT signal type "%s"' % modes[ix]);
        raise SSBCCException('Unrecognized INPORT signal type "%s"' % modes[ix]);
      if has__set_reset and len(names) > 1:
      if has__set_reset and len(names) > 1:
        raise SSBCCException('set-reset cannot be simultaneous with other signals in "%s"' % line[:-1]);
        raise SSBCCException('set-reset cannot be simultaneous with other signals in "%s"' % line[:-1]);
      if nBits > self.Get('data_width'):
      if nBits > self.Get('data_width'):
        raise SSBCCException('Signal width too wide in "%s"' % line[:-1]);
        raise SSBCCException('Signal width too wide in "%s"' % line[:-1]);
    self.AddInport(thisPort,loc);
    self.AddInport(thisPort,loc);
 
 
  def ProcessOutport(self,line,loc):
  def ProcessOutport(self,line,loc):
    """
    """
    Parse the "OUTPORT" configuration commands as follows:
    Parse the "OUTPORT" configuration commands as follows:
      The configuration command is well formatted.
      The configuration command is well formatted.
      The number of signals matches the corresponding list of signal declarations.
      The number of signals matches the corresponding list of signal declarations.
      The port name starts with 'O_'.
      The port name starts with 'O_'.
      The signal declarations are valid.
      The signal declarations are valid.
        n-bit[=value]
        n-bit[=value]
        strobe
        strobe
      The total output data with does not exceed the maximum data width.\n
      The total output data with does not exceed the maximum data width.\n
    The output port is appended to the list of outports as a tuple.  The first
    The output port is appended to the list of outports as a tuple.  The first
    entry in this tuple is the port name.  The subsequent entries are tuples
    entry in this tuple is the port name.  The subsequent entries are tuples
    consisting of the following:
    consisting of the following:
      signal name
      signal name
      signal width
      signal width
      signal type
      signal type
      initial value (optional)
      initial value (optional)
    """
    """
    cmd = re.findall(r'^\s*OUTPORT\s+(\S+)\s+(\S+)\s+(O_\w+)\s*$',line);
    cmd = re.findall(r'^\s*OUTPORT\s+(\S+)\s+(\S+)\s+(O_\w+)\s*$',line);
    if not cmd:
    if not cmd:
      raise SSBCCException('Malformed OUTPUT configuration command on %s: "%s"' % (loc,line[:-1],));
      raise SSBCCException('Malformed OUTPUT configuration command on %s: "%s"' % (loc,line[:-1],));
    modes = re.findall(r'([^,]+)',cmd[0][0]);
    modes = re.findall(r'([^,]+)',cmd[0][0]);
    names = re.findall(r'([^,]+)',cmd[0][1]);
    names = re.findall(r'([^,]+)',cmd[0][1]);
    portName = cmd[0][2];
    portName = cmd[0][2];
    if len(modes) != len(names):
    if len(modes) != len(names):
      raise SSBCCException('Malformed OUTPORT configuration command -- number of widths/types and signal names don\'t match on %s: "%s"' % (loc,line[:-1],));
      raise SSBCCException('Malformed OUTPORT configuration command -- number of widths/types and signal names don\'t match on %s: "%s"' % (loc,line[:-1],));
    # Append the input signal names, mode, and bit-width to the list of I/Os.
    # Append the input signal names, mode, and bit-width to the list of I/Os.
    nBits = 0;
    nBits = 0;
    isStrobeOnly = True;
    isStrobeOnly = True;
    thisPort = tuple();
    thisPort = tuple();
    for ix in range(len(names)):
    for ix in range(len(names)):
      if re.match(r'\d+-bit',modes[ix]):
      if re.match(r'\d+-bit',modes[ix]):
        isStrobeOnly = False;
        isStrobeOnly = False;
        a = re.match(r'(\d+)-bit(=\S+)?$',modes[ix]);
        a = re.match(r'(\d+)-bit(=\S+)?$',modes[ix]);
        if not a:
        if not a:
          raise SSBCCException('Malformed bitwith/bitwidth=initialization on %s:  "%s"' % (loc,modes[ix],));
          raise SSBCCException('Malformed bitwith/bitwidth=initialization on %s:  "%s"' % (loc,modes[ix],));
        thisNBits = int(a.group(1));
        thisNBits = int(a.group(1));
        self.AddIO(names[ix],thisNBits,'output',loc);
        self.AddIO(names[ix],thisNBits,'output',loc);
        if a.group(2):
        if a.group(2):
          thisPort += ((names[ix],thisNBits,'data',a.group(2)[1:],),);
          thisPort += ((names[ix],thisNBits,'data',a.group(2)[1:],),);
        else:
        else:
          thisPort += ((names[ix],thisNBits,'data',),);
          thisPort += ((names[ix],thisNBits,'data',),);
        nBits = nBits + thisNBits;
        nBits = nBits + thisNBits;
        self.config['haveBitOutportSignals'] = 'True';
        self.config['haveBitOutportSignals'] = 'True';
      elif modes[ix] == 'strobe':
      elif modes[ix] == 'strobe':
        self.AddIO(names[ix],1,'output',loc);
        self.AddIO(names[ix],1,'output',loc);
        thisPort += ((names[ix],1,'strobe',),);
        thisPort += ((names[ix],1,'strobe',),);
      else:
      else:
        raise SSBCCException('Unrecognized OUTPORT signal type on %s: "%s"' % (loc,modes[ix],));
        raise SSBCCException('Unrecognized OUTPORT signal type on %s: "%s"' % (loc,modes[ix],));
      if nBits > 8:
      if nBits > 8:
        raise SSBCCException('Signal width too wide on %s:  in "%s"' % (loc,line[:-1],));
        raise SSBCCException('Signal width too wide on %s:  in "%s"' % (loc,line[:-1],));
    self.AddOutport((portName,isStrobeOnly,)+thisPort,loc);
    self.AddOutport((portName,isStrobeOnly,)+thisPort,loc);
 
 
  def ProcessPeripheral(self,loc,line):
  def ProcessPeripheral(self,loc,line):
    """
    """
    Process the "PERIPHERAL" configuration command as follows:
    Process the "PERIPHERAL" configuration command as follows:
      Validate the format of the configuration command.
      Validate the format of the configuration command.
      Find the peripheral in the candidate list of paths for peripherals.
      Find the peripheral in the candidate list of paths for peripherals.
      Execute the file declaring the peripheral.
      Execute the file declaring the peripheral.
        Note:  This is done since I couldn't find a way to "import" the
        Note:  This is done since I couldn't find a way to "import" the
               peripheral.  Executing the peripheral makes its definition local
               peripheral.  Executing the peripheral makes its definition local
               to this invokation of the ProcessPeripheral function, but the
               to this invokation of the ProcessPeripheral function, but the
               object subsequently created retains the required functionality
               object subsequently created retains the required functionality
               to instantiate the peripheral
               to instantiate the peripheral
      Go through the parameters for the peripheral and do the following for each:
      Go through the parameters for the peripheral and do the following for each:
        If the argument for the peripheral is the string "help", then print the
        If the argument for the peripheral is the string "help", then print the
          docstring for the peripheral and exit.
          docstring for the peripheral and exit.
        Append the parameter name and its argument to the list of parameters
        Append the parameter name and its argument to the list of parameters
          (use "None" as the argument if no argument was provided).
          (use "None" as the argument if no argument was provided).
      Append the instantiated peripheral to the list of peripherals.
      Append the instantiated peripheral to the list of peripherals.
        Note:  The "exec" function dynamically executes the instruction to
        Note:  The "exec" function dynamically executes the instruction to
               instantiate the peripheral and append it to the list of
               instantiate the peripheral and append it to the list of
               peripherals.
               peripherals.
    """
    """
    # Validate the format of the peripheral configuration command and the the name of the peripheral.
    # Validate the format of the peripheral configuration command and the the name of the peripheral.
    cmd = re.findall(r'\s*PERIPHERAL\s+(\w+)\s*(.*)$',line);
    cmd = re.findall(r'\s*PERIPHERAL\s+(\w+)\s*(.*)$',line);
    if not cmd:
    if not cmd:
      raise SSBCCException('Missing peripheral name in %s:  %s' % (loc,line[:-1],));
      raise SSBCCException('Missing peripheral name in %s:  %s' % (loc,line[:-1],));
    peripheral = cmd[0][0];
    peripheral = cmd[0][0];
    # Find and execute the peripheral Python script.
    # Find and execute the peripheral Python script.
    # Note:  Because "execfile" and "exec" method are used to load the
    # Note:  Because "execfile" and "exec" method are used to load the
    #        peripheral python script, the __file__ object is set to be this
    #        peripheral python script, the __file__ object is set to be this
    #        file, not the peripheral source file.
    #        file, not the peripheral source file.
    for testPath in self.peripheralpaths:
    for testPath in self.peripheralpaths:
      fullperipheral = os.path.join(testPath,'%s.py' % peripheral);
      fullperipheral = os.path.join(testPath,'%s.py' % peripheral);
      if os.path.isfile(fullperipheral):
      if os.path.isfile(fullperipheral):
        break;
        break;
    else:
    else:
      raise SSBCCException('Peripheral "%s" not found' % peripheral);
      raise SSBCCException('Peripheral "%s" not found' % peripheral);
    execfile(fullperipheral);
    execfile(fullperipheral);
    # Convert the space delimited parameters to a list of tuples.
    # Convert the space delimited parameters to a list of tuples.
    param_list = list();
    param_list = list();
    for param_string in re.findall(r'(\w+="[^"]*"|\w+=\S+|\w+)\s*',cmd[0][1]):
    for param_string in re.findall(r'(\w+="[^"]*"|\w+=\S+|\w+)\s*',cmd[0][1]):
      if param_string == "help":
      if param_string == "help":
        exec('helpmsg = %s.__doc__' % peripheral);
        exec('helpmsg = %s.__doc__' % peripheral);
        if not helpmsg:
        if not helpmsg:
          raise SSBCCException('No help for peripheral %s is provided' % fullperipheral);
          raise SSBCCException('No help for peripheral %s is provided' % fullperipheral);
        print;
        print;
        print 'Help message for peripheral:  %s' % peripheral;
        print 'Help message for peripheral:  %s' % peripheral;
        print 'Located at:  %s' % fullperipheral;
        print 'Located at:  %s' % fullperipheral;
        print;
        print;
        print helpmsg;
        print helpmsg;
        raise SSBCCException('Terminated by "help" for peripheral %s' % peripheral);
        raise SSBCCException('Terminated by "help" for peripheral %s' % peripheral);
      ix = param_string.find('=');
      ix = param_string.find('=');
      if param_string.find('="') > 0:
      if param_string.find('="') > 0:
        param_list.append((param_string[:ix],param_string[ix+2:-1],));
        param_list.append((param_string[:ix],param_string[ix+2:-1],));
      elif param_string.find('=') > 0:
      elif param_string.find('=') > 0:
        param_list.append((param_string[:ix],param_string[ix+1:],));
        param_list.append((param_string[:ix],param_string[ix+1:],));
      else:
      else:
        param_list.append((param_string,None));
        param_list.append((param_string,None));
    # Add the peripheral to the micro controller configuration.
    # Add the peripheral to the micro controller configuration.
    exec('self.peripheral.append(%s(fullperipheral,self,param_list,loc));' % peripheral);
    exec('self.peripheral.append(%s(fullperipheral,self,param_list,loc));' % peripheral);
 
 
  def Set(self,name,value):
  def Set(self,name,value):
    """
    """
    Create or override the specified attribute in the ssbccConfig object.
    Create or override the specified attribute in the ssbccConfig object.
    """
    """
    self.config[name] = value;
    self.config[name] = value;
 
 
  def SetMemoryBlock(self,name,value,errorInfo):
  def SetMemoryBlock(self,name,value,errorInfo):
    """
    """
    Set an attribute in the ssbccConfig object for the specified memory with
    Set an attribute in the ssbccConfig object for the specified memory with
    the specified memory architecture.\n
    the specified memory architecture.\n
    "value" must be a string with the format "\d+" or "\d+*\d+" where "\d+" is
    "value" must be a string with the format "\d+" or "\d+*\d+" where "\d+" is
    an integer.  The first format specifies a single memory with the stated
    an integer.  The first format specifies a single memory with the stated
    size and the size must be a power of two.  The second format specified
    size and the size must be a power of two.  The second format specified
    allocation of multiple memory blocks where the size is given by the first
    allocation of multiple memory blocks where the size is given by the first
    integer and must be a power of 2 and the number of blocks is given by the
    integer and must be a power of 2 and the number of blocks is given by the
    second integer and doesn't need to be a power of 2.
    second integer and doesn't need to be a power of 2.
    """
    """
    findStar = value.find('*');
    findStar = value.find('*');
    if findStar == -1:
    if findStar == -1:
      blockSize = int(value);
      blockSize = int(value);
      nBlocks = 1;
      nBlocks = 1;
    else:
    else:
      blockSize = int(value[0:findStar]);
      blockSize = int(value[0:findStar]);
      nBlocks = int(value[findStar+1:]);
      nBlocks = int(value[findStar+1:]);
    nbits_blockSize = int(round(math.log(blockSize,2)));
    nbits_blockSize = int(round(math.log(blockSize,2)));
    if blockSize != 2**nbits_blockSize:
    if blockSize != 2**nbits_blockSize:
      raise SSBCCException('block size must be a power of 2 at %s: "%s"' % errorInfo);
      raise SSBCCException('block size must be a power of 2 at %s: "%s"' % errorInfo);
    nbits_nBlocks = CeilLog2(nBlocks);
    nbits_nBlocks = CeilLog2(nBlocks);
    self.Set(name, dict(
    self.Set(name, dict(
                   length=blockSize*nBlocks,
                   length=blockSize*nBlocks,
                   nbits=nbits_blockSize+nbits_nBlocks,
                   nbits=nbits_blockSize+nbits_nBlocks,
                   blockSize=blockSize,
                   blockSize=blockSize,
                   nbits_blockSize=nbits_blockSize,
                   nbits_blockSize=nbits_blockSize,
                   nBlocks=nBlocks,
                   nBlocks=nBlocks,
                   nbits_nBlocks=nbits_nBlocks));
                   nbits_nBlocks=nbits_nBlocks));
 
 
  def SetMemoryParameters(self,memParam,values):
  def SetMemoryParameters(self,memParam,values):
    """
    """
    Record the body of the specified memory based on the assembler output.
    Record the body of the specified memory based on the assembler output.
    """
    """
    index = memParam['index'];
    index = memParam['index'];
    for field in values:
    for field in values:
      if field not in self.memories:
      if field not in self.memories:
        self.memories[field] = list();
        self.memories[field] = list();
        for ix in range(len(self.memories['name'])):
        for ix in range(len(self.memories['name'])):
          self.memories[field].append(None);
          self.memories[field].append(None);
      self.memories[field][index] = values[field];
      self.memories[field][index] = values[field];
 
 
  def SignalLengthList(self):
  def SignalLengthList(self):
    """
    """
    Generate a list of the I/O signals and their lengths.
    Generate a list of the I/O signals and their lengths.
    """
    """
    outlist = list();
    outlist = list();
    for io in self.ios:
    for io in self.ios:
      if io[2] == 'comment':
      if io[2] == 'comment':
        continue;
        continue;
      outlist.append((io[0],io[1],));
      outlist.append((io[0],io[1],));
    return outlist;
    return outlist;
 
 

powered by: WebSVN 2.1.0

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