summaryrefslogtreecommitdiff
path: root/src/cpu/inorder/resource.hh
blob: 7899a215fe4fb05d1fb0f9d343b873c21662cbd2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
/*
 * Copyright (c) 2007 MIPS Technologies, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Korey Sewell
 *
 */

#ifndef __CPU_INORDER_RESOURCE_HH__
#define __CPU_INORDER_RESOURCE_HH__

#include <vector>
#include <list>
#include <string>

#include "base/types.hh"
#include "cpu/inst_seq.hh"
#include "cpu/inorder/inorder_dyn_inst.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "sim/eventq.hh"
#include "sim/sim_object.hh"

class Event;
class InOrderCPU;
class ResourceEvent;
class ResourceRequest;

typedef ResourceRequest ResReq;
typedef ResourceRequest* ResReqPtr;

class Resource {
  public:
    typedef ThePipeline::DynInstPtr DynInstPtr;

    friend class ResourceEvent;
    friend class ResourceRequest;

  public:
    Resource(std::string res_name, int res_id, int res_width,
             int res_latency, InOrderCPU *_cpu);
    virtual ~Resource();


    /** Return name of this resource */
    virtual std::string name();

    /** Define this function if resource, has a port to connect to an outside
     *  simulation object.
     */
    virtual Port* getPort(const std::string &if_name, int idx) 
    { return NULL; }

    /** Return ID for this resource */
    int getId() { return id; }

    /** Any extra initiliazation stuff can be set up using this function that
     * should get called before the simulation starts (tick 0)
     */
    virtual void init();    
    virtual void initSlots();

    /** Register Stats for this resource */
    virtual void regStats() { }

    /** Resources that care about thread activation override this. */
    virtual void activateThread(ThreadID tid) { }

    /** Deactivate Thread. Default action is to squash all instructions
     *  from deactivated thread.
     */
    virtual void deactivateThread(ThreadID tid);

    /** Resources that care about thread activation override this. */
    virtual void suspendThread(ThreadID tid) { }
    
    /** Will be called the cycle before a context switch. Any bookkeeping
     *  that needs to be kept for that, can be done here
     */
    virtual void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid) { }    

    /** Resources that care when an instruction has been graduated
     *  can override this
     */
    virtual void instGraduated(InstSeqNum seq_num, ThreadID tid) { }

    /** Request usage of this resource. Returns a ResourceRequest object
     *  with all the necessary resource information
     */
    virtual ResourceRequest* request(DynInstPtr inst);

    /** Get the next available slot in this resource. Instruction is passed
     *  so that resources can check the instruction before allocating a slot
     *  if necessary.
     */
    virtual int getSlot(DynInstPtr inst);

    /** Find the slot that this instruction is using in a resource */
    virtual int findSlot(DynInstPtr inst);

    /** Free a resource slot */
    virtual void freeSlot(int slot_idx);

    /** Request usage of a resource for this instruction. If this instruction 
     *  already has made this request to this resource, and that request is 
     *  uncompleted this function will just return that request
     */
    virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
                                        int res_idx, int slot_num,
                                        unsigned cmd);

    /** Schedule Execution of This Resource For A Given Slot*/
    void scheduleExecution(int slot_idx);

    /** Execute the function of this resource. The Default is action
     *  is to do nothing. More specific models will derive from this
     *  class and define their own execute function.
     */
    virtual void execute(int slot_idx);

    /** Fetch on behalf of an instruction. Will check to see
     *  if instruction is actually in resource before
     *  trying to fetch. Needs to be defined for derived units.
     */
    virtual Fault doFetchAccess(DynInstPtr inst)
    { panic("doFetchAccess undefined for %s", name()); return NoFault; }

    /** Read/Write on behalf of an instruction. Will check to see
     *  if instruction is actually in resource before
     *  trying to do access.Needs to be defined for derived units.
     */
    virtual Fault doCacheAccess(DynInstPtr inst, uint64_t *res=NULL)
    { panic("doCacheAccess undefined for %s", name()); return NoFault; }

    /** Squash All Requests After This Seq Num */
    virtual void squash(DynInstPtr inst, int stage_num,
                        InstSeqNum squash_seq_num, ThreadID tid);

    virtual void squashDueToMemStall(DynInstPtr inst, int stage_num,
                                     InstSeqNum squash_seq_num, ThreadID tid);

    /** The number of instructions available that this resource can
     *  can still process
     */
    int slotsAvail();

    /** The number of instructions using this resource */
    int slotsInUse();

    /** Schedule resource event, regardless of its current state. */
    void scheduleEvent(int slot_idx, int delay);

    /** Find instruction in list, Schedule resource event, regardless of its 
     *  current state. */
    bool scheduleEvent(DynInstPtr inst, int delay);

    /** Unschedule resource event, regardless of its current state. */
    void unscheduleEvent(int slot_idx);

    /** Unschedule resource event, regardless of its current state. */
    bool unscheduleEvent(DynInstPtr inst);

    /** Return the number of cycles in 'Tick' format */
    Tick ticks(int numCycles);

    /** Find the request that corresponds to this instruction */
    virtual ResReqPtr findRequest(DynInstPtr inst);

    /** */
    void rejectRequest(DynInstPtr inst);

    /** Request a Resource again. Some resources have to special process this
     *  in subsequent accesses.
     */
    virtual void requestAgain(DynInstPtr inst, bool &try_request);

    /** Return Latency of Resource */
    /*  Can be overridden for complex cases */
    virtual int getLatency(int slot_num) { return latency; }

  protected:
    /** The name of this resource */
    std::string resName;

    /** ID of the resource. The Resource Pool uses this # to identify this
     *  resource.
     */
    int id;

    /** The number of instructions the resource can simultaneously
     *  process.
     */
    int width;

    /** Constant latency for this resource.
     *  Note: Dynamic latency resources set this to 0 and
     *  manage the latency themselves
     */
    const int latency;

  public:
    /** List of all Requests the Resource is Servicing. Each request
        represents part of the resource's bandwidth
    */
    std::vector<ResReqPtr> reqs;

    /** A list of all the available execution slots for this resource.
     *  This correlates with the actual resource event idx.
     */
    std::vector<int> availSlots;

    /** The CPU(s) that this resource interacts with */
    InOrderCPU *cpu;

  protected:
    /** The resource event used for scheduling resource slots on the
     *  event queue
     */
    ResourceEvent *resourceEvent;

    /** Default denied resource request pointer*/
    ResReqPtr deniedReq;
};

