/******************************************************************************
  Target Script for STM32

  Copyright (c) 2008, 2010, 2011, 2012 Rowley Associates Limited.

  This file may be distributed under the terms of the License Agreement
  provided with this software.

  THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE
  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 ******************************************************************************/

function EnableTrace(TraceInterfaceType)
{
  if (TraceInterfaceType == "TracePort")
    {        
      // F2xx/F4xx
      switch (TargetInterface.peekWord(0xE0042000) & 0xfff)
        { 
          case 0x412: // STM32F1 low density
          case 0x410: // medium density
          case 0x414: // high density
          case 0x430: // xl density
          case 0x418: // connectivity
            TargetInterface.pokeWord(0x40021018, TargetInterface.peekWord(0x40021018) | (1<<6)); // RCC_APB2ENR:   IO port E clock enable
            TargetInterface.pokeWord(0x48011800, 0x00002AA0);                       // GPIOE_MODER:   PE2..PE6 = Alternate function mode
            TargetInterface.pokeWord(0x48011808, 0x00001550);                       // GPIOx_OSPEEDR: PE2..PE6 = 25 MHz Medium speed
            TargetInterface.pokeWord(0x4801180C, 0x00001550);                       // GPIOx_PUPDR:   PE2..PE6 = Pull-up
            TargetInterface.pokeWord(0x48011820, 0x00000000);                       // GPIOx_AFRL:    PE2..PE6 = AF0
            break;
          case 0x411: // STM32F2xx
          case 0x413: // STM32F40x/STM32F41x
          case 0x419: // STM32F42x/STM32F43x
          case 0x434: // STM32F469/STM32F479
            TargetInterface.pokeWord(0x40023830, TargetInterface.peekWord(0x40023830) | (1<<4)); // RCC_AHB1ENR:   IO port E clock enable
            TargetInterface.pokeWord(0x40021000, 0x00002AA0);                       // GPIOE_MODER:   PE2..PE6 = Alternate function mode
            TargetInterface.pokeWord(0x40021008, 0x00001550);                       // GPIOx_OSPEEDR: PE2..PE6 = 25 MHz Medium speed
            TargetInterface.pokeWord(0x4002100C, 0x00001550);                       // GPIOx_PUPDR:   PE2..PE6 = Pull-up
            TargetInterface.pokeWord(0x40021020, 0x00000000);                       // GPIOx_AFRL:    PE2..PE6 = AF0
            break;
          case 0x422: // STM32F30x         
          case 0x432: // STM32F37x
          case 0x438: // STM32F334/F303/F328
          case 0x439: // STM32F30x
          case 0x446:
            TargetInterface.pokeWord(0x40021014, TargetInterface.peekWord(0x40021014) | (1<<21)); // RCC_AHBENR:   IO port E clock enable
            TargetInterface.pokeWord(0x48001000, 0x00002AA0);                       // GPIOE_MODER:   PE2..PE6 = Alternate function mode
            TargetInterface.pokeWord(0x48001008, 0x00001550);                       // GPIOx_OSPEEDR: PE2..PE6 = 25 MHz Medium speed
            TargetInterface.pokeWord(0x4800100C, 0x00001550);                       // GPIOx_PUPDR:   PE2..PE6 = Pull-up
            TargetInterface.pokeWord(0x48001020, 0x00000000);                       // GPIOx_AFRL:    PE2..PE6 = AF0
            break;
          case 0x416: // STM32L
          case 0x427: // medium+
          case 0x429:
          case 0x436: // high density STM32L
          case 0x437: // STM32L152E
            TargetInterface.pokeWord(0x4002381C, TargetInterface.peekWord(0x4002381C) | (1<<4)); // RCC_AHBENR:   IO port E clock enable
            TargetInterface.pokeWord(0x40021000, 0x00002AA0);                       // GPIOE_MODER:   PE2..PE6 = Alternate function mode
            TargetInterface.pokeWord(0x40021008, 0x00001550);                       // GPIOx_OSPEEDR: PE2..PE6 = 25 MHz Medium speed
            TargetInterface.pokeWord(0x4002100C, 0x00001550);                       // GPIOx_PUPDR:   PE2..PE6 = Pull-up
            TargetInterface.pokeWord(0x40021020, 0x00000000);                       // GPIOx_AFRL:    PE2..PE6 = AF0
            break;
        }
      TargetInterface.pokeWord(0xE0042004, TargetInterface.peekWord(0xE0042004) | 0x000000E0); // DBG_MCU_CR : assign SYNC TRACE I/Os for SIZE=4
    }
  else if (TraceInterfaceType == "SWO")
    TargetInterface.pokeWord(0xE0042004, TargetInterface.peekWord(0xE0042004) | 0x00000020); // DBG_MCU_CR : TRACE_IOEN
}

