changeset 304:e206cd7d2ed1

Fix coprocessor register handling in ARM stub.
author msalter
date Thu, 22 Aug 2002 12:24:19 +0000
parents afd40c766438
children 82c554739834
files packages/hal/arm/arch/current/ChangeLog packages/hal/arm/arch/current/include/arm_stub.h packages/hal/arm/arch/current/include/hal_arch.h packages/hal/arm/arch/current/src/arm_stub.c
diffstat 4 files changed, 148 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/packages/hal/arm/arch/current/ChangeLog
+++ b/packages/hal/arm/arch/current/ChangeLog
@@ -1,3 +1,9 @@
+2002-08-21  Mark Salter  <msalter@redhat.com>
+
+	* src/arm_stub.c: Add support for large registers (e.g. FPU).
+	* include/arm_stub.h: Add infrastructure for support of coprocessors.
+	* include/hal_arch.h: Ditto.
+
 2002-08-02  Andrew Lunn <Andrew.Lunn@ascom.ch>
 
 	* cdl/hal_arm.cdl: Redboot exec command can now be disabled by CDL
--- a/packages/hal/arm/arch/current/include/arm_stub.h
+++ b/packages/hal/arm/arch/current/include/arm_stub.h
@@ -57,6 +57,13 @@
 extern "C" {
 #endif
 
+// The ARM has float (and possibly other coprocessor) registers that are
+// larger than it can hold in a target_register_t.
+#define TARGET_HAS_LARGE_REGISTERS
+
+// ARM stub has special needs for register handling (not all regs are the
+// the same size), so special put_register and get_register are provided.
+#define CYGARC_STUB_REGISTER_ACCESS_DEFINED 1
 
 #define NUMREGS    (16+8+2)  // 16 GPR, 8 FPR (unused), 2 PS
 
@@ -77,6 +84,9 @@ enum regnames {
     FPS, PS
 };
 
+#define HAL_STUB_REGISTERS_SIZE \
+ ((sizeof(GDB_Registers) + sizeof(target_register_t) - 1) / sizeof(target_register_t))
+
 #define PS_N 0x80000000
 #define PS_Z 0x40000000
 #define PS_C 0x20000000
--- a/packages/hal/arm/arch/current/include/hal_arch.h
+++ b/packages/hal/arm/arch/current/include/hal_arch.h
@@ -229,52 +229,78 @@ extern cyg_uint16 __thumb_breakinst;
 //--------------------------------------------------------------------------
 // Thread register state manipulation for GDB support.
 
-// GDB expects the registers in this structure:
-//   r0..r10, fp, ip, sp, lr, pc  - 4 bytes each
-//   f0..f7                       - 12 bytes each (N/A on ARM7)
-//   fps                          - 4 bytes       (N/A on ARM7)
-//   ps                           - 4 bytes
+// Register layout expected by GDB
+typedef struct
+{
+    cyg_uint32  gpr[16];
+    cyg_uint32  f0[3];
+    cyg_uint32  f1[3];
+    cyg_uint32  f2[3];
+    cyg_uint32  f3[3];
+    cyg_uint32  f4[3];
+    cyg_uint32  f5[3];
+    cyg_uint32  f6[3];
+    cyg_uint32  f7[3];
+    cyg_uint32  fps;
+    cyg_uint32  ps;
+} GDB_Registers;
 
 // Translate a stack pointer as saved by the thread context macros above into
 // a pointer to a HAL_SavedRegisters structure.
 #define HAL_THREAD_GET_SAVED_REGISTERS( _sp_, _regs_ )  \
         (_regs_) = (HAL_SavedRegisters *)(_sp_)
 
+// Copy a set of coprocessor registers from a HAL_SavedRegisters structure
+// into a GDB_Registers structure. GDB expects placeholders for FP regs
+// even for non-FP targets, so we just zero fill the fields.
+#define HAL_GET_GDB_COPROCESSOR_REGISTERS( _gdb_, _regs_ )      \
+    CYG_MACRO_START                                             \
+    cyg_uint32 *_p_ = _gdb_->f0;                                \
+    for(_i_ = 0; _i_ < (8 * 3); _i_++)                          \
+        *_p_++ = 0;                                             \
+    _gdb_->fps = 0;                                             \
+    CYG_MACRO_END
+
+// Copy coprocessor registers from a GDB_Registers structure into a
+// HAL_SavedRegisters structure.
+#define HAL_SET_GDB_COPROCESSOR_REGISTERS( _regs_, _gdb_ )
+
 // Copy a set of registers from a HAL_SavedRegisters structure into a
-// GDB ordered array.    
+// GDB_Registers structure.
 #define HAL_GET_GDB_REGISTERS( _aregval_, _regs_ )              \
     CYG_MACRO_START                                             \
-    CYG_ADDRWORD *_regval_ = (CYG_ADDRWORD *)(_aregval_);       \
+    GDB_Registers *_gdb_ = (GDB_Registers *)(_aregval_);        \
     int _i_;                                                    \
                                                                 \
     for( _i_ = 0; _i_ <= 10; _i_++ )                            \
-        _regval_[_i_] = (_regs_)->d[_i_];                       \
+        _gdb_->gpr[_i_] = (_regs_)->d[_i_];                     \
                                                                 \
-    _regval_[11] = (_regs_)->fp;                                \
-    _regval_[12] = (_regs_)->ip;                                \
-    _regval_[13] = (_regs_)->sp;                                \
-    _regval_[14] = (_regs_)->lr;                                \
-    _regval_[15] = (_regs_)->pc;                                \
-    _regval_[25] = (_regs_)->cpsr;                              \
-    for( _i_ = 0; _i_ < 8; _i_++ )                              \
-        _regval_[_i_+16] = 0;                                   \
+    _gdb_->gpr[11] = (_regs_)->fp;                              \
+    _gdb_->gpr[12] = (_regs_)->ip;                              \
+    _gdb_->gpr[13] = (_regs_)->sp;                              \
+    _gdb_->gpr[14] = (_regs_)->lr;                              \
+    _gdb_->gpr[15] = (_regs_)->pc;                              \
+    _gdb_->ps = (_regs_)->cpsr;                                 \
+    HAL_GET_GDB_COPROCESSOR_REGISTERS(_gdb_,_regs_);            \
     CYG_MACRO_END
 
-// Copy a GDB ordered array into a HAL_SavedRegisters structure.
+// Copy a set of registers from a GDB_Registers structure into a
+// HAL_SavedRegisters structure.
 #define HAL_SET_GDB_REGISTERS( _regs_ , _aregval_ )             \
     CYG_MACRO_START                                             \
-    CYG_ADDRWORD *_regval_ = (CYG_ADDRWORD *)(_aregval_);       \
+    GDB_Registers *_gdb_ = (GDB_Registers *)(_aregval_);        \
     int _i_;                                                    \
                                                                 \
     for( _i_ = 0; _i_ <= 10; _i_++ )                            \
-        (_regs_)->d[_i_] = _regval_[_i_];                       \
+        (_regs_)->d[_i_] = _gdb_->gpr[_i_];                     \
                                                                 \
-    (_regs_)->fp = _regval_[11];                                \
-    (_regs_)->ip = _regval_[12];                                \
-    (_regs_)->sp = _regval_[13];                                \
-    (_regs_)->lr = _regval_[14];                                \
-    (_regs_)->pc = _regval_[15];                                \
-    (_regs_)->cpsr = _regval_[25];                              \
+    (_regs_)->fp = _gdb_->gpr[11];                              \
+    (_regs_)->ip = _gdb_->gpr[12];                              \
+    (_regs_)->sp = _gdb_->gpr[13];                              \
+    (_regs_)->lr = _gdb_->gpr[14];                              \
+    (_regs_)->pc = _gdb_->gpr[15];                              \
+    (_regs_)->cpsr = _gdb_->ps;                                 \
+    HAL_SET_GDB_COPROCESSOR_REGISTERS(_regs_,_gdb_);            \
     CYG_MACRO_END
 
 #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) || defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT)
--- a/packages/hal/arm/arch/current/src/arm_stub.c
+++ b/packages/hal/arm/arch/current/src/arm_stub.c
@@ -151,6 +151,87 @@ void set_pc (target_register_t pc)
     put_register (PC, pc);
 }
 
