"""
 mbed CMSIS-DAP debugger
 Copyright (c) 2006-2013 ARM Limited

 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.
"""

from .family.target_kinetis import Kinetis
from .family.flash_kinetis import Flash_Kinetis
from ..core.memory_map import (FlashRegion, RamRegion, RomRegion, MemoryMap)
from ..coresight import ap
from ..coresight.cortex_m import CortexM
from ..debug.svd import SVDFile
import logging
import os.path
from time import (time, sleep)

SIM_SDID = 0x40075024
SIM_SDID_KEYATTR_MASK = 0x70
SIM_SDID_KEYATTR_SHIFT = 4

KEYATTR_DUAL_CORE = 1

RCM_MR = 0x4007f010
RCM_MR_BOOTROM_MASK = 0x6

SCG_CSR = 0x4007B010

SCG_RCCR = 0x4007B014
SCS_MASK = 0x0F000000
SCS_SHIFT = 24
DIVCORE_MASK = 0x000F0000
DIVCORE_SHIFT = 16
DIVSLOW_MASK = 0x0000000F
DIVSLOW_SHIFT = 0

SCG_FIRCCSR = 0x4007B300
FIRCEN_MASK = 1

SCG_FIRCCFG = 0x4007B308

RECOVER_TIMEOUT = 1.0 # 1 second