function Reset()
{   
  TargetInterface.pokeWord(0xE000EDF0, 0xA05F0003); // set C_HALT and C_DEBUGEN in DHCSR      
  TargetInterface.waitForDebugState(1000);
  var CPUID = TargetInterface.peekWord(0xE000ED00);
  if (((CPUID>>4)&0xf)==0) // Cortex-M0
    {
      TargetInterface.pokeWord(0xE000EDFC, 0x1); // set VC_CORERESET in DEMCR
      TargetInterface.pokeWord(0xE000ED0C, 0x05FA0004); // set SYSRESETREQ in AIRCR
      TargetInterface.waitForDebugState(1000);
      switch ((TargetInterface.peekWord(0x40015800) & 0xfff))
        {
          case 0x457: // STM32L0x1 - category 1
          case 0x425: // STM32L0x1 - category 2
          case 0x417: // STM32L0x1/STM32L0x2/STM32L0x3 - category 3
          case 0x447: // STM32L0x1/STM32L0x2/STM32L0x3 - category 5
            TargetInterface.pokeWord(0x40021034, 1<<22); // DBG_EN
            break;
          default:
            TargetInterface.pokeWord(0x40021018, 1<<22); // DBG_EN
            break;
        }
      TargetInterface.pokeWord(0x40015804, 1<<2|1<<1|1<<0); // enable low-power mode debugging
      TargetInterface.pokeWord(0x40015808, 1<<12|1<<11); // turn off WWDG and IWDG in debug mode
    }
  else if (((CPUID>>4)&0xfff)==0xD21) // Cortex-M33
    {
      var DBGMCU_IDCODE = TargetInterface.peekWord(0xE0044000);
      TargetInterface.pokeWord(0xE000EDFC, 0x1); // set VC_CORERESET in DEMCR
      TargetInterface.pokeWord(0xE000ED0C, 0x05FA0004); // set SYSRESETREQ in AIRCR 
      TargetInterface.waitForDebugState(1000);
      switch (DBGMCU_IDCODE & 0xfff)
        {
          case 0x472: // STM32L5
          case 0x482: // STM32U5
            TargetInterface.pokeWord(0xE0044004, 1<<2|1<<1); // enable low-power mode debugging
            TargetInterface.pokeWord(0xE0044008, 1<<12|1<<11); // turn off WWDG and IWDG in debug mode
            break;
          default:
            break;
        }
    }
  else
    {
      var DBGMCU_IDCODE = TargetInterface.peekWord(0xE0042000);
      TargetInterface.pokeWord(0xE000EDFC, 0x1); // set VC_CORERESET in DEMCR
      switch (DBGMCU_IDCODE & 0xffff0fff)
        {           
          case 0x00000410: // STM32F10xx8/STM32F10xxB Revision A devices
          case 0x10010414: // STM32F10xxE Revision Z
          case 0x20000410: // Some STM32F10xx8/STM32F10xxB Revision B devices are affected
            TargetInterface.pokeWord(0xE000ED0C, 0x05FA0001); // set VECTRESET in AIRCR  
            break;
          default:
            TargetInterface.pokeWord(0xE000ED0C, 0x05FA0004); // set SYSRESETREQ in AIRCR 
            break;
        }
      TargetInterface.waitForDebugState(1000);  
      switch (DBGMCU_IDCODE & 0xfff)
        {
          case 0x0: // STM32W108
            break;
          case 0x411: // STM32F2xx
          case 0x413: // STM32F40x/STM32F41x
          case 0x415: // STM32L4x1/STM32L4x5/STM32L4x6
          case 0x416: // STM32L
          case 0x419: // STM32F42x/STM32F43x
          case 0x421: // STM32F446xx
          case 0x422: // STM32F30x
          case 0x423: // STM32F401x
          case 0x431: // STM32F411xE
          case 0x429: // STM32L
          case 0x432: // STM32F37x
          case 0x433: // STM32F401x
          case 0x434: // STM32F469/STM32F479
          case 0x435: // STM32L4x2/STM32L4x3
          case 0x438: // STM32F334
          case 0x436: // STM32L
          case 0x439: // STM32F30x
          case 0x441: // STM32F412
          case 0x446: // STM32F303
          case 0x449: // STM32F75x/STM32F74x
          case 0x451: // STM32F76x/STM32F77x
          case 0x452: // STM32F72x/STM32F73x
          case 0x458: // STM32F410x
          case 0x461: // STM32L496/STM32L9A6
          case 0x462: // STM32L451/STM32L452/STM32L462
          case 0x463: // STM32F413
          case 0x464: // STM32L412/STM32L422
          case 0x468: // STM32G4
          case 0x469: // STM32G4
          case 0x470: // STM32L4R/STM32L4S
          case 0x471: // STM32L4P5/STM32L4Q5
          case 0x479: // STM32G4
            TargetInterface.pokeWord(0xE0042004, 1<<2|1<<1|1<<0); // enable low-power mode debugging
            TargetInterface.pokeWord(0xE0042008, 1<<12|1<<11); // turn off WWDG and IWDG in debug mode
            break;
          case 0x495: // STM32WB55xx/STM32WB35xx
            TargetInterface.pokeWord(0xE0042004, 1<<2|1<<1|1<<0); // enable low-power mode debugging
            TargetInterface.pokeWord(0xE004203C, 1<<12|1<<11); // turn off WWDG and IWDG in debug mode
            break;
          case 0x497: // STM32WL5x/STM32WLEx
            TargetInterface.pokeWord(0xE0042004, 1<<2|1<<1|1<<0); // enable low-power mode debugging
            TargetInterface.pokeWord(0xE004203C, 1<<12|1<<11); // turn off WWDG and IWDG in debug mode
            break;
          default:
            switch ((TargetInterface.peekWord(0x5C001000) & 0xfff))
              {
                case 0x450:
                case 0x480:
                  TargetInterface.pokeWord(0x5C001004, 1<<2|1<<1|1<<0); // enable low-power mode debugging
                  TargetInterface.pokeWord(0x5C001034, 1<<6); // turn off WWDG1 in debug mode
                  break;
                default:
                  TargetInterface.pokeWord(0xE0042004, 1<<8|1<<9|1<<2|1<<1|1<<0); // turn off WWDG and IWDG in debug mode and enable low-power mode debugging
                  break;
              }
        }
    }  
}

