#!/usr/bin/env python

##########################################################################################
#  File   : genarch.py
#  Date   : 2016
#  Author : Alain Greiner
#  Copyright (c)  UPMC Sorbonne Universites
#########################################################################################
# This python script generates the "arch_info.bin" file required by the ALMOS-MK
# operating system bootloader and describing the target hardware architecture.
# It uses an architecture specific, python script that must be called "arch_info.py".
#
# The source directory containing the "arch_info.py" file and the destination directory
# to store the "arch_info.bin" file are defined by parameters on the command line:
#  --arch=string     : path to directory containing the "arch_info.py" file
#  --bin=string      : path to directory store the "arch_info.bin" file
#
# As the target architecture is generic, the following hardware parameters can be
# defined on the command line:
#  --x_size=int      : number of clusters in a row
#  --y_size=int      : number of clusters in a column
#  --nb_cores=int    : number of cores per cluster
#  --nb_ttys=int     : number of TTY channels 
#  --nb_nics=int     : number of NIC channels 
#  --nb_cmas=int     : number of CMA channels
#  --fbf_size=int    : frame buffer width & heigth
#  --ioc_type=string : can be IOC_BDV , IOC_HBA , IOC_SDC , IOC_SPI
#  --mwr_type=string : can be MWR_GCD , MWR_DCT , MWR_CPY
#  --io_cxy=int      : IO cluster identifier
#  --boot_cxy=int    : boot cluster identifier
#  --cache_line=int  : number of bytes in a cache line
#
# The following parameters can be used to generate the optional "hard_config.h" file,
# that is required to configurate the SystemC virtual prototype, and the "arch_info.xml" 
# file for debug.
#  --hard=string     : path to directory to store the "hard_config.h" file
#  --xml=string      : path to directory to store the "arch_info.xml" file
#
#########################################################################################

import sys

from arch_classes import *
from optparse import OptionParser

###################################################################################
#   define command line arguments   
###################################################################################

parser = OptionParser()

parser.add_option( '--arch', type = 'string', dest = 'arch_path',
                   help = 'define pathname to directory containing arch_info.py file' )

parser.add_option( '--bin', type = 'string', dest = 'bin_path',
                   help = 'define pathname to directory to store arch_info.bin file' )

parser.add_option( '--x_size', type = 'int', dest = 'x_size', 
                   default = 2,
                   help = 'define number of clusters in a row' )

parser.add_option( '--y_size', type = 'int', dest = 'y_size', 
                   default = 2,
                   help = 'define number of clusters in a column' )

parser.add_option( '--nb_cores', type = 'int', dest = 'nb_cores', 
                   default = 2,
                   help = 'define number of cores per cluster' )

parser.add_option( '--nb_ttys', type = 'int', dest = 'nb_ttys', 
                   default = 1,
                   help = 'define number of TTY channels' )

parser.add_option( '--nb_nics', type = 'int', dest = 'nb_nics',
                   default = 1,
                   help = 'define number ot NIC channels' )

parser.add_option( '--nb_cmas', type = 'int', dest = 'nb_cmas',
                   default = 2,
                   help = 'define number ot CMA channels' )

parser.add_option( '--fbf_size', type = 'int', dest = 'fbf_size', 
                   default = 128,
                   help = 'define frame buffer width and heigth' )

parser.add_option( '--ioc_type', type = 'string', dest = 'ioc_type',
                   default = 'IOC_BDV',
                   help = 'define type of IOC: BDV / HBA / SDC / RDK / SPI' )

parser.add_option( '--mwr_type', type = 'string', dest = 'mwr_type',
                   default = 'MWR_CPY',
                   help = 'define type of COPROC: CPY / DCT / GCD' )

parser.add_option( '--io_cxy', type = 'int', dest = 'io_cxy',
                   default = 0,
                   help = 'define IO cluster identifier' )

parser.add_option( '--boot_cxy', type = 'int', dest = 'boot_cxy',
                   default = 0,
                   help = 'define boot cluster identifier' )

parser.add_option( '--cache_line', type = 'int', dest = 'cache_line',
                   default = 64,
                   help = 'define number of bytes in a cache line' )

parser.add_option( '--hard', type = 'string', dest = 'hard_path',
                   help = 'define pathname to directory for the hard_config.h file ' )

parser.add_option( '--xml', type = 'string', dest = 'xml_path', 
                   help = 'define pathname to directory for the arch_info.xml file' )

parser.add_option( '--v', action = 'store_true', dest = 'verbose',
                   default = False,
                   help = 'display detailed report on arch_info.bin generation' )

###################################################################################
#   Get command line arguments
###################################################################################

(options,args) = parser.parse_args()

arch_path      = options.arch_path   # path to arch_info.py file
bin_path       = options.bin_path    # path for arch_info.bin file

x_size         = options.x_size      # number of clusters in a row
y_size         = options.y_size      # number of clusters in a column
nb_cores       = options.nb_cores    # number of cores in a cluster
nb_ttys        = options.nb_ttys     # number of TTY channels           
fbf_size       = options.fbf_size    # frame buffer width & heigth
nb_nics        = options.nb_nics     # number of NIC channels           
nb_cmas        = options.nb_cmas     # number of CMA channels           
ioc_type       = options.ioc_type    # ioc controller type
mwr_type       = options.mwr_type    # hardware coprocessor type
io_cxy         = options.io_cxy      # IO cluster identifier 
boot_cxy       = options.boot_cxy    # boot cluster identifier 
cache_line     = options.cache_line  # number of bytes in a cache line

hard_path      = options.hard_path   # path for hard_config.h file
xml_path       = options.xml_path    # path for arch_info.xml file     

verbose        = options.verbose     # report on arch_info.bin generation


###################################################################################
#   Build the archinfo structure for the selected arch_info.py
###################################################################################

if   ( arch_path == None  ):  
    print 'You must define a path to the arch_info.py file on command line' 
    sys.exit(1)

# dynamically append arch_path to PYTHONPATH
sys.path.append( arch_path )

# import the arch_info.py module (using file name without suffix)
select = __import__( 'arch_info' )
print select

# build the arch_info structure by calling the arch function
archinfo = select.arch( x_size,
                        y_size, 
                        nb_cores,
                        nb_ttys, 
                        nb_nics, 
                        nb_cmas, 
                        fbf_size, 
                        ioc_type, 
                        mwr_type,
                        io_cxy,
                        boot_cxy,
                        cache_line )

print '[genarch] archinfo build for %s' % archinfo.name 

###################################################################################
#   Generate arch_info.xml file if required.
###################################################################################

if ( xml_path != None ):
    pathname = xml_path + '/arch_info.xml'
    f = open ( pathname, 'w' )
    f.write( archinfo.xml() )

    print '[genarch] %s generated' % pathname

###################################################################################
#   Generate arch_info.bin file if required.
###################################################################################

if ( bin_path != None ):
    pathname = bin_path + '/arch_info.bin'
    f = open ( pathname, 'wb' )
    f.write( archinfo.cbin( verbose ) )
    print '[genarch] %s generated' % pathname

###################################################################################
#   Generate hard_config.h file if required.
###################################################################################

if ( hard_path != None ):

    pathname = hard_path + '/hard_config.h'
    f = open ( pathname, 'w' )
    f.write( archinfo.hard_config() )
    print '[genarch] %s generated' % pathname

