This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [WIP/RFC] MIPS registers overhaul



For instance, do a 64 bit FP restore then clear the FR bit; the reverse; some other variant; ...?


So, if the process is running with FR=0, then the save/restore should
("must" i believe) be done with FR=0.

When FR=0, there are two options as to how to do it:

	for (i = 0; i < 32; i++)
	   move/store word from c1 reg $i (i.e., dmfc1/sdc1)

mfc1/sc1


OR:

	for (i = 0; i < 32; i += 2)
	   move/store dword from c1 reg $i (i.e., dmfc1/sdc1)

OK, I'm going to go out on a limb here. I don't think the two are equivalent, and I think the second is wrong. For big-endian, the second would store fp[n+0] ||| fp[n+1] backwards.


When extracting a double from a MIPS register pair, GDB does the rough equivalent of:

	if (big-endian && type == double)
	  memcpy (dest + 0, &fp[regnum + 1], 4);
	  memcpy (dest + 4, &fp[regnum + 0], 4);
	else if (little-endian && type == double)
	  memcpy (dest + 0, &fp[regnum + 0], 4);
	  memcpy (dest + 4, &fp[regnum + 1], 4);

(See register_to_type. The code dates back to ~92 and was added to fix IRIX double value display problems.) The effect is to always get the least significant part of a double value from fp[n+0], and the most significant from fp[n+1].

Given MIPS xor endian sillyness, it's hard to see this is happening, however looking at (MIPS IV ref 3.2) DMFC1, given a 32 bit FGR, it does:

GPR[rt] = FGR[fs+1] ||| FGR[fs+0]

A double word store of that GPR would then order the value as:

	0: FGR[fs+0]
	1: FGR[fs+1]

little endian, and

	0: FGR[fs+1]
	1: FGR[fs+0]

big endian.

If you stare at LDC1 long enough, remembering that LoadMemory contains the horrible XOR magic, you'll realise that it has the same effect.

Anyway, this, I believe, means that any implementation of:

	union {
	  float flt;
	  double dbl;
	  int32 i32;
	  int64 i64;
	} $fp0

is going to need, for BE, a big-byte little-word DOUBLE, and a similar INT64. Otherwize, $f0.int32 would modify the wrong part of the double register. Alternatively, some of those union values could be given magic offsets. Looking at kevin's patch:

+  t = init_composite_type ("__gdb_mips_type_float_double_register_big",
+                           TYPE_CODE_UNION);
+  append_composite_type_field (t, "i", builtin_type_uint64);
+  append_composite_type_field (t, "f", builtin_type_ieee_single_big);
+  f = &(TYPE_FIELDS (t))[TYPE_NFIELDS (t) - 1];
+  FIELD_BITPOS (f[0]) = 32;
+  append_composite_type_field (t, "d", builtin_type_ieee_double_big);
+
+  TYPE_NAME (t) = "mips_type_float_double_register_big";

It appears to have taken the second option.

Andrew

(move to / load for the state restore, of course.)

(of course, these will typically be written in assembly code, and
"fully unrolled" -- the pseudo-C-code is to demonstrate the concept
only.)

either one is valid, though all implementations that I know of choose
the latter because it's fewer instructions and almost certainly more
efficient.


the linux kernel presents that to o32 userland (o32 ptrace syscall) as an array of 32 32-bit values, but IIRC it's stored internally as (8 byte reg, 8 byte pad) * 16.



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]