| 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 |