/*
 * Copyright (c) 2009 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include "arch/sparc/asi.hh"
#include "arch/sparc/isa.hh"
#include "base/bitfield.hh"
#include "base/trace.hh"
#include "config/full_system.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "debug/MiscRegs.hh"
#include "debug/Timer.hh"

namespace SparcISA
{

enum RegMask
{
    PSTATE_MASK = (((1 << 4) - 1) << 1) | (((1 << 4) - 1) << 6) | (1 << 12)
};

void
ISA::reloadRegMap()
{
    installGlobals(gl, CurrentGlobalsOffset);
    installWindow(cwp, CurrentWindowOffset);
    // Microcode registers.
    for (int i = 0; i < NumMicroIntRegs; i++)
        intRegMap[MicroIntOffset + i] = i + TotalGlobals + NWindows * 16;
    installGlobals(gl, NextGlobalsOffset);
    installWindow(cwp - 1, NextWindowOffset);
    installGlobals(gl, PreviousGlobalsOffset);
    installWindow(cwp + 1, PreviousWindowOffset);
}

void
ISA::installWindow(int cwp, int offset)
{
    assert(offset >= 0 && offset + NumWindowedRegs <= NumIntRegs);
    RegIndex *mapChunk = intRegMap + offset;
    for (int i = 0; i < NumWindowedRegs; i++)
        mapChunk[i] = TotalGlobals +
            ((i - cwp * RegsPerWindow + TotalWindowed) % (TotalWindowed));
}

void
ISA::installGlobals(int gl, int offset)
{
    assert(offset >= 0 && offset + NumGlobalRegs <= NumIntRegs);
    RegIndex *mapChunk = intRegMap + offset;
    mapChunk[0] = 0;
    for (int i = 1; i < NumGlobalRegs; i++)
        mapChunk[i] = i + gl * NumGlobalRegs;
}

void
ISA::clear()
{
    cwp = 0;
    gl = 0;
    reloadRegMap();

    // y = 0;
    // ccr = 0;
    asi = 0;
    tick = ULL(1) << 63;
    fprs = 0;
    gsr = 0;
    softint = 0;
    tick_cmpr = 0;
    stick = 0;
    stick_cmpr = 0;
    memset(tpc, 0, sizeof(tpc));
    memset(tnpc, 0, sizeof(tnpc));
    memset(tstate, 0, sizeof(tstate));
    memset(tt, 0, sizeof(tt));
    tba = 0;
    pstate = 0;
    tl = 0;
    pil = 0;
    // cansave = 0;
    // canrestore = 0;
    // cleanwin = 0;
    // otherwin = 0;
    // wstate = 0;
    // In a T1, bit 11 is apparently always 1
    hpstate = (1 << 11);
    memset(htstate, 0, sizeof(htstate));
    hintp = 0;
    htba = 0;
    hstick_cmpr = 0;
    // This is set this way in Legion for some reason
    strandStatusReg = 0x50000;
    fsr = 0;

    priContext = 0;
    secContext = 0;
    partId = 0;
    lsuCtrlReg = 0;

    memset(scratchPad, 0, sizeof(scratchPad));

    cpu_mondo_head = 0;
    cpu_mondo_tail = 0;
    dev_mondo_head = 0;
    dev_mondo_tail = 0;
    res_error_head = 0;
    res_error_tail = 0;
    nres_error_head = 0;
    nres_error_tail = 0;

#if FULL_SYSTEM
    // If one of these events is active, it's not obvious to me how to get
    // rid of it cleanly. For now we'll just assert that they're not.
    if (tickCompare != NULL && sTickCompare != NULL && hSTickCompare != NULL)
        panic("Tick comparison event active when clearing the ISA object.\n");
#endif
}

MiscReg
ISA::readMiscRegNoEffect(int miscReg)
{

  // The three miscRegs are moved up from the switch statement
  // due to more frequent calls.

  if (miscReg == MISCREG_GL)
    return gl;
  if (miscReg == MISCREG_CWP)
    return cwp;
  if (miscReg == MISCREG_TLB_DATA) {
    /* Package up all the data for the tlb:
     * 6666555555555544444444443333333333222222222211111111110000000000
     * 3210987654321098765432109876543210987654321098765432109876543210
     *   secContext   | priContext    |             |tl|partid|  |||||^hpriv
     *                                                           ||||^red
     *                                                           |||^priv
     *                                                           ||^am
     *                                                           |^lsuim
     *                                                           ^lsudm
     */
    return bits((uint64_t)hpstate,2,2) |
           bits((uint64_t)hpstate,5,5) << 1 |
           bits((uint64_t)pstate,3,2) << 2 |
           bits((uint64_t)lsuCtrlReg,3,2) << 4 |
           bits((uint64_t)partId,7,0) << 8 |
           bits((uint64_t)tl,2,0) << 16 |
                (uint64_t)priContext << 32 |
                (uint64_t)secContext << 48;
  }

    switch (miscReg) {
      // case MISCREG_TLB_DATA:
      //  [original contents see above]
      // case MISCREG_Y:
      //  return y;
      // case MISCREG_CCR:
      //  return ccr;
      case MISCREG_ASI:
        return asi;
      case MISCREG_FPRS:
        return fprs;
      case MISCREG_TICK:
        return tick;
      case MISCREG_PCR:
        panic("PCR not implemented\n");
      case MISCREG_PIC:
        panic("PIC not implemented\n");
      case MISCREG_GSR:
        return gsr;
      case MISCREG_SOFTINT:
        return softint;
      case MISCREG_TICK_CMPR:
        return tick_cmpr;
      case MISCREG_STICK:
        return stick;
      case MISCREG_STICK_CMPR:
        return stick_cmpr;

        /** Privilged Registers */
      case MISCREG_TPC:
        return tpc[tl-1];
      case MISCREG_TNPC:
        return tnpc[tl-1];
      case MISCREG_TSTATE:
        return tstate[tl-1];
      case MISCREG_TT:
        return tt[tl-1];
      case MISCREG_PRIVTICK:
        panic("Priviliged access to tick registers not implemented\n");
      case MISCREG_TBA:
        return tba;
      case MISCREG_PSTATE:
        return pstate;
      case MISCREG_TL:
        return tl;
      case MISCREG_PIL:
        return pil;
      // CWP, GL moved
      // case MISCREG_CWP:
      //   return cwp;
      // case MISCREG_CANSAVE:
      //   return cansave;
      // case MISCREG_CANRESTORE:
      //   return canrestore;
      // case MISCREG_CLEANWIN:
      //   return cleanwin;
      // case MISCREG_OTHERWIN:
      //   return otherwin;
      // case MISCREG_WSTATE:
      //   return wstate;
      // case MISCREG_GL:
      //   return gl;

        /** Hyper privileged registers */
      case MISCREG_HPSTATE:
        return hpstate;
      case MISCREG_HTSTATE:
        return htstate[tl-1];
      case MISCREG_HINTP:
        return hintp;
      case MISCREG_HTBA:
        return htba;
      case MISCREG_STRAND_STS_REG:
        return strandStatusReg;
      case MISCREG_HSTICK_CMPR:
        return hstick_cmpr;

        /** Floating Point Status Register */
      case MISCREG_FSR:
        DPRINTF(MiscRegs, "FSR read as: %#x\n", fsr);
        return fsr;

      case MISCREG_MMU_P_CONTEXT:
        return priContext;
      case MISCREG_MMU_S_CONTEXT:
        return secContext;
      case MISCREG_MMU_PART_ID:
        return partId;
      case MISCREG_MMU_LSU_CTRL:
        return lsuCtrlReg;

      case MISCREG_SCRATCHPAD_R0:
        return scratchPad[0];
      case MISCREG_SCRATCHPAD_R1:
        return scratchPad[1];
      case MISCREG_SCRATCHPAD_R2:
        return scratchPad[2];
      case MISCREG_SCRATCHPAD_R3:
        return scratchPad[3];
      case MISCREG_SCRATCHPAD_R4:
        return scratchPad[4];
      case MISCREG_SCRATCHPAD_R5:
        return scratchPad[5];
      case MISCREG_SCRATCHPAD_R6:
        return scratchPad[6];
      case MISCREG_SCRATCHPAD_R7:
        return scratchPad[7];
      case MISCREG_QUEUE_CPU_MONDO_HEAD:
        return cpu_mondo_head;
      case MISCREG_QUEUE_CPU_MONDO_TAIL:
        return cpu_mondo_tail;
      case MISCREG_QUEUE_DEV_MONDO_HEAD:
        return dev_mondo_head;
      case MISCREG_QUEUE_DEV_MONDO_TAIL:
        return dev_mondo_tail;
      case MISCREG_QUEUE_RES_ERROR_HEAD:
        return res_error_head;
      case MISCREG_QUEUE_RES_ERROR_TAIL:
        return res_error_tail;
      case MISCREG_QUEUE_NRES_ERROR_HEAD:
        return nres_error_head;
      case MISCREG_QUEUE_NRES_ERROR_TAIL:
        return nres_error_tail;
      default:
        panic("Miscellaneous register %d not implemented\n", miscReg);
    }
}