+// Calculate byte offset a given register from start of register save area.
+static int
+reg_offset(regnames_t reg)
+{
+    int base_offset;
+
+    if (reg < F0)
+	return reg * 4;
+
+    base_offset = 16 * 4;
+
+    if (reg < FPS)
+	return base_offset + ((reg - F0) * 12);
+
+    base_offset += (8 * 12);
+
+    if (reg <= PS)
+	return base_offset + ((reg - FPS) * 4);
+
+    return -1;  // Should never happen!
+}
+
+
+// Return the currently-saved value corresponding to register REG of
+// the exception context.
+target_register_t 
+get_register (regnames_t reg)
+{
+    target_register_t val;
+    int offset = reg_offset(reg);
+
+    if (REGSIZE(reg) > sizeof(target_register_t) || offset == -1)
+	return -1;
+
+    val = _registers[offset/sizeof(target_register_t)];
+
+    return val;
+}
+
+// Store VALUE in the register corresponding to WHICH in the exception
+// context.
+void 
+put_register (regnames_t which, target_register_t value)
+{
+    int offset = reg_offset(which);
+
+    if (REGSIZE(which) > sizeof(target_register_t) || offset == -1)
+	return;
+
+    _registers[offset/sizeof(target_register_t)] = value;
+}
+
+// Write the contents of register WHICH into VALUE as raw bytes. This
+// is only used for registers larger than sizeof(target_register_t).
+// Return non-zero if it is a valid register.
+int
+get_register_as_bytes (regnames_t which, char *value)
+{
+    int offset = reg_offset(which);
+
+    if (offset != -1) {
+	memcpy (value, (char *)_registers + offset, REGSIZE(which));
+	return 1;
+    }
+    return 0;
+}
+
+// Alter the contents of saved register WHICH to contain VALUE. This
+// is only used for registers larger than sizeof(target_register_t).
+// Return non-zero if it is a valid register.
+int
+put_register_as_bytes (regnames_t which, char *value)
+{
+    int offset = reg_offset(which);
+
+    if (offset != -1) {
+	memcpy ((char *)_registers + offset, value, REGSIZE(which));
+	return 1;
+    }
+    return 0;
+}
 
 /*----------------------------------------------------------------------
  * Single-step support