flash_algo = {
    'load_address' : 0x20000000,
    'instructions' : [
    0xE00ABE00, 0x062D780D, 0x24084068, 0xD3000040, 0x1E644058, 0x1C49D1FA, 0x2A001E52, 0x4770D1F2,
    0x4832b510, 0x60414930, 0x60814931, 0x22806801, 0x22204391, 0x60014311, 0x4448482e, 0xf860f000,
    0xd0002800, 0xbd102001, 0x47702000, 0xb5104829, 0x44484929, 0xf922f000, 0xd1042800, 0x21004825,
    0xf0004448, 0x4a25f9c3, 0x230168d1, 0x4319029b, 0xbd1060d1, 0x4c1fb570, 0x444c4605, 0x4b1e4601,
    0x68e24620, 0xf89ef000, 0xd1052800, 0x46292300, 0x68e24620, 0xf916f000, 0x68ca4918, 0x029b2301,
    0x60ca431a, 0xb570bd70, 0x460b460c, 0x46014606, 0xb0844810, 0x44484615, 0xf8bef000, 0xd10a2800,
    0x90029001, 0x480b2101, 0x462b9100, 0x46314622, 0xf0004448, 0x4909f957, 0x230168ca, 0x431a029b,
    0xb00460ca, 0x0000bd70, 0xd928c520, 0x40076000, 0x0000ffff, 0x00000004, 0x6b65666b, 0xf0003000,
    0xd00a2800, 0x68c9492b, 0x0e094a2b, 0x447a0049, 0x03095a51, 0x2064d103, 0x20044770, 0xb4104770,
    0x60032300, 0x21026041, 0x02896081, 0x492360c1, 0x158a7a0c, 0x610240a2, 0x61837ac9, 0xbc106141,
    0x47704618, 0xd0022800, 0x20006181, 0x20044770, 0x28004770, 0x2004d101, 0xb4104770, 0x42191e5b,
    0x421ad101, 0xbc10d002, 0x47702065, 0x428b6803, 0x6840d804, 0x18181889, 0xd2024288, 0x2066bc10,
    0xbc104770, 0x47702000, 0x4288490d, 0x206bd001, 0x20004770, 0x28004770, 0x290fd008, 0x2a04d802,
    0xe005d104, 0xd8012913, 0xd0012a08, 0x47702004, 0x47702000, 0x40075040, 0x00000512, 0x40020020,
    0x6b65666b, 0x4605b5f8, 0x460c4616, 0xf7ff4618, 0x2800ffdb, 0x2308d12b, 0x46214632, 0xf7ff4628,
    0x0007ffb8, 0x19a6d123, 0x1e7668e9, 0x91004630, 0xf922f000, 0xd0032900, 0x1c409e00, 0x1e764346,
    0xd81342b4, 0x4478480a, 0x60046800, 0x20094909, 0xf00071c8, 0x4607f8f9, 0x280069a8, 0x4780d000,
    0xd1032f00, 0x190468e8, 0xd9eb42b4, 0xbdf84638, 0x00000416, 0x40020000, 0xd1012a00, 0x47702004,
    0x461cb5ff, 0x4615b081, 0x2304460e, 0x98014622, 0xff7ff7ff, 0xd11a0007, 0xd0172c00, 0x4478480d,
    0x600e6801, 0x6800cd02, 0x490b6041, 0x71c82006, 0xf8caf000, 0x98014607, 0x28006980, 0x4780d000,
    0xd1032f00, 0x1d361f24, 0xd1e72c00, 0xb0054638, 0x0000bdf0, 0x000003be, 0x40020000, 0x4604b510,
    0xf7ff4608, 0x2800ff71, 0x2c00d106, 0x4904d005, 0x71c82044, 0xf8a8f000, 0x2004bd10, 0x0000bd10,
    0x40020000, 0xb081b5ff, 0x460e4614, 0x23084605, 0xff3ff7ff, 0xd12a2800, 0x686868a9, 0xf8acf000,
    0x42719000, 0x40014240, 0x42b7424f, 0x9800d101, 0x2c00183f, 0x1bbdd01a, 0xd90042a5, 0x490d4625,
    0x447908e8, 0x600e6809, 0x2201490b, 0x0a0271ca, 0x728872ca, 0x72489804, 0xf876f000, 0xd1062800,
    0x1b649800, 0x183f1976, 0xd1e42c00, 0xb0052000, 0x0000bdf0, 0x0000031a, 0x40020000, 0xd00c2800,
    0xd00a2a00, 0xd21a2908, 0x447b000b, 0x18db791b, 0x0705449f, 0x0d0b0907, 0x2004110f, 0x68c04770,
    0x6840e00a, 0x6880e008, 0x6800e006, 0x2001e004, 0x6900e002, 0x6940e000, 0x20006010, 0x206a4770,
    0x00004770, 0xd1012b00, 0x47702004, 0x461cb5f8, 0x460e4615, 0x9f082304, 0xfedbf7ff, 0xd1192800,
    0xd0172d00, 0x447a4a0f, 0x60066810, 0x2102480e, 0x990671c1, 0x681172c1, 0x60886820, 0xf824f000,
    0xd0082800, 0x29009907, 0x600ed000, 0xd0012f00, 0x60392100, 0x1d24bdf8, 0x1d361f2d, 0xd1e12d00,
    0x0000bdf8, 0x00000276, 0x40020000, 0xd1012800, 0x47702004, 0x4803b510, 0x71c22240, 0xf0007181,
    0xbd10f803, 0x40020000, 0x2170480a, 0x21807001, 0x78017001, 0xd5fc0609, 0x06817800, 0x2067d501,
    0x06c14770, 0x2068d501, 0x07c04770, 0x2069d0fc, 0x00004770, 0x40020000, 0x09032200, 0xd373428b,
    0x428b0a03, 0x0b03d358, 0xd33c428b, 0x428b0c03, 0xe012d321, 0x430b4603, 0x2200d47f, 0x428b0843,
    0x0903d374, 0xd35f428b, 0x428b0a03, 0x0b03d344, 0xd328428b, 0x428b0c03, 0x22ffd30d, 0xba120209,
    0x428b0c03, 0x1212d302, 0xd0650209, 0x428b0b03, 0xe000d319, 0x0bc30a09, 0xd301428b, 0x1ac003cb,
    0x0b834152, 0xd301428b, 0x1ac0038b, 0x0b434152, 0xd301428b, 0x1ac0034b, 0x0b034152, 0xd301428b,
    0x1ac0030b, 0x0ac34152, 0xd301428b, 0x1ac002cb, 0x0a834152, 0xd301428b, 0x1ac0028b, 0x0a434152,
    0xd301428b, 0x1ac0024b, 0x0a034152, 0xd301428b, 0x1ac0020b, 0xd2cd4152, 0x428b09c3, 0x01cbd301,
    0x41521ac0, 0x428b0983, 0x018bd301, 0x41521ac0, 0x428b0943, 0x014bd301, 0x41521ac0, 0x428b0903,
    0x010bd301, 0x41521ac0, 0x428b08c3, 0x00cbd301, 0x41521ac0, 0x428b0883, 0x008bd301, 0x41521ac0,
    0x428b0843, 0x004bd301, 0x41521ac0, 0xd2001a41, 0x41524601, 0x47704610, 0x0fcae05d, 0x4249d000,
    0xd3001003, 0x40534240, 0x469c2200, 0x428b0903, 0x0a03d32d, 0xd312428b, 0x018922fc, 0x0a03ba12,
    0xd30c428b, 0x11920189, 0xd308428b, 0x11920189, 0xd304428b, 0xd03a0189, 0xe0001192, 0x09c30989,
    0xd301428b, 0x1ac001cb, 0x09834152, 0xd301428b, 0x1ac0018b, 0x09434152, 0xd301428b, 0x1ac0014b,
    0x09034152, 0xd301428b, 0x1ac0010b, 0x08c34152, 0xd301428b, 0x1ac000cb, 0x08834152, 0xd301428b,
    0x1ac0008b, 0xd2d94152, 0x428b0843, 0x004bd301, 0x41521ac0, 0xd2001a41, 0x46634601, 0x105b4152,
    0xd3014610, 0x2b004240, 0x4249d500, 0x46634770, 0xd300105b, 0xb5014240, 0x46c02000, 0xbd0246c0,
    0x40020004, 0x00000000, 0x00000000, 0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x00000000,
    0x00800000, 0x00000000,
    ],

    'pc_init' : 0x20000021,
    'pc_unInit': 0x20000049,
    'pc_program_page': 0x200000A7,
    'pc_erase_sector': 0x20000075,
    'pc_eraseAll' : 0x2000004D,

    'static_base' : 0x20000000 + 0x00000020 + 0x00000624,
    'begin_stack' : 0x20000000 + 0x00000800,
    'begin_data' : 0x20000000 + 0x00000A00,
    'page_size' : 0x00000200,

    # All keys above are auto-generated. The following are added or modified.
    'analyzer_supported' : True,                 # [modified] default is False
    'analyzer_address' : 0x1fffa000,             # [modified] default is zero. Use 8K block before flash algo. Can be any unused SRAM.
    'page_buffers' : [0x20000a00, 0x20001200],   # [added] Use areas above algo. Note 'begin_data' is unused if double buffering. Can be any unused SRAM.
    'min_program_length' : 4                     # [added] See FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE in KSDK features header file
};

