/*
 * Copyright (c) 2007-2015 Freescale Semiconductor, Inc.
 * Copyright 2018-2019 NXP
 *
 * License: NXP LA_OPT_NXP_Software_License
 *
 * NXP Confidential. This software is owned or controlled by NXP and may
 * only be used strictly in accordance with the applicable license terms.
 * By expressly accepting such terms or by downloading, installing,
 * activating and/or otherwise using the software, you are agreeing that
 * you have read, and that you agree to comply with and are bound by,
 * such license terms.  If you do not agree to be bound by the applicable
 * license terms, then you may not retain, install, activate or otherwise
 * use the software.  This code may only be used in a microprocessor,
 * microcontroller, sensor or digital signal processor ("NXP Product")
 * supplied directly or indirectly from NXP.  See the full NXP Software
 * License Agreement in license/LA_OPT_NXP_Software_License.pdf
 *
 * FreeMASTER Communication Driver - TSA
 */

#ifndef __FREEMASTER_TSA_H
#define __FREEMASTER_TSA_H

#include "freemaster_defcfg.h"

/*****************************************************************************
 Target-side Address translation structures and macros
******************************************************************************/

/* current TSA version  */
#define FMSTR_TSA_VERSION 3U

/* TSA flags carried in TSA_ENTRY.info (except the first entry in table) */
#define FMSTR_TSA_INFO_ENTRYTYPE_MASK 0x0003U    /* flags reserved for TSA_ENTRY use */
#define FMSTR_TSA_INFO_NON_VAR        0x0000U    /* ENTRYTYPE: non-variable object. The "type" determines the real type. */
#define FMSTR_TSA_INFO_RO_VAR         0x0001U    /* ENTRYTYPE: read-only variable */
#define FMSTR_TSA_INFO_RO_FLASH       0x0002U    /* ENTRYTYPE: read-only variable located in flash, can be written as part of Flash-write access */
#define FMSTR_TSA_INFO_RW_VAR         0x0003U    /* ENTRYTYPE: read-write variable */

#define FMSTR_TSA_INFO_VAR_MASK       0x03      /* R/W flags in info */

/* pointer types used in TSA tables can be overridden in freemaster.h */
/* (this is why macros are used instead of typedefs) */
#ifndef FMSTR_TSATBL_STRPTR
#define FMSTR_TSATBL_STRPTR  const char*
#endif
#ifndef FMSTR_TSATBL_VOIDPTR
#define FMSTR_TSATBL_VOIDPTR volatile const void*
#endif

#ifdef __cplusplus
  extern "C" {
#endif
      
/******************************************************************************
* Types definition
******************************************************************************/
      
/* TSA table entry. The unions inside assures variables sized enough to */
/* accommodate both the C-pointer and the user-requested size (FMSTR_ADDR) */
#if defined(__S12Z__)
typedef struct
{
	/* sizeof(FMSTR_ADDR) is 3 on S12Z platform. We need an extra byte to align to 4 bytes.
	 * An extra byte is put in front of each entry as S12Z is a big-endian machine. */
    FMSTR_U8 dummy0; 
    union { FMSTR_TSATBL_STRPTR p; FMSTR_ADDR n; } name;
    FMSTR_U8 dummy1;
    union { FMSTR_TSATBL_STRPTR p; FMSTR_ADDR n; } type;
    FMSTR_U8 dummy2;
    union { FMSTR_TSATBL_VOIDPTR p; FMSTR_ADDR n; } addr;
    FMSTR_U8 dummy3;
    union { FMSTR_TSATBL_VOIDPTR p; FMSTR_ADDR n; } info;
} FMSTR_TSA_ENTRY;

/* dummy member initializers */
#define FMSTR_TSATBL_FILL_PRE  0, 
#define FMSTR_TSATBL_FILL_POST  
#else
typedef struct
{
	/* Generic table entry on little-endian systems */
    union { FMSTR_TSATBL_STRPTR  p; FMSTR_ADDR n; } name;
    union { FMSTR_TSATBL_STRPTR  p; FMSTR_ADDR n; } type;
    union { FMSTR_TSATBL_VOIDPTR p; FMSTR_ADDR n; } addr;
    union { FMSTR_TSATBL_VOIDPTR p; FMSTR_ADDR n; } info;
} FMSTR_TSA_ENTRY;

/* no dummy members */
#define FMSTR_TSATBL_FILL_PRE  
#define FMSTR_TSATBL_FILL_POST  
#endif

#ifdef __cplusplus
  }
