/*  *********************************************************************
    *  ASTRIS - Remote JTAG probe
    *
    *  ARM7 CPU debug header			File: astris_arm7.h
    *
    *  Astris' private API is defined here
    *
    *********************************************************************
    *
    *  Copyright (C) 2009-2012  Apple, Inc. All rights reserved.
    *
    *  This document is the property of Apple Inc.
    *  It is considered confidential and proprietary.
    *
    *  This document may not be reproduced or transmitted in any form,
    *  in whole or in part, without the express written permission of
    *  Apple Inc.
    ********************************************************************* */

#ifndef _ASTRIS_ARM7_H
#define _ASTRIS_ARM7_H

#include "astris_armcpu.h"
#include "bitfields.h"

/*  *********************************************************************
 *  Instruction register values
 ********************************************************************* */

#define ARM7_SCAN1_CHLEN_BYTES 5
#define ARM7_SCAN1_CHLEN_BITS  33

#define ARM7_SCAN2_CHLEN_BYTES 5
#define ARM7_SCAN2_CHLEN_BITS  38

#define ARM7_IR_LEN     4
#define ARM7_IR_SCAN_N  0x40 /* b0010, bit reversed, left justified */
#define ARM7_IR_INTEST  0x30 /* b1100, bit reversed, left justified */
#define ARM7_IR_IDCODE  0x70 /* b1110, bit reversed, left justified */
#define ARM7_IR_BYPASS  0xF0 /* b1111, bit reversed, left justified */
#define ARM7_IR_RESTART 0x20 /* b0100, bit reversed, left justified */

#define ARM7_SCHAIN_LENGTH   4
#define ARM7_SCHAIN_RESERVED 0x00
#define ARM7_SCHAIN_DEBUG    0x80    /* b0001, bit reversed, left justified. AKA "Scan Chain 1" */
#define ARM7_SCHAIN_ICE      0x40    /* b0010, bit reversed, left justified, AKA "Scan Chain 2" */

#define EICE_WRITE 1
#define EICE_READ  0

/*
 * EmbeddedICE registers - sent to chain without bitswapping
 */

#define R_EICE_DBGCTRL   0x00
#define R_EICE_DBGSTATUS 0x01
#define R_EICE_ABTSTAT   0x02
#define R_EICE_DCCCTRL   0x04
#define R_EICE_DCCDATA   0x05

#define R_EICE_WP0ADDRVALUE 0x08
#define R_EICE_WP0ADDRMASK  0x09
#define R_EICE_WP0DATAVALUE 0x0A
#define R_EICE_WP0DATAMASK  0x0B
#define R_EICE_WP0CTRLVALUE 0x0C
#define R_EICE_WP0CTRLMASK  0x0D

#define R_EICE_WP1ADDRVALUE 0x10
#define R_EICE_WP1ADDRMASK  0x11
#define R_EICE_WP1DATAVALUE 0x12
#define R_EICE_WP1DATAMASK  0x13
#define R_EICE_WP1CTRLVALUE 0x14
#define R_EICE_WP1CTRLMASK  0x15

/*
 * Debug Communications Channel
 */

#define S_EICE_DCC_VERSION    28
#define M_EICE_DCC_VERSION    _MM_MAKEMASK(4, S_EICE_DCC_VERSION)
#define V_EICE_DCC_VERSION(v) _MM_MAKEVALUE((v), S_EICE_DCC_VERSION)
#define G_EICE_DCC_VERSION(v) _MM_GETVALUE((v), S_EICE_DCC_VERSION, M_EICE_DCC_VERSION)

#define M_EICE_DCC_R _MM_MAKEMASK1(0)
#define M_EICE_DCC_W _MM_MAKEMASK1(1)

/* Watchpoint control and mask */

#define M_EICE_WP_WRITE _MM_MAKEMASK1(0)

#define S_EICE_WP_SIZE    1
#define M_EICE_WP_SIZE    _MM_MAKEMASK(2, S_EICE_WP_SIZE)
#define V_EICE_WP_SIZE(v) _MM_MAKEVALUE((v), S_EICE_WP_SIZE)
#define G_EICE_WP_SIZE(v) _MM_GETVALUE((v), S_EICE_WP_SIZE, M_EICE_WP_SIZE)

#define K_EICE_WP_SIZE_BYTE     0
#define K_EICE_WP_SIZE_HALF     1
#define K_EICE_WP_SIZE_WORD     2
#define K_EICE_WP_SIZE_RESERVED 3

#define S_EICE_WP_PROT    3
#define M_EICE_WP_PROT    _MM_MAKEMASK(2, S_EICE_WP_PROT)
#define V_EICE_WP_PROT(v) _MM_MAKEVALUE((v), S_EICE_WP_PROT)
#define G_EICE_WP_PROT(v) _MM_GETVALUE((v), S_EICE_WP_PROT, M_EICE_WP_PROT)