function SRAMReset()
{
  if (TargetInterface.implementation() == "j-link" || TargetInterface.implementation() == "crossworks_simulator")
    TargetInterface.resetAndStop(100);
  else
    Reset();
}

function FLASHReset()
{
  if (TargetInterface.implementation() == "j-link" || TargetInterface.implementation() == "crossworks_simulator")
    TargetInterface.resetAndStop(100);
  else
    Reset();
}

function GetPartName()
{
  var CPUID = TargetInterface.peekWord(0xE000ED00);
  if (((CPUID>>4)&0xf)==0) // Cortex-M0
    switch ((TargetInterface.peekWord(0x40015800) & 0xfff))
      {
        case 0x457:
        case 0x425:
        case 0x417:
        case 0x447:
          return "STM32L0x1/STM32L0x2/STM32L0x3";
        case 0x440:
          return "STM32F05x/STM32F030x8";
        case 0x442:
          return "STM32F09x/STM32F030xC";
        case 0x444:
          return "STM32F03x/STM32F030x4/STM32F030x6";
        case 0x445:
          return "STM32F04x/STM32F070x6";
        case 0x448:
          return "STM32F07x/STM32F070xB";
        case 0x456:
          return "STM32G050xx/STM32G051xx/STM32G061xx";
        case 0x460:
          return "STM32G070xx/STM32G071xx/STM32G081xx";
        case 0x466:
          return "STM32G030xx/STM32G031xx/STM32G041xx";
        case 0x467:
          return "STM32G0B0xx/STM32G0B1xx/STM32G0C1xx";
        default: // The ROM table may not be visible
          TargetInterface.setDebugInterfaceProperty("component_base", 0xe000e000);
          TargetInterface.setDebugInterfaceProperty("component_base", 0xe0001000);
          TargetInterface.setDebugInterfaceProperty("component_base", 0xe0002000);
          break;
      }
  else if (((CPUID>>4)&0xfff)==0xD21) // Cortex-M33
    switch ((TargetInterface.peekWord(0xE0044000) & 0xfff))
      {
        case 0x472:
          return "STM32L552xx/STM32L562xx";
        case 0x482:
          return "STM32U575xx/STM32U585xx";
      }
  else
    switch ((TargetInterface.peekWord(0xE0042000) & 0xfff))
      {
        case 0x420: // low and medium density value 
          return "STM32F100x4/STM32F100x6/STM32F100x8/STM32F100xB";
        case 0x428: // high density value
          return "STM32F100xC/STM32F100xD/STM32F100xE";
        case 0x412: // low density
          return "STM32F10xx4/STM32F10xx6";
        case 0x410: // medium density   
          return "STM32F10xx8/STM32F10xxB";
        case 0x414: // high density
          return "STM32F10xxC/STM32F10xxD/STM32F10xxE";
        case 0x430: // xl density
          return "STM32F10xxF/STM32F10xxG";
        case 0x418: // connectivity
          return "STM32F105xx/STM32F107xx";
        case 0x411: // STM32F2xx/STM32F4xx
          if ((TargetInterface.peekWord(0xE000ED00) & 0xf0)==0x40)
            return "STM32F40x/STM32F41x";
          else
            return "STM32F205xx/STM32F207xx/STM32F215xx/STM32F217xx";
        case 0x413: // STM32F40x/STM32F41x
          return "STM32F40x/STM32F41x";
        case 0x415: // STM32L4x1/STM32L4x5/STM32L4x6
          return "STM32L4x1/STM32L4x5/STM32L4x6";
        case 0x416: // low and medium density STM32L
        case 0x429:
          return "STM32L151x8/STM32L151xB/STM32L152x8/STM32L152xB/STM32L100x6/STM32L100x8/STM32L100xB";
        case 0x419: // STM32F42x/STM32F43x
          return "STM32F42x/STM32F43x";
        case 0x421:
          return "STM32F446xx";
        case 0x423: // STM32F401
        case 0x433: // STM32F401
          return "STM32F401x";
        case 0x431: // STM32F411xE
          return "STM32F411x";
        case 0x427: // medium+
        case 0x436: // high density STM32L
          return "STM32L151xC/STM32L151xD/STM32L152xC/STM32L152xD/STM32L162xD/STM32L100xC";
        case 0x434: // STM32F469/STM32F479
          return "STM32F469/STM32F479";
        case 0x435: // STM32L4x2/L4x3
          return "STM32L4x2/STM32L431/STM32L433/STM32L443";
        case 0x437:
          return "STM32L152E";
        case 0x422: // STM32F30x
        case 0x439: // STM32F30x
          return "STM32F30x";
        case 0x432: // STM32F37x
          return "STM32F37x";
        case 0x438: // STM32F334
          return "STM32F334xx/STM32F303x6/STM32F303x8/STM32F328";
        case 0x441: // STM32F412
          return "STM32F412";
        case 0x446:
          return "STM32F303xD/STM32F303xE/STM32F398xE";
        case 0x449:
          return "STM32F75x/STM32F74x";
        case 0x451:
          return "STM32F76x/STM32F77x";
        case 0x452: // STM32F72x/STM32F73x
          return "STM32F72x/STM32F73x";
        case 0x458: // STM32F410
          return "STM32F410x";
        case 0x461: 
          return "STM32L496/STM32L4A6";
        case 0x462:
          return "STM32L451/STM32L452/STM32L462";
        case 0x463: 
          return "STM32F413";
        case 0x464:
          return "STM32L412/STM32L422";
        case 0x468: // STM32G4 Category 2
          return "STM32G431/STM32G441"; 
        case 0x469: // STM32G4 Category 3
          return "STM32G471/STM32G473/STM32G474/STM32G483/STM32G484"; 
        case 0x470:
          return "STM32L4R/STM32L4S";
        case 0x471:
          return "STM32L4P5/STM32L4Q5";
        case 0x479: // STM32G4 Category 4
          return "STM32G491/STM32G4A1";
        case 0x495:
          return "STM32WB55xx/STM32WB35xx";
        case 0x497:
          return "STM32WL5x/STM32WLEx";
        default:
          switch ((TargetInterface.peekWord(0x5C001000) & 0xfff))
            {
              case 0x450:
                if (((CPUID>>4)&0xf)==4)
                  return "STM32H7_CM4";
                else
                  return "STM32H7";
              case 0x480:
                return "STM32H7A3/STM32H7B3/STM32H7B0";
            }
      }
  // STM32W108 has a bootloader program in the fixed flash memory area check that it's value is within SRAM
  var FIB0 = TargetInterface.peekWord(0x08040000);
  if (FIB0 >= 0x20000000 && FIB0 <= 0x20002000)
    return "STM32W108";
}

