9
0
Fork 0
nuttx-bb/nuttx/arch/8051/src/up_head.S

472 lines
9.7 KiB
ArmAsm

/************************************************************
* up_head.S
*
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name Gregory Nutt nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************/
/************************************************************
* Included Files
************************************************************/
#include <nuttx/config.h>
#include <nuttx/irq.h>
#include "up_internal.h"
.module up_head
.optsdcc -mmcs51 --model-large
/************************************************************
* Private Data
************************************************************/
.area REG_BANK_0 (REL,OVR,DATA)
.ds 8
#ifndef CONFIG_8052_TIMER2
.area XSEG
_g_timer0tick:
.ds 1
#endif
/************************************************************
* Public Data
************************************************************/
.globl _g_irqtos
.globl _g_irqcontext
.globl _g_irqregs
/************************************************************
* Public Functions
************************************************************/
.globl _irq_dispatch
.globl _up_restoreregisters
/************************************************************
* Program entry points
************************************************************/
/* Program entry is through PROGRAM_BASE. This is just a
* branch to our start up logic.
*/
.area CODE1 (ABS)
.org PROGRAM_BASE
ljmp start
/* These are indirect interrupt vectors. Logic in PAULMON2,
* captures the interrupt vectors (near address 0x0000) and
* re-routes them through the following entry points.
*
* Each of these saves acc and ie then passes the IRQ number
* to higher level logic in a
*/
.org PM2_VECTOR_EXTINT0
push acc
mov a, #EXT_INT0_IRQ
ljmp _up_interrupt
.org PM2_VECTOR_TIMER0
push acc
#ifdef CONFIG_8052_TIMER2
mov a, #TIMER0_IRQ
ljmp _up_interrupt
#else
ljmp _up_timer0
#endif
.org PM2_VECTOR_EXTINT1
push acc
mov a, #EXT_INT1_IRQ
ljmp _up_interrupt
.org PM2_VECTOR_TIMER1
push acc
mov a, #TIMER1_IRQ
ljmp _up_interrupt
.org PM2_VECTOR_UART
push acc
mov a, #UART_IRQ
ljmp _up_interrupt
.org PM2_VECTOR_TIMER2
push acc
mov a, #TIMER2_IRQ
ljmp _up_interrupt
/************************************************************
* Name: start
*
* Description:
* This is the initial entry point into NuttX
*
************************************************************/
start:
mov sp, #(STACK_BASE-1)
#ifdef CONFIG_ARCH_LEDS
lcall _up_ledinit
#endif
ljmp _os_start
/************************************************************
* Name: up_timer0
*
* Description:
* Timer 0, mode 0 can be used as a system timer. In that
* mode, the 1.8432 MHz clock is divided by 32. A single
* 8-bit value is incremented at 57600 Hz, which results
* in 225 Timer 0 overflow interrupts per second.
*
* The Timer0 interrupt vectors to this point which then
* does a software divide by 2 to get a system timer of
* 112.5Hz.
*
* On Entry:
*
* (1) acc on the stack and
* (2) the IRQ number(TIMER0_IRQ) in the accumulator
*
************************************************************/
#ifndef CONFIG_8052_TIMER2
_up_timer0:
ar2 = 0x02
ar3 = 0x03
ar4 = 0x04
ar5 = 0x05
ar6 = 0x06
ar7 = 0x07
ar0 = 0x00
ar1 = 0x01
/* ACC already on the stack; push IE. Then disable interrupts */
push ie
clr ea
/* Save the remaining registers with interrupts disabled
*
* a, ie, and dptr go on the stack.
*/
push dpl
push dph
/* Increment the tick counter */
mov dptr, #_g_timer0tick
movx a, @dptr
inc a
movx @dptr, a
/* If bit 0 is '0', then just return from the interrupt */
anl a, #0x01
jnz 00101$
ljmp _up_timer0exit
/* If bit 0 is '1', then process the interrupt */
00101$:
mov a, #TIMER0_IRQ
sjmp _up_timer0join
#endif
/************************************************************
* Name: up_interrupt
*
* Description:
* All interrupts vector to this point with:
*
* (1) acc on the stack and
* (2) the IRQ number in the accumulator
*
************************************************************/
_up_interrupt:
ar2 = 0x02
ar3 = 0x03
ar4 = 0x04
ar5 = 0x05
ar6 = 0x06
ar7 = 0x07
ar0 = 0x00
ar1 = 0x01
/* ACC already on the stack; push IE. Then disable interrupts */
push ie
clr ea
/* Save the remaining registers with interrupts disabled
*
* a, ie, and dptr go on the stack.
*/
push dpl
push dph
_up_timer0join:
/* Other registers go into the IRQ register save area */
push acc
mov dptr, #_g_irqregs
lcall _up_saveregisters
/* Show interrupt status on the LEDs */
#ifdef CONFIG_ARCH_LEDS
mov dpl, #LED_INIRQ
lcall _up_ledon
#endif
/* Save the IRQ number in r2 */
pop ar2
/* Mark that we are in an interrupt and provide the top
* of stack pointer to the context switching logic.
*/
mov dptr, #_g_irqtos
mov a, sp
movx @dptr, a
/* Nullify the context pointer. If a context switch is
* needed, this will be set to the address of the context
* structure.
*/
mov dptr, #_g_irqcontext
clr a
movx @dptr,a
inc dptr
movx @dptr,a
/* Now call void irq_dispatch(int irq, FAR void *context)
*
* First, create the first argument as (int)irqno
*/
mov dpl, r2
mov dph, #0
/* Create the second argument (void *context) on the stack */
push sp
clr a
push acc
/* Then dispatch the IRQ. */
lcall _irq_dispatch
pop acc
pop acc
/* Indicate that we are no longer in an interrupt */
mov dptr, #_g_irqtos
clr a
movx @dptr, a
/* Check if a context switch is pending */
mov dptr,#_g_irqcontext
movx a, @dptr
mov r2, a
inc dptr
movx a, @dptr
mov r3, a
orl a, r2
jnz 00001$
/* No context switch is pending. Restore registers
* from the interrupt register save area.
*/
mov dptr, #_g_irqregs
sjmp 00004$
00001$: /****************************************************/
/* A context switch is pending, clear g_irqcontext */
mov dpl, r2
mov dph, r3
clr a
movx @dptr, a
inc dptr
movx @dptr, a
#ifdef CONFIG_INTERRUPT_FRAME_DUMP
mov dpl, r2
mov dph, r3
push ar2
push ar3
lcall _up_dumpframe
pop ar3
pop ar2
#endif
/* Register usage in the following:
*
* R0 - Holds working the 8-bit IRAM pointer
* R1 - Not used
* R2-3 - Holds the working 16-bit XRAM pointer
* R4 - Holds the working byte count
* R5 - Holds the new stack pointer
* R6-7 - Not used
*/
/* Fetch r4 = context->nbytes */
mov dpl, r2
mov dph, r3
movx a, @dptr
mov r4, a
/* Save the new stack pointer in r5 */
add a, #(STACK_BASE-1)
mov r5, a
/* Save r2-3 = &context->stack */
inc dptr
push dpl
push dph
mov r2, dpl
mov r3, dph
/* Set r0 = stack base address */
mov r0, #STACK_BASE
/* Top of the copy loop */
00002$:
mov a, r4 /* a = bytes left to transfer */
dec r4 /* (for next time through the loop) */
jz 00003$ /* Jump if a = 0 (done) */
/* Fetch the next byte from context->stack */
mov dpl, r2
mov dph, r3
movx a,@dptr
/* Increment the XRAM pointer */
inc dptr
mov r2, dpl
mov r3, dph
/* Save the next byte into IRAM */
mov @r0, a
/* Increment the IRAM pointer */
inc r0
sjmp 00002$
/* The entire stack has been copied from XRAM into
* IRAM. Set the new stack pointer
*/
00003$:
pop dph
pop dpl
mov sp, r5
#ifdef CONFIG_INTERRUPT_FRAME_DUMP
push dpl
push dph
lcall _up_dumpstack
pop dph
pop dpl
#endif
/* Get the pointer to the register save area */
mov a, #STACK_SIZE
add a, dpl
mov dpl, a
clr a
addc a, dph
mov dph, a
00004$: /****************************************************/
/* Restore the context from the register save area
* and return from the interrupt. At this point, dptr
* holds the pointer to the memory region that holds
* the register save area. This could be either
* g_irqregs (no context switch) or &g_irqcontext->regs
* (context switch).
*/
#ifdef CONFIG_ARCH_LEDS
push dpl
push dph
mov dpl, #LED_INIRQ
lcall _up_ledoff
pop dph
pop dpl
#endif
/* Restore registers from the register save area */
lcall _up_restoreregisters
_up_timer0exit:
/* Restore registers from the stack and return */
pop dph
pop dpl
/* Restore the interrupt state per the stored IE value */
pop acc
jb acc.7,00005$
clr ie.7
sjmp 00006$
00005$:
setb ie.7
00006$:
pop acc
reti