-
Notifications
You must be signed in to change notification settings - Fork 0
/
bus.cpp
116 lines (102 loc) · 3.57 KB
/
bus.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include "ensitlm.h"
#include "bus.h"
Bus::Bus(sc_core::sc_module_name name) : sc_core::sc_module(name) {
}
void Bus::map(ensitlm::compatible_socket &port, ensitlm::addr_t start_addr,
ensitlm::addr_t size) {
port_map.insert(std::pair<ensitlm::compatible_socket *, addr_range>(
&port, addr_range(start_addr, start_addr + size - 1)));
}
void Bus::end_of_elaboration() {
// for each target connected to this bus initiator port
for (int i = 0; i < initiator.size(); ++i) {
// get the target
ensitlm::compatible_socket *target =
dynamic_cast<ensitlm::compatible_socket *>(initiator[i]);
if (!target) {
std::cerr << name()
<< ": target is not a tlm_target_socket\n";
abort();
}
// get the set of port maps which correspond to this name
std::pair<port_map_t::iterator, port_map_t::iterator> it =
port_map.equal_range(target);
// if no port map corresponds
if (it.first == it.second) {
std::cerr << name() << ": no address map information "
"available for target "
<< target->name() << "\n";
abort();
}
// iterate through port maps
for (port_map_t::iterator j = it.first; j != it.second; ++j) {
std::pair<addr_range, int> map_entry((*j).second, i);
// add to address map and check for conflicts
if (!addr_map.insert(map_entry).second) {
std::pair<addr_range, int> map_entry_bis =
(*addr_map.find((*j).second));
int k = map_entry_bis.second;
ensitlm::compatible_socket *target_bis =
dynamic_cast<ensitlm::compatible_socket *>(
initiator[k]);
std::cerr << name() << ": address map conflict "
"between target ports "
<< target->name() << " and "
<< target_bis->name() << "\n";
abort();
}
}
}
// #ifdef DEBUG
print_addr_map();
// #endif
}
void Bus::print_addr_map() {
// iterate through port maps
for (addr_map_t::iterator i = addr_map.begin(); i != addr_map.end();
++i) {
std::cout << name() << ": range [" << std::hex
<< (*i).first.begin << "-" << (*i).first.end + 1
<< "[ is mapped to target '"
<< dynamic_cast<ensitlm::compatible_socket *>(
initiator[((*i).second)])->name() << "'\n";
}
}
tlm::tlm_response_status Bus::read(ensitlm::addr_t a, ensitlm::data_t &d) {
if (a % sizeof(ensitlm::data_t)) {
SC_REPORT_ERROR(name(), "unaligned read");
return tlm::TLM_ADDRESS_ERROR_RESPONSE;
}
addr_map_t::iterator it = addr_map.find(addr_range(a, a));
if (it == addr_map.end()) {
std::cerr << name() << ": no target at address " << std::hex
<< a << std::endl;
return tlm::TLM_ADDRESS_ERROR_RESPONSE;
}
tlm::tlm_response_status s =
initiator.read(a - (*it).first.begin, d, (*it).second);
#ifdef DEBUG
std::cout << "Debug: " << name() << ": read access at 0x" << std::hex
<< a << " (data: 0x" << d << ")\n";
#endif
return s;
}
tlm::tlm_response_status Bus::write(ensitlm::addr_t a, ensitlm::data_t d) {
if (a % sizeof(ensitlm::data_t)) {
SC_REPORT_ERROR(name(), "unaligned write");
return tlm::TLM_ADDRESS_ERROR_RESPONSE;
}
addr_map_t::iterator it = addr_map.find(addr_range(a, a));
if (it == addr_map.end()) {
std::cerr << name() << ": no target at address " << std::hex
<< a << std::endl;
return tlm::TLM_ADDRESS_ERROR_RESPONSE;
}
#ifdef DEBUG
std::cout << "Debug: " << name() << ": write access at 0x" << std::hex
<< a << " (data: 0x" << d << ")\n";
#endif
tlm::tlm_response_status s =
initiator.write(a - (*it).first.begin, d, (*it).second);
return s;
}