73 | | * MP-SoC architecture using the Mutek/D operation system, |
74 | | * MP-SoC architecture using the Mutek/S operating system, |
75 | | |
76 | | Mutek/D is an embedded, POSIX compliant, distributed, operating system for MP-SoCs, |
| 73 | * MP-SoC architecture using the Mutek/S operating system (SRL directly implemented on Hexo), |
| 74 | * MP-SoC architecture using the Mutek/H operation system (SRL with Posix threads on Hexo), |
| 75 | |
| 76 | Mutek/H is an embedded, POSIX compliant, distributed, operating system for MP-SoCs, |
205 | | For all components, the instance name is mandatory, but all other parameters have default values and can be skipped: |
206 | | {{{ |
207 | | # creation of a MIPS R3000 processor core |
208 | | my_proc = Mips( 'proc' ) |
209 | | |
210 | | # creation of a cache controler |
211 | | my_cache = Xcache( 'cache', |
| 202 | As it is possible to mix CABA and TLM-T simulation models in the same hardware architecture, |
| 203 | the system designer can specify the type of simulation model used for each hardware component. |
| 204 | For all components, the instance name is mandatory. |
| 205 | {{{ |
| 206 | # definition of the hardware architecture |
| 207 | archi = soclib.Architecture() |
| 208 | |
| 209 | # instanciation of a MIPS R3000 processor (MIPS ISS in a CABA wrapper), with CPUID = 0 |
| 210 | my_proc = archi.create('caba:iss_wrapper', 'proc', iss_t = 'common:mipsel', ident = 0) |
| 211 | |
| 212 | # instanciation of a CABA cache controler. Both instruction and data caches contain 32 lines of 8 bytes |
| 213 | my_cache = archi.create('caba:vci_xcache', 'cache', |
226 | | * When the number of ports is fixed, the ports are attributs : My_Proc0.cache define the cache port of the MIPS processor. |
227 | | * When the number of port is not fixed (typivally for interconnect component, the ports are allocated through a dedicated method : the getTarget() method of the !LocalCrossbar component allocates a VCI target port, the getInit() method allocates an VCI Initiator port. |
| 229 | * When the port is alone, the port is an attribute : My_Proc0.dcache define the data cache port of the processor. |
| 230 | * When the number of ports is fixed, the ports are in a array : My_Proc0.irq[3] define the 4th irq line of the processor. |
| 231 | * When the number of port in a port array is not fixed (typically for interconnect component), the ports are allocated through a dedicated method on the port array : the new() method on !Vgmn.from_initiator allocates a VCI target port. |
231 | | my_proc0 = Mips( 'proc0' ) |
232 | | my_cache0 = Xcache( 'cache0' ) |
233 | | my_proc1 = Mips( 'proc1' ) |
234 | | my_cache1 = Xcache( 'cache1' ) |
235 | | my_ram = MultiRam( 'ram' ) |
236 | | my_crossbar = LocalCrossbar( 'crossbar' ) |
237 | | |
| 235 | my_proc0 = archi.create('caba:iss_wrapper', 'proc0', iss_t = 'common:mipsel', ident = 0) |
| 236 | my_cache0 = archi.create('caba:vci_xcache', 'cache0', |
| 237 | dcache_lines = 32, |
| 238 | dcache_words = 8, |
| 239 | dcache_lines = 32, |
| 240 | dcache_words = 8) |
| 241 | my_proc1 = archi.create('caba:iss_wrapper', 'proc1', iss_t = 'common:mipsel', ident = 1) |
| 242 | my_cache1 = archi.create('caba:vci_xcache', 'cache1', |
| 243 | dcache_lines = 32, |
| 244 | dcache_words = 8, |
| 245 | dcache_lines = 32, |
| 246 | dcache_words = 8) |
| 247 | my_ram = archi.create('caba:vci_ram', 'ram' ) |
| 248 | my_vgmn = archi.create('caba:vci_vgmn', 'vgmn' ) |
| 249 | |
239 | | my_proc0.cache // my_cache0.cache |
240 | | my_proc1.cache // my_cache1.cache |
241 | | my_crossbar.getTarget() // my_cache0.vci |
242 | | my_crossbar.getTarget() // my_cache1.vci |
243 | | my_crossbar.getInitiator() // my_cache0.vci |
| 251 | my_proc0.dcache // my_cache0.dcache |
| 252 | my_proc0.icache // my_cache0.icache |
| 253 | my_proc1.dcache // my_cache1.dcache |
| 254 | my_proc1.icache // my_cache1.icache |
| 255 | my_vgmn.from_initiator.new() // my_cache0.vci |
| 256 | my_vgmn.from_initiator.new() // my_cache1.vci |
| 257 | my_vgmn.to_target.new() // my_ram.vci |
261 | | The base address and the segment size are optional parameters : |
262 | | {{{ |
263 | | # segments definition |
264 | | seg_data1 = Segment( 'seg1', Cached ) |
265 | | seg_data2 = Segment( 'seg2', Uncached ) |
266 | | seg_reset = Segment( 'reset', Cached, addr = 0xBFC00000 ) |
267 | | |
268 | | # Instanciating a VCI target hardware component |
269 | | # and assigning the segments to this component |
270 | | my_ram = MultiRam ( 'ram', seg_data1, seg_data2, seg_reset ) |
| 268 | {{{ |
| 269 | my_ram = archi.create('caba:vci_ram', 'ram' ) |
| 270 | my_ram.addSegment('cram0', 0x40000, 0x320) |
| 271 | my_ram.addSegment('mipsel_reset', 0xbfc00000, 0x100) |
285 | | be reused for various applications. Those reusable architectures are derived classes |
286 | | from the basic '''Architecture''' class. The implementation is defined in the architecture() method. |
287 | | |
288 | | As an example we define a parameterized multi-processors architecture, called !MultiProc, and containing |
289 | | a variable number of processors. The parameter(s) must be named, and the actual parameter value is defined |
290 | | when the architecture is instanciated. The parameter is referenced with the ''getParam()'' method, and it |
291 | | is possible to define a default value. |
| 284 | be reused for various applications. Those reusable architectures are functions. |
| 285 | |
296 | | class MultiProc(Architecture) : |
297 | | defaults = { ’nbcpu’ : 2 } |
298 | | def architecture(self): |
299 | | |
300 | | # segments definition |
301 | | self.reset = Segment( ’reset’, address = 0xbfc00000, type = Cached ) |
302 | | self.code = Segment( ’code’, type = Cached ) |
303 | | self.data = Segment( ’data’, type = Uncached ) |
304 | | |
305 | | # components instanciation and connexion |
306 | | self.vgmn = Vgmn( ’vgmn’ ) |
307 | | self.ram = MultiRam( ’ram’, self.reset, self.code, self.data ) |
308 | | # processors and caches |
309 | | self.cpus = [] |
310 | | for i in self.getParam( ’nbcpu’ ): |
311 | | m = Mips( ’mips%d’%i ) |
312 | | self.cpus.append( m ) |
313 | | c = Xcache( ’cache%d’%i ) |
314 | | g:c.cache // m.cache ) |
315 | | c.vci // self.vgmn.getTarget() ) |
316 | | self.vgmn.getTarget() // self.c1 |
317 | | self.vgmn.getTarget() // self.c2 |
318 | | self.vgmn.getInit() // self.ram |
319 | | |
320 | | # base definition |
321 | | self.setBase( self.vgmn ) |
322 | | |
323 | | # segment table initialization |
324 | | self.setConfig(’mapping_table’, MappingTable() ) |
| 290 | def MultiProc(nbcpu = 2): |
| 291 | archi = soclib.Architecture() |
| 292 | |
| 293 | vgmn = archi.create('caba:vci_vgmn', 'vgmn' ) |
| 294 | |
| 295 | for i in range(nbcpu): |
| 296 | proc = archi.create('caba:iss_wrapper', 'proc%d'%i, iss_t = 'common:mipsel', ident = i) |
| 297 | cache = archi.create('caba:vci_xcache', 'cache%d'%i, |
| 298 | dcache_lines = 32, |
| 299 | dcache_words = 8, |
| 300 | dcache_lines = 32, |
| 301 | dcache_words = 8) |
| 302 | |
| 303 | proc.dcache // cache.dcache |
| 304 | proc.icache // cache.icache |
| 305 | |
| 306 | my_ram = archi.create('caba:vci_ram', 'ram' ) |
| 307 | my_ram.addSegment( ’reset’, 0xbfc00000, true ) |
| 308 | my_ram.addSegment( ’code’, 0x40000000, true ) |
| 309 | my_ram.addSegment( ’data0’, 0x20000000, true ) |
| 310 | my_ram.addSegment( ’data1’, 0x30000000, false ) |
| 311 | |
| 312 | my_vgmn.to_target.new() // my_ram.vci |
357 | | lock = my_archi.seg_locks, # The lock protecting the channel is placed in segment seg_locks |
358 | | status = my_archi.seg_data, # The channel status is placed in segment seg_data |
359 | | desc = my_archi.segdata, # The channel descriptor is placed in segment seg_readonly |
360 | | buffer = my_archi.sgdata ) # The channel buffer is placed in segment seg_data |
| 343 | status = 'data0', # The channel status is placed in segment seg_data |
| 344 | desc = 'data1', # The channel descriptor is placed in segment seg_readonly |
| 345 | buffer = 'data1' ) # The channel buffer is placed in segment seg_data |
364 | | desc = my_archi.seg_data, # The task descriptor is placed in segment seg_readonly |
365 | | status = my_archi.seg_data, # The task state is placed in segment seg_data |
366 | | stack = my_archi.seg_data, # The private task stack is placed in segment seg_stack |
367 | | run = my_archi.cpu0 ) # task will be running on cpu0 |
| 349 | desc = 'data0', # The task descriptor is placed in segment seg_readonly |
| 350 | status = 'data1', # The task state is placed in segment seg_data |
| 351 | stack = 'data0', # The private task stack is placed in segment seg_stack |
| 352 | run = 'proc0' ) # task will be running on processor no 0 |