日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

GD32VF103启动流程分析

發布時間:2023/12/10 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 GD32VF103启动流程分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1 *.S文件分析

1.1 文件位置

啟動文件為:freertos_GD32VF103/nuclei_sdk/SoC/gd32vf103/Common/Source/GCC/startup_gd32vf103.S

1.2 中斷異常背景知識

GD32VF103的中斷控制器具有兩種模式:默認模式和ECLIC模式。模式的設置由mtvec[5:0]指定,當mtvec[5:0]==6’b000011時為ECLIC模式。處理函數入口由mtvec[31:6]指定(處理函數入口地址必須為64字節對齊)。

默認模式:所有中斷,異常,NMI都由mtvec[31:6]指定的處理函數進行處理;
ECLIC模式:異常,NMI由mtvec[31:6]指定的處理函數進行處理,中斷由mtvt2寄存器指定的處理函數進行處理,并由mtvt寄存器指定中斷向量表地址

RISC-V處理器的中斷系統和NVIC的中斷系統不同,RISC-V的中斷系統分為NMI,異常,外部中斷三個概念。因此也分由不同的向量寄存器設置入口地址。由于risc-v的中斷和異常都不進行自動現場保護,所以需要軟件手動進行現場保護處理,因此無法直接使用C函數響應中斷,需要一個基于匯編的入口函數進行處理,在匯編入口函數中再對C函數進行調用。

GD32VF103在ECLIC中斷模式中,mtvec用于保存NMI和異常入口函數地址,不會進行自動的向量表調用。需要由入口函數進行轉發處理。在官方代碼中,響應函數為entry.S中的trap_entry函數。

mtvt2用于保存中斷響應入口函數地址,處理函數位于entry.S中的irq_entry,函數mtvt保存向量表地址,mtvt2寄存器的irq_entry函數和mtvt寄存器中的向量表共同組成一個two-stage的中斷向量表系統,irq_entry中對現場進行保護,并觸發ECLIC調用中斷向量表。

GD32VF103 ECLIC的中斷向量寄存器

寄存器全名說明
mtvecMachine Trap-Vector Base-Address Register用于配置中斷和異常處理程序的入口地址。一般用于處理NMI和異常中斷
mtvtECLIC Interrupt Vector Table Base Address用于保存ECLIC中斷向量表的基地址,此基地址至少為64byte對齊。
mtvt2ECLIC non-vectored interrupt handler address register用于指定ECLIC非向量模式的中斷common-code入口地址。

2 源碼分析

