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/atomic.hh"
32 #include "mem/packet_impl.hh"
33 #include "sim/builder.hh"
36 using namespace TheISA
;
38 AtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU
*c
)
39 : Event(&mainEventQueue
, CPU_Tick_Pri
), cpu(c
)
45 AtomicSimpleCPU::TickEvent::process()
51 AtomicSimpleCPU::TickEvent::description()
53 return "AtomicSimpleCPU tick event";
58 AtomicSimpleCPU::init()
60 //Create Memory Ports (conect them up)
61 Port
*mem_dport
= mem
->getPort("");
62 dcachePort
.setPeer(mem_dport
);
63 mem_dport
->setPeer(&dcachePort
);
65 Port
*mem_iport
= mem
->getPort("");
66 icachePort
.setPeer(mem_iport
);
67 mem_iport
->setPeer(&icachePort
);
71 for (int i
= 0; i
< execContexts
.size(); ++i
) {
72 ExecContext
*xc
= execContexts
[i
];
74 // initialize CPU, including PC
75 TheISA::initCPU(xc
, xc
->readCpuId());
81 AtomicSimpleCPU::CpuPort::recvTiming(Packet
*pkt
)
83 panic("AtomicSimpleCPU doesn't expect recvAtomic callback!");
88 AtomicSimpleCPU::CpuPort::recvAtomic(Packet
*pkt
)
90 panic("AtomicSimpleCPU doesn't expect recvAtomic callback!");
95 AtomicSimpleCPU::CpuPort::recvFunctional(Packet
*pkt
)
97 panic("AtomicSimpleCPU doesn't expect recvFunctional callback!");
101 AtomicSimpleCPU::CpuPort::recvStatusChange(Status status
)
103 if (status
== RangeChange
)
106 panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
110 AtomicSimpleCPU::CpuPort::recvRetry()
112 panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
117 AtomicSimpleCPU::AtomicSimpleCPU(Params
*p
)
118 : BaseSimpleCPU(p
), tickEvent(this),
119 width(p
->width
), simulate_stalls(p
->simulate_stalls
),
120 icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this)
124 ifetch_req
= new Request(true);
125 ifetch_req
->setAsid(0);
126 // @todo fix me and get the real cpu iD!!!
127 ifetch_req
->setCpuNum(0);
128 ifetch_req
->setSize(sizeof(MachInst
));
129 ifetch_pkt
= new Packet(ifetch_req
, Packet::ReadReq
, Packet::Broadcast
);
130 ifetch_pkt
->dataStatic(&inst
);
132 data_read_req
= new Request(true);
133 // @todo fix me and get the real cpu iD!!!
134 data_read_req
->setCpuNum(0);
135 data_read_req
->setAsid(0);
136 data_read_pkt
= new Packet(data_read_req
, Packet::ReadReq
,
138 data_read_pkt
->dataStatic(&dataReg
);
140 data_write_req
= new Request(true);
141 // @todo fix me and get the real cpu iD!!!
142 data_write_req
->setCpuNum(0);
143 data_write_req
->setAsid(0);
144 data_write_pkt
= new Packet(data_write_req
, Packet::WriteReq
,
149 AtomicSimpleCPU::~AtomicSimpleCPU()
154 AtomicSimpleCPU::serialize(ostream
&os
)
156 BaseSimpleCPU::serialize(os
);
157 SERIALIZE_ENUM(_status
);
158 nameOut(os
, csprintf("%s.tickEvent", name()));
159 tickEvent
.serialize(os
);
163 AtomicSimpleCPU::unserialize(Checkpoint
*cp
, const string
§ion
)
165 BaseSimpleCPU::unserialize(cp
, section
);
166 UNSERIALIZE_ENUM(_status
);
167 tickEvent
.unserialize(cp
, csprintf("%s.tickEvent", section
));
171 AtomicSimpleCPU::switchOut(Sampler
*s
)
174 if (status() == Running
) {
175 _status
= SwitchedOut
;
179 sampler
->signalSwitched();
184 AtomicSimpleCPU::takeOverFrom(BaseCPU
*oldCPU
)
186 BaseCPU::takeOverFrom(oldCPU
);
188 assert(!tickEvent
.scheduled());
190 // if any of this CPU's ExecContexts are active, mark the CPU as
191 // running and schedule its tick event.
192 for (int i
= 0; i
< execContexts
.size(); ++i
) {
193 ExecContext
*xc
= execContexts
[i
];
194 if (xc
->status() == ExecContext::Active
&& _status
!= Running
) {
196 tickEvent
.schedule(curTick
);
204 AtomicSimpleCPU::activateContext(int thread_num
, int delay
)
206 assert(thread_num
== 0);
209 assert(_status
== Idle
);
210 assert(!tickEvent
.scheduled());
213 tickEvent
.schedule(curTick
+ cycles(delay
));
219 AtomicSimpleCPU::suspendContext(int thread_num
)
221 assert(thread_num
== 0);
224 assert(_status
== Running
);
226 // tick event may not be scheduled if this gets called from inside
227 // an instruction's execution, e.g. "quiesce"
228 if (tickEvent
.scheduled())
229 tickEvent
.deschedule();
238 AtomicSimpleCPU::read(Addr addr
, T
&data
, unsigned flags
)
240 data_read_req
->setVaddr(addr
);
241 data_read_req
->setSize(sizeof(T
));
242 data_read_req
->setFlags(flags
);
243 data_read_req
->setTime(curTick
);
246 traceData
->setAddr(addr
);
249 // translate to physical address
250 Fault fault
= cpuXC
->translateDataReadReq(data_read_req
);
252 // Now do the access.
253 if (fault
== NoFault
) {
254 data_read_pkt
->reset();
255 data_read_pkt
->reinitFromRequest();
257 dcache_complete
= dcachePort
.sendAtomic(data_read_pkt
);
258 dcache_access
= true;
260 assert(data_read_pkt
->result
== Packet::Success
);
261 data
= data_read_pkt
->get
<T
>();
265 // This will need a new way to tell if it has a dcache attached.
266 if (data_read_req
->getFlags() & UNCACHEABLE
)
267 recordEvent("Uncached Read");
272 #ifndef DOXYGEN_SHOULD_SKIP_THIS
276 AtomicSimpleCPU::read(Addr addr
, uint64_t &data
, unsigned flags
);
280 AtomicSimpleCPU::read(Addr addr
, uint32_t &data
, unsigned flags
);
284 AtomicSimpleCPU::read(Addr addr
, uint16_t &data
, unsigned flags
);
288 AtomicSimpleCPU::read(Addr addr
, uint8_t &data
, unsigned flags
);
290 #endif //DOXYGEN_SHOULD_SKIP_THIS
294 AtomicSimpleCPU::read(Addr addr
, double &data
, unsigned flags
)
296 return read(addr
, *(uint64_t*)&data
, flags
);
301 AtomicSimpleCPU::read(Addr addr
, float &data
, unsigned flags
)
303 return read(addr
, *(uint32_t*)&data
, flags
);
309 AtomicSimpleCPU::read(Addr addr
, int32_t &data
, unsigned flags
)
311 return read(addr
, (uint32_t&)data
, flags
);
317 AtomicSimpleCPU::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
319 data_write_req
->setVaddr(addr
);
320 data_write_req
->setTime(curTick
);
321 data_write_req
->setSize(sizeof(T
));
322 data_write_req
->setFlags(flags
);
325 traceData
->setAddr(addr
);
328 // translate to physical address
329 Fault fault
= cpuXC
->translateDataWriteReq(data_write_req
);
331 // Now do the access.
332 if (fault
== NoFault
) {
333 data_write_pkt
->reset();
335 data_write_pkt
->dataStatic(&data
);
336 data_write_pkt
->reinitFromRequest();
338 dcache_complete
= dcachePort
.sendAtomic(data_write_pkt
);
339 dcache_access
= true;
341 assert(data_write_pkt
->result
== Packet::Success
);
343 if (res
&& data_write_req
->getFlags() & LOCKED
) {
344 *res
= data_write_req
->getScResult();
348 // This will need a new way to tell if it's hooked up to a cache or not.
349 if (data_write_req
->getFlags() & UNCACHEABLE
)
350 recordEvent("Uncached Write");
352 // If the write needs to have a fault on the access, consider calling
353 // changeStatus() and changing it to "bad addr write" or something.
358 #ifndef DOXYGEN_SHOULD_SKIP_THIS
361 AtomicSimpleCPU::write(uint64_t data
, Addr addr
,
362 unsigned flags
, uint64_t *res
);
366 AtomicSimpleCPU::write(uint32_t data
, Addr addr
,
367 unsigned flags
, uint64_t *res
);
371 AtomicSimpleCPU::write(uint16_t data
, Addr addr
,
372 unsigned flags
, uint64_t *res
);
376 AtomicSimpleCPU::write(uint8_t data
, Addr addr
,
377 unsigned flags
, uint64_t *res
);
379 #endif //DOXYGEN_SHOULD_SKIP_THIS
383 AtomicSimpleCPU::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
385 return write(*(uint64_t*)&data
, addr
, flags
, res
);
390 AtomicSimpleCPU::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
392 return write(*(uint32_t*)&data
, addr
, flags
, res
);
398 AtomicSimpleCPU::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
400 return write((uint32_t)data
, addr
, flags
, res
);
405 AtomicSimpleCPU::tick()
407 Tick latency
= cycles(1); // instruction takes one cycle by default
409 for (int i
= 0; i
< width
; ++i
) {
412 checkForInterrupts();
414 ifetch_req
->resetMin();
416 Fault fault
= setupFetchPacket(ifetch_pkt
);
418 if (fault
== NoFault
) {
419 Tick icache_complete
= icachePort
.sendAtomic(ifetch_pkt
);
420 // ifetch_req is initialized to read the instruction directly
421 // into the CPU object's inst field.
423 dcache_access
= false; // assume no dcache access
425 fault
= curStaticInst
->execute(this, traceData
);
428 if (simulate_stalls
) {
429 // This calculation assumes that the icache and dcache
430 // access latencies are always a multiple of the CPU's
431 // cycle time. If not, the next tick event may get
432 // scheduled at a non-integer multiple of the CPU
434 Tick icache_stall
= icache_complete
- curTick
- cycles(1);
436 dcache_access
? dcache_complete
- curTick
- cycles(1) : 0;
437 latency
+= icache_stall
+ dcache_stall
;
446 tickEvent
.schedule(curTick
+ latency
);
450 ////////////////////////////////////////////////////////////////////////
452 // AtomicSimpleCPU Simulation Object
454 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU
)
456 Param
<Counter
> max_insts_any_thread
;
457 Param
<Counter
> max_insts_all_threads
;
458 Param
<Counter
> max_loads_any_thread
;
459 Param
<Counter
> max_loads_all_threads
;
460 SimObjectParam
<MemObject
*> mem
;
463 SimObjectParam
<AlphaITB
*> itb
;
464 SimObjectParam
<AlphaDTB
*> dtb
;
465 SimObjectParam
<System
*> system
;
469 SimObjectParam
<Process
*> workload
;
470 #endif // FULL_SYSTEM
474 Param
<bool> defer_registration
;
476 Param
<bool> function_trace
;
477 Param
<Tick
> function_trace_start
;
478 Param
<bool> simulate_stalls
;
480 END_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU
)
482 BEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU
)
484 INIT_PARAM(max_insts_any_thread
,
485 "terminate when any thread reaches this inst count"),
486 INIT_PARAM(max_insts_all_threads
,
487 "terminate when all threads have reached this inst count"),
488 INIT_PARAM(max_loads_any_thread
,
489 "terminate when any thread reaches this load count"),
490 INIT_PARAM(max_loads_all_threads
,
491 "terminate when all threads have reached this load count"),
492 INIT_PARAM(mem
, "memory"),
495 INIT_PARAM(itb
, "Instruction TLB"),
496 INIT_PARAM(dtb
, "Data TLB"),
497 INIT_PARAM(system
, "system object"),
498 INIT_PARAM(cpu_id
, "processor ID"),
499 INIT_PARAM(profile
, ""),
501 INIT_PARAM(workload
, "processes to run"),
502 #endif // FULL_SYSTEM
504 INIT_PARAM(clock
, "clock speed"),
505 INIT_PARAM(defer_registration
, "defer system registration (for sampling)"),
506 INIT_PARAM(width
, "cpu width"),
507 INIT_PARAM(function_trace
, "Enable function trace"),
508 INIT_PARAM(function_trace_start
, "Cycle to start function trace"),
509 INIT_PARAM(simulate_stalls
, "Simulate cache stall cycles")
511 END_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU
)
514 CREATE_SIM_OBJECT(AtomicSimpleCPU
)
516 AtomicSimpleCPU::Params
*params
= new AtomicSimpleCPU::Params();
517 params
->name
= getInstanceName();
518 params
->numberOfThreads
= 1;
519 params
->max_insts_any_thread
= max_insts_any_thread
;
520 params
->max_insts_all_threads
= max_insts_all_threads
;
521 params
->max_loads_any_thread
= max_loads_any_thread
;
522 params
->max_loads_all_threads
= max_loads_all_threads
;
523 params
->deferRegistration
= defer_registration
;
524 params
->clock
= clock
;
525 params
->functionTrace
= function_trace
;
526 params
->functionTraceStart
= function_trace_start
;
527 params
->width
= width
;
528 params
->simulate_stalls
= simulate_stalls
;
534 params
->system
= system
;
535 params
->cpu_id
= cpu_id
;
536 params
->profile
= profile
;
538 params
->process
= workload
;
541 AtomicSimpleCPU
*cpu
= new AtomicSimpleCPU(params
);
545 REGISTER_SIM_OBJECT("AtomicSimpleCPU", AtomicSimpleCPU
)