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]

Example code: gdb pseudo-registers


Here is an example of how you would use the pseudo-register feature.

This will represent a mips-like CPU with a vector co-processor.
It will show an example of an alias register (one that shares
the same storage as another "real" register), and a non-alias
pseudo-register (one that has its own storage, and whose value
must be computed).

First I will lay out my register-names array, starting with the
real physical registers:

#define MIPS_REGISTER_NAMES { \
  "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7", \
  "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",\
  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",\
  "r24", "r25", "r26", "r27", "gp",  "sp",  "s8",  "ra", \
  "sr",  "lo",  "hi",  "bad", "cause","pc",              \
  "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7", \
  "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",\
  "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",\
  "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",\
  "fsr", "fir", "fp",  "inx", "rand","tlblo","ctxt","tlbhi", \
  "epc", "prid", "",   "",    "",    "",     "",    "",  \
  "",    "",    "",    "",                               \
  "v0_00", "v0_01", "v0_02", "v0_03", \
  "v0_04", "v0_05", "v0_06", "v0_07", \
  "v0_08", "v0_09", "v0_10", "v0_11", \
  "v0_12", "v0_13", "v0_14", "v0_15", \
   [...]
   "v15_56","v15_57","v15_58","v15_59", \
   "v15_60","v15_61","v15_62","v15_63", \
Above are my vector register elements, which are treated as
real registers.  After the last one, I add some pseudo-registers
which will be aliases for the real registers:
  "vector0",  "vector1",  "vector2",  "vector3",  \
  "vector4",  "vector5",  "vector6",  "vector7",  \
  "vector8",  "vector9",  "vector10", "vector11", \
  "vector12", "vector13", "vector14", "vector15", \
and some more pseudo-registers whose values must be computed.
  "vrow0", "vrow1", "vrow2", "vrow3",  \
  "vrow4", "vrow5", "vrow6", "vrow7",  \
  "vrow8", "vrow9", "vrow10","vrow11", \
  "vrow12","vrow13","vrow14","vrow15", \
  [...], "vrow63" \
}

Vector0 is my first pseudo-register and vrow63 is my last.  So
#define NUM_REGS VECTOR0_REGNUM
#define NUM_PSEUDO_REGS VROW63_REGNUM - VECTOR0_REGNUM + 1

v0_00 etc. will be int, and vector0 etc. will be (int[64]).
vrow0 etc. will be (int[16]).  REGISTER_VIRTUAL_TYPE etc. 
will be defined so as to return these types.

REGISTER_RAW_SIZE will return sizeof(int) for V0_00_REGNUM, 
sizeof(int[64]) for VECTOR0_REGNUM, etc.

REGISTER_BYTE will return the same result for:
V0_00_REGNUM and VECTOR0_REGNUM, 
V1_00_REGNUM and VECTOR1_REGNUM, 
V2_00_REGNUM and VECTOR2_REGNUM, etc.
so that $vector0[0..63] is just an alias for $v0_00 thru $v0_63
and so on (they share space in the registers cache).

But $vrow0 will be a 16-element array containing one element
from each of the 16 $vector registers -- and because of the
element ordering, it cannot just point to the same storage.
It has to have storage of its own in the registers cache, 
and every read and write from this register has to make sure
that it contains the same values as the corresponding storage
for the element registers and the $vector registers.

So, REGISTER_BYTES does not need to include any extra storage
for the $vectorN regs, but it does have to include 16 * 64 *
sizeof(int) for the $vrowN regs.

Now all I have to do is define ARCH_FETCH_PSEUDO_REGISTERS
and ARCH_STORE_PSEUDO_REGISTERS, which may look something like:

