This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [WIP/RFC] MIPS registers overhaul
- From: Andrew Cagney <ac131313 at redhat dot com>
- To: cgd at broadcom dot com, Kevin Buettner <kevinb at redhat dot com>
- Cc: gdb-patches at sources dot redhat dot com
- Date: Sun, 15 Jun 2003 13:23:21 -0400
- Subject: Re: [WIP/RFC] MIPS registers overhaul
- References: <1030510002453.ZM3880@localhost.localdomain> <3EBD6131.30209@redhat.com> <1030514220025.ZM10373@localhost.localdomain> <3EC461C1.1080104@redhat.com> <mailpost.1053057614.17325@news-sj1-1> <yov5znlma5s9.fsf@broadcom.com> <mailpost.1053123913.16634@news-sj1-1> <yov5wugqa4m8.fsf@broadcom.com> <3ECA8EC6.6030405@redhat.com> <yov5llx1mkab.fsf@broadcom.com>
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.