pseudo_inst.cc revision 8734
1/* 2 * Copyright (c) 2010-2011 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2011 Advanced Micro Devices, Inc. 15 * Copyright (c) 2003-2006 The Regents of The University of Michigan 16 * All rights reserved. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions are 20 * met: redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer; 22 * redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution; 25 * neither the name of the copyright holders nor the names of its 26 * contributors may be used to endorse or promote products derived from 27 * this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 * 41 * Authors: Nathan Binkert 42 */ 43 44#include <fcntl.h> 45#include <unistd.h> 46 47#include <cerrno> 48#include <fstream> 49#include <string> 50 51#include "arch/vtophys.hh" 52#include "base/debug.hh" 53#include "base/output.hh" 54#include "config/full_system.hh" 55#include "config/the_isa.hh" 56#include "cpu/base.hh" 57#include "cpu/quiesce_event.hh" 58#include "cpu/thread_context.hh" 59#include "debug/Loader.hh" 60#include "debug/Quiesce.hh" 61#include "debug/WorkItems.hh" 62#include "params/BaseCPU.hh" 63#include "sim/pseudo_inst.hh" 64#include "sim/serialize.hh" 65#include "sim/sim_events.hh" 66#include "sim/sim_exit.hh" 67#include "sim/stat_control.hh" 68#include "sim/stats.hh" 69#include "sim/system.hh" 70 71#if FULL_SYSTEM 72#include "arch/kernel_stats.hh" 73#include "sim/vptr.hh" 74#endif 75 76using namespace std; 77 78using namespace Stats; 79using namespace TheISA; 80 81namespace PseudoInst { 82 83#if FULL_SYSTEM 84 85void 86arm(ThreadContext *tc) 87{ 88 if (tc->getKernelStats()) 89 tc->getKernelStats()->arm(); 90} 91 92void 93quiesce(ThreadContext *tc) 94{ 95 if (!tc->getCpuPtr()->params()->do_quiesce) 96 return; 97 98 DPRINTF(Quiesce, "%s: quiesce()\n", tc->getCpuPtr()->name()); 99 100 tc->suspend(); 101 if (tc->getKernelStats()) 102 tc->getKernelStats()->quiesce(); 103} 104 105void 106quiesceSkip(ThreadContext *tc) 107{ 108 BaseCPU *cpu = tc->getCpuPtr(); 109 110 if (!cpu->params()->do_quiesce) 111 return; 112 113 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); 114 115 Tick resume = curTick() + 1; 116 117 cpu->reschedule(quiesceEvent, resume, true); 118 119 DPRINTF(Quiesce, "%s: quiesceSkip() until %d\n", 120 cpu->name(), resume); 121 122 tc->suspend(); 123 if (tc->getKernelStats()) 124 tc->getKernelStats()->quiesce(); 125} 126 127void 128quiesceNs(ThreadContext *tc, uint64_t ns) 129{ 130 BaseCPU *cpu = tc->getCpuPtr(); 131 132 if (!cpu->params()->do_quiesce || ns == 0) 133 return; 134 135 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); 136 137 Tick resume = curTick() + SimClock::Int::ns * ns; 138 139 cpu->reschedule(quiesceEvent, resume, true); 140 141 DPRINTF(Quiesce, "%s: quiesceNs(%d) until %d\n", 142 cpu->name(), ns, resume); 143 144 tc->suspend(); 145 if (tc->getKernelStats()) 146 tc->getKernelStats()->quiesce(); 147} 148 149void 150quiesceCycles(ThreadContext *tc, uint64_t cycles) 151{ 152 BaseCPU *cpu = tc->getCpuPtr(); 153 154 if (!cpu->params()->do_quiesce || cycles == 0) 155 return; 156 157 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); 158 159 Tick resume = curTick() + cpu->ticks(cycles); 160 161 cpu->reschedule(quiesceEvent, resume, true); 162 163 DPRINTF(Quiesce, "%s: quiesceCycles(%d) until %d\n", 164 cpu->name(), cycles, resume); 165 166 tc->suspend(); 167 if (tc->getKernelStats()) 168 tc->getKernelStats()->quiesce(); 169} 170 171uint64_t 172quiesceTime(ThreadContext *tc) 173{ 174 return (tc->readLastActivate() - tc->readLastSuspend()) / 175 SimClock::Int::ns; 176} 177 178#endif 179 180uint64_t 181rpns(ThreadContext *tc) 182{ 183 return curTick() / SimClock::Int::ns; 184} 185 186void 187wakeCPU(ThreadContext *tc, uint64_t cpuid) 188{ 189 System *sys = tc->getSystemPtr(); 190 ThreadContext *other_tc = sys->threadContexts[cpuid]; 191 if (other_tc->status() == ThreadContext::Suspended) 192 other_tc->activate(); 193} 194 195void 196m5exit(ThreadContext *tc, Tick delay) 197{ 198 Tick when = curTick() + delay * SimClock::Int::ns; 199 exitSimLoop("m5_exit instruction encountered", 0, when); 200} 201 202#if FULL_SYSTEM 203 204void 205loadsymbol(ThreadContext *tc) 206{ 207 const string &filename = tc->getCpuPtr()->system->params()->symbolfile; 208 if (filename.empty()) { 209 return; 210 } 211 212 std::string buffer; 213 ifstream file(filename.c_str()); 214 215 if (!file) 216 fatal("file error: Can't open symbol table file %s\n", filename); 217 218 while (!file.eof()) { 219 getline(file, buffer); 220 221 if (buffer.empty()) 222 continue; 223 224 string::size_type idx = buffer.find(' '); 225 if (idx == string::npos) 226 continue; 227 228 string address = "0x" + buffer.substr(0, idx); 229 eat_white(address); 230 if (address.empty()) 231 continue; 232 233 // Skip over letter and space 234 string symbol = buffer.substr(idx + 3); 235 eat_white(symbol); 236 if (symbol.empty()) 237 continue; 238 239 Addr addr; 240 if (!to_number(address, addr)) 241 continue; 242 243 if (!tc->getSystemPtr()->kernelSymtab->insert(addr, symbol)) 244 continue; 245 246 247 DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); 248 } 249 file.close(); 250} 251 252void 253addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr) 254{ 255 char symb[100]; 256 CopyStringOut(tc, symb, symbolAddr, 100); 257 std::string symbol(symb); 258 259 DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); 260 261 tc->getSystemPtr()->kernelSymtab->insert(addr,symbol); 262 debugSymbolTable->insert(addr,symbol); 263} 264 265uint64_t 266initParam(ThreadContext *tc) 267{ 268 return tc->getCpuPtr()->system->init_param; 269} 270 271#endif 272 273 274void 275resetstats(ThreadContext *tc, Tick delay, Tick period) 276{ 277 if (!tc->getCpuPtr()->params()->do_statistics_insts) 278 return; 279 280 281 Tick when = curTick() + delay * SimClock::Int::ns; 282 Tick repeat = period * SimClock::Int::ns; 283 284 Stats::schedStatEvent(false, true, when, repeat); 285} 286 287void 288dumpstats(ThreadContext *tc, Tick delay, Tick period) 289{ 290 if (!tc->getCpuPtr()->params()->do_statistics_insts) 291 return; 292 293 294 Tick when = curTick() + delay * SimClock::Int::ns; 295 Tick repeat = period * SimClock::Int::ns; 296 297 Stats::schedStatEvent(true, false, when, repeat); 298} 299 300void 301dumpresetstats(ThreadContext *tc, Tick delay, Tick period) 302{ 303 if (!tc->getCpuPtr()->params()->do_statistics_insts) 304 return; 305 306 307 Tick when = curTick() + delay * SimClock::Int::ns; 308 Tick repeat = period * SimClock::Int::ns; 309 310 Stats::schedStatEvent(true, true, when, repeat); 311} 312 313void 314m5checkpoint(ThreadContext *tc, Tick delay, Tick period) 315{ 316 if (!tc->getCpuPtr()->params()->do_checkpoint_insts) 317 return; 318 319 Tick when = curTick() + delay * SimClock::Int::ns; 320 Tick repeat = period * SimClock::Int::ns; 321 322 exitSimLoop("checkpoint", 0, when, repeat); 323} 324 325#if FULL_SYSTEM 326 327uint64_t 328readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset) 329{ 330 const string &file = tc->getSystemPtr()->params()->readfile; 331 if (file.empty()) { 332 return ULL(0); 333 } 334 335 uint64_t result = 0; 336 337 int fd = ::open(file.c_str(), O_RDONLY, 0); 338 if (fd < 0) 339 panic("could not open file %s\n", file); 340 341 if (::lseek(fd, offset, SEEK_SET) < 0) 342 panic("could not seek: %s", strerror(errno)); 343 344 char *buf = new char[len]; 345 char *p = buf; 346 while (len > 0) { 347 int bytes = ::read(fd, p, len); 348 if (bytes <= 0) 349 break; 350 351 p += bytes; 352 result += bytes; 353 len -= bytes; 354 } 355 356 close(fd); 357 CopyIn(tc, vaddr, buf, result); 358 delete [] buf; 359 return result; 360} 361 362uint64_t 363writefile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset, 364 Addr filename_addr) 365{ 366 ostream *os; 367 368 // copy out target filename 369 char fn[100]; 370 std::string filename; 371 CopyStringOut(tc, fn, filename_addr, 100); 372 filename = std::string(fn); 373 374 if (offset == 0) { 375 // create a new file (truncate) 376 os = simout.create(filename, true); 377 } else { 378 // do not truncate file if offset is non-zero 379 // (ios::in flag is required as well to keep the existing data 380 // intact, otherwise existing data will be zeroed out.) 381 os = simout.openFile(simout.directory() + filename, 382 ios::in | ios::out | ios::binary); 383 } 384 if (!os) 385 panic("could not open file %s\n", filename); 386 387 // seek to offset 388 os->seekp(offset); 389 390 // copy out data and write to file 391 char *buf = new char[len]; 392 CopyOut(tc, buf, vaddr, len); 393 os->write(buf, len); 394 if (os->fail() || os->bad()) 395 panic("Error while doing writefile!\n"); 396 397 simout.close(os); 398 399 delete [] buf; 400 401 return len; 402} 403 404#endif 405 406void 407debugbreak(ThreadContext *tc) 408{ 409 Debug::breakpoint(); 410} 411 412void 413switchcpu(ThreadContext *tc) 414{ 415 exitSimLoop("switchcpu"); 416} 417 418// 419// This function is executed when annotated work items begin. Depending on 420// what the user specified at the command line, the simulation may exit and/or 421// take a checkpoint when a certain work item begins. 422// 423void 424workbegin(ThreadContext *tc, uint64_t workid, uint64_t threadid) 425{ 426 tc->getCpuPtr()->workItemBegin(); 427 System *sys = tc->getSystemPtr(); 428 const System::Params *params = sys->params(); 429 sys->workItemBegin(threadid, workid); 430 431 DPRINTF(WorkItems, "Work Begin workid: %d, threadid %d\n", workid, 432 threadid); 433 434 // 435 // If specified, determine if this is the specific work item the user 436 // identified 437 // 438 if (params->work_item_id == -1 || params->work_item_id == workid) { 439 440 uint64_t systemWorkBeginCount = sys->incWorkItemsBegin(); 441 int cpuId = tc->getCpuPtr()->cpuId(); 442 443 if (params->work_cpus_ckpt_count != 0 && 444 sys->markWorkItem(cpuId) >= params->work_cpus_ckpt_count) { 445 // 446 // If active cpus equals checkpoint count, create checkpoint 447 // 448 exitSimLoop("checkpoint"); 449 } 450 451 if (systemWorkBeginCount == params->work_begin_ckpt_count) { 452 // 453 // Note: the string specified as the cause of the exit event must 454 // exactly equal "checkpoint" inorder to create a checkpoint 455 // 456 exitSimLoop("checkpoint"); 457 } 458 459 if (systemWorkBeginCount == params->work_begin_exit_count) { 460 // 461 // If a certain number of work items started, exit simulation 462 // 463 exitSimLoop("work started count reach"); 464 } 465 466 if (cpuId == params->work_begin_cpu_id_exit) { 467 // 468 // If work started on the cpu id specified, exit simulation 469 // 470 exitSimLoop("work started on specific cpu"); 471 } 472 } 473} 474 475// 476// This function is executed when annotated work items end. Depending on 477// what the user specified at the command line, the simulation may exit and/or 478// take a checkpoint when a certain work item ends. 479// 480void 481workend(ThreadContext *tc, uint64_t workid, uint64_t threadid) 482{ 483 tc->getCpuPtr()->workItemEnd(); 484 System *sys = tc->getSystemPtr(); 485 const System::Params *params = sys->params(); 486 sys->workItemEnd(threadid, workid); 487 488 DPRINTF(WorkItems, "Work End workid: %d, threadid %d\n", workid, threadid); 489 490 // 491 // If specified, determine if this is the specific work item the user 492 // identified 493 // 494 if (params->work_item_id == -1 || params->work_item_id == workid) { 495 496 uint64_t systemWorkEndCount = sys->incWorkItemsEnd(); 497 int cpuId = tc->getCpuPtr()->cpuId(); 498 499 if (params->work_cpus_ckpt_count != 0 && 500 sys->markWorkItem(cpuId) >= params->work_cpus_ckpt_count) { 501 // 502 // If active cpus equals checkpoint count, create checkpoint 503 // 504 exitSimLoop("checkpoint"); 505 } 506 507 if (params->work_end_ckpt_count != 0 && 508 systemWorkEndCount == params->work_end_ckpt_count) { 509 // 510 // If total work items completed equals checkpoint count, create 511 // checkpoint 512 // 513 exitSimLoop("checkpoint"); 514 } 515 516 if (params->work_end_exit_count != 0 && 517 systemWorkEndCount == params->work_end_exit_count) { 518 // 519 // If total work items completed equals exit count, exit simulation 520 // 521 exitSimLoop("work items exit count reached"); 522 } 523 } 524} 525 526} // namespace PseudoInst 527