Re: A better register interface

Nick Duffek
2001-02-26T14:01:00Z

On 14-Feb-2001, Andrew Cagney wrote:

>While eventually, I'd like to see a clear separation between the two
>sides of the register cache

Note that the register cache already separates target and core ("raw" and
"cooked") register numbers. REGNUM in core GDB is an opaque identifier
that happens to coincide with certain target register numbers, but if a
particular target uses a different numbering scheme, it can do so using
REGISTER_BUFFER.

For example, if PowerPC target "foo" identifies general purpose register 0
as 33, the target can supply the register as follows:

char rawbuf[FOO_MAXREG_SIZE];

if (!foo_read_register (33, rawbuf))
error ("can't read register 33");
memcpy (REGISTER_BUFFER (PPC_GP0_REGNUM), rawbuf,
REGISTER_SIZE (PPC_GP0_REGNUM));
SET_REGISTER_CACHED (PPC_GP0_REGNUM, 1);

> supply_raw_register(RAWNUM, buf, sizeof buf)
> set_raw_register_state (RAWNUM, that register valid stuff);
> fetch_raw_register(RAWNUM, buf, sizeof buf)
> something for value changed?
> raw_register_size(RAWNUM)
> raw_register_name(RAWNUM)

If I understand you correctly, we would also need a target interface to
tell the register cache how to map between RAWNUM and cooked REGNUM. For
example:

/* Associate raw register number RAWNUM in GDBARCH with internal
register id REGNUM. */
void map_raw_register (struct gdbarch *gdbarch, int rawnum, int regnum)

Right?

Or perhaps REGNUM in map_raw_register() would actually be a register name.
To catch spelling errors at compile-time rather than run-time, though,
register names would have to be presented as C symbols. As far as I can
see, there's not much advantage of this:

#define PPC_GP0_REGNUM "gp0"
#define PPC_GP1_REGNUM "gp1"
...

over this:

enum
{
PPC_GP0_REGNUM,
PPC_GP1_REGNUM,
...
};

So with your proposal, the architecture "foo" example above would be
accomplished as follows:

map_raw_register (gdbarch, 33, PPC_GP0_REGNUM);
...
supply_raw_register(RAWNUM, buf, sizeof buf)

The map_raw_register() call would be performed in the appropriate gdbarch
initialization phase.

That looks like a reasonable change to me, but it doesn't significantly
reduce code complexity: for a particular piece of hardware, we'd still
have M*N map_raw_register() sequences, where M is the number of ISAs and N
is the number of targets.

To address that complexity, we could formalize the concept of pure
hardware descriptions, perhaps autogenerated from CGEN. They would define
canonical register names, sizes, default types, numeric IDs, default
groupings, etc. Targets would provide mappings from their numbers to
those IDs if necessary. ISAs could override register names, add
pseudo-registers, etc.

These hardware descriptions could be stored in *-hwdep.c and *-hwdep.h.

Nick