* arch/z80/src/z8/switch.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_Z80_SRC_Z8_SWITCH_H
#define __ARCH_Z80_SRC_Z8_SWITCH_H
* Included Files
****************************************************************************/
#ifndef __ASSEMBLY__
# include <stdint.h>
# include <nuttx/sched.h>
# include <nuttx/arch.h>
#endif
#include "z80_internal.h"
* Pre-processor Definitions
****************************************************************************/
* These are used in the state field of 'struct z8_irqstate_s' structure
* to define the current state of the interrupt handling.
* These definition support "lazy" interrupt context saving. See comments
* below associated with s'truct z8_irqstate_s'.
*/
#define Z8_IRQSTATE_NONE 0
#define Z8_IRQSTATE_ENTRY 1
#define Z8_IRQSTATE_SAVED 2
* uint24_t values. These are
*
* value[0] = RP (MS byte) and Flags (LS) byte
* value[1] = PC
*
* The pointer to the save structure is a stack pointer at the time
* that z80_doirq() was called:
*
* PC[7:0]
* PC[15:8]
* Flags Register
* SP -> RP
*
* The stack pointer on return from interrupt can be obtained by adding 4
* to the pointer to the save structure.
*/
#define Z8_IRQSAVE_RPFLAGS (0)
#define Z8_IRQSAVE_PC (1)
#define Z8_IRQSAVE_REGS (2)
#define Z8_IRQSAVE_RP_OFFS (2*Z8_IRQSAVE_RPFLAGS)
#define Z8_IRQSAVE_FLAGS_OFFS (2*Z8_IRQSAVE_RPFLAGS+1)
#define Z8_IRQSAVE_PCH_OFFS (2*Z8_IRQSAVE_PC)
#define Z8_IRQSAVE_PCL_OFFS (2*Z8_IRQSAVE_PC+1)
#define Z8_IRQSAVE_SIZE (2*Z8_IRQSAVE_REGS)
*
* Common logic in arch/z80/src/common is customized for the z8
* context switching logic via the following macros.
*/
#define INIT_IRQCONTEXT() \
do { \
g_z8irqstate.state = Z8_IRQSTATE_NONE; \
} while (0)
* interrupt context. IN_INTERRUPT is the inline equivalent
* of up_interrupt_context().
*/
#define IN_INTERRUPT() \
(g_z8irqstate.state != Z8_IRQSTATE_NONE)
* handling logic
*
* NOTE: Nested interrupts are not supported in this implementation. If you
* want to implement nested interrupts, you would have to change the way that
* g_current_regs is handled. The savestate variable would not work for
* that purpose as implemented here because only the outermost nested
* interrupt can result in a context switch (it can probably be deleted).
*/
#define DECL_SAVESTATE() \
struct z8_irqstate_s savestate
#define IRQ_ENTER(irq, regs) \
do { \
savestate.state = g_z8irqstate.state; \
savestate.regs = g_z8irqstate.regs; \
g_z8irqstate.state = Z8_IRQSTATE_ENTRY; \
g_z8irqstate.regs = (regs); \
up_ack_irq(irq); \
} while (0)
* handling logic
*/
#define IRQ_LEAVE(irq) \
do { \
g_z8irqstate.state = savestate.state; \
g_z8irqstate.regs = savestate.regs; \
} while (0)
* (as a opaque handle)
*/
#define IRQ_STATE() \
(g_z8irqstate.regs)
#define SAVE_IRQCONTEXT(tcb) \
z8_saveirqcontext((tcb)->xcp.regs)
#define SET_IRQCONTEXT(tcb) \
do { \
g_z8irqstate.state = Z8_IRQSTATE_SAVED; \
g_z8irqstate.regs = (tcb)->xcp.regs; \
} while (0)
* can be simpler because only those registers normally
* saved in a C called need be stored.
*/
#define SAVE_USERCONTEXT(tcb) \
up_saveusercontext((tcb)->xcp.regs)
* IRQ state save.
*/
#define RESTORE_USERCONTEXT(tcb) \
z8_restorecontext((tcb)->xcp.regs)
* Public Types
****************************************************************************/
* "lazy" context saving as described below:
*
* (1) At the time of the interrupt, minimum information is saved and the
* register pointer is changed so that the interrupt logic does not alter
* the state of the interrupted task's registers.
* (2) If no context switch occurs during the interrupt processing, then
* the return from interrupt is also simple.
* (3) If a context switch occurs during interrupt processing, then
* (a) The full context of the interrupt task is saved, and
* (b) A full context switch is performed when the interrupt exits (see
* z8_vector.S).
*
* The following structure is used to manage this "lazy" context saving.
*/
#ifndef __ASSEMBLY__
struct z8_irqstate_s
{
uint8_t state;
chipreg_t *regs;
};
#endif
* Public Data
****************************************************************************/
#ifndef __ASSEMBLY__
* processing state
*/
extern struct z8_irqstate_s g_z8irqstate;
#endif
* Public Function Prototypes
****************************************************************************/
#ifndef __ASSEMBLY__
#ifdef __cplusplus
extern "C"
{
#endif
void up_ack_irq(int irq);
int up_saveusercontext(FAR chipreg_t *regs);
void z8_saveirqcontext(FAR chipreg_t *regs);
void z8_restorecontext(FAR chipreg_t *regs);
void z8_sigsetup(FAR struct tcb_s *tcb, sig_deliver_t sigdeliver,
FAR chipreg_t *regs);
#ifdef __cplusplus
}
#endif
#endif
#endif