configs, mem: Support running VIPER with GCN3
[gem5.git] / src / mem / ruby / protocol / GPU_VIPER-SQC.sm
1 /*
2 * Copyright (c) 2012-2015 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 * Author: Blake Hechtman
34 */
35
36 machine(MachineType:SQC, "GPU SQC (L1 I Cache)")
37 : Sequencer* sequencer;
38 CacheMemory * L1cache;
39 int TCC_select_num_bits;
40 Cycles issue_latency := 80; // time to send data down to TCC
41 Cycles l2_hit_latency := 18; // for 1MB L2, 20 for 2MB
42
43 MessageBuffer * requestFromSQC, network="To", virtual_network="1", vnet_type="request";
44
45 MessageBuffer * probeToSQC, network="From", virtual_network="1", vnet_type="request";
46 MessageBuffer * responseToSQC, network="From", virtual_network="3", vnet_type="response";
47
48 MessageBuffer * mandatoryQueue;
49 {
50 state_declaration(State, desc="SQC Cache States", default="SQC_State_I") {
51 I, AccessPermission:Invalid, desc="Invalid";
52 V, AccessPermission:Read_Only, desc="Valid";
53 }
54
55 enumeration(Event, desc="SQC Events") {
56 // Core initiated
57 Fetch, desc="Fetch";
58 // Mem sys initiated
59 Repl, desc="Replacing block from cache";
60 Data, desc="Received Data";
61 }
62
63 enumeration(RequestType, desc="To communicate stats from transitions to recordStats") {
64 DataArrayRead, desc="Read the data array";
65 DataArrayWrite, desc="Write the data array";
66 TagArrayRead, desc="Read the data array";
67 TagArrayWrite, desc="Write the data array";
68 }
69
70
71 structure(Entry, desc="...", interface="AbstractCacheEntry") {
72 State CacheState, desc="cache state";
73 bool Dirty, desc="Is the data dirty (diff than memory)?";
74 DataBlock DataBlk, desc="data for the block";
75 bool FromL2, default="false", desc="block just moved from L2";
76 }
77
78 structure(TBE, desc="...") {
79 State TBEState, desc="Transient state";
80 DataBlock DataBlk, desc="data for the block, required for concurrent writebacks";
81 bool Dirty, desc="Is the data dirty (different than memory)?";
82 int NumPendingMsgs, desc="Number of acks/data messages that this processor is waiting for";
83 bool Shared, desc="Victim hit by shared probe";
84 }
85
86 structure(TBETable, external="yes") {
87 TBE lookup(Addr);
88 void allocate(Addr);
89 void deallocate(Addr);
90 bool isPresent(Addr);
91 }
92
93 TBETable TBEs, template="<SQC_TBE>", constructor="m_number_of_TBEs";
94 int TCC_select_low_bit, default="RubySystem::getBlockSizeBits()";
95
96 void set_cache_entry(AbstractCacheEntry b);
97 void unset_cache_entry();
98 void set_tbe(TBE b);
99 void unset_tbe();
100 void wakeUpAllBuffers();
101 void wakeUpBuffers(Addr a);
102 Cycles curCycle();
103
104 // Internal functions
105 Tick clockEdge();
106
107 Entry getCacheEntry(Addr address), return_by_pointer="yes" {
108 Entry cache_entry := static_cast(Entry, "pointer", L1cache.lookup(address));
109 return cache_entry;
110 }
111
112 DataBlock getDataBlock(Addr addr), return_by_ref="yes" {
113 TBE tbe := TBEs.lookup(addr);
114 if(is_valid(tbe)) {
115 return tbe.DataBlk;
116 } else {
117 return getCacheEntry(addr).DataBlk;
118 }
119 }
120
121 State getState(TBE tbe, Entry cache_entry, Addr addr) {
122 if(is_valid(tbe)) {
123 return tbe.TBEState;
124 } else if (is_valid(cache_entry)) {
125 return cache_entry.CacheState;
126 }
127 return State:I;
128 }
129
130 void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
131 if (is_valid(tbe)) {
132 tbe.TBEState := state;
133 }
134
135 if (is_valid(cache_entry)) {
136 cache_entry.CacheState := state;
137 }
138 }
139
140 void functionalRead(Addr addr, Packet *pkt) {
141 TBE tbe := TBEs.lookup(addr);
142 if(is_valid(tbe)) {
143 testAndRead(addr, tbe.DataBlk, pkt);
144 } else {
145 functionalMemoryRead(pkt);
146 }
147 }
148
149 int functionalWrite(Addr addr, Packet *pkt) {
150 int num_functional_writes := 0;
151
152 TBE tbe := TBEs.lookup(addr);
153 if(is_valid(tbe)) {
154 num_functional_writes := num_functional_writes +
155 testAndWrite(addr, tbe.DataBlk, pkt);
156 }
157
158 num_functional_writes := num_functional_writes +
159 functionalMemoryWrite(pkt);
160 return num_functional_writes;
161 }
162
163 AccessPermission getAccessPermission(Addr addr) {
164 TBE tbe := TBEs.lookup(addr);
165 if(is_valid(tbe)) {
166 return SQC_State_to_permission(tbe.TBEState);
167 }
168
169 Entry cache_entry := getCacheEntry(addr);
170 if(is_valid(cache_entry)) {
171 return SQC_State_to_permission(cache_entry.CacheState);
172 }
173
174 return AccessPermission:NotPresent;
175 }
176
177 void setAccessPermission(Entry cache_entry, Addr addr, State state) {
178 if (is_valid(cache_entry)) {
179 cache_entry.changePermission(SQC_State_to_permission(state));
180 }
181 }
182
183 void recordRequestType(RequestType request_type, Addr addr) {
184 if (request_type == RequestType:DataArrayRead) {
185 L1cache.recordRequestType(CacheRequestType:DataArrayRead, addr);
186 } else if (request_type == RequestType:DataArrayWrite) {
187 L1cache.recordRequestType(CacheRequestType:DataArrayWrite, addr);
188 } else if (request_type == RequestType:TagArrayRead) {
189 L1cache.recordRequestType(CacheRequestType:TagArrayRead, addr);
190 } else if (request_type == RequestType:TagArrayWrite) {
191 L1cache.recordRequestType(CacheRequestType:TagArrayWrite, addr);
192 }
193 }
194
195 bool checkResourceAvailable(RequestType request_type, Addr addr) {
196 if (request_type == RequestType:DataArrayRead) {
197 return L1cache.checkResourceAvailable(CacheResourceType:DataArray, addr);
198 } else if (request_type == RequestType:DataArrayWrite) {
199 return L1cache.checkResourceAvailable(CacheResourceType:DataArray, addr);
200 } else if (request_type == RequestType:TagArrayRead) {
201 return L1cache.checkResourceAvailable(CacheResourceType:TagArray, addr);
202 } else if (request_type == RequestType:TagArrayWrite) {
203 return L1cache.checkResourceAvailable(CacheResourceType:TagArray, addr);
204 } else {
205 error("Invalid RequestType type in checkResourceAvailable");
206 return true;
207 }
208 }
209
210 // Out Ports
211
212 out_port(requestNetwork_out, CPURequestMsg, requestFromSQC);
213
214 // In Ports
215
216 in_port(responseToSQC_in, ResponseMsg, responseToSQC) {
217 if (responseToSQC_in.isReady(clockEdge())) {
218 peek(responseToSQC_in, ResponseMsg, block_on="addr") {
219
220 Entry cache_entry := getCacheEntry(in_msg.addr);
221 TBE tbe := TBEs.lookup(in_msg.addr);
222
223 if (in_msg.Type == CoherenceResponseType:TDSysResp) {
224 if (is_valid(cache_entry) || L1cache.cacheAvail(in_msg.addr)) {
225 trigger(Event:Data, in_msg.addr, cache_entry, tbe);
226 } else {
227 Addr victim := L1cache.cacheProbe(in_msg.addr);
228 trigger(Event:Repl, victim, getCacheEntry(victim), TBEs.lookup(victim));
229 }
230 } else {
231 error("Unexpected Response Message to Core");
232 }
233 }
234 }
235 }
236
237 in_port(mandatoryQueue_in, RubyRequest, mandatoryQueue, desc="...") {
238 if (mandatoryQueue_in.isReady(clockEdge())) {
239 peek(mandatoryQueue_in, RubyRequest, block_on="LineAddress") {
240 Entry cache_entry := getCacheEntry(in_msg.LineAddress);
241 TBE tbe := TBEs.lookup(in_msg.LineAddress);
242 trigger(Event:Fetch, in_msg.LineAddress, cache_entry, tbe);
243 }
244 }
245 }
246
247 // Actions
248
249 action(ic_invCache, "ic", desc="invalidate cache") {
250 if(is_valid(cache_entry)) {
251 L1cache.deallocate(address);
252 }
253 unset_cache_entry();
254 }
255
256 action(nS_issueRdBlkS, "nS", desc="Issue RdBlkS") {
257 enqueue(requestNetwork_out, CPURequestMsg, issue_latency) {
258 out_msg.addr := address;
259 out_msg.Type := CoherenceRequestType:RdBlk;
260 out_msg.Requestor := machineID;
261 out_msg.Destination.add(mapAddressToRange(address,MachineType:TCC,
262 TCC_select_low_bit, TCC_select_num_bits));
263 out_msg.MessageSize := MessageSizeType:Request_Control;
264 out_msg.InitialRequestTime := curCycle();
265 }
266 }
267
268 action(a_allocate, "a", desc="allocate block") {
269 if (is_invalid(cache_entry)) {
270 set_cache_entry(L1cache.allocate(address, new Entry));
271 }
272 }
273
274 action(p_popMandatoryQueue, "pm", desc="Pop Mandatory Queue") {
275 mandatoryQueue_in.dequeue(clockEdge());
276 }
277
278 action(pr_popResponseQueue, "pr", desc="Pop Response Queue") {
279 responseToSQC_in.dequeue(clockEdge());
280 }
281
282 action(l_loadDone, "l", desc="local load done") {
283 assert(is_valid(cache_entry));
284 sequencer.readCallback(address, cache_entry.DataBlk, false, MachineType:L1Cache);
285 APPEND_TRANSITION_COMMENT(cache_entry.DataBlk);
286 }
287
288 action(w_writeCache, "w", desc="write data to cache") {
289 peek(responseToSQC_in, ResponseMsg) {
290 assert(is_valid(cache_entry));
291 cache_entry.DataBlk := in_msg.DataBlk;
292 cache_entry.Dirty := false;
293 }
294 }
295
296 // Transitions
297
298 // transitions from base
299 transition({I, V}, Repl, I) {TagArrayRead, TagArrayWrite} {
300 ic_invCache
301 }
302
303 transition(I, Data, V) {TagArrayRead, TagArrayWrite, DataArrayRead} {
304 a_allocate;
305 w_writeCache
306 l_loadDone;
307 pr_popResponseQueue;
308 }
309
310 transition(I, Fetch) {TagArrayRead, TagArrayWrite} {
311 nS_issueRdBlkS;
312 p_popMandatoryQueue;
313 }
314
315 // simple hit transitions
316 transition(V, Fetch) {TagArrayRead, DataArrayRead} {
317 l_loadDone;
318 p_popMandatoryQueue;
319 }
320 }