soc_maker 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/History.txt +4 -0
- data/LICENSE +678 -0
- data/README.rdoc +228 -0
- data/Rakefile +46 -0
- data/bin/soc_maker_cli +80 -0
- data/bin/soc_maker_parser +85 -0
- data/core_lib/cores/adv_debug_sys/01_adv_debug_sys.yaml +245 -0
- data/core_lib/cores/or1200_rel2/01_or1200.yaml +208 -0
- data/core_lib/cores/or1200_rel2/02_or1200_files.yaml +421 -0
- data/core_lib/cores/or1200_rel2/03_or1200_sparam.yaml +188 -0
- data/core_lib/cores/or1200_rel2/or1200_defines.v.in +1799 -0
- data/core_lib/cores/ram_wb/ram_wb.yaml +102 -0
- data/core_lib/cores/ram_wb/ram_wb_b3.v.in +259 -0
- data/core_lib/cores/uart16550/01_uart16550.yaml +99 -0
- data/core_lib/cores/uart16550/02_uart16550_files.yaml +70 -0
- data/core_lib/cores/wb_connect/minsoc_tc_top.v +1802 -0
- data/core_lib/cores/wb_connect/wb_connect.yaml +733 -0
- data/core_lib/inc.yaml +13 -0
- data/core_lib/interfaces/clk_rst/clk.yaml +9 -0
- data/core_lib/interfaces/clk_rst/rst.yaml +9 -0
- data/core_lib/interfaces/clk_rst/single.yaml +7 -0
- data/core_lib/interfaces/debug/debug.yaml +32 -0
- data/core_lib/interfaces/jtag/jtag.yaml +13 -0
- data/core_lib/interfaces/jtag/jtag_tap.yaml +22 -0
- data/core_lib/interfaces/power/or_power.yaml +25 -0
- data/core_lib/interfaces/uart/uart.yaml +21 -0
- data/core_lib/interfaces/wishbone/wishbone_ma_b3.yaml +54 -0
- data/core_lib/interfaces/wishbone/wishbone_sl_b3.yaml +51 -0
- data/doc/class_arch.uml +5113 -0
- data/doc/fig/hierarchical.svg +273 -0
- data/examples/or1200_test/or1200_test.cmd +78 -0
- data/examples/or1200_test/or1200_test.rb +136 -0
- data/examples/or1200_test/rtl/or1200_test_top.vhd +274 -0
- data/examples/or1200_test/rtl/s3astarter.ucf +10 -0
- data/examples/or1200_test/rtl/xilinx_internal_jtag.v +438 -0
- data/examples/or1200_test/rtl/xilinx_internal_jtag_options.v +12 -0
- data/examples/or1200_test/sw/README.txt +35 -0
- data/examples/or1200_test/sw/bin2vmem.c +159 -0
- data/examples/or1200_test/sw/board.h +24 -0
- data/examples/or1200_test/sw/compile.sh +18 -0
- data/examples/or1200_test/sw/except.S +152 -0
- data/examples/or1200_test/sw/int.c +79 -0
- data/examples/or1200_test/sw/int.h +14 -0
- data/examples/or1200_test/sw/interconnect.h +17 -0
- data/examples/or1200_test/sw/interrupts.c +14 -0
- data/examples/or1200_test/sw/main.c +16 -0
- data/examples/or1200_test/sw/or1200.h +454 -0
- data/examples/or1200_test/sw/orp.ld +60 -0
- data/examples/or1200_test/sw/reset.S +112 -0
- data/examples/or1200_test/sw/support.c +123 -0
- data/examples/or1200_test/sw/support.h +33 -0
- data/examples/or1200_test/sw/tick.c +30 -0
- data/examples/or1200_test/sw/tick.h +2 -0
- data/examples/or1200_test/sw/uart.c +136 -0
- data/examples/or1200_test/sw/uart.h +126 -0
- data/lib/soc_maker.rb +324 -0
- data/lib/soc_maker/cli.rb +544 -0
- data/lib/soc_maker/conf.rb +310 -0
- data/lib/soc_maker/core_def.rb +579 -0
- data/lib/soc_maker/core_inst.rb +305 -0
- data/lib/soc_maker/err.rb +211 -0
- data/lib/soc_maker/hdl_coder.rb +500 -0
- data/lib/soc_maker/hdl_file.rb +166 -0
- data/lib/soc_maker/hdl_parser.rb +431 -0
- data/lib/soc_maker/ifc_def.rb +193 -0
- data/lib/soc_maker/ifc_port.rb +133 -0
- data/lib/soc_maker/ifc_spc.rb +180 -0
- data/lib/soc_maker/lib.rb +289 -0
- data/lib/soc_maker/lib_inc.rb +109 -0
- data/lib/soc_maker/parameter.rb +149 -0
- data/lib/soc_maker/soc_def.rb +847 -0
- data/lib/soc_maker/sparameter.rb +289 -0
- data/lib/soc_maker/version.rb +8 -0
- data/lib/soc_maker/ypp.rb +130 -0
- data/soc_maker.gemspec +28 -0
- data/spec/cli_cmds1.txt +39 -0
- data/spec/cli_spec.rb +49 -0
- data/spec/conf_spec.rb +44 -0
- data/spec/core_def_spec.rb +503 -0
- data/spec/core_inst_spec.rb +169 -0
- data/spec/hdl_file_spec.rb +154 -0
- data/spec/hdl_parser_spec.rb +201 -0
- data/spec/ifc_def_spec.rb +121 -0
- data/spec/ifc_port_spec.rb +92 -0
- data/spec/ifc_spc_spec.rb +196 -0
- data/spec/lib_inc_spec.rb +99 -0
- data/spec/lib_spec.rb +209 -0
- data/spec/parameter_spec.rb +86 -0
- data/spec/soc_def_spec.rb +611 -0
- data/spec/soc_maker_spec.rb +7 -0
- data/spec/sparameter_spec.rb +182 -0
- data/spec/spec_helper.rb +78 -0
- data/spec/test_soc.yaml +105 -0
- data/spec/test_soc2.yaml +60 -0
- data/spec/test_soc_lib/cores/core_A_rel1/00_core_a.yaml +75 -0
- data/spec/test_soc_lib/cores/core_A_rel1/01_core_a.yaml +57 -0
- data/spec/test_soc_lib/cores/core_A_rel1/core_a.vhd +29 -0
- data/spec/test_soc_lib/cores/core_A_rel1/core_a_pkg.vhd.src +3 -0
- data/spec/test_soc_lib/cores/core_A_rel1/core_a_pkg2.vhd.src +4 -0
- data/spec/test_soc_lib/cores/core_A_rel1/core_a_pkg3.v.src +6 -0
- data/spec/test_soc_lib/cores/core_B_rel1/core_b.vhd +25 -0
- data/spec/test_soc_lib/cores/core_B_rel1/core_b.yaml +36 -0
- data/spec/test_soc_lib/cores/core_C_v1/core_C.vhd +57 -0
- data/spec/test_soc_lib/cores/core_C_v1/core_c.yaml +42 -0
- data/spec/test_soc_lib/cores/soc_A/soc_A.yaml +12 -0
- data/spec/test_soc_lib/cores/soc_maker_include.yaml +6 -0
- data/spec/test_soc_lib/ifcs/core_AB_ifc/bidir_ifc.yaml +19 -0
- data/spec/test_soc_lib/ifcs/core_AB_ifc/core_AB_ifc.yaml +15 -0
- data/spec/test_soc_lib/ifcs/core_AB_ifc/top_ifc.yaml +9 -0
- data/spec/test_soc_lib/soc_maker_include.yaml +4 -0
- data/spec/yaml_examples.rb +367 -0
- data/spec/ypp_spec.rb +156 -0
- data/test/test_soc_maker.rb +0 -0
- metadata +255 -0
@@ -0,0 +1,847 @@
|
|
1
|
+
###############################################################
|
2
|
+
#
|
3
|
+
# File: soc_def.rb
|
4
|
+
#
|
5
|
+
# Author: Christian Hättich
|
6
|
+
#
|
7
|
+
# Project: System-On-Chip Maker
|
8
|
+
#
|
9
|
+
# Target: Linux / Windows / Mac
|
10
|
+
#
|
11
|
+
# Language: ruby
|
12
|
+
#
|
13
|
+
#
|
14
|
+
###############################################################
|
15
|
+
#
|
16
|
+
#
|
17
|
+
# Copyright (C) 2014 Christian Hättich - feddischson [ at ] opencores.org
|
18
|
+
#
|
19
|
+
# This program is free software: you can redistribute it and/or modify
|
20
|
+
# it under the terms of the GNU General Public License as published by
|
21
|
+
# the Free Software Foundation, either version 3 of the License, or
|
22
|
+
# (at your option) any later version.
|
23
|
+
#
|
24
|
+
# This program is distributed in the hope that it will be useful,
|
25
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
26
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
27
|
+
# GNU General Public License for more details.
|
28
|
+
#
|
29
|
+
# You should have received a copy of the GNU General Public License
|
30
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
31
|
+
#
|
32
|
+
#
|
33
|
+
###############################################################
|
34
|
+
module SOCMaker
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
#
|
39
|
+
# This class represents a System-on-chip and derives
|
40
|
+
# the functionallity from SOCMaker::CoreDef.
|
41
|
+
# The two important fields are
|
42
|
+
# - #cores: holds all core-instances
|
43
|
+
# - #cons: holds all connections
|
44
|
+
# In addition, the field @static is used to store
|
45
|
+
# static parameters, which are set for cores used in this SOC.
|
46
|
+
class SOCDef < CoreDef
|
47
|
+
include ERR
|
48
|
+
include YAML_EXT
|
49
|
+
|
50
|
+
#
|
51
|
+
# Hash of cores (core instances: SOCMaker::CoreInst)
|
52
|
+
#
|
53
|
+
attr_accessor :cores
|
54
|
+
|
55
|
+
#
|
56
|
+
# Hash of all connections.
|
57
|
+
# The structure is the following
|
58
|
+
#
|
59
|
+
# @cons = { :connection_name_1 => {
|
60
|
+
# :mapping => [
|
61
|
+
# { :instance_1 => :interface_of_instance_1, #\ dir=0
|
62
|
+
# :instance_2 => :interface_of_instance_2, #/
|
63
|
+
# ...},
|
64
|
+
# { :instance_3 => :interface_of_instance_3, #\ dir=1
|
65
|
+
# :instance_4 => :interface_of_instance_4, #/
|
66
|
+
# ...}
|
67
|
+
# ] },
|
68
|
+
#
|
69
|
+
# :connection_name_2 => {
|
70
|
+
# :mapping => [
|
71
|
+
# { :instance_a => :interface_of_instance_a, #\ dir=0
|
72
|
+
# :instance_b => :interface_of_instance_b, #/
|
73
|
+
# ...},
|
74
|
+
# { :instance_c => :interface_of_instance_c, #\ dir=1
|
75
|
+
# :instance_d => :interface_of_instance_d, #/
|
76
|
+
# ...}
|
77
|
+
# ] },
|
78
|
+
# ....
|
79
|
+
#
|
80
|
+
# }
|
81
|
+
# The important part is the mapping: it is a list with two entries. Ech
|
82
|
+
# entry is a Hash containing instance-interface assignments.
|
83
|
+
#
|
84
|
+
# <tt>TODO: this needs to be re-designed, because it allowes only
|
85
|
+
# one core to be used in one connection-direction.</tt>
|
86
|
+
#
|
87
|
+
#
|
88
|
+
#
|
89
|
+
#
|
90
|
+
attr_accessor :cons
|
91
|
+
|
92
|
+
#
|
93
|
+
# Hash of all static parameters defined within this SOC
|
94
|
+
#
|
95
|
+
attr_accessor :static
|
96
|
+
|
97
|
+
# This constructor expects the name, an id, the toplevel-name
|
98
|
+
# as mandatory arguments. All other attributes can be privided
|
99
|
+
# as optional argument
|
100
|
+
def initialize( name, id, toplevel, optional = {} )
|
101
|
+
|
102
|
+
init_with( { 'name' => name,
|
103
|
+
'id' => id,
|
104
|
+
'toplevel' => toplevel }.merge( optional ) )
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# Encoder method (to yaml)
|
110
|
+
#
|
111
|
+
# +coder+:: An instance of the Psych::Coder to encode this class to a YAML file
|
112
|
+
#
|
113
|
+
def encode_with( coder )
|
114
|
+
init_error_if !coder.is_a?( Psych::Coder ),
|
115
|
+
'coder is not given as Psych::Coder'
|
116
|
+
super coder
|
117
|
+
%w[ cores cons static ].
|
118
|
+
each { |v| coder[ v ] = instance_variable_get "@#{v}" }
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Initialization method (from yaml)
|
123
|
+
#
|
124
|
+
# +coder+:: An instance of the Psych::Coder to init this class from a YAML file
|
125
|
+
#
|
126
|
+
#
|
127
|
+
def init_with( coder )
|
128
|
+
init_error_if !( coder.is_a?( Hash ) || coder.is_a?( Psych::Coder ) ),
|
129
|
+
'coder is not given as Hash neither as Psych::Coder'
|
130
|
+
super coder
|
131
|
+
@cores = coder[ 'cores' ] || {}
|
132
|
+
@static = coder[ 'static' ] || {}
|
133
|
+
@cons = coder[ 'cons' ] || {}
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
#
|
138
|
+
# Consistence check method:
|
139
|
+
# - ensures, that all cores are available and consistent
|
140
|
+
# - ensures, that all connections are possible
|
141
|
+
#
|
142
|
+
#
|
143
|
+
def consistence_check
|
144
|
+
super
|
145
|
+
|
146
|
+
@cores.values.each do |inst|
|
147
|
+
inst.consistence_check
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
@cons.each do |con_name, con_def|
|
152
|
+
con_def[ :mapping ].each_with_index do |mapping,dir|
|
153
|
+
mapping.each do |inst_name, ifc_name|
|
154
|
+
if !is_it_me?( inst_name )
|
155
|
+
consistence_error "#{inst_name} not does not exist in SOCDef #{@name}" if @cores[ inst_name ] == nil
|
156
|
+
end
|
157
|
+
|
158
|
+
core_def = core_definition( inst_name ) or
|
159
|
+
consistence_error "Can't find definition of core #{inst_name}"
|
160
|
+
|
161
|
+
consistence_error "Interface #{ifc_name} doesn exist in #{core_def.name}" if core_def.interfaces[ ifc_name ] == nil
|
162
|
+
|
163
|
+
consistence_error "Wrong connection definition of #{inst_name}:#{ifc_name}",
|
164
|
+
direction: core_def.interfaces[ ifc_name ].dir,
|
165
|
+
localtion: dir,
|
166
|
+
internal: is_it_me?( inst_name ) if !(
|
167
|
+
( (core_def.interfaces[ ifc_name ].dir != dir) && is_it_me?( inst_name ) ) ||
|
168
|
+
( (core_def.interfaces[ ifc_name ].dir == dir) && !is_it_me?( inst_name ) ) )
|
169
|
+
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
#
|
180
|
+
# Method to check, if inst_name means this SOC.
|
181
|
+
# For connecting cores, the instance name is used. But
|
182
|
+
# If a toplevel connection to a core needs to be done, the SOC
|
183
|
+
# is identified by @toplevel (even if this is not an instance)
|
184
|
+
#
|
185
|
+
# +inst_name+:: name of instance
|
186
|
+
# +return+:: true if inst_name == @toplevel.to_sym, otherwise false
|
187
|
+
#
|
188
|
+
def is_it_me?( inst_name )
|
189
|
+
# TODO: is there a better way to identify self via @toplevel?
|
190
|
+
inst_name == @toplevel.to_sym
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
|
195
|
+
#
|
196
|
+
# Check, if the instance name is already used within this SOC
|
197
|
+
#
|
198
|
+
def inst_in_use?( inst_name )
|
199
|
+
return ( @cores[ inst_name ] != nil or @cons[ inst_name ] != nil )
|
200
|
+
end
|
201
|
+
|
202
|
+
#
|
203
|
+
# Method to remove a instance
|
204
|
+
#
|
205
|
+
def rm( inst_name )
|
206
|
+
|
207
|
+
if @cores[ inst_name ] != nil
|
208
|
+
@cores.delete( inst_name )
|
209
|
+
|
210
|
+
# remove all connection entries of this core
|
211
|
+
@cons.each do |_con_name, con_def|
|
212
|
+
con_def[ :mapping ][ 0 ].delete( inst_name ) if con_def[ :mapping ][ 0 ].has_key?( inst_name )
|
213
|
+
con_def[ :mapping ][ 1 ].delete( inst_name ) if con_def[ :mapping ][ 1 ].has_key?( inst_name )
|
214
|
+
end
|
215
|
+
|
216
|
+
elsif @cons[ inst_name ] != nil
|
217
|
+
@cons.delete( inst_name )
|
218
|
+
else
|
219
|
+
consistence_error( "Can't remove instance #{inst_name}" )
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
#
|
225
|
+
# Add an instance to the SoC
|
226
|
+
#
|
227
|
+
# +id+:: the core ID, used to get the desired core from SOCMaker::Lib
|
228
|
+
# +inst_name+:: name of the instance
|
229
|
+
#
|
230
|
+
def add_core( id, inst_name )
|
231
|
+
|
232
|
+
consistence_error_if(
|
233
|
+
inst_in_use?( inst_name ),
|
234
|
+
"Instance name #{inst_name} is already in use" )
|
235
|
+
|
236
|
+
# check, if the core exits in our library
|
237
|
+
# if not: an error will be raised
|
238
|
+
SOCMaker::lib.get_core( id )
|
239
|
+
|
240
|
+
@cores[ inst_name ] = SOCMaker::CoreInst.new( id )
|
241
|
+
end
|
242
|
+
|
243
|
+
|
244
|
+
#
|
245
|
+
# Method to check, if the interface of an instance is already
|
246
|
+
# connected
|
247
|
+
#
|
248
|
+
# +inst_name+:: name of the instance
|
249
|
+
# +ifc_name+:: name of the interface
|
250
|
+
#
|
251
|
+
def ifc_in_use?( inst_name, ifc_name )
|
252
|
+
|
253
|
+
# go through all connections and check,
|
254
|
+
# that non of the interfaces we want to connect is used
|
255
|
+
@cons.each do |_con_name, con_def|
|
256
|
+
return true if con_def[ :mapping ][ 0 ][ inst_name] == ifc_name
|
257
|
+
return true if con_def[ :mapping ][ 1 ][ inst_name] == ifc_name
|
258
|
+
end
|
259
|
+
return false
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
|
264
|
+
#
|
265
|
+
# Method to get the port length. All arguments as symbol.
|
266
|
+
#
|
267
|
+
# +ifc_name+:: name of the interface
|
268
|
+
# +port_name+:: name of the port
|
269
|
+
# +inst+:: name of the instance
|
270
|
+
#
|
271
|
+
def port_length( ifc_name, port_name, inst )
|
272
|
+
if @cores[ inst ] != nil
|
273
|
+
return @cores[ inst ].port_length( ifc_name, port_name )
|
274
|
+
elsif is_it_me?( inst )
|
275
|
+
tmp = @interfaces[ ifc_name ].ports.select{ |k,v| v.spc_ref == port_name.to_s }
|
276
|
+
return tmp.values.first.len
|
277
|
+
else
|
278
|
+
return nil
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
|
283
|
+
#
|
284
|
+
# Method to get the core definition.
|
285
|
+
#
|
286
|
+
#
|
287
|
+
# +inst+:: instance name (as symbol)
|
288
|
+
# +return+:: nil, if there is no core with the
|
289
|
+
# name and if it is not this SOC
|
290
|
+
#
|
291
|
+
def core_definition( inst )
|
292
|
+
if @cores[ inst ] != nil
|
293
|
+
return @cores[ inst ].defn
|
294
|
+
|
295
|
+
elsif is_it_me?( inst )
|
296
|
+
return self
|
297
|
+
else
|
298
|
+
return nil
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
|
303
|
+
|
304
|
+
|
305
|
+
|
306
|
+
#
|
307
|
+
# Method add/modify a connection.
|
308
|
+
# The number of arguments are variable and multiple entries can be provided as once.
|
309
|
+
#
|
310
|
+
# +args+:: number of arguments must be >3 and odd. The first argument defines
|
311
|
+
# the connection name. The following arguments are treaded as pairs. Each
|
312
|
+
# pair consists of the instance name and the interface name.
|
313
|
+
#
|
314
|
+
#
|
315
|
+
#
|
316
|
+
def add_connection( *args )
|
317
|
+
|
318
|
+
if args.size < 3 || args.size % 2 != 1
|
319
|
+
processing_error "FATAL: wrong number of arguments: " +
|
320
|
+
"(#{args.size}) must be > = 3 and odd"
|
321
|
+
end
|
322
|
+
|
323
|
+
consistence_check
|
324
|
+
|
325
|
+
|
326
|
+
con_name = args[0]
|
327
|
+
args[ 1..-1].each_slice(2).to_a.each do |entry|
|
328
|
+
inst_name = entry[0]
|
329
|
+
ifc_name = entry[1]
|
330
|
+
|
331
|
+
# get the core definition
|
332
|
+
core_def = core_definition( inst_name ) or
|
333
|
+
consistence_error "Can't find definition of core #{inst_name}"
|
334
|
+
|
335
|
+
|
336
|
+
consistence_error_if ifc_in_use?( inst_name, ifc_name ),
|
337
|
+
"Interface #{ifc_name} of instance '#{inst_name}' is already in use "
|
338
|
+
|
339
|
+
|
340
|
+
consistence_error_if core_def.interfaces[ ifc_name ] == nil,
|
341
|
+
"Interface '#{ifc_name}' dosn't exist in core '#{inst_name}' \n" +
|
342
|
+
"The following interfaces do exist: '#{core_def.interfaces.keys}'"
|
343
|
+
|
344
|
+
# get the interface specification
|
345
|
+
ifc_spc = core_def.ifc_specification( ifc_name )
|
346
|
+
|
347
|
+
# get the directions
|
348
|
+
ifc_dir = core_def.interfaces[ ifc_name ].dir
|
349
|
+
|
350
|
+
ifc_dir = ( ifc_dir + 1 ) % 2 if is_it_me?( inst_name )
|
351
|
+
|
352
|
+
|
353
|
+
# create a new connection, if there is no one
|
354
|
+
if @cons[ con_name ] == nil
|
355
|
+
@cons[ con_name ] = { mapping: [ {},{} ] }
|
356
|
+
end
|
357
|
+
|
358
|
+
if ifc_spc.n_connections_ok?( ifc_dir, @cons[ con_name ][ :mapping ][ ifc_dir ].size+1 )
|
359
|
+
@cons[ con_name ][ :mapping ][ ifc_dir ][ inst_name ] = ifc_name
|
360
|
+
else
|
361
|
+
consistence_error "Only #{ ifc_spc.multiplicity[ ifc_dir ] } " +
|
362
|
+
"connections are allowed for direction #{ifc_dir}",
|
363
|
+
connection: con_name,
|
364
|
+
instance: inst_name,
|
365
|
+
interface: ifc_name
|
366
|
+
|
367
|
+
end
|
368
|
+
|
369
|
+
end
|
370
|
+
|
371
|
+
|
372
|
+
end
|
373
|
+
|
374
|
+
|
375
|
+
#
|
376
|
+
# Method to set an instance parameter
|
377
|
+
#
|
378
|
+
# +instance+:: name of the instance
|
379
|
+
# +param+:: name of the parameter
|
380
|
+
# +vlue+:: value, which is set
|
381
|
+
#
|
382
|
+
def set_param( instance, param, value )
|
383
|
+
|
384
|
+
# get instance
|
385
|
+
core_inst = @cores[ instance ]
|
386
|
+
consistence_error "Can't find '#{instance}' in SOC" if core_inst == nil
|
387
|
+
|
388
|
+
# get the core-definition
|
389
|
+
core_def = SOCMaker::lib.get_core( core_inst.type )
|
390
|
+
|
391
|
+
# check if parameter exist
|
392
|
+
if core_def.inst_parameters[ param ] != nil
|
393
|
+
core_inst.params[ param ] = value
|
394
|
+
else
|
395
|
+
consistence_error "Parameter '#{param}' not found in '#{core_def.name}'"
|
396
|
+
end
|
397
|
+
|
398
|
+
end
|
399
|
+
|
400
|
+
#
|
401
|
+
# Method to get an instance parameter
|
402
|
+
#
|
403
|
+
# +instance+:: name of the instance
|
404
|
+
# +param+:: name of the parameter
|
405
|
+
#
|
406
|
+
def get_param( instance, param )
|
407
|
+
|
408
|
+
# get instance
|
409
|
+
core_inst = @cores[ instance ]
|
410
|
+
consistence_error "Can't find '#{instance}' in SOC" if core_inst == nil
|
411
|
+
param_val = core_inst.params[ param ]
|
412
|
+
consistence_error "Can't find parameter '#{param}' in '#{instance}'" if param_val == nil
|
413
|
+
return param_val
|
414
|
+
end
|
415
|
+
|
416
|
+
|
417
|
+
#
|
418
|
+
# Method to set a static parameter
|
419
|
+
#
|
420
|
+
# +instance+:: name of the instance
|
421
|
+
# +param+:: name of the parameter
|
422
|
+
# +vlue+:: value, which is set
|
423
|
+
#
|
424
|
+
def set_sparam( core, param, value )
|
425
|
+
|
426
|
+
#get instance
|
427
|
+
|
428
|
+
# check, if we are instantiating this core
|
429
|
+
processing_error_if( @cores.select{ |name,inst| inst.type == core }.size == 0,
|
430
|
+
"Core '#{core}' is not instantiated in this SOC" )
|
431
|
+
|
432
|
+
# get the core-definition
|
433
|
+
core_def = SOCMaker::lib.get_core( core )
|
434
|
+
|
435
|
+
# check if parameter exist
|
436
|
+
processing_error_if( core_def.static_parameters.select{ |f,p| p.parameters[ param ] != nil }.size == 0,
|
437
|
+
"Parameter '#{param}' not found in '#{core_def.name}'" )
|
438
|
+
|
439
|
+
@static[ core ] ||= {}
|
440
|
+
@static[ core ][ param ] = value
|
441
|
+
end
|
442
|
+
|
443
|
+
#
|
444
|
+
# Method to get a static parameter
|
445
|
+
#
|
446
|
+
# +instance+:: name of the instance
|
447
|
+
# +param+:: name of the parameter
|
448
|
+
#
|
449
|
+
def get_sparam( core, param )
|
450
|
+
consistence_error "Core '#{core}' does not exist in this SOC" if @static[ core ] == nil
|
451
|
+
|
452
|
+
consistence_error "Parameter '#{param}' does not exist for core '#{core}'" if @static[ core ][ param ] == nil
|
453
|
+
|
454
|
+
return @static[ core ][ param ]
|
455
|
+
end
|
456
|
+
|
457
|
+
|
458
|
+
|
459
|
+
#
|
460
|
+
# Method, to deploy this SOC:
|
461
|
+
# It runs gen_toplevel and calls also super to
|
462
|
+
# copy files, which are added in addition to this SOC.
|
463
|
+
#
|
464
|
+
# +options+:: Common entries are coder and static:
|
465
|
+
# coder must be a SOCMaker::Coder and static must be a hash
|
466
|
+
# of static parameters.
|
467
|
+
#
|
468
|
+
def deploy( options = {} )
|
469
|
+
options = { coder: VHDLCoder.new }.merge( options )
|
470
|
+
gen_toplevel( options[ :coder ] )
|
471
|
+
super( options )
|
472
|
+
end
|
473
|
+
|
474
|
+
|
475
|
+
#
|
476
|
+
# Method to get all connections of an instance
|
477
|
+
# +inst_name+:: Instance name (as symbol)
|
478
|
+
# +return+:: A connection hash
|
479
|
+
#
|
480
|
+
#
|
481
|
+
def inst_connections( inst_name )
|
482
|
+
connections = {};
|
483
|
+
@cons.each do |con_name, con|
|
484
|
+
if con[ :mapping ][ 0 ].select{ |k,v| k == inst_name }.size > 0 ||
|
485
|
+
con[ :mapping ][ 1 ].select{ |k,v| k == inst_name }.size > 0
|
486
|
+
connections[ con_name ] = con
|
487
|
+
end
|
488
|
+
end
|
489
|
+
return connections
|
490
|
+
end
|
491
|
+
|
492
|
+
|
493
|
+
#
|
494
|
+
# Method to get all connections which connected to
|
495
|
+
# the top
|
496
|
+
# +inst_name+:: Instance name (as symbol)
|
497
|
+
# +return+:: A connection hash
|
498
|
+
#
|
499
|
+
def top_connections( inst_name )
|
500
|
+
inst = inst_connections( inst_name )
|
501
|
+
top = inst_connections( toplevel.to_sym )
|
502
|
+
|
503
|
+
tmp = inst.keys & top.keys
|
504
|
+
return inst.select{ |k,v| tmp.include?( k ) }
|
505
|
+
end
|
506
|
+
|
507
|
+
|
508
|
+
|
509
|
+
|
510
|
+
#
|
511
|
+
# Generate toplevel hdl file for this instance.
|
512
|
+
# This assumes, that this instance represents a SOC with
|
513
|
+
# further instances.
|
514
|
+
#
|
515
|
+
#
|
516
|
+
# +coder+:: An instance of the SOCMaker::HDLCoder, which is used to
|
517
|
+
# create the auto-generated HDL (optional).
|
518
|
+
# If no coder is given, a SOCMaker::VHDLCoder is used.
|
519
|
+
#
|
520
|
+
#
|
521
|
+
def gen_toplevel( coder = VHDLCoder.new )
|
522
|
+
|
523
|
+
|
524
|
+
#
|
525
|
+
# Get filename
|
526
|
+
#
|
527
|
+
file_name = coder.filename( dir_name )
|
528
|
+
dst_dir = CoreDef::get_and_ensure_dst_dir!( dir_name )
|
529
|
+
|
530
|
+
SOCMaker::logger.proc( "START of creating top-level '" + file_name + "'" )
|
531
|
+
|
532
|
+
|
533
|
+
#
|
534
|
+
# Create a unique list of cores and
|
535
|
+
# add for each core a component statement (vhdl only).
|
536
|
+
# Even if there are multiple instances of a core,
|
537
|
+
# we need to decalre it only once
|
538
|
+
#
|
539
|
+
@cores.values.uniq{|x| x.type }.each do |inst; spec|
|
540
|
+
|
541
|
+
spec = SOCMaker::lib.get_core( inst.type )
|
542
|
+
processing_error "Can't find #{ inst.type } in SOC library" if !spec
|
543
|
+
|
544
|
+
coder.add_core_component( inst.type, spec )
|
545
|
+
end
|
546
|
+
|
547
|
+
|
548
|
+
top_connections = {}
|
549
|
+
|
550
|
+
#
|
551
|
+
# Instanciate each core
|
552
|
+
#
|
553
|
+
@cores.each do |inst_name, inst|
|
554
|
+
|
555
|
+
# get all connections of this instance, which are connected
|
556
|
+
# to top and are single-entry connections
|
557
|
+
top_cons_tmp = top_connections( inst_name )
|
558
|
+
top_cons_tmp = top_cons_tmp.select{ |k,v| v[:mapping][0].size == 1 && v[:mapping][1].size == 1 }
|
559
|
+
top_cons_tmp.keys.each do |con_name|
|
560
|
+
@cons[ con_name ][ :top_assigned ] = true
|
561
|
+
end
|
562
|
+
coder.add_core_instance( inst_name.to_s, inst, top_cons_tmp, @interfaces, self )
|
563
|
+
top_connections.merge!( top_cons_tmp )
|
564
|
+
end
|
565
|
+
|
566
|
+
|
567
|
+
# create a list of all top-interfaces, which are directly connected
|
568
|
+
# to cores
|
569
|
+
top_connected_ifcs = []
|
570
|
+
top_connections.values.each do |con|
|
571
|
+
if con[ :mapping ][0].has_key?( @toplevel.to_sym )
|
572
|
+
top_connected_ifcs << con[ :mapping ][0][ @toplevel.to_sym ]
|
573
|
+
else
|
574
|
+
top_connected_ifcs << con[ :mapping ][1][ @toplevel.to_sym ]
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
|
579
|
+
# Iterate over all connections:
|
580
|
+
# - create signal instances
|
581
|
+
# - add assignments
|
582
|
+
#
|
583
|
+
@cons.each do |con_name, con_def|
|
584
|
+
if not con_def[ :top_assigned]
|
585
|
+
gen_toplevel_con( con_name.to_s,
|
586
|
+
con_def[ :mapping ][0],
|
587
|
+
con_def[ :mapping ][1],
|
588
|
+
coder )
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
assign_unused_to_default( coder )
|
593
|
+
|
594
|
+
coder.add_toplevel_sig( self, @toplevel, top_connected_ifcs )
|
595
|
+
|
596
|
+
#
|
597
|
+
# Write content to the file
|
598
|
+
#
|
599
|
+
SOCMaker::logger.proc( "writing top-level" )
|
600
|
+
File.open( File.join( dst_dir, file_name ), 'w' ) do |f|
|
601
|
+
f.write( coder.get_hdl_code( self, @toplevel ) )
|
602
|
+
end
|
603
|
+
SOCMaker::logger.proc( "END of creating top-level hdl code for #{@name}" )
|
604
|
+
|
605
|
+
@cons.values.each{ |v| v[ :top_assigned ] = false }
|
606
|
+
|
607
|
+
|
608
|
+
end
|
609
|
+
|
610
|
+
|
611
|
+
|
612
|
+
|
613
|
+
|
614
|
+
|
615
|
+
|
616
|
+
#
|
617
|
+
# Assign default values for unused interfaces.
|
618
|
+
# This is just a helper function and is used by gen_toplevel
|
619
|
+
#
|
620
|
+
# +coder+:: A HDL coder, which is used to create the auto-generated HDL.
|
621
|
+
#
|
622
|
+
def assign_unused_to_default( coder )
|
623
|
+
|
624
|
+
|
625
|
+
|
626
|
+
# iterate over all instances
|
627
|
+
# and check all interfaces
|
628
|
+
@cores.each do |inst_name, inst|
|
629
|
+
|
630
|
+
inst.defn.interfaces.each do |ifc_name, ifc|
|
631
|
+
|
632
|
+
#
|
633
|
+
# Get the interface specification by using the 1st source entry
|
634
|
+
# and searching for the core-definition.
|
635
|
+
#
|
636
|
+
if !ifc_in_use?( inst_name, ifc_name )
|
637
|
+
coder.add_ifc_default_assignment( inst, inst_name, ifc_name )
|
638
|
+
end
|
639
|
+
end
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
#
|
644
|
+
# This function is called during the toplevel generation
|
645
|
+
# for each connection.
|
646
|
+
#
|
647
|
+
# +name+:: The name of the connection
|
648
|
+
# +src+:: Source hash with instance name as key and interface name as value
|
649
|
+
# +dst+:: Destination hash with instance name as key and interface name as value
|
650
|
+
# +coder+:: The HDL coder which is used
|
651
|
+
#
|
652
|
+
def gen_toplevel_con( name, src, dst, coder )
|
653
|
+
|
654
|
+
src_inst = {};
|
655
|
+
dst_inst = {};
|
656
|
+
|
657
|
+
#
|
658
|
+
# Get the interface specification by using the 1st source entry
|
659
|
+
# and searching for the core-definition.
|
660
|
+
#
|
661
|
+
ifc_spec = SOCMaker::lib.get_ifc(
|
662
|
+
core_definition( src.keys.first ).interfaces[ src.values.first ].id )
|
663
|
+
|
664
|
+
|
665
|
+
#
|
666
|
+
# For each signal in the interface specification,
|
667
|
+
# we create a list. The list has an entry for each source
|
668
|
+
# and destination signal, which defines the length.
|
669
|
+
#
|
670
|
+
# In the second step, we compare all values
|
671
|
+
#
|
672
|
+
length_tmp = Hash.new(0);
|
673
|
+
ifc_spec.ports.keys.each do |_name|
|
674
|
+
length_tmp[ _name ] = 0
|
675
|
+
|
676
|
+
ref_val = nil;
|
677
|
+
ref_inst_name = nil;
|
678
|
+
ref_ifc_name = nil;
|
679
|
+
|
680
|
+
|
681
|
+
[ dst, src].each do |con_hash|
|
682
|
+
|
683
|
+
con_hash.each_with_index do | (inst_name, ifc_name), i|
|
684
|
+
|
685
|
+
length = port_length( ifc_name, _name, inst_name )
|
686
|
+
if length.to_i > 0
|
687
|
+
if ref_val == nil
|
688
|
+
ref_val = port_length( ifc_name, _name, inst_name )
|
689
|
+
ref_inst_name = inst_name
|
690
|
+
ref_ifc_name = ifc_name
|
691
|
+
length_tmp[ _name ] = ref_val
|
692
|
+
end
|
693
|
+
|
694
|
+
consistence_error "Can't connect port #{_name}",
|
695
|
+
length_1: ref_val,
|
696
|
+
instance_1: ref_inst_name,
|
697
|
+
interface_1: ref_ifc_name,
|
698
|
+
length_2: length,
|
699
|
+
instance_2: inst_name,
|
700
|
+
interface_2: ifc_name if ref_val.to_i != length.to_i
|
701
|
+
|
702
|
+
length_tmp[ _name ] = length
|
703
|
+
end
|
704
|
+
end
|
705
|
+
end
|
706
|
+
end
|
707
|
+
|
708
|
+
|
709
|
+
#
|
710
|
+
# Prepare a hash for all sources and destinations, where
|
711
|
+
# the instance name is the key and the core-instance is
|
712
|
+
# the value.
|
713
|
+
#
|
714
|
+
src.keys.each do |inst_name|
|
715
|
+
src_inst[ inst_name ] = core_instance( inst_name )
|
716
|
+
end
|
717
|
+
dst.keys.each do |inst_name|
|
718
|
+
dst_inst[ inst_name ] = core_instance( inst_name )
|
719
|
+
end
|
720
|
+
|
721
|
+
#
|
722
|
+
# create the declaraion and assignments
|
723
|
+
#
|
724
|
+
coder.add_ifc_connection( ifc_spec, name, length_tmp, src_inst, dst_inst, src, dst )
|
725
|
+
|
726
|
+
end
|
727
|
+
|
728
|
+
|
729
|
+
#
|
730
|
+
# Returns a core instance, identified by its name.
|
731
|
+
# If it is not a sub-core, we return our self
|
732
|
+
#
|
733
|
+
# +inst+:: name of the instance
|
734
|
+
#
|
735
|
+
def core_instance( inst )
|
736
|
+
if @cores[ inst ] != nil
|
737
|
+
return @cores[ inst ]
|
738
|
+
else
|
739
|
+
return self
|
740
|
+
end
|
741
|
+
end
|
742
|
+
|
743
|
+
#
|
744
|
+
# Returns a port, identified by the interface and port name
|
745
|
+
# Note: this behaviour is exactly the same than of core_inst.port(...),
|
746
|
+
# but these ports are not evaluated.
|
747
|
+
#
|
748
|
+
# +ifc_name+:: name of the interface
|
749
|
+
# +port_ref+:: name of the port
|
750
|
+
#
|
751
|
+
def port( ifc_name, port_ref )
|
752
|
+
|
753
|
+
ifc = @interfaces[ ifc_name ]
|
754
|
+
|
755
|
+
# get interface specification
|
756
|
+
ifc_spc = SOCMaker::lib.get_ifc( ifc.id )
|
757
|
+
|
758
|
+
# get the port
|
759
|
+
port_tmp = ifc.ports.select{ |k,v| v.spc_ref.to_sym == port_ref }
|
760
|
+
|
761
|
+
# get the reference to the port definition
|
762
|
+
defn_ref = port_tmp.first[1].spc_ref.to_sym
|
763
|
+
|
764
|
+
_port_name = port_tmp.first[0].to_s
|
765
|
+
|
766
|
+
if ifc_spc.ports[ defn_ref ][ :dir ] == 2
|
767
|
+
_port_dir = 1 ^ ifc.dir
|
768
|
+
else
|
769
|
+
_port_dir = ifc_spc.ports[ defn_ref ][ :dir ] ^ ifc.dir
|
770
|
+
end
|
771
|
+
|
772
|
+
_port_default = ifc_spc.ports[ defn_ref ][ :default ]
|
773
|
+
|
774
|
+
_port_len = port_tmp.first[1].len
|
775
|
+
|
776
|
+
return [ _port_name, { len: _port_len, dir: _port_dir, default: _port_default, ref: port_tmp.first[1].spc_ref } ]
|
777
|
+
end
|
778
|
+
|
779
|
+
|
780
|
+
#
|
781
|
+
# Method to get all id's of all cores, sub-socs (recursively)
|
782
|
+
#
|
783
|
+
def all_core_id
|
784
|
+
@cores.values.map{ |c| c.defn.all_core_id }.flatten! << @id
|
785
|
+
end
|
786
|
+
|
787
|
+
|
788
|
+
#
|
789
|
+
# Method to get all static parameters of all cores, sub-socs (recursively)
|
790
|
+
#
|
791
|
+
def all_static_parameters
|
792
|
+
tmp = { @id => @static }
|
793
|
+
@cores.values.each { |v| tmp.merge!( v.defn.all_static_parameters ) }
|
794
|
+
return tmp
|
795
|
+
end
|
796
|
+
|
797
|
+
|
798
|
+
#
|
799
|
+
# Equality operator
|
800
|
+
#
|
801
|
+
def ==(o)
|
802
|
+
o.class == self.class &&
|
803
|
+
o.cores == self.cores &&
|
804
|
+
o.cons == self.cons &&
|
805
|
+
o.static == self.static &&
|
806
|
+
super( o )
|
807
|
+
end
|
808
|
+
|
809
|
+
|
810
|
+
#
|
811
|
+
# Returns a string describing this instance
|
812
|
+
#
|
813
|
+
def to_s
|
814
|
+
|
815
|
+
tmp = "_________ SOC #{@name}: _______\n" +
|
816
|
+
super +
|
817
|
+
"\n__connections__\n"
|
818
|
+
|
819
|
+
@cons.each do |_con_name, con_def|
|
820
|
+
tmp += "#{_con_name}: #{con_def}\n"
|
821
|
+
end
|
822
|
+
|
823
|
+
tmp += "\n__cores__\n"
|
824
|
+
@cores.each do |inst_name, inst|
|
825
|
+
tmp += "#{inst_name}:\n#{inst}\n"
|
826
|
+
end
|
827
|
+
|
828
|
+
|
829
|
+
tmp += "\n__interfaces__\n"
|
830
|
+
@interfaces.each do |ifc_name, ifc|
|
831
|
+
tmp += "#{ifc_name}:#{ifc.id}\n"
|
832
|
+
end
|
833
|
+
|
834
|
+
tmp += "'''''''''''''''''''''''''''''''''''\n"
|
835
|
+
return tmp
|
836
|
+
end
|
837
|
+
|
838
|
+
private :assign_unused_to_default,
|
839
|
+
:gen_toplevel_con,
|
840
|
+
:core_instance
|
841
|
+
|
842
|
+
|
843
|
+
end # class SOCSpec
|
844
|
+
end # module SOCMaker
|
845
|
+
|
846
|
+
|
847
|
+
# vim: noai:ts=2:sw=2
|