From 4ec12dabd57e8f36e20a453e3451b6861263cde6 Mon Sep 17 00:00:00 2001 From: Frank Voorburg Date: Thu, 25 Feb 2016 10:46:45 +0000 Subject: [PATCH] - Added Tricore TC1798 port. git-svn-id: https://svn.code.sf.net/p/openblt/code/trunk@128 5dc33758-31d5-4daf-9ae8-b24bf3d40d73 --- Target/Source/TRICORE_TC1798/GCC/cpu_comp.c | 127 +++ Target/Source/TRICORE_TC1798/GCC/cpu_comp.h | 62 ++ Target/Source/TRICORE_TC1798/GCC/crt0-tc1x.S | 540 +++++++++++ Target/Source/TRICORE_TC1798/GCC/crtn.S | 40 + Target/Source/TRICORE_TC1798/GCC/memory.x | 656 +++++++++++++ Target/Source/TRICORE_TC1798/cpu.c | 140 +++ Target/Source/TRICORE_TC1798/cpu.h | 51 + Target/Source/TRICORE_TC1798/flash.c | 967 +++++++++++++++++++ Target/Source/TRICORE_TC1798/flash.h | 49 + Target/Source/TRICORE_TC1798/nvm.c | 216 +++++ Target/Source/TRICORE_TC1798/nvm.h | 65 ++ Target/Source/TRICORE_TC1798/target.dox | 8 + Target/Source/TRICORE_TC1798/timer.c | 148 +++ Target/Source/TRICORE_TC1798/timer.h | 46 + Target/Source/TRICORE_TC1798/types.h | 63 ++ Target/Source/TRICORE_TC1798/uart.c | 282 ++++++ Target/Source/TRICORE_TC1798/uart.h | 47 + 17 files changed, 3507 insertions(+) create mode 100644 Target/Source/TRICORE_TC1798/GCC/cpu_comp.c create mode 100644 Target/Source/TRICORE_TC1798/GCC/cpu_comp.h create mode 100644 Target/Source/TRICORE_TC1798/GCC/crt0-tc1x.S create mode 100644 Target/Source/TRICORE_TC1798/GCC/crtn.S create mode 100644 Target/Source/TRICORE_TC1798/GCC/memory.x create mode 100644 Target/Source/TRICORE_TC1798/cpu.c create mode 100644 Target/Source/TRICORE_TC1798/cpu.h create mode 100644 Target/Source/TRICORE_TC1798/flash.c create mode 100644 Target/Source/TRICORE_TC1798/flash.h create mode 100644 Target/Source/TRICORE_TC1798/nvm.c create mode 100644 Target/Source/TRICORE_TC1798/nvm.h create mode 100644 Target/Source/TRICORE_TC1798/target.dox create mode 100644 Target/Source/TRICORE_TC1798/timer.c create mode 100644 Target/Source/TRICORE_TC1798/timer.h create mode 100644 Target/Source/TRICORE_TC1798/types.h create mode 100644 Target/Source/TRICORE_TC1798/uart.c create mode 100644 Target/Source/TRICORE_TC1798/uart.h diff --git a/Target/Source/TRICORE_TC1798/GCC/cpu_comp.c b/Target/Source/TRICORE_TC1798/GCC/cpu_comp.c new file mode 100644 index 00000000..a1822bf0 --- /dev/null +++ b/Target/Source/TRICORE_TC1798/GCC/cpu_comp.c @@ -0,0 +1,127 @@ +/************************************************************************************//** +* \file Source\TRICORE_TC1798\GCC\cpu_comp.c +* \brief Bootloader compiler specific cpu module source file. +* \ingroup Target_TRICORE_TC1798 +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2015 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT 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 3 of the License, or (at your option) any later +* version. +* +* OpenBLT 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 OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \endinternal +****************************************************************************************/ + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include "boot.h" /* bootloader generic header */ + + +/**************************************************************************************** +* Local function prototypes +****************************************************************************************/ +static void CpuWriteWDTCON0(blt_int32u uwValue); + + +/************************************************************************************//** +** \brief This macro clears the EndInit bit, which controls access to system critical +** registers. Clearing the EndInit bit unlocks all EndInit protectedd +** registers. Modifications of the EndInit bit are monitored by the watchdog +** timer such that after clearing the EndInit, the watchdog timer enters a +** defined time-out mode; EndInit must be set again before the time-out +** expires. +** \return none. +** +****************************************************************************************/ +void CpuEnterInitMode(void) +{ + /* request clearing of the EndInit bit */ + CpuWriteWDTCON0(WDT_CON0.reg & ~0x00000001); + /* wait for hardware handshake */ + while (WDT_CON0.bits.ENDINIT != 0) + { + /* keep the watchdog happy */ + CopService(); + } +} /*** end of CpuEnterInitMode ***/ + + +/************************************************************************************//** +** \brief This macro sets the EndInit bit, which controls access to system critical +** registers. Setting the EndInit bit locks all EndInit protected registers. +** \return none. +** +****************************************************************************************/ +void CpuLeaveInitMode(void) +{ + /* set the EndInit bit */ + CpuWriteWDTCON0(WDT_CON0.reg | 0x00000001); +} /*** end of CpuLeaveInitMode ***/ + + +/************************************************************************************//** +** \brief Write a new value to the WDTCON0 register. +** \param value New value for the WDTCON0 register. +** \return none. +** +****************************************************************************************/ +static void CpuWriteWDTCON0(blt_int32u value) +{ + blt_int32u dummy; + + /* load current value of the WDTCON0 register */ + dummy = WDT_CON0.reg; + /* set HWPW1 = 1111b */ + dummy |= 0x000000F0; + /* set HWPW0 = WDTDR */ + if(WDT_CON1.bits.DR) + { + dummy |= 0x00000008; + } + else + { + dummy &= ~0x00000008; + } + /* set HWPW0 = WDTIR */ + if(WDT_CON1.bits.IR) + { + dummy |= 0x00000004; + } + else + { + dummy &= ~0x00000004; + } + /* set WDTLCK = 0 */ + dummy &= ~0x00000002; + /* unlock access */ + WDT_CON0.reg = dummy; + /* set HWPW1 = 1111b and WDTLCK = 1 */ + value |= 0x000000F2; + /* set HWPW0 = 00b */ + value &= ~0x0000000C; + /* write access and lock */ + WDT_CON0.reg = value; +} /*** end of CpuWriteWDTCON0 ***/ + + +/*********************************** end of cpu_comp.c *********************************/ diff --git a/Target/Source/TRICORE_TC1798/GCC/cpu_comp.h b/Target/Source/TRICORE_TC1798/GCC/cpu_comp.h new file mode 100644 index 00000000..4e8a53f2 --- /dev/null +++ b/Target/Source/TRICORE_TC1798/GCC/cpu_comp.h @@ -0,0 +1,62 @@ +/************************************************************************************//** +* \file Source\TRICORE_TC1798\GCC\cpu_comp.h +* \brief Bootloader compiler specific cpu module header file. +* \ingroup Target_TRICORE_TC1798 +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2015 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT 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 3 of the License, or (at your option) any later +* version. +* +* OpenBLT 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 OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \endinternal +****************************************************************************************/ +#ifndef CPU_COMP_H +#define CPU_COMP_H + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include +#include +#include +#include + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/** \brief Macro for performing a processor specific desync. This part is located in the + * compiler specific part because it uses an inline assembly call. + */ +#define CpuSetDSYNC() asm("DSYNC") + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +void CpuEnterInitMode(void); +void CpuLeaveInitMode(void); + + +#endif /* CPU_COMP_H */ +/*********************************** end of cpu_comp.h *********************************/ diff --git a/Target/Source/TRICORE_TC1798/GCC/crt0-tc1x.S b/Target/Source/TRICORE_TC1798/GCC/crt0-tc1x.S new file mode 100644 index 00000000..f5db123d --- /dev/null +++ b/Target/Source/TRICORE_TC1798/GCC/crt0-tc1x.S @@ -0,0 +1,540 @@ +/* + * crt0-tc1x.S -- Startup code for GNU/TriCore applications. + * + * Copyright (C) 1998-2012 HighTec EDV-Systeme GmbH. + * + * This file is part of GCC. + * + * GCC 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 3, or (at your option) + * any later version. + * + * GCC 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. + * + * Under Section 7 of GPL version 3, you are granted additional + * permissions described in the GCC Runtime Library Exception, version + * 3.1, as published by the Free Software Foundation. + * + * You should have received a copy of the GNU General Public License and + * a copy of the GCC Runtime Library Exception along with this program; + * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + * . */ + +#ifndef __TRICORE_NAME__ +#error Please define __TRICOR_NAME__ +#endif + +/* define the Derivate Name as a hexvalue + * this name is defined in tricore.specs for specific derivate to + * the derivate number as a hexvalue (e.g. TC1796 => 0x1796 + * This name will be used in the memory.x Memory description to + * to confirm that the crt0.o and the memory.x will be get from + * same directory + */ +.global __TRICORE_DERIVATE_NAME__ +.type __TRICORE_DERIVATE_NAME__,@object +.set __TRICORE_DERIVATE_NAME__,__TRICORE_NAME__ + + .section ".startup_code", "awx", @progbits + .global _start + .type _start,@function +_start: + .code32 + j 0f + + /* + * external boot memory configuration word + */ + .word __EBMCFG + .word __EBMCFG + .word __EBMCFG + .word __EBMCFG + + /* + * default value for this configuration word + */ + .global __EBMCFG + .weak __EBMCFG + __EBMCFG = 0x0000808c +0: + +#; check whether WDTCON0.ENDINIT is set +#; clear it if necessary +#; initialization code must write ENDINIT protected registers + + ld.w %d1,$wdtcon0 # %d1 = *WDTCON0 + jz.t %d1,0,endinit_done + jl asm_clear_endinit +endinit_done: + + /* + * initialize user and interrupt stack pointers + */ + + movh.a %sp,hi:__USTACK # load %sp + lea %sp,[%sp]lo:__USTACK + movh %d0,hi:__ISTACK # load $isp + addi %d0,%d0,lo:__ISTACK + mtcr $isp,%d0 + isync + +#; install trap handlers + + movh %d0,hi:first_trap_table #; load $btv + addi %d0,%d0,lo:first_trap_table + mtcr $btv,%d0 + isync + + /* + * initialize call depth counter + */ + + mfcr %d0,$psw +#ifdef MAX_CALLDEPTH_64 + andn %d0,%d0,0x7f # reset call depth counter + or %d0,%d0,0x80 # set CDE bit +#else + or %d0,%d0,0x7f # disable call depth counting + andn %d0,%d0,0x80 # clear CDE bit +#endif + mtcr $psw,%d0 + isync + + /* + * initialize access to system global registers + */ + + mfcr %d0,$psw + or %d0,%d0,0x100 # set GW bit + mtcr $psw,%d0 + isync + + /* + * initialize SDA base pointers + */ + .global _SMALL_DATA_,_SMALL_DATA2_,_SMALL_DATA3_,_SMALL_DATA4_ + .weak _SMALL_DATA_,_SMALL_DATA2_,_SMALL_DATA3_,_SMALL_DATA4_ + + movh.a %a0,hi:_SMALL_DATA_ # %a0 addresses .sdata/.sbss + lea %a0,[%a0]lo:_SMALL_DATA_ + movh.a %a1,hi:_SMALL_DATA2_ # %a1 addresses .sdata2/.sbss2 + lea %a1,[%a1]lo:_SMALL_DATA2_ + movh.a %a8,hi:_SMALL_DATA3_ # %a8 addresses .sdata3/.sbss3 + lea %a8,[%a8]lo:_SMALL_DATA3_ + movh.a %a9,hi:_SMALL_DATA4_ # %a9 addresses .sdata4/.sbss4 + lea %a9,[%a9]lo:_SMALL_DATA4_ + + +#ifdef READONLY_SYSREGS + mfcr %d0,$psw + andn %d0,%d0,0x100 # clear GW bit + mtcr $psw,%d0 + isync +#endif + + +/* + * initialize target environment (PLLCLC, BUSCONx, ADDSELx etc) + * + * This is done by a user supplied assembler function __board_init + */ +#; force PC to remapped ROM address + movh.a %a15,hi:__remapped + lea %a15,[%a15]lo:__remapped + nop + ji %a15 + +__remapped: + # call _board_init + jl __board_init + +__no_board_init: + + /* + * disable code and data protection + */ + +#ifdef DISABLE_CODE_PROTECTION + mfcr %d0,$cpm0_0 # disable code protection + andn %d0,%d0,0xff + mtcr $cpm0_0,%d0 + isync +#endif +#ifdef DISABLE_DATA_PROTECTION + mfcr %d0,$dpm0_0 # disable data protection + andn %d0,%d0,0xff + mtcr $dpm0_0,%d0 + isync +#endif + + /* + * initialize software break service (OCDS) + */ + +#ifdef INIT_SBS + SRCSB0 = 0xfffeffbc + SWBIPL = 31 + + mov.u %d0,lo:(SWBIPL + 0x00001000) + addih %d0,%d0,hi:(SWBIPL + 0x00001000) + movh.a %a5,hi:SRCSB0 + lea %a5,[%a5]lo:SRCSB0 + st.w [%a5],%d0 +#endif + + /* + * disable watchdog timer and set ENDINIT bit + */ + + jl _disable_wdt + + + + /* + * initialize context save areas + */ + + jl __init_csa + + + + /* + * handle clear table (i.e., fill BSS with zeros) + */ + + jl __clear_table_func + + + /* + * handle copy table (support for romable code) + */ + + jl __copy_table_func + + + /* + * call the initializer, constructors etc. + */ + call _init + + /* + * _exit (main (0, NULL)); + */ + mov %d4,0 # argc = 0 + sub.a %sp,8 + st.w [%sp]0, %d4 + st.w [%sp]4, %d4 + mov.aa %a4, %sp # argv + + call main # int retval = main (0, NULL); + mov %d4,%d2 + lea %sp,[%sp]8 # remove argv[0] + mov.u %d1, 0x900d # set exit code i(A14) for the simulator to + mov %d15, %d2 # 0x900d if the exit status is 0 + movh %d3, 0xffff + or %d2, %d2, %d3 + cmov %d1,%d15,%d2 + mov.a %a14, %d1 + j _exit # _exit (retval); + + debug # should never come here + + + + /* + * disable watchdog timer and set ENDINIT bit + */ + + WDTMASK = 0xffffff03 + WDTMASKA= 0xffffff01 + WDTMASK2= 0xfffffff0 + + .globl _disable_wdt + .type _disable_wdt,function + +_disable_wdt: # lock WDT via passwd access + movh %d2,hi:WDTMASK + addi %d2,%d2,lo:WDTMASK # %d2 = 0xffffff03 + movh %d5,hi:WDTMASK2 # %d5 = 0xfffffff0 + addi %d5,%d5,lo:WDTMASK2 + mov %d6,0x8 # %d6 = "disable WDT" + st.w $wdtcon1,%d6 # WDTCON1.WDTDR = 1 + + ld.w %d0,$wdtcon0 # %d0 = *WDTCON0 + ld.w %d1,$wdtcon1 # %d1 = *WDTCON1 + + and %d3,%d2,%d0 # %d3 = WDTCON0 & 0xffffff03 + or %d3,%d3,0xf0 # %d3 |= 0xf0 + and %d4,%d1,0xc + or %d3,%d3,%d4 # %d3 |= (WDTCON1 & 0xc) + xor %d3,%d3,0x2 # %d3 ^= 0x2 + st.w $wdtcon0,%d3 # WDTCON = %d3 + and %d3,%d3,%d5 # %d3 &= 0xfffffff0 + or %d3,%d3,0x3 # WDTCON0.{WDTLCK,ENDINIT} = 1 + st.w $wdtcon0,%d3 # write back new value + ld.w %d0,$wdtcon0 # ensure that value is written + + ji %a11 + + + + /* + * initialize context save areas (CSAs), PCXI, LCX and FCX + */ + + .globl __init_csa + .type __init_csa,function + +__init_csa: + movh %d0,0 + mtcr $pcxi,%d0 + isync + movh %d0,hi:__CSA_BEGIN #; %d0 = begin of CSA + addi %d0,%d0,lo:__CSA_BEGIN + addi %d0,%d0,63 #; force alignment (2^6) + andn %d0,%d0,63 + movh %d2,hi:__CSA_END #; %d2 = end of CSA + addi %d2,%d2,lo:__CSA_END + andn %d2,%d2,63 #; force alignment (2^6) + sub %d2,%d2,%d0 + sh %d2,%d2,-6 #; %d2 = number of CSAs + mov.a %a3,%d0 #; %a3 = address of first CSA + extr.u %d0,%d0,28,4 #; %d0 = segment << 16 + sh %d0,%d0,16 + lea %a4,0 #; %a4 = previous CSA = 0 + st.a [%a3], %a4 #; store it in 1st CSA + mov.aa %a4,%a3 #; %a4 = current CSA + lea %a3,[%a3]64 #; %a3 = %a3->nextCSA + mov.d %d1,%a3 + extr.u %d1,%d1,6,16 #; get CSA index + or %d1,%d1,%d0 #; add segment number + mtcr $lcx,%d1 #; initialize LCX + add %d2,%d2,-2 #; CSAs to initialize -= 2 + mov.a %a5, %d2 #; %a5 = loop counter +csa_loop: + mov.d %d1,%a4 #; %d1 = current CSA address + extr.u %d1,%d1,6,16 #; get CSA index + or %d1,%d1,%d0 #; add segment number + st.w [%a3],%d1 #; store "nextCSA" pointer + mov.aa %a4,%a3 #; %a4 = current CSA address + lea %a3,[%a3]64 #; %a3 = %a3->nextCSA + loop %a5, csa_loop #; repeat until done + + mov.d %d1,%a4 #; %d1 = current CSA address + extr.u %d1,%d1,6,16 #; get CSA index + or %d1,%d1,%d0 #; add segment number + mtcr $fcx,%d1 #; initialize FCX + isync + ji %a11 + + + + .global asm_clear_endinit + .type asm_clear_endinit,@function + +asm_clear_endinit: + ld.w %d0,$wdtcon0 # %d0 = *WDTCON0 + ld.w %d1,$wdtcon1 # %d1 = *WDTCON1 + + movh %d2,hi:WDTMASKA + addi %d2,%d2,lo:WDTMASKA # %d2 = 0xffffff01 + + and %d0,%d2,%d0 + or %d0,%d0,240 + and %d4,%d1,12 + or %d0,%d4,%d0 + st.w $wdtcon0,%d0 + + movh %d4,hi:WDTMASK2 # %d4 = 0xfffffff0 + addi %d4,%d4,lo:WDTMASK2 + and %d0,%d4,%d0 + or %d0,%d0,2 # ENDINIT = 0 + isync + st.w $wdtcon0,%d0 + ld.w %d0,$wdtcon0 # ensure that value is written + + ji %a11 + + + + /* + * handle clear table (i.e., fill BSS with zeros) + */ + .global __clear_table_func + .type __clear_table_func,@function + +__clear_table_func: + mov %d14,0 # %e14 = 0 + mov %d15,0 + movh.a %a13,hi:__clear_table # %a13 = &first table entry + lea %a13,[%a13]lo:__clear_table + +__clear_table_next: + ld.a %a15,[%a13+]4 # %a15 = current block base + ld.w %d3,[%a13+]4 # %d3 = current block length + jeq %d3,-1,__clear_table_done # length == -1 => end of table + sh %d0,%d3,-3 # %d0 = length / 8 (doublewords) + and %d1,%d3,7 # %d1 = length % 8 (rem. bytes) + jz %d0,__clear_word # block size < 8 => clear word + addi %d0,%d0,-1 # else doublewords -= 1 + mov.a %a2,%d0 # %a2 = loop counter +__clear_dword: + st.d [%a15+]8,%e14 # clear one doubleword + loop %a2,__clear_dword +__clear_word: + jz %d1,__clear_table_next + sh %d0,%d1,-2 # %d0 = length / 4 (words) + and %d1,%d1,3 # %d1 = length % 4 (rem. bytes) + jz %d0,__clear_hword # block size < 4 => clear hword + st.w [%a15+]4,%d15 # clear one word +__clear_hword: + jz %d1,__clear_table_next + sh %d0,%d1,-1 # %d0 = length / 2 (halfwords) + and %d1,%d1,1 # %d1 = length % 2 (rem. bytes) + jz %d0,__clear_byte # block size < 2 => clear byte + st.h [%a15+]2,%d15 # clear one halfword +__clear_byte: + jz %d1,__clear_table_next + st.b [%a15],%d15 # clear one byte + j __clear_table_next # handle next clear table entry +__clear_table_done: + + ji %a11 + + + + /* + * handle copy table (support for romable code) + */ + .global __copy_table_func + .type __copy_table_func,@function + +__copy_table_func: + movh.a %a13,hi:__copy_table # %a13 = &first table entry + lea %a13,[%a13]lo:__copy_table + +__copy_table_next: + ld.a %a15,[%a13+]4 # %a15 = src address + ld.a %a14,[%a13+]4 # %a14 = dst address + ld.w %d3,[%a13+]4 # %d3 = block length + jeq %d3,-1,__copy_table_done # length == -1 => end of table + sh %d0,%d3,-3 # %d0 = length / 8 (doublewords) + and %d1,%d3,7 # %d1 = lenght % 8 (rem. bytes) + jz %d0,__copy_word # block size < 8 => copy word + addi %d0,%d0,-1 # else doublewords -= 1 + mov.a %a2,%d0 # %a2 = loop counter +__copy_dword: + ld.d %e14,[%a15+]8 # copy one doubleword + st.d [%a14+]8,%e14 + loop %a2,__copy_dword +__copy_word: + jz %d1,__copy_table_next + sh %d0,%d1,-2 # %d0 = length / 4 (words) + and %d1,%d1,3 # %d1 = lenght % 4 (rem. bytes) + jz %d0,__copy_hword # block size < 4 => copy hword + ld.w %d14,[%a15+]4 # copy one word + st.w [%a14+]4,%d14 +__copy_hword: + jz %d1,__copy_table_next + sh %d0,%d1,-1 # %d0 = length / 2 (halfwords) + and %d1,%d1,1 # %d1 = lenght % 2 (rem. bytes) + jz %d0,__copy_byte # block size < 2 => copy byte + ld.h %d14,[%a15+]2 # copy one halfword + st.h [%a14+]2,%d14 +__copy_byte: + jz %d1,__copy_table_next + ld.b %d14,[%a15]0 # copy one byte + st.b [%a14],%d14 + j __copy_table_next # handle next copy table entry +__copy_table_done: + + ji %a11 + + +/* + * dummy board initilization function + .global __board_init + .weak __board_init + +__board_init: + ji %a11 + */ + + .global boardSetupTabSize + .weak boardSetupTabSize + .global boardSetupTab + .weak boardSetupTab +boardSetupTab: +boardSetupTabSize: + + + .global __board_init + .type __board_init,@function +__board_init: + .code32 + +#; +#; initialize target environment (PLLCLC, BUSCONx, ADDSELx) +#; +#; this is done by board specific setup table (address/value - pairs) +#; + + movh.a %a15,hi:boardSetupTabSize + lea %a15,[%a15]lo:boardSetupTabSize # %a14 address of table size + movh.a %a14,hi:boardSetupTab + lea %a14,[%a14]lo:boardSetupTab # %a14 address of setup table + jeq.a %a14, %a15, no_setup + + ld.a %a15,[%a15]0 # %a15 = table size + jz.a %a15,no_setup + add.a %a15,-1 # correction for loop +setup_loop: + ld.a %a2,[%a14+] # %a2 = boardSetupTab.addr + ld.w %d2,[%a14+] # %d2 = boardSetupTab.val + st.w [%a2],%d2 + loop %a15,setup_loop + + isync + nop + nop + +no_setup: + + ji %a11 + +/*============================================================================* + * Exception handlers (exceptions in startup code) + * + * This is a minimal trap vector table, which consists of eight + * entries, each consisting of eight words (32 bytes). + *============================================================================*/ + + +#; .section .traptab, "awx", @progbits + +.macro trapentry from=0, to=7 + debug + mov.u %d14, \from << 8 + add %d14, %d14, %d15 + mov.a %a14, %d14 + addih.a %a14, %a14,0xdead + j _exit + 0: j 0b + nop + rfe + .align 5 + .if \to-\from + trapentry "(\from+1)",\to + .endif + .endm + + .align 8 + .globl first_trap_table +first_trap_table: + trapentry 0, 7 + + diff --git a/Target/Source/TRICORE_TC1798/GCC/crtn.S b/Target/Source/TRICORE_TC1798/GCC/crtn.S new file mode 100644 index 00000000..eb882608 --- /dev/null +++ b/Target/Source/TRICORE_TC1798/GCC/crtn.S @@ -0,0 +1,40 @@ +# Copyright (C) 1998-2012 HighTec EDV-Systeme GmbH. +# +# This file is part of GCC. +# +# GCC 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 3, or (at your option) +# any later version. +# +# GCC 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. +# +# Under Section 7 of GPL version 3, you are granted additional +# permissions described in the GCC Runtime Library Exception, version +# 3.1, as published by the Free Software Foundation. +# +# You should have received a copy of the GNU General Public License and +# a copy of the GCC Runtime Library Exception along with this program; +# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +# . */ + +# This file just makes sure that the .fini and .init sections do in +# fact return. Users may put any desired instructions in those sections. +# This file is the last thing linked into any executable. + +# On the tricore we have just to return + + .file "crtn.S" + + .section ".init" + ;; + ret + + .section ".fini" + ;; + ret + +# end of crtn.asm diff --git a/Target/Source/TRICORE_TC1798/GCC/memory.x b/Target/Source/TRICORE_TC1798/GCC/memory.x new file mode 100644 index 00000000..17d977eb --- /dev/null +++ b/Target/Source/TRICORE_TC1798/GCC/memory.x @@ -0,0 +1,656 @@ + +/* + * Name: memory.x + * + * Generated Linker Description File + * Copyright (C) 2010 HighTec EDV-Systeme GmbH. + * (!Do not edit outsite of the protection areas!) + * + * Description: + * internal flash configuration + */ + +/* + * Define Entrypoint of Executable + */ +ENTRY(_start) + +/* + * Global + */ +/*Program Flash Memory (PFLASH0)*/ +__PMU_PFLASH0_BEGIN = 0x80000000; +__PMU_PFLASH0_SIZE = 2M; +/*Program Flash Memory (PFLASH1)*/ +__PMU_PFLASH1_BEGIN = 0x80800000; +__PMU_PFLASH1_SIZE = 2M; +/*Data Flash Memory (DFLASH0)*/ +__PMU_DFLASH0_BEGIN = 0xAF000000; +__PMU_DFLASH0_SIZE = 96K; +/*Data Flash Memory (DFLASH1)*/ +__PMU_DFLASH1_BEGIN = 0xAF080000; +__PMU_DFLASH1_SIZE = 96K; +/*Boot ROM (BROM)*/ +__BROM_BEGIN = 0xAFFFC000; +__BROM_SIZE = 16K; +/*Scratch-Pad RAM (PSPR)*/ +__PMI_PSPR_BEGIN = 0xC0000000; +__PMI_PSPR_SIZE = 32K; +/*Local Data RAM (DSPR)*/ +__DMI_DSPR_BEGIN = 0xD0000000; +__DMI_DSPR_SIZE = 128K; +/*PCP Code Memory (CMEM)*/ +__PCP_CMEM_BEGIN = 0xF0060000; +__PCP_CMEM_SIZE = 32K; +/*PCP Data Memory (PRAM)*/ +__PCP_PRAM_BEGIN = 0xF0050000; +__PCP_PRAM_SIZE = 16K; +/*External Code Memory*/ +__EXT_FLASH_BEGIN = 0x84000000; +__EXT_FLASH_SIZE = 4M; +/*External Data Memory*/ +__EXT_RAM_BEGIN = 0x83000000; +__EXT_RAM_SIZE = 1M; + + +__USTACK_SIZE = DEFINED (__USTACK_SIZE) ? __USTACK_SIZE : 1K; /* Section for ustack*/ +__ISTACK_SIZE = DEFINED (__ISTACK_SIZE) ? __ISTACK_SIZE : 256; /* Section for istack*/ +__HEAP_SIZE = DEFINED (__HEAP_SIZE) ? __HEAP_SIZE : 4K; /* Section for heap*/ +__CSA_SIZE = DEFINED (__CSA_SIZE) ? __CSA_SIZE : 16K; /* Section for CSA*/ + +/** + * User defined global region + */ +/*PROTECTED REGION ID(Protection:iROM-Global) ENABLED START*/ +/*Protection-Area for your own LDF-Code*/ +/*PROTECTED REGION END*/ + +/* + * internal flash configuration + */ +MEMORY +{ + PMU_PFLASH0 (rx!p): org = 0x80000000, len = 2M /*Program Flash Memory (PFLASH0)*/ + PMU_PFLASH1 (rx!p): org = 0x80800000, len = 2M /*Program Flash Memory (PFLASH1)*/ + PMU_DFLASH0 (r!xp): org = 0xAF000000, len = 96K /*Data Flash Memory (DFLASH0)*/ + PMU_DFLASH1 (r!xp): org = 0xAF080000, len = 96K /*Data Flash Memory (DFLASH1)*/ + BROM (rx!p): org = 0xAFFFC000, len = 16K /*Boot ROM (BROM)*/ + PMI_PSPR (wx!p): org = 0xC0000000, len = 32K /*Scratch-Pad RAM (PSPR)*/ + DMI_DSPR (w!xp): org = 0xD0000000, len = 128K /*Local Data RAM (DSPR)*/ + PCP_CMEM (rxp): org = 0xF0060000, len = 32K /*PCP Code Memory (CMEM)*/ + PCP_PRAM (wp!x): org = 0xF0050000, len = 16K /*PCP Data Memory (PRAM)*/ + EXT_FLASH (rx): org = 0x84000000, len = 4M /*External Code Memory*/ + EXT_RAM (w!x): org = 0x83000000, len = 1M /*External Data Memory*/ + +} + +SECTIONS +{ + /*Code-Sections*/ + + /* + * Startup code for TriCore + */ + .startup_code : + { + PROVIDE(__startup_code_start = .); + + /*PROTECTED REGION ID(Protection: iROM .startup_code.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.startup_code) /*Startup code for TriCore*/ + *(.startup_code*) + + /*PROTECTED REGION ID(Protection: iROM .startup_code) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__startup_code_end = .); + . = ALIGN(8); + + } > PMU_PFLASH0 /* PMU_PFLASH0: Program Flash Memory (PFLASH0) */ + + /* + * Code section + */ + .text : + { + PROVIDE(__text_start = .); + + /*PROTECTED REGION ID(Protection: iROM .text.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.text) /*Code section*/ + *(.text*) + *(.gnu.linkonce.t.*) + + /*PROTECTED REGION ID(Protection: iROM .text) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__text_end = .); + . = ALIGN(8); + + } > PMU_PFLASH0 /* PMU_PFLASH0: Program Flash Memory (PFLASH0) */ + + /* + * Code executed before calling main + */ + .init : + { + PROVIDE(__init_start = .); + + /*PROTECTED REGION ID(Protection: iROM .init.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + KEEP(*(.init)) /*Code executed before calling main*/ + KEEP(*(.init*)) + + /*PROTECTED REGION ID(Protection: iROM .init) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__init_end = .); + . = ALIGN(8); + + } > PMU_PFLASH0 /* PMU_PFLASH0: Program Flash Memory (PFLASH0) */ + + /* + * Code executed before exiting program + */ + .fini : + { + PROVIDE(__fini_start = .); + + /*PROTECTED REGION ID(Protection: iROM .fini.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + KEEP(*(.fini)) /*Code executed before exiting program*/ + KEEP(*(.fini*)) + + /*PROTECTED REGION ID(Protection: iROM .fini) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__fini_end = .); + . = ALIGN(8); + + } > PMU_PFLASH0 /* PMU_PFLASH0: Program Flash Memory (PFLASH0) */ + + /* + * Section for trap table + */ + .traptab : + { + PROVIDE(__traptab_start = .); + + /*PROTECTED REGION ID(Protection: iROM .traptab.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.traptab) /*Section for trap table*/ + *(.traptab*) + + /*PROTECTED REGION ID(Protection: iROM .traptab) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__traptab_end = .); + . = ALIGN(8); + + } > PMU_PFLASH0 /* PMU_PFLASH0: Program Flash Memory (PFLASH0) */ + + /* + * Section for interrupt table + */ + .inttab : + { + PROVIDE(__inttab_start = .); + + /*PROTECTED REGION ID(Protection: iROM .inttab.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.inttab) /*Section for interrupt table*/ + *(.inttab*) + + /*PROTECTED REGION ID(Protection: iROM .inttab) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__inttab_end = .); + . = ALIGN(8); + + } > PMU_PFLASH0 /* PMU_PFLASH0: Program Flash Memory (PFLASH0) */ + + /* + * Exception handling frame for C++ exceptions + */ + .eh_frame : + { + PROVIDE(__eh_frame_start = .); + + /*PROTECTED REGION ID(Protection: iROM .eh_frame.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.eh_frame) /*Exception handling frame for C++ exceptions*/ + *(.eh_frame*) + + /*PROTECTED REGION ID(Protection: iROM .eh_frame) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__eh_frame_end = .); + . = ALIGN(8); + + } > PMU_PFLASH0 /* PMU_PFLASH0: Program Flash Memory (PFLASH0) */ + + + + + /*Absolute Data-Sections*/ + + /* + * Initialised data addressed as absolute + */ + .zdata : + { + PROVIDE(__zdata_start = .); + + /*PROTECTED REGION ID(Protection: iROM .zdata.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.zdata) /*Initialised data addressed as absolute*/ + *(.zdata*) + *(.zdata.rodata) /*.zdata.rodata*/ + *(.zdata.rodata*) + *(.zrodata) /*.zrodata*/ + *(.zrodata*) + *(.gnu.linkonce.z.*) + *(.gnu.linkonce.zr.*) + + /*PROTECTED REGION ID(Protection: iROM .zdata) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__zdata_end = .); + . = ALIGN(8); + + } > DMI_DSPR AT > PMU_PFLASH0 /* DMI_DSPR: Local Data RAM (DSPR) */ /* PMU_PFLASH0: Program Flash Memory (PFLASH0) */ + + /* + * Not initialised data addressed as absolute + */ + .zbss (NOLOAD) : + { + PROVIDE(__zbss_start = .); + + /*PROTECTED REGION ID(Protection: iROM .zbss.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.zbss) /*Not Initialised data addressed as absolute*/ + *(.zbss*) + *(.gnu.linkonce.zb.*) + + /*PROTECTED REGION ID(Protection: iROM .zbss) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__zbss_end = .); + . = ALIGN(8); + + } > DMI_DSPR /* DMI_DSPR: Local Data RAM (DSPR) */ + + /* + * Not initialised bit data + */ + .bbss (NOLOAD) : + { + PROVIDE(__bbss_start = .); + + /*PROTECTED REGION ID(Protection: iROM .bbss.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.bbss) /*Not initialised bit data*/ + *(.bbss*) + + /*PROTECTED REGION ID(Protection: iROM .bbss) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__bbss_end = .); + . = ALIGN(8); + + } > DMI_DSPR /* DMI_DSPR: Local Data RAM (DSPR) */ + + /* + * Bit variables + */ + .bdata : + { + PROVIDE(__bdata_start = .); + + /*PROTECTED REGION ID(Protection: iROM .bdata.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.bdata) /*Bit variables*/ + *(.bdata*) + + /*PROTECTED REGION ID(Protection: iROM .bdata) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__bdata_end = .); + . = ALIGN(8); + + } > DMI_DSPR AT > PMU_PFLASH0 /* DMI_DSPR: Local Data RAM (DSPR) */ /* PMU_PFLASH0: Program Flash Memory (PFLASH0) */ + + + + /*Small Data-Sections*/ + + /* + * Storage of write-protected data addressed as small + */ + .sdata2 : + { + PROVIDE(__sdata2_start = .); + + /*PROTECTED REGION ID(Protection: iROM .sdata2.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.sdata.rodata) /*Storage of write-protected data addressed as small*/ + *(.sdata.rodata*) + *(.gnu.linkonce.sr.*) + + /*PROTECTED REGION ID(Protection: iROM .sdata2) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__sdata2_end = .); + . = ALIGN(8); + + } > PMU_PFLASH0 /* PMU_PFLASH0: Program Flash Memory (PFLASH0) */ + + /* + * Section stores initialised data which is addressable by small data area pointer (%a0) + */ + .sdata : + { + PROVIDE(__sdata_start = .); + + /*PROTECTED REGION ID(Protection: iROM .sdata.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.sdata) /*Section stores initialised data which is addressable by small data area pointer (%a0)*/ + *(.sdata*) + *(.gnu.linkonce.s.*) + + /*PROTECTED REGION ID(Protection: iROM .sdata) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__sdata_end = .); + . = ALIGN(8); + + } > DMI_DSPR AT > PMU_PFLASH0 /* DMI_DSPR: Local Data RAM (DSPR) */ /* PMU_PFLASH0: Program Flash Memory (PFLASH0) */ + + /* + * Not initialised data in section ’.sbss’, addressable by small data area pointer (%a0) + */ + .sbss (NOLOAD) : + { + PROVIDE(__sbss_start = .); + + /*PROTECTED REGION ID(Protection: iROM .sbss.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.sbss) /*Not initialised data in section ’.sbss’, addressable by small data area pointer (%a0)*/ + *(.sbss*) + *(.gnu.linkonce.sb.*) + + /*PROTECTED REGION ID(Protection: iROM .sbss) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__sbss_end = .); + . = ALIGN(8); + + } > DMI_DSPR /* DMI_DSPR: Local Data RAM (DSPR) */ + + + + /*Normal Data-Sections*/ + + /* + * Storage of write-protected data + */ + .rodata : + { + PROVIDE(__rodata_start = .); + + /*PROTECTED REGION ID(Protection: iROM .rodata.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.rodata) /*Storage of write-protected data*/ + *(.rodata*) + *(.gnu.linkonce.r.*) + *(.jcr.*) + + /*PROTECTED REGION ID(Protection: iROM .rodata) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__rodata_end = .); + . = ALIGN(8); + + } > PMU_PFLASH0 /* PMU_PFLASH0: Program Flash Memory (PFLASH0) */ + + /* + * Initialised data + */ + .data : + { + PROVIDE(__data_start = .); + + /*PROTECTED REGION ID(Protection: iROM .data.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.data) /*Initialised data*/ + *(.data*) + *(.gnu.linkonce.d.*) + + /*PROTECTED REGION ID(Protection: iROM .data) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__data_end = .); + . = ALIGN(8); + + } > DMI_DSPR AT > PMU_PFLASH0 /* DMI_DSPR: Local Data RAM (DSPR) */ /* PMU_PFLASH0: Program Flash Memory (PFLASH0) */ + + /* + * Not Initialised data + */ + .bss (NOLOAD) : + { + PROVIDE(__bss_start = .); + + /*PROTECTED REGION ID(Protection: iROM .bss.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + *(.bss) /*Not Initialised data*/ + *(.bss*) + *(.gnu.linkonce.b.*) + + /*PROTECTED REGION ID(Protection: iROM .bss) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + + PROVIDE(__bss_end = .); + . = ALIGN(8); + + } > DMI_DSPR /* DMI_DSPR: Local Data RAM (DSPR) */ + + + + + + /* + * Section for constructors + */ + .ctors : + { + __CTOR_LIST__ = . ; + + /*PROTECTED REGION ID(Protection: iROMconstructor.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + LONG(0) ; + /*PROTECTED REGION ID(Protection: iROMconstructor) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + __CTOR_END__ = . ; + . = ALIGN(8); + } > PMU_PFLASH0 + + + /* + * Section for destructors + */ + .dtors : + { + __DTOR_LIST__ = . ; + /*PROTECTED REGION ID(Protection: iROM destructor.begin) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2); + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + LONG(0) ; + /*PROTECTED REGION ID(Protection: iROM destructor) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + __DTOR_END__ = . ; + . = ALIGN(8); + } > PMU_PFLASH0 + + + /* + * Section for clear table + */ + .clear_sec : + { + . = ALIGN(8); + PROVIDE(__clear_table = .) ; + LONG(0 + ADDR(.bss)); LONG(SIZEOF(.bss)); + LONG(0 + ADDR(.sbss)); LONG(SIZEOF(.sbss)); + LONG(0 + ADDR(.zbss)); LONG(SIZEOF(.zbss)); + LONG(0 + ADDR(.bbss)); LONG(SIZEOF(.bbss)); + /*PROTECTED REGION ID(Protection: iROM clear section) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + LONG(-1); LONG(-1); + } > PMU_PFLASH0 + + /* + * Section for copy table + */ + .copy_sec : + { + . = ALIGN(8); + PROVIDE(__copy_table = .) ; + LONG(LOADADDR(.data)); LONG(0 + ADDR(.data)); LONG(SIZEOF(.data)); + LONG(LOADADDR(.sdata)); LONG(0 + ADDR(.sdata)); LONG(SIZEOF(.sdata)); + LONG(LOADADDR(.zdata)); LONG(0 + ADDR(.zdata)); LONG(SIZEOF(.zdata)); + LONG(LOADADDR(.bdata)); LONG(0 + ADDR(.bdata)); LONG(SIZEOF(.bdata)); + /*PROTECTED REGION ID(Protection: iROM copy section) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + LONG(-1); LONG(-1); LONG(-1); + } > PMU_PFLASH0 + + + /* + * Section for ustack + */ + .ustack : + { + . = ALIGN(8); + __USTACK_BEGIN = . ; + . += __USTACK_SIZE ; + . = ALIGN(8); + __USTACK = . ; + __USTACK_END = . ; + } > DMI_DSPR + + /* + * Section for istack + */ + .istack : + { + . = ALIGN(8); + __ISTACK_BEGIN = . ; + . += __ISTACK_SIZE ; + . = ALIGN(8); + __ISTACK = . ; + __ISTACK_END = . ; + } > DMI_DSPR + + /* + * Section for heap + */ + .heap : + { + . = ALIGN(8); + __HEAP_BEGIN = . ; + __HEAP = . ; + . += __HEAP_SIZE ; + . = ALIGN(8); + __HEAP_END = . ; + } > DMI_DSPR + + /* + * Section for CSA + */ + .csa : + { + . = ALIGN(64); + __CSA_BEGIN = . ; + __CSA = . ; + . += __CSA_SIZE ; + . = ALIGN(64); + __CSA_END = . ; + } > DMI_DSPR + + + + + /*PROTECTED REGION ID(Protection:iROM-User-Sections) ENABLED START*/ + /*Protection-Area for your own LDF-Code*/ + /*PROTECTED REGION END*/ + +} + diff --git a/Target/Source/TRICORE_TC1798/cpu.c b/Target/Source/TRICORE_TC1798/cpu.c new file mode 100644 index 00000000..9cb76457 --- /dev/null +++ b/Target/Source/TRICORE_TC1798/cpu.c @@ -0,0 +1,140 @@ +/************************************************************************************//** +* \file Source\TRICORE_TC1798\cpu.c +* \brief Bootloader cpu module source file. +* \ingroup Target_TRICORE_TC1798 +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2015 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT 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 3 of the License, or (at your option) any later +* version. +* +* OpenBLT 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 OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \endinternal +****************************************************************************************/ + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include "boot.h" /* bootloader generic header */ + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/** \brief Pointer to the user program's reset vector. */ +#define CPU_USER_PROGRAM_STARTADDR_PTR ((blt_addr)(FlashGetUserProgBaseAddress())) + + +/**************************************************************************************** +* Hook functions +****************************************************************************************/ +#if (BOOT_CPU_USER_PROGRAM_START_HOOK > 0) +extern blt_bool CpuUserProgramStartHook(void); +#endif + + +/**************************************************************************************** +* External functions +****************************************************************************************/ +extern void _start(void); /* implemented in crt0-tc1x.S */ + + +/************************************************************************************//** +** \brief Starts the user program, if one is present. In this case this function +** does not return. +** \return none. +** +****************************************************************************************/ +void CpuStartUserProgram(void) +{ + void (*pProgResetHandler)(void); + + /* check if a user program is present by verifying the checksum */ + if (NvmVerifyChecksum() == BLT_FALSE) + { + /* not a valid user program so it cannot be started */ + return; + } + #if (BOOT_CPU_USER_PROGRAM_START_HOOK > 0) + /* invoke callback */ + if (CpuUserProgramStartHook() == BLT_FALSE) + { + /* callback requests the user program to not be started */ + return; + } + #endif + #if (BOOT_COM_ENABLE > 0) + /* release the communication interface */ + ComFree(); + #endif + /* reset the timer */ + TimerReset(); + /* set the address where the bootloader needs to jump to. the user program entry, + * typically called _start, is expected to be located at the start of the user program + * flash. + */ + pProgResetHandler = (void(*)(void))((blt_addr*)CPU_USER_PROGRAM_STARTADDR_PTR); + /* start the user program by activating its reset interrupt service routine */ + pProgResetHandler(); +} /*** end of CpuStartUserProgram ***/ + + +/************************************************************************************//** +** \brief Copies data from the source to the destination address. +** \param dest Destination address for the data. +** \param src Source address of the data. +** \param len length of the data in bytes. +** \return none. +** +****************************************************************************************/ +void CpuMemCopy(blt_addr dest, blt_addr src, blt_int16u len) +{ + blt_int8u *from, *to; + + /* set casted pointers */ + from = (blt_int8u *)src; + to = (blt_int8u *)dest; + + /* copy all bytes from source address to destination address */ + while(len-- > 0) + { + /* store byte value from source to destination */ + *to++ = *from++; + /* keep the watchdog happy */ + CopService(); + } +} /*** end of CpuMemCopy ***/ + + +/************************************************************************************//** +** \brief Perform a soft reset of the microcontroller by starting from the reset ISR. +** \return none. +** +****************************************************************************************/ +void CpuReset(void) +{ + /* perform a software reset by calling the reset ISR routine */ + _start(); +} /*** end of CpuReset ***/ + + +/*********************************** end of cpu.c **************************************/ diff --git a/Target/Source/TRICORE_TC1798/cpu.h b/Target/Source/TRICORE_TC1798/cpu.h new file mode 100644 index 00000000..9d3953d8 --- /dev/null +++ b/Target/Source/TRICORE_TC1798/cpu.h @@ -0,0 +1,51 @@ +/************************************************************************************//** +* \file Source\TRICORE_TC1798\cpu.h +* \brief Bootloader cpu module header file. +* \ingroup Target_TRICORE_TC1798 +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2015 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT 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 3 of the License, or (at your option) any later +* version. +* +* OpenBLT 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 OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \endinternal +****************************************************************************************/ +#ifndef CPU_H +#define CPU_H + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include "cpu_comp.h" /* compiler specific CPU definitions */ + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +void CpuStartUserProgram(void); +void CpuMemCopy(blt_addr dest, blt_addr src, blt_int16u len); +void CpuReset(void); + + +#endif /* CPU_H */ +/*********************************** end of cpu.h **************************************/ diff --git a/Target/Source/TRICORE_TC1798/flash.c b/Target/Source/TRICORE_TC1798/flash.c new file mode 100644 index 00000000..31511243 --- /dev/null +++ b/Target/Source/TRICORE_TC1798/flash.c @@ -0,0 +1,967 @@ +/************************************************************************************//** +* \file Source\TRICORE_TC1798\flash.c +* \brief Bootloader flash driver source file. +* \ingroup Target_TRICORE_TC1798 +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2015 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT 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 3 of the License, or (at your option) any later +* version. +* +* OpenBLT 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 OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \endinternal +****************************************************************************************/ + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include "boot.h" /* bootloader generic header */ + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/** \brief Value for an invalid flash sector. */ +#define FLASH_INVALID_SECTOR (0xffu) + +/** \brief Value for an invalid flash address. */ +#define FLASH_INVALID_ADDRESS (0xffffffffu) + +/** \brief Standard size of a flash block for writing. */ +#define FLASH_WRITE_BLOCK_SIZE (256u) + +/** \brief Total numbers of sectors in array flashLayout[]. */ +#define FLASH_TOTAL_SECTORS (sizeof(flashLayout)/sizeof(flashLayout[0])) + +/** \brief The flash driver is setup to operate on the cached PFLASH addresses, whereas + * the actual PFLASH commands should operate on non-cached addresses. This + * macro defines the offset between cached (80xxxxxxh) and non-cached + * (A0xxxxxxh) addresses. + */ +#define FLASH_NON_CACHED_OFFSET (0x20000000u) + +/** \brief Base address of the PFLASH0 module. */ +#define FLASH_PFLASH0_BASE (0x80000000u) + +/** \brief Base address of the PFLASH1 module. */ +#define FLASH_PFLASH1_BASE (0x80800000u) + +/** \brief Base address of the PFLASH0 flash status register. */ +#define FLASH_PFLASH0_FSR_ADDR (0xF8002010u) + +/** \brief Base address of the PFLASH0 flash status register. */ +#define FLASH_PFLASH1_FSR_ADDR (0xF8004010u) + +/** \brief Macro that returns the PFLASHx modules base address, giving any address + * in PFLASH. + */ +#define FLASH_GET_PFLASH_BASE(addr) ((addr < FLASH_PFLASH1_BASE) ? \ + FLASH_PFLASH0_BASE : FLASH_PFLASH1_BASE) + +/** \brief Macro that converts are 32 bit address into a pointer to a 32-bit unsigned + * value and writes a value to this pointer. + */ +#define FLASH_WRITE_TO_U32_PTR_BY_ADDR(addr, val) ((*((volatile blt_int32u *) (addr+FLASH_NON_CACHED_OFFSET))) = val) + +/** \brief The FLASHx_FSR register is the only register used in this driver. Its address + * depends on the PFLASH module that is being operated on. This macro gets the + * correct base address for the FSR register. + */ +#define FLASH_GET_FSR_REG_ADDR(addr) ((addr < FLASH_PFLASH1_BASE) ? \ + FLASH_PFLASH0_FSR_ADDR : FLASH_PFLASH1_FSR_ADDR) + +/** \brief Offset in bytes from the bootblock's base address where the checksum is + * located. + */ +#define FLASH_CS_OFFSET (0x04u) + +/** \brief Offset in bytes from the bootblock's base address where the checksum area + * starts. + */ +#define FLASH_CS_RANGE_START_OFFSET (0x08u) + +/** \brief The total number of 32-bit words that are in the checksum address range. */ +#define FLASH_CS_RANGE_TOTAL_WORDS ((FLASH_WRITE_BLOCK_SIZE/4u) - \ + (FLASH_CS_RANGE_START_OFFSET/4u)) + + +/**************************************************************************************** +* Type definitions +****************************************************************************************/ +/** \brief Flash sector descriptor type. */ +typedef struct +{ + blt_addr sector_start; /**< sector start address */ + blt_int32u sector_size; /**< sector size in bytes */ + blt_int8u sector_num; /**< sector number */ +} tFlashSector; + +/** \brief Structure type for grouping flash block information. + * \details Programming is done per block of max FLASH_WRITE_BLOCK_SIZE. for this a + * flash block manager is implemented in this driver. this flash block manager + * depends on this flash block info structure. It holds the base address of + * the flash block and the data that should be programmed into the flash + * block. The .base_addr must be a multiple of FLASH_WRITE_BLOCK_SIZE. + */ +typedef struct +{ + blt_addr base_addr; + blt_int8u data[FLASH_WRITE_BLOCK_SIZE]; +} tFlashBlockInfo; + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +static blt_bool FlashInitBlock(tFlashBlockInfo *block, blt_addr address); +static tFlashBlockInfo *FlashSwitchBlock(tFlashBlockInfo *block, blt_addr base_addr); +static blt_bool FlashAddToBlock(tFlashBlockInfo *block, blt_addr address, + blt_int8u *data, blt_int32u len); +static blt_bool FlashWriteBlock(tFlashBlockInfo *block); +static blt_bool FlashEraseSectors(blt_int8u first_sector, blt_int8u last_sector); +static blt_int8u FlashGetSector(blt_addr address); +static blt_addr FlashGetSectorBaseAddr(blt_int8u sector); +static blt_int32u FlashGetSectorSize(blt_int8u sector); +static blt_bool FlashTricoreProgramPage(blt_addr start_addr, blt_int8u *data); +static blt_bool FlashTricoreEraseSector(blt_addr start_addr); + + +/**************************************************************************************** +* Local constant declarations +****************************************************************************************/ +/** \brief Array wit the layout of the flash memory. + * \details The current implementation assumes that the bootloader is in the 2Mbyte + * PFLASH0 and supports flash operations only on the 2Mbyte PFLASH1. The reason + * for this is that a flash module cannot be in read mode and command mode at + * the same time. A future improvement is one where the actual flash command + * code is copied and run from RAM, to bypass this restriction. + */ +static const tFlashSector flashLayout[] = +{ + { 0x80800000, 0x04000, 0}, /* flash sector 0 - 16kb */ + { 0x80804000, 0x04000, 1}, /* flash sector 1 - 16kb */ + { 0x80808000, 0x04000, 2}, /* flash sector 2 - 16kb */ + { 0x8080C000, 0x04000, 3}, /* flash sector 3 - 16kb */ + { 0x80810000, 0x04000, 4}, /* flash sector 4 - 16kb */ + { 0x80814000, 0x04000, 5}, /* flash sector 5 - 16kb */ + { 0x80818000, 0x04000, 6}, /* flash sector 6 - 16kb */ + { 0x8081C000, 0x04000, 7}, /* flash sector 7 - 16kb */ + { 0x80820000, 0x20000, 8}, /* flash sector 8 - 128kb */ + { 0x80840000, 0x40000, 9}, /* flash sector 9 - 256kb */ + { 0x80880000, 0x40000, 10}, /* flash sector 10 - 256kb */ + { 0x808C0000, 0x40000, 11}, /* flash sector 11 - 256kb */ + { 0x80900000, 0x40000, 12}, /* flash sector 12 - 256kb */ + { 0x80940000, 0x40000, 13}, /* flash sector 13 - 256kb */ + { 0x80980000, 0x40000, 14}, /* flash sector 14 - 256kb */ + { 0x809C0000, 0x40000, 15}, /* flash sector 15 - 256kb */ +#if (BOOT_NVM_SIZE_KB > 2048) +#error "BOOT_NVM_SIZE_KB > 2048 is currently not supported." +#endif +}; + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief Local variable with information about the flash block that is currently + * being operated on. + * \details The smallest amount of flash that can be programmed is + * FLASH_WRITE_BLOCK_SIZE. A flash block manager is implemented in this driver + * and stores info in this variable. Whenever new data should be flashed, it + * is first added to a RAM buffer, which is part of this variable. Whenever + * the RAM buffer, which has the size of a flash block, is full or data needs + * to be written to a different block, the contents of the RAM buffer are + * programmed to flash. The flash block manager requires some software + * overhead, yet results is faster flash programming because data is first + * harvested, ideally until there is enough to program an entire flash block, + * before the flash device is actually operated on. + */ +static tFlashBlockInfo blockInfo; + +/** \brief Local variable with information about the flash boot block. + * \details The first block of the user program holds the vector table, which on the + * STM32 is also the where the checksum is written to. Is it likely that + * the vector table is first flashed and then, at the end of the programming + * sequence, the checksum. This means that this flash block need to be written + * to twice. Normally this is not a problem with flash memory, as long as you + * write the same values to those bytes that are not supposed to be changed + * and the locations where you do write to are still in the erased 0xFF state. + * Unfortunately, writing twice to flash this way, does not work reliably on + * all micros. This is why we need to have an extra block, the bootblock, + * placed under the management of the block manager. This way is it possible + * to implement functionality so that the bootblock is only written to once + * at the end of the programming sequence. + */ +static tFlashBlockInfo bootBlockInfo; + + +/************************************************************************************//** +** \brief Initializes the flash driver. +** \return none. +** +****************************************************************************************/ +void FlashInit(void) +{ + /* init the flash block info structs by setting the address to an invalid address */ + blockInfo.base_addr = FLASH_INVALID_ADDRESS; + bootBlockInfo.base_addr = FLASH_INVALID_ADDRESS; +} /*** end of FlashInit ***/ + + +/************************************************************************************//** +** \brief Writes the data to flash through a flash block manager. Note that this +** function also checks that no data is programmed outside the flash +** memory region, so the bootloader can never be overwritten. +** \param addr Start address. +** \param len Length in bytes. +** \param data Pointer to the data buffer. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +blt_bool FlashWrite(blt_addr addr, blt_int32u len, blt_int8u *data) +{ + blt_addr base_addr; + + /* make sure the addresses are within the flash device */ + if ( (FlashGetSector(addr) == FLASH_INVALID_SECTOR) || \ + (FlashGetSector(addr+len-1) == FLASH_INVALID_SECTOR) ) + { + return BLT_FALSE; + } + + /* if this is the bootblock, then let the boot block manager handle it */ + base_addr = (addr/FLASH_WRITE_BLOCK_SIZE)*FLASH_WRITE_BLOCK_SIZE; + if (base_addr == flashLayout[0].sector_start) + { + /* let the boot block manager handle it */ + return FlashAddToBlock(&bootBlockInfo, addr, data, len); + } + /* let the block manager handle it */ + return FlashAddToBlock(&blockInfo, addr, data, len); +} /*** end of FlashWrite ***/ + + +/************************************************************************************//** +** \brief Erases the flash memory. Note that this function also checks that no +** data is erased outside the flash memory region, so the bootloader can +** never be erased. +** \param addr Start address. +** \param len Length in bytes. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +blt_bool FlashErase(blt_addr addr, blt_int32u len) +{ + blt_int8u first_sector; + blt_int8u last_sector; + + /* obtain the first and last sector number */ + first_sector = FlashGetSector(addr); + last_sector = FlashGetSector(addr+len-1); + /* check them */ + if ( (first_sector == FLASH_INVALID_SECTOR) || (last_sector == FLASH_INVALID_SECTOR) ) + { + return BLT_FALSE; + } + /* erase the sectors */ + return FlashEraseSectors(first_sector, last_sector); +} /*** end of FlashErase ***/ + + +/************************************************************************************//** +** \brief Writes a checksum of the user program to non-volatile memory. This is +** performed once the entire user program has been programmed. Through +** the checksum, the bootloader can check if the programming session +** was completed, which indicates that a valid user programming is +** present and can be started. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +blt_bool FlashWriteChecksum(void) +{ + blt_int32u signature_checksum = 0; + blt_int8u wordIdx; + + /* for the Tricore TC1798 target, the bootlblock is FLASH_WRITE_BLOCK_SIZE in size. + * the actual 32-bit checksum value in this bootblock is located at: + * + 4. + * for this reason the checksum is defined as the one's complement value of the sum + * of everything else in the bootblock, so starting at: + * + 8 and ending at: + * + FLASH_WRITE_BLOCK_SIZE - 1; + * + * note that the user program need to be modified to reserve 32-bit at + * + 4, because the bootload will write the checksum value + * here. refer to the port specific documentation for additional details. + * + * keep in mind that this checksum is just used as a user program signature, i.e. as + * a flag to figure out if a user program is present or not. the checksum is not + * calculated over the full user program size. such a checksum routine is typically + * application/customer specific and therefore not part of the standard bootloader. + * it can however be easily implemented by adding the following macro to blt_conf.h: + * #define BOOT_NVM_CHECKSUM_HOOKS_ENABLE (1). + * You can then implement your own checksum write/verify routines in the hook + * functions NvmWriteChecksumHook() and NvmVerifyChecksumHook(). + */ + + /* first check that the bootblock contains valid data. if not, this means the + * bootblock is not part of the reprogramming this time and therefore no + * new checksum needs to be written + */ + if (bootBlockInfo.base_addr == FLASH_INVALID_ADDRESS) + { + return BLT_TRUE; + } + + /* compute the checksum. note that the data in the checksum range is not yet written + * to flash but is present in the bootblock data structure at this point. + */ + for (wordIdx = 0; wordIdx < FLASH_CS_RANGE_TOTAL_WORDS; wordIdx++) + { + signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[(wordIdx*4)+FLASH_CS_RANGE_START_OFFSET])); + } + signature_checksum = ~signature_checksum; /* one's complement */ + + /* write the checksum */ + return FlashWrite(flashLayout[0].sector_start+FLASH_CS_OFFSET, + sizeof(blt_addr), (blt_int8u*)&signature_checksum); +} /*** end of FlashWriteChecksum ***/ + + +/************************************************************************************//** +** \brief Verifies the checksum, which indicates that a valid user program is +** present and can be started. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +blt_bool FlashVerifyChecksum(void) +{ + blt_int32u signature_checksum = 0; + blt_int32u signature_checksum_rom; + blt_int8u wordIdx; + + /* compute the checksum by reading it from flash */ + for (wordIdx = 0; wordIdx < FLASH_CS_RANGE_TOTAL_WORDS; wordIdx++) + { + signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start + (wordIdx*4) + FLASH_CS_RANGE_START_OFFSET)); + } + signature_checksum = ~signature_checksum; /* one's complement */ + + /* read the checksum value from flash that was writtin by the bootloader at the end + * of the last firmware update + */ + signature_checksum_rom = *((blt_int32u*)(flashLayout[0].sector_start + FLASH_CS_OFFSET)); + /* verify that they are both the same */ + if (signature_checksum == signature_checksum_rom) + { + /* checksum okay */ + return BLT_TRUE; + } + /* checksum incorrect */ + return BLT_FALSE; +} /*** end of FlashVerifyChecksum ***/ + + +/************************************************************************************//** +** \brief Finalizes the flash driver operations. There could still be data in +** the currently active block that needs to be flashed. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +blt_bool FlashDone(void) +{ + /* check if there is still data waiting to be programmed in the boot block */ + if (bootBlockInfo.base_addr != FLASH_INVALID_ADDRESS) + { + if (FlashWriteBlock(&bootBlockInfo) == BLT_FALSE) + { + return BLT_FALSE; + } + } + + /* check if there is still data waiting to be programmed */ + if (blockInfo.base_addr != FLASH_INVALID_ADDRESS) + { + if (FlashWriteBlock(&blockInfo) == BLT_FALSE) + { + return BLT_FALSE; + } + } + /* still here so all is okay */ + return BLT_TRUE; +} /*** end of FlashDone ***/ + + +/************************************************************************************//** +** \brief Obtains the base address of the flash memory available to the user program. +** This is basically the first address in the flashLayout table. +** \return Base address. +** +****************************************************************************************/ +blt_addr FlashGetUserProgBaseAddress(void) +{ + return flashLayout[0].sector_start; +} /*** end of FlashGetUserProgBaseAddress ***/ + + +/************************************************************************************//** +** \brief Copies data currently in flash to the block->data and sets the +** base address. +** \param block Pointer to flash block info structure to operate on. +** \param address Base address of the block data. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +static blt_bool FlashInitBlock(tFlashBlockInfo *block, blt_addr address) +{ + /* check address alignment */ + if ((address % FLASH_WRITE_BLOCK_SIZE) != 0) + { + return BLT_FALSE; + } + /* make sure that we are initializing a new block and not the same one */ + if (block->base_addr == address) + { + /* block already initialized, so nothing to do */ + return BLT_TRUE; + } + /* set the base address and copies the current data from flash */ + block->base_addr = address; + CpuMemCopy((blt_addr)block->data, address, FLASH_WRITE_BLOCK_SIZE); + return BLT_TRUE; +} /*** end of FlashInitBlock ***/ + + +/************************************************************************************//** +** \brief Switches blocks by programming the current one and initializing the +** next. +** \param block Pointer to flash block info structure to operate on. +** \param base_addr Base address of the next block. +** \return The pointer of the block info struct that is no being used, or a NULL +** pointer in case of error. +** +****************************************************************************************/ +static tFlashBlockInfo *FlashSwitchBlock(tFlashBlockInfo *block, blt_addr base_addr) +{ + /* check if a switch needs to be made away from the boot block. in this case the boot + * block shouldn't be written yet, because this is done at the end of the programming + * session by FlashDone(), this is right after the checksum was written. + */ + if (block == &bootBlockInfo) + { + /* switch from the boot block to the generic block info structure */ + block = &blockInfo; + } + /* check if a switch back into the bootblock is needed. in this case the generic block + * doesn't need to be written here yet. + */ + else if (base_addr == flashLayout[0].sector_start) + { + /* switch from the generic block to the boot block info structure */ + block = &bootBlockInfo; + base_addr = flashLayout[0].sector_start; + } + else + { + /* need to switch to a new block, so program the current one and init the next */ + if (FlashWriteBlock(block) == BLT_FALSE) + { + return BLT_NULL; + } + } + + /* initialize tne new block when necessary */ + if (FlashInitBlock(block, base_addr) == BLT_FALSE) + { + return BLT_NULL; + } + + /* still here to all is okay */ + return block; +} /*** end of FlashSwitchBlock ***/ + + +/************************************************************************************//** +** \brief Programming is done per block. This function adds data to the block +** that is currently collecting data to be written to flash. If the +** address is outside of the current block, the current block is written +** to flash an a new block is initialized. +** \param block Pointer to flash block info structure to operate on. +** \param address Flash destination address. +** \param data Pointer to the byte array with data. +** \param len Number of bytes to add to the block. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +static blt_bool FlashAddToBlock(tFlashBlockInfo *block, blt_addr address, + blt_int8u *data, blt_int32u len) +{ + blt_addr current_base_addr; + blt_int8u *dst; + blt_int8u *src; + + /* determine the current base address */ + current_base_addr = (address/FLASH_WRITE_BLOCK_SIZE)*FLASH_WRITE_BLOCK_SIZE; + + /* make sure the blockInfo is not uninitialized */ + if (block->base_addr == FLASH_INVALID_ADDRESS) + { + /* initialize the blockInfo struct for the current block */ + if (FlashInitBlock(block, current_base_addr) == BLT_FALSE) + { + return BLT_FALSE; + } + } + + /* check if the new data fits in the current block */ + if (block->base_addr != current_base_addr) + { + /* need to switch to a new block, so program the current one and init the next */ + block = FlashSwitchBlock(block, current_base_addr); + if (block == BLT_NULL) + { + return BLT_FALSE; + } + } + + /* add the data to the current block, but check for block overflow */ + dst = &(block->data[address - block->base_addr]); + src = data; + do + { + /* keep the watchdog happy */ + CopService(); + /* buffer overflow? */ + if ((blt_addr)(dst-&(block->data[0])) >= FLASH_WRITE_BLOCK_SIZE) + { + /* need to switch to a new block, so program the current one and init the next */ + block = FlashSwitchBlock(block, current_base_addr+FLASH_WRITE_BLOCK_SIZE); + if (block == BLT_NULL) + { + return BLT_FALSE; + } + /* reset destination pointer */ + dst = &(block->data[0]); + } + /* write the data to the buffer */ + *dst = *src; + /* update pointers */ + dst++; + src++; + /* decrement byte counter */ + len--; + } + while (len > 0); + /* still here so all is good */ + return BLT_TRUE; +} /*** end of FlashAddToBlock ***/ + + +/************************************************************************************//** +** \brief Programs FLASH_WRITE_BLOCK_SIZE bytes to flash from the block->data +** array. +** \param block Pointer to flash block info structure to operate on. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +static blt_bool FlashWriteBlock(tFlashBlockInfo *block) +{ + blt_int8u sector_num; + + /* check that address is actually within flash */ + sector_num = FlashGetSector(block->base_addr); + if (sector_num == FLASH_INVALID_SECTOR) + { + return BLT_FALSE; + } + /* the FLASH_WRITE_BLOCK_SIZE is configured to exactly match the size of a page in + * PFLASH. so here simply need to program one page in PFLASH. + */ + return FlashTricoreProgramPage(block->base_addr, block->data); +} /*** end of FlashWriteBlock ***/ + + +/************************************************************************************//** +** \brief Erases the flash sectors from first_sector up until last_sector. +** \param first_sector First flash sector number. +** \param last_sector Last flash sector number. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +static blt_bool FlashEraseSectors(blt_int8u first_sector, blt_int8u last_sector) +{ + blt_int8u current_sector; + blt_bool result = BLT_TRUE; + + /* validate the sector numbers */ + if (first_sector > last_sector) + { + return BLT_FALSE; + } + if ( (first_sector < flashLayout[0].sector_num) || \ + (last_sector > flashLayout[FLASH_TOTAL_SECTORS-1].sector_num) ) + { + return BLT_FALSE; + } + /* the table flashLayout[] is implemented such that it exactly matches the sectors + * in PFLASH. this means that here we simply need to loop through the sectors one- + * by-one and erase them. + */ + for (current_sector = first_sector; current_sector <= last_sector; current_sector++) + { + if (FlashTricoreEraseSector(FlashGetSectorBaseAddr(current_sector)) == BLT_FALSE) + { + /* flag error and stop the loop */ + result = BLT_FALSE; + break; + } + /* keep the watchdog happy */ + CopService(); + } + /* return the result */ + return result; +} /*** end of FlashEraseSectors ***/ + + +/************************************************************************************//** +** \brief Determines the flash sector the address is in. +** \param address Address in the flash sector. +** \return Flash sector number or FLASH_INVALID_SECTOR. +** +****************************************************************************************/ +static blt_int8u FlashGetSector(blt_addr address) +{ + blt_int8u sectorIdx; + + /* search through the sectors to find the right one */ + for (sectorIdx = 0; sectorIdx < FLASH_TOTAL_SECTORS; sectorIdx++) + { + /* keep the watchdog happy */ + CopService(); + /* is the address in this sector? */ + if ( (address >= flashLayout[sectorIdx].sector_start) && \ + (address < (flashLayout[sectorIdx].sector_start + \ + flashLayout[sectorIdx].sector_size)) ) + { + /* return the sector number */ + return flashLayout[sectorIdx].sector_num; + } + } + /* still here so no valid sector found */ + return FLASH_INVALID_SECTOR; +} /*** end of FlashGetSector ***/ + + +/************************************************************************************//** +** \brief Determines the flash sector base address. +** \param sector Sector to get the base address of. +** \return Flash sector base address or FLASH_INVALID_ADDRESS. +** +****************************************************************************************/ +static blt_addr FlashGetSectorBaseAddr(blt_int8u sector) +{ + blt_int8u sectorIdx; + + /* search through the sectors to find the right one */ + for (sectorIdx = 0; sectorIdx < FLASH_TOTAL_SECTORS; sectorIdx++) + { + /* keep the watchdog happy */ + CopService(); + if (flashLayout[sectorIdx].sector_num == sector) + { + return flashLayout[sectorIdx].sector_start; + } + } + /* still here so no valid sector found */ + return FLASH_INVALID_ADDRESS; +} /*** end of FlashGetSectorBaseAddr ***/ + + +/************************************************************************************//** +** \brief Determines the flash sector size. +** \param sector Sector to get the size of. +** \return Flash sector size or 0. +** +****************************************************************************************/ +static blt_int32u FlashGetSectorSize(blt_int8u sector) +{ + blt_int8u sectorIdx; + + /* search through the sectors to find the right one */ + for (sectorIdx = 0; sectorIdx < FLASH_TOTAL_SECTORS; sectorIdx++) + { + /* keep the watchdog happy */ + CopService(); + if (flashLayout[sectorIdx].sector_num == sector) + { + return flashLayout[sectorIdx].sector_size; + } + } + /* still here so no valid sector found */ + return 0; +} /*** end of FlashGetSectorSize ***/ + + +/************************************************************************************//** +** \brief Programs FLASH_WRITE_BLOCK_SIZE bytes into flash starting at the page's base +** address. +** \param start_addr Starting address of the page where the bytes should be +** programmed. Should be aligned to FLASH_WRITE_BLOCK_SIZE. +** \param data Pointer to a byte array with the data to be programmed. The array +** should have FLASH_WRITE_BLOCK_SIZE bytes. +** \return BLT_TRUE is the page was programmed successfully, BLT_FALSE otherwise. +** +****************************************************************************************/ +static blt_bool FlashTricoreProgramPage(blt_addr start_addr, blt_int8u *data) +{ + blt_addr baseAddr; + blt_int32u *dataPtr; + blt_int8u *readPtr; + blt_int32u idx; + FLASHn_FSR_t *pflashFSR; + + /* check address alignment to a page in PFLASH */ + if ((start_addr % FLASH_WRITE_BLOCK_SIZE) != 0) + { + return BLT_FALSE; + } + /* determine base address of the PFLASH module */ + baseAddr = FLASH_GET_PFLASH_BASE(start_addr); + /* set pointer for the PFLASH module's FSR register */ + pflashFSR = (FLASHn_FSR_t *)FLASH_GET_FSR_REG_ADDR(start_addr); + /* use "clear status" command to clear flags */ + FLASH_WRITE_TO_U32_PTR_BY_ADDR(baseAddr + 0x5554u, 0x000000F5u); + /* execute "enter page mode" command to activate the PFLASH assembly buffer */ + FLASH_WRITE_TO_U32_PTR_BY_ADDR(baseAddr + 0x5554u, 0x00000050u); + /* perform DSYNC */ + CpuSetDSYNC(); + /* wait until FSR.xFPAGE = '1' */ + while(pflashFSR->bits.PFPAGE != 1) + { + /* fail if FSR.SQER = '1' */ + if (pflashFSR->bits.SQER == 1) + { + return BLT_FALSE; + } + /* fail if FSR.PROER = '1' */ + if (pflashFSR->bits.PROER == 1) + { + return BLT_FALSE; + } + /* keep the watchdog happy */ + CopService(); + } + /* load FLASH_WRITE_BLOCK_SIZE bytes of program data into the assembly buffer */ + dataPtr = (blt_int32u *)data; + for (idx = 0; idx <(FLASH_WRITE_BLOCK_SIZE/8u); idx++) + { + /* write first 32-bit value */ + FLASH_WRITE_TO_U32_PTR_BY_ADDR(baseAddr + 0x55F0U, *dataPtr); + dataPtr++; + /* write second 32-bit value */ + FLASH_WRITE_TO_U32_PTR_BY_ADDR(baseAddr + 0x55F4U, *dataPtr); + dataPtr++; + } + /* launch the "write page" command */ + FLASH_WRITE_TO_U32_PTR_BY_ADDR(baseAddr + 0x5554u, 0x000000AAu); + FLASH_WRITE_TO_U32_PTR_BY_ADDR(baseAddr + 0xAAA8u, 0x00000055u); + FLASH_WRITE_TO_U32_PTR_BY_ADDR(baseAddr + 0x5554u, 0x000000A0u); + FLASH_WRITE_TO_U32_PTR_BY_ADDR(start_addr, 0x000000AAu); + /* perform DSYNC */ + CpuSetDSYNC(); + /* wait until FSR.PROG = '1' */ + while(pflashFSR->bits.PROG != 1) + { + /* fail if FSR.SQER = '1' */ + if (pflashFSR->bits.SQER == 1) + { + return BLT_FALSE; + } + /* fail if FSR.PROER = '1' */ + if (pflashFSR->bits.PROER == 1) + { + return BLT_FALSE; + } + /* keep the watchdog happy */ + CopService(); + } + /* wait until FSR.xBUSY = '0' */ + while(pflashFSR->bits.PBUSY == 1) + { + /* check flag FSR.xFOPER for ‘1’ as abort criterion to protect against hardware + * failures causing BUSY to stay '1' + */ + if (pflashFSR->bits.PFOPER == 1) + { + return BLT_FALSE; + } + /* keep the watchdog happy */ + CopService(); + } + /* check FSR.VER flag */ + if (pflashFSR->bits.VER != 0) + { + return BLT_FALSE; + } + /* fail if FSR.xFOPER = '1' */ + if (pflashFSR->bits.PFOPER != 0) + { + return BLT_FALSE; + } + /* evaluate FSR.xDBER */ + if(pflashFSR->bits.PFDBER != 0) + { + return BLT_FALSE; + } + /* use "clear status" command to clear flags */ + FLASH_WRITE_TO_U32_PTR_BY_ADDR(baseAddr + 0x5554u, 0x000000F5u); + /* perform verification by checking the written values. do this on a byte-per-byte + * basis to also check the code for byte swapping mistakes. + */ + readPtr = (blt_int8u *)start_addr; + for (idx = 0; idx bits.ERASE != 1) + { + /* fail if FSR.SQER = '1' */ + if (pflashFSR->bits.SQER == 1) + { + return BLT_FALSE; + } + /* fail if FSR.PROER = '1' */ + if (pflashFSR->bits.PROER == 1) + { + return BLT_FALSE; + } + /* keep the watchdog happy */ + CopService(); + } + /* wait until FSR.xBUSY = '0' */ + while(pflashFSR->bits.PBUSY == 1) + { + /* check flag FSR.xFOPER for ‘1’ as abort criterion to protect against hardware + * failures causing BUSY to stay '1' + */ + if (pflashFSR->bits.PFOPER == 1) + { + return BLT_FALSE; + } + /* keep the watchdog happy */ + CopService(); + } + /* check FSR.VER flag */ + if (pflashFSR->bits.VER != 0) + { + return BLT_FALSE; + } + /* fail if FSR.xFOPER = '1' */ + if (pflashFSR->bits.PFOPER != 0) + { + return BLT_FALSE; + } + /* use "clear status" command to clear flags */ + FLASH_WRITE_TO_U32_PTR_BY_ADDR(baseAddr + 0x5554u, 0x000000F5u); + + /* perform erase verification */ + sectorNum = FlashGetSector(start_addr); + if (sectorNum == FLASH_INVALID_SECTOR) + { + /* should not happen */ + return BLT_FALSE; + } + /* get sector size in words and set the read pointer to the first word in the sector */ + sectorWords = FlashGetSectorSize(sectorNum) / sizeof(blt_int32u); + if (sectorWords == 0) + { + /* should not happen */ + return BLT_FALSE; + } + readPtr = (blt_int32u *)(FlashGetSectorBaseAddr(sectorNum)); + /* loop through all words in the sector and check that they are in the erase state. + * note that this is a 0 value for PFLASH. + */ + for (idx=0; idx. +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \endinternal +****************************************************************************************/ +#ifndef FLASH_H +#define FLASH_H + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +void FlashInit(void); +blt_bool FlashWrite(blt_addr addr, blt_int32u len, blt_int8u *data); +blt_bool FlashErase(blt_addr addr, blt_int32u len); +blt_bool FlashWriteChecksum(void); +blt_bool FlashVerifyChecksum(void); +blt_bool FlashDone(void); +blt_addr FlashGetUserProgBaseAddress(void); + + +#endif /* FLASH_H */ +/*********************************** end of flash.h ************************************/ diff --git a/Target/Source/TRICORE_TC1798/nvm.c b/Target/Source/TRICORE_TC1798/nvm.c new file mode 100644 index 00000000..f4e0c22b --- /dev/null +++ b/Target/Source/TRICORE_TC1798/nvm.c @@ -0,0 +1,216 @@ +/************************************************************************************//** +* \file Source\TRICORE_TC1798\nvm.c +* \brief Bootloader non-volatile memory driver source file. +* \ingroup Target_TRICORE_TC1798 +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2015 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT 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 3 of the License, or (at your option) any later +* version. +* +* OpenBLT 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 OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \endinternal +****************************************************************************************/ + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include "boot.h" /* bootloader generic header */ + + +/**************************************************************************************** +* Hook functions +****************************************************************************************/ +#if (BOOT_NVM_HOOKS_ENABLE > 0) +extern void NvmInitHook(void); +extern blt_int8u NvmWriteHook(blt_addr addr, blt_int32u len, blt_int8u *data); +extern blt_int8u NvmEraseHook(blt_addr addr, blt_int32u len); +extern blt_bool NvmDoneHook(void); +#endif + +#if (BOOT_NVM_CHECKSUM_HOOKS_ENABLE > 0) +extern blt_bool NvmWriteChecksumHook(void); +extern blt_bool NvmVerifyChecksumHook(void); +#endif + + + +/************************************************************************************//** +** \brief Initializes the NVM driver. +** \return none. +** +****************************************************************************************/ +void NvmInit(void) +{ +#if (BOOT_NVM_HOOKS_ENABLE > 0) + /* give the application a chance to initialize a driver for operating on NVM + * that is not by default supported by this driver. + */ + NvmInitHook(); +#endif + + /* init the internal driver */ + FlashInit(); +} /*** end of NvmInit ***/ + + +/************************************************************************************//** +** \brief Programs the non-volatile memory. +** \param addr Start address. +** \param len Length in bytes. +** \param data Pointer to the data buffer. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +blt_bool NvmWrite(blt_addr addr, blt_int32u len, blt_int8u *data) +{ +#if (BOOT_NVM_HOOKS_ENABLE > 0) + blt_int8u result = BLT_NVM_NOT_IN_RANGE; +#endif + +#if (BOOT_NVM_HOOKS_ENABLE > 0) + /* give the application a chance to operate on memory that is not by default supported + * by this driver. + */ + result = NvmWriteHook(addr, len, data); + + /* process the return code */ + if (result == BLT_NVM_OKAY) + { + /* data was within range of the additionally supported memory and succesfully + * programmed, so we are all done. + */ + return BLT_TRUE; + } + else if (result == BLT_NVM_ERROR) + { + /* data was within range of the additionally supported memory and attempted to be + * programmed, but an error occurred, so we can't continue. + */ + return BLT_FALSE; + } +#endif + + /* still here so the internal driver should try and perform the program operation */ + return FlashWrite(addr, len, data); +} /*** end of NvmWrite ***/ + + +/************************************************************************************//** +** \brief Erases the non-volatile memory. +** \param addr Start address. +** \param len Length in bytes. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +blt_bool NvmErase(blt_addr addr, blt_int32u len) +{ +#if (BOOT_NVM_HOOKS_ENABLE > 0) + blt_int8u result = BLT_NVM_NOT_IN_RANGE; +#endif + +#if (BOOT_NVM_HOOKS_ENABLE > 0) + /* give the application a chance to operate on memory that is not by default supported + * by this driver. + */ + result = NvmEraseHook(addr, len); + + /* process the return code */ + if (result == BLT_NVM_OKAY) + { + /* address was within range of the additionally supported memory and succesfully + * erased, so we are all done. + */ + return BLT_TRUE; + } + else if (result == BLT_NVM_ERROR) + { + /* address was within range of the additionally supported memory and attempted to be + * erased, but an error occurred, so we can't continue. + */ + return BLT_FALSE; + } +#endif + + /* still here so the internal driver should try and perform the erase operation */ + return FlashErase(addr, len); +} /*** end of NvmErase ***/ + + +/************************************************************************************//** +** \brief Verifies the checksum, which indicates that a valid user program is +** present and can be started. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +blt_bool NvmVerifyChecksum(void) +{ +#if (BOOT_NVM_CHECKSUM_HOOKS_ENABLE > 0) + /* check checksum using the application specific method. */ + return NvmVerifyChecksumHook(); +#else + /* check checksum using the interally supported method. */ + return FlashVerifyChecksum(); +#endif +} /*** end of NvmVerifyChecksum ***/ + + +/************************************************************************************//** +** \brief Once all erase and programming operations are completed, this +** function is called, so at the end of the programming session and +** right before a software reset is performed. It is used to calculate +** a checksum and program this into flash. This checksum is later used +** to determine if a valid user program is present in flash. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +blt_bool NvmDone(void) +{ +#if (BOOT_NVM_HOOKS_ENABLE > 0) + /* give the application's NVM driver a chance to finish up */ + if (NvmDoneHook() == BLT_FALSE) + { + /* error so no need to continue */ + return BLT_FALSE; + } +#endif + +#if (BOOT_NVM_CHECKSUM_HOOKS_ENABLE > 0) + /* compute and write checksum, using the application specific method. */ + if (NvmWriteChecksumHook() == BLT_FALSE) + { + return BLT_FALSE; + } +#else + /* compute and write checksum, which is programmed by the internal driver. */ + if (FlashWriteChecksum() == BLT_FALSE) + { + return BLT_FALSE; + } +#endif + + /* finish up internal driver operations */ + return FlashDone(); +} /*** end of NvmDone ***/ + + +/*********************************** end of nvm.c **************************************/ diff --git a/Target/Source/TRICORE_TC1798/nvm.h b/Target/Source/TRICORE_TC1798/nvm.h new file mode 100644 index 00000000..70ba13fd --- /dev/null +++ b/Target/Source/TRICORE_TC1798/nvm.h @@ -0,0 +1,65 @@ +/************************************************************************************//** +* \file Source\TRICORE_TC1798\nvm.h +* \brief Bootloader non-volatile memory driver header file. +* \ingroup Target_TRICORE_TC1798 +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2015 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT 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 3 of the License, or (at your option) any later +* version. +* +* OpenBLT 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 OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \endinternal +****************************************************************************************/ +#ifndef NVM_H +#define NVM_H + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include "flash.h" /* LPC2xxx flash driver */ + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +void NvmInit(void); +blt_bool NvmWrite(blt_addr addr, blt_int32u len, blt_int8u *data); +blt_bool NvmErase(blt_addr addr, blt_int32u len); +blt_bool NvmVerifyChecksum(void); +blt_bool NvmDone(void); + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/* return codes for hook function NvmWrite/Erase */ +/** \brief Return code for success. */ +#define BLT_NVM_ERROR (0x00) +/** \brief Return code for error. */ +#define BLT_NVM_OKAY (0x01) +/** \brief Return code for not in range. */ +#define BLT_NVM_NOT_IN_RANGE (0x02) + + +#endif /* NVM_H */ +/*********************************** end of nvm.h **************************************/ diff --git a/Target/Source/TRICORE_TC1798/target.dox b/Target/Source/TRICORE_TC1798/target.dox new file mode 100644 index 00000000..1374c50e --- /dev/null +++ b/Target/Source/TRICORE_TC1798/target.dox @@ -0,0 +1,8 @@ +/** +\defgroup Target_TRICORE_TC1798 Target Tricore TC1798 +\brief Target dependent code for the Tricore TC1798 microcontroller family. +\details This module implements the bootloader's target dependent part for the + Tricore TC1798 microcontroller family. +*/ + + diff --git a/Target/Source/TRICORE_TC1798/timer.c b/Target/Source/TRICORE_TC1798/timer.c new file mode 100644 index 00000000..7afdb52c --- /dev/null +++ b/Target/Source/TRICORE_TC1798/timer.c @@ -0,0 +1,148 @@ +/************************************************************************************//** +* \file Source\TRICORE_TC1798\timer.c +* \brief Bootloader timer driver source file. +* \ingroup Target_TRICORE_TC1798 +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2015 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT 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 3 of the License, or (at your option) any later +* version. +* +* OpenBLT 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 OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \endinternal +****************************************************************************************/ + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include "boot.h" /* bootloader generic header */ + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief Local variable for storing the number of milliseconds that have elapsed since + * startup. + */ +static blt_int32u millisecond_counter; + +/** \brief Holds the timer tick count for 1 millisecond. */ +static blt_int16u millisecond_ticks; + + +/************************************************************************************//** +** \brief Initializes the polling based millisecond timer driver. +** \return none. +** +****************************************************************************************/ +void TimerInit(void) +{ + blt_int32u dummy; + + /* reset the timer configuration */ + TimerReset(); + /* obtain "E" access rights */ + CpuEnterInitMode(); + /* enable the GPT12 timer module */ + GPT120_CLC.reg = 0x00000000; + /* dummy read to avoid pipeline effects */ + dummy = GPT120_CLC.reg; + /* release "E" access rights */ + CpuLeaveInitMode(); + /* core timer 3 is used for polling millisecond events. its configuration is: + * - timer 3 works in timer mode + * - external up/down control is disabled + * - prescaler factor is 128 (Ftimer3 = BOOT_CPU_SYSTEM_SPEED_KHZ / 128) + * - up/down control bit is reset + * - alternate output function T3OUT is disabled + * - timer 3 output toggle latch (T3OTL) is set to 0 + * - timer 3 run bit is set + */ + GPT120_T3CON.reg = 0x00000845; + /* reset the timer 3 register so that counter starts at 0 */ + GPT120_T3.reg = 0x00000000; + /* calculate the number of timer ticks in 1 millisecond */ + millisecond_ticks = ((blt_int32u)BOOT_CPU_SYSTEM_SPEED_KHZ / 128); + /* reset the millisecond counter value */ + millisecond_counter = 0; +} /*** end of TimerInit ***/ + + +/************************************************************************************//** +** \brief Reset the timer by placing the timer back into it's default reset +** configuration. +** \return none. +** +****************************************************************************************/ +void TimerReset(void) +{ + blt_int32u dummy; + /* revert back to timer 3 configuration reset value */ + GPT120_T3CON.reg = 0x00000000; + /* revert back to timer 3 reset value */ + GPT120_T3.reg = 0x00000000; + /* obtain "E" access rights */ + CpuEnterInitMode(); + /* disable the GPT12 timer module */ + GPT120_CLC.reg = 0x00000003; + /* dummy read to avoid pipeline effects */ + dummy = GPT120_CLC.reg; + /* release "E" access rights */ + CpuLeaveInitMode(); +} /* end of TimerReset */ + + +/************************************************************************************//** +** \brief Updates the millisecond timer. +** \return none. +** +****************************************************************************************/ +void TimerUpdate(void) +{ + /* check if the millisecond event occurred */ + if (GPT120_T3.reg >= millisecond_ticks) + { + GPT120_T3.reg = 0; + /* reset timer 3 register for detecting the next millisecond */ + /* increment the millisecond counter */ + millisecond_counter++; + } +} /*** end of TimerUpdate ***/ + + +/************************************************************************************//** +** \brief Obtains the counter value of the millisecond timer. +** \return Current value of the millisecond timer. +** +****************************************************************************************/ +blt_int32u TimerGet(void) +{ + /* updating timer here allows this function to be called in a loop with timeout + * detection. + */ + TimerUpdate(); + /* read and return the amount of milliseconds that passed since initialization */ + return millisecond_counter; +} /*** end of TimerGet ***/ + + +/*********************************** end of timer.c ************************************/ diff --git a/Target/Source/TRICORE_TC1798/timer.h b/Target/Source/TRICORE_TC1798/timer.h new file mode 100644 index 00000000..bbb053da --- /dev/null +++ b/Target/Source/TRICORE_TC1798/timer.h @@ -0,0 +1,46 @@ +/************************************************************************************//** +* \file Source\TRICORE_TC1798\timer.h +* \brief Bootloader timer driver header file. +* \ingroup Target_TRICORE_TC1798 +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2015 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT 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 3 of the License, or (at your option) any later +* version. +* +* OpenBLT 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 OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \endinternal +****************************************************************************************/ +#ifndef TIMER_H +#define TIMER_H + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +void TimerInit(void); +void TimerUpdate(void); +blt_int32u TimerGet(void); +void TimerReset(void); + + +#endif /* TIMER_H */ +/*********************************** end of timer.h ************************************/ diff --git a/Target/Source/TRICORE_TC1798/types.h b/Target/Source/TRICORE_TC1798/types.h new file mode 100644 index 00000000..0a6c2782 --- /dev/null +++ b/Target/Source/TRICORE_TC1798/types.h @@ -0,0 +1,63 @@ +/************************************************************************************//** +* \file Source\TRICORE_TC1798\types.h +* \brief Bootloader types header file. +* \ingroup Target_TRICORE_TC1798 +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2015 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT 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 3 of the License, or (at your option) any later +* version. +* +* OpenBLT 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 OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \endinternal +****************************************************************************************/ +#ifndef TYPES_H +#define TYPES_H + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/** \brief Boolean true value. */ +#define BLT_TRUE (1) +/** \brief Boolean false value. */ +#define BLT_FALSE (0) +/** \brief NULL pointer value. */ +#define BLT_NULL ((void *)0) + + +/**************************************************************************************** +* Type definitions +****************************************************************************************/ +typedef unsigned char blt_bool; /**< boolean type */ +typedef char blt_char; /**< character type */ +typedef unsigned long blt_addr; /**< memory address type */ +typedef unsigned char blt_int8u; /**< 8-bit unsigned integer */ +typedef signed char blt_int8s; /**< 8-bit signed integer */ +typedef unsigned short blt_int16u; /**< 16-bit unsigned integer */ +typedef signed short blt_int16s; /**< 16-bit signed integer */ +typedef unsigned int blt_int32u; /**< 32-bit unsigned integer */ +typedef signed int blt_int32s; /**< 32-bit signed integer */ + + +#endif /* TYPES_H */ +/*********************************** end of types.h ************************************/ diff --git a/Target/Source/TRICORE_TC1798/uart.c b/Target/Source/TRICORE_TC1798/uart.c new file mode 100644 index 00000000..b8cedec8 --- /dev/null +++ b/Target/Source/TRICORE_TC1798/uart.c @@ -0,0 +1,282 @@ +/************************************************************************************//** +* \file Source\TRICORE_TC1798\uart.c +* \brief Bootloader UART communication interface source file. +* \ingroup Target_TRICORE_TC1798 +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2015 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT 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 3 of the License, or (at your option) any later +* version. +* +* OpenBLT 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 OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \endinternal +****************************************************************************************/ + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include "boot.h" /* bootloader generic header */ + + +#if (BOOT_COM_UART_ENABLE > 0) +/**************************************************************************************** +* Type definitions +****************************************************************************************/ +typedef struct +{ + blt_int32u reserved0[0x1]; /* 0x0 */ + ASCn_PISEL_t PISEL; /* 0x4 */ + ASCn_ID_t ID; /* 0x8 */ + blt_int32u reserved3[0x1]; /* 0xc */ + ASCn_CON_t CON; /* 0x10 */ + ASCn_BG_t BG; /* 0x14 */ + ASCn_FDV_t FDV; /* 0x18 */ + blt_int32u reserved7[0x1]; /* 0x1c */ + ASCn_TBUF_t TBUF; /* 0x20 */ + ASCn_RBUF_t RBUF; /* 0x24 */ + blt_int32u reserved10[0xa]; /* 0x28 */ + ASCn_WHBCON_t WHBCON; /* 0x50 */ + blt_int32u reserved12[0x27]; /* 0x54 */ + ASCn_TSRC_t TSRC; /* 0xf0 */ + ASCn_RSRC_t RSRC; /* 0xf4 */ + ASCn_ESRC_t ESRC; /* 0xf8 */ + ASCn_TBSRC_t TBSRC; /* 0xfc */ +} tUartRegs; + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/** \brief Timeout time for the reception of a CTO packet. The timer is started upon + * reception of the first packet byte. + */ +#define UART_CTO_RX_PACKET_TIMEOUT_MS (100u) + + +/**************************************************************************************** +* Register definitions +****************************************************************************************/ +#if (BOOT_COM_UART_CHANNEL_INDEX == 0) +/** \brief Set UART base address to ASC0. */ +#define UARTx ((tUartRegs *) (blt_int32u)0xf0000a00) +#elif (BOOT_COM_UART_CHANNEL_INDEX == 1) +/** \brief Set UART base address to ASC1. */ +#define UARTx ((tUartRegs *) (blt_int32u)0xf0000b00) +#else +/** \brief Set UART base address to ASC0 by default. */ +#define UARTx ((tUartRegs *) (blt_int32u)0xf0000a00) +#endif + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +static blt_bool UartReceiveByte(blt_int8u *data); +static blt_bool UartTransmitByte(blt_int8u data); + + +/************************************************************************************//** +** \brief Initializes the UART communication interface. +** \return none. +** +****************************************************************************************/ +void UartInit(void) +{ + blt_int32u frequency, reload_value, fdv, dfreq; + + /* Compute system frequency and reload value for ASC */ + frequency = BOOT_CPU_SYSTEM_SPEED_KHZ * 1000; + + /* reload_value = fdv/512 * freq/16/baudrate -1 ==> + * reload_value = (512*freq)/(baudrate * 512*16) - 1 + * fdv = (reload_value + 1) * (baudrate*512*16/freq) + * reload_value = (frequency / 32) / baudrate - 1; + */ + reload_value = (frequency / ((blt_int32u)BOOT_COM_UART_BAUDRATE * 16)) - 1; + dfreq = frequency / (16*512); + fdv = (reload_value + 1) * (blt_int32u)BOOT_COM_UART_BAUDRATE / dfreq; + + /* enable ASC module */ + CpuEnterInitMode(); + ASC0_CLC.bits.RMC = 1; + ASC0_CLC.bits.DISR = 0; + CpuLeaveInitMode(); + + /* configure the ASC module for 8,n,1 */ + UARTx->CON.reg = 0; + UARTx->BG.reg = reload_value; + UARTx->FDV.reg = fdv; + + UARTx->CON.bits.M = 0x01; + UARTx->CON.bits.R = 1; + UARTx->CON.bits.REN = 1; + UARTx->CON.bits.FDE = 1; +} /*** end of UartInit ***/ + + +/************************************************************************************//** +** \brief Transmits a packet formatted for the communication interface. +** \param data Pointer to byte array with data that it to be transmitted. +** \param len Number of bytes that are to be transmitted. +** \return none. +** +****************************************************************************************/ +void UartTransmitPacket(blt_int8u *data, blt_int8u len) +{ + blt_int16u data_index; + blt_bool result; + + /* verify validity of the len-paramenter */ + ASSERT_RT(len <= BOOT_COM_UART_TX_MAX_DATA); + + /* first transmit the length of the packet */ + result = UartTransmitByte(len); + ASSERT_RT(result == BLT_TRUE); + + /* transmit all the packet bytes one-by-one */ + for (data_index = 0; data_index < len; data_index++) + { + /* keep the watchdog happy */ + CopService(); + /* write byte */ + result = UartTransmitByte(data[data_index]); + ASSERT_RT(result == BLT_TRUE); + } +} /*** end of UartTransmitPacket ***/ + + +/************************************************************************************//** +** \brief Receives a communication interface packet if one is present. +** \param data Pointer to byte array where the data is to be stored. +** \return BLT_TRUE if a packet was received, BLT_FALSE otherwise. +** +****************************************************************************************/ +blt_bool UartReceivePacket(blt_int8u *data) +{ + static blt_int8u xcpCtoReqPacket[BOOT_COM_UART_RX_MAX_DATA+1]; /* one extra for length */ + static blt_int8u xcpCtoRxLength; + static blt_bool xcpCtoRxInProgress = BLT_FALSE; + static blt_int32u xcpCtoRxStartTime = 0; + + /* start of cto packet received? */ + if (xcpCtoRxInProgress == BLT_FALSE) + { + /* store the message length when received */ + if (UartReceiveByte(&xcpCtoReqPacket[0]) == BLT_TRUE) + { + if (xcpCtoReqPacket[0] > 0) + { + /* store the start time */ + xcpCtoRxStartTime = TimerGet(); + /* reset packet data count */ + xcpCtoRxLength = 0; + /* indicate that a cto packet is being received */ + xcpCtoRxInProgress = BLT_TRUE; + } + } + } + else + { + /* store the next packet byte */ + if (UartReceiveByte(&xcpCtoReqPacket[xcpCtoRxLength+1]) == BLT_TRUE) + { + /* increment the packet data count */ + xcpCtoRxLength++; + + /* check to see if the entire packet was received */ + if (xcpCtoRxLength == xcpCtoReqPacket[0]) + { + /* copy the packet data */ + CpuMemCopy((blt_int32u)data, (blt_int32u)&xcpCtoReqPacket[1], xcpCtoRxLength); + /* done with cto packet reception */ + xcpCtoRxInProgress = BLT_FALSE; + /* packet reception complete */ + return BLT_TRUE; + } + } + else + { + /* check packet reception timeout */ + if (TimerGet() > (xcpCtoRxStartTime + UART_CTO_RX_PACKET_TIMEOUT_MS)) + { + /* cancel cto packet reception due to timeout. note that that automaticaly + * discards the already received packet bytes, allowing the host to retry. + */ + xcpCtoRxInProgress = BLT_FALSE; + } + } + } + /* packet reception not yet complete */ + return BLT_FALSE; +} /*** end of UartReceivePacket ***/ + + +/************************************************************************************//** +** \brief Receives a communication interface byte if one is present. +** \param data Pointer to byte where the data is to be stored. +** \return BLT_TRUE if a byte was received, BLT_FALSE otherwise. +** +****************************************************************************************/ +static blt_bool UartReceiveByte(blt_int8u *data) +{ + blt_bool result = BLT_FALSE; + + /* reception event pending? */ + if (UARTx->RSRC.bits.SRR != 0) + { + /* read out the newly received byte */ + *data = UARTx->RBUF.bits.RD_VALUE; + /* reset the reception event flag */ + UARTx->RSRC.bits.CLRR = 1; + /* set result to indicate that a new byte was received */ + result = BLT_TRUE; + } + + /* inform caller about the result */ + return result; +} /*** end of UartReceiveByte ***/ + + +/************************************************************************************//** +** \brief Transmits a communication interface byte. +** \param data Value of byte that is to be transmitted. +** \return BLT_TRUE if the byte was transmitted, BLT_FALSE otherwise. +** +****************************************************************************************/ +static blt_bool UartTransmitByte(blt_int8u data) +{ + /* reset transmit buffer interrupt request */ + UARTx->TBSRC.bits.CLRR = 1; + /* write byte to transmit buffer register */ + UARTx->TBUF.reg = data; + /* wait for transmit buffer register to be empty */ + while(UARTx->TBSRC.bits.SRR == 0) + { + CopService(); + } + /* byte transmitted */ + return BLT_TRUE; +} /*** end of UartTransmitByte ***/ +#endif /* BOOT_COM_UART_ENABLE > 0 */ + + +/*********************************** end of uart.c *************************************/ diff --git a/Target/Source/TRICORE_TC1798/uart.h b/Target/Source/TRICORE_TC1798/uart.h new file mode 100644 index 00000000..02ba5751 --- /dev/null +++ b/Target/Source/TRICORE_TC1798/uart.h @@ -0,0 +1,47 @@ +/************************************************************************************//** +* \file Source\TRICORE_TC1798\uart.h +* \brief Bootloader UART communication interface header file. +* \ingroup Target_TRICORE_TC1798 +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2015 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT 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 3 of the License, or (at your option) any later +* version. +* +* OpenBLT 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 OpenBLT. +* If not, see . +* +* A special exception to the GPL is included to allow you to distribute a combined work +* that includes OpenBLT without being obliged to provide the source code for any +* proprietary components. The exception text is included at the bottom of the license +* file . +* +* \endinternal +****************************************************************************************/ +#ifndef UART_H +#define UART_H + +#if (BOOT_COM_UART_ENABLE > 0) +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +void UartInit(void); +void UartTransmitPacket(blt_int8u *data, blt_int8u len); +blt_bool UartReceivePacket(blt_int8u *data); +#endif /* BOOT_COM_UART_ENABLE > 0 */ + + +#endif /* UART_H */ +/*********************************** end of uart.h *************************************/