| | 1 | [[PageOutline]] |
| | 2 | |
| | 3 | = Metadata = |
| | 4 | |
| | 5 | For SoCLib components, metadata is in `.sd` files, parsed by `soclib-cc`. |
| | 6 | |
| | 7 | In these files, there is an optional `extensions = ` statement. This statement is a list of string formatted as |
| | 8 | `"namespace:keyword=value"`. An example for the dsx namespace is: |
| | 9 | {{{ |
| | 10 | extensions = [ |
| | 11 | 'dsx:cpu=wrapper:iss_t', |
| | 12 | 'dsx:addressable=target_index', |
| | 13 | ], |
| | 14 | }}} |
| | 15 | |
| | 16 | Here we'll make a list of these extensions and their effects |
| | 17 | |
| | 18 | = Pure C++ module constraints = |
| | 19 | |
| | 20 | == Module without a name as first parameter == |
| | 21 | |
| | 22 | Some pure-C++ (i.e. not SystemC) modules do not need a name as first parameter. There |
| | 23 | is an extension telling the netlister to generate a correct constructor invocation |
| | 24 | for the module: |
| | 25 | {{{ |
| | 26 | "dsx:noname", |
| | 27 | }}} |
| | 28 | |
| | 29 | = Memory mapping & organization = |
| | 30 | |
| | 31 | == VCI srcid / tgtid, ports and mapping tables == |
| | 32 | |
| | 33 | VCI uses `(``r)srcid` to route response packets back to the originating initiator. As it is |
| | 34 | decoded, the srcid field attributed to an initiator is directly equivalent to the port it is |
| | 35 | connected to on peer interconnect. A module then has to be able to retrieve: |
| | 36 | * srcid field value (or initiator index as an `IntTab` parameter) |
| | 37 | * mapping table associated to the interconnect |
| | 38 | * correspondance between ports and indexes |
| | 39 | |
| | 40 | Likewise for targets. |
| | 41 | |
| | 42 | == Target components == |
| | 43 | |
| | 44 | For a simple target component, we'll probably have: |
| | 45 | * a `VciTarget` port |
| | 46 | * a mapping table as parameter |
| | 47 | * a target index as parameter |
| | 48 | |
| | 49 | {{{ |
| | 50 | ports = [ |
| | 51 | Port('caba:vci_target', 'p_vci_port_name'), |
| | 52 | … |
| | 53 | ], |
| | 54 | instance_parameters = [ |
| | 55 | … |
| | 56 | parameter.IntTab('target_index_parameter_name'), |
| | 57 | parameter.Module('mapping_table_parameter_name', typename = 'common:mapping_table'), |
| | 58 | … |
| | 59 | ], |
| | 60 | }}} |
| | 61 | |
| | 62 | Needed metadata are: |
| | 63 | |
| | 64 | {{{ |
| | 65 | "dsx:get_ident=target_index_parameter_name:p_vci_port_name:mapping_table_port_name", |
| | 66 | "dsx:addressable=target_index_parameter_name", |
| | 67 | }}} |
| | 68 | |
| | 69 | `dsx:get_ident` associates a given index to a port and a mapping table. Actual index |
| | 70 | value and mapping table to use will be implicitly retrieved through the module connected |
| | 71 | to the port. |
| | 72 | |
| | 73 | `dsx:addressable` tells the target is accessible through this target index. |
| | 74 | |
| | 75 | == Maximum target segments == |
| | 76 | |
| | 77 | Sometimes targets can only have a limited number of addressable segments. You can enforce |
| | 78 | this limit telling DSX to do so. |
| | 79 | |
| | 80 | For instance, a simple controller may only need one segment: |
| | 81 | |
| | 82 | {{{ |
| | 83 | extensions = [ |
| | 84 | 'dsx:max_segments=1', |
| | 85 | ], |
| | 86 | }}} |
| | 87 | |
| | 88 | == Addressable segments associated to a srcid == |
| | 89 | |
| | 90 | For coherent platforms, we sometimes need to associate a source id to a segment. |
| | 91 | Thus when creating the segment, we have to add an id. This is done through |
| | 92 | `"dsx:on_segment=` extension. Example in the `vci_cc_xcache_wrapper_v1`: |
| | 93 | |
| | 94 | Syntax: `target_segment_mapping_table:add_index:initiator_index_name` |
| | 95 | |
| | 96 | {{{ |
| | 97 | instance_parameters = [ |
| | 98 | parameter.Int('proc_id'), |
| | 99 | parameter.Module('mtp', 'common:mapping_table'), |
| | 100 | parameter.Module('mtc', 'common:mapping_table'), |
| | 101 | parameter.IntTab('initiator_rw_index'), |
| | 102 | parameter.IntTab('initiator_c_index'), |
| | 103 | parameter.IntTab('target_index'), |
| | 104 | … |
| | 105 | ], |
| | 106 | extensions = [ |
| | 107 | 'dsx:get_ident=' |
| | 108 | 'initiator_rw_index:p_vci_ini_rw:mt,' |
| | 109 | 'initiator_c_index:p_vci_ini_c:mc,' |
| | 110 | 'target_index:p_vci_tgt:mc', |
| | 111 | 'dsx:on_segment=mc:add_index:initiator_rw_index', |
| | 112 | 'dsx:addressable=target_index', |
| | 113 | … |
| | 114 | ], |
| | 115 | }}} |
| | 116 | |
| | 117 | == Initiator == |
| | 118 | |
| | 119 | For a simple initiator component, we'll probably have: |
| | 120 | * a `VciInitiator` port |
| | 121 | * a mapping table as parameter |
| | 122 | * a source index as parameter |
| | 123 | |
| | 124 | {{{ |
| | 125 | ports = [ |
| | 126 | Port('caba:vci_initiator', 'p_vci'), |
| | 127 | … |
| | 128 | ], |
| | 129 | instance_parameters = [ |
| | 130 | … |
| | 131 | parameter.Module('mt', 'common:mapping_table'), |
| | 132 | parameter.IntTab('index'), |
| | 133 | … |
| | 134 | ], |
| | 135 | }}} |
| | 136 | |
| | 137 | This works the same way as for targets. Let's have an example with real names: |
| | 138 | |
| | 139 | {{{ |
| | 140 | extensions = [ |
| | 141 | 'dsx:get_ident=index:p_vci:mt', |
| | 142 | ], |
| | 143 | }}} |
| | 144 | |
| | 145 | `dsx:get_ident` associates a given index to a port and a mapping table. Actual index |
| | 146 | value and mapping table to use will be implicitly retrieved through the module connected |
| | 147 | to the port. |
| | 148 | |
| | 149 | == Interconnects == |
| | 150 | |
| | 151 | In order to get the two preceding points working, interconnects need to provide a way to |
| | 152 | get a source / target identifier. When DSX reaches an interconnect, it looks for the following extension: |
| | 153 | |
| | 154 | {{{ |
| | 155 | extensions = [ |
| | 156 | 'dsx:interconnect=root', |
| | 157 | 'dsx:obtain_ident_method=port', |
| | 158 | ], |
| | 159 | }}} |
| | 160 | |
| | 161 | `dsx:interconnect` may either have no value, or "root". "root" means the interconnect is |
| | 162 | the root of the routing tree, for instance a VGMN. Local interconnects (like the `vci_local_crossbar`) |
| | 163 | only need `"dsx:interconnect"`. |
| | 164 | |
| | 165 | `dsx:obtain_ident_method` may value either `port` or `param`. |
| | 166 | |
| | 167 | `port`:: |
| | 168 | The identifier is directly related to the port number in a port array, this is the usual value |
| | 169 | for all port-array based interconnects like VGMN or crossbars. |
| | 170 | |
| | 171 | `param=some_parameter_name`:: |
| | 172 | Use a given instance parameter as identifier for associated component. This is the usual value |
| | 173 | for one-wrapper-per-component interconnects like ring or dspin. |
| | 174 | |
| | 175 | = CPUs / ISS wrappers = |
| | 176 | |
| | 177 | == Processor type == |
| | 178 | |
| | 179 | For DSX software deployment system, we need to highlight CPUs and their types. This is the |
| | 180 | `"dsx:cpu="` extension. |
| | 181 | |
| | 182 | As ISS are wrapped in caches, and wrapping may be nested (GDB, memchecker, …) |
| | 183 | a recursive way, a recursive lookup is achieved. |
| | 184 | |
| | 185 | `"dsx:cpu="` may be: |
| | 186 | |
| | 187 | `wrapper:some_template_parameter_type`:: |
| | 188 | used in caches and iss wrappers, to tell the iss is unknown, but given as a parameter |
| | 189 | |
| | 190 | `some_arch`:: |
| | 191 | used for actual CPU implementations, tells what the cpu architure is. |
| | 192 | Current known architectures are `mips32el`, `mips32eb`, `powerpc405`, `arm`. |
| | 193 | |
| | 194 | == Processor identifier == |
| | 195 | |
| | 196 | CPU are associated to an unique identifier for the platform, usually a sequential name. |
| | 197 | DSX needs to know what parameter corresponds to this identifier. This is done with the |
| | 198 | `"dsx:mapping_type=processor:parameter_name"`: |
| | 199 | |
| | 200 | {{{ |
| | 201 | instance_parameters = [ |
| | 202 | parameter.Int('ident'), # processor identifier |
| | 203 | parameter.Module('mt', 'common:mapping_table'), |
| | 204 | parameter.IntTab('index'), |
| | 205 | … |
| | 206 | ], |
| | 207 | extensions = [ |
| | 208 | 'dsx:mapping_type=processor:ident', |
| | 209 | ], |
| | 210 | }}} |
| | 211 | |
| | 212 | == Devices == |
| | 213 | |
| | 214 | Devices may be declared, in order to be able to map specific options to them. For |
| | 215 | now, only ttys are supported. |
| | 216 | |
| | 217 | {{{ |
| | 218 | extensions = [ |
| | 219 | 'dsx:device=tty', |
| | 220 | ], |
| | 221 | }}} |
| | 222 | |
| | 223 | == C++ hacks == |
| | 224 | |
| | 225 | Sometimes, you have to call a C++ static function once |
| | 226 | per class, or a method once per object instance. |
| | 227 | These two things will help, even if this obscure feature |
| | 228 | is mostly undocumented. Use source code for reference. |
| | 229 | |
| | 230 | === Static configuration lines === |
| | 231 | |
| | 232 | `'dsx:static_config_lines=%(class)s::init(%(env:mapping_table)s,%(env:loader)s,"%(meta:all_peripherals)s")'` |
| | 233 | |
| | 234 | This is an excerpt from `iss_memchecker` metadata, telling |
| | 235 | the netlister must generate a line with a given |
| | 236 | template once for each IssMemchecker<…> type, taking references |
| | 237 | from envorinment and all peripherals. |
| | 238 | |
| | 239 | === Instance configuration lines === |
| | 240 | |
| | 241 | Likewise, there is |
| | 242 | |
| | 243 | `'dsx:config_lines=…'`, emitted once for each object. See dsx soclib's component handling code for usage. |
| | 244 | |
| | 245 | == MutekH configuration == |
| | 246 | |
| | 247 | Some modules may want to influence MutekH's own configuration. This is only available |
| | 248 | when using DSX software-generation feature. Using a given module may then change some |
| | 249 | configuration tokens in MutekH's build system. |
| | 250 | |
| | 251 | For instance, when putting an `iss_memchecker` in the netlist, we want MutekH to be built with |
| | 252 | memchecker support code activated, thus we can add in iss_memchecker's metadata the following |
| | 253 | extension: |
| | 254 | |
| | 255 | {{{ |
| | 256 | extensions = [ |
| | 257 | 'dsx:set_config=CONFIG_SOCLIB_MEMCHECK', |
| | 258 | ], |
| | 259 | }}} |
| | 260 | |
| | 261 | = Examples = |
| | 262 | |
| | 263 | == DMA == |
| | 264 | |
| | 265 | Let's describe a DMA. It has |
| | 266 | * one initiator port |
| | 267 | * one target port |
| | 268 | * an initiator index |
| | 269 | * a target index |
| | 270 | * a mapping table associated to this all |
| | 271 | |
| | 272 | It only supports one addressable segment |
| | 273 | |
| | 274 | {{{ |
| | 275 | ports = [ |
| | 276 | Port('caba:vci_target', 'p_vci_target'), |
| | 277 | Port('caba:vci_initiator', 'p_vci_initiator'), |
| | 278 | … |
| | 279 | ], |
| | 280 | instance_parameters = [ |
| | 281 | parameter.Module('mt', typename = 'common:mapping_table'), |
| | 282 | parameter.IntTab('srcid'), |
| | 283 | parameter.IntTab('tgtid'), |
| | 284 | parameter.Int('burst_size'), |
| | 285 | ], |
| | 286 | extensions = [ |
| | 287 | 'dsx:addressable=tgtid', |
| | 288 | 'dsx:max_segments=1', |
| | 289 | 'dsx:get_ident=srcid:p_vci_target:mt,tgtid:p_vci_initiator:mt', |
| | 290 | ], |
| | 291 | }}} |