This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
fix coprocessor register handling in ARM stub
- From: Mark Salter <msalter at redhat dot com>
- To: ecos-patches at sources dot redhat dot com
- Date: Thu, 22 Aug 2002 08:25:04 -0400
- Subject: fix coprocessor register handling in ARM stub
Index: hal/arm/arch/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/arm/arch/current/ChangeLog,v
retrieving revision 1.73
diff -u -p -5 -r1.73 ChangeLog
--- hal/arm/arch/current/ChangeLog 6 Aug 2002 14:34:03 -0000 1.73
+++ hal/arm/arch/current/ChangeLog 22 Aug 2002 12:19:44 -0000
@@ -1,5 +1,11 @@
+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
2002-07-15 Mark Salter <msalter@redhat.com>
Index: hal/arm/arch/current/include/arm_stub.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/arm/arch/current/include/arm_stub.h,v
retrieving revision 1.14
diff -u -p -5 -r1.14 arm_stub.h
--- hal/arm/arch/current/include/arm_stub.h 15 Jul 2002 19:37:12 -0000 1.14
+++ hal/arm/arch/current/include/arm_stub.h 22 Aug 2002 12:19:44 -0000
@@ -55,10 +55,17 @@
#ifdef __cplusplus
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
#define REGSIZE( _x_ ) (((_x_) < F0 || (_x_) >= FPS) ? 4 : 12)
@@ -74,10 +81,13 @@ enum regnames {
R0, R1, R2, R3, R4, R5, R6, R7,
R8, R9, R10, FP, IP, SP, LR, PC,
F0, F1, F2, F3, F4, F5, F6, F7,
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
#define PS_V 0x10000000
Index: hal/arm/arch/current/include/hal_arch.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/arm/arch/current/include/hal_arch.h,v
retrieving revision 1.19
diff -u -p -5 -r1.19 hal_arch.h
--- hal/arm/arch/current/include/hal_arch.h 23 May 2002 23:01:42 -0000 1.19
+++ hal/arm/arch/current/include/hal_arch.h 22 Aug 2002 12:19:45 -0000
@@ -227,56 +227,82 @@ extern cyg_uint16 __thumb_breakinst;
((void*)&__arm_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)
#define HAL_GET_PROFILE_INFO( _thepc_, _thesp_ ) \
CYG_MACRO_START \
Index: hal/arm/arch/current/src/arm_stub.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/arm/arch/current/src/arm_stub.c,v
retrieving revision 1.23
diff -u -p -5 -r1.23 arm_stub.c
--- hal/arm/arch/current/src/arm_stub.c 23 May 2002 23:01:42 -0000 1.23
+++ hal/arm/arch/current/src/arm_stub.c 22 Aug 2002 12:19:46 -0000
@@ -149,10 +149,91 @@ int __is_bsp_syscall(void)
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
*/