0ca7006340bc7b7da5ebf10f728e1f17769b8914
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/locked_mem.hh"
32 #include "arch/utility.hh"
33 #include "cpu/exetrace.hh"
34 #include "cpu/simple/atomic.hh"
35 #include "mem/packet_impl.hh"
36 #include "sim/builder.hh"
37 #include "sim/system.hh"
40 using namespace TheISA
;
42 AtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU
*c
)
43 : Event(&mainEventQueue
, CPU_Tick_Pri
), cpu(c
)
49 AtomicSimpleCPU::TickEvent::process()
55 AtomicSimpleCPU::TickEvent::description()
57 return "AtomicSimpleCPU tick event";
61 AtomicSimpleCPU::getPort(const std::string
&if_name
, int idx
)
63 if (if_name
== "dcache_port")
65 else if (if_name
== "icache_port")
68 panic("No Such Port\n");
72 AtomicSimpleCPU::init()
74 //Create Memory Ports (conect them up)
75 // Port *mem_dport = mem->getPort("");
76 // dcachePort.setPeer(mem_dport);
77 // mem_dport->setPeer(&dcachePort);
79 // Port *mem_iport = mem->getPort("");
80 // icachePort.setPeer(mem_iport);
81 // mem_iport->setPeer(&icachePort);
85 for (int i
= 0; i
< threadContexts
.size(); ++i
) {
86 ThreadContext
*tc
= threadContexts
[i
];
88 // initialize CPU, including PC
89 TheISA::initCPU(tc
, tc
->readCpuId());
95 AtomicSimpleCPU::CpuPort::recvTiming(Packet
*pkt
)
97 panic("AtomicSimpleCPU doesn't expect recvAtomic callback!");
102 AtomicSimpleCPU::CpuPort::recvAtomic(Packet
*pkt
)
104 panic("AtomicSimpleCPU doesn't expect recvAtomic callback!");
109 AtomicSimpleCPU::CpuPort::recvFunctional(Packet
*pkt
)
111 panic("AtomicSimpleCPU doesn't expect recvFunctional callback!");
115 AtomicSimpleCPU::CpuPort::recvStatusChange(Status status
)
117 if (status
== RangeChange
)
120 panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
124 AtomicSimpleCPU::CpuPort::recvRetry()
126 panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
130 AtomicSimpleCPU::AtomicSimpleCPU(Params
*p
)
131 : BaseSimpleCPU(p
), tickEvent(this),
132 width(p
->width
), simulate_stalls(p
->simulate_stalls
),
133 icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this)
137 ifetch_req
= new Request();
138 ifetch_req
->setThreadContext(p
->cpu_id
, 0); // Add thread ID if we add MT
139 ifetch_pkt
= new Packet(ifetch_req
, Packet::ReadReq
, Packet::Broadcast
);
140 ifetch_pkt
->dataStatic(&inst
);
142 data_read_req
= new Request();
143 data_read_req
->setThreadContext(p
->cpu_id
, 0); // Add thread ID here too
144 data_read_pkt
= new Packet(data_read_req
, Packet::ReadReq
,
146 data_read_pkt
->dataStatic(&dataReg
);
148 data_write_req
= new Request();
149 data_write_req
->setThreadContext(p
->cpu_id
, 0); // Add thread ID here too
150 data_write_pkt
= new Packet(data_write_req
, Packet::WriteReq
,
155 AtomicSimpleCPU::~AtomicSimpleCPU()
160 AtomicSimpleCPU::serialize(ostream
&os
)
162 SimObject::State so_state
= SimObject::getState();
163 SERIALIZE_ENUM(so_state
);
164 BaseSimpleCPU::serialize(os
);
165 nameOut(os
, csprintf("%s.tickEvent", name()));
166 tickEvent
.serialize(os
);
170 AtomicSimpleCPU::unserialize(Checkpoint
*cp
, const string
§ion
)
172 SimObject::State so_state
;
173 UNSERIALIZE_ENUM(so_state
);
174 BaseSimpleCPU::unserialize(cp
, section
);
175 tickEvent
.unserialize(cp
, csprintf("%s.tickEvent", section
));
179 AtomicSimpleCPU::resume()
181 assert(system
->getMemoryMode() == System::Atomic
);
182 changeState(SimObject::Running
);
183 if (thread
->status() == ThreadContext::Active
) {
184 if (!tickEvent
.scheduled())
185 tickEvent
.schedule(curTick
);
190 AtomicSimpleCPU::switchOut()
192 assert(status() == Running
|| status() == Idle
);
193 _status
= SwitchedOut
;
200 AtomicSimpleCPU::takeOverFrom(BaseCPU
*oldCPU
)
202 BaseCPU::takeOverFrom(oldCPU
);
204 assert(!tickEvent
.scheduled());
206 // if any of this CPU's ThreadContexts are active, mark the CPU as
207 // running and schedule its tick event.
208 for (int i
= 0; i
< threadContexts
.size(); ++i
) {
209 ThreadContext
*tc
= threadContexts
[i
];
210 if (tc
->status() == ThreadContext::Active
&& _status
!= Running
) {
212 tickEvent
.schedule(curTick
);
220 AtomicSimpleCPU::activateContext(int thread_num
, int delay
)
222 assert(thread_num
== 0);
225 assert(_status
== Idle
);
226 assert(!tickEvent
.scheduled());
229 tickEvent
.schedule(curTick
+ cycles(delay
));
235 AtomicSimpleCPU::suspendContext(int thread_num
)
237 assert(thread_num
== 0);
240 assert(_status
== Running
);
242 // tick event may not be scheduled if this gets called from inside
243 // an instruction's execution, e.g. "quiesce"
244 if (tickEvent
.scheduled())
245 tickEvent
.deschedule();
254 AtomicSimpleCPU::read(Addr addr
, T
&data
, unsigned flags
)
256 // use the CPU's statically allocated read request and packet objects
257 Request
*req
= data_read_req
;
258 Packet
*pkt
= data_read_pkt
;
260 req
->setVirt(0, addr
, sizeof(T
), flags
, thread
->readPC());
263 traceData
->setAddr(addr
);
266 // translate to physical address
267 Fault fault
= thread
->translateDataReadReq(req
);
269 // Now do the access.
270 if (fault
== NoFault
) {
271 pkt
->reinitFromRequest();
273 dcache_latency
= dcachePort
.sendAtomic(pkt
);
274 dcache_access
= true;
276 assert(pkt
->result
== Packet::Success
);
277 data
= pkt
->get
<T
>();
279 if (req
->isLocked()) {
280 TheISA::handleLockedRead(thread
, req
);
284 // This will need a new way to tell if it has a dcache attached.
285 if (req
->getFlags() & UNCACHEABLE
)
286 recordEvent("Uncached Read");
291 #ifndef DOXYGEN_SHOULD_SKIP_THIS
295 AtomicSimpleCPU::read(Addr addr
, uint64_t &data
, unsigned flags
);
299 AtomicSimpleCPU::read(Addr addr
, uint32_t &data
, unsigned flags
);
303 AtomicSimpleCPU::read(Addr addr
, uint16_t &data
, unsigned flags
);
307 AtomicSimpleCPU::read(Addr addr
, uint8_t &data
, unsigned flags
);
309 #endif //DOXYGEN_SHOULD_SKIP_THIS
313 AtomicSimpleCPU::read(Addr addr
, double &data
, unsigned flags
)
315 return read(addr
, *(uint64_t*)&data
, flags
);
320 AtomicSimpleCPU::read(Addr addr
, float &data
, unsigned flags
)
322 return read(addr
, *(uint32_t*)&data
, flags
);
328 AtomicSimpleCPU::read(Addr addr
, int32_t &data
, unsigned flags
)
330 return read(addr
, (uint32_t&)data
, flags
);
336 AtomicSimpleCPU::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
338 // use the CPU's statically allocated write request and packet objects
339 Request
*req
= data_write_req
;
340 Packet
*pkt
= data_write_pkt
;
342 req
->setVirt(0, addr
, sizeof(T
), flags
, thread
->readPC());
345 traceData
->setAddr(addr
);
348 // translate to physical address
349 Fault fault
= thread
->translateDataWriteReq(req
);
351 // Now do the access.
352 if (fault
== NoFault
) {
353 bool do_access
= true; // flag to suppress cache access
355 if (req
->isLocked()) {
356 do_access
= TheISA::handleLockedWrite(thread
, req
);
361 pkt
->reinitFromRequest();
362 pkt
->dataStatic(&data
);
364 dcache_latency
= dcachePort
.sendAtomic(pkt
);
365 dcache_access
= true;
367 assert(pkt
->result
== Packet::Success
);
370 if (req
->isLocked()) {
371 uint64_t scResult
= req
->getScResult();
373 // clear failure counter
374 thread
->setStCondFailures(0);
377 *res
= req
->getScResult();
382 // This will need a new way to tell if it's hooked up to a cache or not.
383 if (req
->getFlags() & UNCACHEABLE
)
384 recordEvent("Uncached Write");
386 // If the write needs to have a fault on the access, consider calling
387 // changeStatus() and changing it to "bad addr write" or something.
392 #ifndef DOXYGEN_SHOULD_SKIP_THIS
395 AtomicSimpleCPU::write(uint64_t data
, Addr addr
,
396 unsigned flags
, uint64_t *res
);
400 AtomicSimpleCPU::write(uint32_t data
, Addr addr
,
401 unsigned flags
, uint64_t *res
);
405 AtomicSimpleCPU::write(uint16_t data
, Addr addr
,
406 unsigned flags
, uint64_t *res
);
410 AtomicSimpleCPU::write(uint8_t data
, Addr addr
,
411 unsigned flags
, uint64_t *res
);
413 #endif //DOXYGEN_SHOULD_SKIP_THIS
417 AtomicSimpleCPU::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
419 return write(*(uint64_t*)&data
, addr
, flags
, res
);
424 AtomicSimpleCPU::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
426 return write(*(uint32_t*)&data
, addr
, flags
, res
);
432 AtomicSimpleCPU::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
434 return write((uint32_t)data
, addr
, flags
, res
);
439 AtomicSimpleCPU::tick()
441 Tick latency
= cycles(1); // instruction takes one cycle by default
443 for (int i
= 0; i
< width
; ++i
) {
446 checkForInterrupts();
448 Fault fault
= setupFetchRequest(ifetch_req
);
450 if (fault
== NoFault
) {
451 ifetch_pkt
->reinitFromRequest();
453 Tick icache_latency
= icachePort
.sendAtomic(ifetch_pkt
);
454 // ifetch_req is initialized to read the instruction directly
455 // into the CPU object's inst field.
457 dcache_access
= false; // assume no dcache access
459 fault
= curStaticInst
->execute(this, traceData
);
462 if (simulate_stalls
) {
463 Tick icache_stall
= icache_latency
- cycles(1);
465 dcache_access
? dcache_latency
- cycles(1) : 0;
466 Tick stall_cycles
= (icache_stall
+ dcache_stall
) / cycles(1);
467 if (cycles(stall_cycles
) < (icache_stall
+ dcache_stall
))
468 latency
+= cycles(stall_cycles
+1);
470 latency
+= cycles(stall_cycles
);
479 tickEvent
.schedule(curTick
+ latency
);
483 ////////////////////////////////////////////////////////////////////////
485 // AtomicSimpleCPU Simulation Object
487 BEGIN_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU
)
489 Param
<Counter
> max_insts_any_thread
;
490 Param
<Counter
> max_insts_all_threads
;
491 Param
<Counter
> max_loads_any_thread
;
492 Param
<Counter
> max_loads_all_threads
;
493 Param
<Tick
> progress_interval
;
494 SimObjectParam
<MemObject
*> mem
;
495 SimObjectParam
<System
*> system
;
499 SimObjectParam
<AlphaITB
*> itb
;
500 SimObjectParam
<AlphaDTB
*> dtb
;
503 SimObjectParam
<Process
*> workload
;
504 #endif // FULL_SYSTEM
508 Param
<bool> defer_registration
;
510 Param
<bool> function_trace
;
511 Param
<Tick
> function_trace_start
;
512 Param
<bool> simulate_stalls
;
514 END_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU
)
516 BEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU
)
518 INIT_PARAM(max_insts_any_thread
,
519 "terminate when any thread reaches this inst count"),
520 INIT_PARAM(max_insts_all_threads
,
521 "terminate when all threads have reached this inst count"),
522 INIT_PARAM(max_loads_any_thread
,
523 "terminate when any thread reaches this load count"),
524 INIT_PARAM(max_loads_all_threads
,
525 "terminate when all threads have reached this load count"),
526 INIT_PARAM(progress_interval
, "Progress interval"),
527 INIT_PARAM(mem
, "memory"),
528 INIT_PARAM(system
, "system object"),
529 INIT_PARAM(cpu_id
, "processor ID"),
532 INIT_PARAM(itb
, "Instruction TLB"),
533 INIT_PARAM(dtb
, "Data TLB"),
534 INIT_PARAM(profile
, ""),
536 INIT_PARAM(workload
, "processes to run"),
537 #endif // FULL_SYSTEM
539 INIT_PARAM(clock
, "clock speed"),
540 INIT_PARAM(defer_registration
, "defer system registration (for sampling)"),
541 INIT_PARAM(width
, "cpu width"),
542 INIT_PARAM(function_trace
, "Enable function trace"),
543 INIT_PARAM(function_trace_start
, "Cycle to start function trace"),
544 INIT_PARAM(simulate_stalls
, "Simulate cache stall cycles")
546 END_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU
)
549 CREATE_SIM_OBJECT(AtomicSimpleCPU
)
551 AtomicSimpleCPU::Params
*params
= new AtomicSimpleCPU::Params();
552 params
->name
= getInstanceName();
553 params
->numberOfThreads
= 1;
554 params
->max_insts_any_thread
= max_insts_any_thread
;
555 params
->max_insts_all_threads
= max_insts_all_threads
;
556 params
->max_loads_any_thread
= max_loads_any_thread
;
557 params
->max_loads_all_threads
= max_loads_all_threads
;
558 params
->progress_interval
= progress_interval
;
559 params
->deferRegistration
= defer_registration
;
560 params
->clock
= clock
;
561 params
->functionTrace
= function_trace
;
562 params
->functionTraceStart
= function_trace_start
;
563 params
->width
= width
;
564 params
->simulate_stalls
= simulate_stalls
;
566 params
->system
= system
;
567 params
->cpu_id
= cpu_id
;
572 params
->profile
= profile
;
574 params
->process
= workload
;
577 AtomicSimpleCPU
*cpu
= new AtomicSimpleCPU(params
);
581 REGISTER_SIM_OBJECT("AtomicSimpleCPU", AtomicSimpleCPU
)