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
;
92 state
= SimObject::Timing
;
96 TimingSimpleCPU::~TimingSimpleCPU()
101 TimingSimpleCPU::serialize(ostream
&os
)
103 SERIALIZE_ENUM(_status
);
104 BaseSimpleCPU::serialize(os
);
108 TimingSimpleCPU::unserialize(Checkpoint
*cp
, const string
§ion
)
110 UNSERIALIZE_ENUM(_status
);
111 BaseSimpleCPU::unserialize(cp
, section
);
115 TimingSimpleCPU::drain(Event
*drain_event
)
117 // TimingSimpleCPU is ready to drain if it's not waiting for
118 // an access to complete.
119 if (status() == Idle
|| status() == Running
|| status() == SwitchedOut
) {
120 changeState(SimObject::DrainedTiming
);
123 changeState(SimObject::Draining
);
124 drainEvent
= drain_event
;
130 TimingSimpleCPU::resume()
132 if (_status
!= SwitchedOut
&& _status
!= Idle
) {
134 new EventWrapper
<TimingSimpleCPU
, &TimingSimpleCPU::fetch
>(this, true);
135 e
->schedule(curTick
);
140 TimingSimpleCPU::setMemoryMode(State new_mode
)
142 assert(new_mode
== SimObject::Timing
);
146 TimingSimpleCPU::switchOut()
148 assert(status() == Running
|| status() == Idle
);
149 _status
= SwitchedOut
;
154 TimingSimpleCPU::takeOverFrom(BaseCPU
*oldCPU
)
156 BaseCPU::takeOverFrom(oldCPU
);
158 // if any of this CPU's ThreadContexts are active, mark the CPU as
159 // running and schedule its tick event.
160 for (int i
= 0; i
< threadContexts
.size(); ++i
) {
161 ThreadContext
*tc
= threadContexts
[i
];
162 if (tc
->status() == ThreadContext::Active
&& _status
!= Running
) {
171 TimingSimpleCPU::activateContext(int thread_num
, int delay
)
173 assert(thread_num
== 0);
176 assert(_status
== Idle
);
180 // kick things off by initiating the fetch of the next instruction
182 new EventWrapper
<TimingSimpleCPU
, &TimingSimpleCPU::fetch
>(this, true);
183 e
->schedule(curTick
+ cycles(delay
));
188 TimingSimpleCPU::suspendContext(int thread_num
)
190 assert(thread_num
== 0);
193 assert(_status
== Running
);
195 // just change status to Idle... if status != Running,
196 // completeInst() will not initiate fetch of next instruction.
205 TimingSimpleCPU::read(Addr addr
, T
&data
, unsigned flags
)
207 // need to fill in CPU & thread IDs here
208 Request
*data_read_req
= new Request();
209 data_read_req
->setThreadContext(0,0); //Need CPU/Thread IDS HERE
210 data_read_req
->setVirt(0, addr
, sizeof(T
), flags
, thread
->readPC());
213 traceData
->setAddr(data_read_req
->getVaddr());
216 // translate to physical address
217 Fault fault
= thread
->translateDataReadReq(data_read_req
);
219 // Now do the access.
220 if (fault
== NoFault
) {
221 Packet
*data_read_pkt
=
222 new Packet(data_read_req
, Packet::ReadReq
, Packet::Broadcast
);
223 data_read_pkt
->dataDynamic
<T
>(new T
);
225 if (!dcachePort
.sendTiming(data_read_pkt
)) {
226 _status
= DcacheRetry
;
227 dcache_pkt
= data_read_pkt
;
229 _status
= DcacheWaitResponse
;
234 // This will need a new way to tell if it has a dcache attached.
235 if (data_read_req
->getFlags() & UNCACHEABLE
)
236 recordEvent("Uncached Read");
241 #ifndef DOXYGEN_SHOULD_SKIP_THIS
245 TimingSimpleCPU::read(Addr addr
, uint64_t &data
, unsigned flags
);
249 TimingSimpleCPU::read(Addr addr
, uint32_t &data
, unsigned flags
);
253 TimingSimpleCPU::read(Addr addr
, uint16_t &data
, unsigned flags
);
257 TimingSimpleCPU::read(Addr addr
, uint8_t &data
, unsigned flags
);
259 #endif //DOXYGEN_SHOULD_SKIP_THIS
263 TimingSimpleCPU::read(Addr addr
, double &data
, unsigned flags
)
265 return read(addr
, *(uint64_t*)&data
, flags
);
270 TimingSimpleCPU::read(Addr addr
, float &data
, unsigned flags
)
272 return read(addr
, *(uint32_t*)&data
, flags
);
278 TimingSimpleCPU::read(Addr addr
, int32_t &data
, unsigned flags
)
280 return read(addr
, (uint32_t&)data
, flags
);
286 TimingSimpleCPU::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
288 // need to fill in CPU & thread IDs here
289 Request
*data_write_req
= new Request();
290 data_write_req
->setThreadContext(0,0); //Need CPU/Thread IDS HERE
291 data_write_req
->setVirt(0, addr
, sizeof(T
), flags
, thread
->readPC());
293 // translate to physical address
294 Fault fault
= thread
->translateDataWriteReq(data_write_req
);
295 // Now do the access.
296 if (fault
== NoFault
) {
297 Packet
*data_write_pkt
=
298 new Packet(data_write_req
, Packet::WriteReq
, Packet::Broadcast
);
299 data_write_pkt
->allocate();
300 data_write_pkt
->set(data
);
302 if (!dcachePort
.sendTiming(data_write_pkt
)) {
303 _status
= DcacheRetry
;
304 dcache_pkt
= data_write_pkt
;
306 _status
= DcacheWaitResponse
;
311 // This will need a new way to tell if it's hooked up to a cache or not.
312 if (data_write_req
->getFlags() & UNCACHEABLE
)
313 recordEvent("Uncached Write");
315 // If the write needs to have a fault on the access, consider calling
316 // changeStatus() and changing it to "bad addr write" or something.
321 #ifndef DOXYGEN_SHOULD_SKIP_THIS
324 TimingSimpleCPU::write(uint64_t data
, Addr addr
,
325 unsigned flags
, uint64_t *res
);
329 TimingSimpleCPU::write(uint32_t data
, Addr addr
,
330 unsigned flags
, uint64_t *res
);
334 TimingSimpleCPU::write(uint16_t data
, Addr addr
,
335 unsigned flags
, uint64_t *res
);
339 TimingSimpleCPU::write(uint8_t data
, Addr addr
,
340 unsigned flags
, uint64_t *res
);
342 #endif //DOXYGEN_SHOULD_SKIP_THIS
346 TimingSimpleCPU::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
348 return write(*(uint64_t*)&data
, addr
, flags
, res
);
353 TimingSimpleCPU::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
355 return write(*(uint32_t*)&data
, addr
, flags
, res
);
361 TimingSimpleCPU::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
363 return write((uint32_t)data
, addr
, flags
, res
);
368 TimingSimpleCPU::fetch()
370 checkForInterrupts();
372 // need to fill in CPU & thread IDs here
373 Request
*ifetch_req
= new Request();
374 ifetch_req
->setThreadContext(0,0); //Need CPU/Thread IDS HERE
375 Fault fault
= setupFetchRequest(ifetch_req
);
377 ifetch_pkt
= new Packet(ifetch_req
, Packet::ReadReq
, Packet::Broadcast
);
378 ifetch_pkt
->dataStatic(&inst
);
380 if (fault
== NoFault
) {
381 if (!icachePort
.sendTiming(ifetch_pkt
)) {
382 // Need to wait for retry
383 _status
= IcacheRetry
;
385 // Need to wait for cache to respond
386 _status
= IcacheWaitResponse
;
387 // ownership of packet transferred to memory system
391 // fetch fault: advance directly to next instruction (fault handler)
398 TimingSimpleCPU::advanceInst(Fault fault
)
402 if (_status
== Running
) {
403 // kick off fetch of next instruction... callback from icache
404 // response will cause that instruction to be executed,
405 // keeping the CPU running.
412 TimingSimpleCPU::completeIfetch(Packet
*pkt
)
414 // received a response from the icache: execute the received
416 assert(pkt
->result
== Packet::Success
);
417 assert(_status
== IcacheWaitResponse
);
424 if (getState() == SimObject::Draining
) {
430 if (curStaticInst
->isMemRef() && !curStaticInst
->isDataPrefetch()) {
431 // load or store: just send to dcache
432 Fault fault
= curStaticInst
->initiateAcc(this, traceData
);
433 if (fault
== NoFault
) {
434 // successfully initiated access: instruction will
435 // complete in dcache response callback
436 assert(_status
== DcacheWaitResponse
);
438 // fault: complete now to invoke fault handler
443 // non-memory instruction: execute completely now
444 Fault fault
= curStaticInst
->execute(this, traceData
);
452 TimingSimpleCPU::IcachePort::recvTiming(Packet
*pkt
)
454 cpu
->completeIfetch(pkt
);
459 TimingSimpleCPU::IcachePort::recvRetry()
461 // we shouldn't get a retry unless we have a packet that we're
462 // waiting to transmit
463 assert(cpu
->ifetch_pkt
!= NULL
);
464 assert(cpu
->_status
== IcacheRetry
);
465 Packet
*tmp
= cpu
->ifetch_pkt
;
466 if (sendTiming(tmp
)) {
467 cpu
->_status
= IcacheWaitResponse
;
468 cpu
->ifetch_pkt
= NULL
;
473 TimingSimpleCPU::completeDataAccess(Packet
*pkt
)
475 // received a response from the dcache: complete the load or store
477 assert(pkt
->result
== Packet::Success
);
478 assert(_status
== DcacheWaitResponse
);
481 if (getState() == SimObject::Draining
) {
490 Fault fault
= curStaticInst
->completeAcc(pkt
, this, traceData
);
501 TimingSimpleCPU::completeDrain()
503 DPRINTF(Config
, "Done draining\n");
504 changeState(SimObject::DrainedTiming
);
505 drainEvent
->process();
509 TimingSimpleCPU::DcachePort::recvTiming(Packet
*pkt
)
511 cpu
->completeDataAccess(pkt
);
516 TimingSimpleCPU::DcachePort::recvRetry()
518 // we shouldn't get a retry unless we have a packet that we're
519 // waiting to transmit
520 assert(cpu
->dcache_pkt
!= NULL
);
521 assert(cpu
->_status
== DcacheRetry
);
522 Packet
*tmp
= cpu
->dcache_pkt
;
523 if (sendTiming(tmp
)) {
524 cpu
->_status
= DcacheWaitResponse
;
525 cpu
->dcache_pkt
= NULL
;
530 ////////////////////////////////////////////////////////////////////////
532 // TimingSimpleCPU Simulation Object
534 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
536 Param
<Counter
> max_insts_any_thread
;
537 Param
<Counter
> max_insts_all_threads
;
538 Param
<Counter
> max_loads_any_thread
;
539 Param
<Counter
> max_loads_all_threads
;
540 SimObjectParam
<MemObject
*> mem
;
543 SimObjectParam
<AlphaITB
*> itb
;
544 SimObjectParam
<AlphaDTB
*> dtb
;
545 SimObjectParam
<System
*> system
;
549 SimObjectParam
<Process
*> workload
;
550 #endif // FULL_SYSTEM
554 Param
<bool> defer_registration
;
556 Param
<bool> function_trace
;
557 Param
<Tick
> function_trace_start
;
558 Param
<bool> simulate_stalls
;
560 END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
562 BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
564 INIT_PARAM(max_insts_any_thread
,
565 "terminate when any thread reaches this inst count"),
566 INIT_PARAM(max_insts_all_threads
,
567 "terminate when all threads have reached this inst count"),
568 INIT_PARAM(max_loads_any_thread
,
569 "terminate when any thread reaches this load count"),
570 INIT_PARAM(max_loads_all_threads
,
571 "terminate when all threads have reached this load count"),
572 INIT_PARAM(mem
, "memory"),
575 INIT_PARAM(itb
, "Instruction TLB"),
576 INIT_PARAM(dtb
, "Data TLB"),
577 INIT_PARAM(system
, "system object"),
578 INIT_PARAM(cpu_id
, "processor ID"),
579 INIT_PARAM(profile
, ""),
581 INIT_PARAM(workload
, "processes to run"),
582 #endif // FULL_SYSTEM
584 INIT_PARAM(clock
, "clock speed"),
585 INIT_PARAM(defer_registration
, "defer system registration (for sampling)"),
586 INIT_PARAM(width
, "cpu width"),
587 INIT_PARAM(function_trace
, "Enable function trace"),
588 INIT_PARAM(function_trace_start
, "Cycle to start function trace"),
589 INIT_PARAM(simulate_stalls
, "Simulate cache stall cycles")
591 END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
594 CREATE_SIM_OBJECT(TimingSimpleCPU
)
596 TimingSimpleCPU::Params
*params
= new TimingSimpleCPU::Params();
597 params
->name
= getInstanceName();
598 params
->numberOfThreads
= 1;
599 params
->max_insts_any_thread
= max_insts_any_thread
;
600 params
->max_insts_all_threads
= max_insts_all_threads
;
601 params
->max_loads_any_thread
= max_loads_any_thread
;
602 params
->max_loads_all_threads
= max_loads_all_threads
;
603 params
->deferRegistration
= defer_registration
;
604 params
->clock
= clock
;
605 params
->functionTrace
= function_trace
;
606 params
->functionTraceStart
= function_trace_start
;
612 params
->system
= system
;
613 params
->cpu_id
= cpu_id
;
614 params
->profile
= profile
;
616 params
->process
= workload
;
619 TimingSimpleCPU
*cpu
= new TimingSimpleCPU(params
);
623 REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU
)