/****************************************************************************
 * arch/hc/include/hcs12/irq.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.
 *
 ****************************************************************************/

/* This file should never be included directly but, rather,
 * only indirectly through nuttx/irq.h
 */

#ifndef __ARCH_HC_INCLUDE_HCS12_IRQ_H
#define __ARCH_HC_INCLUDE_HCS12_IRQ_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>
#include <nuttx/irq.h>

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* CCR bit definitions */

#define HCS12_CCR_C (1 << 0) /* Bit 0: Carry/Borrow status bit */
#define HCS12_CCR_V (1 << 1) /* Bit 1: Two's complement overflow status bit */
#define HCS12_CCR_Z (1 << 2) /* Bit 2: Zero status bit */
#define HCS12_CCR_N (1 << 3) /* Bit 3: Negative status bit */
#define HCS12_CCR_I (1 << 4) /* Bit 4: Maskable interrupt control bit */
#define HCS12_CCR_H (1 << 5) /* Bit 5: Half-carry status bit */
#define HCS12_CCR_X (1 << 6) /* Bit 6: Non-maskable interrupt control bit */
#define HCS12_CCR_S (1 << 7) /* Bit 7: STOP instruction control bit */

/****************************************************************************
 * Register state save strucure
 *   Low Address        <-- SP after state save
 *                [PPAGE]
 *                [soft regisers]
 *                XYH
 *                XYL
 *                ZH
 *                ZL
 *                TMPH
 *                TMPL
 *                FRAMEH
 *                FRAMEL
 *                SP    <-- SP after interrupt
 *                CCR
 *                B
 *                A
 *                XH
 *                XL
 *                YH
 *                YL
 *                PCH
 *   High Address PCL    <-- SP before interrupt
 *
 ****************************************************************************/

/* Byte offsets */

/* PPAGE register (only in banked mode) */

#ifndef CONFIG_HCS12_NONBANKED
#  define REG_PPAGE          0
#  define REG_FIRST_SOFTREG  1
#else
#  define REG_FIRST_SOFTREG  0
#endif

/* Soft registers (as configured) */

#if CONFIG_HCS12_MSOFTREGS > 2
#  error "Need to save more registers"
#elif CONFIG_HCS12_MSOFTREGS == 2
#  define REG_SOFTREG1       REG_FIRST_SOFTREG
#  define REG_SOFTREG2       (REG_FIRST_SOFTREG+2)
#  define REG_FIRST_HARDREG  (REG_FIRST_SOFTREG+4)
#elif CONFIG_HCS12_MSOFTREGS == 1
#  define REG_SOFTREG1       REG_FIRST_SOFTREG
#  define REG_FIRST_HARDREG  (REG_FIRST_SOFTREG+2)
#else
#  define REG_FIRST_HARDREG  REG_FIRST_SOFTREG
#endif

#define REG_XY               REG_FIRST_HARDREG
#define REG_Z                (REG_FIRST_HARDREG+2)
#  define REG_ZH             (REG_FIRST_HARDREG+2)
#  define REG_ZL             (REG_FIRST_HARDREG+3)
#define REG_TMP              (REG_FIRST_HARDREG+4)
#  define REG_TMPH           (REG_FIRST_HARDREG+4)
#  define REG_TMPL           (REG_FIRST_HARDREG+5)
#define REG_FRAME            (REG_FIRST_HARDREG+6)
#  define REG_FRAMEH         (REG_FIRST_HARDREG+6)
#  define REG_FRAMEL         (REG_FIRST_HARDREG+7)

/* Stack pointer before the interrupt */

#define REG_SP               (REG_FIRST_HARDREG+8)
#  define REG_SPH            (REG_FIRST_HARDREG+8)
#  define REG_SPL            (REG_FIRST_HARDREG+9)

/* On entry into an I- or X-interrupt, into an SWI, or into an undefined
 * instruction interrupt, the stack frame created by hardware looks like:
 *
 * Low Address       <-- SP after interrupt
 *              CCR
 *              B
 *              A
 *              XH
 *              XL
 *              YH
 *              YL
 *              PCH
 * High Address PCL  <-- SP before interrupt
 */

#define REG_CCR              (REG_FIRST_HARDREG+10)
#define REG_BA               (REG_FIRST_HARDREG+11)
#  define REG_B              (REG_FIRST_HARDREG+11)
#  define REG_A              (REG_FIRST_HARDREG+12)
#define REG_X                (REG_FIRST_HARDREG+13)
#  define REG_XH             (REG_FIRST_HARDREG+13)
#  define REG_XL             (REG_FIRST_HARDREG+14)
#define REG_Y                (REG_FIRST_HARDREG+15)
#  define REG_YH             (REG_FIRST_HARDREG+15)
#  define REG_YL             (REG_FIRST_HARDREG+16)
#define REG_PC               (REG_FIRST_HARDREG+17)
#  define REG_PCH            (REG_FIRST_HARDREG+17)
#  define REG_PCL            (REG_FIRST_HARDREG+18)

#define TOTALFRAME_SIZE      (REG_FIRST_HARDREG+17)
#define INTFRAME_SIZE        9
#define XCPTCONTEXT_REGS     TOTALFRAME_SIZE

/****************************************************************************
 * Public Types
 ****************************************************************************/

/* This structure defines the way the registers are stored. */

#ifndef __ASSEMBLY__
struct xcptcontext
{
  uint8_t regs[XCPTCONTEXT_REGS];
};

/****************************************************************************
 * Inline functions
 ****************************************************************************/

/* Name: up_irq_save, up_irq_restore, and friends.
 *
 * NOTE: This function should never be called from application code and,
 * as a general rule unless you really know what you are doing, this
 * function should not be called directly from operation system code either:
 * Typically, the wrapper functions, enter_critical_section() and
 * leave_critical section(), are probably what you really want.
 */

/* Enable/Disable interrupts */

#define ienable()  __asm("cli");
#define idisable() __asm("orcc #0x10")
#define xenable()  __asm("andcc #0xbf")
#define xdisable() __asm("orcc #0x40")

/* Get the current value of the CCR */

static inline irqstate_t up_getccr(void)
{
  irqstate_t ccr;
  __asm__
  (
    "\ttpa\n"
    "\tstaa %0\n"
    : "=m"(ccr) :
  );
  return ccr;
}

/* Save the current interrupt enable state & disable IRQs */

static inline irqstate_t up_irq_save(void)
{
  irqstate_t ccr;
  __asm__
  (
    "\ttpa\n"
    "\tstaa %0\n"
    "\torcc #0x50\n"
    : "=m"(ccr) :
  );
  return ccr;
}

/* Restore saved interrupt state */

static inline void up_irq_restore(irqstate_t flags)
{
  /* Should interrupts be enabled? */

  if ((flags & HCS12_CCR_I) == 0)
    {
      /* Yes.. unmask I- and Z-interrupts */

      __asm("andcc #0xaf");
    }
}

/* System call */

static inline void system_call3(unsigned int nbr, uintptr_t parm1,
                                uintptr_t parm2, uintptr_t parm3)
{
  /* To be provided */

  /* __asm("swi") */
}

/****************************************************************************
 * Public Data
 ****************************************************************************/

#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif

/****************************************************************************
 * Public Functions Prototypes
 ****************************************************************************/

#undef EXTERN
#ifdef __cplusplus
}
#endif

#endif /* __ASSEMBLY__ */
#endif /* __ARCH_HC_INCLUDE_HCS12_IRQ_H */