2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
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.
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.
29 #include "arch/utility.hh"
30 #include "cpu/exetrace.hh"
31 #include "cpu/simple/timing.hh"
32 #include "mem/packet_impl.hh"
33 #include "sim/builder.hh"
36 using namespace TheISA
;
40 TimingSimpleCPU::init()
42 //Create Memory Ports (conect them up)
43 Port
*mem_dport
= mem
->getPort("");
44 dcachePort
.setPeer(mem_dport
);
45 mem_dport
->setPeer(&dcachePort
);
47 Port
*mem_iport
= mem
->getPort("");
48 icachePort
.setPeer(mem_iport
);
49 mem_iport
->setPeer(&icachePort
);
53 for (int i
= 0; i
< execContexts
.size(); ++i
) {
54 ExecContext
*xc
= execContexts
[i
];
56 // initialize CPU, including PC
57 TheISA::initCPU(xc
, xc
->readCpuId());
63 TimingSimpleCPU::CpuPort::recvAtomic(Packet
*pkt
)
65 panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
70 TimingSimpleCPU::CpuPort::recvFunctional(Packet
*pkt
)
72 panic("TimingSimpleCPU doesn't expect recvFunctional callback!");
76 TimingSimpleCPU::CpuPort::recvStatusChange(Status status
)
78 if (status
== RangeChange
)
81 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
84 TimingSimpleCPU::TimingSimpleCPU(Params
*p
)
85 : BaseSimpleCPU(p
), icachePort(this), dcachePort(this)
88 ifetch_pkt
= dcache_pkt
= NULL
;
92 TimingSimpleCPU::~TimingSimpleCPU()
97 TimingSimpleCPU::serialize(ostream
&os
)
99 BaseSimpleCPU::serialize(os
);
100 SERIALIZE_ENUM(_status
);
104 TimingSimpleCPU::unserialize(Checkpoint
*cp
, const string
§ion
)
106 BaseSimpleCPU::unserialize(cp
, section
);
107 UNSERIALIZE_ENUM(_status
);
111 TimingSimpleCPU::switchOut(Sampler
*s
)
114 if (status() == Running
) {
115 _status
= SwitchedOut
;
117 sampler
->signalSwitched();
122 TimingSimpleCPU::takeOverFrom(BaseCPU
*oldCPU
)
124 BaseCPU::takeOverFrom(oldCPU
);
126 // if any of this CPU's ExecContexts are active, mark the CPU as
127 // running and schedule its tick event.
128 for (int i
= 0; i
< execContexts
.size(); ++i
) {
129 ExecContext
*xc
= execContexts
[i
];
130 if (xc
->status() == ExecContext::Active
&& _status
!= Running
) {
139 TimingSimpleCPU::activateContext(int thread_num
, int delay
)
141 assert(thread_num
== 0);
144 assert(_status
== Idle
);
148 // kick things off by initiating the fetch of the next instruction
150 new EventWrapper
<TimingSimpleCPU
, &TimingSimpleCPU::fetch
>(this, true);
151 e
->schedule(curTick
+ cycles(delay
));
156 TimingSimpleCPU::suspendContext(int thread_num
)
158 assert(thread_num
== 0);
161 assert(_status
== Running
);
163 // just change status to Idle... if status != Running,
164 // completeInst() will not initiate fetch of next instruction.
173 TimingSimpleCPU::read(Addr addr
, T
&data
, unsigned flags
)
175 Request
*data_read_req
= new Request(true);
177 data_read_req
->setVaddr(addr
);
178 data_read_req
->setSize(sizeof(T
));
179 data_read_req
->setFlags(flags
);
180 data_read_req
->setTime(curTick
);
183 traceData
->setAddr(data_read_req
->getVaddr());
186 // translate to physical address
187 Fault fault
= cpuXC
->translateDataReadReq(data_read_req
);
189 // Now do the access.
190 if (fault
== NoFault
) {
191 Packet
*data_read_pkt
=
192 new Packet(data_read_req
, Packet::ReadReq
, Packet::Broadcast
);
193 data_read_pkt
->dataDynamic
<T
>(new T
);
195 if (!dcachePort
.sendTiming(data_read_pkt
)) {
196 _status
= DcacheRetry
;
197 dcache_pkt
= data_read_pkt
;
199 _status
= DcacheWaitResponse
;
204 // This will need a new way to tell if it has a dcache attached.
205 if (data_read_req
->getFlags() & UNCACHEABLE
)
206 recordEvent("Uncached Read");
211 #ifndef DOXYGEN_SHOULD_SKIP_THIS
215 TimingSimpleCPU::read(Addr addr
, uint64_t &data
, unsigned flags
);
219 TimingSimpleCPU::read(Addr addr
, uint32_t &data
, unsigned flags
);
223 TimingSimpleCPU::read(Addr addr
, uint16_t &data
, unsigned flags
);
227 TimingSimpleCPU::read(Addr addr
, uint8_t &data
, unsigned flags
);
229 #endif //DOXYGEN_SHOULD_SKIP_THIS
233 TimingSimpleCPU::read(Addr addr
, double &data
, unsigned flags
)
235 return read(addr
, *(uint64_t*)&data
, flags
);
240 TimingSimpleCPU::read(Addr addr
, float &data
, unsigned flags
)
242 return read(addr
, *(uint32_t*)&data
, flags
);
248 TimingSimpleCPU::read(Addr addr
, int32_t &data
, unsigned flags
)
250 return read(addr
, (uint32_t&)data
, flags
);
256 TimingSimpleCPU::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
258 Request
*data_write_req
= new Request(true);
259 data_write_req
->setVaddr(addr
);
260 data_write_req
->setTime(curTick
);
261 data_write_req
->setSize(sizeof(T
));
262 data_write_req
->setFlags(flags
);
264 // translate to physical address
265 Fault fault
= cpuXC
->translateDataWriteReq(data_write_req
);
266 // Now do the access.
267 if (fault
== NoFault
) {
268 Packet
*data_write_pkt
=
269 new Packet(data_write_req
, Packet::WriteReq
, Packet::Broadcast
);
270 data_write_pkt
->allocate();
271 data_write_pkt
->set(data
);
273 if (!dcachePort
.sendTiming(data_write_pkt
)) {
274 _status
= DcacheRetry
;
275 dcache_pkt
= data_write_pkt
;
277 _status
= DcacheWaitResponse
;
282 // This will need a new way to tell if it's hooked up to a cache or not.
283 if (data_write_req
->getFlags() & UNCACHEABLE
)
284 recordEvent("Uncached Write");
286 // If the write needs to have a fault on the access, consider calling
287 // changeStatus() and changing it to "bad addr write" or something.
292 #ifndef DOXYGEN_SHOULD_SKIP_THIS
295 TimingSimpleCPU::write(uint64_t data
, Addr addr
,
296 unsigned flags
, uint64_t *res
);
300 TimingSimpleCPU::write(uint32_t data
, Addr addr
,
301 unsigned flags
, uint64_t *res
);
305 TimingSimpleCPU::write(uint16_t data
, Addr addr
,
306 unsigned flags
, uint64_t *res
);
310 TimingSimpleCPU::write(uint8_t data
, Addr addr
,
311 unsigned flags
, uint64_t *res
);
313 #endif //DOXYGEN_SHOULD_SKIP_THIS
317 TimingSimpleCPU::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
319 return write(*(uint64_t*)&data
, addr
, flags
, res
);
324 TimingSimpleCPU::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
326 return write(*(uint32_t*)&data
, addr
, flags
, res
);
332 TimingSimpleCPU::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
334 return write((uint32_t)data
, addr
, flags
, res
);
339 TimingSimpleCPU::fetch()
341 checkForInterrupts();
343 Request
*ifetch_req
= new Request(true);
344 ifetch_req
->setSize(sizeof(MachInst
));
345 Fault fault
= setupFetchRequest(ifetch_req
);
347 ifetch_pkt
= new Packet(ifetch_req
, Packet::ReadReq
, Packet::Broadcast
);
348 ifetch_pkt
->dataStatic(&inst
);
350 if (fault
== NoFault
) {
351 if (!icachePort
.sendTiming(ifetch_pkt
)) {
352 // Need to wait for retry
353 _status
= IcacheRetry
;
355 // Need to wait for cache to respond
356 _status
= IcacheWaitResponse
;
357 // ownership of packet transferred to memory system
361 // fetch fault: advance directly to next instruction (fault handler)
368 TimingSimpleCPU::advanceInst(Fault fault
)
372 if (_status
== Running
) {
373 // kick off fetch of next instruction... callback from icache
374 // response will cause that instruction to be executed,
375 // keeping the CPU running.
382 TimingSimpleCPU::completeIfetch(Packet
*pkt
)
384 // received a response from the icache: execute the received
386 assert(pkt
->result
== Packet::Success
);
387 assert(_status
== IcacheWaitResponse
);
394 if (curStaticInst
->isMemRef() && !curStaticInst
->isDataPrefetch()) {
395 // load or store: just send to dcache
396 Fault fault
= curStaticInst
->initiateAcc(this, traceData
);
397 if (fault
== NoFault
) {
398 // successfully initiated access: instruction will
399 // complete in dcache response callback
400 assert(_status
== DcacheWaitResponse
);
402 // fault: complete now to invoke fault handler
407 // non-memory instruction: execute completely now
408 Fault fault
= curStaticInst
->execute(this, traceData
);
416 TimingSimpleCPU::IcachePort::recvTiming(Packet
*pkt
)
418 cpu
->completeIfetch(pkt
);
423 TimingSimpleCPU::IcachePort::recvRetry()
425 // we shouldn't get a retry unless we have a packet that we're
426 // waiting to transmit
427 assert(cpu
->ifetch_pkt
!= NULL
);
428 assert(cpu
->_status
== IcacheRetry
);
429 Packet
*tmp
= cpu
->ifetch_pkt
;
430 if (sendTiming(tmp
)) {
431 cpu
->_status
= IcacheWaitResponse
;
432 cpu
->ifetch_pkt
= NULL
;
437 TimingSimpleCPU::completeDataAccess(Packet
*pkt
)
439 // received a response from the dcache: complete the load or store
441 assert(pkt
->result
== Packet::Success
);
442 assert(_status
== DcacheWaitResponse
);
445 Fault fault
= curStaticInst
->completeAcc(pkt
, this, traceData
);
457 TimingSimpleCPU::DcachePort::recvTiming(Packet
*pkt
)
459 cpu
->completeDataAccess(pkt
);
464 TimingSimpleCPU::DcachePort::recvRetry()
466 // we shouldn't get a retry unless we have a packet that we're
467 // waiting to transmit
468 assert(cpu
->dcache_pkt
!= NULL
);
469 assert(cpu
->_status
== DcacheRetry
);
470 Packet
*tmp
= cpu
->dcache_pkt
;
471 if (sendTiming(tmp
)) {
472 cpu
->_status
= DcacheWaitResponse
;
473 cpu
->dcache_pkt
= NULL
;
478 ////////////////////////////////////////////////////////////////////////
480 // TimingSimpleCPU Simulation Object
482 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
484 Param
<Counter
> max_insts_any_thread
;
485 Param
<Counter
> max_insts_all_threads
;
486 Param
<Counter
> max_loads_any_thread
;
487 Param
<Counter
> max_loads_all_threads
;
488 SimObjectParam
<MemObject
*> mem
;
491 SimObjectParam
<AlphaITB
*> itb
;
492 SimObjectParam
<AlphaDTB
*> dtb
;
493 SimObjectParam
<System
*> system
;
497 SimObjectParam
<Process
*> workload
;
498 #endif // FULL_SYSTEM
502 Param
<bool> defer_registration
;
504 Param
<bool> function_trace
;
505 Param
<Tick
> function_trace_start
;
506 Param
<bool> simulate_stalls
;
508 END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
510 BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
512 INIT_PARAM(max_insts_any_thread
,
513 "terminate when any thread reaches this inst count"),
514 INIT_PARAM(max_insts_all_threads
,
515 "terminate when all threads have reached this inst count"),
516 INIT_PARAM(max_loads_any_thread
,
517 "terminate when any thread reaches this load count"),
518 INIT_PARAM(max_loads_all_threads
,
519 "terminate when all threads have reached this load count"),
520 INIT_PARAM(mem
, "memory"),
523 INIT_PARAM(itb
, "Instruction TLB"),
524 INIT_PARAM(dtb
, "Data TLB"),
525 INIT_PARAM(system
, "system object"),
526 INIT_PARAM(cpu_id
, "processor ID"),
527 INIT_PARAM(profile
, ""),
529 INIT_PARAM(workload
, "processes to run"),
530 #endif // FULL_SYSTEM
532 INIT_PARAM(clock
, "clock speed"),
533 INIT_PARAM(defer_registration
, "defer system registration (for sampling)"),
534 INIT_PARAM(width
, "cpu width"),
535 INIT_PARAM(function_trace
, "Enable function trace"),
536 INIT_PARAM(function_trace_start
, "Cycle to start function trace"),
537 INIT_PARAM(simulate_stalls
, "Simulate cache stall cycles")
539 END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
542 CREATE_SIM_OBJECT(TimingSimpleCPU
)
544 TimingSimpleCPU::Params
*params
= new TimingSimpleCPU::Params();
545 params
->name
= getInstanceName();
546 params
->numberOfThreads
= 1;
547 params
->max_insts_any_thread
= max_insts_any_thread
;
548 params
->max_insts_all_threads
= max_insts_all_threads
;
549 params
->max_loads_any_thread
= max_loads_any_thread
;
550 params
->max_loads_all_threads
= max_loads_all_threads
;
551 params
->deferRegistration
= defer_registration
;
552 params
->clock
= clock
;
553 params
->functionTrace
= function_trace
;
554 params
->functionTraceStart
= function_trace_start
;
560 params
->system
= system
;
561 params
->cpu_id
= cpu_id
;
562 params
->profile
= profile
;
564 params
->process
= workload
;
567 TimingSimpleCPU
*cpu
= new TimingSimpleCPU(params
);
571 REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU
)