/***************************************************************************
 *   Copyright (C) 2011 by James K. Larson                                 *
 *   jlarson@pacifier.com                                                  *
 *                                                                         *
 *   Copyright (C) 2013 Cosmin Gorgovan                                    *
 *   cosmin [at] linux-geek [dot] org                                      *
 *                                                                         *
 *   Copyright (C) 2014 Pawel Si                                           *
 *   stawel+openocd@gmail.com                                              *
 *                                                                         *
 *   Copyright (C) 2015 Nemui Trinomius                                    *
 *   nemuisan_kawausogasuki@live.jp                                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "imp.h"
#include <helper/binarybuffer.h>
#include <target/algorithm.h>
#include <target/armv7m.h>
#include <target/cortex_m.h>

/* Nuvoton NuMicro register locations */
#define NUMICRO_SYS_BASE        0x50000000
#define NUMICRO_SYS_WRPROT      0x50000100
#define NUMICRO_SYS_IPRSTC1     0x50000008

#define NUMICRO_SYSCLK_BASE     0x50000200
#define NUMICRO_SYSCLK_PWRCON   0x50000200
#define NUMICRO_SYSCLK_CLKSEL0  0x50000210
#define NUMICRO_SYSCLK_CLKDIV   0x50000218
#define NUMICRO_SYSCLK_AHBCLK   0x50000204

#define NUMICRO_FLASH_BASE      0x5000C000
#define NUMICRO_FLASH_ISPCON    0x5000C000
#define NUMICRO_FLASH_ISPADR    0x5000C004
#define NUMICRO_FLASH_ISPDAT    0x5000C008
#define NUMICRO_FLASH_ISPCMD    0x5000C00C
#define NUMICRO_FLASH_ISPTRG    0x5000C010
#define NUMICRO_FLASH_CHEAT	  0x5000C01C	/* Undocumented isp register(may be cheat register) */

#define NUMICRO_SCS_BASE        0xE000E000
#define NUMICRO_SCS_AIRCR       0xE000ED0C
#define NUMICRO_SCS_DHCSR       0xE000EDF0
#define NUMICRO_SCS_DEMCR       0xE000EDFC

#define NUMICRO_APROM_BASE      0x00000000
#define NUMICRO_DATA_BASE       0x0001F000
#define NUMICRO_LDROM_BASE      0x00100000
#define NUMICRO_CONFIG_BASE     0x00300000

#define NUMICRO_CONFIG0         0x5000C000
#define NUMICRO_CONFIG1         0x5000C004

/* Command register bits */
#define PWRCON_OSC22M         (1 << 2)
#define PWRCON_XTL12M         (1 << 0)

#define IPRSTC1_CPU_RST       (1 << 1)
#define IPRSTC1_CHIP_RST      (1 << 0)

#define AHBCLK_ISP_EN         (1 << 2)
#define AHBCLK_SRAM_EN        (1 << 4)
#define AHBCLK_TICK_EN        (1 << 5)

#define ISPCON_ISPEN          (1 << 0)
#define ISPCON_BS_AP          (0 << 1)
#define ISPCON_BS_LP          (1 << 1)
#define ISPCON_BS_MASK        (1 << 1)
#define ISPCON_APUEN          (1 << 3)
#define ISPCON_CFGUEN         (1 << 4)
#define ISPCON_LDUEN          (1 << 5)
#define ISPCON_ISPFF          (1 << 6)

#define CONFIG0_LOCK_MASK	  (1 << 1)

/* isp commands */
#define ISPCMD_READ           0x00
#define ISPCMD_WRITE          0x21
#define ISPCMD_ERASE          0x22
#define ISPCMD_CHIPERASE      0x26   /* Undocumented isp "Chip-Erase" command */
#define ISPCMD_READ_CID       0x0B
#define ISPCMD_READ_DID       0x0C
#define ISPCMD_READ_UID       0x04
#define ISPCMD_VECMAP         0x2E
#define ISPTRG_ISPGO          (1 << 0)

/* access unlock keys */
#define REG_KEY1              0x59
#define REG_KEY2              0x16
#define REG_KEY3              0x88
#define REG_LOCK              0x00

/* flash pagesizes */
#define NUMICRO_PAGESIZE        512
/* flash MAX banks */
#define NUMICRO_MAX_FLASH_BANKS 4

/* flash bank structs */
struct numicro_flash_bank_type {
	uint32_t base;
	uint32_t size;
};

/* part structs */
struct numicro_cpu_type {
	char *partname;
	uint32_t partid;
	unsigned int n_banks;
	struct numicro_flash_bank_type bank[NUMICRO_MAX_FLASH_BANKS];
};

/* TODO : Support variable DataFlash region for 128kB Flash model */
#define NUMICRO_BANKS_NUC100(aprom_size) \
	.n_banks = 4, \
	{ {NUMICRO_APROM_BASE, (aprom_size)}, {NUMICRO_DATA_BASE, 4*1024}, {NUMICRO_LDROM_BASE, 4*1024}, \
	{NUMICRO_CONFIG_BASE, 1024} }

#define NUMICRO_BANKS_M051(aprom_size) \
	.n_banks = 4, \
	{ {NUMICRO_APROM_BASE, (aprom_size)}, {NUMICRO_DATA_BASE, 4*1024}, {NUMICRO_LDROM_BASE, 4*1024}, \
	{NUMICRO_CONFIG_BASE, 1024} }

#define NUMICRO_BANKS_MINI51(aprom_size) \
	.n_banks = 3, \
	{ {NUMICRO_APROM_BASE, (aprom_size)}, {NUMICRO_LDROM_BASE, 2*1024}, {NUMICRO_CONFIG_BASE, 512} }

#define NUMICRO_BANKS_NANO(aprom_size) \
	.n_banks = 4, \
	{ {NUMICRO_APROM_BASE, (aprom_size)}, {NUMICRO_DATA_BASE, 4*1024}, {NUMICRO_LDROM_BASE, 4*1024}, \
	{NUMICRO_CONFIG_BASE, 1024} }

#define NUMICRO_BANKS_NUC400(aprom_size) \
	.n_banks = 4, \
	{ {NUMICRO_APROM_BASE, (aprom_size)}, {NUMICRO_DATA_BASE, 4*1024}, {NUMICRO_LDROM_BASE, 16*1024}, \
	{NUMICRO_CONFIG_BASE, 1024} }


