This is an automated email from Gerrit.

Tarek BOCHKATI ([email protected]) just uploaded a new patch set to 
Gerrit, which you can find at http://openocd.zylin.com/5395

-- gerrit

commit 0dfd27abdd78fd6b7ef37e619a1a65ba2932364c
Author: Tarek BOCHKATI <[email protected]>
Date:   Sat Jan 11 15:18:16 2020 +0100

    [WIP] flash/stm32l4: enhance protect handler to use efficiently all WRP 
areas
    
    stm32l4_protect: is always using one WRP area per bank, without checking
    if it is already protecting some sectors.
    protection algo is more complicated than that, before using a WRP area
    we should check if it is already used, then either reuse it for extension
    (or reduction) or use a free area.
    another thing to be considered.
    
    for some devices like STM32L4R/S in single bank mode, all 4 WRP areas are
    usable for that bank.
    
    To do that, a helper (interval) was introduced to optimize WRP areas' usage
    
    Change-Id: I6fc28346b4f6dd0217dd98bc585c5b4265cfe24d
    Signed-off-by: Tarek BOCHKATI <[email protected]>

diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c
index 3d15377..48ffaaf 100644
--- a/src/flash/nor/stm32l4x.c
+++ b/src/flash/nor/stm32l4x.c
@@ -25,6 +25,7 @@
 
 #include "imp.h"
 #include <helper/binarybuffer.h>
+#include <helper/interval.h>
 #include <target/algorithm.h>
 #include <target/armv7m.h>
 #include "bits.h"
@@ -137,6 +138,9 @@ struct stm32l4_part_info {
        const size_t num_revs;
        const uint16_t max_flash_size_kb;
        const bool has_dual_bank;
+       /* this field is used for dual bank devices only, it indicates if the
+        * 4 WRPxx are usable if the device is configured in single-bank mode*/
+       const bool use_all_wrpxx;
        const uint32_t flash_regs_base;
        const uint32_t fsize_addr;
 };
@@ -150,6 +154,21 @@ struct stm32l4_flash_bank {
        const struct stm32l4_part_info *part_info;
 };
 
+enum stm32_bank_id {
+       STM32_BANK1,
+       STM32_BANK2,
+       STM32_ALL_BANKS
+};
+
+struct stm32l4_wrp {
+       uint32_t addr;
+       uint32_t value;
+       bool used;
+       int first;
+       int last;
+       int offset;
+};
+
 static const struct stm32l4_rev stm32_415_revs[] = {
        { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" }
 };
@@ -190,6 +209,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .device_str            = "STM32L47/L48xx",
          .max_flash_size_kb     = 1024,
          .has_dual_bank         = true,
+         .use_all_wrpxx         = false,
          .flash_regs_base       = 0x40022000,
          .fsize_addr            = 0x1FFF75E0,
        },
@@ -200,6 +220,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .device_str            = "STM32L43/L44xx",
          .max_flash_size_kb     = 256,
          .has_dual_bank         = false,
+         .use_all_wrpxx         = false,
          .flash_regs_base       = 0x40022000,
          .fsize_addr            = 0x1FFF75E0,
        },
@@ -210,6 +231,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .device_str            = "STM32L49/L4Axx",
          .max_flash_size_kb     = 1024,
          .has_dual_bank         = true,
+         .use_all_wrpxx         = false,
          .flash_regs_base       = 0x40022000,
          .fsize_addr            = 0x1FFF75E0,
        },
@@ -220,6 +242,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .device_str            = "STM32L45/L46xx",
          .max_flash_size_kb     = 512,
          .has_dual_bank         = false,
+         .use_all_wrpxx         = false,
          .flash_regs_base       = 0x40022000,
          .fsize_addr            = 0x1FFF75E0,
        },
@@ -230,6 +253,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .device_str            = "STM32L41/L42xx",
          .max_flash_size_kb     = 128,
          .has_dual_bank         = false,
+         .use_all_wrpxx         = false,
          .flash_regs_base       = 0x40022000,
          .fsize_addr            = 0x1FFF75E0,
        },
@@ -240,6 +264,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .device_str            = "STM32L4R/L4Sxx",
          .max_flash_size_kb     = 2048,
          .has_dual_bank         = true,
+         .use_all_wrpxx         = true,
          .flash_regs_base       = 0x40022000,
          .fsize_addr            = 0x1FFF75E0,
        },