/** Copyright (c) 2019 Nuclei Limited. All rights reserved.** SPDX-License-Identifier: Apache-2.0** Licensed under the Apache License, Version 2.0 (the License); you may* not use this file except in compliance with the License.* You may obtain a copy of the License at** www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an AS IS BASIS, WITHOUT* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/ /******************************************************************************* \file startup_gd32vf103.S* \brief NMSIS Nuclei N/NX Class Core based Core Device Startup File for* Device gd32vf103* \version V1.00* \date 21 Nov 2019********************************************************************************/#include "riscv_encoding.h".macro DECLARE_INT_HANDLER INT_HDL_NAME #if defined(__riscv_xlen) && (__riscv_xlen == 32).word \INT_HDL_NAME #else.dword \INT_HDL_NAME #endif .endm/** Put the interrupt vectors in this section according to the run mode:* FlashXIP: .vtable* ILM: .vtable* Flash: .vtable_ilm*///中斷處理函數定義 #if defined(DOWNLOAD_MODE) && (DOWNLOAD_MODE == DOWNLOAD_MODE_FLASH).section .vtable_ilm #else.section .vtable #endif.weak eclic_msip_handler.weak eclic_mtip_handler.weak eclic_bwei_handler.weak eclic_pmovi_handler.weak WWDGT_IRQHandler.weak LVD_IRQHandler.weak TAMPER_IRQHandler.weak RTC_IRQHandler.weak FMC_IRQHandler.weak RCU_IRQHandler.weak EXTI0_IRQHandler.weak EXTI1_IRQHandler.weak EXTI2_IRQHandler.weak EXTI3_IRQHandler.weak EXTI4_IRQHandler.weak DMA0_Channel0_IRQHandler.weak DMA0_Channel1_IRQHandler.weak DMA0_Channel2_IRQHandler.weak DMA0_Channel3_IRQHandler.weak DMA0_Channel4_IRQHandler.weak DMA0_Channel5_IRQHandler.weak DMA0_Channel6_IRQHandler.weak ADC0_1_IRQHandler.weak CAN0_TX_IRQHandler.weak CAN0_RX0_IRQHandler.weak CAN0_RX1_IRQHandler.weak CAN0_EWMC_IRQHandler.weak EXTI5_9_IRQHandler.weak TIMER0_BRK_IRQHandler.weak TIMER0_UP_IRQHandler.weak TIMER0_TRG_CMT_IRQHandler.weak TIMER0_Channel_IRQHandler.weak TIMER1_IRQHandler.weak TIMER2_IRQHandler.weak TIMER3_IRQHandler.weak I2C0_EV_IRQHandler.weak I2C0_ER_IRQHandler.weak I2C1_EV_IRQHandler.weak I2C1_ER_IRQHandler.weak SPI0_IRQHandler.weak SPI1_IRQHandler.weak USART0_IRQHandler.weak USART1_IRQHandler.weak USART2_IRQHandler.weak EXTI10_15_IRQHandler.weak RTC_Alarm_IRQHandler.weak USBFS_WKUP_IRQHandler.weak EXMC_IRQHandler.weak TIMER4_IRQHandler.weak SPI2_IRQHandler.weak UART3_IRQHandler.weak UART4_IRQHandler.weak TIMER5_IRQHandler.weak TIMER6_IRQHandler.weak DMA1_Channel0_IRQHandler.weak DMA1_Channel1_IRQHandler.weak DMA1_Channel2_IRQHandler.weak DMA1_Channel3_IRQHandler.weak DMA1_Channel4_IRQHandler.weak CAN1_TX_IRQHandler.weak CAN1_RX0_IRQHandler.weak CAN1_RX1_IRQHandler.weak CAN1_EWMC_IRQHandler.weak USBFS_IRQHandler//中斷向量表定義中斷向量表vector_base被放置在.init段的首部從flash地址0x08000000開始。 //GD32VF103的中斷向量表實際是由ECLIC控制器CSR寄存器中的mtvec、mtvt、mtvt2寄存器指定 //GD32VF103的中斷控制器具有兩種模式:默認模式和ECLIC模式。模式的設置由mtvec[5:0]指定, //當mtvec[5:0]==6’b000011時為ECLIC模式。處理函數入口由mtvec[31:6]指定(處理函數入口地址必須為64字節對齊)。 //默認模式:所有中斷,異常,NMI都由mtvec[31:6]指定的處理函數進行處理; //ECLIC模式:異常,NMI由mtvec[31:6]指定的處理函數進行處理,中斷由mtvt2寄存器指定的處理函數進行處理,并由mtvt寄存器指定中斷向量表地址.globl vector_base vector_base: #if defined(DOWNLOAD_MODE) && (DOWNLOAD_MODE != DOWNLOAD_MODE_FLASH)j _start /* 0: Reserved, Jump to _start when reset for ILM/FlashXIP mode.*/.align LOG_REGBYTES /* Need to align 4 byte for RV32, 8 Byte for RV64 */ #elseDECLARE_INT_HANDLER default_intexc_handler /* 0: Reserved, default handler for Flash download mode */ #endifDECLARE_INT_HANDLER default_intexc_handler /* 1: Reserved */DECLARE_INT_HANDLER default_intexc_handler /* 2: Reserved */DECLARE_INT_HANDLER eclic_msip_handler /* 3: Machine software interrupt */DECLARE_INT_HANDLER default_intexc_handler /* 4: Reserved */DECLARE_INT_HANDLER default_intexc_handler /* 5: Reserved */DECLARE_INT_HANDLER default_intexc_handler /* 6: Reserved */DECLARE_INT_HANDLER eclic_mtip_handler /* 7: Machine timer interrupt */DECLARE_INT_HANDLER default_intexc_handler /* 8: Reserved */DECLARE_INT_HANDLER default_intexc_handler /* 9: Reserved */DECLARE_INT_HANDLER default_intexc_handler /* 10: Reserved */DECLARE_INT_HANDLER default_intexc_handler /* 11: Reserved */DECLARE_INT_HANDLER default_intexc_handler /* 12: Reserved */DECLARE_INT_HANDLER default_intexc_handler /* 13: Reserved */DECLARE_INT_HANDLER default_intexc_handler /* 14: Reserved */DECLARE_INT_HANDLER default_intexc_handler /* 15: Reserved */DECLARE_INT_HANDLER default_intexc_handler /* 16: Reserved */DECLARE_INT_HANDLER eclic_bwei_handler /* 17: Bus Error interrupt */DECLARE_INT_HANDLER eclic_pmovi_handler /* 18: Performance Monitor */DECLARE_INT_HANDLER WWDGT_IRQHandlerDECLARE_INT_HANDLER LVD_IRQHandlerDECLARE_INT_HANDLER TAMPER_IRQHandlerDECLARE_INT_HANDLER RTC_IRQHandlerDECLARE_INT_HANDLER FMC_IRQHandlerDECLARE_INT_HANDLER RCU_IRQHandlerDECLARE_INT_HANDLER EXTI0_IRQHandlerDECLARE_INT_HANDLER EXTI1_IRQHandlerDECLARE_INT_HANDLER EXTI2_IRQHandlerDECLARE_INT_HANDLER EXTI3_IRQHandlerDECLARE_INT_HANDLER EXTI4_IRQHandlerDECLARE_INT_HANDLER DMA0_Channel0_IRQHandlerDECLARE_INT_HANDLER DMA0_Channel1_IRQHandlerDECLARE_INT_HANDLER DMA0_Channel2_IRQHandlerDECLARE_INT_HANDLER DMA0_Channel3_IRQHandlerDECLARE_INT_HANDLER DMA0_Channel4_IRQHandlerDECLARE_INT_HANDLER DMA0_Channel5_IRQHandlerDECLARE_INT_HANDLER DMA0_Channel6_IRQHandlerDECLARE_INT_HANDLER ADC0_1_IRQHandlerDECLARE_INT_HANDLER CAN0_TX_IRQHandlerDECLARE_INT_HANDLER CAN0_RX0_IRQHandlerDECLARE_INT_HANDLER CAN0_RX1_IRQHandlerDECLARE_INT_HANDLER CAN0_EWMC_IRQHandlerDECLARE_INT_HANDLER EXTI5_9_IRQHandlerDECLARE_INT_HANDLER TIMER0_BRK_IRQHandlerDECLARE_INT_HANDLER TIMER0_UP_IRQHandlerDECLARE_INT_HANDLER TIMER0_TRG_CMT_IRQHandlerDECLARE_INT_HANDLER TIMER0_Channel_IRQHandlerDECLARE_INT_HANDLER TIMER1_IRQHandlerDECLARE_INT_HANDLER TIMER2_IRQHandlerDECLARE_INT_HANDLER TIMER3_IRQHandlerDECLARE_INT_HANDLER I2C0_EV_IRQHandlerDECLARE_INT_HANDLER I2C0_ER_IRQHandlerDECLARE_INT_HANDLER I2C1_EV_IRQHandlerDECLARE_INT_HANDLER I2C1_ER_IRQHandlerDECLARE_INT_HANDLER SPI0_IRQHandlerDECLARE_INT_HANDLER SPI1_IRQHandlerDECLARE_INT_HANDLER USART0_IRQHandlerDECLARE_INT_HANDLER USART1_IRQHandlerDECLARE_INT_HANDLER USART2_IRQHandlerDECLARE_INT_HANDLER EXTI10_15_IRQHandlerDECLARE_INT_HANDLER RTC_Alarm_IRQHandlerDECLARE_INT_HANDLER USBFS_WKUP_IRQHandlerDECLARE_INT_HANDLER default_intexc_handlerDECLARE_INT_HANDLER default_intexc_handlerDECLARE_INT_HANDLER default_intexc_handlerDECLARE_INT_HANDLER default_intexc_handlerDECLARE_INT_HANDLER default_intexc_handlerDECLARE_INT_HANDLER EXMC_IRQHandlerDECLARE_INT_HANDLER default_intexc_handlerDECLARE_INT_HANDLER TIMER4_IRQHandlerDECLARE_INT_HANDLER SPI2_IRQHandlerDECLARE_INT_HANDLER UART3_IRQHandlerDECLARE_INT_HANDLER UART4_IRQHandlerDECLARE_INT_HANDLER TIMER5_IRQHandlerDECLARE_INT_HANDLER TIMER6_IRQHandlerDECLARE_INT_HANDLER DMA1_Channel0_IRQHandlerDECLARE_INT_HANDLER DMA1_Channel1_IRQHandlerDECLARE_INT_HANDLER DMA1_Channel2_IRQHandlerDECLARE_INT_HANDLER DMA1_Channel3_IRQHandlerDECLARE_INT_HANDLER DMA1_Channel4_IRQHandlerDECLARE_INT_HANDLER default_intexc_handlerDECLARE_INT_HANDLER default_intexc_handlerDECLARE_INT_HANDLER CAN1_TX_IRQHandlerDECLARE_INT_HANDLER CAN1_RX0_IRQHandlerDECLARE_INT_HANDLER CAN1_RX1_IRQHandlerDECLARE_INT_HANDLER CAN1_EWMC_IRQHandlerDECLARE_INT_HANDLER USBFS_IRQHandler.section .init //指明此處section名為.init.globl _start //指明標簽_start的屬性為全局性.type _start,@function/*** Reset Handler called on controller reset*/ _start:/* ===== Startup Stage 1 ===== *//* Disable Global Interrupt */// 關閉所有中斷csrc CSR_MSTATUS, MSTATUS_MIE/* Jump to logical address first to ensure correct operation of RAM region *///把_start地址載入到a0,根據啟動位置的不同,_start可能在ram地址中也可能在flash中la a0, _start li a1, 1// a1 = a1 << 29 (a1=0x20000000,ram起始地址)slli a1, a1, 29 //if (a1 <= a0) goto _start0800檢測是否在ram中運行,如果在ram中運行,_start地址將會大于 0x20000000bleu a1, a0, _start0800//a1 = a1 >> 2 (a1=0x08000000 flash起始地址)srli a1, a1, 2//if (a1 <= a0) goto _start0800bleu a1, a0, _start0800//a0 =_start0800 程序地址不正確la a0, _start0800//a0 = a0+0x08000000 (把程序地址重新定位到flash中)add a0, a0, a1//跳轉到a0所存的地址jr a0_start0800:/* Initialize GP and Stack Pointer SP */.option push //保存編譯設置.option norelax //禁用相對尋址//設置全局變量指針la gp, __global_pointer$ //將標簽__global_pointer$所處的地址賦值給gp寄存器//標簽__global_pointer$在鏈接腳本中定義,見鏈接腳本__global_pointer$標簽.option pop//設置堆棧指針la sp, _sp //將標簽_sp所處的地址賦值給sp寄存器//標簽_sp在鏈接腳本中定義,見鏈接腳本_sp$標簽/** Set the the NMI base mnvec to share* with mtvec by setting CSR_MMISC_CTL* bit 9 NMI_CAUSE_FFF to 1*///mmisc_ctl = 0x200 ECLIC寄存器mmisc_ctl用于控制NMI中斷向量表,這里設置成和mtvec一致li t0, MMISC_CTL_NMI_CAUSE_FFFcsrs CSR_MMISC_CTL, t0/** Intialize ECLIC vector interrupt* base address mtvt to vector_base*///保存ECLIC中斷向量表的基地址,mtvt保存向量表地址la t0, vector_basecsrw CSR_MTVT, t0/** Set ECLIC non-vector entry to be controlled* by mtvt2 CSR register.* Intialize ECLIC non-vector interrupt* base address mtvt2 to irq_entry.*///mtvt2用于保存中斷響應入口函數地址la t0, irq_entrycsrw CSR_MTVT2, t0csrs CSR_MTVT2, 0x1/** Set Exception Entry MTVEC to exc_entry* Due to settings above, Exception and NMI* will share common entry.*///RISCV處理器在程序執行過程中,一旦遇到異常或者中斷,則終止當前程序流,處理器被強行跳轉到一 //個新的PC地址,該地址由mtvec寄存器指定。設置mtvec寄存器的值,使其指向異常處理函數入口//mtvec用于保存NMI和異常入口函數地址la t0, exc_entrycsrw CSR_MTVEC, t0/* Set the interrupt processing mode to ECLIC mode *///將中斷處理模式設置為ECLIC模式,默認模式和ECLIC模式。模式的設置由mtvec[5:0]指定li t0, 0x3fcsrc CSR_MTVEC, t0csrs CSR_MTVEC, 0x3/* ===== Startup Stage 2 ===== */#ifdef __riscv_flen/* Enable FPU */li t0, MSTATUS_FScsrs mstatus, t0csrw fcsr, x0 #endif/* Enable mcycle and minstret counter */csrci CSR_MCOUNTINHIBIT, 0x5//下列代碼判斷_ilm_lma和_ilm標簽的地址是否相同//如果相同,則意味著代碼直接從Flash中執行,那么直接跳轉到后面數字標簽2所在的代碼執行//如果不相同,則意味著代碼需要從Flash中上載至_ilm中執行,因此lw指令逐條將指令從Flash中讀取出來,然后使用sw指令//逐條寫入_ilm中,通過此方式完成將指令上載至_ilm中/* ===== Startup Stage 3 ===== *//** Load code section from FLASH to ILM* when code LMA is different with VMA*/la a0, _ilm_lma //將標簽_ilm_lma所處的地址賦值給a0寄存器//標簽_ilm_lma在鏈接腳本中定義,見鏈接腳本_ilm_lma標簽la a1, _ilm //將標簽_ilm所處的地址賦值給a1寄存器//標簽_ilm在鏈接腳本中定義,見鏈接腳本_ilm標簽/* If the ILM phy-address same as the logic-address, then quit */beq a0, a1, 2f //a0和a1的值分別為標簽_ilm_lma和_ilm標簽的地址,判斷其是否相等,如果相等//則直接跳轉到后面數字標簽2所在的位置la a2, _eilm //將_eilm所處我地址賦值給a2寄存器//標簽_eilm在鏈接腳本中定義,見鏈接腳本_eilm標簽//通過一個循環,將指令從Flash中搬到ITCM中bgeu a1, a2, 2f//如果_ilm標簽地址比_eilm標簽地址還大,屬于不正常的配置//如果放棄搬運,直接跳轉到后面數字標簽2所在的位置1:/* Load code section if necessary */lw t0, (a0) //從地址指針a0所在的位置(Flash中)讀取32位數sw t0, (a1) //將讀取的32位數寫入地址指針a1所在的位置(_ilm中)addi a0, a0, 4 //將地址指針a0寄存器加4(即32位)addi a1, a1, 4 //將地址指針a1寄存器加4(即32位)bltu a1, a2, 1b //跳回之前數字標簽1所在的位置 2:/* Load data section *///使用與上述相同的原理,通過一個循環,將數據從FLASH中搬運到DTCM中la a0, _data_lmala a1, _datala a2, _edatabgeu a1, a2, 2f 1:lw t0, (a0)sw t0, (a1)addi a0, a0, 4addi a1, a1, 4bltu a1, a2, 1b 2:/* Clear bss section *///BSS段是鏈接器預留的未初始化變量所處的地址段,引導程序必須對其初始化為0//此處通過一個循環來初始化BSS段la a0, __bss_startla a1, _endbgeu a0, a1, 2f 1:sw zero, (a0)addi a0, a0, 4bltu a0, a1, 1b 2:/** Call vendor defined SystemInit to* initialize the micro-controller system*///系統初始化,主要是時鐘初始化call SystemInit/* Call global constructors */la a0, __libc_fini_array //將標簽__libc_fini_array的值賦值給a0作為函數參數call atexit //調用atexit函數/* Call C/C++ constructor start up code */call __libc_init_array //調用__libc_init_array//上述 __libc_fini_array、atexit和__libc_init_array函數都是Newlib C運行庫的特殊庫函數,用于處理一些C/C++程序中//的全局性的構造和析構函數。//__libc_init_array函數會調用一個名為_init的函數/* do pre-init steps before main */call _premain_init/* ===== Call Main Function ===== *//* argc = argv = 0 *///函數調用時由a0和a1寄存器傳遞參數li a0, 0li a1, 0#ifdef RTOS_RTTHREAD// Call entry function when using RT-Threadcall entry //調用entry函數,開始執行entry函數 #elsecall main //調用main函數,開始執行main函數 #endif/* do post-main steps after main */call _postmain_fini1:j 1b //最后死循環,程序理論上不可能執行到此處

