arch-arm,cpu: Introduce a getEMI virtual method on StaticInst.
[gem5.git] / src / mem / token_port.cc
1 /*
2 * Copyright (c) 2016-2020 Advanced Micro Devices, Inc.
3 * All rights reserved.
4 *
5 * For use for simulation and test purposes only
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 * Authors: Matthew Poremba
34 */
35
36
37 #include "mem/token_port.hh"
38
39 #include "base/trace.hh"
40 #include "debug/TokenPort.hh"
41
42 void
43 TokenRequestPort::bind(Port &peer)
44 {
45 RequestPort::bind(peer);
46 }
47
48 void
49 TokenRequestPort::recvTokens(int num_tokens)
50 {
51 panic_if(!tokenManager, "TokenManager not set for %s.\n", name());
52
53 tokenManager->recvTokens(num_tokens);
54 }
55
56 bool
57 TokenRequestPort::haveTokens(int num_tokens)
58 {
59 panic_if(!tokenManager, "TokenManager not set for %s.\n", name());
60
61 return tokenManager->haveTokens(num_tokens);
62 }
63
64 void
65 TokenRequestPort::acquireTokens(int num_tokens)
66 {
67 panic_if(!tokenManager, "TokenManager not set for %s.\n", name());
68
69 tokenManager->acquireTokens(num_tokens);
70 }
71
72 void
73 TokenRequestPort::setTokenManager(TokenManager *_tokenManager)
74 {
75 tokenManager = _tokenManager;
76 }
77
78 void
79 TokenResponsePort::sendTokens(int num_tokens)
80 {
81 fatal_if(!tokenRequestPort, "Tried sendTokens to non-token requestor!\n");
82
83 // Send tokens to a requestor
84 tokenRequestPort->recvTokens(num_tokens);
85 }
86
87 void
88 TokenResponsePort::bind(Port& peer)
89 {
90 // TokenResponsePort is allowed to bind to either TokenRequestPort or a
91 // RequestPort as fallback. If the type is a RequestPort, tokenRequestPort
92 // is set to nullptr to indicate tokens should not be exchanged.
93 auto *token_request_port = dynamic_cast<TokenRequestPort*>(&peer);
94 auto *request_port = dynamic_cast<RequestPort*>(&peer);
95 if (!token_request_port && !request_port) {
96 fatal("Attempt to bind port %s to unsupported response port %s.",
97 name(), peer.name());
98 } else if (token_request_port) {
99 // response port keeps track of the request port
100 tokenRequestPort = token_request_port;
101
102 // request port also keeps track of response port
103 tokenRequestPort->bind(*this);
104 } else if (request_port) {
105 tokenRequestPort = nullptr;
106 }
107 }
108
109 void
110 TokenResponsePort::unbind()
111 {
112 ResponsePort::responderUnbind();
113 tokenRequestPort = nullptr;
114 }
115
116 void
117 TokenResponsePort::recvRespRetry()
118 {
119 // fallback to QueuedResponsePort-like impl for now
120 panic_if(respQueue.empty(),
121 "Attempted to retry a response when no retry was queued!\n");
122
123 PacketPtr pkt = respQueue.front();
124 bool success = ResponsePort::sendTimingResp(pkt);
125
126 if (success) {
127 respQueue.pop_front();
128 }
129 }
130
131 bool
132 TokenResponsePort::sendTimingResp(PacketPtr pkt)
133 {
134 bool success = ResponsePort::sendTimingResp(pkt);
135
136 if (!success) {
137 respQueue.push_back(pkt);
138 }
139
140 return success;
141 }
142
143 TokenManager::TokenManager(int init_tokens)
144 {
145 availableTokens = init_tokens;
146 maxTokens = init_tokens;
147 }
148
149 int
150 TokenManager::getMaxTokenCount() const
151 {
152 return maxTokens;
153 }
154
155 void
156 TokenManager::recvTokens(int num_tokens)
157 {
158 availableTokens += num_tokens;
159
160 DPRINTF(TokenPort, "Received %d tokens, have %d\n",
161 num_tokens, availableTokens);
162
163 panic_if(availableTokens > maxTokens,
164 "More tokens available than the maximum after recvTokens!\n");
165 }
166
167 bool
168 TokenManager::haveTokens(int num_tokens)
169 {
170 return (availableTokens >= num_tokens);
171 }
172
173 void
174 TokenManager::acquireTokens(int num_tokens)
175 {
176 panic_if(!haveTokens(num_tokens),
177 "Attempted to acquire more tokens than are available!\n");
178
179 availableTokens -= num_tokens;
180
181 DPRINTF(TokenPort, "Acquired %d tokens, have %d\n",
182 num_tokens, availableTokens);
183 }