14661Sksewell@umich.edu/*
25268Sksewell@umich.edu * Copyright (c) 2007 MIPS Technologies, Inc.
35268Sksewell@umich.edu * All rights reserved.
44661Sksewell@umich.edu *
55268Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without
65268Sksewell@umich.edu * modification, are permitted provided that the following conditions are
75268Sksewell@umich.edu * met: redistributions of source code must retain the above copyright
85268Sksewell@umich.edu * notice, this list of conditions and the following disclaimer;
95268Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright
105268Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the
115268Sksewell@umich.edu * documentation and/or other materials provided with the distribution;
125268Sksewell@umich.edu * neither the name of the copyright holders nor the names of its
135268Sksewell@umich.edu * contributors may be used to endorse or promote products derived from
145268Sksewell@umich.edu * this software without specific prior written permission.
154661Sksewell@umich.edu *
165268Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
175268Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185268Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195268Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
205268Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215268Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225268Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235268Sksewell@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245268Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255268Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265268Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275222Sksewell@umich.edu *
285254Sksewell@umich.edu * Authors: Korey Sewell
294661Sksewell@umich.edu */
304661Sksewell@umich.edu
314661Sksewell@umich.edu#ifndef __ARCH_MIPS_MT_HH__
324661Sksewell@umich.edu#define __ARCH_MIPS_MT_HH__
334661Sksewell@umich.edu
344661Sksewell@umich.edu/**
354661Sksewell@umich.edu * @file
364661Sksewell@umich.edu *
374661Sksewell@umich.edu * ISA-specific helper functions for multithreaded execution.
384661Sksewell@umich.edu */
394661Sksewell@umich.edu
408229Snate@binkert.org#include <iostream>
418229Snate@binkert.org
424661Sksewell@umich.edu#include "arch/mips/faults.hh"
436329Sgblack@eecs.umich.edu#include "arch/mips/isa_traits.hh"
444661Sksewell@umich.edu#include "arch/mips/mt_constants.hh"
456376Sgblack@eecs.umich.edu#include "arch/mips/pra_constants.hh"
466329Sgblack@eecs.umich.edu#include "arch/mips/registers.hh"
474661Sksewell@umich.edu#include "base/bitfield.hh"
4812334Sgabeblack@google.com#include "base/logging.hh"
494661Sksewell@umich.edu#include "base/trace.hh"
5013899Sgabeblack@google.com#include "cpu/exec_context.hh"
514661Sksewell@umich.edu
524661Sksewell@umich.edunamespace MipsISA
534661Sksewell@umich.edu{
544661Sksewell@umich.edu
5513899Sgabeblack@google.comstatic inline RegVal
5613899Sgabeblack@google.comreadRegOtherThread(ThreadContext *tc, const RegId &reg,
5713899Sgabeblack@google.com                   ThreadID tid=InvalidThreadID)
5813899Sgabeblack@google.com{
5913899Sgabeblack@google.com    ThreadContext *otc = nullptr;
6013899Sgabeblack@google.com    if (tid != InvalidThreadID)
6113899Sgabeblack@google.com        otc = tc->getCpuPtr()->getContext(tid);
6213899Sgabeblack@google.com    else
6313899Sgabeblack@google.com        otc = tc;
6413899Sgabeblack@google.com
6513899Sgabeblack@google.com    switch (reg.classValue()) {
6613899Sgabeblack@google.com      case IntRegClass:
6713899Sgabeblack@google.com        return otc->readIntReg(reg.index());
6813899Sgabeblack@google.com        break;
6913899Sgabeblack@google.com      case FloatRegClass:
7013899Sgabeblack@google.com        return otc->readFloatReg(reg.index());
7113899Sgabeblack@google.com        break;
7213899Sgabeblack@google.com      case MiscRegClass:
7313899Sgabeblack@google.com        return otc->readMiscReg(reg.index());
7413899Sgabeblack@google.com      default:
7513899Sgabeblack@google.com        panic("Unexpected reg class! (%s)", reg.className());
7613899Sgabeblack@google.com    }
7713899Sgabeblack@google.com}
7813899Sgabeblack@google.com
7913899Sgabeblack@google.comstatic inline void
8013899Sgabeblack@google.comsetRegOtherThread(ThreadContext *tc, const RegId& reg, RegVal val,
8113899Sgabeblack@google.com                  ThreadID tid=InvalidThreadID)
8213899Sgabeblack@google.com{
8313899Sgabeblack@google.com    ThreadContext *otc = nullptr;
8413899Sgabeblack@google.com    if (tid != InvalidThreadID)
8513899Sgabeblack@google.com        otc = tc->getCpuPtr()->getContext(tid);
8613899Sgabeblack@google.com    else
8713899Sgabeblack@google.com        otc = tc;
8813899Sgabeblack@google.com
8913899Sgabeblack@google.com    switch (reg.classValue()) {
9013899Sgabeblack@google.com      case IntRegClass:
9113899Sgabeblack@google.com        return otc->setIntReg(reg.index(), val);
9213899Sgabeblack@google.com        break;
9313899Sgabeblack@google.com      case FloatRegClass:
9413899Sgabeblack@google.com        return otc->setFloatReg(reg.index(), val);
9513899Sgabeblack@google.com        break;
9613899Sgabeblack@google.com      case MiscRegClass:
9713899Sgabeblack@google.com        return otc->setMiscReg(reg.index(), val);
9813899Sgabeblack@google.com      default:
9913899Sgabeblack@google.com        panic("Unexpected reg class! (%s)", reg.className());
10013899Sgabeblack@google.com    }
10113899Sgabeblack@google.com}
10213899Sgabeblack@google.com
10313899Sgabeblack@google.comstatic inline RegVal
10413899Sgabeblack@google.comreadRegOtherThread(ExecContext *xc, const RegId &reg,
10513899Sgabeblack@google.com                   ThreadID tid=InvalidThreadID)
10613899Sgabeblack@google.com{
10713899Sgabeblack@google.com    return readRegOtherThread(xc->tcBase(), reg, tid);
10813899Sgabeblack@google.com}
10913899Sgabeblack@google.com
11013899Sgabeblack@google.comstatic inline void
11113899Sgabeblack@google.comsetRegOtherThread(ExecContext *xc, const RegId& reg, RegVal val,
11213899Sgabeblack@google.com                  ThreadID tid=InvalidThreadID)
11313899Sgabeblack@google.com{
11413899Sgabeblack@google.com    setRegOtherThread(xc->tcBase(), reg, val, tid);
11513899Sgabeblack@google.com}
11613899Sgabeblack@google.com
1174661Sksewell@umich.edutemplate <class TC>
1184661Sksewell@umich.eduinline unsigned
1194661Sksewell@umich.edugetVirtProcNum(TC *tc)
1204661Sksewell@umich.edu{
1216383Sgblack@eecs.umich.edu    TCBindReg tcbind = tc->readMiscRegNoEffect(MISCREG_TC_BIND);
1226376Sgblack@eecs.umich.edu    return tcbind.curVPE;
1234661Sksewell@umich.edu}
1244661Sksewell@umich.edu
1254661Sksewell@umich.edutemplate <class TC>
1264661Sksewell@umich.eduinline unsigned
1274661Sksewell@umich.edugetTargetThread(TC *tc)
1284661Sksewell@umich.edu{
1296383Sgblack@eecs.umich.edu    VPEControlReg vpeCtrl = tc->readMiscRegNoEffect(MISCREG_VPE_CONTROL);
1306376Sgblack@eecs.umich.edu    return vpeCtrl.targTC;
1314661Sksewell@umich.edu}
1324661Sksewell@umich.edu
1334661Sksewell@umich.edutemplate <class TC>
1344661Sksewell@umich.eduinline void
1354661Sksewell@umich.eduhaltThread(TC *tc)
1364661Sksewell@umich.edu{
1374661Sksewell@umich.edu    if (tc->status() == TC::Active) {
1384661Sksewell@umich.edu        tc->halt();
1394661Sksewell@umich.edu
1404661Sksewell@umich.edu        // Save last known PC in TCRestart
1416378Sgblack@eecs.umich.edu        // @TODO: Needs to check if this is a branch and if so,
1426378Sgblack@eecs.umich.edu        // take previous instruction
1437720Sgblack@eecs.umich.edu        PCState pc = tc->pcState();
1447720Sgblack@eecs.umich.edu        tc->setMiscReg(MISCREG_TC_RESTART, pc.npc());
1454661Sksewell@umich.edu
1466378Sgblack@eecs.umich.edu        warn("%i: Halting thread %i in %s @ PC %x, setting restart PC to %x",
1477823Ssteve.reinhardt@amd.com                curTick(), tc->threadId(), tc->getCpuPtr()->name(),
1487720Sgblack@eecs.umich.edu                pc.pc(), pc.npc());
1494661Sksewell@umich.edu    }
1504661Sksewell@umich.edu}
1514661Sksewell@umich.edu
1524661Sksewell@umich.edutemplate <class TC>
1534661Sksewell@umich.eduinline void
1544661Sksewell@umich.edurestoreThread(TC *tc)
1554661Sksewell@umich.edu{
1564661Sksewell@umich.edu    if (tc->status() != TC::Active) {
1574661Sksewell@umich.edu        // Restore PC from TCRestart
1587720Sgblack@eecs.umich.edu        Addr restartPC = tc->readMiscRegNoEffect(MISCREG_TC_RESTART);
1594661Sksewell@umich.edu
1604661Sksewell@umich.edu        // TODO: SET PC WITH AN EVENT INSTEAD OF INSTANTANEOUSLY
1617720Sgblack@eecs.umich.edu        tc->pcState(restartPC);
16210407Smitch.hayenga@arm.com        tc->activate();
1634661Sksewell@umich.edu
1646378Sgblack@eecs.umich.edu        warn("%i: Restoring thread %i in %s @ PC %x",
1657823Ssteve.reinhardt@amd.com                curTick(), tc->threadId(), tc->getCpuPtr()->name(), restartPC);
1664661Sksewell@umich.edu    }
1674661Sksewell@umich.edu}
1684661Sksewell@umich.edu
1694661Sksewell@umich.edutemplate <class TC>
1704661Sksewell@umich.eduvoid
1714661Sksewell@umich.eduforkThread(TC *tc, Fault &fault, int Rd_bits, int Rs, int Rt)
1724661Sksewell@umich.edu{
1736383Sgblack@eecs.umich.edu    MVPConf0Reg mvpConf = tc->readMiscRegNoEffect(MISCREG_MVP_CONF0);
1746376Sgblack@eecs.umich.edu    int num_threads = mvpConf.ptc + 1;
1754661Sksewell@umich.edu
1764661Sksewell@umich.edu    int success = 0;
1776221Snate@binkert.org    for (ThreadID tid = 0; tid < num_threads && success == 0; tid++) {
1786376Sgblack@eecs.umich.edu        TCBindReg tidTCBind =
17913899Sgabeblack@google.com            readRegOtherThread(tc, RegId(MiscRegClass, MISCREG_TC_BIND), tid);
1806383Sgblack@eecs.umich.edu        TCBindReg tcBind = tc->readMiscRegNoEffect(MISCREG_TC_BIND);
1814661Sksewell@umich.edu
1826424Snate@binkert.org        if (tidTCBind.curVPE == tcBind.curVPE) {
1834661Sksewell@umich.edu
1846376Sgblack@eecs.umich.edu            TCStatusReg tidTCStatus =
18513899Sgabeblack@google.com                readRegOtherThread(tc, RegId(MiscRegClass, MISCREG_TC_STATUS),
18612104Snathanael.premillieu@arm.com                                       tid);
1874661Sksewell@umich.edu
1886376Sgblack@eecs.umich.edu            TCHaltReg tidTCHalt =
18913899Sgabeblack@google.com                readRegOtherThread(tc, RegId(MiscRegClass, MISCREG_TC_HALT),
19012104Snathanael.premillieu@arm.com                                       tid);
1914661Sksewell@umich.edu
1926376Sgblack@eecs.umich.edu            if (tidTCStatus.da == 1 && tidTCHalt.h == 0 &&
1936376Sgblack@eecs.umich.edu                tidTCStatus.a == 0 && success == 0) {
1944661Sksewell@umich.edu
19513899Sgabeblack@google.com                setRegOtherThread(tc, RegId(MiscRegClass, MISCREG_TC_RESTART),
19612104Snathanael.premillieu@arm.com                                      Rs, tid);
19713899Sgabeblack@google.com                setRegOtherThread(tc, RegId(IntRegClass, Rd_bits), Rt, tid);
1984661Sksewell@umich.edu
1996383Sgblack@eecs.umich.edu                StatusReg status = tc->readMiscReg(MISCREG_STATUS);
2006383Sgblack@eecs.umich.edu                TCStatusReg tcStatus = tc->readMiscReg(MISCREG_TC_STATUS);
2014661Sksewell@umich.edu
2024661Sksewell@umich.edu                // Set Run-State to Running
2036376Sgblack@eecs.umich.edu                tidTCStatus.rnst = 0;
2044661Sksewell@umich.edu                // Set Delay-Slot to 0
2056376Sgblack@eecs.umich.edu                tidTCStatus.tds = 0;
2064661Sksewell@umich.edu                // Set Dirty TC to 1
2076376Sgblack@eecs.umich.edu                tidTCStatus.dt = 1;
2084661Sksewell@umich.edu                // Set Activated to 1
2096376Sgblack@eecs.umich.edu                tidTCStatus.a = 1;
2104661Sksewell@umich.edu                // Set status to previous thread's status
2116376Sgblack@eecs.umich.edu                tidTCStatus.tksu = status.ksu;
2124661Sksewell@umich.edu                // Set ASID to previous thread's state
2136376Sgblack@eecs.umich.edu                tidTCStatus.asid = tcStatus.asid;
2144661Sksewell@umich.edu
2154661Sksewell@umich.edu                // Write Status Register
21613899Sgabeblack@google.com                setRegOtherThread(tc, RegId(MiscRegClass, MISCREG_TC_STATUS),
2176376Sgblack@eecs.umich.edu                                      tidTCStatus, tid);
2184661Sksewell@umich.edu
2194661Sksewell@umich.edu                // Mark As Successful Fork
2204661Sksewell@umich.edu                success = 1;
2214661Sksewell@umich.edu            }
2224661Sksewell@umich.edu        } else {
2235991Ssteve.reinhardt@amd.com            std::cerr << "Bad VPEs" << std::endl;
2244661Sksewell@umich.edu        }
2254661Sksewell@umich.edu    }
2264661Sksewell@umich.edu
2274661Sksewell@umich.edu    if (success == 0) {
2286383Sgblack@eecs.umich.edu        VPEControlReg vpeControl =
2296383Sgblack@eecs.umich.edu            tc->readMiscRegNoEffect(MISCREG_VPE_CONTROL);
2306376Sgblack@eecs.umich.edu        vpeControl.excpt = 1;
2316383Sgblack@eecs.umich.edu        tc->setMiscReg(MISCREG_VPE_CONTROL, vpeControl);
23210474Sandreas.hansson@arm.com        fault = std::make_shared<ThreadFault>();
2334661Sksewell@umich.edu    }
2344661Sksewell@umich.edu}
2354661Sksewell@umich.edu
2364661Sksewell@umich.edu
2374661Sksewell@umich.edutemplate <class TC>
2384661Sksewell@umich.eduint
2394661Sksewell@umich.eduyieldThread(TC *tc, Fault &fault, int src_reg, uint32_t yield_mask)
2404661Sksewell@umich.edu{
2414661Sksewell@umich.edu    if (src_reg == 0) {
2426383Sgblack@eecs.umich.edu        MVPConf0Reg mvpConf0 = tc->readMiscRegNoEffect(MISCREG_MVP_CONF0);
2436376Sgblack@eecs.umich.edu        ThreadID num_threads = mvpConf0.ptc + 1;
2444661Sksewell@umich.edu
2454661Sksewell@umich.edu        int ok = 0;
2464661Sksewell@umich.edu
2474661Sksewell@umich.edu        // Get Current VPE & TC numbers from calling thread
2486383Sgblack@eecs.umich.edu        TCBindReg tcBind = tc->readMiscRegNoEffect(MISCREG_TC_BIND);
2494661Sksewell@umich.edu
2506221Snate@binkert.org        for (ThreadID tid = 0; tid < num_threads; tid++) {
2516376Sgblack@eecs.umich.edu            TCStatusReg tidTCStatus =
25213899Sgabeblack@google.com                readRegOtherThread(tc, RegId(MiscRegClass, MISCREG_TC_STATUS),
2536383Sgblack@eecs.umich.edu                                       tid);
2546376Sgblack@eecs.umich.edu            TCHaltReg tidTCHalt =
25513899Sgabeblack@google.com                readRegOtherThread(tc, RegId(MiscRegClass, MISCREG_TC_HALT),
2566383Sgblack@eecs.umich.edu                                       tid);
2576376Sgblack@eecs.umich.edu            TCBindReg tidTCBind =
25813899Sgabeblack@google.com                readRegOtherThread(tc, RegId(MiscRegClass, MISCREG_TC_BIND),
2596383Sgblack@eecs.umich.edu                                       tid);
2604661Sksewell@umich.edu
2616376Sgblack@eecs.umich.edu            if (tidTCBind.curVPE == tcBind.curVPE &&
2626376Sgblack@eecs.umich.edu                tidTCBind.curTC == tcBind.curTC &&
2636376Sgblack@eecs.umich.edu                tidTCStatus.da == 1 &&
2646376Sgblack@eecs.umich.edu                tidTCHalt.h == 0    &&
2656376Sgblack@eecs.umich.edu                tidTCStatus.a == 1) {
2664661Sksewell@umich.edu                ok = 1;
2674661Sksewell@umich.edu            }
2684661Sksewell@umich.edu        }
2694661Sksewell@umich.edu
2704661Sksewell@umich.edu        if (ok == 1) {
2716383Sgblack@eecs.umich.edu            TCStatusReg tcStatus = tc->readMiscRegNoEffect(MISCREG_TC_STATUS);
2726376Sgblack@eecs.umich.edu            tcStatus.a = 0;
2736383Sgblack@eecs.umich.edu            tc->setMiscReg(MISCREG_TC_STATUS, tcStatus);
2746376Sgblack@eecs.umich.edu            warn("%i: Deactivating Hardware Thread Context #%i",
2757823Ssteve.reinhardt@amd.com                    curTick(), tc->threadId());
2764661Sksewell@umich.edu        }
2774661Sksewell@umich.edu    } else if (src_reg > 0) {
2785561Snate@binkert.org        if (src_reg && !yield_mask != 0) {
2796383Sgblack@eecs.umich.edu            VPEControlReg vpeControl = tc->readMiscReg(MISCREG_VPE_CONTROL);
2806376Sgblack@eecs.umich.edu            vpeControl.excpt = 2;
2816383Sgblack@eecs.umich.edu            tc->setMiscReg(MISCREG_VPE_CONTROL, vpeControl);
28210474Sandreas.hansson@arm.com            fault = std::make_shared<ThreadFault>();
2834661Sksewell@umich.edu        } else {
2844661Sksewell@umich.edu        }
2854661Sksewell@umich.edu    } else if (src_reg != -2) {
2866383Sgblack@eecs.umich.edu        TCStatusReg tcStatus = tc->readMiscRegNoEffect(MISCREG_TC_STATUS);
2876383Sgblack@eecs.umich.edu        VPEControlReg vpeControl =
2886383Sgblack@eecs.umich.edu            tc->readMiscRegNoEffect(MISCREG_VPE_CONTROL);
2894661Sksewell@umich.edu
2906376Sgblack@eecs.umich.edu        if (vpeControl.ysi == 1 && tcStatus.dt == 1 ) {
2916376Sgblack@eecs.umich.edu            vpeControl.excpt = 4;
29210474Sandreas.hansson@arm.com            fault = std::make_shared<ThreadFault>();
2934661Sksewell@umich.edu        } else {
2944661Sksewell@umich.edu        }
2954661Sksewell@umich.edu    }
2964661Sksewell@umich.edu
2974661Sksewell@umich.edu    return src_reg & yield_mask;
2984661Sksewell@umich.edu}
2994661Sksewell@umich.edu
3004661Sksewell@umich.edu
3014661Sksewell@umich.edu// TC will usually be a object derived from ThreadContext
3024661Sksewell@umich.edu// (src/cpu/thread_context.hh)
3034661Sksewell@umich.edutemplate <class TC>
3044661Sksewell@umich.eduinline void
3054661Sksewell@umich.eduupdateStatusView(TC *tc)
3064661Sksewell@umich.edu{
3074661Sksewell@umich.edu    // TCStatus' register view must be the same as
3084661Sksewell@umich.edu    // Status register view for CU, MX, KSU bits
3096383Sgblack@eecs.umich.edu    TCStatusReg tcStatus = tc->readMiscRegNoEffect(MISCREG_TC_STATUS);
3106383Sgblack@eecs.umich.edu    StatusReg status = tc->readMiscRegNoEffect(MISCREG_STATUS);
3114661Sksewell@umich.edu
3126376Sgblack@eecs.umich.edu    status.cu = tcStatus.tcu;
3136376Sgblack@eecs.umich.edu    status.mx = tcStatus.tmx;
3146376Sgblack@eecs.umich.edu    status.ksu = tcStatus.tksu;
3154661Sksewell@umich.edu
3166383Sgblack@eecs.umich.edu    tc->setMiscRegNoEffect(MISCREG_STATUS, status);
3174661Sksewell@umich.edu}
3184661Sksewell@umich.edu
3194661Sksewell@umich.edu// TC will usually be a object derived from ThreadContext
3204661Sksewell@umich.edu// (src/cpu/thread_context.hh)
3214661Sksewell@umich.edutemplate <class TC>
3224661Sksewell@umich.eduinline void
3234661Sksewell@umich.eduupdateTCStatusView(TC *tc)
3244661Sksewell@umich.edu{
3254661Sksewell@umich.edu    // TCStatus' register view must be the same as
3264661Sksewell@umich.edu    // Status register view for CU, MX, KSU bits
3276383Sgblack@eecs.umich.edu    TCStatusReg tcStatus = tc->readMiscRegNoEffect(MISCREG_TC_STATUS);
3286383Sgblack@eecs.umich.edu    StatusReg status = tc->readMiscRegNoEffect(MISCREG_STATUS);
3294661Sksewell@umich.edu
3306376Sgblack@eecs.umich.edu    tcStatus.tcu = status.cu;
3316376Sgblack@eecs.umich.edu    tcStatus.tmx = status.mx;
3326376Sgblack@eecs.umich.edu    tcStatus.tksu = status.ksu;
3334661Sksewell@umich.edu
3346383Sgblack@eecs.umich.edu    tc->setMiscRegNoEffect(MISCREG_TC_STATUS, tcStatus);
3354661Sksewell@umich.edu}
3364661Sksewell@umich.edu
3374661Sksewell@umich.edu} // namespace MipsISA
3384661Sksewell@umich.edu
3394661Sksewell@umich.edu
3404661Sksewell@umich.edu#endif
341