decode.cc revision 13646:626670cc6da4
16657Snate@binkert.org/* 26657Snate@binkert.org * Copyright (c) 2013-2014 ARM Limited 36657Snate@binkert.org * All rights reserved 46657Snate@binkert.org * 56657Snate@binkert.org * The license below extends only to copyright in the software and shall 66657Snate@binkert.org * not be construed as granting a license to any other intellectual 76657Snate@binkert.org * property including but not limited to intellectual property relating 86657Snate@binkert.org * to a hardware implementation of the functionality of the software 96657Snate@binkert.org * licensed hereunder. You may use the software subject to the license 106657Snate@binkert.org * terms below provided that you ensure that this notice is replicated 116657Snate@binkert.org * unmodified and in its entirety in all distributions of the software, 126657Snate@binkert.org * modified or unmodified, in source code or in binary form. 136657Snate@binkert.org * 146657Snate@binkert.org * Redistribution and use in source and binary forms, with or without 156657Snate@binkert.org * modification, are permitted provided that the following conditions are 166657Snate@binkert.org * met: redistributions of source code must retain the above copyright 176657Snate@binkert.org * notice, this list of conditions and the following disclaimer; 186657Snate@binkert.org * redistributions in binary form must reproduce the above copyright 196657Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 206657Snate@binkert.org * documentation and/or other materials provided with the distribution; 216657Snate@binkert.org * neither the name of the copyright holders nor the names of its 226657Snate@binkert.org * contributors may be used to endorse or promote products derived from 236657Snate@binkert.org * this software without specific prior written permission. 246657Snate@binkert.org * 256657Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 266657Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 276657Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 286657Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 296657Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 306657Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 316657Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 326657Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 336657Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 346657Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 356657Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 366657Snate@binkert.org * 376657Snate@binkert.org * Authors: Andrew Bardsley 386657Snate@binkert.org */ 396657Snate@binkert.org 406657Snate@binkert.org#include "cpu/minor/decode.hh" 416657Snate@binkert.org 426657Snate@binkert.org#include "cpu/minor/pipeline.hh" 436657Snate@binkert.org#include "debug/Decode.hh" 446657Snate@binkert.org 456657Snate@binkert.orgnamespace Minor 466657Snate@binkert.org{ 476657Snate@binkert.org 486657Snate@binkert.orgDecode::Decode(const std::string &name, 496657Snate@binkert.org MinorCPU &cpu_, 506657Snate@binkert.org MinorCPUParams ¶ms, 516657Snate@binkert.org Latch<ForwardInstData>::Output inp_, 526657Snate@binkert.org Latch<ForwardInstData>::Input out_, 536657Snate@binkert.org std::vector<InputBuffer<ForwardInstData>> &next_stage_input_buffer) : 546657Snate@binkert.org Named(name), 556657Snate@binkert.org cpu(cpu_), 566657Snate@binkert.org inp(inp_), 576657Snate@binkert.org out(out_), 586657Snate@binkert.org nextStageReserve(next_stage_input_buffer), 596657Snate@binkert.org outputWidth(params.executeInputWidth), 606657Snate@binkert.org processMoreThanOneInput(params.decodeCycleInput), 616657Snate@binkert.org decodeInfo(params.numThreads), 626657Snate@binkert.org threadPriority(0) 637839Snilay@cs.wisc.edu{ 647839Snilay@cs.wisc.edu if (outputWidth < 1) 656657Snate@binkert.org fatal("%s: executeInputWidth must be >= 1 (%d)\n", name, outputWidth); 666657Snate@binkert.org 676657Snate@binkert.org if (params.decodeInputBufferSize < 1) { 686657Snate@binkert.org fatal("%s: decodeInputBufferSize must be >= 1 (%d)\n", name, 696657Snate@binkert.org params.decodeInputBufferSize); 706657Snate@binkert.org } 716657Snate@binkert.org 726657Snate@binkert.org /* Per-thread input buffers */ 736657Snate@binkert.org for (ThreadID tid = 0; tid < params.numThreads; tid++) { 746999Snate@binkert.org inputBuffer.push_back( 756657Snate@binkert.org InputBuffer<ForwardInstData>( 766657Snate@binkert.org name + ".inputBuffer" + std::to_string(tid), "insts", 776657Snate@binkert.org params.decodeInputBufferSize)); 786657Snate@binkert.org } 796657Snate@binkert.org} 806657Snate@binkert.org 816657Snate@binkert.orgconst ForwardInstData * 826657Snate@binkert.orgDecode::getInput(ThreadID tid) 836657Snate@binkert.org{ 846657Snate@binkert.org /* Get insts from the inputBuffer to work with */ 856657Snate@binkert.org if (!inputBuffer[tid].empty()) { 867055Snate@binkert.org const ForwardInstData &head = inputBuffer[tid].front(); 876657Snate@binkert.org 886657Snate@binkert.org return (head.isBubble() ? NULL : &(inputBuffer[tid].front())); 896657Snate@binkert.org } else { 906657Snate@binkert.org return NULL; 916657Snate@binkert.org } 927839Snilay@cs.wisc.edu} 937839Snilay@cs.wisc.edu 946657Snate@binkert.orgvoid 956657Snate@binkert.orgDecode::popInput(ThreadID tid) 966657Snate@binkert.org{ 976657Snate@binkert.org if (!inputBuffer[tid].empty()) 986657Snate@binkert.org inputBuffer[tid].pop(); 996657Snate@binkert.org 1006657Snate@binkert.org decodeInfo[tid].inputIndex = 0; 1016657Snate@binkert.org decodeInfo[tid].inMacroop = false; 1026657Snate@binkert.org} 1037007Snate@binkert.org 1047007Snate@binkert.org#if TRACING_ON 1056657Snate@binkert.org/** Add the tracing data to an instruction. This originates in 1066657Snate@binkert.org * decode because this is the first place that execSeqNums are known 1076657Snate@binkert.org * (these are used as the 'FetchSeq' in tracing data) */ 1086657Snate@binkert.orgstatic void 1096657Snate@binkert.orgdynInstAddTracing(MinorDynInstPtr inst, StaticInstPtr static_inst, 1106657Snate@binkert.org MinorCPU &cpu) 1116657Snate@binkert.org{ 112 inst->traceData = cpu.getTracer()->getInstRecord(curTick(), 113 cpu.getContext(inst->id.threadId), 114 inst->staticInst, inst->pc, static_inst); 115 116 /* Use the execSeqNum as the fetch sequence number as this most closely 117 * matches the other processor models' idea of fetch sequence */ 118 if (inst->traceData) 119 inst->traceData->setFetchSeq(inst->id.execSeqNum); 120} 121#endif 122 123void 124Decode::evaluate() 125{ 126 /* Push input onto appropriate input buffer */ 127 if (!inp.outputWire->isBubble()) 128 inputBuffer[inp.outputWire->threadId].setTail(*inp.outputWire); 129 130 ForwardInstData &insts_out = *out.inputWire; 131 132 assert(insts_out.isBubble()); 133 134 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) 135 decodeInfo[tid].blocked = !nextStageReserve[tid].canReserve(); 136 137 ThreadID tid = getScheduledThread(); 138 139 if (tid != InvalidThreadID) { 140 DecodeThreadInfo &decode_info = decodeInfo[tid]; 141 const ForwardInstData *insts_in = getInput(tid); 142 143 unsigned int output_index = 0; 144 145 /* Pack instructions into the output while we can. This may involve 146 * using more than one input line */ 147 while (insts_in && 148 decode_info.inputIndex < insts_in->width() && /* Still more input */ 149 output_index < outputWidth /* Still more output to fill */) 150 { 151 MinorDynInstPtr inst = insts_in->insts[decode_info.inputIndex]; 152 153 if (inst->isBubble()) { 154 /* Skip */ 155 decode_info.inputIndex++; 156 decode_info.inMacroop = false; 157 } else { 158 StaticInstPtr static_inst = inst->staticInst; 159 /* Static inst of a macro-op above the output_inst */ 160 StaticInstPtr parent_static_inst = NULL; 161 MinorDynInstPtr output_inst = inst; 162 163 if (inst->isFault()) { 164 DPRINTF(Decode, "Fault being passed: %d\n", 165 inst->fault->name()); 166 167 decode_info.inputIndex++; 168 decode_info.inMacroop = false; 169 } else if (static_inst->isMacroop()) { 170 /* Generate a new micro-op */ 171 StaticInstPtr static_micro_inst; 172 173 /* Set up PC for the next micro-op emitted */ 174 if (!decode_info.inMacroop) { 175 decode_info.microopPC = inst->pc; 176 decode_info.inMacroop = true; 177 } 178 179 /* Get the micro-op static instruction from the 180 * static_inst. */ 181 static_micro_inst = 182 static_inst->fetchMicroop( 183 decode_info.microopPC.microPC()); 184 185 output_inst = new MinorDynInst(inst->id); 186 output_inst->pc = decode_info.microopPC; 187 output_inst->staticInst = static_micro_inst; 188 output_inst->fault = NoFault; 189 190 /* Allow a predicted next address only on the last 191 * microop */ 192 if (static_micro_inst->isLastMicroop()) { 193 output_inst->predictedTaken = inst->predictedTaken; 194 output_inst->predictedTarget = inst->predictedTarget; 195 } 196 197 DPRINTF(Decode, "Microop decomposition inputIndex:" 198 " %d output_index: %d lastMicroop: %s microopPC:" 199 " %d.%d inst: %d\n", 200 decode_info.inputIndex, output_index, 201 (static_micro_inst->isLastMicroop() ? 202 "true" : "false"), 203 decode_info.microopPC.instAddr(), 204 decode_info.microopPC.microPC(), 205 *output_inst); 206 207 /* Acknowledge that the static_inst isn't mine, it's my 208 * parent macro-op's */ 209 parent_static_inst = static_inst; 210 211 static_micro_inst->advancePC(decode_info.microopPC); 212 213 /* Step input if this is the last micro-op */ 214 if (static_micro_inst->isLastMicroop()) { 215 decode_info.inputIndex++; 216 decode_info.inMacroop = false; 217 } 218 } else { 219 /* Doesn't need decomposing, pass on instruction */ 220 DPRINTF(Decode, "Passing on inst: %s inputIndex:" 221 " %d output_index: %d\n", 222 *output_inst, decode_info.inputIndex, output_index); 223 224 parent_static_inst = static_inst; 225 226 /* Step input */ 227 decode_info.inputIndex++; 228 decode_info.inMacroop = false; 229 } 230 231 /* Set execSeqNum of output_inst */ 232 output_inst->id.execSeqNum = decode_info.execSeqNum; 233 /* Add tracing */ 234#if TRACING_ON 235 dynInstAddTracing(output_inst, parent_static_inst, cpu); 236#endif 237 238 /* Step to next sequence number */ 239 decode_info.execSeqNum++; 240 241 /* Correctly size the output before writing */ 242 if (output_index == 0) insts_out.resize(outputWidth); 243 /* Push into output */ 244 insts_out.insts[output_index] = output_inst; 245 output_index++; 246 } 247 248 /* Have we finished with the input? */ 249 if (decode_info.inputIndex == insts_in->width()) { 250 /* If we have just been producing micro-ops, we *must* have 251 * got to the end of that for inputIndex to be pushed past 252 * insts_in->width() */ 253 assert(!decode_info.inMacroop); 254 popInput(tid); 255 insts_in = NULL; 256 257 if (processMoreThanOneInput) { 258 DPRINTF(Decode, "Wrapping\n"); 259 insts_in = getInput(tid); 260 } 261 } 262 } 263 264 /* The rest of the output (if any) should already have been packed 265 * with bubble instructions by insts_out's initialisation 266 * 267 * for (; output_index < outputWidth; output_index++) 268 * assert(insts_out.insts[output_index]->isBubble()); 269 */ 270 } 271 272 /* If we generated output, reserve space for the result in the next stage 273 * and mark the stage as being active this cycle */ 274 if (!insts_out.isBubble()) { 275 /* Note activity of following buffer */ 276 cpu.activityRecorder->activity(); 277 insts_out.threadId = tid; 278 nextStageReserve[tid].reserve(); 279 } 280 281 /* If we still have input to process and somewhere to put it, 282 * mark stage as active */ 283 for (ThreadID i = 0; i < cpu.numThreads; i++) 284 { 285 if (getInput(i) && nextStageReserve[i].canReserve()) { 286 cpu.activityRecorder->activateStage(Pipeline::DecodeStageId); 287 break; 288 } 289 } 290 291 /* Make sure the input (if any left) is pushed */ 292 if (!inp.outputWire->isBubble()) 293 inputBuffer[inp.outputWire->threadId].pushTail(); 294} 295 296inline ThreadID 297Decode::getScheduledThread() 298{ 299 /* Select thread via policy. */ 300 std::vector<ThreadID> priority_list; 301 302 switch (cpu.threadPolicy) { 303 case Enums::SingleThreaded: 304 priority_list.push_back(0); 305 break; 306 case Enums::RoundRobin: 307 priority_list = cpu.roundRobinPriority(threadPriority); 308 break; 309 case Enums::Random: 310 priority_list = cpu.randomPriority(); 311 break; 312 default: 313 panic("Unknown fetch policy"); 314 } 315 316 for (auto tid : priority_list) { 317 if (cpu.getContext(tid)->status() == ThreadContext::Active && 318 getInput(tid) && 319 !decodeInfo[tid].blocked) { 320 threadPriority = tid; 321 return tid; 322 } 323 } 324 325 return InvalidThreadID; 326} 327 328bool 329Decode::isDrained() 330{ 331 for (const auto &buffer : inputBuffer) { 332 if (!buffer.empty()) 333 return false; 334 } 335 336 return (*inp.outputWire).isBubble(); 337} 338 339void 340Decode::minorTrace() const 341{ 342 std::ostringstream data; 343 344 if (decodeInfo[0].blocked) 345 data << 'B'; 346 else 347 (*out.inputWire).reportData(data); 348 349 MINORTRACE("insts=%s\n", data.str()); 350 inputBuffer[0].minorTrace(); 351} 352 353} 354