c4b137869bd552aed0303182a821a1f65a083410
[gem5.git] / mem / bridge.cc
1
2 /*
3 * Copyright (c) 2006 The Regents of The University of Michigan
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /**
31 * @file Definition of a simple bus bridge without buffering.
32 */
33
34
35 #include "base/trace.hh"
36 #include "mem/bridge.hh"
37 #include "sim/builder.hh"
38
39 void
40 Bridge::init()
41 {
42 // Make sure that both sides are connected to.
43 if (sideA == NULL || sideB == NULL)
44 panic("Both ports of bus bridge are not connected to a bus.\n");
45 }
46
47
48 /** Function called by the port when the bus is recieving a Timing
49 * transaction.*/
50 bool
51 Bridge::recvTiming(Packet *pkt, Side id)
52 {
53 if (blockedA && id == SideA)
54 return false;
55 if (blockedB && id == SideB)
56 return false;
57
58 if (delay) {
59 if (!sendEvent.scheduled())
60 sendEvent.schedule(curTick + delay);
61 if (id == SideA) {
62 inboundA.push_back(std::make_pair<Packet*, Tick>(pkt, curTick));
63 blockCheck(SideA);
64 } else {
65 inboundB.push_back(std::make_pair<Packet*, Tick>(pkt, curTick));
66 blockCheck(SideB);
67 }
68 } else {
69 if (id == SideB) {
70 sideA->sendPkt(pkt);
71 blockCheck(SideB);
72 } else {
73 sideB->sendPkt(pkt);
74 blockCheck(SideA);
75 }
76 }
77 return true;
78
79 }
80
81 void
82 Bridge::blockCheck(Side id)
83 {
84 /* Check that we still have buffer space available. */
85 if (id == SideB) {
86 if (sideA->numQueued() + inboundB.size() >= queueSizeA && !blockedB) {
87 sideB->sendStatusChange(Port::Blocked);
88 blockedB = true;
89 } else if (sideA->numQueued() + inboundB.size() < queueSizeA && blockedB) {
90 sideB->sendStatusChange(Port::Unblocked);
91 blockedB = false;
92 }
93 } else {
94 if (sideB->numQueued() + inboundA.size() >= queueSizeB && !blockedA) {
95 sideA->sendStatusChange(Port::Blocked);
96 blockedA = true;
97 } else if (sideB->numQueued() + inboundA.size() < queueSizeB && blockedA) {
98 sideA->sendStatusChange(Port::Unblocked);
99 blockedA = false;
100 }
101 }
102 }
103
104 void Bridge::timerEvent()
105 {
106 Tick t = 0;
107
108 assert(inboundA.size() || inboundB.size());
109 if (inboundA.size()) {
110 while (inboundA.front().second <= curTick + delay){
111 sideB->sendPkt(inboundA.front());
112 inboundA.pop_front();
113 }
114 if (inboundA.size())
115 t = inboundA.front().second + delay;
116 }
117 if (inboundB.size()) {
118 while (inboundB.front().second <= curTick + delay){
119 sideB->sendPkt(inboundA.front());
120 inboundB.pop_front();
121 }
122 if (inboundB.size())
123 if (t == 0)
124 t = inboundB.front().second + delay;
125 else
126 t = std::min(t,inboundB.front().second + delay);
127 } else {
128 panic("timerEvent() called but nothing to do?");
129 }
130
131 if (t != 0)
132 sendEvent.schedule(t);
133 }
134
135
136 void
137 Bridge::BridgePort::sendPkt(Packet *pkt)
138 {
139 if (!sendTiming(pkt))
140 outbound.push_back(std::make_pair<Packet*,Tick>(pkt, curTick));
141 }
142
143 void
144 Bridge::BridgePort::sendPkt(std::pair<Packet*, Tick> p)
145 {
146 if (!sendTiming(p.first))
147 outbound.push_back(p);
148 }
149
150
151 Packet *
152 Bridge::BridgePort::recvRetry()
153 {
154 Packet *pkt;
155 assert(outbound.size() > 0);
156 assert(outbound.front().second >= curTick + bridge->delay);
157 pkt = outbound.front().first;
158 outbound.pop_front();
159 bridge->blockCheck(side);
160 return pkt;
161 }
162
163 /** Function called by the port when the bus is recieving a Atomic
164 * transaction.*/
165 Tick
166 Bridge::recvAtomic(Packet *pkt, Side id)
167 {
168 pkt->time += delay;
169
170 if (id == SideA)
171 return sideB->sendAtomic(pkt);
172 else
173 return sideA->sendAtomic(pkt);
174 }
175
176 /** Function called by the port when the bus is recieving a Functional
177 * transaction.*/
178 void
179 Bridge::recvFunctional(Packet *pkt, Side id)
180 {
181 pkt->time += delay;
182 std::list<std::pair<Packet*, Tick> >::iterator i;
183 bool pktContinue = true;
184
185 for(i = inboundA.begin(); i != inboundA.end(); ++i) {
186 if (pkt->intersect(i->first)) {
187 pktContinue &= fixPacket(pkt, i->first);
188 }
189 }
190
191 for(i = inboundB.begin(); i != inboundB.end(); ++i) {
192 if (pkt->intersect(i->first)) {
193 pktContinue &= fixPacket(pkt, i->first);
194 }
195 }
196
197 for(i = sideA->outbound.begin(); i != sideA->outbound.end(); ++i) {
198 if (pkt->intersect(i->first)) {
199 pktContinue &= fixPacket(pkt, i->first);
200 }
201 }
202
203 for(i = sideB->outbound.begin(); i != sideB->outbound.end(); ++i) {
204 if (pkt->intersect(i->first)) {
205 pktContinue &= fixPacket(pkt, i->first);
206 }
207 }
208
209 if (pktContinue) {
210 if (id == SideA)
211 sideB->sendFunctional(pkt);
212 else
213 sideA->sendFunctional(pkt);
214 }
215 }
216
217 /** Function called by the port when the bus is recieving a status change.*/
218 void
219 Bridge::recvStatusChange(Port::Status status, Side id)
220 {
221 if (status == Port::Blocked || status == Port::Unblocked)
222 return ;
223
224 if (id == SideA)
225 sideB->sendStatusChange(status);
226 else
227 sideA->sendStatusChange(status);
228 }
229
230 void
231 Bridge::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, Side id)
232 {
233 if (id == SideA)
234 sideB->getPeerAddressRanges(resp, snoop);
235 else
236 sideA->getPeerAddressRanges(resp, snoop);
237 }
238
239 BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge)
240
241 Param<int> queue_size_a;
242 Param<int> queue_size_b;
243 Param<Tick> delay;
244 Param<bool> write_ack;
245
246 END_DECLARE_SIM_OBJECT_PARAMS(Bridge)
247
248 BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge)
249
250 INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"),
251 INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"),
252 INIT_PARAM(delay, "The miminum delay to cross this bridge"),
253 INIT_PARAM(write_ack, "Acknowledge any writes that are received.")
254
255 END_INIT_SIM_OBJECT_PARAMS(Bridge)
256
257 CREATE_SIM_OBJECT(Bridge)
258 {
259 return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay,
260 write_ack);
261 }
262
263 REGISTER_SIM_OBJECT("Bridge", Bridge)