function MatchPartName(name)
{
  var family = name.substring(0, 9); // STM32F100, STM32F102, STM32F101, STM32F103, STM32F105, STM32F107, STM32F205, STM32F207, STM32F405, STM32F407, STM32L151, STM32L152, STM32F051, STM32F050, STM32F427, STM32F437
  var density = name.substring(10, 11); // 4==16K, 6==32K, 8==64K, B=128K, C=256K, D=384K, E=512K, F=768K, G=1024K, I=2048K
  var CPUID = TargetInterface.peekWord(0xE000ED00);
  if (((CPUID>>4)&0xf)==0) // Cortex-M0
    switch ((TargetInterface.peekWord(0x40015800) & 0xfff))
      {
        case 0x457:
        case 0x425:
        case 0x417:
        case 0x447:
          return (family=="STM32L010") || (family=="STM32L011") || (family=="STM32L031") || (family=="STM32L041") || (family=="STM32L051") || (family=="STM32L052") || (family=="STM32L053") || (family=="STM32L061") || (family=="STM32L062") || (family=="STM32L063") || (family=="STM32L071") || (family=="STM32L072") || (family=="STM32L073") || (family=="STM32L083");
        case 0x440:
          return (family=="STM32F058") || (family=="STM32F051") || ((family=="STM32F030") && (density=="8"));
        case 0x442:
          return (family=="STM32F091") || (family=="STM32F098") || ((family=="STM32F030") && (density=="C"));
        case 0x444:
          return (family=="STM32F031") || (family=="STM32F038") || ((family=="STM32F030") && (density=="4" || density=="6"));
        case 0x445:
          return (family=="STM32F042") || (family=="STM32F048") || ((family=="STM32F070") && (density=="6"));
        case 0x448:
          return (family=="STM32F070") || (family=="STM32F071") || (family=="STM32F072") || (family=="STM32F078") || ((family=="STM32F070") && (density=="B"));
        case 0x456:
          return (family=="STM32G050") || (family=="STM32G051") || (family=="STM32F061");
        case 0x460:
          return (family=="STM32G070") || (family=="STM32G071") || (family=="STM32F081");
        case 0x466:
          return (family=="STM32G030") || (family=="STM32G031") || (family=="STM32F041");
        case 0x467:
          return (family=="STM32G0B0") || (family=="STM32G0B1") || (family=="STM32F0C1");
      }
  else if (((CPUID>>4)&0xfff)==0xD21) // Cortex-M33
    switch ((TargetInterface.peekWord(0xE0044000) & 0xfff))
      {
        case 0x472:
          return (family == "STM32L552") || (family == "STM32L562");
        case 0x482:
          return (family == "STM32U575") || (family == "STM32U585");
      }
  else
    switch ((TargetInterface.peekWord(0xE0042000) & 0xfff))
      {
        case 0x420: // low and medium density value 
          return (family=="STM32F100") && (density=="4" || density=="6" || density=="8" || density=="B");
        case 0x428: // high density value
          return  (family=="STM32F100") && (density=="C" || density=="D" || density=="E");
        case 0x412: // low density
          return (family=="STM32F101" || family=="STM32F102" || family=="STM32F103") && (density=="4" || density=="6");
        case 0x410: // medium density   
          return (family=="STM32F101" || family=="STM32F102" || family=="STM32F103") && (density =="8" || density=="B");
        case 0x414: // high density
          return (family=="STM32F101" || family=="STM32F102" || family=="STM32F103") && (density =="C" || density=="D" || density=="E");
        case 0x430: // xl density
          return (family=="STM32F101" || family=="STM32F103") && (density =="F" || density=="G");
        case 0x418: // connectivity
          return (family=="STM32F105" || family=="STM32F107");
        case 0x411: // STM32F2xx/F4xx
          return (family=="STM32F205" || family=="STM32F207" || family=="STM32F215" || family=="STM32F217" || family == "STM32F405" || family == "STM32F407" || family == "STM32F415" || family == "STM32F417");
        case 0x413: // STM32F4xx
          return (family == "STM32F405" || family == "STM32F407" || family == "STM32F415" || family == "STM32F417");
        case 0x415: // STM32L4x6
          return (family == "STM32L476" || family == "STM32L486" || family == "STM32L471" || family == "STM32L475");
        case 0x416: // low and medium density STM32L
        case 0x429:
          return (family=="STM32L151" || family=="STM32L152" || family=="STM32L100") && (density=="6" || density=="8" || density=="B");
        case 0x419: // STM32F427x/STM32F437x
          return (family=="STM32F427" || family=="STM32F437" || family=="STM32F429" || family=="STM32F439") && (density=="G" || density=="I");
        case 0x421:
          return (family=="STM32F446")
        case 0x427: // medium+ density STM32L
        case 0x436: // high density STM32L
          return (family=="STM32L151" || family=="STM32L152" || family=="STM32L162" || family=="STM32L100") && (density=="C" || density=="D");
        case 0x437: // STM32L152E
          return (family=="STM32L152") && (density=="E");
        case 0x422: // STM32F30x
        case 0x439: // STM32F30x
          return (family=="STM32F302" || family=="STM32F303");
        case 0x423: // STM32F401
        case 0x433: // STM32F401
          return (family=="STM32F401");
        case 0x435:
          return (family=="STM32L431" || family=="STM32L432" || family=="STM32L433" || family=="STM32L442" || family=="STM32L443");
        case 0x431: // STM32F411xE
          return (family=="STM32F411");
        case 0x432: // STM32F37x
          return (family=="STM32F372" || family=="STM32F373");
        case 0x434: // STM32F469/STM32F479
          return (family=="STM32F469" || family=="STM32F479");
        case 0x438: // STM32F334
          return (family=="STM32F334" || family=="STM32F303" || family=="STM32F328");
        case 0x441: // STM32F412
          return (family=="STM32F412");
        case 0x446:
          return (family=="STM32F303" || family=="STM32F398");
        case 0x449: // STM32F75x/STM32F74x
          return (family=="STM32F745" || family=="STM32F746" || family=="STM32F756");
        case 0x451: // STM32F76x/STM32F77x
          return (family=="STM32F765" || family=="STM32F767" || family=="STM32F769" || family=="STM32F777" || family=="STM32F778" || family=="STM32F779");
        case 0x452: // STM32F72x/STM32F73x
          return (family=="STM32F722" || family=="STM32F723" || family=="STM32F732" || family=="STM32F733");
        case 0x458: // STM32F410x
          return (family=="STM32F410");
        case 0x461:
          return (family=="STM32L496" || family=="STM32L4A6");
        case 0x462:
          return (family=="STM32L451" || family=="STM32L452" || family == "STM32L462");
        case 0x463:
          return (family=="STM32F413");
        case 0x464:
          return (family=="STM32L412" || family=="STM32L422");
        case 0x468: // STM32G4 Category 2
          return (family=="STM32G431" || family=="STM32G441") && (density=="6" || density=="8" || density=="B");
        case 0x469: // STM32G4 Category 3
          return (family=="STM32G471" || family=="STM32G473" || family=="STM32G474" || family=="STM32G483" || family=="STM32G484") && (density=="B" || density=="C" || density=="E");
        case 0x470:
          return (family=="STM32L4R5" || family=="STM32L4R7" || family=="STM32L4R9" || family=="STM32L4S5" || family=="STM32L4S7" || family=="STM32L4S9");
        case 0x471:
          return (family=="STM32L4P5" || family=="STM32L4Q5");
        case 0x479: // STM32G4 Category 4
          return (family=="STM32G491" || family=="STM32G4A1") && (density=="E");
        case 0x495:
          return (family=="STM32WB55" || family=="STM32WB35");
        case 0x497:
          return (family=="STM32WL55" || family=="STM32WL54" || family=="STM32WLE5" || family=="STM32WLE4");
        default:
          switch ((TargetInterface.peekWord(0x5C001000) & 0xfff))
            {
              case 0x450:
                return (family.indexOf("STM32H74")==0 || family.indexOf("STM32H75")==0);
              case 0x480:
                return (family.indexOf("STM32H7A")==0 || family.indexOf("STM32H7B")==0);
            }
      }
  var FIB0 = TargetInterface.peekWord(0x08040000);
  if (FIB0 >= 0x20000000 && FIB0 <= 0x20002000)
    return family=="STM32W108";
  return false;
}