MiscReg
ISA::readMiscReg(int miscReg, ThreadContext * tc)
{
    switch (miscReg) {
        // tick and stick are aliased to each other in niagra
        // well store the tick data in stick and the interrupt bit in tick
      case MISCREG_STICK:
      case MISCREG_TICK:
      case MISCREG_PRIVTICK:
        // I'm not sure why legion ignores the lowest two bits, but we'll go
        // with it
        // change from curCycle() to instCount() until we're done with legion
        DPRINTF(Timer, "Instruction Count when TICK read: %#X stick=%#X\n",
                tc->getCpuPtr()->instCount(), stick);
        return mbits(tc->getCpuPtr()->instCount() + (int64_t)stick,62,2) |
               mbits(tick,63,63);
      case MISCREG_FPRS:
        // in legion if fp is enabled du and dl are set
        return fprs | 0x3;
      case MISCREG_PCR:
      case MISCREG_PIC:
        panic("Performance Instrumentation not impl\n");
      case MISCREG_SOFTINT_CLR:
      case MISCREG_SOFTINT_SET:
        panic("Can read from softint clr/set\n");
      case MISCREG_SOFTINT:
      case MISCREG_TICK_CMPR:
      case MISCREG_STICK_CMPR:
      case MISCREG_HINTP:
      case MISCREG_HTSTATE:
      case MISCREG_HTBA:
      case MISCREG_HVER:
      case MISCREG_STRAND_STS_REG:
      case MISCREG_HSTICK_CMPR:
      case MISCREG_QUEUE_CPU_MONDO_HEAD:
      case MISCREG_QUEUE_CPU_MONDO_TAIL:
      case MISCREG_QUEUE_DEV_MONDO_HEAD:
      case MISCREG_QUEUE_DEV_MONDO_TAIL:
      case MISCREG_QUEUE_RES_ERROR_HEAD:
      case MISCREG_QUEUE_RES_ERROR_TAIL:
      case MISCREG_QUEUE_NRES_ERROR_HEAD:
      case MISCREG_QUEUE_NRES_ERROR_TAIL:
#if FULL_SYSTEM
      case MISCREG_HPSTATE:
        return readFSReg(miscReg, tc);
#else
      case MISCREG_HPSTATE:
        // HPSTATE is special because because sometimes in privilege
        // checks for instructions it will read HPSTATE to make sure
        // the priv. level is ok So, we'll just have to tell it it
        // isn't, instead of panicing.
        return 0;

      panic("Accessing Fullsystem register %d in SE mode\n", miscReg);
#endif

    }
    return readMiscRegNoEffect(miscReg);
}

