ua2005.cc revision 8232
1/* 2 * Copyright (c) 2006 The Regents of The University of Michigan 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 29#include "arch/sparc/isa.hh" 30#include "arch/sparc/kernel_stats.hh" 31#include "arch/sparc/registers.hh" 32#include "base/bitfield.hh" 33#include "base/trace.hh" 34#include "cpu/base.hh" 35#include "cpu/thread_context.hh" 36#include "debug/Quiesce.hh" 37#include "debug/Timer.hh" 38#include "sim/system.hh" 39 40using namespace SparcISA; 41using namespace std; 42 43 44void 45ISA::checkSoftInt(ThreadContext *tc) 46{ 47 BaseCPU *cpu = tc->getCpuPtr(); 48 49 // If PIL < 14, copy over the tm and sm bits 50 if (pil < 14 && softint & 0x10000) 51 cpu->postInterrupt(IT_SOFT_INT, 16); 52 else 53 cpu->clearInterrupt(IT_SOFT_INT, 16); 54 if (pil < 14 && softint & 0x1) 55 cpu->postInterrupt(IT_SOFT_INT, 0); 56 else 57 cpu->clearInterrupt(IT_SOFT_INT, 0); 58 59 // Copy over any of the other bits that are set 60 for (int bit = 15; bit > 0; --bit) { 61 if (1 << bit & softint && bit > pil) 62 cpu->postInterrupt(IT_SOFT_INT, bit); 63 else 64 cpu->clearInterrupt(IT_SOFT_INT, bit); 65 } 66} 67 68// These functions map register indices to names 69static inline string 70getMiscRegName(RegIndex index) 71{ 72 static string miscRegName[NumMiscRegs] = 73 {/*"y", "ccr",*/ "asi", "tick", "fprs", "pcr", "pic", 74 "gsr", "softint_set", "softint_clr", "softint", "tick_cmpr", 75 "stick", "stick_cmpr", 76 "tpc", "tnpc", "tstate", "tt", "privtick", "tba", "pstate", "tl", 77 "pil", "cwp", /*"cansave", "canrestore", "cleanwin", "otherwin", 78 "wstate",*/ "gl", 79 "hpstate", "htstate", "hintp", "htba", "hver", "strand_sts_reg", 80 "hstick_cmpr", 81 "fsr", "prictx", "secctx", "partId", "lsuCtrlReg", 82 "scratch0", "scratch1", "scratch2", "scratch3", "scratch4", 83 "scratch5", "scratch6", "scratch7", "cpuMondoHead", "cpuMondoTail", 84 "devMondoHead", "devMondoTail", "resErrorHead", "resErrorTail", 85 "nresErrorHead", "nresErrorTail", "TlbData" }; 86 return miscRegName[index]; 87} 88 89void 90ISA::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc) 91{ 92 BaseCPU *cpu = tc->getCpuPtr(); 93 94 int64_t time; 95 switch (miscReg) { 96 /* Full system only ASRs */ 97 case MISCREG_SOFTINT: 98 setMiscRegNoEffect(miscReg, val);; 99 checkSoftInt(tc); 100 break; 101 case MISCREG_SOFTINT_CLR: 102 return setMiscReg(MISCREG_SOFTINT, ~val & softint, tc); 103 case MISCREG_SOFTINT_SET: 104 return setMiscReg(MISCREG_SOFTINT, val | softint, tc); 105 106 case MISCREG_TICK_CMPR: 107 if (tickCompare == NULL) 108 tickCompare = new TickCompareEvent(this, tc); 109 setMiscRegNoEffect(miscReg, val); 110 if ((tick_cmpr & ~mask(63)) && tickCompare->scheduled()) 111 cpu->deschedule(tickCompare); 112 time = (tick_cmpr & mask(63)) - (tick & mask(63)); 113 if (!(tick_cmpr & ~mask(63)) && time > 0) { 114 if (tickCompare->scheduled()) 115 cpu->deschedule(tickCompare); 116 cpu->schedule(tickCompare, curTick() + time * cpu->ticks(1)); 117 } 118 panic("writing to TICK compare register %#X\n", val); 119 break; 120 121 case MISCREG_STICK_CMPR: 122 if (sTickCompare == NULL) 123 sTickCompare = new STickCompareEvent(this, tc); 124 setMiscRegNoEffect(miscReg, val); 125 if ((stick_cmpr & ~mask(63)) && sTickCompare->scheduled()) 126 cpu->deschedule(sTickCompare); 127 time = ((int64_t)(stick_cmpr & mask(63)) - (int64_t)stick) - 128 cpu->instCount(); 129 if (!(stick_cmpr & ~mask(63)) && time > 0) { 130 if (sTickCompare->scheduled()) 131 cpu->deschedule(sTickCompare); 132 cpu->schedule(sTickCompare, curTick() + time * cpu->ticks(1)); 133 } 134 DPRINTF(Timer, "writing to sTICK compare register value %#X\n", val); 135 break; 136 137 case MISCREG_PSTATE: 138 setMiscRegNoEffect(miscReg, val); 139 140 case MISCREG_PIL: 141 setMiscRegNoEffect(miscReg, val); 142 checkSoftInt(tc); 143 break; 144 145 case MISCREG_HVER: 146 panic("Shouldn't be writing HVER\n"); 147 148 case MISCREG_HINTP: 149 setMiscRegNoEffect(miscReg, val); 150 if (hintp) 151 cpu->postInterrupt(IT_HINTP, 0); 152 else 153 cpu->clearInterrupt(IT_HINTP, 0); 154 break; 155 156 case MISCREG_HTBA: 157 // clear lower 7 bits on writes. 158 setMiscRegNoEffect(miscReg, val & ULL(~0x7FFF)); 159 break; 160 161 case MISCREG_QUEUE_CPU_MONDO_HEAD: 162 case MISCREG_QUEUE_CPU_MONDO_TAIL: 163 setMiscRegNoEffect(miscReg, val); 164 if (cpu_mondo_head != cpu_mondo_tail) 165 cpu->postInterrupt(IT_CPU_MONDO, 0); 166 else 167 cpu->clearInterrupt(IT_CPU_MONDO, 0); 168 break; 169 case MISCREG_QUEUE_DEV_MONDO_HEAD: 170 case MISCREG_QUEUE_DEV_MONDO_TAIL: 171 setMiscRegNoEffect(miscReg, val); 172 if (dev_mondo_head != dev_mondo_tail) 173 cpu->postInterrupt(IT_DEV_MONDO, 0); 174 else 175 cpu->clearInterrupt(IT_DEV_MONDO, 0); 176 break; 177 case MISCREG_QUEUE_RES_ERROR_HEAD: 178 case MISCREG_QUEUE_RES_ERROR_TAIL: 179 setMiscRegNoEffect(miscReg, val); 180 if (res_error_head != res_error_tail) 181 cpu->postInterrupt(IT_RES_ERROR, 0); 182 else 183 cpu->clearInterrupt(IT_RES_ERROR, 0); 184 break; 185 case MISCREG_QUEUE_NRES_ERROR_HEAD: 186 case MISCREG_QUEUE_NRES_ERROR_TAIL: 187 setMiscRegNoEffect(miscReg, val); 188 // This one doesn't have an interrupt to report to the guest OS 189 break; 190 191 case MISCREG_HSTICK_CMPR: 192 if (hSTickCompare == NULL) 193 hSTickCompare = new HSTickCompareEvent(this, tc); 194 setMiscRegNoEffect(miscReg, val); 195 if ((hstick_cmpr & ~mask(63)) && hSTickCompare->scheduled()) 196 cpu->deschedule(hSTickCompare); 197 time = ((int64_t)(hstick_cmpr & mask(63)) - (int64_t)stick) - 198 cpu->instCount(); 199 if (!(hstick_cmpr & ~mask(63)) && time > 0) { 200 if (hSTickCompare->scheduled()) 201 cpu->deschedule(hSTickCompare); 202 cpu->schedule(hSTickCompare, curTick() + time * cpu->ticks(1)); 203 } 204 DPRINTF(Timer, "writing to hsTICK compare register value %#X\n", val); 205 break; 206 207 case MISCREG_HPSTATE: 208 // T1000 spec says impl. dependent val must always be 1 209 setMiscRegNoEffect(miscReg, val | HPSTATE::id); 210#if FULL_SYSTEM 211 if (hpstate & HPSTATE::tlz && tl == 0 && !(hpstate & HPSTATE::hpriv)) 212 cpu->postInterrupt(IT_TRAP_LEVEL_ZERO, 0); 213 else 214 cpu->clearInterrupt(IT_TRAP_LEVEL_ZERO, 0); 215#endif 216 break; 217 case MISCREG_HTSTATE: 218 setMiscRegNoEffect(miscReg, val); 219 break; 220 221 case MISCREG_STRAND_STS_REG: 222 if (bits(val,2,2)) 223 panic("No support for setting spec_en bit\n"); 224 setMiscRegNoEffect(miscReg, bits(val,0,0)); 225 if (!bits(val,0,0)) { 226 DPRINTF(Quiesce, "Cpu executed quiescing instruction\n"); 227 // Time to go to sleep 228 tc->suspend(); 229 if (tc->getKernelStats()) 230 tc->getKernelStats()->quiesce(); 231 } 232 break; 233 234 default: 235 panic("Invalid write to FS misc register %s\n", 236 getMiscRegName(miscReg)); 237 } 238} 239 240MiscReg 241ISA::readFSReg(int miscReg, ThreadContext * tc) 242{ 243 uint64_t temp; 244 245 switch (miscReg) { 246 /* Privileged registers. */ 247 case MISCREG_QUEUE_CPU_MONDO_HEAD: 248 case MISCREG_QUEUE_CPU_MONDO_TAIL: 249 case MISCREG_QUEUE_DEV_MONDO_HEAD: 250 case MISCREG_QUEUE_DEV_MONDO_TAIL: 251 case MISCREG_QUEUE_RES_ERROR_HEAD: 252 case MISCREG_QUEUE_RES_ERROR_TAIL: 253 case MISCREG_QUEUE_NRES_ERROR_HEAD: 254 case MISCREG_QUEUE_NRES_ERROR_TAIL: 255 case MISCREG_SOFTINT: 256 case MISCREG_TICK_CMPR: 257 case MISCREG_STICK_CMPR: 258 case MISCREG_PIL: 259 case MISCREG_HPSTATE: 260 case MISCREG_HINTP: 261 case MISCREG_HTSTATE: 262 case MISCREG_HSTICK_CMPR: 263 return readMiscRegNoEffect(miscReg) ; 264 265 case MISCREG_HTBA: 266 return readMiscRegNoEffect(miscReg) & ULL(~0x7FFF); 267 case MISCREG_HVER: 268 // XXX set to match Legion 269 return ULL(0x3e) << 48 | 270 ULL(0x23) << 32 | 271 ULL(0x20) << 24 | 272 // MaxGL << 16 | XXX For some reason legion doesn't set GL 273 MaxTL << 8 | 274 (NWindows -1) << 0; 275 276 case MISCREG_STRAND_STS_REG: 277 System *sys; 278 int x; 279 sys = tc->getSystemPtr(); 280 281 temp = readMiscRegNoEffect(miscReg) & (STS::active | STS::speculative); 282 // Check that the CPU array is fully populated 283 // (by calling getNumCPus()) 284 assert(sys->numContexts() > tc->contextId()); 285 286 temp |= tc->contextId() << STS::shft_id; 287 288 for (x = tc->contextId() & ~3; x < sys->threadContexts.size(); x++) { 289 switch (sys->threadContexts[x]->status()) { 290 case ThreadContext::Active: 291 temp |= STS::st_run << (STS::shft_fsm0 - 292 ((x & 0x3) * (STS::shft_fsm0-STS::shft_fsm1))); 293 break; 294 case ThreadContext::Suspended: 295 // should this be idle? 296 temp |= STS::st_idle << (STS::shft_fsm0 - 297 ((x & 0x3) * (STS::shft_fsm0-STS::shft_fsm1))); 298 break; 299 case ThreadContext::Halted: 300 temp |= STS::st_halt << (STS::shft_fsm0 - 301 ((x & 0x3) * (STS::shft_fsm0-STS::shft_fsm1))); 302 break; 303 default: 304 panic("What state are we in?!\n"); 305 } // switch 306 } // for 307 308 return temp; 309 default: 310 panic("Invalid read to FS misc register\n"); 311 } 312} 313 314void 315ISA::processTickCompare(ThreadContext *tc) 316{ 317 panic("tick compare not implemented\n"); 318} 319 320void 321ISA::processSTickCompare(ThreadContext *tc) 322{ 323 BaseCPU *cpu = tc->getCpuPtr(); 324 325 // since our microcode instructions take two cycles we need to check if 326 // we're actually at the correct cycle or we need to wait a little while 327 // more 328 int ticks; 329 ticks = ((int64_t)(stick_cmpr & mask(63)) - (int64_t)stick) - 330 cpu->instCount(); 331 assert(ticks >= 0 && "stick compare missed interrupt cycle"); 332 333 if (ticks == 0 || tc->status() == ThreadContext::Suspended) { 334 DPRINTF(Timer, "STick compare cycle reached at %#x\n", 335 (stick_cmpr & mask(63))); 336 if (!(tc->readMiscRegNoEffect(MISCREG_STICK_CMPR) & (ULL(1) << 63))) { 337 setMiscReg(MISCREG_SOFTINT, softint | (ULL(1) << 16), tc); 338 } 339 } else { 340 cpu->schedule(sTickCompare, curTick() + ticks * cpu->ticks(1)); 341 } 342} 343 344void 345ISA::processHSTickCompare(ThreadContext *tc) 346{ 347 BaseCPU *cpu = tc->getCpuPtr(); 348 349 // since our microcode instructions take two cycles we need to check if 350 // we're actually at the correct cycle or we need to wait a little while 351 // more 352 int ticks; 353 if ( tc->status() == ThreadContext::Halted) 354 return; 355 356 ticks = ((int64_t)(hstick_cmpr & mask(63)) - (int64_t)stick) - 357 cpu->instCount(); 358 assert(ticks >= 0 && "hstick compare missed interrupt cycle"); 359 360 if (ticks == 0 || tc->status() == ThreadContext::Suspended) { 361 DPRINTF(Timer, "HSTick compare cycle reached at %#x\n", 362 (stick_cmpr & mask(63))); 363 if (!(tc->readMiscRegNoEffect(MISCREG_HSTICK_CMPR) & (ULL(1) << 63))) { 364 setMiscReg(MISCREG_HINTP, 1, tc); 365 } 366 // Need to do something to cause interrupt to happen here !!! @todo 367 } else { 368 cpu->schedule(hSTickCompare, curTick() + ticks * cpu->ticks(1)); 369 } 370} 371 372