#!@pathpython@ # -*- python -*- # Copyright (c) 2005-2006 Arched Rock Corporation # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # - Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # - Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the # distribution. # - Neither the name of the Arched Rock Corporation nor the names of # its contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # ARCHED ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE # # Copyright (c) 2006-2007 Intel Corporation # All rights reserved. # # This file is distributed under the terms in the attached INTEL-LICENSE # file. If you do not find these files, copies can be found by writing to # Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, # 94704. Attention: Intel License Inquiry. # @author Jonathan Hui # @author David Gay # @author Kevin Klues # @author R. Steve McKown # # $Revision$ # $Date$ # from __future__ import with_statement # Does this require too new a python? import os import re from re import match from sys import * from xml.dom import * from xml.dom.minidom import * from subprocess import Popen, PIPE from getopt import * import string import commands #New way of handling arguments........ try: opts, args = getopt(argv[1:], "t", []) except GetoptError, err: print str(err) # will print something like "option -a not recognized" stderr.write( "Usage: tos-storage-stm25p [-t] \n" ) if len( args ) == 1: platformdir = args[0] platform = os.path.basename(platformdir) # In case platformdir was specified with a trailing path separator if not platform: platformdir = os.path.dirname(platformdir) platform = os.path.basename(platformdir) familydir = os.path.dirname(platformdir) if familydir and not os.path.isfile(os.path.join(familydir, '.family')): familydir = "" elif len( args ) == 0: platformdir = "" platform = "" familydir = "" else: stderr.write( "Usage: tos-storage-stm25p [-t] \n" ) cthreads = False for o, a in opts: if o == "-t": cthreads = True else: assert False, "unhandled option" def error_exit( s ): stderr.write( "ERROR: " + s + "\n" ) exit( 2 ) def expand_path( path ): substrs = path.split( "%" ) path = substrs[0] i = 1 while i < len( substrs ): if substrs[i] == "": # There was a %%, leading to a blank substring, and the next string # should just be appended path += "%" i = i + 1 if i < len( substrs ): path += substrs[i] else: # The first character of the string is the one that followed % c = substrs[i][0] if c == 'p': sub = platform elif c == 'P': sub = platformdir elif c == 'F': if not familydir: nfail( "invalid include-path substitution character " + c + "; " + \ platform + " not in a family" ) sub = familydir elif c == 'T': sub = Popen( ["ncc", "-print-tosdir"], stdout=PIPE ).communicate( )[0] sub = sub[:-1] # remove newline else: nfail( "unknown include-path substitution character " + c ) path += sub path += substrs[i][1:] i = i + 1 return path HEADER_FILE = 'Stm25p.h' NUM_SECTORS = 0 SECTOR_SIZE = 0 def parseHeader( dotfile ): """ Return an ordered list of paths from the dotfile """ paths = [] inArray = False p = re.compile('push\s*\(\s*@includes,\s*qw\s*\('); q = re.compile('\)\s*\)\s*;'); try: with open(dotfile, 'r') as file: for line in file: path = line.strip() if path: if p.match(path): inArray = True elif q.match(path): inArray = False elif inArray == True: paths.append(path) return paths except: return [] def findFile( paths, filename ): """ Find the first occurrence of 'filename' in the list of paths given. """ for path in paths: rpath = expand_path(path) try: for file in os.listdir(rpath): if file == filename: return rpath + '/' + filename except OSError: None return None def findVars( path, vars ): """ Finds values for the variables already present in vars from path """ inEnum = False p = re.compile('enum\s.*{'); q = re.compile('}s*;'); r = re.compile('^\s*([A-Z0-9_]*)\s*=\s*([^,]*)'); with open(path, 'r') as file: for line in file: line = line.strip() if line: if p.match(line): inEnum = True elif q.match(line): inEnum = False elif inEnum == True: m = r.search(line) if vars.has_key(m.group(1)): vars[m.group(1)] = m.group(2) paths = parseHeader(os.path.join(familydir, '.family')) + \ parseHeader(os.path.join(platformdir, '.platform')) if paths: path = findFile(paths, HEADER_FILE) if path: enums = {} enums["STM25P_NUM_SECTORS"] = 0 enums["STM25P_SECTOR_SIZE_LOG2"] = 0 findVars(path, enums) NUM_SECTORS = int(enums["STM25P_NUM_SECTORS"]) SECTOR_SIZE = 2**int(enums["STM25P_SECTOR_SIZE_LOG2"]) if NUM_SECTORS == 0 or SECTOR_SIZE == 0: stderr.write( "tos-storage-stm25p: no valid Stm25p.h found.\n\t" "Check @includes in the platform's .platform file\n" ) exit(2) volumes = {} volumeNames = [] volumeSizes = [] volumeOffsets = [] volumeTypes = dict() volumeOptions = dict() freeSectors = NUM_SECTORS*[ True ] def volumeparse( file, fname, depth ): if depth > 10: error_exit( "include nesting too deep - check for cycles" ) try: dom = parse( file ) except xml.parsers.expat.ExpatError: error_exit( fname + " is not a valid input file" ) except IOError: error_exit( "couldn't open file " + fname ) # extract information for volume in dom.documentElement.getElementsByTagName( "volume" ): name = volume.getAttribute( "name" ) size = volume.getAttribute( "size" ) base = volume.getAttribute( "base" ) type = string.lower(volume.getAttribute("type")) isCircular = string.upper(volume.getAttribute("circular")) if isCircular == "": isCircular = "FALSE" if name == "": error_exit( "volume has no name" ) elif not match( "^[a-zA-Z0-9_]+$", name ): error_exit( "volume has invalid name '%s'" % name ) elif volumes.has_key( name ): error_exit( "duplicate volume definition '%s'" % name ) else: volumes[ name ] = "blah" if size == "": error_exit( "volume '%s' has no size" % name ) try: size = int( size ) except ValueError: error_exit( "volume '%s' has invalid size" % name ) if base != "": try: base = int( base ) except ValueError: error_exit( "volume '%s' has invalid base" % name ) if ( size & ( SECTOR_SIZE - 1 ) ) != 0: error_exit( "size of volume '%s' is not a multiple of %d" % \ ( name, SECTOR_SIZE ) ) if base != "" and ( base & ( SECTOR_SIZE - 1 ) ) != 0: error_exit( "base of volume '%s' is not a multiple of %d" % \ ( name, SECTOR_SIZE ) ) volumeNames.append( "VOLUME_" + name ) volumeSizes.append( size / SECTOR_SIZE ) volumeTypes["VOLUME_" + name] = type volumeOptions["VOLUME_" + name] = isCircular if base == "": volumeOffsets.append( -1 ) else: base = base / SECTOR_SIZE size = size / SECTOR_SIZE volumeOffsets.append( base ) for i in range( size ): freeSectors[ i + base ] = False for include in dom.documentElement.getElementsByTagName( "include" ): included = include.firstChild if included != None and included.nodeType == included.TEXT_NODE: included = expand_path( included.data ) volumeparse( included, "(file %s)" % included, depth + 1 ) else: error_exit( "invalid include directive " + fname ) dom.unlink( ) volumeparse( stdin, "(standard input)", 0 ) # allocate with first fit policy for i in range( len( volumeOffsets ) ): size = volumeSizes[ i ] if volumeOffsets[ i ] == -1: for j in range( NUM_SECTORS ): if freeSectors[ j ]: size -= 1 if size == 0: volumeOffsets[ i ] = j - ( volumeSizes[ i ] - 1 ) break else: size = volumeSizes[ i ] if volumeOffsets[ i ] == -1: raise "Unable to satisfy allocation request." else: for j in range( volumeSizes[ i ] ): freeSectors[ volumeOffsets[ i ] + j ] = False # output C file print "#ifndef __STORAGE_VOLUME_H__" print "#define __STORAGE_VOLUME_H__" print "" print "#include \"Stm25p.h\"" print "" for i in range( len( volumeNames ) ): print "#define %s %d" % ( volumeNames[ i ], i ) print "" print "static const stm25p_volume_info_t STM25P_VMAP[ %d ] = {" % \ len( volumeNames ) for i in range( len( volumeNames ) ): print " { base : %d, size : %d }," % \ ( volumeOffsets[ i ], volumeSizes[ i ] ) print "};" print "" print "#endif" # output nc file for threads if cthreads == True: outFile = open(commands.getstatusoutput("pwd")[1] + "/VolumeMapC.nc", "w") outFile.write("#include \"StorageVolumes.h\" \n") outFile.write("\n") outFile.write("configuration VolumeMapC { \n") outFile.write(" provides { \n") outFile.write(" interface BlockRead[uint8_t volume_id]; \n") outFile.write(" interface BlockWrite[uint8_t volume_id]; \n") outFile.write(" interface LogRead[uint8_t volumeId]; \n") outFile.write(" interface LogWrite[uint8_t volumeId]; \n") outFile.write(" interface Mount[uint8_t volumeId]; \n") outFile.write(" interface ConfigStorage[uint8_t volumeId]; \n") outFile.write(" } \n") outFile.write("} \n") outFile.write("\n") outFile.write("implementation { \n") outFile.write(" components VolumeMapP; \n") outFile.write("\n") outFile.write(" BlockRead = VolumeMapP; \n") outFile.write(" BlockWrite = VolumeMapP; \n") outFile.write(" LogRead = VolumeMapP; \n") outFile.write(" LogWrite = VolumeMapP; \n") outFile.write(" Mount = VolumeMapP; \n") outFile.write(" ConfigStorage = VolumeMapP; \n") for i in range(len(volumeNames)): if volumeTypes[volumeNames[i]] == "block": outFile.write("\n") outFile.write(" components new BlockStorageC(" + volumeNames[i] + ") as BlockStorageC_" + volumeNames[i] + "; \n") outFile.write(" VolumeMapP.SubBlockRead[" + volumeNames[i] + "] -> BlockStorageC_" + volumeNames[i] + "; \n") outFile.write(" VolumeMapP.SubBlockWrite[" + volumeNames[i] + "] -> BlockStorageC_" + volumeNames[i] + "; \n") outFile.write("\n") elif volumeTypes[volumeNames[i]] == "log": outFile.write("\n") outFile.write(" components new LogStorageC(" + volumeNames[i] + ", " + volumeOptions[volumeNames[i]] + ") as LogStorageC_" + volumeNames[i] + "; \n") outFile.write(" VolumeMapP.SubLogRead[" + volumeNames[i] + "] -> LogStorageC_" + volumeNames[i] + "; \n") outFile.write(" VolumeMapP.SubLogWrite[" + volumeNames[i] + "] -> LogStorageC_" + volumeNames[i] + "; \n") outFile.write("\n") elif volumeTypes[volumeNames[i]] == "config": outFile.write(" components new ConfigStorageC(" + volumeNames[i] + ") as ConfigStorageC_" + volumeNames[i] + "; \n") outFile.write(" Mount[" + volumeNames[i] + "] = ConfigStorageC_" + volumeNames[i] + "; \n") outFile.write(" ConfigStorage[" + volumeNames[i] + "] = ConfigStorageC_" + volumeNames[i] + "; \n") outFile.write("} \n")