void
ISA::setMiscRegNoEffect(int miscReg, MiscReg val)
{
    switch (miscReg) {
//      case MISCREG_Y:
//        y = val;
//        break;
//      case MISCREG_CCR:
//        ccr = val;
//        break;
      case MISCREG_ASI:
        asi = val;
        break;
      case MISCREG_FPRS:
        fprs = val;
        break;
      case MISCREG_TICK:
        tick = val;
        break;
      case MISCREG_PCR:
        panic("PCR not implemented\n");
      case MISCREG_PIC:
        panic("PIC not implemented\n");
      case MISCREG_GSR:
        gsr = val;
        break;
      case MISCREG_SOFTINT:
        softint = val;
        break;
      case MISCREG_TICK_CMPR:
        tick_cmpr = val;
        break;
      case MISCREG_STICK:
        stick = val;
        break;
      case MISCREG_STICK_CMPR:
        stick_cmpr = val;
        break;

        /** Privilged Registers */
      case MISCREG_TPC:
        tpc[tl-1] = val;
        break;
      case MISCREG_TNPC:
        tnpc[tl-1] = val;
        break;
      case MISCREG_TSTATE:
        tstate[tl-1] = val;
        break;
      case MISCREG_TT:
        tt[tl-1] = val;
        break;
      case MISCREG_PRIVTICK:
        panic("Priviliged access to tick regesiters not implemented\n");
      case MISCREG_TBA:
        // clear lower 7 bits on writes.
        tba = val & ULL(~0x7FFF);
        break;
      case MISCREG_PSTATE:
        pstate = (val & PSTATE_MASK);
        break;
      case MISCREG_TL:
        tl = val;
        break;
      case MISCREG_PIL:
        pil = val;
        break;
      case MISCREG_CWP:
        cwp = val;
        break;
//      case MISCREG_CANSAVE:
//        cansave = val;
//        break;
//      case MISCREG_CANRESTORE:
//        canrestore = val;
//        break;
//      case MISCREG_CLEANWIN:
//        cleanwin = val;
//        break;
//      case MISCREG_OTHERWIN:
//        otherwin = val;
//        break;
//      case MISCREG_WSTATE:
//        wstate = val;
//        break;
      case MISCREG_GL:
        gl = val;
        break;

        /** Hyper privileged registers */
      case MISCREG_HPSTATE:
        hpstate = val;
        break;
      case MISCREG_HTSTATE:
        htstate[tl-1] = val;
        break;
      case MISCREG_HINTP:
        hintp = val;
      case MISCREG_HTBA:
        htba = val;
        break;
      case MISCREG_STRAND_STS_REG:
        strandStatusReg = val;
        break;
      case MISCREG_HSTICK_CMPR:
        hstick_cmpr = val;
        break;

        /** Floating Point Status Register */
      case MISCREG_FSR:
        fsr = val;
        DPRINTF(MiscRegs, "FSR written with: %#x\n", fsr);
        break;

      case MISCREG_MMU_P_CONTEXT:
        priContext = val;
        break;
      case MISCREG_MMU_S_CONTEXT:
        secContext = val;
        break;
      case MISCREG_MMU_PART_ID:
        partId = val;
        break;
      case MISCREG_MMU_LSU_CTRL:
        lsuCtrlReg = val;
        break;

      case MISCREG_SCRATCHPAD_R0:
        scratchPad[0] = val;
        break;
      case MISCREG_SCRATCHPAD_R1:
        scratchPad[1] = val;
        break;
      case MISCREG_SCRATCHPAD_R2:
        scratchPad[2] = val;
        break;
      case MISCREG_SCRATCHPAD_R3:
        scratchPad[3] = val;
        break;
      case MISCREG_SCRATCHPAD_R4:
        scratchPad[4] = val;
        break;
      case MISCREG_SCRATCHPAD_R5:
        scratchPad[5] = val;
        break;
      case MISCREG_SCRATCHPAD_R6:
        scratchPad[6] = val;
        break;
      case MISCREG_SCRATCHPAD_R7:
        scratchPad[7] = val;
        break;
      case MISCREG_QUEUE_CPU_MONDO_HEAD:
        cpu_mondo_head = val;
        break;
      case MISCREG_QUEUE_CPU_MONDO_TAIL:
        cpu_mondo_tail = val;
        break;
      case MISCREG_QUEUE_DEV_MONDO_HEAD:
        dev_mondo_head = val;
        break;
      case MISCREG_QUEUE_DEV_MONDO_TAIL:
        dev_mondo_tail = val;
        break;
      case MISCREG_QUEUE_RES_ERROR_HEAD:
        res_error_head = val;
        break;
      case MISCREG_QUEUE_RES_ERROR_TAIL:
        res_error_tail = val;
        break;
      case MISCREG_QUEUE_NRES_ERROR_HEAD:
        nres_error_head = val;
        break;
      case MISCREG_QUEUE_NRES_ERROR_TAIL:
        nres_error_tail = val;
        break;
      default:
        panic("Miscellaneous register %d not implemented\n", miscReg);
    }
}

