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] = &regs;
   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*)&regs->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  }