class ResourceEvent : public Event
{
  public:
    /** Pointer to the Resource this is an event for */
    Resource *resource;


    /// Resource events that come before other associated CPU events
    /// (for InOrderCPU model).
    /// check src/sim/eventq.hh for more event priorities.
    enum InOrderPriority {
        Resource_Event_Pri = 45,
    };

    /** The Resource Slot that this event is servicing */
    int slotIdx;

    /** Constructs a resource event. */
    ResourceEvent();
    ResourceEvent(Resource *res, int slot_idx);
    virtual ~ResourceEvent() { }

    /** Initialize data for this resource event. */
    virtual void init(Resource *res, int slot_idx);

    /** Processes a resource event. */
    virtual void process();

    /** Returns the description of the resource event. */
    const char *description();

    /** Set slot idx for event */
    void setSlot(int slot) { slotIdx = slot; }

    /** Schedule resource event, regardless of its current state. */
    void scheduleEvent(int delay);

    /** Unschedule resource event, regardless of its current state. */
    void unscheduleEvent()
    {
        if (scheduled())
            squash();
    }

};

class ResourceRequest
{
  public:
    typedef ThePipeline::DynInstPtr DynInstPtr;

    static int resReqID;

    static int maxReqCount;
    
    friend class Resource;

  public:
    ResourceRequest(Resource *_res);
    
    virtual ~ResourceRequest();

    std::string name();
    
    int reqID;

    virtual void setRequest(DynInstPtr _inst, int stage_num,
                    int res_idx, int slot_num, unsigned _cmd);

    virtual void clearRequest();

    /** Acknowledge that this is a request is done and remove
     *  from resource.
     */
    void done(bool completed = true);
    
    void freeSlot();

    /////////////////////////////////////////////
    //
    // GET RESOURCE REQUEST IDENTIFICATION / INFO
    //
    /////////////////////////////////////////////
    /** Get Resource Index */
    int getResIdx() { return resIdx; }
       
    /** Get Slot Number */
    int getSlot() { return slotNum; }
    bool hasSlot()  { return slotNum >= 0; }     

    /** Get Stage Number */
    int getStageNum() { return stageNum; }

    /** Set/Get Thread Ids */
    void setTid(ThreadID _tid) { tid = _tid; }
    ThreadID getTid() { return tid; }

    /** Instruction this request is for */
    DynInstPtr getInst() { return inst; }

    /** Data from this request. Overridden by Resource-Specific Request
     *  Objects
     */
    virtual PacketDataPtr getData() { return NULL; }

    /** Pointer to Resource that is being used */
    Resource *res;

    /** Instruction being used */
    DynInstPtr inst;

    /** Not guaranteed to be set, used for debugging */
    InstSeqNum seqNum;
    
    /** Command For This Resource */
    unsigned cmd;

    short stagePasses;

    bool valid;

    bool doneInResource;

    ////////////////////////////////////////
    //
    // GET RESOURCE REQUEST STATUS FROM VARIABLES
    //
    ////////////////////////////////////////
    /** Get/Set Completed variables */
    bool isCompleted() { return completed; }
    void setCompleted(bool cond = true) { completed = cond; }

    /** Get/Set Squashed variables */
    bool isSquashed() { return squashed; }
    void setSquashed() { squashed = true; }

    /** Get/Set IsProcessing variables */
    bool isProcessing() { return processing; }
    void setProcessing() { processing = true; }

    /** Get/Set IsWaiting variables */
    bool isMemStall() { return memStall; }
    void setMemStall(bool stall = true) { memStall = stall; }

  protected:
    /** Resource Identification */
    ThreadID tid;
    int stageNum;
    int resIdx;
    int slotNum;
    
    /** Resource Request Status */
    bool completed;
    bool squashed;
    bool processing;

    bool memStall;
};

#endif //__CPU_INORDER_RESOURCE_HH__