Clock: Add a Cycles wrapper class and use where applicable
[gem5.git] / src / cpu / inorder / resources / tlb_unit.cc
1 /*
2 * Copyright (c) 2007 MIPS Technologies, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Korey Sewell
29 *
30 */
31
32 #include <list>
33 #include <vector>
34
35 #include "arch/isa_traits.hh"
36 #include "config/the_isa.hh"
37 #include "cpu/inorder/resources/tlb_unit.hh"
38 #include "cpu/inorder/cpu.hh"
39 #include "cpu/inorder/first_stage.hh"
40 #include "cpu/inorder/pipeline_traits.hh"
41
42 using namespace std;
43 using namespace TheISA;
44 using namespace ThePipeline;
45
46 TLBUnit::TLBUnit(string res_name, int res_id, int res_width,
47 Cycles res_latency, InOrderCPU *_cpu,
48 ThePipeline::Params *params)
49 : Resource(res_name, res_id, res_width, res_latency, _cpu)
50 {
51 // Hard-Code Selection For Now
52 if (res_name == "I-TLB")
53 _tlb = params->itb;
54 else if (res_name == "D-TLB")
55 _tlb = params->dtb;
56 else
57 fatal("Unrecognized TLB name passed by user");
58
59 for (int i=0; i < MaxThreads; i++) {
60 tlbBlocked[i] = false;
61 }
62 }
63
64 TheISA::TLB*
65 TLBUnit::tlb()
66 {
67 return _tlb;
68
69 }
70
71 void
72 TLBUnit::init()
73 {
74 resourceEvent = new TLBUnitEvent[width];
75
76 for (int i = 0; i < width; i++) {
77 reqs[i] = new TLBUnitRequest(this);
78 }
79
80 initSlots();
81 }
82
83 int
84 TLBUnit::getSlot(DynInstPtr inst)
85 {
86 if (tlbBlocked[inst->threadNumber]) {
87 return -1;
88 } else {
89 return Resource::getSlot(inst);
90 }
91 }
92
93 ResourceRequest*
94 TLBUnit::getRequest(DynInstPtr _inst, int stage_num,
95 int res_idx, int slot_num,
96 unsigned cmd)
97 {
98 TLBUnitRequest *tlb_req = dynamic_cast<TLBUnitRequest*>(reqs[slot_num]);
99 tlb_req->setRequest(inst, stage_num, id, slot_num, cmd);
100 return ud_req;
101 }
102
103 void
104 TLBUnit::execute(int slot_idx)
105 {
106 // After this is working, change this to a reinterpret cast
107 // for performance considerations
108 TLBUnitRequest* tlb_req = dynamic_cast<TLBUnitRequest*>(reqs[slot_idx]);
109 assert(tlb_req != 0x0);
110
111 DynInstPtr inst = tlb_req->inst;
112 ThreadID tid = inst->readTid();
113 InstSeqNum seq_num = inst->seqNum;
114 int stage_num = tlb_req->getStageNum();
115
116 tlb_req->fault = NoFault;
117
118 assert(cpu->thread[tid]->getTC() != 0x0);
119 assert(cpu->pipelineStage[stage_num] != 0x0);
120
121 switch (tlb_req->cmd)
122 {
123 case FetchLookup:
124 {
125 tlb_req->fault =
126 _tlb->translateAtomic(tlb_req->memReq,
127 cpu->thread[tid]->getTC(), TheISA::TLB::Execute);
128
129 if (tlb_req->fault != NoFault) {
130 DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating "
131 "addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(),
132 tlb_req->memReq->getVaddr(), seq_num);
133
134 DPRINTF(InOrderTLB, "slot:%i sn:%i schedule event.\n", slot_idx, seq_num);
135
136 cpu->pipelineStage[stage_num]->setResStall(tlb_req, tid);
137 tlbBlocked[tid] = true;
138 scheduleEvent(slot_idx, 1);
139
140 // @TODO: SHOULDNT BREAK EXECUTION at misspeculated PC Fault
141 // Let CPU handle the fault
142 cpu->trap(tlb_req->fault, tid);
143 } else {
144 DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated "
145 "to phys. addr:%08p.\n", tid, seq_num,
146 tlb_req->memReq->getVaddr(),
147 tlb_req->memReq->getPaddr());
148 tlb_req->done();
149 }
150 }
151 break;
152
153 case DataReadLookup:
154 case DataWriteLookup:
155 {
156 DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i]: Attempting to translate %08p.\n",
157 tid, seq_num, tlb_req->memReq->getVaddr());
158
159
160 TheISA::TLB::Mode tlb_mode = (tlb_req->cmd == DataReadLookup) ?
161 TheISA::TLB::Read : TheISA::TLB::Write;
162
163 tlb_req->fault =
164 _tlb->translateAtomic(tlb_req->memReq,
165 cpu->thread[tid]->getTC(), tlb_mode);
166
167 if (tlb_req->fault != NoFault) {
168 DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating "
169 "addr:%08p for [sn:%i] %s.\n", tid, tlb_req->fault->name(),
170 tlb_req->memReq->getVaddr(), seq_num, inst->instName());
171
172 if (inst->isDataPrefetch()) {
173 DPRINTF(InOrderTLB, "Ignoring %s fault for data prefetch\n",
174 tlb_req->fault->name());
175
176 tlb_req->fault = NoFault;
177
178 tlb_req->done();
179 } else {
180 cpu->pipelineStage[stage_num]->setResStall(tlb_req, tid);
181 tlbBlocked[tid] = true;
182 scheduleEvent(slot_idx, 1);
183
184 // Let CPU handle the fault
185 cpu->trap(tlb_req->fault, tid, inst);
186 }
187 } else {
188 DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated "
189 "to phys. addr:%08p.\n", tid, seq_num,
190 tlb_req->memReq->getVaddr(),
191 tlb_req->memReq->getPaddr());
192 tlb_req->done();
193 }
194 }
195 break;
196
197 default:
198 fatal("Unrecognized command to %s", resName);
199 }
200 }
201
202 TLBUnitEvent::TLBUnitEvent()
203 : ResourceEvent()
204 { }
205
206 void
207 TLBUnitEvent::process()
208 {
209 DynInstPtr inst = resource->reqs[slotIdx]->inst;
210 int stage_num = resource->reqs[slotIdx]->getStageNum();
211 ThreadID tid = inst->threadNumber;
212
213 DPRINTF(InOrderTLB, "Waking up from TLB Miss caused by [sn:%i].\n",
214 inst->seqNum);
215
216 TLBUnit* tlb_res = dynamic_cast<TLBUnit*>(resource);
217 assert(tlb_res);
218
219 tlb_res->tlbBlocked[tid] = false;
220
221 tlb_res->cpu->pipelineStage[stage_num]->
222 unsetResStall(tlb_res->reqs[slotIdx], tid);
223 }
224
225 void
226 TLBUnit::squash(DynInstPtr inst, int stage_num,
227 InstSeqNum squash_seq_num, ThreadID tid)
228 {
229 for (int i = 0; i < width; i++) {
230 ResReqPtr req_ptr = reqs[i];
231
232 if (req_ptr->valid &&
233 req_ptr->getInst()->readTid() == tid &&
234 req_ptr->getInst()->seqNum > squash_seq_num) {
235
236 DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n",
237 req_ptr->getInst()->readTid(),
238 req_ptr->getInst()->seqNum);
239
240 req_ptr->setSquashed();
241
242 int req_slot_num = req_ptr->getSlot();
243
244 tlbBlocked[tid] = false;
245
246 int stall_stage = reqs[req_slot_num]->getStageNum();
247
248 cpu->pipelineStage[stall_stage]->
249 unsetResStall(reqs[req_slot_num], tid);
250
251 if (resourceEvent[req_slot_num].scheduled())
252 unscheduleEvent(req_slot_num);
253
254 freeSlot(req_slot_num);
255 }
256 }
257 }
258
259