pc_event.cc revision 76
18889Sgeoffrey.blake@arm.com/*
28889Sgeoffrey.blake@arm.com * Copyright (c) 2003 The Regents of The University of Michigan
38889Sgeoffrey.blake@arm.com * All rights reserved.
48889Sgeoffrey.blake@arm.com *
58889Sgeoffrey.blake@arm.com * Redistribution and use in source and binary forms, with or without
68889Sgeoffrey.blake@arm.com * modification, are permitted provided that the following conditions are
78889Sgeoffrey.blake@arm.com * met: redistributions of source code must retain the above copyright
88889Sgeoffrey.blake@arm.com * notice, this list of conditions and the following disclaimer;
98889Sgeoffrey.blake@arm.com * redistributions in binary form must reproduce the above copyright
108889Sgeoffrey.blake@arm.com * notice, this list of conditions and the following disclaimer in the
118889Sgeoffrey.blake@arm.com * documentation and/or other materials provided with the distribution;
128889Sgeoffrey.blake@arm.com * neither the name of the copyright holders nor the names of its
138889Sgeoffrey.blake@arm.com * contributors may be used to endorse or promote products derived from
148889Sgeoffrey.blake@arm.com * this software without specific prior written permission.
158889Sgeoffrey.blake@arm.com *
168889Sgeoffrey.blake@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
178889Sgeoffrey.blake@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
188889Sgeoffrey.blake@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
198889Sgeoffrey.blake@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
208889Sgeoffrey.blake@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
218889Sgeoffrey.blake@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
228889Sgeoffrey.blake@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
238889Sgeoffrey.blake@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
248889Sgeoffrey.blake@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258889Sgeoffrey.blake@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
268889Sgeoffrey.blake@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278889Sgeoffrey.blake@arm.com */
288889Sgeoffrey.blake@arm.com
298889Sgeoffrey.blake@arm.com#include <algorithm>
308889Sgeoffrey.blake@arm.com#include <map>
318889Sgeoffrey.blake@arm.com#include <string>
328889Sgeoffrey.blake@arm.com#include <utility>
338889Sgeoffrey.blake@arm.com
348889Sgeoffrey.blake@arm.com#include "sim/debug.hh"
358889Sgeoffrey.blake@arm.com#include "cpu/exec_context.hh"
368889Sgeoffrey.blake@arm.com#include "cpu/pc_event.hh"
378889Sgeoffrey.blake@arm.com#include "base/trace.hh"
388889Sgeoffrey.blake@arm.com#include "sim/universe.hh"
398889Sgeoffrey.blake@arm.com
408889Sgeoffrey.blake@arm.com#ifdef FULL_SYSTEM
418889Sgeoffrey.blake@arm.com#include "targetarch/arguments.hh"
428889Sgeoffrey.blake@arm.com#include "targetarch/pmap.h"
438889Sgeoffrey.blake@arm.com#include "mem/functional_mem/memory_control.hh"
448889Sgeoffrey.blake@arm.com#include "cpu/full_cpu/cpu.hh"
458889Sgeoffrey.blake@arm.com#include "sim/system.hh"
468889Sgeoffrey.blake@arm.com#include "cpu/full_cpu/bpred.hh"
478889Sgeoffrey.blake@arm.com#endif
488889Sgeoffrey.blake@arm.com
498889Sgeoffrey.blake@arm.comusing namespace std;
508889Sgeoffrey.blake@arm.com
518889Sgeoffrey.blake@arm.comPCEventQueue::PCEventQueue()
528889Sgeoffrey.blake@arm.com{}
538889Sgeoffrey.blake@arm.com
548889Sgeoffrey.blake@arm.comPCEventQueue::~PCEventQueue()
558889Sgeoffrey.blake@arm.com{}
568889Sgeoffrey.blake@arm.com
578889Sgeoffrey.blake@arm.combool
588889Sgeoffrey.blake@arm.comPCEventQueue::remove(PCEvent *event)
598889Sgeoffrey.blake@arm.com{
608889Sgeoffrey.blake@arm.com    int removed = 0;
618889Sgeoffrey.blake@arm.com    range_t range = equal_range(event);
628889Sgeoffrey.blake@arm.com    for (iterator i = range.first; i != range.second; ++i) {
638889Sgeoffrey.blake@arm.com        if (*i == event) {
648889Sgeoffrey.blake@arm.com            DPRINTF(PCEvent, "PC based event removed at %#x: %s\n",
658889Sgeoffrey.blake@arm.com                    event->pc(), event->descr());
668889Sgeoffrey.blake@arm.com            pc_map.erase(i);
678889Sgeoffrey.blake@arm.com            ++removed;
688889Sgeoffrey.blake@arm.com        }
698889Sgeoffrey.blake@arm.com    }
708889Sgeoffrey.blake@arm.com
718889Sgeoffrey.blake@arm.com    return removed > 0;
728889Sgeoffrey.blake@arm.com}
738889Sgeoffrey.blake@arm.com
748889Sgeoffrey.blake@arm.combool
758889Sgeoffrey.blake@arm.comPCEventQueue::schedule(PCEvent *event)
768889Sgeoffrey.blake@arm.com{
778889Sgeoffrey.blake@arm.com    pc_map.push_back(event);
788889Sgeoffrey.blake@arm.com    sort(pc_map.begin(), pc_map.end(), MapCompare());
798889Sgeoffrey.blake@arm.com
808889Sgeoffrey.blake@arm.com    DPRINTF(PCEvent, "PC based event scheduled for %#x: %s\n",
818889Sgeoffrey.blake@arm.com            event->pc(), event->descr());
828889Sgeoffrey.blake@arm.com
838889Sgeoffrey.blake@arm.com    return true;
848889Sgeoffrey.blake@arm.com}
858889Sgeoffrey.blake@arm.com
868889Sgeoffrey.blake@arm.combool
878889Sgeoffrey.blake@arm.comPCEventQueue::doService(ExecContext *xc)
888889Sgeoffrey.blake@arm.com{
898889Sgeoffrey.blake@arm.com    Addr pc = xc->regs.pc;
908889Sgeoffrey.blake@arm.com    int serviced = 0;
918889Sgeoffrey.blake@arm.com    range_t range = equal_range(pc);
928889Sgeoffrey.blake@arm.com    for (iterator i = range.first; i != range.second; ++i) {
938889Sgeoffrey.blake@arm.com        // Make sure that the pc wasn't changed as the side effect of
948889Sgeoffrey.blake@arm.com        // another event.  This for example, prevents two invocations
958889Sgeoffrey.blake@arm.com        // of the SkipFuncEvent.  Maybe we should have separate PC
968889Sgeoffrey.blake@arm.com        // event queues for each processor?
978889Sgeoffrey.blake@arm.com        if (pc != xc->regs.pc)
988889Sgeoffrey.blake@arm.com            continue;
998889Sgeoffrey.blake@arm.com
1008889Sgeoffrey.blake@arm.com        DPRINTF(PCEvent, "PC based event serviced at %#x: %s\n",
1018889Sgeoffrey.blake@arm.com                (*i)->pc(), (*i)->descr());
1028889Sgeoffrey.blake@arm.com
1038889Sgeoffrey.blake@arm.com        (*i)->process(xc);
1048889Sgeoffrey.blake@arm.com        ++serviced;
1058889Sgeoffrey.blake@arm.com    }
1068889Sgeoffrey.blake@arm.com
1078889Sgeoffrey.blake@arm.com    return serviced > 0;
1088889Sgeoffrey.blake@arm.com}
1098889Sgeoffrey.blake@arm.com
1108889Sgeoffrey.blake@arm.comvoid
1118889Sgeoffrey.blake@arm.comPCEventQueue::dump() const
1128889Sgeoffrey.blake@arm.com{
1138889Sgeoffrey.blake@arm.com    const_iterator i = pc_map.begin();
1148889Sgeoffrey.blake@arm.com    const_iterator e = pc_map.end();
1158889Sgeoffrey.blake@arm.com
1168889Sgeoffrey.blake@arm.com    for (; i != e; ++i)
1178889Sgeoffrey.blake@arm.com        cprintf("%d: event at %#x: %s\n", curTick, (*i)->pc(),
1188889Sgeoffrey.blake@arm.com                (*i)->descr());
1198889Sgeoffrey.blake@arm.com}
1208889Sgeoffrey.blake@arm.com
1218889Sgeoffrey.blake@arm.comPCEventQueue::range_t
1228889Sgeoffrey.blake@arm.comPCEventQueue::equal_range(Addr pc)
1238889Sgeoffrey.blake@arm.com{
1248889Sgeoffrey.blake@arm.com    return std::equal_range(pc_map.begin(), pc_map.end(), pc, MapCompare());
1258889Sgeoffrey.blake@arm.com}
1268889Sgeoffrey.blake@arm.com
1278889Sgeoffrey.blake@arm.com#ifdef FULL_SYSTEM
1288889Sgeoffrey.blake@arm.comvoid
1298889Sgeoffrey.blake@arm.comSkipFuncEvent::process(ExecContext *xc)
1308889Sgeoffrey.blake@arm.com{
1318889Sgeoffrey.blake@arm.com    Addr newpc = xc->regs.intRegFile[ReturnAddressReg];
1328889Sgeoffrey.blake@arm.com
1338889Sgeoffrey.blake@arm.com    DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description,
1348889Sgeoffrey.blake@arm.com            xc->regs.pc, newpc);
1358889Sgeoffrey.blake@arm.com
136    xc->regs.pc = newpc;
137    xc->regs.npc = xc->regs.pc + sizeof(MachInst);
138
139    BranchPred *bp = xc->cpu->getBranchPred();
140    if (bp != NULL) {
141        bp->popRAS(xc->thread_num);
142    }
143}
144
145void
146BadAddrEvent::process(ExecContext *xc)
147{
148    // The following gross hack is the equivalent function to the
149    // annotation for vmunix::badaddr in:
150    // simos/simulation/apps/tcl/osf/tlaser.tcl
151
152    uint64_t a0 = xc->regs.intRegFile[ArgumentReg0];
153
154    if (a0 < ALPHA_K0SEG_BASE || a0 >= ALPHA_K1SEG_BASE ||
155        xc->memCtrl->badaddr(ALPHA_K0SEG_TO_PHYS(a0) & PA_IMPL_MASK)) {
156
157        DPRINTF(BADADDR, "badaddr arg=%#x bad\n", a0);
158        xc->regs.intRegFile[ReturnValueReg] = 0x1;
159        SkipFuncEvent::process(xc);
160    }
161    else
162        DPRINTF(BADADDR, "badaddr arg=%#x good\n", a0);
163}
164
165void Printf(AlphaArguments args);
166void DumpMbuf(AlphaArguments args);
167
168void
169PrintfEvent::process(ExecContext *xc)
170{
171    if (DTRACE(Printf)) {
172        DebugOut() << curTick << ": " << xc->cpu->name() << ": ";
173
174        AlphaArguments args(xc);
175        Printf(args);
176    }
177}
178
179void
180DebugPrintfEvent::process(ExecContext *xc)
181{
182    if (DTRACE(DebugPrintf)) {
183        if (!raw)
184            DebugOut() << curTick << ": " << xc->cpu->name() << ": ";
185
186        AlphaArguments args(xc);
187        Printf(args);
188    }
189}
190
191void
192DumpMbufEvent::process(ExecContext *xc)
193{
194    if (DTRACE(DebugPrintf)) {
195        AlphaArguments args(xc);
196        DumpMbuf(args);
197    }
198}
199#endif
200
201BreakPCEvent::BreakPCEvent(PCEventQueue *q, const std::string &desc, bool del)
202    : PCEvent(q, desc), remove(del)
203{
204}
205
206void
207BreakPCEvent::process(ExecContext *xc)
208{
209    debug_break();
210    if (remove)
211        delete this;
212}
213
214#ifdef FULL_SYSTEM
215extern "C"
216void
217sched_break_pc_sys(System *sys, Addr addr)
218{
219    PCEvent *event = new BreakPCEvent(&sys->pcEventQueue, "debug break", true);
220    event->schedule(addr);
221}
222
223extern "C"
224void
225sched_break_pc(Addr addr)
226{
227     for (vector<System *>::iterator sysi = System::systemList.begin();
228          sysi != System::systemList.end(); ++sysi) {
229         sched_break_pc_sys(*sysi, addr);
230    }
231
232}
233#endif
234