mt.hh revision 6376
1/*
2 * Copyright (c) 2007 MIPS Technologies, Inc.
3 * All rights reserved.
4 *
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.
15 *
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.
27 *
28 * Authors: Korey Sewell
29 */
30
31#ifndef __ARCH_MIPS_MT_HH__
32#define __ARCH_MIPS_MT_HH__
33
34/**
35 * @file
36 *
37 * ISA-specific helper functions for multithreaded execution.
38 */
39
40#include "arch/mips/faults.hh"
41#include "arch/mips/isa_traits.hh"
42#include "arch/mips/mt_constants.hh"
43#include "arch/mips/pra_constants.hh"
44#include "arch/mips/registers.hh"
45#include "base/bitfield.hh"
46#include "base/trace.hh"
47#include "base/misc.hh"
48
49#include <iostream>
50
51namespace MipsISA
52{
53
54
55template <class TC>
56inline unsigned
57getVirtProcNum(TC *tc)
58{
59    TCBindReg tcbind = tc->readMiscRegNoEffect(TCBind);
60    return tcbind.curVPE;
61}
62
63template <class TC>
64inline unsigned
65getTargetThread(TC *tc)
66{
67    VPEControlReg vpeCtrl = tc->readMiscRegNoEffect(VPEControl);
68    return vpeCtrl.targTC;
69}
70
71template <class TC>
72inline void
73haltThread(TC *tc)
74{
75    if (tc->status() == TC::Active) {
76        tc->halt();
77
78        // Save last known PC in TCRestart
79        // @TODO: Needs to check if this is a branch and if so, take previous instruction
80        tc->setMiscReg(TCRestart, tc->readNextPC());
81
82        warn("%i: Halting thread %i in %s @ PC %x, setting restart PC to %x", curTick, tc->threadId(), tc->getCpuPtr()->name(),
83             tc->readPC(), tc->readNextPC());
84    }
85}
86
87template <class TC>
88inline void
89restoreThread(TC *tc)
90{
91    if (tc->status() != TC::Active) {
92        // Restore PC from TCRestart
93        IntReg pc = tc->readMiscRegNoEffect(TCRestart);
94
95        // TODO: SET PC WITH AN EVENT INSTEAD OF INSTANTANEOUSLY
96        // tc->setPCEvent(pc, pc + 4, pc + 8);
97        tc->setPC(pc);
98        tc->setNextPC(pc + 4);
99        tc->setNextNPC(pc + 8);
100        tc->activate(0);
101
102        warn("%i: Restoring thread %i in %s @ PC %x", curTick, tc->threadId(), tc->getCpuPtr()->name(),
103             tc->readPC());
104    }
105}
106
107template <class TC>
108void
109forkThread(TC *tc, Fault &fault, int Rd_bits, int Rs, int Rt)
110{
111    MVPConf0Reg mvpConf = tc->readMiscRegNoEffect(MVPConf0);
112    int num_threads = mvpConf.ptc + 1;
113
114    int success = 0;
115    for (ThreadID tid = 0; tid < num_threads && success == 0; tid++) {
116        TCBindReg tidTCBind =
117            tc->readRegOtherThread(TCBind + Ctrl_Base_DepTag, tid);
118        TCBindReg tcBind = tc->readMiscRegNoEffect(TCBind);
119
120        if (tidTCBind.curVPE = tcBind.curVPE) {
121
122            TCStatusReg tidTCStatus =
123                tc->readRegOtherThread(TCStatus + Ctrl_Base_DepTag,tid);
124
125            TCHaltReg tidTCHalt =
126                tc->readRegOtherThread(TCHalt + Ctrl_Base_DepTag,tid);
127
128            if (tidTCStatus.da == 1 && tidTCHalt.h == 0 &&
129                tidTCStatus.a == 0 && success == 0) {
130
131                tc->setRegOtherThread(TCRestart + Ctrl_Base_DepTag, Rs, tid);
132                tc->setRegOtherThread(Rd_bits, Rt, tid);
133
134                StatusReg status = tc->readMiscReg(Status);
135                TCStatusReg tcStatus = tc->readMiscReg(TCStatus);
136
137                // Set Run-State to Running
138                tidTCStatus.rnst = 0;
139                // Set Delay-Slot to 0
140                tidTCStatus.tds = 0;
141                // Set Dirty TC to 1
142                tidTCStatus.dt = 1;
143                // Set Activated to 1
144                tidTCStatus.a = 1;
145                // Set status to previous thread's status
146                tidTCStatus.tksu = status.ksu;
147                // Set ASID to previous thread's state
148                tidTCStatus.asid = tcStatus.asid;
149
150                // Write Status Register
151                tc->setRegOtherThread(TCStatus + Ctrl_Base_DepTag,
152                                      tidTCStatus, tid);
153
154                // Mark As Successful Fork
155                success = 1;
156            }
157        } else {
158            std::cerr << "Bad VPEs" << std::endl;
159        }
160    }
161
162    if (success == 0) {
163        VPEControlReg vpeControl = tc->readMiscRegNoEffect(VPEControl);
164        vpeControl.excpt = 1;
165        tc->setMiscReg(VPEControl, vpeControl);
166        fault = new ThreadFault();
167    }
168}
169
170
171template <class TC>
172int
173yieldThread(TC *tc, Fault &fault, int src_reg, uint32_t yield_mask)
174{
175    if (src_reg == 0) {
176        MVPConf0Reg mvpConf0 = tc->readMiscRegNoEffect(MVPConf0);
177        ThreadID num_threads = mvpConf0.ptc + 1;
178
179        int ok = 0;
180
181        // Get Current VPE & TC numbers from calling thread
182        TCBindReg tcBind = tc->readMiscRegNoEffect(TCBind);
183
184        for (ThreadID tid = 0; tid < num_threads; tid++) {
185            TCStatusReg tidTCStatus =
186                tc->readRegOtherThread(TCStatus + Ctrl_Base_DepTag, tid);
187            TCHaltReg tidTCHalt =
188                tc->readRegOtherThread(TCHalt + Ctrl_Base_DepTag, tid);
189            TCBindReg tidTCBind =
190                tc->readRegOtherThread(TCBind + Ctrl_Base_DepTag, tid);
191
192            if (tidTCBind.curVPE == tcBind.curVPE &&
193                tidTCBind.curTC == tcBind.curTC &&
194                tidTCStatus.da == 1 &&
195                tidTCHalt.h == 0    &&
196                tidTCStatus.a == 1) {
197                ok = 1;
198            }
199        }
200
201        if (ok == 1) {
202            TCStatusReg tcStatus = tc->readMiscRegNoEffect(TCStatus);
203            tcStatus.a = 0;
204            tc->setMiscReg(TCStatus, tcStatus);
205            warn("%i: Deactivating Hardware Thread Context #%i",
206                    curTick, tc->threadId());
207        }
208    } else if (src_reg > 0) {
209        if (src_reg && !yield_mask != 0) {
210            VPEControlReg vpeControl = tc->readMiscReg(VPEControl);
211            vpeControl.excpt = 2;
212            tc->setMiscReg(VPEControl, vpeControl);
213            fault = new ThreadFault();
214        } else {
215        }
216    } else if (src_reg != -2) {
217        TCStatusReg tcStatus = tc->readMiscRegNoEffect(TCStatus);
218        VPEControlReg vpeControl = tc->readMiscRegNoEffect(VPEControl);
219
220        if (vpeControl.ysi == 1 && tcStatus.dt == 1 ) {
221            vpeControl.excpt = 4;
222            fault = new ThreadFault();
223        } else {
224        }
225    }
226
227    return src_reg & yield_mask;
228}
229
230
231// TC will usually be a object derived from ThreadContext
232// (src/cpu/thread_context.hh)
233template <class TC>
234inline void
235updateStatusView(TC *tc)
236{
237    // TCStatus' register view must be the same as
238    // Status register view for CU, MX, KSU bits
239    TCStatusReg tcStatus = tc->readMiscRegNoEffect(TCStatus);
240    StatusReg status = tc->readMiscRegNoEffect(Status);
241
242    status.cu = tcStatus.tcu;
243    status.mx = tcStatus.tmx;
244    status.ksu = tcStatus.tksu;
245
246    tc->setMiscRegNoEffect(Status, status);
247}
248
249// TC will usually be a object derived from ThreadContext
250// (src/cpu/thread_context.hh)
251template <class TC>
252inline void
253updateTCStatusView(TC *tc)
254{
255    // TCStatus' register view must be the same as
256    // Status register view for CU, MX, KSU bits
257    TCStatusReg tcStatus = tc->readMiscRegNoEffect(TCStatus);
258    StatusReg status = tc->readMiscRegNoEffect(Status);
259
260    tcStatus.tcu = status.cu;
261    tcStatus.tmx = status.mx;
262    tcStatus.tksu = status.ksu;
263
264    tc->setMiscRegNoEffect(TCStatus, tcStatus);
265}
266
267} // namespace MipsISA
268
269
270#endif
271