@@ -250,6 +275,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .device_str            = "STM32L4P5/L4Q5x",
          .max_flash_size_kb     = 1024,
          .has_dual_bank         = true,
+         .use_all_wrpxx         = true,
          .flash_regs_base       = 0x40022000,
          .fsize_addr            = 0x1FFF75E0,
        },
@@ -260,6 +286,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .device_str            = "STM32WB5x",
          .max_flash_size_kb     = 1024,
          .has_dual_bank         = false,
+         .use_all_wrpxx         = false,
          .flash_regs_base       = 0x58004000,
          .fsize_addr            = 0x1FFF75E0,
        },
@@ -438,46 +465,76 @@ static int stm32l4_write_option(struct flash_bank *bank, 
uint32_t reg_offset, ui
        return retval;
 }
 
-static int stm32l4_protect_check(struct flash_bank *bank)
+static int stm32l4_get_wrpxy(struct flash_bank *bank, enum stm32_bank_id 
bank_id,
+               struct stm32l4_wrp *wrpxy, int *n_wrp)
 {
        struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+       int ret;
 
-       uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br;
-       stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1AR, &wrp1ar);
-       stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1BR, &wrp1br);
-       stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2AR, &wrp2ar);
-       stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2BR, &wrp2br);
-
-       const uint8_t wrp1a_start = wrp1ar & 0xFF;
-       const uint8_t wrp1a_end = (wrp1ar >> 16) & 0xFF;
-       const uint8_t wrp1b_start = wrp1br & 0xFF;
-       const uint8_t wrp1b_end = (wrp1br >> 16) & 0xFF;
-       const uint8_t wrp2a_start = wrp2ar & 0xFF;
-       const uint8_t wrp2a_end = (wrp2ar >> 16) & 0xFF;
-       const uint8_t wrp2b_start = wrp2br & 0xFF;
-       const uint8_t wrp2b_end = (wrp2br >> 16) & 0xFF;
-
-       for (int i = 0; i < bank->num_sectors; i++) {
-               if (i < stm32l4_info->bank1_sectors) {
-                       if (((i >= wrp1a_start) &&
-                                (i <= wrp1a_end)) ||
-                               ((i >= wrp1b_start) &&
-                                (i <= wrp1b_end)))
-                               bank->sectors[i].is_protected = 1;
-                       else
-                               bank->sectors[i].is_protected = 0;
-               } else {
-                       uint8_t snb;
-                       snb = i - stm32l4_info->bank1_sectors;
-                       if (((snb >= wrp2a_start) &&
-                                (snb <= wrp2a_end)) ||
-                               ((snb >= wrp2b_start) &&
-                                (snb <= wrp2b_end)))
+       *n_wrp = 0;
+
+       /* for single bank devices there is 2 WRP regions.
+        * for dual bank devices there is 2 WRP regions per bank,
+        *   if configured as single bank only 2 WRP are usable
+        *   except for STM32L4R/S and STM32G4 cat3, all 4 WRP are usable
+        * note: this should be revised, if a device will have the SWAP banks 
option
+        */
+
+       int wrp2y_sectors_offset = -1; /* -1 : unused */
+
+       /* if bank_id is BANK1 or ALL_BANKS */
+       if (bank_id != STM32_BANK2) {
+               wrpxy[*n_wrp++] = (struct stm32l4_wrp){.addr = 
STM32_FLASH_WRP1AR, .offset = 0};
+               wrpxy[*n_wrp++] = (struct stm32l4_wrp){.addr = 
STM32_FLASH_WRP1BR, .offset = 0};
+               /* for some devices (like STM32L4R/S) in single-bank mode, the 
4 WRPxx are usable */
+               if (stm32l4_info->part_info->use_all_wrpxx && 
!stm32l4_info->dual_bank_mode)
+                       wrp2y_sectors_offset = 0;
+       }
+
+       /* if bank_id is BANK2 or ALL_BANKS */
+       if (bank_id != STM32_BANK1 && stm32l4_info->dual_bank_mode)
+               wrp2y_sectors_offset = stm32l4_info->bank1_sectors;
+
+       if (wrp2y_sectors_offset > -1) {
+               wrpxy[*n_wrp++] = (struct stm32l4_wrp){.addr = 
STM32_FLASH_WRP2AR, .offset = wrp2y_sectors_offset};
+               wrpxy[*n_wrp++] = (struct stm32l4_wrp){.addr = 
STM32_FLASH_WRP2BR, .offset = wrp2y_sectors_offset};
+       }
+
+       /* read available WRPxx */
+       for (int i = 0; i < *n_wrp; i++) {
+               ret = stm32l4_read_flash_reg(bank, wrpxy[i].addr, 
&wrpxy[i].value);
+               if (ret != ERROR_OK)
+                       return ret;
+
+               wrpxy[i].first = (wrpxy[i].value & 0xff) + wrpxy[i].offset;
+               wrpxy[i].last = ((wrpxy[i].value >> 16) & 0xff) + 
wrpxy[i].offset;
+               wrpxy[i].used = wrpxy[i].first <= wrpxy[i].last;
+       }
+
+       return ERROR_OK;
+}
+
+static int stm32l4_protect_check(struct flash_bank *bank)
+{
+       int n_wrp;
+       struct stm32l4_wrp wrpxy[4];
+
+       int ret = stm32l4_get_wrpxy(bank, STM32_ALL_BANKS, wrpxy, &n_wrp);
+       if (ret != ERROR_OK)
+               return ret;
+
+       /* initialize all sectors as unprotected */
+       for (int i = 0; i < bank->num_sectors; i++)
+               bank->sectors[i].is_protected = 0;
+
+       /* now check WRPxy and mark the protected sectors */
+       for (int i = 0; i < n_wrp; i++) {
+               if (wrpxy[i].used) {
+                       for (int s = wrpxy[i].first; s <= wrpxy[i].last; s++)
                                bank->sectors[i].is_protected = 1;
-                       else
-                               bank->sectors[i].is_protected = 0;
                }
        }
+
        return ERROR_OK;
 }
 
@@ -542,35 +599,124 @@ static int stm32l4_protect(struct flash_bank *bank, int 
set, int first, int last
 {
        struct target *target = bank->target;
        struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+       int ret = ERROR_OK;
+       int i;
 
        if (target->state != TARGET_HALTED) {
                LOG_ERROR("Target not halted");
                return ERROR_TARGET_NOT_HALTED;
        }
 
-       int ret = ERROR_OK;
-       /* Bank 2 */
-       uint32_t reg_value = 0xFF; /* Default to bank un-protected */
+       /* the requested sectors could be located into bank1 and/or bank2 */
+       bool use_bank2 = false;
        if (last >= stm32l4_info->bank1_sectors) {
-               if (set == 1) {
-                       uint8_t begin = first > stm32l4_info->bank1_sectors ? 
first : 0x00;
-                       reg_value = ((last & 0xFF) << 16) | begin;
+               if (first < stm32l4_info->bank1_sectors) {
+                       /* the requested sectors for (un)protection are shared 
between
+                        * bank 1 and 2, then split the operation */
+
+                       /*  1- deal with bank 1 sectors */
+                       LOG_INFO("The requested sectors for %s are shared 
between bank 1 and 2",
+                                       set ? "protection" : "unprotection");
+                       ret = stm32l4_protect(bank, set, first, 
stm32l4_info->bank1_sectors - 1);
+                       if (ret != ERROR_OK)
+                               return ret;
+
+                       /*  2- then continue with bank 2 sectors */
+                       first = stm32l4_info->bank1_sectors;
                }
 
-               ret = stm32l4_write_option(bank, STM32_FLASH_WRP2AR, reg_value, 
0xffffffff);
+               use_bank2 = true;
        }
-       /* Bank 1 */
-       reg_value = 0xFF; /* Default to bank un-protected */
-       if (first < stm32l4_info->bank1_sectors) {
-               if (set == 1) {
-                       uint8_t end = last >= stm32l4_info->bank1_sectors ? 
0xFF : last;
-                       reg_value = (end << 16) | (first & 0xFF);
+
+       /* refresh the sectors' protection */
+       ret = stm32l4_protect_check(bank);
+       if (ret != ERROR_OK)
+               return ret;
+
+       /* check if the desired protection is already configured */
+       for (i = first; i <= last; i++) {
+               if (bank->sectors[i].is_protected != set)
+                       break;
+               else if (i == last) {
+                       LOG_INFO("The specified sectors are already %s", set ? 
"protected" : "unprotected");
+                       return ERROR_OK;
                }
+       }
+
+       /* all sectors from first to last (or part of them) could have different
+        * protection other than the requested */
+       int n_wrp;
+       struct stm32l4_wrp wrpxy[4];
 
-               ret = stm32l4_write_option(bank, STM32_FLASH_WRP1AR, reg_value, 
0xffffffff);
+       ret = stm32l4_get_wrpxy(bank, use_bank2 ? STM32_BANK2 : STM32_BANK1, 
wrpxy, &n_wrp);
+       if (ret != ERROR_OK)
+               return ret;
+
+       /* use the interval helper to optimize the WRP usage */
+       interval_t *wrp_intervals = NULL;
+
+       for (i = 0; i < n_wrp; i++) {
+               if (wrpxy[i].used) {
+                       ret = interval_append(&wrp_intervals, wrpxy[i].first, 
wrpxy[i].last);
+                       if (ret != ERROR_OK)
+                               return ret;
+               }
        }
 
-       return ret;
+       interval_print_all(wrp_intervals);
+
+       if (set) { /* flash protect */
+               ret = interval_append(&wrp_intervals, first, last);
+               if (ret != ERROR_OK)
+                       return ret;
+       } else { /* flash unprotect */
+               ret = interval_delete(&wrp_intervals, first, last);
+               if (ret != ERROR_OK)
+                       return ret;
+       }
+
+       /* reorder the WRP intervals */
+       interval_print_all(wrp_intervals);
+       interval_reorder(&wrp_intervals);
+       interval_print_all(wrp_intervals);
+
+       int n_intervals = interval_count(wrp_intervals);
+       if (n_intervals > n_wrp) {
+               LOG_ERROR("the device WRPxy are not enough to set the requested 
protection");
+               return ERROR_FAIL;
+       }
+
+       /* re-init all WRPxy as disabled (first > last)*/
+       for (i = 0; i < n_wrp; i++) {
+               wrpxy[i].first = wrpxy[i].offset + 1;
+               wrpxy[i].last = wrpxy[i].offset;
+       }
+
+       /* then configure WRPxy areas */
+       interval_t *tmp = wrp_intervals;
+       i = 0;
+       while (tmp) {
+               wrpxy[i].first = tmp->start;
+               wrpxy[i].last = tmp->end;
+               i++;
+               tmp = tmp->next;
+       }
+
+
+       /* finally write WRPxy registers */
+       for (i = 0; i < n_wrp; i++) {
+               int wrp_start = wrpxy[i].first - wrpxy[i].offset;
+               int wrp_end = wrpxy[i].last - wrpxy[i].offset;
+
+               uint32_t wrp_value = (wrp_start & 0xff) | ((wrp_end & 0xff) << 
16);
+
+               ret = stm32l4_write_option(bank, wrpxy[i].addr, wrp_value, 
0x00ff00ff);
+
+               if (ret != ERROR_OK)
+                       return ret;
+       }
+
+       return ERROR_OK;
 }
 
 /* Count is in halfwords */
diff --git a/src/helper/Makefile.am b/src/helper/Makefile.am
index 2b3523f..d18fc6f 100644
--- a/src/helper/Makefile.am
+++ b/src/helper/Makefile.am
@@ -15,6 +15,7 @@ noinst_LTLIBRARIES += %D%/libhelper.la
        %D%/util.c \
        %D%/jep106.c \
        %D%/jim-nvp.c \
+       %D%/interval.c \
        %D%/binarybuffer.h \
        %D%/bits.h \
        %D%/configuration.h \
@@ -30,7 +31,8 @@ noinst_LTLIBRARIES += %D%/libhelper.la
        %D%/system.h \
        %D%/jep106.h \
        %D%/jep106.inc \
-       %D%/jim-nvp.h
+       %D%/jim-nvp.h \
+       %D%/interval.h
 
 if IOUTIL
 %C%_libhelper_la_SOURCES += %D%/ioutil.c
diff --git a/src/helper/interval.c b/src/helper/interval.c
new file mode 100644
index 0000000..cc6d59a
--- /dev/null
+++ b/src/helper/interval.c
@@ -0,0 +1,291 @@
+/***************************************************************************
+ *                                                                         *
+ *   Copyright (C) 2020 by Tarek Bochkati for STMicroelectronics           *
+ *   [email protected]                                             *
+ *                                                                         *
+ *   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/>. *
+ ***************************************************************************/
+
+#include "interval.h"
+
+#include <stdlib.h>
+#include "log.h"
+
+/* this enum is used to compare two intervals
+ *  - interval1 defined by [s1, e1]  (s1 <= e1)
+ *  - interval2 defined by [s2, e2]  (s2 <= e2)
+ */
+enum interval_comparison_result {
+       INTERVAL_EQUAL,              /* intervals are equal */
+       INTERVAL_BEFORE,             /* [s1 <= e1] < [s2 <= e2] */
+       INTERVAL_AFTER,              /* [s2 <= e2] < [s1 <= e1] */
+       INTERVAL_BEFORE_WITH_OVELAP, /* s1 < [s2 <= e1 <= e2] */
+       INTERVAL_AFTER_WITH_OVERLAP, /* [s2 <= s1 <= e2] < e1 */
+       INTERVAL_INTO,               /* s2 <= [s1 <= e1] <= e2 */
+       INTERVAL_EXTO                /* s1 < [s2 <= e2] < e1, (not sure about 
the name) */
+};
+
+int interval_count(interval_t *head)
+{
+       interval_t *cur = head;
+       int count = 0;
+
+       while (cur) {
+               cur = cur->next;
+               count++;
+       }
+
+       return count;
+}
+
+int interval_append(interval_t **head_ref, int start, int end)
+{
+       if (start > end) {
+               LOG_ERROR("interval error: start > end");
+               return ERROR_FAIL;
+       }
+
+       interval_t *new_interval = malloc(sizeof(interval_t));
+       if (!new_interval)
+               return ERROR_FAIL;
+
+       new_interval->start = start;
+       new_interval->end = end;
+       new_interval->next = NULL;
+
+       if (*head_ref) {
+               interval_t *last = *head_ref;
+
+               while (last->next)
+                       last = last->next;
+
+               last->next = new_interval;
+       } else {
+               /* first insertion */
+               *head_ref = new_interval;
+       }
+
+       return ERROR_OK;
+}
+
+static enum interval_comparison_result interval_compare(interval_t *interval1, 
interval_t *interval2)
+{
+       if ((interval1->start == interval2->start) && (interval1->end == 
interval2->end))
+               return INTERVAL_EQUAL;
+
+       if (interval1->start < interval2->start) {
+               if (interval1->end < interval2->start)
+                       return INTERVAL_BEFORE;
+               else if (interval1->end > interval2->end)
+                       return INTERVAL_EXTO;
+               return INTERVAL_BEFORE_WITH_OVELAP;
+       } else if (interval1->start <= interval2->end) {
+               if (interval1->end <= interval2->end)
+                       return INTERVAL_INTO;
+               else
+                       return INTERVAL_AFTER_WITH_OVERLAP;
+       }
+
+       return INTERVAL_AFTER;
+}
+
+int interval_delete(interval_t **head_ref, int del_start, int del_end)
+{
+       interval_t *cur = *head_ref, *prev = NULL, *tmp;
+       interval_t del_interval = {del_start, del_end, NULL}; /* the interval 
to delete */
+
+       while (cur) {
+               switch (interval_compare(cur, &del_interval)) {
+               case INTERVAL_BEFORE:
+               case INTERVAL_AFTER:
+                       /* nothing to do */
+                       break;
+               case INTERVAL_INTO:
+               case INTERVAL_EQUAL:
+                       cur->start = cur->end + 1; /* just a hint to remove the 
interval */
+                       break;
+               case INTERVAL_BEFORE_WITH_OVELAP:
+                       cur->end = del_start - 1; /* check later the interval 
validity */
+                       break;
+               case INTERVAL_AFTER_WITH_OVERLAP:
+                       cur->start = del_end + 1; /* check later the interval 
validity */
+                       break;
+               case INTERVAL_EXTO:
+                       /* split cur */
+                       tmp = malloc(sizeof(interval_t));
+                       if (!tmp)
+                               return ERROR_FAIL;
+                       tmp->start = del_end + 1;
+                       tmp->end = cur->end;
+                       tmp->next = cur->next;
+                       cur->end = del_start - 1;
+                       cur->next = tmp;
+                       /* jump to next (tmp) */
+                       cur = cur->next;
+                       break;
+               }
+
+               /* check the cur interval validity */
+               if (cur->start > cur->end) {
+                       /* invalid, remove it */
+                       if (prev == NULL) {
+                               /* cur is the first element in the list */
+                               *head_ref = cur->next;
+                               free(cur);
+                               cur = *head_ref;
+                       } else {
+                               prev->next = cur->next;
+                               free(cur);
+                               cur = prev->next;
+                       }
+               } else if (cur) {
+                       /* valid, normal execution */
+                       prev = cur;
+                       cur = cur->next;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+/* seek for the first occurrences of interval1 and 2 into the list defined by
+ * head_ref and swap them */
+static int interval_swap(interval_t **head_ref, interval_t *interval1, 
interval_t *interval2)
+{
+       assert(interval1 && interval2);
+
+       if (interval1 == interval2) /* nothing to do */
+               return ERROR_OK;
+
+       interval_t *tmp = *head_ref;
+       interval_t *prev1 = NULL;
+       interval_t *prev2 = NULL;
+
+       /* search for prev1 */
+       if (*head_ref != interval1) {
+               while (tmp && !prev1) {
+                       if (tmp->next == interval1)
+                               prev1 = tmp;
+                       tmp = tmp->next;
+               }
+               if (!prev1)
+                       return ERROR_FAIL;
+       }
+
+       /* search for prev2 */
+       tmp = *head_ref;
+       if (*head_ref != interval2) {
+               while (tmp && !prev2) {
+                       if (tmp->next == interval2)
+                               prev2 = tmp;
+                       tmp = tmp->next;
+               }
+               if (!prev2)
+                       return ERROR_FAIL;
+       }
+
+       /* change prev relation chain */
+       if (prev1)
+               prev1->next = interval2;
+       else /* interval1 is the first element, put interval2 instead */
+               *head_ref = interval2;
+
+       if (prev2)
+               prev2->next = interval1;
+       else /* interval2 is the first element, put interval1 instead */
+               *head_ref = interval1;
+
+       /* change next relation chain */
+       tmp = interval1->next;
+       interval1->next = interval2->next;
+       interval2->next = tmp;
+
+       return ERROR_OK;
+}
+
+int interval_reorder(interval_t **head_ref)
+{
+       if (interval_count(*head_ref) < 2)
+               return ERROR_OK;
+
+       interval_t *cur, *next;
+       bool touched;
+
+       /* bubble like algorithm */
+       do {
+               touched = false;
+               cur = *head_ref;
+
+               while (cur && cur->next) {
+                       next = cur->next;
+
+                       switch (interval_compare(cur, next)) {
+                       case INTERVAL_BEFORE:
+                               /* normal order, nothing to do */
+                               break;
+                       case INTERVAL_BEFORE_WITH_OVELAP:
+                               /* merge into cur and remove next */
+                               cur->end = next->end;
+                               cur->next = next->next;
+                               free(next);
+                               touched = true;
+                               break;
+                       case INTERVAL_EQUAL:
+                       case INTERVAL_EXTO:
+                               /* next is into cur, remove next */
+                               cur->next = next->next;
+                               free(next);
+                               touched = true;
+                               break;
+                       case INTERVAL_AFTER_WITH_OVERLAP:
+                               /* merge into cur and remove next */
+                               cur->start = next->start;
+                               cur->next = next->next;
+                               free(next);
+                               touched = true;
+                               break;
+                       case INTERVAL_INTO:
+                       case INTERVAL_AFTER:
+                               interval_swap(head_ref, cur, next);
+                               touched = true;
+                               break;
+                       }
+
+                       if (cur)
+                               cur = cur->next;
+               }
+       } while (touched);
+
+       return ERROR_OK;
+}
+
+void interval_print(interval_t *interval)
+{
+       if (interval->start == interval->end)
+               printf("[%d]", interval->start);
+       else
+               printf("[%d, %d]", interval->start, interval->end);
+}
+
+void interval_print_all(interval_t *head)
+{
+       interval_t *cur = head;
+
+       while (cur) {
+               interval_print(cur);
+               cur = cur->next;
+       }
+
+       printf("\n");
+}
diff --git a/src/helper/interval.h b/src/helper/interval.h
new file mode 100644
index 0000000..a1a86ec
--- /dev/null
+++ b/src/helper/interval.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ *                                                                         *
+ *   Copyright (C) 2020 by Tarek Bochkati for STMicroelectronics           *
+ *   [email protected]                                             *
+ *                                                                         *
+ *   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/>. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_HELPER_INTERVAL_H
+#define OPENOCD_HELPER_INTERVAL_H
+
+typedef struct interval {
+       int start, end;
+       struct interval *next;
+} interval_t;
+
+int interval_count(interval_t *head);
+int interval_append(interval_t **head_ref, int start, int end);
+int interval_delete(interval_t **head_ref, int start, int end);
+int interval_reorder(interval_t **head_ref);
+void interval_print(interval_t *interval);
+void interval_print_all(interval_t *head);
+
+
+#endif /* OPENOCD_HELPER_INTERVAL_H */

-- 


_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to