void
ISA::setMiscReg(int miscReg, MiscReg val, ThreadContext * tc)
{
    MiscReg new_val = val;

    switch (miscReg) {
      case MISCREG_STICK:
      case MISCREG_TICK:
        // stick and tick are same thing on niagra
        // use stick for offset and tick for holding intrrupt bit
        stick = mbits(val,62,0) - tc->getCpuPtr()->instCount();
        tick = mbits(val,63,63);
        DPRINTF(Timer, "Writing TICK=%#X\n", val);
        break;
      case MISCREG_FPRS:
        // Configure the fpu based on the fprs
        break;
      case MISCREG_PCR:
        // Set up performance counting based on pcr value
        break;
      case MISCREG_PSTATE:
        pstate = val & PSTATE_MASK;
        return;
      case MISCREG_TL:
        tl = val;
#if FULL_SYSTEM
        if (hpstate & HPSTATE::tlz && tl == 0 && !(hpstate & HPSTATE::hpriv))
            tc->getCpuPtr()->postInterrupt(IT_TRAP_LEVEL_ZERO, 0);
        else
            tc->getCpuPtr()->clearInterrupt(IT_TRAP_LEVEL_ZERO, 0);
#endif
        return;
      case MISCREG_CWP:
        new_val = val >= NWindows ? NWindows - 1 : val;
        if (val >= NWindows)
            new_val = NWindows - 1;

        installWindow(new_val, CurrentWindowOffset);
        installWindow(new_val - 1, NextWindowOffset);
        installWindow(new_val + 1, PreviousWindowOffset);
        break;
      case MISCREG_GL:
        installGlobals(val, CurrentGlobalsOffset);
        installGlobals(val, NextGlobalsOffset);
        installGlobals(val, PreviousGlobalsOffset);
        break;
      case MISCREG_PIL:
      case MISCREG_SOFTINT:
      case MISCREG_SOFTINT_SET:
      case MISCREG_SOFTINT_CLR:
      case MISCREG_TICK_CMPR:
      case MISCREG_STICK_CMPR:
      case MISCREG_HINTP:
      case MISCREG_HTSTATE:
      case MISCREG_HTBA:
      case MISCREG_HVER:
      case MISCREG_STRAND_STS_REG:
      case MISCREG_HSTICK_CMPR:
      case MISCREG_QUEUE_CPU_MONDO_HEAD:
      case MISCREG_QUEUE_CPU_MONDO_TAIL:
      case MISCREG_QUEUE_DEV_MONDO_HEAD:
      case MISCREG_QUEUE_DEV_MONDO_TAIL:
      case MISCREG_QUEUE_RES_ERROR_HEAD:
      case MISCREG_QUEUE_RES_ERROR_TAIL:
      case MISCREG_QUEUE_NRES_ERROR_HEAD:
      case MISCREG_QUEUE_NRES_ERROR_TAIL:
#if FULL_SYSTEM
      case MISCREG_HPSTATE:
        setFSReg(miscReg, val, tc);
        return;
#else
      case MISCREG_HPSTATE:
        // HPSTATE is special because normal trap processing saves HPSTATE when
        // it goes into a trap, and restores it when it returns.
        return;
      panic("Accessing Fullsystem register %d to %#x in SE mode\n",
              miscReg, val);
#endif
    }
    setMiscRegNoEffect(miscReg, new_val);
}

