github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/runtime/softfloat_arm.c (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Software floating point interpretaton of ARM 7500 FP instructions. 6 // The interpretation is not bit compatible with the 7500. 7 // It uses true little-endian doubles, while the 7500 used mixed-endian. 8 9 #include "runtime.h" 10 #include "textflag.h" 11 12 #define CPSR 14 13 #define FLAGS_N (1U << 31) 14 #define FLAGS_Z (1U << 30) 15 #define FLAGS_C (1U << 29) 16 #define FLAGS_V (1U << 28) 17 18 void runtime·abort(void); 19 void runtime·sqrtC(uint64, uint64*); 20 21 static uint32 trace = 0; 22 23 static void 24 fabort(void) 25 { 26 if (1) { 27 runtime·printf("Unsupported floating point instruction\n"); 28 runtime·abort(); 29 } 30 } 31 32 static void 33 putf(uint32 reg, uint32 val) 34 { 35 g->m->freglo[reg] = val; 36 } 37 38 static void 39 putd(uint32 reg, uint64 val) 40 { 41 g->m->freglo[reg] = (uint32)val; 42 g->m->freghi[reg] = (uint32)(val>>32); 43 } 44 45 static uint64 46 getd(uint32 reg) 47 { 48 return (uint64)g->m->freglo[reg] | ((uint64)g->m->freghi[reg]<<32); 49 } 50 51 static void 52 fprint(void) 53 { 54 uint32 i; 55 for (i = 0; i < 16; i++) { 56 runtime·printf("\tf%d:\t%X %X\n", i, g->m->freghi[i], g->m->freglo[i]); 57 } 58 } 59 60 static uint32 61 d2f(uint64 d) 62 { 63 uint32 x; 64 65 runtime·f64to32c(d, &x); 66 return x; 67 } 68 69 static uint64 70 f2d(uint32 f) 71 { 72 uint64 x; 73 74 runtime·f32to64c(f, &x); 75 return x; 76 } 77 78 static uint32 79 fstatus(bool nan, int32 cmp) 80 { 81 if(nan) 82 return FLAGS_C | FLAGS_V; 83 if(cmp == 0) 84 return FLAGS_Z | FLAGS_C; 85 if(cmp < 0) 86 return FLAGS_N; 87 return FLAGS_C; 88 } 89 90 // conditions array record the required CPSR cond field for the 91 // first 5 pairs of conditional execution opcodes 92 // higher 4 bits are must set, lower 4 bits are must clear 93 #pragma dataflag NOPTR 94 static const uint8 conditions[10/2] = { 95 [0/2] = (FLAGS_Z >> 24) | 0, // 0: EQ (Z set), 1: NE (Z clear) 96 [2/2] = (FLAGS_C >> 24) | 0, // 2: CS/HS (C set), 3: CC/LO (C clear) 97 [4/2] = (FLAGS_N >> 24) | 0, // 4: MI (N set), 5: PL (N clear) 98 [6/2] = (FLAGS_V >> 24) | 0, // 6: VS (V set), 7: VC (V clear) 99 [8/2] = (FLAGS_C >> 24) | 100 (FLAGS_Z >> 28), // 8: HI (C set and Z clear), 9: LS (C clear and Z set) 101 }; 102 103 #define FAULT (0x80000000U) // impossible PC offset 104 105 // returns number of words that the fp instruction 106 // is occupying, 0 if next instruction isn't float. 107 static uint32 108 stepflt(uint32 *pc, uint32 *regs) 109 { 110 uint32 i, opc, regd, regm, regn, cpsr; 111 int32 delta; 112 uint32 *addr; 113 uint64 uval; 114 int64 sval; 115 bool nan, ok; 116 int32 cmp; 117 M *m; 118 119 // m is locked in vlop_arm.s, so g->m cannot change during this function call, 120 // so caching it in a local variable is safe. 121 m = g->m; 122 i = *pc; 123 124 if(trace) 125 runtime·printf("stepflt %p %x (cpsr %x)\n", pc, i, regs[CPSR] >> 28); 126 127 opc = i >> 28; 128 if(opc == 14) // common case first 129 goto execute; 130 cpsr = regs[CPSR] >> 28; 131 switch(opc) { 132 case 0: case 1: case 2: case 3: case 4: 133 case 5: case 6: case 7: case 8: case 9: 134 if(((cpsr & (conditions[opc/2] >> 4)) == (conditions[opc/2] >> 4)) && 135 ((cpsr & (conditions[opc/2] & 0xf)) == 0)) { 136 if(opc & 1) return 1; 137 } else { 138 if(!(opc & 1)) return 1; 139 } 140 break; 141 case 10: // GE (N == V) 142 case 11: // LT (N != V) 143 if((cpsr & (FLAGS_N >> 28)) == (cpsr & (FLAGS_V >> 28))) { 144 if(opc & 1) return 1; 145 } else { 146 if(!(opc & 1)) return 1; 147 } 148 break; 149 case 12: // GT (N == V and Z == 0) 150 case 13: // LE (N != V or Z == 1) 151 if((cpsr & (FLAGS_N >> 28)) == (cpsr & (FLAGS_V >> 28)) && 152 (cpsr & (FLAGS_Z >> 28)) == 0) { 153 if(opc & 1) return 1; 154 } else { 155 if(!(opc & 1)) return 1; 156 } 157 break; 158 case 14: // AL 159 break; 160 case 15: // shouldn't happen 161 return 0; 162 } 163 if(trace) 164 runtime·printf("conditional %x (cpsr %x) pass\n", opc, cpsr); 165 i = (0xeU << 28) | (i & 0xfffffff); 166 167 execute: 168 // special cases 169 if((i&0xfffff000) == 0xe59fb000) { 170 // load r11 from pc-relative address. 171 // might be part of a floating point move 172 // (or might not, but no harm in simulating 173 // one instruction too many). 174 addr = (uint32*)((uint8*)pc + (i&0xfff) + 8); 175 regs[11] = addr[0]; 176 177 if(trace) 178 runtime·printf("*** cpu R[%d] = *(%p) %x\n", 179 11, addr, regs[11]); 180 return 1; 181 } 182 if(i == 0xe08bb00d) { 183 // add sp to r11. 184 // might be part of a large stack offset address 185 // (or might not, but again no harm done). 186 regs[11] += regs[13]; 187 188 if(trace) 189 runtime·printf("*** cpu R[%d] += R[%d] %x\n", 190 11, 13, regs[11]); 191 return 1; 192 } 193 if(i == 0xeef1fa10) { 194 regs[CPSR] = (regs[CPSR]&0x0fffffff) | m->fflag; 195 196 if(trace) 197 runtime·printf("*** fpsr R[CPSR] = F[CPSR] %x\n", regs[CPSR]); 198 return 1; 199 } 200 if((i&0xff000000) == 0xea000000) { 201 // unconditional branch 202 // can happen in the middle of floating point 203 // if the linker decides it is time to lay down 204 // a sequence of instruction stream constants. 205 delta = i&0xffffff; 206 delta = (delta<<8) >> 8; // sign extend 207 208 if(trace) 209 runtime·printf("*** cpu PC += %x\n", (delta+2)*4); 210 return delta+2; 211 } 212 213 goto stage1; 214 215 stage1: // load/store regn is cpureg, regm is 8bit offset 216 regd = i>>12 & 0xf; 217 regn = i>>16 & 0xf; 218 regm = (i & 0xff) << 2; // PLUS or MINUS ?? 219 220 switch(i & 0xfff00f00) { 221 default: 222 goto stage2; 223 224 case 0xed900a00: // single load 225 addr = (uint32*)(regs[regn] + regm); 226 if((uintptr)addr < 4096) { 227 if(trace) 228 runtime·printf("*** load @%p => fault\n", addr); 229 return FAULT; 230 } 231 m->freglo[regd] = addr[0]; 232 233 if(trace) 234 runtime·printf("*** load F[%d] = %x\n", 235 regd, m->freglo[regd]); 236 break; 237 238 case 0xed900b00: // double load 239 addr = (uint32*)(regs[regn] + regm); 240 if((uintptr)addr < 4096) { 241 if(trace) 242 runtime·printf("*** double load @%p => fault\n", addr); 243 return FAULT; 244 } 245 m->freglo[regd] = addr[0]; 246 m->freghi[regd] = addr[1]; 247 248 if(trace) 249 runtime·printf("*** load D[%d] = %x-%x\n", 250 regd, m->freghi[regd], m->freglo[regd]); 251 break; 252 253 case 0xed800a00: // single store 254 addr = (uint32*)(regs[regn] + regm); 255 if((uintptr)addr < 4096) { 256 if(trace) 257 runtime·printf("*** store @%p => fault\n", addr); 258 return FAULT; 259 } 260 addr[0] = m->freglo[regd]; 261 262 if(trace) 263 runtime·printf("*** *(%p) = %x\n", 264 addr, addr[0]); 265 break; 266 267 case 0xed800b00: // double store 268 addr = (uint32*)(regs[regn] + regm); 269 if((uintptr)addr < 4096) { 270 if(trace) 271 runtime·printf("*** double store @%p => fault\n", addr); 272 return FAULT; 273 } 274 addr[0] = m->freglo[regd]; 275 addr[1] = m->freghi[regd]; 276 277 if(trace) 278 runtime·printf("*** *(%p) = %x-%x\n", 279 addr, addr[1], addr[0]); 280 break; 281 } 282 return 1; 283 284 stage2: // regd, regm, regn are 4bit variables 285 regm = i>>0 & 0xf; 286 switch(i & 0xfff00ff0) { 287 default: 288 goto stage3; 289 290 case 0xf3000110: // veor 291 m->freglo[regd] = m->freglo[regm]^m->freglo[regn]; 292 m->freghi[regd] = m->freghi[regm]^m->freghi[regn]; 293 294 if(trace) 295 runtime·printf("*** veor D[%d] = %x-%x\n", 296 regd, m->freghi[regd], m->freglo[regd]); 297 break; 298 299 case 0xeeb00b00: // D[regd] = const(regn,regm) 300 regn = (regn<<4) | regm; 301 regm = 0x40000000UL; 302 if(regn & 0x80) 303 regm |= 0x80000000UL; 304 if(regn & 0x40) 305 regm ^= 0x7fc00000UL; 306 regm |= (regn & 0x3f) << 16; 307 m->freglo[regd] = 0; 308 m->freghi[regd] = regm; 309 310 if(trace) 311 runtime·printf("*** immed D[%d] = %x-%x\n", 312 regd, m->freghi[regd], m->freglo[regd]); 313 break; 314 315 case 0xeeb00a00: // F[regd] = const(regn,regm) 316 regn = (regn<<4) | regm; 317 regm = 0x40000000UL; 318 if(regn & 0x80) 319 regm |= 0x80000000UL; 320 if(regn & 0x40) 321 regm ^= 0x7e000000UL; 322 regm |= (regn & 0x3f) << 19; 323 m->freglo[regd] = regm; 324 325 if(trace) 326 runtime·printf("*** immed D[%d] = %x\n", 327 regd, m->freglo[regd]); 328 break; 329 330 case 0xee300b00: // D[regd] = D[regn]+D[regm] 331 runtime·fadd64c(getd(regn), getd(regm), &uval); 332 putd(regd, uval); 333 334 if(trace) 335 runtime·printf("*** add D[%d] = D[%d]+D[%d] %x-%x\n", 336 regd, regn, regm, m->freghi[regd], m->freglo[regd]); 337 break; 338 339 case 0xee300a00: // F[regd] = F[regn]+F[regm] 340 runtime·fadd64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval); 341 m->freglo[regd] = d2f(uval); 342 343 if(trace) 344 runtime·printf("*** add F[%d] = F[%d]+F[%d] %x\n", 345 regd, regn, regm, m->freglo[regd]); 346 break; 347 348 case 0xee300b40: // D[regd] = D[regn]-D[regm] 349 runtime·fsub64c(getd(regn), getd(regm), &uval); 350 putd(regd, uval); 351 352 if(trace) 353 runtime·printf("*** sub D[%d] = D[%d]-D[%d] %x-%x\n", 354 regd, regn, regm, m->freghi[regd], m->freglo[regd]); 355 break; 356 357 case 0xee300a40: // F[regd] = F[regn]-F[regm] 358 runtime·fsub64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval); 359 m->freglo[regd] = d2f(uval); 360 361 if(trace) 362 runtime·printf("*** sub F[%d] = F[%d]-F[%d] %x\n", 363 regd, regn, regm, m->freglo[regd]); 364 break; 365 366 case 0xee200b00: // D[regd] = D[regn]*D[regm] 367 runtime·fmul64c(getd(regn), getd(regm), &uval); 368 putd(regd, uval); 369 370 if(trace) 371 runtime·printf("*** mul D[%d] = D[%d]*D[%d] %x-%x\n", 372 regd, regn, regm, m->freghi[regd], m->freglo[regd]); 373 break; 374 375 case 0xee200a00: // F[regd] = F[regn]*F[regm] 376 runtime·fmul64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval); 377 m->freglo[regd] = d2f(uval); 378 379 if(trace) 380 runtime·printf("*** mul F[%d] = F[%d]*F[%d] %x\n", 381 regd, regn, regm, m->freglo[regd]); 382 break; 383 384 case 0xee800b00: // D[regd] = D[regn]/D[regm] 385 runtime·fdiv64c(getd(regn), getd(regm), &uval); 386 putd(regd, uval); 387 388 if(trace) 389 runtime·printf("*** div D[%d] = D[%d]/D[%d] %x-%x\n", 390 regd, regn, regm, m->freghi[regd], m->freglo[regd]); 391 break; 392 393 case 0xee800a00: // F[regd] = F[regn]/F[regm] 394 runtime·fdiv64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval); 395 m->freglo[regd] = d2f(uval); 396 397 if(trace) 398 runtime·printf("*** div F[%d] = F[%d]/F[%d] %x\n", 399 regd, regn, regm, m->freglo[regd]); 400 break; 401 402 case 0xee000b10: // S[regn] = R[regd] (MOVW) (regm ignored) 403 m->freglo[regn] = regs[regd]; 404 405 if(trace) 406 runtime·printf("*** cpy S[%d] = R[%d] %x\n", 407 regn, regd, m->freglo[regn]); 408 break; 409 410 case 0xee100b10: // R[regd] = S[regn] (MOVW) (regm ignored) 411 regs[regd] = m->freglo[regn]; 412 413 if(trace) 414 runtime·printf("*** cpy R[%d] = S[%d] %x\n", 415 regd, regn, regs[regd]); 416 break; 417 } 418 return 1; 419 420 stage3: // regd, regm are 4bit variables 421 switch(i & 0xffff0ff0) { 422 default: 423 goto done; 424 425 case 0xeeb00a40: // F[regd] = F[regm] (MOVF) 426 m->freglo[regd] = m->freglo[regm]; 427 428 if(trace) 429 runtime·printf("*** F[%d] = F[%d] %x\n", 430 regd, regm, m->freglo[regd]); 431 break; 432 433 case 0xeeb00b40: // D[regd] = D[regm] (MOVD) 434 m->freglo[regd] = m->freglo[regm]; 435 m->freghi[regd] = m->freghi[regm]; 436 437 if(trace) 438 runtime·printf("*** D[%d] = D[%d] %x-%x\n", 439 regd, regm, m->freghi[regd], m->freglo[regd]); 440 break; 441 442 case 0xeeb10bc0: // D[regd] = sqrt D[regm] 443 runtime·sqrtC(getd(regm), &uval); 444 putd(regd, uval); 445 446 if(trace) 447 runtime·printf("*** D[%d] = sqrt D[%d] %x-%x\n", 448 regd, regm, m->freghi[regd], m->freglo[regd]); 449 break; 450 451 case 0xeeb00bc0: // D[regd] = abs D[regm] 452 m->freglo[regd] = m->freglo[regm]; 453 m->freghi[regd] = m->freghi[regm] & ((1<<31)-1); 454 455 if(trace) 456 runtime·printf("*** D[%d] = abs D[%d] %x-%x\n", 457 regd, regm, m->freghi[regd], m->freglo[regd]); 458 break; 459 460 case 0xeeb00ac0: // F[regd] = abs F[regm] 461 m->freglo[regd] = m->freglo[regm] & ((1<<31)-1); 462 463 if(trace) 464 runtime·printf("*** F[%d] = abs F[%d] %x\n", 465 regd, regm, m->freglo[regd]); 466 break; 467 468 case 0xeeb40bc0: // D[regd] :: D[regm] (CMPD) 469 runtime·fcmp64c(getd(regd), getd(regm), &cmp, &nan); 470 m->fflag = fstatus(nan, cmp); 471 472 if(trace) 473 runtime·printf("*** cmp D[%d]::D[%d] %x\n", 474 regd, regm, m->fflag); 475 break; 476 477 case 0xeeb40ac0: // F[regd] :: F[regm] (CMPF) 478 runtime·fcmp64c(f2d(m->freglo[regd]), f2d(m->freglo[regm]), &cmp, &nan); 479 m->fflag = fstatus(nan, cmp); 480 481 if(trace) 482 runtime·printf("*** cmp F[%d]::F[%d] %x\n", 483 regd, regm, m->fflag); 484 break; 485 486 case 0xeeb70ac0: // D[regd] = F[regm] (MOVFD) 487 putd(regd, f2d(m->freglo[regm])); 488 489 if(trace) 490 runtime·printf("*** f2d D[%d]=F[%d] %x-%x\n", 491 regd, regm, m->freghi[regd], m->freglo[regd]); 492 break; 493 494 case 0xeeb70bc0: // F[regd] = D[regm] (MOVDF) 495 m->freglo[regd] = d2f(getd(regm)); 496 497 if(trace) 498 runtime·printf("*** d2f F[%d]=D[%d] %x-%x\n", 499 regd, regm, m->freghi[regd], m->freglo[regd]); 500 break; 501 502 case 0xeebd0ac0: // S[regd] = F[regm] (MOVFW) 503 runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok); 504 if(!ok || (int32)sval != sval) 505 sval = 0; 506 m->freglo[regd] = sval; 507 508 if(trace) 509 runtime·printf("*** fix S[%d]=F[%d] %x\n", 510 regd, regm, m->freglo[regd]); 511 break; 512 513 case 0xeebc0ac0: // S[regd] = F[regm] (MOVFW.U) 514 runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok); 515 if(!ok || (uint32)sval != sval) 516 sval = 0; 517 m->freglo[regd] = sval; 518 519 if(trace) 520 runtime·printf("*** fix unsigned S[%d]=F[%d] %x\n", 521 regd, regm, m->freglo[regd]); 522 break; 523 524 case 0xeebd0bc0: // S[regd] = D[regm] (MOVDW) 525 runtime·f64tointc(getd(regm), &sval, &ok); 526 if(!ok || (int32)sval != sval) 527 sval = 0; 528 m->freglo[regd] = sval; 529 530 if(trace) 531 runtime·printf("*** fix S[%d]=D[%d] %x\n", 532 regd, regm, m->freglo[regd]); 533 break; 534 535 case 0xeebc0bc0: // S[regd] = D[regm] (MOVDW.U) 536 runtime·f64tointc(getd(regm), &sval, &ok); 537 if(!ok || (uint32)sval != sval) 538 sval = 0; 539 m->freglo[regd] = sval; 540 541 if(trace) 542 runtime·printf("*** fix unsigned S[%d]=D[%d] %x\n", 543 regd, regm, m->freglo[regd]); 544 break; 545 546 case 0xeeb80ac0: // D[regd] = S[regm] (MOVWF) 547 cmp = m->freglo[regm]; 548 if(cmp < 0) { 549 runtime·fintto64c(-cmp, &uval); 550 putf(regd, d2f(uval)); 551 m->freglo[regd] ^= 0x80000000; 552 } else { 553 runtime·fintto64c(cmp, &uval); 554 putf(regd, d2f(uval)); 555 } 556 557 if(trace) 558 runtime·printf("*** float D[%d]=S[%d] %x-%x\n", 559 regd, regm, m->freghi[regd], m->freglo[regd]); 560 break; 561 562 case 0xeeb80a40: // D[regd] = S[regm] (MOVWF.U) 563 runtime·fintto64c(m->freglo[regm], &uval); 564 putf(regd, d2f(uval)); 565 566 if(trace) 567 runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n", 568 regd, regm, m->freghi[regd], m->freglo[regd]); 569 break; 570 571 case 0xeeb80bc0: // D[regd] = S[regm] (MOVWD) 572 cmp = m->freglo[regm]; 573 if(cmp < 0) { 574 runtime·fintto64c(-cmp, &uval); 575 putd(regd, uval); 576 m->freghi[regd] ^= 0x80000000; 577 } else { 578 runtime·fintto64c(cmp, &uval); 579 putd(regd, uval); 580 } 581 582 if(trace) 583 runtime·printf("*** float D[%d]=S[%d] %x-%x\n", 584 regd, regm, m->freghi[regd], m->freglo[regd]); 585 break; 586 587 case 0xeeb80b40: // D[regd] = S[regm] (MOVWD.U) 588 runtime·fintto64c(m->freglo[regm], &uval); 589 putd(regd, uval); 590 591 if(trace) 592 runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n", 593 regd, regm, m->freghi[regd], m->freglo[regd]); 594 break; 595 } 596 return 1; 597 598 done: 599 if((i&0xff000000) == 0xee000000 || 600 (i&0xff000000) == 0xed000000) { 601 runtime·printf("stepflt %p %x\n", pc, i); 602 fabort(); 603 } 604 return 0; 605 } 606 607 typedef struct Sfregs Sfregs; 608 609 // NOTE: These are all recorded as pointers because they are possibly live registers, 610 // and we don't know what they contain. Recording them as pointers should be 611 // safer than not. 612 struct Sfregs 613 { 614 uint32 *r0; 615 uint32 *r1; 616 uint32 *r2; 617 uint32 *r3; 618 uint32 *r4; 619 uint32 *r5; 620 uint32 *r6; 621 uint32 *r7; 622 uint32 *r8; 623 uint32 *r9; 624 uint32 *r10; 625 uint32 *r11; 626 uint32 *r12; 627 uint32 *r13; 628 uint32 cspr; 629 }; 630 631 static void sfloat2(void); 632 void _sfloatpanic(void); 633 634 #pragma textflag NOSPLIT 635 uint32* 636 runtime·_sfloat2(uint32 *pc, Sfregs regs) 637 { 638 void (*fn)(void); 639 640 g->m->ptrarg[0] = pc; 641 g->m->ptrarg[1] = ®s; 642 fn = sfloat2; 643 runtime·onM(&fn); 644 pc = g->m->ptrarg[0]; 645 g->m->ptrarg[0] = nil; 646 return pc; 647 } 648 649 static void 650 sfloat2(void) 651 { 652 uint32 *pc; 653 G *curg; 654 Sfregs *regs; 655 int32 skip; 656 bool first; 657 658 pc = g->m->ptrarg[0]; 659 regs = g->m->ptrarg[1]; 660 g->m->ptrarg[0] = nil; 661 g->m->ptrarg[1] = nil; 662 663 first = true; 664 while(skip = stepflt(pc, (uint32*)®s->r0)) { 665 first = false; 666 if(skip == FAULT) { 667 // Encountered bad address in store/load. 668 // Record signal information and return to assembly 669 // trampoline that fakes the call. 670 enum { SIGSEGV = 11 }; 671 curg = g->m->curg; 672 curg->sig = SIGSEGV; 673 curg->sigcode0 = 0; 674 curg->sigcode1 = 0; 675 curg->sigpc = (uint32)pc; 676 pc = (uint32*)_sfloatpanic; 677 break; 678 } 679 pc += skip; 680 } 681 if(first) { 682 runtime·printf("sfloat2 %p %x\n", pc, *pc); 683 fabort(); // not ok to fail first instruction 684 } 685 686 g->m->ptrarg[0] = pc; 687 }