1 /*****************************************************************************
3 * SOFTWARE LICENSE AGREEMENT
4 * Copyright 2012 Hewlett-Packard Development Company, L.P.
5 * Copyright (c) 2010-2013 Advanced Micro Devices, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met: redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer;
12 * redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution;
15 * neither the name of the copyright holders nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 ***************************************************************************/
38 #include "basic_circuit.h"
42 #include "iocontrollers.h"
46 SUN Niagara 2 I/O power analysis:
47 total signal bits: 711
48 Total FBDIMM bits: (14+10)*2*8= 384
49 PCIe bits: (8 + 8)*2 = 32
50 10Gb NIC: (4*2+4*2)*2 = 32
52 Other I/Os: 711- 32-32 - 384 - 168 = 95
54 According to "Implementation of an 8-Core, 64-Thread, Power-Efficient SPARC Server on a Chip"
55 90% of I/Os are SerDers (the calucaltion is 384+64/(711-168)=83% about the same as the 90% reported in the paper)
56 --> around 80Pins are common I/Os.
57 Common I/Os consumes 71mW/Gb/s according to Cadence ChipEstimate @65nm
58 Niagara 2 I/O clock is 1/4 of core clock. --> 87pin (<--((711-168)*17%)) * 71mW/Gb/s *0.25*1.4Ghz = 2.17W
60 Total dynamic power of FBDIMM, NIC, PCIe = 84*0.132 + 84*0.049*0.132 = 11.14 - 2.17 = 8.98
61 Further, if assuming I/O logic power is about 50% of I/Os then Total energy of FBDIMM, NIC, PCIe = 11.14 - 2.17*1.5 = 7.89
65 * A bug in Cadence ChipEstimator: After update the clock rate in the clock tab, a user
66 * need to re-select the IP clock (the same clk) and then click Estimate. if not reselect
67 * the new clock rate may not be propogate into the IPs.
71 NIUController::NIUController(XMLNode
* _xml_data
,InputParameter
* interface_ip_
)
72 : McPATComponent(_xml_data
, interface_ip_
) {
77 void NIUController::computeArea() {
82 if (niup
.type
== 0) { //high performance NIU
83 //Area estimation based on average of die photo from Niagara 2 and
84 //Cadence ChipEstimate using 65nm.
85 mac_area
= (1.53 + 0.3) / 2 * (interface_ip
.F_sz_um
/ 0.065) *
86 (interface_ip
.F_sz_um
/ 0.065);
87 //Area estimation based on average of die photo from Niagara 2, ISSCC
88 //"An 800mW 10Gb Ethernet Transceiver in 0.13μm CMOS"
89 //and"A 1.2-V-Only 900-mW 10 Gb Ethernet Transceiver and XAUI Interface
90 //With Robust VCO Tuning Technique" Frontend is PCS
91 frontend_area
= (9.8 + (6 + 18) * 65 / 130 * 65 / 130) / 3 *
92 (interface_ip
.F_sz_um
/ 0.065) * (interface_ip
.F_sz_um
/ 0.065);
93 //Area estimation based on average of die photo from Niagara 2 and
94 //Cadence ChipEstimate hard IP @65nm.
95 //SerDer is very hard to scale
96 SerDer_area
= (1.39 + 0.36) * (interface_ip
.F_sz_um
/
97 0.065);//* (interface_ip.F_sz_um/0.065);
99 //Low power implementations are mostly from Cadence ChipEstimator;
100 //Ignore the multiple IP effect
101 // ---When there are multiple IP (same kind or not) selected, Cadence
102 //ChipEstimator results are not a simple summation of all IPs.
104 mac_area
= 0.24 * (interface_ip
.F_sz_um
/ 0.065) *
105 (interface_ip
.F_sz_um
/ 0.065);
106 frontend_area
= 0.1 * (interface_ip
.F_sz_um
/ 0.065) *
107 (interface_ip
.F_sz_um
/ 0.065);//Frontend is the PCS layer
108 SerDer_area
= 0.35 * (interface_ip
.F_sz_um
/ 0.065) *
109 (interface_ip
.F_sz_um
/0.065);
110 //Compare 130um implementation in "A 1.2-V-Only 900-mW 10 Gb Ethernet
111 //Transceiver and XAUI Interface With Robust VCO Tuning Technique"
112 //and the ChipEstimator XAUI PHY hard IP, confirm that even PHY can
113 //scale perfectly with the technology
117 output_data
.area
= (mac_area
+ frontend_area
+ SerDer_area
) * 1e6
;
120 void NIUController::computeEnergy() {
124 double frontend_gates
;
129 double pmos_to_nmos_sizing_r
= pmos_to_nmos_sz_ratio();
131 if (niup
.type
== 0) { //high performance NIU
133 //Cadence ChipEstimate using 65nm (mac, front_end are all energy.
134 //E=P*T = P/F = 1.37/1Ghz = 1.37e-9);
135 //2.19W@1GHz fully active according to Cadence ChipEstimate @65nm
136 mac_dyn
= 2.19e-9 * g_tp
.peri_global
.Vdd
/ 1.1 * g_tp
.peri_global
.Vdd
/
137 1.1 * (interface_ip
.F_sz_nm
/ 65.0);//niup.clockRate;
138 //Cadence ChipEstimate using 65nm soft IP;
139 frontend_dyn
= 0.27e-9 * g_tp
.peri_global
.Vdd
/ 1.1 *
140 g_tp
.peri_global
.Vdd
/ 1.1 * (interface_ip
.F_sz_nm
/ 65.0);
141 //according to "A 100mW 9.6Gb/s Transceiver in 90nm CMOS..." ISSCC 2006
142 //SerDer_dyn is power not energy, scaling from 10mw/Gb/s @90nm
143 SerDer_dyn
= 0.01 * 10 * sqrt(interface_ip
.F_sz_um
/ 0.09) *
144 g_tp
.peri_global
.Vdd
/ 1.2 * g_tp
.peri_global
.Vdd
/ 1.2;
146 //Cadence ChipEstimate using 65nm
148 frontend_gates
= 320000;
149 SerDer_gates
= 200000;
150 NMOS_sizing
= 5 * g_tp
.min_w_nmos_
;
151 PMOS_sizing
= 5 * g_tp
.min_w_nmos_
* pmos_to_nmos_sizing_r
;
154 //Cadence ChipEstimate using 65nm (mac, front_end are all energy.
155 ///E=P*T = P/F = 1.37/1Ghz = 1.37e-9);
156 //2.19W@1GHz fully active according to Cadence ChipEstimate @65nm
157 mac_dyn
= 1.257e-9 * g_tp
.peri_global
.Vdd
/ 1.1 * g_tp
.peri_global
.Vdd
158 / 1.1 * (interface_ip
.F_sz_nm
/ 65.0);//niup.clockRate;
159 //Cadence ChipEstimate using 65nm soft IP;
160 frontend_dyn
= 0.6e-9 * g_tp
.peri_global
.Vdd
/ 1.1 *
161 g_tp
.peri_global
.Vdd
/ 1.1 * (interface_ip
.F_sz_nm
/ 65.0);
162 //SerDer_dyn is power not energy, scaling from 216mw/10Gb/s @130nm
163 SerDer_dyn
= 0.0216 * 10 * (interface_ip
.F_sz_um
/ 0.13) *
164 g_tp
.peri_global
.Vdd
/ 1.2 * g_tp
.peri_global
.Vdd
/ 1.2;
167 frontend_gates
= 52000;
168 SerDer_gates
= 199260;
169 NMOS_sizing
= g_tp
.min_w_nmos_
;
170 PMOS_sizing
= g_tp
.min_w_nmos_
* pmos_to_nmos_sizing_r
;
173 //covert to energy per clock cycle of whole NIU
174 SerDer_dyn
/= niup
.clockRate
;
176 power
.readOp
.dynamic
= mac_dyn
+ frontend_dyn
+ SerDer_dyn
;
177 power
.readOp
.leakage
= (mac_gates
+ frontend_gates
+ frontend_gates
) *
178 cmos_Isub_leakage(NMOS_sizing
, PMOS_sizing
, 2, nand
) *
179 g_tp
.peri_global
.Vdd
;//unit W
180 double long_channel_device_reduction
=
181 longer_channel_device_reduction(Uncore_device
);
182 power
.readOp
.longer_channel_leakage
=
183 power
.readOp
.leakage
* long_channel_device_reduction
;
184 power
.readOp
.gate_leakage
= (mac_gates
+ frontend_gates
+ frontend_gates
) *
185 cmos_Ig_leakage(NMOS_sizing
, PMOS_sizing
, 2, nand
) *
186 g_tp
.peri_global
.Vdd
;//unit W
189 output_data
.subthreshold_leakage_power
=
190 longer_channel_device
? power
.readOp
.longer_channel_leakage
:
191 power
.readOp
.leakage
;
192 output_data
.gate_leakage_power
= power
.readOp
.gate_leakage
;
193 output_data
.peak_dynamic_power
= power
.readOp
.dynamic
* nius
.duty_cycle
;
194 output_data
.runtime_dynamic_energy
= power
.readOp
.dynamic
* nius
.perc_load
;
197 void NIUController::set_niu_param() {
198 int num_children
= xml_data
->nChildNode("param");
200 for (i
= 0; i
< num_children
; i
++) {
201 XMLNode
* paramNode
= xml_data
->getChildNodePtr("param", &i
);
202 XMLCSTR node_name
= paramNode
->getAttribute("name");
203 XMLCSTR value
= paramNode
->getAttribute("value");
206 warnMissingParamName(paramNode
->getAttribute("id"));
208 ASSIGN_FP_IF("niu_clockRate", niup
.clockRate
);
209 ASSIGN_INT_IF("num_units", niup
.num_units
);
210 ASSIGN_INT_IF("type", niup
.type
);
213 warnUnrecognizedParam(node_name
);
217 // Change from MHz to Hz
218 niup
.clockRate
*= 1e6
;
220 num_children
= xml_data
->nChildNode("stat");
221 for (i
= 0; i
< num_children
; i
++) {
222 XMLNode
* statNode
= xml_data
->getChildNodePtr("stat", &i
);
223 XMLCSTR node_name
= statNode
->getAttribute("name");
224 XMLCSTR value
= statNode
->getAttribute("value");
227 warnMissingStatName(statNode
->getAttribute("id"));
229 ASSIGN_FP_IF("duty_cycle", nius
.duty_cycle
);
230 ASSIGN_FP_IF("perc_load", nius
.perc_load
);
233 warnUnrecognizedStat(node_name
);
238 PCIeController::PCIeController(XMLNode
* _xml_data
,
239 InputParameter
* interface_ip_
)
240 : McPATComponent(_xml_data
, interface_ip_
) {
245 void PCIeController::computeArea() {
249 /* Assuming PCIe is bit-slice based architecture
250 * This is the reason for /8 in both area and power calculation
251 * to get per lane numbers
254 if (pciep
.type
== 0) { //high performance PCIe
255 //Area estimation based on average of die photo from Niagara 2 and
256 //Cadence ChipEstimate @ 65nm.
257 ctrl_area
= (5.2 + 0.5) / 2 * (interface_ip
.F_sz_um
/ 0.065) *
258 (interface_ip
.F_sz_um
/ 0.065);
259 //Area estimation based on average of die photo from Niagara 2 and
260 //Cadence ChipEstimate hard IP @65nm.
261 //SerDer is very hard to scale
262 SerDer_area
= (3.03 + 0.36) * (interface_ip
.F_sz_um
/
263 0.065);//* (interface_ip.F_sz_um/0.065);
265 ctrl_area
= 0.412 * (interface_ip
.F_sz_um
/ 0.065) *
266 (interface_ip
.F_sz_um
/ 0.065);
267 //Area estimation based on average of die photo from Niagara 2, and
268 //Cadence ChipEstimate @ 65nm.
269 SerDer_area
= 0.36 * (interface_ip
.F_sz_um
/ 0.065) *
270 (interface_ip
.F_sz_um
/ 0.065);
274 output_data
.area
= ((ctrl_area
+ (pciep
.withPHY
? SerDer_area
: 0)) / 8 *
275 pciep
.num_channels
) * 1e6
;
278 void PCIeController::computeEnergy() {
282 double SerDer_gates
= 0;
283 double pmos_to_nmos_sizing_r
= pmos_to_nmos_sz_ratio();
287 /* Assuming PCIe is bit-slice based architecture
288 * This is the reason for /8 in both area and power calculation
289 * to get per lane numbers
292 if (pciep
.type
== 0) { //high performance PCIe
294 //Cadence ChipEstimate using 65nm the controller includes everything: the PHY, the data link and transaction layer
295 ctrl_dyn
= 3.75e-9 / 8 * g_tp
.peri_global
.Vdd
/ 1.1 *
296 g_tp
.peri_global
.Vdd
/ 1.1 * (interface_ip
.F_sz_nm
/ 65.0);
297 // //Cadence ChipEstimate using 65nm soft IP;
298 // frontend_dyn = 0.27e-9/8*g_tp.peri_global.Vdd/1.1*g_tp.peri_global.Vdd/1.1*(interface_ip.F_sz_nm/65.0);
299 //SerDer_dyn is power not energy, scaling from 10mw/Gb/s @90nm
300 //PCIe 2.0 max per lane speed is 4Gb/s
301 SerDer_dyn
= 0.01 * 4 * (interface_ip
.F_sz_um
/0.09) *
302 g_tp
.peri_global
.Vdd
/ 1.2 * g_tp
.peri_global
.Vdd
/1.2;
304 //Cadence ChipEstimate using 65nm
305 ctrl_gates
= 900000 / 8 * pciep
.num_channels
;
306 // frontend_gates = 120000/8;
307 // SerDer_gates = 200000/8;
308 NMOS_sizing
= 5 * g_tp
.min_w_nmos_
;
309 PMOS_sizing
= 5 * g_tp
.min_w_nmos_
* pmos_to_nmos_sizing_r
;
312 //Cadence ChipEstimate using 65nm the controller includes everything: the PHY, the data link and transaction layer
313 ctrl_dyn
= 2.21e-9 / 8 * g_tp
.peri_global
.Vdd
/ 1.1 *
314 g_tp
.peri_global
.Vdd
/ 1.1 * (interface_ip
.F_sz_nm
/ 65.0);
315 // //Cadence ChipEstimate using 65nm soft IP;
316 // frontend_dyn = 0.27e-9/8*g_tp.peri_global.Vdd/1.1*g_tp.peri_global.Vdd/1.1*(interface_ip.F_sz_nm/65.0);
317 //SerDer_dyn is power not energy, scaling from 10mw/Gb/s @90nm
318 //PCIe 2.0 max per lane speed is 4Gb/s
319 SerDer_dyn
= 0.01 * 4 * (interface_ip
.F_sz_um
/ 0.09) *
320 g_tp
.peri_global
.Vdd
/ 1.2 * g_tp
.peri_global
.Vdd
/1.2;
322 //Cadence ChipEstimate using 65nm
323 ctrl_gates
= 200000 / 8 * pciep
.num_channels
;
324 // frontend_gates = 120000/8;
325 SerDer_gates
= 200000 / 8 * pciep
.num_channels
;
326 NMOS_sizing
= g_tp
.min_w_nmos_
;
327 PMOS_sizing
= g_tp
.min_w_nmos_
* pmos_to_nmos_sizing_r
;
331 //covert to energy per clock cycle
332 SerDer_dyn
/= pciep
.clockRate
;
334 power
.readOp
.dynamic
= (ctrl_dyn
+ (pciep
.withPHY
? SerDer_dyn
: 0)) *
336 power
.readOp
.leakage
= (ctrl_gates
+ (pciep
.withPHY
? SerDer_gates
: 0)) *
337 cmos_Isub_leakage(NMOS_sizing
, PMOS_sizing
, 2, nand
) *
338 g_tp
.peri_global
.Vdd
;//unit W
339 double long_channel_device_reduction
=
340 longer_channel_device_reduction(Uncore_device
);
341 power
.readOp
.longer_channel_leakage
=
342 power
.readOp
.leakage
* long_channel_device_reduction
;
343 power
.readOp
.gate_leakage
= (ctrl_gates
+
344 (pciep
.withPHY
? SerDer_gates
: 0)) *
345 cmos_Ig_leakage(NMOS_sizing
, PMOS_sizing
, 2, nand
) *
346 g_tp
.peri_global
.Vdd
;//unit W
349 output_data
.subthreshold_leakage_power
=
350 longer_channel_device
? power
.readOp
.longer_channel_leakage
:
351 power
.readOp
.leakage
;
352 output_data
.gate_leakage_power
= power
.readOp
.gate_leakage
;
353 output_data
.peak_dynamic_power
= power
.readOp
.dynamic
* pcies
.duty_cycle
;
354 output_data
.runtime_dynamic_energy
=
355 power
.readOp
.dynamic
* pcies
.perc_load
;
358 void PCIeController::set_pcie_param() {
359 int num_children
= xml_data
->nChildNode("param");
361 for (i
= 0; i
< num_children
; i
++) {
362 XMLNode
* paramNode
= xml_data
->getChildNodePtr("param", &i
);
363 XMLCSTR node_name
= paramNode
->getAttribute("name");
364 XMLCSTR value
= paramNode
->getAttribute("value");
367 warnMissingParamName(paramNode
->getAttribute("id"));
369 ASSIGN_FP_IF("pcie_clockRate", pciep
.clockRate
);
370 ASSIGN_INT_IF("num_units", pciep
.num_units
);
371 ASSIGN_INT_IF("num_channels", pciep
.num_channels
);
372 ASSIGN_INT_IF("type", pciep
.type
);
373 ASSIGN_ENUM_IF("withPHY", pciep
.withPHY
, bool);
376 warnUnrecognizedParam(node_name
);
380 // Change from MHz to Hz
381 pciep
.clockRate
*= 1e6
;
383 num_children
= xml_data
->nChildNode("stat");
384 for (i
= 0; i
< num_children
; i
++) {
385 XMLNode
* statNode
= xml_data
->getChildNodePtr("stat", &i
);
386 XMLCSTR node_name
= statNode
->getAttribute("name");
387 XMLCSTR value
= statNode
->getAttribute("value");
390 warnMissingStatName(statNode
->getAttribute("id"));
392 ASSIGN_FP_IF("duty_cycle", pcies
.duty_cycle
);
393 ASSIGN_FP_IF("perc_load", pcies
.perc_load
);
396 warnUnrecognizedStat(node_name
);
401 FlashController::FlashController(XMLNode
* _xml_data
,
402 InputParameter
* interface_ip_
)
403 : McPATComponent(_xml_data
, interface_ip_
) {
404 name
= "Flash Controller";
408 void FlashController::computeArea() {
412 /* Assuming Flash is bit-slice based architecture
413 * This is the reason for /8 in both area and power calculation
414 * to get per lane numbers
417 if (fcp
.type
== 0) { //high performance flash controller
418 cout
<< "Current McPAT does not support high performance flash "
419 << "controller since even low power designs are enough for "
420 << "maintain throughput" <<endl
;
423 ctrl_area
= 0.243 * (interface_ip
.F_sz_um
/ 0.065) *
424 (interface_ip
.F_sz_um
/ 0.065);
425 //Area estimation based on Cadence ChipEstimate @ 65nm: NANDFLASH-CTRL
427 SerDer_area
= 0.36 / 8 * (interface_ip
.F_sz_um
/ 0.065) *
428 (interface_ip
.F_sz_um
/ 0.065);
431 double number_channel
= 1 + (fcp
.num_channels
- 1) * 0.2;
432 output_data
.area
= (ctrl_area
+ (fcp
.withPHY
? SerDer_area
: 0)) *
433 1e6
* number_channel
;
436 void FlashController::computeEnergy() {
441 double pmos_to_nmos_sizing_r
= pmos_to_nmos_sz_ratio();
445 /* Assuming Flash is bit-slice based architecture
446 * This is the reason for /8 in both area and power calculation
447 * to get per lane numbers
450 if (fcp
.type
== 0) { //high performance flash controller
451 cout
<< "Current McPAT does not support high performance flash "
452 << "controller since even low power designs are enough for "
453 << "maintain throughput" <<endl
;
455 NMOS_sizing
= 5 * g_tp
.min_w_nmos_
;
456 PMOS_sizing
= 5 * g_tp
.min_w_nmos_
* pmos_to_nmos_sizing_r
;
458 //based On PCIe PHY TSMC65GP from Cadence ChipEstimate @ 65nm, it
459 //support 8x lanes with each lane speed up to 250MB/s (PCIe1.1x).
460 //This is already saturate the 200MB/s of the flash controller core
463 SerDer_gates
= 200000 / 8;
464 NMOS_sizing
= g_tp
.min_w_nmos_
;
465 PMOS_sizing
= g_tp
.min_w_nmos_
* pmos_to_nmos_sizing_r
;
468 //Cadence ChipEstimate using 65nm the controller 125mW for every
469 //200MB/s This is power not energy!
470 ctrl_dyn
= 0.125 * g_tp
.peri_global
.Vdd
/ 1.1 * g_tp
.peri_global
.Vdd
/
471 1.1 * (interface_ip
.F_sz_nm
/ 65.0);
472 //SerDer_dyn is power not energy, scaling from 10mw/Gb/s @90nm
473 SerDer_dyn
= 0.01 * 1.6 * (interface_ip
.F_sz_um
/ 0.09) *
474 g_tp
.peri_global
.Vdd
/ 1.2 * g_tp
.peri_global
.Vdd
/ 1.2;
475 //max Per controller speed is 1.6Gb/s (200MB/s)
478 double number_channel
= 1 + (fcp
.num_channels
- 1) * 0.2;
479 power
.readOp
.dynamic
= (ctrl_dyn
+ (fcp
.withPHY
? SerDer_dyn
: 0)) *
481 power
.readOp
.leakage
= ((ctrl_gates
+ (fcp
.withPHY
? SerDer_gates
: 0)) *
483 cmos_Isub_leakage(NMOS_sizing
, PMOS_sizing
, 2, nand
) *
484 g_tp
.peri_global
.Vdd
;//unit W
485 double long_channel_device_reduction
=
486 longer_channel_device_reduction(Uncore_device
);
487 power
.readOp
.longer_channel_leakage
=
488 power
.readOp
.leakage
* long_channel_device_reduction
;
489 power
.readOp
.gate_leakage
=
490 ((ctrl_gates
+ (fcp
.withPHY
? SerDer_gates
: 0)) * number_channel
) *
491 cmos_Ig_leakage(NMOS_sizing
, PMOS_sizing
, 2, nand
) *
492 g_tp
.peri_global
.Vdd
;//unit W
495 output_data
.subthreshold_leakage_power
=
496 longer_channel_device
? power
.readOp
.longer_channel_leakage
:
497 power
.readOp
.leakage
;
498 output_data
.gate_leakage_power
= power
.readOp
.gate_leakage
;
499 output_data
.peak_dynamic_power
= power
.readOp
.dynamic
* fcs
.duty_cycle
;
500 output_data
.runtime_dynamic_energy
= power
.readOp
.dynamic
* fcs
.perc_load
;
503 void FlashController::set_fc_param()
505 int num_children
= xml_data
->nChildNode("param");
507 for (i
= 0; i
< num_children
; i
++) {
508 XMLNode
* paramNode
= xml_data
->getChildNodePtr("param", &i
);
509 XMLCSTR node_name
= paramNode
->getAttribute("name");
510 XMLCSTR value
= paramNode
->getAttribute("value");
513 warnMissingParamName(paramNode
->getAttribute("id"));
515 ASSIGN_INT_IF("num_channels", fcp
.num_channels
);
516 ASSIGN_INT_IF("type", fcp
.type
);
517 ASSIGN_ENUM_IF("withPHY", fcp
.withPHY
, bool);
520 warnUnrecognizedParam(node_name
);
524 num_children
= xml_data
->nChildNode("stat");
525 for (i
= 0; i
< num_children
; i
++) {
526 XMLNode
* statNode
= xml_data
->getChildNodePtr("stat", &i
);
527 XMLCSTR node_name
= statNode
->getAttribute("name");
528 XMLCSTR value
= statNode
->getAttribute("value");
531 warnMissingStatName(statNode
->getAttribute("id"));
533 ASSIGN_FP_IF("duty_cycle", fcs
.duty_cycle
);
534 ASSIGN_FP_IF("perc_load", fcs
.perc_load
);
537 warnUnrecognizedStat(node_name
);