#define M_EICEP_WP_PROT_INSTR 0
#define M_EICEP_WP_PROT_DATA  _MM_MAKEMASK1(3)

#define M_EICEP_WP_PROT_USER    0
#define M_EICEP_WP_PROT_NONUSER _MM_MAKEMASK1(4)

#define M_EICE_WP_DBGEXT _MM_MAKEMASK1(5)
#define M_EICE_WP_CHAIN  _MM_MAKEMASK1(6)
#define M_EICE_WP_RANGE  _MM_MAKEMASK1(7)
#define M_EICE_WP_ENABLE _MM_MAKEMASK1(8)

/*
 * Abort Status Register
 */

#define M_EICE_ABTSTAT_DBGABT _MM_MAKEMASK1(0)

/*
 * Debug control Register
 */

#define M_EICE_DBGCTRL_DBGACK      _MM_MAKEMASK1(0)
#define M_EICE_DBGCTRL_DBGRQ       _MM_MAKEMASK1(1)
#define M_EICE_DBGCTRL_INTDIS      _MM_MAKEMASK1(2)
#define M_EICE_DBGCTRL_SBZRAZ      _MM_MAKEMASK1(3)
#define M_EICE_DBGCTRL_MONITORMODE _MM_MAKEMASK1(4)
#define M_EICE_DBGCTRL_ICEDISABLE  _MM_MAKEMASK1(5)

/*
 * Debug Status Register
 */

#define M_EICE_DBGSTATUS_DBGACK _MM_MAKEMASK1(0)
#define M_EICE_DBGSTATUS_DBGRQ  _MM_MAKEMASK1(1)
#define M_EICE_DBGSTATUS_IFEN   _MM_MAKEMASK1(2)
#define M_EICE_DBGSTATUS_TRANS1 _MM_MAKEMASK1(3)
#define M_EICE_DBGSTATUS_TBIT   _MM_MAKEMASK1(4)

/*
 * SCAN 1 bits
 */

#define ARM7_DBG_SPEED 0
#define ARM7_SYS_SPEED 1

/*  *********************************************************************
    *  Data Structures
    ********************************************************************* */

//
// ARM7cpu_t -- for ARM7 (ARMv4/EICE debug); doesn't currently inhereit from
//              ARMcpu_t or ARM32cpu_t because there's a lot of baggage.
//
class ARM7cpu_t:
    public CPU_t {
public:
    ARM7cpu_t(AXtgt_t *tgt, const char *name);
    virtual ~ARM7cpu_t();

    virtual int read_register(AXregid_t reg, AXregval_t *val);
    virtual int write_register(AXregid_t reg, AXregval_t val);

    virtual int memory_read(AXmemaddr_t address, uint32_t *length, uint8_t *buffer);
    virtual int memory_write(AXmemaddr_t address, uint32_t *length, uint8_t *buffer, int iflush);

    virtual int hwbp_info(int index, bpwp_info_t *info)                       {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int hwbp_insert(AXmemaddr_t address)                              {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int hwbp_remove(int index)                                        {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int hwbp_enable(int index)                                        {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int hwbp_disable(int index)                                       {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int hwwp_info(int index, bpwp_info_t *info)                       {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int hwwp_insert(AXmemaddr_t address, uint32_t len, int rdwr)      {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int hwwp_remove(int index)                                        {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int hwwp_enable(int index)                                        {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int hwwp_disable(int index)                                       {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int swbp_info(int index, bpwp_info_t *info)                       {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int swbp_insert(AXmemaddr_t address, int len)                     {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int swbp_remove(int index)                                        {return ASTRIS_ERR_NOTSUPPORTED;}
    virtual int cache_op(cpu_cacheop_t op, AXmemaddr_t addr, uint32_t length) {return ASTRIS_ERR_NOTSUPPORTED;}

    virtual int cpu_mode(const char **mode, uint32_t cpsr);

protected:
    const char *_log_key; // ARM7 CPU logging domain

    virtual int _get_type_hw() {return AXCPUTYPE_ARM7;}
    virtual int _get_arch_hw() {return AXCPUARCH_ARMV4;}

    virtual bool _init_hw();
    virtual int  _status_hw(uint32_t *status, uint32_t *flags);
    virtual int  _halt_hw();
    virtual int  _collect_hw(int timeout);
    virtual int  _resume_hw(bool step);
    virtual int  _flush_state_hw();
    virtual int  _is_halted(bool *halted);

private:
    typedef struct scanlist_s {
        uint32_t ctl;
        uint32_t value;
    } scanlist_t;

    int _runscanlist(scanlist_t *list);
    int _core_savestate();

    cpureg_t *_registers[REGSET_MAX][REGSET_INDEX_COUNT];
    cpureg_t _regdata[A7_REGIDX_MAX];

    static scanlist_t arm7_scanlist_restorestate[];
    static scanlist_t arm7_scanlist_savestate[];
    static scanlist_t arm7_scanlist_memdump[];
};

#endif // ifndef _ASTRIS_ARM7_H
