github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/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 "../../cmd/ld/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 math·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 m->freglo[reg] = val; 36 } 37 38 static void 39 putd(uint32 reg, uint64 val) 40 { 41 m->freglo[reg] = (uint32)val; 42 m->freghi[reg] = (uint32)(val>>32); 43 } 44 45 static uint64 46 getd(uint32 reg) 47 { 48 return (uint64)m->freglo[reg] | ((uint64)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, m->freghi[i], 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 static const uint8 conditions[10/2] = { 94 [0/2] = (FLAGS_Z >> 24) | 0, // 0: EQ (Z set), 1: NE (Z clear) 95 [2/2] = (FLAGS_C >> 24) | 0, // 2: CS/HS (C set), 3: CC/LO (C clear) 96 [4/2] = (FLAGS_N >> 24) | 0, // 4: MI (N set), 5: PL (N clear) 97 [6/2] = (FLAGS_V >> 24) | 0, // 6: VS (V set), 7: VC (V clear) 98 [8/2] = (FLAGS_C >> 24) | 99 (FLAGS_Z >> 28), // 8: HI (C set and Z clear), 9: LS (C clear and Z set) 100 }; 101 102 // returns number of words that the fp instruction 103 // is occupying, 0 if next instruction isn't float. 104 static uint32 105 stepflt(uint32 *pc, uint32 *regs) 106 { 107 uint32 i, opc, regd, regm, regn, cpsr; 108 int32 delta; 109 uint32 *addr; 110 uint64 uval; 111 int64 sval; 112 bool nan, ok; 113 int32 cmp; 114 115 i = *pc; 116 117 if(trace) 118 runtime·printf("stepflt %p %x (cpsr %x)\n", pc, i, regs[CPSR] >> 28); 119 120 opc = i >> 28; 121 if(opc == 14) // common case first 122 goto execute; 123 cpsr = regs[CPSR] >> 28; 124 switch(opc) { 125 case 0: case 1: case 2: case 3: case 4: 126 case 5: case 6: case 7: case 8: case 9: 127 if(((cpsr & (conditions[opc/2] >> 4)) == (conditions[opc/2] >> 4)) && 128 ((cpsr & (conditions[opc/2] & 0xf)) == 0)) { 129 if(opc & 1) return 1; 130 } else { 131 if(!(opc & 1)) return 1; 132 } 133 break; 134 case 10: // GE (N == V) 135 case 11: // LT (N != V) 136 if((cpsr & (FLAGS_N >> 28)) == (cpsr & (FLAGS_V >> 28))) { 137 if(opc & 1) return 1; 138 } else { 139 if(!(opc & 1)) return 1; 140 } 141 break; 142 case 12: // GT (N == V and Z == 0) 143 case 13: // LE (N != V or Z == 1) 144 if((cpsr & (FLAGS_N >> 28)) == (cpsr & (FLAGS_V >> 28)) && 145 (cpsr & (FLAGS_Z >> 28)) == 0) { 146 if(opc & 1) return 1; 147 } else { 148 if(!(opc & 1)) return 1; 149 } 150 break; 151 case 14: // AL 152 break; 153 case 15: // shouldn't happen 154 return 0; 155 } 156 if(trace) 157 runtime·printf("conditional %x (cpsr %x) pass\n", opc, cpsr); 158 i = (0xeU << 28) | (i & 0xfffffff); 159 160 execute: 161 // special cases 162 if((i&0xfffff000) == 0xe59fb000) { 163 // load r11 from pc-relative address. 164 // might be part of a floating point move 165 // (or might not, but no harm in simulating 166 // one instruction too many). 167 addr = (uint32*)((uint8*)pc + (i&0xfff) + 8); 168 regs[11] = addr[0]; 169 170 if(trace) 171 runtime·printf("*** cpu R[%d] = *(%p) %x\n", 172 11, addr, regs[11]); 173 return 1; 174 } 175 if(i == 0xe08bb00d) { 176 // add sp to r11. 177 // might be part of a large stack offset address 178 // (or might not, but again no harm done). 179 regs[11] += regs[13]; 180 181 if(trace) 182 runtime·printf("*** cpu R[%d] += R[%d] %x\n", 183 11, 13, regs[11]); 184 return 1; 185 } 186 if(i == 0xeef1fa10) { 187 regs[CPSR] = (regs[CPSR]&0x0fffffff) | m->fflag; 188 189 if(trace) 190 runtime·printf("*** fpsr R[CPSR] = F[CPSR] %x\n", regs[CPSR]); 191 return 1; 192 } 193 if((i&0xff000000) == 0xea000000) { 194 // unconditional branch 195 // can happen in the middle of floating point 196 // if the linker decides it is time to lay down 197 // a sequence of instruction stream constants. 198 delta = i&0xffffff; 199 delta = (delta<<8) >> 8; // sign extend 200 201 if(trace) 202 runtime·printf("*** cpu PC += %x\n", (delta+2)*4); 203 return delta+2; 204 } 205 206 goto stage1; 207 208 stage1: // load/store regn is cpureg, regm is 8bit offset 209 regd = i>>12 & 0xf; 210 regn = i>>16 & 0xf; 211 regm = (i & 0xff) << 2; // PLUS or MINUS ?? 212 213 switch(i & 0xfff00f00) { 214 default: 215 goto stage2; 216 217 case 0xed900a00: // single load 218 addr = (uint32*)(regs[regn] + regm); 219 m->freglo[regd] = addr[0]; 220 221 if(trace) 222 runtime·printf("*** load F[%d] = %x\n", 223 regd, m->freglo[regd]); 224 break; 225 226 case 0xed900b00: // double load 227 addr = (uint32*)(regs[regn] + regm); 228 m->freglo[regd] = addr[0]; 229 m->freghi[regd] = addr[1]; 230 231 if(trace) 232 runtime·printf("*** load D[%d] = %x-%x\n", 233 regd, m->freghi[regd], m->freglo[regd]); 234 break; 235 236 case 0xed800a00: // single store 237 addr = (uint32*)(regs[regn] + regm); 238 addr[0] = m->freglo[regd]; 239 240 if(trace) 241 runtime·printf("*** *(%p) = %x\n", 242 addr, addr[0]); 243 break; 244 245 case 0xed800b00: // double store 246 addr = (uint32*)(regs[regn] + regm); 247 addr[0] = m->freglo[regd]; 248 addr[1] = m->freghi[regd]; 249 250 if(trace) 251 runtime·printf("*** *(%p) = %x-%x\n", 252 addr, addr[1], addr[0]); 253 break; 254 } 255 return 1; 256 257 stage2: // regd, regm, regn are 4bit variables 258 regm = i>>0 & 0xf; 259 switch(i & 0xfff00ff0) { 260 default: 261 goto stage3; 262 263 case 0xf3000110: // veor 264 m->freglo[regd] = m->freglo[regm]^m->freglo[regn]; 265 m->freghi[regd] = m->freghi[regm]^m->freghi[regn]; 266 267 if(trace) 268 runtime·printf("*** veor D[%d] = %x-%x\n", 269 regd, m->freghi[regd], m->freglo[regd]); 270 break; 271 272 case 0xeeb00b00: // D[regd] = const(regn,regm) 273 regn = (regn<<4) | regm; 274 regm = 0x40000000UL; 275 if(regn & 0x80) 276 regm |= 0x80000000UL; 277 if(regn & 0x40) 278 regm ^= 0x7fc00000UL; 279 regm |= (regn & 0x3f) << 16; 280 m->freglo[regd] = 0; 281 m->freghi[regd] = regm; 282 283 if(trace) 284 runtime·printf("*** immed D[%d] = %x-%x\n", 285 regd, m->freghi[regd], m->freglo[regd]); 286 break; 287 288 case 0xeeb00a00: // F[regd] = const(regn,regm) 289 regn = (regn<<4) | regm; 290 regm = 0x40000000UL; 291 if(regn & 0x80) 292 regm |= 0x80000000UL; 293 if(regn & 0x40) 294 regm ^= 0x7e000000UL; 295 regm |= (regn & 0x3f) << 19; 296 m->freglo[regd] = regm; 297 298 if(trace) 299 runtime·printf("*** immed D[%d] = %x\n", 300 regd, m->freglo[regd]); 301 break; 302 303 case 0xee300b00: // D[regd] = D[regn]+D[regm] 304 runtime·fadd64c(getd(regn), getd(regm), &uval); 305 putd(regd, uval); 306 307 if(trace) 308 runtime·printf("*** add D[%d] = D[%d]+D[%d] %x-%x\n", 309 regd, regn, regm, m->freghi[regd], m->freglo[regd]); 310 break; 311 312 case 0xee300a00: // F[regd] = F[regn]+F[regm] 313 runtime·fadd64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval); 314 m->freglo[regd] = d2f(uval); 315 316 if(trace) 317 runtime·printf("*** add F[%d] = F[%d]+F[%d] %x\n", 318 regd, regn, regm, m->freglo[regd]); 319 break; 320 321 case 0xee300b40: // D[regd] = D[regn]-D[regm] 322 runtime·fsub64c(getd(regn), getd(regm), &uval); 323 putd(regd, uval); 324 325 if(trace) 326 runtime·printf("*** sub D[%d] = D[%d]-D[%d] %x-%x\n", 327 regd, regn, regm, m->freghi[regd], m->freglo[regd]); 328 break; 329 330 case 0xee300a40: // F[regd] = F[regn]-F[regm] 331 runtime·fsub64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval); 332 m->freglo[regd] = d2f(uval); 333 334 if(trace) 335 runtime·printf("*** sub F[%d] = F[%d]-F[%d] %x\n", 336 regd, regn, regm, m->freglo[regd]); 337 break; 338 339 case 0xee200b00: // D[regd] = D[regn]*D[regm] 340 runtime·fmul64c(getd(regn), getd(regm), &uval); 341 putd(regd, uval); 342 343 if(trace) 344 runtime·printf("*** mul D[%d] = D[%d]*D[%d] %x-%x\n", 345 regd, regn, regm, m->freghi[regd], m->freglo[regd]); 346 break; 347 348 case 0xee200a00: // F[regd] = F[regn]*F[regm] 349 runtime·fmul64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval); 350 m->freglo[regd] = d2f(uval); 351 352 if(trace) 353 runtime·printf("*** mul F[%d] = F[%d]*F[%d] %x\n", 354 regd, regn, regm, m->freglo[regd]); 355 break; 356 357 case 0xee800b00: // D[regd] = D[regn]/D[regm] 358 runtime·fdiv64c(getd(regn), getd(regm), &uval); 359 putd(regd, uval); 360 361 if(trace) 362 runtime·printf("*** div D[%d] = D[%d]/D[%d] %x-%x\n", 363 regd, regn, regm, m->freghi[regd], m->freglo[regd]); 364 break; 365 366 case 0xee800a00: // F[regd] = F[regn]/F[regm] 367 runtime·fdiv64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval); 368 m->freglo[regd] = d2f(uval); 369 370 if(trace) 371 runtime·printf("*** div F[%d] = F[%d]/F[%d] %x\n", 372 regd, regn, regm, m->freglo[regd]); 373 break; 374 375 case 0xee000b10: // S[regn] = R[regd] (MOVW) (regm ignored) 376 m->freglo[regn] = regs[regd]; 377 378 if(trace) 379 runtime·printf("*** cpy S[%d] = R[%d] %x\n", 380 regn, regd, m->freglo[regn]); 381 break; 382 383 case 0xee100b10: // R[regd] = S[regn] (MOVW) (regm ignored) 384 regs[regd] = m->freglo[regn]; 385 386 if(trace) 387 runtime·printf("*** cpy R[%d] = S[%d] %x\n", 388 regd, regn, regs[regd]); 389 break; 390 } 391 return 1; 392 393 stage3: // regd, regm are 4bit variables 394 switch(i & 0xffff0ff0) { 395 default: 396 goto done; 397 398 case 0xeeb00a40: // F[regd] = F[regm] (MOVF) 399 m->freglo[regd] = m->freglo[regm]; 400 401 if(trace) 402 runtime·printf("*** F[%d] = F[%d] %x\n", 403 regd, regm, m->freglo[regd]); 404 break; 405 406 case 0xeeb00b40: // D[regd] = D[regm] (MOVD) 407 m->freglo[regd] = m->freglo[regm]; 408 m->freghi[regd] = m->freghi[regm]; 409 410 if(trace) 411 runtime·printf("*** D[%d] = D[%d] %x-%x\n", 412 regd, regm, m->freghi[regd], m->freglo[regd]); 413 break; 414 415 case 0xeeb10bc0: // D[regd] = sqrt D[regm] 416 math·sqrtC(getd(regm), &uval); 417 putd(regd, uval); 418 419 if(trace) 420 runtime·printf("*** D[%d] = sqrt D[%d] %x-%x\n", 421 regd, regm, m->freghi[regd], m->freglo[regd]); 422 break; 423 424 case 0xeeb00bc0: // D[regd] = abs D[regm] 425 m->freglo[regd] = m->freglo[regm]; 426 m->freghi[regd] = m->freghi[regm] & ((1<<31)-1); 427 428 if(trace) 429 runtime·printf("*** D[%d] = abs D[%d] %x-%x\n", 430 regd, regm, m->freghi[regd], m->freglo[regd]); 431 break; 432 433 case 0xeeb00ac0: // F[regd] = abs F[regm] 434 m->freglo[regd] = m->freglo[regm] & ((1<<31)-1); 435 436 if(trace) 437 runtime·printf("*** F[%d] = abs F[%d] %x\n", 438 regd, regm, m->freglo[regd]); 439 break; 440 441 case 0xeeb40bc0: // D[regd] :: D[regm] (CMPD) 442 runtime·fcmp64c(getd(regd), getd(regm), &cmp, &nan); 443 m->fflag = fstatus(nan, cmp); 444 445 if(trace) 446 runtime·printf("*** cmp D[%d]::D[%d] %x\n", 447 regd, regm, m->fflag); 448 break; 449 450 case 0xeeb40ac0: // F[regd] :: F[regm] (CMPF) 451 runtime·fcmp64c(f2d(m->freglo[regd]), f2d(m->freglo[regm]), &cmp, &nan); 452 m->fflag = fstatus(nan, cmp); 453 454 if(trace) 455 runtime·printf("*** cmp F[%d]::F[%d] %x\n", 456 regd, regm, m->fflag); 457 break; 458 459 case 0xeeb70ac0: // D[regd] = F[regm] (MOVFD) 460 putd(regd, f2d(m->freglo[regm])); 461 462 if(trace) 463 runtime·printf("*** f2d D[%d]=F[%d] %x-%x\n", 464 regd, regm, m->freghi[regd], m->freglo[regd]); 465 break; 466 467 case 0xeeb70bc0: // F[regd] = D[regm] (MOVDF) 468 m->freglo[regd] = d2f(getd(regm)); 469 470 if(trace) 471 runtime·printf("*** d2f F[%d]=D[%d] %x-%x\n", 472 regd, regm, m->freghi[regd], m->freglo[regd]); 473 break; 474 475 case 0xeebd0ac0: // S[regd] = F[regm] (MOVFW) 476 runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok); 477 if(!ok || (int32)sval != sval) 478 sval = 0; 479 m->freglo[regd] = sval; 480 481 if(trace) 482 runtime·printf("*** fix S[%d]=F[%d] %x\n", 483 regd, regm, m->freglo[regd]); 484 break; 485 486 case 0xeebc0ac0: // S[regd] = F[regm] (MOVFW.U) 487 runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok); 488 if(!ok || (uint32)sval != sval) 489 sval = 0; 490 m->freglo[regd] = sval; 491 492 if(trace) 493 runtime·printf("*** fix unsigned S[%d]=F[%d] %x\n", 494 regd, regm, m->freglo[regd]); 495 break; 496 497 case 0xeebd0bc0: // S[regd] = D[regm] (MOVDW) 498 runtime·f64tointc(getd(regm), &sval, &ok); 499 if(!ok || (int32)sval != sval) 500 sval = 0; 501 m->freglo[regd] = sval; 502 503 if(trace) 504 runtime·printf("*** fix S[%d]=D[%d] %x\n", 505 regd, regm, m->freglo[regd]); 506 break; 507 508 case 0xeebc0bc0: // S[regd] = D[regm] (MOVDW.U) 509 runtime·f64tointc(getd(regm), &sval, &ok); 510 if(!ok || (uint32)sval != sval) 511 sval = 0; 512 m->freglo[regd] = sval; 513 514 if(trace) 515 runtime·printf("*** fix unsigned S[%d]=D[%d] %x\n", 516 regd, regm, m->freglo[regd]); 517 break; 518 519 case 0xeeb80ac0: // D[regd] = S[regm] (MOVWF) 520 cmp = m->freglo[regm]; 521 if(cmp < 0) { 522 runtime·fintto64c(-cmp, &uval); 523 putf(regd, d2f(uval)); 524 m->freglo[regd] ^= 0x80000000; 525 } else { 526 runtime·fintto64c(cmp, &uval); 527 putf(regd, d2f(uval)); 528 } 529 530 if(trace) 531 runtime·printf("*** float D[%d]=S[%d] %x-%x\n", 532 regd, regm, m->freghi[regd], m->freglo[regd]); 533 break; 534 535 case 0xeeb80a40: // D[regd] = S[regm] (MOVWF.U) 536 runtime·fintto64c(m->freglo[regm], &uval); 537 putf(regd, d2f(uval)); 538 539 if(trace) 540 runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n", 541 regd, regm, m->freghi[regd], m->freglo[regd]); 542 break; 543 544 case 0xeeb80bc0: // D[regd] = S[regm] (MOVWD) 545 cmp = m->freglo[regm]; 546 if(cmp < 0) { 547 runtime·fintto64c(-cmp, &uval); 548 putd(regd, uval); 549 m->freghi[regd] ^= 0x80000000; 550 } else { 551 runtime·fintto64c(cmp, &uval); 552 putd(regd, uval); 553 } 554 555 if(trace) 556 runtime·printf("*** float D[%d]=S[%d] %x-%x\n", 557 regd, regm, m->freghi[regd], m->freglo[regd]); 558 break; 559 560 case 0xeeb80b40: // D[regd] = S[regm] (MOVWD.U) 561 runtime·fintto64c(m->freglo[regm], &uval); 562 putd(regd, uval); 563 564 if(trace) 565 runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n", 566 regd, regm, m->freghi[regd], m->freglo[regd]); 567 break; 568 } 569 return 1; 570 571 done: 572 if((i&0xff000000) == 0xee000000 || 573 (i&0xff000000) == 0xed000000) { 574 runtime·printf("stepflt %p %x\n", pc, i); 575 fabort(); 576 } 577 return 0; 578 } 579 580 typedef struct Sfregs Sfregs; 581 582 // NOTE: These are all recorded as pointers because they are possibly live registers, 583 // and we don't know what they contain. Recording them as pointers should be 584 // safer than not. 585 struct Sfregs 586 { 587 uint32 *r0; 588 uint32 *r1; 589 uint32 *r2; 590 uint32 *r3; 591 uint32 *r4; 592 uint32 *r5; 593 uint32 *r6; 594 uint32 *r7; 595 uint32 *r8; 596 uint32 *r9; 597 uint32 *r10; 598 uint32 *r11; 599 uint32 *r12; 600 uint32 *r13; 601 uint32 cspr; 602 }; 603 604 #pragma textflag NOSPLIT 605 uint32* 606 runtime·_sfloat2(uint32 *lr, Sfregs regs) 607 { 608 uint32 skip; 609 610 skip = stepflt(lr, (uint32*)®s.r0); 611 if(skip == 0) { 612 runtime·printf("sfloat2 %p %x\n", lr, *lr); 613 fabort(); // not ok to fail first instruction 614 } 615 616 lr += skip; 617 while(skip = stepflt(lr, (uint32*)®s.r0)) 618 lr += skip; 619 return lr; 620 }