void
ISA::serialize(EventManager *em, std::ostream &os)
{
    SERIALIZE_SCALAR(asi);
    SERIALIZE_SCALAR(tick);
    SERIALIZE_SCALAR(fprs);
    SERIALIZE_SCALAR(gsr);
    SERIALIZE_SCALAR(softint);
    SERIALIZE_SCALAR(tick_cmpr);
    SERIALIZE_SCALAR(stick);
    SERIALIZE_SCALAR(stick_cmpr);
    SERIALIZE_ARRAY(tpc,MaxTL);
    SERIALIZE_ARRAY(tnpc,MaxTL);
    SERIALIZE_ARRAY(tstate,MaxTL);
    SERIALIZE_ARRAY(tt,MaxTL);
    SERIALIZE_SCALAR(tba);
    SERIALIZE_SCALAR(pstate);
    SERIALIZE_SCALAR(tl);
    SERIALIZE_SCALAR(pil);
    SERIALIZE_SCALAR(cwp);
    SERIALIZE_SCALAR(gl);
    SERIALIZE_SCALAR(hpstate);
    SERIALIZE_ARRAY(htstate,MaxTL);
    SERIALIZE_SCALAR(hintp);
    SERIALIZE_SCALAR(htba);
    SERIALIZE_SCALAR(hstick_cmpr);
    SERIALIZE_SCALAR(strandStatusReg);
    SERIALIZE_SCALAR(fsr);
    SERIALIZE_SCALAR(priContext);
    SERIALIZE_SCALAR(secContext);
    SERIALIZE_SCALAR(partId);
    SERIALIZE_SCALAR(lsuCtrlReg);
    SERIALIZE_ARRAY(scratchPad,8);
    SERIALIZE_SCALAR(cpu_mondo_head);
    SERIALIZE_SCALAR(cpu_mondo_tail);
    SERIALIZE_SCALAR(dev_mondo_head);
    SERIALIZE_SCALAR(dev_mondo_tail);
    SERIALIZE_SCALAR(res_error_head);
    SERIALIZE_SCALAR(res_error_tail);
    SERIALIZE_SCALAR(nres_error_head);
    SERIALIZE_SCALAR(nres_error_tail);
#if FULL_SYSTEM
    Tick tick_cmp = 0, stick_cmp = 0, hstick_cmp = 0;
    ThreadContext *tc = NULL;
    BaseCPU *cpu = NULL;
    int tc_num = 0;
    bool tick_intr_sched = true;

    if (tickCompare)
        tc = tickCompare->getTC();
    else if (sTickCompare)
        tc = sTickCompare->getTC();
    else if (hSTickCompare)
        tc = hSTickCompare->getTC();
    else
        tick_intr_sched = false;

    SERIALIZE_SCALAR(tick_intr_sched);

    if (tc) {
        cpu = tc->getCpuPtr();
        tc_num = cpu->findContext(tc);
        if (tickCompare && tickCompare->scheduled())
            tick_cmp = tickCompare->when();
        if (sTickCompare && sTickCompare->scheduled())
            stick_cmp = sTickCompare->when();
        if (hSTickCompare && hSTickCompare->scheduled())
            hstick_cmp = hSTickCompare->when();

        SERIALIZE_OBJPTR(cpu);
        SERIALIZE_SCALAR(tc_num);
        SERIALIZE_SCALAR(tick_cmp);
        SERIALIZE_SCALAR(stick_cmp);
        SERIALIZE_SCALAR(hstick_cmp);
    }
#endif
}

