###############################################################
|
###############################################################
|
#
|
#
|
# File: soc_maker.rb
|
# File: soc_maker.rb
|
#
|
#
|
# Author: Christian Hättich
|
# Author: Christian Hättich
|
#
|
#
|
# Project: System-On-Chip Maker
|
# Project: System-On-Chip Maker
|
#
|
#
|
# Target: Linux / Windows / Mac
|
# Target: Linux / Windows / Mac
|
#
|
#
|
# Language: ruby
|
# Language: ruby
|
#
|
#
|
#
|
#
|
###############################################################
|
###############################################################
|
#
|
#
|
#
|
#
|
# Copyright (C) 2014 Christian Hättich - feddischson [ at ] opencores.org
|
# Copyright (C) 2014 Christian Hättich - feddischson [ at ] opencores.org
|
#
|
#
|
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
# (at your option) any later version.
|
# (at your option) any later version.
|
#
|
#
|
# This program is distributed in the hope that it will be useful,
|
# This program is distributed in the hope that it will be useful,
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
#
|
#
|
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
# along with this program. If not, see .
|
# along with this program. If not, see .
|
#
|
#
|
#
|
#
|
###############################################################
|
###############################################################
|
#
|
#
|
# Description:
|
# Description:
|
# This part of the SOCMaker module contains
|
# This part of the SOCMaker module contains
|
# - initialization of
|
# - initialization of
|
# - logger
|
# - logger
|
# - configuration
|
# - configuration
|
# - library
|
# - library
|
# (see SOCMaker::load)
|
# (see SOCMaker::load)
|
# - creating objects from YAML files/strings
|
# - creating objects from YAML files/strings
|
# (see from_f, from_s)
|
# (see from_f, from_s)
|
# - creating YAML files from objects
|
# - creating YAML files from objects
|
# (see SOCMaker::YAML_EXT::write_yaml)
|
# (see SOCMaker::YAML_EXT::write_yaml)
|
# - error-types and functions
|
|
# (see SOCMaker::ERR)
|
|
#
|
#
|
#
|
#
|
#
|
#
|
###############################################################
|
###############################################################
|
require 'logger'
|
require 'logger'
|
require 'yaml'
|
require 'yaml'
|
require 'digest/md5'
|
require 'digest/md5'
|
require 'fileutils'
|
require 'fileutils'
|
|
|
|
|
# from
|
# from
|
# http://stackoverflow.com/questions/2281490/how-to-add-a-custom-log-level-to-logger-in-ruby
|
# http://stackoverflow.com/questions/2281490/how-to-add-a-custom-log-level-to-logger-in-ruby
|
class Logger
|
class Logger
|
def self.custom_level(tag)
|
def self.custom_level(tag)
|
SEV_LABEL << tag
|
SEV_LABEL << tag
|
idx = SEV_LABEL.size - 1
|
idx = SEV_LABEL.size - 1
|
|
|
define_method(tag.downcase.gsub(/\W+/, '_').to_sym) do |progname, &block|
|
define_method(tag.downcase.gsub(/\W+/, '_').to_sym) do |progname, &block|
|
add(idx, nil, progname, &block)
|
add(idx, nil, progname, &block)
|
end
|
end
|
end
|
end
|
# add processing log level
|
# add processing log level
|
custom_level 'PROC'
|
custom_level 'PROC'
|
end
|
end
|
|
|
|
|
|
|
|
|
module SOCMaker
|
module SOCMaker
|
|
|
|
|
class << self
|
class << self
|
public
|
public
|
attr_accessor :logger
|
attr_accessor :logger
|
attr_accessor :conf
|
attr_accessor :conf
|
attr_accessor :lib
|
attr_accessor :lib
|
def load( options={} )
|
def load( options={} )
|
options = { skip_refresh: false, logger_out: STDOUT }.merge( options )
|
options = { skip_refresh: false, logger_out: STDOUT }.merge( options )
|
@conf = Conf::instance
|
@conf = Conf::instance
|
@logger = Logger.new(options[ :logger_out ] )
|
@logger = Logger.new(options[ :logger_out ] )
|
@lib = Lib.new()
|
@lib = Lib.new()
|
@logger.progname = @conf[ :app_name ]
|
@logger.progname = @conf[ :app_name ]
|
@lib.refresh( options[ :libpath ] ) unless options[ :skip_refresh ]
|
@lib.refresh( options[ :libpath ] ) unless options[ :skip_refresh ]
|
end
|
end
|
|
|
#
|
#
|
# loading from from a YAML string
|
# loading from from a YAML string
|
#
|
#
|
def from_s( s )
|
def from_s( s )
|
|
|
objs = []
|
objs = []
|
SOCMaker::YPP.to_yaml( s ) do |yaml_obj_str|
|
SOCMaker::YPP.to_yaml( s ) do |yaml_obj_str|
|
|
|
begin
|
begin
|
YAML::load( yaml_obj_str )
|
YAML::load( yaml_obj_str )
|
o = YAML::load( yaml_obj_str )
|
o = YAML::load( yaml_obj_str )
|
|
|
# ensure, that we load only our classes
|
# ensure, that we load only our classes
|
if SOCMaker::conf[ :yaml_classes ].include?( o.class )
|
if SOCMaker::conf[ :yaml_classes ].include?( o.class )
|
o.verify
|
#o.verify
|
objs << o
|
objs << o
|
else
|
else
|
SOCMaker::logger.warn( "Tried to load something, which does not belong to #{SOCMaker::conf[ :app_name ]}" )
|
SOCMaker::logger.warn( "Tried to load something, which does not belong to #{SOCMaker::conf[ :app_name ]}" )
|
end
|
end
|
rescue ArgumentError, Psych::SyntaxError #=> e
|
rescue ArgumentError, Psych::SyntaxError => e
|
#p e
|
|
SOCMaker::logger.error( 'YAML loading failed, invalid YAML syntax?' )
|
SOCMaker::logger.error( 'YAML loading failed, invalid YAML syntax?' )
|
|
SOCMaker::logger.error( ">>> #{e.to_s} <<<" )
|
raise ERR::YAMLParseError
|
raise ERR::YAMLParseError
|
else
|
else
|
end
|
end
|
end
|
end
|
|
|
if block_given?
|
if block_given?
|
objs.each{ |o| yield(o) }
|
objs.each{ |o| yield(o) }
|
end
|
end
|
return ( objs.size >1 ? objs : objs[0] )
|
return ( objs.size >1 ? objs : objs[0] )
|
end
|
end
|
|
|
# Path argument can be an array of paths
|
# Path argument can be an array of paths
|
# or a file (wildcards are allowed)
|
# or a file (wildcards are allowed)
|
# loading from a YAML file
|
# loading from a YAML file
|
def from_f( path )
|
def from_f( path )
|
|
|
path = Dir[ path ].sort if path.is_a?( String )
|
path = Dir[ path ].sort if path.is_a?( String )
|
|
|
SOCMaker::logger.warn( "No file(s) found to load" ) if path.size == 0
|
SOCMaker::logger.warn( "No file(s) found to load" ) if path.size == 0
|
|
|
yaml_str = ""
|
yaml_str = ""
|
path.each do |file|
|
path.each do |file|
|
SOCMaker::logger.info "reading:" + file
|
SOCMaker::logger.info "reading:" + file
|
yaml_str << File.read( file )
|
yaml_str << File.read( file )
|
end
|
end
|
o = from_s( yaml_str )
|
o = from_s( yaml_str )
|
o.dir = File.dirname( path.first )
|
o.dir = File.dirname( path.first )
|
return o
|
return o
|
end
|
end
|
|
|
end
|
end
|
|
|
|
|
|
|
#
|
#
|
# small module to extend classes,
|
# small module to extend classes,
|
# which need to be written as yaml
|
# which need to be written as yaml
|
# output
|
# output
|
module YAML_EXT
|
module YAML_EXT
|
|
|
# we remember always, were we've loaded a yaml file
|
# we remember always, were we've loaded a yaml file
|
attr_accessor :dir
|
attr_accessor :dir
|
|
|
def save_yaml( args )
|
def save_yaml( args )
|
path = args.size==0 ? @spec_path : args.first
|
path = args.size==0 ? @spec_path : args.first
|
File.open( path, 'w') {|f| f.write SOCMaker::YPP.from_yaml( YAML.dump( self ) ) }
|
File.open( path, 'w') {|f| f.write SOCMaker::YPP.from_yaml( YAML.dump( self ) ) }
|
end
|
end
|
end
|
end
|
|
|
|
|
#
|
|
# This sub-module contains some error-functionallity,
|
|
# which is used in different classes via mixins.
|
|
#
|
|
# serr_if means raise Structure ERRor IF ...
|
|
# verr_if means raise Value ERRor IF ...
|
|
# lerr_if means raise Library ERRor IF ...
|
|
# perr_if mean raise Processing ERRor IF
|
|
module ERR
|
|
class YAMLParseError < RuntimeError
|
|
end
|
|
|
|
class StructureError < RuntimeError
|
|
attr :name
|
|
attr :field
|
|
def initialize( name, field, message )
|
|
super message
|
|
@name = name
|
|
@field = field
|
|
# p message
|
|
SOCMaker::logger.error( "StructureError raised: " + message + " (#{name},#{field})" )
|
|
end
|
|
def to_s
|
|
"->#{@name}:#{@field}"
|
|
end
|
|
end
|
|
|
|
class LibError < RuntimeError
|
|
attr :name
|
|
def initialize( requested, message )
|
|
super message
|
|
@name = requested
|
|
SOCMaker::logger.error( "LibError raised: " + message + " (#{requested})" )
|
|
end
|
|
def to_s
|
|
"->#{@name}"
|
|
end
|
|
end
|
|
|
|
class ProcessingError < RuntimeError
|
|
def initialize( message )
|
|
super message
|
|
SOCMaker::logger.error( "ProcessingError raised: " + message )
|
|
end
|
|
end
|
|
|
|
class ValueError < RuntimeError
|
|
attr :name
|
|
attr :field
|
|
def initialize( name, field, message )
|
|
super message
|
|
@name = name
|
|
@field = field
|
|
SOCMaker::logger.error( "ValueError raised: " + message + " (#{name},#{field})" )
|
|
end
|
|
def to_s
|
|
"->#{@name}:#{@field}"
|
|
end
|
|
end
|
|
|
|
|
|
|
|
def serr_if( res, msg, o={} )
|
|
o = { instance: '??', field: '??' }.merge( o )
|
|
if !!( res )
|
|
raise StructureError.new( o[:instance], o[:field], msg )
|
|
end
|
|
end
|
|
|
|
def verr_if( res, msg, o={})
|
|
o = { instance: '??', field: '??' }.merge( o )
|
|
if !!( res )
|
|
raise ValueError.new( o[:instance], o[:field], msg )
|
|
end
|
|
end
|
|
|
|
def lerr_if( res, msg, o={})
|
|
o = { requested: '??' }.merge( o )
|
|
if !!( res )
|
|
raise LibError.new( o[:requested], msg )
|
|
end
|
|
end
|
|
|
|
def perr_if( res, msg )
|
|
if !!( res )
|
|
raise ProcessingError.new( msg )
|
|
end
|
|
end
|
|
|
|
end # module ERR
|
|
|
|
|
|
|
|
|
|
# :stopdoc:
|
# :stopdoc:
|
LIBPATH = ::File.expand_path('..', __FILE__) + ::File::SEPARATOR
|
LIBPATH = ::File.expand_path('..', __FILE__) + ::File::SEPARATOR
|
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
VERSION = ::File.read(PATH + 'version.txt').strip
|
VERSION = ::File.read(PATH + 'version.txt').strip
|
# :startdoc:
|
# :startdoc:
|
|
|
# Returns the library path for the module. If any arguments are given,
|
# Returns the library path for the module. If any arguments are given,
|
# they will be joined to the end of the libray path using
|
# they will be joined to the end of the libray path using
|
# File.join.
|
# File.join.
|
#
|
#
|
def self.libpath( *args )
|
def self.libpath( *args )
|
rv = args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
rv = args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
if block_given?
|
if block_given?
|
begin
|
begin
|
$LOAD_PATH.unshift LIBPATH
|
$LOAD_PATH.unshift LIBPATH
|
rv = yield
|
rv = yield
|
ensure
|
ensure
|
$LOAD_PATH.shift
|
$LOAD_PATH.shift
|
end
|
end
|
end
|
end
|
return rv
|
return rv
|
end
|
end
|
|
|
# Returns the lpath for the module. If any arguments are given,
|
# Returns the lpath for the module. If any arguments are given,
|
# they will be joined to the end of the path using
|
# they will be joined to the end of the path using
|
# File.join.
|
# File.join.
|
#
|
#
|
def self.path( *args )
|
def self.path( *args )
|
rv = args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
rv = args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
if block_given?
|
if block_given?
|
begin
|
begin
|
$LOAD_PATH.unshift PATH
|
$LOAD_PATH.unshift PATH
|
rv = yield
|
rv = yield
|
ensure
|
ensure
|
$LOAD_PATH.shift
|
$LOAD_PATH.shift
|
end
|
end
|
end
|
end
|
return rv
|
return rv
|
end
|
end
|
|
|
def self.require_all_libs
|
def self.require_all_libs
|
file = ::File.basename(__FILE__, '.*')
|
file = ::File.basename(__FILE__, '.*')
|
dir = ::File.dirname(__FILE__)
|
dir = ::File.dirname(__FILE__)
|
%w[ ypp lib_inc
|
%w[ err ypp
|
component
|
lib_inc component
|
core_def core_inst
|
core_def core_inst
|
hdl_file ifc_def
|
hdl_file ifc_def
|
ifc_port ifc_spc
|
ifc_port ifc_spc
|
soc_def parameter
|
soc_def parameter
|
sparameter hdl_coder
|
sparameter hdl_coder
|
lib cli conf].each { |rb| require ::File.expand_path(
|
lib cli conf].each { |rb| require ::File.expand_path(
|
::File.join( dir, file, rb ) ) }
|
::File.join( dir, file, rb ) ) }
|
end
|
end
|
|
|
end # module SOCMaker
|
end # module SOCMaker
|
|
|
SOCMaker.require_all_libs
|
SOCMaker.require_all_libs
|
|
|
# vim: noai:ts=2:sw=2
|
# vim: noai:ts=2:sw=2
|
|
|