//
// STM32F1xx option byte support
//
var FLASH_KEYR=0x40022004;
var FLASH_OPTKEYR=0x40022008;
var FLASH_SR=0x4002200C;
var FLASH_CR=0x40022010;

//
// Note this function will erase the RDP byte i.e. turn on read protection.
// Call STM32F_Unprotect() to turn off read protection after this has been called.
//
function STM32F_EraseOptionBytes()
{
  if (!TargetInterface.isStopped())
    TargetInterface.stopAndReset(400);
  // unlock FPEC
  TargetInterface.pokeWord(FLASH_KEYR, 0x45670123);
  TargetInterface.pokeWord(FLASH_KEYR, 0xCDEF89AB);
  // unlock OPTWRE
  TargetInterface.pokeWord(FLASH_OPTKEYR, 0x45670123);
  TargetInterface.pokeWord(FLASH_OPTKEYR, 0xCDEF89AB);
  // Erase option bytes
  var cr = TargetInterface.peekWord(FLASH_CR);
  cr |= (1<<5); // OPTER
  TargetInterface.pokeWord(FLASH_CR, cr);
  cr |= (1<<6); // STRT
  TargetInterface.pokeWord(FLASH_CR, cr);
  while (TargetInterface.peekWord(FLASH_SR) & 1);
  cr &= ~(1<<5); // ~OPTER
  TargetInterface.pokeWord(FLASH_CR, cr);
}