(1)__libc_init_array函數會調用一個名為_init的函數,該函數位于:freertos_GD32VF103/nuclei_sdk/SoC/gd32vf103/Common/Source/system_gd32vf103.c
_init函數源碼:

void _init(void) {/* Don't put any code here, please use _premain_init now *///該函數已經不在使用,使用_premain_init()函數 }

(2)由上述源碼可知,_init函數已經不在使用,使用_premain_init()函數,_premain_init()函數源碼:

void _premain_init(void) {/* TODO: Add your own initialization code here, called before main *///用來計算當前運行頻率SystemCoreClock = get_cpu_freq();/* configure USART *///調用gd_com_init()函數對UART模塊進行設計,串口打印信息就是要對uart進行初始化gd_com_init(SOC_DEBUG_UART);/* Display banner after UART initialized *///UART初始化以后打印相關信息,有興趣的可以進入函數看看打印了哪些內容SystemBannerPrint();/* Initialize exception default handlers *///初始化異常處理程序Exception_Init();/* ECLIC initialization, mainly MTH and NLBIT *///ECLIC初始化,主要是MTH和NLBITECLIC_Init(); }

(2-1)get_cpu_freq()函數源碼

uint32_t get_cpu_freq() {uint32_t cpu_freq;// warm upmeasure_cpu_freq(1);// measure for real//調用measure_cpu_freq()函數cpu_freq = measure_cpu_freq(100);return cpu_freq; }

調用measure_cpu_freq()函數,measure_cpu_freq()函數源碼:

uint32_t measure_cpu_freq(uint32_t n) {uint32_t start_mcycle, delta_mcycle;uint32_t start_mtime, delta_mtime;uint32_t mtime_freq = get_timer_freq();// Don't start measuruing until we see an mtime tickuint32_t tmp = (uint32_t)SysTimer_GetLoadValue();do {start_mtime = (uint32_t)SysTimer_GetLoadValue();start_mcycle = __RV_CSR_READ(CSR_MCYCLE); //通過讀取CSR寄存器MCYCLE得到當前時鐘周期,并作為初始計數值} while (start_mtime == tmp); //不斷觀察MTIME計數器并將其值作為初始化時間值do {delta_mtime = (uint32_t)SysTimer_GetLoadValue() - start_mtime;//通過讀取CSR寄存器MCYCLE得到當前時鐘周期,并與初始計數值相減得到這段時間消耗的時鐘周期delta_mcycle = __RV_CSR_READ(CSR_MCYCLE) - start_mcycle;} while (delta_mtime < n);//MTIME計數器的頻率是常開域的參考頻率,Core的運行頻率與CSR寄存器MCYCLE的值一致//通過MCYCLE和MTIME的相對關系計算出當前Core的時鐘頻率return (delta_mcycle / delta_mtime) * mtime_freq+ ((delta_mcycle % delta_mtime) * mtime_freq) / delta_mtime; }

(3)調用gd_com_init()函數對UART模塊進行設計,串口打印信息就是要對uart進行初始化,有興趣的同學可以自行查看
(4) SystemBannerPrint(),UART初始化以后打印相關信息,有興趣的可以進入函數看看打印了哪些內容 ;
(5)Exception_Init(),初始化異常處理程序
(6)ECLIC_Init(),ECLIC初始化,主要是MTH和NLBIT

3 中斷異常

3.1文件位置

中斷異常文件:freertos_GD32VF103/nuclei_sdk/SoC/gd32vf103/Common/Source/GCC/intexc_gd32vf103.S

3.2源碼分析

/** Copyright (c) 2019 Nuclei Limited. All rights reserved.** SPDX-License-Identifier: Apache-2.0** Licensed under the Apache License, Version 2.0 (the License); you may* not use this file except in compliance with the License.* You may obtain a copy of the License at** www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an AS IS BASIS, WITHOUT* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/ /******************************************************************************* \file intexc_gd32vf103.S* \brief NMSIS Interrupt and Exception Handling Template File* for Device gd32vf103* \version V1.00* \date 7 Jan 2020*******************************************************************************/#include "riscv_encoding.h"/*** \brief Global interrupt disabled* \details* This function disable global interrupt.* \remarks* - All the interrupt requests will be ignored by CPU.*/ .macro DISABLE_MIEcsrc CSR_MSTATUS, MSTATUS_MIE .endm/*** \brief Macro for context save* \details* This macro save ABI defined caller saved registers in the stack.* \remarks* - This Macro could use to save context when you enter to interrupt* or exception */ /* Save caller registers */ .macro SAVE_CONTEXT/* Allocate stack space for context saving *///根據宏定義更改堆棧指針,分配20個單字(40位)或者14個單字(28位)空間用于保存寄存器 #ifndef __riscv_32eaddi sp, sp, -20*REGBYTES #elseaddi sp, sp, -14*REGBYTES #endif /* __riscv_32e *///保存ABI定義的“調用者應存儲的寄存器(Caller saved register)”進入堆棧STORE x1, 0*REGBYTES(sp)STORE x4, 1*REGBYTES(sp)STORE x5, 2*REGBYTES(sp)STORE x6, 3*REGBYTES(sp)STORE x7, 4*REGBYTES(sp)STORE x10, 5*REGBYTES(sp)STORE x11, 6*REGBYTES(sp)STORE x12, 7*REGBYTES(sp)STORE x13, 8*REGBYTES(sp)STORE x14, 9*REGBYTES(sp)STORE x15, 10*REGBYTES(sp) #ifndef __riscv_32eSTORE x16, 14*REGBYTES(sp)STORE x17, 15*REGBYTES(sp)STORE x28, 16*REGBYTES(sp)STORE x29, 17*REGBYTES(sp)STORE x30, 18*REGBYTES(sp)STORE x31, 19*REGBYTES(sp) #endif /* __riscv_32e */ .endm/*** \brief Macro for restore caller registers* \details* This macro restore ABI defined caller saved registers from stack.* \remarks* - You could use this macro to restore context before you want return* from interrupt or exeception*/ /* Restore caller registers */ //回復用于從堆棧中恢復ABI定義的“調用者應存儲的寄存器(Caller saved register)” .macro RESTORE_CONTEXTLOAD x1, 0*REGBYTES(sp)LOAD x4, 1*REGBYTES(sp)LOAD x5, 2*REGBYTES(sp)LOAD x6, 3*REGBYTES(sp)LOAD x7, 4*REGBYTES(sp)LOAD x10, 5*REGBYTES(sp)LOAD x11, 6*REGBYTES(sp)LOAD x12, 7*REGBYTES(sp)LOAD x13, 8*REGBYTES(sp)LOAD x14, 9*REGBYTES(sp)LOAD x15, 10*REGBYTES(sp) #ifndef __riscv_32eLOAD x16, 14*REGBYTES(sp)LOAD x17, 15*REGBYTES(sp)LOAD x28, 16*REGBYTES(sp)LOAD x29, 17*REGBYTES(sp)LOAD x30, 18*REGBYTES(sp)LOAD x31, 19*REGBYTES(sp)//恢復寄存器后,更改堆棧指針,回收20個單字(40位)或者14個單字(28位)空間/* De-allocate the stack space */addi sp, sp, 20*REGBYTES #else/* De-allocate the stack space */addi sp, sp, 14*REGBYTES #endif /* __riscv_32e */.endm/*** \brief Macro for save necessary CSRs to stack* \details* This macro store MCAUSE, MEPC, MSUBM to stack.*///將MCAUSE, MEPC, MSUBM寄存器里面的值存入到棧中 .macro SAVE_CSR_CONTEXT/* Store CSR mcause to stack using pushmcause */csrrwi x0, CSR_PUSHMCAUSE, 11/* Store CSR mepc to stack using pushmepc */csrrwi x0, CSR_PUSHMEPC, 12/* Store CSR msub to stack using pushmsub */csrrwi x0, CSR_PUSHMSUBM, 13 .endm/*** \brief Macro for restore necessary CSRs from stack* \details* This macro restore MSUBM, MEPC, MCAUSE from stack.*///將MCAUSE, MEPC, MSUBM寄存器的值從棧中恢復 .macro RESTORE_CSR_CONTEXTLOAD x5, 13*REGBYTES(sp)csrw CSR_MSUBM, x5LOAD x5, 12*REGBYTES(sp)csrw CSR_MEPC, x5LOAD x5, 11*REGBYTES(sp)csrw CSR_MCAUSE, x5 .endm/*** \brief Exception/NMI Entry* \details* This function provide common entry functions for exception/nmi.* \remarks* This function provide a default exception/nmi entry.* ABI defined caller save register and some CSR registers* to be saved before enter interrupt handler and be restored before return.*/ .section .text.trap /* In CLIC mode, the exeception entry must be 64bytes aligned */ .align 6 .global exc_entry //此處exc_entry標簽為“弱(weak)屬性”,“弱(weak)屬性”為C/C++語法中定義的一種屬性,一旦有具體的“非弱”性質同名函數存在/將會覆蓋此函數 .weak exc_entry exc_entry://保存相應的狀態寄存器/* Save the caller saving registers (context) */SAVE_CONTEXT/* Save the necessary CSR registers */SAVE_CSR_CONTEXT/** Set the exception handler function arguments* argument 1: mcause value* argument 2: current stack point(SP) value*///傳參,將mcause value和棧指針作為參數傳給core_exception_handler()函數csrr a0, mcausemv a1, sp/** TODO: Call the exception handler function* By default, the function template is provided in* system_Device.c, you can adjust it as you want*///調用core_exception_handler()函數call core_exception_handler//恢復相應的狀態寄存器/* Restore the necessary CSR registers */RESTORE_CSR_CONTEXT/* Restore the caller saving registers (context) */RESTORE_CONTEXT/* Return to regular code *///調用從異常模式返回mret/*** \brief Non-Vector Interrupt Entry* \details* This function provide common entry functions for handling* non-vector interrupts* \remarks* This function provide a default non-vector interrupt entry.* ABI defined caller save register and some CSR registers need* to be saved before enter interrupt handler and be restored before return.*/ .section .text.irq /* In CLIC mode, the interrupt entry must be 4bytes aligned */ .align 2 .global irq_entry //此處irq_entry標簽為“弱(weak)屬性”,“弱(weak)屬性”為C/C++語法中定義的一種屬性,一旦有具體的“非弱”性質同名函數存在 //將會覆蓋此函數 .weak irq_entry /* This label will be set to MTVT2 register */ irq_entry:保存相應的狀態寄存器/* Save the caller saving registers (context) */SAVE_CONTEXT/* Save the necessary CSR registers */SAVE_CSR_CONTEXT/* This special CSR read/write operation, which is actually* claim the CLIC to find its pending highest ID, if the ID* is not 0, then automatically enable the mstatus.MIE, and* jump to its vector-entry-label, and update the link register*///跳到中斷向量表進行中斷處理csrrw ra, CSR_JALMNXTI, ra/* Critical section with interrupts disabled *///禁止所有中斷DISABLE_MIE//恢復相應的狀態寄存器/* Restore the necessary CSR registers */RESTORE_CSR_CONTEXT/* Restore the caller saving registers (context) */RESTORE_CONTEXT/* Return to regular code *///調用從中斷模式返回mret/* Default Handler for Exceptions / Interrupts */ .global default_intexc_handler .weak default_intexc_handler Undef_Handler: default_intexc_handler: 1: //數字標簽j 1b //跳轉回標簽1處,因此會成為死循環

總結

以上是生活随笔為你收集整理的GD32VF103启动流程分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。