From 7b03129916aa050f4d120a532659dbbba279f7be Mon Sep 17 00:00:00 2001 From: Edward Fewell Date: Thu, 18 Jan 2018 20:48:11 -0600 Subject: [PATCH 001/147] flash/nor: Add support for TI CC26xx/CC13xx flash Added cc26xx flash driver to support the TI CC26xx and CC13xx microcontrollers. Driver is capable of determining which MCU is connected and configures itself accordingly. Added config files for four specific variants: CC26x0, CC13x0, CC26x2, and CC13x2. Note that the flash loader code is based on the sources used to support flash in Code Composer Studio and Uniflash from TI. Removed cc26xx.cfg file made obsolete by this patch. Change-Id: Ie2b0f74f8af7517a9184704b839677d1c9787862 Signed-off-by: Edward Fewell Reviewed-on: http://openocd.zylin.com/4358 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Fredrik Hederstierna --- contrib/loaders/flash/cc26xx/Makefile | 83 + .../loaders/flash/cc26xx/cc26x0/cc26x0r2f.lds | 90 + contrib/loaders/flash/cc26xx/cc26x0_algo.inc | 1217 ++++++++++ .../loaders/flash/cc26xx/cc26x2/cc26x2r1f.lds | 90 + contrib/loaders/flash/cc26xx/cc26x2_algo.inc | 2049 +++++++++++++++++ contrib/loaders/flash/cc26xx/flash.c | 977 ++++++++ contrib/loaders/flash/cc26xx/flash.h | 378 +++ contrib/loaders/flash/cc26xx/flashloader.c | 177 ++ contrib/loaders/flash/cc26xx/flashloader.h | 187 ++ contrib/loaders/flash/cc26xx/hw_regs.h | 1382 +++++++++++ contrib/loaders/flash/cc26xx/main.c | 179 ++ contrib/loaders/flash/cc26xx/startup.c | 97 + doc/openocd.texi | 11 + src/flash/nor/Makefile.am | 2 + src/flash/nor/cc26xx.c | 567 +++++ src/flash/nor/cc26xx.h | 101 + src/flash/nor/drivers.c | 2 + tcl/board/ti_cc13x0_launchpad.cfg | 7 + tcl/board/ti_cc13x2_launchpad.cfg | 7 + tcl/board/ti_cc26x0_launchpad.cfg | 7 + tcl/board/ti_cc26x2_launchpad.cfg | 7 + tcl/target/ti_cc13x0.cfg | 11 + tcl/target/ti_cc13x2.cfg | 11 + tcl/target/{cc26xx.cfg => ti_cc26x0.cfg} | 40 +- tcl/target/ti_cc26x2.cfg | 11 + 25 files changed, 7676 insertions(+), 14 deletions(-) create mode 100644 contrib/loaders/flash/cc26xx/Makefile create mode 100644 contrib/loaders/flash/cc26xx/cc26x0/cc26x0r2f.lds create mode 100644 contrib/loaders/flash/cc26xx/cc26x0_algo.inc create mode 100644 contrib/loaders/flash/cc26xx/cc26x2/cc26x2r1f.lds create mode 100644 contrib/loaders/flash/cc26xx/cc26x2_algo.inc create mode 100644 contrib/loaders/flash/cc26xx/flash.c create mode 100644 contrib/loaders/flash/cc26xx/flash.h create mode 100644 contrib/loaders/flash/cc26xx/flashloader.c create mode 100644 contrib/loaders/flash/cc26xx/flashloader.h create mode 100644 contrib/loaders/flash/cc26xx/hw_regs.h create mode 100644 contrib/loaders/flash/cc26xx/main.c create mode 100644 contrib/loaders/flash/cc26xx/startup.c create mode 100644 src/flash/nor/cc26xx.c create mode 100644 src/flash/nor/cc26xx.h create mode 100644 tcl/board/ti_cc13x0_launchpad.cfg create mode 100644 tcl/board/ti_cc13x2_launchpad.cfg create mode 100644 tcl/board/ti_cc26x0_launchpad.cfg create mode 100644 tcl/board/ti_cc26x2_launchpad.cfg create mode 100644 tcl/target/ti_cc13x0.cfg create mode 100644 tcl/target/ti_cc13x2.cfg rename tcl/target/{cc26xx.cfg => ti_cc26x0.cfg} (57%) mode change 100755 => 100644 create mode 100644 tcl/target/ti_cc26x2.cfg diff --git a/contrib/loaders/flash/cc26xx/Makefile b/contrib/loaders/flash/cc26xx/Makefile new file mode 100644 index 000000000..7cc1fb3c4 --- /dev/null +++ b/contrib/loaders/flash/cc26xx/Makefile @@ -0,0 +1,83 @@ +BIN2C = ../../../../src/helper/bin2char.sh + +CROSS_COMPILE ?= arm-none-eabi- +GCC = $(CROSS_COMPILE)gcc +OBJCOPY = $(CROSS_COMPILE)objcopy + +FLAGS = -mthumb -Os -ffunction-sections -fdata-sections -g -gdwarf-3 +FLAGS += -gstrict-dwarf -Wall -fno-strict-aliasing --asm + +CFLAGS = -c -I. + +CC26X0_CFLAGS = -mcpu=cortex-m3 -DDEVICE_CC26X0 + +CC26X2_CFLAGS = -mcpu=cortex-m4 -DDEVICE_CC26X2 + +CC26X0_OBJS := \ +cc26x0/flashloader.o \ +cc26x0/main.o \ +cc26x0/startup.o \ +cc26x0/flash.o + +CC26X2_OBJS := \ +cc26x2/flashloader.o \ +cc26x2/main.o \ +cc26x2/startup.o \ +cc26x2/flash.o + +all: cc26x0_algo.inc cc26x2_algo.inc + +cc26x0/%.o: %.c + @echo 'Building file: $<' + @echo 'Invoking: GNU Compiler' + $(GCC) $(FLAGS) $(CFLAGS) $(CC26X0_CFLAGS) -o"$@" "$(shell echo $<)" + @echo 'Finished building: $<' + @echo ' ' + +cc26x2/%.o: %.c + @echo 'Building file: $<' + @echo 'Invoking: GNU Compiler' + $(GCC) $(FLAGS) $(CFLAGS) $(CC26X2_CFLAGS) -o"$@" "$(shell echo $<)" + @echo 'Finished building: $<' + @echo ' ' + +cc26x0_algo.out: $(CC26X0_OBJS) + @echo 'Building target: $@' + @echo 'Invoking: GNU Linker' + $(GCC) $(FLAGS) -o$@ $(CC26X0_OBJS) -Wl,-T"cc26x0/cc26x0r2f.lds" + @echo 'Finished building target: $@' + @echo ' ' + +cc26x2_algo.out: $(CC26X2_OBJS) + @echo 'Building target: $@' + @echo 'Invoking: GNU Linker' + $(GCC) $(FLAGS) -o$@ $(CC26X2_OBJS) -Wl,-T"cc26x2/cc26x2r1f.lds" + @echo 'Finished building target: $@' + @echo ' ' + +%.bin: %.out + @echo 'Building target: $@' + @echo 'Invoking: GNU Objcopy Utility' + $(OBJCOPY) -Obinary $< $@ + @echo 'Finished building target: $@' + @echo ' ' + +%.inc: %.bin + @echo 'Building target: $@' + @echo 'Invoking Bin2Char Script' + $(BIN2C) < $< > $@ + rm $< $*.out + @echo 'Finished building target: $@' + @echo ' ' + +clean: + @echo 'Cleaning Targets and Build Artifacts' + rm -rf *.inc *.bin *.out *.map + rm -rf cc26x0/*.o cc26x0/*.d + rm -rf cc26x2/*.o cc26x2/*.d + @echo 'Finished clean' + @echo ' ' + +.PRECIOUS: %.bin + +.PHONY: all clean diff --git a/contrib/loaders/flash/cc26xx/cc26x0/cc26x0r2f.lds b/contrib/loaders/flash/cc26xx/cc26x0/cc26x0r2f.lds new file mode 100644 index 000000000..9a126fc2b --- /dev/null +++ b/contrib/loaders/flash/cc26xx/cc26x0/cc26x0r2f.lds @@ -0,0 +1,90 @@ +/****************************************************************************** +* +* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +/* Entry Point */ +ENTRY( entry ) + +/* System memory map */ +MEMORY +{ + /* Application is stored in and executes from SRAM */ + PROGRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0x1BD8 + BUFFERS (RWX) : ORIGIN = 0x20001BD8, LENGTH = 0x3028 +} + +/* Section allocation in memory */ +SECTIONS +{ + .text : + { + _text = .; + *(.entry*) + *(.text*) + _etext = .; + } > PROGRAM + + .data : + { _data = .; + *(.rodata*) + *(.data*) + _edata = .; + } + + .bss : + { + __bss_start__ = .; + _bss = .; + *(.bss*) + *(COMMON) + _ebss = .; + __bss_end__ = .; + } > PROGRAM + + .stack : + { + _stack = .; + *(.stack*) + _estack = .; + } > PROGRAM + + .buffers : + { + _buffers = .; + *(.buffers.g_cfg) + *(.buffers.g_buf1) + *(.buffers.g_buf2) + *(.buffers*) + _ebuffers = .; + } > BUFFERS +} diff --git a/contrib/loaders/flash/cc26xx/cc26x0_algo.inc b/contrib/loaders/flash/cc26xx/cc26x0_algo.inc new file mode 100644 index 000000000..2246a3670 --- /dev/null +++ b/contrib/loaders/flash/cc26xx/cc26x0_algo.inc @@ -0,0 +1,1217 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x08,0xb5,0x00,0xbf,0x00,0xbf,0x00,0xbf,0x00,0xbf,0xdf,0xf8,0x1c,0xd0,0x07,0x48, +0x07,0x49,0x4f,0xf0,0x00,0x02,0x88,0x42,0xb8,0xbf,0x40,0xf8,0x04,0x2b,0xfa,0xdb, +0x00,0xf0,0xa8,0xf9,0xfe,0xe7,0x00,0x00,0xf0,0x0e,0x00,0x20,0x54,0x13,0x00,0x20, +0x98,0x13,0x00,0x20,0x08,0xb5,0x07,0x4b,0x07,0x48,0x03,0x33,0x1b,0x1a,0x06,0x2b, +0x04,0xd9,0x06,0x4b,0x00,0x2b,0x01,0xd0,0x00,0xf0,0x5c,0xf8,0x08,0xbc,0x01,0xbc, +0x00,0x47,0xc0,0x46,0x50,0x13,0x00,0x20,0x50,0x13,0x00,0x20,0x00,0x00,0x00,0x00, +0x08,0x48,0x09,0x49,0x09,0x1a,0x89,0x10,0x08,0xb5,0xcb,0x0f,0x59,0x18,0x49,0x10, +0x04,0xd0,0x06,0x4b,0x00,0x2b,0x01,0xd0,0x00,0xf0,0x44,0xf8,0x08,0xbc,0x01,0xbc, +0x00,0x47,0xc0,0x46,0x50,0x13,0x00,0x20,0x50,0x13,0x00,0x20,0x00,0x00,0x00,0x00, +0x10,0xb5,0x08,0x4c,0x23,0x78,0x00,0x2b,0x09,0xd1,0xff,0xf7,0xcb,0xff,0x06,0x4b, +0x00,0x2b,0x02,0xd0,0x05,0x48,0xaf,0xf3,0x00,0x80,0x01,0x23,0x23,0x70,0x10,0xbc, +0x01,0xbc,0x00,0x47,0x54,0x13,0x00,0x20,0x00,0x00,0x00,0x00,0xe0,0x0e,0x00,0x20, +0x08,0xb5,0x0b,0x4b,0x00,0x2b,0x03,0xd0,0x0a,0x48,0x0b,0x49,0xaf,0xf3,0x00,0x80, +0x0a,0x48,0x03,0x68,0x00,0x2b,0x04,0xd1,0xff,0xf7,0xc2,0xff,0x08,0xbc,0x01,0xbc, +0x00,0x47,0x07,0x4b,0x00,0x2b,0xf7,0xd0,0x00,0xf0,0x0c,0xf8,0xf4,0xe7,0xc0,0x46, +0x00,0x00,0x00,0x00,0xe0,0x0e,0x00,0x20,0x58,0x13,0x00,0x20,0x4c,0x13,0x00,0x20, +0x00,0x00,0x00,0x00,0x18,0x47,0xc0,0x46,0xd4,0x30,0x9f,0xe5,0x00,0x00,0x53,0xe3, +0xc8,0x30,0x9f,0x05,0x03,0xd0,0xa0,0xe1,0x00,0x20,0x0f,0xe1,0x0f,0x00,0x12,0xe3, +0x15,0x00,0x00,0x0a,0xd1,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1,0x01,0xaa,0x4d,0xe2, +0x0a,0x30,0xa0,0xe1,0xd7,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1,0x01,0x3a,0x43,0xe2, +0xdb,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1,0x01,0x3a,0x43,0xe2,0xd2,0xf0,0x21,0xe3, +0x03,0xd0,0xa0,0xe1,0x02,0x3a,0x43,0xe2,0xd3,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1, +0x02,0x39,0x43,0xe2,0xff,0x30,0xc3,0xe3,0xff,0x3c,0xc3,0xe3,0x04,0x30,0x03,0xe5, +0x00,0x20,0x53,0xe9,0xc0,0x20,0x82,0xe3,0x02,0xf0,0x21,0xe1,0x01,0xa8,0x43,0xe2, +0x00,0x10,0xb0,0xe3,0x01,0xb0,0xa0,0xe1,0x01,0x70,0xa0,0xe1,0x5c,0x00,0x9f,0xe5, +0x5c,0x20,0x9f,0xe5,0x00,0x20,0x52,0xe0,0x01,0x30,0x8f,0xe2,0x13,0xff,0x2f,0xe1, +0x00,0xf0,0x42,0xfd,0x10,0x4b,0x00,0x2b,0x01,0xd0,0xfe,0x46,0x9f,0x46,0x0f,0x4b, +0x00,0x2b,0x01,0xd0,0xfe,0x46,0x9f,0x46,0x00,0x20,0x00,0x21,0x04,0x00,0x0d,0x00, +0x0d,0x48,0x00,0xf0,0x89,0xfc,0x00,0xf0,0xc3,0xfc,0x20,0x00,0x29,0x00,0x00,0xf0, +0xd1,0xf8,0x00,0xf0,0x8b,0xfc,0x7b,0x46,0x18,0x47,0x00,0x00,0x11,0x00,0x00,0xef, +0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x54,0x13,0x00,0x20,0x98,0x13,0x00,0x20,0x15,0x0b,0x00,0x20,0x70,0xb5,0x04,0x46, +0x0e,0x46,0x15,0x46,0x00,0x21,0x28,0x22,0x00,0xf0,0x0e,0xfd,0x26,0x61,0x65,0x62, +0x00,0x21,0x20,0x22,0x02,0x48,0x00,0xf0,0x07,0xfd,0x00,0x20,0x70,0xbd,0x00,0xbf, +0x70,0x13,0x00,0x20,0x10,0xb5,0x01,0x20,0x00,0xf0,0xac,0xf9,0x04,0x46,0x28,0xb9, +0x01,0x21,0x20,0x22,0x03,0x48,0x00,0xf0,0xf7,0xfc,0x01,0xe0,0x40,0xf2,0x01,0x14, +0x20,0x46,0x10,0xbd,0x70,0x13,0x00,0x20,0x01,0x39,0xf8,0xb5,0x04,0x0b,0x08,0x44, +0x05,0x0b,0x26,0x03,0xac,0x42,0x14,0xd8,0x0b,0x4f,0xe3,0x5d,0x6b,0xb9,0x30,0x46, +0x00,0xf0,0xfc,0xf8,0x38,0xb1,0x00,0x04,0x00,0xf4,0x7f,0x00,0x40,0xea,0x04,0x60, +0x40,0xf4,0x81,0x70,0xf8,0xbd,0x01,0x23,0xe3,0x55,0x01,0x34,0x06,0xf5,0x80,0x56, +0xe8,0xe7,0x00,0x20,0xf8,0xbd,0x00,0xbf,0x70,0x13,0x00,0x20,0x2d,0xe9,0xf0,0x4f, +0x0d,0x46,0x53,0x1e,0x85,0xb0,0x0b,0x44,0x02,0x90,0x4f,0xea,0x11,0x38,0x1b,0x0b, +0x16,0x46,0x23,0x48,0x00,0x21,0x20,0x22,0x01,0x93,0x4f,0xea,0x08,0x37,0x00,0xf0, +0xbb,0xfc,0x4f,0xf0,0x00,0x09,0xc5,0xf3,0x0b,0x0c,0x01,0x9b,0x98,0x45,0x33,0xd8, +0x74,0x19,0x07,0xf5,0x80,0x5a,0x54,0x45,0x98,0xbf,0x34,0x46,0xdf,0xf8,0x64,0xb0, +0x88,0xbf,0xc4,0xf3,0x0b,0x04,0x39,0x46,0x4f,0xf4,0x80,0x52,0x58,0x46,0x88,0xbf, +0x34,0x1b,0xcd,0xf8,0x0c,0xc0,0x00,0xf0,0x5f,0xfc,0xdd,0xf8,0x0c,0xc0,0x02,0x9b, +0x0b,0xeb,0x0c,0x00,0x03,0xeb,0x09,0x01,0x22,0x46,0x00,0xf0,0x55,0xfc,0x38,0x46, +0x4f,0xf4,0x80,0x51,0x08,0xf1,0x01,0x08,0xff,0xf7,0x9e,0xff,0x68,0xb9,0x39,0x46, +0x58,0x46,0x4f,0xf4,0x80,0x52,0x25,0x44,0x00,0xf0,0xae,0xf8,0x36,0x1b,0xc5,0xf3, +0x0b,0x0c,0xa1,0x44,0x57,0x46,0xc8,0xe7,0x00,0x20,0x05,0xb0,0xbd,0xe8,0xf0,0x8f, +0x70,0x13,0x00,0x20,0x00,0x3c,0x00,0x20,0xb2,0xf5,0x80,0x5f,0xf8,0xb5,0x07,0x46, +0x0e,0x46,0x15,0x46,0x0b,0xd8,0x08,0x46,0x11,0x46,0xff,0xf7,0x7d,0xff,0x04,0x46, +0x40,0xb9,0x38,0x46,0x31,0x46,0x2a,0x46,0x00,0xf0,0x8e,0xf8,0x02,0xe0,0x4f,0xf4, +0x82,0x70,0xf8,0xbd,0x20,0x46,0xf8,0xbd,0x08,0xb5,0x00,0xf0,0x85,0xf8,0x00,0x20, +0x08,0xbd,0x00,0x00,0xf8,0xb5,0x31,0x48,0x31,0x49,0x32,0x4a,0x32,0x4c,0xff,0xf7, +0x3d,0xff,0x00,0x23,0x23,0x60,0x22,0x68,0x2c,0x4f,0x14,0x23,0x03,0xfb,0x02,0x73, +0x08,0x33,0x5b,0x68,0x00,0x2b,0xf7,0xd0,0x2c,0x4b,0x1a,0x68,0x11,0x07,0xfb,0xd4, +0x2b,0x4d,0x2c,0x4e,0x2a,0x68,0x32,0x60,0x42,0xf0,0x33,0x02,0x2a,0x60,0x1a,0x68, +0x12,0x07,0xfc,0xd4,0x21,0x68,0x14,0x22,0x02,0xfb,0x01,0x73,0x98,0x68,0x13,0x46, +0x01,0x38,0x04,0x28,0x26,0xd8,0xdf,0xe8,0x00,0xf0,0x03,0x06,0x0e,0x16,0x1e,0x00, +0xff,0xf7,0x28,0xff,0x20,0xe0,0x4b,0x43,0xfa,0x18,0x10,0x69,0xf9,0x58,0x52,0x68, +0xff,0xf7,0xc2,0xff,0x18,0xe0,0x4b,0x43,0xfa,0x18,0x10,0x69,0xf9,0x58,0x52,0x68, +0xff,0xf7,0xa2,0xff,0x10,0xe0,0x4b,0x43,0xfa,0x18,0x10,0x69,0xf9,0x58,0x52,0x68, +0xff,0xf7,0x44,0xff,0x08,0xe0,0x4b,0x43,0xfa,0x18,0xf8,0x58,0x51,0x68,0xff,0xf7, +0x1b,0xff,0x01,0xe0,0x40,0xf2,0x05,0x10,0x33,0x68,0x2b,0x60,0x0b,0x4b,0x1b,0x68, +0x1b,0x07,0xfb,0xd4,0x22,0x68,0x14,0x23,0x03,0xfb,0x02,0x77,0xfb,0x68,0xf8,0x60, +0x00,0xb1,0xfe,0xe7,0x82,0xf0,0x01,0x02,0x22,0x60,0xa4,0xe7,0xd8,0x1b,0x00,0x20, +0x00,0x1c,0x00,0x20,0x00,0x2c,0x00,0x20,0x90,0x13,0x00,0x20,0x00,0x40,0x03,0x40, +0x04,0x40,0x03,0x40,0x94,0x13,0x00,0x20,0xfe,0xe7,0x00,0x00,0x08,0xb5,0x04,0x4b, +0x1b,0x68,0x5b,0x69,0x98,0x47,0x03,0x4b,0x00,0x22,0x1a,0x60,0x08,0xbd,0x00,0xbf, +0xa8,0x01,0x00,0x10,0x84,0x04,0x60,0x42,0x08,0xb5,0x04,0x4b,0x1b,0x68,0x9b,0x69, +0x98,0x47,0x03,0x4b,0x00,0x22,0x1a,0x60,0x08,0xbd,0x00,0xbf,0xa8,0x01,0x00,0x10, +0x84,0x04,0x60,0x42,0x10,0xb5,0x33,0x4b,0x33,0x48,0x1b,0x68,0x33,0x4a,0x13,0xf0, +0x02,0x0f,0x03,0x68,0x43,0xf0,0x02,0x03,0x03,0x60,0x13,0x68,0x01,0x68,0x19,0xd0, +0x21,0xf4,0xe1,0x72,0xc3,0xf3,0xc1,0x04,0x22,0xf0,0x01,0x02,0x22,0x43,0xc3,0xf3, +0xc0,0x11,0x42,0xea,0x01,0x22,0xc3,0xf3,0x41,0x11,0x42,0xea,0x81,0x12,0x02,0x60, +0x02,0x68,0xd4,0x07,0x03,0xd5,0x26,0x4a,0x12,0x68,0x50,0x07,0xfb,0xd5,0x03,0xf0, +0x07,0x03,0x18,0xe0,0x21,0xf4,0xe1,0x72,0xc3,0xf3,0xc1,0x24,0x22,0xf0,0x01,0x02, +0xc3,0xf3,0xc0,0x31,0x22,0x43,0x42,0xea,0x01,0x22,0xc3,0xf3,0x41,0x31,0x42,0xea, +0x81,0x12,0x02,0x60,0x02,0x68,0xd1,0x07,0x03,0xd5,0x19,0x4a,0x12,0x68,0x52,0x07, +0xfb,0xd5,0xc3,0xf3,0x02,0x23,0x4a,0xf6,0xaa,0x22,0x16,0x49,0x16,0x48,0x0a,0x60, +0x02,0x68,0x1b,0x03,0xb3,0xf5,0xe0,0x4f,0x22,0xf4,0xe2,0x42,0x18,0xbf,0x43,0xf4, +0x80,0x73,0x13,0x43,0x03,0x60,0x45,0xf2,0xaa,0x53,0x0b,0x60,0x0f,0x4b,0x10,0x49, +0x01,0x22,0x1a,0x60,0x00,0x22,0x0a,0x60,0x1a,0x60,0x05,0x22,0xc3,0xf8,0x58,0x22, +0x4f,0xf0,0xff,0x32,0xc1,0xf8,0x8c,0x22,0xc1,0xf8,0x90,0x22,0x02,0x22,0xc3,0xf8, +0x58,0x22,0x10,0xbd,0x00,0x00,0x09,0x40,0x24,0x00,0x03,0x40,0x08,0x13,0x00,0x50, +0x1c,0x00,0x03,0x40,0x64,0x20,0x03,0x40,0xa8,0x20,0x03,0x40,0x30,0x20,0x03,0x40, +0x34,0x20,0x03,0x40,0x2d,0xe9,0xf8,0x4f,0xd4,0x4d,0x29,0x68,0x11,0xf0,0x01,0x01, +0x40,0xf0,0x95,0x81,0xdf,0xf8,0x90,0xe3,0x05,0x27,0xd1,0x4b,0xce,0xf8,0x00,0x70, +0x1b,0x68,0x4f,0xf4,0x40,0x72,0xc3,0xf3,0x03,0x23,0x01,0x33,0xb2,0xfb,0xf3,0xf3, +0xdf,0xf8,0x78,0xc3,0xdf,0xf8,0x78,0x83,0xdc,0xf8,0x00,0x20,0xd8,0xf8,0x00,0x40, +0x92,0xb2,0x5a,0x43,0xc2,0xf3,0x8f,0x16,0x22,0x0c,0x12,0x04,0x32,0x43,0xc8,0xf8, +0x00,0x20,0xc4,0x4a,0xc4,0x4c,0x12,0x68,0x26,0x68,0x5a,0x43,0xc3,0x4e,0x92,0x09, +0x22,0x60,0x32,0x68,0x54,0xf8,0x24,0x8c,0xc2,0xf3,0x07,0x42,0x5a,0x43,0x28,0xf0, +0xff,0x08,0xc2,0xf3,0x87,0x12,0xdf,0xf8,0x3c,0x93,0x42,0xea,0x08,0x02,0xdf,0xf8, +0x38,0x83,0x44,0xf8,0x24,0x2c,0xd9,0xf8,0x00,0xa0,0xd8,0xf8,0x00,0x20,0xca,0xf3, +0x07,0x4a,0x22,0xf0,0xff,0x02,0x4a,0xea,0x02,0x02,0xc8,0xf8,0x00,0x20,0xd9,0xf8, +0x00,0x20,0xdf,0xf8,0x18,0xa3,0x12,0x0e,0x5a,0x43,0xda,0xf8,0x00,0x80,0x92,0x00, +0x28,0xf4,0x7f,0x48,0x02,0xf4,0x7f,0x42,0x42,0xea,0x08,0x02,0xdf,0xf8,0x00,0x83, +0xca,0xf8,0x00,0x20,0xd8,0xf8,0x00,0x20,0xae,0xf5,0x09,0x7e,0x4f,0xea,0x12,0x6b, +0x0b,0xfb,0x03,0xfb,0xda,0xf8,0x04,0x20,0xcb,0xf3,0x8f,0x1b,0x12,0x0c,0x12,0x04, +0x4b,0xea,0x02,0x02,0xca,0xf8,0x04,0x20,0xd9,0xf8,0x00,0x20,0xc2,0xf3,0x07,0x22, +0x53,0x43,0x9f,0x4a,0x9b,0x00,0xd2,0xf8,0x00,0x90,0x03,0xf4,0x7f,0x43,0x29,0xf4, +0x7f,0x49,0x43,0xea,0x09,0x03,0xdf,0xf8,0xbc,0x92,0x13,0x60,0xd9,0xf8,0x00,0xa0, +0x52,0xf8,0x24,0x3c,0x4f,0xea,0x1a,0x6a,0x23,0xf4,0x7f,0x43,0x43,0xea,0x0a,0x23, +0x42,0xf8,0x24,0x3c,0xd9,0xf8,0x00,0xa0,0x52,0xf8,0x24,0x3c,0xca,0xf3,0x07,0x4a, +0x23,0xf0,0xff,0x03,0x4a,0xea,0x03,0x03,0x42,0xf8,0x24,0x3c,0xd9,0xf8,0x00,0xa0, +0x52,0xf8,0x1c,0x3c,0x0a,0xf4,0x7f,0x4a,0x23,0xf4,0x7f,0x43,0x4a,0xea,0x03,0x03, +0x42,0xf8,0x1c,0x3c,0xd9,0xf8,0x00,0x90,0x52,0xf8,0x1c,0x3c,0x5f,0xfa,0x89,0xf9, +0x23,0xf0,0xff,0x03,0x49,0xea,0x03,0x03,0xdf,0xf8,0x5c,0x92,0x42,0xf8,0x1c,0x3c, +0x32,0x68,0xd9,0xf8,0x00,0x30,0x02,0xf4,0x70,0x42,0x23,0xf4,0x70,0x43,0x13,0x43, +0xc9,0xf8,0x00,0x30,0xd8,0xf8,0x00,0x20,0xdf,0xf8,0x40,0x82,0x02,0xf4,0x70,0x42, +0xd8,0xf8,0x00,0x30,0x23,0xf4,0x70,0x43,0x13,0x43,0xc8,0xf8,0x00,0x30,0x32,0x68, +0x54,0xf8,0x24,0x3c,0x12,0x0e,0x23,0xf4,0x7f,0x43,0x43,0xea,0x02,0x23,0x44,0xf8, +0x24,0x3c,0x70,0x4b,0x1b,0x68,0x62,0x6a,0xc3,0xf3,0x0b,0x06,0x22,0xf4,0x7f,0x63, +0x23,0xf0,0x0f,0x03,0x33,0x43,0x6c,0x4e,0x63,0x62,0x32,0x68,0x63,0x6a,0x02,0xf4, +0x70,0x22,0x23,0xf4,0x70,0x23,0x13,0x43,0x63,0x62,0x68,0x4c,0x22,0x68,0xd8,0xf8, +0x58,0x30,0xc2,0xf3,0x83,0x42,0x23,0xf4,0x70,0x23,0x43,0xea,0x02,0x43,0xc8,0xf8, +0x58,0x30,0xdc,0xf8,0x00,0x30,0xd8,0xf8,0x58,0x20,0xc3,0xf3,0x0b,0x4c,0x22,0xf4, +0x7f,0x63,0x23,0xf0,0x0f,0x03,0x4c,0xea,0x03,0x03,0xc8,0xf8,0x58,0x30,0x23,0x68, +0xd8,0xf8,0x5c,0x20,0x4f,0xea,0xd3,0x5c,0x22,0xf0,0xff,0x73,0x23,0xf4,0x80,0x33, +0x43,0xea,0x0c,0x43,0xc8,0xf8,0x5c,0x30,0x33,0x68,0x55,0x4a,0x0f,0x33,0x03,0xf0, +0x0f,0x03,0x13,0x60,0x26,0x68,0x53,0x68,0xc6,0xf3,0x80,0x56,0x23,0xf4,0x00,0x03, +0x43,0xea,0xc6,0x53,0x53,0x60,0x53,0x68,0x4e,0x4e,0x43,0xf4,0x80,0x43,0x53,0x60, +0x02,0x23,0xce,0xf8,0x24,0x32,0x4a,0xf6,0xaa,0x23,0xdf,0xf8,0x74,0xc1,0xce,0xf8, +0x00,0x30,0xdc,0xf8,0x00,0x30,0x32,0x68,0x03,0xf0,0x0f,0x08,0x22,0xf4,0x7f,0x02, +0x42,0xea,0x08,0x42,0xc3,0xf3,0x03,0x23,0x42,0xea,0x03,0x53,0xdf,0xf8,0x54,0x81, +0x33,0x60,0xd8,0xf8,0x00,0x30,0x32,0x68,0xc3,0xf3,0x03,0x49,0x22,0xf0,0xff,0x02, +0x49,0xea,0x02,0x02,0xc3,0xf3,0x03,0x63,0x42,0xea,0x03,0x13,0x33,0x60,0xdc,0xf8, +0x00,0x60,0xdf,0xf8,0x34,0xc1,0x06,0xf4,0x70,0x22,0xdc,0xf8,0x00,0x30,0x23,0xf4, +0x7f,0x03,0x1a,0x43,0xc6,0xf3,0x03,0x63,0x42,0xea,0x03,0x53,0x32,0x4e,0xcc,0xf8, +0x00,0x30,0x32,0x68,0x5c,0xf8,0x08,0x3c,0xc2,0xf3,0x03,0x22,0x23,0xf0,0x0f,0x03, +0x13,0x43,0x4c,0xf8,0x08,0x3c,0xd8,0xf8,0x00,0x20,0xdc,0xf8,0x08,0x30,0x02,0xf4, +0xf8,0x52,0x23,0xf4,0xf8,0x53,0x13,0x43,0xcc,0xf8,0x08,0x30,0x32,0x68,0xdc,0xf8, +0x0c,0x30,0x12,0x0b,0x02,0xf4,0x70,0x42,0x23,0xf4,0x70,0x43,0x13,0x43,0xcc,0xf8, +0x0c,0x30,0x32,0x68,0x21,0x4e,0xc2,0xf3,0x04,0x42,0x33,0x68,0x23,0xf0,0x1f,0x03, +0x13,0x43,0x33,0x60,0x22,0x68,0x1e,0x4c,0xc2,0xf3,0x01,0x42,0x23,0x68,0x23,0xf4, +0x40,0x13,0x43,0xea,0x02,0x53,0x23,0x60,0x45,0xf2,0xaa,0x53,0x19,0x4a,0xce,0xf8, +0x00,0x30,0x17,0x60,0x2b,0x68,0x43,0xf0,0x01,0x03,0x2b,0x60,0x11,0x60,0x16,0x4b, +0x16,0x4c,0x1b,0x68,0x16,0x4a,0x13,0xf0,0x02,0x0f,0x23,0x68,0x15,0x4d,0x43,0xf0, +0x02,0x03,0x23,0x60,0x13,0x68,0x21,0x68,0x59,0xd0,0x3f,0xe0,0x40,0x00,0x03,0x40, +0x00,0x20,0x03,0x40,0x8c,0x11,0x00,0x50,0x44,0x22,0x03,0x40,0x74,0x11,0x00,0x50, +0x34,0x22,0x03,0x40,0x84,0x11,0x00,0x50,0x80,0x11,0x00,0x50,0xb0,0x12,0x00,0x50, +0x78,0x22,0x03,0x40,0x84,0x20,0x03,0x40,0x98,0x11,0x00,0x50,0x98,0x20,0x03,0x40, +0xa8,0x20,0x03,0x40,0x3c,0x00,0x03,0x40,0x00,0x00,0x09,0x40,0x24,0x00,0x03,0x40, +0x08,0x13,0x00,0x50,0x1c,0x00,0x03,0x40,0x88,0x22,0x03,0x40,0x88,0x11,0x00,0x50, +0x40,0x22,0x03,0x40,0x78,0x11,0x00,0x50,0x24,0x22,0x03,0x40,0x28,0x22,0x03,0x40, +0x7c,0x11,0x00,0x50,0x70,0x11,0x00,0x50,0x1c,0x22,0x03,0x40,0x14,0x22,0x03,0x40, +0x90,0x11,0x00,0x50,0x94,0x11,0x00,0x50,0x88,0x20,0x03,0x40,0x21,0xf4,0xe1,0x72, +0xc3,0xf3,0xc1,0x46,0x22,0xf0,0x01,0x02,0xc3,0xf3,0xc0,0x51,0x32,0x43,0x42,0xea, +0x01,0x22,0xc3,0xf3,0x41,0x51,0x42,0xea,0x81,0x12,0x22,0x60,0x22,0x68,0xd7,0x07, +0x02,0xd5,0x2a,0x68,0x56,0x07,0xfc,0xd5,0xc3,0xf3,0x02,0x43,0x16,0xe0,0xc3,0xf3, +0xc1,0x62,0xde,0x0f,0x42,0xea,0x06,0x26,0x21,0xf4,0xe1,0x72,0x22,0xf0,0x01,0x02, +0x32,0x43,0xc3,0xf3,0x41,0x71,0x42,0xea,0x81,0x12,0x22,0x60,0x22,0x68,0xd4,0x07, +0x02,0xd5,0x2a,0x68,0x51,0x07,0xfc,0xd5,0xc3,0xf3,0x02,0x63,0x4a,0xf6,0xaa,0x22, +0x3a,0x49,0x3b,0x4c,0x0a,0x60,0x22,0x68,0x1b,0x03,0xb3,0xf5,0xe0,0x4f,0x22,0xf4, +0xe2,0x42,0x18,0xbf,0x43,0xf4,0x80,0x73,0x13,0x43,0x23,0x60,0x45,0xf2,0xaa,0x53, +0x4f,0xf6,0xff,0x74,0x0b,0x60,0x33,0x4b,0x00,0x21,0x01,0x22,0x19,0x60,0x43,0xf8, +0x20,0x2c,0x31,0x4a,0x4f,0xf0,0x05,0x0e,0x14,0x60,0x30,0x4c,0x43,0xf8,0x20,0x1c, +0x02,0xf5,0xec,0x72,0x10,0x23,0xc4,0xf8,0x00,0xe0,0x13,0x60,0x2c,0x4b,0x15,0x26, +0x1e,0x60,0x02,0x26,0x26,0x60,0x2b,0x4e,0x37,0x68,0xc4,0xf8,0x00,0xe0,0xdf,0xf8, +0xb4,0xe0,0xce,0xf8,0x00,0x10,0xce,0xf8,0x04,0x10,0x18,0xb1,0x31,0x68,0x41,0xf4, +0x00,0x01,0x31,0x60,0x02,0x21,0x05,0x20,0x21,0x60,0x20,0x60,0x08,0x20,0x10,0x60, +0x15,0x22,0x1a,0x60,0x21,0x60,0x2b,0x68,0x9a,0x07,0xfc,0xd4,0x1e,0x4b,0x1b,0x68, +0x13,0xf0,0x10,0x0f,0x14,0xbf,0x04,0x25,0x00,0x25,0xff,0xf7,0x1b,0xfd,0x3b,0x02, +0x07,0xd4,0x05,0x23,0x23,0x60,0x33,0x68,0x23,0xf4,0x00,0x03,0x33,0x60,0x02,0x23, +0x23,0x60,0xbd,0xb9,0x15,0x4b,0x16,0x48,0x19,0x68,0x03,0xf5,0x10,0x53,0x04,0x33, +0x1a,0x68,0xc9,0xb2,0x02,0xf0,0x0f,0x02,0x51,0x43,0x1b,0x68,0x14,0x22,0x03,0xf0, +0x0f,0x03,0x9b,0x02,0xc3,0xeb,0x81,0x21,0x01,0xf6,0xd8,0x71,0xbd,0xe8,0xf8,0x4f, +0xff,0xf7,0xea,0xbc,0x28,0x46,0xbd,0xe8,0xf8,0x8f,0x00,0xbf,0x64,0x20,0x03,0x40, +0xa8,0x20,0x03,0x40,0x50,0x20,0x03,0x40,0x34,0x20,0x03,0x40,0x88,0x22,0x03,0x40, +0xb4,0x22,0x03,0x40,0x7c,0x22,0x03,0x40,0x54,0x20,0x03,0x40,0x2c,0x00,0x03,0x40, +0xf4,0x0e,0x00,0x20,0xc0,0x22,0x03,0x40,0x08,0xb5,0x01,0x1c,0x00,0x22,0x00,0x20, +0x00,0x23,0x00,0xf0,0xeb,0xf8,0x08,0xbc,0x02,0xbc,0x08,0x47,0x10,0xb5,0x00,0x21, +0x04,0x1c,0x00,0xf0,0x5d,0xf9,0x05,0x4b,0x18,0x68,0xc3,0x6b,0x00,0x2b,0x01,0xd0, +0x00,0xf0,0x06,0xf8,0x20,0x1c,0xff,0xf7,0xa7,0xfc,0xc0,0x46,0x0c,0x0f,0x00,0x20, +0x18,0x47,0xc0,0x46,0x38,0xb5,0x0a,0x4b,0x0a,0x4c,0xe4,0x1a,0xa4,0x10,0x0a,0xd0, +0x09,0x4a,0xa5,0x18,0xad,0x00,0xed,0x18,0x2b,0x68,0x01,0x3c,0x00,0xf0,0x0e,0xf8, +0x04,0x3d,0x00,0x2c,0xf8,0xd1,0x00,0xf0,0xcd,0xf9,0x38,0xbc,0x01,0xbc,0x00,0x47, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x3f,0x18,0x47,0xc0,0x46, +0x70,0xb5,0x10,0x4e,0x10,0x4d,0xad,0x1b,0xad,0x10,0x00,0x24,0x00,0x2d,0x06,0xd0, +0xa3,0x00,0xf3,0x58,0x01,0x34,0x00,0xf0,0x1d,0xf8,0xa5,0x42,0xf8,0xd1,0x00,0xf0, +0xab,0xf9,0x0a,0x4e,0x0a,0x4d,0xad,0x1b,0xad,0x10,0x00,0x24,0x00,0x2d,0x06,0xd0, +0xa3,0x00,0xf3,0x58,0x01,0x34,0x00,0xf0,0x0d,0xf8,0xa5,0x42,0xf8,0xd1,0x70,0xbc, +0x01,0xbc,0x00,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x18,0x47,0xc0,0x46,0x70,0xb5,0x0f,0x2a,0x34,0xd9,0x04,0x1c, +0x0c,0x43,0x0b,0x1c,0xa4,0x07,0x33,0xd1,0x15,0x1c,0x04,0x1c,0x10,0x3d,0x2d,0x09, +0x01,0x35,0x2d,0x01,0x49,0x19,0x1e,0x68,0x26,0x60,0x5e,0x68,0x66,0x60,0x9e,0x68, +0xa6,0x60,0xde,0x68,0x10,0x33,0xe6,0x60,0x10,0x34,0x99,0x42,0xf3,0xd1,0x0f,0x23, +0x45,0x19,0x13,0x40,0x03,0x2b,0x1d,0xd9,0x1c,0x1f,0x00,0x23,0xa4,0x08,0x01,0x34, +0xa4,0x00,0xce,0x58,0xee,0x50,0x04,0x33,0xa3,0x42,0xfa,0xd1,0xed,0x18,0xc9,0x18, +0x03,0x23,0x1a,0x40,0x05,0xd0,0x00,0x23,0xcc,0x5c,0xec,0x54,0x01,0x33,0x93,0x42, +0xfa,0xd1,0x70,0xbc,0x02,0xbc,0x08,0x47,0x05,0x1c,0x00,0x2a,0xf3,0xd1,0xf8,0xe7, +0x05,0x1c,0xf0,0xe7,0x1a,0x1c,0xf8,0xe7,0x70,0xb5,0x83,0x07,0x43,0xd0,0x54,0x1e, +0x00,0x2a,0x3d,0xd0,0x0d,0x06,0x2d,0x0e,0x03,0x1c,0x03,0x26,0x03,0xe0,0x62,0x1e, +0x00,0x2c,0x35,0xd0,0x14,0x1c,0x01,0x33,0x5a,0x1e,0x15,0x70,0x33,0x42,0xf6,0xd1, +0x03,0x2c,0x24,0xd9,0xff,0x25,0x0d,0x40,0x2a,0x02,0x15,0x43,0x2a,0x04,0x15,0x43, +0x0f,0x2c,0x11,0xd9,0x26,0x1c,0x10,0x3e,0x36,0x09,0x01,0x36,0x36,0x01,0x1a,0x1c, +0x9b,0x19,0x15,0x60,0x55,0x60,0x95,0x60,0xd5,0x60,0x10,0x32,0x93,0x42,0xf8,0xd1, +0x0f,0x22,0x14,0x40,0x03,0x2c,0x0a,0xd9,0x26,0x1f,0xb6,0x08,0x01,0x36,0xb6,0x00, +0x1a,0x1c,0x9b,0x19,0x20,0xc2,0x93,0x42,0xfc,0xd1,0x03,0x22,0x14,0x40,0x00,0x2c, +0x06,0xd0,0x09,0x06,0x1c,0x19,0x09,0x0e,0x19,0x70,0x01,0x33,0xa3,0x42,0xfb,0xd1, +0x70,0xbc,0x02,0xbc,0x08,0x47,0x14,0x1c,0x03,0x1c,0xc9,0xe7,0xf8,0xb5,0x44,0x46, +0x5f,0x46,0x56,0x46,0x4d,0x46,0x9b,0x46,0x30,0x4b,0xf0,0xb4,0x1c,0x68,0xa4,0x23, +0x5b,0x00,0x05,0x1c,0xe0,0x58,0x0e,0x1c,0x90,0x46,0x00,0x28,0x4d,0xd0,0x43,0x68, +0x1f,0x2b,0x0f,0xdc,0x5c,0x1c,0x00,0x2d,0x23,0xd1,0x02,0x33,0x9b,0x00,0x44,0x60, +0x1e,0x50,0x00,0x20,0x3c,0xbc,0x90,0x46,0x99,0x46,0xa2,0x46,0xab,0x46,0xf8,0xbc, +0x02,0xbc,0x08,0x47,0x22,0x4b,0x00,0x2b,0x3c,0xd0,0xc8,0x20,0x40,0x00,0xaf,0xf3, +0x00,0x80,0x00,0x28,0x36,0xd0,0xa4,0x22,0x00,0x23,0x52,0x00,0xa1,0x58,0x43,0x60, +0x01,0x60,0xa0,0x50,0x40,0x32,0x83,0x50,0x04,0x32,0x83,0x50,0x01,0x24,0x00,0x2d, +0xdb,0xd0,0x9a,0x00,0x91,0x46,0x81,0x44,0x42,0x46,0x88,0x21,0x4f,0x46,0x7a,0x50, +0xc4,0x22,0x52,0x00,0x90,0x46,0x80,0x44,0x42,0x46,0x87,0x39,0x99,0x40,0x12,0x68, +0x0a,0x43,0x94,0x46,0x8a,0x46,0x42,0x46,0x61,0x46,0x11,0x60,0x84,0x22,0x49,0x46, +0x5f,0x46,0x52,0x00,0x8f,0x50,0x02,0x2d,0xbf,0xd1,0x02,0x1c,0x55,0x46,0x8d,0x32, +0xff,0x32,0x11,0x68,0x0d,0x43,0x15,0x60,0xb7,0xe7,0x20,0x1c,0x4d,0x30,0xff,0x30, +0xe0,0x50,0xac,0xe7,0x01,0x20,0x40,0x42,0xb4,0xe7,0xc0,0x46,0x0c,0x0f,0x00,0x20, +0x00,0x00,0x00,0x00,0x08,0xb5,0x04,0x4b,0x00,0x2b,0x02,0xd0,0x03,0x48,0xff,0xf7, +0x9b,0xfe,0x08,0xbc,0x01,0xbc,0x00,0x47,0x00,0x00,0x00,0x00,0x15,0x0b,0x00,0x20, +0xf0,0xb5,0x56,0x46,0x5f,0x46,0x4d,0x46,0x44,0x46,0xf0,0xb4,0x0e,0x1c,0x3f,0x4b, +0x1b,0x68,0x87,0xb0,0x03,0x93,0x49,0x33,0xff,0x33,0x01,0x90,0x04,0x93,0xa4,0x22, +0x03,0x9b,0x52,0x00,0x9f,0x58,0x00,0x2f,0x4d,0xd0,0x04,0x9b,0x98,0x46,0x00,0x23, +0x9b,0x46,0xc4,0x23,0x5b,0x00,0x9c,0x46,0xbc,0x44,0x63,0x46,0x02,0x93,0xc6,0x23, +0x5b,0x00,0x9a,0x46,0x7c,0x68,0xa5,0x00,0x7d,0x19,0xba,0x44,0x01,0x3c,0x08,0xd5, +0x27,0xe0,0x6b,0x1d,0xff,0x33,0x1b,0x68,0xb3,0x42,0x04,0xd0,0x04,0x3d,0x01,0x3c, +0x1f,0xd3,0x00,0x2e,0xf5,0xd1,0x7b,0x68,0x01,0x3b,0x6a,0x68,0xa3,0x42,0x3e,0xd0, +0x5b,0x46,0x6b,0x60,0x00,0x2a,0xf1,0xd0,0x7b,0x68,0x99,0x46,0x01,0x23,0xa3,0x40, +0x02,0x99,0x09,0x68,0x05,0x91,0x19,0x42,0x26,0xd1,0x00,0xf0,0x43,0xf8,0x7b,0x68, +0x4b,0x45,0xc4,0xd1,0x43,0x46,0x1b,0x68,0xbb,0x42,0xc0,0xd1,0x04,0x3d,0x01,0x3c, +0xdf,0xd2,0x1b,0x4b,0x00,0x2b,0x0e,0xd0,0x7b,0x68,0x00,0x2b,0x27,0xd1,0x3b,0x68, +0x00,0x2b,0x28,0xd0,0x42,0x46,0x38,0x1c,0x13,0x60,0xaf,0xf3,0x00,0x80,0x43,0x46, +0x1f,0x68,0x00,0x2f,0xb5,0xd1,0x07,0xb0,0x3c,0xbc,0x90,0x46,0x99,0x46,0xa2,0x46, +0xab,0x46,0xf0,0xbc,0x01,0xbc,0x00,0x47,0x51,0x46,0x09,0x68,0x19,0x42,0x08,0xd1, +0x2b,0x1c,0x84,0x33,0x19,0x68,0x01,0x98,0x00,0xf0,0x14,0xf8,0xcf,0xe7,0x7c,0x60, +0xc0,0xe7,0x2b,0x1c,0x84,0x33,0x18,0x68,0x00,0xf0,0x0c,0xf8,0xc7,0xe7,0x3b,0x68, +0xb8,0x46,0x1f,0x1c,0xdd,0xe7,0x00,0x23,0xfa,0xe7,0xc0,0x46,0x0c,0x0f,0x00,0x20, +0x00,0x00,0x00,0x00,0x10,0x47,0xc0,0x46,0xf8,0xb5,0xc0,0x46,0xf8,0xbc,0x08,0xbc, +0x9e,0x46,0x70,0x47,0xf8,0xb5,0xc0,0x46,0xf8,0xbc,0x08,0xbc,0x9e,0x46,0x70,0x47, +0x00,0x00,0x00,0x00,0x24,0xf2,0xff,0x7f,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x28,0x15,0x00,0x20,0xff,0xff,0xff,0xc5,0xff,0xff,0xff,0xff,0xc5,0xff,0xff,0xff, +0xc5,0xc5,0xc5,0xff,0xc5,0xc5,0xc5,0xff,0x43,0x00,0x00,0x00,0x18,0x0f,0x00,0x20, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x12,0x00,0x20, +0x6c,0x12,0x00,0x20,0xd4,0x12,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x0f,0x00,0x20, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x33,0xcd,0xab,0x34,0x12,0x6d,0xe6, +0xec,0xde,0x05,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x0f,0x00,0x20,0xc1,0x00,0x00,0x20,0x91,0x00,0x00,0x20,0x00,0x00,0x00,0x00, +0x95,0x0d,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, diff --git a/contrib/loaders/flash/cc26xx/cc26x2/cc26x2r1f.lds b/contrib/loaders/flash/cc26xx/cc26x2/cc26x2r1f.lds new file mode 100644 index 000000000..fb7cc5611 --- /dev/null +++ b/contrib/loaders/flash/cc26xx/cc26x2/cc26x2r1f.lds @@ -0,0 +1,90 @@ +/****************************************************************************** +* +* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +/* Entry Point */ +ENTRY( entry ) + +/* System memory map */ +MEMORY +{ + /* Application is stored in and executes from SRAM */ + PROGRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0x1FD8 + BUFFERS (RWX) : ORIGIN = 0x20001FD8, LENGTH = 0x6028 +} + +/* Section allocation in memory */ +SECTIONS +{ + .text : + { + _text = .; + *(.entry*) + *(.text*) + _etext = .; + } > PROGRAM + + .data : + { _data = .; + *(.rodata*) + *(.data*) + _edata = .; + } + + .bss : + { + __bss_start__ = .; + _bss = .; + *(.bss*) + *(COMMON) + _ebss = .; + __bss_end__ = .; + } > PROGRAM + + .stack : + { + _stack = .; + *(.stack*) + _estack = .; + } > PROGRAM + + .buffers : + { + _buffers = .; + *(.buffers.g_cfg) + *(.buffers.g_buf1) + *(.buffers.g_buf2) + *(.buffers*) + _ebuffers = .; + } > BUFFERS +} diff --git a/contrib/loaders/flash/cc26xx/cc26x2_algo.inc b/contrib/loaders/flash/cc26xx/cc26x2_algo.inc new file mode 100644 index 000000000..9adb919f4 --- /dev/null +++ b/contrib/loaders/flash/cc26xx/cc26x2_algo.inc @@ -0,0 +1,2049 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x08,0xb5,0x00,0xbf,0x00,0xbf,0x00,0xbf,0x00,0xbf,0xdf,0xf8,0x1c,0xd0,0x07,0x48, +0x07,0x49,0x4f,0xf0,0x00,0x02,0x88,0x42,0xb8,0xbf,0x40,0xf8,0x04,0x2b,0xfa,0xdb, +0x00,0xf0,0xa8,0xf9,0xfe,0xe7,0x00,0x00,0xf0,0x0e,0x00,0x20,0x54,0x13,0x00,0x20, +0xfc,0x13,0x00,0x20,0x08,0xb5,0x07,0x4b,0x07,0x48,0x03,0x33,0x1b,0x1a,0x06,0x2b, +0x04,0xd9,0x06,0x4b,0x00,0x2b,0x01,0xd0,0x00,0xf0,0x5c,0xf8,0x08,0xbc,0x01,0xbc, +0x00,0x47,0xc0,0x46,0x50,0x13,0x00,0x20,0x50,0x13,0x00,0x20,0x00,0x00,0x00,0x00, +0x08,0x48,0x09,0x49,0x09,0x1a,0x89,0x10,0x08,0xb5,0xcb,0x0f,0x59,0x18,0x49,0x10, +0x04,0xd0,0x06,0x4b,0x00,0x2b,0x01,0xd0,0x00,0xf0,0x44,0xf8,0x08,0xbc,0x01,0xbc, +0x00,0x47,0xc0,0x46,0x50,0x13,0x00,0x20,0x50,0x13,0x00,0x20,0x00,0x00,0x00,0x00, +0x10,0xb5,0x08,0x4c,0x23,0x78,0x00,0x2b,0x09,0xd1,0xff,0xf7,0xcb,0xff,0x06,0x4b, +0x00,0x2b,0x02,0xd0,0x05,0x48,0xaf,0xf3,0x00,0x80,0x01,0x23,0x23,0x70,0x10,0xbc, +0x01,0xbc,0x00,0x47,0x54,0x13,0x00,0x20,0x00,0x00,0x00,0x00,0xe0,0x0e,0x00,0x20, +0x08,0xb5,0x0b,0x4b,0x00,0x2b,0x03,0xd0,0x0a,0x48,0x0b,0x49,0xaf,0xf3,0x00,0x80, +0x0a,0x48,0x03,0x68,0x00,0x2b,0x04,0xd1,0xff,0xf7,0xc2,0xff,0x08,0xbc,0x01,0xbc, +0x00,0x47,0x07,0x4b,0x00,0x2b,0xf7,0xd0,0x00,0xf0,0x0c,0xf8,0xf4,0xe7,0xc0,0x46, +0x00,0x00,0x00,0x00,0xe0,0x0e,0x00,0x20,0x58,0x13,0x00,0x20,0x4c,0x13,0x00,0x20, +0x00,0x00,0x00,0x00,0x18,0x47,0xc0,0x46,0xd4,0x30,0x9f,0xe5,0x00,0x00,0x53,0xe3, +0xc8,0x30,0x9f,0x05,0x03,0xd0,0xa0,0xe1,0x00,0x20,0x0f,0xe1,0x0f,0x00,0x12,0xe3, +0x15,0x00,0x00,0x0a,0xd1,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1,0x01,0xaa,0x4d,0xe2, +0x0a,0x30,0xa0,0xe1,0xd7,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1,0x01,0x3a,0x43,0xe2, +0xdb,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1,0x01,0x3a,0x43,0xe2,0xd2,0xf0,0x21,0xe3, +0x03,0xd0,0xa0,0xe1,0x02,0x3a,0x43,0xe2,0xd3,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1, +0x02,0x39,0x43,0xe2,0xff,0x30,0xc3,0xe3,0xff,0x3c,0xc3,0xe3,0x04,0x30,0x03,0xe5, +0x00,0x20,0x53,0xe9,0xc0,0x20,0x82,0xe3,0x02,0xf0,0x21,0xe1,0x01,0xa8,0x43,0xe2, +0x00,0x10,0xb0,0xe3,0x01,0xb0,0xa0,0xe1,0x01,0x70,0xa0,0xe1,0x5c,0x00,0x9f,0xe5, +0x5c,0x20,0x9f,0xe5,0x00,0x20,0x52,0xe0,0x01,0x30,0x8f,0xe2,0x13,0xff,0x2f,0xe1, +0x00,0xf0,0x42,0xfd,0x10,0x4b,0x00,0x2b,0x01,0xd0,0xfe,0x46,0x9f,0x46,0x0f,0x4b, +0x00,0x2b,0x01,0xd0,0xfe,0x46,0x9f,0x46,0x00,0x20,0x00,0x21,0x04,0x00,0x0d,0x00, +0x0d,0x48,0x00,0xf0,0x89,0xfc,0x00,0xf0,0xc3,0xfc,0x20,0x00,0x29,0x00,0x00,0xf0, +0xd1,0xf8,0x00,0xf0,0x8b,0xfc,0x7b,0x46,0x18,0x47,0x00,0x00,0x11,0x00,0x00,0xef, +0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x54,0x13,0x00,0x20,0xfc,0x13,0x00,0x20,0x15,0x0b,0x00,0x20,0x70,0xb5,0x04,0x46, +0x0e,0x46,0x15,0x46,0x00,0x21,0x28,0x22,0x00,0xf0,0x0e,0xfd,0x26,0x61,0x65,0x62, +0x00,0x21,0x84,0x22,0x02,0x48,0x00,0xf0,0x07,0xfd,0x00,0x20,0x70,0xbd,0x00,0xbf, +0x70,0x13,0x00,0x20,0x10,0xb5,0x01,0x20,0x00,0xf0,0xac,0xf9,0x04,0x46,0x28,0xb9, +0x01,0x21,0x84,0x22,0x03,0x48,0x00,0xf0,0xf7,0xfc,0x01,0xe0,0x40,0xf2,0x01,0x14, +0x20,0x46,0x10,0xbd,0x70,0x13,0x00,0x20,0x01,0x39,0xf8,0xb5,0x44,0x0b,0x08,0x44, +0x45,0x0b,0x66,0x03,0xac,0x42,0x14,0xd8,0x0b,0x4f,0xe3,0x5d,0x6b,0xb9,0x30,0x46, +0x00,0xf0,0xfc,0xf8,0x38,0xb1,0x00,0x04,0x00,0xf4,0x7f,0x00,0x40,0xea,0x04,0x60, +0x40,0xf4,0x81,0x70,0xf8,0xbd,0x01,0x23,0xe3,0x55,0x01,0x34,0x06,0xf5,0x00,0x56, +0xe8,0xe7,0x00,0x20,0xf8,0xbd,0x00,0xbf,0x70,0x13,0x00,0x20,0x2d,0xe9,0xf0,0x4f, +0x53,0x1e,0x85,0xb0,0x0b,0x44,0x02,0x90,0x0d,0x46,0x4f,0xea,0x51,0x38,0x5b,0x0b, +0x16,0x46,0x23,0x48,0x01,0x93,0x00,0x21,0x84,0x22,0x00,0xf0,0xbd,0xfc,0x4f,0xea, +0x48,0x37,0xc5,0xf3,0x0c,0x0c,0x4f,0xf0,0x00,0x09,0x01,0x9b,0x98,0x45,0x32,0xd8, +0x74,0x19,0xdf,0xf8,0x70,0xb0,0xcd,0xf8,0x0c,0xc0,0x07,0xf5,0x00,0x5a,0x54,0x45, +0x88,0xbf,0xc4,0xf3,0x0c,0x04,0x39,0x46,0x4f,0xf4,0x00,0x52,0x58,0x46,0x8c,0xbf, +0x34,0x1b,0x34,0x46,0x00,0xf0,0x60,0xfc,0xdd,0xf8,0x0c,0xc0,0x02,0x9b,0x0b,0xeb, +0x0c,0x00,0x03,0xeb,0x09,0x01,0x22,0x46,0x00,0xf0,0x56,0xfc,0x38,0x46,0x4f,0xf4, +0x00,0x51,0x08,0xf1,0x01,0x08,0xff,0xf7,0x9f,0xff,0x68,0xb9,0x39,0x46,0x58,0x46, +0x4f,0xf4,0x00,0x52,0x25,0x44,0x00,0xf0,0xaf,0xf8,0x36,0x1b,0xc5,0xf3,0x0c,0x0c, +0xa1,0x44,0x57,0x46,0xc9,0xe7,0x00,0x20,0x05,0xb0,0xbd,0xe8,0xf0,0x8f,0x00,0xbf, +0x70,0x13,0x00,0x20,0x00,0x60,0x00,0x20,0xb2,0xf5,0x00,0x5f,0xf8,0xb5,0x07,0x46, +0x0e,0x46,0x15,0x46,0x0b,0xd8,0x08,0x46,0x11,0x46,0xff,0xf7,0x7d,0xff,0x04,0x46, +0x40,0xb9,0x38,0x46,0x31,0x46,0x2a,0x46,0x00,0xf0,0x8e,0xf8,0x02,0xe0,0x4f,0xf4, +0x82,0x70,0xf8,0xbd,0x20,0x46,0xf8,0xbd,0x08,0xb5,0x00,0xf0,0x85,0xf8,0x00,0x20, +0x08,0xbd,0x00,0x00,0xf8,0xb5,0x31,0x48,0x31,0x49,0x32,0x4a,0x32,0x4c,0xff,0xf7, +0x3d,0xff,0x00,0x23,0x23,0x60,0x22,0x68,0x2c,0x4f,0x14,0x23,0x03,0xfb,0x02,0x73, +0x08,0x33,0x5b,0x68,0x00,0x2b,0xf7,0xd0,0x2c,0x4b,0x1a,0x68,0x11,0x07,0xfb,0xd4, +0x2b,0x4d,0x2c,0x4e,0x2a,0x68,0x32,0x60,0x42,0xf0,0x33,0x02,0x2a,0x60,0x1a,0x68, +0x12,0x07,0xfc,0xd4,0x21,0x68,0x14,0x22,0x02,0xfb,0x01,0x73,0x98,0x68,0x01,0x38, +0x13,0x46,0x04,0x28,0x26,0xd8,0xdf,0xe8,0x00,0xf0,0x03,0x06,0x0e,0x16,0x1e,0x00, +0xff,0xf7,0x28,0xff,0x20,0xe0,0x4b,0x43,0xfa,0x18,0x10,0x69,0xf9,0x58,0x52,0x68, +0xff,0xf7,0xc2,0xff,0x18,0xe0,0x4b,0x43,0xfa,0x18,0x10,0x69,0xf9,0x58,0x52,0x68, +0xff,0xf7,0xa2,0xff,0x10,0xe0,0x4b,0x43,0xfa,0x18,0x10,0x69,0xf9,0x58,0x52,0x68, +0xff,0xf7,0x44,0xff,0x08,0xe0,0x4b,0x43,0xfa,0x18,0xf8,0x58,0x51,0x68,0xff,0xf7, +0x1b,0xff,0x01,0xe0,0x40,0xf2,0x05,0x10,0x33,0x68,0x2b,0x60,0x0b,0x4b,0x1b,0x68, +0x1b,0x07,0xfb,0xd4,0x22,0x68,0x14,0x23,0x03,0xfb,0x02,0x77,0xfb,0x68,0xf8,0x60, +0x00,0xb1,0xfe,0xe7,0x82,0xf0,0x01,0x02,0x22,0x60,0xa4,0xe7,0xd8,0x1f,0x00,0x20, +0x00,0x20,0x00,0x20,0x00,0x40,0x00,0x20,0xf4,0x13,0x00,0x20,0x00,0x40,0x03,0x40, +0x04,0x40,0x03,0x40,0xf8,0x13,0x00,0x20,0xfe,0xe7,0x00,0x00,0x08,0xb5,0x04,0x4b, +0x1b,0x68,0x5b,0x69,0x98,0x47,0x03,0x4b,0x00,0x22,0x1a,0x60,0x08,0xbd,0x00,0xbf, +0xa8,0x01,0x00,0x10,0x84,0x04,0x60,0x42,0x08,0xb5,0x04,0x4b,0x1b,0x68,0x9b,0x69, +0x98,0x47,0x03,0x4b,0x00,0x22,0x1a,0x60,0x08,0xbd,0x00,0xbf,0xa8,0x01,0x00,0x10, +0x84,0x04,0x60,0x42,0x10,0xb5,0x33,0x4b,0x33,0x48,0x1b,0x68,0x33,0x4a,0x13,0xf0, +0x02,0x0f,0x03,0x68,0x43,0xf0,0x02,0x03,0x03,0x60,0x13,0x68,0x01,0x68,0x19,0xd0, +0x21,0xf4,0xe1,0x72,0xc3,0xf3,0xc1,0x04,0x22,0xf0,0x01,0x02,0x22,0x43,0xc3,0xf3, +0xc0,0x11,0x42,0xea,0x01,0x22,0xc3,0xf3,0x41,0x11,0x42,0xea,0x81,0x12,0x02,0x60, +0x02,0x68,0xd4,0x07,0x03,0xd5,0x26,0x4a,0x12,0x68,0x50,0x07,0xfb,0xd5,0x03,0xf0, +0x07,0x03,0x18,0xe0,0x21,0xf4,0xe1,0x72,0xc3,0xf3,0xc1,0x24,0x22,0xf0,0x01,0x02, +0xc3,0xf3,0xc0,0x31,0x22,0x43,0x42,0xea,0x01,0x22,0xc3,0xf3,0x41,0x31,0x42,0xea, +0x81,0x12,0x02,0x60,0x02,0x68,0xd1,0x07,0x03,0xd5,0x19,0x4a,0x12,0x68,0x52,0x07, +0xfb,0xd5,0xc3,0xf3,0x02,0x23,0x17,0x49,0x17,0x48,0x4a,0xf6,0xaa,0x22,0x0a,0x60, +0x02,0x68,0x1b,0x03,0xb3,0xf5,0xe0,0x4f,0x22,0xf4,0xe2,0x42,0x18,0xbf,0x43,0xf4, +0x80,0x73,0x13,0x43,0x03,0x60,0x45,0xf2,0xaa,0x53,0x0b,0x60,0x0f,0x4b,0x10,0x49, +0x01,0x22,0x1a,0x60,0x00,0x22,0x0a,0x60,0x1a,0x60,0x05,0x22,0xc3,0xf8,0x58,0x22, +0x4f,0xf0,0xff,0x32,0xc1,0xf8,0x8c,0x22,0xc1,0xf8,0x90,0x22,0x02,0x22,0xc3,0xf8, +0x58,0x22,0x10,0xbd,0x10,0x00,0x09,0x40,0x24,0x00,0x03,0x40,0x08,0x13,0x00,0x50, +0x1c,0x00,0x03,0x40,0x64,0x20,0x03,0x40,0xa8,0x20,0x03,0x40,0x30,0x20,0x03,0x40, +0x34,0x20,0x03,0x40,0x2d,0xe9,0xf8,0x4f,0xd4,0x4d,0x29,0x68,0x11,0xf0,0x01,0x01, +0x40,0xf0,0x95,0x81,0xdf,0xf8,0x90,0xe3,0xd1,0x4b,0xdf,0xf8,0x90,0xc3,0xdf,0xf8, +0x90,0x83,0xdf,0xf8,0x90,0x93,0x05,0x27,0xce,0xf8,0x00,0x70,0x1b,0x68,0xc3,0xf3, +0x03,0x23,0x4f,0xf4,0x40,0x72,0x01,0x33,0xb2,0xfb,0xf3,0xf3,0xdc,0xf8,0x00,0x20, +0xd8,0xf8,0x00,0x40,0x92,0xb2,0x5a,0x43,0xc2,0xf3,0x8f,0x16,0x22,0x0c,0x12,0x04, +0x32,0x43,0xc8,0xf8,0x00,0x20,0xc3,0x4a,0xc3,0x4c,0x12,0x68,0x26,0x68,0xc3,0x4e, +0x5a,0x43,0x92,0x09,0x22,0x60,0x32,0x68,0x54,0xf8,0x24,0x8c,0xc2,0xf3,0x07,0x42, +0x5a,0x43,0x28,0xf0,0xff,0x08,0xc2,0xf3,0x87,0x12,0x42,0xea,0x08,0x02,0xdf,0xf8, +0x38,0x83,0x44,0xf8,0x24,0x2c,0xd9,0xf8,0x00,0xa0,0xd8,0xf8,0x00,0x20,0xca,0xf3, +0x07,0x4a,0x22,0xf0,0xff,0x02,0x4a,0xea,0x02,0x02,0xc8,0xf8,0x00,0x20,0xd9,0xf8, +0x00,0x20,0xdf,0xf8,0x18,0xa3,0x12,0x0e,0xda,0xf8,0x00,0x80,0x5a,0x43,0x92,0x00, +0x28,0xf4,0x7f,0x48,0x02,0xf4,0x7f,0x42,0x42,0xea,0x08,0x02,0xdf,0xf8,0x00,0x83, +0xca,0xf8,0x00,0x20,0xd8,0xf8,0x00,0x20,0x4f,0xea,0x12,0x6b,0xda,0xf8,0x04,0x20, +0x0b,0xfb,0x03,0xfb,0x12,0x0c,0xcb,0xf3,0x8f,0x1b,0x12,0x04,0x4b,0xea,0x02,0x02, +0xca,0xf8,0x04,0x20,0xd9,0xf8,0x00,0x20,0xc2,0xf3,0x07,0x22,0x53,0x43,0xa0,0x4a, +0xd2,0xf8,0x00,0x90,0x9b,0x00,0x29,0xf4,0x7f,0x49,0x03,0xf4,0x7f,0x43,0x43,0xea, +0x09,0x03,0xdf,0xf8,0xc0,0x92,0x13,0x60,0xd9,0xf8,0x00,0xa0,0x52,0xf8,0x24,0x3c, +0x4f,0xea,0x1a,0x6a,0x23,0xf4,0x7f,0x43,0x43,0xea,0x0a,0x23,0x42,0xf8,0x24,0x3c, +0xd9,0xf8,0x00,0xa0,0x52,0xf8,0x24,0x3c,0xca,0xf3,0x07,0x4a,0x23,0xf0,0xff,0x03, +0x4a,0xea,0x03,0x03,0x42,0xf8,0x24,0x3c,0xd9,0xf8,0x00,0xa0,0x52,0xf8,0x1c,0x3c, +0x0a,0xf4,0x7f,0x4a,0x23,0xf4,0x7f,0x43,0x4a,0xea,0x03,0x03,0x42,0xf8,0x1c,0x3c, +0xd9,0xf8,0x00,0x90,0x52,0xf8,0x1c,0x3c,0x5f,0xfa,0x89,0xf9,0x23,0xf0,0xff,0x03, +0x49,0xea,0x03,0x03,0xdf,0xf8,0x60,0x92,0x42,0xf8,0x1c,0x3c,0x32,0x68,0xd9,0xf8, +0x00,0x30,0x02,0xf4,0x70,0x42,0x23,0xf4,0x70,0x43,0x13,0x43,0xc9,0xf8,0x00,0x30, +0xd8,0xf8,0x00,0x20,0xdf,0xf8,0x44,0x82,0xd8,0xf8,0x00,0x30,0x02,0xf4,0x70,0x42, +0x23,0xf4,0x70,0x43,0x13,0x43,0xc8,0xf8,0x00,0x30,0x32,0x68,0x54,0xf8,0x24,0x3c, +0x12,0x0e,0x23,0xf4,0x7f,0x43,0x43,0xea,0x02,0x23,0x44,0xf8,0x24,0x3c,0x71,0x4b, +0x1b,0x68,0x62,0x6a,0xc3,0xf3,0x0b,0x06,0x22,0xf4,0x7f,0x63,0x23,0xf0,0x0f,0x03, +0x33,0x43,0x6d,0x4e,0x63,0x62,0x32,0x68,0x63,0x6a,0x02,0xf4,0x70,0x22,0x23,0xf4, +0x70,0x23,0x13,0x43,0x63,0x62,0x69,0x4c,0x22,0x68,0xd8,0xf8,0x58,0x30,0xc2,0xf3, +0x83,0x42,0x23,0xf4,0x70,0x23,0x43,0xea,0x02,0x43,0xc8,0xf8,0x58,0x30,0xdc,0xf8, +0x00,0x30,0xd8,0xf8,0x58,0x20,0xc3,0xf3,0x0b,0x4c,0x22,0xf4,0x7f,0x63,0x23,0xf0, +0x0f,0x03,0x4c,0xea,0x03,0x03,0xc8,0xf8,0x58,0x30,0x23,0x68,0xd8,0xf8,0x5c,0x20, +0x4f,0xea,0xd3,0x5c,0x22,0xf0,0xff,0x73,0x23,0xf4,0x80,0x33,0x43,0xea,0x0c,0x43, +0xc8,0xf8,0x5c,0x30,0x33,0x68,0x56,0x4a,0xdf,0xf8,0xa4,0xc1,0x0f,0x33,0x03,0xf0, +0x0f,0x03,0x13,0x60,0x26,0x68,0x53,0x68,0xc6,0xf3,0x80,0x56,0x23,0xf4,0x00,0x03, +0x43,0xea,0xc6,0x53,0x53,0x60,0x53,0x68,0x4e,0x4e,0x43,0xf4,0x80,0x43,0x53,0x60, +0x02,0x23,0xce,0xf8,0x00,0x30,0xae,0xf5,0x09,0x7e,0x4a,0xf6,0xaa,0x23,0xce,0xf8, +0x00,0x30,0xdc,0xf8,0x00,0x30,0x32,0x68,0x03,0xf0,0x0f,0x08,0x22,0xf4,0x7f,0x02, +0x42,0xea,0x08,0x42,0xc3,0xf3,0x03,0x23,0x42,0xea,0x03,0x53,0xdf,0xf8,0x54,0x81, +0x33,0x60,0xd8,0xf8,0x00,0x30,0x32,0x68,0xc3,0xf3,0x03,0x49,0x22,0xf0,0xff,0x02, +0x49,0xea,0x02,0x02,0xc3,0xf3,0x03,0x63,0x42,0xea,0x03,0x13,0x33,0x60,0xdc,0xf8, +0x00,0x60,0xdf,0xf8,0x34,0xc1,0xdc,0xf8,0x00,0x30,0x06,0xf4,0x70,0x22,0x23,0xf4, +0x7f,0x03,0x1a,0x43,0xc6,0xf3,0x03,0x63,0x42,0xea,0x03,0x53,0x32,0x4e,0xcc,0xf8, +0x00,0x30,0x32,0x68,0x5c,0xf8,0x08,0x3c,0xc2,0xf3,0x03,0x22,0x23,0xf0,0x0f,0x03, +0x13,0x43,0x4c,0xf8,0x08,0x3c,0xd8,0xf8,0x00,0x20,0xdc,0xf8,0x08,0x30,0x02,0xf4, +0xf8,0x52,0x23,0xf4,0xf8,0x53,0x13,0x43,0xcc,0xf8,0x08,0x30,0x32,0x68,0xdc,0xf8, +0x0c,0x30,0x12,0x0b,0x02,0xf4,0x70,0x42,0x23,0xf4,0x70,0x43,0x13,0x43,0xcc,0xf8, +0x0c,0x30,0x32,0x68,0x21,0x4e,0x33,0x68,0xc2,0xf3,0x04,0x42,0x23,0xf0,0x1f,0x03, +0x13,0x43,0x33,0x60,0x22,0x68,0x1e,0x4c,0x23,0x68,0xc2,0xf3,0x01,0x42,0x23,0xf4, +0x40,0x13,0x43,0xea,0x02,0x53,0x1b,0x4a,0x23,0x60,0x45,0xf2,0xaa,0x53,0xce,0xf8, +0x00,0x30,0x17,0x60,0x2b,0x68,0x43,0xf0,0x01,0x03,0x2b,0x60,0x11,0x60,0x16,0x4b, +0x16,0x4c,0x1b,0x68,0x16,0x4a,0x17,0x4d,0x13,0xf0,0x02,0x0f,0x23,0x68,0x43,0xf0, +0x02,0x03,0x23,0x60,0x13,0x68,0x21,0x68,0x59,0xd0,0x3f,0xe0,0x40,0x00,0x03,0x40, +0x00,0x20,0x03,0x40,0x8c,0x11,0x00,0x50,0x44,0x22,0x03,0x40,0x74,0x11,0x00,0x50, +0x34,0x22,0x03,0x40,0x84,0x11,0x00,0x50,0x80,0x11,0x00,0x50,0xb0,0x12,0x00,0x50, +0x78,0x22,0x03,0x40,0x84,0x20,0x03,0x40,0x98,0x11,0x00,0x50,0x98,0x20,0x03,0x40, +0xa8,0x20,0x03,0x40,0x3c,0x00,0x03,0x40,0x10,0x00,0x09,0x40,0x24,0x00,0x03,0x40, +0x08,0x13,0x00,0x50,0x1c,0x00,0x03,0x40,0x88,0x22,0x03,0x40,0x88,0x11,0x00,0x50, +0x40,0x22,0x03,0x40,0x78,0x11,0x00,0x50,0x24,0x22,0x03,0x40,0x28,0x22,0x03,0x40, +0x7c,0x11,0x00,0x50,0x70,0x11,0x00,0x50,0x1c,0x22,0x03,0x40,0x14,0x22,0x03,0x40, +0x90,0x11,0x00,0x50,0x94,0x11,0x00,0x50,0x88,0x20,0x03,0x40,0x21,0xf4,0xe1,0x72, +0xc3,0xf3,0xc1,0x46,0x22,0xf0,0x01,0x02,0xc3,0xf3,0xc0,0x51,0x32,0x43,0x42,0xea, +0x01,0x22,0xc3,0xf3,0x41,0x51,0x42,0xea,0x81,0x12,0x22,0x60,0x22,0x68,0xd7,0x07, +0x02,0xd5,0x2a,0x68,0x56,0x07,0xfc,0xd5,0xc3,0xf3,0x02,0x43,0x16,0xe0,0xc3,0xf3, +0xc1,0x62,0xde,0x0f,0x42,0xea,0x06,0x26,0x21,0xf4,0xe1,0x72,0x22,0xf0,0x01,0x02, +0x32,0x43,0xc3,0xf3,0x41,0x71,0x42,0xea,0x81,0x12,0x22,0x60,0x22,0x68,0xd4,0x07, +0x02,0xd5,0x2a,0x68,0x51,0x07,0xfc,0xd5,0xc3,0xf3,0x02,0x63,0x3b,0x49,0x3c,0x4c, +0x4a,0xf6,0xaa,0x22,0x0a,0x60,0x22,0x68,0x1b,0x03,0xb3,0xf5,0xe0,0x4f,0x22,0xf4, +0xe2,0x42,0x18,0xbf,0x43,0xf4,0x80,0x73,0x13,0x43,0x23,0x60,0x45,0xf2,0xaa,0x53, +0x0b,0x60,0x34,0x4b,0x00,0x21,0x01,0x22,0x19,0x60,0x43,0xf8,0x20,0x2c,0x32,0x4a, +0x4f,0xf6,0xff,0x74,0x14,0x60,0x31,0x4c,0x43,0xf8,0x20,0x1c,0x02,0xf5,0xec,0x72, +0x4f,0xf0,0x05,0x0e,0x10,0x23,0xc4,0xf8,0x00,0xe0,0x13,0x60,0x2c,0x4b,0x15,0x26, +0x1e,0x60,0x02,0x26,0x26,0x60,0x2b,0x4e,0x37,0x68,0xc4,0xf8,0x00,0xe0,0xdf,0xf8, +0xb4,0xe0,0xce,0xf8,0x00,0x10,0xce,0xf8,0x04,0x10,0x18,0xb1,0x31,0x68,0x41,0xf4, +0x00,0x01,0x31,0x60,0x02,0x21,0x05,0x20,0x21,0x60,0x20,0x60,0x08,0x20,0x10,0x60, +0x15,0x22,0x1a,0x60,0x21,0x60,0x2b,0x68,0x9a,0x07,0xfc,0xd4,0x1e,0x4b,0x1b,0x68, +0x13,0xf0,0x10,0x0f,0x14,0xbf,0x04,0x25,0x00,0x25,0xff,0xf7,0x1b,0xfd,0x3b,0x02, +0x07,0xd4,0x05,0x23,0x23,0x60,0x33,0x68,0x23,0xf4,0x00,0x03,0x33,0x60,0x02,0x23, +0x23,0x60,0xc5,0xb9,0x15,0x4b,0x16,0x48,0x19,0x68,0x03,0xf5,0x10,0x53,0x04,0x33, +0x1a,0x68,0x1b,0x68,0x02,0xf0,0x0f,0x02,0xc9,0xb2,0x03,0xf0,0x0f,0x03,0x51,0x43, +0x9b,0x02,0xc3,0xeb,0x81,0x21,0x01,0xf5,0xfe,0x51,0x18,0x31,0x14,0x22,0xbd,0xe8, +0xf8,0x4f,0xff,0xf7,0xe9,0xbc,0x28,0x46,0xbd,0xe8,0xf8,0x8f,0x64,0x20,0x03,0x40, +0xa8,0x20,0x03,0x40,0x50,0x20,0x03,0x40,0x34,0x20,0x03,0x40,0x88,0x22,0x03,0x40, +0xb4,0x22,0x03,0x40,0x7c,0x22,0x03,0x40,0x54,0x20,0x03,0x40,0x2c,0x00,0x03,0x40, +0xf4,0x0e,0x00,0x20,0xc0,0x22,0x03,0x40,0x08,0xb5,0x01,0x1c,0x00,0x22,0x00,0x20, +0x00,0x23,0x00,0xf0,0xeb,0xf8,0x08,0xbc,0x02,0xbc,0x08,0x47,0x10,0xb5,0x00,0x21, +0x04,0x1c,0x00,0xf0,0x5d,0xf9,0x05,0x4b,0x18,0x68,0xc3,0x6b,0x00,0x2b,0x01,0xd0, +0x00,0xf0,0x06,0xf8,0x20,0x1c,0xff,0xf7,0xa7,0xfc,0xc0,0x46,0x0c,0x0f,0x00,0x20, +0x18,0x47,0xc0,0x46,0x38,0xb5,0x0a,0x4b,0x0a,0x4c,0xe4,0x1a,0xa4,0x10,0x0a,0xd0, +0x09,0x4a,0xa5,0x18,0xad,0x00,0xed,0x18,0x2b,0x68,0x01,0x3c,0x00,0xf0,0x0e,0xf8, +0x04,0x3d,0x00,0x2c,0xf8,0xd1,0x00,0xf0,0xcd,0xf9,0x38,0xbc,0x01,0xbc,0x00,0x47, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x3f,0x18,0x47,0xc0,0x46, +0x70,0xb5,0x10,0x4e,0x10,0x4d,0xad,0x1b,0xad,0x10,0x00,0x24,0x00,0x2d,0x06,0xd0, +0xa3,0x00,0xf3,0x58,0x01,0x34,0x00,0xf0,0x1d,0xf8,0xa5,0x42,0xf8,0xd1,0x00,0xf0, +0xab,0xf9,0x0a,0x4e,0x0a,0x4d,0xad,0x1b,0xad,0x10,0x00,0x24,0x00,0x2d,0x06,0xd0, +0xa3,0x00,0xf3,0x58,0x01,0x34,0x00,0xf0,0x0d,0xf8,0xa5,0x42,0xf8,0xd1,0x70,0xbc, +0x01,0xbc,0x00,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x18,0x47,0xc0,0x46,0x70,0xb5,0x0f,0x2a,0x34,0xd9,0x04,0x1c, +0x0c,0x43,0x0b,0x1c,0xa4,0x07,0x33,0xd1,0x15,0x1c,0x04,0x1c,0x10,0x3d,0x2d,0x09, +0x01,0x35,0x2d,0x01,0x49,0x19,0x1e,0x68,0x26,0x60,0x5e,0x68,0x66,0x60,0x9e,0x68, +0xa6,0x60,0xde,0x68,0x10,0x33,0xe6,0x60,0x10,0x34,0x99,0x42,0xf3,0xd1,0x0f,0x23, +0x45,0x19,0x13,0x40,0x03,0x2b,0x1d,0xd9,0x1c,0x1f,0x00,0x23,0xa4,0x08,0x01,0x34, +0xa4,0x00,0xce,0x58,0xee,0x50,0x04,0x33,0xa3,0x42,0xfa,0xd1,0xed,0x18,0xc9,0x18, +0x03,0x23,0x1a,0x40,0x05,0xd0,0x00,0x23,0xcc,0x5c,0xec,0x54,0x01,0x33,0x93,0x42, +0xfa,0xd1,0x70,0xbc,0x02,0xbc,0x08,0x47,0x05,0x1c,0x00,0x2a,0xf3,0xd1,0xf8,0xe7, +0x05,0x1c,0xf0,0xe7,0x1a,0x1c,0xf8,0xe7,0x70,0xb5,0x83,0x07,0x43,0xd0,0x54,0x1e, +0x00,0x2a,0x3d,0xd0,0x0d,0x06,0x2d,0x0e,0x03,0x1c,0x03,0x26,0x03,0xe0,0x62,0x1e, +0x00,0x2c,0x35,0xd0,0x14,0x1c,0x01,0x33,0x5a,0x1e,0x15,0x70,0x33,0x42,0xf6,0xd1, +0x03,0x2c,0x24,0xd9,0xff,0x25,0x0d,0x40,0x2a,0x02,0x15,0x43,0x2a,0x04,0x15,0x43, +0x0f,0x2c,0x11,0xd9,0x26,0x1c,0x10,0x3e,0x36,0x09,0x01,0x36,0x36,0x01,0x1a,0x1c, +0x9b,0x19,0x15,0x60,0x55,0x60,0x95,0x60,0xd5,0x60,0x10,0x32,0x93,0x42,0xf8,0xd1, +0x0f,0x22,0x14,0x40,0x03,0x2c,0x0a,0xd9,0x26,0x1f,0xb6,0x08,0x01,0x36,0xb6,0x00, +0x1a,0x1c,0x9b,0x19,0x20,0xc2,0x93,0x42,0xfc,0xd1,0x03,0x22,0x14,0x40,0x00,0x2c, +0x06,0xd0,0x09,0x06,0x1c,0x19,0x09,0x0e,0x19,0x70,0x01,0x33,0xa3,0x42,0xfb,0xd1, +0x70,0xbc,0x02,0xbc,0x08,0x47,0x14,0x1c,0x03,0x1c,0xc9,0xe7,0xf8,0xb5,0x44,0x46, +0x5f,0x46,0x56,0x46,0x4d,0x46,0x9b,0x46,0x30,0x4b,0xf0,0xb4,0x1c,0x68,0xa4,0x23, +0x5b,0x00,0x05,0x1c,0xe0,0x58,0x0e,0x1c,0x90,0x46,0x00,0x28,0x4d,0xd0,0x43,0x68, +0x1f,0x2b,0x0f,0xdc,0x5c,0x1c,0x00,0x2d,0x23,0xd1,0x02,0x33,0x9b,0x00,0x44,0x60, +0x1e,0x50,0x00,0x20,0x3c,0xbc,0x90,0x46,0x99,0x46,0xa2,0x46,0xab,0x46,0xf8,0xbc, +0x02,0xbc,0x08,0x47,0x22,0x4b,0x00,0x2b,0x3c,0xd0,0xc8,0x20,0x40,0x00,0xaf,0xf3, +0x00,0x80,0x00,0x28,0x36,0xd0,0xa4,0x22,0x00,0x23,0x52,0x00,0xa1,0x58,0x43,0x60, +0x01,0x60,0xa0,0x50,0x40,0x32,0x83,0x50,0x04,0x32,0x83,0x50,0x01,0x24,0x00,0x2d, +0xdb,0xd0,0x9a,0x00,0x91,0x46,0x81,0x44,0x42,0x46,0x88,0x21,0x4f,0x46,0x7a,0x50, +0xc4,0x22,0x52,0x00,0x90,0x46,0x80,0x44,0x42,0x46,0x87,0x39,0x99,0x40,0x12,0x68, +0x0a,0x43,0x94,0x46,0x8a,0x46,0x42,0x46,0x61,0x46,0x11,0x60,0x84,0x22,0x49,0x46, +0x5f,0x46,0x52,0x00,0x8f,0x50,0x02,0x2d,0xbf,0xd1,0x02,0x1c,0x55,0x46,0x8d,0x32, +0xff,0x32,0x11,0x68,0x0d,0x43,0x15,0x60,0xb7,0xe7,0x20,0x1c,0x4d,0x30,0xff,0x30, +0xe0,0x50,0xac,0xe7,0x01,0x20,0x40,0x42,0xb4,0xe7,0xc0,0x46,0x0c,0x0f,0x00,0x20, +0x00,0x00,0x00,0x00,0x08,0xb5,0x04,0x4b,0x00,0x2b,0x02,0xd0,0x03,0x48,0xff,0xf7, +0x9b,0xfe,0x08,0xbc,0x01,0xbc,0x00,0x47,0x00,0x00,0x00,0x00,0x15,0x0b,0x00,0x20, +0xf0,0xb5,0x56,0x46,0x5f,0x46,0x4d,0x46,0x44,0x46,0xf0,0xb4,0x0e,0x1c,0x3f,0x4b, +0x1b,0x68,0x87,0xb0,0x03,0x93,0x49,0x33,0xff,0x33,0x01,0x90,0x04,0x93,0xa4,0x22, +0x03,0x9b,0x52,0x00,0x9f,0x58,0x00,0x2f,0x4d,0xd0,0x04,0x9b,0x98,0x46,0x00,0x23, +0x9b,0x46,0xc4,0x23,0x5b,0x00,0x9c,0x46,0xbc,0x44,0x63,0x46,0x02,0x93,0xc6,0x23, +0x5b,0x00,0x9a,0x46,0x7c,0x68,0xa5,0x00,0x7d,0x19,0xba,0x44,0x01,0x3c,0x08,0xd5, +0x27,0xe0,0x6b,0x1d,0xff,0x33,0x1b,0x68,0xb3,0x42,0x04,0xd0,0x04,0x3d,0x01,0x3c, +0x1f,0xd3,0x00,0x2e,0xf5,0xd1,0x7b,0x68,0x01,0x3b,0x6a,0x68,0xa3,0x42,0x3e,0xd0, +0x5b,0x46,0x6b,0x60,0x00,0x2a,0xf1,0xd0,0x7b,0x68,0x99,0x46,0x01,0x23,0xa3,0x40, +0x02,0x99,0x09,0x68,0x05,0x91,0x19,0x42,0x26,0xd1,0x00,0xf0,0x43,0xf8,0x7b,0x68, +0x4b,0x45,0xc4,0xd1,0x43,0x46,0x1b,0x68,0xbb,0x42,0xc0,0xd1,0x04,0x3d,0x01,0x3c, +0xdf,0xd2,0x1b,0x4b,0x00,0x2b,0x0e,0xd0,0x7b,0x68,0x00,0x2b,0x27,0xd1,0x3b,0x68, +0x00,0x2b,0x28,0xd0,0x42,0x46,0x38,0x1c,0x13,0x60,0xaf,0xf3,0x00,0x80,0x43,0x46, +0x1f,0x68,0x00,0x2f,0xb5,0xd1,0x07,0xb0,0x3c,0xbc,0x90,0x46,0x99,0x46,0xa2,0x46, +0xab,0x46,0xf0,0xbc,0x01,0xbc,0x00,0x47,0x51,0x46,0x09,0x68,0x19,0x42,0x08,0xd1, +0x2b,0x1c,0x84,0x33,0x19,0x68,0x01,0x98,0x00,0xf0,0x14,0xf8,0xcf,0xe7,0x7c,0x60, +0xc0,0xe7,0x2b,0x1c,0x84,0x33,0x18,0x68,0x00,0xf0,0x0c,0xf8,0xc7,0xe7,0x3b,0x68, +0xb8,0x46,0x1f,0x1c,0xdd,0xe7,0x00,0x23,0xfa,0xe7,0xc0,0x46,0x0c,0x0f,0x00,0x20, +0x00,0x00,0x00,0x00,0x10,0x47,0xc0,0x46,0xf8,0xb5,0xc0,0x46,0xf8,0xbc,0x08,0xbc, +0x9e,0x46,0x70,0x47,0xf8,0xb5,0xc0,0x46,0xf8,0xbc,0x08,0xbc,0x9e,0x46,0x70,0x47, +0x00,0x00,0x00,0x00,0x24,0xf2,0xff,0x7f,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x8c,0x15,0x00,0x20,0xff,0xff,0xff,0xc5,0xff,0xff,0xff,0xff,0xc5,0xff,0xff,0xff, +0xc5,0xc5,0xc5,0xff,0xc5,0xc5,0xc5,0xff,0x43,0x00,0x00,0x00,0x18,0x0f,0x00,0x20, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x12,0x00,0x20, +0x6c,0x12,0x00,0x20,0xd4,0x12,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x0f,0x00,0x20, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x33,0xcd,0xab,0x34,0x12,0x6d,0xe6, +0xec,0xde,0x05,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x18,0x0f,0x00,0x20,0xc1,0x00,0x00,0x20,0x91,0x00,0x00,0x20,0x00,0x00,0x00,0x00, +0x95,0x0d,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, diff --git a/contrib/loaders/flash/cc26xx/flash.c b/contrib/loaders/flash/cc26xx/flash.c new file mode 100644 index 000000000..c19cb735d --- /dev/null +++ b/contrib/loaders/flash/cc26xx/flash.c @@ -0,0 +1,977 @@ +/****************************************************************************** +* +* Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#include +#include +#include "flash.h" + +/****************************************************************************** +* +* Defines for accesses to the security control in the customer configuration +* area in flash top sector. +* +******************************************************************************/ +#define CCFG_OFFSET_SECURITY CCFG_O_BL_CONFIG +#define CCFG_SIZE_SECURITY 0x00000014 + +/****************************************************************************** +* +* Default values for security control in customer configuration area in flash +* top sector. +* +******************************************************************************/ +const uint8_t g_ccfg_default_sec[] = { + 0xFF, 0xFF, 0xFF, 0xC5, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xC5, 0xFF, 0xFF, 0xFF, + 0xC5, 0xC5, 0xC5, 0xFF, + 0xC5, 0xC5, 0xC5, 0xFF +}; + +typedef uint32_t (*flash_prg_pntr_t) (uint8_t *, uint32_t, uint32_t); +typedef uint32_t (*flash_sector_erase_pntr_t) (uint32_t); + +/****************************************************************************** +* +* Function prototypes for static functions +* +******************************************************************************/ +static void issue_fsm_command(flash_state_command_t command); +static void enable_sectors_for_write(void); +static uint32_t scale_cycle_values(uint32_t specified_timing, + uint32_t scale_value); +static void set_write_mode(void); +static void trim_for_write(void); +static void set_read_mode(void); + +/****************************************************************************** +* +* Erase a flash sector +* +******************************************************************************/ +uint32_t flash_sector_erase(uint32_t sector_address) +{ + uint32_t error_return; + flash_sector_erase_pntr_t func_pntr; + + /* Call ROM function */ + func_pntr = (uint32_t (*)(uint32_t))(ROM_API_FLASH_TABLE[5]); + error_return = func_pntr(sector_address); + + /* Enable standby because ROM function might have disabled it */ + HWREGBITW(FLASH_BASE + FLASH_O_CFG, FLASH_CFG_DIS_STANDBY_BITN) = 0; + + /* Return status of operation. */ + return error_return; +} + +/****************************************************************************** +* +* Erase all unprotected sectors in the flash main bank +* +******************************************************************************/ +uint32_t flash_bank_erase(bool force_precondition) +{ + uint32_t error_return; + uint32_t sector_address; + uint32_t reg_val; + + /* Enable all sectors for erase. */ + enable_sectors_for_write(); + + /* Clear the Status register. */ + issue_fsm_command(FAPI_CLEAR_STATUS); + + /* Enable erase of all sectors and enable precondition if required. */ + reg_val = HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE); + HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; + HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR1) = 0x00000000; + HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR2) = 0x00000000; + if (force_precondition) + HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) |= + FLASH_FSM_ST_MACHINE_DO_PRECOND; + HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; + + /* Issue the bank erase command to the FSM. */ + issue_fsm_command(FAPI_ERASE_BANK); + + /* Wait for erase to finish. */ + while (flash_check_fsm_for_ready() == FAPI_STATUS_FSM_BUSY) + ; + + /* Update status. */ + error_return = flash_check_fsm_for_error(); + + /* Disable sectors for erase. */ + flash_disable_sectors_for_write(); + + /* Set configured precondition mode since it may have been forced on. */ + if (!(reg_val & FLASH_FSM_ST_MACHINE_DO_PRECOND)) { + HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; + HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) &= + ~FLASH_FSM_ST_MACHINE_DO_PRECOND; + HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; + } + + /* Program security data to default values in the customer configuration */ + /* area within the flash top sector if erase was successful. */ + if (error_return == FAPI_STATUS_SUCCESS) { + sector_address = FLASHMEM_BASE + flash_size_get() - + flash_sector_size_get(); + error_return = flash_program((uint8_t *)g_ccfg_default_sec, + (sector_address + CCFG_OFFSET_SECURITY), + CCFG_SIZE_SECURITY); + } + + /* Return status of operation. */ + return error_return; +} + +/****************************************************************************** +* +* Programs unprotected main bank flash sectors +* +******************************************************************************/ +uint32_t flash_program(uint8_t *data_buffer, uint32_t address, uint32_t count) +{ + uint32_t error_return; + flash_prg_pntr_t func_pntr; + + /* Call ROM function */ + func_pntr = (uint32_t (*)(uint8_t *, uint32_t, uint32_t)) + (ROM_API_FLASH_TABLE[6]); + error_return = func_pntr(data_buffer, address, count); + + /* Enable standby because ROM function might have disabled it */ + HWREGBITW(FLASH_BASE + FLASH_O_CFG, FLASH_CFG_DIS_STANDBY_BITN) = 0; + + /* Return status of operation. */ + return error_return; +} + +/****************************************************************************** +* +* Disables all sectors for erase and programming on the active bank +* +******************************************************************************/ +void flash_disable_sectors_for_write(void) +{ + /* Configure flash back to read mode */ + set_read_mode(); + + /* Disable Level 1 Protection. */ + HWREG(FLASH_BASE + FLASH_O_FBPROT) = FLASH_FBPROT_PROTL1DIS; + + /* Disable all sectors for erase and programming. */ + HWREG(FLASH_BASE + FLASH_O_FBSE) = 0x0000; + + /* Enable Level 1 Protection. */ + HWREG(FLASH_BASE + FLASH_O_FBPROT) = 0; + + /* Protect sectors from sector erase. */ + HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; + HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR1) = 0xFFFFFFFF; + HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR2) = 0xFFFFFFFF; + HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; +} + +/****************************************************************************** +* +* Issues a command to the Flash State Machine. +* +******************************************************************************/ +static void issue_fsm_command(flash_state_command_t command) +{ + /* Enable write to FSM register. */ + HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; + + /* Issue FSM command. */ + HWREG(FLASH_BASE + FLASH_O_FSM_CMD) = command; + + /* Start command execute. */ + HWREG(FLASH_BASE + FLASH_O_FSM_EXECUTE) = FLASH_CMD_EXEC; + + /* Disable write to FSM register. */ + HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; +} + +/****************************************************************************** +* +* Enables all sectors for erase and programming on the active bank. +* +* This function disables the idle reading power reduction mode, selects the +* flash bank and enables all sectors for erase and programming on the active +* bank. +* Sectors may be protected from programming depending on the value of the +* FLASH_O_FSM_BSLPx registers. +* Sectors may be protected from erase depending on the value of the +* FLASH_O_FSM_BSLEx registers. Additional sector erase protection is set by +* the FLASH_O_FSM_SECTOR1 register. +* +******************************************************************************/ +static void enable_sectors_for_write(void) +{ + /* Trim flash module for program/erase operation. */ + trim_for_write(); + + /* Configure flash to write mode */ + set_write_mode(); + + /* Select flash bank. */ + HWREG(FLASH_BASE + FLASH_O_FMAC) = 0x00; + + /* Disable Level 1 Protection. */ + HWREG(FLASH_BASE + FLASH_O_FBPROT) = FLASH_FBPROT_PROTL1DIS; + + /* Enable all sectors for erase and programming. */ + HWREG(FLASH_BASE + FLASH_O_FBSE) = 0xFFFF; + + /* Enable Level 1 Protection */ + HWREG(FLASH_BASE + FLASH_O_FBPROT) = 0; +} + +/****************************************************************************** +* +* Trims the Flash Bank and Flash Pump for program/erase functionality +* +* This trimming will make it possible to perform erase and program operations +* of the flash. Trim values are loaded from factory configuration area +* (referred to as FCGF1). The trimming done by this function is valid until +* reset of the flash module. +* +* Some registers shall be written with a value that is a number of FCLK +* cycles. The trim values controlling these registers have a value of +* number of half us. FCLK = SysClk / ((RWAIT+1) x 2). +* +******************************************************************************/ +static void trim_for_write(void) +{ + uint32_t value; + uint32_t temp_val; + uint32_t fclk_scale; + uint32_t rwait; + + /* Return if flash is already trimmed for program/erase operations. */ + if (HWREG(FLASH_BASE + FLASH_O_FWFLAG) & FW_WRT_TRIMMED) + return; + + /* Configure the FSM registers */ + + /* Enable access to the FSM registers. */ + HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; + + /* Determine the scaling value to be used on timing related trim values. */ + /* The value is based on the flash module clock frequency and RWAIT */ + rwait = (HWREG(FLASH_BASE + FLASH_O_FRDCTL) & + FLASH_FRDCTL_RWAIT_M) >> FLASH_FRDCTL_RWAIT_S; + fclk_scale = (16 * FLASH_MODULE_CLK_FREQ) / (rwait + 1); + + /* Configure Program pulse width bits 15:0. */ + /* (FCFG1 offset 0x188 bits 15:0). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_PROG_EP) & + FCFG1_FLASH_PROG_EP_PROGRAM_PW_M) >> + FCFG1_FLASH_PROG_EP_PROGRAM_PW_S; + + value = scale_cycle_values(value, fclk_scale); + + HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PW) = + (HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PW) & + ~FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_M) | + ((value << FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_S) & + FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_M); + + /* Configure Erase pulse width bits 31:0. */ + /* (FCFG1 offset 0x18C bits 31:0). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_ERA_PW) & + FCFG1_FLASH_ERA_PW_ERASE_PW_M) >> + FCFG1_FLASH_ERA_PW_ERASE_PW_S; + + value = scale_cycle_values(value, fclk_scale); + + HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PW) = + (HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PW) & + ~FLASH_FSM_ERA_PW_FSM_ERA_PW_M) | + ((value << FLASH_FSM_ERA_PW_FSM_ERA_PW_S) & + FLASH_FSM_ERA_PW_FSM_ERA_PW_M); + + /* Configure no of flash clock cycles from EXECUTEZ going low to the the + verify data can be read in the program verify mode bits 7:0. */ + /* (FCFG1 offset 0x174 bits 23:16). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_C_E_P_R) & + FCFG1_FLASH_C_E_P_R_PV_ACCESS_M) >> + FCFG1_FLASH_C_E_P_R_PV_ACCESS_S; + + value = scale_cycle_values(value, fclk_scale); + + HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) = + (HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) & + ~FLASH_FSM_EX_VAL_EXE_VALD_M) | + ((value << FLASH_FSM_EX_VAL_EXE_VALD_S) & + FLASH_FSM_EX_VAL_EXE_VALD_M); + + /* Configure the number of flash clocks from the start of the Read mode at + the end of the operations until the FSM clears the BUSY bit in FMSTAT. */ + /* (FCFG1 offset 0x178 bits 23:16). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_P_R_PV) & + FCFG1_FLASH_P_R_PV_RH_M) >> + FCFG1_FLASH_P_R_PV_RH_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_RD_H) = + (HWREG(FLASH_BASE + FLASH_O_FSM_RD_H) & + ~FLASH_FSM_RD_H_RD_H_M) | + ((value << FLASH_FSM_RD_H_RD_H_S) & + FLASH_FSM_RD_H_RD_H_M); + + /* Configure Program hold time */ + /* (FCFG1 offset 0x178 bits 31:24). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_P_R_PV) & + FCFG1_FLASH_P_R_PV_PH_M) >> + FCFG1_FLASH_P_R_PV_PH_S; + + value = scale_cycle_values(value, fclk_scale); + + HWREG(FLASH_BASE + FLASH_O_FSM_P_OH) = + (HWREG(FLASH_BASE + FLASH_O_FSM_P_OH) & + ~FLASH_FSM_P_OH_PGM_OH_M) | + ((value << FLASH_FSM_P_OH_PGM_OH_S) & + FLASH_FSM_P_OH_PGM_OH_M); + + /* Configure Erase hold time */ + /* (FCFG1 offset 0x17C bits 31:24). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_EH_SEQ) & + FCFG1_FLASH_EH_SEQ_EH_M) >> + FCFG1_FLASH_EH_SEQ_EH_S; + + value = scale_cycle_values(value, fclk_scale); + + HWREG(FLASH_BASE + FLASH_O_FSM_ERA_OH) = + (HWREG(FLASH_BASE + FLASH_O_FSM_ERA_OH) & + ~FLASH_FSM_ERA_OH_ERA_OH_M) | + ((value << FLASH_FSM_ERA_OH_ERA_OH_S) & + FLASH_FSM_ERA_OH_ERA_OH_M); + + /* Configure Program verify row switch time */ + /* (FCFG1 offset0x178 bits 15:8). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_P_R_PV) & + FCFG1_FLASH_P_R_PV_PVH_M) >> + FCFG1_FLASH_P_R_PV_PVH_S; + + value = scale_cycle_values(value, fclk_scale); + + HWREG(FLASH_BASE + FLASH_O_FSM_PE_VH) = + (HWREG(FLASH_BASE + FLASH_O_FSM_PE_VH) & + ~FLASH_FSM_PE_VH_PGM_VH_M) | + ((value << FLASH_FSM_PE_VH_PGM_VH_S) & + FLASH_FSM_PE_VH_PGM_VH_M); + + /* Configure Program Operation Setup time */ + /* (FCFG1 offset 0x170 bits 31:24). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) & + FCFG1_FLASH_E_P_PSU_M) >> + FCFG1_FLASH_E_P_PSU_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) = + (HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) & + ~FLASH_FSM_PE_OSU_PGM_OSU_M) | + ((value << FLASH_FSM_PE_OSU_PGM_OSU_S) & + FLASH_FSM_PE_OSU_PGM_OSU_M); + + /* Configure Erase Operation Setup time */ + /* (FCGF1 offset 0x170 bits 23:16). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) & + FCFG1_FLASH_E_P_ESU_M) >> + FCFG1_FLASH_E_P_ESU_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) = + (HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) & + ~FLASH_FSM_PE_OSU_ERA_OSU_M) | + ((value << FLASH_FSM_PE_OSU_ERA_OSU_S) & + FLASH_FSM_PE_OSU_ERA_OSU_M); + + /* Confgure Program Verify Setup time */ + /* (FCFG1 offset 0x170 bits 15:8). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) & + FCFG1_FLASH_E_P_PVSU_M) >> + FCFG1_FLASH_E_P_PVSU_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) = + (HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) & + ~FLASH_FSM_PE_VSU_PGM_VSU_M) | + ((value << FLASH_FSM_PE_VSU_PGM_VSU_S) & + FLASH_FSM_PE_VSU_PGM_VSU_M); + + /* Configure Erase Verify Setup time */ + /* (FCFG1 offset 0x170 bits 7:0). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) & + FCFG1_FLASH_E_P_EVSU_M) >> + FCFG1_FLASH_E_P_EVSU_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) = + (HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) & + ~FLASH_FSM_PE_VSU_ERA_VSU_M) | + ((value << FLASH_FSM_PE_VSU_ERA_VSU_S) & + FLASH_FSM_PE_VSU_ERA_VSU_M); + + /* Configure Addr to EXECUTEZ low setup time */ + /* (FCFG1 offset 0x174 bits 15:12). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_C_E_P_R) & + FCFG1_FLASH_C_E_P_R_A_EXEZ_SETUP_M) >> + FCFG1_FLASH_C_E_P_R_A_EXEZ_SETUP_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_CMP_VSU) = + (HWREG(FLASH_BASE + FLASH_O_FSM_CMP_VSU) & + ~FLASH_FSM_CMP_VSU_ADD_EXZ_M) | + ((value << FLASH_FSM_CMP_VSU_ADD_EXZ_S) & + FLASH_FSM_CMP_VSU_ADD_EXZ_M); + + /* Configure Voltage Status Count */ + /* (FCFG1 offset 0x17C bits 15:12). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_EH_SEQ) & + FCFG1_FLASH_EH_SEQ_VSTAT_M) >> + FCFG1_FLASH_EH_SEQ_VSTAT_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_VSTAT) = + (HWREG(FLASH_BASE + FLASH_O_FSM_VSTAT) & + ~FLASH_FSM_VSTAT_VSTAT_CNT_M) | + ((value << FLASH_FSM_VSTAT_VSTAT_CNT_S) & + FLASH_FSM_VSTAT_VSTAT_CNT_M); + + /* Configure Repeat Verify action setup */ + /* (FCFG1 offset 0x174 bits 31:24). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_C_E_P_R) & + FCFG1_FLASH_C_E_P_R_RVSU_M) >> + FCFG1_FLASH_C_E_P_R_RVSU_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) = + (HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) & + ~FLASH_FSM_EX_VAL_REP_VSU_M) | + ((value << FLASH_FSM_EX_VAL_REP_VSU_S) & + FLASH_FSM_EX_VAL_REP_VSU_M); + + /* Configure Maximum Programming Pulses */ + /* (FCFG1 offset 0x184 bits 15:0). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_PP) & + FCFG1_FLASH_PP_MAX_PP_M) >> + FCFG1_FLASH_PP_MAX_PP_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) = + (HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) & + ~FLASH_FSM_PRG_PUL_MAX_PRG_PUL_M) | + ((value << FLASH_FSM_PRG_PUL_MAX_PRG_PUL_S) & + FLASH_FSM_PRG_PUL_MAX_PRG_PUL_M); + + /* Configure Beginning level for VHVCT used during erase modes */ + /* (FCFG1 offset 0x180 bits 31:16). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_E) & + FCFG1_FLASH_VHV_E_VHV_E_START_M) >> + FCFG1_FLASH_VHV_E_VHV_E_START_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) = + (HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) & + ~FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_M) | + ((value << FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_S) & + FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_M); + + /* Configure Maximum EC Level */ + /* (FCFG1 offset 0x2B0 bits 21:18). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) & + FCFG1_FLASH_OTP_DATA3_MAX_EC_LEVEL_M) >> + FCFG1_FLASH_OTP_DATA3_MAX_EC_LEVEL_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) = + (HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) & + ~FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_M) | + ((value << FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_S) & + FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_M); + + /* Configure Maximum Erase Pulses */ + /* (FCFG1 offset 0x188 bits 31:16). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_PROG_EP) & + FCFG1_FLASH_PROG_EP_MAX_EP_M) >> + FCFG1_FLASH_PROG_EP_MAX_EP_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) = + (HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) & + ~FLASH_FSM_ERA_PUL_MAX_ERA_PUL_M) | + ((value << FLASH_FSM_ERA_PUL_MAX_ERA_PUL_S) & + FLASH_FSM_ERA_PUL_MAX_ERA_PUL_M); + + /* Configure the VHVCT Step Size. This is the number of erase pulses that + must be completed for each level before the FSM increments the + CUR_EC_LEVEL to the next higher level. Actual erase pulses per level + equals (EC_STEP_SIZE +1). The stepping is only needed for the VHVCT + voltage. */ + /* (FCFG1 offset 0x2B0 bits 31:23). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) & + FCFG1_FLASH_OTP_DATA3_EC_STEP_SIZE_M) >> + FCFG1_FLASH_OTP_DATA3_EC_STEP_SIZE_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_STEP_SIZE) = + (HWREG(FLASH_BASE + FLASH_O_FSM_STEP_SIZE) & + ~FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_M) | + ((value << FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_S) & + FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_M); + + /* Configure the hight of each EC step. This is the number of counts that + the CUR_EC_LEVEL will increment when going to a new level. Actual count + size equals (EC_STEP_HEIGHT + 1). The stepping applies only to the VHVCT + voltage. + The read trim value is decremented by 1 before written to the register + since actual counts equals (register value + 1). */ + /* (FCFG1 offset 0x180 bits 15:0). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_E) & + FCFG1_FLASH_VHV_E_VHV_E_STEP_HIGHT_M) >> + FCFG1_FLASH_VHV_E_VHV_E_STEP_HIGHT_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_EC_STEP_HEIGHT) = ((value - 1) & + FLASH_FSM_EC_STEP_HEIGHT_EC_STEP_HEIGHT_M); + + /* Configure Precondition used in erase operations */ + /* (FCFG1 offset 0x2B0 bit 22). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) & + FCFG1_FLASH_OTP_DATA3_DO_PRECOND_M) >> + FCFG1_FLASH_OTP_DATA3_DO_PRECOND_S; + + HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) = + (HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) & + ~FLASH_FSM_ST_MACHINE_DO_PRECOND_M) | + ((value << FLASH_FSM_ST_MACHINE_DO_PRECOND_S) & + FLASH_FSM_ST_MACHINE_DO_PRECOND_M); + + /* Enable the recommended Good Time function. */ + HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) |= + FLASH_FSM_ST_MACHINE_ONE_TIME_GOOD; + + /* Disable write access to FSM registers. */ + HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; + + /* Configure the voltage registers */ + + /* Unlock voltage registers (0x2080 - 0x2098). */ + HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; + + /* Configure voltage level for the specified pump voltage of high + voltage supply input during erase operation VHVCT_E and TRIM13_E */ + /* (FCFG1 offset 0x190 bits[3:0] and bits[11:8]). */ + temp_val = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV); + + value = ((temp_val & FCFG1_FLASH_VHV_TRIM13_E_M)>> + FCFG1_FLASH_VHV_TRIM13_E_S) << FLASH_FVHVCT1_TRIM13_E_S; + value |= ((temp_val & FCFG1_FLASH_VHV_VHV_E_M)>> + FCFG1_FLASH_VHV_VHV_E_S) << FLASH_FVHVCT1_VHVCT_E_S; + + HWREG(FLASH_BASE + FLASH_O_FVHVCT1) = (HWREG(FLASH_BASE + FLASH_O_FVHVCT1) & + ~(FLASH_FVHVCT1_TRIM13_E_M | FLASH_FVHVCT1_VHVCT_E_M)) | value; + + /* Configure voltage level for the specified pump voltage of high voltage + supply input during program verify operation VHVCT_PV and TRIM13_PV */ + /* (OTP offset 0x194 bits[19:16] and bits[27:24]). */ + temp_val = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_PV); + + value = ((temp_val & FCFG1_FLASH_VHV_PV_TRIM13_PV_M) >> + FCFG1_FLASH_VHV_PV_TRIM13_PV_S) << FLASH_FVHVCT1_TRIM13_PV_S; + value |= ((temp_val & FCFG1_FLASH_VHV_PV_VHV_PV_M) >> + FCFG1_FLASH_VHV_PV_VHV_PV_S) << FLASH_FVHVCT1_VHVCT_PV_S; + + HWREG(FLASH_BASE + FLASH_O_FVHVCT1) = (HWREG(FLASH_BASE + FLASH_O_FVHVCT1) & + ~(FLASH_FVHVCT1_TRIM13_PV_M | FLASH_FVHVCT1_VHVCT_PV_M)) | value; + + /* Configure voltage level for the specified pump voltage of high voltage + supply input during program operation VHVCT_P and TRIM13_P */ + /* (FCFG1 offset 0x190 bits[19:16] and bits[27:24]). */ + temp_val = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV); + + value = ((temp_val & FCFG1_FLASH_VHV_TRIM13_P_M) >> + FCFG1_FLASH_VHV_TRIM13_P_S) << FLASH_FVHVCT2_TRIM13_P_S; + value |= ((temp_val & FCFG1_FLASH_VHV_VHV_P_M) >> + FCFG1_FLASH_VHV_VHV_P_S) << FLASH_FVHVCT2_VHVCT_P_S; + + HWREG(FLASH_BASE + FLASH_O_FVHVCT2) = (HWREG(FLASH_BASE + FLASH_O_FVHVCT2) & + ~(FLASH_FVHVCT2_TRIM13_P_M | FLASH_FVHVCT2_VHVCT_P_M)) | value; + + /* Configure voltage level for the specified pump voltage of wordline power + supply for read mode */ + /* (FCFG1 offset 0x198 Bits 15:8). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_V) & + FCFG1_FLASH_V_V_READ_M) >> FCFG1_FLASH_V_V_READ_S; + + HWREG(FLASH_BASE + FLASH_O_FVREADCT) = + (HWREG(FLASH_BASE + FLASH_O_FVREADCT) & + ~FLASH_FVREADCT_VREADCT_M) | + ((value << FLASH_FVREADCT_VREADCT_S) & + FLASH_FVREADCT_VREADCT_M); + + /* Configure the voltage level for the VCG 2.5 CT pump voltage */ + /* (FCFG1 offset 0x194 bits 15:8). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_PV) & + FCFG1_FLASH_VHV_PV_VCG2P5_M) >> + FCFG1_FLASH_VHV_PV_VCG2P5_S; + + HWREG(FLASH_BASE + FLASH_O_FVNVCT) = + (HWREG(FLASH_BASE + FLASH_O_FVNVCT) & + ~FLASH_FVNVCT_VCG2P5CT_M) | + ((value << FLASH_FVNVCT_VCG2P5CT_S) & + FLASH_FVNVCT_VCG2P5CT_M); + + /* Configure the voltage level for the specified pump voltage of high + current power input during program operation */ + /* (FCFG1 offset 0x198 bits 31:24). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_V) & + FCFG1_FLASH_V_VSL_P_M) >> + FCFG1_FLASH_V_VSL_P_S; + + HWREG(FLASH_BASE + FLASH_O_FVSLP) = + (HWREG(FLASH_BASE + FLASH_O_FVSLP) & + ~FLASH_FVSLP_VSL_P_M) | + ((value << FLASH_FVSLP_VSL_P_S) & + FLASH_FVSLP_VSL_P_M); + + /* Configure the voltage level for the specified pump voltage of wordline + power supply during programming operations */ + /* (OTP offset 0x198 bits 23:16). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_V) & + FCFG1_FLASH_V_VWL_P_M) >> + FCFG1_FLASH_V_VWL_P_S; + + HWREG(FLASH_BASE + FLASH_O_FVWLCT) = + (HWREG(FLASH_BASE + FLASH_O_FVWLCT) & + ~FLASH_FVWLCT_VWLCT_P_M) | + ((value << FLASH_FVWLCT_VWLCT_P_S) & + FLASH_FVWLCT_VWLCT_P_M); + + /* Configure the pump's TRIM_1P7 port pins. */ + /* (FCFG1 offset 0x2B0 bits 17:16). */ + value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) & + FCFG1_FLASH_OTP_DATA3_TRIM_1P7_M) >> + FCFG1_FLASH_OTP_DATA3_TRIM_1P7_S; + + HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = + (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & + ~FLASH_FSEQPMP_TRIM_1P7_M) | + ((value << FLASH_FSEQPMP_TRIM_1P7_S) & + FLASH_FSEQPMP_TRIM_1P7_M); + + /* Lock the voltage registers. */ + HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; + + /* Set trimmed flag. */ + HWREG(FLASH_BASE + FLASH_O_FWLOCK) = 5; + HWREG(FLASH_BASE + FLASH_O_FWFLAG) |= FW_WRT_TRIMMED; + HWREG(FLASH_BASE + FLASH_O_FWLOCK) = 0; +} + +/****************************************************************************** +* +* Used to scale the TI OTP values based on the FClk scaling value. +* +******************************************************************************/ +static uint32_t scale_cycle_values(uint32_t specified_timing, + uint32_t scale_value) +{ + uint32_t scaled_value = (specified_timing * scale_value) >> 6; + return scaled_value; +} + +/****************************************************************************** +* +* Used to set flash in read mode. +* +* Flash is configured with values loaded from OTP dependent on the current +* regulator mode. +* +******************************************************************************/ +static void set_read_mode(void) +{ + uint32_t trim_value; + uint32_t value; + + /* Configure the STANDBY_MODE_SEL, STANDBY_PW_SEL, DIS_STANDBY, DIS_IDLE, + VIN_AT_X and VIN_BY_PASS for read mode */ + if (HWREG(AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL) & + AON_PMCTL_PWRCTL_EXT_REG_MODE) { + + /* Select trim values for external regulator mode: + Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 7) + Configure STANDBY_PW_SEL (OTP offset 0x308 bit 6:5) + Must be done while the register bit field CONFIG.DIS_STANDBY = 1 */ + HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY; + + trim_value = + HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4); + + value = ((trim_value & + FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_RD_M) >> + FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_RD_S) << + FLASH_CFG_STANDBY_MODE_SEL_S; + + value |= ((trim_value & + FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_RD_M) >> + FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_RD_S) << + FLASH_CFG_STANDBY_PW_SEL_S; + + /* Configure DIS_STANDBY (OTP offset 0x308 bit 4). + Configure DIS_IDLE (OTP offset 0x308 bit 3). */ + value |= ((trim_value & + (FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_EXT_RD_M | + FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_RD_M)) >> + FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_RD_S) << + FLASH_CFG_DIS_IDLE_S; + + HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) & + ~(FLASH_CFG_STANDBY_MODE_SEL_M | FLASH_CFG_STANDBY_PW_SEL_M | + FLASH_CFG_DIS_STANDBY_M | FLASH_CFG_DIS_IDLE_M)) | value; + + /* Check if sample and hold functionality is disabled. */ + if (HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE) { + /* Wait for disabled sample and hold functionality to be stable. */ + while (!(HWREG(FLASH_BASE+FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS)) + ; + } + + /* Configure VIN_AT_X (OTP offset 0x308 bits 2:0) */ + value = ((trim_value & + FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_RD_M) >> + FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_RD_S) << + FLASH_FSEQPMP_VIN_AT_X_S; + + /* Configure VIN_BY_PASS which is dependent on the VIN_AT_X value. + If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise + VIN_BY_PASS should be 1 */ + if (((value & FLASH_FSEQPMP_VIN_AT_X_M) >> + FLASH_FSEQPMP_VIN_AT_X_S) != 0x7) + value |= FLASH_FSEQPMP_VIN_BY_PASS; + + HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; + HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = + (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & + ~(FLASH_FSEQPMP_VIN_BY_PASS_M | + FLASH_FSEQPMP_VIN_AT_X_M)) | value; + HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; + } else { + + /* Select trim values for internal regulator mode: + Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 15) + COnfigure STANDBY_PW_SEL (OTP offset 0x308 bit 14:13) + Must be done while the register bit field CONFIG.DIS_STANDBY = 1 */ + HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY; + + trim_value = + HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4); + + value = ((trim_value & + FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_RD_M) >> + FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_RD_S) << + FLASH_CFG_STANDBY_MODE_SEL_S; + + value |= ((trim_value & + FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_RD_M) >> + FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_RD_S) << + FLASH_CFG_STANDBY_PW_SEL_S; + + /* Configure DIS_STANDBY (OTP offset 0x308 bit 12). + Configure DIS_IDLE (OTP offset 0x308 bit 11). */ + value |= ((trim_value & + (FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_INT_RD_M | + FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_RD_M)) >> + FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_RD_S) << + FLASH_CFG_DIS_IDLE_S; + + HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) & + ~(FLASH_CFG_STANDBY_MODE_SEL_M | FLASH_CFG_STANDBY_PW_SEL_M | + FLASH_CFG_DIS_STANDBY_M | FLASH_CFG_DIS_IDLE_M)) | value; + + /* Check if sample and hold functionality is disabled. */ + if (HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE) { + /* Wait for disabled sample and hold functionality to be stable. */ + while (!(HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS)) + ; + } + + /* Configure VIN_AT_X (OTP offset 0x308 bits 10:8) */ + value = (((trim_value & + FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_RD_M) >> + FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_RD_S) << + FLASH_FSEQPMP_VIN_AT_X_S); + + /* Configure VIN_BY_PASS which is dependent on the VIN_AT_X value. + If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise + VIN_BY_PASS should be 1 */ + if (((value & FLASH_FSEQPMP_VIN_AT_X_M) >> + FLASH_FSEQPMP_VIN_AT_X_S) != 0x7) + value |= FLASH_FSEQPMP_VIN_BY_PASS; + + HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; + HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = + (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & + ~(FLASH_FSEQPMP_VIN_BY_PASS_M | + FLASH_FSEQPMP_VIN_AT_X_M)) | value; + HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; + } +} + +/****************************************************************************** +* +* Used to set flash in write mode. +* +* Flash is configured with values loaded from OTP dependent on the current +* regulator mode. +* +******************************************************************************/ +static void set_write_mode(void) +{ + uint32_t trim_value; + uint32_t value; + + /* Configure the STANDBY_MODE_SEL, STANDBY_PW_SEL, DIS_STANDBY, DIS_IDLE, + VIN_AT_X and VIN_BY_PASS for program/erase mode */ + if (HWREG(AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL) & + AON_PMCTL_PWRCTL_EXT_REG_MODE) { + + /* Select trim values for external regulator mode: + Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 23) + Configure STANDBY_PW_SEL (OTP offset 0x308 bit 22:21) + Must be done while the register bit field CONFIG.DIS_STANDBY = 1 */ + HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY; + + trim_value = + HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4); + + value = ((trim_value & + FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_WRT_M) >> + FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_WRT_S) << + FLASH_CFG_STANDBY_MODE_SEL_S; + + value |= ((trim_value & + FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_WRT_M) >> + FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_WRT_S) << + FLASH_CFG_STANDBY_PW_SEL_S; + + /* Configure DIS_STANDBY (OTP offset 0x308 bit 20). + Configure DIS_IDLE (OTP offset 0x308 bit 19). */ + value |= ((trim_value & + (FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_EXT_WRT_M | + FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_WRT_M)) >> + FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_WRT_S) << + FLASH_CFG_DIS_IDLE_S; + + HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) & + ~(FLASH_CFG_STANDBY_MODE_SEL_M | FLASH_CFG_STANDBY_PW_SEL_M | + FLASH_CFG_DIS_STANDBY_M | FLASH_CFG_DIS_IDLE_M)) | value; + + /* Check if sample and hold functionality is disabled. */ + if (HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE) { + /* Wait for disabled sample and hold functionality to be stable. */ + while (!(HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS)) + ; + } + + /* Configure VIN_AT_X (OTP offset 0x308 bits 18:16) */ + value = ((trim_value & + FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_WRT_M) >> + FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_WRT_S) << + FLASH_FSEQPMP_VIN_AT_X_S; + + /* Configure VIN_BY_PASS which is dependent on the VIN_AT_X value. + If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise + VIN_BY_PASS should be 1 */ + if (((value & FLASH_FSEQPMP_VIN_AT_X_M) >> + FLASH_FSEQPMP_VIN_AT_X_S) != 0x7) + value |= FLASH_FSEQPMP_VIN_BY_PASS; + + HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; + HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = + (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & + ~(FLASH_FSEQPMP_VIN_BY_PASS_M | + FLASH_FSEQPMP_VIN_AT_X_M)) | value; + HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; + } else { + /* Select trim values for internal regulator mode: + Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 31) + COnfigure STANDBY_PW_SEL (OTP offset 0x308 bit 30:29) + Must be done while the register bit field CONFIG.DIS_STANDBY = 1 */ + HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY; + + trim_value = + HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4); + + value = ((trim_value & + FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_WRT_M) >> + FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_WRT_S) << + FLASH_CFG_STANDBY_MODE_SEL_S; + + value |= ((trim_value & + FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_WRT_M) >> + FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_WRT_S) << + FLASH_CFG_STANDBY_PW_SEL_S; + + /* Configure DIS_STANDBY (OTP offset 0x308 bit 28). + Configure DIS_IDLE (OTP offset 0x308 bit 27). */ + value |= ((trim_value & + (FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_INT_WRT_M | + FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_WRT_M)) >> + FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_WRT_S) << + FLASH_CFG_DIS_IDLE_S; + + HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) & + ~(FLASH_CFG_STANDBY_MODE_SEL_M | FLASH_CFG_STANDBY_PW_SEL_M | + FLASH_CFG_DIS_STANDBY_M | FLASH_CFG_DIS_IDLE_M)) | value; + + /* Check if sample and hold functionality is disabled. */ + if (HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE) { + /* Wait for disabled sample and hold functionality to be stable. */ + while (!(HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS)) + ; + } + + /* Configure VIN_AT_X (OTP offset 0x308 bits 26:24) */ + value = ((trim_value & + FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_WRT_M) >> + FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_WRT_S) << + FLASH_FSEQPMP_VIN_AT_X_S; + + /* Configure VIN_BY_PASS which is dependent on the VIN_AT_X value. + If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise + VIN_BY_PASS should be 1 */ + if (((value & FLASH_FSEQPMP_VIN_AT_X_M) >> + FLASH_FSEQPMP_VIN_AT_X_S) != 0x7) + value |= FLASH_FSEQPMP_VIN_BY_PASS; + + HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; + HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = + (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & + ~(FLASH_FSEQPMP_VIN_BY_PASS_M | + FLASH_FSEQPMP_VIN_AT_X_M)) | value; + HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; + } +} diff --git a/contrib/loaders/flash/cc26xx/flash.h b/contrib/loaders/flash/cc26xx/flash.h new file mode 100644 index 000000000..ec1c24fc5 --- /dev/null +++ b/contrib/loaders/flash/cc26xx/flash.h @@ -0,0 +1,378 @@ +/****************************************************************************** +* +* Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#ifndef OPENOCD_LOADERS_FLASH_CC26XX_FLASH_H +#define OPENOCD_LOADERS_FLASH_CC26XX_FLASH_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include +#include "hw_regs.h" + +/* Location of flash in memory map */ +#define FLASHMEM_BASE 0 + +/* Defines to access flash API calls in ROM */ +#define ROM_API_TABLE ((uint32_t *) 0x10000180) +#define ROM_VERSION (ROM_API_TABLE[0]) +#define ROM_API_FLASH_TABLE ((uint32_t *) (ROM_API_TABLE[10])) + +#if defined(DEVICE_CC26X2) + +/* Agama (CC26x2) specific definitions */ + +#define FLASH_ERASE_SIZE 8192 +/* Agama (and Agama 1M) has a maximum of 132 flash sectors (1056KB / 8KB) */ +#define FLASH_MAX_SECTOR_COUNT 132 +#define FLASH_SECTOR_BASE_M 0xFFFFE000 + +/* Bootloader Configuration */ +#define CCFG_O_BL_CONFIG 0x00001FD8 + +#elif defined(DEVICE_CC26X0) + +/* Chameleon (CC26x0) specific definitions */ + +#define FLASH_ERASE_SIZE 4096 +/* Chameleon has a maximum of 32 flash sectors (128KB / 4KB) */ +#define FLASH_MAX_SECTOR_COUNT 32 +#define FLASH_SECTOR_BASE_M 0xFFFFF000 + +/* Bootloader Configuration */ +#define CCFG_O_BL_CONFIG 0x00000FD8 + +#else +#error No DEVICE defined. +#endif + +/****************************************************************************** +* +* Values that can be returned from the API functions +* +******************************************************************************/ +#define FAPI_STATUS_SUCCESS 0x00000000 /* Function completed successfully */ +#define FAPI_STATUS_FSM_BUSY 0x00000001 /* FSM is Busy */ +#define FAPI_STATUS_FSM_READY 0x00000002 /* FSM is Ready */ +#define FAPI_STATUS_INCORRECT_DATABUFFER_LENGTH \ + 0x00000003 /* Incorrect parameter value */ +#define FAPI_STATUS_FSM_ERROR 0x00000004 /* Operation failed */ + +/****************************************************************************** +* +* Define used by the flash programming and erase functions +* +******************************************************************************/ +#define ADDR_OFFSET (0x1F800000 - FLASHMEM_BASE) + +/****************************************************************************** +* +* Define used for access to factory configuration area. +* +******************************************************************************/ +#define FCFG1_OFFSET 0x1000 + +/****************************************************************************** +* +* Define for the clock frequencey input to the flash module in number of MHz +* +******************************************************************************/ +#define FLASH_MODULE_CLK_FREQ 48 + +/****************************************************************************** +* +* Defined values for Flash State Machine commands +* +******************************************************************************/ +typedef enum { + FAPI_PROGRAM_DATA = 0x0002, /* Program data. */ + FAPI_ERASE_SECTOR = 0x0006, /* Erase sector. */ + FAPI_ERASE_BANK = 0x0008, /* Erase bank. */ + FAPI_VALIDATE_SECTOR = 0x000E, /* Validate sector. */ + FAPI_CLEAR_STATUS = 0x0010, /* Clear status. */ + FAPI_PROGRAM_RESUME = 0x0014, /* Program resume. */ + FAPI_ERASE_RESUME = 0x0016, /* Erase resume. */ + FAPI_CLEAR_MORE = 0x0018, /* Clear more. */ + FAPI_PROGRAM_SECTOR = 0x0020, /* Program sector. */ + FAPI_ERASE_OTP = 0x0030 /* Erase OTP. */ +} flash_state_command_t; + +/****************************************************************************** +* +* Defines for values written to the FLASH_O_FSM_WR_ENA register +* +******************************************************************************/ +#define FSM_REG_WRT_ENABLE 5 +#define FSM_REG_WRT_DISABLE 2 + +/****************************************************************************** +* +* Defines for the bank power mode field the FLASH_O_FBFALLBACK register +* +******************************************************************************/ +#define FBFALLBACK_SLEEP 0 +#define FBFALLBACK_DEEP_STDBY 1 +#define FBFALLBACK_ACTIVE 3 + +/****************************************************************************** +* +* Defines for the bank grace period and pump grace period +* +******************************************************************************/ +#define FLASH_BAGP 0x14 +#define FLASH_PAGP 0x14 + +/****************************************************************************** +* +* Defines for the FW flag bits in the FLASH_O_FWFLAG register +* +******************************************************************************/ +#define FW_WRT_TRIMMED 0x00000001 + +/****************************************************************************** +* +* Defines used by the flash programming functions +* +******************************************************************************/ +typedef volatile uint8_t fwp_write_byte; +#define FWPWRITE_BYTE_ADDRESS \ + ((fwp_write_byte *)((FLASH_BASE + FLASH_O_FWPWRITE0))) + +/****************************************************************************** +* +* Define for FSM command execution +* +******************************************************************************/ +#define FLASH_CMD_EXEC 0x15 + +/****************************************************************************** +* +* Get size of a flash sector in number of bytes. +* +* This function will return the size of a flash sector in number of bytes. +* +* Returns size of a flash sector in number of bytes. +* +******************************************************************************/ +static inline uint32_t flash_sector_size_get(void) +{ + uint32_t sector_size_in_kbyte; + + sector_size_in_kbyte = (HWREG(FLASH_BASE + FLASH_O_FCFG_B0_SSIZE0) & + FLASH_FCFG_B0_SSIZE0_B0_SECT_SIZE_M) >> + FLASH_FCFG_B0_SSIZE0_B0_SECT_SIZE_S; + + /* Return flash sector size in number of bytes. */ + return sector_size_in_kbyte * 1024; +} + +/****************************************************************************** +* +* Get the size of the flash. +* +* This function returns the size of the flash main bank in number of bytes. +* +* Returns the flash size in number of bytes. +* +******************************************************************************/ +static inline uint32_t flash_size_get(void) +{ + uint32_t num_of_sectors; + + /* Get number of flash sectors */ + num_of_sectors = (HWREG(FLASH_BASE + FLASH_O_FLASH_SIZE) & + FLASH_FLASH_SIZE_SECTORS_M) >> + FLASH_FLASH_SIZE_SECTORS_S; + + /* Return flash size in number of bytes */ + return num_of_sectors * flash_sector_size_get(); +} + +/****************************************************************************** +* +* Checks if the Flash state machine has detected an error. +* +* This function returns the status of the Flash State Machine indicating if +* an error is detected or not. Primary use is to check if an Erase or +* Program operation has failed. +* +* Please note that code can not execute in flash while any part of the flash +* is being programmed or erased. This function must be called from ROM or +* SRAM while any part of the flash is being programmed or erased. +* +* Returns status of Flash state machine: +* FAPI_STATUS_FSM_ERROR +* FAPI_STATUS_SUCCESS +* +******************************************************************************/ +static inline uint32_t flash_check_fsm_for_error(void) +{ + if (HWREG(FLASH_BASE + FLASH_O_FMSTAT) & FLASH_FMSTAT_CSTAT) + return FAPI_STATUS_FSM_ERROR; + else + return FAPI_STATUS_SUCCESS; +} + +/****************************************************************************** +* +* Checks if the Flash state machine is ready. +* +* This function returns the status of the Flash State Machine indicating if +* it is ready to accept a new command or not. Primary use is to check if an +* Erase or Program operation has finished. +* +* Please note that code can not execute in flash while any part of the flash +* is being programmed or erased. This function must be called from ROM or +* SRAM while any part of the flash is being programmed or erased. +* +* Returns readiness status of Flash state machine: +* FAPI_STATUS_FSM_READY +* FAPI_STATUS_FSM_BUSY +* +******************************************************************************/ +static inline uint32_t flash_check_fsm_for_ready(void) +{ + if (HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_BUSY) + return FAPI_STATUS_FSM_BUSY; + else + return FAPI_STATUS_FSM_READY; +} + +/****************************************************************************** +* +* Erase a flash sector. +* +* This function will erase the specified flash sector. The function will +* not return until the flash sector has been erased or an error condition +* occurred. If flash top sector is erased the function will program the +* the device security data bytes with default values. The device security +* data located in the customer configuration area of the flash top sector, +* must have valid values at all times. These values affect the configuration +* of the device during boot. +* +* Please note that code can not execute in flash while any part of the flash +* is being programmed or erased. This function must only be executed from ROM +* or SRAM. +* +* sector_address is the starting address in flash of the sector to be +* erased. +* +* Returns the status of the sector erase: +* FAPI_STATUS_SUCCESS : Success. +* FAPI_STATUS_INCORRECT_DATABUFFER_LENGTH : Invalid argument. +* FAPI_STATUS_FSM_ERROR : Programming error was encountered. +* +******************************************************************************/ +extern uint32_t flash_sector_erase(uint32_t sector_address); + +/****************************************************************************** +* +* Erase all unprotected sectors in the flash main bank. +* +* This function will erase all unprotected flash sectors. The function will +* not return until the flash sectors has been erased or an error condition +* occurred. Since the flash top sector is erased the function will program the +* the device security data bytes with default values. The device security +* data located in the customer configuration area of the flash top sector, +* must have valid values at all times. These values affect the configuration +* of the device during boot. The execution time of the operation increases if +* erase precondition is forced. This will cause the flash module to first +* program all 1 bits in the bank to 0 before the actual erase is started. +* +* force_precondition controls if erase precondition should be forced. +* +* Returns the status of the sector erase: +* FAPI_STATUS_SUCCESS : Success +* FAPI_STATUS_FSM_ERROR : Erase error was encountered. +* +******************************************************************************/ +extern uint32_t flash_bank_erase(bool force_precondition); + +/****************************************************************************** +* +* Programs unprotected main bank flash sectors. +* +* This function will program a sequence of bytes into the on-chip flash. +* Programming each location consists of the result of an AND operation +* of the new data and the existing data; in other words bits that contain +* 1 can remain 1 or be changed to 0, but bits that are 0 cannot be changed +* to 1. Therefore, a byte can be programmed multiple times as long as these +* rules are followed; if a program operation attempts to change a 0 bit to +* a 1 bit, that bit will not have its value changed. +* +* This function will not return until the data has been programmed or an +* programming error has occurred. +* +* Please note that code can not execute in flash while any part of the flash +* is being programmed or erased. This function must only be executed from ROM +* or SRAM. +* +* The data_buffer pointer cannot point to flash. +* +* data_buffer is a pointer to the data to be programmed. +* address is the starting address in flash to be programmed. +* count is the number of bytes to be programmed. +* +* Returns status of the flash programming: +* FAPI_STATUS_SUCCESS : Success. +* FAPI_STATUS_INCORRECT_DATABUFFER_LENGTH : Too many bytes were requested. +* FAPI_STATUS_FSM_ERROR : Programming error was encountered. +* +******************************************************************************/ +extern uint32_t flash_program(uint8_t *data_buffer, uint32_t address, + uint32_t count); + +/****************************************************************************** +* +* Disables all sectors for erase and programming on the active bank. +* +* This function disables all sectors for erase and programming on the active +* bank and enables the Idle Reading Power reduction mode if no low power +* mode is configured. Furthermore, an additional level of protection from +* erase is enabled. +* +* Please note that code can not execute in flash while any part of the flash +* is being programmed or erased. +* +******************************************************************************/ +extern void flash_disable_sectors_for_write(void); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef OPENOCD_LOADERS_FLASH_CC26XX_FLASH_H */ diff --git a/contrib/loaders/flash/cc26xx/flashloader.c b/contrib/loaders/flash/cc26xx/flashloader.c new file mode 100644 index 000000000..2eaf61864 --- /dev/null +++ b/contrib/loaders/flash/cc26xx/flashloader.c @@ -0,0 +1,177 @@ +/****************************************************************************** +* +* Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#include +#include +#include "flashloader.h" +#include "flash.h" + +/* Array holding erased state of the flash sectors. */ +static bool g_is_erased[FLASH_MAX_SECTOR_COUNT]; + +extern uint8_t g_retain_buf[]; + +uint32_t flashloader_init(struct flash_params *params, uint8_t *buf1, + uint8_t *buf2) +{ + /* Initialize params buffers */ + memset((void *)params, 0, 2 * sizeof(struct flash_params)); + params[0].buf_addr = (uint32_t)buf1; + params[1].buf_addr = (uint32_t)buf2; + + /* Mark all sectors at "not erased" */ + memset(g_is_erased, false, sizeof(g_is_erased)); + + return STATUS_OK; +} + +uint32_t flashloader_erase_and_program(uint8_t *src, uint32_t address, + uint32_t byte_count) +{ + if (byte_count > BUFFER_LEN) + return STATUS_FAILED_INVALID_ARGUMENTS; + + /* Erase affected sectors */ + uint32_t status = flashloader_erase_sectors(address, byte_count); + + if (status != STATUS_OK) + return status; + + /* Program data */ + status = flashloader_program(src, address, byte_count); + + return status; +} + +uint32_t flashloader_program_with_retain(uint8_t *src, uint32_t address, + uint32_t byte_count) +{ +#if (BUFFER_LEN > FLASH_ERASE_SIZE) +#error Buffer size cannot be larger than the flash sector size! +#endif + + uint32_t first_sector_idx; + uint32_t last_sector_idx; + uint32_t status = STATUS_OK; + uint32_t i; + + first_sector_idx = flashloader_address_to_sector(address); + last_sector_idx = flashloader_address_to_sector(address + byte_count - 1); + + /* Mark all sectors as "not erased" before starting */ + memset(g_is_erased, false, sizeof(g_is_erased)); + + uint32_t sec_offset = address % FLASH_ERASE_SIZE; + uint32_t curr_count; + uint32_t src_offset = 0; + + for (i = first_sector_idx; i <= last_sector_idx; i++) { + + /* Chop off at sector boundary if data goes into the next sector. */ + curr_count = byte_count; + if ((address + byte_count) > ((i+1) * FLASH_ERASE_SIZE)) + curr_count -= (address + byte_count) % FLASH_ERASE_SIZE; + + /* Copy flash sector to retain buffer */ + memcpy(g_retain_buf, (void *)(i * FLASH_ERASE_SIZE), FLASH_ERASE_SIZE); + + /* Copy data buffer to retain buffer */ + memcpy(&g_retain_buf[sec_offset], &src[src_offset], curr_count); + + /* Erase and program from retain buffer */ + status = flashloader_erase_and_program(g_retain_buf, + (i * FLASH_ERASE_SIZE), FLASH_ERASE_SIZE); + if (status != STATUS_OK) + return status; + + address += curr_count; + sec_offset = address % FLASH_ERASE_SIZE; + byte_count -= curr_count; + src_offset += curr_count; + } + + return status; +} + +uint32_t flashloader_erase_all(void) +{ + if (flash_bank_erase(true) != FAPI_STATUS_SUCCESS) + return STATUS_FAILED_ERASE_ALL; + + memset(g_is_erased, true, sizeof(g_is_erased)); + + return STATUS_OK; +} + +uint32_t flashloader_erase_sectors(uint32_t address, uint32_t byte_count) +{ + uint32_t first_sector_idx; + uint32_t last_sector_idx; + uint32_t status; + uint32_t idx; + + /* Floor address to the start of the sector and convert to sector number */ + first_sector_idx = flashloader_address_to_sector(address); + last_sector_idx = flashloader_address_to_sector(address + byte_count - 1); + + /* Erase given sector(s) */ + for (idx = first_sector_idx; idx <= last_sector_idx; idx++) { + + /* Only erase sectors that haven't already been erased */ + if (g_is_erased[idx] == false) { + status = flash_sector_erase(idx * FLASH_ERASE_SIZE); + if (status != FAPI_STATUS_SUCCESS) { + status = (STATUS_FAILED_SECTOR_ERASE | + ((idx << STATUS_EXT_INFO_S) & STATUS_EXT_INFO_M) | + ((status << STATUS_ROM_CODE_S) & STATUS_ROM_CODE_M)); + return status; + } + g_is_erased[idx] = true; + } + } + + return STATUS_OK; +} + +uint32_t flashloader_program(uint8_t *src, uint32_t address, + uint32_t byte_count) +{ + uint32_t status = flash_program(src, address, byte_count); + if (status != FAPI_STATUS_SUCCESS) { + status = (STATUS_FAILED_PROGRAM | + ((status << STATUS_ROM_CODE_S) & STATUS_ROM_CODE_M)); + } + + return STATUS_OK; +} diff --git a/contrib/loaders/flash/cc26xx/flashloader.h b/contrib/loaders/flash/cc26xx/flashloader.h new file mode 100644 index 000000000..aec74aaa9 --- /dev/null +++ b/contrib/loaders/flash/cc26xx/flashloader.h @@ -0,0 +1,187 @@ +/****************************************************************************** +* +* Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#ifndef OPENOCD_LOADERS_FLASH_CC26XX_FLASHLOADER_H +#define OPENOCD_LOADERS_FLASH_CC26XX_FLASHLOADER_H + +#include +#include +#include +#include "flash.h" + +/* Number of elements in an array */ +#define NELEMS(a) (sizeof(a) / sizeof(a[0])) + +struct __attribute__((__packed__)) flash_params { + uint32_t dest; /* Destination address in flash */ + uint32_t len; /* Number of bytes */ + uint32_t cmd; /* Command */ + uint32_t full; /* Handshake signal. Is buffer ready? */ + uint32_t buf_addr; /* Address of data buffer. */ +}; + +typedef enum { + CMD_NO_ACTION = 0, /* No action, default value */ + CMD_ERASE_ALL = 1, /* Erase all unprotected sectors */ + CMD_PROGRAM = 2, /* Program data */ + CMD_ERASE_AND_PROGRAM = 3, /* Erase and program data */ + CMD_ERASE_AND_PROGRAM_WITH_RETAIN = 4, /* Erase and program, but retain */ + /* sector data outside given range */ + CMD_ERASE_SECTORS = 5 /* Erase unprotected sectors */ +} flash_commands_t; + +typedef enum { + BUFFER_EMPTY = 0x0, /* No data in buffer, flags last task complete */ + BUFFER_FULL = 0xFFFFFFFF /* Buffer has data, flags next task to start */ +} flash_handshake_t; + +#define STATUS_FLASHLOADER_STATUS_M 0x0000FFFF +#define STATUS_FLASHLOADER_STATUS_S 0 +#define STATUS_ROM_CODE_M 0x00FF0000 +#define STATUS_ROM_CODE_S 16 +#define STATUS_EXT_INFO_M 0xFF000000 +#define STATUS_EXT_INFO_S 24 + +typedef enum { + STATUS_OK = 0, + STATUS_FAILED_ERASE_ALL = 0x101, + STATUS_FAILED_SECTOR_ERASE = 0x102, + STATUS_FAILED_PROGRAM = 0x103, + STATUS_FAILED_INVALID_ARGUMENTS = 0x104, + STATUS_FAILED_UNKNOWN_COMMAND = 0x105, +} flash_status_t; + +/* The buffer size used by the flashloader. The size of 1 flash sector. */ +#define BUFFER_LEN FLASH_ERASE_SIZE + +/* +* This function initializes the flashloader. The application must +* allocate memory for the two data buffers and the flash_params structures. +* +* params Pointer an flash_params array with 2 elements. +* buf1 Pointer to data buffer 1 +* buf2 Pointer to data buffer 2 +* +* Returns STATUS_OK +* +*/ +extern uint32_t flashloader_init(struct flash_params *params, uint8_t *buf1, + uint8_t *buf2); + +/* +* Erase and program the necessary sectors. Data outside the given +* range will be deleted. +* +* src Pointer to buffer containing the data. +* address Start address in device flash +* byte_count The number of bytes to program +* +* Returns STATUS_OK on success. For status on failure: +* See flashloader_program() and flashloader_erase_sectors(). +* +*/ +extern uint32_t flashloader_erase_and_program(uint8_t *src, uint32_t address, + uint32_t byte_count); + +/* +* Erase and program the device sectors. Data outside the given +* data range will be kept unchanged. +* +* src Pointer to buffer containing the data. +* address Start address in device flash +* byte_count The number of bytes to program +* +* Returns STATUS_OK on success. For status on failure: +* See flashloader_program() and flashloader_erase_sectors(). +* +*/ +extern uint32_t flashloader_program_with_retain(uint8_t *src, uint32_t address, + uint32_t byte_count); + +/* +* Erases all flash sectors (that are not write-protected). +* +* Returns STATUS_OK on success. +* +*/ +extern uint32_t flashloader_erase_all(void); + +/* +* Erases the flash sectors affected by the given range. +* +* This function only erases sectors that are not already erased. +* +* start_addr The first address in the range. +* byte_count The number of bytes in the range. +* +* Returns STATUS_OK on success. Returns a combined status on failure: +* [31:24] The sector that failed. +* [23:16] ROM function status code. 0 means success. +* [16: 0] STATUS_FAILED_SECTOR_ERASE +* +*/ +extern uint32_t flashloader_erase_sectors(uint32_t start_addr, + uint32_t byte_count); + +/* +* Program the given range. +* +* This function does not erase anything, it assumes the sectors are ready to +* be programmed. +* +* src Pointer to buffer containing the data. +* address Start address in device flash +* byte_count The number of bytes to program +* +* Returns STATUS_OK on success. Returns a combined status value on failure: +* [31:16] ROM function status code. 0 means success. +* [15:0 ] STATUS_FAILED_PROGRAM +* +*/ +extern uint32_t flashloader_program(uint8_t *src, uint32_t address, + uint32_t byte_count); + +/* +* Convert the input address into a sector number. +* +* address The address. +* +* Returns the flash sector which the address resides in. The first sector +* is sector 0. +* +*/ +static inline uint32_t flashloader_address_to_sector(uint32_t address) + { return (address / FLASH_ERASE_SIZE); }; + +#endif /* #ifndef OPENOCD_LOADERS_FLASH_CC26XX_FLASHLOADER_H */ diff --git a/contrib/loaders/flash/cc26xx/hw_regs.h b/contrib/loaders/flash/cc26xx/hw_regs.h new file mode 100644 index 000000000..830d3af25 --- /dev/null +++ b/contrib/loaders/flash/cc26xx/hw_regs.h @@ -0,0 +1,1382 @@ +/****************************************************************************** +* +* Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#ifndef OPENOCD_LOADERS_FLASH_CC26XX_HW_REGS_H +#define OPENOCD_LOADERS_FLASH_CC26XX_HW_REGS_H + +/****************************************************************************** +* +* Macros for direct hardware access. +* +* If using these macros the programmer should be aware of any limitations to +* the address accessed i.e. if it supports word and/or byte access. +* +******************************************************************************/ +/* Word (32 bit) access to address x */ +/* Read example : my32BitVar = HWREG(base_addr + offset) ; */ +/* Write example : HWREG(base_addr + offset) = my32BitVar ; */ +#define HWREG(x) (*((volatile unsigned long *)(x))) + +/* Half word (16 bit) access to address x */ +/* Read example : my16BitVar = HWREGH(base_addr + offset) ; */ +/* Write example : HWREGH(base_addr + offset) = my16BitVar ; */ +#define HWREGH(x) (*((volatile unsigned short *)(x))) + +/* Byte (8 bit) access to address x */ +/* Read example : my8BitVar = HWREGB(base_addr + offset) ; */ +/* Write example : HWREGB(base_addr + offset) = my8BitVar ; */ +#define HWREGB(x) (*((volatile unsigned char *)(x))) + +/****************************************************************************** +* +* Macro for access to bit-band supported addresses via the bit-band region. +* +* Macro calculates the corresponding address to access in the bit-band region +* based on the actual address of the memory/register and the bit number. +* +* Do NOT use this macro to access the bit-band region directly! +* +******************************************************************************/ +/* Bit-band access to address x bit number b using word access (32 bit) */ +#define HWREGBITW(x, b) \ + HWREG(((unsigned long)(x) & 0xF0000000) | 0x02000000 | \ + (((unsigned long)(x) & 0x000FFFFF) << 5) | ((b) << 2)) + +/****************************************************************************** +* +* Memory mapped components base address definitions +* +******************************************************************************/ +#define FLASH_BASE 0x40030000 +#define FLASH_CFG_BASE 0x50000000 +#define AON_PMCTL_BASE 0x40090000 + +/****************************************************************************** +* +* This section defines the register offsets of FLASH component +* +******************************************************************************/ + +/* FMC and Efuse Status */ +#define FLASH_O_STAT 0x0000001C + +/* Configuration */ +#define FLASH_O_CFG 0x00000024 + +/* Flash Size Configuration */ +#define FLASH_O_FLASH_SIZE 0x0000002C + +/* Firmware Lock */ +#define FLASH_O_FWLOCK 0x0000003C + +/* Firmware Flags */ +#define FLASH_O_FWFLAG 0x00000040 + +/* FMC Read Control */ +#define FLASH_O_FRDCTL 0x00002000 + +/* FMC Bank Protection */ +#define FLASH_O_FBPROT 0x00002030 + +/* FMC Bank Sector Enable */ +#define FLASH_O_FBSE 0x00002034 + +/* FMC Module Access Control */ +#define FLASH_O_FMAC 0x00002050 + +/* FMC Module Status */ +#define FLASH_O_FMSTAT 0x00002054 + +/* FMC Flash Lock */ +#define FLASH_O_FLOCK 0x00002064 + +/* FMC VREADCT Trim */ +#define FLASH_O_FVREADCT 0x00002080 + +/* FMC VHVCT1 Trim */ +#define FLASH_O_FVHVCT1 0x00002084 + +/* FMC VHVCT2 Trim */ +#define FLASH_O_FVHVCT2 0x00002088 + +/* FMC VNVCT Trim */ +#define FLASH_O_FVNVCT 0x00002090 + +/* FMC VSL_P Trim */ +#define FLASH_O_FVSLP 0x00002094 + +/* FMC VWLCT Trim */ +#define FLASH_O_FVWLCT 0x00002098 + +/* FMC Sequential Pump Information */ +#define FLASH_O_FSEQPMP 0x000020A8 + +/* FMC FSM Command */ +#define FLASH_O_FSM_CMD 0x0000220C + +/* FMC FSM Program/Erase Operation Setup */ +#define FLASH_O_FSM_PE_OSU 0x00002210 + +/* FMC FSM Voltage Status Setup */ +#define FLASH_O_FSM_VSTAT 0x00002214 + +/* FMC FSM Program/Erase Verify Setup */ +#define FLASH_O_FSM_PE_VSU 0x00002218 + +/* FMC FSM Compare Verify Setup */ +#define FLASH_O_FSM_CMP_VSU 0x0000221C + +/* FMC FSM EXECUTEZ to Valid Data */ +#define FLASH_O_FSM_EX_VAL 0x00002220 + +/* FMC FSM Read Mode Hold */ +#define FLASH_O_FSM_RD_H 0x00002224 + +/* FMC FSM Program Hold */ +#define FLASH_O_FSM_P_OH 0x00002228 + +/* FMC FSM Erase Operation Hold */ +#define FLASH_O_FSM_ERA_OH 0x0000222C + +/* FMC FSM Program/Erase Verify Hold */ +#define FLASH_O_FSM_PE_VH 0x00002234 + +/* FMC FSM Program Pulse Width */ +#define FLASH_O_FSM_PRG_PW 0x00002240 + +/* FMC FSM Erase Pulse Width */ +#define FLASH_O_FSM_ERA_PW 0x00002244 + +/* FMC FSM Maximum Programming Pulses */ +#define FLASH_O_FSM_PRG_PUL 0x00002268 + +/* FMC FSM Maximum Erase Pulses */ +#define FLASH_O_FSM_ERA_PUL 0x0000226C + +/* FMC FSM EC Step Size */ +#define FLASH_O_FSM_STEP_SIZE 0x00002270 + +/* FMC FSM EC Step Height */ +#define FLASH_O_FSM_EC_STEP_HEIGHT 0x00002278 + +/* FMC FSM_ST_MACHINE */ +#define FLASH_O_FSM_ST_MACHINE 0x0000227C + +/* FMC FSM Register Write Enable */ +#define FLASH_O_FSM_WR_ENA 0x00002288 + +/* FMC FSM Command Execute */ +#define FLASH_O_FSM_EXECUTE 0x000022B4 + +/* FMC FSM Sector Erased 1 */ +#define FLASH_O_FSM_SECTOR1 0x000022C0 + +/* FMC FSM Sector Erased 2 */ +#define FLASH_O_FSM_SECTOR2 0x000022C4 + +/* FMC Flash Bank 0 Starting Address */ +#define FLASH_O_FCFG_B0_START 0x00002410 + +/* FMC Flash Bank 0 Sector Size 0 */ +#define FLASH_O_FCFG_B0_SSIZE0 0x00002430 + +/****************************************************************************** +* +* Register: FLASH_O_STAT +* +******************************************************************************/ +/* Field: [2] SAMHOLD_DIS +* +* Status indicator of flash sample and hold sequencing logic. This bit will go +* to 1 some delay after CFG.DIS_IDLE is set to 1. +* 0: Not disabled +* 1: Sample and hold disabled and stable */ +#define FLASH_STAT_SAMHOLD_DIS 0x00000004 + +/* Field: [1] BUSY +* +* Fast version of the FMC FMSTAT.BUSY bit. +* This flag is valid immediately after the operation setting it (FMSTAT.BUSY +* is delayed some cycles) +* 0 : Not busy +* 1 : Busy */ +#define FLASH_STAT_BUSY 0x00000002 + +/****************************************************************************** +* +* Register: FLASH_O_CFG +* +******************************************************************************/ +/* Field: [8] STANDBY_MODE_SEL +* +* [Configured by boot firmware] +* STANDBY mode selection control. This bit, in conjunction with +* STANDBY_PW_SEL, determine which 1 of 4 sub-modes is selected for control of +* the behavior and timing of the STANDBY input to the pump. +* +* 0 : Legacy PG1 behavior is selected when STANDBY_PW_SEL = 00. This is +* referred to as sub-mode 1. When STANDBY_PW_SEL != 00, then sub-mode 2 +* behavior is selected. STANDBY will be glitchy in these modes. +* 1 : STANDBY pulse-width counter modes selected. In these two modes (referred +* to as sub-mode 3 and sub-mode 4), the low time pulse width of the STANDBY +* signal to the pump, is controlled by a programmable timer. STANDBY will not +* be glitchy in these modes. */ +#define FLASH_CFG_STANDBY_MODE_SEL_M 0x00000100 +#define FLASH_CFG_STANDBY_MODE_SEL_S 8 + +/* Field: [7:6] STANDBY_PW_SEL +* +* [Configured by boot firmware] +* STANDBY pulse width counter selection control. These bits, in conjunction +* with STANDBY_MODE_SEL, determine which 1 of 4 sub-modes is selected for +* control of the behavior and timing of the STANDBY input to the pump. +* +* 00 : Legacy PG1 behavior is selected when STANDBY_MODE_SEL=0. Sub-mode 4 is +* selected when STANDBY_MODE_SEL=1. In sub-mode 4, STANDBY will be low for at +* least 9 pump clock cycles. +* 01 : Sub-mode 2 or 3 is selected, and STANDBY will be low for at least 9 +* pump clock cycles. +* 10: Sub-mode 2 or 3 is selected, and STANDBY will be low for at least 5 pump +* clock cycles. +* 11: Sub-mode 2 or 3 is selected, and STANDBY will be low for at least 13 +* pump clock cycles. */ +#define FLASH_CFG_STANDBY_PW_SEL_M 0x000000C0 +#define FLASH_CFG_STANDBY_PW_SEL_S 6 + +/* Field: [1] DIS_STANDBY +* +* [Configured by boot firmware] +* Disable standby functionality in read idle state */ +#define FLASH_CFG_DIS_STANDBY 0x00000002 +#define FLASH_CFG_DIS_STANDBY_BITN 1 +#define FLASH_CFG_DIS_STANDBY_M 0x00000002 + +/* Field: [0] DIS_IDLE +* +* [Configured by boot firmware] +* Disable sample and hold functionality in read idle state */ +#define FLASH_CFG_DIS_IDLE 0x00000001 +#define FLASH_CFG_DIS_IDLE_M 0x00000001 +#define FLASH_CFG_DIS_IDLE_S 0 + +/****************************************************************************** +* +* Register: FLASH_O_FLASH_SIZE +* +******************************************************************************/ +/* Field: [7:0] SECTORS +* +* [Configured by boot firmware] +* Flash size. The number of flash sectors in the configured device. Read +* access to sectors equal to this number or higher will result in an error. +* The CCFG area is the sector (SECTORS - 1) Writing to this register is +* disabled by the CFG.CONFIGURED bit. */ +#define FLASH_FLASH_SIZE_SECTORS_M 0x000000FF +#define FLASH_FLASH_SIZE_SECTORS_S 0 + +/****************************************************************************** +* +* Register: FLASH_O_FRDCTL +* +******************************************************************************/ +/* Field: [11:8] RWAIT +* +* [Configured by boot firmware] +* FMC Wait State. This field determines the FLCLK period during FMC controlled +* flash accesses: +* - During power up/ power down / low power mode +* - During FSM operations like program, erase +* - During software interface mode (see FLOCK , FBSTROBES registers) +* FLCLK_period = HCLK_period X (RWAIT + 1), +* FSM state machine operations are usually twice this amount. This value +* should never be set less than 2. */ +#define FLASH_FRDCTL_RWAIT_M 0x00000F00 +#define FLASH_FRDCTL_RWAIT_S 8 + +/****************************************************************************** +* +* Register: FLASH_O_FBPROT +* +******************************************************************************/ +/* Field: [0] PROTL1DIS +* +* Level 1 Protection Disable bit. Setting this bit disables protection from +* writing to the FBAC.OTPPROTDIS bits as well as the Sector Enable registers +* FBSE for all banks. Clearing this bit enables protection and disables write +* access to the FBAC.OTPPROTDIS register bits and FBSE register. */ +#define FLASH_FBPROT_PROTL1DIS 0x00000001 + +/****************************************************************************** +* +* Register: FLASH_O_FMSTAT +* +******************************************************************************/ +/* Field: [4] CSTAT +* +* Command Status. Once the FSM starts any failure will set this bit. When set, +* this bit informs the host that the program, erase, or validate sector +* command failed and the command was stopped. This bit is cleared by the +* Clear_Status command. For some errors, this will be the only indication of +* an FSM error because the cause does not fall within the other error bit +* types. */ +#define FLASH_FMSTAT_CSTAT 0x00000010 + +/****************************************************************************** +* +* Register: FLASH_O_FVREADCT +* +******************************************************************************/ +/* Field: [3:0] VREADCT +* +* [Configured by boot firmware] +* These bits control the voltage level for the specified pump voltage of +* wordline power supply for read mode. */ +#define FLASH_FVREADCT_VREADCT_M 0x0000000F +#define FLASH_FVREADCT_VREADCT_S 0 + +/****************************************************************************** +* +* Register: FLASH_O_FVHVCT1 +* +******************************************************************************/ +/* Field: [23:20] TRIM13_E +* +* [Configured by boot firmware] +* These bits control the voltage level for the specified pump voltage of high +* voltage supply input during erase operation. */ +#define FLASH_FVHVCT1_TRIM13_E_M 0x00F00000 +#define FLASH_FVHVCT1_TRIM13_E_S 20 + +/* Field: [19:16] VHVCT_E +* +* [Configured by boot firmware] +* These bits control the voltage level for the specified pump voltage of high +* voltage supply input during erase operation. */ +#define FLASH_FVHVCT1_VHVCT_E_M 0x000F0000 +#define FLASH_FVHVCT1_VHVCT_E_S 16 + +/* Field: [7:4] TRIM13_PV +* +* [Configured by boot firmware] +* These bits control the voltage level for the specified pump voltage of high +* voltage supply input during program verify operation. */ +#define FLASH_FVHVCT1_TRIM13_PV_M 0x000000F0 +#define FLASH_FVHVCT1_TRIM13_PV_S 4 + +/* Field: [3:0] VHVCT_PV +* +* [Configured by boot firmware] +* These bits control the voltage level for the specified pump voltage of high +* voltage supply input during program verify operation. */ +#define FLASH_FVHVCT1_VHVCT_PV_M 0x0000000F +#define FLASH_FVHVCT1_VHVCT_PV_S 0 + +/****************************************************************************** +* +* Register: FLASH_O_FVHVCT2 +* +******************************************************************************/ +/* Field: [23:20] TRIM13_P +* +* [Configured by boot firmware] +* These bits control the voltage level for the specified pump voltage of high +* voltage supply input during program operation. */ +#define FLASH_FVHVCT2_TRIM13_P_M 0x00F00000 +#define FLASH_FVHVCT2_TRIM13_P_S 20 + +/* Field: [19:16] VHVCT_P +* +* [Configured by boot firmware] +* These bits control the voltage level for the specified pump voltage of high +* voltage supply input during program operation. */ +#define FLASH_FVHVCT2_VHVCT_P_M 0x000F0000 +#define FLASH_FVHVCT2_VHVCT_P_S 16 + +/****************************************************************************** +* +* Register: FLASH_O_FVNVCT +* +******************************************************************************/ +/* Field: [12:8] VCG2P5CT +* +* [Configured by boot firmware] +* These bits control the voltage level for the VCG 2.5 CT pump voltage. */ +#define FLASH_FVNVCT_VCG2P5CT_M 0x00001F00 +#define FLASH_FVNVCT_VCG2P5CT_S 8 + +/****************************************************************************** +* +* Register: FLASH_O_FVSLP +* +******************************************************************************/ +/* Field: [15:12] VSL_P +* +* [Configured by boot firmware] +* These bits control the voltage level for the specified pump voltage of high +* current power input during program operation. */ +#define FLASH_FVSLP_VSL_P_M 0x0000F000 +#define FLASH_FVSLP_VSL_P_S 12 + +/****************************************************************************** +* +* Register: FLASH_O_FVWLCT +* +******************************************************************************/ +/* Field: [4:0] VWLCT_P +* +* [Configured by boot firmware] +* These bits control the voltage level for the specified pump voltage of +* wordline power supply during programming operations. */ +#define FLASH_FVWLCT_VWLCT_P_M 0x0000001F +#define FLASH_FVWLCT_VWLCT_P_S 0 + +/****************************************************************************** +* +* Register: FLASH_O_FSEQPMP +* +******************************************************************************/ +/* Field: [21:20] TRIM_1P7 +* +* [Configured by boot firmware] +* This register goes directly to the pump's TRIM_1P7 port pins. */ +#define FLASH_FSEQPMP_TRIM_1P7_M 0x00300000 +#define FLASH_FSEQPMP_TRIM_1P7_S 20 + +/* Field: [14:12] VIN_AT_X +* +* This register controls to the pump's VIN_AT_XPX port pins with the following +* encoding; +* +* If VIN_BY_PASS=0 then pump VIN_AT_XPX is equal to VIN_AT_XIN input ports +* from the BATMON logic after clocking through synchronizers and the sequence +* checker FSM logic contained in the flash wrapper. +* +* If VIN_BY_PASS=1 and VIN_AT_X=??? +* +* 0: then all pump VIN_AT_XPX signals are 0. +* 1: then pump VIN_AT_1P7 is set. +* 2: then pump VIN_AT_2P1 is also set. +* 3: then pump VIN_AT_2P4 is also set. +* 4-7: then pump VIN_AT_3P0 is also set (ie all VIN_AT_XPX signals are 1). */ +#define FLASH_FSEQPMP_VIN_AT_X_M 0x00007000 +#define FLASH_FSEQPMP_VIN_AT_X_S 12 + +/* Field: [8] VIN_BY_PASS +* +* [Configured by boot firmware] +* +* When this bit is a zero, the pump's VIN_AT_XPX ports comes from the FMC +* input port VIN_AT_XIN. +* +* When this bit is a one, the pump's VIN_AT_XPX ports comes from the VIN_AT_X +* bits in 14:12. */ +#define FLASH_FSEQPMP_VIN_BY_PASS 0x00000100 +#define FLASH_FSEQPMP_VIN_BY_PASS_M 0x00000100 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_PE_OSU +* +******************************************************************************/ +/* Field: [15:8] PGM_OSU +* +* [Configured by boot firmware] +* Program Operation Setup time. This determines the flash clocks from the mode +* change to program, to the start of the program pulse. */ +#define FLASH_FSM_PE_OSU_PGM_OSU_M 0x0000FF00 +#define FLASH_FSM_PE_OSU_PGM_OSU_S 8 + +/* Field: [7:0] ERA_OSU +* +* [Configured by boot firmware] +* Erase Operation Setup time. This determines the flash clocks from the mode +* change to erase, to the start of the erase pulse. */ +#define FLASH_FSM_PE_OSU_ERA_OSU_M 0x000000FF +#define FLASH_FSM_PE_OSU_ERA_OSU_S 0 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_VSTAT +* +******************************************************************************/ +/* Field: [15:12] VSTAT_CNT +* +* [Configured by boot firmware] +* Voltage Status Count. Gives the number of consecutive HCLK pulses that must +* be out of range before a voltage-out-of-range status error is given in +* FMSTAT.VOLSTAT. One pulse in range will reset the counter. This is mainly a +* glitch filter on the voltage status pump signal. */ +#define FLASH_FSM_VSTAT_VSTAT_CNT_M 0x0000F000 +#define FLASH_FSM_VSTAT_VSTAT_CNT_S 12 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_PE_VSU +* +******************************************************************************/ +/* Field: [15:8] PGM_VSU +* +* [Configured by boot firmware] +* Program Verify Setup time. This determines the flash clocks from the mode +* change to program verify, to the change of address and the beginning of the +* address setup time. */ +#define FLASH_FSM_PE_VSU_PGM_VSU_M 0x0000FF00 +#define FLASH_FSM_PE_VSU_PGM_VSU_S 8 + +/* Field: [7:0] ERA_VSU +* +* [Configured by boot firmware] +* Erase Verify Setup time. This determines the flash clocks from the mode +* change to erase verify, to the change of address and the beginning of the +* address setup time. */ +#define FLASH_FSM_PE_VSU_ERA_VSU_M 0x000000FF +#define FLASH_FSM_PE_VSU_ERA_VSU_S 0 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_CMP_VSU +* +******************************************************************************/ +/* Field: [15:12] ADD_EXZ +* +* [Configured by boot firmware] +* Address to EXECUTEZ low setup time. This determines the flash clocks from +* the row address change to the time EXECUTEZ goes low. All operations use +* this value. */ +#define FLASH_FSM_CMP_VSU_ADD_EXZ_M 0x0000F000 +#define FLASH_FSM_CMP_VSU_ADD_EXZ_S 12 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_EX_VAL +* +******************************************************************************/ +/* Field: [15:8] REP_VSU +* +* [Configured by boot firmware] +* Repeat Verify action setup. If a program or erase operation advances to the +* program_verify or erase_verify then this special shorter mode transition +* time will be used in place of FSM_PE_VSU.PGM_VSU or FSM_PE_VSU.ERA_VSU +* times. */ +#define FLASH_FSM_EX_VAL_REP_VSU_M 0x0000FF00 +#define FLASH_FSM_EX_VAL_REP_VSU_S 8 + +/* Field: [7:0] EXE_VALD +* +* [Configured by boot firmware] +* EXECUTEZ low to valid Data. Determines the number of Flash clock cycles from +* EXECUTEZ going low to the time the verify data can be read in the program +* verify mode. Erase and compact verify is always a constant value which is +* currently set at one flash clock. This value must be greater than 0. */ +#define FLASH_FSM_EX_VAL_EXE_VALD_M 0x000000FF +#define FLASH_FSM_EX_VAL_EXE_VALD_S 0 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_RD_H +* +******************************************************************************/ +/* Field: [7:0] RD_H +* +* [Configured by boot firmware] +* Read mode hold. This determines the number of flash clocks from the start of +* the Read mode at the end of the operations until the FSM clears the +* FMSTAT.BUSY. Writing a zero to this register will result in a value of 1. +* The reset value of this register is 0x3Ah before FMC version 3.0.10.0 and +* 0x5Ah after this version. */ +#define FLASH_FSM_RD_H_RD_H_M 0x000000FF +#define FLASH_FSM_RD_H_RD_H_S 0 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_P_OH +* +******************************************************************************/ +/* Field: [15:8] PGM_OH +* +* [Configured by boot firmware] +* EXECUTEZ high to mode change. This value determines the flash clocks from +* the EXECUTEZ going high at the end of a program operation to the time the +* mode can change. This value must be greater than or equal to one. */ +#define FLASH_FSM_P_OH_PGM_OH_M 0x0000FF00 +#define FLASH_FSM_P_OH_PGM_OH_S 8 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_ERA_OH +* +******************************************************************************/ +/* Field: [15:0] ERA_OH +* +* [Configured by boot firmware] +* EXECUTEZ high to mode change. Determines the flash clocks from EXECUTEZ +* going high at the end of an erase operation to the time the mode can change. +* If a bank erase is happening, then this is the time to when the TEZ and TCR +* values for bank erase are released. The mode changes 10 flash clocks after +* they are released. This value must be greater than or equal to one. */ +#define FLASH_FSM_ERA_OH_ERA_OH_M 0x0000FFFF +#define FLASH_FSM_ERA_OH_ERA_OH_S 0 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_PE_VH +* +******************************************************************************/ +/* Field: [15:8] PGM_VH +* +* [Configured by boot firmware] +* Program Verify Hold. This register determines the flash clocks from EXECUTEZ +* going high after a program verify to a mode change. This value must be +* greater than or equal to one */ +#define FLASH_FSM_PE_VH_PGM_VH_M 0x0000FF00 +#define FLASH_FSM_PE_VH_PGM_VH_S 8 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_PRG_PW +* +******************************************************************************/ +/* Field: [15:0] PROG_PUL_WIDTH +* +* [Configured by boot firmware] +* Program Pulse width.This register gives the number of flash clocks that the +* EXECUTEZ signal is low in a program operation. */ +#define FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_M 0x0000FFFF +#define FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_S 0 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_ERA_PW +* +******************************************************************************/ +/* Field: [31:0] FSM_ERA_PW +* +* [Configured by boot firmware] +* Erase Pulse width. This register gives the number flash clocks that the +* EXECUTEZ signal is low in an erase operation. */ +#define FLASH_FSM_ERA_PW_FSM_ERA_PW_M 0xFFFFFFFF +#define FLASH_FSM_ERA_PW_FSM_ERA_PW_S 0 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_PRG_PUL +* +******************************************************************************/ +/* Field: [19:16] BEG_EC_LEVEL +* +* [Configured by boot firmware] +* Beginning level for VHVCT. This determines the beginning level for VHVCT +* that is used during erase modes. The pump voltage control registers supply +* the other values that do not change during FSM operations. The reset value +* is the same as FVHVCT1.VHVCT_E. */ +#define FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_M 0x000F0000 +#define FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_S 16 + +/* Field: [11:0] MAX_PRG_PUL +* +* [Configured by boot firmware] +* Maximum Programming Pulses. This register contains the maximum number of +* programming pulses allowed at one address. If it takes any more than this +* amount during a programming operation then the FSM will exit with an error +* and with the program violation, FMSTAT.PGV set, and the general error set, +* FMSTAT.CSTAT. Setting FSM_ST_MACHINE.OVERRIDE to 0 will allow more than this +* maximum value to occur without an error. During pre-conditioning for an +* erase operation the FSM programs all the bits to zero. If the maximum number +* of programming pulses is reached for an address, the FSM will continue with +* the next address and set the FMSTAT.PCV and the general error FMSTAT.CSTAT. +* If the FSM_ST_MACHINE.PREC_STOP_EN is set then the FSM will stop with errors +* when more than the maximum number of pulses is needed. The +* FSM_ST_MACHINE.OVERRIDE bit will take priority over the +* FSM_ST_MACHINE.PREC_STOP_EN and continue doing pulses without setting the +* error bits. Suspend operations will count a pulse if the program operation +* began no matter how long the pulse lasted before is was suspended. Frequent +* suspend or auto-suspend operations could result in max_pulse count error. */ +#define FLASH_FSM_PRG_PUL_MAX_PRG_PUL_M 0x00000FFF +#define FLASH_FSM_PRG_PUL_MAX_PRG_PUL_S 0 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_ERA_PUL +* +******************************************************************************/ +/* Field: [19:16] MAX_EC_LEVEL +* +* [Configured by boot firmware] +* Maximum VHVCT Level. This determines the maximum level for VHVCT that is +* used during erase modes. The FSM will stop advancing VHVCT once it counts up +* to the MAX_EC_LEVEL level from the beginning level. The MAX_EC_LEVEL + +* FSM_EC_STEP_HEIGHT.EC_STEP_HEIGHT must be less than 0x200. The reset value +* is the same as FVHVCT1.VHVCT_E. */ +#define FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_M 0x000F0000 +#define FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_S 16 + +/* Field: [11:0] MAX_ERA_PUL +* +* [Configured by boot firmware] +* Maximum Erase Pulses. This register contains the maximum number of erase +* pulses allowed at one address. If it takes any more than this amount the FSM +* will exit with an error and with both the FMSTAT.EV and FMSTAT.CSTAT bits +* set. Setting FSM_ST_MACHINE.OVERRIDE to 1 will allow more than this maximum +* value to occur without an error. Suspend operations will count a pulse if +* the erase operation began no matter how long the pulse lasted before is was +* suspended. Frequent suspend or auto-suspend operations could result in +* max_pulse count error. */ +#define FLASH_FSM_ERA_PUL_MAX_ERA_PUL_M 0x00000FFF +#define FLASH_FSM_ERA_PUL_MAX_ERA_PUL_S 0 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_STEP_SIZE +* +******************************************************************************/ +/* Field: [24:16] EC_STEP_SIZE +* +* [Configured by boot firmware] +* VHVCT Step Size. This is the number of erase pulses that must be completed +* for each level before the FSM increments the FSM_PUL_CNTR.CUR_EC_LEVEL to +* the next higher level. Actual erase pulses per level equals (EC_STEP_SIZE +* +1). The stepping is only needed for the VHVCT voltage. */ +#define FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_M 0x01FF0000 +#define FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_S 16 + +/****************************************************************************** +* +* Register: FLASH_O_FSM_EC_STEP_HEIGHT +* +******************************************************************************/ +/* Field: [3:0] EC_STEP_HEIGHT +* +* [Configured by boot firmware] +* Height of each EC step. This is the number of counts that the +* FSM_PUL_CNTR.CUR_EC_LEVEL will increment when going to a new level. Actual +* count size equals (EC_STEP_HEIGHT + 1). The stepping applies only to the +* VHVCT voltage. If adding the height to the FSM_PUL_CNTR.CUR_EC_LEVEL results +* in a value higher than the FSM_ERA_PUL.MAX_EC_LEVEL then the +* FSM_PUL_CNTR.CUR_EC_LEVEL will be lowered to the MAX LEVEL before it is used +* in the next erase pulse. */ +#define FLASH_FSM_EC_STEP_HEIGHT_EC_STEP_HEIGHT_M 0x0000000F + +/****************************************************************************** +* +* Register: FLASH_O_FSM_ST_MACHINE +* +******************************************************************************/ +/* Field: [23] DO_PRECOND +* +* [Configured by boot firmware] +* Do preconditioning. When this bit is a one, the FSM will precondition the +* sector or bank before doing an erase operation. When zero, the FSM will just +* begin with the erase verify and skip the preconditioning. */ +#define FLASH_FSM_ST_MACHINE_DO_PRECOND 0x00800000 +#define FLASH_FSM_ST_MACHINE_DO_PRECOND_M 0x00800000 +#define FLASH_FSM_ST_MACHINE_DO_PRECOND_S 23 + +/* Field: [14] ONE_TIME_GOOD +* +* [Configured by boot firmware] +* One Time Good function. If this bit is a one then the 'One Time Good' +* function is enabled for all program operations. This includes operations +* inside the erase functions and other functions. When zero, this function is +* disabled for all modes. When doing the One Time Good function, the FSM will +* attempt to program a location with data. If a desired zero bit reads back +* from the flash one time as good then that bit is blocked from writing a zero +* to the flash array again for this address. When the address changes, all +* bits are unblocked. This prevents a bit from reading 0 in one programming +* pulse and then 1 in the next programming pulse. On the second time the bit +* would get a programming pulse even though it read 0 in an earlier read. If +* this bit is a zero then the zero bits will be masked for each program verify +* operation. It is recommended for this bit to be set to 1. */ +#define FLASH_FSM_ST_MACHINE_ONE_TIME_GOOD 0x00004000 + +/****************************************************************************** +* +* Register: FLASH_O_FCFG_B0_SSIZE0 +* +******************************************************************************/ +/* Field: [3:0] B0_SECT_SIZE +* +* Size of sectors in Bank 0. Common sector size for all sectors in the bank in +* 1K bytes multiples. +* 0x0: 0K bytes +* 0x1: 1K bytes(FLES) +* 0x2: 2K bytes +* 0x4: 4K bytes (FLEE) +* ... +* 0xF: 15K bytes */ +#define FLASH_FCFG_B0_SSIZE0_B0_SECT_SIZE_M 0x0000000F +#define FLASH_FCFG_B0_SSIZE0_B0_SECT_SIZE_S 0 + +/****************************************************************************** +* +* This section defines the register offsets of FCFG1 component +* +******************************************************************************/ + +/* Flash Erase and Program Setup Time */ +#define FCFG1_O_FLASH_E_P 0x00000170 + +/* Flash Compaction, Execute, Program and Read */ +#define FCFG1_O_FLASH_C_E_P_R 0x00000174 + +/* Flash Program, Read, and Program Verify */ +#define FCFG1_O_FLASH_P_R_PV 0x00000178 + +/* Flash Erase Hold and Sequence */ +#define FCFG1_O_FLASH_EH_SEQ 0x0000017C + +/* Flash VHV Erase */ +#define FCFG1_O_FLASH_VHV_E 0x00000180 + +/* Flash Program Pulse */ +#define FCFG1_O_FLASH_PP 0x00000184 + +/* Flash Program and Erase Pulse */ +#define FCFG1_O_FLASH_PROG_EP 0x00000188 + +/* Flash Erase Pulse Width */ +#define FCFG1_O_FLASH_ERA_PW 0x0000018C + +/* Flash VHV */ +#define FCFG1_O_FLASH_VHV 0x00000190 + +/* Flash VHV Program Verify */ +#define FCFG1_O_FLASH_VHV_PV 0x00000194 + +/* Flash Voltages */ +#define FCFG1_O_FLASH_V 0x00000198 + +/* Flash OTP Data 3 */ +#define FCFG1_O_FLASH_OTP_DATA3 0x000002B0 + +/* Flash OTP Data 4 */ +#define FCFG1_O_FLASH_OTP_DATA4 0x00000308 + +/****************************************************************************** +* +* Register: FCFG1_O_FLASH_E_P +* +******************************************************************************/ +/* Field: [31:24] PSU +* +* Program setup time in cycles. Value will be written to +* FLASH:FSM_PE_OSU.PGM_OSU by the flash device driver when an erase/program +* operation is initiated. */ +#define FCFG1_FLASH_E_P_PSU_M 0xFF000000 +#define FCFG1_FLASH_E_P_PSU_S 24 + +/* Field: [23:16] ESU +* +* Erase setup time in cycles. Value will be written to +* FLASH:FSM_PE_OSU.ERA_OSU by the flash device driver when an erase/program +* operation is initiated. */ +#define FCFG1_FLASH_E_P_ESU_M 0x00FF0000 +#define FCFG1_FLASH_E_P_ESU_S 16 + +/* Field: [15:8] PVSU +* +* Program verify setup time in cycles. Value will be written to +* FLASH:FSM_PE_VSU.PGM_VSU by the flash device driver when an erase/program +* operation is initiated. */ +#define FCFG1_FLASH_E_P_PVSU_M 0x0000FF00 +#define FCFG1_FLASH_E_P_PVSU_S 8 + +/* Field: [7:0] EVSU +* +* Erase verify setup time in cycles. Value will be written to +* FLASH:FSM_PE_VSU.ERA_VSU by the flash device driver when an erase/program +* operation is initiated. */ +#define FCFG1_FLASH_E_P_EVSU_M 0x000000FF +#define FCFG1_FLASH_E_P_EVSU_S 0 + +/****************************************************************************** +* +* Register: FCFG1_O_FLASH_C_E_P_R +* +******************************************************************************/ +/* Field: [31:24] RVSU +* +* Repeat verify setup time in cycles. Used for repeated verifies during +* program and erase. Value will be written to FLASH:FSM_EX_VAL.REP_VSU by the +* flash device driver when an erase/program operation is initiated. */ +#define FCFG1_FLASH_C_E_P_R_RVSU_M 0xFF000000 +#define FCFG1_FLASH_C_E_P_R_RVSU_S 24 + +/* Field: [23:16] PV_ACCESS +* +* Program verify EXECUTEZ->data valid time in half-microseconds. Value +* will be converted to number of FCLK cycles by by flash device driver and the +* converted value is written to FLASH:FSM_EX_VAL.EXE_VALD when an +* erase/program operation is initiated. */ +#define FCFG1_FLASH_C_E_P_R_PV_ACCESS_M 0x00FF0000 +#define FCFG1_FLASH_C_E_P_R_PV_ACCESS_S 16 + +/* Field: [15:12] A_EXEZ_SETUP +* +* Address->EXECUTEZ setup time in cycles. Value will be written to +* FLASH:FSM_CMP_VSU.ADD_EXZ by the flash device driver when an erase/program +* operation is initiated. */ +#define FCFG1_FLASH_C_E_P_R_A_EXEZ_SETUP_M 0x0000F000 +#define FCFG1_FLASH_C_E_P_R_A_EXEZ_SETUP_S 12 + +/****************************************************************************** +* +* Register: FCFG1_O_FLASH_P_R_PV +* +******************************************************************************/ +/* Field: [31:24] PH +* +* Program hold time in half-microseconds after SAFELV goes high. Value will be +* converted to number of FCLK cycles by the flash device driver and the +* converted value is written to FLASH:FSM_P_OH.PGM_OH when an erase/program +* operation is initiated. */ +#define FCFG1_FLASH_P_R_PV_PH_M 0xFF000000 +#define FCFG1_FLASH_P_R_PV_PH_S 24 + +/* Field: [23:16] RH +* +* Read hold/mode transition time in cycles. Value will be written to the RD_H +* field bits[7:0] of the FSM_RD_H register in the flash module by the flash +* device driver when an erase/program operation is initiated. */ +#define FCFG1_FLASH_P_R_PV_RH_M 0x00FF0000 +#define FCFG1_FLASH_P_R_PV_RH_S 16 + +/* Field: [15:8] PVH +* +* Program verify hold time in half-microseconds after SAFELV goes high. Value +* will be converted to number of FCLK cycles by the flash device driver and +* the converted value is written to FLASH:FSM_PE_VH.PGM_VH when an +* erase/program operation is initiated. */ +#define FCFG1_FLASH_P_R_PV_PVH_M 0x0000FF00 +#define FCFG1_FLASH_P_R_PV_PVH_S 8 + +/****************************************************************************** +* +* Register: FCFG1_O_FLASH_EH_SEQ +* +******************************************************************************/ +/* Field: [31:24] EH +* +* Erase hold time in half-microseconds after SAFELV goes high. Value will be +* converted to number of FCLK cycles by the flash device driver and the +* converted value is written to FLASH:FSM_ERA_OH.ERA_OH when an erase/program +* operation is initiated. */ +#define FCFG1_FLASH_EH_SEQ_EH_M 0xFF000000 +#define FCFG1_FLASH_EH_SEQ_EH_S 24 + +/* Field: [15:12] VSTAT +* +* Max number of HCLK cycles allowed for pump brown-out. Value will be written +* to FLASH:FSM_VSTAT.VSTAT_CNT when an erase/program operation is initiated. */ +#define FCFG1_FLASH_EH_SEQ_VSTAT_M 0x0000F000 +#define FCFG1_FLASH_EH_SEQ_VSTAT_S 12 + +/****************************************************************************** +* +* Register: FCFG1_O_FLASH_VHV_E +* +******************************************************************************/ +/* Field: [31:16] VHV_E_START +* +* Starting VHV-Erase CT for stairstep erase. Value will be written to +* FLASH:FSM_PRG_PUL.BEG_EC_LEVEL when erase/program operation is initiated. */ +#define FCFG1_FLASH_VHV_E_VHV_E_START_M 0xFFFF0000 +#define FCFG1_FLASH_VHV_E_VHV_E_START_S 16 + +/* Field: [15:0] VHV_E_STEP_HIGHT +* +* Number of VHV CTs to step after each erase pulse (up to the max). The actual +* FMC register value should be one less than this since the FMC starts +* counting from zero. Value will be written to +* FLASH:FSM_EC_STEP_HEIGHT.EC_STEP_HEIGHT when an erase/program operation is +* initiated. */ +#define FCFG1_FLASH_VHV_E_VHV_E_STEP_HIGHT_M 0x0000FFFF +#define FCFG1_FLASH_VHV_E_VHV_E_STEP_HIGHT_S 0 + +/****************************************************************************** +* +* Register: FCFG1_O_FLASH_PP +* +******************************************************************************/ +/* Field: [15:0] MAX_PP +* +* Max program pulse limit per program operation. Value will be written to +* FLASH:FSM_PRG_PUL.MAX_PRG_PUL when an erase/program operation is initiated. */ +#define FCFG1_FLASH_PP_MAX_PP_M 0x0000FFFF +#define FCFG1_FLASH_PP_MAX_PP_S 0 + +/****************************************************************************** +* +* Register: FCFG1_O_FLASH_PROG_EP +* +******************************************************************************/ +/* Field: [31:16] MAX_EP +* +* Max erase pulse limit per erase operation. Value will be written to +* FLASH:FSM_ERA_PUL.MAX_ERA_PUL when an erase/program operation is initiated. */ +#define FCFG1_FLASH_PROG_EP_MAX_EP_M 0xFFFF0000 +#define FCFG1_FLASH_PROG_EP_MAX_EP_S 16 + +/* Field: [15:0] PROGRAM_PW +* +* Program pulse width in half-microseconds. Value will be converted to number +* of FCLK cycles by the flash device driver and the converted value is written +* to FLASH:FSM_PRG_PW.PROG_PUL_WIDTH when a erase/program operation is +* initiated. */ +#define FCFG1_FLASH_PROG_EP_PROGRAM_PW_M 0x0000FFFF +#define FCFG1_FLASH_PROG_EP_PROGRAM_PW_S 0 + +/****************************************************************************** +* +* Register: FCFG1_O_FLASH_ERA_PW +* +******************************************************************************/ +/* Field: [31:0] ERASE_PW +* +* Erase pulse width in half-microseconds. Value will be converted to number of +* FCLK cycles by the flash device driver and the converted value is written to +* FLASH:FSM_ERA_PW.FSM_ERA_PW when a erase/program operation is initiated. */ +#define FCFG1_FLASH_ERA_PW_ERASE_PW_M 0xFFFFFFFF +#define FCFG1_FLASH_ERA_PW_ERASE_PW_S 0 + +/****************************************************************************** +* +* Register: FCFG1_O_FLASH_VHV +* +******************************************************************************/ +/* Field: [27:24] TRIM13_P +* +* Value will be written to FLASH:FVHVCT2.TRIM13_P by the flash device driver +* when an erase/program operation is initiated. */ +#define FCFG1_FLASH_VHV_TRIM13_P_M 0x0F000000 +#define FCFG1_FLASH_VHV_TRIM13_P_S 24 + +/* Field: [19:16] VHV_P +* +* Value will be written to FLASH:FVHVCT2.VHVCT_P by the flash device driver +* when an erase/program operation is initiated. */ +#define FCFG1_FLASH_VHV_VHV_P_M 0x000F0000 +#define FCFG1_FLASH_VHV_VHV_P_S 16 + +/* Field: [11:8] TRIM13_E +* +* Value will be written to FLASH:FVHVCT1.TRIM13_E by the flash device driver +* when an erase/program operation is initiated. */ +#define FCFG1_FLASH_VHV_TRIM13_E_M 0x00000F00 +#define FCFG1_FLASH_VHV_TRIM13_E_S 8 + +/* Field: [3:0] VHV_E +* +* Value will be written to FLASH:FVHVCT1.VHVCT_E by the flash device driver +* when an erase/program operation is initiated */ +#define FCFG1_FLASH_VHV_VHV_E_M 0x0000000F +#define FCFG1_FLASH_VHV_VHV_E_S 0 + +/****************************************************************************** +* +* Register: FCFG1_O_FLASH_VHV_PV +* +******************************************************************************/ +/* Field: [27:24] TRIM13_PV +* +* Value will be written to FLASH:FVHVCT1.TRIM13_PV by the flash device driver +* when an erase/program operation is initiated. */ +#define FCFG1_FLASH_VHV_PV_TRIM13_PV_M 0x0F000000 +#define FCFG1_FLASH_VHV_PV_TRIM13_PV_S 24 + +/* Field: [19:16] VHV_PV +* +* Value will be written to FLASH:FVHVCT1.VHVCT_PV by the flash device driver +* when an erase/program operation is initiated. */ +#define FCFG1_FLASH_VHV_PV_VHV_PV_M 0x000F0000 +#define FCFG1_FLASH_VHV_PV_VHV_PV_S 16 + +/* Field: [15:8] VCG2P5 +* +* Control gate voltage during read, read margin, and erase verify. Value will +* be written to FLASH:FVNVCT.VCG2P5CT by the flash device driver when an +* erase/program operation is initiated. */ +#define FCFG1_FLASH_VHV_PV_VCG2P5_M 0x0000FF00 +#define FCFG1_FLASH_VHV_PV_VCG2P5_S 8 + +/****************************************************************************** +* +* Register: FCFG1_O_FLASH_V +* +******************************************************************************/ +/* Field: [31:24] VSL_P +* +* Sourceline voltage applied to the selected block during programming. Value +* will be written to FLASH:FVSLP.VSL_P by the flash device driver when an +* erase/program operation is initiated. */ +#define FCFG1_FLASH_V_VSL_P_M 0xFF000000 +#define FCFG1_FLASH_V_VSL_P_S 24 + +/* Field: [23:16] VWL_P +* +* Wordline voltage applied to the selected half-row during programming. Value +* will be written to FLASH:FVWLCT.VWLCT_P by the flash device driver when an +* erase/program operation is initiated. */ +#define FCFG1_FLASH_V_VWL_P_M 0x00FF0000 +#define FCFG1_FLASH_V_VWL_P_S 16 + +/* Field: [15:8] V_READ +* +* Wordline voltage applied to the selected block during reads and verifies. +* Value will be written to FLASH:FVREADCT.VREADCT by the flash device driver +* when an erase/program operation is initiated. */ +#define FCFG1_FLASH_V_V_READ_M 0x0000FF00 +#define FCFG1_FLASH_V_V_READ_S 8 + +/****************************************************************************** +* +* Register: FCFG1_O_FLASH_OTP_DATA3 +* +******************************************************************************/ +/* Field: [31:23] EC_STEP_SIZE +* +* Value will be written to FLASH:FSM_STEP_SIZE.EC_STEP_SIZE by the flash +* device driver when a erase/program operation is initiated. */ +#define FCFG1_FLASH_OTP_DATA3_EC_STEP_SIZE_M 0xFF800000 +#define FCFG1_FLASH_OTP_DATA3_EC_STEP_SIZE_S 23 + +/* Field: [22] DO_PRECOND +* +* Value will be written to FLASH:FSM_ST_MACHINE.DO_PRECOND by the flash device +* driver when a erase/program operation is initiated. +* +* Note that during a Total Erase operation the flash bank will always be +* erased with Precondition enabled independent of the value of this FCFG1 bit +* field. */ +#define FCFG1_FLASH_OTP_DATA3_DO_PRECOND_M 0x00400000 +#define FCFG1_FLASH_OTP_DATA3_DO_PRECOND_S 22 + +/* Field: [21:18] MAX_EC_LEVEL +* +* Value will be written to FLASH:FSM_ERA_PUL.MAX_EC_LEVEL by the flash device +* driver when a erase/program operation is initiated. */ +#define FCFG1_FLASH_OTP_DATA3_MAX_EC_LEVEL_M 0x003C0000 +#define FCFG1_FLASH_OTP_DATA3_MAX_EC_LEVEL_S 18 + +/* Field: [17:16] TRIM_1P7 +* +* Value will be written to FLASH:FSEQPMP.TRIM_1P7 by the flash device driver +* when a erase/program operation is initiated. */ +#define FCFG1_FLASH_OTP_DATA3_TRIM_1P7_M 0x00030000 +#define FCFG1_FLASH_OTP_DATA3_TRIM_1P7_S 16 + +/****************************************************************************** +* +* Register: FCFG1_O_FLASH_OTP_DATA4 +* +******************************************************************************/ +/* Field: [31] STANDBY_MODE_SEL_INT_WRT +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to +* FLASH:CFG.STANDBY_MODE_SEL by flash device driver FW when a flash write +* operation is initiated. */ +#define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_WRT_M 0x80000000 +#define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_WRT_S 31 + +/* Field: [30:29] STANDBY_PW_SEL_INT_WRT +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to +* FLASH:CFG.STANDBY_PW_SEL by flash device driver FW when a flash write +* operation is initiated. */ +#define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_WRT_M 0x60000000 +#define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_WRT_S 29 + +/* Field: [28] DIS_STANDBY_INT_WRT +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to +* FLASH:CFG.DIS_STANDBY by flash device driver FW when a flash write operation +* is initiated. */ +#define FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_INT_WRT_M 0x10000000 + +/* Field: [27] DIS_IDLE_INT_WRT +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to +* FLASH:CFG.DIS_IDLE by flash device driver FW when a flash write operation is +* initiated. */ +#define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_WRT_M 0x08000000 +#define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_WRT_S 27 + +/* Field: [26:24] VIN_AT_X_INT_WRT +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to +* FLASH:FSEQPMP.VIN_AT_X by flash device driver FW when a flash write +* operation is initiated. */ +#define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_WRT_M 0x07000000 +#define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_WRT_S 24 + +/* Field: [23] STANDBY_MODE_SEL_EXT_WRT +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to +* FLASH:CFG.STANDBY_MODE_SEL by flash device driver FW when a flash write +* operation is initiated. */ +#define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_WRT_M 0x00800000 +#define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_WRT_S 23 + +/* Field: [22:21] STANDBY_PW_SEL_EXT_WRT +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to +* FLASH:CFG.STANDBY_PW_SEL by flash device driver FW when a flash write +* operation is initiated. */ +#define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_WRT_M 0x00600000 +#define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_WRT_S 21 + +/* Field: [20] DIS_STANDBY_EXT_WRT +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to +* FLASH:CFG.DIS_STANDBY by flash device driver FW when a flash write operation +* is initiated. */ +#define FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_EXT_WRT_M 0x00100000 + +/* Field: [19] DIS_IDLE_EXT_WRT +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to +* FLASH:CFG.DIS_IDLE by flash device driver FW when a flash write operation is +* initiated. */ +#define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_WRT_M 0x00080000 +#define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_WRT_S 19 + +/* Field: [18:16] VIN_AT_X_EXT_WRT +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to +* FLASH:FSEQPMP.VIN_AT_X by flash device driver FW when a flash write +* operation is initiated. */ +#define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_WRT_M 0x00070000 +#define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_WRT_S 16 + +/* Field: [15] STANDBY_MODE_SEL_INT_RD +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to +* FLASH:CFG.STANDBY_MODE_SEL both by boot FW while in safezone, and by flash +* device driver FW after completion of a flash write operation. */ +#define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_RD_M 0x00008000 +#define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_RD_S 15 + +/* Field: [14:13] STANDBY_PW_SEL_INT_RD +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to +* FLASH:CFG.STANDBY_PW_SEL both by boot FW while in safezone, and by flash +* device driver FW after completion of a flash write operation. */ +#define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_RD_M 0x00006000 +#define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_RD_S 13 + +/* Field: [12] DIS_STANDBY_INT_RD +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to +* FLASH:CFG.DIS_STANDBY both by boot FW while in safezone, and by flash device +* driver FW after completion of a flash write operation. */ +#define FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_INT_RD_M 0x00001000 + +/* Field: [11] DIS_IDLE_INT_RD +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to +* FLASH:CFG.DIS_IDLE both by boot FW while in safezone, and by flash device +* driver FW after completion of a flash write operation. */ +#define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_RD_M 0x00000800 +#define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_RD_S 11 + +/* Field: [10:8] VIN_AT_X_INT_RD +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to +* FLASH:FSEQPMP.VIN_AT_X both by boot FW while in safezone, and by flash +* device driver FW after completion of a flash write operation. */ +#define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_RD_M 0x00000700 +#define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_RD_S 8 + +/* Field: [7] STANDBY_MODE_SEL_EXT_RD +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to +* FLASH:CFG.STANDBY_MODE_SEL both by boot FW while in safezone, and by flash +* device driver FW after completion of a flash write operation. */ +#define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_RD_M 0x00000080 +#define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_RD_S 7 + +/* Field: [6:5] STANDBY_PW_SEL_EXT_RD +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to +* FLASH:CFG.STANDBY_PW_SEL both by boot FW while in safezone, and by flash +* device driver FW after completion of a flash write operation. */ +#define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_RD_M 0x00000060 +#define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_RD_S 5 + +/* Field: [4] DIS_STANDBY_EXT_RD +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to +* FLASH:CFG.DIS_STANDBY both by boot FW while in safezone, and by flash device +* driver FW after completion of a flash write operation. */ +#define FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_EXT_RD_M 0x00000010 + +/* Field: [3] DIS_IDLE_EXT_RD +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to +* FLASH:CFG.DIS_IDLE both by boot FW while in safezone, and by flash device +* driver FW after completion of a flash write operation. */ +#define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_RD_M 0x00000008 +#define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_RD_S 3 + +/* Field: [2:0] VIN_AT_X_EXT_RD +* +* If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to +* FLASH:FSEQPMP.VIN_AT_X both by boot FW while in safezone, and by flash +* device driver FW after completion of a flash write operation. */ +#define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_RD_M 0x00000007 +#define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_RD_S 0 + +/****************************************************************************** +* +* This section defines the register offsets of AON_PMCTL component +* +******************************************************************************/ + +/* Power Management Control */ +#if defined(DEVICE_CC26X2) +/* Agama (CC26x2) specific definition */ +#define AON_PMCTL_O_PWRCTL 0x00000010 +#elif defined(DEVICE_CC26X0) +/* Chameleon (CC26x0) specific definition */ +#define AON_PMCTL_O_PWRCTL 0x00000000 +#endif + +/* Field: [1] EXT_REG_MODE +* +* Status of source for VDDRsupply: +* +* 0: DCDC or GLDO are generating VDDR +* 1: DCDC and GLDO are bypassed and an external regulator supplies VDDR */ +#define AON_PMCTL_PWRCTL_EXT_REG_MODE 0x00000002 + +#endif /* #ifndef OPENOCD_LOADERS_FLASH_CC26XX_HW_REGS_H */ diff --git a/contrib/loaders/flash/cc26xx/main.c b/contrib/loaders/flash/cc26xx/main.c new file mode 100644 index 000000000..13204b458 --- /dev/null +++ b/contrib/loaders/flash/cc26xx/main.c @@ -0,0 +1,179 @@ +/****************************************************************************** +* +* Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#include +#include +#include "flashloader.h" + +/* Data buffers used by host to communicate with flashloader */ + +/* Flashloader parameter structure. */ +__attribute__ ((section(".buffers.g_cfg"))) +volatile struct flash_params g_cfg[2]; +/* Data buffer 1. */ +__attribute__ ((section(".buffers.g_buf1"))) +uint8_t g_buf1[BUFFER_LEN]; +/* Data buffer 2. */ +__attribute__ ((section(".buffers.g_buf2"))) +uint8_t g_buf2[BUFFER_LEN]; + +/* Buffer used for program with retain feature */ +__attribute__ ((section(".buffers.g_retain_buf"))) +uint8_t g_retain_buf[BUFFER_LEN]; + +uint32_t g_curr_buf; /* Current buffer used. */ +uint32_t g_vims_ctl; /* Saved flash cache state. */ + +/****************************************************************************** +* +* This function stores the current VIMS configuration before +* - disabling VIMS flash cache +* - flushing the flash line buffers. +* +* Note Not using driverlib calls because it requires using "NO_ROM" define in +* order to work for both Cha. R1 and R2 using the same code. Manually +* doing the steps to minimize code footprint. +* +******************************************************************************/ +static void disable_flash_cache() +{ + /* 1. Make sure VIMS is not currently changing mode (VIMS:STAT register) */ + while ((HWREG(0x40034000) & 0x00000008) == 0x8) + ; + + /* Save current VIMS:CTL state */ + g_vims_ctl = HWREG(0x40034004); + + /* 2. Set VIMS mode to OFF and disable flash line buffers */ + uint32_t new_vims_ctl = g_vims_ctl | 0x33; + HWREG(0x40034004) = new_vims_ctl; + + /* 3. Wait for VIMS to have changed mode (VIMS:STAT register) */ + while ((HWREG(0x40034000) & 0x00000008) == 0x8) + ; +} + +/****************************************************************************** +* +* This function restores the VIMS configuration saved off by +* disable_flash_cache(). +* +* Note Not using driverlib calls because it requires using "NO_ROM" define in +* order to work for both Cha. R1 and R2 using the same code. Manually +* doing the steps to minimize code footprint. +* +******************************************************************************/ +static void restore_cache_state() +{ + HWREG(0x40034004) = g_vims_ctl; + + /* Wait for VIMS to have changed mode (VIMS:STAT register) */ + while ((HWREG(0x40034000) & 0x00000008) == 0x8) + ; +} + +/****************************************************************************** +* +* CC13xx/CC26xx flashloader main function. +* +******************************************************************************/ +int main(void) +{ + flashloader_init((struct flash_params *)g_cfg, g_buf1, g_buf2); + + g_curr_buf = 0; /* start with the first buffer */ + uint32_t status; + + while (1) { + /* Wait for host to signal buffer is ready */ + while (g_cfg[g_curr_buf].full == BUFFER_EMPTY) + ; + + disable_flash_cache(); + + /* Perform requested task */ + switch (g_cfg[g_curr_buf].cmd) { + case CMD_ERASE_ALL: + status = flashloader_erase_all(); + break; + case CMD_PROGRAM: + status = + flashloader_program( + (uint8_t *)g_cfg[g_curr_buf].buf_addr, + g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); + break; + case CMD_ERASE_AND_PROGRAM: + status = + flashloader_erase_and_program( + (uint8_t *)g_cfg[g_curr_buf].buf_addr, + g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); + break; + case CMD_ERASE_AND_PROGRAM_WITH_RETAIN: + status = + flashloader_program_with_retain( + (uint8_t *)g_cfg[g_curr_buf].buf_addr, + g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); + break; + case CMD_ERASE_SECTORS: + status = + flashloader_erase_sectors(g_cfg[g_curr_buf].dest, + g_cfg[g_curr_buf].len); + break; + default: + status = STATUS_FAILED_UNKNOWN_COMMAND; + break; + } + + restore_cache_state(); + + /* Enter infinite loop on error condition */ + if (status != STATUS_OK) { + g_cfg[g_curr_buf].full = status; + while (1) + ; + } + + /* Mark current task complete, and begin looking at next buffer */ + g_cfg[g_curr_buf].full = BUFFER_EMPTY; + g_curr_buf ^= 1; + } +} + +void _exit(int status) +{ + /* Enter infinite loop on hitting an exit condition */ + (void)status; /* Unused parameter */ + while (1) + ; +} diff --git a/contrib/loaders/flash/cc26xx/startup.c b/contrib/loaders/flash/cc26xx/startup.c new file mode 100644 index 000000000..70fd83650 --- /dev/null +++ b/contrib/loaders/flash/cc26xx/startup.c @@ -0,0 +1,97 @@ +/****************************************************************************** +* +* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#include + +/****************************************************************************** +* +* The entry point for the application startup code. +* +******************************************************************************/ +extern int main(void); + +/****************************************************************************** +* +* Reserve space for the system stack. +* +******************************************************************************/ +__attribute__ ((section(".stack"))) +static uint32_t stack[100]; +const uint32_t stack_pntr = (uint32_t)stack + sizeof(stack); + +/****************************************************************************** +* +* The following are constructs created by the linker indicating where the +* the "bss" and "ebss" segments reside in memory. +* +******************************************************************************/ +extern uint32_t _bss; +extern uint32_t _ebss; + +/****************************************************************************** +* +* This is the entry point that handles setting the stack within the allowed +* workspace, initializing the .bss segment, and then jumping to main. +* +******************************************************************************/ +__attribute__ ((section(".entry"))) +void entry(void) +{ + /* Workaround for ITT instructions. */ + __asm(" NOP"); + __asm(" NOP"); + __asm(" NOP"); + __asm(" NOP"); + + /* Initialize stack pointer */ + __asm(" ldr sp, =stack_pntr"); + + /* Zero fill the bss segment. */ + __asm(" ldr r0, =_bss\n" + " ldr r1, =_ebss\n" + " mov r2, #0\n" + " .thumb_func\n" + " zero_loop:\n" + " cmp r0, r1\n" + " it lt\n" + " strlt r2, [r0], #4\n" + " blt zero_loop"); + + /* Call the application's entry point. */ + main(); + + /* If we ever return, enter an infinite loop */ + while (1) + ; +} diff --git a/doc/openocd.texi b/doc/openocd.texi index 0122224c7..3ae11df8c 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5575,7 +5575,18 @@ flash erase_sector 0 0 127 # It will perform a mass erase on BlueNRG-2 @end example Triggering a mass erase is also useful when users want to disable readout protection. +@end deffn +@deffn {Flash Driver} cc26xx +All versions of the SimpleLink CC13xx and CC26xx microcontrollers from Texas +Instruments include internal flash. The cc26xx flash driver supports both the +CC13xx and CC26xx family of devices. The driver automatically recognizes the +specific version's flash parameters and autoconfigures itself. Flash bank 0 +starts at address 0. + +@example +flash bank $_FLASHNAME cc26xx 0 0 0 0 $_TARGETNAME +@end example @end deffn @deffn {Flash Driver} cc3220sf diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 5e5cdcd3e..991869804 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -20,6 +20,7 @@ NOR_DRIVERS = \ %D%/avrf.c \ %D%/bluenrg-x.c \ %D%/cc3220sf.c \ + %D%/cc26xx.c \ %D%/cfi.c \ %D%/dsp5680xx_flash.c \ %D%/efm32.c \ @@ -66,6 +67,7 @@ NOR_DRIVERS = \ NORHEADERS = \ %D%/core.h \ %D%/cc3220sf.h \ + %D%/cc26xx.h \ %D%/cfi.h \ %D%/driver.h \ %D%/imp.h \ diff --git a/src/flash/nor/cc26xx.c b/src/flash/nor/cc26xx.c new file mode 100644 index 000000000..e6e9e5999 --- /dev/null +++ b/src/flash/nor/cc26xx.c @@ -0,0 +1,567 @@ +/*************************************************************************** + * Copyright (C) 2017 by Texas Instruments, Inc. * + * * + * 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 . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include "cc26xx.h" +#include +#include +#include +#include +#include + +#define FLASH_TIMEOUT 8000 + +struct cc26xx_bank { + const char *family_name; + uint32_t icepick_id; + uint32_t user_id; + uint32_t device_type; + uint32_t sector_length; + bool probed; + struct working_area *working_area; + struct armv7m_algorithm armv7m_info; + const uint8_t *algo_code; + uint32_t algo_size; + uint32_t algo_working_size; + uint32_t buffer_addr[2]; + uint32_t params_addr[2]; +}; + +static int cc26xx_auto_probe(struct flash_bank *bank); + +static uint32_t cc26xx_device_type(uint32_t icepick_id, uint32_t user_id) +{ + uint32_t device_type = 0; + + switch (icepick_id & ICEPICK_ID_MASK) { + case CC26X0_ICEPICK_ID: + device_type = CC26X0_TYPE; + break; + case CC26X1_ICEPICK_ID: + device_type = CC26X1_TYPE; + break; + case CC13X0_ICEPICK_ID: + device_type = CC13X0_TYPE; + break; + case CC13X2_CC26X2_ICEPICK_ID: + default: + if ((user_id & USER_ID_CC13_MASK) != 0) + device_type = CC13X2_TYPE; + else + device_type = CC26X2_TYPE; + break; + } + + return device_type; +} + +static uint32_t cc26xx_sector_length(uint32_t icepick_id) +{ + uint32_t sector_length; + + switch (icepick_id & ICEPICK_ID_MASK) { + case CC26X0_ICEPICK_ID: + case CC26X1_ICEPICK_ID: + case CC13X0_ICEPICK_ID: + /* Chameleon family device */ + sector_length = CC26X0_SECTOR_LENGTH; + break; + case CC13X2_CC26X2_ICEPICK_ID: + default: + /* Agama family device */ + sector_length = CC26X2_SECTOR_LENGTH; + break; + } + + return sector_length; +} + +static int cc26xx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr) +{ + struct target *target = bank->target; + struct cc26xx_bank *cc26xx_bank = bank->driver_priv; + + uint32_t status_addr = params_addr + CC26XX_STATUS_OFFSET; + uint32_t status = CC26XX_BUFFER_FULL; + long long start_ms; + long long elapsed_ms; + + int retval = ERROR_OK; + + start_ms = timeval_ms(); + while (CC26XX_BUFFER_FULL == status) { + retval = target_read_u32(target, status_addr, &status); + if (ERROR_OK != retval) + return retval; + + elapsed_ms = timeval_ms() - start_ms; + if (elapsed_ms > 500) + keep_alive(); + if (elapsed_ms > FLASH_TIMEOUT) + break; + }; + + if (CC26XX_BUFFER_EMPTY != status) { + LOG_ERROR("%s: Flash operation failed", cc26xx_bank->family_name); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int cc26xx_init(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct cc26xx_bank *cc26xx_bank = bank->driver_priv; + + int retval; + + /* Make sure we've probed the flash to get the device and size */ + retval = cc26xx_auto_probe(bank); + if (ERROR_OK != retval) + return retval; + + /* Check for working area to use for flash helper algorithm */ + if (NULL != cc26xx_bank->working_area) + target_free_working_area(target, cc26xx_bank->working_area); + retval = target_alloc_working_area(target, cc26xx_bank->algo_working_size, + &cc26xx_bank->working_area); + if (ERROR_OK != retval) + return retval; + + /* Confirm the defined working address is the area we need to use */ + if (CC26XX_ALGO_BASE_ADDRESS != cc26xx_bank->working_area->address) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + /* Write flash helper algorithm into target memory */ + retval = target_write_buffer(target, CC26XX_ALGO_BASE_ADDRESS, + cc26xx_bank->algo_size, cc26xx_bank->algo_code); + if (ERROR_OK != retval) { + LOG_ERROR("%s: Failed to load flash helper algorithm", + cc26xx_bank->family_name); + target_free_working_area(target, cc26xx_bank->working_area); + return retval; + } + + /* Initialize the ARMv7 specific info to run the algorithm */ + cc26xx_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + cc26xx_bank->armv7m_info.core_mode = ARM_MODE_THREAD; + + /* Begin executing the flash helper algorithm */ + retval = target_start_algorithm(target, 0, NULL, 0, NULL, + CC26XX_ALGO_BASE_ADDRESS, 0, &cc26xx_bank->armv7m_info); + if (ERROR_OK != retval) { + LOG_ERROR("%s: Failed to start flash helper algorithm", + cc26xx_bank->family_name); + target_free_working_area(target, cc26xx_bank->working_area); + return retval; + } + + /* + * At this point, the algorithm is running on the target and + * ready to receive commands and data to flash the target + */ + + return retval; +} + +static int cc26xx_quit(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct cc26xx_bank *cc26xx_bank = bank->driver_priv; + + int retval; + + /* Regardless of the algo's status, attempt to halt the target */ + (void)target_halt(target); + + /* Now confirm target halted and clean up from flash helper algorithm */ + retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, FLASH_TIMEOUT, + &cc26xx_bank->armv7m_info); + + target_free_working_area(target, cc26xx_bank->working_area); + cc26xx_bank->working_area = NULL; + + return retval; +} + +static int cc26xx_mass_erase(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct cc26xx_bank *cc26xx_bank = bank->driver_priv; + struct cc26xx_algo_params algo_params; + + int retval; + + if (TARGET_HALTED != target->state) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = cc26xx_init(bank); + if (ERROR_OK != retval) + return retval; + + /* Initialize algorithm parameters */ + buf_set_u32(algo_params.address, 0, 32, 0); + buf_set_u32(algo_params.length, 0, 32, 4); + buf_set_u32(algo_params.command, 0, 32, CC26XX_CMD_ERASE_ALL); + buf_set_u32(algo_params.status, 0, 32, CC26XX_BUFFER_FULL); + + /* Issue flash helper algorithm parameters for mass erase */ + retval = target_write_buffer(target, cc26xx_bank->params_addr[0], + sizeof(algo_params), (uint8_t *)&algo_params); + + /* Wait for command to complete */ + if (ERROR_OK == retval) + retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[0]); + + /* Regardless of errors, try to close down algo */ + (void)cc26xx_quit(bank); + + return retval; +} + +FLASH_BANK_COMMAND_HANDLER(cc26xx_flash_bank_command) +{ + struct cc26xx_bank *cc26xx_bank; + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + cc26xx_bank = malloc(sizeof(struct cc26xx_bank)); + if (NULL == cc26xx_bank) + return ERROR_FAIL; + + /* Initialize private flash information */ + memset((void *)cc26xx_bank, 0x00, sizeof(struct cc26xx_bank)); + cc26xx_bank->family_name = "cc26xx"; + cc26xx_bank->device_type = CC26XX_NO_TYPE; + cc26xx_bank->sector_length = 0x1000; + + /* Finish initialization of bank */ + bank->driver_priv = cc26xx_bank; + bank->next = NULL; + + return ERROR_OK; +} + +static int cc26xx_erase(struct flash_bank *bank, int first, int last) +{ + struct target *target = bank->target; + struct cc26xx_bank *cc26xx_bank = bank->driver_priv; + struct cc26xx_algo_params algo_params; + + uint32_t address; + uint32_t length; + int retval; + + if (TARGET_HALTED != target->state) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* Do a mass erase if user requested all sectors of flash */ + if ((first == 0) && (last == (bank->num_sectors - 1))) { + /* Request mass erase of flash */ + return cc26xx_mass_erase(bank); + } + + address = first * cc26xx_bank->sector_length; + length = (last - first + 1) * cc26xx_bank->sector_length; + + retval = cc26xx_init(bank); + if (ERROR_OK != retval) + return retval; + + /* Set up algorithm parameters for erase command */ + buf_set_u32(algo_params.address, 0, 32, address); + buf_set_u32(algo_params.length, 0, 32, length); + buf_set_u32(algo_params.command, 0, 32, CC26XX_CMD_ERASE_SECTORS); + buf_set_u32(algo_params.status, 0, 32, CC26XX_BUFFER_FULL); + + /* Issue flash helper algorithm parameters for erase */ + retval = target_write_buffer(target, cc26xx_bank->params_addr[0], + sizeof(algo_params), (uint8_t *)&algo_params); + + /* If no error, wait for erase to finish */ + if (ERROR_OK == retval) + retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[0]); + + /* Regardless of errors, try to close down algo */ + (void)cc26xx_quit(bank); + + return retval; +} + +static int cc26xx_protect(struct flash_bank *bank, int set, int first, + int last) +{ + return ERROR_OK; +} + +static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct cc26xx_bank *cc26xx_bank = bank->driver_priv; + struct cc26xx_algo_params algo_params[2]; + uint32_t size = 0; + long long start_ms; + long long elapsed_ms; + uint32_t address; + + uint32_t index; + int retval; + + if (TARGET_HALTED != target->state) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = cc26xx_init(bank); + if (ERROR_OK != retval) + return retval; + + /* Initialize algorithm parameters to default values */ + buf_set_u32(algo_params[0].command, 0, 32, CC26XX_CMD_PROGRAM); + buf_set_u32(algo_params[1].command, 0, 32, CC26XX_CMD_PROGRAM); + + /* Write requested data, ping-ponging between two buffers */ + index = 0; + start_ms = timeval_ms(); + address = bank->base + offset; + while (count > 0) { + + if (count > cc26xx_bank->sector_length) + size = cc26xx_bank->sector_length; + else + size = count; + + /* Put next block of data to flash into buffer */ + retval = target_write_buffer(target, cc26xx_bank->buffer_addr[index], + size, buffer); + if (ERROR_OK != retval) { + LOG_ERROR("Unable to write data to target memory"); + break; + } + + /* Update algo parameters for next block */ + buf_set_u32(algo_params[index].address, 0, 32, address); + buf_set_u32(algo_params[index].length, 0, 32, size); + buf_set_u32(algo_params[index].status, 0, 32, CC26XX_BUFFER_FULL); + + /* Issue flash helper algorithm parameters for block write */ + retval = target_write_buffer(target, cc26xx_bank->params_addr[index], + sizeof(algo_params[index]), (uint8_t *)&algo_params[index]); + if (ERROR_OK != retval) + break; + + /* Wait for next ping pong buffer to be ready */ + index ^= 1; + retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[index]); + if (ERROR_OK != retval) + break; + + count -= size; + buffer += size; + address += size; + + elapsed_ms = timeval_ms() - start_ms; + if (elapsed_ms > 500) + keep_alive(); + } + + /* If no error yet, wait for last buffer to finish */ + if (ERROR_OK == retval) { + index ^= 1; + retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[index]); + } + + /* Regardless of errors, try to close down algo */ + (void)cc26xx_quit(bank); + + return retval; +} + +static int cc26xx_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct cc26xx_bank *cc26xx_bank = bank->driver_priv; + + uint32_t sector_length; + uint32_t value; + int num_sectors; + int max_sectors; + + int retval; + + retval = target_read_u32(target, FCFG1_ICEPICK_ID, &value); + if (ERROR_OK != retval) + return retval; + cc26xx_bank->icepick_id = value; + + retval = target_read_u32(target, FCFG1_USER_ID, &value); + if (ERROR_OK != retval) + return retval; + cc26xx_bank->user_id = value; + + cc26xx_bank->device_type = cc26xx_device_type(cc26xx_bank->icepick_id, + cc26xx_bank->user_id); + + sector_length = cc26xx_sector_length(cc26xx_bank->icepick_id); + + /* Set up appropriate flash helper algorithm */ + switch (cc26xx_bank->icepick_id & ICEPICK_ID_MASK) { + case CC26X0_ICEPICK_ID: + case CC26X1_ICEPICK_ID: + case CC13X0_ICEPICK_ID: + /* Chameleon family device */ + cc26xx_bank->algo_code = cc26x0_algo; + cc26xx_bank->algo_size = sizeof(cc26x0_algo); + cc26xx_bank->algo_working_size = CC26X0_WORKING_SIZE; + cc26xx_bank->buffer_addr[0] = CC26X0_ALGO_BUFFER_0; + cc26xx_bank->buffer_addr[1] = CC26X0_ALGO_BUFFER_1; + cc26xx_bank->params_addr[0] = CC26X0_ALGO_PARAMS_0; + cc26xx_bank->params_addr[1] = CC26X0_ALGO_PARAMS_1; + max_sectors = CC26X0_MAX_SECTORS; + break; + case CC13X2_CC26X2_ICEPICK_ID: + default: + /* Agama family device */ + cc26xx_bank->algo_code = cc26x2_algo; + cc26xx_bank->algo_size = sizeof(cc26x2_algo); + cc26xx_bank->algo_working_size = CC26X2_WORKING_SIZE; + cc26xx_bank->buffer_addr[0] = CC26X2_ALGO_BUFFER_0; + cc26xx_bank->buffer_addr[1] = CC26X2_ALGO_BUFFER_1; + cc26xx_bank->params_addr[0] = CC26X2_ALGO_PARAMS_0; + cc26xx_bank->params_addr[1] = CC26X2_ALGO_PARAMS_1; + max_sectors = CC26X2_MAX_SECTORS; + break; + } + + retval = target_read_u32(target, CC26XX_FLASH_SIZE_INFO, &value); + if (ERROR_OK != retval) + return retval; + num_sectors = value & 0xff; + if (num_sectors > max_sectors) + num_sectors = max_sectors; + + bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); + if (NULL == bank->sectors) + return ERROR_FAIL; + + bank->base = CC26XX_FLASH_BASE_ADDR; + bank->num_sectors = num_sectors; + bank->size = num_sectors * sector_length; + bank->write_start_alignment = 0; + bank->write_end_alignment = 0; + cc26xx_bank->sector_length = sector_length; + + for (int i = 0; i < num_sectors; i++) { + bank->sectors[i].offset = i * sector_length; + bank->sectors[i].size = sector_length; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = 0; + } + + /* We've successfully determined the stats on the flash bank */ + cc26xx_bank->probed = true; + + /* If we fall through to here, then all went well */ + + return ERROR_OK; +} + +static int cc26xx_auto_probe(struct flash_bank *bank) +{ + struct cc26xx_bank *cc26xx_bank = bank->driver_priv; + + int retval = ERROR_OK; + + if (bank->bank_number != 0) { + /* Invalid bank number somehow */ + return ERROR_FAIL; + } + + if (!cc26xx_bank->probed) + retval = cc26xx_probe(bank); + + return retval; +} + +static int cc26xx_protect_check(struct flash_bank *bank) +{ + return ERROR_OK; +} + +static int cc26xx_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct cc26xx_bank *cc26xx_bank = bank->driver_priv; + int printed = 0; + const char *device; + + switch (cc26xx_bank->device_type) { + case CC26X0_TYPE: + device = "CC26x0"; + break; + case CC26X1_TYPE: + device = "CC26x1"; + break; + case CC13X0_TYPE: + device = "CC13x0"; + break; + case CC13X2_TYPE: + device = "CC13x2"; + break; + case CC26X2_TYPE: + device = "CC26x2"; + break; + case CC26XX_NO_TYPE: + default: + device = "Unrecognized"; + break; + } + + printed = snprintf(buf, buf_size, + "%s device: ICEPick ID 0x%08x, USER ID 0x%08x\n", + device, cc26xx_bank->icepick_id, cc26xx_bank->user_id); + + if (printed >= buf_size) + return ERROR_BUF_TOO_SMALL; + + return ERROR_OK; +} + +struct flash_driver cc26xx_flash = { + .name = "cc26xx", + .flash_bank_command = cc26xx_flash_bank_command, + .erase = cc26xx_erase, + .protect = cc26xx_protect, + .write = cc26xx_write, + .read = default_flash_read, + .probe = cc26xx_probe, + .auto_probe = cc26xx_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = cc26xx_protect_check, + .info = cc26xx_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/cc26xx.h b/src/flash/nor/cc26xx.h new file mode 100644 index 000000000..51a09f19b --- /dev/null +++ b/src/flash/nor/cc26xx.h @@ -0,0 +1,101 @@ +/*************************************************************************** + * Copyright (C) 2017 by Texas Instruments, Inc. * + * * + * 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 . * + ***************************************************************************/ + +#ifndef OPENOCD_FLASH_NOR_CC26XX_H +#define OPENOCD_FLASH_NOR_CC26XX_H + +/* Addresses of FCFG1 registers to access ICEPick Device ID and User ID */ +#define FCFG1_ICEPICK_ID 0x50001318 +#define FCFG1_USER_ID 0x50001294 + +/* ICEPick device ID mask and values */ +#define ICEPICK_ID_MASK 0x0fffffff +#define ICEPICK_REV_MASK 0xf0000000 +#define CC26X0_ICEPICK_ID 0x0b99a02f +#define CC26X1_ICEPICK_ID 0x0b9bd02f +#define CC13X0_ICEPICK_ID 0x0b9be02f +#define CC13X2_CC26X2_ICEPICK_ID 0x0bb4102f + +/* User ID mask for Agama CC13x2 vs CC26x2 */ +#define USER_ID_CC13_MASK 0x00800000 + +/* Common CC26xx/CC13xx flash and memory parameters */ +#define CC26XX_FLASH_BASE_ADDR 0x00000000 +#define CC26XX_FLASH_SIZE_INFO 0x4003002c +#define CC26XX_SRAM_SIZE_INFO 0x40082250 +#define CC26XX_ALGO_BASE_ADDRESS 0x20000000 + +/* Chameleon CC26x0/CC13x0 specific parameters */ +#define CC26X0_MAX_SECTORS 32 +#define CC26X0_SECTOR_LENGTH 0x1000 +#define CC26X0_ALGO_BUFFER_0 0x20001c00 +#define CC26X0_ALGO_BUFFER_1 0x20002c00 +#define CC26X0_ALGO_PARAMS_0 0x20001bd8 +#define CC26X0_ALGO_PARAMS_1 0x20001bec +#define CC26X0_WORKING_SIZE (CC26X0_ALGO_BUFFER_1 + CC26X0_SECTOR_LENGTH - \ + CC26XX_ALGO_BASE_ADDRESS) + +/* Agama CC26x2/CC13x2 specific parameters */ +#define CC26X2_MAX_SECTORS 128 +#define CC26X2_SECTOR_LENGTH 0x2000 +#define CC26X2_ALGO_BUFFER_0 0x20002000 +#define CC26X2_ALGO_BUFFER_1 0x20004000 +#define CC26X2_ALGO_PARAMS_0 0x20001fd8 +#define CC26X2_ALGO_PARAMS_1 0x20001fec +#define CC26X2_WORKING_SIZE (CC26X2_ALGO_BUFFER_1 + CC26X2_SECTOR_LENGTH - \ + CC26XX_ALGO_BASE_ADDRESS) + +/* CC26xx flash helper algorithm buffer flags */ +#define CC26XX_BUFFER_EMPTY 0x00000000 +#define CC26XX_BUFFER_FULL 0xffffffff + +/* CC26XX flash helper algorithm commands */ +#define CC26XX_CMD_NO_ACTION 0 +#define CC26XX_CMD_ERASE_ALL 1 +#define CC26XX_CMD_PROGRAM 2 +#define CC26XX_CMD_ERASE_AND_PROGRAM 3 +#define CC26XX_CMD_ERASE_AND_PROGRAM_WITH_RETAIN 4 +#define CC26XX_CMD_ERASE_SECTORS 5 + +/* CC26xx and CC13xx device types */ +#define CC26XX_NO_TYPE 0 /* Device type not determined yet */ +#define CC26X0_TYPE 1 /* CC26x0 Chameleon device */ +#define CC26X1_TYPE 2 /* CC26x1 Chameleon device */ +#define CC26X2_TYPE 3 /* CC26x2 Agama device */ +#define CC13X0_TYPE 4 /* CC13x0 Chameleon device */ +#define CC13X2_TYPE 5 /* CC13x2 Agama device */ + +/* Flash helper algorithm parameter block struct */ +#define CC26XX_STATUS_OFFSET 0x0c +struct cc26xx_algo_params { + uint8_t address[4]; + uint8_t length[4]; + uint8_t command[4]; + uint8_t status[4]; +}; + +/* Flash helper algorithm for CC26x0 Chameleon targets */ +const uint8_t cc26x0_algo[] = { +#include "../../../contrib/loaders/flash/cc26xx/cc26x0_algo.inc" +}; + +/* Flash helper algorithm for CC26x2 Agama targets */ +const uint8_t cc26x2_algo[] = { +#include "../../../contrib/loaders/flash/cc26xx/cc26x2_algo.inc" +}; + +#endif /* OPENOCD_FLASH_NOR_CC26XX_H */ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 6e1703b41..4efbdf768 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -33,6 +33,7 @@ extern struct flash_driver atsamv_flash; extern struct flash_driver avr_flash; extern struct flash_driver bluenrgx_flash; extern struct flash_driver cc3220sf_flash; +extern struct flash_driver cc26xx_flash; extern struct flash_driver cfi_flash; extern struct flash_driver dsp5680xx_flash; extern struct flash_driver efm32_flash; @@ -95,6 +96,7 @@ static struct flash_driver *flash_drivers[] = { &avr_flash, &bluenrgx_flash, &cc3220sf_flash, + &cc26xx_flash, &cfi_flash, &dsp5680xx_flash, &efm32_flash, diff --git a/tcl/board/ti_cc13x0_launchpad.cfg b/tcl/board/ti_cc13x0_launchpad.cfg new file mode 100644 index 000000000..9e1c1ea37 --- /dev/null +++ b/tcl/board/ti_cc13x0_launchpad.cfg @@ -0,0 +1,7 @@ +# +# TI CC13x0 LaunchPad Evaluation Kit +# +source [find interface/xds110.cfg] +transport select jtag +adapter_khz 2500 +source [find target/ti_cc13x0.cfg] diff --git a/tcl/board/ti_cc13x2_launchpad.cfg b/tcl/board/ti_cc13x2_launchpad.cfg new file mode 100644 index 000000000..18c5ce51c --- /dev/null +++ b/tcl/board/ti_cc13x2_launchpad.cfg @@ -0,0 +1,7 @@ +# +# TI CC13x2 LaunchPad Evaluation Kit +# +source [find interface/xds110.cfg] +adapter_khz 2500 +transport select jtag +source [find target/ti_cc13x2.cfg] diff --git a/tcl/board/ti_cc26x0_launchpad.cfg b/tcl/board/ti_cc26x0_launchpad.cfg new file mode 100644 index 000000000..3613a47f7 --- /dev/null +++ b/tcl/board/ti_cc26x0_launchpad.cfg @@ -0,0 +1,7 @@ +# +# TI CC26x0 LaunchPad Evaluation Kit +# +source [find interface/xds110.cfg] +adapter_khz 2500 +transport select jtag +source [find target/ti_cc26x0.cfg] diff --git a/tcl/board/ti_cc26x2_launchpad.cfg b/tcl/board/ti_cc26x2_launchpad.cfg new file mode 100644 index 000000000..2f2b34b4b --- /dev/null +++ b/tcl/board/ti_cc26x2_launchpad.cfg @@ -0,0 +1,7 @@ +# +# TI CC26x2 LaunchPad Evaluation Kit +# +source [find interface/xds110.cfg] +adapter_khz 2500 +transport select jtag +source [find target/ti_cc26x2.cfg] diff --git a/tcl/target/ti_cc13x0.cfg b/tcl/target/ti_cc13x0.cfg new file mode 100644 index 000000000..6ea9bd807 --- /dev/null +++ b/tcl/target/ti_cc13x0.cfg @@ -0,0 +1,11 @@ +# +# Texas Instruments CC13x0 - ARM Cortex-M3 +# +# http://www.ti.com +# + +set CHIPNAME cc13x0 +set JRC_TAPID 0x0B9BE02F +set WORKAREASIZE 0x4000 + +source [find target/ti_cc26x0.cfg] diff --git a/tcl/target/ti_cc13x2.cfg b/tcl/target/ti_cc13x2.cfg new file mode 100644 index 000000000..280eef45f --- /dev/null +++ b/tcl/target/ti_cc13x2.cfg @@ -0,0 +1,11 @@ +# +# Texas Instruments CC13x2 - ARM Cortex-M4 +# +# http://www.ti.com +# + +set CHIPNAME cc13x2 +set JRC_TAPID 0x0BB4102F +set WORKAREASIZE 0x7000 + +source [find target/ti_cc26x0.cfg] diff --git a/tcl/target/cc26xx.cfg b/tcl/target/ti_cc26x0.cfg old mode 100755 new mode 100644 similarity index 57% rename from tcl/target/cc26xx.cfg rename to tcl/target/ti_cc26x0.cfg index c3ac8470a..7efecb666 --- a/tcl/target/cc26xx.cfg +++ b/tcl/target/ti_cc26x0.cfg @@ -1,23 +1,25 @@ -# Config for Texas Instruments low power SoC CC26xx family - -adapter_khz 100 +# +# Texas Instruments CC26x0 - ARM Cortex-M3 +# +# http://www.ti.com +# source [find target/icepick.cfg] source [find target/ti-cjtag.cfg] if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME + set _CHIPNAME $CHIPNAME } else { - set _CHIPNAME cc26xx + set _CHIPNAME cc26x0 } # # Main DAP # if { [info exists DAP_TAPID] } { - set _DAP_TAPID $DAP_TAPID + set _DAP_TAPID $DAP_TAPID } else { - set _DAP_TAPID 0x4BA00477 + set _DAP_TAPID 0x4BA00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" @@ -26,19 +28,29 @@ jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME. # ICEpick-C (JTAG route controller) # if { [info exists JRC_TAPID] } { - set _JRC_TAPID $JRC_TAPID + set _JRC_TAPID $JRC_TAPID } else { - set _JRC_TAPID 0x1B99A02F + set _JRC_TAPID 0x0B99A02F } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version -# A start sequence is needed to change from cJTAG (Compact JTAG) to -# 4-pin JTAG before talking via JTAG commands jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu" +# A start sequence is needed to change from 2-pin cJTAG to 4-pin JTAG jtag configure $_CHIPNAME.jrc -event post-reset "ti_cjtag_to_4pin_jtag $_CHIPNAME.jrc" -# -# Cortex-M3 target -# set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap + +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x4000 +} + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME cc26xx 0 0 0 0 $_TARGETNAME + +reset_config srst_only +adapter_nsrst_delay 100 diff --git a/tcl/target/ti_cc26x2.cfg b/tcl/target/ti_cc26x2.cfg new file mode 100644 index 000000000..ecee3fab5 --- /dev/null +++ b/tcl/target/ti_cc26x2.cfg @@ -0,0 +1,11 @@ +# +# Texas Instruments CC26x2 - ARM Cortex-M4 +# +# http://www.ti.com +# + +set CHIPNAME cc26x2 +set JRC_TAPID 0x0BB4102F +set WORKAREASIZE 0x7000 + +source [find target/ti_cc26x0.cfg] From f05bcdebbb6673ec5bff2bd1f3c44767568008d9 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 9 Feb 2018 17:24:05 +0100 Subject: [PATCH 002/147] flash/nor/nrf5: remove is_erased setting and autoerase before write Cached flash erase state in sectors[].is_erased is not reliable as running target can change the flash. Autoerase was issued before flash write on condition is_erased != 1 Remove autoerase completely as it is a quite non-standard feature. Change-Id: I19bef459e6afdc4c5fcaa2ccd194cf05be8a42b6 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4400 Tested-by: jenkins --- src/flash/nor/nrf5.c | 58 ++++---------------------------------------- 1 file changed, 5 insertions(+), 53 deletions(-) diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 31dd5aae5..a7ae6f3b7 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -531,7 +531,6 @@ static int nrf5_probe(struct flash_bank *bank) bank->sectors[0].size = bank->size; bank->sectors[0].offset = 0; - /* mark as unknown */ bank->sectors[0].is_erased = 0; bank->sectors[0].is_protected = 0; @@ -553,17 +552,6 @@ static int nrf5_auto_probe(struct flash_bank *bank) return nrf5_probe(bank); } -static struct flash_sector *nrf5_find_sector_by_address(struct flash_bank *bank, uint32_t address) -{ - struct nrf5_info *chip = bank->driver_priv; - - for (int i = 0; i < bank->num_sectors; i++) - if (bank->sectors[i].offset <= address && - address < (bank->sectors[i].offset + chip->code_page_size)) - return &bank->sectors[i]; - return NULL; -} - static int nrf5_erase_all(struct nrf5_info *chip) { LOG_DEBUG("Erasing all non-volatile memory"); @@ -615,9 +603,6 @@ static int nrf5_erase_page(struct flash_bank *bank, sector->offset); } - if (res == ERROR_OK) - sector->is_erased = 1; - return res; } @@ -743,48 +728,22 @@ static int nrf5_write_pages(struct flash_bank *bank, uint32_t start, uint32_t en { int res = ERROR_FAIL; struct nrf5_info *chip = bank->driver_priv; - struct flash_sector *sector; - uint32_t offset; assert(start % chip->code_page_size == 0); assert(end % chip->code_page_size == 0); - /* Erase all sectors */ - for (offset = start; offset < end; offset += chip->code_page_size) { - sector = nrf5_find_sector_by_address(bank, offset); - if (!sector) { - LOG_ERROR("Invalid sector @ 0x%08"PRIx32, offset); - return ERROR_FLASH_SECTOR_INVALID; - } - - if (sector->is_protected) { - LOG_ERROR("Can't erase protected sector @ 0x%08"PRIx32, offset); - goto error; - } - - if (sector->is_erased != 1) { /* 1 = erased, 0= not erased, -1 = unknown */ - res = nrf5_erase_page(bank, chip, sector); - if (res != ERROR_OK) { - LOG_ERROR("Failed to erase sector @ 0x%08"PRIx32, sector->offset); - goto error; - } - } - sector->is_erased = 0; - } - res = nrf5_nvmc_write_enable(chip); if (res != ERROR_OK) goto error; res = nrf5_ll_flash_write(chip, start, buffer, (end - start)); if (res != ERROR_OK) - goto set_read_only; + goto error; return nrf5_nvmc_read_only(chip); -set_read_only: - nrf5_nvmc_read_only(chip); error: + nrf5_nvmc_read_only(chip); LOG_ERROR("Failed to write to nrf5 flash"); return res; } @@ -876,11 +835,9 @@ static int nrf5_uicr_flash_write(struct flash_bank *bank, if (res != ERROR_OK) return res; - if (sector->is_erased != 1) { - res = nrf5_erase_page(bank, chip, sector); - if (res != ERROR_OK) - return res; - } + res = nrf5_erase_page(bank, chip, sector); + if (res != ERROR_OK) + return res; res = nrf5_nvmc_write_enable(chip); if (res != ERROR_OK) @@ -992,9 +949,6 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) return res; } - for (int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - res = nrf5_protect_check(bank); if (res != ERROR_OK) { LOG_ERROR("Failed to check chip's write protection"); @@ -1005,8 +959,6 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) if (res != ERROR_OK) return res; - bank->sectors[0].is_erased = 1; - return ERROR_OK; } From 62b088df4eeb30997278a45f3ee5abc5d9ea2aff Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 9 Feb 2018 17:51:27 +0100 Subject: [PATCH 003/147] src/flash/tms470: remove testing of sectors[].is_erased state The erase check routine checked sectors only if is_erased != 1 Check sector unconditionally. While on it fix clang static analyzer warnings. Change-Id: I9988615fd8530c55a9b0c54b1900f89b550345e9 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4401 Tested-by: jenkins --- src/flash/nor/tms470.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c index 102bf1b15..2435e7990 100644 --- a/src/flash/nor/tms470.c +++ b/src/flash/nor/tms470.c @@ -151,6 +151,7 @@ static int tms470_read_part_info(struct flash_bank *bank) if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; + bank->num_sectors = 0; } /* @@ -754,9 +755,6 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector) target_write_u32(target, 0xFFFFFFDC, glbctrl); LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl); - if (result == ERROR_OK) - bank->sectors[sector].is_erased = 1; - return result; } @@ -1044,27 +1042,17 @@ static int tms470_erase_check(struct flash_bank *bank) * an attempt to reduce the JTAG overhead. */ for (sector = 0; sector < bank->num_sectors; sector++) { - if (bank->sectors[sector].is_erased != 1) { - uint32_t i, addr = bank->base + bank->sectors[sector].offset; + uint32_t i, addr = bank->base + bank->sectors[sector].offset; - LOG_INFO("checking flash bank %d sector %d", tms470_info->ordinal, sector); + LOG_INFO("checking flash bank %d sector %d", tms470_info->ordinal, sector); - target_read_buffer(target, addr, bank->sectors[sector].size, buffer); + target_read_buffer(target, addr, bank->sectors[sector].size, buffer); - bank->sectors[sector].is_erased = 1; - for (i = 0; i < bank->sectors[sector].size; i++) { - if (buffer[i] != 0xff) { - LOG_WARNING("tms470 bank %d, sector %d, not erased.", - tms470_info->ordinal, - sector); - LOG_WARNING( - "at location 0x%08" PRIx32 ": flash data is 0x%02x.", - addr + i, - buffer[i]); - - bank->sectors[sector].is_erased = 0; - break; - } + bank->sectors[sector].is_erased = 1; + for (i = 0; i < bank->sectors[sector].size; i++) { + if (buffer[i] != 0xff) { + bank->sectors[sector].is_erased = 0; + break; } } if (bank->sectors[sector].is_erased != 1) { From 20d18d415da304c65ce4dd0da7d555f5160ff92b Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Mon, 12 Mar 2018 23:42:23 +0100 Subject: [PATCH 004/147] tcl/target/stm32f7x: configure faster system clock in reset-init STM32F7xx devices need faster clock for flash programming over JTAG transport. Using reset default 16 MHz clock resulted in lot of DAP WAITs and substantial decrease of flashing performance. Adapted to the restructured dap support (see 2231da8ec4e7d7ae9b652f3dd1a7104f5a110f3f). Change-Id: Ida6915331dd924c9c0d08822fd94c04ad408cdc5 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4464 Tested-by: jenkins Reviewed-by: Christopher Head --- tcl/target/stm32f7x.cfg | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tcl/target/stm32f7x.cfg b/tcl/target/stm32f7x.cfg index dc310da44..98f3eea37 100755 --- a/tcl/target/stm32f7x.cfg +++ b/tcl/target/stm32f7x.cfg @@ -82,3 +82,27 @@ $_TARGETNAME configure -event trace-config { # assignment mmw 0xE0042004 0x00000020 0 } + +$_TARGETNAME configure -event reset-init { + # Configure PLL to boost clock to HSI x 10 (160 MHz) + mww 0x40023804 0x08002808 ;# RCC_PLLCFGR 16 Mhz /10 (M) * 128 (N) /2(P) + mww 0x40023C00 0x00000107 ;# FLASH_ACR = PRFTBE | 7(Latency) + mmw 0x40023800 0x01000000 0 ;# RCC_CR |= PLLON + sleep 10 ;# Wait for PLL to lock + mww 0x40023808 0x00009400 ;# RCC_CFGR_PPRE1 = 5(div 4), PPRE2 = 4(div 2) + mmw 0x40023808 0x00000002 0 ;# RCC_CFGR |= RCC_CFGR_SW_PLL + + # Boost SWD frequency + # Do not boost JTAG frequency and slow down JTAG memory access or flash write algo + # suffers from DAP WAITs + if {[using_jtag]} { + [[target current] cget -dap] memaccess 16 + } { + adapter_khz 8000 + } +} + +$_TARGETNAME configure -event reset-start { + # Reduce speed since CPU speed will slow down to 16MHz with the reset + adapter_khz 2000 +} From 548bcee30dcfec3174e563e53ffb1559104b8a97 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 11 Jun 2018 10:29:52 +0200 Subject: [PATCH 005/147] flash/nor/psoc5lp: fix compile issue on GCC 8.1.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue already identified by Alex https://sourceforge.net/u/alexbour/ in ticket #191 https://sourceforge.net/p/openocd/tickets/191/ src/flash/nor/psoc5lp.c:237:2: error: ‘strncpy’ output truncated before terminating nul copying 2 bytes from a string of the same length [-Werror=stringop-truncation] Fix it by assigning the value to the array elements. Change-Id: I22468e5700efa64ea48ae8cdec930c48b4a7d8fb Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4563 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/psoc5lp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/psoc5lp.c b/src/flash/nor/psoc5lp.c index ae8e3d3bc..0b21ed649 100644 --- a/src/flash/nor/psoc5lp.c +++ b/src/flash/nor/psoc5lp.c @@ -234,7 +234,8 @@ static void psoc5lp_get_part_number(const struct psoc5lp_device *dev, char *str) } /* Package does not matter. */ - strncpy(str + 8, "xx", 2); + str[8] = 'x'; + str[9] = 'x'; /* Temperate range cannot uniquely be identified. */ str[10] = 'x'; From a0356398e54984d292f4e6812cd67a9874b62f0d Mon Sep 17 00:00:00 2001 From: James Marshall Date: Tue, 16 Jan 2018 21:08:16 -0500 Subject: [PATCH 006/147] target/arm: Add PLD command to ARM disassembler. Updates the ARM disassembler to handle PLD (PreLoad Data) commands. Previously handled by printing a TODO message. There are three forms of the command: literal, register, and immediate. Simply decode based off of the A1 encoding for the instructions in the ARM ARM. Also fixes mask to handle PLDW commands. Change-Id: I63bf97f16af254e838462c7cfac80f6c4681c556 Signed-off-by: James Marshall Reviewed-on: http://openocd.zylin.com/4348 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- src/target/arm_disassembler.c | 75 ++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index 17948d6da..8eb819446 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -118,15 +118,78 @@ static int evaluate_pld(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { /* PLD */ - if ((opcode & 0x0d70f000) == 0x0550f000) { + if ((opcode & 0x0d30f000) == 0x0510f000) { + uint8_t Rn; + uint8_t U; + unsigned offset; + instruction->type = ARM_PLD; + Rn = (opcode & 0xf0000) >> 16; + U = (opcode & 0x00800000) >> 23; + if (Rn == 0xf) { + /* literal */ + offset = opcode & 0x0fff; + snprintf(instruction->text, 128, + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD %s%d", + address, opcode, U ? "" : "-", offset); + } else { + uint8_t I, R; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD ...TODO...", - address, - opcode); + I = (opcode & 0x02000000) >> 25; + R = (opcode & 0x00400000) >> 22; + if (I) { + /* register PLD{W} [,+/-{, }] */ + offset = (opcode & 0x0F80) >> 7; + uint8_t Rm; + Rm = opcode & 0xf; + + if (offset == 0) { + /* No shift */ + snprintf(instruction->text, 128, + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d]", + address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm); + + } else { + uint8_t shift; + shift = (opcode & 0x60) >> 5; + + if (shift == 0x0) { + /* LSL */ + snprintf(instruction->text, 128, + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, LSL #0x%x)", + address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset); + } else if (shift == 0x1) { + /* LSR */ + snprintf(instruction->text, 128, + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, LSR #0x%x)", + address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset); + } else if (shift == 0x2) { + /* ASR */ + snprintf(instruction->text, 128, + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, ASR #0x%x)", + address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset); + } else if (shift == 0x3) { + /* ROR */ + snprintf(instruction->text, 128, + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, ROR #0x%x)", + address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset); + } + } + } else { + /* immediate PLD{W} [, #+/-] */ + offset = opcode & 0x0fff; + if (offset == 0) { + snprintf(instruction->text, 128, + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d]", + address, opcode, R ? "" : "W", Rn); + } else { + snprintf(instruction->text, 128, + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, #%s%d]", + address, opcode, R ? "" : "W", Rn, U ? "" : "-", offset); + } + } + } return ERROR_OK; } /* DSB */ From 4301ad83dbbd1065ff039c7a495118db53280190 Mon Sep 17 00:00:00 2001 From: Liviu Ionescu Date: Wed, 20 Jun 2018 12:30:33 +0300 Subject: [PATCH 007/147] mips_m4k.c: Fix build with --disable-target64 Replace PRIx64 with TARGET_PRIxADDR to avoid build problems when --disable-target64 is used during configure. Change-Id: I054a27a491e86c42c9386a0488194320b808ba96 Signed-off-by: Liviu Ionescu Reviewed-on: http://openocd.zylin.com/4566 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Tim Newsome --- src/target/mips_m4k.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index 7d1c06cf0..78718ca16 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -702,7 +702,7 @@ static int mips_m4k_set_breakpoint(struct target *target, } if (verify == 0) { - LOG_ERROR("Unable to set 32bit breakpoint at address %08" PRIx64 + LOG_ERROR("Unable to set 32bit breakpoint at address %08" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } @@ -723,7 +723,7 @@ static int mips_m4k_set_breakpoint(struct target *target, return retval; if (verify != MIPS16_SDBBP(isa_req)) { - LOG_ERROR("Unable to set 16bit breakpoint at address %08" PRIx64 + LOG_ERROR("Unable to set 16bit breakpoint at address %08" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } From 0057c71ab6b81d0679b232318fc5f84b4becc471 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Fri, 15 Jun 2018 16:30:41 +0200 Subject: [PATCH 008/147] target/arm_adi_v5: sync CSW and TAR cache on apreg write When using apreg to change AP registers CSW or TAR we get internal cached value not valid anymore. Reuse the setup functions for CSW and TAR to write them. Invalidate the cached value before the call to force the write, thus keeping original apreg behaviour. Change-Id: Ib14fafd5e584345de94f2e983de55406c588ac1c Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4565 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/arm_adi_v5.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index d0a58bda0..6795b31af 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1722,6 +1722,7 @@ COMMAND_HANDLER(dap_apreg_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t apsel, reg, value; + struct adiv5_ap *ap; int retval; if (CMD_ARGC < 2 || CMD_ARGC > 3) @@ -1731,6 +1732,7 @@ COMMAND_HANDLER(dap_apreg_command) /* AP address is in bits 31:24 of DP_SELECT */ if (apsel >= 256) return ERROR_COMMAND_SYNTAX_ERROR; + ap = dap_ap(dap, apsel); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg); if (reg >= 256 || (reg & 3)) @@ -1738,9 +1740,21 @@ COMMAND_HANDLER(dap_apreg_command) if (CMD_ARGC == 3) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); - retval = dap_queue_ap_write(dap_ap(dap, apsel), reg, value); + switch (reg) { + case MEM_AP_REG_CSW: + ap->csw_default = 0; /* invalid, force write */ + retval = mem_ap_setup_csw(ap, value); + break; + case MEM_AP_REG_TAR: + ap->tar_valid = false; /* invalid, force write */ + retval = mem_ap_setup_tar(ap, value); + break; + default: + retval = dap_queue_ap_write(ap, reg, value); + break; + } } else { - retval = dap_queue_ap_read(dap_ap(dap, apsel), reg, &value); + retval = dap_queue_ap_read(ap, reg, &value); } if (retval == ERROR_OK) retval = dap_run(dap); From 1dc466f5156741f643c946485cdf280a1054fc7a Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Fri, 15 Jun 2018 16:37:18 +0200 Subject: [PATCH 009/147] target/arm_adi_v5: keep CSW and TAR cache updated The call to dap_queue_ap_write() can fail and the value in CSW and TAR becomes unknown. Invalidate the OpenOCD cache if dap_queue_ap_write() fails. Change-Id: Id6ec370b4c5ad07e454464780c1a1c8ae34ac870 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4564 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/arm_adi_v5.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 6795b31af..4dc2594cf 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -102,8 +102,10 @@ static int mem_ap_setup_csw(struct adiv5_ap *ap, uint32_t csw) if (csw != ap->csw_value) { /* LOG_DEBUG("DAP: Set CSW %x",csw); */ int retval = dap_queue_ap_write(ap, MEM_AP_REG_CSW, csw); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + ap->csw_value = 0; return retval; + } ap->csw_value = csw; } return ERROR_OK; @@ -114,8 +116,10 @@ static int mem_ap_setup_tar(struct adiv5_ap *ap, uint32_t tar) if (!ap->tar_valid || tar != ap->tar_value) { /* LOG_DEBUG("DAP: Set TAR %x",tar); */ int retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR, tar); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + ap->tar_valid = false; return retval; + } ap->tar_value = tar; ap->tar_valid = true; } From 21f52f648058ea71abde2c6ab595223abbaa46e4 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 21 Apr 2018 15:59:17 +0200 Subject: [PATCH 010/147] tcl/target: Add Renesas R-Car R8A7794 E2 target Add configuration for the Renesas R-Car R8A7794 E2 target. This is an SoC with two Cortex A7 ARMv7a cores, both A7 cores are supported. Change-Id: Ic1c81840e3bfcef8ee1de5acedffae5c83612a5e Signed-off-by: Marek Vasut Reviewed-on: http://openocd.zylin.com/4531 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/target/renesas_r8a7794.cfg | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tcl/target/renesas_r8a7794.cfg diff --git a/tcl/target/renesas_r8a7794.cfg b/tcl/target/renesas_r8a7794.cfg new file mode 100644 index 000000000..e3e27246c --- /dev/null +++ b/tcl/target/renesas_r8a7794.cfg @@ -0,0 +1,27 @@ +# Renesas R-Car E2 +# https://www.renesas.com/en-us/solutions/automotive/products/rcar-e2.html + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME r8a7794 +} + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID + +# Configuring only one core using DAP. +# Base addresses of cores: +# core 0 - 0x800F0000 +# core 1 - 0x800F2000 +set _TARGETNAME $_CHIPNAME.ca7. +dap create ${_CHIPNAME}.dap -chain-position $_CHIPNAME.cpu +target create ${_TARGETNAME}0 cortex_a -dap ${_CHIPNAME}.dap -coreid 0 -dbgbase 0x800F0000 +target create ${_TARGETNAME}1 cortex_a -dap ${_CHIPNAME}.dap -coreid 1 -dbgbase 0x800F2000 -defer-examine + +targets ${_TARGETNAME}0 From c8864333327cba8121ac83895eb8d7b455f489fa Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 16 Apr 2018 21:22:04 +0200 Subject: [PATCH 011/147] tcl/board: Add Renesas R-Car R8A7790 H2 Stout board Add configuration for the Renesas R-Car R8A7790 H2 based Stout ADAS board. Change-Id: Ib880b5d2e1fab5c8c0bc0dbcedcdce8055463fe2 Signed-off-by: Marek Vasut Reviewed-on: http://openocd.zylin.com/4497 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/renesas_stout.cfg | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tcl/board/renesas_stout.cfg diff --git a/tcl/board/renesas_stout.cfg b/tcl/board/renesas_stout.cfg new file mode 100644 index 000000000..fb0892425 --- /dev/null +++ b/tcl/board/renesas_stout.cfg @@ -0,0 +1,16 @@ +# Renesas R-Car H2 Evaluation Board + +source [find target/renesas_r8a7790.cfg] + +reset_config trst_and_srst srst_nogate + +proc init_reset {mode} { + # Assert both resets: equivalent to a power-on reset + jtag_reset 1 1 + + # Deassert TRST to begin TAP communication + jtag_reset 0 1 + + # TAP should now be responsive, validate the scan-chain + jtag arp_init +} From 27adc412924eb441bcd45b216ea6fbc257f99758 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 16 Apr 2018 21:20:27 +0200 Subject: [PATCH 012/147] tcl/board: Add Renesas R-Car R8A7791 M2W Porter board Add configuration for the Renesas R-Car R8A7791 M2W based Porter evaluation board. Change-Id: Iaadb18f29748f890ebb68519ea9ddbd18e7649af Signed-off-by: Marek Vasut Reviewed-on: http://openocd.zylin.com/4498 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/renesas_porter.cfg | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tcl/board/renesas_porter.cfg diff --git a/tcl/board/renesas_porter.cfg b/tcl/board/renesas_porter.cfg new file mode 100644 index 000000000..da2bba1f4 --- /dev/null +++ b/tcl/board/renesas_porter.cfg @@ -0,0 +1,16 @@ +# Renesas R-Car M2 Evaluation Board + +source [find target/renesas_r8a7791.cfg] + +reset_config trst_and_srst srst_nogate + +proc init_reset {mode} { + # Assert both resets: equivalent to a power-on reset + jtag_reset 1 1 + + # Deassert TRST to begin TAP communication + jtag_reset 0 1 + + # TAP should now be responsive, validate the scan-chain + jtag arp_init +} From c49ea5dab29a48d4b3e54255892799382b7b1d57 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 21 Apr 2018 15:59:23 +0200 Subject: [PATCH 013/147] tcl/board: Add Renesas R-Car R8A7794 E2 Silk board Add configuration for the Renesas R-Car R8A7794 E2 based Silk evaluation board. Change-Id: I504b5630b1a2791ed6967c6c2af8851ceef9723f Signed-off-by: Marek Vasut --- NOTE: This requires SW7[1] in position 1 (default is 0) Reviewed-on: http://openocd.zylin.com/4532 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/renesas_silk.cfg | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tcl/board/renesas_silk.cfg diff --git a/tcl/board/renesas_silk.cfg b/tcl/board/renesas_silk.cfg new file mode 100644 index 000000000..442c2a6ab --- /dev/null +++ b/tcl/board/renesas_silk.cfg @@ -0,0 +1,16 @@ +# Renesas R-Car E2 Evaluation Board + +source [find target/renesas_r8a7794.cfg] + +reset_config trst_and_srst srst_nogate + +proc init_reset {mode} { + # Assert both resets: equivalent to a power-on reset + jtag_reset 1 1 + + # Deassert TRST to begin TAP communication + jtag_reset 0 1 + + # TAP should now be responsive, validate the scan-chain + jtag arp_init +} From 8b8b66559d5fbfeb1dd408a1af17dc0be52b5a9f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 23 May 2018 15:10:12 +0200 Subject: [PATCH 014/147] tcl/board: Factor out common R-Car Gen2 code Factor out the code shared by all R-Car Gen2 boards into a single file to get rid of the duplication. Change-Id: I70b302c2e71f4e6fdccb2817dd65a5493bb393d8 Signed-off-by: Marek Vasut Reviewed-on: http://openocd.zylin.com/4533 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/renesas_gen2_common.cfg | 14 ++++++++++++++ tcl/board/renesas_porter.cfg | 14 +------------- tcl/board/renesas_silk.cfg | 14 +------------- tcl/board/renesas_stout.cfg | 14 +------------- 4 files changed, 17 insertions(+), 39 deletions(-) create mode 100644 tcl/board/renesas_gen2_common.cfg diff --git a/tcl/board/renesas_gen2_common.cfg b/tcl/board/renesas_gen2_common.cfg new file mode 100644 index 000000000..00fa777c5 --- /dev/null +++ b/tcl/board/renesas_gen2_common.cfg @@ -0,0 +1,14 @@ +# Renesas R-Car Gen2 Evaluation Board common settings + +reset_config trst_and_srst srst_nogate + +proc init_reset {mode} { + # Assert both resets: equivalent to a power-on reset + jtag_reset 1 1 + + # Deassert TRST to begin TAP communication + jtag_reset 0 1 + + # TAP should now be responsive, validate the scan-chain + jtag arp_init +} diff --git a/tcl/board/renesas_porter.cfg b/tcl/board/renesas_porter.cfg index da2bba1f4..c8032f512 100644 --- a/tcl/board/renesas_porter.cfg +++ b/tcl/board/renesas_porter.cfg @@ -1,16 +1,4 @@ # Renesas R-Car M2 Evaluation Board source [find target/renesas_r8a7791.cfg] - -reset_config trst_and_srst srst_nogate - -proc init_reset {mode} { - # Assert both resets: equivalent to a power-on reset - jtag_reset 1 1 - - # Deassert TRST to begin TAP communication - jtag_reset 0 1 - - # TAP should now be responsive, validate the scan-chain - jtag arp_init -} +source [find board/renesas_gen2_common.cfg] diff --git a/tcl/board/renesas_silk.cfg b/tcl/board/renesas_silk.cfg index 442c2a6ab..a026537d4 100644 --- a/tcl/board/renesas_silk.cfg +++ b/tcl/board/renesas_silk.cfg @@ -1,16 +1,4 @@ # Renesas R-Car E2 Evaluation Board source [find target/renesas_r8a7794.cfg] - -reset_config trst_and_srst srst_nogate - -proc init_reset {mode} { - # Assert both resets: equivalent to a power-on reset - jtag_reset 1 1 - - # Deassert TRST to begin TAP communication - jtag_reset 0 1 - - # TAP should now be responsive, validate the scan-chain - jtag arp_init -} +source [find board/renesas_gen2_common.cfg] diff --git a/tcl/board/renesas_stout.cfg b/tcl/board/renesas_stout.cfg index fb0892425..d35f8744f 100644 --- a/tcl/board/renesas_stout.cfg +++ b/tcl/board/renesas_stout.cfg @@ -1,16 +1,4 @@ # Renesas R-Car H2 Evaluation Board source [find target/renesas_r8a7790.cfg] - -reset_config trst_and_srst srst_nogate - -proc init_reset {mode} { - # Assert both resets: equivalent to a power-on reset - jtag_reset 1 1 - - # Deassert TRST to begin TAP communication - jtag_reset 0 1 - - # TAP should now be responsive, validate the scan-chain - jtag arp_init -} +source [find board/renesas_gen2_common.cfg] From 91c125a906221481d7b9ee2c7e4588fbe6ade85c Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 23 Jun 2018 15:12:46 +0200 Subject: [PATCH 015/147] jtag/drivers/cmsis-dap: fix connect in cmsis_dap_swd_switch_seq() The proc cmsis_dap_swd_switch_seq() is part of the SWD API for this interface driver. It is valid only when the interface is used in SWD mode. In this proc there is the need to call, in sequence, first cmsis_dap_cmd_DAP_Disconnect() then cmsis_dap_cmd_DAP_Connect(). The latter call requires the connection mode as parameter, that inside cmsis_dap_swd_switch_seq() can only be CONNECT_SWD. The current implementation is not correct and in some cases can pass mode CONNECT_JTAG. Moreover, JTAG is optional in CMSIS-DAP and passing mode CONNECT_JTAG triggers an error with SWD-only interfaces. Use mode CONNECT_SWD in SWD specific cmsis_dap_swd_switch_seq(). Change-Id: Ib455bf5b69cb2a2d146a6c8875387b00c27a5690 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4571 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/jtag/drivers/cmsis_dap_usb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index b8181d6ae..6b010c1d6 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -802,8 +802,7 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq) /* When we are reconnecting, DAP_Connect needs to be rerun, at * least on Keil ULINK-ME */ - retval = cmsis_dap_cmd_DAP_Connect(seq == LINE_RESET || seq == JTAG_TO_SWD ? - CONNECT_SWD : CONNECT_JTAG); + retval = cmsis_dap_cmd_DAP_Connect(CONNECT_SWD); if (retval != ERROR_OK) return retval; } From 541dcc2487d11fbf0f14707217c616847a7b635d Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 29 May 2018 23:40:36 +0200 Subject: [PATCH 016/147] target/cortex_m: return error if breakpoint address is out of range If the "Flash Patch and Breakpoint" unit is rev.1 then it can only accept breakpoint addresses below 0x1FFFFFFF. Detailed info in "ARM v7-M Architecture Reference Manual", DDI0403E at chapter "C1.11 Flash Patch and Breakpoint unit". Print a message and return error if the address of hardware breakpoint cannot be handled by the breakpoint unit. Change-Id: I95c92b1f058f0dfc568bf03015f99e439b27c59b Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4535 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Christopher Head --- src/target/cortex_m.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index b6043fccf..d1afbd569 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1137,6 +1137,10 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint breakpoint->set = fp_num + 1; fpcr_value = breakpoint->address | 1; if (cortex_m->fp_rev == 0) { + if (breakpoint->address > 0x1FFFFFFF) { + LOG_ERROR("Cortex-M Flash Patch Breakpoint rev.1 cannot handle HW breakpoint above address 0x1FFFFFFE"); + return ERROR_FAIL; + } uint32_t hilo; hilo = (breakpoint->address & 0x2) ? FPCR_REPLACE_BKPT_HIGH : FPCR_REPLACE_BKPT_LOW; fpcr_value = (fpcr_value & 0x1FFFFFFC) | hilo | 1; From 47d0930410bc6f9fdf1d59a60a60fcca4c7bb1d4 Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Mon, 14 May 2018 11:56:56 -0700 Subject: [PATCH 017/147] flash/nor/stm32: Report errors in wait_status_busy Flash operation errors that occur during algorithm programming are reported via the algorithm return value. However, Flash operation errors that occur during non-algorithm work (erasing, programming without a work area, programming the last non-multiple-of-32-bytes on an H7, etc.) generally end with a call to stm32x_wait_status_busy, which reads the status register and clears the error flags but fails to actually report that something went wrong should an error flag (other than WRPERR) be set. Return an error status from stm32x_wait_status_busy in those cases. Correct a log message accordingly. Change-Id: I09369ea5f924fe58833aec1f45e52320ab4aaf43 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4519 Tested-by: jenkins Reviewed-by: Spencer Oliver Reviewed-by: Tomas Vanek --- src/flash/nor/stm32f2x.c | 2 ++ src/flash/nor/stm32h7x.c | 4 +++- src/flash/nor/stm32l4x.c | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 8013e5869..43f5d12d9 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -252,6 +252,8 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) /* Clear but report errors */ if (status & FLASH_ERROR) { + if (retval == ERROR_OK) + retval = ERROR_FAIL; /* If this operation fails, we ignore it and report the original * retval */ diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index 009eb9b86..8f34e0475 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -220,6 +220,8 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) /* Clear error + EOP flags but report errors */ if (status & FLASH_ERROR) { + if (retval == ERROR_OK) + retval = ERROR_FAIL; /* If this operation fails, we ignore it and report the original retval */ target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), status); } @@ -495,7 +497,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) { - LOG_ERROR("erase time-out error sector %d", i); + LOG_ERROR("erase time-out or operation error sector %d", i); return retval; } bank->sectors[i].is_erased = 1; diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index e47313c19..f71369330 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -187,6 +187,8 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) /* Clear but report errors */ if (status & FLASH_ERROR) { + if (retval == ERROR_OK) + retval = ERROR_FAIL; /* If this operation fails, we ignore it and report the original * retval */ From f9d7554ee490e39a5cba3cd4eb2c28ec72ba407f Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Mon, 14 May 2018 13:06:39 -0700 Subject: [PATCH 018/147] flash/nor/stm32: Eliminate working area leak On a specific early-return path, an allocated working area was not freed. Free it. Change-Id: I7c8fe51ff475f191624086996be1c77251780b77 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4520 Tested-by: jenkins Reviewed-by: Spencer Oliver Reviewed-by: Tomas Vanek --- src/flash/nor/stm32f1x.c | 4 +++- src/flash/nor/stm32f2x.c | 4 +++- src/flash/nor/stm32h7x.c | 4 +++- src/flash/nor/stm32l4x.c | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 015988a5d..faada9a61 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -585,8 +585,10 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); return retval; + } /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 43f5d12d9..413d04d77 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -599,8 +599,10 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); return retval; + } /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index 8f34e0475..f2ddaf447 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -583,8 +583,10 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); return retval; + } /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index f71369330..4fb7e039a 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -476,8 +476,10 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32l4_flash_write_code), stm32l4_flash_write_code); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); return retval; + } /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != From 4999c9d98013eeb9746082f6b018e4b763ae3d37 Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Mon, 14 May 2018 13:08:24 -0700 Subject: [PATCH 019/147] flash/nor/stm32h7: Fix incorrect comment The name of the bit according to the reference manual is inconsistency error, not increment error. Change-Id: Ie3b73c0312db586e35519e03fd1a5cb225673d97 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4521 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/flash/nor/stm32h7x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index f2ddaf447..fcfcf9142 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -64,7 +64,7 @@ #define FLASH_WRPERR (1 << 17) /* Write protection error */ #define FLASH_PGSERR (1 << 18) /* Programming sequence error */ #define FLASH_STRBERR (1 << 19) /* Strobe error */ -#define FLASH_INCERR (1 << 21) /* Increment error */ +#define FLASH_INCERR (1 << 21) /* Inconsistency error */ #define FLASH_OPERR (1 << 22) /* Operation error */ #define FLASH_RDPERR (1 << 23) /* Read Protection error */ #define FLASH_RDSERR (1 << 24) /* Secure Protection error */ From d04254196e383965627d4eab805f9b1b93240e69 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 22 Jan 2015 23:12:46 +0800 Subject: [PATCH 020/147] target: fix 'bp' command help message "asid" and "length" are separate arguments of the command. Put space between them. Change-Id: I36cfc1e3a01caafef4fc3b26972a0cc192b0b963 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4511 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Tomas Vanek --- src/target/target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/target.c b/src/target/target.c index 7ab13b020..1ca6c8e53 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -6415,7 +6415,7 @@ static const struct command_registration target_exec_command_handlers[] = { .handler = handle_bp_command, .mode = COMMAND_EXEC, .help = "list or set hardware or software breakpoint", - .usage = "
[] ['hw'|'hw_ctx']", + .usage = "
[] ['hw'|'hw_ctx']", }, { .name = "rbp", From a7da117ad6bc1749863c14fdeef2bd4898620574 Mon Sep 17 00:00:00 2001 From: Omair Javaid Date: Wed, 23 May 2018 17:43:47 +0500 Subject: [PATCH 021/147] Add ARM v8 AArch64 semihosting support This patch implements semihosting support for AArch64. This picks code from previously submitted AArch64 semihosting support patch and rebases on top of reworked semihosting code. Tested in AArch64 mode on a Lemaker Hikey Board with NewLib and GDB. Change-Id: I228a38f1de24f79e49ba99d8514d822a28c2950b Signed-off-by: Omair Javaid Reviewed-on: http://openocd.zylin.com/4537 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/aarch64.c | 13 +++++ src/target/arm_semihosting.c | 84 ++++++++++++++++++++++++++------- src/target/armv8.c | 13 +++++ src/target/armv8.h | 14 ++++++ src/target/semihosting_common.c | 10 ++-- 5 files changed, 112 insertions(+), 22 deletions(-) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index df1e49c21..14542a658 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -28,6 +28,7 @@ #include "target_type.h" #include "armv8_opcodes.h" #include "armv8_cache.h" +#include "arm_semihosting.h" #include enum restart_mode { @@ -522,6 +523,9 @@ static int aarch64_poll(struct target *target) if (target->smp) update_halt_gdb(target, debug_reason); + if (arm_semihosting(target, &retval) != 0) + return retval; + switch (prev_target_state) { case TARGET_RUNNING: case TARGET_UNKNOWN: @@ -543,6 +547,9 @@ static int aarch64_poll(struct target *target) static int aarch64_halt(struct target *target) { + struct armv8_common *armv8 = target_to_armv8(target); + armv8->last_run_control_op = ARMV8_RUNCONTROL_HALT; + if (target->smp) return aarch64_halt_smp(target, false); @@ -831,6 +838,9 @@ static int aarch64_resume(struct target *target, int current, int retval = 0; uint64_t addr = address; + struct armv8_common *armv8 = target_to_armv8(target); + armv8->last_run_control_op = ARMV8_RUNCONTROL_RESUME; + if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; @@ -1069,6 +1079,8 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres int retval; uint32_t edecr; + armv8->last_run_control_op = ARMV8_RUNCONTROL_STEP; + if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; @@ -2351,6 +2363,7 @@ static int aarch64_init_target(struct command_context *cmd_ctx, struct target *target) { /* examine_first() does a bunch of this */ + arm_semihosting_init(target); return ERROR_OK; } diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index 57f3139c2..31ca7792f 100644 --- a/src/target/arm_semihosting.c +++ b/src/target/arm_semihosting.c @@ -46,6 +46,7 @@ #include "arm7_9_common.h" #include "armv7m.h" #include "armv7a.h" +#include "armv8.h" #include "cortex_m.h" #include "register.h" #include "arm_opcodes.h" @@ -55,6 +56,28 @@ #include #include +static int arm_semihosting_resume(struct target *target, int *retval) +{ + if (is_armv8(target_to_armv8(target))) { + struct armv8_common *armv8 = target_to_armv8(target); + if (armv8->last_run_control_op == ARMV8_RUNCONTROL_RESUME) { + *retval = target_resume(target, 1, 0, 0, 0); + if (*retval != ERROR_OK) { + LOG_ERROR("Failed to resume target"); + return 0; + } + } else if (armv8->last_run_control_op == ARMV8_RUNCONTROL_STEP) + target->debug_reason = DBG_REASON_SINGLESTEP; + } else { + *retval = target_resume(target, 1, 0, 0, 0); + if (*retval != ERROR_OK) { + LOG_ERROR("Failed to resume target"); + return 0; + } + } + return 1; +} + static int post_result(struct target *target) { struct arm *arm = target_to_arm(target); @@ -88,6 +111,16 @@ static int post_result(struct target *target) if (spsr & 0x20) arm->core_state = ARM_STATE_THUMB; + } else if (is_armv8(target_to_armv8(target))) { + if (arm->core_state == ARM_STATE_AARCH64) { + /* return value in R0 */ + buf_set_u64(arm->core_cache->reg_list[0].value, 0, 64, target->semihosting->result); + arm->core_cache->reg_list[0].dirty = 1; + + uint64_t pc = buf_get_u64(arm->core_cache->reg_list[32].value, 0, 64); + buf_set_u64(arm->pc->value, 0, 64, pc + 4); + arm->pc->dirty = 1; + } } else { /* resume execution, this will be pc+2 to skip over the * bkpt instruction */ @@ -235,6 +268,24 @@ int arm_semihosting(struct target *target, int *retval) /* bkpt 0xAB */ if (insn != 0xBEAB) return 0; + } else if (is_armv8(target_to_armv8(target))) { + if (target->debug_reason != DBG_REASON_BREAKPOINT) + return 0; + + if (arm->core_state == ARM_STATE_AARCH64) { + uint32_t insn = 0; + r = arm->pc; + uint64_t pc64 = buf_get_u64(r->value, 0, 64); + *retval = target_read_u32(target, pc64, &insn); + + if (*retval != ERROR_OK) + return 1; + + /* bkpt 0xAB */ + if (insn != 0xD45E0000) + return 0; + } else + return 1; } else { LOG_ERROR("Unsupported semi-hosting Target"); return 0; @@ -244,13 +295,18 @@ int arm_semihosting(struct target *target, int *retval) * operation to complete. */ if (!semihosting->hit_fileio) { - /* TODO: update for 64-bits */ - uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32); - uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32); - - semihosting->op = r0; - semihosting->param = r1; - semihosting->word_size_bytes = 4; + if (is_armv8(target_to_armv8(target)) && + arm->core_state == ARM_STATE_AARCH64) { + /* Read op and param from register x0 and x1 respectively. */ + semihosting->op = buf_get_u64(arm->core_cache->reg_list[0].value, 0, 64); + semihosting->param = buf_get_u64(arm->core_cache->reg_list[1].value, 0, 64); + semihosting->word_size_bytes = 8; + } else { + /* Read op and param from register r0 and r1 respectively. */ + semihosting->op = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32); + semihosting->param = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32); + semihosting->word_size_bytes = 4; + } /* Check for ARM operation numbers. */ if (0 <= semihosting->op && semihosting->op <= 0x31) { @@ -265,19 +321,11 @@ int arm_semihosting(struct target *target, int *retval) } } - /* Post result to target if we are not waiting on a fileio + /* Resume if target it is resumable and we are not waiting on a fileio * operation to complete: */ - if (semihosting->is_resumable && !semihosting->hit_fileio) { - /* Resume right after the BRK instruction. */ - *retval = target_resume(target, 1, 0, 0, 0); - if (*retval != ERROR_OK) { - LOG_ERROR("Failed to resume target"); - return 0; - } - - return 1; - } + if (semihosting->is_resumable && !semihosting->hit_fileio) + return arm_semihosting_resume(target, retval); return 0; } diff --git a/src/target/armv8.c b/src/target/armv8.c index 20f2b671c..83f55300b 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -1017,11 +1017,24 @@ int armv8_handle_cache_info_command(struct command_context *cmd_ctx, return ERROR_OK; } +static int armv8_setup_semihosting(struct target *target, int enable) +{ + struct arm *arm = target_to_arm(target); + + if (arm->core_state != ARM_STATE_AARCH64) { + LOG_ERROR("semihosting only supported in AArch64 state\n"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + int armv8_init_arch_info(struct target *target, struct armv8_common *armv8) { struct arm *arm = &armv8->arm; arm->arch_info = armv8; target->arch_info = &armv8->arm; + arm->setup_semihosting = armv8_setup_semihosting; /* target is useful in all function arm v4 5 compatible */ armv8->arm.target = target; armv8->arm.common_magic = ARM_COMMON_MAGIC; diff --git a/src/target/armv8.h b/src/target/armv8.h index b34646224..dfd54edcb 100644 --- a/src/target/armv8.h +++ b/src/target/armv8.h @@ -113,6 +113,12 @@ enum { ARMV8_LAST_REG, }; +enum run_control_op { + ARMV8_RUNCONTROL_UNKNOWN = 0, + ARMV8_RUNCONTROL_RESUME = 1, + ARMV8_RUNCONTROL_HALT = 2, + ARMV8_RUNCONTROL_STEP = 3, +}; #define ARMV8_COMMON_MAGIC 0x0A450AAA @@ -210,6 +216,9 @@ struct armv8_common { struct arm_cti *cti; + /* last run-control command issued to this target (resume, halt, step) */ + enum run_control_op last_run_control_op; + /* Direct processor core register read and writes */ int (*read_reg_u64)(struct armv8_common *armv8, int num, uint64_t *value); int (*write_reg_u64)(struct armv8_common *armv8, int num, uint64_t value); @@ -232,6 +241,11 @@ target_to_armv8(struct target *target) return container_of(target->arch_info, struct armv8_common, arm); } +static inline bool is_armv8(struct armv8_common *armv8) +{ + return armv8->common_magic == ARMV8_COMMON_MAGIC; +} + /* register offsets from armv8.debug_base */ #define CPUV8_DBG_MAINID0 0xD00 #define CPUV8_DBG_CPUFEATURE0 0xD20 diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index beeb4742a..7ef1810e5 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -1397,8 +1397,9 @@ static int semihosting_read_fields(struct target *target, size_t number, uint8_t *fields) { struct semihosting *semihosting = target->semihosting; - return target_read_memory(target, semihosting->param, - semihosting->word_size_bytes, number, fields); + /* Use 4-byte multiples to trigger fast memory access. */ + return target_read_memory(target, semihosting->param, 4, + number * (semihosting->word_size_bytes / 4), fields); } /** @@ -1408,8 +1409,9 @@ static int semihosting_write_fields(struct target *target, size_t number, uint8_t *fields) { struct semihosting *semihosting = target->semihosting; - return target_write_memory(target, semihosting->param, - semihosting->word_size_bytes, number, fields); + /* Use 4-byte multiples to trigger fast memory access. */ + return target_write_memory(target, semihosting->param, 4, + number * (semihosting->word_size_bytes / 4), fields); } /** From 0aa8e8cfc3c28f4fcbba549db45be4e712f02c0a Mon Sep 17 00:00:00 2001 From: Omair Javaid Date: Thu, 31 May 2018 05:26:49 +0500 Subject: [PATCH 022/147] GDB fileIO stdout support This patch fixes gdb fileio support to allow gdb console to be used as stdout. Now we can do something like gdb (gdb) tar ext :3333 (gdb) load (gdb) monitor arm semihosting enable (gdb) monitor arm semihosting_fileio enable (gdb) continue Here: Output from inferior using puts, printf etc will be routed to gdb console. Change-Id: I9cb0dddda1de58038c84f5b035c38229828cd744 Signed-off-by: Omair Javaid Reviewed-on: http://openocd.zylin.com/4538 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/semihosting_common.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 7ef1810e5..59207897a 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -225,6 +225,10 @@ int semihosting_common(struct target *target) else { int fd = semihosting_get_field(target, 0, fields); if (semihosting->is_fileio) { + if (fd == 0 || fd == 1 || fd == 2) { + semihosting->result = 0; + break; + } semihosting->hit_fileio = true; fileio_info->identifier = "close"; fileio_info->param_1 = fd; @@ -445,8 +449,8 @@ int semihosting_common(struct target *target) * - –1 if an error occurs. */ if (semihosting->is_fileio) { - LOG_ERROR("SYS_FLEN not supported by semihosting fileio"); - return ERROR_FAIL; + semihosting->result = -1; + semihosting->sys_errno = EINVAL; } retval = semihosting_read_fields(target, 1, fields); if (retval != ERROR_OK) @@ -690,9 +694,19 @@ int semihosting_common(struct target *target) /* TODO: implement the :semihosting-features special file. * */ if (semihosting->is_fileio) { - if (strcmp((char *)fn, ":tt") == 0) - semihosting->result = 0; - else { + if (strcmp((char *)fn, ":semihosting-features") == 0) { + semihosting->result = -1; + semihosting->sys_errno = EINVAL; + } else if (strcmp((char *)fn, ":tt") == 0) { + if (mode == 0) + semihosting->result = 0; + else if (mode == 4) + semihosting->result = 1; + else if (mode == 8) + semihosting->result = 2; + else + semihosting->result = -1; + } else { semihosting->hit_fileio = true; fileio_info->identifier = "open"; fileio_info->param_1 = addr; From b82ee0799f6e30d3f03bd707c6e9729de92248d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 8 Jul 2018 19:52:06 +0200 Subject: [PATCH 023/147] target: armv8: Avoid semihosting segfault on halt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid a NULL pointer dereference when halting an aarch64 core. Change-Id: I333d40475ab26e2f0dca5c27302a5fa4d817a12f Signed-off-by: Andreas Färber Reviewed-on: http://openocd.zylin.com/4593 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/armv8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/armv8.c b/src/target/armv8.c index 83f55300b..dfa2c67a5 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -1063,7 +1063,7 @@ int armv8_aarch64_state(struct target *target) armv8_mode_name(arm->core_mode), buf_get_u32(arm->cpsr->value, 0, 32), buf_get_u64(arm->pc->value, 0, 64), - target->semihosting->is_active ? ", semihosting" : ""); + (target->semihosting && target->semihosting->is_active) ? ", semihosting" : ""); return ERROR_OK; } From e7a4aa353404b5dc3a2e599d6e4ce4afe8c5d6bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 9 Jul 2018 00:32:54 +0200 Subject: [PATCH 024/147] tcl: target: Add NXP LS1012A config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As seen on the FRDM-LS1012A board. Change-Id: Ifc9074b3f7535167b9ded5f544501ec2879f5db7 Signed-off-by: Andreas Färber Reviewed-on: http://openocd.zylin.com/4594 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/target/ls1012a.cfg | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tcl/target/ls1012a.cfg diff --git a/tcl/target/ls1012a.cfg b/tcl/target/ls1012a.cfg new file mode 100644 index 000000000..9a9e684d7 --- /dev/null +++ b/tcl/target/ls1012a.cfg @@ -0,0 +1,35 @@ +# +# NXP LS1012A +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME ls1012a +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +if { [info exists SAP_TAPID] } { + set _SAP_TAPID $SAP_TAPID +} else { + set _SAP_TAPID 0x06b2001d +} + +jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID +jtag newtap $_CHIPNAME sap -irlen 8 -expected-id $_SAP_TAPID + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap + +cti create $_CHIPNAME.cti -dap $_CHIPNAME.dap -ap-num 1 -ctibase 0x80420000 + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -dbgbase 0x80410000 -cti $_CHIPNAME.cti + +target smp $_TARGETNAME + +adapter_khz 2000 From ce28a0c8c8af3f18c5cfaf73029dd9d4d95f09a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 9 Jul 2018 00:37:51 +0200 Subject: [PATCH 025/147] tcl: board: Add NXP Freedom FRDM-LS1012A config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An update for the K20 CMSIS-DAP firmware can be found here: https://community.nxp.com/thread/387080?commentID=840141#comment-840141 Change-Id: I149d7f8610aa56daf1aeb95f14ee1bf88f7cb647 Signed-off-by: Andreas Färber Reviewed-on: http://openocd.zylin.com/4595 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/nxp_frdm-ls1012a.cfg | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tcl/board/nxp_frdm-ls1012a.cfg diff --git a/tcl/board/nxp_frdm-ls1012a.cfg b/tcl/board/nxp_frdm-ls1012a.cfg new file mode 100644 index 000000000..3973b3cdf --- /dev/null +++ b/tcl/board/nxp_frdm-ls1012a.cfg @@ -0,0 +1,15 @@ +# +# NXP FRDM-LS1012A (Freedom) +# + +# +# NXP Kinetis K20 +# +source [find interface/cmsis-dap.cfg] +transport select jtag + +# Also offers a 10-pin 0.05" CoreSight JTAG connector. + +source [find target/ls1012a.cfg] + +reset_config srst_only From 421e75722db1fa173747d07618ef4016b2e3c80e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 25 Jun 2018 15:09:31 +0200 Subject: [PATCH 026/147] gdb_server: only trigger once the event gdb-detach at gdb quit When GDB quits (e.g. with "quit" command) we first execute gdb_detach() to reply "OK" then, at GDB disconnect (either TCP or pipe connection type), we execute gdb_connection_closed(). In case GDB is killed or it crashes, OpenOCD only executes the latter when detects the disconnection. Both gdb_detach() and gdb_connection_closed() trigger the event TARGET_EVENT_GDB_DETACH thus getting it triggered twice on clean GDB quit. Do not trigger the event TARGET_EVENT_GDB_DETACH in gdb_detach() and let only gdb_connection_closed() to handle it. Change-Id: Iacf035c855b8b3e2239c1c0e259c279688b418ee Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4585 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/server/gdb_server.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index a9c2a6406..f0b552dde 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -3016,9 +3016,12 @@ static int gdb_v_packet(struct connection *connection, static int gdb_detach(struct connection *connection) { - target_call_event_callbacks(get_target_from_connection(connection), - TARGET_EVENT_GDB_DETACH); - + /* + * Only reply "OK" to GDB + * it will close the connection and this will trigger a call to + * gdb_connection_closed() that will in turn trigger the event + * TARGET_EVENT_GDB_DETACH + */ return gdb_put_packet(connection, "OK", 2); } From 73de82898840292b000ded9a48031701961c3c83 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 2 Jul 2018 18:47:34 +0200 Subject: [PATCH 027/147] gdb_server: set current_target from connection's one In a multi-target environment we are supposed to have a single gdb server for each target (or for each group of targets within a SMP node). By default, the gdb attached to a server sends its command to the target (or to the SMP node targets) linked to that server. This is working fine for the normal gdb commands, but it is broken for the native OpenOCD commands executed through gdb "monitor" command. In the latter case, gdb "monitor" commands will be executed on the current target of OpenOCD configuration script (that is either the last target created or the target specified in a "targets" command). Fixed in gdb_new_connection() by replacing the current target in the connection's copy of command context. Change-Id: If7c8f2dce4a3138f0907d3000dd0b15e670cfa80 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4586 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Christopher Head --- src/server/gdb_server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index f0b552dde..2270afffd 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -936,6 +936,7 @@ static int gdb_new_connection(struct connection *connection) target = get_target_from_connection(connection); connection->priv = gdb_connection; + connection->cmd_ctx->current_target = target; /* initialize gdb connection information */ gdb_connection->buf_p = gdb_connection->buffer; From 4a9a07b1c5189e8f9024fa843f511a0e948e61b5 Mon Sep 17 00:00:00 2001 From: Cody Schafer Date: Mon, 2 Jul 2018 15:56:53 -0400 Subject: [PATCH 028/147] target/image: make i/j unsigned to avoid ubsan runtime error src/target/image.c:1055:15: runtime error: left shift of 128 by 24 places cannot be represented in type 'int' Change-Id: I322fd391cf3f242beffc8a274824763c8c5e69a4 Signed-off-by: Cody Schafer Reviewed-on: http://openocd.zylin.com/4584 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Christopher Head --- src/target/image.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/target/image.c b/src/target/image.c index 9f56bea04..0d98c57b2 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -1048,8 +1048,7 @@ int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes, uint32_t *checksu static bool first_init; if (!first_init) { /* Initialize the CRC table and the decoding table. */ - int i, j; - unsigned int c; + unsigned int i, j, c; for (i = 0; i < 256; i++) { /* as per gdb */ for (c = i << 24, j = 8; j > 0; --j) From 98a07154bc588d40b16f4f07b70937133f55e97e Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Mon, 30 Apr 2018 10:28:21 -0700 Subject: [PATCH 029/147] target/stm32f7x: Clear stuck HSE clock with CSS Change-Id: Ica0025ea465910dd664ab546b66f4f25b271f1f5 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4570 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- tcl/target/stm32f7x.cfg | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tcl/target/stm32f7x.cfg b/tcl/target/stm32f7x.cfg index 98f3eea37..562de30f6 100755 --- a/tcl/target/stm32f7x.cfg +++ b/tcl/target/stm32f7x.cfg @@ -84,6 +84,45 @@ $_TARGETNAME configure -event trace-config { } $_TARGETNAME configure -event reset-init { + # If the HSE was previously enabled and the external clock source + # disappeared, RCC_CR.HSERDY can get stuck at 1 and the PLL cannot be + # properly switched back to HSI. This situation persists even over a system + # reset, including a pin reset via SRST. However, activating the clock + # security system will detect the problem and clear HSERDY to 0, which in + # turn allows the PLL to switch back to HSI properly. Since we just came + # out of reset, HSEON should be 0. If HSERDY is 1, then this situation must + # have happened; in that case, activate the clock security system to clear + # HSERDY. + if {[mrw 0x40023800] & 0x00020000} { + mmw 0x40023800 0x00090000 0 ;# RCC_CR = CSSON | HSEON + sleep 10 ;# Wait for CSS to fire, if it wants to + mmw 0x40023800 0 0x00090000 ;# RCC_CR &= ~CSSON & ~HSEON + mww 0x4002380C 0x00800000 ;# RCC_CIR = CSSC + sleep 1 ;# Wait for CSSF to clear + } + + # If the clock security system fired, it will pend an NMI. A pending NMI + # will cause a bad time for any subsequent executing code, such as a + # programming algorithm. + if {[mrw 0xE000ED04] & 0x80000000} { + # ICSR.NMIPENDSET reads as 1. Need to clear it. A pending NMI can’t be + # cleared by any normal means (such as ICSR or NVIC). It can only be + # cleared by entering the NMI handler or by resetting the processor. + echo "[target current]: Clock security system generated NMI. Clearing." + + # Keep the old DEMCR value. + set old [mrw 0xE000EDFC] + + # Enable vector catch on reset. + mww 0xE000EDFC 0x01000001 + + # Issue local reset via AIRCR. + mww 0xE000ED0C 0x05FA0001 + + # Restore old DEMCR value. + mww 0xE000EDFC $old + } + # Configure PLL to boost clock to HSI x 10 (160 MHz) mww 0x40023804 0x08002808 ;# RCC_PLLCFGR 16 Mhz /10 (M) * 128 (N) /2(P) mww 0x40023C00 0x00000107 ;# FLASH_ACR = PRFTBE | 7(Latency) From 493d2f5a34d1f9f3a0b04d3c1d90631f0193fbb8 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 22 Jun 2018 10:09:53 +0200 Subject: [PATCH 030/147] psoc5lp: fix erase check, add free_driver_priv psoc5lp_erase_check() was not properly adapted to the new armv7m_blank_check_memory() in the hot fix 53376dbbede4f0bf42e724ff This change fixes handling of num_sectors in dependecy of ecc_enabled. Also add comments how ecc_enabled influences num_sectors. Add pointer to default_flash_free_driver_priv() to all psoc5lp flash drivers to keep valgrind happy. Change-Id: Ie1806538becd364fe0efb7a414f0fe6a84b2055b Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4569 Tested-by: jenkins --- src/flash/nor/psoc5lp.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/flash/nor/psoc5lp.c b/src/flash/nor/psoc5lp.c index 0b21ed649..b88abbb47 100644 --- a/src/flash/nor/psoc5lp.c +++ b/src/flash/nor/psoc5lp.c @@ -860,6 +860,7 @@ struct flash_driver psoc5lp_nvl_flash = { .erase = psoc5lp_nvl_erase, .erase_check = psoc5lp_nvl_erase_check, .write = psoc5lp_nvl_write, + .free_driver_priv = default_flash_free_driver_priv, }; /* @@ -1068,6 +1069,7 @@ struct flash_driver psoc5lp_eeprom_flash = { .erase = psoc5lp_eeprom_erase, .erase_check = default_flash_blank_check, .write = psoc5lp_eeprom_write, + .free_driver_priv = default_flash_free_driver_priv, }; /* @@ -1078,6 +1080,10 @@ struct psoc5lp_flash_bank { bool probed; const struct psoc5lp_device *device; bool ecc_enabled; + /* If ecc is disabled, num_sectors counts both std and ecc sectors. + * If ecc is enabled, num_sectors indicates just the number of std sectors. + * However ecc sector descriptors bank->sector[num_sectors..2*num_sectors-1] + * are used for driver private flash operations */ }; static int psoc5lp_erase(struct flash_bank *bank, int first, int last) @@ -1122,21 +1128,25 @@ static int psoc5lp_erase_check(struct flash_bank *bank) return ERROR_TARGET_NOT_HALTED; } + int num_sectors = bank->num_sectors; + if (psoc_bank->ecc_enabled) + num_sectors *= 2; /* count both std and ecc sector always */ + struct target_memory_check_block *block_array; - block_array = malloc(bank->num_sectors * sizeof(struct target_memory_check_block)); + block_array = malloc(num_sectors * sizeof(struct target_memory_check_block)); if (block_array == NULL) return ERROR_FAIL; - for (i = 0; i < bank->num_sectors; i++) { + for (i = 0; i < num_sectors; i++) { block_array[i].address = bank->base + bank->sectors[i].offset; block_array[i].size = bank->sectors[i].size; block_array[i].result = UINT32_MAX; /* erase state unknown */ } bool fast_check = true; - for (i = 0; i < bank->num_sectors; ) { + for (i = 0; i < num_sectors; ) { retval = armv7m_blank_check_memory(target, - block_array + i, bank->num_sectors - i, + block_array + i, num_sectors - i, bank->erased_value); if (retval < 1) { /* Run slow fallback if the first run gives no result @@ -1149,15 +1159,15 @@ static int psoc5lp_erase_check(struct flash_bank *bank) } if (fast_check) { - if (!psoc_bank->ecc_enabled) { - int half_sectors = bank->num_sectors / 2; - for (i = 0; i < half_sectors / 2; i++) + if (psoc_bank->ecc_enabled) { + for (i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = (block_array[i].result != 1) - ? block_array[i + half_sectors].result - : block_array[i].result; + ? block_array[i].result + : block_array[i + bank->num_sectors].result; + /* if std sector is erased, use status of ecc sector */ } else { - for (i = 0; i < bank->num_sectors; i++) + for (i = 0; i < num_sectors; i++) bank->sectors[i].is_erased = block_array[i].result; } retval = ERROR_OK; @@ -1572,4 +1582,5 @@ struct flash_driver psoc5lp_flash = { .erase = psoc5lp_erase, .erase_check = psoc5lp_erase_check, .write = psoc5lp_write, + .free_driver_priv = default_flash_free_driver_priv, }; From dda7258c63fa76b3633ca3605b6857339f96b61d Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Wed, 13 Apr 2016 23:35:32 +0000 Subject: [PATCH 031/147] target: atmel samd10 xplained mini cortex m0+ on a tiny board, with an mEDBG (CMSIS-DAP) debug interface. Change-Id: Iaedfab578b4eb4aa2d923bd80f220f59b34e6ef9 Signed-off-by: Karl Palsson Reviewed-on: http://openocd.zylin.com/3402 Tested-by: jenkins Reviewed-by: Tomas Vanek --- tcl/board/atmel_samd10_xplained_mini.cfg | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tcl/board/atmel_samd10_xplained_mini.cfg diff --git a/tcl/board/atmel_samd10_xplained_mini.cfg b/tcl/board/atmel_samd10_xplained_mini.cfg new file mode 100644 index 000000000..64ae11ee9 --- /dev/null +++ b/tcl/board/atmel_samd10_xplained_mini.cfg @@ -0,0 +1,10 @@ +# +# Atmel SAMD10 Xplained mini evaluation kit. +# http://www.atmel.com/tools/atsamd10-xmini.aspx + +source [find interface/cmsis-dap.cfg] + +# chip name +set CHIPNAME at91samd10d14 + +source [find target/at91samdXX.cfg] From 336477c2b8686ab2d73aa26647f7189da4fe0627 Mon Sep 17 00:00:00 2001 From: Peter Lawrence Date: Sat, 28 Apr 2018 17:49:13 -0500 Subject: [PATCH 032/147] tcl/board: add SAMD11 Xplained Pro evaluation board Change-Id: Id996c4de6dc9f25f71424017bf07689fea7bd3af Signed-off-by: Peter Lawrence Reviewed-on: http://openocd.zylin.com/4507 Tested-by: jenkins Reviewed-by: Tomas Vanek --- tcl/board/atmel_samd11_xplained_pro.cfg | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tcl/board/atmel_samd11_xplained_pro.cfg diff --git a/tcl/board/atmel_samd11_xplained_pro.cfg b/tcl/board/atmel_samd11_xplained_pro.cfg new file mode 100644 index 000000000..8ce9751b8 --- /dev/null +++ b/tcl/board/atmel_samd11_xplained_pro.cfg @@ -0,0 +1,10 @@ +# +# Atmel SAMD11 Xplained Pro evaluation kit. +# + +source [find interface/cmsis-dap.cfg] + +# chip name +set CHIPNAME at91samd11d14 + +source [find target/at91samdXX.cfg] From 84b571f667f376ed4e5c948acd4a0fb35adf8e98 Mon Sep 17 00:00:00 2001 From: Christopher Hoover Date: Tue, 10 Jul 2018 02:35:02 -0700 Subject: [PATCH 033/147] Adds SAMD11D14AU flash support. Corrects names of SAMD11D14AM and SAMD11D14ASS per datasheet. Change-Id: I8beb15d5376966a4f8d7de76bfb2cbda2db440dc Signed-off-by: Christopher Hoover Reviewed-on: http://openocd.zylin.com/4597 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/at91samd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index 8553ee8f9..017d1441e 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -115,15 +115,16 @@ static const struct samd_part samd10_parts[] = { /* Known SAMD11 parts */ static const struct samd_part samd11_parts[] = { - { 0x0, "SAMD11D14AMU", 16, 4 }, + { 0x0, "SAMD11D14AM", 16, 4 }, { 0x1, "SAMD11D13AMU", 8, 4 }, { 0x2, "SAMD11D12AMU", 4, 4 }, - { 0x3, "SAMD11D14ASU", 16, 4 }, + { 0x3, "SAMD11D14ASS", 16, 4 }, { 0x4, "SAMD11D13ASU", 8, 4 }, { 0x5, "SAMD11D12ASU", 4, 4 }, { 0x6, "SAMD11C14A", 16, 4 }, { 0x7, "SAMD11C13A", 8, 4 }, { 0x8, "SAMD11C12A", 4, 4 }, + { 0x9, "SAMD11D14AU", 16, 4 }, }; /* Known SAMD20 parts. See Table 12-8 in 42129F–SAM–10/2013 */ From e36c2f2da47a4f038b6c5647d135e0b6f8d3b708 Mon Sep 17 00:00:00 2001 From: Hellosun Wu Date: Wed, 8 Nov 2017 17:04:11 +0800 Subject: [PATCH 034/147] nds32: Avoid detected JTAG clock AICE2 doesn't support scan for the maximum clock frequency of JTAG chain. It will cause USB command timeout. Change-Id: I41d1e3be387b6ed5a4dd0be663385a5f053fbcf9 Signed-off-by: Hellosun Wu Reviewed-on: http://openocd.zylin.com/4292 Tested-by: jenkins Reviewed-by: Hsiangkai Wang Reviewed-by: Tomas Vanek --- src/jtag/aice/aice_usb.c | 52 +++++++++++++++++++++------------------- src/jtag/aice/aice_usb.h | 1 + 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/jtag/aice/aice_usb.c b/src/jtag/aice/aice_usb.c index 50468f375..d77b26b17 100644 --- a/src/jtag/aice/aice_usb.c +++ b/src/jtag/aice/aice_usb.c @@ -2289,37 +2289,39 @@ get_delay: static int aice_usb_set_clock(int set_clock) { - if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL, - AICE_TCK_CONTROL_TCK_SCAN) != ERROR_OK) - return ERROR_FAIL; + if (set_clock & AICE_TCK_CONTROL_TCK_SCAN) { + if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL, + AICE_TCK_CONTROL_TCK_SCAN) != ERROR_OK) + return ERROR_FAIL; - /* Read out TCK_SCAN clock value */ - uint32_t scan_clock; - if (aice_read_ctrl(AICE_READ_CTRL_GET_ICE_STATE, &scan_clock) != ERROR_OK) - return ERROR_FAIL; + /* Read out TCK_SCAN clock value */ + uint32_t scan_clock; + if (aice_read_ctrl(AICE_READ_CTRL_GET_ICE_STATE, &scan_clock) != ERROR_OK) + return ERROR_FAIL; - scan_clock &= 0x0F; + scan_clock &= 0x0F; - uint32_t scan_base_freq; - if (scan_clock & 0x8) - scan_base_freq = 48000; /* 48 MHz */ - else - scan_base_freq = 30000; /* 30 MHz */ + uint32_t scan_base_freq; + if (scan_clock & 0x8) + scan_base_freq = 48000; /* 48 MHz */ + else + scan_base_freq = 30000; /* 30 MHz */ - uint32_t set_base_freq; - if (set_clock & 0x8) - set_base_freq = 48000; - else - set_base_freq = 30000; + uint32_t set_base_freq; + if (set_clock & 0x8) + set_base_freq = 48000; + else + set_base_freq = 30000; - uint32_t set_freq; - uint32_t scan_freq; - set_freq = set_base_freq >> (set_clock & 0x7); - scan_freq = scan_base_freq >> (scan_clock & 0x7); + uint32_t set_freq; + uint32_t scan_freq; + set_freq = set_base_freq >> (set_clock & 0x7); + scan_freq = scan_base_freq >> (scan_clock & 0x7); - if (scan_freq < set_freq) { - LOG_ERROR("User specifies higher jtag clock than TCK_SCAN clock"); - return ERROR_FAIL; + if (scan_freq < set_freq) { + LOG_ERROR("User specifies higher jtag clock than TCK_SCAN clock"); + return ERROR_FAIL; + } } if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL, set_clock) != ERROR_OK) diff --git a/src/jtag/aice/aice_usb.h b/src/jtag/aice/aice_usb.h index 2911ae56b..15cc1f60d 100644 --- a/src/jtag/aice/aice_usb.h +++ b/src/jtag/aice/aice_usb.h @@ -71,6 +71,7 @@ /* Constants for AICE command WRITE_CTRL:TCK_CONTROL */ #define AICE_TCK_CONTROL_TCK3048 0x08 +#define AICE_TCK_CONTROL_TCK_SCAN 0x10 /* Constants for AICE command WRITE_CTRL:JTAG_PIN_CONTROL */ #define AICE_JTAG_PIN_CONTROL_SRST 0x01 From 3a5b2b66dbdaa016de2e14faecb58c5c39c47395 Mon Sep 17 00:00:00 2001 From: Dominik Peklo Date: Sun, 24 Jun 2018 12:35:53 +1000 Subject: [PATCH 035/147] flash/nor/tcl: Distinguish between sectors and blocks in status messages Use the right word in flash protect command status messages based on whether the target bank defines num_prot_blocks. Minor message style tidy-up. Change-Id: I5f40fb5627422536ce737f242fbf80feafe7a1fc Signed-off-by: Dominik Peklo Reviewed-on: http://openocd.zylin.com/4573 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Christopher Head --- src/flash/nor/tcl.c | 56 ++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index 34681db14..b4f375fe7 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -288,24 +288,6 @@ COMMAND_HANDLER(handle_flash_erase_address_command) return retval; } -static int flash_check_sector_parameters(struct command_context *cmd_ctx, - uint32_t first, uint32_t last, uint32_t num_sectors) -{ - if (!(first <= last)) { - command_print(cmd_ctx, "ERROR: " - "first sector must be <= last sector"); - return ERROR_FAIL; - } - - if (!(last <= (num_sectors - 1))) { - command_print(cmd_ctx, "ERROR: last sector must be <= %" PRIu32, - num_sectors - 1); - return ERROR_FAIL; - } - - return ERROR_OK; -} - COMMAND_HANDLER(handle_flash_erase_command) { if (CMD_ARGC != 3) @@ -327,9 +309,18 @@ COMMAND_HANDLER(handle_flash_erase_command) else COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last); - retval = flash_check_sector_parameters(CMD_CTX, first, last, p->num_sectors); - if (retval != ERROR_OK) - return retval; + if (!(first <= last)) { + command_print(CMD_CTX, "ERROR: " + "first sector must be <= last"); + return ERROR_FAIL; + } + + if (!(last <= (uint32_t)(p->num_sectors - 1))) { + command_print(CMD_CTX, "ERROR: " + "last sector must be <= %" PRIu32, + p->num_sectors - 1); + return ERROR_FAIL; + } struct duration bench; duration_start(&bench); @@ -375,15 +366,28 @@ COMMAND_HANDLER(handle_flash_protect_command) bool set; COMMAND_PARSE_ON_OFF(CMD_ARGV[3], set); - retval = flash_check_sector_parameters(CMD_CTX, first, last, num_blocks); - if (retval != ERROR_OK) - return retval; + if (!(first <= last)) { + command_print(CMD_CTX, "ERROR: " + "first %s must be <= last", + (p->num_prot_blocks) ? "block" : "sector"); + return ERROR_FAIL; + } + + if (!(last <= (uint32_t)(num_blocks - 1))) { + command_print(CMD_CTX, "ERROR: " + "last %s must be <= %" PRIu32, + (p->num_prot_blocks) ? "block" : "sector", + num_blocks - 1); + return ERROR_FAIL; + } retval = flash_driver_protect(p, set, first, last); if (retval == ERROR_OK) { - command_print(CMD_CTX, "%s protection for sectors %" PRIu32 + command_print(CMD_CTX, "%s protection for %s %" PRIu32 " through %" PRIu32 " on flash bank %d", - (set) ? "set" : "cleared", first, last, p->bank_number); + (set) ? "set" : "cleared", + (p->num_prot_blocks) ? "blocks" : "sectors", + first, last, p->bank_number); } return retval; From 5aceec24122bc222896cfcfd91f7f082f630ac83 Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Wed, 13 Apr 2016 23:42:48 +0000 Subject: [PATCH 036/147] drivers: cmsis-dap: pull up common connect code Just a minor deduplication Change-Id: Idd256883e5f6d4bd4dcc18462dd5468991f507b3 Signed-off-by: Karl Palsson Reviewed-on: http://openocd.zylin.com/3403 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/jtag/drivers/cmsis_dap_usb.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index 6b010c1d6..a0922d465 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -841,17 +841,6 @@ static int cmsis_dap_swd_open(void) { int retval; - if (cmsis_dap_handle == NULL) { - /* SWD init */ - retval = cmsis_dap_usb_open(); - if (retval != ERROR_OK) - return retval; - - retval = cmsis_dap_get_caps_info(); - if (retval != ERROR_OK) - return retval; - } - if (!(cmsis_dap_handle->caps & INFO_CAPS_SWD)) { LOG_ERROR("CMSIS-DAP: SWD not supported"); return ERROR_JTAG_DEVICE_ERROR; @@ -872,6 +861,14 @@ static int cmsis_dap_init(void) int retval; uint8_t *data; + retval = cmsis_dap_usb_open(); + if (retval != ERROR_OK) + return retval; + + retval = cmsis_dap_get_caps_info(); + if (retval != ERROR_OK) + return retval; + if (swd_mode) { retval = cmsis_dap_swd_open(); if (retval != ERROR_OK) @@ -879,16 +876,6 @@ static int cmsis_dap_init(void) } if (cmsis_dap_handle == NULL) { - - /* JTAG init */ - retval = cmsis_dap_usb_open(); - if (retval != ERROR_OK) - return retval; - - retval = cmsis_dap_get_caps_info(); - if (retval != ERROR_OK) - return retval; - /* Connect in JTAG mode */ if (!(cmsis_dap_handle->caps & INFO_CAPS_JTAG)) { LOG_ERROR("CMSIS-DAP: JTAG not supported"); From b24301a01a0d9d98363bdeaadcdfcb604388e40f Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Wed, 13 Apr 2016 23:44:14 +0000 Subject: [PATCH 037/147] drivers: cmsis-dap: Print version info when available No need to wait until after connecting, might help diagnose part information by printing earlier. Change-Id: I51eb0d584be306baa811fbeb1ad6a604773e602c Signed-off-by: Karl Palsson Reviewed-on: http://openocd.zylin.com/3404 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/jtag/drivers/cmsis_dap_usb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index a0922d465..231e7c81b 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -869,6 +869,10 @@ static int cmsis_dap_init(void) if (retval != ERROR_OK) return retval; + retval = cmsis_dap_get_version_info(); + if (retval != ERROR_OK) + return retval; + if (swd_mode) { retval = cmsis_dap_swd_open(); if (retval != ERROR_OK) @@ -889,10 +893,6 @@ static int cmsis_dap_init(void) LOG_INFO("CMSIS-DAP: Interface Initialised (JTAG)"); } - retval = cmsis_dap_get_version_info(); - if (retval != ERROR_OK) - return retval; - /* INFO_ID_PKT_SZ - short */ retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_SZ, &data); if (retval != ERROR_OK) From 3e84da55a64fbfb025c104d0968e2cb84de80a53 Mon Sep 17 00:00:00 2001 From: Edward Fewell Date: Fri, 2 Jun 2017 21:20:26 -0500 Subject: [PATCH 038/147] flash/nor: add support for TI MSP432 devices Added msp432 flash driver to support the TI MSP432P4x and MSP432E4x microcontrollers. Implemented the flash algo helper as used in the TI debug and flash tools. This implemention supports the MSP432E4, Falcon, and Falcon 2M variants. The flash driver automatically detects the connected variant and configures itself appropriately. Added command to mass erase device for consistency with TI tools and added command to unlock the protected BSL region. Tested using MSP432E401Y, MSP432P401R, and MSP432P4111 LaunchPads. Tested with embedded XDS110 debug probe in CMSIS-DAP mode and with external SEGGER J-Link probe. Removed ti_msp432p4xx.cfg file made obsolete by this patch. Change-Id: I3b29d39ccc492524ef2c4a1733f7f9942c2684c0 Signed-off-by: Edward Fewell Reviewed-on: http://openocd.zylin.com/4153 Tested-by: jenkins Reviewed-by: Matthias Welwarsky Reviewed-by: Tomas Vanek --- .../flash/msp432/MSP432E4_FlashLibIf.h | 126 ++ .../flash/msp432/MSP432P4_FlashLibIf.h | 126 ++ contrib/loaders/flash/msp432/Makefile | 99 ++ contrib/loaders/flash/msp432/driverlib.c | 472 +++++++ contrib/loaders/flash/msp432/driverlib.h | 384 ++++++ contrib/loaders/flash/msp432/main_msp432e4x.c | 351 ++++++ .../loaders/flash/msp432/main_msp432p401x.c | 385 ++++++ .../loaders/flash/msp432/main_msp432p411x.c | 391 ++++++ contrib/loaders/flash/msp432/msp432e4x.h | 229 ++++ .../flash/msp432/msp432e4x/msp432e4x.lds | 149 +++ .../loaders/flash/msp432/msp432e4x_algo.inc | 245 ++++ contrib/loaders/flash/msp432/msp432p401x.h | 102 ++ .../flash/msp432/msp432p401x/msp432p401x.lds | 151 +++ .../loaders/flash/msp432/msp432p401x_algo.inc | 242 ++++ contrib/loaders/flash/msp432/msp432p411x.h | 164 +++ .../flash/msp432/msp432p411x/msp432p411x.lds | 151 +++ .../loaders/flash/msp432/msp432p411x_algo.inc | 361 ++++++ .../loaders/flash/msp432/startup_msp432e4.c | 122 ++ .../loaders/flash/msp432/startup_msp432p4.c | 122 ++ doc/openocd.texi | 35 + src/flash/nor/Makefile.am | 4 +- src/flash/nor/drivers.c | 2 + src/flash/nor/msp432.c | 1103 +++++++++++++++++ src/flash/nor/msp432.h | 127 ++ tcl/board/ti_msp432_launchpad.cfg | 7 + .../{ti_msp432p4xx.cfg => ti_msp432.cfg} | 18 +- 26 files changed, 5657 insertions(+), 11 deletions(-) create mode 100644 contrib/loaders/flash/msp432/MSP432E4_FlashLibIf.h create mode 100644 contrib/loaders/flash/msp432/MSP432P4_FlashLibIf.h create mode 100644 contrib/loaders/flash/msp432/Makefile create mode 100644 contrib/loaders/flash/msp432/driverlib.c create mode 100644 contrib/loaders/flash/msp432/driverlib.h create mode 100644 contrib/loaders/flash/msp432/main_msp432e4x.c create mode 100644 contrib/loaders/flash/msp432/main_msp432p401x.c create mode 100644 contrib/loaders/flash/msp432/main_msp432p411x.c create mode 100644 contrib/loaders/flash/msp432/msp432e4x.h create mode 100644 contrib/loaders/flash/msp432/msp432e4x/msp432e4x.lds create mode 100644 contrib/loaders/flash/msp432/msp432e4x_algo.inc create mode 100644 contrib/loaders/flash/msp432/msp432p401x.h create mode 100644 contrib/loaders/flash/msp432/msp432p401x/msp432p401x.lds create mode 100644 contrib/loaders/flash/msp432/msp432p401x_algo.inc create mode 100644 contrib/loaders/flash/msp432/msp432p411x.h create mode 100644 contrib/loaders/flash/msp432/msp432p411x/msp432p411x.lds create mode 100644 contrib/loaders/flash/msp432/msp432p411x_algo.inc create mode 100644 contrib/loaders/flash/msp432/startup_msp432e4.c create mode 100644 contrib/loaders/flash/msp432/startup_msp432p4.c create mode 100644 src/flash/nor/msp432.c create mode 100644 src/flash/nor/msp432.h create mode 100644 tcl/board/ti_msp432_launchpad.cfg rename tcl/target/{ti_msp432p4xx.cfg => ti_msp432.cfg} (66%) diff --git a/contrib/loaders/flash/msp432/MSP432E4_FlashLibIf.h b/contrib/loaders/flash/msp432/MSP432E4_FlashLibIf.h new file mode 100644 index 000000000..d406d6003 --- /dev/null +++ b/contrib/loaders/flash/msp432/MSP432E4_FlashLibIf.h @@ -0,0 +1,126 @@ +/****************************************************************************** +* +* Copyright (C) 2014-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432E4_FLASHLIBIF_H +#define OPENOCD_LOADERS_FLASH_MSP432_MSP432E4_FLASHLIBIF_H + +#include +#include + +/* RAM loader */ +static const uint32_t RAM_LOADER_START = 0x20000000u; /* Code space */ +static const uint32_t RAM_LOADER_MAIN = 0x20000110u; /* Code space */ +static const uint32_t RAM_LOADER_BUFFER1 = 0x20002000u; /* SBUS data space */ +static const uint32_t RAM_LOADER_BUFFER2 = 0x20003000u; /* SBUS data space */ +static const uint32_t RAM_LOADER_STACK = 0x20002000u; /* SBUS data space */ + +/* Address for flash function to be executed */ +static const uint32_t FLASH_FUNCTION_ADDRESS = 0x20000150u; + +enum flash_command { + FLASH_NO_COMMAND = 0, + FLASH_MASS_ERASE = 1, + FLASH_SECTOR_ERASE = 2, + FLASH_PROGRAM = 4, + FLASH_INIT = 8, + FLASH_EXIT = 16, + FLASH_CONTINUOUS_PROGRAM = 32 +}; + +/* Address for algorithm program and flash buffer */ +static const uint32_t DST_ADDRESS = 0x2000015Cu; +static const uint32_t SRC_LENGTH_ADDRESS = 0x20000160u; +static const uint32_t BUFFER1_STATUS_REGISTER = 0x20000164u; +static const uint32_t BUFFER2_STATUS_REGISTER = 0x20000168u; +static const uint32_t BUFFER_INACTIVE = 0x00000000u; +static const uint32_t BUFFER_ACTIVE = 0x00000001u; +static const uint32_t BUFFER_DATA_READY = 0x00000010u; +static const size_t SRC_LENGTH_MAX = 4096u; + +/* Erase options */ +static const uint32_t ERASE_PARAM_ADDRESS = 0x2000016Cu; +static const uint32_t ERASE_MAIN = 0x00000001u; +static const uint32_t ERASE_INFO = 0x00000002u; + +/* Unlock BSL */ +static const uint32_t UNLOCK_BSL_ADDRESS = 0x20000170u; +static const uint32_t LOCK_BSL_KEY = 0x00000000u; +static const uint32_t UNLOCK_BSL_KEY = 0x0000000Bu; + +/* Address for return code */ +static const uint32_t RETURN_CODE_ADDRESS = 0x20000154u; + +/* Return codes */ +static const uint32_t FLASH_BUSY = 0x00000001u; +static const uint32_t FLASH_SUCCESS = 0x00000ACEu; +static const uint32_t FLASH_ERROR = 0x0000DEADu; +static const uint32_t FLASH_TIMEOUT_ERROR = 0xDEAD0000u; +static const uint32_t FLASH_VERIFY_ERROR = 0xDEADDEADu; +static const uint32_t FLASH_WRONG_COMMAND = 0x00000BADu; +static const uint32_t FLASH_POWER_ERROR = 0x00DEAD00u; + +/* Device ID address */ +static const uint32_t DEVICE_ID_ADDRESS = 0x0020100Cu; +static const uint32_t PC_REGISTER = 15u; +static const uint32_t SP_REGISTER = 13u; + +/* CS silicon and boot code revisions */ +static const uint32_t SILICON_REV_ADDRESS = 0x00201010u; +static const uint32_t SILICON_REV_A = 0x00000041u; +static const uint32_t SILICON_REV_B = 0x00000042u; +static const uint32_t SILICON_REV_C = 0x00000043u; +static const uint32_t SILICON_REV_D = 0x00000044u; +static const uint32_t SILICON_REV_E = 0x00000045u; +static const uint32_t SILICON_REV_F = 0x00000046u; +static const uint32_t SILICON_REV_G = 0x00000047u; +static const uint32_t SILICON_REV_H = 0x00000048u; +static const uint32_t SILICON_REV_I = 0x00000049u; +static const uint32_t SILICON_REV_B_WRONG = 0x00004100u; + +struct flash_interface { + volatile uint32_t FLASH_FUNCTION; + volatile uint32_t RETURN_CODE; + volatile uint32_t _RESERVED0; + volatile uint32_t DST_ADDRESS; + volatile uint32_t SRC_LENGTH; + volatile uint32_t BUFFER1_STATUS_REGISTER; + volatile uint32_t BUFFER2_STATUS_REGISTER; + volatile uint32_t ERASE_PARAM; + volatile uint32_t UNLOCK_BSL; +}; + +#define FLASH_LOADER_BASE ((uint32_t)0x20000150u) +#define FLASH_LOADER ((struct flash_interface *) FLASH_LOADER_BASE) + +#endif /* OPENOCD_LOADERS_FLASH_MSP432_MSP432E4_FLASHLIBIF_H */ diff --git a/contrib/loaders/flash/msp432/MSP432P4_FlashLibIf.h b/contrib/loaders/flash/msp432/MSP432P4_FlashLibIf.h new file mode 100644 index 000000000..c438097ef --- /dev/null +++ b/contrib/loaders/flash/msp432/MSP432P4_FlashLibIf.h @@ -0,0 +1,126 @@ +/****************************************************************************** +* +* Copyright (C) 2014-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432P4_FLASHLIBIF_H +#define OPENOCD_LOADERS_FLASH_MSP432_MSP432P4_FLASHLIBIF_H + +#include +#include + +/* RAM loader */ +static const uint32_t RAM_LOADER_START = 0x01000000u; /* Code space */ +static const uint32_t RAM_LOADER_MAIN = 0x01000110u; /* Code space */ +static const uint32_t RAM_LOADER_BUFFER1 = 0x20002000u; /* SBUS data space */ +static const uint32_t RAM_LOADER_BUFFER2 = 0x20003000u; /* SBUS data space */ +static const uint32_t RAM_LOADER_STACK = 0x20002000u; /* SBUS data space */ + +/* Address for flash function to be executed */ +static const uint32_t FLASH_FUNCTION_ADDRESS = 0x20000150u; + +enum flash_command { + FLASH_NO_COMMAND = 0, + FLASH_MASS_ERASE = 1, + FLASH_SECTOR_ERASE = 2, + FLASH_PROGRAM = 4, + FLASH_INIT = 8, + FLASH_EXIT = 16, + FLASH_CONTINUOUS_PROGRAM = 32 +}; + +/* Address for algorithm program and flash buffer */ +static const uint32_t DST_ADDRESS = 0x2000015Cu; +static const uint32_t SRC_LENGTH_ADDRESS = 0x20000160u; +static const uint32_t BUFFER1_STATUS_REGISTER = 0x20000164u; +static const uint32_t BUFFER2_STATUS_REGISTER = 0x20000168u; +static const uint32_t BUFFER_INACTIVE = 0x00000000u; +static const uint32_t BUFFER_ACTIVE = 0x00000001u; +static const uint32_t BUFFER_DATA_READY = 0x00000010u; +static const size_t SRC_LENGTH_MAX = 4096u; + +/* erase options */ +static const uint32_t ERASE_PARAM_ADDRESS = 0x2000016Cu; +static const uint32_t ERASE_MAIN = 0x00000001u; +static const uint32_t ERASE_INFO = 0x00000002u; + +/* Unlock BSL */ +static const uint32_t UNLOCK_BSL_ADDRESS = 0x20000170u; +static const uint32_t LOCK_BSL_KEY = 0x00000000u; +static const uint32_t UNLOCK_BSL_KEY = 0x0000000Bu; + +/* Address for return code */ +static const uint32_t RETURN_CODE_ADDRESS = 0x20000154u; + +/* Return codes */ +static const uint32_t FLASH_BUSY = 0x00000001u; +static const uint32_t FLASH_SUCCESS = 0x00000ACEu; +static const uint32_t FLASH_ERROR = 0x0000DEADu; +static const uint32_t FLASH_TIMEOUT_ERROR = 0xDEAD0000u; +static const uint32_t FLASH_VERIFY_ERROR = 0xDEADDEADu; +static const uint32_t FLASH_WRONG_COMMAND = 0x00000BADu; +static const uint32_t FLASH_POWER_ERROR = 0x00DEAD00u; + +/* Device ID address */ +static const uint32_t DEVICE_ID_ADDRESS = 0x0020100Cu; +static const uint32_t PC_REGISTER = 15u; +static const uint32_t SP_REGISTER = 13u; + +/* CS silicon and boot code revisions */ +static const uint32_t SILICON_REV_ADDRESS = 0x00201010u; +static const uint32_t SILICON_REV_A = 0x00000041u; +static const uint32_t SILICON_REV_B = 0x00000042u; +static const uint32_t SILICON_REV_C = 0x00000043u; +static const uint32_t SILICON_REV_D = 0x00000044u; +static const uint32_t SILICON_REV_E = 0x00000045u; +static const uint32_t SILICON_REV_F = 0x00000046u; +static const uint32_t SILICON_REV_G = 0x00000047u; +static const uint32_t SILICON_REV_H = 0x00000048u; +static const uint32_t SILICON_REV_I = 0x00000049u; +static const uint32_t SILICON_REV_B_WRONG = 0x00004100u; + +struct flash_interface { + volatile uint32_t FLASH_FUNCTION; + volatile uint32_t RETURN_CODE; + volatile uint32_t _RESERVED0; + volatile uint32_t DST_ADDRESS; + volatile uint32_t SRC_LENGTH; + volatile uint32_t BUFFER1_STATUS_REGISTER; + volatile uint32_t BUFFER2_STATUS_REGISTER; + volatile uint32_t ERASE_PARAM; + volatile uint32_t UNLOCK_BSL; +}; + +#define FLASH_LOADER_BASE ((uint32_t)0x20000150u) +#define FLASH_LOADER ((struct flash_interface *) FLASH_LOADER_BASE) + +#endif /* OPENOCD_LOADERS_FLASH_MSP432_MSP432P4_FLASHLIBIF_H */ diff --git a/contrib/loaders/flash/msp432/Makefile b/contrib/loaders/flash/msp432/Makefile new file mode 100644 index 000000000..608333140 --- /dev/null +++ b/contrib/loaders/flash/msp432/Makefile @@ -0,0 +1,99 @@ +BIN2C = ../../../../src/helper/bin2char.sh + +CROSS_COMPILE ?= arm-none-eabi- +GCC = $(CROSS_COMPILE)gcc +OBJCOPY = $(CROSS_COMPILE)objcopy + +FLAGS = -mcpu=cortex-m4 -march=armv7e-m -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mthumb + +CFLAGS = -c -DNO_MSP_CLASSIC_DEFINES -Dgcc -Wall -ffunction-sections +CFLAGS += -fdata-sections -std=c99 -O4 + +LDFLAGS = -lc -lnosys -Wl,--gc-sections + +MSP432E4X_OBJS := \ +msp432e4x/driverlib.o \ +msp432e4x/main_msp432e4x.o \ +msp432e4x/startup_msp432e4.o + +MSP432P401X_OBJS := \ +msp432p401x/driverlib.o \ +msp432p401x/main_msp432p401x.o \ +msp432p401x/startup_msp432p4.o + +MSP432P411X_OBJS := \ +msp432p411x/driverlib.o \ +msp432p411x/main_msp432p411x.o \ +msp432p411x/startup_msp432p4.o + +all: msp432e4x_algo.inc msp432p401x_algo.inc msp432p411x_algo.inc + +msp432e4x/%.o: %.c + @echo 'Building file: $<' + @echo 'Invoking: GNU Compiler' + $(GCC) -D__MSP432E4X__ $(FLAGS) $(CFLAGS) -o"$@" "$(shell echo $<)" + @echo 'Finished building: $<' + @echo ' ' + +msp432p401x/%.o: %.c + @echo 'Building file: $<' + @echo 'Invoking: GNU Compiler' + $(GCC) -D__MSP432P401X__ $(FLAGS) $(CFLAGS) -o"$@" "$(shell echo $<)" + @echo 'Finished building: $<' + @echo ' ' + +msp432p411x/%.o: %.c + @echo 'Building file: $<' + @echo 'Invoking: GNU Compiler' + $(GCC) -D__MSP432P411X__ $(FLAGS) $(CFLAGS) -o"$@" "$(shell echo $<)" + @echo 'Finished building: $<' + @echo ' ' + +msp432e4x_algo.out: $(MSP432E4X_OBJS) + @echo 'Building target: $@' + @echo 'Invoking: GNU Linker' + $(GCC) $(FLAGS) $(LDFLAGS) -o$@ $(MSP432E4X_OBJS) -Tmsp432e4x/msp432e4x.lds + @echo 'Finished building target: $@' + @echo ' ' + +msp432p401x_algo.out: $(MSP432P401X_OBJS) + @echo 'Building target: $@' + @echo 'Invoking: GNU Linker' + $(GCC) $(FLAGS) $(LDFLAGS) -o$@ $(MSP432P401X_OBJS) -Tmsp432p401x/msp432p401x.lds + @echo 'Finished building target: $@' + @echo ' ' + +msp432p411x_algo.out: $(MSP432P411X_OBJS) + @echo 'Building target: $@' + @echo 'Invoking: GNU Linker' + $(GCC) $(FLAGS) $(LDFLAGS) -o$@ $(MSP432P411X_OBJS) -Tmsp432p411x/msp432p411x.lds + @echo 'Finished building target: $@' + @echo ' ' + +%.bin: %.out + @echo 'Building target: $@' + @echo 'Invoking: GNU Objcopy Utility' + $(OBJCOPY) -Obinary $< $@ + @echo 'Finished building target: $@' + @echo ' ' + +%.inc: %.bin + @echo 'Building target: $@' + @echo 'Invoking Bin2Char Script' + $(BIN2C) < $< > $@ + rm $< $*.out + @echo 'Finished building target: $@' + @echo ' ' + +clean: + @echo 'Cleaning Targets and Build Artifacts' + rm -rf *.inc *.bin *.out *.map + rm -rf msp432e4x/*.o msp432e4x/*.d + rm -rf msp432p401x/*.o msp432p401x/*.d + rm -rf msp432p411x/*.o msp432p411x/*.d + @echo 'Finished clean' + @echo ' ' + +.PRECIOUS: %.bin + +.PHONY: all clean diff --git a/contrib/loaders/flash/msp432/driverlib.c b/contrib/loaders/flash/msp432/driverlib.c new file mode 100644 index 000000000..a4f541619 --- /dev/null +++ b/contrib/loaders/flash/msp432/driverlib.c @@ -0,0 +1,472 @@ +/****************************************************************************** +* +* Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#include +#include +#include "driverlib.h" + +/* + * Wrapper function for the CPSID instruction. + * Returns the state of PRIMASK on entry. + */ +uint32_t __attribute__((naked)) cpu_cpsid(void) +{ + uint32_t ret; + + /* Read PRIMASK and disable interrupts. */ + __asm(" mrs r0, PRIMASK\n" + " cpsid i\n" + " bx lr\n" + : "=r" (ret)); + + /* + * The return is handled in the inline assembly, but the compiler will + * still complain if there is not an explicit return here (despite the fact + * that this does not result in any code being produced because of the + * naked attribute). + */ + return ret; +} + +/* Wrapper function for the CPUWFI instruction. */ +void __attribute__((naked)) cpu_wfi(void) +{ + /* Wait for the next interrupt. */ + __asm(" wfi\n" + " bx lr\n"); +} + +/* Power Control Module APIs */ +#if defined(PCM) + +static bool __pcm_set_core_voltage_level_advanced(uint_fast8_t voltage_level, + uint32_t time_out, bool blocking) +{ + uint8_t power_mode; + uint8_t current_voltage_level; + uint32_t reg_value; + bool bool_timeout; + + /* Getting current power mode and level */ + power_mode = pcm_get_power_mode(); + current_voltage_level = pcm_get_core_voltage_level(); + + bool_timeout = time_out > 0 ? true : false; + + /* If we are already at the power mode they requested, return */ + if (current_voltage_level == voltage_level) + return true; + + while (current_voltage_level != voltage_level) { + + reg_value = PCM->CTL0; + + switch (pcm_get_power_state()) { + case PCM_AM_LF_VCORE1: + case PCM_AM_DCDC_VCORE1: + case PCM_AM_LDO_VCORE0: + PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE1) + | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); + break; + case PCM_AM_LF_VCORE0: + case PCM_AM_DCDC_VCORE0: + case PCM_AM_LDO_VCORE1: + PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE0) + | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); + break; + default: + break; + } + + if (blocking) { + while (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS)) { + if (bool_timeout && !(--time_out)) + return false; + } + } else + return true; + + current_voltage_level = pcm_get_core_voltage_level(); + } + + /* Changing the power mode if we are stuck in LDO mode */ + if (power_mode != pcm_get_power_mode()) { + if (power_mode == PCM_DCDC_MODE) + return pcm_set_power_mode(PCM_DCDC_MODE); + else + return pcm_set_power_mode(PCM_LF_MODE); + } + + return true; +} + +bool pcm_set_core_voltage_level(uint_fast8_t voltage_level) +{ + return __pcm_set_core_voltage_level_advanced(voltage_level, 0, true); +} + +uint8_t pcm_get_power_mode(void) +{ + uint8_t current_power_state; + + current_power_state = pcm_get_power_state(); + + switch (current_power_state) { + case PCM_AM_LDO_VCORE0: + case PCM_AM_LDO_VCORE1: + case PCM_LPM0_LDO_VCORE0: + case PCM_LPM0_LDO_VCORE1: + default: + return PCM_LDO_MODE; + case PCM_AM_DCDC_VCORE0: + case PCM_AM_DCDC_VCORE1: + case PCM_LPM0_DCDC_VCORE0: + case PCM_LPM0_DCDC_VCORE1: + return PCM_DCDC_MODE; + case PCM_LPM0_LF_VCORE0: + case PCM_LPM0_LF_VCORE1: + case PCM_AM_LF_VCORE1: + case PCM_AM_LF_VCORE0: + return PCM_LF_MODE; + } +} + +uint8_t pcm_get_core_voltage_level(void) +{ + uint8_t current_power_state = pcm_get_power_state(); + + switch (current_power_state) { + case PCM_AM_LDO_VCORE0: + case PCM_AM_DCDC_VCORE0: + case PCM_AM_LF_VCORE0: + case PCM_LPM0_LDO_VCORE0: + case PCM_LPM0_DCDC_VCORE0: + case PCM_LPM0_LF_VCORE0: + default: + return PCM_VCORE0; + case PCM_AM_LDO_VCORE1: + case PCM_AM_DCDC_VCORE1: + case PCM_AM_LF_VCORE1: + case PCM_LPM0_LDO_VCORE1: + case PCM_LPM0_DCDC_VCORE1: + case PCM_LPM0_LF_VCORE1: + return PCM_VCORE1; + case PCM_LPM3: + return PCM_VCORELPM3; + } +} + +static bool __pcm_set_power_mode_advanced(uint_fast8_t power_mode, + uint32_t time_out, bool blocking) +{ + uint8_t current_power_mode; + uint8_t current_power_state; + uint32_t reg_value; + bool bool_timeout; + + /* Getting Current Power Mode */ + current_power_mode = pcm_get_power_mode(); + + /* If the power mode being set it the same as the current mode, return */ + if (power_mode == current_power_mode) + return true; + + current_power_state = pcm_get_power_state(); + + bool_timeout = time_out > 0 ? true : false; + + /* Go through the while loop while we haven't achieved the power mode */ + while (current_power_mode != power_mode) { + + reg_value = PCM->CTL0; + + switch (current_power_state) { + case PCM_AM_DCDC_VCORE0: + case PCM_AM_LF_VCORE0: + PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE0 + | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); + break; + case PCM_AM_LF_VCORE1: + case PCM_AM_DCDC_VCORE1: + PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE1 + | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); + break; + case PCM_AM_LDO_VCORE1: { + if (power_mode == PCM_DCDC_MODE) { + PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE1 + | (reg_value & ~(PCM_CTL0_KEY_MASK + | PCM_CTL0_AMR_MASK))); + } else if (power_mode == PCM_LF_MODE) { + PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE1 + | (reg_value & ~(PCM_CTL0_KEY_MASK + | PCM_CTL0_AMR_MASK))); + } else + return false; + break; + } + case PCM_AM_LDO_VCORE0: { + if (power_mode == PCM_DCDC_MODE) { + PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE0 + | (reg_value & ~(PCM_CTL0_KEY_MASK + | PCM_CTL0_AMR_MASK))); + } else if (power_mode == PCM_LF_MODE) { + PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE0 + | (reg_value & ~(PCM_CTL0_KEY_MASK + | PCM_CTL0_AMR_MASK))); + } else + return false; + break; + } + default: + break; + } + + if (blocking) { + while (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS)) { + if (bool_timeout && !(--time_out)) + return false; + } + } else + return true; + + current_power_mode = pcm_get_power_mode(); + current_power_state = pcm_get_power_state(); + } + + return true; +} + +bool pcm_set_power_mode(uint_fast8_t power_mode) +{ + return __pcm_set_power_mode_advanced(power_mode, 0, true); +} + +static bool __pcm_set_power_state_advanced(uint_fast8_t power_state, + uint32_t timeout, bool blocking) +{ + uint8_t current_power_state; + current_power_state = pcm_get_power_state(); + + if (current_power_state == power_state) + return true; + + switch (power_state) { + case PCM_AM_LDO_VCORE0: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE, + timeout, blocking); + case PCM_AM_LDO_VCORE1: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE, + timeout, blocking); + case PCM_AM_DCDC_VCORE0: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE, + timeout, blocking); + case PCM_AM_DCDC_VCORE1: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE, + timeout, blocking); + case PCM_AM_LF_VCORE0: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE, + timeout, blocking); + case PCM_AM_LF_VCORE1: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE, + timeout, blocking); + case PCM_LPM0_LDO_VCORE0: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_LDO_VCORE1: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_DCDC_VCORE0: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_DCDC_VCORE1: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_LF_VCORE0: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_LF_VCORE1: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM3: + return pcm_goto_lpm3(); + case PCM_LPM4: + return pcm_goto_lpm4(); + case PCM_LPM45: + return pcm_shutdown_device(PCM_LPM45); + case PCM_LPM35_VCORE0: + return pcm_shutdown_device(PCM_LPM35_VCORE0); + default: + return false; + } + + return false; +} + +bool pcm_set_power_state(uint_fast8_t power_state) +{ + return __pcm_set_power_state_advanced(power_state, 0, true); +} + +bool pcm_shutdown_device(uint32_t shutdown_mode) +{ + uint32_t shutdown_mode_bits = (shutdown_mode == PCM_LPM45) ? + PCM_CTL0_LPMR_12 : PCM_CTL0_LPMR_10; + + /* If a power transition is occuring, return false */ + if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS)) + return false; + + /* Initiating the shutdown */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_MSK; + + PCM->CTL0 = (PCM_KEY | shutdown_mode_bits + | (PCM->CTL0 & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_LPMR_MASK))); + + cpu_wfi(); + + return true; +} + +bool pcm_goto_lpm4(void) +{ + /* Disabling RTC_C and WDT_A */ + wdt_a_hold_timer(); + rtc_c_hold_clock(); + + /* LPM4 is just LPM3 with WDT_A/RTC_C disabled... */ + return pcm_goto_lpm3(); +} + +bool pcm_goto_lpm0(void) +{ + /* If we are in the middle of a state transition, return false */ + if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS)) + return false; + + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_MSK; + + cpu_wfi(); + + return true; +} + +bool pcm_goto_lpm3(void) +{ + uint_fast8_t current_power_state; + uint_fast8_t current_power_mode; + + /* If we are in the middle of a state transition, return false */ + if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS)) + return false; + + /* If we are in the middle of a shutdown, return false */ + if ((PCM->CTL0 & PCM_CTL0_LPMR_MASK) == PCM_CTL0_LPMR_10 + || (PCM->CTL0 & PCM_CTL0_LPMR_MASK) == PCM_CTL0_LPMR_12) + return false; + + current_power_mode = pcm_get_power_mode(); + current_power_state = pcm_get_power_state(); + + if (current_power_mode == PCM_DCDC_MODE) + pcm_set_power_mode(PCM_LDO_MODE); + + /* Clearing the SDR */ + PCM->CTL0 = + (PCM->CTL0 & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_LPMR_MASK)) | PCM_KEY; + + /* Setting the sleep deep bit */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_MSK; + + cpu_wfi(); + + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_MSK; + + return pcm_set_power_state(current_power_state); +} + +uint8_t pcm_get_power_state(void) +{ + return (PCM->CTL0 & PCM_CTL0_CPM_MASK) >> PCM_CTL0_CPM_OFS; +} + +#endif + +/* Real Time Clock APIs */ +#if defined(RTC_C) + +void rtc_c_hold_clock(void) +{ + RTC_C->CTL0 = (RTC_C->CTL0 & ~RTC_C_CTL0_KEY_MASK) | RTC_C_KEY; + BITBAND_PERI(RTC_C->CTL13, RTC_C_CTL13_HOLD_OFS) = 1; + BITBAND_PERI(RTC_C->CTL0, RTC_C_CTL0_KEY_OFS) = 0; +} + +#endif + +/* Watch Dog Timer APIs */ +#if defined(WDT_A) + +void wdt_a_hold_timer(void) +{ + /* Set Hold bit */ + uint8_t new_wdt_status = (WDT_A->CTL | WDT_A_CTL_HOLD); + + WDT_A->CTL = WDT_A_CTL_PW + new_wdt_status; +} + +#endif diff --git a/contrib/loaders/flash/msp432/driverlib.h b/contrib/loaders/flash/msp432/driverlib.h new file mode 100644 index 000000000..23ba7b520 --- /dev/null +++ b/contrib/loaders/flash/msp432/driverlib.h @@ -0,0 +1,384 @@ +/****************************************************************************** +* +* Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#ifndef OPENOCD_LOADERS_FLASH_MSP432_DRIVERLIB_H +#define OPENOCD_LOADERS_FLASH_MSP432_DRIVERLIB_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__MSP432E4X__) +#include "msp432e4x.h" +#elif defined(__MSP432P401X__) +#include "msp432p401x.h" +#elif defined(__MSP432P411X__) +#include "msp432p411x.h" +#else +#error "Failed to match a device specific include file" +#endif + +/* Structure type to access the System Control Block (SCB). */ +struct SCB_Type { + volatile uint32_t CPUID; /* CPUID Base Register */ + volatile uint32_t ICSR; /* Interrupt Control and State Register */ + volatile uint32_t VTOR; /* Vector Table Offset Register */ + volatile uint32_t AIRCR; /* Application Interrupt and Reset Control */ + volatile uint32_t SCR; /* System Control Register */ + volatile uint32_t CCR; /* Configuration Control Register */ + volatile uint8_t SHP[12U]; /* System Handlers Priority Registers */ + volatile uint32_t SHCSR; /* System Handler Control and State */ + volatile uint32_t CFSR; /* Configurable Fault Status Register */ + volatile uint32_t HFSR; /* HardFault Status Register */ + volatile uint32_t DFSR; /* Debug Fault Status Register */ + volatile uint32_t MMFAR; /* MemManage Fault Address Register */ + volatile uint32_t BFAR; /* BusFault Address Register */ + volatile uint32_t AFSR; /* Auxiliary Fault Status Register */ + volatile uint32_t PFR[2U]; /* Processor Feature Register */ + volatile uint32_t DFR; /* Debug Feature Register */ + volatile uint32_t ADR; /* Auxiliary Feature Register */ + volatile uint32_t MMFR[4U]; /* Memory Model Feature Register */ + volatile uint32_t ISAR[5U]; /* Instruction Set Attributes Register */ + uint32_t RESERVED0[5U]; + volatile uint32_t CPACR; /* Coprocessor Access Control Register */ +}; + +/* SCB:SCR register bits */ +#define SCB_SCR_SLEEPDEEP_POS 2U +#define SCB_SCR_SLEEPDEEP_MSK (1UL << SCB_SCR_SLEEPDEEP_POS) + +/* Memory mapping of Core Hardware */ +#define SCS_BASE (0xE000E000UL) /* System Control Space Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /* System Control Block Base Address */ +#define SCB ((struct SCB_Type *)SCB_BASE) /* SCB configuration struct */ + +/* Definitions of standard bits */ +#define BIT0 (uint16_t)(0x0001) +#define BIT1 (uint16_t)(0x0002) +#define BIT2 (uint16_t)(0x0004) +#define BIT3 (uint16_t)(0x0008) +#define BIT4 (uint16_t)(0x0010) +#define BIT5 (uint16_t)(0x0020) +#define BIT6 (uint16_t)(0x0040) +#define BIT7 (uint16_t)(0x0080) +#define BIT8 (uint16_t)(0x0100) +#define BIT9 (uint16_t)(0x0200) +#define BITA (uint16_t)(0x0400) +#define BITB (uint16_t)(0x0800) +#define BITC (uint16_t)(0x1000) +#define BITD (uint16_t)(0x2000) +#define BITE (uint16_t)(0x4000) +#define BITF (uint16_t)(0x8000) +#define BIT(x) ((uint16_t)1 << (x)) + +/* CPU Module prototypes */ +extern uint32_t cpu_cpsid(void); +extern void cpu_wfi(void); + +/* Clock Signal Module constants */ +#define CS_DCO_FREQUENCY_3 CS_CTL0_DCORSEL_1 +#define CS_DCO_FREQUENCY_24 CS_CTL0_DCORSEL_4 + +/* Power Control Module constants */ +#define PCM_KEY 0x695A0000 +#define PCM_AM_LDO_VCORE0 0x00 +#define PCM_AM_LDO_VCORE1 0x01 +#define PCM_AM_DCDC_VCORE0 0x04 +#define PCM_AM_DCDC_VCORE1 0x05 +#define PCM_AM_LF_VCORE0 0x08 +#define PCM_AM_LF_VCORE1 0x09 +#define PCM_LPM0_LDO_VCORE0 0x10 +#define PCM_LPM0_LDO_VCORE1 0x11 +#define PCM_LPM0_DCDC_VCORE0 0x14 +#define PCM_LPM0_DCDC_VCORE1 0x15 +#define PCM_LPM0_LF_VCORE0 0x18 +#define PCM_LPM0_LF_VCORE1 0x19 +#define PCM_LPM3 0x20 +#define PCM_LPM4 0x21 +#define PCM_LPM35_VCORE0 0xC0 +#define PCM_LPM45 0xA0 +#define PCM_VCORE0 0x00 +#define PCM_VCORE1 0x01 +#define PCM_VCORELPM3 0x02 +#define PCM_LDO_MODE 0x00 +#define PCM_DCDC_MODE 0x01 +#define PCM_LF_MODE 0x02 + +/* Power Control Module prototypes */ +extern bool pcm_set_core_voltage_level(uint_fast8_t voltage_level); +extern uint8_t pcm_get_core_voltage_level(void); +extern bool pcm_set_power_mode(uint_fast8_t power_mode); +extern uint8_t pcm_get_power_mode(void); +extern bool pcm_set_power_state(uint_fast8_t power_state); +extern uint8_t pcm_get_power_state(void); +extern bool pcm_shutdown_device(uint32_t shutdown_mode); +extern bool pcm_goto_lpm0(void); +extern bool pcm_goto_lpm3(void); +extern bool pcm_goto_lpm4(void); + +/* ROM API Function Pointers */ +#define ROM_API_TABLE ((unsigned long *)0x02000800) +#define ROM_FLASH_CTL_TABLE ((unsigned long *)(ROM_API_TABLE[7])) +#define ROM_PCM_TABLE ((unsigned long *)(ROM_API_TABLE[13])) +#define ROM_WDT_TABLE ((unsigned long *)(ROM_API_TABLE[25])) +#define ROM_SYS_CTL_A_TABLE ((unsigned long *)(ROM_API_TABLE[26])) +#define ROM_FLASH_CTL_A_TABLE ((unsigned long *)(ROM_API_TABLE[27])) + +#if defined(__MSP432P401X__) +#define ROM_FLASH_CTL_UNPROTECT_SECTOR \ + ((bool (*)(uint_fast8_t memory_space, \ + uint32_t sector_mask))ROM_FLASH_CTL_TABLE[4]) +#endif +#if defined(__MSP432P401X__) +#define ROM_FLASH_CTL_PROTECT_SECTOR \ + ((bool (*)(uint_fast8_t memory_space, \ + uint32_t sector_mask))ROM_FLASH_CTL_TABLE[5]) +#endif +#if defined(__MSP432P401X__) +#define ROM_FLASH_CTL_PERFORM_MASS_ERASE \ + ((bool (*)(void))ROM_FLASH_CTL_TABLE[8]) +#endif +#if defined(__MSP432P401X__) +#define ROM_FLASH_CTL_ERASE_SECTOR \ + ((bool (*)(uint32_t addr))ROM_FLASH_CTL_TABLE[9]) +#endif +#if defined(__MSP432P401X__) +#define ROM_FLASH_CTL_PROGRAM_MEMORY \ + ((bool (*)(void *src, void *dest, uint32_t length))ROM_FLASH_CTL_TABLE[10]) +#endif +#if defined(__MSP432P401X__) +#define ROM_FLASH_CTL_SET_WAIT_STATE \ + ((void (*)(uint32_t bank, uint32_t wait_state))ROM_FLASH_CTL_TABLE[21]) +#endif +#if defined(__MSP432P401X__) +#define ROM_FLASH_CTL_GET_WAIT_STATE \ + ((uint32_t (*)(uint32_t bank))ROM_FLASH_CTL_TABLE[22]) +#endif +#if defined(__MSP432P401X__) +#define ROM_PCM_SET_CORE_VOLTAGE_LEVEL \ + ((bool (*)(uint_fast8_t voltage_level))ROM_PCM_TABLE[0]) +#endif +#if defined(__MSP432P401X__) +#define ROM_PCM_GET_CORE_VOLTAGE_LEVEL \ + ((uint8_t (*)(void))ROM_PCM_TABLE[1]) +#endif +#if defined(__MSP432P401X__) +#define ROM_PCM_SET_POWER_STATE \ + ((bool (*)(uint_fast8_t power_state))ROM_PCM_TABLE[6]) +#endif +#if defined(__MSP432P401X__) +#define ROM_PCM_GET_POWER_STATE \ + ((uint8_t (*)(void))ROM_PCM_TABLE[8]) +#endif +#if defined(__MSP432P401X__) || defined(__MSP432P411X__) +#define ROM_WDT_A_HOLD_TIMER \ + ((void (*)(void))ROM_WDT_TABLE[0]) +#endif +#if defined(__MSP432P411X__) +#define ROM_SYS_CTL_A_GET_FLASH_SIZE \ + ((uint_least32_t (*)(void))ROM_SYS_CTL_A_TABLE[1]) +#endif +#if defined(__MSP432P411X__) +#define ROM_SYS_CTL_A_GET_INFO_FLASH_SIZE \ + ((uint_least32_t (*)(void))ROM_SYS_CTL_A_TABLE[18]) +#endif +#if defined(__MSP432P411X__) +#define ROM_FLASH_CTL_A_UNPROTECT_MEMORY \ + ((bool (*)(uint32_t start_addr, uint32_t end_addr))ROM_FLASH_CTL_A_TABLE[4]) +#endif +#if defined(__MSP432P411X__) +#define ROM_FLASH_CTL_A_PROTECT_MEMORY \ + ((bool (*)(uint32_t start_addr, uint32_t end_addr))ROM_FLASH_CTL_A_TABLE[5]) +#endif +#if defined(__MSP432P411X__) +#define ROM_FLASH_CTL_A_PERFORM_MASS_ERASE \ + ((bool (*)(void))ROM_FLASH_CTL_A_TABLE[8]) +#endif +#if defined(__MSP432P411X__) +#define ROM_FLASH_CTL_A_ERASE_SECTOR \ + ((bool (*)(uint32_t addr))ROM_FLASH_CTL_A_TABLE[9]) +#endif +#if defined(__MSP432P411X__) +#define ROM_FLASH_CTL_A_PROGRAM_MEMORY \ + ((bool (*)(void *src, void *dest, uint32_t length)) \ + ROM_FLASH_CTL_A_TABLE[10]) +#endif +#if defined(__MSP432P411X__) +#define ROM_FLASH_CTL_A_SET_WAIT_STATE \ + ((void (*)(uint32_t bank, uint32_t wait_state))ROM_FLASH_CTL_A_TABLE[21]) +#endif +#if defined(__MSP432P411X__) +#define ROM_FLASH_CTL_A_GET_WAIT_STATE \ + ((uint32_t (*)(uint32_t bank))ROM_FLASH_CTL_A_TABLE[22]) +#endif + +/* Map API functions to ROM or locally built functions */ +#ifdef ROM_FLASH_CTL_UNPROTECT_SECTOR +#define MAP_FLASH_CTL_UNPROTECT_SECTOR ROM_FLASH_CTL_UNPROTECT_SECTOR +#else +#define MAP_FLASH_CTL_UNPROTECT_SECTOR flash_ctl_unprotect_sector +#endif +#ifdef ROM_FLASH_CTL_PROTECT_SECTOR +#define MAP_FLASH_CTL_PROTECT_SECTOR ROM_FLASH_CTL_PROTECT_SECTOR +#else +#define MAP_FLASH_CTL_PROTECT_SECTOR flash_ctl_protect_sector +#endif +#ifdef ROM_FLASH_CTL_PERFORM_MASS_ERASE +#define MAP_FLASH_CTL_PERFORM_MASS_ERASE ROM_FLASH_CTL_PERFORM_MASS_ERASE +#else +#define MAP_FLASH_CTL_PERFORM_MASS_ERASE flash_ctl_perform_mass_erase +#endif +#ifdef ROM_FLASH_CTL_ERASE_SECTOR +#define MAP_FLASH_CTL_ERASE_SECTOR ROM_FLASH_CTL_ERASE_SECTOR +#else +#define MAP_FLASH_CTL_ERASE_SECTOR flash_ctl_erase_sector +#endif +#ifdef ROM_FLASH_CTL_PROGRAM_MEMORY +#define MAP_FLASH_CTL_PROGRAM_MEMORY ROM_FLASH_CTL_PROGRAM_MEMORY +#else +#define MAP_FLASH_CTL_PROGRAM_MEMORY flash_ctl_program_memory +#endif +#ifdef ROM_FLASH_CTL_SET_WAIT_STATE +#define MAP_FLASH_CTL_SET_WAIT_STATE ROM_FLASH_CTL_SET_WAIT_STATE +#else +#define MAP_FLASH_CTL_SET_WAIT_STATE flash_ctl_set_wait_state +#endif +#ifdef ROM_FLASH_CTL_GET_WAIT_STATE +#define MAP_FLASH_CTL_GET_WAIT_STATE ROM_FLASH_CTL_GET_WAIT_STATE +#else +#define MAP_FLASH_CTL_GET_WAIT_STATE flash_ctl_get_wait_state +#endif +#ifdef ROM_PCM_SET_CORE_VOLTAGE_LEVEL +#define MAP_PCM_SET_CORE_VOLTAGE_LEVEL ROM_PCM_SET_CORE_VOLTAGE_LEVEL +#else +#define MAP_PCM_SET_CORE_VOLTAGE_LEVEL pcm_set_core_voltage_level +#endif +#ifdef ROM_PCM_GET_CORE_VOLTAGE_LEVEL +#define MAP_PCM_GET_CORE_VOLTAGE_LEVEL ROM_PCM_GET_CORE_VOLTAGE_LEVEL +#else +#define MAP_PCM_GET_CORE_VOLTAGE_LEVEL pcm_get_core_voltage_level +#endif +#ifdef ROM_PCM_SET_POWER_STATE +#define MAP_PCM_SET_POWER_STATE ROM_PCM_SET_POWER_STATE +#else +#define MAP_PCM_SET_POWER_STATE pcm_set_power_state +#endif +#ifdef ROM_PCM_GET_POWER_STATE +#define MAP_PCM_GET_POWER_STATE ROM_PCM_GET_POWER_STATE +#else +#define MAP_PCM_GET_POWER_STATE pcm_get_power_state +#endif +#ifdef ROM_WDT_A_HOLD_TIMER +#define MAP_WDT_A_HOLD_TIMER ROM_WDT_A_HOLD_TIMER +#else +#define MAP_WDT_A_HOLD_TIMER wdt_a_hold_timer +#endif +#ifdef ROM_SYS_CTL_A_GET_FLASH_SIZE +#define MAP_SYS_CTL_A_GET_FLASH_SIZE ROM_SYS_CTL_A_GET_FLASH_SIZE +#else +#define MAP_SYS_CTL_A_GET_FLASH_SIZE sys_ctl_a_get_flash_size +#endif +#ifdef ROM_SYS_CTL_A_GET_INFO_FLASH_SIZE +#define MAP_SYS_CTL_A_GET_INFO_FLASH_SIZE ROM_SYS_CTL_A_GET_INFO_FLASH_SIZE +#else +#define MAP_SYS_CTL_A_GET_INFO_FLASH_SIZE sys_ctl_a_get_info_flash_size +#endif +#ifdef ROM_FLASH_CTL_A_UNPROTECT_MEMORY +#define MAP_FLASH_CTL_A_UNPROTECT_MEMORY ROM_FLASH_CTL_A_UNPROTECT_MEMORY +#else +#define MAP_FLASH_CTL_A_UNPROTECT_MEMORY flash_ctl_a_unprotect_memory +#endif +#ifdef ROM_FLASH_CTL_A_PROTECT_MEMORY +#define MAP_FLASH_CTL_A_PROTECT_MEMORY ROM_FLASH_CTL_A_PROTECT_MEMORY +#else +#define MAP_FLASH_CTL_A_PROTECT_MEMORY flash_ctl_a_protect_memory +#endif +#ifdef ROM_FLASH_CTL_A_PERFORM_MASS_ERASE +#define MAP_FLASH_CTL_A_PERFORM_MASS_ERASE ROM_FLASH_CTL_A_PERFORM_MASS_ERASE +#else +#define MAP_FLASH_CTL_A_PERFORM_MASS_ERASE flash_ctl_a_perform_mass_erase +#endif +#ifdef ROM_FLASH_CTL_A_ERASE_SECTOR +#define MAP_FLASH_CTL_A_ERASE_SECTOR ROM_FLASH_CTL_A_ERASE_SECTOR +#else +#define MAP_FLASH_CTL_A_ERASE_SECTOR flash_ctl_a_erase_sector +#endif +#ifdef ROM_FLASH_CTL_A_PROGRAM_MEMORY +#define MAP_FLASH_CTL_A_PROGRAM_MEMORY ROM_FLASH_CTL_A_PROGRAM_MEMORY +#else +#define MAP_FLASH_CTL_A_PROGRAM_MEMORY flash_ctl_a_program_memory +#endif +#ifdef ROM_FLASH_CTL_A_SET_WAIT_STATE +#define MAP_FLASH_CTL_A_SET_WAIT_STATE ROM_FLASH_CTL_A_SET_WAIT_STATE +#else +#define MAP_FLASH_CTL_A_SET_WAIT_STATE flash_ctl_a_set_wait_state +#endif +#ifdef ROM_FLASH_CTL_A_GET_WAIT_STATE +#define MAP_FLASH_CTL_A_GET_WAIT_STATE ROM_FLASH_CTL_A_GET_WAIT_STATE +#else +#define MAP_FLASH_CTL_A_GET_WAIT_STATE flash_ctl_a_get_wait_state +#endif + +/* Real Time Clock Module prototypes */ +extern void rtc_c_hold_clock(void); + +/* Watchdog Timer Module prototypes */ +extern void wdt_a_hold_timer(void); + +#if defined(__MCU_HAS_FLCTL_A__) +#define FLASH_A_BANK0 0x00 +#define FLASH_A_BANK1 0x01 +#define __INFO_FLASH_A_TECH_START__ 0x00200000 +#define __INFO_FLASH_A_TECH_MIDDLE__ 0x00204000 +#endif + +#if defined(__MCU_HAS_FLCTL__) +#define FLASH_BANK0 0x00 +#define FLASH_BANK1 0x01 +#define FLASH_MAIN_MEMORY_SPACE_BANK0 0x01 +#define FLASH_MAIN_MEMORY_SPACE_BANK1 0x02 +#define FLASH_INFO_MEMORY_SPACE_BANK0 0x03 +#define FLASH_INFO_MEMORY_SPACE_BANK1 0x04 +#define FLASH_SECTOR0 FLCTL_BANK0_MAIN_WEPROT_PROT0 +#define FLASH_SECTOR1 FLCTL_BANK0_MAIN_WEPROT_PROT1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* OPENOCD_LOADERS_FLASH_MSP432_DRIVERLIB_H */ diff --git a/contrib/loaders/flash/msp432/main_msp432e4x.c b/contrib/loaders/flash/msp432/main_msp432e4x.c new file mode 100644 index 000000000..23540ac60 --- /dev/null +++ b/contrib/loaders/flash/msp432/main_msp432e4x.c @@ -0,0 +1,351 @@ +/****************************************************************************** +* +* Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#include +#include +#include "driverlib.h" + +#include "MSP432E4_FlashLibIf.h" + +/* Local prototypes */ +void msp432_flash_init(void); +void msp432_flash_mass_erase(void); +void msp432_flash_sector_erase(void); +void msp432_flash_write(void); +void msp432_flash_continous_write(void); +void msp432_flash_exit(void); + +int main(void) +{ + /* Disable interrupts */ + __asm(" cpsid i"); + + /* Halt watchdog */ + SYSCTL->RCGCWD &= ~(SYSCTL_RCGCWD_R1 + SYSCTL_RCGCWD_R0); + + while (1) { + switch (FLASH_LOADER->FLASH_FUNCTION) { + case FLASH_INIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_init(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_MASS_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_mass_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_SECTOR_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_sector_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_PROGRAM: + case FLASH_CONTINUOUS_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_continous_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_EXIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_exit(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_NO_COMMAND: + break; + default: + FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; + break; + } + } +} + +/* Initialize flash */ +void msp432_flash_init(void) +{ + SCB->VTOR = 0x20000000; + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; +} + +/* Erase entire flash */ +void msp432_flash_mass_erase(void) +{ + bool success = false; + + /* Clear the flash access and error interrupts. */ + FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC | + FLASH_FCMISC_ERMISC | FLASH_FCMISC_PMISC); + + /* Trigger mass erase */ + FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_MERASE; + while (FLASH_CTRL->FMC & FLASH_FMC_MERASE) + ; + + /* Return an error if an access violation occurred. */ + success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS | + FLASH_FCRIS_ERRIS)); + if (!success) + FLASH_LOADER->RETURN_CODE = FLASH_VERIFY_ERROR; + else + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; +} + +/* Erase one flash sector */ +void msp432_flash_sector_erase(void) +{ + bool success = false; + + /* Clear the flash access and error interrupts. */ + FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC | + FLASH_FCMISC_ERMISC | FLASH_FCMISC_PMISC); + + /* Set 16kB aligned flash page address to be erased (16kB block) */ + FLASH_CTRL->FMA = FLASH_LOADER->DST_ADDRESS; + /* Trigger sector erase (erase flash page) */ + FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_ERASE; + while (FLASH_CTRL->FMC & FLASH_FMC_ERASE) + ; + + /* Return an error if an access violation occurred. */ + success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS | + FLASH_FCRIS_ERRIS)); + + if (!success) + FLASH_LOADER->RETURN_CODE = FLASH_ERROR; + else + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; +} + +/* Write data to flash */ +void msp432_flash_continous_write(void) +{ + bool buffer1_in_use = false; + bool buffer2_in_use = false; + uint32_t *src_address = NULL; + bool success = true; + uint32_t i = 0; + uint32_t address = FLASH_LOADER->DST_ADDRESS; + uint32_t data_to_write = FLASH_LOADER->SRC_LENGTH; + int32_t write_package = 0; + + /* Clear the flash access and error interrupts. */ + FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC | + FLASH_FCMISC_INVDMISC | FLASH_FCMISC_PROGMISC | FLASH_FCMISC_PMISC); + do { + if (data_to_write > SRC_LENGTH_MAX) { + write_package = SRC_LENGTH_MAX; + data_to_write -= write_package; + } else { + write_package = data_to_write; + data_to_write -= write_package; + } + while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) && + !(FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY)) + ; + + if (FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) { + FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE; + src_address = (uint32_t *) RAM_LOADER_BUFFER1; + buffer1_in_use = true; + } else if (FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY) { + FLASH_LOADER->BUFFER2_STATUS_REGISTER |= BUFFER_ACTIVE; + src_address = (uint32_t *) RAM_LOADER_BUFFER2; + buffer2_in_use = true; + } + + /* + * The flash hardware can only write complete words to flash. If + * an unaligned address is passed in, we must do a read-modify-write + * on a word with enough bytes to align the rest of the buffer. And + * if less than a whole word remains at the end, we must also do a + * read-modify-write on a final word to finish up. + */ + if (0 != (address & 0x3)) { + uint32_t head; + uint8_t *ui8head = (uint8_t *)&head; + uint8_t *buffer = (uint8_t *)src_address; + + /* Get starting offset for data to write (will be 1 to 3) */ + uint32_t head_offset = address & 0x03; + + /* Get the aligned address to write this first word to */ + uint32_t head_address = address & 0xfffffffc; + + /* Retrieve what is already in flash at the head address */ + head = *(uint32_t *)head_address; + + /* Substitute in the new data to write */ + while ((write_package > 0) && (head_offset < 4)) { + ui8head[head_offset] = *buffer; + head_offset++; + address++; + buffer++; + write_package--; + } + src_address = (uint32_t *)buffer; + + FLASH_CTRL->FMD = head; + FLASH_CTRL->FMA = head_address; + FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE; + + /* Wait until the word has been programmed. */ + while (FLASH_CTRL->FMC & FLASH_FMC_WRITE) + ; + + /* Return an error if an access violation occurred. */ + success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | + FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS)); + } + + /* Program a word at a time until aligned on 32-word boundary */ + while ((write_package >= 4) && ((address & 0x7f) != 0) && success) { + FLASH_CTRL->FMD = *src_address++; + FLASH_CTRL->FMA = address; + FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE; + + /* Wait until the word has been programmed. */ + while (FLASH_CTRL->FMC & FLASH_FMC_WRITE) + ; + + /* Prepare for next word to write */ + write_package -= 4; + address += 4; + + /* Return an error if an access violation occurred. */ + success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | + FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS)); + } + + /* Program data in 32-word blocks */ + while ((write_package >= 32) && success) { + /* Loop over the words in this 32-word block. */ + i = 0; + do { + FLASH_CTRL->FWBN[i] = *src_address++; + write_package -= 4; + i++; + } while ((write_package > 0) && (i < 32)); + FLASH_CTRL->FMA = address; + FLASH_CTRL->FMC2 = FLASH_FMC_WRKEY | FLASH_FMC2_WRBUF; + + /* Wait until the write buffer has been programmed. */ + while (FLASH_CTRL->FMC2 & FLASH_FMC2_WRBUF) + ; + + /* Increment destination address by words written */ + address += 128; + + /* Return an error if an access violation occurred. */ + success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | + FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS)); + } + + /* Program a word at a time on left over data */ + while ((write_package >= 4) && success) { + FLASH_CTRL->FMD = *src_address++; + FLASH_CTRL->FMA = address; + FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE; + + /* Wait until the word has been programmed. */ + while (FLASH_CTRL->FMC & FLASH_FMC_WRITE) + ; + + /* Prepare for next word to write */ + write_package -= 4; + address += 4; + + /* Return an error if an access violation occurred. */ + success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | + FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS)); + } + + if ((write_package > 0) && success) { + uint32_t tail; + uint8_t *ui8tail = (uint8_t *)&tail; + uint8_t *buffer = (uint8_t *)src_address; + + /* Set starting offset for data to write */ + uint32_t tail_offset = 0; + + /* Get the address to write this last word to */ + uint32_t tail_address = address; + + /* Retrieve what is already in flash at the tail address */ + tail = *(uint32_t *)address; + + /* Substitute in the new data to write */ + while (write_package > 0) { + ui8tail[tail_offset] = *buffer; + tail_offset++; + address++; + buffer++; + write_package--; + } + + FLASH_CTRL->FMD = tail; + FLASH_CTRL->FMA = tail_address; + FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE; + + /* Wait until the word has been programmed. */ + while (FLASH_CTRL->FMC & FLASH_FMC_WRITE) + ; + + /* Return an error if an access violation occurred. */ + success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | + FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS)); + } + + if (buffer1_in_use) { + FLASH_LOADER->BUFFER1_STATUS_REGISTER &= + ~(BUFFER_ACTIVE | BUFFER_DATA_READY); + buffer1_in_use = false; + } else if (buffer2_in_use) { + FLASH_LOADER->BUFFER2_STATUS_REGISTER &= + ~(BUFFER_ACTIVE | BUFFER_DATA_READY); + buffer2_in_use = false; + } + } while (success && data_to_write); + + if (!success) + FLASH_LOADER->RETURN_CODE = FLASH_ERROR; + else + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; +} + +/* Exit flash programming */ +void msp432_flash_exit(void) +{ + SCB->VTOR = 0x00000000; + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; +} diff --git a/contrib/loaders/flash/msp432/main_msp432p401x.c b/contrib/loaders/flash/msp432/main_msp432p401x.c new file mode 100644 index 000000000..7992f1168 --- /dev/null +++ b/contrib/loaders/flash/msp432/main_msp432p401x.c @@ -0,0 +1,385 @@ +/****************************************************************************** +* +* Copyright (C) 2013-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#include +#include +#include "driverlib.h" + +#include "MSP432P4_FlashLibIf.h" + +/* Number of erase repeats until timeout */ +#define FLASH_MAX_REPEATS 5 + +/* Local prototypes */ +void msp432_flash_init(void); +void msp432_flash_mass_erase(void); +void msp432_flash_sector_erase(void); +void msp432_flash_write(void); +void msp432_flash_continous_write(void); +void msp432_flash_exit(void); +void unlock_flash_sectors(void); +void unlock_all_flash_sectors(void); +void lock_all_flash_sectors(void); +void __cs_set_dco_frequency_range(uint32_t dco_freq); +static bool program_device(void *src, void *dest, uint32_t length); + +struct backup_params { + uint32_t BANK0_WAIT_RESTORE; + uint32_t BANK1_WAIT_RESTORE; + uint32_t CS_DC0_FREQ_RESTORE; + uint8_t VCORE_LEVEL_RESTORE; + uint8_t PCM_VCORE_LEVEL_RESTORE; +}; + +#define BACKUP_PARAMS ((struct backup_params *) 0x20000180) + +/* Main with trampoline */ +int main(void) +{ + /* Halt watchdog */ + MAP_WDT_A_HOLD_TIMER(); + + /* Disable interrupts */ + cpu_cpsid(); + + while (1) { + switch (FLASH_LOADER->FLASH_FUNCTION) { + case FLASH_INIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_init(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_MASS_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_mass_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_SECTOR_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_sector_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_CONTINUOUS_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_continous_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_EXIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_exit(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_NO_COMMAND: + break; + default: + FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; + break; + } + } +} + +/* Initialize flash */ +void msp432_flash_init(void) +{ + bool success = false; + + /* Point to vector table in RAM */ + SCB->VTOR = (uint32_t)0x01000000; + + /* backup system parameters */ + BACKUP_PARAMS->BANK0_WAIT_RESTORE = + MAP_FLASH_CTL_GET_WAIT_STATE(FLASH_BANK0); + BACKUP_PARAMS->BANK1_WAIT_RESTORE = + MAP_FLASH_CTL_GET_WAIT_STATE(FLASH_BANK1); + BACKUP_PARAMS->VCORE_LEVEL_RESTORE = MAP_PCM_GET_CORE_VOLTAGE_LEVEL(); + BACKUP_PARAMS->PCM_VCORE_LEVEL_RESTORE = MAP_PCM_GET_POWER_STATE(); + BACKUP_PARAMS->CS_DC0_FREQ_RESTORE = CS->CTL0 & CS_CTL0_DCORSEL_MASK; + + /* set parameters for flashing */ + success = MAP_PCM_SET_POWER_STATE(PCM_AM_LDO_VCORE0); + + /* Set Flash wait states to 2 */ + MAP_FLASH_CTL_SET_WAIT_STATE(FLASH_BANK0, 2); + MAP_FLASH_CTL_SET_WAIT_STATE(FLASH_BANK1, 2); + + /* Set CPU speed to 24MHz */ + __cs_set_dco_frequency_range(CS_DCO_FREQUENCY_24); + + if (!success) { + /* Indicate failed power switch */ + FLASH_LOADER->RETURN_CODE = FLASH_POWER_ERROR; + } else + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; +} + +/* Erase entire flash */ +void msp432_flash_mass_erase(void) +{ + bool success = false; + + /* Allow flash writes */ + unlock_flash_sectors(); + + /* Allow some mass erase repeats before timeout with error */ + int erase_repeats = FLASH_MAX_REPEATS; + while (!success && (erase_repeats > 0)) { + /* Mass erase with post-verify */ + success = MAP_FLASH_CTL_PERFORM_MASS_ERASE(); + erase_repeats--; + } + + if (erase_repeats == 0) + FLASH_LOADER->RETURN_CODE = FLASH_VERIFY_ERROR; + else + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; + + /* Block flash writes */ + lock_all_flash_sectors(); +} + +/* Erase one flash sector */ +void msp432_flash_sector_erase(void) +{ + bool success = false; + + /* Allow flash writes */ + unlock_all_flash_sectors(); + + /* Allow some sector erase repeats before timeout with error */ + int erase_repeats = FLASH_MAX_REPEATS; + while (!success && (erase_repeats > 0)) { + /* Sector erase with post-verify */ + success = MAP_FLASH_CTL_ERASE_SECTOR(FLASH_LOADER->DST_ADDRESS); + erase_repeats--; + } + + if (erase_repeats == 0) + FLASH_LOADER->RETURN_CODE = FLASH_ERROR; + else + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; + + /* Block flash writes */ + lock_all_flash_sectors(); +} + +/* Write data to flash with the help of DriverLib */ +void msp432_flash_write(void) +{ + bool success = false; + + /* Allow flash writes */ + unlock_all_flash_sectors(); + + while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY)) + ; + + FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE; + + /* Program memory */ + success = program_device((uint32_t *)RAM_LOADER_BUFFER1, + (void *)FLASH_LOADER->DST_ADDRESS, FLASH_LOADER->SRC_LENGTH); + + FLASH_LOADER->BUFFER1_STATUS_REGISTER &= + ~(BUFFER_ACTIVE | BUFFER_DATA_READY); + + /* Block flash writes */ + lock_all_flash_sectors(); + + if (!success) + FLASH_LOADER->RETURN_CODE = FLASH_ERROR; + else + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; +} + +/* Write data to flash with the help of DriverLib with auto-increment */ +void msp432_flash_continous_write(void) +{ + bool buffer1_in_use = false; + bool buffer2_in_use = false; + uint32_t *src_address = NULL; + bool success = false; + + uint32_t bytes_to_write = FLASH_LOADER->SRC_LENGTH; + uint32_t write_package = 0; + uint32_t start_addr = FLASH_LOADER->DST_ADDRESS; + + while (bytes_to_write > 0) { + if (bytes_to_write > SRC_LENGTH_MAX) { + write_package = SRC_LENGTH_MAX; + bytes_to_write -= write_package; + } else { + write_package = bytes_to_write; + bytes_to_write -= write_package; + } + unlock_all_flash_sectors(); + + while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) && + !(FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY)) + ; + + if (FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) { + FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE; + src_address = (uint32_t *)RAM_LOADER_BUFFER1; + buffer1_in_use = true; + } else if (FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY) { + FLASH_LOADER->BUFFER2_STATUS_REGISTER |= BUFFER_ACTIVE; + src_address = (uint32_t *)RAM_LOADER_BUFFER2; + buffer2_in_use = true; + } + if (buffer1_in_use || buffer2_in_use) { + success = program_device(src_address, + (void *)start_addr, write_package); + + if (buffer1_in_use) + P6->OUT &= ~BIT4; /* Program from B1 */ + else if (buffer2_in_use) + P3->OUT &= ~BIT6; /* Program from B1 */ + + start_addr += write_package; + } + if (buffer1_in_use) { + FLASH_LOADER->BUFFER1_STATUS_REGISTER &= + ~(BUFFER_ACTIVE | BUFFER_DATA_READY); + buffer1_in_use = false; + } else if (buffer2_in_use) { + FLASH_LOADER->BUFFER2_STATUS_REGISTER &= + ~(BUFFER_ACTIVE | BUFFER_DATA_READY); + buffer2_in_use = false; + } + /* Block flash writes */ + lock_all_flash_sectors(); + + if (!success) { + FLASH_LOADER->RETURN_CODE = FLASH_ERROR; + break; + } + } + if (success) + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; +} + +/* Unlock Main/Info Flash sectors */ +void unlock_flash_sectors(void) +{ + if (FLASH_LOADER->ERASE_PARAM & ERASE_MAIN) { + MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_MAIN_MEMORY_SPACE_BANK0, + 0xFFFFFFFF); + MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_MAIN_MEMORY_SPACE_BANK1, + 0xFFFFFFFF); + } + if (FLASH_LOADER->ERASE_PARAM & ERASE_INFO) { + MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_INFO_MEMORY_SPACE_BANK0, + FLASH_SECTOR0 | FLASH_SECTOR1); + if (FLASH_LOADER->UNLOCK_BSL == UNLOCK_BSL_KEY) + MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_INFO_MEMORY_SPACE_BANK1, + FLASH_SECTOR0 | FLASH_SECTOR1); + } +} + +/* Unlock All Flash sectors */ +void unlock_all_flash_sectors(void) +{ + MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_MAIN_MEMORY_SPACE_BANK0, 0xFFFFFFFF); + MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_MAIN_MEMORY_SPACE_BANK1, 0xFFFFFFFF); + MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_INFO_MEMORY_SPACE_BANK0, + FLASH_SECTOR0 | FLASH_SECTOR1); + if (FLASH_LOADER->UNLOCK_BSL == UNLOCK_BSL_KEY) + MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_INFO_MEMORY_SPACE_BANK1, + FLASH_SECTOR0 | FLASH_SECTOR1); +} + + +/* Lock all Flash sectors */ +void lock_all_flash_sectors(void) +{ + MAP_FLASH_CTL_PROTECT_SECTOR(FLASH_MAIN_MEMORY_SPACE_BANK0, 0xFFFFFFFF); + MAP_FLASH_CTL_PROTECT_SECTOR(FLASH_MAIN_MEMORY_SPACE_BANK1, 0xFFFFFFFF); + MAP_FLASH_CTL_PROTECT_SECTOR(FLASH_INFO_MEMORY_SPACE_BANK0, + FLASH_SECTOR0 | FLASH_SECTOR1); + MAP_FLASH_CTL_PROTECT_SECTOR(FLASH_INFO_MEMORY_SPACE_BANK1, + FLASH_SECTOR0 | FLASH_SECTOR1); +} + + +/* Force DCO frequency range */ +void __cs_set_dco_frequency_range(uint32_t dco_freq) +{ + /* Unlocking the CS Module */ + CS->KEY = CS_KEY_VAL; + + /* Resetting Tuning Parameters and Setting the frequency */ + CS->CTL0 = (CS->CTL0 & ~CS_CTL0_DCORSEL_MASK) | dco_freq; + + /* Locking the CS Module */ + CS->KEY = 0; +} + +/* Exit flash programming */ +void msp432_flash_exit(void) +{ + bool success = false; + + /* Restore modified registers, in reverse order */ + __cs_set_dco_frequency_range(CS_DCO_FREQUENCY_3); + + MAP_FLASH_CTL_SET_WAIT_STATE(FLASH_BANK0, + BACKUP_PARAMS->BANK0_WAIT_RESTORE); + MAP_FLASH_CTL_SET_WAIT_STATE(FLASH_BANK1, + BACKUP_PARAMS->BANK1_WAIT_RESTORE); + + success = MAP_PCM_SET_POWER_STATE(BACKUP_PARAMS->PCM_VCORE_LEVEL_RESTORE); + + success &= MAP_PCM_SET_CORE_VOLTAGE_LEVEL( + BACKUP_PARAMS->VCORE_LEVEL_RESTORE); + + __cs_set_dco_frequency_range(BACKUP_PARAMS->CS_DC0_FREQ_RESTORE); + + /* Point to vector table in Flash */ + SCB->VTOR = (uint32_t)0x00000000; + + if (!success) + FLASH_LOADER->RETURN_CODE = FLASH_ERROR; + else + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; +} + +static bool program_device(void *src, void *dest, uint32_t length) +{ + return MAP_FLASH_CTL_PROGRAM_MEMORY(src, dest, length); +} diff --git a/contrib/loaders/flash/msp432/main_msp432p411x.c b/contrib/loaders/flash/msp432/main_msp432p411x.c new file mode 100644 index 000000000..be1f70976 --- /dev/null +++ b/contrib/loaders/flash/msp432/main_msp432p411x.c @@ -0,0 +1,391 @@ +/****************************************************************************** +* +* Copyright (C) 2013-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#include +#include +#include "driverlib.h" + +#include "MSP432P4_FlashLibIf.h" + +/* Number of erase repeats until timeout */ +#define FLASH_MAX_REPEATS 5 + +/* Local prototypes */ +void msp432_flash_init(void); +void msp432_flash_mass_erase(void); +void msp432_flash_sector_erase(void); +void msp432_flash_write(void); +void msp432_flash_continous_write(void); +void msp432_flash_exit(void); +void unlock_flash_sectors(void); +void unlock_all_flash_sectors(void); +void lock_all_flash_sectors(void); +void __cs_set_dco_frequency_range(uint32_t dco_freq); +static bool program_device(void *src, void *dest, uint32_t length); + +struct backup_params { + uint32_t BANK0_WAIT_RESTORE; + uint32_t BANK1_WAIT_RESTORE; + uint32_t CS_DC0_FREQ_RESTORE; + uint8_t VCORE_LEVEL_RESTORE; + uint8_t PCM_VCORE_LEVEL_RESTORE; +}; + +#define BACKUP_PARAMS ((struct backup_params *) 0x20000180) +#define INFO_FLASH_START __INFO_FLASH_A_TECH_START__ +#define INFO_FLASH_MIDDLE __INFO_FLASH_A_TECH_MIDDLE__ +#define BSL_FLASH_START BSL_API_TABLE_ADDR + +/* Main with trampoline */ +int main(void) +{ + /* Halt watchdog */ + MAP_WDT_A_HOLD_TIMER(); + + /* Disable interrupts */ + cpu_cpsid(); + + while (1) { + switch (FLASH_LOADER->FLASH_FUNCTION) { + case FLASH_INIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_init(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_MASS_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_mass_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_SECTOR_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_sector_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_CONTINUOUS_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_continous_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_EXIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_exit(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_NO_COMMAND: + break; + default: + FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; + break; + } + } +} + +/* Initialize flash */ +void msp432_flash_init(void) +{ + bool success = false; + + /* Point to vector table in RAM */ + SCB->VTOR = (uint32_t)0x01000000; + + /* backup system parameters */ + BACKUP_PARAMS->BANK0_WAIT_RESTORE = + MAP_FLASH_CTL_A_GET_WAIT_STATE(FLASH_A_BANK0); + BACKUP_PARAMS->BANK1_WAIT_RESTORE = + MAP_FLASH_CTL_A_GET_WAIT_STATE(FLASH_A_BANK1); + BACKUP_PARAMS->VCORE_LEVEL_RESTORE = MAP_PCM_GET_CORE_VOLTAGE_LEVEL(); + BACKUP_PARAMS->PCM_VCORE_LEVEL_RESTORE = MAP_PCM_GET_POWER_STATE(); + BACKUP_PARAMS->CS_DC0_FREQ_RESTORE = CS->CTL0 & CS_CTL0_DCORSEL_MASK; + + /* set parameters for flashing */ + success = MAP_PCM_SET_POWER_STATE(PCM_AM_LDO_VCORE0); + + /* Set Flash wait states to 2 */ + MAP_FLASH_CTL_A_SET_WAIT_STATE(FLASH_A_BANK0, 2); + MAP_FLASH_CTL_A_SET_WAIT_STATE(FLASH_A_BANK1, 2); + + /* Set CPU speed to 24MHz */ + __cs_set_dco_frequency_range(CS_DCO_FREQUENCY_24); + + if (!success) { + /* Indicate failed power switch */ + FLASH_LOADER->RETURN_CODE = FLASH_POWER_ERROR; + } else + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; +} + +/* Erase entire flash */ +void msp432_flash_mass_erase(void) +{ + bool success = false; + + /* Allow flash writes */ + unlock_flash_sectors(); + + /* Allow some mass erase repeats before timeout with error */ + int erase_repeats = FLASH_MAX_REPEATS; + while (!success && (erase_repeats > 0)) { + /* Mass erase with post-verify */ + success = ROM_FLASH_CTL_A_PERFORM_MASS_ERASE(); + erase_repeats--; + } + + if (erase_repeats == 0) + FLASH_LOADER->RETURN_CODE = FLASH_VERIFY_ERROR; + else + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; + + /* Block flash writes */ + lock_all_flash_sectors(); +} + +/* Erase one flash sector */ +void msp432_flash_sector_erase(void) +{ + bool success = false; + + /* Allow flash writes */ + unlock_all_flash_sectors(); + + /* Allow some sector erase repeats before timeout with error */ + int erase_repeats = FLASH_MAX_REPEATS; + while (!success && (erase_repeats > 0)) { + /* Sector erase with post-verify */ + success = MAP_FLASH_CTL_A_ERASE_SECTOR(FLASH_LOADER->DST_ADDRESS); + erase_repeats--; + } + + if (erase_repeats == 0) + FLASH_LOADER->RETURN_CODE = FLASH_ERROR; + else + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; + + /* Block flash writes */ + lock_all_flash_sectors(); +} + +/* Write data to flash with the help of DriverLib */ +void msp432_flash_write(void) +{ + bool success = false; + + /* Allow flash writes */ + unlock_all_flash_sectors(); + + while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY)) + ; + + FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE; + + /* Program memory */ + success = program_device((uint32_t *)RAM_LOADER_BUFFER1, + (void *)FLASH_LOADER->DST_ADDRESS, FLASH_LOADER->SRC_LENGTH); + + FLASH_LOADER->BUFFER1_STATUS_REGISTER &= + ~(BUFFER_ACTIVE | BUFFER_DATA_READY); + + /* Block flash writes */ + lock_all_flash_sectors(); + + if (!success) + FLASH_LOADER->RETURN_CODE = FLASH_ERROR; + else + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; +} + +/* Write data to flash with the help of DriverLib with auto-increment */ +void msp432_flash_continous_write(void) +{ + bool buffer1_in_use = false; + bool buffer2_in_use = false; + uint32_t *src_address = NULL; + bool success = false; + + uint32_t bytes_to_write = FLASH_LOADER->SRC_LENGTH; + uint32_t write_package = 0; + uint32_t start_addr = FLASH_LOADER->DST_ADDRESS; + + while (bytes_to_write > 0) { + if (bytes_to_write > SRC_LENGTH_MAX) { + write_package = SRC_LENGTH_MAX; + bytes_to_write -= write_package; + } else { + write_package = bytes_to_write; + bytes_to_write -= write_package; + } + unlock_all_flash_sectors(); + while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) && + !(FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY)) + ; + + if (FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) { + FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE; + src_address = (uint32_t *) RAM_LOADER_BUFFER1; + buffer1_in_use = true; + } else if (FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY) { + FLASH_LOADER->BUFFER2_STATUS_REGISTER |= BUFFER_ACTIVE; + src_address = (uint32_t *) RAM_LOADER_BUFFER2; + buffer2_in_use = true; + } + if (buffer1_in_use || buffer2_in_use) { + success = program_device(src_address, (void *) start_addr, write_package); + start_addr += write_package; + } + if (buffer1_in_use) { + FLASH_LOADER->BUFFER1_STATUS_REGISTER &= ~(BUFFER_ACTIVE | BUFFER_DATA_READY); + buffer1_in_use = false; + } else if (buffer2_in_use) { + FLASH_LOADER->BUFFER2_STATUS_REGISTER &= ~(BUFFER_ACTIVE | BUFFER_DATA_READY); + buffer2_in_use = false; + } + /* Block flash writes */ + lock_all_flash_sectors(); + + if (!success) { + FLASH_LOADER->RETURN_CODE = FLASH_ERROR; + break; + } + } + if (success) + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; +} + +/* Unlock Main/Info Flash sectors */ +void unlock_flash_sectors(void) +{ + if (FLASH_LOADER->ERASE_PARAM & ERASE_MAIN) + MAP_FLASH_CTL_A_UNPROTECT_MEMORY(FLASH_BASE, FLASH_BASE + + MAP_SYS_CTL_A_GET_FLASH_SIZE() - 1); + + if (FLASH_LOADER->ERASE_PARAM & ERASE_INFO) { + MAP_FLASH_CTL_A_UNPROTECT_MEMORY(INFO_FLASH_START, TLV_BASE - 1); + if (FLASH_LOADER->UNLOCK_BSL == UNLOCK_BSL_KEY) + MAP_FLASH_CTL_A_UNPROTECT_MEMORY(BSL_FLASH_START, + INFO_FLASH_MIDDLE - 1); + MAP_FLASH_CTL_A_UNPROTECT_MEMORY(INFO_FLASH_MIDDLE, INFO_FLASH_MIDDLE + + MAP_SYS_CTL_A_GET_INFO_FLASH_SIZE() - 1); + } +} + +/* Unlock All Flash sectors */ +void unlock_all_flash_sectors(void) +{ + MAP_FLASH_CTL_A_UNPROTECT_MEMORY(FLASH_BASE, FLASH_BASE + + MAP_SYS_CTL_A_GET_FLASH_SIZE() - 1); + MAP_FLASH_CTL_A_UNPROTECT_MEMORY(INFO_FLASH_START, TLV_BASE - 1); + if (FLASH_LOADER->UNLOCK_BSL == UNLOCK_BSL_KEY) + MAP_FLASH_CTL_A_UNPROTECT_MEMORY(BSL_FLASH_START, + INFO_FLASH_MIDDLE - 1); + MAP_FLASH_CTL_A_UNPROTECT_MEMORY(INFO_FLASH_MIDDLE, INFO_FLASH_MIDDLE + + MAP_SYS_CTL_A_GET_INFO_FLASH_SIZE() - 1); +} + +/* Lock all Flash sectors */ +void lock_all_flash_sectors(void) +{ + MAP_FLASH_CTL_A_PROTECT_MEMORY(FLASH_BASE, FLASH_BASE + + MAP_SYS_CTL_A_GET_FLASH_SIZE() - 1); + MAP_FLASH_CTL_A_PROTECT_MEMORY(INFO_FLASH_START, INFO_FLASH_START + + MAP_SYS_CTL_A_GET_INFO_FLASH_SIZE() - 1); +} + +/* Force DCO frequency range */ +void __cs_set_dco_frequency_range(uint32_t dco_freq) +{ + /* Unlocking the CS Module */ + CS->KEY = CS_KEY_VAL; + + /* Resetting Tuning Parameters and Setting the frequency */ + CS->CTL0 = (CS->CTL0 & ~CS_CTL0_DCORSEL_MASK) | dco_freq; + + /* Locking the CS Module */ + CS->KEY = 0; +} + +/* Exit flash programming */ +void msp432_flash_exit(void) +{ + bool success = false; + + /* Restore modified registers, in reverse order */ + __cs_set_dco_frequency_range(CS_DCO_FREQUENCY_3); + + MAP_FLASH_CTL_A_SET_WAIT_STATE(FLASH_A_BANK0, + BACKUP_PARAMS->BANK0_WAIT_RESTORE); + MAP_FLASH_CTL_A_SET_WAIT_STATE(FLASH_A_BANK1, + BACKUP_PARAMS->BANK1_WAIT_RESTORE); + + success = MAP_PCM_SET_POWER_STATE(BACKUP_PARAMS->PCM_VCORE_LEVEL_RESTORE); + + success &= MAP_PCM_SET_CORE_VOLTAGE_LEVEL( + BACKUP_PARAMS->VCORE_LEVEL_RESTORE); + + __cs_set_dco_frequency_range(BACKUP_PARAMS->CS_DC0_FREQ_RESTORE); + + /* Point to vector table in Flash */ + SCB->VTOR = (uint32_t)0x00000000; + + if (!success) + FLASH_LOADER->RETURN_CODE = FLASH_ERROR; + else + FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; +} + +static bool program_device(void *src, void *dest, uint32_t length) +{ + uint32_t dst_address = (uint32_t)dest; + + /* Flash main memory first, then information memory */ + if ((dst_address < INFO_FLASH_START) && ((dst_address + length) > + INFO_FLASH_START)) { + uint32_t block_length = INFO_FLASH_START - dst_address; + uint32_t src_address = (uint32_t)src; + /* Main memory block */ + bool success = MAP_FLASH_CTL_A_PROGRAM_MEMORY(src, dest, block_length); + + src_address = src_address + block_length; + block_length = length - block_length; + /* Information memory block */ + success &= MAP_FLASH_CTL_A_PROGRAM_MEMORY((void *)src_address, + (void *)INFO_FLASH_START, block_length); + return success; + } else + return MAP_FLASH_CTL_A_PROGRAM_MEMORY(src, dest, length); +} diff --git a/contrib/loaders/flash/msp432/msp432e4x.h b/contrib/loaders/flash/msp432/msp432e4x.h new file mode 100644 index 000000000..2a9d15511 --- /dev/null +++ b/contrib/loaders/flash/msp432/msp432e4x.h @@ -0,0 +1,229 @@ +/****************************************************************************** +* +* Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432E4X_H +#define OPENOCD_LOADERS_FLASH_MSP432_MSP432E4X_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Register map for FLASH_CTRL peripheral (FLASH_CTRL) */ +struct flash_ctrl { + volatile uint32_t FMA; /* Flash Memory Address */ + volatile uint32_t FMD; /* Flash Memory Data */ + volatile uint32_t FMC; /* Flash Memory Control */ + volatile uint32_t FCRIS; /* Flash Controller Raw Interrupt Status */ + volatile uint32_t FCIM; /* Flash Controller Interrupt Mask */ + volatile uint32_t FCMISC; /* Flash Cont. Masked Int. Status and Clear */ + volatile uint32_t RESERVED0[2]; + volatile uint32_t FMC2; /* Flash Memory Control 2 */ + volatile uint32_t RESERVED1[3]; + volatile uint32_t FWBVAL; /* Flash Write Buffer Valid */ + volatile uint32_t RESERVED2[2]; + volatile uint32_t FLPEKEY; /* Flash Program/Erase Key */ + volatile uint32_t RESERVED3[48]; + volatile uint32_t FWBN[32]; /* Flash Write Buffer n */ +}; + +/* Register map for SYSCTL peripheral (SYSCTL) */ +struct sys_ctrl { + volatile uint32_t DID0; /* Device Identification 0 */ + volatile uint32_t DID1; /* Device Identification 1 */ + volatile uint32_t RESERVED0[12]; + volatile uint32_t PTBOCTL; /* Power-Temp Brown Out Control */ + volatile uint32_t RESERVED1[5]; + volatile uint32_t RIS; /* Raw Interrupt Status */ + volatile uint32_t IMC; /* Interrupt Mask Control */ + volatile uint32_t MISC; /* Masked Interrupt Status and Clear */ + volatile uint32_t RESC; /* Reset Cause */ + volatile uint32_t PWRTC; /* Power-Temperature Cause */ + volatile uint32_t NMIC; /* NMI Cause Register */ + volatile uint32_t RESERVED2[5]; + volatile uint32_t MOSCCTL; /* Main Oscillator Control */ + volatile uint32_t RESERVED3[12]; + volatile uint32_t RSCLKCFG; /* Run and Sleep Mode Configuration Register */ + volatile uint32_t RESERVED4[3]; + volatile uint32_t MEMTIM0; /* Memory Timing Register 0 for Main Flash */ + volatile uint32_t RESERVED5[29]; + volatile uint32_t ALTCLKCFG; /* Alternate Clock Configuration */ + volatile uint32_t RESERVED6[2]; + union { + volatile uint32_t DSLPCLKCFG; /* Deep Sleep Clock Configuration */ + volatile uint32_t DSCLKCFG; /* Deep Sleep Clock Register */ + }; + volatile uint32_t DIVSCLK; /* Divisor and Source Clock Configuration */ + volatile uint32_t SYSPROP; /* System Properties */ + volatile uint32_t PIOSCCAL; /* Precision Internal Oscillator Calibration */ + volatile uint32_t PIOSCSTAT; /* Precision Internal Oscillator Statistics */ + volatile uint32_t RESERVED7[2]; + volatile uint32_t PLLFREQ0; /* PLL Frequency 0 */ + volatile uint32_t PLLFREQ1; /* PLL Frequency 1 */ + volatile uint32_t PLLSTAT; /* PLL Status */ + volatile uint32_t RESERVED8[7]; + volatile uint32_t SLPPWRCFG; /* Sleep Power Configuration */ + volatile uint32_t DSLPPWRCFG; /* Deep-Sleep Power Configuration */ + volatile uint32_t RESERVED9[4]; + volatile uint32_t NVMSTAT; /* Non-Volatile Memory Information */ + volatile uint32_t RESERVED10[4]; + volatile uint32_t LDOSPCTL; /* LDO Sleep Power Control */ + volatile uint32_t RESERVED11; + volatile uint32_t LDODPCTL; /* LDO Deep-Sleep Power Control */ + volatile uint32_t RESERVED12[6]; + volatile uint32_t RESBEHAVCTL; /* Reset Behavior Control Register */ + volatile uint32_t RESERVED13[6]; + volatile uint32_t HSSR; /* Hardware System Service Request */ + volatile uint32_t RESERVED14[34]; + volatile uint32_t USBPDS; /* USB Power Domain Status */ + volatile uint32_t USBMPC; /* USB Memory Power Control */ + volatile uint32_t EMACPDS; /* Ethernet MAC Power Domain Status */ + volatile uint32_t EMACMPC; /* Ethernet MAC Memory Power Control */ + volatile uint32_t RESERVED15; + volatile uint32_t LCDMPC; /* LCD Memory Power Control */ + volatile uint32_t RESERVED16[26]; + volatile uint32_t PPWD; /* Watchdog Timer Peripheral Present */ + volatile uint32_t PPTIMER; /* General-Purpose Timer Peripheral Present */ + volatile uint32_t PPGPIO; /* General-Purpose I/O Peripheral Present */ + volatile uint32_t PPDMA; /* Micro DMA Peripheral Present */ + volatile uint32_t PPEPI; /* EPI Peripheral Present */ + volatile uint32_t PPHIB; /* Hibernation Peripheral Present */ + volatile uint32_t PPUART; /* UART Peripheral Present */ + volatile uint32_t PPSSI; /* Synchronous Serial Inter. Periph. Present */ + volatile uint32_t PPI2C; /* Inter-Integrated Circuit Periph. Present */ + volatile uint32_t RESERVED17; + volatile uint32_t PPUSB; /* Universal Serial Bus Peripheral Present */ + volatile uint32_t RESERVED18; + volatile uint32_t PPEPHY; /* Ethernet PHY Peripheral Present */ + volatile uint32_t PPCAN; /* Controller Area Network Periph. Present */ + volatile uint32_t PPADC; /* Analog-to-Dig. Converter Periph. Present */ + volatile uint32_t PPACMP; /* Analog Comparator Peripheral Present */ + volatile uint32_t PPPWM; /* Pulse Width Modulator Peripheral Present */ + volatile uint32_t PPQEI; /* Quadrature Encoder Inter. Periph. Present */ + volatile uint32_t RESERVED19[4]; + volatile uint32_t PPEEPROM; /* EEPROM Peripheral Present */ + volatile uint32_t RESERVED20[6]; + volatile uint32_t PPCCM; /* CRC/Cryptographic Modules Periph. Present */ + volatile uint32_t RESERVED21[6]; + volatile uint32_t PPLCD; /* LCD Peripheral Present */ + volatile uint32_t RESERVED22; + volatile uint32_t PPOWIRE; /* 1-Wire Peripheral Present */ + volatile uint32_t PPEMAC; /* Ethernet MAC Peripheral Present */ + volatile uint32_t RESERVED23[88]; + volatile uint32_t SRWD; /* Watchdog Timer Software Reset */ + volatile uint32_t SRTIMER; /* General-Purpose Timer Software Reset */ + volatile uint32_t SRGPIO; /* General-Purpose I/O Software Reset */ + volatile uint32_t SRDMA; /* Micro Direct Memory Access Software Reset */ + volatile uint32_t SREPI; /* EPI Software Reset */ + volatile uint32_t SRHIB; /* Hibernation Software Reset */ + volatile uint32_t SRUART; /* UART Software Reset */ + volatile uint32_t SRSSI; /* Synchronous Serial Inter. Software Reset */ + volatile uint32_t SRI2C; /* Inter-Integrated Circuit Software Reset */ + volatile uint32_t RESERVED24; + volatile uint32_t SRUSB; /* Universal Serial Bus Software Reset */ + volatile uint32_t RESERVED25; + volatile uint32_t SREPHY; /* Ethernet PHY Software Reset */ + volatile uint32_t SRCAN; /* Controller Area Network Software Reset */ + volatile uint32_t SRADC; /* Analog-to-Dig. Converter Software Reset */ + volatile uint32_t SRACMP; /* Analog Comparator Software Reset */ + volatile uint32_t SRPWM; /* Pulse Width Modulator Software Reset */ + volatile uint32_t SRQEI; /* Quadrature Encoder Inter. Software Reset */ + volatile uint32_t RESERVED26[4]; + volatile uint32_t SREEPROM; /* EEPROM Software Reset */ + volatile uint32_t RESERVED27[6]; + volatile uint32_t SRCCM; /* CRC/Cryptographic Modules Software Reset */ + volatile uint32_t RESERVED28[6]; + volatile uint32_t SRLCD; /* LCD Controller Software Reset */ + volatile uint32_t RESERVED29; + volatile uint32_t SROWIRE; /* 1-Wire Software Reset */ + volatile uint32_t SREMAC; /* Ethernet MAC Software Reset */ + volatile uint32_t RESERVED30[24]; + volatile uint32_t RCGCWD; /* Watchdog Run Mode Clock Gating Control */ +}; + +/* Peripheral Memory Map */ +#define FLASH_CTRL_BASE 0x400FD000UL +#define SYSCTL_BASE 0x400FE000UL + +/* Peripheral Declarations */ +#define FLASH_CTRL ((struct flash_ctrl *) FLASH_CTRL_BASE) +#define SYSCTL ((struct sys_ctrl *) SYSCTL_BASE) + +/* The following are defines for the bit fields in the FLASH_FMC register. */ +#define FLASH_FMC_WRKEY 0xA4420000 /* FLASH write key */ +#define FLASH_FMC_COMT 0x00000008 /* Commit Register Value */ +#define FLASH_FMC_MERASE 0x00000004 /* Mass Erase Flash Memory */ +#define FLASH_FMC_ERASE 0x00000002 /* Erase a Page of Flash Memory */ +#define FLASH_FMC_WRITE 0x00000001 /* Write a Word into Flash Memory */ + +/* The following are defines for the bit fields in the FLASH_FCRIS register. */ +#define FLASH_FCRIS_PROGRIS 0x00002000 /* Program Verify Raw Interrupt Status */ +#define FLASH_FCRIS_ERRIS 0x00000800 /* Erase Verify Raw Interrupt Status */ +#define FLASH_FCRIS_INVDRIS 0x00000400 /* Invalid Data Raw Interrupt Status */ +#define FLASH_FCRIS_VOLTRIS 0x00000200 /* Pump Voltage Raw Interrupt Status */ +#define FLASH_FCRIS_ERIS 0x00000004 /* EEPROM Raw Interrupt Status */ +#define FLASH_FCRIS_PRIS 0x00000002 /* Programming Raw Interrupt Status */ +#define FLASH_FCRIS_ARIS 0x00000001 /* Access Raw Interrupt Status */ + +/* The following are defines for the bit fields in the FLASH_FCIM register. */ +#define FLASH_FCIM_PROGMASK 0x00002000 /* PROGVER Interrupt Mask */ +#define FLASH_FCIM_ERMASK 0x00000800 /* ERVER Interrupt Mask */ +#define FLASH_FCIM_INVDMASK 0x00000400 /* Invalid Data Interrupt Mask */ +#define FLASH_FCIM_VOLTMASK 0x00000200 /* VOLT Interrupt Mask */ +#define FLASH_FCIM_EMASK 0x00000004 /* EEPROM Interrupt Mask */ +#define FLASH_FCIM_PMASK 0x00000002 /* Programming Interrupt Mask */ +#define FLASH_FCIM_AMASK 0x00000001 /* Access Interrupt Mask */ + +/* The following are defines for the bit fields in the FLASH_FCMISC register. */ +#define FLASH_FCMISC_PROGMISC 0x00002000 /* PROGVER Interrupt Status/Clear */ +#define FLASH_FCMISC_ERMISC 0x00000800 /* ERVER Interrupt Status/Clear */ +#define FLASH_FCMISC_INVDMISC 0x00000400 /* Invalid Data Int. Status/Clear */ +#define FLASH_FCMISC_VOLTMISC 0x00000200 /* VOLT Interrupt Status/Clear */ +#define FLASH_FCMISC_EMISC 0x00000004 /* EEPROM Interrupt Status/Clear */ +#define FLASH_FCMISC_PMISC 0x00000002 /* Programming Int. Status/Clear */ +#define FLASH_FCMISC_AMISC 0x00000001 /* Access Interrupt Status/Clear */ + +/* The following are defines for the bit fields in the FLASH_FMC2 register. */ +#define FLASH_FMC2_WRBUF 0x00000001 /* Buffered Flash Memory Write */ + +/* The following are defines for the bit fields in the SYSCTL_RCGCWD reg. */ +#define SYSCTL_RCGCWD_R1 0x00000002 /* Watchdog 1 Run Mode Clock Gating Cont. */ +#define SYSCTL_RCGCWD_R0 0x00000001 /* Watchdog 0 Run Mode Clock Gating Cont. */ + +#ifdef __cplusplus +} +#endif + +#endif /* OPENOCD_LOADERS_FLASH_MSP432_MSP432E4X_H */ diff --git a/contrib/loaders/flash/msp432/msp432e4x/msp432e4x.lds b/contrib/loaders/flash/msp432/msp432e4x/msp432e4x.lds new file mode 100644 index 000000000..af97458e6 --- /dev/null +++ b/contrib/loaders/flash/msp432/msp432e4x/msp432e4x.lds @@ -0,0 +1,149 @@ +/****************************************************************************** +* +* Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +MEMORY { + MAIN_FLASH (RX) : ORIGIN = 0x00000000, LENGTH = 0x00100000 + SRAM_CODE_0(RWX): ORIGIN = 0x20000000, LENGTH = 0x00000110 + SRAM_CODE_1(RWX): ORIGIN = 0x20000110, LENGTH = 0x00000030 + SRAM_CODE_2(RWX): ORIGIN = 0x20000150, LENGTH = 0x00000040 + SRAM_CODE_3(RWX): ORIGIN = 0x20000190, LENGTH = 0x00000F70 + SRAM_CODE_4(RWX): ORIGIN = 0x20001170, LENGTH = 0x00000200 + SRAM_DATA (RW) : ORIGIN = 0x20002000, LENGTH = 0x00001000 +} + +REGION_ALIAS("REGION_INTVECT", SRAM_CODE_0); +REGION_ALIAS("REGION_RESET", SRAM_CODE_1); +REGION_ALIAS("REGION_DESCRIPTOR", SRAM_CODE_2); +REGION_ALIAS("REGION_TEXT", SRAM_CODE_3); +REGION_ALIAS("REGION_BSS", SRAM_CODE_3); +REGION_ALIAS("REGION_DATA", SRAM_DATA); +REGION_ALIAS("REGION_STACK", SRAM_CODE_4); +REGION_ALIAS("REGION_HEAP", SRAM_DATA); +REGION_ALIAS("REGION_ARM_EXIDX", SRAM_CODE_3); +REGION_ALIAS("REGION_ARM_EXTAB", SRAM_CODE_3); + +SECTIONS { + /* section for the interrupt vector area */ + .intvecs : { + KEEP (*(.intvecs)) + } > REGION_INTVECT + + PROVIDE (_vtable_base_address = + DEFINED(_vtable_base_address) ? _vtable_base_address : 0x20000000); + + .vtable (_vtable_base_address) : AT (_vtable_base_address) { + KEEP (*(.vtable)) + } > REGION_DATA + + .descriptor :{ + FILL(0x00000000); + . = ORIGIN(REGION_DESCRIPTOR) + LENGTH(REGION_DESCRIPTOR) - 1; + BYTE(0x00); + __ROM_AT = .; + } > REGION_DESCRIPTOR + + .reset : { + KEEP(*(.reset)) + } > REGION_RESET AT> REGION_RESET + + .text : { + CREATE_OBJECT_SYMBOLS + KEEP (*(.text)) + *(.text.*) + . = ALIGN(0x4); + KEEP (*(.ctors)) + . = ALIGN(0x4); + KEEP (*(.dtors)) + . = ALIGN(0x4); + __init_array_start = .; + KEEP (*(.init_array*)) + __init_array_end = .; + KEEP (*(.init)) + KEEP (*(.fini*)) + } > REGION_TEXT AT> REGION_TEXT + + .rodata : { + *(.rodata) + *(.rodata.*) + } > REGION_TEXT AT> REGION_TEXT + + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > REGION_ARM_EXIDX AT> REGION_ARM_EXIDX + + .ARM.extab : { + KEEP (*(.ARM.extab* .gnu.linkonce.armextab.*)) + } > REGION_ARM_EXTAB AT> REGION_ARM_EXTAB + + __etext = .; + + .data : { + __data_load__ = LOADADDR (.data); + __data_start__ = .; + KEEP (*(.data)) + KEEP (*(.data*)) + . = ALIGN (4); + __data_end__ = .; + } > REGION_DATA AT> REGION_TEXT + + .bss : { + __bss_start__ = .; + *(.shbss) + KEEP (*(.bss)) + *(.bss.*) + *(COMMON) + . = ALIGN (4); + __bss_end__ = .; + } > REGION_BSS AT> REGION_BSS + + .heap : { + __heap_start__ = .; + end = __heap_start__; + _end = end; + __end = end; + KEEP (*(.heap)) + __heap_end__ = .; + __HeapLimit = __heap_end__; + } > REGION_HEAP AT> REGION_HEAP + + .stack (NOLOAD) : ALIGN(0x8) { + _stack = .; + KEEP(*(.stack)) + } > REGION_STACK AT> REGION_STACK + + __stack_top = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK); + PROVIDE(__stack = __stack_top); +} diff --git a/contrib/loaders/flash/msp432/msp432e4x_algo.inc b/contrib/loaders/flash/msp432/msp432e4x_algo.inc new file mode 100644 index 000000000..1f36a212a --- /dev/null +++ b/contrib/loaders/flash/msp432/msp432e4x_algo.inc @@ -0,0 +1,245 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x70,0x13,0x00,0x20,0x11,0x01,0x00,0x20,0xc9,0x0a,0x00,0x20,0xc9,0x0a,0x00,0x20, +0xc9,0x0a,0x00,0x20,0xc9,0x0a,0x00,0x20,0xc9,0x0a,0x00,0x20,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x0a,0x00,0x20, +0xc9,0x0a,0x00,0x20,0x00,0x00,0x00,0x00,0xc9,0x0a,0x00,0x20,0xc9,0x0a,0x00,0x20, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x41,0xf2,0x00,0x70,0xc2,0xf2,0x00,0x00,0x85,0x46,0x05,0x48,0x05,0x49,0x4f,0xf0, +0x00,0x02,0x88,0x42,0xb8,0xbf,0x40,0xf8,0x04,0x2b,0xfa,0xdb,0x00,0xf0,0x16,0xbc, +0x34,0x0f,0x00,0x20,0x50,0x0f,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x04,0x4b,0x05,0x48,0x1b,0x1a,0x06,0x2b,0x02,0xd9,0x04,0x4b,0x03,0xb1,0x18,0x47, +0x70,0x47,0x00,0xbf,0x37,0x24,0x00,0x20,0x34,0x24,0x00,0x20,0x00,0x00,0x00,0x00, +0x05,0x49,0x06,0x48,0x09,0x1a,0x89,0x10,0x01,0xeb,0xd1,0x71,0x49,0x10,0x02,0xd0, +0x03,0x4b,0x03,0xb1,0x18,0x47,0x70,0x47,0x34,0x24,0x00,0x20,0x34,0x24,0x00,0x20, +0x00,0x00,0x00,0x00,0x10,0xb5,0x06,0x4c,0x23,0x78,0x43,0xb9,0xff,0xf7,0xd8,0xff, +0x04,0x4b,0x13,0xb1,0x04,0x48,0xaf,0xf3,0x00,0x80,0x01,0x23,0x23,0x70,0x10,0xbd, +0x34,0x0f,0x00,0x20,0x00,0x00,0x00,0x00,0xf8,0x0a,0x00,0x20,0x08,0xb5,0x08,0x4b, +0x1b,0xb1,0x08,0x48,0x08,0x49,0xaf,0xf3,0x00,0x80,0x08,0x48,0x03,0x68,0x13,0xb9, +0xbd,0xe8,0x08,0x40,0xcc,0xe7,0x06,0x4b,0x00,0x2b,0xf9,0xd0,0x98,0x47,0xf7,0xe7, +0x00,0x00,0x00,0x00,0xf8,0x0a,0x00,0x20,0x38,0x0f,0x00,0x20,0x34,0x24,0x00,0x20, +0x00,0x00,0x00,0x00,0x13,0x4b,0x00,0x2b,0x08,0xbf,0x11,0x4b,0x9d,0x46,0xa3,0xf5, +0x80,0x3a,0x00,0x21,0x8b,0x46,0x0f,0x46,0x11,0x48,0x12,0x4a,0x12,0x1a,0x00,0xf0, +0x13,0xf9,0x0d,0x4b,0x00,0x2b,0x00,0xd0,0x98,0x47,0x0c,0x4b,0x00,0x2b,0x00,0xd0, +0x98,0x47,0x00,0x20,0x00,0x21,0x04,0x00,0x0d,0x00,0x0b,0x48,0x00,0xf0,0xb0,0xf8, +0x00,0xf0,0xda,0xf8,0x20,0x00,0x29,0x00,0x00,0xf0,0x70,0xfb,0x00,0xf0,0xae,0xf8, +0x00,0x00,0x08,0x00,0x70,0x13,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x34,0x0f,0x00,0x20,0x50,0x0f,0x00,0x20,0xfd,0x03,0x00,0x20,0x84,0x46,0x41,0xea, +0x00,0x03,0x13,0xf0,0x03,0x03,0x6d,0xd1,0x40,0x3a,0x41,0xd3,0x51,0xf8,0x04,0x3b, +0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, +0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, +0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, +0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, +0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, +0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, +0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, +0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x40,0x3a,0xbd,0xd2, +0x30,0x32,0x11,0xd3,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, +0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, +0x40,0xf8,0x04,0x3b,0x10,0x3a,0xed,0xd2,0x0c,0x32,0x05,0xd3,0x51,0xf8,0x04,0x3b, +0x40,0xf8,0x04,0x3b,0x04,0x3a,0xf9,0xd2,0x04,0x32,0x08,0xd0,0xd2,0x07,0x1c,0xbf, +0x11,0xf8,0x01,0x3b,0x00,0xf8,0x01,0x3b,0x01,0xd3,0x0b,0x88,0x03,0x80,0x60,0x46, +0x70,0x47,0x00,0xbf,0x08,0x2a,0x13,0xd3,0x8b,0x07,0x8d,0xd0,0x10,0xf0,0x03,0x03, +0x8a,0xd0,0xc3,0xf1,0x04,0x03,0xd2,0x1a,0xdb,0x07,0x1c,0xbf,0x11,0xf8,0x01,0x3b, +0x00,0xf8,0x01,0x3b,0x80,0xd3,0x31,0xf8,0x02,0x3b,0x20,0xf8,0x02,0x3b,0x7b,0xe7, +0x04,0x3a,0xd9,0xd3,0x01,0x3a,0x11,0xf8,0x01,0x3b,0x00,0xf8,0x01,0x3b,0xf9,0xd2, +0x0b,0x78,0x03,0x70,0x4b,0x78,0x43,0x70,0x8b,0x78,0x83,0x70,0x60,0x46,0x70,0x47, +0x01,0x46,0x00,0x20,0x02,0x46,0x03,0x46,0x00,0xf0,0x9c,0xb8,0x08,0xb5,0x00,0x21, +0x04,0x46,0x00,0xf0,0xf3,0xf8,0x04,0x4b,0x18,0x68,0xc3,0x6b,0x03,0xb1,0x98,0x47, +0x20,0x46,0x00,0xf0,0x55,0xf9,0x00,0xbf,0xf4,0x0a,0x00,0x20,0x38,0xb5,0x08,0x4b, +0x08,0x4d,0xed,0x1a,0xac,0x10,0x18,0xbf,0xed,0x18,0x05,0xd0,0x01,0x3c,0x55,0xf8, +0x04,0x3d,0x98,0x47,0x00,0x2c,0xf9,0xd1,0xbd,0xe8,0x38,0x40,0x00,0xf0,0x60,0xbb, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0xb5,0x0f,0x4e,0x0f,0x4d,0x76,0x1b, +0xb6,0x10,0x18,0xbf,0x00,0x24,0x05,0xd0,0x01,0x34,0x55,0xf8,0x04,0x3b,0x98,0x47, +0xa6,0x42,0xf9,0xd1,0x0a,0x4e,0x0b,0x4d,0x76,0x1b,0x00,0xf0,0x43,0xfb,0xb6,0x10, +0x18,0xbf,0x00,0x24,0x06,0xd0,0x01,0x34,0x55,0xf8,0x04,0x3b,0x98,0x47,0xa6,0x42, +0xf9,0xd1,0x70,0xbd,0x70,0xbd,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xd4,0x0a,0x00,0x20,0xcc,0x0a,0x00,0x20,0x70,0xb4,0x84,0x07,0x46,0xd0,0x54,0x1e, +0x00,0x2a,0x41,0xd0,0xcd,0xb2,0x03,0x46,0x02,0xe0,0x62,0x1e,0xe4,0xb3,0x14,0x46, +0x03,0xf8,0x01,0x5b,0x9a,0x07,0xf8,0xd1,0x03,0x2c,0x2e,0xd9,0xcd,0xb2,0x45,0xea, +0x05,0x25,0x0f,0x2c,0x45,0xea,0x05,0x45,0x19,0xd9,0x03,0xf1,0x10,0x02,0x26,0x46, +0x10,0x3e,0x0f,0x2e,0x42,0xf8,0x10,0x5c,0x42,0xf8,0x0c,0x5c,0x42,0xf8,0x08,0x5c, +0x42,0xf8,0x04,0x5c,0x02,0xf1,0x10,0x02,0xf2,0xd8,0xa4,0xf1,0x10,0x02,0x22,0xf0, +0x0f,0x02,0x04,0xf0,0x0f,0x04,0x10,0x32,0x03,0x2c,0x13,0x44,0x0d,0xd9,0x1e,0x46, +0x22,0x46,0x04,0x3a,0x03,0x2a,0x46,0xf8,0x04,0x5b,0xfa,0xd8,0x22,0x1f,0x22,0xf0, +0x03,0x02,0x04,0x32,0x13,0x44,0x04,0xf0,0x03,0x04,0x2c,0xb1,0xc9,0xb2,0x1c,0x44, +0x03,0xf8,0x01,0x1b,0xa3,0x42,0xfb,0xd1,0x70,0xbc,0x70,0x47,0x14,0x46,0x03,0x46, +0xc2,0xe7,0x00,0xbf,0x2d,0xe9,0xf0,0x47,0x25,0x4c,0x25,0x68,0xd5,0xf8,0x48,0x41, +0x06,0x46,0x88,0x46,0x92,0x46,0x99,0x46,0xcc,0xb3,0x60,0x68,0x1f,0x28,0x18,0xdc, +0x43,0x1c,0x7e,0xb1,0x04,0xeb,0x80,0x05,0x01,0x21,0xc5,0xf8,0x88,0xa0,0xd4,0xf8, +0x88,0x71,0x01,0xfa,0x00,0xf2,0x17,0x43,0x02,0x2e,0xc4,0xf8,0x88,0x71,0xc5,0xf8, +0x08,0x91,0x1e,0xd0,0x02,0x30,0x63,0x60,0x44,0xf8,0x20,0x80,0x00,0x20,0xbd,0xe8, +0xf0,0x87,0x14,0x4b,0x03,0xb3,0x4f,0xf4,0xc8,0x70,0xaf,0xf3,0x00,0x80,0x04,0x46, +0xd0,0xb1,0xd5,0xf8,0x48,0x31,0x00,0x27,0x80,0xe8,0x88,0x00,0xc5,0xf8,0x48,0x41, +0x38,0x46,0x01,0x23,0xc4,0xf8,0x88,0x71,0xc4,0xf8,0x8c,0x71,0x00,0x2e,0xe1,0xd0, +0xd0,0xe7,0xd4,0xf8,0x8c,0x11,0x0a,0x43,0xc4,0xf8,0x8c,0x21,0xda,0xe7,0x05,0xf5, +0xa6,0x74,0xc5,0xf8,0x48,0x41,0xc0,0xe7,0x4f,0xf0,0xff,0x30,0xbd,0xe8,0xf0,0x87, +0xf4,0x0a,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x4b,0x13,0xb1,0x02,0x48,0xff,0xf7, +0x07,0xbf,0x70,0x47,0x00,0x00,0x00,0x00,0xfd,0x03,0x00,0x20,0x2d,0xe9,0xf0,0x4f, +0x31,0x4b,0x83,0xb0,0x1b,0x68,0x00,0x93,0x03,0xf5,0xa4,0x73,0x81,0x46,0x0e,0x46, +0x01,0x93,0x00,0x9b,0xd3,0xf8,0x48,0x71,0x27,0xb3,0xdd,0xf8,0x04,0xa0,0x7c,0x68, +0x65,0x1e,0x0e,0xd4,0x01,0x34,0x07,0xeb,0x84,0x04,0x4f,0xf0,0x00,0x08,0xe6,0xb1, +0xd4,0xf8,0x00,0x31,0xb3,0x42,0x18,0xd0,0x01,0x3d,0x6b,0x1c,0xa4,0xf1,0x04,0x04, +0xf5,0xd1,0x22,0x4b,0x73,0xb1,0x7b,0x68,0x00,0x2b,0x36,0xd1,0x3b,0x68,0x00,0x2b, +0x34,0xd0,0x38,0x46,0xca,0xf8,0x00,0x30,0xaf,0xf3,0x00,0x80,0xda,0xf8,0x00,0x70, +0x00,0x2f,0xdc,0xd1,0x03,0xb0,0xbd,0xe8,0xf0,0x8f,0x7b,0x68,0x22,0x68,0x01,0x3b, +0xab,0x42,0x0c,0xbf,0x7d,0x60,0xc4,0xf8,0x00,0x80,0x00,0x2a,0xdc,0xd0,0xd7,0xf8, +0x88,0x31,0xd7,0xf8,0x04,0xb0,0x01,0x21,0xa9,0x40,0x19,0x42,0x08,0xd1,0x90,0x47, +0x7b,0x68,0x5b,0x45,0xbd,0xd1,0xda,0xf8,0x00,0x30,0xbb,0x42,0xcc,0xd0,0xb8,0xe7, +0xd7,0xf8,0x8c,0x31,0x19,0x42,0x04,0xd1,0x48,0x46,0xd4,0xf8,0x80,0x10,0x90,0x47, +0xee,0xe7,0xd4,0xf8,0x80,0x00,0x90,0x47,0xea,0xe7,0x3b,0x68,0xba,0x46,0x1f,0x46, +0x00,0x2f,0xac,0xd1,0xce,0xe7,0x00,0xbf,0xf4,0x0a,0x00,0x20,0x00,0x00,0x00,0x00, +0xfe,0xe7,0x00,0xbf,0x2d,0xe9,0xf0,0x4f,0xa8,0x4b,0xa9,0x4a,0xde,0x68,0xd3,0xf8, +0x10,0xb0,0x85,0xb0,0x42,0xf2,0x03,0x61,0x00,0x24,0x99,0x46,0xa5,0x4b,0x51,0x61, +0x15,0x46,0x90,0x46,0x00,0x94,0xbb,0xf5,0x80,0x5f,0x93,0xbf,0x5f,0x46,0xab,0xf5, +0x80,0x5b,0x4f,0xf4,0x80,0x57,0x4f,0xf0,0x00,0x0b,0x03,0xe0,0xd9,0xf8,0x18,0x20, +0xd2,0x06,0x03,0xd4,0xd9,0xf8,0x14,0x20,0xd1,0x06,0xf7,0xd5,0xd9,0xf8,0x14,0x20, +0x12,0xf0,0x10,0x02,0x00,0xf0,0xb9,0x80,0xd9,0xf8,0x14,0x20,0x42,0xf0,0x01,0x02, +0xc9,0xf8,0x14,0x20,0x4f,0xf0,0x20,0x24,0x4f,0xf0,0x01,0x0a,0x16,0xf0,0x03,0x02, +0x00,0xf0,0xa9,0x80,0x26,0xf0,0x03,0x0c,0xdc,0xf8,0x00,0x10,0x03,0x91,0x47,0xb3, +0x21,0x46,0x78,0x1e,0x11,0xf8,0x01,0xeb,0x01,0x91,0x04,0xa9,0x11,0x44,0x01,0xf8, +0x04,0xec,0x02,0xf1,0x01,0x01,0x06,0xf1,0x01,0x0e,0x00,0xf0,0x01,0x81,0x04,0x29, +0x00,0xf0,0xfe,0x80,0x04,0xa8,0x01,0x44,0x60,0x78,0x01,0xf8,0x04,0x0c,0xb9,0x1e, +0x00,0x29,0x06,0xf1,0x02,0x00,0x04,0xf1,0x02,0x0e,0x40,0xf3,0xec,0x80,0x01,0x2a, +0x40,0xf0,0xe9,0x80,0xa2,0x78,0x8d,0xf8,0x0f,0x20,0x03,0x99,0x03,0x36,0x03,0x3f, +0x03,0x34,0x78,0x4a,0x69,0x60,0xc5,0xf8,0x00,0xc0,0xaa,0x60,0xaa,0x68,0xd0,0x07, +0xfc,0xd4,0xd8,0xf8,0x0c,0x10,0x42,0xf2,0x05,0x42,0x0a,0x40,0xb2,0xfa,0x82,0xf2, +0x52,0x09,0x03,0x2f,0x1a,0xdd,0x71,0x06,0x79,0xd0,0x00,0x2a,0x75,0xd0,0x54,0xf8, +0x04,0x2b,0x6a,0x60,0x2e,0x60,0xab,0x60,0xaa,0x68,0xd2,0x07,0xfc,0xd4,0xd8,0xf8, +0x0c,0x10,0x04,0x3f,0x42,0xf2,0x05,0x42,0x03,0x2f,0x02,0xea,0x01,0x02,0x06,0xf1, +0x04,0x06,0xb2,0xfa,0x82,0xf2,0x4f,0xea,0x52,0x12,0xe4,0xdc,0x00,0x2f,0x15,0xdc, +0xba,0xf1,0x00,0x0f,0x33,0xd0,0xd9,0xf8,0x14,0x10,0x21,0xf0,0x11,0x01,0xc9,0xf8, +0x14,0x10,0x00,0x2a,0x38,0xd0,0xbb,0xf1,0x00,0x0f,0x7f,0xf4,0x6c,0xaf,0x57,0x4b, +0x40,0xf6,0xce,0x22,0x5a,0x60,0x05,0xb0,0xbd,0xe8,0xf0,0x8f,0x00,0x2a,0xe7,0xd0, +0x04,0xa8,0x32,0x68,0x40,0xf8,0x04,0x2d,0x21,0x46,0x3a,0x46,0x01,0x93,0xff,0xf7, +0x45,0xfd,0x03,0x9a,0x4f,0x4b,0x6a,0x60,0x2e,0x60,0xab,0x60,0x01,0x9b,0x37,0x44, +0xaa,0x68,0xd2,0x07,0xfc,0xd4,0xd8,0xf8,0x0c,0x10,0x42,0xf2,0x05,0x42,0x0a,0x40, +0x3e,0x46,0xb2,0xfa,0x82,0xf2,0x52,0x09,0xba,0xf1,0x00,0x0f,0xcb,0xd1,0x00,0x99, +0x00,0x29,0xce,0xd0,0xd9,0xf8,0x18,0x10,0xcd,0xf8,0x00,0xa0,0x21,0xf0,0x11,0x01, +0xc9,0xf8,0x18,0x10,0x00,0x2a,0xc6,0xd1,0x3c,0x4b,0x4d,0xf6,0xad,0x62,0x5a,0x60, +0x05,0xb0,0xbd,0xe8,0xf0,0x8f,0x01,0x22,0x93,0xe7,0xd9,0xf8,0x18,0x10,0x11,0xf0, +0x10,0x01,0x5e,0xd0,0xd9,0xf8,0x18,0x10,0x37,0x4c,0x41,0xf0,0x01,0x01,0x92,0x46, +0x01,0x22,0xc9,0xf8,0x18,0x10,0x00,0x92,0x40,0xe7,0x00,0x22,0xa0,0xe7,0x1f,0x2f, +0x32,0xdd,0x00,0x2a,0xf9,0xd0,0x07,0xf1,0xff,0x3e,0x2e,0xf0,0x03,0x0e,0x0e,0xf1, +0x04,0x0e,0xa6,0x44,0x39,0x46,0x04,0xf1,0x80,0x0c,0x00,0x22,0x01,0xe0,0x64,0x45, +0x0b,0xd0,0x54,0xf8,0x04,0x7b,0x02,0xf1,0x40,0x00,0x74,0x45,0xa1,0xf1,0x04,0x01, +0x45,0xf8,0x20,0x70,0x02,0xf1,0x01,0x02,0xf1,0xd1,0x2e,0x60,0x0f,0x46,0x2b,0x62, +0x2a,0x6a,0xd0,0x07,0xfc,0xd4,0xd8,0xf8,0x0c,0x00,0x42,0xf2,0x05,0x42,0x1f,0x29, +0x02,0xea,0x00,0x02,0x06,0xf1,0x80,0x06,0xb2,0xfa,0x82,0xf2,0x4f,0xea,0x52,0x12, +0xcf,0xdc,0x03,0x29,0x7f,0xf7,0x6a,0xaf,0x00,0x2a,0xc6,0xd0,0x54,0xf8,0x04,0x2b, +0x6a,0x60,0x2e,0x60,0xab,0x60,0xaa,0x68,0xd1,0x07,0xfc,0xd4,0xd8,0xf8,0x0c,0x10, +0x04,0x3f,0x42,0xf2,0x05,0x42,0x03,0x2f,0x02,0xea,0x01,0x02,0x06,0xf1,0x04,0x06, +0xb2,0xfa,0x82,0xf2,0x4f,0xea,0x52,0x12,0xe6,0xdc,0x00,0x2f,0x7f,0xf7,0x50,0xaf, +0x64,0xe7,0x8a,0x46,0xea,0xe6,0x0f,0x46,0x74,0x46,0x06,0x46,0x03,0x99,0x18,0xe7, +0x01,0x9c,0x03,0x99,0x07,0x46,0x76,0x46,0x13,0xe7,0x00,0xbf,0x50,0x01,0x00,0x20, +0x00,0xd0,0x0f,0x40,0x01,0x00,0x42,0xa4,0x00,0x30,0x00,0x20,0x80,0xb5,0x72,0xb6, +0x52,0x4a,0x53,0x4c,0xd2,0xf8,0x00,0x36,0x52,0x4d,0x53,0x4f,0x53,0x4e,0x23,0xf0, +0x03,0x03,0xc2,0xf8,0x00,0x36,0xa0,0x46,0x2b,0x68,0x20,0x2b,0x00,0xf2,0x8d,0x80, +0x01,0xa2,0x52,0xf8,0x23,0xf0,0x00,0xbf,0x79,0x09,0x00,0x20,0x75,0x0a,0x00,0x20, +0x4b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x3d,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20, +0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x21,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20, +0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20, +0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x0d,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20, +0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20, +0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20, +0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20, +0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x3d,0x0a,0x00,0x20,0x2c,0x49,0x00,0x23, +0x01,0x20,0x40,0xf6,0xce,0x22,0x68,0x60,0x8b,0x60,0x6a,0x60,0x2b,0x60,0xab,0xe7, +0x27,0x49,0x4f,0xf0,0x01,0x0e,0x4f,0xf0,0x00,0x50,0x40,0xf6,0xce,0x22,0x00,0x23, +0xc5,0xf8,0x04,0xe0,0x88,0x60,0x6a,0x60,0x2b,0x60,0x9d,0xe7,0x01,0x23,0x6b,0x60, +0xff,0xf7,0x30,0xfe,0x00,0x23,0x2b,0x60,0x96,0xe7,0x40,0xf6,0x03,0x23,0x01,0x22, +0x6a,0x60,0x63,0x61,0xeb,0x68,0x23,0x60,0xa7,0x60,0xa3,0x68,0x9b,0x07,0xfc,0xd4, +0xd8,0xf8,0x0c,0x20,0x40,0xf6,0x01,0x23,0x13,0x40,0xd3,0xb9,0x40,0xf6,0xce,0x23, +0x6b,0x60,0xe7,0xe7,0x01,0x22,0x40,0xf6,0x03,0x23,0x6a,0x60,0x63,0x61,0xa6,0x60, +0xa3,0x68,0x5a,0x07,0xfc,0xd4,0xd8,0xf8,0x0c,0x20,0x40,0xf6,0x01,0x23,0x13,0x40, +0x00,0x2b,0xeb,0xd0,0x0b,0x4b,0x6b,0x60,0xd4,0xe7,0x40,0xf6,0xad,0x33,0x6b,0x60, +0x6a,0xe7,0x4d,0xf6,0xad,0x63,0x6b,0x60,0xcc,0xe7,0x00,0xbf,0x00,0xe0,0x0f,0x40, +0x00,0xd0,0x0f,0x40,0x50,0x01,0x00,0x20,0x02,0x00,0x42,0xa4,0x04,0x00,0x42,0xa4, +0x00,0xed,0x00,0xe0,0xad,0xde,0xad,0xde,0xfe,0xe7,0x00,0xbf,0xfd,0x01,0x00,0x20, +0xb9,0x05,0x00,0x20,0xf8,0xb5,0x00,0xbf,0xf8,0xbc,0x08,0xbc,0x9e,0x46,0x70,0x47, +0xf8,0xb5,0x00,0xbf,0xd5,0x01,0x00,0x20,0xf8,0xbc,0x08,0xbc,0x9e,0x46,0x70,0x47, +0x43,0x00,0x00,0x00,0x08,0x20,0x00,0x20,0x3c,0xf7,0xff,0x7f,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf4,0x22,0x00,0x20, +0x5c,0x23,0x00,0x20,0xc4,0x23,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x0a,0x00,0x20, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x33,0xcd,0xab,0x34,0x12,0x6d,0xe6, +0xec,0xde,0x05,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x08,0x20,0x00,0x20, diff --git a/contrib/loaders/flash/msp432/msp432p401x.h b/contrib/loaders/flash/msp432/msp432p401x.h new file mode 100644 index 000000000..ca219fdd6 --- /dev/null +++ b/contrib/loaders/flash/msp432/msp432p401x.h @@ -0,0 +1,102 @@ +/****************************************************************************** +* +* Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432P401X_H +#define OPENOCD_LOADERS_FLASH_MSP432_MSP432P401X_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define __MCU_HAS_FLCTL__ /* Module FLCTL is available */ + +/* Device and peripheral memory map */ +#define FLASH_BASE ((uint32_t)0x00000000) /* Flash memory start address */ +#define SRAM_BASE ((uint32_t)0x20000000) /* SRAM memory start address */ +#define PERIPH_BASE ((uint32_t)0x40000000) /* Peripherals start address */ +#define CS_BASE (PERIPH_BASE + 0x00010400) /* Address of module CS regs. */ +#define DIO_BASE (PERIPH_BASE + 0x00004C00) /* Address of module DIO regs. */ + +/* Register map for Clock Signal peripheral (CS) */ +struct cs { + volatile uint32_t KEY; /* Key Register */ + volatile uint32_t CTL0; /* Control 0 Register */ + volatile uint32_t CTL1; /* Control 1 Register */ + volatile uint32_t CTL2; /* Control 2 Register */ + volatile uint32_t CTL3; /* Control 3 Register */ +}; + +/* Register map for DIO port (odd interrupt) */ +struct dio_port_odd_int { + volatile uint8_t IN; /* Port Input */ + uint8_t RESERVED0; + volatile uint8_t OUT; /* Port Output */ +}; + +/* Register map for DIO port (even interrupt) */ +struct dio_port_even_int { + uint8_t RESERVED0; + volatile uint8_t IN; /* Port Input */ + uint8_t RESERVED1; + volatile uint8_t OUT; /* Port Output */ +}; + +/* Peripheral declarations */ +#define CS ((struct cs *) CS_BASE) +#define P3 ((struct dio_port_odd_int *) (DIO_BASE + 0x0020)) +#define P6 ((struct dio_port_even_int *) (DIO_BASE + 0x0040)) + +/* Peripheral bit definitions */ + +/* DCORSEL Bit Mask */ +#define CS_CTL0_DCORSEL_MASK ((uint32_t)0x00070000) +/* Nominal DCO Frequency Range (MHz): 2 to 4 */ +#define CS_CTL0_DCORSEL_1 ((uint32_t)0x00010000) +/* Nominal DCO Frequency Range (MHz): 16 to 32 */ +#define CS_CTL0_DCORSEL_4 ((uint32_t)0x00040000) +/* CS control key value */ +#define CS_KEY_VAL ((uint32_t)0x0000695A) + +/* Protects Sector 0 from program or erase */ +#define FLCTL_BANK0_MAIN_WEPROT_PROT0 ((uint32_t)0x00000001) +/* Protects Sector 1 from program or erase */ +#define FLCTL_BANK0_MAIN_WEPROT_PROT1 ((uint32_t)0x00000002) + +#ifdef __cplusplus +} +#endif + +#endif /* OPENOCD_LOADERS_FLASH_MSP432_MSP432P401X_H */ diff --git a/contrib/loaders/flash/msp432/msp432p401x/msp432p401x.lds b/contrib/loaders/flash/msp432/msp432p401x/msp432p401x.lds new file mode 100644 index 000000000..f9d04ed88 --- /dev/null +++ b/contrib/loaders/flash/msp432/msp432p401x/msp432p401x.lds @@ -0,0 +1,151 @@ +/****************************************************************************** +* +* Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +MEMORY { + MAIN_FLASH (RX) : ORIGIN = 0x00000000, LENGTH = 0x00040000 + INFO_FLASH (RX) : ORIGIN = 0x00200000, LENGTH = 0x00004000 + SRAM_CODE_0(RWX): ORIGIN = 0x01000000, LENGTH = 0x00000110 + SRAM_CODE_1(RWX): ORIGIN = 0x01000110, LENGTH = 0x00000030 + SRAM_CODE_2(RWX): ORIGIN = 0x01000150, LENGTH = 0x00000040 + SRAM_CODE_3(RWX): ORIGIN = 0x01000190, LENGTH = 0x00000F70 + SRAM_CODE_4(RWX): ORIGIN = 0x01001170, LENGTH = 0x00000200 + SRAM_DATA (RW) : ORIGIN = 0x20002000, LENGTH = 0x00001000 +} + +REGION_ALIAS("REGION_INTVECT", SRAM_CODE_0); +REGION_ALIAS("REGION_RESET", SRAM_CODE_1); +REGION_ALIAS("REGION_DESCRIPTOR", SRAM_CODE_2); +REGION_ALIAS("REGION_TEXT", SRAM_CODE_3); +REGION_ALIAS("REGION_BSS", SRAM_CODE_3); +REGION_ALIAS("REGION_DATA", SRAM_DATA); +REGION_ALIAS("REGION_STACK", SRAM_CODE_4); +REGION_ALIAS("REGION_HEAP", SRAM_DATA); +REGION_ALIAS("REGION_ARM_EXIDX", SRAM_CODE_3); +REGION_ALIAS("REGION_ARM_EXTAB", SRAM_CODE_3); + + +SECTIONS { + /* section for the interrupt vector area */ + .intvecs : { + KEEP (*(.intvecs)) + } > REGION_INTVECT + + PROVIDE (_vtable_base_address = + DEFINED(_vtable_base_address) ? _vtable_base_address : 0x20000000); + + .vtable (_vtable_base_address) : AT (_vtable_base_address) { + KEEP (*(.vtable)) + } > REGION_DATA + + .descriptor :{ + FILL(0x00000000); + . = ORIGIN(REGION_DESCRIPTOR) + LENGTH(REGION_DESCRIPTOR) - 1; + BYTE(0x00); + __ROM_AT = .; + } > REGION_DESCRIPTOR + + .reset : { + KEEP(*(.reset)) + } > REGION_RESET AT> REGION_RESET + + .text : { + CREATE_OBJECT_SYMBOLS + KEEP (*(.text)) + *(.text.*) + . = ALIGN(0x4); + KEEP (*(.ctors)) + . = ALIGN(0x4); + KEEP (*(.dtors)) + . = ALIGN(0x4); + __init_array_start = .; + KEEP (*(.init_array*)) + __init_array_end = .; + KEEP (*(.init)) + KEEP (*(.fini*)) + } > REGION_TEXT AT> REGION_TEXT + + .rodata : { + *(.rodata) + *(.rodata.*) + } > REGION_TEXT AT> REGION_TEXT + + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > REGION_ARM_EXIDX AT> REGION_ARM_EXIDX + + .ARM.extab : { + KEEP (*(.ARM.extab* .gnu.linkonce.armextab.*)) + } > REGION_ARM_EXTAB AT> REGION_ARM_EXTAB + + __etext = .; + + .data : { + __data_load__ = LOADADDR (.data); + __data_start__ = .; + KEEP (*(.data)) + KEEP (*(.data*)) + . = ALIGN (4); + __data_end__ = .; + } > REGION_DATA AT> REGION_TEXT + + .bss : { + __bss_start__ = .; + *(.shbss) + KEEP (*(.bss)) + *(.bss.*) + *(COMMON) + . = ALIGN (4); + __bss_end__ = .; + } > REGION_BSS AT> REGION_BSS + + .heap : { + __heap_start__ = .; + end = __heap_start__; + _end = end; + __end = end; + KEEP (*(.heap)) + __heap_end__ = .; + __HeapLimit = __heap_end__; + } > REGION_HEAP AT> REGION_HEAP + + .stack (NOLOAD) : ALIGN(0x8) { + _stack = .; + KEEP(*(.stack)) + } > REGION_STACK AT> REGION_STACK + + __stack_top = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK); + PROVIDE(__stack = __stack_top); +} diff --git a/contrib/loaders/flash/msp432/msp432p401x_algo.inc b/contrib/loaders/flash/msp432/msp432p401x_algo.inc new file mode 100644 index 000000000..c30234218 --- /dev/null +++ b/contrib/loaders/flash/msp432/msp432p401x_algo.inc @@ -0,0 +1,242 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x70,0x13,0x00,0x01,0x11,0x01,0x00,0x01,0xa1,0x0a,0x00,0x01,0xa1,0x0a,0x00,0x01, +0xa1,0x0a,0x00,0x01,0xa1,0x0a,0x00,0x01,0xa1,0x0a,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa1,0x0a,0x00,0x01, +0xa1,0x0a,0x00,0x01,0x00,0x00,0x00,0x00,0xa1,0x0a,0x00,0x01,0xa1,0x0a,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x41,0xf2,0x00,0x70,0xc0,0xf2,0x00,0x10,0x85,0x46,0x05,0x48,0x05,0x49,0x4f,0xf0, +0x00,0x02,0x88,0x42,0xb8,0xbf,0x40,0xf8,0x04,0x2b,0xfa,0xdb,0x00,0xf0,0x96,0xbb, +0x0c,0x0f,0x00,0x01,0x28,0x0f,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x04,0x4b,0x05,0x48,0x1b,0x1a,0x06,0x2b,0x02,0xd9,0x04,0x4b,0x03,0xb1,0x18,0x47, +0x70,0x47,0x00,0xbf,0x37,0x24,0x00,0x20,0x34,0x24,0x00,0x20,0x00,0x00,0x00,0x00, +0x05,0x49,0x06,0x48,0x09,0x1a,0x89,0x10,0x01,0xeb,0xd1,0x71,0x49,0x10,0x02,0xd0, +0x03,0x4b,0x03,0xb1,0x18,0x47,0x70,0x47,0x34,0x24,0x00,0x20,0x34,0x24,0x00,0x20, +0x00,0x00,0x00,0x00,0x10,0xb5,0x06,0x4c,0x23,0x78,0x43,0xb9,0xff,0xf7,0xd8,0xff, +0x04,0x4b,0x13,0xb1,0x04,0x48,0xaf,0xf3,0x00,0x80,0x01,0x23,0x23,0x70,0x10,0xbd, +0x0c,0x0f,0x00,0x01,0x00,0x00,0x00,0x00,0xd0,0x0a,0x00,0x01,0x08,0xb5,0x08,0x4b, +0x1b,0xb1,0x08,0x48,0x08,0x49,0xaf,0xf3,0x00,0x80,0x08,0x48,0x03,0x68,0x13,0xb9, +0xbd,0xe8,0x08,0x40,0xcc,0xe7,0x06,0x4b,0x00,0x2b,0xf9,0xd0,0x98,0x47,0xf7,0xe7, +0x00,0x00,0x00,0x00,0xd0,0x0a,0x00,0x01,0x10,0x0f,0x00,0x01,0x34,0x24,0x00,0x20, +0x00,0x00,0x00,0x00,0x13,0x4b,0x00,0x2b,0x08,0xbf,0x11,0x4b,0x9d,0x46,0xa3,0xf5, +0x80,0x3a,0x00,0x21,0x8b,0x46,0x0f,0x46,0x11,0x48,0x12,0x4a,0x12,0x1a,0x00,0xf0, +0x79,0xf8,0x0d,0x4b,0x00,0x2b,0x00,0xd0,0x98,0x47,0x0c,0x4b,0x00,0x2b,0x00,0xd0, +0x98,0x47,0x00,0x20,0x00,0x21,0x04,0x00,0x0d,0x00,0x0b,0x48,0x00,0xf0,0x16,0xf8, +0x00,0xf0,0x40,0xf8,0x20,0x00,0x29,0x00,0x00,0xf0,0xf0,0xfa,0x00,0xf0,0x14,0xf8, +0x00,0x00,0x08,0x00,0x70,0x13,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0c,0x0f,0x00,0x01,0x28,0x0f,0x00,0x01,0xc9,0x02,0x00,0x01,0x01,0x46,0x00,0x20, +0x02,0x46,0x03,0x46,0x00,0xf0,0x9c,0xb8,0x08,0xb5,0x00,0x21,0x04,0x46,0x00,0xf0, +0xf3,0xf8,0x04,0x4b,0x18,0x68,0xc3,0x6b,0x03,0xb1,0x98,0x47,0x20,0x46,0x00,0xf0, +0x55,0xf9,0x00,0xbf,0xcc,0x0a,0x00,0x01,0x38,0xb5,0x08,0x4b,0x08,0x4d,0xed,0x1a, +0xac,0x10,0x18,0xbf,0xed,0x18,0x05,0xd0,0x01,0x3c,0x55,0xf8,0x04,0x3d,0x98,0x47, +0x00,0x2c,0xf9,0xd1,0xbd,0xe8,0x38,0x40,0x00,0xf0,0xe6,0xbb,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x70,0xb5,0x0f,0x4e,0x0f,0x4d,0x76,0x1b,0xb6,0x10,0x18,0xbf, +0x00,0x24,0x05,0xd0,0x01,0x34,0x55,0xf8,0x04,0x3b,0x98,0x47,0xa6,0x42,0xf9,0xd1, +0x0a,0x4e,0x0b,0x4d,0x76,0x1b,0x00,0xf0,0xc9,0xfb,0xb6,0x10,0x18,0xbf,0x00,0x24, +0x06,0xd0,0x01,0x34,0x55,0xf8,0x04,0x3b,0x98,0x47,0xa6,0x42,0xf9,0xd1,0x70,0xbd, +0x70,0xbd,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x0a,0x00,0x01, +0xa4,0x0a,0x00,0x01,0x70,0xb4,0x84,0x07,0x46,0xd0,0x54,0x1e,0x00,0x2a,0x41,0xd0, +0xcd,0xb2,0x03,0x46,0x02,0xe0,0x62,0x1e,0xe4,0xb3,0x14,0x46,0x03,0xf8,0x01,0x5b, +0x9a,0x07,0xf8,0xd1,0x03,0x2c,0x2e,0xd9,0xcd,0xb2,0x45,0xea,0x05,0x25,0x0f,0x2c, +0x45,0xea,0x05,0x45,0x19,0xd9,0x03,0xf1,0x10,0x02,0x26,0x46,0x10,0x3e,0x0f,0x2e, +0x42,0xf8,0x10,0x5c,0x42,0xf8,0x0c,0x5c,0x42,0xf8,0x08,0x5c,0x42,0xf8,0x04,0x5c, +0x02,0xf1,0x10,0x02,0xf2,0xd8,0xa4,0xf1,0x10,0x02,0x22,0xf0,0x0f,0x02,0x04,0xf0, +0x0f,0x04,0x10,0x32,0x03,0x2c,0x13,0x44,0x0d,0xd9,0x1e,0x46,0x22,0x46,0x04,0x3a, +0x03,0x2a,0x46,0xf8,0x04,0x5b,0xfa,0xd8,0x22,0x1f,0x22,0xf0,0x03,0x02,0x04,0x32, +0x13,0x44,0x04,0xf0,0x03,0x04,0x2c,0xb1,0xc9,0xb2,0x1c,0x44,0x03,0xf8,0x01,0x1b, +0xa3,0x42,0xfb,0xd1,0x70,0xbc,0x70,0x47,0x14,0x46,0x03,0x46,0xc2,0xe7,0x00,0xbf, +0x2d,0xe9,0xf0,0x47,0x25,0x4c,0x25,0x68,0xd5,0xf8,0x48,0x41,0x06,0x46,0x88,0x46, +0x92,0x46,0x99,0x46,0xcc,0xb3,0x60,0x68,0x1f,0x28,0x18,0xdc,0x43,0x1c,0x7e,0xb1, +0x04,0xeb,0x80,0x05,0x01,0x21,0xc5,0xf8,0x88,0xa0,0xd4,0xf8,0x88,0x71,0x01,0xfa, +0x00,0xf2,0x17,0x43,0x02,0x2e,0xc4,0xf8,0x88,0x71,0xc5,0xf8,0x08,0x91,0x1e,0xd0, +0x02,0x30,0x63,0x60,0x44,0xf8,0x20,0x80,0x00,0x20,0xbd,0xe8,0xf0,0x87,0x14,0x4b, +0x03,0xb3,0x4f,0xf4,0xc8,0x70,0xaf,0xf3,0x00,0x80,0x04,0x46,0xd0,0xb1,0xd5,0xf8, +0x48,0x31,0x00,0x27,0x80,0xe8,0x88,0x00,0xc5,0xf8,0x48,0x41,0x38,0x46,0x01,0x23, +0xc4,0xf8,0x88,0x71,0xc4,0xf8,0x8c,0x71,0x00,0x2e,0xe1,0xd0,0xd0,0xe7,0xd4,0xf8, +0x8c,0x11,0x0a,0x43,0xc4,0xf8,0x8c,0x21,0xda,0xe7,0x05,0xf5,0xa6,0x74,0xc5,0xf8, +0x48,0x41,0xc0,0xe7,0x4f,0xf0,0xff,0x30,0xbd,0xe8,0xf0,0x87,0xcc,0x0a,0x00,0x01, +0x00,0x00,0x00,0x00,0x02,0x4b,0x13,0xb1,0x02,0x48,0xff,0xf7,0x07,0xbf,0x70,0x47, +0x00,0x00,0x00,0x00,0xc9,0x02,0x00,0x01,0x2d,0xe9,0xf0,0x4f,0x31,0x4b,0x83,0xb0, +0x1b,0x68,0x00,0x93,0x03,0xf5,0xa4,0x73,0x81,0x46,0x0e,0x46,0x01,0x93,0x00,0x9b, +0xd3,0xf8,0x48,0x71,0x27,0xb3,0xdd,0xf8,0x04,0xa0,0x7c,0x68,0x65,0x1e,0x0e,0xd4, +0x01,0x34,0x07,0xeb,0x84,0x04,0x4f,0xf0,0x00,0x08,0xe6,0xb1,0xd4,0xf8,0x00,0x31, +0xb3,0x42,0x18,0xd0,0x01,0x3d,0x6b,0x1c,0xa4,0xf1,0x04,0x04,0xf5,0xd1,0x22,0x4b, +0x73,0xb1,0x7b,0x68,0x00,0x2b,0x36,0xd1,0x3b,0x68,0x00,0x2b,0x34,0xd0,0x38,0x46, +0xca,0xf8,0x00,0x30,0xaf,0xf3,0x00,0x80,0xda,0xf8,0x00,0x70,0x00,0x2f,0xdc,0xd1, +0x03,0xb0,0xbd,0xe8,0xf0,0x8f,0x7b,0x68,0x22,0x68,0x01,0x3b,0xab,0x42,0x0c,0xbf, +0x7d,0x60,0xc4,0xf8,0x00,0x80,0x00,0x2a,0xdc,0xd0,0xd7,0xf8,0x88,0x31,0xd7,0xf8, +0x04,0xb0,0x01,0x21,0xa9,0x40,0x19,0x42,0x08,0xd1,0x90,0x47,0x7b,0x68,0x5b,0x45, +0xbd,0xd1,0xda,0xf8,0x00,0x30,0xbb,0x42,0xcc,0xd0,0xb8,0xe7,0xd7,0xf8,0x8c,0x31, +0x19,0x42,0x04,0xd1,0x48,0x46,0xd4,0xf8,0x80,0x10,0x90,0x47,0xee,0xe7,0xd4,0xf8, +0x80,0x00,0x90,0x47,0xea,0xe7,0x3b,0x68,0xba,0x46,0x1f,0x46,0x00,0x2f,0xac,0xd1, +0xce,0xe7,0x00,0xbf,0xcc,0x0a,0x00,0x01,0x00,0x00,0x00,0x00,0xfe,0xe7,0x00,0xbf, +0xef,0xf3,0x10,0x80,0x72,0xb6,0x70,0x47,0xf8,0xb5,0x20,0x4e,0x20,0x4a,0x33,0x68, +0x20,0x4d,0x21,0x4f,0x21,0x4c,0x4f,0xf0,0x80,0x71,0x91,0x60,0x9b,0x6d,0x00,0x20, +0x98,0x47,0x33,0x68,0x28,0x60,0x9b,0x6d,0x01,0x20,0x98,0x47,0x3b,0x68,0x68,0x60, +0x5b,0x68,0x98,0x47,0x3b,0x68,0x28,0x73,0x1b,0x6a,0x98,0x47,0x63,0x68,0x3a,0x68, +0x68,0x73,0x03,0xf4,0xe0,0x23,0xab,0x60,0x93,0x69,0x00,0x20,0x98,0x47,0x33,0x68, +0x02,0x21,0x5b,0x6d,0x05,0x46,0x00,0x20,0x98,0x47,0x33,0x68,0x01,0x20,0x5b,0x6d, +0x02,0x21,0x98,0x47,0x46,0xf6,0x5a,0x13,0x23,0x60,0x63,0x68,0x23,0xf4,0xe0,0x23, +0x43,0xf4,0x80,0x23,0x00,0x22,0x63,0x60,0x22,0x60,0x09,0x4b,0x1d,0xb1,0x40,0xf6, +0xce,0x22,0x5a,0x60,0xf8,0xbd,0x07,0x4a,0x5a,0x60,0xf8,0xbd,0x1c,0x08,0x00,0x02, +0x00,0xed,0x00,0xe0,0x80,0x01,0x00,0x20,0x34,0x08,0x00,0x02,0x00,0x04,0x01,0x40, +0x50,0x01,0x00,0x20,0x00,0xad,0xde,0x00,0x2d,0xe9,0xf8,0x4f,0x4e,0x4c,0x25,0x69, +0xe7,0x68,0x00,0x2d,0x6d,0xd0,0xdf,0xf8,0x38,0xb1,0xdf,0xf8,0x38,0xa1,0xdf,0xf8, +0x38,0x91,0x4f,0xf0,0x00,0x08,0xdb,0xf8,0x00,0x30,0xb5,0xf5,0x80,0x5f,0x1b,0x69, +0x4f,0xf0,0xff,0x31,0x4f,0xf0,0x01,0x00,0x93,0xbf,0x2e,0x46,0xa5,0xf5,0x80,0x55, +0x4f,0xf4,0x80,0x56,0x00,0x25,0x98,0x47,0xdb,0xf8,0x00,0x30,0x4f,0xf0,0xff,0x31, +0x1b,0x69,0x02,0x20,0x98,0x47,0xdb,0xf8,0x00,0x30,0x03,0x20,0x1b,0x69,0x01,0x46, +0x98,0x47,0x23,0x6a,0x0b,0x2b,0x03,0xd1,0x60,0xe0,0xa3,0x69,0xd9,0x06,0x02,0xd4, +0x63,0x69,0xd8,0x06,0xf9,0xd5,0x63,0x69,0xda,0x06,0x3c,0xd5,0x63,0x69,0xdb,0xf8, +0x00,0x20,0x43,0xf0,0x01,0x03,0x63,0x61,0x93,0x6a,0x39,0x46,0x4f,0xf0,0x20,0x20, +0x32,0x46,0x98,0x47,0x99,0xf8,0x03,0x30,0x03,0xf0,0xef,0x03,0x89,0xf8,0x03,0x30, +0x63,0x69,0x23,0xf0,0x11,0x03,0x80,0x46,0x37,0x44,0x63,0x61,0xdb,0xf8,0x00,0x30, +0x4f,0xf0,0xff,0x31,0x5b,0x69,0x01,0x20,0x98,0x47,0xdb,0xf8,0x00,0x30,0x4f,0xf0, +0xff,0x31,0x5b,0x69,0x02,0x20,0x98,0x47,0xdb,0xf8,0x00,0x30,0x03,0x20,0x5b,0x69, +0x01,0x46,0x98,0x47,0xdb,0xf8,0x00,0x30,0x04,0x20,0x5b,0x69,0x03,0x21,0x98,0x47, +0xb8,0xf1,0x00,0x0f,0x29,0xd0,0x00,0x2d,0x9d,0xd1,0x17,0x4b,0x40,0xf6,0xce,0x22, +0x5a,0x60,0xbd,0xe8,0xf8,0x8f,0xa3,0x69,0xdb,0x06,0xd7,0xd5,0xa3,0x69,0xdb,0xf8, +0x00,0x20,0x12,0x48,0x43,0xf0,0x01,0x03,0xa3,0x61,0x93,0x6a,0x39,0x46,0x32,0x46, +0x98,0x47,0x9a,0xf8,0x02,0x30,0x03,0xf0,0xbf,0x03,0x8a,0xf8,0x02,0x30,0xa3,0x69, +0x23,0xf0,0x11,0x03,0x80,0x46,0x37,0x44,0xa3,0x61,0xbf,0xe7,0xdb,0xf8,0x00,0x30, +0x03,0x21,0x1b,0x69,0x04,0x20,0x98,0x47,0x9a,0xe7,0x03,0x4b,0x4d,0xf6,0xad,0x62, +0x5a,0x60,0xbd,0xe8,0xf8,0x8f,0x00,0xbf,0x50,0x01,0x00,0x20,0x00,0x30,0x00,0x20, +0x1c,0x08,0x00,0x02,0x20,0x4c,0x00,0x40,0x40,0x4c,0x00,0x40,0x13,0x4b,0xdb,0x69, +0xda,0x07,0x70,0xb5,0x14,0xd4,0x11,0x4c,0xe3,0x69,0x9b,0x07,0x00,0xd4,0x70,0xbd, +0x0f,0x4d,0x2b,0x68,0x03,0x20,0x1b,0x69,0x01,0x46,0x98,0x47,0x23,0x6a,0x0b,0x2b, +0xf5,0xd1,0x2b,0x68,0x04,0x20,0x1b,0x69,0x03,0x21,0xbd,0xe8,0x70,0x40,0x18,0x47, +0x07,0x4c,0x23,0x68,0x4f,0xf0,0xff,0x31,0x1b,0x69,0x01,0x20,0x98,0x47,0x23,0x68, +0x4f,0xf0,0xff,0x31,0x1b,0x69,0x02,0x20,0x98,0x47,0xdc,0xe7,0x50,0x01,0x00,0x20, +0x1c,0x08,0x00,0x02,0x2d,0xe9,0xf8,0x43,0x1e,0x4c,0x1f,0x4d,0x1f,0x4f,0x29,0x68, +0x3a,0x68,0xdf,0xf8,0x84,0x90,0x46,0xf6,0x5a,0x18,0xc4,0xf8,0x00,0x80,0x63,0x68, +0x23,0xf4,0xe0,0x23,0x00,0x26,0x43,0xf4,0x80,0x33,0x63,0x60,0x26,0x60,0x53,0x6d, +0x30,0x46,0x98,0x47,0x3b,0x68,0x69,0x68,0x5b,0x6d,0x01,0x20,0x98,0x47,0xd9,0xf8, +0x00,0x30,0x68,0x7b,0x9b,0x69,0x98,0x47,0xd9,0xf8,0x00,0x30,0x07,0x46,0x1b,0x68, +0x28,0x7b,0x98,0x47,0xc4,0xf8,0x00,0x80,0x63,0x68,0xaa,0x68,0x0c,0x49,0x23,0xf4, +0xe0,0x23,0x13,0x43,0x63,0x60,0x26,0x60,0x0a,0x4b,0x8e,0x60,0x28,0xb1,0x27,0xb1, +0x40,0xf6,0xce,0x22,0x5a,0x60,0xbd,0xe8,0xf8,0x83,0x4d,0xf6,0xad,0x62,0x5a,0x60, +0xbd,0xe8,0xf8,0x83,0x00,0x04,0x01,0x40,0x80,0x01,0x00,0x20,0x1c,0x08,0x00,0x02, +0x00,0xed,0x00,0xe0,0x50,0x01,0x00,0x20,0x34,0x08,0x00,0x02,0x8c,0x4b,0x8d,0x4c, +0x1b,0x68,0x8d,0x4d,0x1b,0x68,0x80,0xb5,0x98,0x47,0xff,0xf7,0x81,0xfe,0x27,0x46, +0x23,0x68,0x20,0x2b,0x00,0xf2,0xeb,0x80,0x01,0xa2,0x52,0xf8,0x23,0xf0,0x00,0xbf, +0x71,0x08,0x00,0x01,0xff,0x09,0x00,0x01,0xb9,0x09,0x00,0x01,0x4f,0x0a,0x00,0x01, +0x2f,0x09,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01, +0x21,0x09,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01, +0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01, +0x13,0x09,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01, +0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01, +0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01, +0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01, +0x05,0x09,0x00,0x01,0x01,0x23,0x63,0x60,0xff,0xf7,0x86,0xfe,0x00,0x23,0x23,0x60, +0xae,0xe7,0x01,0x23,0x63,0x60,0xff,0xf7,0x55,0xff,0x00,0x23,0x23,0x60,0xa7,0xe7, +0x01,0x23,0x63,0x60,0xff,0xf7,0x28,0xfe,0x00,0x23,0x23,0x60,0xa0,0xe7,0x2b,0x68, +0x01,0x20,0x60,0x60,0x1b,0x69,0x4f,0xf0,0xff,0x31,0x98,0x47,0x2b,0x68,0x4f,0xf0, +0xff,0x31,0x1b,0x69,0x02,0x20,0x98,0x47,0x2b,0x68,0x03,0x20,0x1b,0x69,0x01,0x46, +0x98,0x47,0x23,0x6a,0x0b,0x2b,0x00,0xf0,0x82,0x80,0x63,0x69,0xdb,0x06,0xfc,0xd5, +0x7b,0x69,0x28,0x68,0x43,0xf0,0x01,0x03,0x7b,0x61,0xf9,0x68,0x83,0x6a,0x3a,0x69, +0x4f,0xf0,0x20,0x20,0x98,0x47,0x7b,0x69,0x2a,0x68,0x23,0xf0,0x11,0x03,0x7b,0x61, +0x53,0x69,0x06,0x46,0x4f,0xf0,0xff,0x31,0x01,0x20,0x98,0x47,0x2b,0x68,0x4f,0xf0, +0xff,0x31,0x5b,0x69,0x02,0x20,0x98,0x47,0x2b,0x68,0x03,0x20,0x5b,0x69,0x01,0x46, +0x98,0x47,0x2b,0x68,0x04,0x20,0x5b,0x69,0x03,0x21,0x98,0x47,0x00,0x2e,0x52,0xd0, +0x40,0xf6,0xce,0x23,0x7b,0x60,0xb0,0xe7,0x2b,0x68,0x01,0x20,0x60,0x60,0x1b,0x69, +0x4f,0xf0,0xff,0x31,0x98,0x47,0x2b,0x68,0x4f,0xf0,0xff,0x31,0x1b,0x69,0x02,0x20, +0x98,0x47,0x2b,0x68,0x03,0x20,0x1b,0x69,0x01,0x46,0x98,0x47,0x23,0x6a,0x0b,0x2b, +0x43,0xd0,0x05,0x26,0x2b,0x68,0xe0,0x68,0x5b,0x6a,0x98,0x47,0x01,0x3e,0x00,0x28, +0x47,0xd1,0x00,0x2e,0xf6,0xd1,0x4d,0xf6,0xad,0x63,0x63,0x60,0x0e,0xe0,0x01,0x23, +0x63,0x60,0xff,0xf7,0xb3,0xfe,0x05,0x26,0x2b,0x68,0x1b,0x6a,0x98,0x47,0x01,0x3e, +0x00,0x28,0x30,0xd1,0x00,0x2e,0xf7,0xd1,0x20,0x4b,0x63,0x60,0x2b,0x68,0x4f,0xf0, +0xff,0x31,0x5b,0x69,0x01,0x20,0x98,0x47,0x2b,0x68,0x4f,0xf0,0xff,0x31,0x5b,0x69, +0x02,0x20,0x98,0x47,0x2b,0x68,0x03,0x20,0x5b,0x69,0x01,0x46,0x98,0x47,0x2b,0x68, +0x04,0x20,0x5b,0x69,0x03,0x21,0x98,0x47,0x00,0x23,0x23,0x60,0x10,0xe7,0x40,0xf6, +0xad,0x33,0x63,0x60,0x0c,0xe7,0x4d,0xf6,0xad,0x63,0x7b,0x60,0x5d,0xe7,0x2b,0x68, +0x03,0x21,0x1b,0x69,0x04,0x20,0x98,0x47,0x77,0xe7,0x2b,0x68,0x03,0x21,0x1b,0x69, +0x04,0x20,0x98,0x47,0xb5,0xe7,0x00,0x2e,0xce,0xd0,0x40,0xf6,0xce,0x23,0x63,0x60, +0xcc,0xe7,0x00,0x2e,0xb7,0xd0,0x40,0xf6,0xce,0x23,0x7b,0x60,0xc6,0xe7,0x00,0xbf, +0x64,0x08,0x00,0x02,0x50,0x01,0x00,0x20,0x1c,0x08,0x00,0x02,0xad,0xde,0xad,0xde, +0xfe,0xe7,0x00,0xbf,0xfd,0x01,0x00,0x01,0x85,0x04,0x00,0x01,0xf8,0xb5,0x00,0xbf, +0xf8,0xbc,0x08,0xbc,0x9e,0x46,0x70,0x47,0xf8,0xb5,0x00,0xbf,0xd5,0x01,0x00,0x01, +0xf8,0xbc,0x08,0xbc,0x9e,0x46,0x70,0x47,0x43,0x00,0x00,0x00,0x08,0x20,0x00,0x20, +0x64,0xf7,0xff,0x7f,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xf4,0x22,0x00,0x20,0x5c,0x23,0x00,0x20,0xc4,0x23,0x00,0x20, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xc8,0x0a,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0e,0x33,0xcd,0xab,0x34,0x12,0x6d,0xe6,0xec,0xde,0x05,0x00,0x0b,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x20,0x00,0x20, diff --git a/contrib/loaders/flash/msp432/msp432p411x.h b/contrib/loaders/flash/msp432/msp432p411x.h new file mode 100644 index 000000000..6482dd333 --- /dev/null +++ b/contrib/loaders/flash/msp432/msp432p411x.h @@ -0,0 +1,164 @@ +/****************************************************************************** +* +* Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432P411X_H +#define OPENOCD_LOADERS_FLASH_MSP432_MSP432P411X_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Available Peripherals */ +#define __MCU_HAS_FLCTL_A__ /* Module FLCTL_A is available */ +#define __MCU_HAS_SYSCTL_A__ /* Module SYSCTL_A is available */ + +/* Device and Peripheral Memory Map */ +#define FLASH_BASE ((uint32_t)0x00000000) /* Flash memory address */ +#define PERIPH_BASE ((uint32_t)0x40000000) /* Peripherals address */ +#define CS_BASE (PERIPH_BASE + 0x00010400) /* Address of CS regs. */ +#define PCM_BASE (PERIPH_BASE + 0x00010000) /* Address of PCM regs. */ +#define RTC_C_BASE (PERIPH_BASE + 0x00004400) /* Address of RTC_C regs */ +#define TLV_BASE ((uint32_t)0x00201000) /* Address of TLV regs. */ +#define WDT_A_BASE (PERIPH_BASE + 0x00004800) /* Address of WDT_A regs */ +#define BITBAND_PERI_BASE ((uint32_t)(0x42000000)) + +/* + * Peripherals with 8-bit or 16-bit register access allow only 8-bit or + * 16-bit bit band access, so cast to 8 bit always + */ +#define BITBAND_PERI(x, b) (*((volatile uint8_t *) (BITBAND_PERI_BASE + \ + (((uint32_t)(uint32_t *)&(x)) - PERIPH_BASE)*32 + (b)*4))) + +/* Register map for CLock Signal peripheral (CS) */ +struct cs { + volatile uint32_t KEY; /* Key Register */ + volatile uint32_t CTL0; /* Control 0 Register */ + volatile uint32_t CTL1; /* Control 1 Register */ + volatile uint32_t CTL2; /* Control 2 Register */ + volatile uint32_t CTL3; /* Control 3 Register */ +}; + +/* Register map for Power Control Module peripheral (PCM) */ +struct pcm { + volatile uint32_t CTL0; /* Control 0 Register */ + volatile uint32_t CTL1; /* Control 1 Register */ + volatile uint32_t IE; /* Interrupt Enable Register */ + volatile uint32_t IFG; /* Interrupt Flag Register */ + volatile uint32_t CLRIFG; /* Clear Interrupt Flag Register */ +}; + +/* Register map for Real-Time Clock peripheral (RTC_C) */ +struct rtc_c { + volatile uint16_t CTL0; /* RTCCTL0 Register */ + volatile uint16_t CTL13; /* RTCCTL13 Register */ + volatile uint16_t OCAL; /* RTCOCAL Register */ + volatile uint16_t TCMP; /* RTCTCMP Register */ + volatile uint16_t PS0CTL; /* RTC Prescale Timer 0 Control Register */ + volatile uint16_t PS1CTL; /* RTC Prescale Timer 1 Control Register */ + volatile uint16_t PS; /* Real-Time Clock Prescale Timer Register */ + volatile uint16_t IV; /* Real-Time Clock Interrupt Vector Register */ + volatile uint16_t TIM0; /* RTCTIM0 Register Hexadecimal Format */ + volatile uint16_t TIM1; /* Real-Time Clock Hour, Day of Week */ + volatile uint16_t DATE; /* RTCDATE - Hexadecimal Format */ + volatile uint16_t YEAR; /* RTCYEAR Register - Hexadecimal Format */ + volatile uint16_t AMINHR; /* RTCMINHR - Hexadecimal Format */ + volatile uint16_t ADOWDAY; /* RTCADOWDAY - Hexadecimal Format */ + volatile uint16_t BIN2BCD; /* Binary-to-BCD Conversion Register */ + volatile uint16_t BCD2BIN; /* BCD-to-Binary Conversion Register */ +}; + +/* Register map for Watchdog Timer peripheral (WDT_A) */ +struct wdt_a { + uint16_t RESERVED0[6]; + volatile uint16_t CTL; /* Watchdog Timer Control Register */ +}; + +/* Peripheral Declarations */ +#define CS ((struct cs *) CS_BASE) +#define PCM ((struct pcm *) PCM_BASE) +#define RTC_C ((struct rtc_c *) RTC_C_BASE) +#define WDT_A ((struct wdt_a *) WDT_A_BASE) + +/* Peripheral Register Bit Definitions */ + +/* DCORSEL Bit Mask */ +#define CS_CTL0_DCORSEL_MASK ((uint32_t)0x00070000) +/* Nominal DCO Frequency Range (MHz): 2 to 4 */ +#define CS_CTL0_DCORSEL_1 ((uint32_t)0x00010000) +/* Nominal DCO Frequency Range (MHz): 16 to 32 */ +#define CS_CTL0_DCORSEL_4 ((uint32_t)0x00040000) +/* CS control key value */ +#define CS_KEY_VAL ((uint32_t)0x0000695A) + +/* AMR Bit Mask */ +#define PCM_CTL0_AMR_MASK ((uint32_t)0x0000000F) +/* LPMR Bit Mask */ +#define PCM_CTL0_LPMR_MASK ((uint32_t)0x000000F0) +/* LPM3.5. Core voltage setting 0. */ +#define PCM_CTL0_LPMR_10 ((uint32_t)0x000000A0) +/* LPM4.5 */ +#define PCM_CTL0_LPMR_12 ((uint32_t)0x000000C0) +/* CPM Bit Offset */ +#define PCM_CTL0_CPM_OFS (8) +/* CPM Bit Mask */ +#define PCM_CTL0_CPM_MASK ((uint32_t)0x00003F00) +/* PCMKEY Bit Mask */ +#define PCM_CTL0_KEY_MASK ((uint32_t)0xFFFF0000) +/* PMR_BUSY Bit Offset */ +#define PCM_CTL1_PMR_BUSY_OFS (8) + +/* RTCKEY Bit Offset */ +#define RTC_C_CTL0_KEY_OFS (8) +/* RTCKEY Bit Mask */ +#define RTC_C_CTL0_KEY_MASK ((uint16_t)0xFF00) +/* RTCHOLD Bit Offset */ +#define RTC_C_CTL13_HOLD_OFS (6) +/* RTC_C Key Value for RTC_C write access */ +#define RTC_C_KEY ((uint16_t)0xA500) + +/* Watchdog timer hold */ +#define WDT_A_CTL_HOLD ((uint16_t)0x0080) +/* WDT Key Value for WDT write access */ +#define WDT_A_CTL_PW ((uint16_t)0x5A00) + +/* Address of BSL API table */ +#define BSL_API_TABLE_ADDR ((uint32_t)0x00202000) + +#ifdef __cplusplus +} +#endif + +#endif /* OPENOCD_LOADERS_FLASH_MSP432_MSP432P411X_H */ diff --git a/contrib/loaders/flash/msp432/msp432p411x/msp432p411x.lds b/contrib/loaders/flash/msp432/msp432p411x/msp432p411x.lds new file mode 100644 index 000000000..7798b304a --- /dev/null +++ b/contrib/loaders/flash/msp432/msp432p411x/msp432p411x.lds @@ -0,0 +1,151 @@ +/****************************************************************************** +* +* Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +MEMORY { + MAIN_FLASH (RX) : ORIGIN = 0x00000000, LENGTH = 0x00200000 + INFO_FLASH (RX) : ORIGIN = 0x00200000, LENGTH = 0x00008000 + SRAM_CODE_0(RWX): ORIGIN = 0x01000000, LENGTH = 0x00000110 + SRAM_CODE_1(RWX): ORIGIN = 0x01000110, LENGTH = 0x00000030 + SRAM_CODE_2(RWX): ORIGIN = 0x01000150, LENGTH = 0x00000040 + SRAM_CODE_3(RWX): ORIGIN = 0x01000190, LENGTH = 0x00001E70 + SRAM_CODE_4(RWX): ORIGIN = 0x01002000, LENGTH = 0x00000200 + SRAM_DATA (RW) : ORIGIN = 0x20002000, LENGTH = 0x00001000 +} + +REGION_ALIAS("REGION_INTVECT", SRAM_CODE_0); +REGION_ALIAS("REGION_RESET", SRAM_CODE_1); +REGION_ALIAS("REGION_DESCRIPTOR", SRAM_CODE_2); +REGION_ALIAS("REGION_TEXT", SRAM_CODE_3); +REGION_ALIAS("REGION_BSS", SRAM_CODE_3); +REGION_ALIAS("REGION_DATA", SRAM_DATA); +REGION_ALIAS("REGION_STACK", SRAM_CODE_4); +REGION_ALIAS("REGION_HEAP", SRAM_DATA); +REGION_ALIAS("REGION_ARM_EXIDX", SRAM_CODE_3); +REGION_ALIAS("REGION_ARM_EXTAB", SRAM_CODE_3); + +SECTIONS { + /* section for the interrupt vector area */ + .intvecs : { + KEEP (*(.intvecs)) + } > REGION_INTVECT + + PROVIDE (_vtable_base_address = + DEFINED(_vtable_base_address) ? _vtable_base_address : 0x20000000); + + .vtable (_vtable_base_address) : AT (_vtable_base_address) { + KEEP (*(.vtable)) + } > REGION_DATA + + .descriptor :{ + FILL(0x00000000); + . = ORIGIN(REGION_DESCRIPTOR) + LENGTH(REGION_DESCRIPTOR) - 1; + BYTE(0x00); + __ROM_AT = .; + } > REGION_DESCRIPTOR + + .reset : { + KEEP(*(.reset)) + } > REGION_RESET AT> REGION_RESET + + .text : { + CREATE_OBJECT_SYMBOLS + KEEP (*(.text)) + *(.text.*) + . = ALIGN(0x4); + KEEP (*(.ctors)) + . = ALIGN(0x4); + KEEP (*(.dtors)) + . = ALIGN(0x4); + __init_array_start = .; + KEEP (*(.init_array*)) + __init_array_end = .; + KEEP (*(.init)) + KEEP (*(.fini*)) + } > REGION_TEXT AT> REGION_TEXT + + .rodata : { + *(.rodata) + *(.rodata.*) + } > REGION_TEXT AT> REGION_TEXT + + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > REGION_ARM_EXIDX AT> REGION_ARM_EXIDX + + .ARM.extab : { + KEEP (*(.ARM.extab* .gnu.linkonce.armextab.*)) + } > REGION_ARM_EXTAB AT> REGION_ARM_EXTAB + + __etext = .; + + .data : { + __data_load__ = LOADADDR (.data); + __data_start__ = .; + KEEP (*(.data)) + KEEP (*(.data*)) + . = ALIGN (4); + __data_end__ = .; + } > REGION_DATA AT> REGION_TEXT + + .bss : { + __bss_start__ = .; + *(.shbss) + KEEP (*(.bss)) + *(.bss.*) + *(COMMON) + . = ALIGN (4); + __bss_end__ = .; + } > REGION_BSS AT> REGION_BSS + + .heap : { + __heap_start__ = .; + end = __heap_start__; + _end = end; + __end = end; + KEEP (*(.heap)) + __heap_end__ = .; + __HeapLimit = __heap_end__; + } > REGION_HEAP AT> REGION_HEAP + + .stack (NOLOAD) : ALIGN(0x8) { + _stack = .; + KEEP(*(.stack)) + } > REGION_STACK AT> REGION_STACK + + __stack_top = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK); + PROVIDE(__stack = __stack_top); +} + diff --git a/contrib/loaders/flash/msp432/msp432p411x_algo.inc b/contrib/loaders/flash/msp432/msp432p411x_algo.inc new file mode 100644 index 000000000..da41bb734 --- /dev/null +++ b/contrib/loaders/flash/msp432/msp432p411x_algo.inc @@ -0,0 +1,361 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x00,0x22,0x00,0x01,0x11,0x01,0x00,0x01,0x0d,0x12,0x00,0x01,0x0d,0x12,0x00,0x01, +0x0d,0x12,0x00,0x01,0x0d,0x12,0x00,0x01,0x0d,0x12,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x12,0x00,0x01, +0x0d,0x12,0x00,0x01,0x00,0x00,0x00,0x00,0x0d,0x12,0x00,0x01,0x0d,0x12,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x41,0xf2,0x00,0x70,0xc0,0xf2,0x00,0x10,0x85,0x46,0x05,0x48,0x05,0x49,0x4f,0xf0, +0x00,0x02,0x88,0x42,0xb8,0xbf,0x40,0xf8,0x04,0x2b,0xfa,0xdb,0x00,0xf0,0xaa,0xbf, +0x78,0x16,0x00,0x01,0x94,0x16,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x04,0x4b,0x05,0x48,0x1b,0x1a,0x06,0x2b,0x02,0xd9,0x04,0x4b,0x03,0xb1,0x18,0x47, +0x70,0x47,0x00,0xbf,0x37,0x24,0x00,0x20,0x34,0x24,0x00,0x20,0x00,0x00,0x00,0x00, +0x05,0x49,0x06,0x48,0x09,0x1a,0x89,0x10,0x01,0xeb,0xd1,0x71,0x49,0x10,0x02,0xd0, +0x03,0x4b,0x03,0xb1,0x18,0x47,0x70,0x47,0x34,0x24,0x00,0x20,0x34,0x24,0x00,0x20, +0x00,0x00,0x00,0x00,0x10,0xb5,0x06,0x4c,0x23,0x78,0x43,0xb9,0xff,0xf7,0xd8,0xff, +0x04,0x4b,0x13,0xb1,0x04,0x48,0xaf,0xf3,0x00,0x80,0x01,0x23,0x23,0x70,0x10,0xbd, +0x78,0x16,0x00,0x01,0x00,0x00,0x00,0x00,0x3c,0x12,0x00,0x01,0x08,0xb5,0x08,0x4b, +0x1b,0xb1,0x08,0x48,0x08,0x49,0xaf,0xf3,0x00,0x80,0x08,0x48,0x03,0x68,0x13,0xb9, +0xbd,0xe8,0x08,0x40,0xcc,0xe7,0x06,0x4b,0x00,0x2b,0xf9,0xd0,0x98,0x47,0xf7,0xe7, +0x00,0x00,0x00,0x00,0x3c,0x12,0x00,0x01,0x7c,0x16,0x00,0x01,0x34,0x24,0x00,0x20, +0x00,0x00,0x00,0x00,0x13,0x4b,0x00,0x2b,0x08,0xbf,0x11,0x4b,0x9d,0x46,0xa3,0xf5, +0x80,0x3a,0x00,0x21,0x8b,0x46,0x0f,0x46,0x11,0x48,0x12,0x4a,0x12,0x1a,0x00,0xf0, +0x79,0xf8,0x0d,0x4b,0x00,0x2b,0x00,0xd0,0x98,0x47,0x0c,0x4b,0x00,0x2b,0x00,0xd0, +0x98,0x47,0x00,0x20,0x00,0x21,0x04,0x00,0x0d,0x00,0x0b,0x48,0x00,0xf0,0x16,0xf8, +0x00,0xf0,0x40,0xf8,0x20,0x00,0x29,0x00,0x00,0xf0,0x04,0xff,0x00,0xf0,0x14,0xf8, +0x00,0x00,0x08,0x00,0x00,0x22,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x78,0x16,0x00,0x01,0x94,0x16,0x00,0x01,0xc9,0x02,0x00,0x01,0x01,0x46,0x00,0x20, +0x02,0x46,0x03,0x46,0x00,0xf0,0x9c,0xb8,0x08,0xb5,0x00,0x21,0x04,0x46,0x00,0xf0, +0xf3,0xf8,0x04,0x4b,0x18,0x68,0xc3,0x6b,0x03,0xb1,0x98,0x47,0x20,0x46,0x00,0xf0, +0x55,0xf9,0x00,0xbf,0x38,0x12,0x00,0x01,0x38,0xb5,0x08,0x4b,0x08,0x4d,0xed,0x1a, +0xac,0x10,0x18,0xbf,0xed,0x18,0x05,0xd0,0x01,0x3c,0x55,0xf8,0x04,0x3d,0x98,0x47, +0x00,0x2c,0xf9,0xd1,0xbd,0xe8,0x38,0x40,0x00,0xf0,0x9c,0xbf,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x70,0xb5,0x0f,0x4e,0x0f,0x4d,0x76,0x1b,0xb6,0x10,0x18,0xbf, +0x00,0x24,0x05,0xd0,0x01,0x34,0x55,0xf8,0x04,0x3b,0x98,0x47,0xa6,0x42,0xf9,0xd1, +0x0a,0x4e,0x0b,0x4d,0x76,0x1b,0x00,0xf0,0x7f,0xff,0xb6,0x10,0x18,0xbf,0x00,0x24, +0x06,0xd0,0x01,0x34,0x55,0xf8,0x04,0x3b,0x98,0x47,0xa6,0x42,0xf9,0xd1,0x70,0xbd, +0x70,0xbd,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x12,0x00,0x01, +0x10,0x12,0x00,0x01,0x70,0xb4,0x84,0x07,0x46,0xd0,0x54,0x1e,0x00,0x2a,0x41,0xd0, +0xcd,0xb2,0x03,0x46,0x02,0xe0,0x62,0x1e,0xe4,0xb3,0x14,0x46,0x03,0xf8,0x01,0x5b, +0x9a,0x07,0xf8,0xd1,0x03,0x2c,0x2e,0xd9,0xcd,0xb2,0x45,0xea,0x05,0x25,0x0f,0x2c, +0x45,0xea,0x05,0x45,0x19,0xd9,0x03,0xf1,0x10,0x02,0x26,0x46,0x10,0x3e,0x0f,0x2e, +0x42,0xf8,0x10,0x5c,0x42,0xf8,0x0c,0x5c,0x42,0xf8,0x08,0x5c,0x42,0xf8,0x04,0x5c, +0x02,0xf1,0x10,0x02,0xf2,0xd8,0xa4,0xf1,0x10,0x02,0x22,0xf0,0x0f,0x02,0x04,0xf0, +0x0f,0x04,0x10,0x32,0x03,0x2c,0x13,0x44,0x0d,0xd9,0x1e,0x46,0x22,0x46,0x04,0x3a, +0x03,0x2a,0x46,0xf8,0x04,0x5b,0xfa,0xd8,0x22,0x1f,0x22,0xf0,0x03,0x02,0x04,0x32, +0x13,0x44,0x04,0xf0,0x03,0x04,0x2c,0xb1,0xc9,0xb2,0x1c,0x44,0x03,0xf8,0x01,0x1b, +0xa3,0x42,0xfb,0xd1,0x70,0xbc,0x70,0x47,0x14,0x46,0x03,0x46,0xc2,0xe7,0x00,0xbf, +0x2d,0xe9,0xf0,0x47,0x25,0x4c,0x25,0x68,0xd5,0xf8,0x48,0x41,0x06,0x46,0x88,0x46, +0x92,0x46,0x99,0x46,0xcc,0xb3,0x60,0x68,0x1f,0x28,0x18,0xdc,0x43,0x1c,0x7e,0xb1, +0x04,0xeb,0x80,0x05,0x01,0x21,0xc5,0xf8,0x88,0xa0,0xd4,0xf8,0x88,0x71,0x01,0xfa, +0x00,0xf2,0x17,0x43,0x02,0x2e,0xc4,0xf8,0x88,0x71,0xc5,0xf8,0x08,0x91,0x1e,0xd0, +0x02,0x30,0x63,0x60,0x44,0xf8,0x20,0x80,0x00,0x20,0xbd,0xe8,0xf0,0x87,0x14,0x4b, +0x03,0xb3,0x4f,0xf4,0xc8,0x70,0xaf,0xf3,0x00,0x80,0x04,0x46,0xd0,0xb1,0xd5,0xf8, +0x48,0x31,0x00,0x27,0x80,0xe8,0x88,0x00,0xc5,0xf8,0x48,0x41,0x38,0x46,0x01,0x23, +0xc4,0xf8,0x88,0x71,0xc4,0xf8,0x8c,0x71,0x00,0x2e,0xe1,0xd0,0xd0,0xe7,0xd4,0xf8, +0x8c,0x11,0x0a,0x43,0xc4,0xf8,0x8c,0x21,0xda,0xe7,0x05,0xf5,0xa6,0x74,0xc5,0xf8, +0x48,0x41,0xc0,0xe7,0x4f,0xf0,0xff,0x30,0xbd,0xe8,0xf0,0x87,0x38,0x12,0x00,0x01, +0x00,0x00,0x00,0x00,0x02,0x4b,0x13,0xb1,0x02,0x48,0xff,0xf7,0x07,0xbf,0x70,0x47, +0x00,0x00,0x00,0x00,0xc9,0x02,0x00,0x01,0x2d,0xe9,0xf0,0x4f,0x31,0x4b,0x83,0xb0, +0x1b,0x68,0x00,0x93,0x03,0xf5,0xa4,0x73,0x81,0x46,0x0e,0x46,0x01,0x93,0x00,0x9b, +0xd3,0xf8,0x48,0x71,0x27,0xb3,0xdd,0xf8,0x04,0xa0,0x7c,0x68,0x65,0x1e,0x0e,0xd4, +0x01,0x34,0x07,0xeb,0x84,0x04,0x4f,0xf0,0x00,0x08,0xe6,0xb1,0xd4,0xf8,0x00,0x31, +0xb3,0x42,0x18,0xd0,0x01,0x3d,0x6b,0x1c,0xa4,0xf1,0x04,0x04,0xf5,0xd1,0x22,0x4b, +0x73,0xb1,0x7b,0x68,0x00,0x2b,0x36,0xd1,0x3b,0x68,0x00,0x2b,0x34,0xd0,0x38,0x46, +0xca,0xf8,0x00,0x30,0xaf,0xf3,0x00,0x80,0xda,0xf8,0x00,0x70,0x00,0x2f,0xdc,0xd1, +0x03,0xb0,0xbd,0xe8,0xf0,0x8f,0x7b,0x68,0x22,0x68,0x01,0x3b,0xab,0x42,0x0c,0xbf, +0x7d,0x60,0xc4,0xf8,0x00,0x80,0x00,0x2a,0xdc,0xd0,0xd7,0xf8,0x88,0x31,0xd7,0xf8, +0x04,0xb0,0x01,0x21,0xa9,0x40,0x19,0x42,0x08,0xd1,0x90,0x47,0x7b,0x68,0x5b,0x45, +0xbd,0xd1,0xda,0xf8,0x00,0x30,0xbb,0x42,0xcc,0xd0,0xb8,0xe7,0xd7,0xf8,0x8c,0x31, +0x19,0x42,0x04,0xd1,0x48,0x46,0xd4,0xf8,0x80,0x10,0x90,0x47,0xee,0xe7,0xd4,0xf8, +0x80,0x00,0x90,0x47,0xea,0xe7,0x3b,0x68,0xba,0x46,0x1f,0x46,0x00,0x2f,0xac,0xd1, +0xce,0xe7,0x00,0xbf,0x38,0x12,0x00,0x01,0x00,0x00,0x00,0x00,0xfe,0xe7,0x00,0xbf, +0x4f,0x4a,0x13,0x68,0xc3,0xf3,0x05,0x23,0x04,0x3b,0xdb,0xb2,0x15,0x2b,0x70,0xb4, +0x00,0xf2,0x8c,0x80,0x01,0x22,0x02,0xfa,0x03,0xf3,0x13,0xf0,0x30,0x1f,0x61,0xd0, +0x02,0x23,0x98,0x42,0x31,0xd0,0x46,0x4b,0x1b,0x68,0xc3,0xf3,0x05,0x23,0x44,0x4c, +0x44,0x49,0x01,0x25,0x22,0x68,0x09,0x2b,0x10,0xd8,0xdf,0xe8,0x03,0xf0,0x05,0x35, +0x0f,0x0f,0x45,0x29,0x0f,0x0f,0x45,0x29,0x01,0x28,0x63,0xd0,0x02,0x28,0x73,0xd1, +0x4f,0xf6,0xf0,0x76,0x3c,0x4b,0x16,0x40,0x33,0x43,0x23,0x60,0x0b,0x78,0x03,0xf0, +0xff,0x02,0x00,0x2b,0xfa,0xd1,0x23,0x68,0xc3,0xf3,0x05,0x23,0x04,0x3b,0xdb,0xb2, +0x15,0x2b,0x05,0xd8,0x05,0xfa,0x03,0xf3,0x13,0xf0,0x30,0x1f,0x38,0xd0,0x02,0x22, +0x23,0x68,0x90,0x42,0xc3,0xf3,0x05,0x23,0xd4,0xd1,0x01,0x20,0x70,0xbc,0x70,0x47, +0x4f,0xf6,0xf0,0x76,0x2d,0x4b,0x16,0x40,0x33,0x43,0x23,0x60,0x0b,0x78,0x03,0xf0, +0xff,0x02,0x00,0x2b,0xda,0xd1,0xde,0xe7,0x01,0x28,0x27,0xd0,0x02,0x28,0x43,0xd1, +0x4f,0xf6,0xf0,0x76,0x26,0x4b,0x16,0x40,0x33,0x43,0x23,0x60,0x0b,0x78,0x03,0xf0, +0xff,0x02,0x00,0x2b,0xca,0xd1,0xce,0xe7,0x4f,0xf6,0xf0,0x73,0x13,0x40,0x43,0xf0, +0xd2,0x43,0x43,0xf4,0xb4,0x03,0x23,0x60,0x0b,0x78,0x03,0xf0,0xff,0x02,0x00,0x2b, +0xbc,0xd1,0xc0,0xe7,0x13,0xf0,0x03,0x1f,0x14,0xbf,0x13,0x46,0x00,0x23,0x98,0xe7, +0x13,0xf0,0x03,0x1f,0x14,0xbf,0x01,0x22,0x00,0x22,0xc1,0xe7,0x4f,0xf6,0xf0,0x76, +0x14,0x4b,0x16,0x40,0x33,0x43,0x23,0x60,0x0b,0x78,0x03,0xf0,0xff,0x02,0x00,0x2b, +0xa4,0xd1,0xa8,0xe7,0x4f,0xf6,0xf0,0x76,0x0f,0x4b,0x16,0x40,0x33,0x43,0x23,0x60, +0x0b,0x78,0x03,0xf0,0xff,0x02,0x00,0x2b,0x98,0xd1,0x9c,0xe7,0x00,0x28,0xac,0xd0, +0x13,0x68,0xc3,0xf3,0x05,0x23,0x7a,0xe7,0x00,0x20,0x70,0xbc,0x70,0x47,0x00,0xbf, +0x00,0x00,0x01,0x40,0xa0,0x00,0x20,0x42,0x08,0x00,0x5a,0x69,0x01,0x00,0x5a,0x69, +0x09,0x00,0x5a,0x69,0x05,0x00,0x5a,0x69,0x04,0x00,0x5a,0x69,0x4a,0x4b,0x1b,0x68, +0xc3,0xf3,0x05,0x23,0x04,0x3b,0xdb,0xb2,0x15,0x2b,0xf0,0xb4,0x7e,0xd8,0x01,0x22, +0x02,0xfa,0x03,0xf3,0x13,0xf0,0x30,0x1f,0x5f,0xd0,0x02,0x26,0x42,0x4b,0x1b,0x68, +0xc3,0xf3,0x05,0x23,0x01,0x3b,0xdb,0xb2,0x1f,0x2b,0x69,0xd8,0x01,0x22,0x02,0xfa, +0x03,0xf3,0x03,0xf0,0x11,0x31,0x21,0xf0,0x10,0x21,0x00,0x29,0x68,0xd1,0x00,0x2b, +0xb4,0xbf,0x02,0x23,0x00,0x23,0x98,0x42,0x5d,0xd0,0x37,0x4c,0x37,0x49,0x01,0x25, +0x22,0x68,0x23,0x68,0xc3,0xf3,0x05,0x23,0x09,0x2b,0x0e,0xd8,0x05,0xfa,0x03,0xf3, +0x13,0xf4,0x89,0x7f,0x41,0xd1,0x40,0xf2,0x21,0x27,0x1f,0x40,0x2f,0xb1,0x4f,0xf6, +0xf0,0x77,0x2f,0x4b,0x17,0x40,0x3b,0x43,0x23,0x60,0x0b,0x78,0x03,0xf0,0xff,0x02, +0x00,0x2b,0xfa,0xd1,0x23,0x68,0xc3,0xf3,0x05,0x23,0x01,0x3b,0xdb,0xb2,0x1f,0x2b, +0x29,0xd8,0x05,0xfa,0x03,0xf3,0x03,0xf0,0x11,0x37,0x27,0xf0,0x10,0x27,0x6f,0xbb, +0x00,0x2b,0xb4,0xbf,0x02,0x23,0x00,0x23,0x98,0x42,0xd1,0xd1,0x1e,0x4b,0x1b,0x68, +0xc3,0xf3,0x05,0x23,0x04,0x3b,0xdb,0xb2,0x15,0x2b,0x06,0xd8,0x01,0x22,0x02,0xfa, +0x03,0xf3,0x13,0xf0,0x30,0x1f,0x25,0xd0,0x02,0x22,0x96,0x42,0x1b,0xd0,0x01,0x2e, +0x25,0xd0,0x02,0x20,0xf0,0xbc,0xff,0xf7,0xe3,0xbe,0x13,0xf0,0x03,0x1f,0x14,0xbf, +0x16,0x46,0x00,0x26,0x9a,0xe7,0x13,0x46,0xde,0xe7,0x4f,0xf6,0xf0,0x73,0x13,0x40, +0x43,0xf0,0xd2,0x43,0x43,0xf4,0xb4,0x03,0x23,0x60,0xbe,0xe7,0x01,0x23,0xd3,0xe7, +0x00,0x23,0x98,0x42,0xa1,0xd1,0x01,0x20,0xf0,0xbc,0x70,0x47,0x00,0x26,0x85,0xe7, +0x13,0x46,0x98,0xe7,0x13,0xf0,0x03,0x1f,0x08,0xbf,0x00,0x22,0xd5,0xe7,0x30,0x46, +0xf0,0xbc,0xff,0xf7,0xbd,0xbe,0x00,0xbf,0x00,0x00,0x01,0x40,0xa0,0x00,0x20,0x42, +0x01,0x00,0x5a,0x69,0xef,0xf3,0x10,0x80,0x72,0xb6,0x70,0x47,0x30,0xbf,0x70,0x47, +0x04,0x4a,0x08,0xb5,0x13,0x69,0x23,0xf0,0x04,0x03,0x13,0x61,0xff,0xf7,0xf6,0xff, +0x01,0x20,0x08,0xbd,0x00,0xed,0x00,0xe0,0xff,0xf7,0x50,0xbf,0x0b,0x4b,0x1b,0x68, +0xc3,0xf3,0x05,0x23,0x01,0x3b,0xdb,0xb2,0x1f,0x2b,0x0c,0xd8,0x01,0x20,0x00,0xfa, +0x03,0xf2,0x02,0xf0,0x11,0x33,0x23,0xf0,0x10,0x23,0x2b,0xb9,0x00,0x2a,0xb4,0xbf, +0x02,0x20,0x00,0x20,0x70,0x47,0x00,0x20,0x70,0x47,0x00,0xbf,0x00,0x00,0x01,0x40, +0x2d,0xe9,0xf8,0x43,0x7b,0x4e,0x7c,0x4c,0xdf,0xf8,0x00,0x82,0x7b,0x4f,0x7c,0x4d, +0x33,0x78,0x00,0x2b,0x43,0xd1,0x23,0x68,0x03,0xf0,0xf0,0x03,0xa0,0x2b,0x3e,0xd0, +0x23,0x68,0x03,0xf0,0xf0,0x03,0xc0,0x2b,0x39,0xd0,0x23,0x68,0xc3,0xf3,0x05,0x23, +0x04,0x3b,0xdb,0xb2,0x15,0x2b,0x08,0xd8,0x01,0x22,0x02,0xfa,0x03,0xf3,0x13,0xf0, +0x30,0x10,0x02,0xd1,0x13,0xf0,0x03,0x1f,0x55,0xd1,0x23,0x68,0xc3,0xf3,0x05,0x29, +0x22,0x68,0x4f,0xf6,0x0f,0x73,0x13,0x40,0x43,0xf0,0xd2,0x43,0x43,0xf4,0xb4,0x03, +0x23,0x60,0x2b,0x69,0x43,0xf0,0x04,0x03,0x2b,0x61,0xff,0xf7,0x9f,0xff,0x2b,0x69, +0x23,0xf0,0x04,0x03,0x2b,0x61,0x23,0x68,0xc3,0xf3,0x05,0x23,0x4b,0x45,0x29,0xd0, +0xb9,0xf1,0x11,0x0f,0x6b,0xd0,0x0d,0xd9,0xb9,0xf1,0x19,0x0f,0x72,0xd0,0x4b,0xd9, +0xb9,0xf1,0x21,0x0f,0x35,0xd0,0x02,0xd8,0xb9,0xf1,0x20,0x0f,0xb8,0xd0,0x00,0x20, +0xbd,0xe8,0xf8,0x83,0xb9,0xf1,0x05,0x0f,0x6f,0xd0,0x16,0xd9,0xb9,0xf1,0x09,0x0f, +0x00,0xf0,0x8c,0x80,0xb9,0xf1,0x10,0x0f,0x00,0xf0,0x81,0x80,0xb9,0xf1,0x08,0x0f, +0xed,0xd1,0x00,0x20,0xff,0xf7,0xd2,0xfe,0x98,0xb1,0x02,0x20,0xbd,0xe8,0xf8,0x43, +0xff,0xf7,0x1e,0xbe,0x01,0x20,0xbd,0xe8,0xf8,0x83,0xb9,0xf1,0x01,0x0f,0x68,0xd0, +0x5d,0xd3,0xb9,0xf1,0x04,0x0f,0xda,0xd1,0x00,0x20,0xff,0xf7,0xbf,0xfe,0x00,0x28, +0x50,0xd1,0xbd,0xe8,0xf8,0x83,0x23,0x68,0xc3,0xf3,0x05,0x29,0xff,0xf7,0x08,0xfe, +0xa6,0xe7,0x40,0x49,0x40,0x4a,0x8b,0x89,0x03,0xf0,0x7f,0x03,0x43,0xf4,0xb5,0x43, +0x8b,0x81,0x13,0x88,0xdb,0xb2,0x43,0xf4,0x25,0x43,0x01,0x20,0x00,0x21,0x13,0x80, +0x88,0xf8,0x00,0x00,0x39,0x70,0x72,0xe7,0xb9,0xf1,0x15,0x0f,0x5b,0xd0,0xb9,0xf1, +0x18,0x0f,0x51,0xd0,0xb9,0xf1,0x14,0x0f,0xb1,0xd1,0x00,0x20,0xff,0xf7,0x96,0xfe, +0x00,0x28,0xac,0xd0,0x01,0x20,0xff,0xf7,0xe3,0xfd,0x00,0x28,0xa7,0xd0,0x29,0x4b, +0x1b,0x78,0x00,0x2b,0xa3,0xd1,0xbd,0xe8,0xf8,0x43,0xff,0xf7,0x29,0xbf,0x01,0x20, +0xff,0xf7,0x84,0xfe,0x00,0x28,0x9a,0xd0,0x00,0x20,0xff,0xf7,0xd1,0xfd,0x00,0x28, +0xed,0xd1,0x94,0xe7,0x01,0x20,0xff,0xf7,0x79,0xfe,0x00,0x28,0x8f,0xd0,0x02,0x20, +0xff,0xf7,0xc6,0xfd,0x00,0x28,0xe2,0xd1,0x89,0xe7,0x01,0x20,0xff,0xf7,0x6e,0xfe, +0x00,0x28,0xae,0xd0,0x01,0x20,0xbd,0xe8,0xf8,0x43,0xff,0xf7,0xb9,0xbd,0x00,0x20, +0xff,0xf7,0x64,0xfe,0x00,0x28,0xa4,0xd0,0x00,0x20,0xbd,0xe8,0xf8,0x43,0xff,0xf7, +0xaf,0xbd,0x48,0x46,0xff,0xf7,0x5a,0xfe,0x00,0x28,0x9a,0xd0,0xf4,0xe7,0x00,0x20, +0xff,0xf7,0x54,0xfe,0x00,0x28,0x3f,0xf4,0x6a,0xaf,0xcd,0xe7,0x01,0x20,0xff,0xf7, +0x4d,0xfe,0x00,0x28,0x8d,0xd0,0x78,0xe7,0x00,0x20,0xff,0xf7,0x47,0xfe,0x00,0x28, +0x3f,0xf4,0x5d,0xaf,0xcb,0xe7,0x01,0x20,0xff,0xf7,0x40,0xfe,0x00,0x28,0x3f,0xf4, +0x56,0xaf,0xa7,0xe7,0xa0,0x00,0x20,0x42,0x00,0x00,0x01,0x40,0x20,0x80,0x08,0x42, +0x00,0xed,0x00,0xe0,0x00,0x48,0x00,0x40,0x00,0x44,0x00,0x40,0x58,0x80,0x08,0x42, +0x6b,0x49,0x30,0xb5,0x0a,0x68,0xc2,0xf3,0x05,0x22,0x90,0x42,0x83,0xb0,0x21,0xd0, +0x11,0x28,0x00,0xf0,0xbf,0x80,0x20,0xd9,0x19,0x28,0x00,0xf0,0x95,0x80,0x3a,0xd9, +0x21,0x28,0x5d,0xd0,0x55,0xd9,0xa0,0x28,0x00,0xf0,0x86,0x80,0xc0,0x28,0x1e,0xd1, +0x60,0x4b,0x1b,0x78,0xdb,0xb9,0x60,0x48,0x5d,0x49,0x02,0x69,0x5f,0x4b,0x42,0xf0, +0x04,0x02,0x02,0x61,0x08,0x68,0x4f,0xf6,0x0f,0x72,0x02,0x40,0x13,0x43,0x0b,0x60, +0xff,0xf7,0xa4,0xfe,0x01,0x20,0x03,0xb0,0x30,0xbd,0x05,0x28,0x00,0xf0,0xa1,0x80, +0x08,0xd9,0x09,0x28,0x62,0xd0,0x10,0x28,0x55,0xd0,0x08,0x28,0x4c,0xd0,0x00,0x20, +0x03,0xb0,0x30,0xbd,0x01,0x28,0x00,0xf0,0x87,0x80,0x7d,0xd3,0x04,0x28,0xf6,0xd1, +0x00,0x20,0xff,0xf7,0xeb,0xfd,0x00,0x28,0xe5,0xd0,0x01,0x20,0x03,0xb0,0xbd,0xe8, +0x30,0x40,0xff,0xf7,0x35,0xbd,0x15,0x28,0x67,0xd0,0x18,0x28,0x5f,0xd0,0x14,0x28, +0xe5,0xd1,0x00,0x20,0xff,0xf7,0xda,0xfd,0x00,0x28,0xe0,0xd0,0x01,0x20,0xff,0xf7, +0x27,0xfd,0x00,0x28,0xdb,0xd0,0x3f,0x4b,0x1b,0x78,0x00,0x2b,0xd7,0xd1,0x3e,0x4a, +0x01,0x90,0x13,0x69,0x23,0xf0,0x04,0x03,0x13,0x61,0xff,0xf7,0x67,0xfe,0x01,0x98, +0xc1,0xe7,0x20,0x28,0xcb,0xd1,0x03,0xb0,0xbd,0xe8,0x30,0x40,0xff,0xf7,0x88,0xbe, +0x37,0x49,0x38,0x4a,0x8b,0x89,0x38,0x4c,0x38,0x48,0x03,0xf0,0x7f,0x03,0x43,0xf4, +0xb5,0x43,0x8b,0x81,0x13,0x88,0xdb,0xb2,0x43,0xf4,0x25,0x43,0x01,0x25,0x00,0x21, +0x13,0x80,0x25,0x70,0x01,0x70,0xe6,0xe7,0x00,0x20,0xff,0xf7,0xa7,0xfd,0x00,0x28, +0xa1,0xd0,0x02,0x20,0xba,0xe7,0x00,0x20,0xff,0xf7,0xa0,0xfd,0x00,0x28,0xa6,0xd0, +0x00,0x20,0xff,0xf7,0xed,0xfc,0x00,0x28,0xc5,0xd1,0xa0,0xe7,0x01,0x20,0xff,0xf7, +0x95,0xfd,0x00,0x28,0x8f,0xd0,0xec,0xe7,0x1e,0x4b,0x1b,0x78,0x00,0x2b,0x96,0xd1, +0x1d,0x48,0x23,0x4b,0x02,0x69,0x7a,0xe7,0x01,0x20,0xff,0xf7,0x87,0xfd,0x00,0x28, +0x8d,0xd0,0x02,0x20,0xff,0xf7,0xd4,0xfc,0x00,0x28,0xac,0xd1,0x87,0xe7,0x00,0x20, +0xff,0xf7,0x7c,0xfd,0x00,0x28,0x82,0xd0,0xf3,0xe7,0x01,0x20,0xff,0xf7,0x76,0xfd, +0x00,0x28,0x3f,0xf4,0x7c,0xaf,0x99,0xe7,0x00,0x20,0xff,0xf7,0x6f,0xfd,0x00,0x28, +0x3f,0xf4,0x69,0xaf,0x00,0x20,0x81,0xe7,0xff,0xf7,0x68,0xfd,0x00,0x28,0x3f,0xf4, +0x62,0xaf,0xf7,0xe7,0x01,0x20,0xff,0xf7,0x61,0xfd,0x00,0x28,0x3f,0xf4,0x67,0xaf, +0xbe,0xe7,0x01,0x20,0xff,0xf7,0x5a,0xfd,0x00,0x28,0x3f,0xf4,0x54,0xaf,0x6c,0xe7, +0x00,0x00,0x01,0x40,0xa0,0x00,0x20,0x42,0x00,0xed,0x00,0xe0,0xa0,0x00,0x5a,0x69, +0x00,0x48,0x00,0x40,0x00,0x44,0x00,0x40,0x58,0x80,0x08,0x42,0x20,0x80,0x08,0x42, +0xc0,0x00,0x5a,0x69,0x02,0x4b,0x18,0x68,0xc0,0xf3,0x05,0x20,0x70,0x47,0x00,0xbf, +0x00,0x00,0x01,0x40,0x70,0xb5,0x1e,0x4e,0x1e,0x4a,0x33,0x68,0x1e,0x4d,0x1f,0x4c, +0x4f,0xf0,0x80,0x71,0x91,0x60,0x9b,0x6d,0x00,0x20,0x98,0x47,0x33,0x68,0x28,0x60, +0x9b,0x6d,0x01,0x20,0x98,0x47,0x68,0x60,0xff,0xf7,0xd8,0xfd,0x28,0x73,0xff,0xf7, +0xe1,0xff,0x63,0x68,0x68,0x73,0x03,0xf4,0xe0,0x23,0xab,0x60,0x00,0x20,0xff,0xf7, +0xef,0xfe,0x33,0x68,0x02,0x21,0x5b,0x6d,0x05,0x46,0x00,0x20,0x98,0x47,0x33,0x68, +0x01,0x20,0x5b,0x6d,0x02,0x21,0x98,0x47,0x46,0xf6,0x5a,0x13,0x23,0x60,0x63,0x68, +0x23,0xf4,0xe0,0x23,0x43,0xf4,0x80,0x23,0x00,0x22,0x63,0x60,0x22,0x60,0x08,0x4b, +0x1d,0xb1,0x40,0xf6,0xce,0x22,0x5a,0x60,0x70,0xbd,0x06,0x4a,0x5a,0x60,0x70,0xbd, +0x6c,0x08,0x00,0x02,0x00,0xed,0x00,0xe0,0x80,0x01,0x00,0x20,0x00,0x04,0x01,0x40, +0x50,0x01,0x00,0x20,0x00,0xad,0xde,0x00,0x19,0x4b,0xdb,0x69,0xda,0x07,0x70,0xb5, +0x1d,0xd4,0x17,0x4c,0xe3,0x69,0x9b,0x07,0x00,0xd4,0x70,0xbd,0x15,0x4d,0x16,0x49, +0x2b,0x68,0x4f,0xf4,0x00,0x10,0x1b,0x69,0x98,0x47,0x23,0x6a,0x0b,0x2b,0x19,0xd0, +0x12,0x4b,0x10,0x4a,0x1b,0x68,0x12,0x68,0x9b,0x6c,0x14,0x69,0x98,0x47,0x10,0x49, +0x23,0x46,0x01,0x44,0xbd,0xe8,0x70,0x40,0x4f,0xf4,0x01,0x10,0x18,0x47,0x0b,0x4b, +0x08,0x4a,0x1b,0x68,0x12,0x68,0x5b,0x68,0x14,0x69,0x98,0x47,0x41,0x1e,0x00,0x20, +0xa0,0x47,0xd6,0xe7,0x2b,0x68,0x06,0x49,0x1b,0x69,0x06,0x48,0x98,0x47,0xdf,0xe7, +0x50,0x01,0x00,0x20,0x6c,0x08,0x00,0x02,0xff,0x0f,0x20,0x00,0x68,0x08,0x00,0x02, +0xff,0x3f,0x20,0x00,0x00,0x20,0x20,0x00,0x14,0x4b,0x70,0xb5,0x14,0x4c,0x1b,0x68, +0x22,0x68,0x5b,0x68,0x15,0x69,0x98,0x47,0x41,0x1e,0x00,0x20,0xa8,0x47,0x23,0x68, +0x10,0x49,0x1b,0x69,0x4f,0xf4,0x00,0x10,0x98,0x47,0x0f,0x4b,0x1b,0x6a,0x0b,0x2b, +0x0e,0xd0,0x0a,0x4b,0x0a,0x4a,0x1b,0x68,0x12,0x68,0x9b,0x6c,0x14,0x69,0x98,0x47, +0x0a,0x49,0x23,0x46,0x01,0x44,0xbd,0xe8,0x70,0x40,0x4f,0xf4,0x01,0x10,0x18,0x47, +0x23,0x68,0x06,0x49,0x1b,0x69,0x06,0x48,0x98,0x47,0xea,0xe7,0x68,0x08,0x00,0x02, +0x6c,0x08,0x00,0x02,0xff,0x0f,0x20,0x00,0x50,0x01,0x00,0x20,0xff,0x3f,0x20,0x00, +0x00,0x20,0x20,0x00,0x2d,0xe9,0xf0,0x41,0xff,0xf7,0xc6,0xff,0x2d,0x49,0x4b,0x69, +0x2c,0x4a,0xdb,0x06,0xfb,0xd5,0x53,0x69,0x43,0xf0,0x01,0x03,0x53,0x61,0xd4,0x68, +0x15,0x69,0xb4,0xf5,0x00,0x1f,0x03,0xd2,0x2b,0x19,0xb3,0xf5,0x00,0x1f,0x2d,0xd8, +0x25,0x4b,0x1b,0x68,0x21,0x46,0x2a,0x46,0x9b,0x6a,0x4f,0xf0,0x20,0x20,0x98,0x47, +0x07,0x46,0x20,0x4c,0x21,0x4e,0x63,0x69,0x1f,0x4d,0x31,0x68,0x2a,0x68,0x23,0xf0, +0x11,0x03,0x63,0x61,0x4b,0x68,0xd2,0xf8,0x14,0x80,0x98,0x47,0x41,0x1e,0x00,0x20, +0xc0,0x47,0x33,0x68,0x2a,0x68,0x9b,0x6c,0x55,0x69,0x98,0x47,0x18,0x49,0x01,0x44, +0x4f,0xf4,0x00,0x10,0xa8,0x47,0x27,0xb1,0x40,0xf6,0xce,0x23,0x63,0x60,0xbd,0xe8, +0xf0,0x81,0x4d,0xf6,0xad,0x63,0x63,0x60,0xbd,0xe8,0xf0,0x81,0xdf,0xf8,0x38,0x80, +0xd8,0xf8,0x00,0x30,0xc4,0xf5,0x00,0x17,0x3a,0x46,0x9b,0x6a,0x21,0x46,0x4f,0xf0, +0x20,0x20,0x98,0x47,0xd8,0xf8,0x00,0x30,0x06,0x46,0xc4,0xf1,0x20,0x20,0xea,0x1b, +0x9b,0x6a,0x00,0xf5,0x00,0x10,0x4f,0xf4,0x00,0x11,0x98,0x47,0x30,0x40,0xc7,0xb2, +0xbf,0xe7,0x00,0xbf,0x50,0x01,0x00,0x20,0x6c,0x08,0x00,0x02,0x68,0x08,0x00,0x02, +0xff,0xff,0x1f,0x00,0x2d,0xe9,0xf0,0x4f,0x4f,0x4c,0x26,0x69,0xe7,0x68,0x83,0xb0, +0x00,0x2e,0x59,0xd0,0x4f,0xf0,0x00,0x09,0xca,0x46,0xcd,0xf8,0x00,0x90,0xb6,0xf5, +0x80,0x5f,0x93,0xbf,0xb0,0x46,0xa6,0xf5,0x80,0x56,0x4f,0xf4,0x80,0x58,0x00,0x26, +0xff,0xf7,0x4a,0xff,0x02,0xe0,0xa3,0x69,0xdb,0x06,0x02,0xd4,0x63,0x69,0xda,0x06, +0xf9,0xd5,0x65,0x69,0x15,0xf0,0x10,0x05,0x41,0xd0,0x63,0x69,0x43,0xf0,0x01,0x03, +0x63,0x61,0x4f,0xf0,0x20,0x2a,0x01,0x25,0x3c,0x4b,0x9f,0x42,0x08,0xeb,0x07,0x09, +0x3b,0x4b,0x02,0xd8,0xb9,0xf5,0x00,0x1f,0x4c,0xd8,0x1b,0x68,0x39,0x46,0x42,0x46, +0x9b,0x6a,0x50,0x46,0x98,0x47,0x4f,0x46,0x81,0x46,0x00,0x2d,0x39,0xd0,0x63,0x69, +0x23,0xf0,0x11,0x03,0x63,0x61,0xdf,0xf8,0xcc,0x80,0x31,0x4d,0xd8,0xf8,0x00,0x20, +0x2b,0x68,0x52,0x68,0xd3,0xf8,0x14,0xb0,0x90,0x47,0x41,0x1e,0x00,0x20,0xd8,0x47, +0xd8,0xf8,0x00,0x30,0x2a,0x68,0x9b,0x6c,0x55,0x69,0x98,0x47,0x27,0x49,0x01,0x44, +0x4f,0xf4,0x00,0x10,0xa8,0x47,0xb9,0xf1,0x00,0x0f,0x3e,0xd0,0x00,0x2e,0xae,0xd1, +0x21,0x4b,0x40,0xf6,0xce,0x22,0x5a,0x60,0x03,0xb0,0xbd,0xe8,0xf0,0x8f,0xa3,0x69, +0x13,0xf0,0x10,0x03,0x08,0xd0,0xa3,0x69,0xdf,0xf8,0x7c,0xa0,0x43,0xf0,0x01,0x03, +0xa3,0x61,0x01,0x23,0x00,0x93,0xb7,0xe7,0x00,0x9a,0x00,0x2a,0xcb,0xd0,0x1d,0x46, +0xb2,0xe7,0x00,0x9b,0x00,0x2b,0xc6,0xd0,0xa3,0x69,0x00,0x95,0x23,0xf0,0x11,0x03, +0xa3,0x61,0xc0,0xe7,0x1a,0x68,0x01,0x93,0xc7,0xf5,0x00,0x1b,0xd2,0xf8,0x28,0xc0, +0x39,0x46,0x5a,0x46,0x50,0x46,0xe0,0x47,0x01,0x9b,0x19,0x68,0x07,0x46,0xd1,0xf8, +0x28,0xc0,0xcb,0xeb,0x08,0x02,0x0a,0xeb,0x0b,0x00,0x4f,0xf4,0x00,0x11,0xe0,0x47, +0x38,0x40,0x4f,0x46,0x5f,0xfa,0x80,0xf9,0x9f,0xe7,0x03,0x4b,0x4d,0xf6,0xad,0x62, +0x5a,0x60,0x03,0xb0,0xbd,0xe8,0xf0,0x8f,0x50,0x01,0x00,0x20,0xff,0xff,0x1f,0x00, +0x6c,0x08,0x00,0x02,0x68,0x08,0x00,0x02,0x00,0x30,0x00,0x20,0x2d,0xe9,0xf0,0x41, +0x1b,0x4c,0x1c,0x4d,0x1c,0x4f,0x29,0x68,0x3a,0x68,0x46,0xf6,0x5a,0x18,0xc4,0xf8, +0x00,0x80,0x63,0x68,0x23,0xf4,0xe0,0x23,0x00,0x26,0x43,0xf4,0x80,0x33,0x63,0x60, +0x26,0x60,0x53,0x6d,0x30,0x46,0x98,0x47,0x3b,0x68,0x69,0x68,0x5b,0x6d,0x01,0x20, +0x98,0x47,0x68,0x7b,0xff,0xf7,0x1c,0xfd,0x07,0x46,0x28,0x7b,0xff,0xf7,0xf4,0xfb, +0xc4,0xf8,0x00,0x80,0x63,0x68,0xaa,0x68,0x0c,0x49,0x23,0xf4,0xe0,0x23,0x13,0x43, +0x63,0x60,0x26,0x60,0x0a,0x4b,0x8e,0x60,0x28,0xb1,0x27,0xb1,0x40,0xf6,0xce,0x22, +0x5a,0x60,0xbd,0xe8,0xf0,0x81,0x4d,0xf6,0xad,0x62,0x5a,0x60,0xbd,0xe8,0xf0,0x81, +0x00,0x04,0x01,0x40,0x80,0x01,0x00,0x20,0x6c,0x08,0x00,0x02,0x00,0xed,0x00,0xe0, +0x50,0x01,0x00,0x20,0x5b,0x4b,0x5c,0x4c,0x1b,0x68,0x5c,0x4e,0x1b,0x68,0x80,0xb5, +0x98,0x47,0xff,0xf7,0xb7,0xfb,0x27,0x46,0x23,0x68,0x20,0x2b,0x00,0xf2,0x99,0x80, +0x01,0xa2,0x52,0xf8,0x23,0xf0,0x00,0xbf,0x99,0x10,0x00,0x01,0x89,0x11,0x00,0x01, +0x65,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0x57,0x11,0x00,0x01,0xd3,0x11,0x00,0x01, +0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0x49,0x11,0x00,0x01,0xd3,0x11,0x00,0x01, +0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01, +0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0x3b,0x11,0x00,0x01,0xd3,0x11,0x00,0x01, +0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01, +0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01, +0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01, +0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0x2d,0x11,0x00,0x01,0x01,0x23,0x63,0x60, +0xff,0xf7,0xb8,0xfe,0x00,0x23,0x23,0x60,0xae,0xe7,0x01,0x23,0x63,0x60,0xff,0xf7, +0x5d,0xff,0x00,0x23,0x23,0x60,0xa7,0xe7,0x01,0x23,0x63,0x60,0xff,0xf7,0x82,0xfd, +0x00,0x23,0x23,0x60,0xa0,0xe7,0x01,0x23,0x63,0x60,0xff,0xf7,0x3b,0xfe,0x00,0x23, +0x23,0x60,0x99,0xe7,0x01,0x23,0x63,0x60,0xff,0xf7,0xfe,0xfd,0x05,0x25,0x33,0x68, +0xe0,0x68,0x5b,0x6a,0x98,0x47,0x01,0x3d,0x00,0x28,0x2e,0xd1,0x00,0x2d,0xf6,0xd1, +0x4d,0xf6,0xad,0x63,0x63,0x60,0x0d,0xe0,0x01,0x23,0x63,0x60,0xff,0xf7,0xac,0xfd, +0x05,0x25,0x33,0x68,0x1b,0x6a,0x98,0x47,0x01,0x3d,0x20,0xbb,0x00,0x2d,0xf8,0xd1, +0x17,0x4b,0x63,0x60,0x17,0x4d,0x32,0x68,0x2b,0x68,0xd2,0xf8,0x14,0x80,0x5b,0x68, +0x98,0x47,0x41,0x1e,0x00,0x20,0xc0,0x47,0x2b,0x68,0x32,0x68,0x9b,0x6c,0x55,0x69, +0x98,0x47,0x11,0x49,0x01,0x44,0x4f,0xf4,0x00,0x10,0xa8,0x47,0x00,0x23,0x23,0x60, +0x62,0xe7,0x40,0xf6,0xad,0x33,0x63,0x60,0x5e,0xe7,0x00,0x2d,0xd0,0xd0,0x40,0xf6, +0xce,0x23,0x7b,0x60,0xde,0xe7,0x00,0x2d,0xda,0xd0,0x40,0xf6,0xce,0x23,0x63,0x60, +0xd8,0xe7,0x00,0xbf,0x64,0x08,0x00,0x02,0x50,0x01,0x00,0x20,0x6c,0x08,0x00,0x02, +0xad,0xde,0xad,0xde,0x68,0x08,0x00,0x02,0xff,0xff,0x1f,0x00,0xfe,0xe7,0x00,0xbf, +0xfd,0x01,0x00,0x01,0x85,0x04,0x00,0x01,0xf8,0xb5,0x00,0xbf,0xf8,0xbc,0x08,0xbc, +0x9e,0x46,0x70,0x47,0xf8,0xb5,0x00,0xbf,0xd5,0x01,0x00,0x01,0xf8,0xbc,0x08,0xbc, +0x9e,0x46,0x70,0x47,0x43,0x00,0x00,0x00,0x08,0x20,0x00,0x20,0xf8,0xef,0xff,0x7f, +0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xf4,0x22,0x00,0x20,0x5c,0x23,0x00,0x20,0xc4,0x23,0x00,0x20,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x34,0x12,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x33,0xcd,0xab, +0x34,0x12,0x6d,0xe6,0xec,0xde,0x05,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x08,0x20,0x00,0x20, diff --git a/contrib/loaders/flash/msp432/startup_msp432e4.c b/contrib/loaders/flash/msp432/startup_msp432e4.c new file mode 100644 index 000000000..8adce8356 --- /dev/null +++ b/contrib/loaders/flash/msp432/startup_msp432e4.c @@ -0,0 +1,122 @@ +/****************************************************************************** +* +* Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#include + +/* Entry point for the application. */ +extern int main(); + +/* Reserve space for the system stack. */ +extern uint32_t __stack_top; + +typedef void(*pFunc)(void); + +/* Interrupt handler prototypes */ +void default_handler(void); +void reset_handler(void); + +/* + * The vector table. Note that the proper constructs must be placed on this to + * ensure that it ends up at physical address 0x0000.0000 or at the start of + * the program if located at a start address other than 0. + */ +void (* const intr_vectors[])(void) __attribute__((section(".intvecs"))) = { + (pFunc)&__stack_top, /* The initial stack pointer */ + reset_handler, /* The reset handler */ + default_handler, /* The NMI handler */ + default_handler, /* The hard fault handler */ + default_handler, /* The MPU fault handler */ + default_handler, /* The bus fault handler */ + default_handler, /* The usage fault handler */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + default_handler, /* SVCall handler */ + default_handler, /* Debug monitor handler */ + 0, /* Reserved */ + default_handler, /* The PendSV handler */ + default_handler /* The SysTick handler */ +}; + +/* + * The following are constructs created by the linker, indicating where the + * the "data" and "bss" segments reside in memory. The initializers for the + * for the "data" segment resides immediately following the "text" segment. + */ +extern uint32_t __bss_start__; +extern uint32_t __bss_end__; + +/* + * This is the code that gets called when the processor first starts execution + * following a reset event. Only the absolutely necessary set is performed, + * after which the application supplied entry() routine is called. Any fancy + * actions (such as making decisions based on the reset cause register, and + * resetting the bits in that register) are left solely in the hands of the + * application. + */ +__attribute__((section(".reset"))) __attribute__((naked)) +void reset_handler(void) +{ + /* Set stack pointer */ + __asm(" MOVW.W r0, #0x1700\n" + " MOVT.W r0, #0x2000\n" + " mov sp, r0\n"); + + /* Zero fill the bss segment. */ + __asm(" ldr r0, =__bss_start__\n" + " ldr r1, =__bss_end__\n" + " mov r2, #0\n" + " .thumb_func\n" + "zero_loop:\n" + " cmp r0, r1\n" + " it lt\n" + " strlt r2, [r0], #4\n" + " blt zero_loop"); + + /* Call the application's entry point. */ + main(); +} + +/* + * This is the code that gets called when the processor receives an unexpected + * interrupt. This simply enters an infinite loop, preserving the system state + * for examination by a debugger. + */ +void default_handler(void) +{ + /* Enter an infinite loop. */ + while (1) + ; +} diff --git a/contrib/loaders/flash/msp432/startup_msp432p4.c b/contrib/loaders/flash/msp432/startup_msp432p4.c new file mode 100644 index 000000000..ed7ea10a9 --- /dev/null +++ b/contrib/loaders/flash/msp432/startup_msp432p4.c @@ -0,0 +1,122 @@ +/****************************************************************************** +* +* Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +******************************************************************************/ + +#include + +/* Entry point for the application. */ +extern int main(); + +/* Reserve space for the system stack. */ +extern uint32_t __stack_top; + +typedef void(*pFunc)(void); + +/* Interrupt handler prototypes */ +void default_handler(void); +void reset_handler(void); + +/* + * The vector table. Note that the proper constructs must be placed on this to + * ensure that it ends up at physical address 0x0000.0000 or at the start of + * the program if located at a start address other than 0. + */ +void (* const intr_vectors[])(void) __attribute__((section(".intvecs"))) = { + (pFunc)&__stack_top, /* The initial stack pointer */ + reset_handler, /* The reset handler */ + default_handler, /* The NMI handler */ + default_handler, /* The hard fault handler */ + default_handler, /* The MPU fault handler */ + default_handler, /* The bus fault handler */ + default_handler, /* The usage fault handler */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + default_handler, /* SVCall handler */ + default_handler, /* Debug monitor handler */ + 0, /* Reserved */ + default_handler, /* The PendSV handler */ + default_handler /* The SysTick handler */ +}; + +/* + * The following are constructs created by the linker, indicating where the + * the "data" and "bss" segments reside in memory. The initializers for the + * for the "data" segment resides immediately following the "text" segment. + */ +extern uint32_t __bss_start__; +extern uint32_t __bss_end__; + +/* + * This is the code that gets called when the processor first starts execution + * following a reset event. Only the absolutely necessary set is performed, + * after which the application supplied entry() routine is called. Any fancy + * actions (such as making decisions based on the reset cause register, and + * resetting the bits in that register) are left solely in the hands of the + * application. + */ +__attribute__((section(".reset"))) __attribute__((naked)) +void reset_handler(void) +{ + /* Set stack pointer */ + __asm(" MOVW.W r0, #0x1700\n" + " MOVT.W r0, #0x0100\n" + " mov sp, r0\n"); + + /* Zero fill the bss segment. */ + __asm(" ldr r0, =__bss_start__\n" + " ldr r1, =__bss_end__\n" + " mov r2, #0\n" + " .thumb_func\n" + "zero_loop:\n" + " cmp r0, r1\n" + " it lt\n" + " strlt r2, [r0], #4\n" + " blt zero_loop"); + + /* Call the application's entry point. */ + main(); +} + +/* + * This is the code that gets called when the processor receives an unexpected + * interrupt. This simply enters an infinite loop, preserving the system state + * for examination by a debugger. + */ +void default_handler(void) +{ + /* Enter an infinite loop. */ + while (1) + ; +} diff --git a/doc/openocd.texi b/doc/openocd.texi index 3ae11df8c..15cf74268 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -6000,6 +6000,41 @@ if @{ [info exists IMEMORY] && [string equal $IMEMORY true] @} @{ @end example @end deffn +@deffn {Flash Driver} msp432 +All versions of the SimpleLink MSP432 microcontrollers from Texas +Instruments include internal flash. The msp432 flash driver automatically +recognizes the specific version's flash parameters and autoconfigures itself. +Main program flash (starting at address 0) is flash bank 0. Information flash +region on MSP432P4 versions (starting at address 0x200000) is flash bank 1. + +@example +flash bank $_FLASHNAME msp432 0 0 0 0 $_TARGETNAME +@end example + +@deffn Command {msp432 mass_erase} [main|all] +Performs a complete erase of flash. By default, @command{mass_erase} will erase +only the main program flash. + +On MSP432P4 versions, using @command{mass_erase all} will erase both the +main program and information flash regions. To also erase the BSL in information +flash, the user must first use the @command{bsl} command. +@end deffn + +@deffn Command {msp432 bsl} [unlock|lock] +On MSP432P4 versions, @command{bsl} unlocks and locks the bootstrap loader (BSL) +region in information flash so that flash commands can erase or write the BSL. +Leave the BSL locked to prevent accidentally corrupting the bootstrap loader. + +To erase and program the BSL: +@example +msp432 bsl unlock +flash erase_address 0x202000 0x2000 +flash write_image bsl.bin 0x202000 +msp432 bsl lock +@end example +@end deffn +@end deffn + @deffn {Flash Driver} niietcm4 This drivers handles the integrated NOR flash on NIIET Cortex-M4 based controllers. Flash size and sector layout are auto-configured by the driver. diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 991869804..13e589cd0 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -36,6 +36,7 @@ NOR_DRIVERS = \ %D%/lpc2900.c \ %D%/lpcspifi.c \ %D%/mdr.c \ + %D%/msp432.c \ %D%/mrvlqspi.c \ %D%/niietcm4.c \ %D%/non_cfi.c \ @@ -73,4 +74,5 @@ NORHEADERS = \ %D%/imp.h \ %D%/non_cfi.h \ %D%/ocl.h \ - %D%/spi.h + %D%/spi.h \ + %D%/msp432.h diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 4efbdf768..196717f46 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -50,6 +50,7 @@ extern struct flash_driver lpc2900_flash; extern struct flash_driver lpcspifi_flash; extern struct flash_driver mdr_flash; extern struct flash_driver mrvlqspi_flash; +extern struct flash_driver msp432_flash; extern struct flash_driver niietcm4_flash; extern struct flash_driver nrf5_flash; extern struct flash_driver nrf51_flash; @@ -113,6 +114,7 @@ static struct flash_driver *flash_drivers[] = { &lpcspifi_flash, &mdr_flash, &mrvlqspi_flash, + &msp432_flash, &niietcm4_flash, &nrf5_flash, &nrf51_flash, diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c new file mode 100644 index 000000000..5caa0520d --- /dev/null +++ b/src/flash/nor/msp432.c @@ -0,0 +1,1103 @@ +/*************************************************************************** + * Copyright (C) 2018 by Texas Instruments, Inc. * + * * + * 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 . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include "msp432.h" +#include +#include +#include +#include +#include + +/* MSP432P4 hardware registers */ +#define P4_FLASH_MAIN_SIZE_REG 0xE0043020 +#define P4_FLASH_INFO_SIZE_REG 0xE0043024 +#define P4_DEVICE_ID_REG 0x0020100C +#define P4_HARDWARE_REV_REG 0x00201010 + +/* MSP432E4 hardware registers */ +#define E4_DID0_REG 0x400FE000 +#define E4_DID1_REG 0x400FE004 + +#define FLASH_TIMEOUT 8000 + +#define SUPPORT_MESSAGE \ + "Your pre-production MSP432P401x silicon is not fully supported\n" \ + "You can find more information at www.ti.com/product/MSP432P401R" + +struct msp432_bank { + uint32_t device_id; + uint32_t hardware_rev; + int family_type; + int device_type; + uint32_t sector_length; + bool probed[2]; + bool unlock_bsl; + struct working_area *working_area; + struct armv7m_algorithm armv7m_info; +}; + +static int msp432_auto_probe(struct flash_bank *bank); + +static int msp432_device_type(uint32_t family_type, uint32_t device_id, + uint32_t hardware_rev) +{ + int device_type = MSP432_NO_TYPE; + + if (MSP432E4 == family_type) { + /* MSP432E4 device family */ + + if (device_id == 0x180C0002) { + if (hardware_rev == 0x102DC06E) { + /* The 01Y variant */ + device_type = MSP432E401Y; + } else if (hardware_rev == 0x1032E076) { + /* The 11Y variant */ + device_type = MSP432E411Y; + } else { + /* Reasonable guess that this is a new variant */ + device_type = MSP432E4X_GUESS; + } + } else { + /* Wild guess that this is an MSP432E4 */ + device_type = MSP432E4X_GUESS; + } + } else { + /* MSP432P4 device family */ + + /* Examine the device ID and hardware revision to get the device type */ + switch (device_id) { + case 0xA000: + case 0xA001: + case 0xA002: + case 0xA003: + case 0xA004: + case 0xA005: + /* Device is definitely MSP432P401x, check hardware revision */ + if (hardware_rev == 0x41 || hardware_rev == 0x42) { + /* Rev A or B of the silicon has been deprecated */ + device_type = MSP432P401X_DEPR; + } else if (hardware_rev >= 0x43 && hardware_rev <= 0x49) { + /* Current and future revisions of the MSP432P401x device */ + device_type = MSP432P401X; + } else { + /* Unknown or unanticipated hardware revision */ + device_type = MSP432P401X_GUESS; + } + break; + case 0xA010: + case 0xA012: + case 0xA016: + case 0xA019: + case 0xA01F: + case 0xA020: + case 0xA022: + case 0xA026: + case 0xA029: + case 0xA02F: + /* Device is definitely MSP432P411x, check hardware revision */ + if (hardware_rev >= 0x41 && hardware_rev <= 0x49) { + /* Current and future revisions of the MSP432P411x device */ + device_type = MSP432P411X; + } else { + /* Unknown or unanticipated hardware revision */ + device_type = MSP432P411X_GUESS; + } + break; + case 0xFFFF: + /* Device is very early silicon that has been deprecated */ + device_type = MSP432P401X_DEPR; + break; + default: + if (device_id < 0xA010) { + /* Wild guess that this is an MSP432P401x */ + device_type = MSP432P401X_GUESS; + } else { + /* Reasonable guess that this is a new variant */ + device_type = MSP432P411X_GUESS; + } + break; + } + } + + return device_type; +} + +static const char *msp432_return_text(uint32_t return_code) +{ + switch (return_code) { + case FLASH_BUSY: + return "FLASH_BUSY"; + case FLASH_SUCCESS: + return "FLASH_SUCCESS"; + case FLASH_ERROR: + return "FLASH_ERROR"; + case FLASH_TIMEOUT_ERROR: + return "FLASH_TIMEOUT_ERROR"; + case FLASH_VERIFY_ERROR: + return "FLASH_VERIFY_WRONG"; + case FLASH_WRONG_COMMAND: + return "FLASH_WRONG_COMMAND"; + case FLASH_POWER_ERROR: + return "FLASH_POWER_ERROR"; + default: + return "UNDEFINED_RETURN_CODE"; + } +} + +static void msp432_init_params(struct msp432_algo_params *algo_params) +{ + buf_set_u32(algo_params->flash_command, 0, 32, FLASH_NO_COMMAND); + buf_set_u32(algo_params->return_code, 0, 32, 0); + buf_set_u32(algo_params->_reserved0, 0, 32, 0); + buf_set_u32(algo_params->address, 0, 32, 0); + buf_set_u32(algo_params->length, 0, 32, 0); + buf_set_u32(algo_params->buffer1_status, 0, 32, BUFFER_INACTIVE); + buf_set_u32(algo_params->buffer2_status, 0, 32, BUFFER_INACTIVE); + buf_set_u32(algo_params->erase_param, 0, 32, FLASH_ERASE_MAIN); + buf_set_u32(algo_params->unlock_bsl, 0, 32, FLASH_LOCK_BSL); +} + +static int msp432_exec_cmd(struct target *target, struct msp432_algo_params + *algo_params, uint32_t command) +{ + int retval; + + /* Make sure the given params do not include the command */ + buf_set_u32(algo_params->flash_command, 0, 32, FLASH_NO_COMMAND); + buf_set_u32(algo_params->return_code, 0, 32, 0); + buf_set_u32(algo_params->buffer1_status, 0, 32, BUFFER_INACTIVE); + buf_set_u32(algo_params->buffer2_status, 0, 32, BUFFER_INACTIVE); + + /* Write out parameters to target memory */ + retval = target_write_buffer(target, ALGO_PARAMS_BASE_ADDR, + sizeof(struct msp432_algo_params), (uint8_t *)algo_params); + if (ERROR_OK != retval) + return retval; + + /* Write out command to target memory */ + retval = target_write_buffer(target, ALGO_FLASH_COMMAND_ADDR, + sizeof(command), (uint8_t *)&command); + + return retval; +} + +static int msp432_wait_return_code(struct target *target) +{ + uint32_t return_code = 0; + long long start_ms; + long long elapsed_ms; + + int retval = ERROR_OK; + + start_ms = timeval_ms(); + while ((0 == return_code) || (FLASH_BUSY == return_code)) { + retval = target_read_buffer(target, ALGO_RETURN_CODE_ADDR, + sizeof(return_code), (uint8_t *)&return_code); + if (ERROR_OK != retval) + return retval; + + elapsed_ms = timeval_ms() - start_ms; + if (elapsed_ms > 500) + keep_alive(); + if (elapsed_ms > FLASH_TIMEOUT) + break; + }; + + if (FLASH_SUCCESS != return_code) { + LOG_ERROR("msp432: Flash operation failed: %s", + msp432_return_text(return_code)); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int msp432_wait_inactive(struct target *target, uint32_t buffer) +{ + uint32_t status_code = BUFFER_ACTIVE; + uint32_t status_addr; + long long start_ms; + long long elapsed_ms; + + int retval; + + switch (buffer) { + case 1: /* Buffer 1 */ + status_addr = ALGO_BUFFER1_STATUS_ADDR; + break; + case 2: /* Buffer 2 */ + status_addr = ALGO_BUFFER2_STATUS_ADDR; + break; + default: + return ERROR_FAIL; + } + + start_ms = timeval_ms(); + while (BUFFER_INACTIVE != status_code) { + retval = target_read_buffer(target, status_addr, sizeof(status_code), + (uint8_t *)&status_code); + if (ERROR_OK != retval) + return retval; + + elapsed_ms = timeval_ms() - start_ms; + if (elapsed_ms > 500) + keep_alive(); + if (elapsed_ms > FLASH_TIMEOUT) + break; + }; + + if (BUFFER_INACTIVE != status_code) { + LOG_ERROR( + "msp432: Flash operation failed: buffer not written to flash"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int msp432_init(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct msp432_bank *msp432_bank = bank->driver_priv; + struct msp432_algo_params algo_params; + struct reg_param reg_params[1]; + + const uint8_t *loader_code; + uint32_t loader_size; + uint32_t algo_entry_addr; + int retval; + + /* Make sure we've probed the flash to get the device and size */ + retval = msp432_auto_probe(bank); + if (ERROR_OK != retval) + return retval; + + /* Choose appropriate flash helper algorithm */ + switch (msp432_bank->device_type) { + case MSP432P401X: + case MSP432P401X_DEPR: + case MSP432P401X_GUESS: + default: + loader_code = msp432p401x_algo; + loader_size = sizeof(msp432p401x_algo); + algo_entry_addr = P4_ALGO_ENTRY_ADDR; + break; + case MSP432P411X: + case MSP432P411X_GUESS: + loader_code = msp432p411x_algo; + loader_size = sizeof(msp432p411x_algo); + algo_entry_addr = P4_ALGO_ENTRY_ADDR; + break; + case MSP432E401Y: + case MSP432E411Y: + case MSP432E4X_GUESS: + loader_code = msp432e4x_algo; + loader_size = sizeof(msp432e4x_algo); + algo_entry_addr = E4_ALGO_ENTRY_ADDR; + break; + } + + /* Issue warnings if this is a device we may not be able to flash */ + if (MSP432P401X_GUESS == msp432_bank->device_type || + MSP432P411X_GUESS == msp432_bank->device_type) { + /* Explicit device type check failed. Report this. */ + LOG_WARNING( + "msp432: Unrecognized MSP432P4 Device ID and Hardware " + "Rev (%04X, %02X)", msp432_bank->device_id, + msp432_bank->hardware_rev); + } else if (MSP432P401X_DEPR == msp432_bank->device_type) { + LOG_WARNING( + "msp432: MSP432P401x pre-production device (deprecated " + "silicon)\n" SUPPORT_MESSAGE); + } else if (MSP432E4X_GUESS == msp432_bank->device_type) { + /* Explicit device type check failed. Report this. */ + LOG_WARNING( + "msp432: Unrecognized MSP432E4 DID0 and DID1 values " + "(%08X, %08X)", msp432_bank->device_id, + msp432_bank->hardware_rev); + } + + /* Check for working area to use for flash helper algorithm */ + if (NULL != msp432_bank->working_area) + target_free_working_area(target, msp432_bank->working_area); + retval = target_alloc_working_area(target, ALGO_WORKING_SIZE, + &msp432_bank->working_area); + if (ERROR_OK != retval) + return retval; + + /* Confirm the defined working address is the area we need to use */ + if (ALGO_BASE_ADDR != msp432_bank->working_area->address) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + /* Write flash helper algorithm into target memory */ + retval = target_write_buffer(target, ALGO_BASE_ADDR, loader_size, + loader_code); + if (ERROR_OK != retval) + return retval; + + /* Initialize the ARMv7 specific info to run the algorithm */ + msp432_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + msp432_bank->armv7m_info.core_mode = ARM_MODE_THREAD; + + /* Initialize algorithm parameters to default values */ + msp432_init_params(&algo_params); + + /* Write out parameters to target memory */ + retval = target_write_buffer(target, ALGO_PARAMS_BASE_ADDR, + sizeof(algo_params), (uint8_t *)&algo_params); + if (ERROR_OK != retval) + return retval; + + /* Initialize stack pointer for flash helper algorithm */ + init_reg_param(®_params[0], "sp", 32, PARAM_OUT); + buf_set_u32(reg_params[0].value, 0, 32, ALGO_STACK_POINTER_ADDR); + + /* Begin executing the flash helper algorithm */ + retval = target_start_algorithm(target, 0, 0, 1, reg_params, + algo_entry_addr, 0, &msp432_bank->armv7m_info); + destroy_reg_param(®_params[0]); + if (ERROR_OK != retval) { + LOG_ERROR("msp432: Failed to start flash helper algorithm"); + return retval; + } + + /* + * At this point, the algorithm is running on the target and + * ready to receive commands and data to flash the target + */ + + /* Issue the init command to the flash helper algorithm */ + retval = msp432_exec_cmd(target, &algo_params, FLASH_INIT); + if (ERROR_OK != retval) + return retval; + + retval = msp432_wait_return_code(target); + + return retval; +} + +static int msp432_quit(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct msp432_bank *msp432_bank = bank->driver_priv; + struct msp432_algo_params algo_params; + + int retval; + + /* Initialize algorithm parameters to default values */ + msp432_init_params(&algo_params); + + /* Issue the exit command to the flash helper algorithm */ + retval = msp432_exec_cmd(target, &algo_params, FLASH_EXIT); + if (ERROR_OK != retval) + return retval; + + (void)msp432_wait_return_code(target); + + /* Regardless of the return code, attempt to halt the target */ + (void)target_halt(target); + + /* Now confirm target halted and clean up from flash helper algorithm */ + retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, FLASH_TIMEOUT, + &msp432_bank->armv7m_info); + + target_free_working_area(target, msp432_bank->working_area); + msp432_bank->working_area = NULL; + + return retval; +} + +static int msp432_mass_erase(struct flash_bank *bank, bool all) +{ + struct target *target = bank->target; + struct msp432_bank *msp432_bank = bank->driver_priv; + struct msp432_algo_params algo_params; + + int retval; + + if (TARGET_HALTED != target->state) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = msp432_init(bank); + if (ERROR_OK != retval) + return retval; + + /* Initialize algorithm parameters to default values */ + msp432_init_params(&algo_params); + if (all) { + buf_set_u32(algo_params.erase_param, 0, 32, + FLASH_ERASE_MAIN | FLASH_ERASE_INFO); + if (msp432_bank->unlock_bsl) + buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL); + } + + /* Issue the mass erase command to the flash helper algorithm */ + retval = msp432_exec_cmd(target, &algo_params, FLASH_MASS_ERASE); + if (ERROR_OK != retval) { + (void)msp432_quit(bank); + return retval; + } + + retval = msp432_wait_return_code(target); + if (ERROR_OK != retval) { + (void)msp432_quit(bank); + return retval; + } + + retval = msp432_quit(bank); + if (ERROR_OK != retval) + return retval; + + return retval; +} + +COMMAND_HANDLER(msp432_mass_erase_command) +{ + struct flash_bank *bank; + struct msp432_bank *msp432_bank; + bool all; + int retval; + + if (0 == CMD_ARGC) { + all = false; + } else if (1 == CMD_ARGC) { + /* Check argument for how much to erase */ + if (0 == strcmp(CMD_ARGV[0], "main")) + all = false; + else if (0 == strcmp(CMD_ARGV[0], "all")) + all = true; + else + return ERROR_COMMAND_SYNTAX_ERROR; + } else { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + retval = get_flash_bank_by_num(0, &bank); + if (ERROR_OK != retval) + return retval; + + msp432_bank = bank->driver_priv; + + if (MSP432E4 == msp432_bank->family_type) { + /* MSP432E4 does not have main vs info regions, ignore "all" */ + all = false; + } + + retval = msp432_mass_erase(bank, all); + if (ERROR_OK != retval) + return retval; + + if (MSP432E4 == msp432_bank->family_type) { + /* MSP432E4 does not have main vs info regions */ + LOG_INFO("msp432: Mass erase of flash is complete"); + } else { + LOG_INFO("msp432: Mass erase of %s is complete", + all ? "main + info flash" : "main flash"); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(msp432_bsl_command) +{ + struct flash_bank *bank; + struct msp432_bank *msp432_bank; + int retval; + + if (1 < CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + retval = get_flash_bank_by_num(0, &bank); + if (ERROR_OK != retval) + return retval; + + msp432_bank = bank->driver_priv; + + if (MSP432E4 == msp432_bank->family_type) { + LOG_WARNING("msp432: MSP432E4 does not have a BSL region"); + return ERROR_OK; + } + + if (1 == CMD_ARGC) { + if (0 == strcmp(CMD_ARGV[0], "lock")) + msp432_bank->unlock_bsl = false; + else if (0 == strcmp(CMD_ARGV[0], "unlock")) + msp432_bank->unlock_bsl = true; + else + return ERROR_COMMAND_SYNTAX_ERROR; + } + + LOG_INFO("msp432: BSL flash region is currently %slocked", + msp432_bank->unlock_bsl ? "un" : ""); + + return ERROR_OK; +} + +FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command) +{ + struct msp432_bank *msp432_bank; + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + msp432_bank = malloc(sizeof(struct msp432_bank)); + if (NULL == msp432_bank) + return ERROR_FAIL; + + /* Initialize private flash information */ + msp432_bank->device_id = 0; + msp432_bank->hardware_rev = 0; + msp432_bank->family_type = MSP432_NO_FAMILY; + msp432_bank->device_type = MSP432_NO_TYPE; + msp432_bank->sector_length = 0x1000; + msp432_bank->probed[0] = false; + msp432_bank->probed[1] = false; + msp432_bank->unlock_bsl = false; + msp432_bank->working_area = NULL; + + /* Finish initialization of bank 0 (main flash) */ + bank->driver_priv = msp432_bank; + bank->next = NULL; + + return ERROR_OK; +} + +static int msp432_erase(struct flash_bank *bank, int first, int last) +{ + struct target *target = bank->target; + struct msp432_bank *msp432_bank = bank->driver_priv; + struct msp432_algo_params algo_params; + + int retval; + + if (TARGET_HALTED != target->state) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* Do a mass erase if user requested all sectors of main flash */ + if ((0 == bank->bank_number) && (first == 0) && + (last == (bank->num_sectors - 1))) { + /* Request mass erase of main flash */ + return msp432_mass_erase(bank, false); + } + + retval = msp432_init(bank); + if (ERROR_OK != retval) + return retval; + + /* Initialize algorithm parameters to default values */ + msp432_init_params(&algo_params); + + /* Adjust params if this is the info bank */ + if (1 == bank->bank_number) { + buf_set_u32(algo_params.erase_param, 0, 32, FLASH_ERASE_INFO); + /* And flag if BSL is unlocked */ + if (msp432_bank->unlock_bsl) + buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL); + } + + /* Erase requested sectors one by one */ + for (int i = first; i <= last; i++) { + + /* Skip TVL (read-only) sector of the info bank */ + if (1 == bank->bank_number && 1 == i) + continue; + + /* Skip BSL sectors of info bank if locked */ + if (1 == bank->bank_number && (2 == i || 3 == i) && + !msp432_bank->unlock_bsl) + continue; + + /* Convert sector number to starting address of sector */ + buf_set_u32(algo_params.address, 0, 32, bank->base + + (i * msp432_bank->sector_length)); + + /* Issue the sector erase command to the flash helper algorithm */ + retval = msp432_exec_cmd(target, &algo_params, FLASH_SECTOR_ERASE); + if (ERROR_OK != retval) { + (void)msp432_quit(bank); + return retval; + } + + retval = msp432_wait_return_code(target); + if (ERROR_OK != retval) { + (void)msp432_quit(bank); + return retval; + } + } + + retval = msp432_quit(bank); + if (ERROR_OK != retval) + return retval; + + return retval; +} + +static int msp432_protect(struct flash_bank *bank, int set, int first, + int last) +{ + return ERROR_OK; +} + +static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct msp432_bank *msp432_bank = bank->driver_priv; + struct msp432_algo_params algo_params; + uint32_t size; + uint32_t data_ready = BUFFER_DATA_READY; + long long start_ms; + long long elapsed_ms; + + int retval; + + if (TARGET_HALTED != target->state) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* + * Block attempts to write to read-only sectors of flash + * The TVL region in sector 1 of the info flash is always read-only + * The BSL region in sectors 2 and 3 of the info flash may be unlocked + * The helper algorithm will hang on attempts to write to TVL + */ + if (1 == bank->bank_number) { + /* Set read-only start to TVL sector */ + uint32_t start = 0x1000; + /* Set read-only end after BSL region if locked */ + uint32_t end = (msp432_bank->unlock_bsl) ? 0x2000 : 0x4000; + /* Check if request includes anything in read-only sectors */ + if ((offset + count - 1) < start || offset >= end) { + /* The request includes no bytes in read-only sectors */ + /* Fall out and process the request normally */ + } else { + /* Send a request for anything before read-only sectors */ + if (offset < start) { + uint32_t start_count = MIN(start - offset, count); + retval = msp432_write(bank, buffer, offset, start_count); + if (ERROR_OK != retval) + return retval; + } + /* Send a request for anything after read-only sectors */ + if ((offset + count - 1) >= end) { + uint32_t skip = end - offset; + count -= skip; + offset += skip; + buffer += skip; + return msp432_write(bank, buffer, offset, count); + } else { + /* Request is entirely in read-only sectors */ + return ERROR_OK; + } + } + } + + retval = msp432_init(bank); + if (ERROR_OK != retval) + return retval; + + /* Initialize algorithm parameters to default values */ + msp432_init_params(&algo_params); + + /* Set up parameters for requested flash write operation */ + buf_set_u32(algo_params.address, 0, 32, bank->base + offset); + buf_set_u32(algo_params.length, 0, 32, count); + + /* Check if this is the info bank */ + if (1 == bank->bank_number) { + /* And flag if BSL is unlocked */ + if (msp432_bank->unlock_bsl) + buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL); + } + + /* Set up flash helper algorithm to continuous flash mode */ + retval = msp432_exec_cmd(target, &algo_params, FLASH_CONTINUOUS); + if (ERROR_OK != retval) { + (void)msp432_quit(bank); + return retval; + } + + /* Write requested data, one buffer at a time */ + start_ms = timeval_ms(); + while (count > 0) { + + if (count > ALGO_BUFFER_SIZE) + size = ALGO_BUFFER_SIZE; + else + size = count; + + /* Put next block of data to flash into buffer */ + retval = target_write_buffer(target, ALGO_BUFFER1_ADDR, size, buffer); + if (ERROR_OK != retval) { + LOG_ERROR("Unable to write data to target memory"); + (void)msp432_quit(bank); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* Signal the flash helper algorithm that data is ready to flash */ + retval = target_write_buffer(target, ALGO_BUFFER1_STATUS_ADDR, + sizeof(data_ready), (uint8_t *)&data_ready); + if (ERROR_OK != retval) { + (void)msp432_quit(bank); + return ERROR_FLASH_OPERATION_FAILED; + } + + retval = msp432_wait_inactive(target, 1); + if (ERROR_OK != retval) { + (void)msp432_quit(bank); + return retval; + } + + count -= size; + buffer += size; + + elapsed_ms = timeval_ms() - start_ms; + if (elapsed_ms > 500) + keep_alive(); + } + + /* Confirm that the flash helper algorithm is finished */ + retval = msp432_wait_return_code(target); + if (ERROR_OK != retval) { + (void)msp432_quit(bank); + return retval; + } + + retval = msp432_quit(bank); + if (ERROR_OK != retval) + return retval; + + return retval; +} + +static int msp432_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct msp432_bank *msp432_bank = bank->driver_priv; + + char *name; + + uint32_t device_id; + uint32_t hardware_rev; + + uint32_t base; + uint32_t sector_length; + uint32_t size; + int num_sectors; + int bank_id; + + int retval; + + bank_id = bank->bank_number; + + /* Read the flash size register to determine this is a P4 or not */ + /* MSP432P4s will return the size of flash. MSP432E4s will return zero */ + retval = target_read_u32(target, P4_FLASH_MAIN_SIZE_REG, &size); + if (ERROR_OK != retval) + return retval; + + if (0 == size) { + /* This is likely an MSP432E4 */ + msp432_bank->family_type = MSP432E4; + + retval = target_read_u32(target, E4_DID0_REG, &device_id); + if (ERROR_OK != retval) + return retval; + + msp432_bank->device_id = device_id; + + retval = target_read_u32(target, E4_DID1_REG, &hardware_rev); + if (ERROR_OK != retval) + return retval; + + msp432_bank->hardware_rev = hardware_rev; + } else { + /* This is likely an MSP432P4 */ + msp432_bank->family_type = MSP432P4; + + retval = target_read_u32(target, P4_DEVICE_ID_REG, &device_id); + if (ERROR_OK != retval) + return retval; + + msp432_bank->device_id = device_id & 0xFFFF; + + retval = target_read_u32(target, P4_HARDWARE_REV_REG, &hardware_rev); + if (ERROR_OK != retval) + return retval; + + msp432_bank->hardware_rev = hardware_rev & 0xFF; + } + + msp432_bank->device_type = msp432_device_type(msp432_bank->family_type, + msp432_bank->device_id, msp432_bank->hardware_rev); + + /* If not already allocated, create the info bank for MSP432P4 */ + /* We could not determine it was needed until device was probed */ + if (MSP432P4 == msp432_bank->family_type) { + /* If we've been given bank 1, then this was already done */ + if (0 == bank_id) { + /* And only allocate it if it doesn't exist yet */ + if (NULL == bank->next) { + struct flash_bank *info_bank; + info_bank = malloc(sizeof(struct flash_bank)); + if (NULL == info_bank) + return ERROR_FAIL; + + name = malloc(strlen(bank->name)+1); + if (NULL == name) { + free(info_bank); + return ERROR_FAIL; + } + strcpy(name, bank->name); + + /* Initialize bank 1 (info region) */ + info_bank->name = name; + info_bank->target = bank->target; + info_bank->driver = bank->driver; + info_bank->driver_priv = bank->driver_priv; + info_bank->bank_number = 1; + info_bank->base = 0x00200000; + info_bank->size = 0; + info_bank->chip_width = 0; + info_bank->bus_width = 0; + info_bank->erased_value = 0xff; + info_bank->default_padded_value = 0xff; + info_bank->write_start_alignment = 0; + info_bank->write_end_alignment = 0; + info_bank->minimal_write_gap = FLASH_WRITE_GAP_SECTOR; + info_bank->num_sectors = 0; + info_bank->sectors = NULL; + info_bank->num_prot_blocks = 0; + info_bank->prot_blocks = NULL; + info_bank->next = NULL; + + /* Enable the new bank */ + bank->next = info_bank; + } + } + } + + if (MSP432P4 == msp432_bank->family_type) { + /* Set up MSP432P4 specific flash parameters */ + if (0 == bank_id) { + retval = target_read_u32(target, P4_FLASH_MAIN_SIZE_REG, &size); + if (ERROR_OK != retval) + return retval; + + base = P4_FLASH_MAIN_BASE; + sector_length = P4_SECTOR_LENGTH; + num_sectors = size / sector_length; + } else if (1 == bank_id) { + if (msp432_bank->device_type == MSP432P411X || + msp432_bank->device_type == MSP432P411X_GUESS) { + /* MSP432P411x has an info size register, use that for size */ + retval = target_read_u32(target, P4_FLASH_INFO_SIZE_REG, &size); + if (ERROR_OK != retval) + return retval; + } else { + /* All other MSP432P401x devices have fixed info region size */ + size = 0x4000; /* 16 KB info region */ + } + base = P4_FLASH_INFO_BASE; + sector_length = P4_SECTOR_LENGTH; + num_sectors = size / sector_length; + } else { + /* Invalid bank number somehow */ + return ERROR_FAIL; + } + } else { + /* Set up MSP432E4 specific flash parameters */ + base = E4_FLASH_BASE; + size = E4_FLASH_SIZE; + sector_length = E4_SECTOR_LENGTH; + num_sectors = size / sector_length; + } + + if (NULL != bank->sectors) { + free(bank->sectors); + bank->sectors = NULL; + } + + bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); + if (NULL == bank->sectors) + return ERROR_FAIL; + + bank->base = base; + bank->size = size; + bank->write_start_alignment = 0; + bank->write_end_alignment = 0; + bank->num_sectors = num_sectors; + msp432_bank->sector_length = sector_length; + + for (int i = 0; i < num_sectors; i++) { + bank->sectors[i].offset = i * sector_length; + bank->sectors[i].size = sector_length; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = 0; + } + + /* We've successfully determined the stats on this flash bank */ + msp432_bank->probed[bank_id] = true; + + /* If we fall through to here, then all went well */ + + return ERROR_OK; +} + +static int msp432_auto_probe(struct flash_bank *bank) +{ + struct msp432_bank *msp432_bank = bank->driver_priv; + + int retval = ERROR_OK; + + if (bank->bank_number < 0 || bank->bank_number > 1) { + /* Invalid bank number somehow */ + return ERROR_FAIL; + } + + if (!msp432_bank->probed[bank->bank_number]) + retval = msp432_probe(bank); + + return retval; +} + +static int msp432_protect_check(struct flash_bank *bank) +{ + return ERROR_OK; +} + +static int msp432_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct msp432_bank *msp432_bank = bank->driver_priv; + int printed = 0; + + switch (msp432_bank->device_type) { + case MSP432P401X_DEPR: + if (0xFFFF == msp432_bank->device_id) { + /* Very early pre-production silicon currently deprecated */ + printed = snprintf(buf, buf_size, + "MSP432P401x pre-production device (deprecated silicon)\n" + SUPPORT_MESSAGE); + } else { + /* Revision A or B silicon, also deprecated */ + printed = snprintf(buf, buf_size, + "MSP432P401x Device Rev %c (deprecated silicon)\n" + SUPPORT_MESSAGE, (char)msp432_bank->hardware_rev); + } + break; + case MSP432P401X: + printed = snprintf(buf, buf_size, + "MSP432P401x Device Rev %c\n", + (char)msp432_bank->hardware_rev); + break; + case MSP432P411X: + printed = snprintf(buf, buf_size, + "MSP432P411x Device Rev %c\n", + (char)msp432_bank->hardware_rev); + break; + case MSP432E401Y: + printed = snprintf(buf, buf_size, "MSP432E401Y Device\n"); + break; + case MSP432E411Y: + printed = snprintf(buf, buf_size, "MSP432E411Y Device\n"); + break; + case MSP432E4X_GUESS: + printed = snprintf(buf, buf_size, + "Unrecognized MSP432E4 DID0 and DID1 IDs (%08X, %08X)", + msp432_bank->device_id, msp432_bank->hardware_rev); + break; + case MSP432P401X_GUESS: + case MSP432P411X_GUESS: + default: + printed = snprintf(buf, buf_size, + "Unrecognized MSP432P4 Device ID and Hardware Rev (%04X, %02X)", + msp432_bank->device_id, msp432_bank->hardware_rev); + break; + } + + buf_size -= printed; + + if (0 > buf_size) + return ERROR_BUF_TOO_SMALL; + + return ERROR_OK; +} + +static void msp432_flash_free_driver_priv(struct flash_bank *bank) +{ + /* A single private struct is shared between main and info banks */ + /* Only free it on the call for main bank (#0) */ + if ((0 == bank->bank_number) && (NULL != bank->driver_priv)) + free(bank->driver_priv); + /* Forget about the private struct on both main and info banks */ + bank->driver_priv = NULL; +} + +static const struct command_registration msp432_exec_command_handlers[] = { + { + .name = "mass_erase", + .handler = msp432_mass_erase_command, + .mode = COMMAND_EXEC, + .help = "Erase entire flash memory on device.", + .usage = "['main' | 'all']", + }, + { + .name = "bsl", + .handler = msp432_bsl_command, + .mode = COMMAND_EXEC, + .help = "Allow BSL to be erased or written by flash commands.", + .usage = "['unlock' | 'lock']", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration msp432_command_handlers[] = { + { + .name = "msp432", + .mode = COMMAND_EXEC, + .help = "MSP432 flash command group", + .usage = "", + .chain = msp432_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct flash_driver msp432_flash = { + .name = "msp432", + .commands = msp432_command_handlers, + .flash_bank_command = msp432_flash_bank_command, + .erase = msp432_erase, + .protect = msp432_protect, + .write = msp432_write, + .read = default_flash_read, + .probe = msp432_probe, + .auto_probe = msp432_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = msp432_protect_check, + .info = msp432_info, + .free_driver_priv = msp432_flash_free_driver_priv, +}; diff --git a/src/flash/nor/msp432.h b/src/flash/nor/msp432.h new file mode 100644 index 000000000..ffefa8f43 --- /dev/null +++ b/src/flash/nor/msp432.h @@ -0,0 +1,127 @@ +/*************************************************************************** + * Copyright (C) 2018 by Texas Instruments, Inc. * + * * + * 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 . * + ***************************************************************************/ + +#ifndef OPENOCD_FLASH_NOR_MSP432_H +#define OPENOCD_FLASH_NOR_MSP432_H + +/* MSP432 family types */ +#define MSP432_NO_FAMILY 0 /* Family type not determined yet */ +#define MSP432E4 1 /* MSP432E4 family of devices */ +#define MSP432P4 2 /* MSP432P4 family of devices */ + +/* MSP432 device types */ +#define MSP432_NO_TYPE 0 /* Device type not determined yet */ +#define MSP432P401X_DEPR 1 /* Early MSP432P401x offerings, now deprecated */ +#define MSP432P401X 2 /* MSP432P401x device, revision C or higher */ +#define MSP432P411X 3 /* MSP432P411x device, revision A or higher */ +#define MSP432P401X_GUESS 4 /* Assuming it's an MSP432P401x device */ +#define MSP432P411X_GUESS 5 /* Assuming it's an MSP432P411x device */ +#define MSP432E401Y 6 /* MSP432E401Y device */ +#define MSP432E411Y 7 /* MSP432E401Y device */ +#define MSP432E4X_GUESS 8 /* Assuming it's an MSP432E4x device */ + +/* MSP432P4 flash parameters */ +#define P4_FLASH_MAIN_BASE 0x00000000 +#define P4_FLASH_INFO_BASE 0x00200000 +#define P4_SECTOR_LENGTH 0x1000 +#define P4_ALGO_ENTRY_ADDR 0x01000110 + +/* MSP432E4 flash paramters */ +#define E4_FLASH_BASE 0x00000000 +#define E4_FLASH_SIZE 0x100000 +#define E4_SECTOR_LENGTH 0x4000 +#define E4_ALGO_ENTRY_ADDR 0x20000110 + +/* Flash helper algorithm key addresses */ +#define ALGO_BASE_ADDR 0x20000000 +#define ALGO_BUFFER1_ADDR 0x20002000 +#define ALGO_BUFFER2_ADDR 0x20003000 +#define ALGO_PARAMS_BASE_ADDR 0x20000150 +#define ALGO_FLASH_COMMAND_ADDR 0x20000150 +#define ALGO_RETURN_CODE_ADDR 0x20000154 +#define ALGO_FLASH_DEST_ADDR 0x2000015c +#define ALGO_FLASH_LENGTH_ADDR 0x20000160 +#define ALGO_BUFFER1_STATUS_ADDR 0x20000164 +#define ALGO_BUFFER2_STATUS_ADDR 0x20000168 +#define ALGO_ERASE_PARAM_ADDR 0x2000016c +#define ALGO_UNLOCK_BSL_ADDR 0x20000170 +#define ALGO_STACK_POINTER_ADDR 0x20002000 + +/* Flash helper algorithm key sizes */ +#define ALGO_BUFFER_SIZE 0x1000 +#define ALGO_WORKING_SIZE (ALGO_BUFFER2_ADDR + 0x1000 - ALGO_BASE_ADDR) + +/* Flash helper algorithm flash commands */ +#define FLASH_NO_COMMAND 0 +#define FLASH_MASS_ERASE 1 +#define FLASH_SECTOR_ERASE 2 +#define FLASH_PROGRAM 4 +#define FLASH_INIT 8 +#define FLASH_EXIT 16 +#define FLASH_CONTINUOUS 32 + +/* Flash helper algorithm return codes */ +#define FLASH_BUSY 0x00000001 +#define FLASH_SUCCESS 0x00000ACE +#define FLASH_ERROR 0x0000DEAD +#define FLASH_TIMEOUT_ERROR 0xDEAD0000 +#define FLASH_VERIFY_ERROR 0xDEADDEAD +#define FLASH_WRONG_COMMAND 0x00000BAD +#define FLASH_POWER_ERROR 0x00DEAD00 + +/* Flash helper algorithm buffer status values */ +#define BUFFER_INACTIVE 0x00 +#define BUFFER_ACTIVE 0x01 +#define BUFFER_DATA_READY 0x10 + +/* Flash helper algorithm erase parameters */ +#define FLASH_ERASE_MAIN 0x01 +#define FLASH_ERASE_INFO 0x02 + +/* Flash helper algorithm lock/unlock BSL options */ +#define FLASH_LOCK_BSL 0x00 +#define FLASH_UNLOCK_BSL 0x0b + +/* Flash helper algorithm parameter block struct */ +struct msp432_algo_params { + uint8_t flash_command[4]; + uint8_t return_code[4]; + uint8_t _reserved0[4]; + uint8_t address[4]; + uint8_t length[4]; + uint8_t buffer1_status[4]; + uint8_t buffer2_status[4]; + uint8_t erase_param[4]; + uint8_t unlock_bsl[4]; +}; + +/* Flash helper algorithm for MSP432P401x targets */ +const uint8_t msp432p401x_algo[] = { +#include "../../../contrib/loaders/flash/msp432/msp432p401x_algo.inc" +}; + +/* Flash helper algorithm for MSP432P411x targets */ +const uint8_t msp432p411x_algo[] = { +#include "../../../contrib/loaders/flash/msp432/msp432p411x_algo.inc" +}; + +/* Flash helper algorithm for MSP432E4x targets */ +const uint8_t msp432e4x_algo[] = { +#include "../../../contrib/loaders/flash/msp432/msp432e4x_algo.inc" +}; + +#endif /* OPENOCD_FLASH_NOR_MSP432_H */ diff --git a/tcl/board/ti_msp432_launchpad.cfg b/tcl/board/ti_msp432_launchpad.cfg new file mode 100644 index 000000000..bfad32235 --- /dev/null +++ b/tcl/board/ti_msp432_launchpad.cfg @@ -0,0 +1,7 @@ +# +# TI MSP432 LaunchPad Evaluation Kit +# +source [find interface/xds110.cfg] +adapter_khz 2500 +transport select swd +source [find target/ti_msp432.cfg] diff --git a/tcl/target/ti_msp432p4xx.cfg b/tcl/target/ti_msp432.cfg similarity index 66% rename from tcl/target/ti_msp432p4xx.cfg rename to tcl/target/ti_msp432.cfg index 461b59547..3407f7505 100644 --- a/tcl/target/ti_msp432p4xx.cfg +++ b/tcl/target/ti_msp432.cfg @@ -1,5 +1,5 @@ # -# Texas Instruments MSP432P4xx - ARM Cortex-M4F @ up to 48 MHz +# Texas Instruments MSP432 - ARM Cortex-M4F @ up to 48 MHz # # http://www.ti.com/MSP432 # @@ -7,7 +7,7 @@ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { - set _CHIPNAME msp432p4xx + set _CHIPNAME msp432 } if { [info exists CPUTAPID] } { @@ -39,15 +39,13 @@ target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { - # On MSP432P401x Bank0 (8k) is always powered - set _WORKAREASIZE 0x2000 + set _WORKAREASIZE 0x4000 } -$_TARGETNAME configure -work-area-phys 0x20000000 \ - -work-area-size $_WORKAREASIZE -work-area-backup 0 +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -if { ![using_hla] } { - cortex_m reset_config sysresetreq -} +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME msp432 0 0 0 0 $_TARGETNAME -adapter_khz 500 +reset_config srst_only +adapter_nsrst_delay 100 From c4c14d614bfa6f02e8802ebb3f71fcafa729a335 Mon Sep 17 00:00:00 2001 From: Erwin Oegema <> Date: Fri, 13 Jul 2018 15:50:40 +0200 Subject: [PATCH 039/147] flash/nor/at91sam4: fix sam4sa16c flash banks and its gpnvms count There was already a github fork that had this fixed, but as we try to use the latest, non-modified version of all software we use, I would like to have this fix in the next releases of OpenOCD so that if people uses $packagemanager, they will not have issues flashing the last part of the flash of sam4sa16c chips. Additionally, I've added some more logging related to the flash bank that was used, and the chip ID that was detected. Change-Id: I7ea5970105906e4560b727e46222ae9a91e41559 Signed-off-by: Erwin Oegema Reviewed-on: http://openocd.zylin.com/4599 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/flash/nor/at91sam4.c | 81 ++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index 04752169f..c5b31e964 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -682,6 +682,40 @@ static const struct sam4_chip_details all_sam4_details[] = { }, }, }, + /*at91sam4sa16c - TFBGA100/VFBGA100/LQFP100*/ + { + .chipid_cidr = 0x28a70ce0, + .name = "at91sam4sa16c", + .total_flash_size = 1024 * 1024, + .total_sram_size = 160 * 1024, + .n_gpnvms = 2, + .n_banks = 1, + +/* .bank[0] = { */ + { + { + .probed = 0, + .pChip = NULL, + .pBank = NULL, + .bank_number = 0, + .base_address = FLASH_BANK_BASE_S, + .controller_address = 0x400e0a00, + .flash_wait_states = 5, + .present = 1, + .size_bytes = 1024 * 1024, + .nsectors = 128, + .sector_size = 8192, + .page_size = 512, + }, +/* .bank[1] = {*/ + { + .present = 0, + .probed = 0, + .bank_number = 1, + + }, + }, + }, /*atsam4s16b - LQFP64/QFN64/WLCSP64*/ { .chipid_cidr = 0x289C0CE0, @@ -1243,50 +1277,6 @@ static const struct sam4_chip_details all_sam4_details[] = { .page_size = 512, }, -/* .bank[1] = { */ - { - .probed = 0, - .pChip = NULL, - .pBank = NULL, - .bank_number = 1, - .base_address = FLASH_BANK1_BASE_1024K_SD, - .controller_address = 0x400e0c00, - .flash_wait_states = 5, - .present = 1, - .size_bytes = 512 * 1024, - .nsectors = 64, - .sector_size = 8192, - .page_size = 512, - }, - }, - }, - - /*at91sam4sa16c*/ - { - .chipid_cidr = 0x28a70ce0, - .name = "at91sam4sa16c", - .total_flash_size = 1024 * 1024, - .total_sram_size = 160 * 1024, - .n_gpnvms = 3, - .n_banks = 2, - -/* .bank[0] = { */ - { - { - .probed = 0, - .pChip = NULL, - .pBank = NULL, - .bank_number = 0, - .base_address = FLASH_BANK0_BASE_SD, - .controller_address = 0x400e0a00, - .flash_wait_states = 5, - .present = 1, - .size_bytes = 512 * 1024, - .nsectors = 64, - .sector_size = 8192, - .page_size = 512, - }, - /* .bank[1] = { */ { .probed = 0, @@ -2554,6 +2544,8 @@ static int sam4_GetDetails(struct sam4_bank_private *pPrivate) pPrivate->pChip->cfg.CHIPID_CIDR); sam4_explain_chipid_cidr(pPrivate->pChip); return ERROR_FAIL; + } else { + LOG_INFO("SAM4 Found chip %s, CIDR 0x%08x", pDetails->name, pDetails->chipid_cidr); } /* DANGER: THERE ARE DRAGONS HERE */ @@ -2624,6 +2616,7 @@ static int _sam4_probe(struct flash_bank *bank, int noise) for (x = 0; x < SAM4_MAX_FLASH_BANKS; x++) { if (bank->base == pPrivate->pChip->details.bank[x].base_address) { bank->size = pPrivate->pChip->details.bank[x].size_bytes; + LOG_INFO("SAM4 Set flash bank to %08X - %08X, idx %d", bank->base, bank->base + bank->size, x); break; } } From e270127288d608dc450a3e37557ab1b8de4620e6 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Mon, 2 Jul 2018 19:44:45 +0200 Subject: [PATCH 040/147] flash/nor/stm32lx: Add revision 'V' for STM32L1xx Cat.3 devices Change-Id: Ic92b0fb5b738af3bec79ae335876aa9e26f5f4cd Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4600 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Antonio Borneo --- src/flash/nor/stm32lx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index c68d7c243..3251df3fc 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -146,7 +146,7 @@ static const struct stm32lx_rev stm32_425_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, { 0x2008, "Y" }, }; static const struct stm32lx_rev stm32_427_revs[] = { - { 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" }, + { 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" }, { 0x10f8, "V" }, }; static const struct stm32lx_rev stm32_429_revs[] = { { 0x1000, "A" }, { 0x1018, "Z" }, From 6fa18a455f7aa78182cdead94278a8659f2dbc89 Mon Sep 17 00:00:00 2001 From: Liviu Ionescu Date: Sun, 15 Jul 2018 09:45:13 +0300 Subject: [PATCH 041/147] Avoid null target->semihosting references. The new common semihosting code introduced a bug, in certain conditions target->semihosting was used without semihosting being initialised. The solution was to explicitly test for target->semihosting before dereferencing it. Change-Id: I4c83e596140c68fe4ab32e586e51f7e981a40798 Signed-off-by: Liviu Ionescu Reviewed-on: http://openocd.zylin.com/4603 Tested-by: jenkins Reviewed-by: Jonathan Larmour Reviewed-by: Tomas Vanek --- src/target/arm_semihosting.c | 3 +++ src/target/armv4_5.c | 6 +++--- src/target/armv7m.c | 6 +++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index 31ca7792f..9117a7442 100644 --- a/src/target/arm_semihosting.c +++ b/src/target/arm_semihosting.c @@ -82,6 +82,9 @@ static int post_result(struct target *target) { struct arm *arm = target_to_arm(target); + if (!target->semihosting) + return ERROR_FAIL; + /* REVISIT this looks wrong ... ARM11 and Cortex-A8 * should work this way at least sometimes. */ diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 5ee8ead66..96a63e497 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -752,7 +752,7 @@ int arm_arch_state(struct target *target) } /* avoid filling log waiting for fileio reply */ - if (target->semihosting->hit_fileio) + if (target->semihosting && target->semihosting->hit_fileio) return ERROR_OK; LOG_USER("target halted in %s state due to %s, current mode: %s\n" @@ -762,8 +762,8 @@ int arm_arch_state(struct target *target) arm_mode_name(arm->core_mode), buf_get_u32(arm->cpsr->value, 0, 32), buf_get_u32(arm->pc->value, 0, 32), - target->semihosting->is_active ? ", semihosting" : "", - target->semihosting->is_fileio ? " fileio" : ""); + (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "", + (target->semihosting && target->semihosting->is_fileio) ? " fileio" : ""); return ERROR_OK; } diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 1b4e5b154..7d3bd7367 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -541,7 +541,7 @@ int armv7m_arch_state(struct target *target) uint32_t ctrl, sp; /* avoid filling log waiting for fileio reply */ - if (target->semihosting->hit_fileio) + if (target->semihosting && target->semihosting->hit_fileio) return ERROR_OK; ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32); @@ -556,8 +556,8 @@ int armv7m_arch_state(struct target *target) buf_get_u32(arm->pc->value, 0, 32), (ctrl & 0x02) ? 'p' : 'm', sp, - target->semihosting->is_active ? ", semihosting" : "", - target->semihosting->is_fileio ? " fileio" : ""); + (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "", + (target->semihosting && target->semihosting->is_fileio) ? " fileio" : ""); return ERROR_OK; } From d293583e03b2615aaee1cae21796771c87b48ee2 Mon Sep 17 00:00:00 2001 From: James Jacobsson Date: Mon, 16 Jul 2018 10:27:03 +0200 Subject: [PATCH 042/147] nrf5: Add HWID 0x139 (52832 rev E0) Change-Id: I71b7471ccfcb8fcc6de30da57ce4165c7fb1f73f Signed-off-by: James Jacobsson Reviewed-on: http://openocd.zylin.com/4604 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/nrf5.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index a7ae6f3b7..ad80e02e0 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -204,6 +204,7 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = { /* nRF52832 Devices */ NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512), + NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512), }; static int nrf5_bank_is_probed(struct flash_bank *bank) From abc270c8837bc7aad3f390e4e9858e4f652261b7 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Wed, 4 Apr 2018 09:50:40 +0200 Subject: [PATCH 043/147] target: Fix segfault for 'mem2array' Call 'mem2array' without arguments to reproduce the segmentation fault. Change-Id: I02bf46cc8bd317abbb721a8c75d7cbfac99eb34e Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4534 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Christopher Head --- src/target/target.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/target/target.c b/src/target/target.c index 1ca6c8e53..591b9ea2c 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -4131,8 +4131,9 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, * argv[3] = memory address * argv[4] = count of times to read */ + if (argc < 4 || argc > 5) { - Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems [phys]"); + Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]"); return JIM_ERR; } varname = Jim_GetString(argv[0], &len); From 55abb63752196de5a2e79fc4944a6af24e6414f6 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 10 Dec 2016 12:48:44 +0100 Subject: [PATCH 044/147] target/armv7m_trace: Fix typo in enum Change-Id: I6364ee5011ef2d55c59674e3b97504a285de0cb2 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/3904 Tested-by: jenkins Reviewed-by: Paul Fertser --- src/jtag/core.c | 2 +- src/jtag/drivers/jlink.c | 2 +- src/jtag/drivers/stlink_usb.c | 2 +- src/jtag/hla/hla_interface.c | 2 +- src/jtag/hla/hla_layout.h | 2 +- src/jtag/interface.h | 4 ++-- src/target/armv7m_trace.h | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/jtag/core.c b/src/jtag/core.c index 5d9b8101e..f90ae99ba 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -1843,7 +1843,7 @@ void adapter_deassert_reset(void) LOG_ERROR("transport is not selected"); } -int adapter_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol, +int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq) { if (jtag->config_trace) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 132ef06e9..c078102a0 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -1263,7 +1263,7 @@ static bool check_trace_freq(struct jaylink_swo_speed speed, return false; } -static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol, +static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq) { int ret; diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 99f96b9c9..01f947131 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -2194,7 +2194,7 @@ error_open: return ERROR_FAIL; } -int stlink_config_trace(void *handle, bool enabled, enum tpio_pin_protocol pin_protocol, +int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq) { struct stlink_usb_handle_s *h = handle; diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index cb9ef3969..2abed210d 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -191,7 +191,7 @@ int hl_interface_override_target(const char **targetname) return ERROR_FAIL; } -int hl_interface_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol, +int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq) { if (hl_if.layout->api->config_trace) diff --git a/src/jtag/hla/hla_layout.h b/src/jtag/hla/hla_layout.h index 40c1321ba..9f41b59a4 100644 --- a/src/jtag/hla/hla_layout.h +++ b/src/jtag/hla/hla_layout.h @@ -91,7 +91,7 @@ struct hl_layout_api_s { * its maximum supported rate there * @returns ERROR_OK on success, an error code on failure. */ - int (*config_trace)(void *handle, bool enabled, enum tpio_pin_protocol pin_protocol, + int (*config_trace)(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq); /** * Poll for new trace data diff --git a/src/jtag/interface.h b/src/jtag/interface.h index cdfc676ee..e6fa0caef 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -309,7 +309,7 @@ struct jtag_interface { * its maximum supported rate there * @returns ERROR_OK on success, an error code on failure. */ - int (*config_trace)(bool enabled, enum tpio_pin_protocol pin_protocol, + int (*config_trace)(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq); /** @@ -328,7 +328,7 @@ extern const char * const jtag_only[]; void adapter_assert_reset(void); void adapter_deassert_reset(void); -int adapter_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol, +int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq); int adapter_poll_trace(uint8_t *buf, size_t *size); diff --git a/src/target/armv7m_trace.h b/src/target/armv7m_trace.h index 4f9939464..02bec96a1 100644 --- a/src/target/armv7m_trace.h +++ b/src/target/armv7m_trace.h @@ -32,7 +32,7 @@ enum trace_config_type { INTERNAL /**< trace output is handled by OpenOCD adapter driver */ }; -enum tpio_pin_protocol { +enum tpiu_pin_protocol { SYNC, /**< synchronous trace output */ ASYNC_MANCHESTER, /**< asynchronous output with Manchester coding */ ASYNC_UART /**< asynchronous output with NRZ coding */ @@ -50,7 +50,7 @@ struct armv7m_trace_config { enum trace_config_type config_type; /** Currently active trace output mode */ - enum tpio_pin_protocol pin_protocol; + enum tpiu_pin_protocol pin_protocol; /** TPIU formatter enable/disable (in async mode) */ bool formatter; /** Synchronous output port width */ From 9f93cca42738cf0c5060296ef5899fee53fc642f Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 10 Dec 2016 12:59:27 +0100 Subject: [PATCH 045/147] target/armv7m_trace: Use prefix for enums Change-Id: I3f199e6053146a1094d96b98ea174b41bb021599 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/3905 Tested-by: jenkins Reviewed-by: Paul Fertser --- src/jtag/drivers/jlink.c | 2 +- src/jtag/drivers/stlink_usb.c | 3 ++- src/target/armv7m_trace.c | 20 ++++++++++---------- src/target/armv7m_trace.h | 12 ++++++------ src/target/cortex_m.c | 2 +- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index c078102a0..e74965e61 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -1275,7 +1275,7 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, return ERROR_FAIL; } - if (pin_protocol != ASYNC_UART) { + if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) { LOG_ERROR("Selected pin protocol is not supported."); return ERROR_FAIL; } diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 01f947131..d9ca53e29 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -2199,7 +2199,8 @@ int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_p { struct stlink_usb_handle_s *h = handle; - if (enabled && (h->jtag_api < 2 || pin_protocol != ASYNC_UART)) { + if (enabled && (h->jtag_api < 2 || + pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) { LOG_ERROR("The attached ST-LINK version doesn't support this trace mode"); return ERROR_FAIL; } diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c index c1e4f5baa..62f0f8e61 100644 --- a/src/target/armv7m_trace.c +++ b/src/target/armv7m_trace.c @@ -62,7 +62,7 @@ int armv7m_trace_tpiu_config(struct target *target) target_unregister_timer_callback(armv7m_poll_trace, target); - retval = adapter_config_trace(trace_config->config_type == INTERNAL, + retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL, trace_config->pin_protocol, trace_config->port_size, &trace_config->trace_freq); @@ -83,7 +83,7 @@ int armv7m_trace_tpiu_config(struct target *target) trace_config->trace_freq, trace_config->traceclkin_freq, trace_freq); trace_config->trace_freq = trace_freq; - retval = adapter_config_trace(trace_config->config_type == INTERNAL, + retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL, trace_config->pin_protocol, trace_config->port_size, &trace_config->trace_freq); @@ -115,7 +115,7 @@ int armv7m_trace_tpiu_config(struct target *target) if (retval != ERROR_OK) return retval; - if (trace_config->config_type == INTERNAL) + if (trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL) target_register_timer_callback(armv7m_poll_trace, 1, 1, target); target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG); @@ -173,7 +173,7 @@ COMMAND_HANDLER(handle_tpiu_config_command) if (CMD_ARGC == cmd_idx + 1) { close_trace_file(armv7m); - armv7m->trace_config.config_type = DISABLED; + armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED; if (CMD_CTX->mode == COMMAND_EXEC) return armv7m_trace_tpiu_config(target); else @@ -183,13 +183,13 @@ COMMAND_HANDLER(handle_tpiu_config_command) !strcmp(CMD_ARGV[cmd_idx], "internal")) { close_trace_file(armv7m); - armv7m->trace_config.config_type = EXTERNAL; + armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_EXTERNAL; if (!strcmp(CMD_ARGV[cmd_idx], "internal")) { cmd_idx++; if (CMD_ARGC == cmd_idx) return ERROR_COMMAND_SYNTAX_ERROR; - armv7m->trace_config.config_type = INTERNAL; + armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_INTERNAL; if (strcmp(CMD_ARGV[cmd_idx], "-") != 0) { armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab"); @@ -204,7 +204,7 @@ COMMAND_HANDLER(handle_tpiu_config_command) return ERROR_COMMAND_SYNTAX_ERROR; if (!strcmp(CMD_ARGV[cmd_idx], "sync")) { - armv7m->trace_config.pin_protocol = SYNC; + armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_SYNC; cmd_idx++; if (CMD_ARGC == cmd_idx) @@ -213,9 +213,9 @@ COMMAND_HANDLER(handle_tpiu_config_command) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[cmd_idx], armv7m->trace_config.port_size); } else { if (!strcmp(CMD_ARGV[cmd_idx], "manchester")) - armv7m->trace_config.pin_protocol = ASYNC_MANCHESTER; + armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER; else if (!strcmp(CMD_ARGV[cmd_idx], "uart")) - armv7m->trace_config.pin_protocol = ASYNC_UART; + armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_UART; else return ERROR_COMMAND_SYNTAX_ERROR; @@ -237,7 +237,7 @@ COMMAND_HANDLER(handle_tpiu_config_command) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.trace_freq); cmd_idx++; } else { - if (armv7m->trace_config.config_type != INTERNAL) { + if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_INTERNAL) { LOG_ERROR("Trace port frequency can't be omitted in external capture mode"); return ERROR_COMMAND_SYNTAX_ERROR; } diff --git a/src/target/armv7m_trace.h b/src/target/armv7m_trace.h index 02bec96a1..c63f36dea 100644 --- a/src/target/armv7m_trace.h +++ b/src/target/armv7m_trace.h @@ -27,15 +27,15 @@ */ enum trace_config_type { - DISABLED, /**< tracing is disabled */ - EXTERNAL, /**< trace output is captured externally */ - INTERNAL /**< trace output is handled by OpenOCD adapter driver */ + TRACE_CONFIG_TYPE_DISABLED, /**< tracing is disabled */ + TRACE_CONFIG_TYPE_EXTERNAL, /**< trace output is captured externally */ + TRACE_CONFIG_TYPE_INTERNAL /**< trace output is handled by OpenOCD adapter driver */ }; enum tpiu_pin_protocol { - SYNC, /**< synchronous trace output */ - ASYNC_MANCHESTER, /**< asynchronous output with Manchester coding */ - ASYNC_UART /**< asynchronous output with NRZ coding */ + TPIU_PIN_PROTOCOL_SYNC, /**< synchronous trace output */ + TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER, /**< asynchronous output with Manchester coding */ + TPIU_PIN_PROTOCOL_ASYNC_UART /**< asynchronous output with NRZ coding */ }; enum itm_ts_prescaler { diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index d1afbd569..dcb3ddd82 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -2080,7 +2080,7 @@ int cortex_m_examine(struct target *target) if (retval != ERROR_OK) return retval; - if (armv7m->trace_config.config_type != DISABLED) { + if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_DISABLED) { armv7m_trace_tpiu_config(target); armv7m_trace_itm_config(target); } From e59bb6c285d21ba59f785d4340048abda1c39466 Mon Sep 17 00:00:00 2001 From: Dennis Ostermann Date: Wed, 18 Jul 2018 11:21:17 +0200 Subject: [PATCH 046/147] target/aarch64: Call aarch64_init_debug_access() earlier in aarch64_deassert_reset() On Renesas R-Car, calling 'reset halt' and 'reset init' always made DAP inaccessible. Calling 'reset' and 'halt' seperatly worked fine. The only differences seems to be the point in time when aarch64_init_debug_access() is called. This patch aligns the behaviour. Change-Id: I2296c65e48414a7d9846f12a395e5eca315b49ca Signed-off-by: Dennis Ostermann Reviewed-on: http://openocd.zylin.com/4607 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/aarch64.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 14542a658..454de9e92 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -1694,17 +1694,19 @@ static int aarch64_deassert_reset(struct target *target) if (retval != ERROR_OK) return retval; + retval = aarch64_init_debug_access(target); + if (retval != ERROR_OK) + return retval; + if (target->reset_halt) { if (target->state != TARGET_HALTED) { LOG_WARNING("%s: ran after reset and before halt ...", target_name(target)); retval = target_halt(target); - if (retval != ERROR_OK) - return retval; } } - return aarch64_init_debug_access(target); + return retval; } static int aarch64_write_cpu_memory_slow(struct target *target, From c584686fd1d1dc7d2059e619de90f35516598134 Mon Sep 17 00:00:00 2001 From: Brent Roman Date: Wed, 1 Feb 2017 20:49:18 -0800 Subject: [PATCH 047/147] server: Improve signal handling under Linux Commit 5087a955 added custom signal handlers for the openocd server process. Before this commit, when openocd is run as a background process having the same controlling terminal as gdb, Control-C would be handled by gdb to stop target execution and return to the gdb prompt. However, after commit 5087a955, the SIGINT caused by pressing Control-C also terminates openocd, effectively crashing the debugging session. The only way to avoid this is run openocd in a different controling terminal or to detach openocd from its controlling terminal, thus losing all job control for the openocd process. This patch improves the server's handling of POSIX signals: 1) Keyboard generated signals (INT and QUIT) are ignored when server process has is no controlling terminal. 2) SIGHUP and SIGPIPE are handled to ensure that .quit functions for each interface are called if user's logs out of X session or there is a network failure. SIG_INT & SIG_QUIT still stop openocd when it is running in the foreground. Change-Id: I03ad645e62408fdaf4edc49a3550b89b287eda10 Signed-off-by: Brent Roman Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/3963 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/server/server.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/server/server.c b/src/server/server.c index 4e806563c..06a2f39de 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -505,7 +505,7 @@ int server_loop(struct command_context *command_context) for (service = services; service; service = service->next) { /* handle new connections on listeners */ if ((service->fd != -1) - && (FD_ISSET(service->fd, &read_fds))) { + && (FD_ISSET(service->fd, &read_fds))) { if (service->max_connections != 0) add_connection(service, command_context); else { @@ -563,21 +563,36 @@ int server_loop(struct command_context *command_context) return shutdown_openocd != 2 ? ERROR_OK : ERROR_FAIL; } +void sig_handler(int sig) +{ + /* store only first signal that hits us */ + if (!shutdown_openocd) { + last_signal = sig; + shutdown_openocd = 1; + LOG_DEBUG("Terminating on Signal %d", sig); + } else + LOG_DEBUG("Ignored extra Signal %d", sig); +} + + #ifdef _WIN32 BOOL WINAPI ControlHandler(DWORD dwCtrlType) { shutdown_openocd = 1; return TRUE; } +#else +static void sigkey_handler(int sig) +{ + /* ignore keystroke generated signals if not in foreground process group */ + + if (tcgetpgrp(STDIN_FILENO) > 0) + sig_handler(sig); + else + LOG_DEBUG("Ignored Signal %d", sig); +} #endif -void sig_handler(int sig) -{ - /* store only first signal that hits us */ - if (!last_signal) - last_signal = sig; - shutdown_openocd = 1; -} int server_preinit(void) { @@ -600,8 +615,13 @@ int server_preinit(void) SetConsoleCtrlHandler(ControlHandler, TRUE); signal(SIGBREAK, sig_handler); -#endif signal(SIGINT, sig_handler); +#else + signal(SIGHUP, sig_handler); + signal(SIGPIPE, sig_handler); + signal(SIGQUIT, sigkey_handler); + signal(SIGINT, sigkey_handler); +#endif signal(SIGTERM, sig_handler); signal(SIGABRT, sig_handler); @@ -743,7 +763,7 @@ static const struct command_registration server_command_handlers[] = { .mode = COMMAND_ANY, .usage = "[name]", .help = "Specify address by name on which to listen for " - "incoming TCP/IP connections", + "incoming TCP/IP connections", }, COMMAND_REGISTRATION_DONE }; From 42097baf19d4459a57f5224506e59a8347740f19 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 12 Jul 2018 16:15:45 +0200 Subject: [PATCH 048/147] armv7a: read ttbcr and ttb0/1 at every entry in debug state Commit bfc5c764df145f68835543119865eabe462e19c2 avoids reading ttbcr and ttb0/1 at every virt2phys translation by caching them, and it updates the cached values in armv7a_arch_state(). But the purpose of any (*arch_state)() method, thus including armv7a_arch_state(), is to only print out and inform the user about some architecture specific status. Moreover, to reduce the verbosity during a GDB session, the method (*arch_state)() is not executed anymore at debug state entry (check use of target->verbose_halt_msg in src/openocd.c), thus the state of translation table gets out-of-sync triggering Error: Address translation failure or even using a wrong address in the memory R/W operation. In addition, the commit above breaks the case of armv7r by calling armv7a_read_ttbcr() unconditionally. Fixed by moving in cortex_a_post_debug_entry() the call to armv7a_read_ttbcr() on armv7a case only. Remove the call to armv7a_read_ttbcr() in armv7a_identify_cache() since it is (conditionally) called only in the same procedure cortex_a_post_debug_entry(). Fixes: bfc5c764df14 ("armv7a: cache ttbcr and ttb0/1 on debug state entry") Change-Id: Ifc20eca190111832e339a01b7f85d28c1547c8ba Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4601 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/armv7a.c | 7 +------ src/target/armv7a.h | 1 + src/target/cortex_a.c | 3 +++ 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/target/armv7a.c b/src/target/armv7a.c index fab736310..eecfa7097 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -124,7 +124,7 @@ done: return retval; } -static int armv7a_read_ttbcr(struct target *target) +int armv7a_read_ttbcr(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; @@ -554,9 +554,6 @@ int armv7a_identify_cache(struct target *target) struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache); - if (!armv7a->is_armv7r) - armv7a_read_ttbcr(target); - retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; @@ -729,8 +726,6 @@ int armv7a_arch_state(struct target *target) arm_arch_state(target); - armv7a_read_ttbcr(target); - if (armv7a->is_armv7r) { LOG_USER("D-Cache: %s, I-Cache: %s", state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled], diff --git a/src/target/armv7a.h b/src/target/armv7a.h index 33f6f5dbe..57779c61a 100644 --- a/src/target/armv7a.h +++ b/src/target/armv7a.h @@ -194,6 +194,7 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val); int armv7a_handle_cache_info_command(struct command_context *cmd_ctx, struct armv7a_cache_common *armv7a_cache); +int armv7a_read_ttbcr(struct target *target); extern const struct command_registration armv7a_command_handlers[]; diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 8985051ee..21ce4fae8 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -1297,6 +1297,9 @@ static int cortex_a_post_debug_entry(struct target *target) LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, cortex_a->cp15_control_reg); cortex_a->cp15_control_reg_curr = cortex_a->cp15_control_reg; + if (!armv7a->is_armv7r) + armv7a_read_ttbcr(target); + if (armv7a->armv7a_mmu.armv7a_cache.info == -1) armv7a_identify_cache(target); From fe38562dbebfd02a6f0ca77af37bba642e5bb0f7 Mon Sep 17 00:00:00 2001 From: Darius Rad Date: Tue, 22 May 2018 16:38:57 -0400 Subject: [PATCH 049/147] Avoid dereferencing NULL pointer. If a NULL pointer is passed, don't attempt to increment it. This avoids passing the now not-NULL pointer on and eventually segfaulting. Also remove some unnecessary temporary variables. Change-Id: I268e225121aa283d59179bfae407ebf6959d3a4e Signed-off-by: Darius Rad Reviewed-on: http://openocd.zylin.com/4550 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- src/jtag/drivers/jtag_vpi.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c index a1787d496..1a42b3a05 100644 --- a/src/jtag/drivers/jtag_vpi.c +++ b/src/jtag/drivers/jtag_vpi.c @@ -204,23 +204,20 @@ static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift) static int jtag_vpi_queue_tdi(uint8_t *bits, int nb_bits, int tap_shift) { int nb_xfer = DIV_ROUND_UP(nb_bits, XFERT_MAX_SIZE * 8); - uint8_t *xmit_buffer = bits; - int xmit_nb_bits = nb_bits; - int i = 0; int retval; while (nb_xfer) { - if (nb_xfer == 1) { - retval = jtag_vpi_queue_tdi_xfer(&xmit_buffer[i], xmit_nb_bits, tap_shift); + retval = jtag_vpi_queue_tdi_xfer(bits, nb_bits, tap_shift); if (retval != ERROR_OK) return retval; } else { - retval = jtag_vpi_queue_tdi_xfer(&xmit_buffer[i], XFERT_MAX_SIZE * 8, NO_TAP_SHIFT); + retval = jtag_vpi_queue_tdi_xfer(bits, XFERT_MAX_SIZE * 8, NO_TAP_SHIFT); if (retval != ERROR_OK) return retval; - xmit_nb_bits -= XFERT_MAX_SIZE * 8; - i += XFERT_MAX_SIZE; + nb_bits -= XFERT_MAX_SIZE * 8; + if (bits) + bits += XFERT_MAX_SIZE; } nb_xfer--; From 4cd5c64122a0656bd6806c0d08c84711bf01328a Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 11 Jun 2018 12:47:52 -0700 Subject: [PATCH 050/147] Remove FSF mailing address. Checkpatch complains about this (FSF_MAILING_ADDRESS). Change-Id: Ib46a7704f9aed4ed16ce7733d43c58254a094149 Signed-off-by: Tim Newsome Reviewed-on: http://openocd.zylin.com/4559 Tested-by: jenkins Reviewed-by: Spencer Oliver --- contrib/libdcc/dcc_stdio.c | 4 +--- contrib/libdcc/dcc_stdio.h | 4 +--- contrib/libdcc/example.c | 4 +--- contrib/loaders/flash/at91sam7x/dcc.c | 4 +--- contrib/loaders/flash/at91sam7x/dcc.h | 4 +--- contrib/loaders/flash/at91sam7x/main.c | 4 +--- contrib/loaders/flash/at91sam7x/ocl.h | 4 +--- contrib/loaders/flash/at91sam7x/platform.h | 4 +--- contrib/loaders/flash/at91sam7x/samflash.c | 4 +--- contrib/loaders/flash/at91sam7x/samflash.h | 4 +--- contrib/remote_bitbang/remote_bitbang_sysfsgpio.c | 4 +--- testing/examples/ledtest-imx27ads/test.c | 4 +--- testing/examples/ledtest-imx31pdk/test.c | 4 +--- 13 files changed, 13 insertions(+), 39 deletions(-) diff --git a/contrib/libdcc/dcc_stdio.c b/contrib/libdcc/dcc_stdio.c index 5a457e7f6..7da78c647 100644 --- a/contrib/libdcc/dcc_stdio.c +++ b/contrib/libdcc/dcc_stdio.c @@ -17,9 +17,7 @@ * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ #include "dcc_stdio.h" diff --git a/contrib/libdcc/dcc_stdio.h b/contrib/libdcc/dcc_stdio.h index cb87ab358..f4a5d7e32 100644 --- a/contrib/libdcc/dcc_stdio.h +++ b/contrib/libdcc/dcc_stdio.h @@ -15,9 +15,7 @@ * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ #ifndef DCC_STDIO_H diff --git a/contrib/libdcc/example.c b/contrib/libdcc/example.c index 2cbef2053..99b7bf602 100644 --- a/contrib/libdcc/example.c +++ b/contrib/libdcc/example.c @@ -15,9 +15,7 @@ * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ #include "dcc_stdio.h" diff --git a/contrib/loaders/flash/at91sam7x/dcc.c b/contrib/loaders/flash/at91sam7x/dcc.c index 6ab2417b2..04a7f7a4d 100644 --- a/contrib/loaders/flash/at91sam7x/dcc.c +++ b/contrib/loaders/flash/at91sam7x/dcc.c @@ -13,9 +13,7 @@ * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ #include "dcc.h" diff --git a/contrib/loaders/flash/at91sam7x/dcc.h b/contrib/loaders/flash/at91sam7x/dcc.h index a3c13938b..428bf49ff 100644 --- a/contrib/loaders/flash/at91sam7x/dcc.h +++ b/contrib/loaders/flash/at91sam7x/dcc.h @@ -13,9 +13,7 @@ * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ #ifndef dccH #define dccH diff --git a/contrib/loaders/flash/at91sam7x/main.c b/contrib/loaders/flash/at91sam7x/main.c index c4b4dcf2f..831e03f14 100644 --- a/contrib/loaders/flash/at91sam7x/main.c +++ b/contrib/loaders/flash/at91sam7x/main.c @@ -13,9 +13,7 @@ * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ #include "platform.h" diff --git a/contrib/loaders/flash/at91sam7x/ocl.h b/contrib/loaders/flash/at91sam7x/ocl.h index 1fe459669..ef30c33f4 100644 --- a/contrib/loaders/flash/at91sam7x/ocl.h +++ b/contrib/loaders/flash/at91sam7x/ocl.h @@ -13,9 +13,7 @@ * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ #ifndef OCL_H #define OCL_H diff --git a/contrib/loaders/flash/at91sam7x/platform.h b/contrib/loaders/flash/at91sam7x/platform.h index 2b26e4bd5..3dfa4dc08 100644 --- a/contrib/loaders/flash/at91sam7x/platform.h +++ b/contrib/loaders/flash/at91sam7x/platform.h @@ -13,9 +13,7 @@ * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ #ifndef platformH #define platformH diff --git a/contrib/loaders/flash/at91sam7x/samflash.c b/contrib/loaders/flash/at91sam7x/samflash.c index 49c84c812..30953942a 100644 --- a/contrib/loaders/flash/at91sam7x/samflash.c +++ b/contrib/loaders/flash/at91sam7x/samflash.c @@ -13,9 +13,7 @@ * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ #include "samflash.h" diff --git a/contrib/loaders/flash/at91sam7x/samflash.h b/contrib/loaders/flash/at91sam7x/samflash.h index 1de02ae54..18973a70d 100644 --- a/contrib/loaders/flash/at91sam7x/samflash.h +++ b/contrib/loaders/flash/at91sam7x/samflash.h @@ -13,9 +13,7 @@ * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ #ifndef samflashH #define samflashH diff --git a/contrib/remote_bitbang/remote_bitbang_sysfsgpio.c b/contrib/remote_bitbang/remote_bitbang_sysfsgpio.c index 664130703..5c717ce0e 100644 --- a/contrib/remote_bitbang/remote_bitbang_sysfsgpio.c +++ b/contrib/remote_bitbang/remote_bitbang_sysfsgpio.c @@ -13,9 +13,7 @@ * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ /* diff --git a/testing/examples/ledtest-imx27ads/test.c b/testing/examples/ledtest-imx27ads/test.c index 92deaf4cf..a3dd52234 100644 --- a/testing/examples/ledtest-imx27ads/test.c +++ b/testing/examples/ledtest-imx27ads/test.c @@ -13,9 +13,7 @@ * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ void delay() diff --git a/testing/examples/ledtest-imx31pdk/test.c b/testing/examples/ledtest-imx31pdk/test.c index c80cc611f..4135f89c0 100644 --- a/testing/examples/ledtest-imx31pdk/test.c +++ b/testing/examples/ledtest-imx31pdk/test.c @@ -13,9 +13,7 @@ * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ void delay() From c5658364b2c7fe19b677f762d6bcd579cb2e17e1 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 16 Apr 2018 22:54:22 +0200 Subject: [PATCH 051/147] drivers: cmsis_dap_usb: implement cmd JTAG_TMS Simply add a wrapper around cmsis_dap_cmd_DAP_SWJ_Sequence() Change-Id: Icf86f84b24e9fec56e2f9e155396aac34b0e06d2 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4517 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/jtag/drivers/cmsis_dap_usb.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index 231e7c81b..928389faf 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -1444,6 +1444,12 @@ static void cmsis_dap_execute_stableclocks(struct jtag_command *cmd) cmsis_dap_stableclocks(cmd->cmd.runtest->num_cycles); } +static void cmsis_dap_execute_tms(struct jtag_command *cmd) +{ + DEBUG_JTAG_IO("TMS: %d bits", cmd->cmd.tms->num_bits); + cmsis_dap_cmd_DAP_SWJ_Sequence(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits); +} + /* TODO: Is there need to call cmsis_dap_flush() for the JTAG_PATHMOVE, * JTAG_RUNTEST, JTAG_STABLECLOCKS? */ static void cmsis_dap_execute_command(struct jtag_command *cmd) @@ -1474,6 +1480,8 @@ static void cmsis_dap_execute_command(struct jtag_command *cmd) cmsis_dap_execute_stableclocks(cmd); break; case JTAG_TMS: + cmsis_dap_execute_tms(cmd); + break; default: LOG_ERROR("BUG: unknown JTAG command type 0x%X encountered", cmd->type); exit(-1); @@ -1636,6 +1644,7 @@ static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL }; struct jtag_interface cmsis_dap_interface = { .name = "cmsis-dap", + .supported = DEBUG_CAP_TMS_SEQ, .commands = cmsis_dap_command_handlers, .swd = &cmsis_dap_swd_driver, .transports = cmsis_dap_transport, From 9363705820d9552bd24a4e876041a90a881ede55 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 10 Jun 2018 14:39:26 +0200 Subject: [PATCH 052/147] arm_adi_v5: put SWJ-DP back to JTAG mode at exit When SWD mode is used, current OpenOCD code left the SWJ-DP in SWD mode at exit. Also, current code is unable to switch back the SWJ-DP in JTAG at next run, thus a power cycle of both target and interface is required in order to run OpenOCD in JTAG mode again. Put the SWJ-DP back to JTAG mode before exit from OpenOCD. Use switch_seq(SWD_TO_JTAG) instead of dap_to_jtag(), because the latter is not implemented on some interfaces. This is aligned with the use of switch_seq(JTAG_TO_SWD) in swd_connect(). Change-Id: I55d3faebe60d6402037ec39dd9700dc5f17c53b0 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4493 Tested-by: jenkins Reviewed-by: Bohdan Tymkiv Reviewed-by: Matthias Welwarsky --- src/target/adi_v5_swd.c | 11 +++++++++++ src/target/arm_adi_v5.h | 3 +++ src/target/arm_dap.c | 5 +++++ 3 files changed, 19 insertions(+) diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index 0de272dd9..b520223b0 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -276,6 +276,16 @@ static int swd_run(struct adiv5_dap *dap) return swd_run_inner(dap); } +/** Put the SWJ-DP back to JTAG mode */ +static void swd_quit(struct adiv5_dap *dap) +{ + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + + swd->switch_seq(SWD_TO_JTAG); + /* flush the queue before exit */ + swd->run(); +} + const struct dap_ops swd_dap_ops = { .connect = swd_connect, .queue_dp_read = swd_queue_dp_read, @@ -284,6 +294,7 @@ const struct dap_ops swd_dap_ops = { .queue_ap_write = swd_queue_ap_write, .queue_ap_abort = swd_queue_ap_abort, .run = swd_run, + .quit = swd_quit, }; /* diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index 22c316630..883ac8b5d 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -286,6 +286,9 @@ struct dap_ops { /** Executes all queued DAP operations but doesn't check * sticky error conditions */ int (*sync)(struct adiv5_dap *dap); + + /** Optional; called at OpenOCD exit */ + void (*quit)(struct adiv5_dap *dap); }; /* diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c index 8c081800f..3be4d7199 100644 --- a/src/target/arm_dap.c +++ b/src/target/arm_dap.c @@ -132,8 +132,13 @@ static int dap_init_all(void) int dap_cleanup_all(void) { struct arm_dap_object *obj, *tmp; + struct adiv5_dap *dap; list_for_each_entry_safe(obj, tmp, &all_dap, lh) { + dap = &obj->dap; + if (dap->ops && dap->ops->quit) + dap->ops->quit(dap); + free(obj->name); free(obj); } From a51ab8ddf63a0d60eaaf3b8f3eedcada1e773c20 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 18 Jul 2018 13:34:23 -0700 Subject: [PATCH 053/147] Add RISC-V support. This supports both 0.11 and 0.13 versions of the debug spec. Support for `-rtos riscv` will come in a separate commit since it was easy to separate out, and is likely to be more controversial. Flash support for the SiFive boards will also come in a later commit. Change-Id: I1d38fe669c2041b4e21a5c54a091594aac3e2190 Signed-off-by: Tim Newsome Reviewed-on: http://openocd.zylin.com/4578 Tested-by: jenkins Reviewed-by: Liviu Ionescu Reviewed-by: Matthias Welwarsky --- doc/openocd.texi | 78 + src/helper/log.h | 2 + src/target/Makefile.am | 5 +- src/target/riscv/Makefile.am | 16 + src/target/riscv/asm.h | 38 + src/target/riscv/batch.c | 172 ++ src/target/riscv/batch.h | 64 + src/target/riscv/debug_defines.h | 1414 ++++++++++++ src/target/riscv/encoding.h | 1473 +++++++++++++ src/target/riscv/gdb_regs.h | 93 + src/target/riscv/opcodes.h | 310 +++ src/target/riscv/program.c | 162 ++ src/target/riscv/program.h | 75 + src/target/riscv/riscv-011.c | 2328 ++++++++++++++++++++ src/target/riscv/riscv-013.c | 3036 ++++++++++++++++++++++++++ src/target/riscv/riscv.c | 2512 +++++++++++++++++++++ src/target/riscv/riscv.h | 262 +++ src/target/riscv/riscv_semihosting.c | 194 ++ src/target/target.c | 2 + tcl/board/sifive-e31arty.cfg | 22 + tcl/board/sifive-e51arty.cfg | 22 + tcl/board/sifive-hifive1.cfg | 34 + 22 files changed, 12313 insertions(+), 1 deletion(-) create mode 100644 src/target/riscv/Makefile.am create mode 100644 src/target/riscv/asm.h create mode 100644 src/target/riscv/batch.c create mode 100644 src/target/riscv/batch.h create mode 100644 src/target/riscv/debug_defines.h create mode 100644 src/target/riscv/encoding.h create mode 100644 src/target/riscv/gdb_regs.h create mode 100644 src/target/riscv/opcodes.h create mode 100644 src/target/riscv/program.c create mode 100644 src/target/riscv/program.h create mode 100644 src/target/riscv/riscv-011.c create mode 100644 src/target/riscv/riscv-013.c create mode 100644 src/target/riscv/riscv.c create mode 100644 src/target/riscv/riscv.h create mode 100644 src/target/riscv/riscv_semihosting.c create mode 100644 tcl/board/sifive-e31arty.cfg create mode 100644 tcl/board/sifive-e51arty.cfg create mode 100644 tcl/board/sifive-hifive1.cfg diff --git a/doc/openocd.texi b/doc/openocd.texi index 15cf74268..43ebf8cb2 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8946,6 +8946,84 @@ Display all registers in @emph{group}. "timer" or any new group created with addreg command. @end deffn +@section RISC-V Architecture + +@uref{http://riscv.org/, RISC-V} is a free and open ISA. OpenOCD supports JTAG +debug of targets that implement version 0.11 and 0.13 of the RISC-V Debug +Specification. + +@subsection RISC-V Terminology + +A @emph{hart} is a hardware thread. A hart may share resources (eg. FPU) with +another hart, or may be a separate core. RISC-V treats those the same, and +OpenOCD exposes each hart as a separate core. + +@subsection RISC-V Debug Configuration Commands + +@deffn Command {riscv expose_csrs} n0[-m0][,n1[-m1]]... +Configure a list of inclusive ranges for CSRs to expose in addition to the +standard ones. This must be executed before `init`. + +By default OpenOCD attempts to expose only CSRs that are mentioned in a spec, +and then only if the corresponding extension appears to be implemented. This +command can be used if OpenOCD gets this wrong, or a target implements custom +CSRs. +@end deffn + +@deffn Command {riscv set_command_timeout_sec} [seconds] +Set the wall-clock timeout (in seconds) for individual commands. The default +should work fine for all but the slowest targets (eg. simulators). +@end deffn + +@deffn Command {riscv set_reset_timeout_sec} [seconds] +Set the maximum time to wait for a hart to come out of reset after reset is +deasserted. +@end deffn + +@deffn Command {riscv set_scratch_ram} none|[address] +Set the address of 16 bytes of scratch RAM the debugger can use, or 'none'. +This is used to access 64-bit floating point registers on 32-bit targets. +@end deffn + +@deffn Command {riscv set_prefer_sba} on|off +When on, prefer to use System Bus Access to access memory. When off, prefer to +use the Program Buffer to access memory. +@end deffn + +@subsection RISC-V Authentication Commands + +The following commands can be used to authenticate to a RISC-V system. Eg. a +trivial challenge-response protocol could be implemented as follows in a +configuration file, immediately following @command{init}: +@example +set challenge [ocd_riscv authdata_read] +riscv authdata_write [expr $challenge + 1] +@end example + +@deffn Command {riscv authdata_read} +Return the 32-bit value read from authdata. Note that to get read value back in +a TCL script, it needs to be invoked as @command{ocd_riscv authdata_read}. +@end deffn + +@deffn Command {riscv authdata_write} value +Write the 32-bit value to authdata. +@end deffn + +@subsection RISC-V DMI Commands + +The following commands allow direct access to the Debug Module Interface, which +can be used to interact with custom debug features. + +@deffn Command {riscv dmi_read} +Perform a 32-bit DMI read at address, returning the value. Note that to get +read value back in a TCL script, it needs to be invoked as @command{ocd_riscv +dmi_read}. +@end deffn + +@deffn Command {riscv dmi_write} address value +Perform a 32-bit DMI write of value at address. +@end deffn + @anchor{softwaredebugmessagesandtracing} @section Software Debug Messages and Tracing @cindex Linux-ARM DCC support diff --git a/src/helper/log.h b/src/helper/log.h index 512bcc512..d60587f72 100644 --- a/src/helper/log.h +++ b/src/helper/log.h @@ -149,6 +149,8 @@ extern int debug_level; */ #define ERROR_FAIL (-4) #define ERROR_WAIT (-5) +/* ERROR_TIMEOUT is already taken by winerror.h. */ +#define ERROR_TIMEOUT_REACHED (-6) #endif /* OPENOCD_HELPER_LOG_H */ diff --git a/src/target/Makefile.am b/src/target/Makefile.am index fcc23adbe..b1119e7df 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -4,7 +4,9 @@ else OOCD_TRACE_FILES = endif -%C%_libtarget_la_LIBADD = %D%/openrisc/libopenrisc.la +%C%_libtarget_la_LIBADD = %D%/openrisc/libopenrisc.la \ + %D%/riscv/libriscv.la + STARTUP_TCL_SRCS += %D%/startup.tcl @@ -218,3 +220,4 @@ INTEL_IA32_SRC = \ %D%/arm_cti.h include %D%/openrisc/Makefile.am +include %D%/riscv/Makefile.am diff --git a/src/target/riscv/Makefile.am b/src/target/riscv/Makefile.am new file mode 100644 index 000000000..83f1a8ca3 --- /dev/null +++ b/src/target/riscv/Makefile.am @@ -0,0 +1,16 @@ +noinst_LTLIBRARIES += %D%/libriscv.la +%C%_libriscv_la_SOURCES = \ + %D%/asm.h \ + %D%/batch.h \ + %D%/debug_defines.h \ + %D%/encoding.h \ + %D%/gdb_regs.h \ + %D%/opcodes.h \ + %D%/program.h \ + %D%/riscv.h \ + %D%/batch.c \ + %D%/program.c \ + %D%/riscv-011.c \ + %D%/riscv-013.c \ + %D%/riscv.c \ + %D%/riscv_semihosting.c diff --git a/src/target/riscv/asm.h b/src/target/riscv/asm.h new file mode 100644 index 000000000..d81aa0285 --- /dev/null +++ b/src/target/riscv/asm.h @@ -0,0 +1,38 @@ +#ifndef TARGET__RISCV__ASM_H +#define TARGET__RISCV__ASM_H + +#include "riscv.h" + +/*** Version-independent functions that we don't want in the main address space. ***/ + +static uint32_t load(const struct target *target, unsigned int rd, + unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t load(const struct target *target, unsigned int rd, + unsigned int base, uint16_t offset) +{ + switch (riscv_xlen(target)) { + case 32: + return lw(rd, base, offset); + case 64: + return ld(rd, base, offset); + } + assert(0); + return 0; /* Silence -Werror=return-type */ +} + +static uint32_t store(const struct target *target, unsigned int src, + unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t store(const struct target *target, unsigned int src, + unsigned int base, uint16_t offset) +{ + switch (riscv_xlen(target)) { + case 32: + return sw(src, base, offset); + case 64: + return sd(src, base, offset); + } + assert(0); + return 0; /* Silence -Werror=return-type */ +} + +#endif diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c new file mode 100644 index 000000000..9327cb38b --- /dev/null +++ b/src/target/riscv/batch.c @@ -0,0 +1,172 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "batch.h" +#include "debug_defines.h" +#include "riscv.h" + +#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) +#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) + +static void dump_field(const struct scan_field *field); + +struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_t idle) +{ + scans += 4; + struct riscv_batch *out = malloc(sizeof(*out)); + memset(out, 0, sizeof(*out)); + out->target = target; + out->allocated_scans = scans; + out->used_scans = 0; + out->idle_count = idle; + out->data_out = malloc(sizeof(*out->data_out) * (scans) * sizeof(uint64_t)); + out->data_in = malloc(sizeof(*out->data_in) * (scans) * sizeof(uint64_t)); + out->fields = malloc(sizeof(*out->fields) * (scans)); + out->last_scan = RISCV_SCAN_TYPE_INVALID; + out->read_keys = malloc(sizeof(*out->read_keys) * (scans)); + out->read_keys_used = 0; + return out; +} + +void riscv_batch_free(struct riscv_batch *batch) +{ + free(batch->data_in); + free(batch->data_out); + free(batch->fields); + free(batch); +} + +bool riscv_batch_full(struct riscv_batch *batch) +{ + return batch->used_scans > (batch->allocated_scans - 4); +} + +int riscv_batch_run(struct riscv_batch *batch) +{ + if (batch->used_scans == 0) { + LOG_DEBUG("Ignoring empty batch."); + return ERROR_OK; + } + + keep_alive(); + + LOG_DEBUG("running a batch of %ld scans", (long)batch->used_scans); + riscv_batch_add_nop(batch); + + for (size_t i = 0; i < batch->used_scans; ++i) { + jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE); + if (batch->idle_count > 0) + jtag_add_runtest(batch->idle_count, TAP_IDLE); + } + + LOG_DEBUG("executing queue"); + if (jtag_execute_queue() != ERROR_OK) { + LOG_ERROR("Unable to execute JTAG queue"); + return ERROR_FAIL; + } + + for (size_t i = 0; i < batch->used_scans; ++i) + dump_field(batch->fields + i); + + return ERROR_OK; +} + +void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data) +{ + assert(batch->used_scans < batch->allocated_scans); + struct scan_field *field = batch->fields + batch->used_scans; + field->num_bits = riscv_dmi_write_u64_bits(batch->target); + field->out_value = (void *)(batch->data_out + batch->used_scans * sizeof(uint64_t)); + field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t)); + riscv_fill_dmi_write_u64(batch->target, (char *)field->out_value, address, data); + riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value); + batch->last_scan = RISCV_SCAN_TYPE_WRITE; + batch->used_scans++; +} + +size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address) +{ + assert(batch->used_scans < batch->allocated_scans); + struct scan_field *field = batch->fields + batch->used_scans; + field->num_bits = riscv_dmi_write_u64_bits(batch->target); + field->out_value = (void *)(batch->data_out + batch->used_scans * sizeof(uint64_t)); + field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t)); + riscv_fill_dmi_read_u64(batch->target, (char *)field->out_value, address); + riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value); + batch->last_scan = RISCV_SCAN_TYPE_READ; + batch->used_scans++; + + /* FIXME We get the read response back on the next scan. For now I'm + * just sticking a NOP in there, but this should be coelesced away. */ + riscv_batch_add_nop(batch); + + batch->read_keys[batch->read_keys_used] = batch->used_scans - 1; + LOG_DEBUG("read key %u for batch 0x%p is %u (0x%p)", + (unsigned) batch->read_keys_used, batch, (unsigned) (batch->used_scans - 1), + batch->data_in + sizeof(uint64_t) * (batch->used_scans + 1)); + return batch->read_keys_used++; +} + +uint64_t riscv_batch_get_dmi_read(struct riscv_batch *batch, size_t key) +{ + assert(key < batch->read_keys_used); + size_t index = batch->read_keys[key]; + assert(index <= batch->used_scans); + uint8_t *base = batch->data_in + 8 * index; + return base[0] | + ((uint64_t) base[1]) << 8 | + ((uint64_t) base[2]) << 16 | + ((uint64_t) base[3]) << 24 | + ((uint64_t) base[4]) << 32 | + ((uint64_t) base[5]) << 40 | + ((uint64_t) base[6]) << 48 | + ((uint64_t) base[7]) << 56; +} + +void riscv_batch_add_nop(struct riscv_batch *batch) +{ + assert(batch->used_scans < batch->allocated_scans); + struct scan_field *field = batch->fields + batch->used_scans; + field->num_bits = riscv_dmi_write_u64_bits(batch->target); + field->out_value = (void *)(batch->data_out + batch->used_scans * sizeof(uint64_t)); + field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t)); + riscv_fill_dmi_nop_u64(batch->target, (char *)field->out_value); + riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value); + batch->last_scan = RISCV_SCAN_TYPE_NOP; + batch->used_scans++; + LOG_DEBUG(" added NOP with in_value=0x%p", field->in_value); +} + +void dump_field(const struct scan_field *field) +{ + static const char * const op_string[] = {"-", "r", "w", "?"}; + static const char * const status_string[] = {"+", "?", "F", "b"}; + + if (debug_level < LOG_LVL_DEBUG) + return; + + assert(field->out_value != NULL); + uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits); + unsigned int out_op = get_field(out, DTM_DMI_OP); + unsigned int out_data = get_field(out, DTM_DMI_DATA); + unsigned int out_address = out >> DTM_DMI_ADDRESS_OFFSET; + + if (field->in_value) { + uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits); + unsigned int in_op = get_field(in, DTM_DMI_OP); + unsigned int in_data = get_field(in, DTM_DMI_DATA); + unsigned int in_address = in >> DTM_DMI_ADDRESS_OFFSET; + + log_printf_lf(LOG_LVL_DEBUG, + __FILE__, __LINE__, __PRETTY_FUNCTION__, + "%db %s %08x @%02x -> %s %08x @%02x", + field->num_bits, + op_string[out_op], out_data, out_address, + status_string[in_op], in_data, in_address); + } else { + log_printf_lf(LOG_LVL_DEBUG, + __FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %s %08x @%02x -> ?", + field->num_bits, op_string[out_op], out_data, out_address); + } +} diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h new file mode 100644 index 000000000..70690a601 --- /dev/null +++ b/src/target/riscv/batch.h @@ -0,0 +1,64 @@ +#ifndef TARGET__RISCV__SCANS_H +#define TARGET__RISCV__SCANS_H + +#include "target/target.h" +#include "jtag/jtag.h" + +enum riscv_scan_type { + RISCV_SCAN_TYPE_INVALID, + RISCV_SCAN_TYPE_NOP, + RISCV_SCAN_TYPE_READ, + RISCV_SCAN_TYPE_WRITE, +}; + +/* A batch of multiple JTAG scans, which are grouped together to avoid the + * overhead of some JTAG adapters when sending single commands. This is + * designed to support block copies, as that's what we actually need to go + * fast. */ +struct riscv_batch { + struct target *target; + + size_t allocated_scans; + size_t used_scans; + + size_t idle_count; + + uint8_t *data_out; + uint8_t *data_in; + struct scan_field *fields; + + /* In JTAG we scan out the previous value's output when performing a + * scan. This is a pain for users, so we just provide them the + * illusion of not having to do this by eliding all but the last NOP. + * */ + enum riscv_scan_type last_scan; + + /* The read keys. */ + size_t *read_keys; + size_t read_keys_used; +}; + +/* Allocates (or frees) a new scan set. "scans" is the maximum number of JTAG + * scans that can be issued to this object, and idle is the number of JTAG idle + * cycles between every real scan. */ +struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_t idle); +void riscv_batch_free(struct riscv_batch *batch); + +/* Checks to see if this batch is full. */ +bool riscv_batch_full(struct riscv_batch *batch); + +/* Executes this scan batch. */ +int riscv_batch_run(struct riscv_batch *batch); + +/* Adds a DMI write to this batch. */ +void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data); + +/* DMI reads must be handled in two parts: the first one schedules a read and + * provides a key, the second one actually obtains the value of that read .*/ +size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address); +uint64_t riscv_batch_get_dmi_read(struct riscv_batch *batch, size_t key); + +/* Scans in a NOP. */ +void riscv_batch_add_nop(struct riscv_batch *batch); + +#endif diff --git a/src/target/riscv/debug_defines.h b/src/target/riscv/debug_defines.h new file mode 100644 index 000000000..d6ddd4ff1 --- /dev/null +++ b/src/target/riscv/debug_defines.h @@ -0,0 +1,1414 @@ +#define DTM_IDCODE 0x01 +/* +* Identifies the release version of this part. + */ +#define DTM_IDCODE_VERSION_OFFSET 28 +#define DTM_IDCODE_VERSION_LENGTH 4 +#define DTM_IDCODE_VERSION (0xfU << DTM_IDCODE_VERSION_OFFSET) +/* +* Identifies the designer's part number of this part. + */ +#define DTM_IDCODE_PARTNUMBER_OFFSET 12 +#define DTM_IDCODE_PARTNUMBER_LENGTH 16 +#define DTM_IDCODE_PARTNUMBER (0xffffU << DTM_IDCODE_PARTNUMBER_OFFSET) +/* +* Identifies the designer/manufacturer of this part. Bits 6:0 must be +* bits 6:0 of the designer/manufacturer's Identification Code as +* assigned by JEDEC Standard JEP106. Bits 10:7 contain the modulo-16 +* count of the number of continuation characters (0x7f) in that same +* Identification Code. + */ +#define DTM_IDCODE_MANUFID_OFFSET 1 +#define DTM_IDCODE_MANUFID_LENGTH 11 +#define DTM_IDCODE_MANUFID (0x7ffU << DTM_IDCODE_MANUFID_OFFSET) +#define DTM_IDCODE_1_OFFSET 0 +#define DTM_IDCODE_1_LENGTH 1 +#define DTM_IDCODE_1 (0x1U << DTM_IDCODE_1_OFFSET) +#define DTM_DTMCS 0x10 +/* +* Writing 1 to this bit does a hard reset of the DTM, +* causing the DTM to forget about any outstanding DMI transactions. +* In general this should only be used when the Debugger has +* reason to expect that the outstanding DMI transaction will never +* complete (e.g. a reset condition caused an inflight DMI transaction to +* be cancelled). + */ +#define DTM_DTMCS_DMIHARDRESET_OFFSET 17 +#define DTM_DTMCS_DMIHARDRESET_LENGTH 1 +#define DTM_DTMCS_DMIHARDRESET (0x1U << DTM_DTMCS_DMIHARDRESET_OFFSET) +/* +* Writing 1 to this bit clears the sticky error state +* and allows the DTM to retry or complete the previous +* transaction. + */ +#define DTM_DTMCS_DMIRESET_OFFSET 16 +#define DTM_DTMCS_DMIRESET_LENGTH 1 +#define DTM_DTMCS_DMIRESET (0x1U << DTM_DTMCS_DMIRESET_OFFSET) +/* +* This is a hint to the debugger of the minimum number of +* cycles a debugger should spend in +* Run-Test/Idle after every DMI scan to avoid a `busy' +* return code (\Fdmistat of 3). A debugger must still +* check \Fdmistat when necessary. +* +* 0: It is not necessary to enter Run-Test/Idle at all. +* +* 1: Enter Run-Test/Idle and leave it immediately. +* +* 2: Enter Run-Test/Idle and stay there for 1 cycle before leaving. +* +* And so on. + */ +#define DTM_DTMCS_IDLE_OFFSET 12 +#define DTM_DTMCS_IDLE_LENGTH 3 +#define DTM_DTMCS_IDLE (0x7U << DTM_DTMCS_IDLE_OFFSET) +/* +* 0: No error. +* +* 1: Reserved. Interpret the same as 2. +* +* 2: An operation failed (resulted in \Fop of 2). +* +* 3: An operation was attempted while a DMI access was still in +* progress (resulted in \Fop of 3). + */ +#define DTM_DTMCS_DMISTAT_OFFSET 10 +#define DTM_DTMCS_DMISTAT_LENGTH 2 +#define DTM_DTMCS_DMISTAT (0x3U << DTM_DTMCS_DMISTAT_OFFSET) +/* +* The size of \Faddress in \Rdmi. + */ +#define DTM_DTMCS_ABITS_OFFSET 4 +#define DTM_DTMCS_ABITS_LENGTH 6 +#define DTM_DTMCS_ABITS (0x3fU << DTM_DTMCS_ABITS_OFFSET) +/* +* 0: Version described in spec version 0.11. +* +* 1: Version described in spec version 0.13 (and later?), which +* reduces the DMI data width to 32 bits. +* +* 15: Version not described in any available version of this spec. + */ +#define DTM_DTMCS_VERSION_OFFSET 0 +#define DTM_DTMCS_VERSION_LENGTH 4 +#define DTM_DTMCS_VERSION (0xfU << DTM_DTMCS_VERSION_OFFSET) +#define DTM_DMI 0x11 +/* +* Address used for DMI access. In Update-DR this value is used +* to access the DM over the DMI. + */ +#define DTM_DMI_ADDRESS_OFFSET 34 +#define DTM_DMI_ADDRESS_LENGTH abits +#define DTM_DMI_ADDRESS (((1L<> lo) & ((1 << (hi+1-lo)) - 1); +} + +static uint32_t bit(uint32_t value, unsigned int b) +{ + return (value >> b) & 1; +} + +static uint32_t jal(unsigned int rd, uint32_t imm) __attribute__ ((unused)); +static uint32_t jal(unsigned int rd, uint32_t imm) +{ + return (bit(imm, 20) << 31) | + (bits(imm, 10, 1) << 21) | + (bit(imm, 11) << 20) | + (bits(imm, 19, 12) << 12) | + (rd << 7) | + MATCH_JAL; +} + +static uint32_t csrsi(unsigned int csr, uint16_t imm) __attribute__ ((unused)); +static uint32_t csrsi(unsigned int csr, uint16_t imm) +{ + return (csr << 20) | + (bits(imm, 4, 0) << 15) | + MATCH_CSRRSI; +} + +static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 5) << 25) | + (src << 20) | + (base << 15) | + (bits(offset, 4, 0) << 7) | + MATCH_SW; +} + +static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 5) << 25) | + (src << 20) | + (base << 15) | + (bits(offset, 4, 0) << 7) | + MATCH_SD; +} + +static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 5) << 25) | + (src << 20) | + (base << 15) | + (bits(offset, 4, 0) << 7) | + MATCH_SH; +} + +static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 5) << 25) | + (src << 20) | + (base << 15) | + (bits(offset, 4, 0) << 7) | + MATCH_SB; +} + +static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 0) << 20) | + (base << 15) | + (bits(rd, 4, 0) << 7) | + MATCH_LD; +} + +static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 0) << 20) | + (base << 15) | + (bits(rd, 4, 0) << 7) | + MATCH_LW; +} + +static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 0) << 20) | + (base << 15) | + (bits(rd, 4, 0) << 7) | + MATCH_LH; +} + +static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 0) << 20) | + (base << 15) | + (bits(rd, 4, 0) << 7) | + MATCH_LB; +} + +static uint32_t csrw(unsigned int source, unsigned int csr) __attribute__ ((unused)); +static uint32_t csrw(unsigned int source, unsigned int csr) +{ + return (csr << 20) | (source << 15) | MATCH_CSRRW; +} + +static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused)); +static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) +{ + return (bits(imm, 11, 0) << 20) | + (src << 15) | + (dest << 7) | + MATCH_ADDI; +} + +static uint32_t csrr(unsigned int rd, unsigned int csr) __attribute__ ((unused)); +static uint32_t csrr(unsigned int rd, unsigned int csr) +{ + return (csr << 20) | (rd << 7) | MATCH_CSRRS; +} + +static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused)); +static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) +{ + return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRS; +} + +static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused)); +static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) +{ + return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRW; +} + +static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 5) << 25) | + (bits(src, 4, 0) << 20) | + (base << 15) | + (bits(offset, 4, 0) << 7) | + MATCH_FSW; +} + +static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 5) << 25) | + (bits(src, 4, 0) << 20) | + (base << 15) | + (bits(offset, 4, 0) << 7) | + MATCH_FSD; +} + +static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 0) << 20) | + (base << 15) | + (bits(dest, 4, 0) << 7) | + MATCH_FLW; +} + +static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 0) << 20) | + (base << 15) | + (bits(dest, 4, 0) << 7) | + MATCH_FLD; +} + +static uint32_t fmv_x_w(unsigned dest, unsigned src) __attribute__ ((unused)); +static uint32_t fmv_x_w(unsigned dest, unsigned src) +{ + return src << 15 | + dest << 7 | + MATCH_FMV_X_W; +} + +static uint32_t fmv_x_d(unsigned dest, unsigned src) __attribute__ ((unused)); +static uint32_t fmv_x_d(unsigned dest, unsigned src) +{ + return src << 15 | + dest << 7 | + MATCH_FMV_X_D; +} + +static uint32_t fmv_w_x(unsigned dest, unsigned src) __attribute__ ((unused)); +static uint32_t fmv_w_x(unsigned dest, unsigned src) +{ + return src << 15 | + dest << 7 | + MATCH_FMV_W_X; +} + +static uint32_t fmv_d_x(unsigned dest, unsigned src) __attribute__ ((unused)); +static uint32_t fmv_d_x(unsigned dest, unsigned src) +{ + return src << 15 | + dest << 7 | + MATCH_FMV_D_X; +} + +static uint32_t ebreak(void) __attribute__ ((unused)); +static uint32_t ebreak(void) +{ + return MATCH_EBREAK; +} +static uint32_t ebreak_c(void) __attribute__ ((unused)); +static uint32_t ebreak_c(void) +{ + return MATCH_C_EBREAK; +} + +static uint32_t fence_i(void) __attribute__ ((unused)); +static uint32_t fence_i(void) +{ + return MATCH_FENCE_I; +} + +static uint32_t lui(unsigned int dest, uint32_t imm) __attribute__ ((unused)); +static uint32_t lui(unsigned int dest, uint32_t imm) +{ + return (bits(imm, 19, 0) << 12) | + (dest << 7) | + MATCH_LUI; +} + +/* +static uint32_t csrci(unsigned int csr, uint16_t imm) __attribute__ ((unused)); +static uint32_t csrci(unsigned int csr, uint16_t imm) +{ + return (csr << 20) | + (bits(imm, 4, 0) << 15) | + MATCH_CSRRCI; +} + +static uint32_t li(unsigned int dest, uint16_t imm) __attribute__ ((unused)); +static uint32_t li(unsigned int dest, uint16_t imm) +{ + return addi(dest, 0, imm); +} + +static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); +static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 5) << 25) | + (bits(src, 4, 0) << 20) | + (base << 15) | + (bits(offset, 4, 0) << 7) | + MATCH_FSD; +} + +static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused)); +static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm) +{ + return (bits(imm, 11, 0) << 20) | + (src << 15) | + (dest << 7) | + MATCH_ORI; +} + +static uint32_t nop(void) __attribute__ ((unused)); +static uint32_t nop(void) +{ + return addi(0, 0, 0); +} +*/ + +static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused)); +static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) +{ + return (bits(imm, 11, 0) << 20) | + (src << 15) | + (dest << 7) | + MATCH_XORI; +} + +static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) __attribute__ ((unused)); +static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) +{ + return (bits(shamt, 4, 0) << 20) | + (src << 15) | + (dest << 7) | + MATCH_SRLI; +} + +static uint32_t fence(void) __attribute__((unused)); +static uint32_t fence(void) +{ + return MATCH_FENCE; +} + +static uint32_t auipc(unsigned int dest) __attribute__((unused)); +static uint32_t auipc(unsigned int dest) +{ + return MATCH_AUIPC | (dest << 7); +} diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c new file mode 100644 index 000000000..5e899b252 --- /dev/null +++ b/src/target/riscv/program.c @@ -0,0 +1,162 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "target/target.h" +#include "target/register.h" +#include "riscv.h" +#include "program.h" +#include "helper/log.h" + +#include "asm.h" +#include "encoding.h" + +/* Program interface. */ +int riscv_program_init(struct riscv_program *p, struct target *target) +{ + memset(p, 0, sizeof(*p)); + p->target = target; + p->instruction_count = 0; + p->target_xlen = riscv_xlen(target); + for (size_t i = 0; i < RISCV_REGISTER_COUNT; ++i) + p->writes_xreg[i] = 0; + + for (size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i) + p->debug_buffer[i] = -1; + + return ERROR_OK; +} + +int riscv_program_write(struct riscv_program *program) +{ + for (unsigned i = 0; i < program->instruction_count; ++i) { + LOG_DEBUG("%p: debug_buffer[%02x] = DASM(0x%08x)", program, i, program->debug_buffer[i]); + if (riscv_write_debug_buffer(program->target, i, + program->debug_buffer[i]) != ERROR_OK) + return ERROR_FAIL; + } + return ERROR_OK; +} + +/** Add ebreak and execute the program. */ +int riscv_program_exec(struct riscv_program *p, struct target *t) +{ + keep_alive(); + + riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1]; + for (size_t i = GDB_REGNO_ZERO + 1; i <= GDB_REGNO_XPR31; ++i) { + if (p->writes_xreg[i]) { + LOG_DEBUG("Saving register %d as used by program", (int)i); + int result = riscv_get_register(t, &saved_registers[i], i); + if (result != ERROR_OK) + return result; + } + } + + if (riscv_program_ebreak(p) != ERROR_OK) { + LOG_ERROR("Unable to write ebreak"); + for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) + LOG_ERROR("ram[%02x]: DASM(0x%08lx) [0x%08lx]", (int)i, (long)p->debug_buffer[i], (long)p->debug_buffer[i]); + return ERROR_FAIL; + } + + if (riscv_program_write(p) != ERROR_OK) + return ERROR_FAIL; + + if (riscv_execute_debug_buffer(t) != ERROR_OK) { + LOG_DEBUG("Unable to execute program %p", p); + return ERROR_FAIL; + } + + for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) + if (i >= riscv_debug_buffer_size(p->target)) + p->debug_buffer[i] = riscv_read_debug_buffer(t, i); + + for (size_t i = GDB_REGNO_ZERO; i <= GDB_REGNO_XPR31; ++i) + if (p->writes_xreg[i]) + riscv_set_register(t, i, saved_registers[i]); + + return ERROR_OK; +} + +int riscv_program_swr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +{ + return riscv_program_insert(p, sw(d, b, offset)); +} + +int riscv_program_shr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +{ + return riscv_program_insert(p, sh(d, b, offset)); +} + +int riscv_program_sbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +{ + return riscv_program_insert(p, sb(d, b, offset)); +} + +int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +{ + return riscv_program_insert(p, lw(d, b, offset)); +} + +int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +{ + return riscv_program_insert(p, lh(d, b, offset)); +} + +int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +{ + return riscv_program_insert(p, lb(d, b, offset)); +} + +int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr) +{ + assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); + return riscv_program_insert(p, csrrs(d, GDB_REGNO_ZERO, csr - GDB_REGNO_CSR0)); +} + +int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr) +{ + assert(csr >= GDB_REGNO_CSR0); + return riscv_program_insert(p, csrrw(GDB_REGNO_ZERO, s, csr - GDB_REGNO_CSR0)); +} + +int riscv_program_fence_i(struct riscv_program *p) +{ + return riscv_program_insert(p, fence_i()); +} + +int riscv_program_fence(struct riscv_program *p) +{ + return riscv_program_insert(p, fence()); +} + +int riscv_program_ebreak(struct riscv_program *p) +{ + struct target *target = p->target; + RISCV_INFO(r); + if (p->instruction_count == riscv_debug_buffer_size(p->target) && + r->impebreak) { + return ERROR_OK; + } + return riscv_program_insert(p, ebreak()); +} + +int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t u) +{ + return riscv_program_insert(p, addi(d, s, u)); +} + +int riscv_program_insert(struct riscv_program *p, riscv_insn_t i) +{ + if (p->instruction_count >= riscv_debug_buffer_size(p->target)) { + LOG_ERROR("Unable to insert instruction:"); + LOG_ERROR(" instruction_count=%d", (int)p->instruction_count); + LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target)); + return ERROR_FAIL; + } + + p->debug_buffer[p->instruction_count] = i; + p->instruction_count++; + return ERROR_OK; +} diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h new file mode 100644 index 000000000..d641be1be --- /dev/null +++ b/src/target/riscv/program.h @@ -0,0 +1,75 @@ +#ifndef TARGET__RISCV__PROGRAM_H +#define TARGET__RISCV__PROGRAM_H + +#include "riscv.h" + +#define RISCV_MAX_DEBUG_BUFFER_SIZE 32 +#define RISCV_REGISTER_COUNT 32 +#define RISCV_DSCRATCH_COUNT 2 + +/* The various RISC-V debug specifications all revolve around setting up + * program buffers and executing them on the target. This structure contains a + * single program, which can then be executed on targets. */ +struct riscv_program { + struct target *target; + + uint32_t debug_buffer[RISCV_MAX_DEBUG_BUFFER_SIZE]; + + /* Number of 32-bit instructions in the program. */ + size_t instruction_count; + + /* Side effects of executing this program. These must be accounted for + * in order to maintain correct executing of the target system. */ + bool writes_xreg[RISCV_REGISTER_COUNT]; + + /* XLEN on the target. */ + int target_xlen; +}; + +/* Initializes a program with the header. */ +int riscv_program_init(struct riscv_program *p, struct target *t); + +/* Write the program to the program buffer. */ +int riscv_program_write(struct riscv_program *program); + +/* Executes a program, returning 0 if the program successfully executed. Note + * that this may cause registers to be saved or restored, which could result to + * calls to things like riscv_save_register which itself could require a + * program to execute. That's OK, just make sure this eventually terminates. + * */ +int riscv_program_exec(struct riscv_program *p, struct target *t); +int riscv_program_load(struct riscv_program *p, struct target *t); + +/* Clears a program, removing all the state associated with it. */ +int riscv_program_clear(struct riscv_program *p, struct target *t); + +/* A lower level interface, you shouldn't use this unless you have a reason. */ +int riscv_program_insert(struct riscv_program *p, riscv_insn_t i); + +/* There is hardware support for saving at least one register. This register + * doesn't need to be saved/restored the usual way, which is useful during + * early initialization when we can't save/restore arbitrary registerrs to host + * memory. */ +int riscv_program_save_to_dscratch(struct riscv_program *p, enum gdb_regno to_save); + +/* Helpers to assembly various instructions. Return 0 on success. These might + * assembly into a multi-instruction sequence that overwrites some other + * register, but those will be properly saved and restored. */ +int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); +int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); +int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); + +int riscv_program_swr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); +int riscv_program_shr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); +int riscv_program_sbr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); + +int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr); +int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr); + +int riscv_program_fence_i(struct riscv_program *p); +int riscv_program_fence(struct riscv_program *p); +int riscv_program_ebreak(struct riscv_program *p); + +int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t i); + +#endif diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c new file mode 100644 index 000000000..f2a68698b --- /dev/null +++ b/src/target/riscv/riscv-011.c @@ -0,0 +1,2328 @@ +/* + * Support for RISC-V, debug version 0.11. This was never an officially adopted + * spec, but SiFive made some silicon that uses it. + */ + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "target/target.h" +#include "target/algorithm.h" +#include "target/target_type.h" +#include "log.h" +#include "jtag/jtag.h" +#include "target/register.h" +#include "target/breakpoints.h" +#include "helper/time_support.h" +#include "riscv.h" +#include "asm.h" +#include "gdb_regs.h" + +/** + * Since almost everything can be accomplish by scanning the dbus register, all + * functions here assume dbus is already selected. The exception are functions + * called directly by OpenOCD, which can't assume anything about what's + * currently in IR. They should set IR to dbus explicitly. + */ + +/** + * Code structure + * + * At the bottom of the stack are the OpenOCD JTAG functions: + * jtag_add_[id]r_scan + * jtag_execute_query + * jtag_add_runtest + * + * There are a few functions to just instantly shift a register and get its + * value: + * dtmcontrol_scan + * idcode_scan + * dbus_scan + * + * Because doing one scan and waiting for the result is slow, most functions + * batch up a bunch of dbus writes and then execute them all at once. They use + * the scans "class" for this: + * scans_new + * scans_delete + * scans_execute + * scans_add_... + * Usually you new(), call a bunch of add functions, then execute() and look + * at the results by calling scans_get...() + * + * Optimized functions will directly use the scans class above, but slightly + * lazier code will use the cache functions that in turn use the scans + * functions: + * cache_get... + * cache_set... + * cache_write + * cache_set... update a local structure, which is then synced to the target + * with cache_write(). Only Debug RAM words that are actually changed are sent + * to the target. Afterwards use cache_get... to read results. + */ + +#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) +#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) + +#define DIM(x) (sizeof(x)/sizeof(*x)) + +/* Constants for legacy SiFive hardware breakpoints. */ +#define CSR_BPCONTROL_X (1<<0) +#define CSR_BPCONTROL_W (1<<1) +#define CSR_BPCONTROL_R (1<<2) +#define CSR_BPCONTROL_U (1<<3) +#define CSR_BPCONTROL_S (1<<4) +#define CSR_BPCONTROL_H (1<<5) +#define CSR_BPCONTROL_M (1<<6) +#define CSR_BPCONTROL_BPMATCH (0xf<<7) +#define CSR_BPCONTROL_BPACTION (0xff<<11) + +#define DEBUG_ROM_START 0x800 +#define DEBUG_ROM_RESUME (DEBUG_ROM_START + 4) +#define DEBUG_ROM_EXCEPTION (DEBUG_ROM_START + 8) +#define DEBUG_RAM_START 0x400 + +#define SETHALTNOT 0x10c + +/*** JTAG registers. ***/ + +#define DTMCONTROL 0x10 +#define DTMCONTROL_DBUS_RESET (1<<16) +#define DTMCONTROL_IDLE (7<<10) +#define DTMCONTROL_ADDRBITS (0xf<<4) +#define DTMCONTROL_VERSION (0xf) + +#define DBUS 0x11 +#define DBUS_OP_START 0 +#define DBUS_OP_SIZE 2 +typedef enum { + DBUS_OP_NOP = 0, + DBUS_OP_READ = 1, + DBUS_OP_WRITE = 2 +} dbus_op_t; +typedef enum { + DBUS_STATUS_SUCCESS = 0, + DBUS_STATUS_FAILED = 2, + DBUS_STATUS_BUSY = 3 +} dbus_status_t; +#define DBUS_DATA_START 2 +#define DBUS_DATA_SIZE 34 +#define DBUS_ADDRESS_START 36 + +typedef enum { + RE_OK, + RE_FAIL, + RE_AGAIN +} riscv_error_t; + +typedef enum slot { + SLOT0, + SLOT1, + SLOT_LAST, +} slot_t; + +/*** Debug Bus registers. ***/ + +#define DMCONTROL 0x10 +#define DMCONTROL_INTERRUPT (((uint64_t)1)<<33) +#define DMCONTROL_HALTNOT (((uint64_t)1)<<32) +#define DMCONTROL_BUSERROR (7<<19) +#define DMCONTROL_SERIAL (3<<16) +#define DMCONTROL_AUTOINCREMENT (1<<15) +#define DMCONTROL_ACCESS (7<<12) +#define DMCONTROL_HARTID (0x3ff<<2) +#define DMCONTROL_NDRESET (1<<1) +#define DMCONTROL_FULLRESET 1 + +#define DMINFO 0x11 +#define DMINFO_ABUSSIZE (0x7fU<<25) +#define DMINFO_SERIALCOUNT (0xf<<21) +#define DMINFO_ACCESS128 (1<<20) +#define DMINFO_ACCESS64 (1<<19) +#define DMINFO_ACCESS32 (1<<18) +#define DMINFO_ACCESS16 (1<<17) +#define DMINFO_ACCESS8 (1<<16) +#define DMINFO_DRAMSIZE (0x3f<<10) +#define DMINFO_AUTHENTICATED (1<<5) +#define DMINFO_AUTHBUSY (1<<4) +#define DMINFO_AUTHTYPE (3<<2) +#define DMINFO_VERSION 3 + +/*** Info about the core being debugged. ***/ + +#define DBUS_ADDRESS_UNKNOWN 0xffff + +#define DRAM_CACHE_SIZE 16 + +struct trigger { + uint64_t address; + uint32_t length; + uint64_t mask; + uint64_t value; + bool read, write, execute; + int unique_id; +}; + +struct memory_cache_line { + uint32_t data; + bool valid; + bool dirty; +}; + +typedef struct { + /* Number of address bits in the dbus register. */ + uint8_t addrbits; + /* Number of words in Debug RAM. */ + unsigned int dramsize; + uint64_t dcsr; + uint64_t dpc; + uint64_t tselect; + bool tselect_dirty; + /* The value that mstatus actually has on the target right now. This is not + * the value we present to the user. That one may be stored in the + * reg_cache. */ + uint64_t mstatus_actual; + + struct memory_cache_line dram_cache[DRAM_CACHE_SIZE]; + + /* Number of run-test/idle cycles the target requests we do after each dbus + * access. */ + unsigned int dtmcontrol_idle; + + /* This value is incremented every time a dbus access comes back as "busy". + * It's used to determine how many run-test/idle cycles to feed the target + * in between accesses. */ + unsigned int dbus_busy_delay; + + /* This value is incremented every time we read the debug interrupt as + * high. It's used to add extra run-test/idle cycles after setting debug + * interrupt high, so ideally we never have to perform a whole extra scan + * before the interrupt is cleared. */ + unsigned int interrupt_high_delay; + + bool need_strict_step; + bool never_halted; +} riscv011_info_t; + +typedef struct { + bool haltnot; + bool interrupt; +} bits_t; + +/*** Necessary prototypes. ***/ + +static int poll_target(struct target *target, bool announce); +static int riscv011_poll(struct target *target); +static int get_register(struct target *target, riscv_reg_t *value, int hartid, + int regid); + +/*** Utility functions. ***/ + +#define DEBUG_LENGTH 264 + +static riscv011_info_t *get_info(const struct target *target) +{ + riscv_info_t *info = (riscv_info_t *) target->arch_info; + return (riscv011_info_t *) info->version_specific; +} + +static unsigned int slot_offset(const struct target *target, slot_t slot) +{ + riscv011_info_t *info = get_info(target); + switch (riscv_xlen(target)) { + case 32: + switch (slot) { + case SLOT0: return 4; + case SLOT1: return 5; + case SLOT_LAST: return info->dramsize-1; + } + case 64: + switch (slot) { + case SLOT0: return 4; + case SLOT1: return 6; + case SLOT_LAST: return info->dramsize-2; + } + } + LOG_ERROR("slot_offset called with xlen=%d, slot=%d", + riscv_xlen(target), slot); + assert(0); + return 0; /* Silence -Werror=return-type */ +} + +static uint32_t load_slot(const struct target *target, unsigned int dest, + slot_t slot) +{ + unsigned int offset = DEBUG_RAM_START + 4 * slot_offset(target, slot); + return load(target, dest, ZERO, offset); +} + +static uint32_t store_slot(const struct target *target, unsigned int src, + slot_t slot) +{ + unsigned int offset = DEBUG_RAM_START + 4 * slot_offset(target, slot); + return store(target, src, ZERO, offset); +} + +static uint16_t dram_address(unsigned int index) +{ + if (index < 0x10) + return index; + else + return 0x40 + index - 0x10; +} + +static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) +{ + struct scan_field field; + uint8_t in_value[4]; + uint8_t out_value[4]; + + buf_set_u32(out_value, 0, 32, out); + + jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE); + + field.num_bits = 32; + field.out_value = out_value; + field.in_value = in_value; + jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); + + /* Always return to dbus. */ + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); + + int retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("failed jtag scan: %d", retval); + return retval; + } + + uint32_t in = buf_get_u32(field.in_value, 0, 32); + LOG_DEBUG("DTMCONTROL: 0x%x -> 0x%x", out, in); + + return in; +} + +static uint32_t idcode_scan(struct target *target) +{ + struct scan_field field; + uint8_t in_value[4]; + + jtag_add_ir_scan(target->tap, &select_idcode, TAP_IDLE); + + field.num_bits = 32; + field.out_value = NULL; + field.in_value = in_value; + jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); + + int retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("failed jtag scan: %d", retval); + return retval; + } + + /* Always return to dbus. */ + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); + + uint32_t in = buf_get_u32(field.in_value, 0, 32); + LOG_DEBUG("IDCODE: 0x0 -> 0x%x", in); + + return in; +} + +static void increase_dbus_busy_delay(struct target *target) +{ + riscv011_info_t *info = get_info(target); + info->dbus_busy_delay += info->dbus_busy_delay / 10 + 1; + LOG_DEBUG("dtmcontrol_idle=%d, dbus_busy_delay=%d, interrupt_high_delay=%d", + info->dtmcontrol_idle, info->dbus_busy_delay, + info->interrupt_high_delay); + + dtmcontrol_scan(target, DTMCONTROL_DBUS_RESET); +} + +static void increase_interrupt_high_delay(struct target *target) +{ + riscv011_info_t *info = get_info(target); + info->interrupt_high_delay += info->interrupt_high_delay / 10 + 1; + LOG_DEBUG("dtmcontrol_idle=%d, dbus_busy_delay=%d, interrupt_high_delay=%d", + info->dtmcontrol_idle, info->dbus_busy_delay, + info->interrupt_high_delay); +} + +static void add_dbus_scan(const struct target *target, struct scan_field *field, + uint8_t *out_value, uint8_t *in_value, dbus_op_t op, + uint16_t address, uint64_t data) +{ + riscv011_info_t *info = get_info(target); + + field->num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE; + field->in_value = in_value; + field->out_value = out_value; + + buf_set_u64(out_value, DBUS_OP_START, DBUS_OP_SIZE, op); + buf_set_u64(out_value, DBUS_DATA_START, DBUS_DATA_SIZE, data); + buf_set_u64(out_value, DBUS_ADDRESS_START, info->addrbits, address); + + jtag_add_dr_scan(target->tap, 1, field, TAP_IDLE); + + int idle_count = info->dtmcontrol_idle + info->dbus_busy_delay; + if (data & DMCONTROL_INTERRUPT) + idle_count += info->interrupt_high_delay; + + if (idle_count) + jtag_add_runtest(idle_count, TAP_IDLE); +} + +static void dump_field(const struct scan_field *field) +{ + static const char * const op_string[] = {"nop", "r", "w", "?"}; + static const char * const status_string[] = {"+", "?", "F", "b"}; + + if (debug_level < LOG_LVL_DEBUG) + return; + + uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits); + unsigned int out_op = (out >> DBUS_OP_START) & ((1 << DBUS_OP_SIZE) - 1); + char out_interrupt = ((out >> DBUS_DATA_START) & DMCONTROL_INTERRUPT) ? 'i' : '.'; + char out_haltnot = ((out >> DBUS_DATA_START) & DMCONTROL_HALTNOT) ? 'h' : '.'; + unsigned int out_data = out >> 2; + unsigned int out_address = out >> DBUS_ADDRESS_START; + uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits); + unsigned int in_op = (in >> DBUS_OP_START) & ((1 << DBUS_OP_SIZE) - 1); + char in_interrupt = ((in >> DBUS_DATA_START) & DMCONTROL_INTERRUPT) ? 'i' : '.'; + char in_haltnot = ((in >> DBUS_DATA_START) & DMCONTROL_HALTNOT) ? 'h' : '.'; + unsigned int in_data = in >> 2; + unsigned int in_address = in >> DBUS_ADDRESS_START; + + log_printf_lf(LOG_LVL_DEBUG, + __FILE__, __LINE__, "scan", + "%db %s %c%c:%08x @%02x -> %s %c%c:%08x @%02x", + field->num_bits, + op_string[out_op], out_interrupt, out_haltnot, out_data, + out_address, + status_string[in_op], in_interrupt, in_haltnot, in_data, + in_address); +} + +static dbus_status_t dbus_scan(struct target *target, uint16_t *address_in, + uint64_t *data_in, dbus_op_t op, uint16_t address_out, uint64_t data_out) +{ + riscv011_info_t *info = get_info(target); + uint8_t in[8] = {0}; + uint8_t out[8]; + struct scan_field field = { + .num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE, + .out_value = out, + .in_value = in + }; + + assert(info->addrbits != 0); + + buf_set_u64(out, DBUS_OP_START, DBUS_OP_SIZE, op); + buf_set_u64(out, DBUS_DATA_START, DBUS_DATA_SIZE, data_out); + buf_set_u64(out, DBUS_ADDRESS_START, info->addrbits, address_out); + + /* Assume dbus is already selected. */ + jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); + + int idle_count = info->dtmcontrol_idle + info->dbus_busy_delay; + + if (idle_count) + jtag_add_runtest(idle_count, TAP_IDLE); + + int retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("dbus_scan failed jtag scan"); + return DBUS_STATUS_FAILED; + } + + if (data_in) + *data_in = buf_get_u64(in, DBUS_DATA_START, DBUS_DATA_SIZE); + + if (address_in) + *address_in = buf_get_u32(in, DBUS_ADDRESS_START, info->addrbits); + + dump_field(&field); + + return buf_get_u32(in, DBUS_OP_START, DBUS_OP_SIZE); +} + +static uint64_t dbus_read(struct target *target, uint16_t address) +{ + uint64_t value; + dbus_status_t status; + uint16_t address_in; + + /* If the previous read/write was to the same address, we will get the read data + * from the previous access. + * While somewhat nonintuitive, this is an efficient way to get the data. + */ + + unsigned i = 0; + do { + status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, address, 0); + if (status == DBUS_STATUS_BUSY) + increase_dbus_busy_delay(target); + if (status == DBUS_STATUS_FAILED) { + LOG_ERROR("dbus_read(0x%x) failed!", address); + return 0; + } + } while (((status == DBUS_STATUS_BUSY) || (address_in != address)) && + i++ < 256); + + if (status != DBUS_STATUS_SUCCESS) + LOG_ERROR("failed read from 0x%x; value=0x%" PRIx64 ", status=%d\n", address, value, status); + + return value; +} + +static void dbus_write(struct target *target, uint16_t address, uint64_t value) +{ + dbus_status_t status = DBUS_STATUS_BUSY; + unsigned i = 0; + while (status == DBUS_STATUS_BUSY && i++ < 256) { + status = dbus_scan(target, NULL, NULL, DBUS_OP_WRITE, address, value); + if (status == DBUS_STATUS_BUSY) + increase_dbus_busy_delay(target); + } + if (status != DBUS_STATUS_SUCCESS) + LOG_ERROR("failed to write 0x%" PRIx64 " to 0x%x; status=%d\n", value, address, status); +} + +/*** scans "class" ***/ + +typedef struct { + /* Number of scans that space is reserved for. */ + unsigned int scan_count; + /* Size reserved in memory for each scan, in bytes. */ + unsigned int scan_size; + unsigned int next_scan; + uint8_t *in; + uint8_t *out; + struct scan_field *field; + const struct target *target; +} scans_t; + +static scans_t *scans_new(struct target *target, unsigned int scan_count) +{ + scans_t *scans = malloc(sizeof(scans_t)); + scans->scan_count = scan_count; + /* This code also gets called before xlen is detected. */ + if (riscv_xlen(target)) + scans->scan_size = 2 + riscv_xlen(target) / 8; + else + scans->scan_size = 2 + 128 / 8; + scans->next_scan = 0; + scans->in = calloc(scans->scan_size, scans->scan_count); + scans->out = calloc(scans->scan_size, scans->scan_count); + scans->field = calloc(scans->scan_count, sizeof(struct scan_field)); + scans->target = target; + return scans; +} + +static scans_t *scans_delete(scans_t *scans) +{ + assert(scans); + free(scans->field); + free(scans->out); + free(scans->in); + free(scans); + return NULL; +} + +static void scans_reset(scans_t *scans) +{ + scans->next_scan = 0; +} + +static void scans_dump(scans_t *scans) +{ + for (unsigned int i = 0; i < scans->next_scan; i++) + dump_field(&scans->field[i]); +} + +static int scans_execute(scans_t *scans) +{ + int retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("failed jtag scan: %d", retval); + return retval; + } + + scans_dump(scans); + + return ERROR_OK; +} + +/** Add a 32-bit dbus write to the scans structure. */ +static void scans_add_write32(scans_t *scans, uint16_t address, uint32_t data, + bool set_interrupt) +{ + const unsigned int i = scans->next_scan; + int data_offset = scans->scan_size * i; + add_dbus_scan(scans->target, &scans->field[i], scans->out + data_offset, + scans->in + data_offset, DBUS_OP_WRITE, address, + (set_interrupt ? DMCONTROL_INTERRUPT : 0) | DMCONTROL_HALTNOT | data); + scans->next_scan++; + assert(scans->next_scan <= scans->scan_count); +} + +/** Add a 32-bit dbus write for an instruction that jumps to the beginning of + * debug RAM. */ +static void scans_add_write_jump(scans_t *scans, uint16_t address, + bool set_interrupt) +{ + scans_add_write32(scans, address, + jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*address))), + set_interrupt); +} + +/** Add a 32-bit dbus write for an instruction that loads from the indicated + * slot. */ +static void scans_add_write_load(scans_t *scans, uint16_t address, + unsigned int reg, slot_t slot, bool set_interrupt) +{ + scans_add_write32(scans, address, load_slot(scans->target, reg, slot), + set_interrupt); +} + +/** Add a 32-bit dbus write for an instruction that stores to the indicated + * slot. */ +static void scans_add_write_store(scans_t *scans, uint16_t address, + unsigned int reg, slot_t slot, bool set_interrupt) +{ + scans_add_write32(scans, address, store_slot(scans->target, reg, slot), + set_interrupt); +} + +/** Add a 32-bit dbus read. */ +static void scans_add_read32(scans_t *scans, uint16_t address, bool set_interrupt) +{ + assert(scans->next_scan < scans->scan_count); + const unsigned int i = scans->next_scan; + int data_offset = scans->scan_size * i; + add_dbus_scan(scans->target, &scans->field[i], scans->out + data_offset, + scans->in + data_offset, DBUS_OP_READ, address, + (set_interrupt ? DMCONTROL_INTERRUPT : 0) | DMCONTROL_HALTNOT); + scans->next_scan++; +} + +/** Add one or more scans to read the indicated slot. */ +static void scans_add_read(scans_t *scans, slot_t slot, bool set_interrupt) +{ + const struct target *target = scans->target; + switch (riscv_xlen(target)) { + case 32: + scans_add_read32(scans, slot_offset(target, slot), set_interrupt); + break; + case 64: + scans_add_read32(scans, slot_offset(target, slot), false); + scans_add_read32(scans, slot_offset(target, slot) + 1, set_interrupt); + break; + } +} + +static uint32_t scans_get_u32(scans_t *scans, unsigned int index, + unsigned first, unsigned num) +{ + return buf_get_u32(scans->in + scans->scan_size * index, first, num); +} + +static uint64_t scans_get_u64(scans_t *scans, unsigned int index, + unsigned first, unsigned num) +{ + return buf_get_u64(scans->in + scans->scan_size * index, first, num); +} + +/*** end of scans class ***/ + +static uint32_t dram_read32(struct target *target, unsigned int index) +{ + uint16_t address = dram_address(index); + uint32_t value = dbus_read(target, address); + return value; +} + +static void dram_write32(struct target *target, unsigned int index, uint32_t value, + bool set_interrupt) +{ + uint64_t dbus_value = DMCONTROL_HALTNOT | value; + if (set_interrupt) + dbus_value |= DMCONTROL_INTERRUPT; + dbus_write(target, dram_address(index), dbus_value); +} + +/** Read the haltnot and interrupt bits. */ +static bits_t read_bits(struct target *target) +{ + uint64_t value; + dbus_status_t status; + uint16_t address_in; + riscv011_info_t *info = get_info(target); + + bits_t err_result = { + .haltnot = 0, + .interrupt = 0 + }; + + do { + unsigned i = 0; + do { + status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, 0, 0); + if (status == DBUS_STATUS_BUSY) { + if (address_in == (1<addrbits) - 1 && + value == (1ULL<= 256) { + LOG_ERROR("Failed to read from 0x%x; status=%d", address_in, status); + return err_result; + } + } while (address_in > 0x10 && address_in != DMCONTROL); + + bits_t result = { + .haltnot = get_field(value, DMCONTROL_HALTNOT), + .interrupt = get_field(value, DMCONTROL_INTERRUPT) + }; + return result; +} + +static int wait_for_debugint_clear(struct target *target, bool ignore_first) +{ + time_t start = time(NULL); + if (ignore_first) { + /* Throw away the results of the first read, since they'll contain the + * result of the read that happened just before debugint was set. + * (Assuming the last scan before calling this function was one that + * sets debugint.) */ + read_bits(target); + } + while (1) { + bits_t bits = read_bits(target); + if (!bits.interrupt) + return ERROR_OK; + if (time(NULL) - start > riscv_command_timeout_sec) { + LOG_ERROR("Timed out waiting for debug int to clear." + "Increase timeout with riscv set_command_timeout_sec."); + return ERROR_FAIL; + } + } +} + +static int dram_check32(struct target *target, unsigned int index, + uint32_t expected) +{ + uint16_t address = dram_address(index); + uint32_t actual = dbus_read(target, address); + if (expected != actual) { + LOG_ERROR("Wrote 0x%x to Debug RAM at %d, but read back 0x%x", + expected, index, actual); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static void cache_set32(struct target *target, unsigned int index, uint32_t data) +{ + riscv011_info_t *info = get_info(target); + if (info->dram_cache[index].valid && + info->dram_cache[index].data == data) { + /* This is already preset on the target. */ + LOG_DEBUG("cache[0x%x] = 0x%08x: DASM(0x%x) (hit)", index, data, data); + return; + } + LOG_DEBUG("cache[0x%x] = 0x%08x: DASM(0x%x)", index, data, data); + info->dram_cache[index].data = data; + info->dram_cache[index].valid = true; + info->dram_cache[index].dirty = true; +} + +static void cache_set(struct target *target, slot_t slot, uint64_t data) +{ + unsigned int offset = slot_offset(target, slot); + cache_set32(target, offset, data); + if (riscv_xlen(target) > 32) + cache_set32(target, offset + 1, data >> 32); +} + +static void cache_set_jump(struct target *target, unsigned int index) +{ + cache_set32(target, index, + jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*index)))); +} + +static void cache_set_load(struct target *target, unsigned int index, + unsigned int reg, slot_t slot) +{ + uint16_t offset = DEBUG_RAM_START + 4 * slot_offset(target, slot); + cache_set32(target, index, load(target, reg, ZERO, offset)); +} + +static void cache_set_store(struct target *target, unsigned int index, + unsigned int reg, slot_t slot) +{ + uint16_t offset = DEBUG_RAM_START + 4 * slot_offset(target, slot); + cache_set32(target, index, store(target, reg, ZERO, offset)); +} + +static void dump_debug_ram(struct target *target) +{ + for (unsigned int i = 0; i < DRAM_CACHE_SIZE; i++) { + uint32_t value = dram_read32(target, i); + LOG_ERROR("Debug RAM 0x%x: 0x%08x", i, value); + } +} + +/* Call this if the code you just ran writes to debug RAM entries 0 through 3. */ +static void cache_invalidate(struct target *target) +{ + riscv011_info_t *info = get_info(target); + for (unsigned int i = 0; i < info->dramsize; i++) { + info->dram_cache[i].valid = false; + info->dram_cache[i].dirty = false; + } +} + +/* Called by cache_write() after the program has run. Also call this if you're + * running programs without calling cache_write(). */ +static void cache_clean(struct target *target) +{ + riscv011_info_t *info = get_info(target); + for (unsigned int i = 0; i < info->dramsize; i++) { + if (i >= 4) + info->dram_cache[i].valid = false; + info->dram_cache[i].dirty = false; + } +} + +static int cache_check(struct target *target) +{ + riscv011_info_t *info = get_info(target); + int error = 0; + + for (unsigned int i = 0; i < info->dramsize; i++) { + if (info->dram_cache[i].valid && !info->dram_cache[i].dirty) { + if (dram_check32(target, i, info->dram_cache[i].data) != ERROR_OK) + error++; + } + } + + if (error) { + dump_debug_ram(target); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +/** Write cache to the target, and optionally run the program. + * Then read the value at address into the cache, assuming address < 128. */ +#define CACHE_NO_READ 128 +static int cache_write(struct target *target, unsigned int address, bool run) +{ + LOG_DEBUG("enter"); + riscv011_info_t *info = get_info(target); + scans_t *scans = scans_new(target, info->dramsize + 2); + + unsigned int last = info->dramsize; + for (unsigned int i = 0; i < info->dramsize; i++) { + if (info->dram_cache[i].dirty) + last = i; + } + + if (last == info->dramsize) { + /* Nothing needs to be written to RAM. */ + dbus_write(target, DMCONTROL, DMCONTROL_HALTNOT | (run ? DMCONTROL_INTERRUPT : 0)); + + } else { + for (unsigned int i = 0; i < info->dramsize; i++) { + if (info->dram_cache[i].dirty) { + bool set_interrupt = (i == last && run); + scans_add_write32(scans, i, info->dram_cache[i].data, + set_interrupt); + } + } + } + + if (run || address < CACHE_NO_READ) { + /* Throw away the results of the first read, since it'll contain the + * result of the read that happened just before debugint was set. */ + scans_add_read32(scans, address, false); + + /* This scan contains the results of the read the caller requested, as + * well as an interrupt bit worth looking at. */ + scans_add_read32(scans, address, false); + } + + int retval = scans_execute(scans); + if (retval != ERROR_OK) { + scans_delete(scans); + LOG_ERROR("JTAG execute failed."); + return retval; + } + + int errors = 0; + for (unsigned int i = 0; i < scans->next_scan; i++) { + dbus_status_t status = scans_get_u32(scans, i, DBUS_OP_START, + DBUS_OP_SIZE); + switch (status) { + case DBUS_STATUS_SUCCESS: + break; + case DBUS_STATUS_FAILED: + LOG_ERROR("Debug RAM write failed. Hardware error?"); + scans_delete(scans); + return ERROR_FAIL; + case DBUS_STATUS_BUSY: + errors++; + break; + default: + LOG_ERROR("Got invalid bus access status: %d", status); + scans_delete(scans); + return ERROR_FAIL; + } + } + + if (errors) { + increase_dbus_busy_delay(target); + + /* Try again, using the slow careful code. + * Write all RAM, just to be extra cautious. */ + for (unsigned int i = 0; i < info->dramsize; i++) { + if (i == last && run) + dram_write32(target, last, info->dram_cache[last].data, true); + else + dram_write32(target, i, info->dram_cache[i].data, false); + info->dram_cache[i].dirty = false; + } + if (run) + cache_clean(target); + + if (wait_for_debugint_clear(target, true) != ERROR_OK) { + LOG_ERROR("Debug interrupt didn't clear."); + dump_debug_ram(target); + scans_delete(scans); + return ERROR_FAIL; + } + + } else { + if (run) { + cache_clean(target); + } else { + for (unsigned int i = 0; i < info->dramsize; i++) + info->dram_cache[i].dirty = false; + } + + if (run || address < CACHE_NO_READ) { + int interrupt = scans_get_u32(scans, scans->next_scan-1, + DBUS_DATA_START + 33, 1); + if (interrupt) { + increase_interrupt_high_delay(target); + /* Slow path wait for it to clear. */ + if (wait_for_debugint_clear(target, false) != ERROR_OK) { + LOG_ERROR("Debug interrupt didn't clear."); + dump_debug_ram(target); + scans_delete(scans); + return ERROR_FAIL; + } + } else { + /* We read a useful value in that last scan. */ + unsigned int read_addr = scans_get_u32(scans, scans->next_scan-1, + DBUS_ADDRESS_START, info->addrbits); + if (read_addr != address) { + LOG_INFO("Got data from 0x%x but expected it from 0x%x", + read_addr, address); + } + info->dram_cache[read_addr].data = + scans_get_u32(scans, scans->next_scan-1, DBUS_DATA_START, 32); + info->dram_cache[read_addr].valid = true; + } + } + } + + scans_delete(scans); + LOG_DEBUG("exit"); + + return ERROR_OK; +} + +static uint32_t cache_get32(struct target *target, unsigned int address) +{ + riscv011_info_t *info = get_info(target); + if (!info->dram_cache[address].valid) { + info->dram_cache[address].data = dram_read32(target, address); + info->dram_cache[address].valid = true; + } + return info->dram_cache[address].data; +} + +static uint64_t cache_get(struct target *target, slot_t slot) +{ + unsigned int offset = slot_offset(target, slot); + uint64_t value = cache_get32(target, offset); + if (riscv_xlen(target) > 32) + value |= ((uint64_t) cache_get32(target, offset + 1)) << 32; + return value; +} + +/* Write instruction that jumps from the specified word in Debug RAM to resume + * in Debug ROM. */ +static void dram_write_jump(struct target *target, unsigned int index, + bool set_interrupt) +{ + dram_write32(target, index, + jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*index))), + set_interrupt); +} + +static int wait_for_state(struct target *target, enum target_state state) +{ + time_t start = time(NULL); + while (1) { + int result = riscv011_poll(target); + if (result != ERROR_OK) + return result; + if (target->state == state) + return ERROR_OK; + if (time(NULL) - start > riscv_command_timeout_sec) { + LOG_ERROR("Timed out waiting for state %d. " + "Increase timeout with riscv set_command_timeout_sec.", state); + return ERROR_FAIL; + } + } +} + +static int read_csr(struct target *target, uint64_t *value, uint32_t csr) +{ + riscv011_info_t *info = get_info(target); + cache_set32(target, 0, csrr(S0, csr)); + cache_set_store(target, 1, S0, SLOT0); + cache_set_jump(target, 2); + if (cache_write(target, 4, true) != ERROR_OK) + return ERROR_FAIL; + *value = cache_get(target, SLOT0); + LOG_DEBUG("csr 0x%x = 0x%" PRIx64, csr, *value); + + uint32_t exception = cache_get32(target, info->dramsize-1); + if (exception) { + LOG_WARNING("Got exception 0x%x when reading %s", exception, + gdb_regno_name(GDB_REGNO_CSR0 + csr)); + *value = ~0; + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int write_csr(struct target *target, uint32_t csr, uint64_t value) +{ + LOG_DEBUG("csr 0x%x <- 0x%" PRIx64, csr, value); + cache_set_load(target, 0, S0, SLOT0); + cache_set32(target, 1, csrw(S0, csr)); + cache_set_jump(target, 2); + cache_set(target, SLOT0, value); + if (cache_write(target, 4, true) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +static int write_gpr(struct target *target, unsigned int gpr, uint64_t value) +{ + cache_set_load(target, 0, gpr, SLOT0); + cache_set_jump(target, 1); + cache_set(target, SLOT0, value); + if (cache_write(target, 4, true) != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; +} + +static int maybe_read_tselect(struct target *target) +{ + riscv011_info_t *info = get_info(target); + + if (info->tselect_dirty) { + int result = read_csr(target, &info->tselect, CSR_TSELECT); + if (result != ERROR_OK) + return result; + info->tselect_dirty = false; + } + + return ERROR_OK; +} + +static int maybe_write_tselect(struct target *target) +{ + riscv011_info_t *info = get_info(target); + + if (!info->tselect_dirty) { + int result = write_csr(target, CSR_TSELECT, info->tselect); + if (result != ERROR_OK) + return result; + info->tselect_dirty = true; + } + + return ERROR_OK; +} + +static int execute_resume(struct target *target, bool step) +{ + riscv011_info_t *info = get_info(target); + + LOG_DEBUG("step=%d", step); + + maybe_write_tselect(target); + + /* TODO: check if dpc is dirty (which also is true if an exception was hit + * at any time) */ + cache_set_load(target, 0, S0, SLOT0); + cache_set32(target, 1, csrw(S0, CSR_DPC)); + cache_set_jump(target, 2); + cache_set(target, SLOT0, info->dpc); + if (cache_write(target, 4, true) != ERROR_OK) + return ERROR_FAIL; + + struct reg *mstatus_reg = &target->reg_cache->reg_list[GDB_REGNO_MSTATUS]; + if (mstatus_reg->valid) { + uint64_t mstatus_user = buf_get_u64(mstatus_reg->value, 0, riscv_xlen(target)); + if (mstatus_user != info->mstatus_actual) { + cache_set_load(target, 0, S0, SLOT0); + cache_set32(target, 1, csrw(S0, CSR_MSTATUS)); + cache_set_jump(target, 2); + cache_set(target, SLOT0, mstatus_user); + if (cache_write(target, 4, true) != ERROR_OK) + return ERROR_FAIL; + } + } + + info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | DCSR_EBREAKU; + info->dcsr &= ~DCSR_HALT; + + if (step) + info->dcsr |= DCSR_STEP; + else + info->dcsr &= ~DCSR_STEP; + + dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false); + dram_write32(target, 1, csrw(S0, CSR_DCSR), false); + dram_write32(target, 2, fence_i(), false); + dram_write_jump(target, 3, false); + + /* Write DCSR value, set interrupt and clear haltnot. */ + uint64_t dbus_value = DMCONTROL_INTERRUPT | info->dcsr; + dbus_write(target, dram_address(4), dbus_value); + + cache_invalidate(target); + + if (wait_for_debugint_clear(target, true) != ERROR_OK) { + LOG_ERROR("Debug interrupt didn't clear."); + return ERROR_FAIL; + } + + target->state = TARGET_RUNNING; + register_cache_invalidate(target->reg_cache); + + return ERROR_OK; +} + +/* Execute a step, and wait for reentry into Debug Mode. */ +static int full_step(struct target *target, bool announce) +{ + int result = execute_resume(target, true); + if (result != ERROR_OK) + return result; + time_t start = time(NULL); + while (1) { + result = poll_target(target, announce); + if (result != ERROR_OK) + return result; + if (target->state != TARGET_DEBUG_RUNNING) + break; + if (time(NULL) - start > riscv_command_timeout_sec) { + LOG_ERROR("Timed out waiting for step to complete." + "Increase timeout with riscv set_command_timeout_sec"); + return ERROR_FAIL; + } + } + return ERROR_OK; +} + +static int resume(struct target *target, int debug_execution, bool step) +{ + if (debug_execution) { + LOG_ERROR("TODO: debug_execution is true"); + return ERROR_FAIL; + } + + return execute_resume(target, step); +} + +static uint64_t reg_cache_get(struct target *target, unsigned int number) +{ + struct reg *r = &target->reg_cache->reg_list[number]; + if (!r->valid) { + LOG_ERROR("Register cache entry for %d is invalid!", number); + assert(r->valid); + } + uint64_t value = buf_get_u64(r->value, 0, r->size); + LOG_DEBUG("%s = 0x%" PRIx64, r->name, value); + return value; +} + +static void reg_cache_set(struct target *target, unsigned int number, + uint64_t value) +{ + struct reg *r = &target->reg_cache->reg_list[number]; + LOG_DEBUG("%s <= 0x%" PRIx64, r->name, value); + r->valid = true; + buf_set_u64(r->value, 0, r->size, value); +} + +static int update_mstatus_actual(struct target *target) +{ + struct reg *mstatus_reg = &target->reg_cache->reg_list[GDB_REGNO_MSTATUS]; + if (mstatus_reg->valid) { + /* We previously made it valid. */ + return ERROR_OK; + } + + /* Force reading the register. In that process mstatus_actual will be + * updated. */ + riscv_reg_t mstatus; + return get_register(target, &mstatus, 0, GDB_REGNO_MSTATUS); +} + +/*** OpenOCD target functions. ***/ + +static int register_read(struct target *target, riscv_reg_t *value, int regnum) +{ + riscv011_info_t *info = get_info(target); + if (regnum >= GDB_REGNO_CSR0 && regnum <= GDB_REGNO_CSR4095) { + cache_set32(target, 0, csrr(S0, regnum - GDB_REGNO_CSR0)); + cache_set_store(target, 1, S0, SLOT0); + cache_set_jump(target, 2); + } else { + LOG_ERROR("Don't know how to read register %d", regnum); + return ERROR_FAIL; + } + + if (cache_write(target, 4, true) != ERROR_OK) + return ERROR_FAIL; + + uint32_t exception = cache_get32(target, info->dramsize-1); + if (exception) { + LOG_WARNING("Got exception 0x%x when reading %s", exception, gdb_regno_name(regnum)); + *value = ~0; + return ERROR_FAIL; + } + + *value = cache_get(target, SLOT0); + LOG_DEBUG("reg[%d]=0x%" PRIx64, regnum, *value); + + if (regnum == GDB_REGNO_MSTATUS) + info->mstatus_actual = *value; + + return ERROR_OK; +} + +/* Write the register. No caching or games. */ +static int register_write(struct target *target, unsigned int number, + uint64_t value) +{ + riscv011_info_t *info = get_info(target); + + maybe_write_tselect(target); + + if (number == S0) { + cache_set_load(target, 0, S0, SLOT0); + cache_set32(target, 1, csrw(S0, CSR_DSCRATCH)); + cache_set_jump(target, 2); + } else if (number == S1) { + cache_set_load(target, 0, S0, SLOT0); + cache_set_store(target, 1, S0, SLOT_LAST); + cache_set_jump(target, 2); + } else if (number <= GDB_REGNO_XPR31) { + cache_set_load(target, 0, number - GDB_REGNO_ZERO, SLOT0); + cache_set_jump(target, 1); + } else if (number == GDB_REGNO_PC) { + info->dpc = value; + return ERROR_OK; + } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + int result = update_mstatus_actual(target); + if (result != ERROR_OK) + return result; + unsigned i = 0; + if ((info->mstatus_actual & MSTATUS_FS) == 0) { + info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1); + cache_set_load(target, i++, S0, SLOT1); + cache_set32(target, i++, csrw(S0, CSR_MSTATUS)); + cache_set(target, SLOT1, info->mstatus_actual); + } + + if (riscv_xlen(target) == 32) + cache_set32(target, i++, flw(number - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); + else + cache_set32(target, i++, fld(number - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); + cache_set_jump(target, i++); + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + cache_set_load(target, 0, S0, SLOT0); + cache_set32(target, 1, csrw(S0, number - GDB_REGNO_CSR0)); + cache_set_jump(target, 2); + + if (number == GDB_REGNO_MSTATUS) + info->mstatus_actual = value; + } else if (number == GDB_REGNO_PRIV) { + info->dcsr = set_field(info->dcsr, DCSR_PRV, value); + return ERROR_OK; + } else { + LOG_ERROR("Don't know how to write register %d", number); + return ERROR_FAIL; + } + + cache_set(target, SLOT0, value); + if (cache_write(target, info->dramsize - 1, true) != ERROR_OK) + return ERROR_FAIL; + + uint32_t exception = cache_get32(target, info->dramsize-1); + if (exception) { + LOG_WARNING("Got exception 0x%x when writing %s", exception, + gdb_regno_name(number)); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int get_register(struct target *target, riscv_reg_t *value, int hartid, + int regid) +{ + assert(hartid == 0); + riscv011_info_t *info = get_info(target); + + maybe_write_tselect(target); + + if (regid <= GDB_REGNO_XPR31) { + *value = reg_cache_get(target, regid); + } else if (regid == GDB_REGNO_PC) { + *value = info->dpc; + } else if (regid >= GDB_REGNO_FPR0 && regid <= GDB_REGNO_FPR31) { + int result = update_mstatus_actual(target); + if (result != ERROR_OK) + return result; + unsigned i = 0; + if ((info->mstatus_actual & MSTATUS_FS) == 0) { + info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1); + cache_set_load(target, i++, S0, SLOT1); + cache_set32(target, i++, csrw(S0, CSR_MSTATUS)); + cache_set(target, SLOT1, info->mstatus_actual); + } + + if (riscv_xlen(target) == 32) + cache_set32(target, i++, fsw(regid - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); + else + cache_set32(target, i++, fsd(regid - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); + cache_set_jump(target, i++); + + if (cache_write(target, 4, true) != ERROR_OK) + return ERROR_FAIL; + } else if (regid == GDB_REGNO_PRIV) { + *value = get_field(info->dcsr, DCSR_PRV); + } else { + int result = register_read(target, value, regid); + if (result != ERROR_OK) + return result; + } + + if (regid == GDB_REGNO_MSTATUS) + target->reg_cache->reg_list[regid].valid = true; + + return ERROR_OK; +} + +static int set_register(struct target *target, int hartid, int regid, + uint64_t value) +{ + assert(hartid == 0); + return register_write(target, regid, value); +} + +static int halt(struct target *target) +{ + LOG_DEBUG("riscv_halt()"); + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); + + cache_set32(target, 0, csrsi(CSR_DCSR, DCSR_HALT)); + cache_set32(target, 1, csrr(S0, CSR_MHARTID)); + cache_set32(target, 2, sw(S0, ZERO, SETHALTNOT)); + cache_set_jump(target, 3); + + if (cache_write(target, 4, true) != ERROR_OK) { + LOG_ERROR("cache_write() failed."); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int init_target(struct command_context *cmd_ctx, + struct target *target) +{ + LOG_DEBUG("init"); + riscv_info_t *generic_info = (riscv_info_t *) target->arch_info; + generic_info->get_register = get_register; + generic_info->set_register = set_register; + + generic_info->version_specific = calloc(1, sizeof(riscv011_info_t)); + if (!generic_info->version_specific) + return ERROR_FAIL; + + /* Assume 32-bit until we discover the real value in examine(). */ + generic_info->xlen[0] = 32; + riscv_init_registers(target); + + return ERROR_OK; +} + +static void deinit_target(struct target *target) +{ + LOG_DEBUG("riscv_deinit_target()"); + riscv_info_t *info = (riscv_info_t *) target->arch_info; + free(info->version_specific); + info->version_specific = NULL; +} + +static int strict_step(struct target *target, bool announce) +{ + riscv011_info_t *info = get_info(target); + + LOG_DEBUG("enter"); + + struct breakpoint *breakpoint = target->breakpoints; + while (breakpoint) { + riscv_remove_breakpoint(target, breakpoint); + breakpoint = breakpoint->next; + } + + struct watchpoint *watchpoint = target->watchpoints; + while (watchpoint) { + riscv_remove_watchpoint(target, watchpoint); + watchpoint = watchpoint->next; + } + + int result = full_step(target, announce); + if (result != ERROR_OK) + return result; + + breakpoint = target->breakpoints; + while (breakpoint) { + riscv_add_breakpoint(target, breakpoint); + breakpoint = breakpoint->next; + } + + watchpoint = target->watchpoints; + while (watchpoint) { + riscv_add_watchpoint(target, watchpoint); + watchpoint = watchpoint->next; + } + + info->need_strict_step = false; + + return ERROR_OK; +} + +static int step(struct target *target, int current, target_addr_t address, + int handle_breakpoints) +{ + riscv011_info_t *info = get_info(target); + + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); + + if (!current) { + if (riscv_xlen(target) > 32) { + LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.", + riscv_xlen(target)); + } + int result = register_write(target, GDB_REGNO_PC, address); + if (result != ERROR_OK) + return result; + } + + if (info->need_strict_step || handle_breakpoints) { + int result = strict_step(target, true); + if (result != ERROR_OK) + return result; + } else { + return resume(target, 0, true); + } + + return ERROR_OK; +} + +static int examine(struct target *target) +{ + /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ + + uint32_t dtmcontrol = dtmcontrol_scan(target, 0); + LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); + LOG_DEBUG(" addrbits=%d", get_field(dtmcontrol, DTMCONTROL_ADDRBITS)); + LOG_DEBUG(" version=%d", get_field(dtmcontrol, DTMCONTROL_VERSION)); + LOG_DEBUG(" idle=%d", get_field(dtmcontrol, DTMCONTROL_IDLE)); + if (dtmcontrol == 0) { + LOG_ERROR("dtmcontrol is 0. Check JTAG connectivity/board power."); + return ERROR_FAIL; + } + if (get_field(dtmcontrol, DTMCONTROL_VERSION) != 0) { + LOG_ERROR("Unsupported DTM version %d. (dtmcontrol=0x%x)", + get_field(dtmcontrol, DTMCONTROL_VERSION), dtmcontrol); + return ERROR_FAIL; + } + + RISCV_INFO(r); + r->hart_count = 1; + + riscv011_info_t *info = get_info(target); + info->addrbits = get_field(dtmcontrol, DTMCONTROL_ADDRBITS); + info->dtmcontrol_idle = get_field(dtmcontrol, DTMCONTROL_IDLE); + if (info->dtmcontrol_idle == 0) { + /* Some old SiFive cores don't set idle but need it to be 1. */ + uint32_t idcode = idcode_scan(target); + if (idcode == 0x10e31913) + info->dtmcontrol_idle = 1; + } + + uint32_t dminfo = dbus_read(target, DMINFO); + LOG_DEBUG("dminfo: 0x%08x", dminfo); + LOG_DEBUG(" abussize=0x%x", get_field(dminfo, DMINFO_ABUSSIZE)); + LOG_DEBUG(" serialcount=0x%x", get_field(dminfo, DMINFO_SERIALCOUNT)); + LOG_DEBUG(" access128=%d", get_field(dminfo, DMINFO_ACCESS128)); + LOG_DEBUG(" access64=%d", get_field(dminfo, DMINFO_ACCESS64)); + LOG_DEBUG(" access32=%d", get_field(dminfo, DMINFO_ACCESS32)); + LOG_DEBUG(" access16=%d", get_field(dminfo, DMINFO_ACCESS16)); + LOG_DEBUG(" access8=%d", get_field(dminfo, DMINFO_ACCESS8)); + LOG_DEBUG(" dramsize=0x%x", get_field(dminfo, DMINFO_DRAMSIZE)); + LOG_DEBUG(" authenticated=0x%x", get_field(dminfo, DMINFO_AUTHENTICATED)); + LOG_DEBUG(" authbusy=0x%x", get_field(dminfo, DMINFO_AUTHBUSY)); + LOG_DEBUG(" authtype=0x%x", get_field(dminfo, DMINFO_AUTHTYPE)); + LOG_DEBUG(" version=0x%x", get_field(dminfo, DMINFO_VERSION)); + + if (get_field(dminfo, DMINFO_VERSION) != 1) { + LOG_ERROR("OpenOCD only supports Debug Module version 1, not %d " + "(dminfo=0x%x)", get_field(dminfo, DMINFO_VERSION), dminfo); + return ERROR_FAIL; + } + + info->dramsize = get_field(dminfo, DMINFO_DRAMSIZE) + 1; + + if (get_field(dminfo, DMINFO_AUTHTYPE) != 0) { + LOG_ERROR("Authentication required by RISC-V core but not " + "supported by OpenOCD. dminfo=0x%x", dminfo); + return ERROR_FAIL; + } + + /* Pretend this is a 32-bit system until we have found out the true value. */ + r->xlen[0] = 32; + + /* Figure out XLEN, and test writing all of Debug RAM while we're at it. */ + cache_set32(target, 0, xori(S1, ZERO, -1)); + /* 0xffffffff 0xffffffff:ffffffff 0xffffffff:ffffffff:ffffffff:ffffffff */ + cache_set32(target, 1, srli(S1, S1, 31)); + /* 0x00000001 0x00000001:ffffffff 0x00000001:ffffffff:ffffffff:ffffffff */ + cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START)); + cache_set32(target, 3, srli(S1, S1, 31)); + /* 0x00000000 0x00000000:00000003 0x00000000:00000003:ffffffff:ffffffff */ + cache_set32(target, 4, sw(S1, ZERO, DEBUG_RAM_START + 4)); + cache_set_jump(target, 5); + for (unsigned i = 6; i < info->dramsize; i++) + cache_set32(target, i, i * 0x01020304); + + cache_write(target, 0, false); + + /* Check that we can actually read/write dram. */ + if (cache_check(target) != ERROR_OK) + return ERROR_FAIL; + + cache_write(target, 0, true); + cache_invalidate(target); + + uint32_t word0 = cache_get32(target, 0); + uint32_t word1 = cache_get32(target, 1); + riscv_info_t *generic_info = (riscv_info_t *) target->arch_info; + if (word0 == 1 && word1 == 0) { + generic_info->xlen[0] = 32; + } else if (word0 == 0xffffffff && word1 == 3) { + generic_info->xlen[0] = 64; + } else if (word0 == 0xffffffff && word1 == 0xffffffff) { + generic_info->xlen[0] = 128; + } else { + uint32_t exception = cache_get32(target, info->dramsize-1); + LOG_ERROR("Failed to discover xlen; word0=0x%x, word1=0x%x, exception=0x%x", + word0, word1, exception); + dump_debug_ram(target); + return ERROR_FAIL; + } + LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target)); + + if (read_csr(target, &r->misa[0], CSR_MISA) != ERROR_OK) { + const unsigned old_csr_misa = 0xf10; + LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA, + old_csr_misa); + if (read_csr(target, &r->misa[0], old_csr_misa) != ERROR_OK) { + /* Maybe this is an old core that still has $misa at the old + * address. */ + LOG_ERROR("Failed to read misa at 0x%x.", old_csr_misa); + return ERROR_FAIL; + } + } + + /* Update register list to match discovered XLEN/supported extensions. */ + riscv_init_registers(target); + + info->never_halted = true; + + int result = riscv011_poll(target); + if (result != ERROR_OK) + return result; + + target_set_examined(target); + riscv_set_current_hartid(target, 0); + for (size_t i = 0; i < 32; ++i) + reg_cache_set(target, i, -1); + LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64, + riscv_xlen(target), r->misa[0]); + + return ERROR_OK; +} + +static riscv_error_t handle_halt_routine(struct target *target) +{ + riscv011_info_t *info = get_info(target); + + scans_t *scans = scans_new(target, 256); + + /* Read all GPRs as fast as we can, because gdb is going to ask for them + * anyway. Reading them one at a time is much slower. */ + + /* Write the jump back to address 1. */ + scans_add_write_jump(scans, 1, false); + for (int reg = 1; reg < 32; reg++) { + if (reg == S0 || reg == S1) + continue; + + /* Write store instruction. */ + scans_add_write_store(scans, 0, reg, SLOT0, true); + + /* Read value. */ + scans_add_read(scans, SLOT0, false); + } + + /* Write store of s0 at index 1. */ + scans_add_write_store(scans, 1, S0, SLOT0, false); + /* Write jump at index 2. */ + scans_add_write_jump(scans, 2, false); + + /* Read S1 from debug RAM */ + scans_add_write_load(scans, 0, S0, SLOT_LAST, true); + /* Read value. */ + scans_add_read(scans, SLOT0, false); + + /* Read S0 from dscratch */ + unsigned int csr[] = {CSR_DSCRATCH, CSR_DPC, CSR_DCSR}; + for (unsigned int i = 0; i < DIM(csr); i++) { + scans_add_write32(scans, 0, csrr(S0, csr[i]), true); + scans_add_read(scans, SLOT0, false); + } + + /* Final read to get the last value out. */ + scans_add_read32(scans, 4, false); + + int retval = scans_execute(scans); + if (retval != ERROR_OK) { + LOG_ERROR("JTAG execute failed: %d", retval); + goto error; + } + + unsigned int dbus_busy = 0; + unsigned int interrupt_set = 0; + unsigned result = 0; + uint64_t value = 0; + reg_cache_set(target, 0, 0); + /* The first scan result is the result from something old we don't care + * about. */ + for (unsigned int i = 1; i < scans->next_scan && dbus_busy == 0; i++) { + dbus_status_t status = scans_get_u32(scans, i, DBUS_OP_START, + DBUS_OP_SIZE); + uint64_t data = scans_get_u64(scans, i, DBUS_DATA_START, DBUS_DATA_SIZE); + uint32_t address = scans_get_u32(scans, i, DBUS_ADDRESS_START, + info->addrbits); + switch (status) { + case DBUS_STATUS_SUCCESS: + break; + case DBUS_STATUS_FAILED: + LOG_ERROR("Debug access failed. Hardware error?"); + goto error; + case DBUS_STATUS_BUSY: + dbus_busy++; + break; + default: + LOG_ERROR("Got invalid bus access status: %d", status); + return ERROR_FAIL; + } + if (data & DMCONTROL_INTERRUPT) { + interrupt_set++; + break; + } + if (address == 4 || address == 5) { + unsigned int reg; + switch (result) { + case 0: + reg = 1; + break; + case 1: + reg = 2; + break; + case 2: + reg = 3; + break; + case 3: + reg = 4; + break; + case 4: + reg = 5; + break; + case 5: + reg = 6; + break; + case 6: + reg = 7; + break; + /* S0 */ + /* S1 */ + case 7: + reg = 10; + break; + case 8: + reg = 11; + break; + case 9: + reg = 12; + break; + case 10: + reg = 13; + break; + case 11: + reg = 14; + break; + case 12: + reg = 15; + break; + case 13: + reg = 16; + break; + case 14: + reg = 17; + break; + case 15: + reg = 18; + break; + case 16: + reg = 19; + break; + case 17: + reg = 20; + break; + case 18: + reg = 21; + break; + case 19: + reg = 22; + break; + case 20: + reg = 23; + break; + case 21: + reg = 24; + break; + case 22: + reg = 25; + break; + case 23: + reg = 26; + break; + case 24: + reg = 27; + break; + case 25: + reg = 28; + break; + case 26: + reg = 29; + break; + case 27: + reg = 30; + break; + case 28: + reg = 31; + break; + case 29: + reg = S1; + break; + case 30: + reg = S0; + break; + case 31: + reg = CSR_DPC; + break; + case 32: + reg = CSR_DCSR; + break; + default: + assert(0); + } + if (riscv_xlen(target) == 32) { + reg_cache_set(target, reg, data & 0xffffffff); + result++; + } else if (riscv_xlen(target) == 64) { + if (address == 4) { + value = data & 0xffffffff; + } else if (address == 5) { + reg_cache_set(target, reg, ((data & 0xffffffff) << 32) | value); + value = 0; + result++; + } + } + } + } + + if (dbus_busy) { + increase_dbus_busy_delay(target); + return RE_AGAIN; + } + if (interrupt_set) { + increase_interrupt_high_delay(target); + return RE_AGAIN; + } + + /* TODO: get rid of those 2 variables and talk to the cache directly. */ + info->dpc = reg_cache_get(target, CSR_DPC); + info->dcsr = reg_cache_get(target, CSR_DCSR); + + scans_delete(scans); + + cache_invalidate(target); + + return RE_OK; + +error: + scans_delete(scans); + return RE_FAIL; +} + +static int handle_halt(struct target *target, bool announce) +{ + riscv011_info_t *info = get_info(target); + target->state = TARGET_HALTED; + + riscv_error_t re; + do { + re = handle_halt_routine(target); + } while (re == RE_AGAIN); + if (re != RE_OK) { + LOG_ERROR("handle_halt_routine failed"); + return ERROR_FAIL; + } + + int cause = get_field(info->dcsr, DCSR_CAUSE); + switch (cause) { + case DCSR_CAUSE_SWBP: + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case DCSR_CAUSE_HWBP: + target->debug_reason = DBG_REASON_WPTANDBKPT; + /* If we halted because of a data trigger, gdb doesn't know to do + * the disable-breakpoints-step-enable-breakpoints dance. */ + info->need_strict_step = true; + break; + case DCSR_CAUSE_DEBUGINT: + target->debug_reason = DBG_REASON_DBGRQ; + break; + case DCSR_CAUSE_STEP: + target->debug_reason = DBG_REASON_SINGLESTEP; + break; + case DCSR_CAUSE_HALT: + default: + LOG_ERROR("Invalid halt cause %d in DCSR (0x%" PRIx64 ")", + cause, info->dcsr); + } + + if (info->never_halted) { + info->never_halted = false; + + int result = maybe_read_tselect(target); + if (result != ERROR_OK) + return result; + riscv_enumerate_triggers(target); + } + + if (target->debug_reason == DBG_REASON_BREAKPOINT) { + int retval; + if (riscv_semihosting(target, &retval) != 0) + return retval; + } + + if (announce) + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + const char *cause_string[] = { + "none", + "software breakpoint", + "hardware trigger", + "debug interrupt", + "step", + "halt" + }; + /* This is logged to the user so that gdb will show it when a user types + * 'monitor reset init'. At that time gdb appears to have the pc cached + * still so if a user manually inspects the pc it will still have the old + * value. */ + LOG_USER("halted at 0x%" PRIx64 " due to %s", info->dpc, cause_string[cause]); + + return ERROR_OK; +} + +static int poll_target(struct target *target, bool announce) +{ + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); + + /* Inhibit debug logging during poll(), which isn't usually interesting and + * just fills up the screen/logs with clutter. */ + int old_debug_level = debug_level; + if (debug_level >= LOG_LVL_DEBUG) + debug_level = LOG_LVL_INFO; + bits_t bits = read_bits(target); + debug_level = old_debug_level; + + if (bits.haltnot && bits.interrupt) { + target->state = TARGET_DEBUG_RUNNING; + LOG_DEBUG("debug running"); + } else if (bits.haltnot && !bits.interrupt) { + if (target->state != TARGET_HALTED) + return handle_halt(target, announce); + } else if (!bits.haltnot && bits.interrupt) { + /* Target is halting. There is no state for that, so don't change anything. */ + LOG_DEBUG("halting"); + } else if (!bits.haltnot && !bits.interrupt) { + target->state = TARGET_RUNNING; + } + + return ERROR_OK; +} + +static int riscv011_poll(struct target *target) +{ + return poll_target(target, true); +} + +static int riscv011_resume(struct target *target, int current, + target_addr_t address, int handle_breakpoints, int debug_execution) +{ + riscv011_info_t *info = get_info(target); + + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); + + if (!current) { + if (riscv_xlen(target) > 32) { + LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.", + riscv_xlen(target)); + } + int result = register_write(target, GDB_REGNO_PC, address); + if (result != ERROR_OK) + return result; + } + + if (info->need_strict_step || handle_breakpoints) { + int result = strict_step(target, false); + if (result != ERROR_OK) + return result; + } + + return resume(target, debug_execution, false); +} + +static int assert_reset(struct target *target) +{ + riscv011_info_t *info = get_info(target); + /* TODO: Maybe what I implemented here is more like soft_reset_halt()? */ + + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); + + /* The only assumption we can make is that the TAP was reset. */ + if (wait_for_debugint_clear(target, true) != ERROR_OK) { + LOG_ERROR("Debug interrupt didn't clear."); + return ERROR_FAIL; + } + + /* Not sure what we should do when there are multiple cores. + * Here just reset the single hart we're talking to. */ + info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | + DCSR_EBREAKU | DCSR_HALT; + if (target->reset_halt) + info->dcsr |= DCSR_NDRESET; + else + info->dcsr |= DCSR_FULLRESET; + dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false); + dram_write32(target, 1, csrw(S0, CSR_DCSR), false); + /* We shouldn't actually need the jump because a reset should happen. */ + dram_write_jump(target, 2, false); + dram_write32(target, 4, info->dcsr, true); + cache_invalidate(target); + + target->state = TARGET_RESET; + + return ERROR_OK; +} + +static int deassert_reset(struct target *target) +{ + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); + if (target->reset_halt) + return wait_for_state(target, TARGET_HALTED); + else + return wait_for_state(target, TARGET_RUNNING); +} + +static int read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); + + cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16)); + switch (size) { + case 1: + cache_set32(target, 1, lb(S1, S0, 0)); + cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16)); + break; + case 2: + cache_set32(target, 1, lh(S1, S0, 0)); + cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16)); + break; + case 4: + cache_set32(target, 1, lw(S1, S0, 0)); + cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16)); + break; + default: + LOG_ERROR("Unsupported size: %d", size); + return ERROR_FAIL; + } + cache_set_jump(target, 3); + cache_write(target, CACHE_NO_READ, false); + + riscv011_info_t *info = get_info(target); + const unsigned max_batch_size = 256; + scans_t *scans = scans_new(target, max_batch_size); + + uint32_t result_value = 0x777; + uint32_t i = 0; + while (i < count + 3) { + unsigned int batch_size = MIN(count + 3 - i, max_batch_size); + scans_reset(scans); + + for (unsigned int j = 0; j < batch_size; j++) { + if (i + j == count) { + /* Just insert a read so we can scan out the last value. */ + scans_add_read32(scans, 4, false); + } else if (i + j >= count + 1) { + /* And check for errors. */ + scans_add_read32(scans, info->dramsize-1, false); + } else { + /* Write the next address and set interrupt. */ + uint32_t offset = size * (i + j); + scans_add_write32(scans, 4, address + offset, true); + } + } + + int retval = scans_execute(scans); + if (retval != ERROR_OK) { + LOG_ERROR("JTAG execute failed: %d", retval); + goto error; + } + + int dbus_busy = 0; + int execute_busy = 0; + for (unsigned int j = 0; j < batch_size; j++) { + dbus_status_t status = scans_get_u32(scans, j, DBUS_OP_START, + DBUS_OP_SIZE); + switch (status) { + case DBUS_STATUS_SUCCESS: + break; + case DBUS_STATUS_FAILED: + LOG_ERROR("Debug RAM write failed. Hardware error?"); + goto error; + case DBUS_STATUS_BUSY: + dbus_busy++; + break; + default: + LOG_ERROR("Got invalid bus access status: %d", status); + return ERROR_FAIL; + } + uint64_t data = scans_get_u64(scans, j, DBUS_DATA_START, + DBUS_DATA_SIZE); + if (data & DMCONTROL_INTERRUPT) + execute_busy++; + if (i + j == count + 2) { + result_value = data; + } else if (i + j > 1) { + uint32_t offset = size * (i + j - 2); + switch (size) { + case 1: + buffer[offset] = data; + break; + case 2: + buffer[offset] = data; + buffer[offset+1] = data >> 8; + break; + case 4: + buffer[offset] = data; + buffer[offset+1] = data >> 8; + buffer[offset+2] = data >> 16; + buffer[offset+3] = data >> 24; + break; + } + } + LOG_DEBUG("j=%d status=%d data=%09" PRIx64, j, status, data); + } + if (dbus_busy) + increase_dbus_busy_delay(target); + if (execute_busy) + increase_interrupt_high_delay(target); + if (dbus_busy || execute_busy) { + wait_for_debugint_clear(target, false); + + /* Retry. */ + LOG_INFO("Retrying memory read starting from 0x%" TARGET_PRIxADDR + " with more delays", address + size * i); + } else { + i += batch_size; + } + } + + if (result_value != 0) { + LOG_USER("Core got an exception (0x%x) while reading from 0x%" + TARGET_PRIxADDR, result_value, address + size * (count-1)); + if (count > 1) { + LOG_USER("(It may have failed between 0x%" TARGET_PRIxADDR + " and 0x%" TARGET_PRIxADDR " as well, but we " + "didn't check then.)", + address, address + size * (count-2) + size - 1); + } + goto error; + } + + scans_delete(scans); + cache_clean(target); + return ERROR_OK; + +error: + scans_delete(scans); + cache_clean(target); + return ERROR_FAIL; +} + +static int setup_write_memory(struct target *target, uint32_t size) +{ + switch (size) { + case 1: + cache_set32(target, 0, lb(S0, ZERO, DEBUG_RAM_START + 16)); + cache_set32(target, 1, sb(S0, T0, 0)); + break; + case 2: + cache_set32(target, 0, lh(S0, ZERO, DEBUG_RAM_START + 16)); + cache_set32(target, 1, sh(S0, T0, 0)); + break; + case 4: + cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16)); + cache_set32(target, 1, sw(S0, T0, 0)); + break; + default: + LOG_ERROR("Unsupported size: %d", size); + return ERROR_FAIL; + } + cache_set32(target, 2, addi(T0, T0, size)); + cache_set_jump(target, 3); + cache_write(target, 4, false); + + return ERROR_OK; +} + +static int write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + riscv011_info_t *info = get_info(target); + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); + + /* Set up the address. */ + cache_set_store(target, 0, T0, SLOT1); + cache_set_load(target, 1, T0, SLOT0); + cache_set_jump(target, 2); + cache_set(target, SLOT0, address); + if (cache_write(target, 5, true) != ERROR_OK) + return ERROR_FAIL; + + uint64_t t0 = cache_get(target, SLOT1); + LOG_DEBUG("t0 is 0x%" PRIx64, t0); + + if (setup_write_memory(target, size) != ERROR_OK) + return ERROR_FAIL; + + const unsigned max_batch_size = 256; + scans_t *scans = scans_new(target, max_batch_size); + + uint32_t result_value = 0x777; + uint32_t i = 0; + while (i < count + 2) { + unsigned int batch_size = MIN(count + 2 - i, max_batch_size); + scans_reset(scans); + + for (unsigned int j = 0; j < batch_size; j++) { + if (i + j >= count) { + /* Check for an exception. */ + scans_add_read32(scans, info->dramsize-1, false); + } else { + /* Write the next value and set interrupt. */ + uint32_t value; + uint32_t offset = size * (i + j); + switch (size) { + case 1: + value = buffer[offset]; + break; + case 2: + value = buffer[offset] | + (buffer[offset+1] << 8); + break; + case 4: + value = buffer[offset] | + ((uint32_t) buffer[offset+1] << 8) | + ((uint32_t) buffer[offset+2] << 16) | + ((uint32_t) buffer[offset+3] << 24); + break; + default: + goto error; + } + + scans_add_write32(scans, 4, value, true); + } + } + + int retval = scans_execute(scans); + if (retval != ERROR_OK) { + LOG_ERROR("JTAG execute failed: %d", retval); + goto error; + } + + int dbus_busy = 0; + int execute_busy = 0; + for (unsigned int j = 0; j < batch_size; j++) { + dbus_status_t status = scans_get_u32(scans, j, DBUS_OP_START, + DBUS_OP_SIZE); + switch (status) { + case DBUS_STATUS_SUCCESS: + break; + case DBUS_STATUS_FAILED: + LOG_ERROR("Debug RAM write failed. Hardware error?"); + goto error; + case DBUS_STATUS_BUSY: + dbus_busy++; + break; + default: + LOG_ERROR("Got invalid bus access status: %d", status); + return ERROR_FAIL; + } + int interrupt = scans_get_u32(scans, j, DBUS_DATA_START + 33, 1); + if (interrupt) + execute_busy++; + if (i + j == count + 1) + result_value = scans_get_u32(scans, j, DBUS_DATA_START, 32); + } + if (dbus_busy) + increase_dbus_busy_delay(target); + if (execute_busy) + increase_interrupt_high_delay(target); + if (dbus_busy || execute_busy) { + wait_for_debugint_clear(target, false); + + /* Retry. + * Set t0 back to what it should have been at the beginning of this + * batch. */ + LOG_INFO("Retrying memory write starting from 0x%" TARGET_PRIxADDR + " with more delays", address + size * i); + + cache_clean(target); + + if (write_gpr(target, T0, address + size * i) != ERROR_OK) + goto error; + + if (setup_write_memory(target, size) != ERROR_OK) + goto error; + } else { + i += batch_size; + } + } + + if (result_value != 0) { + LOG_ERROR("Core got an exception (0x%x) while writing to 0x%" + TARGET_PRIxADDR, result_value, address + size * (count-1)); + if (count > 1) { + LOG_ERROR("(It may have failed between 0x%" TARGET_PRIxADDR + " and 0x%" TARGET_PRIxADDR " as well, but we " + "didn't check then.)", + address, address + size * (count-2) + size - 1); + } + goto error; + } + + scans_delete(scans); + cache_clean(target); + return register_write(target, T0, t0); + +error: + scans_delete(scans); + cache_clean(target); + return ERROR_FAIL; +} + +static int arch_state(struct target *target) +{ + return ERROR_OK; +} + +struct target_type riscv011_target = { + .name = "riscv", + + .init_target = init_target, + .deinit_target = deinit_target, + .examine = examine, + + /* poll current target status */ + .poll = riscv011_poll, + + .halt = halt, + .resume = riscv011_resume, + .step = step, + + .assert_reset = assert_reset, + .deassert_reset = deassert_reset, + + .read_memory = read_memory, + .write_memory = write_memory, + + .arch_state = arch_state, +}; diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c new file mode 100644 index 000000000..4acd42754 --- /dev/null +++ b/src/target/riscv/riscv-013.c @@ -0,0 +1,3036 @@ +/* + * Support for RISC-V, debug version 0.13, which is currently (2/4/17) the + * latest draft. + */ + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "target/target.h" +#include "target/algorithm.h" +#include "target/target_type.h" +#include "log.h" +#include "jtag/jtag.h" +#include "target/register.h" +#include "target/breakpoints.h" +#include "helper/time_support.h" +#include "helper/list.h" +#include "riscv.h" +#include "debug_defines.h" +#include "rtos/rtos.h" +#include "program.h" +#include "asm.h" +#include "batch.h" + +#define DMI_DATA1 (DMI_DATA0 + 1) +#define DMI_PROGBUF1 (DMI_PROGBUF0 + 1) + +static int riscv013_on_step_or_resume(struct target *target, bool step); +static int riscv013_step_or_resume_current_hart(struct target *target, bool step); +static void riscv013_clear_abstract_error(struct target *target); + +/* Implementations of the functions in riscv_info_t. */ +static int riscv013_get_register(struct target *target, + riscv_reg_t *value, int hid, int rid); +static int riscv013_set_register(struct target *target, int hartid, int regid, uint64_t value); +static int riscv013_select_current_hart(struct target *target); +static int riscv013_halt_current_hart(struct target *target); +static int riscv013_resume_current_hart(struct target *target); +static int riscv013_step_current_hart(struct target *target); +static int riscv013_on_halt(struct target *target); +static int riscv013_on_step(struct target *target); +static int riscv013_on_resume(struct target *target); +static bool riscv013_is_halted(struct target *target); +static enum riscv_halt_reason riscv013_halt_reason(struct target *target); +static int riscv013_write_debug_buffer(struct target *target, unsigned index, + riscv_insn_t d); +static riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned + index); +static int riscv013_execute_debug_buffer(struct target *target); +static void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d); +static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a); +static int riscv013_dmi_write_u64_bits(struct target *target); +static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf); +static int register_read(struct target *target, uint64_t *value, uint32_t number); +static int register_read_direct(struct target *target, uint64_t *value, uint32_t number); +static int register_write_direct(struct target *target, unsigned number, + uint64_t value); +static int read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer); +static int write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer); + +/** + * Since almost everything can be accomplish by scanning the dbus register, all + * functions here assume dbus is already selected. The exception are functions + * called directly by OpenOCD, which can't assume anything about what's + * currently in IR. They should set IR to dbus explicitly. + */ + +#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) +#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) + +#define DIM(x) (sizeof(x)/sizeof(*x)) + +#define CSR_DCSR_CAUSE_SWBP 1 +#define CSR_DCSR_CAUSE_TRIGGER 2 +#define CSR_DCSR_CAUSE_DEBUGINT 3 +#define CSR_DCSR_CAUSE_STEP 4 +#define CSR_DCSR_CAUSE_HALT 5 + +#define RISCV013_INFO(r) riscv013_info_t *r = get_info(target) + +/*** JTAG registers. ***/ + +typedef enum { + DMI_OP_NOP = 0, + DMI_OP_READ = 1, + DMI_OP_WRITE = 2 +} dmi_op_t; +typedef enum { + DMI_STATUS_SUCCESS = 0, + DMI_STATUS_FAILED = 2, + DMI_STATUS_BUSY = 3 +} dmi_status_t; + +typedef enum { + RE_OK, + RE_FAIL, + RE_AGAIN +} riscv_error_t; + +typedef enum slot { + SLOT0, + SLOT1, + SLOT_LAST, +} slot_t; + +/*** Debug Bus registers. ***/ + +#define CMDERR_NONE 0 +#define CMDERR_BUSY 1 +#define CMDERR_NOT_SUPPORTED 2 +#define CMDERR_EXCEPTION 3 +#define CMDERR_HALT_RESUME 4 +#define CMDERR_OTHER 7 + +/*** Info about the core being debugged. ***/ + +struct trigger { + uint64_t address; + uint32_t length; + uint64_t mask; + uint64_t value; + bool read, write, execute; + int unique_id; +}; + +typedef enum { + YNM_MAYBE, + YNM_YES, + YNM_NO +} yes_no_maybe_t; + +typedef struct { + struct list_head list; + int abs_chain_position; + /* Indicates we already reset this DM, so don't need to do it again. */ + bool was_reset; + /* Targets that are connected to this DM. */ + struct list_head target_list; + /* The currently selected hartid on this DM. */ + int current_hartid; +} dm013_info_t; + +typedef struct { + struct list_head list; + struct target *target; +} target_list_t; + +typedef struct { + /* Number of address bits in the dbus register. */ + unsigned abits; + /* Number of abstract command data registers. */ + unsigned datacount; + /* Number of words in the Program Buffer. */ + unsigned progbufsize; + + /* We cache the read-only bits of sbcs here. */ + uint32_t sbcs; + + yes_no_maybe_t progbuf_writable; + /* We only need the address so that we know the alignment of the buffer. */ + riscv_addr_t progbuf_address; + + /* Number of run-test/idle cycles the target requests we do after each dbus + * access. */ + unsigned int dtmcontrol_idle; + + /* This value is incremented every time a dbus access comes back as "busy". + * It's used to determine how many run-test/idle cycles to feed the target + * in between accesses. */ + unsigned int dmi_busy_delay; + + /* Number of run-test/idle cycles to add between consecutive bus master + * reads/writes respectively. */ + unsigned int bus_master_write_delay, bus_master_read_delay; + + /* This value is increased every time we tried to execute two commands + * consecutively, and the second one failed because the previous hadn't + * completed yet. It's used to add extra run-test/idle cycles after + * starting a command, so we don't have to waste time checking for busy to + * go low. */ + unsigned int ac_busy_delay; + + bool need_strict_step; + + bool abstract_read_csr_supported; + bool abstract_write_csr_supported; + bool abstract_read_fpr_supported; + bool abstract_write_fpr_supported; + + /* When a function returns some error due to a failure indicated by the + * target in cmderr, the caller can look here to see what that error was. + * (Compare with errno.) */ + uint8_t cmderr; + + /* Some fields from hartinfo. */ + uint8_t datasize; + uint8_t dataaccess; + int16_t dataaddr; + + /* The width of the hartsel field. */ + unsigned hartsellen; + + /* DM that provides access to this target. */ + dm013_info_t *dm; +} riscv013_info_t; + +LIST_HEAD(dm_list); + +static riscv013_info_t *get_info(const struct target *target) +{ + riscv_info_t *info = (riscv_info_t *) target->arch_info; + return (riscv013_info_t *) info->version_specific; +} + +/** + * Return the DM structure for this target. If there isn't one, find it in the + * global list of DMs. If it's not in there, then create one and initialize it + * to 0. + */ +static dm013_info_t *get_dm(struct target *target) +{ + RISCV013_INFO(info); + if (info->dm) + return info->dm; + + int abs_chain_position = target->tap->abs_chain_position; + + dm013_info_t *entry; + dm013_info_t *dm = NULL; + list_for_each_entry(entry, &dm_list, list) { + if (entry->abs_chain_position == abs_chain_position) { + dm = entry; + break; + } + } + + if (!dm) { + dm = calloc(1, sizeof(dm013_info_t)); + dm->abs_chain_position = abs_chain_position; + dm->current_hartid = -1; + INIT_LIST_HEAD(&dm->target_list); + list_add(&dm->list, &dm_list); + } + + info->dm = dm; + target_list_t *target_entry; + list_for_each_entry(target_entry, &dm->target_list, list) { + if (target_entry->target == target) + return dm; + } + target_entry = calloc(1, sizeof(*target_entry)); + target_entry->target = target; + list_add(&target_entry->list, &dm->target_list); + + return dm; +} + +static uint32_t set_hartsel(uint32_t initial, uint32_t index) +{ + initial &= ~DMI_DMCONTROL_HARTSELLO; + initial &= ~DMI_DMCONTROL_HARTSELHI; + + uint32_t index_lo = index & ((1 << DMI_DMCONTROL_HARTSELLO_LENGTH) - 1); + initial |= index_lo << DMI_DMCONTROL_HARTSELLO_OFFSET; + uint32_t index_hi = index >> DMI_DMCONTROL_HARTSELLO_LENGTH; + assert(index_hi < 1 << DMI_DMCONTROL_HARTSELHI_LENGTH); + initial |= index_hi << DMI_DMCONTROL_HARTSELHI_OFFSET; + + return initial; +} + +static void decode_dmi(char *text, unsigned address, unsigned data) +{ + static const struct { + unsigned address; + uint64_t mask; + const char *name; + } description[] = { + { DMI_DMCONTROL, DMI_DMCONTROL_HALTREQ, "haltreq" }, + { DMI_DMCONTROL, DMI_DMCONTROL_RESUMEREQ, "resumereq" }, + { DMI_DMCONTROL, DMI_DMCONTROL_HARTRESET, "hartreset" }, + { DMI_DMCONTROL, DMI_DMCONTROL_HASEL, "hasel" }, + { DMI_DMCONTROL, DMI_DMCONTROL_HARTSELHI, "hartselhi" }, + { DMI_DMCONTROL, DMI_DMCONTROL_HARTSELLO, "hartsello" }, + { DMI_DMCONTROL, DMI_DMCONTROL_NDMRESET, "ndmreset" }, + { DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE, "dmactive" }, + { DMI_DMCONTROL, DMI_DMCONTROL_ACKHAVERESET, "ackhavereset" }, + + { DMI_DMSTATUS, DMI_DMSTATUS_IMPEBREAK, "impebreak" }, + { DMI_DMSTATUS, DMI_DMSTATUS_ALLHAVERESET, "allhavereset" }, + { DMI_DMSTATUS, DMI_DMSTATUS_ANYHAVERESET, "anyhavereset" }, + { DMI_DMSTATUS, DMI_DMSTATUS_ALLRESUMEACK, "allresumeack" }, + { DMI_DMSTATUS, DMI_DMSTATUS_ANYRESUMEACK, "anyresumeack" }, + { DMI_DMSTATUS, DMI_DMSTATUS_ALLNONEXISTENT, "allnonexistent" }, + { DMI_DMSTATUS, DMI_DMSTATUS_ANYNONEXISTENT, "anynonexistent" }, + { DMI_DMSTATUS, DMI_DMSTATUS_ALLUNAVAIL, "allunavail" }, + { DMI_DMSTATUS, DMI_DMSTATUS_ANYUNAVAIL, "anyunavail" }, + { DMI_DMSTATUS, DMI_DMSTATUS_ALLRUNNING, "allrunning" }, + { DMI_DMSTATUS, DMI_DMSTATUS_ANYRUNNING, "anyrunning" }, + { DMI_DMSTATUS, DMI_DMSTATUS_ALLHALTED, "allhalted" }, + { DMI_DMSTATUS, DMI_DMSTATUS_ANYHALTED, "anyhalted" }, + { DMI_DMSTATUS, DMI_DMSTATUS_AUTHENTICATED, "authenticated" }, + { DMI_DMSTATUS, DMI_DMSTATUS_AUTHBUSY, "authbusy" }, + { DMI_DMSTATUS, DMI_DMSTATUS_DEVTREEVALID, "devtreevalid" }, + { DMI_DMSTATUS, DMI_DMSTATUS_VERSION, "version" }, + + { DMI_ABSTRACTCS, DMI_ABSTRACTCS_PROGBUFSIZE, "progbufsize" }, + { DMI_ABSTRACTCS, DMI_ABSTRACTCS_BUSY, "busy" }, + { DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR, "cmderr" }, + { DMI_ABSTRACTCS, DMI_ABSTRACTCS_DATACOUNT, "datacount" }, + + { DMI_COMMAND, DMI_COMMAND_CMDTYPE, "cmdtype" }, + + { DMI_SBCS, DMI_SBCS_SBREADONADDR, "sbreadonaddr" }, + { DMI_SBCS, DMI_SBCS_SBACCESS, "sbaccess" }, + { DMI_SBCS, DMI_SBCS_SBAUTOINCREMENT, "sbautoincrement" }, + { DMI_SBCS, DMI_SBCS_SBREADONDATA, "sbreadondata" }, + { DMI_SBCS, DMI_SBCS_SBERROR, "sberror" }, + { DMI_SBCS, DMI_SBCS_SBASIZE, "sbasize" }, + { DMI_SBCS, DMI_SBCS_SBACCESS128, "sbaccess128" }, + { DMI_SBCS, DMI_SBCS_SBACCESS64, "sbaccess64" }, + { DMI_SBCS, DMI_SBCS_SBACCESS32, "sbaccess32" }, + { DMI_SBCS, DMI_SBCS_SBACCESS16, "sbaccess16" }, + { DMI_SBCS, DMI_SBCS_SBACCESS8, "sbaccess8" }, + }; + + text[0] = 0; + for (unsigned i = 0; i < DIM(description); i++) { + if (description[i].address == address) { + uint64_t mask = description[i].mask; + unsigned value = get_field(data, mask); + if (value) { + if (i > 0) + *(text++) = ' '; + if (mask & (mask >> 1)) { + /* If the field is more than 1 bit wide. */ + sprintf(text, "%s=%d", description[i].name, value); + } else { + strcpy(text, description[i].name); + } + text += strlen(text); + } + } + } +} + +static void dump_field(const struct scan_field *field) +{ + static const char * const op_string[] = {"-", "r", "w", "?"}; + static const char * const status_string[] = {"+", "?", "F", "b"}; + + if (debug_level < LOG_LVL_DEBUG) + return; + + uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits); + unsigned int out_op = get_field(out, DTM_DMI_OP); + unsigned int out_data = get_field(out, DTM_DMI_DATA); + unsigned int out_address = out >> DTM_DMI_ADDRESS_OFFSET; + + uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits); + unsigned int in_op = get_field(in, DTM_DMI_OP); + unsigned int in_data = get_field(in, DTM_DMI_DATA); + unsigned int in_address = in >> DTM_DMI_ADDRESS_OFFSET; + + log_printf_lf(LOG_LVL_DEBUG, + __FILE__, __LINE__, "scan", + "%db %s %08x @%02x -> %s %08x @%02x", + field->num_bits, + op_string[out_op], out_data, out_address, + status_string[in_op], in_data, in_address); + + char out_text[500]; + char in_text[500]; + decode_dmi(out_text, out_address, out_data); + decode_dmi(in_text, in_address, in_data); + if (in_text[0] || out_text[0]) { + log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, "scan", "%s -> %s", + out_text, in_text); + } +} + +/*** Utility functions. ***/ + +static void select_dmi(struct target *target) +{ + static uint8_t ir_dmi[1] = {DTM_DMI}; + struct scan_field field = { + .num_bits = target->tap->ir_length, + .out_value = ir_dmi, + .in_value = NULL, + .check_value = NULL, + .check_mask = NULL + }; + + jtag_add_ir_scan(target->tap, &field, TAP_IDLE); +} + +static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) +{ + struct scan_field field; + uint8_t in_value[4]; + uint8_t out_value[4]; + + buf_set_u32(out_value, 0, 32, out); + + jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE); + + field.num_bits = 32; + field.out_value = out_value; + field.in_value = in_value; + jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); + + /* Always return to dmi. */ + select_dmi(target); + + int retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("failed jtag scan: %d", retval); + return retval; + } + + uint32_t in = buf_get_u32(field.in_value, 0, 32); + LOG_DEBUG("DTMCS: 0x%x -> 0x%x", out, in); + + return in; +} + +static void increase_dmi_busy_delay(struct target *target) +{ + riscv013_info_t *info = get_info(target); + info->dmi_busy_delay += info->dmi_busy_delay / 10 + 1; + LOG_DEBUG("dtmcontrol_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", + info->dtmcontrol_idle, info->dmi_busy_delay, + info->ac_busy_delay); + + dtmcontrol_scan(target, DTM_DTMCS_DMIRESET); +} + +/** + * exec: If this is set, assume the scan results in an execution, so more + * run-test/idle cycles may be required. + */ +static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, + uint32_t *data_in, dmi_op_t op, uint32_t address_out, uint32_t data_out, + bool exec) +{ + riscv013_info_t *info = get_info(target); + uint8_t in[8] = {0}; + uint8_t out[8]; + struct scan_field field = { + .num_bits = info->abits + DTM_DMI_OP_LENGTH + DTM_DMI_DATA_LENGTH, + .out_value = out, + .in_value = in + }; + + assert(info->abits != 0); + + buf_set_u32(out, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, op); + buf_set_u32(out, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, data_out); + buf_set_u32(out, DTM_DMI_ADDRESS_OFFSET, info->abits, address_out); + + /* Assume dbus is already selected. */ + jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); + + int idle_count = info->dmi_busy_delay; + if (exec) + idle_count += info->ac_busy_delay; + + if (idle_count) + jtag_add_runtest(idle_count, TAP_IDLE); + + int retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("dmi_scan failed jtag scan"); + return DMI_STATUS_FAILED; + } + + if (data_in) + *data_in = buf_get_u32(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); + + if (address_in) + *address_in = buf_get_u32(in, DTM_DMI_ADDRESS_OFFSET, info->abits); + + dump_field(&field); + + return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); +} + +static int dmi_op_timeout(struct target *target, uint32_t *data_in, int dmi_op, + uint32_t address, uint32_t data_out, int timeout_sec) +{ + select_dmi(target); + + dmi_status_t status; + uint32_t address_in; + + const char *op_name; + switch (dmi_op) { + case DMI_OP_NOP: + op_name = "nop"; + break; + case DMI_OP_READ: + op_name = "read"; + break; + case DMI_OP_WRITE: + op_name = "write"; + break; + default: + LOG_ERROR("Invalid DMI operation: %d", dmi_op); + return ERROR_FAIL; + } + + time_t start = time(NULL); + /* This first loop performs the request. Note that if for some reason this + * stays busy, it is actually due to the previous access. */ + while (1) { + status = dmi_scan(target, NULL, NULL, dmi_op, address, data_out, + false); + if (status == DMI_STATUS_BUSY) { + increase_dmi_busy_delay(target); + } else if (status == DMI_STATUS_SUCCESS) { + break; + } else { + LOG_ERROR("failed %s at 0x%x, status=%d", op_name, address, status); + return ERROR_FAIL; + } + if (time(NULL) - start > timeout_sec) + return ERROR_TIMEOUT_REACHED; + } + + if (status != DMI_STATUS_SUCCESS) { + LOG_ERROR("Failed %s at 0x%x; status=%d", op_name, address, status); + return ERROR_FAIL; + } + + /* This second loop ensures the request succeeded, and gets back data. + * Note that NOP can result in a 'busy' result as well, but that would be + * noticed on the next DMI access we do. */ + while (1) { + status = dmi_scan(target, &address_in, data_in, DMI_OP_NOP, address, 0, + false); + if (status == DMI_STATUS_BUSY) { + increase_dmi_busy_delay(target); + } else if (status == DMI_STATUS_SUCCESS) { + break; + } else { + LOG_ERROR("failed %s (NOP) at 0x%x, status=%d", op_name, address, + status); + return ERROR_FAIL; + } + if (time(NULL) - start > timeout_sec) + return ERROR_TIMEOUT_REACHED; + } + + if (status != DMI_STATUS_SUCCESS) { + if (status == DMI_STATUS_FAILED || !data_in) { + LOG_ERROR("Failed %s (NOP) at 0x%x; status=%d", op_name, address, + status); + } else { + LOG_ERROR("Failed %s (NOP) at 0x%x; value=0x%x, status=%d", + op_name, address, *data_in, status); + } + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int dmi_op(struct target *target, uint32_t *data_in, int dmi_op, + uint32_t address, uint32_t data_out) +{ + int result = dmi_op_timeout(target, data_in, dmi_op, address, data_out, + riscv_command_timeout_sec); + if (result == ERROR_TIMEOUT_REACHED) { + LOG_ERROR("DMI operation didn't complete in %d seconds. The target is " + "either really slow or broken. You could increase the " + "timeout with riscv set_command_timeout_sec.", + riscv_command_timeout_sec); + return ERROR_FAIL; + } + return result; +} + +static int dmi_read(struct target *target, uint32_t *value, uint32_t address) +{ + return dmi_op(target, value, DMI_OP_READ, address, 0); +} + +static int dmi_write(struct target *target, uint32_t address, uint32_t value) +{ + return dmi_op(target, NULL, DMI_OP_WRITE, address, value); +} + +int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus, + bool authenticated, unsigned timeout_sec) +{ + int result = dmi_op_timeout(target, dmstatus, DMI_OP_READ, DMI_DMSTATUS, 0, + timeout_sec); + if (result != ERROR_OK) + return result; + if (authenticated && !get_field(*dmstatus, DMI_DMSTATUS_AUTHENTICATED)) { + LOG_ERROR("Debugger is not authenticated to target Debug Module. " + "(dmstatus=0x%x). Use `riscv authdata_read` and " + "`riscv authdata_write` commands to authenticate.", *dmstatus); + return ERROR_FAIL; + } + return ERROR_OK; +} + +int dmstatus_read(struct target *target, uint32_t *dmstatus, + bool authenticated) +{ + return dmstatus_read_timeout(target, dmstatus, authenticated, + riscv_command_timeout_sec); +} + +static void increase_ac_busy_delay(struct target *target) +{ + riscv013_info_t *info = get_info(target); + info->ac_busy_delay += info->ac_busy_delay / 10 + 1; + LOG_DEBUG("dtmcontrol_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", + info->dtmcontrol_idle, info->dmi_busy_delay, + info->ac_busy_delay); +} + +uint32_t abstract_register_size(unsigned width) +{ + switch (width) { + case 32: + return set_field(0, AC_ACCESS_REGISTER_SIZE, 2); + case 64: + return set_field(0, AC_ACCESS_REGISTER_SIZE, 3); + break; + case 128: + return set_field(0, AC_ACCESS_REGISTER_SIZE, 4); + break; + default: + LOG_ERROR("Unsupported register width: %d", width); + return 0; + } +} + +static int wait_for_idle(struct target *target, uint32_t *abstractcs) +{ + RISCV013_INFO(info); + time_t start = time(NULL); + while (1) { + if (dmi_read(target, abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; + + if (get_field(*abstractcs, DMI_ABSTRACTCS_BUSY) == 0) + return ERROR_OK; + + if (time(NULL) - start > riscv_command_timeout_sec) { + info->cmderr = get_field(*abstractcs, DMI_ABSTRACTCS_CMDERR); + if (info->cmderr != CMDERR_NONE) { + const char *errors[8] = { + "none", + "busy", + "not supported", + "exception", + "halt/resume", + "reserved", + "reserved", + "other" }; + + LOG_ERROR("Abstract command ended in error '%s' (abstractcs=0x%x)", + errors[info->cmderr], *abstractcs); + } + + LOG_ERROR("Timed out after %ds waiting for busy to go low (abstractcs=0x%x). " + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_command_timeout_sec, + *abstractcs); + return ERROR_FAIL; + } + } +} + +static int execute_abstract_command(struct target *target, uint32_t command) +{ + RISCV013_INFO(info); + LOG_DEBUG("command=0x%x", command); + dmi_write(target, DMI_COMMAND, command); + + uint32_t abstractcs = 0; + wait_for_idle(target, &abstractcs); + + info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); + if (info->cmderr != 0) { + LOG_DEBUG("command 0x%x failed; abstractcs=0x%x", command, abstractcs); + /* Clear the error. */ + dmi_write(target, DMI_ABSTRACTCS, set_field(0, DMI_ABSTRACTCS_CMDERR, + info->cmderr)); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static riscv_reg_t read_abstract_arg(struct target *target, unsigned index, + unsigned size_bits) +{ + riscv_reg_t value = 0; + uint32_t v; + unsigned offset = index * size_bits / 32; + switch (size_bits) { + default: + LOG_ERROR("Unsupported size: %d", size_bits); + return ~0; + case 64: + dmi_read(target, &v, DMI_DATA0 + offset + 1); + value |= ((uint64_t) v) << 32; + /* falls through */ + case 32: + dmi_read(target, &v, DMI_DATA0 + offset); + value |= v; + } + return value; +} + +static int write_abstract_arg(struct target *target, unsigned index, + riscv_reg_t value, unsigned size_bits) +{ + unsigned offset = index * size_bits / 32; + switch (size_bits) { + default: + LOG_ERROR("Unsupported size: %d", size_bits); + return ERROR_FAIL; + case 64: + dmi_write(target, DMI_DATA0 + offset + 1, value >> 32); + /* falls through */ + case 32: + dmi_write(target, DMI_DATA0 + offset, value); + } + return ERROR_OK; +} + +/** + * @size in bits + */ +static uint32_t access_register_command(uint32_t number, unsigned size, + uint32_t flags) +{ + uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0); + switch (size) { + case 32: + command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2); + break; + case 64: + command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3); + break; + default: + assert(0); + } + + if (number <= GDB_REGNO_XPR31) { + command = set_field(command, AC_ACCESS_REGISTER_REGNO, + 0x1000 + number - GDB_REGNO_ZERO); + } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + command = set_field(command, AC_ACCESS_REGISTER_REGNO, + 0x1020 + number - GDB_REGNO_FPR0); + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + command = set_field(command, AC_ACCESS_REGISTER_REGNO, + number - GDB_REGNO_CSR0); + } else { + assert(0); + } + + command |= flags; + + return command; +} + +static int register_read_abstract(struct target *target, uint64_t *value, + uint32_t number, unsigned size) +{ + RISCV013_INFO(info); + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && + !info->abstract_read_fpr_supported) + return ERROR_FAIL; + if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 && + !info->abstract_read_csr_supported) + return ERROR_FAIL; + + uint32_t command = access_register_command(number, size, + AC_ACCESS_REGISTER_TRANSFER); + + int result = execute_abstract_command(target, command); + if (result != ERROR_OK) { + if (info->cmderr == CMDERR_NOT_SUPPORTED) { + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + info->abstract_read_fpr_supported = false; + LOG_INFO("Disabling abstract command reads from FPRs."); + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + info->abstract_read_csr_supported = false; + LOG_INFO("Disabling abstract command reads from CSRs."); + } + } + return result; + } + + if (value) + *value = read_abstract_arg(target, 0, size); + + return ERROR_OK; +} + +static int register_write_abstract(struct target *target, uint32_t number, + uint64_t value, unsigned size) +{ + RISCV013_INFO(info); + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && + !info->abstract_write_fpr_supported) + return ERROR_FAIL; + if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 && + !info->abstract_write_csr_supported) + return ERROR_FAIL; + + uint32_t command = access_register_command(number, size, + AC_ACCESS_REGISTER_TRANSFER | + AC_ACCESS_REGISTER_WRITE); + + if (write_abstract_arg(target, 0, value, size) != ERROR_OK) + return ERROR_FAIL; + + int result = execute_abstract_command(target, command); + if (result != ERROR_OK) { + if (info->cmderr == CMDERR_NOT_SUPPORTED) { + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + info->abstract_write_fpr_supported = false; + LOG_INFO("Disabling abstract command writes to FPRs."); + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + info->abstract_write_csr_supported = false; + LOG_INFO("Disabling abstract command writes to CSRs."); + } + } + return result; + } + + return ERROR_OK; +} + +static int examine_progbuf(struct target *target) +{ + riscv013_info_t *info = get_info(target); + + if (info->progbuf_writable != YNM_MAYBE) + return ERROR_OK; + + /* Figure out if progbuf is writable. */ + + if (info->progbufsize < 1) { + info->progbuf_writable = YNM_NO; + LOG_INFO("No program buffer present."); + return ERROR_OK; + } + + uint64_t s0; + if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + struct riscv_program program; + riscv_program_init(&program, target); + riscv_program_insert(&program, auipc(S0)); + if (riscv_program_exec(&program, target) != ERROR_OK) + return ERROR_FAIL; + + if (register_read_direct(target, &info->progbuf_address, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + riscv_program_init(&program, target); + riscv_program_insert(&program, sw(S0, S0, 0)); + int result = riscv_program_exec(&program, target); + + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) + return ERROR_FAIL; + + if (result != ERROR_OK) { + /* This program might have failed if the program buffer is not + * writable. */ + info->progbuf_writable = YNM_NO; + return ERROR_OK; + } + + uint32_t written; + if (dmi_read(target, &written, DMI_PROGBUF0) != ERROR_OK) + return ERROR_FAIL; + if (written == (uint32_t) info->progbuf_address) { + LOG_INFO("progbuf is writable at 0x%" PRIx64, + info->progbuf_address); + info->progbuf_writable = YNM_YES; + + } else { + LOG_INFO("progbuf is not writeable at 0x%" PRIx64, + info->progbuf_address); + info->progbuf_writable = YNM_NO; + } + + return ERROR_OK; +} + +typedef enum { + SPACE_DMI_DATA, + SPACE_DMI_PROGBUF, + SPACE_DMI_RAM +} memory_space_t; + +typedef struct { + /* How can the debugger access this memory? */ + memory_space_t memory_space; + /* Memory address to access the scratch memory from the hart. */ + riscv_addr_t hart_address; + /* Memory address to access the scratch memory from the debugger. */ + riscv_addr_t debug_address; + struct working_area *area; +} scratch_mem_t; + +/** + * Find some scratch memory to be used with the given program. + */ +static int scratch_reserve(struct target *target, + scratch_mem_t *scratch, + struct riscv_program *program, + unsigned size_bytes) +{ + riscv_addr_t alignment = 1; + while (alignment < size_bytes) + alignment *= 2; + + scratch->area = NULL; + + riscv013_info_t *info = get_info(target); + + if (info->dataaccess == 1) { + /* Sign extend dataaddr. */ + scratch->hart_address = info->dataaddr; + if (info->dataaddr & (1<<11)) + scratch->hart_address |= 0xfffffffffffff000ULL; + /* Align. */ + scratch->hart_address = (scratch->hart_address + alignment - 1) & ~(alignment - 1); + + if ((size_bytes + scratch->hart_address - info->dataaddr + 3) / 4 >= + info->datasize) { + scratch->memory_space = SPACE_DMI_DATA; + scratch->debug_address = (scratch->hart_address - info->dataaddr) / 4; + return ERROR_OK; + } + } + + if (examine_progbuf(target) != ERROR_OK) + return ERROR_FAIL; + + /* Allow for ebreak at the end of the program. */ + unsigned program_size = (program->instruction_count + 1) * 4; + scratch->hart_address = (info->progbuf_address + program_size + alignment - 1) & + ~(alignment - 1); + if ((size_bytes + scratch->hart_address - info->progbuf_address + 3) / 4 >= + info->progbufsize) { + scratch->memory_space = SPACE_DMI_PROGBUF; + scratch->debug_address = (scratch->hart_address - info->progbuf_address) / 4; + return ERROR_OK; + } + + if (target_alloc_working_area(target, size_bytes + alignment - 1, + &scratch->area) == ERROR_OK) { + scratch->hart_address = (scratch->area->address + alignment - 1) & + ~(alignment - 1); + scratch->memory_space = SPACE_DMI_RAM; + scratch->debug_address = scratch->hart_address; + return ERROR_OK; + } + + LOG_ERROR("Couldn't find %d bytes of scratch RAM to use. Please configure " + "a work area with 'configure -work-area-phys'.", size_bytes); + return ERROR_FAIL; +} + +static int scratch_release(struct target *target, + scratch_mem_t *scratch) +{ + if (scratch->area) + return target_free_working_area(target, scratch->area); + + return ERROR_OK; +} + +static int scratch_read64(struct target *target, scratch_mem_t *scratch, + uint64_t *value) +{ + uint32_t v; + switch (scratch->memory_space) { + case SPACE_DMI_DATA: + if (dmi_read(target, &v, DMI_DATA0 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value = v; + if (dmi_read(target, &v, DMI_DATA1 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value |= ((uint64_t) v) << 32; + break; + case SPACE_DMI_PROGBUF: + if (dmi_read(target, &v, DMI_PROGBUF0 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value = v; + if (dmi_read(target, &v, DMI_PROGBUF1 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value |= ((uint64_t) v) << 32; + break; + case SPACE_DMI_RAM: + { + uint8_t buffer[8]; + if (read_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK) + return ERROR_FAIL; + *value = buffer[0] | + (((uint64_t) buffer[1]) << 8) | + (((uint64_t) buffer[2]) << 16) | + (((uint64_t) buffer[3]) << 24) | + (((uint64_t) buffer[4]) << 32) | + (((uint64_t) buffer[5]) << 40) | + (((uint64_t) buffer[6]) << 48) | + (((uint64_t) buffer[7]) << 56); + } + break; + } + return ERROR_OK; +} + +static int scratch_write64(struct target *target, scratch_mem_t *scratch, + uint64_t value) +{ + switch (scratch->memory_space) { + case SPACE_DMI_DATA: + dmi_write(target, DMI_DATA0 + scratch->debug_address, value); + dmi_write(target, DMI_DATA1 + scratch->debug_address, value >> 32); + break; + case SPACE_DMI_PROGBUF: + dmi_write(target, DMI_PROGBUF0 + scratch->debug_address, value); + dmi_write(target, DMI_PROGBUF1 + scratch->debug_address, value >> 32); + break; + case SPACE_DMI_RAM: + { + uint8_t buffer[8] = { + value, + value >> 8, + value >> 16, + value >> 24, + value >> 32, + value >> 40, + value >> 48, + value >> 56 + }; + if (write_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK) + return ERROR_FAIL; + } + break; + } + return ERROR_OK; +} + +/** Return register size in bits. */ +static unsigned register_size(struct target *target, unsigned number) +{ + /* If reg_cache hasn't been initialized yet, make a guess. We need this for + * when this function is called during examine(). */ + if (target->reg_cache) + return target->reg_cache->reg_list[number].size; + else + return riscv_xlen(target); +} + +/** + * Immediately write the new value to the requested register. This mechanism + * bypasses any caches. + */ +static int register_write_direct(struct target *target, unsigned number, + uint64_t value) +{ + RISCV013_INFO(info); + RISCV_INFO(r); + + LOG_DEBUG("[%d] reg[0x%x] <- 0x%" PRIx64, riscv_current_hartid(target), + number, value); + + int result = register_write_abstract(target, number, value, + register_size(target, number)); + if (result == ERROR_OK && target->reg_cache) { + struct reg *reg = &target->reg_cache->reg_list[number]; + buf_set_u64(reg->value, 0, reg->size, value); + reg->valid = true; + } + if (result == ERROR_OK || info->progbufsize + r->impebreak < 2 || + !riscv_is_halted(target)) + return result; + + struct riscv_program program; + riscv_program_init(&program, target); + + uint64_t s0; + if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + scratch_mem_t scratch; + bool use_scratch = false; + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && + riscv_supports_extension(target, riscv_current_hartid(target), 'D') && + riscv_xlen(target) < 64) { + /* There are no instructions to move all the bits from a register, so + * we need to use some scratch RAM. */ + use_scratch = true; + riscv_program_insert(&program, fld(number - GDB_REGNO_FPR0, S0, 0)); + + if (scratch_reserve(target, &scratch, &program, 8) != ERROR_OK) + return ERROR_FAIL; + + if (register_write_direct(target, GDB_REGNO_S0, scratch.hart_address) + != ERROR_OK) { + scratch_release(target, &scratch); + return ERROR_FAIL; + } + + if (scratch_write64(target, &scratch, value) != ERROR_OK) { + scratch_release(target, &scratch); + return ERROR_FAIL; + } + + } else { + if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK) + return ERROR_FAIL; + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + if (riscv_supports_extension(target, riscv_current_hartid(target), 'D')) + riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); + else + riscv_program_insert(&program, fmv_w_x(number - GDB_REGNO_FPR0, S0)); + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + riscv_program_csrw(&program, S0, number); + } else { + LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); + return ERROR_FAIL; + } + } + + int exec_out = riscv_program_exec(&program, target); + /* Don't message on error. Probably the register doesn't exist. */ + if (exec_out == ERROR_OK && target->reg_cache) { + struct reg *reg = &target->reg_cache->reg_list[number]; + buf_set_u64(reg->value, 0, reg->size, value); + reg->valid = true; + } + + if (use_scratch) + scratch_release(target, &scratch); + + /* Restore S0. */ + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) + return ERROR_FAIL; + + return exec_out; +} + +/** Return the cached value, or read from the target if necessary. */ +static int register_read(struct target *target, uint64_t *value, uint32_t number) +{ + if (number == GDB_REGNO_ZERO) { + *value = 0; + return ERROR_OK; + } + if (target->reg_cache && + (number <= GDB_REGNO_XPR31 || + (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31))) { + /* Only check the cache for registers that we know won't spontaneously + * change. */ + struct reg *reg = &target->reg_cache->reg_list[number]; + if (reg && reg->valid) { + *value = buf_get_u64(reg->value, 0, reg->size); + return ERROR_OK; + } + } + int result = register_read_direct(target, value, number); + if (result != ERROR_OK) + return ERROR_FAIL; + if (target->reg_cache) { + struct reg *reg = &target->reg_cache->reg_list[number]; + buf_set_u64(reg->value, 0, reg->size, *value); + reg->valid = true; + } + return ERROR_OK; +} + +/** Actually read registers from the target right now. */ +static int register_read_direct(struct target *target, uint64_t *value, uint32_t number) +{ + RISCV013_INFO(info); + RISCV_INFO(r); + + int result = register_read_abstract(target, value, number, + register_size(target, number)); + + if (result != ERROR_OK && + info->progbufsize + r->impebreak >= 2 && + number > GDB_REGNO_XPR31) { + struct riscv_program program; + riscv_program_init(&program, target); + + scratch_mem_t scratch; + bool use_scratch = false; + + uint64_t s0; + if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + /* Write program to move data into s0. */ + + uint64_t mstatus; + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + if (register_read(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) + return ERROR_FAIL; + if ((mstatus & MSTATUS_FS) == 0) + if (register_write_direct(target, GDB_REGNO_MSTATUS, + set_field(mstatus, MSTATUS_FS, 1)) != ERROR_OK) + return ERROR_FAIL; + + if (riscv_supports_extension(target, riscv_current_hartid(target), 'D') + && riscv_xlen(target) < 64) { + /* There are no instructions to move all the bits from a + * register, so we need to use some scratch RAM. */ + riscv_program_insert(&program, fsd(number - GDB_REGNO_FPR0, S0, + 0)); + + if (scratch_reserve(target, &scratch, &program, 8) != ERROR_OK) + return ERROR_FAIL; + use_scratch = true; + + if (register_write_direct(target, GDB_REGNO_S0, + scratch.hart_address) != ERROR_OK) { + scratch_release(target, &scratch); + return ERROR_FAIL; + } + } else if (riscv_supports_extension(target, + riscv_current_hartid(target), 'D')) { + riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); + } else { + riscv_program_insert(&program, fmv_x_w(S0, number - GDB_REGNO_FPR0)); + } + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + riscv_program_csrr(&program, S0, number); + } else { + LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); + return ERROR_FAIL; + } + + /* Execute program. */ + result = riscv_program_exec(&program, target); + /* Don't message on error. Probably the register doesn't exist. */ + + if (use_scratch) { + result = scratch_read64(target, &scratch, value); + scratch_release(target, &scratch); + if (result != ERROR_OK) + return result; + } else { + /* Read S0 */ + if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + } + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && + (mstatus & MSTATUS_FS) == 0) + if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus) != ERROR_OK) + return ERROR_FAIL; + + /* Restore S0. */ + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) + return ERROR_FAIL; + } + + if (result == ERROR_OK) { + LOG_DEBUG("[%d] reg[0x%x] = 0x%" PRIx64, riscv_current_hartid(target), + number, *value); + } + + return result; +} + +int wait_for_authbusy(struct target *target, uint32_t *dmstatus) +{ + time_t start = time(NULL); + while (1) { + uint32_t value; + if (dmstatus_read(target, &value, false) != ERROR_OK) + return ERROR_FAIL; + if (dmstatus) + *dmstatus = value; + if (!get_field(value, DMI_DMSTATUS_AUTHBUSY)) + break; + if (time(NULL) - start > riscv_command_timeout_sec) { + LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dmstatus=0x%x). " + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_command_timeout_sec, + value); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +/*** OpenOCD target functions. ***/ + +static void deinit_target(struct target *target) +{ + LOG_DEBUG("riscv_deinit_target()"); + riscv_info_t *info = (riscv_info_t *) target->arch_info; + free(info->version_specific); + info->version_specific = NULL; +} + +static int examine(struct target *target) +{ + /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ + + uint32_t dtmcontrol = dtmcontrol_scan(target, 0); + LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); + LOG_DEBUG(" dmireset=%d", get_field(dtmcontrol, DTM_DTMCS_DMIRESET)); + LOG_DEBUG(" idle=%d", get_field(dtmcontrol, DTM_DTMCS_IDLE)); + LOG_DEBUG(" dmistat=%d", get_field(dtmcontrol, DTM_DTMCS_DMISTAT)); + LOG_DEBUG(" abits=%d", get_field(dtmcontrol, DTM_DTMCS_ABITS)); + LOG_DEBUG(" version=%d", get_field(dtmcontrol, DTM_DTMCS_VERSION)); + if (dtmcontrol == 0) { + LOG_ERROR("dtmcontrol is 0. Check JTAG connectivity/board power."); + return ERROR_FAIL; + } + if (get_field(dtmcontrol, DTM_DTMCS_VERSION) != 1) { + LOG_ERROR("Unsupported DTM version %d. (dtmcontrol=0x%x)", + get_field(dtmcontrol, DTM_DTMCS_VERSION), dtmcontrol); + return ERROR_FAIL; + } + + riscv013_info_t *info = get_info(target); + info->abits = get_field(dtmcontrol, DTM_DTMCS_ABITS); + info->dtmcontrol_idle = get_field(dtmcontrol, DTM_DTMCS_IDLE); + + uint32_t dmstatus; + if (dmstatus_read(target, &dmstatus, false) != ERROR_OK) + return ERROR_FAIL; + LOG_DEBUG("dmstatus: 0x%08x", dmstatus); + if (get_field(dmstatus, DMI_DMSTATUS_VERSION) != 2) { + LOG_ERROR("OpenOCD only supports Debug Module version 2, not %d " + "(dmstatus=0x%x)", get_field(dmstatus, DMI_DMSTATUS_VERSION), dmstatus); + return ERROR_FAIL; + } + + /* Reset the Debug Module. */ + dm013_info_t *dm = get_dm(target); + if (!dm->was_reset) { + dmi_write(target, DMI_DMCONTROL, 0); + dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); + dm->was_reset = true; + } + + dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_HARTSELLO | + DMI_DMCONTROL_HARTSELHI | DMI_DMCONTROL_DMACTIVE); + uint32_t dmcontrol; + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; + + if (!get_field(dmcontrol, DMI_DMCONTROL_DMACTIVE)) { + LOG_ERROR("Debug Module did not become active. dmcontrol=0x%x", + dmcontrol); + return ERROR_FAIL; + } + + uint32_t hartsel = + (get_field(dmcontrol, DMI_DMCONTROL_HARTSELHI) << + DMI_DMCONTROL_HARTSELLO_LENGTH) | + get_field(dmcontrol, DMI_DMCONTROL_HARTSELLO); + info->hartsellen = 0; + while (hartsel & 1) { + info->hartsellen++; + hartsel >>= 1; + } + LOG_DEBUG("hartsellen=%d", info->hartsellen); + + uint32_t hartinfo; + if (dmi_read(target, &hartinfo, DMI_HARTINFO) != ERROR_OK) + return ERROR_FAIL; + + info->datasize = get_field(hartinfo, DMI_HARTINFO_DATASIZE); + info->dataaccess = get_field(hartinfo, DMI_HARTINFO_DATAACCESS); + info->dataaddr = get_field(hartinfo, DMI_HARTINFO_DATAADDR); + + if (!get_field(dmstatus, DMI_DMSTATUS_AUTHENTICATED)) { + LOG_ERROR("Debugger is not authenticated to target Debug Module. " + "(dmstatus=0x%x). Use `riscv authdata_read` and " + "`riscv authdata_write` commands to authenticate.", dmstatus); + /* If we return ERROR_FAIL here, then in a multicore setup the next + * core won't be examined, which means we won't set up the + * authentication commands for them, which means the config script + * needs to be a lot more complex. */ + return ERROR_OK; + } + + if (dmi_read(target, &info->sbcs, DMI_SBCS) != ERROR_OK) + return ERROR_FAIL; + + /* Check that abstract data registers are accessible. */ + uint32_t abstractcs; + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; + info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); + info->progbufsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); + + LOG_INFO("datacount=%d progbufsize=%d", info->datacount, info->progbufsize); + + RISCV_INFO(r); + r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK); + + if (info->progbufsize + r->impebreak < 2) { + LOG_WARNING("We won't be able to execute fence instructions on this " + "target. Memory may not always appear consistent. " + "(progbufsize=%d, impebreak=%d)", info->progbufsize, + r->impebreak); + } + + /* Before doing anything else we must first enumerate the harts. */ + + /* Don't call any riscv_* functions until after we've counted the number of + * cores and initialized registers. */ + for (int i = 0; i < MIN(RISCV_MAX_HARTS, 1 << info->hartsellen); ++i) { + if (!riscv_rtos_enabled(target) && i != target->coreid) + continue; + + r->current_hartid = i; + if (riscv013_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + + uint32_t s; + if (dmstatus_read(target, &s, true) != ERROR_OK) + return ERROR_FAIL; + if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) + break; + r->hart_count = i + 1; + + if (get_field(s, DMI_DMSTATUS_ANYHAVERESET)) + dmi_write(target, DMI_DMCONTROL, + set_hartsel(DMI_DMCONTROL_DMACTIVE | DMI_DMCONTROL_ACKHAVERESET, i)); + + if (!riscv_is_halted(target)) { + if (riscv013_halt_current_hart(target) != ERROR_OK) { + LOG_ERROR("Fatal: Hart %d failed to halt during examine()", i); + return ERROR_FAIL; + } + } + + /* Without knowing anything else we can at least mess with the + * program buffer. */ + r->debug_buffer_size[i] = info->progbufsize; + + int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64); + if (result == ERROR_OK) + r->xlen[i] = 64; + else + r->xlen[i] = 32; + + if (register_read(target, &r->misa[i], GDB_REGNO_MISA)) { + LOG_ERROR("Fatal: Failed to read MISA from hart %d.", i); + return ERROR_FAIL; + } + + /* Now init registers based on what we discovered. */ + if (riscv_init_registers(target) != ERROR_OK) + return ERROR_FAIL; + + /* Display this as early as possible to help people who are using + * really slow simulators. */ + LOG_DEBUG(" hart %d: XLEN=%d, misa=0x%" PRIx64, i, r->xlen[i], + r->misa[i]); + } + + LOG_DEBUG("Enumerated %d harts", r->hart_count); + + if (r->hart_count == 0) { + LOG_ERROR("No harts found!"); + return ERROR_FAIL; + } + + /* Resumes all the harts, so the debugger can later pause them. */ + /* TODO: Only do this if the harts were halted to start with. */ + riscv_resume_all_harts(target); + target->state = TARGET_RUNNING; + + target_set_examined(target); + + /* Some regression suites rely on seeing 'Examined RISC-V core' to know + * when they can connect with gdb/telnet. + * We will need to update those suites if we want to change that text. */ + LOG_INFO("Examined RISC-V core; found %d harts", + riscv_count_harts(target)); + for (int i = 0; i < riscv_count_harts(target); ++i) { + if (riscv_hart_enabled(target, i)) { + LOG_INFO(" hart %d: XLEN=%d, misa=0x%" PRIx64, i, r->xlen[i], + r->misa[i]); + } else { + LOG_INFO(" hart %d: currently disabled", i); + } + } + return ERROR_OK; +} + +int riscv013_authdata_read(struct target *target, uint32_t *value) +{ + if (wait_for_authbusy(target, NULL) != ERROR_OK) + return ERROR_FAIL; + + return dmi_read(target, value, DMI_AUTHDATA); +} + +int riscv013_authdata_write(struct target *target, uint32_t value) +{ + uint32_t before, after; + if (wait_for_authbusy(target, &before) != ERROR_OK) + return ERROR_FAIL; + + dmi_write(target, DMI_AUTHDATA, value); + + if (wait_for_authbusy(target, &after) != ERROR_OK) + return ERROR_FAIL; + + if (!get_field(before, DMI_DMSTATUS_AUTHENTICATED) && + get_field(after, DMI_DMSTATUS_AUTHENTICATED)) { + LOG_INFO("authdata_write resulted in successful authentication"); + int result = ERROR_OK; + dm013_info_t *dm = get_dm(target); + target_list_t *entry; + list_for_each_entry(entry, &dm->target_list, list) { + if (examine(entry->target) != ERROR_OK) + result = ERROR_FAIL; + } + return result; + } + + return ERROR_OK; +} + +static int init_target(struct command_context *cmd_ctx, + struct target *target) +{ + LOG_DEBUG("init"); + riscv_info_t *generic_info = (riscv_info_t *) target->arch_info; + + generic_info->get_register = &riscv013_get_register; + generic_info->set_register = &riscv013_set_register; + generic_info->select_current_hart = &riscv013_select_current_hart; + generic_info->is_halted = &riscv013_is_halted; + generic_info->halt_current_hart = &riscv013_halt_current_hart; + generic_info->resume_current_hart = &riscv013_resume_current_hart; + generic_info->step_current_hart = &riscv013_step_current_hart; + generic_info->on_halt = &riscv013_on_halt; + generic_info->on_resume = &riscv013_on_resume; + generic_info->on_step = &riscv013_on_step; + generic_info->halt_reason = &riscv013_halt_reason; + generic_info->read_debug_buffer = &riscv013_read_debug_buffer; + generic_info->write_debug_buffer = &riscv013_write_debug_buffer; + generic_info->execute_debug_buffer = &riscv013_execute_debug_buffer; + generic_info->fill_dmi_write_u64 = &riscv013_fill_dmi_write_u64; + generic_info->fill_dmi_read_u64 = &riscv013_fill_dmi_read_u64; + generic_info->fill_dmi_nop_u64 = &riscv013_fill_dmi_nop_u64; + generic_info->dmi_write_u64_bits = &riscv013_dmi_write_u64_bits; + generic_info->authdata_read = &riscv013_authdata_read; + generic_info->authdata_write = &riscv013_authdata_write; + generic_info->dmi_read = &dmi_read; + generic_info->dmi_write = &dmi_write; + generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); + if (!generic_info->version_specific) + return ERROR_FAIL; + riscv013_info_t *info = get_info(target); + + info->progbufsize = -1; + + info->dmi_busy_delay = 0; + info->bus_master_read_delay = 0; + info->bus_master_write_delay = 0; + info->ac_busy_delay = 0; + + /* Assume all these abstract commands are supported until we learn + * otherwise. + * TODO: The spec allows eg. one CSR to be able to be accessed abstractly + * while another one isn't. We don't track that this closely here, but in + * the future we probably should. */ + info->abstract_read_csr_supported = true; + info->abstract_write_csr_supported = true; + info->abstract_read_fpr_supported = true; + info->abstract_write_fpr_supported = true; + + return ERROR_OK; +} + +static int assert_reset(struct target *target) +{ + RISCV_INFO(r); + + select_dmi(target); + + uint32_t control_base = set_field(0, DMI_DMCONTROL_DMACTIVE, 1); + + if (target->rtos) { + /* There's only one target, and OpenOCD thinks each hart is a thread. + * We must reset them all. */ + + /* TODO: Try to use hasel in dmcontrol */ + + /* Set haltreq for each hart. */ + uint32_t control = control_base; + for (int i = 0; i < riscv_count_harts(target); ++i) { + if (!riscv_hart_enabled(target, i)) + continue; + + control = set_hartsel(control_base, i); + control = set_field(control, DMI_DMCONTROL_HALTREQ, + target->reset_halt ? 1 : 0); + dmi_write(target, DMI_DMCONTROL, control); + } + /* Assert ndmreset */ + control = set_field(control, DMI_DMCONTROL_NDMRESET, 1); + dmi_write(target, DMI_DMCONTROL, control); + + } else { + /* Reset just this hart. */ + uint32_t control = set_hartsel(control_base, r->current_hartid); + control = set_field(control, DMI_DMCONTROL_HALTREQ, + target->reset_halt ? 1 : 0); + control = set_field(control, DMI_DMCONTROL_NDMRESET, 1); + dmi_write(target, DMI_DMCONTROL, control); + } + + target->state = TARGET_RESET; + + return ERROR_OK; +} + +static int deassert_reset(struct target *target) +{ + RISCV_INFO(r); + RISCV013_INFO(info); + select_dmi(target); + + /* Clear the reset, but make sure haltreq is still set */ + uint32_t control = 0; + control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); + control = set_field(control, DMI_DMCONTROL_DMACTIVE, 1); + dmi_write(target, DMI_DMCONTROL, + set_hartsel(control, r->current_hartid)); + + uint32_t dmstatus; + int dmi_busy_delay = info->dmi_busy_delay; + time_t start = time(NULL); + + for (int i = 0; i < riscv_count_harts(target); ++i) { + int index = i; + if (target->rtos) { + if (!riscv_hart_enabled(target, index)) + continue; + dmi_write(target, DMI_DMCONTROL, + set_hartsel(control, index)); + } else { + index = r->current_hartid; + } + + char *operation; + uint32_t expected_field; + if (target->reset_halt) { + operation = "halt"; + expected_field = DMI_DMSTATUS_ALLHALTED; + } else { + operation = "run"; + expected_field = DMI_DMSTATUS_ALLRUNNING; + } + LOG_DEBUG("Waiting for hart %d to %s out of reset.", index, operation); + while (1) { + int result = dmstatus_read_timeout(target, &dmstatus, true, + riscv_reset_timeout_sec); + if (result == ERROR_TIMEOUT_REACHED) + LOG_ERROR("Hart %d didn't complete a DMI read coming out of " + "reset in %ds; Increase the timeout with riscv " + "set_reset_timeout_sec.", + index, riscv_reset_timeout_sec); + if (result != ERROR_OK) + return result; + if (get_field(dmstatus, expected_field)) + break; + if (time(NULL) - start > riscv_reset_timeout_sec) { + LOG_ERROR("Hart %d didn't %s coming out of reset in %ds; " + "dmstatus=0x%x; " + "Increase the timeout with riscv set_reset_timeout_sec.", + index, operation, riscv_reset_timeout_sec, dmstatus); + return ERROR_FAIL; + } + } + target->state = TARGET_HALTED; + + if (get_field(dmstatus, DMI_DMSTATUS_ALLHAVERESET)) { + /* Ack reset. */ + dmi_write(target, DMI_DMCONTROL, + set_hartsel(control, index) | + DMI_DMCONTROL_ACKHAVERESET); + } + + if (!target->rtos) + break; + } + info->dmi_busy_delay = dmi_busy_delay; + return ERROR_OK; +} + +/** + * @size in bytes + */ +static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) +{ + switch (size) { + case 8: + buffer[7] = value >> 56; + buffer[6] = value >> 48; + buffer[5] = value >> 40; + buffer[4] = value >> 32; + /* falls through */ + case 4: + buffer[3] = value >> 24; + buffer[2] = value >> 16; + /* falls through */ + case 2: + buffer[1] = value >> 8; + /* falls through */ + case 1: + buffer[0] = value; + break; + default: + assert(false); + } +} + +static int execute_fence(struct target *target) +{ + struct riscv_program program; + riscv_program_init(&program, target); + riscv_program_fence(&program); + int result = riscv_program_exec(&program, target); + if (result != ERROR_OK) + LOG_ERROR("Unable to execute fence"); + return result; +} + +static void log_memory_access(target_addr_t address, uint64_t value, + unsigned size_bytes, bool read) +{ + if (debug_level < LOG_LVL_DEBUG) + return; + + char fmt[80]; + sprintf(fmt, "M[0x%" TARGET_PRIxADDR "] %ss 0x%%0%d" PRIx64, + address, read ? "read" : "write", size_bytes * 2); + value &= (((uint64_t) 0x1) << (size_bytes * 8)) - 1; + LOG_DEBUG(fmt, value); +} + +/* Read the relevant sbdata regs depending on size, and put the results into + * buffer. */ +static int read_memory_bus_word(struct target *target, target_addr_t address, + uint32_t size, uint8_t *buffer) +{ + uint32_t value; + if (size > 12) { + if (dmi_read(target, &value, DMI_SBDATA3) != ERROR_OK) + return ERROR_FAIL; + write_to_buf(buffer + 12, value, 4); + log_memory_access(address + 12, value, 4, true); + } + if (size > 8) { + if (dmi_read(target, &value, DMI_SBDATA2) != ERROR_OK) + return ERROR_FAIL; + write_to_buf(buffer + 8, value, 4); + log_memory_access(address + 8, value, 4, true); + } + if (size > 4) { + if (dmi_read(target, &value, DMI_SBDATA1) != ERROR_OK) + return ERROR_FAIL; + write_to_buf(buffer + 4, value, 4); + log_memory_access(address + 4, value, 4, true); + } + if (dmi_read(target, &value, DMI_SBDATA0) != ERROR_OK) + return ERROR_FAIL; + write_to_buf(buffer, value, MIN(size, 4)); + log_memory_access(address, value, MIN(size, 4), true); + return ERROR_OK; +} + +static uint32_t sb_sbaccess(unsigned size_bytes) +{ + switch (size_bytes) { + case 1: + return set_field(0, DMI_SBCS_SBACCESS, 0); + case 2: + return set_field(0, DMI_SBCS_SBACCESS, 1); + case 4: + return set_field(0, DMI_SBCS_SBACCESS, 2); + case 8: + return set_field(0, DMI_SBCS_SBACCESS, 3); + case 16: + return set_field(0, DMI_SBCS_SBACCESS, 4); + } + assert(0); + return 0; /* Make mingw happy. */ +} + +static target_addr_t sb_read_address(struct target *target) +{ + RISCV013_INFO(info); + unsigned sbasize = get_field(info->sbcs, DMI_SBCS_SBASIZE); + target_addr_t address = 0; + uint32_t v; + if (sbasize > 32) { +#if BUILD_TARGET64 + dmi_read(target, &v, DMI_SBADDRESS1); + address |= v; + address <<= 32; +#endif + } + dmi_read(target, &v, DMI_SBADDRESS0); + address |= v; + return address; +} + +static int sb_write_address(struct target *target, target_addr_t address) +{ + RISCV013_INFO(info); + unsigned sbasize = get_field(info->sbcs, DMI_SBCS_SBASIZE); + /* There currently is no support for >64-bit addresses in OpenOCD. */ + if (sbasize > 96) + dmi_write(target, DMI_SBADDRESS3, 0); + if (sbasize > 64) + dmi_write(target, DMI_SBADDRESS2, 0); + if (sbasize > 32) +#if BUILD_TARGET64 + dmi_write(target, DMI_SBADDRESS1, address >> 32); +#else + dmi_write(target, DMI_SBADDRESS1, 0); +#endif + return dmi_write(target, DMI_SBADDRESS0, address); +} + +static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs) +{ + time_t start = time(NULL); + while (1) { + if (dmi_read(target, sbcs, DMI_SBCS) != ERROR_OK) + return ERROR_FAIL; + if (!get_field(*sbcs, DMI_SBCS_SBBUSY)) + return ERROR_OK; + if (time(NULL) - start > riscv_command_timeout_sec) { + LOG_ERROR("Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). " + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_command_timeout_sec, *sbcs); + return ERROR_FAIL; + } + } +} + +static int read_memory_bus_v0(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" + TARGET_PRIxADDR, size, count, address); + uint8_t *t_buffer = buffer; + riscv_addr_t cur_addr = address; + riscv_addr_t fin_addr = address + (count * size); + uint32_t access = 0; + + const int DMI_SBCS_SBSINGLEREAD_OFFSET = 20; + const uint32_t DMI_SBCS_SBSINGLEREAD = (0x1U << DMI_SBCS_SBSINGLEREAD_OFFSET); + + const int DMI_SBCS_SBAUTOREAD_OFFSET = 15; + const uint32_t DMI_SBCS_SBAUTOREAD = (0x1U << DMI_SBCS_SBAUTOREAD_OFFSET); + + /* ww favorise one off reading if there is an issue */ + if (count == 1) { + for (uint32_t i = 0; i < count; i++) { + if (dmi_read(target, &access, DMI_SBCS) != ERROR_OK) + return ERROR_FAIL; + dmi_write(target, DMI_SBADDRESS0, cur_addr); + /* size/2 matching the bit access of the spec 0.13 */ + access = set_field(access, DMI_SBCS_SBACCESS, size/2); + access = set_field(access, DMI_SBCS_SBSINGLEREAD, 1); + LOG_DEBUG("\r\nread_memory: sab: access: 0x%08x", access); + dmi_write(target, DMI_SBCS, access); + /* 3) read */ + uint32_t value; + if (dmi_read(target, &value, DMI_SBDATA0) != ERROR_OK) + return ERROR_FAIL; + LOG_DEBUG("\r\nread_memory: sab: value: 0x%08x", value); + write_to_buf(t_buffer, value, size); + t_buffer += size; + cur_addr += size; + } + return ERROR_OK; + } + + /* has to be the same size if we want to read a block */ + LOG_DEBUG("reading block until final address 0x%" PRIx64, fin_addr); + if (dmi_read(target, &access, DMI_SBCS) != ERROR_OK) + return ERROR_FAIL; + /* set current address */ + dmi_write(target, DMI_SBADDRESS0, cur_addr); + /* 2) write sbaccess=2, sbsingleread,sbautoread,sbautoincrement + * size/2 matching the bit access of the spec 0.13 */ + access = set_field(access, DMI_SBCS_SBACCESS, size/2); + access = set_field(access, DMI_SBCS_SBAUTOREAD, 1); + access = set_field(access, DMI_SBCS_SBSINGLEREAD, 1); + access = set_field(access, DMI_SBCS_SBAUTOINCREMENT, 1); + LOG_DEBUG("\r\naccess: 0x%08x", access); + dmi_write(target, DMI_SBCS, access); + + while (cur_addr < fin_addr) { + LOG_DEBUG("\r\nsab:autoincrement: \r\n size: %d\tcount:%d\taddress: 0x%08" + PRIx64, size, count, cur_addr); + /* read */ + uint32_t value; + if (dmi_read(target, &value, DMI_SBDATA0) != ERROR_OK) + return ERROR_FAIL; + write_to_buf(t_buffer, value, size); + cur_addr += size; + t_buffer += size; + + /* if we are reaching last address, we must clear autoread */ + if (cur_addr == fin_addr && count != 1) { + dmi_write(target, DMI_SBCS, 0); + if (dmi_read(target, &value, DMI_SBDATA0) != ERROR_OK) + return ERROR_FAIL; + write_to_buf(t_buffer, value, size); + } + } + + return ERROR_OK; +} + +/** + * Read the requested memory using the system bus interface. + */ +static int read_memory_bus_v1(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + RISCV013_INFO(info); + target_addr_t next_address = address; + target_addr_t end_address = address + count * size; + + while (next_address < end_address) { + uint32_t sbcs = set_field(0, DMI_SBCS_SBREADONADDR, 1); + sbcs |= sb_sbaccess(size); + sbcs = set_field(sbcs, DMI_SBCS_SBAUTOINCREMENT, 1); + sbcs = set_field(sbcs, DMI_SBCS_SBREADONDATA, count > 1); + dmi_write(target, DMI_SBCS, sbcs); + + /* This address write will trigger the first read. */ + sb_write_address(target, next_address); + + if (info->bus_master_read_delay) { + jtag_add_runtest(info->bus_master_read_delay, TAP_IDLE); + if (jtag_execute_queue() != ERROR_OK) { + LOG_ERROR("Failed to scan idle sequence"); + return ERROR_FAIL; + } + } + + for (uint32_t i = (next_address - address) / size; i < count - 1; i++) { + read_memory_bus_word(target, address + i * size, size, + buffer + i * size); + } + + sbcs = set_field(sbcs, DMI_SBCS_SBREADONDATA, 0); + dmi_write(target, DMI_SBCS, sbcs); + + read_memory_bus_word(target, address + (count - 1) * size, size, + buffer + (count - 1) * size); + + if (read_sbcs_nonbusy(target, &sbcs) != ERROR_OK) + return ERROR_FAIL; + + if (get_field(sbcs, DMI_SBCS_SBBUSYERROR)) { + /* We read while the target was busy. Slow down and try again. */ + dmi_write(target, DMI_SBCS, DMI_SBCS_SBBUSYERROR); + next_address = sb_read_address(target); + info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1; + continue; + } + + unsigned error = get_field(sbcs, DMI_SBCS_SBERROR); + if (error == 0) { + next_address = end_address; + } else { + /* Some error indicating the bus access failed, but not because of + * something we did wrong. */ + dmi_write(target, DMI_SBCS, DMI_SBCS_SBERROR); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +/** + * Read the requested memory, taking care to execute every read exactly once, + * even if cmderr=busy is encountered. + */ +static int read_memory_progbuf(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + RISCV013_INFO(info); + + int result = ERROR_OK; + + LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, + size, address); + + select_dmi(target); + + /* s0 holds the next address to write to + * s1 holds the next data value to write + */ + uint64_t s0, s1; + if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + + if (execute_fence(target) != ERROR_OK) + return ERROR_FAIL; + + /* Write the program (load, increment) */ + struct riscv_program program; + riscv_program_init(&program, target); + switch (size) { + case 1: + riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + case 2: + riscv_program_lhr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + case 4: + riscv_program_lwr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + default: + LOG_ERROR("Unsupported size: %d", size); + return ERROR_FAIL; + } + riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); + + if (riscv_program_ebreak(&program) != ERROR_OK) + return ERROR_FAIL; + riscv_program_write(&program); + + /* Write address to S0, and execute buffer. */ + result = register_write_direct(target, GDB_REGNO_S0, address); + if (result != ERROR_OK) + goto error; + uint32_t command = access_register_command(GDB_REGNO_S1, riscv_xlen(target), + AC_ACCESS_REGISTER_TRANSFER | + AC_ACCESS_REGISTER_POSTEXEC); + result = execute_abstract_command(target, command); + if (result != ERROR_OK) + goto error; + + /* First read has just triggered. Result is in s1. */ + + dmi_write(target, DMI_ABSTRACTAUTO, + 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); + + /* read_addr is the next address that the hart will read from, which is the + * value in s0. */ + riscv_addr_t read_addr = address + size; + /* The next address that we need to receive data for. */ + riscv_addr_t receive_addr = address; + riscv_addr_t fin_addr = address + (count * size); + unsigned skip = 1; + while (read_addr < fin_addr) { + LOG_DEBUG("read_addr=0x%" PRIx64 ", receive_addr=0x%" PRIx64 + ", fin_addr=0x%" PRIx64, read_addr, receive_addr, fin_addr); + /* The pipeline looks like this: + * memory -> s1 -> dm_data0 -> debugger + * It advances every time the debugger reads dmdata0. + * So at any time the debugger has just read mem[s0 - 3*size], + * dm_data0 contains mem[s0 - 2*size] + * s1 contains mem[s0-size] */ + + LOG_DEBUG("creating burst to read from 0x%" PRIx64 + " up to 0x%" PRIx64, read_addr, fin_addr); + assert(read_addr >= address && read_addr < fin_addr); + struct riscv_batch *batch = riscv_batch_alloc(target, 32, + info->dmi_busy_delay + info->ac_busy_delay); + + size_t reads = 0; + for (riscv_addr_t addr = read_addr; addr < fin_addr; addr += size) { + riscv_batch_add_dmi_read(batch, DMI_DATA0); + + reads++; + if (riscv_batch_full(batch)) + break; + } + + riscv_batch_run(batch); + + /* Wait for the target to finish performing the last abstract command, + * and update our copy of cmderr. */ + uint32_t abstractcs; + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; + while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; + info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); + + unsigned cmderr = info->cmderr; + riscv_addr_t next_read_addr; + uint32_t dmi_data0 = -1; + switch (info->cmderr) { + case CMDERR_NONE: + LOG_DEBUG("successful (partial?) memory read"); + next_read_addr = read_addr + reads * size; + break; + case CMDERR_BUSY: + LOG_DEBUG("memory read resulted in busy response"); + + /* + * If you want to exercise this code path, apply the following patch to spike: +--- a/riscv/debug_module.cc ++++ b/riscv/debug_module.cc +@@ -1,3 +1,5 @@ ++#include ++ + #include + + #include "debug_module.h" +@@ -398,6 +400,15 @@ bool debug_module_t::perform_abstract_command() + // Since the next instruction is what we will use, just use nother NOP + // to get there. + write32(debug_abstract, 1, addi(ZERO, ZERO, 0)); ++ ++ if (abstractauto.autoexecdata && ++ program_buffer[0] == 0x83 && ++ program_buffer[1] == 0x24 && ++ program_buffer[2] == 0x04 && ++ program_buffer[3] == 0 && ++ rand() < RAND_MAX / 10) { ++ usleep(1000000); ++ } + } else { + write32(debug_abstract, 1, ebreak()); + } + */ + increase_ac_busy_delay(target); + riscv013_clear_abstract_error(target); + + dmi_write(target, DMI_ABSTRACTAUTO, 0); + + /* This is definitely a good version of the value that we + * attempted to read when we discovered that the target was + * busy. */ + if (dmi_read(target, &dmi_data0, DMI_DATA0) != ERROR_OK) { + riscv_batch_free(batch); + goto error; + } + + /* Clobbers DMI_DATA0. */ + result = register_read_direct(target, &next_read_addr, + GDB_REGNO_S0); + if (result != ERROR_OK) { + riscv_batch_free(batch); + goto error; + } + /* Restore the command, and execute it. + * Now DMI_DATA0 contains the next value just as it would if no + * error had occurred. */ + dmi_write(target, DMI_COMMAND, command); + + dmi_write(target, DMI_ABSTRACTAUTO, + 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); + break; + default: + LOG_ERROR("error when reading memory, abstractcs=0x%08lx", (long)abstractcs); + riscv013_clear_abstract_error(target); + riscv_batch_free(batch); + result = ERROR_FAIL; + goto error; + } + + /* Now read whatever we got out of the batch. */ + for (size_t i = 0; i < reads; i++) { + if (read_addr >= next_read_addr) + break; + + read_addr += size; + + if (skip > 0) { + skip--; + continue; + } + + riscv_addr_t offset = receive_addr - address; + uint64_t dmi_out = riscv_batch_get_dmi_read(batch, i); + uint32_t value = get_field(dmi_out, DTM_DMI_DATA); + write_to_buf(buffer + offset, value, size); + log_memory_access(receive_addr, value, size, true); + + receive_addr += size; + } + riscv_batch_free(batch); + + if (cmderr == CMDERR_BUSY) { + riscv_addr_t offset = receive_addr - address; + write_to_buf(buffer + offset, dmi_data0, size); + log_memory_access(receive_addr, dmi_data0, size, true); + read_addr += size; + receive_addr += size; + } + } + + dmi_write(target, DMI_ABSTRACTAUTO, 0); + + if (count > 1) { + /* Read the penultimate word. */ + uint32_t value; + if (dmi_read(target, &value, DMI_DATA0) != ERROR_OK) + goto error; + write_to_buf(buffer + receive_addr - address, value, size); + log_memory_access(receive_addr, value, size, true); + receive_addr += size; + } + + /* Read the last word. */ + uint64_t value; + result = register_read_direct(target, &value, GDB_REGNO_S1); + if (result != ERROR_OK) + goto error; + write_to_buf(buffer + receive_addr - address, value, size); + log_memory_access(receive_addr, value, size, true); + + riscv_set_register(target, GDB_REGNO_S0, s0); + riscv_set_register(target, GDB_REGNO_S1, s1); + return ERROR_OK; + +error: + dmi_write(target, DMI_ABSTRACTAUTO, 0); + + riscv_set_register(target, GDB_REGNO_S0, s0); + riscv_set_register(target, GDB_REGNO_S1, s1); + return result; +} + +static int read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + RISCV013_INFO(info); + if (info->progbufsize >= 2 && !riscv_prefer_sba) + return read_memory_progbuf(target, address, size, count, buffer); + + if ((get_field(info->sbcs, DMI_SBCS_SBACCESS8) && size == 1) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS16) && size == 2) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS32) && size == 4) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS64) && size == 8) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16)) { + if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 0) + return read_memory_bus_v0(target, address, size, count, buffer); + else if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 1) + return read_memory_bus_v1(target, address, size, count, buffer); + } + + if (info->progbufsize >= 2) + return read_memory_progbuf(target, address, size, count, buffer); + + LOG_ERROR("Don't know how to read memory on this target."); + return ERROR_FAIL; +} + +static int write_memory_bus_v0(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + /*1) write sbaddress: for singlewrite and autoincrement, we need to write the address once*/ + LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" + TARGET_PRIxADDR, size, count, address); + dmi_write(target, DMI_SBADDRESS0, address); + int64_t value = 0; + int64_t access = 0; + riscv_addr_t offset = 0; + riscv_addr_t t_addr = 0; + const uint8_t *t_buffer = buffer + offset; + + /* B.8 Writing Memory, single write check if we write in one go */ + if (count == 1) { /* count is in bytes here */ + /* check the size */ + switch (size) { + case 1: + value = t_buffer[0]; + break; + case 2: + value = t_buffer[0] + | ((uint32_t) t_buffer[1] << 8); + break; + case 4: + value = t_buffer[0] + | ((uint32_t) t_buffer[1] << 8) + | ((uint32_t) t_buffer[2] << 16) + | ((uint32_t) t_buffer[3] << 24); + break; + default: + LOG_ERROR("unsupported access size: %d", size); + return ERROR_FAIL; + } + + access = 0; + access = set_field(access, DMI_SBCS_SBACCESS, size/2); + dmi_write(target, DMI_SBCS, access); + LOG_DEBUG("\r\naccess: 0x%08" PRIx64, access); + LOG_DEBUG("\r\nwrite_memory:SAB: ONE OFF: value 0x%08" PRIx64, value); + dmi_write(target, DMI_SBDATA0, value); + return ERROR_OK; + } + + /*B.8 Writing Memory, using autoincrement*/ + + access = 0; + access = set_field(access, DMI_SBCS_SBACCESS, size/2); + access = set_field(access, DMI_SBCS_SBAUTOINCREMENT, 1); + LOG_DEBUG("\r\naccess: 0x%08" PRIx64, access); + dmi_write(target, DMI_SBCS, access); + + /*2)set the value according to the size required and write*/ + for (riscv_addr_t i = 0; i < count; ++i) { + offset = size*i; + /* for monitoring only */ + t_addr = address + offset; + t_buffer = buffer + offset; + + switch (size) { + case 1: + value = t_buffer[0]; + break; + case 2: + value = t_buffer[0] + | ((uint32_t) t_buffer[1] << 8); + break; + case 4: + value = t_buffer[0] + | ((uint32_t) t_buffer[1] << 8) + | ((uint32_t) t_buffer[2] << 16) + | ((uint32_t) t_buffer[3] << 24); + break; + default: + LOG_ERROR("unsupported access size: %d", size); + return ERROR_FAIL; + } + LOG_DEBUG("SAB:autoincrement: expected address: 0x%08x value: 0x%08x" + PRIx64, (uint32_t)t_addr, (uint32_t)value); + dmi_write(target, DMI_SBDATA0, value); + } + /*reset the autoincrement when finished (something weird is happening if this is not done at the end*/ + access = set_field(access, DMI_SBCS_SBAUTOINCREMENT, 0); + dmi_write(target, DMI_SBCS, access); + + return ERROR_OK; +} + +static int write_memory_bus_v1(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + RISCV013_INFO(info); + uint32_t sbcs = sb_sbaccess(size); + sbcs = set_field(sbcs, DMI_SBCS_SBAUTOINCREMENT, 1); + dmi_write(target, DMI_SBCS, sbcs); + + target_addr_t next_address = address; + target_addr_t end_address = address + count * size; + + sb_write_address(target, next_address); + while (next_address < end_address) { + for (uint32_t i = (next_address - address) / size; i < count; i++) { + const uint8_t *p = buffer + i * size; + if (size > 12) + dmi_write(target, DMI_SBDATA3, + ((uint32_t) p[12]) | + (((uint32_t) p[13]) << 8) | + (((uint32_t) p[14]) << 16) | + (((uint32_t) p[15]) << 24)); + if (size > 8) + dmi_write(target, DMI_SBDATA2, + ((uint32_t) p[8]) | + (((uint32_t) p[9]) << 8) | + (((uint32_t) p[10]) << 16) | + (((uint32_t) p[11]) << 24)); + if (size > 4) + dmi_write(target, DMI_SBDATA1, + ((uint32_t) p[4]) | + (((uint32_t) p[5]) << 8) | + (((uint32_t) p[6]) << 16) | + (((uint32_t) p[7]) << 24)); + uint32_t value = p[0]; + if (size > 2) { + value |= ((uint32_t) p[2]) << 16; + value |= ((uint32_t) p[3]) << 24; + } + if (size > 1) + value |= ((uint32_t) p[1]) << 8; + dmi_write(target, DMI_SBDATA0, value); + + log_memory_access(address + i * size, value, size, false); + + if (info->bus_master_write_delay) { + jtag_add_runtest(info->bus_master_write_delay, TAP_IDLE); + if (jtag_execute_queue() != ERROR_OK) { + LOG_ERROR("Failed to scan idle sequence"); + return ERROR_FAIL; + } + } + } + + if (read_sbcs_nonbusy(target, &sbcs) != ERROR_OK) + return ERROR_FAIL; + + if (get_field(sbcs, DMI_SBCS_SBBUSYERROR)) { + /* We wrote while the target was busy. Slow down and try again. */ + dmi_write(target, DMI_SBCS, DMI_SBCS_SBBUSYERROR); + next_address = sb_read_address(target); + info->bus_master_write_delay += info->bus_master_write_delay / 10 + 1; + continue; + } + + unsigned error = get_field(sbcs, DMI_SBCS_SBERROR); + if (error == 0) { + next_address = end_address; + } else { + /* Some error indicating the bus access failed, but not because of + * something we did wrong. */ + dmi_write(target, DMI_SBCS, DMI_SBCS_SBERROR); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +static int write_memory_progbuf(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + RISCV013_INFO(info); + + LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address); + + select_dmi(target); + + /* s0 holds the next address to write to + * s1 holds the next data value to write + */ + + int result = ERROR_OK; + uint64_t s0, s1; + if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + + /* Write the program (store, increment) */ + struct riscv_program program; + riscv_program_init(&program, target); + + switch (size) { + case 1: + riscv_program_sbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + case 2: + riscv_program_shr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + case 4: + riscv_program_swr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + default: + LOG_ERROR("Unsupported size: %d", size); + result = ERROR_FAIL; + goto error; + } + + riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); + + result = riscv_program_ebreak(&program); + if (result != ERROR_OK) + goto error; + riscv_program_write(&program); + + riscv_addr_t cur_addr = address; + riscv_addr_t fin_addr = address + (count * size); + bool setup_needed = true; + LOG_DEBUG("writing until final address 0x%016" PRIx64, fin_addr); + while (cur_addr < fin_addr) { + LOG_DEBUG("transferring burst starting at address 0x%016" PRIx64, + cur_addr); + + struct riscv_batch *batch = riscv_batch_alloc( + target, + 32, + info->dmi_busy_delay + info->ac_busy_delay); + + /* To write another word, we put it in S1 and execute the program. */ + unsigned start = (cur_addr - address) / size; + for (unsigned i = start; i < count; ++i) { + unsigned offset = size*i; + const uint8_t *t_buffer = buffer + offset; + + uint32_t value; + switch (size) { + case 1: + value = t_buffer[0]; + break; + case 2: + value = t_buffer[0] + | ((uint32_t) t_buffer[1] << 8); + break; + case 4: + value = t_buffer[0] + | ((uint32_t) t_buffer[1] << 8) + | ((uint32_t) t_buffer[2] << 16) + | ((uint32_t) t_buffer[3] << 24); + break; + default: + LOG_ERROR("unsupported access size: %d", size); + riscv_batch_free(batch); + result = ERROR_FAIL; + goto error; + } + + log_memory_access(address + offset, value, size, false); + cur_addr += size; + + if (setup_needed) { + result = register_write_direct(target, GDB_REGNO_S0, + address + offset); + if (result != ERROR_OK) { + riscv_batch_free(batch); + goto error; + } + + /* Write value. */ + dmi_write(target, DMI_DATA0, value); + + /* Write and execute command that moves value into S1 and + * executes program buffer. */ + uint32_t command = access_register_command(GDB_REGNO_S1, 32, + AC_ACCESS_REGISTER_POSTEXEC | + AC_ACCESS_REGISTER_TRANSFER | + AC_ACCESS_REGISTER_WRITE); + result = execute_abstract_command(target, command); + if (result != ERROR_OK) { + riscv_batch_free(batch); + goto error; + } + + /* Turn on autoexec */ + dmi_write(target, DMI_ABSTRACTAUTO, + 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); + + setup_needed = false; + } else { + riscv_batch_add_dmi_write(batch, DMI_DATA0, value); + if (riscv_batch_full(batch)) + break; + } + } + + result = riscv_batch_run(batch); + riscv_batch_free(batch); + if (result != ERROR_OK) + goto error; + + /* Note that if the scan resulted in a Busy DMI response, it + * is this read to abstractcs that will cause the dmi_busy_delay + * to be incremented if necessary. */ + + uint32_t abstractcs; + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + goto error; + while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; + info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); + switch (info->cmderr) { + case CMDERR_NONE: + LOG_DEBUG("successful (partial?) memory write"); + break; + case CMDERR_BUSY: + LOG_DEBUG("memory write resulted in busy response"); + riscv013_clear_abstract_error(target); + increase_ac_busy_delay(target); + + dmi_write(target, DMI_ABSTRACTAUTO, 0); + result = register_read_direct(target, &cur_addr, GDB_REGNO_S0); + if (result != ERROR_OK) + goto error; + setup_needed = true; + break; + + default: + LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs); + riscv013_clear_abstract_error(target); + result = ERROR_FAIL; + goto error; + } + } + +error: + dmi_write(target, DMI_ABSTRACTAUTO, 0); + + if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK) + return ERROR_FAIL; + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) + return ERROR_FAIL; + + if (execute_fence(target) != ERROR_OK) + return ERROR_FAIL; + + return result; +} + +static int write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + RISCV013_INFO(info); + if (info->progbufsize >= 2 && !riscv_prefer_sba) + return write_memory_progbuf(target, address, size, count, buffer); + + if ((get_field(info->sbcs, DMI_SBCS_SBACCESS8) && size == 1) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS16) && size == 2) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS32) && size == 4) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS64) && size == 8) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16)) { + if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 0) + return write_memory_bus_v0(target, address, size, count, buffer); + else if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 1) + return write_memory_bus_v1(target, address, size, count, buffer); + } + + if (info->progbufsize >= 2) + return write_memory_progbuf(target, address, size, count, buffer); + + LOG_ERROR("Don't know how to write memory on this target."); + return ERROR_FAIL; +} + +static int arch_state(struct target *target) +{ + return ERROR_OK; +} + +struct target_type riscv013_target = { + .name = "riscv", + + .init_target = init_target, + .deinit_target = deinit_target, + .examine = examine, + + .poll = &riscv_openocd_poll, + .halt = &riscv_openocd_halt, + .resume = &riscv_openocd_resume, + .step = &riscv_openocd_step, + + .assert_reset = assert_reset, + .deassert_reset = deassert_reset, + + .read_memory = read_memory, + .write_memory = write_memory, + + .arch_state = arch_state, +}; + +/*** 0.13-specific implementations of various RISC-V helper functions. ***/ +static int riscv013_get_register(struct target *target, + riscv_reg_t *value, int hid, int rid) +{ + LOG_DEBUG("reading register %s on hart %d", gdb_regno_name(rid), hid); + + riscv_set_current_hartid(target, hid); + + int result = ERROR_OK; + if (rid == GDB_REGNO_PC) { + result = register_read(target, value, GDB_REGNO_DPC); + LOG_DEBUG("read PC from DPC: 0x%016" PRIx64, *value); + } else if (rid == GDB_REGNO_PRIV) { + uint64_t dcsr; + result = register_read(target, &dcsr, GDB_REGNO_DCSR); + *value = get_field(dcsr, CSR_DCSR_PRV); + } else { + result = register_read(target, value, rid); + if (result != ERROR_OK) + *value = -1; + } + + return result; +} + +static int riscv013_set_register(struct target *target, int hid, int rid, uint64_t value) +{ + LOG_DEBUG("writing 0x%" PRIx64 " to register %s on hart %d", value, + gdb_regno_name(rid), hid); + + riscv_set_current_hartid(target, hid); + + if (rid <= GDB_REGNO_XPR31) { + return register_write_direct(target, rid, value); + } else if (rid == GDB_REGNO_PC) { + LOG_DEBUG("writing PC to DPC: 0x%016" PRIx64, value); + register_write_direct(target, GDB_REGNO_DPC, value); + uint64_t actual_value; + register_read_direct(target, &actual_value, GDB_REGNO_DPC); + LOG_DEBUG(" actual DPC written: 0x%016" PRIx64, actual_value); + if (value != actual_value) { + LOG_ERROR("Written PC (0x%" PRIx64 ") does not match read back " + "value (0x%" PRIx64 ")", value, actual_value); + return ERROR_FAIL; + } + } else if (rid == GDB_REGNO_PRIV) { + uint64_t dcsr; + register_read(target, &dcsr, GDB_REGNO_DCSR); + dcsr = set_field(dcsr, CSR_DCSR_PRV, value); + return register_write_direct(target, GDB_REGNO_DCSR, dcsr); + } else { + return register_write_direct(target, rid, value); + } + + return ERROR_OK; +} + +static int riscv013_select_current_hart(struct target *target) +{ + RISCV_INFO(r); + + dm013_info_t *dm = get_dm(target); + if (r->current_hartid == dm->current_hartid) + return ERROR_OK; + + uint32_t dmcontrol; + /* TODO: can't we just "dmcontrol = DMI_DMACTIVE"? */ + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; + dmcontrol = set_hartsel(dmcontrol, r->current_hartid); + int result = dmi_write(target, DMI_DMCONTROL, dmcontrol); + dm->current_hartid = r->current_hartid; + return result; +} + +static int riscv013_halt_current_hart(struct target *target) +{ + RISCV_INFO(r); + LOG_DEBUG("halting hart %d", r->current_hartid); + if (riscv_is_halted(target)) + LOG_ERROR("Hart %d is already halted!", r->current_hartid); + + /* Issue the halt command, and then wait for the current hart to halt. */ + uint32_t dmcontrol; + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; + dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HALTREQ, 1); + dmi_write(target, DMI_DMCONTROL, dmcontrol); + for (size_t i = 0; i < 256; ++i) + if (riscv_is_halted(target)) + break; + + if (!riscv_is_halted(target)) { + uint32_t dmstatus; + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return ERROR_FAIL; + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; + + LOG_ERROR("unable to halt hart %d", r->current_hartid); + LOG_ERROR(" dmcontrol=0x%08x", dmcontrol); + LOG_ERROR(" dmstatus =0x%08x", dmstatus); + return ERROR_FAIL; + } + + dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HALTREQ, 0); + dmi_write(target, DMI_DMCONTROL, dmcontrol); + + return ERROR_OK; +} + +static int riscv013_resume_current_hart(struct target *target) +{ + return riscv013_step_or_resume_current_hart(target, false); +} + +static int riscv013_step_current_hart(struct target *target) +{ + return riscv013_step_or_resume_current_hart(target, true); +} + +static int riscv013_on_resume(struct target *target) +{ + return riscv013_on_step_or_resume(target, false); +} + +static int riscv013_on_step(struct target *target) +{ + return riscv013_on_step_or_resume(target, true); +} + +static int riscv013_on_halt(struct target *target) +{ + return ERROR_OK; +} + +static bool riscv013_is_halted(struct target *target) +{ + uint32_t dmstatus; + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return false; + if (get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL)) + LOG_ERROR("Hart %d is unavailable.", riscv_current_hartid(target)); + if (get_field(dmstatus, DMI_DMSTATUS_ANYNONEXISTENT)) + LOG_ERROR("Hart %d doesn't exist.", riscv_current_hartid(target)); + if (get_field(dmstatus, DMI_DMSTATUS_ANYHAVERESET)) { + int hartid = riscv_current_hartid(target); + LOG_INFO("Hart %d unexpectedly reset!", hartid); + /* TODO: Can we make this more obvious to eg. a gdb user? */ + uint32_t dmcontrol = DMI_DMCONTROL_DMACTIVE | + DMI_DMCONTROL_ACKHAVERESET; + dmcontrol = set_hartsel(dmcontrol, hartid); + /* If we had been halted when we reset, request another halt. If we + * ended up running out of reset, then the user will (hopefully) get a + * message that a reset happened, that the target is running, and then + * that it is halted again once the request goes through. + */ + if (target->state == TARGET_HALTED) + dmcontrol |= DMI_DMCONTROL_HALTREQ; + dmi_write(target, DMI_DMCONTROL, dmcontrol); + } + return get_field(dmstatus, DMI_DMSTATUS_ALLHALTED); +} + +static enum riscv_halt_reason riscv013_halt_reason(struct target *target) +{ + riscv_reg_t dcsr; + int result = register_read(target, &dcsr, GDB_REGNO_DCSR); + if (result != ERROR_OK) + return RISCV_HALT_UNKNOWN; + + switch (get_field(dcsr, CSR_DCSR_CAUSE)) { + case CSR_DCSR_CAUSE_SWBP: + return RISCV_HALT_BREAKPOINT; + case CSR_DCSR_CAUSE_TRIGGER: + /* We could get here before triggers are enumerated if a trigger was + * already set when we connected. Force enumeration now, which has the + * side effect of clearing any triggers we did not set. */ + riscv_enumerate_triggers(target); + return RISCV_HALT_TRIGGER; + case CSR_DCSR_CAUSE_STEP: + return RISCV_HALT_SINGLESTEP; + case CSR_DCSR_CAUSE_DEBUGINT: + case CSR_DCSR_CAUSE_HALT: + return RISCV_HALT_INTERRUPT; + } + + LOG_ERROR("Unknown DCSR cause field: %x", (int)get_field(dcsr, CSR_DCSR_CAUSE)); + LOG_ERROR(" dcsr=0x%016lx", (long)dcsr); + return RISCV_HALT_UNKNOWN; +} + +int riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) +{ + return dmi_write(target, DMI_PROGBUF0 + index, data); +} + +riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) +{ + uint32_t value; + dmi_read(target, &value, DMI_PROGBUF0 + index); + return value; +} + +int riscv013_execute_debug_buffer(struct target *target) +{ + uint32_t run_program = 0; + run_program = set_field(run_program, AC_ACCESS_REGISTER_SIZE, 2); + run_program = set_field(run_program, AC_ACCESS_REGISTER_POSTEXEC, 1); + run_program = set_field(run_program, AC_ACCESS_REGISTER_TRANSFER, 0); + run_program = set_field(run_program, AC_ACCESS_REGISTER_REGNO, 0x1000); + + return execute_abstract_command(target, run_program); +} + +void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d) +{ + RISCV013_INFO(info); + buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_WRITE); + buf_set_u64((unsigned char *)buf, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, d); + buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a); +} + +void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a) +{ + RISCV013_INFO(info); + buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_READ); + buf_set_u64((unsigned char *)buf, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, 0); + buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a); +} + +void riscv013_fill_dmi_nop_u64(struct target *target, char *buf) +{ + RISCV013_INFO(info); + buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_NOP); + buf_set_u64((unsigned char *)buf, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, 0); + buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, 0); +} + +int riscv013_dmi_write_u64_bits(struct target *target) +{ + RISCV013_INFO(info); + return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH; +} + +static int maybe_execute_fence_i(struct target *target) +{ + RISCV013_INFO(info); + RISCV_INFO(r); + if (info->progbufsize + r->impebreak >= 2) { + struct riscv_program program; + riscv_program_init(&program, target); + if (riscv_program_fence_i(&program) != ERROR_OK) + return ERROR_FAIL; + if (riscv_program_exec(&program, target) != ERROR_OK) { + LOG_ERROR("Failed to execute fence.i"); + return ERROR_FAIL; + } + } + return ERROR_OK; +} + +/* Helper Functions. */ +static int riscv013_on_step_or_resume(struct target *target, bool step) +{ + if (maybe_execute_fence_i(target) != ERROR_OK) + return ERROR_FAIL; + + /* We want to twiddle some bits in the debug CSR so debugging works. */ + riscv_reg_t dcsr; + int result = register_read(target, &dcsr, GDB_REGNO_DCSR); + if (result != ERROR_OK) + return result; + dcsr = set_field(dcsr, CSR_DCSR_STEP, step); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, 1); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, 1); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, 1); + return riscv_set_register(target, GDB_REGNO_DCSR, dcsr); +} + +static int riscv013_step_or_resume_current_hart(struct target *target, bool step) +{ + RISCV_INFO(r); + LOG_DEBUG("resuming hart %d (for step?=%d)", r->current_hartid, step); + if (!riscv_is_halted(target)) { + LOG_ERROR("Hart %d is not halted!", r->current_hartid); + return ERROR_FAIL; + } + + if (maybe_execute_fence_i(target) != ERROR_OK) + return ERROR_FAIL; + + /* Issue the resume command, and then wait for the current hart to resume. */ + uint32_t dmcontrol = DMI_DMCONTROL_DMACTIVE; + dmcontrol = set_hartsel(dmcontrol, r->current_hartid); + dmi_write(target, DMI_DMCONTROL, dmcontrol | DMI_DMCONTROL_RESUMEREQ); + + uint32_t dmstatus; + for (size_t i = 0; i < 256; ++i) { + usleep(10); + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return ERROR_FAIL; + if (get_field(dmstatus, DMI_DMSTATUS_ALLRESUMEACK) == 0) + continue; + if (step && get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0) + continue; + + dmi_write(target, DMI_DMCONTROL, dmcontrol); + return ERROR_OK; + } + + LOG_ERROR("unable to resume hart %d", r->current_hartid); + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; + LOG_ERROR(" dmcontrol=0x%08x", dmcontrol); + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return ERROR_FAIL; + LOG_ERROR(" dmstatus =0x%08x", dmstatus); + + if (step) { + LOG_ERROR(" was stepping, halting"); + riscv013_halt_current_hart(target); + return ERROR_OK; + } + + return ERROR_FAIL; +} + +void riscv013_clear_abstract_error(struct target *target) +{ + /* Wait for busy to go away. */ + time_t start = time(NULL); + uint32_t abstractcs; + dmi_read(target, &abstractcs, DMI_ABSTRACTCS); + while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) { + dmi_read(target, &abstractcs, DMI_ABSTRACTCS); + + if (time(NULL) - start > riscv_command_timeout_sec) { + LOG_ERROR("abstractcs.busy is not going low after %d seconds " + "(abstractcs=0x%x). The target is either really slow or " + "broken. You could increase the timeout with riscv " + "set_command_timeout_sec.", + riscv_command_timeout_sec, abstractcs); + break; + } + } + /* Clear the error status. */ + dmi_write(target, DMI_ABSTRACTCS, abstractcs & DMI_ABSTRACTCS_CMDERR); +} diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c new file mode 100644 index 000000000..8d76c4aa4 --- /dev/null +++ b/src/target/riscv/riscv.c @@ -0,0 +1,2512 @@ +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "target/target.h" +#include "target/algorithm.h" +#include "target/target_type.h" +#include "log.h" +#include "jtag/jtag.h" +#include "target/register.h" +#include "target/breakpoints.h" +#include "helper/time_support.h" +#include "riscv.h" +#include "gdb_regs.h" +#include "rtos/rtos.h" + +/** + * Since almost everything can be accomplish by scanning the dbus register, all + * functions here assume dbus is already selected. The exception are functions + * called directly by OpenOCD, which can't assume anything about what's + * currently in IR. They should set IR to dbus explicitly. + */ + +/** + * Code structure + * + * At the bottom of the stack are the OpenOCD JTAG functions: + * jtag_add_[id]r_scan + * jtag_execute_query + * jtag_add_runtest + * + * There are a few functions to just instantly shift a register and get its + * value: + * dtmcontrol_scan + * idcode_scan + * dbus_scan + * + * Because doing one scan and waiting for the result is slow, most functions + * batch up a bunch of dbus writes and then execute them all at once. They use + * the scans "class" for this: + * scans_new + * scans_delete + * scans_execute + * scans_add_... + * Usually you new(), call a bunch of add functions, then execute() and look + * at the results by calling scans_get...() + * + * Optimized functions will directly use the scans class above, but slightly + * lazier code will use the cache functions that in turn use the scans + * functions: + * cache_get... + * cache_set... + * cache_write + * cache_set... update a local structure, which is then synced to the target + * with cache_write(). Only Debug RAM words that are actually changed are sent + * to the target. Afterwards use cache_get... to read results. + */ + +#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) +#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) + +#define DIM(x) (sizeof(x)/sizeof(*x)) + +/* Constants for legacy SiFive hardware breakpoints. */ +#define CSR_BPCONTROL_X (1<<0) +#define CSR_BPCONTROL_W (1<<1) +#define CSR_BPCONTROL_R (1<<2) +#define CSR_BPCONTROL_U (1<<3) +#define CSR_BPCONTROL_S (1<<4) +#define CSR_BPCONTROL_H (1<<5) +#define CSR_BPCONTROL_M (1<<6) +#define CSR_BPCONTROL_BPMATCH (0xf<<7) +#define CSR_BPCONTROL_BPACTION (0xff<<11) + +#define DEBUG_ROM_START 0x800 +#define DEBUG_ROM_RESUME (DEBUG_ROM_START + 4) +#define DEBUG_ROM_EXCEPTION (DEBUG_ROM_START + 8) +#define DEBUG_RAM_START 0x400 + +#define SETHALTNOT 0x10c + +/*** JTAG registers. ***/ + +#define DTMCONTROL 0x10 +#define DTMCONTROL_DBUS_RESET (1<<16) +#define DTMCONTROL_IDLE (7<<10) +#define DTMCONTROL_ADDRBITS (0xf<<4) +#define DTMCONTROL_VERSION (0xf) + +#define DBUS 0x11 +#define DBUS_OP_START 0 +#define DBUS_OP_SIZE 2 +typedef enum { + DBUS_OP_NOP = 0, + DBUS_OP_READ = 1, + DBUS_OP_WRITE = 2 +} dbus_op_t; +typedef enum { + DBUS_STATUS_SUCCESS = 0, + DBUS_STATUS_FAILED = 2, + DBUS_STATUS_BUSY = 3 +} dbus_status_t; +#define DBUS_DATA_START 2 +#define DBUS_DATA_SIZE 34 +#define DBUS_ADDRESS_START 36 + +typedef enum { + RE_OK, + RE_FAIL, + RE_AGAIN +} riscv_error_t; + +typedef enum slot { + SLOT0, + SLOT1, + SLOT_LAST, +} slot_t; + +/*** Debug Bus registers. ***/ + +#define DMCONTROL 0x10 +#define DMCONTROL_INTERRUPT (((uint64_t)1)<<33) +#define DMCONTROL_HALTNOT (((uint64_t)1)<<32) +#define DMCONTROL_BUSERROR (7<<19) +#define DMCONTROL_SERIAL (3<<16) +#define DMCONTROL_AUTOINCREMENT (1<<15) +#define DMCONTROL_ACCESS (7<<12) +#define DMCONTROL_HARTID (0x3ff<<2) +#define DMCONTROL_NDRESET (1<<1) +#define DMCONTROL_FULLRESET 1 + +#define DMINFO 0x11 +#define DMINFO_ABUSSIZE (0x7fU<<25) +#define DMINFO_SERIALCOUNT (0xf<<21) +#define DMINFO_ACCESS128 (1<<20) +#define DMINFO_ACCESS64 (1<<19) +#define DMINFO_ACCESS32 (1<<18) +#define DMINFO_ACCESS16 (1<<17) +#define DMINFO_ACCESS8 (1<<16) +#define DMINFO_DRAMSIZE (0x3f<<10) +#define DMINFO_AUTHENTICATED (1<<5) +#define DMINFO_AUTHBUSY (1<<4) +#define DMINFO_AUTHTYPE (3<<2) +#define DMINFO_VERSION 3 + +/*** Info about the core being debugged. ***/ + +#define DBUS_ADDRESS_UNKNOWN 0xffff + +#define MAX_HWBPS 16 +#define DRAM_CACHE_SIZE 16 + +uint8_t ir_dtmcontrol[1] = {DTMCONTROL}; +struct scan_field select_dtmcontrol = { + .in_value = NULL, + .out_value = ir_dtmcontrol +}; +uint8_t ir_dbus[1] = {DBUS}; +struct scan_field select_dbus = { + .in_value = NULL, + .out_value = ir_dbus +}; +uint8_t ir_idcode[1] = {0x1}; +struct scan_field select_idcode = { + .in_value = NULL, + .out_value = ir_idcode +}; + +struct trigger { + uint64_t address; + uint32_t length; + uint64_t mask; + uint64_t value; + bool read, write, execute; + int unique_id; +}; + +/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ +int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC; + +/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ +int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC; + +bool riscv_prefer_sba; + +/* In addition to the ones in the standard spec, we'll also expose additional + * CSRs in this list. + * The list is either NULL, or a series of ranges (inclusive), terminated with + * 1,0. */ +struct { + uint16_t low, high; +} *expose_csr; + +static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) +{ + struct scan_field field; + uint8_t in_value[4]; + uint8_t out_value[4]; + + buf_set_u32(out_value, 0, 32, out); + + jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE); + + field.num_bits = 32; + field.out_value = out_value; + field.in_value = in_value; + jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); + + /* Always return to dbus. */ + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); + + int retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("failed jtag scan: %d", retval); + return retval; + } + + uint32_t in = buf_get_u32(field.in_value, 0, 32); + LOG_DEBUG("DTMCONTROL: 0x%x -> 0x%x", out, in); + + return in; +} + +static struct target_type *get_target_type(struct target *target) +{ + riscv_info_t *info = (riscv_info_t *) target->arch_info; + + if (!info) { + LOG_ERROR("Target has not been initialized"); + return NULL; + } + + switch (info->dtm_version) { + case 0: + return &riscv011_target; + case 1: + return &riscv013_target; + default: + LOG_ERROR("Unsupported DTM version: %d", info->dtm_version); + return NULL; + } +} + +static int riscv_init_target(struct command_context *cmd_ctx, + struct target *target) +{ + LOG_DEBUG("riscv_init_target()"); + target->arch_info = calloc(1, sizeof(riscv_info_t)); + if (!target->arch_info) + return ERROR_FAIL; + riscv_info_t *info = (riscv_info_t *) target->arch_info; + riscv_info_init(target, info); + info->cmd_ctx = cmd_ctx; + + select_dtmcontrol.num_bits = target->tap->ir_length; + select_dbus.num_bits = target->tap->ir_length; + select_idcode.num_bits = target->tap->ir_length; + + riscv_semihosting_init(target); + + return ERROR_OK; +} + +static void riscv_deinit_target(struct target *target) +{ + LOG_DEBUG("riscv_deinit_target()"); + struct target_type *tt = get_target_type(target); + if (tt) { + tt->deinit_target(target); + riscv_info_t *info = (riscv_info_t *) target->arch_info; + free(info); + } + target->arch_info = NULL; +} + +static int oldriscv_halt(struct target *target) +{ + struct target_type *tt = get_target_type(target); + return tt->halt(target); +} + +static void trigger_from_breakpoint(struct trigger *trigger, + const struct breakpoint *breakpoint) +{ + trigger->address = breakpoint->address; + trigger->length = breakpoint->length; + trigger->mask = ~0LL; + trigger->read = false; + trigger->write = false; + trigger->execute = true; + /* unique_id is unique across both breakpoints and watchpoints. */ + trigger->unique_id = breakpoint->unique_id; +} + +static int maybe_add_trigger_t1(struct target *target, unsigned hartid, + struct trigger *trigger, uint64_t tdata1) +{ + RISCV_INFO(r); + + const uint32_t bpcontrol_x = 1<<0; + const uint32_t bpcontrol_w = 1<<1; + const uint32_t bpcontrol_r = 1<<2; + const uint32_t bpcontrol_u = 1<<3; + const uint32_t bpcontrol_s = 1<<4; + const uint32_t bpcontrol_h = 1<<5; + const uint32_t bpcontrol_m = 1<<6; + const uint32_t bpcontrol_bpmatch = 0xf << 7; + const uint32_t bpcontrol_bpaction = 0xff << 11; + + if (tdata1 & (bpcontrol_r | bpcontrol_w | bpcontrol_x)) { + /* Trigger is already in use, presumably by user code. */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + tdata1 = set_field(tdata1, bpcontrol_r, trigger->read); + tdata1 = set_field(tdata1, bpcontrol_w, trigger->write); + tdata1 = set_field(tdata1, bpcontrol_x, trigger->execute); + tdata1 = set_field(tdata1, bpcontrol_u, + !!(r->misa[hartid] & (1 << ('U' - 'A')))); + tdata1 = set_field(tdata1, bpcontrol_s, + !!(r->misa[hartid] & (1 << ('S' - 'A')))); + tdata1 = set_field(tdata1, bpcontrol_h, + !!(r->misa[hartid] & (1 << ('H' - 'A')))); + tdata1 |= bpcontrol_m; + tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */ + tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); /* cause bp exception */ + + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, tdata1); + + riscv_reg_t tdata1_rb; + if (riscv_get_register_on_hart(target, &tdata1_rb, hartid, + GDB_REGNO_TDATA1) != ERROR_OK) + return ERROR_FAIL; + LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); + + if (tdata1 != tdata1_rb) { + LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%" + PRIx64 " to tdata1 it contains 0x%" PRIx64, + tdata1, tdata1_rb); + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA2, trigger->address); + + return ERROR_OK; +} + +static int maybe_add_trigger_t2(struct target *target, unsigned hartid, + struct trigger *trigger, uint64_t tdata1) +{ + RISCV_INFO(r); + + /* tselect is already set */ + if (tdata1 & (MCONTROL_EXECUTE | MCONTROL_STORE | MCONTROL_LOAD)) { + /* Trigger is already in use, presumably by user code. */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* address/data match trigger */ + tdata1 |= MCONTROL_DMODE(riscv_xlen(target)); + tdata1 = set_field(tdata1, MCONTROL_ACTION, + MCONTROL_ACTION_DEBUG_MODE); + tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL); + tdata1 |= MCONTROL_M; + if (r->misa[hartid] & (1 << ('H' - 'A'))) + tdata1 |= MCONTROL_H; + if (r->misa[hartid] & (1 << ('S' - 'A'))) + tdata1 |= MCONTROL_S; + if (r->misa[hartid] & (1 << ('U' - 'A'))) + tdata1 |= MCONTROL_U; + + if (trigger->execute) + tdata1 |= MCONTROL_EXECUTE; + if (trigger->read) + tdata1 |= MCONTROL_LOAD; + if (trigger->write) + tdata1 |= MCONTROL_STORE; + + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, tdata1); + + uint64_t tdata1_rb; + int result = riscv_get_register_on_hart(target, &tdata1_rb, hartid, GDB_REGNO_TDATA1); + if (result != ERROR_OK) + return result; + LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); + + if (tdata1 != tdata1_rb) { + LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%" + PRIx64 " to tdata1 it contains 0x%" PRIx64, + tdata1, tdata1_rb); + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA2, trigger->address); + + return ERROR_OK; +} + +static int add_trigger(struct target *target, struct trigger *trigger) +{ + RISCV_INFO(r); + + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + + /* In RTOS mode, we need to set the same trigger in the same slot on every + * hart, to keep up the illusion that each hart is a thread running on the + * same core. */ + + /* Otherwise, we just set the trigger on the one hart this target deals + * with. */ + + riscv_reg_t tselect[RISCV_MAX_HARTS]; + + int first_hart = -1; + for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) { + if (!riscv_hart_enabled(target, hartid)) + continue; + if (first_hart < 0) + first_hart = hartid; + int result = riscv_get_register_on_hart(target, &tselect[hartid], + hartid, GDB_REGNO_TSELECT); + if (result != ERROR_OK) + return result; + } + assert(first_hart >= 0); + + unsigned int i; + for (i = 0; i < r->trigger_count[first_hart]; i++) { + if (r->trigger_unique_id[i] != -1) + continue; + + riscv_set_register_on_hart(target, first_hart, GDB_REGNO_TSELECT, i); + + uint64_t tdata1; + int result = riscv_get_register_on_hart(target, &tdata1, first_hart, + GDB_REGNO_TDATA1); + if (result != ERROR_OK) + return result; + int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); + + result = ERROR_OK; + for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) { + if (!riscv_hart_enabled(target, hartid)) + continue; + if (hartid > first_hart) + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, i); + switch (type) { + case 1: + result = maybe_add_trigger_t1(target, hartid, trigger, tdata1); + break; + case 2: + result = maybe_add_trigger_t2(target, hartid, trigger, tdata1); + break; + default: + LOG_DEBUG("trigger %d has unknown type %d", i, type); + continue; + } + + if (result != ERROR_OK) + continue; + } + + if (result != ERROR_OK) + continue; + + LOG_DEBUG("Using trigger %d (type %d) for bp %d", i, type, + trigger->unique_id); + r->trigger_unique_id[i] = trigger->unique_id; + break; + } + + for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) { + if (!riscv_hart_enabled(target, hartid)) + continue; + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, + tselect[hartid]); + } + + if (i >= r->trigger_count[first_hart]) { + LOG_ERROR("Couldn't find an available hardware trigger."); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + return ERROR_OK; +} + +int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) +{ + if (breakpoint->type == BKPT_SOFT) { + if (target_read_memory(target, breakpoint->address, breakpoint->length, 1, + breakpoint->orig_instr) != ERROR_OK) { + LOG_ERROR("Failed to read original instruction at 0x%" TARGET_PRIxADDR, + breakpoint->address); + return ERROR_FAIL; + } + + int retval; + if (breakpoint->length == 4) + retval = target_write_u32(target, breakpoint->address, ebreak()); + else + retval = target_write_u16(target, breakpoint->address, ebreak_c()); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write %d-byte breakpoint instruction at 0x%" + TARGET_PRIxADDR, breakpoint->length, breakpoint->address); + return ERROR_FAIL; + } + + } else if (breakpoint->type == BKPT_HARD) { + struct trigger trigger; + trigger_from_breakpoint(&trigger, breakpoint); + int result = add_trigger(target, &trigger); + if (result != ERROR_OK) + return result; + + } else { + LOG_INFO("OpenOCD only supports hardware and software breakpoints."); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + breakpoint->set = true; + + return ERROR_OK; +} + +static int remove_trigger(struct target *target, struct trigger *trigger) +{ + RISCV_INFO(r); + + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + + int first_hart = -1; + for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) { + if (!riscv_hart_enabled(target, hartid)) + continue; + if (first_hart < 0) { + first_hart = hartid; + break; + } + } + assert(first_hart >= 0); + + unsigned int i; + for (i = 0; i < r->trigger_count[first_hart]; i++) { + if (r->trigger_unique_id[i] == trigger->unique_id) + break; + } + if (i >= r->trigger_count[first_hart]) { + LOG_ERROR("Couldn't find the hardware resources used by hardware " + "trigger."); + return ERROR_FAIL; + } + LOG_DEBUG("Stop using resource %d for bp %d", i, trigger->unique_id); + for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) { + if (!riscv_hart_enabled(target, hartid)) + continue; + riscv_reg_t tselect; + int result = riscv_get_register_on_hart(target, &tselect, hartid, GDB_REGNO_TSELECT); + if (result != ERROR_OK) + return result; + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, i); + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0); + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, tselect); + } + r->trigger_unique_id[i] = -1; + + return ERROR_OK; +} + +int riscv_remove_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + if (breakpoint->type == BKPT_SOFT) { + if (target_write_memory(target, breakpoint->address, breakpoint->length, 1, + breakpoint->orig_instr) != ERROR_OK) { + LOG_ERROR("Failed to restore instruction for %d-byte breakpoint at " + "0x%" TARGET_PRIxADDR, breakpoint->length, breakpoint->address); + return ERROR_FAIL; + } + + } else if (breakpoint->type == BKPT_HARD) { + struct trigger trigger; + trigger_from_breakpoint(&trigger, breakpoint); + int result = remove_trigger(target, &trigger); + if (result != ERROR_OK) + return result; + + } else { + LOG_INFO("OpenOCD only supports hardware and software breakpoints."); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + breakpoint->set = false; + + return ERROR_OK; +} + +static void trigger_from_watchpoint(struct trigger *trigger, + const struct watchpoint *watchpoint) +{ + trigger->address = watchpoint->address; + trigger->length = watchpoint->length; + trigger->mask = watchpoint->mask; + trigger->value = watchpoint->value; + trigger->read = (watchpoint->rw == WPT_READ || watchpoint->rw == WPT_ACCESS); + trigger->write = (watchpoint->rw == WPT_WRITE || watchpoint->rw == WPT_ACCESS); + trigger->execute = false; + /* unique_id is unique across both breakpoints and watchpoints. */ + trigger->unique_id = watchpoint->unique_id; +} + +int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint) +{ + struct trigger trigger; + trigger_from_watchpoint(&trigger, watchpoint); + + int result = add_trigger(target, &trigger); + if (result != ERROR_OK) + return result; + watchpoint->set = true; + + return ERROR_OK; +} + +int riscv_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + struct trigger trigger; + trigger_from_watchpoint(&trigger, watchpoint); + + int result = remove_trigger(target, &trigger); + if (result != ERROR_OK) + return result; + watchpoint->set = false; + + return ERROR_OK; +} + +static int oldriscv_step(struct target *target, int current, uint32_t address, + int handle_breakpoints) +{ + struct target_type *tt = get_target_type(target); + return tt->step(target, current, address, handle_breakpoints); +} + +static int old_or_new_riscv_step( + struct target *target, + int current, + target_addr_t address, + int handle_breakpoints +){ + RISCV_INFO(r); + LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); + if (r->is_halted == NULL) + return oldriscv_step(target, current, address, handle_breakpoints); + else + return riscv_openocd_step(target, current, address, handle_breakpoints); +} + + +static int riscv_examine(struct target *target) +{ + LOG_DEBUG("riscv_examine()"); + if (target_was_examined(target)) { + LOG_DEBUG("Target was already examined."); + return ERROR_OK; + } + + /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ + + riscv_info_t *info = (riscv_info_t *) target->arch_info; + uint32_t dtmcontrol = dtmcontrol_scan(target, 0); + LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); + info->dtm_version = get_field(dtmcontrol, DTMCONTROL_VERSION); + LOG_DEBUG(" version=0x%x", info->dtm_version); + + struct target_type *tt = get_target_type(target); + if (tt == NULL) + return ERROR_FAIL; + + int result = tt->init_target(info->cmd_ctx, target); + if (result != ERROR_OK) + return result; + + return tt->examine(target); +} + +static int oldriscv_poll(struct target *target) +{ + struct target_type *tt = get_target_type(target); + return tt->poll(target); +} + +static int old_or_new_riscv_poll(struct target *target) +{ + RISCV_INFO(r); + if (r->is_halted == NULL) + return oldriscv_poll(target); + else + return riscv_openocd_poll(target); +} + +static int old_or_new_riscv_halt(struct target *target) +{ + RISCV_INFO(r); + if (r->is_halted == NULL) + return oldriscv_halt(target); + else + return riscv_openocd_halt(target); +} + +static int riscv_assert_reset(struct target *target) +{ + struct target_type *tt = get_target_type(target); + return tt->assert_reset(target); +} + +static int riscv_deassert_reset(struct target *target) +{ + LOG_DEBUG("RISCV DEASSERT RESET"); + struct target_type *tt = get_target_type(target); + return tt->deassert_reset(target); +} + + +static int oldriscv_resume(struct target *target, int current, uint32_t address, + int handle_breakpoints, int debug_execution) +{ + struct target_type *tt = get_target_type(target); + return tt->resume(target, current, address, handle_breakpoints, + debug_execution); +} + +static int old_or_new_riscv_resume( + struct target *target, + int current, + target_addr_t address, + int handle_breakpoints, + int debug_execution +){ + RISCV_INFO(r); + LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); + if (r->is_halted == NULL) + return oldriscv_resume(target, current, address, handle_breakpoints, debug_execution); + else + return riscv_openocd_resume(target, current, address, handle_breakpoints, debug_execution); +} + +static int riscv_select_current_hart(struct target *target) +{ + RISCV_INFO(r); + if (r->rtos_hartid != -1 && riscv_rtos_enabled(target)) + return riscv_set_current_hartid(target, r->rtos_hartid); + else + return riscv_set_current_hartid(target, target->coreid); +} + +static int riscv_read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + struct target_type *tt = get_target_type(target); + return tt->read_memory(target, address, size, count, buffer); +} + +static int riscv_write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + struct target_type *tt = get_target_type(target); + return tt->write_memory(target, address, size, count, buffer); +} + +static int riscv_get_gdb_reg_list(struct target *target, + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class) +{ + RISCV_INFO(r); + LOG_DEBUG("reg_class=%d", reg_class); + LOG_DEBUG("rtos_hartid=%d current_hartid=%d", r->rtos_hartid, r->current_hartid); + + if (!target->reg_cache) { + LOG_ERROR("Target not initialized. Return ERROR_FAIL."); + return ERROR_FAIL; + } + + if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + + switch (reg_class) { + case REG_CLASS_GENERAL: + *reg_list_size = 32; + break; + case REG_CLASS_ALL: + *reg_list_size = GDB_REGNO_COUNT; + break; + default: + LOG_ERROR("Unsupported reg_class: %d", reg_class); + return ERROR_FAIL; + } + + *reg_list = calloc(*reg_list_size, sizeof(struct reg *)); + if (!*reg_list) + return ERROR_FAIL; + + for (int i = 0; i < *reg_list_size; i++) { + assert(!target->reg_cache->reg_list[i].valid || + target->reg_cache->reg_list[i].size > 0); + (*reg_list)[i] = &target->reg_cache->reg_list[i]; + } + + return ERROR_OK; +} + +static int riscv_arch_state(struct target *target) +{ + struct target_type *tt = get_target_type(target); + return tt->arch_state(target); +} + +/* Algorithm must end with a software breakpoint instruction. */ +static int riscv_run_algorithm(struct target *target, int num_mem_params, + struct mem_param *mem_params, int num_reg_params, + struct reg_param *reg_params, target_addr_t entry_point, + target_addr_t exit_point, int timeout_ms, void *arch_info) +{ + riscv_info_t *info = (riscv_info_t *) target->arch_info; + + if (num_mem_params > 0) { + LOG_ERROR("Memory parameters are not supported for RISC-V algorithms."); + return ERROR_FAIL; + } + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* Save registers */ + struct reg *reg_pc = register_get_by_name(target->reg_cache, "pc", 1); + if (!reg_pc || reg_pc->type->get(reg_pc) != ERROR_OK) + return ERROR_FAIL; + uint64_t saved_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size); + + uint64_t saved_regs[32]; + for (int i = 0; i < num_reg_params; i++) { + LOG_DEBUG("save %s", reg_params[i].reg_name); + struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, 0); + if (!r) { + LOG_ERROR("Couldn't find register named '%s'", reg_params[i].reg_name); + return ERROR_FAIL; + } + + if (r->size != reg_params[i].size) { + LOG_ERROR("Register %s is %d bits instead of %d bits.", + reg_params[i].reg_name, r->size, reg_params[i].size); + return ERROR_FAIL; + } + + if (r->number > GDB_REGNO_XPR31) { + LOG_ERROR("Only GPRs can be use as argument registers."); + return ERROR_FAIL; + } + + if (r->type->get(r) != ERROR_OK) + return ERROR_FAIL; + saved_regs[r->number] = buf_get_u64(r->value, 0, r->size); + if (r->type->set(r, reg_params[i].value) != ERROR_OK) + return ERROR_FAIL; + } + + + /* Disable Interrupts before attempting to run the algorithm. */ + uint64_t current_mstatus; + uint8_t mstatus_bytes[8]; + + LOG_DEBUG("Disabling Interrupts"); + struct reg *reg_mstatus = register_get_by_name(target->reg_cache, + "mstatus", 1); + if (!reg_mstatus) { + LOG_ERROR("Couldn't find mstatus!"); + return ERROR_FAIL; + } + + reg_mstatus->type->get(reg_mstatus); + current_mstatus = buf_get_u64(reg_mstatus->value, 0, reg_mstatus->size); + uint64_t ie_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE; + buf_set_u64(mstatus_bytes, 0, info->xlen[0], set_field(current_mstatus, + ie_mask, 0)); + + reg_mstatus->type->set(reg_mstatus, mstatus_bytes); + + /* Run algorithm */ + LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point); + if (oldriscv_resume(target, 0, entry_point, 0, 0) != ERROR_OK) + return ERROR_FAIL; + + int64_t start = timeval_ms(); + while (target->state != TARGET_HALTED) { + LOG_DEBUG("poll()"); + int64_t now = timeval_ms(); + if (now - start > timeout_ms) { + LOG_ERROR("Algorithm timed out after %d ms.", timeout_ms); + LOG_ERROR(" now = 0x%08x", (uint32_t) now); + LOG_ERROR(" start = 0x%08x", (uint32_t) start); + oldriscv_halt(target); + old_or_new_riscv_poll(target); + return ERROR_TARGET_TIMEOUT; + } + + int result = old_or_new_riscv_poll(target); + if (result != ERROR_OK) + return result; + } + + if (reg_pc->type->get(reg_pc) != ERROR_OK) + return ERROR_FAIL; + uint64_t final_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size); + if (final_pc != exit_point) { + LOG_ERROR("PC ended up at 0x%" PRIx64 " instead of 0x%" + TARGET_PRIxADDR, final_pc, exit_point); + return ERROR_FAIL; + } + + /* Restore Interrupts */ + LOG_DEBUG("Restoring Interrupts"); + buf_set_u64(mstatus_bytes, 0, info->xlen[0], current_mstatus); + reg_mstatus->type->set(reg_mstatus, mstatus_bytes); + + /* Restore registers */ + uint8_t buf[8]; + buf_set_u64(buf, 0, info->xlen[0], saved_pc); + if (reg_pc->type->set(reg_pc, buf) != ERROR_OK) + return ERROR_FAIL; + + for (int i = 0; i < num_reg_params; i++) { + LOG_DEBUG("restore %s", reg_params[i].reg_name); + struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, 0); + buf_set_u64(buf, 0, info->xlen[0], saved_regs[r->number]); + if (r->type->set(r, buf) != ERROR_OK) + return ERROR_FAIL; + } + + return ERROR_OK; +} + +/* Should run code on the target to perform CRC of +memory. Not yet implemented. +*/ + +static int riscv_checksum_memory(struct target *target, + target_addr_t address, uint32_t count, + uint32_t *checksum) +{ + *checksum = 0xFFFFFFFF; + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; +} + +/*** OpenOCD Helper Functions ***/ + +enum riscv_poll_hart { + RPH_NO_CHANGE, + RPH_DISCOVERED_HALTED, + RPH_DISCOVERED_RUNNING, + RPH_ERROR +}; +static enum riscv_poll_hart riscv_poll_hart(struct target *target, int hartid) +{ + RISCV_INFO(r); + if (riscv_set_current_hartid(target, hartid) != ERROR_OK) + return RPH_ERROR; + + LOG_DEBUG("polling hart %d, target->state=%d", hartid, target->state); + + /* If OpenOCD thinks we're running but this hart is halted then it's time + * to raise an event. */ + bool halted = riscv_is_halted(target); + if (target->state != TARGET_HALTED && halted) { + LOG_DEBUG(" triggered a halt"); + r->on_halt(target); + return RPH_DISCOVERED_HALTED; + } else if (target->state != TARGET_RUNNING && !halted) { + LOG_DEBUG(" triggered running"); + target->state = TARGET_RUNNING; + return RPH_DISCOVERED_RUNNING; + } + + return RPH_NO_CHANGE; +} + +/*** OpenOCD Interface ***/ +int riscv_openocd_poll(struct target *target) +{ + LOG_DEBUG("polling all harts"); + int halted_hart = -1; + if (riscv_rtos_enabled(target)) { + /* Check every hart for an event. */ + for (int i = 0; i < riscv_count_harts(target); ++i) { + enum riscv_poll_hart out = riscv_poll_hart(target, i); + switch (out) { + case RPH_NO_CHANGE: + case RPH_DISCOVERED_RUNNING: + continue; + case RPH_DISCOVERED_HALTED: + halted_hart = i; + break; + case RPH_ERROR: + return ERROR_FAIL; + } + } + if (halted_hart == -1) { + LOG_DEBUG(" no harts just halted, target->state=%d", target->state); + return ERROR_OK; + } + LOG_DEBUG(" hart %d halted", halted_hart); + + /* If we're here then at least one hart triggered. That means + * we want to go and halt _every_ hart in the system, as that's + * the invariant we hold here. Some harts might have already + * halted (as we're either in single-step mode or they also + * triggered a breakpoint), so don't attempt to halt those + * harts. */ + for (int i = 0; i < riscv_count_harts(target); ++i) + riscv_halt_one_hart(target, i); + } else { + enum riscv_poll_hart out = riscv_poll_hart(target, + riscv_current_hartid(target)); + if (out == RPH_NO_CHANGE || out == RPH_DISCOVERED_RUNNING) + return ERROR_OK; + else if (out == RPH_ERROR) + return ERROR_FAIL; + + halted_hart = riscv_current_hartid(target); + LOG_DEBUG(" hart %d halted", halted_hart); + } + + target->state = TARGET_HALTED; + switch (riscv_halt_reason(target, halted_hart)) { + case RISCV_HALT_BREAKPOINT: + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case RISCV_HALT_TRIGGER: + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case RISCV_HALT_INTERRUPT: + target->debug_reason = DBG_REASON_DBGRQ; + break; + case RISCV_HALT_SINGLESTEP: + target->debug_reason = DBG_REASON_SINGLESTEP; + break; + case RISCV_HALT_UNKNOWN: + target->debug_reason = DBG_REASON_UNDEFINED; + break; + case RISCV_HALT_ERROR: + return ERROR_FAIL; + } + + if (riscv_rtos_enabled(target)) { + target->rtos->current_threadid = halted_hart + 1; + target->rtos->current_thread = halted_hart + 1; + } + + target->state = TARGET_HALTED; + + if (target->debug_reason == DBG_REASON_BREAKPOINT) { + int retval; + if (riscv_semihosting(target, &retval) != 0) + return retval; + } + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + return ERROR_OK; +} + +int riscv_openocd_halt(struct target *target) +{ + RISCV_INFO(r); + + LOG_DEBUG("halting all harts"); + + int out = riscv_halt_all_harts(target); + if (out != ERROR_OK) { + LOG_ERROR("Unable to halt all harts"); + return out; + } + + register_cache_invalidate(target->reg_cache); + if (riscv_rtos_enabled(target)) { + target->rtos->current_threadid = r->rtos_hartid + 1; + target->rtos->current_thread = r->rtos_hartid + 1; + } + + target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_DBGRQ; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + return out; +} + +int riscv_openocd_resume( + struct target *target, + int current, + target_addr_t address, + int handle_breakpoints, + int debug_execution) +{ + LOG_DEBUG("debug_reason=%d", target->debug_reason); + + if (!current) + riscv_set_register(target, GDB_REGNO_PC, address); + + if (target->debug_reason == DBG_REASON_WATCHPOINT) { + /* To be able to run off a trigger, disable all the triggers, step, and + * then resume as usual. */ + struct watchpoint *watchpoint = target->watchpoints; + bool trigger_temporarily_cleared[RISCV_MAX_HWBPS] = {0}; + + int i = 0; + int result = ERROR_OK; + while (watchpoint && result == ERROR_OK) { + LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->set); + trigger_temporarily_cleared[i] = watchpoint->set; + if (watchpoint->set) + result = riscv_remove_watchpoint(target, watchpoint); + watchpoint = watchpoint->next; + i++; + } + + if (result == ERROR_OK) + result = riscv_step_rtos_hart(target); + + watchpoint = target->watchpoints; + i = 0; + while (watchpoint) { + LOG_DEBUG("watchpoint %d: cleared=%d", i, trigger_temporarily_cleared[i]); + if (trigger_temporarily_cleared[i]) { + if (result == ERROR_OK) + result = riscv_add_watchpoint(target, watchpoint); + else + riscv_add_watchpoint(target, watchpoint); + } + watchpoint = watchpoint->next; + i++; + } + + if (result != ERROR_OK) + return result; + } + + int out = riscv_resume_all_harts(target); + if (out != ERROR_OK) { + LOG_ERROR("unable to resume all harts"); + return out; + } + + register_cache_invalidate(target->reg_cache); + target->state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + return out; +} + +int riscv_openocd_step( + struct target *target, + int current, + target_addr_t address, + int handle_breakpoints +) { + LOG_DEBUG("stepping rtos hart"); + + if (!current) + riscv_set_register(target, GDB_REGNO_PC, address); + + int out = riscv_step_rtos_hart(target); + if (out != ERROR_OK) { + LOG_ERROR("unable to step rtos hart"); + return out; + } + + register_cache_invalidate(target->reg_cache); + target->state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_SINGLESTEP; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + return out; +} + +/* Command Handlers */ +COMMAND_HANDLER(riscv_set_command_timeout_sec) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + int timeout = atoi(CMD_ARGV[0]); + if (timeout <= 0) { + LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); + return ERROR_FAIL; + } + + riscv_command_timeout_sec = timeout; + + return ERROR_OK; +} + +COMMAND_HANDLER(riscv_set_reset_timeout_sec) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + int timeout = atoi(CMD_ARGV[0]); + if (timeout <= 0) { + LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); + return ERROR_FAIL; + } + + riscv_reset_timeout_sec = timeout; + return ERROR_OK; +} + +COMMAND_HANDLER(riscv_set_prefer_sba) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_prefer_sba); + return ERROR_OK; +} + +void parse_error(const char *string, char c, unsigned position) +{ + char buf[position+2]; + for (unsigned i = 0; i < position; i++) + buf[i] = ' '; + buf[position] = '^'; + buf[position + 1] = 0; + + LOG_ERROR("Parse error at character %c in:", c); + LOG_ERROR("%s", string); + LOG_ERROR("%s", buf); +} + +COMMAND_HANDLER(riscv_set_expose_csrs) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + for (unsigned pass = 0; pass < 2; pass++) { + unsigned range = 0; + unsigned low = 0; + bool parse_low = true; + unsigned high = 0; + for (unsigned i = 0; i == 0 || CMD_ARGV[0][i-1]; i++) { + char c = CMD_ARGV[0][i]; + if (isspace(c)) { + /* Ignore whitespace. */ + continue; + } + + if (parse_low) { + if (isdigit(c)) { + low *= 10; + low += c - '0'; + } else if (c == '-') { + parse_low = false; + } else if (c == ',' || c == 0) { + if (pass == 1) { + expose_csr[range].low = low; + expose_csr[range].high = low; + } + low = 0; + range++; + } else { + parse_error(CMD_ARGV[0], c, i); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + } else { + if (isdigit(c)) { + high *= 10; + high += c - '0'; + } else if (c == ',' || c == 0) { + parse_low = true; + if (pass == 1) { + expose_csr[range].low = low; + expose_csr[range].high = high; + } + low = 0; + high = 0; + range++; + } else { + parse_error(CMD_ARGV[0], c, i); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } + } + + if (pass == 0) { + if (expose_csr) + free(expose_csr); + expose_csr = calloc(range + 2, sizeof(*expose_csr)); + } else { + expose_csr[range].low = 1; + expose_csr[range].high = 0; + } + } + return ERROR_OK; +} + +COMMAND_HANDLER(riscv_authdata_read) +{ + if (CMD_ARGC != 0) { + LOG_ERROR("Command takes no parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + if (!target) { + LOG_ERROR("target is NULL!"); + return ERROR_FAIL; + } + + RISCV_INFO(r); + if (!r) { + LOG_ERROR("riscv_info is NULL!"); + return ERROR_FAIL; + } + + if (r->authdata_read) { + uint32_t value; + if (r->authdata_read(target, &value) != ERROR_OK) + return ERROR_FAIL; + command_print(CMD_CTX, "0x%" PRIx32, value); + return ERROR_OK; + } else { + LOG_ERROR("authdata_read is not implemented for this target."); + return ERROR_FAIL; + } +} + +COMMAND_HANDLER(riscv_authdata_write) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 argument"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + uint32_t value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], value); + + if (r->authdata_write) { + return r->authdata_write(target, value); + } else { + LOG_ERROR("authdata_write is not implemented for this target."); + return ERROR_FAIL; + } +} + +COMMAND_HANDLER(riscv_dmi_read) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + if (!target) { + LOG_ERROR("target is NULL!"); + return ERROR_FAIL; + } + + RISCV_INFO(r); + if (!r) { + LOG_ERROR("riscv_info is NULL!"); + return ERROR_FAIL; + } + + if (r->dmi_read) { + uint32_t address, value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); + if (r->dmi_read(target, &value, address) != ERROR_OK) + return ERROR_FAIL; + command_print(CMD_CTX, "0x%" PRIx32, value); + return ERROR_OK; + } else { + LOG_ERROR("dmi_read is not implemented for this target."); + return ERROR_FAIL; + } +} + + +COMMAND_HANDLER(riscv_dmi_write) +{ + if (CMD_ARGC != 2) { + LOG_ERROR("Command takes exactly 2 arguments"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + uint32_t address, value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + + if (r->dmi_write) { + return r->dmi_write(target, address, value); + } else { + LOG_ERROR("dmi_write is not implemented for this target."); + return ERROR_FAIL; + } +} + +static const struct command_registration riscv_exec_command_handlers[] = { + { + .name = "set_command_timeout_sec", + .handler = riscv_set_command_timeout_sec, + .mode = COMMAND_ANY, + .usage = "riscv set_command_timeout_sec [sec]", + .help = "Set the wall-clock timeout (in seconds) for individual commands" + }, + { + .name = "set_reset_timeout_sec", + .handler = riscv_set_reset_timeout_sec, + .mode = COMMAND_ANY, + .usage = "riscv set_reset_timeout_sec [sec]", + .help = "Set the wall-clock timeout (in seconds) after reset is deasserted" + }, + { + .name = "set_prefer_sba", + .handler = riscv_set_prefer_sba, + .mode = COMMAND_ANY, + .usage = "riscv set_prefer_sba on|off", + .help = "When on, prefer to use System Bus Access to access memory. " + "When off, prefer to use the Program Buffer to access memory." + }, + { + .name = "expose_csrs", + .handler = riscv_set_expose_csrs, + .mode = COMMAND_ANY, + .usage = "riscv expose_csrs n0[-m0][,n1[-m1]]...", + .help = "Configure a list of inclusive ranges for CSRs to expose in " + "addition to the standard ones. This must be executed before " + "`init`." + }, + { + .name = "authdata_read", + .handler = riscv_authdata_read, + .mode = COMMAND_ANY, + .usage = "riscv authdata_read", + .help = "Return the 32-bit value read from authdata." + }, + { + .name = "authdata_write", + .handler = riscv_authdata_write, + .mode = COMMAND_ANY, + .usage = "riscv authdata_write value", + .help = "Write the 32-bit value to authdata." + }, + { + .name = "dmi_read", + .handler = riscv_dmi_read, + .mode = COMMAND_ANY, + .usage = "riscv dmi_read address", + .help = "Perform a 32-bit DMI read at address, returning the value." + }, + { + .name = "dmi_write", + .handler = riscv_dmi_write, + .mode = COMMAND_ANY, + .usage = "riscv dmi_write address value", + .help = "Perform a 32-bit DMI write of value at address." + }, + COMMAND_REGISTRATION_DONE +}; + +extern __COMMAND_HANDLER(handle_common_semihosting_command); +extern __COMMAND_HANDLER(handle_common_semihosting_fileio_command); +extern __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command); +extern __COMMAND_HANDLER(handle_common_semihosting_cmdline); + +/* + * To be noted that RISC-V targets use the same semihosting commands as + * ARM targets. + * + * The main reason is compatibility with existing tools. For example the + * Eclipse OpenOCD/SEGGER J-Link/QEMU plug-ins have several widgets to + * configure semihosting, which generate commands like `arm semihosting + * enable`. + * A secondary reason is the fact that the protocol used is exactly the + * one specified by ARM. If RISC-V will ever define its own semihosting + * protocol, then a command like `riscv semihosting enable` will make + * sense, but for now all semihosting commands are prefixed with `arm`. + */ +static const struct command_registration arm_exec_command_handlers[] = { + { + "semihosting", + .handler = handle_common_semihosting_command, + .mode = COMMAND_EXEC, + .usage = "['enable'|'disable']", + .help = "activate support for semihosting operations", + }, + { + "semihosting_cmdline", + .handler = handle_common_semihosting_cmdline, + .mode = COMMAND_EXEC, + .usage = "arguments", + .help = "command line arguments to be passed to program", + }, + { + "semihosting_fileio", + .handler = handle_common_semihosting_fileio_command, + .mode = COMMAND_EXEC, + .usage = "['enable'|'disable']", + .help = "activate support for semihosting fileio operations", + }, + { + "semihosting_resexit", + .handler = handle_common_semihosting_resumable_exit_command, + .mode = COMMAND_EXEC, + .usage = "['enable'|'disable']", + .help = "activate support for semihosting resumable exit", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration riscv_command_handlers[] = { + { + .name = "riscv", + .mode = COMMAND_ANY, + .help = "RISC-V Command Group", + .usage = "", + .chain = riscv_exec_command_handlers + }, + { + .name = "arm", + .mode = COMMAND_ANY, + .help = "ARM Command Group", + .usage = "", + .chain = arm_exec_command_handlers + }, + COMMAND_REGISTRATION_DONE +}; + +struct target_type riscv_target = { + .name = "riscv", + + .init_target = riscv_init_target, + .deinit_target = riscv_deinit_target, + .examine = riscv_examine, + + /* poll current target status */ + .poll = old_or_new_riscv_poll, + + .halt = old_or_new_riscv_halt, + .resume = old_or_new_riscv_resume, + .step = old_or_new_riscv_step, + + .assert_reset = riscv_assert_reset, + .deassert_reset = riscv_deassert_reset, + + .read_memory = riscv_read_memory, + .write_memory = riscv_write_memory, + + .checksum_memory = riscv_checksum_memory, + + .get_gdb_reg_list = riscv_get_gdb_reg_list, + + .add_breakpoint = riscv_add_breakpoint, + .remove_breakpoint = riscv_remove_breakpoint, + + .add_watchpoint = riscv_add_watchpoint, + .remove_watchpoint = riscv_remove_watchpoint, + + .arch_state = riscv_arch_state, + + .run_algorithm = riscv_run_algorithm, + + .commands = riscv_command_handlers +}; + +/*** RISC-V Interface ***/ + +void riscv_info_init(struct target *target, riscv_info_t *r) +{ + memset(r, 0, sizeof(*r)); + r->dtm_version = 1; + r->registers_initialized = false; + r->current_hartid = target->coreid; + + memset(r->trigger_unique_id, 0xff, sizeof(r->trigger_unique_id)); + + for (size_t h = 0; h < RISCV_MAX_HARTS; ++h) { + r->xlen[h] = -1; + + for (size_t e = 0; e < RISCV_MAX_REGISTERS; ++e) + r->valid_saved_registers[h][e] = false; + } +} + +int riscv_halt_all_harts(struct target *target) +{ + for (int i = 0; i < riscv_count_harts(target); ++i) { + if (!riscv_hart_enabled(target, i)) + continue; + + riscv_halt_one_hart(target, i); + } + + return ERROR_OK; +} + +int riscv_halt_one_hart(struct target *target, int hartid) +{ + RISCV_INFO(r); + LOG_DEBUG("halting hart %d", hartid); + if (riscv_set_current_hartid(target, hartid) != ERROR_OK) + return ERROR_FAIL; + if (riscv_is_halted(target)) { + LOG_DEBUG(" hart %d requested halt, but was already halted", hartid); + return ERROR_OK; + } + + return r->halt_current_hart(target); +} + +int riscv_resume_all_harts(struct target *target) +{ + for (int i = 0; i < riscv_count_harts(target); ++i) { + if (!riscv_hart_enabled(target, i)) + continue; + + riscv_resume_one_hart(target, i); + } + + riscv_invalidate_register_cache(target); + return ERROR_OK; +} + +int riscv_resume_one_hart(struct target *target, int hartid) +{ + RISCV_INFO(r); + LOG_DEBUG("resuming hart %d", hartid); + if (riscv_set_current_hartid(target, hartid) != ERROR_OK) + return ERROR_FAIL; + if (!riscv_is_halted(target)) { + LOG_DEBUG(" hart %d requested resume, but was already resumed", hartid); + return ERROR_OK; + } + + r->on_resume(target); + return r->resume_current_hart(target); +} + +int riscv_step_rtos_hart(struct target *target) +{ + RISCV_INFO(r); + int hartid = r->current_hartid; + if (riscv_rtos_enabled(target)) { + hartid = r->rtos_hartid; + if (hartid == -1) { + LOG_USER("GDB has asked me to step \"any\" thread, so I'm stepping hart 0."); + hartid = 0; + } + } + if (riscv_set_current_hartid(target, hartid) != ERROR_OK) + return ERROR_FAIL; + LOG_DEBUG("stepping hart %d", hartid); + + if (!riscv_is_halted(target)) { + LOG_ERROR("Hart isn't halted before single step!"); + return ERROR_FAIL; + } + riscv_invalidate_register_cache(target); + r->on_step(target); + if (r->step_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + riscv_invalidate_register_cache(target); + r->on_halt(target); + if (!riscv_is_halted(target)) { + LOG_ERROR("Hart was not halted after single step!"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +bool riscv_supports_extension(struct target *target, int hartid, char letter) +{ + RISCV_INFO(r); + unsigned num; + if (letter >= 'a' && letter <= 'z') + num = letter - 'a'; + else if (letter >= 'A' && letter <= 'Z') + num = letter - 'A'; + else + return false; + return r->misa[hartid] & (1 << num); +} + +int riscv_xlen(const struct target *target) +{ + return riscv_xlen_of_hart(target, riscv_current_hartid(target)); +} + +int riscv_xlen_of_hart(const struct target *target, int hartid) +{ + RISCV_INFO(r); + assert(r->xlen[hartid] != -1); + return r->xlen[hartid]; +} + +bool riscv_rtos_enabled(const struct target *target) +{ + return target->rtos != NULL; +} + +int riscv_set_current_hartid(struct target *target, int hartid) +{ + RISCV_INFO(r); + if (!r->select_current_hart) + return ERROR_OK; + + int previous_hartid = riscv_current_hartid(target); + r->current_hartid = hartid; + assert(riscv_hart_enabled(target, hartid)); + LOG_DEBUG("setting hartid to %d, was %d", hartid, previous_hartid); + if (r->select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + + /* This might get called during init, in which case we shouldn't be + * setting up the register cache. */ + if (!target_was_examined(target)) + return ERROR_OK; + + /* Avoid invalidating the register cache all the time. */ + if (r->registers_initialized + && (!riscv_rtos_enabled(target) || (previous_hartid == hartid)) + && target->reg_cache->reg_list[GDB_REGNO_ZERO].size == (unsigned)riscv_xlen(target) + && (!riscv_rtos_enabled(target) || (r->rtos_hartid != -1))) { + return ERROR_OK; + } else + LOG_DEBUG("Initializing registers: xlen=%d", riscv_xlen(target)); + + riscv_invalidate_register_cache(target); + return ERROR_OK; +} + +void riscv_invalidate_register_cache(struct target *target) +{ + RISCV_INFO(r); + + register_cache_invalidate(target->reg_cache); + for (size_t i = 0; i < GDB_REGNO_COUNT; ++i) { + struct reg *reg = &target->reg_cache->reg_list[i]; + reg->valid = false; + } + + r->registers_initialized = true; +} + +int riscv_current_hartid(const struct target *target) +{ + RISCV_INFO(r); + return r->current_hartid; +} + +void riscv_set_all_rtos_harts(struct target *target) +{ + RISCV_INFO(r); + r->rtos_hartid = -1; +} + +void riscv_set_rtos_hartid(struct target *target, int hartid) +{ + LOG_DEBUG("setting RTOS hartid %d", hartid); + RISCV_INFO(r); + r->rtos_hartid = hartid; +} + +int riscv_count_harts(struct target *target) +{ + if (target == NULL) + return 1; + RISCV_INFO(r); + if (r == NULL) + return 1; + return r->hart_count; +} + +bool riscv_has_register(struct target *target, int hartid, int regid) +{ + return 1; +} + +/** + * This function is called when the debug user wants to change the value of a + * register. The new value may be cached, and may not be written until the hart + * is resumed. */ +int riscv_set_register(struct target *target, enum gdb_regno r, riscv_reg_t v) +{ + return riscv_set_register_on_hart(target, riscv_current_hartid(target), r, v); +} + +int riscv_set_register_on_hart(struct target *target, int hartid, + enum gdb_regno regid, uint64_t value) +{ + RISCV_INFO(r); + LOG_DEBUG("[%d] %s <- %" PRIx64, hartid, gdb_regno_name(regid), value); + assert(r->set_register); + return r->set_register(target, hartid, regid, value); +} + +int riscv_get_register(struct target *target, riscv_reg_t *value, + enum gdb_regno r) +{ + return riscv_get_register_on_hart(target, value, + riscv_current_hartid(target), r); +} + +int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value, + int hartid, enum gdb_regno regid) +{ + RISCV_INFO(r); + int result = r->get_register(target, value, hartid, regid); + LOG_DEBUG("[%d] %s: %" PRIx64, hartid, gdb_regno_name(regid), *value); + return result; +} + +bool riscv_is_halted(struct target *target) +{ + RISCV_INFO(r); + assert(r->is_halted); + return r->is_halted(target); +} + +enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid) +{ + RISCV_INFO(r); + if (riscv_set_current_hartid(target, hartid) != ERROR_OK) + return RISCV_HALT_ERROR; + if (!riscv_is_halted(target)) { + LOG_ERROR("Hart is not halted!"); + return RISCV_HALT_UNKNOWN; + } + return r->halt_reason(target); +} + +size_t riscv_debug_buffer_size(struct target *target) +{ + RISCV_INFO(r); + return r->debug_buffer_size[riscv_current_hartid(target)]; +} + +int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn) +{ + RISCV_INFO(r); + r->write_debug_buffer(target, index, insn); + return ERROR_OK; +} + +riscv_insn_t riscv_read_debug_buffer(struct target *target, int index) +{ + RISCV_INFO(r); + return r->read_debug_buffer(target, index); +} + +int riscv_execute_debug_buffer(struct target *target) +{ + RISCV_INFO(r); + return r->execute_debug_buffer(target); +} + +void riscv_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d) +{ + RISCV_INFO(r); + r->fill_dmi_write_u64(target, buf, a, d); +} + +void riscv_fill_dmi_read_u64(struct target *target, char *buf, int a) +{ + RISCV_INFO(r); + r->fill_dmi_read_u64(target, buf, a); +} + +void riscv_fill_dmi_nop_u64(struct target *target, char *buf) +{ + RISCV_INFO(r); + r->fill_dmi_nop_u64(target, buf); +} + +int riscv_dmi_write_u64_bits(struct target *target) +{ + RISCV_INFO(r); + return r->dmi_write_u64_bits(target); +} + +bool riscv_hart_enabled(struct target *target, int hartid) +{ + /* FIXME: Add a hart mask to the RTOS. */ + if (riscv_rtos_enabled(target)) + return hartid < riscv_count_harts(target); + + return hartid == target->coreid; +} + +/** + * Count triggers, and initialize trigger_count for each hart. + * trigger_count is initialized even if this function fails to discover + * something. + * Disable any hardware triggers that have dmode set. We can't have set them + * ourselves. Maybe they're left over from some killed debug session. + * */ +int riscv_enumerate_triggers(struct target *target) +{ + RISCV_INFO(r); + + if (r->triggers_enumerated) + return ERROR_OK; + + r->triggers_enumerated = true; /* At the very least we tried. */ + + for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) { + if (!riscv_hart_enabled(target, hartid)) + continue; + + riscv_reg_t tselect; + int result = riscv_get_register_on_hart(target, &tselect, hartid, + GDB_REGNO_TSELECT); + if (result != ERROR_OK) + return result; + + for (unsigned t = 0; t < RISCV_MAX_TRIGGERS; ++t) { + r->trigger_count[hartid] = t; + + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, t); + uint64_t tselect_rb; + result = riscv_get_register_on_hart(target, &tselect_rb, hartid, + GDB_REGNO_TSELECT); + if (result != ERROR_OK) + return result; + /* Mask off the top bit, which is used as tdrmode in old + * implementations. */ + tselect_rb &= ~(1ULL << (riscv_xlen(target)-1)); + if (tselect_rb != t) + break; + uint64_t tdata1; + result = riscv_get_register_on_hart(target, &tdata1, hartid, + GDB_REGNO_TDATA1); + if (result != ERROR_OK) + return result; + + int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); + switch (type) { + case 1: + /* On these older cores we don't support software using + * triggers. */ + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0); + break; + case 2: + if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0); + break; + } + } + + riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, tselect); + + LOG_INFO("[%d] Found %d triggers", hartid, r->trigger_count[hartid]); + } + + return ERROR_OK; +} + +const char *gdb_regno_name(enum gdb_regno regno) +{ + static char buf[32]; + + switch (regno) { + case GDB_REGNO_ZERO: + return "zero"; + case GDB_REGNO_S0: + return "s0"; + case GDB_REGNO_S1: + return "s1"; + case GDB_REGNO_PC: + return "pc"; + case GDB_REGNO_FPR0: + return "fpr0"; + case GDB_REGNO_FPR31: + return "fpr31"; + case GDB_REGNO_CSR0: + return "csr0"; + case GDB_REGNO_TSELECT: + return "tselect"; + case GDB_REGNO_TDATA1: + return "tdata1"; + case GDB_REGNO_TDATA2: + return "tdata2"; + case GDB_REGNO_MISA: + return "misa"; + case GDB_REGNO_DPC: + return "dpc"; + case GDB_REGNO_DCSR: + return "dcsr"; + case GDB_REGNO_DSCRATCH: + return "dscratch"; + case GDB_REGNO_MSTATUS: + return "mstatus"; + case GDB_REGNO_PRIV: + return "priv"; + default: + if (regno <= GDB_REGNO_XPR31) + sprintf(buf, "x%d", regno - GDB_REGNO_ZERO); + else if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) + sprintf(buf, "csr%d", regno - GDB_REGNO_CSR0); + else if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) + sprintf(buf, "f%d", regno - GDB_REGNO_FPR0); + else + sprintf(buf, "gdb_regno_%d", regno); + return buf; + } +} + +static int register_get(struct reg *reg) +{ + struct target *target = (struct target *) reg->arch_info; + uint64_t value; + int result = riscv_get_register(target, &value, reg->number); + if (result != ERROR_OK) + return result; + buf_set_u64(reg->value, 0, reg->size, value); + return ERROR_OK; +} + +static int register_set(struct reg *reg, uint8_t *buf) +{ + struct target *target = (struct target *) reg->arch_info; + + uint64_t value = buf_get_u64(buf, 0, reg->size); + + LOG_DEBUG("write 0x%" PRIx64 " to %s", value, reg->name); + struct reg *r = &target->reg_cache->reg_list[reg->number]; + r->valid = true; + memcpy(r->value, buf, (r->size + 7) / 8); + + riscv_set_register(target, reg->number, value); + return ERROR_OK; +} + +static struct reg_arch_type riscv_reg_arch_type = { + .get = register_get, + .set = register_set +}; + +struct csr_info { + unsigned number; + const char *name; +}; + +static int cmp_csr_info(const void *p1, const void *p2) +{ + return (int) (((struct csr_info *)p1)->number) - (int) (((struct csr_info *)p2)->number); +} + +int riscv_init_registers(struct target *target) +{ + RISCV_INFO(info); + + if (target->reg_cache) { + if (target->reg_cache->reg_list) + free(target->reg_cache->reg_list); + free(target->reg_cache); + } + + target->reg_cache = calloc(1, sizeof(*target->reg_cache)); + target->reg_cache->name = "RISC-V Registers"; + target->reg_cache->num_regs = GDB_REGNO_COUNT; + + target->reg_cache->reg_list = calloc(GDB_REGNO_COUNT, sizeof(struct reg)); + + const unsigned int max_reg_name_len = 12; + if (info->reg_names) + free(info->reg_names); + info->reg_names = calloc(1, GDB_REGNO_COUNT * max_reg_name_len); + char *reg_name = info->reg_names; + + static struct reg_feature feature_cpu = { + .name = "org.gnu.gdb.riscv.cpu" + }; + static struct reg_feature feature_fpu = { + .name = "org.gnu.gdb.riscv.fpu" + }; + static struct reg_feature feature_csr = { + .name = "org.gnu.gdb.riscv.csr" + }; + static struct reg_feature feature_virtual = { + .name = "org.gnu.gdb.riscv.virtual" + }; + + static struct reg_data_type type_ieee_single = { + .type = REG_TYPE_IEEE_SINGLE, + .id = "ieee_single" + }; + static struct reg_data_type type_ieee_double = { + .type = REG_TYPE_IEEE_DOUBLE, + .id = "ieee_double" + }; + struct csr_info csr_info[] = { +#define DECLARE_CSR(name, number) { number, #name }, +#include "encoding.h" +#undef DECLARE_CSR + }; + /* encoding.h does not contain the registers in sorted order. */ + qsort(csr_info, DIM(csr_info), sizeof(*csr_info), cmp_csr_info); + unsigned csr_info_index = 0; + + /* When gdb request register N, gdb_get_register_packet() assumes that this + * is register at index N in reg_list. So if there are certain registers + * that don't exist, we need to leave holes in the list (or renumber, but + * it would be nice not to have yet another set of numbers to translate + * between). */ + for (uint32_t number = 0; number < GDB_REGNO_COUNT; number++) { + struct reg *r = &target->reg_cache->reg_list[number]; + r->dirty = false; + r->valid = false; + r->exist = true; + r->type = &riscv_reg_arch_type; + r->arch_info = target; + r->number = number; + r->size = riscv_xlen(target); + /* r->size is set in riscv_invalidate_register_cache, maybe because the + * target is in theory allowed to change XLEN on us. But I expect a lot + * of other things to break in that case as well. */ + if (number <= GDB_REGNO_XPR31) { + r->caller_save = true; + switch (number) { + case GDB_REGNO_ZERO: + r->name = "zero"; + break; + case GDB_REGNO_RA: + r->name = "ra"; + break; + case GDB_REGNO_SP: + r->name = "sp"; + break; + case GDB_REGNO_GP: + r->name = "gp"; + break; + case GDB_REGNO_TP: + r->name = "tp"; + break; + case GDB_REGNO_T0: + r->name = "t0"; + break; + case GDB_REGNO_T1: + r->name = "t1"; + break; + case GDB_REGNO_T2: + r->name = "t2"; + break; + case GDB_REGNO_FP: + r->name = "fp"; + break; + case GDB_REGNO_S1: + r->name = "s1"; + break; + case GDB_REGNO_A0: + r->name = "a0"; + break; + case GDB_REGNO_A1: + r->name = "a1"; + break; + case GDB_REGNO_A2: + r->name = "a2"; + break; + case GDB_REGNO_A3: + r->name = "a3"; + break; + case GDB_REGNO_A4: + r->name = "a4"; + break; + case GDB_REGNO_A5: + r->name = "a5"; + break; + case GDB_REGNO_A6: + r->name = "a6"; + break; + case GDB_REGNO_A7: + r->name = "a7"; + break; + case GDB_REGNO_S2: + r->name = "s2"; + break; + case GDB_REGNO_S3: + r->name = "s3"; + break; + case GDB_REGNO_S4: + r->name = "s4"; + break; + case GDB_REGNO_S5: + r->name = "s5"; + break; + case GDB_REGNO_S6: + r->name = "s6"; + break; + case GDB_REGNO_S7: + r->name = "s7"; + break; + case GDB_REGNO_S8: + r->name = "s8"; + break; + case GDB_REGNO_S9: + r->name = "s9"; + break; + case GDB_REGNO_S10: + r->name = "s10"; + break; + case GDB_REGNO_S11: + r->name = "s11"; + break; + case GDB_REGNO_T3: + r->name = "t3"; + break; + case GDB_REGNO_T4: + r->name = "t4"; + break; + case GDB_REGNO_T5: + r->name = "t5"; + break; + case GDB_REGNO_T6: + r->name = "t6"; + break; + } + r->group = "general"; + r->feature = &feature_cpu; + } else if (number == GDB_REGNO_PC) { + r->caller_save = true; + sprintf(reg_name, "pc"); + r->group = "general"; + r->feature = &feature_cpu; + } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + r->caller_save = true; + if (riscv_supports_extension(target, riscv_current_hartid(target), + 'D')) { + r->reg_data_type = &type_ieee_double; + r->size = 64; + } else if (riscv_supports_extension(target, + riscv_current_hartid(target), 'F')) { + r->reg_data_type = &type_ieee_single; + r->size = 32; + } else { + r->exist = false; + } + switch (number) { + case GDB_REGNO_FT0: + r->name = "ft0"; + break; + case GDB_REGNO_FT1: + r->name = "ft1"; + break; + case GDB_REGNO_FT2: + r->name = "ft2"; + break; + case GDB_REGNO_FT3: + r->name = "ft3"; + break; + case GDB_REGNO_FT4: + r->name = "ft4"; + break; + case GDB_REGNO_FT5: + r->name = "ft5"; + break; + case GDB_REGNO_FT6: + r->name = "ft6"; + break; + case GDB_REGNO_FT7: + r->name = "ft7"; + break; + case GDB_REGNO_FS0: + r->name = "fs0"; + break; + case GDB_REGNO_FS1: + r->name = "fs1"; + break; + case GDB_REGNO_FA0: + r->name = "fa0"; + break; + case GDB_REGNO_FA1: + r->name = "fa1"; + break; + case GDB_REGNO_FA2: + r->name = "fa2"; + break; + case GDB_REGNO_FA3: + r->name = "fa3"; + break; + case GDB_REGNO_FA4: + r->name = "fa4"; + break; + case GDB_REGNO_FA5: + r->name = "fa5"; + break; + case GDB_REGNO_FA6: + r->name = "fa6"; + break; + case GDB_REGNO_FA7: + r->name = "fa7"; + break; + case GDB_REGNO_FS2: + r->name = "fs2"; + break; + case GDB_REGNO_FS3: + r->name = "fs3"; + break; + case GDB_REGNO_FS4: + r->name = "fs4"; + break; + case GDB_REGNO_FS5: + r->name = "fs5"; + break; + case GDB_REGNO_FS6: + r->name = "fs6"; + break; + case GDB_REGNO_FS7: + r->name = "fs7"; + break; + case GDB_REGNO_FS8: + r->name = "fs8"; + break; + case GDB_REGNO_FS9: + r->name = "fs9"; + break; + case GDB_REGNO_FS10: + r->name = "fs10"; + break; + case GDB_REGNO_FS11: + r->name = "fs11"; + break; + case GDB_REGNO_FT8: + r->name = "ft8"; + break; + case GDB_REGNO_FT9: + r->name = "ft9"; + break; + case GDB_REGNO_FT10: + r->name = "ft10"; + break; + case GDB_REGNO_FT11: + r->name = "ft11"; + break; + } + r->group = "float"; + r->feature = &feature_fpu; + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + r->group = "csr"; + r->feature = &feature_csr; + unsigned csr_number = number - GDB_REGNO_CSR0; + + while (csr_info[csr_info_index].number < csr_number && + csr_info_index < DIM(csr_info) - 1) { + csr_info_index++; + } + if (csr_info[csr_info_index].number == csr_number) { + r->name = csr_info[csr_info_index].name; + } else { + sprintf(reg_name, "csr%d", csr_number); + /* Assume unnamed registers don't exist, unless we have some + * configuration that tells us otherwise. That's important + * because eg. Eclipse crashes if a target has too many + * registers, and apparently has no way of only showing a + * subset of registers in any case. */ + r->exist = false; + } + + switch (csr_number) { + case CSR_FFLAGS: + case CSR_FRM: + case CSR_FCSR: + r->exist = riscv_supports_extension(target, + riscv_current_hartid(target), 'F'); + r->group = "float"; + r->feature = &feature_fpu; + break; + case CSR_SSTATUS: + case CSR_STVEC: + case CSR_SIP: + case CSR_SIE: + case CSR_SCOUNTEREN: + case CSR_SSCRATCH: + case CSR_SEPC: + case CSR_SCAUSE: + case CSR_STVAL: + case CSR_SATP: + r->exist = riscv_supports_extension(target, + riscv_current_hartid(target), 'S'); + break; + case CSR_MEDELEG: + case CSR_MIDELEG: + /* "In systems with only M-mode, or with both M-mode and + * U-mode but without U-mode trap support, the medeleg and + * mideleg registers should not exist." */ + r->exist = riscv_supports_extension(target, riscv_current_hartid(target), 'S') || + riscv_supports_extension(target, riscv_current_hartid(target), 'N'); + break; + + case CSR_CYCLEH: + case CSR_TIMEH: + case CSR_INSTRETH: + case CSR_HPMCOUNTER3H: + case CSR_HPMCOUNTER4H: + case CSR_HPMCOUNTER5H: + case CSR_HPMCOUNTER6H: + case CSR_HPMCOUNTER7H: + case CSR_HPMCOUNTER8H: + case CSR_HPMCOUNTER9H: + case CSR_HPMCOUNTER10H: + case CSR_HPMCOUNTER11H: + case CSR_HPMCOUNTER12H: + case CSR_HPMCOUNTER13H: + case CSR_HPMCOUNTER14H: + case CSR_HPMCOUNTER15H: + case CSR_HPMCOUNTER16H: + case CSR_HPMCOUNTER17H: + case CSR_HPMCOUNTER18H: + case CSR_HPMCOUNTER19H: + case CSR_HPMCOUNTER20H: + case CSR_HPMCOUNTER21H: + case CSR_HPMCOUNTER22H: + case CSR_HPMCOUNTER23H: + case CSR_HPMCOUNTER24H: + case CSR_HPMCOUNTER25H: + case CSR_HPMCOUNTER26H: + case CSR_HPMCOUNTER27H: + case CSR_HPMCOUNTER28H: + case CSR_HPMCOUNTER29H: + case CSR_HPMCOUNTER30H: + case CSR_HPMCOUNTER31H: + case CSR_MCYCLEH: + case CSR_MINSTRETH: + case CSR_MHPMCOUNTER3H: + case CSR_MHPMCOUNTER4H: + case CSR_MHPMCOUNTER5H: + case CSR_MHPMCOUNTER6H: + case CSR_MHPMCOUNTER7H: + case CSR_MHPMCOUNTER8H: + case CSR_MHPMCOUNTER9H: + case CSR_MHPMCOUNTER10H: + case CSR_MHPMCOUNTER11H: + case CSR_MHPMCOUNTER12H: + case CSR_MHPMCOUNTER13H: + case CSR_MHPMCOUNTER14H: + case CSR_MHPMCOUNTER15H: + case CSR_MHPMCOUNTER16H: + case CSR_MHPMCOUNTER17H: + case CSR_MHPMCOUNTER18H: + case CSR_MHPMCOUNTER19H: + case CSR_MHPMCOUNTER20H: + case CSR_MHPMCOUNTER21H: + case CSR_MHPMCOUNTER22H: + case CSR_MHPMCOUNTER23H: + case CSR_MHPMCOUNTER24H: + case CSR_MHPMCOUNTER25H: + case CSR_MHPMCOUNTER26H: + case CSR_MHPMCOUNTER27H: + case CSR_MHPMCOUNTER28H: + case CSR_MHPMCOUNTER29H: + case CSR_MHPMCOUNTER30H: + case CSR_MHPMCOUNTER31H: + r->exist = riscv_xlen(target) == 32; + break; + } + + if (!r->exist && expose_csr) { + for (unsigned i = 0; expose_csr[i].low <= expose_csr[i].high; i++) { + if (csr_number >= expose_csr[i].low && csr_number <= expose_csr[i].high) { + LOG_INFO("Exposing additional CSR %d", csr_number); + r->exist = true; + break; + } + } + } + + } else if (number == GDB_REGNO_PRIV) { + sprintf(reg_name, "priv"); + r->group = "general"; + r->feature = &feature_virtual; + r->size = 8; + } + if (reg_name[0]) + r->name = reg_name; + reg_name += strlen(reg_name) + 1; + assert(reg_name < info->reg_names + GDB_REGNO_COUNT * max_reg_name_len); + r->value = &info->reg_cache_values[number]; + } + + return ERROR_OK; +} diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h new file mode 100644 index 000000000..31f3cf63c --- /dev/null +++ b/src/target/riscv/riscv.h @@ -0,0 +1,262 @@ +#ifndef RISCV_H +#define RISCV_H + +struct riscv_program; + +#include +#include "opcodes.h" +#include "gdb_regs.h" + +/* The register cache is statically allocated. */ +#define RISCV_MAX_HARTS 32 +#define RISCV_MAX_REGISTERS 5000 +#define RISCV_MAX_TRIGGERS 32 +#define RISCV_MAX_HWBPS 16 + +#define DEFAULT_COMMAND_TIMEOUT_SEC 2 +#define DEFAULT_RESET_TIMEOUT_SEC 30 + +extern struct target_type riscv011_target; +extern struct target_type riscv013_target; + +/* + * Definitions shared by code supporting all RISC-V versions. + */ +typedef uint64_t riscv_reg_t; +typedef uint32_t riscv_insn_t; +typedef uint64_t riscv_addr_t; + +enum riscv_halt_reason { + RISCV_HALT_INTERRUPT, + RISCV_HALT_BREAKPOINT, + RISCV_HALT_SINGLESTEP, + RISCV_HALT_TRIGGER, + RISCV_HALT_UNKNOWN, + RISCV_HALT_ERROR +}; + +typedef struct { + unsigned dtm_version; + + struct command_context *cmd_ctx; + void *version_specific; + + /* The number of harts on this system. */ + int hart_count; + + /* The hart that the RTOS thinks is currently being debugged. */ + int rtos_hartid; + + /* The hart that is currently being debugged. Note that this is + * different than the hartid that the RTOS is expected to use. This + * one will change all the time, it's more of a global argument to + * every function than an actual */ + int current_hartid; + + /* Enough space to store all the registers we might need to save. */ + /* FIXME: This should probably be a bunch of register caches. */ + uint64_t saved_registers[RISCV_MAX_HARTS][RISCV_MAX_REGISTERS]; + bool valid_saved_registers[RISCV_MAX_HARTS][RISCV_MAX_REGISTERS]; + + /* OpenOCD's register cache points into here. This is not per-hart because + * we just invalidate the entire cache when we change which hart is + * selected. */ + uint64_t reg_cache_values[RISCV_MAX_REGISTERS]; + + /* Single buffer that contains all register names, instead of calling + * malloc for each register. Needs to be freed when reg_list is freed. */ + char *reg_names; + + /* It's possible that each core has a different supported ISA set. */ + int xlen[RISCV_MAX_HARTS]; + riscv_reg_t misa[RISCV_MAX_HARTS]; + + /* The number of triggers per hart. */ + unsigned trigger_count[RISCV_MAX_HARTS]; + + /* For each physical trigger, contains -1 if the hwbp is available, or the + * unique_id of the breakpoint/watchpoint that is using it. + * Note that in RTOS mode the triggers are the same across all harts the + * target controls, while otherwise only a single hart is controlled. */ + int trigger_unique_id[RISCV_MAX_HWBPS]; + + /* The number of entries in the debug buffer. */ + int debug_buffer_size[RISCV_MAX_HARTS]; + + /* This avoids invalidating the register cache too often. */ + bool registers_initialized; + + /* This hart contains an implicit ebreak at the end of the program buffer. */ + bool impebreak; + + bool triggers_enumerated; + + /* Helper functions that target the various RISC-V debug spec + * implementations. */ + int (*get_register)(struct target *target, + riscv_reg_t *value, int hid, int rid); + int (*set_register)(struct target *, int hartid, int regid, + uint64_t value); + int (*select_current_hart)(struct target *); + bool (*is_halted)(struct target *target); + int (*halt_current_hart)(struct target *); + int (*resume_current_hart)(struct target *target); + int (*step_current_hart)(struct target *target); + int (*on_halt)(struct target *target); + int (*on_resume)(struct target *target); + int (*on_step)(struct target *target); + enum riscv_halt_reason (*halt_reason)(struct target *target); + int (*write_debug_buffer)(struct target *target, unsigned index, + riscv_insn_t d); + riscv_insn_t (*read_debug_buffer)(struct target *target, unsigned index); + int (*execute_debug_buffer)(struct target *target); + int (*dmi_write_u64_bits)(struct target *target); + void (*fill_dmi_write_u64)(struct target *target, char *buf, int a, uint64_t d); + void (*fill_dmi_read_u64)(struct target *target, char *buf, int a); + void (*fill_dmi_nop_u64)(struct target *target, char *buf); + + int (*authdata_read)(struct target *target, uint32_t *value); + int (*authdata_write)(struct target *target, uint32_t value); + + int (*dmi_read)(struct target *target, uint32_t *value, uint32_t address); + int (*dmi_write)(struct target *target, uint32_t address, uint32_t value); +} riscv_info_t; + +/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ +extern int riscv_command_timeout_sec; + +/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ +extern int riscv_reset_timeout_sec; + +extern bool riscv_prefer_sba; + +/* Everything needs the RISC-V specific info structure, so here's a nice macro + * that provides that. */ +static inline riscv_info_t *riscv_info(const struct target *target) __attribute__((unused)); +static inline riscv_info_t *riscv_info(const struct target *target) +{ return target->arch_info; } +#define RISCV_INFO(R) riscv_info_t *R = riscv_info(target); + +extern uint8_t ir_dtmcontrol[1]; +extern struct scan_field select_dtmcontrol; +extern uint8_t ir_dbus[1]; +extern struct scan_field select_dbus; +extern uint8_t ir_idcode[1]; +extern struct scan_field select_idcode; + +/*** OpenOCD Interface */ +int riscv_openocd_poll(struct target *target); + +int riscv_openocd_halt(struct target *target); + +int riscv_openocd_resume( + struct target *target, + int current, + target_addr_t address, + int handle_breakpoints, + int debug_execution +); + +int riscv_openocd_step( + struct target *target, + int current, + target_addr_t address, + int handle_breakpoints +); + +int riscv_openocd_assert_reset(struct target *target); +int riscv_openocd_deassert_reset(struct target *target); + +/*** RISC-V Interface ***/ + +/* Initializes the shared RISC-V structure. */ +void riscv_info_init(struct target *target, riscv_info_t *r); + +/* Run control, possibly for multiple harts. The _all_harts versions resume + * all the enabled harts, which when running in RTOS mode is all the harts on + * the system. */ +int riscv_halt_all_harts(struct target *target); +int riscv_halt_one_hart(struct target *target, int hartid); +int riscv_resume_all_harts(struct target *target); +int riscv_resume_one_hart(struct target *target, int hartid); + +/* Steps the hart that's currently selected in the RTOS, or if there is no RTOS + * then the only hart. */ +int riscv_step_rtos_hart(struct target *target); + +bool riscv_supports_extension(struct target *target, int hartid, char letter); + +/* Returns XLEN for the given (or current) hart. */ +int riscv_xlen(const struct target *target); +int riscv_xlen_of_hart(const struct target *target, int hartid); + +bool riscv_rtos_enabled(const struct target *target); + +/* Sets the current hart, which is the hart that will actually be used when + * issuing debug commands. */ +int riscv_set_current_hartid(struct target *target, int hartid); +int riscv_current_hartid(const struct target *target); + +/*** Support functions for the RISC-V 'RTOS', which provides multihart support + * without requiring multiple targets. */ + +/* When using the RTOS to debug, this selects the hart that is currently being + * debugged. This doesn't propogate to the hardware. */ +void riscv_set_all_rtos_harts(struct target *target); +void riscv_set_rtos_hartid(struct target *target, int hartid); + +/* Lists the number of harts in the system, which are assumed to be + * concecutive and start with mhartid=0. */ +int riscv_count_harts(struct target *target); + +/* Returns TRUE if the target has the given register on the given hart. */ +bool riscv_has_register(struct target *target, int hartid, int regid); + +/* Returns the value of the given register on the given hart. 32-bit registers + * are zero extended to 64 bits. */ +int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v); +int riscv_set_register_on_hart(struct target *target, int hid, enum gdb_regno rid, uint64_t v); +int riscv_get_register(struct target *target, riscv_reg_t *value, + enum gdb_regno r); +int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value, + int hartid, enum gdb_regno regid); + +/* Checks the state of the current hart -- "is_halted" checks the actual + * on-device register. */ +bool riscv_is_halted(struct target *target); +enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid); + +/* These helper functions let the generic program interface get target-specific + * information. */ +size_t riscv_debug_buffer_size(struct target *target); + +riscv_insn_t riscv_read_debug_buffer(struct target *target, int index); +int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn); +int riscv_execute_debug_buffer(struct target *target); + +void riscv_fill_dmi_nop_u64(struct target *target, char *buf); +void riscv_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d); +void riscv_fill_dmi_read_u64(struct target *target, char *buf, int a); +int riscv_dmi_write_u64_bits(struct target *target); + +/* Invalidates the register cache. */ +void riscv_invalidate_register_cache(struct target *target); + +/* Returns TRUE when a hart is enabled in this target. */ +bool riscv_hart_enabled(struct target *target, int hartid); + +int riscv_enumerate_triggers(struct target *target); + +int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint); +int riscv_remove_breakpoint(struct target *target, + struct breakpoint *breakpoint); +int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint); +int riscv_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint); + +int riscv_init_registers(struct target *target); + +void riscv_semihosting_init(struct target *target); +int riscv_semihosting(struct target *target, int *retval); + +#endif diff --git a/src/target/riscv/riscv_semihosting.c b/src/target/riscv/riscv_semihosting.c new file mode 100644 index 000000000..c4b665372 --- /dev/null +++ b/src/target/riscv/riscv_semihosting.c @@ -0,0 +1,194 @@ +/*************************************************************************** + * Copyright (C) 2018 by Liviu Ionescu * + * ilg@livius.net * + * * + * Copyright (C) 2009 by Marvell Technology Group Ltd. * + * Written by Nicolas Pitre * + * * + * Copyright (C) 2010 by Spencer Oliver * + * spen@spen-soft.co.uk * + * * + * Copyright (C) 2016 by Square, Inc. * + * Steven Stallion * + * * + * 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 . * + ***************************************************************************/ + +/** + * @file + * Hold RISC-V semihosting support. + * + * The RISC-V code is inspired from ARM semihosting. + * + * Details can be found in chapter 8 of DUI0203I_rvct_developer_guide.pdf + * from ARM Ltd. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "log.h" + +#include "target/target.h" +#include "target/semihosting_common.h" +#include "riscv.h" + +static int riscv_semihosting_setup(struct target *target, int enable); +static int riscv_semihosting_post_result(struct target *target); + +/** + * Initialize RISC-V semihosting. Use common ARM code. + */ +void riscv_semihosting_init(struct target *target) +{ + semihosting_common_init(target, riscv_semihosting_setup, + riscv_semihosting_post_result); +} + +/** + * Check for and process a semihosting request using the ARM protocol). This + * is meant to be called when the target is stopped due to a debug mode entry. + * If the value 0 is returned then there was nothing to process. A non-zero + * return value signifies that a request was processed and the target resumed, + * or an error was encountered, in which case the caller must return + * immediately. + * + * @param target Pointer to the target to process. + * @param retval Pointer to a location where the return code will be stored + * @return non-zero value if a request was processed or an error encountered + */ +int riscv_semihosting(struct target *target, int *retval) +{ + struct semihosting *semihosting = target->semihosting; + if (!semihosting) + return 0; + + if (!semihosting->is_active) + return 0; + + riscv_reg_t dpc; + int result = riscv_get_register(target, &dpc, GDB_REGNO_DPC); + if (result != ERROR_OK) + return 0; + + uint8_t tmp[12]; + + /* Read the current instruction, including the bracketing */ + *retval = target_read_memory(target, dpc - 4, 2, 6, tmp); + if (*retval != ERROR_OK) + return 0; + + /* + * The instructions that trigger a semihosting call, + * always uncompressed, should look like: + * + * 01f01013 slli zero,zero,0x1f + * 00100073 ebreak + * 40705013 srai zero,zero,0x7 + */ + uint32_t pre = target_buffer_get_u32(target, tmp); + uint32_t ebreak = target_buffer_get_u32(target, tmp + 4); + uint32_t post = target_buffer_get_u32(target, tmp + 8); + LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, dpc); + + if (pre != 0x01f01013 || ebreak != 0x00100073 || post != 0x40705013) { + + /* Not the magic sequence defining semihosting. */ + return 0; + } + + /* + * Perform semihosting call if we are not waiting on a fileio + * operation to complete. + */ + if (!semihosting->hit_fileio) { + + /* RISC-V uses A0 and A1 to pass function arguments */ + riscv_reg_t r0; + riscv_reg_t r1; + + result = riscv_get_register(target, &r0, GDB_REGNO_A0); + if (result != ERROR_OK) + return 0; + + result = riscv_get_register(target, &r1, GDB_REGNO_A1); + if (result != ERROR_OK) + return 0; + + semihosting->op = r0; + semihosting->param = r1; + semihosting->word_size_bytes = riscv_xlen(target) / 8; + + /* Check for ARM operation numbers. */ + if (0 <= semihosting->op && semihosting->op <= 0x31) { + *retval = semihosting_common(target); + if (*retval != ERROR_OK) { + LOG_ERROR("Failed semihosting operation"); + return 0; + } + } else { + /* Unknown operation number, not a semihosting call. */ + return 0; + } + } + + /* + * Resume target if we are not waiting on a fileio + * operation to complete. + */ + if (semihosting->is_resumable && !semihosting->hit_fileio) { + /* Resume right after the EBREAK 4 bytes instruction. */ + *retval = target_resume(target, 0, dpc+4, 0, 0); + if (*retval != ERROR_OK) { + LOG_ERROR("Failed to resume target"); + return 0; + } + + return 1; + } + + return 0; +} + +/* ------------------------------------------------------------------------- + * Local functions. */ + +/** + * Called via semihosting->setup() later, after the target is known, + * usually on the first semihosting command. + */ +static int riscv_semihosting_setup(struct target *target, int enable) +{ + LOG_DEBUG("enable=%d", enable); + + struct semihosting *semihosting = target->semihosting; + if (semihosting) + semihosting->setup_time = clock(); + + return ERROR_OK; +} + +static int riscv_semihosting_post_result(struct target *target) +{ + struct semihosting *semihosting = target->semihosting; + if (!semihosting) { + /* If not enabled, silently ignored. */ + return 0; + } + + LOG_DEBUG("0x%" PRIx64, semihosting->result); + riscv_set_register(target, GDB_REGNO_A0, semihosting->result); + return 0; +} diff --git a/src/target/target.c b/src/target/target.c index 591b9ea2c..68f93210a 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -107,6 +107,7 @@ extern struct target_type or1k_target; extern struct target_type quark_x10xx_target; extern struct target_type quark_d20xx_target; extern struct target_type stm8_target; +extern struct target_type riscv_target; static struct target_type *target_types[] = { &arm7tdmi_target, @@ -139,6 +140,7 @@ static struct target_type *target_types[] = { &quark_x10xx_target, &quark_d20xx_target, &stm8_target, + &riscv_target, #if BUILD_TARGET64 &aarch64_target, #endif diff --git a/tcl/board/sifive-e31arty.cfg b/tcl/board/sifive-e31arty.cfg new file mode 100644 index 000000000..ec10b27c3 --- /dev/null +++ b/tcl/board/sifive-e31arty.cfg @@ -0,0 +1,22 @@ +# +# Be sure you include the speed and interface before this file +# Example: +# -c "adapter_khz 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e31arty.cfg" + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME +$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 + +flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 +init +if {[ info exists pulse_srst]} { + ftdi_set_signal nSRST 0 + ftdi_set_signal nSRST z +} +halt +flash protect 0 64 last off +echo "Ready for Remote Connections" diff --git a/tcl/board/sifive-e51arty.cfg b/tcl/board/sifive-e51arty.cfg new file mode 100644 index 000000000..ffd83a058 --- /dev/null +++ b/tcl/board/sifive-e51arty.cfg @@ -0,0 +1,22 @@ +# +# Be sure you include the speed and interface before this file +# Example: +# -c "adapter_khz 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e51arty.cfg" + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME +$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 + +flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 +init +if {[ info exists pulse_srst]} { + ftdi_set_signal nSRST 0 + ftdi_set_signal nSRST z +} +halt +flash protect 0 64 last off +echo "Ready for Remote Connections" diff --git a/tcl/board/sifive-hifive1.cfg b/tcl/board/sifive-hifive1.cfg new file mode 100644 index 000000000..9bc66701c --- /dev/null +++ b/tcl/board/sifive-hifive1.cfg @@ -0,0 +1,34 @@ +adapter_khz 10000 + +interface ftdi +ftdi_device_desc "Dual RS232-HS" +ftdi_vid_pid 0x0403 0x6010 + +ftdi_layout_init 0x0008 0x001b +ftdi_layout_signal nSRST -oe 0x0020 -data 0x0020 + +#Reset Stretcher logic on FE310 is ~1 second long +#This doesn't apply if you use +# ftdi_set_signal, but still good to document +#adapter_nsrst_delay 1500 + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913 + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME riscv -chain-position $_TARGETNAME +$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 + +flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME +init +#reset -- This type of reset is not implemented yet +if {[ info exists pulse_srst]} { + ftdi_set_signal nSRST 0 + ftdi_set_signal nSRST z + #Wait for the reset stretcher + #It will work without this, but + #will incur lots of delays for later commands. + sleep 1500 +} +halt +flash protect 0 64 last off From e57f8e12da6da02c192cd9365185fe8eee46b080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gl=C3=B6ckner?= Date: Wed, 4 Oct 2017 23:07:53 +0200 Subject: [PATCH 054/147] usb_blaster: Don't unnecessarily go through DR-/IR-Pause MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need to pass through DR-/IR-Pause after a scan if we want to go to DR-/IR-Update. We just have to skip the first step of the path to the end state because we already did that step when shifting the last bit. v2: - Fix comments as remarked in review of v1 Change-Id: I3c10f02794b2233f63d2150934e2768430873caa Signed-off-by: Daniel Glöckner Reviewed-on: http://openocd.zylin.com/4245 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Matthias Welwarsky --- src/jtag/drivers/usb_blaster/usb_blaster.c | 41 ++++++++++------------ 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c index df9f2a174..8ccf87172 100644 --- a/src/jtag/drivers/usb_blaster/usb_blaster.c +++ b/src/jtag/drivers/usb_blaster/usb_blaster.c @@ -445,6 +445,7 @@ static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes) * ublast_tms_seq - write a TMS sequence transition to JTAG * @bits: TMS bits to be written (bit0, bit1 .. bitN) * @nb_bits: number of TMS bits (between 1 and 8) + * @skip: number of TMS bits to skip at the beginning of the series * * Write a serie of TMS transitions, where each transition consists in : * - writing out TCK=0, TMS=, TDI= @@ -452,12 +453,12 @@ static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes) * The function ensures that at the end of the sequence, the clock (TCK) is put * low. */ -static void ublast_tms_seq(const uint8_t *bits, int nb_bits) +static void ublast_tms_seq(const uint8_t *bits, int nb_bits, int skip) { int i; DEBUG_JTAG_IO("(bits=%02x..., nb_bits=%d)", bits[0], nb_bits); - for (i = 0; i < nb_bits; i++) + for (i = skip; i < nb_bits; i++) ublast_clock_tms((bits[i / 8] >> (i % 8)) & 0x01); ublast_idle_clock(); } @@ -469,7 +470,7 @@ static void ublast_tms_seq(const uint8_t *bits, int nb_bits) static void ublast_tms(struct tms_command *cmd) { DEBUG_JTAG_IO("(num_bits=%d)", cmd->num_bits); - ublast_tms_seq(cmd->bits, cmd->num_bits); + ublast_tms_seq(cmd->bits, cmd->num_bits, 0); } /** @@ -501,11 +502,12 @@ static void ublast_path_move(struct pathmove_command *cmd) /** * ublast_state_move - move JTAG state to the target state * @state: the target state + * @skip: number of bits to skip at the beginning of the path * * Input the correct TMS sequence to the JTAG TAP so that we end up in the * target state. This assumes the current state (tap_get_state()) is correct. */ -static void ublast_state_move(tap_state_t state) +static void ublast_state_move(tap_state_t state, int skip) { uint8_t tms_scan; int tms_len; @@ -516,7 +518,7 @@ static void ublast_state_move(tap_state_t state) return; tms_scan = tap_get_tms_path(tap_get_state(), state); tms_len = tap_get_tms_path_len(tap_get_state(), state); - ublast_tms_seq(&tms_scan, tms_len); + ublast_tms_seq(&tms_scan, tms_len, skip); tap_set_state(state); } @@ -688,9 +690,9 @@ static void ublast_runtest(int cycles, tap_state_t state) { DEBUG_JTAG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state); - ublast_state_move(TAP_IDLE); + ublast_state_move(TAP_IDLE, 0); ublast_queue_tdi(NULL, cycles, SCAN_OUT); - ublast_state_move(state); + ublast_state_move(state, 0); } static void ublast_stableclocks(int cycles) @@ -720,9 +722,9 @@ static int ublast_scan(struct scan_command *cmd) scan_bits = jtag_build_buffer(cmd, &buf); if (cmd->ir_scan) - ublast_state_move(TAP_IRSHIFT); + ublast_state_move(TAP_IRSHIFT, 0); else - ublast_state_move(TAP_DRSHIFT); + ublast_state_move(TAP_DRSHIFT, 0); log_buf = hexdump(buf, DIV_ROUND_UP(scan_bits, 8)); DEBUG_JTAG_IO("%s(scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d)", __func__, @@ -733,20 +735,15 @@ static int ublast_scan(struct scan_command *cmd) ublast_queue_tdi(buf, scan_bits, type); - /* - * As our JTAG is in an unstable state (IREXIT1 or DREXIT1), move it - * forward to a stable IRPAUSE or DRPAUSE. - */ - ublast_clock_tms(0); - if (cmd->ir_scan) - tap_set_state(TAP_IRPAUSE); - else - tap_set_state(TAP_DRPAUSE); - ret = jtag_read_buffer(buf, cmd); if (buf) free(buf); - ublast_state_move(cmd->end_state); + /* + * ublast_queue_tdi sends the last bit with TMS=1. We are therefore + * already in Exit1-DR/IR and have to skip the first step on our way + * to end_state. + */ + ublast_state_move(cmd->end_state, 1); return ret; } @@ -776,7 +773,7 @@ static void ublast_initial_wipeout(void) /* * Put JTAG in RESET state (five 1 on TMS) */ - ublast_tms_seq(&tms_reset, 5); + ublast_tms_seq(&tms_reset, 5, 0); tap_set_state(TAP_RESET); } @@ -805,7 +802,7 @@ static int ublast_execute_queue(void) ublast_stableclocks(cmd->cmd.stableclocks->num_cycles); break; case JTAG_TLR_RESET: - ublast_state_move(cmd->cmd.statemove->end_state); + ublast_state_move(cmd->cmd.statemove->end_state, 0); break; case JTAG_PATHMOVE: ublast_path_move(cmd->cmd.pathmove); From ad6c71e151590f9d07eb07eda978a8d2a845259c Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Fri, 15 Jul 2016 14:23:25 +0200 Subject: [PATCH 055/147] cortex_a: fix virt2phys when mmu is disabled When the MMU is not enabled on debug state entry, virt2phys cannot perform a translation since it is unknown whether a valid MMU configuration existed before. In this case, return the virtual address as physical address. Change-Id: I6f85a7a5dbc200be1a4b5badf10a1a717f1c79c0 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4480 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Matthias Welwarsky --- src/target/cortex_a.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 21ce4fae8..b15dcb414 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -3229,6 +3229,20 @@ static int cortex_a_virt2phys(struct target *target, struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; uint8_t apsel = swjdp->apsel; + int mmu_enabled; + + /* + * If the MMU was not enabled at debug entry, there is no + * way of knowing if there was ever a valid configuration + * for it and thus it's not safe to enable it. In this case, + * just return the virtual address as physical. + */ + cortex_a_mmu(target, &mmu_enabled); + if (!mmu_enabled) { + *phys = virt; + return ERROR_OK; + } + if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num)) { uint32_t ret; retval = armv7a_mmu_translate_va(target, From 1e374d508b141699b6126a61223133ed75cb6713 Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Wed, 13 Apr 2016 23:45:12 +0000 Subject: [PATCH 056/147] drivers: cmsis-dap: print serial if available Helpful for sanity checking connections Change-Id: Ife0d8b4e12d4c03685aac8115c9739a4c1e994fe Signed-off-by: Karl Palsson Reviewed-on: http://openocd.zylin.com/3405 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/jtag/drivers/cmsis_dap_usb.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index 928389faf..4ee483659 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -729,6 +729,20 @@ static void cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_del cmsis_dap_swd_queue_cmd(cmd, value, 0); } +static int cmsis_dap_get_serial_info(void) +{ + uint8_t *data; + + int retval = cmsis_dap_cmd_DAP_Info(INFO_ID_SERNUM, &data); + if (retval != ERROR_OK) + return retval; + + if (data[0]) /* strlen */ + LOG_INFO("CMSIS-DAP: Serial# = %s", &data[1]); + + return ERROR_OK; +} + static int cmsis_dap_get_version_info(void) { uint8_t *data; @@ -873,6 +887,10 @@ static int cmsis_dap_init(void) if (retval != ERROR_OK) return retval; + retval = cmsis_dap_get_serial_info(); + if (retval != ERROR_OK) + return retval; + if (swd_mode) { retval = cmsis_dap_swd_open(); if (retval != ERROR_OK) From 11e3b6fb09f06f730e5591c6099d4bbc193ff312 Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Tue, 17 Jul 2018 13:59:38 -0700 Subject: [PATCH 057/147] target/cortex_m: make a variable local The vec_ids variable is not referenced anywhere other than the vector catch command handler. Make it local to that function. Change-Id: Ie5865e8f78698c19a09f0b9d58269ced1c9db440 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4606 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/cortex_m.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index dcb3ddd82..03dc51572 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -2274,20 +2274,6 @@ static int cortex_m_verify_pointer(struct command_context *cmd_ctx, * cortexm3_target structure, which is only used with CM3 targets. */ -static const struct { - char name[10]; - unsigned mask; -} vec_ids[] = { - { "hard_err", VC_HARDERR, }, - { "int_err", VC_INTERR, }, - { "bus_err", VC_BUSERR, }, - { "state_err", VC_STATERR, }, - { "chk_err", VC_CHKERR, }, - { "nocp_err", VC_NOCPERR, }, - { "mm_err", VC_MMERR, }, - { "reset", VC_CORERESET, }, -}; - COMMAND_HANDLER(handle_cortex_m_vector_catch_command) { struct target *target = get_current_target(CMD_CTX); @@ -2296,6 +2282,20 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command) uint32_t demcr = 0; int retval; + static const struct { + char name[10]; + unsigned mask; + } vec_ids[] = { + { "hard_err", VC_HARDERR, }, + { "int_err", VC_INTERR, }, + { "bus_err", VC_BUSERR, }, + { "state_err", VC_STATERR, }, + { "chk_err", VC_CHKERR, }, + { "nocp_err", VC_NOCPERR, }, + { "mm_err", VC_MMERR, }, + { "reset", VC_CORERESET, }, + }; + retval = cortex_m_verify_pointer(CMD_CTX, cortex_m); if (retval != ERROR_OK) return retval; From 4896c83ce8f28674a0beb34e7d475cb5b0ac7dab Mon Sep 17 00:00:00 2001 From: Paul Bartholomew Date: Wed, 25 Jul 2018 22:59:01 +0200 Subject: [PATCH 058/147] target/cortex_a: fix compile error for uninitialized variable Commit ad6c71e151590f9d07eb07eda978a8d2a845259c introduced the variable "mmu_enabled" whose pointer is passed to cortex_a_mmu() that initialises it. This initialization is not visible to the compiler that issue a compile error. The same situation is common across the same file and the usual workaround is to initialize it to zero; thus the same fix i applied here. Ticket: https://sourceforge.net/p/openocd/tickets/197/ Fixes: commit ad6c71e15159 ("cortex_a: fix virt2phys when mmu is disabled") Change-Id: I77dec41acdf4c715b45ae37b72e36719d96d9283 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4619 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/cortex_a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index b15dcb414..e4d8331b2 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -3229,7 +3229,7 @@ static int cortex_a_virt2phys(struct target *target, struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; uint8_t apsel = swjdp->apsel; - int mmu_enabled; + int mmu_enabled = 0; /* * If the MMU was not enabled at debug entry, there is no From 16e95146be107667f26dd805df8d7564b7ea5d8a Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 10 Feb 2018 16:37:31 +0100 Subject: [PATCH 059/147] mips_m4k: add optional reset handler In some cases by using SRST we can't halt CPU early enough. And option PrRst is not available too. In this case the only way is to set BOOT flag over EJTAG and reset CPU or SoC from CPU itself. For example by writing to some reset register. This patch is providing possibility to use user defined reset-assert handler which will be enabled only in case SRST is disabled. It is needed to be able switch between two different reset variants on run time. Change-Id: I6ef98f1871ea657115877190f7cc7a5e8f3233e4 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4404 Tested-by: jenkins Reviewed-by: Paul Fertser --- src/target/mips_m4k.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index 78718ca16..20c707bb6 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -344,6 +344,8 @@ static int mips_m4k_assert_reset(struct target *target) jtag_add_reset(1, 1); else if (!srst_asserted) jtag_add_reset(0, 1); + } else if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) { + target_handle_event(target, TARGET_EVENT_RESET_ASSERT); } else { if (mips_m4k->is_pic32mx) { LOG_DEBUG("Using MTAP reset to reset processor..."); From 8e8b50f65dffd6908375cfd96e57820031bf6e2c Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 31 Jan 2018 11:54:39 +0100 Subject: [PATCH 060/147] tcl/target: add config for Qualcomm QCA4531 The QCA4531 is a two stream (2x2) 802.11b/g/n single-band programmable Wi-Fi System-on-Chip (SoC) for the Internet of Things (IoT). https://www.qualcomm.com/products/qca4531 Change-Id: I58398c00943b005cfaf0ac1eaad92d1fa4e2cba7 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4405 Tested-by: jenkins Reviewed-by: Paul Fertser --- tcl/target/qualcomm_qca4531.cfg | 154 ++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 tcl/target/qualcomm_qca4531.cfg diff --git a/tcl/target/qualcomm_qca4531.cfg b/tcl/target/qualcomm_qca4531.cfg new file mode 100644 index 000000000..3d2157852 --- /dev/null +++ b/tcl/target/qualcomm_qca4531.cfg @@ -0,0 +1,154 @@ +# The QCA4531 is a two stream (2x2) 802.11b/g/n single-band programmable +# Wi-Fi System-on-Chip (SoC) for the Internet of Things (IoT). +# +# Product page: +# https://www.qualcomm.com/products/qca4531 +# +# Notes: +# - MIPS Processor ID (PRId): 0x00019374 +# - 24Kc MIPS processor with 64 KB I-Cache and 32 KB D-Cache, +# operating at up to 650 MHz +# - External 16-bit DDR1, operating at up to 200 MHz, DDR2 operating at up +# to 300 MHz +# - TRST is not available. +# - EJTAG PrRst signal is not supported +# - RESET_L pin B56 on the SoC will reset internal JTAG logic. +# +# Pins related for debug and bootstrap: +# Name Pin Description +# JTAG +# JTAG_TCK GPIO0, (A27) Software configurable, default JTAG +# JTAG_TDI GPIO1, (B23) Software configurable, default JTAG +# JTAG_TDO GPIO2, (A28) Software configurable, default JTAG +# JTAG_TMS GPIO3, (A29) Software configurable, default JTAG +# Reset +# RESET_L -, (B56) Input only +# SYS_RST_L GPIO17, (A79) Output reset request or GPIO +# Bootstrap +# JTAG_MODE GPIO16, (A78) 0 - JTAG (Default); 1 - EJTAG +# DDR_SELECT GPIO10, (A57) 0 - DDR2; 1 - DDR1 +# UART +# UART0_SOUT GPIO10, (A57) +# UART0_SIN GPIO9, (B49) + +# Per default we need to use "none" variant to be able properly "reset init" +# or "reset halt" the CPU. +reset_config none srst_pulls_trst + +# For SRST based variant we still need proper timings. +# For ETH part the reset should be asserted at least for 10ms +# Since there is no other information let's take 100ms to be sure. +adapter_nsrst_assert_width 100 + +# according to the SoC documentation it should take at least 5ms from +# reset end till bootstrap end. In the practice we need 8ms to get JTAG back +# to live. +adapter_nsrst_delay 8 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $_CHIPNAME +} else { + set _CHIPNAME qca4531 +} + +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00000001 + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME + +# provide watchdog helper. +proc disable_watchdog { } { + mww 0xb8060008 0x0 +} + +$_TARGETNAME configure -event halted { disable_watchdog } + +# Since PrRst is not supported and SRST will reset complete chip +# with JTAG engine, we need to reset CPU from CPU itself. +$_TARGETNAME configure -event reset-assert-pre { + halt +} + +$_TARGETNAME configure -event reset-assert { + catch "mww 0xb806001C 0x01000000" +} + +# To be able to trigger complete chip reset, in case JTAG is blocked +# or CPU not responding, we still can use this helper. +proc full_reset { } { + reset_config srst_only + reset + halt + reset_config none +} + +# Section with helpers which can be used by boards +proc qca4531_ddr2_550_550_init {} { + # Clear reset flags for different SoC components + mww 0xb806001c 0xfeceffff + mww 0xb806001c 0xeeceffff + mww 0xb806001c 0xe6ceffff + + # PMU configurations + # Internal Switcher + mww 0xb8116c40 0x633c8176 + # Increase the DDR voltage + mww 0xb8116c44 0x10200000 + # XTAL Configurations + mww 0xb81162c0 0x4b962100 + mww 0xb81162c4 0x480 + mww 0xb81162c8 0x04000144 + # Recommended PLL configurations + mww 0xb81161c4 0x54086000 + mww 0xb8116244 0x54086000 + + # PLL init + mww 0xb8050008 0x0131001c + mww 0xb8050000 0x40001580 + mww 0xb8050004 0x40015800 + mww 0xb8050008 0x0131001c + mww 0xb8050000 0x00001580 + mww 0xb8050004 0x00015800 + mww 0xb8050008 0x01310000 + mww 0xb8050044 0x781003ff + mww 0xb8050048 0x003c103f + + # DDR2 init + mww 0xb8000108 0x401f0042 + mww 0xb80000b8 0x0000166d + mww 0xb8000000 0xcfaaf33b + mww 0xb800015c 0x0000000f + mww 0xb8000004 0xa272efa8 + mww 0xb8000018 0x0000ffff + mww 0xb80000c4 0x74444444 + mww 0xb80000c8 0x00000444 + mww 0xb8000004 0xa210ee28 + mww 0xb8000004 0xa2b2e1a8 + mww 0xb8000010 0x8 + mww 0xb80000bc 0x0 + mww 0xb8000010 0x10 + mww 0xb80000c0 0x0 + mww 0xb8000010 0x40 + mww 0xb800000c 0x2 + mww 0xb8000010 0x2 + mww 0xb8000008 0xb43 + mww 0xb8000010 0x1 + mww 0xb8000010 0x8 + mww 0xb8000010 0x4 + mww 0xb8000010 0x4 + mww 0xb8000008 0xa43 + mww 0xb8000010 0x1 + mww 0xb800000c 0x382 + mww 0xb8000010 0x2 + mww 0xb800000c 0x402 + mww 0xb8000010 0x2 + mww 0xb8000014 0x40be + mww 0xb800001C 0x20 + mww 0xb8000020 0x20 + mww 0xb80000cc 0xfffff + + # UART GPIO programming + mww 0xb8040000 0xff30b + mww 0xb8040044 0x908 + mww 0xb8040034 0x160000 +} From 87610a41790f3568720701008259c859e2d01ae2 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 31 Jan 2018 11:58:50 +0100 Subject: [PATCH 061/147] tcl/board: add config for 8devices LIMA board More information about this board can be found here: https://www.8devices.com/products/lima Change-Id: Id35a35d3e986630d58d37b47828870afd107cc6a Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4406 Tested-by: jenkins Reviewed-by: Paul Fertser --- tcl/board/8devices-lima.cfg | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tcl/board/8devices-lima.cfg diff --git a/tcl/board/8devices-lima.cfg b/tcl/board/8devices-lima.cfg new file mode 100644 index 000000000..136f86197 --- /dev/null +++ b/tcl/board/8devices-lima.cfg @@ -0,0 +1,30 @@ +# Product page: +# https://www.8devices.com/products/lima +# +# Location of JTAG pins: +# J2 GPIO0 JTAG TCK +# J2 GPIO1 JTAG TDI +# J2 GPIO2 JTAG TDO +# J2 GPIO3 JTAG TMS +# J2 RST directly connected to RESET_L of the SoC and can be used as +# JTAG SRST. Note: this pin will also reset the debug engine. +# J1 +3,3V Can be use as JTAG Vref +# J1 or J2 GND Can be used for JTAG GND +# +# This board is powered from mini USB connecter which is also used +# as USB to UART converted based on FTDI FT230XQ chip + +source [find target/qualcomm_qca4531.cfg] + +proc board_init { } { + qca4531_ddr2_550_550_init +} + +$_TARGETNAME configure -event reset-init { + board_init +} + +set ram_boot_address 0xa0000000 +$_TARGETNAME configure -work-area-phys 0xa1FFE000 -work-area-size 0x1000 + +flash bank flash0 ath79 0 0 0 0 $_TARGETNAME cs0 From dcf977c89a24b02fd8200af633be1fdd3add4ae7 Mon Sep 17 00:00:00 2001 From: Antony Pavlov Date: Sun, 20 Sep 2015 16:52:37 +0300 Subject: [PATCH 062/147] tcl/target|board: move common AR9331 code to atheros_ar9331.cfg The ar9331_25mhz_pll_init and ar9331_ddr1_init routines can be used not only for TP-Link MR3020 board, so move them to the common atheros_ar9331.cfg file. Change-Id: I04090856b08151d6bb0f5ef9cc654efae1c81835 Signed-off-by: Antony Pavlov Reviewed-on: http://openocd.zylin.com/2999 Tested-by: jenkins Reviewed-by: Paul Fertser --- tcl/board/tp-link_tl-mr3020.cfg | 34 --------------------------------- tcl/target/atheros_ar9331.cfg | 34 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/tcl/board/tp-link_tl-mr3020.cfg b/tcl/board/tp-link_tl-mr3020.cfg index 7e040b325..48fb69893 100644 --- a/tcl/board/tp-link_tl-mr3020.cfg +++ b/tcl/board/tp-link_tl-mr3020.cfg @@ -1,39 +1,5 @@ source [find target/atheros_ar9331.cfg] -proc ar9331_25mhz_pll_init {} { - mww 0xb8050008 0x00018004 ;# bypass PLL; AHB_POST_DIV - ratio 4 - mww 0xb8050004 0x00000352 ;# 34000(ns)/40ns(25MHz) = 0x352 (850) - mww 0xb8050000 0x40818000 ;# Power down control for CPU PLL - ;# OUTDIV | REFDIV | DIV_INT - mww 0xb8050010 0x001003e8 ;# CPU PLL Dither FRAC Register - ;# (disabled?) - mww 0xb8050000 0x00818000 ;# Power on | OUTDIV | REFDIV | DIV_INT - mww 0xb8050008 0x00008000 ;# remove bypass; - ;# AHB_POST_DIV - ratio 2 -} - -proc ar9331_ddr1_init {} { - mww 0xb8000000 0x7fbc8cd0 ;# DDR_CONFIG - lots of DRAM confs - mww 0xb8000004 0x9dd0e6a8 ;# DDR_CONFIG2 - more DRAM confs - - mww 0xb8000010 0x8 ;# Forces a PRECHARGE ALL cycle - mww 0xb8000008 0x133 ;# mode reg: 0x133 - default - mww 0xb8000010 0x1 ;# Forces an MRS update cycl - mww 0xb800000c 0x2 ;# Extended mode register value. - ;# default 0x2 - Reset to weak driver, DLL on - mww 0xb8000010 0x2 ;# Forces an EMRS update cycle - mww 0xb8000010 0x8 ;# Forces a PRECHARGE ALL cycle - mww 0xb8000008 0x33 ;# mode reg: remove some bit? - mww 0xb8000010 0x1 ;# Forces an MRS update cycl - mww 0xb8000014 0x4186 ;# enable refres: bit(14) - set refresh rate - mww 0xb800001c 0x8 ;# This register is used along with DQ Lane 0, - ;# DQ[7:0], DQS_0 - mww 0xb8000020 0x9 ;# This register is used along with DQ Lane 1, - ;# DQ[15:8], DQS_1. - mww 0xb8000018 0xff ;# DDR read and capture bit mask. - ;# Each bit represents a cycle of valid data. -} - $_TARGETNAME configure -event reset-init { ar9331_25mhz_pll_init sleep 1 diff --git a/tcl/target/atheros_ar9331.cfg b/tcl/target/atheros_ar9331.cfg index c5609bb1d..cd6918339 100644 --- a/tcl/target/atheros_ar9331.cfg +++ b/tcl/target/atheros_ar9331.cfg @@ -14,3 +14,37 @@ jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME + +proc ar9331_25mhz_pll_init {} { + mww 0xb8050008 0x00018004 ;# bypass PLL; AHB_POST_DIV - ratio 4 + mww 0xb8050004 0x00000352 ;# 34000(ns)/40ns(25MHz) = 0x352 (850) + mww 0xb8050000 0x40818000 ;# Power down control for CPU PLL + ;# OUTDIV | REFDIV | DIV_INT + mww 0xb8050010 0x001003e8 ;# CPU PLL Dither FRAC Register + ;# (disabled?) + mww 0xb8050000 0x00818000 ;# Power on | OUTDIV | REFDIV | DIV_INT + mww 0xb8050008 0x00008000 ;# remove bypass; + ;# AHB_POST_DIV - ratio 2 +} + +proc ar9331_ddr1_init {} { + mww 0xb8000000 0x7fbc8cd0 ;# DDR_CONFIG - lots of DRAM confs + mww 0xb8000004 0x9dd0e6a8 ;# DDR_CONFIG2 - more DRAM confs + + mww 0xb8000010 0x8 ;# Forces a PRECHARGE ALL cycle + mww 0xb8000008 0x133 ;# mode reg: 0x133 - default + mww 0xb8000010 0x1 ;# Forces an MRS update cycl + mww 0xb800000c 0x2 ;# Extended mode register value. + ;# default 0x2 - Reset to weak driver, DLL on + mww 0xb8000010 0x2 ;# Forces an EMRS update cycle + mww 0xb8000010 0x8 ;# Forces a PRECHARGE ALL cycle + mww 0xb8000008 0x33 ;# mode reg: remove some bit? + mww 0xb8000010 0x1 ;# Forces an MRS update cycl + mww 0xb8000014 0x4186 ;# enable refres: bit(14) - set refresh rate + mww 0xb800001c 0x8 ;# This register is used along with DQ Lane 0, + ;# DQ[7:0], DQS_0 + mww 0xb8000020 0x9 ;# This register is used along with DQ Lane 1, + ;# DQ[15:8], DQS_1. + mww 0xb8000018 0xff ;# DDR read and capture bit mask. + ;# Each bit represents a cycle of valid data. +} From bfdccf4c8a7a0b358991ca3b9dc91f526d39ac96 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 19 Feb 2018 15:49:31 +0100 Subject: [PATCH 063/147] tcl/target/atheros_ar9331: add DDR2 helper this helper works on many different boards, so it is good to have it in target config Change-Id: I068deac36fdd73dbbcedffc87865cc5b9d992c1d Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4422 Tested-by: jenkins Reviewed-by: Paul Fertser --- tcl/target/atheros_ar9331.cfg | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tcl/target/atheros_ar9331.cfg b/tcl/target/atheros_ar9331.cfg index cd6918339..290825f0c 100644 --- a/tcl/target/atheros_ar9331.cfg +++ b/tcl/target/atheros_ar9331.cfg @@ -48,3 +48,46 @@ proc ar9331_ddr1_init {} { mww 0xb8000018 0xff ;# DDR read and capture bit mask. ;# Each bit represents a cycle of valid data. } + +proc ar9331_ddr2_init {} { + mww 0xb8000000 0x7fbc8cd0 ;# DDR_CONFIG - lots of DRAM confs + mww 0xb8000004 0x9dd0e6a8 ;# DDR_CONFIG2 - more DRAM confs + + mww 0xb800008c 0x00000a59 + mww 0xb8000010 0x00000008 ;# PRECHARGE ALL cycle + + mww 0xb8000090 0x00000000 + mww 0xb8000010 0x00000010 ;# EMR2S update cycle + + mww 0xb8000094 0x00000000 + mww 0xb8000010 0x00000020 ;# EMR3S update cycle + + mww 0xb800000c 0x00000000 + mww 0xb8000010 0x00000002 ;# EMRS update cycle + + mww 0xb8000008 0x00000100 + mww 0xb8000010 0x00000001 ;# MRS update cycle + + mww 0xb8000010 0x00000008 ;# PRECHARGE ALL cycle + + mww 0xb8000010 0x00000004 + mww 0xb8000010 0x00000004 ;# AUTO REFRESH cycle + + mww 0xb8000008 0x00000a33 + mww 0xb8000010 0x00000001 ;# MRS update cycle + + mww 0xb800000c 0x00000382 + mww 0xb8000010 0x00000002 ;# EMRS update cycle + + mww 0xb800000c 0x00000402 + mww 0xb8000010 0x00000002 ;# EMRS update cycle + + mww 0xb8000014 0x00004186 ;# DDR_REFRESH + mww 0xb800001c 0x00000008 ;# DDR_TAP_CTRL0 + mww 0xb8000020 0x00000009 ;# DDR_TAP_CTRL1 + + ;# DDR read and capture bit mask. + ;# Each bit represents a cycle of valid data. + ;# 0xff: use 16-bit DDR + mww 0xb8000018 0x000000ff +} From bebdbe8b73b8d7cb2837687c0d38396fee0142fd Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 2 Dec 2017 19:55:11 +0100 Subject: [PATCH 064/147] tcl/target/atheros_ar9331: add documentation and extra helpers Sync it with experience gathered on Qualcomm QCA4531 SoC. This chips are in many ways similar. Change-Id: I06b9c85e5985a09a9be3cb6cc0ce3b37695d2e54 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4423 Tested-by: jenkins Reviewed-by: Paul Fertser --- tcl/target/atheros_ar9331.cfg | 92 ++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 7 deletions(-) diff --git a/tcl/target/atheros_ar9331.cfg b/tcl/target/atheros_ar9331.cfg index 290825f0c..bea37ed3c 100644 --- a/tcl/target/atheros_ar9331.cfg +++ b/tcl/target/atheros_ar9331.cfg @@ -1,20 +1,98 @@ +# The Atheros AR9331 is a highly integrated and cost effective +# IEEE 802.11n 1x1 2.4 GHz System- on-a-Chip (SoC) for wireless +# local area network (WLAN) AP and router platforms. +# +# Notes: +# - MIPS Processor ID (PRId): 0x00019374 +# - 24Kc MIPS processor with 64 KB I-Cache and 32 KB D-Cache, +# operating at up to 400 MHz +# - External 16-bit DDR1, DDR2, or SDRAM memory interface +# - TRST is not available. +# - EJTAG PrRst signal is not supported +# - RESET_L pin A72 on the SoC will reset internal JTAG logic. +# + +# Pins related for debug and bootstrap: +# Name Pin Description +# JTAG +# JTAG_TCK GPIO0, (A27) Software configurable, default JTAG +# JTAG_TDI GPIO6, (B46) Software configurable, default JTAG +# JTAG_TDO GPIO7, (A54) Software configurable, default JTAG +# JTAG_TMS GPIO8, (A52) Software configurable, default JTAG +# Reset +# RESET_L -, (A72) Input only +# SYS_RST_L ???????? Output reset request or GPIO +# Bootstrap +# MEM_TYPE[1] GPIO28, (A74) 0 - SDRAM, 1 - DDR1 RAM, 2 - DDR2 RAM +# MEM_TYPE[0] GPIO12, (A56) +# FW_DOWNLOAD GPIO16, (A75) Used if BOOT_FROM_SPI = 0. 0 - boot from USB +# 1 - boot from MDIO. +# JTAG_MODE(JS) GPIO11, (B48) 0 - JTAG (Default); 1 - EJTAG +# BOOT_FROM_SPI GPIO1, (A77) 0 - ROM boot; 1 - SPI boot +# SEL_25M_40M GPIO0, (A78) 0 - 25MHz; 1 - 40MHz +# UART +# UART0_SOUT GPIO10, (A79) +# UART0_SIN GPIO9, (B68) + +# Per default we need to use "none" variant to be able properly "reset init" +# or "reset halt" the CPU. +reset_config none srst_pulls_trst + +# For SRST based variant we still need proper timings. +# For ETH part the reset should be asserted at least for 10ms +# Since there is no other information let's take 100ms to be sure. +adapter_nsrst_assert_width 100 + +# according to the SoC documentation it should take at least 5ms from +# reset end till bootstrap end. In the practice we need 8ms to get JTAG back +# to live. +adapter_nsrst_delay 8 + if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME ar9331 } -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - set _CPUTAPID 0x00000001 -} - -jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00000001 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME +# provide watchdog helper. +proc disable_watchdog { } { + mww 0xb8060008 0x0 +} + +$_TARGETNAME configure -event halted { disable_watchdog } + +# Since PrRst is not supported and SRST will reset complete chip +# with JTAG engine, we need to reset CPU from CPU itself. +$_TARGETNAME configure -event reset-assert-pre { + halt +} + +$_TARGETNAME configure -event reset-assert { + catch "mww 0xb806001C 0x01000000" +} + +# To be able to trigger complete chip reset, in case JTAG is blocked +# or CPU not responding, we still can use this helper. +proc full_reset { } { + reset_config srst_only + reset + halt + reset_config none +} + +proc disable_watchdog { } { + ;# disable watchdog + mww 0xb8060008 0x0 +} + +$_TARGETNAME configure -event reset-end { disable_watchdog } + +# Section with helpers which can be used by boards proc ar9331_25mhz_pll_init {} { mww 0xb8050008 0x00018004 ;# bypass PLL; AHB_POST_DIV - ratio 4 mww 0xb8050004 0x00000352 ;# 34000(ns)/40ns(25MHz) = 0x352 (850) From c1b8824d1936bd13a3edc11784e3f872ca3255db Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 19 Feb 2018 17:00:17 +0100 Subject: [PATCH 065/147] tcl/board: add DPTechnics DPT-Board-v1 it is Atheros AR9331 based IoT dev board. Change-Id: I6fc3cdea1bef49c53045018ff5acfec4d5610ba6 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4424 Tested-by: jenkins Reviewed-by: Paul Fertser --- tcl/board/dptechnics_dpt-board-v1.cfg | 32 +++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tcl/board/dptechnics_dpt-board-v1.cfg diff --git a/tcl/board/dptechnics_dpt-board-v1.cfg b/tcl/board/dptechnics_dpt-board-v1.cfg new file mode 100644 index 000000000..de31c7c09 --- /dev/null +++ b/tcl/board/dptechnics_dpt-board-v1.cfg @@ -0,0 +1,32 @@ +# Product page: +# https://www.dptechnics.com/en/products/dpt-board-v1.html +# +# JTAG is a 5 pin array located close to main module in following order: +# 1. JTAG TCK +# 2. JTAG TDO +# 3. JTAG TDI +# 4. JTAG TMS +# 5. GND The GND is located near letter G of word JTAG on board. +# +# Two RST pins are connected to: +# 1. GND +# 2. GPIO11 this pin is located near letter R of word RST. +# +# To enable EJTAG mode, GPIO11 (RST[1]) pin should be pulled up. For example +# with 10K resistor connected to V3.3 pin. +# +# This board is powered from micro USB connector. No real reset pin or button, for +# example RESET_L is available. + +source [find target/atheros_ar9331.cfg] + +$_TARGETNAME configure -event reset-init { + ar9331_25mhz_pll_init + sleep 1 + ar9331_ddr2_init +} + +set ram_boot_address 0xa0000000 +$_TARGETNAME configure -work-area-phys 0xa1FFE000 -work-area-size 0x1000 + +flash bank flash0 ath79 0 0 0 0 $_TARGETNAME cs0 From 36c3e0719d580b37b24a264fe6d0bf184531ccfc Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 10 Jul 2018 09:55:54 +0200 Subject: [PATCH 066/147] fpga/altera-10m50: add all device id add all currently know Intel (Alter) MAX 10 device ids Change-Id: I6a88fef222c8e206812499d41be863c3d89fa944 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4598 Tested-by: jenkins Reviewed-by: Paul Fertser --- tcl/fpga/altera-10m50.cfg | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/tcl/fpga/altera-10m50.cfg b/tcl/fpga/altera-10m50.cfg index 9d00daa83..d5af71059 100644 --- a/tcl/fpga/altera-10m50.cfg +++ b/tcl/fpga/altera-10m50.cfg @@ -1,6 +1,22 @@ -# Altera MAX10 10M50SAE144C8GES FPGA # see MAX 10 FPGA Device Architecture # Table 3-1: IDCODE Information for MAX 10 Devices -# Version Part Number Manuf. ID LSB -# 0000 0011 0001 1000 0101 000 0110 1110 1 -jtag newtap 10m50 tap -expected-id 0x031850dd -irlen 10 +# Intel MAX 10M02 0x31810dd +# Intel MAX 10M04 0x318a0dd +# Intel MAX 10M08 0x31820dd +# Intel MAX 10M16 0x31830dd +# Intel MAX 10M25 0x31840dd +# Intel MAX 10M40 0x318d0dd +# Intel MAX 10M50 0x31850dd +# Intel MAX 10M02 0x31010dd +# Intel MAX 10M04 0x310a0dd +# Intel MAX 10M08 0x31020dd +# Intel MAX 10M16 0x31030dd +# Intel MAX 10M25 0x31040dd +# Intel MAX 10M40 0x310d0dd +# Intel MAX 10M50 0x31050dd + +jtag newtap 10m50 tap -irlen 10 -expected-id 0x31810dd -expected-id 0x318a0dd \ + -expected-id 0x31820dd -expected-id 0x31830dd -expected-id 0x31840dd \ + -expected-id 0x318d0dd -expected-id 0x31850dd -expected-id 0x31010dd \ + -expected-id 0x310a0dd -expected-id 0x31020dd -expected-id 0x31030dd \ + -expected-id 0x31040dd -expected-id 0x310d0dd -expected-id 0x31050dd From c8c778882570c36ff51b83b9c7d1e575566bc4ce Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 28 Jun 2018 12:18:07 +0200 Subject: [PATCH 067/147] target|board: Add Intel (Altera) Arria 10 target and related board Target information about this SoC can be found here: https://www.altera.com/products/fpga/arria-series/arria-10/overview.html Achilles Instant-Development Kit Arria 10 SoC SoM: https://www.reflexces.com/products-solutions/development-kits/arria-10/achilles-instant-development-kit-arria-10-soc-som Change-Id: Id78c741be6a8b7d3a70f37d41088e47ee61b437a Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4583 Tested-by: jenkins Reviewed-by: Paul Fertser --- .../reflexces_achilles_i-dev_kit_arria10.cfg | 13 +++++ tcl/target/altera_fpgasoc_arria10.cfg | 56 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 tcl/board/reflexces_achilles_i-dev_kit_arria10.cfg create mode 100644 tcl/target/altera_fpgasoc_arria10.cfg diff --git a/tcl/board/reflexces_achilles_i-dev_kit_arria10.cfg b/tcl/board/reflexces_achilles_i-dev_kit_arria10.cfg new file mode 100644 index 000000000..a6e80650e --- /dev/null +++ b/tcl/board/reflexces_achilles_i-dev_kit_arria10.cfg @@ -0,0 +1,13 @@ +# Achilles Instant-Development Kit Arria 10 SoC SoM +# https://www.reflexces.com/products-solutions/achilles-instant-development-kit-arria-10-soc-som +# + +if { [info exists USE_EXTERNAL_DEBUGGER] } { + echo "Using external debugger" +} else { + source [find interface/altera-usb-blaster2.cfg] + usb_blaster_device_desc "Arria10 IDK" +} + +source [find fpga/altera-10m50.cfg] +source [find target/altera_fpgasoc_arria10.cfg] diff --git a/tcl/target/altera_fpgasoc_arria10.cfg b/tcl/target/altera_fpgasoc_arria10.cfg new file mode 100644 index 000000000..c9c5ab66f --- /dev/null +++ b/tcl/target/altera_fpgasoc_arria10.cfg @@ -0,0 +1,56 @@ +# Intel (Altera) Arria10 FPGA SoC + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME arria10 +} + +# ARM CoreSight Debug Access Port (dap HPS) +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} +jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_DAP_TAPID + +# Subsidiary TAP: fpga (tap) +# See Intel Arria 10 Handbook +# https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/hb/arria-10/a10_handbook.pdf +# Intel Arria 10 GX 160 0x02ee20dd +# Intel Arria 10 GX 220 0x02e220dd +# Intel Arria 10 GX 270 0x02ee30dd +# Intel Arria 10 GX 320 0x02e230dd +# Intel Arria 10 GX 480 0x02e240dd +# Intel Arria 10 GX 570 0x02ee50dd +# Intel Arria 10 GX 660 0x02e250dd +# Intel Arria 10 GX 900 0x02ee60dd +# Intel Arria 10 GX 1150 0x02e660dd +# Intel Arria 10 GT 900 0x02e260dd +# Intel Arria 10 GT 1150 0x02e060dd +# Intel Arria 10 SX 160 0x02e620dd +# Intel Arria 10 SX 220 0x02e020dd +# Intel Arria 10 SX 270 0x02e630dd +# Intel Arria 10 SX 320 0x02e030dd +# Intel Arria 10 SX 480 0x02e040dd +# Intel Arria 10 SX 570 0x02e650dd +# Intel Arria 10 SX 660 0x02e050dd +jtag newtap $_CHIPNAME.fpga tap -irlen 10 -expected-id 0x02ee20dd -expected-id 0x02e220dd \ + -expected-id 0x02ee30dd -expected-id 0x02e230dd -expected-id 0x02e240dd \ + -expected-id 0x02ee50dd -expected-id 0x02e250dd -expected-id 0x02ee60dd \ + -expected-id 0x02e660dd -expected-id 0x02e260dd -expected-id 0x02e060dd \ + -expected-id 0x02e620dd -expected-id 0x02e020dd -expected-id 0x02e630dd \ + -expected-id 0x02e030dd -expected-id 0x02e040dd -expected-id 0x02e650dd \ + -expected-id 0x02e050dd + +set _TARGETNAME $_CHIPNAME.cpu + +# +# Cortex-A9 target + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +target create $_TARGETNAME.0 cortex_a -dap $_CHIPNAME.dap -coreid 0 +target create $_TARGETNAME.1 cortex_a -dap $_CHIPNAME.dap -coreid 1 \ + -defer-examine +target smp $_TARGETNAME.0 $_TARGETNAME.1 From d537cce7ef49bf2f4bc81cf016f784a9adf2537a Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 25 Jul 2018 22:51:51 +0200 Subject: [PATCH 068/147] target/riscv: fix compile error with gcc 8.1.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix compile error: src/target/riscv/riscv-011.c: In function ‘slot_offset’: src/target/riscv/riscv-011.c:238:4: error: this statement may fall through [-Werror=implicit-fallthrough=] switch (slot) { ^~~~~~ src/target/riscv/riscv-011.c:243:3: note: here case 64: ^~~~ Fixes: a51ab8ddf63a ("Add RISC-V support.") Change-Id: I7fa86b305bd90cc590fd4359c3698632d44712e5 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4618 Tested-by: jenkins Reviewed-by: Jiri Kastner Reviewed-by: Oleksij Rempel Reviewed-by: Tim Newsome Reviewed-by: Paul Fertser --- src/target/riscv/riscv-011.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index f2a68698b..498da5ad5 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -240,6 +240,7 @@ static unsigned int slot_offset(const struct target *target, slot_t slot) case SLOT1: return 5; case SLOT_LAST: return info->dramsize-1; } + break; case 64: switch (slot) { case SLOT0: return 4; From 5e13e0114105c51a8afa6ac2cb40523ac269ad78 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Fri, 1 Jun 2018 18:31:49 +0200 Subject: [PATCH 069/147] server: explicitly call "shutdown" when catch CTRL-C or a signal Every TCL command can be renamed (or deleted) and then replaced by a TCL proc that has the same name of the original TCL command. This can be used either to completely replace an existing command or to wrap the original command to extend its functionality. This applies also to the OpenOCD command "shutdown" and can be useful, for example, to set back some default value to the target before quitting OpenOCD. E.g. (TCL code): rename shutdown original_shutdown proc shutdown {} { puts "This is my implementation of shutdown" # my own stuff before exit OpenOCD original_shutdown } Unfortunately, sending a signal (or pressing CTRL-C) to terminate OpenOCD doesn't trigger calling the original "shutdown" command nor its (eventual) replacement. Detect if the main loop is terminated by an external signal and in such case execute explicitly the command "shutdown". Replace with enum the magic numbers assumed by "shutdown_openocd". Please notice that it's possible to write a custom "shutdown" TCL proc that does not call the original "shutdown" command. This is useful, for example, to prevent the user to quit OpenOCD by typing "shutdown" in the telnet session. Such case will not prevent OpenOCD to terminate when receiving a signal; OpenOCD will quit after executing the custom "shutdown" command. Change-Id: I86b8f9eab8dbd7a28dad58b8cafd97caa7a82f43 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4551 Tested-by: jenkins Reviewed-by: Tomas Vanek --- doc/openocd.texi | 13 +++++++++++++ src/server/server.c | 32 ++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 43ebf8cb2..16aa26bf5 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -7390,6 +7390,19 @@ Useful in connection with script files Close the OpenOCD server, disconnecting all clients (GDB, telnet, other). If option @option{error} is used, OpenOCD will return a non-zero exit code to the parent process. + +Like any TCL commands, also @command{shutdown} can be redefined, e.g.: +@example +# redefine shutdown +rename shutdown original_shutdown +proc shutdown @{@} @{ + puts "This is my implementation of shutdown" + # my own stuff before exit OpenOCD + original_shutdown +@} +@end example +If user types CTRL-C or kills OpenOCD, either the command @command{shutdown} +or its replacement will be automatically executed before OpenOCD exits. @end deffn @anchor{debuglevel} diff --git a/src/server/server.c b/src/server/server.c index 06a2f39de..bc5856ccc 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -46,9 +46,13 @@ static struct service *services; -/* shutdown_openocd == 1: exit the main event loop, and quit the - * debugger; 2: quit with non-zero return code */ -static int shutdown_openocd; +enum shutdown_reason { + CONTINUE_MAIN_LOOP, /* stay in main event loop */ + SHUTDOWN_REQUESTED, /* set by shutdown command; exit the event loop and quit the debugger */ + SHUTDOWN_WITH_ERROR_CODE, /* set by shutdown command; quit with non-zero return code */ + SHUTDOWN_WITH_SIGNAL_CODE /* set by sig_handler; exec shutdown then exit with signal as return code */ +}; +static enum shutdown_reason shutdown_openocd = CONTINUE_MAIN_LOOP; /* store received signal to exit application by killing ourselves */ static int last_signal; @@ -413,7 +417,7 @@ int server_loop(struct command_context *command_context) LOG_ERROR("couldn't set SIGPIPE to SIG_IGN"); #endif - while (!shutdown_openocd) { + while (shutdown_openocd == CONTINUE_MAIN_LOOP) { /* monitor sockets for activity */ fd_max = 0; FD_ZERO(&read_fds); @@ -537,7 +541,7 @@ int server_loop(struct command_context *command_context) service->type == CONNECTION_STDINOUT) { /* if connection uses a pipe then * shutdown openocd on error */ - shutdown_openocd = 1; + shutdown_openocd = SHUTDOWN_REQUESTED; } remove_connection(service, c); LOG_INFO("dropped '%s' connection", @@ -555,20 +559,24 @@ int server_loop(struct command_context *command_context) MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) - shutdown_openocd = 1; + shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE; } #endif } - return shutdown_openocd != 2 ? ERROR_OK : ERROR_FAIL; + /* when quit for signal or CTRL-C, run (eventually user implemented) "shutdown" */ + if (shutdown_openocd == SHUTDOWN_WITH_SIGNAL_CODE) + command_run_line(command_context, "shutdown"); + + return shutdown_openocd == SHUTDOWN_WITH_ERROR_CODE ? ERROR_FAIL : ERROR_OK; } void sig_handler(int sig) { /* store only first signal that hits us */ - if (!shutdown_openocd) { + if (shutdown_openocd == CONTINUE_MAIN_LOOP) { + shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE; last_signal = sig; - shutdown_openocd = 1; LOG_DEBUG("Terminating on Signal %d", sig); } else LOG_DEBUG("Ignored extra Signal %d", sig); @@ -578,7 +586,7 @@ void sig_handler(int sig) #ifdef _WIN32 BOOL WINAPI ControlHandler(DWORD dwCtrlType) { - shutdown_openocd = 1; + shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE; return TRUE; } #else @@ -702,11 +710,11 @@ COMMAND_HANDLER(handle_shutdown_command) { LOG_USER("shutdown command invoked"); - shutdown_openocd = 1; + shutdown_openocd = SHUTDOWN_REQUESTED; if (CMD_ARGC == 1) { if (!strcmp(CMD_ARGV[0], "error")) { - shutdown_openocd = 2; + shutdown_openocd = SHUTDOWN_WITH_ERROR_CODE; return ERROR_FAIL; } } From 64bb6244794075b254ce1f08e8d2b1f2818ced51 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 19 Jul 2018 09:38:05 +0200 Subject: [PATCH 070/147] zy1000: fix compile error with gcc 8.1.1 The fall-through comment is not taken in consideration by gcc 8.1.1 because it is inside the braces of a C-code block. Move the comment outside the C block. Change-Id: I22d87b2dee109fb8bcf2071ac55fdf7171ffcf4b Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4614 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/jtag/zy1000/zy1000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jtag/zy1000/zy1000.c b/src/jtag/zy1000/zy1000.c index 67d990700..4e53dd1f7 100644 --- a/src/jtag/zy1000/zy1000.c +++ b/src/jtag/zy1000/zy1000.c @@ -265,8 +265,8 @@ COMMAND_HANDLER(handle_power_command) bool enable; COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable); setPower(enable); - /* fall through */ } + /* fall through */ case 0: LOG_INFO("Target power %s", savePower ? "on" : "off"); break; From d92773b2057ef163cd062b2408b99bdc3404f905 Mon Sep 17 00:00:00 2001 From: Bohdan Tymkiv Date: Thu, 3 May 2018 22:50:58 +0300 Subject: [PATCH 071/147] flash/nor/tcl.c: fix flash bank bounds check in 'flash fill' command handler Steps to reproduce ( STM32F103 'Blue Pill', 128KiB of flash ): > flash fillh 0x0801FFFE 00 1 wrote 2 bytes to 0x0801fffe in 0.019088s (0.102 KiB/s) > flash fillw 0x0801FFFE 00 1 Error: stm32f1x.cpu -- clearing lockup after double fault Error: error waiting for target flash write algorithm Error: error writing to flash at address 0x08000000 at offset 0x0001fffe Change-Id: I145092ec5e45bc586b3df48bf37c38c9226915c1 Signed-off-by: Bohdan Tymkiv Reviewed-on: http://openocd.zylin.com/4516 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/tcl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index b4f375fe7..95ca8192f 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -506,7 +506,7 @@ COMMAND_HANDLER(handle_flash_fill_command) if (count == 0) return ERROR_OK; - if (address + count >= bank->base + bank->size) { + if (address + count * wordsize > bank->base + bank->size) { LOG_ERROR("Cannot cross flash bank borders"); return ERROR_FAIL; } From 6738e447c5c010c4b3451e3714df86e9ab653e1f Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 23 May 2018 00:55:03 +0200 Subject: [PATCH 072/147] target/arm_adi_v5: add command "dpreg" For very low level debug or development around DAP, it is useful to have direct access to DP registers. Add command "dpreg" by mimic the syntax of the existing "apreg" command: $dap_name dpreg reg [value] Change-Id: Ic4ab451eb5e74453133adee61050b4c6f656ffa3 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4612 Tested-by: jenkins Reviewed-by: Tomas Vanek --- doc/openocd.texi | 12 ++++++++++++ src/target/arm_adi_v5.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index 16aa26bf5..def0c9d6c 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4087,6 +4087,18 @@ or set a new value @var{value}. Select AP @var{num}, defaulting to 0. @end deffn +@deffn Command {$dap_name dpreg} reg [value] +Displays the content of DP register at address @var{reg}, or set it to a new +value @var{value}. + +In case of SWD, @var{reg} is a value in packed format +@math{dpbanksel << 4 | addr} and assumes values 0, 4, 8 ... 0xfc. +In case of JTAG it only assumes values 0, 4, 8 and 0xc. + +@emph{Note:} Consider using @command{poll off} to avoid any disturbing +background activity by OpenOCD while you are operating at such low-level. +@end deffn + @deffn Command {$dap_name baseaddr} [num] Displays debug base address from MEM-AP @var{num}, defaulting to the currently selected AP. diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 4dc2594cf..dc5c80393 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1772,6 +1772,37 @@ COMMAND_HANDLER(dap_apreg_command) return retval; } +COMMAND_HANDLER(dap_dpreg_command) +{ + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); + uint32_t reg, value; + int retval; + + if (CMD_ARGC < 1 || CMD_ARGC > 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg); + if (reg >= 256 || (reg & 3)) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (CMD_ARGC == 2) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + retval = dap_queue_dp_write(dap, reg, value); + } else { + retval = dap_queue_dp_read(dap, reg, &value); + } + if (retval == ERROR_OK) + retval = dap_run(dap); + + if (retval != ERROR_OK) + return retval; + + if (CMD_ARGC == 1) + command_print(CMD_CTX, "0x%08" PRIx32, value); + + return retval; +} + COMMAND_HANDLER(dap_ti_be_32_quirks_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); @@ -1836,6 +1867,14 @@ const struct command_registration dap_instance_commands[] = { "(reg is byte address of a word register, like 0 4 8...)", .usage = "ap_num reg [value]", }, + { + .name = "dpreg", + .handler = dap_dpreg_command, + .mode = COMMAND_EXEC, + .help = "read/write a register from DP " + "(reg is byte address (bank << 4 | reg) of a word register, like 0 4 8...)", + .usage = "reg [value]", + }, { .name = "baseaddr", .handler = dap_baseaddr_command, From 7ce8624dbfc3c26a4dfb7ca089a99ccf52a8539b Mon Sep 17 00:00:00 2001 From: Jim Paris Date: Fri, 20 Jul 2018 11:14:34 -0400 Subject: [PATCH 073/147] nrf5: add free_driver_priv Change-Id: I429a9868deb0c4b51f47a4bbad844bdc348e8d21 Signed-off-by: Jim Paris Reviewed-on: http://openocd.zylin.com/4608 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/nrf5.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index ad80e02e0..16459c7f8 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -108,6 +108,7 @@ enum nrf5_nvmc_config_bits { struct nrf5_info { uint32_t code_page_size; + uint32_t refcount; struct { bool probed; @@ -869,6 +870,18 @@ static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, return chip->bank[bank->bank_number].write(bank, chip, buffer, offset, count); } +static void nrf5_free_driver_priv(struct flash_bank *bank) +{ + struct nrf5_info *chip = bank->driver_priv; + if (chip == NULL) + return; + + chip->refcount--; + if (chip->refcount == 0) { + free(chip); + bank->driver_priv = NULL; + } +} FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) { @@ -904,6 +917,7 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) break; } + chip->refcount++; chip->bank[bank->bank_number].probed = false; bank->driver_priv = chip; @@ -1128,6 +1142,7 @@ struct flash_driver nrf5_flash = { .auto_probe = nrf5_auto_probe, .erase_check = default_flash_blank_check, .protect_check = nrf5_protect_check, + .free_driver_priv = nrf5_free_driver_priv, }; /* We need to retain the flash-driver name as well as the commands @@ -1145,4 +1160,5 @@ struct flash_driver nrf51_flash = { .auto_probe = nrf5_auto_probe, .erase_check = default_flash_blank_check, .protect_check = nrf5_protect_check, + .free_driver_priv = nrf5_free_driver_priv, }; From 9ec306e95a07ca9a5a72619618f5ed54e1fc8920 Mon Sep 17 00:00:00 2001 From: Masatoshi Tateishi Date: Mon, 10 Apr 2017 08:48:44 +0900 Subject: [PATCH 074/147] rtos: add support for NuttX This patch introduces RTOS support for NuttX. Currently, only ARM Cortex-M (both FPU and FPU-less) targets are supported. To use, add the following lines to ~/.gdbinit. define hookpost-file eval "monitor nuttx.pid_offset %d", &((struct tcb_s *)(0))->pid eval "monitor nuttx.xcpreg_offset %d", &((struct tcb_s *)(0))->xcp.regs eval "monitor nuttx.state_offset %d", &((struct tcb_s *)(0))->task_state eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name) end And please make sure the above values are the same as in src/rtos/nuttx_header.h Change-Id: I2aaf8644d24dfb84b500516a9685382d5d8fe48f Signed-off-by: Masayuki Ishikawa Signed-off-by: Masatoshi Tateishi Signed-off-by: Nobuto Kobayashi Reviewed-on: http://openocd.zylin.com/4103 Tested-by: jenkins Reviewed-by: Alan Carvalho de Assis Reviewed-by: Tomas Vanek --- doc/openocd.texi | 5 +- src/rtos/Makefile.am | 4 +- src/rtos/nuttx.c | 405 ++++++++++++++++++++++++++++++++++++++++ src/rtos/nuttx_header.h | 71 +++++++ src/rtos/rtos.c | 2 + 5 files changed, 485 insertions(+), 2 deletions(-) create mode 100644 src/rtos/nuttx.c create mode 100644 src/rtos/nuttx_header.h diff --git a/doc/openocd.texi b/doc/openocd.texi index def0c9d6c..1a89a53de 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4441,7 +4441,7 @@ The value should normally correspond to a static mapping for the @item @code{-rtos} @var{rtos_type} -- enable rtos support for target, @var{rtos_type} can be one of @option{auto}, @option{eCos}, @option{ThreadX}, @option{FreeRTOS}, @option{linux}, @option{ChibiOS}, -@option{embKernel}, @option{mqx}, @option{uCOS-III} +@option{embKernel}, @option{mqx}, @option{uCOS-III}, @option{nuttx} @xref{gdbrtossupport,,RTOS Support}. @item @code{-defer-examine} -- skip target examination at initial JTAG chain @@ -9806,6 +9806,7 @@ Currently supported rtos's include: @item @option{embKernel} @item @option{mqx} @item @option{uCOS-III} +@item @option{nuttx} @end itemize @quotation Note @@ -9841,6 +9842,8 @@ Rtos::sListSuspended, Rtos::sMaxPriorities, Rtos::sCurrentTaskCount. _mqx_kernel_data, MQX_init_struct. @item uC/OS-III symbols OSRunning, OSTCBCurPtr, OSTaskDbgListPtr, OSTaskQty +@item nuttx symbols +g_readytorun, g_tasklisttable @end table For most RTOS supported the above symbols will be exported by default. However for diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am index c59ee3f8c..c8c402303 100644 --- a/src/rtos/Makefile.am +++ b/src/rtos/Makefile.am @@ -15,6 +15,7 @@ noinst_LTLIBRARIES += %D%/librtos.la %D%/embKernel.c \ %D%/mqx.c \ %D%/uCOS-III.c \ + %D%/nuttx.c \ %D%/rtos.h \ %D%/rtos_standard_stackings.h \ %D%/rtos_ecos_stackings.h \ @@ -22,7 +23,8 @@ noinst_LTLIBRARIES += %D%/librtos.la %D%/rtos_chibios_stackings.h \ %D%/rtos_embkernel_stackings.h \ %D%/rtos_mqx_stackings.h \ - %D%/rtos_ucos_iii_stackings.h + %D%/rtos_ucos_iii_stackings.h \ + %D%/nuttx_header.h %C%_librtos_la_CFLAGS = $(AM_CFLAGS) diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c new file mode 100644 index 000000000..284b968cc --- /dev/null +++ b/src/rtos/nuttx.c @@ -0,0 +1,405 @@ +/*************************************************************************** + * Copyright 2016,2017 Sony Video & Sound Products Inc. * + * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com * + * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com * + * * + * 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 . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "target/target.h" +#include "target/target_type.h" +#include "target/armv7m.h" +#include "target/cortex_m.h" +#include "rtos.h" +#include "helper/log.h" +#include "helper/types.h" +#include "server/gdb_server.h" + +#include "nuttx_header.h" + + +int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size); + +#ifdef CONFIG_DISABLE_SIGNALS +#define SIG_QUEUE_NUM 0 +#else +#define SIG_QUEUE_NUM 1 +#endif /* CONFIG_DISABLE_SIGNALS */ + +#ifdef CONFIG_DISABLE_MQUEUE +#define M_QUEUE_NUM 0 +#else +#define M_QUEUE_NUM 2 +#endif /* CONFIG_DISABLE_MQUEUE */ + +#ifdef CONFIG_PAGING +#define PAGING_QUEUE_NUM 1 +#else +#define PAGING_QUEUE_NUM 0 +#endif /* CONFIG_PAGING */ + + +#define TASK_QUEUE_NUM (6 + SIG_QUEUE_NUM + M_QUEUE_NUM + PAGING_QUEUE_NUM) + + +/* see nuttx/sched/os_start.c */ +static char *nuttx_symbol_list[] = { + "g_readytorun", /* 0: must be top of this array */ + "g_tasklisttable", + NULL +}; + +/* see nuttx/include/nuttx/sched.h */ +struct tcb { + uint32_t flink; + uint32_t blink; + uint8_t dat[512]; +}; + +struct { + uint32_t addr; + uint32_t prio; +} g_tasklist[TASK_QUEUE_NUM]; + +static char *task_state_str[] = { + "INVALID", + "PENDING", + "READYTORUN", + "RUNNING", + "INACTIVE", + "WAIT_SEM", +#ifndef CONFIG_DISABLE_SIGNALS + "WAIT_SIG", +#endif /* CONFIG_DISABLE_SIGNALS */ +#ifndef CONFIG_DISABLE_MQUEUE + "WAIT_MQNOTEMPTY", + "WAIT_MQNOTFULL", +#endif /* CONFIG_DISABLE_MQUEUE */ +#ifdef CONFIG_PAGING + "WAIT_PAGEFILL", +#endif /* CONFIG_PAGING */ +}; + +/* see arch/arm/include/armv7-m/irq_cmnvector.h */ +static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = { + { 0x28, 32 }, /* r0 */ + { 0x2c, 32 }, /* r1 */ + { 0x30, 32 }, /* r2 */ + { 0x34, 32 }, /* r3 */ + { 0x08, 32 }, /* r4 */ + { 0x0c, 32 }, /* r5 */ + { 0x10, 32 }, /* r6 */ + { 0x14, 32 }, /* r7 */ + { 0x18, 32 }, /* r8 */ + { 0x1c, 32 }, /* r9 */ + { 0x20, 32 }, /* r10 */ + { 0x24, 32 }, /* r11 */ + { 0x38, 32 }, /* r12 */ + { 0, 32 }, /* sp */ + { 0x3c, 32 }, /* lr */ + { 0x40, 32 }, /* pc */ + { 0x44, 32 }, /* xPSR */ +}; + + +static const struct rtos_register_stacking nuttx_stacking_cortex_m = { + 0x48, /* stack_registers_size */ + -1, /* stack_growth_direction */ + 17, /* num_output_registers */ + 0, /* stack_alignment */ + nuttx_stack_offsets_cortex_m /* register_offsets */ +}; + +static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = { + { 0x6c, 32 }, /* r0 */ + { 0x70, 32 }, /* r1 */ + { 0x74, 32 }, /* r2 */ + { 0x78, 32 }, /* r3 */ + { 0x08, 32 }, /* r4 */ + { 0x0c, 32 }, /* r5 */ + { 0x10, 32 }, /* r6 */ + { 0x14, 32 }, /* r7 */ + { 0x18, 32 }, /* r8 */ + { 0x1c, 32 }, /* r9 */ + { 0x20, 32 }, /* r10 */ + { 0x24, 32 }, /* r11 */ + { 0x7c, 32 }, /* r12 */ + { 0, 32 }, /* sp */ + { 0x80, 32 }, /* lr */ + { 0x84, 32 }, /* pc */ + { 0x88, 32 }, /* xPSR */ +}; + +static const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = { + 0x8c, /* stack_registers_size */ + -1, /* stack_growth_direction */ + 17, /* num_output_registers */ + 0, /* stack_alignment */ + nuttx_stack_offsets_cortex_m_fpu /* register_offsets */ +}; + +static int pid_offset = PID; +static int state_offset = STATE; +static int name_offset = NAME; +static int xcpreg_offset = XCPREG; +static int name_size = NAME_SIZE; + +static int rcmd_offset(const char *cmd, const char *name) +{ + if (strncmp(cmd, name, strlen(name))) + return -1; + + if (strlen(cmd) <= strlen(name) + 1) + return -1; + + return atoi(cmd + strlen(name)); +} + +static int nuttx_thread_packet(struct connection *connection, + char const *packet, int packet_size) +{ + char cmd[GDB_BUFFER_SIZE / 2] = ""; + + if (!strncmp(packet, "qRcmd", 5)) { + size_t len = unhexify((uint8_t *)cmd, packet + 6, sizeof(cmd)); + int offset; + + if (len <= 0) + goto pass; + + offset = rcmd_offset(cmd, "nuttx.pid_offset"); + + if (offset >= 0) { + LOG_INFO("pid_offset: %d", offset); + pid_offset = offset; + goto retok; + } + + offset = rcmd_offset(cmd, "nuttx.state_offset"); + + if (offset >= 0) { + LOG_INFO("state_offset: %d", offset); + state_offset = offset; + goto retok; + } + + offset = rcmd_offset(cmd, "nuttx.name_offset"); + + if (offset >= 0) { + LOG_INFO("name_offset: %d", offset); + name_offset = offset; + goto retok; + } + + offset = rcmd_offset(cmd, "nuttx.xcpreg_offset"); + + if (offset >= 0) { + LOG_INFO("xcpreg_offset: %d", offset); + xcpreg_offset = offset; + goto retok; + } + + offset = rcmd_offset(cmd, "nuttx.name_size"); + + if (offset >= 0) { + LOG_INFO("name_size: %d", offset); + name_size = offset; + goto retok; + } + } +pass: + return rtos_thread_packet(connection, packet, packet_size); +retok: + gdb_put_packet(connection, "OK", 2); + return ERROR_OK; +} + + +static bool nuttx_detect_rtos(struct target *target) +{ + if ((target->rtos->symbols != NULL) && + (target->rtos->symbols[0].address != 0) && + (target->rtos->symbols[1].address != 0)) { + return true; + } + return false; +} + +static int nuttx_create(struct target *target) +{ + + target->rtos->gdb_thread_packet = nuttx_thread_packet; + LOG_INFO("target type name = %s", target->type->name); + return 0; +} + +static int nuttx_update_threads(struct rtos *rtos) +{ + uint32_t thread_count; + struct tcb tcb; + int ret; + uint32_t head; + uint32_t tcb_addr; + uint32_t i; + uint8_t state; + + if (rtos->symbols == NULL) { + LOG_ERROR("No symbols for NuttX"); + return -3; + } + + /* free previous thread details */ + rtos_free_threadlist(rtos); + + ret = target_read_buffer(rtos->target, rtos->symbols[1].address, + sizeof(g_tasklist), (uint8_t *)&g_tasklist); + if (ret) { + LOG_ERROR("target_read_buffer : ret = %d\n", ret); + return ERROR_FAIL; + } + + thread_count = 0; + + for (i = 0; i < TASK_QUEUE_NUM; i++) { + + if (g_tasklist[i].addr == 0) + continue; + + ret = target_read_u32(rtos->target, g_tasklist[i].addr, + &head); + + if (ret) { + LOG_ERROR("target_read_u32 : ret = %d\n", ret); + return ERROR_FAIL; + } + + /* readytorun head is current thread */ + if (g_tasklist[i].addr == rtos->symbols[0].address) + rtos->current_thread = head; + + + tcb_addr = head; + while (tcb_addr) { + struct thread_detail *thread; + ret = target_read_buffer(rtos->target, tcb_addr, + sizeof(tcb), (uint8_t *)&tcb); + if (ret) { + LOG_ERROR("target_read_buffer : ret = %d\n", + ret); + return ERROR_FAIL; + } + thread_count++; + + rtos->thread_details = realloc(rtos->thread_details, + sizeof(struct thread_detail) * thread_count); + thread = &rtos->thread_details[thread_count - 1]; + thread->threadid = tcb_addr; + thread->exists = true; + + state = tcb.dat[state_offset - 8]; + thread->extra_info_str = NULL; + if (state < sizeof(task_state_str)/sizeof(char *)) { + thread->extra_info_str = malloc(256); + snprintf(thread->extra_info_str, 256, "pid:%d, %s", + tcb.dat[pid_offset - 8] | + tcb.dat[pid_offset - 8 + 1] << 8, + task_state_str[state]); + } + + if (name_offset) { + thread->thread_name_str = malloc(name_size + 1); + snprintf(thread->thread_name_str, name_size, + "%s", (char *)&tcb.dat[name_offset - 8]); + } else { + thread->thread_name_str = malloc(sizeof("None")); + strcpy(thread->thread_name_str, "None"); + } + + tcb_addr = tcb.flink; + } + } + rtos->thread_count = thread_count; + + return 0; +} + + +/* + * thread_id = tcb address; + */ +static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + char **hex_reg_list) { + int retval; + + *hex_reg_list = NULL; + + /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */ + bool cm4_fpu_enabled = false; + struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); + if (is_armv7m(armv7m_target)) { + if (armv7m_target->fp_feature == FPv4_SP) { + /* Found ARM v7m target which includes a FPU */ + uint32_t cpacr; + + retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read CPACR register to check FPU state"); + return -1; + } + + /* Check if CP10 and CP11 are set to full access. */ + if (cpacr & 0x00F00000) { + /* Found target with enabled FPU */ + cm4_fpu_enabled = 1; + } + } + } + + const struct rtos_register_stacking *stacking; + if (cm4_fpu_enabled) + stacking = &nuttx_stacking_cortex_m_fpu; + else + stacking = &nuttx_stacking_cortex_m; + + return rtos_generic_stack_read(rtos->target, stacking, + (uint32_t)thread_id + xcpreg_offset, hex_reg_list); +} + +static int nuttx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +{ + unsigned int i; + + *symbol_list = (symbol_table_elem_t *) calloc(1, + sizeof(symbol_table_elem_t) * ARRAY_SIZE(nuttx_symbol_list)); + + for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++) + (*symbol_list)[i].symbol_name = nuttx_symbol_list[i]; + + return 0; +} + +struct rtos_type nuttx_rtos = { + .name = "nuttx", + .detect_rtos = nuttx_detect_rtos, + .create = nuttx_create, + .update_threads = nuttx_update_threads, + .get_thread_reg_list = nuttx_get_thread_reg_list, + .get_symbol_list_to_lookup = nuttx_get_symbol_list_to_lookup, +}; + diff --git a/src/rtos/nuttx_header.h b/src/rtos/nuttx_header.h new file mode 100644 index 000000000..00b0484ee --- /dev/null +++ b/src/rtos/nuttx_header.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright 2016,2017 Sony Video & Sound Products Inc. * + * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com * + * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com * + * * + * 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 . * + ***************************************************************************/ + +#ifndef OPENOCD_RTOS_NUTTX_HEADER_H +#define OPENOCD_RTOS_NUTTX_HEADER_H + +/* gdb script to update the header file + according to kernel version and build option + before executing function awareness + kernel symbol must be loaded : symbol nuttx + +define awareness + set logging off + set logging file nuttx_header.h + set logging on + + printf "#define PID %p\n",&((struct tcb_s *)(0))->pid + printf "#define XCPREG %p\n",&((struct tcb_s *)(0))->xcp.regs + printf "#define STATE %p\n",&((struct tcb_s *)(0))->task_state + printf "#define NAME %p\n",&((struct tcb_s *)(0))->name + printf "#define NAME_SIZE %d\n",sizeof(((struct tcb_s *)(0))->name) + end + + + OR ~/.gdbinit + + +define hookpost-file + + if &g_readytorun != 0 + eval "monitor nuttx.pid_offset %d", &((struct tcb_s *)(0))->pid + eval "monitor nuttx.xcpreg_offset %d", &((struct tcb_s *)(0))->xcp.regs + eval "monitor nuttx.state_offset %d", &((struct tcb_s *)(0))->task_state + eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name + eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name) + end + +end + +*/ + +/* default offset */ +#define PID 0xc +#define XCPREG 0x70 +#define STATE 0x19 +#define NAME 0xb8 +#define NAME_SIZE 32 + +/* defconfig of nuttx */ +/* #define CONFIG_DISABLE_SIGNALS */ +#define CONFIG_DISABLE_MQUEUE +/* #define CONFIG_PAGING */ + + +#endif /* OPENOCD_RTOS_NUTTX_HEADER_H */ diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index 1fee5b084..1b3a47f9c 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -35,6 +35,7 @@ extern struct rtos_type ChibiOS_rtos; extern struct rtos_type embKernel_rtos; extern struct rtos_type mqx_rtos; extern struct rtos_type uCOS_III_rtos; +extern struct rtos_type nuttx_rtos; static struct rtos_type *rtos_types[] = { &ThreadX_rtos, @@ -45,6 +46,7 @@ static struct rtos_type *rtos_types[] = { &embKernel_rtos, &mqx_rtos, &uCOS_III_rtos, + &nuttx_rtos, NULL }; From 9bcd2b2fa3709a6653ff2f7ea8d0af5d4be790f0 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Mon, 19 Dec 2016 20:09:08 +0100 Subject: [PATCH 075/147] server/server: Add ability to remove services Add the ability to remove services while OpenOCD is running. Change-Id: I4067916fda6d03485463fa40901b40484d94e24e Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4054 Tested-by: jenkins Reviewed-by: Fredrik Hederstierna Reviewed-by: Tomas Vanek --- src/server/server.c | 29 +++++++++++++++++++++++++++++ src/server/server.h | 1 + 2 files changed, 30 insertions(+) diff --git a/src/server/server.c b/src/server/server.c index bc5856ccc..f8273d42d 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -364,6 +364,35 @@ static void remove_connections(struct service *service) } } +int remove_service(const char *name, const char *port) +{ + struct service *tmp; + struct service *prev; + + prev = services; + + for (tmp = services; tmp; prev = tmp, tmp = tmp->next) { + if (!strcmp(tmp->name, name) && !strcmp(tmp->port, port)) { + remove_connections(tmp); + + if (tmp == services) + services = tmp->next; + else + prev->next = tmp->next; + + if (tmp->type != CONNECTION_STDINOUT) + close_socket(tmp->fd); + + free(tmp->priv); + free_service(tmp); + + return ERROR_OK; + } + } + + return ERROR_OK; +} + static int remove_services(void) { struct service *c = services; diff --git a/src/server/server.h b/src/server/server.h index d4eae9424..96e0b48ef 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -78,6 +78,7 @@ int add_service(char *name, const char *port, int max_connections, new_connection_handler_t new_connection_handler, input_handler_t in_handler, connection_closed_handler_t close_handler, void *priv); +int remove_service(const char *name, const char *port); int server_preinit(void); int server_init(struct command_context *cmd_ctx); From c04a59286ea2ba014fbd6f02b8c1072c8b29b924 Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Tue, 31 Jul 2018 10:05:36 -0700 Subject: [PATCH 076/147] target/cortex_m: fix incorrect comment The code sets C_MASKINTS if that bit is not already set (correctly). Fix the comment to agree. Change-Id: If4543e2660a9fa2cdabb2d2698427a6c8d9a274c Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4620 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/cortex_m.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 03dc51572..f18694672 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -165,7 +165,7 @@ static int cortex_m_single_step_core(struct target *target) struct armv7m_common *armv7m = &cortex_m->armv7m; int retval; - /* Mask interrupts before clearing halt, if done already. This avoids + /* Mask interrupts before clearing halt, if not done already. This avoids * Erratum 377497 (fixed in r1p0) where setting MASKINTS while clearing * HALT can put the core into an unknown state. */ From 1eeb547abc0aaff65343d1898db905c4706031bd Mon Sep 17 00:00:00 2001 From: Dominik Peklo Date: Sat, 7 Jul 2018 17:16:43 +1000 Subject: [PATCH 077/147] tcl/target/stm32f0x: Allow overriding the Flash bank size Copy & paste from another stm32 target. Change-Id: I0f6cbcec974ce70c23c1850526354106caee1172 Signed-off-by: Dominik Peklo Reviewed-on: http://openocd.zylin.com/4575 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/target/stm32f0x.cfg | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tcl/target/stm32f0x.cfg b/tcl/target/stm32f0x.cfg index b8c0de94c..baac9b68d 100644 --- a/tcl/target/stm32f0x.cfg +++ b/tcl/target/stm32f0x.cfg @@ -22,6 +22,14 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x1000 } +# Allow overriding the Flash bank size +if { [info exists FLASH_SIZE] } { + set _FLASH_SIZE $FLASH_SIZE +} else { + # autodetect size + set _FLASH_SIZE 0 +} + #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID @@ -41,7 +49,7 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE # flash size will be probed set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME stm32f1x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME # adapter speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz adapter_khz 1000 From f8367dbb4976474ac0a99f20b8028a1721f0c82e Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 22 Feb 2018 09:42:59 +0100 Subject: [PATCH 078/147] tcl/target: add Allwinner V3s SoC support Change-Id: I2459d2b137050985b7301047f9651951d72d9e9e Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4427 Tested-by: jenkins Reviewed-by: Paul Fertser --- tcl/target/allwinner_v3s.cfg | 71 ++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 tcl/target/allwinner_v3s.cfg diff --git a/tcl/target/allwinner_v3s.cfg b/tcl/target/allwinner_v3s.cfg new file mode 100644 index 000000000..32fd18872 --- /dev/null +++ b/tcl/target/allwinner_v3s.cfg @@ -0,0 +1,71 @@ +# This is the config for an Allwinner V3/V3s (sun8iw8). +# +# Notes: +# - Single core ARM Cortex-A7 with a maximum frequency of 1.2 GHz. +# - Thumb-2 Technology +# - Support NEON Advanced SIMD(Single Instruction Multiple Data)instruction +# for acceleration of media and signal processing functions +# - Support Large Physical Address Extensions(LPAE) +# - VFPv4 Floating Point Unit +# - 32KB L1 Instruction cache and 32KB L1 Data cache +# - 128KB L2 cache +# - has some integrated DDR2 RAM. +# +# Pins related for debug and bootstrap: +# JTAG +# JTAG_TMS PF0, SDC0_D1 +# JTAG_TDI PF1, SDC0_D0 +# JTAG_TDO PF3, SDC0_CMD +# JTAG_TCK PF5, SDC0_D2 +# UART +# None of UART ports seems to be enabled by ROM. +# UART0_TX PF2, SDC0_CLK Per default disabled +# UART0_RX PF4, SDC0_D3 Per default disabled +# UART1_TX PE21 Per default disabled +# UART1_RX PE22 Per default disabled +# UART2_TX PB0 Per default disabled +# UART2_RX PB1 Per default disabled +# +# JTAG is enabled by default after power on on listed JTAG_* pins. So far the +# boot sequence is: +# Time Action +# 0000ms Power ON +# 0200ms JTAG enabled +# 0220ms JTAG pins switched to SD mode +# +# The time frame of 20ms can be not enough to init and halt the CPU. In this +# case I would recommend to set: "adapter_khz 15000" +# To get more or less precise timings, the board should provide reset pin, +# or some bench power supply with remote function. In my case I used +# EEZ H24005 with this command to power on and halt the target: +# "exec echo "*TRG" > /dev/ttyACM0; sleep 220; reset halt" +# After this it is possible to enable JTAG mode again from boot loader or OS. +# Following DAPs are available: +# dap[0]->MEM-AP AHB +# dap[1]->MEM-AP APB->CA7[0] +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME v3s +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +# No NRST or SRST is present on the SoC. Boards may provide +# some sort of Power cycle reset for complete board or SoC. +# For this case we provide srst_pulls_trst so the board config +# only needs to set srst_only. +reset_config none srst_pulls_trst + +jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x0f \ + -expected-id $_DAP_TAPID + +# Add Cortex A7 core +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap From e48690cb26e4ab3499623c70feae7ad7c54b94bd Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 25 Jul 2018 10:24:49 +0200 Subject: [PATCH 079/147] target/arm_adi_v5: allow commands apsel and apcsw during init phase The current implementation of apsel cannot be executed during the initialization phase because it queries the DAP AP to retrieve and print the content of IDR register, and the query is only possible later on during the exec phase. But IDR information is already printed by the dedicated command apid, making redundant printing it by apsel too. Being unable to run apsel during initialization, makes also apcsw command (that depends on apsel) not usable in such phase. Modify the command apsel to only set the current AP, without making any transfer to the (possibly not initialized yet) DAP. When run without parameters, just print the current AP number. Change mode to COMMAND_ANY to apsel and to apcsw. Change-Id: Ibea6d531e435d1d49d782de1ed8ee6846e91bfdf Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4624 Tested-by: jenkins Reviewed-by: Matthias Welwarsky Reviewed-by: Tomas Vanek --- src/target/arm_adi_v5.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index dc5c80393..302ea7891 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1616,13 +1616,12 @@ COMMAND_HANDLER(dap_memaccess_command) COMMAND_HANDLER(dap_apsel_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); - uint32_t apsel, apid; - int retval; + uint32_t apsel; switch (CMD_ARGC) { case 0: - apsel = dap->apsel; - break; + command_print(CMD_CTX, "%" PRIi32, dap->apsel); + return ERROR_OK; case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ @@ -1634,18 +1633,7 @@ COMMAND_HANDLER(dap_apsel_command) } dap->apsel = apsel; - - retval = dap_queue_ap_read(dap_ap(dap, apsel), AP_REG_IDR, &apid); - if (retval != ERROR_OK) - return retval; - retval = dap_run(dap); - if (retval != ERROR_OK) - return retval; - - command_print(CMD_CTX, "ap %" PRIi32 " selected, identification register 0x%8.8" PRIx32, - apsel, apid); - - return retval; + return ERROR_OK; } COMMAND_HANDLER(dap_apcsw_command) @@ -1838,7 +1826,7 @@ const struct command_registration dap_instance_commands[] = { { .name = "apsel", .handler = dap_apsel_command, - .mode = COMMAND_EXEC, + .mode = COMMAND_ANY, .help = "Set the currently selected AP (default 0) " "and display the result", .usage = "[ap_num]", @@ -1846,7 +1834,7 @@ const struct command_registration dap_instance_commands[] = { { .name = "apcsw", .handler = dap_apcsw_command, - .mode = COMMAND_EXEC, + .mode = COMMAND_ANY, .help = "Set CSW default bits", .usage = "[value [mask]]", }, From 766d6114fea0c2748ed281db866588f975d2ba83 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 25 Jul 2018 09:47:16 +0200 Subject: [PATCH 080/147] target/cortex_a: allow command dacrfixup during init phase There is no reason to restrict the command "cortex_a dacrfixup" to the EXEC phase only. Change the command mode to ANY so the command can be used in the initialization phase too. Change-Id: I498cc6b2dbdc48b3b2dd5f0445519a51857b295f Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4623 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/cortex_a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index e4d8331b2..4aae5e473 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -3438,7 +3438,7 @@ static const struct command_registration cortex_a_exec_command_handlers[] = { { .name = "dacrfixup", .handler = handle_cortex_a_dacrfixup_command, - .mode = COMMAND_EXEC, + .mode = COMMAND_ANY, .help = "set domain access control (DACR) to all-manager " "on memory access", .usage = "['on'|'off']", From 527113ad2b876860c551f807d693955bb7c45af4 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 24 Jul 2018 10:17:57 +0200 Subject: [PATCH 081/147] target/armv7a_cache: add gdb keep-alive and fix a missing dpm finish Depending on range size, the loop on cache operations can take quite some time, causing gdb to timeout. Add keep-alive to prevent gdb to timeout. Add also a missing dpm->finish() to balance dpm->prepare(). Change-Id: Ia87934b1ec19a0332bb50e3010b582381e5f3685 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4627 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/armv7a_cache.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index 3e5f8d6de..7435aab95 100644 --- a/src/target/armv7a_cache.c +++ b/src/target/armv7a_cache.c @@ -70,6 +70,7 @@ static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cach LOG_DEBUG("cl %" PRId32, cl); do { + keep_alive(); c_way = size->way; do { uint32_t value = (c_index << size->index_shift) @@ -89,6 +90,7 @@ static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cach } while (c_index >= 0); done: + keep_alive(); return retval; } @@ -164,7 +166,7 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->dminline; uint32_t va_line, va_end; - int retval; + int retval, i = 0; retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) @@ -198,6 +200,8 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, } while (va_line < va_end) { + if ((i++ & 0x3f) == 0) + keep_alive(); /* DCIMVAC - Invalidate data cache line by VA to PoC. */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line); @@ -206,11 +210,13 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, va_line += linelen; } + keep_alive(); dpm->finish(dpm); return retval; done: LOG_ERROR("d-cache invalidate failed"); + keep_alive(); dpm->finish(dpm); return retval; @@ -224,7 +230,7 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->dminline; uint32_t va_line, va_end; - int retval; + int retval, i = 0; retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) @@ -238,6 +244,8 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, va_end = virt + size; while (va_line < va_end) { + if ((i++ & 0x3f) == 0) + keep_alive(); /* DCCMVAC - Data Cache Clean by MVA to PoC */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line); @@ -246,11 +254,13 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, va_line += linelen; } + keep_alive(); dpm->finish(dpm); return retval; done: LOG_ERROR("d-cache invalidate failed"); + keep_alive(); dpm->finish(dpm); return retval; @@ -264,7 +274,7 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt, struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->dminline; uint32_t va_line, va_end; - int retval; + int retval, i = 0; retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) @@ -278,6 +288,8 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt, va_end = virt + size; while (va_line < va_end) { + if ((i++ & 0x3f) == 0) + keep_alive(); /* DCCIMVAC */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line); @@ -286,11 +298,13 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt, va_line += linelen; } + keep_alive(); dpm->finish(dpm); return retval; done: LOG_ERROR("d-cache invalidate failed"); + keep_alive(); dpm->finish(dpm); return retval; @@ -342,7 +356,7 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt, &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->iminline; uint32_t va_line, va_end; - int retval; + int retval, i = 0; retval = armv7a_l1_i_cache_sanity_check(target); if (retval != ERROR_OK) @@ -356,6 +370,8 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt, va_end = virt + size; while (va_line < va_end) { + if ((i++ & 0x3f) == 0) + keep_alive(); /* ICIMVAU - Invalidate instruction cache by VA to PoU. */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line); @@ -368,10 +384,13 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt, goto done; va_line += linelen; } + keep_alive(); + dpm->finish(dpm); return retval; done: LOG_ERROR("i-cache invalidate failed"); + keep_alive(); dpm->finish(dpm); return retval; From fd0446002f89975f616c17abdb354aa5614f5f7c Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 25 Jun 2018 13:44:01 -0700 Subject: [PATCH 082/147] Add detail to `wrong register size` error. Signed-off-by: Tim Newsome Change-Id: Id31499c94b539969970251145e42c89c943fd87c Reviewed-on: http://openocd.zylin.com/4577 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/server/gdb_server.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 2270afffd..69afb2fd4 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1360,7 +1360,8 @@ static int gdb_set_register_packet(struct connection *connection, int chars = (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2); if ((unsigned int)chars != strlen(separator + 1)) { - LOG_ERROR("gdb sent a packet with wrong register size"); + LOG_ERROR("gdb sent %zu bits for a %d-bit register (%s)", + strlen(separator + 1) * 4, chars * 4, reg_list[reg_num]->name); free(bin_buf); return ERROR_SERVER_REMOTE_CLOSED; } From 45f0c1591253f0c18fb8d41c6a572e1d81331053 Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Tue, 31 Jul 2018 10:25:32 -0700 Subject: [PATCH 083/147] doc: fix typo in cortex_m maskisr command Change-Id: I37795c320ff7cbf6f2c7434e03b26dbaf6fc6db4 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4621 Tested-by: jenkins Reviewed-by: Tomas Vanek --- doc/openocd.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 1a89a53de..c0d065d4b 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8800,8 +8800,8 @@ Enable or disable trace output for all ITM stimulus ports. @deffn Command {cortex_m maskisr} (@option{auto}|@option{on}|@option{off}) Control masking (disabling) interrupts during target step/resume. -The @option{auto} option handles interrupts during stepping a way they get -served but don't disturb the program flow. The step command first allows +The @option{auto} option handles interrupts during stepping in a way that they +get served but don't disturb the program flow. The step command first allows pending interrupt handlers to execute, then disables interrupts and steps over the next instruction where the core was halted. After the step interrupts are enabled again. If the interrupt handlers don't complete within 500ms, From c6cc60e0e13590433162a8ebefa4861226ca2b4d Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Tue, 17 Jul 2018 13:55:55 -0700 Subject: [PATCH 084/147] target/cortex_m: restore C_MASKINTS after reset The cortex_m maskisr user-facing setting is not changed across a target reset. However, the in-core C_MASKINTS bit was always cleared as part of reset processing, meaning that a cortex_m maskisr on setting would not be respected after a reset. Set C_MASKINTS based on the user-facing setting value rather than always clearing it after reset. Change-Id: I5aa5b9dfde04a0fb9c6816fa55b5ef1faf39f8de Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4605 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/cortex_m.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index f18694672..ca3dbec78 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -237,8 +237,11 @@ static int cortex_m_endreset_event(struct target *target) return retval; } - /* clear any interrupt masking */ - cortex_m_write_debug_halt_mask(target, 0, C_MASKINTS); + /* Restore proper interrupt masking setting. */ + if (cortex_m->isrmasking_mode == CORTEX_M_ISRMASK_ON) + cortex_m_write_debug_halt_mask(target, C_MASKINTS, 0); + else + cortex_m_write_debug_halt_mask(target, 0, C_MASKINTS); /* Enable features controlled by ITM and DWT blocks, and catch only * the vectors we were told to pay attention to. From 471c3cdb2d7f0d8e3fb5017b6fff85d1e1bb8225 Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Wed, 7 Mar 2018 11:29:45 -0500 Subject: [PATCH 085/147] tcl/board: update all uses of interface/stlink-v2-1 to interface/stlink Change-Id: I5e27e84d022f73101376e8b4a1bdc65f58fd348a Signed-off-by: Cody P Schafer Reviewed-on: http://openocd.zylin.com/4456 Tested-by: jenkins Reviewed-by: Tomas Vanek --- tcl/board/st_nucleo_f7.cfg | 2 +- tcl/board/st_nucleo_h743zi.cfg | 2 +- tcl/board/st_nucleo_l073rz.cfg | 2 +- tcl/board/stm32h7x3i_eval.cfg | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tcl/board/st_nucleo_f7.cfg b/tcl/board/st_nucleo_f7.cfg index 88a8a308a..f94679b70 100644 --- a/tcl/board/st_nucleo_f7.cfg +++ b/tcl/board/st_nucleo_f7.cfg @@ -1,7 +1,7 @@ # STMicroelectronics STM32F7 Nucleo development board # Known boards: NUCLEO-F746ZG and NUCLEO-F767ZI -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/st_nucleo_h743zi.cfg b/tcl/board/st_nucleo_h743zi.cfg index baedeb6d4..cfe2cda1b 100644 --- a/tcl/board/st_nucleo_h743zi.cfg +++ b/tcl/board/st_nucleo_h743zi.cfg @@ -1,7 +1,7 @@ # This is an ST NUCLEO-H743ZI board with single STM32H743ZI chip. # http://www.st.com/en/evaluation-tools/nucleo-h743zi.html -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/st_nucleo_l073rz.cfg b/tcl/board/st_nucleo_l073rz.cfg index fa9dc87c9..b32f8d5fb 100644 --- a/tcl/board/st_nucleo_l073rz.cfg +++ b/tcl/board/st_nucleo_l073rz.cfg @@ -1,6 +1,6 @@ # This is an ST NUCLEO-L073RZ board with single STM32L073RZ chip. # http://www.st.com/en/evaluation-tools/nucleo-l073rz.html -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32h7x3i_eval.cfg b/tcl/board/stm32h7x3i_eval.cfg index 2949ded32..caf68b6c4 100644 --- a/tcl/board/stm32h7x3i_eval.cfg +++ b/tcl/board/stm32h7x3i_eval.cfg @@ -4,7 +4,7 @@ # This is an ST EVAL-H753XI board with single STM32H753XI chip. # http://www.st.com/en/evaluation-tools/stm32h753i-eval.html -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd From 404495b191ecfe1085e10e9057d4e2e47a7a3399 Mon Sep 17 00:00:00 2001 From: Svetoslav Enchev Date: Sun, 5 Aug 2018 12:40:32 +0300 Subject: [PATCH 086/147] target/riscv/riscv-011: fix compile warning about uninitialized variable In MSYS2 MinGW 64-bit git clone git://git.code.sf.net/p/openocd/code openocd $ gcc --version gcc.exe (Rev1, Built by MSYS2 project) 8.2.0 ./bootstrap ./configure --prefix= $ cat config.status | grep CFLAGS CFLAGS='-g -O2' make bindir = "bin-x64" depbase=`echo src/target/riscv/riscv-011.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\ /bin/sh ./libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -D__USE_MINGW_ANSI_STDIO -I./src -I./src -I./src/helper -DPKGDATADIR=\"/mingw64/share/openocd\" -DBINDIR=\"bin-x64\" -I./jimtcl -I./jimtcl -Wall -Wstrict-prototypes -Wformat-security -Wshadow -Wextra -Wno-unused-parameter -Wbad-function-cast -Wcast-align -Wredundant-decls -Werror -g -O2 -MT src/target/riscv/riscv-011.lo -MD -MP -MF $depbase.Tpo -c -o src/target/riscv/riscv-011.lo src/target/riscv/riscv-011.c &&\ mv -f $depbase.Tpo $depbase.Plo libtool: compile: gcc -DHAVE_CONFIG_H -I. -D__USE_MINGW_ANSI_STDIO -I./src -I./src -I./src/helper -DPKGDATADIR=\"/mingw64/share/openocd\" -DBINDIR=\"bin-x64\" -I./jimtcl -I./jimtcl -Wall -Wstrict-prototypes -Wformat-security -Wshadow -Wextra -Wno-unused-parameter -Wbad-function-cast -Wcast-align -Wredundant-decls -Werror -g -O2 -MT src/target/riscv/riscv-011.lo -MD -MP -MF src/target/riscv/.deps/riscv-011.Tpo -c src/target/riscv/riscv-011.c -o src/target/riscv/riscv-011.o src/target/riscv/riscv-011.c: In function 'poll_target': src/target/riscv/riscv-011.c:1799:6: error: 'reg' may be used uninitialized in this function [-Werror=maybe-uninitialized] reg_cache_set(target, reg, ((data & 0xffffffff) << 32) | value); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/target/riscv/riscv-011.c:1686:17: note: 'reg' was declared here unsigned int reg; ^~~ cc1.exe: all warnings being treated as errors make[2]: *** [Makefile:3250: src/target/riscv/riscv-011.lo] Error 1 Change-Id: I6996dcb866fbace26817636f4bedba09510a087f Signed-off-by: Svetoslav Enchev Reviewed-on: http://openocd.zylin.com/4635 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tim Newsome Reviewed-by: Tomas Vanek --- src/target/riscv/riscv-011.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index 498da5ad5..3820d8fc0 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -1788,6 +1788,8 @@ static riscv_error_t handle_halt_routine(struct target *target) break; default: assert(0); + LOG_ERROR("Got invalid register result %d", result); + goto error; } if (riscv_xlen(target) == 32) { reg_cache_set(target, reg, data & 0xffffffff); From 6060545458f6863710d576fc4bd2512d34f88f89 Mon Sep 17 00:00:00 2001 From: Kevin Gillespie Date: Thu, 14 Jul 2016 13:00:23 -0500 Subject: [PATCH 087/147] max32xxx: Support for MAX32XXX devices. Adding flash programming support for Maxim Integrated MAX32XXX devices. Change-Id: I5b0f57a885f9d813240e4bc2d9f765b743e1cfc3 Signed-off-by: Kevin Gillespie Reviewed-on: http://openocd.zylin.com/3543 Tested-by: jenkins Reviewed-by: Ismail H. KOSE Reviewed-by: Tomas Vanek Reviewed-by: Andreas Fritiofson --- contrib/loaders/Makefile | 1 + contrib/loaders/flash/max32xxx/Makefile | 19 + contrib/loaders/flash/max32xxx/max32xxx.inc | 6 + contrib/loaders/flash/max32xxx/max32xxx.s | 70 ++ src/flash/nor/Makefile.am | 1 + src/flash/nor/drivers.c | 2 + src/flash/nor/max32xxx.c | 997 ++++++++++++++++++++ tcl/target/max32620.cfg | 28 + tcl/target/max32625.cfg | 28 + tcl/target/max3263x.cfg | 28 + 10 files changed, 1180 insertions(+) create mode 100644 contrib/loaders/flash/max32xxx/Makefile create mode 100644 contrib/loaders/flash/max32xxx/max32xxx.inc create mode 100644 contrib/loaders/flash/max32xxx/max32xxx.s create mode 100644 src/flash/nor/max32xxx.c create mode 100644 tcl/target/max32620.cfg create mode 100644 tcl/target/max32625.cfg create mode 100644 tcl/target/max3263x.cfg diff --git a/contrib/loaders/Makefile b/contrib/loaders/Makefile index a9a27706d..0a637aff5 100644 --- a/contrib/loaders/Makefile +++ b/contrib/loaders/Makefile @@ -12,6 +12,7 @@ ARM_CROSS_COMPILE ?= arm-none-eabi- arm_dirs = \ flash/fm4 \ flash/kinetis_ke \ + flash/max32xxx \ flash/xmc1xxx \ debug/xscale diff --git a/contrib/loaders/flash/max32xxx/Makefile b/contrib/loaders/flash/max32xxx/Makefile new file mode 100644 index 000000000..8f3f9242e --- /dev/null +++ b/contrib/loaders/flash/max32xxx/Makefile @@ -0,0 +1,19 @@ +BIN2C = ../../../../src/helper/bin2char.sh + +CROSS_COMPILE ?= arm-none-eabi- +AS = $(CROSS_COMPILE)as +OBJCOPY = $(CROSS_COMPILE)objcopy + +all: max32xxx.inc + +%.elf: %.s + $(AS) $< -o $@ + +%.bin: %.elf + $(OBJCOPY) -Obinary $< $@ + +%.inc: %.bin + $(BIN2C) < $< > $@ + +clean: + -rm -f *.elf *.bin *.inc diff --git a/contrib/loaders/flash/max32xxx/max32xxx.inc b/contrib/loaders/flash/max32xxx/max32xxx.inc new file mode 100644 index 000000000..442165d0d --- /dev/null +++ b/contrib/loaders/flash/max32xxx/max32xxx.inc @@ -0,0 +1,6 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0xdf,0xf8,0x44,0x40,0xd0,0xf8,0x00,0x80,0xb8,0xf1,0x00,0x0f,0x1a,0xd0,0x47,0x68, +0x47,0x45,0xf7,0xd0,0x22,0x60,0x02,0xf1,0x04,0x02,0x57,0xf8,0x04,0x8b,0xc4,0xf8, +0x30,0x80,0xa5,0x68,0x45,0xf0,0x01,0x05,0xa5,0x60,0xd4,0xf8,0x08,0x80,0x18,0xf0, +0x01,0x0f,0xfa,0xd1,0x8f,0x42,0x28,0xbf,0x00,0xf1,0x08,0x07,0x47,0x60,0x01,0x3b, +0x03,0xb1,0xdf,0xe7,0x00,0xbe,0x00,0xbf,0x00,0x00,0x00,0x40, diff --git a/contrib/loaders/flash/max32xxx/max32xxx.s b/contrib/loaders/flash/max32xxx/max32xxx.s new file mode 100644 index 000000000..f5306d6c5 --- /dev/null +++ b/contrib/loaders/flash/max32xxx/max32xxx.s @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2016 by Maxim Integrated * + * Kevin Gillespie . * + ***************************************************************************/ + +.text +.syntax unified +.cpu cortex-m3 +.thumb +.thumb_func + +/* + * Params : + * r0 = workarea start + * r1 = workarea end + * r2 = target address + * r3 = count (32bit words) + * r4 = pFLASH_CTRL_BASE + * + * Clobbered: + * r5 = FLASHWRITECMD + * r7 - rp + * r8 - wp, tmp + */ + +write: + +wait_fifo: +ldr r8, [r0, #0] /* read wp */ +cmp r8, #0 /* abort if wp == 0 */ +beq exit +ldr r7, [r0, #4] /* read rp */ +cmp r7, r8 /* wait until rp != wp */ +beq wait_fifo + +mainloop: +str r2, [r4, #0x00] /* FLSH_ADDR - write address */ +add r2, r2, #4 /* increment target address */ +ldr r8, [r7], #4 +str r8, [r4, #0x30] /* FLSH_DATA0 - write data */ +ldr r5, [r4, #0x08] /* FLSH_CN */ +orr r5, r5, #1 +str r5, [r4, #0x08] /* FLSH_CN - enable write */ +busy: +ldr r8, [r4, #0x08] /* FLSH_CN */ +tst r8, #1 +bne busy + +cmp r7, r1 /* wrap rp at end of buffer */ +it cs +addcs r7, r0, #8 /* skip loader args */ +str r7, [r0, #4] /* store rp */ +subs r3, r3, #1 /* decrement word count */ +cbz r3, exit /* loop if not done */ +b wait_fifo +exit: +bkpt diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 13e589cd0..3839d0a8d 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -35,6 +35,7 @@ NOR_DRIVERS = \ %D%/lpc288x.c \ %D%/lpc2900.c \ %D%/lpcspifi.c \ + %D%/max32xxx.c \ %D%/mdr.c \ %D%/msp432.c \ %D%/mrvlqspi.c \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 196717f46..2251b965a 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -48,6 +48,7 @@ extern struct flash_driver lpc2000_flash; extern struct flash_driver lpc288x_flash; extern struct flash_driver lpc2900_flash; extern struct flash_driver lpcspifi_flash; +extern struct flash_driver max32xxx_flash; extern struct flash_driver mdr_flash; extern struct flash_driver mrvlqspi_flash; extern struct flash_driver msp432_flash; @@ -112,6 +113,7 @@ static struct flash_driver *flash_drivers[] = { &lpc288x_flash, &lpc2900_flash, &lpcspifi_flash, + &max32xxx_flash, &mdr_flash, &mrvlqspi_flash, &msp432_flash, diff --git a/src/flash/nor/max32xxx.c b/src/flash/nor/max32xxx.c new file mode 100644 index 000000000..ca037de4d --- /dev/null +++ b/src/flash/nor/max32xxx.c @@ -0,0 +1,997 @@ +/*************************************************************************** + * Copyright (C) 2016 by Maxim Integrated * + * Kevin Gillespie * + * * + * 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 . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include +#include + +/* Register Addresses */ +#define FLSH_ADDR 0x000 +#define FLSH_CLKDIV 0x004 +#define FLSH_CN 0x008 +#define PR1E_ADDR 0x00C +#define PR2S_ADDR 0x010 +#define PR2E_ADDR 0x014 +#define PR3S_ADDR 0x018 +#define PR3E_ADDR 0x01C +#define FLSH_MD 0x020 +#define FLSH_INT 0x024 +#define FLSH_DATA0 0x030 +#define FLSH_DATA1 0x034 +#define FLSH_DATA2 0x038 +#define FLSH_DATA3 0x03C +#define FLSH_BL_CTRL 0x170 +#define FLSH_PROT 0x300 + +#define ARM_PID_REG 0xE00FFFE0 +#define MAX326XX_ID_REG 0x40000838 + +/* Register settings */ +#define FLSH_INT_AF 0x00000002 + +#define FLSH_CN_UNLOCK_MASK 0xF0000000 +#define FLSH_CN_UNLOCK_VALUE 0x20000000 + +#define FLSH_CN_PEND 0x01000000 + +#define FLSH_CN_ERASE_CODE_MASK 0x0000FF00 +#define FLSH_CN_ERASE_CODE_PGE 0x00005500 +#define FLSH_CN_ERASE_CODE_ME 0x0000AA00 + +#define FLSH_CN_PGE 0x00000004 +#define FLSH_CN_ME 0x00000002 +#define FLSH_CN_WR 0x00000001 +#define FLASH_BL_CTRL_23 0x00020000 +#define FLASH_BL_CTRL_IFREN 0x00000001 + +#define ARM_PID_DEFAULT_CM3 0xB4C3 +#define ARM_PID_DEFAULT_CM4 0xB4C4 +#define MAX326XX_ID 0x4D + +static int max32xxx_mass_erase(struct flash_bank *bank); + +struct max32xxx_flash_bank { + int probed; + int max326xx; + unsigned int flash_size; + unsigned int flc_base; + unsigned int sector_size; + unsigned int clkdiv_value; + unsigned int int_state; + unsigned int burst_size_bits; +}; + +/* see contib/loaders/flash/max32xxx/max32xxx.s for src */ +static const uint8_t write_code[] = { +#include "../../contrib/loaders/flash/max32xxx/max32xxx.inc" +}; + +/* Config Command: flash bank name driver base size chip_width bus_width target [driver_option] + flash bank max32xxx 0 0 [burst_bits] + */ +FLASH_BANK_COMMAND_HANDLER(max32xxx_flash_bank_command) +{ + struct max32xxx_flash_bank *info; + + if (CMD_ARGC < 9) { + LOG_WARNING("incomplete flash bank max32xxx configuration: 0 0 [burst_bits]"); + return ERROR_FLASH_BANK_INVALID; + } + + info = calloc(sizeof(struct max32xxx_flash_bank), 1); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], info->flash_size); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->flc_base); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], info->sector_size); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[8], info->clkdiv_value); + + if (CMD_ARGC > 9) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[9], info->burst_size_bits); + else + info->burst_size_bits = 32; + + info->int_state = 0; + bank->driver_priv = info; + return ERROR_OK; +} + +static int get_info(struct flash_bank *bank, char *buf, int buf_size) +{ + int printed; + struct max32xxx_flash_bank *info = bank->driver_priv; + + if (info->probed == 0) + return ERROR_FLASH_BANK_NOT_PROBED; + + printed = snprintf(buf, buf_size, "\nMaxim Integrated max32xxx flash driver\n"); + buf += printed; + buf_size -= printed; + return ERROR_OK; +} + +/*************************************************************************** +* flash operations +***************************************************************************/ + +static int max32xxx_flash_op_pre(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct max32xxx_flash_bank *info = bank->driver_priv; + uint32_t flsh_cn; + uint32_t bootloader; + + /* Check if the flash controller is busy */ + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + if (flsh_cn & (FLSH_CN_PEND | FLSH_CN_ERASE_CODE_MASK | FLSH_CN_PGE | + FLSH_CN_ME | FLSH_CN_WR)) + return ERROR_FLASH_BUSY; + + /* Refresh flash controller timing */ + target_write_u32(target, info->flc_base + FLSH_CLKDIV, info->clkdiv_value); + + /* Clear and disable flash programming interrupts */ + target_read_u32(target, info->flc_base + FLSH_INT, &info->int_state); + target_write_u32(target, info->flc_base + FLSH_INT, 0x00000000); + + /* Clear the lower bit in the bootloader configuration register in case flash page 0 has been replaced */ + if (target_read_u32(target, info->flc_base + FLSH_BL_CTRL, &bootloader) != ERROR_OK) { + LOG_ERROR("Read failure on FLSH_BL_CTRL"); + return ERROR_FAIL; + } + if (bootloader & FLASH_BL_CTRL_23) { + LOG_WARNING("FLSH_BL_CTRL indicates BL mode 2 or mode 3."); + if (bootloader & FLASH_BL_CTRL_IFREN) { + LOG_WARNING("Flash page 0 swapped out, attempting to swap back in for programming"); + bootloader &= ~(FLASH_BL_CTRL_IFREN); + if (target_write_u32(target, info->flc_base + FLSH_BL_CTRL, bootloader) != ERROR_OK) { + LOG_ERROR("Write failure on FLSH_BL_CTRL"); + return ERROR_FAIL; + } + if (target_read_u32(target, info->flc_base + FLSH_BL_CTRL, &bootloader) != ERROR_OK) { + LOG_ERROR("Read failure on FLSH_BL_CTRL"); + return ERROR_FAIL; + } + if (bootloader & FLASH_BL_CTRL_IFREN) { + /* Bummer */ + LOG_ERROR("Unable to swap flash page 0 back in. Writes to page 0 will fail."); + } + } + } + + /* Unlock flash */ + flsh_cn &= ~FLSH_CN_UNLOCK_MASK; + flsh_cn |= FLSH_CN_UNLOCK_VALUE; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + + /* Confirm flash is unlocked */ + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + if ((flsh_cn & FLSH_CN_UNLOCK_VALUE) != FLSH_CN_UNLOCK_VALUE) + return ERROR_FAIL; + + return ERROR_OK; +} + +static int max32xxx_flash_op_post(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct max32xxx_flash_bank *info = bank->driver_priv; + uint32_t flsh_cn; + + /* Restore flash programming interrupts */ + target_write_u32(target, info->flc_base + FLSH_INT, info->int_state); + + /* Lock flash */ + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + flsh_cn &= ~FLSH_CN_UNLOCK_MASK; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + return ERROR_OK; +} + +static int max32xxx_protect_check(struct flash_bank *bank) +{ + struct max32xxx_flash_bank *info = bank->driver_priv; + struct target *target = bank->target; + int i; + uint32_t temp_reg; + + if (info->probed == 0) + return ERROR_FLASH_BANK_NOT_PROBED; + + if (!info->max326xx) { + for (i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_protected = -1; + + return ERROR_FLASH_OPER_UNSUPPORTED; + } + + /* Check the protection */ + for (i = 0; i < bank->num_sectors; i++) { + if (i%32 == 0) + target_read_u32(target, info->flc_base + FLSH_PROT + ((i/32)*4), &temp_reg); + + if (temp_reg & (0x1 << i%32)) + bank->sectors[i].is_protected = 1; + else + bank->sectors[i].is_protected = 0; + } + return ERROR_OK; +} + +static int max32xxx_erase(struct flash_bank *bank, int first, int last) +{ + int banknr; + uint32_t flsh_cn, flsh_int; + struct max32xxx_flash_bank *info = bank->driver_priv; + struct target *target = bank->target; + int retval; + int retry; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (info->probed == 0) + return ERROR_FLASH_BANK_NOT_PROBED; + + if ((first < 0) || (last < first) || (last >= bank->num_sectors)) + return ERROR_FLASH_SECTOR_INVALID; + + if ((first == 0) && (last == (bank->num_sectors - 1))) + return max32xxx_mass_erase(bank); + + /* Prepare to issue flash operation */ + retval = max32xxx_flash_op_pre(bank); + + if (retval != ERROR_OK) + return retval; + + int erased = 0; + for (banknr = first; banknr <= last; banknr++) { + + /* Check the protection */ + if (bank->sectors[banknr].is_protected == 1) { + LOG_WARNING("Flash sector %d is protected", banknr); + continue; + } else + erased = 1; + + /* Address is first word in page */ + target_write_u32(target, info->flc_base + FLSH_ADDR, banknr * info->sector_size); + + /* Write page erase code */ + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + flsh_cn |= FLSH_CN_ERASE_CODE_PGE; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + + /* Issue page erase command */ + flsh_cn |= 0x4; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + + /* Wait until erase complete */ + retry = 1000; + do { + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + + if (retry <= 0) { + LOG_ERROR("Timed out waiting for flash page erase @ 0x%08x", + banknr * info->sector_size); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* Check access violations */ + target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int); + if (flsh_int & FLSH_INT_AF) { + LOG_ERROR("Error erasing flash page %i", banknr); + target_write_u32(target, info->flc_base + FLSH_INT, 0); + max32xxx_flash_op_post(bank); + return ERROR_FLASH_OPERATION_FAILED; + } + + bank->sectors[banknr].is_erased = 1; + } + + if (!erased) { + LOG_ERROR("All pages protected %d to %d", first, last); + max32xxx_flash_op_post(bank); + return ERROR_FAIL; + } + + if (max32xxx_flash_op_post(bank) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +static int max32xxx_protect(struct flash_bank *bank, int set, int first, int last) +{ + struct max32xxx_flash_bank *info = bank->driver_priv; + struct target *target = bank->target; + int page; + uint32_t temp_reg; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (info->probed == 0) + return ERROR_FLASH_BANK_NOT_PROBED; + + if (!info->max326xx) + return ERROR_FLASH_OPER_UNSUPPORTED; + + if ((first < 0) || (last < first) || (last >= bank->num_sectors)) + return ERROR_FLASH_SECTOR_INVALID; + + /* Setup the protection on the pages given */ + for (page = first; page <= last; page++) { + if (set) { + /* Set the write/erase bit for this page */ + target_read_u32(target, info->flc_base + FLSH_PROT + (page/32), &temp_reg); + temp_reg |= (0x1 << page%32); + target_write_u32(target, info->flc_base + FLSH_PROT + (page/32), temp_reg); + bank->sectors[page].is_protected = 1; + } else { + /* Clear the write/erase bit for this page */ + target_read_u32(target, info->flc_base + FLSH_PROT + (page/32), &temp_reg); + temp_reg &= ~(0x1 << page%32); + target_write_u32(target, info->flc_base + FLSH_PROT + (page/32), temp_reg); + bank->sectors[page].is_protected = 0; + } + } + + return ERROR_OK; +} + +static int max32xxx_write_block(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t wcount) +{ + struct max32xxx_flash_bank *info = bank->driver_priv; + struct target *target = bank->target; + uint32_t buffer_size = 16384; + struct working_area *source; + struct working_area *write_algorithm; + uint32_t address = bank->base + offset; + struct reg_param reg_params[5]; + struct armv7m_algorithm armv7m_info; + int retval = ERROR_OK; + /* power of two, and multiple of word size */ + static const unsigned buf_min = 128; + + /* for small buffers it's faster not to download an algorithm */ + if (wcount * 4 < buf_min) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "", + bank, buffer, offset, wcount); + + /* flash write code */ + if (target_alloc_working_area(target, sizeof(write_code), &write_algorithm) != ERROR_OK) { + LOG_DEBUG("no working area for block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* plus a buffer big enough for this data */ + if (wcount * 4 < buffer_size) + buffer_size = wcount * 4; + + /* memory buffer */ + while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { + buffer_size /= 2; + + if (buffer_size <= buf_min) { + target_free_working_area(target, write_algorithm); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + LOG_DEBUG("retry target_alloc_working_area(%s, size=%u)", + target_name(target), (unsigned) buffer_size); + } + + target_write_buffer(target, write_algorithm->address, sizeof(write_code), + write_code); + + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); + + buf_set_u32(reg_params[0].value, 0, 32, source->address); + buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); + buf_set_u32(reg_params[2].value, 0, 32, address); + buf_set_u32(reg_params[3].value, 0, 32, wcount); + buf_set_u32(reg_params[4].value, 0, 32, info->flc_base); + retval = target_run_flash_async_algorithm(target, buffer, wcount, 4, 0, NULL, + 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); + + if (retval == ERROR_FLASH_OPERATION_FAILED) + LOG_ERROR("error %d executing max32xxx flash write algorithm", retval); + + target_free_working_area(target, write_algorithm); + target_free_working_area(target, source); + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + return retval; +} + +static int max32xxx_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct max32xxx_flash_bank *info = bank->driver_priv; + struct target *target = bank->target; + uint32_t flsh_cn, flsh_int; + uint32_t address = offset; + uint32_t remaining = count; + uint32_t words_remaining; + int retval; + int retry; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + LOG_DEBUG("bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32 "", + bank, buffer, offset, count); + + if (info->probed == 0) + return ERROR_FLASH_BANK_NOT_PROBED; + + if (offset & 0x3) { + LOG_WARNING("offset size must be word aligned"); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } + + if (offset + count > bank->size) + return ERROR_FLASH_DST_OUT_OF_BANK; + + /* Prepare to issue flash operation */ + retval = max32xxx_flash_op_pre(bank); + + if (retval != ERROR_OK) + return retval; + + if (remaining >= 4) { + /* write in 32-bit units */ + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + flsh_cn &= 0xF7FFFFFF; + flsh_cn |= 0x00000010; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + + /* try using a block write */ + words_remaining = remaining / 4; + retval = max32xxx_write_block(bank, buffer, offset, words_remaining); + + if (retval != ERROR_OK) { + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + LOG_DEBUG("writing flash word-at-a-time"); + else { + max32xxx_flash_op_post(bank); + return ERROR_FLASH_OPERATION_FAILED; + } + } else { + /* all 32-bit words have been written */ + buffer += words_remaining * 4; + address += words_remaining * 4; + remaining -= words_remaining * 4; + } + } + + if ((remaining >= 4) && ((address & 0x1F) != 0)) { + /* write in 32-bit units until we are 128-bit aligned */ + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + flsh_cn &= 0xF7FFFFFF; + flsh_cn |= 0x00000010; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + + while ((remaining >= 4) && ((address & 0x1F) != 0)) { + target_write_u32(target, info->flc_base + FLSH_ADDR, address); + target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, buffer); + flsh_cn |= 0x00000001; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + /* Wait until flash operation is complete */ + retry = 10; + + do { + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + + if (retry <= 0) { + LOG_ERROR("Timed out waiting for flash write @ 0x%08x", address); + return ERROR_FLASH_OPERATION_FAILED; + } + + buffer += 4; + address += 4; + remaining -= 4; + } + } + + if ((info->burst_size_bits == 128) && (remaining >= 16)) { + /* write in 128-bit bursts while we can */ + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + + flsh_cn &= 0xFFFFFFEF; + flsh_cn |= 0x08000000; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + target_write_u32(target, info->flc_base + FLSH_ADDR, address); + + while (remaining >= 16) { + if ((address & 0xFFF) == 0) + LOG_DEBUG("Writing @ 0x%08x", address); + + target_write_buffer(target, info->flc_base + FLSH_DATA0, 16, buffer); + flsh_cn |= 0x00000001; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + /* Wait until flash operation is complete */ + retry = 10; + + do { + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + + if (retry <= 0) { + LOG_ERROR("Timed out waiting for flash write @ 0x%08x", address); + return ERROR_FLASH_OPERATION_FAILED; + } + + buffer += 16; + address += 16; + remaining -= 16; + } + } + + if (remaining >= 4) { + + /* write in 32-bit units while we can */ + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + flsh_cn &= 0xF7FFFFFF; + flsh_cn |= 0x00000010; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + + while (remaining >= 4) { + target_write_u32(target, info->flc_base + FLSH_ADDR, address); + target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, buffer); + flsh_cn |= 0x00000001; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + /* Wait until flash operation is complete */ + retry = 10; + + do { + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + + if (retry <= 0) { + LOG_ERROR("Timed out waiting for flash write @ 0x%08x", address); + return ERROR_FLASH_OPERATION_FAILED; + } + + buffer += 4; + address += 4; + remaining -= 4; + } + } + + if (remaining > 0) { + /* write remaining bytes in a 32-bit unit */ + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + flsh_cn &= 0xF7FFFFFF; + flsh_cn |= 0x00000010; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + + uint8_t last_word[4] = {0xff, 0xff, 0xff, 0xff}; + int i = 0; + + while (remaining > 0) { + last_word[i++] = *buffer; + buffer++; + remaining--; + } + + target_write_u32(target, info->flc_base + FLSH_ADDR, address); + target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, last_word); + flsh_cn |= 0x00000001; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + /* Wait until flash operation is complete */ + retry = 10; + + do { + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + + if (retry <= 0) { + LOG_ERROR("Timed out waiting for flash write @ 0x%08x", address); + return ERROR_FLASH_OPERATION_FAILED; + } + } + + /* Check access violations */ + target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int); + if (flsh_int & FLSH_INT_AF) { + LOG_ERROR("Flash Error writing 0x%x bytes at 0x%08x", count, offset); + max32xxx_flash_op_post(bank); + return ERROR_FLASH_OPERATION_FAILED; + } + + if (max32xxx_flash_op_post(bank) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +static int max32xxx_probe(struct flash_bank *bank) +{ + struct max32xxx_flash_bank *info = bank->driver_priv; + struct target *target = bank->target; + uint32_t arm_id[2]; + uint16_t arm_pid; + + if (bank->sectors) { + free(bank->sectors); + bank->sectors = NULL; + } + + /* provide this for the benefit of the NOR flash framework */ + bank->size = info->flash_size; + bank->num_sectors = info->flash_size / info->sector_size; + bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); + + for (int i = 0; i < bank->num_sectors; i++) { + bank->sectors[i].offset = i * info->sector_size; + bank->sectors[i].size = info->sector_size; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = -1; + } + + /* Probe to determine if this part is in the max326xx family */ + info->max326xx = 0; + target_read_u32(target, ARM_PID_REG, &arm_id[0]); + target_read_u32(target, ARM_PID_REG+4, &arm_id[1]); + arm_pid = (arm_id[1] << 8) + arm_id[0]; + LOG_DEBUG("arm_pid = 0x%x", arm_pid); + + if ((arm_pid == ARM_PID_DEFAULT_CM3) || arm_pid == ARM_PID_DEFAULT_CM4) { + uint32_t max326xx_id; + target_read_u32(target, MAX326XX_ID_REG, &max326xx_id); + LOG_DEBUG("max326xx_id = 0x%x", max326xx_id); + max326xx_id = ((max326xx_id & 0xFF000000) >> 24); + if (max326xx_id == MAX326XX_ID) + info->max326xx = 1; + } + LOG_DEBUG("info->max326xx = %d", info->max326xx); + + /* Initialize the protection bits for each flash page */ + if (max32xxx_protect_check(bank) == ERROR_FLASH_OPER_UNSUPPORTED) + LOG_WARNING("Flash protection not supported on this device"); + + info->probed = 1; + return ERROR_OK; +} + +static int max32xxx_mass_erase(struct flash_bank *bank) +{ + struct target *target = NULL; + struct max32xxx_flash_bank *info = NULL; + uint32_t flsh_cn, flsh_int; + int retval; + int retry; + info = bank->driver_priv; + target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (info->probed == 0) + return ERROR_FLASH_BANK_NOT_PROBED; + + int not_protected = 0; + for (int i = 0; i < bank->num_sectors; i++) { + if (bank->sectors[i].is_protected == 1) + LOG_WARNING("Flash sector %d is protected", i); + else + not_protected = 1; + } + + if (!not_protected) { + LOG_ERROR("All pages protected"); + return ERROR_FAIL; + } + + /* Prepare to issue flash operation */ + retval = max32xxx_flash_op_pre(bank); + + if (retval != ERROR_OK) + return retval; + + /* Write mass erase code */ + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + flsh_cn |= FLSH_CN_ERASE_CODE_ME; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + + /* Issue mass erase command */ + flsh_cn |= 0x2; + target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + + /* Wait until erase complete */ + retry = 1000; + do { + target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); + } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + + if (retry <= 0) { + LOG_ERROR("Timed out waiting for flash mass erase"); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* Check access violations */ + target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int); + if (flsh_int & FLSH_INT_AF) { + LOG_ERROR("Error mass erasing"); + target_write_u32(target, info->flc_base + FLSH_INT, 0); + return ERROR_FLASH_OPERATION_FAILED; + } + + if (max32xxx_flash_op_post(bank) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +COMMAND_HANDLER(max32xxx_handle_mass_erase_command) +{ + int i; + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + + if (CMD_ARGC < 1) { + command_print(CMD_CTX, "max32xxx mass_erase "); + return ERROR_OK; + } + + if (ERROR_OK != retval) + return retval; + + if (max32xxx_mass_erase(bank) == ERROR_OK) { + /* set all sectors as erased */ + for (i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_erased = 1; + + command_print(CMD_CTX, "max32xxx mass erase complete"); + } else + command_print(CMD_CTX, "max32xxx mass erase failed"); + + return ERROR_OK; +} + +COMMAND_HANDLER(max32xxx_handle_protection_set_command) +{ + struct flash_bank *bank; + int retval; + struct max32xxx_flash_bank *info; + uint32_t addr, len; + + if (CMD_ARGC != 3) { + command_print(CMD_CTX, "max32xxx protection_set "); + return ERROR_OK; + } + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + info = bank->driver_priv; + + /* Convert the range to the page numbers */ + if (1 != sscanf(CMD_ARGV[1], "0x%"SCNx32, &addr)) { + LOG_WARNING("Error parsing address"); + command_print(CMD_CTX, "max32xxx protection_set "); + return ERROR_FAIL; + } + /* Mask off the top portion on the address */ + addr = (addr & 0x0FFFFFFF); + + if (1 != sscanf(CMD_ARGV[2], "0x%"SCNx32, &len)) { + LOG_WARNING("Error parsing length"); + command_print(CMD_CTX, "max32xxx protection_set "); + return ERROR_FAIL; + } + + /* Check the address is in the range of the flash */ + if ((addr+len) >= info->flash_size) + return ERROR_FLASH_SECTOR_INVALID; + + if (len == 0) + return ERROR_OK; + + /* Convert the address and length to the page boundaries */ + addr = addr - (addr % info->sector_size); + if (len % info->sector_size) + len = len + info->sector_size - (len % info->sector_size); + + /* Convert the address and length to page numbers */ + addr = (addr / info->sector_size); + len = addr + (len / info->sector_size) - 1; + + if (max32xxx_protect(bank, 1, addr, len) == ERROR_OK) + command_print(CMD_CTX, "max32xxx protection set complete"); + else + command_print(CMD_CTX, "max32xxx protection set failed"); + + return ERROR_OK; +} + +COMMAND_HANDLER(max32xxx_handle_protection_clr_command) +{ + struct flash_bank *bank; + int retval; + struct max32xxx_flash_bank *info; + uint32_t addr, len; + + if (CMD_ARGC != 3) { + command_print(CMD_CTX, "max32xxx protection_clr "); + return ERROR_OK; + } + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + info = bank->driver_priv; + + /* Convert the range to the page numbers */ + if (1 != sscanf(CMD_ARGV[1], "0x%"SCNx32, &addr)) { + LOG_WARNING("Error parsing address"); + command_print(CMD_CTX, "max32xxx protection_clr "); + return ERROR_FAIL; + } + /* Mask off the top portion on the address */ + addr = (addr & 0x0FFFFFFF); + + if (1 != sscanf(CMD_ARGV[2], "0x%"SCNx32, &len)) { + LOG_WARNING("Error parsing length"); + command_print(CMD_CTX, "max32xxx protection_clr "); + return ERROR_FAIL; + } + + /* Check the address is in the range of the flash */ + if ((addr+len) >= info->flash_size) + return ERROR_FLASH_SECTOR_INVALID; + + if (len == 0) + return ERROR_OK; + + /* Convert the address and length to the page boundaries */ + addr = addr - (addr % info->sector_size); + if (len % info->sector_size) + len = len + info->sector_size - (len % info->sector_size); + + /* Convert the address and length to page numbers */ + addr = (addr / info->sector_size); + len = addr + (len / info->sector_size) - 1; + + if (max32xxx_protect(bank, 0, addr, len) == ERROR_OK) + command_print(CMD_CTX, "max32xxx protection clear complete"); + else + command_print(CMD_CTX, "max32xxx protection clear failed"); + + return ERROR_OK; +} + +COMMAND_HANDLER(max32xxx_handle_protection_check_command) +{ + struct flash_bank *bank; + int retval; + struct max32xxx_flash_bank *info; + int i; + + if (CMD_ARGC < 1) { + command_print(CMD_CTX, "max32xxx protection_check "); + return ERROR_OK; + } + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + info = bank->driver_priv; + + /* Update the protection array */ + retval = max32xxx_protect_check(bank); + if (ERROR_OK != retval) { + LOG_WARNING("Error updating the protection array"); + return retval; + } + + LOG_WARNING("s: a:
p:"); + for (i = 0; i < bank->num_sectors; i += 4) { + LOG_WARNING("s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d", + (i+0), (i+0)*info->sector_size, bank->sectors[(i+0)].is_protected, + (i+1), (i+1)*info->sector_size, bank->sectors[(i+1)].is_protected, + (i+2), (i+2)*info->sector_size, bank->sectors[(i+2)].is_protected, + (i+3), (i+3)*info->sector_size, bank->sectors[(i+3)].is_protected); + } + + return ERROR_OK; +} + +static const struct command_registration max32xxx_exec_command_handlers[] = { + { + .name = "mass_erase", + .handler = max32xxx_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "mass erase flash", + }, + { + .name = "protection_set", + .handler = max32xxx_handle_protection_set_command, + .mode = COMMAND_EXEC, + .usage = "bank_id addr size", + .help = "set flash protection for address range", + }, + { + .name = "protection_clr", + .handler = max32xxx_handle_protection_clr_command, + .mode = COMMAND_EXEC, + .usage = "bank_id addr size", + .help = "clear flash protection for address range", + }, + { + .name = "protection_check", + .handler = max32xxx_handle_protection_check_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "check flash protection", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration max32xxx_command_handlers[] = { + { + .name = "max32xxx", + .mode = COMMAND_EXEC, + .help = "max32xxx flash command group", + .chain = max32xxx_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct flash_driver max32xxx_flash = { + .name = "max32xxx", + .commands = max32xxx_command_handlers, + .flash_bank_command = max32xxx_flash_bank_command, + .erase = max32xxx_erase, + .protect = max32xxx_protect, + .write = max32xxx_write, + .read = default_flash_read, + .probe = max32xxx_probe, + .auto_probe = max32xxx_probe, + .erase_check = default_flash_blank_check, + .protect_check = max32xxx_protect_check, + .info = get_info, +}; diff --git a/tcl/target/max32620.cfg b/tcl/target/max32620.cfg new file mode 100644 index 000000000..80cb25a47 --- /dev/null +++ b/tcl/target/max32620.cfg @@ -0,0 +1,28 @@ +# Maxim Integrated MAX32620 OpenOCD target configuration file +# www.maximintegrated.com + +# adapter speed +adapter_khz 4000 + +# reset pin configuration +reset_config srst_only + +if {[using_jtag]} { + jtag newtap max32620 cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version + jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -ignore-version +} else { + swd newdap max32620 cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version +} + +# target configuration +target create max32620.cpu cortex_m -chain-position max32620.cpu +max32620.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 + +# Config Command: flash bank name driver base size chip_width bus_width target [driver_options] +# flash bank max32xxx 0 0 +# max32620 flash base address 0x00000000 +# max32620 flash size 0x200000 (2MB) +# max32620 FLC base address 0x40002000 +# max32620 sector (page) size 0x2000 (8kB) +# max32620 clock speed 96 (MHz) +flash bank max32620.flash max32xxx 0x00000000 0x200000 0 0 max32620.cpu 0x40002000 0x2000 96 diff --git a/tcl/target/max32625.cfg b/tcl/target/max32625.cfg new file mode 100644 index 000000000..7182b235f --- /dev/null +++ b/tcl/target/max32625.cfg @@ -0,0 +1,28 @@ +# Maxim Integrated MAX32625 OpenOCD target configuration file +# www.maximintegrated.com + +# adapter speed +adapter_khz 4000 + +# reset pin configuration +reset_config srst_only + +if {[using_jtag]} { + jtag newtap max32625 cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version + jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -expected-id 0x07f71197 -ignore-version +} else { + swd newdap max32625 cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version +} + +# target configuration +target create max32625.cpu cortex_m -chain-position max32625.cpu +max32625.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 + +# Config Command: flash bank name driver base size chip_width bus_width target [driver_options] +# flash bank max32xxx 0 0 +# max32625 flash base address 0x00000000 +# max32625 flash size 0x80000 (512k) +# max32625 FLC base address 0x40002000 +# max32625 sector (page) size 0x2000 (8kB) +# max32625 clock speed 96 (MHz) +flash bank max32625.flash max32xxx 0x00000000 0x80000 0 0 max32625.cpu 0x40002000 0x2000 96 diff --git a/tcl/target/max3263x.cfg b/tcl/target/max3263x.cfg new file mode 100644 index 000000000..f23b0b64d --- /dev/null +++ b/tcl/target/max3263x.cfg @@ -0,0 +1,28 @@ +# Maxim Integrated MAX3263X OpenOCD target configuration file +# www.maximintegrated.com + +# adapter speed +adapter_khz 4000 + +# reset pin configuration +reset_config srst_only + +if {[using_jtag]} { + jtag newtap max3263x cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version + jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -expected-id 0x07f76197 -ignore-version +} else { + swd newdap max3263x cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version +} + +# target configuration +target create max3263x.cpu cortex_m -chain-position max3263x.cpu +max3263x.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 + +# Config Command: flash bank name driver base size chip_width bus_width target [driver_options] +# flash bank max32xxx 0 0 +# max3263x flash base address 0x00000000 +# max3263x flash size 0x200000 (2MB) +# max3263x FLC base address 0x40002000 +# max3263x sector (page) size 0x2000 (8kB) +# max3263x clock speed 96 (MHz) +flash bank max3263x.flash max32xxx 0x00000000 0x200000 0 0 max3263x.cpu 0x40002000 0x2000 96 From e537e807f6e634eb921988ad5db353cdcf03ee50 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sat, 21 Jul 2018 10:28:48 +0200 Subject: [PATCH 088/147] flash/at91sam4: run probe just once Reread registers in sam4_GetInfo() Change-Id: I3b023b3e642a9c052b5c41673d196317f7e7f2e3 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4609 Tested-by: jenkins Reviewed-by: Erwin Oegema Reviewed-by: Svetoslav Enchev --- src/flash/nor/at91sam4.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index c5b31e964..f922c762b 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -2376,6 +2376,11 @@ static int sam4_GetInfo(struct sam4_chip *pChip) { const struct sam4_reg_list *pReg; uint32_t regval; + int r; + + r = sam4_ReadAllRegs(pChip); + if (r != ERROR_OK) + return r; pReg = &(sam4_all_regs[0]); while (pReg->name) { @@ -2581,14 +2586,14 @@ static int sam4_GetDetails(struct sam4_bank_private *pPrivate) return ERROR_OK; } -static int _sam4_probe(struct flash_bank *bank, int noise) +static int sam4_probe(struct flash_bank *bank) { unsigned x; int r; struct sam4_bank_private *pPrivate; - LOG_DEBUG("Begin: Bank: %d, Noise: %d", bank->bank_number, noise); + LOG_DEBUG("Begin: Bank: %d", bank->bank_number); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; @@ -2655,14 +2660,15 @@ static int _sam4_probe(struct flash_bank *bank, int noise) return r; } -static int sam4_probe(struct flash_bank *bank) -{ - return _sam4_probe(bank, 1); -} - static int sam4_auto_probe(struct flash_bank *bank) { - return _sam4_probe(bank, 0); + struct sam4_bank_private *pPrivate; + + pPrivate = get_sam4_bank_private(bank); + if (pPrivate && pPrivate->probed) + return ERROR_OK; + + return sam4_probe(bank); } static int sam4_erase(struct flash_bank *bank, int first, int last) From 20922f47c74b97c5d39f8e3036a107ebfdc7e8c3 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sat, 21 Jul 2018 11:17:59 +0200 Subject: [PATCH 089/147] flash/at91sam4: emit flash bank info Change related LOG_INFO to LOG_DEBUG Change-Id: I0c09b1ec83da631b26980dc8632b9031fe2921a3 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4610 Tested-by: jenkins Reviewed-by: Erwin Oegema Reviewed-by: Svetoslav Enchev --- src/flash/nor/at91sam4.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index f922c762b..b8f4e1622 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -2550,7 +2550,7 @@ static int sam4_GetDetails(struct sam4_bank_private *pPrivate) sam4_explain_chipid_cidr(pPrivate->pChip); return ERROR_FAIL; } else { - LOG_INFO("SAM4 Found chip %s, CIDR 0x%08x", pDetails->name, pDetails->chipid_cidr); + LOG_DEBUG("SAM4 Found chip %s, CIDR 0x%08x", pDetails->name, pDetails->chipid_cidr); } /* DANGER: THERE ARE DRAGONS HERE */ @@ -2586,6 +2586,27 @@ static int sam4_GetDetails(struct sam4_bank_private *pPrivate) return ERROR_OK; } +static int sam4_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct sam4_bank_private *pPrivate; + int k = bank->size / 1024; + + pPrivate = get_sam4_bank_private(bank); + if (pPrivate == NULL) { + buf[0] = '\0'; + return ERROR_FAIL; + } + + snprintf(buf, buf_size, + "%s bank %d: %d kB at 0x%08" PRIx32, + pPrivate->pChip->details.name, + pPrivate->bank_number, + k, + bank->base); + + return ERROR_OK; +} + static int sam4_probe(struct flash_bank *bank) { unsigned x; @@ -2621,7 +2642,7 @@ static int sam4_probe(struct flash_bank *bank) for (x = 0; x < SAM4_MAX_FLASH_BANKS; x++) { if (bank->base == pPrivate->pChip->details.bank[x].base_address) { bank->size = pPrivate->pChip->details.bank[x].size_bytes; - LOG_INFO("SAM4 Set flash bank to %08X - %08X, idx %d", bank->base, bank->base + bank->size, x); + LOG_DEBUG("SAM4 Set flash bank to %08X - %08X, idx %d", bank->base, bank->base + bank->size, x); break; } } @@ -3209,5 +3230,6 @@ struct flash_driver at91sam4_flash = { .auto_probe = sam4_auto_probe, .erase_check = default_flash_blank_check, .protect_check = sam4_protect_check, + .info = sam4_info, .free_driver_priv = sam4_free_driver_priv, }; From d78cf6f3126b0c28321d36614e184912dfc0c609 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sat, 21 Jul 2018 13:21:08 +0200 Subject: [PATCH 090/147] flash/at91sam4: set wait states only once per write Read-modify-write setting of FMR register requires an USB turnaround. Setting FMR before each page write is not necessary and decreases the write speed. Change-Id: I67844c898aaf117f155c762c979840b603c767ed Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4611 Tested-by: jenkins Reviewed-by: Svetoslav Enchev --- src/flash/nor/at91sam4.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index b8f4e1622..577360a6e 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -2789,20 +2789,17 @@ static int sam4_page_read(struct sam4_bank_private *pPrivate, unsigned pagenum, return r; } -static int sam4_page_write(struct sam4_bank_private *pPrivate, unsigned pagenum, const uint8_t *buf) +static int sam4_set_wait(struct sam4_bank_private *pPrivate) { - uint32_t adr; - uint32_t status; uint32_t fmr; /* EEFC Flash Mode Register */ int r; - adr = pagenum * pPrivate->page_size; - adr = (adr + pPrivate->base_address); - /* Get flash mode register value */ r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address, &fmr); - if (r != ERROR_OK) - LOG_DEBUG("Error Read failed: read flash mode register"); + if (r != ERROR_OK) { + LOG_ERROR("Error Read failed: read flash mode register"); + return r; + } /* Clear flash wait state field */ fmr &= 0xfffff0ff; @@ -2813,7 +2810,19 @@ static int sam4_page_write(struct sam4_bank_private *pPrivate, unsigned pagenum, LOG_DEBUG("Flash Mode: 0x%08x", ((unsigned int)(fmr))); r = target_write_u32(pPrivate->pBank->target, pPrivate->controller_address, fmr); if (r != ERROR_OK) - LOG_DEBUG("Error Write failed: set flash mode register"); + LOG_ERROR("Error Write failed: set flash mode register"); + + return r; +} + +static int sam4_page_write(struct sam4_bank_private *pPrivate, unsigned pagenum, const uint8_t *buf) +{ + uint32_t adr; + uint32_t status; + int r; + + adr = pagenum * pPrivate->page_size; + adr = (adr + pPrivate->base_address); /* 1st sector 8kBytes - page 0 - 15*/ /* 2nd sector 8kBytes - page 16 - 30*/ @@ -2901,6 +2910,10 @@ static int sam4_write(struct flash_bank *bank, goto done; } + r = sam4_set_wait(pPrivate); + if (r != ERROR_OK) + goto done; + /* what page do we start & end in? */ page_cur = offset / pPrivate->page_size; page_end = (offset + count - 1) / pPrivate->page_size; From 6ec5fe8269fc1b28531c734071f8dd5abf984b46 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sun, 5 Aug 2018 16:39:31 +0200 Subject: [PATCH 091/147] flash/at91sam4: fix clang static analyzer warning Change-Id: I5e5319d855c868adfa012f68086f7f809ec5a069 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4639 Tested-by: jenkins --- src/flash/nor/at91sam4.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index 577360a6e..2eec15e2a 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -3131,7 +3131,8 @@ showall: } if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) { r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v); - command_print(CMD_CTX, "sam4-gpnvm%u: %u", who, v); + if (r == ERROR_OK) + command_print(CMD_CTX, "sam4-gpnvm%u: %u", who, v); return r; } else { command_print(CMD_CTX, "sam4-gpnvm invalid GPNVM: %u", who); From 704d7ac2d0551514b81650addd76e35327c7beb0 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sun, 5 Aug 2018 17:16:01 +0200 Subject: [PATCH 092/147] rtos/linux.c: fix clang static analyzer warning Remove sizeof(int64_t) from string size computation. Change-Id: I029b394df5d62a2594a723c4c0e13608b3423b9b Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4640 Tested-by: jenkins --- src/rtos/linux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 3b2a2b0c3..4529ddb9a 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -1134,7 +1134,7 @@ int linux_gdb_thread_packet(struct target *target, if (retval != ERROR_OK) return ERROR_TARGET_FAILURE; - char *out_str = calloc(1, 350 * sizeof(int64_t)); + char *out_str = calloc(MAX_THREADS * 17 + 10, 1); char *tmp_str = out_str; tmp_str += sprintf(tmp_str, "m"); struct threads *temp = linux_os->thread_list; @@ -1171,7 +1171,7 @@ int linux_gdb_thread_update(struct target *target, if (found == 1) { /*LOG_INFO("INTO GDB THREAD UPDATE FOUNDING START TASK");*/ - char *out_strr = calloc(1, 350 * sizeof(int64_t)); + char *out_strr = calloc(MAX_THREADS * 17 + 10, 1); char *tmp_strr = out_strr; tmp_strr += sprintf(tmp_strr, "m"); /*LOG_INFO("CHAR MALLOC & M DONE");*/ From 2a3b709aa5d1ab83faed1dc7c296ffc117022d62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Fri, 10 Aug 2018 12:01:17 +0200 Subject: [PATCH 093/147] target: armv8: Ensure target is halted for virt2phys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Othewise the error reported as Timeout waiting for dpm prepare Change-Id: Ieed2fdcd94ae4e877a749df3eec07a01dbf80b10 Closes: https://sourceforge.net/p/openocd/tickets/201/ Found-by: Matthias Welwarsky Signed-off-by: Guido Günther Reviewed-on: http://openocd.zylin.com/4647 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/armv8.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/target/armv8.c b/src/target/armv8.c index dfa2c67a5..75ada896d 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -936,6 +936,11 @@ int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va, "Secure", "Not Secure" }; + if (target->state != TARGET_HALTED) { + LOG_WARNING("target %s not halted", target_name(target)); + return ERROR_TARGET_NOT_HALTED; + } + retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; From 11019a824d0273012e9b253fd63ddda6a2468c83 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 5 Sep 2018 15:37:15 +0200 Subject: [PATCH 094/147] adi_v5: enforce check on AP number value The AP number value is restricted in 8 bits unsigned by ADI-v5 specification. Nevertheless, an "invalid" value is used by target cortex-m to force an automatic detection of the AP. Replace magic numbers by using new macros for AP max number and for the value of AP invalid. Check the value passed through -ap-num flag during configuration. Change-Id: Ic19a367db0ab11c0ebd070750eca0647d25279a5 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4668 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/arm_adi_v5.c | 20 ++++++++++++-------- src/target/arm_adi_v5.h | 3 +++ src/target/arm_cti.c | 4 ++++ src/target/arm_dap.c | 4 ++-- src/target/cortex_m.c | 2 +- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 302ea7891..b4e252bb4 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -793,7 +793,7 @@ int dap_find_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_a int ap_num; /* Maximum AP number is 255 since the SELECT register is 8 bits */ - for (ap_num = 0; ap_num <= 255; ap_num++) { + for (ap_num = 0; ap_num <= DP_APSEL_MAX; ap_num++) { /* read the IDR register of the Access Port */ uint32_t id_val = 0; @@ -1429,7 +1429,7 @@ int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi) pc = (struct adiv5_private_config *)target->private_config; if (pc == NULL) { pc = calloc(1, sizeof(struct adiv5_private_config)); - pc->ap_num = -1; + pc->ap_num = DP_APSEL_INVALID; target->private_config = pc; } @@ -1498,6 +1498,10 @@ int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi) e = Jim_GetOpt_Wide(goi, &ap_num); if (e != JIM_OK) return e; + if (ap_num < 0 || ap_num > DP_APSEL_MAX) { + Jim_SetResultString(goi->interp, "Invalid AP number!", -1); + return JIM_ERR; + } pc->ap_num = ap_num; } else { if (goi->argc != 0) { @@ -1507,7 +1511,7 @@ int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_ERR; } - if (pc->ap_num < 0) { + if (pc->ap_num == DP_APSEL_INVALID) { Jim_SetResultString(goi->interp, "AP number not configured", -1); return JIM_ERR; } @@ -1543,7 +1547,7 @@ COMMAND_HANDLER(handle_dap_info_command) break; case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); - if (apsel >= 256) + if (apsel > DP_APSEL_MAX) return ERROR_COMMAND_SYNTAX_ERROR; break; default: @@ -1566,7 +1570,7 @@ COMMAND_HANDLER(dap_baseaddr_command) case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel >= 256) + if (apsel > DP_APSEL_MAX) return ERROR_COMMAND_SYNTAX_ERROR; break; default: @@ -1625,7 +1629,7 @@ COMMAND_HANDLER(dap_apsel_command) case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel >= 256) + if (apsel > DP_APSEL_MAX) return ERROR_COMMAND_SYNTAX_ERROR; break; default: @@ -1691,7 +1695,7 @@ COMMAND_HANDLER(dap_apid_command) case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel >= 256) + if (apsel > DP_APSEL_MAX) return ERROR_COMMAND_SYNTAX_ERROR; break; default: @@ -1722,7 +1726,7 @@ COMMAND_HANDLER(dap_apreg_command) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel >= 256) + if (apsel > DP_APSEL_MAX) return ERROR_COMMAND_SYNTAX_ERROR; ap = dap_ap(dap, apsel); diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index 883ac8b5d..a340b76f0 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -136,6 +136,9 @@ #define DP_SELECT_DPBANK 0x0000000F #define DP_SELECT_INVALID 0x00FFFF00 /* Reserved bits one */ +#define DP_APSEL_MAX (255) +#define DP_APSEL_INVALID (-1) + /** * This represents an ARM Debug Interface (v5) Access Port (AP). * Most common is a MEM-AP, for memory access. diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index 0d117e76d..dcaf21e50 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -431,6 +431,10 @@ static int cti_configure(Jim_GetOptInfo *goi, struct arm_cti_object *cti) e = Jim_GetOpt_Wide(goi, &w); if (e != JIM_OK) return e; + if (w < 0 || w > DP_APSEL_MAX) { + Jim_SetResultString(goi->interp, "-ap-num is invalid", -1); + return JIM_ERR; + } cti->ap_num = (uint32_t)w; } } diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c index 3be4d7199..3adb4ed26 100644 --- a/src/target/arm_dap.c +++ b/src/target/arm_dap.c @@ -48,7 +48,7 @@ static void dap_instance_init(struct adiv5_dap *dap) { int i; /* Set up with safe defaults */ - for (i = 0; i <= 255; i++) { + for (i = 0; i <= DP_APSEL_MAX; i++) { dap->ap[i].dap = dap; dap->ap[i].ap_num = i; /* memaccess_tck max is 255 */ @@ -319,7 +319,7 @@ COMMAND_HANDLER(handle_dap_info_command) break; case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); - if (apsel >= 256) + if (apsel > DP_APSEL_MAX) return ERROR_COMMAND_SYNTAX_ERROR; break; default: diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index ca3dbec78..d1f7f3eea 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1986,7 +1986,7 @@ int cortex_m_examine(struct target *target) /* stlink shares the examine handler but does not support * all its calls */ if (!armv7m->stlink) { - if (cortex_m->apsel < 0) { + if (cortex_m->apsel == DP_APSEL_INVALID) { /* Search for the MEM-AP */ retval = dap_find_ap(swjdp, AP_TYPE_AHB_AP, &armv7m->debug_ap); if (retval != ERROR_OK) { From ab858febb6ca6e5dada1492e96c00d8b12c575c0 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 21 May 2018 16:14:33 +0200 Subject: [PATCH 095/147] gdb_server: add per target option "-gdb-port" The argument passed to global config command "gdb_port" is usually, but not always, a TCP port number. In case of multiple targets, this numeric value is used as the first port of a set of consecutive TCP ports assigned one per target. If the argument is not a numeric value (e.g. "pipe", "disabled", ...) then incrementing it for the next target has no sense. Add the option "-gdb-port number" to the commands "target create" and "$target_name configure" to override, for the specific target, the general global configuration. This permits to use a per target "-gdb-port disabled", when no gdb port is required for that specific target. It also makes possible to choose a custom TCP port number for each target, overriding the usual sequence of consecutive port numbers. Change-Id: I3b9a1910b28ab4bc757e839d0e5d08ffc29f7ab4 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4530 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Matthias Welwarsky --- doc/openocd.texi | 14 +++++++++++++- src/server/gdb_server.c | 27 +++++++++++++++++++-------- src/target/target.c | 21 +++++++++++++++++++++ src/target/target.h | 2 ++ 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index c0d065d4b..3eb630902 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2114,6 +2114,7 @@ In such cases, just specify the relevant port number as "disabled". If you disable all access through TCP/IP, you will need to use the command line @option{-pipe} option. +@anchor{gdb_port} @deffn {Command} gdb_port [number] @cindex GDB server Normally gdb listens to a TCP/IP port, but GDB can also @@ -2139,11 +2140,15 @@ The GDB port for the first target will be the base port, the second target will listen on gdb_port + 1, and so on. When not specified during the configuration stage, the port @var{number} defaults to 3333. +When @var{number} is not a numeric value, incrementing it to compute +the next port number does not work. In this case, specify the proper +@var{number} for each target by using the option @code{-gdb-port} of the +commands @command{target create} or @command{$target_name configure}. +@xref{gdbportoverride,,option -gdb-port}. Note: when using "gdb_port pipe", increasing the default remote timeout in gdb (with 'set remotetimeout') is recommended. An insufficient timeout may cause initialization to fail with "Unknown remote qXfer reply: OK". - @end deffn @deffn {Command} tcl_port [number] @@ -4458,6 +4463,13 @@ to the target. Currently, only the @code{aarch64} target makes use of this optio where it is a mandatory configuration for the target run control. @xref{armcrosstrigger,,ARM Cross-Trigger Interface}, for instruction on how to declare and control a CTI instance. + +@anchor{gdbportoverride} +@item @code{-gdb-port} @var{number} -- see command @command{gdb_port} for the +possible values of the parameter @var{number}, which are not only numeric values. +Use this option to override, for this target only, the global parameter set with +command @command{gdb_port}. +@xref{gdb_port,,command gdb_port}. @end itemize @end deffn diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 69afb2fd4..2375e9511 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -3373,6 +3373,8 @@ static int gdb_target_start(struct target *target, const char *port) if (NULL == gdb_service) return -ENOMEM; + LOG_DEBUG("starting gdb server for %s on %s", target_name(target), port); + gdb_service->target = target; gdb_service->core[0] = -1; gdb_service->core[1] = -1; @@ -3398,16 +3400,30 @@ static int gdb_target_start(struct target *target, const char *port) static int gdb_target_add_one(struct target *target) { + /* one gdb instance per smp list */ + if ((target->smp) && (target->gdb_service)) + return ERROR_OK; + + if (target->gdb_port_override) { + if (strcmp(target->gdb_port_override, "disabled") == 0) { + LOG_INFO("gdb port disabled"); + return ERROR_OK; + } + return gdb_target_start(target, target->gdb_port_override); + } + if (strcmp(gdb_port, "disabled") == 0) { LOG_INFO("gdb port disabled"); return ERROR_OK; } - /* one gdb instance per smp list */ - if ((target->smp) && (target->gdb_service)) - return ERROR_OK; int retval = gdb_target_start(target, gdb_port_next); if (retval == ERROR_OK) { + /* save the port number so can be queried with + * $target_name cget -gdb-port + */ + target->gdb_port_override = strdup(gdb_port_next); + long portnumber; /* If we can parse the port number * then we increment the port number for the next target. @@ -3432,11 +3448,6 @@ static int gdb_target_add_one(struct target *target) int gdb_target_add_all(struct target *target) { - if (strcmp(gdb_port, "disabled") == 0) { - LOG_INFO("gdb server disabled"); - return ERROR_OK; - } - if (NULL == target) { LOG_WARNING("gdb services need one or more targets defined"); return ERROR_OK; diff --git a/src/target/target.c b/src/target/target.c index 68f93210a..253928d7c 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1927,6 +1927,7 @@ static void target_destroy(struct target *target) target->smp = 0; } + free(target->gdb_port_override); free(target->type); free(target->trace_info); free(target->fileio_info); @@ -4537,6 +4538,7 @@ enum target_cfg_param { TCFG_DBGBASE, TCFG_RTOS, TCFG_DEFER_EXAMINE, + TCFG_GDB_PORT, }; static Jim_Nvp nvp_config_opts[] = { @@ -4552,6 +4554,7 @@ static Jim_Nvp nvp_config_opts[] = { { .name = "-dbgbase", .value = TCFG_DBGBASE }, { .name = "-rtos", .value = TCFG_RTOS }, { .name = "-defer-examine", .value = TCFG_DEFER_EXAMINE }, + { .name = "-gdb-port", .value = TCFG_GDB_PORT }, { .name = NULL, .value = -1 } }; @@ -4839,6 +4842,20 @@ no_params: /* loop for more */ break; + case TCFG_GDB_PORT: + if (goi->isconfigure) { + const char *s; + e = Jim_GetOpt_String(goi, &s, NULL); + if (e != JIM_OK) + return e; + target->gdb_port_override = strdup(s); + } else { + if (goi->argc != 0) + goto no_params; + } + Jim_SetResultString(goi->interp, target->gdb_port_override ? : "undefined", -1); + /* loop for more */ + break; } } /* while (goi->argc) */ @@ -5613,6 +5630,8 @@ static int target_create(Jim_GetOptInfo *goi) target->rtos = NULL; target->rtos_auto_detect = false; + target->gdb_port_override = NULL; + /* Do the rest as "configure" options */ goi->isconfigure = 1; e = target_configure(goi, target); @@ -5635,6 +5654,7 @@ static int target_create(Jim_GetOptInfo *goi) } if (e != JIM_OK) { + free(target->gdb_port_override); free(target->type); free(target); return e; @@ -5652,6 +5672,7 @@ static int target_create(Jim_GetOptInfo *goi) e = (*(target->type->target_create))(target, goi->interp); if (e != ERROR_OK) { LOG_DEBUG("target_create failed"); + free(target->gdb_port_override); free(target->type); free(target->cmd_name); free(target); diff --git a/src/target/target.h b/src/target/target.h index 51a5b6935..c3137a08c 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -206,6 +206,8 @@ struct target { /* file-I/O information for host to do syscall */ struct gdb_fileio_info *fileio_info; + char *gdb_port_override; /* target-specific override for gdb_port */ + /* The semihosting information, extracted from the target. */ struct semihosting *semihosting; }; From d1b74376336814266236054f925a9964b87dd8a5 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 5 Jul 2018 11:46:44 +0200 Subject: [PATCH 096/147] libusb: return oocd error values keep same return style where possible Change-Id: I2f9b85dbc307a483609f76a84de77e3c74d346c7 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4588 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/jtag/drivers/libusb1_common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jtag/drivers/libusb1_common.c b/src/jtag/drivers/libusb1_common.c index 89f809271..a1db86f4b 100644 --- a/src/jtag/drivers/libusb1_common.c +++ b/src/jtag/drivers/libusb1_common.c @@ -71,11 +71,11 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], struct jtag_libusb_device_handle **out) { int cnt, idx, errCode; - int retval = -ENODEV; + int retval = ERROR_FAIL; struct jtag_libusb_device_handle *libusb_handle = NULL; if (libusb_init(&jtag_libusb_context) < 0) - return -ENODEV; + return ERROR_FAIL; cnt = libusb_get_device_list(jtag_libusb_context, &devs); @@ -105,7 +105,7 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], /* Success. */ *out = libusb_handle; - retval = 0; + retval = ERROR_OK; break; } if (cnt >= 0) From 724fddcba0482d674ca2a630bb8790eee63e29b8 Mon Sep 17 00:00:00 2001 From: Steven Stallion Date: Tue, 28 Aug 2018 17:02:10 -0700 Subject: [PATCH 097/147] rtos-helpers: fix minor typo in uC/OS-III helper This patch corrects a spelling error in uCOS-III-openocd.c. Change-Id: I6d1923ff1f5e6361358c45cec3dd6c08ca9ccef0 Signed-off-by: Steven Stallion Reviewed-on: http://openocd.zylin.com/4659 Tested-by: jenkins Reviewed-by: Antonio Borneo --- contrib/rtos-helpers/uCOS-III-openocd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/rtos-helpers/uCOS-III-openocd.c b/contrib/rtos-helpers/uCOS-III-openocd.c index 9037334f2..5a37bd4c5 100644 --- a/contrib/rtos-helpers/uCOS-III-openocd.c +++ b/contrib/rtos-helpers/uCOS-III-openocd.c @@ -3,8 +3,8 @@ * impossible to determine the appropriate offsets within the structure * unaided. A priori knowledge of offsets based on os_dbg.c is tied to a * specific release and thusly, brittle. The constants defined below - * provide the neccessary information OpenOCD needs to provide support - * in the most robust manner possible. + * provide the necessary information OpenOCD needs to provide support in + * the most robust manner possible. * * This file should be linked along with the project to enable RTOS * support for uC/OS-III. From 23cd59cdf2a563b840e5917e36c4241ee4d988f4 Mon Sep 17 00:00:00 2001 From: Cody Schafer Date: Tue, 21 Aug 2018 10:46:40 -0400 Subject: [PATCH 098/147] flash/stm32f2x: add stm32f7 revision Z identification Signed-off-by: Cody P Schafer Change-Id: Ia0169514d494bae2a98d92ebc97c8eccc10bc6c4 Reviewed-on: http://openocd.zylin.com/4657 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Tomas Vanek --- src/flash/nor/stm32f2x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 413d04d77..b46fb0786 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -1190,6 +1190,9 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) case 0x1000: rev_str = "A"; break; + case 0x1001: + rev_str = "Z"; + break; } break; From 5d458cf72734a4474f38bbed10eea4d9acfe93a2 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Mon, 20 Feb 2017 14:29:01 +0100 Subject: [PATCH 099/147] target/mem_ap: generic mem-ap target This pseudo target allows attaching to any access point on the DAP at the MEM-AP level and read and write addresses on the connected bus. For example, one can create a mem_ap target on the APB-AP and read and write registers of debug components directly. This allows many diagnostic and other features be programmed entirely using TCL, without necessity of adding drivers to OpenOCD. Change-Id: I53229ffd68fb0f96fb68be15b0f3a76cc8843c8e Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4002 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Leonard Crestez --- src/target/Makefile.am | 3 +- src/target/mem_ap.c | 181 +++++++++++++++++++++++++++++++++++++++++ src/target/target.c | 2 + 3 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 src/target/mem_ap.c diff --git a/src/target/Makefile.am b/src/target/Makefile.am index b1119e7df..4b7c8c076 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -75,7 +75,8 @@ ARMV7_SRC = \ %D%/cortex_m.c \ %D%/armv7a.c \ %D%/cortex_a.c \ - %D%/ls1_sap.c + %D%/ls1_sap.c \ + %D%/mem_ap.c ARMV8_SRC = \ %D%/armv8_dpm.c \ diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c new file mode 100644 index 000000000..3a2d4b7c5 --- /dev/null +++ b/src/target/mem_ap.c @@ -0,0 +1,181 @@ +/***************************************************************************** + * Copyright (C) 2016 by Matthias Welwarsky * + * * + * 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. * + ****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "target.h" +#include "target_type.h" +#include "arm.h" +#include "arm_adi_v5.h" + +#include + +struct mem_ap { + struct arm arm; + struct adiv5_ap *ap; + int ap_num; +}; + +static int mem_ap_target_create(struct target *target, Jim_Interp *interp) +{ + struct mem_ap *mem_ap = calloc(1, sizeof(struct mem_ap)); + struct adiv5_private_config *pc; + + pc = (struct adiv5_private_config *)target->private_config; + if (pc == NULL) + return ERROR_FAIL; + + if (pc->ap_num == DP_APSEL_INVALID) { + LOG_ERROR("AP number not specified"); + return ERROR_FAIL; + } + + mem_ap->ap_num = pc->ap_num; + mem_ap->arm.common_magic = ARM_COMMON_MAGIC; + mem_ap->arm.dap = pc->dap; + + target->arch_info = mem_ap; + + return ERROR_OK; +} + +static int mem_ap_init_target(struct command_context *cmd_ctx, struct target *target) +{ + LOG_DEBUG("%s", __func__); + target->state = TARGET_UNKNOWN; + return ERROR_OK; +} + +static int mem_ap_arch_state(struct target *target) +{ + LOG_DEBUG("%s", __func__); + return ERROR_OK; +} + +static int mem_ap_poll(struct target *target) +{ + if (target->state == TARGET_UNKNOWN) + target->state = TARGET_RUNNING; + + return ERROR_OK; +} + +static int mem_ap_halt(struct target *target) +{ + LOG_DEBUG("%s", __func__); + target->state = TARGET_HALTED; + return ERROR_OK; +} + +static int mem_ap_resume(struct target *target, int current, target_addr_t address, + int handle_breakpoints, int debug_execution) +{ + LOG_DEBUG("%s", __func__); + target->state = TARGET_RUNNING; + return ERROR_OK; +} + +static int mem_ap_step(struct target *target, int current, target_addr_t address, + int handle_breakpoints) +{ + LOG_DEBUG("%s", __func__); + target->state = TARGET_HALTED; + return ERROR_OK; +} + +static int mem_ap_assert_reset(struct target *target) +{ + target->state = TARGET_RESET; + + LOG_DEBUG("%s", __func__); + return ERROR_OK; +} + +static int mem_ap_examine(struct target *target) +{ + struct mem_ap *mem_ap = target->arch_info; + + if (!target_was_examined(target)) { + mem_ap->ap = dap_ap(mem_ap->arm.dap, mem_ap->ap_num); + target_set_examined(target); + target->state = TARGET_UNKNOWN; + return mem_ap_init(mem_ap->ap); + } + + return ERROR_OK; +} + +static int mem_ap_deassert_reset(struct target *target) +{ + if (target->reset_halt) + target->state = TARGET_HALTED; + else + target->state = TARGET_RUNNING; + + LOG_DEBUG("%s", __func__); + return ERROR_OK; +} + +static int mem_ap_read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + struct mem_ap *mem_ap = target->arch_info; + + LOG_DEBUG("Reading memory at physical address 0x" TARGET_ADDR_FMT + "; size %" PRId32 "; count %" PRId32, address, size, count); + + if (count == 0 || buffer == NULL) + return ERROR_COMMAND_SYNTAX_ERROR; + + return mem_ap_read_buf(mem_ap->ap, buffer, size, count, address); +} + +static int mem_ap_write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, + const uint8_t *buffer) +{ + struct mem_ap *mem_ap = target->arch_info; + + LOG_DEBUG("Writing memory at physical address 0x" TARGET_ADDR_FMT + "; size %" PRId32 "; count %" PRId32, address, size, count); + + if (count == 0 || buffer == NULL) + return ERROR_COMMAND_SYNTAX_ERROR; + + return mem_ap_write_buf(mem_ap->ap, buffer, size, count, address); +} + +struct target_type mem_ap_target = { + .name = "mem_ap", + + .target_create = mem_ap_target_create, + .init_target = mem_ap_init_target, + .examine = mem_ap_examine, + .target_jim_configure = adiv5_jim_configure, + + .poll = mem_ap_poll, + .arch_state = mem_ap_arch_state, + + .halt = mem_ap_halt, + .resume = mem_ap_resume, + .step = mem_ap_step, + + .assert_reset = mem_ap_assert_reset, + .deassert_reset = mem_ap_deassert_reset, + + .read_memory = mem_ap_read_memory, + .write_memory = mem_ap_write_memory, +}; diff --git a/src/target/target.c b/src/target/target.c index 253928d7c..060fbdca5 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -108,6 +108,7 @@ extern struct target_type quark_x10xx_target; extern struct target_type quark_d20xx_target; extern struct target_type stm8_target; extern struct target_type riscv_target; +extern struct target_type mem_ap_target; static struct target_type *target_types[] = { &arm7tdmi_target, @@ -144,6 +145,7 @@ static struct target_type *target_types[] = { #if BUILD_TARGET64 &aarch64_target, #endif + &mem_ap_target, NULL, }; From 9e2883b07d1574f00e13ab97447606b1fe6b844e Mon Sep 17 00:00:00 2001 From: Steven Stallion Date: Sun, 26 Mar 2017 10:47:34 -0500 Subject: [PATCH 100/147] interface: adapter configuration for FTDI C232HM This patch adds support for the C232HM-DDSL-0 and C232HM-EDSL-0 FT232H-based cables from FTDI. For more information, see: http://www.ftdichip.com/Products/Cables/USBMPSSE.htm Change-Id: Ic97423eb1e2f6b5ebae04943cd5cce86f38771d5 Signed-off-by: Steven Stallion Reviewed-on: http://openocd.zylin.com/4081 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/interface/ftdi/c232hm.cfg | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tcl/interface/ftdi/c232hm.cfg diff --git a/tcl/interface/ftdi/c232hm.cfg b/tcl/interface/ftdi/c232hm.cfg new file mode 100644 index 000000000..387abbb05 --- /dev/null +++ b/tcl/interface/ftdi/c232hm.cfg @@ -0,0 +1,15 @@ +# +# FTDI USB Hi-Speed to MPSSE Cable +# +# http://www.ftdichip.com/Products/Cables/USBMPSSE.htm +# +# C232HM-DDHSL-0 and C232HM-EDSL-0 provide 3.3V and 5V on pin 1 (Red), +# respectively. +# + +interface ftdi +#ftdi_device_desc "C232HM-DDHSL-0" +#ftdi_device_desc "C232HM-EDHSL-0" +ftdi_vid_pid 0x0403 0x6014 + +ftdi_layout_init 0x0008 0x000b From 2253a31fb19cbc501fd8e54bfd43310c35dacd4b Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 4 Aug 2018 14:49:35 +0200 Subject: [PATCH 101/147] ftdi: extend ftdi_location format To existing :, format add -. support. The last format is used by kernel and other drivers. Change-Id: I6528970d3af4f6a8bf7b27a0f7a763b5957fdf2b Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4631 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/jtag/drivers/mpsse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jtag/drivers/mpsse.c b/src/jtag/drivers/mpsse.c index 06d008b47..89248921a 100644 --- a/src/jtag/drivers/mpsse.c +++ b/src/jtag/drivers/mpsse.c @@ -120,7 +120,7 @@ static bool device_location_equal(libusb_device *device, const char *location) LOG_DEBUG("device path has %i steps", path_len); - ptr = strtok(loc, ":"); + ptr = strtok(loc, "-:"); if (ptr == NULL) { LOG_DEBUG("no ':' in path"); goto done; @@ -132,7 +132,7 @@ static bool device_location_equal(libusb_device *device, const char *location) path_step = 0; while (path_step < 7) { - ptr = strtok(NULL, ","); + ptr = strtok(NULL, ".,"); if (ptr == NULL) { LOG_DEBUG("no more tokens in path at step %i", path_step); break; From 56cdc3f3d54ecef9f1847045c041a2d8e723c375 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 23 Jul 2018 15:20:40 +0200 Subject: [PATCH 102/147] target/cortex_a: poll all targets in SMP node after halt The periodic poll scans all the targets in the same order they have been declared in the configuration file. When one target in a SMP node halts, the transition is detected in the following poll and this triggers a halt request to all the other cores of the SMP node. The targets that will be polled afterwards will be identified as "halted", but the targets already scanned will remain as "running" until the next periodic poll. This creates a race condition with GDB; GDB sets the breakpoints when runs the target and removes them as soon as the target is halted. When it receives the halt event, it starts removing the breakpoints and fails on the targets that are still reported as "running". Fixed by polling all the targets in the SMP node before informing GDB about the halt event. This implementation is almost copy/paste from the one in aarch64. Change-Id: Id2bd99f1e56b014e48e9e34ccb891b4219c518f8 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4622 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/cortex_a.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 4aae5e473..bc4aa33b4 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -57,6 +57,9 @@ #include "transport/transport.h" #include +#define foreach_smp_target(pos, head) \ + for (pos = head; (pos != NULL); pos = pos->next) + static int cortex_a_poll(struct target *target); static int cortex_a_debug_entry(struct target *target); static int cortex_a_restore_context(struct target *target, bool bpwp); @@ -806,12 +809,43 @@ static int cortex_a_halt_smp(struct target *target) static int update_halt_gdb(struct target *target) { + struct target *gdb_target = NULL; + struct target_list *head; + struct target *curr; int retval = 0; + if (target->gdb_service && target->gdb_service->core[0] == -1) { target->gdb_service->target = target; target->gdb_service->core[0] = target->coreid; retval += cortex_a_halt_smp(target); } + + if (target->gdb_service) + gdb_target = target->gdb_service->target; + + foreach_smp_target(head, target->head) { + curr = head->target; + /* skip calling context */ + if (curr == target) + continue; + if (!target_was_examined(curr)) + continue; + /* skip targets that were already halted */ + if (curr->state == TARGET_HALTED) + continue; + /* Skip gdb_target; it alerts GDB so has to be polled as last one */ + if (curr == gdb_target) + continue; + + /* avoid recursion in cortex_a_poll() */ + curr->smp = 0; + cortex_a_poll(curr); + curr->smp = 1; + } + + /* after all targets were updated, poll the gdb serving target */ + if (gdb_target != NULL && gdb_target != target) + cortex_a_poll(gdb_target); return retval; } From 1f37b94859e01c565219a7e7d6ddd85d122f7892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 9 Aug 2018 17:11:43 +0200 Subject: [PATCH 103/147] tcl/board: Add Emcraft imx8 SOM BSB support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested with Olimex ARM-USB-TINY-H adapter Simple commands work fine but there are currently issues when attaching remote gdb or running virt2phys: https://sourceforge.net/p/openocd/tickets/201/ Change-Id: I86ccf1d93c5d23870bb522f92b3e2af190d529e8 Signed-off-by: Guido Günther Reviewed-on: http://openocd.zylin.com/4646 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/emcraft_imx8m-som-bsb.cfg | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tcl/board/emcraft_imx8m-som-bsb.cfg diff --git a/tcl/board/emcraft_imx8m-som-bsb.cfg b/tcl/board/emcraft_imx8m-som-bsb.cfg new file mode 100644 index 000000000..5571d0ecb --- /dev/null +++ b/tcl/board/emcraft_imx8m-som-bsb.cfg @@ -0,0 +1,22 @@ +# +# configuration file for Emcraft IMX8M-SOM-BSB +# + +# only JTAG supported +transport select jtag + +# set a safe JTAG clock speed, can be overridden +adapter_khz 1000 + +# SRST and TRST are wired up +reset_config trst_and_srst + +# delay after SRST goes inactive +adapter_nsrst_delay 70 + +# board has an i.MX8MQ with 4 Cortex-A53 cores +set CHIPNAME imx8mq +set CHIPCORES 4 + +# source SoC configuration +source [find target/imx8m.cfg] From 8c67115c7b02a10668c9b05cd4fd95a8a7d01c88 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 4 Sep 2018 15:37:32 +0200 Subject: [PATCH 104/147] arm_adi_v5: remove useless cast to int The field ap_num in struct adiv5_private_config is already of type int. Casting it to type int has no sense. Change-Id: Ida642e808c02591bb58609425eccd096d404e2c4 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4666 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/arm_adi_v5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index b4e252bb4..d9f3bd74f 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1515,7 +1515,7 @@ int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi) Jim_SetResultString(goi->interp, "AP number not configured", -1); return JIM_ERR; } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, (int)pc->ap_num)); + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, pc->ap_num)); } break; } From ad41246cf66d96b506694a0100e1bbf792d5ea77 Mon Sep 17 00:00:00 2001 From: Kai Geissdoerfer Date: Mon, 13 Aug 2018 12:35:09 +0200 Subject: [PATCH 105/147] flash/nrf5: time-based timeout waiting for flash controller Change-Id: Id214df154dc359ca130c8d8fe1554d106621b9cd Signed-off-by: Kai Geissdoerfer Reviewed-on: http://openocd.zylin.com/4648 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/nrf5.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 16459c7f8..1994bbce8 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -26,6 +26,7 @@ #include #include #include +#include enum { NRF5_FLASH_BASE = 0x00000000, @@ -240,7 +241,8 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip) { uint32_t ready; int res; - int timeout = 100; + int timeout_ms = 200; + int64_t ts_start = timeval_ms(); do { res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready); @@ -252,8 +254,9 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip) if (ready == 0x00000001) return ERROR_OK; - alive_sleep(1); - } while (timeout--); + keep_alive(); + + } while ((timeval_ms()-ts_start) < timeout_ms); LOG_DEBUG("Timed out waiting for NVMC_READY"); return ERROR_FLASH_BUSY; From 08a79c71f264626152cc7269a334ef20abc3ff2b Mon Sep 17 00:00:00 2001 From: Kai Geissdoerfer Date: Mon, 13 Aug 2018 12:35:47 +0200 Subject: [PATCH 106/147] flash/nrf5: support for nRF52840 Q1AAC0 Change-Id: Id3280dadece84e1d68544936e44d506c7930a55d Signed-off-by: Kai Geissdoerfer Reviewed-on: http://openocd.zylin.com/4649 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/nrf5.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 1994bbce8..cb764817f 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -207,6 +207,9 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = { /* nRF52832 Devices */ NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512), NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512), + + /* nRF52840 Devices */ + NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024), }; static int nrf5_bank_is_probed(struct flash_bank *bank) From 4423a58b4dd7e0e38d50886abd1bd09328c34e70 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 4 Sep 2018 19:01:45 +0200 Subject: [PATCH 107/147] doc: fix use of deprecated config file in the example Commit 31c58c139d85 ("jtag: drivers: stlink: handle all versions with single config") deprecates the use of "interface/stlink-v2-1.cfg" in favor of a unique config file "interface/stlink.cfg". Update the example in the documentation. Change-Id: I1aed7c70e15f4edb4f81a3ee8e3bce575fde873b Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4667 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- doc/openocd.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 3eb630902..1c005f2f8 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8789,7 +8789,7 @@ baud with our custom divisor to get 12MHz) @item @code{itmdump -f /dev/ttyUSB1 -d1} @item OpenOCD invocation line: @example -openocd -f interface/stlink-v2-1.cfg \ +openocd -f interface/stlink.cfg \ -c "transport select hla_swd" \ -f target/stm32l1.cfg \ -c "tpiu config external uart off 24000000 12000000" From b2d259f67cc3ee4b689e704228d97943bae94064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20S=C3=B8hus?= Date: Thu, 16 Aug 2018 14:04:45 +0200 Subject: [PATCH 108/147] Added support for STM32L4X option bytes writing. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enables the programming of Write protection lock bits. - Updated/re-factored with option_read, option_write and option_load commands. Change-Id: I86358c7eb1285c3c0baac1564e46da8ced5fd025 Signed-off-by: Thomas Søhus Reviewed-on: http://openocd.zylin.com/4654 Tested-by: jenkins Reviewed-by: Tomas Vanek --- doc/openocd.texi | 36 ++++ src/flash/nor/stm32l4x.c | 434 ++++++++++++++++++++++----------------- 2 files changed, 282 insertions(+), 188 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 1c005f2f8..e87d8c296 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -6596,6 +6596,42 @@ The @var{num} parameter is a value shown by @command{flash banks}. Mass erases the entire stm32l4x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn + +@deffn Command {stm32l4x option_read} num reg_offset +Reads an option byte register from the stm32l4x device. +The @var{num} parameter is a value shown by @command{flash banks}, @var{reg_offset} +is the register offset of the Option byte to read. + +For example to read the FLASH_OPTR register: +@example +stm32l4x option_read 0 0x20 +# Option Register: <0x40022020> = 0xffeff8aa +@end example + +The above example will read out the FLASH_OPTR register which contains the RDP +option byte, Watchdog configuration, BOR level etc. +@end deffn + +@deffn Command {stm32l4x option_write} num reg_offset reg_mask +Write an option byte register of the stm32l4x device. +The @var{num} parameter is a value shown by @command{flash banks}, @var{reg_offset} +is the register offset of the Option byte to write, and @var{reg_mask} is the mask +to apply when writing the register (only bits with a '1' will be touched). + +For example to write the WRP1AR option bytes: +@example +stm32l4x option_write 0 0x28 0x00FF0000 0x00FF00FF +@end example + +The above example will write the WRP1AR option register configuring the Write protection +Area A for bank 1. The above example set WRP1AR_END=255, WRP1AR_START=0. +This will effectively write protect all sectors in flash bank 1. +@end deffn + +@deffn Command {stm32l4x option_load} num +Forces a re-load of the option byte registers. Will cause a reset of the device. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn @end deffn @deffn {Flash Driver} str7x diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 4fb7e039a..ad179216d 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -57,8 +57,8 @@ #define STM32_FLASH_CR 0x40022014 #define STM32_FLASH_OPTR 0x40022020 #define STM32_FLASH_WRP1AR 0x4002202c -#define STM32_FLASH_WRP2AR 0x40022030 -#define STM32_FLASH_WRP1BR 0x4002204c +#define STM32_FLASH_WRP1BR 0x40022030 +#define STM32_FLASH_WRP2AR 0x4002204c #define STM32_FLASH_WRP2BR 0x40022050 /* FLASH_CR register bits */ @@ -70,8 +70,10 @@ #define FLASH_CR_BKER (1 << 11) #define FLASH_MER2 (1 << 15) #define FLASH_STRT (1 << 16) +#define FLASH_OPTSTRT (1 << 17) #define FLASH_EOPIE (1 << 24) #define FLASH_ERRIE (1 << 25) +#define FLASH_OBLLAUNCH (1 << 27) #define FLASH_OPTLOCK (1 << 30) #define FLASH_LOCK (1 << 31) @@ -102,28 +104,17 @@ #define OPTKEY1 0x08192A3B #define OPTKEY2 0x4C5D6E7F +#define RDP_LEVEL_0 0xAA +#define RDP_LEVEL_1 0xBB +#define RDP_LEVEL_2 0xCC + /* other registers */ #define DBGMCU_IDCODE 0xE0042000 #define FLASH_SIZE_REG 0x1FFF75E0 -struct stm32l4_options { - uint8_t RDP; - uint16_t bank_b_start; - uint8_t user_options; - uint8_t wpr1a_start; - uint8_t wpr1a_end; - uint8_t wpr1b_start; - uint8_t wpr1b_end; - uint8_t wpr2a_start; - uint8_t wpr2a_end; - uint8_t wpr2b_start; - uint8_t wpr2b_end; - /* Fixme: Handle PCROP */ -}; - struct stm32l4_flash_bank { - struct stm32l4_options option_bytes; + uint16_t bank2_start; int probed; }; @@ -265,97 +256,80 @@ static int stm32l4_unlock_option_reg(struct target *target) return ERROR_OK; } -static int stm32l4_read_options(struct flash_bank *bank) +static int stm32l4_read_option(struct flash_bank *bank, uint32_t address, uint32_t* value) { - uint32_t optiondata; - struct stm32l4_flash_bank *stm32l4_info = NULL; struct target *target = bank->target; - - stm32l4_info = bank->driver_priv; - - /* read current option bytes */ - int retval = target_read_u32(target, STM32_FLASH_OPTR, &optiondata); - if (retval != ERROR_OK) - return retval; - - stm32l4_info->option_bytes.user_options = (optiondata >> 8) & 0x3ffff; - stm32l4_info->option_bytes.RDP = optiondata & 0xff; - - retval = target_read_u32(target, STM32_FLASH_WRP1AR, &optiondata); - if (retval != ERROR_OK) - return retval; - stm32l4_info->option_bytes.wpr1a_start = optiondata & 0xff; - stm32l4_info->option_bytes.wpr1a_end = (optiondata >> 16) & 0xff; - - retval = target_read_u32(target, STM32_FLASH_WRP2AR, &optiondata); - if (retval != ERROR_OK) - return retval; - stm32l4_info->option_bytes.wpr2a_start = optiondata & 0xff; - stm32l4_info->option_bytes.wpr2a_end = (optiondata >> 16) & 0xff; - - retval = target_read_u32(target, STM32_FLASH_WRP1BR, &optiondata); - if (retval != ERROR_OK) - return retval; - stm32l4_info->option_bytes.wpr1b_start = optiondata & 0xff; - stm32l4_info->option_bytes.wpr1b_end = (optiondata >> 16) & 0xff; - - retval = target_read_u32(target, STM32_FLASH_WRP2BR, &optiondata); - if (retval != ERROR_OK) - return retval; - stm32l4_info->option_bytes.wpr2b_start = optiondata & 0xff; - stm32l4_info->option_bytes.wpr2b_end = (optiondata >> 16) & 0xff; - - if (stm32l4_info->option_bytes.RDP != 0xAA) - LOG_INFO("Device Security Bit Set"); - - return ERROR_OK; + return target_read_u32(target, address, value); } -static int stm32l4_write_options(struct flash_bank *bank) +static int stm32l4_write_option(struct flash_bank *bank, uint32_t address, uint32_t value, uint32_t mask) { - struct stm32l4_flash_bank *stm32l4_info = NULL; struct target *target = bank->target; uint32_t optiondata; - stm32l4_info = bank->driver_priv; - - (void) optiondata; - (void) stm32l4_info; - - int retval = stm32l4_unlock_option_reg(target); + int retval = target_read_u32(target, address, &optiondata); if (retval != ERROR_OK) return retval; - /* FIXME: Implement Option writing!*/ - return ERROR_OK; + + retval = stm32l4_unlock_reg(target); + if (retval != ERROR_OK) + return retval; + + retval = stm32l4_unlock_option_reg(target); + if (retval != ERROR_OK) + return retval; + + optiondata = (optiondata & ~mask) | (value & mask); + + retval = target_write_u32(target, address, optiondata); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OPTSTRT); + if (retval != ERROR_OK) + return retval; + + retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + return retval; } static int stm32l4_protect_check(struct flash_bank *bank) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br; + stm32l4_read_option(bank, STM32_FLASH_WRP1AR, &wrp1ar); + stm32l4_read_option(bank, STM32_FLASH_WRP1BR, &wrp1br); + stm32l4_read_option(bank, STM32_FLASH_WRP2AR, &wrp2ar); + stm32l4_read_option(bank, STM32_FLASH_WRP2BR, &wrp2br); - /* read write protection settings */ - int retval = stm32l4_read_options(bank); - if (retval != ERROR_OK) { - LOG_DEBUG("unable to read option bytes"); - return retval; - } + 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->option_bytes.bank_b_start) { - if (((i >= stm32l4_info->option_bytes.wpr1a_start) && - (i <= stm32l4_info->option_bytes.wpr1a_end)) || - ((i >= stm32l4_info->option_bytes.wpr2a_start) && - (i <= stm32l4_info->option_bytes.wpr2a_end))) + if (i < stm32l4_info->bank2_start) { + 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->option_bytes.bank_b_start + 256; - if (((snb >= stm32l4_info->option_bytes.wpr1b_start) && - (snb <= stm32l4_info->option_bytes.wpr1b_end)) || - ((snb >= stm32l4_info->option_bytes.wpr2b_start) && - (snb <= stm32l4_info->option_bytes.wpr2b_end))) + snb = i - stm32l4_info->bank2_start + 256; + if (((snb >= wrp2a_start) && + (snb <= wrp2a_end)) || + ((snb >= wrp2b_start) && + (snb <= wrp2b_end))) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; @@ -398,9 +372,9 @@ static int stm32l4_erase(struct flash_bank *bank, int first, int last) uint32_t erase_flags; erase_flags = FLASH_PER | FLASH_STRT; - if (i >= stm32l4_info->option_bytes.bank_b_start) { + if (i >= stm32l4_info->bank2_start) { uint8_t snb; - snb = (i - stm32l4_info->option_bytes.bank_b_start) + 256; + snb = (i - stm32l4_info->bank2_start) + 256; erase_flags |= snb << FLASH_PAGE_SHIFT | FLASH_CR_BKER; } else erase_flags |= i << FLASH_PAGE_SHIFT; @@ -434,20 +408,29 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last return ERROR_TARGET_NOT_HALTED; } - /* read protection settings */ - int retval = stm32l4_read_options(bank); - if (retval != ERROR_OK) { - LOG_DEBUG("unable to read option bytes"); - return retval; + int ret = ERROR_OK; + /* Bank 2 */ + uint32_t reg_value = 0xFF; /* Default to bank un-protected */ + if (last >= stm32l4_info->bank2_start) { + if (set == 1) { + uint8_t begin = first > stm32l4_info->bank2_start ? first : 0x00; + reg_value = ((last & 0xFF) << 16) | begin; + } + + ret = stm32l4_write_option(bank, STM32_FLASH_WRP2AR, reg_value, 0xffffffff); + } + /* Bank 1 */ + reg_value = 0xFF; /* Default to bank un-protected */ + if (first < stm32l4_info->bank2_start) { + if (set == 1) { + uint8_t end = last >= stm32l4_info->bank2_start ? 0xFF : last; + reg_value = (end << 16) | (first & 0xFF); + } + + ret = stm32l4_write_option(bank, STM32_FLASH_WRP1AR, reg_value, 0xffffffff); } - (void)stm32l4_info; - /* FIXME: Write First and last in a valid WRPxx_start/end combo*/ - retval = stm32l4_write_options(bank); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; + return ret; } /* Count is in halfwords */ @@ -650,9 +633,9 @@ static int stm32l4_probe(struct flash_bank *bank) /* only devices with < 1024 kiB may be set to single bank dual banks */ if ((flash_size_in_kb == 1024) || !(options & OPT_DUALBANK)) - stm32l4_info->option_bytes.bank_b_start = 256; + stm32l4_info->bank2_start = 256; else - stm32l4_info->option_bytes.bank_b_start = flash_size_in_kb << 9; + stm32l4_info->bank2_start = flash_size_in_kb << 9; /* did we assign flash size? */ assert((flash_size_in_kb != 0xffff) && flash_size_in_kb); @@ -747,89 +730,6 @@ static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size) return ERROR_OK; } -COMMAND_HANDLER(stm32l4_handle_lock_command) -{ - struct target *target = NULL; - struct stm32l4_flash_bank *stm32l4_info = NULL; - - if (CMD_ARGC < 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) - return retval; - - stm32l4_info = bank->driver_priv; - target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (stm32l4_read_options(bank) != ERROR_OK) { - command_print(CMD_CTX, "%s failed to read options", - bank->driver->name); - return ERROR_OK; - } - - /* set readout protection */ - stm32l4_info->option_bytes.RDP = 0; - - if (stm32l4_write_options(bank) != ERROR_OK) { - command_print(CMD_CTX, "%s failed to lock device", bank->driver->name); - return ERROR_OK; - } - - command_print(CMD_CTX, "%s locked", bank->driver->name); - - return ERROR_OK; -} - -COMMAND_HANDLER(stm32l4_handle_unlock_command) -{ - struct target *target = NULL; - struct stm32l4_flash_bank *stm32l4_info = NULL; - - if (CMD_ARGC < 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) - return retval; - - stm32l4_info = bank->driver_priv; - target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (stm32l4_read_options(bank) != ERROR_OK) { - command_print(CMD_CTX, "%s failed to read options", bank->driver->name); - return ERROR_OK; - } - - /* clear readout protection and complementary option bytes - * this will also force a device unlock if set */ - stm32l4_info->option_bytes.RDP = 0xAA; - - if (stm32l4_write_options(bank) != ERROR_OK) { - command_print(CMD_CTX, "%s failed to unlock device", - bank->driver->name); - return ERROR_OK; - } - - command_print(CMD_CTX, "%s unlocked.\n" - "INFO: a reset or power cycle is required " - "for the new settings to take effect.", bank->driver->name); - - return ERROR_OK; -} - static int stm32l4_mass_erase(struct flash_bank *bank, uint32_t action) { int retval; @@ -873,7 +773,7 @@ COMMAND_HANDLER(stm32l4_handle_mass_erase_command) uint32_t action; if (CMD_ARGC < 1) { - command_print(CMD_CTX, "stm32x mass_erase "); + command_print(CMD_CTX, "stm32l4x mass_erase "); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -889,14 +789,151 @@ COMMAND_HANDLER(stm32l4_handle_mass_erase_command) for (i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; - command_print(CMD_CTX, "stm32x mass erase complete"); + command_print(CMD_CTX, "stm32l4x mass erase complete"); } else { - command_print(CMD_CTX, "stm32x mass erase failed"); + command_print(CMD_CTX, "stm32l4x mass erase failed"); } return retval; } +COMMAND_HANDLER(stm32l4_handle_option_read_command) +{ + if (CMD_ARGC < 2) { + command_print(CMD_CTX, "stm32l4x option_read "); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + uint32_t reg_addr = STM32_FLASH_BASE; + uint32_t value = 0; + + reg_addr += strtoul(CMD_ARGV[1], NULL, 16); + + retval = stm32l4_read_option(bank, reg_addr, &value); + if (ERROR_OK != retval) + return retval; + + command_print(CMD_CTX, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32 "", reg_addr, value); + + return retval; +} + +COMMAND_HANDLER(stm32l4_handle_option_write_command) +{ + if (CMD_ARGC < 3) { + command_print(CMD_CTX, "stm32l4x option_write [mask]"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + uint32_t reg_addr = STM32_FLASH_BASE; + uint32_t value = 0; + uint32_t mask = 0xFFFFFFFF; + + reg_addr += strtoul(CMD_ARGV[1], NULL, 16); + value = strtoul(CMD_ARGV[2], NULL, 16); + if (CMD_ARGC > 3) + mask = strtoul(CMD_ARGV[3], NULL, 16); + + command_print(CMD_CTX, "%s Option written.\n" + "INFO: a reset or power cycle is required " + "for the new settings to take effect.", bank->driver->name); + + retval = stm32l4_write_option(bank, reg_addr, value, mask); + return retval; +} + +COMMAND_HANDLER(stm32l4_handle_option_load_command) +{ + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + struct target *target = bank->target; + + retval = stm32l4_unlock_reg(target); + if (ERROR_OK != retval) + return retval; + + retval = stm32l4_unlock_option_reg(target); + if (ERROR_OK != retval) + return retval; + + /* Write the OBLLAUNCH bit in CR -> Cause device "POR" and option bytes reload */ + retval = target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OBLLAUNCH); + + command_print(CMD_CTX, "stm32l4x option load (POR) completed."); + return retval; +} + +COMMAND_HANDLER(stm32l4_handle_lock_command) +{ + struct target *target = NULL; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* set readout protection level 1 by erasing the RDP option byte */ + if (stm32l4_write_option(bank, STM32_FLASH_OPTR, 0, 0x000000FF) != ERROR_OK) { + command_print(CMD_CTX, "%s failed to lock device", bank->driver->name); + return ERROR_OK; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(stm32l4_handle_unlock_command) +{ + struct target *target = NULL; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (stm32l4_write_option(bank, STM32_FLASH_OPTR, RDP_LEVEL_0, 0x000000FF) != ERROR_OK) { + command_print(CMD_CTX, "%s failed to unlock device", bank->driver->name); + return ERROR_OK; + } + + return ERROR_OK; +} + static const struct command_registration stm32l4_exec_command_handlers[] = { { .name = "lock", @@ -919,6 +956,27 @@ static const struct command_registration stm32l4_exec_command_handlers[] = { .usage = "bank_id", .help = "Erase entire flash device.", }, + { + .name = "option_read", + .handler = stm32l4_handle_option_read_command, + .mode = COMMAND_EXEC, + .usage = "bank_id reg_offset", + .help = "Read & Display device option bytes.", + }, + { + .name = "option_write", + .handler = stm32l4_handle_option_write_command, + .mode = COMMAND_EXEC, + .usage = "bank_id reg_offset value mask", + .help = "Write device option bit fields with provided value.", + }, + { + .name = "option_load", + .handler = stm32l4_handle_option_load_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Force re-load of device options (will cause device reset).", + }, COMMAND_REGISTRATION_DONE }; From e2b6f347c72b1291c34cf23057d04edde6841670 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 24 Aug 2018 13:01:49 -0700 Subject: [PATCH 109/147] Clarify what exactly the RISC-V code supports. Change-Id: I8da657426cc52c738ab41bfb0164cbc6721c0aef Signed-off-by: Tim Newsome Reviewed-on: http://openocd.zylin.com/4655 Tested-by: jenkins Reviewed-by: Philipp Guehring Reviewed-by: Liviu Ionescu Reviewed-by: Tomas Vanek --- doc/openocd.texi | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index e87d8c296..bbe6cffd4 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -9022,8 +9022,11 @@ Display all registers in @emph{group}. @section RISC-V Architecture @uref{http://riscv.org/, RISC-V} is a free and open ISA. OpenOCD supports JTAG -debug of targets that implement version 0.11 and 0.13 of the RISC-V Debug -Specification. +debug of RV32 and RV64 cores in heterogeneous multicore systems of up to 32 +harts. (It's possible to increase this limit to 1024 by changing +RISCV_MAX_HARTS in riscv.h.) OpenOCD primarily supports 0.13 of the RISC-V +Debug Specification, but there is also support for legacy targets that +implement version 0.11. @subsection RISC-V Terminology From ce8937a987620cb32de0ccad60ea06c296850139 Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Mon, 17 Sep 2018 15:49:24 -0700 Subject: [PATCH 110/147] target/cortex_m: fix typo The subunit of the debug unit is called the Flash Patch and Breakpoint unit, abbreviated (by ARM no less) as FPB, not FBP. Change-Id: Ia2f08470da705f0f1518feeca878f0f500507308 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4675 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Antonio Borneo --- src/target/cortex_m.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index d1f7f3eea..07fea5137 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -42,7 +42,7 @@ /* NOTE: most of this should work fine for the Cortex-M1 and * Cortex-M0 cores too, although they're ARMv6-M not ARMv7-M. - * Some differences: M0/M1 doesn't have FBP remapping or the + * Some differences: M0/M1 doesn't have FPB remapping or the * DWT tracing/profiling support. (So the cycle counter will * not be usable; the other stuff isn't currently used here.) * @@ -255,7 +255,7 @@ static int cortex_m_endreset_event(struct target *target) return retval; /* Paranoia: evidently some (early?) chips don't preserve all the - * debug state (including FBP, DWT, etc) across reset... + * debug state (including FPB, DWT, etc) across reset... */ /* Enable FPB */ @@ -1277,7 +1277,7 @@ int cortex_m_remove_breakpoint(struct target *target, struct breakpoint *breakpo { struct cortex_m_common *cortex_m = target_to_cm(target); - /* REVISIT why check? FBP can be updated with core running ... */ + /* REVISIT why check? FPB can be updated with core running ... */ if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; From 723fc07ddc925d101e8d2de1fa1d83e7843e246f Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 27 Aug 2018 19:11:19 +0200 Subject: [PATCH 111/147] contrib/60-openocd.rules: provide hint to reload udev rules No need to reboot the Linux box when new rules are added to udev. Suggest the command in the script header. Change-Id: Ie95383bfd73914a3d2e2c05d77fa3eb32e68b7e2 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4665 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- contrib/60-openocd.rules | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/60-openocd.rules b/contrib/60-openocd.rules index af092c18b..692e1b10b 100644 --- a/contrib/60-openocd.rules +++ b/contrib/60-openocd.rules @@ -1,4 +1,6 @@ # Copy this file to /etc/udev/rules.d/ +# If rules fail to reload automatically, you can refresh udev rules +# with the command "udevadm control --reload" ACTION!="add|change", GOTO="openocd_rules_end" SUBSYSTEM!="usb|tty|hidraw", GOTO="openocd_rules_end" From bdef93520a4721e1ed4ac4675476772fab064896 Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Fri, 14 Sep 2018 15:27:34 -0700 Subject: [PATCH 112/147] target/stm32: make APCSW cacheable Change-Id: I7c5c9720ded329848647f17db95f845e46c01c19 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4674 Tested-by: jenkins Reviewed-by: Tomas Vanek --- tcl/target/stm32f7x.cfg | 8 ++++++++ tcl/target/stm32h7x.cfg | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/tcl/target/stm32f7x.cfg b/tcl/target/stm32f7x.cfg index 562de30f6..e06a34594 100755 --- a/tcl/target/stm32f7x.cfg +++ b/tcl/target/stm32f7x.cfg @@ -145,3 +145,11 @@ $_TARGETNAME configure -event reset-start { # Reduce speed since CPU speed will slow down to 16MHz with the reset adapter_khz 2000 } + +# Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal +# HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 +# makes the data access cacheable. This allows reading and writing data in the +# CPU cache from the debugger, which is far more useful than going straight to +# RAM when operating on typical variables, and is generally no worse when +# operating on special memory locations. +$_CHIPNAME.dap apcsw 0x08000000 0x08000000 diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index 10477a5a7..e2ea8a84e 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -92,3 +92,11 @@ $_TARGETNAME configure -event reset-init { # Clock after reset is HSI at 64 MHz, no need of PLL adapter_khz 4000 } + +# Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal +# HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 +# makes the data access cacheable. This allows reading and writing data in the +# CPU cache from the debugger, which is far more useful than going straight to +# RAM when operating on typical variables, and is generally no worse when +# operating on special memory locations. +$_CHIPNAME.dap apcsw 0x08000000 0x08000000 From 6823a97beb706a5a3a4b7f813d33a7f3faadf2f0 Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Wed, 19 Sep 2018 16:20:26 -0700 Subject: [PATCH 113/147] target/atsamv: make APCSW cacheable Change-Id: Ic00d3192642c682f370a6f7f8b70ae29744eb746 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4678 Tested-by: jenkins Reviewed-by: Tomas Vanek --- tcl/target/atsamv.cfg | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tcl/target/atsamv.cfg b/tcl/target/atsamv.cfg index d1f8454d5..1d026aa95 100644 --- a/tcl/target/atsamv.cfg +++ b/tcl/target/atsamv.cfg @@ -50,3 +50,10 @@ if {![using_hla]} { set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME atsamv 0x00400000 0 0 0 $_TARGETNAME +# Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal +# HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 +# makes the data access cacheable. This allows reading and writing data in the +# CPU cache from the debugger, which is far more useful than going straight to +# RAM when operating on typical variables, and is generally no worse when +# operating on special memory locations. +$_CHIPNAME.dap apcsw 0x08000000 0x08000000 From 24654759d5fd92c0dbafac40c8604842dd6d6709 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 28 Aug 2018 12:29:09 +0200 Subject: [PATCH 114/147] gdb_server: avoid gdb server for virtual targets Virtual targets, like mem_ap, do not or cannot implement the required functionality to accept a GDB connection. In the case of mem_ap, the method get_gdb_reg_list() is missing and a following connection from gdb causes OpenOCD to segfault. OpenOCD opens a GDB port for each target; it's always possible to connect, by mistake, GDB to one virtual target. Add a method to check if the target supports GDB connections (for the moment just checking if get_gdb_reg_list is implemented). Skip opening a gdb server for every targets that don't support GDB connections. Change-Id: Ia439a43efe1a9adbb1771cd9d252db8ffa32eb9d Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4676 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/server/gdb_server.c | 6 ++++++ src/target/target.c | 10 ++++++++++ src/target/target.h | 7 +++++++ 3 files changed, 23 insertions(+) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 2375e9511..a45127360 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -3404,6 +3404,12 @@ static int gdb_target_add_one(struct target *target) if ((target->smp) && (target->gdb_service)) return ERROR_OK; + /* skip targets that cannot handle a gdb connections (e.g. mem_ap) */ + if (!target_supports_gdb_connection(target)) { + LOG_DEBUG("skip gdb server for target %s", target_name(target)); + return ERROR_OK; + } + if (target->gdb_port_override) { if (strcmp(target->gdb_port_override, "disabled") == 0) { LOG_INFO("gdb port disabled"); diff --git a/src/target/target.c b/src/target/target.c index 060fbdca5..478c39d1b 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1205,6 +1205,16 @@ int target_get_gdb_reg_list(struct target *target, { return target->type->get_gdb_reg_list(target, reg_list, reg_list_size, reg_class); } + +bool target_supports_gdb_connection(struct target *target) +{ + /* + * based on current code, we can simply exclude all the targets that + * don't provide get_gdb_reg_list; this could change with new targets. + */ + return !!target->type->get_gdb_reg_list; +} + int target_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { diff --git a/src/target/target.h b/src/target/target.h index c3137a08c..fe7e1a7db 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -481,6 +481,13 @@ int target_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); +/** + * Check if @a target allows GDB connections. + * + * Some target do not implement the necessary code required by GDB. + */ +bool target_supports_gdb_connection(struct target *target); + /** * Step the target. * From 2f1540710756434942be49ccf2b0f5530297adc2 Mon Sep 17 00:00:00 2001 From: Adam Bass Date: Mon, 10 Sep 2018 10:55:32 -0400 Subject: [PATCH 115/147] tcl/target: Add Renesas R-Car Gen3 targets Add configuration for the Renesas R-Car Generation 3 targets. These are SoCs with Cortex A57s, A53s, and R7s. All cores are supported. Change-Id: I795233210e4f647a1a2a0adea7c058ae98b5db70 Signed-off-by: Adam Bass Reviewed-on: http://openocd.zylin.com/4669 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/target/renesas_rcar_gen3.cfg | 169 +++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 tcl/target/renesas_rcar_gen3.cfg diff --git a/tcl/target/renesas_rcar_gen3.cfg b/tcl/target/renesas_rcar_gen3.cfg new file mode 100644 index 000000000..a6eef674b --- /dev/null +++ b/tcl/target/renesas_rcar_gen3.cfg @@ -0,0 +1,169 @@ +# Renesas R-Car Generation 3 SOCs +# - There are a combination of Cortex-A57s, Cortex-A53s, and Cortex-R7 for each Gen3 SOC +# - Each SOC can boot through any of the, up to 3, core types that it has +# e.g. H3 can boot through Cortex-A57, Cortex-A53, or Cortex-R7 + +# Supported Gen3 SOCs and their cores: +# H3: Cortex-A57 x 4, Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step) +# M3W: Cortex-A57 x 2, Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step) +# M3N: Cortex-A57 x 2, Cortex-R7 x 2 (Lock-Step) +# V3H: Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step) +# V3M: Cortex-A53 x 2, Cortex-R7 x 2 (Lock-Step) +# E3: Cortex-A53 x 1, Cortex-R7 x 2 (Lock-Step) +# D3: Cortex-A53 x 1 + +# Usage: +# There are 2 configuration options: +# SOC: Selects the supported SOC. (Default 'H3') +# BOOT_CORE: Selects the booting core. 'CA57', 'CA53', or 'CR7' +# Defaults to 'CA57' if the SOC has one, else defaults to 'CA53' + +if { [info exists SOC] } { + set _soc $SOC +} else { + set _soc H3 +} + +# Set configuration for each SOC and the default 'BOOT_CORE' +switch $_soc { + H3 { + set _CHIPNAME r8a77950 + set _num_ca57 4 + set _num_ca53 4 + set _num_cr7 1 + set _boot_core CA57 + } + M3W { + set _CHIPNAME r8a77960 + set _num_ca57 2 + set _num_ca53 4 + set _num_cr7 1 + set _boot_core CA57 + } + M3N { + set _CHIPNAME r8a77965 + set _num_ca57 2 + set _num_ca53 4 + set _num_cr7 1 + set _boot_core CA57 + } + V3H { + set _CHIPNAME r8a77970 + set _num_ca57 0 + set _num_ca53 4 + set _num_cr7 1 + set _boot_core CA53 + } + V3M { + set _CHIPNAME r8a77980 + set _num_ca57 0 + set _num_ca53 2 + set _num_cr7 1 + set _boot_core CA53 + } + E3 { + set _CHIPNAME r8a77990 + set _num_ca57 0 + set _num_ca53 1 + set _num_cr7 1 + set _boot_core CA53 + } + D3 { + set _CHIPNAME r8a77995 + set _num_ca57 0 + set _num_ca53 1 + set _num_cr7 0 + set _boot_core CA53 + } + default { + echo "'$_soc' is invalid!" + } +} + +# If configured, override the default 'CHIPNAME' +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} + +# If configured, override the default 'BOOT_CORE' +if { [info exists BOOT_CORE] } { + set _boot_core $BOOT_CORE +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +echo "\t$_soc - $_num_ca57 CA57(s), $_num_ca53 CA53(s), $_num_cr7 CR7(s)" +echo "\tBoot Core - $_boot_core\n" + +set _DAPNAME $_CHIPNAME.dap + +# TAP and DAP +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID +dap create $_DAPNAME -chain-position $_CHIPNAME.cpu + +set CA57_DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} +set CA57_CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} +set CA53_DBGBASE {0x80C10000 0x80D10000 0x80E10000 0x80F10000} +set CA53_CTIBASE {0x80C20000 0x80D20000 0x80E20000 0x80F20000} +set CR7_DBGBASE 0x80910000 +set CR7_CTIBASE 0x80918000 + +set smp_targets "" + +proc setup_a5x {core_name dbgbase ctibase num boot} { + global _CHIPNAME + global _DAPNAME + global smp_targets + for { set _core 0 } { $_core < $num } { incr _core } { + set _TARGETNAME $_CHIPNAME.$core_name.$_core + set _CTINAME $_TARGETNAME.cti + cti create $_CTINAME -dap $_DAPNAME -ap-num 1 \ + -ctibase [lindex $ctibase $_core] + set _command "target create $_TARGETNAME aarch64 -dap $_DAPNAME \ + -ap-num 1 -dbgbase [lindex $dbgbase $_core] -cti $_CTINAME" + if { $_core == 0 && $boot == 1 } { + set _targets "$_TARGETNAME" + } else { + set _command "$_command -defer-examine" + } + set smp_targets "$smp_targets $_TARGETNAME" + eval $_command + } +} + +proc setup_cr7 {dbgbase ctibase boot} { + global _CHIPNAME + global _DAPNAME + set _TARGETNAME $_CHIPNAME.r7 + set _CTINAME $_TARGETNAME.cti + cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -ctibase $ctibase + set _command "target create $_TARGETNAME cortex_r4 -dap $_DAPNAME \ + -ap-num 1 -dbgbase $dbgbase" + if { $boot == 1 } { + set _targets "$_TARGETNAME" + } else { + set _command "$_command -defer-examine" + } + eval $_command +} + +# Organize target list based on the boot core +if { [string equal $_boot_core CA57] } { + setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 1 + setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0 + setup_cr7 $CR7_DBGBASE $CR7_CTIBASE 0 +} elseif { [string equal $_boot_core CA53] } { + setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 1 + setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0 + setup_cr7 $CR7_DBGBASE $CR7_CTIBASE 0 +} else { + setup_cr7 $CR7_DBGBASE $CR7_CTIBASE 1 + setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0 + setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0 +} + +eval "target smp $smp_targets" From 1afec4f561392539197fae678de4cd2ca01c127d Mon Sep 17 00:00:00 2001 From: Adam Bass Date: Mon, 10 Sep 2018 11:04:23 -0400 Subject: [PATCH 116/147] tcl/board: Add Renesas R-Car Salvator-X(S) boards. Add configuration for the Renesas R-Car Salvator-X and Renesas R-Car Salvator-XS boards. Change-Id: I898008f56adb31908d30760f18217583fabf1c51 Signed-off-by: Adam Bass Reviewed-on: http://openocd.zylin.com/4670 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/renesas_salvator-xs.cfg | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tcl/board/renesas_salvator-xs.cfg diff --git a/tcl/board/renesas_salvator-xs.cfg b/tcl/board/renesas_salvator-xs.cfg new file mode 100644 index 000000000..1558a5274 --- /dev/null +++ b/tcl/board/renesas_salvator-xs.cfg @@ -0,0 +1,23 @@ +# Renesas R-Car Gen3 Salvator-X(S) Board Config + +# The Salvator-X(S) boards come with either an H3, M3W, or M3N SOC. + +echo "\nSalvator-X(S):" +if { ![info exists SOC] } { + set SOC H3 +} +source [find target/renesas_rcar_gen3.cfg] + +reset_config trst_and_srst srst_nogate + +proc init_reset {mode} { + # Assert both resets: equivalent to a power-on reset + jtag_reset 1 1 + + # Deassert TRST to begin TAP communication + jtag_reset 0 1 + + # TAP should now be responsive, validate the scan-chain + jtag arp_init +} + From 76ee93a81db72d16cc2e446f6f43411de5d6e8c2 Mon Sep 17 00:00:00 2001 From: Anders Westrup Date: Tue, 25 Sep 2018 21:18:53 +0200 Subject: [PATCH 117/147] flash/nrf5: support for nRF52810 Change-Id: I01c430bfa593d20ea7a51c90d67052e374d239b3 Signed-off-by: Anders Westrup Reviewed-on: http://openocd.zylin.com/4680 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Slowcoder --- src/flash/nor/nrf5.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index cb764817f..de5c23051 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -204,6 +204,10 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = { NRF5_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), NRF5_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), + /* nRF52810 Devices */ + NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192), + NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192), + /* nRF52832 Devices */ NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512), NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512), From 06589d2de48556f5216e3e671e656f4fd9069b43 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 8 Oct 2018 16:42:10 +0200 Subject: [PATCH 118/147] drivers: cmsis-dap: fix connection in JTAG mode Commit 5aceec24122bc222896cfcfd91f7f082f630ac83 ("drivers: cmsis-dap: pull up common connect code") breaks the driver and it cannot connect anymore in JTAG mode. The issue is caused in cmsis_dap_init() by anticipating the call to cmsis_dap_usb_open(), which then sets cmsis_dap_handle and makes the following test to always fail. Actually the original code was quite tricky: if (swd_mode) do something that also sets cmsis_dap_handle; if (cmsis_dap_handle == NULL) do something for !swd_mode; Convert the sequence of tricky "if"s in a single "if-then-else" to handle clearly the cases swd_mode and !swd_mode. Change-Id: I359a23bf26a3edc2461f4352daa0be83e78868f7 Fixes: 5aceec24122b ("drivers: cmsis-dap: pull up common connect code") Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4697 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/jtag/drivers/cmsis_dap_usb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index 4ee483659..9e723b51d 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -895,9 +895,7 @@ static int cmsis_dap_init(void) retval = cmsis_dap_swd_open(); if (retval != ERROR_OK) return retval; - } - - if (cmsis_dap_handle == NULL) { + } else { /* Connect in JTAG mode */ if (!(cmsis_dap_handle->caps & INFO_CAPS_JTAG)) { LOG_ERROR("CMSIS-DAP: JTAG not supported"); From b5964191f0d2fc3ace607af001df3d57cbfbaf2b Mon Sep 17 00:00:00 2001 From: Steven Stallion Date: Mon, 1 May 2017 14:38:35 -0500 Subject: [PATCH 119/147] register: support non-existent registers This patch fixes a number of bugs caused by incomplete support for non-existent registers. This is needed for targets that provide optional registers or non-linear register numbers. Change-Id: I216196e0051f28887a2c3da410959382369eed80 Signed-off-by: Steven Stallion Reviewed-on: http://openocd.zylin.com/4113 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/server/gdb_server.c | 7 ++++++- src/target/register.c | 4 ++++ src/target/target.c | 15 +++++++++++---- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index a45127360..ee9fc1c97 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1179,8 +1179,11 @@ static int gdb_get_registers_packet(struct connection *connection, if (retval != ERROR_OK) return gdb_error(connection, retval); - for (i = 0; i < reg_list_size; i++) + for (i = 0; i < reg_list_size; i++) { + if (reg_list[i] == NULL || reg_list[i]->exist == false) + continue; reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2; + } assert(reg_packet_size > 0); @@ -1191,6 +1194,8 @@ static int gdb_get_registers_packet(struct connection *connection, reg_packet_p = reg_packet; for (i = 0; i < reg_list_size; i++) { + if (reg_list[i] == NULL || reg_list[i]->exist == false) + continue; if (!reg_list[i]->valid) { retval = reg_list[i]->type->get(reg_list[i]); if (retval != ERROR_OK && gdb_report_register_access_error) { diff --git a/src/target/register.c b/src/target/register.c index 1d63e12f7..850641448 100644 --- a/src/target/register.c +++ b/src/target/register.c @@ -44,6 +44,8 @@ struct reg *register_get_by_name(struct reg_cache *first, while (cache) { for (i = 0; i < cache->num_regs; i++) { + if (cache->reg_list[i].exist == false) + continue; if (strcmp(cache->reg_list[i].name, name) == 0) return &(cache->reg_list[i]); } @@ -84,6 +86,8 @@ void register_cache_invalidate(struct reg_cache *cache) struct reg *reg = cache->reg_list; for (unsigned n = cache->num_regs; n != 0; n--, reg++) { + if (reg->exist == false) + continue; reg->valid = 0; reg->dirty = 0; } diff --git a/src/target/target.c b/src/target/target.c index 478c39d1b..3aaebcd49 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -2804,6 +2804,8 @@ COMMAND_HANDLER(handle_reg_command) for (i = 0, reg = cache->reg_list; i < cache->num_regs; i++, reg++, count++) { + if (reg->exist == false) + continue; /* only print cached values if they are valid */ if (reg->valid) { value = buf_to_str(reg->value, @@ -2857,14 +2859,15 @@ COMMAND_HANDLER(handle_reg_command) /* access a single register by its name */ reg = register_get_by_name(target->reg_cache, CMD_ARGV[0], 1); - if (!reg) { - command_print(CMD_CTX, "register %s not found in current target", CMD_ARGV[0]); - return ERROR_OK; - } + if (!reg) + goto not_found; } assert(reg != NULL); /* give clang a hint that we *know* reg is != NULL here */ + if (!reg->exist) + goto not_found; + /* display a register */ if ((CMD_ARGC == 1) || ((CMD_ARGC == 2) && !((CMD_ARGV[1][0] >= '0') && (CMD_ARGV[1][0] <= '9')))) { @@ -2898,6 +2901,10 @@ COMMAND_HANDLER(handle_reg_command) } return ERROR_COMMAND_SYNTAX_ERROR; + +not_found: + command_print(CMD_CTX, "register %s not found in current target", CMD_ARGV[0]); + return ERROR_OK; } COMMAND_HANDLER(handle_poll_command) From d92adf8abf6257c2d58ba409731f4d7fa5aa6b5f Mon Sep 17 00:00:00 2001 From: Steven Stallion Date: Wed, 3 May 2017 12:46:11 -0500 Subject: [PATCH 120/147] rtos: support gdb_get_register_packet This patch adds support for p packet responses by targets configured with RTOS support. This change required moving to a rtos_reg struct, which is similar to struct reg used by targets, which resulted in needing to update each stacking with register numbers. This patch also allows targets with non-linear register numbers to function with RTOSes as well. Change-Id: I5b189d74110d6b6f2fa851a67ab0762ae6b1832f Signed-off-by: Steven Stallion Reviewed-on: http://openocd.zylin.com/4121 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/rtos/ChibiOS.c | 9 +- src/rtos/FreeRTOS.c | 13 +- src/rtos/ThreadX.c | 81 +++++----- src/rtos/eCos.c | 10 +- src/rtos/embKernel.c | 9 +- src/rtos/linux.c | 169 ++++++--------------- src/rtos/mqx.c | 6 +- src/rtos/nuttx.c | 75 +++++---- src/rtos/rtos.c | 116 ++++++++++---- src/rtos/rtos.h | 14 +- src/rtos/rtos_chibios_stackings.c | 68 ++++----- src/rtos/rtos_ecos_stackings.c | 34 ++--- src/rtos/rtos_embkernel_stackings.c | 34 ++--- src/rtos/rtos_mqx_stackings.c | 34 ++--- src/rtos/rtos_standard_stackings.c | 226 ++++++++++++++-------------- src/rtos/rtos_ucos_iii_stackings.c | 34 ++--- src/rtos/uCOS-III.c | 6 +- src/server/gdb_server.c | 3 + 18 files changed, 470 insertions(+), 471 deletions(-) diff --git a/src/rtos/ChibiOS.c b/src/rtos/ChibiOS.c index 312fc4d99..8839acc9a 100644 --- a/src/rtos/ChibiOS.c +++ b/src/rtos/ChibiOS.c @@ -105,7 +105,8 @@ static struct ChibiOS_params ChibiOS_params_list[] = { static bool ChibiOS_detect_rtos(struct target *target); static int ChibiOS_create(struct target *target); static int ChibiOS_update_threads(struct rtos *rtos); -static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); +static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs); static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); struct rtos_type ChibiOS_rtos = { @@ -464,13 +465,13 @@ static int ChibiOS_update_threads(struct rtos *rtos) return 0; } -static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list) +static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs) { int retval; const struct ChibiOS_params *param; uint32_t stack_ptr = 0; - *hex_reg_list = NULL; if ((rtos == NULL) || (thread_id == 0) || (rtos->rtos_specific_params == NULL)) return -1; @@ -495,7 +496,7 @@ static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, cha return retval; } - return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list); + return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs); } static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) diff --git a/src/rtos/FreeRTOS.c b/src/rtos/FreeRTOS.c index 6027d6739..9d89974cc 100644 --- a/src/rtos/FreeRTOS.c +++ b/src/rtos/FreeRTOS.c @@ -102,7 +102,8 @@ static const struct FreeRTOS_params FreeRTOS_params_list[] = { static bool FreeRTOS_detect_rtos(struct target *target); static int FreeRTOS_create(struct target *target); static int FreeRTOS_update_threads(struct rtos *rtos); -static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); +static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs); static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); struct rtos_type FreeRTOS_rtos = { @@ -395,13 +396,13 @@ static int FreeRTOS_update_threads(struct rtos *rtos) return 0; } -static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list) +static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs) { int retval; const struct FreeRTOS_params *param; int64_t stack_ptr = 0; - *hex_reg_list = NULL; if (rtos == NULL) return -1; @@ -460,11 +461,11 @@ static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, ch return retval; } if ((LR_svc & 0x10) == 0) - return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f_fpu, stack_ptr, hex_reg_list); + return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f_fpu, stack_ptr, reg_list, num_regs); else - return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f, stack_ptr, hex_reg_list); + return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f, stack_ptr, reg_list, num_regs); } else - return rtos_generic_stack_read(rtos->target, param->stacking_info_cm3, stack_ptr, hex_reg_list); + return rtos_generic_stack_read(rtos->target, param->stacking_info_cm3, stack_ptr, reg_list, num_regs); } static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) diff --git a/src/rtos/ThreadX.c b/src/rtos/ThreadX.c index b7dbe6d11..9605533aa 100644 --- a/src/rtos/ThreadX.c +++ b/src/rtos/ThreadX.c @@ -38,7 +38,7 @@ static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_ static bool ThreadX_detect_rtos(struct target *target); static int ThreadX_create(struct target *target); static int ThreadX_update_threads(struct rtos *rtos); -static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); +static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); @@ -69,45 +69,45 @@ static const struct ThreadX_thread_state ThreadX_thread_states[] = { #define ARM926EJS_REGISTERS_SIZE_SOLICITED (11 * 4) static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_solicited[] = { - { -1, 32 }, /* r0 */ - { -1, 32 }, /* r1 */ - { -1, 32 }, /* r2 */ - { -1, 32 }, /* r3 */ - { 0x08, 32 }, /* r4 */ - { 0x0C, 32 }, /* r5 */ - { 0x10, 32 }, /* r6 */ - { 0x14, 32 }, /* r7 */ - { 0x18, 32 }, /* r8 */ - { 0x1C, 32 }, /* r9 */ - { 0x20, 32 }, /* r10 */ - { 0x24, 32 }, /* r11 */ - { -1, 32 }, /* r12 */ - { -2, 32 }, /* sp (r13) */ - { 0x28, 32 }, /* lr (r14) */ - { -1, 32 }, /* pc (r15) */ - /*{ -1, 32 },*/ /* lr (r14) */ - /*{ 0x28, 32 },*/ /* pc (r15) */ - { 0x04, 32 }, /* xPSR */ + { 0, -1, 32 }, /* r0 */ + { 1, -1, 32 }, /* r1 */ + { 2, -1, 32 }, /* r2 */ + { 3, -1, 32 }, /* r3 */ + { 4, 0x08, 32 }, /* r4 */ + { 5, 0x0C, 32 }, /* r5 */ + { 6, 0x10, 32 }, /* r6 */ + { 7, 0x14, 32 }, /* r7 */ + { 8, 0x18, 32 }, /* r8 */ + { 9, 0x1C, 32 }, /* r9 */ + { 10, 0x20, 32 }, /* r10 */ + { 11, 0x24, 32 }, /* r11 */ + { 12, -1, 32 }, /* r12 */ + { 13, -2, 32 }, /* sp (r13) */ + { 14, 0x28, 32 }, /* lr (r14) */ + { 15, -1, 32 }, /* pc (r15) */ + /*{ 16, -1, 32 },*/ /* lr (r14) */ + /*{ 17, 0x28, 32 },*/ /* pc (r15) */ + { 16, 0x04, 32 }, /* xPSR */ }; #define ARM926EJS_REGISTERS_SIZE_INTERRUPT (17 * 4) static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_interrupt[] = { - { 0x08, 32 }, /* r0 */ - { 0x0C, 32 }, /* r1 */ - { 0x10, 32 }, /* r2 */ - { 0x14, 32 }, /* r3 */ - { 0x18, 32 }, /* r4 */ - { 0x1C, 32 }, /* r5 */ - { 0x20, 32 }, /* r6 */ - { 0x24, 32 }, /* r7 */ - { 0x28, 32 }, /* r8 */ - { 0x2C, 32 }, /* r9 */ - { 0x30, 32 }, /* r10 */ - { 0x34, 32 }, /* r11 */ - { 0x38, 32 }, /* r12 */ - { -2, 32 }, /* sp (r13) */ - { 0x3C, 32 }, /* lr (r14) */ - { 0x40, 32 }, /* pc (r15) */ - { 0x04, 32 }, /* xPSR */ + { 0, 0x08, 32 }, /* r0 */ + { 1, 0x0C, 32 }, /* r1 */ + { 2, 0x10, 32 }, /* r2 */ + { 3, 0x14, 32 }, /* r3 */ + { 4, 0x18, 32 }, /* r4 */ + { 5, 0x1C, 32 }, /* r5 */ + { 6, 0x20, 32 }, /* r6 */ + { 7, 0x24, 32 }, /* r7 */ + { 8, 0x28, 32 }, /* r8 */ + { 9, 0x2C, 32 }, /* r9 */ + { 10, 0x30, 32 }, /* r10 */ + { 11, 0x34, 32 }, /* r11 */ + { 12, 0x38, 32 }, /* r12 */ + { 13, -2, 32 }, /* sp (r13) */ + { 14, 0x3C, 32 }, /* lr (r14) */ + { 15, 0x40, 32 }, /* pc (r15) */ + { 16, 0x04, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking[] = { @@ -433,13 +433,12 @@ static int ThreadX_update_threads(struct rtos *rtos) return 0; } -static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list) +static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs) { int retval; const struct ThreadX_params *param; - *hex_reg_list = NULL; - if (rtos == NULL) return -1; @@ -477,7 +476,7 @@ static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, cha return -6; } - return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, hex_reg_list); + return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, reg_list, num_regs); } static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) diff --git a/src/rtos/eCos.c b/src/rtos/eCos.c index 9e41030ee..e6b70730b 100644 --- a/src/rtos/eCos.c +++ b/src/rtos/eCos.c @@ -30,7 +30,7 @@ static bool eCos_detect_rtos(struct target *target); static int eCos_create(struct target *target); static int eCos_update_threads(struct rtos *rtos); -static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); +static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); struct eCos_thread_state { @@ -285,13 +285,12 @@ static int eCos_update_threads(struct rtos *rtos) return 0; } -static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list) +static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs) { int retval; const struct eCos_params *param; - *hex_reg_list = NULL; - if (rtos == NULL) return -1; @@ -345,7 +344,8 @@ static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char * return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, - hex_reg_list); + reg_list, + num_regs); } return -1; diff --git a/src/rtos/embKernel.c b/src/rtos/embKernel.c index a40c86c3f..8a307f198 100644 --- a/src/rtos/embKernel.c +++ b/src/rtos/embKernel.c @@ -34,7 +34,8 @@ static bool embKernel_detect_rtos(struct target *target); static int embKernel_create(struct target *target); static int embKernel_update_threads(struct rtos *rtos); -static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); +static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs); static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); struct rtos_type embKernel_rtos = { @@ -300,13 +301,13 @@ static int embKernel_update_threads(struct rtos *rtos) return 0; } -static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list) +static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs) { int retval; const struct embKernel_params *param; int64_t stack_ptr = 0; - *hex_reg_list = NULL; if (rtos == NULL) return -1; @@ -326,7 +327,7 @@ static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, c return retval; } - return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list); + return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs); } static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 4529ddb9a..74172b70a 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -144,16 +144,6 @@ static int linux_read_memory(struct target *target, return ERROR_OK; } -static char *reg_converter(char *buffer, void *reg, int size) -{ - int i; - - for (i = 0; i < size; i++) - buffer += sprintf(buffer, "%02x", ((uint8_t *) reg)[i]); - - return buffer; -} - int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer) { @@ -174,15 +164,13 @@ uint32_t get_buffer(struct target *target, const uint8_t *buffer) } static int linux_os_thread_reg_list(struct rtos *rtos, - int64_t thread_id, char **hex_reg_list) + int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { struct target *target = rtos->target; struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; - int i = 0; struct current_thread *tmp = linux_os->current_threads; struct current_thread *next; - char *hex_string; int found = 0; int retval; /* check if a current thread is requested */ @@ -195,117 +183,52 @@ static int linux_os_thread_reg_list(struct rtos *rtos, next = next->next; } while ((found == 0) && (next != tmp) && (next != NULL)); - if (found == 1) { - /* search target to perfom the access */ - struct reg **reg_list; - int reg_list_size, reg_packet_size = 0; - struct target_list *head; - head = target->head; - found = 0; - do { - if (head->target->coreid == next->core_id) { - - target = head->target; - found = 1; - } else - head = head->next; - - } while ((head != (struct target_list *)NULL) && (found == 0)); - - if (found == 0) { - LOG_ERROR - ( - "current thread %" PRIx64 ": no target to perform access of core id %" PRIx32, - thread_id, - next->core_id); - return ERROR_FAIL; - } - - /*LOG_INFO("thread %lx current on core %x",thread_id, - * target->coreid);*/ - retval = - target_get_gdb_reg_list(target, ®_list, ®_list_size, - REG_CLASS_GENERAL); - - if (retval != ERROR_OK) - return retval; - - for (i = 0; i < reg_list_size; i++) - reg_packet_size += reg_list[i]->size; - - assert(reg_packet_size > 0); - - *hex_reg_list = malloc(DIV_ROUND_UP(reg_packet_size, 8) * 2); - - hex_string = *hex_reg_list; - - for (i = 0; i < reg_list_size; i++) { - if (!reg_list[i]->valid) - reg_list[i]->type->get(reg_list[i]); - - hex_string = reg_converter(hex_string, - reg_list[i]->value, - (reg_list[i]->size) / 8); - } - - free(reg_list); - - } else { - struct threads *temp = linux_os->thread_list; - *hex_reg_list = calloc(1, 500 * sizeof(char)); - hex_string = *hex_reg_list; - - for (i = 0; i < 16; i++) - hex_string += sprintf(hex_string, "%02x", 0); - - while ((temp != NULL) && - (temp->threadid != target->rtos->current_threadid)) - temp = temp->next; - - if (temp != NULL) { - if (temp->context == NULL) - temp->context = cpu_context_read(target, - temp-> - base_addr, - &temp-> - thread_info_addr); - - hex_string = - reg_converter(hex_string, &temp->context->R4, 4); - hex_string = - reg_converter(hex_string, &temp->context->R5, 4); - hex_string = - reg_converter(hex_string, &temp->context->R6, 4); - hex_string = - reg_converter(hex_string, &temp->context->R7, 4); - hex_string = - reg_converter(hex_string, &temp->context->R8, 4); - hex_string = - reg_converter(hex_string, &temp->context->R9, 4); - - for (i = 0; i < 4; i++) /*R10 = 0x0 */ - hex_string += sprintf(hex_string, "%02x", 0); - - hex_string = - reg_converter(hex_string, &temp->context->FP, 4); - hex_string = - reg_converter(hex_string, &temp->context->IP, 4); - hex_string = - reg_converter(hex_string, &temp->context->SP, 4); - - for (i = 0; i < 4; i++) - hex_string += sprintf(hex_string, "%02x", 0); - - hex_string = - reg_converter(hex_string, &temp->context->PC, 4); - - for (i = 0; i < 100; i++) /*100 */ - hex_string += sprintf(hex_string, "%02x", 0); - - uint32_t cpsr = 0x00000000; - reg_converter(hex_string, &cpsr, 4); - } + if (found == 0) { + LOG_ERROR("could not find thread: %" PRIx64, thread_id); + return ERROR_FAIL; } + + /* search target to perfom the access */ + struct reg **gdb_reg_list; + struct target_list *head; + head = target->head; + found = 0; + do { + if (head->target->coreid == next->core_id) { + + target = head->target; + found = 1; + } else + head = head->next; + + } while ((head != (struct target_list *)NULL) && (found == 0)); + + if (found == 0) { + LOG_ERROR + ( + "current thread %" PRIx64 ": no target to perform access of core id %" PRIx32, + thread_id, + next->core_id); + return ERROR_FAIL; + } + + /*LOG_INFO("thread %lx current on core %x",thread_id, target->coreid);*/ + retval = target_get_gdb_reg_list(target, &gdb_reg_list, num_regs, REG_CLASS_GENERAL); + if (retval != ERROR_OK) + return retval; + + *reg_list = calloc(*num_regs, sizeof(struct rtos_reg)); + + for (int i = 0; i < *num_regs; ++i) { + if (!gdb_reg_list[i]->valid) + gdb_reg_list[i]->type->get(gdb_reg_list[i]); + + (*reg_list)[i].number = gdb_reg_list[i]->number; + (*reg_list)[i].size = gdb_reg_list[i]->size; + + buf_cpy(gdb_reg_list[i]->value, (*reg_list)[i].value, (*reg_list)[i].size); + } + return ERROR_OK; } diff --git a/src/rtos/mqx.c b/src/rtos/mqx.c index 531b03b57..6646ad4de 100644 --- a/src/rtos/mqx.c +++ b/src/rtos/mqx.c @@ -456,7 +456,8 @@ static int mqx_update_threads( static int mqx_get_thread_reg_list( struct rtos *rtos, int64_t thread_id, - char **hex_reg_list + struct rtos_reg **reg_list, + int *num_regs ) { int64_t stack_ptr = 0; @@ -465,7 +466,6 @@ static int mqx_get_thread_reg_list( uint32_t task_queue_size = 0; uint32_t kernel_data_addr = 0; - *hex_reg_list = NULL; if (thread_id == 0) { LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id); return ERROR_FAIL; @@ -535,7 +535,7 @@ static int mqx_get_thread_reg_list( return ERROR_FAIL; } return rtos_generic_stack_read( - rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, hex_reg_list + rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, reg_list, num_regs ); } diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c index 284b968cc..61fd9aa6c 100644 --- a/src/rtos/nuttx.c +++ b/src/rtos/nuttx.c @@ -98,23 +98,23 @@ static char *task_state_str[] = { /* see arch/arm/include/armv7-m/irq_cmnvector.h */ static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = { - { 0x28, 32 }, /* r0 */ - { 0x2c, 32 }, /* r1 */ - { 0x30, 32 }, /* r2 */ - { 0x34, 32 }, /* r3 */ - { 0x08, 32 }, /* r4 */ - { 0x0c, 32 }, /* r5 */ - { 0x10, 32 }, /* r6 */ - { 0x14, 32 }, /* r7 */ - { 0x18, 32 }, /* r8 */ - { 0x1c, 32 }, /* r9 */ - { 0x20, 32 }, /* r10 */ - { 0x24, 32 }, /* r11 */ - { 0x38, 32 }, /* r12 */ - { 0, 32 }, /* sp */ - { 0x3c, 32 }, /* lr */ - { 0x40, 32 }, /* pc */ - { 0x44, 32 }, /* xPSR */ + { ARMV7M_R0, 0x28, 32 }, /* r0 */ + { ARMV7M_R1, 0x2c, 32 }, /* r1 */ + { ARMV7M_R2, 0x30, 32 }, /* r2 */ + { ARMV7M_R3, 0x34, 32 }, /* r3 */ + { ARMV7M_R4, 0x08, 32 }, /* r4 */ + { ARMV7M_R5, 0x0c, 32 }, /* r5 */ + { ARMV7M_R6, 0x10, 32 }, /* r6 */ + { ARMV7M_R7, 0x14, 32 }, /* r7 */ + { ARMV7M_R8, 0x18, 32 }, /* r8 */ + { ARMV7M_R9, 0x1c, 32 }, /* r9 */ + { ARMV7M_R10, 0x20, 32 }, /* r10 */ + { ARMV7M_R11, 0x24, 32 }, /* r11 */ + { ARMV7M_R12, 0x38, 32 }, /* r12 */ + { ARMV7M_R13, 0, 32 }, /* sp */ + { ARMV7M_R14, 0x3c, 32 }, /* lr */ + { ARMV7M_PC, 0x40, 32 }, /* pc */ + { ARMV7M_xPSR, 0x44, 32 }, /* xPSR */ }; @@ -127,23 +127,23 @@ static const struct rtos_register_stacking nuttx_stacking_cortex_m = { }; static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = { - { 0x6c, 32 }, /* r0 */ - { 0x70, 32 }, /* r1 */ - { 0x74, 32 }, /* r2 */ - { 0x78, 32 }, /* r3 */ - { 0x08, 32 }, /* r4 */ - { 0x0c, 32 }, /* r5 */ - { 0x10, 32 }, /* r6 */ - { 0x14, 32 }, /* r7 */ - { 0x18, 32 }, /* r8 */ - { 0x1c, 32 }, /* r9 */ - { 0x20, 32 }, /* r10 */ - { 0x24, 32 }, /* r11 */ - { 0x7c, 32 }, /* r12 */ - { 0, 32 }, /* sp */ - { 0x80, 32 }, /* lr */ - { 0x84, 32 }, /* pc */ - { 0x88, 32 }, /* xPSR */ + { ARMV7M_R0, 0x6c, 32 }, /* r0 */ + { ARMV7M_R1, 0x70, 32 }, /* r1 */ + { ARMV7M_R2, 0x74, 32 }, /* r2 */ + { ARMV7M_R3, 0x78, 32 }, /* r3 */ + { ARMV7M_R4, 0x08, 32 }, /* r4 */ + { ARMV7M_R5, 0x0c, 32 }, /* r5 */ + { ARMV7M_R6, 0x10, 32 }, /* r6 */ + { ARMV7M_R7, 0x14, 32 }, /* r7 */ + { ARMV7M_R8, 0x18, 32 }, /* r8 */ + { ARMV7M_R9, 0x1c, 32 }, /* r9 */ + { ARMV7M_R10, 0x20, 32 }, /* r10 */ + { ARMV7M_R11, 0x24, 32 }, /* r11 */ + { ARMV7M_R12, 0x7c, 32 }, /* r12 */ + { ARMV7M_R13, 0, 32 }, /* sp */ + { ARMV7M_R14, 0x80, 32 }, /* lr */ + { ARMV7M_PC, 0x84, 32 }, /* pc */ + { ARMV7M_xPSR, 0x88, 32 }, /* xPSR */ }; static const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = { @@ -344,11 +344,10 @@ static int nuttx_update_threads(struct rtos *rtos) * thread_id = tcb address; */ static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, - char **hex_reg_list) { + struct rtos_reg **reg_list, int *num_regs) +{ int retval; - *hex_reg_list = NULL; - /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */ bool cm4_fpu_enabled = false; struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); @@ -378,7 +377,7 @@ static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, stacking = &nuttx_stacking_cortex_m; return rtos_generic_stack_read(rtos->target, stacking, - (uint32_t)thread_id + xcpreg_offset, hex_reg_list); + (uint32_t)thread_id + xcpreg_offset, reg_list, num_regs); } static int nuttx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index 1b3a47f9c..8ca1183b0 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -435,6 +435,68 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa return GDB_THREAD_PACKET_NOT_CONSUMED; } +static int rtos_put_gdb_reg_list(struct connection *connection, + struct rtos_reg *reg_list, int num_regs) +{ + size_t num_bytes = 1; /* NUL */ + for (int i = 0; i < num_regs; ++i) + num_bytes += DIV_ROUND_UP(reg_list[i].size, 8) * 2; + + char *hex = malloc(num_bytes); + char *hex_p = hex; + + for (int i = 0; i < num_regs; ++i) { + size_t count = DIV_ROUND_UP(reg_list[i].size, 8); + size_t n = hexify(hex_p, reg_list[i].value, count, num_bytes); + hex_p += n; + num_bytes -= n; + } + + gdb_put_packet(connection, hex, strlen(hex)); + free(hex); + + return ERROR_OK; +} + +int rtos_get_gdb_reg(struct connection *connection, int reg_num) +{ + struct target *target = get_target_from_connection(connection); + int64_t current_threadid = target->rtos->current_threadid; + if ((target->rtos != NULL) && (current_threadid != -1) && + (current_threadid != 0) && + ((current_threadid != target->rtos->current_thread) || + (target->smp))) { /* in smp several current thread are possible */ + struct rtos_reg *reg_list; + int num_regs; + + LOG_DEBUG("RTOS: getting register %d for thread 0x%" PRIx64 + ", target->rtos->current_thread=0x%" PRIx64 "\r\n", + reg_num, + current_threadid, + target->rtos->current_thread); + + int retval = target->rtos->type->get_thread_reg_list(target->rtos, + current_threadid, + ®_list, + &num_regs); + if (retval != ERROR_OK) { + LOG_ERROR("RTOS: failed to get register list"); + return retval; + } + + for (int i = 0; i < num_regs; ++i) { + if (reg_list[i].number == (uint32_t)reg_num) { + rtos_put_gdb_reg_list(connection, reg_list + i, 1); + free(reg_list); + return ERROR_OK; + } + } + + free(reg_list); + } + return ERROR_FAIL; +} + int rtos_get_gdb_reg_list(struct connection *connection) { struct target *target = get_target_from_connection(connection); @@ -443,7 +505,8 @@ int rtos_get_gdb_reg_list(struct connection *connection) (current_threadid != 0) && ((current_threadid != target->rtos->current_thread) || (target->smp))) { /* in smp several current thread are possible */ - char *hex_reg_list; + struct rtos_reg *reg_list; + int num_regs; LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64 ", target->rtos->current_thread=0x%" PRIx64 "\r\n", @@ -452,17 +515,17 @@ int rtos_get_gdb_reg_list(struct connection *connection) int retval = target->rtos->type->get_thread_reg_list(target->rtos, current_threadid, - &hex_reg_list); + ®_list, + &num_regs); if (retval != ERROR_OK) { LOG_ERROR("RTOS: failed to get register list"); return retval; } - if (hex_reg_list != NULL) { - gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list)); - free(hex_reg_list); - return ERROR_OK; - } + rtos_put_gdb_reg_list(connection, reg_list, num_regs); + free(reg_list); + + return ERROR_OK; } return ERROR_FAIL; } @@ -470,12 +533,9 @@ int rtos_get_gdb_reg_list(struct connection *connection) int rtos_generic_stack_read(struct target *target, const struct rtos_register_stacking *stacking, int64_t stack_ptr, - char **hex_reg_list) + struct rtos_reg **reg_list, + int *num_regs) { - int list_size = 0; - char *tmp_str_ptr; - int64_t new_stack_ptr; - int i; int retval; if (stack_ptr == 0) { @@ -502,10 +562,8 @@ int rtos_generic_stack_read(struct target *target, LOG_OUTPUT("%02X", stack_data[i]); LOG_OUTPUT("\r\n"); #endif - for (i = 0; i < stacking->num_output_registers; i++) - list_size += stacking->register_offsets[i].width_bits/8; - *hex_reg_list = malloc(list_size*2 + 1); - tmp_str_ptr = *hex_reg_list; + + int64_t new_stack_ptr; if (stacking->calculate_process_stack != NULL) { new_stack_ptr = stacking->calculate_process_stack(target, stack_data, stacking, stack_ptr); @@ -513,19 +571,21 @@ int rtos_generic_stack_read(struct target *target, new_stack_ptr = stack_ptr - stacking->stack_growth_direction * stacking->stack_registers_size; } - for (i = 0; i < stacking->num_output_registers; i++) { - int j; - for (j = 0; j < stacking->register_offsets[i].width_bits/8; j++) { - if (stacking->register_offsets[i].offset == -1) - tmp_str_ptr += sprintf(tmp_str_ptr, "%02x", 0); - else if (stacking->register_offsets[i].offset == -2) - tmp_str_ptr += sprintf(tmp_str_ptr, "%02x", - ((uint8_t *)&new_stack_ptr)[j]); - else - tmp_str_ptr += sprintf(tmp_str_ptr, "%02x", - stack_data[stacking->register_offsets[i].offset + j]); - } + + *reg_list = calloc(stacking->num_output_registers, sizeof(struct rtos_reg)); + *num_regs = stacking->num_output_registers; + + for (int i = 0; i < stacking->num_output_registers; ++i) { + (*reg_list)[i].number = stacking->register_offsets[i].number; + (*reg_list)[i].size = stacking->register_offsets[i].width_bits; + + int offset = stacking->register_offsets[i].offset; + if (offset == -2) + buf_cpy(&new_stack_ptr, (*reg_list)[i].value, (*reg_list)[i].size); + else if (offset != -1) + buf_cpy(stack_data + offset, (*reg_list)[i].value, (*reg_list)[i].size); } + free(stack_data); /* LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */ return ERROR_OK; diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index 9978b34ff..b34604787 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -58,19 +58,27 @@ struct rtos { void *rtos_specific_params; }; +struct rtos_reg { + uint32_t number; + uint32_t size; + uint8_t value[8]; +}; + struct rtos_type { const char *name; bool (*detect_rtos)(struct target *target); int (*create)(struct target *target); int (*smp_init)(struct target *target); int (*update_threads)(struct rtos *rtos); - int (*get_thread_reg_list)(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); + int (*get_thread_reg_list)(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs); int (*get_symbol_list_to_lookup)(symbol_table_elem_t *symbol_list[]); int (*clean)(struct target *target); char * (*ps_command)(struct target *target); }; struct stack_register_offset { + unsigned short number; /* register number */ signed short offset; /* offset in bytes from stack head, or -1 to indicate * register is not stacked, or -2 to indicate this is the * stack pointer register */ @@ -99,9 +107,11 @@ int rtos_create(Jim_GetOptInfo *goi, struct target *target); int rtos_generic_stack_read(struct target *target, const struct rtos_register_stacking *stacking, int64_t stack_ptr, - char **hex_reg_list); + struct rtos_reg **reg_list, + int *num_regs); int rtos_try_next(struct target *target); int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size); +int rtos_get_gdb_reg(struct connection *connection, int reg_num); int rtos_get_gdb_reg_list(struct connection *connection); int rtos_update_threads(struct target *target); void rtos_free_threadlist(struct rtos *rtos); diff --git a/src/rtos/rtos_chibios_stackings.c b/src/rtos/rtos_chibios_stackings.c index 3651c49a9..2887930bd 100644 --- a/src/rtos/rtos_chibios_stackings.c +++ b/src/rtos/rtos_chibios_stackings.c @@ -27,23 +27,23 @@ #include "target/armv7m.h" static const struct stack_register_offset rtos_chibios_arm_v7m_stack_offsets[ARMV7M_NUM_CORE_REGS] = { - { -1, 32 }, /* r0 */ - { -1, 32 }, /* r1 */ - { -1, 32 }, /* r2 */ - { -1, 32 }, /* r3 */ - { 0x00, 32 }, /* r4 */ - { 0x04, 32 }, /* r5 */ - { 0x08, 32 }, /* r6 */ - { 0x0c, 32 }, /* r7 */ - { 0x10, 32 }, /* r8 */ - { 0x14, 32 }, /* r9 */ - { 0x18, 32 }, /* r10 */ - { 0x1c, 32 }, /* r11 */ - { -1, 32 }, /* r12 */ - { -2, 32 }, /* sp */ - { -1, 32 }, /* lr */ - { 0x20, 32 }, /* pc */ - { -1, 32 }, /* xPSR */ + { ARMV7M_R0, -1, 32 }, /* r0 */ + { ARMV7M_R1, -1, 32 }, /* r1 */ + { ARMV7M_R2, -1, 32 }, /* r2 */ + { ARMV7M_R3, -1, 32 }, /* r3 */ + { ARMV7M_R4, 0x00, 32 }, /* r4 */ + { ARMV7M_R5, 0x04, 32 }, /* r5 */ + { ARMV7M_R6, 0x08, 32 }, /* r6 */ + { ARMV7M_R7, 0x0c, 32 }, /* r7 */ + { ARMV7M_R8, 0x10, 32 }, /* r8 */ + { ARMV7M_R9, 0x14, 32 }, /* r9 */ + { ARMV7M_R10, 0x18, 32 }, /* r10 */ + { ARMV7M_R11, 0x1c, 32 }, /* r11 */ + { ARMV7M_R12, -1, 32 }, /* r12 */ + { ARMV7M_R13, -2, 32 }, /* sp */ + { ARMV7M_R14, -1, 32 }, /* lr */ + { ARMV7M_PC, 0x20, 32 }, /* pc */ + { ARMV7M_xPSR, -1, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking = { @@ -55,23 +55,23 @@ const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking = { }; static const struct stack_register_offset rtos_chibios_arm_v7m_stack_offsets_w_fpu[ARMV7M_NUM_CORE_REGS] = { - { -1, 32 }, /* r0 */ - { -1, 32 }, /* r1 */ - { -1, 32 }, /* r2 */ - { -1, 32 }, /* r3 */ - { 0x40, 32 }, /* r4 */ - { 0x44, 32 }, /* r5 */ - { 0x48, 32 }, /* r6 */ - { 0x4c, 32 }, /* r7 */ - { 0x50, 32 }, /* r8 */ - { 0x54, 32 }, /* r9 */ - { 0x58, 32 }, /* r10 */ - { 0x5c, 32 }, /* r11 */ - { -1, 32 }, /* r12 */ - { -2, 32 }, /* sp */ - { -1, 32 }, /* lr */ - { 0x60, 32 }, /* pc */ - { -1, 32 }, /* xPSR */ + { ARMV7M_R0, -1, 32 }, /* r0 */ + { ARMV7M_R1, -1, 32 }, /* r1 */ + { ARMV7M_R2, -1, 32 }, /* r2 */ + { ARMV7M_R3, -1, 32 }, /* r3 */ + { ARMV7M_R4, 0x40, 32 }, /* r4 */ + { ARMV7M_R5, 0x44, 32 }, /* r5 */ + { ARMV7M_R6, 0x48, 32 }, /* r6 */ + { ARMV7M_R7, 0x4c, 32 }, /* r7 */ + { ARMV7M_R8, 0x50, 32 }, /* r8 */ + { ARMV7M_R9, 0x54, 32 }, /* r9 */ + { ARMV7M_R10, 0x58, 32 }, /* r10 */ + { ARMV7M_R11, 0x5c, 32 }, /* r11 */ + { ARMV7M_R12, -1, 32 }, /* r12 */ + { ARMV7M_R13, -2, 32 }, /* sp */ + { ARMV7M_R14, -1, 32 }, /* lr */ + { ARMV7M_PC, 0x60, 32 }, /* pc */ + { ARMV7M_xPSR, -1, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking_w_fpu = { diff --git a/src/rtos/rtos_ecos_stackings.c b/src/rtos/rtos_ecos_stackings.c index 43d97a605..ca98d9417 100644 --- a/src/rtos/rtos_ecos_stackings.c +++ b/src/rtos/rtos_ecos_stackings.c @@ -23,23 +23,23 @@ #include "target/armv7m.h" static const struct stack_register_offset rtos_eCos_Cortex_M3_stack_offsets[ARMV7M_NUM_CORE_REGS] = { - { 0x0c, 32 }, /* r0 */ - { 0x10, 32 }, /* r1 */ - { 0x14, 32 }, /* r2 */ - { 0x18, 32 }, /* r3 */ - { 0x1c, 32 }, /* r4 */ - { 0x20, 32 }, /* r5 */ - { 0x24, 32 }, /* r6 */ - { 0x28, 32 }, /* r7 */ - { 0x2c, 32 }, /* r8 */ - { 0x30, 32 }, /* r9 */ - { 0x34, 32 }, /* r10 */ - { 0x38, 32 }, /* r11 */ - { 0x3c, 32 }, /* r12 */ - { -2, 32 }, /* sp */ - { -1, 32 }, /* lr */ - { 0x40, 32 }, /* pc */ - { -1, 32 }, /* xPSR */ + { ARMV7M_R0, 0x0c, 32 }, /* r0 */ + { ARMV7M_R1, 0x10, 32 }, /* r1 */ + { ARMV7M_R2, 0x14, 32 }, /* r2 */ + { ARMV7M_R3, 0x18, 32 }, /* r3 */ + { ARMV7M_R4, 0x1c, 32 }, /* r4 */ + { ARMV7M_R5, 0x20, 32 }, /* r5 */ + { ARMV7M_R6, 0x24, 32 }, /* r6 */ + { ARMV7M_R7, 0x28, 32 }, /* r7 */ + { ARMV7M_R8, 0x2c, 32 }, /* r8 */ + { ARMV7M_R9, 0x30, 32 }, /* r9 */ + { ARMV7M_R10, 0x34, 32 }, /* r10 */ + { ARMV7M_R11, 0x38, 32 }, /* r11 */ + { ARMV7M_R12, 0x3c, 32 }, /* r12 */ + { ARMV7M_R13, -2, 32 }, /* sp */ + { ARMV7M_R14, -1, 32 }, /* lr */ + { ARMV7M_PC, 0x40, 32 }, /* pc */ + { ARMV7M_xPSR, -1, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_eCos_Cortex_M3_stacking = { diff --git a/src/rtos/rtos_embkernel_stackings.c b/src/rtos/rtos_embkernel_stackings.c index 2a3062955..4ee79af93 100644 --- a/src/rtos/rtos_embkernel_stackings.c +++ b/src/rtos/rtos_embkernel_stackings.c @@ -25,23 +25,23 @@ #include "rtos_standard_stackings.h" static const struct stack_register_offset rtos_embkernel_Cortex_M_stack_offsets[ARMV7M_NUM_CORE_REGS] = { - { 0x24, 32 }, /* r0 */ - { 0x28, 32 }, /* r1 */ - { 0x2c, 32 }, /* r2 */ - { 0x30, 32 }, /* r3 */ - { 0x00, 32 }, /* r4 */ - { 0x04, 32 }, /* r5 */ - { 0x08, 32 }, /* r6 */ - { 0x0c, 32 }, /* r7 */ - { 0x10, 32 }, /* r8 */ - { 0x14, 32 }, /* r9 */ - { 0x18, 32 }, /* r10 */ - { 0x1c, 32 }, /* r11 */ - { 0x34, 32 }, /* r12 */ - { -2, 32 }, /* sp */ - { 0x38, 32 }, /* lr */ - { 0x3c, 32 }, /* pc */ - { 0x40, 32 }, /* xPSR */ + { ARMV7M_R0, 0x24, 32 }, /* r0 */ + { ARMV7M_R1, 0x28, 32 }, /* r1 */ + { ARMV7M_R2, 0x2c, 32 }, /* r2 */ + { ARMV7M_R3, 0x30, 32 }, /* r3 */ + { ARMV7M_R4, 0x00, 32 }, /* r4 */ + { ARMV7M_R5, 0x04, 32 }, /* r5 */ + { ARMV7M_R6, 0x08, 32 }, /* r6 */ + { ARMV7M_R7, 0x0c, 32 }, /* r7 */ + { ARMV7M_R8, 0x10, 32 }, /* r8 */ + { ARMV7M_R9, 0x14, 32 }, /* r9 */ + { ARMV7M_R10, 0x18, 32 }, /* r10 */ + { ARMV7M_R11, 0x1c, 32 }, /* r11 */ + { ARMV7M_R12, 0x34, 32 }, /* r12 */ + { ARMV7M_R13, -2, 32 }, /* sp */ + { ARMV7M_R14, 0x38, 32 }, /* lr */ + { ARMV7M_PC, 0x3c, 32 }, /* pc */ + { ARMV7M_xPSR, 0x40, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_embkernel_Cortex_M_stacking = { diff --git a/src/rtos/rtos_mqx_stackings.c b/src/rtos/rtos_mqx_stackings.c index 5db2f8ec3..1a8bdfcc7 100644 --- a/src/rtos/rtos_mqx_stackings.c +++ b/src/rtos/rtos_mqx_stackings.c @@ -51,23 +51,23 @@ */ static const struct stack_register_offset rtos_mqx_arm_v7m_stack_offsets[ARMV7M_NUM_CORE_REGS] = { - { 0x2C, 32 }, /* r0 */ - { 0x30, 32 }, /* r1 */ - { 0x34, 32 }, /* r2 */ - { 0x38, 32 }, /* r3 */ - { 0x08, 32 }, /* r4 */ - { 0x0C, 32 }, /* r5 */ - { 0x10, 32 }, /* r6 */ - { 0x14, 32 }, /* r7 */ - { 0x18, 32 }, /* r8 */ - { 0x1C, 32 }, /* r9 */ - { 0x20, 32 }, /* r10 */ - { 0x24, 32 }, /* r11 */ - { 0x3C, 32 }, /* r12 */ - { -2 , 32 }, /* sp */ - { 0x28, 32 }, /* lr */ - { 0x44, 32 }, /* pc */ - { 0x48, 32 }, /* xPSR */ + { ARMV7M_R0, 0x2C, 32 }, /* r0 */ + { ARMV7M_R1, 0x30, 32 }, /* r1 */ + { ARMV7M_R2, 0x34, 32 }, /* r2 */ + { ARMV7M_R3, 0x38, 32 }, /* r3 */ + { ARMV7M_R4, 0x08, 32 }, /* r4 */ + { ARMV7M_R5, 0x0C, 32 }, /* r5 */ + { ARMV7M_R6, 0x10, 32 }, /* r6 */ + { ARMV7M_R7, 0x14, 32 }, /* r7 */ + { ARMV7M_R8, 0x18, 32 }, /* r8 */ + { ARMV7M_R9, 0x1C, 32 }, /* r9 */ + { ARMV7M_R10, 0x20, 32 }, /* r10 */ + { ARMV7M_R11, 0x24, 32 }, /* r11 */ + { ARMV7M_R12, 0x3C, 32 }, /* r12 */ + { ARMV7M_R13, -2 , 32 }, /* sp */ + { ARMV7M_R14, 0x28, 32 }, /* lr */ + { ARMV7M_PC, 0x44, 32 }, /* pc */ + { ARMV7M_xPSR, 0x48, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_mqx_arm_v7m_stacking = { diff --git a/src/rtos/rtos_standard_stackings.c b/src/rtos/rtos_standard_stackings.c index 931cfc7ed..7b054cbbc 100644 --- a/src/rtos/rtos_standard_stackings.c +++ b/src/rtos/rtos_standard_stackings.c @@ -24,132 +24,132 @@ #include "target/armv7m.h" static const struct stack_register_offset rtos_standard_Cortex_M3_stack_offsets[ARMV7M_NUM_CORE_REGS] = { - { 0x20, 32 }, /* r0 */ - { 0x24, 32 }, /* r1 */ - { 0x28, 32 }, /* r2 */ - { 0x2c, 32 }, /* r3 */ - { 0x00, 32 }, /* r4 */ - { 0x04, 32 }, /* r5 */ - { 0x08, 32 }, /* r6 */ - { 0x0c, 32 }, /* r7 */ - { 0x10, 32 }, /* r8 */ - { 0x14, 32 }, /* r9 */ - { 0x18, 32 }, /* r10 */ - { 0x1c, 32 }, /* r11 */ - { 0x30, 32 }, /* r12 */ - { -2, 32 }, /* sp */ - { 0x34, 32 }, /* lr */ - { 0x38, 32 }, /* pc */ - { 0x3c, 32 }, /* xPSR */ + { ARMV7M_R0, 0x20, 32 }, /* r0 */ + { ARMV7M_R1, 0x24, 32 }, /* r1 */ + { ARMV7M_R2, 0x28, 32 }, /* r2 */ + { ARMV7M_R3, 0x2c, 32 }, /* r3 */ + { ARMV7M_R4, 0x00, 32 }, /* r4 */ + { ARMV7M_R5, 0x04, 32 }, /* r5 */ + { ARMV7M_R6, 0x08, 32 }, /* r6 */ + { ARMV7M_R7, 0x0c, 32 }, /* r7 */ + { ARMV7M_R8, 0x10, 32 }, /* r8 */ + { ARMV7M_R9, 0x14, 32 }, /* r9 */ + { ARMV7M_R10, 0x18, 32 }, /* r10 */ + { ARMV7M_R11, 0x1c, 32 }, /* r11 */ + { ARMV7M_R12, 0x30, 32 }, /* r12 */ + { ARMV7M_R13, -2, 32 }, /* sp */ + { ARMV7M_R14, 0x34, 32 }, /* lr */ + { ARMV7M_PC, 0x38, 32 }, /* pc */ + { ARMV7M_xPSR, 0x3c, 32 }, /* xPSR */ }; static const struct stack_register_offset rtos_standard_Cortex_M4F_stack_offsets[] = { - { 0x24, 32 }, /* r0 */ - { 0x28, 32 }, /* r1 */ - { 0x2c, 32 }, /* r2 */ - { 0x30, 32 }, /* r3 */ - { 0x00, 32 }, /* r4 */ - { 0x04, 32 }, /* r5 */ - { 0x08, 32 }, /* r6 */ - { 0x0c, 32 }, /* r7 */ - { 0x10, 32 }, /* r8 */ - { 0x14, 32 }, /* r9 */ - { 0x18, 32 }, /* r10 */ - { 0x1c, 32 }, /* r11 */ - { 0x34, 32 }, /* r12 */ - { -2, 32 }, /* sp */ - { 0x38, 32 }, /* lr */ - { 0x3c, 32 }, /* pc */ - { 0x40, 32 }, /* xPSR */ + { ARMV7M_R0, 0x24, 32 }, /* r0 */ + { ARMV7M_R1, 0x28, 32 }, /* r1 */ + { ARMV7M_R2, 0x2c, 32 }, /* r2 */ + { ARMV7M_R3, 0x30, 32 }, /* r3 */ + { ARMV7M_R4, 0x00, 32 }, /* r4 */ + { ARMV7M_R5, 0x04, 32 }, /* r5 */ + { ARMV7M_R6, 0x08, 32 }, /* r6 */ + { ARMV7M_R7, 0x0c, 32 }, /* r7 */ + { ARMV7M_R8, 0x10, 32 }, /* r8 */ + { ARMV7M_R9, 0x14, 32 }, /* r9 */ + { ARMV7M_R10, 0x18, 32 }, /* r10 */ + { ARMV7M_R11, 0x1c, 32 }, /* r11 */ + { ARMV7M_R12, 0x34, 32 }, /* r12 */ + { ARMV7M_R13, -2, 32 }, /* sp */ + { ARMV7M_R14, 0x38, 32 }, /* lr */ + { ARMV7M_PC, 0x3c, 32 }, /* pc */ + { ARMV7M_xPSR, 0x40, 32 }, /* xPSR */ }; static const struct stack_register_offset rtos_standard_Cortex_M4F_FPU_stack_offsets[] = { - { 0x64, 32 }, /* r0 */ - { 0x68, 32 }, /* r1 */ - { 0x6c, 32 }, /* r2 */ - { 0x70, 32 }, /* r3 */ - { 0x00, 32 }, /* r4 */ - { 0x04, 32 }, /* r5 */ - { 0x08, 32 }, /* r6 */ - { 0x0c, 32 }, /* r7 */ - { 0x10, 32 }, /* r8 */ - { 0x14, 32 }, /* r9 */ - { 0x18, 32 }, /* r10 */ - { 0x1c, 32 }, /* r11 */ - { 0x74, 32 }, /* r12 */ - { -2, 32 }, /* sp */ - { 0x78, 32 }, /* lr */ - { 0x7c, 32 }, /* pc */ - { 0x80, 32 }, /* xPSR */ + { ARMV7M_R0, 0x64, 32 }, /* r0 */ + { ARMV7M_R1, 0x68, 32 }, /* r1 */ + { ARMV7M_R2, 0x6c, 32 }, /* r2 */ + { ARMV7M_R3, 0x70, 32 }, /* r3 */ + { ARMV7M_R4, 0x00, 32 }, /* r4 */ + { ARMV7M_R5, 0x04, 32 }, /* r5 */ + { ARMV7M_R6, 0x08, 32 }, /* r6 */ + { ARMV7M_R7, 0x0c, 32 }, /* r7 */ + { ARMV7M_R8, 0x10, 32 }, /* r8 */ + { ARMV7M_R9, 0x14, 32 }, /* r9 */ + { ARMV7M_R10, 0x18, 32 }, /* r10 */ + { ARMV7M_R11, 0x1c, 32 }, /* r11 */ + { ARMV7M_R12, 0x74, 32 }, /* r12 */ + { ARMV7M_R13, -2, 32 }, /* sp */ + { ARMV7M_R14, 0x78, 32 }, /* lr */ + { ARMV7M_PC, 0x7c, 32 }, /* pc */ + { ARMV7M_xPSR, 0x80, 32 }, /* xPSR */ }; static const struct stack_register_offset rtos_standard_Cortex_R4_stack_offsets[] = { - { 0x08, 32 }, /* r0 (a1) */ - { 0x0c, 32 }, /* r1 (a2) */ - { 0x10, 32 }, /* r2 (a3) */ - { 0x14, 32 }, /* r3 (a4) */ - { 0x18, 32 }, /* r4 (v1) */ - { 0x1c, 32 }, /* r5 (v2) */ - { 0x20, 32 }, /* r6 (v3) */ - { 0x24, 32 }, /* r7 (v4) */ - { 0x28, 32 }, /* r8 (a1) */ - { 0x2c, 32 }, /* r9 (sb) */ - { 0x30, 32 }, /* r10 (sl) */ - { 0x34, 32 }, /* r11 (fp) */ - { 0x38, 32 }, /* r12 (ip) */ - { -2, 32 }, /* sp */ - { 0x3c, 32 }, /* lr */ - { 0x40, 32 }, /* pc */ - { -1, 96 }, /* FPA1 */ - { -1, 96 }, /* FPA2 */ - { -1, 96 }, /* FPA3 */ - { -1, 96 }, /* FPA4 */ - { -1, 96 }, /* FPA5 */ - { -1, 96 }, /* FPA6 */ - { -1, 96 }, /* FPA7 */ - { -1, 96 }, /* FPA8 */ - { -1, 32 }, /* FPS */ - { 0x04, 32 }, /* CSPR */ + { 0, 0x08, 32 }, /* r0 (a1) */ + { 1, 0x0c, 32 }, /* r1 (a2) */ + { 2, 0x10, 32 }, /* r2 (a3) */ + { 3, 0x14, 32 }, /* r3 (a4) */ + { 4, 0x18, 32 }, /* r4 (v1) */ + { 5, 0x1c, 32 }, /* r5 (v2) */ + { 6, 0x20, 32 }, /* r6 (v3) */ + { 7, 0x24, 32 }, /* r7 (v4) */ + { 8, 0x28, 32 }, /* r8 (a1) */ + { 10, 0x2c, 32 }, /* r9 (sb) */ + { 11, 0x30, 32 }, /* r10 (sl) */ + { 12, 0x34, 32 }, /* r11 (fp) */ + { 13, 0x38, 32 }, /* r12 (ip) */ + { 14, -2, 32 }, /* sp */ + { 15, 0x3c, 32 }, /* lr */ + { 16, 0x40, 32 }, /* pc */ + { 17, -1, 96 }, /* FPA1 */ + { 18, -1, 96 }, /* FPA2 */ + { 19, -1, 96 }, /* FPA3 */ + { 20, -1, 96 }, /* FPA4 */ + { 21, -1, 96 }, /* FPA5 */ + { 22, -1, 96 }, /* FPA6 */ + { 23, -1, 96 }, /* FPA7 */ + { 24, -1, 96 }, /* FPA8 */ + { 25, -1, 32 }, /* FPS */ + { 26, 0x04, 32 }, /* CSPR */ }; static const struct stack_register_offset rtos_standard_NDS32_N1068_stack_offsets[] = { - { 0x88, 32 }, /* R0 */ - { 0x8C, 32 }, /* R1 */ - { 0x14, 32 }, /* R2 */ - { 0x18, 32 }, /* R3 */ - { 0x1C, 32 }, /* R4 */ - { 0x20, 32 }, /* R5 */ - { 0x24, 32 }, /* R6 */ - { 0x28, 32 }, /* R7 */ - { 0x2C, 32 }, /* R8 */ - { 0x30, 32 }, /* R9 */ - { 0x34, 32 }, /* R10 */ - { 0x38, 32 }, /* R11 */ - { 0x3C, 32 }, /* R12 */ - { 0x40, 32 }, /* R13 */ - { 0x44, 32 }, /* R14 */ - { 0x48, 32 }, /* R15 */ - { 0x4C, 32 }, /* R16 */ - { 0x50, 32 }, /* R17 */ - { 0x54, 32 }, /* R18 */ - { 0x58, 32 }, /* R19 */ - { 0x5C, 32 }, /* R20 */ - { 0x60, 32 }, /* R21 */ - { 0x64, 32 }, /* R22 */ - { 0x68, 32 }, /* R23 */ - { 0x6C, 32 }, /* R24 */ - { 0x70, 32 }, /* R25 */ - { 0x74, 32 }, /* R26 */ - { 0x78, 32 }, /* R27 */ - { 0x7C, 32 }, /* R28 */ - { 0x80, 32 }, /* R29 */ - { 0x84, 32 }, /* R30 (LP) */ - { 0x00, 32 }, /* R31 (SP) */ - { 0x04, 32 }, /* PSW */ - { 0x08, 32 }, /* IPC */ - { 0x0C, 32 }, /* IPSW */ - { 0x10, 32 }, /* IFC_LP */ + { 0, 0x88, 32 }, /* R0 */ + { 1, 0x8C, 32 }, /* R1 */ + { 2, 0x14, 32 }, /* R2 */ + { 3, 0x18, 32 }, /* R3 */ + { 4, 0x1C, 32 }, /* R4 */ + { 5, 0x20, 32 }, /* R5 */ + { 6, 0x24, 32 }, /* R6 */ + { 7, 0x28, 32 }, /* R7 */ + { 8, 0x2C, 32 }, /* R8 */ + { 9, 0x30, 32 }, /* R9 */ + { 10, 0x34, 32 }, /* R10 */ + { 11, 0x38, 32 }, /* R11 */ + { 12, 0x3C, 32 }, /* R12 */ + { 13, 0x40, 32 }, /* R13 */ + { 14, 0x44, 32 }, /* R14 */ + { 15, 0x48, 32 }, /* R15 */ + { 16, 0x4C, 32 }, /* R16 */ + { 17, 0x50, 32 }, /* R17 */ + { 18, 0x54, 32 }, /* R18 */ + { 19, 0x58, 32 }, /* R19 */ + { 20, 0x5C, 32 }, /* R20 */ + { 21, 0x60, 32 }, /* R21 */ + { 22, 0x64, 32 }, /* R22 */ + { 23, 0x68, 32 }, /* R23 */ + { 24, 0x6C, 32 }, /* R24 */ + { 25, 0x70, 32 }, /* R25 */ + { 26, 0x74, 32 }, /* R26 */ + { 27, 0x78, 32 }, /* R27 */ + { 28, 0x7C, 32 }, /* R28 */ + { 29, 0x80, 32 }, /* R29 */ + { 30, 0x84, 32 }, /* R30 (LP) */ + { 31, 0x00, 32 }, /* R31 (SP) */ + { 32, 0x04, 32 }, /* PSW */ + { 33, 0x08, 32 }, /* IPC */ + { 34, 0x0C, 32 }, /* IPSW */ + { 35, 0x10, 32 }, /* IFC_LP */ }; static int64_t rtos_generic_stack_align(struct target *target, diff --git a/src/rtos/rtos_ucos_iii_stackings.c b/src/rtos/rtos_ucos_iii_stackings.c index c260b7f80..0a7411edd 100644 --- a/src/rtos/rtos_ucos_iii_stackings.c +++ b/src/rtos/rtos_ucos_iii_stackings.c @@ -26,23 +26,23 @@ #include static const struct stack_register_offset rtos_uCOS_III_Cortex_M_stack_offsets[] = { - { 0x20, 32 }, /* r0 */ - { 0x24, 32 }, /* r1 */ - { 0x28, 32 }, /* r2 */ - { 0x2c, 32 }, /* r3 */ - { 0x00, 32 }, /* r4 */ - { 0x04, 32 }, /* r5 */ - { 0x08, 32 }, /* r6 */ - { 0x0c, 32 }, /* r7 */ - { 0x10, 32 }, /* r8 */ - { 0x14, 32 }, /* r9 */ - { 0x18, 32 }, /* r10 */ - { 0x1c, 32 }, /* r11 */ - { 0x30, 32 }, /* r12 */ - { -2, 32 }, /* sp */ - { 0x34, 32 }, /* lr */ - { 0x38, 32 }, /* pc */ - { 0x3c, 32 }, /* xPSR */ + { ARMV7M_R0, 0x20, 32 }, /* r0 */ + { ARMV7M_R1, 0x24, 32 }, /* r1 */ + { ARMV7M_R2, 0x28, 32 }, /* r2 */ + { ARMV7M_R3, 0x2c, 32 }, /* r3 */ + { ARMV7M_R4, 0x00, 32 }, /* r4 */ + { ARMV7M_R5, 0x04, 32 }, /* r5 */ + { ARMV7M_R6, 0x08, 32 }, /* r6 */ + { ARMV7M_R7, 0x0c, 32 }, /* r7 */ + { ARMV7M_R8, 0x10, 32 }, /* r8 */ + { ARMV7M_R9, 0x14, 32 }, /* r9 */ + { ARMV7M_R10, 0x18, 32 }, /* r10 */ + { ARMV7M_R11, 0x1c, 32 }, /* r11 */ + { ARMV7M_R12, 0x30, 32 }, /* r12 */ + { ARMV7M_R13, -2, 32 }, /* sp */ + { ARMV7M_R14, 0x34, 32 }, /* lr */ + { ARMV7M_PC, 0x38, 32 }, /* pc */ + { ARMV7M_xPSR, 0x3c, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking = { diff --git a/src/rtos/uCOS-III.c b/src/rtos/uCOS-III.c index 8e63ea4e6..e06bf41f8 100644 --- a/src/rtos/uCOS-III.c +++ b/src/rtos/uCOS-III.c @@ -454,7 +454,8 @@ static int uCOS_III_update_threads(struct rtos *rtos) return ERROR_OK; } -static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, char **hex_reg_list) +static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, + struct rtos_reg **reg_list, int *num_regs) { struct uCOS_III_params *params = rtos->rtos_specific_params; int retval; @@ -484,7 +485,8 @@ static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, return rtos_generic_stack_read(rtos->target, params->stacking_info, stack_address, - hex_reg_list); + reg_list, + num_regs); } static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index ee9fc1c97..2b3057a1a 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1301,6 +1301,9 @@ static int gdb_get_register_packet(struct connection *connection, LOG_DEBUG("-"); #endif + if ((target->rtos != NULL) && (ERROR_OK == rtos_get_gdb_reg(connection, reg_num))) + return ERROR_OK; + retval = target_get_gdb_reg_list(target, ®_list, ®_list_size, REG_CLASS_ALL); if (retval != ERROR_OK) From e65acd889c61a424c7bd72fdee5d6a3aee1d8504 Mon Sep 17 00:00:00 2001 From: Steven Stallion Date: Tue, 21 Mar 2017 10:33:09 -0500 Subject: [PATCH 121/147] gdb_server: add support for architecture element This change adds optional support for a target to report architecture information in the target description to GDB. This is needed by some GDB implementations to properly support remote target with custom behavior. More information on the architecture element can be found here: https://sourceware.org/gdb/onlinedocs/gdb/Target-Description-Format.html#Target-Description-Format Change-Id: I57b19cae5ac3496256e4e5cc52cf6526ca5c322d Signed-off-by: Steven Stallion Reviewed-on: http://openocd.zylin.com/4078 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Matthias Welwarsky --- src/server/gdb_server.c | 11 ++++++++++- src/target/target.c | 7 +++++++ src/target/target.h | 7 +++++++ src/target/target_type.h | 9 +++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 2b3057a1a..13e5aca6a 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2196,6 +2196,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o int retval = ERROR_OK; struct reg **reg_list = NULL; int reg_list_size; + char const *architecture; char const **features = NULL; char const **arch_defined_types = NULL; int feature_list_size = 0; @@ -2237,6 +2238,12 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o "\n" "\n"); + /* generate architecture element if supported by target */ + architecture = target_get_gdb_arch(target); + if (architecture != NULL) + xml_printf(&retval, &tdesc, &pos, &size, + "%s\n", architecture); + /* generate target description according to register list */ if (features != NULL) { while (features[current_feature]) { @@ -2386,6 +2393,8 @@ static int gdb_target_description_supported(struct target *target, int *supporte char const **features = NULL; int feature_list_size = 0; + char const *architecture = target_get_gdb_arch(target); + retval = target_get_gdb_reg_list(target, ®_list, ®_list_size, REG_CLASS_ALL); if (retval != ERROR_OK) { @@ -2407,7 +2416,7 @@ static int gdb_target_description_supported(struct target *target, int *supporte } if (supported) { - if (feature_list_size) + if (architecture || feature_list_size) *supported = 1; else *supported = 0; diff --git a/src/target/target.c b/src/target/target.c index 3aaebcd49..c1ccf962e 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1199,6 +1199,13 @@ int target_hit_watchpoint(struct target *target, return target->type->hit_watchpoint(target, hit_watchpoint); } +const char *target_get_gdb_arch(struct target *target) +{ + if (target->type->get_gdb_arch == NULL) + return NULL; + return target->type->get_gdb_arch(target); +} + int target_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) diff --git a/src/target/target.h b/src/target/target.h index fe7e1a7db..5457f0abf 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -472,6 +472,13 @@ int target_remove_watchpoint(struct target *target, int target_hit_watchpoint(struct target *target, struct watchpoint **watchpoint); +/** + * Obtain the architecture for GDB. + * + * This routine is a wrapper for target->type->get_gdb_arch. + */ +const char *target_get_gdb_arch(struct target *target); + /** * Obtain the registers for GDB. * diff --git a/src/target/target_type.h b/src/target/target_type.h index fbbd57d98..a8928911f 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -88,6 +88,15 @@ struct target_type { int (*deassert_reset)(struct target *target); int (*soft_reset_halt)(struct target *target); + /** + * Target architecture for GDB. + * + * The string returned by this function will not be automatically freed; + * if dynamic allocation is used for this value, it must be managed by + * the target, ideally by caching the result for subsequent calls. + */ + const char *(*get_gdb_arch)(struct target *target); + /** * Target register access for GDB. Do @b not call this function * directly, use target_get_gdb_reg_list() instead. From e72b2601e71f49af10f72c4bb6220ee2061ef173 Mon Sep 17 00:00:00 2001 From: Steven Stallion Date: Sun, 26 Mar 2017 15:01:56 -0500 Subject: [PATCH 122/147] jtag: make cmd_queue_scan_field_clone public This patch makes the cmd_queue_scan_field_clone function public. This permits targets to insert fields without affecting the submitted scan_field list. This will be used in an upcoming target implementation that needs to insert additional padding bits. Change-Id: I8fbd3b9b4e413432471f4f1444048932c8fa189e Signed-off-by: Steven Stallion Reviewed-on: http://openocd.zylin.com/4082 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/jtag/Makefile.am | 5 ++--- src/jtag/commands.c | 12 ++++++++++++ src/jtag/commands.h | 1 + src/jtag/drivers/driver.c | 16 ++-------------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am index 50ee263d0..a76486399 100644 --- a/src/jtag/Makefile.am +++ b/src/jtag/Makefile.am @@ -1,6 +1,6 @@ noinst_LTLIBRARIES += %D%/libjtag.la -JTAG_SRCS = +JTAG_SRCS = %D%/commands.c %C%_libjtag_la_LIBADD = BUILT_SOURCES += %D%/minidriver_imp.h @@ -13,7 +13,7 @@ JTAG_SRCS += %D%/zy1000/zy1000.c JTAG_MINIDRIVER_DIR = %D%/zy1000 endif if MINIDRIVER_DUMMY -JTAG_SRCS += %D%/minidummy/minidummy.c %D%/commands.c +JTAG_SRCS += %D%/minidummy/minidummy.c JTAG_MINIDRIVER_DIR = %D%/minidummy endif @@ -29,7 +29,6 @@ CLEANFILES += %D%/jtag_minidriver.h else MINIDRIVER_IMP_DIR = %D%/drivers -JTAG_SRCS += %D%/commands.c if HLADAPTER include %D%/hla/Makefile.am diff --git a/src/jtag/commands.c b/src/jtag/commands.c index ed40755b7..e2d22cc94 100644 --- a/src/jtag/commands.c +++ b/src/jtag/commands.c @@ -144,6 +144,18 @@ void jtag_command_queue_reset(void) next_command_pointer = &jtag_command_queue; } +/** + * Copy a struct scan_field for insertion into the queue. + * + * This allocates a new copy of out_value using cmd_queue_alloc. + */ +void jtag_scan_field_clone(struct scan_field *dst, const struct scan_field *src) +{ + dst->num_bits = src->num_bits; + dst->out_value = buf_cpy(src->out_value, cmd_queue_alloc(DIV_ROUND_UP(src->num_bits, 8)), src->num_bits); + dst->in_value = src->in_value; +} + enum scan_type jtag_scan_type(const struct scan_command *cmd) { int i; diff --git a/src/jtag/commands.h b/src/jtag/commands.h index 947c94725..c0375964c 100644 --- a/src/jtag/commands.h +++ b/src/jtag/commands.h @@ -168,6 +168,7 @@ void *cmd_queue_alloc(size_t size); void jtag_queue_command(struct jtag_command *cmd); void jtag_command_queue_reset(void); +void jtag_scan_field_clone(struct scan_field *dst, const struct scan_field *src); enum scan_type jtag_scan_type(const struct scan_command *cmd); int jtag_scan_size(const struct scan_command *cmd); int jtag_read_buffer(uint8_t *buffer, const struct scan_command *cmd); diff --git a/src/jtag/drivers/driver.c b/src/jtag/drivers/driver.c index daf7cd426..4923f96eb 100644 --- a/src/jtag/drivers/driver.c +++ b/src/jtag/drivers/driver.c @@ -55,18 +55,6 @@ static void jtag_callback_queue_reset(void) jtag_callback_queue_tail = NULL; } -/** - * Copy a struct scan_field for insertion into the queue. - * - * This allocates a new copy of out_value using cmd_queue_alloc. - */ -static void cmd_queue_scan_field_clone(struct scan_field *dst, const struct scan_field *src) -{ - dst->num_bits = src->num_bits; - dst->out_value = buf_cpy(src->out_value, cmd_queue_alloc(DIV_ROUND_UP(src->num_bits, 8)), src->num_bits); - dst->in_value = src->in_value; -} - /** * see jtag_add_ir_scan() * @@ -101,7 +89,7 @@ int interface_jtag_add_ir_scan(struct jtag_tap *active, /* if TAP is listed in input fields, copy the value */ tap->bypass = 0; - cmd_queue_scan_field_clone(field, in_fields); + jtag_scan_field_clone(field, in_fields); } else { /* if a TAP isn't listed in input fields, set it to BYPASS */ @@ -168,7 +156,7 @@ int interface_jtag_add_dr_scan(struct jtag_tap *active, int in_num_fields, #endif /* NDEBUG */ for (int j = 0; j < in_num_fields; j++) { - cmd_queue_scan_field_clone(field, in_fields + j); + jtag_scan_field_clone(field, in_fields + j); field++; } From 4ab75a3634901c4e3897d771e2c75a64c7353c28 Mon Sep 17 00:00:00 2001 From: Steven Stallion Date: Tue, 28 Aug 2018 17:18:01 -0700 Subject: [PATCH 123/147] esirisc: support eSi-RISC targets eSi-RISC is a highly configurable microprocessor architecture for embedded systems provided by EnSilica. This patch adds support for 32-bit targets and also includes an internal flash driver and uC/OS-III RTOS support. This is a non-traditional target and required a number of additional changes to support non-linear register numbers and the 'p' packet in RTOS support for proper integration into EnSilica's GDB port. Change-Id: I59d5c40b3bb2ace1b1a01b2538bfab211adf113f Signed-off-by: Steven Stallion Reviewed-on: http://openocd.zylin.com/4660 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- README | 15 +- doc/openocd.texi | 46 + src/flash/nor/Makefile.am | 1 + src/flash/nor/drivers.c | 2 + src/flash/nor/esirisc_flash.c | 621 ++++++++++ src/rtos/rtos_ucos_iii_stackings.c | 30 + src/rtos/rtos_ucos_iii_stackings.h | 1 + src/rtos/uCOS-III.c | 14 + src/target/Makefile.am | 10 +- src/target/esirisc.c | 1787 ++++++++++++++++++++++++++++ src/target/esirisc.h | 129 ++ src/target/esirisc_jtag.c | 514 ++++++++ src/target/esirisc_jtag.h | 104 ++ src/target/esirisc_regs.h | 184 +++ src/target/target.c | 4 +- src/target/target.h | 7 + tcl/target/esi32xx.cfg | 36 + 17 files changed, 3496 insertions(+), 9 deletions(-) create mode 100644 src/flash/nor/esirisc_flash.c create mode 100644 src/target/esirisc.c create mode 100644 src/target/esirisc.h create mode 100644 src/target/esirisc_jtag.c create mode 100644 src/target/esirisc_jtag.h create mode 100644 src/target/esirisc_regs.h create mode 100644 tcl/target/esi32xx.cfg diff --git a/README b/README index 985e39a98..e1e1b94d3 100644 --- a/README +++ b/README @@ -117,17 +117,18 @@ Debug targets ------------- ARM11, ARM7, ARM9, AVR32, Cortex-A, Cortex-R, Cortex-M, LS102x-SAP, -Feroceon/Dragonite, DSP563xx, DSP5680xx, FA526, MIPS EJTAG, NDS32, -XScale, Intel Quark. +Feroceon/Dragonite, DSP563xx, DSP5680xx, EnSilica eSi-RISC, FA526, MIPS +EJTAG, NDS32, XScale, Intel Quark. Flash drivers ------------- -ADUC702x, AT91SAM, ATH79, AVR, CFI, DSP5680xx, EFM32, EM357, FM3, FM4, Kinetis, -LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPCSPIFI, Marvell QSPI, -Milandr, NIIET, NuMicro, PIC32mx, PSoC4, PSoC5LP, SiM3x, Stellaris, STM32, -STMSMI, STR7x, STR9x, nRF51; NAND controllers of AT91SAM9, LPC3180, LPC32xx, -i.MX31, MXC, NUC910, Orion/Kirkwood, S3C24xx, S3C6400, XMC1xxx, XMC4xxx. +ADUC702x, AT91SAM, ATH79, AVR, CFI, DSP5680xx, EFM32, EM357, eSi-TSMC, +FM3, FM4, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPCSPIFI, +Marvell QSPI, Milandr, NIIET, NuMicro, PIC32mx, PSoC4, PSoC5LP, SiM3x, +Stellaris, STM32, STMSMI, STR7x, STR9x, nRF51; NAND controllers of +AT91SAM9, LPC3180, LPC32xx, i.MX31, MXC, NUC910, Orion/Kirkwood, +S3C24xx, S3C6400, XMC1xxx, XMC4xxx. ================== diff --git a/doc/openocd.texi b/doc/openocd.texi index bbe6cffd4..77c9ff7b6 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4275,6 +4275,8 @@ compact Thumb2 instruction set. @item @code{dragonite} -- resembles arm966e @item @code{dsp563xx} -- implements Freescale's 24-bit DSP. (Support for this is still incomplete.) +@item @code{esirisc} -- this is an EnSilica eSi-RISC core. +The current implementation supports eSi-32xx cores. @item @code{fa526} -- resembles arm920 (w/o Thumb) @item @code{feroceon} -- resembles arm926 @item @code{mips_m4k} -- a MIPS core @@ -5647,6 +5649,27 @@ Note that in order for this command to take effect, the target needs to be reset supported.} @end deffn +@deffn {Flash Driver} esirisc +Members of the eSi-RISC family may optionally include internal flash programmed +via the eSi-TSMC Flash interface. Additional parameters are required to +configure the driver: @option{cfg_address} is the base address of the +configuration register interface, @option{clock_hz} is the expected clock +frequency, and @option{wait_states} is the number of configured read wait states. + +@example +flash bank $_FLASHNAME esirisc base_address size_bytes 0 0 $_TARGETNAME cfg_address clock_hz wait_states +@end example + +@deffn Command {esirisc_flash mass_erase} (bank_id) +Erases all pages in data memory for the bank identified by @option{bank_id}. +@end deffn + +@deffn Command {esirisc_flash ref_erase} (bank_id) +Erases the reference cell for the bank identified by @option{bank_id}. This is +an uncommon operation. +@end deffn +@end deffn + @deffn {Flash Driver} fm3 All members of the FM3 microcontroller family from Fujitsu include internal flash and use ARM Cortex-M3 cores. @@ -8933,6 +8956,29 @@ Selects whether interrupts will be processed when single stepping. The default c @option{on}. @end deffn +@section EnSilica eSi-RISC Architecture + +eSi-RISC is a highly configurable microprocessor architecture for embedded systems +provided by EnSilica. (See: @url{http://www.ensilica.com/risc-ip/}.) + +@subsection esirisc specific commands +@deffn Command {esirisc cache_arch} (@option{harvard}|@option{von_neumann}) +Configure the caching architecture. Targets with the @code{UNIFIED_ADDRESS_SPACE} +option disabled employ a Harvard architecture. By default, @option{von_neumann} is assumed. +@end deffn + +@deffn Command {esirisc flush_caches} +Flush instruction and data caches. This command requires that the target is halted +when the command is issued and configured with an instruction or data cache. +@end deffn + +@deffn Command {esirisc hwdc} (@option{all}|@option{none}|mask ...) +Configure hardware debug control. The HWDC register controls which exceptions return +control back to the debugger. Possible masks are @option{all}, @option{none}, +@option{reset}, @option{interrupt}, @option{syscall}, @option{error}, and @option{debug}. +By default, @option{reset}, @option{error}, and @option{debug} are enabled. +@end deffn + @section Intel Architecture Intel Quark X10xx is the first product in the Quark family of SoCs. It is an IA-32 diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 3839d0a8d..864f7f29a 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -25,6 +25,7 @@ NOR_DRIVERS = \ %D%/dsp5680xx_flash.c \ %D%/efm32.c \ %D%/em357.c \ + %D%/esirisc_flash.c \ %D%/faux.c \ %D%/fm3.c \ %D%/fm4.c \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 2251b965a..4ffd5aca5 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -38,6 +38,7 @@ extern struct flash_driver cfi_flash; extern struct flash_driver dsp5680xx_flash; extern struct flash_driver efm32_flash; extern struct flash_driver em357_flash; +extern struct flash_driver esirisc_flash; extern struct flash_driver faux_flash; extern struct flash_driver fm3_flash; extern struct flash_driver fm4_flash; @@ -103,6 +104,7 @@ static struct flash_driver *flash_drivers[] = { &dsp5680xx_flash, &efm32_flash, &em357_flash, + &esirisc_flash, &faux_flash, &fm3_flash, &fm4_flash, diff --git a/src/flash/nor/esirisc_flash.c b/src/flash/nor/esirisc_flash.c new file mode 100644 index 000000000..f3833df1c --- /dev/null +++ b/src/flash/nor/esirisc_flash.c @@ -0,0 +1,621 @@ +/*************************************************************************** + * Copyright (C) 2018 by Square, Inc. * + * Steven Stallion * + * James Zhao * + * * + * 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 . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +/* eSi-TSMC Flash Registers */ +#define CONTROL 0x00 /* Control Register */ +#define TIMING0 0x04 /* Timing Register 0 */ +#define TIMING1 0x08 /* Timing Register 1 */ +#define TIMING2 0x0c /* Timing Register 2 */ +#define UNLOCK1 0x18 /* Unlock 1 */ +#define UNLOCK2 0x1c /* Unlock 2 */ +#define ADDRESS 0x20 /* Erase/Program Address */ +#define PB_DATA 0x24 /* Program Buffer Data */ +#define PB_INDEX 0x28 /* Program Buffer Index */ +#define STATUS 0x2c /* Status Register */ +#define REDUN_0 0x30 /* Redundant Address 0 */ +#define REDUN_1 0x34 /* Redundant Address 1 */ + +/* Control Fields */ +#define CONTROL_SLM (1<<0) /* Sleep Mode */ +#define CONTROL_WP (1<<1) /* Register Write Protect */ +#define CONTROL_E (1<<3) /* Erase */ +#define CONTROL_EP (1<<4) /* Erase Page */ +#define CONTROL_P (1<<5) /* Program Flash */ +#define CONTROL_ERC (1<<6) /* Erase Reference Cell */ +#define CONTROL_R (1<<7) /* Recall Trim Code */ +#define CONTROL_AP (1<<8) /* Auto-Program */ + +/* Timing Fields */ +#define TIMING0_R(x) (((x) << 0) & 0x3f) /* Read Wait States */ +#define TIMING0_F(x) (((x) << 16) & 0xffff0000) /* Tnvh Clock Cycles */ +#define TIMING1_E(x) (((x) << 0) & 0xffffff) /* Tme/Terase/Tre Clock Cycles */ +#define TIMING2_P(x) (((x) << 0) & 0xffff) /* Tprog Clock Cycles */ +#define TIMING2_H(x) (((x) << 16) & 0xff0000) /* Clock Cycles in 100ns */ +#define TIMING2_T(x) (((x) << 24) & 0xf000000) /* Clock Cycles in 10ns */ + +/* Status Fields */ +#define STATUS_BUSY (1<<0) /* Busy (Erase/Program) */ +#define STATUS_WER (1<<1) /* Write Protect Error */ +#define STATUS_DR (1<<2) /* Disable Redundancy */ +#define STATUS_DIS (1<<3) /* Discharged */ +#define STATUS_BO (1<<4) /* Brown Out */ + +/* Redundant Address Fields */ +#define REDUN_R (1<<0) /* Used */ +#define REDUN_P(x) (((x) << 12) & 0x7f000) /* Redundant Page Address */ + +/* + * The eSi-TSMC Flash manual provides two sets of timings based on the + * underlying flash process. By default, 90nm is assumed. + */ +#if 0 /* 55nm */ +#define TNVH 5000 /* 5us */ +#define TME 80000000 /* 80ms */ +#define TERASE 160000000 /* 160ms */ +#define TRE 100000000 /* 100ms */ +#define TPROG 8000 /* 8us */ +#else /* 90nm */ +#define TNVH 5000 /* 5us */ +#define TME 20000000 /* 20ms */ +#define TERASE 40000000 /* 40ms */ +#define TRE 40000000 /* 40ms */ +#define TPROG 40000 /* 40us */ +#endif + +#define CONTROL_TIMEOUT 5000 /* 5s */ +#define PAGE_SIZE 4096 +#define PB_MAX 32 + +#define NUM_NS_PER_S 1000000000ULL + +struct esirisc_flash_bank { + bool probed; + uint32_t cfg; + uint32_t clock; + uint32_t wait_states; +}; + +FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command) +{ + struct esirisc_flash_bank *esirisc_info; + + if (CMD_ARGC < 9) + return ERROR_COMMAND_SYNTAX_ERROR; + + esirisc_info = calloc(1, sizeof(struct esirisc_flash_bank)); + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], esirisc_info->cfg); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], esirisc_info->clock); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[8], esirisc_info->wait_states); + + bank->driver_priv = esirisc_info; + + return ERROR_OK; +} + +/* + * Register writes are ignored if the control.WP flag is set; the + * following sequence is required to modify this flag even when + * protection is disabled. + */ +static int esirisc_flash_unlock(struct flash_bank *bank) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + struct target *target = bank->target; + + target_write_u32(target, esirisc_info->cfg + UNLOCK1, 0x7123); + target_write_u32(target, esirisc_info->cfg + UNLOCK2, 0x812a); + target_write_u32(target, esirisc_info->cfg + UNLOCK1, 0xbee1); + + return ERROR_OK; +} + +static int esirisc_flash_disable_protect(struct flash_bank *bank) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + struct target *target = bank->target; + uint32_t control; + + target_read_u32(target, esirisc_info->cfg + CONTROL, &control); + if (!(control & CONTROL_WP)) + return ERROR_OK; + + esirisc_flash_unlock(bank); + + control &= ~CONTROL_WP; + + target_write_u32(target, esirisc_info->cfg + CONTROL, control); + + return ERROR_OK; +} + +static int esirisc_flash_enable_protect(struct flash_bank *bank) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + struct target *target = bank->target; + uint32_t control; + + target_read_u32(target, esirisc_info->cfg + CONTROL, &control); + if (control & CONTROL_WP) + return ERROR_OK; + + esirisc_flash_unlock(bank); + + control |= CONTROL_WP; + + target_write_u32(target, esirisc_info->cfg + CONTROL, control); + + return ERROR_OK; +} + +static int esirisc_flash_check_status(struct flash_bank *bank) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + struct target *target = bank->target; + uint32_t status; + + target_read_u32(target, esirisc_info->cfg + STATUS, &status); + if (status & STATUS_WER) { + LOG_ERROR("%s: bad status: 0x%" PRIx32, bank->name, status); + return ERROR_FLASH_OPERATION_FAILED; + } + + return ERROR_OK; +} + +static int esirisc_flash_clear_status(struct flash_bank *bank) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + struct target *target = bank->target; + + target_write_u32(target, esirisc_info->cfg + STATUS, STATUS_WER); + + return ERROR_OK; +} + +static int esirisc_flash_wait(struct flash_bank *bank, int ms) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + struct target *target = bank->target; + uint32_t status; + int64_t t; + + t = timeval_ms(); + for (;;) { + target_read_u32(target, esirisc_info->cfg + STATUS, &status); + if (!(status & STATUS_BUSY)) + return ERROR_OK; + + if ((timeval_ms() - t) > ms) + return ERROR_TARGET_TIMEOUT; + + keep_alive(); + } +} + +static int esirisc_flash_control(struct flash_bank *bank, uint32_t control) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + struct target *target = bank->target; + + esirisc_flash_clear_status(bank); + + target_write_u32(target, esirisc_info->cfg + CONTROL, control); + + int retval = esirisc_flash_wait(bank, CONTROL_TIMEOUT); + if (retval != ERROR_OK) { + LOG_ERROR("%s: control timed out: 0x%" PRIx32, bank->name, control); + return retval; + } + + return esirisc_flash_check_status(bank); +} + +static int esirisc_flash_recall(struct flash_bank *bank) +{ + return esirisc_flash_control(bank, CONTROL_R); +} + +static int esirisc_flash_erase(struct flash_bank *bank, int first, int last) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + struct target *target = bank->target; + int retval = ERROR_OK; + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + esirisc_flash_disable_protect(bank); + + for (int page = first; page < last; ++page) { + uint32_t address = page * PAGE_SIZE; + + target_write_u32(target, esirisc_info->cfg + ADDRESS, address); + + retval = esirisc_flash_control(bank, CONTROL_EP); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to erase address: 0x%" PRIx32, bank->name, address); + break; + } + } + + esirisc_flash_enable_protect(bank); + + return retval; +} + +static int esirisc_flash_mass_erase(struct flash_bank *bank) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + struct target *target = bank->target; + int retval; + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + esirisc_flash_disable_protect(bank); + + target_write_u32(target, esirisc_info->cfg + ADDRESS, 0); + + retval = esirisc_flash_control(bank, CONTROL_E); + if (retval != ERROR_OK) + LOG_ERROR("%s: failed to mass erase", bank->name); + + esirisc_flash_enable_protect(bank); + + return retval; +} + +/* + * Per TSMC, the reference cell should be erased once per sample. This + * is typically done during wafer sort, however we include support for + * those that may need to calibrate flash at a later time. + */ +static int esirisc_flash_ref_erase(struct flash_bank *bank) +{ + struct target *target = bank->target; + int retval; + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + esirisc_flash_disable_protect(bank); + + retval = esirisc_flash_control(bank, CONTROL_ERC); + if (retval != ERROR_OK) + LOG_ERROR("%s: failed to erase reference cell", bank->name); + + esirisc_flash_enable_protect(bank); + + return retval; +} + +static int esirisc_flash_protect(struct flash_bank *bank, int set, int first, int last) +{ + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + if (set) + esirisc_flash_enable_protect(bank); + else + esirisc_flash_disable_protect(bank); + + return ERROR_OK; +} + +static int esirisc_flash_fill_pb(struct flash_bank *bank, + const uint8_t *buffer, uint32_t count) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + struct target *target = bank->target; + struct esirisc_common *esirisc = target_to_esirisc(target); + + /* + * The pb_index register is auto-incremented when pb_data is written + * and should be cleared before each operation. + */ + target_write_u32(target, esirisc_info->cfg + PB_INDEX, 0); + + /* + * The width of the pb_data register depends on the underlying + * target; writing one byte at a time incurs a significant + * performance penalty and should be avoided. + */ + while (count > 0) { + uint32_t max_bytes = DIV_ROUND_UP(esirisc->num_bits, 8); + uint32_t num_bytes = MIN(count, max_bytes); + + target_write_buffer(target, esirisc_info->cfg + PB_DATA, num_bytes, buffer); + + buffer += num_bytes; + count -= num_bytes; + } + + return ERROR_OK; +} + +static int esirisc_flash_write(struct flash_bank *bank, + const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + struct target *target = bank->target; + int retval = ERROR_OK; + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + esirisc_flash_disable_protect(bank); + + /* + * The address register is auto-incremented based on the contents of + * the pb_index register after each operation completes. It can be + * set once provided pb_index is cleared before each operation. + */ + target_write_u32(target, esirisc_info->cfg + ADDRESS, offset); + + /* + * Care must be taken when filling the program buffer; a maximum of + * 32 bytes may be written at a time and may not cross a 32-byte + * boundary based on the current offset. + */ + while (count > 0) { + uint32_t max_bytes = PB_MAX - (offset & 0x1f); + uint32_t num_bytes = MIN(count, max_bytes); + + esirisc_flash_fill_pb(bank, buffer, num_bytes); + + retval = esirisc_flash_control(bank, CONTROL_P); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to program address: 0x%" PRIx32, bank->name, offset); + break; + } + + buffer += num_bytes; + offset += num_bytes; + count -= num_bytes; + } + + esirisc_flash_enable_protect(bank); + + return retval; +} + +static uint32_t esirisc_flash_num_cycles(struct flash_bank *bank, uint64_t ns) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + + /* apply scaling factor to avoid truncation */ + uint64_t hz = (uint64_t)esirisc_info->clock * 1000; + uint64_t num_cycles = ((hz / NUM_NS_PER_S) * ns) / 1000; + + if (hz % NUM_NS_PER_S > 0) + num_cycles++; + + return num_cycles; +} + +static int esirisc_flash_init(struct flash_bank *bank) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + struct target *target = bank->target; + uint32_t value; + int retval; + + esirisc_flash_disable_protect(bank); + + /* initialize timing registers */ + value = TIMING0_F(esirisc_flash_num_cycles(bank, TNVH)) | + TIMING0_R(esirisc_info->wait_states); + + LOG_DEBUG("TIMING0: 0x%" PRIx32, value); + target_write_u32(target, esirisc_info->cfg + TIMING0, value); + + value = TIMING1_E(esirisc_flash_num_cycles(bank, TERASE)); + + LOG_DEBUG("TIMING1: 0x%" PRIx32, value); + target_write_u32(target, esirisc_info->cfg + TIMING1, value); + + value = TIMING2_T(esirisc_flash_num_cycles(bank, 10)) | + TIMING2_H(esirisc_flash_num_cycles(bank, 100)) | + TIMING2_P(esirisc_flash_num_cycles(bank, TPROG)); + + LOG_DEBUG("TIMING2: 0x%" PRIx32, value); + target_write_u32(target, esirisc_info->cfg + TIMING2, value); + + /* recall trim code */ + retval = esirisc_flash_recall(bank); + if (retval != ERROR_OK) + LOG_ERROR("%s: failed to recall trim code", bank->name); + + esirisc_flash_enable_protect(bank); + + return retval; +} + +static int esirisc_flash_probe(struct flash_bank *bank) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + struct target *target = bank->target; + int retval; + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + bank->num_sectors = bank->size / PAGE_SIZE; + bank->sectors = alloc_block_array(0, PAGE_SIZE, bank->num_sectors); + + /* + * Register write protection is enforced using a single protection + * block for the entire bank. This is as good as it gets. + */ + bank->num_prot_blocks = 1; + bank->prot_blocks = alloc_block_array(0, bank->size, bank->num_prot_blocks); + + retval = esirisc_flash_init(bank); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to initialize bank", bank->name); + return retval; + } + + esirisc_info->probed = true; + + return ERROR_OK; +} + +static int esirisc_flash_auto_probe(struct flash_bank *bank) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + + if (esirisc_info->probed) + return ERROR_OK; + + return esirisc_flash_probe(bank); +} + +static int esirisc_flash_protect_check(struct flash_bank *bank) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + struct target *target = bank->target; + uint32_t control; + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + target_read_u32(target, esirisc_info->cfg + CONTROL, &control); + + /* single protection block (also see: esirisc_flash_probe()) */ + bank->prot_blocks[0].is_protected = !!(control & CONTROL_WP); + + return ERROR_OK; +} + +static int esirisc_flash_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct esirisc_flash_bank *esirisc_info = bank->driver_priv; + + snprintf(buf, buf_size, + "%4s cfg at 0x%" PRIx32 ", clock %" PRId32 ", wait_states %" PRId32, + "", /* align with first line */ + esirisc_info->cfg, + esirisc_info->clock, + esirisc_info->wait_states); + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_esirisc_flash_mass_erase_command) +{ + struct flash_bank *bank; + int retval; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (retval != ERROR_OK) + return retval; + + retval = esirisc_flash_mass_erase(bank); + + command_print(CMD_CTX, "mass erase %s", + (retval == ERROR_OK) ? "successful" : "failed"); + + return retval; +} + +COMMAND_HANDLER(handle_esirisc_flash_ref_erase_command) +{ + struct flash_bank *bank; + int retval; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (retval != ERROR_OK) + return retval; + + retval = esirisc_flash_ref_erase(bank); + + command_print(CMD_CTX, "erase reference cell %s", + (retval == ERROR_OK) ? "successful" : "failed"); + + return retval; +} + +static const struct command_registration esirisc_flash_exec_command_handlers[] = { + { + .name = "mass_erase", + .handler = handle_esirisc_flash_mass_erase_command, + .mode = COMMAND_EXEC, + .help = "erases all pages in data memory", + .usage = "bank_id", + }, + { + .name = "ref_erase", + .handler = handle_esirisc_flash_ref_erase_command, + .mode = COMMAND_EXEC, + .help = "erases reference cell (uncommon)", + .usage = "bank_id", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration esirisc_flash_command_handlers[] = { + { + .name = "esirisc_flash", + .mode = COMMAND_ANY, + .help = "eSi-RISC flash command group", + .usage = "", + .chain = esirisc_flash_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct flash_driver esirisc_flash = { + .name = "esirisc", + .commands = esirisc_flash_command_handlers, + .usage = "flash bank bank_id 'esirisc' base_address size_bytes 0 0 target " + "cfg_address clock_hz wait_states", + .flash_bank_command = esirisc_flash_bank_command, + .erase = esirisc_flash_erase, + .protect = esirisc_flash_protect, + .write = esirisc_flash_write, + .read = default_flash_read, + .probe = esirisc_flash_probe, + .auto_probe = esirisc_flash_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = esirisc_flash_protect_check, + .info = esirisc_flash_info, +}; diff --git a/src/rtos/rtos_ucos_iii_stackings.c b/src/rtos/rtos_ucos_iii_stackings.c index 0a7411edd..d093563ba 100644 --- a/src/rtos/rtos_ucos_iii_stackings.c +++ b/src/rtos/rtos_ucos_iii_stackings.c @@ -24,6 +24,7 @@ #include #include #include +#include static const struct stack_register_offset rtos_uCOS_III_Cortex_M_stack_offsets[] = { { ARMV7M_R0, 0x20, 32 }, /* r0 */ @@ -45,6 +46,27 @@ static const struct stack_register_offset rtos_uCOS_III_Cortex_M_stack_offsets[] { ARMV7M_xPSR, 0x3c, 32 }, /* xPSR */ }; +static const struct stack_register_offset rtos_uCOS_III_eSi_RISC_stack_offsets[] = { + { ESIRISC_SP, -2, 32 }, /* sp */ + { ESIRISC_RA, 0x48, 32 }, /* ra */ + { ESIRISC_R2, 0x44, 32 }, /* r2 */ + { ESIRISC_R3, 0x40, 32 }, /* r3 */ + { ESIRISC_R4, 0x3c, 32 }, /* r4 */ + { ESIRISC_R5, 0x38, 32 }, /* r5 */ + { ESIRISC_R6, 0x34, 32 }, /* r6 */ + { ESIRISC_R7, 0x30, 32 }, /* r7 */ + { ESIRISC_R8, 0x2c, 32 }, /* r8 */ + { ESIRISC_R9, 0x28, 32 }, /* r9 */ + { ESIRISC_R10, 0x24, 32 }, /* r10 */ + { ESIRISC_R11, 0x20, 32 }, /* r11 */ + { ESIRISC_R12, 0x1c, 32 }, /* r12 */ + { ESIRISC_R13, 0x18, 32 }, /* r13 */ + { ESIRISC_R14, 0x14, 32 }, /* r14 */ + { ESIRISC_R15, 0x10, 32 }, /* r15 */ + { ESIRISC_PC, 0x04, 32 }, /* PC */ + { ESIRISC_CAS, 0x08, 32 }, /* CAS */ +}; + const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking = { 0x40, /* stack_registers_size */ -1, /* stack_growth_direction */ @@ -52,3 +74,11 @@ const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking = { rtos_generic_stack_align8, /* stack_alignment */ rtos_uCOS_III_Cortex_M_stack_offsets /* register_offsets */ }; + +const struct rtos_register_stacking rtos_uCOS_III_eSi_RISC_stacking = { + 0x4c, /* stack_registers_size */ + -1, /* stack_growth_direction */ + ARRAY_SIZE(rtos_uCOS_III_eSi_RISC_stack_offsets), /* num_output_registers */ + NULL, /* stack_alignment */ + rtos_uCOS_III_eSi_RISC_stack_offsets /* register_offsets */ +}; diff --git a/src/rtos/rtos_ucos_iii_stackings.h b/src/rtos/rtos_ucos_iii_stackings.h index f4703da37..a9398138b 100644 --- a/src/rtos/rtos_ucos_iii_stackings.h +++ b/src/rtos/rtos_ucos_iii_stackings.h @@ -26,5 +26,6 @@ #include extern const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking; +extern const struct rtos_register_stacking rtos_uCOS_III_eSi_RISC_stacking; #endif /* OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H */ diff --git a/src/rtos/uCOS-III.c b/src/rtos/uCOS-III.c index e06bf41f8..3cd9c2ae6 100644 --- a/src/rtos/uCOS-III.c +++ b/src/rtos/uCOS-III.c @@ -68,6 +68,20 @@ static const struct uCOS_III_params uCOS_III_params_list[] = { &rtos_uCOS_III_Cortex_M_stacking, /* stacking_info */ 0, /* num_threads */ }, + { + "esirisc", /* target_name */ + sizeof(uint32_t), /* pointer_width */ + 0, /* thread_stack_offset */ + 0, /* thread_name_offset */ + 0, /* thread_state_offset */ + 0, /* thread_priority_offset */ + 0, /* thread_prev_offset */ + 0, /* thread_next_offset */ + false, /* thread_offsets_updated */ + 1, /* threadid_start */ + &rtos_uCOS_III_eSi_RISC_stacking, /* stacking_info */ + 0, /* num_threads */ + }, }; static const char * const uCOS_III_symbol_list[] = { diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 4b7c8c076..05f174870 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -23,6 +23,7 @@ noinst_LTLIBRARIES += %D%/libtarget.la $(NDS32_SRC) \ $(STM8_SRC) \ $(INTEL_IA32_SRC) \ + $(ESIRISC_SRC) \ %D%/avrt.c \ %D%/dsp563xx.c \ %D%/dsp563xx_once.c \ @@ -139,6 +140,10 @@ INTEL_IA32_SRC = \ %D%/lakemont.c \ %D%/x86_32_common.c +ESIRISC_SRC = \ + %D%/esirisc.c \ + %D%/esirisc_jtag.c + %C%_libtarget_la_SOURCES += \ %D%/algorithm.h \ %D%/arm.h \ @@ -218,7 +223,10 @@ INTEL_IA32_SRC = \ %D%/stm8.h \ %D%/lakemont.h \ %D%/x86_32_common.h \ - %D%/arm_cti.h + %D%/arm_cti.h \ + %D%/esirisc.h \ + %D%/esirisc_jtag.h \ + %D%/esirisc_regs.h include %D%/openrisc/Makefile.am include %D%/riscv/Makefile.am diff --git a/src/target/esirisc.c b/src/target/esirisc.c new file mode 100644 index 000000000..38100e834 --- /dev/null +++ b/src/target/esirisc.c @@ -0,0 +1,1787 @@ +/*************************************************************************** + * Copyright (C) 2018 by Square, Inc. * + * Steven Stallion * + * James Zhao * + * * + * 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 . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "esirisc.h" + +#define RESET_TIMEOUT 5000 /* 5s */ +#define STEP_TIMEOUT 1000 /* 1s */ + +/* + * eSi-RISC targets support a configurable number of interrupts; + * up to 32 interrupts are supported. + */ +static const char * const esirisc_exceptions[] = { + "Reset", "HardwareFailure", "NMI", "InstBreakpoint", "DataBreakpoint", + "Unsupported", "PrivilegeViolation", "InstBusError", "DataBusError", + "AlignmentError", "ArithmeticError", "SystemCall", "MemoryManagement", + "Unrecoverable", "Reserved", + + "Interrupt0", "Interrupt1", "Interrupt2", "Interrupt3", + "Interrupt4", "Interrupt5", "Interrupt6", "Interrupt7", + "Interrupt8", "Interrupt9", "Interrupt10", "Interrupt11", + "Interrupt12", "Interrupt13", "Interrupt14", "Interrupt15", + "Interrupt16", "Interrupt17", "Interrupt18", "Interrupt19", + "Interrupt20", "Interrupt21", "Interrupt22", "Interrupt23", + "Interrupt24", "Interrupt25", "Interrupt26", "Interrupt27", + "Interrupt28", "Interrupt29", "Interrupt30", "Interrupt31", +}; + +/* + * eSi-RISC targets support a configurable number of general purpose + * registers; 8, 16, and 32 registers are supported. + */ +static const struct { + enum esirisc_reg_num number; + const char *name; + enum reg_type type; + const char *group; +} esirisc_regs[] = { + { ESIRISC_SP, "sp", REG_TYPE_DATA_PTR, "general" }, + { ESIRISC_RA, "ra", REG_TYPE_INT, "general" }, + { ESIRISC_R2, "r2", REG_TYPE_INT, "general" }, + { ESIRISC_R3, "r3", REG_TYPE_INT, "general" }, + { ESIRISC_R4, "r4", REG_TYPE_INT, "general" }, + { ESIRISC_R5, "r5", REG_TYPE_INT, "general" }, + { ESIRISC_R6, "r6", REG_TYPE_INT, "general" }, + { ESIRISC_R7, "r7", REG_TYPE_INT, "general" }, + { ESIRISC_R8, "r8", REG_TYPE_INT, "general" }, + { ESIRISC_R9, "r9", REG_TYPE_INT, "general" }, + { ESIRISC_R10, "r10", REG_TYPE_INT, "general" }, + { ESIRISC_R11, "r11", REG_TYPE_INT, "general" }, + { ESIRISC_R12, "r12", REG_TYPE_INT, "general" }, + { ESIRISC_R13, "r13", REG_TYPE_INT, "general" }, + { ESIRISC_R14, "r14", REG_TYPE_INT, "general" }, + { ESIRISC_R15, "r15", REG_TYPE_INT, "general" }, + { ESIRISC_R16, "r16", REG_TYPE_INT, "general" }, + { ESIRISC_R17, "r17", REG_TYPE_INT, "general" }, + { ESIRISC_R18, "r18", REG_TYPE_INT, "general" }, + { ESIRISC_R19, "r19", REG_TYPE_INT, "general" }, + { ESIRISC_R20, "r20", REG_TYPE_INT, "general" }, + { ESIRISC_R21, "r21", REG_TYPE_INT, "general" }, + { ESIRISC_R22, "r22", REG_TYPE_INT, "general" }, + { ESIRISC_R23, "r23", REG_TYPE_INT, "general" }, + { ESIRISC_R24, "r24", REG_TYPE_INT, "general" }, + { ESIRISC_R25, "r25", REG_TYPE_INT, "general" }, + { ESIRISC_R26, "r26", REG_TYPE_INT, "general" }, + { ESIRISC_R27, "r27", REG_TYPE_INT, "general" }, + { ESIRISC_R28, "r28", REG_TYPE_INT, "general" }, + { ESIRISC_R29, "r29", REG_TYPE_INT, "general" }, + { ESIRISC_R30, "r30", REG_TYPE_INT, "general" }, + { ESIRISC_R31, "r31", REG_TYPE_INT, "general" }, +}; + +/* + * Control and Status Registers (CSRs) are largely defined as belonging + * to the system register group. The exception to this rule are the PC + * and CAS registers, which belong to the general group. While debug is + * active, EPC, ECAS, and ETC must be used to read and write the PC, + * CAS, and TC CSRs, respectively. + */ +static const struct { + enum esirisc_reg_num number; + uint8_t bank; + uint8_t csr; + const char *name; + enum reg_type type; + const char *group; +} esirisc_csrs[] = { + { ESIRISC_PC, CSR_THREAD, CSR_THREAD_EPC, "PC", REG_TYPE_CODE_PTR, "general" }, /* PC -> EPC */ + { ESIRISC_CAS, CSR_THREAD, CSR_THREAD_ECAS, "CAS", REG_TYPE_INT, "general" }, /* CAS -> ECAS */ + { ESIRISC_TC, CSR_THREAD, CSR_THREAD_ETC, "TC", REG_TYPE_INT, "system" }, /* TC -> ETC */ + { ESIRISC_ETA, CSR_THREAD, CSR_THREAD_ETA, "ETA", REG_TYPE_INT, "system" }, + { ESIRISC_ETC, CSR_THREAD, CSR_THREAD_ETC, "ETC", REG_TYPE_INT, "system" }, + { ESIRISC_EPC, CSR_THREAD, CSR_THREAD_EPC, "EPC", REG_TYPE_CODE_PTR, "system" }, + { ESIRISC_ECAS, CSR_THREAD, CSR_THREAD_ECAS, "ECAS", REG_TYPE_INT, "system" }, + { ESIRISC_EID, CSR_THREAD, CSR_THREAD_EID, "EID", REG_TYPE_INT, "system" }, + { ESIRISC_ED, CSR_THREAD, CSR_THREAD_ED, "ED", REG_TYPE_INT, "system" }, + { ESIRISC_IP, CSR_INTERRUPT, CSR_INTERRUPT_IP, "IP", REG_TYPE_INT, "system"}, + { ESIRISC_IM, CSR_INTERRUPT, CSR_INTERRUPT_IM, "IM", REG_TYPE_INT, "system"}, + { ESIRISC_IS, CSR_INTERRUPT, CSR_INTERRUPT_IS, "IS", REG_TYPE_INT, "system"}, + { ESIRISC_IT, CSR_INTERRUPT, CSR_INTERRUPT_IT, "IT", REG_TYPE_INT, "system"}, +}; + +static int esirisc_disable_interrupts(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + uint32_t etc; + int retval; + + LOG_DEBUG("-"); + + retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, &etc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: ETC", target_name(target)); + return retval; + } + + etc &= ~(1<<0); /* TC.I */ + + retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, etc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: ETC", target_name(target)); + return retval; + } + + return ERROR_OK; +} + +#if 0 +static int esirisc_enable_interrupts(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + uint32_t etc; + int retval; + + LOG_DEBUG("-"); + + retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, &etc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: ETC", target_name(target)); + return retval; + } + + etc |= (1<<0); /* TC.I */ + + retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, etc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: ETC", target_name(target)); + return retval; + } + + return ERROR_OK; +} +#endif + +static int esirisc_save_interrupts(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + + LOG_DEBUG("-"); + + int retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, + &esirisc->etc_save); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: ETC", target_name(target)); + return retval; + } + + return ERROR_OK; +} + +static int esirisc_restore_interrupts(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + + LOG_DEBUG("-"); + + int retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, + esirisc->etc_save); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: ETC", target_name(target)); + return retval; + } + + return ERROR_OK; +} + +#if 0 +static int esirisc_save_hwdc(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + + LOG_DEBUG("-"); + + int retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_HWDC, + &esirisc->hwdc_save); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: HWDC", target_name(target)); + return retval; + } + + return ERROR_OK; +} +#endif + +static int esirisc_restore_hwdc(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + + LOG_DEBUG("-"); + + int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_HWDC, + esirisc->hwdc_save); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: HWDC", target_name(target)); + return retval; + } + + return ERROR_OK; +} + +static int esirisc_save_context(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + + LOG_DEBUG("-"); + + for (unsigned i = 0; i < esirisc->reg_cache->num_regs; ++i) { + struct reg *reg = esirisc->reg_cache->reg_list + i; + struct esirisc_reg *reg_info = reg->arch_info; + + if (reg->exist && !reg->valid) + reg_info->read(reg); + } + + return ERROR_OK; +} + +static int esirisc_restore_context(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + + LOG_DEBUG("-"); + + for (unsigned i = 0; i < esirisc->reg_cache->num_regs; ++i) { + struct reg *reg = esirisc->reg_cache->reg_list + i; + struct esirisc_reg *reg_info = reg->arch_info; + + if (reg->exist && reg->dirty) + reg_info->write(reg); + } + + return ERROR_OK; +} + +static int esirisc_flush_caches(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + + LOG_DEBUG("-"); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + int retval = esirisc_jtag_flush_caches(jtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to flush caches", target_name(target)); + return retval; + } + + return ERROR_OK; +} + +static int esirisc_wait_debug_active(struct esirisc_common *esirisc, int ms) +{ + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + int64_t t; + + LOG_DEBUG("-"); + + t = timeval_ms(); + for (;;) { + int retval = esirisc_jtag_enable_debug(jtag_info); + if (retval == ERROR_OK && esirisc_jtag_is_debug_active(jtag_info)) + return retval; + + if ((timeval_ms() - t) > ms) + return ERROR_TARGET_TIMEOUT; + + alive_sleep(100); + } +} + +static int esirisc_read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + int retval; + + LOG_DEBUG("-"); + + int num_bits = 8 * size; + for (uint32_t i = 0; i < count; ++i) { + union esirisc_memory value; + void *value_p; + + switch (size) { + case sizeof(value.word): + value_p = &value.word; + retval = esirisc_jtag_read_word(jtag_info, address, value_p); + break; + + case sizeof(value.hword): + value_p = &value.hword; + retval = esirisc_jtag_read_hword(jtag_info, address, value_p); + break; + + case sizeof(value.byte): + value_p = &value.byte; + retval = esirisc_jtag_read_byte(jtag_info, address, value_p); + break; + + default: + LOG_ERROR("%s: unsupported size: %" PRIu32, target_name(target), size); + return ERROR_FAIL; + } + + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read address: 0x%" TARGET_PRIxADDR, target_name(target), + address); + return retval; + } + + buf_cpy(value_p, buffer, num_bits); + address += size; + buffer += size; + } + + return ERROR_OK; +} + +static int esirisc_write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + int retval; + + LOG_DEBUG("-"); + + int num_bits = 8 * size; + for (uint32_t i = 0; i < count; ++i) { + union esirisc_memory value; + + switch (size) { + case sizeof(value.word): + value.word = buf_get_u32(buffer, 0, num_bits); + retval = esirisc_jtag_write_word(jtag_info, address, value.word); + break; + + case sizeof(value.hword): + value.hword = buf_get_u32(buffer, 0, num_bits); + retval = esirisc_jtag_write_hword(jtag_info, address, value.hword); + break; + + case sizeof(value.byte): + value.byte = buf_get_u32(buffer, 0, num_bits); + retval = esirisc_jtag_write_byte(jtag_info, address, value.byte); + break; + + default: + LOG_ERROR("%s: unsupported size: %" PRIu32, target_name(target), size); + return ERROR_FAIL; + } + + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write address: 0x%" TARGET_PRIxADDR, target_name(target), + address); + return retval; + } + + address += size; + buffer += size; + } + + return ERROR_OK; +} + +static int esirisc_checksum_memory(struct target *target, target_addr_t address, + uint32_t count, uint32_t *checksum) +{ + return ERROR_FAIL; /* not supported */ +} + +static int esirisc_next_breakpoint(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct breakpoint **breakpoints_p = esirisc->breakpoints_p; + struct breakpoint **breakpoints_e = breakpoints_p + esirisc->num_breakpoints; + + LOG_DEBUG("-"); + + for (int bp_index = 0; breakpoints_p < breakpoints_e; ++breakpoints_p, ++bp_index) + if (*breakpoints_p == NULL) + return bp_index; + + return -1; +} + +static int esirisc_add_breakpoint(struct target *target, struct breakpoint *breakpoint) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + int bp_index; + uint32_t ibc; + int retval; + + LOG_DEBUG("-"); + + /* + * The default linker scripts provided by the eSi-RISC toolchain do + * not specify attributes on memory regions, which results in + * incorrect application of software breakpoints by GDB. Targets + * must be configured with `gdb_breakpoint_override hard` as + * software breakpoints are not supported. + */ + if (breakpoint->type != BKPT_HARD) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + bp_index = esirisc_next_breakpoint(target); + if (bp_index < 0) { + LOG_ERROR("%s: out of hardware breakpoints", target_name(target)); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + breakpoint->set = bp_index + 1; + esirisc->breakpoints_p[bp_index] = breakpoint; + + /* specify instruction breakpoint address */ + retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBAn + bp_index, + breakpoint->address); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: IBA", target_name(target)); + return retval; + } + + /* enable instruction breakpoint */ + retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, &ibc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: IBC", target_name(target)); + return retval; + } + + ibc |= (1 << bp_index); /* IBC.In */ + + retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, ibc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: IBC", target_name(target)); + return retval; + } + + return ERROR_OK; +} + +static int esirisc_add_breakpoints(struct target *target) +{ + struct breakpoint *breakpoint = target->breakpoints; + + LOG_DEBUG("-"); + + while (breakpoint != NULL) { + if (breakpoint->set == 0) + esirisc_add_breakpoint(target, breakpoint); + + breakpoint = breakpoint->next; + } + + return ERROR_OK; +} + +static int esirisc_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + int bp_index = breakpoint->set - 1; + uint32_t ibc; + int retval; + + LOG_DEBUG("-"); + + /* disable instruction breakpoint */ + retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, &ibc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: IBC", target_name(target)); + return retval; + } + + ibc &= ~(1 << bp_index); /* IBC.In */ + + retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, ibc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: IBC", target_name(target)); + return retval; + } + + esirisc->breakpoints_p[bp_index] = NULL; + breakpoint->set = 0; + + return ERROR_OK; +} + +static int esirisc_remove_breakpoints(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + + LOG_DEBUG("-"); + + /* clear instruction breakpoints */ + int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, 0); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: IBC", target_name(target)); + return retval; + } + + memset(esirisc->breakpoints_p, 0, sizeof(esirisc->breakpoints_p)); + + return ERROR_OK; +} + +static int esirisc_next_watchpoint(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct watchpoint **watchpoints_p = esirisc->watchpoints_p; + struct watchpoint **watchpoints_e = watchpoints_p + esirisc->num_watchpoints; + + LOG_DEBUG("-"); + + for (int wp_index = 0; watchpoints_p < watchpoints_e; ++watchpoints_p, ++wp_index) + if (*watchpoints_p == NULL) + return wp_index; + + return -1; +} + +static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watchpoint) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + int wp_index; + uint32_t dbs, dbc; + int retval; + + LOG_DEBUG("-"); + + wp_index = esirisc_next_watchpoint(target); + if (wp_index < 0) { + LOG_ERROR("%s: out of hardware watchpoints", target_name(target)); + return ERROR_FAIL; + } + + watchpoint->set = wp_index + 1; + esirisc->watchpoints_p[wp_index] = watchpoint; + + /* specify data breakpoint address */ + retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBAn + wp_index, + watchpoint->address); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: DBA", target_name(target)); + return retval; + } + + /* specify data breakpoint size */ + retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBS, &dbs); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: DBS", target_name(target)); + return retval; + } + + uint32_t sn; + switch (watchpoint->length) { + case sizeof(uint64_t): + sn = 0x3; + break; + case sizeof(uint32_t): + sn = 0x2; + break; + + case sizeof(uint16_t): + sn = 0x1; + break; + + case sizeof(uint8_t): + sn = 0x0; + break; + + default: + LOG_ERROR("%s: unsupported length: %" PRIu32, target_name(target), + watchpoint->length); + return ERROR_FAIL; + } + + dbs |= (sn << (2 * wp_index)); /* DBS.Sn */ + + retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBS, dbs); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: DBS", target_name(target)); + return retval; + } + + /* enable data breakpoint */ + retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, &dbc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: DBC", target_name(target)); + return retval; + } + + uint32_t dn; + switch (watchpoint->rw) { + case WPT_READ: + dn = 0x1; + break; + + case WPT_WRITE: + dn = 0x2; + break; + + case WPT_ACCESS: + dn = 0x3; + break; + + default: + LOG_ERROR("%s: unsupported rw: %" PRId32, target_name(target), + watchpoint->rw); + return ERROR_FAIL; + } + + dbc |= (dn << (2 * wp_index)); /* DBC.Dn */ + + retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, dbc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: DBC", target_name(target)); + return retval; + } + + return ERROR_OK; +} + +static int esirisc_add_watchpoints(struct target *target) +{ + struct watchpoint *watchpoint = target->watchpoints; + + LOG_DEBUG("-"); + + while (watchpoint != NULL) { + if (watchpoint->set == 0) + esirisc_add_watchpoint(target, watchpoint); + + watchpoint = watchpoint->next; + } + + return ERROR_OK; +} + +static int esirisc_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + int wp_index = watchpoint->set - 1; + uint32_t dbc; + int retval; + + LOG_DEBUG("-"); + + /* disable data breakpoint */ + retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, &dbc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: DBC", target_name(target)); + return retval; + } + + dbc &= ~(0x3 << (2 * wp_index)); /* DBC.Dn */ + + retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, dbc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: DBC", target_name(target)); + return retval; + } + + esirisc->watchpoints_p[wp_index] = NULL; + watchpoint->set = 0; + + return ERROR_OK; +} + +static int esirisc_remove_watchpoints(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + + LOG_DEBUG("-"); + + /* clear data breakpoints */ + int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, 0); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: DBC", target_name(target)); + return retval; + } + + memset(esirisc->watchpoints_p, 0, sizeof(esirisc->watchpoints_p)); + + return ERROR_OK; +} + +static int esirisc_halt(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + + LOG_DEBUG("-"); + + if (target->state == TARGET_HALTED) + return ERROR_OK; + + int retval = esirisc_jtag_break(jtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to halt target", target_name(target)); + return retval; + } + + target->debug_reason = DBG_REASON_DBGRQ; + + return ERROR_OK; +} + +static int esirisc_disable_step(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + uint32_t dc; + int retval; + + LOG_DEBUG("-"); + + retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, &dc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: DC", target_name(target)); + return retval; + } + + dc &= ~(1<<0); /* DC.S */ + + retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, dc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: DC", target_name(target)); + return retval; + } + + return ERROR_OK; +} + +static int esirisc_enable_step(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + uint32_t dc; + int retval; + + LOG_DEBUG("-"); + + retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, &dc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: DC", target_name(target)); + return retval; + } + + dc |= (1<<0); /* DC.S */ + + retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, dc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: DC", target_name(target)); + return retval; + } + + return ERROR_OK; +} + +static int esirisc_resume_or_step(struct target *target, int current, target_addr_t address, + int handle_breakpoints, int debug_execution, bool step) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + struct breakpoint *breakpoint = NULL; + int retval; + + LOG_DEBUG("-"); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + if (!debug_execution) { + target_free_all_working_areas(target); + esirisc_add_breakpoints(target); + esirisc_add_watchpoints(target); + } + + if (current) + address = buf_get_u32(esirisc->epc->value, 0, esirisc->epc->size); + else { + buf_set_u32(esirisc->epc->value, 0, esirisc->epc->size, address); + esirisc->epc->dirty = true; + esirisc->epc->valid = true; + } + + esirisc_restore_context(target); + + if (esirisc_has_cache(esirisc)) + esirisc_flush_caches(target); + + if (handle_breakpoints) { + breakpoint = breakpoint_find(target, address); + if (breakpoint != NULL) + esirisc_remove_breakpoint(target, breakpoint); + } + + if (step) { + esirisc_disable_interrupts(target); + esirisc_enable_step(target); + target->debug_reason = DBG_REASON_SINGLESTEP; + } else { + esirisc_disable_step(target); + esirisc_restore_interrupts(target); + target->debug_reason = DBG_REASON_NOTHALTED; + } + + esirisc_restore_hwdc(target); + + retval = esirisc_jtag_continue(jtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to resume target", target_name(target)); + return retval; + } + + register_cache_invalidate(esirisc->reg_cache); + + if (!debug_execution) { + target->state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + } else { + target->state = TARGET_DEBUG_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); + } + + return ERROR_OK; +} + +static int esirisc_resume(struct target *target, int current, target_addr_t address, + int handle_breakpoints, int debug_execution) +{ + LOG_DEBUG("-"); + + return esirisc_resume_or_step(target, current, address, + handle_breakpoints, debug_execution, false); +} + +static int esirisc_step(struct target *target, int current, target_addr_t address, + int handle_breakpoints) +{ + LOG_DEBUG("-"); + + return esirisc_resume_or_step(target, current, address, + handle_breakpoints, 0, true); +} + +static int esirisc_debug_step(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + int retval; + + LOG_DEBUG("-"); + + esirisc_disable_interrupts(target); + esirisc_enable_step(target); + + retval = esirisc_jtag_continue(jtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to resume target", target_name(target)); + return retval; + } + + retval = esirisc_wait_debug_active(esirisc, STEP_TIMEOUT); + if (retval != ERROR_OK) { + LOG_ERROR("%s: step timed out", target_name(target)); + return retval; + } + + esirisc_disable_step(target); + esirisc_restore_interrupts(target); + + return ERROR_OK; +} + +static int esirisc_debug_reset(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + int retval; + + LOG_DEBUG("-"); + + retval = esirisc_jtag_assert_reset(jtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to assert reset", target_name(target)); + return retval; + } + + retval = esirisc_jtag_deassert_reset(jtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to deassert reset", target_name(target)); + return retval; + } + + retval = esirisc_wait_debug_active(esirisc, RESET_TIMEOUT); + if (retval != ERROR_OK) { + LOG_ERROR("%s: reset timed out", target_name(target)); + return retval; + } + + return ERROR_OK; +} + +static int esirisc_debug_enable(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + int retval; + + LOG_DEBUG("-"); + + retval = esirisc_jtag_enable_debug(jtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to enable debug mode", target_name(target)); + return retval; + } + + /* + * The debug clock is inactive until the first command is sent. + * If the target is stopped, we must first issue a reset before + * attempting further communication. This also handles unpowered + * targets, which will respond with all ones and appear active. + */ + if (esirisc_jtag_is_stopped(jtag_info)) { + LOG_INFO("%s: debug clock inactive; attempting debug reset", target_name(target)); + retval = esirisc_debug_reset(target); + if (retval != ERROR_OK) + return retval; + + if (esirisc_jtag_is_stopped(jtag_info)) { + LOG_ERROR("%s: target unresponsive; giving up", target_name(target)); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +static int esirisc_debug_entry(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct breakpoint *breakpoint; + + LOG_DEBUG("-"); + + esirisc_save_context(target); + + if (esirisc_has_cache(esirisc)) + esirisc_flush_caches(target); + + if (target->debug_reason != DBG_REASON_SINGLESTEP) { + esirisc_save_interrupts(target); + + uint32_t eid = buf_get_u32(esirisc->eid->value, 0, esirisc->eid->size); + switch (eid) { + /* + * InstBreakpoint exceptions are also raised when a core is + * halted for debugging. The following is required to + * determine if a breakpoint was encountered. + */ + case EID_INST_BREAKPOINT: + breakpoint = breakpoint_find(target, + buf_get_u32(esirisc->epc->value, 0, esirisc->epc->size)); + target->debug_reason = (breakpoint != NULL) ? + DBG_REASON_BREAKPOINT : DBG_REASON_DBGRQ; + break; + + /* + * eSi-RISC treats watchpoints similarly to breakpoints, + * however GDB will not request to step over the current + * instruction when a watchpoint fires. The following is + * required to resume the target. + */ + case EID_DATA_BREAKPOINT: + esirisc_remove_watchpoints(target); + esirisc_debug_step(target); + esirisc_add_watchpoints(target); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + + default: + target->debug_reason = DBG_REASON_DBGRQ; + } + } + + return ERROR_OK; +} + +static int esirisc_poll(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + int retval; + + retval = esirisc_jtag_enable_debug(jtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to poll target", target_name(target)); + return retval; + } + + if (esirisc_jtag_is_stopped(jtag_info)) { + LOG_ERROR("%s: target has stopped; reset required", target_name(target)); + target->state = TARGET_UNKNOWN; + return ERROR_TARGET_FAILURE; + } + + if (esirisc_jtag_is_debug_active(jtag_info)) { + if (target->state == TARGET_RUNNING || target->state == TARGET_RESET) { + target->state = TARGET_HALTED; + + retval = esirisc_debug_entry(target); + if (retval != ERROR_OK) + return retval; + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + + } else if (target->state == TARGET_HALTED || target->state == TARGET_RESET) { + target->state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + } + + return ERROR_OK; +} + +static int esirisc_assert_reset(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + int retval; + + LOG_DEBUG("-"); + + if (jtag_get_reset_config() & RESET_HAS_SRST) { + jtag_add_reset(1, 1); + if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) == 0) + jtag_add_reset(0, 1); + } else { + esirisc_remove_breakpoints(target); + esirisc_remove_watchpoints(target); + + retval = esirisc_jtag_assert_reset(jtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to assert reset", target_name(target)); + return retval; + } + } + + target->state = TARGET_RESET; + + register_cache_invalidate(esirisc->reg_cache); + + return ERROR_OK; +} + +static int esirisc_reset_entry(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + uint32_t eta, epc; + int retval; + + LOG_DEBUG("-"); + + /* read exception table address */ + retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETA, &eta); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: ETA", target_name(target)); + return retval; + } + + /* read reset entry point */ + retval = esirisc_jtag_read_word(jtag_info, eta + ENTRY_RESET, &epc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read address: 0x%" TARGET_PRIxADDR, target_name(target), + (target_addr_t)epc); + return retval; + } + + /* write reset entry point */ + retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_EPC, epc); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: EPC", target_name(target)); + return retval; + } + + return ERROR_OK; +} + +static int esirisc_deassert_reset(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + int retval; + + LOG_DEBUG("-"); + + if (jtag_get_reset_config() & RESET_HAS_SRST) { + jtag_add_reset(0, 0); + + retval = esirisc_debug_enable(target); + if (retval != ERROR_OK) + return retval; + + retval = esirisc_debug_reset(target); + if (retval != ERROR_OK) + return retval; + + } else { + retval = esirisc_jtag_deassert_reset(jtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to deassert reset", target_name(target)); + return retval; + } + } + + retval = esirisc_wait_debug_active(esirisc, RESET_TIMEOUT); + if (retval != ERROR_OK) { + LOG_ERROR("%s: reset timed out", target_name(target)); + return retval; + } + + retval = esirisc_reset_entry(target); + if (retval != ERROR_OK) + return retval; + + esirisc_add_breakpoints(target); + esirisc_add_watchpoints(target); + + esirisc_restore_hwdc(target); + + if (!target->reset_halt) { + retval = esirisc_jtag_continue(jtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to resume target", target_name(target)); + return retval; + } + } + + return ERROR_OK; +} + +static int esirisc_arch_state(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + uint32_t epc = buf_get_u32(esirisc->epc->value, 0, esirisc->epc->size); + uint32_t ecas = buf_get_u32(esirisc->ecas->value, 0, esirisc->ecas->size); + uint32_t eid = buf_get_u32(esirisc->eid->value, 0, esirisc->eid->size); + uint32_t ed = buf_get_u32(esirisc->ed->value, 0, esirisc->ed->size); + + LOG_DEBUG("-"); + + const char *exception = "Unknown"; + if (eid < ARRAY_SIZE(esirisc_exceptions)) + exception = esirisc_exceptions[eid]; + + LOG_USER("target halted due to %s, exception: %s\n" + "EPC: 0x%" PRIx32 " ECAS: 0x%" PRIx32 " EID: 0x%" PRIx32 " ED: 0x%" PRIx32, + debug_reason_name(target), exception, epc, ecas, eid, ed); + + return ERROR_OK; +} + +static const char *esirisc_get_gdb_arch(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + + LOG_DEBUG("-"); + + /* + * Targets with the UNIFIED_ADDRESS_SPACE option disabled employ a + * Harvard architecture. This option is not exposed in a CSR, which + * requires additional configuration to properly interact with these + * targets in GDB (also see: `esirisc cache_arch`). + */ + if (esirisc->gdb_arch == NULL && target_was_examined(target)) + esirisc->gdb_arch = alloc_printf("esirisc:%d_bit_%d_reg_%s", + esirisc->num_bits, esirisc->num_regs, esirisc_cache_arch(esirisc)); + + return esirisc->gdb_arch; +} + +static int esirisc_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + + LOG_DEBUG("-"); + + *reg_list_size = ESIRISC_NUM_REGS; + + *reg_list = calloc(*reg_list_size, sizeof(struct reg *)); + if (*reg_list == NULL) + return ERROR_FAIL; + + if (reg_class == REG_CLASS_ALL) + for (int i = 0; i < *reg_list_size; ++i) + (*reg_list)[i] = esirisc->reg_cache->reg_list + i; + else { + for (int i = 0; i < esirisc->num_regs; ++i) + (*reg_list)[i] = esirisc->reg_cache->reg_list + i; + + (*reg_list)[ESIRISC_PC] = esirisc->reg_cache->reg_list + ESIRISC_PC; + (*reg_list)[ESIRISC_CAS] = esirisc->reg_cache->reg_list + ESIRISC_CAS; + } + + return ERROR_OK; +} + +static int esirisc_read_reg(struct reg *reg) +{ + struct esirisc_reg *reg_info = reg->arch_info; + struct esirisc_common *esirisc = reg_info->esirisc; + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + struct target *target = esirisc->target; + uint32_t data; + + LOG_DEBUG("-"); + + int retval = esirisc_jtag_read_reg(jtag_info, reg->number, &data); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read register: %s", target_name(target), reg->name); + return retval; + } + + buf_set_u32(reg->value, 0, reg->size, data); + reg->dirty = false; + reg->valid = true; + + return ERROR_OK; +} + +static int esirisc_write_reg(struct reg *reg) +{ + struct esirisc_reg *reg_info = reg->arch_info; + struct esirisc_common *esirisc = reg_info->esirisc; + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + struct target *target = esirisc->target; + uint32_t data = buf_get_u32(reg->value, 0, reg->size); + + LOG_DEBUG("-"); + + int retval = esirisc_jtag_write_reg(jtag_info, reg->number, data); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write register: %s", target_name(target), reg->name); + return retval; + } + + reg->dirty = false; + reg->valid = true; + + return ERROR_OK; +} + +static int esirisc_read_csr(struct reg *reg) +{ + struct esirisc_reg *reg_info = reg->arch_info; + struct esirisc_common *esirisc = reg_info->esirisc; + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + struct target *target = esirisc->target; + uint32_t data; + + LOG_DEBUG("-"); + + int retval = esirisc_jtag_read_csr(jtag_info, reg_info->bank, reg_info->csr, &data); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: %s", target_name(target), reg->name); + return retval; + } + + buf_set_u32(reg->value, 0, reg->size, data); + reg->dirty = false; + reg->valid = true; + + return ERROR_OK; +} + +static int esirisc_write_csr(struct reg *reg) +{ + struct esirisc_reg *reg_info = reg->arch_info; + struct esirisc_common *esirisc = reg_info->esirisc; + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + struct target *target = esirisc->target; + uint32_t data = buf_get_u32(reg->value, 0, reg->size); + + LOG_DEBUG("-"); + + int retval = esirisc_jtag_write_csr(jtag_info, reg_info->bank, reg_info->csr, data); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to write CSR: %s", target_name(target), reg->name); + return retval; + } + + reg->dirty = false; + reg->valid = true; + + return ERROR_OK; +} + +static int esirisc_get_reg(struct reg *reg) +{ + struct esirisc_reg *reg_info = reg->arch_info; + struct esirisc_common *esirisc = reg_info->esirisc; + struct target *target = esirisc->target; + + LOG_DEBUG("-"); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + return reg_info->read(reg); +} + +static int esirisc_set_reg(struct reg *reg, uint8_t *buf) +{ + struct esirisc_reg *reg_info = reg->arch_info; + struct esirisc_common *esirisc = reg_info->esirisc; + struct target *target = esirisc->target; + uint32_t value = buf_get_u32(buf, 0, reg->size); + + LOG_DEBUG("-"); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + buf_set_u32(reg->value, 0, reg->size, value); + reg->dirty = true; + reg->valid = true; + + return ERROR_OK; +} + +static const struct reg_arch_type esirisc_reg_type = { + .get = esirisc_get_reg, + .set = esirisc_set_reg, +}; + +static struct reg_cache *esirisc_build_reg_cache(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); + struct reg_cache *cache = malloc(sizeof(struct reg_cache)); + struct reg *reg_list = calloc(ESIRISC_NUM_REGS, sizeof(struct reg)); + + LOG_DEBUG("-"); + + cache->name = "eSi-RISC registers"; + cache->next = NULL; + cache->reg_list = reg_list; + cache->num_regs = ESIRISC_NUM_REGS; + (*cache_p) = cache; + + esirisc->reg_cache = cache; + esirisc->epc = reg_list + ESIRISC_EPC; + esirisc->ecas = reg_list + ESIRISC_ECAS; + esirisc->eid = reg_list + ESIRISC_EID; + esirisc->ed = reg_list + ESIRISC_ED; + + for (int i = 0; i < esirisc->num_regs; ++i) { + struct reg *reg = reg_list + esirisc_regs[i].number; + struct esirisc_reg *reg_info = calloc(1, sizeof(struct esirisc_reg)); + + reg->name = esirisc_regs[i].name; + reg->number = esirisc_regs[i].number; + reg->value = calloc(1, DIV_ROUND_UP(esirisc->num_bits, 8)); + reg->size = esirisc->num_bits; + reg->reg_data_type = calloc(1, sizeof(struct reg_data_type)); + reg->reg_data_type->type = esirisc_regs[i].type; + reg->group = esirisc_regs[i].group; + reg_info->esirisc = esirisc; + reg_info->read = esirisc_read_reg; + reg_info->write = esirisc_write_reg; + reg->arch_info = reg_info; + reg->type = &esirisc_reg_type; + reg->exist = true; + } + + for (size_t i = 0; i < ARRAY_SIZE(esirisc_csrs); ++i) { + struct reg *reg = reg_list + esirisc_csrs[i].number; + struct esirisc_reg *reg_info = calloc(1, sizeof(struct esirisc_reg)); + + reg->name = esirisc_csrs[i].name; + reg->number = esirisc_csrs[i].number; + reg->value = calloc(1, DIV_ROUND_UP(esirisc->num_bits, 8)); + reg->size = esirisc->num_bits; + reg->reg_data_type = calloc(1, sizeof(struct reg_data_type)); + reg->reg_data_type->type = esirisc_csrs[i].type; + reg->group = esirisc_csrs[i].group; + reg_info->esirisc = esirisc; + reg_info->bank = esirisc_csrs[i].bank; + reg_info->csr = esirisc_csrs[i].csr; + reg_info->read = esirisc_read_csr; + reg_info->write = esirisc_write_csr; + reg->arch_info = reg_info; + reg->type = &esirisc_reg_type; + reg->exist = true; + } + + return cache; +} + +static int esirisc_identify(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + uint32_t csr; + int retval; + + LOG_DEBUG("-"); + + retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_ARCH0, &csr); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: ARCH0", target_name(target)); + return retval; + } + + esirisc->num_bits = (csr >> 0) & 0x3f; /* ARCH0.B */ + esirisc->num_regs = (csr >> 10) & 0x3f; /* ARCH0.R */ + + retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_MEM, &csr); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: MEM", target_name(target)); + return retval; + } + + target->endianness = (csr & 1<<0) ? /* MEM.E */ + TARGET_BIG_ENDIAN : TARGET_LITTLE_ENDIAN; + + retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_IC, &csr); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: IC", target_name(target)); + return retval; + } + + esirisc->has_icache = !!(csr & 1<<0); /* IC.E */ + + retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_DC, &csr); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: DC", target_name(target)); + return retval; + } + + esirisc->has_dcache = !!(csr & 1<<0); /* DC.E */ + + retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_DBG, &csr); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to read CSR: DBG", target_name(target)); + return retval; + } + + esirisc->num_breakpoints = (csr >> 7) & 0xf; /* DBG.BP */ + esirisc->num_watchpoints = (csr >> 12) & 0xf; /* DBG.WP */ + + return ERROR_OK; +} + +static int esirisc_target_create(struct target *target, Jim_Interp *interp) +{ + struct jtag_tap *tap = target->tap; + struct esirisc_common *esirisc; + + if (tap == NULL) + return ERROR_FAIL; + + if (tap->ir_length != INSTR_LENGTH) { + LOG_ERROR("%s: invalid IR length; expected %d", target_name(target), + INSTR_LENGTH); + return ERROR_FAIL; + } + + esirisc = calloc(1, sizeof(struct esirisc_common)); + if (esirisc == NULL) + return ERROR_FAIL; + + esirisc->target = target; + esirisc->jtag_info.tap = tap; + target->arch_info = esirisc; + + return ERROR_OK; +} + +static int esirisc_init_target(struct command_context *cmd_ctx, struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + + /* trap reset, error, and debug exceptions */ + esirisc->hwdc_save = HWDC_R | HWDC_E | HWDC_D; + + return ERROR_OK; +} + +static int esirisc_examine(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct esirisc_jtag *jtag_info = &esirisc->jtag_info; + int retval; + + LOG_DEBUG("-"); + + if (!target_was_examined(target)) { + retval = esirisc_debug_enable(target); + if (retval != ERROR_OK) + return retval; + + /* + * In order to identify the target we must first halt the core. + * We quietly resume once identification has completed for those + * targets that were running when target_examine was called. + */ + if (esirisc_jtag_is_debug_active(jtag_info)) { + if (target->state == TARGET_UNKNOWN) + target->debug_reason = DBG_REASON_DBGRQ; + + target->state = TARGET_HALTED; + } else { + retval = esirisc_jtag_break(jtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to halt target", target_name(target)); + return retval; + } + + target->state = TARGET_RUNNING; + } + + retval = esirisc_identify(target); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to identify target", target_name(target)); + return retval; + } + + esirisc_build_reg_cache(target); + + esirisc_remove_breakpoints(target); + esirisc_remove_watchpoints(target); + + esirisc_disable_step(target); + esirisc_restore_hwdc(target); + + if (target->state == TARGET_HALTED) + esirisc_save_interrupts(target); + else { + retval = esirisc_jtag_continue(jtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("%s: failed to resume target", target_name(target)); + return retval; + } + } + + target_set_examined(target); + + LOG_INFO("%s: %d bit, %d registers, %s%s%s", target_name(target), + esirisc->num_bits, esirisc->num_regs, + target_endianness(target), + esirisc->has_icache ? ", icache" : "", + esirisc->has_dcache ? ", dcache" : ""); + + LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints", target_name(target), + esirisc->num_breakpoints, esirisc->num_watchpoints); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_esirisc_cache_arch_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct esirisc_common *esirisc = target_to_esirisc(target); + + if (CMD_ARGC > 0) { + if (strcmp(*CMD_ARGV, "harvard") == 0) + esirisc->cache_arch = ESIRISC_CACHE_HARVARD; + else if (strcmp(*CMD_ARGV, "von_neumann") == 0) + esirisc->cache_arch = ESIRISC_CACHE_VON_NEUMANN; + else { + LOG_ERROR("invalid cache_arch: %s", *CMD_ARGV); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } + + command_print(CMD_CTX, "esirisc cache_arch %s", esirisc_cache_arch(esirisc)); + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_esirisc_flush_caches_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct esirisc_common *esirisc = target_to_esirisc(target); + int retval; + + if (!esirisc_has_cache(esirisc)) { + LOG_ERROR("target does not support caching"); + return ERROR_FAIL; + } + + retval = esirisc_flush_caches(target); + + command_print(CMD_CTX, "cache flush %s", + (retval == ERROR_OK) ? "successful" : "failed"); + + return retval; +} + +static const struct { + const char *name; + int mask; +} esirisc_hwdc_masks[] = { + { "reset", HWDC_R }, + { "interrupt", HWDC_I }, + { "syscall", HWDC_S }, + { "error", HWDC_E }, + { "debug", HWDC_D }, +}; + +static int esirisc_find_hwdc_mask(const char *name) +{ + for (size_t i = 0; i < ARRAY_SIZE(esirisc_hwdc_masks); ++i) + if (strcmp(esirisc_hwdc_masks[i].name, name) == 0) + return esirisc_hwdc_masks[i].mask; + + return -1; +} + +COMMAND_HANDLER(handle_esirisc_hwdc_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct esirisc_common *esirisc = target_to_esirisc(target); + + if (CMD_ARGC > 0) { + if (strcmp(CMD_ARGV[0], "all") == 0) + esirisc->hwdc_save = HWDC_R | HWDC_I | HWDC_S | HWDC_E | HWDC_D; + else { + esirisc->hwdc_save = 0; + if (strcmp(CMD_ARGV[0], "none") != 0) { + while (CMD_ARGC-- > 0) { + int mask = esirisc_find_hwdc_mask(CMD_ARGV[CMD_ARGC]); + if (mask < 0) { + LOG_ERROR("invalid mask: %s", CMD_ARGV[CMD_ARGC]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + esirisc->hwdc_save |= mask; + } + } + } + } + + for (size_t i = 0; i < ARRAY_SIZE(esirisc_hwdc_masks); ++i) + command_print(CMD_CTX, "%9s: %s", esirisc_hwdc_masks[i].name, + (esirisc->hwdc_save & esirisc_hwdc_masks[i].mask) ? "enabled" : "disabled"); + + return ERROR_OK; +} + +static const struct command_registration esirisc_exec_command_handlers[] = { + { + .name = "cache_arch", + .handler = handle_esirisc_cache_arch_command, + .mode = COMMAND_ANY, + .help = "configure cache architecture", + .usage = "['harvard'|'von_neumann']", + }, + { + .name = "flush_caches", + .handler = handle_esirisc_flush_caches_command, + .mode = COMMAND_EXEC, + .help = "flush instruction and data caches", + .usage = "", + }, + { + .name = "hwdc", + .handler = handle_esirisc_hwdc_command, + .mode = COMMAND_ANY, + .help = "configure hardware debug control", + .usage = "['all'|'none'|mask ...]", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration esirisc_command_handlers[] = { + { + .name = "esirisc", + .mode = COMMAND_ANY, + .help = "eSi-RISC command group", + .usage = "", + .chain = esirisc_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct target_type esirisc_target = { + .name = "esirisc", + + .poll = esirisc_poll, + .arch_state = esirisc_arch_state, + + .halt = esirisc_halt, + .resume = esirisc_resume, + .step = esirisc_step, + + .assert_reset = esirisc_assert_reset, + .deassert_reset = esirisc_deassert_reset, + + .get_gdb_arch = esirisc_get_gdb_arch, + .get_gdb_reg_list = esirisc_get_gdb_reg_list, + + .read_memory = esirisc_read_memory, + .write_memory = esirisc_write_memory, + .checksum_memory = esirisc_checksum_memory, + + .add_breakpoint = esirisc_add_breakpoint, + .remove_breakpoint = esirisc_remove_breakpoint, + .add_watchpoint = esirisc_add_watchpoint, + .remove_watchpoint = esirisc_remove_watchpoint, + + .commands = esirisc_command_handlers, + + .target_create = esirisc_target_create, + .init_target = esirisc_init_target, + .examine = esirisc_examine, +}; diff --git a/src/target/esirisc.h b/src/target/esirisc.h new file mode 100644 index 000000000..bb50652aa --- /dev/null +++ b/src/target/esirisc.h @@ -0,0 +1,129 @@ +/*************************************************************************** + * Copyright (C) 2018 by Square, Inc. * + * Steven Stallion * + * James Zhao * + * * + * 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 . * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESIRISC_H +#define OPENOCD_TARGET_ESIRISC_H + +#include +#include +#include + +#include "esirisc_jtag.h" +#include "esirisc_regs.h" + +#define MAX_BREAKPOINTS 8 +#define MAX_WATCHPOINTS 8 + +/* Exception IDs */ +#define EID_RESET 0x00 +#define EID_HARDWARE_FAILURE 0x01 +#define EID_NMI 0x02 +#define EID_INST_BREAKPOINT 0x03 +#define EID_DATA_BREAKPOINT 0x04 +#define EID_UNSUPPORTED 0x05 +#define EID_PRIVILEGE_VIOLATION 0x06 +#define EID_INST_BUS_ERROR 0x07 +#define EID_DATA_BUS_ERROR 0x08 +#define EID_ALIGNMENT_ERROR 0x09 +#define EID_ARITHMETIC_ERROR 0x0a +#define EID_SYSTEM_CALL 0x0b +#define EID_MEMORY_MANAGEMENT 0x0c +#define EID_UNRECOVERABLE 0x0d +#define EID_INTERRUPTn 0x20 + +/* Exception Entry Points */ +#define ENTRY_RESET 0x00 +#define ENTRY_UNRECOVERABLE 0x01 +#define ENTRY_HARDWARE_FAILURE 0x02 +#define ENTRY_RUNTIME 0x03 +#define ENTRY_MEMORY 0x04 +#define ENTRY_SYSCALL 0x05 +#define ENTRY_DEBUG 0x06 +#define ENTRY_NMI 0x07 +#define ENTRY_INTERRUPTn 0x08 + +/* Hardware Debug Control */ +#define HWDC_R (1<<4) /* Reset & Hardware Failure */ +#define HWDC_I (1<<3) /* Interrupts */ +#define HWDC_S (1<<2) /* System Calls */ +#define HWDC_E (1<<1) /* Program Errors */ +#define HWDC_D (1<<0) /* Debug Exceptions */ + +enum esirisc_cache { + ESIRISC_CACHE_VON_NEUMANN, + ESIRISC_CACHE_HARVARD, +}; + +struct esirisc_common { + struct target *target; + struct esirisc_jtag jtag_info; + enum esirisc_cache cache_arch; + char *gdb_arch; + + struct reg_cache *reg_cache; + struct reg *epc; + struct reg *ecas; + struct reg *eid; + struct reg *ed; + uint32_t etc_save; + uint32_t hwdc_save; + + int num_bits; + int num_regs; + bool has_icache; + bool has_dcache; + int num_breakpoints; + int num_watchpoints; + + struct breakpoint *breakpoints_p[MAX_BREAKPOINTS]; + struct watchpoint *watchpoints_p[MAX_WATCHPOINTS]; +}; + +union esirisc_memory { + uint32_t word; + uint16_t hword; + uint8_t byte; +}; + +struct esirisc_reg { + struct esirisc_common *esirisc; + + uint8_t bank; + uint8_t csr; + + int (*read)(struct reg *reg); + int (*write)(struct reg *reg); +}; + +static inline struct esirisc_common *target_to_esirisc(struct target *target) +{ + return (struct esirisc_common *)target->arch_info; +} + +static inline char *esirisc_cache_arch(struct esirisc_common *esirisc) +{ + return esirisc->cache_arch == ESIRISC_CACHE_HARVARD ? "harvard" : "von_neumann"; +} + +static inline bool esirisc_has_cache(struct esirisc_common *esirisc) +{ + return esirisc->has_icache || esirisc->has_dcache; +} + +#endif /* OPENOCD_TARGET_ESIRISC_H */ diff --git a/src/target/esirisc_jtag.c b/src/target/esirisc_jtag.c new file mode 100644 index 000000000..8ab47fa8f --- /dev/null +++ b/src/target/esirisc_jtag.c @@ -0,0 +1,514 @@ +/*************************************************************************** + * Copyright (C) 2018 by Square, Inc. * + * Steven Stallion * + * James Zhao * + * * + * 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 . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include "esirisc_jtag.h" + +static void esirisc_jtag_set_instr(struct esirisc_jtag *jtag_info, uint32_t new_instr) +{ + struct jtag_tap *tap = jtag_info->tap; + + if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { + struct scan_field field; + uint8_t t[4]; + + field.num_bits = tap->ir_length; + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = NULL; + + jtag_add_ir_scan(tap, &field, TAP_IDLE); + } +} + +/* + * The data register is latched every 8 bits while in the Shift-DR state + * (Update-DR is not supported). This necessitates prepending padding + * bits to ensure data is aligned when multiple TAPs are present. + */ +static int esirisc_jtag_get_padding(void) +{ + int padding = 0; + int bypass_devices = 0; + + for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; + tap = jtag_tap_next_enabled(tap)) + if (tap->bypass) + bypass_devices++; + + int num_bits = bypass_devices % 8; + if (num_bits > 0) + padding = 8 - num_bits; + + return padding; +} + +static int esirisc_jtag_count_bits(int num_fields, struct scan_field *fields) +{ + int bit_count = 0; + + for (int i = 0; i < num_fields; ++i) + bit_count += fields[i].num_bits; + + return bit_count; +} + +/* + * Data received from the target will be byte-stuffed if it contains + * either the pad byte (0xAA) or stuffing marker (0x55). Buffers should + * be sized twice the expected length to account for stuffing overhead. + */ +static void esirisc_jtag_unstuff(uint8_t *data, size_t len) +{ + uint8_t *r, *w; + uint8_t *end; + + r = w = data; + end = data + len; + while (r < end) { + if (*r == STUFF_MARKER) { + r++; /* skip stuffing marker */ + assert(r < end); + *w++ = *r++ ^ STUFF_MARKER; + } else + *w++ = *r++; + } +} + +/* + * The eSi-Debug protocol defines a byte-oriented command/response + * channel that operates over serial or JTAG. While not strictly + * required, separate DR scans are used for sending and receiving data. + * This allows the TAP to recover gracefully if the byte stream is + * corrupted at the expense of sending additional padding bits. + */ + +static int esirisc_jtag_send(struct esirisc_jtag *jtag_info, uint8_t command, + int num_out_fields, struct scan_field *out_fields) +{ + int num_fields = 2 + num_out_fields; + struct scan_field *fields = cmd_queue_alloc(num_fields * sizeof(struct scan_field)); + + esirisc_jtag_set_instr(jtag_info, INSTR_DEBUG); + + fields[0].num_bits = esirisc_jtag_get_padding(); + fields[0].out_value = NULL; + fields[0].in_value = NULL; + + fields[1].num_bits = 8; + fields[1].out_value = &command; + fields[1].in_value = NULL; + + /* append command data */ + for (int i = 0; i < num_out_fields; ++i) + jtag_scan_field_clone(&fields[2+i], &out_fields[i]); + + jtag_add_dr_scan(jtag_info->tap, num_fields, fields, TAP_IDLE); + + return jtag_execute_queue(); +} + +static int esirisc_jtag_recv(struct esirisc_jtag *jtag_info, + int num_in_fields, struct scan_field *in_fields) +{ + int num_in_bits = esirisc_jtag_count_bits(num_in_fields, in_fields); + int num_in_bytes = DIV_ROUND_UP(num_in_bits, 8); + + struct scan_field fields[3]; + uint8_t r[num_in_bytes * 2]; + + esirisc_jtag_set_instr(jtag_info, INSTR_DEBUG); + + fields[0].num_bits = esirisc_jtag_get_padding() + 1; + fields[0].out_value = NULL; + fields[0].in_value = NULL; + + fields[1].num_bits = 8; + fields[1].out_value = NULL; + fields[1].in_value = &jtag_info->status; + + fields[2].num_bits = num_in_bits * 2; + fields[2].out_value = NULL; + fields[2].in_value = r; + + jtag_add_dr_scan(jtag_info->tap, ARRAY_SIZE(fields), fields, TAP_IDLE); + + int retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + /* unstuff response data and write back to caller */ + if (num_in_fields > 0) { + esirisc_jtag_unstuff(r, ARRAY_SIZE(r)); + + int bit_count = 0; + for (int i = 0; i < num_in_fields; ++i) { + buf_set_buf(r, bit_count, in_fields[i].in_value, 0, in_fields[i].num_bits); + bit_count += in_fields[i].num_bits; + } + } + + return ERROR_OK; +} + +static int esirisc_jtag_check_status(struct esirisc_jtag *jtag_info) +{ + uint8_t eid = esirisc_jtag_get_eid(jtag_info); + if (eid != EID_NONE) { + LOG_ERROR("esirisc_jtag: bad status: 0x%02" PRIx32 " (DA: %" PRId32 ", " + "S: %" PRId32 ", EID: 0x%02" PRIx32 ")", + jtag_info->status, esirisc_jtag_is_debug_active(jtag_info), + esirisc_jtag_is_stopped(jtag_info), eid); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int esirisc_jtag_send_and_recv(struct esirisc_jtag *jtag_info, uint8_t command, + int num_out_fields, struct scan_field *out_fields, + int num_in_fields, struct scan_field *in_fields) +{ + int retval; + + jtag_info->status = 0; /* clear status */ + + retval = esirisc_jtag_send(jtag_info, command, num_out_fields, out_fields); + if (retval != ERROR_OK) { + LOG_ERROR("esirisc_jtag: send failed (command: 0x%02" PRIx32 ")", command); + return ERROR_FAIL; + } + + retval = esirisc_jtag_recv(jtag_info, num_in_fields, in_fields); + if (retval != ERROR_OK) { + LOG_ERROR("esirisc_jtag: recv failed (command: 0x%02" PRIx32 ")", command); + return ERROR_FAIL; + } + + return esirisc_jtag_check_status(jtag_info); +} + +/* + * Status is automatically updated after each command completes; + * these functions make each field available to the caller. + */ + +bool esirisc_jtag_is_debug_active(struct esirisc_jtag *jtag_info) +{ + return !!(jtag_info->status & 1<<7); /* DA */ +} + +bool esirisc_jtag_is_stopped(struct esirisc_jtag *jtag_info) +{ + return !!(jtag_info->status & 1<<6); /* S */ +} + +uint8_t esirisc_jtag_get_eid(struct esirisc_jtag *jtag_info) +{ + return jtag_info->status & 0x3f; /* EID */ +} + +/* + * Most commands manipulate target data (eg. memory and registers); each + * command returns a status byte that indicates success. Commands must + * transmit multibyte values in big-endian order, however response + * values are in little-endian order. Target endianness does not have an + * effect on this ordering. + */ + +int esirisc_jtag_read_byte(struct esirisc_jtag *jtag_info, uint32_t address, uint8_t *data) +{ + struct scan_field out_fields[1]; + uint8_t a[4]; + + out_fields[0].num_bits = 32; + out_fields[0].out_value = a; + h_u32_to_be(a, address); + out_fields[0].in_value = NULL; + + struct scan_field in_fields[1]; + uint8_t d[1]; + + in_fields[0].num_bits = 8; + in_fields[0].out_value = NULL; + in_fields[0].in_value = d; + + int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_BYTE, + ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields); + if (retval != ERROR_OK) + return retval; + + *data = *d; + + return ERROR_OK; +} + +int esirisc_jtag_read_hword(struct esirisc_jtag *jtag_info, uint32_t address, uint16_t *data) +{ + struct scan_field out_fields[1]; + uint8_t a[4]; + + out_fields[0].num_bits = 32; + out_fields[0].out_value = a; + h_u32_to_be(a, address); + out_fields[0].in_value = NULL; + + struct scan_field in_fields[1]; + uint8_t d[2]; + + in_fields[0].num_bits = 16; + in_fields[0].out_value = NULL; + in_fields[0].in_value = d; + + int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_HWORD, + ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields); + if (retval != ERROR_OK) + return retval; + + *data = le_to_h_u16(d); + + return ERROR_OK; +} + +int esirisc_jtag_read_word(struct esirisc_jtag *jtag_info, uint32_t address, uint32_t *data) +{ + struct scan_field out_fields[1]; + uint8_t a[4]; + + out_fields[0].num_bits = 32; + out_fields[0].out_value = a; + h_u32_to_be(a, address); + out_fields[0].in_value = NULL; + + struct scan_field in_fields[1]; + uint8_t d[4]; + + in_fields[0].num_bits = 32; + in_fields[0].out_value = NULL; + in_fields[0].in_value = d; + + int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_WORD, + ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields); + if (retval != ERROR_OK) + return retval; + + *data = le_to_h_u32(d); + + return ERROR_OK; +} + +int esirisc_jtag_write_byte(struct esirisc_jtag *jtag_info, uint32_t address, uint8_t data) +{ + struct scan_field out_fields[2]; + uint8_t a[4]; + + out_fields[0].num_bits = 32; + out_fields[0].out_value = a; + h_u32_to_be(a, address); + out_fields[0].in_value = NULL; + + out_fields[1].num_bits = 8; + out_fields[1].out_value = &data; + out_fields[1].in_value = NULL; + + return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_BYTE, + ARRAY_SIZE(out_fields), out_fields, 0, NULL); +} + +int esirisc_jtag_write_hword(struct esirisc_jtag *jtag_info, uint32_t address, uint16_t data) +{ + struct scan_field out_fields[2]; + uint8_t a[4], d[2]; + + out_fields[0].num_bits = 32; + out_fields[0].out_value = a; + h_u32_to_be(a, address); + out_fields[0].in_value = NULL; + + out_fields[1].num_bits = 16; + out_fields[1].out_value = d; + h_u16_to_be(d, data); + out_fields[1].in_value = NULL; + + return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_HWORD, + ARRAY_SIZE(out_fields), out_fields, 0, NULL); +} + +int esirisc_jtag_write_word(struct esirisc_jtag *jtag_info, uint32_t address, uint32_t data) +{ + struct scan_field out_fields[2]; + uint8_t a[4], d[4]; + + out_fields[0].num_bits = 32; + out_fields[0].out_value = a; + h_u32_to_be(a, address); + out_fields[0].in_value = NULL; + + out_fields[1].num_bits = 32; + out_fields[1].out_value = d; + h_u32_to_be(d, data); + out_fields[1].in_value = NULL; + + return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_WORD, + ARRAY_SIZE(out_fields), out_fields, 0, NULL); +} + +int esirisc_jtag_read_reg(struct esirisc_jtag *jtag_info, uint8_t reg, uint32_t *data) +{ + struct scan_field out_fields[1]; + + out_fields[0].num_bits = 8; + out_fields[0].out_value = ® + out_fields[0].in_value = NULL; + + struct scan_field in_fields[1]; + uint8_t d[4]; + + in_fields[0].num_bits = 32; + in_fields[0].out_value = NULL; + in_fields[0].in_value = d; + + int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_REG, + ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields); + if (retval != ERROR_OK) + return retval; + + *data = le_to_h_u32(d); + + return ERROR_OK; +} + +int esirisc_jtag_write_reg(struct esirisc_jtag *jtag_info, uint8_t reg, uint32_t data) +{ + struct scan_field out_fields[2]; + uint8_t d[4]; + + out_fields[0].num_bits = 8; + out_fields[0].out_value = ® + out_fields[0].in_value = NULL; + + out_fields[1].num_bits = 32; + out_fields[1].out_value = d; + h_u32_to_be(d, data); + out_fields[1].in_value = NULL; + + return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_REG, + ARRAY_SIZE(out_fields), out_fields, 0, NULL); +} + +int esirisc_jtag_read_csr(struct esirisc_jtag *jtag_info, uint8_t bank, uint8_t csr, uint32_t *data) +{ + struct scan_field out_fields[1]; + uint8_t c[2]; + + out_fields[0].num_bits = 16; + out_fields[0].out_value = c; + h_u16_to_be(c, (csr << 5) | bank); + out_fields[0].in_value = NULL; + + struct scan_field in_fields[1]; + uint8_t d[4]; + + in_fields[0].num_bits = 32; + in_fields[0].out_value = NULL; + in_fields[0].in_value = d; + + int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_CSR, + ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields); + if (retval != ERROR_OK) + return retval; + + *data = le_to_h_u32(d); + + return ERROR_OK; +} + +int esirisc_jtag_write_csr(struct esirisc_jtag *jtag_info, uint8_t bank, uint8_t csr, uint32_t data) +{ + struct scan_field out_fields[2]; + uint8_t c[2], d[4]; + + out_fields[0].num_bits = 16; + out_fields[0].out_value = c; + h_u16_to_be(c, (csr << 5) | bank); + out_fields[0].in_value = NULL; + + out_fields[1].num_bits = 32; + out_fields[1].out_value = d; + h_u32_to_be(d, data); + out_fields[1].in_value = NULL; + + return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_CSR, + ARRAY_SIZE(out_fields), out_fields, 0, NULL); +} + +/* + * Control commands affect CPU operation; these commands send no data + * and return a status byte. + */ + +static inline int esirisc_jtag_send_ctrl(struct esirisc_jtag *jtag_info, uint8_t command) +{ + return esirisc_jtag_send_and_recv(jtag_info, command, 0, NULL, 0, NULL); +} + +int esirisc_jtag_enable_debug(struct esirisc_jtag *jtag_info) +{ + return esirisc_jtag_send_ctrl(jtag_info, DEBUG_ENABLE_DEBUG); +} + +int esirisc_jtag_disable_debug(struct esirisc_jtag *jtag_info) +{ + return esirisc_jtag_send_ctrl(jtag_info, DEBUG_DISABLE_DEBUG); +} + +int esirisc_jtag_assert_reset(struct esirisc_jtag *jtag_info) +{ + return esirisc_jtag_send_ctrl(jtag_info, DEBUG_ASSERT_RESET); +} + +int esirisc_jtag_deassert_reset(struct esirisc_jtag *jtag_info) +{ + return esirisc_jtag_send_ctrl(jtag_info, DEBUG_DEASSERT_RESET); +} + +int esirisc_jtag_break(struct esirisc_jtag *jtag_info) +{ + return esirisc_jtag_send_ctrl(jtag_info, DEBUG_BREAK); +} + +int esirisc_jtag_continue(struct esirisc_jtag *jtag_info) +{ + return esirisc_jtag_send_ctrl(jtag_info, DEBUG_CONTINUE); +} + +int esirisc_jtag_flush_caches(struct esirisc_jtag *jtag_info) +{ + return esirisc_jtag_send_ctrl(jtag_info, DEBUG_FLUSH_CACHES); +} diff --git a/src/target/esirisc_jtag.h b/src/target/esirisc_jtag.h new file mode 100644 index 000000000..8189ddc6c --- /dev/null +++ b/src/target/esirisc_jtag.h @@ -0,0 +1,104 @@ +/*************************************************************************** + * Copyright (C) 2018 by Square, Inc. * + * Steven Stallion * + * James Zhao * + * * + * 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 . * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESIRISC_JTAG_H +#define OPENOCD_TARGET_ESIRISC_JTAG_H + +#include + +/* TAP Instructions */ +#define INSTR_IDCODE 0x8 +#define INSTR_DEBUG 0x9 +#define INSTR_BYPASS 0xf +#define INSTR_LENGTH 4 + +/* eSi-Debug Commands */ +#define DEBUG_NOP 0x00 +#define DEBUG_READ_BYTE 0x10 +#define DEBUG_READ_HWORD 0x20 +#define DEBUG_READ_WORD 0x30 +#define DEBUG_WRITE_BYTE 0x60 +#define DEBUG_WRITE_HWORD 0x70 +#define DEBUG_WRITE_WORD 0x80 +#define DEBUG_READ_REG 0xb0 +#define DEBUG_WRITE_REG 0xc0 +#define DEBUG_READ_CSR 0xd0 +#define DEBUG_WRITE_CSR 0xe0 +#define DEBUG_ENABLE_DEBUG 0xf0 +#define DEBUG_DISABLE_DEBUG 0xf2 +#define DEBUG_ASSERT_RESET 0xf4 +#define DEBUG_DEASSERT_RESET 0xf6 +#define DEBUG_BREAK 0xf8 +#define DEBUG_CONTINUE 0xfa +#define DEBUG_FLUSH_CACHES 0xfc + +/* Exception IDs */ +#define EID_OVERFLOW 0x3d +#define EID_CANT_DEBUG 0x3e +#define EID_NONE 0x3f + +/* Byte Stuffing */ +#define STUFF_MARKER 0x55 +#define PAD_BYTE 0xaa + +struct esirisc_jtag { + struct jtag_tap *tap; + uint8_t status; +}; + +bool esirisc_jtag_is_debug_active(struct esirisc_jtag *jtag_info); +bool esirisc_jtag_is_stopped(struct esirisc_jtag *jtag_info); +uint8_t esirisc_jtag_get_eid(struct esirisc_jtag *jtag_info); + +int esirisc_jtag_read_byte(struct esirisc_jtag *jtag_info, + uint32_t address, uint8_t *data); +int esirisc_jtag_read_hword(struct esirisc_jtag *jtag_info, + uint32_t address, uint16_t *data); +int esirisc_jtag_read_word(struct esirisc_jtag *jtag_info, + uint32_t address, uint32_t *data); + +int esirisc_jtag_write_byte(struct esirisc_jtag *jtag_info, + uint32_t address, uint8_t data); +int esirisc_jtag_write_hword(struct esirisc_jtag *jtag_info, + uint32_t address, uint16_t data); +int esirisc_jtag_write_word(struct esirisc_jtag *jtag_info, + uint32_t address, uint32_t data); + +int esirisc_jtag_read_reg(struct esirisc_jtag *jtag_info, + uint8_t reg, uint32_t *data); +int esirisc_jtag_write_reg(struct esirisc_jtag *jtag_info, + uint8_t reg, uint32_t data); + +int esirisc_jtag_read_csr(struct esirisc_jtag *jtag_info, + uint8_t bank, uint8_t csr, uint32_t *data); +int esirisc_jtag_write_csr(struct esirisc_jtag *jtag_info, + uint8_t bank, uint8_t csr, uint32_t data); + +int esirisc_jtag_enable_debug(struct esirisc_jtag *jtag_info); +int esirisc_jtag_disable_debug(struct esirisc_jtag *jtag_info); + +int esirisc_jtag_assert_reset(struct esirisc_jtag *jtag_info); +int esirisc_jtag_deassert_reset(struct esirisc_jtag *jtag_info); + +int esirisc_jtag_break(struct esirisc_jtag *jtag_info); +int esirisc_jtag_continue(struct esirisc_jtag *jtag_info); + +int esirisc_jtag_flush_caches(struct esirisc_jtag *jtag_info); + +#endif /* OPENOCD_TARGET_ESIRISC_JTAG_H */ diff --git a/src/target/esirisc_regs.h b/src/target/esirisc_regs.h new file mode 100644 index 000000000..ad3385819 --- /dev/null +++ b/src/target/esirisc_regs.h @@ -0,0 +1,184 @@ +/*************************************************************************** + * Copyright (C) 2018 by Square, Inc. * + * Steven Stallion * + * James Zhao * + * * + * 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 . * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESIRISC_REGS_H +#define OPENOCD_TARGET_ESIRISC_REGS_H + +enum esirisc_reg_num { + ESIRISC_SP, + ESIRISC_RA, + ESIRISC_R2, + ESIRISC_R3, + ESIRISC_R4, + ESIRISC_R5, + ESIRISC_R6, + ESIRISC_R7, + ESIRISC_R8, + ESIRISC_R9, + ESIRISC_R10, + ESIRISC_R11, + ESIRISC_R12, + ESIRISC_R13, + ESIRISC_R14, + ESIRISC_R15, + ESIRISC_R16, + ESIRISC_R17, + ESIRISC_R18, + ESIRISC_R19, + ESIRISC_R20, + ESIRISC_R21, + ESIRISC_R22, + ESIRISC_R23, + ESIRISC_R24, + ESIRISC_R25, + ESIRISC_R26, + ESIRISC_R27, + ESIRISC_R28, + ESIRISC_R29, + ESIRISC_R30, + ESIRISC_R31, + + ESIRISC_V0, + ESIRISC_V1, + ESIRISC_V2, + ESIRISC_V3, + ESIRISC_V4, + ESIRISC_V5, + ESIRISC_V6, + ESIRISC_V7, + ESIRISC_V8, + ESIRISC_V9, + ESIRISC_V10, + ESIRISC_V11, + ESIRISC_V12, + ESIRISC_V13, + ESIRISC_V14, + ESIRISC_V15, + ESIRISC_V16, + ESIRISC_V17, + ESIRISC_V18, + ESIRISC_V19, + ESIRISC_V20, + ESIRISC_V21, + ESIRISC_V22, + ESIRISC_V23, + ESIRISC_V24, + ESIRISC_V25, + ESIRISC_V26, + ESIRISC_V27, + ESIRISC_V28, + ESIRISC_V29, + ESIRISC_V30, + ESIRISC_V31, + + ESIRISC_A0, + ESIRISC_A1, + ESIRISC_A2, + ESIRISC_A3, + ESIRISC_A4, + ESIRISC_A5, + ESIRISC_A6, + ESIRISC_A7, + + ESIRISC_PC, + ESIRISC_CAS, + ESIRISC_TC, + ESIRISC_ETA, + ESIRISC_ETC, + ESIRISC_EPC, + ESIRISC_ECAS, + ESIRISC_EID, + ESIRISC_ED, + ESIRISC_IP, + ESIRISC_IM, + ESIRISC_IS, + ESIRISC_IT, + + ESIRISC_NUM_REGS, +}; + +/* CSR Banks */ +#define CSR_THREAD 0x00 +#define CSR_INTERRUPT 0x01 +#define CSR_DEBUG 0x04 +#define CSR_CONFIG 0x05 +#define CSR_TRACE 0x09 + +/* Thread CSRs */ +#define CSR_THREAD_TC 0x00 /* Thread Control */ +#define CSR_THREAD_PC 0x01 /* Program Counter */ +#define CSR_THREAD_CAS 0x02 /* Comparison & Arithmetic Status */ +#define CSR_THREAD_AC 0x03 /* Arithmetic Control */ +#define CSR_THREAD_LF 0x04 /* Locked Flag */ +#define CSR_THREAD_LA 0x05 /* Locked Address */ +#define CSR_THREAD_ETA 0x07 /* Exception Table Address */ +#define CSR_THREAD_ETC 0x08 /* Exception TC */ +#define CSR_THREAD_EPC 0x09 /* Exception PC */ +#define CSR_THREAD_ECAS 0x0a /* Exception CAS */ +#define CSR_THREAD_EID 0x0b /* Exception ID */ +#define CSR_THREAD_ED 0x0c /* Exception Data */ + +/* Interrupt CSRs */ +#define CSR_INTERRUPT_IP 0x00 /* Interrupt Pending */ +#define CSR_INTERRUPT_IA 0x01 /* Interrupt Acknowledge */ +#define CSR_INTERRUPT_IM 0x02 /* Interrupt Mask */ +#define CSR_INTERRUPT_IS 0x03 /* Interrupt Sense */ +#define CSR_INTERRUPT_IT 0x04 /* Interrupt Trigger */ + +/* Debug CSRs */ +#define CSR_DEBUG_DC 0x00 /* Debug Control */ +#define CSR_DEBUG_IBC 0x01 /* Instruction Breakpoint Control */ +#define CSR_DEBUG_DBC 0x02 /* Data Breakpoint Control */ +#define CSR_DEBUG_HWDC 0x03 /* Hardware Debug Control */ +#define CSR_DEBUG_DBS 0x04 /* Data Breakpoint Size */ +#define CSR_DEBUG_DBR 0x05 /* Data Breakpoint Range */ +#define CSR_DEBUG_IBAn 0x08 /* Instruction Breakpoint Address [0..7] */ +#define CSR_DEBUG_DBAn 0x10 /* Data Breakpoint Address [0..7] */ + +/* Configuration CSRs */ +#define CSR_CONFIG_ARCH0 0x00 /* Architectural Configuration 0 */ +#define CSR_CONFIG_ARCH1 0x01 /* Architectural Configuration 1 */ +#define CSR_CONFIG_ARCH2 0x02 /* Architectural Configuration 2 */ +#define CSR_CONFIG_ARCH3 0x03 /* Architectural Configuration 3 */ +#define CSR_CONFIG_MEM 0x04 /* Memory Configuration */ +#define CSR_CONFIG_IC 0x05 /* Instruction Cache Configuration */ +#define CSR_CONFIG_DC 0x06 /* Data Cache Configuration */ +#define CSR_CONFIG_INT 0x07 /* Interrupt Configuration */ +#define CSR_CONFIG_ISAn 0x08 /* Instruction Set Configuration [0..6] */ +#define CSR_CONFIG_DBG 0x0f /* Debug Configuration */ +#define CSR_CONFIG_MID 0x10 /* Manufacturer ID */ +#define CSR_CONFIG_REV 0x11 /* Revision Number */ +#define CSR_CONFIG_MPID 0x12 /* Mulitprocessor ID */ +#define CSR_CONFIG_FREQn 0x13 /* Frequency [0..2] */ +#define CSR_CONFIG_TRACE 0x16 /* Trace Configuration */ + +/* Trace CSRs */ +#define CSR_TRACE_CONTROL 0x00 +#define CSR_TRACE_STATUS 0x01 +#define CSR_TRACE_BUFFER_START 0x02 +#define CSR_TRACE_BUFFER_END 0x03 +#define CSR_TRACE_BUFFER_CUR 0x04 +#define CSR_TRACE_TRIGGER 0x05 +#define CSR_TRACE_START_DATA 0x06 +#define CSR_TRACE_START_MASK 0x07 +#define CSR_TRACE_STOP_DATA 0x08 +#define CSR_TRACE_STOP_MASK 0x09 +#define CSR_TRACE_DELAY 0x0a + +#endif /* OPENOCD_TARGET_ESIRISC_REGS_H */ diff --git a/src/target/target.c b/src/target/target.c index c1ccf962e..bf3669192 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -109,6 +109,7 @@ extern struct target_type quark_d20xx_target; extern struct target_type stm8_target; extern struct target_type riscv_target; extern struct target_type mem_ap_target; +extern struct target_type esirisc_target; static struct target_type *target_types[] = { &arm7tdmi_target, @@ -142,10 +143,11 @@ static struct target_type *target_types[] = { &quark_d20xx_target, &stm8_target, &riscv_target, + &mem_ap_target, + &esirisc_target, #if BUILD_TARGET64 &aarch64_target, #endif - &mem_ap_target, NULL, }; diff --git a/src/target/target.h b/src/target/target.h index 5457f0abf..d79613138 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -225,6 +225,13 @@ struct gdb_fileio_info { uint64_t param_4; }; +/** Returns a description of the endianness for the specified target. */ +static inline const char *target_endianness(struct target *target) +{ + return (target->endianness == TARGET_ENDIAN_UNKNOWN) ? "unknown" : + (target->endianness == TARGET_BIG_ENDIAN) ? "big endian" : "little endian"; +} + /** Returns the instance-specific name of the specified target. */ static inline const char *target_name(struct target *target) { diff --git a/tcl/target/esi32xx.cfg b/tcl/target/esi32xx.cfg new file mode 100644 index 000000000..d32af39bd --- /dev/null +++ b/tcl/target/esi32xx.cfg @@ -0,0 +1,36 @@ +# +# EnSilica eSi-32xx SoC (eSi-RISC Family) +# http://www.ensilica.com/risc-ip/ +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME esi32xx +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x11234001 +} + +jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME esirisc -chain-position $_CHIPNAME.cpu + +# Targets with the UNIFIED_ADDRESS_SPACE option disabled should set +# CACHEARCH to 'harvard'. By default, 'von_neumann' is assumed. +if { [info exists CACHEARCH] } { + $_TARGETNAME esirisc cache_arch $CACHEARCH +} + +adapter_khz 2000 + +reset_config none + +# The default linker scripts provided by the eSi-RISC toolchain do not +# specify attributes on memory regions, which results in incorrect +# application of software breakpoints by GDB. +gdb_breakpoint_override hard From 05e0d633bad9e8b0bdfaf16fc76ab1f9d9419d8b Mon Sep 17 00:00:00 2001 From: Steven Stallion Date: Tue, 9 Oct 2018 13:48:18 -0500 Subject: [PATCH 124/147] rtos: check symbol list when updating uCOS-III This patch corrects a crash in uCOS-III on a new GDB connection when RTOS autodetection is not used. The crash was caused by not checking if the symbol list had been loaded prior to updating threads. Change-Id: I64c5133e02fe22fc8d14584cc40d87b49c935b0b Signed-off-by: Steven Stallion Reviewed-on: http://openocd.zylin.com/4719 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/rtos/uCOS-III.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/rtos/uCOS-III.c b/src/rtos/uCOS-III.c index 3cd9c2ae6..304d07c59 100644 --- a/src/rtos/uCOS-III.c +++ b/src/rtos/uCOS-III.c @@ -300,6 +300,11 @@ static int uCOS_III_update_threads(struct rtos *rtos) struct uCOS_III_params *params = rtos->rtos_specific_params; int retval; + if (rtos->symbols == NULL) { + LOG_ERROR("uCOS-III: symbol list not loaded"); + return ERROR_FAIL; + } + /* free previous thread details */ rtos_free_threadlist(rtos); From 7c298a76374859f87cc3bececb8bbed956c09303 Mon Sep 17 00:00:00 2001 From: Steven Stallion Date: Mon, 1 May 2017 13:59:38 -0500 Subject: [PATCH 125/147] ftdi: demote unhelpful debug messages Some protocols make use of empty scan fields for optional padding, which causes the log to fill with unhelpful messages that a field is empty. The remaining LOG_DEBUG messages in ftdi_execute_scan have been demoted to DEBUG_JTAG_IO such that these messages are only seen when debugging JTAG. Change-Id: I61fd4551411ce851da34e67d003bca5d7a71cd92 Signed-off-by: Steven Stallion Reviewed-on: http://openocd.zylin.com/4112 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- src/jtag/drivers/ftdi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 7c6709cd5..1afedd1af 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -439,11 +439,11 @@ static void ftdi_execute_scan(struct jtag_command *cmd) while (cmd->cmd.scan->num_fields > 0 && cmd->cmd.scan->fields[cmd->cmd.scan->num_fields - 1].num_bits == 0) { cmd->cmd.scan->num_fields--; - LOG_DEBUG("discarding trailing empty field"); + DEBUG_JTAG_IO("discarding trailing empty field"); } if (cmd->cmd.scan->num_fields == 0) { - LOG_DEBUG("empty scan, doing nothing"); + DEBUG_JTAG_IO("empty scan, doing nothing"); return; } From d0be1630dc080b0c881830fa28bf2ccfe7850bb8 Mon Sep 17 00:00:00 2001 From: Rohit Singh Date: Fri, 12 Oct 2018 20:42:11 +0530 Subject: [PATCH 126/147] tcl: Add support for the Numato Lab Mimas A7 board The Mimas A7 FPGA board has FTDI FT2232 whose channel B is connected to Artix-7 FPGA's JTAG interface. Hence, OpenOCD can easily interface with it via the its ftdi driver interface. Tested to be working great up to 30 MHz. Change-Id: Ieda015fbc6135bf95ad5a069cbf38650da45911e Signed-off-by: Rohit Singh Reviewed-on: http://openocd.zylin.com/4720 Tested-by: jenkins Reviewed-by: Tim "mithro" Ansell Reviewed-by: Robert Jordens Reviewed-by: Paul Fertser --- tcl/board/numato_mimas_a7.cfg | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tcl/board/numato_mimas_a7.cfg diff --git a/tcl/board/numato_mimas_a7.cfg b/tcl/board/numato_mimas_a7.cfg new file mode 100644 index 000000000..1261feacc --- /dev/null +++ b/tcl/board/numato_mimas_a7.cfg @@ -0,0 +1,36 @@ +# +# Numato Mimas A7 - Artix 7 FPGA Board +# +# https://numato.com/product/mimas-a7-artix-7-fpga-development-board-with-ddr-sdram-and-gigabit-ethernet +# +# Note: Connect external DC power supply if programming a heavy design onto FPGA. +# Programming while powering via USB may lead to programming failure. +# Therefore, prefer external power supply. + +interface ftdi +ftdi_device_desc "Mimas Artix 7 FPGA Module" +ftdi_vid_pid 0x2a19 0x1009 + +# channel 0 is for custom purpose by users (like uart, fifo etc) +# channel 1 is reserved for JTAG (by-default) or SPI (possible via changing solder jumpers) +ftdi_channel 1 +ftdi_tdo_sample_edge falling + + +# FTDI Pin Layout +# +# +--------+-------+-------+-------+-------+-------+-------+-------+ +# | DBUS7 | DBUS6 | DBUS5 | DBUS4 | DBUS3 | DBUS2 | DBUS1 | DBUS0 | +# +--------+-------+-------+-------+-------+-------+-------+-------+ +# | PROG_B | OE_N | NC | NC | TMS | TDO | TDI | TCK | +# +--------+-------+-------+-------+-------+-------+-------+-------+ +# +# OE_N is JTAG buffer output enable signal (active-low) +# PROG_B is not used, so left as input to FTDI. +# +ftdi_layout_init 0x0008 0x004b +reset_config none +adapter_khz 30000 + +source [find cpld/xilinx-xc7.cfg] +source [find cpld/jtagspi.cfg] From 1ba715422fba733bb5426ea887368e2dcf371b91 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Fri, 21 Sep 2018 15:52:02 +0200 Subject: [PATCH 127/147] target/arm_adi_v5: fix sync CSW cache on apreg write Commit 0057c71ab6b81d0679b232318fc5f84b4becc471 updates the OpenOCD cached values of CSW and TAR registers if these registers are modified by an apreg command. The condition to force the update of CSW cache is incorrect and it will erase the default CSW value. Moreover, calling mem_ap_setup_csw() does not honor the value requested in the apreg command because such value is incorrectly bitwise or-ed with csw_default. Fix it by updating csw_value, instead of erasing csw_default, and writing directly in CSW register the new value from the command line. Change-Id: I40273cb64d22ccfb9b6d3499bd39b586eb60de38 Fixes: 0057c71ab6b8 ("target/arm_adi_v5: sync CSW and TAR cache on apreg write") Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4679 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Tomas Vanek --- src/target/arm_adi_v5.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index d9f3bd74f..e62ac0757 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1738,8 +1738,10 @@ COMMAND_HANDLER(dap_apreg_command) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); switch (reg) { case MEM_AP_REG_CSW: - ap->csw_default = 0; /* invalid, force write */ - retval = mem_ap_setup_csw(ap, value); + ap->csw_value = 0; /* invalid, in case write fails */ + retval = dap_queue_ap_write(ap, reg, value); + if (retval == ERROR_OK) + ap->csw_value = value; break; case MEM_AP_REG_TAR: ap->tar_valid = false; /* invalid, force write */ From 0cdb44a9dbb2c1aa5321e86a9948a493ffde5979 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Tue, 15 May 2018 18:05:02 -0400 Subject: [PATCH 128/147] tcl/board: Add Arty-S7 Spartan 7 FPGA Development Board Change-Id: I8bfe780cb67a1777d5112a68e8a9781bfe4f2038 Signed-off-by: William D. Jones Reviewed-on: http://openocd.zylin.com/4525 Reviewed-by: Robert Jordens Tested-by: jenkins Reviewed-by: Rohit Singh Reviewed-by: Matthias Welwarsky --- tcl/board/arty_s7.cfg | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tcl/board/arty_s7.cfg diff --git a/tcl/board/arty_s7.cfg b/tcl/board/arty_s7.cfg new file mode 100644 index 000000000..ca7d3f1c4 --- /dev/null +++ b/tcl/board/arty_s7.cfg @@ -0,0 +1,35 @@ +# +# Arty S7: Spartan7 25/50 FPGA Board for Makers and Hobbyists +# +# https://www.xilinx.com/products/boards-and-kits/1-pnziih.html +# https://store.digilentinc.com/arty-s7-spartan-7-fpga-board-for-makers-and-hobbyists/ + +source [find interface/ftdi/digilent-hs1.cfg] + +# Xilinx Spartan7-25/50 FPGA (XC7S{25,50}-CSGA324) +source [find cpld/xilinx-xc7.cfg] +source [find cpld/jtagspi.cfg] + +adapter_khz 25000 + +# Usage: +# +# Load Bitstream into FPGA: +# openocd -f board/arty_s7.cfg -c "init;\ +# pld load 0 bitstream.bit;\ +# shutdown" +# +# Write Bitstream to Flash: +# openocd -f board/arty_s7.cfg -c "init;\ +# jtagspi_init 0 bscan_spi_xc7s??.bit;\ +# jtagspi_program bitstream.bin 0;\ +# xc7s_program xc7s.tap;\ +# shutdown" +# +# jtagspi flash proxies can be found at: +# https://github.com/quartiq/bscan_spi_bitstreams +# +# For the Spartan 50 variant, use +# - https://github.com/quartiq/bscan_spi_bitstreams/raw/master/bscan_spi_xc7s50.bit +# For the Spartan 25 variant, use +# - https://github.com/quartiq/bscan_spi_bitstreams/raw/master/bscan_spi_xc7s25.bit From 988a002a30afe4facd116c97cba88b3793841046 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 22 Feb 2018 11:30:18 -0500 Subject: [PATCH 129/147] xilinx-xc7: Add additional IDCODEs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add/detect missing IDCODEs for the Spartan 7 family and Artix 25T and Artix 12T. Change-Id: Ib6c83c5592e90df1eb8e715e79b279da9a95f9c6 Signed-off-by: William D. Jones Reviewed-on: http://openocd.zylin.com/4428 Reviewed-by: Robert Jördens Tested-by: jenkins Reviewed-by: Rohit Singh Reviewed-by: Matthias Welwarsky --- tcl/cpld/xilinx-xc7.cfg | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tcl/cpld/xilinx-xc7.cfg b/tcl/cpld/xilinx-xc7.cfg index d5824f8a1..4c0502c5d 100644 --- a/tcl/cpld/xilinx-xc7.cfg +++ b/tcl/cpld/xilinx-xc7.cfg @@ -9,7 +9,15 @@ if { [info exists CHIPNAME] } { # the 4 top bits (28:31) are the die stepping/revisions. ignore it. jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ + -expected-id 0x03622093 \ + -expected-id 0x03620093 \ + -expected-id 0x037C4093 \ + -expected-id 0x0362F093 \ + -expected-id 0x037C8093 \ + -expected-id 0x037C7093 \ + -expected-id 0x037C3093 \ -expected-id 0x0362E093 \ + -expected-id 0x037C2093 \ -expected-id 0x0362D093 \ -expected-id 0x0362C093 \ -expected-id 0x03632093 \ From cf81de70524d615aa307f94b9b326bed42d7dfc0 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 18 Jul 2018 15:38:49 +0200 Subject: [PATCH 130/147] target/cortex_a: fix temporary breakpoint during step Commit c8926d14579528bfcead1e179baf7cb846513db4 introduces the context and hybrid breakpoint types beside existing SW and HW types. The new field "asid" is non-zero only for these new types. The commit above did not properly initialize "asid" to 0 for a temporarily HW breakpoint used during single step. This causes cortex_a_unset_breakpoint() to identify this breakpoint as of type "hybrid". Identified through valgrind error: Conditional jump or move depends on uninitialised value(s) Actually valgrind triggers a total of 10 messages about use of uninitialized variables, but they are all caused by the first conditional jump bases on "asid != 0". Fixed by initializing "asid" to 0 in cortex_a_step(). Fixes: c8926d145795 ("cortex_a hybrid & context breakpoints") Change-Id: Ib674d8457d1e02e10332fd9d73554d13719ef93d Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4613 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/cortex_a.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index bc4aa33b4..e209c801c 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -1420,6 +1420,7 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre /* Setup single step breakpoint */ stepbreakpoint.address = address; + stepbreakpoint.asid = 0; stepbreakpoint.length = (arm->core_state == ARM_STATE_THUMB) ? 2 : 4; stepbreakpoint.type = BKPT_HARD; From abd78a0ff8df04cd46a68ff8a716bf1eda215af0 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Wed, 5 Jul 2017 11:48:34 -0700 Subject: [PATCH 131/147] zynq_7000: Add zynqpl_program command This allows for programming the PL part of the Xilinx Zynq 7000 Change-Id: I89e86c0f381951091f6948c46802d17d7f1f3500 Signed-off-by: Moritz Fischer Reviewed-on: http://openocd.zylin.com/4177 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/target/zynq_7000.cfg | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tcl/target/zynq_7000.cfg b/tcl/target/zynq_7000.cfg index 07a6c8352..1562768c5 100644 --- a/tcl/target/zynq_7000.cfg +++ b/tcl/target/zynq_7000.cfg @@ -27,3 +27,22 @@ adapter_khz 1000 ${_TARGETNAME}0 configure -event reset-assert-post "cortex_a dbginit" ${_TARGETNAME}1 configure -event reset-assert-post "cortex_a dbginit" + +pld device virtex2 zynq_pl.bs 1 + +set XC7_JSHUTDOWN 0x0d +set XC7_JPROGRAM 0x0b +set XC7_JSTART 0x0c +set XC7_BYPASS 0x3f + +proc zynqpl_program {tap} { + global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS + irscan $tap $XC7_JSHUTDOWN + irscan $tap $XC7_JPROGRAM + runtest 60000 + #JSTART prevents this from working... + #irscan $tap $XC7_JSTART + runtest 2000 + irscan $tap $XC7_BYPASS + runtest 2000 +} From fe732bad94231a34f2180ef367271aa413c093ed Mon Sep 17 00:00:00 2001 From: Kevin Gillespie Date: Thu, 4 Oct 2018 10:34:29 -0500 Subject: [PATCH 132/147] target/target.c: adding keep_alive() to while loop. Adding the call to keep_alive() to suppress warnings when running the async flash algorithm. Issue observed when loading large pieces of code on slower debuggers. Change-Id: I7660fa05f68ebd7be07b2ca0a55b0f3b6ae718f3 Signed-off-by: Kevin Gillespie Reviewed-on: http://openocd.zylin.com/4686 Tested-by: jenkins Reviewed-by: Jesse Marroquin Reviewed-by: Tomas Vanek --- src/target/target.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/target/target.c b/src/target/target.c index bf3669192..871588393 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1047,6 +1047,9 @@ int target_run_flash_async_algorithm(struct target *target, retval = target_write_u32(target, wp_addr, wp); if (retval != ERROR_OK) break; + + /* Avoid GDB timeouts */ + keep_alive(); } if (retval != ERROR_OK) { From da4b2d5beb5ff19af8099d15f6a44513703f355c Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 23 Mar 2017 10:13:09 +0100 Subject: [PATCH 133/147] drivers/cmsis-dap: speed up sending multiple HID requests The performance of CMSIS-DAP in long data transfers was improved substantially in ef02b69b14d133b061217a91add5a028a77e86bc. But it not as good as some other USB/MCU based adapters. Using HID and therefore interrupt endpoint is slower than USB bulk transfer. CMSIS-DAP adapter implements multiple HID buffer handling and OpenOCD already reads number of buffers from info command. This change adds capability to sumbit more than one HID requests before driver waits for a HID response. This scenario is used for long transfers only. Results show about double speed on USB FS and ~140% speed on USB HS: | w/o this change | with multi HIDrq -----------------------------------------+-----------------+----------------- Open source CMSIS-DAP, USB FS, adapter_khz 1000 dump_image ram32k.bin 0x1fffe000 0x8000 | 23.225 KiB/s | 45.901 KiB/s load_image ram32k.bin 0x1fffe000 | 23.324 KiB/s | 46.552 KiB/s Cypress' Kitprog in CMSIS-DAP mode, USB FS, adapter_khz 1000 (over firmware limit) dump_image ram64k.bin 0x20000000 0x10000 | 15.537 KiB/s | 42.558 KiB/s load_image ram64k.bin 0x20000000 | 15.605 KiB/s | 43.291 KiB/s Atmel's EDBG, USB HS, adapter_khz 10000 (#3945 applied) dump_image ram384k.bin 0x20400000 0x6000 | 248.402 KiB/s | 345.250 KiB/s load_image ram384k.bin 0x20400000 | 256.039 KiB/s | 365.945 KiB/s Change-Id: I9edbe018086176d357c6aaba5d6b657a5e5e1c64 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4080 Tested-by: jenkins Reviewed-by: Paul Fertser --- src/jtag/drivers/cmsis_dap_usb.c | 196 ++++++++++++++++++++++++------- 1 file changed, 153 insertions(+), 43 deletions(-) diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index 9e723b51d..035cc446e 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -166,7 +166,7 @@ static const char * const info_caps_str[] = { struct cmsis_dap { hid_device *dev_handle; uint16_t packet_size; - uint16_t packet_count; + int packet_count; uint8_t *packet_buffer; uint8_t caps; uint8_t mode; @@ -178,6 +178,11 @@ struct pending_transfer_result { void *buffer; }; +struct pending_request_block { + struct pending_transfer_result *transfers; + int transfer_count; +}; + struct pending_scan_result { /** Offset in bytes in the CMD_DAP_JTAG_SEQ response buffer. */ unsigned first; @@ -189,8 +194,16 @@ struct pending_scan_result { unsigned buffer_offset; }; -static int pending_transfer_count, pending_queue_len; -static struct pending_transfer_result *pending_transfers; +/* Up to MIN(packet_count, MAX_PENDING_REQUESTS) requests may be issued + * until the first response arrives */ +#define MAX_PENDING_REQUESTS 3 + +/* Pending requests are organized as a FIFO - circular buffer */ +/* Each block in FIFO can contain up to pending_queue_len transfers */ +static int pending_queue_len; +static struct pending_request_block pending_fifo[MAX_PENDING_REQUESTS]; +static int pending_fifo_put_idx, pending_fifo_get_idx; +static int pending_fifo_block_count; /* pointers to buffers that will receive jtag scan results on the next flush */ #define MAX_PENDING_SCAN_RESULTS 256 @@ -346,14 +359,16 @@ static void cmsis_dap_usb_close(struct cmsis_dap *dap) cmsis_dap_handle = NULL; free(cmsis_dap_serial); cmsis_dap_serial = NULL; - free(pending_transfers); - pending_transfers = NULL; + + for (int i = 0; i < MAX_PENDING_REQUESTS; i++) { + free(pending_fifo[i].transfers); + pending_fifo[i].transfers = NULL; + } return; } -/* Send a message and receive the reply */ -static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen) +static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen) { #ifdef CMSIS_DAP_JTAG_DEBUG LOG_DEBUG("cmsis-dap usb xfer cmd=%02X", dap->packet_buffer[1]); @@ -368,6 +383,26 @@ static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen) return ERROR_FAIL; } + return ERROR_OK; +} + +/* Send a message and receive the reply */ +static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen) +{ + if (pending_fifo_block_count) { + LOG_ERROR("pending %d blocks, flushing", pending_fifo_block_count); + while (pending_fifo_block_count) { + hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, 10); + pending_fifo_block_count--; + } + pending_fifo_put_idx = 0; + pending_fifo_get_idx = 0; + } + + int retval = cmsis_dap_usb_write(dap, txlen); + if (retval != ERROR_OK) + return retval; + /* get reply */ retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, USB_TIMEOUT); if (retval == -1 || retval == 0) { @@ -594,29 +629,31 @@ static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us) } #endif -static int cmsis_dap_swd_run_queue(void) +static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) { - uint8_t *buffer = cmsis_dap_handle->packet_buffer; + uint8_t *buffer = dap->packet_buffer; + struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx]; - LOG_DEBUG_IO("Executing %d queued transactions", pending_transfer_count); + LOG_DEBUG_IO("Executing %d queued transactions from FIFO index %d", block->transfer_count, pending_fifo_put_idx); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); goto skip; } - if (!pending_transfer_count) + if (block->transfer_count == 0) goto skip; size_t idx = 0; buffer[idx++] = 0; /* report number */ buffer[idx++] = CMD_DAP_TFER; buffer[idx++] = 0x00; /* DAP Index */ - buffer[idx++] = pending_transfer_count; + buffer[idx++] = block->transfer_count; - for (int i = 0; i < pending_transfer_count; i++) { - uint8_t cmd = pending_transfers[i].cmd; - uint32_t data = pending_transfers[i].data; + for (int i = 0; i < block->transfer_count; i++) { + struct pending_transfer_result *transfer = &(block->transfers[i]); + uint8_t cmd = transfer->cmd; + uint32_t data = transfer->data; LOG_DEBUG_IO("%s %s reg %x %"PRIx32, cmd & SWD_CMD_APnDP ? "AP" : "DP", @@ -651,26 +688,62 @@ static int cmsis_dap_swd_run_queue(void) } } - queued_retval = cmsis_dap_usb_xfer(cmsis_dap_handle, idx); + queued_retval = cmsis_dap_usb_write(dap, idx); if (queued_retval != ERROR_OK) goto skip; - idx = 2; - uint8_t ack = buffer[idx] & 0x07; - if (ack != SWD_ACK_OK || (buffer[idx] & 0x08)) { - LOG_DEBUG("SWD ack not OK: %d %s", buffer[idx-1], + pending_fifo_put_idx = (pending_fifo_put_idx + 1) % dap->packet_count; + pending_fifo_block_count++; + if (pending_fifo_block_count > dap->packet_count) + LOG_ERROR("too much pending writes %d", pending_fifo_block_count); + + return; + +skip: + block->transfer_count = 0; +} + +static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms) +{ + uint8_t *buffer = dap->packet_buffer; + struct pending_request_block *block = &pending_fifo[pending_fifo_get_idx]; + + if (pending_fifo_block_count == 0) + LOG_ERROR("no pending write"); + + /* get reply */ + int retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, timeout_ms); + if (retval == 0 && timeout_ms < USB_TIMEOUT) + return; + + if (retval == -1 || retval == 0) { + LOG_DEBUG("error reading data: %ls", hid_error(dap->dev_handle)); + queued_retval = ERROR_FAIL; + goto skip; + } + + if (buffer[2] & 0x08) { + LOG_DEBUG("CMSIS-DAP Protocol Error @ %d (wrong parity)", buffer[1]); + queued_retval = ERROR_FAIL; + goto skip; + } + uint8_t ack = buffer[2] & 0x07; + if (ack != SWD_ACK_OK) { + LOG_DEBUG("SWD ack not OK @ %d %s", buffer[1], ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK"); queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL; goto skip; } - idx++; - if (pending_transfer_count != buffer[1]) + if (block->transfer_count != buffer[1]) LOG_ERROR("CMSIS-DAP transfer count mismatch: expected %d, got %d", - pending_transfer_count, buffer[1]); + block->transfer_count, buffer[1]); + LOG_DEBUG_IO("Received results of %d queued transactions FIFO index %d", buffer[1], pending_fifo_get_idx); + size_t idx = 3; for (int i = 0; i < buffer[1]; i++) { - if (pending_transfers[i].cmd & SWD_CMD_RnW) { + struct pending_transfer_result *transfer = &(block->transfers[i]); + if (transfer->cmd & SWD_CMD_RnW) { static uint32_t last_read; uint32_t data = le_to_h_u32(&buffer[idx]); uint32_t tmp = data; @@ -679,19 +752,36 @@ static int cmsis_dap_swd_run_queue(void) LOG_DEBUG_IO("Read result: %"PRIx32, data); /* Imitate posted AP reads */ - if ((pending_transfers[i].cmd & SWD_CMD_APnDP) || - ((pending_transfers[i].cmd & SWD_CMD_A32) >> 1 == DP_RDBUFF)) { + if ((transfer->cmd & SWD_CMD_APnDP) || + ((transfer->cmd & SWD_CMD_A32) >> 1 == DP_RDBUFF)) { tmp = last_read; last_read = data; } - if (pending_transfers[i].buffer) - *(uint32_t *)pending_transfers[i].buffer = tmp; + if (transfer->buffer) + *(uint32_t *)(transfer->buffer) = tmp; } } skip: - pending_transfer_count = 0; + block->transfer_count = 0; + pending_fifo_get_idx = (pending_fifo_get_idx + 1) % dap->packet_count; + pending_fifo_block_count--; +} + +static int cmsis_dap_swd_run_queue(void) +{ + if (pending_fifo_block_count) + cmsis_dap_swd_read_process(cmsis_dap_handle, 0); + + cmsis_dap_swd_write_from_queue(cmsis_dap_handle); + + while (pending_fifo_block_count) + cmsis_dap_swd_read_process(cmsis_dap_handle, USB_TIMEOUT); + + pending_fifo_put_idx = 0; + pending_fifo_get_idx = 0; + int retval = queued_retval; queued_retval = ERROR_OK; @@ -700,21 +790,29 @@ skip: static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) { - if (pending_transfer_count == pending_queue_len) { + if (pending_fifo[pending_fifo_put_idx].transfer_count == pending_queue_len) { + if (pending_fifo_block_count) + cmsis_dap_swd_read_process(cmsis_dap_handle, 0); + /* Not enough room in the queue. Run the queue. */ - queued_retval = cmsis_dap_swd_run_queue(); + cmsis_dap_swd_write_from_queue(cmsis_dap_handle); + + if (pending_fifo_block_count >= cmsis_dap_handle->packet_count) + cmsis_dap_swd_read_process(cmsis_dap_handle, USB_TIMEOUT); } if (queued_retval != ERROR_OK) return; - pending_transfers[pending_transfer_count].data = data; - pending_transfers[pending_transfer_count].cmd = cmd; + struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx]; + struct pending_transfer_result *transfer = &(block->transfers[block->transfer_count]); + transfer->data = data; + transfer->cmd = cmd; if (cmd & SWD_CMD_RnW) { /* Queue a read transaction */ - pending_transfers[pending_transfer_count].buffer = dst; + transfer->buffer = dst; } - pending_transfer_count++; + block->transfer_count++; } static void cmsis_dap_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) @@ -909,6 +1007,11 @@ static int cmsis_dap_init(void) LOG_INFO("CMSIS-DAP: Interface Initialised (JTAG)"); } + /* Be conservative and supress submiting multiple HID requests + * until we get packet count info from the adaptor */ + cmsis_dap_handle->packet_count = 1; + pending_queue_len = 12; + /* INFO_ID_PKT_SZ - short */ retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_SZ, &data); if (retval != ERROR_OK) @@ -921,11 +1024,6 @@ static int cmsis_dap_init(void) * write. For bulk read sequences just 4 bytes are * needed per transfer, so this is suboptimal. */ pending_queue_len = (pkt_sz - 4) / 5; - pending_transfers = malloc(pending_queue_len * sizeof(*pending_transfers)); - if (!pending_transfers) { - LOG_ERROR("Unable to allocate memory for CMSIS-DAP queue"); - return ERROR_FAIL; - } if (cmsis_dap_handle->packet_size != pkt_sz + 1) { /* reallocate buffer */ @@ -947,11 +1045,23 @@ static int cmsis_dap_init(void) return retval; if (data[0] == 1) { /* byte */ - uint16_t pkt_cnt = data[1]; - cmsis_dap_handle->packet_count = pkt_cnt; - LOG_DEBUG("CMSIS-DAP: Packet Count = %" PRId16, pkt_cnt); + int pkt_cnt = data[1]; + if (pkt_cnt > 1) + cmsis_dap_handle->packet_count = MIN(MAX_PENDING_REQUESTS, pkt_cnt); + + LOG_DEBUG("CMSIS-DAP: Packet Count = %d", pkt_cnt); } + LOG_DEBUG("Allocating FIFO for %d pending HID requests", cmsis_dap_handle->packet_count); + for (int i = 0; i < cmsis_dap_handle->packet_count; i++) { + pending_fifo[i].transfers = malloc(pending_queue_len * sizeof(struct pending_transfer_result)); + if (!pending_fifo[i].transfers) { + LOG_ERROR("Unable to allocate memory for CMSIS-DAP queue"); + return ERROR_FAIL; + } + } + + retval = cmsis_dap_get_status(); if (retval != ERROR_OK) return ERROR_FAIL; From 2ed21488cd52eb8eac10b7984096bdf0652cbae7 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Mon, 22 Oct 2018 23:13:04 +0300 Subject: [PATCH 134/147] tcl: target: omit apcsw for hla When using stlink for CM7 targets we have to rely on its firmware to do the right thing as direct DAP access is not possible. Change-Id: Ieee69f4eeea5c911f89f060f31ce86ed043bdfd0 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4732 Tested-by: jenkins Reviewed-by: Matthias Welwarsky Reviewed-by: Tomas Vanek --- tcl/target/atsamv.cfg | 15 ++++++++------- tcl/target/stm32f7x.cfg | 15 ++++++++------- tcl/target/stm32h7x.cfg | 15 ++++++++------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/tcl/target/atsamv.cfg b/tcl/target/atsamv.cfg index 1d026aa95..43962de31 100644 --- a/tcl/target/atsamv.cfg +++ b/tcl/target/atsamv.cfg @@ -45,15 +45,16 @@ if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq + + # Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal + # HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 + # makes the data access cacheable. This allows reading and writing data in the + # CPU cache from the debugger, which is far more useful than going straight to + # RAM when operating on typical variables, and is generally no worse when + # operating on special memory locations. + $_CHIPNAME.dap apcsw 0x08000000 0x08000000 } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME atsamv 0x00400000 0 0 0 $_TARGETNAME -# Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal -# HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 -# makes the data access cacheable. This allows reading and writing data in the -# CPU cache from the debugger, which is far more useful than going straight to -# RAM when operating on typical variables, and is generally no worse when -# operating on special memory locations. -$_CHIPNAME.dap apcsw 0x08000000 0x08000000 diff --git a/tcl/target/stm32f7x.cfg b/tcl/target/stm32f7x.cfg index e06a34594..b0468e21e 100755 --- a/tcl/target/stm32f7x.cfg +++ b/tcl/target/stm32f7x.cfg @@ -65,6 +65,14 @@ if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq + + # Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal + # HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 + # makes the data access cacheable. This allows reading and writing data in the + # CPU cache from the debugger, which is far more useful than going straight to + # RAM when operating on typical variables, and is generally no worse when + # operating on special memory locations. + $_CHIPNAME.dap apcsw 0x08000000 0x08000000 } $_TARGETNAME configure -event examine-end { @@ -146,10 +154,3 @@ $_TARGETNAME configure -event reset-start { adapter_khz 2000 } -# Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal -# HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 -# makes the data access cacheable. This allows reading and writing data in the -# CPU cache from the debugger, which is far more useful than going straight to -# RAM when operating on typical variables, and is generally no worse when -# operating on special memory locations. -$_CHIPNAME.dap apcsw 0x08000000 0x08000000 diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index e2ea8a84e..c9aec7612 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -63,6 +63,14 @@ if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq + + # Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal + # HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 + # makes the data access cacheable. This allows reading and writing data in the + # CPU cache from the debugger, which is far more useful than going straight to + # RAM when operating on typical variables, and is generally no worse when + # operating on special memory locations. + $_CHIPNAME.dap apcsw 0x08000000 0x08000000 } $_TARGETNAME configure -event examine-end { @@ -93,10 +101,3 @@ $_TARGETNAME configure -event reset-init { adapter_khz 4000 } -# Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal -# HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 -# makes the data access cacheable. This allows reading and writing data in the -# CPU cache from the debugger, which is far more useful than going straight to -# RAM when operating on typical variables, and is generally no worse when -# operating on special memory locations. -$_CHIPNAME.dap apcsw 0x08000000 0x08000000 From 17de29c5265e0518e85f11ba6487194da4fb26e5 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 23 Oct 2018 11:21:10 +0200 Subject: [PATCH 135/147] flash/nor/at91samd: add SAMR21E19A DID While on it correct RAM amount of SAMR21x16A devices Change-Id: Ie9ab9de1551bdceff17af7597a9a2ee41f5aebe0 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4734 Reviewed-by: Eduardo Montoya Tested-by: jenkins --- src/flash/nor/at91samd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index 017d1441e..5f172d118 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -165,12 +165,13 @@ static const struct samd_part samd21_parts[] = { { 0xE, "SAMD21E14A", 16, 2 }, /* SAMR21 parts have integrated SAMD21 with a radio */ + { 0x18, "SAMR21G19A", 256, 32 }, /* with 512k of serial flash */ { 0x19, "SAMR21G18A", 256, 32 }, { 0x1A, "SAMR21G17A", 128, 32 }, - { 0x1B, "SAMR21G16A", 64, 32 }, + { 0x1B, "SAMR21G16A", 64, 16 }, { 0x1C, "SAMR21E18A", 256, 32 }, { 0x1D, "SAMR21E17A", 128, 32 }, - { 0x1E, "SAMR21E16A", 64, 32 }, + { 0x1E, "SAMR21E16A", 64, 16 }, /* SAMD21 B Variants (Table 3-7 from rev I of datasheet) */ { 0x20, "SAMD21J16B", 64, 8 }, From 1e3ba2046cf93dd037fd6e5c7babf95dd2716a1f Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 15 Sep 2018 00:09:16 +0200 Subject: [PATCH 136/147] arm_adi_v5: do not deactivate power domains while trying to clear sticky error At OpenOCD start-up the operation of clearing the sticky error in CTRL/STAT register ignores the current value of the power domains bits CDBGPWRUPREQ and CSYSPWRUPREQ in the same register and incorrectly set them to zero. This abrupt disable does not follow the requirement in IHI0031 to wait for the acknowledgment of power disabled before continuing. The power domains are then re-enabled immediately after; it is possible that such short disable period has passed undetected or has been tested only on devices that do not implement the power domains. Anyway, this sequence is incorrect and can generate unexpected and hard-to-debug issues while OpenOCD attaches to a running target that implements power domains. Anticipate the initialization of dap->dp_ctrl_stat and use it while clearing the sticky bit. This has the additional effect of avoiding a power disable in the error recovery part of the function dap_dp_read_atomic(). Keep the same sequence of read/write in dap_dp_init() to avoid breaking the initialization of some problematic target. Add comments to document these choices. Change-Id: I8d6da788f2dd11909792b5d6b69bc90fbe4df25d Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4677 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Matthias Welwarsky --- src/target/arm_adi_v5.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index e62ac0757..03e642bfe 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -652,6 +652,15 @@ int dap_dp_init(struct adiv5_dap *dap) dap_invalidate_cache(dap); + /* + * Early initialize dap->dp_ctrl_stat. + * In jtag mode only, if the following atomic reads fail and set the + * sticky error, it will trigger the clearing of the sticky. Without this + * initialization system and debug power would be disabled while clearing + * the sticky error bit. + */ + dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; + for (size_t i = 0; i < 30; i++) { /* DP initialization */ @@ -660,7 +669,18 @@ int dap_dp_init(struct adiv5_dap *dap) break; } - retval = dap_queue_dp_write(dap, DP_CTRL_STAT, SSTICKYERR); + /* + * This write operation clears the sticky error bit in jtag mode only and + * is ignored in swd mode. It also powers-up system and debug domains in + * both jtag and swd modes, if not done before. + * Actually we do not need to clear the sticky error here because it has + * been already cleared (if it was set) in the previous atomic read. This + * write could be removed, but this initial part of dap_dp_init() is the + * result of years of fine tuning and there are strong concerns about any + * unnecessary code change. It doesn't harm, so let's keep it here and + * preserve the historical sequence of read/write operations! + */ + retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat | SSTICKYERR); if (retval != ERROR_OK) return retval; @@ -668,7 +688,6 @@ int dap_dp_init(struct adiv5_dap *dap) if (retval != ERROR_OK) return retval; - dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat); if (retval != ERROR_OK) return retval; From cea40152f82f52bfc718c7bda9fa4a9d70bf9cfd Mon Sep 17 00:00:00 2001 From: Dominik Peklo Date: Thu, 12 Jul 2018 20:44:28 +1000 Subject: [PATCH 137/147] flash/nor/stm32f1x: Use of protection blocks, improved option bytes handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handle write protection status in blocks instead of sectors, removing unnecessary complexity in the process. Now closer to stm32f2x. Support sequential modification of option bytes by read/modify/write directly to option bytes area instead of always starting with the currently loaded bytes from FLASH_OBR/WRPR registers. Added new command 'options_load' to force re-load of option bytes w/o having to power cycle target. Change-Id: I5c76191e29c17a1e11482df06379d10ca8d6d04d Signed-off-by: Dominik Peklo Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4576 Tested-by: jenkins Reviewed-by: Jan VojtÄ›ch --- doc/openocd.texi | 18 +- src/flash/nor/stm32f1x.c | 405 ++++++++++++++++++--------------------- 2 files changed, 196 insertions(+), 227 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 77c9ff7b6..ac81b35ed 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -6429,23 +6429,24 @@ flash bank $_FLASHNAME stm32f1x 0x08080000 0 0 0 $_TARGETNAME Some stm32f1x-specific commands are defined: @deffn Command {stm32f1x lock} num -Locks the entire stm32 device. +Locks the entire stm32 device against reading. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32f1x unlock} num -Unlocks the entire stm32 device. +Unlocks the entire stm32 device for reading. This command will cause +a mass erase of the entire stm32 device if previously locked. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32f1x mass_erase} num -Mass erases the entire stm32f1x device. +Mass erases the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32f1x options_read} num -Read and display the stm32 option bytes written by -the @command{stm32f1x options_write} command. +Reads and displays active stm32 option bytes loaded during POR +or upon executing the @command{stm32f1x options_load} command. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @@ -6453,6 +6454,13 @@ The @var{num} parameter is a value shown by @command{flash banks}. Writes the stm32 option byte with the specified values. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn + +@deffn Command {stm32f1x options_load} num +Generates a special kind of reset to re-load the stm32 option bytes written +by the @command{stm32f1x options_write} or @command{flash protect} commands +without having to power cycle the target. Not applicable to stm32f1x devices. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn @end deffn @deffn {Flash Driver} stm32f2x diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index faada9a61..fbd759828 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -70,14 +70,15 @@ /* FLASH_CR register bits */ -#define FLASH_PG (1 << 0) -#define FLASH_PER (1 << 1) -#define FLASH_MER (1 << 2) -#define FLASH_OPTPG (1 << 4) -#define FLASH_OPTER (1 << 5) -#define FLASH_STRT (1 << 6) -#define FLASH_LOCK (1 << 7) -#define FLASH_OPTWRE (1 << 9) +#define FLASH_PG (1 << 0) +#define FLASH_PER (1 << 1) +#define FLASH_MER (1 << 2) +#define FLASH_OPTPG (1 << 4) +#define FLASH_OPTER (1 << 5) +#define FLASH_STRT (1 << 6) +#define FLASH_LOCK (1 << 7) +#define FLASH_OPTWRE (1 << 9) +#define FLASH_OBL_LAUNCH (1 << 13) /* except stm32f1x series */ /* FLASH_SR register bits */ @@ -106,10 +107,10 @@ #define FLASH_ERASE_TIMEOUT 100 struct stm32x_options { - uint16_t RDP; - uint16_t user_options; - uint16_t user_data; - uint16_t protection[4]; + uint8_t rdp; + uint8_t user; + uint16_t data; + uint32_t protection; }; struct stm32x_flash_bank { @@ -119,8 +120,9 @@ struct stm32x_flash_bank { bool has_dual_banks; /* used to access dual flash bank stm32xl */ + bool can_load_options; uint32_t register_base; - uint16_t default_rdp; + uint8_t default_rdp; int user_data_offset; int option_offset; uint32_t user_bank_size; @@ -145,6 +147,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) bank->driver_priv = stm32x_info; stm32x_info->probed = 0; stm32x_info->has_dual_banks = false; + stm32x_info->can_load_options = false; stm32x_info->register_base = FLASH_REG_BASE_B0; stm32x_info->user_bank_size = bank->size; @@ -221,44 +224,47 @@ static int stm32x_check_operation_supported(struct flash_bank *bank) static int stm32x_read_options(struct flash_bank *bank) { - uint32_t optiondata; - struct stm32x_flash_bank *stm32x_info = NULL; + struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; + uint32_t option_bytes; + int retval; - stm32x_info = bank->driver_priv; - - /* read current option bytes */ - int retval = target_read_u32(target, STM32_FLASH_OBR_B0, &optiondata); + /* read user and read protection option bytes */ + retval = target_read_u32(target, STM32_OB_RDP, &option_bytes); if (retval != ERROR_OK) return retval; - stm32x_info->option_bytes.user_options = (optiondata >> stm32x_info->option_offset >> 2) & 0xffff; - stm32x_info->option_bytes.user_data = (optiondata >> stm32x_info->user_data_offset) & 0xffff; - stm32x_info->option_bytes.RDP = (optiondata & (1 << OPT_READOUT)) ? 0xFFFF : 0x5AA5; + stm32x_info->option_bytes.rdp = option_bytes & 0xFF; + stm32x_info->option_bytes.user = (option_bytes >> 16) & 0xFF; - if (optiondata & (1 << OPT_READOUT)) - LOG_INFO("Device Security Bit Set"); - - /* each bit refers to a 4bank protection */ - retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &optiondata); + /* read user data option bytes */ + retval = target_read_u32(target, STM32_OB_DATA0, &option_bytes); if (retval != ERROR_OK) return retval; - stm32x_info->option_bytes.protection[0] = (uint16_t)optiondata; - stm32x_info->option_bytes.protection[1] = (uint16_t)(optiondata >> 8); - stm32x_info->option_bytes.protection[2] = (uint16_t)(optiondata >> 16); - stm32x_info->option_bytes.protection[3] = (uint16_t)(optiondata >> 24); + stm32x_info->option_bytes.data = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF); + + /* read write protection option bytes */ + retval = target_read_u32(target, STM32_OB_WRP0, &option_bytes); + if (retval != ERROR_OK) + return retval; + + stm32x_info->option_bytes.protection = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF); + + retval = target_read_u32(target, STM32_OB_WRP2, &option_bytes); + if (retval != ERROR_OK) + return retval; + + stm32x_info->option_bytes.protection |= (((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF)) << 16; return ERROR_OK; } static int stm32x_erase_options(struct flash_bank *bank) { - struct stm32x_flash_bank *stm32x_info = NULL; + struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; - stm32x_info = bank->driver_priv; - /* read current options */ stm32x_read_options(bank); @@ -291,9 +297,9 @@ static int stm32x_erase_options(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - /* clear readout protection and complementary option bytes + /* clear read protection option byte * this will also force a device unlock if set */ - stm32x_info->option_bytes.RDP = stm32x_info->default_rdp; + stm32x_info->option_bytes.rdp = stm32x_info->default_rdp; return ERROR_OK; } @@ -328,14 +334,14 @@ static int stm32x_write_options(struct flash_bank *bank) uint8_t opt_bytes[16]; - target_buffer_set_u16(target, opt_bytes, stm32x_info->option_bytes.RDP); - target_buffer_set_u16(target, opt_bytes + 2, stm32x_info->option_bytes.user_options); - target_buffer_set_u16(target, opt_bytes + 4, stm32x_info->option_bytes.user_data & 0xff); - target_buffer_set_u16(target, opt_bytes + 6, (stm32x_info->option_bytes.user_data >> 8) & 0xff); - target_buffer_set_u16(target, opt_bytes + 8, stm32x_info->option_bytes.protection[0]); - target_buffer_set_u16(target, opt_bytes + 10, stm32x_info->option_bytes.protection[1]); - target_buffer_set_u16(target, opt_bytes + 12, stm32x_info->option_bytes.protection[2]); - target_buffer_set_u16(target, opt_bytes + 14, stm32x_info->option_bytes.protection[3]); + target_buffer_set_u16(target, opt_bytes, stm32x_info->option_bytes.rdp); + target_buffer_set_u16(target, opt_bytes + 2, stm32x_info->option_bytes.user); + target_buffer_set_u16(target, opt_bytes + 4, stm32x_info->option_bytes.data & 0xff); + target_buffer_set_u16(target, opt_bytes + 6, (stm32x_info->option_bytes.data >> 8) & 0xff); + target_buffer_set_u16(target, opt_bytes + 8, stm32x_info->option_bytes.protection & 0xff); + target_buffer_set_u16(target, opt_bytes + 10, (stm32x_info->option_bytes.protection >> 8) & 0xff); + target_buffer_set_u16(target, opt_bytes + 12, (stm32x_info->option_bytes.protection >> 16) & 0xff); + target_buffer_set_u16(target, opt_bytes + 14, (stm32x_info->option_bytes.protection >> 24) & 0xff); uint32_t offset = STM32_OB_RDP - bank->base; retval = stm32x_write_block(bank, opt_bytes, offset, sizeof(opt_bytes) / 2); @@ -355,64 +361,21 @@ static int stm32x_write_options(struct flash_bank *bank) static int stm32x_protect_check(struct flash_bank *bank) { struct target *target = bank->target; - struct stm32x_flash_bank *stm32x_info = bank->driver_priv; - uint32_t protection; - int i, s; - int num_bits; - int set; int retval = stm32x_check_operation_supported(bank); if (ERROR_OK != retval) return retval; - /* medium density - each bit refers to a 4bank protection - * high density - each bit refers to a 2bank protection */ + /* medium density - each bit refers to a 4 sector protection block + * high density - each bit refers to a 2 sector protection block + * bit 31 refers to all remaining sectors in a bank */ retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &protection); if (retval != ERROR_OK) return retval; - /* medium density - each protection bit is for 4 * 1K pages - * high density - each protection bit is for 2 * 2K pages */ - num_bits = (bank->num_sectors / stm32x_info->ppage_size); - - if (stm32x_info->ppage_size == 2) { - /* high density flash/connectivity line protection */ - - set = 1; - - if (protection & (1 << 31)) - set = 0; - - /* bit 31 controls sector 62 - 255 protection for high density - * bit 31 controls sector 62 - 127 protection for connectivity line */ - for (s = 62; s < bank->num_sectors; s++) - bank->sectors[s].is_protected = set; - - if (bank->num_sectors > 61) - num_bits = 31; - - for (i = 0; i < num_bits; i++) { - set = 1; - - if (protection & (1 << i)) - set = 0; - - for (s = 0; s < stm32x_info->ppage_size; s++) - bank->sectors[(i * stm32x_info->ppage_size) + s].is_protected = set; - } - } else { - /* low/medium density flash protection */ - for (i = 0; i < num_bits; i++) { - set = 1; - - if (protection & (1 << i)) - set = 0; - - for (s = 0; s < stm32x_info->ppage_size; s++) - bank->sectors[(i * stm32x_info->ppage_size) + s].is_protected = set; - } - } + for (int i = 0; i < bank->num_prot_blocks; i++) + bank->prot_blocks[i].is_protected = (protection & (1 << i)) ? 0 : 1; return ERROR_OK; } @@ -467,14 +430,8 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) static int stm32x_protect(struct flash_bank *bank, int set, int first, int last) { - struct stm32x_flash_bank *stm32x_info = NULL; struct target *target = bank->target; - uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; - int i, reg, bit; - int status; - uint32_t protection; - - stm32x_info = bank->driver_priv; + struct stm32x_flash_bank *stm32x_info = bank->driver_priv; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -482,80 +439,20 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last) } int retval = stm32x_check_operation_supported(bank); - if (ERROR_OK != retval) - return retval; - - if ((first % stm32x_info->ppage_size) != 0) { - LOG_WARNING("aligned start protect sector to a %d sector boundary", - stm32x_info->ppage_size); - first = first - (first % stm32x_info->ppage_size); - } - if (((last + 1) % stm32x_info->ppage_size) != 0) { - LOG_WARNING("aligned end protect sector to a %d sector boundary", - stm32x_info->ppage_size); - last++; - last = last - (last % stm32x_info->ppage_size); - last--; - } - - /* medium density - each bit refers to a 4bank protection - * high density - each bit refers to a 2bank protection */ - retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &protection); if (retval != ERROR_OK) return retval; - prot_reg[0] = (uint16_t)protection; - prot_reg[1] = (uint16_t)(protection >> 8); - prot_reg[2] = (uint16_t)(protection >> 16); - prot_reg[3] = (uint16_t)(protection >> 24); + retval = stm32x_erase_options(bank); + if (retval != ERROR_OK) + return retval; - if (stm32x_info->ppage_size == 2) { - /* high density flash */ - - /* bit 7 controls sector 62 - 255 protection */ - if (last > 61) { - if (set) - prot_reg[3] &= ~(1 << 7); - else - prot_reg[3] |= (1 << 7); - } - - if (first > 61) - first = 62; - if (last > 61) - last = 61; - - for (i = first; i <= last; i++) { - reg = (i / stm32x_info->ppage_size) / 8; - bit = (i / stm32x_info->ppage_size) - (reg * 8); - - if (set) - prot_reg[reg] &= ~(1 << bit); - else - prot_reg[reg] |= (1 << bit); - } - } else { - /* medium density flash */ - for (i = first; i <= last; i++) { - reg = (i / stm32x_info->ppage_size) / 8; - bit = (i / stm32x_info->ppage_size) - (reg * 8); - - if (set) - prot_reg[reg] &= ~(1 << bit); - else - prot_reg[reg] |= (1 << bit); - } + for (int i = first; i <= last; i++) { + if (set) + stm32x_info->option_bytes.protection &= ~(1 << i); + else + stm32x_info->option_bytes.protection |= (1 << i); } - status = stm32x_erase_options(bank); - if (status != ERROR_OK) - return status; - - stm32x_info->option_bytes.protection[0] = prot_reg[0]; - stm32x_info->option_bytes.protection[1] = prot_reg[1]; - stm32x_info->option_bytes.protection[2] = prot_reg[2]; - stm32x_info->option_bytes.protection[3] = prot_reg[3]; - return stm32x_write_options(bank); } @@ -808,7 +705,6 @@ static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_i static int stm32x_probe(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; - int i; uint16_t flash_size_in_kb; uint16_t max_flash_size_in_kb; uint32_t device_id; @@ -820,8 +716,8 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->user_data_offset = 10; stm32x_info->option_offset = 0; - /* default factory protection level */ - stm32x_info->default_rdp = 0x5AA5; + /* default factory read protection level 0 */ + stm32x_info->default_rdp = 0xA5; /* read stm32 device id register */ int retval = stm32x_get_device_id(bank, &device_id); @@ -863,7 +759,8 @@ static int stm32x_probe(struct flash_bank *bank) max_flash_size_in_kb = 256; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; - stm32x_info->default_rdp = 0x55AA; + stm32x_info->default_rdp = 0xAA; + stm32x_info->can_load_options = true; break; case 0x446: /* stm32f303xD/E */ page_size = 2048; @@ -871,7 +768,8 @@ static int stm32x_probe(struct flash_bank *bank) max_flash_size_in_kb = 512; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; - stm32x_info->default_rdp = 0x55AA; + stm32x_info->default_rdp = 0xAA; + stm32x_info->can_load_options = true; break; case 0x428: /* value line High density */ page_size = 2048; @@ -890,7 +788,8 @@ static int stm32x_probe(struct flash_bank *bank) max_flash_size_in_kb = 256; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; - stm32x_info->default_rdp = 0x55AA; + stm32x_info->default_rdp = 0xAA; + stm32x_info->can_load_options = true; break; case 0x438: /* stm32f33x */ case 0x439: /* stm32f302x6/8 */ @@ -899,7 +798,8 @@ static int stm32x_probe(struct flash_bank *bank) max_flash_size_in_kb = 64; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; - stm32x_info->default_rdp = 0x55AA; + stm32x_info->default_rdp = 0xAA; + stm32x_info->can_load_options = true; break; case 0x440: /* stm32f05x */ case 0x444: /* stm32f03x */ @@ -909,7 +809,8 @@ static int stm32x_probe(struct flash_bank *bank) max_flash_size_in_kb = 64; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; - stm32x_info->default_rdp = 0x55AA; + stm32x_info->default_rdp = 0xAA; + stm32x_info->can_load_options = true; break; case 0x448: /* stm32f07x */ case 0x442: /* stm32f09x */ @@ -918,7 +819,8 @@ static int stm32x_probe(struct flash_bank *bank) max_flash_size_in_kb = 256; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; - stm32x_info->default_rdp = 0x55AA; + stm32x_info->default_rdp = 0xAA; + stm32x_info->can_load_options = true; break; default: LOG_WARNING("Cannot identify target as a STM32 family."); @@ -972,17 +874,31 @@ static int stm32x_probe(struct flash_bank *bank) bank->sectors = NULL; } + if (bank->prot_blocks) { + free(bank->prot_blocks); + bank->prot_blocks = NULL; + } + bank->base = base_address; bank->size = (num_pages * page_size); - bank->num_sectors = num_pages; - bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); - for (i = 0; i < num_pages; i++) { - bank->sectors[i].offset = i * page_size; - bank->sectors[i].size = page_size; - bank->sectors[i].is_erased = -1; - bank->sectors[i].is_protected = 1; - } + bank->num_sectors = num_pages; + bank->sectors = alloc_block_array(0, page_size, num_pages); + if (!bank->sectors) + return ERROR_FAIL; + + /* calculate number of write protection blocks */ + int num_prot_blocks = num_pages / stm32x_info->ppage_size; + if (num_prot_blocks > 32) + num_prot_blocks = 32; + + bank->num_prot_blocks = num_prot_blocks; + bank->prot_blocks = alloc_block_array(0, stm32x_info->ppage_size * page_size, num_prot_blocks); + if (!bank->prot_blocks) + return ERROR_FAIL; + + if (num_prot_blocks == 32) + bank->prot_blocks[31].size = (num_pages - (31 * stm32x_info->ppage_size)) * page_size; stm32x_info->probed = 1; @@ -1275,7 +1191,7 @@ COMMAND_HANDLER(stm32x_handle_lock_command) } /* set readout protection */ - stm32x_info->option_bytes.RDP = 0; + stm32x_info->option_bytes.rdp = 0; if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD_CTX, "stm32x failed to lock device"); @@ -1329,7 +1245,7 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) COMMAND_HANDLER(stm32x_handle_options_read_command) { - uint32_t optionbyte; + uint32_t optionbyte, protection; struct target *target = NULL; struct stm32x_flash_bank *stm32x_info = NULL; @@ -1357,47 +1273,38 @@ COMMAND_HANDLER(stm32x_handle_options_read_command) retval = target_read_u32(target, STM32_FLASH_OBR_B0, &optionbyte); if (retval != ERROR_OK) return retval; - command_print(CMD_CTX, "Option Byte: 0x%" PRIx32 "", optionbyte); - int user_data = optionbyte; + uint16_t user_data = optionbyte >> stm32x_info->user_data_offset; - if (optionbyte >> OPT_ERROR & 1) - command_print(CMD_CTX, "Option Byte Complement Error"); + retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &protection); + if (retval != ERROR_OK) + return retval; - if (optionbyte >> OPT_READOUT & 1) - command_print(CMD_CTX, "Readout Protection On"); - else - command_print(CMD_CTX, "Readout Protection Off"); + if (optionbyte & (1 << OPT_ERROR)) + command_print(CMD_CTX, "option byte complement error"); + + command_print(CMD_CTX, "option byte register = 0x%" PRIx32 "", optionbyte); + command_print(CMD_CTX, "write protection register = 0x%" PRIx32 "", protection); + + command_print(CMD_CTX, "read protection: %s", + (optionbyte & (1 << OPT_READOUT)) ? "on" : "off"); /* user option bytes are offset depending on variant */ optionbyte >>= stm32x_info->option_offset; - if (optionbyte >> OPT_RDWDGSW & 1) - command_print(CMD_CTX, "Software Watchdog"); - else - command_print(CMD_CTX, "Hardware Watchdog"); + command_print(CMD_CTX, "watchdog: %sware", + (optionbyte & (1 << OPT_RDWDGSW)) ? "soft" : "hard"); - if (optionbyte >> OPT_RDRSTSTOP & 1) - command_print(CMD_CTX, "Stop: No reset generated"); - else - command_print(CMD_CTX, "Stop: Reset generated"); + command_print(CMD_CTX, "stop mode: %sreset generated upon entry", + (optionbyte & (1 << OPT_RDRSTSTOP)) ? "no " : ""); - if (optionbyte >> OPT_RDRSTSTDBY & 1) - command_print(CMD_CTX, "Standby: No reset generated"); - else - command_print(CMD_CTX, "Standby: Reset generated"); + command_print(CMD_CTX, "standby mode: %sreset generated upon entry", + (optionbyte & (1 << OPT_RDRSTSTDBY)) ? "no " : ""); - if (stm32x_info->has_dual_banks) { - if (optionbyte >> OPT_BFB2 & 1) - command_print(CMD_CTX, "Boot: Bank 0"); - else - command_print(CMD_CTX, "Boot: Bank 1"); - } + if (stm32x_info->has_dual_banks) + command_print(CMD_CTX, "boot: bank %d", (optionbyte & (1 << OPT_BFB2)) ? 0 : 1); - command_print(CMD_CTX, "User Option0: 0x%02" PRIx8, - (uint8_t)((user_data >> stm32x_info->user_data_offset) & 0xff)); - command_print(CMD_CTX, "User Option1: 0x%02" PRIx8, - (uint8_t)((user_data >> (stm32x_info->user_data_offset + 8)) & 0xff)); + command_print(CMD_CTX, "user data = 0x%02" PRIx16 "", user_data); return ERROR_OK; } @@ -1434,7 +1341,7 @@ COMMAND_HANDLER(stm32x_handle_options_write_command) return retval; /* start with current options */ - optionbyte = stm32x_info->option_bytes.user_options; + optionbyte = stm32x_info->option_bytes.user; /* skip over flash bank */ CMD_ARGC--; @@ -1471,7 +1378,7 @@ COMMAND_HANDLER(stm32x_handle_options_write_command) return ERROR_OK; } - stm32x_info->option_bytes.user_options = optionbyte; + stm32x_info->option_bytes.user = optionbyte; if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD_CTX, "stm32x failed to write options"); @@ -1479,8 +1386,55 @@ COMMAND_HANDLER(stm32x_handle_options_write_command) } command_print(CMD_CTX, "stm32x write options complete.\n" - "INFO: a reset or power cycle is required " - "for the new settings to take effect."); + "INFO: %spower cycle is required " + "for the new settings to take effect.", + stm32x_info->can_load_options + ? "'stm32f1x options_load' command or " : ""); + + return ERROR_OK; +} + +COMMAND_HANDLER(stm32x_handle_options_load_command) +{ + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + struct stm32x_flash_bank *stm32x_info = bank->driver_priv; + + if (!stm32x_info->can_load_options) { + LOG_ERROR("Command not applicable to stm32f1x devices - power cycle is " + "required instead."); + return ERROR_FAIL; + } + + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = stm32x_check_operation_supported(bank); + if (ERROR_OK != retval) + return retval; + + /* unlock option flash registers */ + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); + if (retval != ERROR_OK) + return retval; + + /* force re-load of option bytes - generates software reset */ + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OBL_LAUNCH); + if (retval != ERROR_OK) + return retval; return ERROR_OK; } @@ -1574,7 +1528,7 @@ static const struct command_registration stm32x_exec_command_handlers[] = { .handler = stm32x_handle_options_read_command, .mode = COMMAND_EXEC, .usage = "bank_id", - .help = "Read and display device option byte.", + .help = "Read and display device option bytes.", }, { .name = "options_write", @@ -1583,7 +1537,14 @@ static const struct command_registration stm32x_exec_command_handlers[] = { .usage = "bank_id ('SWWDG'|'HWWDG') " "('RSTSTNDBY'|'NORSTSTNDBY') " "('RSTSTOP'|'NORSTSTOP')", - .help = "Replace bits in device option byte.", + .help = "Replace bits in device option bytes.", + }, + { + .name = "options_load", + .handler = stm32x_handle_options_load_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Force re-load of device option bytes.", }, COMMAND_REGISTRATION_DONE }; From e63dab08986e7ec28acdb0bcc592305239810a48 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 31 Oct 2018 17:57:59 +0100 Subject: [PATCH 138/147] target/cortex_a: remove unused code controlled by "fast_reg_read" The variable fast_reg_read is always zero, causing some code to never be executed. Such code try to read the target registers by dumping them in memory and then reading back the memory through the debugger. But it is broken due to lack of cache and MMU management. This code also uses the broken memory_ap access that is going to be removed soon. Remove all the code that depends on fast_reg_read not zero. Add a missing check on arm_dpm_read_current_registers() return. Keep the unused function cortex_a_dap_write_coreregister_u32() to balance the used "read" version. Change-Id: If2ff28a8c49eb0a87dc85207f5431978efd158db Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4746 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/cortex_a.c | 87 +++---------------------------------------- src/target/cortex_a.h | 3 -- 2 files changed, 6 insertions(+), 84 deletions(-) diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index e209c801c..21943f220 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -307,32 +307,6 @@ static int cortex_a_exec_opcode(struct target *target, return retval; } -/************************************************************************** -Read core register with very few exec_opcode, fast but needs work_area. -This can cause problems with MMU active. -**************************************************************************/ -static int cortex_a_read_regs_through_mem(struct target *target, uint32_t address, - uint32_t *regfile) -{ - int retval = ERROR_OK; - struct armv7a_common *armv7a = target_to_armv7a(target); - - retval = cortex_a_dap_read_coreregister_u32(target, regfile, 0); - if (retval != ERROR_OK) - return retval; - retval = cortex_a_dap_write_coreregister_u32(target, address, 0); - if (retval != ERROR_OK) - return retval; - retval = cortex_a_exec_opcode(target, ARMV4_5_STMIA(0, 0xFFFE, 0, 0), NULL); - if (retval != ERROR_OK) - return retval; - - retval = mem_ap_read_buf(armv7a->memory_ap, - (uint8_t *)(®file[1]), 4, 15, address); - - return retval; -} - static int cortex_a_dap_read_coreregister_u32(struct target *target, uint32_t *value, int regnum) { @@ -395,6 +369,7 @@ static int cortex_a_dap_read_coreregister_u32(struct target *target, return retval; } +__attribute__((unused)) static int cortex_a_dap_write_coreregister_u32(struct target *target, uint32_t value, int regnum) { @@ -1183,10 +1158,8 @@ static int cortex_a_resume(struct target *target, int current, static int cortex_a_debug_entry(struct target *target) { - int i; - uint32_t regfile[16], cpsr, spsr, dscr; + uint32_t spsr, dscr; int retval = ERROR_OK; - struct working_area *regfile_working_area = NULL; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; @@ -1227,56 +1200,10 @@ static int cortex_a_debug_entry(struct target *target) arm_dpm_report_wfar(&armv7a->dpm, wfar); } - /* REVISIT fast_reg_read is never set ... */ - - /* Examine target state and mode */ - if (cortex_a->fast_reg_read) - target_alloc_working_area(target, 64, ®file_working_area); - - - /* First load register acessible through core debug port*/ - if (!regfile_working_area) - retval = arm_dpm_read_current_registers(&armv7a->dpm); - else { - retval = cortex_a_read_regs_through_mem(target, - regfile_working_area->address, regfile); - - target_free_working_area(target, regfile_working_area); - if (retval != ERROR_OK) - return retval; - - /* read Current PSR */ - retval = cortex_a_dap_read_coreregister_u32(target, &cpsr, 16); - /* store current cpsr */ - if (retval != ERROR_OK) - return retval; - - LOG_DEBUG("cpsr: %8.8" PRIx32, cpsr); - - arm_set_cpsr(arm, cpsr); - - /* update cache */ - for (i = 0; i <= ARM_PC; i++) { - reg = arm_reg_current(arm, i); - - buf_set_u32(reg->value, 0, 32, regfile[i]); - reg->valid = 1; - reg->dirty = 0; - } - - /* Fixup PC Resume Address */ - if (cpsr & (1 << 5)) { - /* T bit set for Thumb or ThumbEE state */ - regfile[ARM_PC] -= 4; - } else { - /* ARM state */ - regfile[ARM_PC] -= 8; - } - - reg = arm->pc; - buf_set_u32(reg->value, 0, 32, regfile[ARM_PC]); - reg->dirty = reg->valid; - } + /* First load register accessible through core debug port */ + retval = arm_dpm_read_current_registers(&armv7a->dpm); + if (retval != ERROR_OK) + return retval; if (arm->spsr) { /* read Saved PSR */ @@ -3174,8 +3101,6 @@ static int cortex_a_init_arch_info(struct target *target, cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; armv7a->arm.dap = dap; - cortex_a->fast_reg_read = 0; - /* register arch-specific functions */ armv7a->examine_debug_reason = NULL; diff --git a/src/target/cortex_a.h b/src/target/cortex_a.h index ff0343208..197a5992d 100644 --- a/src/target/cortex_a.h +++ b/src/target/cortex_a.h @@ -93,9 +93,6 @@ struct cortex_a_common { int brp_num_available; struct cortex_a_brp *brp_list; - /* Use cortex_a_read_regs_through_mem for fast register reads */ - int fast_reg_read; - uint32_t cpuid; uint32_t didr; From fac9be64d9444138c77ffe45078a85e063593a38 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 31 Oct 2018 18:13:06 +0100 Subject: [PATCH 139/147] target/cortex_a: remove buggy memory AP accesses The armv7m debug port provides a direct access to the CPU memory bus, allowing the debugger to bypass the CPU for every memory operation. The armv7a debug port doesn't offer the same feature, mainly because CPU caches and MMU makes the direct memory access more tricky. Nevertheless most SoC with armv7a provide direct memory access through an AHB bus available on another DAP access port, different from the debug port. The original port of cortex_a in OpenOCD was inspired from the working cortex_m code, and provided optional memory access through the AHB, if present. The code for AHB access is problematic and partially buggy due to incomplete management of cache coherency and missing check of page boundary during virtual address operations. With the commit 5d458cf72734a4474f38bbed10eea4d9acfe93a2 ("target/mem_ap: generic mem-ap target") we have a clean support for memory access through system buses connected to DAP AP, which obsoletes the buggy memory AP hack in cortex_a. Remove any code that uses the memory AP accesses in cortex_a. Change-Id: I7cd1f94885e5817448058953e043d8da90dea3cc Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4748 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/armv7a.h | 2 - src/target/cortex_a.c | 150 +++--------------------------------------- 2 files changed, 10 insertions(+), 142 deletions(-) diff --git a/src/target/armv7a.h b/src/target/armv7a.h index 57779c61a..cf938809a 100644 --- a/src/target/armv7a.h +++ b/src/target/armv7a.h @@ -106,8 +106,6 @@ struct armv7a_common { struct arm_dpm dpm; uint32_t debug_base; struct adiv5_ap *debug_ap; - struct adiv5_ap *memory_ap; - bool memory_ap_available; /* mdir */ uint8_t multi_processor_system; uint8_t cluster_id; diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 21943f220..2768e18cf 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -2622,9 +2622,6 @@ static int cortex_a_read_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; - uint8_t apsel = swjdp->apsel; int retval; if (!count || !buffer) @@ -2633,9 +2630,6 @@ static int cortex_a_read_phys_memory(struct target *target, LOG_DEBUG("Reading memory at real address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, address, size, count); - if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num)) - return mem_ap_read_buf(armv7a->memory_ap, buffer, size, count, address); - /* read memory through the CPU */ cortex_a_prep_memaccess(target, 1); retval = cortex_a_read_cpu_memory(target, address, size, count, buffer); @@ -2660,57 +2654,10 @@ static int cortex_a_read_memory(struct target *target, target_addr_t address, return retval; } -static int cortex_a_read_memory_ahb(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) -{ - int mmu_enabled = 0; - target_addr_t virt, phys; - int retval; - struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; - uint8_t apsel = swjdp->apsel; - - if (!armv7a->memory_ap_available || (apsel != armv7a->memory_ap->ap_num)) - return target_read_memory(target, address, size, count, buffer); - - /* cortex_a handles unaligned memory access */ - LOG_DEBUG("Reading memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, - address, size, count); - - /* determine if MMU was enabled on target stop */ - if (!armv7a->is_armv7r) { - retval = cortex_a_mmu(target, &mmu_enabled); - if (retval != ERROR_OK) - return retval; - } - - if (mmu_enabled) { - virt = address; - retval = cortex_a_virt2phys(target, virt, &phys); - if (retval != ERROR_OK) - return retval; - - LOG_DEBUG("Reading at virtual address. " - "Translating v:" TARGET_ADDR_FMT " to r:" TARGET_ADDR_FMT, - virt, phys); - address = phys; - } - - if (!count || !buffer) - return ERROR_COMMAND_SYNTAX_ERROR; - - retval = mem_ap_read_buf(armv7a->memory_ap, buffer, size, count, address); - - return retval; -} - static int cortex_a_write_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; - uint8_t apsel = swjdp->apsel; int retval; if (!count || !buffer) @@ -2719,9 +2666,6 @@ static int cortex_a_write_phys_memory(struct target *target, LOG_DEBUG("Writing memory to real address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, address, size, count); - if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num)) - return mem_ap_write_buf(armv7a->memory_ap, buffer, size, count, address); - /* write memory through the CPU */ cortex_a_prep_memaccess(target, 1); retval = cortex_a_write_cpu_memory(target, address, size, count, buffer); @@ -2748,51 +2692,6 @@ static int cortex_a_write_memory(struct target *target, target_addr_t address, return retval; } -static int cortex_a_write_memory_ahb(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) -{ - int mmu_enabled = 0; - target_addr_t virt, phys; - int retval; - struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; - uint8_t apsel = swjdp->apsel; - - if (!armv7a->memory_ap_available || (apsel != armv7a->memory_ap->ap_num)) - return target_write_memory(target, address, size, count, buffer); - - /* cortex_a handles unaligned memory access */ - LOG_DEBUG("Writing memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, - address, size, count); - - /* determine if MMU was enabled on target stop */ - if (!armv7a->is_armv7r) { - retval = cortex_a_mmu(target, &mmu_enabled); - if (retval != ERROR_OK) - return retval; - } - - if (mmu_enabled) { - virt = address; - retval = cortex_a_virt2phys(target, virt, &phys); - if (retval != ERROR_OK) - return retval; - - LOG_DEBUG("Writing to virtual address. " - "Translating v:" TARGET_ADDR_FMT " to r:" TARGET_ADDR_FMT, - virt, - phys); - address = phys; - } - - if (!count || !buffer) - return ERROR_COMMAND_SYNTAX_ERROR; - - retval = mem_ap_write_buf(armv7a->memory_ap, buffer, size, count, address); - - return retval; -} - static int cortex_a_read_buffer(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer) { @@ -2802,7 +2701,7 @@ static int cortex_a_read_buffer(struct target *target, target_addr_t address, * will have something to do with the size we leave to it. */ for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) { if (address & size) { - int retval = cortex_a_read_memory_ahb(target, address, size, 1, buffer); + int retval = target_read_memory(target, address, size, 1, buffer); if (retval != ERROR_OK) return retval; address += size; @@ -2815,7 +2714,7 @@ static int cortex_a_read_buffer(struct target *target, target_addr_t address, for (; size > 0; size /= 2) { uint32_t aligned = count - count % size; if (aligned > 0) { - int retval = cortex_a_read_memory_ahb(target, address, size, aligned / size, buffer); + int retval = target_read_memory(target, address, size, aligned / size, buffer); if (retval != ERROR_OK) return retval; address += aligned; @@ -2836,7 +2735,7 @@ static int cortex_a_write_buffer(struct target *target, target_addr_t address, * will have something to do with the size we leave to it. */ for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) { if (address & size) { - int retval = cortex_a_write_memory_ahb(target, address, size, 1, buffer); + int retval = target_write_memory(target, address, size, 1, buffer); if (retval != ERROR_OK) return retval; address += size; @@ -2849,7 +2748,7 @@ static int cortex_a_write_buffer(struct target *target, target_addr_t address, for (; size > 0; size /= 2) { uint32_t aligned = count - count % size; if (aligned > 0) { - int retval = cortex_a_write_memory_ahb(target, address, size, aligned / size, buffer); + int retval = target_write_memory(target, address, size, aligned / size, buffer); if (retval != ERROR_OK) return retval; address += aligned; @@ -2927,21 +2826,6 @@ static int cortex_a_examine_first(struct target *target) armv7a->debug_ap->memaccess_tck = 80; - /* Search for the AHB-AB. - * REVISIT: We should search for AXI-AP as well and make sure the AP's MEMTYPE says it - * can access system memory. */ - armv7a->memory_ap_available = false; - retval = dap_find_ap(swjdp, AP_TYPE_AHB_AP, &armv7a->memory_ap); - if (retval == ERROR_OK) { - retval = mem_ap_init(armv7a->memory_ap); - if (retval == ERROR_OK) - armv7a->memory_ap_available = true; - } - if (retval != ERROR_OK) { - /* AHB-AP not found or unavailable - use the CPU */ - LOG_DEBUG("No AHB-AP available for memory access"); - } - if (!target->dbgbase_set) { uint32_t dbgbase; /* Get ROM Table base */ @@ -3185,10 +3069,7 @@ static int cortex_a_mmu(struct target *target, int *enabled) static int cortex_a_virt2phys(struct target *target, target_addr_t virt, target_addr_t *phys) { - int retval = ERROR_FAIL; - struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; - uint8_t apsel = swjdp->apsel; + int retval; int mmu_enabled = 0; /* @@ -3203,23 +3084,12 @@ static int cortex_a_virt2phys(struct target *target, return ERROR_OK; } - if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num)) { - uint32_t ret; - retval = armv7a_mmu_translate_va(target, - virt, &ret); - if (retval != ERROR_OK) - goto done; - *phys = ret; - } else {/* use this method if armv7a->memory_ap not selected - * mmu must be enable in order to get a correct translation */ - retval = cortex_a_mmu_modify(target, 1); - if (retval != ERROR_OK) - goto done; - retval = armv7a_mmu_translate_va_pa(target, (uint32_t)virt, + /* mmu must be enable in order to get a correct translation */ + retval = cortex_a_mmu_modify(target, 1); + if (retval != ERROR_OK) + return retval; + return armv7a_mmu_translate_va_pa(target, (uint32_t)virt, (uint32_t *)phys, 1); - } -done: - return retval; } COMMAND_HANDLER(cortex_a_handle_cache_info_command) From cf9c0fba9bae1eead383db94a9865f34eac6c811 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 3 Nov 2018 14:52:30 +0100 Subject: [PATCH 140/147] target/arm_dpm: uniform names of exported functions The name of the function dpm_modeswitch() does not follow the common style of the other function names in the same file. Rename it as arm_dpm_modeswitch(). Change-Id: Idebf3c7bbddcd9b3c7b44f8d0dea1e5f7549b0eb Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4756 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/arm_dpm.c | 20 ++++++++++---------- src/target/arm_dpm.h | 2 +- src/target/cortex_a.c | 10 +++++----- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index f9b30c187..9bab96f7e 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -108,7 +108,7 @@ static int dpm_mcr(struct target *target, int cpnum, /* Toggles between recorded core mode (USR, SVC, etc) and a temporary one. * Routines *must* restore the original mode before returning!! */ -int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) +int arm_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) { int retval; uint32_t cpsr; @@ -543,7 +543,7 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) /* REVISIT error checks */ if (tmode != ARM_MODE_ANY) { - retval = dpm_modeswitch(dpm, tmode); + retval = arm_dpm_modeswitch(dpm, tmode); if (retval != ERROR_OK) goto done; } @@ -564,7 +564,7 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) * or it's dirty. Must write PC to ensure the return address is * defined, and must not write it before CPSR. */ - retval = dpm_modeswitch(dpm, ARM_MODE_ANY); + retval = arm_dpm_modeswitch(dpm, ARM_MODE_ANY); if (retval != ERROR_OK) goto done; arm->cpsr->dirty = false; @@ -671,7 +671,7 @@ static int arm_dpm_read_core_reg(struct target *target, struct reg *r, return retval; if (mode != ARM_MODE_ANY) { - retval = dpm_modeswitch(dpm, mode); + retval = arm_dpm_modeswitch(dpm, mode); if (retval != ERROR_OK) goto fail; } @@ -682,7 +682,7 @@ static int arm_dpm_read_core_reg(struct target *target, struct reg *r, /* always clean up, regardless of error */ if (mode != ARM_MODE_ANY) - /* (void) */ dpm_modeswitch(dpm, ARM_MODE_ANY); + /* (void) */ arm_dpm_modeswitch(dpm, ARM_MODE_ANY); fail: /* (void) */ dpm->finish(dpm); @@ -715,7 +715,7 @@ static int arm_dpm_write_core_reg(struct target *target, struct reg *r, return retval; if (mode != ARM_MODE_ANY) { - retval = dpm_modeswitch(dpm, mode); + retval = arm_dpm_modeswitch(dpm, mode); if (retval != ERROR_OK) goto fail; } @@ -724,7 +724,7 @@ static int arm_dpm_write_core_reg(struct target *target, struct reg *r, /* always clean up, regardless of error */ if (mode != ARM_MODE_ANY) - /* (void) */ dpm_modeswitch(dpm, ARM_MODE_ANY); + /* (void) */ arm_dpm_modeswitch(dpm, ARM_MODE_ANY); fail: /* (void) */ dpm->finish(dpm); @@ -773,9 +773,9 @@ static int arm_dpm_full_context(struct target *target) * in FIQ mode we need to patch mode. */ if (mode != ARM_MODE_ANY) - retval = dpm_modeswitch(dpm, mode); + retval = arm_dpm_modeswitch(dpm, mode); else - retval = dpm_modeswitch(dpm, ARM_MODE_USR); + retval = arm_dpm_modeswitch(dpm, ARM_MODE_USR); if (retval != ERROR_OK) goto done; @@ -793,7 +793,7 @@ static int arm_dpm_full_context(struct target *target) } while (did_read); - retval = dpm_modeswitch(dpm, ARM_MODE_ANY); + retval = arm_dpm_modeswitch(dpm, ARM_MODE_ANY); /* (void) */ dpm->finish(dpm); done: return retval; diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h index f8d124813..ea6b25a60 100644 --- a/src/target/arm_dpm.h +++ b/src/target/arm_dpm.h @@ -153,7 +153,7 @@ int arm_dpm_setup(struct arm_dpm *dpm); int arm_dpm_initialize(struct arm_dpm *dpm); int arm_dpm_read_current_registers(struct arm_dpm *); -int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode); +int arm_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode); int arm_dpm_write_dirty_registers(struct arm_dpm *, bool bpwp); diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 2768e18cf..77859d3e8 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -113,7 +113,7 @@ static int cortex_a_prep_memaccess(struct target *target, int phys_access) int mmu_enabled = 0; if (phys_access == 0) { - dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); + arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); cortex_a_mmu(target, &mmu_enabled); if (mmu_enabled) cortex_a_mmu_modify(target, 1); @@ -148,7 +148,7 @@ static int cortex_a_post_memaccess(struct target *target, int phys_access) 0, 0, 3, 0, cortex_a->cp15_dacr_reg); } - dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); + arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); } else { int mmu_enabled = 0; cortex_a_mmu(target, &mmu_enabled); @@ -1011,7 +1011,7 @@ static int cortex_a_internal_restore(struct target *target, int current, arm->pc->valid = 1; /* restore dpm_mode at system halt */ - dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); + arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); /* called it now before restoring context because it uses cpu * register r0 for restoring cp15 control register */ retval = cortex_a_restore_cp15_control_reg(target); @@ -1277,7 +1277,7 @@ static int cortex_a_post_debug_entry(struct target *target) cortex_a->curr_mode = armv7a->arm.core_mode; /* switch to SVC mode to read DACR */ - dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); + arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); armv7a->arm.mrc(target, 15, 0, 0, 3, 0, &cortex_a->cp15_dacr_reg); @@ -1285,7 +1285,7 @@ static int cortex_a_post_debug_entry(struct target *target) LOG_DEBUG("cp15_dacr_reg: %8.8" PRIx32, cortex_a->cp15_dacr_reg); - dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); + arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); return ERROR_OK; } From 29c81a80510aa82b1842b15a9b091a3062cb51dc Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 7 Oct 2018 16:27:27 +0200 Subject: [PATCH 141/147] target/cortex_a: remove duplicate code to read target registers The functions cortex_a_dap_{read,write}_coreregister_u32() are duplicate of the functions dpm_{read,write}_reg(). Remove both duplicated functions in cortex_a.c while export only dpm_read_reg(), since dpm_write_reg() is currently not used. Rename dpm_read_reg() as arm_dpm_read_reg() to keep uniform the naming style. Change-Id: I501bc99dc402039e630c47917a086a0bb382782c Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4747 Reviewed-by: Matthias Welwarsky Tested-by: jenkins --- src/target/arm_dpm.c | 10 +-- src/target/arm_dpm.h | 1 + src/target/cortex_a.c | 158 +----------------------------------------- 3 files changed, 9 insertions(+), 160 deletions(-) diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index 9bab96f7e..8b9957033 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -168,7 +168,7 @@ static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) } /* just read the register -- rely on the core mode being right */ -static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { uint32_t value; int retval; @@ -352,7 +352,7 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm) for (unsigned i = 0; i < 2; i++) { r = arm->core_cache->reg_list + i; if (!r->valid) { - retval = dpm_read_reg(dpm, r, i); + retval = arm_dpm_read_reg(dpm, r, i); if (retval != ERROR_OK) goto fail; } @@ -372,7 +372,7 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm) if (r->valid) continue; - retval = dpm_read_reg(dpm, r, i); + retval = arm_dpm_read_reg(dpm, r, i); if (retval != ERROR_OK) goto fail; } @@ -676,7 +676,7 @@ static int arm_dpm_read_core_reg(struct target *target, struct reg *r, goto fail; } - retval = dpm_read_reg(dpm, r, regnum); + retval = arm_dpm_read_reg(dpm, r, regnum); if (retval != ERROR_OK) goto fail; /* always clean up, regardless of error */ @@ -784,7 +784,7 @@ static int arm_dpm_full_context(struct target *target) continue; /* CPSR was read, so "R16" must mean SPSR */ - retval = dpm_read_reg(dpm, + retval = arm_dpm_read_reg(dpm, &cache->reg_list[i], (r->num == 16) ? 17 : r->num); if (retval != ERROR_OK) diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h index ea6b25a60..d05c66c43 100644 --- a/src/target/arm_dpm.h +++ b/src/target/arm_dpm.h @@ -152,6 +152,7 @@ struct arm_dpm { int arm_dpm_setup(struct arm_dpm *dpm); int arm_dpm_initialize(struct arm_dpm *dpm); +int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum); int arm_dpm_read_current_registers(struct arm_dpm *); int arm_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode); diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 77859d3e8..73fb8e0f5 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -71,10 +71,6 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint); static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); -static int cortex_a_dap_read_coreregister_u32(struct target *target, - uint32_t *value, int regnum); -static int cortex_a_dap_write_coreregister_u32(struct target *target, - uint32_t value, int regnum); static int cortex_a_mmu(struct target *target, int *enabled); static int cortex_a_mmu_modify(struct target *target, int enable); static int cortex_a_virt2phys(struct target *target, @@ -307,147 +303,6 @@ static int cortex_a_exec_opcode(struct target *target, return retval; } -static int cortex_a_dap_read_coreregister_u32(struct target *target, - uint32_t *value, int regnum) -{ - int retval = ERROR_OK; - uint8_t reg = regnum&0xFF; - uint32_t dscr = 0; - struct armv7a_common *armv7a = target_to_armv7a(target); - - if (reg > 17) - return retval; - - if (reg < 15) { - /* Rn to DCCTX, "MCR p14, 0, Rn, c0, c5, 0" 0xEE00nE15 */ - retval = cortex_a_exec_opcode(target, - ARMV4_5_MCR(14, 0, reg, 0, 5, 0), - &dscr); - if (retval != ERROR_OK) - return retval; - } else if (reg == 15) { - /* "MOV r0, r15"; then move r0 to DCCTX */ - retval = cortex_a_exec_opcode(target, 0xE1A0000F, &dscr); - if (retval != ERROR_OK) - return retval; - retval = cortex_a_exec_opcode(target, - ARMV4_5_MCR(14, 0, 0, 0, 5, 0), - &dscr); - if (retval != ERROR_OK) - return retval; - } else { - /* "MRS r0, CPSR" or "MRS r0, SPSR" - * then move r0 to DCCTX - */ - retval = cortex_a_exec_opcode(target, ARMV4_5_MRS(0, reg & 1), &dscr); - if (retval != ERROR_OK) - return retval; - retval = cortex_a_exec_opcode(target, - ARMV4_5_MCR(14, 0, 0, 0, 5, 0), - &dscr); - if (retval != ERROR_OK) - return retval; - } - - /* Wait for DTRRXfull then read DTRRTX */ - int64_t then = timeval_ms(); - while ((dscr & DSCR_DTR_TX_FULL) == 0) { - retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DSCR, &dscr); - if (retval != ERROR_OK) - return retval; - if (timeval_ms() > then + 1000) { - LOG_ERROR("Timeout waiting for cortex_a_exec_opcode"); - return ERROR_FAIL; - } - } - - retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DTRTX, value); - LOG_DEBUG("read DCC 0x%08" PRIx32, *value); - - return retval; -} - -__attribute__((unused)) -static int cortex_a_dap_write_coreregister_u32(struct target *target, - uint32_t value, int regnum) -{ - int retval = ERROR_OK; - uint8_t Rd = regnum&0xFF; - uint32_t dscr; - struct armv7a_common *armv7a = target_to_armv7a(target); - - LOG_DEBUG("register %i, value 0x%08" PRIx32, regnum, value); - - /* Check that DCCRX is not full */ - retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DSCR, &dscr); - if (retval != ERROR_OK) - return retval; - if (dscr & DSCR_DTR_RX_FULL) { - LOG_ERROR("DSCR_DTR_RX_FULL, dscr 0x%08" PRIx32, dscr); - /* Clear DCCRX with MRC(p14, 0, Rd, c0, c5, 0), opcode 0xEE100E15 */ - retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), - &dscr); - if (retval != ERROR_OK) - return retval; - } - - if (Rd > 17) - return retval; - - /* Write DTRRX ... sets DSCR.DTRRXfull but exec_opcode() won't care */ - LOG_DEBUG("write DCC 0x%08" PRIx32, value); - retval = mem_ap_write_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DTRRX, value); - if (retval != ERROR_OK) - return retval; - - if (Rd < 15) { - /* DCCRX to Rn, "MRC p14, 0, Rn, c0, c5, 0", 0xEE10nE15 */ - retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, Rd, 0, 5, 0), - &dscr); - - if (retval != ERROR_OK) - return retval; - } else if (Rd == 15) { - /* DCCRX to R0, "MRC p14, 0, R0, c0, c5, 0", 0xEE100E15 - * then "mov r15, r0" - */ - retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), - &dscr); - if (retval != ERROR_OK) - return retval; - retval = cortex_a_exec_opcode(target, 0xE1A0F000, &dscr); - if (retval != ERROR_OK) - return retval; - } else { - /* DCCRX to R0, "MRC p14, 0, R0, c0, c5, 0", 0xEE100E15 - * then "MSR CPSR_cxsf, r0" or "MSR SPSR_cxsf, r0" (all fields) - */ - retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), - &dscr); - if (retval != ERROR_OK) - return retval; - retval = cortex_a_exec_opcode(target, ARMV4_5_MSR_GP(0, 0xF, Rd & 1), - &dscr); - if (retval != ERROR_OK) - return retval; - - /* "Prefetch flush" after modifying execution status in CPSR */ - if (Rd == 16) { - retval = cortex_a_exec_opcode(target, - ARMV4_5_MCR(15, 0, 0, 7, 5, 4), - &dscr); - if (retval != ERROR_OK) - return retval; - } - } - - return retval; -} - /* Write to memory mapped registers directly with no cache or mmu handling */ static int cortex_a_dap_write_memap_register_u32(struct target *target, uint32_t address, @@ -1158,12 +1013,11 @@ static int cortex_a_resume(struct target *target, int current, static int cortex_a_debug_entry(struct target *target) { - uint32_t spsr, dscr; + uint32_t dscr; int retval = ERROR_OK; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; - struct reg *reg; LOG_DEBUG("dscr = 0x%08" PRIx32, cortex_a->cpudbg_dscr); @@ -1206,16 +1060,10 @@ static int cortex_a_debug_entry(struct target *target) return retval; if (arm->spsr) { - /* read Saved PSR */ - retval = cortex_a_dap_read_coreregister_u32(target, &spsr, 17); - /* store current spsr */ + /* read SPSR */ + retval = arm_dpm_read_reg(&armv7a->dpm, arm->spsr, 17); if (retval != ERROR_OK) return retval; - - reg = arm->spsr; - buf_set_u32(reg->value, 0, 32, spsr); - reg->valid = 1; - reg->dirty = 0; } #if 0 From 010b09121ca08f955921654c6a3d405be80afef1 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Thu, 14 Jul 2016 21:00:59 +0200 Subject: [PATCH 142/147] armv7a: ARMv7-A MMU tools factor out mmu-related code from armv7a.c, add a 'dump' command for page tables. Change-Id: Ic1ac3c645d7fd097e9d625c7c8302e7065875dd4 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4327 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Matthias Welwarsky --- doc/openocd.texi | 6 + src/target/Makefile.am | 2 + src/target/armv7a.c | 169 +-------------- src/target/armv7a.h | 3 - src/target/armv7a_mmu.c | 456 ++++++++++++++++++++++++++++++++++++++++ src/target/armv7a_mmu.h | 28 +++ src/target/cortex_a.c | 4 + 7 files changed, 497 insertions(+), 171 deletions(-) create mode 100644 src/target/armv7a_mmu.c create mode 100644 src/target/armv7a_mmu.h diff --git a/doc/openocd.texi b/doc/openocd.texi index ac81b35ed..e7d0c67c5 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8766,6 +8766,12 @@ Selects whether interrupts will be processed when single stepping configure l2x cache @end deffn +@deffn Command {cortex_a mmu dump} [@option{0}|@option{1}|@option{addr} address [@option{num_entries}]] +Dump the MMU translation table from TTB0 or TTB1 register, or from physical +memory location @var{address}. When dumping the table from @var{address}, print at most +@var{num_entries} page table entries. @var{num_entries} is optional, if omitted, the maximum +possible (4096) entries are printed. +@end deffn @subsection ARMv7-R specific commands @cindex Cortex-R diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 05f174870..8e9fcb27e 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -75,6 +75,7 @@ ARMV7_SRC = \ %D%/armv7m_trace.c \ %D%/cortex_m.c \ %D%/armv7a.c \ + %D%/armv7a_mmu.c \ %D%/cortex_a.c \ %D%/ls1_sap.c \ %D%/mem_ap.c @@ -152,6 +153,7 @@ ESIRISC_SRC = \ %D%/arm_adi_v5.h \ %D%/armv7a_cache.h \ %D%/armv7a_cache_l2x.h \ + %D%/armv7a_mmu.h \ %D%/arm_disassembler.h \ %D%/arm_opcodes.h \ %D%/arm_simulator.h \ diff --git a/src/target/armv7a.c b/src/target/armv7a.c index eecfa7097..f9594c9c3 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -24,6 +24,7 @@ #include #include "armv7a.h" +#include "armv7a_mmu.h" #include "arm_disassembler.h" #include "register.h" @@ -188,174 +189,6 @@ done: return retval; } -/* method adapted to Cortex-A : reused ARM v4 v5 method */ -int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val) -{ - uint32_t first_lvl_descriptor = 0x0; - uint32_t second_lvl_descriptor = 0x0; - int retval; - struct armv7a_common *armv7a = target_to_armv7a(target); - uint32_t ttbidx = 0; /* default to ttbr0 */ - uint32_t ttb_mask; - uint32_t va_mask; - uint32_t ttb; - - if (target->state != TARGET_HALTED) - LOG_INFO("target not halted, using cached values for translation table!"); - - /* if va is above the range handled by ttbr0, select ttbr1 */ - if (va > armv7a->armv7a_mmu.ttbr_range[0]) { - /* select ttb 1 */ - ttbidx = 1; - } - - ttb = armv7a->armv7a_mmu.ttbr[ttbidx]; - ttb_mask = armv7a->armv7a_mmu.ttbr_mask[ttbidx]; - va_mask = 0xfff00000 & armv7a->armv7a_mmu.ttbr_range[ttbidx]; - - LOG_DEBUG("ttb_mask %" PRIx32 " va_mask %" PRIx32 " ttbidx %i", - ttb_mask, va_mask, ttbidx); - retval = armv7a->armv7a_mmu.read_physical_memory(target, - (ttb & ttb_mask) | ((va & va_mask) >> 18), - 4, 1, (uint8_t *)&first_lvl_descriptor); - if (retval != ERROR_OK) - return retval; - first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *) - &first_lvl_descriptor); - /* reuse armv4_5 piece of code, specific armv7a changes may come later */ - LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor); - - if ((first_lvl_descriptor & 0x3) == 0) { - LOG_ERROR("Address translation failure"); - return ERROR_TARGET_TRANSLATION_FAULT; - } - - - if ((first_lvl_descriptor & 0x40002) == 2) { - /* section descriptor */ - *val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff); - return ERROR_OK; - } else if ((first_lvl_descriptor & 0x40002) == 0x40002) { - /* supersection descriptor */ - if (first_lvl_descriptor & 0x00f001e0) { - LOG_ERROR("Physical address does not fit into 32 bits"); - return ERROR_TARGET_TRANSLATION_FAULT; - } - *val = (first_lvl_descriptor & 0xff000000) | (va & 0x00ffffff); - return ERROR_OK; - } - - /* page table */ - retval = armv7a->armv7a_mmu.read_physical_memory(target, - (first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10), - 4, 1, (uint8_t *)&second_lvl_descriptor); - if (retval != ERROR_OK) - return retval; - - second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *) - &second_lvl_descriptor); - - LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor); - - if ((second_lvl_descriptor & 0x3) == 0) { - LOG_ERROR("Address translation failure"); - return ERROR_TARGET_TRANSLATION_FAULT; - } - - if ((second_lvl_descriptor & 0x3) == 1) { - /* large page descriptor */ - *val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff); - } else { - /* small page descriptor */ - *val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff); - } - - return ERROR_OK; -} - -/* V7 method VA TO PA */ -int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, - uint32_t *val, int meminfo) -{ - int retval = ERROR_FAIL; - struct armv7a_common *armv7a = target_to_armv7a(target); - struct arm_dpm *dpm = armv7a->arm.dpm; - uint32_t virt = va & ~0xfff; - uint32_t NOS, NS, INNER, OUTER; - *val = 0xdeadbeef; - retval = dpm->prepare(dpm); - if (retval != ERROR_OK) - goto done; - /* mmu must be enable in order to get a correct translation - * use VA to PA CP15 register for conversion */ - retval = dpm->instr_write_data_r0(dpm, - ARMV4_5_MCR(15, 0, 0, 7, 8, 0), - virt); - if (retval != ERROR_OK) - goto done; - retval = dpm->instr_read_data_r0(dpm, - ARMV4_5_MRC(15, 0, 0, 7, 4, 0), - val); - /* decode memory attribute */ - NOS = (*val >> 10) & 1; /* Not Outer shareable */ - NS = (*val >> 9) & 1; /* Non secure */ - INNER = (*val >> 4) & 0x7; - OUTER = (*val >> 2) & 0x3; - - if (retval != ERROR_OK) - goto done; - *val = (*val & ~0xfff) + (va & 0xfff); - if (*val == va) - LOG_WARNING("virt = phys : MMU disable !!"); - if (meminfo) { - LOG_INFO("%" PRIx32 " : %" PRIx32 " %s outer shareable %s secured", - va, *val, - NOS == 1 ? "not" : " ", - NS == 1 ? "not" : ""); - switch (OUTER) { - case 0: - LOG_INFO("outer: Non-Cacheable"); - break; - case 1: - LOG_INFO("outer: Write-Back, Write-Allocate"); - break; - case 2: - LOG_INFO("outer: Write-Through, No Write-Allocate"); - break; - case 3: - LOG_INFO("outer: Write-Back, no Write-Allocate"); - break; - } - switch (INNER) { - case 0: - LOG_INFO("inner: Non-Cacheable"); - break; - case 1: - LOG_INFO("inner: Strongly-ordered"); - break; - case 3: - LOG_INFO("inner: Device"); - break; - case 5: - LOG_INFO("inner: Write-Back, Write-Allocate"); - break; - case 6: - LOG_INFO("inner: Write-Through"); - break; - case 7: - LOG_INFO("inner: Write-Back, no Write-Allocate"); - break; - default: - LOG_INFO("inner: %" PRIx32 " ???", INNER); - } - } - -done: - dpm->finish(dpm); - - return retval; -} - /* FIXME: remove it */ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way) { diff --git a/src/target/armv7a.h b/src/target/armv7a.h index cf938809a..1e88c98cf 100644 --- a/src/target/armv7a.h +++ b/src/target/armv7a.h @@ -186,9 +186,6 @@ static inline bool is_armv7a(struct armv7a_common *armv7a) int armv7a_arch_state(struct target *target); int armv7a_identify_cache(struct target *target); int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a); -int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, - uint32_t *val, int meminfo); -int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val); int armv7a_handle_cache_info_command(struct command_context *cmd_ctx, struct armv7a_cache_common *armv7a_cache); diff --git a/src/target/armv7a_mmu.c b/src/target/armv7a_mmu.c new file mode 100644 index 000000000..eed73ee58 --- /dev/null +++ b/src/target/armv7a_mmu.c @@ -0,0 +1,456 @@ +/*************************************************************************** + * Copyright (C) 2016 by Matthias Welwarsky * + * matthias.welwarsky@sysgo.com * + * * + * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com * + * * + * 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 . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "jtag/interface.h" +#include "arm.h" +#include "armv7a.h" +#include "armv7a_mmu.h" +#include "arm_opcodes.h" +#include "cortex_a.h" + +#define SCTLR_BIT_AFE (1 << 29) + +/* method adapted to Cortex-A : reused ARM v4 v5 method */ +int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val) +{ + uint32_t first_lvl_descriptor = 0x0; + uint32_t second_lvl_descriptor = 0x0; + int retval; + struct armv7a_common *armv7a = target_to_armv7a(target); + uint32_t ttbidx = 0; /* default to ttbr0 */ + uint32_t ttb_mask; + uint32_t va_mask; + uint32_t ttb; + + if (target->state != TARGET_HALTED) + LOG_INFO("target not halted, using cached values for translation table!"); + + /* if va is above the range handled by ttbr0, select ttbr1 */ + if (va > armv7a->armv7a_mmu.ttbr_range[0]) { + /* select ttb 1 */ + ttbidx = 1; + } + + ttb = armv7a->armv7a_mmu.ttbr[ttbidx]; + ttb_mask = armv7a->armv7a_mmu.ttbr_mask[ttbidx]; + va_mask = 0xfff00000 & armv7a->armv7a_mmu.ttbr_range[ttbidx]; + + LOG_DEBUG("ttb_mask %" PRIx32 " va_mask %" PRIx32 " ttbidx %i", + ttb_mask, va_mask, ttbidx); + retval = armv7a->armv7a_mmu.read_physical_memory(target, + (ttb & ttb_mask) | ((va & va_mask) >> 18), + 4, 1, (uint8_t *)&first_lvl_descriptor); + if (retval != ERROR_OK) + return retval; + first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *) + &first_lvl_descriptor); + /* reuse armv4_5 piece of code, specific armv7a changes may come later */ + LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor); + + if ((first_lvl_descriptor & 0x3) == 0) { + LOG_ERROR("Address translation failure"); + return ERROR_TARGET_TRANSLATION_FAULT; + } + + if ((first_lvl_descriptor & 0x40002) == 2) { + /* section descriptor */ + *val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff); + return ERROR_OK; + } else if ((first_lvl_descriptor & 0x40002) == 0x40002) { + /* supersection descriptor */ + if (first_lvl_descriptor & 0x00f001e0) { + LOG_ERROR("Physical address does not fit into 32 bits"); + return ERROR_TARGET_TRANSLATION_FAULT; + } + *val = (first_lvl_descriptor & 0xff000000) | (va & 0x00ffffff); + return ERROR_OK; + } + + /* page table */ + retval = armv7a->armv7a_mmu.read_physical_memory(target, + (first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10), + 4, 1, (uint8_t *)&second_lvl_descriptor); + if (retval != ERROR_OK) + return retval; + + second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *) + &second_lvl_descriptor); + + LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor); + + if ((second_lvl_descriptor & 0x3) == 0) { + LOG_ERROR("Address translation failure"); + return ERROR_TARGET_TRANSLATION_FAULT; + } + + if ((second_lvl_descriptor & 0x3) == 1) { + /* large page descriptor */ + *val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff); + } else { + /* small page descriptor */ + *val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff); + } + + return ERROR_OK; +} + +/* V7 method VA TO PA */ +int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, + uint32_t *val, int meminfo) +{ + int retval = ERROR_FAIL; + struct armv7a_common *armv7a = target_to_armv7a(target); + struct arm_dpm *dpm = armv7a->arm.dpm; + uint32_t virt = va & ~0xfff; + uint32_t NOS, NS, INNER, OUTER; + *val = 0xdeadbeef; + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + /* mmu must be enable in order to get a correct translation + * use VA to PA CP15 register for conversion */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_MCR(15, 0, 0, 7, 8, 0), + virt); + if (retval != ERROR_OK) + goto done; + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 0, 0, 7, 4, 0), + val); + /* decode memory attribute */ + NOS = (*val >> 10) & 1; /* Not Outer shareable */ + NS = (*val >> 9) & 1; /* Non secure */ + INNER = (*val >> 4) & 0x7; + OUTER = (*val >> 2) & 0x3; + + if (retval != ERROR_OK) + goto done; + *val = (*val & ~0xfff) + (va & 0xfff); + if (*val == va) + LOG_WARNING("virt = phys : MMU disable !!"); + if (meminfo) { + LOG_INFO("%" PRIx32 " : %" PRIx32 " %s outer shareable %s secured", + va, *val, + NOS == 1 ? "not" : " ", + NS == 1 ? "not" : ""); + switch (OUTER) { + case 0: + LOG_INFO("outer: Non-Cacheable"); + break; + case 1: + LOG_INFO("outer: Write-Back, Write-Allocate"); + break; + case 2: + LOG_INFO("outer: Write-Through, No Write-Allocate"); + break; + case 3: + LOG_INFO("outer: Write-Back, no Write-Allocate"); + break; + } + switch (INNER) { + case 0: + LOG_INFO("inner: Non-Cacheable"); + break; + case 1: + LOG_INFO("inner: Strongly-ordered"); + break; + case 3: + LOG_INFO("inner: Device"); + break; + case 5: + LOG_INFO("inner: Write-Back, Write-Allocate"); + break; + case 6: + LOG_INFO("inner: Write-Through"); + break; + case 7: + LOG_INFO("inner: Write-Back, no Write-Allocate"); + break; + default: + LOG_INFO("inner: %" PRIx32 " ???", INNER); + } + } + +done: + dpm->finish(dpm); + + return retval; +} + +static const char *desc_bits_to_string(bool c_bit, bool b_bit, bool s_bit, bool ap2, int ap10, bool afe) +{ + static char bits_string[64]; + unsigned int len; + + if (afe) { + bool acc_r = true; + bool acc_w = !ap2; + bool priv = !(ap10 & 2); + len = snprintf(bits_string, sizeof(bits_string), "%s%s%s access%s: %s%s", + s_bit ? "S " : "", c_bit ? "C " : "", b_bit ? "B " : "", + priv ? "(priv)" : "", acc_r ? "R" : "N", acc_w ? "W " : "O "); + } else { + bool priv_acc_w = !ap2; + bool priv_acc_r = true; + bool unpriv_acc_w = priv_acc_w; + bool unpriv_acc_r = priv_acc_r; + + switch (ap10) { + case 0: + priv_acc_r = priv_acc_w = false; + unpriv_acc_r = unpriv_acc_w = false; + break; + case 1: + unpriv_acc_r = unpriv_acc_w = false; + break; + case 2: + unpriv_acc_w = false; + break; + default: + break; + } + + len = snprintf(bits_string, sizeof(bits_string), "%s%s%s access(priv): %s%s access(unpriv): %s%s", + s_bit ? "S " : "", c_bit ? "C " : "", b_bit ? "B " : "", priv_acc_r ? "R" : "N", priv_acc_w ? "W" : "O", + unpriv_acc_r ? "R" : "N", unpriv_acc_w ? "W" : "O"); + } + + if (len >= sizeof(bits_string)) + bits_string[63] = 0; + + return bits_string; +} + +static const char *l2_desc_bits_to_string(uint32_t l2_desc, bool afe) +{ + bool c_bit = !!(l2_desc & (1 << 3)); + bool b_bit = !!(l2_desc & (1 << 2)); + bool s_bit = !!(l2_desc & (1 << 10)); + bool ap2 = !!(l2_desc & (1 << 9)); + int ap10 = (l2_desc >> 4) & 3; + + return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe); +} + +static const char *l1_desc_bits_to_string(uint32_t l1_desc, bool afe) +{ + bool c_bit = !!(l1_desc & (1 << 3)); + bool b_bit = !!(l1_desc & (1 << 2)); + bool s_bit = !!(l1_desc & (1 << 16)); + bool ap2 = !!(l1_desc & (1 << 15)); + int ap10 = (l1_desc >> 10) & 3; + + return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe); +} + +COMMAND_HANDLER(armv7a_mmu_dump_table) +{ + struct target *target = get_current_target(CMD_CTX); + struct cortex_a_common *cortex_a = target_to_cortex_a(target); + struct armv7a_common *armv7a = target_to_armv7a(target); + struct armv7a_mmu_common *mmu = &armv7a->armv7a_mmu; + struct armv7a_cache_common *cache = &mmu->armv7a_cache; + uint32_t *first_lvl_ptbl; + target_addr_t ttb; + int ttbidx = 0; + int retval; + int pt_idx; + int max_pt_idx = 4095; + bool afe; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!strcmp(CMD_ARGV[0], "addr")) { + if (CMD_ARGC < 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[1], ttb); + + if (CMD_ARGC > 2) { + COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], max_pt_idx); + + if (max_pt_idx < 1 || max_pt_idx > 4096) + return ERROR_COMMAND_ARGUMENT_INVALID; + max_pt_idx -= 1; + } + } else { + if (mmu->cached != 1) { + LOG_ERROR("TTB not cached!"); + return ERROR_FAIL; + } + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], ttbidx); + if (ttbidx < 0 || ttbidx > 1) + return ERROR_COMMAND_ARGUMENT_INVALID; + + ttb = mmu->ttbr[ttbidx] & mmu->ttbr_mask[ttbidx]; + + if (ttbidx == 0) { + int ttbcr_n = mmu->ttbcr & 0x7; + max_pt_idx = 0x0fff >> ttbcr_n; + } + } + + LOG_USER("Page Directory at (phys): %8.8" TARGET_PRIxADDR, ttb); + + first_lvl_ptbl = malloc(sizeof(uint32_t)*(max_pt_idx+1)); + if (first_lvl_ptbl == NULL) + return ERROR_FAIL; + + /* + * this may or may not be necessary depending on whether + * the table walker is configured to use the cache or not. + */ + cache->flush_all_data_cache(target); + + retval = mmu->read_physical_memory(target, ttb, 4, max_pt_idx+1, (uint8_t *)first_lvl_ptbl); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read first-level page table!"); + return retval; + } + + afe = !!(cortex_a->cp15_control_reg & SCTLR_BIT_AFE); + + for (pt_idx = 0; pt_idx <= max_pt_idx;) { + uint32_t first_lvl_descriptor = target_buffer_get_u32(target, + (uint8_t *)&first_lvl_ptbl[pt_idx]); + + LOG_DEBUG("L1 desc[%8.8"PRIx32"]: %8.8"PRIx32, pt_idx << 20, first_lvl_descriptor); + + /* skip empty entries in the first level table */ + if ((first_lvl_descriptor & 3) == 0) { + pt_idx++; + } else + if ((first_lvl_descriptor & 0x40002) == 2) { + /* section descriptor */ + uint32_t va_range = 1024*1024-1; /* 1MB range */ + uint32_t va_start = pt_idx << 20; + uint32_t va_end = va_start + va_range; + + uint32_t pa_start = (first_lvl_descriptor & 0xfff00000); + uint32_t pa_end = pa_start + va_range; + + LOG_USER("SECT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s", + va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe)); + pt_idx++; + } else + if ((first_lvl_descriptor & 0x40002) == 0x40002) { + /* supersection descriptor */ + uint32_t va_range = 16*1024*1024-1; /* 16MB range */ + uint32_t va_start = pt_idx << 20; + uint32_t va_end = va_start + va_range; + + uint32_t pa_start = (first_lvl_descriptor & 0xff000000); + uint32_t pa_end = pa_start + va_range; + + LOG_USER("SSCT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s", + va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe)); + + /* skip next 15 entries, they're duplicating the first entry */ + pt_idx += 16; + } else { + target_addr_t second_lvl_ptbl = first_lvl_descriptor & 0xfffffc00; + uint32_t second_lvl_descriptor; + uint32_t *pt2; + int pt2_idx; + + /* page table, always 1KB long */ + pt2 = malloc(1024); + retval = mmu->read_physical_memory(target, second_lvl_ptbl, + 4, 256, (uint8_t *)pt2); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read second-level page table!"); + return ERROR_FAIL; + } + + for (pt2_idx = 0; pt2_idx < 256; ) { + second_lvl_descriptor = target_buffer_get_u32(target, + (uint8_t *)&pt2[pt2_idx]); + + if ((second_lvl_descriptor & 3) == 0) { + /* skip entry */ + pt2_idx++; + } else + if ((second_lvl_descriptor & 3) == 1) { + /* large page */ + uint32_t va_range = 64*1024-1; /* 64KB range */ + uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12); + uint32_t va_end = va_start + va_range; + + uint32_t pa_start = (second_lvl_descriptor & 0xffff0000); + uint32_t pa_end = pa_start + va_range; + + LOG_USER("LPGE: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s", + va_start, va_end, pa_start, pa_end, l2_desc_bits_to_string(second_lvl_descriptor, afe)); + + pt2_idx += 16; + } else { + /* small page */ + uint32_t va_range = 4*1024-1; /* 4KB range */ + uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12); + uint32_t va_end = va_start + va_range; + + uint32_t pa_start = (second_lvl_descriptor & 0xfffff000); + uint32_t pa_end = pa_start + va_range; + + LOG_USER("SPGE: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s", + va_start, va_end, pa_start, pa_end, l2_desc_bits_to_string(second_lvl_descriptor, afe)); + + pt2_idx++; + } + } + free(pt2); + pt_idx++; + } + } + + free(first_lvl_ptbl); + return ERROR_OK; +} + +static const struct command_registration armv7a_mmu_group_handlers[] = { + { + .name = "dump", + .handler = armv7a_mmu_dump_table, + .mode = COMMAND_ANY, + .help = "dump translation table 0, 1 or from
", + .usage = "(0|1|addr
[num_entries])", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration armv7a_mmu_command_handlers[] = { + { + .name = "mmu", + .mode = COMMAND_ANY, + .help = "mmu command group", + .usage = "", + .chain = armv7a_mmu_group_handlers, + }, + COMMAND_REGISTRATION_DONE +}; diff --git a/src/target/armv7a_mmu.h b/src/target/armv7a_mmu.h new file mode 100644 index 000000000..4372aa8eb --- /dev/null +++ b/src/target/armv7a_mmu.h @@ -0,0 +1,28 @@ +/*************************************************************************** + * Copyright (C) 2016 by Matthias Welwarsky * + * matthias.welwarsky@sysgo.com * + * * + * 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 . * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ARMV7A_MMU_H +#define OPENOCD_TARGET_ARMV7A_MMU_H + +extern int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val); +extern int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, + uint32_t *val, int meminfo); + +extern const struct command_registration armv7a_mmu_command_handlers[]; + +#endif /* OPENOCD_TARGET_ARMV7A_MMU_H */ diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 73fb8e0f5..92ba54789 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -50,6 +50,7 @@ #include "breakpoints.h" #include "cortex_a.h" #include "register.h" +#include "armv7a_mmu.h" #include "target_request.h" #include "target_type.h" #include "arm_opcodes.h" @@ -3121,6 +3122,9 @@ static const struct command_registration cortex_a_exec_command_handlers[] = { "on memory access", .usage = "['on'|'off']", }, + { + .chain = armv7a_mmu_command_handlers, + }, COMMAND_REGISTRATION_DONE }; From 8262e8a2c03efa5ddcb780da7174210b4c5da7ca Mon Sep 17 00:00:00 2001 From: xuguangxiao Date: Tue, 23 Oct 2018 15:43:11 +0800 Subject: [PATCH 143/147] jtag/bitq: array boundary overflow The for loop inside bitq_path_move function is not correct, this will overflow the cmd->path array and produces an unpredictable result. Change-Id: I81e3bc9ee6d1dd948acd2fe4c667103ac22bb26f Signed-off-by: xuguangxiao Reviewed-on: http://openocd.zylin.com/4733 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/jtag/drivers/bitq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jtag/drivers/bitq.c b/src/jtag/drivers/bitq.c index 66285f700..55dfe0aa4 100644 --- a/src/jtag/drivers/bitq.c +++ b/src/jtag/drivers/bitq.c @@ -123,7 +123,7 @@ static void bitq_path_move(struct pathmove_command *cmd) { int i; - for (i = 0; i <= cmd->num_states; i++) { + for (i = 0; i < cmd->num_states; i++) { if (tap_state_transition(tap_get_state(), false) == cmd->path[i]) bitq_io(0, 0, 0); else if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) From 5ea55a39753aa570c45cffbdb7c39f6f9a9bb359 Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Fri, 26 Oct 2018 17:05:00 -0700 Subject: [PATCH 144/147] target/stm32h7x: Fix documentation of reset_config The stm32h7x.cfg does not specify connect_assert_srst or connect_deassert_srst in its reset_config. The comment claims that it will therefore connect in reset. However, per the manual, the default configuration is actually connect_deassert_srst, not connect_assert_srst. In actual fact, connect_assert_srst does not work on the STM32H7 because, while SRST is asserted, everything on the AXI bus is inaccessible. The CPU core is accessible, but since the examine-end event handler also pokes at the DBGMCU peripheral, that will fail in connect_assert_srst mode. So using connect_deassert_srst is appropriate, so fix the comment accordingly. Change-Id: If3e32e871fb19cc61183bdf911b7c5efd80b62e2 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4741 Tested-by: jenkins Reviewed-by: Tomas Vanek --- tcl/target/stm32h7x.cfg | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index c9aec7612..0bfc43dfd 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -56,7 +56,17 @@ if {[using_jtag]} { jtag_ntrst_delay 100 } -# use hardware reset, connect under reset +# use hardware reset +# +# The STM32H7 does not support connect_assert_srst mode because the AXI is +# unavailable while SRST is asserted, and that is used to access the DBGMCU +# component at 0x5C001000 in the examine-end event handler. +# +# It is possible to access the DBGMCU component at 0xE00E1000 via AP2 instead +# of the default AP0, and that works with SRST asserted; however, nonzero AP +# usage does not work with HLA, so is not done by default. That change could be +# made in a local configuration file if connect_assert_srst mode is needed for +# a specific application and a non-HLA adapter is in use. reset_config srst_only srst_nogate if {![using_hla]} { From a2a282c7b4501954d99ed30829989df116e5dc43 Mon Sep 17 00:00:00 2001 From: Spencer Oliver Date: Thu, 1 Nov 2018 21:19:48 +0000 Subject: [PATCH 145/147] docs: fix typo in manual Change-Id: I28717105eb2a907b0cb4b03f4b5ff1f47194413b Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/4751 Tested-by: jenkins Reviewed-by: Antonio Borneo --- HACKING | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HACKING b/HACKING index 0d24957e1..b7ef0705b 100644 --- a/HACKING +++ b/HACKING @@ -201,7 +201,7 @@ Further reading: http://www.coreboot.org/Git The code review is intended to take as long as a week or two to allow maintainers and contributors who work on OpenOCD only in their spare -time oportunity to perform a review and raise objections. +time opportunity to perform a review and raise objections. With Gerrit much of the urgency of getting things committed has been removed as the work in progress is safely stored in Gerrit and From 8d914e4d97df45b72fbb6919af1d276f3f69c6f3 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Fri, 14 Sep 2018 17:14:30 +0300 Subject: [PATCH 146/147] README: fix stlink instructions Since 31c58c139d85c35cc8ebce4196edb2c5eb157c7a there is a unified config for all stlink versions. Change-Id: Id736063496ecd96e2024ed69dcb67a22c44b80bb Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4672 Tested-by: jenkins Reviewed-by: Antonio Borneo --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index e1e1b94d3..30443d37c 100644 --- a/README +++ b/README @@ -42,7 +42,7 @@ e.g.: openocd -f interface/ftdi/jtagkey2.cfg -c "transport select jtag" \ -f target/ti_calypso.cfg - openocd -f interface/stlink-v2-1.cfg -c "transport select hla_swd" \ + openocd -f interface/stlink.cfg -c "transport select hla_swd" \ -f target/stm32l0.cfg After OpenOCD startup, connect GDB with From ea41048830f3ef79129fdbf3623d708585929f5b Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Thu, 18 Oct 2018 14:20:45 -0700 Subject: [PATCH 147/147] Permit null target on TCL connection In previous versions of OpenOCD, it was possible to connect to the TCL RPC interface without a current target. In `tcl_new_connection`, the curent target would be queried by number, and the possibility of a null current target was handled properly. In commit bb9d9c60264a905926e0d15f84842858d0de80b7, the `get_target_by_num` call was replaced by a `get_current_target` call, without noticing that `get_current_target` aborts if there is no current target, whereas `tcl_new_connection` is perfectly able to handle that situation. Provide a `get_current_target_or_null` function for use by consumers who are OK with a null current target, and use it in `tcl_new_connection`. Change-Id: I06f7e1e149f1169e23c73ba328c7ad9f9425cc2a Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4730 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Franck Jullien --- src/server/tcl_server.c | 2 +- src/target/target.c | 11 ++++++++--- src/target/target.h | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index 3cb63a275..0676c883b 100644 --- a/src/server/tcl_server.c +++ b/src/server/tcl_server.c @@ -157,7 +157,7 @@ static int tcl_new_connection(struct connection *connection) connection->priv = tclc; - struct target *target = get_current_target(connection->cmd_ctx); + struct target *target = get_current_target_or_null(connection->cmd_ctx); if (target != NULL) tclc->tc_laststate = target->state; diff --git a/src/target/target.c b/src/target/target.c index 871588393..74b332df5 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -517,9 +517,7 @@ struct target *get_target_by_num(int num) struct target *get_current_target(struct command_context *cmd_ctx) { - struct target *target = cmd_ctx->current_target_override - ? cmd_ctx->current_target_override - : cmd_ctx->current_target; + struct target *target = get_current_target_or_null(cmd_ctx); if (target == NULL) { LOG_ERROR("BUG: current_target out of bounds"); @@ -529,6 +527,13 @@ struct target *get_current_target(struct command_context *cmd_ctx) return target; } +struct target *get_current_target_or_null(struct command_context *cmd_ctx) +{ + return cmd_ctx->current_target_override + ? cmd_ctx->current_target_override + : cmd_ctx->current_target; +} + int target_poll(struct target *target) { int retval; diff --git a/src/target/target.h b/src/target/target.h index d79613138..fb9d71465 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -396,6 +396,7 @@ int target_call_timer_callbacks_now(void); struct target *get_target_by_num(int num); struct target *get_current_target(struct command_context *cmd_ctx); +struct target *get_current_target_or_null(struct command_context *cmd_ctx); struct target *get_target(const char *id); /**