void
ISA::unserialize(EventManager *em, Checkpoint *cp, const std::string &section)
{
    UNSERIALIZE_SCALAR(asi);
    UNSERIALIZE_SCALAR(tick);
    UNSERIALIZE_SCALAR(fprs);
    UNSERIALIZE_SCALAR(gsr);
    UNSERIALIZE_SCALAR(softint);
    UNSERIALIZE_SCALAR(tick_cmpr);
    UNSERIALIZE_SCALAR(stick);
    UNSERIALIZE_SCALAR(stick_cmpr);
    UNSERIALIZE_ARRAY(tpc,MaxTL);
    UNSERIALIZE_ARRAY(tnpc,MaxTL);
    UNSERIALIZE_ARRAY(tstate,MaxTL);
    UNSERIALIZE_ARRAY(tt,MaxTL);
    UNSERIALIZE_SCALAR(tba);
    UNSERIALIZE_SCALAR(pstate);
    UNSERIALIZE_SCALAR(tl);
    UNSERIALIZE_SCALAR(pil);
    UNSERIALIZE_SCALAR(cwp);
    UNSERIALIZE_SCALAR(gl);
    reloadRegMap();
    UNSERIALIZE_SCALAR(hpstate);
    UNSERIALIZE_ARRAY(htstate,MaxTL);
    UNSERIALIZE_SCALAR(hintp);
    UNSERIALIZE_SCALAR(htba);
    UNSERIALIZE_SCALAR(hstick_cmpr);
    UNSERIALIZE_SCALAR(strandStatusReg);
    UNSERIALIZE_SCALAR(fsr);
    UNSERIALIZE_SCALAR(priContext);
    UNSERIALIZE_SCALAR(secContext);
    UNSERIALIZE_SCALAR(partId);
    UNSERIALIZE_SCALAR(lsuCtrlReg);
    UNSERIALIZE_ARRAY(scratchPad,8);
    UNSERIALIZE_SCALAR(cpu_mondo_head);
    UNSERIALIZE_SCALAR(cpu_mondo_tail);
    UNSERIALIZE_SCALAR(dev_mondo_head);
    UNSERIALIZE_SCALAR(dev_mondo_tail);
    UNSERIALIZE_SCALAR(res_error_head);
    UNSERIALIZE_SCALAR(res_error_tail);
    UNSERIALIZE_SCALAR(nres_error_head);
    UNSERIALIZE_SCALAR(nres_error_tail);

#if FULL_SYSTEM
    Tick tick_cmp = 0, stick_cmp = 0, hstick_cmp = 0;
    ThreadContext *tc = NULL;
    BaseCPU *cpu = NULL;
    int tc_num;
    bool tick_intr_sched;
    UNSERIALIZE_SCALAR(tick_intr_sched);
    if (tick_intr_sched) {
        UNSERIALIZE_OBJPTR(cpu);
        if (cpu) {
            UNSERIALIZE_SCALAR(tc_num);
            UNSERIALIZE_SCALAR(tick_cmp);
            UNSERIALIZE_SCALAR(stick_cmp);
            UNSERIALIZE_SCALAR(hstick_cmp);
            tc = cpu->getContext(tc_num);

            if (tick_cmp) {
                tickCompare = new TickCompareEvent(this, tc);
                em->schedule(tickCompare, tick_cmp);
            }
            if (stick_cmp)  {
                sTickCompare = new STickCompareEvent(this, tc);
                em->schedule(sTickCompare, stick_cmp);
            }
            if (hstick_cmp)  {
                hSTickCompare = new HSTickCompareEvent(this, tc);
                em->schedule(hSTickCompare, hstick_cmp);
            }
        }
    }

 #endif
}

}