static const struct numicro_cpu_type NuMicroParts[] = {
	/*PART NO*/     /*PART ID*/ /*Banks*/
	/* NUC100 Version B */
	{"NUC100LD2BN", 0x10010004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100LD1BN", 0x10010005, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100LD0BN", 0x10010027, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100LC2BN", 0x10010007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100LC1BN", 0x10010008, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100LC0BN", 0x10010028, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100LB2BN", 0x10010029, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC100LB1BN", 0x10010030, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC100LB0BN", 0x10010031, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC100LA2BN", 0x10010032, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC100LA1BN", 0x10010033, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC100LA0BN", 0x10010034, NUMICRO_BANKS_NUC100(8*1024)},

	{"NUC100RD2BN", 0x10010013, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100RD1BN", 0x10010014, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100RD0BN", 0x10010035, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100RC2BN", 0x10010016, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100RC1BN", 0x10010017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100RC0BN", 0x10010036, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100RB2BN", 0x10010037, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC100RB1BN", 0x10010038, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC100RB0BN", 0x10010039, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC100RA2BN", 0x10010040, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC100RA1BN", 0x10010041, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC100RA0BN", 0x10010042, NUMICRO_BANKS_NUC100(8*1024)},

    /* NUC100 Version C */
	{"NUC100LE3CN", 0x20010000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100LE2CN", 0x20010001, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100LE1CN", 0x20010002, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100LD3CN", 0x20010003, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100LD2CN", 0x20010004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100LD1CN", 0x20010005, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100LC3CN", 0x20010006, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100LC2CN", 0x20010007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100LC1CN", 0x20010008, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100RE3CN", 0x20010009, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100RE2CN", 0x20010010, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100RE1CN", 0x20010011, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100RD3CN", 0x20010012, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100RD2CN", 0x20010013, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100RD1CN", 0x20010014, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100RC3CN", 0x20010015, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100RC2CN", 0x20010016, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100RC1CN", 0x20010017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100VE3CN", 0x20010018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100VE2CN", 0x20010019, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100VE1CN", 0x20010020, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100VD3CN", 0x20010021, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100VD2CN", 0x20010022, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100VD1CN", 0x20010023, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100VC3CN", 0x20010024, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100VC2CN", 0x20010025, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100VC1CN", 0x20010026, NUMICRO_BANKS_NUC100(32*1024)},

    /* NUC100 Version B */
	{"NUC101YD2BN", 0x10010143, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101YD1BN", 0x10010144, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101YD0BN", 0x10010145, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101YC2BN", 0x10010146, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101YC1BN", 0x10010147, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101YC0BN", 0x10010148, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101YB2BN", 0x10010149, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC101YB1BN", 0x10010150, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC101YB0BN", 0x10010151, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC101YA2BN", 0x10010152, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC101YA1BN", 0x10010153, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC101YA0BN", 0x10010154, NUMICRO_BANKS_NUC100(8*1024)},

	{"NUC101LD2BN", 0x10010104, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101LD1BN", 0x10010105, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101LD0BN", 0x10010127, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101LC2BN", 0x10010107, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101LC1BN", 0x10010108, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101LC0BN", 0x10010128, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101LB2BN", 0x10010129, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC101LB1BN", 0x10010130, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC101LB0BN", 0x10010131, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC101LA2BN", 0x10010132, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC101LA1BN", 0x10010133, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC101LA0BN", 0x10010134, NUMICRO_BANKS_NUC100(8*1024)},

	{"NUC101RD2BN", 0x10010113, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101RD1BN", 0x10010114, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101RD0BN", 0x10010135, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101RC2BN", 0x10010116, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101RC1BN", 0x10010117, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101RC0BN", 0x10010136, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101RB2BN", 0x10010137, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC101RB1BN", 0x10010138, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC101RB0BN", 0x10010139, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC101RA2BN", 0x10010140, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC101RA1BN", 0x10010141, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC101RA0BN", 0x10010142, NUMICRO_BANKS_NUC100(8*1024)},

    /* NUC101 Version C */
	{"NUC101LE3CN", 0x20010100, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101LE2CN", 0x20010101, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101LE1CN", 0x20010102, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101LD3CN", 0x20010103, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101LD2CN", 0x20010104, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101LD1CN", 0x20010105, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101LC3CN", 0x20010106, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101LC2CN", 0x20010107, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101LC1CN", 0x20010108, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101RE3CN", 0x20010109, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101RE2CN", 0x20010110, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101RE1CN", 0x20010111, NUMICRO_BANKS_NUC100(128*1024)},

	{"NUC101RD3CN", 0x20010112, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101RD2CN", 0x20010113, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101RD1CN", 0x20010114, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101RC3CN", 0x20010115, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101RC2CN", 0x20010116, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101RC1CN", 0x20010117, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101VE3CN", 0x20010118, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101VE2CN", 0x20010119, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101VE1CN", 0x20010120, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101VD3CN", 0x20010121, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101VD2CN", 0x20010122, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101VD1CN", 0x20010123, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101VC3CN", 0x20010124, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101VC2CN", 0x20010125, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101VC1CN", 0x20010126, NUMICRO_BANKS_NUC100(32*1024)},

    /* NUC102 Version A */
	{"NUC102ZD2AN", 0x00010231, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC102ZC1AN", 0x00010235, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC102LD2AN", 0x00010204, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC102LC1AN", 0x00010208, NUMICRO_BANKS_NUC100(32*1024)},

	{"NUC102RB3AN", 0x00010248, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC102RB2AN", 0x00010249, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC102RB1AN", 0x00010250, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC102RA3AN", 0x00010251, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC102RA2AN", 0x00010252, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC102RA1AN", 0x00010253, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC102VB3AN", 0x00010254, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC102VB2AN", 0x00010255, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC102VB1AN", 0x00010256, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC102VA3AN", 0x00010257, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC102VA2AN", 0x00010258, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC102VA1AN", 0x00010259, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC102LA0AN", 0x00010260, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC102LB0AN", 0x00010261, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC102LC0AN", 0x00010262, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC102LD0AN", 0x00010263, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC102RA0AN", 0x00010264, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC102RB0AN", 0x00010265, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC102RC0AN", 0x00010266, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC102RD0AN", 0x00010267, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC102VA0AN", 0x00010268, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC102VB0AN", 0x00010269, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC102VC0AN", 0x00010270, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC102VD0AN", 0x00010271, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC102ZA0AN", 0x00010272, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC102ZB0AN", 0x00010273, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC102ZC0AN", 0x00010274, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC102ZD0AN", 0x00010275, NUMICRO_BANKS_NUC100(64*1024)},

    /* NUC102 Version A */
	{"NUC122LD2AN", 0x00012204, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122LD1AN", 0x00012205, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122LC2AN", 0x00012207, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122LC1AN", 0x00012208, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122RD2AN", 0x00012213, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122RD1AN", 0x00012214, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122RC2AN", 0x00012216, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122RC1AN", 0x00012217, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122SD2AN", 0x00012222, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122SD1AN", 0x00012223, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122SC2AN", 0x00012225, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122SC1AN", 0x00012226, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122ZD2AN", 0x00012231, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122ZD1AN", 0x00012232, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122ZC2AN", 0x00012234, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122ZC1AN", 0x00012235, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122ZB2AN", 0x00012237, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122ZB1AN", 0x00012238, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122ZA2AN", 0x00012240, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC122ZA1AN", 0x00012241, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC122LB2AN", 0x00012243, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122LB1AN", 0x00012244, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122LA2AN", 0x00012246, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC122LA1AN", 0x00012247, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC122RB2AN", 0x00012249, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122RB1AN", 0x00012250, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122RA2AN", 0x00012252, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC122RA1AN", 0x00012253, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC122SB2AN", 0x00012255, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122SB1AN", 0x00012256, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122SA2AN", 0x00012258, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC122SA1AN", 0x00012259, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC122LA0AN", 0x00012260, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC122LB0AN", 0x00012261, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122LC0AN", 0x00012262, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122LD0AN", 0x00012263, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122RA0AN", 0x00012264, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC122RB0AN", 0x00012265, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122RC0AN", 0x00012266, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122RD0AN", 0x00012267, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122SA0AN", 0x00012268, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC122SB0AN", 0x00012269, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122SC0AN", 0x00012270, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122SD0AN", 0x00012271, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122ZA0AN", 0x00012272, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC122ZB0AN", 0x00012273, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122ZC0AN", 0x00012274, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122ZD0AN", 0x00012275, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122YD2AN", 0x00012277, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122YD1AN", 0x00012278, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122YD0AN", 0x00012279, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC122YC2AN", 0x00012281, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122YC1AN", 0x00012282, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122YC0AN", 0x00012283, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC122YB2AN", 0x00012285, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122YB1AN", 0x00012286, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122YB0AN", 0x00012287, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC122YA2AN", 0x00012289, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC122YA1AN", 0x00012290, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC122YA0AN", 0x00012291, NUMICRO_BANKS_NUC100(8*1024)},

    /* NUC120 Version C */
	{"NUC120LD2BN", 0x10012004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120LD1BN", 0x10012005, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120LD0BN", 0x10012027, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120LC2BN", 0x10012007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120LC1BN", 0x10012008, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120LC0BN", 0x10012028, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120LB2BN", 0x10012029, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC120LB1BN", 0x10012030, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC120LB0BN", 0x10012031, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC120LA2BN", 0x10012032, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC120LA1BN", 0x10012033, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC120LA0BN", 0x10012034, NUMICRO_BANKS_NUC100(8*1024)},

	{"NUC120RD2BN", 0x10012013, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120RD1BN", 0x10012014, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120RD0BN", 0x10012035, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120RC2BN", 0x10012016, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120RC1BN", 0x10012017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120RC0BN", 0x10012036, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120RB2BN", 0x10012037, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC120RB1BN", 0x10012038, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC120RB0BN", 0x10012039, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC120RA2BN", 0x10012040, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC120RA1BN", 0x10012041, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC120RA0BN", 0x10012042, NUMICRO_BANKS_NUC100(8*1024)},

    /* NUC120 Version C */
	{"NUC120LE3CN", 0x20012000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120LE2CN", 0x20012001, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120LE1CN", 0x20012002, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120LD3CN", 0x20012003, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120LD2CN", 0x20012004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120LD1CN", 0x20012005, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120LC3CN", 0x20012006, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120LC2CN", 0x20012007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120LC1CN", 0x20012008, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120RE3CN", 0x20012009, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120RE2CN", 0x20012010, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120RE1CN", 0x20012011, NUMICRO_BANKS_NUC100(128*1024)},

	{"NUC120RD3CN", 0x20012012, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120RD2CN", 0x20012013, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120RD1CN", 0x20012014, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120RC3CN", 0x20012015, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120RC2CN", 0x20012016, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120RC1CN", 0x20012017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120VE3CN", 0x20012018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120VE2CN", 0x20012019, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120VE1CN", 0x20012020, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120VD3CN", 0x20012021, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120VD2CN", 0x20012022, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120VD1CN", 0x20012023, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120VC3CN", 0x20012024, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120VC2CN", 0x20012025, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120VC1CN", 0x20012026, NUMICRO_BANKS_NUC100(32*1024)},

    /* NUC120 Version B */
	{"NUC130LD2BN", 0x10013004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130LD1BN", 0x10013005, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130LD0BN", 0x10013027, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130LC2BN", 0x10013007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130LC1BN", 0x10013008, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130LC0BN", 0x10013028, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130LB2BN", 0x10013029, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC130LB1BN", 0x10013030, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC130LB0BN", 0x10013031, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC130LA2BN", 0x10013032, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC130LA1BN", 0x10013033, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC130LA0BN", 0x10013034, NUMICRO_BANKS_NUC100(8*1024)},

	{"NUC130RD2BN", 0x10013013, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130RD1BN", 0x10013014, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130RD0BN", 0x10013035, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130RC2BN", 0x10013016, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130RC1BN", 0x10013017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130RC0BN", 0x10013036, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130RB2BN", 0x10013037, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC130RB1BN", 0x10013038, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC130RB0BN", 0x10013039, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC130RA2BN", 0x10013040, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC130RA1BN", 0x10013041, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC130RA0BN", 0x10013042, NUMICRO_BANKS_NUC100(8*1024)},

    /* NUC130 Version C */
	{"NUC130LE3CN", 0x20013000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130LE2CN", 0x20013001, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130LE1CN", 0x20013002, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130LD3CN", 0x20013003, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130LD2CN", 0x20013004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130LD1CN", 0x20013005, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130LC3CN", 0x20013006, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130LC2CN", 0x20013007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130LC1CN", 0x20013008, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130RE3CN", 0x20013009, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130RE2CN", 0x20013010, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130RE1CN", 0x20013011, NUMICRO_BANKS_NUC100(128*1024)},

	{"NUC130RD3CN", 0x20013012, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130RD2CN", 0x20013013, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130RD1CN", 0x20013014, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130RC3CN", 0x20013015, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130RC2CN", 0x20013016, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130RC1CN", 0x20013017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130VE3CN", 0x20013018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130VE2CN", 0x20013019, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130VE1CN", 0x20013020, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130VD3CN", 0x20013021, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130VD2CN", 0x20013022, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130VD1CN", 0x20013023, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130VC3CN", 0x20013024, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130VC2CN", 0x20013025, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130VC1CN", 0x20013026, NUMICRO_BANKS_NUC100(32*1024)},

    /* NUC140 Version B */
	{"NUC140LD2BN", 0x10014004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140LD1BN", 0x10014005, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140LD0BN", 0x10014027, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140LC2BN", 0x10014007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140LC1BN", 0x10014008, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140LC0BN", 0x10014028, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140LB2BN", 0x10014029, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC140LB1BN", 0x10014030, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC140LB0BN", 0x10014031, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC140LA2BN", 0x10014032, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC140LA1BN", 0x10014033, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC140LA0BN", 0x10014034, NUMICRO_BANKS_NUC100(8*1024)},

	{"NUC140RD2BN", 0x10014013, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140RD1BN", 0x10014014, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140RD0BN", 0x10014035, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140RC2BN", 0x10014016, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140RC1BN", 0x10014017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140RC0BN", 0x10014036, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140RB2BN", 0x10014037, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC140RB1BN", 0x10014038, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC140RB0BN", 0x10014039, NUMICRO_BANKS_NUC100(16*1024)},
	{"NUC140RA2BN", 0x10014040, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC140RA1BN", 0x10014041, NUMICRO_BANKS_NUC100(8*1024)},
	{"NUC140RA0BN", 0x10014042, NUMICRO_BANKS_NUC100(8*1024)},

    /* NUC140 Version C */
	{"NUC140LE3CN", 0x20014000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140LE2CN", 0x20014001, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140LE1CN", 0x20014002, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140LD3CN", 0x20014003, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140LD2CN", 0x20014004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140LD1CN", 0x20014005, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140LC3CN", 0x20014006, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140LC2CN", 0x20014007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140LC1CN", 0x20014008, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140RE3CN", 0x20014009, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140RE2CN", 0x20014010, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140RE1CN", 0x20014011, NUMICRO_BANKS_NUC100(128*1024)},

	{"NUC140RD3CN", 0x20014012, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140RD2CN", 0x20014013, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140RD1CN", 0x20014014, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140RC3CN", 0x20014015, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140RC2CN", 0x20014016, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140RC1CN", 0x20014017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140VE3CN", 0x20014018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140VE2CN", 0x20014019, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140VE1CN", 0x20014020, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140VD3CN", 0x20014021, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140VD2CN", 0x20014022, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140VD1CN", 0x20014023, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140VC3CN", 0x20014024, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140VC2CN", 0x20014025, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140VC1CN", 0x20014026, NUMICRO_BANKS_NUC100(32*1024)},

    /* NUC100 Version A */
	{"NUC100LE3AN", 0x00010000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100LE2AN", 0x00010001, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100LE1AN", 0x00010002, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100LD3AN", 0x00010003, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100LD2AN", 0x00010004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100LD1AN", 0x00010005, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100LC3AN", 0x00010006, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100LC2AN", 0x00010007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100LC1AN", 0x00010008, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100RE3AN", 0x00010009, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100RE2AN", 0x00010010, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100RE1AN", 0x00010011, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100RD3AN", 0x00010012, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100RD2AN", 0x00010013, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100RD1AN", 0x00010014, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100RC3AN", 0x00010015, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100RC2AN", 0x00010016, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100RC1AN", 0x00010017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100VE3AN", 0x00010018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100VE2AN", 0x00010019, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100VE1AN", 0x00010020, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100VD3AN", 0x00010021, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100VD2AN", 0x00010022, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100VD1AN", 0x00010023, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100VC3AN", 0x00010024, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100VC2AN", 0x00010025, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100VC1AN", 0x00010026, NUMICRO_BANKS_NUC100(32*1024)},

    /* NUC100 Version A */
	{"NUC101LE3AN", 0x00010100, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101LE2AN", 0x00010101, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101LE1AN", 0x00010102, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101LD3AN", 0x00010103, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101LD2AN", 0x00010104, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101LD1AN", 0x00010105, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101LC3AN", 0x00010106, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101LC2AN", 0x00010107, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101LC1AN", 0x00010108, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101RE3AN", 0x00010109, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101RE2AN", 0x00010110, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101RE1AN", 0x00010111, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101RD3AN", 0x00010112, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101RD2AN", 0x00010113, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101RD1AN", 0x00010114, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101RC3AN", 0x00010115, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101RC2AN", 0x00010116, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101RC1AN", 0x00010117, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101VE3AN", 0x00010118, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101VE2AN", 0x00010119, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101VE1AN", 0x00010120, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC101VD3AN", 0x00010121, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101VD2AN", 0x00010122, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101VD1AN", 0x00010123, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC101VC3AN", 0x00010124, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101VC2AN", 0x00010125, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC101VC1AN", 0x00010126, NUMICRO_BANKS_NUC100(32*1024)},

    /* NUC120 Version A */
	{"NUC120LE3AN", 0x00012000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120LE2AN", 0x00012001, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120LE1AN", 0x00012002, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120LD3AN", 0x00012003, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120LD2AN", 0x00012004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120LD1AN", 0x00012005, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120LC3AN", 0x00012006, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120LC2AN", 0x00012007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120LC1AN", 0x00012008, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120RE3AN", 0x00012009, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120RE2AN", 0x00012010, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120RE1AN", 0x00012011, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120RD3AN", 0x00012012, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120RD2AN", 0x00012013, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120RD1AN", 0x00012014, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120RC3AN", 0x00012015, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120RC2AN", 0x00012016, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120RC1AN", 0x00012017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120VE3AN", 0x00012018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120VE2AN", 0x00012019, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120VE1AN", 0x00012020, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120VD3AN", 0x00012021, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120VD2AN", 0x00012022, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120VD1AN", 0x00012023, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120VC3AN", 0x00012024, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120VC2AN", 0x00012025, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120VC1AN", 0x00012026, NUMICRO_BANKS_NUC100(32*1024)},

    /* NUC120 Version A */
	{"NUC130LE3AN", 0x00013000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130LE2AN", 0x00013001, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130LE1AN", 0x00013002, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130LD3AN", 0x00013003, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130LD2AN", 0x00013004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130LD1AN", 0x00013005, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130LC3AN", 0x00013006, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130LC2AN", 0x00013007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130LC1AN", 0x00013008, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130RE3AN", 0x00013009, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130RE2AN", 0x00013010, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130RE1AN", 0x00013011, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130RD3AN", 0x00013012, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130RD2AN", 0x00013013, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130RD1AN", 0x00013014, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130RC3AN", 0x00013015, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130RC2AN", 0x00013016, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130RC1AN", 0x00013017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130VE3AN", 0x00013018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130VE2AN", 0x00013019, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130VE1AN", 0x00013020, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130VD3AN", 0x00013021, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130VD2AN", 0x00013022, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130VD1AN", 0x00013023, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC130VC3AN", 0x00013024, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130VC2AN", 0x00013025, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC130VC1AN", 0x00013026, NUMICRO_BANKS_NUC100(32*1024)},

    /* NUC140 Version A */
	{"NUC140LE3AN", 0x00014000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140LE2AN", 0x00014001, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140LE1AN", 0x00014002, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140LD3AN", 0x00014003, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140LD2AN", 0x00014004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140LD1AN", 0x00014005, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140LC3AN", 0x00014006, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140LC2AN", 0x00014007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140LC1AN", 0x00014008, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140RE3AN", 0x00014009, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140RE2AN", 0x00014010, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140RE1AN", 0x00014011, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140RD3AN", 0x00014012, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140RD2AN", 0x00014013, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140RD1AN", 0x00014014, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140RC3AN", 0x00014015, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140RC2AN", 0x00014016, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140RC1AN", 0x00014017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140VE3AN", 0x00014018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140VE2AN", 0x00014019, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140VE1AN", 0x00014020, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC140VD3AN", 0x00014021, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140VD2AN", 0x00014022, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140VD1AN", 0x00014023, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC140VC3AN", 0x00014024, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140VC2AN", 0x00014025, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC140VC1AN", 0x00014026, NUMICRO_BANKS_NUC100(32*1024)},


	/* M052 */
	{"M052LAN"  , 0x00005200, NUMICRO_BANKS_M051(8*1024)},
	{"M052PAN"  , 0x00005201, NUMICRO_BANKS_M051(8*1024)},
	{"M052YAN"  , 0x00005202, NUMICRO_BANKS_M051(8*1024)},
	{"M052ZAN"  , 0x00005203, NUMICRO_BANKS_M051(8*1024)},

    /* M054 */
	{"M054LAN"  , 0x00005400, NUMICRO_BANKS_M051(16*1024)},
	{"M054PAN"  , 0x00005401, NUMICRO_BANKS_M051(16*1024)},
	{"M054YAN"  , 0x00005402, NUMICRO_BANKS_M051(16*1024)},
	{"M054ZAN"  , 0x00005403, NUMICRO_BANKS_M051(16*1024)},

    /* M058 */
	{"M058LAN"  , 0x00005800, NUMICRO_BANKS_M051(32*1024)},
	{"M058PAN"  , 0x00005801, NUMICRO_BANKS_M051(32*1024)},
	{"M058YAN"  , 0x00005802, NUMICRO_BANKS_M051(32*1024)},
	{"M058ZAN"  , 0x00005803, NUMICRO_BANKS_M051(32*1024)},

    /* M0516 */
	{"M0516LAN" , 0x00005A00, NUMICRO_BANKS_M051(64*1024)},
	{"M0516PAN" , 0x00005A01, NUMICRO_BANKS_M051(64*1024)},
	{"M0516YAN" , 0x00005A02, NUMICRO_BANKS_M051(64*1024)},
	{"M0516ZAN" , 0x00005A03, NUMICRO_BANKS_M051(64*1024)},
	{"M051LBN"  , 0x10005100, NUMICRO_BANKS_M051(4*1024)},
	{"M051PBN"  , 0x10005101, NUMICRO_BANKS_M051(4*1024)},
	{"M051YBN"  , 0x10005102, NUMICRO_BANKS_M051(4*1024)},
	{"M051ZBN"  , 0x10005103, NUMICRO_BANKS_M051(4*1024)},
	{"M052LBN"  , 0x10005200, NUMICRO_BANKS_M051(8*1024)},
	{"M052PBN"  , 0x10005201, NUMICRO_BANKS_M051(8*1024)},
	{"M052YBN"  , 0x10005202, NUMICRO_BANKS_M051(8*1024)},
	{"M052ZBN"  , 0x10005203, NUMICRO_BANKS_M051(8*1024)},
	{"M054LBN"  , 0x10005400, NUMICRO_BANKS_M051(16*1024)},
	{"M054PBN"  , 0x10005401, NUMICRO_BANKS_M051(16*1024)},
	{"M054YBN"  , 0x10005402, NUMICRO_BANKS_M051(16*1024)},
	{"M054ZBN"  , 0x10005403, NUMICRO_BANKS_M051(16*1024)},
	{"M058LBN"  , 0x10005800, NUMICRO_BANKS_M051(32*1024)},
	{"M058PBN"  , 0x10005801, NUMICRO_BANKS_M051(32*1024)},
	{"M058YBN"  , 0x10005802, NUMICRO_BANKS_M051(32*1024)},
	{"M058ZBN"  , 0x10005803, NUMICRO_BANKS_M051(32*1024)},
	{"M0516LBN" , 0x10005A00, NUMICRO_BANKS_M051(64*1024)},
	{"M0516PBN" , 0x10005A01, NUMICRO_BANKS_M051(64*1024)},
	{"M0516YBN" , 0x10005A02, NUMICRO_BANKS_M051(64*1024)},
	{"M0516ZBN" , 0x10005A03, NUMICRO_BANKS_M051(64*1024)},
	{"M052LDN"  , 0x20005200, NUMICRO_BANKS_M051(8*1024)},
	{"M054LDN"  , 0x20005400, NUMICRO_BANKS_M051(16*1024)},
	{"M058LDN"  , 0x20005800, NUMICRO_BANKS_M051(32*1024)},
	{"M0516LDN" , 0x20005A00, NUMICRO_BANKS_M051(64*1024)},
	{"M052ZDN"  , 0x20005203, NUMICRO_BANKS_M051(8*1024)},
	{"M054ZDN"  , 0x20005403, NUMICRO_BANKS_M051(16*1024)},
	{"M058ZDN"  , 0x20005803, NUMICRO_BANKS_M051(32*1024)},
	{"M0516ZDN" , 0x20005A03, NUMICRO_BANKS_M051(64*1024)},
	{"M052TDN"  , 0x20005204, NUMICRO_BANKS_M051(8*1024)},
	{"M054TDN"  , 0x20005404, NUMICRO_BANKS_M051(16*1024)},
	{"M058TDN"  , 0x20005804, NUMICRO_BANKS_M051(32*1024)},
	{"M0516TDN" , 0x20005A04, NUMICRO_BANKS_M051(64*1024)},
	{"M052XDN"  , 0x20005205, NUMICRO_BANKS_M051(8*1024)},
	{"M054XDN"  , 0x20005405, NUMICRO_BANKS_M051(16*1024)},
	{"M058XDN"  , 0x20005805, NUMICRO_BANKS_M051(32*1024)},
	{"M0516XDN" , 0x20005A05, NUMICRO_BANKS_M051(64*1024)},
	{"M052LDE"  , 0x30005200, NUMICRO_BANKS_M051(8*1024)},
	{"M054LDE"  , 0x30005400, NUMICRO_BANKS_M051(16*1024)},
	{"M058LDE"  , 0x30005800, NUMICRO_BANKS_M051(32*1024)},
	{"M0516LDE" , 0x30005A00, NUMICRO_BANKS_M051(64*1024)},
	{"M052ZDE"  , 0x30005203, NUMICRO_BANKS_M051(8*1024)},
	{"M054ZDE"  , 0x30005403, NUMICRO_BANKS_M051(16*1024)},
	{"M058ZDE"  , 0x30005803, NUMICRO_BANKS_M051(32*1024)},
	{"M0516ZDE" , 0x30005A03, NUMICRO_BANKS_M051(64*1024)},
	{"M052TDE"  , 0x30005204, NUMICRO_BANKS_M051(8*1024)},
	{"M054TDE"  , 0x30005404, NUMICRO_BANKS_M051(16*1024)},
	{"M058TDE"  , 0x30005804, NUMICRO_BANKS_M051(32*1024)},
	{"M0516TDE" , 0x30005A04, NUMICRO_BANKS_M051(64*1024)},
	{"M052XDE"  , 0x30005205, NUMICRO_BANKS_M051(8*1024)},
	{"M054XDE"  , 0x30005405, NUMICRO_BANKS_M051(16*1024)},
	{"M058XDE"  , 0x30005805, NUMICRO_BANKS_M051(32*1024)},
	{"M0516XDE" , 0x30005A05, NUMICRO_BANKS_M051(64*1024)},

	/* Mini51 */
	{"MINI51LAN",  0x00205100, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI51QAN",  0x00205101, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI51   ",  0x00205102, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI51ZAN",  0x00205103, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI51TAN",  0x00205104, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI52LAN",  0x00205200, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI52QAN",  0x00205201, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI52   ",  0x00205202, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI52ZAN",  0x00205203, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI52TAN",  0x00205204, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI54LAN",  0x00205400, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI54QAN",  0x00205401, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI54   ",  0x00205402, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI54ZAN",  0x00205403, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI54TAN",  0x00205404, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI51LBN",  0x10205100, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI51QBN",  0x10205101, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI51   ",  0x10205102, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI51ZBN",  0x10205103, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI51TBN",  0x10205104, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI52LBN",  0x10205200, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI52QBN",  0x10205201, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI52   ",  0x10205202, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI52ZBN",  0x10205203, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI52TBN",  0x10205204, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI54LBN",  0x10205400, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI54QBN",  0x10205401, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI54   ",  0x10205402, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI54ZBN" , 0x10205403, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI54TBN" , 0x10205404, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI51LDE" , 0x20205100, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI51QDE" , 0x20205101, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI51   " , 0x20205102, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI51ZDE" , 0x20205103, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI51TDE" , 0x20205104, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI51FDE" , 0x20205105, NUMICRO_BANKS_MINI51(4*1024)},
	{"MINI52LDE" , 0x20205200, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI52QDE" , 0x20205201, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI52   " , 0x20205202, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI52ZDE" , 0x20205203, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI52TDE" , 0x20205204, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI52FDE" , 0x20205205, NUMICRO_BANKS_MINI51(8*1024)},
	{"MINI54LDE" , 0x20205400, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI54QDE" , 0x20205401, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI54   " , 0x20205402, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI54ZDE" , 0x20205403, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI54TDE" , 0x20205404, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI54FDE" , 0x20205405, NUMICRO_BANKS_MINI51(16*1024)},
	{"MINI55LDE" , 0x20205500, NUMICRO_BANKS_MINI51(16*1024)},

	/* NANO100 */
	{"NANO100VF3AN" , 0x00110000, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO100VF2AN" , 0x00110001, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO100RF3AN" , 0x00110002, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO100RF2AN" , 0x00110003, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO100LF3AN" , 0x00110004, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO100LF2AN" , 0x00110005, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO100VE3AN" , 0x00110006, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO100VE2AN" , 0x00110007, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO100RE3AN" , 0x00110008, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO100RE2AN" , 0x00110009, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO100LE3AN" , 0x00110010, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO100LE2AN" , 0x00110011, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO100VD3AN" , 0x00110012, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100VD2AN" , 0x00110013, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100VD1AN" , 0x00110014, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100RD3AN" , 0x00110015, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100RD2AN" , 0x00110016, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100RD1AN" , 0x00110017, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100LD3AN" , 0x00110018, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100LD2AN" , 0x00110019, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100LD1AN" , 0x00110020, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100VC2AN" , 0x00110021, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO100VC1AN" , 0x00110022, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO100RC2AN" , 0x00110023, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO100RC1AN" , 0x00110024, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO100LC2AN" , 0x00110025, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO100LC1AN" , 0x00110026, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO100VB1AN" , 0x00110027, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO100VB0AN" , 0x00110028, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO100RB1AN" , 0x00110029, NUMICRO_BANKS_NANO(16*1024)},

	{"NANO110VF3AN" , 0x00111000, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO110VF2AN" , 0x00111001, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO110RF3AN" , 0x00111002, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO110RF2AN" , 0x00111003, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO110VE3AN" , 0x00111006, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO110VE2AN" , 0x00111007, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO110RE3AN" , 0x00111008, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO110RE2AN" , 0x00111009, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO110VD3AN" , 0x00111012, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO110VD2AN" , 0x00111013, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO110VD1AN" , 0x00111014, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO110RD3AN" , 0x00111015, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO110RD2AN" , 0x00111016, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO110RD1AN" , 0x00111017, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO110VC2AN" , 0x00111021, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO110VC1AN" , 0x00111022, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO110SC2AN" , 0x00111023, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO110SC1AN" , 0x00111024, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO120VF3AN" , 0x00112000, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO120VF2AN" , 0x00112001, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO120RF3AN" , 0x00112002, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO120RF2AN" , 0x00112003, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO120LF3AN" , 0x00112004, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO120LF2AN" , 0x00112005, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO120VE3AN" , 0x00112006, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO120VE2AN" , 0x00112007, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO120RE3AN" , 0x00112008, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO120RE2AN" , 0x00112009, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO120LE3AN" , 0x00112010, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO120LE2AN" , 0x00112011, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO120VD3AN" , 0x00112012, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120VD2AN" , 0x00112013, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120VD1AN" , 0x00112014, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120SD3AN" , 0x00112015, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120SD2AN" , 0x00112016, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120SD1AN" , 0x00112017, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120LD3AN" , 0x00112018, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120LD2AN" , 0x00112019, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120LD1AN" , 0x00112020, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120VC2AN" , 0x00112021, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO120VC1AN" , 0x00112022, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO120SC2AN" , 0x00112023, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO120SC1AN" , 0x00112024, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO120LC2AN" , 0x00112025, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO120LC1AN" , 0x00112026, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO130VF3AN" , 0x00113000, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO130VF2AN" , 0x00113001, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO130SF3AN" , 0x00113002, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO130SF2AN" , 0x00113003, NUMICRO_BANKS_NANO(256*1024)},
	{"NANO130VE3AN" , 0x00113006, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO130VE2AN" , 0x00113007, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO130SE3AN" , 0x00113008, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO130SE2AN" , 0x00113009, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO130VD3AN" , 0x00113012, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO130VD2AN" , 0x00113013, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO130VD1AN" , 0x00113014, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO130SD3AN" , 0x00113015, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO130SD2AN" , 0x00113016, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO130SD1AN" , 0x00113017, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO130VC2AN" , 0x00113021, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO130VC1AN" , 0x00113022, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO130SC2AN" , 0x00113023, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO130SC1AN" , 0x00113024, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO100KE3BN" , 0x00110030, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO100KE2BN" , 0x00110031, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO100VE3BN" , 0x00110032, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO100VE2BN" , 0x00110033, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO100SE3BN" , 0x00110034, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO100SE2BN" , 0x00110035, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO100LE3BN" , 0x00110036, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO100LE2BN" , 0x00110037, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO100KD3BN" , 0x00110038, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100KD2BN" , 0x00110039, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100VD3BN" , 0x0011003A, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100VD2BN" , 0x0011003B, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100SD3BN" , 0x0011003C, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100SD2BN" , 0x0011003D, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100LD3BN" , 0x0011003E, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100LD2BN" , 0x0011003F, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO100KC2BN" , 0x00110040, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO100VC2BN" , 0x00110041, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO100SC2BN" , 0x00110042, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO100LC2BN" , 0x00110043, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO110KE3BN" , 0x00111030, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO110KE2BN" , 0x00111031, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO110VE3BN" , 0x00111032, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO110VE2BN" , 0x00111033, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO110SE3BN" , 0x00111034, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO110SE2BN" , 0x00111035, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO110KD3BN" , 0x00111038, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO110KD2BN" , 0x00111039, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO110VD3BN" , 0x0011103A, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO110VD2BN" , 0x0011103B, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO110SD3BN" , 0x0011103C, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO110SD2BN" , 0x0011103D, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO110KC2BN" , 0x00111040, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO110VC2BN" , 0x00111041, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO110SC2BN" , 0x00111042, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO120KE3BN" , 0x00112030, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO120KE2BN" , 0x00112031, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO120VE3BN" , 0x00112032, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO120VE2BN" , 0x00112033, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO120SE3BN" , 0x00112034, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO120SE2BN" , 0x00112035, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO120LE3BN" , 0x00112036, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO120LE2BN" , 0x00112037, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO120KD3BN" , 0x00112038, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120KD2BN" , 0x00112039, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120VD3BN" , 0x0011203A, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120VD2BN" , 0x0011203B, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120SD3BN" , 0x0011203C, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120SD2BN" , 0x0011203D, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120LD3BN" , 0x0011203E, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120LD2BN" , 0x0011203F, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO120KC2BN" , 0x00112040, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO120VC2BN" , 0x00112041, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO120SC2BN" , 0x00112042, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO120LC2BN" , 0x00112043, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO130KE3BN" , 0x00113030, NUMICRO_BANKS_NANO(123*1024)},
	{"NANO130KE2BN" , 0x00113031, NUMICRO_BANKS_NANO(123*1024)},
	{"NANO130VE3BN" , 0x00113032, NUMICRO_BANKS_NANO(123*1024)},
	{"NANO130VE2BN" , 0x00113033, NUMICRO_BANKS_NANO(123*1024)},
	{"NANO130SE3BN" , 0x00113034, NUMICRO_BANKS_NANO(123*1024)},
	{"NANO130SE2BN" , 0x00113035, NUMICRO_BANKS_NANO(123*1024)},
	{"NANO130KD3BN" , 0x00113038, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO130KD2BN" , 0x00113039, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO130VD3BN" , 0x0011303A, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO130VD2BN" , 0x0011303B, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO130SD3BN" , 0x0011303C, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO130SD2BN" , 0x0011303D, NUMICRO_BANKS_NANO(64*1024)},
	{"NANO130KC2BN" , 0x00113040, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO130VC2BN" , 0x00113041, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO130SC2BN" , 0x00113042, NUMICRO_BANKS_NANO(32*1024)},
	{"N512DC4"      , 0x00100000, NUMICRO_BANKS_NANO(64*1024)},
	{"N512LC4"      , 0x00100001, NUMICRO_BANKS_NANO(64*1024)},
	{"N512MC4"      , 0x00100003, NUMICRO_BANKS_NANO(64*1024)},

	{"N512SC4"      , 0x00100005, NUMICRO_BANKS_NANO(64*1024)},
	{"N512VD4"      , 0x00100008, NUMICRO_BANKS_NANO(128*1024)},
	{"N512MD4"      , 0x00100009, NUMICRO_BANKS_NANO(128*1024)},
	{"N512SD4"      , 0x00100010, NUMICRO_BANKS_NANO(128*1024)},
	{"NANO110RC2BN" , 0x00111043, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO110RD3BN" , 0x00111045, NUMICRO_BANKS_NANO(64*1024)},
	{"TX110VE3BN"   , 0x00111036, NUMICRO_BANKS_NANO(128*1024)},

	/* NANO102/NANO112 */
	{"NANO112LB0AN" , 0x00111201, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO112LB1AN" , 0x00111202, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO112LC1AN" , 0x00111203, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO112LC2AN" , 0x00111204, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO112SB0AN" , 0x00111205, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO112SB1AN" , 0x00111206, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO112SC1AN" , 0x00111207, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO112SC2AN" , 0x00111208, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO112RB0AN" , 0x00111209, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO112RB1AN" , 0x00111210, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO112RC1AN" , 0x00111211, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO112RC2AN" , 0x00111212, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO112VB0AN" , 0x00111213, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO112VB1AN" , 0x00111214, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO112VC1AN" , 0x00111215, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO112VC2AN" , 0x00111216, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO102ZB0AN" , 0x00110201, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO102ZB1AN" , 0x00110202, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO102ZC1AN" , 0x00110203, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO102ZC2AN" , 0x00110204, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO102LB0AN" , 0x00110205, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO102LB1AN" , 0x00110206, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO102LC1AN" , 0x00110207, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO102LC2AN" , 0x00110208, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO102SB0AN" , 0x00110209, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO102SB1AN" , 0x00110210, NUMICRO_BANKS_NANO(16*1024)},
	{"NANO102SC1AN" , 0x00110211, NUMICRO_BANKS_NANO(32*1024)},
	{"NANO102SC2AN" , 0x00110212, NUMICRO_BANKS_NANO(32*1024)},

	/* NUC103/NUC105/NUC123 */
	{"NUC123SC2AN" , 0x00012305, NUMICRO_BANKS_NUC100(36*1024)},
	{"NUC123SD4AN" , 0x00012315, NUMICRO_BANKS_NUC100(68*1024)},
	{"NUC123LC2AN" , 0x00012325, NUMICRO_BANKS_NUC100(36*1024)},
	{"NUC103LC2AN" , 0x00010325, NUMICRO_BANKS_NUC100(36*1024)},
	{"NUC105LC2AN" , 0x00010525, NUMICRO_BANKS_NUC100(36*1024)},
	{"NUC123LD4AN" , 0x00012335, NUMICRO_BANKS_NUC100(68*1024)},
	{"NUC103LD4AN" , 0x00010335, NUMICRO_BANKS_NUC100(68*1024)},
	{"NUC105LD4AN" , 0x00010535, NUMICRO_BANKS_NUC100(68*1024)},
	{"NUC123ZC2AN" , 0x00012345, NUMICRO_BANKS_NUC100(36*1024)},
	{"NUC103ZC2AN" , 0x00010345, NUMICRO_BANKS_NUC100(36*1024)},
	{"NUC105ZC2AN" , 0x00010545, NUMICRO_BANKS_NUC100(36*1024)},
	{"NUC123ZD4AN" , 0x00012355, NUMICRO_BANKS_NUC100(68*1024)},
	{"NUC103ZD4AN" , 0x00010355, NUMICRO_BANKS_NUC100(68*1024)},
	{"NUC105ZD4AN" , 0x00010555, NUMICRO_BANKS_NUC100(68*1024)},

	/* NUC200 */
	{"NUC200LC2AN" , 0x00020007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC200LD2AN" , 0x00020004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC200LE3AN" , 0x00020000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC200SC1AN" , 0x00020035, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC200SD2AN" , 0x00020031, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC200SE3AN" , 0x00020027, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC200VE3AN" , 0x00020018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC220LC2AN" , 0x00022007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC220LD2AN" , 0x00022004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC220LE3AN" , 0x00022000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC220SC1AN" , 0x00022035, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC220SD2AN" , 0x00022031, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC220SE3AN" , 0x00022027, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC220VE3AN" , 0x00022018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC230LC2AN" , 0x00023007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC230LD2AN" , 0x00023004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC230LE3AN" , 0x00023000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC230SC1AN" , 0x00023035, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC230SD2AN" , 0x00023031, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC230SE3AN" , 0x00023027, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC230VE3AN" , 0x00023018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC240LC2AN" , 0x00024007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC240LD2AN" , 0x00024004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC240LE3AN" , 0x00024000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC240SC1AN" , 0x00024035, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC240SD2AN" , 0x00024031, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC240SE3AN" , 0x00024027, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC240VE3AN" , 0x00024018, NUMICRO_BANKS_NUC100(128*1024)},

	/* NUC200 NUC2XXAE */
	{"NUC230RC1AE" , 0x40013017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC200LC2AE" , 0x10020007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC200LD2AE" , 0x10020004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC200LE3AE" , 0x10020000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC200SC2AE" , 0x10020034, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC200SD2AE" , 0x10020031, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC200SE3AE" , 0x10020027, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC200VE3AE" , 0x10020018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC230LC2AE" , 0x10023007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC230LD2AE" , 0x10023004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC230LE3AE" , 0x10023000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC230SC2AE" , 0x10023034, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC230SD2AE" , 0x10023031, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC230SE3AE" , 0x10023027, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC230VE3AE" , 0x10023018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC240LC2AE" , 0x10024007, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC240LD2AE" , 0x10024004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC240LE3AE" , 0x10024000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC240SC2AE" , 0x10024034, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC240SD2AE" , 0x10024031, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC240SE3AE" , 0x10024027, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC240VE3AE" , 0x10024018, NUMICRO_BANKS_NUC100(128*1024)},

	/* NUC100 Version D */
	{"NUC100LC1DN" , 0x30010008, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100LD1DN" , 0x30010005, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100LD2DN" , 0x30010004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100RC1DN" , 0x30010017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC100RD1DN" , 0x30010014, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100RD2DN" , 0x30010013, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100LD3DN" , 0x30010003, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100LE3DN" , 0x30010000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100RD3DN" , 0x30010012, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100RE3DN" , 0x30010009, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC100VD2DN" , 0x30010022, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100VD3DN" , 0x30010021, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC100VE3DN" , 0x30010018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120LC1DN" , 0x30012008, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120LD1DN" , 0x30012005, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120LD2DN" , 0x30012004, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120RC1DN" , 0x30012017, NUMICRO_BANKS_NUC100(32*1024)},
	{"NUC120RD1DN" , 0x30012014, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120RD2DN" , 0x30012013, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120LD3DN" , 0x30012003, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120LE3DN" , 0x30012000, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120RD3DN" , 0x30012012, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120RE3DN" , 0x30012009, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC120VD2DN" , 0x30012022, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120VD3DN" , 0x30012021, NUMICRO_BANKS_NUC100(64*1024)},
	{"NUC120VE3DN" , 0x30012018, NUMICRO_BANKS_NUC100(128*1024)},
	{"NUC130RC1DN" , 0x30013017, NUMICRO_BANKS_NUC100(32*1024)},

	{"UNKNOWN"     , 0x00000000, NUMICRO_BANKS_NUC100(128*1024)},
};

/* Private bank information for NuMicro. */
struct  numicro_flash_bank {
	struct working_area *write_algorithm;
	int probed;
	const struct numicro_cpu_type *cpu;
};

/* Private methods */
static int numicro_reg_unlock(struct target *target)
{
	uint32_t is_protected;
	int retval = ERROR_OK;

	/* Check to see if NUC is register unlocked or not */
	retval = target_read_u32(target, NUMICRO_SYS_WRPROT, &is_protected);
	if (retval != ERROR_OK)
		return retval;

	LOG_DEBUG("protected = 0x%08" PRIx32 "", is_protected);
	if (is_protected == 0) {	/* means protected - so unlock it */
		/* unlock flash registers */
		retval = target_write_u32(target, NUMICRO_SYS_WRPROT, REG_KEY1);
		if (retval != ERROR_OK)
			return retval;
		retval = target_write_u32(target, NUMICRO_SYS_WRPROT, REG_KEY2);
		if (retval != ERROR_OK)
			return retval;
		retval = target_write_u32(target, NUMICRO_SYS_WRPROT, REG_KEY3);
		if (retval != ERROR_OK)
			return retval;
	}
	/* Check that unlock worked */
	retval = target_read_u32(target, NUMICRO_SYS_WRPROT, &is_protected);
	if (retval != ERROR_OK)
		return retval;

	if (is_protected == 1) {	/* means unprotected */
		LOG_DEBUG("protection removed");
	} else {
		LOG_DEBUG("still protected!!");
	}

	return ERROR_OK;
}

static int numicro_init_isp(struct target *target)
{
	uint32_t reg_stat;
	int retval = ERROR_OK;

	if (target->state != TARGET_HALTED) {
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	retval = numicro_reg_unlock(target);
	if (retval != ERROR_OK)
		return retval;

	/* Enable ISP/SRAM/TICK Clock */
	retval = target_read_u32(target, NUMICRO_SYSCLK_AHBCLK, &reg_stat);
	if (retval != ERROR_OK)
		return retval;

	reg_stat |= AHBCLK_ISP_EN | AHBCLK_SRAM_EN | AHBCLK_TICK_EN;
	retval = target_write_u32(target, NUMICRO_SYSCLK_AHBCLK, reg_stat);
	if (retval != ERROR_OK)
		return retval;

	/* Enable ISP */
	retval = target_read_u32(target, NUMICRO_FLASH_ISPCON, &reg_stat);
	if (retval != ERROR_OK)
		return retval;

	reg_stat |= ISPCON_ISPFF | ISPCON_LDUEN | ISPCON_APUEN | ISPCON_CFGUEN | ISPCON_ISPEN;
	retval = target_write_u32(target, NUMICRO_FLASH_ISPCON, reg_stat);
	if (retval != ERROR_OK)
		return retval;

	/* Write one to undocumented flash control register */
	retval = target_write_u32(target, NUMICRO_FLASH_CHEAT, 1);
	if (retval != ERROR_OK)
		return retval;

	return ERROR_OK;
}

static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t addr, uint32_t wdata, uint32_t *rdata)
{
	uint32_t timeout, status;
	int retval = ERROR_OK;

	retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD, cmd);
	if (retval != ERROR_OK)
		return retval;

	retval = target_write_u32(target, NUMICRO_FLASH_ISPDAT, wdata);
	if (retval != ERROR_OK)
		return retval;

	retval = target_write_u32(target, NUMICRO_FLASH_ISPADR, addr);
	if (retval != ERROR_OK)
		return retval;

	retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG, ISPTRG_ISPGO);
	if (retval != ERROR_OK)
		return retval;

	/* Wait for busy to clear - check the GO flag */
	timeout = 100;
	for (;;) {
		retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status);
		if (retval != ERROR_OK)
			return retval;
			LOG_DEBUG("status: 0x%" PRIx32 "", status);
		if ((status & (ISPTRG_ISPGO)) == 0)
			break;
		if (timeout-- <= 0) {
			LOG_DEBUG("timed out waiting for flash");
			return ERROR_FAIL;
		}
		busy_sleep(1);	/* can use busy sleep for short times. */
	}

	retval = target_read_u32(target, NUMICRO_FLASH_ISPDAT, rdata);
	if (retval != ERROR_OK)
		return retval;

	return ERROR_OK;
}


/* NuMicro Program-LongWord Microcodes */
static const uint8_t numicro_flash_write_code[] = {
				/* Params:
				 * r0 - workarea buffer / result
				 * r1 - target address
				 * r2 - wordcount
				 * Clobbered:
				 * r4 - tmp
				 * r5 - tmp
				 * r6 - tmp
				 * r7 - tmp
				 */

				/* .L1: */
						/* for(register uint32_t i=0;i<wcount;i++){ */
	0x04, 0x1C,				/* mov    r4, r0          */
	0x00, 0x23,				/* mov    r3, #0          */
				/* .L2: */
	0x0D, 0x1A,				/* sub    r5, r1, r0      */
	0x67, 0x19,				/* add    r7, r4, r7      */
	0x93, 0x42,				/* cmp	  r3, r2		  */
	0x0C, 0xD0,				/* beq    .L7             */
				/* .L4: */
						/* NUMICRO_FLASH_ISPADR = faddr; */
	0x08, 0x4E,				/* ldr	r6, .L8           */
	0x37, 0x60,				/* str	r7, [r6]          */
						/* NUMICRO_FLASH_ISPDAT = *pLW; */
	0x80, 0xCC,				/* ldmia	r4!, {r7}     */
	0x08, 0x4D,				/* ldr	r5, .L8+4         */
	0x2F, 0x60,				/* str	r7, [r5]		  */
							/* faddr += 4; */
							/* pLW++; */
							/*  Trigger write action  */
						/* NUMICRO_FLASH_ISPTRG = ISPTRG_ISPGO; */
	0x08, 0x4D,				/* ldr	r5, .L8+8         */
	0x01, 0x26,				/* mov	r6, #1            */
	0x2E, 0x60,				/* str	r6, [r5]          */
				/* .L3: */
						/* while((NUMICRO_FLASH_ISPTRG & ISPTRG_ISPGO) == ISPTRG_ISPGO){}; */
	0x2F, 0x68,				/* ldr	r7, [r5]          */
	0xFF, 0x07,				/* lsl	r7, r7, #31       */
	0xFC, 0xD4,				/* bmi	.L3               */

	0x01, 0x33,				/* add	r3, r3, #1        */
	0xEE, 0xE7,				/* b	.L2               */
				/* .L7: */
						/* return (NUMICRO_FLASH_ISPCON & ISPCON_ISPFF); */
	0x05, 0x4B,				/* ldr	r3, .L8+12        */
	0x18, 0x68,				/* ldr	r0, [r3]          */
	0x40, 0x21,				/* mov	r1, #64           */
	0x08, 0x40,				/* and	r0, r1            */
				/* .L9: */
	0x00, 0xBE,				/* bkpt    #0             */
				/* .L8: */
	0x04, 0xC0, 0x00, 0x50,/* .word	1342226436    */
	0x08, 0xC0, 0x00, 0x50,/* .word	1342226440    */
	0x10, 0xC0, 0x00, 0x50,/* .word	1342226448    */
	0x00, 0xC0, 0x00, 0x50 /* .word	1342226432    */
};
/* Program LongWord Block Write */
static int numicro_writeblock(struct flash_bank *bank, const uint8_t *buffer,
		uint32_t offset, uint32_t count)
{
	struct target *target = bank->target;
	uint32_t buffer_size = 1024;		/* Default minimum value */
	struct working_area *write_algorithm;
	struct working_area *source;
	uint32_t address = bank->base + offset;
	struct reg_param reg_params[3];
	struct armv7m_algorithm armv7m_info;
	int retval = ERROR_OK;

	/* Params:
	 * r0 - workarea buffer / result
	 * r1 - target address
	 * r2 - wordcount
	 * Clobbered:
	 * r4 - tmp
	 * r5 - tmp
	 * r6 - tmp
	 * r7 - tmp
	 */

	/* Increase buffer_size if needed */
	if (buffer_size < (target->working_area_size/2))
		buffer_size = (target->working_area_size/2);

	/* check code alignment */
	if (offset & 0x1) {
		LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
	}

	/* allocate working area with flash programming code */
	if (target_alloc_working_area(target, sizeof(numicro_flash_write_code),
			&write_algorithm) != ERROR_OK) {
		LOG_WARNING("no working area available, can't do block memory writes");
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}

	retval = target_write_buffer(target, write_algorithm->address,
		sizeof(numicro_flash_write_code), numicro_flash_write_code);
	if (retval != ERROR_OK)
		return retval;

	/* memory buffer */
	while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
		buffer_size /= 4;
		if (buffer_size <= 256) {
			/* free working area, write algorithm already allocated */
			target_free_working_area(target, write_algorithm);

			LOG_WARNING("No large enough working area available, can't do block memory writes");
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
	}

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARM_MODE_THREAD;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* *pLW (*buffer) */
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);    /* faddr */
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);    /* number of words to program */

	struct armv7m_common *armv7m = target_to_armv7m(target);
	if (armv7m == NULL) {
		/* something is very wrong if armv7m is NULL */
		LOG_ERROR("unable to get armv7m target");
		return retval;
	}

	/* write code buffer and use Flash programming code within NuMicro     */
	/* Set breakpoint to 0 with time-out of 1000 ms                        */
	while (count > 0) {
		uint32_t thisrun_count = (count > (buffer_size / 4)) ? (buffer_size / 4) : count;

		retval = target_write_buffer(target, source->address, thisrun_count * 4, buffer);
		if (retval != ERROR_OK)
			break;

		buf_set_u32(reg_params[0].value, 0, 32, source->address);
		buf_set_u32(reg_params[1].value, 0, 32, address);
		buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);

		retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
				write_algorithm->address, 0, 100000, &armv7m_info);
		if (retval != ERROR_OK) {
			LOG_ERROR("Error executing NuMicro Flash programming algorithm");
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}

		buffer  += thisrun_count * 4;
		address += thisrun_count * 4;
		count   -= thisrun_count;
	}

	target_free_working_area(target, source);
	target_free_working_area(target, write_algorithm);

	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);

	return retval;
}

/* Flash Lock checking - examines the lock bit. */
static int numicro_protect_check(struct flash_bank *bank)
{
	struct target *target = bank->target;
	uint32_t set, config[2];
	int retval = ERROR_OK;

	if (target->state != TARGET_HALTED) {
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	LOG_INFO("Nuvoton NuMicro: Flash Lock Check...");

	retval = numicro_init_isp(target);
	if (retval != ERROR_OK)
		return retval;

	/* Read CONFIG0,CONFIG1 */
	numicro_fmc_cmd(target, ISPCMD_READ, NUMICRO_CONFIG0, 0 , &config[0]);
	numicro_fmc_cmd(target, ISPCMD_READ, NUMICRO_CONFIG1, 0 , &config[1]);

	LOG_DEBUG("CONFIG0: 0x%" PRIx32 ",CONFIG1: 0x%" PRIx32 "", config[0], config[1]);

	if ((config[0] & (1<<7)) == 0)
		LOG_INFO("CBS=0: Boot From LPROM");
	else
		LOG_INFO("CBS=1: Boot From APROM");

	if ((config[0] & CONFIG0_LOCK_MASK) == 0) {

		LOG_INFO("Flash is secure locked!");
		LOG_INFO("TO UNLOCK FLASH,EXECUTE chip_erase COMMAND!!");
		set = 1;
	} else {
		LOG_INFO("Flash is not locked!");
	    set = 0;
	}

	for (unsigned int i = 0; i < bank->num_sectors; i++)
		bank->sectors[i].is_protected = set;

	return ERROR_OK;
}


static int numicro_erase(struct flash_bank *bank, unsigned int first,
		unsigned int last)
{
	struct target *target = bank->target;
	uint32_t timeout, status;
	int retval = ERROR_OK;

	if (target->state != TARGET_HALTED) {
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	LOG_INFO("Nuvoton NuMicro: Sector Erase ... (%u to %u)", first, last);

	retval = numicro_init_isp(target);
	if (retval != ERROR_OK)
		return retval;

	retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD, ISPCMD_ERASE);
	if (retval != ERROR_OK)
		return retval;

	for (unsigned int i = first; i <= last; i++) {
		LOG_DEBUG("erasing sector %u at address " TARGET_ADDR_FMT, i,
				bank->base + bank->sectors[i].offset);
		retval = target_write_u32(target, NUMICRO_FLASH_ISPADR, bank->base + bank->sectors[i].offset);
		if (retval != ERROR_OK)
			return retval;
		retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG, ISPTRG_ISPGO); /* This is the only bit available */
		if (retval != ERROR_OK)
			return retval;

		/* wait for busy to clear - check the GO flag */
		timeout = 100;
		for (;;) {
			retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status);
			if (retval != ERROR_OK)
				return retval;
				LOG_DEBUG("status: 0x%" PRIx32 "", status);
			if (status == 0)
				break;
			if (timeout-- <= 0) {
				LOG_DEBUG("timed out waiting for flash");
				return ERROR_FAIL;
			}
			busy_sleep(1);	/* can use busy sleep for short times. */
		}

		/* check for failure */
		retval = target_read_u32(target, NUMICRO_FLASH_ISPCON, &status);
		if (retval != ERROR_OK)
			return retval;
		if ((status & ISPCON_ISPFF) != 0) {
			LOG_DEBUG("failure: 0x%" PRIx32 "", status);
			/* if bit is set, then must write to it to clear it. */
			retval = target_write_u32(target, NUMICRO_FLASH_ISPCON, (status | ISPCON_ISPFF));
			if (retval != ERROR_OK)
				return retval;
		} else {
			bank->sectors[i].is_erased = 1;
		}
	}

	/* done, */
	LOG_DEBUG("Erase done.");

	return ERROR_OK;
}

/* The write routine stub. */
static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
		uint32_t offset, uint32_t count)
{
	struct target *target = bank->target;
	uint32_t timeout, status;
	int retval = ERROR_OK;

	if (target->state != TARGET_HALTED) {
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	LOG_INFO("Nuvoton NuMicro: Flash Write ...");

	retval = numicro_init_isp(target);
	if (retval != ERROR_OK)
		return retval;

	retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD, ISPCMD_WRITE);
	if (retval != ERROR_OK)
		return retval;

	assert(offset % 4 == 0);
	assert(count % 4 == 0);

	uint32_t words_remaining = count / 4;

	/* try using a block write */
	retval = numicro_writeblock(bank, buffer, offset, words_remaining);

	if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
		/* if block write failed (no sufficient working area),
		 * we use normal (slow) single word accesses */
		LOG_WARNING("couldn't use block writes, falling back to single "
			"memory accesses");

		/* program command */
		for (uint32_t i = 0; i < count; i += 4) {

			LOG_DEBUG("write longword @ %08" PRIX32, offset + i);

			retval = target_write_u32(target, NUMICRO_FLASH_ISPADR, bank->base + offset + i);
			if (retval != ERROR_OK)
				return retval;
			retval = target_write_memory(target, NUMICRO_FLASH_ISPDAT, 4, 1, buffer + i);
			if (retval != ERROR_OK)
				return retval;
			retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG, ISPTRG_ISPGO);
			if (retval != ERROR_OK)
				return retval;

			/* wait for busy to clear - check the GO flag */
			timeout = 100;
			for (;;) {
				retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status);
				if (retval != ERROR_OK)
					return retval;
					LOG_DEBUG("status: 0x%" PRIx32 "", status);
				if (status == 0)
					break;
				if (timeout-- <= 0) {
					LOG_DEBUG("timed out waiting for flash");
					return ERROR_FAIL;
				}
				busy_sleep(1);	/* can use busy sleep for short times. */
			}

		}
	}

	/* check for failure */
	retval = target_read_u32(target, NUMICRO_FLASH_ISPCON, &status);
	if (retval != ERROR_OK)
		return retval;
	if ((status & ISPCON_ISPFF) != 0) {
		LOG_DEBUG("failure: 0x%" PRIx32 "", status);
		/* if bit is set, then must write to it to clear it. */
		retval = target_write_u32(target, NUMICRO_FLASH_ISPCON, (status | ISPCON_ISPFF));
		if (retval != ERROR_OK)
			return retval;
	} else {
		LOG_DEBUG("Write OK");
	}

	/* done. */
	LOG_DEBUG("Write done.");

	return ERROR_OK;
}

static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_type **cpu)
{
	uint32_t part_id;
	int retval = ERROR_OK;

	/* Read NuMicro PartID */
	retval = target_read_u32(target, NUMICRO_SYS_BASE, &part_id);
	if (retval != ERROR_OK) {
		LOG_WARNING("NuMicro flash driver: Failed to Get PartID\n");
		return ERROR_FLASH_OPERATION_FAILED;
	}

	LOG_INFO("Device ID: 0x%08" PRIx32 "", part_id);
	/* search part numbers */
	for (size_t i = 0; i < ARRAY_SIZE(NuMicroParts); i++) {
		if (part_id == NuMicroParts[i].partid) {
			*cpu = &NuMicroParts[i];
			LOG_INFO("Device Name: %s", (*cpu)->partname);
			return ERROR_OK;
		}
	}

	return ERROR_FAIL;
}

static int numicro_get_flash_size(struct flash_bank *bank, const struct numicro_cpu_type *cpu, uint32_t *flash_size)
{
	for (size_t i = 0; i < cpu->n_banks; i++) {
		if (bank->base == cpu->bank[i].base) {
			*flash_size = cpu->bank[i].size;
			LOG_INFO("bank base = " TARGET_ADDR_FMT ", size = 0x%08"
					PRIx32, bank->base, *flash_size);
			return ERROR_OK;
		}
	}
	return ERROR_FLASH_OPERATION_FAILED;
}

static int numicro_probe(struct flash_bank *bank)
{
	uint32_t flash_size, offset = 0;
	int num_pages;
	const struct numicro_cpu_type *cpu;
	struct target *target = bank->target;
	int retval = ERROR_OK;

	retval = numicro_get_cpu_type(target, &cpu);
	if (retval != ERROR_OK) {
		LOG_WARNING("NuMicro flash driver: Failed to detect a known part\n");
		return ERROR_FLASH_OPERATION_FAILED;
	}

	retval = numicro_get_flash_size(bank, cpu, &flash_size);
	if (retval != ERROR_OK) {
		LOG_WARNING("NuMicro flash driver: Failed to detect flash size\n");
		return ERROR_FLASH_OPERATION_FAILED;
	}

	num_pages = flash_size / NUMICRO_PAGESIZE;

	bank->num_sectors = num_pages;
	bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
	bank->size = flash_size;

	for (int i = 0; i < num_pages; i++) {
		bank->sectors[i].offset = offset;
		bank->sectors[i].size = NUMICRO_PAGESIZE;
		bank->sectors[i].is_erased = -1;
		bank->sectors[i].is_protected = 0;
		offset += NUMICRO_PAGESIZE;
	}

	struct numicro_flash_bank *numicro_info = bank->driver_priv;
	numicro_info->probed = true;
	numicro_info->cpu = cpu;
	LOG_DEBUG("Nuvoton NuMicro: Probed ...");

	return ERROR_OK;
}

/* Standard approach to autoprobing. */
static int numicro_auto_probe(struct flash_bank *bank)
{
	struct numicro_flash_bank *numicro_info = bank->driver_priv;
	if (numicro_info->probed)
		return ERROR_OK;
	return numicro_probe(bank);
}


/* This is the function called in the config file. */
FLASH_BANK_COMMAND_HANDLER(numicro_flash_bank_command)
{
	struct numicro_flash_bank *bank_info;

	if (CMD_ARGC < 6)
		return ERROR_COMMAND_SYNTAX_ERROR;

	LOG_DEBUG("add flash_bank numicro %s", bank->name);

	bank_info = malloc(sizeof(struct numicro_flash_bank));

	memset(bank_info, 0, sizeof(struct numicro_flash_bank));

	bank->driver_priv = bank_info;
	bank->write_start_alignment = bank->write_end_alignment = 4;

	return ERROR_OK;

}

COMMAND_HANDLER(numicro_handle_read_isp_command)
{
	uint32_t address;
	uint32_t ispdat;
	int retval = ERROR_OK;

	if (CMD_ARGC != 1)
		return ERROR_COMMAND_SYNTAX_ERROR;

	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);

	struct target *target = get_current_target(CMD_CTX);

	retval = numicro_init_isp(target);
	if (retval != ERROR_OK)
		return retval;

	retval = numicro_fmc_cmd(target, ISPCMD_READ, address, 0, &ispdat);
	if (retval != ERROR_OK)
		return retval;

	LOG_INFO("0x%08" PRIx32 ": 0x%08" PRIx32, address, ispdat);

	return ERROR_OK;
}

COMMAND_HANDLER(numicro_handle_write_isp_command)
{
	uint32_t address;
	uint32_t ispdat, rdat;
	int retval = ERROR_OK;

	if (CMD_ARGC != 2)
		return ERROR_COMMAND_SYNTAX_ERROR;

	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], ispdat);

	struct target *target = get_current_target(CMD_CTX);

	retval = numicro_init_isp(target);
	if (retval != ERROR_OK)
		return retval;

	retval = numicro_fmc_cmd(target, ISPCMD_WRITE, address, ispdat, &rdat);
	if (retval != ERROR_OK)
		return retval;

	LOG_INFO("0x%08" PRIx32 ": 0x%08" PRIx32, address, ispdat);
	return ERROR_OK;
}

COMMAND_HANDLER(numicro_handle_chip_erase_command)
{
	int retval = ERROR_OK;
	uint32_t rdat;

	if (CMD_ARGC != 0)
		return ERROR_COMMAND_SYNTAX_ERROR;

	struct target *target = get_current_target(CMD_CTX);

	retval = numicro_init_isp(target);
	if (retval != ERROR_OK)
		return retval;

	retval = numicro_fmc_cmd(target, ISPCMD_CHIPERASE, 0, 0, &rdat);
	if (retval != ERROR_OK) {
		command_print(CMD, "numicro chip_erase failed");
		return retval;
	}

	command_print(CMD, "numicro chip_erase complete");

	return ERROR_OK;
}

static const struct command_registration numicro_exec_command_handlers[] = {
	{
		.name = "read_isp",
		.handler = numicro_handle_read_isp_command,
		.usage = "address",
		.mode = COMMAND_EXEC,
		.help = "read flash through ISP.",
	},
	{
		.name = "write_isp",
		.handler = numicro_handle_write_isp_command,
		.usage = "address value",
		.mode = COMMAND_EXEC,
		.help = "write flash through ISP.",
	},
	{
		.name = "chip_erase",
		.handler = numicro_handle_chip_erase_command,
		.mode = COMMAND_EXEC,
		.help = "chip erase through ISP.",
		.usage = "",
	},
	COMMAND_REGISTRATION_DONE
};

static const struct command_registration numicro_command_handlers[] = {
	{
		.name = "numicro",
		.mode = COMMAND_ANY,
		.help = "numicro flash command group",
		.usage = "",
		.chain = numicro_exec_command_handlers,
	},
	COMMAND_REGISTRATION_DONE
};

const struct flash_driver numicro_flash = {
	.name = "numicro",
	.commands = numicro_command_handlers,
	.flash_bank_command = numicro_flash_bank_command,
	.erase = numicro_erase,
	.write = numicro_write,
	.read = default_flash_read,
	.probe = numicro_probe,
	.auto_probe = numicro_auto_probe,
	.erase_check = default_flash_blank_check,
	.protect_check = numicro_protect_check,
	.free_driver_priv = default_flash_free_driver_priv,
};
