/* $Id: sparc.h,v 1.3 2010/06/05 19:37:56 fredette Exp $ */

/* tme/ic/sparc.h - public header file for SPARC emulation */

/*
 * Copyright (c) 2005 Matt Fredette
 * All rights reserved.
 *
 * 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. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Matt Fredette.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
 */

#ifndef _TME_IC_SPARC_H
#define _TME_IC_SPARC_H

#include <tme/common.h>
_TME_RCSID("$Id: sparc.h,v 1.3 2010/06/05 19:37:56 fredette Exp $");

/* includes: */
#include <tme/element.h>
#include <tme/generic/bus.h>

/* macros: */

/* the sparc32 address spaces: */
#define TME_SPARC32_ASI_UI			(0x08)
#define TME_SPARC32_ASI_SI			(0x09)
#define TME_SPARC32_ASI_UD			(0x0A)
#define TME_SPARC32_ASI_SD			(0x0B)

/* common sparc64 address space identifier flags: */
#define TME_SPARC64_ASI_FLAG_SECONDARY		(0x01)
#define TME_SPARC64_ASI_FLAG_NO_FAULT		(0x02)
#define TME_SPARC64_ASI_FLAG_LITTLE		(0x08)
#define TME_SPARC64_ASI_FLAG_UNRESTRICTED	(0x80)

/* the sparc address space masks: */
/* bits 24 through 31 must be zero - except when
   TME_SPARC_ASI_MASK_FLAG_UNDEF is set, which is what makes an ASI
   mask undefined.

   bits 16 through 23 are the original ASI.

   ASIs are divided into two categories: special and normal.  an
   address space mask from a special ASI never matches an address
   space mask from a normal ASI, and vice-versa.

   if bit 15 is set, the ASI is special.  an address space mask from a
   special ASI never matches an address space mask from a different
   ASI.

   if bit 15 is clear, the ASI is normal.  an address space mask from
   a normal ASI may match address space masks from different normal
   ASIs.

   each of the bits eight through 14 identifies an address
   translation.  an address translation is usually the combination of
   an address space with privilege.

   an address space mask generated by a memory instruction has exactly
   one of these bits set, since the instruction's ASI+privilege
   combination can translate addresses in only one way.  an address
   space mask generated from an MMU mapping has at least one of these
   bits set, for the ASI+privilege from the instruction that caused
   the mapping lookup.  if the same mapping is also valid for other
   ASI+privilege combinations that can be added to the address space
   mask, the bits for their address translations can also be set.

   the meanings of the address translation bits must be consistent
   across all normal ASIs, since these bits are the only ones that are
   significant when address masks from two normal ASIs are compared.
   since an address mask from a special ASI can never match an address
   mask from a different ASI, the address translation bits for a
   special ASI are effectively unique to that ASI, and so there are
   only two of them - privileged and nonprivileged.

   bits zero through seven are available for ASI-specific use, and
   they never affect ASI mask comparison: */
#define TME_SPARC_ASI_MASK_FLAG_SPECIAL				TME_BIT(15)
#define TME_SPARC_ASI_MASK_FLAG_UNDEF				TME_BIT(24)
#define TME_SPARC_ASI_MASK_RAW(asi)				\
  (((tme_uint32_t) (asi))					\
   * (TME_SPARC_ASI_MASK_FLAG_SPECIAL * 2))
#define TME_SPARC_ASI_MASK(asi, xlat)				\
  (TME_SPARC_ASI_MASK_RAW(asi)					\
   + TME_BIT(8 + (xlat)))
#define TME_SPARC_ASI_MASK_SPECIAL(asi, priv)			\
  (TME_SPARC_ASI_MASK(asi, (priv) != 0)				\
   + TME_SPARC_ASI_MASK_FLAG_SPECIAL)
#define TME_SPARC_ASI_MASK_WHICH(asi_mask)			\
  ((asi_mask)							\
   / (TME_SPARC_ASI_MASK_FLAG_SPECIAL * 2))
#define TME_SPARC_ASI_MASK_FLAGS_AVAIL				\
  (TME_SPARC_ASI_MASK(0, 0) - 1)

/* this evaluates to nonzero iff the two ASI masks overlap: */
/* NB: asi_mask0 must be a single ASI mask from a memory instruction
   (in other words, it must have exactly one address translation bit
   set), and it may also have TME_SPARC_ASI_MASK_FLAG_UNDEF set.  .
   if asi_mask1 is a binary-OR of multiple ASI masks, either all of
   them must be for normal ASIs, or all of them must be for the same
   special ASI.  asi_mask1 must not have TME_SPARC_ASI_MASK_FLAG_UNDEF
   set: */