//
// Set the option byte at address to value
// STM32F_EraseOptionBytes() should been called before calling this function.
//
function STM32F_SetOptionByte(address, value)
{ 
  var cr = TargetInterface.peekWord(FLASH_CR);
  cr |= (1<<4); // OPTPG
  TargetInterface.pokeWord(FLASH_CR, cr);
  TargetInterface.pokeUint16(address, value);
  while (TargetInterface.peekWord(FLASH_SR) & 1);
  cr &= ~(1<<4); // ~FLASH_OPTPG
  TargetInterface.pokeWord(FLASH_CR, cr);
}

// 
// Turn off read protection
//
function STM32F_Unprotect()
{
  STM32F_SetOptionByte(0x1FFFF800, 0xA5);
}

// 
// Set user byte
//
function STM32F_SetUSER(b)
{
  STM32F_SetOptionByte(0x1FFFF802, b);
}

// 
// Set user data0
//
function STM32F_SetData0(b)
{
  STM32F_SetOptionByte(0x1FFFF804, b);
}

// 
// Set user data1
//
function STM32F_SetData1(b)
{
  STM32F_SetOptionByte(0x1FFFF806, b);
}

//
// STM32L option byte support
//
var FLASH2_PECR=0x40023C04;
var FLASH2_PEKEYR=0x40023C0C;
var FLASH2_OPTKEYR=0x40023C14;
var FLASH2_SR=0x40023C18;

