atomic.cc revision 2626
1955SN/A/*
2955SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
31762SN/A * All rights reserved.
4955SN/A *
5955SN/A * Redistribution and use in source and binary forms, with or without
6955SN/A * modification, are permitted provided that the following conditions are
7955SN/A * met: redistributions of source code must retain the above copyright
8955SN/A * notice, this list of conditions and the following disclaimer;
9955SN/A * redistributions in binary form must reproduce the above copyright
10955SN/A * notice, this list of conditions and the following disclaimer in the
11955SN/A * documentation and/or other materials provided with the distribution;
12955SN/A * neither the name of the copyright holders nor the names of its
13955SN/A * contributors may be used to endorse or promote products derived from
14955SN/A * this software without specific prior written permission.
15955SN/A *
16955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23955SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24955SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27955SN/A */
282665Ssaidi@eecs.umich.edu
292665Ssaidi@eecs.umich.edu#include "arch/utility.hh"
30955SN/A#include "cpu/exetrace.hh"
31955SN/A#include "cpu/simple/atomic.hh"
32955SN/A#include "mem/packet_impl.hh"
331608SN/A#include "sim/builder.hh"
34955SN/A
35955SN/Ausing namespace std;
36955SN/Ausing namespace TheISA;
37955SN/A
38955SN/AAtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
39955SN/A    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
40955SN/A{
41955SN/A}
42955SN/A
43955SN/A
44955SN/Avoid
45955SN/AAtomicSimpleCPU::TickEvent::process()
46955SN/A{
47955SN/A    cpu->tick();
482023SN/A}
49955SN/A
50955SN/Aconst char *
51955SN/AAtomicSimpleCPU::TickEvent::description()
52955SN/A{
53955SN/A    return "AtomicSimpleCPU tick event";
54955SN/A}
55955SN/A
56955SN/A
57955SN/Avoid
581031SN/AAtomicSimpleCPU::init()
59955SN/A{
601388SN/A    //Create Memory Ports (conect them up)
61955SN/A    Port *mem_dport = mem->getPort("");
62955SN/A    dcachePort.setPeer(mem_dport);
631296SN/A    mem_dport->setPeer(&dcachePort);
64955SN/A
652609SN/A    Port *mem_iport = mem->getPort("");
66955SN/A    icachePort.setPeer(mem_iport);
67955SN/A    mem_iport->setPeer(&icachePort);
68955SN/A
69955SN/A    BaseCPU::init();
70955SN/A#if FULL_SYSTEM
71955SN/A    for (int i = 0; i < execContexts.size(); ++i) {
72955SN/A        ExecContext *xc = execContexts[i];
73955SN/A
74955SN/A        // initialize CPU, including PC
75955SN/A        TheISA::initCPU(xc, xc->readCpuId());
76955SN/A    }
77955SN/A#endif
78955SN/A}
79955SN/A
80955SN/Abool
81955SN/AAtomicSimpleCPU::CpuPort::recvTiming(Packet &pkt)
82955SN/A{
83955SN/A    panic("AtomicSimpleCPU doesn't expect recvAtomic callback!");
841717SN/A    return true;
852190SN/A}
862652Ssaidi@eecs.umich.edu
87955SN/ATick
882410SN/AAtomicSimpleCPU::CpuPort::recvAtomic(Packet &pkt)
89955SN/A{
90955SN/A    panic("AtomicSimpleCPU doesn't expect recvAtomic callback!");
911717SN/A    return curTick;
922568SN/A}
932568SN/A
942568SN/Avoid
952499SN/AAtomicSimpleCPU::CpuPort::recvFunctional(Packet &pkt)
962462SN/A{
972568SN/A    panic("AtomicSimpleCPU doesn't expect recvFunctional callback!");
982395SN/A}
992405SN/A
100955SN/Avoid
101955SN/AAtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
102955SN/A{
103955SN/A    if (status == RangeChange)
104955SN/A        return;
1052090SN/A
106955SN/A    panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
1072667Sstever@eecs.umich.edu}
108955SN/A
109955SN/APacket *
1101696SN/AAtomicSimpleCPU::CpuPort::recvRetry()
111955SN/A{
112955SN/A    panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
113955SN/A    return NULL;
1141127SN/A}
115955SN/A
116955SN/A
1172379SN/AAtomicSimpleCPU::AtomicSimpleCPU(Params *p)
118955SN/A    : BaseSimpleCPU(p), tickEvent(this),
119955SN/A      width(p->width), simulate_stalls(p->simulate_stalls),
120955SN/A      icachePort(this), dcachePort(this)
1212155SN/A{
1222155SN/A    _status = Idle;
1232155SN/A
1242155SN/A    ifetch_req = new Request(true);
1252155SN/A    ifetch_req->setAsid(0);
1262155SN/A    // @todo fix me and get the real cpu iD!!!
1272155SN/A    ifetch_req->setCpuNum(0);
1282155SN/A    ifetch_req->setSize(sizeof(MachInst));
1292155SN/A    ifetch_pkt = new Packet;
1302155SN/A    ifetch_pkt->cmd = Read;
1312155SN/A    ifetch_pkt->dataStatic(&inst);
1322155SN/A    ifetch_pkt->req = ifetch_req;
1332155SN/A    ifetch_pkt->size = sizeof(MachInst);
1342155SN/A    ifetch_pkt->dest = Packet::Broadcast;
1352155SN/A
1362155SN/A    data_read_req = new Request(true);
1372155SN/A    // @todo fix me and get the real cpu iD!!!
1382155SN/A    data_read_req->setCpuNum(0);
1392155SN/A    data_read_req->setAsid(0);
1402155SN/A    data_read_pkt = new Packet;
1412155SN/A    data_read_pkt->cmd = Read;
1422155SN/A    data_read_pkt->dataStatic(&dataReg);
1432155SN/A    data_read_pkt->req = data_read_req;
1442155SN/A    data_read_pkt->dest = Packet::Broadcast;
1452155SN/A
1462155SN/A    data_write_req = new Request(true);
1472155SN/A    // @todo fix me and get the real cpu iD!!!
1482155SN/A    data_write_req->setCpuNum(0);
1492155SN/A    data_write_req->setAsid(0);
1502155SN/A    data_write_pkt = new Packet;
1512155SN/A    data_write_pkt->cmd = Write;
1522155SN/A    data_write_pkt->req = data_write_req;
1532155SN/A    data_write_pkt->dest = Packet::Broadcast;
1542155SN/A}
1552155SN/A
1562155SN/A
1572155SN/AAtomicSimpleCPU::~AtomicSimpleCPU()
1582155SN/A{
1592155SN/A}
1602422SN/A
1612422SN/Avoid
1622422SN/AAtomicSimpleCPU::serialize(ostream &os)
1632422SN/A{
1642422SN/A    BaseSimpleCPU::serialize(os);
1652422SN/A    SERIALIZE_ENUM(_status);
1662422SN/A    nameOut(os, csprintf("%s.tickEvent", name()));
1672397SN/A    tickEvent.serialize(os);
1682397SN/A}
1692422SN/A
1702422SN/Avoid
171955SN/AAtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
172955SN/A{
173955SN/A    BaseSimpleCPU::unserialize(cp, section);
174955SN/A    UNSERIALIZE_ENUM(_status);
175955SN/A    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
176955SN/A}
177955SN/A
178955SN/Avoid
1791078SN/AAtomicSimpleCPU::switchOut(Sampler *s)
180955SN/A{
181955SN/A    sampler = s;
182955SN/A    if (status() == Running) {
183955SN/A        _status = SwitchedOut;
1841917SN/A
185955SN/A        tickEvent.squash();
186955SN/A    }
187955SN/A    sampler->signalSwitched();
188955SN/A}
189974SN/A
190955SN/A
191955SN/Avoid
192955SN/AAtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
193955SN/A{
1942566SN/A    BaseCPU::takeOverFrom(oldCPU);
1952566SN/A
196955SN/A    assert(!tickEvent.scheduled());
197955SN/A
1982539SN/A    // if any of this CPU's ExecContexts are active, mark the CPU as
199955SN/A    // running and schedule its tick event.
200955SN/A    for (int i = 0; i < execContexts.size(); ++i) {
201955SN/A        ExecContext *xc = execContexts[i];
2021817SN/A        if (xc->status() == ExecContext::Active && _status != Running) {
2031154SN/A            _status = Running;
2041840SN/A            tickEvent.schedule(curTick);
2052522SN/A            break;
2062522SN/A        }
2072629SN/A    }
208955SN/A}
209955SN/A
210955SN/A
2112539SN/Avoid
212955SN/AAtomicSimpleCPU::activateContext(int thread_num, int delay)
2132539SN/A{
214955SN/A    assert(thread_num == 0);
2151730SN/A    assert(cpuXC);
216955SN/A
2171070SN/A    assert(_status == Idle);
218955SN/A    assert(!tickEvent.scheduled());
219955SN/A
2202212SN/A    notIdleFraction++;
221955SN/A    tickEvent.schedule(curTick + cycles(delay));
2221040SN/A    _status = Running;
2232507SN/A}
2242521SN/A
2252521SN/A
2262507SN/Avoid
2272507SN/AAtomicSimpleCPU::suspendContext(int thread_num)
2282507SN/A{
2292521SN/A    assert(thread_num == 0);
2302507SN/A    assert(cpuXC);
2312507SN/A
232955SN/A    assert(_status == Running);
233955SN/A
234955SN/A    // tick event may not be scheduled if this gets called from inside
235955SN/A    // an instruction's execution, e.g. "quiesce"
236955SN/A    if (tickEvent.scheduled())
237955SN/A        tickEvent.deschedule();
2381742SN/A
2391742SN/A    notIdleFraction--;
2401742SN/A    _status = Idle;
2411742SN/A}
2421742SN/A
2431742SN/A
2441742SN/Atemplate <class T>
2451742SN/AFault
2461742SN/AAtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
2471742SN/A{
2481742SN/A    data_read_req->setVaddr(addr);
2491742SN/A    data_read_req->setSize(sizeof(T));
2501742SN/A    data_read_req->setFlags(flags);
2511742SN/A    data_read_req->setTime(curTick);
2521742SN/A
2531742SN/A    if (traceData) {
2541742SN/A        traceData->setAddr(addr);
2551742SN/A    }
2561742SN/A
2571742SN/A    // translate to physical address
258955SN/A    Fault fault = cpuXC->translateDataReadReq(data_read_req);
259955SN/A
2602520SN/A    // Now do the access.
2612517SN/A    if (fault == NoFault) {
2622253SN/A        data_read_pkt->reset();
2632253SN/A        data_read_pkt->addr = data_read_req->getPaddr();
2642253SN/A        data_read_pkt->size = sizeof(T);
2652253SN/A
2662553SN/A        dcache_complete = dcachePort.sendAtomic(*data_read_pkt);
2672553SN/A        dcache_access = true;
2682553SN/A
2692553SN/A        assert(data_read_pkt->result == Success);
2702507SN/A        data = data_read_pkt->get<T>();
2712470SN/A
2721744SN/A    }
2731744SN/A
2742470SN/A    // This will need a new way to tell if it has a dcache attached.
2752470SN/A    if (data_read_req->getFlags() & UNCACHEABLE)
2762470SN/A        recordEvent("Uncached Read");
2772470SN/A
2782470SN/A    return fault;
2792470SN/A}
2802400SN/A
2812400SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS
282955SN/A
283955SN/Atemplate
2842667Sstever@eecs.umich.eduFault
2852667Sstever@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
2862667Sstever@eecs.umich.edu
2872667Sstever@eecs.umich.edutemplate
2882667Sstever@eecs.umich.eduFault
2892667Sstever@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
2902037SN/A
2912037SN/Atemplate
2922037SN/AFault
2932667Sstever@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
2942139SN/A
2952667Sstever@eecs.umich.edutemplate
2962155SN/AFault
2972155SN/AAtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
2982155SN/A
2992155SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
3002155SN/A
3012155SN/Atemplate<>
302955SN/AFault
3032155SN/AAtomicSimpleCPU::read(Addr addr, double &data, unsigned flags)
304955SN/A{
305955SN/A    return read(addr, *(uint64_t*)&data, flags);
306955SN/A}
3071742SN/A
3081742SN/Atemplate<>
309955SN/AFault
310955SN/AAtomicSimpleCPU::read(Addr addr, float &data, unsigned flags)
311955SN/A{
3121858SN/A    return read(addr, *(uint32_t*)&data, flags);
313955SN/A}
3141858SN/A
3151858SN/A
3161858SN/Atemplate<>
3171085SN/AFault
318955SN/AAtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
319955SN/A{
320955SN/A    return read(addr, (uint32_t&)data, flags);
321955SN/A}
322955SN/A
323955SN/A
324955SN/Atemplate <class T>
325955SN/AFault
326955SN/AAtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
327955SN/A{
328955SN/A    data_write_req->setVaddr(addr);
329955SN/A    data_write_req->setTime(curTick);
3302667Sstever@eecs.umich.edu    data_write_req->setSize(sizeof(T));
3311045SN/A    data_write_req->setFlags(flags);
332955SN/A
333955SN/A    if (traceData) {
334955SN/A        traceData->setAddr(addr);
335955SN/A    }
3361108SN/A
337955SN/A    // translate to physical address
338955SN/A    Fault fault = cpuXC->translateDataWriteReq(data_write_req);
339955SN/A
340955SN/A    // Now do the access.
341955SN/A    if (fault == NoFault) {
342955SN/A        data_write_pkt->reset();
343955SN/A        data = htog(data);
344955SN/A        data_write_pkt->dataStatic(&data);
345955SN/A        data_write_pkt->addr = data_write_req->getPaddr();
346955SN/A        data_write_pkt->size = sizeof(T);
347955SN/A
348955SN/A        dcache_complete = dcachePort.sendAtomic(*data_write_pkt);
349955SN/A        dcache_access = true;
350955SN/A
351955SN/A        assert(data_write_pkt->result == Success);
352955SN/A    }
3532655Sstever@eecs.umich.edu
3542655Sstever@eecs.umich.edu    if (res && (fault == NoFault))
3552655Sstever@eecs.umich.edu        *res = data_write_pkt->result;
3562655Sstever@eecs.umich.edu
3572655Sstever@eecs.umich.edu    // This will need a new way to tell if it's hooked up to a cache or not.
3582655Sstever@eecs.umich.edu    if (data_write_req->getFlags() & UNCACHEABLE)
3592655Sstever@eecs.umich.edu        recordEvent("Uncached Write");
3602655Sstever@eecs.umich.edu
3612655Sstever@eecs.umich.edu    // @todo this is a hack and only works on uniprocessor systems
3622655Sstever@eecs.umich.edu    // some one else can implement LL/SC.
3632655Sstever@eecs.umich.edu    if (data_write_req->getFlags() & LOCKED)
3642655Sstever@eecs.umich.edu        *res = 1;
3652655Sstever@eecs.umich.edu
3662655Sstever@eecs.umich.edu    // If the write needs to have a fault on the access, consider calling
3672655Sstever@eecs.umich.edu    // changeStatus() and changing it to "bad addr write" or something.
3682655Sstever@eecs.umich.edu    return fault;
3692655Sstever@eecs.umich.edu}
3702655Sstever@eecs.umich.edu
3712655Sstever@eecs.umich.edu
3722655Sstever@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
3732655Sstever@eecs.umich.edutemplate
3742655Sstever@eecs.umich.eduFault
375955SN/AAtomicSimpleCPU::write(uint64_t data, Addr addr,
3762655Sstever@eecs.umich.edu                       unsigned flags, uint64_t *res);
3772655Sstever@eecs.umich.edu
3782655Sstever@eecs.umich.edutemplate
379955SN/AFault
380955SN/AAtomicSimpleCPU::write(uint32_t data, Addr addr,
3812655Sstever@eecs.umich.edu                       unsigned flags, uint64_t *res);
3822655Sstever@eecs.umich.edu
383955SN/Atemplate
384955SN/AFault
3852655Sstever@eecs.umich.eduAtomicSimpleCPU::write(uint16_t data, Addr addr,
3862655Sstever@eecs.umich.edu                       unsigned flags, uint64_t *res);
3872655Sstever@eecs.umich.edu
388955SN/Atemplate
389955SN/AFault
3902655Sstever@eecs.umich.eduAtomicSimpleCPU::write(uint8_t data, Addr addr,
3912655Sstever@eecs.umich.edu                       unsigned flags, uint64_t *res);
3922655Sstever@eecs.umich.edu
3931869SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
3941869SN/A
395template<>
396Fault
397AtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
398{
399    return write(*(uint64_t*)&data, addr, flags, res);
400}
401
402template<>
403Fault
404AtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
405{
406    return write(*(uint32_t*)&data, addr, flags, res);
407}
408
409
410template<>
411Fault
412AtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
413{
414    return write((uint32_t)data, addr, flags, res);
415}
416
417
418void
419AtomicSimpleCPU::tick()
420{
421    Tick latency = cycles(1); // instruction takes one cycle by default
422
423    for (int i = 0; i < width; ++i) {
424        numCycles++;
425
426        checkForInterrupts();
427
428        ifetch_req->resetMin();
429        ifetch_pkt->reset();
430        Fault fault = setupFetchPacket(ifetch_pkt);
431
432        if (fault == NoFault) {
433            Tick icache_complete = icachePort.sendAtomic(*ifetch_pkt);
434            // ifetch_req is initialized to read the instruction directly
435            // into the CPU object's inst field.
436
437            dcache_access = false; // assume no dcache access
438            preExecute();
439            fault = curStaticInst->execute(this, traceData);
440            postExecute();
441
442            if (traceData) {
443                traceData->finalize();
444            }
445
446            if (simulate_stalls) {
447                // This calculation assumes that the icache and dcache
448                // access latencies are always a multiple of the CPU's
449                // cycle time.  If not, the next tick event may get
450                // scheduled at a non-integer multiple of the CPU
451                // cycle time.
452                Tick icache_stall = icache_complete - curTick - cycles(1);
453                Tick dcache_stall =
454                    dcache_access ? dcache_complete - curTick - cycles(1) : 0;
455                latency += icache_stall + dcache_stall;
456            }
457
458        }
459
460        advancePC(fault);
461    }
462
463    if (_status != Idle)
464        tickEvent.schedule(curTick + latency);
465}
466
467
468////////////////////////////////////////////////////////////////////////
469//
470//  AtomicSimpleCPU Simulation Object
471//
472BEGIN_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
473
474    Param<Counter> max_insts_any_thread;
475    Param<Counter> max_insts_all_threads;
476    Param<Counter> max_loads_any_thread;
477    Param<Counter> max_loads_all_threads;
478    SimObjectParam<MemObject *> mem;
479
480#if FULL_SYSTEM
481    SimObjectParam<AlphaITB *> itb;
482    SimObjectParam<AlphaDTB *> dtb;
483    SimObjectParam<System *> system;
484    Param<int> cpu_id;
485    Param<Tick> profile;
486#else
487    SimObjectParam<Process *> workload;
488#endif // FULL_SYSTEM
489
490    Param<int> clock;
491
492    Param<bool> defer_registration;
493    Param<int> width;
494    Param<bool> function_trace;
495    Param<Tick> function_trace_start;
496    Param<bool> simulate_stalls;
497
498END_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
499
500BEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
501
502    INIT_PARAM(max_insts_any_thread,
503               "terminate when any thread reaches this inst count"),
504    INIT_PARAM(max_insts_all_threads,
505               "terminate when all threads have reached this inst count"),
506    INIT_PARAM(max_loads_any_thread,
507               "terminate when any thread reaches this load count"),
508    INIT_PARAM(max_loads_all_threads,
509               "terminate when all threads have reached this load count"),
510    INIT_PARAM(mem, "memory"),
511
512#if FULL_SYSTEM
513    INIT_PARAM(itb, "Instruction TLB"),
514    INIT_PARAM(dtb, "Data TLB"),
515    INIT_PARAM(system, "system object"),
516    INIT_PARAM(cpu_id, "processor ID"),
517    INIT_PARAM(profile, ""),
518#else
519    INIT_PARAM(workload, "processes to run"),
520#endif // FULL_SYSTEM
521
522    INIT_PARAM(clock, "clock speed"),
523    INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
524    INIT_PARAM(width, "cpu width"),
525    INIT_PARAM(function_trace, "Enable function trace"),
526    INIT_PARAM(function_trace_start, "Cycle to start function trace"),
527    INIT_PARAM(simulate_stalls, "Simulate cache stall cycles")
528
529END_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
530
531
532CREATE_SIM_OBJECT(AtomicSimpleCPU)
533{
534    AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params();
535    params->name = getInstanceName();
536    params->numberOfThreads = 1;
537    params->max_insts_any_thread = max_insts_any_thread;
538    params->max_insts_all_threads = max_insts_all_threads;
539    params->max_loads_any_thread = max_loads_any_thread;
540    params->max_loads_all_threads = max_loads_all_threads;
541    params->deferRegistration = defer_registration;
542    params->clock = clock;
543    params->functionTrace = function_trace;
544    params->functionTraceStart = function_trace_start;
545    params->width = width;
546    params->simulate_stalls = simulate_stalls;
547    params->mem = mem;
548
549#if FULL_SYSTEM
550    params->itb = itb;
551    params->dtb = dtb;
552    params->system = system;
553    params->cpu_id = cpu_id;
554    params->profile = profile;
555#else
556    params->process = workload;
557#endif
558
559    AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params);
560    return cpu;
561}
562
563REGISTER_SIM_OBJECT("AtomicSimpleCPU", AtomicSimpleCPU)
564
565