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 panic("TimingSimpleCPU::suspendContext not implemented");
163 assert(_status
== Running
);
172 TimingSimpleCPU::read(Addr addr
, T
&data
, unsigned flags
)
174 Request
*data_read_req
= new Request(true);
176 data_read_req
->setVaddr(addr
);
177 data_read_req
->setSize(sizeof(T
));
178 data_read_req
->setFlags(flags
);
179 data_read_req
->setTime(curTick
);
182 traceData
->setAddr(data_read_req
->getVaddr());
185 // translate to physical address
186 Fault fault
= cpuXC
->translateDataReadReq(data_read_req
);
188 // Now do the access.
189 if (fault
== NoFault
) {
190 Packet
*data_read_pkt
= new Packet
;
191 data_read_pkt
->cmd
= Read
;
192 data_read_pkt
->req
= data_read_req
;
193 data_read_pkt
->dataDynamic
<T
>(new T
);
194 data_read_pkt
->addr
= data_read_req
->getPaddr();
195 data_read_pkt
->size
= sizeof(T
);
196 data_read_pkt
->dest
= Packet::Broadcast
;
198 if (!dcachePort
.sendTiming(data_read_pkt
)) {
199 _status
= DcacheRetry
;
200 dcache_pkt
= data_read_pkt
;
202 _status
= DcacheWaitResponse
;
207 // This will need a new way to tell if it has a dcache attached.
208 if (data_read_req
->getFlags() & UNCACHEABLE
)
209 recordEvent("Uncached Read");
214 #ifndef DOXYGEN_SHOULD_SKIP_THIS
218 TimingSimpleCPU::read(Addr addr
, uint64_t &data
, unsigned flags
);
222 TimingSimpleCPU::read(Addr addr
, uint32_t &data
, unsigned flags
);
226 TimingSimpleCPU::read(Addr addr
, uint16_t &data
, unsigned flags
);
230 TimingSimpleCPU::read(Addr addr
, uint8_t &data
, unsigned flags
);
232 #endif //DOXYGEN_SHOULD_SKIP_THIS
236 TimingSimpleCPU::read(Addr addr
, double &data
, unsigned flags
)
238 return read(addr
, *(uint64_t*)&data
, flags
);
243 TimingSimpleCPU::read(Addr addr
, float &data
, unsigned flags
)
245 return read(addr
, *(uint32_t*)&data
, flags
);
251 TimingSimpleCPU::read(Addr addr
, int32_t &data
, unsigned flags
)
253 return read(addr
, (uint32_t&)data
, flags
);
259 TimingSimpleCPU::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
261 Request
*data_write_req
= new Request(true);
262 data_write_req
->setVaddr(addr
);
263 data_write_req
->setTime(curTick
);
264 data_write_req
->setSize(sizeof(T
));
265 data_write_req
->setFlags(flags
);
267 // translate to physical address
268 Fault fault
= cpuXC
->translateDataWriteReq(data_write_req
);
269 // Now do the access.
270 if (fault
== NoFault
) {
271 Packet
*data_write_pkt
= new Packet
;
272 data_write_pkt
->cmd
= Write
;
273 data_write_pkt
->req
= data_write_req
;
274 data_write_pkt
->allocate();
275 data_write_pkt
->size
= sizeof(T
);
276 data_write_pkt
->set(data
);
277 data_write_pkt
->addr
= data_write_req
->getPaddr();
278 data_write_pkt
->dest
= Packet::Broadcast
;
280 if (!dcachePort
.sendTiming(data_write_pkt
)) {
281 _status
= DcacheRetry
;
282 dcache_pkt
= data_write_pkt
;
284 _status
= DcacheWaitResponse
;
289 // This will need a new way to tell if it's hooked up to a cache or not.
290 if (data_write_req
->getFlags() & UNCACHEABLE
)
291 recordEvent("Uncached Write");
293 // If the write needs to have a fault on the access, consider calling
294 // changeStatus() and changing it to "bad addr write" or something.
299 #ifndef DOXYGEN_SHOULD_SKIP_THIS
302 TimingSimpleCPU::write(uint64_t data
, Addr addr
,
303 unsigned flags
, uint64_t *res
);
307 TimingSimpleCPU::write(uint32_t data
, Addr addr
,
308 unsigned flags
, uint64_t *res
);
312 TimingSimpleCPU::write(uint16_t data
, Addr addr
,
313 unsigned flags
, uint64_t *res
);
317 TimingSimpleCPU::write(uint8_t data
, Addr addr
,
318 unsigned flags
, uint64_t *res
);
320 #endif //DOXYGEN_SHOULD_SKIP_THIS
324 TimingSimpleCPU::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
326 return write(*(uint64_t*)&data
, addr
, flags
, res
);
331 TimingSimpleCPU::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
333 return write(*(uint32_t*)&data
, addr
, flags
, res
);
339 TimingSimpleCPU::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
341 return write((uint32_t)data
, addr
, flags
, res
);
346 TimingSimpleCPU::fetch()
348 checkForInterrupts();
350 Request
*ifetch_req
= new Request(true);
351 ifetch_req
->setSize(sizeof(MachInst
));
353 ifetch_pkt
= new Packet
;
354 ifetch_pkt
->cmd
= Read
;
355 ifetch_pkt
->dataStatic(&inst
);
356 ifetch_pkt
->req
= ifetch_req
;
357 ifetch_pkt
->size
= sizeof(MachInst
);
358 ifetch_pkt
->dest
= Packet::Broadcast
;
360 Fault fault
= setupFetchPacket(ifetch_pkt
);
361 if (fault
== NoFault
) {
362 if (!icachePort
.sendTiming(ifetch_pkt
)) {
363 // Need to wait for retry
364 _status
= IcacheRetry
;
366 // Need to wait for cache to respond
367 _status
= IcacheWaitResponse
;
368 // ownership of packet transferred to memory system
372 panic("TimingSimpleCPU fetch fault handling not implemented");
378 TimingSimpleCPU::completeInst(Fault fault
)
383 traceData
->finalize();
388 if (_status
== Running
) {
389 // kick off fetch of next instruction... callback from icache
390 // response will cause that instruction to be executed,
391 // keeping the CPU running.
398 TimingSimpleCPU::completeIfetch()
400 // received a response from the icache: execute the received
402 assert(_status
== IcacheWaitResponse
);
405 if (curStaticInst
->isMemRef()) {
406 // load or store: just send to dcache
407 Fault fault
= curStaticInst
->initiateAcc(this, traceData
);
408 assert(fault
== NoFault
);
409 assert(_status
== DcacheWaitResponse
);
410 // instruction will complete in dcache response callback
412 // non-memory instruction: execute completely now
413 Fault fault
= curStaticInst
->execute(this, traceData
);
420 TimingSimpleCPU::IcachePort::recvTiming(Packet
*pkt
)
422 cpu
->completeIfetch();
427 TimingSimpleCPU::IcachePort::recvRetry()
429 // we shouldn't get a retry unless we have a packet that we're
430 // waiting to transmit
431 assert(cpu
->ifetch_pkt
!= NULL
);
432 assert(cpu
->_status
== IcacheRetry
);
433 cpu
->_status
= IcacheWaitResponse
;
434 Packet
*tmp
= cpu
->ifetch_pkt
;
435 cpu
->ifetch_pkt
= NULL
;
440 TimingSimpleCPU::completeDataAccess(Packet
*pkt
)
442 // received a response from the dcache: complete the load or store
444 assert(pkt
->result
== Success
);
445 assert(_status
== DcacheWaitResponse
);
448 Fault fault
= curStaticInst
->completeAcc(pkt
, this, traceData
);
456 TimingSimpleCPU::DcachePort::recvTiming(Packet
*pkt
)
458 cpu
->completeDataAccess(pkt
);
463 TimingSimpleCPU::DcachePort::recvRetry()
465 // we shouldn't get a retry unless we have a packet that we're
466 // waiting to transmit
467 assert(cpu
->dcache_pkt
!= NULL
);
468 assert(cpu
->_status
== DcacheRetry
);
469 cpu
->_status
= DcacheWaitResponse
;
470 Packet
*tmp
= cpu
->dcache_pkt
;
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
)