Repository: pyocd/pyocd
Issue: [pyocd 0.26] pyocd gdbserver exceptions

**tested boards**
1. twrk22f12, daplink version 0247
2. frdmk66f, daplink version 0243

**description**
1. At first, run command `pyocd erase -c -u 0231000026294e450024000e58a900543ee1000097969900` to perform a chip erase.
2. Exceptions will occured on gdb command "load" is sent.

*used gdb commands*
```
target remote localhost: {gdbport}
load
monitor reset
q
```

**note**
Verfied above steps works very well on version 0.14

**pyocd gdbserver**
```
$ pyocd gdbserver --trust-crc --uid 0231000026294e450024000e58a900543ee1000097969900 --port 7100 
0000675:WARNING:common:STLink and CMSIS-DAPv2 probes are not supported because no libusb library was found.
0001093:INFO:board:Target type is k22f
0001108:INFO:coresight_target:Performing connect pre-reset
0001342:INFO:dap:DP IDR = 0x2ba01477 (v1 rev2)
0001367:INFO:ap:AP#0 IDR = 0x24770011 (AHB-AP var1 rev2)
0001386:INFO:ap:AP#1 IDR = 0x001c0000 (proprietary)
0003197:WARNING:target_kinetis:K22F in secure state: will try to unlock via mass erase
0003426:WARNING:target_kinetis:K22F secure state: unlocked successfully
0003440:INFO:rom_table:AP#0 Class 0x1 ROM table #0 @ 0xe00ff000 (designer=43b part=4c4)
0003451:INFO:rom_table:[0]<e000e000:SCS-M4 class=14 designer=43b part=00c>
0003459:INFO:rom_table:[1]<e0001000:DWT class=14 designer=43b part=002>
0003467:INFO:rom_table:[2]<e0002000:FPB class=14 designer=43b part=003>
0003476:INFO:rom_table:[3]<e0000000:ITM class=14 designer=43b part=001>
0003484:INFO:rom_table:[4]<e0040000:TPIU-M4 class=9 designer=43b part=9a1 devtype=11 archid=0000 devid=ca0:0:0>
0003488:INFO:cortex_m:CPU core #0 is Cortex-M4 r0p1
0003501:INFO:dwt:4 hardware watchpoints
0003506:INFO:fpb:6 hardware breakpoints, 4 literal comparators
0003538:INFO:server:Semihost server started on port 4444 (core 0)
0003539:INFO:gdbserver:GDB server started on port 7100 (core 0)
0004069:INFO:gdbserver:One client connected!
0004102:ERROR:gdbserver:Unhandled exception in handle_message: type object 'CortexM' has no attribute 'DFSR_PMU'
Traceback (most recent call last):
  File "c:\\python27\\lib\\site-packages\\pyocd\\gdbserver\\gdbserver.py", line 381, in handle_message
    reply = handler()
  File "c:\\python27\\lib\\site-packages\\pyocd\\gdbserver\\gdbserver.py", line 516, in stop_reason_query
    return self.create_rsp_packet(self.get_t_response())
  File "c:\\python27\\lib\\site-packages\\pyocd\\gdbserver\\gdbserver.py", line 1116, in get_t_response
    response = self.target_facade.get_t_response(forceSignal)
  File "c:\\python27\\lib\\site-packages\\pyocd\\gdbserver\\context_facade.py", line 138, in get_t_response
    response = six.b('T' + conversion.byte_to_hex2(self.get_signal_value()))
  File "c:\\python27\\lib\\site-packages\\pyocd\\gdbserver\\context_facade.py", line 152, in get_signal_value
    if self._context.core.is_vector_catch():
  File "c:\\python27\\lib\\site-packages\\pyocd\\coresight\\cortex_m.py", line 1335, in is_vector_catch
    return self.get_halt_reason() == Target.HaltReason.VECTOR_CATCH
  File "c:\\python27\\lib\\site-packages\\pyocd\\coresight\\cortex_m.py", line 1349, in get_halt_reason
    elif dfsr & CortexM.DFSR_PMU:
AttributeError: type object 'CortexM' has no attribute 'DFSR_PMU'
0008320:ERROR:gdbserver:Unhandled exception in handle_message: init error: 536870913
Traceback (most recent call last):
  File "c:\\python27\\lib\\site-packages\\pyocd\\gdbserver\\gdbserver.py", line 383, in handle_message
    reply = handler(msg[msgStart:])
  File "c:\\python27\\lib\\site-packages\\pyocd\\gdbserver\\gdbserver.py", line 602, in v_command
    return self.flash_op(data)
  File "c:\\python27\\lib\\site-packages\\pyocd\\gdbserver\\gdbserver.py", line 718, in flash_op
    self.flash_loader.commit()
  File "c:\\python27\\lib\\site-packages\\pyocd\\flash\\loader.py", line 168, in commit
    keep_unwritten=self._keep_unwritten)
  File "c:\\python27\\lib\\site-packages\\pyocd\\flash\\builder.py", line 417, in program
    self._build_sectors_and_pages(keep_unwritten)
  File "c:\\python27\\lib\\site-packages\\pyocd\\flash\\builder.py", line 315, in _build_sectors_and_pages
    fill_end_of_page_gap()
  File "c:\\python27\\lib\\site-packages\\pyocd\\flash\\builder.py", line 259, in fill_end_of_page_gap
    self._enable_read_access()
  File "c:\\python27\\lib\\site-packages\\pyocd\\flash\\builder.py", line 221, in _enable_read_access
    self.flash.init(self.flash.Operation.VERIFY)
  File "c:\\python27\\lib\\site-packages\\pyocd\\flash\\flash.py", line 250, in init
    raise FlashFailure('init error: %i' % result, result_code=result)
FlashFailure: init error: 536870913
0008342:INFO:gdbserver:Client detached
0008342:INFO:gdbserver:Client disconnected!
0008546:INFO:server:Semihost server stopped
```




