#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
###############################################################
|
###############################################################
|
#
|
#
|
# File: soc_maker_cli.rb
|
# File: soc_maker_cli.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:
|
#
|
#
|
# Command-line interface for accessing the SOC-Maker functionallity
|
# Command-line interface for accessing the SOC-Maker functionallity
|
#
|
#
|
# The following commands are available:
|
# The following commands are available:
|
# - new -> create a new soc file
|
# - new -> create a new soc file
|
# - open -> open soc file
|
# - open -> open soc file
|
# - list -> list library
|
# - list -> list library
|
# - add -> add core to soc
|
# - add -> add core to soc
|
# - parameter -> set/get parameter
|
# - parameter -> set/get parameter
|
# - sparameter -> set/get static parameter
|
# - sparameter -> set/get static parameter
|
# - connect -> connect cores
|
# - connect -> connect cores
|
# - delete -> delete core or connection
|
# - delete -> delete core or connection
|
# - save -> save soc
|
# - save -> save soc
|
# - generate -> generate soc
|
# - generate -> generate soc
|
# - quit -> quit this CLI
|
# - quit -> quit this CLI
|
# - exit -> same than quit
|
# - exit -> same than quit
|
# - help -> print some help
|
# - help -> print some help
|
#
|
#
|
# Please use the help command to get more information about
|
# Please use the help command to get more information about
|
# each command and its parameters.
|
# each command and its parameters.
|
#
|
#
|
# This CLI is a wrapper around SOCMaker::SOCDef.
|
# This CLI is a wrapper around SOCMaker::SOCDef.
|
#
|
#
|
#
|
#
|
#######
|
#######
|
#
|
#
|
# TODO: add commands for
|
# TODO: add commands for
|
# - selecting the coder
|
# - selecting the coder
|
# (at the moment, only VHDL is supported)
|
# (at the moment, only VHDL is supported)
|
#
|
#
|
# - refreshing the lib
|
# - refreshing the lib
|
#
|
#
|
#
|
#
|
###############################################################
|
###############################################################
|
require 'readline'
|
require 'readline'
|
require 'optparse'
|
require 'optparse'
|
|
|
|
|
module SOCMaker
|
module SOCMaker
|
class Cli
|
class Cli
|
|
|
private_class_method :new
|
private_class_method :new
|
def Cli.instance
|
def Cli.instance
|
@@inst = new if @@inst == nil
|
@@inst = new if @@inst == nil
|
return @@inst
|
return @@inst
|
end
|
end
|
|
|
FMSG = ' -> failed '
|
FMSG = ' -> failed '
|
|
|
|
|
|
|
#########################################
|
#########################################
|
#
|
#
|
# command implementations:
|
# command implementations:
|
# -> a usage string and
|
# -> a usage string and
|
# a function for every command
|
# a function for every command
|
#
|
#
|
|
|
#
|
#
|
# New
|
# New
|
#
|
#
|
NEW_USAGE =
|
NEW_USAGE =
|
" > new <> <> <> # opens a system-on-chip file
|
" > new <> <> <> # opens a system-on-chip file
|
- <> : the SOC name
|
- <> : the SOC name
|
- <> : the SOC version
|
- <> : the SOC id
|
- <> : the toplevel name
|
- <> : the toplevel name
|
"
|
"
|
def do_new( args )
|
def do_new( args )
|
if args.size != 3
|
if args.size != 3
|
puts "three arguments are required:\nusage:\n#{NEW_USAGE}"
|
puts "three arguments are required:\nusage:\n#{NEW_USAGE}"
|
else
|
else
|
@soc = SOCMaker::SOCDef.new( args[0], args[1], args[2] )
|
@soc = SOCMaker::SOCDef.new( args[0], args[1], args[2] )
|
SOCMaker::lib.add_core( @soc )
|
SOCMaker::lib.add_core( @soc )
|
@soc_inst = SOCMaker::CoreInst.new( "#{args[0]}#{args[1]}" )
|
@soc_inst = SOCMaker::CoreInst.new( "#{args[0]}#{args[1]}" )
|
#puts FMSG if @soc.load_soc( args[ 0 ] ) == nil
|
#puts FMSG if @soc.load_soc( args[ 0 ] ) == nil
|
end
|
end
|
end
|
end
|
|
|
|
|
|
|
#
|
#
|
# Open
|
# Open
|
#
|
#
|
OPEN_USAGE =
|
OPEN_USAGE =
|
" > open <> # opens a system-on-chip file
|
" > open <> # opens a system-on-chip file
|
- <> : system-on-chip definition in in YAML format
|
- <> : system-on-chip definition in in YAML format
|
|
|
"
|
"
|
def do_open( args )
|
def do_open( args )
|
if args.size != 1
|
if args.size != 1
|
puts "only one argument is required:\nusage:\n#{OPEN_USAGE}"
|
puts "only one argument is required:\nusage:\n#{OPEN_USAGE}"
|
else
|
else
|
puts "loading #{args[0]}"
|
puts "loading #{args[0]}"
|
@soc = SOCMaker::from_f( args[0] )
|
@soc = SOCMaker::from_f( args[0] )
|
SOCMaker::lib.add_core( @soc )
|
SOCMaker::lib.add_core( @soc )
|
@soc_inst = SOCMaker::CoreInst.new( "#{@soc.name}#{@soc.version}" )
|
@soc_inst = SOCMaker::CoreInst.new( "#{@soc.version.to_s}" )
|
#puts FMSG if @soc.load_soc( args[ 0 ] ) == nil
|
#puts FMSG if @soc.load_soc( args[ 0 ] ) == nil
|
end
|
end
|
end
|
end
|
|
|
|
|
#
|
#
|
# List
|
# List
|
#
|
#
|
LIST_USAGE =
|
LIST_USAGE =
|
" > list # prints list of cores and interfaces,
|
" > list # prints list of cores and interfaces,
|
which are in the library
|
which are in the library
|
|
|
"
|
"
|
def do_list( args )
|
def do_list( args )
|
puts SOCMaker::lib
|
puts SOCMaker::lib
|
end
|
end
|
|
|
|
|
#
|
#
|
# Add
|
# Add
|
#
|
#
|
ADD_USAGE =
|
ADD_USAGE =
|
" > add <> <> <>
|
" > add <> <>
|
# adds a ip-core from the library to the SOC
|
# adds an ip-core from the library to the SOC
|
- <> : name of the IP core
|
- <> : id of the IP core
|
- <> : version of the IP core
|
|
- <> : instanciation name
|
- <> : instanciation name
|
|
|
"
|
"
|
def do_add( args )
|
def do_add( args )
|
if args.size != 3
|
if args.size != 2
|
puts "three arguments are required:\nusage:\n#{ADD_USAGE}"
|
puts "two arguments are required:\nusage:\n#{ADD_USAGE}"
|
else
|
else
|
puts FMSG if @soc.add_core( args[ 0 ], args[ 1 ], args[ 2 ] ) == nil
|
puts FMSG if @soc.add_core( args[ 0 ], args[ 1 ] ) == nil
|
end
|
end
|
end
|
end
|
|
|
|
|
#
|
#
|
# Set/Get Parameter
|
# Set/Get Parameter
|
#
|
#
|
PARAMETER_USAGE =
|
PARAMETER_USAGE =
|
" > prameter <> <> <>
|
" > prameter <> <> <>
|
# modifies a parameter of an instance
|
# modifies a parameter of an instance
|
- <> : the instance name of the core
|
- <> : the instance name of the core
|
- <> : the instance parameter name
|
- <> : the instance parameter name
|
- <> : the value which is set (optional). The current
|
- <> : the value which is set (optional). The current
|
value is printed, if omitted
|
value is printed, if omitted
|
"
|
"
|
def do_parameter( args )
|
def do_parameter( args )
|
if args.size == 2
|
if args.size == 2
|
puts FMSG if @soc.get_param( args[ 0 ], args[ 1 ] ) == nil
|
puts FMSG if @soc.get_param( args[ 0 ], args[ 1 ] ) == nil
|
elsif args.size == 3
|
elsif args.size == 3
|
puts FMSG if @soc.set_param( args[ 0 ], args[ 1 ], args[ 2 ] ) == nil
|
puts FMSG if @soc.set_param( args[ 0 ], args[ 1 ], args[ 2 ] ) == nil
|
else
|
else
|
puts "two or three arguments required:\nusage:\n#{PARAMETER_USAGE}"
|
puts "two or three arguments required:\nusage:\n#{PARAMETER_USAGE}"
|
end
|
end
|
end
|
end
|
|
|
|
|
#
|
#
|
# Set/Get Static Parameter
|
# Set/Get Static Parameter
|
#
|
#
|
SPARAMETER_USAGE =
|
SPARAMETER_USAGE =
|
" > sprameter <> <> <>
|
" > sprameter <> <> <>
|
# modifies the static parameter of a core
|
# modifies the static parameter of a core
|
- <> : the name of the core
|
- <> : the name of the core
|
- <> : the static parameter name
|
- <> : the static parameter name
|
- <> : the value which is set (optional). The current
|
- <> : the value which is set (optional). The current
|
value is printed, if omitted
|
value is printed, if omitted
|
"
|
"
|
def do_sparameter( args )
|
def do_sparameter( args )
|
if args.size == 2
|
if args.size == 2
|
puts FMSG if @soc.get_sparam( args[ 0 ], args[ 1 ] ) == nil
|
puts FMSG if @soc.get_sparam( args[ 0 ], args[ 1 ] ) == nil
|
elsif args.size == 3
|
elsif args.size == 3
|
puts FMSG if @soc.set_sparam( args[ 0 ], args[ 1 ], args[ 2 ] ) == nil
|
puts FMSG if @soc.set_sparam( args[ 0 ], args[ 1 ], args[ 2 ] ) == nil
|
else
|
else
|
puts "two or three arguments required:\nusage:\n#{SPARAMETER_USAGE}"
|
puts "two or three arguments required:\nusage:\n#{SPARAMETER_USAGE}"
|
end
|
end
|
end
|
end
|
|
|
|
|
#
|
#
|
# Connect
|
# Connect
|
#
|
#
|
CONNECT_USAGE =
|
CONNECT_USAGE =
|
" > connect <> <> <> <> <>
|
" > connect <> <> <> <> <>
|
# connects two cores
|
# connects two cores
|
- <> : instance name of the first core
|
- <> : instance name of the first core
|
- <> : instance name of the second core
|
- <> : instance name of the second core
|
- <> : interface name of the first core
|
- <> : interface name of the first core
|
- <> : interface name of the second core
|
- <> : interface name of the second core
|
- <> : connection name
|
- <> : connection name
|
|
|
"
|
"
|
def do_connect( args )
|
def do_connect( args )
|
if args.size != 5
|
if args.size != 5
|
puts "five arguments are required:\nusage:\n#{CONNECT_USAGE}"
|
puts "five arguments are required:\nusage:\n#{CONNECT_USAGE}"
|
else
|
else
|
puts FMSG if @soc.add_connection( args[ 0 ], args[ 1 ], args[ 2 ], args[ 3 ], args[ 4 ] )
|
puts FMSG if @soc.add_connection( args[ 0 ], args[ 1 ], args[ 2 ], args[ 3 ], args[ 4 ] )
|
end
|
end
|
end
|
end
|
|
|
|
|
#
|
#
|
# Delete
|
# Delete
|
#
|
#
|
DELETE_USAGE =
|
DELETE_USAGE =
|
" > delete <>
|
" > delete <>
|
# removes a core or a connection
|
# removes a core or a connection
|
- < : the core or connection, which is removed
|
- < : the core or connection, which is removed
|
|
|
"
|
"
|
def do_delete( args )
|
def do_delete( args )
|
if args.size != 1
|
if args.size != 1
|
puts "five arguments are required:\nusage:\n#{DELETE_USAGE}"
|
puts "five arguments are required:\nusage:\n#{DELETE_USAGE}"
|
else
|
else
|
puts FMSG if @soc.rm( args[ 0 ] ) == nil
|
puts FMSG if @soc.rm( args[ 0 ] ) == nil
|
end
|
end
|
end
|
end
|
|
|
|
|
#
|
#
|
# Save
|
# Save
|
#
|
#
|
SAVE_USAGE =
|
SAVE_USAGE =
|
" > save <> # saves system-on-chip definition in YAML format to file
|
" > save <> # saves system-on-chip definition in YAML format to file
|
- <> : optional destination file, when omitted: the
|
- <> : optional destination file, when omitted: the
|
original file-path is used
|
original file-path is used
|
|
|
"
|
"
|
def do_save( args )
|
def do_save( args )
|
if args.size > 1
|
if args.size > 1
|
puts "zero or one argument is required:\nusage:\n#{SAVE_USAGE}"
|
puts "zero or one argument is required:\nusage:\n#{SAVE_USAGE}"
|
else
|
else
|
p args
|
p args
|
puts FMSG if @soc.save_yaml( args ) == nil
|
puts FMSG if @soc.save_yaml( args ) == nil
|
end
|
end
|
end
|
end
|
|
|
|
|
#
|
#
|
# Generate
|
# Generate
|
#
|
#
|
GENERATE_USAGE =
|
GENERATE_USAGE =
|
" > generate # generates a synthesizable system-on-chip implementation
|
" > generate # generates a synthesizable system-on-chip implementation
|
|
|
"
|
"
|
def do_generate( args )
|
def do_generate( args )
|
if args.size != 0
|
if args.size != 0
|
puts "no arguments are required:\nusage:\n#{GENERATE_USAGE}"
|
puts "no arguments are required:\nusage:\n#{GENERATE_USAGE}"
|
else
|
else
|
@soc_inst.gen_toplevel
|
@soc_inst.gen_toplevel
|
@soc.copy_files
|
@soc.copy_files
|
end
|
end
|
end
|
end
|
|
|
|
|
|
|
PRINT_USAGE =
|
PRINT_USAGE =
|
" > print # prints SOC information
|
" > print # prints SOC information
|
|
|
"
|
"
|
def do_print( args )
|
def do_print( args )
|
if args.size != 0
|
if args.size != 0
|
puts "no arguments are required:\nusage:\n#{PRINT_USAGE}"
|
puts "no arguments are required:\nusage:\n#{PRINT_USAGE}"
|
else
|
else
|
puts @soc
|
puts @soc
|
end
|
end
|
end
|
end
|
|
|
|
|
#
|
#
|
# Quit
|
# Quit
|
#
|
#
|
QUIT_USAGE =
|
QUIT_USAGE =
|
" > quit # the same than exit
|
" > quit # the same than exit
|
|
|
"
|
"
|
def do_quit( args )
|
def do_quit( args )
|
do_exit( args )
|
do_exit( args )
|
end
|
end
|
|
|
|
|
#
|
#
|
# Exit
|
# Exit
|
#
|
#
|
EXIT_USAGE =
|
EXIT_USAGE =
|
" > exit # exits this tool
|
" > exit # exits this tool
|
|
|
"
|
"
|
def do_exit( args )
|
def do_exit( args )
|
puts "... bye bye!"
|
puts "... bye bye!"
|
exit 0
|
exit 0
|
end
|
end
|
|
|
|
|
#
|
#
|
# Help
|
# Help
|
#
|
#
|
HELP_USAGE =
|
HELP_USAGE =
|
" > help # prints some help information
|
" > help # prints some help information
|
|
|
"
|
"
|
def do_help( args )
|
def do_help( args )
|
puts "The following commands are available:\n\n"
|
puts "The following commands are available:\n\n"
|
@commands.each { |c| eval "puts #{c.upcase}_USAGE" }
|
@commands.each { |c| eval "puts #{c.upcase}_USAGE" }
|
end
|
end
|
|
|
|
|
SET_USAGE =
|
SET_USAGE =
|
" > set # not implemented yet
|
" > set # not implemented yet
|
|
|
"
|
"
|
def do_set( args )
|
def do_set( args )
|
puts "NOT IMPLEMENTED, YET"
|
puts "NOT IMPLEMENTED, YET"
|
end
|
end
|
|
|
GET_USAGE =
|
GET_USAGE =
|
" > get # not implemented yet
|
" > get # not implemented yet
|
|
|
"
|
"
|
def do_get( args )
|
def do_get( args )
|
puts "NOT IMPLEMENTED, YET"
|
puts "NOT IMPLEMENTED, YET"
|
end
|
end
|
|
|
# end command implementations
|
# end command implementations
|
#
|
#
|
#################################
|
#################################
|
|
|
|
|
|
|
@soc = nil
|
@soc = nil
|
@soc_inst = nil
|
@soc_inst = nil
|
|
|
def initialize
|
def initialize
|
|
|
# appreviation map
|
# appreviation map
|
@appr_map = { 'n' => "new",
|
@appr_map = { 'n' => "new",
|
'o' => "open",
|
'o' => "open",
|
'q' => "quit",
|
'q' => "quit",
|
'h' => "help",
|
'h' => "help",
|
'l' => "list",
|
'l' => "list",
|
'a' => "add",
|
'a' => "add",
|
'g' => "generate",
|
'g' => "generate",
|
's' => "save",
|
's' => "save",
|
'p' => "parameter",
|
'p' => "parameter",
|
'd' => "delete",
|
'd' => "delete",
|
'c' => "connect",
|
'c' => "connect",
|
'i' => "print",
|
'i' => "print",
|
'x' => "exit"
|
'x' => "exit"
|
}
|
}
|
|
|
# all available commands
|
# all available commands
|
@commands = %w[ new open list add parameter sparameter
|
@commands = %w[ new open list add parameter sparameter
|
delete connect save help quit exit
|
delete connect save help quit exit
|
generate print set get ]
|
generate print set get ]
|
|
|
comp = proc { |s| (@commands + Dir.entries( Dir.pwd )).grep( /^#{Regexp.escape(s)}/ ) }
|
comp = proc { |s| (@commands + Dir.entries( Dir.pwd )).grep( /^#{Regexp.escape(s)}/ ) }
|
Readline.completion_append_character = " "
|
Readline.completion_append_character = " "
|
Readline.completion_proc = comp
|
Readline.completion_proc = comp
|
|
|
end
|
end
|
|
|
def run
|
def run
|
|
|
##
|
##
|
# process user commands
|
# process user commands
|
#
|
#
|
while buf = Readline.readline( "> ", true )
|
while buf = Readline.readline( "> ", true )
|
process_cmd buf
|
process_cmd buf
|
end
|
end
|
end
|
end
|
|
|
def process_cmd( c )
|
def process_cmd( c )
|
|
|
# remove the comments and split each line
|
# remove the comments and split each line
|
match = SOCMaker::conf[ :COMMENT_REGEX ].match( c )
|
match = SOCMaker::conf[ :COMMENT_REGEX ].match( c )
|
cmd_arr = match[1].split( ' ' )
|
cmd_arr = match[1].split( ' ' )
|
|
|
# process the command, if there is one
|
# process the command, if there is one
|
if cmd_arr.size > 0
|
if cmd_arr.size > 0
|
cmd = ""
|
cmd = ""
|
if cmd_arr[ 0 ].size == 1 and @appr_map[ cmd_arr[ 0 ] ] != nil
|
if cmd_arr[ 0 ].size == 1 and @appr_map[ cmd_arr[ 0 ] ] != nil
|
cmd = @appr_map[ cmd_arr[ 0 ] ]
|
cmd = @appr_map[ cmd_arr[ 0 ] ]
|
else
|
else
|
cmd = cmd_arr[ 0 ]
|
cmd = cmd_arr[ 0 ]
|
end
|
end
|
|
|
if @commands.include?( cmd )
|
if @commands.include?( cmd )
|
cmd_str = "do_#{cmd}( cmd_arr[ 1..-1] )"
|
cmd_str = "do_#{cmd}( cmd_arr[ 1..-1] )"
|
puts "evaluating >>#{cmd_str}<< "
|
puts "evaluating >>#{cmd_str}<< "
|
eval( cmd_str )
|
eval( cmd_str )
|
#TODO this is for linux only
|
#TODO this is for linux only
|
elsif system( "which #{cmd} > /dev/null 2>&1" )
|
elsif system( "which #{cmd} > /dev/null 2>&1" )
|
system( c )
|
system( c )
|
else
|
else
|
puts "Command #{cmd} not available"
|
puts "Command #{cmd} not available"
|
end
|
end
|
#begin
|
#begin
|
#rescue
|
#rescue
|
# puts "evaluating >>#{cmd_str}<< failed"
|
# puts "evaluating >>#{cmd_str}<< failed"
|
#end
|
#end
|
end
|
end
|
end
|
end
|
|
|
@@inst = nil
|
@@inst = nil
|
|
|
|
|
end
|
end
|
end
|
end
|
|
|
|
|
# vim: noai:ts=2:sw=2
|
# vim: noai:ts=2:sw=2
|
|
|
|
|