function STM32L_SetOptionByte(address, value)
{
  if (!TargetInterface.isStopped())
    TargetInterface.stopAndReset(400);
  // Unlock PECR
  TargetInterface.pokeWord(FLASH2_PEKEYR, 0x89ABCDEF);
  TargetInterface.pokeWord(FLASH2_PEKEYR, 0x02030405);
  // Unlock option byte block
  TargetInterface.pokeWord(FLASH2_OPTKEYR, 0xFBEAD9C8);
  TargetInterface.pokeWord(FLASH2_OPTKEYR, 0x24252627);
  // Erase/Write option byte word
  var pecr = TargetInterface.peekWord(FLASH2_PECR);
  pecr |= (1<<8); // FTDW
  TargetInterface.pokeWord(FLASH2_PECR, pecr);
  TargetInterface.pokeWord(address, value);
  while (TargetInterface.peekWord(FLASH2_SR) & 1);
  pecr &= ~(1<<8); // ~FTDW
  TargetInterface.pokeWord(FLASH2_PECR, pecr);
}

function STM32L_MakeOptionWord(b0, b1)
{
  return (b0|b1<<8|((~b0)&0xff)<<16|((~b1)&0xff)<<24);
}

function STM32L_SetUSER(u)
{
  STM32L_SetOptionByte(0x1FF80004, STM32L_MakeOptionWord(u, 0));
}

//
// STM32F2xx option byte support
//
var FLASH3_KEYR=0x40023C04;
var FLASH3_OPTKEYR=0x40023C08;
var FLASH3_SR=0x40023C0C;
var FLASH3_CR=0x40023C10;
var FLASH3_OPTCR=0x40023C14;

//
// Set the USER option byte
//
function STM32F2xx_SetUSER(value)
{
  if (!TargetInterface.isStopped())
    TargetInterface.stopAndReset(400);
  // unlock OPTCR
  TargetInterface.pokeWord(FLASH3_OPTKEYR, 0x08192A3B);
  TargetInterface.pokeWord(FLASH3_OPTKEYR, 0x4C5D6E7F);

  // write USER option byte and then the OPTSTRT bit
  TargetInterface.pokeByte(FLASH3_OPTCR, value & 0xFC);
  TargetInterface.pokeByte(FLASH3_OPTCR, (value & 0xFC) | 2);
  // wait
  while (TargetInterface.peekWord(FLASH3_SR) & (1<<16));
}