Changed files:
pyocd/tools/pyocd.py, pyocd/flash/builder.py, pyocd/gdbserver/gdbserver.py, pyocd/target/builtin/target_MKL28Z512xxx7.py, pyocd/core/coresight_target.py

diff --git a/pyocd/core/coresight_target.py b/pyocd/core/coresight_target.py
index bc896140..3e599ac8 100644
--- a/pyocd/core/coresight_target.py
+++ b/pyocd/core/coresight_target.py
@@ -135,7 +135,6 @@ class CoreSightTarget(Target, GraphNode):
     def create_init_sequence(self):
         seq = CallSequence(
             ('load_svd',            self.load_svd),
-            ('create_flash',        self.create_flash),
             ('pre_connect',         self.pre_connect),
             ('dp_init',             self.dp.init_sequence),
             ('create_discoverer',   self.create_discoverer),
@@ -144,6 +143,7 @@ class CoreSightTarget(Target, GraphNode):
             ('halt_on_connect',     self.perform_halt_on_connect),
             ('post_connect',        self.post_connect),
             ('post_connect_hook',   self.post_connect_hook),
+            ('create_flash',        self.create_flash),
             ('notify',              lambda : self.session.notify(Target.Event.POST_CONNECT, self))
             )
         
diff --git a/pyocd/flash/builder.py b/pyocd/flash/builder.py
index fd57f43e..e10c51e6 100644
--- a/pyocd/flash/builder.py
+++ b/pyocd/flash/builder.py
@@ -218,7 +218,11 @@ class FlashBuilder(object):
         memory mapped and accessible.
         """
         if not self.algo_inited_for_read:
-            self.flash.init(self.flash.Operation.VERIFY)
+            try:
+                self.flash.init(self.flash.Operation.VERIFY)
+            except FlashFailure:
+                # If initing for verify fails, then try again in erase mode.
+                self.flash.init(self.flash.Operation.ERASE)
             self.algo_inited_for_read = True
 
     def _build_sectors_and_pages(self, keep_unwritten):
diff --git a/pyocd/gdbserver/gdbserver.py b/pyocd/gdbserver/gdbserver.py
index 1595d7d4..c5b81287 100644
--- a/pyocd/gdbserver/gdbserver.py
+++ b/pyocd/gdbserver/gdbserver.py
@@ -714,12 +714,13 @@ class GDBServer(threading.Thread):
         elif b'FlashDone' in ops :
             # Only program if we received data.
             if self.flash_loader is not None:
-                # Write all buffered flash contents.
-                self.flash_loader.commit()
-
-                # Set flash loader to None so that on the next flash command a new
-                # object is used.
-                self.flash_loader = None
+                try:
+                    # Write all buffered flash contents.
+                    self.flash_loader.commit()
+                finally:
+                    # Set flash loader to None so that on the next flash command a new
+                    # object is used.
+                    self.flash_loader = None
 
             self.first_run_after_reset_or_flash = True
             if self.thread_provider is not None:
diff --git a/pyocd/target/builtin/target_MKL28Z512xxx7.py b/pyocd/target/builtin/target_MKL28Z512xxx7.py
index ada56177..faca9c5b 100644
--- a/pyocd/target/builtin/target_MKL28Z512xxx7.py
+++ b/pyocd/target/builtin/target_MKL28Z512xxx7.py
@@ -132,14 +132,12 @@ class Flash_kl28z(Flash_Kinetis):
         self._saved_firccsr = 0
         self._saved_rccr = 0
 
-    def prepare_target(self, operation, address=None, clock=0, reset=True):
+    def prepare_target(self):
         """!
         This function sets up target clocks to ensure that flash is clocked at the maximum
         of 24MHz. Doing so gets the best flash programming performance. The FIRC clock source
         is used so that there is no dependency on an external crystal frequency.
         """
-        super(Flash_kl28z, self).init(operation, address, clock, reset)
-
         # Enable FIRC.
         value = self.target.read32(SCG_FIRCCSR)
         self._saved_firccsr = value
diff --git a/pyocd/tools/pyocd.py b/pyocd/tools/pyocd.py
index 65ffcf32..a63610bf 100755
--- a/pyocd/tools/pyocd.py
+++ b/pyocd/tools/pyocd.py
@@ -1028,7 +1028,10 @@ class PyOCDCommander(object):
         region = self.session.target.memory_map.get_region_for_address(addr)
         flash_init_required =  region is not None and region.is_flash and not region.is_powered_on_boot and region.flash is not None
         if flash_init_required:
-            region.flash.init(region.flash.Operation.VERIFY)
+            try:
+                region.flash.init(region.flash.Operation.VERIFY)
+            except exceptions.FlashFailure:
+                region.flash.init(region.flash.Operation.ERASE)
 
         data = bytearray(self.target.aps[self.selected_ap].read_memory_block8(addr, count))
 
@@ -1082,7 +1085,10 @@ class PyOCDCommander(object):
         region = self.session.target.memory_map.get_region_for_address(addr)
         flash_init_required =  region is not None and region.is_flash and not region.is_powered_on_boot and region.flash is not None
         if flash_init_required:
-            region.flash.init(region.flash.Operation.VERIFY)
+            try:
+                region.flash.init(region.flash.Operation.VERIFY)
+            except exceptions.FlashFailure:
+                region.flash.init(region.flash.Operation.ERASE)
 
         with open(filename, 'rb') as f:
             file_data = f.read(length)