#define TME_SPARC_ASI_MASK_OVERLAP(asi_mask0, asi_mask1)	\
  ((((asi_mask0)						\
     ^ (asi_mask1))						\
    & ((((tme_uint32_t)						\
	 (tme_int32_t)						\
	 (tme_int16_t)						\
	 (asi_mask0))						\
	| TME_SPARC_ASI_MASK_FLAG_SPECIAL			\
	| TME_SPARC_ASI_MASK_FLAG_UNDEF)			\
       & (0 - TME_SPARC_ASI_MASK(0, 0)))) == 0)

/* this evaluates to nonzero iff this TLB entry allows access to an
   ASI, given by mask: */
#define TME_SPARC_TLB_ASI_MASK_OK(tlb, asi_mask)		\
  TME_SPARC_ASI_MASK_OVERLAP(asi_mask, (tlb)->tme_sparc_tlb_asi_mask)

/* sparc32 has four required address translations, corresponding to
   the four required ASIs: supervisor data, supervisor instruction,
   user data, user instruction.  all normal ASIs must use one of these
   address translations, and so you must specify one of the required
   ASIs to build an address space mask for a normal ASI: */
/* NB: this assumes that the four required ASIs are dense, and start
   with TME_SPARC32_ASI_UI: */
#define TME_SPARC32_ASI_MASK(asi, asi_required)			\
  TME_SPARC_ASI_MASK(asi, (asi_required) - TME_SPARC32_ASI_UI)

/* sparc32 address space mask flags: */
#define TME_SPARC32_ASI_MASK_FLAG_SPECIAL		(0x01)

/* for convenience we also provide the address space masks for the
   sparc32 required ASIs here: */
#define TME_SPARC32_ASI_MASK_UI		TME_SPARC32_ASI_MASK(TME_SPARC32_ASI_UI, TME_SPARC32_ASI_UI)
#define TME_SPARC32_ASI_MASK_SI		TME_SPARC32_ASI_MASK(TME_SPARC32_ASI_SI, TME_SPARC32_ASI_SI)
#define TME_SPARC32_ASI_MASK_UD		TME_SPARC32_ASI_MASK(TME_SPARC32_ASI_UD, TME_SPARC32_ASI_UD)
#define TME_SPARC32_ASI_MASK_SD		TME_SPARC32_ASI_MASK(TME_SPARC32_ASI_SD, TME_SPARC32_ASI_SD)

/* sparc64 address space masks use the common sparc64 address space
   identifier flags for address space mask flags, plus these other
   address space mask flags.  these other flags can't conflict with
   the common flags (which are essentially architected), and the same
   flag value (common or other) may have different names and meanings
   in an ASI mask from an instruction and one from a TLB entry: */
#define TME_SPARC64_ASI_MASK_FLAG_INSN_NUCLEUS		(0x04)
#define TME_SPARC64_ASI_MASK_FLAG_INSN_AS_IF_USER	(0x10)
#define TME_SPARC64_ASI_MASK_FLAG_SPECIAL		(0x20)
#define TME_SPARC64_ASI_MASK_FLAG_TLB_SIDE_EFFECTS	(0x40)
#define TME_SPARC64_ASI_MASK_FLAG_TLB_UNCACHEABLE	(TME_SPARC64_ASI_MASK_FLAG_INSN_NUCLEUS)

/* sparc64 has five architected address translations: privileged
   primary, privileged secondary, nonprivileged primary, nonprivileged
   secondary, and nucleus.  all of these are required, except for
   nucleus.  all normal ASIs must use one of these translations.

   however, note that sparc64 address translation, by itself, doesn't
   depend on privilege - the architected mapping from ASI to context
   doesn't consider it.  only address protection depends on privilege.
   (this isn't necessarily true on sparc32 - a sparc32 without a
   reference MMU could translate addresses completely differently for
   its different architected ASIs.)

   this means that a sparc64 normal ASI's address translation check
   will be done completely by the context comparison, leaving only
   privilege to be represented as generic sparc address space mask
   address translations: */
#define TME_SPARC64_ASI_MASK_USER			TME_SPARC_ASI_MASK(0 /* asi */, 0)
#define TME_SPARC64_ASI_MASK_PRIV			TME_SPARC_ASI_MASK(0 /* asi */, 1)
#define TME_SPARC64_ASI_MASK(asi, asi_mask_flags)		\
  ((asi_mask_flags)						\
   + TME_SPARC_ASI_MASK(asi,					\
                        (((asi_mask_flags)			\
			  & TME_SPARC64_ASI_MASK_FLAG_INSN_AS_IF_USER) == 0)))

/* for convenience, we provide macros to build address space masks for
   the architected ASIs given ASI mask flags here: */
#define TME_SPARC64_ASI_MASK_NUCLEUS(asi_flag_little)			\
  TME_SPARC64_ASI_MASK(0x04 + (asi_flag_little),			\
		       (TME_SPARC64_ASI_MASK_FLAG_INSN_NUCLEUS + (asi_flag_little)))
