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