afc415b5a335faa795af9997a1e30f05289f2d6d
[gem5.git] / src / mem / protocol / MI_example-cache.sm
1
2 machine(L1Cache, "MI Example L1 Cache")
3 : Sequencer * sequencer,
4 CacheMemory * cacheMemory,
5 int cache_response_latency = 12,
6 int issue_latency = 2
7 {
8
9 // NETWORK BUFFERS
10 MessageBuffer requestFromCache, network="To", virtual_network="2", ordered="true", vnet_type="request";
11 MessageBuffer responseFromCache, network="To", virtual_network="4", ordered="true", vnet_type="response";
12
13 MessageBuffer forwardToCache, network="From", virtual_network="3", ordered="true", vnet_type="forward";
14 MessageBuffer responseToCache, network="From", virtual_network="4", ordered="true", vnet_type="response";
15
16 // STATES
17 state_declaration(State, desc="Cache states") {
18 I, AccessPermission:Invalid, desc="Not Present/Invalid";
19 II, AccessPermission:Busy, desc="Not Present/Invalid, issued PUT";
20 M, AccessPermission:Read_Write, desc="Modified";
21 MI, AccessPermission:Busy, desc="Modified, issued PUT";
22 MII, AccessPermission:Busy, desc="Modified, issued PUTX, received nack";
23
24 IS, AccessPermission:Busy, desc="Issued request for LOAD/IFETCH";
25 IM, AccessPermission:Busy, desc="Issued request for STORE/ATOMIC";
26 }
27
28 // EVENTS
29 enumeration(Event, desc="Cache events") {
30 // From processor
31
32 Load, desc="Load request from processor";
33 Ifetch, desc="Ifetch request from processor";
34 Store, desc="Store request from processor";
35
36 Data, desc="Data from network";
37 Fwd_GETX, desc="Forward from network";
38
39 Inv, desc="Invalidate request from dir";
40
41 Replacement, desc="Replace a block";
42 Writeback_Ack, desc="Ack from the directory for a writeback";
43 Writeback_Nack, desc="Nack from the directory for a writeback";
44 }
45
46 // STRUCTURE DEFINITIONS
47
48 MessageBuffer mandatoryQueue, ordered="false";
49
50 // CacheEntry
51 structure(Entry, desc="...", interface="AbstractCacheEntry") {
52 State CacheState, desc="cache state";
53 bool Dirty, desc="Is the data dirty (different than memory)?";
54 DataBlock DataBlk, desc="Data in the block";
55 }
56
57
58 // TBE fields
59 structure(TBE, desc="...") {
60 State TBEState, desc="Transient state";
61 DataBlock DataBlk, desc="data for the block, required for concurrent writebacks";
62 }
63
64 structure(TBETable, external="yes") {
65 TBE lookup(Address);
66 void allocate(Address);
67 void deallocate(Address);
68 bool isPresent(Address);
69 }
70
71
72 // STRUCTURES
73
74 TBETable TBEs, template_hack="<L1Cache_TBE>";
75
76 // PROTOTYPES
77 void set_cache_entry(AbstractCacheEntry a);
78 void unset_cache_entry();
79 void set_tbe(TBE b);
80 void unset_tbe();
81
82 Entry getCacheEntry(Address address), return_by_pointer="yes" {
83 return static_cast(Entry, "pointer", cacheMemory.lookup(address));
84 }
85
86 // FUNCTIONS
87 Event mandatory_request_type_to_event(RubyRequestType type) {
88 if (type == RubyRequestType:LD) {
89 return Event:Load;
90 } else if (type == RubyRequestType:IFETCH) {
91 return Event:Ifetch;
92 } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)) {
93 return Event:Store;
94 } else {
95 error("Invalid RubyRequestType");
96 }
97 }
98
99 State getState(TBE tbe, Entry cache_entry, Address addr) {
100
101 if (is_valid(tbe)) {
102 return tbe.TBEState;
103 }
104 else if (is_valid(cache_entry)) {
105 return cache_entry.CacheState;
106 }
107 else {
108 return State:I;
109 }
110 }
111
112 void setState(TBE tbe, Entry cache_entry, Address addr, State state) {
113
114 if (is_valid(tbe)) {
115 tbe.TBEState := state;
116 }
117
118 if (is_valid(cache_entry)) {
119 cache_entry.CacheState := state;
120 }
121 }
122
123 AccessPermission getAccessPermission(Address addr) {
124 TBE tbe := TBEs[addr];
125 if(is_valid(tbe)) {
126 return L1Cache_State_to_permission(tbe.TBEState);
127 }
128
129 Entry cache_entry := getCacheEntry(addr);
130 if(is_valid(cache_entry)) {
131 return L1Cache_State_to_permission(cache_entry.CacheState);
132 }
133
134 return AccessPermission:NotPresent;
135 }
136
137 void setAccessPermission(Entry cache_entry, Address addr, State state) {
138 if (is_valid(cache_entry)) {
139 cache_entry.changePermission(L1Cache_State_to_permission(state));
140 }
141 }
142
143 GenericMachineType getNondirectHitMachType(MachineID sender) {
144 if (machineIDToMachineType(sender) == MachineType:L1Cache) {
145 //
146 // NOTE direct local hits should not call this
147 //
148 return GenericMachineType:L1Cache_wCC;
149 } else {
150 return ConvertMachToGenericMach(machineIDToMachineType(sender));
151 }
152 }
153
154
155 // NETWORK PORTS
156
157 out_port(requestNetwork_out, RequestMsg, requestFromCache);
158 out_port(responseNetwork_out, ResponseMsg, responseFromCache);
159
160 in_port(forwardRequestNetwork_in, RequestMsg, forwardToCache) {
161 if (forwardRequestNetwork_in.isReady()) {
162 peek(forwardRequestNetwork_in, RequestMsg, block_on="Address") {
163
164 Entry cache_entry := getCacheEntry(in_msg.Address);
165 TBE tbe := TBEs[in_msg.Address];
166
167 if (in_msg.Type == CoherenceRequestType:GETX) {
168 trigger(Event:Fwd_GETX, in_msg.Address, cache_entry, tbe);
169 }
170 else if (in_msg.Type == CoherenceRequestType:WB_ACK) {
171 trigger(Event:Writeback_Ack, in_msg.Address, cache_entry, tbe);
172 }
173 else if (in_msg.Type == CoherenceRequestType:WB_NACK) {
174 trigger(Event:Writeback_Nack, in_msg.Address, cache_entry, tbe);
175 }
176 else if (in_msg.Type == CoherenceRequestType:INV) {
177 trigger(Event:Inv, in_msg.Address, cache_entry, tbe);
178 }
179 else {
180 error("Unexpected message");
181 }
182 }
183 }
184 }
185
186 in_port(responseNetwork_in, ResponseMsg, responseToCache) {
187 if (responseNetwork_in.isReady()) {
188 peek(responseNetwork_in, ResponseMsg, block_on="Address") {
189
190 Entry cache_entry := getCacheEntry(in_msg.Address);
191 TBE tbe := TBEs[in_msg.Address];
192
193 if (in_msg.Type == CoherenceResponseType:DATA) {
194 trigger(Event:Data, in_msg.Address, cache_entry, tbe);
195 }
196 else {
197 error("Unexpected message");
198 }
199 }
200 }
201 }
202
203 // Mandatory Queue
204 in_port(mandatoryQueue_in, RubyRequest, mandatoryQueue, desc="...") {
205 if (mandatoryQueue_in.isReady()) {
206 peek(mandatoryQueue_in, RubyRequest, block_on="LineAddress") {
207
208 Entry cache_entry := getCacheEntry(in_msg.LineAddress);
209 if (is_invalid(cache_entry) &&
210 cacheMemory.cacheAvail(in_msg.LineAddress) == false ) {
211 // make room for the block
212 trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.LineAddress),
213 getCacheEntry(cacheMemory.cacheProbe(in_msg.LineAddress)),
214 TBEs[cacheMemory.cacheProbe(in_msg.LineAddress)]);
215 }
216 else {
217 trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress,
218 cache_entry, TBEs[in_msg.LineAddress]);
219 }
220 }
221 }
222 }
223
224 // ACTIONS
225
226 action(a_issueRequest, "a", desc="Issue a request") {
227 enqueue(requestNetwork_out, RequestMsg, latency=issue_latency) {
228 out_msg.Address := address;
229 out_msg.Type := CoherenceRequestType:GETX;
230 out_msg.Requestor := machineID;
231 out_msg.Destination.add(map_Address_to_Directory(address));
232 out_msg.MessageSize := MessageSizeType:Control;
233 }
234 }
235
236 action(b_issuePUT, "b", desc="Issue a PUT request") {
237 enqueue(requestNetwork_out, RequestMsg, latency=issue_latency) {
238 assert(is_valid(cache_entry));
239 out_msg.Address := address;
240 out_msg.Type := CoherenceRequestType:PUTX;
241 out_msg.Requestor := machineID;
242 out_msg.Destination.add(map_Address_to_Directory(address));
243 out_msg.DataBlk := cache_entry.DataBlk;
244 out_msg.MessageSize := MessageSizeType:Data;
245 }
246 }
247
248
249 action(e_sendData, "e", desc="Send data from cache to requestor") {
250 peek(forwardRequestNetwork_in, RequestMsg) {
251 enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
252 assert(is_valid(cache_entry));
253 out_msg.Address := address;
254 out_msg.Type := CoherenceResponseType:DATA;
255 out_msg.Sender := machineID;
256 out_msg.Destination.add(in_msg.Requestor);
257 out_msg.DataBlk := cache_entry.DataBlk;
258 out_msg.MessageSize := MessageSizeType:Response_Data;
259 }
260 }
261 }
262
263 action(ee_sendDataFromTBE, "\e", desc="Send data from TBE to requestor") {
264 peek(forwardRequestNetwork_in, RequestMsg) {
265 enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
266 assert(is_valid(tbe));
267 out_msg.Address := address;
268 out_msg.Type := CoherenceResponseType:DATA;
269 out_msg.Sender := machineID;
270 out_msg.Destination.add(in_msg.Requestor);
271 out_msg.DataBlk := tbe.DataBlk;
272 out_msg.MessageSize := MessageSizeType:Response_Data;
273 }
274 }
275 }
276
277 action(i_allocateL1CacheBlock, "i", desc="Allocate a cache block") {
278 if (is_valid(cache_entry)) {
279 } else {
280 set_cache_entry(cacheMemory.allocate(address, new Entry));
281 }
282 }
283
284 action(h_deallocateL1CacheBlock, "h", desc="deallocate a cache block") {
285 if (is_valid(cache_entry)) {
286 cacheMemory.deallocate(address);
287 unset_cache_entry();
288 }
289 }
290
291 action(m_popMandatoryQueue, "m", desc="Pop the mandatory request queue") {
292 mandatoryQueue_in.dequeue();
293 }
294
295 action(n_popResponseQueue, "n", desc="Pop the response queue") {
296 profileMsgDelay(1, responseNetwork_in.dequeue_getDelayCycles());
297 }
298
299 action(o_popForwardedRequestQueue, "o", desc="Pop the forwarded request queue") {
300 profileMsgDelay(2, forwardRequestNetwork_in.dequeue_getDelayCycles());
301 }
302
303 action(p_profileMiss, "p", desc="Profile cache miss") {
304 peek(mandatoryQueue_in, RubyRequest) {
305 cacheMemory.profileMiss(in_msg);
306 }
307 }
308
309 action(r_load_hit, "r", desc="Notify sequencer the load completed.") {
310 assert(is_valid(cache_entry));
311 DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk);
312 sequencer.readCallback(address,
313 GenericMachineType:L1Cache,
314 cache_entry.DataBlk);
315 }
316
317 action(rx_load_hit, "rx", desc="External load completed.") {
318 peek(responseNetwork_in, ResponseMsg) {
319 assert(is_valid(cache_entry));
320 DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk);
321 sequencer.readCallback(address,
322 getNondirectHitMachType(in_msg.Sender),
323 cache_entry.DataBlk);
324 }
325 }
326
327 action(s_store_hit, "s", desc="Notify sequencer that store completed.") {
328 assert(is_valid(cache_entry));
329 DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk);
330 sequencer.writeCallback(address,
331 GenericMachineType:L1Cache,
332 cache_entry.DataBlk);
333 }
334
335 action(sx_store_hit, "sx", desc="External store completed.") {
336 peek(responseNetwork_in, ResponseMsg) {
337 assert(is_valid(cache_entry));
338 DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk);
339 sequencer.writeCallback(address,
340 getNondirectHitMachType(in_msg.Sender),
341 cache_entry.DataBlk);
342 }
343 }
344
345 action(u_writeDataToCache, "u", desc="Write data to the cache") {
346 peek(responseNetwork_in, ResponseMsg) {
347 assert(is_valid(cache_entry));
348 cache_entry.DataBlk := in_msg.DataBlk;
349 }
350 }
351
352
353 action(v_allocateTBE, "v", desc="Allocate TBE") {
354 TBEs.allocate(address);
355 set_tbe(TBEs[address]);
356 }
357
358
359 action(w_deallocateTBE, "w", desc="Deallocate TBE") {
360 TBEs.deallocate(address);
361 unset_tbe();
362 }
363
364 action(x_copyDataFromCacheToTBE, "x", desc="Copy data from cache to TBE") {
365 assert(is_valid(cache_entry));
366 assert(is_valid(tbe));
367 tbe.DataBlk := cache_entry.DataBlk;
368 }
369
370 action(z_stall, "z", desc="stall") {
371 // do nothing
372 }
373
374 // TRANSITIONS
375
376 transition({IS, IM, MI, II}, {Load, Ifetch, Store, Replacement}) {
377 z_stall;
378 }
379
380 transition({IS, IM}, {Fwd_GETX, Inv}) {
381 z_stall;
382 }
383
384 transition(MI, Inv) {
385 o_popForwardedRequestQueue;
386 }
387
388 transition(M, Store) {
389 s_store_hit;
390 m_popMandatoryQueue;
391 }
392
393 transition(M, {Load, Ifetch}) {
394 r_load_hit;
395 m_popMandatoryQueue;
396 }
397
398 transition(I, Inv) {
399 o_popForwardedRequestQueue;
400 }
401
402 transition(I, Store, IM) {
403 v_allocateTBE;
404 i_allocateL1CacheBlock;
405 a_issueRequest;
406 p_profileMiss;
407 m_popMandatoryQueue;
408 }
409
410 transition(I, {Load, Ifetch}, IS) {
411 v_allocateTBE;
412 i_allocateL1CacheBlock;
413 a_issueRequest;
414 p_profileMiss;
415 m_popMandatoryQueue;
416 }
417
418 transition(IS, Data, M) {
419 u_writeDataToCache;
420 rx_load_hit;
421 w_deallocateTBE;
422 n_popResponseQueue;
423 }
424
425 transition(IM, Data, M) {
426 u_writeDataToCache;
427 sx_store_hit;
428 w_deallocateTBE;
429 n_popResponseQueue;
430 }
431
432 transition(M, Fwd_GETX, I) {
433 e_sendData;
434 o_popForwardedRequestQueue;
435 }
436
437 transition(I, Replacement) {
438 h_deallocateL1CacheBlock;
439 }
440
441 transition(M, {Replacement,Inv}, MI) {
442 v_allocateTBE;
443 b_issuePUT;
444 x_copyDataFromCacheToTBE;
445 h_deallocateL1CacheBlock;
446 }
447
448 transition(MI, Writeback_Ack, I) {
449 w_deallocateTBE;
450 o_popForwardedRequestQueue;
451 }
452
453 transition(MI, Fwd_GETX, II) {
454 ee_sendDataFromTBE;
455 o_popForwardedRequestQueue;
456 }
457
458 transition(MI, Writeback_Nack, MII) {
459 o_popForwardedRequestQueue;
460 }
461
462 transition(MII, Fwd_GETX, I) {
463 ee_sendDataFromTBE;
464 w_deallocateTBE;
465 o_popForwardedRequestQueue;
466 }
467
468 transition(II, Writeback_Nack, I) {
469 w_deallocateTBE;
470 o_popForwardedRequestQueue;
471 }
472 }
473