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.
28 * Authors: Steve Reinhardt
31 #include "arch/utility.hh"
32 #include "cpu/exetrace.hh"
33 #include "cpu/simple/timing.hh"
34 #include "mem/packet_impl.hh"
35 #include "sim/builder.hh"
38 using namespace TheISA
;
42 TimingSimpleCPU::init()
44 //Create Memory Ports (conect them up)
45 Port
*mem_dport
= mem
->getPort("");
46 dcachePort
.setPeer(mem_dport
);
47 mem_dport
->setPeer(&dcachePort
);
49 Port
*mem_iport
= mem
->getPort("");
50 icachePort
.setPeer(mem_iport
);
51 mem_iport
->setPeer(&icachePort
);
55 for (int i
= 0; i
< threadContexts
.size(); ++i
) {
56 ThreadContext
*tc
= threadContexts
[i
];
58 // initialize CPU, including PC
59 TheISA::initCPU(tc
, tc
->readCpuId());
65 TimingSimpleCPU::CpuPort::recvAtomic(Packet
*pkt
)
67 panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
72 TimingSimpleCPU::CpuPort::recvFunctional(Packet
*pkt
)
74 panic("TimingSimpleCPU doesn't expect recvFunctional callback!");
78 TimingSimpleCPU::CpuPort::recvStatusChange(Status status
)
80 if (status
== RangeChange
)
83 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
86 TimingSimpleCPU::TimingSimpleCPU(Params
*p
)
87 : BaseSimpleCPU(p
), icachePort(this), dcachePort(this)
90 ifetch_pkt
= dcache_pkt
= NULL
;
94 TimingSimpleCPU::~TimingSimpleCPU()
99 TimingSimpleCPU::serialize(ostream
&os
)
101 BaseSimpleCPU::serialize(os
);
102 SERIALIZE_ENUM(_status
);
106 TimingSimpleCPU::unserialize(Checkpoint
*cp
, const string
§ion
)
108 BaseSimpleCPU::unserialize(cp
, section
);
109 UNSERIALIZE_ENUM(_status
);
113 TimingSimpleCPU::switchOut(Sampler
*s
)
116 if (status() == Running
) {
117 _status
= SwitchedOut
;
119 sampler
->signalSwitched();
124 TimingSimpleCPU::takeOverFrom(BaseCPU
*oldCPU
)
126 BaseCPU::takeOverFrom(oldCPU
);
128 // if any of this CPU's ThreadContexts are active, mark the CPU as
129 // running and schedule its tick event.
130 for (int i
= 0; i
< threadContexts
.size(); ++i
) {
131 ThreadContext
*tc
= threadContexts
[i
];
132 if (tc
->status() == ThreadContext::Active
&& _status
!= Running
) {
141 TimingSimpleCPU::activateContext(int thread_num
, int delay
)
143 assert(thread_num
== 0);
146 assert(_status
== Idle
);
150 // kick things off by initiating the fetch of the next instruction
152 new EventWrapper
<TimingSimpleCPU
, &TimingSimpleCPU::fetch
>(this, true);
153 e
->schedule(curTick
+ cycles(delay
));
158 TimingSimpleCPU::suspendContext(int thread_num
)
160 assert(thread_num
== 0);
163 assert(_status
== Running
);
165 // just change status to Idle... if status != Running,
166 // completeInst() will not initiate fetch of next instruction.
175 TimingSimpleCPU::read(Addr addr
, T
&data
, unsigned flags
)
177 // need to fill in CPU & thread IDs here
178 Request
*data_read_req
= new Request();
180 data_read_req
->setVirt(0, addr
, sizeof(T
), flags
, cpuXC
->readPC());
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 // need to fill in CPU & thread IDs here
259 Request
*data_write_req
= new Request();
260 data_write_req
->setVirt(0, addr
, sizeof(T
), flags
, cpuXC
->readPC());
262 // translate to physical address
263 Fault fault
= cpuXC
->translateDataWriteReq(data_write_req
);
264 // Now do the access.
265 if (fault
== NoFault
) {
266 Packet
*data_write_pkt
=
267 new Packet(data_write_req
, Packet::WriteReq
, Packet::Broadcast
);
268 data_write_pkt
->allocate();
269 data_write_pkt
->set(data
);
271 if (!dcachePort
.sendTiming(data_write_pkt
)) {
272 _status
= DcacheRetry
;
273 dcache_pkt
= data_write_pkt
;
275 _status
= DcacheWaitResponse
;
280 // This will need a new way to tell if it's hooked up to a cache or not.
281 if (data_write_req
->getFlags() & UNCACHEABLE
)
282 recordEvent("Uncached Write");
284 // If the write needs to have a fault on the access, consider calling
285 // changeStatus() and changing it to "bad addr write" or something.
290 #ifndef DOXYGEN_SHOULD_SKIP_THIS
293 TimingSimpleCPU::write(uint64_t data
, Addr addr
,
294 unsigned flags
, uint64_t *res
);
298 TimingSimpleCPU::write(uint32_t data
, Addr addr
,
299 unsigned flags
, uint64_t *res
);
303 TimingSimpleCPU::write(uint16_t data
, Addr addr
,
304 unsigned flags
, uint64_t *res
);
308 TimingSimpleCPU::write(uint8_t data
, Addr addr
,
309 unsigned flags
, uint64_t *res
);
311 #endif //DOXYGEN_SHOULD_SKIP_THIS
315 TimingSimpleCPU::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
317 return write(*(uint64_t*)&data
, addr
, flags
, res
);
322 TimingSimpleCPU::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
324 return write(*(uint32_t*)&data
, addr
, flags
, res
);
330 TimingSimpleCPU::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
332 return write((uint32_t)data
, addr
, flags
, res
);
337 TimingSimpleCPU::fetch()
339 checkForInterrupts();
341 // need to fill in CPU & thread IDs here
342 Request
*ifetch_req
= new Request();
343 Fault fault
= setupFetchRequest(ifetch_req
);
345 ifetch_pkt
= new Packet(ifetch_req
, Packet::ReadReq
, Packet::Broadcast
);
346 ifetch_pkt
->dataStatic(&inst
);
348 if (fault
== NoFault
) {
349 if (!icachePort
.sendTiming(ifetch_pkt
)) {
350 // Need to wait for retry
351 _status
= IcacheRetry
;
353 // Need to wait for cache to respond
354 _status
= IcacheWaitResponse
;
355 // ownership of packet transferred to memory system
359 // fetch fault: advance directly to next instruction (fault handler)
366 TimingSimpleCPU::advanceInst(Fault fault
)
370 if (_status
== Running
) {
371 // kick off fetch of next instruction... callback from icache
372 // response will cause that instruction to be executed,
373 // keeping the CPU running.
380 TimingSimpleCPU::completeIfetch(Packet
*pkt
)
382 // received a response from the icache: execute the received
384 assert(pkt
->result
== Packet::Success
);
385 assert(_status
== IcacheWaitResponse
);
392 if (curStaticInst
->isMemRef() && !curStaticInst
->isDataPrefetch()) {
393 // load or store: just send to dcache
394 Fault fault
= curStaticInst
->initiateAcc(this, traceData
);
395 if (fault
== NoFault
) {
396 // successfully initiated access: instruction will
397 // complete in dcache response callback
398 assert(_status
== DcacheWaitResponse
);
400 // fault: complete now to invoke fault handler
405 // non-memory instruction: execute completely now
406 Fault fault
= curStaticInst
->execute(this, traceData
);
414 TimingSimpleCPU::IcachePort::recvTiming(Packet
*pkt
)
416 cpu
->completeIfetch(pkt
);
421 TimingSimpleCPU::IcachePort::recvRetry()
423 // we shouldn't get a retry unless we have a packet that we're
424 // waiting to transmit
425 assert(cpu
->ifetch_pkt
!= NULL
);
426 assert(cpu
->_status
== IcacheRetry
);
427 Packet
*tmp
= cpu
->ifetch_pkt
;
428 if (sendTiming(tmp
)) {
429 cpu
->_status
= IcacheWaitResponse
;
430 cpu
->ifetch_pkt
= NULL
;
435 TimingSimpleCPU::completeDataAccess(Packet
*pkt
)
437 // received a response from the dcache: complete the load or store
439 assert(pkt
->result
== Packet::Success
);
440 assert(_status
== DcacheWaitResponse
);
443 Fault fault
= curStaticInst
->completeAcc(pkt
, this, traceData
);
455 TimingSimpleCPU::DcachePort::recvTiming(Packet
*pkt
)
457 cpu
->completeDataAccess(pkt
);
462 TimingSimpleCPU::DcachePort::recvRetry()
464 // we shouldn't get a retry unless we have a packet that we're
465 // waiting to transmit
466 assert(cpu
->dcache_pkt
!= NULL
);
467 assert(cpu
->_status
== DcacheRetry
);
468 Packet
*tmp
= cpu
->dcache_pkt
;
469 if (sendTiming(tmp
)) {
470 cpu
->_status
= DcacheWaitResponse
;
471 cpu
->dcache_pkt
= NULL
;
476 ////////////////////////////////////////////////////////////////////////
478 // TimingSimpleCPU Simulation Object
480 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
482 Param
<Counter
> max_insts_any_thread
;
483 Param
<Counter
> max_insts_all_threads
;
484 Param
<Counter
> max_loads_any_thread
;
485 Param
<Counter
> max_loads_all_threads
;
486 SimObjectParam
<MemObject
*> mem
;
489 SimObjectParam
<AlphaITB
*> itb
;
490 SimObjectParam
<AlphaDTB
*> dtb
;
491 SimObjectParam
<System
*> system
;
495 SimObjectParam
<Process
*> workload
;
496 #endif // FULL_SYSTEM
500 Param
<bool> defer_registration
;
502 Param
<bool> function_trace
;
503 Param
<Tick
> function_trace_start
;
504 Param
<bool> simulate_stalls
;
506 END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
508 BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
510 INIT_PARAM(max_insts_any_thread
,
511 "terminate when any thread reaches this inst count"),
512 INIT_PARAM(max_insts_all_threads
,
513 "terminate when all threads have reached this inst count"),
514 INIT_PARAM(max_loads_any_thread
,
515 "terminate when any thread reaches this load count"),
516 INIT_PARAM(max_loads_all_threads
,
517 "terminate when all threads have reached this load count"),
518 INIT_PARAM(mem
, "memory"),
521 INIT_PARAM(itb
, "Instruction TLB"),
522 INIT_PARAM(dtb
, "Data TLB"),
523 INIT_PARAM(system
, "system object"),
524 INIT_PARAM(cpu_id
, "processor ID"),
525 INIT_PARAM(profile
, ""),
527 INIT_PARAM(workload
, "processes to run"),
528 #endif // FULL_SYSTEM
530 INIT_PARAM(clock
, "clock speed"),
531 INIT_PARAM(defer_registration
, "defer system registration (for sampling)"),
532 INIT_PARAM(width
, "cpu width"),
533 INIT_PARAM(function_trace
, "Enable function trace"),
534 INIT_PARAM(function_trace_start
, "Cycle to start function trace"),
535 INIT_PARAM(simulate_stalls
, "Simulate cache stall cycles")
537 END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
540 CREATE_SIM_OBJECT(TimingSimpleCPU
)
542 TimingSimpleCPU::Params
*params
= new TimingSimpleCPU::Params();
543 params
->name
= getInstanceName();
544 params
->numberOfThreads
= 1;
545 params
->max_insts_any_thread
= max_insts_any_thread
;
546 params
->max_insts_all_threads
= max_insts_all_threads
;
547 params
->max_loads_any_thread
= max_loads_any_thread
;
548 params
->max_loads_all_threads
= max_loads_all_threads
;
549 params
->deferRegistration
= defer_registration
;
550 params
->clock
= clock
;
551 params
->functionTrace
= function_trace
;
552 params
->functionTraceStart
= function_trace_start
;
558 params
->system
= system
;
559 params
->cpu_id
= cpu_id
;
560 params
->profile
= profile
;
562 params
->process
= workload
;
565 TimingSimpleCPU
*cpu
= new TimingSimpleCPU(params
);
569 REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU
)