text: /* IBM_PROLOG_BEGIN_TAG                                                   */
  /* This is an automatically generated prolog.                             */
  /*                                                                        */
  /* $Source: src/import/chips/p9/procedures/ppe/pk/ppe42/ppe42.h $         */
  /*                                                                        */
  /* OpenPOWER sbe Project                                                  */
  /*                                                                        */
  /* Contributors Listed Below - COPYRIGHT 2015,2017                        */
  /* [+] International Business Machines Corp.                              */
  /*                                                                        */
  /*                                                                        */
  /* Licensed 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.                         */
  /*                                                                        */
  /* IBM_PROLOG_END_TAG                                                     */
  #ifndef __PPE42_H__
  #define __PPE42_H__
  
  /// \file ppe42.h
  /// \brief PPE42 port header for PK
  
  // Macros to define where declared code is actually compiled
  
  #ifdef __PPE42_CORE_C__
      #define IF__PPE42_CORE_C__(x) x
      #define UNLESS__PPE42_CORE_C__(x)
  #else
      #define IF__PPE42_CORE_C__(x)
      #define UNLESS__PPE42_CORE_C__(x) x
  #endif
  
  #ifdef __PPE42_IRQ_CORE_C__
      #define IF__PPE42_IRQ_CORE_C__(x) x
      #define UNLESS__PPE42_IRQ_CORE_C__(x)
  #else
      #define IF__PPE42_IRQ_CORE_C__(x)
      #define UNLESS__PPE42_IRQ_CORE_C__(x) x
  #endif
  
  #ifdef HWMACRO_GPE
      #include "gpe.h"
  #elif defined(HWMACRO_STD)
      #include "std.h"
  #elif defined(HWMACRO_PPE)
      #include "ppe.h"
  #else
      #error "Macro Type not specified.  Are you building from the correct directory?"
  #endif
  
  
  #include "ppe42_asm.h"
  #include "ppe42_gcc.h"
  #include "ppe42_spr.h"
  #include "ppe42_msr.h"
  
  
  ///start
  
  /// The synchronization macros defined here all create a compiler
  /// memory barrier that will cause GCC to flush/invalidate all memory data
  /// held in registers before the macro. This is consistent with other systems,
  /// e.g., the PowerPC Linux kernel, and is the safest way to define these
  /// macros.
  
  
  // Condition register fields
  
  #define CR_LT(n) (0x80000000u >> (4 * (n)))
  #define CR_GT(n) (0x40000000u >> (4 * (n)))
  #define CR_EQ(n) (0x20000000u >> (4 * (n)))
  #define CR_SO(n) (0x10000000u >> (4 * (n)))
  
  
  #ifndef __ASSEMBLER__
  
  #include "stdint.h"
  
  /// ssize_t is defined explictly rather than bringing in all of <unistd.h>
  #ifndef __ssize_t_defined
      #define __ssize_t_defined
      typedef int ssize_t;
  #endif
  
  /// A memory barrier
  #define barrier() asm volatile ("" : : : "memory")
  
  /// Ensure In-order Execution of Input/Output
  #define eieio() asm volatile ("sync" : : : "memory")
  
  /// Memory barrier
  #define sync() asm volatile ("sync" : : : "memory")
  
  /// Instruction barrier
  #define isync() asm volatile ("sync" : : : "memory")
  
  /// CouNT Leading Zeros Word
  #define cntlzw(x) \
      ({uint32_t __x = (x); \
          uint32_t __lzw; \
          asm volatile ("cntlzw %0, %1" : "=r" (__lzw) : "r" (__x)); \
          __lzw;})
  
  /// CouNT Leading Zeros : uint32_t
  static inline int
  cntlz32(uint32_t x)
  {
      return cntlzw(x);
  }
  
  /// CouNT Leading Zeros : uint64_t
  static inline int
  cntlz64(uint64_t x)
  {
      if (x > 0xffffffff)
      {
          return cntlz32(x >> 32);
      }
      else
      {
          return 32 + cntlz32(x);
      }
  }
  
  
  /// 32-bit population count
  static inline int
  popcount32(uint32_t x)
  {
      return __builtin_popcount(x);
  }
  
  
  /// 64-bit population count
  static inline int
  popcount64(uint64_t x)
  {
      return __builtin_popcountll(x);
  }
  
  
  // NB: Normally we wouldn't like to force coercion inside a macro because it
  // can mask programming errors, but for the MMIO macros the addresses are
  // typically manifest constants or 32-bit unsigned integer expressions so we
  // embed the coercion to avoid warnings.
  
  /// 8-bit MMIO Write
  #define out8(addr, data) \
      do {*(volatile uint8_t *)(addr) = (data);} while(0)
  
  /// 8-bit MMIO Read
  #define in8(addr) \
      ({uint8_t __data = *(volatile uint8_t *)(addr); __data;})
  
  /// 16-bit MMIO Write
  #define out16(addr, data) \
      do {*(volatile uint16_t *)(addr) = (data);} while(0)
  
  /// 16-bit MMIO Read
  #define in16(addr) \
      ({uint16_t __data = *(volatile uint16_t *)(addr); __data;})
  
  /// 32-bit MMIO Write
  #define out32(addr, data) \
      do {*(volatile uint32_t *)(addr) = (data);} while(0)
  
  /// 32-bit MMIO Read
  #define in32(addr) \
      ({uint32_t __data = *(volatile uint32_t *)(addr); __data;})
  
  /// 64-bit MMIO Write
  #define out64(addr, data) \
      {\
          uint64_t __d = (data); \
          uint32_t* __a = (uint32_t*)(addr); \
          asm volatile \
          (\
           "stvd %1, %0 \n" \
           : "=o"(*__a) \
           : "r"(__d) \
          ); \
      }
  
  #define in64(addr) \
      ({\
          uint64_t __d; \
          uint32_t* __a = (uint32_t*)(addr); \
          asm volatile \
          (\
           "lvd %0, %1 \n" \
           :"=r"(__d) \
           :"o"(*__a) \
          ); \
          __d; \
      })
  
  #endif  /* __ASSEMBLER__ */
  
  #include "ppe42_irq.h"
  
  #ifndef __ASSEMBLER__
  
  /// Store revision information as a (global) string constant
  #define REVISION_STRING(symbol, rev) const char* symbol = rev;
  
  #else // __ASSEMBLER__
  // *INDENT-OFF*
  
  /// Store revision information as a global string constant
          .macro  .revision_string, symbol:req, rev:req
          .pushsection .rodata
          .balign 4
          .global \symbol
  \symbol\():
          .asciz  "\rev"
          .balign 4
          .popsection
          .endm
  
  // *INDENT-ON*
  #endif  // __ASSEMBLER__
  
  
  
  #include "ppe42_context.h"
  #include "pk_panic_codes.h"
  
  // PPE42 stack characteristics for PK.  The pre-pattern pattern is selected
  // to be easily recognizable yet be an illegal instruction.
  
  #define PK_STACK_DIRECTION     -1
  #define PK_STACK_PRE_DECREMENT 1
  #define PK_STACK_ALIGNMENT     8
  #define PK_STACK_TYPE          unsigned int
  #define PK_STACK_PATTERN       0x03abcdef
  
  // Kernel data structure offsets for assembler code
  
  #define PK_THREAD_OFFSET_SAVED_STACK_POINTER 0
  #define PK_THREAD_OFFSET_STACK_LIMIT         4
  #define PK_THREAD_OFFSET_STACK_BASE          8
  
  
  // Application-overrideable definitions
  
  /// The default thread machine context has
  ///  MSR[CE], MSR[EE] MSR[ME] MSR[IS0] MSR[IS1] MSR[IS2] set.
  ///  MSR[IPE] is set if USE_PPE_IMPRECISE_MODE is defined.
  ///  and all other MSR bits cleared.
  ///
  ///  MSR[IS0] = Data Cache Populate
  ///  MSR[IS1] = Store Gathering
  ///  MSR[IS2] = Instruction Cache Prefetch
  ///  MSR[IS3] = Reserved
  ///
  /// The default definition allows external and machine check exceptions.  This
  /// definition can be overriden by the application.
  
  #ifndef PK_THREAD_MACHINE_CONTEXT_DEFAULT
  
  #if defined(USE_PPE_IMPRECISE_MODE)
  
  #if defined(MASK_MSR_SEM6)
  
  #define PK_THREAD_MACHINE_CONTEXT_DEFAULT \
      (MSR_UIE | MSR_EE | MSR_ME | MSR_IS0 | MSR_IS1 | MSR_IS2 | MSR_IPE | MSR_SEM6)
  
  #else
  
  #define PK_THREAD_MACHINE_CONTEXT_DEFAULT \
      (MSR_UIE | MSR_EE | MSR_ME | MSR_IS0 | MSR_IS1 | MSR_IS2 | MSR_IPE)
  
  #endif  /*MASK_MSR_SEM6*/
  
  #else
  
  #if defined(MASK_MSR_SEM6)
  
  #define PK_THREAD_MACHINE_CONTEXT_DEFAULT \
      (MSR_UIE | MSR_EE | MSR_ME | MSR_IS0 | MSR_IS1 | MSR_IS2 | MSR_SEM6)
  
  #else
  
  #define PK_THREAD_MACHINE_CONTEXT_DEFAULT \
      (MSR_UIE | MSR_EE | MSR_ME | MSR_IS0 | MSR_IS1 | MSR_IS2)
  
  #endif  /*MASK_MSR_SEM6*/
  #endif  /*USE_PPE_IMPRECISE_MODE*/
  #endif  /*PK_THREAD_MACHINE_CONTEXT_DEFAULT*/
  
  
  #ifndef __ASSEMBLER__
  
  /// The PK kernel default panic sequence for C code is to issue a trap
  /// instruction with DBCR[TRAP] set, which causes XSR[TRAP] <- 1
  /// and causes the PPE to halt.
  ///
  ///
  /// The Simics environment does not model Debug events correctly. It executes
  /// the TRAP as an illegal instruction and branches to the Program Interrupt
  /// handler, destroying the contents of SRR0 and SRR1. Therefore we always
  /// insert a special Simics magic breakpoint (which is an effective NOP)
  /// before the hardware trap.  The special-form magic instruction is
  /// recognized by our Simics support scripts which decode the kernel state and
  /// try to help the user interpret what happened based on the TRAP code.
  ///   NOTE! SIMICS does not seem to recognize the "magic breakpoint" on PPE!
  
  
  #ifndef PK_PANIC
  
  #if SIMICS_ENVIRONMENT
  #define PK_PANIC(code)                  \
      do {                                \
          asm volatile ("stw     %r3, __pk_panic_save_r3@sda21(0)");      \
          asm volatile ("lwz     %r3, __pk_panic_dbcr@sda21(0)");         \
          asm volatile ("mtdbcr  %r3");                                   \
          asm volatile (".long %0" : : "i" (code));                       \
      } while(0)
  #else
  #define PK_PANIC(code)                                                  \
      do {                                                                \
          asm volatile ("tw 31, %0, %1" : : "i" (code/256) , "i" (code%256)); \
      } while (0)
  #endif
  #endif // SIMICS_ENVIRONMENT
  
  // These variables are used by the PK_PANIC() definition above to save and
  // restore state. __pk_panic_dbcr is the value loaded into DBCR to force
  // traps to halt the PPE and freeze the timers.
  
  #if SIMICS_ENVIRONMENT
  #ifdef __PPE42_CORE_C__
  uint32_t __pk_panic_save_r3;
  uint32_t __pk_panic_dbcr = DBCR_RST_HALT;
  #define __PK_PANIC_DEFS__
  #else
  #define __PK_PANIC_DEFS__                                               \
          extern uint32_t __pk_panic_save_r3;                             \
          extern uint32_t __pk_panic_dbcr;
  #endif //SIMICS_ENVIRONMENT
  
  #endif // PK_PANIC
  
  /// This is the Simics 'magic breakpoint' instruction.
  ///
  /// Note that this form does not include a memory barrier, as doing so might
  /// change the semantics of the program.  There is an alternative form
  /// SIMICS_MAGIC_BREAKPOINT_BARRIER that does include a barrier.
  
  //#define SIMICS_MAGIC_BREAKPOINT asm volatile ("rlwimi 0,0,0,0,0")
  
  /// This is the Simics 'magic breakpoint' instruction including a memory
  /// barrier.
  ///
  /// Note that the memory barrier guarantees that all variables held in
  /// registers are flushed to memory before the breakpoint, however this might
  /// change the semantics of the program.  There is an alternative form of
  /// SIMICS_MAGIC_BREAKPOINT that does not include a barrier.  If the idea is
  /// to use the breakpoint for tracing code execution in Simics, the barrier
  /// form may be preferred so that variable values will be visible in memory.
  
  /*#define SIMICS_MAGIC_BREAKPOINT_BARRIER \
               asm volatile ("rlwimi 0,0,0,0,0" : : : "memory")
  */
  
  #else // __ASSEMBLER__
  // *INDENT-OFF*
  
  /// This is the Simics 'magic breakpoint' instruction.  An assembler macro
  /// form is also provided for use within macros.
  
  //#define SIMICS_MAGIC_BREAKPOINT rlwimi 0,0,0,0,0
  
  //        .macro _simics_magic_breakpoint
  //        rlwimi  0,0,0,0,0
  //        .endm
  
  /// The PK kernel panic default panic sequence for assembler code
  ///
  /// By default a kernel panic from assembler forces external debug mode then
  /// generates a \c trap instruction followed by the error code.  The \a code
  /// argument must be a compile-time integer immediate. This definition can be
  /// overriden by the application.
  ///
  /// See the comments for the non-ASSEMBLER version for further details.  Note
  /// that the code space reserved for exception handlers is only 8
  /// instructions, so in the assembler context we don't save DBCR0 as doing so
  /// would require 10.
  
  #ifndef PK_PANIC
  
  #define PK_PANIC(code) _pk_panic code
  #if SIMICS_ENVIRONMENT
          .macro _pk_panic, code
              stw     %r3, __pk_panic_save_r3@sda21(0)
              lwz     %r3, __pk_panic_dbcr@sda21(0)
              mtdbcr  %r3,
              .long   (\code)
          .endm
  #else
          .macro  _pk_panic, code
              tw  31,(\code)/256, (\code)%256
          .endm
  #endif // SIMICS_ENVIRONMENT
  #endif // PK_PANIC
  
  // *INDENT-ON*
  #endif // __ASSEMBLER__
  
  
  //  Application-overridible definitions for the PK boot loader
  
  /// In order to enable the default kernel panic (a trap) to halt the machine,
  /// the Debug Control Register 0 (DBCR0) is initialized in externel debug
  /// mode, with the Trap Debug Event enabled so that the trap will not cause a
  /// program exception, and the FT bit set so that the timers will freeze.
  /// This definition can be overridden by the application.
  ///
  /// NB: It is expected that a reliable production system will redefine all of
  /// the 'panic' macros and the default DBCR0 setup.
  
  #ifndef PPE42_DBCR_INITIAL
  #define PPE42_DBCR_INITIAL (DBCR_TRAP | DBCR_IACE)
  #endif
  
  
  #ifndef PPE42_DACR_INITIAL
  #define PPE42_DACR_INITIAL 0
  #endif
  
  /// This is the value of the MSR used during initialization.  Once PK threads
  /// are started (with \c pk_start_threads()), all machine contexts derive
  /// from the default thread context \c
  /// PK_THREAD_MACHINE_CONTEXT_DEFAULT. This definition can be overriden by
  /// the application.
  ///
  
  
  #ifndef PPE42_MSR_INITIAL
  #if defined(USE_PPE_IMPRECISE_MODE)
  #define PPE42_MSR_INITIAL (MSR_ME | MSR_IS0 | MSR_IS1 | MSR_IS2 | MSR_IPE)
  #else
  #define PPE42_MSR_INITIAL (MSR_ME | MSR_IS0 | MSR_IS1 | MSR_IS2)
  #endif
  #endif
  
  /// The \a argc argument passed to \c main(). This definition can be overriden
  /// by the application.
  
  #ifndef PPE42_ARGC_INITIAL
  #define PPE42_ARGC_INITIAL 0
  #endif
  
  /// The \a argv argument passed to \c main(). This definition can be overriden
  /// by the application.
  
  #ifndef PPE42_ARGV_INITIAL
  #define PPE42_ARGV_INITIAL 0
  #endif
  
  /// Optionally trap the reset for the debugger, which means that the PPE42
  /// will simply spin at the symbol \c __reset_trap after a chip reset. Set R0
  /// to a non-zero value in the debugger to continue execution. This definition
  /// can be overriden by the application.
  
  #ifndef PPE42_RESET_TRAP
  #define PPE42_RESET_TRAP 0
  #endif
  
  #ifndef __ASSEMBLER__
  
  /// The PPE42 PK machine context is simply the MSR, a 32-bit integer.
  
  typedef uint32_t PkMachineContext;
  
  /// Disable interrupts and return the current
  /// context.
  ///
  /// \param context A pointer to an PkMachineContext, this is the context that
  ///                existed before interrupts were disabled. Typically this
  ///                context is restored at the end of a critical section.
  ///
  /// Return values other then PK_OK (0) are errors; see \ref pk_errors
  ///
  /// \retval 0 Successful completion
  ///
  /// \retval -PK_INVALID_ARGUMENT_INTERRUPT An illegal priority was specified.
  
  UNLESS__PPE42_CORE_C__(extern)
  inline int
  pk_interrupt_disable(PkMachineContext* context)
  {
  *context = mfmsr();
  
  wrteei(0);
  
  return PK_OK;
  }
  
  /// Set the machine context.
  ///
  /// \param context A pointer to an PkMachineContext
  ///
  /// Return values other then PK_OK (0) are errors; see \ref pk_errors
  ///
  /// \retval 0 Successful completion
  ///
  /// \retval -PK_INVALID_ARGUMENT_CONTEXT_SET A null pointer was provided as
  /// the \a context argument or an illegal machine context was specified.
  
  UNLESS__PPE42_CORE_C__(extern)
  inline int
  pk_machine_context_set(PkMachineContext* context)
  {
  if (PK_ERROR_CHECK_API)
  {
  PK_ERROR_IF(context == 0, PK_INVALID_ARGUMENT_CONTEXT_SET);
  }
  
  mtmsr(*context);
  
  return PK_OK;
  }
  
  /// Get the machine context.
  ///
  /// \param context A pointer to an PkMachineContext.
  ///
  /// Return values other then PK_OK (0) are errors; see \ref pk_errors
  ///
  /// \retval 0 Successful completion
  ///
  /// \retval -PK_INVALID_ARGUMENT_CONTEXT_GET A null pointer was provided as
  /// the \a context argument.
  
  UNLESS__PPE42_CORE_C__(extern)
  inline int
  pk_machine_context_get(PkMachineContext* context)
  {
  if (PK_ERROR_CHECK_API)
  {
  PK_ERROR_IF(context == 0, PK_INVALID_ARGUMENT_CONTEXT_GET);
  }
  
  *context = mfmsr();
  
  return PK_OK;
  }
  
  extern void __ctx_switch();
  /// The PK context switch for the PPE kernel
  //  There is no protected mode in PPE42 so just call kernel code
  #define __pk_switch() __ctx_switch()
  
  
  /// In the PowerPC EABI all initial stack frames require 8 bytes - the 4 bytes
  /// at the SP are zeroed to indicate the end of the stack, and the 4 bytes
  /// behind the SP are for the initial subroutine's LR.
  
  static inline void
  __pk_stack_create_initial_frame(PkAddress* stack, size_t* size)
  {
  *stack -= 8;
  * size -= 8;
  * ((PK_STACK_TYPE*)(*stack)) = 0;
  }
  
  /// The PK Kernel Context for PPE42
  ///
  /// The PK portable kernel does not define how the kernel keeps track of
  /// whether PK is running, interrupt levels, and other debug
  /// information. Instead it defines an API that the port must provide to the
  /// portable kernel.
  ///
  /// In the PPE42 port, the kernel context is maintained in SPRG0.  This
  /// 32-bit value is treated as 6 distinct fields as indicated in the structure
  /// definition.
  typedef union
  {
  
  uint32_t value;
  
  struct
  {
  
  /// A flag indicating that PK is in thread mode after a call of
  /// pk_start_threads().
  unsigned thread_mode : 1;
  
  /// If this field is non-zero then PK is processing an interrupt
  /// and the \c irq field will contain the PkIrqId of the interrupt
  /// that kicked off interrupt processing.
  unsigned processing_interrupt : 1;
  
  /// The priority of the currently running thread.  In an interrupt
  /// context, this is the priority of the thread that was interrupted.
  unsigned thread_priority : 6;
  
  /// This bit tracks whether the current context can be discarded or
  /// if the context must be saved.  If the processor takes an interrupt
  /// and this bit is set, then the current context will be discarded.
  /// This bit is set at the end of handling an interrupt and prior
  /// to entering the wait enabled state.
  unsigned discard_ctx : 1;
  
  /// The PkIrqId of the currently running (or last run) handler.  If
  /// \c processing_interrupt is set, then this is the
  /// PkIrqId of the IRQ that is currently executing.
  unsigned irq : 7;
  
  /// Each PPE application will define (or not) the interpretation of
  /// this field.  Since SPRG0 is saved and restored during during thread
  /// context switches, this field can be used to record the progress of
  /// individual threads.  The kernel and/or application will provide
  /// APIs or macros to read and write this field.
  unsigned app_specific : 16;
  
  } fields;
  
  } __PkKernelContext;
  
  // These APIs are provided for applications to get and set the app_specific
  // field of the kernel context which is held in sprg0.
  
  static inline uint16_t ppe42_app_ctx_get(void)
  {
  __PkKernelContext __ctx;
  __ctx.value = mfspr(SPRN_SPRG0);
  return __ctx.fields.app_specific;
  }
  
  static inline void ppe42_app_ctx_set(uint16_t app_ctx)
  {
  PkMachineContext    mctx;
  __PkKernelContext   __ctx;
  mctx = mfmsr();
  wrteei(0);
  __ctx.value = mfspr(SPRN_SPRG0);
  __ctx.fields.app_specific = app_ctx;
  mtspr(SPRN_SPRG0, __ctx.value);
  mtmsr(mctx);
  }
  
  // These APIs are provided to the PK portable kernel by the port.
  
  /// PK threads have been started by a call of pk_start_threads().
  
  #define __pk_kernel_mode_thread() \
      ({ \
          __PkKernelContext __ctx; \
          __ctx.value = mfspr(SPRN_SPRG0); \
          __ctx.fields.thread_mode;})
  
  
  ///  PK is executing in a thread context (not an interrupt handler).
  
  #define __pk_kernel_context_thread() \
      ({ \
          __PkKernelContext __ctx; \
          __ctx.value = mfspr(SPRN_SPRG0); \
          __ctx.fields.thread_mode && !__ctx.fields.processing_interrupt;})
  
  
  ///  PK is executing an interrupt handler of any priority.
  
  #define __pk_kernel_context_any_interrupt() \
      ({ \
          __PkKernelContext __ctx; \
          __ctx.value = mfspr(SPRN_SPRG0); \
          __ctx.fields.processing_interrupt;})
  
  
  // PK requires the port to define the type PkThreadQueue, which is a
  // priority queue (where 0 is the highest priority).  This queue must be able
  // to handle PK_THREADS + 1 priorities (the last for the idle thread) The
  // port must also define methods for clearing, insertion, deletion and min
  // (with assumed legal priorities).  The min operation returns PK_THREADS if
  // the queue is empty (or a queue could be initialized with that entry always
  // present - PK code never tries to delete the idle thread from a thread
  // queue).
  //
  // These queues are used both for the run queue and the pending queue
  // associated with every semaphore.
  //
  // On PPE42 with 32 threads (implied), this is a job for a uint32_t and
  // cntlzw().
  
  static inline void
  __pk_thread_queue_clear(volatile PkThreadQueue* queue)
  {
  *queue = 0;
  }
  
  static inline void
  __pk_thread_queue_insert(volatile PkThreadQueue* queue, PkThreadPriority priority)
  {
  *queue |= (0x80000000u >> priority);
  }
  
  static inline void
  __pk_thread_queue_delete(volatile PkThreadQueue* queue, PkThreadPriority priority)
  {
  *queue &= ~(0x80000000u >> priority);
  }
  
  static inline PkThreadPriority
  __pk_thread_queue_min(volatile PkThreadQueue* queue)
  {
  return cntlzw(*queue);
  }
  
  static inline int
  __pk_thread_queue_member(volatile PkThreadQueue* queue, PkThreadPriority priority)
  {
  return ((*queue >> (31 - priority)) & 1);
  }
  
  static inline void
  __pk_thread_queue_union(volatile PkThreadQueue* queue0,
  volatile PkThreadQueue* queue1)
  {
  *queue0 |= *queue1;
  }
  
  static inline int
  __pk_thread_queue_count(volatile PkThreadQueue* queue)
  {
  return __builtin_popcount(*queue);
  }
  
  
  /// This macro is used to call __pk_start_threads() using the kernel stack,
  /// in a critical section.
  
  #define __pk_call_pk_start_threads()                          \
      do {                                                        \
          PkMachineContext ctx;                                  \
          pk_critical_section_enter(&ctx);      \
          asm volatile ("mr 1, %0; mtlr %1; blrl" : :             \
                        "r" (__pk_kernel_stack),            \
                        "r" (__pk_start_threads));               \
          PK_PANIC(PK_START_THREADS_RETURNED);                  \
      } while (0)
  
  
  #endif  /* __ASSEMBLER__ */
  
  /// The __PkKernelContext 'thread_mode' bit as a flag
  
  #define PPE42_THREAD_MODE   0x8000
  #define PPE42_PROC_IRQ      0x4000
  #define PPE42_DISCARD_CTX   0x0080
  
  #define PPE42_THREAD_MODE_BIT   0
  #define PPE42_PROC_IRQ_BIT      1
  #define PPE42_DISCARD_CTX_BIT   8
  
  #ifndef __ASSEMBLER__
  
  /// Code breakpoints for PPE42
  ///
  /// This macro inserts a special PPE42-only breakpoint into the object code
  /// at the place the macro invocation appears.  This facility is designed for
  /// VBU/VPO procedure debugging. This type of breakpoint may not be required
  /// on real hardware as we will then have the full power of RISCWatch, gdb,
  /// etc. Once inserted into the code, code breakpoints can be enabled or
  /// disabled by manipulating the global variable _code_breakpoint_enable,
  /// which defaults to 1.
  ///
  /// The code breakpoint is implemented as a setup routine and a teardown
  /// routine, executed in an critical section.  The actual break
  /// will occur at the address of the call of the teardown routine, in the
  /// context of the calling code.  The setup routine saves the state of DBCR0/1
  /// and IAC4, then programs the DBCR for an external debug mode, IAC4
  /// breakpoint.  The IAC4 breakpoint is set for the address of the call of the
  /// teardown routine.  The teardown routine simply restores the state of the
  /// debug registers that existed before the code breakpoint.
  ///
  /// Once hit, restarting from the break requires clearing IAC4 and restarting
  /// instructions:
  ///
  /// \code
  ///
  /// putspr pu.occ iac4 0
  /// cipinstruct pu.occ start
  ///
  /// \endcode
  ///
  /// The above restart processes is also encapsulated as the p8_tclEcmd
  /// procedure 'unbreakOcc'.
  ///
  /// In code built for the Simics environment (i.e., with the preprocessor
  /// macro SIMICS_ENVIRONMENT=1) this macro simply expands into
  /// SIMICS_MAGIC_BREAKPOINT, and simulation can be continued from the break as
  /// normal. This Simics magic breakpoint is also under the control of
  /// _code_breakpoint_enable.  In code not built with SIMICS_ENVIROMENT=1, note
  /// that the CODE_BREAKPOINT is ignored by the Simics PPE42 model as it does
  /// not model debug events.
  
  //void
  //_code_breakpoint_prologue(void);
  
  //void
  //_code_breakpoint_epilogue(void);
  
  //extern uint32_t _code_breakpoint_enable;
  
  #endif // __ASSEMBLER__
  
  
  #endif /* __PPE42_H__ */
  