Official mbed Real Time Operating System based on the RTX implementation of the CMSIS-RTOS API open standard.

Fork of mbed-rtos by mbed official

Committer:
bogdanm
Date:
Mon Aug 05 14:12:52 2013 +0300
Revision:
13:869ef732a8a2
Parent:
rtx/LPC4088/ARM/HAL_CM4.c@12:58b30ac3f00e
Update sources to revision 64

Who changed what in which revision?

UserRevisionLine numberNew contents of line
emilmont 12:58b30ac3f00e 1 /*----------------------------------------------------------------------------
emilmont 12:58b30ac3f00e 2 * RL-ARM - RTX
emilmont 12:58b30ac3f00e 3 *----------------------------------------------------------------------------
emilmont 12:58b30ac3f00e 4 * Name: HAL_CM4.C
emilmont 12:58b30ac3f00e 5 * Purpose: Hardware Abstraction Layer for Cortex-M4
emilmont 12:58b30ac3f00e 6 * Rev.: V4.70
emilmont 12:58b30ac3f00e 7 *----------------------------------------------------------------------------
emilmont 12:58b30ac3f00e 8 *
emilmont 12:58b30ac3f00e 9 * Copyright (c) 1999-2009 KEIL, 2009-2013 ARM Germany GmbH
emilmont 12:58b30ac3f00e 10 * All rights reserved.
emilmont 12:58b30ac3f00e 11 * Redistribution and use in source and binary forms, with or without
emilmont 12:58b30ac3f00e 12 * modification, are permitted provided that the following conditions are met:
emilmont 12:58b30ac3f00e 13 * - Redistributions of source code must retain the above copyright
emilmont 12:58b30ac3f00e 14 * notice, this list of conditions and the following disclaimer.
emilmont 12:58b30ac3f00e 15 * - Redistributions in binary form must reproduce the above copyright
emilmont 12:58b30ac3f00e 16 * notice, this list of conditions and the following disclaimer in the
emilmont 12:58b30ac3f00e 17 * documentation and/or other materials provided with the distribution.
emilmont 12:58b30ac3f00e 18 * - Neither the name of ARM nor the names of its contributors may be used
emilmont 12:58b30ac3f00e 19 * to endorse or promote products derived from this software without
emilmont 12:58b30ac3f00e 20 * specific prior written permission.
emilmont 12:58b30ac3f00e 21 *
emilmont 12:58b30ac3f00e 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
emilmont 12:58b30ac3f00e 23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
emilmont 12:58b30ac3f00e 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
emilmont 12:58b30ac3f00e 25 * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
emilmont 12:58b30ac3f00e 26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
emilmont 12:58b30ac3f00e 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
emilmont 12:58b30ac3f00e 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
emilmont 12:58b30ac3f00e 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
emilmont 12:58b30ac3f00e 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
emilmont 12:58b30ac3f00e 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
emilmont 12:58b30ac3f00e 32 * POSSIBILITY OF SUCH DAMAGE.
emilmont 12:58b30ac3f00e 33 *---------------------------------------------------------------------------*/
emilmont 12:58b30ac3f00e 34
emilmont 12:58b30ac3f00e 35 #include "rt_TypeDef.h"
emilmont 12:58b30ac3f00e 36 #include "RTX_Conf.h"
emilmont 12:58b30ac3f00e 37 #include "rt_System.h"
emilmont 12:58b30ac3f00e 38 #include "rt_HAL_CM.h"
emilmont 12:58b30ac3f00e 39 #include "rt_Task.h"
emilmont 12:58b30ac3f00e 40 #include "rt_MemBox.h"
emilmont 12:58b30ac3f00e 41
emilmont 12:58b30ac3f00e 42
emilmont 12:58b30ac3f00e 43 /*----------------------------------------------------------------------------
emilmont 12:58b30ac3f00e 44 * Functions
emilmont 12:58b30ac3f00e 45 *---------------------------------------------------------------------------*/
emilmont 12:58b30ac3f00e 46
emilmont 12:58b30ac3f00e 47
emilmont 12:58b30ac3f00e 48 /*--------------------------- rt_set_PSP ------------------------------------*/
emilmont 12:58b30ac3f00e 49
emilmont 12:58b30ac3f00e 50 __asm void rt_set_PSP (U32 stack) {
emilmont 12:58b30ac3f00e 51 MSR PSP,R0
emilmont 12:58b30ac3f00e 52 BX LR
emilmont 12:58b30ac3f00e 53 }
emilmont 12:58b30ac3f00e 54
emilmont 12:58b30ac3f00e 55
emilmont 12:58b30ac3f00e 56 /*--------------------------- rt_get_PSP ------------------------------------*/
emilmont 12:58b30ac3f00e 57
emilmont 12:58b30ac3f00e 58 __asm U32 rt_get_PSP (void) {
emilmont 12:58b30ac3f00e 59 MRS R0,PSP
emilmont 12:58b30ac3f00e 60 BX LR
emilmont 12:58b30ac3f00e 61 }
emilmont 12:58b30ac3f00e 62
emilmont 12:58b30ac3f00e 63
emilmont 12:58b30ac3f00e 64 /*--------------------------- os_set_env ------------------------------------*/
emilmont 12:58b30ac3f00e 65
emilmont 12:58b30ac3f00e 66 __asm void os_set_env (void) {
emilmont 12:58b30ac3f00e 67 /* Switch to Unprivileged/Privileged Thread mode, use PSP. */
emilmont 12:58b30ac3f00e 68 MOV R0,SP ; PSP = MSP
emilmont 12:58b30ac3f00e 69 MSR PSP,R0
emilmont 12:58b30ac3f00e 70 LDR R0,=__cpp(&os_flags)
emilmont 12:58b30ac3f00e 71 LDRB R0,[R0]
emilmont 12:58b30ac3f00e 72 LSLS R0,#31
emilmont 12:58b30ac3f00e 73 MOVNE R0,#0x02 ; Privileged Thread mode, use PSP
emilmont 12:58b30ac3f00e 74 MOVEQ R0,#0x03 ; Unprivileged Thread mode, use PSP
emilmont 12:58b30ac3f00e 75 MSR CONTROL,R0
emilmont 12:58b30ac3f00e 76 BX LR
emilmont 12:58b30ac3f00e 77
emilmont 12:58b30ac3f00e 78 ALIGN
emilmont 12:58b30ac3f00e 79 }
emilmont 12:58b30ac3f00e 80
emilmont 12:58b30ac3f00e 81
emilmont 12:58b30ac3f00e 82 /*--------------------------- _alloc_box ------------------------------------*/
emilmont 12:58b30ac3f00e 83
emilmont 12:58b30ac3f00e 84 __asm void *_alloc_box (void *box_mem) {
emilmont 12:58b30ac3f00e 85 /* Function wrapper for Unprivileged/Privileged mode. */
emilmont 12:58b30ac3f00e 86 LDR R12,=__cpp(rt_alloc_box)
emilmont 12:58b30ac3f00e 87 MRS R3,IPSR
emilmont 12:58b30ac3f00e 88 LSLS R3,#24
emilmont 12:58b30ac3f00e 89 BXNE R12
emilmont 12:58b30ac3f00e 90 MRS R3,CONTROL
emilmont 12:58b30ac3f00e 91 LSLS R3,#31
emilmont 12:58b30ac3f00e 92 BXEQ R12
emilmont 12:58b30ac3f00e 93 SVC 0
emilmont 12:58b30ac3f00e 94 BX LR
emilmont 12:58b30ac3f00e 95
emilmont 12:58b30ac3f00e 96 ALIGN
emilmont 12:58b30ac3f00e 97 }
emilmont 12:58b30ac3f00e 98
emilmont 12:58b30ac3f00e 99
emilmont 12:58b30ac3f00e 100 /*--------------------------- _free_box -------------------------------------*/
emilmont 12:58b30ac3f00e 101
emilmont 12:58b30ac3f00e 102 __asm int _free_box (void *box_mem, void *box) {
emilmont 12:58b30ac3f00e 103 /* Function wrapper for Unprivileged/Privileged mode. */
emilmont 12:58b30ac3f00e 104 LDR R12,=__cpp(rt_free_box)
emilmont 12:58b30ac3f00e 105 MRS R3,IPSR
emilmont 12:58b30ac3f00e 106 LSLS R3,#24
emilmont 12:58b30ac3f00e 107 BXNE R12
emilmont 12:58b30ac3f00e 108 MRS R3,CONTROL
emilmont 12:58b30ac3f00e 109 LSLS R3,#31
emilmont 12:58b30ac3f00e 110 BXEQ R12
emilmont 12:58b30ac3f00e 111 SVC 0
emilmont 12:58b30ac3f00e 112 BX LR
emilmont 12:58b30ac3f00e 113
emilmont 12:58b30ac3f00e 114 ALIGN
emilmont 12:58b30ac3f00e 115 }
emilmont 12:58b30ac3f00e 116
emilmont 12:58b30ac3f00e 117
emilmont 12:58b30ac3f00e 118 /*-------------------------- SVC_Handler ------------------------------------*/
emilmont 12:58b30ac3f00e 119
emilmont 12:58b30ac3f00e 120 __asm void SVC_Handler (void) {
emilmont 12:58b30ac3f00e 121 PRESERVE8
emilmont 12:58b30ac3f00e 122
emilmont 12:58b30ac3f00e 123 IMPORT SVC_Count
emilmont 12:58b30ac3f00e 124 IMPORT SVC_Table
emilmont 12:58b30ac3f00e 125 IMPORT rt_stk_check
emilmont 12:58b30ac3f00e 126
emilmont 12:58b30ac3f00e 127 #ifdef IFX_XMC4XXX
emilmont 12:58b30ac3f00e 128 EXPORT SVC_Handler_Veneer
emilmont 12:58b30ac3f00e 129 SVC_Handler_Veneer
emilmont 12:58b30ac3f00e 130 #endif
emilmont 12:58b30ac3f00e 131
emilmont 12:58b30ac3f00e 132 MRS R0,PSP ; Read PSP
emilmont 12:58b30ac3f00e 133 LDR R1,[R0,#24] ; Read Saved PC from Stack
emilmont 12:58b30ac3f00e 134 LDRB R1,[R1,#-2] ; Load SVC Number
emilmont 12:58b30ac3f00e 135 CBNZ R1,SVC_User
emilmont 12:58b30ac3f00e 136
emilmont 12:58b30ac3f00e 137 LDM R0,{R0-R3,R12} ; Read R0-R3,R12 from stack
emilmont 12:58b30ac3f00e 138 PUSH {R4,LR} ; Save EXC_RETURN
emilmont 12:58b30ac3f00e 139 BLX R12 ; Call SVC Function
emilmont 12:58b30ac3f00e 140 POP {R4,LR} ; Restore EXC_RETURN
emilmont 12:58b30ac3f00e 141
emilmont 12:58b30ac3f00e 142 MRS R12,PSP ; Read PSP
emilmont 12:58b30ac3f00e 143 STM R12,{R0-R2} ; Store return values
emilmont 12:58b30ac3f00e 144
emilmont 12:58b30ac3f00e 145 LDR R3,=__cpp(&os_tsk)
emilmont 12:58b30ac3f00e 146 LDM R3,{R1,R2} ; os_tsk.run, os_tsk.new
emilmont 12:58b30ac3f00e 147 CMP R1,R2
emilmont 12:58b30ac3f00e 148 #ifdef IFX_XMC4XXX
emilmont 12:58b30ac3f00e 149 PUSHEQ {LR}
emilmont 12:58b30ac3f00e 150 POPEQ {PC}
emilmont 12:58b30ac3f00e 151 #else
emilmont 12:58b30ac3f00e 152 BXEQ LR ; RETI, no task switch
emilmont 12:58b30ac3f00e 153 #endif
emilmont 12:58b30ac3f00e 154
emilmont 12:58b30ac3f00e 155 CBZ R1,SVC_Next ; Runtask deleted?
emilmont 12:58b30ac3f00e 156 TST LR,#0x10 ; is it extended frame?
emilmont 12:58b30ac3f00e 157 VSTMDBEQ R12!,{S16-S31} ; yes, stack also VFP hi-regs
emilmont 12:58b30ac3f00e 158 MOVEQ R0,#0x01 ; os_tsk->stack_frame val
emilmont 12:58b30ac3f00e 159 MOVNE R0,#0x00
emilmont 12:58b30ac3f00e 160 STRB R0,[R1,#TCB_STACKF] ; os_tsk.run->stack_frame = val
emilmont 12:58b30ac3f00e 161 STMDB R12!,{R4-R11} ; Save Old context
emilmont 12:58b30ac3f00e 162 STR R12,[R1,#TCB_TSTACK] ; Update os_tsk.run->tsk_stack
emilmont 12:58b30ac3f00e 163
emilmont 12:58b30ac3f00e 164 PUSH {R2,R3}
emilmont 12:58b30ac3f00e 165 BL rt_stk_check ; Check for Stack overflow
emilmont 12:58b30ac3f00e 166 POP {R2,R3}
emilmont 12:58b30ac3f00e 167
emilmont 12:58b30ac3f00e 168 SVC_Next
emilmont 12:58b30ac3f00e 169 STR R2,[R3] ; os_tsk.run = os_tsk.new
emilmont 12:58b30ac3f00e 170
emilmont 12:58b30ac3f00e 171 LDR R12,[R2,#TCB_TSTACK] ; os_tsk.new->tsk_stack
emilmont 12:58b30ac3f00e 172 LDMIA R12!,{R4-R11} ; Restore New Context
emilmont 12:58b30ac3f00e 173 LDRB R0,[R2,#TCB_STACKF] ; Stack Frame
emilmont 12:58b30ac3f00e 174 CMP R0,#0 ; Basic/Extended Stack Frame
emilmont 12:58b30ac3f00e 175 VLDMIANE R12!,{S16-S31} ; restore VFP hi-registers
emilmont 12:58b30ac3f00e 176 MVNNE LR,#:NOT:0xFFFFFFED ; set EXC_RETURN value
emilmont 12:58b30ac3f00e 177 MVNEQ LR,#:NOT:0xFFFFFFFD
emilmont 12:58b30ac3f00e 178 MSR PSP,R12 ; Write PSP
emilmont 12:58b30ac3f00e 179
emilmont 12:58b30ac3f00e 180 SVC_Exit
emilmont 12:58b30ac3f00e 181 #ifdef IFX_XMC4XXX
emilmont 12:58b30ac3f00e 182 PUSH {LR}
emilmont 12:58b30ac3f00e 183 POP {PC}
emilmont 12:58b30ac3f00e 184 #else
emilmont 12:58b30ac3f00e 185 BX LR
emilmont 12:58b30ac3f00e 186 #endif
emilmont 12:58b30ac3f00e 187
emilmont 12:58b30ac3f00e 188 /*------------------- User SVC ------------------------------*/
emilmont 12:58b30ac3f00e 189
emilmont 12:58b30ac3f00e 190 SVC_User
emilmont 12:58b30ac3f00e 191 PUSH {R4,LR} ; Save Registers
emilmont 12:58b30ac3f00e 192 LDR R2,=SVC_Count
emilmont 12:58b30ac3f00e 193 LDR R2,[R2]
emilmont 12:58b30ac3f00e 194 CMP R1,R2
emilmont 12:58b30ac3f00e 195 BHI SVC_Done ; Overflow
emilmont 12:58b30ac3f00e 196
emilmont 12:58b30ac3f00e 197 LDR R4,=SVC_Table-4
emilmont 12:58b30ac3f00e 198 LDR R4,[R4,R1,LSL #2] ; Load SVC Function Address
emilmont 12:58b30ac3f00e 199
emilmont 12:58b30ac3f00e 200 LDM R0,{R0-R3,R12} ; Read R0-R3,R12 from stack
emilmont 12:58b30ac3f00e 201 BLX R4 ; Call SVC Function
emilmont 12:58b30ac3f00e 202
emilmont 12:58b30ac3f00e 203 MRS R12,PSP
emilmont 12:58b30ac3f00e 204 STM R12,{R0-R3} ; Function return values
emilmont 12:58b30ac3f00e 205 SVC_Done
emilmont 12:58b30ac3f00e 206 POP {R4,PC} ; RETI
emilmont 12:58b30ac3f00e 207
emilmont 12:58b30ac3f00e 208 ALIGN
emilmont 12:58b30ac3f00e 209 }
emilmont 12:58b30ac3f00e 210
emilmont 12:58b30ac3f00e 211
emilmont 12:58b30ac3f00e 212 /*-------------------------- PendSV_Handler ---------------------------------*/
emilmont 12:58b30ac3f00e 213
emilmont 12:58b30ac3f00e 214 __asm void PendSV_Handler (void) {
emilmont 12:58b30ac3f00e 215 PRESERVE8
emilmont 12:58b30ac3f00e 216
emilmont 12:58b30ac3f00e 217 #ifdef IFX_XMC4XXX
emilmont 12:58b30ac3f00e 218 EXPORT PendSV_Handler_Veneer
emilmont 12:58b30ac3f00e 219 PendSV_Handler_Veneer
emilmont 12:58b30ac3f00e 220 #endif
emilmont 12:58b30ac3f00e 221
emilmont 12:58b30ac3f00e 222 PUSH {R4,LR} ; Save EXC_RETURN
emilmont 12:58b30ac3f00e 223 BL __cpp(rt_pop_req)
emilmont 12:58b30ac3f00e 224
emilmont 12:58b30ac3f00e 225 Sys_Switch
emilmont 12:58b30ac3f00e 226 POP {R4,LR} ; Restore EXC_RETURN
emilmont 12:58b30ac3f00e 227
emilmont 12:58b30ac3f00e 228 LDR R3,=__cpp(&os_tsk)
emilmont 12:58b30ac3f00e 229 LDM R3,{R1,R2} ; os_tsk.run, os_tsk.new
emilmont 12:58b30ac3f00e 230 CMP R1,R2
emilmont 12:58b30ac3f00e 231 #ifdef IFX_XMC4XXX
emilmont 12:58b30ac3f00e 232 PUSHEQ {LR}
emilmont 12:58b30ac3f00e 233 POPEQ {PC}
emilmont 12:58b30ac3f00e 234 #else
emilmont 12:58b30ac3f00e 235 BXEQ LR ; RETI, no task switch
emilmont 12:58b30ac3f00e 236 #endif
emilmont 12:58b30ac3f00e 237
emilmont 12:58b30ac3f00e 238 MRS R12,PSP ; Read PSP
emilmont 12:58b30ac3f00e 239 TST LR,#0x10 ; is it extended frame?
emilmont 12:58b30ac3f00e 240 VSTMDBEQ R12!,{S16-S31} ; yes, stack also VFP hi-regs
emilmont 12:58b30ac3f00e 241 MOVEQ R0,#0x01 ; os_tsk->stack_frame val
emilmont 12:58b30ac3f00e 242 MOVNE R0,#0x00
emilmont 12:58b30ac3f00e 243 STRB R0,[R1,#TCB_STACKF] ; os_tsk.run->stack_frame = val
emilmont 12:58b30ac3f00e 244 STMDB R12!,{R4-R11} ; Save Old context
emilmont 12:58b30ac3f00e 245 STR R12,[R1,#TCB_TSTACK] ; Update os_tsk.run->tsk_stack
emilmont 12:58b30ac3f00e 246
emilmont 12:58b30ac3f00e 247 PUSH {R2,R3}
emilmont 12:58b30ac3f00e 248 BL rt_stk_check ; Check for Stack overflow
emilmont 12:58b30ac3f00e 249 POP {R2,R3}
emilmont 12:58b30ac3f00e 250
emilmont 12:58b30ac3f00e 251 STR R2,[R3] ; os_tsk.run = os_tsk.new
emilmont 12:58b30ac3f00e 252
emilmont 12:58b30ac3f00e 253 LDR R12,[R2,#TCB_TSTACK] ; os_tsk.new->tsk_stack
emilmont 12:58b30ac3f00e 254 LDMIA R12!,{R4-R11} ; Restore New Context
emilmont 12:58b30ac3f00e 255 LDRB R0,[R2,#TCB_STACKF] ; Stack Frame
emilmont 12:58b30ac3f00e 256 CMP R0,#0 ; Basic/Extended Stack Frame
emilmont 12:58b30ac3f00e 257 VLDMIANE R12!,{S16-S31} ; restore VFP hi-regs
emilmont 12:58b30ac3f00e 258 MVNNE LR,#:NOT:0xFFFFFFED ; set EXC_RETURN value
emilmont 12:58b30ac3f00e 259 MVNEQ LR,#:NOT:0xFFFFFFFD
emilmont 12:58b30ac3f00e 260 MSR PSP,R12 ; Write PSP
emilmont 12:58b30ac3f00e 261
emilmont 12:58b30ac3f00e 262 Sys_Exit
emilmont 12:58b30ac3f00e 263 #ifdef IFX_XMC4XXX
emilmont 12:58b30ac3f00e 264 PUSH {LR}
emilmont 12:58b30ac3f00e 265 POP {PC}
emilmont 12:58b30ac3f00e 266 #else
emilmont 12:58b30ac3f00e 267 BX LR ; Return to Thread Mode
emilmont 12:58b30ac3f00e 268 #endif
emilmont 12:58b30ac3f00e 269
emilmont 12:58b30ac3f00e 270 ALIGN
emilmont 12:58b30ac3f00e 271 }
emilmont 12:58b30ac3f00e 272
emilmont 12:58b30ac3f00e 273
emilmont 12:58b30ac3f00e 274 /*-------------------------- SysTick_Handler --------------------------------*/
emilmont 12:58b30ac3f00e 275
emilmont 12:58b30ac3f00e 276 __asm void SysTick_Handler (void) {
emilmont 12:58b30ac3f00e 277 PRESERVE8
emilmont 12:58b30ac3f00e 278
emilmont 12:58b30ac3f00e 279 #ifdef IFX_XMC4XXX
emilmont 12:58b30ac3f00e 280 EXPORT SysTick_Handler_Veneer
emilmont 12:58b30ac3f00e 281 SysTick_Handler_Veneer
emilmont 12:58b30ac3f00e 282 #endif
emilmont 12:58b30ac3f00e 283
emilmont 12:58b30ac3f00e 284 PUSH {R4,LR} ; Save EXC_RETURN
emilmont 12:58b30ac3f00e 285 BL __cpp(rt_systick)
emilmont 12:58b30ac3f00e 286 B Sys_Switch
emilmont 12:58b30ac3f00e 287
emilmont 12:58b30ac3f00e 288 ALIGN
emilmont 12:58b30ac3f00e 289 }
emilmont 12:58b30ac3f00e 290
emilmont 12:58b30ac3f00e 291
emilmont 12:58b30ac3f00e 292 /*-------------------------- OS_Tick_Handler --------------------------------*/
emilmont 12:58b30ac3f00e 293
emilmont 12:58b30ac3f00e 294 __asm void OS_Tick_Handler (void) {
emilmont 12:58b30ac3f00e 295 PRESERVE8
emilmont 12:58b30ac3f00e 296
emilmont 12:58b30ac3f00e 297 PUSH {R4,LR} ; Save EXC_RETURN
emilmont 12:58b30ac3f00e 298 BL __cpp(os_tick_irqack)
emilmont 12:58b30ac3f00e 299 BL __cpp(rt_systick)
emilmont 12:58b30ac3f00e 300 B Sys_Switch
emilmont 12:58b30ac3f00e 301
emilmont 12:58b30ac3f00e 302 ALIGN
emilmont 12:58b30ac3f00e 303 }
emilmont 12:58b30ac3f00e 304
emilmont 12:58b30ac3f00e 305
emilmont 12:58b30ac3f00e 306 /*----------------------------------------------------------------------------
emilmont 12:58b30ac3f00e 307 * end of file
emilmont 12:58b30ac3f00e 308 *---------------------------------------------------------------------------*/
emilmont 12:58b30ac3f00e 309