summaryrefslogtreecommitdiffstats
path: root/c/src/exec/score/cpu/hppa1.1/cpu_asm.s
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/exec/score/cpu/hppa1.1/cpu_asm.s')
-rw-r--r--c/src/exec/score/cpu/hppa1.1/cpu_asm.s797
1 files changed, 797 insertions, 0 deletions
diff --git a/c/src/exec/score/cpu/hppa1.1/cpu_asm.s b/c/src/exec/score/cpu/hppa1.1/cpu_asm.s
new file mode 100644
index 0000000000..43a5bb2499
--- /dev/null
+++ b/c/src/exec/score/cpu/hppa1.1/cpu_asm.s
@@ -0,0 +1,797 @@
+# @(#)cpu_asm.S 1.5 - 95/04/24
+#
+#
+# TODO:
+# Context_switch needs to only save callee save registers
+# I think this means can skip: r1, r2, r19-29, r31
+# Ref: p 3-2 of Procedure Calling Conventions Manual
+# This should be #ifndef DEBUG so that debugger has
+# accurate visibility into all registers
+#
+# This file contains the assembly code for the HPPA implementation
+# of RTEMS.
+#
+# COPYRIGHT (c) 1994,95 by Division Incorporated
+#
+# To anyone who acknowledges that this file is provided "AS IS"
+# without any express or implied warranty:
+# permission to use, copy, modify, and distribute this file
+# for any purpose is hereby granted without fee, provided that
+# the above copyright notice and this notice appears in all
+# copies, and that the name of Division Incorporated not be
+# used in advertising or publicity pertaining to distribution
+# of the software without specific, written prior permission.
+# Division Incorporated makes no representations about the
+# suitability of this software for any purpose.
+#
+# $Id$
+#
+
+#include <rtems/hppa.h>
+#include <rtems/cpu_asm.h>
+#include <rtems/cpu.h>
+
+#include <offsets.h>
+
+ .SPACE $PRIVATE$
+ .SUBSPA $DATA$,QUAD=1,ALIGN=8,ACCESS=31
+ .SUBSPA $BSS$,QUAD=1,ALIGN=8,ACCESS=31,ZERO,SORT=82
+ .SPACE $TEXT$
+ .SUBSPA $LIT$,QUAD=0,ALIGN=8,ACCESS=44
+ .SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY
+ .SPACE $TEXT$
+ .SUBSPA $CODE$
+
+#
+# Special register usage for context switch and interrupts
+# Stay away from %cr28 which is used for TLB misses on 72000
+#
+
+isr_arg0 .reg %cr24
+isr_r9 .reg %cr25
+
+#
+# Interrupt stack frame looks like this
+#
+# offset item
+# -----------------------------------------------------------------
+# INTEGER_CONTEXT_OFFSET Context_Control
+# FP_CONTEXT_OFFSET Context_Control_fp
+#
+# It is padded out to a multiple of 64
+#
+
+
+# PAGE^L
+# void __Generic_ISR_Handler()
+#
+# This routine provides the RTEMS interrupt management.
+#
+# NOTE:
+# Upon entry, the stack will contain a stack frame back to the
+# interrupted task. If dispatching is enabled, this is the
+# outer most interrupt, (and a context switch is necessary or
+# the current task has signals), then set up the stack to
+# transfer control to the interrupt dispatcher.
+#
+#
+# We jump here from the interrupt vector.
+# The hardware has done some stuff for us:
+# PSW saved in IPSW
+# PSW set to 0
+# PSW[E] set to default (0)
+# PSW[M] set to 1 iff this is HPMC
+#
+# IIA queue is frozen (since PSW[Q] is now 0)
+# privilege level promoted to 0
+# IIR, ISR, IOR potentially updated if PSW[Q] was 1 at trap
+# registers GR 1,8,9,16,17,24,25 copied to shadow regs
+# SHR 0 1 2 3 4 5 6
+#
+# Our vector stub did the following
+# placed vector number is in r1
+#
+# stub
+# r1 <- vector number
+# save ipsw under rock
+# ipsw = ipsw & ~1 -- disable ints
+# save qregs under rock
+# qra = _Generic_ISR_handler
+# rfi
+#
+################################################
+
+# Distinct Interrupt Entry Points
+#
+# The following macro and the 32 instantiations of the macro
+# are necessary to determine which interrupt vector occurred.
+# The following macro allows a unique entry point to be defined
+# for each vector.
+#
+# r9 was loaded with the vector before branching here
+# scratch registers available: gr1, gr8, gr9, gr16, gr17, gr24
+#
+# NOTE:
+# .align 32 doesn not seem to work in the continuation below
+# so just have to count 8 instructions
+#
+# NOTE:
+# this whole scheme needs to be rethought for TLB traps which
+# have requirements about what tlb faults they can incur.
+# ref: TLB Operation Requirements in 1.1 arch book
+
+#define THANDLER(vector) \
+ mtctl %r9, isr_r9 ! \
+ b _Generic_ISR_Handler! \
+ ldi vector, %r9! \
+ nop ! \
+ nop ! \
+ nop ! \
+ nop ! \
+ nop
+
+ .align 4096
+ .EXPORT IVA_Table,ENTRY,PRIV_LEV=0
+IVA_Table:
+ .PROC
+ .CALLINFO FRAME=0,NO_CALLS
+ .ENTRY
+
+ THANDLER(0) /* unused */
+
+ THANDLER(HPPA_INTERRUPT_HIGH_PRIORITY_MACHINE_CHECK)
+
+ THANDLER(HPPA_INTERRUPT_POWER_FAIL)
+
+ THANDLER(HPPA_INTERRUPT_RECOVERY_COUNTER)
+
+ THANDLER(HPPA_INTERRUPT_EXTERNAL_INTERRUPT)
+
+ THANDLER(HPPA_INTERRUPT_LOW_PRIORITY_MACHINE_CHECK)
+
+ THANDLER(HPPA_INTERRUPT_INSTRUCTION_TLB_MISS)
+
+ THANDLER(HPPA_INTERRUPT_INSTRUCTION_MEMORY_PROTECTION)
+
+ THANDLER(HPPA_INTERRUPT_ILLEGAL_INSTRUCTION)
+
+ THANDLER(HPPA_INTERRUPT_BREAK_INSTRUCTION)
+
+ THANDLER(HPPA_INTERRUPT_PRIVILEGED_OPERATION)
+
+ THANDLER(HPPA_INTERRUPT_PRIVILEGED_REGISTER)
+
+ THANDLER(HPPA_INTERRUPT_OVERFLOW)
+
+ THANDLER(HPPA_INTERRUPT_CONDITIONAL)
+
+ THANDLER(HPPA_INTERRUPT_ASSIST_EXCEPTION)
+
+ THANDLER(HPPA_INTERRUPT_DATA_TLB_MISS)
+
+ THANDLER(HPPA_INTERRUPT_NON_ACCESS_INSTRUCTION_TLB_MISS)
+
+ THANDLER(HPPA_INTERRUPT_NON_ACCESS_DATA_TLB_MISS)
+
+ THANDLER(HPPA_INTERRUPT_DATA_MEMORY_PROTECTION)
+
+ THANDLER(HPPA_INTERRUPT_DATA_MEMORY_BREAK)
+
+ THANDLER(HPPA_INTERRUPT_TLB_DIRTY_BIT)
+
+ THANDLER(HPPA_INTERRUPT_PAGE_REFERENCE)
+
+ THANDLER(HPPA_INTERRUPT_ASSIST_EMULATION)
+
+ THANDLER(HPPA_INTERRUPT_HIGHER_PRIVILEGE_TRANSFER)
+
+ THANDLER(HPPA_INTERRUPT_LOWER_PRIVILEGE_TRANSFER)
+
+ THANDLER(HPPA_INTERRUPT_TAKEN_BRANCH)
+
+ THANDLER(HPPA_INTERRUPT_DATA_MEMORY_ACCESS_RIGHTS)
+
+ THANDLER(HPPA_INTERRUPT_DATA_MEMORY_PROTECTION_ID)
+
+ THANDLER(HPPA_INTERRUPT_UNALIGNED_DATA_REFERENCE)
+
+ THANDLER(HPPA_INTERRUPT_PERFORMANCE_MONITOR)
+
+ THANDLER(HPPA_INTERRUPT_INSTRUCTION_DEBUG)
+
+ THANDLER(HPPA_INTERRUPT_DATA_DEBUG)
+
+ .EXIT
+ .PROCEND
+
+ .EXPORT _Generic_ISR_Handler,ENTRY,PRIV_LEV=0
+_Generic_ISR_Handler:
+ .PROC
+ .CALLINFO FRAME=0,NO_CALLS
+ .ENTRY
+
+# Turn on the D bit in psw so we can start saving stuff on stack
+# (interrupt context pieces that need to be saved before the RFI)
+
+ ssm HPPA_PSW_D, %r0
+ mtctl arg0, isr_arg0
+
+# save interrupt state
+ mfctl ipsw, arg0
+ stw arg0, IPSW_OFFSET(sp)
+
+ mfctl iir, arg0
+ stw arg0, IIR_OFFSET(sp)
+
+ mfctl ior, arg0
+ stw arg0, IOR_OFFSET(sp)
+
+ mfctl pcoq, arg0
+ stw arg0, PCOQFRONT_OFFSET(sp)
+
+ mtctl %r0, pcoq
+ mfctl pcoq, arg0
+ stw arg0, PCOQBACK_OFFSET(sp)
+
+ mfctl %sar, arg0
+ stw arg0, SAR_OFFSET(sp)
+
+# Prepare to re-enter virtual mode
+# We need Q in case the interrupt handler enables interrupts
+#
+
+ ldil L%CPU_PSW_DEFAULT, arg0
+ ldo R%CPU_PSW_DEFAULT(arg0), arg0
+ mtctl arg0, ipsw
+
+# Now jump to "rest_of_isr_handler" with the rfi
+# We are assuming the space queues are all correct already
+
+ ldil L%rest_of_isr_handler, arg0
+ ldo R%rest_of_isr_handler(arg0), arg0
+ mtctl arg0, pcoq
+ ldo 4(arg0), arg0
+ mtctl arg0, pcoq
+
+ rfi
+ nop
+
+# At this point we are back in virtual mode and all our
+# normal addressing is once again ok.
+
+rest_of_isr_handler:
+
+#
+# Build an interrupt frame to hold the contexts we will need.
+# We have already saved the interrupt items on the stack
+
+# At this point the following registers are damaged wrt the interrupt
+# reg current value saved value
+# ------------------------------------------------
+# arg0 scratch isr_arg0 (ctl)
+# r9 vector number isr_r9 (ctl)
+#
+# Point to beginning of integer context and
+# save the integer context
+ stw %r1,R1_OFFSET(sp)
+ stw %r2,R2_OFFSET(sp)
+ stw %r3,R3_OFFSET(sp)
+ stw %r4,R4_OFFSET(sp)
+ stw %r5,R5_OFFSET(sp)
+ stw %r6,R6_OFFSET(sp)
+ stw %r7,R7_OFFSET(sp)
+ stw %r8,R8_OFFSET(sp)
+ stw %r9,R9_OFFSET(sp)
+ stw %r10,R10_OFFSET(sp)
+ stw %r11,R11_OFFSET(sp)
+ stw %r12,R12_OFFSET(sp)
+ stw %r13,R13_OFFSET(sp)
+ stw %r14,R14_OFFSET(sp)
+ stw %r15,R15_OFFSET(sp)
+ stw %r16,R16_OFFSET(sp)
+ stw %r17,R17_OFFSET(sp)
+ stw %r18,R18_OFFSET(sp)
+ stw %r19,R19_OFFSET(sp)
+ stw %r20,R20_OFFSET(sp)
+ stw %r21,R21_OFFSET(sp)
+ stw %r22,R22_OFFSET(sp)
+ stw %r23,R23_OFFSET(sp)
+ stw %r24,R24_OFFSET(sp)
+ stw %r25,R25_OFFSET(sp)
+ stw %r26,R26_OFFSET(sp)
+ stw %r27,R27_OFFSET(sp)
+ stw %r28,R28_OFFSET(sp)
+ stw %r29,R29_OFFSET(sp)
+ stw %r30,R30_OFFSET(sp)
+ stw %r31,R31_OFFSET(sp)
+
+# Now most registers are available since they have been saved
+#
+# The following items are currently wrong in the integer context
+# reg current value saved value
+# ------------------------------------------------
+# arg0 scratch isr_arg0 (ctl)
+# r9 vector number isr_r9 (ctl)
+#
+# Fix them
+
+ mfctl isr_arg0,%r3
+ stw %r3,ARG0_OFFSET(sp)
+
+ mfctl isr_r9,%r3
+ stw %r3,R9_OFFSET(sp)
+
+#
+# At this point we are done with isr_arg0, and isr_r9 control registers
+#
+
+
+# Point to beginning of float context and
+# save the floating point context -- doing whatever patches are necessary
+ .call ARGW0=GR
+ bl _CPU_Save_float_context,%r2
+ ldo FP_CONTEXT_OFFSET(sp),arg0
+
+# save the ptr to interrupt frame as an argument for the interrupt handler
+ copy sp, arg1
+
+# Advance the frame to point beyond all interrupt contexts (integer & float)
+# this also includes the pad to align to 64byte stack boundary
+ ldo CPU_INTERRUPT_FRAME_SIZE(sp), sp
+
+# r3 -- &_ISR_Nest_level
+# r5 -- value _ISR_Nest_level
+# r4 -- &_Thread_Dispatch_disable_level
+# r6 -- value _Thread_Dispatch_disable_level
+# r9 -- vector number
+
+ .import _ISR_Nest_level,data
+ ldil L%_ISR_Nest_level,%r3
+ ldo R%_ISR_Nest_level(%r3),%r3
+ ldw 0(%r3),%r5
+
+ .import _Thread_Dispatch_disable_level,data
+ ldil L%_Thread_Dispatch_disable_level,%r4
+ ldo R%_Thread_Dispatch_disable_level(%r4),%r4
+ ldw 0(%r4),%r6
+
+# increment interrupt nest level counter. If outermost interrupt
+# switch the stack and squirrel away the previous sp.
+ addi 1,%r5,%r5
+ stw %r5, 0(%r3)
+
+# compute and save new stack (with frame)
+# just in case we are nested -- simpler this way
+ comibf,= 1,%r5,stack_done
+ ldo 128(sp),%r7
+
+#
+# Switch to interrupt stack allocated by the interrupt manager (intr.c)
+#
+ .import _CPU_Interrupt_stack_low,data
+ ldil L%_CPU_Interrupt_stack_low,%r7
+ ldw R%_CPU_Interrupt_stack_low(%r7),%r7
+ ldo 128(%r7),%r7
+
+stack_done:
+# save our current stack pointer where the "old sp" is supposed to be
+ stw sp, -4(%r7)
+# and switch stacks (or advance old stack in nested case)
+ copy %r7, sp
+
+# increment the dispatch disable level counter.
+ addi 1,%r6,%r6
+ stw %r6, 0(%r4)
+
+# load address of user handler
+ .import _ISR_Vector_table,data
+ ldil L%_ISR_Vector_table,%r8
+ ldo R%_ISR_Vector_table(%r8),%r8
+ ldwx,s %r9(%r8),%r8
+
+# invoke user interrupt handler
+# Interrupts are currently disabled, as per RTEMS convention
+# The handler has the option of re-enabling interrupts
+# NOTE: can not use 'bl' since it uses "pc-relative" addressing
+# and we are using a hard coded address from a table
+# So... we fudge r2 ourselves (ala dynacall)
+#
+ copy %r9, %r26
+ .call ARGW0=GR, ARGW1=GR
+ blr %r0, rp
+ bv,n 0(%r8)
+
+post_user_interrupt_handler:
+
+# Back from user handler(s)
+# Disable external interrupts (since the interrupt handler could
+# have turned them on) and return to the interrupted task stack (assuming
+# (_ISR_Nest_level == 0)
+
+ rsm HPPA_PSW_I, %r0
+ ldw -4(sp), sp
+
+# r3 -- &_ISR_Nest_level
+# r5 -- value _ISR_Nest_level
+# r4 -- &_Thread_Dispatch_disable_level
+# r6 -- value _Thread_Dispatch_disable_level
+
+ .import _ISR_Nest_level,data
+ ldil L%_ISR_Nest_level,%r3
+ ldo R%_ISR_Nest_level(%r3),%r3
+ ldw 0(%r3),%r5
+
+ .import _Thread_Dispatch_disable_level,data
+ ldil L%_Thread_Dispatch_disable_level,%r4
+ ldo R%_Thread_Dispatch_disable_level(%r4),%r4
+ ldw 0(%r4), %r6
+
+# decrement isr nest level
+ addi -1, %r5, %r5
+ stw %r5, 0(%r3)
+
+# decrement dispatch disable level counter and, if not 0, go on
+ addi -1,%r6,%r6
+ comibf,= 0,%r6,isr_restore
+ stw %r6, 0(%r4)
+
+# check whether or not a context switch is necessary
+ .import _Context_Switch_necessary,data
+ ldil L%_Context_Switch_necessary,%r8
+ ldw R%_Context_Switch_necessary(%r8),%r8
+ comibf,=,n 0,%r8,ISR_dispatch
+
+# check whether or not a context switch is necessary because an ISR
+# sent signals to the interrupted task
+ .import _ISR_Signals_to_thread_executing,data
+ ldil L%_ISR_Signals_to_thread_executing,%r8
+ ldw R%_ISR_Signals_to_thread_executing(%r8),%r8
+ comibt,=,n 0,%r8,isr_restore
+
+# OK, something happened while in ISR and we need to switch to a task
+# other than the one which was interrupted or the
+# ISR_Signals_to_thread_executing case
+# We also turn on interrupts, since the interrupted task had them
+# on (obviously :-) and Thread_Dispatch is happy to leave ints on.
+#
+
+ISR_dispatch:
+ ssm HPPA_PSW_I, %r0
+
+ .import _Thread_Dispatch,code
+ .call
+ bl _Thread_Dispatch,%r2
+ ldo 128(sp),sp
+
+ ldo -128(sp),sp
+
+ rsm HPPA_PSW_I, %r0
+
+isr_restore:
+
+# Get a pointer to beginning of our stack frame
+ ldo -CPU_INTERRUPT_FRAME_SIZE(sp), %arg1
+
+# restore float
+ .call ARGW0=GR
+ bl _CPU_Restore_float_context,%r2
+ ldo FP_CONTEXT_OFFSET(%arg1), arg0
+
+ copy %arg1, %arg0
+
+# ********** FALL THRU **********
+
+# Jump here from bottom of Context_Switch
+# Also called directly by _CPU_Context_Restart_self via _Thread_Restart_self
+# restore interrupt state
+#
+
+ .EXPORT _CPU_Context_restore
+_CPU_Context_restore:
+
+# Turn off Q & I so we can write pcoq
+ rsm HPPA_PSW_Q + HPPA_PSW_I, %r0
+
+ ldw IPSW_OFFSET(arg0), %r8
+ mtctl %r8, ipsw
+
+ ldw SAR_OFFSET(arg0), %r9
+ mtctl %r9, sar
+
+ ldw PCOQFRONT_OFFSET(arg0), %r10
+ mtctl %r10, pcoq
+
+ ldw PCOQBACK_OFFSET(arg0), %r11
+ mtctl %r11, pcoq
+
+#
+# restore integer state
+#
+ ldw R1_OFFSET(arg0),%r1
+ ldw R2_OFFSET(arg0),%r2
+ ldw R3_OFFSET(arg0),%r3
+ ldw R4_OFFSET(arg0),%r4
+ ldw R5_OFFSET(arg0),%r5
+ ldw R6_OFFSET(arg0),%r6
+ ldw R7_OFFSET(arg0),%r7
+ ldw R8_OFFSET(arg0),%r8
+ ldw R9_OFFSET(arg0),%r9
+ ldw R10_OFFSET(arg0),%r10
+ ldw R11_OFFSET(arg0),%r11
+ ldw R12_OFFSET(arg0),%r12
+ ldw R13_OFFSET(arg0),%r13
+ ldw R14_OFFSET(arg0),%r14
+ ldw R15_OFFSET(arg0),%r15
+ ldw R16_OFFSET(arg0),%r16
+ ldw R17_OFFSET(arg0),%r17
+ ldw R18_OFFSET(arg0),%r18
+ ldw R19_OFFSET(arg0),%r19
+ ldw R20_OFFSET(arg0),%r20
+ ldw R21_OFFSET(arg0),%r21
+ ldw R22_OFFSET(arg0),%r22
+ ldw R23_OFFSET(arg0),%r23
+ ldw R24_OFFSET(arg0),%r24
+ ldw R25_OFFSET(arg0),%r25
+# skipping r26 (aka arg0) until we are done with it
+ ldw R27_OFFSET(arg0),%r27
+ ldw R28_OFFSET(arg0),%r28
+ ldw R29_OFFSET(arg0),%r29
+ ldw R30_OFFSET(arg0),%r30
+ ldw R31_OFFSET(arg0),%r31
+
+# Must load r26 last since it is arg0
+ ldw R26_OFFSET(arg0),%r26
+
+isr_exit:
+ rfi
+ .EXIT
+ .PROCEND
+
+#
+# This section is used to context switch floating point registers.
+# Ref: 6-35 of Architecture 1.1
+#
+# NOTE: since integer multiply uses the floating point unit,
+# we have to save/restore fp on every trap. We cannot
+# just try to keep track of fp usage.
+
+ .align 32
+ .EXPORT _CPU_Save_float_context,ENTRY,PRIV_LEV=0
+_CPU_Save_float_context:
+ .PROC
+ .CALLINFO FRAME=0,NO_CALLS
+ .ENTRY
+ fstds,ma %fr0,8(%arg0)
+ fstds,ma %fr1,8(%arg0)
+ fstds,ma %fr2,8(%arg0)
+ fstds,ma %fr3,8(%arg0)
+ fstds,ma %fr4,8(%arg0)
+ fstds,ma %fr5,8(%arg0)
+ fstds,ma %fr6,8(%arg0)
+ fstds,ma %fr7,8(%arg0)
+ fstds,ma %fr8,8(%arg0)
+ fstds,ma %fr9,8(%arg0)
+ fstds,ma %fr10,8(%arg0)
+ fstds,ma %fr11,8(%arg0)
+ fstds,ma %fr12,8(%arg0)
+ fstds,ma %fr13,8(%arg0)
+ fstds,ma %fr14,8(%arg0)
+ fstds,ma %fr15,8(%arg0)
+ fstds,ma %fr16,8(%arg0)
+ fstds,ma %fr17,8(%arg0)
+ fstds,ma %fr18,8(%arg0)
+ fstds,ma %fr19,8(%arg0)
+ fstds,ma %fr20,8(%arg0)
+ fstds,ma %fr21,8(%arg0)
+ fstds,ma %fr22,8(%arg0)
+ fstds,ma %fr23,8(%arg0)
+ fstds,ma %fr24,8(%arg0)
+ fstds,ma %fr25,8(%arg0)
+ fstds,ma %fr26,8(%arg0)
+ fstds,ma %fr27,8(%arg0)
+ fstds,ma %fr28,8(%arg0)
+ fstds,ma %fr29,8(%arg0)
+ fstds,ma %fr30,8(%arg0)
+ fstds %fr31,0(%arg0)
+ bv 0(%r2)
+ addi -(31*8), %arg0, %arg0 ; restore arg0 just for fun
+ .EXIT
+ .PROCEND
+
+ .align 32
+ .EXPORT _CPU_Restore_float_context,ENTRY,PRIV_LEV=0
+_CPU_Restore_float_context:
+ .PROC
+ .CALLINFO FRAME=0,NO_CALLS
+ .ENTRY
+ addi (31*8), %arg0, %arg0 ; point at last double
+ fldds 0(%arg0),%fr31
+ fldds,mb -8(%arg0),%fr30
+ fldds,mb -8(%arg0),%fr29
+ fldds,mb -8(%arg0),%fr28
+ fldds,mb -8(%arg0),%fr27
+ fldds,mb -8(%arg0),%fr26
+ fldds,mb -8(%arg0),%fr25
+ fldds,mb -8(%arg0),%fr24
+ fldds,mb -8(%arg0),%fr23
+ fldds,mb -8(%arg0),%fr22
+ fldds,mb -8(%arg0),%fr21
+ fldds,mb -8(%arg0),%fr20
+ fldds,mb -8(%arg0),%fr19
+ fldds,mb -8(%arg0),%fr18
+ fldds,mb -8(%arg0),%fr17
+ fldds,mb -8(%arg0),%fr16
+ fldds,mb -8(%arg0),%fr15
+ fldds,mb -8(%arg0),%fr14
+ fldds,mb -8(%arg0),%fr13
+ fldds,mb -8(%arg0),%fr12
+ fldds,mb -8(%arg0),%fr11
+ fldds,mb -8(%arg0),%fr10
+ fldds,mb -8(%arg0),%fr9
+ fldds,mb -8(%arg0),%fr8
+ fldds,mb -8(%arg0),%fr7
+ fldds,mb -8(%arg0),%fr6
+ fldds,mb -8(%arg0),%fr5
+ fldds,mb -8(%arg0),%fr4
+ fldds,mb -8(%arg0),%fr3
+ fldds,mb -8(%arg0),%fr2
+ fldds,mb -8(%arg0),%fr1
+ bv 0(%r2)
+ fldds,mb -8(%arg0),%fr0
+ .EXIT
+ .PROCEND
+
+#
+# These 2 small routines are unused right now.
+# Normally we just go thru _CPU_Save_float_context (and Restore)
+#
+# Here we just deref the ptr and jump up, letting _CPU_Save_float_context
+# do the return for us.
+#
+ .EXPORT _CPU_Context_save_fp,ENTRY,PRIV_LEV=0
+_CPU_Context_save_fp:
+ .PROC
+ .CALLINFO FRAME=0,NO_CALLS
+ .ENTRY
+ bl _CPU_Save_float_context, %r0
+ ldw 0(%arg0), %arg0
+ .EXIT
+ .PROCEND
+
+ .EXPORT _CPU_Context_restore_fp,ENTRY,PRIV_LEV=0
+_CPU_Context_restore_fp:
+ .PROC
+ .CALLINFO FRAME=0,NO_CALLS
+ .ENTRY
+ bl _CPU_Restore_float_context, %r0
+ ldw 0(%arg0), %arg0
+ .EXIT
+ .PROCEND
+
+
+# void _CPU_Context_switch( run_context, heir_context )
+#
+# This routine performs a normal non-FP context switch.
+#
+
+ .align 32
+ .EXPORT _CPU_Context_switch,ENTRY,PRIV_LEV=0,ARGW0=GR,ARGW1=GR
+_CPU_Context_switch:
+ .PROC
+ .CALLINFO FRAME=64
+ .ENTRY
+
+# Save the integer context
+ stw %r1,R1_OFFSET(arg0)
+ stw %r2,R2_OFFSET(arg0)
+ stw %r3,R3_OFFSET(arg0)
+ stw %r4,R4_OFFSET(arg0)
+ stw %r5,R5_OFFSET(arg0)
+ stw %r6,R6_OFFSET(arg0)
+ stw %r7,R7_OFFSET(arg0)
+ stw %r8,R8_OFFSET(arg0)
+ stw %r9,R9_OFFSET(arg0)
+ stw %r10,R10_OFFSET(arg0)
+ stw %r11,R11_OFFSET(arg0)
+ stw %r12,R12_OFFSET(arg0)
+ stw %r13,R13_OFFSET(arg0)
+ stw %r14,R14_OFFSET(arg0)
+ stw %r15,R15_OFFSET(arg0)
+ stw %r16,R16_OFFSET(arg0)
+ stw %r17,R17_OFFSET(arg0)
+ stw %r18,R18_OFFSET(arg0)
+ stw %r19,R19_OFFSET(arg0)
+ stw %r20,R20_OFFSET(arg0)
+ stw %r21,R21_OFFSET(arg0)
+ stw %r22,R22_OFFSET(arg0)
+ stw %r23,R23_OFFSET(arg0)
+ stw %r24,R24_OFFSET(arg0)
+ stw %r25,R25_OFFSET(arg0)
+ stw %r26,R26_OFFSET(arg0)
+ stw %r27,R27_OFFSET(arg0)
+ stw %r28,R28_OFFSET(arg0)
+ stw %r29,R29_OFFSET(arg0)
+ stw %r30,R30_OFFSET(arg0)
+ stw %r31,R31_OFFSET(arg0)
+
+# fill in interrupt context section
+ stw %r2, PCOQFRONT_OFFSET(%arg0)
+ ldo 4(%r2), %r2
+ stw %r2, PCOQBACK_OFFSET(%arg0)
+
+# Generate a suitable IPSW by using the system default psw
+# with the current low bits added in.
+
+ ldil L%CPU_PSW_DEFAULT, %r2
+ ldo R%CPU_PSW_DEFAULT(%r2), %r2
+ ssm 0, %arg2
+ dep %arg2, 31, 8, %r2
+ stw %r2, IPSW_OFFSET(%arg0)
+
+# at this point, the running task context is completely saved
+# Now jump to the bottom of the interrupt handler to load the
+# heirs context
+
+ b _CPU_Context_restore
+ copy %arg1, %arg0
+
+ .EXIT
+ .PROCEND
+
+
+/*
+ * Find first bit
+ * NOTE:
+ * This is used (and written) only for the ready chain code and
+ * priority bit maps.
+ * Any other use constitutes fraud.
+ * Returns first bit from the least significant side.
+ * Eg: if input is 0x8001
+ * output will indicate the '1' bit and return 0.
+ * This is counter to HPPA bit numbering which calls this
+ * bit 31. This way simplifies the macros _CPU_Priority_Mask
+ * and _CPU_Priority_Bits_index.
+ *
+ * NOTE:
+ * We just use 16 bit version
+ * does not handle zero case
+ *
+ * Based on the UTAH Mach libc version of ffs.
+ */
+
+ .align 32
+ .EXPORT hppa_rtems_ffs,ENTRY,PRIV_LEV=0,ARGW0=GR
+hppa_rtems_ffs:
+ .PROC
+ .CALLINFO FRAME=0,NO_CALLS
+ .ENTRY
+
+#ifdef RETURN_ERROR_ON_ZERO
+ comb,= %arg0,%r0,ffsdone ; If arg0 is 0
+ ldi -1,%ret0 ; return -1
+#endif
+
+#if BITFIELD_SIZE == 32
+ ldi 31,%ret0 ; Set return to high bit
+ extru,= %arg0,31,16,%r0 ; If low 16 bits are non-zero
+ addi,tr -16,%ret0,%ret0 ; subtract 16 from bitpos
+ shd %r0,%arg0,16,%arg0 ; else shift right 16 bits
+#else
+ ldi 15,%ret0 ; Set return to high bit
+#endif
+ extru,= %arg0,31,8,%r0 ; If low 8 bits are non-zero
+ addi,tr -8,%ret0,%ret0 ; subtract 8 from bitpos
+ shd %r0,%arg0,8,%arg0 ; else shift right 8 bits
+ extru,= %arg0,31,4,%r0 ; If low 4 bits are non-zero
+ addi,tr -4,%ret0,%ret0 ; subtract 4 from bitpos
+ shd %r0,%arg0,4,%arg0 ; else shift right 4 bits
+ extru,= %arg0,31,2,%r0 ; If low 2 bits are non-zero
+ addi,tr -2,%ret0,%ret0 ; subtract 2 from bitpos
+ shd %r0,%arg0,2,%arg0 ; else shift right 2 bits
+ extru,= %arg0,31,1,%r0 ; If low bit is non-zero
+ addi -1,%ret0,%ret0 ; subtract 1 from bitpos
+ffsdone:
+ bv,n 0(%r2)
+ nop
+ .EXIT
+ .PROCEND