void
vector_fetch_pseudo_registers (int regnum)
{
  int row, col, temp_regnum;

  if (!register_cached (regnum))
    {
      if (regnum >= VECTOR0_REGNUM && regnum <= VECTOR15_REGNUM)
        {
          /* vectorN is an alias for vN_00 thru vN_63.  */
          row = regnum - VECTOR0_REGNUM;
          temp_regnum = V0_00_REGNUM + 64 * row;
          /* Read the real regs for which this one is an alias.  */
          for (col = 0; col < 64; col++)
            if (!register_cached (temp_regnum + col))
              target_fetch_registers (temp_regnum + col);
        }
      else if (regnum >= VROW0_REGNUM && regnum <= VROW63_REGNUM)
        {
          /* vrowN is a pseudo-register, not an alias.
             It does not exist on the target at all, but is
             made up of elements from several target vector regs.  */
          col = regnum - VROW0_REGNUM;
          temp_regnum = V0_00_REGNUM + col;
          for (row = 0; row < 16; row++)
            {
              if (!register_cached (temp_regnum + 64 * row))
                target_fetch_registers (temp_regnum + 64 * row);
              /* Because this is not an alias, we also have to
                 copy the fetched value to a new location.  */
              memcpy (&registers[REGISTER_BYTE (regnum) + row * 
						MIPS_REGSIZE],
                      &registers[REGISTER_BYTE (temp_regnum + 64 * 
							row)],
                      TYPE_LENGTH (get_vector_element_type ()));
            }
        }
      register_valid [regnum] = 1;
    }
}

void
vector_store_pseudo_registers (int regnum)
{
  int row, col, temp_regnum;

  if (regnum >= VECTOR0_REGNUM && regnum <= VECTOR15_REGNUM)
    {
      /* vectorN is an alias for vN_00 thru vN_63.  */
      row = regnum - VECTOR0_REGNUM;
      temp_regnum = V0_00_REGNUM + 64 * row;
      /* Write the real regs for which this one is an alias.  */
      for (col = 0; col < 64; col++)
        {
          register_valid[temp_regnum + col] = 1;
          target_store_registers (temp_regnum + col);
        }
    }
  else if (regnum >= VROW0_REGNUM && regnum <= VROW63_REGNUM)
    {
      /* vrowN is a pseudo-register, not an alias.
         It does not exist on the target at all, but is
         made up of elements from several target vector regs.  */
      col = regnum - VROW0_REGNUM;
      temp_regnum = V0_00_REGNUM + col;
      for (row = 0; row < 16; row++)
        {
          /* Because this is not an alias, we have to compute the
             results of storing it (which should be to modify and
             then store the values of several vector elements).  */
          memcpy (&registers[REGISTER_BYTE (temp_regnum + 64 * 
						 row)],
                  &registers[REGISTER_BYTE (regnum) + row *
						 MIPS_REGSIZE],
                  TYPE_LENGTH (get_vector_element_type ()));
          register_valid[temp_regnum + 64 * row] = 1;
          target_store_registers (temp_regnum + 64 * row);
        }
    }
}

Note that although $vector0 shares the same space in the regs
cache as $v0_00 thru $v0_63, it ($vector0) has it's own
cache-valid bit.  This is so that the ARCH_FETCH_PSEUDO_REGS
function will be called for $vector0 whether or not $v0_00
is in the cache.  In order for $vector0 to be marked "cached",
it is necessary that ALL of the component registers be cached.
But only this function needs to know that in order to "fetch"
$vector0, it is necessary to fetch all 64 component vectors.

Moreover, $vrow0 is not "cached" even if ALL of its component
registers are in the cache.  In order for $vrow0 to be "fetched",
it is necessary to copy the values of $v0_00 thru $v15_00 from
their own storage location into $vrow0's storage location.

Therefore, the ARCH_FETCH_PSEUDO_REGISTERS function will be
called for every pseudo-register, alias or not, regardless 
of whether any other register is or is not in the cache.
And the same for ARCH_STORE_PSEUDO_REGISTERS.

Obviously, a highly desireable next step will be to get these
#defines into the gdbarch namespace.

				Cheers, 
				Michael

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