SystemC Library API Reference Manual
Reference documentation for the Simics SystemC Library.
 
Loading...
Searching...
No Matches
pci_mapping_interconnect.h
Go to the documentation of this file.
1/* -*- mode: C++; c-file-style: "virtutech-c++" -*-
2
3 © 2015 Intel Corporation
4
5 This software and the related documents are Intel copyrighted materials, and
6 your use of them is governed by the express license under which they were
7 provided to you ("License"). Unless the License provides otherwise, you may
8 not use, modify, copy, publish, distribute, disclose or transmit this software
9 or the related documents without Intel's prior written permission.
10
11 This software and the related documents are provided as is, with no express or
12 implied warranties, other than those that are expressly stated in the License.
13*/
14
15#ifndef SIMICS_SYSTEMC_COMPOSITE_PCI_MAPPING_INTERCONNECT_H
16#define SIMICS_SYSTEMC_COMPOSITE_PCI_MAPPING_INTERCONNECT_H
17
18#if defined SIMICS_5_API || defined SIMICS_6_API
19
20#include <systemc>
21#include <tlm>
22#include <tlm_utils/multi_passthrough_target_socket.h>
23#include <tlm_utils/simple_target_socket.h>
24#include <tlm_utils/simple_initiator_socket.h>
25
32
37
38#include <vector>
39
40namespace { // NOLINT(build/namespaces_headers)
41const char *const PCI_MAPPING_INTERCONNECT_TAG = "intel/PciMappingInterconnect";
42} // namespace
43
44namespace simics {
45namespace systemc {
46namespace composite {
47
50template<typename TSocket>
51class PciMappingInterconnectExtensionSender
52 : public iface::ExtensionSender<TSocket> {
53 public:
54 virtual ~PciMappingInterconnectExtensionSender() {}
55 virtual void send_extension(iface::Transaction *transaction) {
56 failed_transaction_ = iface::Transaction(NULL);
57 iface::ExtensionSender<TSocket>::send_extension(transaction);
58 }
59 virtual void send_failed(iface::Transaction *transaction) {
60 failed_transaction_ = *transaction;
61 iface::ExtensionSender<TSocket>::send_failed(transaction);
62 }
63 iface::Transaction failed_transaction_;
64};
65
84template <unsigned int BUSWIDTH, typename TYPES>
85class PciMappingInterconnect : public sc_core::sc_module {
86 private:
87 // Socket types used by the interconnect
88 typedef tlm_utils::simple_target_socket<
89 PciMappingInterconnect, BUSWIDTH, TYPES> target_socket_t;
90 typedef tlm_utils::multi_passthrough_target_socket<
91 PciMappingInterconnect, BUSWIDTH, TYPES> multi_target_socket_t;
92 typedef tlm_utils::simple_initiator_socket<
93 PciMappingInterconnect, BUSWIDTH, TYPES> initiator_socket_t;
94 typedef struct {
95 tlm::tlm_target_socket<BUSWIDTH, TYPES> *tlm;
96 tlm_utils::multi_target_base<BUSWIDTH, TYPES> *multi;
97 } supported_target_socket_t;
98
99 public:
100#ifndef SYSTEMC_3_0_0
101 SC_HAS_PROCESS(PciMappingInterconnect);
102#endif
103 explicit PciMappingInterconnect(
104 sc_core::sc_module_name = "PciMappingInterconnect")
105 : target_socket("target_socket"),
106 simics_target_socket("simics_target_socket"),
107 pci_bus_initiator_socket("pci_bus_initiator_socket"),
108 initiator_sockets_("initiator_socket"),
109 pci_target_socket_(),
110 pci_device_target_socket_(),
111 pci_bus_target_socket_("pci_bus_target_socket"),
112 number_of_functions_(1),
113 mapping_id_offset_(0x10100) { // 255 + 64k (max VFs) + 1 (round up)
114 target_socket.register_b_transport(
115 this, &PciMappingInterconnect::b_transport);
116 target_socket.register_transport_dbg(
117 this, &PciMappingInterconnect::transport_dbg);
118 simics_target_socket.register_b_transport(
119 this, &PciMappingInterconnect::simics_b_transport);
120 pci_bus_target_socket_.register_b_transport(
121 this, &PciMappingInterconnect::pci_bus_b_transport);
122 pci_bus_target_socket_.register_transport_dbg(
123 this, &PciMappingInterconnect::pci_bus_transport_dbg);
124 pci_bus_target_socket_.register_get_direct_mem_ptr(
125 this, &PciMappingInterconnect::pci_bus_get_direct_mem_ptr);
126 pci_bus_initiator_socket.register_invalidate_direct_mem_ptr(
127 this, &PciMappingInterconnect::pci_bus_invalidate_direct_mem_ptr);
128 sender_.init(&pci_bus_initiator_socket);
129 extension_.init(&sender_);
130 }
131
132 virtual void before_end_of_elaboration();
133
134 void retrieveFunctionData(int id, int bar);
135
136 void connect(iface::PciDeviceQueryInterface *pci, ConfObjectRef o);
137
138 void connectConfig(iface::BaseAddressRegisterQueryInterface *bar,
139 simics2tlm::IoMemory *gasket,
140 ConfObjectRef o);
141
142 void connectMmio(iface::BaseAddressRegisterQueryInterface *bar,
143 simics2tlm::IoMemory *gasket,
144 ConfObjectRef o);
145
146 void busReset();
147
148 // Sockets bound by external logic (see also private scope):
150 multi_target_socket_t target_socket;
151 multi_target_socket_t simics_target_socket;
153 initiator_socket_t pci_bus_initiator_socket;
154
155 private:
156 // TLM2 methods
157 void b_transport(int id, tlm::tlm_generic_payload &trans, // NOLINT: SystemC API
158 sc_core::sc_time &t); // NOLINT: SystemC API
159 unsigned int transport_dbg(int id, tlm::tlm_generic_payload &trans); // NOLINT: SystemC API
160 void simics_b_transport(int id, tlm::tlm_generic_payload &trans, // NOLINT: SystemC API
161 sc_core::sc_time &t); // NOLINT: SystemC API
162 void pci_bus_b_transport(tlm::tlm_generic_payload &trans, // NOLINT: SystemC API
163 sc_core::sc_time &t); // NOLINT: SystemC API
164 unsigned int pci_bus_transport_dbg(tlm::tlm_generic_payload &trans); // NOLINT: SystemC API
165 bool pci_bus_get_direct_mem_ptr(tlm::tlm_generic_payload &trans, // NOLINT: SystemC API
166 tlm::tlm_dmi &dmi_data); // NOLINT: SystemC API
167 void pci_bus_invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
168 sc_dt::uint64 end_range);
169
170 // Helper methods
171 void castToTarget(sc_core::sc_object *object,
172 supported_target_socket_t *target);
173 template <typename TGasket>
174 void bindToGasket(supported_target_socket_t target,
175 TGasket *gasket, ConfObjectRef o, int id);
176 void updateCommand(int id, uint16_t old_command);
177 void updateBaseAddress(int id, int bar);
178 void updateMemoryMapping(bool enable, types::addr_space_t space,
179 uint64_t base_address, int bar_size_bits,
180 int mapping_id);
181 void interceptBarAccess(int id, tlm::tlm_generic_payload &trans, // NOLINT
182 sc_core::sc_time &t); // NOLINT: SystemC API
183
184 // Sockets created and bound by internal logic (see also public scope):
185 // IC -> Device, forwards the incoming PCI transactions
186 sc_core::sc_vector<initiator_socket_t> initiator_sockets_;
187 supported_target_socket_t pci_target_socket_;
188 initiator_socket_t pci_device_initiator_socket_;
189 supported_target_socket_t pci_device_target_socket_;
190 // Device -> IC, intercept upstream pci-bus transactions
191 target_socket_t pci_bus_target_socket_;
192
193 struct function_data_t {
194 int function;
195 uint16_t command;
196 uint32_t base_address[6];
197 };
198 std::vector<function_data_t> function_data_;
199 int number_of_functions_;
200 int mapping_id_offset_;
201 iface::BaseAddressRegisterQueryInterface::BarInfo bar_info_;
202
203 PciMappingInterconnectExtensionSender<
204 initiator_socket_t> sender_;
205 iface::PciBusExtension extension_;
206};
207
208template <unsigned int BUSWIDTH, typename TYPES>
209void PciMappingInterconnect<BUSWIDTH, TYPES>::before_end_of_elaboration() {
210 // Because of the way SystemC has been designed, we cannot create new
211 // sockets dynamically ouside of the CTOR except for in the
212 // before_end_of_elaboration() method.
213
214 // Create initiator sockets equal to the number of PCI functions
215 initiator_sockets_.init(number_of_functions_);
216 for (std::size_t i = 0; i < initiator_sockets_.size(); ++i) {
217 if (pci_target_socket_.tlm) {
218 initiator_sockets_[i].bind(*pci_target_socket_.tlm);
219 } else {
220 initiator_sockets_[i].bind(*pci_target_socket_.multi);
221 }
222 }
223
224 // Allocate and initialize function data based on device configuration
225 function_data_ = std::vector<function_data_t>(number_of_functions_);
226 int prev_function = -1;
227 int id = -1;
228 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
229 = bar_info_.begin(); it != bar_info_.end(); ++it) {
230 int current_function = (*it).function;
231 if (current_function != prev_function) {
232 function_data_[++id].function = current_function;
233 prev_function = current_function;
234 }
235 }
236
237 if (pci_device_target_socket_.tlm) {
238 pci_device_initiator_socket_.bind(*pci_device_target_socket_.tlm);
239 } else if (pci_device_target_socket_.multi) {
240 pci_device_initiator_socket_.bind(*pci_device_target_socket_.multi);
241 }
242}
243
244// Get up-to-date BAR/CMD information whenever we need it. It cannot be cached
245// in the interconnect module as it might change over time by the model,
246// reverse execution, checkpoint restore, ...
247// @id is the function ID (socket ID) currently accessed
248// @bar is the BAR number currently access, or -1 for config register access in
249// which case all BARs must be retrieved
250template <unsigned int BUSWIDTH, typename TYPES>
251void PciMappingInterconnect<BUSWIDTH, TYPES>::retrieveFunctionData(
252 int id, int bar) {
253 tlm::tlm_generic_payload trans;
254 trans.set_command(tlm::TLM_READ_COMMAND);
255 trans.set_data_length(4);
256 trans.set_streaming_width(4);
257
258 uint32_t value = 0;
259 trans.set_data_ptr(reinterpret_cast<unsigned char *>(&value));
260 trans.set_address(0x4);
261
262 auto ret = initiator_sockets_[id]->transport_dbg(trans);
263 if (ret == 0) {
264 // The target is not able to perform the transport_dbg.
265 // The PCI interconnector is unable to get the up-to-date
266 // BAR/CMD information which may cause unexpected behavior
267 return;
268 }
269
270 function_data_[id].command = value;
271
272 // -1 means config register access => read all bars
273 bool all_bars = (bar == -1) ? true : false;
274
275 // NOTE: the IO, Mem32, Mem64 bits are ignored by updateMemoryMapping, no
276 // need to filter them out here
277 int function = function_data_[id].function;
278 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator
279 it = bar_info_.begin(); it != bar_info_.end(); ++it) {
280 // BarInfo holds _all_ BARs for _all_ functions. This can probably
281 // be done in a much more clever way that avoids iterating over the
282 // entire BarInfo for each function in the outer loop.
283 if ((*it).function != function) {
284 continue;
285 }
286 if (all_bars) {
287 bar = ((*it).offset - 0x10) / 4;
288 } else if (bar != ((*it).offset - 0x10) / 4) {
289 continue;
290 }
291 uint32_t base_address = 0;
292 trans.set_address((*it).offset);
293 trans.set_data_ptr(
294 reinterpret_cast<unsigned char *>(&base_address));
295 trans.set_data_length(sizeof base_address);
296 trans.set_streaming_width(trans.get_data_length());
297 initiator_sockets_[id]->transport_dbg(trans);
298 function_data_[id].base_address[bar] = base_address;
299 if ((*it).is_64bit) {
300 // Read higher 32 bits in next BAR
301 trans.set_address((*it).offset + 4);
302 trans.set_data_ptr(
303 reinterpret_cast<unsigned char *>(&base_address));
304 trans.set_data_length(sizeof base_address);
305 trans.set_streaming_width(trans.get_data_length());
306 initiator_sockets_[id]->transport_dbg(trans);
307 function_data_[id].base_address[bar + 1] = base_address;
308 }
309 }
310}
311
320template <unsigned int BUSWIDTH, typename TYPES>
321void PciMappingInterconnect<BUSWIDTH, TYPES>::connect(
322 iface::PciDeviceQueryInterface *pci, ConfObjectRef o) {
323 castToTarget(pci->getPciDeviceTargetSocket(),
324 &pci_device_target_socket_);
325 castToTarget(pci->getConfigTargetSocket(), &pci_target_socket_);
326 tlm::tlm_initiator_socket<BUSWIDTH, TYPES> *initiator
327 = dynamic_cast<tlm::tlm_initiator_socket<BUSWIDTH, TYPES> *>(
328 pci->getPciBusInitiatorSocket());
329 if (initiator) {
330 pci_bus_target_socket_.bind(*initiator);
331 } else {
332 SIM_LOG_ERROR(o, Log_Configuration,
333 "object returned by getPciBusInitiatorSocket was not"
334 " a tlm::tlm_initiator_socket.");
335 }
336}
337
344template <unsigned int BUSWIDTH, typename TYPES>
345void PciMappingInterconnect<BUSWIDTH, TYPES>::connectConfig(
346 iface::BaseAddressRegisterQueryInterface *bar,
347 simics2tlm::IoMemory *gasket, ConfObjectRef o) {
348 // F0 must always exist
349 // NOTE: by Simics convention, F0 always get mapping ID = 255
350 gasket->addGasket(
351 255, simics2tlm::createGasket(&target_socket, o));
352
353 // How many more functions are there?
354 bar_info_ = bar->getBarInfo();
355 int prev_function = 0;
356 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
357 = bar_info_.begin(); it != bar_info_.end(); ++it) {
358 int current_function = (*it).function;
359 if (current_function != prev_function) {
360 ++number_of_functions_;
361 prev_function = current_function;
362 gasket->addGasket(255 + current_function,
363 simics2tlm::createGasket(&target_socket, o));
364 }
365 FATAL_ERROR_IF(current_function < prev_function,
366 "BarInfo must be sorted on function number"
367 " in ascending order");
368 }
369}
370
376template <unsigned int BUSWIDTH, typename TYPES>
377void PciMappingInterconnect<BUSWIDTH, TYPES>::connectMmio(
378 iface::BaseAddressRegisterQueryInterface *bar,
379 simics2tlm::IoMemory *gasket, ConfObjectRef o) {
381 = bar->getBarTargetSockets();
382 iface::BaseAddressRegisterQueryInterface::BarSockets::const_iterator it;
383 for (iface::BaseAddressRegisterQueryInterface::BarSockets::const_iterator it
384 = bar_sockets.begin(); it != bar_sockets.end(); ++it) {
385 supported_target_socket_t target = {};
386 castToTarget((*it).second, &target);
387 bindToGasket(target, gasket, o,
388 (*it).first.mapping_id + mapping_id_offset_);
389 }
390}
391
393template <unsigned int BUSWIDTH, typename TYPES>
394void PciMappingInterconnect<BUSWIDTH, TYPES>::busReset() {
395 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
396 = bar_info_.begin(); it != bar_info_.end(); ++it) {
397 int mapping_id = (*it).mapping_id + mapping_id_offset_;
399 if ((*it).is_memory) {
401 }
402 extension_.remove_map(space, mapping_id);
403 if (sender_.failed_transaction_.payload()) {
404 SC_REPORT_INFO(PCI_MAPPING_INTERCONNECT_TAG,
405 "Failure to unmap device on bus_reset");
406 }
407 }
408}
409
411
412/*
413 * Intercept the BAR and Command regs, always forward transaction to target to
414 * handle all errors there
415 */
416template <unsigned int BUSWIDTH, typename TYPES>
417void PciMappingInterconnect<BUSWIDTH, TYPES>::b_transport(
418 int id,
419 tlm::tlm_generic_payload &trans, // NOLINT
420 sc_core::sc_time &t) { // NOLINT
421 interceptBarAccess(id, trans, t);
422 initiator_sockets_[id]->b_transport(trans, t);
423}
424
425/*
426 * transport_dbg is side-effect free = forwarded without inspection
427 */
428template <unsigned int BUSWIDTH, typename TYPES>
429unsigned int PciMappingInterconnect<BUSWIDTH, TYPES>::transport_dbg(
430 int id,
431 tlm::tlm_generic_payload &trans) { // NOLINT
432 return initiator_sockets_[id]->transport_dbg(trans);
433}
434
435/*
436 * For pci-device, just relay the incoming transaction to outgoing socket
437 */
438template <unsigned int BUSWIDTH, typename TYPES>
439void PciMappingInterconnect<BUSWIDTH, TYPES>::simics_b_transport(
440 int id, tlm::tlm_generic_payload &trans, // NOLINT
441 sc_core::sc_time &t) { // NOLINT
442 pci_device_initiator_socket_->b_transport(trans, t);
443}
444
445/*
446 * For pci-bus, just relay the incoming transaction to outgoing socket
447 */
448template <unsigned int BUSWIDTH, typename TYPES>
449void PciMappingInterconnect<BUSWIDTH, TYPES>::pci_bus_b_transport(
450 tlm::tlm_generic_payload &trans, // NOLINT
451 sc_core::sc_time &t) { // NOLINT
452 pci_bus_initiator_socket->b_transport(trans, t);
453}
454
455/*
456 * For pci-bus, just relay the incoming transaction to outgoing socket
457 */
458template <unsigned int BUSWIDTH, typename TYPES>
459unsigned int PciMappingInterconnect<BUSWIDTH, TYPES>::pci_bus_transport_dbg(
460 tlm::tlm_generic_payload &trans) { // NOLINT
461 return pci_bus_initiator_socket->transport_dbg(trans);
462}
463
464/*
465 * For pci-bus, just relay the incoming transaction to outgoing socket
466 */
467template <unsigned int BUSWIDTH, typename TYPES>
468bool PciMappingInterconnect<BUSWIDTH, TYPES>::pci_bus_get_direct_mem_ptr(
469 tlm::tlm_generic_payload &trans, // NOLINT
470 tlm::tlm_dmi &dmi_data) { // NOLINT
471 return pci_bus_initiator_socket->get_direct_mem_ptr(trans, dmi_data);
472}
473
474/*
475 * For pci-bus, just relay the incoming BW transaction to target socket
476 */
477template <unsigned int BUSWIDTH, typename TYPES>
478void PciMappingInterconnect<BUSWIDTH, TYPES>::pci_bus_invalidate_direct_mem_ptr(
479 sc_dt::uint64 start_range,
480 sc_dt::uint64 end_range) {
481 pci_bus_target_socket_->invalidate_direct_mem_ptr(start_range,
482 end_range);
483}
484
485// Cast sc_object to a supported target socket and return it.
486// TPciDevice is the type of the PCI device,
487template <unsigned int BUSWIDTH, typename TYPES>
488void PciMappingInterconnect<BUSWIDTH, TYPES>::castToTarget(
489 sc_core::sc_object *object, supported_target_socket_t *target) {
490 tlm::tlm_target_socket<BUSWIDTH, TYPES> *tlm_target
491 = dynamic_cast<tlm::tlm_target_socket<BUSWIDTH, TYPES> *>(object);
492 if (tlm_target) {
493 target->tlm = tlm_target;
494 return;
495 }
496
497 tlm_utils::multi_target_base<BUSWIDTH, TYPES> *multi_target
498 = dynamic_cast<tlm_utils::multi_target_base<BUSWIDTH, TYPES> *>(object);
499 if (multi_target) {
500 target->multi = multi_target;
501 return;
502 }
503
504 SC_REPORT_ERROR(PCI_MAPPING_INTERCONNECT_TAG,
505 "Unable to dynamic-cast PCI target socket");
506}
507
508template <unsigned int BUSWIDTH, typename TYPES>
509template <typename TGasket>
510void PciMappingInterconnect<BUSWIDTH, TYPES>::bindToGasket(
511 supported_target_socket_t target,
512 TGasket *gasket, ConfObjectRef o, int id) {
513 if (target.tlm) {
514 gasket->addGasket(id, simics2tlm::createGasket(target.tlm, o));
515 } else if (target.multi) {
516 // coverity[var_deref_model], safe cast based on castToTarget() func
517 gasket->addGasket(id, simics2tlm::createGasket(target.multi, o));
518 }
519}
520
521/*
522 * When command register is written to, the mappings need to be re-evaluated
523 * and possibly updated.
524 *
525 * There is no error handling, so if the mapping fails this will only be logged
526 * but the access will still pass (i.e. transaction forwarded to target device
527 * where registers are updated without side-effects)
528 */
529template <unsigned int BUSWIDTH, typename TYPES>
530void PciMappingInterconnect<BUSWIDTH, TYPES>::updateCommand(
531 int id, uint16_t old_command) {
532 int command = function_data_[id].command;
533 if (command == old_command) {
534 return;
535 }
536 int function = function_data_[id].function;
537 bool mem_enable = (command >> 1) & 1;
538 bool io_enable = command & 1;
539
540 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
541 = bar_info_.begin(); it != bar_info_.end(); ++it) {
542 if ((*it).function == function) {
543 bool enable
544 = (*it).is_memory ? mem_enable : io_enable;
546 = (*it).is_memory ? types::Sim_Addr_Space_Memory
548 int bar = ((*it).offset - 0x10) / 4;
549 uint64_t base_address = function_data_[id].base_address[bar];
550 if ((*it).is_64bit) {
551 base_address |= static_cast<uint64_t>(
552 function_data_[id].base_address[bar + 1]) << 32;
553 }
554 updateMemoryMapping(enable, space, base_address,
555 (*it).size_bits,
556 (*it).mapping_id + mapping_id_offset_);
557 }
558 }
559}
560
561/*
562 * When BAR register is written to, the mapping need to be re-evaluated and
563 * possibly updated.
564 *
565 * There is no error handling, so if the mapping fails this will only be logged
566 * but the access will still pass (i.e. transaction forwarded to target device
567 * where registers are updated without side-effects)
568 */
569template <unsigned int BUSWIDTH, typename TYPES>
570void PciMappingInterconnect<BUSWIDTH, TYPES>::updateBaseAddress(int id,
571 int bar) {
572 int command = function_data_[id].command;
573 int function = function_data_[id].function;
574 bool mem_enable = (command >> 1) & 1;
575 bool io_enable = command & 1;
576 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
577 = bar_info_.begin(); it != bar_info_.end(); ++it) {
578 if ((*it).function == function && (*it).offset == 0x10 + 4 * bar) {
579 bool enable = (*it).is_memory ? mem_enable : io_enable;
580 if (!enable) {
581 // no re-mapping will be done as encoding is not enabled
582 return;
583 }
585 = (*it).is_memory ? types::Sim_Addr_Space_Memory
587 uint64_t base_address = function_data_[id].base_address[bar];
588 if ((*it).is_64bit) {
589 base_address |= static_cast<uint64_t>(
590 function_data_[id].base_address[bar + 1]) << 32;
591 }
592 updateMemoryMapping(enable, space, base_address,
593 (*it).size_bits,
594 (*it).mapping_id + mapping_id_offset_);
595 break;
596 }
597 }
598}
599
600template <unsigned int BUSWIDTH, typename TYPES>
601void PciMappingInterconnect<BUSWIDTH, TYPES>::updateMemoryMapping(
602 bool enable,
604 uint64_t base_address,
605 int bar_size_bits,
606 int mapping_id) {
607 extension_.remove_map(space, mapping_id);
608 if (sender_.failed_transaction_.payload()) {
609 SC_REPORT_INFO(PCI_MAPPING_INTERCONNECT_TAG, "Failure to unmap device");
610 return;
611 }
612
613 if (enable) {
614 types::map_info_t info(base_address & ~((1ULL << bar_size_bits) - 1),
615 0, 1ULL << bar_size_bits,
616 mapping_id);
617 extension_.add_map(space, info);
618
619 if (sender_.failed_transaction_.payload()) {
620 SC_REPORT_INFO(PCI_MAPPING_INTERCONNECT_TAG,
621 "Failure to map device");
622 return;
623 }
624 }
625}
626
627template <unsigned int BUSWIDTH, typename TYPES>
628void PciMappingInterconnect<BUSWIDTH, TYPES>::interceptBarAccess(
629 int id,
630 tlm::tlm_generic_payload &trans, // NOLINT
631 sc_core::sc_time &t) { // NOLINT
632 // Decode the generic payload (GP) struct
633 sc_dt::uint64 offset = trans.get_address();
634 unsigned int size = trans.get_data_length();
635 uint64_t *data = reinterpret_cast<uint64_t *>(trans.get_data_ptr());
636
637 // Check assumptions (but leave it up to target device to report errors)
638 if (trans.get_byte_enable_ptr()) {
639 return;
640 }
641 if (trans.get_streaming_width() != size) {
642 return;
643 }
644 // NOTE: we should also check that address is DWORD/4-byte aligned, but
645 // our Viper/X58 platform seems to address single bytes so ...
646
647 // We are only interested in write access to BARn or Command regs
648 if (trans.is_write()) {
649 uint16_t old_command = function_data_[id].command;
650
651 switch (offset) {
652 case 0x04: { // command & status
653 retrieveFunctionData(id, -1);
654 function_data_[id].command = (*data) & 0xffff; // ignore status
655 updateCommand(id, old_command);
656 break;
657 }
658 case 0x10: // BAR0-BAR5
659 case 0x14:
660 case 0x18:
661 case 0x1c:
662 case 0x20:
663 case 0x24:
664 int bar = (offset - 0x10) / 4;
665 retrieveFunctionData(id, bar);
666 // NOTE: the IO, Mem32, Mem64 bits are ignored by
667 // updateMemoryMapping, no need to filter them out here. In
668 // addition, any bits less than the size of the BAR as defined by
669 // the BarInfo will also be ignored/truncated by
670 // updateMemoryMapping; making sure we always send a naturally
671 // aligned address to Simics
672 function_data_[id].base_address[bar] = *data & 0xffffffff;
673 if (size == 8 && !(offset % 8)) {
674 function_data_[id].base_address[bar + 1] = *data >> 32;
675 }
676 updateBaseAddress(id, bar);
677 break;
678 }
679 }
680}
681
682} // namespace composite
683} // namespace systemc
684} // namespace simics
685
686#endif
687#endif
std::vector< std::pair< BaseAddressRegister, sc_core::sc_object * > > BarSockets
IO/Memory space target socket(s).
Definition: pci_device_query_interface.h:106
@ Log_Configuration
Definition: adapter_log_groups.h:25
addr_space_t
Stand-alone, version of the Simics addr_space_t enum.
Definition: addr_space.h:23
@ Sim_Addr_Space_Memory
Definition: addr_space.h:26
@ Sim_Addr_Space_IO
Definition: addr_space.h:25
Definition: adapter.h:80