Class: SOCMaker::SOCDef
- Defined in:
- lib/soc_maker/soc_def.rb
Overview
This class represents a System-on-chip and derives the functionallity from SOCMaker::CoreDef. The two important fields are
-
#cores: holds all core-instances
-
#cons: holds all connections
In addition, the field @static is used to store static parameters, which are set for cores used in this SOC.
Instance Attribute Summary collapse
-
#cons ⇒ Object
Hash of all connections.
-
#cores ⇒ Object
Hash of cores (core instances: SOCMaker::CoreInst).
-
#static ⇒ Object
Hash of all static parameters defined within this SOC.
Attributes included from YAML_EXT
Attributes inherited from CoreDef
#author, #authormail, #date, #description, #functions, #hdlfiles, #id, #id_clean, #inst_parameters, #interfaces, #license, #licensefile, #name, #static_parameters, #toplevel, #vccmd
Instance Method Summary collapse
-
#==(o) ⇒ Object
Equality operator.
-
#add_connection(*args) ⇒ Object
Method add/modify a connection.
-
#add_core(id, inst_name) ⇒ Object
Add an instance to the SoC.
-
#all_core_id ⇒ Object
Method to get all id’s of all cores, sub-socs (recursively).
-
#all_static_parameters ⇒ Object
Method to get all static parameters of all cores, sub-socs (recursively).
-
#consistence_check ⇒ Object
Consistence check method: - ensures, that all cores are available and consistent - ensures, that all connections are possible.
-
#core_definition(inst) ⇒ Object
Method to get the core definition.
-
#deploy(options = {}) ⇒ Object
Method, to deploy this SOC: It runs gen_toplevel and calls also super to copy files, which are added in addition to this SOC.
-
#encode_with(coder) ⇒ Object
Encoder method (to yaml).
-
#gen_toplevel(coder = VHDLCoder.new) ⇒ Object
Generate toplevel hdl file for this instance.
-
#get_param(instance, param) ⇒ Object
Method to get an instance parameter.
-
#get_sparam(core, param) ⇒ Object
Method to get a static parameter.
-
#ifc_in_use?(inst_name, ifc_name) ⇒ Boolean
Method to check, if the interface of an instance is already connected.
-
#init_with(coder) ⇒ Object
Initialization method (from yaml).
-
#initialize(name, id, toplevel, optional = {}) ⇒ SOCDef
constructor
This constructor expects the name, an id, the toplevel-name as mandatory arguments.
-
#inst_connections(inst_name) ⇒ Object
- Method to get all connections of an instance
inst_name
- Instance name (as symbol)
return
-
A connection hash.
- Instance name (as symbol)
- Method to get all connections of an instance
-
#inst_in_use?(inst_name) ⇒ Boolean
Check, if the instance name is already used within this SOC.
-
#is_it_me?(inst_name) ⇒ Boolean
Method to check, if inst_name means this SOC.
-
#port(ifc_name, port_ref) ⇒ Object
Returns a port, identified by the interface and port name Note: this behaviour is exactly the same than of core_inst.port(…), but these ports are not evaluated.
-
#port_length(ifc_name, port_name, inst) ⇒ Object
Method to get the port length.
-
#rm(inst_name) ⇒ Object
Method to remove a instance.
-
#set_param(instance, param, value) ⇒ Object
Method to set an instance parameter.
-
#set_sparam(core, param, value) ⇒ Object
Method to set a static parameter.
-
#to_s ⇒ Object
Returns a string describing this instance.
-
#top_connections(inst_name) ⇒ Object
- Method to get all connections which connected to the top
inst_name
- Instance name (as symbol)
return
-
A connection hash.
- Instance name (as symbol)
- Method to get all connections which connected to the top
Methods included from YAML_EXT
Methods included from ERR
#consistence_error, #consistence_error_if, #init_error, #init_error_if, #processing_error, #processing_error_if
Methods inherited from CoreDef
#add_interface, core_cnt, #dir_name, #generics, get_and_ensure_dst_dir!, #ifc_specification, #ports, #update_vcs
Constructor Details
#initialize(name, id, toplevel, optional = {}) ⇒ SOCDef
This constructor expects the name, an id, the toplevel-name as mandatory arguments. All other attributes can be privided as optional argument
100 101 102 103 104 105 106 |
# File 'lib/soc_maker/soc_def.rb', line 100 def initialize( name, id, toplevel, optional = {} ) init_with( { 'name' => name, 'id' => id, 'toplevel' => toplevel }.merge( optional ) ) end |
Instance Attribute Details
#cons ⇒ Object
Hash of all connections. The structure is the following
@cons = { :connection_name_1 => {
:mapping => [
{ :instance_1 => :interface_of_instance_1, #\ dir=0
:instance_2 => :interface_of_instance_2, #/
...},
{ :instance_3 => :interface_of_instance_3, #\ dir=1
:instance_4 => :interface_of_instance_4, #/
...}
] },
:connection_name_2 => {
:mapping => [
{ :instance_a => :interface_of_instance_a, #\ dir=0
:instance_b => :interface_of_instance_b, #/
...},
{ :instance_c => :interface_of_instance_c, #\ dir=1
:instance_d => :interface_of_instance_d, #/
...}
] },
....
}
The important part is the mapping: it is a list with two entries. Ech entry is a Hash containing instance-interface assignments.
TODO: this needs to be re-designed, because it allowes only one core to be used in one connection-direction.
90 91 92 |
# File 'lib/soc_maker/soc_def.rb', line 90 def cons @cons end |
#cores ⇒ Object
Hash of cores (core instances: SOCMaker::CoreInst)
53 54 55 |
# File 'lib/soc_maker/soc_def.rb', line 53 def cores @cores end |
#static ⇒ Object
Hash of all static parameters defined within this SOC
95 96 97 |
# File 'lib/soc_maker/soc_def.rb', line 95 def static @static end |
Instance Method Details
#==(o) ⇒ Object
Equality operator
801 802 803 804 805 806 807 |
# File 'lib/soc_maker/soc_def.rb', line 801 def ==(o) o.class == self.class && o.cores == self.cores && o.cons == self.cons && o.static == self.static && super( o ) end |
#add_connection(*args) ⇒ Object
Method add/modify a connection. The number of arguments are variable and multiple entries can be provided as once.
args
-
number of arguments must be >3 and odd. The first argument defines
the connection name. The following arguments are treaded as pairs. Each pair consists of the instance name and the interface name.
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
# File 'lib/soc_maker/soc_def.rb', line 316 def add_connection( *args ) if args.size < 3 || args.size % 2 != 1 processing_error "FATAL: wrong number of arguments: " + "(#{args.size}) must be > = 3 and odd" end consistence_check con_name = args[0] args[ 1..-1].each_slice(2).to_a.each do |entry| inst_name = entry[0] ifc_name = entry[1] # get the core definition core_def = core_definition( inst_name ) or consistence_error "Can't find definition of core #{inst_name}" consistence_error_if ifc_in_use?( inst_name, ifc_name ), "Interface #{ifc_name} of instance '#{inst_name}' is already in use " consistence_error_if core_def.interfaces[ ifc_name ] == nil, "Interface '#{ifc_name}' dosn't exist in core '#{inst_name}' \n" + "The following interfaces do exist: '#{core_def.interfaces.keys}'" # get the interface specification ifc_spc = core_def.ifc_specification( ifc_name ) # get the directions ifc_dir = core_def.interfaces[ ifc_name ].dir ifc_dir = ( ifc_dir + 1 ) % 2 if is_it_me?( inst_name ) # create a new connection, if there is no one if @cons[ con_name ] == nil @cons[ con_name ] = { mapping: [ {},{} ] } end if ifc_spc.n_connections_ok?( ifc_dir, @cons[ con_name ][ :mapping ][ ifc_dir ].size+1 ) @cons[ con_name ][ :mapping ][ ifc_dir ][ inst_name ] = ifc_name else consistence_error "Only #{ ifc_spc.multiplicity[ ifc_dir ] } " + "connections are allowed for direction #{ifc_dir}", connection: con_name, instance: inst_name, interface: ifc_name end end end |
#add_core(id, inst_name) ⇒ Object
Add an instance to the SoC
id
-
the core ID, used to get the desired core from SOCMaker::Lib
inst_name
-
name of the instance
230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/soc_maker/soc_def.rb', line 230 def add_core( id, inst_name ) consistence_error_if( inst_in_use?( inst_name ), "Instance name #{inst_name} is already in use" ) # check, if the core exits in our library # if not: an error will be raised SOCMaker::lib.get_core( id ) @cores[ inst_name ] = SOCMaker::CoreInst.new( id ) end |
#all_core_id ⇒ Object
Method to get all id’s of all cores, sub-socs (recursively)
783 784 785 |
# File 'lib/soc_maker/soc_def.rb', line 783 def all_core_id @cores.values.map{ |c| c.defn.all_core_id }.flatten! << @id end |
#all_static_parameters ⇒ Object
Method to get all static parameters of all cores, sub-socs (recursively)
791 792 793 794 795 |
# File 'lib/soc_maker/soc_def.rb', line 791 def all_static_parameters tmp = { @id => @static } @cores.values.each { |v| tmp.merge!( v.defn.all_static_parameters ) } return tmp end |
#consistence_check ⇒ Object
Consistence check method:
-
ensures, that all cores are available and consistent
-
ensures, that all connections are possible
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/soc_maker/soc_def.rb', line 143 def consistence_check super @cores.values.each do |inst| inst.consistence_check end @cons.each do |con_name, con_def| con_def[ :mapping ].each_with_index do |mapping,dir| mapping.each do |inst_name, ifc_name| if !is_it_me?( inst_name ) consistence_error "#{inst_name} not does not exist in SOCDef #{@name}" if @cores[ inst_name ] == nil end core_def = core_definition( inst_name ) or consistence_error "Can't find definition of core #{inst_name}" consistence_error "Interface #{ifc_name} doesn exist in #{core_def.name}" if core_def.interfaces[ ifc_name ] == nil consistence_error "Wrong connection definition of #{inst_name}:#{ifc_name}", direction: core_def.interfaces[ ifc_name ].dir, localtion: dir, internal: is_it_me?( inst_name ) if !( ( (core_def.interfaces[ ifc_name ].dir != dir) && is_it_me?( inst_name ) ) || ( (core_def.interfaces[ ifc_name ].dir == dir) && !is_it_me?( inst_name ) ) ) end end end end |
#core_definition(inst) ⇒ Object
Method to get the core definition.
inst
-
instance name (as symbol)
return
-
nil, if there is no core with the name and if it is not this SOC
291 292 293 294 295 296 297 298 299 300 |
# File 'lib/soc_maker/soc_def.rb', line 291 def core_definition( inst ) if @cores[ inst ] != nil return @cores[ inst ].defn elsif is_it_me?( inst ) return self else return nil end end |
#deploy(options = {}) ⇒ Object
Method, to deploy this SOC: It runs gen_toplevel and calls also super to copy files, which are added in addition to this SOC.
options
-
Common entries are coder and static:
coder must be a SOCMaker::Coder and static must be a hash of static parameters.
468 469 470 471 472 |
# File 'lib/soc_maker/soc_def.rb', line 468 def deploy( = {} ) = { coder: VHDLCoder.new }.merge( ) gen_toplevel( [ :coder ] ) super( ) end |
#encode_with(coder) ⇒ Object
Encoder method (to yaml)
coder
-
An instance of the Psych::Coder to encode this class to a YAML file
113 114 115 116 117 118 119 |
# File 'lib/soc_maker/soc_def.rb', line 113 def encode_with( coder ) init_error_if !coder.is_a?( Psych::Coder ), 'coder is not given as Psych::Coder' super coder %w[ cores cons static ]. each { |v| coder[ v ] = instance_variable_get "@#{v}" } end |
#gen_toplevel(coder = VHDLCoder.new) ⇒ Object
Generate toplevel hdl file for this instance. This assumes, that this instance represents a SOC with further instances.
coder
-
An instance of the SOCMaker::HDLCoder, which is used to create the auto-generated HDL (optional). If no coder is given, a SOCMaker::VHDLCoder is used.
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 |
# File 'lib/soc_maker/soc_def.rb', line 521 def gen_toplevel( coder = VHDLCoder.new ) # # Get filename # file_name = coder.filename( dir_name ) dst_dir = CoreDef::get_and_ensure_dst_dir!( dir_name ) SOCMaker::logger.proc( "START of creating top-level '" + file_name + "'" ) # # Create a unique list of cores and # add for each core a component statement (vhdl only). # Even if there are multiple instances of a core, # we need to decalre it only once # @cores.values.uniq{|x| x.type }.each do |inst; spec| spec = SOCMaker::lib.get_core( inst.type ) processing_error "Can't find #{ inst.type } in SOC library" if !spec coder.add_core_component( inst.type, spec ) end top_connections = {} # # Instanciate each core # @cores.each do |inst_name, inst| # get all connections of this instance, which are connected # to top and are single-entry connections top_cons_tmp = top_connections( inst_name ) top_cons_tmp = top_cons_tmp.select{ |k,v| v[:mapping][0].size == 1 && v[:mapping][1].size == 1 } top_cons_tmp.keys.each do |con_name| @cons[ con_name ][ :top_assigned ] = true end coder.add_core_instance( inst_name.to_s, inst, top_cons_tmp, @interfaces, self ) top_connections.merge!( top_cons_tmp ) end # create a list of all top-interfaces, which are directly connected # to cores top_connected_ifcs = [] top_connections.values.each do |con| if con[ :mapping ][0].has_key?( @toplevel.to_sym ) top_connected_ifcs << con[ :mapping ][0][ @toplevel.to_sym ] else top_connected_ifcs << con[ :mapping ][1][ @toplevel.to_sym ] end end # Iterate over all connections: # - create signal instances # - add assignments # @cons.each do |con_name, con_def| if not con_def[ :top_assigned] gen_toplevel_con( con_name.to_s, con_def[ :mapping ][0], con_def[ :mapping ][1], coder ) end end assign_unused_to_default( coder ) coder.add_toplevel_sig( self, @toplevel, top_connected_ifcs ) # # Write content to the file # SOCMaker::logger.proc( "writing top-level" ) File.open( File.join( dst_dir, file_name ), 'w' ) do |f| f.write( coder.get_hdl_code( self, @toplevel ) ) end SOCMaker::logger.proc( "END of creating top-level hdl code for #{@name}" ) @cons.values.each{ |v| v[ :top_assigned ] = false } end |
#get_param(instance, param) ⇒ Object
Method to get an instance parameter
instance
-
name of the instance
param
-
name of the parameter
406 407 408 409 410 411 412 413 414 |
# File 'lib/soc_maker/soc_def.rb', line 406 def get_param( instance, param ) # get instance core_inst = @cores[ instance ] consistence_error "Can't find '#{instance}' in SOC" if core_inst == nil param_val = core_inst.params[ param ] consistence_error "Can't find parameter '#{param}' in '#{instance}'" if param_val == nil return param_val end |
#get_sparam(core, param) ⇒ Object
Method to get a static parameter
instance
-
name of the instance
param
-
name of the parameter
449 450 451 452 453 454 455 |
# File 'lib/soc_maker/soc_def.rb', line 449 def get_sparam( core, param ) consistence_error "Core '#{core}' does not exist in this SOC" if @static[ core ] == nil consistence_error "Parameter '#{param}' does not exist for core '#{core}'" if @static[ core ][ param ] == nil return @static[ core ][ param ] end |
#ifc_in_use?(inst_name, ifc_name) ⇒ Boolean
Method to check, if the interface of an instance is already connected
inst_name
-
name of the instance
ifc_name
-
name of the interface
251 252 253 254 255 256 257 258 259 260 261 |
# File 'lib/soc_maker/soc_def.rb', line 251 def ifc_in_use?( inst_name, ifc_name ) # go through all connections and check, # that non of the interfaces we want to connect is used @cons.each do |_con_name, con_def| return true if con_def[ :mapping ][ 0 ][ inst_name] == ifc_name return true if con_def[ :mapping ][ 1 ][ inst_name] == ifc_name end return false end |
#init_with(coder) ⇒ Object
Initialization method (from yaml)
coder
-
An instance of the Psych::Coder to init this class from a YAML file
127 128 129 130 131 132 133 134 |
# File 'lib/soc_maker/soc_def.rb', line 127 def init_with( coder ) init_error_if !( coder.is_a?( Hash ) || coder.is_a?( Psych::Coder ) ), 'coder is not given as Hash neither as Psych::Coder' super coder @cores = coder[ 'cores' ] || {} @static = coder[ 'static' ] || {} @cons = coder[ 'cons' ] || {} end |
#inst_connections(inst_name) ⇒ Object
Method to get all connections of an instance
inst_name
-
Instance name (as symbol)
return
-
A connection hash
481 482 483 484 485 486 487 488 489 490 |
# File 'lib/soc_maker/soc_def.rb', line 481 def inst_connections( inst_name ) connections = {}; @cons.each do |con_name, con| if con[ :mapping ][ 0 ].select{ |k,v| k == inst_name }.size > 0 || con[ :mapping ][ 1 ].select{ |k,v| k == inst_name }.size > 0 connections[ con_name ] = con end end return connections end |
#inst_in_use?(inst_name) ⇒ Boolean
Check, if the instance name is already used within this SOC
198 199 200 |
# File 'lib/soc_maker/soc_def.rb', line 198 def inst_in_use?( inst_name ) return ( @cores[ inst_name ] != nil or @cons[ inst_name ] != nil ) end |
#is_it_me?(inst_name) ⇒ Boolean
Method to check, if inst_name means this SOC. For connecting cores, the instance name is used. But If a toplevel connection to a core needs to be done, the SOC is identified by @toplevel (even if this is not an instance)
inst_name
-
name of instance
return
-
true if inst_name == @toplevel.to_sym, otherwise false
188 189 190 191 |
# File 'lib/soc_maker/soc_def.rb', line 188 def is_it_me?( inst_name ) # TODO: is there a better way to identify self via @toplevel? inst_name == @toplevel.to_sym end |
#port(ifc_name, port_ref) ⇒ Object
Returns a port, identified by the interface and port name Note: this behaviour is exactly the same than of core_inst.port(…), but these ports are not evaluated.
ifc_name
-
name of the interface
port_ref
-
name of the port
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 |
# File 'lib/soc_maker/soc_def.rb', line 751 def port( ifc_name, port_ref ) ifc = @interfaces[ ifc_name ] # get interface specification ifc_spc = SOCMaker::lib.get_ifc( ifc.id ) # get the port port_tmp = ifc.ports.select{ |k,v| v.spc_ref.to_sym == port_ref } # get the reference to the port definition defn_ref = port_tmp.first[1].spc_ref.to_sym _port_name = port_tmp.first[0].to_s if ifc_spc.ports[ defn_ref ][ :dir ] == 2 _port_dir = 1 ^ ifc.dir else _port_dir = ifc_spc.ports[ defn_ref ][ :dir ] ^ ifc.dir end _port_default = ifc_spc.ports[ defn_ref ][ :default ] _port_len = port_tmp.first[1].len return [ _port_name, { len: _port_len, dir: _port_dir, default: _port_default, ref: port_tmp.first[1].spc_ref } ] end |
#port_length(ifc_name, port_name, inst) ⇒ Object
Method to get the port length. All arguments as symbol.
ifc_name
-
name of the interface
port_name
-
name of the port
inst
-
name of the instance
271 272 273 274 275 276 277 278 279 280 |
# File 'lib/soc_maker/soc_def.rb', line 271 def port_length( ifc_name, port_name, inst ) if @cores[ inst ] != nil return @cores[ inst ].port_length( ifc_name, port_name ) elsif is_it_me?( inst ) tmp = @interfaces[ ifc_name ].ports.select{ |k,v| v.spc_ref == port_name.to_s } return tmp.values.first.len else return nil end end |
#rm(inst_name) ⇒ Object
Method to remove a instance
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/soc_maker/soc_def.rb', line 205 def rm( inst_name ) if @cores[ inst_name ] != nil @cores.delete( inst_name ) # remove all connection entries of this core @cons.each do |_con_name, con_def| con_def[ :mapping ][ 0 ].delete( inst_name ) if con_def[ :mapping ][ 0 ].has_key?( inst_name ) con_def[ :mapping ][ 1 ].delete( inst_name ) if con_def[ :mapping ][ 1 ].has_key?( inst_name ) end elsif @cons[ inst_name ] != nil @cons.delete( inst_name ) else consistence_error( "Can't remove instance #{inst_name}" ) end end |
#set_param(instance, param, value) ⇒ Object
Method to set an instance parameter
instance
-
name of the instance
param
-
name of the parameter
vlue
-
value, which is set
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
# File 'lib/soc_maker/soc_def.rb', line 382 def set_param( instance, param, value ) # get instance core_inst = @cores[ instance ] consistence_error "Can't find '#{instance}' in SOC" if core_inst == nil # get the core-definition core_def = SOCMaker::lib.get_core( core_inst.type ) # check if parameter exist if core_def.inst_parameters[ param ] != nil core_inst.params[ param ] = value else consistence_error "Parameter '#{param}' not found in '#{core_def.name}'" end end |
#set_sparam(core, param, value) ⇒ Object
Method to set a static parameter
instance
-
name of the instance
param
-
name of the parameter
vlue
-
value, which is set
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
# File 'lib/soc_maker/soc_def.rb', line 424 def set_sparam( core, param, value ) #get instance # check, if we are instantiating this core processing_error_if( @cores.select{ |name,inst| inst.type == core }.size == 0, "Core '#{core}' is not instantiated in this SOC" ) # get the core-definition core_def = SOCMaker::lib.get_core( core ) # check if parameter exist processing_error_if( core_def.static_parameters.select{ |f,p| p.parameters[ param ] != nil }.size == 0, "Parameter '#{param}' not found in '#{core_def.name}'" ) @static[ core ] ||= {} @static[ core ][ param ] = value end |
#to_s ⇒ Object
Returns a string describing this instance
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 |
# File 'lib/soc_maker/soc_def.rb', line 813 def to_s tmp = "_________ SOC #{@name}: _______\n" + super + "\n__connections__\n" @cons.each do |_con_name, con_def| tmp += "#{_con_name}: #{con_def}\n" end tmp += "\n__cores__\n" @cores.each do |inst_name, inst| tmp += "#{inst_name}:\n#{inst}\n" end tmp += "\n__interfaces__\n" @interfaces.each do |ifc_name, ifc| tmp += "#{ifc_name}:#{ifc.id}\n" end tmp += "'''''''''''''''''''''''''''''''''''\n" return tmp end |
#top_connections(inst_name) ⇒ Object
Method to get all connections which connected to the top
inst_name
-
Instance name (as symbol)
return
-
A connection hash
499 500 501 502 503 504 505 |
# File 'lib/soc_maker/soc_def.rb', line 499 def top_connections( inst_name ) inst = inst_connections( inst_name ) top = inst_connections( toplevel.to_sym ) tmp = inst.keys & top.keys return inst.select{ |k,v| tmp.include?( k ) } end |