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::quiesce(Event
*quiesce_event
)
117 // TimingSimpleCPU is ready to quiesce if it's not waiting for
118 // an access to complete.
119 if (status() == Idle
|| status() == Running
|| status() == SwitchedOut
) {
120 DPRINTF(Config
, "Ready to quiesce\n");
123 DPRINTF(Config
, "Waiting to quiesce\n");
124 changeState(SimObject::Quiescing
);
125 quiesceEvent
= quiesce_event
;
131 TimingSimpleCPU::resume()
133 if (_status
!= SwitchedOut
&& _status
!= Idle
) {
135 new EventWrapper
<TimingSimpleCPU
, &TimingSimpleCPU::fetch
>(this, true);
136 e
->schedule(curTick
);
141 TimingSimpleCPU::setMemoryMode(State new_mode
)
143 assert(new_mode
== SimObject::Timing
);
147 TimingSimpleCPU::switchOut()
149 assert(status() == Running
|| status() == Idle
);
150 _status
= SwitchedOut
;
155 TimingSimpleCPU::takeOverFrom(BaseCPU
*oldCPU
)
157 BaseCPU::takeOverFrom(oldCPU
);
159 // if any of this CPU's ThreadContexts are active, mark the CPU as
160 // running and schedule its tick event.
161 for (int i
= 0; i
< threadContexts
.size(); ++i
) {
162 ThreadContext
*tc
= threadContexts
[i
];
163 if (tc
->status() == ThreadContext::Active
&& _status
!= Running
) {
172 TimingSimpleCPU::activateContext(int thread_num
, int delay
)
174 assert(thread_num
== 0);
177 assert(_status
== Idle
);
181 // kick things off by initiating the fetch of the next instruction
183 new EventWrapper
<TimingSimpleCPU
, &TimingSimpleCPU::fetch
>(this, true);
184 e
->schedule(curTick
+ cycles(delay
));
189 TimingSimpleCPU::suspendContext(int thread_num
)
191 assert(thread_num
== 0);
194 assert(_status
== Running
);
196 // just change status to Idle... if status != Running,
197 // completeInst() will not initiate fetch of next instruction.
206 TimingSimpleCPU::read(Addr addr
, T
&data
, unsigned flags
)
208 // need to fill in CPU & thread IDs here
209 Request
*data_read_req
= new Request();
210 data_read_req
->setThreadContext(0,0); //Need CPU/Thread IDS HERE
211 data_read_req
->setVirt(0, addr
, sizeof(T
), flags
, thread
->readPC());
214 traceData
->setAddr(data_read_req
->getVaddr());
217 // translate to physical address
218 Fault fault
= thread
->translateDataReadReq(data_read_req
);
220 // Now do the access.
221 if (fault
== NoFault
) {
222 Packet
*data_read_pkt
=
223 new Packet(data_read_req
, Packet::ReadReq
, Packet::Broadcast
);
224 data_read_pkt
->dataDynamic
<T
>(new T
);
226 if (!dcachePort
.sendTiming(data_read_pkt
)) {
227 _status
= DcacheRetry
;
228 dcache_pkt
= data_read_pkt
;
230 _status
= DcacheWaitResponse
;
235 // This will need a new way to tell if it has a dcache attached.
236 if (data_read_req
->getFlags() & UNCACHEABLE
)
237 recordEvent("Uncached Read");
242 #ifndef DOXYGEN_SHOULD_SKIP_THIS
246 TimingSimpleCPU::read(Addr addr
, uint64_t &data
, unsigned flags
);
250 TimingSimpleCPU::read(Addr addr
, uint32_t &data
, unsigned flags
);
254 TimingSimpleCPU::read(Addr addr
, uint16_t &data
, unsigned flags
);
258 TimingSimpleCPU::read(Addr addr
, uint8_t &data
, unsigned flags
);
260 #endif //DOXYGEN_SHOULD_SKIP_THIS
264 TimingSimpleCPU::read(Addr addr
, double &data
, unsigned flags
)
266 return read(addr
, *(uint64_t*)&data
, flags
);
271 TimingSimpleCPU::read(Addr addr
, float &data
, unsigned flags
)
273 return read(addr
, *(uint32_t*)&data
, flags
);
279 TimingSimpleCPU::read(Addr addr
, int32_t &data
, unsigned flags
)
281 return read(addr
, (uint32_t&)data
, flags
);
287 TimingSimpleCPU::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
289 // need to fill in CPU & thread IDs here
290 Request
*data_write_req
= new Request();
291 data_write_req
->setThreadContext(0,0); //Need CPU/Thread IDS HERE
292 data_write_req
->setVirt(0, addr
, sizeof(T
), flags
, thread
->readPC());
294 // translate to physical address
295 Fault fault
= thread
->translateDataWriteReq(data_write_req
);
296 // Now do the access.
297 if (fault
== NoFault
) {
298 Packet
*data_write_pkt
=
299 new Packet(data_write_req
, Packet::WriteReq
, Packet::Broadcast
);
300 data_write_pkt
->allocate();
301 data_write_pkt
->set(data
);
303 if (!dcachePort
.sendTiming(data_write_pkt
)) {
304 _status
= DcacheRetry
;
305 dcache_pkt
= data_write_pkt
;
307 _status
= DcacheWaitResponse
;
312 // This will need a new way to tell if it's hooked up to a cache or not.
313 if (data_write_req
->getFlags() & UNCACHEABLE
)
314 recordEvent("Uncached Write");
316 // If the write needs to have a fault on the access, consider calling
317 // changeStatus() and changing it to "bad addr write" or something.
322 #ifndef DOXYGEN_SHOULD_SKIP_THIS
325 TimingSimpleCPU::write(uint64_t data
, Addr addr
,
326 unsigned flags
, uint64_t *res
);
330 TimingSimpleCPU::write(uint32_t data
, Addr addr
,
331 unsigned flags
, uint64_t *res
);
335 TimingSimpleCPU::write(uint16_t data
, Addr addr
,
336 unsigned flags
, uint64_t *res
);
340 TimingSimpleCPU::write(uint8_t data
, Addr addr
,
341 unsigned flags
, uint64_t *res
);
343 #endif //DOXYGEN_SHOULD_SKIP_THIS
347 TimingSimpleCPU::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
349 return write(*(uint64_t*)&data
, addr
, flags
, res
);
354 TimingSimpleCPU::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
356 return write(*(uint32_t*)&data
, addr
, flags
, res
);
362 TimingSimpleCPU::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
364 return write((uint32_t)data
, addr
, flags
, res
);
369 TimingSimpleCPU::fetch()
371 checkForInterrupts();
373 // need to fill in CPU & thread IDs here
374 Request
*ifetch_req
= new Request();
375 ifetch_req
->setThreadContext(0,0); //Need CPU/Thread IDS HERE
376 Fault fault
= setupFetchRequest(ifetch_req
);
378 ifetch_pkt
= new Packet(ifetch_req
, Packet::ReadReq
, Packet::Broadcast
);
379 ifetch_pkt
->dataStatic(&inst
);
381 if (fault
== NoFault
) {
382 if (!icachePort
.sendTiming(ifetch_pkt
)) {
383 // Need to wait for retry
384 _status
= IcacheRetry
;
386 // Need to wait for cache to respond
387 _status
= IcacheWaitResponse
;
388 // ownership of packet transferred to memory system
392 // fetch fault: advance directly to next instruction (fault handler)
399 TimingSimpleCPU::advanceInst(Fault fault
)
403 if (_status
== Running
) {
404 // kick off fetch of next instruction... callback from icache
405 // response will cause that instruction to be executed,
406 // keeping the CPU running.
413 TimingSimpleCPU::completeIfetch(Packet
*pkt
)
415 // received a response from the icache: execute the received
417 assert(pkt
->result
== Packet::Success
);
418 assert(_status
== IcacheWaitResponse
);
425 if (getState() == SimObject::Quiescing
) {
431 if (curStaticInst
->isMemRef() && !curStaticInst
->isDataPrefetch()) {
432 // load or store: just send to dcache
433 Fault fault
= curStaticInst
->initiateAcc(this, traceData
);
434 if (fault
== NoFault
) {
435 // successfully initiated access: instruction will
436 // complete in dcache response callback
437 assert(_status
== DcacheWaitResponse
);
439 // fault: complete now to invoke fault handler
444 // non-memory instruction: execute completely now
445 Fault fault
= curStaticInst
->execute(this, traceData
);
453 TimingSimpleCPU::IcachePort::recvTiming(Packet
*pkt
)
455 cpu
->completeIfetch(pkt
);
460 TimingSimpleCPU::IcachePort::recvRetry()
462 // we shouldn't get a retry unless we have a packet that we're
463 // waiting to transmit
464 assert(cpu
->ifetch_pkt
!= NULL
);
465 assert(cpu
->_status
== IcacheRetry
);
466 Packet
*tmp
= cpu
->ifetch_pkt
;
467 if (sendTiming(tmp
)) {
468 cpu
->_status
= IcacheWaitResponse
;
469 cpu
->ifetch_pkt
= NULL
;
474 TimingSimpleCPU::completeDataAccess(Packet
*pkt
)
476 // received a response from the dcache: complete the load or store
478 assert(pkt
->result
== Packet::Success
);
479 assert(_status
== DcacheWaitResponse
);
482 if (getState() == SimObject::Quiescing
) {
491 Fault fault
= curStaticInst
->completeAcc(pkt
, this, traceData
);
502 TimingSimpleCPU::completeQuiesce()
504 DPRINTF(Config
, "Done quiescing\n");
505 changeState(SimObject::QuiescedTiming
);
506 quiesceEvent
->process();
510 TimingSimpleCPU::DcachePort::recvTiming(Packet
*pkt
)
512 cpu
->completeDataAccess(pkt
);
517 TimingSimpleCPU::DcachePort::recvRetry()
519 // we shouldn't get a retry unless we have a packet that we're
520 // waiting to transmit
521 assert(cpu
->dcache_pkt
!= NULL
);
522 assert(cpu
->_status
== DcacheRetry
);
523 Packet
*tmp
= cpu
->dcache_pkt
;
524 if (sendTiming(tmp
)) {
525 cpu
->_status
= DcacheWaitResponse
;
526 cpu
->dcache_pkt
= NULL
;
531 ////////////////////////////////////////////////////////////////////////
533 // TimingSimpleCPU Simulation Object
535 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
537 Param
<Counter
> max_insts_any_thread
;
538 Param
<Counter
> max_insts_all_threads
;
539 Param
<Counter
> max_loads_any_thread
;
540 Param
<Counter
> max_loads_all_threads
;
541 SimObjectParam
<MemObject
*> mem
;
544 SimObjectParam
<AlphaITB
*> itb
;
545 SimObjectParam
<AlphaDTB
*> dtb
;
546 SimObjectParam
<System
*> system
;
550 SimObjectParam
<Process
*> workload
;
551 #endif // FULL_SYSTEM
555 Param
<bool> defer_registration
;
557 Param
<bool> function_trace
;
558 Param
<Tick
> function_trace_start
;
559 Param
<bool> simulate_stalls
;
561 END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
563 BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
565 INIT_PARAM(max_insts_any_thread
,
566 "terminate when any thread reaches this inst count"),
567 INIT_PARAM(max_insts_all_threads
,
568 "terminate when all threads have reached this inst count"),
569 INIT_PARAM(max_loads_any_thread
,
570 "terminate when any thread reaches this load count"),
571 INIT_PARAM(max_loads_all_threads
,
572 "terminate when all threads have reached this load count"),
573 INIT_PARAM(mem
, "memory"),
576 INIT_PARAM(itb
, "Instruction TLB"),
577 INIT_PARAM(dtb
, "Data TLB"),
578 INIT_PARAM(system
, "system object"),
579 INIT_PARAM(cpu_id
, "processor ID"),
580 INIT_PARAM(profile
, ""),
582 INIT_PARAM(workload
, "processes to run"),
583 #endif // FULL_SYSTEM
585 INIT_PARAM(clock
, "clock speed"),
586 INIT_PARAM(defer_registration
, "defer system registration (for sampling)"),
587 INIT_PARAM(width
, "cpu width"),
588 INIT_PARAM(function_trace
, "Enable function trace"),
589 INIT_PARAM(function_trace_start
, "Cycle to start function trace"),
590 INIT_PARAM(simulate_stalls
, "Simulate cache stall cycles")
592 END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU
)
595 CREATE_SIM_OBJECT(TimingSimpleCPU
)
597 TimingSimpleCPU::Params
*params
= new TimingSimpleCPU::Params();
598 params
->name
= getInstanceName();
599 params
->numberOfThreads
= 1;
600 params
->max_insts_any_thread
= max_insts_any_thread
;
601 params
->max_insts_all_threads
= max_insts_all_threads
;
602 params
->max_loads_any_thread
= max_loads_any_thread
;
603 params
->max_loads_all_threads
= max_loads_all_threads
;
604 params
->deferRegistration
= defer_registration
;
605 params
->clock
= clock
;
606 params
->functionTrace
= function_trace
;
607 params
->functionTraceStart
= function_trace_start
;
613 params
->system
= system
;
614 params
->cpu_id
= cpu_id
;
615 params
->profile
= profile
;
617 params
->process
= workload
;
620 TimingSimpleCPU
*cpu
= new TimingSimpleCPU(params
);
624 REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU
)