class Flash_kl28z(Flash_Kinetis):
    def __init__(self, target):
        super(Flash_kl28z, self).__init__(target, flash_algo)

    ##
    # This function sets up target clocks to ensure that flash is clocked at the maximum
    # of 24MHz. Doing so gets the best flash programming performance. The FIRC clock source
    # is used so that there is no dependency on an external crystal frequency.
    def init(self):
        super(Flash_kl28z, self).init()

        # Enable FIRC.
        value = self.target.read32(SCG_FIRCCSR)
        value |= FIRCEN_MASK
        self.target.write32(SCG_FIRCCSR, value)

        # Switch system to FIRC, core=48MHz (/1), slow=24MHz (/2).
        # Flash and the bus are clocked from the slow clock, and its max is 24MHz,
        # so there is no benefit from raising the core clock further.
        self.target.write32(SCG_RCCR, (0x3 << SCS_SHIFT) | (1 << DIVSLOW_SHIFT))

        csr = self.target.read32(SCG_CSR)
        logging.debug("SCG_CSR = 0x%08x", csr)

class KL28x(Kinetis):

    singleMap = MemoryMap(
        FlashRegion(name='flash', start=0, length=0x80000, blocksize=0x800, isBootMemory=True),
        RamRegion(name='ram', start=0x1fff8000, length=0x20000),
        RamRegion(name='usb ram', start=0x40100000, length=0x800)
        )

    dualMap = MemoryMap(
        FlashRegion(name='flash', start=0, length=0x80000, blocksize=0x800, isBootMemory=True),
        RomRegion(name='core1 imem alias', start=0x1d200000, length=0x40000),
        RamRegion(name='core0 ram', start=0x1fffa000, length=0x18000),
        RomRegion(name='core1 imem', start=0x2d200000, length=0x40000),
        RamRegion(name='core1 dmem', start=0x2d300000, length=0x8000),
        RamRegion(name='usb ram', start=0x40100000, length=0x800)
        )

    def __init__(self, link):
        super(KL28x, self).__init__(link, self.singleMap)
        self.mdm_idr = 0x001c0020
        self.is_dual_core = False

        self._svd_location = SVDFile(vendor="Freescale", filename="MKL28T7_CORE0.svd", is_local=False)

    def init(self):
        super(KL28x, self).init()

        # Check if this is the dual core part.
        sdid = self.readMemory(SIM_SDID)
        keyattr = (sdid & SIM_SDID_KEYATTR_MASK) >> SIM_SDID_KEYATTR_SHIFT
        logging.debug("KEYATTR=0x%x SDID=0x%08x", keyattr, sdid)
        self.is_dual_core = (keyattr == KEYATTR_DUAL_CORE)
        if self.is_dual_core:
            logging.info("KL28 is dual core")
            self.memory_map = self.dualMap
            self.cores[0].memory_map = self.dualMap

            # Add second core's AHB-AP.
            core1_ap = ap.AHB_AP(self.dp, 2)
            core1_ap.init(True)
            self.add_ap(core1_ap)

            # Add second core. It is held in reset until released by software.
            core1 = CortexM(self.link, self.dp, core1_ap, self.memory_map, core_num=1)
            core1.init()
            self.add_core(core1)

        # Disable ROM vector table remapping.
        self.write32(RCM_MR, RCM_MR_BOOTROM_MASK)




