[[PageOutline]] = Metadata = For SoCLib components, metadata is in `.sd` files, parsed by `soclib-cc`. In these files, there is an optional `extensions = ` statement. This statement is a list of string formatted as `"namespace:keyword=value"`. An example for the dsx namespace is: {{{ extensions = [ 'dsx:cpu=wrapper:iss_t', 'dsx:addressable=target_index', ], }}} Here we'll make a list of these extensions and their effects = Pure C++ module constraints = == Module without a name as first parameter == Some pure-C++ (i.e. not SystemC) modules do not need a name as first parameter. There is an extension telling the netlister to generate a correct constructor invocation for the module: {{{ "dsx:noname", }}} = Memory mapping & organization = == VCI srcid / tgtid, ports and mapping tables == VCI uses `(``r)srcid` to route response packets back to the originating initiator. As it is decoded, the srcid field attributed to an initiator is directly equivalent to the port it is connected to on peer interconnect. A module then has to be able to retrieve: * srcid field value (or initiator index as an `IntTab` parameter) * mapping table associated to the interconnect * correspondance between ports and indexes Likewise for targets. == Target components == For a simple target component, we'll probably have: * a `VciTarget` port * a mapping table as parameter * a target index as parameter {{{ ports = [ Port('caba:vci_target', 'p_vci_port_name'), … ], instance_parameters = [ … parameter.IntTab('target_index_parameter_name'), parameter.Module('mapping_table_parameter_name', typename = 'common:mapping_table'), … ], }}} Needed metadata are: {{{ "dsx:get_ident=target_index_parameter_name:p_vci_port_name:mapping_table_port_name", "dsx:addressable=target_index_parameter_name", }}} `dsx:get_ident` associates a given index to a port and a mapping table. Actual index value and mapping table to use will be implicitly retrieved through the module connected to the port. `dsx:addressable` tells the target is accessible through this target index. == Maximum target segments == Sometimes targets can only have a limited number of addressable segments. You can enforce this limit telling DSX to do so. For instance, a simple controller may only need one segment: {{{ extensions = [ 'dsx:max_segments=1', ], }}} == Addressable segments associated to a srcid == For coherent platforms, we sometimes need to associate a source id to a segment. Thus when creating the segment, we have to add an id. This is done through `"dsx:on_segment=` extension. Example in the `vci_cc_xcache_wrapper_v1`: Syntax: `target_segment_mapping_table:add_index:initiator_index_name` {{{ instance_parameters = [ parameter.Int('proc_id'), parameter.Module('mtp', 'common:mapping_table'), parameter.Module('mtc', 'common:mapping_table'), parameter.IntTab('initiator_rw_index'), parameter.IntTab('initiator_c_index'), parameter.IntTab('target_index'), … ], extensions = [ 'dsx:get_ident=' 'initiator_rw_index:p_vci_ini_rw:mt,' 'initiator_c_index:p_vci_ini_c:mc,' 'target_index:p_vci_tgt:mc', 'dsx:on_segment=mc:add_index:initiator_rw_index', 'dsx:addressable=target_index', … ], }}} == Initiator == For a simple initiator component, we'll probably have: * a `VciInitiator` port * a mapping table as parameter * a source index as parameter {{{ ports = [ Port('caba:vci_initiator', 'p_vci'), … ], instance_parameters = [ … parameter.Module('mt', 'common:mapping_table'), parameter.IntTab('index'), … ], }}} This works the same way as for targets. Let's have an example with real names: {{{ extensions = [ 'dsx:get_ident=index:p_vci:mt', ], }}} `dsx:get_ident` associates a given index to a port and a mapping table. Actual index value and mapping table to use will be implicitly retrieved through the module connected to the port. == Interconnects == In order to get the two preceding points working, interconnects need to provide a way to get a source / target identifier. When DSX reaches an interconnect, it looks for the following extension: {{{ extensions = [ 'dsx:interconnect=root', 'dsx:obtain_ident_method=port', ], }}} `dsx:interconnect` may either have no value, or "root". "root" means the interconnect is the root of the routing tree, for instance a VGMN. Local interconnects (like the `vci_local_crossbar`) only need `"dsx:interconnect"`. `dsx:obtain_ident_method` may value either `port` or `param`. `port`:: The identifier is directly related to the port number in a port array, this is the usual value for all port-array based interconnects like VGMN or crossbars. `param=some_parameter_name`:: Use a given instance parameter as identifier for associated component. This is the usual value for one-wrapper-per-component interconnects like ring or dspin. = CPUs / ISS wrappers = == Processor type == For DSX software deployment system, we need to highlight CPUs and their types. This is the `"dsx:cpu="` extension. As ISS are wrapped in caches, and wrapping may be nested (GDB, memchecker, …) a recursive way, a recursive lookup is achieved. `"dsx:cpu="` may be: `wrapper:some_template_parameter_type`:: used in caches and iss wrappers, to tell the iss is unknown, but given as a parameter `some_arch`:: used for actual CPU implementations, tells what the cpu architure is. Current known architectures are `mips32el`, `mips32eb`, `powerpc405`, `arm`. == Processor identifier == CPU are associated to an unique identifier for the platform, usually a sequential name. DSX needs to know what parameter corresponds to this identifier. This is done with the `"dsx:mapping_type=processor:parameter_name"`: {{{ instance_parameters = [ parameter.Int('ident'), # processor identifier parameter.Module('mt', 'common:mapping_table'), parameter.IntTab('index'), … ], extensions = [ 'dsx:mapping_type=processor:ident', ], }}} == Devices == Devices may be declared, in order to be able to map specific options to them. For now, only ttys are supported. {{{ extensions = [ 'dsx:device=tty', ], }}} == C++ hacks == Sometimes, you have to call a C++ static function once per class, or a method once per object instance. These two things will help, even if this obscure feature is mostly undocumented. Use source code for reference. === Static configuration lines === `'dsx:static_config_lines=%(class)s::init(%(env:mapping_table)s,%(env:loader)s,"%(meta:all_peripherals)s")'` This is an excerpt from `iss_memchecker` metadata, telling the netlister must generate a line with a given template once for each IssMemchecker<…> type, taking references from envorinment and all peripherals. === Instance configuration lines === Likewise, there is `'dsx:config_lines=…'`, emitted once for each object. See dsx soclib's component handling code for usage. == MutekH configuration == Some modules may want to influence MutekH's own configuration. This is only available when using DSX software-generation feature. Using a given module may then change some configuration tokens in MutekH's build system. For instance, when putting an `iss_memchecker` in the netlist, we want MutekH to be built with memchecker support code activated, thus we can add in iss_memchecker's metadata the following extension: {{{ extensions = [ 'dsx:set_config=CONFIG_SOCLIB_MEMCHECK', ], }}} = Examples = == DMA == Let's describe a DMA. It has * one initiator port * one target port * an initiator index * a target index * a mapping table associated to this all It only supports one addressable segment {{{ ports = [ Port('caba:vci_target', 'p_vci_target'), Port('caba:vci_initiator', 'p_vci_initiator'), … ], instance_parameters = [ parameter.Module('mt', typename = 'common:mapping_table'), parameter.IntTab('srcid'), parameter.IntTab('tgtid'), parameter.Int('burst_size'), ], extensions = [ 'dsx:addressable=tgtid', 'dsx:max_segments=1', 'dsx:get_ident=srcid:p_vci_target:mt,tgtid:p_vci_initiator:mt', ], }}}