cpu_impl.hh revision 2315
15643Sgblack@eecs.umich.edu/* 25643Sgblack@eecs.umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan 35643Sgblack@eecs.umich.edu * All rights reserved. 45643Sgblack@eecs.umich.edu * 55643Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 65643Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 75643Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 85643Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 95643Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 105643Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 115643Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 125643Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 135643Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 145643Sgblack@eecs.umich.edu * this software without specific prior written permission. 155643Sgblack@eecs.umich.edu * 165643Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 175643Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 185643Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 195643Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 205643Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 215643Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 225643Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235643Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245643Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255643Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 265643Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275643Sgblack@eecs.umich.edu */ 285643Sgblack@eecs.umich.edu 295643Sgblack@eecs.umich.edu//#include <cmath> 305643Sgblack@eecs.umich.edu#include <cstdio> 3111793Sbrandon.potter@amd.com//#include <cstdlib> 3211793Sbrandon.potter@amd.com#include <iostream> 336138Sgblack@eecs.umich.edu#include <iomanip> 345651Sgblack@eecs.umich.edu#include <list> 358746Sgblack@eecs.umich.edu//#include <sstream> 368232Snate@binkert.org#include <string> 375657Sgblack@eecs.umich.edu 385643Sgblack@eecs.umich.edu//#include "base/cprintf.hh" 395643Sgblack@eecs.umich.edu//#include "base/inifile.hh" 405643Sgblack@eecs.umich.edu//#include "base/loader/symtab.hh" 415643Sgblack@eecs.umich.edu#include "base/misc.hh" 429805Sstever@gmail.com//#include "base/pollevent.hh" 439808Sstever@gmail.com//#include "base/range.hh" 449805Sstever@gmail.com#include "base/refcnt.hh" 455643Sgblack@eecs.umich.edu//#include "base/stats/events.hh" 467913SBrad.Beckmann@amd.com#include "cpu/base.hh" 477913SBrad.Beckmann@amd.com#include "cpu/base_dyn_inst.hh" 487913SBrad.Beckmann@amd.com#include "cpu/checker/cpu.hh" 497913SBrad.Beckmann@amd.com#include "cpu/cpu_exec_context.hh" 507913SBrad.Beckmann@amd.com#include "cpu/exec_context.hh" 516136Sgblack@eecs.umich.edu//#include "cpu/exetrace.hh" 525643Sgblack@eecs.umich.edu//#include "cpu/profile.hh" 535643Sgblack@eecs.umich.edu#include "cpu/sampler/sampler.hh" 545653Sgblack@eecs.umich.edu//#include "cpu/smt.hh" 555653Sgblack@eecs.umich.edu#include "cpu/static_inst.hh" 565653Sgblack@eecs.umich.edu//#include "kern/kernel_stats.hh" 575653Sgblack@eecs.umich.edu#include "mem/base_mem.hh" 585827Sgblack@eecs.umich.edu#include "mem/mem_interface.hh" 595653Sgblack@eecs.umich.edu#include "sim/byteswap.hh" 605643Sgblack@eecs.umich.edu#include "sim/builder.hh" 615643Sgblack@eecs.umich.edu//#include "sim/debug.hh" 627913SBrad.Beckmann@amd.com//#include "sim/host.hh" 637913SBrad.Beckmann@amd.com//#include "sim/sim_events.hh" 647913SBrad.Beckmann@amd.com#include "sim/sim_object.hh" 657913SBrad.Beckmann@amd.com#include "sim/stats.hh" 667913SBrad.Beckmann@amd.com 679807Sstever@gmail.com#include "cpu/o3/alpha_dyn_inst.hh" 687913SBrad.Beckmann@amd.com#include "cpu/o3/alpha_impl.hh" 699805Sstever@gmail.com 709807Sstever@gmail.com#include "cpu/ozone/dyn_inst.hh" 717913SBrad.Beckmann@amd.com#include "cpu/ozone/ozone_impl.hh" 727913SBrad.Beckmann@amd.com#include "cpu/ozone/simple_impl.hh" 739805Sstever@gmail.com 749805Sstever@gmail.com#if FULL_SYSTEM 759805Sstever@gmail.com#include "base/remote_gdb.hh" 769805Sstever@gmail.com#include "mem/functional/memory_control.hh" 779805Sstever@gmail.com#include "mem/functional/physical.hh" 789805Sstever@gmail.com#include "sim/system.hh" 799805Sstever@gmail.com#include "arch/tlb.hh" 809805Sstever@gmail.com#include "arch/stacktrace.hh" 819805Sstever@gmail.com#include "arch/vtophys.hh" 829805Sstever@gmail.com#else // !FULL_SYSTEM 839805Sstever@gmail.com#include "mem/functional/functional.hh" 849805Sstever@gmail.com#endif // FULL_SYSTEM 859805Sstever@gmail.com 869805Sstever@gmail.comusing namespace std; 879805Sstever@gmail.com//The CheckerCPU does alpha only 889805Sstever@gmail.comusing namespace AlphaISA; 899805Sstever@gmail.com 909805Sstever@gmail.comvoid 915643Sgblack@eecs.umich.eduCheckerCPU::init() 9211144Sjthestness@gmail.com{ 9311144Sjthestness@gmail.com/* 9411144Sjthestness@gmail.com BaseCPU::init(); 9511144Sjthestness@gmail.com#if FULL_SYSTEM 9611144Sjthestness@gmail.com for (int i = 0; i < execContexts.size(); ++i) { 9711144Sjthestness@gmail.com ExecContext *xc = execContexts[i]; 9811144Sjthestness@gmail.com 9911144Sjthestness@gmail.com // initialize CPU, including PC 1005643Sgblack@eecs.umich.edu TheISA::initCPU(xc, xc->readCpuId()); 1015643Sgblack@eecs.umich.edu } 1025643Sgblack@eecs.umich.edu#endif 1035643Sgblack@eecs.umich.edu*/ 1045643Sgblack@eecs.umich.edu} 1055643Sgblack@eecs.umich.edu 10613229Sgabeblack@google.comCheckerCPU::CheckerCPU(Params *p) 1075643Sgblack@eecs.umich.edu : BaseCPU(p), cpuXC(NULL), xcProxy(NULL) 1085643Sgblack@eecs.umich.edu{ 10913229Sgabeblack@google.com memReq = new MemReq(); 1105643Sgblack@eecs.umich.edu memReq->xc = xcProxy; 1115643Sgblack@eecs.umich.edu memReq->asid = 0; 1125643Sgblack@eecs.umich.edu memReq->data = new uint8_t[64]; 1135643Sgblack@eecs.umich.edu 1145898Sgblack@eecs.umich.edu numInst = 0; 1159805Sstever@gmail.com startNumInst = 0; 1165643Sgblack@eecs.umich.edu numLoad = 0; 1175643Sgblack@eecs.umich.edu startNumLoad = 0; 1185643Sgblack@eecs.umich.edu youngestSN = 0; 1195643Sgblack@eecs.umich.edu 1205643Sgblack@eecs.umich.edu changedPC = willChangePC = changedNextPC = false; 1215643Sgblack@eecs.umich.edu 1225643Sgblack@eecs.umich.edu exitOnError = p->exitOnError; 1235643Sgblack@eecs.umich.edu#if FULL_SYSTEM 1245643Sgblack@eecs.umich.edu itb = p->itb; 12513229Sgabeblack@google.com dtb = p->dtb; 1265643Sgblack@eecs.umich.edu systemPtr = NULL; 1275643Sgblack@eecs.umich.edu memPtr = NULL; 12813229Sgabeblack@google.com#endif 1295643Sgblack@eecs.umich.edu} 1305643Sgblack@eecs.umich.edu 1315643Sgblack@eecs.umich.eduCheckerCPU::~CheckerCPU() 1325643Sgblack@eecs.umich.edu{ 1335898Sgblack@eecs.umich.edu} 1349805Sstever@gmail.com 1355643Sgblack@eecs.umich.eduvoid 1365643Sgblack@eecs.umich.eduCheckerCPU::setMemory(FunctionalMemory *mem) 1375643Sgblack@eecs.umich.edu{ 1385643Sgblack@eecs.umich.edu memPtr = mem; 1395643Sgblack@eecs.umich.edu#if !FULL_SYSTEM 1405643Sgblack@eecs.umich.edu cpuXC = new CPUExecContext(this, /* thread_num */ 0, mem, 1417913SBrad.Beckmann@amd.com /* asid */ 0); 1425643Sgblack@eecs.umich.edu 1435643Sgblack@eecs.umich.edu cpuXC->setStatus(ExecContext::Suspended); 1445643Sgblack@eecs.umich.edu xcProxy = cpuXC->getProxy(); 1457913SBrad.Beckmann@amd.com execContexts.push_back(xcProxy); 1465643Sgblack@eecs.umich.edu#else 1475643Sgblack@eecs.umich.edu if (systemPtr) { 1485643Sgblack@eecs.umich.edu cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr); 1495643Sgblack@eecs.umich.edu 1505643Sgblack@eecs.umich.edu cpuXC->setStatus(ExecContext::Suspended); 1515643Sgblack@eecs.umich.edu xcProxy = cpuXC->getProxy(); 1525643Sgblack@eecs.umich.edu execContexts.push_back(xcProxy); 1535643Sgblack@eecs.umich.edu memReq->xc = xcProxy; 1545643Sgblack@eecs.umich.edu } 1555643Sgblack@eecs.umich.edu#endif 1565643Sgblack@eecs.umich.edu} 1575643Sgblack@eecs.umich.edu 1585643Sgblack@eecs.umich.edu#if FULL_SYSTEM 1595643Sgblack@eecs.umich.eduvoid 1605643Sgblack@eecs.umich.eduCheckerCPU::setSystem(System *system) 1615643Sgblack@eecs.umich.edu{ 1625643Sgblack@eecs.umich.edu systemPtr = system; 1635643Sgblack@eecs.umich.edu 1645643Sgblack@eecs.umich.edu if (memPtr) { 1655643Sgblack@eecs.umich.edu cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr); 1665643Sgblack@eecs.umich.edu 1675643Sgblack@eecs.umich.edu cpuXC->setStatus(ExecContext::Suspended); 1685643Sgblack@eecs.umich.edu xcProxy = cpuXC->getProxy(); 1695643Sgblack@eecs.umich.edu execContexts.push_back(xcProxy); 1705643Sgblack@eecs.umich.edu memReq->xc = xcProxy; 1715643Sgblack@eecs.umich.edu } 1725643Sgblack@eecs.umich.edu} 1735643Sgblack@eecs.umich.edu#endif 1745643Sgblack@eecs.umich.edu 1755643Sgblack@eecs.umich.eduvoid 1765643Sgblack@eecs.umich.eduCheckerCPU::serialize(ostream &os) 1775643Sgblack@eecs.umich.edu{ 1785643Sgblack@eecs.umich.edu/* 1795643Sgblack@eecs.umich.edu BaseCPU::serialize(os); 1805643Sgblack@eecs.umich.edu SERIALIZE_SCALAR(inst); 1815643Sgblack@eecs.umich.edu nameOut(os, csprintf("%s.xc", name())); 1825643Sgblack@eecs.umich.edu cpuXC->serialize(os); 1835643Sgblack@eecs.umich.edu cacheCompletionEvent.serialize(os); 1845643Sgblack@eecs.umich.edu*/ 1855643Sgblack@eecs.umich.edu} 1865643Sgblack@eecs.umich.edu 1875643Sgblack@eecs.umich.eduvoid 1885643Sgblack@eecs.umich.eduCheckerCPU::unserialize(Checkpoint *cp, const string §ion) 1895643Sgblack@eecs.umich.edu{ 1905643Sgblack@eecs.umich.edu/* 1915643Sgblack@eecs.umich.edu BaseCPU::unserialize(cp, section); 1925643Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(inst); 1935643Sgblack@eecs.umich.edu cpuXC->unserialize(cp, csprintf("%s.xc", section)); 1945643Sgblack@eecs.umich.edu*/ 1955643Sgblack@eecs.umich.edu} 1965643Sgblack@eecs.umich.edu 1976712Snate@binkert.orgFault 1985651Sgblack@eecs.umich.eduCheckerCPU::copySrcTranslate(Addr src) 1995657Sgblack@eecs.umich.edu{ 2005657Sgblack@eecs.umich.edu static bool no_warn = true; 2015657Sgblack@eecs.umich.edu int blk_size = 64; 2025657Sgblack@eecs.umich.edu // Only support block sizes of 64 atm. 2035657Sgblack@eecs.umich.edu assert(blk_size == 64); 2045657Sgblack@eecs.umich.edu int offset = src & (blk_size - 1); 2055651Sgblack@eecs.umich.edu 2065651Sgblack@eecs.umich.edu // Make sure block doesn't span page 2075654Sgblack@eecs.umich.edu if (no_warn && 2085654Sgblack@eecs.umich.edu (src & PageMask) != ((src + blk_size) & PageMask) && 2096138Sgblack@eecs.umich.edu (src >> 40) != 0xfffffc) { 2106138Sgblack@eecs.umich.edu warn("Copied block source spans pages %x.", src); 2116138Sgblack@eecs.umich.edu no_warn = false; 2126138Sgblack@eecs.umich.edu } 2136138Sgblack@eecs.umich.edu 2146138Sgblack@eecs.umich.edu memReq->reset(src & ~(blk_size - 1), blk_size); 2156138Sgblack@eecs.umich.edu 2166138Sgblack@eecs.umich.edu // translate to physical address 2176138Sgblack@eecs.umich.edu Fault fault = cpuXC->translateDataReadReq(memReq); 2186138Sgblack@eecs.umich.edu 2196138Sgblack@eecs.umich.edu if (fault == NoFault) { 2206138Sgblack@eecs.umich.edu cpuXC->copySrcAddr = src; 2216138Sgblack@eecs.umich.edu cpuXC->copySrcPhysAddr = memReq->paddr + offset; 2226138Sgblack@eecs.umich.edu } else { 2236138Sgblack@eecs.umich.edu assert(!fault->isAlignmentFault()); 2246138Sgblack@eecs.umich.edu 2256138Sgblack@eecs.umich.edu cpuXC->copySrcAddr = 0; 2268746Sgblack@eecs.umich.edu cpuXC->copySrcPhysAddr = 0; 22711150Smitch.hayenga@arm.com } 2286138Sgblack@eecs.umich.edu return fault; 2296138Sgblack@eecs.umich.edu} 2308746Sgblack@eecs.umich.edu 2316138Sgblack@eecs.umich.eduFault 2326138Sgblack@eecs.umich.eduCheckerCPU::copy(Addr dest) 2336139Sgblack@eecs.umich.edu{ 2346139Sgblack@eecs.umich.edu static bool no_warn = true; 2356139Sgblack@eecs.umich.edu int blk_size = 64; 2366139Sgblack@eecs.umich.edu // Only support block sizes of 64 atm. 2376139Sgblack@eecs.umich.edu assert(blk_size == 64); 2386139Sgblack@eecs.umich.edu uint8_t data[blk_size]; 2396139Sgblack@eecs.umich.edu //assert(cpuXC->copySrcAddr); 2406139Sgblack@eecs.umich.edu int offset = dest & (blk_size - 1); 2416139Sgblack@eecs.umich.edu 2426139Sgblack@eecs.umich.edu // Make sure block doesn't span page 2436139Sgblack@eecs.umich.edu if (no_warn && 2446139Sgblack@eecs.umich.edu (dest & PageMask) != ((dest + blk_size) & PageMask) && 2456139Sgblack@eecs.umich.edu (dest >> 40) != 0xfffffc) { 2466139Sgblack@eecs.umich.edu no_warn = false; 2476139Sgblack@eecs.umich.edu warn("Copied block destination spans pages %x. ", dest); 2486139Sgblack@eecs.umich.edu } 2496138Sgblack@eecs.umich.edu 2506138Sgblack@eecs.umich.edu memReq->reset(dest & ~(blk_size -1), blk_size); 2519524SAndreas.Sandberg@ARM.com // translate to physical address 2525643Sgblack@eecs.umich.edu Fault fault = cpuXC->translateDataWriteReq(memReq); 2535643Sgblack@eecs.umich.edu 2545643Sgblack@eecs.umich.edu if (fault == NoFault) { 2555827Sgblack@eecs.umich.edu Addr dest_addr = memReq->paddr + offset; 2565827Sgblack@eecs.umich.edu // Need to read straight from memory since we have more than 8 bytes. 2575827Sgblack@eecs.umich.edu memReq->paddr = cpuXC->copySrcPhysAddr; 2585827Sgblack@eecs.umich.edu cpuXC->mem->read(memReq, data); 2595827Sgblack@eecs.umich.edu memReq->paddr = dest_addr; 2605827Sgblack@eecs.umich.edu cpuXC->mem->write(memReq, data); 2615827Sgblack@eecs.umich.edu memReq->cmd = Copy; 2625827Sgblack@eecs.umich.edu memReq->completionEvent = NULL; 2635827Sgblack@eecs.umich.edu memReq->paddr = cpuXC->copySrcPhysAddr; 2645827Sgblack@eecs.umich.edu memReq->dest = dest_addr; 2655827Sgblack@eecs.umich.edu memReq->size = 64; 2665827Sgblack@eecs.umich.edu memReq->time = curTick; 2675827Sgblack@eecs.umich.edu memReq->flags &= ~INST_READ; 2685827Sgblack@eecs.umich.edu } 2695827Sgblack@eecs.umich.edu else 2705827Sgblack@eecs.umich.edu assert(!fault->isAlignmentFault()); 2716137Sgblack@eecs.umich.edu 27210905Sandreas.sandberg@arm.com return fault; 2737903Shestness@cs.utexas.edu} 2747903Shestness@cs.utexas.edu 2757903Shestness@cs.utexas.edu// precise architected memory state accessor macros 2767903Shestness@cs.utexas.edutemplate <class T> 2777903Shestness@cs.utexas.eduFault 2787903Shestness@cs.utexas.eduCheckerCPU::read(Addr addr, T &data, unsigned flags) 2797903Shestness@cs.utexas.edu{ 2807903Shestness@cs.utexas.edu memReq->reset(addr, sizeof(T), flags); 2817903Shestness@cs.utexas.edu 2827903Shestness@cs.utexas.edu // translate to physical address 2837903Shestness@cs.utexas.edu // Should I probe the DTB? Or should I just take the physical address 2847903Shestness@cs.utexas.edu // and assume correct translation? 28510905Sandreas.sandberg@arm.com translateDataReadReq(memReq); 2867903Shestness@cs.utexas.edu 2877903Shestness@cs.utexas.edu // if we have a cache, do cache access too 2887903Shestness@cs.utexas.edu memReq->cmd = Read; 2897903Shestness@cs.utexas.edu memReq->completionEvent = NULL; 2907903Shestness@cs.utexas.edu memReq->time = curTick; 2917903Shestness@cs.utexas.edu memReq->flags &= ~INST_READ; 2927903Shestness@cs.utexas.edu 2937903Shestness@cs.utexas.edu if (!(memReq->flags & UNCACHEABLE)) { 2947903Shestness@cs.utexas.edu cpuXC->read(memReq, data); 2957903Shestness@cs.utexas.edu } else { 2967903Shestness@cs.utexas.edu // Assume the data is correct if it's an uncached access 2977903Shestness@cs.utexas.edu memcpy(&data, &unverifiedResult.integer, sizeof(T)); 2987903Shestness@cs.utexas.edu } 2997903Shestness@cs.utexas.edu 3005643Sgblack@eecs.umich.edu return NoFault; 3015643Sgblack@eecs.umich.edu} 3025643Sgblack@eecs.umich.edu 3035643Sgblack@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS 3045643Sgblack@eecs.umich.edu 305template 306Fault 307CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags); 308 309template 310Fault 311CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags); 312 313template 314Fault 315CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags); 316 317template 318Fault 319CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags); 320 321#endif //DOXYGEN_SHOULD_SKIP_THIS 322 323template<> 324Fault 325CheckerCPU::read(Addr addr, double &data, unsigned flags) 326{ 327 return read(addr, *(uint64_t*)&data, flags); 328} 329 330template<> 331Fault 332CheckerCPU::read(Addr addr, float &data, unsigned flags) 333{ 334 return read(addr, *(uint32_t*)&data, flags); 335} 336 337template<> 338Fault 339CheckerCPU::read(Addr addr, int32_t &data, unsigned flags) 340{ 341 return read(addr, (uint32_t&)data, flags); 342} 343 344template <class T> 345Fault 346CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 347{ 348 memReq->reset(addr, sizeof(T), flags); 349 350 // translate to physical address 351 cpuXC->translateDataWriteReq(memReq); 352 353 if ((!(unverifiedReq->flags & LOCKED) || 354 ((unverifiedReq->flags & LOCKED) && 355 unverifiedReq->result == 1)) && 356 !(unverifiedReq->flags & UNCACHEABLE)) { 357 // do functional access 358// cpuXC->read(memReq, data); 359 360 memReq->cmd = Write; 361// memcpy(memReq->data,(uint8_t *)&data,memReq->size); 362 T inst_data; 363 memcpy(&inst_data, unverifiedReq->data, sizeof(T)); 364 memReq->completionEvent = NULL; 365 memReq->time = curTick; 366 memReq->flags &= ~INST_READ; 367 368 // Hard to verify this as the data writes back after the 369 // instruction commits. May only be able to check that the 370 // value produced from execute() matches the value produced 371 // from the instruction's first execution. 372 if (data != inst_data) { 373 warn("Store value does not match value in memory! " 374 "Instruction: %#x, memory: %#x", 375 inst_data, data); 376 handleError(); 377 } 378 } 379 380 // Assume the result was the same as the one passed in. This checker 381 // doesn't check if the SC should succeed or fail, it just checks the 382 // value. 383 if (res) 384 *res = unverifiedReq->result; 385 386 return NoFault; 387} 388 389 390#ifndef DOXYGEN_SHOULD_SKIP_THIS 391template 392Fault 393CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); 394 395template 396Fault 397CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); 398 399template 400Fault 401CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); 402 403template 404Fault 405CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); 406 407#endif //DOXYGEN_SHOULD_SKIP_THIS 408 409template<> 410Fault 411CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 412{ 413 return write(*(uint64_t*)&data, addr, flags, res); 414} 415 416template<> 417Fault 418CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 419{ 420 return write(*(uint32_t*)&data, addr, flags, res); 421} 422 423template<> 424Fault 425CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 426{ 427 return write((uint32_t)data, addr, flags, res); 428} 429 430 431#if FULL_SYSTEM 432Addr 433CheckerCPU::dbg_vtophys(Addr addr) 434{ 435 return vtophys(xcProxy, addr); 436} 437#endif // FULL_SYSTEM 438 439#if FULL_SYSTEM 440void 441CheckerCPU::post_interrupt(int int_num, int index) 442{ 443 BaseCPU::post_interrupt(int_num, index); 444 445 if (cpuXC->status() == ExecContext::Suspended) { 446 DPRINTF(IPI,"Suspended Processor awoke\n"); 447 cpuXC->activate(); 448 } 449} 450#endif // FULL_SYSTEM 451 452bool 453CheckerCPU::translateInstReq(MemReqPtr &req) 454{ 455#if FULL_SYSTEM 456 return (cpuXC->translateInstReq(req) == NoFault); 457#else 458 cpuXC->translateInstReq(req); 459 return true; 460#endif 461} 462 463void 464CheckerCPU::translateDataReadReq(MemReqPtr &req) 465{ 466 cpuXC->translateDataReadReq(req); 467 468 if (req->vaddr != unverifiedReq->vaddr) { 469 warn("Request virtual addresses do not match! Inst: %#x, checker:" 470 " %#x", 471 unverifiedReq->vaddr, req->vaddr); 472 } 473 req->paddr = unverifiedReq->paddr; 474 475 if (checkFlags(req)) { 476 warn("Request flags do not match! Inst: %#x, checker: %#x", 477 unverifiedReq->flags, req->flags); 478 handleError(); 479 } 480} 481 482void 483CheckerCPU::translateDataWriteReq(MemReqPtr &req) 484{ 485 cpuXC->translateDataWriteReq(req); 486 487 if (req->vaddr != unverifiedReq->vaddr) { 488 warn("Request virtual addresses do not match! Inst: %#x, checker:" 489 " %#x", 490 unverifiedReq->vaddr, req->vaddr); 491 } 492 req->paddr = unverifiedReq->paddr; 493 494 if (checkFlags(req)) { 495 warn("Request flags do not match! Inst: %#x, checker: %#x", 496 unverifiedReq->flags, req->flags); 497 handleError(); 498 } 499} 500 501bool 502CheckerCPU::checkFlags(MemReqPtr &req) 503{ 504 // Remove any dynamic flags that don't have to do with the request itself. 505 unsigned flags = unverifiedReq->flags; 506 unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | NO_FAULT; 507 flags = flags & (mask); 508 if (flags == req->flags) { 509 return false; 510 } else { 511 return true; 512 } 513} 514 515/* start simulation, program loaded, processor precise state initialized */ 516template <class DynInstPtr> 517void 518Checker<DynInstPtr>::tick(DynInstPtr &completed_inst) 519{ 520 DynInstPtr inst; 521 522 if (!instList.empty()) { 523 if (youngestSN < completed_inst->seqNum) { 524 DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n", 525 completed_inst->seqNum, completed_inst->readPC()); 526 instList.push_back(completed_inst); 527 youngestSN = completed_inst->seqNum; 528 } 529 530 if (!instList.front()->isCompleted()) { 531 return; 532 } else { 533 inst = instList.front(); 534 instList.pop_front(); 535 } 536 } else { 537 if (!completed_inst->isCompleted()) { 538 if (youngestSN < completed_inst->seqNum) { 539 DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n", 540 completed_inst->seqNum, completed_inst->readPC()); 541 instList.push_back(completed_inst); 542 youngestSN = completed_inst->seqNum; 543 } 544 return; 545 } else { 546 if (youngestSN < completed_inst->seqNum) { 547 inst = completed_inst; 548 youngestSN = completed_inst->seqNum; 549 } else { 550// panic("SN already seen yet the list is empty!"); 551 return; 552 } 553 } 554 } 555 556 while (1) { 557 DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%#x.\n", 558 inst->seqNum, inst->readPC()); 559// verifyInst = completed_inst; 560 unverifiedResult.integer = inst->readIntResult(); 561 unverifiedReq = inst->req; 562 numCycles++; 563 564 Fault fault = NoFault; 565 566 // maintain $r0 semantics 567 cpuXC->setIntReg(ZeroReg, 0); 568#ifdef TARGET_ALPHA 569 cpuXC->setFloatRegDouble(ZeroReg, 0.0); 570#endif // TARGET_ALPHA 571 572 // Try to fetch an instruction 573 574 // set up memory request for instruction fetch 575#if FULL_SYSTEM 576#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 577#else 578#define IFETCH_FLAGS(pc) 0 579#endif 580 581 if (changedPC) { 582 DPRINTF(Checker, "Changed PC recently to %#x\n", 583 cpuXC->readPC()); 584 if (willChangePC) { 585 if (newPC == cpuXC->readPC()) { 586 DPRINTF(Checker, "Changed PC matches expected PC\n"); 587 } else { 588 warn("Changed PC does not match expected PC, changed: %#x, " 589 "expected: %#x", 590 cpuXC->readPC(), newPC); 591 handleError(); 592 } 593 willChangePC = false; 594 } 595 changedPC = false; 596 } 597 if (changedNextPC) { 598 DPRINTF(Checker, "Changed NextPC recently to %#x\n", 599 cpuXC->readNextPC()); 600 changedNextPC = false; 601 } 602 603 memReq->cmd = Read; 604 memReq->reset(cpuXC->readPC() & ~3, sizeof(uint32_t), 605 IFETCH_FLAGS(cpuXC->readPC())); 606 607 bool succeeded = translateInstReq(memReq); 608 609 if (!succeeded) { 610 warn("Instruction PC %#x was not found in the ITB!", 611 cpuXC->readPC()); 612 handleError(); 613 614 // go to the next instruction 615 cpuXC->setPC(cpuXC->readNextPC()); 616 cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); 617 618 return; 619 } 620 621// if (fault == NoFault) 622// fault = cpuXC->mem->read(memReq, machInst); 623 cpuXC->mem->read(memReq, machInst); 624 625 // If we've got a valid instruction (i.e., no fault on instruction 626 // fetch), then execute it. 627 628 // keep an instruction count 629 numInst++; 630// numInsts++; 631 632 // decode the instruction 633 machInst = gtoh(machInst); 634 // Checks that the instruction matches what we expected it to be. 635 // Checks both the machine instruction and the PC. 636 validateInst(inst); 637 638 curStaticInst = StaticInst::decode(makeExtMI(machInst, cpuXC->readPC())); 639 640#if FULL_SYSTEM 641 cpuXC->setInst(machInst); 642#endif // FULL_SYSTEM 643 644 fault = inst->getFault(); 645 646 // Either the instruction was a fault and we should process the fault, 647 // or we should just go ahead execute the instruction. This assumes 648 // that the instruction is properly marked as a fault. 649 if (fault == NoFault) { 650 651 cpuXC->func_exe_inst++; 652 653 fault = curStaticInst->execute(this, NULL); 654 655 // Checks to make sure instrution results are correct. 656 validateExecution(inst); 657 658// if (curStaticInst->isMemRef()) { 659// numMemRefs++; 660// } 661 662 if (curStaticInst->isLoad()) { 663 ++numLoad; 664 } 665 } 666 667 if (fault != NoFault) { 668#if FULL_SYSTEM 669 fault->invoke(xcProxy); 670 willChangePC = true; 671 newPC = cpuXC->readPC(); 672 DPRINTF(Checker, "Fault, PC is now %#x\n", newPC); 673#else // !FULL_SYSTEM 674 fatal("fault (%d) detected @ PC 0x%08p", fault, cpuXC->readPC()); 675#endif // FULL_SYSTEM 676 } else { 677#if THE_ISA != MIPS_ISA 678 // go to the next instruction 679 cpuXC->setPC(cpuXC->readNextPC()); 680 cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); 681#else 682 // go to the next instruction 683 cpuXC->setPC(cpuXC->readNextPC()); 684 cpuXC->setNextPC(cpuXC->readNextNPC()); 685 cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst)); 686#endif 687 688 } 689 690#if FULL_SYSTEM 691 Addr oldpc; 692 int count = 0; 693 do { 694 oldpc = cpuXC->readPC(); 695 system->pcEventQueue.service(xcProxy); 696 count++; 697 } while (oldpc != cpuXC->readPC()); 698 if (count > 1) { 699 willChangePC = true; 700 newPC = cpuXC->readPC(); 701 DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC); 702 } 703#endif 704 705 // Checks PC, next PC. Optionally can check all registers. (Or just those 706 // that have been modified). 707 validateState(); 708 709 if (instList.empty()) { 710 break; 711 } else if (instList.front()->isCompleted()) { 712 inst = instList.front(); 713 instList.pop_front(); 714 } else { 715 break; 716 } 717 } 718} 719 720template <class DynInstPtr> 721void 722Checker<DynInstPtr>::switchOut(Sampler *s) 723{ 724 sampler = s; 725 instList.clear(); 726} 727 728template <class DynInstPtr> 729void 730Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU) 731{ 732// BaseCPU::takeOverFrom(oldCPU); 733 734 // if any of this CPU's ExecContexts are active, mark the CPU as 735 // running and schedule its tick event. 736/* 737 for (int i = 0; i < execContexts.size(); ++i) { 738 ExecContext *xc = execContexts[i]; 739 } 740*/ 741} 742 743template <class DynInstPtr> 744void 745Checker<DynInstPtr>::validateInst(DynInstPtr &inst) 746{ 747 if (inst->readPC() != cpuXC->readPC()) { 748 warn("PCs do not match! Inst: %#x, checker: %#x", 749 inst->readPC(), cpuXC->readPC()); 750 if (changedPC) { 751 warn("Changed PCs recently, may not be an error"); 752 } else { 753 handleError(); 754 } 755 } 756 757 if (static_cast<MachInst>(inst->staticInst->machInst) != 758 machInst) { 759 warn("Binary instructions do not match! Inst: %#x, checker: %#x", 760 static_cast<MachInst>(inst->staticInst->machInst), 761 machInst); 762 handleError(); 763 } 764} 765 766template <class DynInstPtr> 767void 768Checker<DynInstPtr>::validateExecution(DynInstPtr &inst) 769{ 770 if (inst->numDestRegs()) { 771 if (inst->isUnverifiable()) { 772 // @todo: Support more destination registers. 773 // Grab the result from the instruction and write it to the 774 // register. 775 RegIndex idx = inst->destRegIdx(0); 776 if (idx < TheISA::FP_Base_DepTag) { 777 cpuXC->setIntReg(idx, inst->readIntResult()); 778 } else if (idx < TheISA::Fpcr_DepTag) { 779 cpuXC->setFloatRegInt(idx, inst->readIntResult()); 780 } else { 781 cpuXC->setMiscReg(idx, inst->readIntResult()); 782 } 783 } else if (result.integer != inst->readIntResult()) { 784 warn("Instruction results do not match! (May not be integer results) " 785 "Inst: %#x, checker: %#x", 786 inst->readIntResult(), result.integer); 787 handleError(); 788 } 789 } 790 791 if (inst->readNextPC() != cpuXC->readNextPC()) { 792 warn("Instruction next PCs do not match! Inst: %#x, checker: %#x", 793 inst->readNextPC(), cpuXC->readNextPC()); 794 handleError(); 795 } 796 797 // Checking side effect registers can be difficult if they are not 798 // checked simultaneously with the execution of the instruction. 799 // This is because other valid instructions may have modified 800 // these registers in the meantime, and their values are not 801 // stored within the DynInst. 802 while (!miscRegIdxs.empty()) { 803 int misc_reg_idx = miscRegIdxs.front(); 804 miscRegIdxs.pop(); 805 806 if (inst->xcBase()->readMiscReg(misc_reg_idx) != 807 cpuXC->readMiscReg(misc_reg_idx)) { 808 warn("Misc reg idx %i (side effect) does not match! Inst: %#x, " 809 "checker: %#x", 810 misc_reg_idx, inst->xcBase()->readMiscReg(misc_reg_idx), 811 cpuXC->readMiscReg(misc_reg_idx)); 812 handleError(); 813 } 814 } 815} 816 817template <class DynInstPtr> 818void 819Checker<DynInstPtr>::validateState() 820{ 821} 822 823template <class DynInstPtr> 824void 825Checker<DynInstPtr>::dumpInsts() 826{ 827 int num = 0; 828 829 InstListIt inst_list_it = --(instList.end()); 830 831 cprintf("Inst list size: %i\n", instList.size()); 832 833 while (inst_list_it != instList.end()) 834 { 835 cprintf("Instruction:%i\n", 836 num); 837 838 cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" 839 "Completed:%i\n", 840 (*inst_list_it)->readPC(), 841 (*inst_list_it)->seqNum, 842 (*inst_list_it)->threadNumber, 843 (*inst_list_it)->isCompleted()); 844 845 cprintf("\n"); 846 847 inst_list_it--; 848 ++num; 849 } 850 851} 852 853template 854class Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >; 855 856template 857class Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >; 858