#endif

#ifndef FMSTR_TSATBL_STRPTR_CAST
#define FMSTR_TSATBL_STRPTR_CAST(x) ((FMSTR_TSATBL_STRPTR)(x))
#endif
#ifndef FMSTR_TSATBL_STRPTR_ENTRY
#define FMSTR_TSATBL_STRPTR_ENTRY(x) FMSTR_TSATBL_FILL_PRE {FMSTR_TSATBL_STRPTR_CAST(x)} FMSTR_TSATBL_FILL_POST
#endif
#ifndef FMSTR_TSATBL_VOIDPTR_CAST
#define FMSTR_TSATBL_VOIDPTR_CAST(x) ((FMSTR_TSATBL_VOIDPTR)(x))
#endif
#ifndef FMSTR_TSATBL_VOIDPTR_ENTRY
#define FMSTR_TSATBL_VOIDPTR_ENTRY(x) FMSTR_TSATBL_FILL_PRE {FMSTR_TSATBL_VOIDPTR_CAST(x)} FMSTR_TSATBL_FILL_POST
#endif
  
/* list of available types for TSA table definition */
#define FMSTR_TSA_MEMBER_CFG(parenttype,name,type) \
    FMSTR_TSATBL_STRPTR_ENTRY(#name), FMSTR_TSATBL_STRPTR_ENTRY(type), FMSTR_TSATBL_VOIDPTR_ENTRY(&((parenttype*)0)->name), FMSTR_TSATBL_VOIDPTR_ENTRY(FMSTR_TSA_INFO1(((parenttype*)0)->name, FMSTR_TSA_INFO_NON_VAR)),

#define FMSTR_TSA_RO_VAR_CFG(name,type) \
    FMSTR_TSATBL_STRPTR_ENTRY(#name), FMSTR_TSATBL_STRPTR_ENTRY(type), FMSTR_TSATBL_VOIDPTR_ENTRY(&(name)), FMSTR_TSATBL_VOIDPTR_ENTRY(FMSTR_TSA_INFO1(name, FMSTR_TSA_INFO_RO_VAR)),

#define FMSTR_TSA_RW_VAR_CFG(name,type) \
    FMSTR_TSATBL_STRPTR_ENTRY(#name), FMSTR_TSATBL_STRPTR_ENTRY(type), FMSTR_TSATBL_VOIDPTR_ENTRY(&(name)), FMSTR_TSATBL_VOIDPTR_ENTRY(FMSTR_TSA_INFO1(name, FMSTR_TSA_INFO_RW_VAR)),

#define FMSTR_TSA_RO_MEM_CFG(name,type,addr,size) \
    FMSTR_TSATBL_STRPTR_ENTRY(#name), FMSTR_TSATBL_STRPTR_ENTRY(type), FMSTR_TSATBL_VOIDPTR_ENTRY(addr), FMSTR_TSATBL_VOIDPTR_ENTRY(FMSTR_TSA_INFO2(size, FMSTR_TSA_INFO_RO_VAR)),

#define FMSTR_TSA_RW_MEM_CFG(name,type,addr,size) \
    FMSTR_TSATBL_STRPTR_ENTRY(#name), FMSTR_TSATBL_STRPTR_ENTRY(type), FMSTR_TSATBL_VOIDPTR_ENTRY(addr), FMSTR_TSATBL_VOIDPTR_ENTRY(FMSTR_TSA_INFO2(size, FMSTR_TSA_INFO_RW_VAR)),

#define FMSTR_TSA_RO_ENTRY(name_string,type_string,addr,size) \
    FMSTR_TSATBL_STRPTR_ENTRY(name_string), FMSTR_TSATBL_STRPTR_ENTRY(type_string), FMSTR_TSATBL_VOIDPTR_ENTRY(addr), FMSTR_TSATBL_VOIDPTR_ENTRY(FMSTR_TSA_INFO2(size, FMSTR_TSA_INFO_RW_VAR)),

#define FMSTR_TSA_NOMEM_SIZE(name_string,type_string,addr,size) \
    FMSTR_TSATBL_STRPTR_ENTRY(name_string), FMSTR_TSATBL_STRPTR_ENTRY(type_string), FMSTR_TSATBL_VOIDPTR_ENTRY(addr), FMSTR_TSATBL_VOIDPTR_ENTRY(FMSTR_TSA_INFO2(size, FMSTR_TSA_INFO_NON_VAR)),

#define FMSTR_TSA_NOMEM_NOSIZE(name_string,type_string,addr,size) \
    FMSTR_TSATBL_STRPTR_ENTRY(name_string), FMSTR_TSATBL_STRPTR_ENTRY(type_string), FMSTR_TSATBL_VOIDPTR_ENTRY(addr), FMSTR_TSATBL_VOIDPTR_ENTRY(size),


/*///////////////////////////////////////////////////////////////////// */
/* TSA "Base Types", all start with one (non-printable) character. */
/* Type is retrieved by PC and parsed according to the binary format of: */
/* "111STTZZ" where TT=type[int,frac,fp,special] S=signed ZZ=size[1,2,4,8] */
/* "11101100" is a special information block (not a real TSA symbol). */

/* S=0 TT=int */
#define FMSTR_TSA_UINT8   "\xE0"
#define FMSTR_TSA_UINT16  "\xE1"
#define FMSTR_TSA_UINT32  "\xE2"
#define FMSTR_TSA_UINT64  "\xE3"
/* S=1 TT=int */
#define FMSTR_TSA_SINT8   "\xF0"
#define FMSTR_TSA_SINT16  "\xF1"
#define FMSTR_TSA_SINT32  "\xF2"
#define FMSTR_TSA_SINT64  "\xF3"
/* S=0 TT=frac */
#define FMSTR_TSA_UFRAC_UQ(m,n) "\xE4:" #m "." #n /* UQm.n fractional m+n=bitsize */
#define FMSTR_TSA_UFRAC16 "\xE5"  /* standard UQ1.15 */
#define FMSTR_TSA_UFRAC32 "\xE6"  /* standard UQ1.31 */
#define FMSTR_TSA_UFRAC64 "\xE7"  /* standard UQ1.63 */
/* S=1 TT=frac */
#define FMSTR_TSA_FRAC_Q(m,n) "\xF4:" #m "." #n /* Qm.n fractional m+n+1=bitsize */
#define FMSTR_TSA_FRAC16  "\xF5"  /* standard Q0.15 */
#define FMSTR_TSA_FRAC32  "\xF6"  /* standard Q0.31 */
#define FMSTR_TSA_FRAC64  "\xF7"  /* standard Q0.63 */
/* S=1 TT=fp */
#define FMSTR_TSA_FLOAT   "\xFA"
#define FMSTR_TSA_DOUBLE  "\xFB"
/* TT=special */
#define FMSTR_TSA_SPECIAL_MEM   "\xEC"
#define FMSTR_TSA_SPECIAL_NOMEM "\xED"

/* a pointer type is like UINT with proper size set to sizeof(void*)
 * it is platform-specific, so made as external constant variable and
 * implemented in freemaster_tsa.c */
#if FMSTR_USE_TSA
extern FMSTR_TSA_CDECL char FMSTR_TSA_POINTER[];
#else
#define FMSTR_TSA_POINTER ""
#endif

/* macro used to describe "User Type" */
#define FMSTR_TSA_USERTYPE(type) #type

/* macro used to describe pure memory space */
#define FMSTR_TSA_MEMORY NULL

/*****************************/
/* TSA table-building macros */

#if FMSTR_USE_TSA

#define FMSTR_TSA_FUNC(id)  FMSTR_TsaGetTable_##id
#define FMSTR_TSA_FUNC_PROTO(id) const FMSTR_TSA_ENTRY* FMSTR_TSA_FUNC(id) (FMSTR_SIZE* tableSize)

#define FMSTR_TSA_TABLE_BEGIN(id) \
    FMSTR_TSA_FUNC_PROTO(id); \
    FMSTR_TSA_FUNC_PROTO(id) { \
        static FMSTR_TSA_CDECL FMSTR_TSA_ENTRY fmstr_tsatable[] = {

/* entry info  */
#define FMSTR_TSA_INFO1(elem, flags) FMSTR_TSATBL_VOIDPTR_CAST(((sizeof(elem))<<2)|(flags))
#define FMSTR_TSA_INFO2(size, flags) FMSTR_TSATBL_VOIDPTR_CAST(((size)<<2)|(flags))

/* TSA entry describing the structure/union member (must follow the FMSTR_TSA_STRUCT entry) */
#define FMSTR_TSA_MEMBER(parenttype,name,type) \
    { FMSTR_TSA_MEMBER_CFG(parenttype,name,type) },

/* TSA entry describing read-only variable */
#define FMSTR_TSA_RO_VAR(name,type) \
    { FMSTR_TSA_RO_VAR_CFG(name,type) },

/* TSA entry describing read-write variable */
#define FMSTR_TSA_RW_VAR(name,type) \
    { FMSTR_TSA_RW_VAR_CFG(name,type) },

/* TSA entry describing read-only memory area */
#define FMSTR_TSA_RO_MEM(name,type,addr,size) \
    { FMSTR_TSA_RO_MEM_CFG(name,type,addr,size) },

/* TSA entry describing read-write variable */
#define FMSTR_TSA_RW_MEM(name,type,addr,size) \
    { FMSTR_TSA_RW_MEM_CFG(name,type,addr,size) },

    /* TSA entry describing structure/union */
#define FMSTR_TSA_STRUCT(name) \
    { FMSTR_TSA_NOMEM_SIZE(#name,FMSTR_TSA_SPECIAL_NOMEM":STRUCT",NULL,sizeof(name)) },

    /* TSA entry describing enum */
#define FMSTR_TSA_ENUM(name) \
    { FMSTR_TSA_NOMEM_SIZE(#name,FMSTR_TSA_SPECIAL_NOMEM":ENUM",NULL,sizeof(name)) },

    /* TSA entry describing named constant as part of enumeration type
    (entry must follow the ENUM definition) */
#define FMSTR_TSA_CONST(name) \
    { FMSTR_TSA_NOMEM_NOSIZE(#name,FMSTR_TSA_SPECIAL_NOMEM":CONST",name,0) },

/* TSA entry describing virtual directory for the subsequent FILE entries
   The 'dirname' is either root-based if it starts with '/' or is relative to parent folder */
#define FMSTR_TSA_DIRECTORY(dirname) \
    { FMSTR_TSA_RO_ENTRY(dirname,FMSTR_TSA_SPECIAL_NOMEM":DIR",NULL,0) },

/* TSA entry describing virtual file content statically mapped in memory (static content cached by PC)
   The 'filename' may be specified with relative paths using normal slash */
#define FMSTR_TSA_MEMFILE(filename,filemem,filesize) \
    { FMSTR_TSA_RO_ENTRY(filename,FMSTR_TSA_SPECIAL_MEM":MEMFILE",&(filemem),(filesize)) },

/* TSA entry describing project to be opened in FreeMASTER
   'project_uri' may be a existing file (one of FILE entries) or a web URI */
#define FMSTR_TSA_PROJECT(projectname,project_uri) \
    { FMSTR_TSA_RO_ENTRY(projectname,FMSTR_TSA_SPECIAL_MEM":PRJ",project_uri,sizeof(project_uri)) },

/* TSA entry describing general WEB link. All web links are offered to be navigated in FreeMASTER
   'link_uri' may be a existing file (one of FILE entries) or a web URI */
#define FMSTR_TSA_HREF(linkname,link_uri) \
    { FMSTR_TSA_RO_ENTRY(linkname,FMSTR_TSA_SPECIAL_MEM":HREF",link_uri,sizeof(link_uri)) },

/* TSA entry describing user defined resource: File.
   The 'function' is an pointer to existing function FMSTR_URES_HANDLER_FUNC.
   The 'param' is a pointer to user params, which is put into in function param.*/
#define FMSTR_TSA_USER_FILE(filename, function, param) \
    { FMSTR_TSA_NOMEM_NOSIZE(filename,FMSTR_TSA_SPECIAL_NOMEM":U:FILE",(function),param) },

/* TSA entry describing user defined resource: Firmware image.
   The 'function' is an pointer to existing function FMSTR_URES_HANDLER_FUNC.
   The 'param' is a pointer to user params, which is put into in function param.*/
#define FMSTR_TSA_USER_FW(filename, function, param) \
    { FMSTR_TSA_NOMEM_NOSIZE(filename,FMSTR_TSA_SPECIAL_NOMEM":U:FW",(function),param) },

/* TSA entry describing user defined resource: EEPROM, Flash, or other kind of fixed-size persistent storage.
   The 'function' is an pointer to existing function FMSTR_URES_HANDLER_FUNC.
   The 'param' is a pointer to user params, which is put into in function param.*/
#define FMSTR_TSA_USER_PROM(filename, function, param) \
    { FMSTR_TSA_NOMEM_NOSIZE(filename,FMSTR_TSA_SPECIAL_NOMEM":U:PROM",(function),param) },

#define FMSTR_TSA_TABLE_END() }; \
    if(tableSize) *tableSize = sizeof(fmstr_tsatable); \
    return fmstr_tsatable; }

#else /* FMSTR_USE_TSA */

#define FMSTR_TSA_TABLE_BEGIN(id)
#define FMSTR_TSA_INFO1(elem, flags)
#define FMSTR_TSA_INFO2(size, flags)
#define FMSTR_TSA_STRUCT(name)
#define FMSTR_TSA_MEMBER(parenttype,name,type)
#define FMSTR_TSA_RO_VAR(name,type)
#define FMSTR_TSA_RW_VAR(name,type)
#define FMSTR_TSA_RO_MEM(name,type,addr,size)
#define FMSTR_TSA_RW_MEM(name,type,addr,size)
#define FMSTR_TSA_DIRECTORY(dirname)
#define FMSTR_TSA_MEMFILE(filename,filemem,filesize)
#define FMSTR_TSA_PROJECT(projectname,project_uri)
#define FMSTR_TSA_HREF(linkname,link_uri)
#define FMSTR_TSA_ENUM(name)
#define FMSTR_TSA_CONST(name)
#define FMSTR_TSA_USER_FILE(filename, function, param)
#define FMSTR_TSA_USER_FW(filename, function, param)
#define FMSTR_TSA_USER_PROM(filename, function, param)
#define FMSTR_TSA_TABLE_END()

#endif /* FMSTR_USE_TSA */

/**********************************************/
/* master TSA table-retrieval building macros */

#ifdef __cplusplus
extern "C" {
#endif

#if FMSTR_USE_TSA

#define FMSTR_TSA_TABLE_LIST_BEGIN() \
    const FMSTR_TSA_ENTRY* FMSTR_TsaGetTable(FMSTR_SIZE tableIndex, FMSTR_SIZE* tableSize) {

#define FMSTR_TSA_TABLE(id) \
    if(!tableIndex--) { \
        FMSTR_TSA_FUNC_PROTO(id); \
        return FMSTR_TSA_FUNC(id)(tableSize); \
    } else

#if (FMSTR_USE_TSA_DYNAMIC)
#define FMSTR_TSA_TABLE_LIST_END()                              \
        {                                                       \
            if(!tableIndex--)                                   \
            {                                                   \
                FMSTR_TSA_FUNC_PROTO(dynamic_tsa);              \
                return FMSTR_TSA_FUNC(dynamic_tsa)(tableSize);  \
            }                                                   \
            else                                                \
            {                                                   \
                return NULL;                                    \
            }                                                   \
        }                                                       \
    }
#else
#define FMSTR_TSA_TABLE_LIST_END() \
    { return NULL; } }
#endif

/*****************************************************************************
 Target-side Address translation functions
******************************************************************************/

/* master TSA table-retrieval function */
const FMSTR_TSA_ENTRY* FMSTR_TsaGetTable(FMSTR_SIZE tableIndex, FMSTR_SIZE* tableSize);
const FMSTR_TSA_ENTRY * FMSTR_FindUresInTsa(FMSTR_ADDR resourceId);
FMSTR_TSA_FUNC_PROTO(dynamic_tsa);

#else /* FMSTR_USE_TSA */

#define FMSTR_TSA_TABLE_LIST_BEGIN()
#define FMSTR_TSA_TABLE(id)
#define FMSTR_TSA_TABLE_LIST_END()

#endif /* FMSTR_USE_TSA */

#ifdef __cplusplus
}
#endif

#endif /* __FREEMASTER_TSA_H */