#define TME_SPARC64_ASI_MASK_REQUIRED_UNRESTRICTED(asi_flags)		\
  TME_SPARC64_ASI_MASK(TME_SPARC64_ASI_FLAG_UNRESTRICTED		\
		       + ((asi_flags)					\
			  & (TME_SPARC64_ASI_FLAG_SECONDARY		\
			     + TME_SPARC64_ASI_FLAG_NO_FAULT		\
			     + TME_SPARC64_ASI_FLAG_LITTLE)),		\
		       asi_flags)

/* these busy and unbusy a TLB entry: */
#define tme_sparc_tlb_busy(tlb)					\
  tme_bus_tlb_busy(&(tlb)->tme_sparc_tlb_bus_tlb)
#define tme_sparc_tlb_unbusy(tlb)				\
  tme_bus_tlb_unbusy(&(tlb)->tme_sparc_tlb_bus_tlb)

/* the minimum and maximum IPL levels: */
#define TME_SPARC_IPL_NONE	(0)
#define TME_SPARC_IPL_MIN	(1)
#define TME_SPARC_IPL_MAX	(15)
#define TME_SPARC_IPL_NMI	(15)

/* this indexes an sparc bus router array for an sparc with a port size
   of 8 * (2 ^ siz_lg2) bits: */
#define TME_SPARC_BUS_ROUTER_INDEX(siz_lg2, cycle_size, address)\
(((								\
   /* by the maximum cycle size: */				\
   ((cycle_size) - 1)						\
								\
   /* by the address alignment: */				\
   << siz_lg2)							\
  + ((address) & ((1 << (siz_lg2)) - 1)))			\
								\
 /* factor in the size of the generic bus router array: */	\
 * TME_BUS_ROUTER_SIZE(siz_lg2))

/* this gives the number of entries that must be in a generic bus
   router array for a device with a bus size of 8 * (2 ^ siz_lg2)
   bits: */
#define TME_SPARC_BUS_ROUTER_SIZE(siz_lg2)			\
  TME_SPARC_BUS_ROUTER_INDEX(siz_lg2, (1 << (siz_lg2)) + 1, 0)

/* structures: */

/* an sparc TLB entry: */
struct tme_sparc_tlb {

  /* the generic bus TLB associated with this TLB entry: */
  struct tme_bus_tlb tme_sparc_tlb_bus_tlb;
#define tme_sparc_tlb_addr_first tme_sparc_tlb_bus_tlb.tme_bus_tlb_addr_first
#define tme_sparc_tlb_addr_last tme_sparc_tlb_bus_tlb.tme_bus_tlb_addr_last
#define tme_sparc_tlb_bus_rwlock tme_sparc_tlb_bus_tlb.tme_bus_tlb_rwlock
#define tme_sparc_tlb_cycles_ok tme_sparc_tlb_bus_tlb.tme_bus_tlb_cycles_ok
#define tme_sparc_tlb_addr_offset tme_sparc_tlb_bus_tlb.tme_bus_tlb_addr_offset
#define tme_sparc_tlb_addr_shift tme_sparc_tlb_bus_tlb.tme_bus_tlb_addr_shift
#define tme_sparc_tlb_emulator_off_read tme_sparc_tlb_bus_tlb.tme_bus_tlb_emulator_off_read
#define tme_sparc_tlb_emulator_off_write tme_sparc_tlb_bus_tlb.tme_bus_tlb_emulator_off_write

  /* any link for this TLB entry: */
  tme_uint32_t tme_sparc_tlb_link;

  /* the context for this TLB entry: */
  tme_bus_context_t tme_sparc_tlb_context;

  /* an ASI mask: */
  tme_uint32_t tme_sparc_tlb_asi_mask;
};

/* an sparc bus connection: */
struct tme_sparc_bus_connection {

  /* a generic bus connection: */
  struct tme_bus_connection tme_sparc_bus_connection;

  /* the sparc interrupt function: */
  int (*tme_sparc_bus_interrupt) _TME_P((struct tme_sparc_bus_connection *, unsigned int));

  /* the sparc TLB entry filler: */
  int (*tme_sparc_bus_tlb_fill) _TME_P((struct tme_sparc_bus_connection *, struct tme_sparc_tlb *,
					tme_uint32_t, tme_bus_addr_t, unsigned int));

  /* the sparc FPU strict-compliance enabler: */
  void (*tme_sparc_bus_fpu_strict) _TME_P((struct tme_sparc_bus_connection *, unsigned int));
};

/* globals: */
extern _tme_const tme_bus_lane_t tme_sparc_router_32[];

#endif /* !_TME_IC_SPARC_H */
